断点设置
越狱的工程无法正常打断点调试,所以我们需要学习LLDB
函数断点设置 breakpoint set -n
C 函数设置
(lldb) breakpoint set -n test1
Breakpoint 2: where = KTest`test1 + 4 at ViewController.m:28:1, address = 0x0000000104abef64
OC 函数设置 breakpoint set
普通方法
(lldb) breakpoint set -n "[ViewController rf_save:]" -n "[ViewController rf_pause:]" -n "[ViewController rf_continue:]"
Breakpoint 2: 3 locations.
selector
- 全局设置
全局设置这里有95个
touchesBegan:withEvent:被设置了断点
(lldb) breakpoint set --selector touchesBegan:withEvent:
Breakpoint 1: 95 locations.
- 指定某个文件
(lldb) breakpoint set --file ViewController.m --selector touchesBegan:withEvent:
Breakpoint 2: where = KTest`-[ViewController touchesBegan:withEvent:] + 70 at ViewController.m:25:6, address = 0x0000000105ac9e66
- 指定某一类
只要包含指定字符的都会被下断点;eg:自定义的方法都包含testKKK
(lldb) breakpoint set -r testKKK
Breakpoint 1: 3 locations.
- 结合使用
(lldb) breakpoint set --file ViewController.m -r testKKK
Breakpoint 1: 3 locations.
断点列表 breakpoint list
(lldb) breakpoint list
Current breakpoints:
1: file = '/KTest/ViewController.m', line = 24, exact_match = 0, locations = 1, resolved = 1, hit count = 0
1.1: where = KTest`-[ViewController touchesBegan:withEvent:] + 74 at ViewController.m:26:1, address = 0x0000000106d5aeba, resolved, hit count = 0
2: names = {'[ViewController rf_save:]', '[ViewController rf_save:]', '[ViewController rf_pause:]', '[ViewController rf_pause:]', '[ViewController rf_continue:]', '[ViewController rf_continue:]'}, locations = 3, resolved = 3, hit count = 0
2.1: where = KTest`-[ViewController rf_save:] + 15 at ViewController.m:30:1, address = 0x0000000106d5aeef, resolved, hit count = 0
2.2: where = KTest`-[ViewController rf_pause:] + 15 at ViewController.m:34:1, address = 0x0000000106d5af0f, resolved, hit count = 0
2.3: where = KTest`-[ViewController rf_continue:] + 15 at ViewController.m:38:1, address = 0x0000000106d5af2f, resolved, hit count = 0
继续执行命令 c
(lldb) c//continue继续执行命令
Process 25671 resuming
断点禁用 breakpoint disable
(lldb) breakpoint set -n "[ViewController rf_save:]" -n "[ViewController rf_pause:]" -n "[ViewController rf_continue:]"
Breakpoint 2: 3 locations.
//禁用一个
(lldb) breakpoint disable 1.1
1 breakpoints disabled.
//禁用一组
(lldb) breakpoint disable 1
1 breakpoints disabled.
断点启用 breakpoint enable
(lldb) breakpoint enable 1.1
1 breakpoints enabled.
(lldb) break list
Current breakpoints:
1: names = {'[ViewController rf_save:]', '[ViewController rf_save:]', '[ViewController rf_pause:]', '[ViewController rf_pause:]', '[ViewController rf_continue:]', '[ViewController rf_continue:]'}, locations = 3, resolved = 3, hit count = 0
1.1: where = KTest`-[ViewController rf_save:] + 15 at ViewController.m:32:1, address = 0x0000000106222eef, resolved, hit count = 0
1.2: where = KTest`-[ViewController rf_pause:] + 15 at ViewController.m:36:1, address = 0x0000000106222f0f, resolved, hit count = 0
1.3: where = KTest`-[ViewController rf_continue:] + 15 at ViewController.m:40:1, address = 0x0000000106222f2f, resolved, hit count = 0
断点删除 breakpoint delete
注意删只能删一组,不能删一个;要是删一个只是禁用
(lldb) breakpoint delete 1.1
0 breakpoints deleted; 1 breakpoint locations disabled.
(lldb) breakpoint list
Current breakpoints:
1: names = {'[ViewController rf_save:]', '[ViewController rf_save:]', '[ViewController rf_pause:]', '[ViewController rf_pause:]', '[ViewController rf_continue:]', '[ViewController rf_continue:]'}, locations = 3, resolved = 2, hit count = 0
1.1: where = KTest`-[ViewController rf_save:] + 15 at ViewController.m:32:1, address = 0x0000000106222eef, unresolved, hit count = 0 Options: disabled
1.2: where = KTest`-[ViewController rf_pause:] + 15 at ViewController.m:36:1, address = 0x0000000106222f0f, resolved, hit count = 0
1.3: where = KTest`-[ViewController rf_continue:] + 15 at ViewController.m:40:1, address = 0x0000000106222f2f, resolved, hit count = 0
(lldb) breakpoint delete 1
1 breakpoints deleted; 0 breakpoint locations disabled.
(lldb) breakpoint list
No breakpoints currently set.
断点指南 help breakpoint
(lldb) help breakpoint
Commands for operating on breakpoints (see 'help b' for shorthand.)
Syntax: breakpoint <subcommand> [<command-options>]
The following subcommands are supported:
clear -- Delete or disable breakpoints matching the specified source
file and line.
command -- Commands for adding, removing and listing LLDB commands
executed when a breakpoint is hit.
delete -- Delete the specified breakpoint(s). If no breakpoints are
specified, delete them all.
disable -- Disable the specified breakpoint(s) without deleting them. If
none are specified, disable all breakpoints.
enable -- Enable the specified disabled breakpoint(s). If no breakpoints
are specified, enable all of them.
list -- List some or all breakpoints at configurable levels of detail.
modify -- Modify the options on a breakpoint or set of breakpoints in
the executable. If no breakpoint is specified, acts on the
last created breakpoint. With the exception of -e, -d and -i,
passing an empty argument clears the modification.
name -- Commands to manage name tags for breakpoints
read -- Read and set the breakpoints previously saved to a file with
"breakpoint write".
set -- Sets a breakpoint or set of breakpoints in the executable.
write -- Write the breakpoints listed to a file that can be read in
with "breakpoint read". If given no arguments, writes all
breakpoints.
For more help on any particular subcommand, type 'help <command> <subcommand>'.
断点执行
expression p po
- expression 可以执行一行代码的
(lldb) expression self
(ViewController *) $2 = 0x00007fd965c08d30
- p 是 expression的缩写
(lldb) p self
(ViewController *) $1 = 0x00007fd965c08d30
(lldb) help p
Evaluate an expression on the current thread. Displays any returned value
with LLDB's default formatting. Expects 'raw' input (see 'help
raw-input'.)
Syntax: p <expr>
Command Options Usage:
p <expr>
'p' is an abbreviation for 'expression --'
- po 是p 加了-o,而o又是调用对象的description方法
(lldb) po self
<ViewController: 0x7fd965c08d30>
(lldb) help po
Evaluate an expression on the current thread. Displays any returned value
with formatting controlled by the type's author. Expects 'raw' input (see
'help raw-input'.)
Syntax: po <expr>
Command Options Usage:
po <expr>
'po' is an abbreviation for 'expression -O --'
//-o 对象的description方法
-O ( --object-description )
Display using a language-specific description API, if possible.
···
···
···
日常使用
先看条件准备代码
### Person
@interface Person : NSObject
@property (nonatomic,copy) NSString *name;
@property (nonatomic,assign) int age;
@end
### ViewController
#import "ViewController.h"
#import "Person.h"
@interface ViewController ()
@property (nonatomic,strong) NSMutableArray<Person *> *models;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
Person *p = [[Person alloc] init];
[self.models addObject:p];
Person *p1 = [[Person alloc] init];
[self.models addObject:p1];
Person *p2 = [[Person alloc] init];
[self.models addObject:p2];
}
- (NSMutableArray<Person *> *)models {
if (!_models) {
_models = [NSMutableArray array];
}
return _models;
}
@end
赋值
(lldb) p self.view.backgroundColor = [UIColor redColor];
(UICachedDeviceRGBColor *) $3 = 0x0000600003ea4a40
(lldb) c//需要continue执行
Process 26689 resuming
对象需要强转
(lldb) p self.models
(__NSArrayM *) $6 = 0x00006000025b68e0 @"3 elements"
(lldb) p self.models.lastObject
(Person *) $7 = 0x0000600002bc3580
//没有强转无法赋值
(lldb) p $7.name = @"riceFun"
error: property 'name' not found on object of type 'id _Nullable'
//使用KVC赋值
(lldb) p [(Person *)$7 setValue:@"riceFun" forKey:@"name"];
//需要用强转接收
(lldb) p (Person *)self.models.lastObject
(Person *) $8 = 0x0000600002bc3580
(lldb) p $8.name
(NSTaggedPointerString *) $9 = 0xcd3d78cc84f1708a @"riceFun"
//强转后才能普通赋值
(lldb) p $8.name = @"dingding"
(NSTaggedPointerString *) $10 = 0xcbd8ad877046ca05 @"dingding"
连续执行
(lldb) p Person *p1 = [[Person alloc] init]; p1.name = @"lala"; p1.age = 5; [self.models addObject:p1];
(lldb) p self.models
(__NSArrayM *) $12 = 0x00006000025b68e0 @"4 elements"
(lldb)
调用堆栈
演示代码
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[self rf_save:1];
}
- (void)rf_save:(int)value{
[self rf_pause:1];
NSLog(@"rf_continue参数=%d",value);
}
- (void)rf_pause:(int)value{
[self rf_continue:1];
NSLog(@"rf_continue参数=%d",value);
}
- (void)rf_continue:(int)value{
NSLog(@"rf_continue参数=%d",value);
}
常用命令
- bt :查看调用堆栈
- frame frame select :指定某一个
- up :上一个
- down :下一个
- frame variable :变量参数查看
- thread return: 返回上一个堆栈并return
lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
* frame #0: 0x000000010264cc5a KTest`-[ViewController rf_continue:](self=0x00007fd37d409d30, _cmd="rf_continue:", value=1) at ViewController.m:51:35
frame #1: 0x000000010264cc24 KTest`-[ViewController rf_pause:](self=0x00007fd37d409d30, _cmd="rf_pause:", value=1) at ViewController.m:46:5
frame #2: 0x000000010264cbd4 KTest`-[ViewController rf_save:](self=0x00007fd37d409d30, _cmd="rf_save:", value=1) at ViewController.m:41:5
frame #3: 0x000000010264cb6f KTest`-[ViewController touchesBegan:withEvent:](self=0x00007fd37d409d30, _cmd="touchesBegan:withEvent:", touches=1 element, event=0x00006000013d8dc0) at ViewController.m:37:5
frame #4: 0x00000001064c6863 UIKitCore`forwardTouchMethod + 340
frame #5: 0x00000001064c66fe UIKitCore`-[UIResponder touchesBegan:withEvent:] + 49
frame #6: 0x00000001064d58de UIKitCore`-[UIWindow _sendTouchesForEvent:] + 1867
frame #7: 0x00000001064d74c6 UIKitCore`-[UIWindow sendEvent:] + 4596
frame #8: 0x00000001064b253b UIKitCore`-[UIApplication sendEvent:] + 356
frame #9: 0x000000010653371a UIKitCore`__dispatchPreprocessedEventFromEventQueue + 6847
frame #10: 0x00000001065361e0 UIKitCore`__handleEventQueueInternal + 5980
frame #11: 0x00000001036c3471 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
frame #12: 0x00000001036c339c CoreFoundation`__CFRunLoopDoSource0 + 76
frame #13: 0x00000001036c2b74 CoreFoundation`__CFRunLoopDoSources0 + 180
frame #14: 0x00000001036bd87f CoreFoundation`__CFRunLoopRun + 1263
frame #15: 0x00000001036bd066 CoreFoundation`CFRunLoopRunSpecific + 438
frame #16: 0x000000010c67fbb0 GraphicsServices`GSEventRunModal + 65
frame #17: 0x0000000106499d4d UIKitCore`UIApplicationMain + 1621
frame #18: 0x000000010264d054 KTest`main(argc=1, argv=0x00007ffeed5b2d68) at main.m:18:12
frame #19: 0x0000000104ad1c25 libdyld.dylib`start + 1
frame #20: 0x0000000104ad1c25 libdyld.dylib`start + 1
//指定某一个
(lldb) frame select 2
frame #2: 0x000000010264cbd4 KTest`-[ViewController rf_save:](self=0x00007fd37d409d30, _cmd="rf_save:", value=1) at ViewController.m:41:5
38 }
39
40 - (void)rf_save:(int)value{
-> 41 [self rf_pause:1];
^
42 NSLog(@"rf_save参数=%d",value);
43 }
44
// 上一个
(lldb) up
frame #3: 0x000000010264cb6f KTest`-[ViewController touchesBegan:withEvent:](self=0x00007fd37d409d30, _cmd="touchesBegan:withEvent:", touches=1 element, event=0x00006000013d8dc0) at ViewController.m:37:5
34 }
35
36 - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
-> 37 [self rf_save:1];
^
38 }
39
40 - (void)rf_save:(int)value{
//下一个
(lldb) down
frame #2: 0x000000010264cbd4 KTest`-[ViewController rf_save:](self=0x00007fd37d409d30, _cmd="rf_save:", value=1) at ViewController.m:41:5
38 }
39
40 - (void)rf_save:(int)value{
-> 41 [self rf_pause:1];
^
42 NSLog(@"rf_save参数=%d",value);
43 }
44
//查看变量参数
(lldb) frame variable
(ViewController *) self = 0x00007fd37d409d30
(SEL) _cmd = "rf_save:"
(int) value = 1
//返回上一个堆栈并修改参数
(lldb) thread return
(lldb) thread return
(lldb) frame variable
(ViewController *) self = 0x00007f8f01c04ce0
(SEL) _cmd = "rf_save:"
(int) value = 1
(lldb) p value = 2
(int) $0 = 2
(lldb) c
Process 27213 resuming
2020-03-12 19:21:52.828799+0800 KTest[27213:513167] XPC connection interrupted
2020-03-12 19:21:52.828817+0800 KTest[27213:512656] rf_save参数=2
流程控制
内存点断 watchpoint set
测试代码
#import "ViewController.h"
#import "Person.h"
@interface ViewController ()
@property (nonatomic,strong) Person *person;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.person = [[Person alloc] init];
self.person.name = @"dingding";
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
self.person.name = @"lala";
}
@end
设置内存断点
//设置
(lldb) watchpoint set variable self->_person->_name
Watchpoint created: Watchpoint 1: addr = 0x60000238a610 size = 8 state = enabled type = w
watchpoint spec = 'self->_person->_name'
new value: 0x0000000104346018
//触发
Watchpoint 1 hit:
old value: 0x0000000104346018
new value: 0x0000000104346038
(lldb) po 0x0000000104346018
dingding
(lldb) po 0x0000000104346038
lala
设置指针断点
(lldb) p &self->_person->_name
(NSString **) $0 = 0x00006000039433d0
(lldb) watchpoint set expression 0x00006000039433d0
Watchpoint created: Watchpoint 1: addr = 0x6000039433d0 size = 8 state = enabled type = w
new value: 4407803928
Watchpoint 1 hit:
old value: 4407803928
new value: 4407803960
(lldb) po 4407803928
dingding
(lldb) po 4407803960
lala
watchpoint 删除 禁用 列表
(lldb) watchpoint disable 1
1 watchpoints disabled.
(lldb) watchpoint enable 1
1 watchpoints enabled.
(lldb) watchpoint delete 1
1 watchpoints deleted.
断点添加command 执行命令
(lldb) breakpoint set --file ViewController.m --selector rf_save:
Breakpoint 2: where = KTest`-[ViewController rf_save:] + 19 at ViewController.m:46:6, address = 0x000000010eb81af3
(lldb) breakpoint list
Current breakpoints:
1: file = '/KTest/ViewController.m', line = 40, exact_match = 0, locations = 1, resolved = 1, hit count = 1
1.1: where = KTest`-[ViewController touchesBegan:withEvent:] + 70 at ViewController.m:42:6, address = 0x000000010eb81a96, resolved, hit count = 1
2: name = 'rf_save:', locations = 1, resolved = 1, hit count = 0
2.1: where = KTest`-[ViewController rf_save:] + 19 at ViewController.m:46:6, address = 0x000000010eb81af3, resolved, hit count = 0
//在断点后添加命令自动执行
(lldb) breakpoint command add 2
Enter your debugger command(s). Type 'DONE' to end.
> po self
> p self.view
> DONE
po self
<ViewController: 0x7fc26460b1c0>
p self.view
(UIView *) $1 = 0x00007fc264508320
target stop-hook
表示hook断点,-o表示一条指令
//添加target stop-hook
(lldb) target stop-hook add -o "frame variable"
Stop hook #1 added.
(lldb) target stop-hook add -o "po self"
Stop hook #2 added.
- Hook 1 (frame variable)
(ViewController *) self = 0x00007f821d00b400
(SEL) _cmd = "touchesBegan:withEvent:"
(__NSSetM *) touches = 0x00006000036d68c0 1 element
(UITouchesEvent *) event = 0x00006000007b88c0
- Hook 2 (po self)
<ViewController: 0x7f821d00b400>
//list
(lldb) target stop-hook list
Hook: 1
State: enabled
Commands:
frame variable
Hook: 2
State: enabled
Commands:
po self
//快速删除第二个target stop-hook
(lldb) undisplay 2
(lldb) target stop-hook list
Hook: 1
State: enabled
Commands:
frame variable
(lldb) target stop-hook delete 1
(lldb) target stop-hook list
No stop hooks.
////删除全部target stop-hook
(lldb) target stop-hook delete
Delete all stop hooks?: [Y/n] Y
脚本全局配置lldb指令
LLDB每次启动的时候都会去加载.lldbinit文件,所以我们可以去修改这个文件
- 1.用终端找到
.lldbinit文件
//在用户目录下查找
$ pwd
/Users/XXX
$ ls -a
. .zsh_history
.. .zshrc
.CFUserTextEncoding .zshrc.swm
.DS_Store .zshrc.swn
.Trash .zshrc.swp
.anyconnect Applications
.bash_history Desktop
.bash_sessions Documents
.cisco Downloads
.cocoapods Library
.gem Movies
.gemrc Music
.gitconfig Pictures
.itmstransporter Public
.oh-my-zsh RecentHostImage
.oracle_jre_usage block.cpp
.private_keys controlconfig.conf
.python_history id_rsa_dtdream__home
.sogouinput id_rsa_dtdream__home.pub
.ssh image
.viminfo sunlogincontrol.pid
.zcompdump-MacBook Pro-5.7.1
如果没有找到,自己创建(还是当前目录)
$ vi .lldbinit
- 2.写入lldb指令,保存退出
查看.lldbinit文件
$ cat .lldbinit
target stop-hook add -o "frame variable"
- 3.重新运行项目,可以看到lldb自动执行指令
image指令
- 快速查看某个类的信息
(lldb) image lookup -t Person
1 match found in /Users/baofan/Library/Developer/Xcode/DerivedData/KTest-aljwhltjgylwbnayiwdyysnxrrny/Build/Products/Debug-iphonesimulator/KTest.app/KTest:
id = {0x30000002b}, name = "Person", byte-size = 24, decl = Person.h:13, compiler_type = "@interface Person : NSObject{
int _age;
NSString * _name;
}
@property ( getter = name,setter = setName:,readwrite,copy,nonatomic ) NSString * name;
@property ( getter = age,setter = setAge:,assign,readwrite,nonatomic ) int age;
@end"
(lldb) image lookup -t Person
Best match found in /Users/baofan/Library/Developer/Xcode/DerivedData/KTest-aljwhltjgylwbnayiwdyysnxrrny/Build/Products/Debug-iphonesimulator/KTest.app/KTest:
id = {0x30000002b}, name = "Person", byte-size = 24, decl = Person.h:13, compiler_type = "@interface Person : NSObject{
int _age;
NSString * _name;
}
@property ( getter = name,setter = setName:,readwrite,copy,nonatomic ) NSString * name;
@property ( getter = age,setter = setAge:,assign,readwrite,nonatomic ) int age;
@end"
(lldb) image lookup -t ViewController
Best match found in /Users/baofan/Library/Developer/Xcode/DerivedData/KTest-aljwhltjgylwbnayiwdyysnxrrny/Build/Products/Debug-iphonesimulator/KTest.app/KTest:
id = {0x10000002b}, name = "ViewController", byte-size = 24, decl = ViewController.h:11, compiler_type = "@interface ViewController : UIViewController{
NSMutableArray * _models;
Person * _person;
}
@property ( getter = models,setter = setModels:,readwrite,nonatomic ) NSMutableArray * models;
@property ( getter = person,setter = setPerson:,readwrite,nonatomic ) Person * person;
@end"
- 查看当前进程加载了哪些个库
(lldb) image list
[ 0] B3A61FD3-D8DA-3C36-8349-ACEB1392496D 0x000000010ac1c000 /Users/baofan/Library/Developer/Xcode/DerivedData/KTest-aljwhltjgylwbnayiwdyysnxrrny/Build/Products/Debug-iphonesimulator/KTest.app/KTest
[ 1] EEA931D0-403E-3BC8-862A-CBA037DE4A74 0x000000010f66f000 /usr/lib/dyld
[ 2] 75369F31-702D-364A-95C3-8AFA9DD4B3A2 0x000000010ac2b000 /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/usr/lib/dyld_sim
[ 3] 56E47800-2CCB-3B7D-B94B-CCF5F13D6BCF 0x000000010af3a000 /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/Frameworks/Foundation.framework/Foundation
[ 4] 3EC683F6-36EF-33E1-8B98-C95E12BA38D2 0x000000010b53e000 /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/usr/lib/libobjc.A.dylib
[ 5] 7881AD7F-524C-3CFA-9595-02ED549166AA 0x000000010b58e000 /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneO
。。。
。。。
。。。
注意第一行 [ 0] B3A61FD3-D8DA-3C36-8349-ACEB1392496D 0x000000010ac1c000这里的0x000000010ac1c000地址是当前执行程序的首地址,将在下面用到
ASLR
在计算机科学中,地址空间配置随机加载(英语:Address space layout randomization,缩写ASLR,又称地址空间配置随机化、地址空间布局随机化)是一种防范内存损坏漏洞被利用的计算机安全技术。
mochO中打断点
方法真实地址 = ASLR偏移地址+虚拟地址
- 将工程跑起来后,找到工程包,拿到Mach-o文件用hopper打开
- 取方法
rf_test的虚拟地址0000000100001b00 - 回到工程先用image list命令取到ASLR地址
0x0000000108b46000中的偏移地址0x8b46000
(lldb) image list
[ 0] F3126824-4DDC-35AD-8948-40CB8CFFE795 0x0000000108b46000 /Users/baofan/Library/Developer/Xcode/DerivedData/KTest-aljwhltjgylwbnayiwdyysnxrrny/Build/Products/Debug-iphonesimulator/KTest.app/KTest
[ 1] EEA931D0-403E-3BC8-862A-CBA037DE4A74 0x0000000108ba3000 /usr/lib/dyld
- 设置指针断点:将ASLR偏移地址和虚拟地址相加就是方法的指针真实地址
(lldb) b -a 0x8b46000+0x0000000100001b00
Breakpoint 2: where = KTest`-[ViewController rf_test:] at ViewController.m:55, address = 0x0000000108b47b00