From f52a87093cef5608b00603814a6768cdc4dabab2 Mon Sep 17 00:00:00 2001 From: tdeerenberg Date: Tue, 8 Apr 2025 17:23:22 +0200 Subject: [PATCH] Add SysWhispers3 data --- SysWhispers3/.gitignore | 7 +- SysWhispers3/data/base.c | 265 +++++++++ SysWhispers3/data/base.h | 63 ++ .../example-output/Syscalls-asm.x64.asm | 563 ++++++++++++++++++ SysWhispers3/example-output/Syscalls.c | 278 +++++++++ SysWhispers3/example-output/Syscalls.h | 487 +++++++++++++++ 6 files changed, 1657 insertions(+), 6 deletions(-) create mode 100644 SysWhispers3/data/base.c create mode 100644 SysWhispers3/data/base.h create mode 100644 SysWhispers3/example-output/Syscalls-asm.x64.asm create mode 100644 SysWhispers3/example-output/Syscalls.c create mode 100644 SysWhispers3/example-output/Syscalls.h diff --git a/SysWhispers3/.gitignore b/SysWhispers3/.gitignore index a53b798..4d07118 100644 --- a/SysWhispers3/.gitignore +++ b/SysWhispers3/.gitignore @@ -1,6 +1 @@ -.idea -!data/* -__pycache__ -*.asm -*.c -*.h \ No newline at end of file +__pycache__ diff --git a/SysWhispers3/data/base.c b/SysWhispers3/data/base.c new file mode 100644 index 0000000..8f6e942 --- /dev/null +++ b/SysWhispers3/data/base.c @@ -0,0 +1,265 @@ +#include ".h" +#include + +//#define DEBUG + +// JUMPER + +#ifdef _M_IX86 + +EXTERN_C PVOID internal_cleancall_wow64_gate(VOID) { + return (PVOID)__readfsdword(0xC0); +} + +// LOCAL_IS_WOW64 + +#endif + +// Code below is adapted from @modexpblog. Read linked article for more details. +// https://www.mdsec.co.uk/2020/12/bypassing-user-mode-hooks-and-direct-invocation-of-system-calls-for-red-teams + +SW3_SYSCALL_LIST SW3_SyscallList; + +// SEARCH_AND_REPLACE +#ifdef SEARCH_AND_REPLACE +// THIS IS NOT DEFINED HERE; don't know if I'll add it in a future release +EXTERN void SearchAndReplace(unsigned char[], unsigned char[]); +#endif + +DWORD SW3_HashSyscall(PCSTR FunctionName) +{ + DWORD i = 0; + DWORD Hash = SW3_SEED; + + while (FunctionName[i]) + { + WORD PartialName = *(WORD*)((ULONG_PTR)FunctionName + i++); + Hash ^= PartialName + SW3_ROR8(Hash); + } + + return Hash; +} + +#ifndef JUMPER +PVOID SC_Address(PVOID NtApiAddress) +{ + return NULL; +} +#else +PVOID SC_Address(PVOID NtApiAddress) +{ + DWORD searchLimit = 512; + PVOID SyscallAddress; + + #ifdef _WIN64 + // If the process is 64-bit on a 64-bit OS, we need to search for syscall + BYTE syscall_code[] = { 0x0f, 0x05, 0xc3 }; + ULONG distance_to_syscall = 0x12; + #else + // If the process is 32-bit on a 32-bit OS, we need to search for sysenter + BYTE syscall_code[] = { 0x0f, 0x34, 0xc3 }; + ULONG distance_to_syscall = 0x0f; + #endif + + #ifdef _M_IX86 + // If the process is 32-bit on a 64-bit OS, we need to jump to WOW32Reserved + if (local_is_wow64()) + { + #ifdef DEBUG + printf("[+] Running 32-bit app on x64 (WOW64)\n"); + #endif +// JUMP_TO_WOW32Reserved + } + #endif + + // we don't really care if there is a 'jmp' between + // NtApiAddress and the 'syscall; ret' instructions + SyscallAddress = SW3_RVA2VA(PVOID, NtApiAddress, distance_to_syscall); + + if (!memcmp((PVOID)syscall_code, SyscallAddress, sizeof(syscall_code))) + { + // we can use the original code for this system call :) + #if defined(DEBUG) + printf("Found Syscall Opcodes at address 0x%p\n", SyscallAddress); + #endif + return SyscallAddress; + } + + // the 'syscall; ret' intructions have not been found, + // we will try to use one near it, similarly to HalosGate + + for (ULONG32 num_jumps = 1; num_jumps < searchLimit; num_jumps++) + { + // let's try with an Nt* API below our syscall + SyscallAddress = SW3_RVA2VA( + PVOID, + NtApiAddress, + distance_to_syscall + num_jumps * 0x20); + if (!memcmp((PVOID)syscall_code, SyscallAddress, sizeof(syscall_code))) + { + #if defined(DEBUG) + printf("Found Syscall Opcodes at address 0x%p\n", SyscallAddress); + #endif + return SyscallAddress; + } + + // let's try with an Nt* API above our syscall + SyscallAddress = SW3_RVA2VA( + PVOID, + NtApiAddress, + distance_to_syscall - num_jumps * 0x20); + if (!memcmp((PVOID)syscall_code, SyscallAddress, sizeof(syscall_code))) + { + #if defined(DEBUG) + printf("Found Syscall Opcodes at address 0x%p\n", SyscallAddress); + #endif + return SyscallAddress; + } + } + +#ifdef DEBUG + printf("Syscall Opcodes not found!\n"); +#endif + + return NULL; +} +#endif + + +BOOL SW3_PopulateSyscallList() +{ + // Return early if the list is already populated. + if (SW3_SyscallList.Count) return TRUE; + + #ifdef _WIN64 + PSW3_PEB Peb = (PSW3_PEB)__readgsqword(0x60); + #else + PSW3_PEB Peb = (PSW3_PEB)__readfsdword(0x30); + #endif + PSW3_PEB_LDR_DATA Ldr = Peb->Ldr; + PIMAGE_EXPORT_DIRECTORY ExportDirectory = NULL; + PVOID DllBase = NULL; + + // Get the DllBase address of NTDLL.dll. NTDLL is not guaranteed to be the second + // in the list, so it's safer to loop through the full list and find it. + PSW3_LDR_DATA_TABLE_ENTRY LdrEntry; + for (LdrEntry = (PSW3_LDR_DATA_TABLE_ENTRY)Ldr->Reserved2[1]; LdrEntry->DllBase != NULL; LdrEntry = (PSW3_LDR_DATA_TABLE_ENTRY)LdrEntry->Reserved1[0]) + { + DllBase = LdrEntry->DllBase; + PIMAGE_DOS_HEADER DosHeader = (PIMAGE_DOS_HEADER)DllBase; + PIMAGE_NT_HEADERS NtHeaders = SW3_RVA2VA(PIMAGE_NT_HEADERS, DllBase, DosHeader->e_lfanew); + PIMAGE_DATA_DIRECTORY DataDirectory = (PIMAGE_DATA_DIRECTORY)NtHeaders->OptionalHeader.DataDirectory; + DWORD VirtualAddress = DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; + if (VirtualAddress == 0) continue; + + ExportDirectory = (PIMAGE_EXPORT_DIRECTORY)SW3_RVA2VA(ULONG_PTR, DllBase, VirtualAddress); + + // If this is NTDLL.dll, exit loop. + PCHAR DllName = SW3_RVA2VA(PCHAR, DllBase, ExportDirectory->Name); + + if ((*(ULONG*)DllName | 0x20202020) != 0x6c64746e) continue; + if ((*(ULONG*)(DllName + 4) | 0x20202020) == 0x6c642e6c) break; + } + + if (!ExportDirectory) return FALSE; + + DWORD NumberOfNames = ExportDirectory->NumberOfNames; + PDWORD Functions = SW3_RVA2VA(PDWORD, DllBase, ExportDirectory->AddressOfFunctions); + PDWORD Names = SW3_RVA2VA(PDWORD, DllBase, ExportDirectory->AddressOfNames); + PWORD Ordinals = SW3_RVA2VA(PWORD, DllBase, ExportDirectory->AddressOfNameOrdinals); + + // Populate SW3_SyscallList with unsorted Zw* entries. + DWORD i = 0; + PSW3_SYSCALL_ENTRY Entries = SW3_SyscallList.Entries; + do + { + PCHAR FunctionName = SW3_RVA2VA(PCHAR, DllBase, Names[NumberOfNames - 1]); + + // Is this a system call? + if (*(USHORT*)FunctionName == 0x775a) + { + Entries[i].Hash = SW3_HashSyscall(FunctionName); + Entries[i].Address = Functions[Ordinals[NumberOfNames - 1]]; + Entries[i].SyscallAddress = SC_Address(SW3_RVA2VA(PVOID, DllBase, Entries[i].Address)); + + i++; + if (i == SW3_MAX_ENTRIES) break; + } + } while (--NumberOfNames); + + // Save total number of system calls found. + SW3_SyscallList.Count = i; + + // Sort the list by address in ascending order. + for (DWORD i = 0; i < SW3_SyscallList.Count - 1; i++) + { + for (DWORD j = 0; j < SW3_SyscallList.Count - i - 1; j++) + { + if (Entries[j].Address > Entries[j + 1].Address) + { + // Swap entries. + SW3_SYSCALL_ENTRY TempEntry; + + TempEntry.Hash = Entries[j].Hash; + TempEntry.Address = Entries[j].Address; + TempEntry.SyscallAddress = Entries[j].SyscallAddress; + + Entries[j].Hash = Entries[j + 1].Hash; + Entries[j].Address = Entries[j + 1].Address; + Entries[j].SyscallAddress = Entries[j + 1].SyscallAddress; + + Entries[j + 1].Hash = TempEntry.Hash; + Entries[j + 1].Address = TempEntry.Address; + Entries[j + 1].SyscallAddress = TempEntry.SyscallAddress; + } + } + } + + return TRUE; +} + +EXTERN_C DWORD SW3_GetSyscallNumber(DWORD FunctionHash) +{ + // Ensure SW3_SyscallList is populated. + if (!SW3_PopulateSyscallList()) return -1; + + for (DWORD i = 0; i < SW3_SyscallList.Count; i++) + { + if (FunctionHash == SW3_SyscallList.Entries[i].Hash) + { + return i; + } + } + + return -1; +} + +EXTERN_C PVOID SW3_GetSyscallAddress(DWORD FunctionHash) +{ + // Ensure SW3_SyscallList is populated. + if (!SW3_PopulateSyscallList()) return NULL; + + for (DWORD i = 0; i < SW3_SyscallList.Count; i++) + { + if (FunctionHash == SW3_SyscallList.Entries[i].Hash) + { + return SW3_SyscallList.Entries[i].SyscallAddress; + } + } + + return NULL; +} + +EXTERN_C PVOID SW3_GetRandomSyscallAddress(DWORD FunctionHash) +{ + // Ensure SW3_SyscallList is populated. + if (!SW3_PopulateSyscallList()) return NULL; + + DWORD index = ((DWORD) rand()) % SW3_SyscallList.Count; + + while (FunctionHash == SW3_SyscallList.Entries[index].Hash){ + // Spoofing the syscall return address + index = ((DWORD) rand()) % SW3_SyscallList.Count; + } + return SW3_SyscallList.Entries[index].SyscallAddress; +} diff --git a/SysWhispers3/data/base.h b/SysWhispers3/data/base.h new file mode 100644 index 0000000..a21a286 --- /dev/null +++ b/SysWhispers3/data/base.h @@ -0,0 +1,63 @@ +#pragma once + +// Code below is adapted from @modexpblog. Read linked article for more details. +// https://www.mdsec.co.uk/2020/12/bypassing-user-mode-hooks-and-direct-invocation-of-system-calls-for-red-teams + +#ifndef SW3_HEADER_H_ +#define SW3_HEADER_H_ + +#include + +#ifndef _NTDEF_ +typedef _Return_type_success_(return >= 0) LONG NTSTATUS; +typedef NTSTATUS* PNTSTATUS; +#endif + +#define SW3_SEED +#define SW3_ROL8(v) (v << 8 | v >> 24) +#define SW3_ROR8(v) (v >> 8 | v << 24) +#define SW3_ROX8(v) ((SW3_SEED % 2) ? SW3_ROL8(v) : SW3_ROR8(v)) +#define SW3_MAX_ENTRIES 600 +#define SW3_RVA2VA(Type, DllBase, Rva) (Type)((ULONG_PTR) DllBase + Rva) + +// Typedefs are prefixed to avoid pollution. + +typedef struct _SW3_SYSCALL_ENTRY +{ + DWORD Hash; + DWORD Address; + PVOID SyscallAddress; +} SW3_SYSCALL_ENTRY, *PSW3_SYSCALL_ENTRY; + +typedef struct _SW3_SYSCALL_LIST +{ + DWORD Count; + SW3_SYSCALL_ENTRY Entries[SW3_MAX_ENTRIES]; +} SW3_SYSCALL_LIST, *PSW3_SYSCALL_LIST; + +typedef struct _SW3_PEB_LDR_DATA { + BYTE Reserved1[8]; + PVOID Reserved2[3]; + LIST_ENTRY InMemoryOrderModuleList; +} SW3_PEB_LDR_DATA, *PSW3_PEB_LDR_DATA; + +typedef struct _SW3_LDR_DATA_TABLE_ENTRY { + PVOID Reserved1[2]; + LIST_ENTRY InMemoryOrderLinks; + PVOID Reserved2[2]; + PVOID DllBase; +} SW3_LDR_DATA_TABLE_ENTRY, *PSW3_LDR_DATA_TABLE_ENTRY; + +typedef struct _SW3_PEB { + BYTE Reserved1[2]; + BYTE BeingDebugged; + BYTE Reserved2[1]; + PVOID Reserved3[2]; + PSW3_PEB_LDR_DATA Ldr; +} SW3_PEB, *PSW3_PEB; + +DWORD SW3_HashSyscall(PCSTR FunctionName); +BOOL SW3_PopulateSyscallList(); +EXTERN_C DWORD SW3_GetSyscallNumber(DWORD FunctionHash); +EXTERN_C PVOID SW3_GetSyscallAddress(DWORD FunctionHash); +EXTERN_C PVOID internal_cleancall_wow64_gate(VOID); diff --git a/SysWhispers3/example-output/Syscalls-asm.x64.asm b/SysWhispers3/example-output/Syscalls-asm.x64.asm new file mode 100644 index 0000000..fe50ca9 --- /dev/null +++ b/SysWhispers3/example-output/Syscalls-asm.x64.asm @@ -0,0 +1,563 @@ +.code + +EXTERN SW3_GetSyscallNumber: PROC + +NtCreateProcess PROC + mov [rsp +8], rcx ; Save registers. + mov [rsp+16], rdx + mov [rsp+24], r8 + mov [rsp+32], r9 + sub rsp, 28h + mov ecx, 029943818h ; Load function hash into ECX. + call SW3_GetSyscallNumber ; Resolve function hash into syscall number. + add rsp, 28h + mov rcx, [rsp+8] ; Restore registers. + mov rdx, [rsp+16] + mov r8, [rsp+24] + mov r9, [rsp+32] + mov r10, rcx + syscall ; Invoke system call. + ret +NtCreateProcess ENDP + +NtCreateThreadEx PROC + mov [rsp +8], rcx ; Save registers. + mov [rsp+16], rdx + mov [rsp+24], r8 + mov [rsp+32], r9 + sub rsp, 28h + mov ecx, 052B6124Eh ; Load function hash into ECX. + call SW3_GetSyscallNumber ; Resolve function hash into syscall number. + add rsp, 28h + mov rcx, [rsp+8] ; Restore registers. + mov rdx, [rsp+16] + mov r8, [rsp+24] + mov r9, [rsp+32] + mov r10, rcx + syscall ; Invoke system call. + ret +NtCreateThreadEx ENDP + +NtOpenProcess PROC + mov [rsp +8], rcx ; Save registers. + mov [rsp+16], rdx + mov [rsp+24], r8 + mov [rsp+32], r9 + sub rsp, 28h + mov ecx, 00DD60C24h ; Load function hash into ECX. + call SW3_GetSyscallNumber ; Resolve function hash into syscall number. + add rsp, 28h + mov rcx, [rsp+8] ; Restore registers. + mov rdx, [rsp+16] + mov r8, [rsp+24] + mov r9, [rsp+32] + mov r10, rcx + syscall ; Invoke system call. + ret +NtOpenProcess ENDP + +NtOpenProcessToken PROC + mov [rsp +8], rcx ; Save registers. + mov [rsp+16], rdx + mov [rsp+24], r8 + mov [rsp+32], r9 + sub rsp, 28h + mov ecx, 0C3914A8Dh ; Load function hash into ECX. + call SW3_GetSyscallNumber ; Resolve function hash into syscall number. + add rsp, 28h + mov rcx, [rsp+8] ; Restore registers. + mov rdx, [rsp+16] + mov r8, [rsp+24] + mov r9, [rsp+32] + mov r10, rcx + syscall ; Invoke system call. + ret +NtOpenProcessToken ENDP + +NtTestAlert PROC + mov [rsp +8], rcx ; Save registers. + mov [rsp+16], rdx + mov [rsp+24], r8 + mov [rsp+32], r9 + sub rsp, 28h + mov ecx, 02EB45D3Ah ; Load function hash into ECX. + call SW3_GetSyscallNumber ; Resolve function hash into syscall number. + add rsp, 28h + mov rcx, [rsp+8] ; Restore registers. + mov rdx, [rsp+16] + mov r8, [rsp+24] + mov r9, [rsp+32] + mov r10, rcx + syscall ; Invoke system call. + ret +NtTestAlert ENDP + +NtOpenThread PROC + mov [rsp +8], rcx ; Save registers. + mov [rsp+16], rdx + mov [rsp+24], r8 + mov [rsp+32], r9 + sub rsp, 28h + mov ecx, 075426DE5h ; Load function hash into ECX. + call SW3_GetSyscallNumber ; Resolve function hash into syscall number. + add rsp, 28h + mov rcx, [rsp+8] ; Restore registers. + mov rdx, [rsp+16] + mov r8, [rsp+24] + mov r9, [rsp+32] + mov r10, rcx + syscall ; Invoke system call. + ret +NtOpenThread ENDP + +NtSuspendProcess PROC + mov [rsp +8], rcx ; Save registers. + mov [rsp+16], rdx + mov [rsp+24], r8 + mov [rsp+32], r9 + sub rsp, 28h + mov ecx, 0F022DFBFh ; Load function hash into ECX. + call SW3_GetSyscallNumber ; Resolve function hash into syscall number. + add rsp, 28h + mov rcx, [rsp+8] ; Restore registers. + mov rdx, [rsp+16] + mov r8, [rsp+24] + mov r9, [rsp+32] + mov r10, rcx + syscall ; Invoke system call. + ret +NtSuspendProcess ENDP + +NtSuspendThread PROC + mov [rsp +8], rcx ; Save registers. + mov [rsp+16], rdx + mov [rsp+24], r8 + mov [rsp+32], r9 + sub rsp, 28h + mov ecx, 00F3F9E0Dh ; Load function hash into ECX. + call SW3_GetSyscallNumber ; Resolve function hash into syscall number. + add rsp, 28h + mov rcx, [rsp+8] ; Restore registers. + mov rdx, [rsp+16] + mov r8, [rsp+24] + mov r9, [rsp+32] + mov r10, rcx + syscall ; Invoke system call. + ret +NtSuspendThread ENDP + +NtResumeProcess PROC + mov [rsp +8], rcx ; Save registers. + mov [rsp+16], rdx + mov [rsp+24], r8 + mov [rsp+32], r9 + sub rsp, 28h + mov ecx, 041D54040h ; Load function hash into ECX. + call SW3_GetSyscallNumber ; Resolve function hash into syscall number. + add rsp, 28h + mov rcx, [rsp+8] ; Restore registers. + mov rdx, [rsp+16] + mov r8, [rsp+24] + mov r9, [rsp+32] + mov r10, rcx + syscall ; Invoke system call. + ret +NtResumeProcess ENDP + +NtResumeThread PROC + mov [rsp +8], rcx ; Save registers. + mov [rsp+16], rdx + mov [rsp+24], r8 + mov [rsp+32], r9 + sub rsp, 28h + mov ecx, 0B28FAC35h ; Load function hash into ECX. + call SW3_GetSyscallNumber ; Resolve function hash into syscall number. + add rsp, 28h + mov rcx, [rsp+8] ; Restore registers. + mov rdx, [rsp+16] + mov r8, [rsp+24] + mov r9, [rsp+32] + mov r10, rcx + syscall ; Invoke system call. + ret +NtResumeThread ENDP + +NtGetContextThread PROC + mov [rsp +8], rcx ; Save registers. + mov [rsp+16], rdx + mov [rsp+24], r8 + mov [rsp+32], r9 + sub rsp, 28h + mov ecx, 0BB97FF4Fh ; Load function hash into ECX. + call SW3_GetSyscallNumber ; Resolve function hash into syscall number. + add rsp, 28h + mov rcx, [rsp+8] ; Restore registers. + mov rdx, [rsp+16] + mov r8, [rsp+24] + mov r9, [rsp+32] + mov r10, rcx + syscall ; Invoke system call. + ret +NtGetContextThread ENDP + +NtSetContextThread PROC + mov [rsp +8], rcx ; Save registers. + mov [rsp+16], rdx + mov [rsp+24], r8 + mov [rsp+32], r9 + sub rsp, 28h + mov ecx, 093B3CF03h ; Load function hash into ECX. + call SW3_GetSyscallNumber ; Resolve function hash into syscall number. + add rsp, 28h + mov rcx, [rsp+8] ; Restore registers. + mov rdx, [rsp+16] + mov r8, [rsp+24] + mov r9, [rsp+32] + mov r10, rcx + syscall ; Invoke system call. + ret +NtSetContextThread ENDP + +NtClose PROC + mov [rsp +8], rcx ; Save registers. + mov [rsp+16], rdx + mov [rsp+24], r8 + mov [rsp+32], r9 + sub rsp, 28h + mov ecx, 04B1B40BBh ; Load function hash into ECX. + call SW3_GetSyscallNumber ; Resolve function hash into syscall number. + add rsp, 28h + mov rcx, [rsp+8] ; Restore registers. + mov rdx, [rsp+16] + mov r8, [rsp+24] + mov r9, [rsp+32] + mov r10, rcx + syscall ; Invoke system call. + ret +NtClose ENDP + +NtReadVirtualMemory PROC + mov [rsp +8], rcx ; Save registers. + mov [rsp+16], rdx + mov [rsp+24], r8 + mov [rsp+32], r9 + sub rsp, 28h + mov ecx, 009824143h ; Load function hash into ECX. + call SW3_GetSyscallNumber ; Resolve function hash into syscall number. + add rsp, 28h + mov rcx, [rsp+8] ; Restore registers. + mov rdx, [rsp+16] + mov r8, [rsp+24] + mov r9, [rsp+32] + mov r10, rcx + syscall ; Invoke system call. + ret +NtReadVirtualMemory ENDP + +NtWriteVirtualMemory PROC + mov [rsp +8], rcx ; Save registers. + mov [rsp+16], rdx + mov [rsp+24], r8 + mov [rsp+32], r9 + sub rsp, 28h + mov ecx, 08E108490h ; Load function hash into ECX. + call SW3_GetSyscallNumber ; Resolve function hash into syscall number. + add rsp, 28h + mov rcx, [rsp+8] ; Restore registers. + mov rdx, [rsp+16] + mov r8, [rsp+24] + mov r9, [rsp+32] + mov r10, rcx + syscall ; Invoke system call. + ret +NtWriteVirtualMemory ENDP + +NtAllocateVirtualMemory PROC + mov [rsp +8], rcx ; Save registers. + mov [rsp+16], rdx + mov [rsp+24], r8 + mov [rsp+32], r9 + sub rsp, 28h + mov ecx, 0C253FAF2h ; Load function hash into ECX. + call SW3_GetSyscallNumber ; Resolve function hash into syscall number. + add rsp, 28h + mov rcx, [rsp+8] ; Restore registers. + mov rdx, [rsp+16] + mov r8, [rsp+24] + mov r9, [rsp+32] + mov r10, rcx + syscall ; Invoke system call. + ret +NtAllocateVirtualMemory ENDP + +NtProtectVirtualMemory PROC + mov [rsp +8], rcx ; Save registers. + mov [rsp+16], rdx + mov [rsp+24], r8 + mov [rsp+32], r9 + sub rsp, 28h + mov ecx, 0C0603A1Dh ; Load function hash into ECX. + call SW3_GetSyscallNumber ; Resolve function hash into syscall number. + add rsp, 28h + mov rcx, [rsp+8] ; Restore registers. + mov rdx, [rsp+16] + mov r8, [rsp+24] + mov r9, [rsp+32] + mov r10, rcx + syscall ; Invoke system call. + ret +NtProtectVirtualMemory ENDP + +NtFreeVirtualMemory PROC + mov [rsp +8], rcx ; Save registers. + mov [rsp+16], rdx + mov [rsp+24], r8 + mov [rsp+32], r9 + sub rsp, 28h + mov ecx, 087118D83h ; Load function hash into ECX. + call SW3_GetSyscallNumber ; Resolve function hash into syscall number. + add rsp, 28h + mov rcx, [rsp+8] ; Restore registers. + mov rdx, [rsp+16] + mov r8, [rsp+24] + mov r9, [rsp+32] + mov r10, rcx + syscall ; Invoke system call. + ret +NtFreeVirtualMemory ENDP + +NtQuerySystemInformation PROC + mov [rsp +8], rcx ; Save registers. + mov [rsp+16], rdx + mov [rsp+24], r8 + mov [rsp+32], r9 + sub rsp, 28h + mov ecx, 0A4069EABh ; Load function hash into ECX. + call SW3_GetSyscallNumber ; Resolve function hash into syscall number. + add rsp, 28h + mov rcx, [rsp+8] ; Restore registers. + mov rdx, [rsp+16] + mov r8, [rsp+24] + mov r9, [rsp+32] + mov r10, rcx + syscall ; Invoke system call. + ret +NtQuerySystemInformation ENDP + +NtQueryDirectoryFile PROC + mov [rsp +8], rcx ; Save registers. + mov [rsp+16], rdx + mov [rsp+24], r8 + mov [rsp+32], r9 + sub rsp, 28h + mov ecx, 09533C586h ; Load function hash into ECX. + call SW3_GetSyscallNumber ; Resolve function hash into syscall number. + add rsp, 28h + mov rcx, [rsp+8] ; Restore registers. + mov rdx, [rsp+16] + mov r8, [rsp+24] + mov r9, [rsp+32] + mov r10, rcx + syscall ; Invoke system call. + ret +NtQueryDirectoryFile ENDP + +NtQueryInformationFile PROC + mov [rsp +8], rcx ; Save registers. + mov [rsp+16], rdx + mov [rsp+24], r8 + mov [rsp+32], r9 + sub rsp, 28h + mov ecx, 0AC3E2418h ; Load function hash into ECX. + call SW3_GetSyscallNumber ; Resolve function hash into syscall number. + add rsp, 28h + mov rcx, [rsp+8] ; Restore registers. + mov rdx, [rsp+16] + mov r8, [rsp+24] + mov r9, [rsp+32] + mov r10, rcx + syscall ; Invoke system call. + ret +NtQueryInformationFile ENDP + +NtQueryInformationProcess PROC + mov [rsp +8], rcx ; Save registers. + mov [rsp+16], rdx + mov [rsp+24], r8 + mov [rsp+32], r9 + sub rsp, 28h + mov ecx, 002AC0B33h ; Load function hash into ECX. + call SW3_GetSyscallNumber ; Resolve function hash into syscall number. + add rsp, 28h + mov rcx, [rsp+8] ; Restore registers. + mov rdx, [rsp+16] + mov r8, [rsp+24] + mov r9, [rsp+32] + mov r10, rcx + syscall ; Invoke system call. + ret +NtQueryInformationProcess ENDP + +NtQueryInformationThread PROC + mov [rsp +8], rcx ; Save registers. + mov [rsp+16], rdx + mov [rsp+24], r8 + mov [rsp+32], r9 + sub rsp, 28h + mov ecx, 0745A2EE3h ; Load function hash into ECX. + call SW3_GetSyscallNumber ; Resolve function hash into syscall number. + add rsp, 28h + mov rcx, [rsp+8] ; Restore registers. + mov rdx, [rsp+16] + mov r8, [rsp+24] + mov r9, [rsp+32] + mov r10, rcx + syscall ; Invoke system call. + ret +NtQueryInformationThread ENDP + +NtCreateSection PROC + mov [rsp +8], rcx ; Save registers. + mov [rsp+16], rdx + mov [rsp+24], r8 + mov [rsp+32], r9 + sub rsp, 28h + mov ecx, 0F42FD4F1h ; Load function hash into ECX. + call SW3_GetSyscallNumber ; Resolve function hash into syscall number. + add rsp, 28h + mov rcx, [rsp+8] ; Restore registers. + mov rdx, [rsp+16] + mov r8, [rsp+24] + mov r9, [rsp+32] + mov r10, rcx + syscall ; Invoke system call. + ret +NtCreateSection ENDP + +NtOpenSection PROC + mov [rsp +8], rcx ; Save registers. + mov [rsp+16], rdx + mov [rsp+24], r8 + mov [rsp+32], r9 + sub rsp, 28h + mov ecx, 064CE6A2Fh ; Load function hash into ECX. + call SW3_GetSyscallNumber ; Resolve function hash into syscall number. + add rsp, 28h + mov rcx, [rsp+8] ; Restore registers. + mov rdx, [rsp+16] + mov r8, [rsp+24] + mov r9, [rsp+32] + mov r10, rcx + syscall ; Invoke system call. + ret +NtOpenSection ENDP + +NtMapViewOfSection PROC + mov [rsp +8], rcx ; Save registers. + mov [rsp+16], rdx + mov [rsp+24], r8 + mov [rsp+32], r9 + sub rsp, 28h + mov ecx, 0508A5019h ; Load function hash into ECX. + call SW3_GetSyscallNumber ; Resolve function hash into syscall number. + add rsp, 28h + mov rcx, [rsp+8] ; Restore registers. + mov rdx, [rsp+16] + mov r8, [rsp+24] + mov r9, [rsp+32] + mov r10, rcx + syscall ; Invoke system call. + ret +NtMapViewOfSection ENDP + +NtUnmapViewOfSection PROC + mov [rsp +8], rcx ; Save registers. + mov [rsp+16], rdx + mov [rsp+24], r8 + mov [rsp+32], r9 + sub rsp, 28h + mov ecx, 0DF54DBCEh ; Load function hash into ECX. + call SW3_GetSyscallNumber ; Resolve function hash into syscall number. + add rsp, 28h + mov rcx, [rsp+8] ; Restore registers. + mov rdx, [rsp+16] + mov r8, [rsp+24] + mov r9, [rsp+32] + mov r10, rcx + syscall ; Invoke system call. + ret +NtUnmapViewOfSection ENDP + +NtAdjustPrivilegesToken PROC + mov [rsp +8], rcx ; Save registers. + mov [rsp+16], rdx + mov [rsp+24], r8 + mov [rsp+32], r9 + sub rsp, 28h + mov ecx, 05DC34340h ; Load function hash into ECX. + call SW3_GetSyscallNumber ; Resolve function hash into syscall number. + add rsp, 28h + mov rcx, [rsp+8] ; Restore registers. + mov rdx, [rsp+16] + mov r8, [rsp+24] + mov r9, [rsp+32] + mov r10, rcx + syscall ; Invoke system call. + ret +NtAdjustPrivilegesToken ENDP + +NtDeviceIoControlFile PROC + mov [rsp +8], rcx ; Save registers. + mov [rsp+16], rdx + mov [rsp+24], r8 + mov [rsp+32], r9 + sub rsp, 28h + mov ecx, 0D1DAE373h ; Load function hash into ECX. + call SW3_GetSyscallNumber ; Resolve function hash into syscall number. + add rsp, 28h + mov rcx, [rsp+8] ; Restore registers. + mov rdx, [rsp+16] + mov r8, [rsp+24] + mov r9, [rsp+32] + mov r10, rcx + syscall ; Invoke system call. + ret +NtDeviceIoControlFile ENDP + +NtQueueApcThread PROC + mov [rsp +8], rcx ; Save registers. + mov [rsp+16], rdx + mov [rsp+24], r8 + mov [rsp+32], r9 + sub rsp, 28h + mov ecx, 0E851AAFFh ; Load function hash into ECX. + call SW3_GetSyscallNumber ; Resolve function hash into syscall number. + add rsp, 28h + mov rcx, [rsp+8] ; Restore registers. + mov rdx, [rsp+16] + mov r8, [rsp+24] + mov r9, [rsp+32] + mov r10, rcx + syscall ; Invoke system call. + ret +NtQueueApcThread ENDP + +NtWaitForMultipleObjects PROC + mov [rsp +8], rcx ; Save registers. + mov [rsp+16], rdx + mov [rsp+24], r8 + mov [rsp+32], r9 + sub rsp, 28h + mov ecx, 003837B11h ; Load function hash into ECX. + call SW3_GetSyscallNumber ; Resolve function hash into syscall number. + add rsp, 28h + mov rcx, [rsp+8] ; Restore registers. + mov rdx, [rsp+16] + mov r8, [rsp+24] + mov r9, [rsp+32] + mov r10, rcx + syscall ; Invoke system call. + ret +NtWaitForMultipleObjects ENDP + +end \ No newline at end of file diff --git a/SysWhispers3/example-output/Syscalls.c b/SysWhispers3/example-output/Syscalls.c new file mode 100644 index 0000000..1806273 --- /dev/null +++ b/SysWhispers3/example-output/Syscalls.c @@ -0,0 +1,278 @@ +#include "Syscalls.h" +#include + +//#define DEBUG + +// JUMPER + +#ifdef _M_IX86 + +EXTERN_C PVOID internal_cleancall_wow64_gate(VOID) { + return (PVOID)__readfsdword(0xC0); +} + +__declspec(naked) BOOL local_is_wow64(void) +{ + __asm { + mov eax, fs:[0xc0] + test eax, eax + jne wow64 + mov eax, 0 + ret + wow64: + mov eax, 1 + ret + } +} + + +#endif + +// Code below is adapted from @modexpblog. Read linked article for more details. +// https://www.mdsec.co.uk/2020/12/bypassing-user-mode-hooks-and-direct-invocation-of-system-calls-for-red-teams + +SW3_SYSCALL_LIST SW3_SyscallList; + +// SEARCH_AND_REPLACE +#ifdef SEARCH_AND_REPLACE +// THIS IS NOT DEFINED HERE; don't know if I'll add it in a future release +EXTERN void SearchAndReplace(unsigned char[], unsigned char[]); +#endif + +DWORD SW3_HashSyscall(PCSTR FunctionName) +{ + DWORD i = 0; + DWORD Hash = SW3_SEED; + + while (FunctionName[i]) + { + WORD PartialName = *(WORD*)((ULONG_PTR)FunctionName + i++); + Hash ^= PartialName + SW3_ROR8(Hash); + } + + return Hash; +} + +#ifndef JUMPER +PVOID SC_Address(PVOID NtApiAddress) +{ + return NULL; +} +#else +PVOID SC_Address(PVOID NtApiAddress) +{ + DWORD searchLimit = 512; + PVOID SyscallAddress; + + #ifdef _WIN64 + // If the process is 64-bit on a 64-bit OS, we need to search for syscall + BYTE syscall_code[] = { 0x0f, 0x05, 0xc3 }; + ULONG distance_to_syscall = 0x12; + #else + // If the process is 32-bit on a 32-bit OS, we need to search for sysenter + BYTE syscall_code[] = { 0x0f, 0x34, 0xc3 }; + ULONG distance_to_syscall = 0x0f; + #endif + + #ifdef _M_IX86 + // If the process is 32-bit on a 64-bit OS, we need to jump to WOW32Reserved + if (local_is_wow64()) + { + #ifdef DEBUG + printf("[+] Running 32-bit app on x64 (WOW64)\n"); + #endif + return NULL; + } + #endif + + // we don't really care if there is a 'jmp' between + // NtApiAddress and the 'syscall; ret' instructions + SyscallAddress = SW3_RVA2VA(PVOID, NtApiAddress, distance_to_syscall); + + if (!memcmp((PVOID)syscall_code, SyscallAddress, sizeof(syscall_code))) + { + // we can use the original code for this system call :) + #if defined(DEBUG) + printf("Found Syscall Opcodes at address 0x%p\n", SyscallAddress); + #endif + return SyscallAddress; + } + + // the 'syscall; ret' intructions have not been found, + // we will try to use one near it, similarly to HalosGate + + for (ULONG32 num_jumps = 1; num_jumps < searchLimit; num_jumps++) + { + // let's try with an Nt* API below our syscall + SyscallAddress = SW3_RVA2VA( + PVOID, + NtApiAddress, + distance_to_syscall + num_jumps * 0x20); + if (!memcmp((PVOID)syscall_code, SyscallAddress, sizeof(syscall_code))) + { + #if defined(DEBUG) + printf("Found Syscall Opcodes at address 0x%p\n", SyscallAddress); + #endif + return SyscallAddress; + } + + // let's try with an Nt* API above our syscall + SyscallAddress = SW3_RVA2VA( + PVOID, + NtApiAddress, + distance_to_syscall - num_jumps * 0x20); + if (!memcmp((PVOID)syscall_code, SyscallAddress, sizeof(syscall_code))) + { + #if defined(DEBUG) + printf("Found Syscall Opcodes at address 0x%p\n", SyscallAddress); + #endif + return SyscallAddress; + } + } + +#ifdef DEBUG + printf("Syscall Opcodes not found!\n"); +#endif + + return NULL; +} +#endif + + +BOOL SW3_PopulateSyscallList() +{ + // Return early if the list is already populated. + if (SW3_SyscallList.Count) return TRUE; + + #ifdef _WIN64 + PSW3_PEB Peb = (PSW3_PEB)__readgsqword(0x60); + #else + PSW3_PEB Peb = (PSW3_PEB)__readfsdword(0x30); + #endif + PSW3_PEB_LDR_DATA Ldr = Peb->Ldr; + PIMAGE_EXPORT_DIRECTORY ExportDirectory = NULL; + PVOID DllBase = NULL; + + // Get the DllBase address of NTDLL.dll. NTDLL is not guaranteed to be the second + // in the list, so it's safer to loop through the full list and find it. + PSW3_LDR_DATA_TABLE_ENTRY LdrEntry; + for (LdrEntry = (PSW3_LDR_DATA_TABLE_ENTRY)Ldr->Reserved2[1]; LdrEntry->DllBase != NULL; LdrEntry = (PSW3_LDR_DATA_TABLE_ENTRY)LdrEntry->Reserved1[0]) + { + DllBase = LdrEntry->DllBase; + PIMAGE_DOS_HEADER DosHeader = (PIMAGE_DOS_HEADER)DllBase; + PIMAGE_NT_HEADERS NtHeaders = SW3_RVA2VA(PIMAGE_NT_HEADERS, DllBase, DosHeader->e_lfanew); + PIMAGE_DATA_DIRECTORY DataDirectory = (PIMAGE_DATA_DIRECTORY)NtHeaders->OptionalHeader.DataDirectory; + DWORD VirtualAddress = DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; + if (VirtualAddress == 0) continue; + + ExportDirectory = (PIMAGE_EXPORT_DIRECTORY)SW3_RVA2VA(ULONG_PTR, DllBase, VirtualAddress); + + // If this is NTDLL.dll, exit loop. + PCHAR DllName = SW3_RVA2VA(PCHAR, DllBase, ExportDirectory->Name); + + if ((*(ULONG*)DllName | 0x20202020) != 0x6c64746e) continue; + if ((*(ULONG*)(DllName + 4) | 0x20202020) == 0x6c642e6c) break; + } + + if (!ExportDirectory) return FALSE; + + DWORD NumberOfNames = ExportDirectory->NumberOfNames; + PDWORD Functions = SW3_RVA2VA(PDWORD, DllBase, ExportDirectory->AddressOfFunctions); + PDWORD Names = SW3_RVA2VA(PDWORD, DllBase, ExportDirectory->AddressOfNames); + PWORD Ordinals = SW3_RVA2VA(PWORD, DllBase, ExportDirectory->AddressOfNameOrdinals); + + // Populate SW3_SyscallList with unsorted Zw* entries. + DWORD i = 0; + PSW3_SYSCALL_ENTRY Entries = SW3_SyscallList.Entries; + do + { + PCHAR FunctionName = SW3_RVA2VA(PCHAR, DllBase, Names[NumberOfNames - 1]); + + // Is this a system call? + if (*(USHORT*)FunctionName == 0x775a) + { + Entries[i].Hash = SW3_HashSyscall(FunctionName); + Entries[i].Address = Functions[Ordinals[NumberOfNames - 1]]; + Entries[i].SyscallAddress = SC_Address(SW3_RVA2VA(PVOID, DllBase, Entries[i].Address)); + + i++; + if (i == SW3_MAX_ENTRIES) break; + } + } while (--NumberOfNames); + + // Save total number of system calls found. + SW3_SyscallList.Count = i; + + // Sort the list by address in ascending order. + for (DWORD i = 0; i < SW3_SyscallList.Count - 1; i++) + { + for (DWORD j = 0; j < SW3_SyscallList.Count - i - 1; j++) + { + if (Entries[j].Address > Entries[j + 1].Address) + { + // Swap entries. + SW3_SYSCALL_ENTRY TempEntry; + + TempEntry.Hash = Entries[j].Hash; + TempEntry.Address = Entries[j].Address; + TempEntry.SyscallAddress = Entries[j].SyscallAddress; + + Entries[j].Hash = Entries[j + 1].Hash; + Entries[j].Address = Entries[j + 1].Address; + Entries[j].SyscallAddress = Entries[j + 1].SyscallAddress; + + Entries[j + 1].Hash = TempEntry.Hash; + Entries[j + 1].Address = TempEntry.Address; + Entries[j + 1].SyscallAddress = TempEntry.SyscallAddress; + } + } + } + + return TRUE; +} + +EXTERN_C DWORD SW3_GetSyscallNumber(DWORD FunctionHash) +{ + // Ensure SW3_SyscallList is populated. + if (!SW3_PopulateSyscallList()) return -1; + + for (DWORD i = 0; i < SW3_SyscallList.Count; i++) + { + if (FunctionHash == SW3_SyscallList.Entries[i].Hash) + { + return i; + } + } + + return -1; +} + +EXTERN_C PVOID SW3_GetSyscallAddress(DWORD FunctionHash) +{ + // Ensure SW3_SyscallList is populated. + if (!SW3_PopulateSyscallList()) return NULL; + + for (DWORD i = 0; i < SW3_SyscallList.Count; i++) + { + if (FunctionHash == SW3_SyscallList.Entries[i].Hash) + { + return SW3_SyscallList.Entries[i].SyscallAddress; + } + } + + return NULL; +} + +EXTERN_C PVOID SW3_GetRandomSyscallAddress(DWORD FunctionHash) +{ + // Ensure SW3_SyscallList is populated. + if (!SW3_PopulateSyscallList()) return NULL; + + DWORD index = ((DWORD) rand()) % SW3_SyscallList.Count; + + while (FunctionHash == SW3_SyscallList.Entries[index].Hash){ + // Spoofing the syscall return address + index = ((DWORD) rand()) % SW3_SyscallList.Count; + } + return SW3_SyscallList.Entries[index].SyscallAddress; +} diff --git a/SysWhispers3/example-output/Syscalls.h b/SysWhispers3/example-output/Syscalls.h new file mode 100644 index 0000000..fb0fc27 --- /dev/null +++ b/SysWhispers3/example-output/Syscalls.h @@ -0,0 +1,487 @@ +#pragma once + +// Code below is adapted from @modexpblog. Read linked article for more details. +// https://www.mdsec.co.uk/2020/12/bypassing-user-mode-hooks-and-direct-invocation-of-system-calls-for-red-teams + +#ifndef SW3_HEADER_H_ +#define SW3_HEADER_H_ + +#include + +#define SW3_SEED 0x769430A3 +#define SW3_ROL8(v) (v << 8 | v >> 24) +#define SW3_ROR8(v) (v >> 8 | v << 24) +#define SW3_ROX8(v) ((SW3_SEED % 2) ? SW3_ROL8(v) : SW3_ROR8(v)) +#define SW3_MAX_ENTRIES 500 +#define SW3_RVA2VA(Type, DllBase, Rva) (Type)((ULONG_PTR) DllBase + Rva) + +// Typedefs are prefixed to avoid pollution. + +typedef struct _SW3_SYSCALL_ENTRY +{ + DWORD Hash; + DWORD Address; + PVOID SyscallAddress; +} SW3_SYSCALL_ENTRY, *PSW3_SYSCALL_ENTRY; + +typedef struct _SW3_SYSCALL_LIST +{ + DWORD Count; + SW3_SYSCALL_ENTRY Entries[SW3_MAX_ENTRIES]; +} SW3_SYSCALL_LIST, *PSW3_SYSCALL_LIST; + +typedef struct _SW3_PEB_LDR_DATA { + BYTE Reserved1[8]; + PVOID Reserved2[3]; + LIST_ENTRY InMemoryOrderModuleList; +} SW3_PEB_LDR_DATA, *PSW3_PEB_LDR_DATA; + +typedef struct _SW3_LDR_DATA_TABLE_ENTRY { + PVOID Reserved1[2]; + LIST_ENTRY InMemoryOrderLinks; + PVOID Reserved2[2]; + PVOID DllBase; +} SW3_LDR_DATA_TABLE_ENTRY, *PSW3_LDR_DATA_TABLE_ENTRY; + +typedef struct _SW3_PEB { + BYTE Reserved1[2]; + BYTE BeingDebugged; + BYTE Reserved2[1]; + PVOID Reserved3[2]; + PSW3_PEB_LDR_DATA Ldr; +} SW3_PEB, *PSW3_PEB; + +DWORD SW3_HashSyscall(PCSTR FunctionName); +BOOL SW3_PopulateSyscallList(); +EXTERN_C DWORD SW3_GetSyscallNumber(DWORD FunctionHash); +EXTERN_C PVOID SW3_GetSyscallAddress(DWORD FunctionHash); +EXTERN_C PVOID internal_cleancall_wow64_gate(VOID); +typedef struct _SYSTEM_HANDLE +{ + ULONG ProcessId; + BYTE ObjectTypeNumber; + BYTE Flags; + USHORT Handle; + PVOID Object; + ACCESS_MASK GrantedAccess; +} SYSTEM_HANDLE, *PSYSTEM_HANDLE; + +typedef struct _IO_STATUS_BLOCK +{ + union + { + NTSTATUS Status; + VOID* Pointer; + }; + ULONG_PTR Information; +} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; + +typedef struct _SYSTEM_HANDLE_INFORMATION +{ + ULONG HandleCount; + SYSTEM_HANDLE Handles[1]; +} SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION; + +typedef VOID(KNORMAL_ROUTINE) ( + IN PVOID NormalContext, + IN PVOID SystemArgument1, + IN PVOID SystemArgument2); + +typedef struct _PS_ATTRIBUTE +{ + ULONG Attribute; + SIZE_T Size; + union + { + ULONG Value; + PVOID ValuePtr; + } u1; + PSIZE_T ReturnLength; +} PS_ATTRIBUTE, *PPS_ATTRIBUTE; + +typedef struct _UNICODE_STRING +{ + USHORT Length; + USHORT MaximumLength; + PWSTR Buffer; +} UNICODE_STRING, *PUNICODE_STRING; + +#ifndef InitializeObjectAttributes +#define InitializeObjectAttributes( p, n, a, r, s ) { \ + (p)->Length = sizeof( OBJECT_ATTRIBUTES ); \ + (p)->RootDirectory = r; \ + (p)->Attributes = a; \ + (p)->ObjectName = n; \ + (p)->SecurityDescriptor = s; \ + (p)->SecurityQualityOfService = NULL; \ +} +#endif + +typedef struct _OBJECT_ATTRIBUTES +{ + ULONG Length; + HANDLE RootDirectory; + PUNICODE_STRING ObjectName; + ULONG Attributes; + PVOID SecurityDescriptor; + PVOID SecurityQualityOfService; +} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES; + +typedef struct _CLIENT_ID +{ + HANDLE UniqueProcess; + HANDLE UniqueThread; +} CLIENT_ID, *PCLIENT_ID; + +typedef enum _SYSTEM_INFORMATION_CLASS +{ + SystemBasicInformation = 0, + SystemPerformanceInformation = 2, + SystemTimeOfDayInformation = 3, + SystemProcessInformation = 5, + SystemProcessorPerformanceInformation = 8, + SystemHandleInformation = 16, + SystemInterruptInformation = 23, + SystemExceptionInformation = 33, + SystemRegistryQuotaInformation = 37, + SystemLookasideInformation = 45, + SystemCodeIntegrityInformation = 103, + SystemPolicyInformation = 134, +} SYSTEM_INFORMATION_CLASS, *PSYSTEM_INFORMATION_CLASS; + +typedef enum _PROCESSINFOCLASS +{ + ProcessBasicInformation = 0, + ProcessDebugPort = 7, + ProcessWow64Information = 26, + ProcessImageFileName = 27, + ProcessBreakOnTermination = 29 +} PROCESSINFOCLASS, *PPROCESSINFOCLASS; + +typedef enum _WAIT_TYPE +{ + WaitAll = 0, + WaitAny = 1 +} WAIT_TYPE, *PWAIT_TYPE; + +typedef VOID(NTAPI* PIO_APC_ROUTINE) ( + IN PVOID ApcContext, + IN PIO_STATUS_BLOCK IoStatusBlock, + IN ULONG Reserved); + +typedef KNORMAL_ROUTINE* PKNORMAL_ROUTINE; + +typedef enum _THREADINFOCLASS +{ + ThreadBasicInformation, + ThreadTimes, + ThreadPriority, + ThreadBasePriority, + ThreadAffinityMask, + ThreadImpersonationToken, + ThreadDescriptorTableEntry, + ThreadEnableAlignmentFaultFixup, + ThreadEventPair_Reusable, + ThreadQuerySetWin32StartAddress, + ThreadZeroTlsCell, + ThreadPerformanceCount, + ThreadAmILastThread, + ThreadIdealProcessor, + ThreadPriorityBoost, + ThreadSetTlsArrayAddress, + ThreadIsIoPending, + ThreadHideFromDebugger, + ThreadBreakOnTermination, + MaxThreadInfoClass +} THREADINFOCLASS, *PTHREADINFOCLASS; + +typedef enum _SECTION_INHERIT +{ + ViewShare = 1, + ViewUnmap = 2 +} SECTION_INHERIT, *PSECTION_INHERIT; + +typedef enum _FILE_INFORMATION_CLASS +{ + FileDirectoryInformation = 1, + FileFullDirectoryInformation = 2, + FileBothDirectoryInformation = 3, + FileBasicInformation = 4, + FileStandardInformation = 5, + FileInternalInformation = 6, + FileEaInformation = 7, + FileAccessInformation = 8, + FileNameInformation = 9, + FileRenameInformation = 10, + FileLinkInformation = 11, + FileNamesInformation = 12, + FileDispositionInformation = 13, + FilePositionInformation = 14, + FileFullEaInformation = 15, + FileModeInformation = 16, + FileAlignmentInformation = 17, + FileAllInformation = 18, + FileAllocationInformation = 19, + FileEndOfFileInformation = 20, + FileAlternateNameInformation = 21, + FileStreamInformation = 22, + FilePipeInformation = 23, + FilePipeLocalInformation = 24, + FilePipeRemoteInformation = 25, + FileMailslotQueryInformation = 26, + FileMailslotSetInformation = 27, + FileCompressionInformation = 28, + FileObjectIdInformation = 29, + FileCompletionInformation = 30, + FileMoveClusterInformation = 31, + FileQuotaInformation = 32, + FileReparsePointInformation = 33, + FileNetworkOpenInformation = 34, + FileAttributeTagInformation = 35, + FileTrackingInformation = 36, + FileIdBothDirectoryInformation = 37, + FileIdFullDirectoryInformation = 38, + FileValidDataLengthInformation = 39, + FileShortNameInformation = 40, + FileIoCompletionNotificationInformation = 41, + FileIoStatusBlockRangeInformation = 42, + FileIoPriorityHintInformation = 43, + FileSfioReserveInformation = 44, + FileSfioVolumeInformation = 45, + FileHardLinkInformation = 46, + FileProcessIdsUsingFileInformation = 47, + FileNormalizedNameInformation = 48, + FileNetworkPhysicalNameInformation = 49, + FileIdGlobalTxDirectoryInformation = 50, + FileIsRemoteDeviceInformation = 51, + FileUnusedInformation = 52, + FileNumaNodeInformation = 53, + FileStandardLinkInformation = 54, + FileRemoteProtocolInformation = 55, + FileRenameInformationBypassAccessCheck = 56, + FileLinkInformationBypassAccessCheck = 57, + FileVolumeNameInformation = 58, + FileIdInformation = 59, + FileIdExtdDirectoryInformation = 60, + FileReplaceCompletionInformation = 61, + FileHardLinkFullIdInformation = 62, + FileIdExtdBothDirectoryInformation = 63, + FileDispositionInformationEx = 64, + FileRenameInformationEx = 65, + FileRenameInformationExBypassAccessCheck = 66, + FileMaximumInformation = 67, +} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS; + +typedef struct _PS_ATTRIBUTE_LIST +{ + SIZE_T TotalLength; + PS_ATTRIBUTE Attributes[1]; +} PS_ATTRIBUTE_LIST, *PPS_ATTRIBUTE_LIST; + +EXTERN_C NTSTATUS NtCreateProcess( + OUT PHANDLE ProcessHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN HANDLE ParentProcess, + IN BOOLEAN InheritObjectTable, + IN HANDLE SectionHandle OPTIONAL, + IN HANDLE DebugPort OPTIONAL, + IN HANDLE ExceptionPort OPTIONAL); + +EXTERN_C NTSTATUS NtCreateThreadEx( + OUT PHANDLE ThreadHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN HANDLE ProcessHandle, + IN PVOID StartRoutine, + IN PVOID Argument OPTIONAL, + IN ULONG CreateFlags, + IN SIZE_T ZeroBits, + IN SIZE_T StackSize, + IN SIZE_T MaximumStackSize, + IN PPS_ATTRIBUTE_LIST AttributeList OPTIONAL); + +EXTERN_C NTSTATUS NtOpenProcess( + OUT PHANDLE ProcessHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN PCLIENT_ID ClientId OPTIONAL); + +EXTERN_C NTSTATUS NtOpenProcessToken( + IN HANDLE ProcessHandle, + IN ACCESS_MASK DesiredAccess, + OUT PHANDLE TokenHandle); + +EXTERN_C NTSTATUS NtTestAlert(); + +EXTERN_C NTSTATUS NtOpenThread( + OUT PHANDLE ThreadHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN PCLIENT_ID ClientId OPTIONAL); + +EXTERN_C NTSTATUS NtSuspendProcess( + IN HANDLE ProcessHandle); + +EXTERN_C NTSTATUS NtSuspendThread( + IN HANDLE ThreadHandle, + OUT PULONG PreviousSuspendCount); + +EXTERN_C NTSTATUS NtResumeProcess( + IN HANDLE ProcessHandle); + +EXTERN_C NTSTATUS NtResumeThread( + IN HANDLE ThreadHandle, + IN OUT PULONG PreviousSuspendCount OPTIONAL); + +EXTERN_C NTSTATUS NtGetContextThread( + IN HANDLE ThreadHandle, + IN OUT PCONTEXT ThreadContext); + +EXTERN_C NTSTATUS NtSetContextThread( + IN HANDLE ThreadHandle, + IN PCONTEXT Context); + +EXTERN_C NTSTATUS NtClose( + IN HANDLE Handle); + +EXTERN_C NTSTATUS NtReadVirtualMemory( + IN HANDLE ProcessHandle, + IN PVOID BaseAddress OPTIONAL, + OUT PVOID Buffer, + IN SIZE_T BufferSize, + OUT PSIZE_T NumberOfBytesRead OPTIONAL); + +EXTERN_C NTSTATUS NtWriteVirtualMemory( + IN HANDLE ProcessHandle, + IN PVOID BaseAddress, + IN PVOID Buffer, + IN SIZE_T NumberOfBytesToWrite, + OUT PSIZE_T NumberOfBytesWritten OPTIONAL); + +EXTERN_C NTSTATUS NtAllocateVirtualMemory( + IN HANDLE ProcessHandle, + IN OUT PVOID * BaseAddress, + IN ULONG ZeroBits, + IN OUT PSIZE_T RegionSize, + IN ULONG AllocationType, + IN ULONG Protect); + +EXTERN_C NTSTATUS NtProtectVirtualMemory( + IN HANDLE ProcessHandle, + IN OUT PVOID * BaseAddress, + IN OUT PSIZE_T RegionSize, + IN ULONG NewProtect, + OUT PULONG OldProtect); + +EXTERN_C NTSTATUS NtFreeVirtualMemory( + IN HANDLE ProcessHandle, + IN OUT PVOID * BaseAddress, + IN OUT PSIZE_T RegionSize, + IN ULONG FreeType); + +EXTERN_C NTSTATUS NtQuerySystemInformation( + IN SYSTEM_INFORMATION_CLASS SystemInformationClass, + IN OUT PVOID SystemInformation, + IN ULONG SystemInformationLength, + OUT PULONG ReturnLength OPTIONAL); + +EXTERN_C NTSTATUS NtQueryDirectoryFile( + IN HANDLE FileHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, + IN PVOID ApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + OUT PVOID FileInformation, + IN ULONG Length, + IN FILE_INFORMATION_CLASS FileInformationClass, + IN BOOLEAN ReturnSingleEntry, + IN PUNICODE_STRING FileName OPTIONAL, + IN BOOLEAN RestartScan); + +EXTERN_C NTSTATUS NtQueryInformationFile( + IN HANDLE FileHandle, + OUT PIO_STATUS_BLOCK IoStatusBlock, + OUT PVOID FileInformation, + IN ULONG Length, + IN FILE_INFORMATION_CLASS FileInformationClass); + +EXTERN_C NTSTATUS NtQueryInformationProcess( + IN HANDLE ProcessHandle, + IN PROCESSINFOCLASS ProcessInformationClass, + OUT PVOID ProcessInformation, + IN ULONG ProcessInformationLength, + OUT PULONG ReturnLength OPTIONAL); + +EXTERN_C NTSTATUS NtQueryInformationThread( + IN HANDLE ThreadHandle, + IN THREADINFOCLASS ThreadInformationClass, + OUT PVOID ThreadInformation, + IN ULONG ThreadInformationLength, + OUT PULONG ReturnLength OPTIONAL); + +EXTERN_C NTSTATUS NtCreateSection( + OUT PHANDLE SectionHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN PLARGE_INTEGER MaximumSize OPTIONAL, + IN ULONG SectionPageProtection, + IN ULONG AllocationAttributes, + IN HANDLE FileHandle OPTIONAL); + +EXTERN_C NTSTATUS NtOpenSection( + OUT PHANDLE SectionHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes); + +EXTERN_C NTSTATUS NtMapViewOfSection( + IN HANDLE SectionHandle, + IN HANDLE ProcessHandle, + IN OUT PVOID BaseAddress, + IN ULONG ZeroBits, + IN SIZE_T CommitSize, + IN OUT PLARGE_INTEGER SectionOffset OPTIONAL, + IN OUT PSIZE_T ViewSize, + IN SECTION_INHERIT InheritDisposition, + IN ULONG AllocationType, + IN ULONG Win32Protect); + +EXTERN_C NTSTATUS NtUnmapViewOfSection( + IN HANDLE ProcessHandle, + IN PVOID BaseAddress); + +EXTERN_C NTSTATUS NtAdjustPrivilegesToken( + IN HANDLE TokenHandle, + IN BOOLEAN DisableAllPrivileges, + IN PTOKEN_PRIVILEGES NewState OPTIONAL, + IN ULONG BufferLength, + OUT PTOKEN_PRIVILEGES PreviousState OPTIONAL, + OUT PULONG ReturnLength OPTIONAL); + +EXTERN_C NTSTATUS NtDeviceIoControlFile( + IN HANDLE FileHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, + IN PVOID ApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN ULONG IoControlCode, + IN PVOID InputBuffer OPTIONAL, + IN ULONG InputBufferLength, + OUT PVOID OutputBuffer OPTIONAL, + IN ULONG OutputBufferLength); + +EXTERN_C NTSTATUS NtQueueApcThread( + IN HANDLE ThreadHandle, + IN PKNORMAL_ROUTINE ApcRoutine, + IN PVOID ApcArgument1 OPTIONAL, + IN PVOID ApcArgument2 OPTIONAL, + IN PVOID ApcArgument3 OPTIONAL); + +EXTERN_C NTSTATUS NtWaitForMultipleObjects( + IN ULONG Count, + IN PHANDLE Handles, + IN WAIT_TYPE WaitType, + IN BOOLEAN Alertable, + IN PLARGE_INTEGER Timeout OPTIONAL); + +#endif