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

C++程序反编译笔记(19) 雷区数据结构分析

2023-01-10 21:24 作者:GC_CH  | 我要投稿

    我们接着上文继续分析点击菜单的处理代码.

    

    点击某个菜单项后窗口会收到WM_COMMAND消息, 上文已经将这个消息的处理代码放到了OnCommand函数中, 其中WPARAM参数的低2个字节是菜单项的ID.

分析菜单代码

    

        开局菜单项的ID是520, 那里调用了sub_100367A这个函数, 里面全是不认识的全局变量, 不适合现在分析.

    初级, 中级, 高级 三个菜单项的ID分别是521, 522, 523. 整理了一下它们的处理代码后

    这里直接将dword_10056A0命名为g_level_10056A0了, 我猜测是用0, 1, 2表示3个游戏难度, 起一个有意义的名字方便分析. 即使错了也没关系, 后面再改个名字就行了.

    从这里可以看出来, 这三个数组都应该至少有7个元素, 那么看一下它们的定义

    这三个数组都只有一个元素, 明显存在数组越界的问题. 而且这3个数组的后缀地址只相差4个字节(int在Windows系统中是4个字节), 说明前两个数组确实只有一个元素. 这就矛盾了.

    解决这个矛盾的唯一办法是将三个数组和并成一个, 实际上对第2个和第3个数组的访问是在访问第1个数组的第2个和第3个元素, v8可能的值是0, 3, 6, 那么这个数组的长度至少是6 + 2 + 1 = 9(索引从0开始, +1得到数组长度). 这说明IDA 将数组长度识别错了. 修正后的代码如下

    如果对数组和指针比较熟悉的话, 这里的转换应该不难理解. 使用的公式是

    array[index] = *(array + index)

    上图中, 拿uValue = dword_1005014[v8] 来解释一下的话, 就是

原来的 uValue 是 从 1005014 + v8 * 4 的地址处取值,

修改后的 uValue 是从 1005010 + (v8 + 1) * 4 = 1005010 + 4 + v8 * 4 = 1005014 + v8 * 4处取值. 

    所以, 修改前的代码和修改后的代码等价.

修正数组越界

    在IDA 中 按G跳转到1005010 处, 将这个变量命名为g_gameLevelSetting, 并右键菜单点击 "Array... ", 然后将数组长度设置为9. 然后用"Edit"菜单下的"Export Data"菜单项导出数组

    在Visual Studio中, 使用导出的数组替换原来的三个数组并修正编译错误即可.

成果

    在这篇文章中, 如果细心的话, 会发现有个成果还蛮让人欢喜的. 那就是导出的9个元素的数组, 3个元素一组, 第1个元素是地雷个数, 第2个元素雷区宽度, 第3个元素是雷区长度.

    比如, 点击"高级"菜单时, v8 = 2 * 3 = 6,  那么dword_1005010[6] = 99 时地雷个数, dword_1005010[7] = 16是雷区宽度, dword_1005010[8] = 40是雷区长度.

    因此, 可以知道dword_1005010就是预定义的雷区数据. 到此已经接触到扫雷的数据结构了!

    

C++程序反编译笔记(19) 雷区数据结构分析的评论 (共 条)

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