有关The Last Promise的汉化②改写程序
来源:互联网 发布:linux服务器常用命令 编辑:程序博客网 时间:2024/05/16 15:40
①,必须要懂得汇编
说简单,是简单,说复杂呢,也那么复杂
我所用的编码识别是参照国外的hack方法出来的
;我们用Thumb指令,比较简单些@Thumb;;此处,我将用09CFADD1代替,新手可直接将从5BA2开始 0A 48 03 68;;然后在地址5BCC 修改成 D1 AD CF 09ldrr0,=#0x09CFADD1;自定义程序首地址,一定要为首地址+1,表示Thumb程序,此段在实际中会有出入,自己适当的修改bxr0;跳转,或者mov r15,r0;;我们只修改以上8个字节,,贪方便,区分自定义程序lsl r0,r0,0lslr0,r0,0lsl r0,r0,0lsl r0,r0,0;;自定义程序;;我们先执行曾经改写的程序;;用goldroad1.7编译后,用16进制编辑器从此段bin(0D 48 03 68)开始复制到结尾;;在ROM的地址01CFADD0开始粘贴完ldrr0,=#0x2028D70ldrr3,[r0]ldrr2,[r3,#4]ldrbr1,[r4];;一下判断 字符编码的值,这里我们用GB 2312;cmpr1,#0xa1bgegbk;;如果是小于,则执行ldrr1,=#0x8005BA9;跳回原程序bxr1;;GB程序;;我们要判断原程序中有哪几个寄存器是要覆盖的;;或者,你可以把sp转移到没有数据的地址;;分别是,r1,r2,r0,;;竟然只有三个可用.....;;r2为字库首地址.gbklslr1,r1,#2addr1,r1,r2ldrbr2,[r4+#1]addr4,#2;;循环判断编码2的所有比较.loopldrr1,[r1]movr0,#9lslr0,r0,#0x18;用来判断是否为rom地址andr0,r1cmpr0,#0beq.NUldrbr0,[r1,#4];;这里我们读取字首地址+4(作为编码2),因为+5为字宽度cmpr2,r0beqend;;首地址+4为编码2时,跳出此循环bneloop.NUmovr1,#0.endldrr2,[r3,#4];返回状态ldrr0,=#0x8005BB3;返回原程序bxr0
程序返回原来的程序时,r1=字模首地址
用goldroad1.7编译此汇编
②然后用16进制编辑器把,一些数据导入进去变化如图
好了,自定义程序写好了.
③运行后,发现没有任何问题,但是我们的字库并未导入,所以编码还是有问题.这里我们将写入字库
经分析:
字模首地址+0:下一个字模指针字模首地址+4:字模编码2字模首地址+5:字模宽度字模首地址+8:字模数据
/// <summary> /// 图新转换成2 /// </summary> /// <param name="b">图形</param> /// <param name="data">输出数据</param> public static void map2bit2(Bitmap b, out byte[] data) { data = new byte[0x40]; int index = 0; int bitIn = 0; byte[] C = new byte[] { 0, 3 }; //这里为四色,因为嫌麻烦,我取消了阴影 int Ci = 0; //颜色索引 for (int Y = 0; Y < 16; Y++) for (int X = 0; X < 16; X++) { Ci = (b.GetPixel(X, Y).ToArgb() == 0) ? 0 : 1; //当有颜色是,索引值为1. data[index] |= (byte)(C[Ci] << (bitIn * 2)); //进行位运算 bitIn++; if (bitIn > 3) { bitIn = 0; index++; } } } /// <summary> /// 写入指针,ROM的指针,循环发现有空指针,在空指针出写上新的指针, /// </summary> /// <param name="fs">文件</param> /// <param name="Y">编码2</param> /// <param name="Xbase">编码1的指针</param> /// <param name="baseOff">字库首地址</param> /// <param name="Newoff">新指针</param> public static void WritePoint(FileStream fs,byte Y,int Xbase,int baseOff, int Newoff) { byte[] data = new byte[5]; int off = Xbase; while (true) { Xbase = off - baseOff; fs.Position = Xbase; fs.Read(data, 0, 5); off = BitConverter.ToInt32(data, 0); if (off == 0) { fs.Position = Xbase; fs.Write(BitConverter.GetBytes(Newoff + baseOff), 0, 4); break; } if (data[4] == Y) break; } } /// <summary> /// 写入数据 /// </summary> /// <param name="fs">文件</param> /// <param name="off">地址</param> /// <param name="data">数据</param> public static void WriteData(FileStream fs, int off,byte[] data) { fs.Position = off; fs.Write(data, 0, data.Length); } void creatBin() { FileStream Bin = new FileStream(@"D:\Tile.bin",FileMode.OpenOrCreate); Bitmap map = new Bitmap(@"D:\000001.png"); //博客中某篇文章的图片 Bitmap Tile; Graphics g; byte X, Y; byte[] data; //生成的数据 int baseOff = 0x09CFAE30; //ROM中自定义字库的基址 int newDataOff = 20; //新数据的指针 int[] Xoff = new int[0xf7 - 0xb0+1]; //初始化编码1的指针,这里适应文件 bool b = true; for (Y = 0xA1; Y <= 0xfe; Y++) for (X = 0xB0; X <= 0xF7; X++) { Tile = new Bitmap(16, 16); g = Graphics.FromImage(Tile); g.DrawImage(map, new Rectangle(0, 0, 16, 16), new RectangleF((Y - 0xA1) * 16, (X - 0xB0) * 16, 16, 16), GraphicsUnit.Pixel); map2bit2(Tile, out data); //转换出数据,请看上面的函数 if (b) //第一次运行时,要初始化编码1的指针,后面就不用在初始化了 { Xoff[X - 0xB0] = newDataOff; } else { WritePoint(Bin,Y, Xoff[X - 0xB0]+baseOff, baseOff, newDataOff); //写入新指针,并且在指针地址写入数据 } WriteData(Bin,newDataOff+4,new byte[]{Y,14}); //写入编码2的值,和宽度,最好是13,14是为了安全显示 WriteData(Bin, newDataOff + 8, data); //写入数据 if (X == 0xf7) b = false; newDataOff += 0x50; //其中包括 下一个字指针,编码2,宽度,数据 g.Dispose(); } Bin.Close(); }
生成好后,你就要查找检验字库是否正确
/// <summary> /// 查找字库的指针 /// </summary> /// <param name="fs">文件</param> /// <param name="Y">编码2</param> /// <param name="Xbase">编码1的指针+字库基址</param> /// <param name="baseOff">字库基址</param> /// <returns></returns> public static int searchData(FileStream fs, byte Y, int Xbase, int baseOff) { fs.Seek(0, SeekOrigin.Begin); byte[] data = new byte[5]; int off = Xbase; while (true) { Xbase = off - baseOff; fs.Position = Xbase; fs.Read(data, 0, 5); off = BitConverter.ToInt32(data, 0); if (off == 0) return 0; if (data[4] == Y) break; } return Xbase; }
④以上,我们生成好字库后
因为我们采用0x01CFAE30为基址,所以在0x01CFAE30处把生成好的bin数据全粘贴
⑤虽说,我们改写了程序,又导入了字库,那么成功了吗?
答案是,并没有成功,因为我们找到的一段程序中:
过程大概是,
字模 = 字指针基地址+(编码1值*4),数据如图
在下方,所有指针都为空,表示没有任何指针,不出现字符
这时我们重新写入指针
生成bin文件
private void ceateBinPont() { FileStream Bin = new FileStream(@"D:\TilePoint.bin",FileMode.OpenOrCreate); int[] Xoff = new int[0xf7 - 0xb0 + 1]; //所有指针 for(int Y=0;Y<Xoff.Length;Y++) { Xoff[Y] = Y * 0x50 + 20; Bin.Write(BitConverter.GetBytes(Xoff[Y] + 0x9CFAE30), 0, 4); //0x9CFAE30为字库基址 } Bin.Close(); }
因为编码1的值是0xb0-0xf7,所以计算得出指针偏移,(0xb0*4)+0xB8B5B0 = 0xB8B870
把bin数据从0xB8B870导入进去
好了,现在终于完成导入工作了
查找"A man with a strong"(注:这是The Last Promise 版本的主角说明,随意修改成GBK文本)
测试结果如下
⑥发现写得好简略,下次有时间写详细点吧
附带已导入的游戏(下载地址:这里)
注:这个是白底黑字,还有个方框字.
- 有关The Last Promise的汉化②改写程序
- 有关The Last Promise的汉化①<国外高手的FE7 hack版>
- 测试程序的改写
- 程序的自动改写
- 程序的自我改写
- 程序的自我改写
- 改写Hadoop的wordcount程序
- ClamWin杀毒程序的改写
- Java程序的汉化
- the promise
- 有关birt报表汉化的问题
- 有关Zend studio 5 的汉化方法
- 有关几种排序算法的改写(JAVA实现)
- 确定的世界 - The Promise's World
- [JS]把函数改写为Promise
- The Last Samurai 最后的武士**
- 有关程序的发布
- 有关扑克的程序
- OpenGL ES着色器语言之着色概览(官方文档第二章)
- OpenGl 资料
- 千万级并发实现的秘密:内核不是解决方案,而是问题所在!
- OCI调用存储过程
- FindBugs 错误信息汇总
- 有关The Last Promise的汉化②改写程序
- Ceph操作——监视OSD和PG
- 【PAT Advanced Level】1021. Deepest Root (25)
- sql 语句记录
- 利用GoAhead构建嵌入式web应用
- Jquery的高级应用总结
- OpenGL ES着色器语言之语言基础(官方文档第三章)
- spring的bean的init-method和 destroy-method=
- 提高eclipse运行速度