Intro[]
Complex programs (like the Canon firmware) have many data structures which group variables belonging to the same module.
Some examples: 2.0.4_HotPlug_Structs, 2.0.4_MovieRecorder_structs, 2.0.4_MovieWriter_structs, 2.0.4_small_LiveView_struct_at_0x44FC, mvr_config from mvr.h...
In C, you would declare a struct like this:
struct foo { int bar; int baz; ... };
In Assembler, a member of a structure is referenced like this:
FF0EAC88: e51f8e78 ldr r8, [pc, #-3704] ; 0xff0e9e18: pointer to 0x4B4C (aAJ_0x44FC_LiveView_struct_0x00_to_0xC8) ⬁ FF0EAC8C: e1a04000 mov r4, r0 ⬁ FF0EAC90: e5980028 ldr r0, [r8, #40] ; 0x28 ⬁ FF0EAC94: e1a06001 mov r6, r1 ⬁ FF0EAC98: e1a05002 mov r5, r2 ⬁ FF0EAC9C: eb03b683 bl AJ_if_StateObject_then_Get.State__R0.StateObj
decompiled:
AJ_if_StateObject_then_Get.State__R0.StateObj(*(0x4b74))
Mem-spy (Memory Addresses) and ARM-console decompiler (module "deco") will only show addresses like 0x4b74. These are found after some computation (you can't find them in the dump easily).
Step-by-step example[]
Let's say we have found an interesting address on 550D/1.0.8 or 1.0.9 (these two versions are identical, unlike 60D):
#define FOCUS_CONFIRMATION (*(int*)0x41d0)
To find other related references, you need to find the structure which our address belongs to. We are looking for a number which satisfies these conditions:
- it's smaller than our interesting address (0x41d0), but not with too much
- the firmware has some references to it
Load arm-console, define this function:
def guess_struct(d, x, refmin=2, maxsize=1000): candidates = {} for a,v in d.ROM.iteritems(): if v <= x and v >= x-maxsize: nrefs = len(find_refs(d, v)) if nrefs > refmin: candidates[v] = nrefs for c,n in sorted(candidates.iteritems(), key=lambda x: -x[1]): print hex(c),"refs=%d" % n, "dif=%d" % (x-c)
... and try it (it will find some candidates and sort them according to the number of references to them).
In [119]: guess_struct(d,0x41d0,2,500) 4000 refs=236 dif=464 4100 refs=54 dif=208 41B4 refs=31 dif=28 41CC refs=20 dif=4 4154 refs=17 dif=124 3FFF refs=17 dif=465 41A0 refs=16 dif=48 4001 refs=13 dif=463 4002 refs=12 dif=462 4009 refs=10 dif=455 4008 refs=9 dif=456 4014 refs=9 dif=444 [...]
Now we have to use some intuition. Obviously, the first results are not the good ones (as you have noticed from the NumPy'ing tutorial, "round" numbers have a lot of references to them, and the reason can be found easily by studying some human psychology :)
So, from these candidates, we notice that "41CC refs=20 dif=4" is very close to our address and the firmware has many references to it, so let's see what other functions are referencing it.
In [120]: d.refs(0x41CC) olc_info_changed+4: ff0a8d30: e59f12ec ldr r1, [pc, #748] ; 0xff0a9024: pointer to 0x41cc 0x41cc focusinfo+4: ff0a90f8: e51f40dc ldr r4, [pc, #-220] ; 0xff0a9024: pointer to 0x41cc 0x41cc rmt_olc_com_gr8_focusStatus+16: ff0a8f9c: e59f5080 ldr r5, [pc, #128] ; 0xff0a9024: pointer to 0x41cc 0x41cc [... and a bunch of others ... ]
Indeed, it seems to be something related to focus and GUI display.
Let's try to see one of those functions:
In [121]: g focusinfo // Start of function: focusinfo NSTUB(focusinfo, ff0a90f4): ff0a90f4: e92d403e push {r1, r2, r3, r4, r5, lr} ff0a90f8: e51f40dc ldr r4, [pc, #-220] ; 0xff0a9024: pointer to 0x41cc ff0a90fc: e3a01000 mov r1, #0 ff0a9100: e58d1008 str r1, [sp, #8] ff0a9104: e5941008 ldr r1, [r4, #8] ff0a9108: e3510000 cmp r1, #0 ff0a910c: 0a00000e beq 0xff0a914c: pointer to 0xe5dd2009 ff0a9110: e5941004 ldr r1, [r4, #4] ff0a9114: e3510001 cmp r1, #1 ff0a9118: 1a000007 bne 0xff0a913c: pointer to 0xe3a02004
In [122]: dec focusinfo *(-4 + sp0) = lr0 *(-8 + sp0) = unk_R5 *(-12 + sp0) = unk_R4 *(-16 + sp0) = arg3 *(-20 + sp0) = arg2 *(-24 + sp0) = arg1 *(-16 + sp0) = 0 if *(0x41D4) == 0: *(-24 + sp0) = BYTE(MEM(-15 + sp0)) DebugMsg(159, 1, msg=' focusinfo %x,%x,%lx', BYTE(0), BYTE(MEM(-15 + sp0)), arg2, 0x0, unk_R4, ...) return ret_DebugMsg_FF0A9168 if *(0x41D0) != 1: PD_NotifyOlcInfoChanged(0x0, -16 + sp0, 0x4, arg3) => ret_PD_NotifyOlcInfoChanged_FF0A9148 *(-24 + sp0) = BYTE(MEM(-15 + sp0)) DebugMsg(159, 1, msg=' focusinfo %x,%x,%lx', BYTE(0), BYTE(MEM(-15 + sp0)), arg2, 0x0, unk_R4, ...) return ret_DebugMsg_FF0A9168 *(-16 + sp0) = BYTE(MEM(1 + arg0)) *(-15 + sp0) = BYTE(MEM(arg0)) *(-14 + sp0) = BYTE(MEM(2 + arg0)) *(-13 + sp0) = BYTE(MEM(3 + arg0)) PD_NotifyOlcInfoChanged(0x0, -16 + sp0, 0x4, arg3) => ret_PD_NotifyOlcInfoChanged_FF0A9148 *(-24 + sp0) = BYTE(MEM(arg0)) DebugMsg(159, 1, msg=' focusinfo %x,%x,%lx', BYTE(MEM(1 + arg0)), BYTE(MEM(arg0)), arg2, BYTE(MEM(1 + arg0)), unk_R4, ...) return ret_DebugMsg_FF0A9168 !end
Bingo! Now we have a way to find this address inside a function... we just have to look for "focusinfo" to find this on a new camera.
Applying the new findings on other cameras[]
Let's validate our new finding on 60D and 600D. By decompiling the function referencing "focusinfo %x,%x,%lx", we find:
60D.109 : if *(0x4680) != 1: ... (value identical to the one found with mem-spy -> confirmed) 600D.101: if *(0x479C) != 1: ...
For 50D, I'm too lazy to load the dump and decompile it, so let's just look in assembler:
FF8AF378: e59f4070 ldr r4, [pc, #112] ; 0xff8af3f0: pointer to 0x3cdc FF8AF37C: e5941008 ldr r1, [r4, #8] ; this will be: r1 = *(int*)0x3ce4; FF8AF380: e3510000 cmp r1, #0 ; <--- this is the first decompiled "if" FF8AF384: 0a000010 beq FF8AF3CC FF8AF388: e5941004 ldr r1, [r4, #4] ; this will be: r1 = *(int*)0x3ce0; FF8AF38C: e3510001 cmp r1, #1 ; <--- this is the second decompiled "if" ... FF8AF3E0: e28f208c add r2, pc, #140 ; *' focusinfo %x,%x,%lx'
So, the focus confirmation address on 600D is 0x479C, and on 50D is 0x3ce0.
Now, all we have to do is to put the new values in platform/MODEL.FWVERSION/consts.c, in the definition of FOCUS_CONFIRMATION, and try :)
Homework[]
Fix the decompiler so it can show structures and offsets instead of magic numbers.