如何在内存中找到代表扫雷的矿山布局的数据结构?

Kin*_*tor 93 windbg reverse-engineering memory-editing ida minesweeper

我正在尝试学习逆向工程,使用Minesweeper作为示例应用程序.我在一个简单的WinDbg命令上发现了这篇MSDN文章,它揭示了所有的地雷,但它已经很老了,没有详细解释,也不是我想要的.

我有IDA Pro反汇编程序WinDbg调试程序,我已经将winmine.exe加载到它们中.在找到代表矿区的数据结构的位置方面,有人能为这些程序中的任何一个提供一些实用技巧吗?

在WinDbg中我可以设置断点,但是我很难想象在什么时候设置断点和什么内存位置.同样,当我在IDA Pro中查看静态代码时,我不知道在哪里开始找到代表矿区的函数或数据结构.

Stackoverflow上是否有任何反向工程师可以指向正确的方向?

小智 123

第1部分,共3部分


如果你认真对待逆向工程 - 忘记训练师和作弊引擎.

优秀的逆向工程师应该首先了解操作系统,核心API函数,程序通用结构(什么是运行循环,窗口结构,事件处理例程),文件格式(PE).Petzold的经典作品"Programming Windows"可以提供帮助(www.amazon.com/exec/obidos/ISBN=157231995X)以及在线MSDN.

首先,您应该考虑可以调用雷区初始化例程的位置.我想到了以下几点:

  • 当你启动游戏时
  • 当你点击快乐的脸
  • 单击游戏 - >新建或按F2时
  • 当你改变等级难度

我决定查看F2加速器命令.

要查找加速器处理代码,您需要查找窗口消息处理过程(WndProc).它可以通过CreateWindowEx和RegisterClass调用来追踪.

阅读:

打开IDA,Imports窗口,找到"CreateWindow*",跳转到它并使用"Jump xref to operand(X)"命令查看它的调用位置.应该只有一个电话.

现在看一下RegisterClass函数和它的参数WndClass.lpfnWndProc.在我的例子中,我已经将函数mainWndProc命名为.

.text:0100225D                 mov     [ebp+WndClass.lpfnWndProc], offset mainWndProc
.text:01002264                 mov     [ebp+WndClass.cbClsExtra], edi
.text:01002267                 mov     [ebp+WndClass.cbWndExtra], edi
.text:0100226A                 mov     [ebp+WndClass.hInstance], ecx
.text:0100226D                 mov     [ebp+WndClass.hIcon], eax

.text:01002292                 call    ds:RegisterClassW
Run Code Online (Sandbox Code Playgroud)

在函数名称上按Enter键(使用'N'将其重命名为更好的东西)

现在来看看

.text:01001BCF                 mov     edx, [ebp+Msg]
Run Code Online (Sandbox Code Playgroud)

这是消息ID,在按下F2按钮的情况下应该包含WM_COMMAND值.你要找到它与111h的比较.可以通过在IDA中追踪edx或在WinDbg中设置条件断点并在游戏中按F2来完成.

无论哪种方式都会导致类似的东西

.text:01001D5B                 sub     eax, 111h
.text:01001D60                 jz      short loc_1001DBC
Run Code Online (Sandbox Code Playgroud)

右键单击111h并使用"符号常量" - >"使用标准符号常量",键入WM_和Enter.你现在应该有

.text:01001D5B                 sub     eax, WM_COMMAND
.text:01001D60                 jz      short loc_1001DBC
Run Code Online (Sandbox Code Playgroud)

这是一种查找消息ID值的简便方法.

要了解加速器处理,请查看:

单个答案的文字相当多.如果你有兴趣,我可以写另外几篇文章.长故事短雷区存储为字节数组[24x36],0x0F表示不使用字节(播放较小字段),0x10 - 空字段,0x80 - 我的.

第2部分,共3部分


好吧,让我们继续使用F2按钮.

根据使用键盘加速器按下F2按钮时wndProc功能

...收到WM_COMMAND或WM_SYSCOMMAND消息.wParam参数的低位字包含加速器的标识符.

好的,我们已经找到了WM_COMMAND的处理位置,但是如何确定相应的wParam参数值?这就是资源黑客发挥作用的地方.用二进制文件提供它,它会显示所有内容.像加速器表对我来说.

alt text http://files.getdropbox.com/u/1478671/2009-07-29_161532.jpg

你可以在这里看到,F2按钮对应于wParam中的510.

现在让我们回到处理WM_COMMAND的代码.它将wParam与不同的常量进行比较.

.text:01001DBC HandleWM_COMMAND:                       ; CODE XREF: mainWndProc+197j
.text:01001DBC                 movzx   eax, word ptr [ebp+wParam]
.text:01001DC0                 mov     ecx, 210h
.text:01001DC5                 cmp     eax, ecx
.text:01001DC7                 jg      loc_1001EDC
.text:01001DC7
.text:01001DCD                 jz      loc_1001ED2
.text:01001DCD
.text:01001DD3                 cmp     eax, 1FEh
.text:01001DD8                 jz      loc_1001EC8
Run Code Online (Sandbox Code Playgroud)

使用上下文菜单或"H"键盘快捷键显示小数值,您可以看到我们的跳转

.text:01001DBC HandleWM_COMMAND:                       ; CODE XREF: mainWndProc+197j
.text:01001DBC                 movzx   eax, word ptr [ebp+wParam]
.text:01001DC0                 mov     ecx, 528
.text:01001DC5                 cmp     eax, ecx
.text:01001DC7                 jg      loc_1001EDC
.text:01001DC7
.text:01001DCD                 jz      loc_1001ED2
.text:01001DCD
.text:01001DD3                 cmp     eax, 510
.text:01001DD8                 jz      loc_1001EC8 ; here is our jump
Run Code Online (Sandbox Code Playgroud)

它导致代码块调用一些proc并退出wndProc.

.text:01001EC8 loc_1001EC8:                            ; CODE XREF: mainWndProc+20Fj
.text:01001EC8                 call    sub_100367A     ; startNewGame ?
.text:01001EC8
.text:01001ECD                 jmp     callDefAndExit  ; default
Run Code Online (Sandbox Code Playgroud)

这是启动新游戏的功能吗?在最后一部分找到它!敬请关注.

第3部分,共3部分

我们来看看该函数的第一部分

.text:0100367A sub_100367A     proc near               ; CODE XREF: sub_100140C+CAp
.text:0100367A                                         ; sub_1001B49+33j ...
.text:0100367A                 mov     eax, dword_10056AC
.text:0100367F                 mov     ecx, uValue
.text:01003685                 push    ebx
.text:01003686                 push    esi
.text:01003687                 push    edi
.text:01003688                 xor     edi, edi
.text:0100368A                 cmp     eax, dword_1005334
.text:01003690                 mov     dword_1005164, edi
.text:01003696                 jnz     short loc_10036A4
.text:01003696
.text:01003698                 cmp     ecx, dword_1005338
.text:0100369E                 jnz     short loc_10036A4
Run Code Online (Sandbox Code Playgroud)

有两个值(dword_10056AC,uValue)读入寄存器eax和ecx,并与另外两个值(dword_1005164,dword_1005338)进行比较.

使用WinDBG('bp 01003696';中断'p eax; p ecx')查看实际值 - 它们对我来说似乎是雷区维度.使用自定义雷区尺寸显示第一对是新尺寸和第二尺寸.让我们设置新名称.

.text:0100367A startNewGame    proc near               ; CODE XREF: handleButtonPress+CAp
.text:0100367A                                         ; sub_1001B49+33j ...
.text:0100367A                 mov     eax, newMineFieldWidth
.text:0100367F                 mov     ecx, newMineFieldHeight
.text:01003685                 push    ebx
.text:01003686                 push    esi
.text:01003687                 push    edi
.text:01003688                 xor     edi, edi
.text:0100368A                 cmp     eax, currentMineFieldWidth
.text:01003690                 mov     dword_1005164, edi
.text:01003696                 jnz     short loc_10036A4
.text:01003696
.text:01003698                 cmp     ecx, currentMineFieldHeight
.text:0100369E                 jnz     short loc_10036A4
Run Code Online (Sandbox Code Playgroud)

稍后,新值将覆盖当前和子例程

.text:010036A7                 mov     currentMineFieldWidth, eax
.text:010036AC                 mov     currentMineFieldHeight, ecx
.text:010036B2                 call    sub_1002ED5
Run Code Online (Sandbox Code Playgroud)

当我看到它

.text:01002ED5 sub_1002ED5     proc near               ; CODE XREF: sub_1002B14:loc_1002B1Ep
.text:01002ED5                                         ; sub_100367A+38p
.text:01002ED5                 mov     eax, 360h
.text:01002ED5
.text:01002EDA
.text:01002EDA loc_1002EDA:                            ; CODE XREF: sub_1002ED5+Dj
.text:01002EDA                 dec     eax
.text:01002EDB                 mov     byte ptr dword_1005340[eax], 0Fh
.text:01002EE2                 jnz     short loc_1002EDA
Run Code Online (Sandbox Code Playgroud)

我完全相信我找到了雷区阵列.循环的原因在于具有0xF的360h字节长度数组(dword_1005340).

为什么360h = 864?下面有一些提示,该行占用32个字节,864可以除以32,因此数组可以容纳27*32个单元格(尽管UI允许最大24*30字段,但是对于边框,数组周围有一个字节填充).

以下代码生成雷区顶部和底部边框(0x10字节).我希望你能在那个混乱中看到循环迭代;)我不得不使用纸和笔

.text:01002EE4                 mov     ecx, currentMineFieldWidth
.text:01002EEA                 mov     edx, currentMineFieldHeight
.text:01002EF0                 lea     eax, [ecx+2]
.text:01002EF3                 test    eax, eax
.text:01002EF5                 push    esi
.text:01002EF6                 jz      short loc_1002F11    ; 
.text:01002EF6
.text:01002EF8                 mov     esi, edx
.text:01002EFA                 shl     esi, 5
.text:01002EFD                 lea     esi, dword_1005360[esi]
.text:01002EFD
.text:01002F03 draws top and bottom borders
.text:01002F03 
.text:01002F03 loc_1002F03:                            ; CODE XREF: sub_1002ED5+3Aj
.text:01002F03                 dec     eax
.text:01002F04                 mov     byte ptr MineField?[eax], 10h ; top border
.text:01002F0B                 mov     byte ptr [esi+eax], 10h       ; bottom border
.text:01002F0F                 jnz     short loc_1002F03
.text:01002F0F
.text:01002F11
.text:01002F11 loc_1002F11:                            ; CODE XREF: sub_1002ED5+21j
.text:01002F11                 lea     esi, [edx+2]
.text:01002F14                 test    esi, esi
.text:01002F16                 jz      short loc_1002F39
Run Code Online (Sandbox Code Playgroud)

其余子程序绘制左右边界

.text:01002F18                 mov     eax, esi
.text:01002F1A                 shl     eax, 5
.text:01002F1D                 lea     edx, MineField?[eax]
.text:01002F23                 lea     eax, (MineField?+1)[eax+ecx]
.text:01002F23
.text:01002F2A
.text:01002F2A loc_1002F2A:                            ; CODE XREF: sub_1002ED5+62j
.text:01002F2A                 sub     edx, 20h
.text:01002F2D                 sub     eax, 20h
.text:01002F30                 dec     esi
.text:01002F31                 mov     byte ptr [edx], 10h
.text:01002F34                 mov     byte ptr [eax], 10h
.text:01002F37                 jnz     short loc_1002F2A
.text:01002F37
.text:01002F39
.text:01002F39 loc_1002F39:                            ; CODE XREF: sub_1002ED5+41j
.text:01002F39                 pop     esi
.text:01002F3A                 retn
Run Code Online (Sandbox Code Playgroud)

智能使用WinDBG命令可以为您提供很酷的雷区转储(自定义大小9x9).看看边框!

0:000> db /c 20 01005340 L360
01005340  10 10 10 10 10 10 10 10-10 10 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f  ................................
01005360  10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f  ................................
01005380  10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f  ................................
010053a0  10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f  ................................
010053c0  10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f  ................................
010053e0  10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f  ................................
01005400  10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f  ................................
01005420  10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f  ................................
01005440  10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f  ................................
01005460  10 0f 0f 0f 0f 0f 0f 0f-0f 0f 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f  ................................
01005480  10 10 10 10 10 10 10 10-10 10 10 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f  ................................
010054a0  0f 0f 0f 0f 0f 0f 0f 0f-0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f  ................................
010054c0  0f 0f 0f 0f 0f 0f 0f 0f-0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f  ................................
010054e0  0f 0f 0f 0f 0f 0f 0f 0f-0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f  ................................
Run Code Online (Sandbox Code Playgroud)

嗯,看起来我需要另一个帖子才能结束这个话题

  • 此外,史诗回答斯坦尼斯拉夫.非常感谢您的辛勤工作! (2认同)

Jam*_*hon 15

看起来您正在尝试反汇编源代码,但您需要做的是查看正在运行的程序的内存空间.十六进制编辑器HxD有一个功能,可以让你这样做.

http://www.freeimagehosting.net/uploads/fcc1991162.png http://www.freeimagehosting.net/uploads/fcc1991162.png

一旦进入内存空间,就可以在使用电路板时拍摄内存快照.隔离哪些更改与哪些更改.如果您认为数据结构位于十六进制内存中的位置,请尝试在内存中进行编辑,并查看该板是否因此而更改.

您想要的过程与为视频游戏构建"培训师"并没有什么不同.这些通常基于找到像健康和弹药这样的值存在于记忆中并在运行中更改它们的位置.您可以找到一些关于如何构建游戏培训师的好教程.

  • 好吧,你可以通过静态反汇编找到内存位置.您可以按照汇编指令进行操作,查找调用rand()函数以生成矿场,然后从那里进行跟踪以查看该字段存储在内存中的位置(以及如何). (2认同)

Kir*_*ein 11

查看此代码项目文章,它比您提到的博客文章更深入一些.

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.提及)并完成它附带的教程.


Nic*_*kis 9

"在WinDbg中,我可以设置断点,但是我很难想象在什么时候设置断点和内存位置.同样,当我在IDA Pro中查看静态代码时,我不确定从哪里开始找到代表矿场的功能或数据结构."

究竟!

那么,您可以查找在构建mines表期间将调用的例如random()的例程.当我试验逆向工程时,这本书给了我很多帮助.:)

一般来说,设置断点的好地方是调用消息框,调用播放声音,定时器和其他win32 API例程.

顺便说一句,我现在用OllyDbg扫描扫雷.

更新: nemo让我想起了一个很棒的工具,由Eric"Dark Byte"Heijnen创作的Cheat Engine.

Cheat Engine(CE)是观察和修改其他进程内存空间的绝佳工具.除了这个基本功能外,CE还具有更多特殊功能,例如查看进程的反汇编内存以及将代码注入其他进程.

(该项目的真正价值在于您可以下载源代码-Delphi-并了解这些机制是如何实现的 - 我多年前就这样做了:o)


mrd*_*law 5

关于这个话题的一篇非常好的文章可以在Uninformed上找到.它涵盖了逆转扫雷(作为逆向工程Win32应用程序的介绍)非常精细,并且都是一个非常好的资源.