【专题文章】西门子Flash修改入门
主题:西门子手机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 )。这些工具都很有用,比如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= Unused block? 不用的Block
F0= Deleted block?删除的Block
FC= Used block? 当前有效的Block
01 BYTE Version.
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 ???
Always zero in EEFULL & EELITE blocks.
Always 02 in LBA_FS & EE_FS blocks.
0B BYTE Record ending marker
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 - A00000H5FF974
47 00Block ID 0047H , 0047H = 71
00 在EELITE 中为 0
FC结束标志。
4、寄存器的习惯用法
在Flash程序中,一些寄存器有固定的习惯用法。R12,R13,R14,R15作为传入参数,而R4和R5作为传出参数,R0被用为系统栈。例如下面的指令:
Mov [-R0],R6
.......
Mov R6,
就是一次常见的压栈过程。下面是一个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编辑过]
三、常见工具的基本用法。
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 , 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 , 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 , 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, //出栈
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,
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, //恢复R8,R9
seg214:3B6E mov r9,
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,
seg215:738E mov r12,
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,
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编辑过]
五、图形菜单的例子
这个程序就是图形菜单吧!我本不想说这个,因为不能完整的掌握它,是一种知其然而不知其所以然的状态。但想想,说一下我知道的,大家补充一下我不知道的,可能更完整吧!所以下面的不能算为教程,权当作一次讨论好了!
首先它需要更改待机时的键盘处理,使之在按右导航键或右软键进入图形菜单。这个可以看一下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, ->取得键码,如为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, ->按先低后高的字节序取得地址
27D584 : 99 9E MOVB RH4, ->offset:R4
27D586 : 99 AE MOVB RL5, ->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,
27D608 : 98 90 MOV R9,
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编辑过]
这篇文章应该置顶的,因为很多人找的,升级论坛又连续崩溃了两次了,以后找点东西多难咯~
西门子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处理器手册
汇编指令手册
借个地方一用,希望不要生气!
好好学一下,谢谢狼大! 珍贵的资料
象我这样的菜鸟也要装懂研究一下
我保存到硬盘上了!! 不知道那些软件到哪里下载啊??我在baidu上用那些软件的名字做关键字搜索,结果搜索到的是这篇帖子,晕~~ 狼大有空的话,希望能再出一些内容,一年级的毕业了 :)
究竟我这等汇编外行还要借助你的资料才能看懂一些补丁内容。 能提供上述所需软件下载吗? c166指令说明(英文)
http://yeman.snqindu.gov.cn/6688/jiaocheng/m166ism.htm 不错.我可要研究一下.谢谢了! 大师,能不能修改出使小3/小6支持java的flash版本呢?
没见你回我的帖子“激活x618的JAVA-请cool_lang大师解疑”,大概是您太忙了吧 唉~~狼大
就是狼大
我一定好好学习 顶狼大 学习 太高深了~ 学习学习再学习! 我也要学!呵呵~ 好好学习!天天向上! aiyong888,你的头衔太搞笑了!