|
本帖最后由 守护¥云 于 2010-8-24 17:37 编辑
汉化基础教程——ASM篇 by PGCG
并非需要很多的计算机知识才能够进行程序跟踪,当然要想便捷有效的跟踪程序的确需要扎实的汇编语言基础。许多朋友都是出于个人爱好才接触汉化的,如果一开始进行跟踪就学习大量的硬件知识和汇编知识一定会感觉吃力而对自己丧失信心。其实学习ASM HACK完全可以遵循循序渐进的原则,先使用最简单但比较费力的方法,通过对程序认识的深入再不断改进自己的跟踪手段来提高效率。在这篇文章中我将讲解如何使用比较原始的方法来捕获游戏图片在ROM中的位置,这只是跟踪的第一步,如果想要捕获显示程序或解压程序就需要了解更多的知识才能实现,但这是后话了,让我们先从最简单的开始。
工具软件:
BATGBA模拟器(一款免费的GBA模拟器,带基本的DEBUG功能。对于初学者不推荐使用NO$GBA)
UltraEdit(全球最著名的文本编辑器,功能强大,中文界面)
技术手册:
ARM指令集手册(ARM是GBA使用的处理器芯片,学习汇编的必备工具书)
几本计算机基础书籍(良好的计算机基础是你进行汉化的必要条件)
其他:
很多很多的耐心和一点点运气
在我们开始跟踪之前有必要了解一下GBA的芯片和模拟器的用法,大家开始的时候不用彻底学习这些知识,只要知道用法就可以。GBA使用的是ARM7TDMI处理器芯片,它和我们常见的INTER或AMD芯片有很大区别,不要把二者混为一谈。ARM使用RISC(精简指令集)架构 32位 16.78MHz。我们跟踪主要需要了解的是它的寄存器结构和汇编代码。ARM 处理器有二十七个寄存器,其中一些是在一定条件下使用的,所以一次只能使用十六个。
寄存器 0 到寄存器 7 是通用寄存器并可以用做任何目的。
寄存器 8 到 12 也是通用寄存器,但是在切换到 FIQ 模式的时候,使用它们的影子(shadow)寄存器。
寄存器 13 典型的用做 OS 栈指针,但也可被用做一个通用寄存器。
寄存器 14 专职持有返回点的地址以便于写子例程。
寄存器 15 是程序计数器。它除了持有指示程序当前使用的地址的二十六位数之外,还持有处理器的状态。
寄存器在程序中的表示符号是R0-R15,大家先不要深究这些寄存器的功能和区别,只要知道这些寄存器的名称就可以,然后我们讲关键的地方。
GBA和电脑一样,在运行任何程序时都遵循一个过程,先从卡带(ROM)里将程序或文件读入内存,然后将内存中的程序或文件按一定顺序装载到寄存器中,再由寄存器与处理器交互处理,将处理结果返回内存中。正是因为我们可以通过模拟器观察这个过程,才有跟踪的实现。那么GBA是如何将文件从ROM中装载到内存的呢?GBA在运行的时候将内存划分成一个连续的区域。用地址表示就是00000000H-FFFFFFFFH其中00000000H-08000000H是实际意义上的内存空间,而08000000H以后的地址则是ROM的地址映射,也就是说08000000H就是实际ROM中的首地址00000000H。GBA通过这个映射地址来读取ROM中的文件,理解这个概念很重要,也就是说你在寄存器中观察到的以08XXXXXXH表示的地址即说明此刻程序正从ROM里读取相应的文件,可能是程序,图片,文本,字库。这些正是我们需要找到的东西。
如何才能截获这个地址呢?这就是模拟器的工作了,现在几乎所有的GBA模拟器都带有跟踪功能,允许你查看游戏运行过程中内存和寄存器里的内容,通过观察寄存器中的数值和内存中的程序,我们可以滴水不漏的获得游戏运行的全过程。以下让我们看看模拟器是如何跟踪游戏程序的。
打开BATGBA,看看DEBUG菜单下的内容,第一项是ENABLE,开始跟踪时可别忘选上它,否则跟踪无从谈起。第二项是UPDATE DIALOGS,这是自动刷新功能,当然跟踪时也要选上,否则你只能看到静止不动的程序。第三个选项就是我们的主角,观测功能菜单,在这个菜单中提供了10个不同的观测对象,我们主要用到的是最上面两个对象,CPU和DISASM。让我们选择这两个对象,这时候我们看见如下的两个窗口:
(图片1)ARM7TDMI CPU窗口,你一眼就可以认出来,这个窗口表示的就是我们上文提到的GBA使用的那15个寄存器R0-R15,没错。既然所有的程序都必须经由寄存器才能与处理器交互,那么我们要找的地址也不例外,那些08XXXXXXH表示的地址都会在这些寄存器中出现,你只要在跟踪过程中从这些寄存器窗口中抓到它就可以了。
(图片2)ARM7TDMI ARM/THUMB DISASM窗口,就是将GBA内存中的数据反汇编成ARM汇编语言的窗口。通过这个窗口,我们可以以汇编语言的形式而不是二进制代码的形式来观察程序的运行过程,这大大方便了我们了解游戏是如何运行的。不论是字库显示程序,解压缩程序还是图片调用程序都需要在内存中运行,这些程序会被反编译成ARM的汇编指令在这个窗口显示,找到这些程序就是我们跟踪的目的。
下面我们以GBA游戏拿破伦传为例来看看怎样找到这个游戏中一个图片文件在ROM中的位置:
(图片3)是我们需要找到图片文件,思考这样一个问题,GBA是通过哪几个步骤来完成这个图片的显示的?首先,GBA先将图片文件从ROM中读入内存,然后调用图象解析程序来处理这个图片文件,最后输出到显示屏上显示。我们暂时不考虑它的解析和输出过程,只要抓到它读取图片文件时的过程就可以找到它读取ROM的位置。那么它从哪里开始这个过程的呢?让我们看看这幅图片显示前的状态。
(图片4)是游戏里的一个选择菜单,当我们选择指挥官设定选项时,游戏随即显示我们需要跟踪的那个图片,也就是说,从你按下按键开始到(图片3)开始显示的这个过程中即包含了游戏调用图片文件的过程,我们就从这里来寻找图片文件在ROM中的地址数据。
BATGBA提供了4种不同的跟踪模式,STEP INTO(F7),STEP OVER(F8),STEP LINE(F9),STEP FRAME(F10)这4种模式对应不同的程序运行流程,大家先不要深究它们,先这样理解,GBA在执行程序时是一条语句一条语句执行的,这4种模式对应不同的中断模式,打个比方说STEP FRAME(F10)是程序执行100条停止一次,STEP LINE(F9)是执行10条停止一次,而STEP OVER(F8)和STEP INTO(F7)则是每执行一条就停止一次。当然还有一个中断程序的方法,就是按(F4)键。你可以在游戏运行中的任何时候中断游戏。有了这5种中断模式我们就可以在游戏执行时在需要的地方暂停游戏来观察此时GBA寄存器和内存中的东东,也许你要找的图片地址就在其中。
上文我们已经圈定了我们跟踪的范围,从你按下按键开始到(图片3)开始显示,这个过程只有短短的几秒钟,打开模拟器载入游戏,然后进入(图片4)的菜单。这时打开ARM7TDMI CPU窗口和ARM7TDMI ARM/THUMB DISASM窗口,你可以看到此刻寄存器和内存中的全部内容,但是好象没找到象08XXXXXXH这样的数据啊?别着急,在(图片4)的菜单中选择指挥官设定选项,在你按下按键的同时立即按(F4)键,这时游戏停止了,我们的跟踪旅程也就从此开始,上文我们讲到的4种中断模式中的STEP OVER(F8)和STEP INTO(F7)是单步跟踪模式,我们随便选一种,比如STEP INTO(F7),在你再次按下(F4)的同时按下(F7)键。好,我们现在切换到单步跟踪模式了。这时你仔细观察ARM7TDMI ARM/THUMB DISASM窗口,每当我们按一次(F7),窗口里的指针就向下移动一格,这表明游戏程序已经执行了一步。看看ARM7TDMI CPU窗口,寄存器R0-R15里的数值也变化了。可是还是没看见有08打头的数据,慢慢来,继续按(F7),观察ARM7TDMI CPU窗口里寄存器里的数值,我保证你一定会看到以08开头的数据,记下你见到的所有08XXXXXX样子的数据,直到模拟器窗口显示出(图片3)为止。这时你也许已经记下了许多以08开头的数据,这里面肯定包括(图片3)的地址,但哪个才是真的呢?简单,使用UltraEdit打开游戏的ROM文件,我们前面说过了,GBA把ROM里的地址都映射到08000000H之后,那么将你找到的数据转化成ROM里的地址的方法就是将开头的08变成00,比如你找到一个08123456的数据,那么它在ROM中表示的地址就是00123456H。将你记下的数据都按这种方法转换成ROM中的地址,然后在UltraEdit找到对应的地址下随便修改几个字节,保存。再用模拟器打开修改后的ROM。看看(图片3)是不是变样了?没有,再换下一个地址试试,直到找到一个地址[我可以告诉你这个地址是:00759E37H在UltraEdit修改后(图片3)变样了,那么恭喜你,你已经找到你需要的东西了。
说到这里,你已经学会了使用最简单的方法跟踪了。但如果你真的按我上面说的一步一步跟踪程序的话,你一定会累死!别小看这短短几秒,其实程序已经执行了成千上万步了。如果一步一步跟踪的话,你一整天也跟不完。先别抱怨,谁让我们是菜鸟呢。便捷的方法当然有,但在你不了解跟踪原理,ARM汇编语言的情况下,这是唯一可行的办法,下面我们就来看看有没有更好的方法来提高效率。不过前提是你必须理解以上所说的内容,会使用单步跟踪来跟踪程序,否则提高无从谈起。
如果你懒的理会那些繁琐复杂的汇编语言,其实可以利用模拟器提供的功能来缩短跟踪范围。记得我们提到的那4个中断模式吗?我们只使用了两个,不是还有两个吗?STEP FRAME(F10)一次中断执行的语句最多。如果用它来跟踪以上过程的话,只需要按几次就可以跟完,但是你很可能会遗漏掉程序读取ROM的过程,毕竟STEP FRAME(F10)中断时的位置不可能正好就在程序读取ROM时。让我们将这几种中断模式组合起来。STEP FRAME(F10)既然一次执行语句最多,让我们先用它来进行一次粗跟踪,假设从你按下按键开始到(图片3)开始显示这个过程一共执行了一万条语句,使用STEP FRAME(F10)跟踪,我们一共执行了10次中断,记下每次中断时寄存器的状态。这样我们就把一万条语句分割成10等份,假设我们估计调用ROM的程序在第9到第10状态之间,先用STEP FRAME(F10)跟踪到第9个状态,然后用STEP LINE(F9)来跟踪。因为STEP LINE(F9)一次执行的语句比STEP FRAME(F10)要少,所以它能跟踪到这两个状态之间的程序。如果使用STEP LINE(F9)还是没找到,就用STEP LINE(F9)将这两个状态再分割成更细的状态,使用单步跟踪来查找。如此我们等于将程序化整为零,如果运气好的话,我们根本不需要从头到尾全部跟踪就可以找到我们需要的图片地址。
可是上述方法还是很笨,而且运气的成分太多。有没有更科学更有效的方法呢?有,当然有,这就是断点设置跟踪。它是目前最有效最科学的跟踪方法。不过要学习这个方法不了解程序和汇编是很难使用好的。让我们先了解一下程序的运行模式。不论是什么游戏程序都具有这样一种特征,假设我们把一个游戏程序看做一个完整的大程序,那么这个大程序就是由若干个功能相对独立的小程序组成的。他们可能是游戏初始化,图象显示,字库调用,文本调用,声音播放等等不同的功能,我们称这些具有相对独立功能的小程序为子程序。一个游戏程序就是由这一个一个子程序相互嵌套组成的。也就是说我们要找的图片调用过程也是子程序的一种,还有字库显示程序,解压缩程序都可以称为子程序。每**程序都是由数量不等的汇编语句构成的。倘若我们能以子程序为单位而不是以单条语句为单位来进行跟踪的话不仅能大大提高效率,同时还能完整的捕获程序的代码,避免了盲目性。那么这些子程序在游戏中使用什么形式表示的呢?让我们以LZ77解压缩程序为例来看看子程序的模式。
引用00000DB4 Ldr r2,[r0],#0x4
00000DB8 mov r2, r2,lsr #0x8
00000DBC mvn r9,#0x0
00000DC0 mov r10,#0x1
00000DC4 mov r6,#0x7
00000DC8 ldrb r3,[r0],#0x1
00000DCC ldrb r8,[r0],#0x1
00000DD0 tst r10,r3,lsr r6
00000DD4 beq 0xE08
00000DD8 mov r5,r8,lsr #0x4
00000DDC add r5,r5,#0x2
00000DE0 sub r2,r2,r5
00000DE4 and r8,r8,#0xF
00000DE8 ldrb r4,[r0],#0x1
00000DEC orr r4,r4,r8,lsl #0x8
00000DF0 add r4,r4,#0x1
00000DF4 ldrb r8,[r1,-r4]
00000DF8 strb r8,[r1],#0x1
00000DFC subs r5,r5,#0x1
00000E00 bpl 0xDF4
00000E04 b 0xE18
00000E08 tst r1,#0x1
00000E0C ldrneb r7,[r1,r9]
00000E10 orrne r8,r7,r8,lsl #0x8
00000E14 strh r8,[r1],#0x1
00000E18 subs r2,r2,#0x1
00000E1C bmi 0xE2C
00000E20 subs r6,r6,#0x1 #
00000E24 bpl 0xDCC
00000E28 b 0xDC4
这就是一段完整的子程序,它具有相对独立完整的功能。让我们实际跟踪一下看看它是如何运行的。找到一个使用LZ77压缩的游戏(如逆转裁判或铸剑物语)用模拟器打开,这时请看ARM7TDMI ARM/THUMB DISASM窗口右上方,是不是有一个BREAK文本框?那就是我们设置断点的地方,先按(F4)键暂停游戏,在这个文本框里输入00000DB4,点击SET按键。好,我们已经设置好一个断点了。再按(F4)键运行游戏,不久游戏就停止在00000DB4处了。然后我们使用(F7)键单步跟踪一下,你会发现窗口里的指针总是在00000DB4-00000E28之间来回循环跳转。这时让我们使用(F4)键中断试试。哈,每按一次,程序就中断到我们设的断点位置,同时观察ARM7TDMI CPU窗口中寄存器的变化你会发现子程序进行了一次循环。这样我们一次中断跟踪就是以一次子程序循环为单位,再也不用逐条语句的看了。象这样的子程序在游戏中随处可见。随便你找个什么游戏,使用单步跟踪观察一下就会发现,ARM7TDMI ARM/THUMB DISASM窗口中的指针总是在一个地址段中循环执行后再跳转到下一个地址段继续循环执行。这样一个连续的循环地址段所包含的语句段都是子程序。那么什么时候程序才能跳出一个循环到下一个循环呢?这就要求你能读懂子程序的跳转条件了。先别着急去读它,我们先总结一下设置断点的步骤,首先找到游戏程序中的一段子程序,然后在子程序开始的位置设置断点,断点的表示方式就是子程序在内存中的地址。
这就是设置断点的跟踪方法,在实际跟踪中我们往往需要综合我们上述讲到的所有方法来协调跟踪。首先圈定你的跟踪范围,在这个范围中使用单步跟踪或分割跟踪先找到一段子程序,在子程序的开始位置设置断点,转换成断点跟踪模式,努力读懂子程序的跳转条件,找到子程序跳转后的位置,再在这个子程序将要跳出循环时使用单步跟踪跟到下一个子程序,再设断点继续跟踪下一段子程序,如此下去,直到你找到需要的图片显示程序或字库显示程序为止。
断点跟踪是不是很奇妙?不过这时你也许会抱怨BATGBA模拟器了,它每次只能设一个断点,有时跳转条件没读懂还容易跟出界。没办法,剑术既然已经高超了,让我们换更好的剑使用。NO$GBA,这个模拟器可以一次设好几个断点,同时允许你自己设定程序运行多少步中断一次,不用担心跟出界了吧?还有CowBite,它允许你倒退跟踪几步来观察程序,这对于寻找子程序跳转位置太有用了,不过它对游戏的兼容性一般。
小结:
ASM跟踪的基本方法我们就讲完了。(什么?这只是基本方法????)没错。真正跟踪的时候光靠这些是不够的,你如何圈定你的跟踪范围,如何判断你找到的地址和程序就是你需要的。这些就有赖于你对汉化其他知识的了解了,字库,文本,图片的结构,压缩算法等等知识。你对游戏汉化了解的越深,跟踪起来就越得心应手。大家也许奇怪我在文档中只字未提ARM汇编语言,原因是想讲清一门语言不是三言两语就能说清的。这需要你平时不断的积累,学习,多读多看程序。那本ARM指令集手册就是最好的教材。你不一定全读懂,能读懂40%再看子程序就容易多了。文中提到的所有技术手册和软件各汉化网站都有下载,还等什么?马上开始你的跟踪之路吧。
|
|