Neso Lab’s AppMinder project is another attempt at providing jailbreak detection for enterprise iOS applications (and perhaps AppStore apps). It provides three variants of jailbreak detections codes, each with an increasing level of self integrity checks and code obfuscation, and optionally including anti-debugging checks. It generates a piece of code with a function containing inline assembly code which can be inserted into the app’s source code and called where jailbreak detection needs to be implemented. The generated code is metamorphic with a random function name. Metamorphism is achieved by a combination of register interchanges, instruction reordering, inserting dead code such as unused
The code can be made a little more readable using
cat jbdetect.c | tr ';' '\n'.
The code makes use of
svc 0x80 instruction throughout to invoke system calls.
svc 0x80 is the ARM counterpart of Intel’s
int 0x80 instruction, used to invoke system calls. In iOS, which is a derivative of Darwin, the system call number is passed in r12 and the arguments in r0-r3. The return value is optionally returned in r0.
svc also goes by the name of
swi or software interrupt.
Process tracing utilities and debuggers make use of
ptrace system call to trace a running process. If the ‘Anti-debugging option’ was selected, the code tries to detect and deny any debugging attempts. It does this by invoking
ptrace (system call 26) on the current process with an argument of 31, i.e.
PT_DENY_ATTACH. Quoting from the man page:
The process is killed if a debugger is detected. Additionally, debuggers are denied to trace the process in any future requests. gdb shows a “Operation not permitted” message if it tries to attach to a process which has called
A complete list of system calls can be found in sys/syscall.h.
The code detects jailbreaks using
fork. On non-jailbroken iOS, the sandbox restricts the use of
fork fails with a return value of 1. However, on a jailbroken iOS,
fork succeeds and spawns a new process. The code terminates the process using
fork does not return 1.
The code does not do anything new, and does not even conceal its presence. It can be easily identified in memory by simply looking for
svc 0x80 instructions, which assemble to
80 00 00 EF. Given the fact that jailbreak detection is inherently self defeating, it becomes trivial to bypass the above checks.