Jun 5, 2013

[rev] a small ARM riddle

Today I just looked over some ARM binary and found this interesting piece:

47 78          BX      PC
46 C0          NOP
E5 5E C0 01    LDRB    R12, [LR, #-1]
E1 53 00 0C    CMP     R3, R12
37 DE 30 03    LDRCCB  R3, [LR, R3]
27 DE 30 0C    LDRCSB  R3, [LR, R12]
E0 8E C0 83    ADD     R12, LR, R3, LSL#1
E1 2F FF 1C    BX      R12

So, let's start my new blog with a small riddle ;-)
I'll soon provide a sample calling this method and later a full explanation.

Update 1:
The function is called from thumb mode like this
0xB8: FX XX FX XX    BL      func
0xBC: 06 04 16 1B+   DCB 6, 4, 0x16, 0x1B, 0x20, 0x57, 0x5C, 0x61

Update 2:
Since I'm frustrated with DisplayLink and Intel... let's use the time to explain.
BX PC changes the mode from thumb to arm. Inside LR we have the next address that should be executed on a return. This is still in thumb mode (which is offset+1). So the LDRB will load 0x06 to R12. What is not visible, is that R3 is loaded with a value. In the next instruction this value is compared with the currently loaded byte. LDRCCB (UAL instruction) will load LR + R3 to R3 if R3 is lower than R12. Else it will use the R12 value. At the end it will jump to R3 << 1 offset from LR. So we have a jumptable (switch). The first byte after the call (BL) tells us the entries. The next one is the default branch. The left shift by two is done so it will always go to valid thumb mode instructions again.

If you have a valid IDA license you can follow the following instrcutions :-)
  1. Rename the switch function to switch or whatever
  2. Right click and set it will not return. This prevents parsing of the switch byte table.
  3. Place your cursor on a BL switch and choose Edit -> Other -> Specify switch idiom
  4. Address of jump table set to 0xBC (modify to meet the count entry in your case)
  5. Number of elements to the first byte + 2 (8)
  6. Size of table element to 1 (one byte for one switch case)
  7. Element shift count to 1, this is the LSL#1
  8. Input register to R3 (does not really matter)
  9. First(lowest) input value to -1 (because of the count at the beginning, so it will align switch cases correctly)
Et voilĂ  :-) Now it's time to write a script that will do this automatically for all switch()es...

2 comments:

  1. Anonymous9/06/2014

    Thanks for this post. I just came across this exact same snippet of code in a binary I'm examining and couldn't quite figure out what it was doing.

    ReplyDelete
  2. Anonymous2/19/2015

    I encountered a similar piece of code. After further analysis I found it in a lot of places in the code and decided to write a script. How can I post it?

    ReplyDelete