这一节, 我们主要分析上一节 中的反汇编代码,通过汇编代码的分析, 让你更加的清楚汇编程序的处理逻辑
也让你了解我们写出的汇编源码和反汇编代码之间的差别和对应关系
程序分为2个部分, 一个是程序的入口, 通过DialogBoxParam函数启动一个对话框
另一个就是对话框的处理过程, 这个是关键, 下面是反汇编代码的分析:
_ProcDlgMain处理过程:
窗口处理过程只处理了三个消息WM_COMMAND, WM_INITDIALOG, WM_CLOSE
00401000 . 55 push ebp
00401001 . 8BEC mov ebp, esp
00401003 . 8B45 0C mov eax, dword ptr [ebp+C]
mov eax, uMsg 将消息值送入eax
00401006 . 3D 11010000 cmp eax, 111 ; Switch (cases 10..111)
比较消息值是否WM_COMMAND消息
0040100B . 75 6D jnz short 0040107A
不是, 转入下一个消息的判断
下面是WM_COMMAND消息的处理
WM_COMMAND消息的
wParam 参数的高16为是通知码, 低16位是控件ID
lParam 参数为控件的句柄
0040100D . 8B45 10 mov eax, dword ptr [ebp+10] ; Case 111 (WM_COMMAND) of switch 00401006
mov eax, wParam 得到wParam参数
00401010 . 66:83F8 01 cmp ax, 1
比较控件ID是不是IDOK
00401014 . 75 52 jnz short 00401068
不是IDOK则转入下一个判断
00401016 . 6A 00 push 0 ; /IsSigned = FALSE
00401018 . 6A 00 push 0 ; |pSuccess = NULL
0040101A . 68 E8030000 push 3E8 ; |ControlID = 3E8 (1000.)
0040101F . FF75 08 push dword ptr [ebp+8] ; |hWnd
00401022 . E8 D7000000 call <jmp.&user32.GetDlgItemInt> ; /GetDlgItemInt
用GetDlgItemInt函数得到被除数
00401027 . 50 push eax
保存被除数
00401028 . 6A 00 push 0 ; /IsSigned = FALSE
0040102A . 6A 00 push 0 ; |pSuccess = NULL
0040102C . 68 E9030000 push 3E9 ; |ControlID = 3E9 (1001.)
00401031 . FF75 08 push dword ptr [ebp+8] ; |hWnd
00401034 . E8 C5000000 call <jmp.&user32.GetDlgItemInt> ; /GetDlgItemInt
得到除数
00401039 . 8BC8 mov ecx, eax
将除数送入ecx
0040103B . 33D2 xor edx, edx
被除数高32位清0
0040103D . 58 pop eax
得到被除数低32位
0040103E . 0BC9 or ecx, ecx
看看除数是否为0
00401040 . 74 77 je short 004010B9
如果为0, 则不做处理,直接退出
00401042 . F7F1 div ecx
被除数不为0, 则进行32位无符号除法运算
对于32位无符号除法运算, 被除数是64位的, 用寄存器edx保存高32位, 用eax保存低32位
除数是32位的, 运算的结果, 商放在eax中, 余数放在edx中
00401044 . 50 push eax
保存商
00401045 . 6A 00 push 0 ; /IsSigned = FALSE
00401047 . 52 push edx ; |Value
00401048 . 68 EB030000 push 3EB ; |ControlID = 3EB (1003.)
0040104D . FF75 08 push dword ptr [ebp+8] ; |hWnd
00401050 . E8 AF000000 call <jmp.&user32.SetDlgItemInt> ; /SetDlgItemInt
调用SetDlgItemInt将余数edx显示在对应的文本框中
00401055 . 58 pop eax
得到商
00401056 . 6A 00 push 0 ; /IsSigned = FALSE
00401058 . 50 push eax ; |Value
00401059 . 68 EA030000 push 3EA ; |ControlID = 3EA (1002.)
0040105E . FF75 08 push dword ptr [ebp+8] ; |hWnd
00401061 . E8 9E000000 call <jmp.&user32.SetDlgItemInt> ; /SetDlgItemInt
用SetDlgItemInt将商eax显示在对应的文本框中
00401066 . EB 51 jmp short 004010B9
处理完毕, 退出
00401068 > 66:83F8 02 cmp ax, 2
比较控件ID是不是IDCANCEL
0040106C . 75 4B jnz short 004010B9
不是, 则退出
0040106E . 6A 00 push 0 ; /Result = 0
00401070 . FF75 08 push dword ptr [ebp+8] ; |hWnd
00401073 . E8 7A000000 call <jmp.&user32.EndDialog> ; /EndDialog
调用EndDialog关闭对话框
00401078 . EB 3F jmp short 004010B9
处理完毕,退出
0040107A > 3D 10010000 cmp eax, 110
看看是不是WM_INITDIALOG
0040107F . 75 1E jnz short 0040109F
不是, 则转入下一个消息判断
00401081 . 68 E8030000 push 3E8 ; /ControlID = 3E8 (1000.); Case 110 (WM_INITDIALOG) of switch 00401006
00401086 . FF75 08 push dword ptr [ebp+8] ; |hWnd
00401089 . E8 6A000000 call <jmp.&user32.GetDlgItem> ; /GetDlgItem
0040108E . 50 push eax ; /hWnd
0040108F . E8 76000000 call <jmp.&user32.SetFocus> ; /SetFocus
00401094 . B8 00000000 mov eax, 0
00401099 . C9 leave
0040109A . C2 1000 retn 10
0040109D . EB 1A jmp short 004010B9
处理WM_INITDIALOG消息, 用GetDlgItem得到被除数文本框的句柄, 并用SetFocus设置焦点
注意, 在WM_INITDIALOG中设置控件焦点后, 必须返回FALSE,即0, 否则焦点设置无效
0040109F > 83F8 10 cmp eax, 10
看看是不是WM_CLOSE
004010A2 . 75 0C jnz short 004010B0
不是,则转入默认处理
004010A4 . 6A 00 push 0 ; /Result = 0; Case 10 (WM_CLOSE) of switch 00401006
004010A6 . FF75 08 push dword ptr [ebp+8] ; |hWnd
004010A9 . E8 44000000 call <jmp.&user32.EndDialog> ; /EndDialog
004010AE . EB 09 jmp short 004010B9
处理WM_CLOSE消息, 结束对话框, 退出程序
004010B0 > B8 00000000 mov eax, 0 ; Default case of switch 00401006
004010B5 . C9 leave
004010B6 . C2 1000 retn 10
对话框默认处理, 如果eax的值是0, 则表示消息未处理,交给对话框的默认处理过程处理
004010B9 > B8 01000000 mov eax, 1
004010BE . C9 leave
004010BF . C2 1000 retn 10
如果eax的值是1, 则表示消息已经处理过
程序入口点:
004010C2 >/$ 6A 00 push 0 ; /pModule = NULL
004010C4 |. E8 4D000000 call <jmp.&kernel32.GetModuleHandleA> ; /GetModuleHandleA
用GetModuleHandleA获取模块句柄, 就是实例句柄
004010C9 |. A3 00304000 mov dword ptr [403000], eax
将获取的实例句柄存入全局变量hInstance中
004010CE |. 6A 00 push 0 ; /lParam = NULL
004010D0 |. 68 00104000 push 00401000 ; |DlgProc = Dialog.00401000
004010D5 |. 6A 00 push 0 ; |hOwner = NULL
004010D7 |. 6A 65 push 65 ; |pTemplate = 65
004010D9 |. FF35 00304000 push dword ptr [403000] ; |hInst = NULL
004010DF |. E8 08000000 call <jmp.&user32.DialogBoxParamA> ; /DialogBoxParamA
调用DialogBoxParamA,产生一个对话框,该函数原型如下:
INT_PTR DialogBoxParam(
HINSTANCE hInstance, // handle to module
LPCTSTR lpTemplateName, // dialog box template
HWND hWndParent, // handle to owner window
DLGPROC lpDialogFunc, // dialog box procedure
LPARAM dwInitParam // initialization value
);
hInstance 实例句柄
lpTemplateName 对话框资源名称,这里可填入资源ID
hWndParent 父窗口
lpDialogFunc 对话框窗口过程, 这里可以处理我们感兴趣的消息
dwInitParam 对话框创库过程的lParam参数
只有当你点击关闭按钮的时候, 这个函数才结束,也就是说,这个函数内部有一个消息循环
不断的处理对话框的各种消息
004010E4 |. 6A 00 push 0 ; /ExitCode = 0
004010E6 /. E8 25000000 call <jmp.&kernel32.ExitProcess> ; /ExitProcess
调用ExitProcess退出程序
这个程序需要注意的是, 用div ecx进行运算后, edx和eax分别保存着32位无符号除法的余数和商
如果要用SetDlgItemInt函数把它们显示在文本框中, 则至少先要保存其中的一个, 因为SetDlgItemInt
会修改eax, ecx, edx寄存器, 如果不保存的话, 则会破坏运算的结果
对于整个程序的分析到此为止, 可以看出用了资源之后, 我们可以把更多的精力放在任务处理上
而不必花费时间自己去创建界面。 对于用sdk写windows应用程序的朋友来说, 可以用汇编很容易
的写出用c写出的程序, 然而用汇编写的程序, 不仅程序体积小, 而且效率也更高。
所以,用masm32的宏和VC资源编辑器, 写出功能强大而且效率高的复杂程序不再是一个难题。
<script type="text/javascript"> </script> <script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"></script>