1

我认为编写一个使用未记录的 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

如果有人可以提供帮助,我们将不胜感激。

4

1 回答 1

0

如果您实际上是在编写生产代码,则不应自己调用系统调用门;导入并调用 NTDLL 中的函数。系统调用门可以在补丁版本中更改,并且之前已更改。

NTDLL 中实际的系统调用门是一个只包含系统调用指令的函数;您的代码不起作用,因为您尝试自己执行并且您的堆栈与内核期望的不一致。

服务包中的系统调用号已更改;再次,理论上你可能会在那里遇到问题。

于 2021-04-01T21:11:36.340 回答