上个礼拜看win32汇编看的很晕,主要水平不够,今天抽空总结了一下
.*p/.* 特权
flat 平坦的内存,4G
stdcall
casemap:none 表示区别大小写
.data .data?(在pe中只有描述信息) .stack(flat常常忽略)(其中代码可以执行!)
.code
';'表示注释
'/'表示换行符,有区别于Makefile,/后可以有空格或注释
api
kernel32.dll--系统服务功能,内存管理、任务管理、动态链接等
gdi32.dll--图形设备接口
user32.dll--用户接口,建立窗口、传送消息
invoke 函数名[,参数1][,参数2].....
类似于[push 1,push 2,.....,call funcation]
API的返回值放在eax中,如果返回值多余一个eax中是一个指针(内存或缓冲区地址)
调用api之前要声明
函数名 proto [距离] [语言] [参数1]:数据类型 [参数2]:数据类型
默认为.model
默认为.model
参数的名称对于编译器来说无用,可省
win32下,to strings 1.ANSII(A) 2.Unicode(W)
MessageBoxA MessageBoxB
include name [<name>]
includelib
win32下,函数代码放在dll文件中,导入库中只留有函数懂得定位信息和参数数目等简单信息,这种库文件叫做导入库,一个dll文件对应一个导入库,user32.dll-》user32.lib
masm下标号和变量的命名规范
1.字母、数字、下划线和@、¥、?
2.第一个符号不能是数字
3.长度不超过240
4.不能使用指令名等关键字
5.作用域内唯一
标号: 当前子程序
标号:: 全局
@f 只找最近的一个@@
@@
@b 只找最近的一个@@
@@的使用尽量小,不然在以后的维护中容易发生错误
全局变量 定义可以用?预留空间,运行是os复位0(。data?只能用?)
变量名 类型 初始值1.......
变量名 类型 重复数量 dup (1,2......)
只有定义全局变量的类型时,才可以使用缩写(db,dw,dd.....)
byte db 字节
word dw 字
dword dd 双字
fword df 三字
qword dq 四字
tbyte dt 十字节BCD码
sbyte 有符号字节
sword 有符号字
wdword 有符号双字
real4 单精度
real8 双精度
real10 十字节
局部变量
local 变脸名1[[重复数量][:类型]],变量2[[重复数量][:类型]]......
类型默认为dword(32)
local伪指令必须紧接在子程序proc之后,且要在指令开始之前把局部变量确定下来
push ebp 暂存ebp
mov ebp,esp 因为esp随时都会被用到,所以用ebp作为局部变量的指针
add esp,XXXXXXX esp+负值,以预留出局部变量的空间
.......... 内存以dword对其读写最快,masm下会是2的倍数
leave 1.mov esp,ebp
2.pop ebp
从局部变量的实现来看,ebp是实现的关键,所以在子程序中修改ebp的结果会很严重
局部变量和全局变量定义时有所不同,os会给全局变量赋值0,局部变量则是随机的
最好的全局变量初始化方法是调用RrlZeroMemory,因为0通常是api参数的默认值
数据结构(汇编)
结构名 struct
字段1 类型 ?
字段2 类型 ?
......
结构名 ends
使用数据结构定义变量的方法
变量名 结构名 <>[<1,2.......>]
1.变量名.结构成员,直接指向逻辑地址 mov eax,stWndClass.lpfnWndProc
2.结构名.结构成员,以变量名为基址加上偏移地址得到逻辑地址
mov esi,offset stWndClass
mov eax,[esi+WNDCLASS.lpfnWndProc]
3.
mov esi,offset stWndClass
assume esi:ptr WNDCLASS 把esi假定为指向WNDCLASS的结构指针
mov eax,[esi].lpfnWndProc
...
assume esi:nothing 在不用的时候,必须将esi设定为nothing
结构可以嵌套 引用的方式 mov eax,[esi].oldWndClass.lpfnWndProc
变量的“强制类型转化”
类型 ptr 变量名
word ptr bTest
以字节为单位算长度 sizeof 变量名、数据类型、数据结构名
取得变量中的项数 lengthof same
变量的取地址
全局变量 offset(lea可以写入寄存器,在运行是计算地址)
局部变量 addr addr会覆盖eax的值
addr 会自动判断全局和局部
全局同 offset
局部 lea eax,以eax为基址计算
所以 addr对局部变量只能用在invoke中
addr会覆盖eax的值,又由于invoke调用参数从右push,所以eax必须在addr的右边
子程序的定义
子程序名 proc [距离][语言类型][可视区域][USES 寄存器列表][,参数:类型]......
忽略 忽略 默认public
local 局部变量列表
codes
子程序名 endp
不同语言模式的参数传递与子函数回归page95
proto
高级语法最终被翻译为test cmp等比较指令
分支语句 编译器会对分支语句进行很好的优化,但是只有第一条成功匹配后就会跳转。所以有时,会用多条。if语句进行处理
.if 1
...
[.elseif 2]
...
[.elseif 3]
...
[.else]
...
.endif
不要忽视小数点
循环语句
.while 条件
code
[.break [.if 条件]]
[.continue]
.endw
.repeat
code
[.break [.if 条件]]
[.continue]
.until 条件 此处可以用.untilcxz,不过要提前设定ecx
@@以上的高级语法都是多无符号数来说的,要注意判断有符号数时自己取反
代码风格
1.匈牙利表示法
b byte
w word
dw dword
h headle
lp point
sz string end with 0
lpsz point point to sz
f float
st struct
2.补充
全局变量-》 匈牙利
参数-》 _匈牙利
局部变量-》 @匈牙利
内部子程序-》 _匈牙利
书写格式
指令,寄存器小写
equ定义的常量大写
变量、标号大小混写
缩进
变量、标号 不缩进
指令 2个tab
分支 +个tab
就这么多,其实分页管理那块很复杂,要慢慢来