使用NASM汇编直接调用NtOpenProcess时遇访问违规求助
问题背景
我想要开发一个基于直接系统调用的小型工具包,用NASM汇编调用Windows原生API(如NtOpenProcess)打开进程并显示信息,要求:
- 使用直接系统调用
- 采用NASM汇编
我的初始代码如下:
section .bss CI resb 16 ; Client ID (CI) - 16 bytes OA resb 40 ; OBJECT_ATTRIBUTES (OA) - 40 bytes h_process resb 8 ; Handle to opened process - 8 bytes section .text global main main: ; Setup stack frame push rbp mov rbp, rsp sub rsp, 60h ; Allocate 96 bytes for stack shadow ; ------------------------- ; Initialize Client ID (CI) ; ------------------------- mov qword [rel CI], 790h ; Process ID set to 790h mov qword [rel CI + 8], 0x0 ; Thread ID set to 0 ; ------------------------------------------- ; Initialize OBJECT_ATTRIBUTES (OA) structure ; ------------------------------------------- mov dword [rel OA], 0x30 ; Length = 0x30 (48 bytes) mov qword [rel OA + 8], 0x0 ; RootDirectory = NULL mov qword [rel OA + 16], 0x0 ; ObjectName = NULL mov dword [rel OA + 24], 0x0 ; Attributes = 0 mov qword [rel OA + 32], 0x0 ; SecurityDescriptor = NULL mov qword [rel OA + 40], 0x0 ; SecurityQualityOfService = NULL ; -------------------------------- ; Initialize process handle to 0 ; -------------------------------- mov qword [rel h_process], 0x0 ; h_process = NULL ; ----------------------------- ; Call NtOpenProcess syscall ; ----------------------------- lea rcx, [rel h_process] ; rcx = address of h_process mov rdx, 1FFFFFh ; rdx = access mask (all permissions) lea r9, [rel CI] ; r9 = address of Client ID (CI) lea r8, [rel OA] ; r8 = address of OBJECT_ATTRIBUTES (OA) mov rax, 0x26 ; rax = NtOpenProcess syscall number
代码编译正常,但调用NtOpenProcess后返回状态码0xc000005(访问违规),已对齐并初始化相关结构,参数传递顺序自认为正确,需要排查问题原因。
问题排查与修复
1. 系统调用参数顺序错误
Windows x64系统调用的参数传递规则为:前4个参数依次放入RCX、RDX、R8、R9。而NtOpenProcess的函数原型是:
NTSTATUS NtOpenProcess( OUT PHANDLE ProcessHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, IN PCLIENT_ID ClientId OPTIONAL );
你的代码将第3个参数ObjectAttributes放到了R8,第4个参数ClientId放到了R9,顺序完全颠倒,这会导致内核接收到错误的指针,直接触发访问违规。正确的参数顺序应为:
RCX= 指向h_process的指针RDX= 权限掩码(1FFFFFh)R8= 指向OBJECT_ATTRIBUTES的指针R9= 指向CLIENT_ID的指针
2. OBJECT_ATTRIBUTES结构长度不匹配
你在.bss段定义OA为resb 40,但初始化时设置Length为0x30(48字节),这会导致写入OA+40的位置时越界,覆盖后续的h_process内存空间,引发内存访问错误。64位系统下OBJECT_ATTRIBUTES的实际大小就是48字节,因此.bss段应改为OA resb 48。
3. 缺少系统调用执行指令
代码仅设置了系统调用号到RAX,但没有执行syscall指令,这会导致后续代码执行混乱,同样可能触发访问违规。必须在参数设置完成后添加syscall指令来触发系统调用。
4. 硬编码系统调用号存在兼容性问题
0x26是Windows 10早期版本的NtOpenProcess系统调用号,Windows 11或更新版本的调用号可能已变更。建议通过动态方式获取调用号(比如从ntdll.dll导出的函数中提取),避免硬编码导致的错误。
修复后的代码片段
section .bss CI resb 16 ; Client ID (CI) - 16 bytes OA resb 48 ; OBJECT_ATTRIBUTES (OA) - 48 bytes (修正长度) h_process resb 8 ; Handle to opened process - 8 bytes section .text global main main: ; Setup stack frame push rbp mov rbp, rsp sub rsp, 60h ; Allocate 96 bytes for stack shadow ; ------------------------- ; Initialize Client ID (CI) ; ------------------------- mov qword [rel CI], 790h ; Process ID set to 790h mov qword [rel CI + 8], 0x0 ; Thread ID set to 0 ; ------------------------------------------- ; Initialize OBJECT_ATTRIBUTES (OA) structure ; ------------------------------------------- mov dword [rel OA], 0x30 ; Length = 0x30 (48 bytes) mov qword [rel OA + 8], 0x0 ; RootDirectory = NULL mov qword [rel OA + 16], 0x0 ; ObjectName = NULL mov dword [rel OA + 24], 0x0 ; Attributes = 0 mov qword [rel OA + 32], 0x0 ; SecurityDescriptor = NULL mov qword [rel OA + 40], 0x0 ; SecurityQualityOfService = NULL ; -------------------------------- ; Initialize process handle to 0 ; -------------------------------- mov qword [rel h_process], 0x0 ; h_process = NULL ; ----------------------------- ; Call NtOpenProcess syscall ; ----------------------------- lea rcx, [rel h_process] ; rcx = ProcessHandle (OUT) mov rdx, 1FFFFFh ; rdx = DesiredAccess (IN) lea r8, [rel OA] ; r8 = ObjectAttributes (IN) lea r9, [rel CI] ; r9 = ClientId (IN) mov rax, 0x26 ; rax = NtOpenProcess syscall number syscall ; 执行系统调用 ; 后续可处理返回值,比如检查RAX是否为STATUS_SUCCESS(0) ; ...
内容的提问来源于stack exchange,提问作者katysha

