一:等号伪指令:等号伪指令将符号名和整数表达式联系起来
名字 = 表达式
编译器在预处理阶段,扫描源代码,将出现“”名字“”的地方换成表达式
count = 10
name DWORD count DUP(?)
mov eax, count
可以重复定义
二:$:当前指令地址
list BYTE 10,20,30,40
ListSize = ($ - list)
三:EQU伪指令将符号名同整数表达式或任意文本联系起来
name EQU expression ;必须是有效的整数表达式
name EQU symbol ;symbol必须是已用“=”或者EQU定义的符号名
name EQU
pressKey EQU <"Press any key to continue......", 0>
.data
prompt BYTE pressKey
setupBL EQU
setupBL ; = mov bl,10
不可以重复定义
四:TEXTQU伪指令
name TEXTEQU
name TEXTEQU textmacro
name TEXTEQU %constExpr
continueMsg TEXTEQU <"Do you wish to continue">
.data
prompt1 BYTE continueMsg
rowSize = 5
count TEXTEQU %(rowSize *2)
move TEXTEQU
setupAL TEXTEQU
setupAL ; = mov al, 10
可以重定义
三:OFFSET操作符
返回数据标号的偏移地址
num DWORD 80h
mov eax, OFFSET num
讲过查询,该条指令在PE文件中是mov eax, (num的VA),注意是VA,不是书中所说的是段内的偏移!!
mov eax, OFFSET num + 2 ;该条指令是将num的VA+2的结果,放在eax中,不是书中所说的该地址的数值
mov eax, [OFFSET num +2] ;改指令和上条指令结果是一致的。so,直接内存操作数,只是对数据标号来说的,没有这里的[OFFSET num + 2]
四:ALIGN伪指令
bVal BYTE ?
ALIGN 2
wVal WORD ?
bVal2 BYTE ?
ALIGN 4
dVal DWORD?
经过查看,没有ALIGN时,这几个变量在.data数据节中是紧挨着的,加上ALIGN后,地址开始对齐。
ALIGN仅对下一个变量起到左右,一是变量紧挨着,二是单位是变量(包括数组),数组内的内容不按照ALIGN对齐
例如
mytl BYTE 10h
ALIGN 2
myArray BYTE 1,2,3,4,5
mj DWORD 12h
1:mj不按照2对齐,2:myArray起始地址按照2对齐,里面的不按照2对齐
五:PTR操作符
重载操作数声明的默认尺寸
myDouble DWORD 12345678h
mov ax, WORD PTR myDouble ;ax=5678h
mov ax, WORD PTR [myDouble+2]; ax=1234h == WORD PTR myDouble +2
mov bl, BYTE PTR myDouble ;ax=78h == BYTE PTR[myDouble]
六:TYPE操作符
val1 BYTE ?
val2 DWORD?
mov eax, TYPE val1
mov ebx, TYPE val2
在PE文件中,直接将TYPE val1变为1,TYPE val2 变为4
七:LENGTHOF数组个数
myArray DWORD 1,2,3,4,5
DWORD 6,7
LENGTHOF myArray = 5
八:SIZEOF=LENGTHOF*TYPE
九:LABEL伪指令
val16 LABEL WORD
val32 DWORD 12345678h
mov ax, val16; ax=5678h
十:定义指针
arrayB BYTE 10h,20h,30h,40h
arrayW WORD 1000h,2000h,3000h
ptrB DWORD arrayB == ptrBB DWORD OFFSET arrayB
ptrW DWORDarrayW == ptrWW DWORD OFFSET arrayW
PBYTE TYPEDEF PTR BYTE (TYPEDEF PTR 声明PBYTE是指针)
arrayB BYTE 10h,20h
ptr1 PBYTE arrayB
数据标号指针定义:
arrayA BYTE 'asdf',0
ptrA DWORD arrayA
===
ptrB DWORD OFFSET arrayA
代码标号指针定义
CaseTable BYTE 'A'
DWORD Process_A
EntrySize = ($-CaseTable)
BYTE 'B'
DWORD Process_B ;===DWORD OFFSET Process_B
BYTE 'C'
DWORD Process_C
BYTE 'D'
DWORD Process_D
其中process_*是函数名称,通过OD可以知道,是直接在.data中,写入了Process_*的VA
call NEAR PTR [ebx+1]
十一: ::
标号::
jmp的标号必须在本过程内,但可以使用标号::定义全局标号
十二:局部变量 LOCAL
LOCAL tmp:DWORD, SwapFlag:BYTE,Array[10]:DWORD
十二:保留一定大小的堆栈空间
.stack 4096
十二:EXTERN
test.asm:
fun1 PROC
enter 0,0
mov eax, [ebp+8] ;有参数的
leave
ret 4 ;去掉参数 ;由于没有和fun2一样定义,必须自己处理堆栈平衡
fun1 ENDP
fun2 PROC, op1:DWORD, op2:DWORD
mov eax, op1
ret ;不需要自己处理堆栈平衡,编译器生成的时候,自动ret 8
fun2 ENDP
main.asm:
EXTERN fun1@0:PROC ;虽然fun1使用时候需要使用堆栈参数,但是函数没有和fun2一样定义,so是@0
EXTERN fun2@8PROC ; fun2使用了函数参数定义,so是@8
十三:PROC PROTO USES
myfun1 PROC USERS eax, ebx, op1:DWORD,op2:DWORD
ret
myfun1 ENDP
在编译器编译遇到声明了参数的PROC的时候,会生成push ebp ;mov ebp, esp; sub esp, 8.........;leave ret 8