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.


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.

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 <sys/types.h>
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:


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. is a handy tool for conversion between bytecode and instruction mnemonics. The code after patching looks like following:


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 🙂

Working of LD_PRELOAD for Android Applications and its anti-RE Technique

Have you ever checked the parent process of an Android application launched using “wrap” system property set with LD_PRELOAD value? It’s not Zygote!!!  

Expected Reading Time: 10 mins

There are multiple tools and methodology available for reverse engineering an Android application. In this post, I am not exploring various RE techniques available, instead look into how one such technique works in case of Android applications. LD_PRELOAD is a functionality of dynamic linker present across all Linux distributions, giving precedence to library passed to be searched first for symbols. It is not a RE technique per se, but I have used it often for such purposes and hence I classify it as a RE technique which one should know.

Many Linux users will be aware of how LD_PRELOAD works in case of native binaries. For the starters, there are many good blogs available and I will leave it as an assignment. As a side note, knowledge of how dynamic linkers work is always handy for reverse engineering assignments.

In case of a simple native binary compiled to run on Android, LD_PRELOAD works as for other Linux systems. Things get interesting once you intend to use LD_PRELOAD for an Android application. If you simply set the LD_PRELOAD env variable and then try to launch the application, it will not work. Rather you need to perform some Android trickery to make it work for an application. For example, we want to load using LD_PRELOAD for application with package name We need to perform following steps:
• Push the library to the device.  adb push /data/local/tmp/
• Set system property:  setprop LD_PRELOAD=/data/local/tmp/

Note, in last step the property name is  “wrap” prefixed to the application’s package name.

Now if you launch the application, the library will be searched first by the dynamic linker for symbols. (In recent Android versions, one need to disable SELinux to make this work, as does not have SELinux context assigned, because of which the library is not loaded and whole process exits on such an error.) The above work around is neither a hidden feature nor a newly added feature. Many of us might have used it several times in the past.

After knowing how to make it work practically, lets try to understand what is actually happening internally, and why we need to perform these extra steps. Some might have already guessed, it is because of Zygote process creation model used in Android. As covered previously on this blog as well, an Android application is launched by forking a Zygote process. Argument being,  in order to save time while launching an application, Android coldstarts a process during OS startup, from which applications can be forked when required. This process is initialized with all necessary libraries required to run an Android application, and remains in sleep state. When a request to launch an application is received, this Zygote process is simply forked and used there on.

Since, Zygote process is initialized well before launching the application, setting LD_PRELOAD env variable before launching an application will cause no change in symbol search order for linker. Thus, to enable LD_PRELOAD functionality, Android needs a work around.

Lets revisit how an application launch request is passed to Zygote. When user makes a request to launch an application,  a request is sent to /dev/socket/zygote. On receiving request, Zygote forks itself and launches the application in the child process. As per this mechanism all the application’s, as expected, will have Zygote as the parent process. But in case of LD_PRELOAD scenario, a slight different code path is taken.

Code listening at /dev/socket/zygote runs in a loop, referred as ‘select loop’ in code. On receiving request, runOnce() in ZygoteConnection  is called. In this function, many checks and operations are performed, one such check is to check if “wrap” system property set for the given application’s package name.

boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
applyUidSecurityPolicy(parsedArgs, peer, peerSecurityContext);
applyRlimitSecurityPolicy(parsedArgs, peer, peerSecurityContext);
applyInvokeWithSecurityPolicy(parsedArgs, peer, peerSecurityContext);
applyseInfoSecurityPolicy(parsedArgs, peer, peerSecurityContext);
checkTime(startTime, "zygoteConnection.runOnce: apply security policies");
checkTime(startTime, "zygoteConnection.runOnce: apply security policies");

If it is set, it extracts the value of the property. It is important that, a system property name cannot be more than 31 chars, and if package name is more than 31 chars, it need to be truncated to 31 chars.

After extracting the value, execApplication() in WrapperInit is called. In this function, a command string is constructed with required parameters, to launch application via /system/bin/app_process  (Zygote) directly. The shell arguments, LD_PRELOAD in this case, is appended in this command string. This command is executed using /system/bin/sh. Thus, making /system/bin/sh as the parent process to the finally launched application.

public static void execApplication(String invokeWith, String niceName,
int targetSdkVersion, FileDescriptor pipeFd, String[] args) {

StringBuilder command = new StringBuilder(invokeWith);
command.append(" /system/bin/app_process /system/bin --application");
if (niceName != null) {
command.append(" '--nice-name=").append(niceName).append("'");
command.append(" ");
command.append(pipeFd != null ? pipeFd.getInt$() : 0);
command.append(' ');
Zygote.appendQuotedShellArgs(command, args);

This very fact, that parent process for such an application is not Zygote, can be used as an anti-RE technique. If application’s parent is not Zygote, then application can change its behavior or exit, preventing application analysis.

Keep hacking 🙂

Intercepting HTTPS traffic of Android Nougat Applications

TL;DR To intercept network traffic for Android 7.0 targeted applications, introduce a res/xml/network_security_config.xml file.

Expected Reading Time: 5 mins

In this post I am exploring the new security feature of Android 7.0, which by default makes applications to not to trust “user” installed CA certificates (non-admin), and how to bypass this new security feature.  I started with the feeling that it might not be easy to find a way past these checks, but it panned out to be quite straightforward and much less technical than expected.

Android 7.0 (Nougat) has introduced many new security features to harden the OS. The changes ranges from low level stuff like using more of Linux Seccomp, having File based encryption, to making mediaserver more secure by compartmentalization and compiler level checks for integer overflows. Among all these changes, Android 7.0 also changed the default trust level of installed CA certificates for the applications.

In Android Nougat, the default trusted CA certificates by the applications has changed. In the earlier versions of Android, by default the application apart from trusting the “system” installed CA certificates, it also used to trust the “user” added CA certificates as well. For example, while using some MITM proxy like mitmproxy, burp etc, you can simply install the proxy’s certificate on Android device/emulator and then you can intercept and observe the network traffic in clear text. But from Android 7.0 onwards, the default behaviour has been altered and the “user” installed certificates won’t be trusted anymore by the applications. Thus, intercepting  application’s traffic using a proxy will not be possible out of the box.

So how to observe the network traffic for the applications targeting Android 7.0? Apparently, Google has not provided any simple switch in settings menu, which can be toggled and apps start trusting user installed CA certs. So it means we need to get our hands dirty.

So with a task in hand, I picked up an open source Android application and compiled with target SDK Level 24 (for Android 7.0). I prepared a release build and installed on a device running Android 7.0. I used mitmproxy for the job to intercept network traffic. And to no surprises, the application was not able to connect and reported no internet connectivity.

As the adage goes, RTFD, lo and behold, the hint is there in the same blog post. For ease of setting network security configuration, Android provides a network security configuration file, while lets you to “customize network security settings in a safe, declarative configuration file without modifying app code”. So that is all needed. We need to decompile the application using apktool and introduce a network_security_config.xml (shown below) file at res/xml folder of the application.  Recompile the application with apktool again, sign it using jarsigner and we are good to go.

                <!-- Trust preinstalled CAs -->  
                <certificates src="system" />  
                <!-- Additionally trust user added CAs -->  
                <certificates src="user" />  


For the better understanding, I highly recommend to read the original blog and the security config documentation.

In the end it turned out to be quite trivial than expected, but nevertheless requires few extra steps now to intercept an applications traffic. This technique might be not be needed immediately, as most applications will still be targeting at least Android 4.4 for now, for which the user added CA certificate are still trusted.

Bypassing SSL Pinning in Android Applications

It is a common practice for Android and iOS applications’ developers to implement SSL Pinning in order to make reverse engineering of the apps difficult. As per OWASP, SSL Pinning can be defined as the process of associating a host (in this case the app), with their expected X509 certificate or public key. Applications communicating over HTTPS and using SSL Pinning makes it non-trivial to perform Man-In-The-Middle attack and grab the network traffic in clear text using the proxy tools. For further reading about SSL Pinning, I would recommend  OWASP article to get started with.

In this post, I will be looking into the steps involved in bypassing SSL Pinning checks for an Android application and show how we can patch the application binaries in order to intercept the traffic. For this post I am using Facebook Messenger (FBM) application as an example.

SSL Pinning In Android:

SSL Pinning in case of Android can be performed either in the Java layer, using the Android API, or in the native C/C++ layer. Lets look into each of the cases one at a time:

Java Layer:

To implement SSL Pinning, Android API exposes multiple functions to do so.  Android developer website provides a good overview about the topic.  In order to bypass the SSL Pinning in Java layer one can use existing tools or can patch the APK file manually.

  • Xposed Framework: If the device is rooted, one can install Xposed Framework and use one of the multiple modules available to disable SSL Pinning. One such module is SSL Unpinning. Using the module is straight forward and I would leave the details of usage to the readers to figure out.
  • Manual Patching:  Xposed Framework requires the device to be rooted. In such a case we cannot use the tools discussed above to bypass the SSL checks. In such a situation we can patch the APK file manually. Patching the file manually requires some extra effort, but given the abundance of exiting tools, this can be done with ease. The steps involved are following:
  1. Decompile the application using Apktool or any other similar tool. Apktool gives Smali code for the application.
  2. Patch the relevant functions in the Smali code.
  3. Compile the application back using apktool, sign it using jarsign and run zipalign over it.
  4. Installed the patched APK generated above.

The above approach is discussed in detail in this blog post. Hence, I will refrain from duplicating the information and recommend you to read it there.

Native Layer:

Now enters a bit more challenging part. If the above approaches fail, you can fairly be confident that the SSL Pinning checks are being performed in the native layer. FBM is doing exactly same. To make things a bit obscure, the FBM application do have SSL Pinning logic in Java layer as well, but patching it does not work.

To get started, simply run APKTool and get the decompiled/unzipped version of the APK. If you look in the lib folder, there are 6 native libraries.


After exploring these libraries using IDA Pro, to my surprise, none was having network related code. Which entailed more research is required to find the relevant code. If you look into these existing native libraries, you will find there is logic for xz decoding and logic for loading more native libraries. Also, if you go on and install the application and after the first usage, you will find that the /data/data/com.facebook.orca directory have a folder lib-xzs, which contains another 30+ libraries.


So now the work is cut out clearly, we have to look into these libraries to find the network code. After evaluating each library using IDAPro, the code for SSL Pinning was found in There are many functions corresponding to SSL Pinning and network in this library. On seeing the various functions,  proxygen::SSLVerification::verifyWithMetrics() seems to be an easy target to fix. The function performs a comparison of the certificate received against the desired certificate embedded/pinned in the application and returns true or false. The pseudocode is shown below:


  • Dynamic Patching: Dynamic library can be patched by performing dynamic injection and patching the function during the runtime. ADBI and FRIDA are the two frameworks that provide such functionality. After some fiddling around with the above mentioned tools,  in both the cases FBM was crashing whenever an injection is made. Whether it was a security defense mechanism or instability of the process post injection, I left this unexplored for the time being. A note to the readers, to use these framework you need a rooted device.
  • Native Library Patching: Given the dynamic injection is causing frequent crashes, patching the binary manually and reloading it again seems to be the only other option to go with. I used IDAPro to patch the binary. At the offset  0x0006732E patch code from 0xB948 (CBNZ R0, loc_6744) to 0xB9B8 (CBNZ R0, loc_6760). Where the block at loc_6760 is responsible for setting the return value, variable ‘result‘, to always true. To get more understanding how the ARMv7 instructions represented at the bit level, read this answer. After patching, replace the file in /data/data/com.facebook.orca/lib-xzs with the new one, restart the application and now you can intercept the traffic.
Before Patching
After Patching

Recently, there was another blog post discussing patching of Android application (Pokemon Go app) to bypass SSL Pinning and I would recommend to read that one as well. The approach taken in that post is slightly different, as each application has different implementation.

AOSP 5.1.1 Renderscript Build Error

While building AOSP 5.1.1_r14 I encountered a build error with renderscript, in frameworks/rs. The error looks like following:

target level api 22 is out of range ('11' - '21')

The problem is AOSP 5.1 is API level 22, while it seems the renderscript is compatible till 21 only. Some searching through git logs of AOSP, I came across this commit. Although the commit is not directly applicable to current problem, but it provides a hint to solve the current compatibility issue. To summarise, the fix is, in core/ file, change the version number for variable renderscript_target_api := 21.


Linux threads are standard process

As per Wikipedia, a computing thread is defined as “the smallest sequence of programmed instructions that can be managed independently by a scheduler”. And further goes on to say, the implementation of threads and processes differs between operating systems, but in most cases a thread is a component of a process. A process can have multiple threads within a shared memory address space of the process.  In this article, I won’t be going into the nitty-gritty of threads. There are many good resources available on the Internet discussing various details of threads. Rather I would like to focus on an important aspect of threads specifically in Linux kernel.

While discussing Linux internals with a senior developer, he mentioned that in case of Linux kernel, there is no difference between a process and a thread. Intrigued by the fact, I started looking into kernel’s source, aided by the excellent book on Linux kernel, Linux Kernel Development, by Robert Love.

Coming on to the topic, in Linux, there is no separate data structure defining a thread. A thread and a process have the same data structure. Also, a thread is created exactly in the same way as a normal process is created, i.e by calling fork or vfork() (which eventually calls clone() system call). Although, in case of a thread, while making clone() system call some extra flags are passed. These extra flags specify the resources which are to be shared. A typical call looks like:

So the address space, filesystem resources, file descriptors, and signal handlers are shared.

For the readers who want to delve more into the internal working, struct task_struct contains information about a process, defined in <linux/sched.h>. The field unsigned int flags stores all the flag related information. These flags, help specify the behaviour of the new process and detail what resources the parent and child will share. List of other clone flags can also be found in linux/sched.h.

For completeness, in case of Microsoft Windows, kernel have explicit support for kernels and also referred as lighweight process. For Windows, a thread is an abstraction which provides  a lighter, quicker execution than the heavy process. The pros and cons of the two approaches required more deep understanding of the two, and would require a much bigger post than this one.

Android Root Detection Techniques

I am trying to create a exhaustive list of various techniques which can be used to detect whether an Android device is rooted or not. These techniques have been taken from various sources, listed in the references section at the end of this post. If you are aware of techniques apart from one mentioned in the post, please add them in the comment.

  • Check Installed Packages:
    1. SuperSU app
    2. Rooting apps: Apps that exploit privilege-escalation vulnerabilities to root the device (e.g One Click Root, iRoot)
    3. Root Apps: Apps that require root privileges for their functions. E.g busybox, SetCPU, Titanium Backup.
    4. Root Cloakers: Apps that hide whether the device is rooted or not. e.g Root Cloaker, Root Cloaker Plus.
    5. API hooking frameworks: Libraries that provide API hooking functions. E.g Cydia Substrate, Xpose Framework.
  • Check Installed Files:
    1. Static Paths:
      1. /system/xbin/su, /system/bin/su or /system/xbin/../xbin/su (path manipulated)
      2. /system/xbin/busybox and all symbolic links of commands created by BusyBox.
      3. /data/app/<APK name> or /system/app/<APK name> of popular apps packages that are installed during or after rooting.
    2. Dynamic Paths: Parse the PATH variable, appending “/su” to each entry; open each in a loop
  • Check the BUILD tag: stock android images from Google are built with “release-keys” tag. If “test-keys” are presented, this can probably mean the Android image is developer build or an unofficial build. This value is basically from “”.
  • Check Directory Permissions:
    1. Rooting makes certain root folders readable, like /data, or writable, like /etc, /system/xbin, /system, /proc, /vendor/bin etc. Run the mount command and check if any device is mounted with “rw” flag, or try to create a file under “/system” or “/data” folder.
    2. Attempt to mount “/system” partition with command “mount -o remount, rw /system“, and check the return code.
  • Check Processes/Services/Tasks:
    1. ActivityManager.getRunningAppProcesses method returns a list of currently running application processes. This API can be used to determine if any app which requires root privileges is running.
    2. getRunningServices or getRunningTasks: Get currently running services or tasks.
  • Check Rooting Traits Using Shell Commands: Using Runtime.exec, ProcessBuilder or execve()
    1. su
    2. which su
    3. ps | grep <target> : lists currently running processes.
    4. ls – <target>: check existence of a file in the file system
    5. pm list packages
    6. pm path <package>: Output the full path of the targeted package
    7. cat /system/build.prop or grep Check whether =release-keys. This test can be used only as an indicator, as there are many contrary observations in the wild.
    8. Build Version: “ro.modversion” can be used to identify certain custom Android ROMs (e.g CyanogenMod)
  • Check System Properties:
    1., means adb shell will be running as root, instead of shell user.
    2. ro.debuggable =1 or service.adb.root=1, then adb will run as root as well.

Needless to say, these techniques can be bypassed by function hooking or custom build Android ROMs etc.