Emulator 板


LINE

【杂言】 我有点後悔写这系列文章了....比我预想的还难写(抱头 先说明一下,因为我不可能从计算机概论或写编译器谈起, 所以这系列的经验谈是假定读者有资工背景或具基本程式能力。 反组译这边则最好有修过组合语言或系统程式这类课程,具备基本概念即可。 一般来说,资工大三~大四学生应该就具备充足知识了.....。 之前三篇中提到的工具我并没有解释如何使用,因为那是自己花时间摸一下就会用的。 但这篇的反组译模拟器我会稍微提一下用法,因为这边有些"经验上"的用法。 【正文】 ~PART I. Rom、Ram、VRam~ 跟中文化有关系的SFC记忆体是Rom、Ram跟VRam。 Rom应该都知道了,就是包含程式与资料的游戏"软体"部分 (实际是存放在卡匣硬体上,这点就跟存放在光碟中的软体一样)。 Ram则是用来放置游戏记录与暂存资料的地方, SFC会用7E:0000~7F:FFFF这个特殊SFC位址来代表Ram里的资料位置。 所以SFC的金手指码"基本上"都是7E、7F开头,就是为了处理Ram里的数值。 我们也随时可以用snes9x v1.43.ep9r8将游戏目前Ram的内容dump出来。 http://0rz.tw/cT4l6 (第一个红框应该在Dump Ram,不是Dump Palette,我画错了) VRam则是存放显示在萤幕上的内容。 根据游戏设计不同,最多会有4个图层与一些sprites....。 (如果是用Snes9X的玩家,在游戏中按数字键1~5就能看出图层来) VRam在每个图层上要显示的东西都会分成两部分: (1)8x8为单位的图块(tile): 依模式不同每个点有可能是2bits~4bits(4色~16色)显示。 基本上这些就像一块块可重复使用的拼图。 (2)每个位置要使用的图块编号: 萤幕上(严格讲是某图层或sprites)由左到右、由上到下依序使用的图块编号。 相当於是指明萤幕上(严格讲是某图层或sprites)每个地方要用什麽图块。 (以前做的示意图 http://0rz.tw/NgBGU ) 就结果而言,要看到萤幕上有什麽字就代表VRam里有该文字的图块, 并在要显示的位置给图块编号(不是字库代码)。 这些图块即便是每个点以2bits(4色)显示的8x8最小文字图, 也要用到16 bytes的连续资料来显示。因此游戏时常会用DMA的方式, 直接把未压缩的连续文字图资料一口气在Rom、Ram、VRam间搬运,提升处理速度。 (DMA的写法很重要,以後会用实例解释,现在先有个印象就好) 以流程来说,要完成文字的显示工作,我"看过还有印象的"主要有4种方式: (1)Rom --(解压、挑字)--> Ram --(整个字串)--> VRam 这可能使用在"使用字库较大,并显示名词文本"的情况下。 因为名词长度一般了不起8个字,但因为字库太大, 所以先在Rom里依使用顺序挑出字图,复制到Ram里成为字串图, 再把Ram里整个字串图复制到VRam显示出来。 若是有压缩的字图就要先解压,再一个一个byte放进Ram里, 若是未压缩的字图就DMA直接整个字图传进Ram里,效率相对较高。 有时剧情文字也会用这种方式处理。 (2)Rom --(解压、挑字)--> Ram --(挑字)--> VRam 这可能使用在"使用字库较大,并显示剧情文本"的情况下。 在Ram里排成字串图会发生的问题就是...有些字会重复被使用。 因为Ram里还要放一堆其他图像、数据,所以其实没太多空间浪费。 如果一段对话很长,这时可以把会用到的字图挑"一份"到Ram里, 再根据剧情代码从这个"Ram里的小字库"挑字图到VRam显示出来。 有时非字库的文字图也会用这种方式处理,例如皇骑1的地图名称。 (3)Rom --(挑字)--> VRam 这相当於是上面的简化版,直接从Rom里依序挑字到VRam。 但可能因为速度慢(从Rom挑越多字越慢)或因为文字图必须未经压缩, 感觉不常被使用在剧情文字。可能用在指令名称等显示在固定位置的内容。 (4)Rom --(解压、整个字库)--> Ram --(挑字)--> VRam 这可能使用在字库够小的情况,特别是游戏只有使用平、片假名,没几个汉字时, 可以轻松地把整个字库全塞到Ram里。之後只要看文本代码用到哪些字, 再依序拷贝到VRam就行,对游戏而言可说是最方便的了..... .....然後做中文化的就泪目了T____T 如果看到某些SFC汉化游戏改不出"只有平、片假名的小字库",那可能卡这边了。 (或是代码数量不足等其他原因.....也可能只是单纯反组译不熟 XD) 因为这部份我不会提出实例(解释不完),所以我把我在皇骑1的处理概念解释一下: <i>想办法拆成对应不同条件的小字库: 例如皇骑1战斗时可以切换成有动画或无动画,攻击名称会因而有所差别。 所以我可以把所有攻击名称会用到的中文字,重新分成两个不同小字库, 各别对应有动画跟无动画两种情形。 这样只要在原架构下,写段函式去判断这时是有动画或无动画, 再依情况载入不同的小字库就行。 缺点是....拆出来的小字库都要小於原字库,且可能发生代码重复使用的问题, 也就是人名、道具名等需要统一代码的地方不适合使用。 但如果只是指令名或是人名、道具名不多的情况就还蛮好用的。 <ii>简单说.....就是想办法硬干成(1): 例如皇骑1的状态画面有可能显示上千种不同人名、道具名、职业名.... 字库最少要700个中文字,而且也没额外条件好拆字库时.....就只好吐血吧。 先在Ram里找一块没被使用的空间,写个函式把当下用到的中文字图 依序写到前述的空间,另外要同时计算目前写了几个字图到Ram里。 写完後再把所有的字图依序复制成为VRam里特定位置的图块, 并将原本显示日文的位置所对应的编号,固定成特定位置开始的连续编号。 这样不管字库多大,理论上都能"动态地"从Rom里挑字图到Ram, 再从Ram复制字串到"固定的"VRam位置。 光是要让皇骑1状态画面不受限地显示中文,我就多加了10几个函式。 因为这边其实还同时并发8x8显示与代码数量不足这两个问题。 不然我通常将一个地方改中文化,只需要加1~3个函式,这里真的改太大.... ~Part II. 反组译log档~ 所谓的反组译,简单来说就是把0与1机械码实际运作的过程(机器看得懂,人看不懂), 改用较高阶、精简的指令集与16进位数字表现出来(也就是组合语言)。 相对於程式码是给人看、机械码是给电脑看,组合语言就介於中间。 因为每行都相当於是机器硬体上的一个简单动作,所以会比高阶程式语言琐碎得多。 我们先来看看怎麽用snes9x v1.43.ep9r8将游戏中的运作过程dump出来。 载入Rom档後,按下右边debuger介面中的Run键,开始游戏。 根据需求上的不同,有两种方式决定何时开始dump: (1)不知道资料在Rom里位址的情况: 例如,当我想把ロシュフォル教会改成中文,但却找不到这些字在Rom的哪里时, 可以在文字出现前的画面,先去右边debuger介面勾选Loggin下的cpu栏, 再把滑鼠移到游戏视窗,立即按键显示出目标"ロシュフォル教会"。 再马上取消掉debuger介面中cpu栏的勾选,就会dump出勾选其间的组语代码, (上述动作越快越好,因为一秒就会dump出几十MB的组语代码.....) 并存在与Rom同一资料夹下的"Rom档名0000.log"。 http://0rz.tw/hgpPL 在这种情况下要知道确切的相关程式开始位置比较麻烦, 如果知道现在显示文字的代码,可以用这代码在log档中搜寻。 如果不知道可以搜寻何时有DMA的动作,或是观察VRam中的变化, 再反推相关程式的开始位置(以後会给实例说明)。 (2)知道资料在Rom里位址的情况: 按下介面中的Breakpoints键,贴上位址并勾选3个中断时机, 当游戏对该位址资料进行读写时就会自动中断停止, 这时按下Step Over键就会开始一行一行执行指令。 http://0rz.tw/yLJAr 配合(1)用UltraEdit搜寻这几行指令在log档的位置, 就知道相关程式从何处开始,不用在几十MB的组语代码中大海捞针。 这时我们终於得到log档,甚至知道程式大概从哪里开始。 把(1)中例子的log档打开来看,即使在我缓慢的准系统上只跑了一秒, 就产生了20MB的庞大log资料,每个栏位代表的意义如下: (省略後面不重要的部分,"无视"那栏的暂存器我没遇过要改的情况,故...无视) SFC位址 机器码 组语代码 A暂存 X暂存 Y暂存 无视 bank ======== ======== ===================== ====== ====== ====== ====== ===== $00/BC7F E8 INX A:FF01 X:001C Y:5555 D:0000 DB:00 $00/BC80 E8 INX A:FF01 X:001D Y:5555 D:0000 DB:00 $00/BC81 E0 28 00 CPX #$0028 A:FF01 X:001E Y:5555 D:0000 DB:00 $00/BC84 90 E2 BCC $E2 [$BC68] A:FF01 X:001E Y:5555 D:0000 DB:00 $00/BC68 DA PHX A:FF01 X:001E Y:5555 D:0000 DB:00 $00/BC69 20 8C BC JSR $BC8C [$00:BC8C] A:FF01 X:001E Y:5555 D:0000 DB:00 $00/BC8C 86 1C STX $1C [$00:001C] A:FF01 X:001E Y:5555 D:0000 DB:00 $00/BC8E A9 01 LDA #$01 A:FF01 X:001E Y:5555 D:0000 DB:00 $00/BC90 8D 5E 16 STA $165E [$00:165E] A:FF01 X:001E Y:5555 D:0000 DB:00 .....(略) SFC位址: 目前的指令位址$oo/xxxx,oo是第oo个bank,xxxx是该bank里的位址。 机器码: 实际执行的二进位指令码,只是在此以16进位表示比较容易看。 一个基本的SFC指令会包含1~4个bytes,第1个byte一定是指令本身的代号。 第2~4个byte(如果有的话)都是资料内容。 组语代码:即使机器码用16进位表示也只是"变短",很难记住这机器码对应什麽指令。 所以需要用组合语言的方式来简单表示指令与资料内容。 我随便拿上面例子来解释,例如.... ‧INX 表示X暂存器的值加1。 ‧CPX #$0028 表示把X暂存器的值跟数字0x0028做比较 (#$表示资料就是"数字",只有$的话表示资料是"位址内的值")。 ‧BCC $E2 表示前面比较结果是"小於"的话,移动0xe2的距离。 因为读了2个bytes,所以现在程式指标位址是0x00bc84 + 2 = 0x00bc86。 移动距离是0xe2-0x100(0xe2是负数)=向前移0x1e, 也就是移到0x00bc86-0x1e=0x00bc68的位址。 如果前面比较结果是"大於等於"的话,就略过继续处理0x00bc86的指令。 [$BC68]是反组译器提供的额外资讯,表示这边程式指标跳到0x00bc68。 ‧PHX 表示把X值放到堆叠(stack)中。 ‧JSR $BC8C 表示跳到同一个bank中,位址0xbc8c的位址。 後面[ ]的内容一样是反组译器提供的额外资讯.... ‧STX $1C 表示把X暂存器的内容存到同bank中,位址0x001c的位址。 ‧LDA #$01 表示把数值0x01载入A暂存器中。 ‧STA $165E 表示把A暂存器中的内容存到同bank中,位址0x165e的位址。 熟悉的话,只要看到组语代码就能知道每行在干什麽。 不熟悉的话可以参考我第一篇提到的网页,里面有所有指令代码的解释。 A暂存: SFC主要有3个2 bytes暂存器:A、X跟Y。 A暂存器是功能较强的,可以做加减、AND、OR、shift、比大小等工作。 大部分数学运算会在A暂存器里完成。 X、Y暂存:这两个暂存器比较算辅助性质,只能做"加1"等少数极基本功能。 经常用来辅助A暂存器,完成一些较复杂的计算或资料搬运功能。 bank值: 之前有说过程式执行时不太会切换bank,如此可以提升程式执行效率。 从 JSR $BC8C 这例子可以看出来,即使实际要跳过去的位址是0x00bc8c, 最前面00这个bank值却被省略了,连带也有效节省了指令长度 。 =========================================================================== ....先写到这边吧,下周再给实际的中文化例子。 看看如何解读log档,并且加上新的函式来突破原本程式的限制。 中间有些概念如果有错的话,也随时欢迎指正。 --



※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 118.161.167.231
1F:推 tonybin:先谢再推 11/24 17:44
2F:推 tonybin:後面关於反组译的说明 真是受教了 11/24 17:52
3F:推 ADHI:喔喔,越来越艰深专业了,感谢分享!! 11/24 18:27
4F:推 qazxswptt:太神了 感谢留下记录给後人参考 11/24 23:46
5F:推 EDGE: 太神了,看不懂还是要推…身为OB的爱好者非常感谢您 11/25 01:09
6F:推 busin:专业文推~ 11/25 03:04
※ 编辑: lulaptt 来自: 118.161.167.231 (11/25 09:08)
7F:推 dansha:推专业 11/25 10:27
8F:推 jachen168:推~ 11/25 21:32
9F:推 willkill:不推不行 11/25 22:11
10F:推 djboy:神文推! 11/26 09:42
11F:推 oginome:大推~ 11/26 12:17
12F:推 conpo:专业好文推,长知识! 11/26 13:03







like.gif 您可能会有兴趣的文章
icon.png[问题/行为] 猫晚上进房间会不会有憋尿问题
icon.pngRe: [闲聊] 选了错误的女孩成为魔法少女 XDDDDDDDDDD
icon.png[正妹] 瑞典 一张
icon.png[心得] EMS高领长版毛衣.墨小楼MC1002
icon.png[分享] 丹龙隔热纸GE55+33+22
icon.png[问题] 清洗洗衣机
icon.png[寻物] 窗台下的空间
icon.png[闲聊] 双极の女神1 木魔爵
icon.png[售车] 新竹 1997 march 1297cc 白色 四门
icon.png[讨论] 能从照片感受到摄影者心情吗
icon.png[狂贺] 贺贺贺贺 贺!岛村卯月!总选举NO.1
icon.png[难过] 羡慕白皮肤的女生
icon.png阅读文章
icon.png[黑特]
icon.png[问题] SBK S1安装於安全帽位置
icon.png[分享] 旧woo100绝版开箱!!
icon.pngRe: [无言] 关於小包卫生纸
icon.png[开箱] E5-2683V3 RX480Strix 快睿C1 简单测试
icon.png[心得] 苍の海贼龙 地狱 执行者16PT
icon.png[售车] 1999年Virage iO 1.8EXi
icon.png[心得] 挑战33 LV10 狮子座pt solo
icon.png[闲聊] 手把手教你不被桶之新手主购教学
icon.png[分享] Civic Type R 量产版官方照无预警流出
icon.png[售车] Golf 4 2.0 银色 自排
icon.png[出售] Graco提篮汽座(有底座)2000元诚可议
icon.png[问题] 请问补牙材质掉了还能再补吗?(台中半年内
icon.png[问题] 44th 单曲 生写竟然都给重复的啊啊!
icon.png[心得] 华南红卡/icash 核卡
icon.png[问题] 拔牙矫正这样正常吗
icon.png[赠送] 老莫高业 初业 102年版
icon.png[情报] 三大行动支付 本季掀战火
icon.png[宝宝] 博客来Amos水蜡笔5/1特价五折
icon.pngRe: [心得] 新鲜人一些面试分享
icon.png[心得] 苍の海贼龙 地狱 麒麟25PT
icon.pngRe: [闲聊] (君の名は。雷慎入) 君名二创漫画翻译
icon.pngRe: [闲聊] OGN中场影片:失踪人口局 (英文字幕)
icon.png[问题] 台湾大哥大4G讯号差
icon.png[出售] [全国]全新千寻侘草LED灯, 水草

请输入看板名称,例如:BabyMother 或 站内搜寻

TOP