LLDB
-
简介:LLDB是个开源的内置于XCode的调试工具,给我们平时开发调试带来很大的便利,同时它对我们逆向分析别人的APP同样有很大的帮助
-
查看指令的用法
$help [cmd]
-
内存查看
$memory read 0x地址(缩写是:x) //可以查看寄存器内存 比如str 是把寄存器值写到内存中,可以在前后下断点用memory查看 $memory write 0xaddress 0x65 //写入
-
寄存器操作
$register write r0 1 $register read //打印寄存器list $p/x $lr // 查看LR funcA调用funcB,funcB结束后,会回到funcA。如果能知道LR的值就知道funcB被谁调用 $p/x $x0 //打印寄存器地址 可以执行运算 比如 p/x 0x0064000 + 0xff $x/10 $sp //打印从栈底开始连续的10个字 一般情况下,oc方法在栈中参数不会超过10个,这个命令就足够了,挨个打印 然后 po address $dis -a 内存地址。 通过内存看函数 拿到内存后可以通过此命令查看汇编代码 $po $x1 $pblock 0xaaaaa //打印函数的Block参数 $methods 0xffffff //查看对像 及属性方法 $search UItextfiled //搜索UItextfiled的对象和实例
p/x 表示输出16进制,还有 p/t(10进制) p/o(8进制)
-
查看代码段
$image lookup -a 0x102110226 //汇编的地址 $image lookup -t Person //快速查看一个类 $image list //系统加载的各种文件信息 $image list -o -f //模块偏移地址
-
X命令是直接输出内存内容 格式为$x/nfu target
$x/16xb charArray $x/16xb self $x/c $x1 //打印X0掉用函数 $x/s $1
参数解释:
n,表示要显示的内存单元的个数
f,表示显示方式, 可取如下值:
参数 | 含义
---|---
x | 按十六进制格式显示变量
d | 按十进制格式显示变量
u | 按十进制格式显示无符号整型
o | 按八进制格式显示变量
t | 按二进制格式显示变量
a | 按十六进制格式显示变量
i | 指令地址格式
c | 按字符格式显示变量
s | 按字符串格式显示变量
f | 按浮点数格式显示变量
u,表示一个地址单元的长度:
参数 | 含义
---|---
b | 按单字节分段输出
h | 按双字节分段输出
w | 按四字节分段输出
g | 按八字节分段输出
target,表示内存地址,可以是变量名,也可以是内存地址。
- 断点操作
$bt //查看堆栈列表 $up //断下后才可以使用 往函数上一层 $down //断下后才可以使用 往函数下一层 $b set -n "C函数名" $br s -a 0x1029c28d0 //给内存地址下断点 常用 $b -[class method] //给类的方法下断点 常用 $b set -n "-[OC类 方法名:]" $b set -r 方法名: //遍历整个项目中,为所有同名的所有方法下断点 $br delete //删除全部断点 也可以指定index $n next //遇到子函数也一并执行 $s //单步运行,遇到子函数会进去 $ni 和n一样 只是针对汇编 上两个是针对源代码 $si 和s一样, 只是针对汇编 $continue //继续执行 $c $b list //查看断点列表 $breakpoint disable //断点禁用 $breakpoint enable //断点启用 $watchpoint set variable p1->name $watchpoint set expression 0x312315(一个内存地址) $stop-hook - 让你在每次stop的时候去执行一些命令,只对breadpoint,watchpoint $target stop-hook list $target stop-hook add -o "frame variable" $target stop-hook delete $frame select index //定位到第index层的代码位置 $frame variable 查看所有参数,可以通过p进行修改 $thread return 代码回滚到上一层,并退出
传统下断点的方式
- LLDB链接到程序
- 调动命令
im li -o -f Aweme #查看二进制模块偏移
3.在反编译工具中查看要断点位置的基地址
4.计算偏移后的地址
p/x 基地址 + 偏移地址
br -s -a 地址
但以上存在两个问题
1.需要工具支持IDA Hopper
2.不能对已经通过运行时替换函数地址的函数
改进
作为一个逆向开发新手,特分享一个以小技巧,可以免除对反汇编软件的依赖,而且拦截成功率更高。
LLDB连接到程序
--[模型对象 _shortMethodDescription]
找到需要下断点的类,如MMServiceCenter,然后在LLDB命令行输入po [MMServiceCenter _shortMethodDescription]。以微信的[MMServiceCenter getService:]断点为例,操作如下:
然后在命令行输入br -s -a 0x100bd04f0 即可下断点
--[模型对象 _ivarDescription]
使用方式如上
断点设置
如果有不会的可以查看LLDB官方文档
- 设置地址
br s -a addr //eg br s -a 0x0000193c 或者 br s -a 0x0000193b + 0x00013bc
或者
b addr // b 0x0000193c
- 设置方法名断点
breakpoint/b set -n xxx //xxx:方法名
- 在名为main的所有函数上设置断点。
br s -n main
-在文件的某一行下断点
br s -f test.c -l 12
#或者
b test.c:12
-通过函数名称下断点
(lldb) breakpoint set --name "-[NSString stringWithFormat:]"
(lldb) br s -n "-[NSString stringWithFormat:]"
(lldb) b -[NSString stringWithFormat:]
expression命令
打印变量
print 简写p 是 expression -- 别名,打印基本数据类型。
po 是 expr -o -- 的别名。
(lldb) expr -o -- [SomeClass returnAnObject]
or using the po alias:
(lldb) po [SomeClass returnAnObject]
以特定格式打印变量
下面分别以16进制(x),字符(c),二进制(t)打印变量
(lldb) p/x 2
(int) $0 = 0x00000002
lldb) p/c (char)97
(char) $2 = 'a'
(lldb) p/t 2
(int) $4 = 0b00000000000000000000000000000010
调试信息
- frame info 可以查看当前调试的行数和源码信息
(lldb) frame info
frame #0: 0x0000000104cc6d1c TestPAD`-[ViewController testParam:b:c:d:](self=0x0000000149d0aaa0, _cmd="testParam:b:c:d:", a=10, b=20, c=30, d=40) at ViewController.m:31
- thread info 可以查看当前调试线程、行数、和源码信息
(lldb) thread info
thread #1: tid = 0xfb0ab5, 0x0000000104cc6d1c TestPAD`-[ViewController testParam:b:c:d:](self=0x0000000149d0aaa0, _cmd="testParam:b:c:d:", a=10, b=20, c=30, d=40) at ViewController.m:31, queue = 'com.apple.main-thread', stop reason = breakpoint 9.1
- thread list 可以查看当前所有线程的调试状态
lldb) thread list
Process 29252 stopped
* thread #1: tid = 0xfb0ab5, 0x0000000104cc6d1c TestPAD`-[ViewController testParam:b:c:d:](self=0x0000000149d0aaa0, _cmd="testParam:b:c:d:", a=10, b=20, c=30, d=40) at ViewController.m:31, queue = 'com.apple.main-thread', stop reason = breakpoint 9.1
thread #3: tid = 0xfb0ad8, 0x000000018608fdf4 libsystem_dnssd.dylib`ConvertHeaderBytes, queue = 'com.skyeye.analytics.network.queue'
thread #4: tid = 0xfb0ad9, 0x00000001860f5dbc libsystem_kernel.dylib`__workq_kernreturn + 8
thread #5: tid = 0xfb0ada, 0x0000000186206c1c libsystem_pthread.dylib`start_wqthread
thread #6: tid = 0xfb0adb, 0x00000001860d4bc4 libsystem_kernel.dylib`mach_msg_trap + 8, queue = 'com.SkyEye.905541C85D654B539C85DEECF2689651.0x1c0462b00.network'
thread #7: tid = 0xfb0adc, 0x00000001860d4bc4 libsystem_kernel.dylib`mach_msg_trap + 8, name = 'com.apple.uikit.eventfetch-thread'
thread #8: tid = 0xfb0ade, 0x00000001860f5c1c libsystem_kernel.dylib`__ulock_wait + 8, queue = 'com.skyeye.analytics.interface.queue'
thread #9: tid = 0xfb0ae0, 0x00000001860d4bc4 libsystem_kernel.dylib`mach_msg_trap + 8, name = 'com.apple.NSURLConnectionLoader'
- frame variable(简写 fr v)当前调试堆栈的所有参数和临时变量
(lldb) frame variable
(ViewController *) self = 0x0000000149d0aaa0
(SEL) _cmd = "testParam:b:c:d:"
(int) a = 10
(int) b = 20
(int) c = 30
(int) d = 40
(int) ii = 10000
- register read 返回当前线程通用寄存器的值(对64为对应x0-x31)
lldb) register read
General Purpose Registers:
x0 = 0x0000000149d0aaa0
x1 = 0x0000000104d9dd46 "testParam:b:c:d:"
x2 = 0x000000000000000a
x3 = 0x0000000000000014
x4 = 0x000000000000001e
x5 = 0x0000000000000028
x6 = 0x0000000000000000
x7 = 0x000000016b156808
x8 = 0x0000000104dd9330 "testParam:b:c:d:"
x9 = 0x0000000000000000
x10 = 0x0086860100868680
x11 = 0x0000000000868601
x12 = 0x0000000000868500
x13 = 0x0000000000000001
x14 = 0x0000000000000000
x15 = 0x00868601008686c0
x16 = 0x0000000000000000
x17 = 0x0000000104cc6cf4 TestPAD`-[ViewController testParam:b:c:d:] at ViewController.m:29
x18 = 0x0000000000000000
x19 = 0x00000001b70ab8c0 UIKit`_UIApplicationLinkedOnVersion
x20 = 0x0000000149d0aaa0
x21 = 0x0000000000000018
x22 = 0x0000000190799d6a "count"
x23 = 0x0000000000000000
x24 = 0x0000000000000000
x25 = 0x000000014a017c00
x26 = 0x0000000000000408
x27 = 0x00000001c0099410
x28 = 0x0000000000000000
fp = 0x000000016b157f60
lr = 0x0000000104cc6bbc TestPAD`-[ViewController viewDidLoad] + 164 at ViewController.m:24
sp = 0x000000016b157f30
pc = 0x0000000104cc6d1c TestPAD`-[ViewController testParam:b:c:d:] + 40 at ViewController.m:31
cpsr = 0x20000000
- memory read (简写x)以给定格式读取给定内存地址数据
(1)比如以字符串读取x1寄存器的值
(lldb) memory read -f s $x1
或者
(lldb) x -f s $x1
或者
(lldb) x/s $x1
输出为:
0x104d9dd46: "testParam:b:c:d:"
(2)读取栈中所有值,即sp和fp连续内存区域值。
(lldb) x -f A $sp $fp
(3)每多少字节读取某个地址
memory read --size 8 --format x 0x17425ff20
#或者
x/8 0x17425ff20
#node:函数指针占8个字节,int占4个字节
几个实用的命令
- 查看层级
pviews
- 查看某个控件的响应链
presponder 0x1133d32
- 查看按钮Action事件
pactions 0x1133d32
- 查看block参数
pblock 0x134a32d
- 查看某个对象所有的方法
methods 0x13d42
- 搜索UITextField的实例对象及地址
search UITextField
- 对某个类所有的方法下断点并跟踪打印调用参数,
bclass
//例如
blcass LoginViewController
br command add 1
Enter your debugger command(s). Type 'DONE' to end
> po $0 //打印第一个参数(调用类)
> x/s $1 //打印方法
> c //下一步
> DONE
- 查看某个地址所在模块的信息
- image lookup
//例如
(lldb) b [LoginRegiseterViewController snapchatterButtonClicked]
Brekpoint 1: where = Snapchat -[LoginRegiseterViewController snapchatterButtonClicked],
address = 0x0000012da2
(lldb) c
Process 18474 resuming
(lldb) image lookup -a 0x0000012da2
Adress: ---对应的偏移地址-----
Summary: ---对应的函数信息---
对模块中进行模糊查询有关的符号信息
- image lookup -rn
#查看snapchat中所有带有login字符串的符号信息
(lldb)image lookup -rn login snapchat
Adress: ---对应的偏移地址-----
Summary: ---对应的函数信息---
等等