6

As the title says, how to calculate offsets for branch instructions? For example i have following assembly code,

0x60ECE    B loc_60EE6
;
;
;
0x60EE6    LDR.W R2, #0x123

Hex code for location 0x60ECE is 0A E0. i want to know how it is calculated. According to https://stackoverflow.com/questions/6744661/understanding-arm-assembler-branch-offset-calculation , offset should be 04 instead of 0A.

I'm working on android binary.

2 Answers 2

5

The instruction format is in little-endian, so bytes 0A E0 gets parsed as machine code 0xE00A, or 1110000000001010b in binary.

According to the documentation for the THUMB Instruction Set, the first 5 bits (11100b) decode to an unconditional branch opcode, and the last 11 bits (00000001010b) decode to Offset11:

Unconditional branch

As per the documentation above, the destination address is calculated as "PC relative +/- Offset11 << 1" plus 4 for the prefetch operation.

If we do the math, we see that everything works out:

   0x60ECE + (00000001010b << 1) + 0x4
== 0x60ECE +       10100b        + 0x4
== 0x60ECE +        0x14         + 0x4
== 0x60EE6
4

You're missing the fact that you're working in THUMB mode, where you have two bytes per instruction (for most instructions at least), and that link describes ARM mode, where every instruction has 4 bytes.

(How do i know you're in THUMB mode? Apart from your last question, your 0x60ECE B loc_60EE6 isn't 4-byte aligned, so it must be THUMB).

If you add 4 bytes to the instruction at loc_60ECE, you get 0x60ED2. Subtract this from 60EE6 to get 14, or 20 decimal. Divide by 2 (2 byte instructions in THUMB mode) to get 10 decimal, or 0A hex.

As calculating offsets can be hard and is error-prone, i let the gnu arm assembler handle it for me. First write an assembly file, like this (named q.s, choose any name you want):

.thumb
.arch armv7a
.syntax unified
.org 0x60ECE
    B codecave
original:
.org 0x60EE6
codecave:
movw R2, #0x123
B original

then assemble it and check the result:

arm-linux-gnueabi-as q.s
arm-linux-gnueabi-objdump -s a.out | grep -v "00000000 00000000 00000000 00000000"

Contents of section .text:
 60ec0 00000000 00000000 00000000 00000ae0  ................
 60ee0 00000000 000040f2 2312f1e7           ......@.#...    

You see your 0ae0 at 60ece, and 40f22312f1e7 at 60ee6. You can patch this in IDA directly, or use the idapatcher plugin to copy/paste the hex. I found this to be much easier than crafting the patched bytes manually.

1
  • Thank you sir for pointing out this trick. It made everything a lot easier for me. Finally i was able to create codecave. Commented Jun 9, 2015 at 4:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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