學(xué)習(xí)是一個(gè)循序漸進(jìn)的過程斋日,其實(shí)這句話是有道理的,O(∩_∩)O哈哈~墓陈,本文是上一篇文章的續(xù)恶守,上篇文章主要是一些基本的工具安裝第献,以及使用,本篇文章做進(jìn)一步的App調(diào)試兔港。
- 端口映射
在前面我們說到庸毫,如何將iphone的22端口(SSH端口)映射到Mac本地的10010端口, 那么登錄電腦上的10010就相當(dāng)于鏈接到手機(jī)的22端口了衫樊,如果在 usb.sh腳本中后面加上一組映射飒赃,如下:
cd /Users/cuilinhao/Desktop/usbmuxd-1.0.8
python tcprelay.py -t 22:10010 10011:10011
則此時(shí),端口會(huì)做兩次映射科侈,訪問電腦10011 就是訪問手機(jī)的10011载佳,當(dāng)然你也可以寫成不同的,這里為了方便映射臀栈,才設(shè)置手機(jī)端和電腦端為同一個(gè)端口10011
- bebugServer 簽名
debugserver是運(yùn)行在ios上蔫慧,作為服務(wù)端,實(shí)際上執(zhí)行LLDB(作為客戶端)傳過來的沒命令权薯,再把執(zhí)行結(jié)果反饋給LLDB,顯示給用戶姑躲,即所謂的”遠(yuǎn)程調(diào)試”。在默認(rèn)情況下盟蚣,ios上并沒有安裝debugserver黍析。需要設(shè)備連接Xcode,在window-->Devices菜單中增加此設(shè)備后屎开,debugserver才會(huì)被Xcode安裝到IOS設(shè)備的/Developer/usr/bin/目錄下翻伺。注意:由于缺少task_for_pid權(quán)限驹马,通過Xcode安裝的debugserver只能調(diào)試自己的APP慷彤。為了逆向获搏,我們需要對(duì)debugserver進(jìn)行相關(guān)配置,使我們可以調(diào)試別人的APP如孝。
通過iFunBox找到Devicce/Developer/usr/bin 先找到debugserver, 并拷貝到桌面,由于debugserver 權(quán)限是不足的娩贷,故需要簽名第晰,先把debugserver拿到桌面,重新簽名彬祖,如果希望調(diào)試其他App茁瘦,則需要對(duì)debugserver重新簽名,簽上2個(gè)調(diào)試相關(guān)的權(quán)限
- get-task-allow
- task_for_pid_allow
簽名要三步,具體操作如下:
- 使用命令 -e 將debugserver 導(dǎo)出為debugserver.entitlements
ldid -e debugserver > debugserver.entitlements
- 雙擊打開debugserver.entitlements 添加權(quán)限
- 使用命令-S 簽名
cuilinhao$ ldid -Sdebugserver.entitlements debugserver
- 將簽名后的文件放到 usr/bin目錄下即可储笑。
測(cè)試:
Zhanghua123:~ root# debugserver
-sh: /usr/bin/debugserver: Permission denied
Zhanghua123:~ root#
//權(quán)限不夠 使用chmod +x
Zhanghua123:~ root# chmod +x /usr/bin/debugserver
- debugserver鏈接WiFi伴侶App甜熔,如果出現(xiàn)Failed to get connection from a remote gdb process.連接失敗,則可以試著重啟手機(jī)(reboot)或者killall SpringBoard突倍,在下面debugserver進(jìn)行連接時(shí)腔稀,*為主機(jī)地址盆昙,就是手機(jī),: 是端口號(hào)
Zhanghua123:~ root# debugserver *:10011 -a wifibanlv
debugserver-@(#)PROGRAM:debugserver PROJECT:debugserver-360.0.26.1
for arm64.
Attaching to process wifibanlv...
Listening to port 10011 for a connection from *...
- LLDB命令調(diào)試
1)啟動(dòng)LLDB
$lldb
(lldb)
2)連接debugserver服務(wù)
(lldb) process connect connect:// 手機(jī)IP地址:debugserver 服務(wù)的端口號(hào)
3)使用LLDB的c命令讓程序先繼續(xù)運(yùn)行
(lldb) c
如下圖:
4)LLDB 指令
補(bǔ)充:
- breakpoint list 查看斷點(diǎn)編號(hào)
- register read 讀出地址
- po $x0: 打印方法調(diào)用者
- x/s $x1: 打印方法名
- po $x2: 打印參數(shù)(以此類推焊虏,x3, x4也可能是參數(shù))
- 如果是非arm64淡喜, 寄存器就是r0, r1, r2
Hopper + LLDB 調(diào)試
在之前是有介紹過Hopper的,LLDB連接上debugserver后诵闭,我們首先使用下方的命令來查看當(dāng)前進(jìn)程中的所有模塊炼团,從這些輸出信息中我們能找到“WeChat”這個(gè)進(jìn)程在虛擬內(nèi)存相對(duì)于模塊基地址的偏移量
執(zhí)行 image list -o -f 命令可以看到如下結(jié)果
左邊紅框就是ASLR偏移量(隨機(jī)偏移量),ASLR偏移量其實(shí)就是虛擬內(nèi)存的地址相對(duì)于模塊基地址的偏移量
右邊紅框中的地址就是偏移后的地址
- 模塊在內(nèi)存中的起始地址----模塊基地址
- ASLR偏移 ---- 虛擬內(nèi)存起始地址與模塊基地址的偏移量
從下方的輸出結(jié)果我們可以知道:
ASLR偏移量 = 0x5b000, 模塊偏移后基地址 = 0x5f000
=====
下方是使用Hopper打開的解密后的微信的安裝包
其起始地址從下圖中我們可以看出是0x4000, 這個(gè)地址就是模塊偏移前的地址疏尿,也就是模塊在虛擬內(nèi)存中的起始地址瘟芝。從Hopper中我們可以知道:模塊偏移前的基地址=0x4000
從上面兩組數(shù)據(jù)我們可以得出:
模塊偏移后的基地址(0x5f000)= ASLR偏移量(0x5b000)+ 模塊偏移前基地址(0x4000)
因?yàn)镠opper中顯示的都是“ 模塊偏移前基地址”,而LLDB要操作的都是“模塊偏移后的基地址”
所以從Hopper到LLDB褥琐,我們要做一個(gè)地址偏移量的轉(zhuǎn)換
當(dāng)然锌俱,有一點(diǎn)需要注意的是Hopper與LLDB所選擇的AMR架構(gòu)的位數(shù)得一致,要么是32位踩衩,要么都是64位嚼鹉,如果位數(shù)不匹配的話,那么計(jì)算出來的內(nèi)存地址肯定是不對(duì)的驱富。
以上是用到的基本知識(shí)锚赤,然后我們就來操作一波,我們以WiFi伴侶為例褐鸥,來查看WiFi伴侶獲取的mac地址的相關(guān)方法线脚。
PS:在進(jìn)行斷點(diǎn)調(diào)試時(shí),如果有對(duì)要提示的App進(jìn)行Tweak文件叫榕,請(qǐng)刪除浑侥,如果不刪除,斷點(diǎn)會(huì)添加不上晰绎。
操作如下:
- usb登錄
cd /Users/cuilinhao/Desktop/usbmuxd-1.0.8
python tcprelay.py -t 22:10010 10011:10011
另開一個(gè)終端
ssh root@localhost -p 10010
- debugServer 連接
Zhanghua123:~ root# debugserver *:10011 -a wifibanlv
debugserver-@(#)PROGRAM:debugserver PROJECT:debugserver-360.0.26.1
for arm64.
Attaching to process wifibanlv...
Listening to port 10011 for a connection from *...
Waiting for debugger instructions for process 0.
- lldb 斷點(diǎn)調(diào)試
(lldb) process connect connect://localhost:10011
Process 3667 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
frame #0: 0x000000018addef88 libobjc.A.dylib`objc_msgSend + 40
libobjc.A.dylib`objc_msgSend:
-> 0x18addef88 <+40>: br x17
0x18addef8c <+44>: cbz x9, 0x18addf260 ; _objc_msgSend_uncached
0x18addef90 <+48>: cmp x12, x10
0x18addef94 <+52>: b.eq 0x18addefa0 ; <+64>
Target 0: (wifibanlv) stopped.
(lldb) c
Process 3667 resuming
(lldb)
ps: 上面的步驟一共開了三個(gè)終端
- 通過Reveal 找到控制器
通過Reveal 可以看到要找的類是WBNetDetectViewController寓落,頭文件如下
#import "WBBaseViewController.h"
@class IPUserModel, NSMutableArray, NetDetectTool, WBNetDetectView, WBTableViewModel;
@interface WBNetDetectViewController : WBBaseViewController
{
NSMutableArray *_foundDevicesList;
WBNetDetectView *_selfView;
WBTableViewModel *_tableModel;
NetDetectTool *_detectTool;
IPUserModel *_selectModel;
}
@property(retain, nonatomic) IPUserModel *selectModel; // @synthesize selectModel=_selectModel;
@property(retain, nonatomic) NetDetectTool *detectTool; // @synthesize detectTool=_detectTool;
@property(retain, nonatomic) WBTableViewModel *tableModel; // @synthesize tableModel=_tableModel;
@property(retain, nonatomic) WBNetDetectView *selfView; // @synthesize selfView=_selfView;
@property(retain, nonatomic) NSMutableArray *foundDevicesList; // @synthesize foundDevicesList=_foundDevicesList;
- (void).cxx_destruct;
- (void)handleMacNameResult:(id)arg1;
- (void)completeNetDetectResult;
- (void)openAntiRubNetworkGuide;
- (id)resultSection;
- (void)loadTableView;
- (void)startNetDetect;
- (void)backToPreViewController;
- (void)triggerRefreshNetDetect;
- (void)setupTableHeader;
- (void)didReceiveMemoryWarning;
- (void)viewWillAppear:(_Bool)arg1;
- (void)viewDidLoad;
- (_Bool)fd_prefersNavigationBarHidden;
- (void)loadView;
@end
因?yàn)槟嫦蛭覀冎荒軐?dǎo)出一些類的頭文件,所以在想找到自己想要的數(shù)據(jù)時(shí)荞下,也需要猜測(cè)伶选,此時(shí)在WBNetDetectViewController中,看到handleMacNameResult這個(gè)方法尖昏,很可能是有我們要的mac地址的數(shù)據(jù)仰税,so,我們可以先tweak找個(gè)類中的handleMacNameResult抽诉,打印一下arg參數(shù)看到確實(shí)是我們要找的
%hook WBNetDetectViewController
- (void)handleMacNameResult:(id)arg1
{
NSLog(@"---mac------%@", arg1);
打印結(jié)果
---mac------(
"<WiFiMacModel: 0x1708530e0> {\n mac = \"C0:CE:CD:22:91:3C\";\n macname = \"Apple, Inc.\";\n macname_zh = \"Apple\U82f9\U679c\";\n nickname = <nil>;\n pic = \"http://static.wlanbanlv.com/3de765ea1fa9cf94c3cff3b2ded6bdcddea09461.png\"\n}",
"<WiFiMacModel: 0x17084eac0> {\n mac = \"C8:1E:E7:51:52:B3\";\n macname = \"Apple, Inc.\";\n macname_zh = \"Apple\U82f9\U679c\";\n nickname = <nil>;\n pic = \"http://static.wlanbanlv.com/3de765ea1fa9cf94c3cff3b2ded6bdcddea09461.png\"\n}",
"<WiFiMacModel: 0x1708512b0> {\n mac = \"B8:BC:1B:5B:58:AB\";\n macname = \"HUAWEI TECHNOLOGIES CO.,LTD\";\n macname_zh = \"Huawei\U534e\U4e3a\";\n nickname = <nil>;\n pic = \"http://static.wlanbanlv.com/06ab4e63498a29ac8b5a2d9c9e869dc22ad74697.png\"\n}"
)
}
%end
上面打印的結(jié)果可以通過mac自帶的控制臺(tái)來打印陨簇,老鐵可以一試,這個(gè)是個(gè)好東東~你懂得
- 通過Hopper找到handleMacNameResult這個(gè)方法
- 獲取基地址
(lldb) image list -o -f | grep wifibanlv
[ 0] 0x00000000000a0000 /var/containers/Bundle/Application/759BFDCF-F926-42DC-A271-4F4D15C5818D/wifibanlv.app/wifibanlv(0x00000001000a0000)
- 設(shè)置斷點(diǎn)迹淌,利用公式
模塊偏移后的基地址(0x5f000)= ASLR偏移量(0x5b000)+ 模塊偏移前基地址(0x4000)
此時(shí)的ASLR偏移量 是0x00000000000a0000河绽,模塊偏移前基地址是0x00000001001bbc14
breakpoint set -a 0x00000000000a0000+0x00000001001bbc14
- 查看地址
register read
General Purpose Registers:
x0 = 0x0000000129abe4b0
x1 = 0x00000001009fa67c "handleMacNameResult:"
x2 = 0x0000000170e5a760
x3 = 0x000000016fd5e978
x4 = 0x0000000000000010
x5 = 0x0000000000000068
x6 = 0x0000000170e5a190
x7 = 0x0000000000000000
x8 = 0x0000000100d9a000 "splashAd"
x9 = 0x00000001009fa67c "handleMacNameResult:"
x10 = 0x000000012811ec00
x11 = 0x000000b1000000ff
x12 = 0x000000012811f3c0
x13 = 0x000005a100dc312f
x14 = 0x0000000000000000
- 查看參數(shù)
(lldb) po $x0
<WBNetDetectViewController: 0x129abe4b0>
(lldb) x/s $x1
0x1009fa67c: "handleMacNameResult:"
(lldb) po $x2
<__NSArrayM 0x170e5a760>(
<WiFiMacModel: 0x170e4c7b0> {
mac = "C0:CE:CD:22:91:3C";
macname = "Apple, Inc.";
macname_zh = "Apple蘋果";
nickname = <nil>;
pic = "http://static.wlanbanlv.com/3de765ea1fa9cf94c3cff3b2ded6bdcddea09461.png"
},
<WiFiMacModel: 0x170e4d950> {
mac = "BC:A9:20:E0:A2:E6";
macname = "Apple, Inc.";
macname_zh = "Apple蘋果";
nickname = <nil>;
pic = "http://static.wlanbanlv.com/3de765ea1fa9cf94c3cff3b2ded6bdcddea09461.png"
},
<WiFiMacModel: 0x170e4d6e0> {
mac = "40:9C:28:9D:AE:22";
macname = "";
macname_zh = "";
nickname = <nil>;
pic = ""
},
- 查看方法是誰調(diào)用的,使用指令bt 打印方法調(diào)用棧
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
* frame #0: 0x00000001002763b4 wifibanlv`_mh_execute_header + 1926068
frame #1: 0x0000000100894f4c wifibanlv`__cxa_throw + 1064120
frame #2: 0x00000001008960a4 wifibanlv`__cxa_throw + 1068560
frame #3: 0x000000018b21e1fc libdispatch.dylib`_dispatch_call_block_and_release + 24
frame #4: 0x000000018b21e1bc libdispatch.dylib`_dispatch_client_callout + 16
frame #5: 0x000000018b222d68 libdispatch.dylib`_dispatch_main_queue_callback_4CF + 1000
frame #6: 0x000000018c342810 CoreFoundation`__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 12
frame #7: 0x000000018c3403fc CoreFoundation`__CFRunLoopRun + 1660
frame #8: 0x000000018c26e2b8 CoreFoundation`CFRunLoopRunSpecific + 444
frame #9: 0x000000018dd22198 GraphicsServices`GSEventRunModal + 180
frame #10: 0x00000001922b57fc UIKit`-[UIApplication _run] + 684
frame #11: 0x00000001922b0534 UIKit`UIApplicationMain + 208
frame #12: 0x00000001000a9c7c wifibanlv`_mh_execute_header + 40060
frame #13: 0x000000018b2515b8 libdyld.dylib`start + 4
(lldb)
此時(shí)如果你要找是誰調(diào)用了handleMacNameResult這個(gè)方法己单,為什么要找這個(gè)方法呢,因?yàn)閺纳厦娣治隹梢钥闯鰄andleMacNameResult中的參數(shù)才是我們需要 的葵姥,反過來推荷鼠,一定是哪個(gè)方法調(diào)用handleMacNameResult,然后將參數(shù)傳入了handleMacNameResult中榔幸, 那怎么繼續(xù)跟蹤呢允乐? 這里先說一下,oc方法運(yùn)行時(shí)削咆,其本質(zhì)是Runtime在調(diào)用方法牍疏,比如:
【self testMethod:url】其實(shí)在調(diào)用方法時(shí),走的是
objc_msgSend(self, @selector(testMethod), url),在我們進(jìn)行斷點(diǎn)時(shí)拨齐,是斷在了方法中鳞陨,那么在我們打印的x0 就是一個(gè)方法調(diào)用者,后面是方法瞻惋,然后是參數(shù)等厦滤。用bt指令打印出來的調(diào)用棧,是從下向上調(diào)用的歼狼,故如果想知道是誰調(diào)用了handleMacNameResult掏导,則可以用地址偏移公式來進(jìn)行查找,
要找的地址 = 0x0000000100894f4c - ASLR偏移量(0x00000000000a0000)
此時(shí)可以用mac自帶計(jì)算器運(yùn)算
通過計(jì)算得到地址為 0x1007F4F4C羽峰,在Hopper中通過Navigation/Go to Address 進(jìn)行查找,可以看到該地址在[ZLOpenWiFi getMacNameList:completionHandler:]趟咆,然后再次對(duì)該方法進(jìn)行斷點(diǎn)跟蹤
對(duì)偽代碼進(jìn)行分析如下:
typedef void (^AFURLSessionTaskCompletionHandler)(NSURLResponse *response, id responseObject, NSError *error);
@implementation XMNetWorkHelper
+(void)getMacNameList:(NSArray *)nameList completionHandler:(AFURLSessionTaskCompletionHandler)completionHandler
{
r31 = r31 - 0xb0;
*(r31 + 0x70) = r24;
*(0x80 + r31) = r23;
*(r31 + 0x80) = dic;
*(0x90 + r31) = self;
*(r31 + 0x90) = r20;
*(0xa0 + r31) = nameList;
*(r31 + 0xa0) = r29;
*(0xb0 + r31) = r30;
r29 = r31 + 0xa0;
nameList = [arg2 retain];
r20 = [arg3 retain];
[ZLHelper isValidArray:nameList];//對(duì)數(shù)組判斷是否合法
NSMutableDictionary *dic;
if (!CPU_FLAGS & E) {
dic = [[NSMutableDictionary dictionaryWithCapacity:zero_extend_64(0x0)] retain];
r0 = [self urlEncodeFormatStringList:nameList];//對(duì)數(shù)組進(jìn)行處理然后拼成一個(gè)字符串
r0 = [r0 retain];
r24 = [[r0 componentsJoinedByString:@","] retain];//按照,進(jìn)行分割成一個(gè)數(shù)組r24
[dic setObject:r24 forKey:@"bssid"];
[r24 release];
[r0 release];
ZLOpenWiFi *openWifi = [ZLOpenWiFi sharedInstance];//r0 = openWifi;
r29 = r29;
r0 = [r0 retain];
r23 = openWifi;
if ([openWifi debugMode] != 0x0) {//[openWifi debugMode] 返回一個(gè)bool值
*r31 = "+[ZLOpenWiFi getMacNameList:completionHandler:]";
*(r31 + 0x8) = zero_extend_64(0x221);
*(0x18 + r31) = dic;
NSLog(0x100b82ae8);
}
[r23 release];
r23 = [[ZLUrlHelper MacNameGetList] retain];//r23 是請(qǐng)求([self apiUrlMake:@"29004"])出的數(shù)據(jù)拼接在一起的字符串
*(r31 + 0x20) = __NSConcreteStackBlock;
*(r31 + 0x28) = *0x1008f5640;
*(r31 + 0x30) = 0x1007f4f10;
*(r31 + 0x38) = 0x100b47138;
*(0x48 + r31) = r20;
[r20 retain];
/*
r23 是請(qǐng)求([self apiUrlMake:@"29004"])出的數(shù)據(jù)拼接在一起的字符串
dic中裝的是 key 為bssid value為 namelist
*/
[self getHttpEncryptRequestForUrl:r23 parameters:dic completionHandler:stack[2048]];
[r23 release];
[*(r31 + 0x40) release];
[r20 release];
r0 = dic;
}
else {
r0 = [ZLOpenWiFi sharedInstance];
r0 = [r0 retain];
self = r0;
if ([r0 debugMode] != 0x0) {
asm { stp x8, x9, sp };
NSLog(0x100b82ac8);
}
[self release];
*(r31 + 0x48) = __NSConcreteStackBlock;
*(r31 + 0x50) = *0x1008f5640;
*(r31 + 0x58) = 0x1007f4e88;
*(r31 + 0x60) = 0x100b47108;
*(0x70 + r31) = r20;
[r20 retain];
dispatch_async(__dispatch_main_q, r31 + 0x48);
[*(r31 + 0x68) release];
r0 = r20;
}
[r0 release];
[nameList release];
}