0x1:
a,首先,看一下原APK和經過騰訊雲應用加固後的文件相關變化
加固後的文件列表變化:
新增2個so文件:
libmain.so
libshell.so
修改:
AndroidManifest.xml
classes.dex
b, 用ApkTool反編譯加固後的APK, 出現反編譯不過去,錯誤日誌以下:
1.
經過下面日誌能看出來是apktool解析AndroidManifest.xml時出錯,注意綠色下劃線的name=fasten,這裏TX加固是利用android系統解析axml的一個特色來致使apktool反編譯時,在解析AndroidManifest.xml時出錯。
2.下面來分析和修復AndroidManifest.xml
分析前,仍是得先了解一下AndroidManifest.xml的二進制格式,能夠參考下列文章:
輔助分析AndroidManifest.xml的二進制格式可使用下面的:
AXML的010 Editor模板
利用axml模版在010Editor解析AndroidManifest.xml能看到,有一個屬性結構的name成員的值是25,該值指向是string的索引,同時也是res ID的索引。
屬性結構:
String索引:
Res ID索引:
爲何這樣作,哈哈哈,我懶,因此直接截圖引用萬抽抽大神的解釋:
嗯,屬性結構的name成員的值是便是string索引,又是ResID索引,因此:
Name=25
String[25]=fasten
ResIDs[25]=0x01017FFF
再次引用抽抽大神文章裏的一段話:
Android系統在解析AXML的屬性的時候,是經過該屬性的res id號而非屬性名定位的。所謂的AXML就是AndroidManifest.xml對應的二進制文件,APK包中存儲的就是AXML。好比屬性:
<public type="attr"name="name" id="0x01010003" />
它的屬性名爲name,id號爲0x01010003。
因此fasten這個字符串能夠隨意改,關鍵仍是ResID的值,TX加固對AndroidManifest.xml處理,是插入一下非法的屬性ID (在Android的attr裏沒有一個ID爲0x01017FFF),由於是非法的屬性ID,Android是不會去解析,但ApkTool卻會去解析,因此致使反編譯出錯了。
修復方法:
知道怎麼回事,修復起來就很簡單了,只要把非法的屬性ID=0x0101FFFF改爲一個合法的屬性ID,好比把0x0101FFFF改爲name的屬性ID=0x01010003,而後再把修改後的AndroidManifest.xml再替換加固後apk裏的AndroidManifest.xml,而後用apktook就能夠順利的成功的反編譯出來。
附件有我用官網最新版的ApkTool 2.0.0 RC3源碼編譯,修改了一下,修復非法屬性ID沒法反編譯。若是懶得手動去修改AndroidManifest.xml,能夠直接用我這個修改過的apktool進行反編譯。
<ignore_js_op>
反編譯後,看加固修改後的AndroidManifest.xml和原版的AndroidManifest.xml多這三條:
1. <serviceandroid:name="com.tencent.mm.fasten.check.log" />
2. android:fasten="meta-data"
3. <meta-dataandroid:name="@anim/push_top_out2"android:value="meta-data" />
0x2:
a,ApkTool反編譯能夠成功,那接下來看一下TX加固是怎麼對Dex進行加密的
1. 新增了2個smail文件
com\tencent\StubShell\ProxyShell.smali
com\tencent\StubShell\ ShellHelper.smali
2. Smail代碼的變化(對指定方法進行加密)
從截圖能看到,加固後的dex,經過apktool反編譯後的smali代碼變化。
(1)
新增靜態代碼塊:
(只要加載此類,就會先執行該代碼塊,做用是用來動態恢復被加固的方法)
.methodstatic constructor <clinit>()V
.locals 2
.prologue
const-string v0,"com.boco.nfc.activity"
const/16 v1, 0x0
invoke-static {v0,v1},Lcom/tencent/StubShell/ShellHelper;->StartShell(Ljava/lang/String;I)Z
return-void
.endmethod
用JEB轉成代碼以下:
static{
ShellHelper.StartShell("com.boco.nfc.activity",0);
}
(2)
原始方法:
.methodpublic constructor <init>(Landroid/content/Context;)V
改成native屬性,而且隱藏字節碼:
.methodpublic native constructor <init>(Landroid/content/Context;)V
被加固後的Method數據:
從這裏能看到關鍵是在StartShell函數,這個StartShell函數專門負責在執行時動態恢復被加固的方法,TX加固這種方式沒辦法直接經過dump來進行脫殼,它機制是須要運行到某個類,加載這個類時纔會修復一下該類被加固的方法,但你又不能保證全部類你都能執行到,因此仍是得找原始數據來進行修復dex。
publicstatic boolean StartShell(String packageName, int iIndex)
從StartShell函數第二個參數iIndex來看,應該是要修復那個函數的編號。因此,能夠猜想確定會有一份原始的數據供給修復,因此從StartShell函數入手,就能找到修復的原始數據。
StartShell函數會先判斷若是沒有初始化過則執行InitProxyShell函數,InitProxyShell函數做用其實就是加載libshell.so, 最後,調用libshell.so的load(ShellHelper.strPackageName, iIndex);來進行修復,這裏調用具體過程就不說了,哈哈,TX加固還有log能夠看,方便你們理思路,你們想了解本身能夠去看看,。
從這裏能看到,關鍵是libshell.so的load函數在負責動態修復功能,下面就用IDA把libshell.so分析一下load函數。
(1)看一下libshell.so的JNI_OnLoad函數
主要就是作一些初始化的時,看來沒什麼,咱們直接主題,找load函數。
(2)Load函數在0xC630的偏移
ART模式下的修復就先不看了,有興趣的朋友本身去看吧, libshell的代碼流程再加上有log信息輔助,流程能夠很清晰…
這裏我大概說一下func_ShellFixDexMethod這個函數處理,詳細的能夠本身看下附件的libshell.idb吧。
1. 經過/proc/(getpid)/maps 打開自身進程的內存映射,查找classes.dex的內存地址。
2. TX加固會把全部被加固過的Method的原始數據存一份在文件尾部。
定位Method的原始數據存放地址的方法:
原始數據偏移 = DexDataOff + DexDataSize
有多少個Method須要修復 = (DexFileSize – (DexDataOff + DexDataSize))/0x12
每個Method方法的原始數據是用一個0x12大小的結構來保存的,結構以下
:
typedef
struct TXFixDexData
{
DWORD dwClassDefItem; //Class_defs的索引id
DWORD dwMethodIdx; //DexMethod結構裏的methodIdx值
DWORD dwaccessFlags; //DexMethod結構裏的dwaccessFlags值
DWORD dwDexCodeOff; //DexMethod結構裏的codeOff
WORD wProtoIdItem; //proto_ids
的索引id
}TXFixDexData;
3. 已經能夠知道Method的原始數據,接下來就看怎麼修復。關鍵就是要怎麼定位到哪一個Method是須要修復的。若是熟悉Dex結構的,應該就比較容易如何修復。
個人修復方法:先經過Class_defs的索引id(TXFixDexData->dwClassDefItem)定位到須要修復的Method所在的類,再取該類的全部Method,把每一個Method的DexMethod->methoIdx值等於TXFixDexData->dwMethodIdx,就肯定是須要修復的Method, 而後把該Method的DexMethod結構的accessFlags和codeOff修復就OK。
下面修復TX加固的classes.dex的工具, 附件有Bin和Src,代碼比較挫,大夥將就看下思路就好了:
<ignore_js_op>
最後,把修復完的classes.dex放到apk,再反編譯下,能看到被隱藏Method的代碼回來了,可是還須要作一些掃尾的事,才能算徹底脫殼成功。
1.
搜索一下全部smali文件的下面這一句代碼,而後所有替換爲空:
invoke-static {v0, v1},Lcom/tencent/StubShell/ShellHelper;->StartShell(Ljava/lang/String;I)Z
2.
刪除掉
AndroidManifest.xml
這三個地方:
a. <serviceandroid:name="com.tencent.mm.fasten.check.log" />
b. android:fasten="meta-data"
c. <meta-dataandroid:name="@anim/push_top_out2"android:value="meta-data" />
最後再從新打包APK,至此,脫殼完畢!
PS:寫文檔真累人啊,比分析脫殼還累,寫到後面都不知道本身在寫什麼,文章已亂成漿糊,可能也有一些東西沒說到,見諒,由於我已暈死…
最後,提早預祝一下你們...春節快樂!!!
轉載請註明出處來自吾愛破解論壇:http://www.52pojie.cn/thread-330022-1-1.htmlphp