读过windows核心编程的人都知道,书中的第一个例子就是用FormatMessage显示程序中的错误代码,这个代码是由微软定义好的, 通过FormatMessage可以将错误代码转换成错误代码的描述,通过描述,你就能知道函数调用失败的原因是什么, 书中是用C语言写的, 闲来无事,就用汇编写了一个类似的程序,重温一下汇编代码的书写方法,程序中的大部分代码都是参考书上的例子, 如果书上的例子你懂了,这段汇编就很好懂了,好了,废话少说,上代码:
// 资源文件// ErrorShow.rc#include #define IDD_ERRSHOW 101#define IDI_ERRSHOW 102#define IDC_ERRCODE 1000#define IDC_ERRTEXT 1001#define IDC_ALWAYSONTOP 1002IDD_ERRSHOW DIALOGEX 0, 0, 182, 75STYLE DS_SETFOREGROUND | DS_3DLOOK | DS_CENTER | WS_MINIMIZEBOX | WS_VISIBLE | WS_CAPTION | WS_SYSMENUCAPTION "Error Show"FONT 8, "Verdana"BEGIN LTEXT "Error :", IDC_STATIC, 4, 4, 19, 8 EDITTEXT IDC_ERRCODE, 24, 2, 24, 14, ES_AUTOHSCROLL | ES_NUMBER DEFPUSHBUTTON "Look up", IDOK, 56, 2, 36, 14 CONTROL "&On top", IDC_ALWAYSONTOP, "Button", BS_AUTOCHECKBOX | WS_TABSTOP, 104, 4, 38, 10 EDITTEXT IDC_ERRTEXT, 4, 20, 176, 50, ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY | NOT WS_BORDER | WS_VSCROLL, WS_EX_CLIENTEDGEENDIDI_ERRSHOW ICON DISCARDABLE "ErrorShow.ico"; 汇编代码; ErrorShow.asm .386 .model flat, stdcall option casemap: noneinclude windows.incinclude kernel32.incincludelib kernel32.libinclude user32.incincludelib user32.libIDD_ERRSHOW EQU 101IDI_ERRSHOW EQU 102IDC_ERRCODE EQU 1000IDC_ERRTEXT EQU 1001IDC_ALWAYSONTOP EQU 1002 .data?hInst dd ? .constszAppName db 'Error Show', 0szNotFound db 'Error Number Not Found', 0 .code_DialogProc proc uses ecx ebx hWnd, uMsg, wParam, lParam local hLocal mov eax, uMsg .if eax == WM_COMMAND mov eax, wParam .if ax == IDOK invoke GetDlgItemInt, hWnd, IDC_ERRCODE, NULL, FALSE mov ecx, eax ; store error code in ecx lea ebx, [hLocal] invoke FormatMessage, FORMAT_MESSAGE_FROM_SYSTEM or FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, ecx, 409h, ebx, 0, NULL .if eax > 0 && hLocal > 0 invoke LocalLock, hLocal .if eax != 0 invoke SetDlgItemText, hWnd, IDC_ERRTEXT, eax invoke LocalFree, hLocal .endif .else invoke SetDlgItemText, hWnd, IDC_ERRTEXT, offset szNotFound .endif .elseif ax == IDCANCEL invoke EndDialog, hWnd, 0 .elseif ax == IDC_ALWAYSONTOP invoke IsDlgButtonChecked, hWnd, IDC_ALWAYSONTOP .if eax > 0 invoke SetWindowPos, hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE or SWP_NOSIZE .else invoke SetWindowPos, hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE or SWP_NOSIZE .endif .endif .elseif eax == WM_CLOSE invoke EndDialog, hWnd, 0 .elseif eax == WM_INITDIALOG invoke LoadIcon, hInst, IDI_ERRSHOW invoke SendMessage, hWnd, WM_SETICON, ICON_BIG, eax invoke SendDlgItemMessage, hWnd, IDC_ERRCODE, EM_LIMITTEXT, 5, 0 invoke SetDlgItemInt, hWnd, IDC_ERRCODE, 0, FALSE mov ax, BN_CLICKED mov cl, 16 shl eax, cl mov ax, IDOK mov ecx, eax invoke GetDlgItem, hWnd, IDOK invoke PostMessage, hWnd, WM_COMMAND, ecx, eax .else mov eax, FALSE ret .endif mov eax, TRUE ret_DialogProc endpstart: invoke GetModuleHandle, NULL ;push eax ;pop hInst mov hInst, eax invoke DialogBoxParam, hInst, IDD_ERRSHOW, NULL, addr _DialogProc, 0 invoke ExitProcess, 0 end start编译:
ml /c /coff ErrorShow.asmrc ErrorShow.rclink /subsystem:windows /out:ErrorShow.exe ErrorShow.obj ErrorShow.res或者用写makefile, 用nmake.exe编译:
makefile如下:
NAME=ErrorShowOBJ=$(NAME).objRES=$(NAME).resML_FLAG=/c /coffLINK_FLAG=/subsystem:windows /out:$(NAME).exe$(NAME).exe: $(OBJ) $(RES) link $(LINK_FLAG) $(OBJ) $(RES).asm.obj: ml $(ML_FLAG) $<.rc.res: rc $<clean: del *.obj del *.res del *.exe程序运行效果如下:
将上面的程序反汇编,对照着看:
00401000 /. 55 push ebp00401001 |. 8BEC mov ebp, esp00401003 |. 83C4 FC add esp, -4 ; 为局部变量hLocal分配栈空间00401006 |. 51 push ecx ; 保存ecx00401007 |. 53 push ebx ; 保存ebx00401008 |. 8B45 0C mov eax, dword ptr [ebp+C] ; mov eax, uMsg0040100B |. 3D 11010000 cmp eax, 111 ; cmp eax, WM_COMMAND; Switch (cases 10..111)00401010 |. 0F85 E3000000 jnz 004010F900401016 |. 8B45 10 mov eax, dword ptr [ebp+10] ; mov eax, wParam; Case 111 (WM_COMMAND) of switch 0040100B00401019 |. 66:83F8 01 cmp ax, 1 ; cmp ax, IDOK0040101D |. 75 7A jnz short 004010990040101F |. 6A 00 push 0 ; /IsSigned = FALSE00401021 |. 6A 00 push 0 ; |pSuccess = NULL00401023 |. 68 E8030000 push 3E8 ; |ControlID = 3E8 (1000.)00401028 |. FF75 08 push dword ptr [ebp+8] ; |hWnd0040102B |. E8 BE010000 call ; \GetDlgItemInt00401030 |. 8BC8 mov ecx, eax ; 将ErrCode保存在ecx中00401032 |. 8D5D FC lea ebx, dword ptr [ebp-4] ; lea ebx, [hLocal]00401035 |. 6A 00 push 0 ; /Arguments = NULL00401037 |. 6A 00 push 0 ; |BufSize = 000401039 |. 53 push ebx ; |Buffer0040103A |. 68 09040000 push 409 ; |LanguageId = 409 (LANG_ENGLISH)0040103F |. 51 push ecx ; |MessageId00401040 |. 6A 00 push 0 ; |pSource = NULL00401042 |. 68 00110000 push 1100 ; |Flags = ALLOCATE_BUFFER|FROM_SYSTEM|000401047 |. E8 78010000 call ; \FormatMessageA0040104C |. 83F8 00 cmp eax, 0 ; FormatMessageA是否执行成功0040104F |. 76 31 jbe short 00401082 ; 执行失败, 转到失败处理00401051 |. 837D FC 00 cmp dword ptr [ebp-4], 0 ; cmp hLocal, 000401055 |. 76 2B jbe short 0040108200401057 |. FF75 FC push dword ptr [ebp-4] ; /hMemory0040105A |. E8 77010000 call ; \LocalLock0040105F |. 0BC0 or eax, eax ; if eax > 0 ?00401061 |. 0F84 22010000 je 0040118900401067 |. 50 push eax ; /Text00401068 |. 68 E9030000 push 3E9 ; |ControlID = 3E9 (1001.)0040106D |. FF75 08 push dword ptr [ebp+8] ; |hWnd00401070 |. E8 A3010000 call ; \SetDlgItemTextA00401075 |. FF75 FC push dword ptr [ebp-4] ; /hMemory00401078 |. E8 53010000 call ; \LocalFree0040107D |. E9 07010000 jmp 0040118900401082 |> 68 57204000 push 00402057 ; /Text = "Error Number Not Found"00401087 |. 68 E9030000 push 3E9 ; |ControlID = 3E9 (1001.)0040108C |. FF75 08 push dword ptr [ebp+8] ; |hWnd0040108F |. E8 84010000 call ; \SetDlgItemTextA00401094 |. E9 F0000000 jmp 0040118900401099 |> 66:83F8 02 cmp ax, 2 ; cmp ax, IDCANCEL0040109D |. 75 0F jnz short 004010AE0040109F |. 6A 00 push 0 ; /Result = 0004010A1 |. FF75 08 push dword ptr [ebp+8] ; |hWnd004010A4 |. E8 39010000 call ; \EndDialog004010A9 |. E9 DB000000 jmp 00401189004010AE |> 66:3D EA03 cmp ax, 3EA ; cmp ax, IDC_ALWAYSONTOP004010B2 |. 0F85 D1000000 jnz 00401189004010B8 |. 68 EA030000 push 3EA ; /ButtonID = 3EA (1002.)004010BD |. FF75 08 push dword ptr [ebp+8] ; |hWnd004010C0 |. E8 2F010000 call ; \IsDlgButtonChecked004010C5 |. 83F8 00 cmp eax, 0004010C8 |. 76 16 jbe short 004010E0004010CA |. 6A 03 push 3 ; /Flags = SWP_NOSIZE|SWP_NOMOVE004010CC |. 6A 00 push 0 ; |Height = 0004010CE |. 6A 00 push 0 ; |Width = 0004010D0 |. 6A 00 push 0 ; |Y = 0004010D2 |. 6A 00 push 0 ; |X = 0004010D4 |. 6A FF push -1 ; |InsertAfter = HWND_TOPMOST004010D6 |. FF75 08 push dword ptr [ebp+8] ; |hWnd004010D9 |. E8 40010000 call ; \SetWindowPos004010DE |. EB 14 jmp short 004010F4004010E0 |> 6A 03 push 3 ; /Flags = SWP_NOSIZE|SWP_NOMOVE004010E2 |. 6A 00 push 0 ; |Height = 0004010E4 |. 6A 00 push 0 ; |Width = 0004010E6 |. 6A 00 push 0 ; |Y = 0004010E8 |. 6A 00 push 0 ; |X = 0004010EA |. 6A FE push -2 ; |InsertAfter = HWND_NOTOPMOST004010EC |. FF75 08 push dword ptr [ebp+8] ; |hWnd004010EF |. E8 2A010000 call ; \SetWindowPos004010F4 |> E9 90000000 jmp 00401189004010F9 |> 83F8 10 cmp eax, 10 ; cmp eax, WM_CLOSE004010FC |. 75 0C jnz short 0040110A004010FE |. 6A 00 push 0 ; /Result = 0; Case 10 (WM_CLOSE) of switch 0040100B00401100 |. FF75 08 push dword ptr [ebp+8] ; |hWnd00401103 |. E8 DA000000 call ; \EndDialog00401108 |. EB 7F jmp short 004011890040110A |> 3D 10010000 cmp eax, 110 ; cmp eax, WM_INITDIALOG0040110F |. 75 6D jnz short 0040117E00401111 |. 6A 66 push 66 ; /RsrcName = 102.; Case 110 (WM_INITDIALOG) of switch 0040100B00401113 |. FF35 00304000 push dword ptr [403000] ; |hInst = NULL00401119 |. E8 DC000000 call ; \LoadIconA0040111E |. 50 push eax ; /lParam0040111F |. 6A 01 push 1 ; |wParam = 100401121 |. 68 80000000 push 80 ; |Message = WM_SETICON00401126 |. FF75 08 push dword ptr [ebp+8] ; |hWnd00401129 |. E8 DE000000 call ; \SendMessageA0040112E |. 6A 00 push 0 ; /lParam = 000401130 |. 6A 05 push 5 ; |wParam = 500401132 |. 68 C5000000 push 0C5 ; |Message = EM_LIMITTEXT00401137 |. 68 E8030000 push 3E8 ; |ControlID = 3E8 (1000.)0040113C |. FF75 08 push dword ptr [ebp+8] ; |hWnd0040113F |. E8 C2000000 call ; \SendDlgItemMessageA00401144 |. 6A 00 push 0 ; /IsSigned = FALSE00401146 |. 6A 00 push 0 ; |Value = 000401148 |. 68 E8030000 push 3E8 ; |ControlID = 3E8 (1000.)0040114D |. FF75 08 push dword ptr [ebp+8] ; |hWnd00401150 |. E8 BD000000 call ; \SetDlgItemInt00401155 |. 66:B8 0000 mov ax, 0 ; mov ax, BN_CLICKED00401159 |. B1 10 mov cl, 100040115B |. D3E0 shl eax, cl ; 将BN_CLICKED放入EAX的高16位0040115D |. 66:B8 0100 mov ax, 1 ; mov ax, IDOK00401161 |. 8BC8 mov ecx, eax00401163 |. 6A 01 push 1 ; /ControlID = 100401165 |. FF75 08 push dword ptr [ebp+8] ; |hWnd00401168 |. E8 7B000000 call ; \GetDlgItem0040116D |. 50 push eax ; /lParam0040116E |. 51 push ecx ; |wParam0040116F |. 68 11010000 push 111 ; |Message = WM_COMMAND00401174 |. FF75 08 push dword ptr [ebp+8] ; |hWnd00401177 |. E8 84000000 call ; \PostMessageA0040117C |. EB 0B jmp short 004011890040117E |> B8 00000000 mov eax, 0 ; eax=FALSE, 表示消息未处理,留给系统默认处理; Default case of switch 0040100B00401183 |. 5B pop ebx ; 恢复ebx00401184 |. 59 pop ecx ; 恢复ecx00401185 |. C9 leave ; 平衡堆栈,相当于mov esp, ebp; pop ebp00401186 |. C2 1000 retn 10 ; 平衡堆栈, 子程序返回00401189 |> B8 01000000 mov eax, 1 ; eax返回TRUE,表示消息处理过0040118E |. 5B pop ebx ; 恢复ebx0040118F |. 59 pop ecx ; 恢复ecx00401190 |. C9 leave ; 平衡堆栈,相当于mov esp, ebp; pop ebp00401191 \. C2 1000 retn 10 ; 平衡堆栈,子程序返回00401194 >/$ 6A 00 push 0 ; /pModule = NULL00401196 |. E8 2F000000 call ; \GetModuleHandleA0040119B |. A3 00304000 mov dword ptr [403000], eax004011A0 |. 6A 00 push 0 ; /lParam = NULL004011A2 |. 68 00104000 push 00401000 ; |DlgProc = ErrorSho.00401000004011A7 |. 6A 00 push 0 ; |hOwner = NULL004011A9 |. 6A 65 push 65 ; |pTemplate = 65004011AB |. FF35 00304000 push dword ptr [403000] ; |hInst = NULL004011B1 |. E8 26000000 call ; \DialogBoxParamA004011B6 |. 6A 00 push 0 ; /ExitCode = 0004011B8 \. E8 01000000 call ; \ExitProcess004011BD CC int3004011BE .- FF25 10204000 jmp dword ptr [<&kernel32.ExitProces>; kernel32.ExitProcess004011C4 $- FF25 00204000 jmp dword ptr [<&kernel32.FormatMess>; kernel32.FormatMessageA004011CA $- FF25 04204000 jmp dword ptr [<&kernel32.GetModuleH>; kernel32.GetModuleHandleA004011D0 $- FF25 08204000 jmp dword ptr [<&kernel32.LocalFree>>; kernel32.LocalFree004011D6 $- FF25 0C204000 jmp dword ptr [<&kernel32.LocalLock>>; kernel32.LocalLock004011DC $- FF25 18204000 jmp dword ptr [<&user32.DialogBoxPar>; user32.DialogBoxParamA004011E2 $- FF25 1C204000 jmp dword ptr [<&user32.EndDialog>] ; user32.EndDialog004011E8 $- FF25 20204000 jmp dword ptr [<&user32.GetDlgItem>] ; user32.GetDlgItem004011EE $- FF25 24204000 jmp dword ptr [<&user32.GetDlgItemIn>; user32.GetDlgItemInt004011F4 $- FF25 28204000 jmp dword ptr [<&user32.IsDlgButtonC>; user32.IsDlgButtonChecked004011FA $- FF25 2C204000 jmp dword ptr [<&user32.LoadIconA>] ; user32.LoadIconA00401200 $- FF25 30204000 jmp dword ptr [<&user32.PostMessageA>; user32.PostMessageA00401206 $- FF25 34204000 jmp dword ptr [<&user32.SendDlgItemM>; user32.SendDlgItemMessageA0040120C $- FF25 38204000 jmp dword ptr [<&user32.SendMessageA>; user32.SendMessageA00401212 $- FF25 3C204000 jmp dword ptr [<&user32.SetDlgItemIn>; user32.SetDlgItemInt00401218 $- FF25 40204000 jmp dword ptr [<&user32.SetDlgItemTe>; user32.SetDlgItemTextA0040121E $- FF25 44204000 jmp dword ptr [<&user32.SetWindowPos>; user32.SetWindowPos反汇编后的代码将汇编源码中的很多宏改成了直接的跳转命令,对于invoke宏也改成了push和call指令。
阅读(1357) | 评论(0) | 转发(0) |