该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
///代码第二部分
;==============================================================
; 声明要用到的包含文件
;include “m64.inc”;呵呵,这是我将放上面几个宏的包含文件
; 外部函数声明【示例中只用到少数几个API,所以没有去折腾“Kernel32.inc”、“msvcrt.inc”】
extrn ExitProcess: proc; Kernel32.dll、Kernel32.lib[、Kernel32.inc]
extrn GetVolumeInformationA: proc; Kernel32.dll、Kernel32.lib[、Kernel32.inc]
extrn printf: proc; msvcrt.dll、msvcrt.lib[、msvcrt.inc]
; 测试用数据
.const
nC1dq0h
nC2dq0FFFFFFFFFFFFFFFFh
nC3dq0h
nC4dq0h
nC5dq0h
nC6dq0h
.data
_pFuncdq?;函数指针
;GetVolumeInformationA函数使用的数据【◆用的是64位的,但仍按照win32 api里定义的参数长度进行定义】
szVolumelabeldb 64 DUP(0); 函数返回卷标用
nSerialNumberdd?; 函数返回系列号用
nMaxCLengthdd?; 函数返回最大文件名长度用
nFileSysFlagdd?; 函数返回文件系统标识用
szFileSysNamedb100 DUP(0); 函数返回文件系统名称用
;◆转义符测试用数据。ml64不支持转义符,不会把“\n”解释成0x0A的!
szMsgdb 0Ah, 0Dh, "Volumelabel = %s", 0Ah, 0Dh, 0
; 代码
.code
; 测试用函数【自己写的函数,名称前加下划线是我的习惯。呵呵】
;_Func proc;有效
;_Func proc _param1:QWORD, _param2:QWORD, _param3:QWORD, _param4:QWORD, _param5:QWORD, _param6:QWORD;有效
_Func proc uses rbx _param1:QWORD, _param2:QWORD, _param3:QWORD, _param4:QWORD, _param5:QWORD, _param6:QWORD;设定rbx会被改变
ret
_Func endp
;附:自定义函数“_Func”的反汇编代码:
;0000000001271000 | 55 | push rbp
;0000000001271001 | 48:8BEC | mov rbp,rsp ;ml64依然像masm32一样,采用STDCall
;0000000001271004 | 53 | push rbx ;uses rbx
;0000000001271005 | 5B | pop rbx
;0000000001271006 | C9 | leave ;即:mov rsp,rbp/pop rbp
;0000000001271007 | C3 | ret
main proc
; 测试局部变量的定义【默认是DWORD】
local@szTmpBuf[150], @dwCount
local@pMaxCLength:QWORD, @pFileSysFlag:QWORD;存放变量指针
; ★指令测试:AMDx64 PUSH指令不支持64位立即数。push指令支持的最大立即数是0x7FFFFFFF
;push0F000000000000000h;◆错误:操作数无效
; 装填函数指针
movrax, offset _Func
mov_pFunc, rax
; 测试函数调用【“invoke”宏不负责检测参数数量,呵呵】
invoke_Func, rcx, rdx; 仿masm32的函数调用方式
invoke_pFunc, rcx, rdx; 仿masm32的函数指针调用方式
xorrbx,rbx; 示例而已,不取当前实例的加载基址了
invoke[rbx + _pFunc], rcx, rax; 仿masm32的重定位写法(rbx中应该是实例加载后的实际内存基址)
; 多参数(超过4个参数时)函数调用测试
invoke_Func, nC1, nC2, nC3, nC4, nC5, nC6;
invoke_Func, nC1, 7FFFFFFFh, _TXT("Hello!\n"), nC4, nC5, nC6; 测试立即数和字符串直接作为参数
;invoke_Func, nC1, 255, nC3, nC4, nC5, _TXT("Hello!\n"); 错误:第6个参数是64位立即数,push指令不支持
; 用64位API来测试,专门找了一个参数超多、又没有结构参数的API:GetVolumeInformationA(Kernel32.dll)
; 函数定义见代码后面的“附录三”
addrsp, 8*8
movrax, offset nMaxCLength
mov@pMaxCLength, rax
learax, nFileSysFlag
mov@pFileSysFlag, rax
learax, szFileSysName
; ◆错误:“invoke”宏不支持“offset”操作符、也不能像masm32那样支持“addr”伪操作符
;invokeGetVolumeInformationA, _TXT("C:\\"), offset szVolumelabel, 255, offset nSerialNumber, offset nMaxCLength, offset nFileSysFlag, offset szFileSysName, 255;错误
; ◆错误:“_ADDR”宏返回的是64位地址,参数5~8是通过栈传递的,使用“_ADDR”的结果,就成了“push 立即数地址”,像前面的指令测试,肯定不行!
;invokeGetVolumeInformationA, _TXT("C:\\"), _ADDR(szVolumelabel), 255, _addr(nSerialNumber), _addr(nMaxCLength), _addr(nFileSysFlag), _ADDR(szFileSysName), 255
; ★完全正确的写法:
invokeGetVolumeInformationA, _TXT("C:\\"), _ADDR(szVolumelabel), 255, _addr(nSerialNumber), @pMaxCLength, @pFileSysFlag, rax, 0FFh;OK!!!
; ★伪指令测试。不支持伪指令.if/.ifend、.while/.endw :(
;.if!rax
;int3
;.endif
oreax, eax
jz_err
@@:
invokeprintf, _TXT("Volumelabel = %s\n"), _addr(szVolumelabel);◆ml64不会把“\n”解释成0x0A的!
invokeprintf, _addr(szMsg), _ADDR(szVolumelabel)
int3; ◆未设置控制台(窗口会一闪而过),也不想使用“MessageBox”(在“User32.dll”里),
; 而且也需要看反汇编代码,顺带测试“invoke”宏,故强置断点!(建议使用x64dbg调试器)
; ◆不屏蔽掉此句,直接运行“invoke.exe”会在看到控制台窗口的同时,弹出带调试按钮的窗口(应用程序错误)
; 如果系统已经有了默认调试器,则应用程序错误的窗口不会出现,而是直接呼叫出调试器来......
; 退出(使用“ExitProcess”的话,后面的"ret"似乎成了多余...)
;xorrcx, rcx
;callExitProcess; ml64正规写法来调用“ExitProcess”
ret
_err:
invoke printf, _TXT("\n\rFunction GetVolumeInformationA run error!\n\r")
;int3
jmp @B
main endp
end