Skip to content

MASTG-TECH-0066: Static Analysis on iOS

The preferred method for statically analyzing iOS apps is to use the original Xcode project files. Ideally, you can compile and debug the app to quickly identify potential issues in the source code.

Black box analysis of iOS apps without access to the original source code requires reverse engineering. For example, no decompilers are available for iOS apps (although most commercial and open-source disassemblers can provide a pseudo-source code view of the binary), so a deep inspection requires you to read assembly code.

Using radare2 (iOS)

Radare2 (r2) is a powerful reverse engineering framework that provides a wide range of tools for analyzing binaries. This section explains how to use r2 effectively for static analysis, focusing on identifying and analyzing relevant functions in iOS applications.

For interactive analysis, you can also use radare2's visual mode by pressing V after opening a binary, which provides a more graphical interface for navigation and analysis.

Identifying Relevant Functions

Listing Functions:

Use the afl command to list all functions in the binary and combine the ~ operator to filter functions by name. For example, if you're interested in cryptographic functions, you can search using a filter like afl~SecKey to find all functions related to SecKey. If you already know the function name, you can use afl~<function_name> to directly filter for that specific function.

afl~SecKeyCreateRandomKey

You can also use the afl, command to output all function information in CSV format, which allows for custom views, filtering, and sorting of function details in a table. This is useful for more advanced analysis or when working with large binaries.

afl,
addr        size name                                                                                                                               noret nbbs nins refs xref axref calls cc file
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
0x100007894 12   sym.imp.SecKeyCopyExternalRepresentation                                                                                           0     1    3    2    2    2     0     1
0x1000078a0 12   sym.imp.SecKeyCopyPublicKey                                                                                                        0     1    3    2    1    1     0     1
0x1000078ac 12   sym.imp.SecKeyCreateRandomKey                                                                                                      0     1    3    2    1    1     0     1
0x1000078b8 12   sym.imp.SecKeyCreateSignature                                                                                                      0     1    3    2    1    1     0     1
0x1000078c4 12   sym.imp.SecKeyVerifySignature                                                                                                      0     1    3    2    1    1     0     1
0x1000078d0 12   sym.imp.__stack_chk_fail                                                                                                           1     1    3    2    2    2     0     1
...

Additionally, the aflc command shows the total count of functions identified in the binary:

aflc
175

Example: In Uses of Insufficient Key Size in SecKeyCreateRandomKey with r2, SecKeyCreateRandomKey is identified as a function of interest.

When Not to Use afl:

In some cases, functions may not appear in the list generated by afl. For example, canEvaluatePolicy is a dynamically resolved function and may not be listed.

afl~canEvaluatePolicy
< no results >

Instead, use flags (f), string searches with /, /z, iz~ and then use cross-references (axt) to locate its usage in the binary. This approach ensures that dynamically resolved or obfuscated functions are not overlooked.

In visual mode you can use V_ which is the visual hud that interactively filters all the flags, classes, methods, comments, symbols, strings in a single view. So you can simply type V_, press enter, and then type canEvaluatePolicy to find the references to the string.

f~canEvaluatePolicy
0x100008360 24 str.canEvaluatePolicy:error:

In the output, you can see a flag str.canEvaluatePolicy:error: representing the string canEvaluatePolicy:error: which is located at 0x100008360. You can then use the axt command to find cross-references to this string using its address:

axt @ 0x100008360

(nofunc) 0x100000350 [UNKNOWN] invalid
sym.func.100004ea8 0x100004f10 [STRING] ldr x1, [x8, 0xa0]

The output shows the cross-references to the given address, indicating where the function is used in the binary in two different locations:

  • 0x100000350: This indicates an invalid reference, possibly due to dynamic resolution.
  • sym.func.100004ea8: This indicates a valid reference to a function located at 0x100004ea8, which can be further analyzed. The reference to the string will be at 0x100004f10.

Identifying Strings

Listing Strings:

Use the iz command to list all strings in the binary. Combine it with ~ filtering to filter for specific strings. For example, to search for a string containing somestring:

iz~+somestring

Alternatively, you can use izz

Searching for Specific Strings:

Use the / command to search for a string directly in the binary:

/ somestring

Use advanced search options with /.

Analyzing Cross-References

Finding Cross-References:

Use the ax, command to display a table of all cross-references in the binary, which is especially useful for getting an overview or exporting data. You can filter this table by address using the ~ operator. For example, to show all cross-references to 0x1000078ac, run:

ax,~78ac
0x1000049a0 0x1000078ac 0    CALL --x  sym.func.1000046f8 + 680                                                                                                               sym.imp.SecKeyCreateRandomKey
0x1000078ac 0x10000c000 4    ICOD --x  sym.imp.SecKeyCreateRandomKey                                                                                                          section.16.__DATA_CONST.__got

This will output only the rows related to the address 0x1000078ac, making it easier to focus on relevant references. The table includes columns such as source address, destination address, type, permissions, and symbolic names, helping you quickly identify where and how a function like SecKeyCreateRandomKey is used.

You can also open the entire cross-reference table with ax, and manually search or filter as needed.

ax,

from        to          size type perm fromname                                                                                                                               toname
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
0x100000040 0x100000000 0    NULL r--  segment.__TEXT + 64                                                                                                                    segment.__TEXT
0x100000080 0x100000000 0    NULL r--  segment.__TEXT + 128                                                                                                                   segment.__TEXT
0x1000000d0 0x100004000 0    NULL r--  segment.__TEXT + 208                                                                                                                   section.0.__TEXT.__text
...
0x1000049a0 0x1000078ac 0    CALL --x  sym.func.1000046f8 + 680                                                                                                               sym.imp.SecKeyCreateRandomKey
0x1000078ac 0x10000c000 4    ICOD --x  sym.imp.SecKeyCreateRandomKey                                                                                                          section.16.__DATA_CONST.__got

Use the axt command to find cross-references to a specific function or address. This helps you understand how and where the function is invoked.

axt @ 0x1000078ac
sym.func.1000046f8 0x1000049a0 [CALL:--x] bl sym.imp.SecKeyCreateRandomKey

The @ symbol is used for temporal seeking to a specific address for the duration of the command.

You can also pass the address directly to axt without using @:

axt 0x1000078ac
sym.func.1000046f8 0x1000049a0 [CALL:--x] bl sym.imp.SecKeyCreateRandomKey

Alternatively, you can use the s (seek) command to move to an address before running axt, which is useful if you plan to run multiple commands at that location:

s 0x1000078ac
axt
sym.func.1000046f8 0x1000049a0 [CALL:--x] bl sym.imp.SecKeyCreateRandomKey

Both @ and s accept partial addresses, so you don't need to type the full hexadecimal value. For example, [email protected] is sufficient if the address is unique.

There's also axg which finds the path between a function and its cross-references, showing the call graph in reverse of how functions are related. This is particularly useful for understanding the flow of execution in the binary.

The axg command output starts from the target function or address you gave it and works backward, showing which functions lead to it. So even though the output is printed top to bottom, it represents a path from the callee up to its callers.

axg ..78ac
- 0x1000078ac fcn 0x1000078ac sym.imp.SecKeyCreateRandomKey
  - 0x1000049a0 fcn 0x1000046f8 sym.func.1000046f8
  - 0x1000046f8 fcn 0x1000046f8 sym.func.1000046f8
    - 0x1000063d8 fcn 0x1000063a0 sym.func.1000063a0
    - 0x1000063a0 fcn 0x1000063a0 sym.func.1000063a0
      - 0x100006fc4 fcn 0x100006fbc sym.func.100006fbc
      - 0x100006fbc fcn 0x100006fbc sym.func.100006fbc
        - 0x100006040 fcn 0x100005c8c sym.func.100005c8c
        - 0x100005c8c fcn 0x100005c8c sym.func.100005c8c
          - 0x100005944 fcn 0x1000056b8 sym.func.1000056b8
          - 0x1000056b8 fcn 0x1000056b8 sym.func.1000056b8
            - 0x100006de8 fcn 0x100006d60 sym.func.100006d60

In the above example, the call graph shows how SecKeyCreateRandomKey is invoked by sym.func.1000046f8, which in turn is called by sym.func.1000063a0, and so on, tracing back through the function calls. Reading it becomes easier after you've analyzed the functions and renamed them according to their purpose.

Example: In Uses of Insufficient Key Size in SecKeyCreateRandomKey with r2, cross-references to SecKeyCreateRandomKey are analyzed to ensure secure key sizes.

Inspecting Function Calls:

Use the pdf command to decompile a function and inspect its implementation. This provides insights into how the function operates.

pdf @ <function_address>

The @ symbol seeks to the specified address before executing the command.

Inspecting Specific Instructions: Use the pd-- command to disassemble a specific number of instructions before and after a given address, providing context around that point in the code:

pd-- 5 @ 0x1000048c4

If you want to disassemble instructions starting from a specific address, use pd <number_of_instructions> instead:

pd 5 @ 0x1000048c4

This is particularly useful for examining the immediate context of a function call or instruction.

Tests

MASTG-TEST-0210: Broken Symmetric Encryption Algorithms MASTG-TEST-0317: Broken Symmetric Encryption Modes MASTG-TEST-0311: Insecure Random API Usage MASTG-TEST-0209: Insufficient Key Sizes MASTG-TEST-0213: Use of Hardcoded Cryptographic Keys in Code MASTG-TEST-0211: Broken Hashing Algorithms MASTG-TEST-0214: Hardcoded Cryptographic Keys in Files MASTG-TEST-0345: Embedded or Third-party TLS Stack Configuration MASTG-TEST-0343: URLSession TLS Protocol Configuration MASTG-TEST-0344: Network.framework TLS Protocol Configuration MASTG-TEST-0323: Uses of Low-Level Networking APIs for Cleartext Traffic MASTG-TEST-0333: Overly Broad File Read Access in WebViews MASTG-TEST-0335: WebView File Origin Access Relaxed by Configuration MASTG-TEST-0278: Pasteboard Contents Not Cleared After Use MASTG-TEST-0279: Pasteboard Contents Not Expiring MASTG-TEST-0280: Pasteboard Contents Not Restricted to Local Device MASTG-TEST-0331: Use of Deprecated WebView APIs MASTG-TEST-0332: Attacker-Controlled URI in WebViews MASTG-TEST-0346: References to APIs Hiding Sensitive Data in Text Input Fields MASTG-TEST-0276: Use of the iOS General Pasteboard MASTG-TEST-0266: References to APIs for Event-Bound Biometric Authentication MASTG-TEST-0268: References to APIs Allowing Fallback to Non-Biometric Authentication MASTG-TEST-0270: References to APIs Detecting Biometric Enrollment Changes MASTG-TEST-0303: References to APIs for Storing Unencrypted Data in Shared Storage MASTG-TEST-0313: References to APIs for Preventing Keyboard Caching of Text Fields MASTG-TEST-0297: Insertion of Sensitive Data into Logs MASTG-TEST-0300: References to APIs for Storing Unencrypted Data in Private Storage MASTG-TEST-0215: Sensitive Data Not Marked For Backup Exclusion MASTG-TEST-0281: Undeclared Known Tracking Domains MASTG-TEST-0240: Jailbreak Detection in Code MASTG-TEST-0248: References to APIs for Detecting Secure Screen Lock