LLDB is the abbreviation of low level Debugger , lldb is often used in the debugging of iOS development,LLDB is the dynamic debugging tool built in Xcode . With Lldb you can debug your application dynamically, and if you don't do other extra processing because Debugserver lacks task_for_pid permissions , you can only use LLDB to debug your own app. Then this blog will use LLDB to debug the app downloaded from AppStore, and combine the hopper to analyze the structure inside the third-party app. Lldb and Hopper combination , will let you see different things, this blog will be with you to enjoy the charm of lldb and Hopper.
one, SSH USB connection--usbmuxd
Before we ssh connect the iOS device is connected through the local area network is the WiFi, when the network environment is not good to enter a command line card, so we need a faster way to access the iOS device, that is, using a USB connection. In this blog, whether it is SSH connection iOS device or lldb connection iOS device, we all use the way of USB to make the device access, so the speed is not enough. The first part of this blog is about how to use USB for device SSH connection, which is the basis of this blog, but the content is simple.
1. Get Usbmuxd
Usbmuxd Although the latest version is 1.1.0, the 1.1.0 version and the 1.0.9 version only support the Linux system , which means that our Mac still has to download the v1.0.8 version, ( usbmuxd-v1.0.8). After downloading, unzip the downloaded file as follows:
2. Use usbmuxd to connect iOS jailbreak devices(1) Using Usbmuxd forwarding interface
Switch to the Python-client directory under the above folder , and execute the command below to forward the 22 port on iOS to Port 2221 on the current device as shown below.
. /tcprelay.py-t 22:2221
Below is the result of executing the above command:
(2) using SSH to connect to the jailbreak device
SSH [email protected]-P 2222
The above command is the SSH connection command-P followed by the above forwarded port, after executing the above command, the result is as follows:
With usbmuxd , we can connect our iOS jailbreak device via USB, and the LLDB connection iOS device below is also connected via USB. Please see below for details.
Second, the configuration Debugserver
When doing iOS development, enter lldb commands on your Mac to control the iOS app because there is a debugserver server in our iOS client. The debugserver is dedicated to the LLDB client that connects to the Mac, receives the commands provided by the LLDB, and executes accordingly. If your iOS device has been debugged, the device will be installed on debugserver, but the debugserver can only be used to debug your own app. If you want to debug an app you get from AppStore , then we need to process the debugserver on the iOS device. This part is to deal with our debugserver.
1. Get Debugserver
First we have to find debugserverin the iOS device and copy it to the MAC for processing, below is the debugserver in the /developer/usr/bin directory. This debugserver only supports debugging our own app, and if you need to debug someone else's app, this debugserver needs to be processed and the process is described below.
2. Slimming the Debugserver
Lipo-thin arm64 debugserver-output Debugserver
Go to the Debugserver directory in the Mac to execute the above command,-thin to fill in your test machine corresponding ARM architecture, because my test machine is the IPhone 6 Plus, is the arm64 architecture , So the parameter here is arm64, if you are iPhone5 device, then it is armv7s .
3. Add task_for_pid permissions to Debugserver
After adding task_for_pid permissions to Debugserver, we can use lldb to debug other apps. in this section we need an XML file that stores the configuration information, which is as follows. You can copy the text below and save it as a ent.xml .
<!DOCTYPE plist Public "-//apple//dtd plist 1.0//en" "Http://www.apple.com/DTDs/PropertyList-1.0.dtd "><plistversion= "1.0"><Dict> <Key>Com.apple.springboard.debugapplications</Key> <true/> <Key>Get-task-allow</Key> <true/> <Key>Task_for_pid-allow</Key> <true/> <Key>Run-unsigned-code</Key> <true/></Dict></plist>
We need to use the Ldid command when giving Debugserver, and if you don't have the LDID command installed on your Mac, use brew to install it. Execute the command line below to assign Task_for_pid permissions to our debugserver. It is important to note that the-s and ent.xml have no spaces in the file name.
Ldid-sent.xml Debugserver
Below are the steps we handle Debugserver, as follows:
4. Copy the debugserver to the iOS device
The final step is to copy the processed debugserver to our jailbreak device and assign the executable permission to Debugserver. Because the debugserver in the /developer/usr/bin directory is read-only, you cannot copy the processed debugserver to the above file, and you will copy the processed debugserver to /usr/ bin/ directory (of course here we use Ifunbox to copy files).
After copying the debugserver to the /usr/bin directory, execute the command under Assign permissions and assign the executable permission to Debugserver as follows:
chmod +x Debugserver
Once you have finished assigning permissions, you can use the debugserver command to turn on Debuserver, as follows:
third, the opening of Debugserver and LLDB connection1. Turn on Debugserver
In the jailbreak device, we can open the Debugserver through the command line below, we are here to debug the app as an example. The command below is to start Debugserver to listen for access from any IP address, the access port of the iOS device is 12345, the app to debug is "WeChat". The command is as follows:
Debugserver *:12345-a "WeChat"
The effect of executing the above command on our iOS device is as follows, after executing the above command, our iOS device waits for the Mac terminal Lldb to access.
2.LLDB Connection Debugserver
LLDB connection Debugserver can be connected using WiFi, but WiFi is unstable and especially slow, so here we use usbmuxd for lldb and Debugserver connection.
(1) Port forwarding
And the first part of the same, we use USBMUXD for port forwarding, the above "12345" Port to a Mac local port, where we use "12345" port. Go to python-client under the usbmuxd-1.0.8 directory to execute the command below.
./tcprelay.py-t 12,345:12,345
The procedure is as follows:
(2) Mac-Lldb Access
After the port forwarding, we begin to enter LLDB mode and then make a debugserver connection. First enter the LLDB command on the terminal and enter the address below to connect. Because we use USBMUXD for port forwarding, we can use the local loopback test address to make a debugserver connection.
Process Connect connect://127.0.0.1:12345
Below is the result of the connection, after Lldb and Debugserver are established, we can use the LLDB to debug the application.
Four, Hopper + lldb
In the previous blog "iOS reverse engineering to WeChat shelling " we have to carry out the shelling, so the use of hopper processing is not a problem. In this part we will combine Hopper and lldb to play the role of double swords. This section is also part of the actual combat in this blog post.
1. View the WeChat in the thread
Lldb Connect on debugserver , we first use the command below to view all modules in the current process. From these output information we can find the "WeChat" process in virtual memory relative to the base address of the module offset.
Image List-o-F
After the LLDB is connected to Debugserver, some of the results of executing the above command output are shown below. Below, the first one is the "WeChat" program related information. The red box on the left is the ASLR offset (random offset), the ASLR offset is actually the virtual memory address, relative to the module base address offset. The address in the red box on the right is the offset address.
In the introduction of the address of this piece is first familiar with the following two concepts:
- Start address of module in memory----module base site
- ASLR offset----The offset of the virtual memory start address from the base site of the module
From the output below we can know:ASLR offset = 0x5b000, module offset after base address = 0x5f000
Below is the decrypted installation package opened with Hopper, the starting address from which we can see is 0x4000, this address is the module before the offset of the address, that is, the module in the virtual memory of the starting address. From Hopper we can know: Base address before module offset =0x4000
From the above two sets of data we can draw:
Base Address after module offset (0x5f000) = ASLR offset (0x5b000) + module offset pre-base address (0x4000)
The above formula is especially important because the hopper shows "module offset before base address" and LLDB to operate "base site after module offset". So from Hopper to Lldb, we're going to do an address offset conversion. This will be used more than once in the bottom. Of course, one thing to note is that the hopper and LLDB have the same number of AMR architectures selected, either 32-bit or 64-bit, and if the number of bits does not match, then the computed memory address is definitely wrong .
2. Use Lldb to add breakpoints to logins(1), plus the analysis before the breakpoint
"Breakpoints" is something that is often used in iOS development, and the next thing we do is add a breakpoint to the page jump when you click Sign in. Just click the login button on the left to add a breakpoint when you jump to the right page. Let's add breakpoints to the initialization method on the right page for the moment.
To add a breakpoint to the right-hand page above, you first need to know the memory address of the "phone number Login" View controller above before you can add breakpoints using LLDB. Then the task of finding the memory address of the above view controller is given to our hopper. In Hopper we search for "login" and then we filter out the good viewcontroller with the Login keyword, and then we look for the suspect target object again in the filtered results. Then we found a class called "wcaccountphonelogincontrollogic" (We can translate English, probably meaning " Mobile account Login control Logic "), From the name of this class it is not difficult to infer that this class is most likely the "Mobile account Login" Page we are looking for.
After the above analysis, we decided to give the class "Initwithdata" (which is definitely an initialization method) to add breakpoints using LLDB.
(2), Location breakpoint address
After the first step to find the method in the class that added the breakpoint, we then calculate the memory address of the method, and then use LLDB to add a breakpoint to the address. By Hopper we can easily navigate to the position of the "Initwithdata:" method described above, as shown below. The address under this "asterisk" in the lower part is the base site before the "Initwithdata:" Method is offset. Based on the above formula, it is easy to calculate the "base address after offset", which is the real memory address. The algorithm looks like this:
Initwithdata memory address = 0x1304b60 + 0x5b000 (alsr offset) = 0x135fb60
(3), add breakpoint
Use the command below to add a breakpoint to the above address. After the breakpoint is added, clicking the login button will jump to the "Phone number Login" page to execute the breakpoint, and the red box below is the effect after the breakpoint is executed. From the bottom we can see that the breakpoint number is 1,breakpoint is the breakpoint number, the number will be used in the operation of the breakpoint, the below will give an example .
BR S-a 0x135fb60
(4), single Step Execution of breakpoints (Ni, si)
You can use Nexti (abbreviated: NI) and Stepi (abbreviated: SI) to perform one-step debugging. Ni encounters jumps that do not go into the jump, and Si jumps to the corresponding branch. Below is the effect of single-step debugging with Si and NI.
(5) Release execution of the breakpoint (c)
Command C can execute the breakpoint, if the C command is executed, because there is only one breakpoint, the breakpoint executes, it jumps to the "Phone number landing page".
(6) Disabling and opening of breakpoints
As mentioned above, the breakpoint created above is numbered 1, and we want to disable and open the breakpoint, as shown in the following command:
BR Dis 1--Disable (disable) breakpoint with number 1
BR en 1--enabled (enable) breakpoint with number 1
BR Dis-Disables all breakpoints
BR en--Enable all breakpoints
The result of the operation is as follows, when the breakpoint is disabled, click the login button will not trigger the breakpoint. When the breakpoint is restarted, clicking the login button will trigger the breakpoint. The specific effects are as follows:
(7) Deletion of breakpoints
BR del 1--Remove (delete) breakpoint with number 1
BR del--Delete all breakpoints
3. Value of the output register (p, PO)
In iOS development, when we use LLDB debugging, we often use the PO command to output a variable or constant value. When using LLDB to debug WeChat, we can also use some commands to output the value in the register. We use $ to access the values in a register and print using the P command. Below is the P command to print the contents of the R1 register, before printing the $R1 for type conversion, PO command output Objective-c object, and P output is the C language type of data. As shown below:
We can also print the value stored in an address, which is the output of the value stored at the address where the $sp pointer refers:
p/x $SP
4. Modify the value in the Register
Not only can we view the values in some registers, but we can modify the values in the register by modifying the following commands.
Register Write Register value
And then we're going to go through an example. register Write This command, through the analysis of the login module in Hopper, we are not difficult to find "wcaccountmanualauthcontrollogic "Thehandleauthresponse:" Method in this class is used to handle the "Login Authentication Response" method. In other words, "handleauthresponse:" is responsible for handling the network response of the login business logic, and there is a comparison (CMP r0, R1)in front of this function, which jumps according to the results of r0 and R1 comparisons.
The next thing we want to do is to change the value in the R1 register when we compare the values in the registers R0 and R1, and then see how the app works. Below this is the random input phone number and password when prompted. That is, the normal flow will pop up below the box.
The next thing we do is to add a breakpoint to the memory address of 0x1063a24 + 0x5b000 = 0x10bea24 (CMP) and then to modify the value of the register R1. Below is to add a breakpoint to 0x10bea24 this memory address, and after entering the phone number and password, click Login will execute the breakpoint we added, as shown below. At the breakpoint we see clearly the CMP r0, R1 This line of arm instructions.
Next we print the values in R0 and R1,$r 0 = 8, $r 1 = 351. Then we change the value in the $R1 to 8, and then enter C to continue execution, and we find that the alter of the normal process does not pop up, but we re-made a network request.
The above example is done on a 32-bit system, and if you are using a arm64 architecture device, such as Iphone6plus, your address will be one-fold longer than the above address. The bottom two are experiments using the iPhone 6 Plus jailbreak device, which can be compared with the above steps, although different, but the above content is also applicable when debugging the content below.
The content of this blog is here, so, you should be able to use LLDB and hopper together. Today we take "" as an example, and have no other meaning, just want to implement in real instance. The reason to use the experiment is to be safe enough, after all, the team is still very powerful. Because with my jailbreak device after the above experiment, the jailbreak device can not login account, it is certainly the background to monitor the "jailbreak device" abnormal behavior, thereby doing some security measures.
" Attack and Defense " is like " Spear and shield " complement each other.
iOS reverse engineering use LLDB USB connection to debug third-party apps