我对一些用于内存管理的 x64 汇编代码感到困惑,例如 CreateFileA、WriteFile 和 ReadFile。当使用 WriteFile 创建文件时,他们为将被推送到堆栈的参数定义了几个位置。例如,
.dwCreationDisposition equ 32
.dwFlagsAndAttributes equ 36
.hTemplateFile equ 40
WriteFile 的函数结构为
HANDLE CreateFileA(
[in] LPCSTR lpFileName, //8 bytes
[in] DWORD dwDesiredAccess, //4 bytes
[in] DWORD dwShareMode, //4 bytes
[in, optional] LPSECURITY_ATTRIBUTES lpSecurityAttributes, //8 bytes
[in] DWORD dwCreationDisposition, //4 bytes
[in] DWORD dwFlagsAndAttributes, //4 bytes
[in, optional] HANDLE hTemplateFile //8 bytes
);
我对WriteFile的猜测:因为在x86中调用函数时所有参数都会被压入堆栈,但在x64中它们发生了变化。前四个参数传递到寄存器。从第五个开始,它们将被推入堆栈。在 x86 中,hTemplateFile 将通过 esp + 40 访问,dwFlagsAndAttributes 将通过 esp + 36 访问。x64 程序集遵循此规则。
但是,对于 WriteFile,他们使用
.lpNumberOfBytesWritten equ 52
.lpOverlapped equ 0
.fileHandle equ 40
BOOL WriteFile(
[in] HANDLE hFile, //8 bytes
[in] LPCVOID lpBuffer, //8 bytes
[in] DWORD nNumberOfBytesToWrite, //4 bytes
[out, optional] LPDWORD lpNumberOfBytesWritten, //8 bytes
[in, out, optional] LPOVERLAPPED lpOverlapped //8 bytes
);
我不知道他们是如何计算的。
与 ReadFile 相同,他们使用
.lpOverlapped2 equ 0
.lpNumberOfBytesRead equ 32
.lpBuffer equ 40
BOOL ReadFile(
[in] HANDLE hFile,
[out] LPVOID lpBuffer,
[in] DWORD nNumberOfBytesToRead,
[out, optional] LPDWORD lpNumberOfBytesRead,
[in, out, optional] LPOVERLAPPED lpOverlapped
);
代码参考:https://github.com/sonictk/asm_tutorial/blob/master/win_create_file.asm
我想知道当我们使用x64程序集进行Windows x64内存管理时,如何计算参数应该推送到的位置。
在 64 位模式下将参数传输到 Windows 函数有点复杂。
CALL Function
之前是 16 字节对齐的。SUB RSP, 4*8
创建阴影空间
在调用的函数内部(当
CALL function
被执行时),RSP不是16对齐的,事实上寄存器SPL的最低位是1000b
并且RSP指向返回地址。[RSP+5*8]
,参数 #6 位于 [RSP+6*8]
等等。
无论参数指定为HANDLE、LPVOID还是DWORD,堆栈上每个对应的槽总是8字节宽。 x86 不允许在 64 位模式下推送 DWORD。另请参阅此示例(快速版本)。