非越獄環(huán)境下iOS版WeChat 逆向研究示例,dylibz(動態(tài)庫)注入、應用重簽名
基本原理
通過app啟動時調(diào)用我們注入的dylib,進行app hook,最終能夠執(zhí)行我們注入的dylib。
應用砸殼
App store里的應用都是加密的,沒辦法直接拿來使用,所以在做之前都需要一個砸殼的過程,而砸殼使用的工具是dumpdecrypted, 原理就是讓app預先加載一個dumpdecrypted.dylib,然后在程序運行時,將代碼動態(tài)解密,最后在內(nèi)存中dump出來整個程序。當然砸殼是需要在越獄環(huán)境下進行的,所以我直接從PP助手等各種xx助手里面下載越獄應用(不是正版應用),也就是所謂的脫過殼的應用。
注意: 有好多應用是只有部分架構(gòu)被解密,這時需要檢查從xx助手下載的越獄應用是否已解密,還有就是Watch App以及一些擴展依然加密了,所以最好還是確認一下,否則的話,就算hook成功,簽名成功,安裝成功,app還是會閃退。
查看越獄應用是否已經(jīng)解密的方式,以WeChat-6.5.18為例:
1.將xx助手中下載的WeChat-6.5.18.ipa包解壓,會得到一個相同的名稱的文件夾,然后進入該文件夾中->Payload->WeChat,右鍵WeChat->顯示包內(nèi)容,進入app包中
2.打開終端,并進入剛才解壓的WeChat-6.5.18文件夾中Payload文件夾中,執(zhí)行cd命令:
cd /Users/mofeini/Desktop/weChat/WeChat-6.5.18/Payload
3.通過終端,找到應用對應的二進制文件,查看該app包含哪些架構(gòu), 執(zhí)行file命令:
file WeChat.app/WeChat
結(jié)果:
WeChat.app/WeChat: Mach-O universal binary with 2 architectures: [arm_v7: Mach-O executable arm_v7] [arm64]
WeChat.app/WeChat (for architecture armv7): Mach-O executable arm_v7
WeChat.app/WeChat (for architecture arm64): Mach-O 64-bit executable arm64
從結(jié)果中可以看到WeChat.app包含兩個構(gòu)架: arm_v7 和 arm64,關(guān)于架構(gòu)和設備之間的關(guān)系,可以查看iossupportmatrix。理論上只要把最老的架構(gòu)解密即可,因為新的cpu會兼容老的架構(gòu)。
- 通過終端命令
otool輸出app 的load commands,然后查看獲取的cryptid這個對應的value來判斷app是否被加密,1代表加密了,0代表解密,執(zhí)行otool -l (注意不是1哦)命令;
otool -l WeChat.app/WeChat | grep -B 2 crypt
結(jié)果:
cmd LC_ENCRYPTION_INFO
cmdsize 20
cryptoff 16384
cryptsize 48906240
cryptid 0
--
cmd LC_ENCRYPTION_INFO_64
cmdsize 24
cryptoff 16384
cryptsize 52396032
cryptid 0
從結(jié)果中可以看到cryptid對應的value都是0,可以確定此app已經(jīng)被解密了,第一個對應的是較老的armv7架構(gòu),后者則是arm64架構(gòu)
由于微信的項目中包含多個target: 包含WeChatWatchNative和WeChatShareExtensionNew。所以我們還需要按照上面的步驟,確認以下二進制文件(其中有兩個是Watch中的,一個是微信分享擴展):
WeChat.app/Watch/WeChatWatchNative.app/WeChatWatchNative
WeChat.app/Watch/WeChatWatchNative.app/PlugIns/WeChatWatchNativeExtension.appex/WeChatWatchNativeExtension
WeChat.app/PlugIns/WeChatShareExtensionNew.appex/WeChatShareExtensionNew
結(jié)果:
WeChatWatchNative 未獲取到信息
WeChatWatchNativeExtension cryptid 1
WeChatShareExtensionNew cryptid 0
注意: WeChatWatch還是加密的,會影響到下面步驟中的重簽名,最簡單的辦法就是,對對應ipa包解壓后,將里面的Watch文件夾刪除,再進行重新簽名
制作需要注入微信的dylib動態(tài)庫
制作dylib動態(tài)庫的兩種方式: iOSOpenDev 和 theos
由于iOSOpenDev總是安裝失敗,所以這里使用theos
- 使用終端命令,安裝配置theos,將其Cloning into '/opt/theos'...
安裝ldid:brew install dpkg ldid,在Theos開發(fā)插件中,iOS文件的簽名是使用ldid工具來完成的,也就是說ldid取代了Xcode自帶的Codesign;當出現(xiàn)Updating Homebrew...耐心等待即可;
配置$THEOS:export THEOS=/opt/theos等號后面是theos文件所在路徑
Theos安裝:sudo git clone --recursive https://github.com/theos/theos.git $THEOS,Theos一般是安裝在/opt/目錄下的,Cloning完成后,可cd到/opt目錄下查看;
Cloning完成Theos后,要修改一下文件的權(quán)限:sudo chown -R $(id -u):$(id -g) /opt/theos
配置環(huán)境變量: 在終端執(zhí)行open ~/.bash_profile打開此文件,在后面加入:
export PATH=/opt/theos/bin:$PATH
export THEOS=/opt/theos
出現(xiàn)的問題: 當執(zhí)行brew install dpkg ldid提示
/usr/local/Homebrew/Library/Homebrew/brew.rb:12:in `<main>': Homebrew must be run under Ruby 2.3! (RuntimeError)
解決:重新執(zhí)行brew install dpkg ldid
創(chuàng)建tweak
使用theos來創(chuàng)建工程,創(chuàng)建工程也是比較簡單的,就是調(diào)用我們theos目錄中bin下的nic.pl命令。在執(zhí)行nic.pl命令后,會讓你選擇新建工程的模板,目前theos中內(nèi)置的是12套模板。當然我們此處創(chuàng)建的是tweak類型的工程,所有我們選擇11
- 新建工程,執(zhí)行終端命令:
nic.pl
然后,終端會顯示12套模板,并提示Choose a Template (required):,我們輸入11回車
接下來會提示項目名Project Name (required):,輸入項目名wechatplugin,回車
該 deb 包的名字:Package Name [com.yourcompany.wechatplugin]:輸入com.ossey.WeChatPlugin回車
作者Author/Maintainer Name [Swae]:輸入你的名
tweak 作用對象的 bundle identifier(比如微信為com.tencent.xin):[iphone/tweak] MobileSubstrate Bundle filter [com.apple.springboard]:輸入com.tencent.xin回車
tweak 安裝完成后需要重啟的應用名[iphone/tweak] List of applications to terminate upon installation (space-separated, '-' for none) [SpringBoard],(比如微信為WeChat)
tweak項目中文件介紹
安裝完成后進入cd wechatplugin/, 執(zhí)行
ls -l, 可以看到里面有四個文件:
完成后會看到四個文件(make 后將生成 .theos 、obj 文件夾).
Makefile WeChatPlugin.plist Tweak.xm control對Makefile文件進行修改
Makefile : 工程用到的文件、框架、庫等信息。
該文件過于簡單,還需要添加一些信息。如
指定處理器架構(gòu)ARCHS = armv7 arm64
指定SDK版本TARGET = iphone:latest:8.0
導入所需的framework等等。
修改后的Makefile文件:
ARCHS = armv7 arm64
TARGET = iphone:latest:8.0
include $(THEOS)/makefiles/common.mk
TWEAK_NAME = WeChatPlugin
WeChatPlugin_FILES = Tweak.xm
include $(THEOS_MAKE_PATH)/tweak.mk
after-install::
install.exec "killall -9 WeChat"
WeChatPlugin.plist: 該文件中的 Bundles : 指定 bundle 為 tweak 的作用對象。也可添加多個 bundle, 指定多個為 tweak 作用對象。
control: 該 tweak 所需的基本信息
Tweak.xm: 主要是用來編寫hook代碼,它支持Logos和c/c++,可以讓我們不用去寫一些 runtime 方法
.x 文件支持Logos語法,.xm 文件支持Logos和C/C++語法
Logos 常用語法:
%hook: 指定需要hook的類,以%end結(jié)尾
%orig 在%hook內(nèi)部使用,執(zhí)行hook住方法的原代碼
%new: 在%hook內(nèi)部使用,給class添加新方法,與class_addMethod相同; 在Category中添加方法的區(qū)別: Category為編譯時添加,class_addMethod為d動態(tài)添加
warm: 添加的方法需要在@interface中聲明
%c:獲取一個類,等同于objc_getClass、NSClassFromString
定制Tweak.xm
- 以微信中的設置頁面為例:
NewSettingViewController是微信的設置頁面,我們hook它的viewDidAppear:方法
%hook NewSettingViewController
- (void)viewDidAppear:(BOOL)animated {
%orig;
[self helloWorld];
}
%new
- (void)helloWorld {
UIAlertController *alc = [UIAlertController alertControllerWithTitle:@"hello world" message:nil preferredStyle:UIAlertControllerStyleActionSheet];
[alc addAction:[UIAlertAction actionWithTitle:@"ok" style:UIAlertActionStyleDefault handler:NULL]];
[alc addAction:[UIAlertAction actionWithTitle:@"cancel" style:UIAlertActionStyleCancel handler:NULL]];
[self presentViewController:alc animated:YES completion:NULL];
}
%end
- 編寫代碼完成后,使用
make package命令對其進行編譯,注意:執(zhí)行命令前先cd到項目文件夾
如果是在之前編寫的基礎上行修改,則需要重新編譯, 需要先使用make clean,清理make, make package生成的文件
執(zhí)行完成后,會在項目多兩個文件夾:.theos和obj,那么在.theos->obj->debug中有一個WeChatPlugin.dylib就是我們生成的dylib動態(tài)庫;
修改生成的.dylib動態(tài)庫中的依賴
- 通過 otool -L命令查看生成的.dylib文件
結(jié)果中的一段/Library/Frameworks/CydiaSubstrate.framework/CydiaSubstrate (offset 24)
可以看到這里還有對CydiaSubstrate的依賴,這是不行的 , 這個是theos在越獄機上特有的, 在非越獄機上需要更改此依賴 - 修改依賴,將libsubstrate.dylib文件(該文件應該在/opt/thoes/lib/目錄下),拷貝到與你生成的的.dylib一個目錄下,通過下面的指令修改依賴,
cd /Users/mofeini/Desktop/weChat/Project/wechatplugin/.theos/obj/debug
install_name_tool -change /Library/Frameworks/CydiaSubstrate.framework/CydiaSubstrate @loader_path/libsubstrate.dylib WeChatPlugin.dylib
然后重新查看WeChatPlugin.dylib,會發(fā)現(xiàn)依賴已經(jīng)修改成@loader_path/libsubstrate.dylib (offset 24)
重新簽名自制的.dylib 和libsubstrate.dylib(很重要)
我們需要把生成的dylib和libsubstrate.dylib文件copy到WeChat.app中,然后用codesign開始簽名
codesign -f -s 'iPhone Developer: Xiaoyuan Yang (29H47J82NP)' (自己的證書名)
添加可執(zhí)行文件的依賴動態(tài)注入
此處用到是insert_dylib,先從gitHUb下載insert_dylib,編譯后將 insert_dylib 放到/usr/local/bin目錄中(不放到此目錄中需要使用./insert_dylib,放在目錄中后只需要使用insert_dylib);
再將自制的dylib和libsubstrate.dylib拷貝到WeChat.app包中,執(zhí)行以下命令:
cd /Users/mofeini/Desktop/weChat/WeChat-6.5.18/Payload/WeChat.app/
insert_dylib @executable_path/WeChatPlugin.dylib WeChat
以下為執(zhí)行步驟
localhost:debug apple$ insert_dylib @executable_path/wechatplugin.dylib /Users/mofeini/Desktop/weChat/WeChat.app/WeChat
Binary is a fat binary with 2 archs.
LC_CODE_SIGNATURE load command found. Remove it? [y/n] n
LC_CODE_SIGNATURE load command found. Remove it? [y/n] n
Added LC_LOAD_DYLIB to all archs in /Users/mofeini/Desktop/weChat/WeChat.app/WeChat_patched
會生成一個WeChat_patched 這個就是修改了依賴關(guān)系的二進制文件,
注意替換
注意: 別忘了之前將 自制的.dylib libsubstrate.dylib 拷貝進WeChat.app
如果WeChat_patched在WeChat.app中,還要將WeChat_patched拷貝進WeChat.app中 替換原來的WeChat, 把WeChat_patched的名字改回來WeChat
應用重簽名
將脫殼后的app進行重簽名,我使用的是上面步驟中從pp助手下載的越獄版本的微信,如果使用加密的App重簽名成功安到設備上也會閃退。
應用重簽名的方法,我使用了ios-app-signer
以下是一些錯誤解決
使用以下命令編譯時候
make package
第一次會報以下錯誤
> Making stage for tweak ioswechat…
dpkg-deb: error: obsolete compression type 'lzma'; use xz instead
Type dpkg-deb --help for help about manipulating *.deb files;
Type dpkg --help for help about installing and deinstalling packages.
make: *** [internal-package] Error 2
查找了一些資料后發(fā)現(xiàn),這個錯誤是dpkg引起的,隨著版本的升級,打包格式發(fā)生了變化
dpkg-deb: error: obsolete compression type 'lzma'; use xz instead
解決方案是按以下路徑找到該文件修改其內(nèi)容
/opt/theos/makefiles/package/deb.mk
找到第六行
_THEOS_PLATFORM_DPKG_DEB_COMPRESSION ?= lzma
將其改為
_THEOS_PLATFORM_DPKG_DEB_COMPRESSION ?= xz