从上篇中的注册窗口类的时候可以看出消息处理函数的地址为00402318。从这里也可以看出不太像VC,je,jl的一大堆。 流程概述 1. WM_CREATE消息,申请空间创建内存图像和游戏绘图DC,以及画出开场的画面。 2. WM_DESTORY消息,释放空间恢复和释放游戏绘图DC,发送退出消息。 3. WM_ACTIVATE消息,调整程序的优先级。 4. WM_PAINT消息,及时刷新屏幕。 5. WM_KEYDOWN,根据不同的按键调用不同的功能,比如控制游戏 6. WM_KEYUP,和WM_KEYDOWN相反,主要用来平衡WM_KEYDOWN的控制游戏 流程分析 1. WM_CREATE 进入事件call 004025BF |. 68 28040000 push 428 /HeapSize = 428 (1064.) 004025C4 |. 6A 00 push 0 |Flags = 0 004025C6 |. E8 21220000 call <jmp.&KERNEL32.GetProcessHeap> |[GetProcessHeap 004025CB |. 50 push eax |hHeap 004025CC |. E8 15220000 call <jmp.&KERNEL32.HeapAlloc> \HeapAlloc 004025D1 |. 8BF0 mov esi, eax 004025D3 |. BA 28000000 mov edx, 28 004025D8 |. 8BC6 mov eax, esi 004025DA |. E8 75FBFFFF call 00402154 004025DF |. C706 28000000 mov dword ptr [esi], 28 004025E5 |. 33C9 xor ecx, ecx 004025E7 |. C746 04 40010>mov dword ptr [esi+4], 140 004025EE |. C746 08 F0000>mov dword ptr [esi+8], 0F0 004025F5 |. 66:C746 0C 01>mov word ptr [esi+C], 1 004025FB |. 66:C746 0E 08>mov word ptr [esi+E], 8 00402601 |. 894E 10 mov dword ptr [esi+10], ecx 00402604 |. 33DB xor ebx, ebx 00402606 |. C746 20 10000>mov dword ptr [esi+20], 10 0040260D |. 8D46 2A lea eax, dword ptr [esi+2A] 00402610 |> 8BD3 mov edx, ebx 00402612 |. 8BCA mov ecx, edx 00402614 |. 80E1 01 and cl, 1 00402617 |. C1E1 07 shl ecx, 7 0040261A |. 8808 mov byte ptr [eax], cl 0040261C |. 8BCB mov ecx, ebx 0040261E |. 83E1 01 and ecx, 1 00402621 |. 8BE9 mov ebp, ecx 00402623 |. C1E1 08 shl ecx, 8 00402626 |. 2BCD sub ecx, ebp 00402628 |. 8848 20 mov byte ptr [eax+20], cl 0040262B |. 8BCA mov ecx, edx 0040262D |. 80E1 02 and cl, 2 00402630 |. 80E2 04 and dl, 4 00402633 |. C1E1 07 shl ecx, 7 00402636 |. 8848 FF mov byte ptr [eax-1], cl 00402639 |. 8BCB mov ecx, ebx 0040263B |. 83E1 02 and ecx, 2 0040263E |. 8BE9 mov ebp, ecx 00402640 |. C1E1 08 shl ecx, 8 00402643 |. 2BCD sub ecx, ebp 00402645 |. C1E2 07 shl edx, 7 00402648 |. 8848 1F mov byte ptr [eax+1F], cl 0040264B |. 8850 FE mov byte ptr [eax-2], dl 0040264E |. 8BD3 mov edx, ebx 00402650 |. 83E2 04 and edx, 4 00402653 |. 43 inc ebx 00402654 |. 8BCA mov ecx, edx 00402656 |. C1E1 08 shl ecx, 8 00402659 |. 2BCA sub ecx, edx 0040265B |. 8848 1E mov byte ptr [eax+1E], cl 0040265E |. 83C0 04 add eax, 4 00402661 |. 83FB 08 cmp ebx, 8 00402664 |.^\7C AA jl short 00402610 00402666 |. C646 46 C0 mov byte ptr [esi+46], 0C0 0040266A |. C646 45 C0 mov byte ptr [esi+45], 0C0 0040266E |. C646 44 C0 mov byte ptr [esi+44], 0C0 00402672 |. C646 4A 80 mov byte ptr [esi+4A], 80 00402676 |. C646 49 80 mov byte ptr [esi+49], 80 0040267A |. C646 48 80 mov byte ptr [esi+48], 80 申请堆空间,并在堆空间里写入了bitmap的头信息。 00402681 |. 50 push eax /hWnd 00402682 |. E8 CB210000 call <jmp.&USER32.GetDC> \GetDC 00402687 |. 8BE8 mov ebp, eax 00402689 |. 6A 00 push 0 /Offset = 0 0040268B |. 6A 00 push 0 |hSection = NULL 0040268D |. 68 FC694000 push 004069FC |ppBits = game.004069FC 00402692 |. 6A 00 push 0 |Usage = DIB_RGB_COLORS 00402694 |. 56 push esi |pBitmapInfo 00402695 |. 55 push ebp |hDC 00402696 |. E8 3B220000 call <jmp.&GDI32.CreateDIBSection> \CreateDIBSection 0040269B |. A3 EC694000 mov dword ptr [4069EC], eax 004026A0 |. 68 F0000000 push 0F0 /Height = F0 (240.) 004026A5 |. 68 40010000 push 140 |Width = 140 (320.) 004026AA |. 55 push ebp |hDC 004026AB |. E8 32220000 call <jmp.&GDI32.CreateCompatibleBitm> \CreateCompatibleBitmap 004026B0 |. A3 F4694000 mov dword ptr [4069F4], eax 004026B5 |. 56 push esi /pMemory 004026B6 |. 6A 00 push 0 |Flags = 0 004026B8 |. E8 2F210000 call <jmp.&KERNEL32.GetProcessHeap> |[GetProcessHeap 004026BD |. 50 push eax |hHeap 004026BE |. E8 1D210000 call <jmp.&KERNEL32.HeapFree> \HeapFree 根据以上的头信息创建内存的位图,绘图的内存首地址指针放在0x004069F4 ||||||||||||||||||||||||||||||||||||||| 在游戏开场画面上写上文字、贴上位图。 2. WM_DESTORY 00402986 |. 50 push eax /pMemory => NULL 00402987 |. 6A 00 push 0 |Flags = 0 00402989 |. E8 5E1E0000 call <jmp.&KERNEL32.GetProcessHeap> |[GetProcessHeap 0040298E |. 50 push eax |hHeap 0040298F |. E8 4C1E0000 call <jmp.&KERNEL32.HeapFree> \HeapFree 00402994 |. 33D2 xor edx, edx 00402996 |. 8915 006A4000 mov dword ptr [406A00], edx 0040299C |> 6A FF push -1 /nSavedDC = FFFFFFFF (-1.) 0040299E |. 8B0D E0694000 mov ecx, dword ptr [4069E0] | 004029A4 |. 51 push ecx |hDC => NULL 004029A5 |. E8 081F0000 call <jmp.&GDI32.RestoreDC> \RestoreDC 004029AA |. 6A FF push -1 /nSavedDC = FFFFFFFF (-1.) 004029AC |. A1 E4694000 mov eax, dword ptr [4069E4] | 004029B1 |. 50 push eax |hDC => NULL 004029B2 |. E8 FB1E0000 call <jmp.&GDI32.RestoreDC> \RestoreDC 004029B7 |. 6A FF push -1 /nSavedDC = FFFFFFFF (-1.) 004029B9 |. 8B15 E8694000 mov edx, dword ptr [4069E8] | 004029BF |. 52 push edx |hDC => NULL 004029C0 |. E8 ED1E0000 call <jmp.&GDI32.RestoreDC> \RestoreDC 释放所申请的堆空间和游戏绘图DC 、、、、、、、、、、、、、、、、、、、、、、、、、、、、 00402A1F |. 6A 00 push 0 /ExitCode = 0 00402A21 |. 8915 906D4000 mov dword ptr [406D90], edx | 00402A27 |. E8 081E0000 call <jmp.&USER32.PostQuitMessage> \PostQuitMessage 发送消息通知退出 3. WM_ACTIVATE 00402394 |> \B8 01000000 mov eax, 1 00402399 |. E8 2E230000 call 004046CC 注意上面有为eax传参的操作,跟进call 004046CC会发现: 004046DA |. 85C0 test eax, eax 004046DC |. 74 6D je short 0040474B 首先判断eax,然后有分支: 004046F5 |. 6A 01 push 1 /Show = TRUE 004046F7 |. E8 26010000 call <jmp.&USER32.ShowCursor> \ShowCursor 004046FC |. 8B0D CC6D4000 mov ecx, dword ptr [406DCC] 00404702 |. 85C9 test ecx, ecx 00404704 |. 74 0D je short 00404713 00404706 |. 6A 20 push 20 /Priority = NORMAL_PRIORITY_CLASS 00404708 |. E8 F1000000 call <jmp.&KERNEL32.GetCurrentProcess> |[GetCurrentProcess 0040470D |. 50 push eax |hProcess 0040470E |. E8 C7000000 call <jmp.&KERNEL32.SetPriorityClass> \SetPriorityClass 00404713 |> 6A 00 push 0 /Priority = THREAD_PRIORITY_NORMAL 00404715 |. E8 DE000000 call <jmp.&KERNEL32.GetCurrentThread> |[GetCurrentThread 0040471A |. 50 push eax |hThread 0040471B |. E8 B4000000 call <jmp.&KERNEL32.SetThreadPriority> \SetThreadPriority 00404720 |. 68 2000CC00 push 0CC0020 /ROP = SRCCOPY 00404725 |. 6A 00 push 0 |YSrc = 0 00404727 |. 6A 00 push 0 |XSrc = 0 00404729 |. A1 E0694000 mov eax, dword ptr [4069E0] | 0040472E |. 50 push eax |hSrcDC => NULL 0040472F |. 68 F0000000 push 0F0 |Height = F0 (240.) 00404734 |. 68 40010000 push 140 |Width = 140 (320.) 00404739 |. 6A 00 push 0 |YDest = 0 0040473B |. 6A 00 push 0 |XDest = 0 0040473D |. 8B15 E4694000 mov edx, dword ptr [4069E4] | 00404743 |. 52 push edx |hDestDC => NULL 00404744 |. E8 9F010000 call <jmp.&GDI32.BitBlt> \BitBlt 这些代码的意思是把鼠标显示出来然后把游戏进程的优先级调低(比如说游戏暂停或窗口失去焦点的时候),另一个分支和此完全相反,而本消息适合于另一分支。后面调用这个函数的时候很多。 4. WM_PAINT 用BeginPaint和EndPaint做了简单的刷新。 5. WM_KEYDOWN 提取按键信息,比如游戏控制按键,将按键和全局变量[406D7C]以不同的变量作或运算。 如果按键为ESC的话 00402431 |> \B8 01000000 mov eax, 1 Case 1B of switch 004023C2 00402436 |. E8 91220000 call 004046CC 0040243B |. 6A 06 push 6 /ShowState = SW_MINIMIZE 0040243D |. 8B55 08 mov edx, dword ptr [ebp+8] | 00402440 |. 52 push edx |hWnd 00402441 |. E8 D6230000 call <jmp.&USER32.ShowWindow> \ShowWindow 就降低游戏程序的优先级,并最小化。 如果按键为ENTER时 0040244B |> \8B0D 846D4000 mov ecx, dword ptr [406D84] Cases D,20 of switch 004023C2 00402451 |. 83E9 01 sub ecx, 1 Switch (cases 0..6) 00402454 |. 72 33 jb short 00402489 00402456 |. 74 0D je short 00402465 这里会把一个全局变量减1并判断,这个全局变量是用来做回车暂停的计数的,从下文的程序里可以看出当暂停11次后就自动死亡,同时它也是用来判断游戏的当前状态的(活动中还是暂停) 进去: 004042F7 |. 6A 00 push 0 /Show = FALSE 004042F9 |. E8 24050000 call <jmp.&USER32.ShowCursor> \ShowCursor 把鼠标隐藏。 继续call 00404660进去: 00404660 /$ B8 106E4000 mov eax, 00406E10 00404665 |. 33D2 xor edx, edx 00404667 |> C640 08 FF /mov byte ptr [eax+8], 0FF 0040466B |. 83C0 0F |add eax, 0F 0040466E |. 42 |inc edx 0040466F |. 81FA 2C010000 |cmp edx, 12C 00404675 |.^ 7C F0 \jl short 00404667 00404677 |. 8B0D C06D4000 mov ecx, dword ptr [406DC0] 把00406E10为首地址的内存每15个字节在偏移为8的位置上写入FF。 其实这个内存就是来存储子弹的信息的。 00404677 |. 8B0D C06D4000 mov ecx, dword ptr [406DC0] 0040467D |. 83E9 01 sub ecx, 1 Switch (cases 0..3) 00404680 |. /72 0A jb short 0040468C 00404682 |. |74 14 je short 00404698 00404684 |. |49 dec ecx 00404685 |. |74 1D je short 004046A4 00404687 |. |49 dec ecx 00404688 |. |74 26 je short 004046B0 0040468A |. |EB 0C jmp short 00404698 0040468C |> \C705 A86D4000>mov dword ptr [406DA8], 1E 00404696 |. EB 22 jmp short 004046BA 00404698 |> C705 A86D4000>mov dword ptr [406DA8], 32 Default case of switch 0040467D 004046A2 |. EB 16 jmp short 004046BA 004046A4 |> C705 A86D4000>mov dword ptr [406DA8], 64 Case 2 of switch 0040467D 004046AE |. EB 0A jmp short 004046BA 004046B0 |> C705 A86D4000>mov dword ptr [406DA8], 0C8 Case 3 of switch 0040467D 根据406DC0里的数据来给406DA8赋予不同的值。其实在后面的程序中可以看出406DC0里的东西就是子弹数量(可能也是难度的一个标识)的标识。而地址406DA8里放的是子弹的数量。 最后是对一些全局变量的初始化 返回(这个函数可以看作为游戏的初始化过程) 往后是对游戏各个地方的初始化,包括场景,各种标记常量。 (责任编辑:科锐软件教育机构) |