某數(shù)字公司VMP脫殼簡記

Android安全交流群:478084054

0x00

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

0x01 DUMP classes.dex

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

已經(jīng)變成了殼代理,沒有一點原APK的代碼。

在assets中,有兩個殼相關(guān)的SO:

嘗試從內(nèi)存中DUMP原classes.dex。

考慮到在Dalvik下,360可能會自己實現(xiàn)從內(nèi)存中加載classes.dex的代碼,不容易找到DUMP的點。而ART下,可操作空間就小多了,所以我是在ART下操作的。

具體的,我是在ClassLinker::DefineClass函數(shù)處得到dex_file的begin和size,然后DUMP出原來的classes.dex。我看到有人在dex2oat的地方DUMP,但我覺得如果360 HOOK execv,阻止dex2oat對原classes.dex作oat轉(zhuǎn)換的話,會不會就脫不出來了呢?不過我對Android虛擬機不太了解,可能有更好的DUMP點。

成功DUMP出原classes.dex:

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

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

interface11以及onCreate對應(yīng)的native方法,以及解釋器并沒有實現(xiàn)在上圖中的libjiagu.so中,而是實現(xiàn)在另一個運行時從內(nèi)存中加載的SO中(暫且稱其為解釋器SO)。

0x02?DUMP解釋器SO

APK運行后,會首先加載libjiagu.so,并執(zhí)行其JNI_Onload方法。該方法最終會調(diào)用到__fun_a_18,這個方法進行了控制流混淆,流程對于我來說是非常復(fù)雜的。

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

怎么破?我沒有什么好辦法,只有硬看,不斷的調(diào)試,參考大神們的帖子。

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

第一處反調(diào),來自case 37:

繼續(xù)執(zhí)行:

來到這個位置,看到R3保存的是rtld_db_dlactivity符號的地址,我擔(dān)心它是要作SIGTRAP信號反調(diào),所以手動將R3的值修改為0。

繼續(xù)執(zhí)行。當?shù)?次進入case 32時:

繼續(xù)執(zhí)行,來到下面的位置:

注意此時R1的值,要將600B0010修改為200B0010,否則會執(zhí)行R4地址處的代碼。

R4地址處的代碼是什么?看一下:

就是終止進程的代碼。

過了此處反調(diào)之后,繼續(xù)執(zhí)行,來到case 31:

繼續(xù),來到如下位置,這里就是加載解釋器SO的函數(shù)了。

注意,這里不是通過調(diào)用dlopen函數(shù)來加載解釋器SO的,而是自己實現(xiàn)的類似于linker的加載代碼。

其實linker的工作原理并不復(fù)雜,簡單來說就是將目標SO文件的LOAD段映射內(nèi)存,解析文件格式,做好符號重定位,再調(diào)用init/init_array方法等等。

繼續(xù)執(zhí)行,來到解密ELF Header的地方:

解密完畢:

根據(jù)R3的值,將ELF Header先DUMP出來。

繼續(xù)執(zhí)行,來到解密Program Header的地方:

解密完畢:

將Program Header也DUMP出來:

繼續(xù)執(zhí)行,來到如下位置:

這個方法是要將解釋器SO的LOAD段映射到內(nèi)存,然后完成整個加載過程。

根據(jù)so_addr和so_size將整個SO DUMP出來,但這里DUMP出來的SO是沒有ELF Header和Program Header的,但這兩個頭前面已經(jīng)DUMP出來了。最后三者拼在一起,就是完整的解釋器SO了。

0x03還原onCreate

有了解釋器SO,就可以繼續(xù)分析了,核心的內(nèi)容都在這個SO里面。

由于我編譯的系統(tǒng),加了很多日志,所以在執(zhí)行到前面的onCreate方法時,看到如下日志:

就像前面猜測的那樣,當執(zhí)行該onCreate方法時,先執(zhí)行class的static代碼塊,調(diào)用interface11方法,該方法將onCreate注冊到了一個地址為0x75c74e2d的native方法上。該native方法就實現(xiàn)在解釋器SO中。用0x75c74e2d減去load_base,可知是解釋器SO中的sub_10E2C方法。

跟蹤并分析該方法。

繼續(xù)動態(tài)調(diào)試,在解釋器SO中偏移0xFAAE處下斷點:

觀察此時R1寄存器的值為0xBE027450,跳到該處內(nèi)存,并得到0xBE027458處的值為0x75EA5418。

跳到0x75EA5418內(nèi)存處。

觀察0x75EA5418內(nèi)存處的值,得到本次解釋執(zhí)行的方法是:com.xxx.xxxActivity->onCreate。

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

觀察此時R7寄存器的值為0x75E96A10,在Hex View中,跳到0x75E96A10內(nèi)存處:

觀察此時0x75E96A18地址處存儲的值為0x7699C61C,在Hex View中跳到0x7699C61C內(nèi)存處:

在0x7699C61C內(nèi)存處存儲的就是DexCode結(jié)構(gòu),DexCode的結(jié)構(gòu)定義如下:

由此可知“com.xxx.xxxActivity->onCreate”方法的insns指令數(shù)組大小是0x93*2=294個字節(jié),指令數(shù)據(jù)流是:

這個指令數(shù)據(jù)流是經(jīng)過加密的,解密key存儲在0x75E96A2C地址處,值為0x3B。

繼續(xù)調(diào)試的話,就是執(zhí)行switch型的解釋器了。這個解釋器和Dalvik解釋器類似。在android 2.x版本中曾有2種形式的C實現(xiàn)的解釋器,一種goto的,一種switch的。后來谷歌把switch型解釋器去掉了,因為執(zhí)行效率沒有g(shù)oto的好。再后來就有了ART,貌似把C語言實現(xiàn)的解釋器都去掉了。再再后來到了7.0,goto和switch型的C解釋器又都回來了。

簡單來說,就是解釋執(zhí)行整個onCreate方法的指令數(shù)據(jù)流,每條指令在執(zhí)行前會解密。那怎么將這些指令還原回原本的dalvik字節(jié)碼指令,達到脫殼目的呢?可以根據(jù)每個case的實現(xiàn),來得到當前執(zhí)行的opcode對應(yīng)dalvik字節(jié)碼指令中的哪一條,然后對應(yīng)還原。

比如,這里的0xAE,在解釋執(zhí)行時,跳轉(zhuǎn)到case 174處執(zhí)行。假設(shè)拿case 174處的代碼對比分析Dalvik解釋器,發(fā)現(xiàn)case 174執(zhí)行的是invoke-static指令,那么這條指令就還原出來了。

這樣有點麻煩。

有一個好點的辦法就是:自己在onCreate方法中將所有的dalvik指令,一共200多條全部寫出來。然后用360加固,動態(tài)調(diào)試,總結(jié)出每條dalvik指令對應(yīng)的360解釋器的case處理指令的偏移,最后得到一張指令映射表。這樣,后續(xù)在脫殼的時候,就可以根據(jù)解釋執(zhí)行代碼的偏移,還原出原來的指令。當然,360解釋器也是在不斷變化的,所以,這個表也是要跟著變化的。

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

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

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

0x04后序

由于時間和水平都有限,很多地方還沒仔細分析,本篇筆記只是簡單記錄一下本次操作的大致過程和一些思路。

最后,感謝論壇中各大神的分享,讓我學(xué)習(xí)到了很多東西。

End

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,224評論 6 529
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 97,916評論 3 413
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 175,014評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,466評論 1 308
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,245評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,795評論 1 320
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,869評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,010評論 0 285
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,524評論 1 331
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,487評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,634評論 1 366
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,173評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 43,884評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,282評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,541評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,236評論 3 388
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,623評論 2 370

推薦閱讀更多精彩內(nèi)容