Skip to content

Instantly share code, notes, and snippets.

@JamesHagerman
Last active June 12, 2017 23:42
Show Gist options
  • Select an option

  • Save JamesHagerman/16eb6f5fb6592af3eb68c6bb42f82704 to your computer and use it in GitHub Desktop.

Select an option

Save JamesHagerman/16eb6f5fb6592af3eb68c6bb42f82704 to your computer and use it in GitHub Desktop.
Found an issue with CS_ARCH_ARM, CS_MODE_THUMB not handling an op code correctly

Issue (resolved! See comments!)

As a test, I compiled the 1bitsy miniblink example (from https://github.com/1Bitsy/1bitsy-examples) using:

make miniblink.bin

Decompile of address 0x1ac using arm-none-eabi-objdump -d miniblink.bin gets me

080001ac <button_boot>:
 80001ac:	b510      	push	{r4, lr}
 80001ae:	f240 6002 	movw	r0, #1538	; 0x602
 80001b2:	f000 f862 	bl	800027a <rcc_periph_clock_enable>
 80001b6:	2100      	movs	r1, #0
 80001b8:	2302      	movs	r3, #2
 80001ba:	480a      	ldr	r0, [pc, #40]	; (80001e4 <button_boot+0x38>)
 80001bc:	460a      	mov	r2, r1
 80001be:	f000 f83f 	bl	8000240 <gpio_mode_setup>
 80001c2:	4b09      	ldr	r3, [pc, #36]	; (80001e8 <button_boot+0x3c>)
 80001c4:	681b      	ldr	r3, [r3, #0]
 80001c6:	f013 0302 	ands.w	r3, r3, #2
 80001ca:	d10a      	bne.n	80001e2 <button_boot+0x36>
 80001cc:	4a07      	ldr	r2, [pc, #28]	; (80001ec <button_boot+0x40>)
 80001ce:	6013      	str	r3, [r2, #0]
 80001d0:	4b07      	ldr	r3, [pc, #28]	; (80001f0 <button_boot+0x44>)
 80001d2:	681b      	ldr	r3, [r3, #0]
 80001d4:	f383 8808 	msr	MSP, r3
 80001d8:	4b06      	ldr	r3, [pc, #24]	; (80001f4 <button_boot+0x48>)
 80001da:	e8bd 4010 	ldmia.w	sp!, {r4, lr}
 80001de:	681b      	ldr	r3, [r3, #0]
 80001e0:	4718      	bx	r3
 80001e2:	bd10      	pop	{r4, pc}
 80001e4:	40020800 	.word	0x40020800
 80001e8:	40020810 	.word	0x40020810
 80001ec:	e000ed08 	.word	0xe000ed08
 80001f0:	1fff0000 	.word	0x1fff0000
 80001f4:	1fff0004 	.word	0x1fff0004

But Capstone, running this script:

from capstone import *

file = open('./miniblink.bin', 'rb')
content = file.read()

md = Cs(CS_ARCH_ARM, CS_MODE_THUMB) #CS_MODE_ARM)
for i in md.disasm(content, 0x0):
    print("0x%x:\t%s\t%s" %(i.address, i.mnemonic, i.op_str))

... spits out the following before returning to the command prompt.

0x1ac:	push	{r4, lr}
0x1ae:	movw	r0, #0x602
0x1b2:	bl	#0x27a
0x1b6:	movs	r1, #0
0x1b8:	movs	r3, #2
0x1ba:	ldr	r0, [pc, #0x28]
0x1bc:	mov	r2, r1
0x1be:	bl	#0x240
0x1c2:	ldr	r3, [pc, #0x24]
0x1c4:	ldr	r3, [r3]
0x1c6:	ands	r3, r3, #2
0x1ca:	bne	#0x1e2
0x1cc:	ldr	r2, [pc, #0x1c]
0x1ce:	str	r3, [r2]
0x1d0:	ldr	r3, [pc, #0x1c]
0x1d2:	ldr	r3, [r3]

And radare2 gives me:

% r2 -a arm -b16 miniblink.bin                                            
 -- Move between your search hits in visual mode using the 'f' and 'F' keys
[0x00000000]> aaa
[x] Analyze all flags starting with sym. and entry0 (aa)
[ ] 
[aav: Cannot find section at this address
aav: Cannot find section at this address
[x] Analyze len bytes of instructions for references (aar)
[x] Analyze function calls (aac)
[ ] [*] Use -AA or aaaa to perform additional experimental analysis.
[x] Constructing a function name for fcn.* and sym.func.* functions (aan))
[0x00000000]> afl
0x00000000    1 428          fcn.00000000
0x000001ac    2 42           fcn.000001ac
0x000001f8    4 48           fcn.000001f8
0x00000230    1 16           fcn.00000230
0x00000240    5 58           fcn.00000240
0x0000027a    1 26           fcn.0000027a
[0x00000000]> pdf @0x000001ac
/ (fcn) fcn.000001ac 42
|   fcn.000001ac ();
|              ; CALL XREF from 0x000001fa (fcn.000001f8)
|           0x000001ac      10b5           push {r4, lr}
|           0x000001ae      40f20260       movw r0, 0x602              ; 1538
|           0x000001b2      00f062f8       bl fcn.0000027a
|           0x000001b6      0021           movs r1, 0
|           0x000001b8      0223           movs r3, 2
|           0x000001ba      0a48           ldr r0, [0x000001e6]        ; [0x1e4:4]=0x40020800
|           0x000001bc      0a46           mov r2, r1
|           0x000001be      00f03ff8       bl fcn.00000240
|           0x000001c2      094b           ldr r3, [0x000001ea]        ; [0x1e8:4]=0x40020810
|           0x000001c4      1b68           ldr r3, [r3]
|           0x000001c6      13f00203       ands r3, r3, 2
|       ,=< 0x000001ca      0ad1           bne 0x1e2
|       |   0x000001cc      074a           ldr r2, [0x000001ec]        ; [0x1ec:4]=0xe000ed08
|       |   0x000001ce      1360           str r3, [r2]
|       |   0x000001d0      074b           ldr r3, [0x000001f0]        ; [0x1f0:4]=0x1fff0000
|       |   0x000001d2      1b68           ldr r3, [r3]
\       |   0x000001d4      83f3           invalid

So apparently something in Capstone can't handle:

80001d4: f383 8808   msr MSP, r3

I'll install Capstone from source and try again. If I still get the issue and can't track it down, I'll open an issue.

@JamesHagerman

Copy link
Copy Markdown
Author

Ah! Found the thing I missed in Capstone!

I have to use the following to get it to work correctly:

md = Cs(CS_ARCH_ARM, CS_MODE_THUMB + CS_MODE_MCLASS)

That enables MClass mode. After that, the decompile works correctly!

@JamesHagerman

Copy link
Copy Markdown
Author

Also, the trick here was realizing how Capstone was being configured. So, I dug into doing the decompile entirely with Capstone first and realized that I wasn't configuring either r2 or Capstone correctly.

This page, http://www.capstone-engine.org/lang_c.html, mentions (in section 2. Architectures and modes) that there are multiple configurations you can OR together:

cs_open(CS_ARCH_MIPS, CS_MODE_MIPS64 + CS_MODE_LITTLE_ENDIAN, &handle);

I tried that with Capstone:

from capstone import *

file = open('./miniblink.bin', 'rb')
content = file.read()

md = Cs(CS_ARCH_ARM, CS_MODE_THUMB | CS_MODE_MCLASS)
for i in md.disasm(content, 0x0):
    print("0x%x:\t%s\t%s" %(i.address, i.mnemonic, i.op_str))

And it worked!

Once that was working, I dug into the r2 sourcecode (by searching the radare2 gihub repo for CS_MODE_MCLASS and found this file: https://github.com/radare/radare2/blob/74690db2b17a9603648501a9ecb2bd8fdb38cf5c/libr/asm/p/asm_arm_cs.c#L30

That information (along with the direction from a few people on twitter) lead me to trying to figure out what I had to set in r2 to get the asm.cpu config set to cortex

My first attempt was just setting that variable in r2:

> e asm.cpu=cortex

But that didn't seem to work correctly. I'm not sure why.

However, setting it on the command line worked correctly!

r2 -a arm -b 16 -e asm.cpu=cortex mybin.bin

So now I know how to disassemble STM32F4 binaries correctly in r2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment