Lldb is a debugger that comes with Xcode, and as an iOS app developer, I usually use LLDB to debug code when I'm developing an app. In reverse applications, LLDB is also used to track the execution of the application.
LLDB also has a Python parser built in, using Python scripts to facilitate lldb debugging, such as automating some commands, or automating the processing of data, with reference to the official documentation: LLDB Python Reference.
The following is a concrete example of how a Python script is written:
First, get the offset address of the method
Run the system's own calculator Calculator.app
:
You can see a "about Calculator" option in the Calculator's menu:
If we are going to break the "about Calculator" event, we will set a breakpoint on this method.
First find the path to the calculator's executable file, the path is: /Applications/Calculator.app/Contents/MacOS/Calculator
.
Open the Hopper Disassembler
disassembly debugger, drag the executable file in, and wait for the hopper analysis to complete.
Enter "Showabout" in the search box on the left to search for a result:
Clicking on this result will jump to the assembly code of the method:
-[calculatorcontroller SHOWABOUT:]:00000001000093DD Push RBP ; Objective C Implementation defined at 0X1000188D0 (instance) 00000001000093de mov rbp, rsp00000001000093e1 mov rdi, Qword [ds:objc_cls_ref_nsdictionary]; Objc_cls_ref_nsdictionary, argument "instance" for method Imp___got__objc_msgsend00000001000093e8 mov rsi, Qword [DS:0X10001B6F0]; @selector (Dictionarywithobject:forkey:), argument "selector" for method imp___got__objc_msgsend00000001000093ef le A RDX, Qword [ds:cfstring_2000]; @ "00000001000093f6 Lea RCX, Qword [ds:cfstring_copyrightstartyear]; @ "Copyrightstartyear" 00000001000093FD call Qword [ds:imp___got__objc_msgsend]0000000100009403 mov RDI, rax0000000100009406 pop rbp0000000100009407 jmp Imp___stubs__nsshowsysteminfopanel ; Endp
The assembly code shows that the [CalculatorController showAbout:]
method has an offset address in the file 0x00000001000093dd
.
Second, use the LLDB debugger to set breakpoints
Next run the terminal and execute the following command to have the Lldb debugger attach to the process of the calculator:
Jobs: ~$ PS aux | grep calculatorjobs 79888 0.0 0.1 2781792 11620?? S 6:21 pm 0:01.07/applications/calculator.app/contents/macos/calculatorjobs 80204 0.0 0.0 2432772 568 s002 r+ 6:26 pm 0:00.00 grep calculatorjobs: ~$ lldb-p 79888 (lldb) process attach--pid 79888Process 79888 Stopp ed* thread #1: tid = 0x6030af, 0x00007fff912d34de libsystem_kernel.dylib ' Mach_msg_trap + ten, queue = ' Com.apple.main-threa d ', stop reason = signal SIGSTOP frame #0:0x00007fff912d34de libsystem_kernel.dylib ' Mach_msg_trap + 10libsystem_kernel . dylib ' mach_msg_trap:-> 0x7fff912d34de <+10>: Retq 0x7fff912d34df <+11>: Noplibsystem_kernel.dylib ' Mach_msg_overwrite_trap:0x7fff912d34e0 <+0>: Movq%rcx,%r10 0x7fff912d34e3 <+3>: Movl $0x1000020 ,%eaxexecutable module set to "/applications/calculator.app/contents/macos/calculator". Architecture set TO:X86_64H-APPLE-MACOSX. (LLDB) continueprocess 79888 resuming (LLDB)
Then execute the following command to get the ASLR offset address for the app:
(lldb) image list -o[ 0] 0x000000000cafa000[ 1] 0x00007fff93d51000[ 2] 0x000000010cb1e000......(lldb)
The 16-based address of the first row of data is the ASLR offset address of the 0x000000000cafa000
application, before we have found the [CalculatorController showAbout:]
offset address of the method 0x00000001000093dd
, then the address of the method in memory is 0x000000000cafa000 + 0x00000001000093dd
.
So we can execute the following command to set breakpoints for this method, note that there are no spaces on either side of the plus sign:
(lldb) br set -a "0x000000000cafa000+0x00000001000093dd"Breakpoint 1: where = Calculator`___lldb_unnamed_function161$$Calculator, address = 0x000000010cb033dd(lldb)
When you click the "About Calculator" option on the menu, the program will be broken:
Process 79888 stopped* thread #1: tid = 0x6709de, 0x000000010cb033dd Calculator`___lldb_unnamed_function161$$Calculator, queue = ‘com.apple.main-thread‘, stop reason = breakpoint 2.1 frame #0: 0x000000010cb033dd Calculator`___lldb_unnamed_function161$$CalculatorCalculator`___lldb_unnamed_function161$$Calculator:-> 0x10cb033dd <+0>: pushq %rbp 0x10cb033de <+1>: movq %rsp, %rbp 0x10cb033e1 <+4>: movq 0x12b98(%rip), %rdi ; (void *)0x00007fff78684488: NSDictionary 0x10cb033e8 <+11>: movq 0x12301(%rip), %rsi ; "dictionaryWithObject:forKey:"(lldb)
Third, write a Python script
So the question is, every time we debug the application to get the ASLR offset address manually, if you want to give multiple address break point, it will be written many times "ASLR offset address + method offset address", the operation is more cumbersome. If these repetitive operations can be done automatically, you should be able to save a lot of time during your normal use.
It's easy to do this with Python, and then we'll write a simple script that simplifies setting breakpoints. The main function of the script is to automatically obtain the application's ASLR address, when the user sets a breakpoint by simply entering the offset address of the method in the file, the script automatically adds the ASLR offset address and the method offset address, and then sets the breakpoint.
Create a new Python file, save to ~/sbr.py
with the following code:
#!/usr/bin/python#coding:utf-8import lldbimport commandsimport optparseimport shleximport re# get ASLR offset address def get_ASLR ( ): # Gets the return result of the ' image list-o ' command interpreter = Lldb.debugger.GetCommandInterpreter () Returnobject = Lldb. Sbcommandreturnobject () interpreter. Handlecommand (' Image List-o ', returnobject) output = Returnobject.getoutput (); # Regular matches the 16-binary address at the beginning of the first 0x match = Re.match (R '. + (0x[0-9a-fa-f]+) ', output) if Match:return Match.group (1) Else : Return none# Super breakpointdef SBR (debugger, command, result, internal_dict): #用户是否输入了地址参数 if not command : Print >>result, ' please input the address! ' return ASLR = GET_ASLR () If ASLR: #如果找到了ASLR偏移, set breakpoint debugger. Handlecommand (' br set-a '%s+%s "'% (ASLR, command)) Else:print >>result, ' ASLR not found! ' # and the initialization code to add your commands def __lldb_init_module (debugger, internal_dict): # ' command script a DD SBR ': Add an ' sbr ' life to Lldb# '-F sbr.sbr ': This command invokes the SBR function debugger of the SBR file. Handlecommand (' command script add sbr-f sbr.sbr ') print ' the ' SBR ' Python command has been installed and was ready for Use. '
You can then import the script into Lldb by executing the following statement in LLDB:
(lldb) command script import ~/sbr.pyThe "sbr" python command has been installed and is ready for use.(lldb)
The output shows that sbr
the python command named is already loaded and ready to use.
sbr
It Super breakpoint
means simply receiving a method to offset the address as an argument.
Next, verify the effect, clear the list of breakpoints, and then use the sbr
command to set breakpoints.
(lldb) br deleteAbout to delete all breakpoints, do you want to do that?: [Y/n] yAll breakpoints removed. (1 breakpoint)(lldb) sbr 0x00000001000093ddBreakpoint 2: where = Calculator`___lldb_unnamed_function161$$Calculator, address = 0x000000010cb033dd(lldb)
By clicking on the "About Calculator" option on the menu, the method has been successfully broken.
Iv. automatic loading of Python scripts when starting Lldb
For frequently used scripts, you can add a command load script to the LLDB initialization file so that the custom commands can be used when the LLDB is started.
Modify the ~/.lldbinit
file to include a line in the file:
command script import ~/sbr.py
To re-enter LLDB, you can see that the script has been loaded automatically:
Jobs: ~$ lldbThe "sbr" python command has been installed and is ready for use.(lldb) command source -s 1 ‘/Users/Jobs/./.lldbinit‘The "sbr" python command has been installed and is ready for use.(lldb)
Hardening the Lldb debugger with a python script