惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

V
Visual Studio Blog
Recent Announcements
Recent Announcements
雷峰网
雷峰网
The GitHub Blog
The GitHub Blog
罗磊的独立博客
月光博客
月光博客
J
Java Code Geeks
A
About on SuperTechFans
Microsoft Security Blog
Microsoft Security Blog
D
Docker
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
F
Fortinet All Blogs
U
Unit 42
C
Check Point Blog
Martin Fowler
Martin Fowler
有赞技术团队
有赞技术团队
博客园 - 叶小钗
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
酷 壳 – CoolShell
酷 壳 – CoolShell
Blog — PlanetScale
Blog — PlanetScale
大猫的无限游戏
大猫的无限游戏
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
阮一峰的网络日志
阮一峰的网络日志
MyScale Blog
MyScale Blog

Security Research | Blog

SloppyRAT: A New Tool For Ransomware Attacks | ThreatLabz Microsoft Exchange Vulnerability: What Admins Should Do C2Looper Backdoor Uses GitHub for C2 | ThreatLabz Midnight Blizzard launches CaptiveCrunch | ThreatLabz ChainDrop NPM Worm Analysis | ThreatLabz Abyssos Modular RAT Analysis | ThreatLabz Frontier AI and Enterprise Readiness | Zscaler Ransomware Victims Research | ThreatLabz Technical Analysis of GoGRPC | ThreatLabz Targeted Attack on Middle East Govts (Part 1) | ThreatLabz ClaudeFix: Shared Claude Chats Meet ClickFix | Zscaler Why Do F1 Teams Need Cybersecurity, and What Is AI’s Role? Indirect Prompt Injection Targets AI Agents | ThreatLabz Splunk Enterprise RCE (CVE-2026-20253) | ThreatLabz Edgecution: Malicious Edge Extension Backdoor | ThreatLabz SmartApeSG Supply Chain Attack Targets Okendo | ThreatLabz AI Generated ClickFix Attack Delivers SmartRAT | ThreatLabz What the ThreatLabz 2026 Phishing and Initial Access Report Means for the Public Sector | Zscaler Shai-Hulud: Miasma, Hades, & AI Scanner Evasion | ThreatLabz Zscaler ThreatLabz 2026 Phishing and Initial Access Report Technical Analysis of MLTBackdoor | ThreatLabz When the Scanner Starts Thinking: Learnings from Mythos & GPT 5.5 Cyber in Security Testing | Zscaler OpenClaw Skill Distributes Remcos & GhostLoader | ThreatLabz Tropic Trooper: AdaptixC2 + Custom Beacon | ThreatLabz Do not delete blog (testing) | Zscaler Payouts King Takes Aim at the Ransomware Throne | ThreatLabz The Alibaba Incident and Why Zero Trust Matters More Than Ever In-Memory Loader Drops ScreenConnect | ThreatLabz Supply Chain Attacks Surge in March 2026 | ThreatLabz Claude Code Leak: Critical AI Security Threat 2026
Targeted Attack on Middle East Govts (Part 2) | ThreatLabz
Sudeep Singh, Roy Tay · 2026-08-04 · via Security Research | Blog

Technical Analysis

BINDCLOAK is a 64-bit modular backdoor written in C++ that uses a complex message routing mechanism to manage the C2 communication channel. In the following section, we share a detailed technical analysis of BINDCLOAK and how it implements the C2 communication.

This report is based on a DLL sample with the MD5 hash 7a14a99d70d42d3f7bf72f843185fc07 that exports two malicious functions named curl_easy_escape and mn_dcode. The MIXEDKEY loader (mentioned in Part 1 of this blog series) calls the curl_easy_escape export.

Host identifier generation

BINDCLOAK first generates a unique 4-byte identifier for each victim’s machine using the hostname and the volume serial number as follows.

  • Uses GetComputerNameW to fetch the computer name
  • Uses GetVolumeInformation to get the volume serial number for C:\
  • Adds up the ASCII values of all the wide characters of the computer name and adds this sum to the volume serial number to generate a unique identifier for the host. This 4-byte identifier will be used as an ID in the C2 messages exchanged between the infected machine and the C2 server.

Modules

BINDCLOAK contains two core modules with additional plugin modules delivered from the C2 server as DLLs when the INIT_PLUGIN_MODULE command is issued by the C2 server. 

Each built-in module is configured with two functions:

  • The first function is an initialization function that sets metadata such as the module type and flags.
  • The second function implements the core functionality of the module. This involves processing incoming messages and encoding the results in outgoing messages. BINDCLOAK calls ImpersonateLoggedOnUser to allow this function to execute with elevated privileges when the module is supplied with a higher-privileged token.

Upon creation, a unique ID is derived from the module type to identify each module instance as shown in the table below.

Name

Type

Default ID

C2

0x1010

0x10100000

Command

0x1020

0x10200000

Table 1: Core BINDCLOAK modules and their types.

The C2 module connects to a C2 server via TLS over TCP connections.

C2 communication


Message structure

All incoming and outgoing messages, including the beacon message, begin with a 28-byte header followed by the sizes of two binary blobs and the respective blobs' contents. 

The Flags is a bitfield that indicates the message type (e.g., the flags 0x3001 indicate a control message, which is a special message type used for managing modules to stop or reset state).

The table below summarizes BINDCLOAK’s message structure.

Offset

Size

Field

Description 

*The message type will determine the meaning of the field.

0x00

4

Source

Beacon message:

  •  Host identifier


Module messages: 

  • Module ID

0x04

4

Destination 

Beacon message: 0


Module messages: 

  • Module ID


Messages from C2 

  • server:Target module ID

0x08

4

Flags

Message type bitfield. 
 

  • 0x1000=control message
  • 0x2000=internal (never sent to C2 server) 
  • 0x0001=Message complete
  • 0x0002=Message stream complete

0x0C

4

Command Type

Beacon message: 0


Control message: 

  • 1=stop
  • 2=activate
  • 3=reset 


Command message: 

  • Command parameter 1

0x10

4

Sub-Command

Beacon message: 0


Command message: 

  • Command parameter 2

0x14

4

Command ID

Beacon message: 0


Command message: 

  • Command ID 

0x18

4

Sequence

Beacon message: 0


Command message: 

  • Command parameter 3

0x1C

4

Blob 1 Size

Byte count of Blob 1 data. 

Beacon message size: 0x620

0x20

4

Blob 2 Size

Byte count of Blob 2 data. 

Beacon message: 0
 

Command message: 0

0x24

variable

Blob 1 Data

Primary payload (see beacon message below).

0x24 + blob1_size

variable

Blob 2 Data

Secondary payload. 

Empty for beacon message.

Table 2: BINDCLOAK message structure.

Beacon message

The beacon message is the first message that BINDCLOAK sends to the C2 server to register an infected machine’s host-specific information. This message payload has the following format and a size of 1568 (0x620) bytes and will be sent in the message’s blob1 data field. The structure is shown below. Information gathered from the host machine by BINDCLOAK and the structure of the beacon message sent to the C2 server is the same as the OctLurk backdoor.

Offset

Size

Field

Description

0x000

276 (0x114)

OS Version Information

Operating system version information returned in OSVERSIONINFOEX structure.

0x114

32 (0x020)

Computer Name

Calls GetComputerNameW to fetch the computer name.

0x134

200 (0xC8)

Username

Calls GetUserNameW to fetch the username.

0x1FC

520 (0x208)

Hostname

Calls gethostname to fetch the hostname.

0x404

520 (0x208)

Local IP

Calls GetAddrInfoW to get the local IP and formats it as %u.%u.%u.%u

0x60C

4 (0x004)

Platform Flag

Hardcoded DWORD = 2

0x610

16 (0x010)

Local Time

System time information returned in the SYSTEMTIME structure via GetLocalTime.

Table 3: BINDCLOAK beacon message payload structure.

Message encryption

This C2 message encryption algorithm is the same as the one used by the OctLurk backdoor and it is summarized below.

  • The message is first zlib compressed. The uncompressed data size is added as a 4-byte prefix to the compressed data.
  • A 105-byte rolling XOR key is used to encrypt the previous compressed data + uncompressed size prefix. The XOR key for pass 1 is the value FDrertgr#$%JYRFhgesjr839qyewaf9d8aoidshufscZDGT$#@QEWASGkio865ehyf98foidsjzhug874392dfsREFDfdsAGH43wea98h. This is hardcoded in the sample as a stack string. Although this XOR key is different from the key used in the OctLurk backdoor, there is a high-level of similarity between the keys.
  • A random rolling XOR key of 83 bytes in length is generated using a PRNG for encryption pass 2. The seed for the PRNG is initialized using GetTickCount. This random key is sent in cleartext, which allows the C2 server to decrypt the message.
  • Generates random padding bytes between length 14 and 41.

All of this is assembled together to produce the final encrypted message that is sent over the network. The table below summarizes the structure of the encrypted message.

Offset

Size

Value

Description

0x00

4 (0x04)

DWORD

Total payload size (everything after this field)

0x04

83 (0x53)

Random

Random generated 83-byte XOR key used in XOR pass 2

0x57

4 (0x04)

Encrypted

Compressed message size + 4. Two passes of XOR.

0x5B

4 (0x4)

Encrypted

Uncompressed message size Two passes of XOR.

0x5F

variable

Encrypted

zlib compressed message. Two passes of XOR.

Table 4: Encrypted BINDCLOAK message structure.

C2 response

Upon receiving the beacon message, the C2 server may respond with similarly encrypted messages (e.g., a message containing a C2 command for the BINDCLOAK command module). This will be followed by a message with the 0x2 flag bit set to initiate the routing of the C2 message to the respective modules. These messages are decrypted by BINDCLOAK in the reverse order as described earlier.

Command module

BINDCLOAK supports a total of 11 C2 commands that are described in this section.

Commands

The commands can be grouped as follows:

  • Token commands
    • 0x58320: COLLECT_USER_TOKEN
    • 0x22577: CLEANUP_USER_TOKENS
    • 0x95267: GET_STATUS
  • General module commands
    • 0x65918: START_MODULE_WITH_USER_TOKEN
    • 0x47621: START_MODULE_WITH_PROCESS_TOKEN
    • 0x96324: STOP_MODULE
    • 0x74523: REMOVE_MODULE
  • Plugin module commands
    • 0x86321: INIT_PLUGIN_MODULE 
    • 0x45717: REMOVE_PLUGIN_MODULE
  • Misc commands
    • 0x27844: SET_THREAD_EXECUTION_STATE
    • 0x64570: UNKNOWN
Token commands

This group of commands collect and manage useful user and process tokens that can be used to elevate privileges for modules using the module commands.

The COLLECT_USER_TOKEN (0x58320) command attempts to log in with the provided credentials via LogonUserW and stores the user token handle on successful authentication. The domain, username, and password are sent in the message’s blob1 and the size of blob1 is 712 (0x2C8) bytes. The result for this command contains only the authentication status.

The CLEANUP_USER_TOKENS (0x22577) command clears the list of user token handles collected by the COLLECT_USER_TOKEN command.

The GET_STATUS command returns a result containing BINDCLOAK modules, all user token handles collected via the COLLECT_USER_TOKEN command, and information about running processes. 

BINDCLOAK uses WTSEnumerateProcessesW to collect the process ID, name, and session ID, LookupAccountSidW to collect the process user name and domain, and OpenProcessToken to check whether its token has the following flags: TOKEN_QUERYTOKEN_DUPLICATE, and TOKEN_ASSIGN_PRIMARY. This process info can be used by the threat actor to elevate privileges for specific modules.

General module commands

This set of commands start and stop specific BINDCLOAK modules. Modules need to be stopped before module start commands are issued. The start commands have no effect if the module is currently running.

The START_MODULE_WITH_USER_TOKEN (0x65918) command starts a module with the specified ID with a duplicate of the provided user token handle created using DuplicateTokenEx with TOKEN_ASSIGN_PRIMARY as the TokenType parameter. This command is likely used in conjunction with the user tokens collected with the COLLECT_USER_TOKEN command.

The START_MODULE_WITH_PROCESS_TOKEN (0x47621) command behaves similarly but uses the process token of the provided process ID. This command is likely used in conjunction with the process info collected with the GET_STATUS command.

The STOP_MODULE (0x96324) command stops the module with the specified ID and returns whether it’s still running after 5 seconds.

The REMOVE_MODULE (0x74523) command removes the module only if it is not running. Once removed, a module cannot be restarted and must be reinitialized.

Plugin module commands

The INIT_PLUGIN_MODULE (0x86321) command reflectively loads a plugin module into memory. The plugin module is stored in the first blob of the message. The loader is described in the plugin loader section.

The plugin module does not run after loading; the result contains the module ID of the loaded plugin module so the C2 can send it messages (e.g., the START_MODULE commands to start running).

The REMOVE_PLUGIN_MODULE (0x45717) command stops the plugin modules that match specific metadata flags after waiting for the specified timeout.

Miscellaneous commands

The command (0x64570) copies the command message into a new outgoing message. The intent or purpose of this command is currently unknown.

The SET_THREAD_EXECUTION_STATE (0x27844) command calls the SetThreadExecutionState API with the specified flags, likely to prevent the infected machine from entering sleep mode.

Plugin loader

A plugin module is expected to be a DLL with the exports ins_ctl_db (for the initialization function) and oct_lk_col (main function).

The DLL size is stored as a DWORD at offset 0x8 (overwriting the e_cparhdr and e_minalloc fields of the DOS header). As the PE header offset at e_lfanew field in the DOS header and the SizeOfOptionalHeader field in the file header are accessed directly via their offsets (offsets 0x3C and  0x11C respectively), it’s possible that some of the fields in the DOS header and/or PE headers have been modified or zeroed to hinder static detection.

Memory for the plugin is allocated via VirtualAlloc with PAGE_EXECUTE_READWRITE (RWX) permissions and reflective loading used to load the plugin DLL into the allocated memory. When resolving imports, each DLL is loaded via RtlQueueWorkItem with LoadLibraryW and the DLL name as arguments to evade EDRs since LoadLibraryW calls from unbacked executable memory regions are considered highly suspicious by EDRs.

The plugin loader then calls the DLL entrypoint function and returns. If the entrypoint function returns FALSE, the allocated memory for the plugin for is zeroed and freed.