Post-ex User Defined Reflective DLL Loader

Cobalt Strike 4.9 added support for using customer reflective loaders for the post-ex payloads. The Post-ex User Defined Reflective Loader example is part of the udrl-vs kit in the Arsenal Kit. Got to Help -> Arsenal and download the Arsenal Kit. Your licence key is required.

A Post-ex User Defined Reflective Loader can only be applied to the following post-ex DLLs:

Beacon Command Aggressor Script Function DLL Name
browserpivot bbrowserpivot browserpivot
hashdump bhashdump hashdump
execute-assembly bexecute_assembly invokeassembly
keylogger bkeylogger keylogger
chromedump N/A mimikatz
logonpasswords blogonpasswords mimikatz
mimikatz bmimikatz and bmimikatz_small mimikatz
pth bpassthehash mimikatz
net bnet netview
portscan bportscan portscan
powerpick bpowerpick powershell
psinject bpsinject powershell
printscreen bprintscreen screenshot
screenshot bscreenshot screenshot
screenwatch bscreenwatch screenshot
ssh-key bssh_key shagent
ssh bssh sshagent

Implementation

The following Aggressor script hook is provided to allow implementation of Post-ex User Defined Reflective Loaders:

Function Description
POSTEX_RDLL_GENERATE Hook used to implement Reflective Loader replacement for post-ex DLLs. Arguments provided include Beacon ID, GetModuleHandleA address, and GetProcAddress address.

Using Post-ex User Defined Reflective DLL Loaders

Create/Compile your Reflective Loaders

The Post-ex User Defined Reflective Loader example is part of the udrl-vs kit in the Arsenal Kit. Got to Help -> Arsenal and download the Arsenal Kit. Your license key is required. Please note that User Defined Reflective Loaders for Beacon payloads and post-ex payloads are very similar but have some subtle differences.

The loader entry function is called with the WinAPI calling convention, and it takes a single LPVOID argument. Therefore, the entry function must be declared as follows:

void WINAPI ReflectiveLoader(LPVOID loaderArgument)

Post-exploitation payloads assume that the DLL's entry point is called with the following order and arguments:

DllMain(<Loaded DLL Base Address>, DLL_PROCESS_ATTACH, <Pointer to RDATA_SECTION strucutre>);
DllMain(<Loader Base Address>, 4, <Loader Argument from the entry function>);

The RDATA_SECTION point argument is as some long-running post-exploitation payloads obfuscate their .rdata section during the waiting period. It is the loader's responsibility to provide the following structure to the DLL. However, if the NULL value is passed then the DLL does not perform runtime obfuscation.

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;

The obfuscation start offset ensures that the Import Address Table (IAT) will not be obfuscated. Typically, this value should be set to the size of the IMAGE_DIRECTORY_ENTRY_IAT Data Directory entry as follows:

rdata->offset = ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size;