coollang 发表于 2005-8-10 00:00:00

【专题文章】西门子Flash修改进阶

Flash修改进阶
作者:coollang
很久之前写了那篇《Flash修改入门》,一直打算再写一篇,就在年前完成吧!
因为西门子的手机到目前为止,一直使用的是80C166的处理器,我写的东西主要以6688为主,一些东西在整个系列都是适用的,有时我会指出在不同机型的差别。

一、西门子手机的系统软件介绍
西门子系列手机使用了英飞凌公司(Infineon)的80C166系列的处理器,支持多级的中断。里面包含了大量的片内资源如RAM,ROM,IO部分,中断控制,CAN总线等等,有兴趣的可以看一下附录的处理器手册,对此有详细的介绍!他的片内RAM,主要是两部分:A 2 KByte 16-bit wide internal RAM provides fast access to General Purpose Registers (GPRs),user data (variables) and system stack. The internal RAM may also be used for code.A 2 KByte 16-bit wide on-chip XRAM provides fast access to user data (variables), user stacks and code.
C166的寻址空间是16M,有相当多的通用寄存器(GPRs)和专用寄存器(SFRs)。其中GPRs是16个WORD寄存器,其中前八个可以作为BYTE寄存器使用,R0L,R0H...R7L,R7H,这些GPRs和SFRs都是维持在片内RAM中。
在我的理解上,西门子手机软件是一个基于消息的多任务系统。使用定时中断来执行任务切换(在非常多的系统中使用)。比如大家经常看到的一个函数0xB4724C(pSendMessage),就是用来发送消息的。而在MP3播放、短消息处理时多处用到了这个函数进行发送消息来执行各种操作。所以一些多任务操作才成为可能。和Windows的窗口函数一样,西门子的系统也使用了类似的技术,他在创建一个菜单时,也是注册一个结构,其中提供了一个回调函数来处理各种消息(主要是键盘消息)。
手机内部有一个BootRom,里面包含BootCore(类似于PC的BIOS),负责启动时加载系统,一般嵌入式的CPU都支持多种启动方式,比如从Ram、Flash启动,或者从串行部件启动。这些都是通过BootCore来完成的。启动时,CPU在加电后会跳转到固定地址去执行,一般会把BootRom映射到这个位置,然后BootCore负责硬件自检,然后根据IO量来判断启动方式(Flash或串行借口)。比如长按或短按开机键就可以提供不同的选择。如果是从Flash启动,那么Bootcore会进行一部分地址映射工作,比如6688,他会把Flash中0xC70000的一部分映射到0x870000去,然后跳转到0xC7:FADA,这是手机软件的入口点,然后手机软件启动。手机软件首先会执行C库的初始化函数,把库函数的一部分搬到Ram中去(为了加快速度),并初始化C库的堆栈。(以下部分很多借鉴了Mamaich的IDA汇编,他对这些研究的很深入,有兴趣的可以看一下他的相关的东西http://mamaich.fuckru.net/)

0xC7:FADA             ;☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆
0xC7:FADA             Entry_StartFromFlash:
0xC7:FADA A5 5A A5 A5               diswdt
0xC7:FADE E6 08 00 FC               mov   CP, #0FC00h
0xC7:FAE2 CC 00                     nop
0xC7:FAE4 E6 89 46 94               mov   SYSCON, #9446h
0xC7:FAE8 E6 0B 00 FC               mov   STKUN, #0FC00h
0xC7:FAEC E6 0A 0C F9               mov   STKOV, #0F90Ch
0xC7:FAF0 E6 09 00 FC               mov   SP, #0FC00h
0xC7:FAF4 CC 00                     nop
0xC7:FAF6 DA 87 2E FB               calls   87h, sub_87FB2E
0xC7:FAFA DA 87 D4 FB               calls   87h, sub_87FBD4
0xC7:FAFE DA 87 F2 FB               calls   87h, sub_87FBF2
0xC7:FB02 E6 00 00 00               mov   DPP0, #0
0xC7:FB06                           ; assume dpp0: 0 (page 0x0)
0xC7:FB06 E6 01 03 00               mov   DPP1, #3
0xC7:FB0A                           ; assume dpp1: 3 (page 0xC000)
0xC7:FB0A E6 02 02 00               mov   DPP2, #2
0xC7:FB0E                           ; assume dpp2: 2 (page 0x8000)
0xC7:FB0E E6 03 03 00               mov   DPP3, #3
0xC7:FB12                           ; assume dpp3: 3 (page 0xC000)
0xC7:FB12 E6 F0 00 60               mov   r0, #6000h
0xC7:FB16 DA B3 CE 3D               calls   0B3h, sub_B33DCE
0xC7:FB1A B5 4A B5 B5               einit
0xC7:FB1E DA 87 A2 FC               calls   87h, sub_87FCA2
0xC7:FB22 DA 87 E2 FC               calls   87h, sub_87FCE2
0xC7:FB26 DA 87 36 FD               calls   87h, loc_87FD36
0xC7:FB2A FA B4 72 5D               jmps    0B4h, loc_B45D72

0xB4:5D72 26 F0 0C 00               sub   r0, #0Ch
0xB4:5D76 DA B4 0A 57               calls   0B4h, GbsInit
0xB4:5D7A DA B4 EE 5C               calls   0B4h, MainLoop?
0xB4:5D7E DA B4 6E 5D               calls   0B4h, GbsExit
0xB4:5D82 E1 02                     movb    rl1, #0
0xB4:5D84 E4 20 0B 00               movb    , rl1
0xB4:5D88 A9 40                     movb    rl2,
0xB4:5D8A C0 44                     movbz   r4, rl2
0xB4:5D8C 06 F0 0C 00               add   r0, #0Ch
0xB4:5D90 DB 00                     rets
从X55开始,将BootCore的一部分放在Flash上,并将直接从串口启动的能力封锁(TestPoint)。通过Flash中的BootCore部分,简化了官方软件升级时的操作,并增加了一些验证。最初第三方软件是是通过处理TestPoint的办法来达到自由读写Flash的目的,后来Nutzo(KSie,Freia系列的作者)找到了BootCore的溢出bug,不需处理TestPoint即可读写FullFlash。所以针对X55的软件都会有两个选项,一个是正常的(Nutzo的Loader),另一个是WithTestPoint,因为会用到不同的Loader。

二、80C166的常用汇编级规则
西门子软件是用C写成的(会加以汇编),所以在C编译成汇编汇编语言的时候,依赖于编译器的实现,有一些固定的规则,这些规则有利于读懂反汇编的程序。如果有兴趣大家可以用Tasking写一些C语言的程序,编译后看一下对应的LST文件,也可以看到一些规则。
1、堆栈
软件使用的栈有两种,系统栈和用户栈。系统栈主要存储返回地址,段寄存器等等(主要是函数调用),使用Push,PoP一类的操作可以存取系统栈。下面给出一个察看调用栈的修改:
$Segmented
$Mod167
Patch_Address    EQU 1F8000h ;Free Space in Flash (CHANGE THIS)
Patch        Section Code Word At Patch_address ; Start Patch at Patch_Address
    main proc far; start main of patch
;TODO,恢复跳转指令覆盖的语句
        mov[-r0],r12
        mov[-r0],r13
        mov[-r0],r14
        mov[-r0],r15
        mov       r4,#8            ;调用栈深度
        cmp       r12, #4E3h         ;以下为判断察看条件,比如调用字符4E3的时候,需自行修改   
        jmpCC_NZ, ProcEnd   
        movr15, r4
        movr14, #1000h      ;调用栈的输出开始地址,我一般会用0C:1000
PopProc:
        popr12
        pop       r13
        extp #0Ch, #1
        mov,r12          ;存储调用栈的Offset
        add       r14,#2
        extp #0Ch, #1
        mov,r13          ;存储调用栈的Seg
        add       r14,#2
        mov       [-r0],r12          ;将系统栈的内容压入用户栈保存
        mov[-r0],r13
        subr15,#1
        jmpCC_NZ,PopProc      ;判断深度
        movr15,r4             ;恢复系统栈
PushProc:
        movr13,
        mov       r12,
        push r13
        push r12
        subr15,#1
        jmpCC_NZ,PushProc       
ProcEnd:
        movr15,
        mov       r14,
        movr13,
        mov       r12,
        rets
    main endp
Patch   EndS
END
这个例程可以把一定深度的调用栈显示在c:1000的位置,然后用AT指令可以看到函数的调用点的下一个位置,因为调用函数是会把吓一条指令的位置压入系统栈。
一般情况下,函数内部的局部变量会使用用户栈,用户栈的栈顶指针一般存储在R0,因为栈是向上增长,若以在压栈的过程就是mov [-R0],R12这种形式,而弹栈就是mov R12,。可以压入WORD或BYTE。相应的用mov或movb。
系统的堆内存操作需要使用malloc和free,在6688上的对应函数为
0xB4853C: void far* huge HeapMalloc( void far *Heap, unsigned int Size);
0xB486DC:void far* huge HeapFree( void far *Heap);
用这两个函数可以在堆中分配或释放内存,不过一般情况下Patch会使用全局变量来存储数据。
2、指针
C166的处理器地址空间为24位(16M),整型是16位。对于数据来说,寻址用Page,而对于指令来说,寻址使用Seg。对于一个16位的数据地址Offset来说,要想获得24位的绝对地址,需要和DPP1-4来配合得到。DPP(Data Page Pointer)是4个数据Page寄存器,根据Offset的最高两位Bit,来决定使用哪一个DPP。使用时用Offset和当前使用的DPP左移14位相加即为24bit的地址。如果临时指定一个绝对地址,可以用EXTP或EXTS,分别对应Page和Seg。所以一个DWORD的绝对地址指针(far*)根据是数据还是地址会有不同的解释。在Keil中可以用pag()和seg()来取得对应的内容。这部分的内容可以详细看一下指令手册的第六章Addressing Modes。
3、函数
对于结构性程序设计来说,对程序的理解就是对一个个函数的理解(当然还有数据结构,下面会说到)。因为是用C语言写的,所以调用规则是cdecl。即参数传入顺序是从右到左,调用函数负责清除堆栈。在西门子用的C编译器处理参数的规则是首先使用寄存器R12,R13,R14,R15。如果参数多于4个WORD,则用用户栈来传入参数。比如void f(int a,int b,int c,int d,int e,int f)则汇编结果会是
mov [-R0],f
mov [-R0],e
mov R12,a
mov R13,b
mov R14,c
mov R15,d
calls _f
add R0,#4
而R6,R7,R8,R9一般是作为函数内的局部变量,所以在函数调用的时候,通常需要保存这个寄存器。函数的返回值回放在R4,R5中,一般情况只用到R4,如果返回一个指针,则需要用R4和R5。R0一般是用户栈了。R1,R2,R3和R10,R11则根据需要使用。

三、一些Patch的技巧性内容
四、Patch中遇到的一些数据结构
五、对一些常用菜单函数的介绍

附录:
Patch所需要的汇编头文件
C166处理器手册viewfile.asp?ID=6757
C166汇编手册viewfile.asp?ID=6758

                                                 待续。。。。。。。。。。。。。。。。。。























[此贴子已经被作者于2004-1-12 15:07:53编辑过]

leeyond 发表于 2005-8-10 00:01:00

太高了,顶

zzjycsbglc 发表于 2005-8-10 00:02:00

又够消化一阵子了,使劲顶.

myxd2000 发表于 2005-8-10 00:03:00

先顶

wsxboy 发表于 2005-8-10 00:04:00

呵呵!前一篇还没有消化呢。

aiyong888 发表于 2005-8-10 00:06:00

晕,真是层出不穷呀!狼大辛苦了!

mjordan23 发表于 2005-8-10 00:07:00

榜样啊!

绿风筝 发表于 2005-8-10 00:08:00

up

RainMoon 发表于 2005-8-10 00:09:00

多谢狼大,第二节课签到。

toodle 发表于 2005-8-10 00:10:00


这个东西好啊!
支持!!

xxyu 发表于 2005-8-10 00:11:00

支持!!!回家学学!!!

tzhywj 发表于 2005-8-10 00:12:00

使劲顶.

Dong 发表于 2005-8-10 00:13:00

狼大高不可攀,我的6------------6---------8----------8---------------万岁!!!

wildgoose 发表于 2005-8-10 00:14:00

顶!存下来慢慢看

MrJewes 发表于 2005-8-10 00:15:00

不好意思,我迟到了!

coollang 发表于 2005-8-10 00:16:00

不好意思,本来打算年前要写完的,但是有一些事太忙了,而且明天就要回家。所以可能要跳票了。
因为我不想写的太粗糙,一些函数的对应这类工作非常繁琐,所以只能等年后才能完成,抱歉!

huajia 发表于 2005-8-10 00:17:00

多谢!!!
期待......

RainMoon 发表于 2005-8-10 00:18:00

回家了啊,提前拜年了!!这期间还有时间上来么,真想来此大聚会啊

狼大慢慢写,我们耐心等。

港币咋不行呢 发表于 2005-8-10 00:19:00

是啊 是啊RainMoon兄说的对~!这我还真的好好学习一下了~!和和`!

希望回家后也可以经常来

zjszmj 发表于 2005-8-10 00:20:00

怎么都消化不了,我对老大的景仰如。。。。。。。。。。。。。。。。。
页: [1] 2
查看完整版本: 【专题文章】西门子Flash修改进阶