Magic Lantern Firmware Wiki

Struct Guessing

327pages on
this wiki
Add New Page
Add New Page Talk0


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 exampleEdit

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 camerasEdit

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 :)


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


Also on Fandom

Random Wiki