如何在NASM汇编中正确向Windows系统调用传递参数?
问题分析与解决
核心错误点
你的段错误主要来自两个关键问题:参数传递类型错误,以及调用约定声明不当(寄存器顺序本身是正确的)。
1. 输出参数传递错误
NtOpenProcess的第一个参数ProcessHandle是输出参数,类型为PHANDLE(即HANDLE*),需要传入变量的内存地址,而非变量本身。你代码里直接传了proc(值为NULL),系统调用会试图向NULL地址写入进程句柄,直接触发段错误。
2. Win64调用约定声明错误
Win64平台不存在真正的__stdcall调用约定,所有函数默认使用Win64调用约定(前4个参数通过寄存器传递),应使用NTAPI宏来声明函数,或直接省略调用约定声明。
3. 系统调用号的兼容性
0x26是Win10及后续版本NtOpenProcess的正确系统调用号,若使用更早Windows版本,需对应调整调用号(可通过逆向ntdll.dll导出表确认)。
修正后的代码
修正后的funcs.asm
section .text global NtOpenProcess NtOpenProcess: mov rax, 26h ; Win10+ 下NtOpenProcess的系统调用号 syscall ret
修正后的main.c
#include <windows.h> // 使用NTAPI声明,匹配Win64调用约定 extern NTSTATUS NTAPI NtOpenProcess( PHANDLE ProcessHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PCLIENT_ID ClientId ); int main() { HANDLE proc = NULL; OBJECT_ATTRIBUTES obj_attr = {sizeof(obj_attr), 0, NULL, 0}; CLIENT_ID cid; cid.UniqueProcess = (HANDLE)316; cid.UniqueThread = 0; // 第一个参数传入proc的地址,而非proc本身 NTSTATUS res = NtOpenProcess(&proc, PROCESS_ALL_ACCESS, &obj_attr, &cid); // 可选:检查调用结果并清理句柄 if (NT_SUCCESS(res) && proc != NULL) { CloseHandle(proc); } return 0; }
关键说明
- Windows x64下NT系统调用的参数寄存器顺序确实为:
rcx→第一个参数、rdx→第二个、r8→第三个、r9→第四个,你的初始理解是正确的。 - 输出参数必须传递指针,否则会导致非法内存访问,这是触发段错误的核心原因。
内容的提问来源于stack exchange,提问作者RAT
相关产品推荐
相关产品推荐

