Steps Taken:
-
Reviewed entrypoint start (0x401380) and noted immediate stack setup plus helper invocations; recognized RC4/XOR helpers (fill_buffer, rc4_init_state, xor_dword_table) driving string decryption.
- Traced module discovery via find_module_entry/get_module_base_address; confirmed ntdll.dll name emerges after RC4 at start:0x40146f using key from xor_dword_table.
- Observed manual export resolution through resolve_export_by_name (0x402450) and unicode compare helpers, with first API decrypted as NtQueryVirtualMemory (start:0x4014a1 ➜ start:0x40156e).
- Confirmed NtQueryVirtualMemory invoked at start:0x4015bf (call [ebp-0x20]) against code address 0x4015be; results stored in local MEMORY_BASIC_INFORMATION, flag 0x40 used to gate execution (anti-hook check).
- Logged secondary RC4 cycle at start:0x4015e0 resolving another export pointer saved to [ebp-0x60], later referenced while staging payload protection changes.
- Inspected decrypt_payload_stage (0x401C10) and noted embedded stub materialized via load_embedded_stub, repeated RC4 decrypts, PRNG usage (prng_next, prng_pick_byte) and eventual memory writes preparing runnable payload.
- Cataloged supporting primitives (read_shared_tick_count, compare_unicode_ascii, copy_ascii_to_wide) for timing noise and string conversion.
- Verified absence of imported APIs and reliance on PEB traversal, highlighting stealth intent.
Function Mapping Table
- start | start | 0x401380 | Orchestrator: decrypts strings, resolves APIs, launches stage.
- sub_401000 | zero_buffer | 0x401000 | Wrapper around memset(0) for stack buffers.
- sub_4010A0 | xor_neighbor_decode | 0x4010A0 | Byte-wise XOR decoder used on late-stage payload data.
- sub_401180 | sub_401180 | 0x401180 | Emits keyed blocks for RC4/XOR pipelines (string/key material).
- sub_401AF0 | xor_dword_table | 0x401AF0 | XORs five dwords with supplied constant (key whitening).
- sub_401C10 | decrypt_payload_stage | 0x401C10 | Multi-stage decryptor/loader preparing in-memory payload.
- sub_402310 | ascii_case_compare | 0x402310 | Case-insensitive compare feeding export lookup.
- sub_402450 | resolve_export_by_name | 0x402450 | Walks PE export directory to locate target APIs.
- sub_402680 | get_module_base_address | 0x402680 | Fetches module base from LDR entry.
- sub_402720 | find_module_entry | 0x402720 | Traverses PEB loader lists to match module name.
- sub_4028C0 | load_embedded_stub | 0x4028C0 | Copies encoded blob that becomes executable stub after XOR.
- sub_402950 | NtCurrentTeb helper | 0x402950 | Retrieves PEB via TEB for module enumeration.
- sub_402A90 | rc4_init_state | 0x402A90 | Initializes RC4 S-box and decrypts buffer.
- sub_402C10 | rc4_process_byte | 0x402C10 | RC4 PRGA step per byte.
- sub_402CF0 | rc4_crypt_buffer | 0x402CF0 | Applies RC4 keystream across buffer.
- sub_402DA0 | compare_unicode_ascii | 0x402DA0 | Unicode-to-ASCII compare used in export match.
- sub_402DD0 | copy_ascii_to_wide | 0x402DD0 | Builds Unicode strings from ASCII ciphertext output.
- sub_402E50 | fill_buffer | 0x402E50 | memset helper.
- sub_402E80 | read_shared_tick_count | 0x402E80 | Reads shared user data tick counter (timing noise).
- sub_402EC0 | prng_next | 0x402EC0 | Custom LFSR-style PRNG step.
- sub_402FC0 | prng_pick_byte | 0x402FC0 | PRNG-driven byte selection within range.
Behavioral Analysis
- Capabilities: Self-decrypting loader that (1) uncovers required DLL/APIs at runtime, (2) validates memory protections around its own code, and (3) decrypts/installs an in-memory payload while manipulating page access.
- Implementation:
- RC4 + XOR pipelines at start:0x40146f and start:0x4015e0 decrypt ntdll.dll, NtQueryVirtualMemory, and subsequent API names entirely in memory, using sub_401180 material and xor_dword_table whitening.
- resolve_export_by_name (0x402450) manually walks PE exports via NtCurrentTeb→PEB traversal instead of imports, keeping IAT clean.
- NtQueryVirtualMemory invoked at start:0x4015bf captures MEMORY_BASIC_INFORMATION for 0x4015be and checks Protect & PAGE_EXECUTE_READWRITE, a classic anti-patch/anti-breakpoint gate.
- Pointer saved at [ebp-0x60] after second resolution (start:0x401649) is subsequently used with page size arguments inside decrypt_payload_stage to change target memory protection before writing executable stub—pattern aligns with NtProtectVirtualMemory.
- decrypt_payload_stage (0x401C10) builds larger buffers, seeds RC4 multiple times, and leverages load_embedded_stub plus PRNG outputs to reconstruct executable content, culminating in memory writes guarded by API pointers resolved earlier.
- Execution Flow: Entry clears workspace, decodes module/API strings, resolves NtQueryVirtualMemory, validates code page, derives further APIs (incl. protection changer), and transitions into decrypt_payload_stage which decrypts and activates embedded stub—payload ready post memory-protection adjustment and stub execution.
Evidence Summary
- start:0x40146f – RC4 decrypt yields ASCII "ntdll.dll", demonstrating encrypted string store.
- start:0x4014a1 ➜ start:0x40156e – resolve_export_by_name called with decrypted "NtQueryVirtualMemory".
- start:0x4015bf – Call [ebp-0x20] invokes resolved NtQueryVirtualMemory(-1, 0x4015be, ...), populating local MEMORY_BASIC_INFORMATION.
- start:0x4015d7 – Conditional on MEMORY_BASIC_INFORMATION.Protect & 0x40, acting as integrity/anti-tamper gate.
- start:0x4015e0..0x401649 – Second RC4 round resolving another API, pointer stored at [ebp-0x60] later consumed inside decrypt_payload_stage for memory protection changes.
- decrypt_payload_stage:0x401e9e – load_embedded_stub + XOR (0x1B) produce executable stub bytes (55 8B EC …), confirming payload reconstruction.
- decrypt_payload_stage:0x4020xx (multiple) – RC4 decrypts and PRNG-driven writes populate large buffer prior to execution.
Verdict Malicious. The sample employs layered RC4/XOR string concealment, PEB-based export resolution, anti-hook memory checks, and staged payload decryption with planned memory-protection modification—clear traits of a loader preparing in-memory execution of concealed code.