转贴:俄版补丁在你的现金贴里发过了.
我开始移植补丁没多久,很久以前用M55的时候就读过狼大的一些文章,对补丁的基本原理有一定了解,真正开始下决心学移植补丁也就在大约2周以前,参照 Herrliu 的 《玩转补丁移植》移植了待机隐藏左右软件补丁,才开始对移植补丁有了感觉。之后在ShineGood的指点下,终于能够移植一些简单的补丁了。
本文通过移植 锁键盘时读短信 这个补丁来让真正想动手移植补丁的机油来了解移植一个补丁的全过程。
在开始之前,读者如果想要有收获的话,需要先读一些入门文章,知道补丁的基本原理。最好是读过Herrliu 的 《玩转补丁移植》。跟Herrliu说的一样,我也不大了解别人是如何移植的,这里说的是我学来和悟出的方法,不一定代表主流做法。
说了这么多,终于可以开始正题了。我的手机是S6C,拿到的补丁是C6Cv50上的
;C6Cv50, 锁键盘时读短信
08D8DFA: 00281fd0 27F701FB
0x00800400: FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF 002810D10223E95E57290ADA4B2908DB
0x00800410: FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF 1FB403201E21FF22034CA0471FBC0348
0x00800420: FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF 874603488746F746C564B2A0638B8DA0
0x00800430: FFFFFFFF 3F8E8DA0
移植的目的当然是让我的S6Cv50能用上这个补丁。因为X65的软件都是大同小异,补丁基本代码都是一样的,只是代码所在的地址和代码要跳转到的地址不同。找到合适的地方放代码,并且让代码都能正确跳转就是移植补丁的工作。首先要做的是用IDA反编译C6Cv50的Fullflash。 反编译的方法别的文章里已多次介绍,这里要提一下的就是开启IDA 修改Fullflash的方法:
修改IDA的cfg目录下的idagui.cfg文件
DISPLAY_PATCH_SUBMENU = YES
这样设置之后,在IDA 的Edit菜单里就多了一项Patch program。 通过这个功能,可以把补丁直接写到反编译的代码里去,来看到打了补丁后的代码。
还有另外一种更简便的方法,就是利用IDC脚本patch.idc和unpatch.idc来加载和卸载补丁。使用时在IDA菜单里选fileidc file,然后打开上面两个文件,就能直接加载vkp补丁文件了。
首先按照Herrliu的文章里的方法用IDA打开C6Cv50的bin文件。
我们从补丁开始的地方来反编译。当运行停止后,按G,填上要跳转到的地址:A08D8DFA, 就是补丁第一行的代码地址在前面加了个A。至于为什么要加A,这里不做赘述。
按Alt+G,Value=1切换到16位的Thumb状态,然后按C,IDA就在开始工作了,反编译之后,调整一下显示,Options General Number of opcode bytes , 填4。
得到代码如图所示:
按同样的办法,在打开一个IDA,反编译自己的S6Cv43的反编译是有时候得不到正确的代码,需要不同的地方多按几下C,如果还是得不到正常代码,可以试试Alt+G,value=0,转成arm指令。得到图中的代码后,对照补丁中的08D8DFA: 00281fd0 27F701FB,可以看到被修改的是
CMP R0, #0
BEQ loc_A08D8E3E
光标定位到ROM:A08D8DFA, 然后选择菜单中的Edit patch programchange byte.., 在弹出的框里填上27 F7 01 FB,OK之后,代码就变成了
BL unk_A0800400
可以看到,补丁把原来的2条指令修改成了一个跳转,双击这条指令,可以到
ROM:A0800400 FF unk_A0800400 DCB 0xFF
ROM:A0800401 FF DCB 0xFF
ROM:A0800402 FF DCB 0xFF
ROM:A0800403 FF DCB 0xFF
ROM:A0800404 FF DCB 0xFF
ROM:A0800405 FF DCB 0xFF
ROM:A0800406 FF DCB 0xFF
这里是一段空白的内存,用来放补丁的代码。到这里再通过Patch program功能,把剩下的补丁代码打到Fullflash里面。方法跟前面一样,补丁打进去后,按C来反编译,得到补丁的汇编代码,如下图:
ROM:A0800400 CODE16
ROM:A0800400 loc_A0800400
ROM:A0800400 00 28 CMP R0, #0
ROM:A0800402 10 D1 BNE loc_A0800426
ROM:A0800404 02 23 MOV R3, #2
ROM:A0800406 E9 5E LDRSH R1, [R5,R3]
ROM:A0800408 57 29 CMP R1, #0x57
ROM:A080040A 0A DA BGE loc_A0800422
ROM:A080040C 4B 29 CMP R1, #0x4B
ROM:A080040E 08 DB BLT loc_A0800422
ROM:A0800410 1F B4 PUSH {R0-R4}
ROM:A0800412 03 20 MOV R0, #3
ROM:A0800414 1E 21 MOV R1, #0x1E
ROM:A0800416 FF 22 MOV R2, #0xFF
ROM:A0800418 03 4C LDR R4, =(loc_A0B264C4+1)
ROM:A080041A A0 47 BLX R4
ROM:A080041C 1F BC POP {R0-R4}
ROM:A080041E 03 48 LDR R0, =(loc_A08D8B62+1)
ROM:A0800420 87 46 MOV PC, R0
ROM:A0800422 loc_A0800422
ROM:A0800422 03 48 LDR R0, =(loc_A08D8E3E+1)
ROM:A0800424 87 46 MOV PC, R0
ROM:A0800426 loc_A0800426
ROM:A0800426 F7 46 MOV PC, LR
ROM:A0800428 C5 64 B2 A0 off_A0800428 DCD loc_A0B264C4+1
ROM:A080042C 63 8B 8D A0 off_A080042C DCD loc_A08D8B62+1
ROM:A0800430 3F 8E 8D A0 off_A0800430 DCD loc_A08D8E3E+1
先看看反汇编得到的代码,来理解一下,移植究竟要干什么。首先:
ROM:A0800400 00 28 CMP R0, #0
这是补上的08D8DFA: 0028,因为前面修改的代码占用了4个字节,就少了一个0028的指令,这里来把它补上。接下来的代码来实现锁键盘读短信的功能代码,其中
ROM:A0800410 1F B4 PUSH {R0-R4}
ROM:A0800412 03 20 MOV R0, #3
ROM:A0800414 1E 21 MOV R1, #0x1E
ROM:A0800416 FF 22 MOV R2, #0xFF
ROM:A0800418 03 4C LDR R4, =(loc_A0B264C4+1)
ROM:A080041A A0 47 BLX R4
ROM:A080041C 1F BC POP {R0-R4}
这一段是用来打开背景灯。MOV R1, #0x1E 这条指令就是设置背景灯亮度的,把亮度调到30%,也就是16进制数1E。其实移植补丁用不着看懂代码是怎么工作的,只需要让代码能跳转到正确的地方就行了,所以,对我们移植最重要的是最后几行代码:
ROM:A0800428 C5 64 B2 A0 off_A0800428 DCD loc_A0B264C4+1
ROM:A080042C 63 8B 8D A0 off_A080042C DCD loc_A08D8B62+1
ROM:A0800430 3F 8E 8D A0 off_A0800430 DCD loc_A08D8E3E+1
它们决定了跳转的目标地址。在Thumb指令里实现任意跳转,需要如下:
LDR R0, =JumpAddress
mov PC, R0
DCD JumpAddress
在补丁里,也许是因为方便修改的原因,把DCD都放到了代码的最后。这里的JumpAddress就是loc_A0B264C4这样的代码,后面+1表示跳转后的地址是Thumb指令,如果没有+1,就是32位的ARM指令。双击DCD loc_A0B264C4+1就能跳到
ROM:A0B264C4 loc_A0B264C4
因为有+1, 所以要按Alt+G, value=1,再按C,就能得到目标地址的汇编代码。
反编译好了,我们就可以开始移植了。先确定一下移植的任务:
1. 移植08D8DFA: 00281fd0 27F701FB;
2. 在S6Cv50里找到合适的空间来放补丁代码;
3. 移植补丁的3个 DCD 。
我们按顺序来移植。第一步,就是找到S6C中,00 28 1f d0代码对应的地址。我们按工具栏上的 退到ROM:A08D8DFA, 选取一段比较固定的代码:0B 28 09 D1 01 20到S6C中搜索。转到打开了S6Cv43 Fullflash的另一个IDA,按alt+ B打开搜索对话框,填上0B 28 09 D1 01 20后,选中下面的Find all recurrence,点OK,搜索结束后,刚好只找到一处:
双击高亮的这一行,然后转到IDA View-A窗口,可以看到我们搜索到的代码正好就是跟C6Cv50里一样的。现在我们可以认为,ROM:A08DAECA 就是S6C中第一行的代码地址。
因为要移植的是,BL loc_A0800400,有了起点的地址还要找到目标地址。这里的目标地址就是A0800400,也就是放补丁代码的空地址。在S6C中需要找到一个类似的地方来放补丁代码。通过Smelter,在A0CB0000这个地方找到了一块空地址。要注意的是BL 指令只能在+/-4MB的地址跳转,所以找空地址的时候得注意不能离起点地址太远。最后选择A0CB00A0后面的空间来存放补丁代码。因为在S6C里跳转的起点和目标地址都是不一样的,需要重新编译BL 指令成机器码,要用到ABraGen0.21。这个工具打开后,选择BL,填上前面找到的起点与终点的地址,按generate,就能得到需要的机器码D5F3E9F8。
得到D5F3E9F8,我们移植的第一步和第二步就完成了,把原来的补丁另存一份S6C版的,修改第一行08D8DFA: 00281fd0 27F701FB 成 08DAECA: 00281fd0 D5F3E9F8。 并把后面的地址改成0x00CB00A0: 0x00CB00B0: 0x00CB00C0: 0x00CB00D0: 。在回到S6C的IDA中,通过Patch program 把移植后的第一行打到Fullflash中,得到的代码如图,双击unk_A0CB00A0可以跳转到空白地址ROM:A0CB00A0,同时也验证计算出的BL 指令是正确的。
然后进行第二步,移植补丁的3个 DCD。为了移植方便,可以先把未修改的补丁在IDA中打到S6C上面,可以得到:
这样能得到S6C补丁的基本代码,只要把3个DCD改成正确的地址,移植就完成了。首先看第一个DCD loc_A0B264C4+1。这个是开背景灯的函数地址,打开C6C的IDA,双击DCD loc_A0B264C4+1跳转ROM:A0B264C4 loc_A0B264C4,反编译后可以看到:
这一块的代码都是比较固定的,跳转指令比较少,移植比较容易。转到S6C的IDA中,Alt+B搜索F7 B5 84 B0 04 98 0E 1C就能找着ROM:A0B2C214这个地址:
跟C6C比较之后,能确定这里就是我们要找的,现在可以在S6C的IDA里把ROM:A0CB00C8: C5 64 B2 A0改成ROM:A0CB00C8: 15 C2 B2 A0。并把补丁改成
0x00CB00C0:FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
874603488746F74615C2B2A0638B8DA0
然后再来看DCD loc_A08D8B62+1,对应地址的代码如图:
这附近的代码都包含很多的跳转,很难找到合适的关键词来搜索到正确的地方。也许有人能用通配符来搜索对,但在这里,提供另外一个移植补丁的方法。思路是这样的,我们要移植的C6C代码中调用了一个叫A的函数,而且在C6C中,A被调用的次数并不多,假如能能找着A函数在S6C中的地址,然后对比每处调用A函数的代码,就能在S6C中找到C6C中调用A函数的代码。用这个方法,需要用到一个工具FindCall。
联系到要移植的这段代码中来,我们要找的是loc_A08D8B62,不幸的是这个函数附近的代码不好搜索,而且还是local属性的,FindCall只能搜索Sub或者Fun的函数。我们继续察看C6C中A08D8B62附近的代码,在A08D8B62 前面有一处BL sub_A0937920。先假定在C6C中sub_A0937920只被调用了几次,而且S6C中对应的代码跟我们要找的loc_A08D8B62紧接着。只要这一假定成立,我们就能用前面提到的思路来移植loc_A08D8B62。在CMD下运行findcall c6cv50.bin A0937920,输出如下:
D:\CELLPH~1\fubu\c65>findcall c6cv50.bin A0937920
callee address: [A0937920]
finding start ...
<T> 0x008D8B56: BL fun_A0937920
<T> 0x00985EFC: BL fun_A0937920
<T> 0x009D80C0: BL fun_A0937920
finding result: 3 caller is found!
很幸运,假设中的第一条成立,sub_A0937920被调用了3次。然后要做的是找到fun_A0937920这个函数在S6C中的地址。跳转到C6C的ROM:A0937920,找到关键词B5 05 1C 04 20 87 B0,然后在S6C中搜索。很容易就找到了S6C中的
ROM: A0935118 30 B5 PUSH {R4,R5,LR}
ROM: A093511A 05 1C ADD R5, R0, #0
ROM: A093511C 04 20 MOV R0, #4
ROM: A093511E 87 B0 SUB SP, SP, #0x1C
ROM: A0935120 86 F7 DA FC BL sub_A08BBAD8
ROM: A0935124 04 1C ADD R4, R0, #0
跟C6C的fun_A0937920比较后,能确定找对了。然后用FindCall搜索S6C中A0935118的调用:
D:\CELLPH~1\fubu\S65>findcall s6cv50.bin A0935118
callee address: [A0935118]
finding start ...
<T> 0x008DAC26: BL fun_A0935118
<T> 0x00970268: BL fun_A0935118
<T> 0x009CFC98: BL fun_A0935118
finding result: 3 caller is found!
同C6C一样,也被调用了3次。找到S6C中的ROM: A08DAC26, 跟C6C中的A08D8B56比较后可以确定,假设成立,地址找对了。
现在我们可以把S6C的ROM:A0CB00CC 63 8B 8D A0 off_A0CB00CC DCD unk_A08D8B63改成ROM:A0CB00CC 33 AC 8D A0 off_A0CB00CC DCD loc_A08DAC32+1。同时把补丁改成0x00CB00C0: FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF 874603488746F74615C2B2A033AC8DA0。
还有一种移植的思路。要找C6C的一个叫A的函数在S6C的地址,但是这个函数不容易用关键词搜到。A在C6C中被多次调用,假如能找到另外一处调用A的代码,并且在S6C中能比较容易的找到调用这个函数的代码,然后通过找到的代码就能跳转到我们要找的函数的代码。不过在这里并不适用,就不举例说明了。我不知道Bennie开发FindCall这个工具究竟是想怎么用,不过在移植补丁的时候能比较灵活地解决一些问题。
最后一个DCD的移植DCD loc_A08D8E3E+1 不难,搜索A08D8E3E前面的68 68 41 88 89 05 89 0D FF 39 94 39很容易就能找到A08D8E3E 在S6C对应的地址是A08DAF0E。修改完S6C的代码,在检查一下是不是所有的跳转都能跳到正确的地方,补丁就能确定下来了。
补丁做完后就是这个样子:
08DAECA: 00281fd0 D5F3E9F8
0x00CB00A0: FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF 002810D10223E95E57290ADA4B2908DB
0x00CB00B0: FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF 1FB403201E21FF22034CA0471FBC0348
0x00CB00C0: FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF 874603488746F74615C2B2A033AC8DA0
0x00CB00D0: FFFFFFFF 0FAF8DA0
刷上手机,锁了键盘让别人发条短信过来,果然能直接读了。这个补丁有些不足的地方就是只能在没有屏保的情况下看短信,而且一收到短信就读的话,背景灯很快就灭了。这里提到的方法并不适用于RAM地址的移植。对于移植补丁来说,我还是个新手,也许高手们会觉得我的方法过于麻烦,我也希望有人能提出更容易的方法。
玩转补丁移植
Herrliu
? 补丁很神秘吗?补丁移植很难吗?我能自己移植补丁吗?
? 我说不好,不过我相信,看完这篇文章你一定会手痒痒。
? 搞补丁移植没有任何经验,但是我有自己的思路:就象自学日语德语一样,不要教科书,直接去日本德国的网站找感兴趣的东西看,越糊涂越好,坚持下去,大彻大悟之时,再去比照别人的经验。
? 所以,至今也不太了解别人是如何移植补丁的。
? 写完这篇文章后,我想自己应该去深造一下了。
? 如果你觉得我下面的方法比较苯、比较另类,我希望你会谅解。
? 在研究、移植补丁之前,需要知晓几个必备的条件:
? 1、不必具有太多的相关专业知识,但是必须具有清晰、灵活的思路;
? 2、需要一定的耐心和搞坏爱机的心理承受能力;
? 3、具备几个软件和文件:UltraEdit(二进制文本编辑软件)、Smelter(Fullflash综合分析工具)、IDA(反汇编调试工具)、ABraGen(ArshOr写的分支跳转计算工具)、补丁手机的Fullflash和你自己手机的Fullflash。
? 一般情况下,我们认为FUBU(FUllflash BackUp)和Fullflash是有所区别的:FUBU是手机的.fbk格式的整机备份(x65flasher-backup-fullflash),内部含有解释性的地址参数,所以在Restore时不用提供起始地址和长度;Fullflash是.bin格式的整机备份(x65flasher-Read Flash),是A0000000H开始的“原汁原味”的纯二进制文件,可以重新定位到任何地址段,是这里移植补丁所需要的格式。
? 有关地址的说明:x65有32M内存,使用8位地址,基址为A0000000,反汇编都是基于这个基址的,而在V_Klay格式的补丁中,必须去掉最高位的A,剩下的7位数据可以去掉或者保留最前面的0。
? IDA的基本用法:处理器选ARM或者ARM 710a;ROM和Loading地址选A0000000;切换到16位的Thumb状态用Alt+G,Value=1;定位地址按G键;反汇编按C键...
? 我们下面会通过三个比较典型的例子,介绍一下补丁移植的基本方法,大家细嚼慢咽,就会品出“腊肉”的滋味。
? 请先准备好干净的、没刷过下面补丁的S65 v25和C6C v25(或者其他机型)的Fullflash,我们来把S65 v25的补丁移植到你的手机上。
? 一、通话时间50秒提示
? 1.补丁原型:
?;S65
? 0B7BBB6: 00 32
? 2.基本思路:
? 上面的补丁是把S65手机中地址为0B7BBB6处的一个字节的16进制数据00(代表默认的60秒)替换为32(表示50秒)。
? 在C6C(或者其他类型)手机中,数据00可能不在0B7BBB6这个位置上,我们必须重新找到这个位置。要从32M(32x1024x1024)个字节的数据里面直接找到这个特定的00几乎是不可能的。但是由于这两款手机的软件系统结构具有相当的一致性,我们可以将这个00数据及其周围的一段数据作为特征字串,在C6C的Fullflash里面搜索一下,看看能不能找到一个唯一的位置,然后,把这个位置的00改为32,刷进C6C进行测试。
? 3. 补丁移植
? 3.1 用UltraEdit打开S65的Fullflash,找到00B7BBB0这一行(00位于这一行的0B7BBB6这个位置上);
? 3.2 从00B7BBB6开始,直到这一行结束,用“鼠标右键-Hex复制选定区”进行复制;
? 3.3 用UltraEdit打开C6C的Fullflash,在搜索功能里面,粘贴上面复制的内容,去掉开头的地址和后面的乱码,只要有用的数据:00 29 06 D1 2A 1C 2B 1C 5B 21
? 3.4 搜索的结果,在地址00b006b2这里找到了这个和S65一样的特征字串,继续搜索,没有发现其他位置有这个字串,现在,我们认定这就是我们要找的位置了;
? 3.5 新建一个V_Klay文件,输入0b006b2: 00 32,刷进手机试一下补丁的效果。
? 3.6 很幸运,一次成功。
? 4. 最终补丁:
?;C6C v25 通话时间50秒提示
? 0b006b2: 00 32
? 5.补充说明:
? 如果特征字串选的太短,可能会搜索到多个结果,难以确定真实有效的位置;如果字串太长,可能一个位置也找不到。所以,应该由短到长逐渐改变字串的长度,缩小地址范围。
? 如果这个补丁的移植过程没有看明白,建议先不要继续下面的内容。
? 二、待机画面取消软键显示
? 1.补丁原型:
?;S65
? 0854992: 05D1 0028
? 08548B3: D0 E0
? 0877A4C: 06D1 0028
? 2.基本思路:
? 相当多的补丁不能用上面那种简单的、搜索固定字串的方式来移植。由于地址、数据和程序位置的不同,特征字串里面可能会有一些不确定的变数,需要进行模糊搜索,具体的方法就是用?号来代替那些不确定的数据。
? 在“0854992: 05D1 0028”中,05D1是一个条件跳转指令(BNE loc_A08549A0)的机器码,用来判断是否在屏幕上显示软键提示,我们不想要这个判断,需要取消显示,让程序继续执行下去,所以要屏蔽掉这条指令,方法是用一个无实际效果的多余指令来代替它(相当于NOP),作者选用了“ CMP R0, #0”(机器码就是0028)。
? 我们知道05D1在S65中的位置是A0854992,现在,我们用程序分析的方法来确定这条程序在C6C中的位置,然后屏蔽它。
? 3.补丁移植:
? 3.1
? 用IDA反汇编S65 Fullflash从A0854992开始的代码:
? ROM:A0854992* BNE loc_A08549A0
? ROM:A0854994 MOV R0, #0x1A
? ROM:A0854996 STR R0, [R5,#0x24]
? ROM:A0854998 STR R0, [R5,#0x20]
? ROM:A085499A B loc_A08549A0
? ROM:A085499C MOV R3, #0
? ROM:A085499E STR R3, [R5,#0x20]
? ROM:A08549A0* loc_A08549A0
? ROM:A08549A0 LDR R0, =0xA847F4B4
? ROM:A08549A2 LDR R3, [R5,#0x1C]
? 由于BNE loc_A08549A0只是一个范围很小的、跨越了几条指令的短跳,不同地址,但是具有相同方向和距离的相对地址的短跳指令具有相同的机器码。尽管在它的指令机器码中包含了相对的地址偏移量,我们还是先假定在C6C中具有相同的跳转,这样,可以先直接搜索它的机器码而不是用?号来代替搜索。接下来的几条指令都是一些常数赋值处理,在C6C中应该具有相同的指令。基于这样的认识,我们假定在C6C里面具有完全相同的代码段,先使用固定的特征字串进行定位。
? 这一次,我们用Smelter来搜索。
? 用Smelter打开C6C的Fullflash,按Ctrl+B,搜索前两条指令的机器码05D11A20,得到两个地址,增加搜索长度05D11A206862,得到唯一的地址a084bbe6,也许是巧合,但是我们先假定这次也是幸运的,或者可以再用一个IDA看一下C6C的a084bbe6开始的程序结构与S65是否类似,以此确定地址的准确性。
? 这样就得到了第一行移植后的补丁数据:
? 084bbe6:05D1 0028
? 3.2
? 用IDA反汇编补丁第二行A08548B3处的程序:
? ROM:A08548B3* DCB 0xD0 ; 反汇编不出来
? ROM:A08548B4 BL sub_A083FA8A
? ROM:A08548B8 CMP R0, #0
? ROM:A08548BA BEQ loc_A08548E4
? ROM:A08548BC MOV R0, #0x1A
? ROM:A08548BE STR R0, [R5,#0x1C]
? ROM:A08548C0 B loc_A08548F4
? 发现这个地址开始的数据D0没有反汇编出来,被当作了一个字节的数据,难以确定搜索特征。我们继续从上一个地址位置重新反汇编,得到新的结果:
? ROM:A08548B0 CMP R0, #0
? ROM:A08548B2* BEQ loc_A08548BC
? ROM:A08548B4 BL sub_A083FA8A
? ROM:A08548B8 CMP R0, #0
? ROM:A08548BA BEQ loc_A08548E4
? ROM:A08548BC loc_A08548BC
? ROM:A08548BC MOV R0, #0x1A
? ROM:A08548BE STR R0, [R5,#0x1C]
? ROM:A08548C0 B loc_A08548F4
? 这一下明白了,原来A08548B2处的数据03是指令BEQ loc_A08548BC的固定部分,在新的补丁中没有变化,所以补丁中没有写出这个字节来。
? 用UltraEdit将A08548B3处的D0改为E0,再用IDA反汇编:
? ROM:A08548B2* B loc_A08548BC
? ROM:A08548B4 BL sub_A083FA8A
? ROM:A08548B8 CMP R0, #0
? ROM:A08548BA BEQ loc_A08548E4
? ROM:A08548BC loc_A08548BC
? ROM:A08548BC MOV R0, #0x1A
? ROM:A08548BE STR R0, [R5,#0x1C]
? ROM:A08548C0 B loc_A08548F4
? 补丁里将条件跳转改成了无条件跳转。其中BEQ loc_A08548BC类似实例一中的情况,所以,我们也假设C6C中有相同的机器码。但是,接下来的BL sub_A083FA8A是一个4字节的绝对地址跳转,这在不同的机型中的机器码很可能是不一样的,不能做为特征值搜索,使用?号代替(或者代替其中的变数部分),为了缩小搜索范围,把后面的两条比较“老实”的指令的机器码也加入搜索。这样,用Smelter在C6C的Fullflash里面搜索“03D0????????002813D0” 得到唯一的地址A084BB06,需要修改的地址是A084BB07,于是,我们得到了第二行移植后的补丁数据:
? 084BB07

0 E0
? 3.3
? 使用和1同样的方法得到第三行移植后的补丁数据:
? 086a214: 06D1 0028
? 4.最终补丁:
?;C6C v25 待机画面取消软键显示
? 084bbe6: 05D1 0028
? 084bb07: D0 E0
? 086a214: 06D1 0028
? 5.补充说明:
? 在“将A08548B3处的D0改为E0,再用IDA反汇编”这一步,我们可以用工具软件ABraGen的反汇编功能来确定补丁的指令格式,但是ABraGen的反汇编功能还存在bug,仅供参考。
? 特征值的模糊搜索也可以用DOS软件sfe来进行,比较而言,Smelter更直观、功能也更丰富一些。
? 如果不进行反汇编,是难以确定需要进行模糊搜索的?号的位置的。这是移植跳转类补丁的基本方法。
? 三、按###进入九宫菜单
? 1.补丁原型:
?;S65
? 0B6E9E0: 39F021FF F3F4C8FF
? 2.基本思路:
? 我们曾经移植过“任意处按###进入极速菜单”的补丁,现在,只需改一下补丁的指针,就可以改为调出正常的九宫菜单,也可以进一步修改,按###进入其他功能。
? 在这个补丁中,包括一个地址和两个入口指针(绝对地址长跳指令)。按###进入陷阱地址A0B6E9E0再转向九宫菜单。
? 移植工作需要做的是,在C6C中,找到39F021FF(作用相同但数值不一定是39F021FF)的位置,替换为F3F4C8FF(作用相同但数值不一定是F3F4C8FF)的位置。
? 3.补丁移植:
? 用IDA反汇编S65的Fullflash:
? ROM:A0B6E9E0* BL sub_A0BA8826
? ROM:A0B6E9E4 STR R6, [R5,#4]
? ROM:A0B6E9E6 POP {R3-R7,PC}
? ROM:A0BA8826* PUSH {R4,LR}
? ROM:A0BA8828 SUB SP, SP, #0x1C0
? ROM:A0BA882A BL sub_A0BA8200
? ROM:A0BA882E CMP R0, #0
? ROM:A0BA8830 BEQ loc_A0BA8862
? ROM:A0BA8832 ADD R0, SP, #0x1C8+var_1C4
? ROM:A0BA8834 BL sub_A0BA8610
? 可以看到BL sub_A0BA8826是一个绝对地址长跳指令,需要进行模糊搜索,增加一些特征值后,我们用Smelter在C6C的Fullflash中搜索“????????6E60F8BD80B5”,得到唯一的地址A0AF9C98 ,数据为2AF03DFF,从而确定了补丁的一部分:
? 0AF9C98:2AF03DFF
? 下面需要看一下,修改后的补丁跳到了哪里。将S65的A0B6E9E0处的数据39F021FF替换为F3F4C8FF之后,反汇编得到:
? ROM:A0B6E9E0 BL loc_A0862974
? ROM:A0B6E9E4 STR R6, [R5,#4]
? ROM:A0B6E9E6 POP {R3-R7,PC}
? ...
? ROM:A0862974 PUSH {R7,LR}
? ROM:A0862976 BL sub_A0849094
? ROM:A086297A BL sub_A083D85E
? ROM:A086297E POP {R7,PC}
? 需要在C6C里面找到这段功能相同的程序:用Smelter搜索“80B5??????F???????F?80BD08B5????????0028”,得到地址A08796E0,这就是正常的九宫菜单的入口。下面我们就要确定一下使用BL指令由A0AF9C98跳到A08796E0的机器码,还是要用到ABraGen这个软件,经计算得到了数据7FF522FD。
? 4.最终补丁:
?;C6C v25 按###进入九宫菜单
? 0AF9C98:2AF03DFF 7FF522FD
? 5.补充说明:
? 刷这个补丁之前需要先撤销原来的按###进极速菜单的补丁。当然也可以强刷(因为###的陷阱地址相同),V_Klay产生的Repair文件会包含极速菜单的补丁。
? 实际使用中,并不是任意处按###都有效,大家可以自己尝试一下。
? 移植类似“远端同步->极速菜单”和“黑白名单”这样的补丁还需要更灵活的处理方式,其中的原理都是一样的。
? 这篇文章向大家介绍了个人在移植补丁中摸索出来的几种基本方法,有不当之处,请大家批评指正。
? 有时间的话,我希望再写一点开发补丁的方法和思路,与大家探讨。
? 文中所用软件和Fullflash都可以在
http://www.siediyer.com下载。
? --------------------------------
补充:在IDA里面直接修改机器码的方法:
修改IDA的cfg目录下的idagui.cfg文件
DISPLAY_PATCH_SUBMENU = YES
然后,在IDA的Edit菜单里选择Patch program项。