首先先来看源程序:
1 .386 2 .model flat,stdcall 3 option casemap:none 4 5 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 6 ;包含的文件 7 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 8 9 include windows.inc 10 include user32.inc 11 include kernel32.inc 12 13 includelib user32.lib 14 includelib kernel32.lib 15 16 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 17 ; 18 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 19 WinMain proto :DWORD,:DWORD,:DWORD,:DWORD 20 21 .DATA ; initialized data 22 ClassName db "SimpleWinClass",0 ; the name of our window class 23 AppName db "Our First Window",0 ; the name of our window 24 25 .DATA? ; Uninitialized data 26 hInstance HINSTANCE ? ; Instance handle of our program 27 CommandLine LPSTR ? 28 .CODE ; Here begins our code 29 start: 30 invoke GetModuleHandle, NULL ; get the instance handle of our program. 31 ; Under Win32, hmodule==hinstance mov hInstance,eax 32 mov hInstance,eax 33 invoke GetCommandLine ; get the command line. You don't have to call this function IF 34 ; your program doesn't process the command line. 35 mov CommandLine,eax 36 invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT ; call the main function 37 invoke ExitProcess, eax 38 39 40 41 42 WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD 43 44 LOCAL wc:WNDCLASSEX 45 LOCAL msg:MSG 46 LOCAL hwnd:HWND 47 48 mov wc.cbSize,SIZEOF WNDCLASSEX ; fill values in members of wc 49 mov wc.style, CS_HREDRAW or CS_VREDRAW 50 mov wc.lpfnWndProc, OFFSET WndProc 51 mov wc.cbClsExtra,NULL 52 mov wc.cbWndExtra,NULL 53 push hInstance 54 pop wc.hInstance 55 mov wc.hbrBackground,COLOR_WINDOW+1 56 mov wc.lpszMenuName,NULL 57 mov wc.lpszClassName,OFFSET ClassName 58 invoke LoadIcon,NULL,IDI_APPLICATION 59 mov wc.hIcon,eax 60 mov wc.hIconSm,eax 61 invoke LoadCursor,NULL,IDC_ARROW 62 mov wc.hCursor,eax 63 invoke RegisterClassEx, addr wc ; register our window class 64 invoke CreateWindowEx,NULL,\ 65 ADDR ClassName,\ 66 ADDR AppName,\ 67 WS_OVERLAPPEDWINDOW,\ 68 CW_USEDEFAULT,\ 69 CW_USEDEFAULT,\ 70 CW_USEDEFAULT,\ 71 CW_USEDEFAULT,\ 72 NULL,\ 73 NULL,\ 74 hInst,\ 75 NULL 76 mov hwnd,eax 77 invoke ShowWindow, hwnd,CmdShow ; display our window on desktop 78 invoke UpdateWindow, hwnd ; refresh the client area 79 80 .WHILE TRUE ; Enter message loop 81 invoke GetMessage, ADDR msg,NULL,0,0 82 .BREAK .IF (!eax) 83 invoke TranslateMessage, ADDR msg 84 invoke DispatchMessage, ADDR msg 85 .ENDW 86 mov eax,msg.wParam ; return exit code in eax 87 ret 88 WinMain endp 89 90 WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM 91 .IF uMsg==WM_DESTROY ; if the user closes our window 92 invoke PostQuitMessage,NULL ; quit our application 93 .ELSE 94 invoke DefWindowProc,hWnd,uMsg,wParam,lParam ; Default message processing 95 ret 96 .ENDIF 97 xor eax,eax 98 ret 99 WndProc endp 100 101 end start
然后是反汇编程序,我自己添加了些注释
1 00401000 >/$ 6A 00 push 0 ; /pModule = NULL 2 00401002 |. E8 8D010000 call <jmp.&kernel32.GetModuleHandleA> ; \GetModuleHandleA 3 00401007 |. A3 20304000 mov dword ptr [403020], eax ; mov hInstance,eax 4 0040100C |. E8 7D010000 call <jmp.&kernel32.GetCommandLineA> ; [GetCommandLineA 5 00401011 |. A3 24304000 mov dword ptr [403024], eax ; mov CommandLine,eax 6 00401016 |. 6A 0A push 0A ; SW_SHOWDEFAULT 7 00401018 |. FF35 24304000 push dword ptr [403024] ; CommandLine 8 0040101E |. 6A 00 push 0 ; NULL 9 00401020 |. FF35 20304000 push dword ptr [403020] ; hInstance 10 00401026 |. E8 06000000 call 00401031 ; WinMain 11 0040102B |. 50 push eax ; /ExitCode 12 0040102C \. E8 57010000 call <jmp.&kernel32.ExitProcess> ; \ExitProcess
只要和源程序对比,就很清晰了
1 start: 2 invoke GetModuleHandle, NULL ; get the instance handle of our program. 3 ; Under Win32, hmodule==hinstance mov hInstance,eax 4 mov hInstance,eax 5 invoke GetCommandLine ; get the command line. You don't have to call this function IF 6 ; your program doesn't process the command line. 7 mov CommandLine,eax 8 invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT ; call the main function 9 invoke ExitProcess, eax
首先是以0为参数,获取模块的句柄,句柄值放在eax中
然后将eax放入一个变量中,这里变量名为hInstance。
然后用GetCommandLine 获得程序的路径,并通过mov CommandLine,eax 保存到变量CommandLine中。
调用主函数WinMain
退出程序。
下面是WinMain:
1 00401031 /$ 55 push ebp 2 00401032 |. 8BEC mov ebp, esp 3 00401034 |. 83C4 B0 add esp, -50 4 00401037 |. C745 D0 30000>mov dword ptr [ebp-30], 30 ; mov wc.cbSize,SIZEOF WNDCLASSEX 5 0040103E |. C745 D4 03000>mov dword ptr [ebp-2C], 3 ; mov wc.style, CS_HREDRAW or CS_VREDRAW 6 00401045 |. C745 D8 19114>mov dword ptr [ebp-28], 00401119 ; mov wc.lpfnWndProc, OFFSET WndProc 7 0040104C |. C745 DC 00000>mov dword ptr [ebp-24], 0 ; mov wc.cbClsExtra,NULL 8 00401053 |. C745 E0 00000>mov dword ptr [ebp-20], 0 ; mov wc.cbWndExtra,NULL 9 0040105A |. FF35 20304000 push dword ptr [403020] ; push hInstance 10 00401060 |. 8F45 E4 pop dword ptr [ebp-1C] ; pop wc.hInstance 11 00401063 |. C745 F0 06000>mov dword ptr [ebp-10], 6 ; mov wc.hbrBackground,COLOR_WINDOW+1 12 0040106A |. C745 F4 00000>mov dword ptr [ebp-C], 0 ; mov wc.lpszMenuName,NULL 13 00401071 |. C745 F8 00304>mov dword ptr [ebp-8], 00403000 ; mov wc.lpszClassName,OFFSET ClassName 14 00401078 |. 68 007F0000 push 7F00 ; /RsrcName = IDI_APPLICATION 15 0040107D |. 6A 00 push 0 ; |hInst = NULL 16 0040107F |. E8 E0000000 call <jmp.&user32.LoadIconA> ; \LoadIconA 17 00401084 |. 8945 E8 mov dword ptr [ebp-18], eax 18 00401087 |. 8945 FC mov dword ptr [ebp-4], eax 19 0040108A |. 68 007F0000 push 7F00 ; /RsrcName = IDC_ARROW 20 0040108F |. 6A 00 push 0 ; |hInst = NULL 21 00401091 |. E8 C8000000 call <jmp.&user32.LoadCursorA> ; \LoadCursorA 22 00401096 |. 8945 EC mov dword ptr [ebp-14], eax 23 00401099 |. 8D45 D0 lea eax, dword ptr [ebp-30] ; wc结构体的起始位置 24 0040109C |. 50 push eax ; /pWndClassEx 25 0040109D |. E8 CE000000 call <jmp.&user32.RegisterClassExA> ; \RegisterClassExA 26 004010A2 |. 6A 00 push 0 ; /lParam = NULL 27 004010A4 |. FF75 08 push dword ptr [ebp+8] ; |hInstance 28 004010A7 |. 6A 00 push 0 ; |hMenu = NULL 29 004010A9 |. 6A 00 push 0 ; |hParent = NULL 30 004010AB |. 68 00000080 push 80000000 ; |Height = 80000000 (-2147483648.) 31 004010B0 |. 68 00000080 push 80000000 ; |Width = 80000000 (-2147483648.) 32 004010B5 |. 68 00000080 push 80000000 ; |Y = 80000000 (-2147483648.) 33 004010BA |. 68 00000080 push 80000000 ; |X = 80000000 (-2147483648.) 34 004010BF |. 68 0000CF00 push 0CF0000 ; |Style = WS_OVERLAPPED|WS_MINIMIZEBOX|WS_MAXIMIZEBOX
|WS_SYSMENU|WS_THICKFRAME|WS_CAPTION 35 004010C4 |. 68 0F304000 push 0040300F ; |WindowName = "Our First Window" 36 004010C9 |. 68 00304000 push 00403000 ; |Class = "SimpleWinClass" 37 004010CE |. 6A 00 push 0 ; |ExtStyle = 0 38 004010D0 |. E8 71000000 call <jmp.&user32.CreateWindowExA> ; \CreateWindowExA 39 004010D5 |. 8945 B0 mov dword ptr [ebp-50], eax ; eax保存创建成功后的窗口句柄 40 004010D8 |. FF75 14 push dword ptr [ebp+14] ; /ShowState 41 004010DB |. FF75 B0 push dword ptr [ebp-50] ; |hWnd 42 004010DE |. E8 93000000 call <jmp.&user32.ShowWindow> ; \ShowWindow 43 004010E3 |. FF75 B0 push dword ptr [ebp-50] ; /hWnd 44 004010E6 |. E8 97000000 call <jmp.&user32.UpdateWindow> ; \UpdateWindow 45 004010EB |> 6A 00 /push 0 ; /MsgFilterMax = 0 46 004010ED |. 6A 00 |push 0 ; |MsgFilterMin = 0 47 004010EF |. 6A 00 |push 0 ; |hWnd = NULL 48 004010F1 |. 8D45 B4 |lea eax, dword ptr [ebp-4C] ; | 49 004010F4 |. 50 |push eax ; |pMsg 50 004010F5 |. E8 5E000000 |call <jmp.&user32.GetMessageA> ; \GetMessageA 51 004010FA |. 0BC0 |or eax, eax 52 004010FC |. 74 14 |je short 00401112 53 004010FE |. 8D45 B4 |lea eax, dword ptr [ebp-4C] 54 00401101 |. 50 |push eax ; /pMsg 55 00401102 |. E8 75000000 |call <jmp.&user32.TranslateMessage> ; \TranslateMessage 56 00401107 |. 8D45 B4 |lea eax, dword ptr [ebp-4C] 57 0040110A |. 50 |push eax ; /pMsg 58 0040110B |. E8 42000000 |call <jmp.&user32.DispatchMessageA> ; \DispatchMessageA 59 00401110 |.^ EB D9 \jmp short 004010EB 60 00401112 |> 8B45 BC mov eax, dword ptr [ebp-44] 61 00401115 |. C9 leave 62 00401116 \. C2 1000 retn 10
感觉对消息机制还不是很了解。
在窗口注册函数RegisterClassEx中涉及到WNDCLASSEX结构,在WNDCLASSEX结构中涉及到消息处理函数WndProc
这样,当产生消息后,GetMessage获得消息,TranslateMessage转换键盘消息,DispatchMessage分派消息。
在消息处理函数中WndProc可以自己定义处理消息的方式,如果不是自己定义的处理,就交给DefWindowProc作默认处理。