Intro[edit | edit source]

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	



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[edit | edit source]

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)

ff0a8d30:	e59f12ec 	ldr	r1, [pc, #748]	; 0xff0a9024: pointer to 0x41cc

ff0a90f8:	e51f40dc 	ldr	r4, [pc, #-220]	; 0xff0a9024: pointer to 0x41cc

ff0a8f9c:	e59f5080 	ldr	r5, [pc, #128]	; 0xff0a9024: pointer to 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

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[edit | edit source]

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[edit | edit source]

Fix the decompiler so it can show structures and offsets instead of magic numbers.

Discussion[edit | edit source]

Community content is available under CC-BY-SA unless otherwise noted.