Two blogs will be posted for this topic and two free apps are picked to show some differences based on their build options.
iOS app manual decryption can be done by the following steps.
- Finding the starting offset and the size of encrypted area in an app’s executable
- Finding the memory loading address of an app under test
- Dumping the decrypted portion of an app on memory using a debugger
- Overwriting an app’s executable with dumped binary data
An app downloaded from Apple Store is encrypted and you can find the encryption information in the header of an app’s executable. Some fields in the header we use are cryptid (1: encrypted, 0: plain), cryptoff (starting offset of encrypted area), and cryptsize (size of encrypted area). There are other fields we need to check if an app supports multiple architectures and you will see them in the following blog
When an app is loaded, its encrypted area is decrypted by loader. Take advantage of this process and dump the decrypted area using a debugger.
The last step for the decryption will be overwriting the encrypted area of an executable with the dumped data.
Single architecture and no PIE
An app in this category is the simplest one to decrypt because you can easily find a starting offset/size in an executable and its code and data sections are loaded as set in its header. You will see how to decrypt an app built with PIE in the 2nd part.
Let’s take a look at a simple app in terms of decryption.
Log into your jailbroken device via ssh, and go to the directory where an app resides. The directory will be under “/var/mobile/Applications/”. Run otool to see how the app is built (Figure 1).
You can confirm this app is compiled without PIE with the result of “otool -vh”, but you can see it is encrypted by checking cryptid (1 means encrypted, 0 means decrypted) on Figure 1. cryptoff is 4096 (0x1000) and cryptsize is 405504 (0x63000) in this example. Hence we will overwrite the area between 0x1000 and 0x64000 with decrypted data at a later time.
To see where this app is loaded on memory, run otool again with -l option (Figure 2).
It will be loaded at 0x1000, which means the decrypted area of the app will be loaded between 0x2000 (base address + cryptoff) and 0x65000 (base address + cryptoff + cryptsize). So we will dump this area.
Again we will not decrypt any encrypted data by ourselves. Instead we ask loader to do that for us and we just dump decrypted data using a debugger. Run the app under test. Then attach gdb to the loaded app and dump memory as follows (see Figure 3).
Copy the app’s executable and decrypted.bin to your Mac.
Before overwriting the executable, let’s see the snippet of class-dump-z result
$ ./class-dump-z GuessWord
Now overwrite the file with decrypted.bin
$ dd seek=0x1000 bs=1 conv=notrunc if=./decrypted.bin of=./GuessWord
We are not done yet, if you run otool again, you will see that the executable still seems to be encrypted (Figure 5).
We need to update cryptid as well. Open the executable with any hex editor, and search “/System/Library/Frameworks”. Before the string, you can find something similar to the highlighted string as follows (see Figure 6).
You need to change the number 01 to 00 at the end of highlighted part. So it will be like this (see Figure 7).
Check encryption status again with otool (Figure 8).
Let’s check the result of class-dump-z
$ ./class-dump-z GuessWord
- OS: iOS 6.01
- Device: jailbroken iPod 4G
- tools: otool, gdb, class-dump-z
- Hacking and Securing iOS Applications – O’REILLY: chapter 7