;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Sample code for < Win32ASM Programming >
; by 罗云彬, http://asm.yeah.net
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Hello.asm
; 使用 Win32ASM 写的 Hello, world 程序
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 使用 nmake 或下列命令进行编译和链接:
; ml /c /coff Hello.asm
; Link /subsystem:windows Hello.obj
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.386
.model flat,stdcall
option casemap:none
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Include 文件定义
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 数据段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.data
szCaption db 'A MessageBox !',0
szText db 'Hello, World !',0
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 代码段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.code
start:
invoke MessageBox,NULL,offset szText,offset szCaption,MB_OK
invoke ExitProcess,NULL
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
end start
@1.模式定义:
程序的第一部分是模式和源程序格式的定义语句:
.386
.model flat,stdcall
option casemap:none
这些指令定义了程序使用的指令集、工作模式和格式
.386 语句是汇编语言的伪指令,用于告诉编译器在本程序中使用的指令集。在DOS的汇编中默认使用8086指令集
.model 语句在低版本的汇编中已经存在,用来定义程序工作的模式,它的使用办法是
.model 内存模式[,语言模式][,其它模式]
内存模式的定义影响最后生成的可执行文件,可执行文件的规模从小到大,可以有很多种类型,在DOS的可执行程序中,有只用到64KB的.com文件,也有大大小小的.exe文件。到了Win32环境下,又有了可以用4GB内存的PE格式可执行文件,编写不同类型的可执行文件要用.model语句定义不同的参数
Windows程序运行在保护模式下,系统把每一个Win32应用程序都放到分开的虚拟地址空间中去运行,也就是说,第一个应用程序都拥有其相互独立的4GB地址空间,对Win32程序来说,只有一种内存模式,即flat(平坦)模式,意思是内存是很“平坦”地从0延伸到4GB,再没有64KB段大小限制。
纵观Win32汇编的源程序,没有一处可以找到 ds 或 es 等段寄存器的使用,因为所有的4GB空间用32位寄存器全部都能访问到了。
如果定义了.model flat, MASM 自动为各种段寄存器做了如下定义:
ASSUME cs:FLAT, ds:FLAT, ss:FLAT, es:FLAT, fs:ERROR, gs:ERROR
这时如果在源程序中使用FS或GS,编译时会报错。如果有必要使用它们,只需在使用前用下面的语句声明一下就可以了
assume fs:nothing, gs:nothing 或者 assume fs:flat, gs:flat
option 语句
用 option 语句定义的选项很多,如 option language 定义和 option segment 定义等,在Win32汇编程序中,需要的只是定义 option casemap:none,这个语句定义了程序中的变量和子程序名是否对大小写敏感,由于Win32 API中的API名称是区分大小写的,所以必须指定这个选项,否则在调用API的时候会有问题。
@2.段的定义
1.段的概念
.stack,,.data, .data?,.const,和.code是分段伪指令,Win32中实际只有代码和数据之分,.data,.data?和.const都是数据段,.code是代码段,与DOS汇编不同,由于Win32汇编不必考虑堆栈,系统会为程序分配一个向下可扩展的、足够大的段作为堆栈段,所以.stack段定义常常被忽略。
2.数据段
[1] 可读可写的已定义变量——必须定义在.data段中
[2] 可读可写的未定义变量——这些数据可以在.data段中,也可以在.data?段中,但一般放到.data?段中
>>>定义在.data?段中不会增大.exe文件的大小
[3] 常量放在.const段中,它是不可读不可写的,为了方便起见在小程序中常常把一些常量定义到.data段中,在程序中如果不小心对.const段的数据段写操作的指令,会引起保护作用,Windows会显示一个提示框并结束程序
3.代码段
.code 段是代码段,所有指令都必须写在代码段中,在可执行文件中,代码段一般是放在_TEXT节区的。
Win32环境中的数据段是不可执行的,只有代码段有执行的属性。对于工作在特权级3的应用程序来说,.code段是不可写的。
4.堆栈段
在程序中不必定义堆栈段,系统会自动分配堆栈空间。
堆栈段的内存属性是可读写并且是可执行的,这样靠动态修改代码的反跟踪模块可以拷贝到堆栈中去边修改边执行。