欢迎光临散文网 会员登陆 & 注册

C++程序反编译笔记(20) 解决扫雷"乱码"问题

2023-01-16 22:40 作者:GC_CH  | 我要投稿

    目前的游戏界面是这样的

    

绘制地雷数目的代码

    前文已经分析出 sub_1002AC3 是绘制整个游戏界面的函数.

    并且通过注释掉某个函数的观察界面的方法了解了内部调用的各个函数的作用. 边框基本上是没有什么问题的, 因此从绘制地雷数目的代码入手.

    

    知道了函数是做什么的, 那么就给它起一个易于理解的名字. DrawPixels 也是我起的名字, 因为它只调用了系统函数将图片数据绘制到窗口上, 因此起了这个名字.

    这个函数的看上去是没什么问题的. 而DrawMineCount函数需要判断一下有没有问题. 观察原来的好的程序界面.

    可以发现这个显示的是 3 个数字.  对比代码, 显然对DrawPixels的三次调用时依次绘制3个数字. 分析 v3 以确定 DrawPixels 的第3个参数, 首先 v3 = dword_1005194 % 100; , 可以得出 v3 是 dword_1005194 的个位和十位, 而 v3 / 10 是 dword_1005194 的十位, v3 % 10 是 dword_100519 的个位, 那么 dword_1005194 肯定就是当前存在的地雷数目了, DrawPixels 的第3个参数是要绘制的数字.

    运行代码, 在这个调用DrawPixels的地方下断点, 可以发现与分析相符.

寻找"乱码"源头

    既然 DrawMineCount 函数没有错误, 那么DrawPixels肯定有错, 因此绘制地雷数目的代码只调用到了这两个.

    可能出错的变量有2个 g_bmpInfoNumber 和 dword_1005A60.

    g_bmpInfoNumber  是从资源中读取的像素数据, 不太可能出问题. 重点放在dword_1005A60 上. dword_1005A60 只有一处赋值点.

    还记得最开始解决项目的编译错误时, 有很多个未初始化的变量吗? 当初的解决方法是将它们全部初始化为0, v11 就是这样的一个变量. 那么几乎可以确定是v11的初值出现了问题.

内嵌汇编

    要知道v11的初值, 只能看汇编代码了.

    上图中 ,v11 的初值来自于ecx,  ecx的值可能来自顺序执行下来的, 也可能来自于跳转过来的. 但是仔细分析, 可以看到, 只有 loc_10024F1 下面的一段代码给 ecx 赋值了. 观察函数代码, 发现并没有对这段汇编代码的反编译. 所以, 错误的原因是IDA Pro没有反编译出这段代码.

    一个简单的办法是将这段汇编代码内嵌到C++代码中, 这样就不必了解每个指令的具体含义了. 只提取与ECX有关的代码就行了.

    

        __asm{} 语句就是用于内嵌汇编代码的, 汇编代码中, 第一句和最后一句是我自己加的, 开始前将ECX的值入栈, 最后出栈, 目的是不修改ECX原来的值, 只使用计算结果就行了. 要知道的一点是, 源程序的汇编代码和反编译后再编译回去的汇编代码几乎是不可能相同的.

成果

    内嵌汇编后再运行项目.

    可以看到, 游戏界面已经能正常显示了, 游戏也可以正常运行了.

C++程序反编译笔记(20) 解决扫雷"乱码"问题的评论 (共 条)

分享到微博请遵守国家法律