Beacon Object File for Cobalt Strike that executes .NET assemblies in beacon with evasion techniques.
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Cobalt Strike Beacon β
β (Parent Process) β
ββββββββββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββββββ
β
β beacon_inline_execute()
β - Parse packed arguments
β - Call go()
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β BOF Execute-Assembly Entry (go) β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Configuration Parsing β β
β β β’ ProxyMethod (None/Draugr/Timer/RegWait) β β
β β β’ AmsiEvasion (None/Patch/HWBP) β β
β β β’ EtwEvasion (None/Patch) β β
β β β’ PipeName, AppDomainName, Assembly bytes, Arguments β β
β ββββββββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββ β
β β β
β ββββββββββββββββββββββββββββββββββΌββββββββββββββββββββββββββββββββββββββββ β
β β Framework Initialization β β
β β β’ InitVxTable() - Resolve syscall numbers β β
β β ββ> NtProtectVirtualMemory, NtContinue, NtCreateEvent, β β
β β NtSetEvent, NtWaitForSingleObject, NtClose β β
β β β’ DraugrInit() - Setup synthetic stack frames β β
β β ββ> Locate RtlUserThreadStart, BaseThreadInitThunk β β
β ββββββββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββ β
β β β
β ββββββββββββββββββββββββββββββββββΌββββββββββββββββββββββββββββββββββββββββ β
β β DLL Loading (ProxyLoadLibraryA) β β
β β β’ amsi.dll, OleAut32.dll, mscoree.dll, User32.dll β β
β β β β
β β PROXY_NONE: LoadLibraryA() directly β β
β β PROXY_DRAUGR: DRAUGR_API(LoadLibraryA) - spoofed stack β β
β β PROXY_TIMER: CreateTimerQueue β Timer callback β β
β β PROXY_REGWAIT: RegisterWaitForSingleObject β Event callback β β
β ββββββββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββ β
β β β
β ββββββββββββββββββββββββββββββββββΌββββββββββββββββββββββββββββββββββββββββ β
β β AMSI Evasion Setup β β
β β β β
β β AMSI_PATCH: AMSI_HWBP: β β
β β βββββββββββββββββββββββββββ ββββββββββββββββββββββββββββββββ β β
β β β 1. Backup 4 bytes β β 1. Add VEH Handler β β β
β β β 2. NtProtectVirtualMem β β 2. RtlCaptureContext β β β
β β β (RW) β β 3. Set DR0 = AmsiScanBuffer β β β
β β β 3. Write: β β 4. Enable DR7 breakpoint β β β
β β β 48 31 C0 xor rax,raxβ β 5. NtContinue (apply ctx) β β β
β β β C3 ret β β β β β
β β β 4. NtProtectVirtualMem β β On AmsiScanBuffer call: β β β
β β β (restore) β β β #BP Exception β β β
β β βββββββββββββββββββββββββββ β β VEH redirects to RET β β β
β β β β RAX = 0 β β β
β β ββββββββββββββββββββββββββββββββ β β
β ββββββββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββ β
β β β
β ββββββββββββββββββββββββββββββββββΌββββββββββββββββββββββββββββββββββββββββ β
β β ETW Evasion (if enabled) β β
β β β’ NtProtectVirtualMemory(NtTraceEvent, RW) β β
β β β’ Backup 4 bytes β β
β β β’ Write: 48 31 C0 C3 (xor rax,rax; ret) β β
β β β’ NtProtectVirtualMemory(restore protection) β β
β ββββββββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββ β
β β β
β ββββββββββββββββββββββββββββββββββΌββββββββββββββββββββββββββββββββββββββββ β
β β Output Redirection Setup β β
β β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β
β β β 1. CreateNamedPipeW(\\.\pipe\{CustomName}) β hPipe β β β
β β β 2. CreateFileW(pipe path) β hFile β β β
β β β 3. AllocConsole() + ShowWindow(SW_HIDE) β Hidden console β β β
β β β β β β
β β β 4. PEB Manipulation: β β β
β β β β’ Backup: hCurrentStdOut = PEB->ProcessParameters->StdOut β β β
β β β β’ Backup: hCurrentStdErr = PEB->ProcessParameters->StdErr β β β
β β β β’ Redirect: PEB->StdOut = hFile β β β
β β β β’ Redirect: PEB->StdErr = hFile β β β
β β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β
β ββββββββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββ β
β β β
β ββββββββββββββββββββββββββββββββββΌββββββββββββββββββββββββββββββββββββββββ β
β β CLR Hosting & Assembly Execution (ExecuteAssembly) β β
β β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β
β β β 1. CLR Version Detection β β β
β β β β’ Scan assembly bytes for "v2.0.50727" or "v4.0.30319" β β β
β β β β β β
β β β 2. CLR Initialization β β β
β β β β’ CLRCreateInstance β ICLRMetaHost β β β
β β β β’ GetRuntime(v2/v4) β ICLRRuntimeInfo β β β
β β β β’ GetInterface β ICorRuntimeHost β β β
β β β β’ Start() β β β
β β β β β β
β β β 3. AppDomain Management β β β
β β β β’ GetDefaultDomain() β Default AppDomain β β β
β β β β’ CreateDomain(CustomName) β Isolated AppDomain β β β
β β β β β β
β β β 4. Assembly Loading β β β
β β β β’ Create SAFEARRAY (VT_UI1) with assembly bytes β β β
β β β β’ SafeArrayAccessData β Copy assembly to safe array β β β
β β β β’ CustomAppDomain->Load_3(safearray) β Load in memory β β β
β β β β β β
β β β 5. Argument Preparation β β β
β β β β’ Parse space-delimited arguments β β β
β β β β’ Create SAFEARRAY(VT_BSTR) for each argument β β β
β β β β’ Wrap in VARIANT structure β β β
β β β β β β
β β β 6. Execution β β β
β β β β’ Assembly->EntryPoint() β Get Main() MethodInfo β β β
β β β β’ MethodInfo->Invoke_3(arguments) β Execute β β β
β β β ββ> Assembly writes to Console β β β
β β β ββ> Redirected to hFile β Named Pipe β β β
β β β β β β
β β β 7. Cleanup β β β
β β β β’ Release COM interfaces (MethodInfo, Assembly, etc.) β β β
β β β β’ UnloadDomain(CustomAppDomain) β Full unload β β β
β β β β’ FreeLibrary(mscoree.dll) β β β
β β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β
β ββββββββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββ β
β β β
β ββββββββββββββββββββββββββββββββββΌββββββββββββββββββββββββββββββββββββββββ β
β β Output Capture & Display β β
β β β’ Restore PEB: StdOut/StdErr = original handles β β
β β β’ Allocate buffer (0x10000 bytes) β β
β β β’ ReadFile(hPipe) β Capture assembly output β β
β β β’ BeaconPrintf(CALLBACK_OUTPUT, output) β Display to operator β β
β ββββββββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββ β
β β β
β ββββββββββββββββββββββββββββββββββΌββββββββββββββββββββββββββββββββββββββββ β
β β Cleanup & Restoration β β
β β β’ free(pAssemblyStdOut) β β
β β β’ NtClose(hFile, hPipe) β β
β β β’ FreeConsole() β β
β β β β
β β if (AMSI_PATCH): β β
β β β’ RestoreAmsi() - Write original 4 bytes back β β
β β β β
β β if (AMSI_HWBP): β β
β β β’ RemoveHwbp() - Clear debug registers β β
β β β’ RemoveVectoredExceptionHandler(VehHandler) β β
β β β β
β β if (ETW_PATCH): β β
β β β’ RestoreEtw() - Write original 4 bytes back β β
β β β β
β β β’ Restore PEB: StdOut/StdErr = original β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
β Return to Beacon
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Beacon continues execution β
β (BOF memory cleaned up) β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
| Method | Description |
|---|---|
None |
Direct API calls |
Draugr |
Stack spoofed API calls via Draugr |
Regwait |
RegisterWaitForSingleObject callback execution |
Timer |
Timer Queue callback execution |
| Method | Description |
|---|---|
None |
No AMSI bypass |
Patch |
Memory patch of AMSI!AmsiScanBuffer (xor rax,rax; ret) |
HWBP |
Hardware breakpoint hook on AMSI!AmsiScanBuffer via VEH |
| Method | Description |
|---|---|
None |
No ETW bypass |
Patch |
Memory patch of NTDLL!NtTraceEvent (xor rax,rax; ret) |
| Parameter | Description | Example |
|---|---|---|
| PipeName | Named pipe name for capturing assembly output | P1p3N4m3 |
| AppDomain | Custom .NET AppDomain name for assembly isolation | Tot4lL3g1t |
LoadLibraryA("amsi.dll") β Direct call
DRAUGR_API(LoadLibraryA, "amsi.dll")
β
ββ Synthetic Stack Construction
ββ Return Address Spoofing
ββ Indirect Execution
CreateTimerQueue() β CreateTimerQueueTimer(
callback = LoadLibraryA,
parameter = "amsi.dll",
dueTime = 100ms
) β Wait β DeleteTimerQueueEx()
CreateEvent() β RegisterWaitForSingleObject(
event,
callback = LoadLibraryA,
context = "amsi.dll"
) β SetEvent() β UnregisterWait()
Before Patch: After Patch:
AmsiScanBuffer: AmsiScanBuffer:
4C 8B DC mov r11, rsp 48 31 C0 xor rax, rax
49 89 5B 08 mov [r11+8], rbx C3 ret
... ...
Result: All scans return S_OK (clean)
Method:
- Save original 4 bytes
- Change memory protection to RW
- Write
xor rax, rax; ret - Restore memory protection
- Restore original bytes on cleanup
Setup:
1. AddVectoredExceptionHandler
2. RtlCaptureContext
3. Set DR0 = AmsiScanBuffer address
4. Enable DR7 breakpoint flag
5. NtContinue (apply context)
Execution Flow:
AmsiScanBuffer called
β
βΌ
#BP Exception (EXCEPTION_SINGLE_STEP)
β
βΌ
VEH Handler intercepts
β
ββ Verify RIP == AmsiScanBuffer
ββ Set RIP = FindRetInstruction(AmsiScanBuffer)
ββ Set RAX = 0 (S_OK)
ββ Set TF (Trap Flag)
β
βΌ
Return with RAX=0
Before: After:
NtTraceEvent: NtTraceEvent:
4C 8B D1 mov r10, rcx 48 31 C0 xor rax, rax
B8 XX XX mov eax, syscall C3 ret
Standard Assembly (No BOF): BOF Execute-Assembly:
Assembly β Console.WriteLine 1. Create \\.\pipe\{name}
β β
βΌ βΌ
Output lost 2. Open pipe as file handle
β
βΌ
3. Redirect PEB handles:
β’ StdOut β pipe
β’ StdErr β pipe
β
βΌ
4. Execute assembly
β
βΌ
5. ReadFile(pipe)
β
βΌ
6. BeaconPrintf β Operator
| Technique | Bypasses |
|---|---|
| Indirect Syscalls | Userland API hooks (EDR/AV) |
| Draugr Stack Spoofing | Call stack inspection tools |
| AMSI Patch/HWBP | .NET assembly scanning |
| ETW Patching | Event-based monitoring |
| Proxy DLL Loading | LoadLibrary stackframe monitoring |
| Named Pipe Malleable | Pipe monitoring |
| Custom AppDomain | Default AppDomain monitoring |
Memory Protection Changes:
NtProtectVirtualMemorycalls logged viaEtwTiLogReadWriteVm- AMSI patching creates RWβRX transition on
amsi.dll.text section - ETW patching creates RWβRX transition on
ntdll.dll.text section
Detection: Memory protection changes on loaded modules are strong indicators.
Named Pipe Creation:
NtCreateFilewith\\.\pipe\*path visible to minifilter drivers- Pipe-based output redirection creates detectable artifacts
Module Loading:
LdrLoadDllevents logged by EDR kernel drivers- Timer Queue / RegisterWait abuse may trigger behavioral detection
Thread Context Manipulation (HWBP method):
- Hardware breakpoint usage without debugger presence is suspicious
- Hidden console creation (
AllocConsole+ShowWindow(SW_HIDE)) - PEB modification (StandardOutput/StandardError handles changed)
- CLR loaded in beacon process (unusual for native executables)
- Custom AppDomain creation (non-default domains suspicious)
- VEH handler registration without debugger (HWBP method)
Cobalt Strike β Script Manager β Load β BOF_ExecuteAssembly.cna
Menu: Additionals postex β Execute-Assembly Config
BOF_ExecuteAssembly --assembly /tmp/Ghostpack-CompiledBinaries/Rubeus.exe --args help
beacon> help BOF_ExecuteAssembl
With Dockerfile:
sudo docker build -t ubuntu-gcc-13 .
sudo docker run --rm -it -v "$PWD":/work -w /work ubuntu-gcc-13:latest makeOr, if you have nasm, make, and mingw-w64 (compatible with gcc-13) on your system:
makeOutput: Bin/BOF_ExecuteAssembly.o
- anthemtotheego: https://github.com/anthemtotheego/InlineExecute-Assembly/tree/main
- TheWover: https://github.com/TheWover/donut


