Bypassing anti-debugger check in iOS Applications

Expected Reading Time: 5 Mins

While pentesting mobile applications, very often you will come across applications implementing myriads of anti-reversing techniques. Specially while performing dynamic analysis, it is imperative to disable these checks. To make the bypassing these checks more daunting, some applications heavily obfuscate the binaries. In this post, we will look into bypassing one of the anti-debugging technique for iOS applications and using IDAPython script to automate patching of the binary. The idea presented in this post is really simple, and many readers might have been already using it, for others here is another idea to add to your armory.

Ptrace:

iOS under the hood runs a XNU kernel. The XNU kernel do implement ptrace() system call, but it is not potent enough when compared to Unix and Linux implementations. On the other hand, XNU kernel exposes another interface via Mach IPC to perform debugging. In this post we won’t be comparing between the two mechanisms, in fact we will only talk about one feature of ptrace syscall, PT_DENY_ATTACH. It is a fairly well known among the iOS application hackers, and among the most frequently encountered anti-debugging technique in iOS applications.

Before getting into the details of bypassing the check, lets first try to understand briefly what exactly does PT_DENY_ATTACH do. Although, there is ample literature available on the Internet discussing PT_DENY_ATTACH in various depths, but The Mac Hacker’s Handbook defines it most succinctly.

PT_DENY_ATTACH
This request is the other operation used by the traced process; it allows a process that is not currently being traced to deny future traces by its parent. All other arguments are ignored. If the process is currently being traced, it will exit with the exit status of ENOTSUP; otherwise, it sets a flag that denies future traces. An attempt by the parent to trace a process which has set this flag will result in the segmentation violation in the parent.

To rephrase it, using ptrace with PT_DENY_ATTACH, it ensures that no other debugger can attach to the calling process; even if an attempt is made to attach a debugger, the process exits.

It is important to know that ptrace() is not part of public API on iOS. As per the AppStore publishing policy, use of non-public API is prohibited and use of them may lead to rejection of the app from the AppStore ). Because of this, developers don’t call ptrace()   directly in the code, instead its called via obtaining ptrace() function pointer using dlsym. Programmatically it looks like:

#import 
#import <sys/types.h>
#import 
typedef int (*ptrace_ptr_t)(int _request, pid_t _pid, caddr_t _addr, int _data);
void anti_debug() {
 ptrace_ptr_t ptrace_ptr = (ptrace_ptr_t)dlsym(RTLD_SELF, "ptrace");
 ptrace_ptr(31, 0, 0, 0); // PTRACE_DENY_ATTACH = 31
}

The dis-assembly of the binary implementing this approach looks like following:

ptrace_original.PNG

To break down whats happening in the binary, at 0x19086 dlsym() is called with “ptrace” as the 2nd argument (register R1, offset 0x19084) to the function. The return value, in register R0 is moved to register R6 at offset 0x1908A. Eventually at offset 0x19098, the pointer value in register R6 is called using BLX R6 instruction. In this case, to disable ptrace() call, all we need to do is to replace the instruction BLX R6 (0xB0 0x47 in Little Endian) with NOP (0x00 0xBF in Little Endian) instruction. Armconverter.com is a handy tool for conversion between bytecode and instruction mnemonics. The code after patching looks like following:

call_ptrace

This can be done manually easily if there is only one or a few calls to ptrace, but this turns tedious once such calls are made multiple times across the binary.

IDAPython Script:
IDAPython script can be leveraged to perform this task automatically. I wrote one such script to automate the task for the binary dis-assembly shown above. The script is quite self explanatory, but if something is not clear, feel free to drop a comment below for further clarification.

To conclude, there are many other anti-debugging approaches available for iOS, the one discussed here is the most commonly found in the iOS applications. Using such techniques to slow down the attackers is fine, but solely depending on such techniques for the security of an application is not at all advisable. Such techniques can be part of the defense in depth approach, but should not be the only defense.

Keep hacking 🙂

iOS Solid State NAND Storage

There is not much literature available on how does NAND storage of Apple’s iDevices is like. While reading “Hacking and Securing iOS Applications” by Jonathan Zdziarski, I came across how does the NAND storage looks like until iOS 5. As a note on caution, it is very possible that this structure has been changed in the subsequent iOS versions.

Knowing the structure of storage is an important step in order to understand how encryption works in iOS. The text below is verbatim from the book.
The NAND is divided into six separate slices:

  • BOOT: Block zero is referred to as the BOOT block of the NAND, and contains a copy of Apple’s low level boot loader.
  • PLOG: Block 1 is referred to as effaceable storage, and is designed as a storage locker for encryption keys and other data that needs to be quickly wiped or updated. The PLOG is where three very important keys are stored, which you’ll learn about in this chapter: the BAGI, Dkey, and EMF! keys. This is also where a security epoch is stored, which caused iOS 4 firmware to seemingly brick devices if the owner
    attempted a downgrade of the firmware.
  • NVM: Blocks 2–7 are used to store the NVRAM parameters set for the device.
  • FIRM: Blocks 8–15 store the device’s firmware, including iBoot (Apple’s second stage boot loader), the device tree, and logos.
  • FSYS: Blocks 16–4084 (and higher, depending on the capacity of the device) are used for the filesystem itself. This is the filesystem portion of NAND, where the operating system and data are stored. The filesystem for both partitions is stored here.
  • RSRV: The last 15 blocks of the NAND are reserved.

If there is any recent material on this topic, please let me know by commenting below.

Keep Hacking 😀