Last updated on:February 18, 2023 pm
1 win32的汇编开发流程
2 win32汇编源程序的结构
Hello world程序在DOS汇编:
;堆栈段
stack segment stack
db 100 dup (?)
stack ends
;数据段
data segment
szHello db 'Hello, world',0dh,0ah,'$'
data ends
;代码段
code segment
assume cs:code,ds:data,ss:stack
start:
mov ax,data
mov ds,ax
mov ah,9
mov dx,offset,szHello
int 21h
code ends
end start
Hello world的Win32程序:
.386
.model flat,stdcall
option casemap:none
;include定义
include windows.inc
include user32.inc
include user32.lib
include kernel32.inc
include 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
2.1 模式定义
2.1.1 指定使用的指令集
.386
是汇编的伪指令,用于告诉编译器在本程序中使用的指令集为80386所拥有的指令集。类似的指令还有:.8086, .186, .386p, .486/486p, .586/.586p
等。后面带p的伪指令表示程序中可以使用**特权指令(必须在特权级0上运行的指令)**如:mov cr0, eax
2.1.2 .model语句
用来定义程序工作的模式。用法如下:
.model 内存模式 [, 语言模式] [, 其他模式]
模式 | 内存使用方式 |
---|---|
tiny | 用来建立 .com文件,所有代码、数据和堆栈都在同一个64KB段内 |
small | 建立代码和数据分别别用一个64KB段的 .exe文件 |
medium | 代码段可以有多个64KB段,数据段只有一个64KB段 |
compact | 代码段只有一个64KB段,数据段可以有多个64KB段 |
large | 代码段和数据段都可以由多个64KB段 |
huge | 同large,并且数据段中的一个数组也可以超过64KB |
flat | Win32程序使用的模式,代码和数据段使用同一个4GB段 |
对于运行在保护模式下的win32程序,它只有一种内存模式——flat模式,即每一个应用程序都拥有其相互独立的4GB地址空间。
2.1.3 option语句
option casemap:none
,该语句定义了程序中变量和子程序名是否对大小写敏感。由于Win32 API名称是区分大小写的,故在win32汇编程序中必须指定此语句。
2.2 段的定义
2.2.1 段的概念
一个包含全部段的源程序结构:
.386
.model flat, stdcall
option casemap:none
<include statements>
.stack [堆栈段的大小]
.data
<一些初始化过的变量定义>
.data?
<一些没有初始化过的变量定义>
.const
<一些常量定义>
.code
<代码>
<开始标号>
<语句>
end 开始标号
- 其中.stack, .data, .data?, .const和.code都是分段伪指令。
- Win32只有代码和数据段之分,因此.data, .data?和.const属于数据段,.code属于代码段。
- 与DOS汇编不同,Win32汇编不必考虑堆栈,.stack段定义常常被忽略。
2.2.2 数据段
.data,.data?和.const定义在数据段,分别对应不同方式的数据定义,在最后生成的可执行文件中也放置在不同的节区(Section)。程序中的数据定义一般可以归纳为三类:
- 可读可写的已定义变量。被定义在.data段,具有以下性质:
- 在源程序已经被定义了初始值。
- 具有可读可写性。
- 在程序装入完成之后,这些值存在于内存中。
- .data段一般存放在可执行文件的_DATA节区内。
- 可读可写的未定义变量。可定义在.data段,也可以定义在.data?段,具有以下性质:
- 一般用作缓冲区,或者程序执行后在开始使用。
- 若定义在.data段,则编译器在生成可执行文件时会保留声明大小的空间,即使它们是全0
- 若定义在.data?段,则编译器在生成可执行文件时只会记录空间大小信息,不会浪费磁盘空间,而是在程序执行时才会用到。
- .data?段在可执行文件中一般放在_BSS节区。
- 常量。如一些要显示的字符串信息。
- 它们在程序装入时就已经有效,但在整个执行过程中不需要修改。
- 具有可读不可写性。
- 如果程序对.const段进行写操作,会引起保护错误并结束程序。
2.2.3 代码段
- .code段时代码段,所有的指令都必须写在代码段中
- 在可执行文件中,代码段一般放在_TEXT节区。
- Win32环境下的数据段是不可执行的,只有代码段有可执行的属性。(特权级0下运行的程序对所有段有读写权限)
2.2.4 堆栈段
- Win32程序中不必定义堆栈段,系统会自动分配堆栈空间。
- 堆栈段的内存属性是可读写并可执行的。(靠动态修改代码的反跟踪模块可以拷贝到堆栈中边修改边执行)
2.3 程序入口与结束
- 汇编源程序中,并没有main函数来指定开始执行的地方。取而代之的是程序的最后一句的end语句
end [开始地址]
- 上述语句的开始地址就是源程序从代码段开始执行的地址。
- 上述语句同时还表示源程序结束,所有代码都必须在end语句之前。
- 多模块程序编写时,单一的模块可以没有入口标号,但是最后把多个模块连接在一起时,必须有一个主模块的入口地址被指明。
3 API的调用
3.1 API是什么
3.2 如何调用
3.3.1 invoke语句
3.3.2 函数的声明与返回值
3.3.3 include语句
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!