简单的32位汇编程序

hello.inc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
.386    ;指令集
.model flat,stdcall ;平坦模式(不分段)
OPTION CASEMAP:none ;大小写敏感

;常量区
.const
MY_MSG db "Hello World!",0
MY_TITLE db "51asm",0

;未初始化数据区
;.data?
;NUM2 db ? ;不占用文件空间

;初始化数据区
.data
NUM1 db 0

;函数声明
MessageBoxA proto hWnd:dword,lpText:dword,lpCaption:dword,uType:dword
ExitProcess proto uExitCode:dword

hello.asm

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
include hello.inc
includelib user32.lib
includelib kernel32.lib

;代码区
.code
START:
;寻址方式的差异 新指令
;内存寻址
; mov eax,[eax]
; mov eax,[ebx+eax+01]
; mov eax,[esp]
; mov eax,[esp+1]

;增加比例因子寻址方式
; mov eax,[ebx+eax*2]
; mov eax,[esp+ebx*8+8]

; add eax,ebx
; add ax,bx
; movzx eax,ax ;16位0扩展位32位
; movsx eax,ax ;16位符号扩展位32位

; pushad ;保存所有通用寄存器
; popad
; movzx,ax,al

; mov eax,dword ptr [START] ;windbg
; jmp eax

invoke MessageBoxA,0,offset MY_MSG,offset MY_TITLE,0
invoke ExitProcess,0
ret

end START
1
.386    ;指令集
  • 指定代码适用于80386处理器,启用32位指令。
1
.model flat,stdcall     ;平坦模式(不分段)
  • 指定使用平坦内存模型,不分段,使用 stdcall 调用约定。
1
OPTION CASEMAP:none     ;大小写敏感
  • 设置大小写敏感,意味着标识符区分大小写。
1
2
3
4
;常量区
.const
MY_MSG db "Hello World!",0
MY_TITLE db "51asm",0
  • 常量区,定义两个字符串常量,MY_MSG 是要显示的信息,MY_TITLE 是消息框的标题。每个字符串以0结尾,表示C风格字符串。
1
2
3
;未初始化数据区
;.data?
;NUM2 db ? ;不占用文件空间
  • 注释掉的未初始化数据段(.data?),可以用于声明不占用文件空间的未初始化变量,例如 NUM2
1
2
3
;初始化数据区
.data
NUM1 db 0
  • 初始化数据段,定义一个名为 NUM1 的字节变量并初始化为0。
1
2
3
;函数声明
MessageBoxA proto hWnd:dword,lpText:dword,lpCaption:dword,uType:dword
ExitProcess proto uExitCode:dword
  • 声明两个外部函数 MessageBoxAExitProcessMessageBoxA 用于显示一个消息框,ExitProcess 用于终止进程。
1
2
3
;代码区
.code
START:
  • 代码段开始,定义程序的入口点为 START
1
2
3
4
5
6
;寻址方式的差异 新指令
;内存寻址
; mov eax,[eax]
; mov eax,[ebx+eax+01]
; mov eax,[esp]
; mov eax,[esp+1]
  • 这些是各种内存寻址方式的示例代码:
    • mov eax,[eax]:直接寻址。
    • mov eax,[ebx+eax+01]:基址加变址加偏移寻址。
    • mov eax,[esp]:栈指针寻址。
    • mov eax,[esp+1]:栈指针加偏移寻址。
1
2
3
;增加比例因子寻址方式
; mov eax,[ebx+eax*2]
; mov eax,[esp+ebx*8+8]
  • 这些是使用比例因子的寻址方式:
    • mov eax,[ebx+eax*2]:基址加比例变址寻址。
    • mov eax,[esp+ebx*8+8]:栈指针加基址加比例变址加偏移寻址。
1
2
3
4
; add eax,ebx
; add ax,bx
; movzx eax,ax ;16位0扩展位32位
; movsx eax,ax ;16位符号扩展位32位
  • 算术和数据转换操作:
    • add eax,ebx:将寄存器 ebx 的值加到寄存器 eax
    • add ax,bx:将16位寄存器 bx 的值加到16位寄存器 ax
    • movzx eax,ax:将16位寄存器 ax 的值零扩展到32位寄存器 eax
    • movsx eax,ax:将16位寄存器 ax 的值符号扩展到32位寄存器 eax
1
2
3
; pushad      ;保存所有通用寄存器
; popad
; movzx,ax,al
  • 寄存器保存与数据转换:
    • pushad:将所有通用寄存器的值压入堆栈。
    • popad:从堆栈中弹出所有通用寄存器的值。
    • movzx ax,al:将8位寄存器 al 的值零扩展到16位寄存器 ax
1
2
; mov eax,dword ptr [START]   ;windbg
; jmp eax
  • 这些是用于调试或跳转的指令示例:
    • mov eax,dword ptr [START]:将 START 地址的值移动到 eax 寄存器中。
    • jmp eax:跳转到 eax 指定的地址。
1
invoke MessageBoxA,0,offset MY_MSG,offset MY_TITLE,0
  • 调用 MessageBoxA 函数,显示一个消息框,标题为 MY_TITLE,内容为 MY_MSG,其他参数为0。
1
invoke ExitProcess,0
  • 调用 ExitProcess 函数,终止进程,返回代码为0。
1
ret
  • 返回指令,但在这里是多余的,因为程序已经通过 ExitProcess 终止。
1
end START
  • 指定程序的结束,并标识入口点为 START

运行结果

image-20240816221359486