An experimental decompiler for ARM ASM is implemented in ARM-console, module deco.
Theory: Static_analysis
Notations[]
- arg0, arg1, arg2, arg3 => function arguments passed in r0, r1, r2, r3
- sp0 => stack pointer at the beginning of the function
- *(sp0), *(sp0+4), *(sp0+8) => arg4, arg5, arg6
- *(sp0-4), *(sp0-8)... => local variables
- !end => end of code path
- EQ(x), NE(x): check some condition flags; e.g. EQ(x) is true if x == 0
- EQ5(x) is true if x == 5 (these will appear when decompiling jump tables)
Forward (normal) decompilation[]
You decompile from the start of a function.
dec AJ_guess_get_DIGIC_time return struct_0xc0242000.off_0x14 /*0xC0242014*/ !end
dec PrintRemconParam *(-4 + sp0) = lr0 *(-8 + sp0) = unk_R4 TH_con_puts('\n[RemDriver] RemconParam\n', arg1, arg2, arg3) => ret_TH_con_puts_FF066D6C TH_con_puts(' PulseWidthMin : %4ld\n', remocon_struct.PulseWidthMin /*off_0x10, 0x2AA0*/, arg2, arg3) => ret_TH_con_puts_FF066D7C TH_con_puts(' PulseWidthMax : %4ld\n', remocon_struct.PulseWidthMax /*off_0x14, 0x2AA4*/, arg2, arg3) => ret_TH_con_puts_FF066D88 [...] return 0 !end
dec RemOff_secret_mode_RemOn *(-4 + sp0) = lr0 *(-8 + sp0) = unk_R4 RemOff() => ret_RemOff_FF07BF08 if arg0 != 0: if arg0 == 1: secret_mode(0x4, 0x14, 0x1, 0x2) => ret_secret_mode_FF07BF30 if arg0 == 0: secret_mode(0x4, 0x14, 0x1, 0x1) => ret_secret_mode_FF07BF30 RemOn() => ret_RemOn_FF07BF38 !end
Loops[]
The decompiler doesn't supoort loops, but it will usually handle the first iteration:
dec gui_main_task *(-4 + sp0) = lr0 *(-8 + sp0) = unk_R5 *(-12 + sp0) = unk_R4 memcpy(-44 + sp0, GMT_FUNCTABLE, 0x20) => ret_memcpy_FF01FFA8 gui_init_end() => ret_gui_init_end_FF01FFAC msg_queue_receive(gui_main_struct.msg_queue /*off_0x38, 0x1C3C*/, -48 + sp0, 0x0, arg3) => ret_msg_queue_receive_FF01FFC4 gui_main_struct.counter /*off_0x4, 0x1C08*/ = -1 + gui_main_struct.counter /*off_0x4, 0x1C08*/ [...]
Reverse decompilation[]
This is useful when normal decompilation fails (usually when you have to deal with huge monsters like IDLEHandler or AJ_CopyDataToStorage).
S PROP_SHUT String references to ff2014d4 'PROP_SHUTTER_COUNTER [%d][%d]': AJ_CopyDataToStorage+22892: ff201390: e28f2f4f add r2, pc, #316 ; *'PROP_SHUTTER_COUNTER [%d][%d]' 'PROP_SHUTTER_COUNTER [%d][%d]' [...]
g ff201390 f201390: e28f2f4f add r2, pc, #316 ; *'PROP_SHUTTER_COUNTER [%d][%d]' ff201394: e58d3000 str r3, [sp] ff201398: e5943004 ldr r3, [r4, #4] ff20139c: e3a01003 mov r1, #3 ff2013a0: e3a00083 mov r0, #131 ; 0x83 ff2013a4: ebf99810 bl @DebugMsg [...]
bd ff2013a4 [...] DebugMsg(132, 2, msg='copyDataToStorage eventID(%#x)Data(%d)size(%d)', *(arg0), arg0->off_0x8, arg3, unk_R4, unk_R5, ...) if arg0 != 0: if *(arg0) <= 0x8005002D: if *(arg0) > 0x80030013: if *(arg0) <= 0x80040006: if *(arg0) <= PROP_HDMI_CHANGE: if *(arg0) <= 0x80030029: REGWRITE(PC, 4279483944 + 4**(arg0)) if EQ21(2147287020 + *(arg0)): *(-40 + sp0) = arg0->off_0x8 DebugMsg(131, 3, msg='PROP_SHUTTER_COUNTER [%d][%d]', arg0->off_0x4, arg0->off_0x8, arg3, unk_R4, unk_R5, ...) !!! Stack not restored !!! !end
hex(21 - 2147287020) '80030029'
#define PROP_SHUTTER_COUNTER 0x80030029 :)
Advanced use[]
cp = range(0xff31695c, 0xff316970+1, 4)
cp [4281428316L, 4281428320L, 4281428324L, 4281428328L, 4281428332L, 4281428336L]
emusym.print_cp(cp) CODE PATH: ff31695c: e5940008 ldr r0, [r4, #8] ff316960: e3500007 cmp r0, #7 ff316964: 83a020d3 movhi r2, #211 ; 0xd3 ff316968: 828f1f55 addhi r1, pc, #340 ; *'GUI\\ShootInfo\\DlgShootOlcAFFrame.c' ff31696c: 828f0f5d addhi r0, pc, #372 ; 0xff316ae8: pointer to 0x30 ff316970: 8bf3f3a9 blhi @assert_0
cp = emusym.add_branch_info(cp)
print deco.decompile(cp[0], [cp]) SEQ(IF(-7 + MEM(8 + unk_R4), IFB(HI, SEQ(CALL(4281428336, 4278269980, 4281428712, 4281428676, 211, arg3, arg4, arg5, arg6, arg7), !end))))
print emusym.P.doprint(deco.decompile(cp[0], [cp])) if unk_R4->off_0x8 > 7: assert_0(0xff316ae8: pointer to 0x30, 'GUI\\ShootInfo\\DlgShootOlcAFFrame.c', 0xd3) => ret_assert_0_FF316970 !end