fatwolf08 发表于 2010-2-13 18:20:47

乱弹《是男人就下一百层》之外挂分析

【标题】乱弹《是男人就下一百层》之外挂分析
【作者】fatwolf08
【主页】http://hi.baidu.com/fatwolf08
【工具】OD
【平台】WinXP
------------------------------------------------------------------------
【分析过程】
   以前玩过这个游戏,可惜始终没到过一百层。看了xiaobaozi49老兄的扫雷外挂制作的文章,学到了不少东西,动手实践实践,才有了这篇菜文,因水平有限只能乱弹。

浮躁的2009就要过去了,不知道来年是不是还这么浮躁,每个人总要经历那么几个阶段。闲言少叙,言归正传。

首先找窗口的过程函数,根据xiaobaozi49老兄的方法,找到RegisterClass函数来确定过程函数地址,BP RegisterClassA下断点,断下后,ALT+F9,返回到下面的代码:

00401C10    8D45 D8         lea   eax, dword ptr
00401C13    50            push    eax
00401C14    FF15 7C514900   call    dword ptr [<&user32.#535>]         ; USER32.RegisterClassA
00401C1A    0FB7C0          movzx   eax, ax

CALL之前入栈的EAX中的值就是WNDCLASS类的指针:0012FEC8,窗口类偏移四个字节保存的就是窗口过程函数,我这是:401C96。跳转到401C96,向下拖动,找到消息判断的代码:

00401F72    837D F8 06      cmp   dword ptr , 6               ;
00401F76    0F87 1F000000   ja      00401F9B
00401F7C^ 0F84 E6FDFFFF   je      00401D68
00401F82    837D F8 01      cmp   dword ptr , 1
00401F86^ 0F84 0BFEFFFF   je      00401D97
00401F8C    837D F8 02      cmp   dword ptr , 2
00401F90^ 0F84 2AFEFFFF   je      00401DC0
00401F96^ E9 B7FFFFFF   jmp   00401F52
00401F9B    817D F8 0001000>cmp   dword ptr , 100             ; WM_KEYDOWN
00401FA2    0F87 15000000   ja      00401FBD
00401FA8^ 0F84 54FEFFFF   je      00401E02
00401FAE    837D F8 0F      cmp   dword ptr , 0F            ;
00401FB2^ 0F84 FCFEFFFF   je      00401EB4
00401FB8^ E9 95FFFFFF   jmp   00401F52
00401FBD    817D F8 1101000>cmp   dword ptr , 111             ; WM_COMMAND
00401FC4    0F87 18000000   ja      00401FE2
00401FCA^ 0F84 03FEFFFF   je      00401DD3
00401FD0    817D F8 0101000>cmp   dword ptr , 101             ; WM_KEYUP
00401FD7^ 0F84 52FEFFFF   je      00401E2F
00401FDD^ E9 70FFFFFF   jmp   00401F52
00401FE2    817D F8 0102000>cmp   dword ptr , 201             ; WM_LBUTTONDOWN
00401FE9    0F87 18000000   ja      00402007
00401FEF^ 0F84 67FEFFFF   je      00401E5C
00401FF5    817D F8 1301000>cmp   dword ptr , 113             ; WM_TIMER
00401FFC^ 0F84 F4FEFFFF   je      00401EF6
00402002^ E9 4BFFFFFF   jmp   00401F52
00402007    817D F8 1002000>cmp   dword ptr , 210
0040200E    0F87 18000000   ja      0040202C
00402014^ 0F84 ADFEFFFF   je      00401EC7
0040201A    817D F8 0202000>cmp   dword ptr , 202             ; WM_LBUTTONUP
00402021^ 0F84 62FEFFFF   je      00401E89
00402027^ E9 26FFFFFF   jmp   00401F52
0040202C    817D F8 0F03000>cmp   dword ptr , 30F
00402033^ 0F84 E5FEFFFF   je      00401F1E
00402039    817D F8 1103000>cmp   dword ptr , 311
00402040^ 0F84 C7FEFFFF   je      00401F0D
00402046    817D F8 B903000>cmp   dword ptr , 3B9
0040204D^ 0F84 DFFEFFFF   je      00401F32
00402053^ E9 FAFEFFFF   jmp   00401F52
00402058    5F            pop   edi
00402059    5E            pop   esi
0040205A    5B            pop   ebx
0040205B    C9            leave
0040205C    C2 1000         retn    10

在VC查找各个消息值代表的宏,几个有用的我已经标出来了。游戏有简单、一般、困难三个级别,通过菜单来选定,通过玩游戏我们可以知道,不同的级别,出现的障碍物的数量不一样,物体移动的速度也不一样,障碍物的类型应该是通过游戏的级别来算出的。

我们来看一下级别保存在哪里。我们在WM_COMMAND下断点,跟随跳转来到下面的代码:
00401DD3    8B45 10         mov   eax, dword ptr             ; WM_COMMAND
00401DD6    C1E8 10         shr   eax, 10
00401DD9    25 FFFF0000   and   eax, 0FFFF
00401DDE    0FB7C0          movzx   eax, ax
00401DE1    50            push    eax
00401DE2    8B45 14         mov   eax, dword ptr
00401DE5    50            push    eax
00401DE6    8B45 10         mov   eax, dword ptr    菜单序号
00401DE9    25 FFFF0000   and   eax, 0FFFF
00401DEE    50            push    eax                         入栈做参数
00401DEF    8B45 FC         mov   eax, dword ptr
00401DF2    50            push    eax
00401DF3    E8 17090000   call    0040270F                  关键CALL,F7跟进
00401DF8    83C4 10         add   esp, 10
00401DFB    33C0            xor   eax, eax


跟随来到下面的代码:
0040283A    816D FC 419C000>sub   dword ptr , 9C41
00402841    837D FC 14      cmp   dword ptr , 14
00402845    0F87 5E000000   ja      004028A9
0040284B    8B45 FC         mov   eax, dword ptr
0040284E    FF2485 55284000 jmp   dword ptr       向上跳转

跟随跳转来到下面代码:
00402792    8B45 0C         mov   eax, dword ptr           所选菜单序号
00402795    50            push    eax
00402796    8B45 08         mov   eax, dword ptr
00402799    50            push    eax                           某个基址
0040279A    E8 FA5F0000   call    00408799                        关键CALL,F7跟进
0040279F    83C4 08         add   esp, 8
004027A2    E9 02010000   jmp   004028A9

F7跟进来到下面:

00408799    55            push    ebp
0040879A    8BEC            mov   ebp, esp
0040879C    53            push    ebx
0040879D    56            push    esi
0040879E    57            push    edi
0040879F    8B45 0C         mov   eax, dword ptr
004087A2    2D 459C0000   sub   eax, 9C45                        ; 选择菜单序号减去上级菜单序号,得出选择的是第几个
004087A7    8B4D 08         mov   ecx, dword ptr
004087AA    8981 08130000   mov   dword ptr , eax          ; 存放所选级别标志序号
004087B0    8B45 08         mov   eax, dword ptr
004087B3    50            push    eax

到此我们可以知道dword ptr 存放的是所选择的级别,ECX存放的是一个基址,对的地址下内存访问断点,可以找到下面的代码:

004054C3    8B80 08130000   mov   eax, dword ptr           ; 取选定的级别
004054C9    50            push    eax
004054CA    E8 B0E2FFFF   call    0040377F                           ; 通过级别来算出下一个是什么类型,结果放在EAX
004054CF    83C4 0C         add   esp, 0C
004054D2    8B4D DC         mov   ecx, dword ptr
004054D5    8D0C49          lea   ecx, dword ptr
004054D8    8B55 08         mov   edx, dword ptr
004054DB    8984CA 98110000 mov   dword ptr , eax    ; 存放下一个出现的类型代表序号
004054E2    E8 73E2FFFF   call    0040375A                           ; 算下个物体水平位置
004054E7    8B4D DC         mov   ecx, dword ptr
004054EA    8D0C49          lea   ecx, dword ptr
004054ED    8B55 08         mov   edx, dword ptr
004054F0    8984CA 9C110000 mov   dword ptr , eax    存放水平位置

CALL是算下一个出现的类型的代表序号:0-实体版,1-逆时针转动链条,2-顺时针转动链条,3-弹簧板,4-带刺的板,5-翻转墙,当人工改为其他值时,
就出现乱画面。我们只要修改上面两个CALL,就可以实现出现的物体的类型和水平位置。

同样的方法,跟踪WM_KEYUP消息,来到下面:
00401E02    8B45 14         mov   eax, dword ptr             ; 按键
00401E05    C1E8 10         shr   eax, 10
00401E08    25 FFFF0000   and   eax, 0FFFF
00401E0D    0FB7C0          movzx   eax, ax
00401E10    50            push    eax
00401E11    0FBF45 14       movsx   eax, word ptr
00401E15    50            push    eax
00401E16    6A 01         push    1
00401E18    8B45 10         mov   eax, dword ptr             ; 所按下键的ASCII值
00401E1B    50            push    eax
00401E1C    8B45 FC         mov   eax, dword ptr              ; 基址
00401E1F    50            push    eax
00401E20    E8 800C0000   call    00402AA5                            关键CALL跟进

F7跟进上面的关键CALL:

00402AA5    55            push    ebp
00402AA6    8BEC            mov   ebp, esp
00402AA8    53            push    ebx
00402AA9    56            push    esi
00402AAA    57            push    edi
00402AAB    837D 0C 25      cmp   dword ptr , 25            ; 判断是不是按下左方向键
00402AAF    0F85 23000000   jnz   00402AD8
00402AB5    837D 10 00      cmp   dword ptr , 0
00402AB9    0F84 0F000000   je      00402ACE
00402ABF    8B45 08         mov   eax, dword ptr
00402AC2    8388 EC120000 0>or      dword ptr , 1            ; 存放按下左方向键的标记:1
00402AC9    E9 0A000000   jmp   00402AD8
00402ACE    8B45 08         mov   eax, dword ptr
00402AD1    83A0 EC120000 F>and   dword ptr , FFFFFFFE
00402AD8    837D 0C 27      cmp   dword ptr , 27            ; 判断是不是按下有方向键
00402ADC    0F85 23000000   jnz   00402B05
00402AE2    837D 10 00      cmp   dword ptr , 0
00402AE6    0F84 0F000000   je      00402AFB
00402AEC    8B45 08         mov   eax, dword ptr
00402AEF    8388 EC120000 0>or      dword ptr , 2            ; 存放按下右方向键的标记:2
00402AF6    E9 0A000000   jmp   00402B05
00402AFB    8B45 08         mov   eax, dword ptr
00402AFE    83A0 EC120000 F>and   dword ptr , FFFFFFFD
00402B05    837D 0C 5A      cmp   dword ptr , 5A            ; 判断是不是按下Z字母键
00402B09    0F85 23000000   jnz   00402B32
00402B0F    837D 10 00      cmp   dword ptr , 0
00402B13    0F84 0F000000   je      00402B28
00402B19    8B45 08         mov   eax, dword ptr
00402B1C    8388 EC120000 0>or      dword ptr , 4            ; 存放标记
00402B23    E9 0A000000   jmp   00402B32
00402B28    8B45 08         mov   eax, dword ptr
00402B2B    83A0 EC120000 F>and   dword ptr , FFFFFFFB
00402B32    837D 0C 58      cmp   dword ptr , 58            ; 判断是不是按下X字母键
00402B36    0F85 23000000   jnz   00402B5F
00402B3C    837D 10 00      cmp   dword ptr , 0
00402B40    0F84 0F000000   je      00402B55
00402B46    8B45 08         mov   eax, dword ptr
00402B49    8388 EC120000 0>or      dword ptr , 8            ; 存放标记

通过跟踪调试得出,当按键时,会在dword ptr 存放标记,1-左方向键,2-有方向键,4-Z键,8-X键,后两个是在两个人时才有效。
我们在这个内存地址下内存访问断点,点击“开始”,首先断在下面代码,是初始化参数的:

0040825D    8B45 08         mov   eax, dword ptr
00408260    C780 EC120000 0>mov   dword ptr , 0            ; 初始化为0

然后断在下面位置:

00405DB8    8B45 08         mov   eax, dword ptr
00405DBB    F680 EC120000 0>test    byte ptr , 1             ; 左方向键
00405DC2    0F84 1C000000   je      00405DE4
00405DC8    8B45 08         mov   eax, dword ptr
00405DCB    83A8 58110000 0>sub   dword ptr , 8            ; 水平位置减少8
00405DD2    8B45 08         mov   eax, dword ptr
00405DD5    C780 60110000 F>mov   dword ptr , -1
00405DDF    E9 39000000   jmp   00405E1D
00405DE4    8B45 08         mov   eax, dword ptr
00405DE7    F680 EC120000 0>test    byte ptr , 2             ; 右方向键
00405DEE    0F84 1C000000   je      00405E10
00405DF4    8B45 08         mov   eax, dword ptr
00405DF7    8380 58110000 0>add   dword ptr , 8            ; 水平位置加8
00405DFE    8B45 08         mov   eax, dword ptr
00405E01    C780 60110000 0>mov   dword ptr , 1
00405E0B    E9 0D000000   jmp   00405E1D
00405E10    8B45 08         mov   eax, dword ptr
00405E13    C780 60110000 0>mov   dword ptr , 0
00405E1D    8B45 08         mov   eax, dword ptr
00405E20    F680 10130000 0>test    byte ptr , 2
00405E27    0F84 65000000   je      00405E92
00405E2D    8B45 08         mov   eax, dword ptr
00405E30    F680 EC120000 0>test    byte ptr , 4             ; Z键
00405E37    0F84 1C000000   je      00405E59
00405E3D    8B45 08         mov   eax, dword ptr
00405E40    83A8 78110000 0>sub   dword ptr , 8            ; 水平位置加8
00405E47    8B45 08         mov   eax, dword ptr
00405E4A    C780 80110000 F>mov   dword ptr , -1
00405E54    E9 39000000   jmp   00405E92
00405E59    8B45 08         mov   eax, dword ptr
00405E5C    F680 EC120000 0>test    byte ptr , 8             ; X键
00405E63    0F84 1C000000   je      00405E85
00405E69    8B45 08         mov   eax, dword ptr
00405E6C    8380 78110000 0>add   dword ptr , 8            ; 水平位置加8
00405E73    8B45 08         mov   eax, dword ptr
00405E76    C780 80110000 0>mov   dword ptr , 1

由此我们可以得出dword ptr 存放的就是人物的水平位置,通过就改增减的数字就可以控制人物的移动速度。

接下来我们查找血量的存放位置,由于不会用CE这些工具,也没学做外挂分析,还是用熟悉的OD自己找吧。我们知道
当人物遇到不同的物体时会发出不同的声音,我就从此入手,一般游戏播放声音,用的是PlaySound这个API,我就下这个
断点,断下后,ALT+F9返回,来到下面的代码:

004062F8    6A 01         push    1
004062FA    6A 6E         push    6E
004062FC    8B45 08         mov   eax, dword ptr
004062FF    50            push    eax
00406300    E8 F8090000   call    00406CFD                         ; 上面的刺
00406305    83C4 0C         add   esp, 0C
00406308    8B45 F4         mov   eax, dword ptr
0040630B    C1E0 05         shl   eax, 5
0040630E    8B4D 08         mov   ecx, dword ptr
00406311    83AC08 70110000>sub   dword ptr , 5      ; 血量减5
00406319    8B45 F4         mov   eax, dword ptr
0040631C    C1E0 05         shl   eax, 5
0040631F    8B4D 08         mov   ecx, dword ptr
00406322    C78408 68110000>mov   dword ptr , 10   ; 闪烁时间
0040632D    8B45 08         mov   eax, dword ptr
00406330    50            push    eax
00406331    E8 70E7FFFF   call    00404AA6

。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
。。
。。省略很多代码
..
.............................................................................
004065FF    0F84 10000000   je      00406615
00406605    6A 01         push    1
00406607    6A 6E         push    6E
00406609    8B45 08         mov   eax, dword ptr
0040660C    50            push    eax
0040660D    E8 EB060000   call    00406CFD                         ; 上面的刺
00406612    83C4 0C         add   esp, 0C
00406615    8B45 F4         mov   eax, dword ptr
00406618    C1E0 05         shl   eax, 5
0040661B    8B4D 08         mov   ecx, dword ptr
0040661E    83AC08 70110000>sub   dword ptr , 5      ; 血量减5
00406626    8B45 F4         mov   eax, dword ptr
00406629    C1E0 05         shl   eax, 5
0040662C    8B4D 08         mov   ecx, dword ptr
0040662F    C78408 68110000>mov   dword ptr , 10
0。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
。。
。。省略很多代码
..
.............................................................................
004068A4    8B55 08         mov   edx, dword ptr
004068A7    898411 6C110000 mov   dword ptr , eax
004068AE    8B45 F8         mov   eax, dword ptr
004068B1    8D0440          lea   eax, dword ptr
004068B4    8B4D 08         mov   ecx, dword ptr
004068B7    83BCC1 98110000>cmp   dword ptr , 3
004068BF    0F85 25000000   jnz   004068EA
004068C5    8B45 08         mov   eax, dword ptr
004068C8    83B8 18130000 0>cmp   dword ptr , 0          ; 判断有没有音效
004068CF    0F84 10000000   je      004068E5
004068D5    6A 01         push    1
004068D7    6A 6D         push    6D
004068D9    8B45 08         mov   eax, dword ptr
004068DC    50            push    eax
004068DD    E8 1B040000   call    00406CFD                         ; 弹簧
004068E2    83C4 0C         add   esp, 0C
004068E5    E9 31010000   jmp   00406A1B
004068EA    8B45 F8         mov   eax, dword ptr
004068ED    8D0440          lea   eax, dword ptr
004068F0    8B4D 08         mov   ecx, dword ptr
004068F3    83BCC1 98110000>cmp   dword ptr , 2
004068FB    0F84 17000000   je      00406918
00406901    8B45 F8         mov   eax, dword ptr
00406904    8D0440          lea   eax, dword ptr
00406907    8B4D 08         mov   ecx, dword ptr
0040690A    83BCC1 98110000>cmp   dword ptr , 1
00406912    0F85 25000000   jnz   0040693D
00406918    8B45 08         mov   eax, dword ptr
0040691B    83B8 18130000 0>cmp   dword ptr , 0
00406922    0F84 10000000   je      00406938
00406928    6A 01         push    1
0040692A    6A 6C         push    6C
0040692C    8B45 08         mov   eax, dword ptr
0040692F    50            push    eax
00406930    E8 C8030000   call    00406CFD                         ; 链条
00406935    83C4 0C         add   esp, 0C
00406938    E9 DE000000   jmp   00406A1B
0040693D    8B45 F8         mov   eax, dword ptr
00406940    8D0440          lea   eax, dword ptr
00406943    8B4D 08         mov   ecx, dword ptr
00406946    83BCC1 98110000>cmp   dword ptr , 4
0040694E    0F85 4A000000   jnz   0040699E
00406954    8B45 08         mov   eax, dword ptr
00406957    83B8 18130000 0>cmp   dword ptr , 0
0040695E    0F84 10000000   je      00406974
00406964    6A 01         push    1
00406966    6A 6E         push    6E
00406968    8B45 08         mov   eax, dword ptr
0040696B    50            push    eax
0040696C    E8 8C030000   call    00406CFD                         ; 带刺的板
00406971    83C4 0C         add   esp, 0C
00406974    8B45 F4         mov   eax, dword ptr
00406977    C1E0 05         shl   eax, 5
0040697A    8B4D 08         mov   ecx, dword ptr
0040697D    C78408 68110000>mov   dword ptr , 10   ; 闪烁时间
00406988    8B45 F4         mov   eax, dword ptr
0040698B    C1E0 05         shl   eax, 5
0040698E    8B4D 08         mov   ecx, dword ptr
00406991    83AC08 70110000>sub   dword ptr , 6      ; 血量减6
00406999    E9 7D000000   jmp   00406A1B
0040699E    8B45 F8         mov   eax, dword ptr
004069A1    8D0440          lea   eax, dword ptr
004069A4    8B4D 08         mov   ecx, dword ptr
004069A7    83BCC1 98110000>cmp   dword ptr , 5
004069AF    0F85 46000000   jnz   004069FB
004069B5    8B45 08         mov   eax, dword ptr
004069B8    83B8 18130000 0>cmp   dword ptr , 0
004069BF    0F84 10000000   je      004069D5
004069C5    6A 01         push    1
004069C7    6A 6F         push    6F
004069C9    8B45 08         mov   eax, dword ptr
004069CC    50            push    eax
004069CD    E8 2B030000   call    00406CFD                         ; 翻转板
004069D2    83C4 0C         add   esp, 0C
004069D5    8B45 F4         mov   eax, dword ptr
004069D8    C1E0 05         shl   eax, 5
004069DB    8B4D 08         mov   ecx, dword ptr
004069DE    8B8408 6C110000 mov   eax, dword ptr
004069E5    8D0440          lea   eax, dword ptr
004069E8    8B4D 08         mov   ecx, dword ptr
004069EB    C784C1 A8110000>mov   dword ptr , 1   此处修改为0,板子就不会翻转
004069F6    E9 20000000   jm069FB    8B45 08         mov   eax, dword ptr
004069FE    83B8 18130000 0>cmp   dword ptr , 0
00406A05    0F84 10000000   je      00406A1B
00406A0B    6A 01         push    1
00406A0D    6A 6B         push    6B
00406A0F    8B45 08         mov   eax, dword ptr
00406A12    50            push    eax
00406A13    E8 E5020000   call    00406CFD                         ; 实体板
00406A18    83C4 0C         add   esp, 0C
00406A1B    8B45 F4         mov   eax, dword ptr
00406A1E    C1E0 05         shl   eax, 5
00406A21    8B4D 08         mov   ecx, dword ptr
00406A24    83BC08 70110000>cmp   dword ptr , 0C   ; 判断血量是不是大于12
00406A2C    0F8D 10000000   jge   00406A42
00406A32    8B45 F4         mov   eax, dword ptr
00406A35    C1E0 05         shl   eax, 5
00406A38    8B4D 08         mov   ecx, dword ptr
00406A3B    FF8408 70110000 inc   dword ptr          ; 血量加一
00406A42    8B45 08         mov   eax, dword ptr
00406A45    50            push    eax
00406A46    E8 5BE0FFFF   call    00404AA6
00406A4B    83C4 04         add   esp, 4


通过上面的代码我们得出dword ptr 处存放的就是血量,当遇到上面的刺时,血量减4,遇到带刺的板,减4,其他的加一。
通过修改上面的数值,就可以使血量不减少。也可以使翻转板不再翻转,也可以修改音乐效果。

通过上面的分析,我们就可以实现下面三个外挂功能:
1、控制出现的物体的类型,实现只出现一种类型;
2、增加或减小移动的速度;
3、实现血量不减少
------------------------------------------------------------------------
【疑问】
在编写修改软件时,用ReadProcessMemory读出的内存数据竟然跟OD里显示的不一样,也不知道是什么原因,还请各位看官赐教。

-----------------------------------------------------------------------
【版权声明】本文纯属技术交流, 转载请注明作者信息并保持文章的完整, 谢谢!

MOV 发表于 2010-2-13 22:37:14

顶上

jatoo 发表于 2010-2-18 20:00:19

研究研究,谢谢分享
页: [1]
查看完整版本: 乱弹《是男人就下一百层》之外挂分析