我'm trying to learn about reverse engineering, using Minesweeper as a sample application. I'在一个简单的WinDbg命令中发现了这个MSDN article,它显示了所有的地雷,但是它已经很老了,没有详细解释,真的没有't what I'我正在寻找 .
我有IDA Pro disassembler和WinDbg debugger,我已经将winmine.exe加载到它们中 . 在找到代表矿区的数据结构的位置方面,有人能为这些程序中的任何一个提供一些实用技巧吗?
在WinDbg中我可以设置断点,但是我很难想象在什么时候设置断点和什么内存位置 . 同样,当我在IDA Pro中查看静态代码时,我不知道在哪里开始找到代表矿区的函数或数据结构 .
Stackoverflow上是否有任何反向工程师可以指向正确的方向?
10 回答
第1部分,共3部分
如果你认真对待逆向工程 - 忘记训练师和作弊引擎 .
优秀的逆向工程师应该首先了解操作系统,核心API函数,程序通用结构(什么是运行循环,窗口结构,事件处理例程),文件格式(PE) . Petzold的经典作品“Programming Windows”可以提供帮助(www.amazon.com/exec/obidos/ISBN=157231995X)以及在线MSDN .
首先,您应该考虑可以调用雷区初始化例程的位置 . 我想到了以下几点:
启动游戏时
当你点击快乐的脸
单击游戏 - >新建或按F2
当你改变等级难度时
我决定查看F2加速器命令 .
要查找加速器处理代码,您需要查找窗口消息处理过程(WndProc) . 它可以通过CreateWindowEx和RegisterClass调用来追踪 .
阅读:
CreateWindowEx http://msdn.microsoft.com/en-us/library/ms632680%28VS.85%29.aspx
RegisterClass http://msdn.microsoft.com/en-us/library/ms633586%28VS.85%29.aspx
Petzold的第3章"Windows and Messages"
打开IDA,Imports窗口,找到“CreateWindow *”,跳转到它并使用“Jump xref to operand(X)”命令查看它的调用位置 . 应该只有一个电话 .
现在看一下RegisterClass函数和它的参数WndClass.lpfnWndProc . 在我的例子中,我已经将函数mainWndProc命名为 .
在函数名称上按Enter键(使用'N'将其重命名为更好的东西)
现在来看看
这是消息ID,在按下F2按钮的情况下应该包含WM_COMMAND值 . 你要找到它与111h的比较 . 可以通过在IDA中追踪edx或在WinDbg中按setting conditional breakpoint并在游戏中按F2来完成 .
无论哪种方式都会导致类似的东西
右键单击111h并使用“符号常量” - >“使用标准符号常量”,键入WM_和Enter . 你现在应该有
这是一种查找消息ID值的简便方法 .
要了解加速器处理,请查看:
Using Keyboard Accelerators
资源黑客(http://angusj.com/resourcehacker/)
单个答案的文字相当多 . 如果你有兴趣,我可以写另外几篇文章 . 长故事短雷区存储为字节数组[24x36],0x0F表示不使用字节(播放较小字段),0x10 - 空字段,0x80 - 我的 .
第2部分,共3部分
好吧,让我们继续使用F2按钮 .
按Using Keyboard Accelerators按F2按钮时按下wndProc功能
好的,我们已经找到了WM_COMMAND的处理位置,但是如何确定相应的wParam参数值?这是Resource hacker发挥作用的地方 . 用二进制文件提供它,它会显示所有内容 . 像加速器表对我来说 .
alt text http://files.getdropbox.com/u/1478671/2009-07-29_161532.jpg
你可以在这里看到,F2按钮对应于wParam中的510 .
现在让我们回到处理WM_COMMAND的代码 . 它将wParam与不同的常量进行比较 .
使用上下文菜单或“H”键盘快捷键显示小数值,您可以看到我们的跳转
它导致代码块调用一些proc并退出wndProc .
这是启动新游戏的功能吗?在最后一部分找到它!敬请关注 .
第3部分,共3部分
我们来看看该函数的第一部分
有两个值(dword_10056AC,uValue)读入寄存器eax和ecx,并与另外两个值(dword_1005164,dword_1005338)进行比较 .
使用WinDBG('bp 01003696';中断'p eax; p ecx')查看实际值 - 它们对我来说似乎是雷区维度 . 玩自定义雷区尺寸显示第一对是新尺寸和第二尺寸 . 让我们设置新名称 .
稍后,新值将覆盖当前和子例程
当我看到它
我完全相信我找到了雷区阵列 . 循环的原因在于具有0xF的360h字节长度数组(dword_1005340) .
为什么360h = 864?下面有一些提示,该行占用32个字节,864可以除以32,因此数组可以容纳27 * 32个单元格(尽管UI允许最大24 * 30字段,但是对于边框,数组周围有一个字节填充) .
以下代码生成雷区顶部和底部边框(0x10字节) . 我希望你能在那个混乱中看到循环迭代;)我不得不使用纸和笔
其余子程序绘制左右边界
智能使用WinDBG命令可以为您提供很酷的雷区转储(自定义大小9x9) . 看看边框!
嗯,看起来我需要另一个帖子才能结束这个话题
看起来您正在尝试反汇编源代码,但您需要做的是查看正在运行的程序的内存空间 . 十六进制编辑器HxD有一个功能,可以让你这样做 .
http://www.freeimagehosting.net/uploads/fcc1991162.png http://www.freeimagehosting.net/uploads/fcc1991162.png
一旦进入内存空间,就可以在使用电路板时拍摄内存快照 . 隔离哪些更改与哪些更改 . 如果您认为数据结构位于十六进制内存中的位置,请尝试在内存中进行编辑,并查看该板是否因此而更改 .
您想要的过程与为视频游戏构建“培训师”并没有什么不同 . 这些通常基于找到像 Health 和弹药这样的值存在于记忆中并在运行中更改它们的位置 . 您可以找到一些关于如何构建游戏培训师的好教程 .
查看此代码项目文章,它比您提到的博客文章更深入一些 .
http://www.codeproject.com/KB/trace/minememoryreader.aspx
编辑
这篇文章虽然不是直接关于扫雷,但是通过WinDbg为你提供了一个关于通过内存搜索的一步一步的指导:
http://www.codingthewheel.com/archives/extracting-hidden-text-with-windbg
编辑2
同样,这不是关于扫雷,但它确实给了我一些思考我的记忆调试,这里有很多教程:
http://memoryhacking.com/forums/index.php
另外,下载CheatEngine(由Nick D.提及)并完成它附带的教程 .
究竟!
那么,您可以查找在构建mines表期间将调用的例如random()的例程 . 当我在进行逆向工程实验时,这个book给了我很多帮助 . :)
一般来说,设置断点的好地方是调用消息框,调用播放声音,定时器和其他win32 API例程 .
顺便说一下,我现在用OllyDbg扫描扫雷 .
Update: nemo提醒我一个伟大的工具,Cheat Engine由Eric "Dark Byte" Heijnen .
Cheat Engine(CE)是观察和修改其他进程内存空间的绝佳工具 . 除了这个基本功能外,CE还具有更多特殊功能,例如查看进程的反汇编内存以及将代码注入其他进程 .
(该项目的真正 Value 在于您可以下载源代码-Delphi-并了解这些机制是如何实现的 - 我多年前就这样做了:o)
关于这个主题的一篇非常好的文章可以在Uninformed找到 . 它涵盖了逆转扫雷(作为逆向工程Win32应用程序的介绍)非常精细,并且都是一个非常好的资源 .
这个网站可能会更有帮助:
http://www.subversity.net/reversing/hacking-minesweeper
这样做的一般方法是:
不知何故得到源代码 .
反汇编并希望剩下的符号可以帮到你 .
猜测数据类型并尝试操作它并使用内存扫描程序来限制可能性 .
In response to Bounty
好吧,在第二次阅读时,似乎你想要一个如何使用像WinDBG这样的调试器的指南,而不是通常的逆向工程问题 . 我已经向您展示了告诉您需要搜索的值的网站,所以问题是,您如何搜索它?
我在这个例子中使用记事本,因为我没有安装Minesweeper . 但是想法是一样的 .
你输入
按“?”然后按“s”查看帮助 .
一旦找到所需的内存模式,就可以按alt 5调出内存查看器以获得良好的显示效果 .
WinDBG需要一些时间来适应,但它与其他任何调试器一样好 .
在调试器中开始跟踪的一个好处是鼠标向上 . 所以找到主窗口程序(我认为像spyxx这样的工具可以检查windows属性,事件处理程序地址就是其中之一) . 闯入它并找到它处理鼠标事件的位置 - 如果你能在汇编程序中识别它,就会有一个开关(在windows.h中查看WM_XXX的值是否为鼠标) .
在那里放置一个断点并开始踩踏 . 在释放鼠标按钮和屏幕更新之间的某个时间点,victum将访问您正在寻找的数据结构 .
要有耐心,尝试确定在任何给定时间正在做什么,但不要太费力地看待你怀疑对你目前的目标无趣的代码 . 在调试器中可能需要多次运行才能确定它 .
了解正常的win32应用程序工作流程也有帮助 .
地雷可能会存储在某种二维阵列中 . 这意味着它既可以是指针数组,也可以是单个C样式的布尔数组 .
每当表单收到鼠标悬停事件时,都会引用此数据结构 . 索引将使用鼠标坐标计算,可能使用整数除法 . 这意味着您应该查找
cmp
或类似的指令,其中一个操作数使用偏移量计算x
,其中x
是涉及整数除法的计算结果 . 然后,偏移量将是指向数据结构开头的指针 .假设关于地雷的信息在存储器中至少对于行(即,它是2D阵列或阵列阵列)连续布局是相当合理的 . 因此,我会尝试打开同一行中的几个相邻单元格,按照我的方式对进程进行内存转储,然后对它们进行差异化并查找同一内存区域中的任何重复更改(即第一步更改1个字节,下一步字节在下一步变为完全相同的值,等等 .
它也有可能是一个打包的位阵列(每个3位应该足以记录所有可能的状态 - 关闭/打开,我的/不打雷,标记/非标记),所以我也会注意这一点(这些模式也是可重复的,但更难以发现 . 但它不是一个方便的结构,我不认为内存使用是扫雷的瓶颈,所以不太可能使用这种东西 .
虽然不是严格意义上的"reverse engineer's tool",而且更像玩具甚至像我这样的白痴都可以使用,请查看Cheat Engine . 它可以很容易地跟踪内存的哪些部分已经改变,何时,甚至有通过指针跟踪已更改的内存部分的规定(尽管你可能不需要) . 包括一个很好的互动教程 .