CobaltStrike Guide. #7 Malleable PE, Process Implementation and Post-Operation

19 June 2023 16 minutes
Author: Lady Liberty

Malleable PE, In-Process Implementation and Post-Operation

Want to learn how to use Malleable PE, process implementation, and effectively perform post-exploitation activities in CobaltStrike? Our guide provides detailed information, step-by-step instructions, and practical tips for effectively using these cybersecurity features. In our CobaltStrike guide, we’ll look at Malleable PE, a feature that allows you to change the parameters and properties of an executable file to avoid detection and analysis by security mechanisms. You will learn how to build and configure Malleable PE to effectively deploy and make your cyber attack resilient. The guide also covers process injection, a technique that allows you to infiltrate a system and perform malicious actions by exploiting the trust of processes already running on the system.

We’ll cover different implementation techniques and provide you with the knowledge you need to successfully use these techniques in your cyber attack. In addition, our guide offers extensive information on post-exploitation, the phase that follows a successful penetration. You’ll learn how to effectively perform post-intrusion actions, gather information, expand your access, and ensure a long-term presence in the system while avoiding detection and blocking. With the CobaltStrike Guide, you’ll have all the information and skills you need to successfully use Malleable PE, implement processes, and conduct post-exploitation in CobaltStrike. The guide will help you expand your cyber security skills and ensure your cyber attack is successful in the digital world. Access the CobaltStrike Guide today and excel in Malleable PE, process implementation, and post-operational security in the digital space.

Malleable PE, In-Process Implementation and Post-Operation


C2 compliant profiles are more than communication metrics. C2 compliant profiles also control the characteristics of the beacon in memory, determine how the beacon is introduced into the process, and affect the operation of Cobalt Strike after operation. The following sections describe these extensions to the flexible C2 language.

PE and memory LEDs

The scene block in the Malleable C2 profiles controls how the beacon is loaded into memory and edits the contents of the Beacon DLL.

stage {
set userwx "false";
set compile_time "14 Jul 2009 8:14:00";
set image_size_x86 "512000";
set image_size_x64 "512000"; set obfuscate "true";

transform-x86 {
prepend "\x90\x90";
strrep "ReflectiveLoader" "DoLegitStuff";

transform-x64 {
# преобразование x64 stage DLL

stringw "I am not Beacon";

The stages block accepts commands that add lines to the .rdata Beacon section of the DLL. The string command adds a null-terminated string. The stringw command adds a wide (UTF-16LE encoded)  string. The data command  adds the string as is.

The transform-x86 and transform-x64 blocks place and transform the choppy DLL of the Beacon stage. These blocks support three commands: prepend, add, and strrep.

The prepend command inserts a line before the Reflective Beacon DLL. The add command  adds a line after the Reflecting Beacon DLL. Make sure the added data is the correct stage architecture code (x86, x64). The c2lint program does not provide a check for this. The strrep command replaces a string inside the Reflective Beacon DLL.

The stages block accepts several parameters that control the contents of the Beacon DLL and provide hints for changing the behavior of the beacon’s reflective loader:

The module_x86 and module_x64 parameters now support the ability to specify a starting ordinal value to search for the exported function. The optional part 0x## is the starting ordinal value given by an integer.

If the library is installed and the beacon does not overwrite itself in memory, then the library probably does not have an exported function with an ordinal value between 1 and 15. To solve this problem, define a valid ordinal value and specify it using additional syntax, such as: setmodule_x64 “libtemp.dll+0x90”.

Cloning PE headers

The scene block has several parameters that change the characteristics of the Reflective Beacon DLL so that it looks like something else in memory. They are designed to create indicators that support analytical tasks and threat modeling scenarios.

Cobalt Strike’s Linux package includes the peclone tool for extracting headers from DLLs and presenting them as a ready-to-use staging block:

./peclone [/шлях/до/зразка.dll]

Evasion and confusion in memory

Use the stage block’s prepend command to override the analysis, which scans the first few bytes of a memory segment for signs of an embedded DLL. If specific strings are used to search for agents, change them using the strrep command.

If strrep is not enough, set sleep_mask  to true. This tells the beacon to entangle itself and its stack in memory before going to sleep. After sleeping, Beacon deobfuscates itself to query and perform tasks. SMB and TCP Beaons will be confused when waiting for a new connection or waiting for data from a parent session.

Decide how much you want the DLL to remember in memory. If you want easy detection, set stomppe to false. If you want to easily obfuscate the Beacon DLL in memory, set the stomppe parameter to true. If you want more complexity, set obfuscate to true. This option will take many steps to confuse your beacon tag and the final state of the DLL in memory.

One way to detect DLL memory injections is to look for the MZ and PE magic bytes in their expected locations relative to each other. These values are usually not confused because the reflective loading process depends on them. The obfuscate option does not affect these values. Set magic_pe to the two letters or bytes that mark the beginning of the PE header. Set magic_mz_x86 to change these magic bytes in the x86 Beacon DLL. Install magic_mz_x64  for x64 Beacon DLLs. Instructions that change the state of the processor are followed by instructions that undo the changes. For example, MZ is an easily recognizable sequence in the header, but they are also valid x86 and x64 instructions. The following RE (x86) and AR (x64) are valid x86 and x64 instructions that undo MZ changes. These recommendations will change the magic values in the Reflective Beacon DLL and force the reflective boot process to use the new values.

Figure 46. We analyze the default values for module_mz_x86

Set userwx to false to tell the beacon loader not to use RWX permissions. Memory segments with these permissions will attract increased attention from analysts and security products.

By default, the beacon loader allocates memory using VirtualAlloc. Use the allocator parameter to change this. The HeapAlloc option allocates heap memory for beacons with RWX permissions. The MapViewOfFile allocator allocates memory for the beacon by creating an anonymous memory area of the mapped area of the file in the current process. The tamp module is an alternative to these options and a way to force the beacon to run from the desired memory image. Set module_x86 for DLLs that are about twice the size of the payload itself. The x86 beacon loader will load the specified DLL, locate it in memory, and overwrite it.

This is a way of placing a beacon in memory that Windows associates with a file on disk. It is important that the DLL you choose is not required by the applications you intend to host. The module_x64 option is the same story, but it affects the x64 Beacon.

If you are concerned about the Beacon stage initializing the Beacon DLL in memory, set clear to true. This option will free the memory associated with the beacon stage when it is no longer needed.

Implementation in progress

The process input block in Malleable C2 profiles generates the input content and controls the Beacon payload input behavior. It also controls the execution behavior of beacon object files (BOFs) in the current beacon.

процес-ін'єкція {
# Налаштувати спосіб розподілу пам'яті у віддаленому процесі для вбудованого вмісту
набір розподільників "VirtualAllocEx";
# установка способу виділення пам'яті в поточному процесі для  вмісту конвертерного конвертера
набір bof_allocator «VirtualAlloc»; встановити bof_reuse_memory "true";
# Налаштування характеристик пам'яті для вбудованого вмісту та
Конвертерні конвертери
встановити min_alloc "16384"; встановити startrwx "true"; встановити userwx	"false";
# Перетворення вбудованого вмісту x86
transform-x86 {
претендувати "\x90\x90";
# Перетворення вбудованого вмісту x64
transform-x64 {
додати "\x90\x90";
# Визначте, як виконати вбудований код
виконати {
CreateThread "ntdll.dll! RtlUserThreadStart»; SetThreadContext;

The process-injection block accepts several parameters that control the process of injecting the process into the beacon.

The transform-x86 and transform-x64 blocks contain beacon-embedded content. These blocks support two commands: prepend and append. The Precedence command inserts a line before the embedded content. The add command adds a line after the embedded content. Make sure that the added data is a valid code for the embedded content architecture (x86, x64). The c2lint program does not include a check for this.

The execution block  controls the methods that the beacon will use when it needs to inject code into the process. The beacon checks each parameter in the execution block to determine if the parameter is valid for the current context, tries the method if it is, and moves on to the next parameter if code execution has not occurred. Execution parameters include:

The CreateThread and CreateRemoteThread options have variations that wait for a suspended thread with the address of another function, update the suspended thread to execute embedded code, and resume that thread. Use “module!function+0x##” to specify the starting address to spoof. For remote processes, it is recommended to use only the ntdll and kernel32 modules. The optional part 0x## is the offset added to the starting address. These options only work for  x86 -> x86 and  x64 -> x64.

The execution options you choose should cover different side situations. These side effects include self-injection, injection into suspended temporary processes, cross-session remote process injection, x86->x64, x64->x86 injection, and pass-in or non-argument injection. The c2lint tool will warn you about contexts that your execution block does not cover.

Process implementation management

Cobalt Strike 4.5 adds support that allows users to define their own implementation technique in-process instead of using the built-in methods. This is done using the PROCESS_INJECT_SPAWN and PROCESS_INJECT_EXPLICIT hook functions. Cobalt Strike will call one of these hooks when executing commands after exploitation. See the hook section for a table of supported commands.

Two hooks will cover most post-production teams. However, there are some exceptions that will not use these hooks and will continue to use the built-in technique.

To implement your own injection technique, you will need to provide a Beacon Object File (BOF) containing the executable code for x86 and/or x64 architectures and an aggressor script file containing the hook function. See examples of process implementation hooks in the Community Kit.

Since you are implementing your own injection technique, the process injection settings in your Malleable C2 profile will not be used unless your converter calls the BeaconInjectProcess or BeaconInjectTemporaryProcess API function. These functions implement injection by default and most likely will not be used unless it is a default fallback method implementation.

Implementation generation in process

The PROCESS_INJECT_SPAWN hook is used to define the implementation technique in the fork process &; run. The following Beacon commands, aggressor script functions, and user interfaces listed in the table below will trigger the hook, and the user can implement their own technique or use the built-in one.

Pay attention to the following:

  1. The commands elevate, runasadmin, &belevate,   &brunasadmin, and [beacon]  -> Access -> Elevate will only use the PROCESS_INJECT_SPAWN hook when the specified exploit uses one of the aggressor script functions listed in the table, such as  &bpowerpick.

  2. For the net and &bnet commands, the ‘domain’ command will not use a hook.

  3. Note “(use hash)” means to select credentials that refer to the hash.

Types of work

Explicit implementation in process

The PROCESS_INJECT_EXPLICIT hook is used to specify the explicit implementation technique in the process. The following Beacon commands, aggressor script functions, and user interfaces listed in the table below will invoke the hook, and the user can implement their own technique or use the built-in one.

Pay attention to the following:

  1. The [Process Explorer] interface is accessed via [beacon] -> Explore  -> Process List. There is also a multi-version of this interface, accessed by selecting multiple sessions and using the same user interface menu. In the process explorer, use the buttons to execute additional commands for the selected process.

  2. Chromedump, dcsync, hashdump, keylogger, logonpasswords, mimikatz, net, portscan, printscreen, pth, screenshot, screenwatch, ssh and ssh-key commands. They also have a fork&run version. To use the explicit version, the arguments pid and arch are required.

  3. For the net and &bnet commands, the ‘domain’ command will not use a hook.

Types of work

Postoperative management

Cobalt Strike’s major post-exploitation features (eg screenshot, keylogger, hashdump, etc.) are implemented as Windows DLLs. To perform these functions, Cobalt Strike spawns a temporary process and injects a function into it. The process injection block controls the process implementation phase. The post-ex section manages the content and behavior specific to Cobalt Strike’s post-ex functions. In version 4.5, these post-exploit functions now support explicit injection into an existing process when using the [pid] and [arch] arguments.

post-ex {
# контроль тимчасового процесу, який ми породжуємо встановити spawnto_x86 "%windir%\\syswow64\\rundll32.exe"; встановити spawnto_x64 "%windir%\\sysnative\\rundll32.exe";
# зміна дозволів і вмісту наших бібліотек DLL після експлуатації
встановити заплутування "true";
# Зміна назв названих труб...
встановити ім'я труби "evil_####, stuff\\not_##_ev#l";

# передача покажчиків на ключові функції від маяка до його дочірніх завдань
встановити SmartInject "true";

# відключення AMSI в powerpick, execute-assembly і psinject
встановити amsi

The spawnto_x86 and spawnto_x64 options  control the default temp process that Beacon will spawn for its post-op functions. Here are some tips for these options:

  1. Always specify the full path to the program you want to spawn Beacon.

  2. Environment variables (eg %windir%) on these paths are allowed.

  3. Do not specify %windir%\system32 or c:\windows\system32 directly. Always use syswow64 (x86) and sysnative (x64). Beacon will adjust these values to system32 where appropriate.

  4. An x86 spawnto value must specify an x86 program. For the x64 spawnto value, you must specify an x64 program.

  5. The specified paths (with the exception of the syswow64/sysnative autocorrect) must exist in both x64 (native) and x86 (wow64) views of the file system.

The obfuscation option encrypts the contents of post-production DLLs and places these functions in memory in a more secure OPSEC manner. This is very similar to obfuscate and userwx, available to Beacon through the stage block. Some long-running DLLs mask and unmask their string table as needed when this option is set.

Use pipename to change the name of the named pipes used by DLLs to send output back to the beacon. This parameter accepts a comma-separated list of named pipes.

Cobalt Strike will select a randomly named channel from this parameter when the post-production job is set. Each # in the channel name is replaced with a valid hexadecimal character.

The smartinject option  tells Beacon to inject pointers to key functions such as GetProcAddress and LoadLibrary into its DLLs after a single-arch exploit. This allows a post-production DLL to load itself into a new process without shell-like behavior, which is detected and remedied by monitoring PEB and kernel32.dll memory access.

The thread_hint parameter allows multi-threaded post-production DLLs to wait for threads with a fake start address. Specify the stream label as “module!function+0x##” to define the starting address for spoofing. The optional part 0x## is the offset added to the starting address.

The amsi_disable option  tells powerpick, execute-assembly, and psinject to fix the AmsiScanBuffer function before loading .NET or PowerShell code. This limits the visibility of these AMSI (Antimalware Scan Interface) features.

Set  keylogger option to configure Cobalt Strike keylogger. The GetAsyncKeyState option (default) uses the GetAsyncKeyState API to track keystrokes. The SetWindowsHookEx option uses SetWindowsHookEx to track keystrokes.

User Defined Reflective DLL Loader

Cobalt Strike version 4.4 adds support for using custom reflector loaders for Beacon. The Custom Reflective Loader (UDRL) Kit is the source code to demonstrate the UDRL example. Go to Help -> Arsenal and download the UDRL Kit. A license key is required.

NOTE: The Reflective Loader executable is an extracted .text section from a user-supplied compiled object file. Extracted executable code must be less than 100Kb.


The following aggressor script hooks are provided to implement user-defined choppy loaders:

The following Aggressor Script functions are designed to extract the Reflective Loader executable code (.text sections) from the compiled object file and inject the executable code into the beacon:

The following aggressor script functions are designed to modify the beacon using information from the Malleable C2 profile:

The following Aggressor Script function is designed to retrieve information about: A beacon to facilitate its modification:

The following functions of the aggressor script allow you to perform custom modifications of the beacon:

NOTE: Depending on custom modifications made (obfuscation, masking, etc.), Reflective Loader may need to undo these modifications during loading.

Using User Defined Reflective DLL Loaders

Creation/compilation of reflective loaders

The user-defined UDRL set (UDRL) is the starting point for demonstrating the UDRL example.

Go to Help -> Arsenal and download the UDRL Kit (requires a license key). Next is the process of making beacons:

The BEACON_RDLL_SIZE hook is called when preparing beacons.

  1. This gives the user the option to specify that their reflective bootloader will require more than 5KB of space.

  2. Users can use beacons that reserve space for a reflective bootloader of up to 100 KB.

  3. By overlapping the available space of the chopper loader in the beacons, the beacons will become much larger. In fact, they will be too large for the standard artifacts provided by Cobal Strike. Users will have to update their processes to use specialized artifacts with increased reserved space for large beacons.

Necessary settings are added to beacons as payload data.

The following fixes have been made to beacons for UDRL:

  1. Listener settings.

  2. Some parameters of Malleable C2.

Using sleepmask and userwx  requires a beacon bootloader capable of creating memory for executable .text code with RWX permissions, otherwise the beacon will fail when masking/unmasking write-protected memory. Standard reflective forklifts usually do the job.

Using sleepmask and obfuscate requires a reflective loader capable of removing the first 4KB block (header) of the DLL because the header will not be obfuscated.

  • The following are NOT fixed in beacons for UDRL: EP Mods

  • Usually called BEACON_RDLL_GENERATE. Hook


  • Next, it is determined what causes it: Malleable C2 has a parameter “.stage.smartinject”.

  • Using the extract_reflective_loader function to extract the Reflective Loader.

Use the setup_reflective_loader function to place the extracted reflective loader into the reflective loader space in the beacons. If the loader is too large for the selected beacon, you will see the following message: o Reflective DLL Content length (123456) exceeds available space (5120).

Use “BEACON_RDLL_SIZE” to use beacons with larger reflective loaders.

There are additional features to help you test and make changes to beacons based on the capabilities of reflective forklifts.

  • Guaranteed to tangle

  • Discuss changes to support smart implementation

Beacons turn into artifacts.

  1. Beacons that have been created with larger reflector loader space (according to the “BEACON_RDLL_SIZE” parameter above) must be loaded into special artifacts with space to store large beacons.

  2. Go to Help -> Arsenal from licensed Cobalt Strike to download

Set of artifacts.

See the reference to “stagesize” in these artifact set files provided by CobaltStrike:

  1. See the reference to “stagesize” in the artifact creation script.

  2. See the reference to “stagesize” in “script.example”.

Thanks to various open source guides.

Found an error?
If you find an error, take a screenshot and send it to the bot.