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時出錯。
關於利用AndroidManifest.xml這塊的技術點可以參考一下萬抽抽大神的文章:http://www.cnblogs.com/wanyuanchun/p/4084292.html

2.下面來分析和修復AndroidManifest.xml
分析前,還是得先了解一下AndroidManifest.xml的二進制格式,可以參考下列文章:
AndroidManifest二進制文件格式分析 http://bbs.pediy.com/showthread.php?t=194206
輔助分析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://pan.baidu.com/s/1eQs3fZc
轉載請注明出處來自吾愛破解論壇:http://www.52pojie.cn/thread-330022-1-1.html