-
LLDB常用命令--飘云整理
- 本地调试(macOS)
- 远程调试
- expression(执行表达式)
- po(打印参数)
- print(打印参数)
- backtrace(调用栈信息)
- frame(栈帧信息)
- breakpoint(打印断点列表)
- run(运行程序)
- process continue(继续执行)
- step(源码级步入)
- stepi(指令级步入)
- next(源码级步过)
- nexti(指令级步过)
- finish(完成并退出子函数)
- return(退出子函数)
- thread(线程操作)
- image (镜像操作)
- disassemble(反汇编)
- memory (内存操作)
- register(寄存器操作)
- display(查看表达式的值)
- watchpoint(内存断点)
- 找按钮事件
LLDB常用命令--飘云整理
这里整理一下飘哥常用的,我会慢慢添加并总结一些经验。
lldb命令支持简写,自己慢慢研究吧
优雅人生飘云原创整理,转载请注明出处!
https://www.dllhook.com
https://www.chinapyg.com
本地调试(macOS)
(lldb) target create "/Users/piaoyun/Desktop/xx.app/Contents/MacOS/xxxx"
带参数运行
(lldb) target create "/bin/ls"
Current executable set to '/bin/ls' (x86_64).
(lldb) set set target.run-args $(python \-c 'print "a"*200')
(lldb) run
Process 40752 launched: '/bin/ls' (x86_64)
ls: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: No such file or directory
Process 40752 exited with status = 1 (0x00000001)
(lldb)
远程调试
iOS设备端
附加进程:
$ ./debugserver *:1234 -a "YourAPPName"
直接启动进程:
$ debugserver -x backboard *:1234 /path/to/app/executable
例:
$ debugserver -x backboard *:1234 /Applications/MobileNotes.app/MobileNotes
此命令会启动记事本,并断在dyld的第一条指令上
macOS端
在macOS终端运行LLDB命令后,输入以下2条命令:
$ platform select remote-ios
$ process connect connect://你的设备IP地址:1234
用USB连接
- 老版本usbmuxd
1.wget下载源代码
$ wget http://cgit.sukimashita.com/usbmuxd.git/snapshot/usbmuxd-1.0.8.tar.bz2
$ tar xjfv usbmuxd-1.0.8.tar.bz2
$ cd usbmuxd-1.0.8/python-client/
$ python tcprelay.py -t 1234:1234
2.在macOS终端运行LLDB命令后,输入以下2条命令:
(lldb) platform select remote-ios
(lldb) process connect connect://localhost:1234
- 新版本usbmuxd
1.用brew安装
$ brew install usbmuxd
2.端口映射
$ iproxy 2222 22 [设备UUID]
3.另外开启一个终端用2222端口进行连接
$ ssh –p 2222 root@127.0.0.1
expression(执行表达式)
简写:expr
- 实例OC代码
-(void)loginWithUserName:(NSString *)username password:(NSString *)password
{
NSLog(@"login.... username:%@ password:%@", username, password); // 假设我们在此下断点
}
例子:
(lldb) expression $r6 = 1 // 设置r6寄存器的值
(lldb) expression $r6 // 查看r6寄存器的值
(lldb) expression username(源代码中变量) = @"www.dllhook.com"
(lldb) expression [self btnTest] // 调用某类某方法
po(打印参数)
OC代码同上一节
例子:
(lldb) po $r6
(lldb) po username
(lldb) po [[NSString alloc] initWithData:$r2 encoding:4] // 打印$r2寄存器的明文数据
(lldb) po [$r5 base64EncodedStringWithOptions:0]; // 打印$r5寄存器(NSData)类型的base64明文数据
print(打印参数)
print (type)
例子:
(lldb) print (int)$r6
(lldb) print username
backtrace(调用栈信息)
简写:bt
例子:
(lldb) bt
// 返回如下:
* thread #1: tid = 0x1ee09, 0x00035e80 debug`-[ViewController loginWithUserName:password:](self=0x15d7be60, _cmd=0x00036441, username=0x15db0120, password=0x0003768c) + 168 at ViewController.m:34, queue = 'com.apple.main-thread', stop reason = breakpoint 2.1
* frame #0: 0x00035e80 debug`-[ViewController loginWithUserName:password:](self=0x15d7be60, _cmd=0x00036441, username=0x15db0120, password=0x0003768c) + 168 at ViewController.m:34
frame(栈帧信息)
查看当前栈帧信息
(lldb) frame info
frame #0: 0x0000000197c60c30 libsystem_asl.dylib` asl_open
选择栈帧
语法:frame select 序号
(lldb) frame select 0
frame #0: 0x0000000197c60c30 libsystem_asl.dylib` asl_open
libsystem_asl.dylib`asl_open:
-> 0x197c60c30 <+0>: stp x20, x19, [sp, #-32]!
0x197c60c34 <+4>: stp x29, x30, [sp, #16]
0x197c60c38 <+8>: add x29, sp, #16 ; =16
0x197c60c3c <+12>: mov x20, x2
0x197c60c40 <+16>: bl 0x197c64798 ; asl_client_open
0x197c60c44 <+20>: mov x19, x0
0x197c60c48 <+24>: cbz x19, 0x197c60c70 ; <+64>
0x197c60c4c <+28>: movz w0, #0
breakpoint(打印断点列表)
breakpoint
可以简写为br
打印断点列表
- breakpoint list // 打印断点列表
例子:
(lldb) br l
// 返回如下:
Current breakpoints:
1: file = '/Users/piao/Desktop/debug/debug/main.m', line = 16, locations = 1, resolved = 1, hit count = 1
1.1: where = debug`main + 54 at main.m:16, address = 0x00036232, resolved, hit count = 1
2: file = '/Users/piao/Desktop/debug/debug/ViewController.m', line = 34, locations = 1, resolved = 1, hit count = 1
2.1: where = debug`-[ViewController loginWithUserName:password:] + 168 at ViewController.m:34, address = 0x00035e80, resolved, hit count = 1
函数地址下断
(lldb) breakpoint set -a 函数地址 // 常规断点
匹配特征字下断
飘云提示:这个非常有用!虽然官方文档一直有,但是没重视。
(lldb) breakpoint set --func-regex 函数/方法关键字
例子:
(lldb) breakpoint set --func-regex ptrace
Breakpoint 1: where = libsystem_kernel.dylib`__ptrace, address = 0x0000000197d6b244
(lldb) breakpoint set --func-regex open
Breakpoint 2: 1130 locations.
这样下断的优势:
比如在某动态库中有 testA函数,那么常规做法是先 image list -o -f 查看模块基址 然后 image lookup -r -n 函数关键字找到偏移 然后再 br s -a 基址+偏移!
用上面这个命令下端就简洁方便了!!!lldb会自动帮你下断所有匹配特征字的断点,可以模糊匹配哦
对动态库函数下断
(lldb) breakpoint set --shlib foo.dylib --name foo
对某个OC方法下断
(lldb) breakpoint set --method/--name "-[TSRegistWinCtrl showRegister]"
对某个OC类的所有方法下断
(lldb) breakpoint set -r '\[RegisterWindowController .*\]'
// 或者
(lldb) breakpoint set --func-regex '\[RegisterViewController .*\]'
在某个OC所有同名方法设置断点
下面例子对每个viewDidLoad方法都设置断点:
(lldb) breakpoint set --selector viewDidLoad
断点命令处理
这个非常有用,可以进行断点过程中的一些自动化处理:
(lldb) breakpoint command add 断点序号
对导出函数下断
这个非常有用,对导出函数下断非常好 / 貌似是模糊匹配:
(lldb) breakpoint set -F isTest
// 可以简写为: b isTest
run(运行程序)
简写:r
process continue(继续执行)
简写:c
step(源码级步入)
简写:s
源码级别单步执行,遇到子函数则进入。
stepi(指令级步入)
简写:si
单步执行,遇到子函数则进入。
next(源码级步过)
简写:n
源码级别单步执行,遇到子函数不进入,直接步过。
nexti(指令级步过)
简写:ni
单步执行,遇到子函数不进入,直接步过。
finish(完成并退出子函数)
完成并退出子函数
return(退出子函数)
直接退出子函数
thread(线程操作)
(lldb) thread list // 打印线程列表
image (镜像操作)
列出所有依赖库
(lldb) image list
[ 0] 69F6C476-555D-3987-B162-E62C9A1D718C 0x000000010008c000 /var/mobile/Containers/Bundle/Application/D6B51B8B-00F8-443F-9B8E-EF47C2330D2B/WhatsApp.app/WhatsApp (0x000000010008c000)
[ 1] 3134CFB2-F722-310E-A2C7-42AE4DC131AB 0x00000001017ec000 /Library/MobileSubstrate/MobileSubstrate.dylib (0x00000001017ec000)
[ 2] 4DB79D94-6764-3180-99C9-5615E29073E7 0x0000000196848000 /Users/piao/Library/Developer/Xcode/iOS DeviceSupport/9.0.2 (13A452)/Symbols/usr/lib/libSystem.B.dylib
查找ASLR偏移
(lldb) image list -f -o WhatsApp
[ 0] /var/mobile/Containers/Bundle/Application/D6B51B8B-00F8-443F-9B8E-EF47C2330D2B/WhatsApp.app/WhatsApp 0x000000000008c000(0x000000010008c000)
ASLR偏移:0x000000000008c000
打印加载模块列表
(lldb) image list -f -o // 通常带这两个参数使用
[ 0] 40E417A4-F966-3DB4-B028-B0272DC016A7 0x000a0000 /Users/piao/Library/Developer/Xcode/DerivedData/debug-bdkhskdqykkoqmhjedilckzvpuls/Build/Products/Debug-iphoneos/debug.app/debug
/Users/piao/Library/Developer/Xcode/DerivedData/debug-bdkhskdqykkoqmhjedilckzvpuls/Build/Products/Debug-iphoneos/debug.app.dSYM/Contents/Resources/DWARF/debug
[ 1] 011601C0-F561-3306-846B-94A7C8C841DA 0x2d9e6000 /Users/piao/Library/Developer/Xcode/iOS DeviceSupport/7.1.2 (11D257)/Symbols/System/Library/Frameworks/CoreGraphics.framework/CoreGraphics
查找原始地址信息
在可执行文件或任何共享库中查找原始地址的信息。
- image lookup -a 表达式
例子:
(lldb) image lookup -a $pc
Address: debug[0x0000b236] (debug.__TEXT.__text + 1254)
Summary: debug`main + 58 at main.m:16
查找某个函数
- 对于有调试符号的这样使用:
image lookup -r -n <FUNC_REGEX>
例子:
(lldb) image lookup -r -n ptrace
libsystem_kernel.dylib:
Address: libsystem_kernel.dylib[0x0000000197693244] (libsystem_kernel.dylib.__TEXT.__text + 108616)
Summary: libsystem_kernel.dylib`__ptrace Address: libsystem_kernel.dylib[0x0000000197693244] (libsystem_kernel.dylib.__TEXT.__text + 108616)
Summary: libsystem_kernel.dylib`__ptrace
[PiaoYunDbg]$
- 对于无调试符号的这样使用:
(lldb) image lookup -r -s <FUNC_REGEX>
disassemble(反汇编)
- disassemble -a 地址
例子:
(lldb) dis -a $pc
debug`main at main.m:14:
0xa71fc: push {r7, lr}
0xa71fe: mov r7, sp
0xa7200: sub sp, #0x24
0xa7202: movs r2, #0x0
0xa7204: movt r2, #0x0
0xa7208: str r2, [sp, #0x20]
0xa720a: str r0, [sp, #0x1c]
0xa720c: str r1, [sp, #0x18]
0xa720e: blx 0xa7fe0 ; symbol stub for:
...
(lldb) disassemble -A thumb // 指定thumb
可选:
thumbv4t
thumbv5
thumbv5e
thumbv6
thumbv6m
thumbv7
thumbv7f
thumbv7s
thumbv7k
thumbv7m
thumbv7em
memory (内存操作)
读内存
- memory read [起始地址 结束地址]/寄存器 -outfile 输出路径(内存操作)
例子:
(lldb) memory read $pc
0x00035ebe: 0e 98 07 99 09 68 08 9a 90 47 0c 99 03 90 08 46 .....h...G.....F
0x00035ece: 03 99 01 f0 80 e8 02 22 c0 f2 00 02 41 f2 52 10 ......."....A.R.
(lldb) memory read 0x35f1c 0x35f46 -outfile /tmp/test.txt // 将内存区域保存到文件
默认情况下,memory read 只能读取 1024字节数据
例如下面的代码就会报错:
(lldb) memory read 0x1000 0x3000 -outfile /tmp/test.txt
error: Normally, 'memory read' will not read over 1024 bytes of data.
解决方法:加-force
参数
(lldb) memory read 0x1000 0x3000 -outfile /tmp/test.txt -force
或者:
(lldb) memory read 0x1000 -outfile /tmp/test.txt -count 0x2000 -force
(lldb) memory read $x0(寄存器) -outfile /tmp/test.txt -count 0x2000 -force
二进制输出到文件
- memory read xxxx --binary
例子:
(lldb) memory read 0x1000 0x3000 -outfile /tmp/test.bin --binary -force
写内存
- memory write 寄存器/地址 数据
例子:
(lldb) memory write $rip 0xc3
(lldb) memory write $rip+1 0x90
std::string读取
- 读取方式:从内存+8的地方开始 64bit自行变通
例子:
(lldb) x $r0+8
0x02db9248: 20 82 e3 14 71 00 00 00 61 00 00 00 c0 82 d3 14 .惝q...a...喇赢
0x02db9258: 71 00 00 00 2b 00 00 00 20 f9 e6 14 61 00 00 00 q...+... .a...
(lldb) x/s 0x14e38220
0x14e38220: "hello!piaoyun"
register(寄存器操作)
读寄存器
- register read/格式
例子:
(lldb) register read/x
//返回如下:
General Purpose Registers:
r0 = 0x1599e028
r1 = 0x38131621 libobjc.A.dylib`objc_msgSend + 1
r2 = 0x000a85cc "class"
r3 = 0x000a85d4 (void *)0x000a8618: AppDelegate
r4 = 0x00000000
r5 = 0x000a71fd debug`main + 1 at main.m:14
r6 = 0x00000000
r7 = 0x27d63c80
r8 = 0x27d63c98
r9 = 0x00000002
r10 = 0x00000000
r11 = 0x00000000
r12 = 0x3a3ff1c8 (void *)0x3875cc19: _Unwind_SjLj_Unregister + 1
sp = 0x27d63c5c
lr = 0x38136eaf libobjc.A.dylib`objc_autoreleasePoolPush + 311
pc = 0x000a7236 debug`main + 58 at main.m:16
cpsr = 0x20000030
写寄存器
- register write 寄存器名称 数值
例子:改写r9寄存器例子:
(lldb) register write r9 2
display(查看表达式的值)
使用display命令设置一个表达式后,它将在每次单步后,紧接着输出被设置的表达式的的值
- display 表达式
- undisplay 序号
例子:
(lldb) display $R0
(lldb) undisplay 1
watchpoint(内存断点)
- 内存断点 watchpoint set expression 地址
- watchpoint set variable 变量名称 // 源码调试用到,略过
设置内存断点
例子:
(lldb) watchpoint set expression 0x1457fa70
// 命中后得到结果:
Watchpoint 3 hit:
old value: 3
new value: 4
内存访问断点
- watchpoint set expression -w read -- 内存地址
例子:
(lldb) watchpoint set expression -w read -- 0x16b9dd91
内存写入断点
- watchpoint set expression -w write -- 内存地址
例子:
(lldb) watchpoint set expression -w read -- 0x16b9dd91
例子:
条件断点
- watchpoint modify -c 表达式
例子:
(lldb) watchpoint modify -c '*(int *)0x1457fa70 == 20'
命中后得到结果:
Watchpoint 3 hit:
old value: 15
new value: 20
找按钮事件
- po [按钮名称/内存地址 allTargets]
例子:
(lldb) po [[self btnTest] allTargets]
{(
<ViewController: 0x166af1f0>
)}
(lldb) po [[self btnTest] actionsForTarget:(id)0x166af1f0 forControlEvent:0]
<__NSArrayM 0x165b8950>(
testAction:
)
在机器上实战
(lldb) po [[[UIApplication sharedApplication] keyWindow] recursiveDescription]
<UIWindow:
0x15e771c0; frame = (0 0; 320 568); gestureRecognizers = <NSArray:
0x15e96210>; layer = <UIWindowLayer: 0x15e988e0>>
| <UIView: 0x15eb4180; frame = (0 0; 320 568); autoresize = W+H; layer = <CALayer: 0x15eb4300>>
| | <UIButton: 0x15eb32d0; frame = (277 285; 46 30); opaque = NO;
autoresize = RM+BM; layer = <CALayer: 0x15eb2e30>>
|
| | <UIButtonLabel: 0x15db5220; frame = (0 6; 46 18); text =
'Button'; opaque = NO; userInteractionEnabled = NO; layer =
<_UILabelLayer: 0x15db5410>>
| | <_UILayoutGuide: 0x15eb4360; frame = (0 0; 0 20); hidden = YES; layer = <CALayer: 0x15eb4540>>
| | <_UILayoutGuide: 0x15eb4af0; frame = (0 568; 0 0); hidden = YES; layer = <CALayer: 0x15eb4b70>>
(lldb) po [(UIButton *)0x15eb32d0 allTargets]
{(
<ViewController: 0x15e93250>
)}
(lldb) po [(UIButton *)0x15eb32d0 allTargets]
{(
<ViewController: 0x15e93250>
)}
(lldb) po [(UIButton *)0x15eb32d0 actionsForTarget:(id)0x15e93250 forControlEvent:0]
<__NSArrayM 0x15dbfc50>(
testAction:
)
// 调用--
(lldb) po [0x15e93250 testAction:nil]
0x00210c18
对按钮属性操作
(lldb) po [[[UIApplication sharedApplication] keyWindow] recursiveDescription]
<UIWindow: 0x15e771c0; frame = (0 0; 320 568); gestureRecognizers = <NSArray: 0x15e96210>; layer = <UIWindowLayer: 0x15e988e0>>
| <UIView: 0x15eb4180; frame = (0 0; 320 568); autoresize = W+H; layer = <CALayer: 0x15eb4300>>
| | <UIButton: 0x15eb32d0; frame = (277 285; 46 30); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x15eb2e30>>
| | | <UIButtonLabel: 0x15db5220; frame = (0 6; 46 18); text = 'Button'; opaque = NO; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x15db5410>>
| | <_UILayoutGuide: 0x15eb4360; frame = (0 0; 0 20); hidden = YES; layer = <CALayer: 0x15eb4540>>
| | <_UILayoutGuide: 0x15eb4af0; frame = (0 568; 0 0); hidden = YES; layer = <CALayer: 0x15eb4b70>>
(lldb) expression UIButton *$btn = (UIButton *)0x15eb32d0
(lldb) expression [$btn setHidden:YES]
已有3367位网友发表了看法:
例如我们在代码中使用scanf()函数循环读取外部的值,在调试时怎么输入呢?具体命令是什么的
发表评论