Malware analysis

SleepWalker: Passive Tasking and a 23-Command Interpreter

Overview

SleepWalker is a Windows x64 backdoor built around passive task reception rather than a conventional outbound beacon. Its embedded bootstrap watches raw IPv4 traffic for authenticated tasking and routes accepted bytecode into a 23-command interpreter spanning scheduling, staged execution, files, sockets, ICMP, and named pipes. The interpreter also implements a DNS-encoded carrier that later tasking can enable.

Analyzed sample

R136a1 published SLEEPWALKER: A Passive Backdoor With Its Own Command Language on August 24, 2026. Proofmetry independently examined one variant and traced its startup, task authentication, shared interpreter, transport abstractions, and command-driven host effects.

FieldValue
SHA-256d347170752a28e2b8c4b8b9f3cab2e3a6541ba11682c94498d26eb9002779d60
File typeWindows x64 DLL
Required host nameERAAgent.exe
Command count23

Host activation and proxy behavior

SleepWalker does not enter its backdoor worker unconditionally. On process attach, it reconstructs the UTF-16 basename ERAAgent.exe and compares it with the current executable name. Only an exact match starts the detached worker. The startup logic closes the new thread handle immediately and has no duplicate-worker guard.

A separate proxy path resolves one of seven forwarded exports from dpapisvc.dll. If the dependency cannot be loaded, the selected export is invalid, or resolution fails, the DLL terminates the host process. The proxy role and the process-name test are therefore part of the implant's activation design, not incidental loader behavior.

The worker allocates a 128 KiB process-wide staging area, initializes Winsock, recovers the embedded task, and enters the interpreter. Process detach sets a shared stop flag consulted by the interpreter, sleep helpers, schedulers, and long-running receive operations.

A passive opening move

The embedded bootstrap does not identify an initial remote C2 endpoint. Its active instruction places the sample into passive raw-packet capture across eligible local IPv4 interfaces. Subsequent endpoints, files, pipe names, delays, and nested work arrive as authenticated operands rather than fixed bootstrap values.

Incoming traffic is filtered before it reaches the task decoder. Structurally valid candidates must then pass authenticated decryption; only accepted plaintext is handed to the shared interpreter. A second receive mode extracts a compact authenticated task from specially formed DNS queries and feeds it into the same dispatch path.

SleepWalker task-delivery architecture showing passive capture, authenticated decoding, and the shared command dispatcher
Figure 1. SleepWalker task-delivery architecture from passive capture through authenticated decoding and the shared dispatcher. Open full size

The passive start is the sample's defining operational difference. Activity begins with an inbound packet rather than a process-originated connection, and consequential endpoint behavior appears only after that packet is accepted. Detection logic that looks only for an outbound beacon can miss the start of this chain.

Authentication and transport architecture

SleepWalker uses AES-CCM to authenticate inbound tasks. Its general transport paths use one envelope form, while the DNS carrier uses a more compact form suited to query-name transport. Both converge on the same rule: unauthenticated bytes are discarded before command interpretation.

The receive side spans TCP clients and listeners, UDP, named-pipe clients and servers, file-backed tasks, passive raw packets, and DNS-carried tasks. Selected socket handlers can also use VMware VMCI after querying \\.\VMCI for the provider's address family.

Outbound commands are intentionally separate from the authenticated input layer. TCP, UDP, ICMP, and named-pipe send handlers pass the task-supplied buffer to their respective transport without adding task-channel protection. For network monitoring, that means the data emitted after a valid task may be plainly recognizable even though the inbound control material was authenticated and encrypted.

The 23-command language

The compact interpreter covers lifecycle control, delays, schedules, nested programs, staged data, file-backed tasks, and several local and network communication modes.

Lifecycle and timing

EXIT, SPAWN_THREAD_SCRIPT, SLEEP_SECONDS, SLEEP_RANDOM_SECONDS, CRON_SCHEDULE, REPEAT_N, and LOOP_FOREVER.

Staging and execution

DECOMPRESS_RUN, STAGE_WRITE, STAGE_VERIFY_EXEC, RUN_FILE_SCRIPT, and RUN_SHELLCODE.

Outbound transport

TCP_SEND, UDP_SEND, ICMP_SEND, and PIPE_SEND.

Authenticated receive

TCP_CONNECT_RECV, TCP_LISTEN_RECV, UDP_BIND_RECV, PIPE_CLIENT_RECV, and PIPE_SERVER_RECV.

Passive reception

SNIFF_MAGIC_PACKET and SNIFF_MAGIC_PACKET_DNS watch for authenticated task carriers without an initial outbound beacon.

Because every route returns to the same interpreter, a passive trigger can lead to any behavior implemented by the command language.

Timing, scheduling, and nested execution

Detached child programs run on separate threads. Fixed and random delays, schedules, bounded repeats, infinite loops, and EXIT all share the process-wide stop state, allowing the stop command to unwind long-running work without terminating the host process. The random-delay branch applies modulo using the supplied upper bound without rejecting zero.

Staging, decompression, and native execution

SleepWalker maintains one 128 KiB staging allocation for incremental task assembly. Its staged-execution branch requires SHA-256 verification and clears the complete shared staging area after processing.

The command set can also expand LZMA-compressed bytecode and load an authenticated task from disk.

RUN_SHELLCODE treats its operand as native code: it allocates writable memory, copies the buffer, changes the region to executable-read, invokes it synchronously, and releases the allocation after control returns.

Network, named-pipe, and file behavior

The TCP and UDP command families support both sending data and receiving additional authenticated tasks. TCP can initiate a connection or bind a listener, while the ICMP branch places supplied content into echo requests.

Named pipes mirror the same send-and-receive split. The optional server-security branch changes the pipe ACL and related registry settings. Teardown restores the saved LSA value but removes the selected NullSessionPipes entry, including one that already existed.

Command walkthrough

Each walkthrough follows a decrypted interpreter record from handler parsing to its native effect. Exact carrier-construction instructions and authentication material are intentionally omitted.

Across the receive modes, SleepWalker validates the carrier, authenticates its encrypted contents, recovers a command record, and passes that record to the shared interpreter. The DNS path uses a compact carrier suited to query-label transport.

Layered SleepWalker command flow showing decoded records, authenticated envelopes, direct receive paths, passive framing, and DNS label transport.
Figure 2. SleepWalker command records share one interpreter. Direct receive paths use the normal authenticated envelope; passive raw frames carry that envelope; DNS labels carry a compact form. Open full size

Lifecycle and timing

0x06 · EXIT

The dispatcher sets the process-wide stop flag to one. Interpreter iterations, schedulers, receive loops, and interruptible sleeps consult that value, allowing the active worker to unwind while the host process remains running.

0x0B · SPAWN_THREAD_SCRIPT

The handler moves an owned nested program into a detached worker thread. That worker re-enters the common interpreter, securely clears the program bytes after execution, and frees the descriptor while the parent continues independently.

0x0C · SLEEP_SECONDS

The command reads a 16-bit interval and calls the interruptible sleep helper. Long waits are divided into chunks of at most 60 seconds so the helper can recheck the shared stop state between calls to Sleep.

0x0D · SLEEP_RANDOM_SECONDS

The random-delay helper obtains four random bytes, reduces the value modulo the supplied 16-bit upper bound, and passes the remainder to the interruptible sleeper. The parser accepts zero, leaving a divide-by-zero condition in the modulo operation.

0x0E · CRON_SCHEDULE

The scheduler compares minute, hour, day-of-month, and weekday masks with UTC. It masks the owned child program while waiting, restores it for a matching minute, interprets it, and masks it again; duplicate suppression is based only on the last minute-of-hour.

0x0F · REPEAT_N

The repeat helper runs an owned nested program up to the parsed 16-bit count and tests the shared stop flag between iterations. A count of zero is a no-op; each nonzero iteration enters the same bounded interpreter used for top-level tasks.

0x10 · LOOP_FOREVER

The loop helper repeatedly re-enters one owned nested program until the process-wide stop flag changes. It checks that flag before every iteration and retains the same program descriptor for the loop's lifetime.

Decompression, transport, and staging

0x1F · DECOMPRESS_RUN

The handler parses a declared output size, five raw-LZMA property bytes, and a compressed blob. It allocates the declared buffer, records the decoder's actual output length, and sends the recovered bytes back to the SleepWalker interpreter; the decompressed content is bytecode, not native code.

0x29 · TCP_SEND

The stream sender parses local and remote host/service pairs, an arbitrary blob, and a deadline. It optionally binds the local tuple, connects to the remote endpoint, and sends the original buffer without AES-CCM wrapping. A vm: destination selects VMware VMCI; ordinary host and service pairs use IPv4/TCP.

0x2A · UDP_SEND

The datagram sender uses the same endpoint grammar as TCP_SEND, optionally binds the local tuple, and transmits the command-owned blob in one datagram without task-envelope protection. A vm: destination selects VMware VMCI; ordinary destinations use IPv4/UDP.

0x2B · ICMP_SEND

The handler resolves the destination as IPv4 and calls IcmpSendEcho with the supplied blob. The parsed source string is never used, the parsed deadline does not reach the handler, the API timeout is fixed at one millisecond, and the request length is truncated to 16 bits.

0x2C · PIPE_SEND

The pipe sender parses server and pipe names, optional username and password strings, a blob, and a deadline. It opens the selected named-pipe client and writes the supplied bytes unchanged.

0x32 · STAGE_WRITE

The inline branch parses a 32-bit offset and a blob, rejects offsets outside the 128 KiB shared stage, checks the computed end for overflow and capacity, and copies only an accepted range. The temporary command buffer is freed on both success and failure paths.

0x33 · STAGE_VERIFY_EXEC

The branch hashes the selected staging prefix with SHA-256 and requires the supplied digest blob to be exactly 32 bytes. A match copies the verified prefix into an owned program before interpretation; both match and mismatch paths clear the complete 128 KiB staging region.

0x65 · RUN_SHELLCODE

The native-code handler allocates read/write memory, copies the supplied blob, changes the region to execute/read with VirtualProtect, calls it synchronously, and releases the allocation after control returns. It does not request a writable and executable page at the same time.

0x66 · RUN_FILE_SCRIPT

The file-backed handler reads the complete named file into owned memory and passes it to the normal authenticated-task sink. The file must contain a normal AES-CCM envelope rather than plaintext bytecode; after processing, the handler clears the owned bytes but does not delete or rewrite the source file.

Authenticated receive paths

0x6F · TCP_CONNECT_RECV

The connect-style receiver parses local and remote endpoint pairs plus a deadline, optionally binds the local tuple, opens the selected stream, and accumulates at most 1 MiB. The complete stream must authenticate as one normal AES-CCM envelope before its plaintext reaches the interpreter. A vm: remote host selects VMware VMCI; ordinary remote endpoints use IPv4/TCP.

0x70 · TCP_LISTEN_RECV

The listener parses a bind endpoint and deadline, accepts one connection with backlog one, and receives a stream capped at 1 MiB. The accumulated bytes enter the normal authenticated-task sink only after the listening transport is replaced by the accepted connection. A vm: bind host selects VMware VMCI; ordinary bind addresses use IPv4/TCP.

0x73 · UDP_BIND_RECV

The datagram receiver binds the supplied endpoint and performs one receive into a 1,500-byte buffer. It does not assemble fragments across application datagrams: the single received datagram must contain a complete normal AES-CCM envelope before dispatch.

0x7D · PIPE_CLIENT_RECV

The pipe client parses server and pipe names, optional credentials, and a deadline, then reads through a pipe transport into an owned buffer capped at 1 MiB. Wildcard credentials suppress the explicit credentialed WNetAddConnection2W step, but the client still connects to the named pipe. The accumulated bytes must authenticate as one normal task envelope before interpretation.

0x7E · PIPE_SERVER_RECV

The server creates one named-pipe instance, accepts one local client, and reads at most 1 MiB for normal-envelope authentication. The optional = security value changes the pipe ACL and related anonymous-access registry settings; an empty value retains the default local security path. Teardown restores the saved LSA value but removes the pipe from NullSessionPipes after either a successful add or an already-present result.

Passive receive modes

0x87 · SNIFF_MAGIC_PACKET

The passive listener expands the interface selector into eligible local IPv4 capture contexts and enables broad raw reception. A candidate frame must satisfy the recovered-length relation, header relation, bounded prefix, CRC-32, and process-wide three-second acceptance guard before its normal AES-CCM envelope is authenticated.

0x88 · SNIFF_MAGIC_PACKET_DNS

This mode retains the normal raw-frame path and additionally inspects eligible port-53 queries. It accepts a one-question message with no resource records, verifies the checksum markers around each carrier label, decodes the lowercase Base32 interiors, concatenates them within a 256-byte bound, and authenticates the result as a compact DNS envelope.

Detection opportunities

No single API call uniquely identifies SleepWalker. The strongest detections correlate the activation context, passive network access, interpreter-driven follow-on behavior, and short-lived memory or registry changes.

  • Host and proxy sequence: a DLL running under an executable named ERAAgent.exe, resolving forwarded exports from dpapisvc.dll, and ending the host when that resolution fails.
  • Raw capture behavior: raw IPv4 sockets placed into broad receive mode with SIO_RCVALL across local interfaces.
  • Passive-to-active transition: unusual packet or DNS activity subsequently followed by file, memory, socket, ICMP, or named-pipe operations from the same process.
  • VMware communication: access to \\.\VMCI before socket-style activity.
  • Staging lifecycle: a 128 KiB allocation followed by content placement, SHA-256 verification, interpreter re-entry, and complete clearing.
  • Native execution pattern: writable memory changing to executable-read immediately before an indirect call.
  • Named-pipe policy changes: a new null-session pipe entry or a change to anonymous-user inclusion near pipe-server activity.
  • Control and output split: direct TCP, UDP, ICMP, or pipe content appearing after authenticated inbound tasking but without the same task-channel wrapping.

Sequence is the useful discriminator. Raw socket access, scheduled execution, hashing, named pipes, or an executable memory transition can each appear in legitimate software. Their ordering around the exact host gate and a passive activation event is much more specific.

Indicators and hunting pivots

IndicatorTypeContext
d347170752a28e2b8c4b8b9f3cab2e3a6541ba11682c94498d26eb9002779d60SHA-256Analyzed DLL
ERAAgent.exeProcess nameExact host gate for this build
dpapisvc.dllModule nameProxy dependency and forwarded-export resolution
\\.\VMCIDevice pathVMware transport discovery
SIO_RCVALLSocket controlBroad raw IPv4 packet reception
NullSessionPipesRegistry valueOptional named-pipe configuration
everyoneincludesanonymousRegistry valueOptional anonymous-access policy change

The names above are strongest when combined with the behavioral sequence described in the detection section. Several refer to legitimate Windows, ESET, or VMware components and are weak indicators on their own.

Conclusion

SleepWalker combines an unusually quiet opening move with a broad, internally consistent command language. Its bootstrap waits on passive network input, while authenticated child tasks can introduce schedules, staged programs, files, sockets, ICMP, named pipes, and VMware-oriented communication. The same interpreter underpins each route.

The receive and send sides should not be treated as one protocol. Inbound task bytes cross a shared authentication boundary before dispatch; outbound commands can transmit supplied content directly. That separation creates useful detection opportunities when passive network activity can be correlated with the native endpoint and network behavior that follows.

Proofmetry Platform

Proofmetry Platform includes a variant-specific SleepWalker workflow that reconstructs the tasking expected by this analyzed build. The workflow provides a predefined test for each of its 23 opcodes. The original malware executes the selected behavior inside a customer-controlled lab, while the customer's existing sensors capture the resulting endpoint and network activity.

Get a demo