爱技术

 找回密码
 注册会员

QQ登录

只需一步,快速开始

微信登录

微信扫一扫,快速登录

搜索
查看: 59313|回复: 60
收起左侧

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

[复制链接]
发表于 2005-8-9 00:00:00 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?注册会员 微信登录

x
主题:西门子手机Flash修改入门
作者:Cool_Lang
摘要:
本文讲述了了西门子手机Flash(FireWare)修改的相关知识,简单的实现了一个Patch,并以图形菜单的Patch展示了Flash修改的强大。

关键字:Siemens Flash Patch

--------------------------------------------------------------------------------

很抱歉,以前答应大家的,一直没时间写。看到越来越多的朋友向加入到这个行列中来,却苦于入门乏术,因此写下这篇教程。
这些东西是我做修改以来总结的一些经验,因为我也是用6688后(15/3/2003)学的这些东西,有些可能不是很准确,还请大家看后共同讨论。

一、Flash修改的必要工具
1、Hex编辑器:UltraEdit,我推荐UltraEdit,因为它比起其他的编辑器界面友好,功能强大(这篇文章就是用它写的)。
2、Flash工具:UniSinmens,V_KLAY, KSie, zSiemens。这些工具各有千秋,最好是备齐。
3、反汇编工具:ADIS16X,IDA。这两个应该是必须的,他们的侧重点不同。IDA用来汇编整个Flash。而ADIS16X可以汇编小文件,或直接编写指令。
4、辅助工具:Fbytes,Fmenu,(RizaPN)C166 Compiler,C166 JMP(ACiD [mrp])。这些工具都很有用,比如Fbytes可以模糊查找某些Bytes。
5、其他工具:科学计算器,FFMod,Cool_Image,LanguageEditor。这些工具也起到一定的用处。其中语言编辑器很重要,因为它可以到处说有的字串资源,但只能在英文98下运行。我会放上55和56的字串表(中文不能显示,只能对照着英文的使用)。
5、编程手册:80C166处理器手册,汇编指令手册

二、Flash修改的预备知识
1、80C166的一些知识。
    至于处理器的信息我就不介绍了(我也不懂),大家可以看166的手册。我只说一些和Flash紧密相关的存储器知识。166的架构和其他所有的嵌入式系统一样,分为内存和外存。段页式寻址。寻址空间16M。每段(seg)为0x10000,每个页(page)是0x4000。内存储器也就是RAM,我在Flash中看到的最大Page是37,所以RAM大小应该是880KB(0x4000 X 0x37)。6688系列的外存分为两部分6M的Flash(用的是INTEL的88C2和88C4)和MMC。6M的Flash被映射到0xA00000,进行统一寻址。而MMC则作为Dos的Fat格式的文件系统进行挂载,无需多说。其中6M的Flash又分为Rom部分和EEPROM,这么划分只是用法的不同。比如大家熟知的EEPROM指的是从5F0000开始的64KB。还有EE_FS。这个叫法是历史原因。早期的手机FLASJ(ROM)和EEPROM(存储动态数据)是分开的。现在只是用Flash的不同部分来处理。
    Flash地址和文件地址的转换,在手机内部是用统一的16M地址来处理Flash的。所以有如下公式
                    FlashAddress = FileAddress + 0xA00000。而转换为页地址则为
                    FlashAddress / 0x4000 = Page ;FlashAddress % 0x4000 = Offset。
    例如DAAF1234这个指令,DA表示CALLS函数调用。而AF5678则是被调函数的地址,其中AF是段地址(seg),而7856H(地位在前,高位在后)则是段内偏移量。
               FlashAddress = 0xAF7856,转换为文件地址则为0xF7856。
               Page = 0xAF7856 / 4000H = 0x2BD, offset = 0x7856 % 4000H = 0x3856。
    在一些资源(Image,Ringtone,Fonts)的索引中,地址就是以(page,offset)的方式存储,而在EEPROM索引中,是以FlashAddress的方式存储的。
2、常用指令的问题。
    在我们的修改中,见到的大多数指令都很简单,不外乎CALL,MOV,JPR,ADD,SUB等,只需注意一下段内跳转和段间跳转即可。还有EXTP等系列指令,在修改中经常见到。他是临时更换页地址的指令,比如D7 40 34 00,为EXTP #32 #1。#32(临时页地址),#1(有效指令数)。表示下面的1条指令的页地址为32H。还需要注意的是乘和除使用乘法寄存器MD进行操作。比如Mul op1,op2执行的操作时MD=op1*op2。32位寄存器MD的地址是FF0C。MDL是FF0C,而MDH是FF0E。除法时则是先把被除数放入MD。DIV op执行的是(MDL)=(MD)/(op1),(MDH)=(MD)mod(op1)。
3、常用资源的索引格式
    这些我在《半月谈》里曾说过一些,不是很详细,这里再说一下。
Image索引格式:
00 Byte 图片高度Higth
01 Byte 图片宽度Weigth
02 Word unhnown
04 Word 页内偏移OFFSET
06 Word 页地址PAGE
例如
ID:1
0x5F0000 (索引表开始地址)  04 04 01 00 FA 3F A1 03
PAGE = 03A1
OFFSET = 3FFA
FlashAddress = (0x03A1 * 0x4000 + 3FFA) = 0xE87FFA
ImageFileAddress 0x487FFA = FlashAddress - 0xA000000

Ringtong索引格式:
00 Word RingID
02 Word 页内偏移OFFSET
04 Word 页地址PAGE
例如
ID:0(从0开始)
0x44E522 (索引表开始地址) 00 00 00 00 93 03
PAGE = 0393
OFFSET = 0000
FlashAddress = (0x0393 * 0x4000 + 0000) = 0xE4C000
ImageFileAddress 0x44C000 = FlashAddress - 0xA000000

Fonts索引格式
这个我还不是很清楚,就不班门弄斧了。
索引开始于0x4E4DA6:
ID:1
0B 20 7E 00 02 00 00 00 A1 03

EEP索引格式:
Offset    Size     Description
------   -----  ----------------------------------------------
00       BYTE      Record starting marker [00,F0,FC] 记录标志为00,F0或FC
                   00= Unused block?   不用的Block
                   F0= Deleted block?  删除的Block
                   FC= Used block?     当前有效的Block
01       BYTE      Version. [00..05]
                   Always zero in LBA_FS & EE_FS blocks.  
                   Only EELITE blocks that has 04 & 05.
02       WORD      Size
04       DWORD     Linear address of data 此处为FlashAddress
08       WORD      ID 为平常说的BlockXX,如Block67
0A       BYTE      ??? [00,01,02]
                   Always zero in EEFULL & EELITE blocks.
                   Always 02 in LBA_FS & EE_FS blocks.
0B       BYTE      Record ending marker [00,F0,FC,FF]
                   FF= No more record
EEPROM分为EEFULL和EELITE。EEFULL主要是和机器软件的相关配置有关的内容,而EELITE更多的是和设备信息有关的内容
例如:

Block ID:71(47H)
FC 01 C8 00 74 F9 FF 00 47 00 00 FC
FC 开始标志,当前有效
01 版本
C8 00文件大小00C8H = 200
74 F9 FF 00Block地址,为Flash地址00FFF974H,转换为文件地址为FFF974H - A00000H  5FF974
47 00Block ID 0047H , 0047H = 71
00 在EELITE 中为 0
FC结束标志。

4、寄存器的习惯用法
    在Flash程序中,一些寄存器有固定的习惯用法。R12,R13,R14,R15作为传入参数,而R4和R5作为传出参数,R0被用为系统栈。例如下面的指令:   
              Mov [-R0],R6
             .......
              Mov R6,[R0+]   
就是一次常见的压栈过程。下面是一个C语言中库函数strchr的汇编实现:
seg199:84CC strchr:                              
seg199:84CC                                         
seg199:84CC                 push    DPP0         //R12也是传入参数,offset   
seg199:84CE                 mov     DPP0, r13          //传入参数,Page
seg199:84D2                 mov     r1, r14            //传入参数,查找的char
seg199:84D4                 calls   1, sub_10240       //这是一个库函数,执行的比较功能
seg199:84D8                 cmpb    rl1, rh1
seg199:84DA                 jmpr    cc_NZ, loc_C784E6  //如果未找到,跳到失败处理
seg199:84DC                 mov     r4, r12            //找到返回,R4未找到的offset
seg199:84DE                 mov     r5, DPP0           //r5 page
seg199:84E2                 pop     DPP0
seg199:84E4                 rets
seg199:84E6 Failed:                           
seg199:84E6                 mov     r5, #0           //为找到返回空   
seg199:84E8                 mov     r4, #0
seg199:84EA                 pop     DPP0
seg199:84EC                 rets
Push指令很少使用,常见的是将当前Page压栈.而对运行中的数据大多使用R0的栈.






[此贴子已经被作者于2003-12-24 13:24:14编辑过]

 楼主| 发表于 2005-8-9 00:01:00 | 显示全部楼层
三、常见工具的基本用法。
1、IDA。
    如果你想要进行Flash的修改,那么一个FullFlash的全文件汇编是必不可少的,更进一步,你需要有55和56的全文件汇编来进行对照。首先是处理一下Flash文件。因为Flash被映射到0xA00000,所以应该在前面填充上10M的空间,这样在反汇编后可以直接双击函数调用来跳转到相应的函数位置。填充可以用UltraEdit的Hex Insert/Delete。之后用IDA打开这个16M的文件进行反汇编。汇编后如果不打包大约有124M。这个步骤需要的时间较长,完成后你会发现很多的代码段没能识别,被表示为数据段。你需要强制反汇编。可以选中0xA00000-0x1000000的部分,然后点击Code,或按C,在弹出的对话框中选择Force,而不是Analyze,然后是等待。完成后数据段已经不正确了,以后需要你手动得来识别代码(按C)或数据(按D)。在程序中,你可以用N来为一个函数重命名,用Alt+M标注一个位置,用;来增加注释。更详细的用法需要你使用中来摸索了。
2、ADIS16X
    这个主要用来汇编小的程序段,因为它是别的地址空间只有一个页。所以在程序中的段间跳转和调用不能被识别。他可以用F1打开Bin文件或He文件进行汇编,其他的如obj和IEEE的格式我不熟悉,并可以选择打开文件的偏移地址。打开后用F4来反汇编,F5打开HEX格式编辑。用F4打开反汇编界面时可以直接在里面修改指令,并可以把反汇编的结果按F10保存为文本文件。
3、Fmenu
    它的用法RizaPN有说明,他可以由相邻两个菜单项的字串ID来查找同级下的所有菜单项。首先需要语言文件,如下
;
; Language data
;
.....
String 348, "Callsmissed"
String 349, "Calls missed"
String 350, "C.missed"
String 351, "Job is completed!"
String 352, "Alarmsmissed"
String 353, "Alarms missed"
String 354, "The stock market is going up."
......

其中表示不能显示的字符,比如是回车。前面的就是10进制的字串ID,系统中读取这些字串就是通过字串ID(有点像Windows的资源ID)。
fmenu的格式是:fmenu FileName MenuItem_1_StringID,MenuItem_2_StringID
这里面MenuItem_1_StringID必须是16进制的。比如fmenu v55.bin 246,312 (分别是商务助理和上网与娱乐),显示如下:
Found index at address 36460E
- menu items address : D6443E
- subroutine address : D64368
- number of item     : 12 (decimal)

1. 03A8 0359 13B7 13B6 0000 0000 0000 0003 0545 => D64368: Goto_D64656
2. 03A8 0359 13BB 13BA 0000 0000 0000 0003 0545 => D6436C: Goto_D6465A
3. 03C4 0359 0246 0245 0000 0000 0000 0003 053A => D64370: Goto_D6468E
4. 03B6 0359 0312 0311 0000 0000 0000 0003 053A => D64374: Goto_D6469E
5. 03D2 0359 021B 0218 0000 0000 0000 0003 053B => D64378: Goto_D6465E
6. 03E2 0359 029A 0299 0000 0000 0000 0003 053C => D6437C: Goto_D6466E
7. 03F2 0359 0294 0292 0000 0000 0000 0003 053D => D64380: Goto_D646AE
8. 0400 0359 008C 008A 0000 0000 0000 0003 0064 => D64384: Goto_D646BE
9. 0410 0359 0385 0383 0000 0000 0000 0003 0258 => D64388: Goto_D646CE
10. 041E 0359 0353 0352 0000 0000 0000 0003 012C => D6438C: Goto_D646DE
11. 042C 0359 014C 0148 0000 0000 0000 0003 03E8 => D64390: Goto_D6467E
12. 0398 0359 0342 0341 0000 0000 0000 0003 053A => D64394: Goto_F4BE32

共有12个菜单项,是住菜单的所有字串和入口地址。其中前面的两个字是主菜单前面动画的图片ID的地址,后面是普通模式下和大字符格式下的字串。最后的一个字一些状态相关的,我不是很清楚。最后Goto给出的是入口地址。

4、fbytes
    用法如下:fbytes FileName x1,x2,x3,,x4,,,
    待查找的字节以“,”隔开,如果不确定的字节可以为空。比如查找mov,Rx,#1234。Rx表示你不知存入那个寄存器。你可以用如下的语法查找:fbytes v55.bin E6,,34,12

四、一个简单的例子
    我们先以一个简单的例子开始,说一下修改的思路和方法,那么就以增加背景灯图标为例。
首先我们要得到处理待机图标的函数,这个函数的地址是0x3637C8。我们简单的看一下这个函数:
seg214:37C8 Idle_Icon_Switch:
seg214:37C8                 mov     [-r0], r9        //保存旧址
seg214:37CA                 mov     [-r0], r8
seg214:37CC                 sub     r0, #0Ch         //处理栈顶指针
seg214:37D0                 calls   0DCh, Signal_Icon_Switch    //DCF788,处理信号的函数,得到信号量,并处理返回值(对应图标ID)
seg214:37D4                 mov     r12, r4          //判断返回值
seg214:37D6                 cmp     r12, #0FFFFh     //如果为-1,则如下处理
seg214:37DA                 jmpr    cc_NZ, loc_D637F2       //否则,显示信号
seg214:37DC                 mov     r8, #0           
seg214:37DE                 mov     [-r0], r8
seg214:37E0                 mov     r12, r8
seg214:37E2                 mov     r13, r8
seg214:37E4                 mov     r14, #1Fh
seg214:37E8                 mov     r15, #7
seg214:37EA                 calls   0B3h, sub_B3BB1C
seg214:37EE                 add     r0, #2
seg214:37F0                 jmpr    cc_UC, loc_D637FE
seg214:37F2
seg214:37F2 loc_D637F2:                           
seg214:37F2                 mov     r8, r12
seg214:37F4                 mov     r12, #0          //x=0
seg214:37F6                 mov     r13, #0          //y=0
seg214:37F8                 mov     r14, r8
seg214:37FA                 calls   0B3h, DrawImageByIndex   //B3DF04         
seg214:37FE
seg214:37FE loc_D637FE:                           
seg214:37FE                 mov     r8, #0
seg214:3800                 mov     r9, #0FFFFh
seg214:3804                 mov     [r0], r9
seg214:3806                 mov     r12, #1
seg214:3808                 calls   0A2h, sub_A2F456    //判断状态量
seg214:380C                 cmp     r4, #5      
seg214:380E                 jmpr    cc_NZ, loc_D63818       //如果不等于5则跳到下一个判断,否则Draw图标345:GPS
seg214:3810                 mov     r8, #158h        //存与R8
seg214:3814                 mov     [r0], r8         //压栈
seg214:3816                 mov     r8, #1           //图标数量
........
seg214:3830 loc_D63830:                           
seg214:3830                 mov     r12, #1
seg214:3832                 calls   0C4h, sub_C4B9BA    //判断状态量
seg214:3836                 cmp     r4, #0           //如为TRUE
seg214:3838                 jmpr    cc_Z, loc_D63848
seg214:383A
seg214:383A loc_D6383A:                             
seg214:383A                 mov     r9, #15Bh        
seg214:383E                 mov     r12, r8
seg214:3840                 shl     r12, #1          //将栈顶指针加2赋予R12
seg214:3842                 add     r12, r0          //
seg214:3844                 mov     [r12], r9        //压栈
seg214:3846                 add     r8, #1           //图标数量加1
.........
//开始显示图标
seg214:39D4                 mov     r9, #0
seg214:39D6                 mov     [-r0], r9
seg214:39D8                 mov     r12, #1Fh
seg214:39DC                 mov     r13, r9
seg214:39DE                 mov     r14, #2Ch ; ','
seg214:39E2                 mov     r15, #7
seg214:39E4                 calls   0B3h, sub_B3BB1C
seg214:39E8                 add     r0, #2
seg214:39EA                 cmp     r8, #0           //比较图标数量
seg214:39EC                 jmpa    cc_Z, loc_D63AEE   
seg214:39F0                 cmp     r8, #1           //如为1,则直接显示
seg214:39F2                 jmpr    cc_NZ, loc_D63A04
seg214:39F4                 mov     r12, #2Ah ;      //位置x=2A      
seg214:39F8                 mov     r13, #0          //y=0
seg214:39FA                 mov     r14, [r0]        //出栈
seg214:39FC                 calls   0B3h, DrawImageByIndex  //Draw对应图标
seg214:3A00                 jmpa    cc_UC, loc_D63AEE
seg214:3A04
seg214:3A04 loc_D63A04:                           
seg214:3A04                 cmp     r8, #2           //如果图标数量为2的处理,  
seg214:3A06                 jmpr    cc_Z, loc_D63A2E    //如果图标数量多于两个,则会处理,使之交替显示。
seg214:3A08                 mov     r12, #3FBAh
seg214:3A0C                 mov     r13, #372h
seg214:3A10                 add     r12, r8
seg214:3A12                 extp    r13, #1
seg214:3A14                 movb    rl1, [r12]
seg214:3A16                 movbz   r9, rl1
seg214:3A18                 extp    #36h, #1 ; '6'
seg214:3A1C                 mov     r14, word_DBF1C
seg214:3A20                 mov     word_FE0E, r14
seg214:3A24                 divu    r9
seg214:3A26                 mov     r14, word_FE0C
seg214:3A2A                 cmp     r14, #2
seg214:3A2C                 jmpr    cc_NC, loc_D63A4C
..........
seg214:3B68 loc_D63B68:                             
seg214:3B68                 add     r0, #0Ch         //返回,调整栈顶指针
seg214:3B6C                 mov     r8, [r0+]        //恢复R8,R9
seg214:3B6E                 mov     r9, [r0+]
seg214:3B70                 rets

    这个函数很长,我已经略过一些,放上了一些主要的部分。这里先看一下重要的函数B3DF04 ,DrawImageByIndex(x:R12,y:R13,ImageID:R14)。大家如果看到的修改较多的话,会发现他的重要性。比较漂亮的功能都是通过它来实现的。它的功能是在指定的坐标处Draw一个固有图片。而图标处理程序就是通过对状态量的判断,来决定Draw那些图标上去。开始部分是把使用到的寄存器压栈。R8,R9经常被作为通用寄存器使用。上面我注释了一部分程序,大家可以自己理解一下。我们的做法就是用一个图标替换不使用的GPS图标(反正我是没见过)。要做到这一点,我们需要把状态量的判断函数改为对背景灯的判断函数,就是seg214:3808这个位置。现在我们就去找背景灯的状态函数GetLightStat。
    如何入手呢,我们知道在菜单项里可以开关背景灯的选项,那我们就用fmenu从那入手。在setup->Device->Display下面,iLLumination和Big Letters的ID分别是BF和1AC,可以找到如下:
Found index at address 3775D2
- menu items address : D7752E
- subroutine address : D7759A
- number of item     : 6 (decimal)

1. 39C2 0399 00BF 00C0 0000 39AE 0399 0003 03F7 => D7759A: Goto_D77384
2. 39C2 0399 01AC 01AD 0000 39AA 0399 0003 053A => D7759E: Goto_D77394
3. 39C2 0399 0400 0401 0000 39AA 0399 0003 03F3 => D775A2: Goto_D773A8
4. 39C2 0399 0402 0403 0000 39A6 0399 0003 053A => D775A6: Goto_D773A4
5. 39C2 0399 0404 0405 0000 39A6 0399 0003 053A => D775AA: Goto_D773B8
6. 39D2 0399 01B0 0341 0000 39A6 0399 0003 0542 => D775AE: Goto_F4BE32

背景灯对应的函数入口为D77384,我们到377384这个位置看一下。

seg215:7384                 mov     [-r0], r12
seg215:7386                 mov     [-r0], r13
seg215:7388                 calls   0D7h, sub_D7765C
seg215:738C                 mov     r13, [r0+]
seg215:738E                 mov     r12, [r0+]
seg215:7390                 jmps    0E5h, sub_E5D6AA

看到每个功能最后都会跳转到 sub_E5D6AA,所以可能是菜单的处理,而前面的一个Calls应该是我们需要的。进去看看,双击,如下:

seg215:765C sub_D7765C:                           
seg215:765C                 mov     [-r0], r8
seg215:765E                 mov     r8, #0Ah
seg215:7660                 calls   0B4h, j_Get_LightStat   //一个判断
seg215:7664                 cmp     r4, #0
seg215:7666                 jmpr    cc_Z, loc_D7766A
seg215:7668                 mov     r8, #9
seg215:766A
seg215:766A loc_D7766A:                             
seg215:766A                 calls   0D9h, sub_D9EBA0    //另一个判断,常返回真,可以忽略。
seg215:766E                 cmp     r4, #0
seg215:7670                 jmpr    cc_Z, loc_D77684    //跳转失效。
seg215:7672                 cmp     r8, #9
seg215:7676                 jmpr    cc_NZ, loc_D7767E
seg215:7678                 calls   0B4h, sub_B4D888
seg215:767C                 jmpr    cc_UC, loc_D776A4
seg215:767E
seg215:767E loc_D7767E:                             
seg215:767E                 calls   0B4h, sub_B4D880
seg215:7682                 jmpr    cc_UC, loc_D776A4
seg215:7684
seg215:7684 loc_D77684:                           
seg215:7684                 mov     [-r0], r8
seg215:7686                 mov     r12, #35F0h
seg215:768A                 mov     r13, #35Dh
seg215:768E                 mov     [-r0], r13
seg215:7690                 mov     [-r0], r12
seg215:7692                 mov     r12, #35F4h   
seg215:7696                 mov     r13, #35Dh
seg215:769A                 mov     r14, #0
seg215:769C                 mov     r15, #0
seg215:769E                 calls   0DDh, sub_DD98E2
seg215:76A2                 add     r0, #6
seg215:76A4
seg215:76A4 loc_D776A4:                             
seg215:76A4                                         
seg215:76A4                 mov     r8, [r0+]
seg215:76A6                 rets

我们可以看到在7660有一个状态判断,而766A也有一个,进入到766A看看,发现是一个空函数,类似于{return TRUE;}
seg217:EBA0 sub_D9EBA0:                             
seg217:EBA0                 mov     r4, #1
seg217:EBA2                 rets
这样可以去掉这些,简化为。

seg215:7660                 calls   0B4h, j_Get_LightStat   //一个判断
seg215:7664                 cmp     r4, #0
seg215:7666                 jmpr    cc_Z, StatFalse
        StatTrue
seg215:7678                 calls   0B4h, sub_B4D888
seg215:767C                 jmpr    cc_UC, loc_D776A4
seg215:767E
seg215:767E StatFalse:                             
seg215:767E                 calls   0B4h, sub_B4D880
seg215:7682                 jmpr    cc_UC, Other_Fun
        Other_Fun   
这样可以看出,7660处应该是我们需要的状态判断函数,双击后发现是一个跳转,再次双击进入如下函数:
seg217:EB4E Get_LightStat:                        
seg217:EB4E                 mov     DPP0, #36h ; '6'
seg217:EB52                 nop
seg217:EB54                 movb    rl1, byte_D8ED1  //offset:ED1
seg217:EB58                 jnb     r1.2, loc_D9EB60
seg217:EB5C                 mov     r4, #1
seg217:EB5E                 jmpr    cc_UC, loc_D9EB62
seg217:EB60
seg217:EB60 loc_D9EB60:                           
seg217:EB60                 mov     r4, #0
seg217:EB62
seg217:EB62 loc_D9EB62:                             
seg217:EB62                 rets
至此,我们认为这就是我们需要的Get_LightStat函数,他是对D8ED1的bit2进行判断.我们就用AT+CGSN:36,ED1察看一下,返回结果是:
取消选项:
F:\sinmens\tools>siemtest /36,ed1
AT+CGSN:36,ed1
+CGSN: DD
FB 9F FB FF FE 53 69 65 6D 65 6E 73 20 36 36 38

选中选项:
+CGSN: DD
FF 9F FB FF FE 53 69 65 6D 65 6E 73 20 36 36 38

这就证明了我们的猜测.得到GetLightStat的地址为D9EB4E.
接着我们可以改写我们的Patch,修改如下位置:
seg214:3808                 calls   0A2h, sub_A2F456 ->calls D9,EB4E :DAD94EEB      
seg214:380C                 cmp     r4, #5       ->cmp R4,#1   :4841
seg214:380E                 jmpr    cc_NZ, loc_D63818      

这样这个补丁就完成了,是不是很简单。当然,这是在知道了图标处理函数的前提下。接下来,我会讲一个复杂的程序

[此贴子已经被作者于2003-11-22 17:41:42编辑过]

 楼主| 发表于 2005-8-9 00:02:00 | 显示全部楼层
五、图形菜单的例子
这个程序就是图形菜单吧!我本不想说这个,因为不能完整的掌握它,是一种知其然而不知其所以然的状态。但想想,说一下我知道的,大家补充一下我不知道的,可能更完整吧!所以下面的不能算为教程,权当作一次讨论好了!

首先它需要更改待机时的键盘处理,使之在按右导航键或右软键进入图形菜单。这个可以看一下0x35E8F4这个函数,它是待机时刻的键盘处理函数。很多关于按键习惯的修改都是从这个函数入手。

下面进入到图形菜单的部分。他大概分为三部分。菜单的入口,菜单需要的的数据结构,回调函数。有点像windows的窗口管理,首先用数据结构注册类(包括窗口回调函数),主程序进入到消息循环,然后当消息来到后调用回调函数,进行消息处理。图形菜单主程序的反汇编如下:

//回调函数,用于键盘处理,调用时传入一个结构,offset:R14,page:R15。具体的内容不清楚。目前已知的如下:
offset:structA
00 ->?
02 ->键码
04 ->另一个结构structB的指针:offset
06 ->另一个结构structB的指针:page
offset:structB可能用以进一步判断按键的方式
06 ->字符码,如想增加对数字键的支持,则应处理此项内容。

27D500 : DC 4F             EXTP     R15,#1      
27D502 : D4 4E 02 00       MOV      R4,[R14+#0002H] ->取得键码,如为0则返回
27D506 : 2D 32             JMPR     CC_Z,006CH      
27D508 : D7 40 34 00       EXTP     #34H,#1     
27D50C : F2 FE 1C 3E       MOV      R14,3E2CH       ->取得当前图形序号
27D510 : 26 FE 6F 00       SUB      R14,#006FH      ->112(修改器中从1开始,Flash从0开始),减去图形首序号,取得菜单号
27D514 : 46 F4 20 00       CMP      R4,#0020H       ->上导航键,可增加长按和测+的处理
27D518 : 3D 02             JMPR     CC_NZ,001EH
27D51A : 08 E3             ADD      R14,#3
27D51C : 0D 11             JMPR     CC_UC,0040H
27D51E : 46 F4 21 00       CMP      R4,#0021H       ->下导航键,可增加长按和测-的处理
27D522 : 3D 02             JMPR     CC_NZ,0028H
27D524 : 28 E3             SUB      R14,#3
27D526 : 0D 0C             JMPR     CC_UC,0040H
27D528 : 46 F4 22 00       CMP      R4,#0022H       ->右导航键
27D52C : 3D 02             JMPR     CC_NZ,0032H
27D52E : 08 E1             ADD      R14,#1
27D530 : 0D 07             JMPR     CC_UC,0040H
27D532 : 46 F4 23 00       CMP      R4,#0023H       ->左导航键
27D536 : 3D 02             JMPR     CC_NZ,003CH
27D538 : 28 E1             SUB      R14,#1
27D53A : 0D 02             JMPR     CC_UC,0040H
27D53C : 48 41             CMP      R4,#1       ->挂机键的处理
27D53E : 2D 62             JMPR     CC_Z,0104H
27D540 : 48 E0             CMP      R14,#0      ->比较菜单号是否超出0-11,并作相应的处理
27D542 : DD 02             JMPR     CC_SGE,0048H
27D544 : E0 BE             MOV      R14,#0BH    ->小于0
27D546 : 0D 04             JMPR     CC_UC,0050H
27D548 : 46 FE 0C 00       CMP      R14,#000CH      ->大于11
27D54C : CD 01             JMPR     CC_SLT,0050H
27D54E : E0 0E             MOV      R14,#00H
27D550 : 48 45             CMP      R4,#5       ->拨号键进入菜单项
27D552 : 2D 0F             JMPR     CC_Z,0072H
27D554 : 48 43             CMP      R4,#3       ->右软键进入菜单项
27D556 : 2D 0D             JMPR     CC_Z,0072H
27D558 : 06 FE 6F 00       ADD      R14,#006FH      ->生成图形ID
27D55C : D7 40 34 00       Invalid Opcode#34H,#1    ->保存当前图形
27D560 : F6 FE 1C 3E       MOV      3E2CH,R14   
27D564 : E0 0C             MOV      R12,#00H
27D566 : E0 0D             MOV      R13,#00H
27D568 : DA C1 EC 22       CALLS    13DF04      ->显示图形,这个函数前面已经介绍
27D56C : E6 F4 FF FF       MOV      R4,#0FFFFH      ->返回-1
27D570 : DB 00             RETS     
//进入下级菜单项
27D572 : F0 4E             MOV      R4,R14      ->取得菜单号
27D574 : 5C 14             SHL      R4,#01H     ->菜单号乘3取得入口地址的偏移量
27D576 : 00 E4             ADD      R14,R4      
27D578 : 06 FE DC 14       ADD      R14,#14DCH      ->加上基地址,取得offset
27D57C : E0 05             MOV      R5,#00H     ->R5清零  
27D57E : D7 60 1F 03       EXTP     #031FH      ->菜单项的页地址,基地址为0x27D4DC。
27D582 : 99 8E             MOVB     RL4,[R14+]      ->按先低后高的字节序取得地址
27D584 : 99 9E             MOVB     RH4,[R14+]      ->offset:R4
27D586 : 99 AE             MOVB     RL5,[R14+]      ->page:R5
27D588 : 2D F1             JMPR     CC_Z,006CH      ->为零则错误
27D58A : DA C7 88 EE       CALLS    27EE88      ->执行菜单项。此函数只是把offset和page压入系统栈中,然后返回,则系统跳到栈顶地址执行。
27D58E : 0D EE             JMPR     CC_UC,006CH ->返回
27D590 : 00 00 00 00            
27D594 : 00 D5 C7 00       //0x27D500,注册回调      
27D598 : 00 00 00 00            
27D59C : 36 E6 F3 00       //F3E636 -> ret ->{return;}
27D5A0 : A8 3F 43 03        //?指向一个数据结构,功能未知
27D5A4 : 28 16 1F 03       //0x27D628        
27D5A8 : 00 00 00 00            
27D5AC : 65 00 50 00       //菜单窗口大小65hx50h ->101x80
27D5B0 : 2C 3E 34 00       //全局变量,Page:34 offset:3E2C;存放菜单项,从子菜单返回时使用      
27D5B4 : 00 00 00 00            
27D5B8 : 00 00 FF 00            
27D5BC : 00 00 00 00            

//菜单住函数入口
27D5C0 : E6 F4 6F 00       MOV      R4,#006FH
27D5C4 : D7 40 34 00       EXTSR    #34H,#1
27D5C8 : F6 F4 1C 3E       MOV      3E2CH,R4    //如果是第一次进入图形菜单,则指向第一项
27D5CC : 88 90             MOV      [-R0],R9    //保存R8,R9(通用寄存器)
27D5CE : 88 80             MOV      [-R0],R8
27D5D0 : E6 FC 5A F5       MOV      R12,#0898CH //这个我不清楚,在每个菜单入口都会有这个动作   
27D5D4 : E6 FD D8 00       MOV      R13,#00D3H //可能是一个初始化的动作
27D5D8 : E6 FE 96 F5       MOV      R14,#089C8H
27D5DC : F0 FD             MOV      R15,R13
27D5DE : DA F0 3C FD       CALLS    427D4E   
27D5E2 : F0 84             MOV      R8,R4      
27D5E4 : F0 95             MOV      R9,R5
27D5E6 : F0 C8             MOV      R12,R8
27D5E8 : F0 D9             MOV      R13,R9
27D5EA : E6 FE 90 15       MOV      R14,#1590H      //地址0x27D590存放菜单的数据结构
27D5EE : E6 FF 1F 03       MOV      R15,#031FH      //注册菜单的相关信息,包括键盘处理,或图标处理
27D5F2 : DA F0 24 FF       CALLS    427F36   
27D5F6 : F0 C8             MOV      R12,R8
27D5F8 : F0 D9             MOV      R13,R9
27D602 : DA F0 9E 80       CALLS    53EA82      //?功能未知   
27D606 : 98 80             MOV      R8,[R0+]
27D608 : 98 90             MOV      R9,[R0+]
27D60A : DB 00             RETS
27D60C : E0 04             MOV      R4,#00H     //?不明白
27D60E : DB 00             RETS  
27D610 : 03 00 03 00
27D614 : FF FF 00 00   
27D618 : 00 00 FF FF           
27D61C : 00 00 00 00  
27D620 : FF FF 05 00  
27D624 : 05 00 FF FF   
27D628 : 10 16 1F 03   ->?未知
27D62C : 01 00 FF FF  
27D630 : 00 00         

//存放子菜单函数入口地址
0x27D4DC : 9A 46 D3 ... Organiser      
0x27D4DF : 66 46 D3 ... Message
0x27D4E2 : AA 46 D3 ... Surf/Fun
0x27D4E5 : CA 46 D3 ... Audio
0x27D4E8 : 7A 46 D3 ... Record
0x27D4EB : 8A 46 D3 ... Setup
0x27D4EE : D4 9F D3 ... WriteMessage
0x27D4F1 : 98 73 D3 ... Java
0x27D4F4 : A8 73 D3 ... MP3Player
0x27D4F7 : BE 73 D3 ... Games
0x27D4FA : EC 9C D6 ... Calendar
0x27D4FD : AE 73 D3 ... Card-Explorer

从上面的注释大家应该可以初步的了解图形菜单的运作,从上面可以看出建造一个菜单的简单过程。依此类推,可以做出带子菜单的图形菜单,所需的只是101x80的图片。这个可以更改固有图片的大小,并把它移到空闲的位置。则可以做出更多的菜单项。


六、我知道的一些函数
//C的库函数
c78360     memchr               
c78388     memcmp        
c783b4     memcpy        
c78416     strset        
c784a6     strcat        
c784cc     strchr        
c784ee     strcmp        

c78516     strcpy        
c78536     getlen     
c7854a     strcat_size
c78578     strcmp_size
c7859e     strcpy_size  
c785cc     strrchr            
c785f0     strcspn      
//其他
A50360     GETWEEK
A509F2     GETDATA_SLIK
A50B34     GETTIME
B362A8     LIGHTONLITTLEMINUTES
B4DF04     DRAWIMAGEBYINDEX
B50C58     BATTLEPROCESS
D58CCE     NETMONETORMENU
D50296     SMSARCHIVE
D5E8F4     IDLE_KEY_SWITCH
D637C8     IDLE_ICON_PROCESS
D6BFF6     MP3_KEY_SWITCH
D75764     GETDATA_SLCK
E4B0D4     输入法图标处理




[此贴子已经被作者于2003-11-22 17:44:35编辑过]

发表于 2005-8-9 00:03:00 | 显示全部楼层
这篇文章应该置顶的,因为很多人找的,升级论坛又连续崩溃了两次了,以后找点东西多难咯~

西门子Flash修改入门中使用到的相关工具下载
V_Klay2.1.5英文版
ksie 2_full
adis16x
IDA
bin_copy
fbytes
fmenu
C166 Compiler
C166 JMP
fcool_Image
LanguageEditor
55版语言文件
CHAOS的AT+命令调试补丁和SL456688i的AT命令控制台
VKP包和AT命令测试器
80C166处理器手册
汇编指令手册
借个地方一用,希望不要生气!

发表于 2005-8-9 00:04:00 | 显示全部楼层
好好学一下,谢谢狼大!
发表于 2005-8-9 00:05:00 | 显示全部楼层
珍贵的资料
象我这样的菜鸟也要装懂研究一下
发表于 2005-8-9 00:06:00 | 显示全部楼层
我保存到硬盘上了!!
发表于 2005-8-9 00:07:00 | 显示全部楼层
不知道那些软件到哪里下载啊??我在baidu上用那些软件的名字做关键字搜索,结果搜索到的是这篇帖子,晕~~
发表于 2005-8-9 00:08:00 | 显示全部楼层
狼大有空的话,希望能再出一些内容,一年级的毕业了 :)
究竟我这等汇编外行还要借助你的资料才能看懂一些补丁内容。
发表于 2005-8-9 00:09:00 | 显示全部楼层
能提供上述所需软件下载吗?
发表于 2005-8-9 00:10:00 | 显示全部楼层
c166指令说明(英文)
http://yeman.snqindu.gov.cn/6688/jiaocheng/m166ism.htm
发表于 2005-8-9 00:11:00 | 显示全部楼层
不错.我可要研究一下.谢谢了!
发表于 2005-8-9 00:12:00 | 显示全部楼层
大师,能不能修改出使小3/小6支持java的flash版本呢?
没见你回我的帖子“激活x618的JAVA-请cool_lang大师解疑”,大概是您太忙了吧
发表于 2005-8-9 00:13:00 | 显示全部楼层
唉~~狼大
就是狼大
我一定好好学习
发表于 2005-8-9 00:14:00 | 显示全部楼层
顶狼大
发表于 2005-8-9 00:15:00 | 显示全部楼层
学习
发表于 2005-8-9 00:16:00 | 显示全部楼层
太高深了~ 学习学习再学习!
发表于 2005-8-9 00:17:00 | 显示全部楼层
我也要学!呵呵~
发表于 2005-8-9 00:18:00 | 显示全部楼层
好好学习!天天向上!
 楼主| 发表于 2005-8-9 00:19:00 | 显示全部楼层
aiyong888,你的头衔太搞笑了!
您需要登录后才可以回帖 登录 | 注册会员 微信登录

本版积分规则

小黑屋|Archiver|手机版|爱技术 ( 沪ICP备08115260号-3 )

GMT+8, 2024-5-19 21:23

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表