有关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:字模数据


生成字库C#代码

        /// <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文本)

测试结果如下


⑥发现写得好简略,下次有时间写详细点吧

附带已导入的游戏(下载地址:这里)

注:这个是白底黑字,还有个方框字.


原创粉丝点击