In the last article, we looked at the Runtime from Fishhook. The HOOK system C function already mentioned some commands using LLDB. Most of the time we can’t actually get the source code when we’re playing reverse. Therefore, it is very necessary to know some LLDB to assist my learning (breaking) of other people’s APP.
Since I started playing reverse, there are always some big guy to send me some transfer information (why not send red envelopes? There is a limit on the amount of red envelopes. It’s all going to look something like this.
Do tao friends want to receive such red envelopes? After reading this article, you can. If you don’t get one, let me know in the comments section and I’ll rewire you.
Needless to say, the content of this article is very simple, very easy to understand, but need to remember more things, financial division strongly recommend a careful heart, in case of need.
Today’s DEMO is also relatively simple, you can download it here: LLDB
The contents of this article are as follows:
- LLDB
- Create LLDB scripts
- chisel
- DerekSelander-LLDB
- Real manipulation of wechat red envelopes
A, LLDB
Dynamic debugging tools built into Xcode by default. The standard LLDB provides an extensive set of commands designed to be compatible with older versions of GDB commands. In addition to using standard configurations, you can easily customize the LLDB to suit your needs.
The command format is as follows:
<command> [<subcommand> [<subcommand>...]] + <action> + [-options [option-value]] + [argument [argument...]]
Copy the code
[]
Indicates that the command is optional, either with or without it<command>
(Command) and<subcommand>
(subcommand) :LLDB
Name of the debugging command. Commands and subcommands are arranged hierarchically: a command object creates a context for the subcommand object that follows it, which creates a context for its subcommands, and so on.<action>
: Some actions that we want to perform in the context of the previous command sequence.<options>
: Action modifiers Usually with some value.<argument>
: represents various things depending on the context of the command being used.
The full lldb command names are often long, but any unique short form can be used. Instead of “breakpoint set”, “br se” is also acceptable. The LLDB command is usually very long, but as long as you can think of an abbreviation that is sufficiently short and unique, the abbreviated command is valid. For example, breakpoint set == br se
You can query all LLDB commands on the LLVM official website or Apple official website. I’ll list some of the more common commands in this article.
1. Breakpoint setting
Name of the command | Command Example |
---|---|
Set breakpoints by name | breakpoint set –name main |
Set breakpoints using memory addresses | breakpoint -a 0xXXXXXXXX |
Remove breakpoints | breakpoint delete 1 |
Make the breakpoint invalid/effective | breakpoint disable/enable 2 |
View all breakpoints | breakpoint list |
All names in OC include breakpoints for Test4’s methods | breakpoint set -r Test4 |
Feel free to use two style diagrams:
These commands can be found here, along with a screenshot from the official website
Breakpoint command
Name of the command | Command Example |
---|---|
Add a command to a breakpoint | breakpoint command add 1 |
View all breakpoint commands | breakpoint command list |
Delete breakpoint command | breakpoint command delete 1 |
Enable/disable a breakpoint command | breakpoint command enable/disable |
Add a command to a breakpoint | breakpoint command delete |
Add a piece of code to a breakpoint that automatically executes terminal code each time it is broken, as shown below:
# set a breakpoint for all functions named xx
breakpoint set- Name xx br s-n xx b xx# set a breakpoint on line L specified in file F
breakpoint set- File F -line L br s-f F -l L
b F:L
The debugger will break only when the thread is executed.
# A piece of code may have multiple threads, cutting between different threads. This is where thread breakpoints can be used
breakPoint set- f File name - L line number - t Thread ID# conditional breakpoint
breakpoint set -f viewController.m -l 362 -c "width > 68"
# set a breakpoint on all C++ functions named xx (hopefully no C functions with the same name)
breakpoint set- Method XXX br S-m XXX# set a breakpoint for an OC function [objc msgSend:
breakpoint set- the name"-[objc msgSend:]"
b -n "-[objc msgSend:]"
# set a breakpoint on all OC methods named xx (hopefully no C or C++ functions named xx)
breakpoint set- Selector xx br s-s count# set a breakpoint for all functions whose names match the regex.
breakpoint set --func-regex regular-expression
br s -r regular-expression
# set a breakpoint at the function func_addr
br set -a xxx
# one-time breakpoint
# -- is the end of a command option, and can be omitted if no option is available
breakpoint set --one-shot true --name "-[objc msgSend:]"
# breakpoint list
breakpoint list
br l
# breakpoint delete
breakpoint delete xxx # index Specifies the breakpoint number. If it is null, all breakpoints are deleted
breakpoint delete xxx -f # force delete (no confirmation required)
br del index
A breakpoint is automatically executed when triggered
--auto-continue # parameters
(lldb) b CCCryptorCreate
Breakpoint 1: where = libcommonCrypto.dylib`CCCryptorCreate, address = 0x000000011047e1b7
(lldb) breakpoint modify --auto-continue true 1
(lldb) br list
Current breakpoints:
1: name = 'CCCryptorCreate', locations = 1, resolved = 1, hit count = 0 Options: enabled auto-continue
1.1: where = libcommonCrypto.dylib`CCCryptorCreate, address = 0x000000011047e1b7, resolved, hit count = 0
(lldb) breakpoint command add -s python 1
Enter your Python command(s). Type 'DONE' to end.
print "Hit this breakpoint!"
DONE
# skip times
-i <count> (--ignore -count <count>)
breakpoint set-f viewDidLoad -i 3 -o < Boolean > Only break a breakpointset -F viewDidLoad: -o yes
Copy the code
3. Execute code
Expression is the command to execute the code, also known as the commonly used P, according to the official website of the uniqueness of the abbreviation e, expr, is also ok. As shown in figure:
4, view the stack, flow control
Name of the command | Command Example |
---|---|
View all current stacks | bt |
Returns the previous stack | up |
View a stack | frame select 1 |
View the arguments for the current stack | frame variable |
The stack rolls back to the previous entry | thread return |
Program continues | c |
Step by step | n |
Move on to the next function (method) | s |
Assembler level single step next | ni |
Assembler level to the next function (method) | si |
Also a style diagram:
Memory breakpoints
A breakpoint is triggered whenever a property address changes. Equivalent to setting KVO for a property.
Name of the command | Command Example |
---|---|
Look at a variable directly | watchpoint set variable global_var |
Look directly at the address of a variable | watchpoint set expression — 0xxxxxx |
Remove breakpoints | watchpoint delete 1 |
Make the breakpoint invalid/effective | watchpoint disable/enable 2 |
View all breakpoints | watchpoint list |
5. Library file image
Name of the command | Command Example |
---|---|
View the libraries used in the project (including MachO himself) | image list |
Find the original address of an executable or shared library | image lookup –address 0x0000000100000de0 |
Output NSURL member variable and attribute information. | image lookup –type NSURL |
Export all symbol tables for executables and shared libraries | image dump symtab |
7. HOOK each breakpoint
For each breakpoint, execute a piece of code.
Name of the command | Command Example |
---|---|
Add a HOOK | target stop-hook add -o “frame variable” |
Direct all hooks | target stop-hook list |
Remove the hooks | target stop-hook disable 1 |
Disable HOOK | target stop-hook disable/enable 2 |
8, register && memory
Name of the command | Command Example |
---|---|
Displays the values of all registers for the current thread | register read –all |
Write 0x01 to register X2 | register write x2 0x01 |
Read the value in memory 0x0002A8A2D | Memory read 0x0002A8A2D (abbreviated x 0x0002A8A2D) |
9. Support Python
Such as:
script print "Here is some text"
Copy the code
2. Self-made LLDB scripts
1、.lldbinit
The LLDB is essentially a program (or process) that loads an initialization file every time it is started. This file is called. Lldbinit, and its address is in the root directory:
~ /Copy the code
If you don’t have this file in your root directory, just use ittouch
Let’s create one
Lldbinit touch ~/.lldbinit // Write vi ~/.lldbinit // to check cat ~/.lldbinitCopy the code
Write the following code in.lldbinit
target stop-hook add -o "frame variable"
Copy the code
Restart Xcode, run the project, and add breakpoints anywhere. You’ll notice that the frame variable is automatically executed when the breakpoint is broken
Here’s an interesting thing to read: Lldbinit can help us preload part of the command, LLDB supports Python syntax, so can not part of Python code encapsulation, use. Lldbinit mechanism, and then we can use our own packaged code, let us more convenient use LLDB?
No sooner said than done.
2. Script practice
Before, we used the command image list to check the first address (ASLR) in the memory after the App runs. This address is actually added with the value of pageZero. In fact, the command image list -o can directly check the ASLR, as shown in the figure:
lldbPyDemo.py
import lldb
import re
Get the ASLR offset address
def fy_get_ASLR(debugger, command, result, internal_dict):
# get the result of 'image list -o'
interpreter = lldb.debugger.GetCommandInterpreter()
returnObject = lldb.SBCommandReturnObject()
interpreter.HandleCommand('image list -o'.returnObject)
output = returnObject.GetOutput();
# regex matches the first hexadecimal address starting with 0x
match = re.match(r'.+(0x[0-9a-fA-F]+)', output)
if match:
print match.group(1)
else:
return None
# And the initialization code to add your commands
def __lldb_init_module(debugger, internal_dict):
# 'command script add fy_get_ASLR' : add a 'fy_get_ASLR' command to LLDB
# '-f lldbpydemo. fy_get_ASLR' : This calls the fy_get_ASLR function of lldbPyDemo
debugger.HandleCommand('command script add fy_get_ASLR -f lldbPyDemo.fy_get_ASLR')
print 'The "fy_get_ASLR" python command has been installed and is ready for use.'
Copy the code
Also, loading lldbPydemo.py every time is a bit annoying. Add its path to.lldbinit to automatically load lldbPydemo.py every time.
All the open interfaces of LLDB can be found on the official website for students who are interested in studying.
Third, chisel
Chisel is a collection of LLDB commands to assist in the debugging of iOS apps. Chisel is a set of LLDB commands for users to Debug iOS apps
The above introduction is from chisel website.
Since it supports BREW, the installation is simple:
brew update
brew install chisel
Copy the code
If the. Lldbinit file is not available locally, create it in the root directory and open it. Otherwise, open it directly
// Create the.lldbinit file touch. Lldbinit // open the.lldbinit file openCopy the code
Then append the following command to the. Lldbinit file
command script import /path/to/fblldb.py
Copy the code
Restart Xcode to use it.
Here are some useful commands:
Name of the command | Command description | iOS | OS X |
---|---|---|---|
pviews | Prints all views of the current KeyWindow | Yes | Yes |
pvc | Prints all the VC’s of the current KeyWindow | Yes | No |
fv | Find and print views based on regular expression printing | Yes | No |
fvc | Find and print VC based on regular expression print | Yes | No |
pactions | Events to find | Yes | No |
presbonder | Response chain | Yes | No |
pclass | Inheritance chain | Yes | No |
pmethods | Look at class methods/instance methods | Yes | No |
pinternals | Viewing member variables | Yes | No |
taplog | After entering, the breakpoint mode will exit, and then click any responsive view on the screen, it will automatically enter LLDB mode and print the button. | Yes | No |
flicker | Calling this directive in breakpoint mode flashes the view by memory address | Yes | No |
vs | Enter debug mode by memory address and the current view will turn red | Yes | No |
show/hide | Show/hide View or Layer without continue | Yes | Yes |
bmessage | A symbolic breakpoint set on a method of a class or on an instance is triggered even if the implementation is not displayed. The viewWillAppear method, for example, is not implemented in the current controller but wants to trigger an interrupt when it is called. | Yes | Yes |
wivar | Equivalent to a watchpoint | Yes | Yes |
Here is a use case diagram for Pviews and PVC:
Fourth, DerekSelander – LLDB
Derekselander-lldb is a collection of LLDB scripts like Chisel, with most of the same functionality, but derekselander-llDB has a very useful feature: SBT: view the current stack and recover the symbol table as much as possible! This is pretty cool, because most of the apps we studied were already unsigned as we went backwards! [image-57C79-1554654483282] [image-57C79-1554654483282]
You can also refer to the official website: Derekselander-llDB
The derekselander-LLDB installation process is not as fancy as chisel and does not require brew. The installation process is as follows:
1, To Install, Copy the lldb_Commands Folder to a dir of your choosing. 2, Open up (or create) ~/. Lldbinit 3, Add the followingcommand to your ~/.lldbinit file: command script import /path/to/lldb_commands/dslldb.py
Copy the code
Five, practice tampering with wechat red envelopes
LLDB since so good, then we use LLDB to continue to analyze our lovely wechat, O(∩_∩) ha ha ~.
Using the previous article iOS reverse (4)- code injection, stealing wechat password mentioned methods, directly using Xcode will run wechat on the phone.
Feel free to send a maximum red envelope (0.01 yuan) through your wechat account to enter the chat page as shown below:
Stop the program at this point and go to the LLDB debug page.
pviews
0.01
Label
As you can see from the figure above, the control that displays the amount is MMUILabel, much like a UILabel, and the address is 0x10e6C7D00. The code to change the text according to the LLDB p command is as follows:
p ((UILabel *)0x10e6c7d00).text = @"¥88888.88"
Copy the code
The amount is just a statically changed string that doesn’t actually make us a penny more or less.
In ordinary life, reverse is actually a very interesting thing, in the increase of their knowledge at the same time, but also give us a lot of joy, think about such a screenshot to a friend circle is not a thief face. Haha, maybe all the screenshots of red envelope transfer in your moments also come from this way? Especially daigou who often send such transfer messages.
Six, summarized
Lldbinit (llDBinit) ¶ LLDB (llDBinit) ¶ LLDB (llDBinit) ¶ LLDB (llDBinit) ¶ This was followed by facebook’s Chiesl and Derekselander-lldb scripts. Finally, LLDB is used for some simple UI analysis and simple code execution.
However, every time you use LLDB, you need to break the program, which is not a very good experience. Is there a capability that allows us to do real-time dynamic analysis of the APP while it’s running normally? The answer is yes, Cycript is such a thing, and in the next article, we will cover some very, very important aspects of reverse engineering around Cycript!
Reference:
- WWDC 2018: Xcode and LLDB debugging tips for improving efficiency
- Enhance the LLDB debugger with Python scripts
- Introduction to the LLDB debugger
- LLDB