"dyld`__abort_with_payload" error and exit code 45 on attempted reverse engineering of iOS app

0

I am attempting to reverse engineer an iOS app to remove jailbreak detection. When using lldb, I got this output:

* thread #1: tid = 0xe26e, 0x00000001012322f8 dyld`__abort_with_payload + 8, queue = 'com.apple.main-thread', stop reason = signal SIGABRT

I looked it up and __abort_with_payload has to do with embedded binaries or code signing or something, which gives me reason to believe it has something to do with how mobilesubstrate injects dylibs into apps.

I tried disabling mobilesubstrate, and running lldb again. This time, it gave a different issue:

Process 16662 resuming
Process 16662 exited with status = 45 (0x0000002d)

What is exit code 45? Google searching didn't help very much, but according to osstatus.com, it can mean ENOTSUP or "Operation not supported". What does "Operation not supported" mean?

ios
reverse-engineering
jailbreak
lldb
asked on Stack Overflow Aug 26, 2019 by Tanner H.

1 Answer

2

It's PT_DENY_ATTACH.

Many SO answers already cover it to some extent to give you an idea: here & here . Even in more details covered in Alexander O'mara 's blog post here

To counter it in lldb before your executable runs type:

b ptrace

You should see something like this:

Breakpoint 5: where = libsystem_kernel.dylib`__ptrace, address = 0x00000001c2b17140

Giving you indication where it's actually handled.

When you hit the ptrace breakpoint type:

th r

i.e. shortened syntax for thread return

It will force exiting the ptrace function without actually doing the denying part.

After the th r you may see something like this

->  0x100daa548 <+140>: str    w0, [sp, #392]
    0x100daa54c <+144>: bl     0x100b01cb8               ; ___lldb_unnamed_function1756$$prodx
    0x100daa550 <+148>: bl     0x100b02538               ; ___lldb_unnamed_function1760$$prodx
    0x100daa554 <+152>: bl     0x100daa470               ; ___lldb_unnamed_function29542$$prodx

The code snippet is from OP and is irrelevant. What is important is ip(i.e. instruction pointer register) is pointing to the next assembly instruction after the ptrace call. Hence to see what's going on we must disassemble preceding assembly code. Every single arm64 assembly instruction is 4 bytes hence we type:

di -s 0x100daa544

That will most likely yield:

0x100daa544    bl     <some address> ; aka ptrace(PT_DENY_ATTACH, ...)

So now you can just inspect the actual bytes of the opcodes^:

x 0x100daa544 -c 4

These are the bytes to replace with the nop mentioned below.

However it may happen the ptrace is made directly instead through a syscall like this (that's what libsystem_kernel.dylib`__ptrace: actually does internally) :

mov x0, #0x1f ; this is PT_DENY_ATTACH 31 syscall argument
mov x16, #0x1a ; x0,x16 can be set in numerous ways so I skip the opcodes
01 10 00 D4    svc  #0x80

This is AARCH64 (aka arm64) assembly so I'm assuming your device is iPhone5s or newer. To further obfuscate it, the instructions might be separated by some nonrelevant instructions. If you need to follow this path check the SO question here.

So replacing 01 10 00 D4 in your favourite hex editor with

1f 20 03 d5      nop

should get you going.

One could go crazy with not using 0x80 in svc for the syscall

01 00 00 d4  svc #0
21 00 00 d4  svc #1
01 02 00 d4  svc #0x10
e1 1f 00 d4  svc #0xff

Each of them would happen to work, but it might break at any point (still it hasn’t since iOS7 up to present iOS 13).

Final remarks:

If you actually modify the binary some extra protection mechanism might exist like checksum and other self integrity checks. That's definitely beyond the scope of this question.

answered on Stack Overflow Aug 26, 2019 by Kamil.S • edited Aug 28, 2019 by Kamil.S

User contributions licensed under CC BY-SA 3.0