微信公眾號:passerbycrk-weixin
如有問題或建議,請公眾號留言
複習iOS逆向知識,以微信消息防撤回為例,一步一步分析調試,到完成插件注入。
環境配置越獄iPhone 5s (iOS 10.1.1) 並安裝了以下軟體:
OpenSSH: 實現在越獄手機上遠程進行 ssh 服務,通過 ssh,即可以通過終端連接 iPhone 進行控制。
dumpdecrypted: 砸殼工具。
Cycript: 腳本語言工具,用於 hook 正在運行的進程,並實時注入代碼。
debugserver: 用於連接手機進行 lldb 調試的工具。用 Xcode 在手機上進行 app 調試即可在iPhone目錄的 /Developer/usr/bin/ 中生成。
蘋果電腦 (macOS High Sierra 10.13.3) 並安裝了以下軟體:
frida-ios-dump: 砸殼利器。
class_dump: dump 目標對象的 class 信息的工具。
Hopper_Disassembler: 靜態分析工具。
usbmuxd: 埠轉發,可以讓我們通過 usb 連接手機進行 ssh、lldb 調試等。
lldb: 調試神器,用過的都說好 (/Applications/Xcode.app/Contents/Developer/usr/bin/lldb)。
theos: 插件編寫IDE。
推薦使用frida-ios-dump,下面會分別以frida-ios-dump和dumpdecrypted為例進行砸殼,實際情況任選一個使用即可。
frida-ios-dump1.獲取app信息 frida-ios-dump -l
# frida-ios-dump -l
PID Name Identifier
---- -
92311 微信 com.tencent.xin
- App Store com.apple.AppStore
- Cydia com.saurik.Cydia
- FaceTime com.apple.facetime
- Safari com.apple.mobilesafari
...
2.根據app信息進行砸殼 frida-ios-dump [bundle id|name]
Start the target app com.tencent.xin
Dumping 微信 to /var/folders/7b/c3cyxy3j0t7_tgnt0dh5wc240000gn/T
start dump /var/containers/Bundle/Application/FC7574FD-C99D-49DE-8130-AF824051424A/WeChat.app/WeChat
WeChat.fid: 100%|█████████████████████████████████████████████████| 71.8M/71.8M [00:06<00:00, 11.1MB/s]
start dump /private/var/containers/Bundle/Application/FC7574FD-C99D-49DE-8130-AF824051424A/WeChat.app/Frameworks/WCDB.framework/WCDB
WCDB.fid: 100%|███████████████████████████████████████████████████| 2.49M/2.49M [00:00<00:00, 9.10MB/s]
start dump /private/var/containers/Bundle/Application/FC7574FD-C99D-49DE-8130-AF824051424A/WeChat.app/Frameworks/MMCommon.framework/MMCommon
MMCommon.fid: 100%|█████████████████████████████████████████████████| 979k/979k [00:00<00:00, 7.56MB/s]
start dump /private/var/containers/Bundle/Application/FC7574FD-C99D-49DE-8130-AF824051424A/WeChat.app/Frameworks/MultiMedia.framework/MultiMedia
MultiMedia.fid: 100%|█████████████████████████████████████████████| 6.61M/6.61M [00:00<00:00, 10.8MB/s]
start dump /private/var/containers/Bundle/Application/FC7574FD-C99D-49DE-8130-AF824051424A/WeChat.app/Frameworks/mars.framework/mars
mars.fid: 100%|███████████████████████████████████████████████████| 8.49M/8.49M [00:00<00:00, 11.2MB/s]
network_setting.html: 139MB [00:25, 5.62MB/s]
0.00B [00:00, ?B/s]
Generating "微信.ipa"
砸殼成功後會在當前目錄下生成去殼後的安裝包微信.ipa。
dumpdecrypted1.獲取app安裝路徑 ps -e | grep /var/
# ps -e | grep /var/
92817 ?? 0:16.99 /var/containers/Bundle/Application/FC7574FD-C99D-49DE-8130-AF824051424A/WeChat.app/WeChat
92867 ?? 0:00.20 /private/var/containers/Bundle/Application/FD3685C9-80D5-419E-B106-DF466545003E/News.app/PlugIns/NewsNotificationServiceExtension.appex/NewsNotificationServiceExtension
93182 ttys000 0:00.02 grep /var/
2.根據app安裝路徑進行砸殼 DYLD_INSERT_LIBRARIES=/path/to/dumpdecrypted.dylib /path/to/app/executablename
# DYLD_INSERT_LIBRARIES=/path/to/dumpdecrypted.dylib /var/containers/Bundle/Application/FC7574FD-C99D-49DE-8130-AF824051424A/WeChat.app/WeChat
mach-o decryption dumper
DISCLAIMER: This tool is only meant for security research purposes, not for application crackers.
[+] detected 64bit ARM binary in memory.
[+] offset to cryptid found: @0x1000b4cf8(from 0x1000b4000) = cf8
[+] Found encrypted data at address 00004000 of length 59457536 bytes - type 1.
[+] Opening /private/var/containers/Bundle/Application/FC7574FD-C99D-49DE-8130-AF824051424A/WeChat.app/WeChat for reading.
[+] Reading header
[+] Detecting header type
[+] Executable is a plain MACH-O image
[+] Opening WeChat.decrypted for writing.
[+] Copying the not encrypted start of the file
[+] Dumping the decrypted data into the file
[+] Copying the not encrypted remainder of the file
[+] Setting the LC_ENCRYPTION_INFO->cryptid to 0 at offset cf8
[+] Closing original file
[+] Closing dump file
成功後會在當前目錄下生成WeChat.decrypted,也就是砸殼後的執行文件。
分析調試Cycript (動態分析工具)官網: http://www.cycript.org/
Cycript允許開發人員調試和修改iOS和Mac OS X上運行的應用程式。
Cycript是一個理解Objective-C語法的javascript解釋器,它能夠掛鈎正在運行的進程,能夠在運行時修改應用的很多東西。
調試命令 cycript [-p <pid|name>]
可以先通過 ps -e | grep /var命令找到對應pid
# cycript -p WeChat
cy# [[[UIWindow keyWindow] rootViewController] _printHierarchy].toString()
`<MMTabBarController 0x14606ae00>, state: appeared, view: <UILayoutContainerView 0x145da6420>
| <MMUINavigationController 0x146179800>, state: appeared, view: <UILayoutContainerView 0x145d99460>
| | <NewMainFrameViewController 0x1460ff600>, state: disappeared, view: <MMUIHookView 0x145d8efa0> not in the window
| | <BaseMsgContentViewController 0x146983e00>, state: appeared, view: <UIView 0x145d7d440>
| <MMUINavigationController 0x14618b000>, state: disappeared, view: <UILayoutContainerView 0x145d9dda0> not in the window
| | <ContactsViewController 0x146191000>, state: disappeared, view: (view not loaded)
| <MMUINavigationController 0x14613a800>, state: disappeared, view: <UILayoutContainerView 0x145da0ec0> not in the window
| | <FindFriendEntryViewController 0x146859200>, state: disappeared, view: (view not loaded)
| <MMUINavigationController 0x1461a4e00>, state: disappeared, view: <UILayoutContainerView 0x145da3950> not in the window
| | <MoreViewController 0x146172c00>, state: disappeared, view: (view not loaded)`
介紹: http://iphonedevwiki.net/index.php/Logify
Logify是一種實用工具,可以將類的頭文件(.h文件)作為輸入,並生成MobileSubstrate文件(.xm文件)。
作用:能自動Hook該類所有的方法,並生成列印日誌信息代碼,方便開發人員看到在使用過程中調用了某些方法。
# logify.pl BaseMsgContentViewController.h > Tweak.xm
介紹: http://iphonedevwiki.net/index.php/Logos
可以在MobileSubstrate文件(.xm文件)中使用的語法
Theos-NIC介紹: http://iphonedevwiki.net/index.php/NIC
Theos NIC templates內置了多種種Theos工程類型的模板。
用於編寫iOS越獄設備的插件。
創建一個追蹤logify的插件工程:
# nic.pl
NIC 2.0 - New Instance Creator
[1.] iphone/activator_event
[2.] iphone/application_modern
[3.] iphone/cydget
[4.] iphone/flipswitch_switch
[5.] iphone/framework
[6.] iphone/ios7_notification_center_widget
[7.] iphone/library
[8.] iphone/notification_center_widget
[9.] iphone/preference_bundle_modern
[10.] iphone/tool
[11.] iphone/tweak
[12.] iphone/xpc_service
Choose a Template (required): 11
Project Name (required): TWeak-Logify-WX
Package Name [com.yourcompany.tweak-logify-wx]: cn.theos.tweak.wx.logify
Author/Maintainer Name [dabing]: author name
[iphone/tweak] MobileSubstrate Bundle filter [com.apple.springboard]: com.tencent.xin
[iphone/tweak] List of applications to terminate upon installation (space-separated, '-' for none) [SpringBoard]:
Instantiating iphone/tweak in tweaklogifywx/...
Done.
工程文件結構如下:
# tree
.
└── tweaklogifywx
├── Makefile
├── TWeakLogifyWX.plist
├── Tweak.xm
└── control
將Logify生成的Tweak.xm覆蓋掉工程中的Tweak.xm
用文本編輯器打開Makefile文件,在文件的開頭增加iOS設備的ip地址和ssh埠等信息:
THEOS_DEVICE_IP = localhost
THEOS_DEVICE_PORT = 2333
ARCHS = arm64
TRAGET = iphone:latest:9.0
include $(THEOS)/makefiles/common.mk
TWEAK_NAME = TWeakLogifyWX
TWeakLogifyWX_FILES = Tweak.xm
logifyWX_FRAMEWORKS = UIKit Foundation CoreGraphics
logifyWX_CFLAGS = -fobjc-arc
include $(THEOS_MAKE_PATH)/tweak.mk
after-install::
install.exec "killall -9 SpringBoard"
編譯打包安裝:
# make package install
> Making all for tweak TWeakLogifyWX…
==> Preprocessing Tweak.xm…
==> Compiling Tweak.xm (arm64)…
==> Linking tweak TWeakLogifyWX (arm64)…
clang: warning: libstdc++ is deprecated; move to libc++ with a minimum deployment target of iOS 7 [-Wdeprecated]
==> Generating debug symbols for TWeakLogifyWX (arm64)…
warning: no debug symbols in executable (-arch arm64)
==> Merging tweak TWeakLogifyWX…
==> Signing TWeakLogifyWX…
> Making stage for tweak TWeakLogifyWX…
dm.pl: building package `cn.theos.tweak.wx.logify:iphoneos-arm' in `./packages/cn.theos.tweak.wx.logify_0.0.1-1+debug_iphoneos-arm.deb'
==> Installing…
Selecting previously unselected package cn.theos.tweak.wx.logify.
(Reading database ... 2279 files and directories currently installed.)
Preparing to unpack /tmp/_theos_install.deb ...
Unpacking cn.theos.tweak.wx.logify (0.0.1-1+debug) ...
Setting up cn.theos.tweak.wx.logify (0.0.1-1+debug) ...
install.exec "killall -9 SpringBoard"
注意:一般該Tweak.xm仍然無法執行,需要進行修改:
去掉 .cxx_destruct 方法
將 HBLogDebug 改為 NSLog
去掉所有的 weak 屬性
將頭文件(.h文件)中的@class和@protocol聲明都拷貝至Tweak.xm (或去掉所有delegate並將所有參數對象類型改為id)。
安裝成功後會在設備中新增以下兩個文件:
/Library/MobileSubstrate/DynamicLibraries/TWeakLogifyWX.dylib
/Library/MobileSubstrate/DynamicLibraries/TWeakLogifyWX.plist
打開Cydia-已安裝可以看到插件已經安裝成功:
idevicesyslog (iOS日誌查看工具)介紹: https://github.com/libimobiledevice/libimobiledevice
是libimobiledevice下的一個子工具,可以實時追蹤iOS設備日誌。
# idevicesyslog | grep "BaseMsgContentViewController"
重新運行app,執行收到消息和撤回消息的case,可以分別獲取兩份log:
接收消息log
撤回消息log整理後log對比可以發現可疑方法調用
-[BaseMsgContentViewController OnMsgRevoked:n64MsgId:]
介紹: http://stevenygard.com/projects/class-dump/
這是一個檢查存儲在Mach-O文件Objective-C運行時信息的命令行實用工具。
能生成classes、categories、protocols定義的頭文件(.h文件)。(與otool -ov命令獲取的信息類似,但可讀性更高)
# class-dump -HA WeChat -o ./Headers
獲得頭文件以及方法的IMP address
例如:-[BaseMsgContentViewController OnMsgRevoked:n64MsgId:] // IMP=0x0000000102129454
Hopper Disassembler (分析工具)介紹: https://www.hopperapp.com
是一款32位和64位的二進位反彙編器,反編譯和調試。可以使用此工具拆開你想要的任何二進位。
使用方法很簡單:將二進位文件拖入軟體中,等待處理完成即可。
(完整解析微信app需要很長一段時間,可以前置該流程進行解析處理)
lldb+debugserver (遠程調試)
打開微信後,在連接至設備的控制臺中鍵入debugserver *:1234 -a "WeChat"啟動debugserver。
2.從控制臺打開新窗口,鍵入lldb進入調試,再鍵入debugserver *:1234 -a "WeChat"連接1234埠。
(此處連接需要一段時間,連接上後鍵入c(continue)命令後app就可以正常運行了)
連接成功後lldb窗口會出現以下內容:
(lldb) process connect connect:
Process 73244 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
frame #0: 0x00000001900f5164 libsystem_kernel.dylib`__fcntl + 8
libsystem_kernel.dylib`__fcntl:
-> 0x1900f5164 <+8>: b.lo 0x1900f517c ; <+32>
0x1900f5168 <+12>: stp x29, x30, [sp, #-0x10]!
0x1900f516c <+16>: mov x29, sp
0x1900f5170 <+20>: bl 0x1900d9e8c ; cerror
Target 0: (WeChat) stopped.
(lldb) c
Process 73244 resuming
獲取aslr的offset。(每次啟動都不同)
其中第一列[X]是image的序號,不用管;第二列是aslr的offset(也就是對應image的虛擬內存slide);第三列是image的全路徑和slide之後的基地址,也不用管~所以第二列就是我們需要的信息。
(lldb) image list -o -f
[ 0] 0x0000000000048000 /var/containers/Bundle/Application/FC7574FD-C99D-49DE-8130-AF824051424A/WeChat.app/WeChat(0x0000000100048000)
[ 1] 0x0000000104a20000 /Users/passerbycrk/Library/Developer/Xcode/iOS DeviceSupport/10.1.1 (14B100)/Symbols/usr/lib/dyld
[ 2] 0x0000000104970000 /Library/MobileSubstrate/MobileSubstrate.dylib(0x0000000104970000)
[ 3] 0x000000000fab4000 /Users/passerbycrk/Library/Developer/Xcode/iOS DeviceSupport/10.1.1 (14B100)/Symbols/System/Library/Frameworks/CallKit.framework/CallKit
[ 4] 0x000000000fab4000 /Users/passerbycrk/Library/Developer/Xcode/iOS DeviceSupport/10.1.1 (14B100)/Symbols/System/Library/Frameworks/Accelerate.framework/Accelerate
[ 5] 0x000000000fab4000 /Users/passerbycrk/Library/Developer/Xcode/iOS DeviceSupport/10.1.1 (14B100)/Symbols/System/Library/Frameworks/Intents.framework/Intents
[ 6] 0x000000000fab4000 /Users/passerbycrk/Library/Developer/Xcode/iOS DeviceSupport/10.1.1 (14B100)/Symbols/usr/lib/libbz2.1.0.dylib
[ 7] 0x0000000104aa4000 /private/var/containers/Bundle/Application/FC7574FD-C99D-49DE-8130-AF824051424A/WeChat.app/Frameworks/WCDB.framework/WCDB(0x0000000104aa4000)
[ 8] 0x000000000fab4000 /Users/passerbycrk/Library/Developer/Xcode/iOS DeviceSupport/10.1.1 (14B100)/Symbols/System/Library/Frameworks/JavaScriptCore.framework/JavaScriptCore
...
得到aslr的offset:0x0000000000048000 (不同的發布版本偏移量不一定相同)
再根據class-dump獲得的頭文件,找到對應的方法,在後面可以看到IMP的offset。
-[BaseMsgContentViewController OnMsgRevoked:n64MsgId:] // IMP=0x0000000102129454
通過br命令設置斷點(aslr_offset + IMP_offset)
(lldb) br s -a '0x0000000000048000+0x0000000102129454'
Breakpoint 1: where = WeChat`ClearDataItem::compareTime(std::__1::shared_ptr<ClearDataItem> const&, std::__1::shared_ptr<ClearDataItem> const&) + 4373492, address = 0x0000000102171454
重新操作消息撤回case後,進入斷點,鍵入bt命令:
Process 73244 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
frame #0: 0x0000000102171454 WeChat`ClearDataItem::compareTime(std::__1::shared_ptr<ClearDataItem> const&, std::__1::shared_ptr<ClearDataItem> const&) + 4373492
WeChat`ClearDataItem::compareTime:
-> 0x102171454 <+4373492>: stp x24, x23, [sp, #-0x40]!
0x102171458 <+4373496>: stp x22, x21, [sp, #0x10]
0x10217145c <+4373500>: stp x20, x19, [sp, #0x20]
0x102171460 <+4373504>: stp x29, x30, [sp, #0x30]
Target 0: (WeChat) stopped.
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
* frame #0: 0x0000000102171454 WeChat`ClearDataItem::compareTime(std::__1::shared_ptr<ClearDataItem> const&, std::__1::shared_ptr<ClearDataItem> const&) + 4373492
frame #1: 0x0000000104d5b980 MMCommon`_callExtension + 480
frame #2: 0x0000000102ccfaac WeChat`ClearDataItem::compareTime(std::__1::shared_ptr<ClearDataItem> const&, std::__1::shared_ptr<ClearDataItem> const&) + 16294476
frame #3: 0x0000000102cda958 WeChat`ClearDataItem::compareTime(std::__1::shared_ptr<ClearDataItem> const&, std::__1::shared_ptr<ClearDataItem> const&) + 16339192
frame #4: 0x0000000102cdb60c WeChat`ClearDataItem::compareTime(std::__1::shared_ptr<ClearDataItem> const&, std::__1::shared_ptr<ClearDataItem> const&) + 16342444
frame #5: 0x0000000104d5b980 MMCommon`_callExtension + 480
frame #6: 0x0000000102f89414 WeChat`ClearSessionItem::compareVideo(std::__1::shared_ptr<ClearSessionItem> const&, std::__1::shared_ptr<ClearSessionItem> const&) + 1516048
...
python+Hopper Disassembler 獲取調用棧
>>> hex(0x0000000102171454-0x0000000000048000)
'0x102129454'
>>> hex(0x0000000102ccfaac-0x0000000000048000)
'0x102c87aac'
創建插件工程
# nic.pl
NIC 2.0 - New Instance Creator
[1.] iphone/activator_event
[2.] iphone/application_modern
[3.] iphone/cydget
[4.] iphone/flipswitch_switch
[5.] iphone/framework
[6.] iphone/ios7_notification_center_widget
[7.] iphone/library
[8.] iphone/notification_center_widget
[9.] iphone/preference_bundle_modern
[10.] iphone/tool
[11.] iphone/tweak
[12.] iphone/xpc_service
Choose a Template (required): 11
Project Name (required): Tweak-crack-WX
Package Name [com.yourcompany.tweak-crack-wx]:
Author/Maintainer Name [dabing]:
[iphone/tweak] MobileSubstrate Bundle filter [com.apple.springboard]: com.tencent.xin
[iphone/tweak] List of applications to terminate upon installation (space-separated, '-' for none) [SpringBoard]:
Instantiating iphone/tweak in tweakcrackwx/...
Done.
Tweak.xm
%hook CMessageMgr
- (void)onRevokeMsg:(id)arg1 {
}
%end
安裝
> Making all for tweak TweakcrackWX…
make[2]: Nothing to be done for `internal-library-compile'.
> Making stage for tweak TweakcrackWX…
dm.pl: building package `com.yourcompany.tweak-crack-wx:iphoneos-arm' in `./packages/com.yourcompany.tweak-crack-wx_0.0.1-2+debug_iphoneos-arm.deb'
==> Installing…
Selecting previously unselected package com.yourcompany.tweak-crack-wx.
(Reading database ... 2277 files and directories currently installed.)
Preparing to unpack /tmp/_theos_install.deb ...
Unpacking com.yourcompany.tweak-crack-wx (0.0.1-2+debug) ...
Setting up com.yourcompany.tweak-crack-wx (0.0.1-2+debug) ...
install.exec "killall -9 SpringBoard"
打開Cydia-已安裝可以看到插件已經安裝成功:
接下來重新運行微信,試試消息撤回的case,發現消息撤回已經被阻止了,任務完成~
(文章特意選了個軟柿子案例,實際情況可能不會這麼容易找到關鍵函數,需要反覆調試驗證)