以下是自己在win32汇编学习实践中总结的一些小知识点,欢迎大家拍砖
1. dos 汇编 与 win32 汇编编译器与连接器的区别:
(1) 编译器
Dos 和 win16 环境下,编译器(masm)生成的obj文件的格式为 OMF(Intel Object Module Format), win32环境下,编译器(多为 ml)生成的obj 文件的格式为 COFF.
masm 从 6.11版开始支持 COFF.
(2) 连接器(link)
Dos 环境下的连接器为 Segmented Executable Linker,该连接器不能连接COFF格式,只能连接OMF格式。
Win32 环境下的连接器为 Incremental Linker,只能连接COFF格式,不能连接OMF格式。
2. masm 中 “stacall调用方式” 应注意的问题(ml: 6.14.8444):
(1) stdcall堆栈平衡的方式 :如果子程序参数不可变,那么由子程序平衡堆栈;如果子程序的参数是可变的(即子程序定义中,参数列表的最后有 VARARG,比如wsprintf),那么由调用者平衡堆栈。
但如果调用子程序用的是 invoke 伪指令,那么masm 会自动为你去平衡堆栈,比如:
invoke wsprintf, offset str1, offset str2, arg1, agr2
masm 会编译为下列汇编代码:
push offset arg2
push offset arg2
push str2
push str1
call wsprintf
add esp, 10h ; 平衡堆栈的指令已经由 invoke 伪指令自动加上了,所以在用 invoke 伪指令调用子程序时(前提是 stdcall),即使子程序时可变参数,也不需要自己加平衡堆栈的代码。
但如果调用子程序用的是 call 指令,那么如果子程序是可变参数的话,那么在 call 指令之后,就应该自己去平衡堆栈了。
3. leave 指令
本科教材的解释:高级过程退出,功能是:
BP/EBP->SP/ESP, POP BP/EBP
4. 子程序声明局部变量后,退出时的清理问题:
Proc1 proc
local b1[6]:byte, w1
mov b1[0], 'H'
mov b1[1], 'e'
mov b1[2], 'l'
mov b1[3], 'l'
mov b1[4], 'o'
mov b1[5], 0
mov w1, 12345678h
。。。。。。 ;其他操作
ret
Proc1 endp
通过反汇编可知,ml 会在 ret 之前自动加上 leave 指令,用来恢复堆栈。但是很奇怪,如果源文件中的返回指令为:retn 或者 retf, 那么 ml 不会在 ret 之前加上 leave 指令,由此导致子程序返回到无效的地址。
5. 关于Win32 API 的参数及返回值
Win32 API 的参数均为 dword 类型(在调用 Win32 API 时,一定要保证每个参数在入栈时压入的是 2 个字节),如果有返回值的话,返回值也是 dword 类型,且永远放在 eax 中。
6. 程序退出
在 8086 汇编中,需要自己调用中断退出。在 win32 汇编中同样需要自己调用相应 Windows API 退出(比如: ExitProcess),否则,程序会在最后一条指令后继续执行下面的‘指令’,即使后面的地址是数据段。
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)