As usual, we should set the breakpoint at 0x6db3000 + 0x2261ab94 = 0x293CDB94. Execute
“c” to trigger the breakpoint:
(lldb) br s -a 0x293CDB94
Breakpoint 1: where = Foundation`NSLog, address = 0x293cdb94
(lldb) c
Process 450336 resuming
Process 450336 stopped
* thread #1: tid = 0x6df20, 0x293cdb94 Foundation`NSLog, queue = ‘com.apple.main-thread,
stop reason = breakpoint 1.1
frame #0: 0x293cdb94 Foundation`NSLog
Foundation`NSLog:
0x293cdb94: sub sp, #12
0x293cdb96: push {r7, lr}
0x293cdb98: mov r7, sp
0x293cdb9a: sub sp, #4
Print out LR:
(lldb) p/x $lr
(unsigned int) $0 = 0x00107f8d
Because the base address of MainBinary is 0x000fc000, open MainBinary in IDA and jump to
0x107f8d - 0xfc000 = 0xBF8D, as shown in figure 6-51.
Figure 6-51 TestFunction3
0xBF8D is right below “BLX _NSLog”, so we have found the caller of NSLog. One thing
should be noted is that because LR may change in the caller, the breakpoint should be set at the
base address. Pretty easy, huh?
-^ Execute “ni” to get inside caller
Although “Inspect LR” is straightforward enough, we’ve played a trick: because we’ve
already known NSLog is called inside MainBinary, we’ve subtracted MainBinary’s ASLR offset
from LR to get the final result. But in more general cases, we don’t know which function calls
NSLog, not to mention which image calls NSLog, so we don’t know whose ASLR offset should
be subtracted from LR. To solve this problem, our theoretical base is still “After the execution of
B, the process needs to go back to A to continue execution”; if we set a breakpoint at the end of