Platform
ios
Last updated: May 15, 2024

Runtime Reverse Engineering

Runtime reverse engineering can be seen as the on-the-fly version of reverse engineering where you don't have the binary data to your host computer. Instead, you'll analyze it straight from the memory of the app.

We'll keep using the iGoat-Swift app, open a session with r2frida r2 frida://usb//iGoat-Swift and you can start by displaying the target binary information by using the :i command:

[0x00000000]> :i
arch                arm
bits                64
os                  darwin
pid                 2166
uid                 501
objc                true
runtime             V8
java                false
cylang              true
pageSize            16384
pointerSize         8
codeSigningPolicy   optional
isDebuggerAttached  false
cwd                 /

Search all symbols of a certain module with :is <lib>, e.g. :is libboringssl.dylib.

The following does a case-insensitive search (grep) for symbols including "aes" (~+aes).

[0x00000000]> :is libboringssl.dylib~+aes
0x1863d6ed8 s EVP_aes_128_cbc
0x1863d6ee4 s EVP_aes_192_cbc
0x1863d6ef0 s EVP_aes_256_cbc
0x1863d6f14 s EVP_has_aes_hardware
0x1863d6f1c s aes_init_key
0x1863d728c s aes_cipher
0x0 u ccaes_cbc_decrypt_mode
0x0 u ccaes_cbc_encrypt_mode
...

Or you might prefer to look into the imports/exports. For example:

  • List all imports of the main binary: :ii iGoat-Swift.
  • List exports of the libc++.1.dylib library: :iE /usr/lib/libc++.1.dylib.

For big binaries it's recommended to pipe the output to the internal less program by appending ~.., i.e. :ii iGoat-Swift~.. (if not, for this binary, you'd get almost 5000 lines printed to your terminal).

The next thing you might want to look at are the classes:

[0x00000000]> :ic~+passcode
PSPasscodeField
_UITextFieldPasscodeCutoutBackground
UIPasscodeField
PasscodeFieldCell
...

List class fields:

[0x19687256c]> :ic UIPasscodeField
0x000000018eec6680 - becomeFirstResponder
0x000000018eec5d78 - appendString:
0x000000018eec6650 - canBecomeFirstResponder
0x000000018eec6700 - isFirstResponder
0x000000018eec6a60 - hitTest:forEvent:
0x000000018eec5384 - setKeyboardType:
0x000000018eec5c8c - setStringValue:
0x000000018eec5c64 - stringValue
...

Imagine that you are interested into 0x000000018eec5c8c - setStringValue:. You can seek to that address with s 0x000000018eec5c8c, analyze that function af and print 10 lines of its disassembly pd 10:

[0x18eec5c8c]> pd 10 (fcn) fcn.18eec5c8c 35   fcn.18eec5c8c (int32_t arg1, int32_t arg3); bp: 0 (vars 0, args 0) sp: 0 (vars 0, args 0) rg: 2 (vars 0, args 2)           0x18eec5c8c      f657bd         not byte [rdi - 0x43]      ; arg1
│           0x18eec5c8f      a9f44f01a9     test eax, 0xa9014ff4
│           0x18eec5c94      fd             std
│       ╭─< 0x18eec5c95      7b02           jnp 0x18eec5c99
│          0x18eec5c97      a9fd830091     test eax, 0x910083fd
│           0x18eec5c9c      f30300         add eax, dword [rax]           0x18eec5c9f      aa             stosb byte [rdi], al
│       ╭─< 0x18eec5ca0      e003           loopne 0x18eec5ca5
│          0x18eec5ca2      02aa9b494197   add ch, byte [rdx - 0x68beb665] ; arg3
╰           0x18eec5ca8      f4             hlt

Finally, instead of doing a full memory search for strings, you may want to retrieve the strings from a certain binary and filter them, as you'd do offline with radare2. For this you have to find the binary, seek to it and then run the :iz command.

It's recommended to apply a filter with a keyword ~<keyword>/~+<keyword> to minimize the terminal output. If just want to explore all results you can also pipe them to the internal less :iz~...

[0x00000000]> :il~iGoa
0x00000001006b8000 iGoat-Swift
[0x00000000]> s 0x00000001006b8000
[0x1006b8000]> :iz
Reading 2.390625MB ...
Do you want to print 8568 lines? (y/N) N
[0x1006b8000]> :iz~+hill
Reading 2.390625MB ...
[0x1006b8000]> :iz~+pass
Reading 2.390625MB ...
0x00000001006b93ed  "passwordTextField"
0x00000001006bb11a  "11iGoat_Swift20KeychainPasswordItemV0C5ErrorO"
0x00000001006bb164  "unexpectedPasswordData"
0x00000001006d3f62  "Error reading password from keychain - "
0x00000001006d40f2  "Incorrect Password"
0x00000001006d4112  "Enter the correct password"
0x00000001006d4632  "T@"UITextField",N,W,VpasswordField"
0x00000001006d46f2  "CREATE TABLE IF NOT EXISTS creds (id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT, password TEXT);"
0x00000001006d4792  "INSERT INTO creds(username, password) VALUES(?, ?)"

To learn more, please refer to the r2frida wiki.