2

I'm facing some issues while debugging an iOS application for educational purposes. This is an iOS application found on the App Store and has some anti-debugging capabilities built in it.

Pretext: The assembly instruction you see below is a snippet of the anti debugging checks done by the application. The instructions below are going to do the following:

  1. Load Register X8 with a memory address of (Current PC Register - 0xa70)
  2. No Operation
  3. Load Byte from register X8 into w8
  4. Compare Register w8 if it is equal to 0xff

Exact Code block for Instructions as seen in IDA

ADR X8, __cB5JgDa_QrhRN_ ; +[cB5JgDa QrhRN] NOP LDRB W8, [X8] CMP W8, #0xFF

Corresponding Byte Code Block for Same Instruction Set

88 AC FF 10 1F 20 03 D5 08 01 40 39 1F FD 03 71

Assembly Instructions for anti-debug check

Now, let's jump the gun and see what happens when it tries to load the byte from register x8 int w8. As you can see, I did a register read of both w8 and X8. In theory, based on the memory contents of X8, this instruction should have loaded 0xff into w8 through the assembly instruction ldrb w8, [x8]

Problematic Assembly Instruction

Problem Faced: Upon evaluation of the instruction the actual memory contents in w8 was 0xfe and NOT 0xff. This is really an unexpected behaviour as my ARM knowledge tells me that the correct value for that evaluation should be 0xff and not 0xfe.

Evaluated result was 0xfe instead of 0xff

Things I have tried but failed to explain this behaviour

  1. Creating mini Xcode iOS app and trying to replicate the same instruction set and memory state
  2. Setting watchpoints to observe if any part of the program is editing the memory in-between
  3. Looking for memory protections such as mprotect if they have modified that memory region

I would be highly appreciative of anyone who can point me in any right direction or ways so that I can better understand this mysterious behaviour. If it was my misunderstanding in ARM instruction, please do tell me too. Thank you so much everyone.

  • 1
    Can you add the opcode bytes for the instructions? Also, if possible, try to use code blocks instead of (or in addition to) screenshots. – Igor Skochinsky May 5 at 12:33
  • 1
    Have added in the code block as well as the byte code for the same instruction set. – Max Chee May 5 at 18:46
3

I think that the code is supposed to be checking for hooks.

The adr instruction sets x8 to the start of the function so if there was a breakpoint or a jump placed there by a hook library, the byte there would be different from the original value FF.

One possibility is that there is a breakpoint there but the debugger is masking it by showing you the original code. If you did place a breakpoint there, try removing it before stepping through the read. You can also try using one-shot breakpoints which are removed automatically after being hit.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.