0. 神器ZjDroid
Xposed框架的另外一個功能就是實現應用的簡單脫殼,其實說是Xposed的作用其實也不是,主要是模塊編寫的好就可以了,主要是利用Xposed的牛逼Hook技術實現的,下面就先來介紹一下這個脫殼模塊工具ZjDroid的原理,因為他是開源的,所以咋們直接分析源碼即可,源碼的下載地址:https://github.com/halfkiss/ZjDroid 不過可惜的時候他只公開了Java層的代碼,而native層的代碼並沒有公開,但是分析源碼之后會發現最重要的功能就在native層,不過也沒關系,等分析到那里的時候我在給大家講解底層的大致實現方案即可。
1. 源碼分析ZjDroid原理(
下面就來詳細的分析一下ZjDroid工具的源碼吧,他是一個Eclipse工程導入很簡單,基於之前的Xposed模塊編寫的經驗,我們知道找到入口代碼也很簡單,在assets目錄下有一個xposed_init文件中就記錄了模塊的入口類:
然后我們直接進入到這個類查看即可:
看到了,遵循統一規則,實現了IXposedHookLoadPackage接口,實現handleLoadPackage回調方法即可,下面繼續分析入口方法ModuleContext的initModuleContext
發現這開始攔截Application的onCreate方法了,而這個方法一般是每個應用程序的啟動方法,在這里做攔截操作也是合情合理的,在看看攔截之后做了什么,也就是ApplicationOnCreateHook類的實現:
一個是進程id:
這個作用主要是為了過濾其他應用,只處理本應用的邏輯,因為這個廣播發送之后所有的應用都能接收到,但是我們脫殼有時候肯定只是針對於某一個應用,那么只需要在這個應用的廣播接收中做處理即可。
一個是命令字符串:這個是為了發送廣播可以支持多種功能,后面分析也可以看到的確有很多功能的。
然后這里得到命令之后就開始構造一個命令執行器類,這里用到了設計模式中的命令模式。下面繼續看看有哪幾種命令執行器類:
在這個方法中就開始分析了這里支持的哪幾種命令類,下面來一一分析一下:
第一個命令:dump_dexinfo
獲取應用運行時內存中dex的信息:DumpDexInfoCommandHandler
進入方法在詳細查看一下:
看到了,這里的實現邏輯還是比較簡單的,全部通過反射機制獲取每個應用的dex文件對應的DexFile類型對象,這里的工作和我們之前介紹了Android中插件化開發已經很熟悉了,通過應用的默認類加載PathClassLoader類得到DexPathList類,然后在得到具體的DexFile對象即可。這里要說的就是這個dex文件對應的cookie值,這個值非常重要,是后續命令操作的基本信息,他代表的含義就是底層中每個應用的dex文件對應的唯一id值,系統會維護一個map結構來保存這些數據的,系統然后通過這個cookie值來找到對應的dex文件信息的。
命令用法:am broadcast -a com.zjdroid.invoke –ei target [pid] –es cmd '{"action":"dump_dexinfo"}'
這里使用的是命令方式發送一個廣播,通過–ei攜帶目標進程id是一個int類型,通過–es攜帶命令字符串
第二個命令:dump_dexfile
這個命令也是后續脫殼的重要命令,就是dump出應用內存中的dex文件:DumpDexFileCommandHandler
這里可以看到dump出應用的內存數據,首先得需要傳入源應用的dex數據也就是apk文件,這個一般都是存放在/data/app/xxx.apk目錄下的,然后就是這里自己構建了一個dump之后的dex文件路徑,通過源碼查看是在/data/data/xxx/files/dexdump.odex中。接下來繼續查看dump的核心代碼:

命令用法:am broadcast -a com.zjdroid.invoke –ei target [pid] –es cmd '{"action":"dump_dexfile","dexpath":"*****"}'
注意這里的dexpath參數是代表需要脫殼的dex文件,也就是應用程序文件。
第三個命令:backsmali
這個命令其實是和上面的命令差不多功能,只是這里的命令多了一層操作就是把dex文件轉化成smali文件,所以這里不再詳細說明了,咋們可以先得到dex文件,然后在通過工具得到smali文件也是可以的。
命令用法:am broadcast -a com.zjdroid.invoke –ei target pid –es cmd ‘{“action”:”backsmali”,”dexpath”:”*****”}’
注意這里的dexpath參數是代表需要脫殼的dex文件,也就是應用程序文件。而最終生成的smali文件夾是放在/data/data/xxx/smali下面的。
第四個命令:dump_mem
這個命令是用來dump出應用程序運行時內存中指定開始位置和長度的內存塊數據的:DumpMemCommandHandler
可惜這個方法也是native層的,但是這個操作就比較簡單了,我們知道每個應用運行時的內存地址都在 /proc/[pid]/maps 文件中:
那么查找內存地址,然后在使用memcpy進行內存數據拷貝也是非常簡單的。
命令用法:am broadcast -a com.zjdroid.invoke –ei target [pid] –es cmd ‘{“action”:”dump_mem”,”start”:111,”length”:23}’
注意這里的start和length都是十進制的,而不是十六進制的數據格式。
第五個命令:dump_heap
這個命令是可以dump出虛擬機的堆內存信息的,文件可以使用java heap工具進行分析,而對於這個命令我們想一下應該也知道實現邏輯應該是也是在native層的,而且這個代碼邏輯應該和上面的那個命令差不多的,但是對於這個命令我還沒有想到具體的思路,悲哀呀,如果有了解的同學就告知一下哈!
命令用法:am broadcast -a com.zjdroid.invoke –ei target [pid] –es cmd ‘{“action”:”dump_heap”}’
第六個命令:dump_class
這個命令主要是用於dump出dex文件中的類信息,這個操作也是非常簡單的,因為在DexFile對象中有一個隱藏的方法可以把dex文件中的所有類名獲取到:getClassNameList
這里可以看到這個方法的傳入參數為一個dex文件對應的cookie值。
命令用法:am broadcast -a com.zjdroid.invoke –ei target pid –es cmd ‘{“action”:”dump_class”,”dexpath”:”*****”}’
這里的dexpath是需要得到所有類信息的dex文件路徑,也就是應用的apk文件路徑。
第七個命令:invoke
這個命令是用於運行時動態調用Lua腳本,本人並沒有看懂這個命令的作用,該功能可以通過Lua腳本動態調用java代碼。使用場景:可以動態調用解密函數,完成解密。可以動態觸發特定邏輯。代碼就不進行分析了,因為我覺得這個命令應該不怎么會使用
命令用法:am broadcast -a com.zjdroid.invoke –ei target pid –es cmd ‘{“action”:”invoke”,”filepath”:”****”}’
這里的filepath是lua腳本文件的存放路徑。
到這里就全部介紹完了ZjDroid的所有命令了,下面還有兩個非常重要的打印日志的tag:
第一個:adb logcat -s zjdroid-shell-{package name}
這個tag可以查看上面每個命令執行的結果,便於查看命令執行的狀態。
第二個:adb logcat -s zjdroid-apimonitor-{package name}
這個tag可以監聽對應包名應用調用的哪些api信息,這個作用有點類似於運行時權限請求的作用。這個做起來就非常簡單了,可以直接通過Xposed提供的方法進行系統的一些敏感api進行攔截然后添加監控代碼即可。
三、命令總結
上面就從源碼的角度完全分析完了ZjDroid工具的功能了,下面就來總結一下:
1、獲取APK當前加載DEX文件信息
am broadcast -a com.zjdroid.invoke –ei target pid –es cmd ‘{“action”:”dump_dexinfo”}’
2、獲取指定DEX文件包含可加載類名
am broadcast -a com.zjdroid.invoke –ei target pid –es cmd ‘{“action”:”dump_class”,”dexpath”:”*****”}’
3、根據Dalvik相關內存指針動態反編譯指定DEX,並以文件形式保存
am broadcast -a com.zjdroid.invoke –ei target pid –es cmd ‘{“action”:”backsmali”,”dexpath”:”*****”}’
4、Dump指定DEX內存中的數據並保存到文件(數據為odex格式,可在pc上反編譯)
am broadcast -a com.zjdroid.invoke –ei target pid –es cmd ‘{“action”:”dump_dexfile”,”dexpath”:”*****”}’
5、Dump指定內存空間區域數據到文件
am broadcast -a com.zjdroid.invoke –ei target pid –es cmd ‘{“action”:”dump_mem”,”start”:1234567,”length”:123}’
6、Dump Dalvik堆棧信息到文件,文件可以通過java heap分析工具分析處理
am broadcast -a com.zjdroid.invoke –ei target pid –es cmd ‘{“action”:”dump_heap”}’
7、運行時動態調用Lua腳本
該功能可以通過Lua腳本動態調用java代碼。使用場景:可以動態調用解密函數,完成解密。可以動態觸發特定邏輯。
am broadcast -a com.zjdroid.invoke –ei target pid –es cmd ‘{“action”:”invoke”,”filepath”:”****”}’
8、相關命令執行結果查看
1、命令執行結果
adb shell logcat -s zjdroid-shell-{package name}
2、敏感API調用監控輸出結果
adb shell logcat -s zjdroid-apimonitor-{package name}
3、總結
好了,到這里我們就講解完了基於Xposed框架的脫殼神器ZjDroid的實現原理以及具體用法。而這里也感受到了Xposed框架的強大之處,當然這也只是一部分,后面還可以利用這個框架編寫游戲外掛等操作。
4、源碼
附件列表