Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
iOS - Prevent debugger attachment in a jailbroken environment. Obfuscated by assembly and symbol mangling.
// jailbreak_protect.c
// Created by Jonathan Cardasis (C) on 10/11/19.
// Copyright © 2019 Jonathan Cardasis (C). All rights reserved.
// Source:
// Simply include this file in your project and ensure the file's Target Membership
// is set to your app.
#if !defined (jailbreak_protect) && defined (__arm64__)
#define jailbreak_protect
#define prevent_debugger PfdVSCqqteGFWxmSPFAw // Obfuscate function name
Prevent debugger attachment by invoking underlying syscalls ptrace uses.
Most anti-debug code relies on libraries which are easy enough to hook
the symbols and bypass these checks. This is an ARM64 assembly solution
which requires much more effort to bypass.
This code is executed by dyld (the dynamic linker) during the initialization phase,
before the instruction pointer enters the program code.
__attribute__((constructor)) static void prevent_debugger() {
asm volatile (
"mov x0, #26\n" // ptrace syscall (26 in XNU)
"mov x1, #31\n" // PT_DENY_ATTACH (0x1f) - first arg
"mov x2, #0\n"
"mov x3, #0\n"
"mov x16, #0\n"
"svc #128\n" // make syscall
#endif /* jailbreak_protect */
Copy link

anonymouz4 commented Apr 25, 2020

Whats the point of doing this on a jailbroken device? One could just remove the P_LNOATTACH Flag from proc->p_lflag in kernel memory

Copy link

joncardasis commented May 20, 2020

It's meant as an example of a single attack deterrent. In the cat-and-mouse game of mobile security, having some form of protection is often enough to deter a number of attackers. This method is by no means a catch-all but is better than using Obj-C methods which can be more easily traced in a dump and swizzled.

Copy link

louniversi commented Aug 19, 2020

I am trying to use your code within the main.m file on my macOS app. It doesn't compile.
Instead , this line works well
ptrace(PT_DENY_ATTACH, 0, 0, 0);
Any idea?

This is the code that won't compile, the errors are aside each line
#ifdef x86_64
asm volatile (
"mov x0, #26\n" // ptrace syscall (26 in XNU) // - COMPILER ERROR: Unknown token in expression
"mov x1, #31\n" // PT_DENY_ATTACH (0x1f) - first arg // - COMPILER ERROR: Unknown token in expression
"mov x2, #0\n" // set rest of the args to zero // - COMPILER ERROR: Unknown token in expression
"mov x3, #0\n" // - COMPILER ERROR: Unknown token in expression
"mov x16, #0\n" // - COMPILER ERROR: Unknown token in expression
"svc #128\n" // make syscall - COMPILER ERROR: Invalid instruction mnemonic 'svc'

It doesn't work even if I use a single line
asm volatile ("mov x0, #26"); // - COMPILER ERROR: Unknown token in expression

If I use
asm volatile ("mov $x0, %ecx");
I get no error. But this is not the code I need to implement.

I use XCode Version 11.5 (11E608c) on macOS 10.15.5 and compile my app with
Architectures: "Standard Architectures (64-bit Intel) - $(ARCHS_STANDARD)"
Base SDK: macOS 10.15
Valid Architectures: i386 x86_64
Deployment Target: macOS 10.13

Copy link

rustymagnet3000 commented Oct 6, 2020

@louniversi you are mixing chipsets. The code sample was for a real iOS device ( arm 64 ) not a simulator ( x86_64 ).

If you just want a solution for a iOS Simulator, you can use either x86_64 instructions or you can call syscall. Syscall won't work on a real device.

if defined(__x86_64__)
result = syscall(SYS_ptrace, 31, pid, addr, data);

@louniversi for a x86_64 version, I can see @joncardasis put this version up:

Copy link

louniversi commented Oct 6, 2020

Thank you rustymagnet3000. I succeeded using ptrace(PT_DENY_ATTACH, 0, 0, 0) and a robust check on the CodeSign. Plus something else…

Copy link

SalCat commented Oct 28, 2020

Very nice! Highly impressed. This will definitely increase the workload of a would-be attacker. Is there any issue with App Store rejection? All they’d have to do is try to debug it...

Copy link

SalCat commented Oct 28, 2020

Unfortunately this does not work on an Apple Watch. When compiling it it gives an error: “GNU-style inline assembly is disabled” it’s unfortunate because an Apple Watch is definitely where you’d like this debug-disable functionality. Not to mention the fact that bitcode has to be turned in if delivering an iPhone app with a companion WatchOS app. Bummer. :( great solution though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment