火焰之纹章吧 关注:289,735贴子:4,668,909

【研究】关于火纹GBA三作哈夫曼编码的新发现[改版相关][多图]

只看楼主收藏回复

艾瑞珂镇楼。



IP属地:广东1楼2015-03-06 18:38回复
    前言:
      我从上个星期开始学习火纹的改版,这篇文章包含我学习过程中的一些体会和(新)发现。期间我遇到了不少困难,经过了数天的努力,我终于在编程语言(Java)的层次上,实现了火纹哈夫曼编码的编码和解码的方法。选择用Java来实现是因为Java比较容易理解和可读性强,移植到安卓和C#方便一些。因为我走了不少弯路,所以我想尽量用正式一点的文字把我的经历写出来。我将一步步讲解我解出这个算法的经过,文章有点长,其中部分内容涉及一些计算机编程基础和二进制基础,可能会有点难理解。


    IP属地:广东2楼2015-03-06 18:38
    回复
      2025-07-29 10:16:33
      广告
      不感兴趣
      开通SVIP免广告
        如果您只是普通的玩家,对rom内部的东西不感兴趣,可以忽略此文;如果你有兴趣和耐心往下看,却发现本文写得太笼统不够详细,可以在楼中楼回复吐槽,但在楼主更完前请不要插楼,不然容易乱。


      IP属地:广东3楼2015-03-06 18:39
      收起回复
        而且,能破解火纹哈夫曼压缩算法的话,不仅仅是实现一个简单的转换程序,


        IP属地:广东6楼2015-03-06 18:45
        收起回复
            还能做到一些先前做不到的事,例如:
            1. 直接在修改器中读取ROM中的文本


          IP属地:广东7楼2015-03-06 18:47
          回复
              2. 查看及导出ROM中的文本列表,通过文本列表,可以方便的找到应该修改的文本指针地址。




            IP属地:广东8楼2015-03-06 18:48
            收起回复
                3. 改版时使用压缩的文字,不过正常人应该不会在意这一点点空间的吧...


              IP属地:广东9楼2015-03-06 18:50
              回复
                  图为我上周开始开发的手机版火纹GBA三作静态修改器,不过还有一些细节待完善,还不打算在这里发布,不然还有人看帖吗?你猜的没错,我在这楼贴图是设置悬念,吸引读者兴趣。


                IP属地:广东10楼2015-03-06 18:51
                回复
                  2025-07-29 10:10:33
                  广告
                  不感兴趣
                  开通SVIP免广告
                    我继续逛着贴吧和火花论坛,终于,我找到了无聊之士的那篇完整帖子(地址见附录)。幸运的是,无聊之士在帖子中的结论前面贴出了他追踪火纹程序时的追踪记录,包括几个汇编程序段和注释。但是,当时我还没接触过汇编语言,在阅读了几遍无聊之士写的注释后,我确定这正是我所需要的。尤其是这句(无聊之士贴出的程序是以铁剑为例的):
                    strb r6, r6, [r1, 0h] 《-----每查到一个要求的字后该字存入[202A6A8+(N-1)*2],例如第1个字指针是90 ,BD 分别存入202A6A8,202A6A9
                    我用的圣魔rom中“铁”字的码表编码是90C2,与上面说的90BD十分接近,原因就是上面说过的我们用的rom版本不一样。也就是说火纹查字程序直接通过rom中的哈夫曼编码得到码表编码!明白这点后,我又跟着结论中的做法做了一遍,真的成功把“铁剑”改成了“剑铁”以及“铁铁”。


                  IP属地:广东12楼2015-03-06 18:54
                  回复
                      于是我下决心要看汇编入门来看懂那几段汇编程序。我一边看着汇编手册,一边然后尝试一条一条代码来阅读,一边还用16进制计算器和16进制编辑器计算结果来推测代码的作用。花了半天多的时间,那几段程序我反复阅读了不下二十遍,还重写了一遍注释。终于大体上读懂那几段程序了,但是还有几个细节不明白,因为程序中用了两层while循环,不亲自追踪一遍的话,就无法理解了。
                      NO$GBA的调试功能之强大让我十分感动。尤其是它可以同时设置多个断点,就能切换断点来方便定位到需要的运行时刻。我一边看着NO$GBA中的汇编片段,一边提前一步用16进制计算器计算下一条语句的结果,当每次看到寄存器中的结果和我计算的一样时,我别提有多高兴了。


                    IP属地:广东13楼2015-03-06 18:57
                    回复
                        三、反推程序
                        当执行到这个断点的时候,当看到右下方寄存器r6的值变成FFFFC290(按字节转置后就是90C2,前面都是F说明这是负数。rom中的哈夫曼解压程序就是通过判断找到的节点的值是否是负数来判断是不是码表编码的,下面会详细说)时,我无比激动。


                      IP属地:广东14楼2015-03-06 18:59
                      回复
                        好贴,还不知道这些事呢,不过很有兴趣,但是知识不够+智商捉急看着真心晕啊


                        15楼2015-03-06 19:04
                        回复
                            先插一段关于指针表的发现作为铺垫:
                            在《纳格尔法尔的fe修改教程》——剧情文字修改中提到了“文本指针表”概念,再通过上面说过的汇编程序可以发现:
                            火纹GBA三作都是在rom的0x000006DC处储存文本指针表的指针的,例如用16进制编辑器打开圣魔的rom定位到6DC处,显示是88 d0 14 08,读出指针0x0814d088,

                            再定位到rom的0x0014d088处,可以发现后面的数据都是指针。

                            但是0x0014d088处又存储了另外一个重要的指针——字符频率结尾的指针,所以文本指针表实际是从0x0014d088+4=0x0014d08C开始的。
                            用日版文字修改器打开圣魔的rom,下拉框选取“艾瑞珂”的序号0199,可以找到文字序号对应的指针:080F969D。而指针表是紧密排列的,每个指针占4个字节,因此可以得到文本指针地址的计算公式:0814d08C+序号*4,例如:0814d08C+0199*4=0814D6F0,在16进制编辑器中定位到0014D6F0,发现数据是9d 96 0f 08,和日版文字修改器的结果一致。


                          IP属地:广东16楼2015-03-06 19:06
                          回复
                            补16楼的图:


                            IP属地:广东17楼2015-03-06 19:12
                            回复
                              2025-07-29 10:04:33
                              广告
                              不感兴趣
                              开通SVIP免广告
                                全部弄明白每一步的语义后我开始通过汇编反推程序,由于我比较粗心,加之这个程序中跳转和循环中断有点复杂。我又花了半天时间才将程序核心部分逆向出来并调试到能用,变量名取和寄存器相同名称是为了调试方便,因为还要和NO$GBA的调试结果核对。程序代码如下:



                              IP属地:广东18楼2015-03-06 19:16
                              回复