我认为编写一个使用未记录的 Windows NT 系统调用接口的程序集(对于 64 位 x86,NASM)可能会很有趣/有趣。不幸的是,似乎在某处我错误地设置了结构或其他参数,导致NtCreateFile
返回STATUS_INVALID_PARAMETER
(0xC000000D)。我怀疑这也可能是因为我可能将参数的顺序错误。我关于如何使用系统调用接口的信息来自另一个 SO question,其中有人提到反编译 ntdll 中的函数,这使我发现我可以以类似于 Linux 的方式调用系统调用,即将幻数放入RAX,然后使用syscall
指令(int 2e
也可以)。这会产生与直接调用相同的结果NtCreateFile
. 在阅读了这个Microsoft 文档后,我弄清楚了放入参数的顺序。for 的幻数NtCreateFile
来自这里。这是程序:
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], rbx
mov rbx, 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, 0, FILE_OVERWRITE_IF,
FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
/* Return to the program loader */
return 0;
}
这是用
cl ntsyscall_equiv.c -link -entry:mainCRTstartup -debug ntdll.lib
如果有人可以提供帮助,我们将不胜感激。