
Tencent VM .tvm0 सेक्शन्स को डीवर्चुअलाइज़ करता है: VM हैंडलर्स को गेस्ट-लेवल लिस्टिंग्स और LLVM IR में लिफ्ट करता है, CFG और डिस्पैच को रिकवर करता है, और रिकवर किए गए कोड को वापस PE में पैच करता है।
संबंधित Zenodo रिकॉर्ड: 10.5281/zenodo.23474767।
⚠️ अस्वीकरण: यह प्रोजेक्ट पूर्णतः अधिकृत सुरक्षा अनुसंधान, इंटरऑपरेबिलिटी विश्लेषण और शिक्षा के लिए है। इसमें वाणिज्यिक एंटी-चीट सिस्टम के लिए कोई बायपास कार्यक्षमता शामिल या प्रदान नहीं की गई है। उपयोगकर्ता पूर्णतः इस बात के लिए उत्तरदायी हैं कि उनके पास लक्ष्य बाइनरीज़ का विश्लेषण करने का कानूनी अधिकार है।
Tencent VM के लिए एक डीवर्चुअलाइज़र। यह .tvm0 सेक्शन में वर्चुअलाइज़्ड कोड को पुनर्प्राप्त करता है, यह उठाता है कि प्रत्येक VM हैंडलर गेस्ट के रजिस्टरों और मेमोरी के साथ क्या करता है, और पुनर्प्राप्त किए गए फ़ंक्शनों को सामान्य read+execute सेक्शन के रूप में बाइनरी में वापस लिख सकता है।
यह एक टूल है: इसे किसी मॉड्यूल पर इंगित करें, और संरचना तथा कोड वापस प्राप्त करें।
.tvm0 section -> VM semantics -> guest-level listing -> LLVM IR -> patched PE
एक VM रूट की डीवर्चुअलाइज़्ड लिस्टिंग, जिसमें गेस्ट रजिस्टर फ़ाइल ब्लॉकों में बंधी हुई है।

python -m venv .venv
source .venv/Scripts/activate # Windows: .venv\Scripts\Activate.ps1
pip install -r requirements.txt
Python 3.13, capstone। बैकएंड के लिए: llvmlite==0.50.0 और, Windows पर, MSVC
link.exe/cl.exe। z3-solver वैकल्पिक है — इसके बिना पथ कंडीशनिंग बनी रहती है और केवल
सीमित डिस्पैच प्रमाण छोड़ दिया जाता है।
.env.example को .env में कॉपी करें और इस मशीन के लिए पथ भरें। .env git-ignored है, और
प्रत्येक सेटिंग का एक कमांड-लाइन फ़्लैग भी है, इसलिए फ़ाइल केवल डिफ़ॉल्ट प्रदान करती है।
| key | meaning |
|---|---|
TVM_MODULE | विश्लेषण करने के लिए मॉड्यूल, बिना स्थितीय तर्क के चलाए गए प्रोब के लिए |
TVM_LISTINGS | लिस्टिंग कॉर्पस जिसे बैकएंड पढ़ता है |
TVM_OUT | सभी आउटपुट के लिए रूट (डिफ़ॉल्ट out/) |
TVM_STEPS | ब्लॉक के ट्रंकेट होने से पहले प्रति ब्लॉक चरण (डिफ़ॉल्ट 900000) |
TVM_BLOCKS | प्रति रूट ब्लॉक बजट (डिफ़ॉल्ट 512) |
TVM_PAYLOAD_OPT | पेलोड कोडजेन स्तर 0–3 |
TVM_PAYLOAD_MEM | sealed | absolute गेस्ट-मेमोरी मोड |
TVM_MSVC_BIN | link.exe/cl.exe वाली डायरेक्टरी, PATH पर निर्भर रहने के बजाय |
प्राथमिकता: कमांड-लाइन फ़्लैग → .env → environment → अंतर्निहित डिफ़ॉल्ट।
इंजन कमांड engine/ से चलते हैं; बैकएंड कमांड रिपॉज़िटरी रूट से।
cd engine
python -m probe.scan_tvm0 /path/to/dir # which files carry a .tvm0, and its roots
python -m probe.trampoline_forms input.exe # what the entry trampolines look like
python -m probe.mnemonic_census input.exe # what x86 the VM contains
python -m core.devirt input.exe --out ../out/listings
प्रत्येक फ़ंक्शन के लिए एक 0x<root>.txt लिस्टिंग और एक 0x<root>.guest-state.json। विकल्प:
| फ़्लैग | डिफ़ॉल्ट | अर्थ |
|---|---|---|
--out=DIR | stdout | लिस्टिंग + guest state लिखें |
--root=0x… | सभी खोजे गए | एक VM प्रविष्टि तक सीमित करें |
--show[=N] | बंद | पहली N पंक्तियाँ प्रिंट करें |
--steps=N | 900000 | ट्रंकेशन से पहले प्रति ब्लॉक चरण |
--blocks=N | 512 | प्रति रूट ब्लॉक बजट |
--caller-entry=0x… --call-site=0x… | बंद | प्रविष्टि को caller-विशिष्ट बनाएँ |
प्रत्येक लिस्टिंग का हेडर बताता है कि रन ट्रंकेटेड था या नहीं; एक ट्रंकेटेड लिस्टिंग एक निचली सीमा है, फ़ंक्शन नहीं।
python -m probe.cfg_run input.exe 0x14015fc2e # walk it, print the CFG
python -m probe.guest_effect input.exe 0x14015fc2e # what handlers do to guest registers
python -m probe.ctx_map input.exe 0x14015fc2e # which context slot holds which register
python -m probe.why_unresolved input.exe 0x14015fc2e # why a dispatch did not resolve
python -m probe.block_exits input.exe 0x14015fc2e # why a block has no successor
python -m probe.stop_debug input.exe 0x14015fc2e # why evaluation stopped
python -m probe.unresolved_detail input.exe 0x14015fc2e # per-block detail
किसी विशिष्ट मान या स्टोर में ड्रिल करें:
python -m probe.trace_window input.exe 0x14015fc2e 0x14015fc40 0x14015fc90
python -m probe.reg_history input.exe 0x14015fc2e rax
python -m probe.who_wrote input.exe 0x14015fc2e 0x18
python -m probe.flags_at input.exe 0x14015fc2e 0x14015fc60
python -m probe.stack_at input.exe 0x14015fc2e
.\write-devirt.ps1 -Module 'C:\path\to\SGuardSvc64.exe'
पेलोड चलाता है → इंजेक्ट करता है → लोड करता है → डिफरेंशियल करता है और पहले विफल होने वाले चरण पर रुक जाता है। विकल्प:
-Listings, -Out, -Opt 0..3, -Mem sealed|absolute, -SkipDifferential, -Force।
चरण अलग-अलग:
cd llvm
python payload.py --listings=../out/hard-cases-listings-final --out=../out/write-devirt --opt=0 --mem=sealed
python peinject.py --host=input.exe --payload=../out/write-devirt --out=../out/write-devirt/input.neko.exe
python miniload.py ../out/write-devirt/input.neko.exe
python diff_payload.py --payload=../out/write-devirt --patched=../out/write-devirt/input.neko.exe
diff_payload.py वह जाँच है जो मायने रखती है: यह कोड को पैच की गई इमेज के अंदर चलाता है और
इसकी तुलना उसी लिस्टिंग पर इंटरप्रेटर के साथ बाइट-दर-बाइट करता है। miniload.py केवल यह सिद्ध करता है
कि इमेज लोड होती है और उसका एंट्री चलता है।
ACE किसी नेटिव फ़ंक्शन को VM डिस्पैचर में एक ट्रैम्पोलिन से बदल देता है। डिस्पैचर नेटिव x86 हैंडलर निष्पादित करता है, लेकिन संरक्षित फ़ंक्शन की आर्किटेक्चरल स्थिति VM कॉन्टेक्स्ट में रहती है।
flowchart TB
subgraph TOP[ ]
direction LR
subgraph TEXT[.text]
ENTRY["<b>Function entry</b><br/>jump to VM entry"]
end
subgraph VM[.tvm0 section]
direction LR
CORE["<b>Shared dispatcher and handlers</b><br/>execute x86 - resolve next handler"]
CTX["<b>Guest context</b><br/>GPRs - RFLAGS - VIP"]
CORE <--> CTX
end
end
subgraph NATIVE[Native execution outside the VM]
direction LR
BOXED["<b>Boxed instruction</b><br/>execute original x86"]
CALL["<b>Guest call</b><br/>invoke native target"]
EXIT["<b>Guest return or tail call</b><br/>resume native execution"]
BOXED ~~~ CALL ~~~ EXIT
end
TEXT --> VM
VM <--> NATIVE
style TOP fill:transparent,stroke:transparent
कुछ ऑपरेशन VM के बाहर निष्पादित होते हैं। एक बॉक्स्ड इंस्ट्रक्शन अपनी मूल x86 एन्कोडिंग को तब चलाता है जब VM उन रजिस्टरों को पुनर्स्थापित कर लेता है जिनकी उसे आवश्यकता होती है, और फिर अपने प्रभावों को गेस्ट कॉन्टेक्स्ट में लौटा देता है। एक गेस्ट कॉल एक नेटिव टारगेट को आमंत्रित करता है और रिटर्न वैल्यू तथा Windows x64 ABI क्लॉबर्स के साथ गेस्ट स्टेट में दर्शाए गए रूप में पुनः आरंभ होता है। गेस्ट रिटर्न और टेल कॉल डिस्पैचर को पूरी तरह छोड़ देते हैं।
कॉन्टेक्स्ट में सभी सोलह गेस्ट जनरल-पर्पस रजिस्टर, जिनमें गेस्ट RSP भी शामिल है, तथा पैक्ड गेस्ट फ्लैग्स होते हैं। इसका लेआउट प्रोटेक्टर बिल्ड के अनुसार भिन्न होता है, इसलिए इसे VM के सेव/रिस्टोर व्यवहार को देखकर स्थित किया जाता है, न कि अनुमान लगाकर — probe.ctx_map स्टोर्स पर मापी गई मैपिंग की रिपोर्ट करता है, और प्रत्येक उत्सर्जित लिस्टिंग किसी कॉन्टेक्स्ट एक्सेस को उसके स्लॉट ऑफ़सेट के साथ कोष्ठक में दर्शाती है।
कंडीशनल कंट्रोल फ़्लो डिस्पैच अंकगणित है: एक हैंडलर एक गेस्ट फ्लैग या प्रेडिकेट निकालता है, उसका उपयोग अगले वर्चुअल प्रोग्राम काउंटर को चुनने के लिए करता है, और अगले हैंडलर का पता परिकलित करता है। डीवर्चुअलाइज़र उसका प्रतीकात्मक मूल्यांकन करता है और तब फोर्क करता है जब चयन किसी अनसुलझे गेस्ट मान पर निर्भर होता है। किसी ब्लॉक की पहचान जोड़ी (handler, vip) होती है, केवल हैंडलर नहीं।