
Rust बाइनरीज़ में obfuscation जो छिपाता है (strings, crates, library functions, flattened control flow) उसे static analysis + Unicorn emulation के माध्यम से recover करें, बिना उन्हें चलाए। Malware triage, protected-app audits के लिए। ELF/PE/Mach-O, x86-64/ARM64/32-bit।
strings कुछ नहीं देखता। FLOSS कुछ नहीं देखता। rust-deobf C2 देखता है।
rust-deobf वह पुनर्प्राप्त करता है जो obfuscated Rust binaries छिपाते हैं — C2 पते, फ़ाइल पथ, mutexes, registry keys, config — बिना कभी sample चलाए।
Demo · इसे AI agent से उपयोग करें · Quick start · Results · वास्तविक malware · सीमाएँ
एक stripped Rust प्रोग्राम जिसे उसी तरह बनाया गया है जैसे malware भेजा जाता है (opt-level="z", fat LTO, panic=abort),
जिसके आठ संकेतक obfstr द्वारा एन्क्रिप्ट किए गए हैं — strings
एक struct, match arms, तुलनाओं, और एक ऐसी शाखा में बैठे हैं जो कभी नहीं चलती। इनमें से कोई भी कभी प्रिंट नहीं होता।
एक वास्तविक रन के कैप्चर किए गए आउटपुट से रेंडर किया गया (Linux x86-64, rustc 1.97): टेक्स्ट शब्दशः है, रंग और टाइपिंग एनिमेशन जोड़े गए हैं, ~8 s का emulation प्रतीक्षा समय तेज़ किया गया है, और आउटपुट को decoded strings तक छोटा किया गया है। नीचे दिया गया plain-text आउटपुट वही रन है।
फ़ाइल आपको क्या दिखाती है:
$ B=build/scatter_obfstr__elf__size-lto__strip
$ strings $B | grep -ciE 'northwind|10\.66|NW-5c1e9a|skip-update'
0
rust-deobf क्या पुनर्प्राप्त करता है (static + Unicorn emulation; बाइनरी को कभी निष्पादित नहीं किया जाता):
$ python3 scripts/recover.py $B
binary: scatter_obfstr__elf__size-lto__strip format=ELF arch=x86_64
static x86-64 (recover_callsite): 0 strings decoders=9 seconds=0.2
emulation (recover_emulate): 8 strings functions=416/416 timed_out=False workers=1 seconds=6.8
== decoded strings ==
10.66.12.7:8443 [ip]
function 0xf20c (emulation)
C:\ProgramData\NorthwindSvc\state.db [path]
function 0xf20c (emulation)
Mozilla/5.0 (Windows NT 10.0; Win64; x64) NorthwindAgent/2.1
function 0xf20c (emulation)
--skip-update-check
function 0xf443 (emulation)
Software\Northwind\Agent\Settings [registry]
function 0xf51b (emulation)
Global\NW-5c1e9a [mutex]
function 0xf5a8 (emulation)
https://telemetry.northwind.example/api/v3/beacon [url]
function 0xfd58 (emulation)
nw-agent::stage=collect
function 0xfd58 (emulation)
10 सेकंड से कम समय में 8/8, प्रत्येक स्ट्रिंग को टैग किया गया और उसे बनाने वाले फ़ंक्शन तक ट्रेस किया गया।
इसे ONLY=scatter_obfstr PROFILES=size-lto FORMATS=elf bash scripts/build_all.sh के साथ पुनरुत्पादित करें
(आउटपुट को डिकोड किए गए स्ट्रिंग्स तक सीमित किया गया है)। (इनपुट एक सौम्य बेंचमार्क
प्रोग्राम है; प्रत्येक रोपित स्ट्रिंग bench_src/manifest.json में सूचीबद्ध है।)
Rust मैलवेयर बढ़ रहा है, और इसका डीऑब्फस्केशन टूलींग प्रभावी रूप से अनुपस्थित है। FLOSS — मानक ओपन-सोर्स स्ट्रिंग डीऑब्फस्केटर — सामान्य Rust ऑब्फस्केशन क्रेट्स से कुछ भी पुनर्प्राप्त नहीं करता:
| obfuscator | strings | FLOSS | rust-deobf |
|---|---|---|---|
| litcrypt / litcrypt2 | 0/5 | 0/5 | 5/5 |
| obfstr (inlined XOR+ADD) | 0/5 | 0/5 | 5/5 |
| cryptify (default key) | 0/5 | 0/5 | 5/5 |
| muddy (ChaCha20-Poly1305 AEAD) | 0/5 | 0/5 | 5/5 |
| tight stack strings | 0/5 | 0/5 | 5/5 |
| hand-rolled XOR / ADD / SUB | 0/5 | 0/5 | 5/5 |
कैनरी बेंचमार्क, रिलीज़ बिल्ड, ELF और PE x86-64 और AArch64, स्ट्रिप्ड और नॉन-स्ट्रिप्ड। पूरी तालिका, जिसमें वह एक मामला भी शामिल है जिसके लिए डायनामिक रिकवरी आवश्यक है (कस्टम कुंजी के साथ cryptify), परिणाम के अंतर्गत।
वास्तविक सैंपल्स पर: EDDIESTEALER (PE) — 32 ऑब्फस्केटेड स्ट्रिंग्स, जिनमें इसका छिपा हुआ C2 डोमेन और URL पथ शामिल है, जहाँ स्टैटिक टूल्स और FLOSS 0 पुनर्प्राप्त करते हैं। AmnesiaStealer (macOS Mach-O) — C2 एक्सफ़िल URL, क्रिप्टो-क्लिपर कॉन्फ़िग, स्टेजिंग पथ। नीचे और देखें।
स्ट्रिंग डीऑब्फस्केशन — स्टैटिक कॉल-साइट रिकवरी (सेकंडों में) + एक Unicorn एमुलेशन इंजन जिसमें
एक वास्तविक लोडर, एक C रनटाइम, पथ अन्वेषण और ग्लोबल-कंस्ट्रक्टर रीप्ले है। केवल एक match आर्म में या
ऐसी ब्रांच पर बनी स्ट्रिंग्स को पुनर्प्राप्त करता है जो कभी नहीं चलती।
एक-स्क्रीन SOC ट्रायाज — soc_triage.py: फ़ॉर्मेट/आर्क, Rust टूलचेन, क्रेट क्षमता
फ़िंगरप्रिंट (नेटवर्किंग / क्रिप्टो / रेकॉन / पर्सिस्टेंस / स्टेजिंग), प्रकार के अनुसार समूहित संकेतक, और
अपने साक्ष्य के साथ एक कैलिब्रेटेड LOW / MEDIUM / HIGH सिग्नल। SIEM के लिए --json, स्क्रिप्टेड गेटिंग के लिए --fail-on HIGH।
--fast (मेटाडेटा + लिटरल संकेतक, कोई डिकोडिंग नहीं) बाइनरी आकार के साथ स्केल करता है: एक छोटे सैंपल पर
एक सेकंड से कम, 20 MB की बाइनरी पर ~20 सेकंड।
मल्टी-आर्क, मल्टी-फ़ॉर्मेट — ELF, PE और Mach-O में x86-64, ARM64 और 32-बिट x86।
आपके वर्कफ़्लो में फ़िट — FLOSS-संगत एक्सपोर्ट (--floss-json), हेडलेस Ghidra एनोटेशन
(प्लेट कमेंट, बुकमार्क, रीनेम), बाइट सिग्नेचर द्वारा लाइब्रेरी-फ़ंक्शन पहचान
(स्ट्रिप्ड बाइनरीज़ में lib_<name>), किसी डायरेक्टरी पर बैच मोड (--jsonl)।
स्ट्रिंग्स से आगे — कॉन्फ़िग/C2 एक्सट्रैक्शन, हैश-ऑब्फस्केटेड API-इम्पोर्ट रिज़ॉल्यूशन, अनपैक्ड
स्टेज-2 कार्विंग, कंट्रोल-फ़्लो-फ़्लैटनिंग डिटेक्शन और पुनर्निर्माण (x86-64 और AArch64,
goldberg, OLLVM -fla और एक वास्तविक LLVM-18 फ़्लैटनिंग पास पर मान्य), Z3 के साथ MBA / अपेक-प्रेडिकेट
सरलीकरण, Rust ट्रेट-ऑब्जेक्ट vtable रिकवरी (recover_types.py), और
ऑप्टिमाइज़ेशन-रिवर्सल (जंप-टेबल अन-स्विचिंग, अनरोल्ड-लूप डिटेक्शन — premium/opt_reverse.py)।
कोड वर्चुअलाइज़ेशन — detect_vm.py VMProtect/Themida/Tigress-शैली बाइटकोड VMs को फ़्लैग करता है; प्रीमियम
डीवर्चुअलाइज़र उन्हें वापस लिफ़्ट करता है। रैंडमाइज़्ड ऑपकोड और एन्क्रिप्टेड
ऑपरेंड वाले VM से, यह पुनर्निर्माण करता है:
return (((a0 > 1000) & (((((a0 * 31) + a1) ^ (a0 >> 3)) % 97) == 0)) ? (a1 + a0) : 0xffffffff);
— फ़ंक्शन का सटीक स्रोत।
डिज़ाइन से सुरक्षित — डिफ़ॉल्ट रूप से स्टैटिक + एमुलेशन: एमुलेशन Unicorn के अंतर्गत बाइनरी के फ़ंक्शन चलाता है, बाइनरी को स्वयं कभी नहीं। डायनामिक (Frida) रिकवरी ऑप्ट-इन है और केवल पृथक VM के लिए है।
strip के बाद भी बची रहने वाली Rust मेटाडेटा — rustc संस्करण, सटीक संस्करणों के साथ तृतीय-पक्ष क्रेट्स, और panic साइट्स, जिन्हें कंपाइलर द्वारा हर Rust बाइनरी में छोड़े गए स्रोत पथों से पुनर्निर्मित किया जाता है (cargo-auditable की आवश्यकता नहीं)।