我认为在汇编中编写一个使用未记录的Windows NT系统调用接口的程序(用于64位x86,NASM(可能很有趣。不幸的是,我似乎在错误地设置结构或其他参数,导致NtCreateFile
返回STATUS_INVALID_PARAMETER
(0xC000000D(。我怀疑这也可能是因为我可能把参数放错了顺序。我关于如何使用系统调用接口的信息来自另一个SO问题,其中有人提到反编译ntdll中的函数,这让我发现我可以以类似于Linux的方式调用系统调用,即将幻数放在RAX中,然后使用syscall
指令(int 2e
也可以(。这产生了与直接调用NtCreateFile
相同的结果。在阅读了这篇微软文档后,我找到了放入参数的顺序。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 "SystemRoottest.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
如果有人能帮忙,我们将不胜感激。
如果您实际上正在编写生产代码,则不应该自己调用系统调用门;导入并调用NTDLL中的函数。系统调用门在补丁版本中可能会发生更改,并且以前也发生过更改。
NTDLL中实际的系统调用门是一个只包含系统调用指令的函数;您的代码不起作用,因为您试图自己完成,并且您的堆栈与内核期望的不一致。
service Pack中的系统调用编号已更改;再说一遍,理论上你可能会遇到问题。