口袋社区-Poke The BBS's Archiver

enler 发表于 2010-8-18 15:23

通过ASM解决空之探险队美版/汉化版进化死机bug

[font=宋体]实在想不到什么好标题,也想不到什么好的分类,毕竟跟改版基本上扯不上关系,不过本文的一些思路跟asm部分应该会对大家有帮助。
关于bug的详细情况看这里[url=http://poketb.com/bbs/thread-17613-1-1.html]http://poketb.com/bbs/thread-17613-1-1.html[/url]
[yct35]准备,空探美版/汉化版rom任意一个,在这里当然推荐汉化版的,别问我为什么,呵呵。[color=White](靠,不就是因为这是你负责汉化的作品么?)[/color]
欧版rom是没有bug,也准备一个。
bug的间接原因是pm名过长,直接原因是读取函数的问题,在这里说一下空探([color=Red]空之探险队美版/汉化版均简称空探[/color],下同)的pm数据结构。
在这个数据结构中,有10字节用来保存pm名,这10字节后面[color=Red]直接[/color]跟的是其他的[color=Red]有用数据[/color]。
[attach]29021[/attach]
本存档由热心玩家提供,在此特别感谢,读取该存档后继续阅读本文
[quote]022AD8A0 C8 00 00 00 00 00 F1 01 00 00 4D 6F 72 6E 69 6E  ..........Mornin
022AD8B0 67 73 75 6E 01 1F 22 02 8D 03 1F 00 01 00 61 00  gsun..".......a. [/quote]
如上所示,Morningsun占用了10字节,不过后面紧跟着01 1F 22 02 8D 03 1F 这些数据,如果你是程序员,在写pm名读取函数的时候,肯定要做个处理的,诸如最多读取10字节不再读取,上面说了,直接原因是读取函数的问题,那么空探是怎么处理的呢?
[attach]28925[/attach]
在游戏中,进入如图所示的场景,连按2个A键,好了,死机了,撒花~~~[yct31]我靠,死机还这么高兴,开玩笑啦,先设置断点咯。
中断条件是“[22AD8AA]?”表示在内存22AD8AA的数据被读取时中断程序,然后按A键吧,程序会不断地读取这部分数据,仔细查看这些读取函数,会发现这么一个函数,如下所示,
[quote]r1是源内存,初始值是22AD8AA,r0是目标内存
02025100 E4D12001 ldrb    r2,[r1],1h              ;2  15
02025104 E1A03000 mov     r3,r0                   ;1  16
02025108 E4C02001 strb    r2,[r0],1h              ;1  17
0202510C E5D32000 ldrb    r2,[r3]                 ;2  19
02025110 E3520000 cmp     r2,0h                   ;1  20 判断数据是否为0h
02025114 1AFFFFF9 bne     2025100h                ;3  23 如果为0h,则中断读取
02025118 E12FFF1E bx      r14                     ;3  26[/quote]
发现了吧~~[yct30]这部分代码很简单,看上去没有什么问题,不过它是用来读取pm名的~如果pm名后面跟着是0h,那么一切正常~但是如上面提供的数据结构那样的话(pm名达到最长),就会连同之后的“01 1F 22 02 8D 03 1F”一并读取,并且导致死机哦。[yct36]
那么怎么解决呢?先看一下r14,为238cc8c,跳转到这个地址吧,p.s. 这个函数是用bl指令调用的,bl指令在跳转的时候,会将r15的值保存到r14,用于函数返回。
回去看看吧,代码如下,
[quote]0238CC6C E59F101C ldr     r1,=238CE40h            ;2  77
0238CC70 E5912000 ldr     r2,[r1]                 ;2  79
0238CC74 E582003C str     r0,[r2,3Ch]             ;2  81
0238CC78 E5910000 ldr     r0,[r1]                 ;2  83
0238CC7C E590103C ldr     r1,[r0,3Ch]             ;2  85
0238CC80 E28000B1 add     r0,r0,0B1h              ;1  86
0238CC84 E281103A add     r1,r1,3Ah               ;1  87
0238CC88 EBF2611C bl      2025100h                ;3  90[/quote]
貌似卡住了?呵呵,这时候,欧版派上用场了,因为欧版解决了这个bug,厂商还算负责嘛,毕竟要卖钱的,囧,扯远了。
欧版的话,内存偏移了,不过无所谓了,跟踪步骤跟刚才一样,注意r14的变化,如果出现023xxxxx这样子的,那就是我们要的了。
[quote]020253E8 E92D4008 push    r3,r14                  ;1  2
020253EC E3A0C000 mov     r12,0h                  ;1  3
020253F0 EA00000E b       2025430h                ;3  6
020253F4 E4D13001 ldrb    r3,[r1],1h              ;2  8
020253F8 E1A0E000 mov     r14,r0                  ;1  9
020253FC E4C03001 strb    r3,[r0],1h              ;1  10
02025400 E5DE3000 ldrb    r3,[r14]                ;2  12
02025404 E3530000 cmp     r3,0h                   ;1  13
02025408 1A000007 bne     202542Ch                ;3  16
0202540C E28CC001 add     r12,r12,1h              ;1  17
02025410 E3A01000 mov     r1,0h                   ;1  18
02025414 EA000001 b       2025420h                ;3  21
02025418 E4C01001 strb    r1,[r0],1h              ;1  22
0202541C E28CC001 add     r12,r12,1h              ;1  23
02025420 E15C0002 cmp     r12,r2                  ;1  24
02025424 BAFFFFFB blt     2025418h                ;3  27
02025428 E8BD8008 pop     r3,r15                  ;4  31
0202542C E28CC001 add     r12,r12,1h              ;1  32
02025430 E15C0002 cmp     r12,r2                  ;1  33
02025434 BAFFFFEE blt     20253F4h                ;3  36
02025438 E8BD8008 pop     r3,r15                  ;4  40[/quote]
这就是欧版的那段代码了,看样子挺长,直接复制粘贴?拜托没有这个空间写这么多代码,其实没必要那么复杂的,直接修改调用它的函数就行了。
根据r14,跳转回去
[quote]0238D7AC E59F1020 ldr     r1,=238D980h            ;2  75
0238D7B0 E3A0200A mov     r2,0Ah                  ;1  76
0238D7B4 E5913000 ldr     r3,[r1]                 ;2  78
0238D7B8 E583003C str     r0,[r3,3Ch]             ;2  80
0238D7BC E5910000 ldr     r0,[r1]                 ;2  82
0238D7C0 E590103C ldr     r1,[r0,3Ch]             ;2  84
0238D7C4 E28000B1 add     r0,r0,0B1h              ;1  85
0238D7C8 E281103A add     r1,r1,3Ah               ;1  86
0238D7CC EBF25F05 bl      20253E8h                ;3  89[/quote]
除了寄存器有变动还有调用的函数不同,另外多了一条mov r2,0Ah,0Ah就是10了,表示最大的读取长度,但是这部分因为多了一条,好像也没办法复制到空探美版/汉化版去,怎么办呢?
呵呵,很简单,用thumb就是了,目前这些代码都是arm,用thumb来节省空间吧~
这里简单说一下快速转换arm与thumb的方法,
用bx Rn,Rn就是寄存器了,当然不能是r15啦,汗,由寄存器数据的最后一位判定,如果为1,则转换为thumb,如果为0则转换为arm,当然还有blx之类的,这里不介绍了。[yct34]
我的代码是
[quote]
add r2,r15,1h
bx r2 这里从arm转换为thumb了,
以下是thumb格式,指令照搬欧版的
0238CC74 4906     ldr     r1,=238CE40h            ;2  5
0238CC76 220A     mov     r2,0Ah                  ;1  6
0238CC78 680B     ldr     r3,[r1]                 ;2  8
0238CC7A 63D8     str     r0,[r3,3Ch]             ;1  9
0238CC7C 6808     ldr     r0,[r1]                 ;2  11
0238CC7E 6BC1     ldr     r1,[r0,3Ch]             ;2  13
0238CC80 30B1     add     r0,0B1h                 ;1  14
0238CC82 313A     add     r1,3Ah                  ;1  15
0238CC84 46FE     mov     r14,r15                 ;1  16
0238CC86 4770     bx      r14                     ;3  19  从thumb转换为arm了[/quote]
接着把bl指令修改为bl 202511c即可,大功告成~[yct35][/font]

[[i] 本帖最后由 enler 于 2010-8-27 10:55 编辑 [/i]]

liuyanghejerry 发表于 2010-8-18 19:04

-。-给你改个名,扔教程区好了。

6619237 发表于 2010-9-10 15:37

加油一起来!~~~~~~~~~~~~~~~~

fig 发表于 2010-9-10 22:02

ASM看起来好难啊
我应该看看 别的教程
这个 收下研究了

逆风DE影 发表于 2010-9-10 23:05

ASM要看初级教程,而且要从GBA的ROM学起,话说空探有补丁了吧

页: [1]

Powered by Discuz! Archiver 6.1.0F  © 2001-2007 Comsenz Inc.