iOS逆向工程(八):动态调试 动态调试

动态调试

一、什么是动态调试

  • 1.动态调试就是将程序运行起来,通过打断点、打印等方式,查看参数、返回值、函数调用流程等信息
  • 2.之前我们说的静态分析,就是程序不运行的时候,对程序的可执行文件进行分析,分析头文件、伪代码之类的信息
  • 3.学会动态调试之后,我们就可以分析某个程序的整体调用流程了,例如:分析微信抢红包的时候,就可以知道微信调用了哪些方法去抢红包,以便我们hook

二、动态调试任意App

第一步:将有权限的debugserver安装到手机

1/进入目录
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport

找到手机对应版本,点开dmg;拷贝debugserver备用
/usr/bin/debugserver

2/修改权限
导出权限

$ ldid -e debugserver > debugserver.entitlements

修改内容

温馨提示->
最好整体copy

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>com.apple.backboardd.debugapplications</key>
    <true/>
    <key>com.apple.backboardd.launchapplications</key>
    <true/>
    <key>com.apple.frontboard.debugapplications</key>
    <true/>
    <key>com.apple.frontboard.launchapplications</key>
    <true/>
    <key>com.apple.springboard.debugapplications</key>
    <true/>
    <key>com.apple.system-task-ports</key>
    <true/>
    <key>get-task-allow</key>
    <true/>
    <key>platform-application</key>
    <true/>
    <key>run-unsigned-code</key>
    <true/>
    <key>task_for_pid-allow</key>
    <true/>
</dict>
</plist>

编辑后将其合入debugserver【注意-S后面不要空格】

$ ldid -Sdebugserver.entitlements debugserver

3/将编辑完成的文件放入手机的/usr/bin目录

电脑端操作->

$ scp -r /Users/gn/Desktop/333/debugserver [email protected]:/usr/bin

手机端操作->如果有过操作,需要删除debugserver

iPhone-7:~ root# rm /usr/bin/debugserver

第二步:让debugserver与App建立交互

在Mac上打开命令行窗口,让10011端口与10011端口映射、10010与22端口映射

新建命令行窗口
$ iproxy 10011 10011
新建命令行窗口
$ iproxy 10010 22

在Mac上新建命令行窗口,然后SSH登陆到手机

gndeMacBook-Pro:~ gn$ ssh -p 10010 [email protected]

提示
server端密码或是其他发生改变的时候。
解决方法一般就需要删除~/.ssh/known_hosts的东西,然后再登录即可。

登录到手机后,启动手机的debugserver服务,让其与App建立交互

iPhone-7:~ root# debugserver 127.0.0.1:10011 -a WeChat
debugserver-@(#)PROGRAM:LLDB  PROJECT:lldb-900.3.106
 for arm64.
Attaching to process WeChat...
Listening to port 10011 for a connection from localhost...
Waiting for debugger instructions for process 0.

第三步:让debugserver与LLDB建立交互

在Mac上新建命令行窗口

$ lldb  
(lldb) process connect connect://127.0.0.1:10011
Process 1079 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
    frame #0: 0x0000000189d2d198 libsystem_kernel.dylib`mach_msg_trap + 8
libsystem_kernel.dylib`mach_msg_trap:
->  0x189d2d198 <+8>: ret    

libsystem_kernel.dylib`mach_msg_overwrite_trap:
    0x189d2d19c <+0>: mov    x16, #-0x20
    0x189d2d1a0 <+4>: svc    #0x80
    0x189d2d1a4 <+8>: ret    
Target 0: (WeChat) stopped.
(lldb)  

使用LLDB命令c,先让程序继续运行

(lldb) c
Process 1079 resuming
(lldb) 

测试

(lldb) image list
[  0] 12AE6955-466B-365D-B4AD-4414062D4AA0 0x0000000100e20000 /private/var/containers/Bundle/Application/155D1862-E927-4904-B513-B48BDA84DE08/WeChat.app/WeChat (0x0000000100e20000)
[  1] D3BB8E91-0746-3426-8707-5B717D156B4E 0x000000010d2a0000 /Library/Caches/cy-B6mYK0.dylib (0x000000010d2a0000)
[  2] BF3B96C2-BD3B-390E-BFCF-33656588C86E 0x000000010cf90000 /usr/lib/substrate/SubstrateBootstrap.dylib (0x000000010cf90000)
[  3] 46F72B20-370B-352E-ABCA-3896633F251D 0x00000001b4191000 /Users/gn/Library/Developer/Xcode/iOS DeviceSupport/13.7 (17H35)/Symbols/System/Library/Frameworks/AuthenticationServices.framework/AuthenticationServices 
[  4] 7602EB30-DE1D-3996-8D0E-024450B58325 0x000000019885d000 /Users/gn/Library/Developer/Xcode/iOS DeviceSupport/13.7 (17H35)/Symbols/System/Library/Frameworks/AVKit.framework/AVKit 
[  5] E545F1E8-28B7-3580-9770-97D87896929B 0x00000001c08be000 /Users/gn/Library/Developer/Xcode/iOS DeviceSupport/13.7 (17H35)/Symbols/usr/lib/libresolv.9.dylib 

第四步:动态调试建立好之后,我们就可以使用LLDB指令,来正式开始调试了

LLDB指令
LLDB指令的格式是:
<command> [<subcommand> [<subcommand>...]] <action> [-options [option- value]] [argument [argument...]],其中,command代表命令,subcommand代表子命令,action代表命令的动作,- options 代表命令的选项,argument代表命令的参数,[]中的可以省略。
help命令,用于查看指令的用法,例如:help breakpoint、help breakpoint set
expression命令,执行一个表达式,例如:expression self.view.backgroundColor = [UIColor redColor],expression与print、p、call的效果一样
thread backtrace命令,打印线程的堆栈信息,与bt命令效果一样
thread return []命令,让函数直接返回某个值,不会执行断点后面的代码了,例如:thread return 3,返回了3
frame variable []命令,打印当前栈帧的变量
thread continue、continue、c命令,让程序继续运行
thread step-over、next、n命令,单步执行,把子函数当做一个整体,不会进入子函数
thread step-in、step、s命令,单步执行,遇到子函数会进入子函数内部
breakpoint set命令,设置断点,参数主要有以下几种:
breakpoint set -a 函数地址
breakpoint set -n 函数名
breakpoint set -r 正则表达式
breakpoint set -s 动态库 -n 函数名
breakpoint list命令,列出所有的断点,每个断点都有自己的编号
breakpoint delete 断点编号命令,删除某个断点
breakpoint command add 断点编号命令,给断点预先设置需要执行的命令,到触发断点时,就会按顺序执行
breakpoint command list 断点编号命令,查看某个断点的预设命令
watchpoint内存断点,就是当内存数据改变时,触发此断点,以便确认是谁修改了内存,子命令主要有以下几种:
watchpoint set variable 变量,例如:watchpoint set variable self->_age,当age变量改变时,断点就会触发,以便找到修改age内存的代码

watchpoint set expression 地址,例如:watchpoint set expression &self->_age

watchpoint list,列出所有的内存断点

watchpoint delete 断点编号,删除此内存断点

watchpoint command add 断点编号,给此内存断点,增加预设命令

image lookup,寻找模块信息,如果你想找某个类型、某个方法、某个地址在模块中的什么位置,就可以用这个命令,主要参数如下:
image lookup -t 类型,查找某个类型的信息,例如image lookup -t NSInterger
image lookup -a 地址,看看某个内存地址在模块中的位置
image lookup -n 符号或者函数名,查找某个符号或者函数的位置
image list,列出所加载的模块信息
一些小技巧:敲Enter会自动执行上次的命令、绝大部分命令可以使用缩写

lldb常用命令

breakpoint使用

1、下断点

breakpoint set --name test1 

breakpoint set -n test1 

打印:

Breakpoint 2: where = LLDB`-[ViewController test1] + 23 at ViewController.m:25:5, address = 0x0000000109de9f97

断点位置信息,执行便能在该处断住。

连续下多个断点:

breakpoint set -n "-[ViewController save:]" -n "-[ViewController pause:]" -n "-[ViewController continues:]"

运行c继续运行,n单步执行,s进入函数内部执行,finish执行到函数尾部。

2、查看断点列表

breakpoint list

打印:

1: file = '/Users/hibo/Documents/test/LLDB/LLDB/ViewController.m', line = 21, exact_match = 0, locations = 1 Options: disabled 

 1.1: where = LLDB`-[ViewController touchesBegan:withEvent:] + 70 at ViewController.m:22:6, address = 0x0000000109de9f46, unresolved, hit count = 2 Options: disabled 

2: name = 'test1', locations = 1, resolved = 1, hit count = 7

 2.1: where = LLDB`-[ViewController test1] + 23 at ViewController.m:25:5, address = 0x0000000109de9f97, resolved, hit count = 7 

3、禁用断点

breakpoint disable  //禁用所有断点
breakpoint disable 1.1 //禁用第一个断点

4、启用断点

breakpoint enable   //启用所有断点
breakpoint enable 1.1  //启用1处断点  

5、删除所有断点

breakpoint delete
breakpoint delete 1

删除只能删除一组,不能单个删除

6、设置selector

breakpoint set --selector touchesBegan:withEvent:

将为所有该方法设置断点

7、设置文件中的selector断点

breakpoint set --file ViewController.m --selector touchesBegan:withEvent:

8、设置带有相同字符串的方法断点

breakpoint set -r Game:

打印:

Current breakpoints:

1: regex = 'Game:', locations = 3, resolved = 3, hit count = 0

 1.1: where = LLDB`-[ViewController pauseGame:] + 43 at ViewController.m:31:5, address = 0x00000001010dff0b, resolved, hit count = 0 

 1.2: where = LLDB`-[ViewController continueGame:] + 43 at ViewController.m:34:5, address = 0x00000001010dff5b, resolved, hit count = 0 

 1.3: where = LinkPresentation`-[LPGameCenterInvitationMetadata setGame:], address = 0x00007fff2733e5e9, resolved, hit count = 0 

如上也给其他带有Game字符的类下了断点。

给某一个文件下的带有相同字符串的方法下断点:

breakpoint set --file ViewController.m -r Game

简写:breakpoint->b
打印列表需要写全:breakpoint list或者break list

bt、frame命令

1、查看函数相关信息,使用p、down追踪函数的调用和被调用关系

frame select

使用bt命令查看函数调用堆栈

2、查找方法的调用者及方法名称

frame variable

methods、pviews

1、methods打印当前对象的属性和方法

methods self 

2、pviews打印当前视图的层级结构

以上两个命令是lldb插件名中的命令。chisel安装

……

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章