- 积分
- 145
- 实力分
- 点
- 金钱数
- 两
- 技术分
- 分
- 贡献分
- 分
|
发表于 2005-8-18 16:03:26
|
显示全部楼层
关于Patch技术的一些文章汇总
这里只整理了部分关于patch开发的文章,更多文章请去 SPGC 和 6688 论坛查找!
目录:
1、[借花献佛]如何找菜单里面对应的功能地址 作者:comman_kang
2、自行定做将菜单隐藏的补丁 作者:huajia
3、图片索引修改的若干问题&待机动画补丁制作示范, 作者:llhn
4、【专题文章】西门子Flash修改入门 作者:coollang
5、如何用UltraEdit构建Patch开发环境 作者:coollang
6、修改IDA程序以适合中文C166 作者:coollang
7、【专题文章】关于电压调整(补充) 作者:coollang
8、【Patch专题】如何在手机中收集有用的信息 作者:coollang
9、【专题文章】手机中的窗体 作者:coollang
10、[原创]用来在IDA中Patch的IDC文件 作者:coollang
;*****************************************************************
1、[借花献佛]如何找菜单里面对应的功能地址
作者:comman_kang
http://bbs.dbsjw.com/dispbbs.asp?boardid=38&id=1160
这是印尼的 RizaPN 大师提供的文章,我只是提供一个中文的对应版本,用到的工具也是他老人家写的
我们做图形菜单时候很需要找到原来菜单对应的函数入口,找函数的方法如下:
首先把你的手机设置成英文的,原因是因为我们只能看得清楚英文的语言资源
然后我以寻找短消息菜单的各个入口为例来讲解
首先看看短消息菜单里面都有什么
New SMS
SMS Signature
Predefined Text
Inbox
Outbox
Voice Message
Cell Broadcast
Message Setup
这些菜单的内容,是通过存储在 flash 里面的菜单数据结构来决定的,每个菜单项的标题都是一个特定的字符串,这个字符串在手机的程序里面是用一个整数的标志符(id)来表示的,而每个菜单项占用的空间是相同的,每个菜单项占用18个字节。如果知道了菜单标题对应的标识符,就可以搜索两条相邻菜单项的标识符来找到菜单结构所在的位置。
俄国人 skylord 作了一个工具,可以从手机的flash 里面取出字符串和其对应标识符的内容,这个工具只能在英文 98 下面用,所以我把弄好了的文件直接传上来,大家就不用再去找ewin98了。
1.lgp::
[upload=rar]viewfile.asp?ID=784[/upload]
这个文件是一个unicode格式的文件,你需要使用支持unicode格式的编辑器来打开它,比如 ultraedit 和 word, 打开以后我们可以看到很多这样的行
LangId 0
String $0, "<91>+List"
String $1, "<95>1 hour"
String $2, "<95>1 day"
String $3, "<95>12 hours"
String $4, "<95>Cancel"
String $5, "<95>Outgoing access"
其中 string $ 后面跟的数字就是这一行里面字符串对应的标识 id
例如 2 对应的是 "1 day" <95> 是格式符可以不用理会
我们在这里面寻找短信菜单中两条相邻菜单项的id, New SMS 和 SMS Signature
结果如下:
有 4 个 id 对应 New SMS , 18e,18f,4f5, 781
有 1 个 id 对应 SMS Signature c43
我们需要在整个 8M flash 寻找对应的菜单项,RizaPN 写了一个工具 fmenu.exe
来简化这个寻找工作
fmenu.exe:
[upload=rar]viewfile.asp?ID=785[/upload]
这是一个命令行的程序,使用方法如下:
fmenu.exe fullflash.bin id1,id2,id3....
第一个参数是你的完整 8M flash备份, 可以用 V_Klay 读出来
后面就是相邻菜单字串 id 的序列了,中间用逗号隔开
因为有多个 id 对应 New SMS 这个字串,
所以我们挨个试验:
fmenu block_00.bin 18e,c43
输出
Found index at address 03AB44
- menu items address : 83AA94
- subroutine address : 83AA74
- number of item : 8 (decimal)
1. 0000 0000 018E 04F5 0000 3794 0283 0003 00D0 => 83AA74: Goto_E0BCDE
2. 0000 0000 0C43 0C43 0000 3794 0283 0003 0559 => 83AA78: Goto_E0BD4A
3. 0000 0000 0236 0235 0000 3794 0283 0003 0559 => 83AA7C: Goto_E0BD52
4. 0000 0000 00B9 04FA 0000 3794 0283 0003 00CB => 83AA80: Goto_E0C0FE
5. 0000 0000 006A 04FB 0000 3794 0283 0003 00CB => 83AA84: Goto_E0C294
6. 0000 0000 01F9 01F8 0000 3794 0283 0003 00E3 => 83AA88: Goto_E0BF54
7. 0000 0000 0098 0097 0000 3794 0283 0003 00E0 => 83AA8C: Goto_E0BF62
8. 0000 0000 04F9 051B 0000 3794 0283 0003 00D9 => 83AA90: Goto_E0C2B8
看来我们运气不错,第一个尝试就找到了,会不会是错误识别呢?
我们来验证一下,注意输出结果的第三列,前两个数就是我们刚才查找的菜单项字串 id
以此类推,后面的应该也是,因此我们在 1.lgp 中寻找第三行的 236 号字串,
String $236, "<95>Predefined text"
就是第三条菜单项的标题,应该说问题不大了,如果你不放心可以继续把后面的都验证一边。
程序输出的最后一列是形如 Goto_XXXXXX 的东西,这个是什么?这个就是我们需要的功能入口地址,赶紧抄下来吧,每一条对应一个菜单项。比如写新短消息的地址就是 E0BCDE 了。
由于西门子手机的 cpu 和 intel pc 的 cpu 一样,都采用 little endian 的字节序,因此在制作 patch 的时候,需要把这个地址两两倒过来输入 patch 里面,例如写新短消息的地址可能需要按照E0DEBC的格式输入。当然,有些图形化的菜单编辑器里面已经做了处理,因此你在编辑这些软件的配置文件增加地址的时候,可以按照原来的格式输入,不用倒过来。
*********************************************************
X618带中文的语言文件(huajia提供)
大家可以使用这个文件,就不再用把手机的语言设为E文了。
以下为X618的语言文件,包括英文、简体中文和语言文件2,方便大家查找字串。
下载:[upload=rar]viewfile.asp?ID=8871[/upload]
字串的使用方法:
String $XYZ--XYZ即为字串的编号,调用是的方法是XYZ -> YZ0X(是零,不是欧)。
比如:String $4, "取消",调用时用0400
String $10, "通讯录",调用时用1000
String $112, "主菜单",调用时用1201
;*****************************************************************
2、自行定做将菜单隐藏的补丁
作者:huajia
http://bbs.dbsjw.com/dispbbs.asp ... 25&star=1#11225
自从我发布了“隐藏SIM卡应用菜单”的补丁后,总有机友要求将某个菜单隐藏。为了使机友能够自己做出补丁将需要的菜单隐藏,现将具体方法公布如下:
1、在我公布的“X618菜单项的入口地址和字串”找到所需的字串;
2、用UltraEdit32等软件打开Flash.bin文件,在查找栏内按规定的格式填入字串(小字符-大字符);
3、找到地址后,向后数8个字符的地方就找到了控制菜单隐藏和打开的函数(一般前面的字符是0300);
4、将找到的字符替换成4405即可隐藏菜单了。
比如:
“功夫小子”: 其字串在“X618菜单项的入口地址和字串”的帖子中为小字符(0532)、大字符(0533),将其颠倒过来即为“32053305”,然后用“32053305”在Flash.bin文件中查找,找到地址后向后数8个字符就找到了控制菜单隐藏和打开的函数“3705“,最后按刷补丁的格式,即:0x1CDF16: 3705 4405, 将其刷入手机就行了。
特别说明:以上的方法仅适用于主菜单项下的各子菜单。
另外,无SIM卡时隐藏菜单的控制函数是C504,通话时隐藏菜单的控制函数是3905,隐藏常用功能和数字快捷键中的条目的控制函数为1405
例:隐藏数字快捷键中的收件箱
0x1CACB8: CC00 1405
0x1cacca: CD00 1405
隐藏菜单中的条目
0x1CC54C: C504 4405 ;隐藏上网与娱乐-文件管理器
0x1CC55E: 5905 4405 ;隐藏上网与娱乐-图片管理器
0x1CC570: 5905 4405 ;隐藏上网与娱乐-音调管理器
0x1C8976: 5905 4405 ;隐藏音调设定-音调-音调管理器
0x1Cd82a: 5905 4405 ;隐藏个人设置菜单
0x1CC516: B004 4405 ;隐藏游戏
0x03ABF4: C900 4405 ;隐藏收发件箱中的SMS文件夹
附:
X618的菜单资料:
附件为X618的菜单资料,是作flash修改和查找菜单函数地址的重要资料。
[upload=rar]viewfile.asp?ID=5600[/upload]
3、图片索引修改的若干问题&待机动画补丁制作示范
作者:llhn
http://bbs.dbsjw.com/dispbbs.asp?boardID=38&ID=41921
经常有机油问起如何更改图片索引,有些新手也不太明白索引和图片的含义到底是什么,早前曾答应过要写一篇文章谈谈这个,这次就借待机动画的制作来谈谈这个问题。废话少说,开始正题。
一、索引是什么?索引和图片数据有什么关系?
关于图片有两个概念:一是索引,二是图片数据。
在手机程序中,想要使用某一个图片,只要知道该图片号就行了;那么如何通过该图片号来找到该图片的数据呢?这就需要索引来实现。有多少个图片,就有多少条图片索引,一一对应,每条图片索引包括:图片高度、图片宽度和图片数据在内存中的地址。
以狼大的CoolImage来说明,如图,选中某一图片,点M图标,弹出修改索引对话框,表明第297号图片高96宽66,数据存放于 2B214E 开始的一段内存空间里。
[upload=jpg]UploadFile/2004-7/200477182918365.jpg[/upload]
二、为什么要修改索引?如何修改?
举例来说,待机动画的大小是101*45,使用图片312--323,而这些图片大小只有49*19,怎么办?只将大小改为101*45行么?显然不行,因为101*45的图片数据要大于49*19的图片数据,也就是说原来的图片数据空间放不下新的图片了。所以还要改图片数据的地址,我们在内存中找到一块空白的空间,将新的图片数据放在这儿,这样新的索引就会指向新的图片数据,虽然原来的图片数据还在那儿不变。
如何修改?还来看待机动画:
1)我们首先将312号图片索引改为101*45,地址为2D3100,点确定,看下图,CoolImage右边上方的图片变为101*45,全黑,这是因为新的地址2D3100之后的一段数据全为FFFF;
2)然后将101*45的图片导入,右边下方则显示出你导近来的图片,只不过是反色的,单击它可变为正常的。
3)点保存,则CoolImage导出一个vkp文件,打开此文件,我们来看看,如下图。它包括两部分:索引的修改和图片数据的修改。
Tips:若修改后的图片大小小于原有图片大小,则地址可不用修改。CoolImage会自动修改原有图片的数据。
[upload=jpg]UploadFile/2004-7/20047718292580.jpg[/upload]
[upload=jpg]UploadFile/2004-7/200477182937238.jpg[/upload]
三、实例:待机动画的制作
以小猪背小猪4帧动画为例:
1)用CoolImage导入一个干净的没打过补丁的Fullflash(以保证新的地址处没有数据,全是FF)
2)修改图片索引(新图片的地址我已经在模版中订好了)
3)导入图片
4)保存为vkp
5)在得到的vkp文件中加入 修改动画待机程序的参数设置。
[upload=jpg]UploadFile/2004-7/200477182944718.jpg[/upload]
;*****************************************************************
4、【专题文章】西门子Flash修改入门
作者:coollang
http://bbs.dbsjw.com/dispbbs.asp?BoardID=35&ID=4809
文中提到的相关软件请去以上地址的帖子第4楼下载!
主题:西门子手机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?br> 例如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的栈.
三、常见工具的基本用法。
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, "<95>Calls<0D>missed"
String 349, "<95>Calls missed"
String 350, "<95>C.missed"
String 351, "<91>Job is completed!"
String 352, "<95>Alarms<0D>missed"
String 353, "<95>Alarms missed"
String 354, "<91>The stock market is going up."
......
其中<X>表示不能显示的字符,比如<0D>是回车。前面的就是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_Icontch:
seg214:37C8 mov [-r0], r9 //保存旧址
seg214:37CA mov [-r0], r8
seg214:37CC sub r0, #0Ch //处理栈顶指针
seg214:37D0 calls 0DCh, Signal_Icontch //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
这样这个补丁就完成了,是不是很简单。当然,这是在知道了图标处理函数的前提下。接下来,我会讲一个复杂的程序
五、图形菜单的例子
这个程序就是图形菜单吧!我本不想说这个,因为不能完整的掌握它,是一种知其然而不知其所以然的状态。但想想,说一下我知道的,大家补充一下我不知道的,可能更完整吧!所以下面的不能算为教程,权当作一次讨论好了!
首先它需要更改待机时的键盘处理,使之在按右导航键或右软键进入图形菜单。这个可以看一下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_KEYTCH
D637C8 IDLE_ICON_PROCESS
D6BFF6 MP3_KEYTCH
D75764 GETDATA_SLCK
E4B0D4 输入法图标处理
;*****************************************************************
5、如何用UltraEdit构建Patch开发环境
作者:coollang
http://bbs.dbsjw.com/dispbbs.asp?BoardID=43&ID=16254
文中提到的相关软件请去该贴2楼下载!
前两天我发上来过KeilC166的汇编器和链接器,以及一个Hex2Vkp的东西。但是这些只能在命令行执行。
现在我给出一个用UltraEdit构建集成开发环境的方法。唯一的遗憾就是不能进行调试(Tasking和Keil可以)
1、把我发上来的压缩包解压缩。并保证其相对目录的完整性,是为了是Licence生效。
2、把压缩包里wordfile.txt拷贝到UltraEdit的对应目录,以后可以实现a66文件的关键字高亮显示。
3、打开UltraEdit,Advanced-ToolConfig,然后作如下配置,%F表示文件全名(带路径),
%P表示文件路径。Command Output选择Output to ListBox,并选中Capture Output。
然后给工具命名为Compile(编译),也可以增加一个图标,如图:
此主题相关图片如下:
这个主要是编译源文件,来发现语法错误。编译结果再下面显示。错误信息在xxxx.LST文件中。
4、增加Build工具,如上图,其他不变,命令行如下:E:\Keil\C166\BIN\A.BAT %P%N
%N表示没有后缀的文件名。也可以增加类似的图标。如图
此主题相关图片如下:
5、在工具栏右击,选择Customize。然后从Advanced中拖对应的tool1和tool2放在工具栏中,如图:
此主题相关图片如下:
6、完成后打开一个汇编文件,先选择Compile如果无错误,则可以选择Build生成Vkp。否则打开对应
目录下的LST文件查看错误。
此主题相关图片如下:
至此,一个方便快捷的集成开发环境已经生成。
;*****************************************************************
6、修改IDA程序以适合中文C166
作者:coollang
http://bbs.dbsjw.com/dispbbs.asp?BoardID=43&ID=5564
大家都用IDA程序来反汇编FuBu,但是IDA在中文下工作的时候有一些问题,比如一些分隔符会显示成这样:
"哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪"
而且他的地址显示格式只能是seg185:ABCD或AB000:ABCD这样子,看着很不爽。
下面的补丁可以更改分割符的显示格式为下面的格式:
0x0D1:9E58 ; ☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆
0x0D1:9E58 ; ★★★★★★★★ S U B R O U T I N E ★★★★★★★★★★★★★★★★★★★
当然也可以用V_KLAY来修改,不过要选择写到文件ida.wll(在IDA的目录下),开始地址为0。
目前的bug:只能输入大写字母,小写会跳转出错!
003CC9: 4B68CD00 4C68A1FE ;1AFE是〓,这个是每Page的分割
003CE0: E7 E8
004BC8: 4B68C400 4C68A1EE ;A1EE是☆
004BDF: E7 E8
004BF9: 4B68DB00 4C68A1EF ;A1EF是★
004C0A: AB AC
004C23: C0DB C120
004C27: E7 E8
0155F4: 8A 8B
0155FD: 8AE0 9090
;下面这句是更改seg123为0x0AB这种形式
0CF27C: 73656725303364 30782530335800
;*****************************************************************
7、【专题文章】关于电压调整(补充)
作者:coollang
http://bbs.dbsjw.com/dispbbs.asp ... mp;star=1&skin=
主题:关于电压调整
作者:Cool_Lang
摘要:
本文讲述了了西门子手机内部电压处理和电压参数的关系,
--------------------------------------------------------------------------------
文中有些公式,是因为我是数学系出身,大家不喜欢可以不看。
这个话题讨论的比较多,因为以前没有研究过电池问题,所以也没写什么文章。不过之前看程序看到了处理电压参数的部分。所以写了一个调整电压参数的程序,劣诟�畹亩�鳎�恢泵皇奔淇础O衷诰桶盐抑�赖暮偷绮斡泄氐亩�餍匆幌拢�┐蠹也慰肌?br>
一、电压问题的由来
在52版以前,升级是使用winswup程序的,这个程序是西门子的官方程序,他在升级过程中只写入Flash的部分。并不更改EEP,所以不会有电压的问题,但在54版以后,因为没有这种升级程序,而且54和55版式应该属于测试版,所以低版本直升不能激活Java,当时的做法是写入别人的EEP(此EEP在初始化的部分Block5005可以激活Java),然后再作MAP,这个过程中,自己的一些唯一性的东西已经丢失,而且再也找不回了。很快,这种升级的弊病就体现出来,那就是电压显示不准确,满电关机,待机时间减少等。于是机友从DarkBear的程序出发,自发的通过调整Block67的各项参数来解决这个问题,但在调整的过程中,对参数的意义认识得并不准确,所谓的参数意义都是基于经验的估计。但在方向上还是可取的。比如对0000和0004的调整规律上的认识。起码对参数和电压的升降关系是正确的。但其中有很也有很多的错误。
二、电压的参数意义是什么。
电池属于一种模拟量输出设备,而手机的系统是一个数字化的系统,只能处理数字量。那么手机要对电池进行各种处理必然有一个模数转换的问题。要用到模数A/D转换器。所有的电子元件都有一个误差范围,不同的只是精确度。而每一批元件都有自己特性。但A/D转换器在一定的范围上可以认为是满足线性的。所以必须确定这个线性的参量。如何确定一条直线?答案是用两个点。而手机的电压参数正是这两个点(A0,V0)和(A1,V1)。下面说每一个一下参数的具体意义(主要是前四个参数,后面主要是和温度有关)。
0000(SpgY03V):A1,V1所对应的A/D转换器的取样值
0002(SpgX0):V0,参考点0的电压值。
0004(SpgY04V):A0,参考点0的A/D转换器的取样值。
0006(SpgDelta):V0-V1,V0-V1的差值Delta。
那么对于任意的取样点(Ax,Vx)-〉(VBattDSP,VB)则有线性关系。
(Vx-V0)/(Ax-A0)=(V0-V1)/(A0-A1)成立。
化简之有: Vx = V0+(V0-V1)*(Ax-A0)/(A0-A1)
即 VB= SpgX0 - SpgDelta*(VBattDSP - SpgY04V)/(SpgY03V - SpgY04V)
图一(在图上蓝线表示标准电压直线,此线上A/D值对应的就是实际电压。而紫线是调整之后的电压线)。
此主题相关图片如下:
从上面的式子我们可以看出我可以任取两点来确定这个线性关系,如图一。这也是我的校准程序的做法。下面我说一下在这个式子中各个参数对真实电压的影响。
图二
此主题相关图片如下:
先说一下现在争论很大0006也就是SpgDelta,大家认为减小它可以增加待机时间,是这样的。因为减小SpgDelta,整个直线的斜率减小,而截距不变所带来的后果就是直线趋缓。现象是在SpgX0以下的电压会比实际值高,而以上部分会比实际值低。这样的好处是明显的,手机可以获得更长的待机时间。但弊病则很隐蔽,首先电池会有损伤,其次因为虽然操作系统受到了欺骗可以工作,但某些元件必须工作在一定的电压范围内,脱离了这个范围可能造成不能正常工作。如图二
图三
此主题相关图片如下:
接着是0002处即SpgX0,这个值的含义是确定参数时的一个电压取样点,为了使参数更准确,取样时采用了差别比较大的两个点。大体上SpgX0在4200左右,而SpgDelta在1000左右(手机A/D的正常工作范围是1.33V-5.91V)。而3.2V这个值是比较特殊的,在它以下系统会用涓流充电(Tricle Charge),这个值没有特别的意义。担当其它的参数都固定后,调整它一样可以改变直线的截距。比如减小这个值,那么系统电压就会比实际的电压低,在图上可以看出,实际4.2V的A/D值所对应的电压低于4.2,而3.6V也相同。增大则相反。所以它对关机电压和满电电压有同样的影响。如图三。
图四
此主题相关图片如下:
0004处即SpgY04V,这个值是电压为SpgX0时的A/D取样值。需要注意的是应把它作为有符号数处理,所以它为负值,增大它相当于减小其绝对值,即从负方向向原点移动。如果确定其他参数只对它进行调整,比如减小。那么其远离原点。从图四上可看出,它的斜率减小。但是对于关机电压的影响较小,而对满电电压影响较大。实际4.2V的A/D值所对应的电压低于4.2,而3.6V的A/D值所得到的电压也偏低,但程度要比满电时小。
图五
此主题相关图片如下:
0000处即SpgY03V,这个值是电压为SpgX0-SpgDelta(大约为3.2V)时所对应的A/D取样值。和SpgY04V不同的是,固定其他参数改变它对满电的影响较小,而对关机电压影响较大。这些从图五上可以看出。
但最终的电压并不是简单得有一个A/D值算出来的,它是几个定时的取样点经过一定的处理。取出异样点,平稳化之后的值。此外,温度对这个电压处理也有一定影响。这个温度分为两种环境温度和电池内部温度。原厂的电池在内部有一个温敏电阻,可以通过中间的触点输出电池温度值。但这些都是在后面处理的过程中用到的。 ……待续
这些可以作为电压调整的一个补充,也算是对cbclcxlcb的争论得答复!新开一贴。
我说这个参数只是为了吓人,而且也看过你的说明,我想你并没有看懂这个公式!
他并不仅仅是为了使工模显示的更准确,那仅仅是我写的程序的功能。
这个公式的重要性是因为他是系统用来从AD计算你的电压值的公式。
我在关于电压调整里已经说过了,
00是A点的AD值,02是B点的电压值,04是B点的AD值,06是A点的电压和B点电压的查值。
他的原理就是两点确定一条直线,然后根据这条直线来确定某个AD值所对应的电压值。
那么你目前所有的东西都是使这条直线的斜率降低。我们可以来看一下你的电参:
(0000)0 (0002)4201 (0004) 62500 (0006)290
(0000)AD为0的话所对应的电压大概是4.100V。(正常情况)
(0004)AD为62500就是-3036(因为是有符号数)对应的电压大概是4.600V(正常情况)
我所说的正常情况是指的是我的参数,一个基本正常的参数。
(0000)5218(0002)4201 (0004) 64931 (0006)1004
如果取点的话。你的A和B点分别是A(-3000,4.201)B(0,3.911)
我的A和B点是A(-600,4.201)B(0, 4.100)B点是我计算得出。
那我们从图形上看一下:
此主题相关图片如下:
黑线是我的电压直线。(为了清晰,重了一条红线)
蓝线是你的电压直线。
你的目的就是为了使电压直线的斜率变小而已。
当然你也可以说我的只是理论,缺乏实践。但是在手机中,就是这样计算电压的。
**************************************************************
不好意思,图是随便画的,不是很清楚。
我在《关于电压调整》就说过,大幅调低0006无非是减小直线的斜率,使电压比实际值在关机时偏大,充电时偏小。这样可以获得更多的待机时间。
而你的作法并没有超出公式的范围,目的也是为了使曲线的斜率偏小,如果这样的话完全不必作这样一个吓人的电参。只需固定一点,如0000和0002,然后调04和06就可以。就是说你现在这个电参和直接调小0006并无分别。
你以前写过的调整电压的新方法根本没有超出公式的范围,因为公式就是系统的准则!
***************************************************************
下面是系统从AD值获得电压的程序,我做了以下注释,大家有兴趣的可以用AT来看一下对应的值!
0xB5:0F68 ADToVolate: ;R12是传入的AD值
0xB5:0F68
0xB5:0F68 mov DPP0, #0Fh
0xB5:0F6C nop
0xB5:0F6E mov r14, word_3E522-----;取得存放电压参数的Block67地址
0xB5:0F72 mov r15, word_3E524
0xB5:0F76 add r14, #4
0xB5:0F78 extp r15, #1------------------;取得参数0004
0xB5:0F7A mov r1, [r14]
0xB5:0F7C mov r4, r12
0xB5:0F7E sub r4, r1-----------------------;AD-P0004
0xB5:0F80 neg r4---------------------------;改变符号
0xB5:0F82 mov r1, word_3E522
0xB5:0F86 mov r2, word_3E524
0xB5:0F8A extp r2, #1
0xB5:0F8C mov r3, [r1+6]---------------;取得参数0006
0xB5:0F90 mul r4, r3----------------------;P0006*(-(AD-P0004))
0xB5:0F92 mov r5, MDH
0xB5:0F96 mov r4, MDL
0xB5:0F9A extp r2, #1
0xB5:0F9C mov r3, [r1]-------------------;取得参数0000
0xB5:0F9E extp r15, #1
0xB5:0FA0 mov r14, [r14]---------------;取得参数0004
0xB5:0FA2 sub r3, r14 ;P0000-P0004
0xB5:0FA4 mov r10, r3
0xB5:0FA6 ashr r10, #0Fh
0xB5:0FA8 mov r11, r10
0xB5:0FAA mov r10, r3
0xB5:0FAC calls 0C7h, DivR4R5byR10R11-----------;(P0006*(-(AD-P0004))/(P0000-P0004))
0xB5:0FB0 mov r12, r4
0xB5:0FB2 mov DPP0, #0Fh
0xB5:0FB6 mov r13, r5
0xB5:0FB8 mov r14, word_3E522
0xB5:0FBC mov r15, word_3E524
0xB5:0FC0 extp r15, #1
0xB5:0FC2 mov r1, [r14+2]----------------------------;取得参数0002
0xB5:0FC6 mov r2, r1
0xB5:0FC8 ashr r2, #0Fh
0xB5:0FCA add r12, r1
0xB5:0FCC addc r13, r2
0xB5:0FCE mov r4, r12------------------------------;P0002+(P0006*(-(AD-P0004))/(P0000-P0004))
0xB5:0FD0 rets---------------------------------------;作为返回的电压值
0xB5:0FD0 ; End of function ADToVolate
;*****************************************************************
8、【Patch专题】如何在手机中收集有用的信息
作者:coollang
http://bbs.dbsjw.com/dispbbs.asp?BoardID=43&ID=45115
在Patch中,一般的困惑就是,看到一段Flash,都是静态的内容,但如果做过Crack的都知道,需要加以动态调试才能深入了解软体的运行过程,可是西门子不会大方的送给我们开发板,那么只能自己想一些办法来。在Flash中,一般的如果是全局数据的话,我们可以看代码段或用AT指令看数据段。但如果是栈区的内容不同方法就无能为力了,此外还有函数的调用栈,这是使用的是系统栈。针对这个我写了两个小程序,一个是Dump一段连续内存,另一个是打印当前的调用栈,大家感兴趣的可以看一下!
;DumpMemory.asm
$Segmented
$Mod167
;Memory Function
Memchr EQU 0C78360h ;Finds characters in a buffer. R12 = Offset R13 = Page R14 = Char R15 = Size
Memcmp EQU 0C78388h ;[R0] = Size.
Memcpy_Src_LT_Dst EQU 0C77430h ;Memory copy. R4 = SrcOff R5 = SrcPag R10 = DstOff R11 = DstPag R3 = Size
Memcpy EQU 0C783DCh ;[r0] = size r12 = Dstoff r13 = Dstpag r14 = Srcoff r15 = Srcpag
;String Function
Strcat EQU 0C784A6h ;Append a string. r12 = Dstoff r13 = Dstpag r14 = Srcoff r15 = Srcpag
Strchr EQU 0C784CCh ;Find a character in a string. R12 = Offset R13 = Page R14 = Char
Strrchr EQU 0C785CCh ;Scan a string for the last occurrence of a character.
Strcmp EQU 0C784EEh ;Compare strings. r12 = Dstoff r13 = Dstpag r14 = Srcoff r15 = Srcpag
Strcmp_Size EQU 0C78578h ;Compare strings. [R0] = Size
Strcpy EQU 0C78516h ;Copy a string. r12 = Dstoff r13 = Dstpag r14 = Srcoff r15 = Srcpag
Strcpy_FillSize EQU 0C7859Eh ;Copy a string,Fill #FF1Ch. [R0] = Size
Strcspn EQU 0C785F0h ;Find a substring in a string.r12 = Setoff r13 = Setpag r14 = SubSrcoff r15 = SubSrcpag
Strset EQU 0C78416h ;Set characters of a string to a character.R12 = Offset R13 = Page R14 = Char R15 = Size
GetLength EQU 0C78536h ;R12 = Offset R13 = Page R4 = Length
;AT Function
SendATCommand EQU 0CC9DCCh ;Send reply string.
;Address for Patch Data
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 R14,R12 ;需要Dump内存的offset
MOV R15,R13 ;需要Dump内存的Page
MOV R12,#400H ;Dump的内存数量
MOV [-R0],R12
MOV R12,#1000H ;Dump到0c:1000,有大段空间(约A00),如果是多次Dump,需递增地址
MOV R13,#0CH
CALLS SEG(Memcpy),SOF(Memcpy)
ADD R0,#2
MOV R15,[R0+]
MOV R14,[R0+]
MOV R13,[R0+]
MOV R12,[R0+]
;///////////////////////////////////////
;ToDo,补充被修改的位置的指令
;///////////////////////////////////////
RETS
main endp
;-------------------------------------------------------------------------------;
Patch EndS
CHANGEBYTE Section Code Word At 0x35622A ; Start Patch at Patch_Address
CHANGE PROC FAR
CALLS SEG(Patch_address+0xA00000),SOF(Patch_address+0xA00000)
CHANGE ENDP
CHANGEBYTE ENDS
END
;***************************************************************************************************
;DumpCS.asm
$Segmented
$Mod167
;Address for Patch Data
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
mov [-r0],r12
mov [-r0],r13
mov [-r0],r14
mov [-r0],r15
mov r4,#8 ;Dump栈的深度
; cmp r12, #243h ;可能满足某种条件才Dump
; jmp CC_NZ, ProcEnd
mov r15, r4
mov r14, #1000h ;Dump到C:1000
PopProc:
pop r12
pop r13
extp #0Ch, #1
mov [r14],r12
add r14,#2
extp #0Ch, #1
mov [r14],r13
add r14,#2
mov [-r0],r12
mov [-r0],r13
sub r15,#1
jmp CC_NZ,PopProc
mov r15,r4
PushProc:
mov r13,[r0+]
mov r12,[r0+]
push r13
push r12
sub r15,#1
jmp CC_NZ,PushProc
ProcEnd:
mov r15,[r0+]
mov r14,[r0+]
mov r13,[r0+]
mov r12,[r0+]
; TODO
cmp r12, #1388h
rets
main endp
Patch EndS
END
;*****************************************************************
9、【专题文章】手机中的窗体
作者:coollang
http://bbs.dbsjw.com/dispbbs.asp?BoardID=43&ID=21884
手机中的窗体
(我的例子中的函数都是以6688V55的地址为准,其他机型请大家参照查找响应函数,函数肯能有所差别)
一、浅谈手机中的窗体机制
在西门子的手机中使用了消息驱动的窗体机制,非常类似于windows中的机制。因为我对其运行机制并不是完全了解,所以在这里只说一下我的了解。
在西门子的手机中一个窗体的基本元素有标题,图标,滚动条,菜单项(菜单项图标,类似于List的Image),软键(按钮?)这些元素在具体的窗体中并不是全部出现的。我的理解是有一个基本的窗体,而其他的各种窗体只不过是这个窗体的实例化时的结果。而窗体的行为也类似于用windows的WindowsProc函数,响应具体的事件(类似的也有一个消息驱动的机制,很抱歉,我不能全部了解),比如大家经常看到这样的形式:
mov [-r0], r9
mov [-r0], r8
mov r9, r13
mov r8, r12
extp r15, #1
mov r12, [r14+4]
cmp r12, #88h ; '?
jmpr cc_Z, loc_D52318
cmp r12, #90h ; '?
jmpr cc_Z, loc_D52318
cmp r12, #0F8h ; '?
jmpr cc_Z, loc_D522F0
cmp r12, #0F9h ; '?
jmpr cc_Z, loc_D5230A
jmpr cc_UC, loc_D52348
其实就是一个窗口函数的形式,而大家一般修改的按键响应我想只是OnKeyDown一样的函数。但是具体的消息定义我也不是很清楚。因为如此,我只总结一下我明白的东西,就当作是抛砖引玉,希望可以对大家有用!
二、一个基本的窗体
先说一个比较复杂的窗体,就是有标题,图标,滚动条,菜单的那种窗体,其实很多简单的窗体只是它的一个特列而已!主要是通过他来介绍一下常用的数据结构,为后面的理解作好准备。它涉及的主要函数有:
//创建窗体(需要注意的是int是16位整型,而所有指针都是32位的),需要注意的其他机型的
//函数可能和这个有所不同,但一般都有这两个结构参数。
int CreateMenu(int bBorder, int * ,int, wndFrame*, wndClass*, int*, int*, int*, int*)
//设置菜单项的信息,类似于windows的List控件的列表项自绘制函数,
//支持一个ImageList,而nImage则是序号,从0开始
int OnDrawMenuItem(int *, int *, int nImage)
//取得选中的菜单项的序号
int GetSelectMenuItem(struct MenuItem *)
//更新菜单项,这个函数会导致OnDrawMenuItem被调用,来更新菜单信息。
int UpdateMenuItem(struct MenuItem *)
//窗体的框架信息
struct wndFrame{
int unKnown_1;
int unKnown_2;
int ViewWidth; //窗体的视图区域宽度,比如菜单中可能只有中间一条是,类似于ClientRect
int ViewHeight; //窗体的视图区域高度
int *pImageID; //指向窗体图标序号的地址
int nTitleID; //菜单标题的字串ID
int EndMask; //通常7FFFh
}
typedef int (*MessgeFunction)(int *, int *); //回调函数指针
//窗口类信息
struct wndClass{
int * pUnknown_1;
MessgeFunction pOnkeyDown; //按键响应函数
int * pUnknown_2;
int * pUnknown_3;
KeyCodeInfo * pKeyCodeInfo; //窗体的软键信息
KeyDefOrder * pKeyDefOrder; //软键配置信息组
int nWndType; //窗体的类型信息
int nUnknown_4;
MessgeFunction OnMenuItemInit; //菜单项初始化函数,注意是函数指针,请参考C语言相关内容。
MenuItem * pMenuItemList; //菜单项结构列表
MessgeFunction *pItemSelectFunList; //菜单项被选中的函数
int nItemCount; //菜单项数量
}
//软键的虚键值信息
struct KeyCodeInfo{
KeyCodeDef * pKeyCodeDef; //软键定义列表
int nDefCount; //软键配置信息组的数量(有待商榷)
}
//软键的虚键值定义
struct KeyCodeDef
{
int nShortPressCode; //短按软键的键值
int nLongPressCode; //长按软键的键值
int nStringID; //软键显示的字串ID
}
//软键配置信息组
struct KeyDefOrder{
int nLeftKeyDefOrder; //左软键的配置信息,是在软键定义列表中的序号
int nRightKeyDefOrder; //右软键的配置信息,是在软键定义列表中的序号
}
//菜单项信息
struct MenuItem{
int * nImageList; //菜单的Image列表,以0结束
int nNormalStringID; //通常模式下的菜单字串ID
int nBigFontStrID; //大字符模式下的菜单字串ID
int nUnkown_1
int * KeyDefOrder; //菜单项被选择时软键的信息,比如选择框和帮助信息会在软键上有不同显示和虚键值。
int nType; //类型信息,细节未知
int nFlag; //标志,比如隐藏菜单就通过这个标志,系统由一个函数,用这个值作为参数来返回TRUE和FALSE信息。
}
具体的信息可以看Patch实例,用户配置菜单。因为程序过长,就不列出,有兴趣的可以看以前的帖子。
在那个程序中,主要实现的是函数有OnMenuItemInit,如下:
//菜单项初始化函数,R14是菜单项序号,开始于0
OnMenuItemInit proc far
mov r2, #0
cmp r14, #0
jmpr cc_Z, loc_EE
mov r2, r14
callr IsFlagTrue ;判断对应的标志位(一个Bit)是否为1
and r2, r1
jmpr cc_Z, loc_EC
mov r2, #1
jmpr cc_UC, loc_EE
loc_EC:
mov r2, #2
loc_EE:
mov [-r0], r2 ;设置ImageOrder
calls seg(SetMenu),sof(SetMenu) ;设置MenuItem
add r0, #2
rets
OnMenuItemInit endp
//标志判断函数
IsFlagTrue proc near
mov r1, #1
sub r2, #1
shl r1, r2
extp #42h, #1
mov r2, 3EFCh
ret
IsFlagTrue endp
//菜单响应函数
OnSelect proc far ; start main of patch
mov [-r0], r12
mov [-r0], r13
calls seg(GetSelectMenu),sof(GetSelectMenu) //判断被选中的菜单项Order
mov r2, r4
callr loc_F8
xor r2, r1
extp #0Eh, #1
mov 3A42h, r2 //更新数据,有意义的Action
mov r13, [r0+]
mov r12, [r0+]
jmps seg(UpdateMenu),sof(UpdateMenu) //更新菜单项信息,这里主要是图片
OnSelect endp
三、其他的窗体函数
前面我做过猜测,就是所有的窗体都是一个基本的函数创建出来,在我在解读FireWare的过程中,发现这样的函数是确实存在的,我就以6688为例说一下这些函数的关系。
A、)
以下的窗体虽然各有不同,但是他们都是由一个函数0xF3:E9FA CreateWnd(struct WndStruct*)创造的,再细分一下,又分成两类,有边框(一个矩形的框,如选项对话框等)和无边框的,分别由如下函数创建。
CreateWnd_FullScreen(struct WndStruct*) 0xF3:EA82
CreateWnd_Pop(struct WndStruct*) 0xF3:EA8A
这两个函数都是调用CreateWnd的。而在第二节中说到的CreateMenu最终也是要调用CreateWnd_FullScreen的。
下面我们看一下6688中存在的窗体类型。
1、基本的菜单式窗体。就是第一节中所说所说的类型,他拥有几乎所有的界面元素。代表:基本的菜单大都是这一类。通过第一个参数bBorder可以决定最后调用CreateWnd_FullScreen还是CreateWnd_Pop,如果bBorder是1,那么则创建一个有边框的弹出式窗体。
2、无标题和图标的窗体。这类窗体没有标题和图标,没有菜单,一般是一张图片。代表:游戏的开始画面,6688和x618的图形菜单也是基于这类窗体。如下是猜数字的主函数:
0xD1:AD08 ; ☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆
0xD1:AD08 loc_D1AD08: ; CODE XREF: 0xD1:AD76J
0xD1:AD08 mov [-r0], r9
0xD1:AD0A mov [-r0], r8
0xD1:AD0C mov r12, #898Ch 0xD3898C MMIMalloc
0xD1:AD10 mov r13, #0D3h ;
0xD1:AD14 mov r14, #89C8h 0xD389C8 MMIFree
0xD1:AD18 mov r15, #0D3h ;
0xD1:AD1C calls 0E2h, InitScreen
0xD1:AD20 mov r8, r4
0xD1:AD22 mov r9, r5
0xD1:AD24 mov r12, r8
0xD1:AD26 mov r13, r9
0xD1:AD28 mov r14, #2CB6h ; 0xD1:ACB6 窗口的相关结构
0xD1:AD2C mov r15, #346h
0xD1:AD30 calls 0E2h, sub_E2367F //填充窗口结构
......
//略去和创建窗口无关的部分
......
0xD1:AD68 mov r12, r8
0xD1:AD6A mov r13, r9
0xD1:AD6C calls 0F3h, CreateWnd_FullScreen //在这里直接调用的创建noBorder的窗口函数
0xD1:AD70 mov r8, [r0+]
0xD1:AD72 mov r9, [r0+]
0xD1:AD74 rets
0xD1:AD76 ; ☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆
//窗口结构的相关信息
0xD1:AC9E dw 2Fh //软键定义Order_0,键码为2F
0xD1:ACA0 dw 2Fh
0xD1:ACA2 dw 38Ch //文字为"Options"
0xD1:ACA4 dw 5 //软键定义Order_1,键码为5
0xD1:ACA6 dw 5
0xD1:ACA8 dw 303h //文字为"Start"
0xD1:ACAA dw 2C9Eh //KeyCodeInfo, 有1套配置
0xD1:ACAC dw 346h
0xD1:ACAE dw 1
0xD1:ACB0 dw 0 //配置信息,左软键用Order为0的配置
0xD1:ACB2 dw 1 //右软键用Order为1的配置
0xD1:ACB4 dw 107h //图标ID
0xD1:ACB6 dw 0 ; field_0
0xD1:ACB6 dw 0 ; field_2
0xD1:ACB6 dw 0ACDCh ; OnCommandOff
0xD1:ACB6 dw 0D1h ; OnCommandPage
0xD1:ACB6 dw 0 ; field_8
0xD1:ACB6 dw 0 ; field_A
0xD1:ACB6 dw 0E636h ; field_C
0xD1:ACB6 dw 0F3h ; field_E
0xD1:ACB6 dw 2CB0h ; SKeyItem_Offset
0xD1:ACB6 dw 346h ; SKeyItem_Page
0xD1:ACB6 dw 2CAAh ; SKeyListOffset
0xD1:ACB6 dw 346h ; SKeyList_Page
0xD1:ACB6 dw 0 ; field_18
0xD1:ACB6 dw 0 ; field_1A
0xD1:ACB6 dw 65h ; Weigth
0xD1:ACB6 dw 41h ; Heigth
0xD1:ACB6 dw 2CB4h ; IconOffset
0xD1:ACB6 dw 346h ; IconPage
0xD1:ACB6 dw 0 ; field_24
这里面的主要结构如下
struct wndClass_2{
int * pUnknown_1;
MessgeFunction pOnkeyDown; //按键响应函数
int * pUnknown_2;
MessgeFunction pUnknown_3; //未知的函数,一般是直接返回,即ret;
KeyCodeInfo * pKeyCodeInfo; //窗体的软键信息
KeyDefOrder * pKeyDefOrder; //软键配置信息组
int unKnown_4;
int unKnown_5;
int ViewWidth; //窗体的视图区域宽度
int ViewHeight; //窗体的视图区域高度
int *pImageID; //指向窗体图标序号的地址
int unKnown_6; //菜单标题的字串ID
}
此外,说一下这里面的按键响应函数
0xD1:ACDC ; ☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆
0xD1:ACDC mov [-r0], r8
0xD1:ACDE mov r8, #0FFFFh //按键响应函数的返回值,意义下面解释
0xD1:ACE2 extp r15, #1
0xD1:ACE4 mov r12, [r14+2]
0xD1:ACE8 cmp r12, #2Fh ; '/' //左软键
0xD1:ACEC jmpr cc_Z, loc_D1ACF4
0xD1:ACEE cmp r12, #5 //右软键
0xD1:ACF0 jmpr cc_Z, loc_D1ACFA
0xD1:ACF2 jmpr cc_UC, loc_D1AD00
0xD1:ACF4 ; ☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆
0xD1:ACF4 loc_D1ACF4: ; CODE XREF: 0xD1:ACECj
0xD1:ACF4 calls 0D1h, sub_D18BAA
0xD1:ACF8 jmpr cc_UC, loc_D1AD02
0xD1:ACFA ; ☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆
0xD1:ACFA loc_D1ACFA: ; CODE XREF: 0xD1:ACF0j
0xD1:ACFA calls 0D1h, sub_D1AC32
0xD1:ACFE jmpr cc_UC, loc_D1AD02
0xD1:AD00 ; ☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆
0xD1:AD00 loc_D1AD00: ; CODE XREF: 0xD1:ACF2j
0xD1:AD00 mov r8, #0
0xD1:AD02 loc_D1AD02: ; CODE XREF: 0xD1:ACF8j
0xD1:AD02 ; 0xD1:ACFEj
0xD1:AD02 mov r4, r8
0xD1:AD04 mov r8, [r0+]
0xD1:AD06 rets
0xD1:AD08 ; ☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆
这里面需要注意是按键响应函数的返回值,如果按键已经被处理,那么需要返回-1(0FFFFh),则消息系统会认为你已经处理,否则会转到系统的默认窗口函数去处理。
3、消息框的窗体,类似于windows的MessageBox,可以显示文本信息,并制定图标,和键盘控制,如一般的确认对话框。如下是写短消息时选项中按清除文本后的处理:
//次函数最终根据bBorder调用CreateWnd_FullScreen还是CreateWnd_Pop。
0xE6:017E MessageBox(int bBorder, int * Prama, int , struct wndClass_3 * pwndClass)
0xD5:63AE ; ☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆
0xD5:63AE DeleteText: ; CODE XREF: 0xD5:62B6j
0xD5:63AE mov r12, r8
0xD5:63B0 mov r13, r9
0xD5:63B2 calls 0E5h, sub_E5F0FC
0xD5:63B6 mov r8, r4
0xD5:63B8 mov r9, r5
0xD5:63BA mov r6, #3A04h ; 0xD4:FA04
0xD5:63BE mov r7, #353h
0xD5:63C2 mov [-r0], r7
0xD5:63C4 mov [-r0], r6
0xD5:63C6 mov r12, #1
0xD5:63C8 mov r13, r8
0xD5:63CA mov r14, r9
0xD5:63CC calls 0E6h, MessageBox
0xD5:63D0 add r0, #4
0xD5:63D2 jmpa cc_UC, loc_D5646E
0xD5:63D6 ; ☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆
0xD4:FA04 dw 0
0xD4:FA06 dw 0
0xD4:FA08 dw 6152h
0xD4:FA0A dw 0D5h
0xD4:FA0C dw 0
0xD4:FA0E dw 0
0xD4:FA10 dw 0E636h
0xD4:FA12 dw 0F3h
0xD4:FA14 dw 39B6h
0xD4:FA16 dw 399h
0xD4:FA18 dw 399Ch
0xD4:FA1A dw 399h
0xD4:FA1C dw 1
0xD4:FA1E dw 0
0xD4:FA20 dw 4E6h ; 删除文本?Delete Text?
0xD4:FA22 dw 39F2h
0xD4:FA24 dw 399h
0xD4:FA26 dw 0
0xD4:FA28 dw 3
0xD4:FA2A dw 2
0xD4:FA2C dw 0
0xD4:FA2E dw 0
0xD4:FA30 dw 0
0xD4:FA30 ; ☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆
这里面的主要结构如下
struct wndClass_2{
int * pUnknown_1;
MessgeFunction pOnkeyDown; //按键响应函数
int * pUnknown_2;
MessgeFunction pUnknown_3; //未知的函数,一般是直接返回,即ret;
KeyCodeInfo * pKeyCodeInfo; //窗体的软键信息
KeyDefOrder * pKeyDefOrder; //软键配置信息组
int unKnown_4;
int unKnown_5;
int nStringID //显示的消息的StringID
int *pImageID; //指向窗体图标序号的地址
int unKnown_6;
int unKnown_7;
int unKnown_8;
int unKnown_9;
int unKnown_A;
int unKnown_B;
}
4、简单消息框的窗体。只是简单的显示一条消息,有三类(i,v,无图标)。其中参数r12来决定由没有边框。本质上,以上的几个函数都是下面复杂窗体的一个特例,为了使用方便,特独立列出!主要有以下三个函数:
0xE6:04A8 MessageBox_v(int bBorder, int nStringID)//消息框图标为i
0xE6:0508 MessageBox_i(int bBorder, int nStringID)//消息框图标为v
0xE6:0538 MessageBox_NoIcon(int bBorder, int nStringID) //无图标
这三个函数比较简单,主要是根据bBorder来决定两个不同的结构,然后调用CreateWnd_FullScreen或CreateWnd_Pop。
B、)
待续。。。。。。。。。。。
;*****************************************************************
10、[原创]用来在IDA中Patch的IDC文件
作者:coollang
http://bbs.dbsjw.com/dispbbs.asp?BoardID=43&ID=30911
这个是用来在IDA中Patch的IDC文件,IDC是IDA的一种脚本语言,类似于C语言,系统提供了一些函数和变量,详细信息可以看IDA的帮助。
这个东西的原始作者是AlexSid,我做了一些修改,增加了注释,大家可以在此基础上发挥,增加Undo的功能等等。
使用也很简单,在IDA的文件-〉IDC文件,选择此IDC文件,然后选择VKP文件,制定基地址。就可以了。
#include <idc.idc>
// 原始作者: AlexSid
// alexsid@mail.ru
// 修改:coollang
// v0.3b
//如果不想进行实际内容的修改,可以打开此注释,只涑龅魇孕畔?br>//#define DEBUG
#define PATCH_ALWAYS 0 // 1-YES 0-NO
//Flash映射的基地址
#define FF_OFFSET 0xA00000
static main() {
auto ea, ea1, pos, st, st2, f, st_addr, st_old, st_new, addr, b_old, b_new, no_olds, ff_offset;
st=AskFile(0,"*.vkp","选择VKP文件:");
Message("Patch file name: %s\n",st);
f=fopen(st,"r");
if (f==-1)
Message("File open error\n");
else{
ff_offset=FF_OFFSET;
ff_offset = AskAddr(FF_OFFSET, "请输入Flash映射的基地址:");
if(ff_offset == BADADDR)
Message("无效地址!\n");
Message("Flash映射的基地址: 0x%06X\n",ff_offset);
// 从VKP文件中读出一行
while ((st=readstr(f))!=-1){
// 过滤注释
pos=strstr(st,";");
if (pos>-1){
st2=substr(st, 0, pos);
st=st2;
}
// 如果是系统参数
pos=strstr(st,"#");
if (pos>-1){
st2=substr(st, 0, pos);
st=st2;
}
// 滤去开头的空格
while (strstr(st," ")==0 && strlen(st)>0){
st2=substr(st,1,-1);
st=st2;
}
// 替换换行\t为空格
while ((pos=strstr(st,"\t"))>-1 && strlen(st)>0){
st_old=substr(st,0,pos);
st_new=substr(st,pos+1,-1);
st=st_old+" "+st_new;
}
// 无内容则继续
if (strlen(st)<1) continue;
// 增加偏移量
if ((substr(st,0,1)=="+") || (substr(st,0,1)=="-")){
addr=xtol(st);
ff_offset=FF_OFFSET+addr;
Message("偏移地址: 0x%06X\n",ff_offset);
continue;
}
// 计算VKP文件的地址
pos=strstr(st, ":");
if(pos == -1)
continue;
st_addr=substr(st, 0, pos);
addr=xtol(st_addr)+ff_offset;
st2=substr(st, pos+1, -1);
st=st2;
// 过滤空格
while (strstr(st," ")==0 && strlen(st)>0){
st2=substr(st,1,-1);
st=st2;
}
// 取得原始内容
pos=strstr(st," ");
st_old=substr(st, 0, pos);
st2=substr(st, pos+1, -1);
st=st2;
while (strstr(st," ")==0 && strlen(st)>0){
st2=substr(st,1,-1);
st=st2;
}
// 取得覆盖内容
pos=strstr(st," ");
st2=substr(st,0,pos);
pos=strstr(st2,"\n");
st_new=substr(st2,0,pos);
no_olds=0;
if (strlen(st_new)==0){
no_olds=1;
st_new=st_old;
}
//如果存在原始信息且长度不相等则输出错误信息
if ((strlen(st_old)!=strlen(st_new)) && (no_olds==0)){
Message("Error! %d %d |%s| |%s|\n",strlen(st_old),strlen(st_new),st_old,st_new);
return;
}
// 如果存在原始信息则比较原始内容
while (strlen(st_old)>0){
b_old=0;
if (no_olds==0){
st=substr(st_old,0,2);
b_old=xtol(st);
st2=substr(st_old,2,-1);
st_old=st2;
}
st=substr(st_new,0,2);
b_new=xtol(st);
st2=substr(st_new,2,-1);
st_new=st2;
if (no_olds==0) Message("0x%6X: %02X %02X ", addr, b_old, b_new);
if (no_olds==1) Message("0x%6X: xx %02X ", addr, b_new);
Jump(addr);
if (Byte(addr)==b_new){
Message(" always patched\n");
addr=addr+1;
continue;
}
if ((Byte(addr)!=b_old) && (PATCH_ALWAYS==0) && (no_olds==0)){
// 如果没有原始信息
Message("Warning! old: %02X",Byte(addr));
// 用户选择
pos=AskYN(1,"新旧内容不符!\n是否继续Patch?");
if (pos==-1){
Message("\nStopped!\n");
return;
}
if (pos==1){
#ifndef DEBUG
PatchByte(addr,b_new);
#endif
Message(" Patched\n");}
if (pos==0){
Message(" Skipped\n");
}
} else {
#ifndef DEBUG
PatchByte(addr,b_new);
#endif
Message(" patched\n");
}
#ifndef DEBUG
MakeUnkn(addr,1);
#endif
addr=addr+1;
}
}
fclose(f);
}
} |
|