Reverse Engineering Techniques • Windows

Debugging Malware: Manually Extracting a Hidden Cobalt Strike Beacon

Debug a high-entropy 64-bit loader with x64dbg, intercepting VirtualAlloc allocations to manually extract and dump an embedded Cobalt Strike beacon.

This analysis documents the journey of deconstructing a high-entropy 64-bit executable. By leveraging Detect It Easy (DIE) for initial triage and monitoring critical Windows API calls like VirtualAlloc, we transition from a suspicious, obfuscated loader to the successful extraction of a hidden payload. The result is the recovery of a fully functional Cobalt Strike Beacon (beacon.dll), providing the essential technical data needed to map Command & Control (C2) infrastructure and understand the attacker’s true intent.

Sample Metadata

DIE Analysis

Screenshot 2026-03-24 at 8.05.19 AM.png
Figure: Screenshot 2026-03-24 at 8.05.19 AM.png Click to zoom ↗

DIE Entropy Analysis

OffsetSizeEntropyStatusName
0x000000000x000004002.42309Not PackedPE Header
0x000004000x00007A006.30426Not PackedSection(0) [.text]
0x00007E000x000544007.13961PackedSection(1) [.data]
0x0005C2000x000010004.39691Not PackedSection(2) [.rdata]
0x0005D2000x000006003.82614Not PackedSection(3) [.pdata]
0x0005D8000x000006003.66488Not PackedSection(4) [.xdata]
0x0005DE000x00000A004.16599Not PackedSection(6) [.idata]
0x0005E8000x000002000.15409Not PackedSection(7) [.CRT]
0x0005EA000x000002000.00282Not PackedSection(8) [.tls]
0x0005EC000x000004003.33387Not PackedSection(9) [.rsrc]
0x0005F0000x000002001.60252Not PackedSection(10) [.reloc]

Description:

The DIE Entropy Analysis provides a mathematical "fingerprint" of the file's data randomness. In malware analysis, this is the quickest way to identify hidden layers.

▪The Packed Indicator: The .data section's high entropy of 7.139 is a "smoking gun." Standard data rarely exceeds 5.0; this high score confirms the section contains compressed or encrypted malicious code.
Screenshot 2026-03-24 at 8.27.22 AM.png
Figure: Screenshot 2026-03-24 at 8.27.22 AM.png Click to zoom ↗

When you see obfuscated data. It usually means data will be decoded during execution time.

Basic Properties

PE Section

SectionNameEntropyFile RatioRaw Address (Begin)Raw SizeVirtual Address (Begin)Virtual Size
section[0].text6.3048.02%0x0000040031,232 B0x0000100031,224 B
section[1].data7.14088.57%0x00007E00345,088 B0x00009000344,848 B
section[2].rdata7.1401.05%0x0005C2004,096 B0x0005E0003,712 B
section[3].pdata4.3970.39%0x00007E001,536 B0x0005F0001,248 B
section[4].xdata3.8250.39%0x0005C2001,536 B0x000600001,172 B
section[5].bss3.664n/a0x0005D2000 B0x000610003,136 B
section[6].idatan/a0.66%0x0005D8002,560 B0x000620002,392 B
section[7].CRT4.1650.13%0x00000000512 B0x0006300080 B
section[8].tls0.1510.13%0x0005DE00512 B0x0006400016 B
section[9].rsrc0.0000.26%0x0005E8001,024 B0x000650001,000 B
section[10].reloc3.3320.13%0x0005EA00512 B0x00009000132 B

Imports

LibraryImported FunctionPotential Malware Behavior
KERNEL32.dllCloseHandleGeneric resource management.
KERNEL32.dllConnectNamedPipeInter-Process Communication (IPC); often used for Command & Control (C2) or lateral movement.
KERNEL32.dllConvertThreadToFiberAnti-Analysis/Evasion; Fibers are a stealthy way to manage execution flow that some debuggers struggle to track.
KERNEL32.dllCreateFiberUsed in conjunction with ConvertThreadToFiber for manual scheduling.
KERNEL32.dllCreateFileAFile system manipulation (dropping payloads or reading configs).
KERNEL32.dllCreateNamedPipeASetting up communication channels for data exfiltration or internal tasking.
KERNEL32.dllCreateThreadSpawning new execution paths (e.g., a background keylogger or downloader).
KERNEL32.dllDeleteCriticalSectionThread synchronization cleanup.
KERNEL32.dllDeleteFiberFiber cleanup.
KERNEL32.dllEnterCriticalSectionManaging thread safety.
msvcrt.dll___lc_codepage_funcStandard C runtime initialization.
msvcrt.dll___mb_cur_max_funcStandard C runtime (character handling).
msvcrt.dll__C_specific_handlerException handling (often used in 64-bit binaries).
msvcrt.dll__getmainargsRetrieving command-line arguments.
msvcrt.dll__initenvSetting up environment variables.
msvcrt.dll__iob_funcStandard I/O stream handling.
msvcrt.dll__set_app_typeDefines if the app is a GUI or Console app.
msvcrt.dll_amsg_exitStandard error handling/exit routine.

Debugging

X64DBG

Screenshot 2026-03-24 at 8.33.10 AM.png
Figure: Screenshot 2026-03-24 at 8.33.10 AM.png Click to zoom ↗

we will be look out for RAX register. This register often holds the return value of a function.

When malware deobfuscates data inn runtime, it usually needs somewhere to put that decoded content. That often means Allocating memory.

On windows there are many ways to do this, but very common Windows API for memory allocation is called VirtualAlloc.

Screenshot 2026-03-24 at 8.43.25 AM.png
Figure: Screenshot 2026-03-24 at 8.43.25 AM.png Click to zoom ↗

Return value

Screenshot 2026-03-24 at 8.44.30 AM.png
Figure: Screenshot 2026-03-24 at 8.44.30 AM.png Click to zoom ↗

Breakpoint

At VirtualAlloc

Screenshot 2026-03-24 at 8.46.58 AM.png
Figure: Screenshot 2026-03-24 at 8.46.58 AM.png Click to zoom ↗

Let’s run the program.

VirtualAlloc hit

Screenshot 2026-03-24 at 8.48.22 AM.png
Figure: Screenshot 2026-03-24 at 8.48.22 AM.png Click to zoom ↗

Where we are paused, we’ll see refrences to Virtualalloc, which is located within kernel32.dll

VirtualAlloc arguments

Arguments being passed to VirtualAlloc.

Screenshot 2026-03-24 at 8.52.17 AM.png
Figure: Screenshot 2026-03-24 at 8.52.17 AM.png Click to zoom ↗
C
1: rcx 0000000000000000 0000000000000000
2: rdx 0000000000058000 0000000000058000
3: r8 0000000000003000 0000000000003000
4: r9 0000000000000040 0000000000000040
5: [rsp+28] 00007FFFE66BA370 kernel32.00007FFFE66BA370

In msdn refrence the forth argument is flProtect

C
LPVOID VirtualAlloc(
  [in, optional] LPVOID lpAddress,
  [in]           SIZE_T dwSize,
  [in]           DWORD  flAllocationType,
  [in]           DWORD  flProtect
);
Screenshot 2026-03-24 at 8.55.34 AM.png
Figure: Screenshot 2026-03-24 at 8.55.34 AM.png Click to zoom ↗

Memory protection constants.

Screenshot 2026-03-24 at 8.56.00 AM.png
Figure: Screenshot 2026-03-24 at 8.56.00 AM.png Click to zoom ↗

Value hex 40 corresponds with the value in the debugger. Which is PAGE_EXECUTE_READWRITE

Argument Breakdown

ArgumentRegister/StackParameterValueDescription
1st ArgRCXlpAddress0NULL: The OS chooses the memory location.
2nd ArgRDXdwSize0x58000Size: Allocating 360,448 bytes (~352 KB).
3rd ArgR8flAllocationType0x3000Commit/Reserve: Prepares the memory for use.
4th ArgR9flProtect0x40RWX: Read, Write, and Execute permissions.

Return Value of VirtualAlloc

Why the Return Value Matters

Once the call to VirtualAlloc executes, the CPU stores the Return Value in the RAX register. This value is the base memory address (the starting point) of the newly allocated region.

▪The Destination: This is the specific memory coordinates where the malware is about to "unpack" its hidden code.
▪The Trap: Without this address, you are searching through millions of lines of memory. With it, you know exactly where to set your "tripwire" (breakpoint) to catch the malware in the act.

TIP: if RAX is 0, the function failed (likely due to an "Anti-Debugging" check), and the malware will likely terminate or crash.

Now Execute the program till return

Screenshot 2026-03-24 at 9.07.10 AM.png
Figure: Screenshot 2026-03-24 at 9.07.10 AM.png Click to zoom ↗

Now we are paused at return at return instruction. Which is commonly the last instruction at the end of a function.

Screenshot 2026-03-24 at 9.12.34 AM.png
Figure: Screenshot 2026-03-24 at 9.12.34 AM.png Click to zoom ↗

If you look RAX , we can see it’s red because it’s recently changed.

Screenshot 2026-03-24 at 9.09.40 AM.png
Figure: Screenshot 2026-03-24 at 9.09.40 AM.png Click to zoom ↗
C
RAX : 0000000000C60000
RBX : 0000000000B78954
RCX : 00007FFFE808D364     ntdll.00007FFFE808D364
RDX : 0000000000000000
RBP : 000000000122FF20
RSP : 000000000122FDB8
RSI : 0000000000000000
RDI : 000000000122FEE8
R8  : 000000000122FD78
R9  : 000000000122FF20
R10 : 0000000000000000
RegisterValueRole in Your Article
RAX0000000000C60000The Return Value. This is the specific start address of the 352 KB buffer the malware just allocated.
RSP000000000122FDB8The current Stack Pointer.
RBX0000000000B78954Often used by the unpacking stub to store a pointer to the encrypted data source.

Dumping

right click —> follow in dump.

Screenshot 2026-03-24 at 9.15.50 AM.png
Figure: Screenshot 2026-03-24 at 9.15.50 AM.png Click to zoom ↗

Dump Window

At this point there’s nothing interesting, By default VirtualAlloc return zeroed out memory.

Screenshot 2026-03-24 at 9.16.44 AM.png
Figure: Screenshot 2026-03-24 at 9.16.44 AM.png Click to zoom ↗

SET Hardware Breakpoint

A hardware breakpoint is more persistence than the breakpoint we set earlier in VirtualAlloc.

right click on the first byte then set hardware breakpoint. This will tell the debugger to pause whenever this byte in this memory region is accessed, wether it’s being read from or written to.

Screenshot 2026-03-24 at 9.21.10 AM.png
Figure: Screenshot 2026-03-24 at 9.21.10 AM.png Click to zoom ↗

This should allow us to catch the exact moment that this memory starts being used.

Resume execution

Screenshot 2026-03-24 at 9.25.36 AM.png
Figure: Screenshot 2026-03-24 at 9.25.36 AM.png Click to zoom ↗
Screenshot 2026-03-24 at 9.26.21 AM.png
Figure: Screenshot 2026-03-24 at 9.26.21 AM.png Click to zoom ↗

We can see at the bottom Hardware breakpoint

At first nothing has changed. Still seeing zero’s in dump.

But We do see mutiple refrence to the character PE . These are the literal characters that appears in the header of windows executable.

Screenshot 2026-03-24 at 9.28.24 AM.png
Figure: Screenshot 2026-03-24 at 9.28.24 AM.png Click to zoom ↗

Memory inspection

Let’s inspect the memory region that contains the character PE.

right click —> follow in dump —> choose value: [rsp+30]

Screenshot 2026-03-24 at 9.33.37 AM.png
Figure: Screenshot 2026-03-24 at 9.33.37 AM.png Click to zoom ↗

Now in the dump window we can see 50 45 which corresponds to the characters PE.

Screenshot 2026-03-24 at 9.35.53 AM.png
Figure: Screenshot 2026-03-24 at 9.35.53 AM.png Click to zoom ↗

Scroll a little up. We can see the ascii text DOS message which typically appears in the beginning of the windows executable.

Screenshot 2026-03-24 at 9.37.48 AM.png
Figure: Screenshot 2026-03-24 at 9.37.48 AM.png Click to zoom ↗

Continue scroll up we got the MZ bytes. Which typically the starting bytes of a windows executable.

Screenshot 2026-03-24 at 9.39.25 AM.png
Figure: Screenshot 2026-03-24 at 9.39.25 AM.png Click to zoom ↗

SO this is a strong indication that we find a windows.exe in memory.

DUMP

right click anywhere in the memory dump —> follow in Memory Map.

Screenshot 2026-03-24 at 9.42.37 AM.png
Figure: Screenshot 2026-03-24 at 9.42.37 AM.png Click to zoom ↗

Memory Map

Screenshot 2026-03-24 at 9.44.35 AM.png
Figure: Screenshot 2026-03-24 at 9.44.35 AM.png Click to zoom ↗

right click on the highlighted row —> Dump Memory to File.

Screenshot 2026-03-24 at 9.45.12 AM.png
Figure: Screenshot 2026-03-24 at 9.45.12 AM.png Click to zoom ↗

Save it

Screenshot 2026-03-24 at 9.46.12 AM.png
Figure: Screenshot 2026-03-24 at 9.46.12 AM.png Click to zoom ↗

Now let’s take a look of the dump file. open it in Hxd

Screenshot 2026-03-24 at 9.51.12 AM.png
Figure: Screenshot 2026-03-24 at 9.51.12 AM.png Click to zoom ↗

TO clean this up. Select extra bytes and delete, Then save it.

Screenshot 2026-03-24 at 9.55.21 AM.png
Figure: Screenshot 2026-03-24 at 9.55.21 AM.png Click to zoom ↗

Analyse the dump file in PE Studio

Screenshot 2026-03-24 at 10.07.35 AM.png
Figure: Screenshot 2026-03-24 at 10.07.35 AM.png Click to zoom ↗

Extracted payload analysis

Description

This extracted payload is the "unmasked" malicious core of the sample. The most significant discovery is the original export name: beacon.dll. This strongly suggests you are looking at a Cobalt Strike Beacon, a highly sophisticated modular tool used by both red teams and advanced threat actors for command-and-control (C2) and post-exploitation.

The "MZ" header and the transition to a 64-bit DLL confirm that the unpacking process was successful, providing you with a clean file for deeper static analysis.

Copied