Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1619728
  • 博文数量: 441
  • 博客积分: 20087
  • 博客等级: 上将
  • 技术积分: 3562
  • 用 户 组: 普通用户
  • 注册时间: 2006-06-19 15:35
文章分类

全部博文(441)

文章存档

2014年(1)

2012年(1)

2011年(8)

2010年(16)

2009年(15)

2008年(152)

2007年(178)

2006年(70)

分类: C/C++

2009-07-03 14:07:25

读过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    1002

IDD_ERRSHOW    DIALOGEX    0, 0, 182, 75
STYLE DS_SETFOREGROUND | DS_3DLOOK | DS_CENTER | WS_MINIMIZEBOX | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "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_CLIENTEDGE
END

IDI_ERRSHOW    ICON    DISCARDABLE    "ErrorShow.ico"

; 汇编代码
; ErrorShow.asm
    .386
    .model flat, stdcall
    option casemap: none

include        windows.inc
include        kernel32.inc
includelib    kernel32.lib
include        user32.inc
includelib    user32.lib

IDD_ERRSHOW        EQU    101
IDI_ERRSHOW        EQU    102
IDC_ERRCODE        EQU    1000
IDC_ERRTEXT        EQU    1001
IDC_ALWAYSONTOP        EQU    1002

    .data?
hInst    dd    ?
    .const
szAppName    db    'Error Show', 0
szNotFound    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 endp

start:
    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.asm
rc ErrorShow.rc
link /subsystem:windows /out:ErrorShow.exe ErrorShow.obj ErrorShow.res

或者用写makefile, 用nmake.exe编译:
makefile如下:

NAME=ErrorShow
OBJ=$(NAME).obj
RES=$(NAME).res

ML_FLAG=/c /coff
LINK_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    ebp
00401001  |.  8BEC          mov     ebp, esp
00401003  |.  83C4 FC       add     esp, -4                          ;  为局部变量hLocal分配栈空间
00401006  |.  51            push    ecx                              ;  保存ecx
00401007  |.  53            push    ebx                              ;  保存ebx
00401008  |.  8B45 0C       mov     eax, dword ptr [ebp+C]           ;  mov eax, uMsg
0040100B  |.  3D 11010000   cmp     eax, 111                         ;  cmp eax, WM_COMMAND; Switch (cases 10..111)
00401010  |.  0F85 E3000000 jnz     004010F9
00401016  |.  8B45 10       mov     eax, dword ptr [ebp+10]          ;  mov eax, wParam; Case 111 (WM_COMMAND) of switch 0040100B
00401019  |.  66:83F8 01    cmp     ax, 1                            ;  cmp ax, IDOK
0040101D  |.  75 7A         jnz     short 00401099
0040101F  |.  6A 00         push    0                                ; /IsSigned = FALSE
00401021  |.  6A 00         push    0                                ; |pSuccess = NULL
00401023  |.  68 E8030000   push    3E8                              ; |ControlID = 3E8 (1000.)
00401028  |.  FF75 08       push    dword ptr [ebp+8]                ; |hWnd
0040102B  |.  E8 BE010000   call          ; \GetDlgItemInt
00401030  |.  8BC8          mov     ecx, eax                         ;  将ErrCode保存在ecx中
00401032  |.  8D5D FC       lea     ebx, dword ptr [ebp-4]           ;  lea ebx, [hLocal]
00401035  |.  6A 00         push    0                                ; /Arguments = NULL
00401037  |.  6A 00         push    0                                ; |BufSize = 0
00401039  |.  53            push    ebx                              ; |Buffer
0040103A  |.  68 09040000   push    409                              ; |LanguageId = 409 (LANG_ENGLISH)
0040103F  |.  51            push    ecx                              ; |MessageId
00401040  |.  6A 00         push    0                                ; |pSource = NULL
00401042  |.  68 00110000   push    1100                             ; |Flags = ALLOCATE_BUFFER|FROM_SYSTEM|0
00401047  |.  E8 78010000   call       ; \FormatMessageA
0040104C  |.  83F8 00       cmp     eax, 0                           ;  FormatMessageA是否执行成功
0040104F  |.  76 31         jbe     short 00401082                   ;  执行失败, 转到失败处理
00401051  |.  837D FC 00    cmp     dword ptr [ebp-4], 0             ;  cmp hLocal, 0
00401055  |.  76 2B         jbe     short 00401082
00401057  |.  FF75 FC       push    dword ptr [ebp-4]                ; /hMemory
0040105A  |.  E8 77010000   call            ; \LocalLock
0040105F  |.  0BC0          or      eax, eax                         ;  if eax > 0 ?
00401061  |.  0F84 22010000 je      00401189
00401067  |.  50            push    eax                              ; /Text
00401068  |.  68 E9030000   push    3E9                              ; |ControlID = 3E9 (1001.)
0040106D  |.  FF75 08       push    dword ptr [ebp+8]                ; |hWnd
00401070  |.  E8 A3010000   call        ; \SetDlgItemTextA
00401075  |.  FF75 FC       push    dword ptr [ebp-4]                ; /hMemory
00401078  |.  E8 53010000   call            ; \LocalFree
0040107D  |.  E9 07010000   jmp     00401189
00401082  |>  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]                ; |hWnd
0040108F  |.  E8 84010000   call        ; \SetDlgItemTextA
00401094  |.  E9 F0000000   jmp     00401189
00401099  |>  66:83F8 02    cmp     ax, 2                            ;  cmp ax, IDCANCEL
0040109D  |.  75 0F         jnz     short 004010AE
0040109F  |.  6A 00         push    0                                ; /Result = 0
004010A1  |.  FF75 08       push    dword ptr [ebp+8]                ; |hWnd
004010A4  |.  E8 39010000   call              ; \EndDialog
004010A9  |.  E9 DB000000   jmp     00401189
004010AE  |>  66:3D EA03    cmp     ax, 3EA                          ;  cmp ax, IDC_ALWAYSONTOP
004010B2  |.  0F85 D1000000 jnz     00401189
004010B8  |.  68 EA030000   push    3EA                              ; /ButtonID = 3EA (1002.)
004010BD  |.  FF75 08       push    dword ptr [ebp+8]                ; |hWnd
004010C0  |.  E8 2F010000   call    ; \IsDlgButtonChecked
004010C5  |.  83F8 00       cmp     eax, 0
004010C8  |.  76 16         jbe     short 004010E0
004010CA  |.  6A 03         push    3                                ; /Flags = SWP_NOSIZE|SWP_NOMOVE
004010CC  |.  6A 00         push    0                                ; |Height = 0
004010CE  |.  6A 00         push    0                                ; |Width = 0
004010D0  |.  6A 00         push    0                                ; |Y = 0
004010D2  |.  6A 00         push    0                                ; |X = 0
004010D4  |.  6A FF         push    -1                               ; |InsertAfter = HWND_TOPMOST
004010D6  |.  FF75 08       push    dword ptr [ebp+8]                ; |hWnd
004010D9  |.  E8 40010000   call           ; \SetWindowPos
004010DE  |.  EB 14         jmp     short 004010F4
004010E0  |>  6A 03         push    3                                ; /Flags = SWP_NOSIZE|SWP_NOMOVE
004010E2  |.  6A 00         push    0                                ; |Height = 0
004010E4  |.  6A 00         push    0                                ; |Width = 0
004010E6  |.  6A 00         push    0                                ; |Y = 0
004010E8  |.  6A 00         push    0                                ; |X = 0
004010EA  |.  6A FE         push    -2                               ; |InsertAfter = HWND_NOTOPMOST
004010EC  |.  FF75 08       push    dword ptr [ebp+8]                ; |hWnd
004010EF  |.  E8 2A010000   call           ; \SetWindowPos
004010F4  |>  E9 90000000   jmp     00401189
004010F9  |>  83F8 10       cmp     eax, 10                          ;  cmp eax, WM_CLOSE
004010FC  |.  75 0C         jnz     short 0040110A
004010FE  |.  6A 00         push    0                                ; /Result = 0; Case 10 (WM_CLOSE) of switch 0040100B
00401100  |.  FF75 08       push    dword ptr [ebp+8]                ; |hWnd
00401103  |.  E8 DA000000   call              ; \EndDialog
00401108  |.  EB 7F         jmp     short 00401189
0040110A  |>  3D 10010000   cmp     eax, 110                         ;  cmp eax, WM_INITDIALOG
0040110F  |.  75 6D         jnz     short 0040117E
00401111  |.  6A 66         push    66                               ; /RsrcName = 102.; Case 110 (WM_INITDIALOG) of switch 0040100B
00401113  |.  FF35 00304000 push    dword ptr [403000]               ; |hInst = NULL
00401119  |.  E8 DC000000   call              ; \LoadIconA
0040111E  |.  50            push    eax                              ; /lParam
0040111F  |.  6A 01         push    1                                ; |wParam = 1
00401121  |.  68 80000000   push    80                               ; |Message = WM_SETICON
00401126  |.  FF75 08       push    dword ptr [ebp+8]                ; |hWnd
00401129  |.  E8 DE000000   call           ; \SendMessageA
0040112E  |.  6A 00         push    0                                ; /lParam = 0
00401130  |.  6A 05         push    5                                ; |wParam = 5
00401132  |.  68 C5000000   push    0C5                              ; |Message = EM_LIMITTEXT
00401137  |.  68 E8030000   push    3E8                              ; |ControlID = 3E8 (1000.)
0040113C  |.  FF75 08       push    dword ptr [ebp+8]                ; |hWnd
0040113F  |.  E8 C2000000   call    ; \SendDlgItemMessageA
00401144  |.  6A 00         push    0                                ; /IsSigned = FALSE
00401146  |.  6A 00         push    0                                ; |Value = 0
00401148  |.  68 E8030000   push    3E8                              ; |ControlID = 3E8 (1000.)
0040114D  |.  FF75 08       push    dword ptr [ebp+8]                ; |hWnd
00401150  |.  E8 BD000000   call          ; \SetDlgItemInt
00401155  |.  66:B8 0000    mov     ax, 0                            ;  mov ax, BN_CLICKED
00401159  |.  B1 10         mov     cl, 10
0040115B  |.  D3E0          shl     eax, cl                          ;  将BN_CLICKED放入EAX的高16位
0040115D  |.  66:B8 0100    mov     ax, 1                            ;  mov ax, IDOK
00401161  |.  8BC8          mov     ecx, eax
00401163  |.  6A 01         push    1                                ; /ControlID = 1
00401165  |.  FF75 08       push    dword ptr [ebp+8]                ; |hWnd
00401168  |.  E8 7B000000   call             ; \GetDlgItem
0040116D  |.  50            push    eax                              ; /lParam
0040116E  |.  51            push    ecx                              ; |wParam
0040116F  |.  68 11010000   push    111                              ; |Message = WM_COMMAND
00401174  |.  FF75 08       push    dword ptr [ebp+8]                ; |hWnd
00401177  |.  E8 84000000   call           ; \PostMessageA
0040117C  |.  EB 0B         jmp     short 00401189
0040117E  |>  B8 00000000   mov     eax, 0                           ;  eax=FALSE, 表示消息未处理,留给系统默认处理; Default case of switch 0040100B
00401183  |.  5B            pop     ebx                              ;  恢复ebx
00401184  |.  59            pop     ecx                              ;  恢复ecx
00401185  |.  C9            leave                                    ;  平衡堆栈,相当于mov esp, ebp; pop ebp
00401186  |.  C2 1000       retn    10                               ;  平衡堆栈, 子程序返回
00401189  |>  B8 01000000   mov     eax, 1                           ;  eax返回TRUE,表示消息处理过
0040118E  |.  5B            pop     ebx                              ;  恢复ebx
0040118F  |.  59            pop     ecx                              ;  恢复ecx
00401190  |.  C9            leave                                    ;  平衡堆栈,相当于mov esp, ebp; pop ebp
00401191  \.  C2 1000       retn    10                               ;  平衡堆栈,子程序返回
00401194 >/$  6A 00         push    0                                ; /pModule = NULL
00401196  |.  E8 2F000000   call    ; \GetModuleHandleA
0040119B  |.  A3 00304000   mov     dword ptr [403000], eax
004011A0  |.  6A 00         push    0                                ; /lParam = NULL
004011A2  |.  68 00104000   push    00401000                         ; |DlgProc = ErrorSho.00401000
004011A7  |.  6A 00         push    0                                ; |hOwner = NULL
004011A9  |.  6A 65         push    65                               ; |pTemplate = 65
004011AB  |.  FF35 00304000 push    dword ptr [403000]               ; |hInst = NULL
004011B1  |.  E8 26000000   call        ; \DialogBoxParamA
004011B6  |.  6A 00         push    0                                ; /ExitCode = 0
004011B8  \.  E8 01000000   call          ; \ExitProcess
004011BD      CC            int3
004011BE   .- FF25 10204000 jmp     dword ptr [<&kernel32.ExitProces>;  kernel32.ExitProcess
004011C4   $- FF25 00204000 jmp     dword ptr [<&kernel32.FormatMess>;  kernel32.FormatMessageA
004011CA   $- FF25 04204000 jmp     dword ptr [<&kernel32.GetModuleH>;  kernel32.GetModuleHandleA
004011D0   $- FF25 08204000 jmp     dword ptr [<&kernel32.LocalFree>>;  kernel32.LocalFree
004011D6   $- FF25 0C204000 jmp     dword ptr [<&kernel32.LocalLock>>;  kernel32.LocalLock
004011DC   $- FF25 18204000 jmp     dword ptr [<&user32.DialogBoxPar>;  user32.DialogBoxParamA
004011E2   $- FF25 1C204000 jmp     dword ptr [<&user32.EndDialog>]  ;  user32.EndDialog
004011E8   $- FF25 20204000 jmp     dword ptr [<&user32.GetDlgItem>] ;  user32.GetDlgItem
004011EE   $- FF25 24204000 jmp     dword ptr [<&user32.GetDlgItemIn>;  user32.GetDlgItemInt
004011F4   $- FF25 28204000 jmp     dword ptr [<&user32.IsDlgButtonC>;  user32.IsDlgButtonChecked
004011FA   $- FF25 2C204000 jmp     dword ptr [<&user32.LoadIconA>]  ;  user32.LoadIconA
00401200   $- FF25 30204000 jmp     dword ptr [<&user32.PostMessageA>;  user32.PostMessageA
00401206   $- FF25 34204000 jmp     dword ptr [<&user32.SendDlgItemM>;  user32.SendDlgItemMessageA
0040120C   $- FF25 38204000 jmp     dword ptr [<&user32.SendMessageA>;  user32.SendMessageA
00401212   $- FF25 3C204000 jmp     dword ptr [<&user32.SetDlgItemIn>;  user32.SetDlgItemInt
00401218   $- FF25 40204000 jmp     dword ptr [<&user32.SetDlgItemTe>;  user32.SetDlgItemTextA
0040121E   $- FF25 44204000 jmp     dword ptr [<&user32.SetWindowPos>;  user32.SetWindowPos

反汇编后的代码将汇编源码中的很多宏改成了直接的跳转命令,对于invoke宏也改成了push和call指令。
阅读(1357) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~