如何解决Windows NtCreateFile 返回 STATUS_INVALID_PARAMETER使用未记录的 NT 系统调用接口
我认为编写一个使用未公开的 Windows NT 系统调用接口的汇编程序(用于 64 位 x86,NASM)可能会很有趣/有趣。不幸的是,似乎我在某处错误地设置了结构或其他参数,导致 NtCreateFile
返回 STATUS_INVALID_ParaMETER
(0xC000000D)。我怀疑这也可能是因为我可能将参数放在错误的顺序中。我关于如何使用系统调用接口的信息来自另一个 SO 问题,其中有人提到在 ntdll 中反编译该函数,这使我意识到我可以以类似于 Linux 的方式调用系统调用,即将幻数放入RAX 然后使用 syscall
指令(int 2e
也有效)。这会产生与直接调用 NtCreateFile
相同的结果。在阅读了 this Microsoft 文档后,我弄清楚了放入参数的顺序。NtCreateFile
的幻数来自 here。这是程序:
BITS 64
section .data
;; Declare a quadword (pointer size) to store the file handle in
file: resq 1
;; Declare the memory necessary for an OBJECT_ATTRIBUTES structure (five quadwords)
;; typedef struct _OBJECT_ATTRIBUTES {
;; ULONG Length;
;; HANDLE RootDirectory;
;; PUNICODE_STRING ObjectName;
;; ULONG Attributes;
;; PVOID SecurityDescriptor;
;; PVOID SecurityQualityOfService;
;; } OBJECT_ATTRIBUTES;
atrs: resq 5
;; Declare a UNICODE_STRING for the file path,and the text to be written
fname:
resq 2
fname_str: dw "\SystemRoot\test.txt",0
;; An IO_STATUS_BLOCK
iostat: resq 3
section .code
;; The signature of NtCreateFile:
;; __kernel_entry NTSTATUS NtCreateFile(
;; PHANDLE FileHandle,;; ACCESS_MASK DesiredAccess,;; POBJECT_ATTRIBUTES ObjectAttributes,;; PIO_STATUS_BLOCK IoStatusBlock,;; PLARGE_INTEGER AllocationSize,;; ULONG FileAttributes,;; ULONG ShareAccess,;; ULONG Createdisposition,;; ULONG CreateOptions,;; PVOID EaBuffer,;; ULONG EaLength
;; );
;; Still counting this as a win since this function is just for a structure
extern RtlInitUnicodeString
global mainCRTstartup
mainCRTstartup:
;; Initialize a Unicode string
lea rcx,[fname] ;; The memory for the structure
lea rdx,[fname_str] ;; The string
call RtlInitUnicodeString
;; NtCreateFile parameters
mov r10,rcx ;; Save rcx (this is what happens in ntdll,not sure why yet)
mov eax,55h ;; NtCreateFile's number is 0x55 in all versions thus far
lea rcx,[file] ;; Put the file handle address into rcx
mov rdx,40100000h ;; The desired file access,which is GENERIC_WRITE | SYNCHRONIZE
;; Set up attributes for the handle
mov rbx,40 ;; Structure size,40 bytes/5 quadwords
mov QWORD [atrs],rbx
xor rbx,rbx ;; Set RootDirectory to NULL
mov QWORD [atrs + 8],rbx
mov rbx,QWORD [fname] ;; Move the start of the filename data to ObjectName
mov QWORD [atrs + 16],40h
mov QWORD [atrs + 12],rbx ;; OBJ_CASE_INSENSITIVE
mov r8,atrs ;; Move the pointer to the OBJECT_ATTRIBUTES structure to r8
xor r9,r9 ;; NULL
;; Now that we've reached 4 arguments,stuff goes on the stack in reverse
xor rbx,rbx ;; Zero rbx for general use as zero
push rbx ;; EaLength,not used
push rbx ;; EaBuffer,NULL
mov rsi,0x20 ;; CreateOptions is FILE_SYNCHRONOUS_IO_NONALERT
push rsi
xor rsi,rsi ;; FILE_OVERWRITE_IF (create/overwrite)
mov rsi,5
push rsi
push rbx ;; We don't have other threads
mov rsi,80h
push rsi ;; FILE_ATTRIBUTE_norMAL
push rbx ;; NULL
syscall ;; Jump into kernel mode and call NtCreateFile
;; Exit
mov eax,2ch ;; NtTerminateProcess
xor ecx,ecx ;; We want to kill this process,not another one
xor edx,edx ;; Exit with code 0
syscall ;; Enter kernel mode again
我用这些命令组装和链接它:
nasm -o ntsyscall.obj -fwin64 ntsyscall.s
cl ntsyscall.obj -link -entry:mainCRTstartup -subsystem:console -largeaddressaware:no -debug ntdll.lib # ntdll's RtlInitUnicodeString is used
我还编写了这个 C 程序,它正在尝试同样的事情并按预期工作:
#define _AMD64_
#include <ntdef.h>
/* DeFinitions for symbols and structures needed */
#define GENERIC_WRITE 0x40000000L
#define SYNCHRONIZE 0x00100000L
#define FILE_SYNCHRONOUS_IO_NONALERT 0x20
#define FILE_OVERWRITE_IF 0x5
#define FILE_ATTRIBUTE_norMAL 0x80
typedef struct _IO_STATUS_BLOCK {
union {
long Status;
long Pointer;
} DUMMYUNIONNAME;
unsigned long *information;
} IO_STATUS_BLOCK,*PIO_STATUS_BLOCK;
extern long NtCreateFile(HANDLE *file_ret,unsigned long desired_access,OBJECT_ATTRIBUTES *oattrs,IO_STATUS_BLOCK *iostat,LARGE_INTEGER *alloc_size,unsigned long fattrs,unsigned long share_access,unsigned long create_disp,unsigned long create_opts,void *ea_buf,unsigned long ea_len);
extern void RtlFillMemory(void *dst,unsigned long n,int c);
extern void RtlInitUnicodeString(UNICODE_STRING *dst,unsigned short *src);
int mainCRTstartup(void)
{
HANDLE file;
OBJECT_ATTRIBUTES atrs;
UNICODE_STRING fname;
//UNICODE_STRING ftext;
IO_STATUS_BLOCK iostat;
/* Initialize obsoletely designed Windows structures (not a fan of the Windows API) */
RtlFillMemory(&atrs,sizeof(atrs),0);
RtlInitUnicodeString(&fname,L"\\SystemRoot\\test.txt");
atrs.Length = sizeof(atrs);
atrs.RootDirectory = NULL;
atrs.ObjectName = &fname;
atrs.Attributes = OBJ_CASE_INSENSITIVE;
/* Call the function */
NtCreateFile(&file,GENERIC_WRITE | SYNCHRONIZE,&atrs,&iostat,NULL,FILE_ATTRIBUTE_norMAL,FILE_OVERWRITE_IF,FILE_SYNCHRONOUS_IO_NONALERT,0);
/* Return to the program loader */
return 0;
}
用
编译cl ntsyscall_equiv.c -link -entry:mainCRTstartup -debug ntdll.lib
如果有人能帮忙解决这个问题,非常感谢。
解决方法
如果您实际上正在编写生产代码,则不应自己调用系统调用门;导入并调用 NTDLL 中的函数。系统调用门可以在补丁版本中更改并且之前已经更改。
NTDLL 中实际的系统调用门是一个只包含系统调用指令的函数;您的代码无法运行,因为您尝试自己完成,而您的堆栈与内核期望的不一致。
服务包中的系统调用号已更改;同样,理论上你可能会在那里遇到问题。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。