Skip to main content
A row of tall painted levers in a railway signal box, one pulled forward out of line with the rest.
Photo by Georg Eiermann on Unsplash
  1. Research/

iTunes anti-debugging bypass with GDB and LLDB

·4 mins
Patrik Grobshäuser
Author
Patrik Grobshäuser
Security researcher at Assetnote / Searchlight Cyber. Before that, seven years triaging other people’s reports at HackerOne and Shopify. Hunting bugs since 2012, published as Patrik Fehrenbach until 2025.
Table of Contents

First of all, if we have a crash in iTunes we need a debugger to see where the actual crash is happening.

Xcode comes with a gdb like Darwin debugger which is a good point to start.

You can simply start iTunes by running it with

sh-3.2# gdb /Applications/iTunes.app/

The next thing you will see is Program exited with code 055. But why is iTunes crashing if I want to attach it onto a debugger ?

The anti-debugging check
#

The reason is simple, Apple has some built in anti-debuggers called in the ptrace function. To disable those we have to look at the source of the ptrace function. Once we are inside the gdb debugger we can set a breakpoint on this function:

(gdb) br ptrace
Breakpoint 1 at 0x7fff8dff9d14

Now our breakpoint is set on the ptrace function, if we now re-run the application iTunes will hold on this function.

Starting program: /Applications/iTunes.app/Contents/MacOS/iTunes
Reading symbols for shared libraries . done

Breakpoint 1, 0x00007fff8dff9d14 in ptrace ()

Now we have the program stopped before the ptrace function is loaded and can now have a look on the registers by

(gdb) i r

rax            0x44f0 17648
rbx            0x7fff5fc35110 140734800023824
rcx            0x0 0
rdx            0x0 0
rsi            0x44f0 17648
rdi            0x1f   31
rbp            0x7fff5fbfe4f0 0x7fff5fbfe4f0
rsp            0x7fff5fbfe498 0x7fff5fbfe498
r8             0x7fff5fc351c0 140734800024000

Patching the rdi register
#

The RDI register is our target we have to set the value of the register to 11 (as seen in the source to disable ptrace)

(gdb) set $rdi=11
(gdb) i r

rax            0x44f0 17648
rbx            0x7fff5fc35110 140734800023824
rcx            0x0 0
rdx            0x0 0
rsi            0x44f0 17648
rdi            0xb 11

Then we simply continue the program with c and are finally able to debug it.

Switching to LLDB
#

But during my research I needed a debugger which was able to interpret Python. Apple’s built in GDB doesn’t support Python and it is no longer developed by Apple.

So I started researching and found out that there is a new Debugger called LLDB which is a gdb alike debugger with tons of new features.

To start iTunes in lldb just do

(lldb) file /Applications/iTunes/
(lldb) r

But we will soon end on the same point as on GDB… the anti-debuggers

Process 17595 launched: '/Applications/iTunes.app/Contents/MacOS/iTunes' (x86_64)
Process 17595 exited with status = 45 (0x0000002d)

But how to proceed on this ?

Porting the breakpoint address
#

What I did to solve the problem : I returned to the previous gdb debugger and looked at the address where the ptrace function was called in this case it was on

Breakpoint 1 at 0x7fff8dff9d14

What I did was set a breakpoint in lldb at that same address:

(lldb) b 0x7fff8dff9d14

The next step is like on GDB to re-run the program to let it stop before the ptrace function is called

Process 17623 launched: '/Applications/iTunes.app/Contents/MacOS/iTunes' (x86_64)
Process 17623 stopped
* thread #1: tid = 0x1c03, 0x00007fff8dff9d14 libsystem_kernel.dylib`ptrace, stop reason = breakpoint 2.1
    frame #0: 0x00007fff8dff9d14 libsystem_kernel.dylib`ptrace

Our debugger has now stopped at that point.

Reading and writing rdi in LLDB
#

The next step is to look at the registers. In lldb this is no longer i r as it was in gdb — you use register read instead.

(lldb) register read

General Purpose Registers:

rax = 0x00000000000044f8
rbx = 0x00007fff5fc35110  dyld::gLinkContext
rcx = 0x0000000000000000
rdx = 0x0000000000000000
rdi = 0x000000000000001f  

Now have a look at the rdi register it is set on 0x000000000000001f , go back to gdb and have a look there

rdi            0x1f   31

rdi is set to 0x1f which equals the function 31 before we’ve set it to 11, so now we have to look at what changed when we set it to 11

rdi            0xb 11

Now we can see that the value is now on 0xb

What we have to tell the debugger now is to set the rdi register to the same value as the gdb debugger lldb has this function (thank god!) too.

(lldb) register write rdi 0x000000000000000b

Now we have disabled the anti debuggers and can start debugging on our lldb debugger with a built in Python interpreter! Great one