第1部分 共3部分
如果您是认真进行逆向工程的人-请忘记训练器和作弊引擎。
优秀的逆向工程师应该首先了解操作系统、核心API函数、程序的一般结构(运行循环、窗口结构、事件处理例程)、文件格式(PE)。Petzold经典著作“Windows编程”可以提供帮助(www.amazon.com/exec/obidos/ISBN=157231995X),还有在线MSDN。
首先,您应该考虑地雷场初始化例程可能被调用的位置。我想到以下几点:
- 当您启动游戏时
- 当您点击笑脸时
- 当您单击“游戏”->“新建”或按F2键时
- 当您更改级别难度时
我决定查看F2加速器命令。
要找到加速器处理代码,您需要找到窗口消息处理过程(WndProc)。它可以通过CreateWindowEx和RegisterClass调用来跟踪下来。
阅读:
打开IDA,进入Imports窗口,找到"CreateWindow*"函数,在其上跳转到操作数(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
在函数名称上按Enter键(使用“N”将其重命名为更好的名称)
现在看一下
.text:01001BCF mov edx, [ebp+Msg]
这是消息ID,在按下F2按钮时应包含WM_COMMAND值。您需要找到它与111h进行比较的位置。可以通过在IDA中跟踪edx或在WinDbg中
设置条件断点并在游戏中按下F2来完成。无论哪种方式,都会导致类似以下内容:
.text:01001D5B sub eax, 111h
.text:01001D60 jz short loc_1001DBC
右键单击111h,使用“符号常量” -> “使用标准符号常量”,输入WM_并按Enter。现在您应该拥有
.text:01001D5B sub eax, WM_COMMAND
.text:01001D60 jz short loc_1001DBC
这是一种简单的查找消息id值的方法。
要了解加速键处理,请查看:
-
使用键盘加速键
- 资源编辑器(
http://angusj.com/resourcehacker/)
这是一篇单个答案的相当长的文本。如果您有兴趣,我可以再写几篇文章。长话短说,地雷存储为字节数组[24x36],0x0F表示该字节未使用(在更小的区域内),0x10表示空位,0x80表示地雷。
第2部分,共3部分。
好的,让我们继续使用F2按钮。
根据使用键盘加速器,当按下F2按钮时,wndProc函数会接收到WM_COMMAND或WM_SYSCOMMAND消息。wParam参数的低位字包含加速器的标识符。
... 接收到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:
.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
使用上下文菜单或'H'键快捷方式显示十进制值,您可以看到我们的跳跃
.text:01001DBC HandleWM_COMMAND:
.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
它会导致调用某个过程并退出wndProc的代码块。
.text:01001EC8 loc_1001EC8: ; CODE XREF: mainWndProc+20Fj
.text:01001EC8 call sub_100367A ; startNewGame ?
.text:01001EC8
.text:01001ECD jmp callDefAndExit ; default
这是启动新游戏的函数吗?最后一部分会有答案!敬请关注。
第三部分(共三部分)
让我们来看看该函数的第一部分。
.text:0100367A sub_100367A proc near
.text:0100367A
.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
有两个值(dword_10056AC,uValue)读入寄存器eax和ecx,并与另外两个值(dword_1005164,dword_1005338)进行比较。
使用WinDBG查看实际值(“bp 01003696”;在中断时“p eax; p ecx”)-它们对我来说就像地雷场的尺寸。通过自定义地雷场大小进行游戏,发现第一对是新尺寸,第二对是当前尺寸。让我们设置新名称。
.text:0100367A startNewGame proc near
.text:0100367A
.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
稍后,新的值将覆盖当前值,并调用子程序。
.text:010036A7 mov currentMineFieldWidth, eax
.text:010036AC mov currentMineFieldHeight, ecx
.text:010036B2 call sub_1002ED5
当我看到它时
.text:01002ED5 sub_1002ED5 proc near
.text:01002ED5
.text:01002ED5 mov eax, 360h
.text:01002ED5
.text:01002EDA
.text:01002EDA loc_1002EDA:
.text:01002EDA dec eax
.text:01002EDB mov byte ptr dword_1005340[eax], 0Fh
.text:01002EE2 jnz short loc_1002EDA
我完全确定我找到了地雷阵列。因为循环将360h字节长度的数组(dword_1005340)初始化为0xF。
为什么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:
.text:01002F03 dec eax
.text:01002F04 mov byte ptr MineField?[eax], 10h
.text:01002F0B mov byte ptr [esi+eax], 10h
.text:01002F0F jnz short loc_1002F03
.text:01002F0F
.text:01002F11
.text:01002F11 loc_1002F11:
.text:01002F11 lea esi, [edx+2]
.text:01002F14 test esi, esi
.text:01002F16 jz short loc_1002F39
其余的子程序绘制左右边框。
.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:
.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:
.text:01002F39 pop esi
.text:01002F3A retn
聪明地使用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 ................................
嗯,看起来我需要另一篇文章来关闭这个话题