天天看點

python 工程結構加強_【安卓逆向】360加強-脫殼修複

360加強-脫殼修複

最近花了一些時間學習逆向脫殼,這方面一直投入的時間比較少。樣本經過某加強寶進行加強,這裡簡單記錄一下脫殼過程和思路,感謝某數字公司對安全加強的無私貢獻,讓我有機會小小的提高一下這方面的技能。

DUMP classes.dex

打開APK包中的classes.dex看一下:

python 工程結構加強_【安卓逆向】360加強-脫殼修複

已經變成了殼代{過}{濾}理,沒有一點原APK的代碼。在assets中,有兩個殼相關的SO:

python 工程結構加強_【安卓逆向】360加強-脫殼修複

嘗試從記憶體中DUMP原classes.dex。

考慮到在Dalvik下,360可能會自己實作從記憶體中加載classes.dex的代碼,不容易找到DUMP的點。而ART下,可操作空間就小多了,是以我是在ART下操作的。

具體的,我是在ClassLinker:

python 工程結構加強_【安卓逆向】360加強-脫殼修複

efineClass函數處得到dex_file的begin和size,然後DUMP出原來的classes.dex。我看到有人在dex2oat的地方DUMP,但我覺得如果360 HOOK execv,阻止dex2oat對原classes.dex作oat轉換的話,會不會就脫不出來了呢?不過我對Android虛拟機不太了解,可能有更好的DUMP點。

成功DUMP出原classes.dex:

python 工程結構加強_【安卓逆向】360加強-脫殼修複

但是可以看到,有些方法(圖中onCreate)的指令被抽走了,并且改為了native方法。同時,在static代碼塊中,有一行調用StubApp.interface11(16)。

可以猜測:當該class被加載時,static代碼塊會首先被執行,這樣StubApp.interface11方法就會将onCreate注冊到殼SO的某個native方法上。這樣,當執行onCreate時,就會執行相應的native方法,該native方法會首先找到onCreate對應的指令,然後解密,最終解釋執行。

interface11以及onCreate對應的native方法,以及解釋器并沒有實作在上圖中的libjiagu.so中,而是實作在另一個運作時從記憶體中加載的SO中(暫且稱其為解釋器SO)。

DUMP解釋器SO

APK運作後,會首先加載libjiagu.so,并執行其JNI_Onload方法。該方法最終會調用到__fun_a_18,這個方法進行了控制流混淆,流程對于我來說是非常複雜的。

python 工程結構加強_【安卓逆向】360加強-脫殼修複

剛開始,我以為它用了o-llvm進行混淆編譯。但仔細看一下彙編代碼,應該不是。應該就是自己在源碼中利用while-switch實作了“控制流平坦化”的混淆算法。

怎麼破?我沒有什麼好辦法,隻有硬看,不斷的調試,參考大神們的文章。

由于我手機是自己編譯的系統,對于某些反調試天然免疫,是以遇到的反調并不多。下面簡述我是怎麼過反調并DUMP出解釋器SO的,因為這個混淆算法應該每個版本都有所變化,是以這個流程并不一定适用别的樣本。

第一處反調,來自case 37:

python 工程結構加強_【安卓逆向】360加強-脫殼修複

繼續執行:

python 工程結構加強_【安卓逆向】360加強-脫殼修複

來到這個位置,看到R3儲存的是rtld_db_dlactivity符号的位址,我擔心它是要作SIGTRAP信号反調,是以手動将R3的值修改為0。

繼續執行。當第4次進入case 32時:

python 工程結構加強_【安卓逆向】360加強-脫殼修複

繼續執行,來到下面的位置:

python 工程結構加強_【安卓逆向】360加強-脫殼修複

注意此時R1的值,要将600B0010修改為200B0010,否則會執行R4位址處的代碼。

R4位址處的代碼是什麼?看一下:

python 工程結構加強_【安卓逆向】360加強-脫殼修複

就是終止程序的代碼。

過了此處反調之後,繼續執行,來到case 31:

python 工程結構加強_【安卓逆向】360加強-脫殼修複

繼續,來到如下位置,這裡就是加載解釋器SO的函數了。

python 工程結構加強_【安卓逆向】360加強-脫殼修複

注意,這裡不是通過調用dlopen函數來加載解釋器SO的,而是自己實作的類似于linker的加載代碼。

其實linker的工作原理并不複雜,簡單來說就是将目标SO檔案的LOAD段映射記憶體,解析檔案格式,做好符号重定位,再調用init/init_array方法等等。

繼續執行,來到解密ELF Header的地方:

python 工程結構加強_【安卓逆向】360加強-脫殼修複

解密完畢:

python 工程結構加強_【安卓逆向】360加強-脫殼修複

根據R3的值,将ELF Header先DUMP出來。

python 工程結構加強_【安卓逆向】360加強-脫殼修複
python 工程結構加強_【安卓逆向】360加強-脫殼修複

繼續執行,來到解密Program Header的地方:

python 工程結構加強_【安卓逆向】360加強-脫殼修複

解密完畢:

python 工程結構加強_【安卓逆向】360加強-脫殼修複

将Program Header也DUMP出來:

python 工程結構加強_【安卓逆向】360加強-脫殼修複

繼續執行,來到如下位置:

python 工程結構加強_【安卓逆向】360加強-脫殼修複

這個方法是要将解釋器SO的LOAD段映射到記憶體,然後完成整個加載過程。

根據so_addr和so_size将整個SO DUMP出來,但這裡DUMP出來的SO是沒有ELF Header和ProgramHeader的,但這兩個頭前面已經DUMP出來了。最後三者拼在一起,就是完整的解釋器SO了。

python 工程結構加強_【安卓逆向】360加強-脫殼修複
python 工程結構加強_【安卓逆向】360加強-脫殼修複

還原onCreate

有了解釋器SO,就可以繼續分析了,核心的内容都在這個SO裡面。

由于我編譯的系統,加了很多日志,是以在執行到前面的onCreate方法時,看到如下日志:

python 工程結構加強_【安卓逆向】360加強-脫殼修複

就像前面猜測的那樣,當執行該onCreate方法時,先執行class的static代碼塊,調用interface11方法,該方法将onCreate注冊到了一個位址為0x75c74e2d的native方法上。該native方法就實作在解釋器SO中。用0x75c74e2d減去load_base,可知是解釋器SO中的sub_10E2C方法。

python 工程結構加強_【安卓逆向】360加強-脫殼修複

跟蹤并分析該方法。

繼續動态調試,在解釋器SO中偏移0xFAAE處下斷點:

python 工程結構加強_【安卓逆向】360加強-脫殼修複

觀察此時R1寄存器的值為0xBE027450,跳到該處記憶體,并得到0xBE027458處的值為0x75EA5418。

跳到0x75EA5418記憶體處。

python 工程結構加強_【安卓逆向】360加強-脫殼修複

觀察0x75EA5418記憶體處的值,得到本次解釋執行的方法是:com.xxx.xxxActivity->onCreate。

繼續,在解釋器SO中偏移0x35C80處下斷點:

python 工程結構加強_【安卓逆向】360加強-脫殼修複

觀察此時R7寄存器的值為0x75E96A10,在Hex View中,跳到0x75E96A10記憶體處:

python 工程結構加強_【安卓逆向】360加強-脫殼修複

觀察此時0x75E96A18位址處存儲的值為0x7699C61C,在Hex View中跳到0x7699C61C記憶體處:

python 工程結構加強_【安卓逆向】360加強-脫殼修複

在0x7699C61C記憶體處存儲的就是DexCode結構,DexCode的結構定義如下:

python 工程結構加強_【安卓逆向】360加強-脫殼修複

由此可知“com.xxx.xxxActivity->onCreate”方法的insns指令數組大小是0x93*2=294個位元組,指令資料流是:

python 工程結構加強_【安卓逆向】360加強-脫殼修複

這個指令資料流是經過加密的,解密key存儲在0x75E96A2C位址處,值為0x3B。

繼續調試的話,就是執行switch型的解釋器了。這個解釋器和Dalvik解釋器類似。在android2.x版本中曾有2種形式的C實作的解釋器,一種goto的,一種switch的。後來谷歌把switch型解釋器去掉了,因為執行效率沒有goto的好。再後來就有了ART,貌似把C語言實作的解釋器都去掉了。再再後來到了7.0,goto和switch型的C解釋器又都回來了。

python 工程結構加強_【安卓逆向】360加強-脫殼修複

簡單來說,就是解釋執行整個onCreate方法的指令資料流,每條指令在執行前會解密。那怎麼将這些指令還原回原本的dalvik位元組碼指令,達到脫殼目的呢?可以根據每個case的實作,來得到目前執行的opcode對應dalvik位元組碼指令中的哪一條,然後對應還原。

python 工程結構加強_【安卓逆向】360加強-脫殼修複

比如,這裡的0xAE,在解釋執行時,跳轉到case 174處執行。假設拿case 174處的代碼對比分析Dalvik解釋器,發現case 174執行的是invoke-static指令,那麼這條指令就還原出來了。

python 工程結構加強_【安卓逆向】360加強-脫殼修複

這樣有點麻煩。

有一個好點的辦法就是:自己在onCreate方法中将所有的dalvik指令,一共200多條全部寫出來。然後用360加強,動态調試,總結出每條dalvik指令對應的360解釋器的case處理指令的偏移,最後得到一張指令映射表。這樣,後續在脫殼的時候,就可以根據解釋執行代碼的偏移,還原出原來的指令。當然,360解釋器也是在不斷變化的,是以,這個表也是要跟着變化的。

那能寫自動脫殼機嗎?隻要這張指令映射表是有效的,脫殼就可以自動化完成。

那如果指令映射表失效了,能通過代碼自動生成新的指令映射表嗎?仔細分析解釋器,每個指令的處理邏輯沒大變化的,也許可以。

扯遠了,下圖是某個onCreate方法還原前後:

python 工程結構加強_【安卓逆向】360加強-脫殼修複

由于時間和水準都有限,很多地方還沒仔細分析,本篇筆記隻是簡單記錄一下本次操作的大緻過程和一些思路。最後,感謝傾聽。

轉載自→