Skip to content
KitploitKITPLOIT
उपकरणब्लॉग
जमा करें
उपकरणब्लॉग
जमा करें

हैकिंग, पेनटेस्ट और साइबर सुरक्षा उपकरण आपके सुरक्षा शस्त्रागार के लिए!

Kitploit हैकिंग, साइबर सुरक्षा और पेंटेस्टिंग टूल्स की एक निर्देशिका है। कमजोरियों को खोजने, सिस्टम का विश्लेषण करने, परीक्षण को स्वचालित करने और अपनी सुरक्षा को मजबूत करने के लिए नवीनतम प्रोजेक्ट अपडेट खोजें।

··फ़ीड·संपर्क·गोपनीयता·© 2026 Kitploit

टूल निर्देशिका

श्रेणियाँ

सभी श्रेणियाँ देखें
Loading categories
mkPIVM — पॉलीमॉर्फिक, स्थिति-स्वतंत्र वर्चुअल मशीनें (PIVMs) उत्पन्न करें, मनमाने x86/x64 शेलकोड से। | Kitploit
उपकरण/GitHubGitHub/d7ead/mkpivm
पेलोड जनरेशनशोषणरिवर्स इंजीनियरिंगशेलकोडमालवेयर विश्लेषणरेड टीमिंग
GitHubd7ead/mkpivm

mkPIVM

पॉलीमॉर्फिक, स्थिति-स्वतंत्र वर्चुअल मशीनें (PIVMs) उत्पन्न करें, मनमाने x86/x64 शेलकोड से।

रिपॉजिटरी देखें
409177 दिन पहलेKitploit द्वारा समीक्षित

सबसे लोकप्रिय

सभी देखें →

हमारे समुदाय द्वारा सबसे अधिक उपयोग किए जाने वाले उपकरण खोजें।

सभी उपकरण खोजें

हमारे उपकरणों का संग्रह ब्राउज़ करें

सभी उपकरण देखें →
साझा करें


पढ़ें शोध पत्र (1.0.0 के लिए लिखा गया)।

mkPIVM एक बहुरूपी स्थिति-स्वतंत्र शेलकोड वर्चुअलाइज़र है जो Windows x86 और x64 (जल्द ही Linux) के लिए है।

इसे रॉ शेलकोड खिलाएं। यह एक और रॉ ब्लॉब उत्सर्जित करता है: एक छोटा वर्चुअल मशीन जो आपके मूल निर्देशों के उठाए गए, आराम पर एन्क्रिप्टेड संस्करण की व्याख्या करता है। आउटपुट स्वयं स्थिति-स्वतंत्र कोड है और वहां चलता है जहां मूल शेलकोड चलता, रिमोट-थ्रेड लोडर से लेकर कोड केव डिटूर तक। प्रति-बीज प्रत्येक नॉब स्वतंत्र रूप से भिन्न होता है: सिफर परिवार, रजिस्टर स्लॉट लेआउट, ऑपकोड-टू-हैंडलर क्रमपरिवर्तन, डिस्पैचर टोपोलॉजी, जंक-गैजेट पैटर्न, IR अस्पष्टता सम्मिलन बिंदु। एक ही इनपुट से दो बिल्ड दसियों किलोबाइट्स में से सौ से कम संयोग बाइट्स साझा करते हैं।

क्यों: नेटिव शेलकोड हस्ताक्षर-तुच्छ है। इसे प्रति-उदाहरण VM में प्रति-उदाहरण सिफर के साथ लपेटने से आराम पर कुछ भी उपयोगी नहीं बचता, और निर्देशों को बाइटकोड में उठाना डिस्क बाइट्स और किसी भी डिसअसेंबलर के बीच एक और दीवार डालता है जो x86 को जानता है। जहां तक मैं साहित्य सर्वेक्षण से बता सकता हूं, कोई सार्वजनिक उपकरण बिल्कुल इस पाइपलाइन को शिप नहीं करता: रॉ PIC इन, रॉ बहुरूपी VM PIC आउट। तो, मैंने इसका उल्लेख शोध पत्र में किया जिसकी मांग की गई थी। सच कहूं तो, अगर मैं इस बारे में सही हूं कि किसी ने पहले (सार्वजनिक रूप से) ऐसा नहीं किया है, और मुझे काफी भरोसा है, तो मुझे आश्चर्य है। फिर भी, आनंद लें।

संबंधित कार्य और योजनाएँ

  • Linux समर्थन जल्द ही जोड़ा जाएगा।

त्वरित आरंभ```

mkpivm.exe shellcode.bin --arch x64 -o out.bin

root@kitploit:~
आपका PIVM गर्म और तैयार है। यह सबसे सरल रास्ता है। कई अन्य मोड अलग-अलग होते हैं कि मूल निर्देश कितने आक्रामक रूप से वर्चुअलाइज़ होते हैं, आउटपुट एक स्टैंडअलोन ब्लॉब है या पैच किया गया PE, और लिफ्ट बिल्कुल चलती है या नहीं।

# Showcase

मेरे पास सबूत हैं। आप नीचे mkPIVM के काम करने का एक वीडियो देख सकते हैं, जो एक Meterpreter स्टेजर (वैनिला btw) को पूरी तरह से वर्चुअलाइज़ कर रहा है, explorer.exe में इंजेक्ट कर रहा है, और हम कॉलबैक कैप्चर कर रहे हैं। बेशक यह सिर्फ एक उदाहरण है, और mkPIVM को और भी अधिक पर लागू किया जा सकता है, बशर्ते शेलकोड में निर्देश समर्थित हों। यदि वे समर्थित नहीं हैं, तो एक Issue बनाएं, मुझे शेलकोड भेजें, मैं संभाल लूंगा।

इसे [here](https://github.com/D7EAD/mkPIVM/raw/refs/heads/main/media/mkpivm-showcase.mp4) देखें। ./media में होस्ट किया गया है, दुर्भाग्य से एम्बेड नहीं कर सकते।

यहाँ उसी वर्चुअलाइज़्ड सैंपल का VirusTotal रिपोर्ट है (06/04/2026 तक)।

<img src="https://assets.kitploit.com/production/public/readmes/7466/3f4a6dbe2777c02fb32f71749a5b1fa2aa324cb0dac2f77d5681bbe3a4e17a81.png">

...और पैक किया गया संस्करण, वर्चुअलाइज़ भी नहीं किया गया, विशेष रूप से उच्च एंट्रॉपी।

<img src="https://assets.kitploit.com/production/public/readmes/7466/47f68372e31a2c24fa49eb71648adbdf8944977db90d645df337125c1bdfa8e3.png">

तुलना के लिए एक सामान्य Cobalt Strike बीकन के परिणाम।

<img src="https://assets.kitploit.com/production/public/readmes/7466/76e2107589cd2b1b65c846a671aed173aa5e6d89630f5e9d283d99c546a2d566.png">

इस उपकरण के आउटपुट के एंट्रॉपी टेलीमेट्री पर सावधानीपूर्वक ध्यान दिया गया, जिसके परिणामस्वरूप शेलकोड की एंट्रॉपी सामान्य Windows WinAPI DLLs (पैकिंग मोड के बाहर) जैसे ntdll.dll या kernel32.dll से कम होती है। एंट्रॉपी तुलना लगभग है...

| फ़ाइल | बाइट्स | एंट्रॉपी |
|------|-------|---------|
| `p_m64.bin` | 3,969 | **7.1181** |
| `msvcrt.dll` | 699,888 | 6.5319 |
| `wininet.dll` | 2,724,528 | 6.4934 |
| `shell32.dll` | 7,839,992 | 6.3639 |
| `kernel32.dll` | 836,232 | 6.3597 |
| `crypt32.dll` | 1,538,632 | 6.3010 |
| `rpcrt4.dll` | 1,162,672 | 6.2405 |
| `ntdll.dll` | 2,522,104 | 6.1934 |
| `v.bin` | 29,229 | **6.0442** |

## एक नज़र में मोड

| मोड | फ़्लैग | क्या बदलता है |
|------|-------|--------------|
| Default | none | पूरे इनपुट को उठाएं। सब कुछ वर्चुअलाइज़्ड। |
| Packer | `--pack` | लिफ्ट न करें। इनपुट को एन्क्रिप्टेड डेटा के रूप में लपेटें, रनटाइम पर डिक्रिप्ट करें, और उसमें कूदें। |
| Hybrid | `--ranges A:B,...` | केवल चुने गए बाइट रेंज को उठाएं। बाकी नेटिव रहता है। |
| Stacked | `--pack --ranges A:B` | हाइब्रिड ब्लॉब बनाएं, फिर इसे पैक-रैप करें। |
| Detour | `--embed-into PE --at RVA` | पहले से निर्मित ब्लॉब लें, PE में एम्बेड करें, चयनित RVA पर jmp पैच करें। |
| Scan | `--scan` | इनपुट के CFG से पात्र `--ranges` उम्मीदवारों को प्रिंट करें, फिर बाहर निकलें। |
| RX | `--rx` | PAGE_EXECUTE_READ ब्लॉब। डेटा आइलैंड आराम पर एन्क्रिप्टेड रहता है; इन-ब्लॉब PEB वॉकर VirtualProtect को हल करता है, state_init पर इन-प्लेस डिक्रिप्ट करता है। |
| RX w/ Loader | `--rx --rx-loader-vp` | `--rx` की तरह, लेकिन आपका लोडर VirtualProtect को ब्लॉब के पहले आर्ग के रूप में पास करता है। कोई PEB वॉकर नहीं। |

हर मोड `--seed`, `--arch`, `--input-format`, और `--format` का सम्मान करता है। बिल्ड पाइपलाइन और रनटाइम फ्लो के लिए नीचे प्रति-मोड अनुभाग देखें।

## डिफ़ॉल्ट वर्चुअलाइज़ेशन

लिफ्टर पूरे CFG पर चलता है और हर निर्देश को एक कस्टम IR में बदल देता है। IR दो ऑब्फस्केशन पास से गुज़रता है, फिर कोडेक्स से होकर जाता है जो प्रत्येक insn को प्रति-सीड बाइटकोड आकार में एनकोड करते हैं। ब्लॉक टेबल, हैंडलर टेबल, और डेटा आइलैंड को बाइटकोड के समान प्रति-बाइट स्ट्रीम सिफर से एन्क्रिप्ट किया जाता है। रनटाइम पर प्रोलॉग उन तीन क्षेत्रों को इन-प्लेस डिक्रिप्ट करता है और डिस्पैचर लूप एक-एक करके बाइटकोड बाइट्स लाता है, डिक्रिप्ट करता है और एक हैंडलर को डिस्पैच करता है जो काम करता है।

### बिल्ड पाइपलाइन

बिल्ड द्वारा कच्चे शेलकोड को निकाले गए वर्चुअलाइज़्ड ब्लॉब में बदलने के लिए किए जाने वाले कदम, शुरू से अंत तक। _नीचे सभी ग्राफ 1.0.0 रिलीज़ पर लागू होते हैं, तब से ये बदल गए हैं, लेकिन विचार वही है।_```mermaid
flowchart TB
    A[shellcode.bin] --> CFG[CFGBuilder: identify blocks via Zydis disasm + recursive descent]
    SEED[seed u64] --> VMC[VMConfig: pick cipher kind, reg perm, opcode map, dispatcher topology]
    CFG --> LIFT[LifterRegistry: lower each block to IR]
    LIFT --> RBT[resolve_branch_targets: link BR_CC/BR/CALL_VM/LOOP_DEC to target_block_id; synthesize JMP_NATIVE block for any out-of-range jcc]
    RBT --> OBF1[obfuscate_ir_dead_inject: 20% per insn-gap, IMM Tmp2/Tmp3 random]
    OBF1 --> OBF2[obfuscate_ir_opaque_predicates: 25% per block, split block with IMM Tmp3=0 + TEST + BR_CC NZ random_block, never taken]
    OBF2 --> ENC[BytecodeBuilder: each codec emits its variant for this seed]
    ENC --> CDATA[compact data island: bytes not covered by any CFG block]
    CDATA --> PROMO[promote LEA-fixup target VAs back into data island if CFG put them in code]
    ENC --> BTAB[build block table: va_off to bytecode_off pairs]
    PROMO --> ECIPH[encrypt data island with cipher_init]
    BTAB --> ECIPH2[encrypt block table with cipher_init]
    ENC --> ECIPH3[encrypt bytecode per-block with cipher_init reset at each block start]
    VMC --> STUB[VMCodeGen::emit_full: prologue, state init, dispatcher tail, handlers, sbox_inv, exit handler]
    STUB --> HTAB[handler table: 256 entries, each a 32-bit offset from handler_base; encrypted at rest]
    ECIPH --> ASM[finalize: stub + trampolines + sbox_inv + bytecode + data island + block table]
    ECIPH2 --> ASM
    ECIPH3 --> ASM
    HTAB --> ASM
    ASM --> OUT[out.bin]

रनटाइम प्रवाह

उत्सर्जित ब्लॉब क्या करता है जब होस्ट लोडर बाइट 0 पर इसे कॉल करता है, प्रोलॉग से डिस्पैचर फेच और विभिन्न समाप्ति पथों के माध्यम से।```mermaid flowchart TB ENTRY[blob entry at byte 0] --> PROL[prologue: push NV regs in seed-shuffled order, pushfq, allocate frame, lea state_ptr] PROL --> SI[emit_state_init body, gated by init_flag byte] SI --> ZERO[zero VM regs via seed-permuted xor source] ZERO --> CINIT[set cipher_state register, store cipher_init at cipher_extra+48] CINIT --> SBOX[copy sbox_inv table from blob to cipher_extra+256] SBOX --> NONCE[derive runtime nonce: rdtsc XOR cipher_init, store at cipher_extra+80] NONCE --> DDI[decrypt data island in place via emit_fetch_byte_dec loop] DDI --> DBT[decrypt block table in place] DBT --> DHT[decrypt handler table in place] DHT --> XHT[XOR each handler table entry with the runtime nonce so memory image is process-variant] XHT --> SET_INIT[set init_flag = 1 to gate subsequent vm_entry invocations] SET_INIT --> DISP[dispatcher tail] DISP --> FB[fetch one byte via emit_fetch_byte_dec, decrypts using cipher_state] FB --> HLU["load handler offset: mov scratch_b_32, [handler_base + op*4]"] HLU --> UXOR["xor scratch_b_32, [state_ptr + cipher_extra + runtime_nonce_off]"] UXOR --> SXD[movsxd to 64 bit, lea handler_addr = handler_base + offset, jmp handler] SXD --> H[handler body: fetch operands via stream cipher, perform op, advance state] H --> NEXT{terminator?} NEXT -- no --> DISP NEXT -- BR/BR_CC --> CRESET[cipher_reset to cipher_init, advance ip to target block] CRESET --> DISP NEXT -- CALL_VM --> CRESET NEXT -- JMP_NATIVE imm --> MARSH["marshal VM regs to host regs, rsp = VM_RSP, jmp [target_slot]"] NEXT -- CALL_NATIVE --> PUSHTR[push trampoline addr to VM_RSP, marshal, jmp target] NEXT -- RET_VM --> POPSS[pop shadow stack, jmp to popped trampoline addr] POPSS --> CRESET NEXT -- exit_handler reached --> EPI[restore NV regs, ret to caller of vm_entry]

root@kitploit:~
रनटाइम नॉन्स ट्रिक मुख्य एंटी-मेमोरी-स्कैन चाल है: हैंडलर तालिका मेमोरी में `rdtsc XOR cipher_init` से प्राप्त मान के साथ XOR की गई होती है, इसलिए एक ही ब्लॉब लोड करने वाली दो प्रक्रियाएं बाइट-भिन्न हैंडलर तालिकाएं रखती हैं। डिस्पैचर लुकअप समय पर एक अतिरिक्त XOR के साथ अनमास्क करता है।

## पैकर मोड: `--pack`

विपरीत ट्रेडऑफ। लिफ्टर नहीं चलता। मूल शेलकोड एन्क्रिप्टेड डेटा आइलैंड में जाता है, और IR एक एकल सिंथेटिक `JMP_NATIVE imm=0` है। प्रोलॉग जानबूझकर डेटा-आइलैंड डिक्रिप्ट को छोड़ देता है जो डिफ़ॉल्ट मोड उत्सुकता से चलाता है। इसके बजाय, पहली बार जब अकेला JMP_NATIVE हैंडलर फायर करता है, तो वह डेटा आइलैंड को जगह में डिक्रिप्ट करता है, एक मार्कर बाइट सेट करता है, फिर नियंत्रण को अब-प्लेनटेक्स्ट शेलकोड के बाइट 0 पर स्थानांतरित करता है। शेलकोड वहां से नेटिव रूप से चलता है।

किसी भी शेलकोड पर काम करता है, लिफ्टर कवरेज की परवाह किए बिना। स्टेजलेस कोबाल्ट, विदेशी सिस्कॉल-हैवी पेलोड, वर्चुअलाइज़ करने के लिए बहुत बड़ी या अजीब किसी भी चीज़ के लिए उपयोगी। प्रति-निर्देश वर्चुअलाइजेशन डिफेंस खो देता है लेकिन रैपर पर पूर्ण प्रति-सीड VM पॉलीमॉर्फिज्म बनाए रखता है।

### बिल्ड पाइपलाइन

कैसे `--pack` मूल शेलकोड को एक-निर्देश सिंथेटिक IR प्रोग्राम के पीछे एक एन्क्रिप्टेड डेटा आइलैंड के रूप में लपेटता है।```mermaid
flowchart TB
    A[shellcode.bin] --> SKIP[skip CFG build, skip lift]
    SEED[seed u64] --> VMC[VMConfig polymorphism axes as in default mode]
    SKIP --> SYN[synthesize 1-insn IRProgram: one block with JMP_NATIVE Imm 0 Width Q]
    SYN --> SETF[VMConfig::set_pack_mode true, set_data_island_size shellcode.size]
    SETF --> ENC[BytecodeBuilder encodes the 1 insn into ~35 bytes]
    ENC --> CDATA[data island = entire shellcode bytes verbatim]
    CDATA --> ECIPH[encrypt shellcode bytes with cipher_init as the data island]
    ENC --> ECIPH2[encrypt bytecode + block table + handler table]
    VMC --> STUB[VMCodeGen::emit_full]
    STUB --> FLAG[data_island_init_flag byte starts at 0 because pack_mode true]
    STUB --> ASM[finalize layout]
    ECIPH --> ASM
    ECIPH2 --> ASM
    FLAG --> ASM
    ASM --> OUT[out.bin]

रनटाइम प्रवाह

पैक रैपर पहली प्रविष्टि पर क्या करता है, जिसमें डेटा आइलैंड का गेटेड लेज़ी डिक्रिप्ट और एकल सिंथेटिक JMP_NATIVE शामिल है जो नियंत्रण को अब-सादा-पाठ शेलकोड को सौंपता है।```mermaid flowchart TB ENTRY[blob entry] --> PROL[prologue + state init] PROL --> SKIP_DI[skip data island decrypt because data_island_size gated on pack_mode false at build] SKIP_DI --> DBT[decrypt block table in place] DBT --> DHT[decrypt handler table in place + runtime nonce XOR] DHT --> DISP[dispatcher fetches first opcode = JMP_NATIVE] DISP --> NH[emit_native_handler entry] NH --> GATE{data_island_init_flag == 0?} GATE -- yes --> SAVE[save cipher_state and ip to kPreDecryptCsOff/IpOff slots] SAVE --> RESET[reset cipher_state to cipher_init] RESET --> LOOP[decrypt data island in place byte by byte] LOOP --> RESTORE[restore cipher_state and ip from saved slots] RESTORE --> SETFLAG[set data_island_init_flag = 1] GATE -- no --> CONT[skip the decrypt body] SETFLAG --> CONT CONT --> FETCH_TGT[fetch JMP_NATIVE operand: tag = 0, imm = 0] FETCH_TGT --> COMPUTE[target = data_island_base + imm = start of decrypted shellcode] COMPUTE --> MARSH[marshal all VM regs to host regs, rsp = VM_RSP seeded with exit_handler] MARSH --> JMP["jmp [target_slot]"] JMP --> NATIVE[original shellcode runs natively] NATIVE --> RET{shellcode does ret?} RET -- yes --> POPSS[ret pops exit_handler from VM shadow stack] POPSS --> EPI[exit_handler restores NV regs, rets to original caller] RET -- ExitProcess --> DEAD[process terminates]

root@kitploit:~
विलंबित डेटा-द्वीप डिक्रिप्ट केवल पैक-मोड में होता है। डिफ़ॉल्ट और हाइब्रिड मोड में, उठाया गया कोड निष्पादन के बीच में डेटा-द्वीप बाइट्स पर VM LOAD/STORE करता है और उन्हें शुरू से ही प्लेनटेक्स्ट की आवश्यकता होती है, इसलिए प्रोलॉग इसे उत्सुकता से संभालता है। पैक मोड में, डेटा द्वीप का ठीक एक उपभोक्ता होता है, जो सिंथेटिक JMP_NATIVE के बाद नेटिव एस्केप है, इसलिए डिक्रिप्ट तब तक प्रतीक्षा कर सकता है।

## हाइब्रिड मोड: `--ranges A:B,C:D`

लक्षित वर्चुअलाइजेशन। इनपुट में उन बाइट रेंजों को चुनें जिन्हें उठाया जाना चाहिए। बाकी सब कुछ आउटपुट में मूल नेटिव बाइट्स के रूप में रहता है। प्रत्येक रेंज की शुरुआत में लिफ्टर नेटिव शेलकोड क्षेत्र के बाद जोड़े गए `vm_entry_K` स्टब में 5-बाइट `jmp rel32` पैच करता है। बाहरी नेटिव कोड केवल पैच किए गए शुरुआती बाइट के माध्यम से उठाए गए रेंज में फिर से प्रवेश कर सकता है। मध्य-रेंज बाइट्स int3 से भरे होते हैं, इसलिए कोई भी नेटिव ब्रांच जो मध्य-रेंज बाइट को लक्षित करता है, स्कैन समय पर अस्वीकार कर दिया जाता है। उठाया गया कोड जो रेंज से बाहर बाइट्स से बाहर निकलता है, वह `JMP_NATIVE` या `CALL_NATIVE` बन जाता है।

पहले योग्य उम्मीदवारों को खोजने के लिए `--scan` का उपयोग करें। स्कैन अंतराल वाली रेंज, बिना `ret`-समाप्त ब्लॉक वाली, 5 बाइट से छोटे बॉडी वाली, या मध्य-रेंज बाइट्स में बाहरी नेटिव शाखाओं वाली रेंज को योग्य के बजाय निकट-चूक के रूप में वर्गीकृत करता है।

### निर्माण पाइपलाइन

कैसे `--ranges` केवल चयनित बाइट रेंजों को उठाता है और नेटिव शेलकोड को स्थान पर पैच करता है ताकि नियंत्रण जोड़े गए VM प्रविष्टि स्टब्स में पुनर्निर्देशित हो जाए।```mermaid
flowchart TB
    A[shellcode.bin] --> RP[parse_ranges from --ranges flag]
    RP --> CFG[CFGBuilder with set_lifted_ranges restriction]
    CFG --> LIFT[lift_program: only blocks whose start_va is inside any range]
    LIFT --> XCG[branches/calls leaving the range become JMP_NATIVE/CALL_NATIVE]
    XCG --> OBF[IR obfuscation passes same as default]
    OBF --> ENC[encode bytecode]
    ENC --> BTAB[block table for RET_VM lookup]
    SEED[seed u64] --> VMC[VMConfig]
    VMC --> STUB[VMCodeGen::emit_range_mode: one vm_entry_K per range + dispatcher + handlers]
    STUB --> NSEC[start with verbatim copy of the native shellcode bytes]
    NSEC --> PATCH[at each range start, write 5-byte jmp rel32 to vm_entry_K]
    PATCH --> INT3[fill remaining bytes of the displaced run with int3]
    INT3 --> APPEND[append: VM stub + sbox_inv + bytecode + data island + block table]
    APPEND --> OUT[out.bin]

रनटाइम प्रवाह

नेटिव और वीएम ब्लॉब के माध्यम से नियंत्रण प्रवाह, जिसमें VM डिस्पैच में प्रवेश शामिल है जब नेटिव कोड पैच की गई रेंज की शुरुआत से टकराता है और नेटिव-एस्केप पथ जिनका उपयोग तब किया जाता है जब उठाया गया कोड वापस बाहर शाखा करता है।```mermaid flowchart TB ENTRY[blob byte 0 = native shellcode prologue] --> NAT[native shellcode runs] NAT --> HIT{control reaches a patched range start?} HIT -- no --> NAT HIT -- yes --> JMP[jmp rel32 to vm_entry_K] JMP --> RPROL[range prologue: push NV regs, allocate frame, lea state_ptr] RPROL --> MARSHIN[marshal host volatile regs to VM slots, NV regs preserved by Win64 ABI] MARSHIN --> SI[state init gated by init_flag for first-time decrypts] SI --> DISP[dispatcher loop] DISP --> HND[handler] HND --> NXT{terminator?} NXT -- BR/BR_CC inside range --> DISP NXT -- range ret reached --> CLEANUP[restore NV regs, pop frame, ret pops native retaddr from host stack] NXT -- JMP_NATIVE to byte outside range --> MIDEXIT[mid-exec cleanup: overwrite caller retaddr slot with target, jmp to exit_handler] NXT -- CALL_NATIVE to API --> APITAIL[push trampoline addr to VM_RSP, jmp resolved API] CLEANUP --> NAT MIDEXIT --> EH[exit_handler unwinds NV pushes, ret lands at the target we wrote] EH --> NAT APITAIL --> APIRET[API rets to trampoline in stub which resumes VM dispatch] APIRET --> DISP

root@kitploit:~
Coroutine-style ranges, the ones with no `ret` that exit via a tail-jmp, are documented via `--coroutines` for `--scan` output. The flag does not change codegen at present. Range mode is best fit for self-contained leaf functions. Helper functions that depend on a specific caller-supplied register state cannot be lifted standalone; the API ends up called with garbage args.

## Stacked mode: `--pack --ranges A:B,C:D`

Run the hybrid build, then pack-wrap the result. The outer VM decrypts the inner hybrid blob in place and jumps to byte 0 of it. From there execution proceeds exactly like standalone hybrid mode, except the entire blob including the chosen-range bytecode is encrypted at rest. The two layers compose cleanly because the inner blob is a self-contained PIC region.

### Build pipeline

How stacked mode recursively invokes the packager: an inner `--ranges` build first, then an outer `--pack` wrap of that build.```mermaid
flowchart TB
    A[shellcode.bin] --> INNER[invoke package_shellcode recursively in range-only mode]
    INNER --> RBLOB[range-mode bytes in memory]
    RBLOB --> WRAP[invoke package_shellcode again in pack-only mode with RBLOB as input]
    WRAP --> OUT[out.bin: outer pack VM wrapping the inner range-mode blob]

रनटाइम प्रवाह

बाहरी पैक VM आंतरिक रेंज-मोड VM को नियंत्रण कैसे सौंपता है, प्रत्येक अपने स्वतंत्र VMState फ्रेम पर चल रहा है।```mermaid flowchart TB E[blob entry] --> OPROL[outer pack prologue + state init] OPROL --> ODISP[outer dispatcher fetches synthetic JMP_NATIVE] ODISP --> LAZY[lazy decrypt of inner range-mode blob via deferred data-island decrypt] LAZY --> JN[outer JMP_NATIVE imm 0 sets target = inner blob byte 0] JN --> INAT[inner native shellcode runs] INAT --> IHIT{inner patched range start hit?} IHIT -- yes --> IVM[inner range vm_entry_K] IHIT -- no --> INAT IVM --> IRDISP[inner dispatcher loop, separate VMState frame] IRDISP --> INAT

root@kitploit:~
आंतरिक VM और बाहरी VM कोई स्थिति साझा नहीं करते। वे दो स्वतंत्र VM हैं जो संयोग से एक ही ब्लॉब में रहते हैं। बाहरी VM का एकमात्र कार्य आंतरिक VM को एक डिक्रिप्शन परत के पीछे रखना है।

## Detour mode: `--embed-into target.exe --at RVA`

दूसरों से अलग आकार। इनपुट रॉ शेलकोड है, परंपरागत रूप से एक VM ब्लॉब जो पहले से किसी अन्य मोड में mkPIVM द्वारा उत्सर्जित किया गया है, हालांकि कोई भी PIC बाइट्स काम करेंगे। आउटपुट एक पैच किया हुआ PE है।

टूल `target.exe` को पार्स करता है, चयनित RVA को एक एक्जीक्यूटेबल सेक्शन में ढूंढता है, वहां पर्याप्त निर्देशों को डिसअसेंबल करता है जो 5 बाइट्स को कवर करते हैं, यदि विस्थापित रन में RIP-relative addressing या सापेक्ष नियंत्रण प्रवाह है जो स्थानांतरित होने पर बच नहीं सकता, तो मना कर देता है, फिर एक नया RWX सेक्शन जोड़ता है जिसमें एक रैपर और VM ब्लॉब होता है। रैपर कॉलर स्थिति को संरक्षित करता है, VM ब्लॉब में स्थानांतरित करता है, स्थिति को पुनर्स्थापित करता है, विस्थापित मूल बाइट्स को निष्पादित करता है, और पैच के बाद बाइट पर वापस कूदता है। चयनित RVA पर एक 5-बाइट `jmp rel32` रैपर की ओर इशारा करता है।

रैपर VM में कैसे स्थानांतरित होता है, इसके दो उप-मोड:

### Threaded sub-mode, the default

दो आरेख अनुसरण करते हैं। पहला बिल्ड-समय PE पैचिंग पाइपलाइन है जो रैपर सेक्शन को इंजेक्ट करता है, संदर्भों को ठीक करता है, और चयनित RVA पर 5-बाइट jmp लिखता है। दूसरा रनटाइम नियंत्रण प्रवाह है जब होस्ट प्रक्रिया अंततः उस RVA तक पहुँचती है।```mermaid
flowchart TB
    BLOB[vm_blob.bin pre-built from any other mode] --> READ[read target.exe bytes]
    TGT[target.exe] --> READ
    READ --> PEHDR[parse DOS header, NT headers, sections, OptionalHeader, BASERELOC dir]
    PEHDR --> ARCHCHK[arch from PE32/PE32+ magic must match blob arch]
    ARCHCHK --> LOC[locate RVA inside an executable section]
    LOC --> DA[Zydis disassemble at RVA, accumulate insns until total length >= 5]
    DA --> VALID{any displaced insn has RIP-relative mem operand or is a rel32 branch?}
    VALID -- yes --> FAIL[error, pick a different RVA]
    VALID -- no --> IATSCAN[scan IMAGE_DIRECTORY_ENTRY_IMPORT for kernel32!CreateThread]
    IATSCAN --> IATFOUND{found?}
    IATFOUND -- no --> FAIL2[error, suggest --detour-inline or different target]
    IATFOUND -- yes --> EMITW[emit threaded wrapper bytes]
    EMITW --> APPEND[concatenate wrapper + vm_blob into new section content]
    APPEND --> ARCHBR{arch?}
    ARCHBR -- x64 --> X64FIX[fix wrapper rel32s: lea r8 to vm_blob; call qword ptr rip+iat_disp32]
    ARCHBR -- x86 --> X86FIX[fix wrapper abs32s: push vm_blob_va; call dword ptr iat_va; then append combined IMAGE_BASE_RELOCATION table with new HIGHLOW entries for those abs32s]
    X64FIX --> RJMP[compute jmp_rel32 from wrapper-tail back to RVA + displaced_len]
    X86FIX --> RJMP
    RJMP --> SEC[allocate next aligned VA + raw offset, write IMAGE_SECTION_HEADER with RWX + CNT_CODE]
    SEC --> BUMP[bump NumberOfSections, SizeOfImage, zero CheckSum]
    BUMP --> X86RELOC{x86?}
    X86RELOC -- yes --> RDIR[update DataDirectory BASERELOC to new combined table]
    X86RELOC -- no --> WJ[write 5-byte jmp rel32 at RVA, NOP-fill remaining displaced bytes]
    RDIR --> WJ
    WJ --> WRITE[serialize patched bytes to output path]
    WRITE --> OUT[patched.exe]

.(No content provided for translation.)```mermaid flowchart TB HOST[host main reaches patched RVA] --> RJMP[jmp rel32 to wrapper in new section] RJMP --> PUSH[pushfq, push all volatile regs and rbp] PUSH --> SAVE_RSP[mov rbp, rsp; and rsp, -16; sub rsp, 0x38 for shadow + spill alignment] SAVE_RSP --> ARGS[xor ecx,ecx; xor edx,edx; lea r8, vm_blob_rel32; xor r9d,r9d; spill 0 at rsp+0x20, 0 at rsp+0x28] ARGS --> CT["call qword ptr [rip + CreateThread_iat_disp32]"] CT --> WTHREAD[worker thread starts running vm_blob] CT --> REST[mov rsp, rbp; pop volatiles; popfq] REST --> DISP[execute the displaced original bytes verbatim] DISP --> RJMP2[jmp rel32 back to RVA + N_displaced] RJMP2 --> HOST_CONT[host main continues normally] WTHREAD --> VMBODY[vm_blob runs concurrently: stager beacons, mbox shows dialog, whatever]

root@kitploit:~
थ्रेडेड उप-मोड स्टेजर्स और बीकन के लिए सही आकार है। होस्ट main कभी ब्लॉक नहीं होता। वर्कर थ्रेड को वह जीवनचक्र विरासत में मिलता है जिसकी पेलोड को आवश्यकता होती है। यदि पेलोड `ExitProcess` को कॉल करता है, तो पूरी प्रक्रिया समाप्त हो जाती है, लेकिन एक गैर-समाप्त होने वाले पेलोड के लिए, जैसे कि हर C2 बीकन, होस्ट उसके साथ समानांतर में हमेशा चलता रहता है।

### Inline उप-मोड: `--detour-inline`

वही रैपर संरचना, लेकिन रैपर `CreateThread` के बजाय सीधे `call vm_blob` करता है। होस्ट main थ्रेड VM के लौटने तक ब्लॉक रहता है। उपयोगी जब लक्ष्य के IAT में `CreateThread` न हो, या बैकअप के रूप में जब थ्रेडेड base-reloc पथ किसी विशेष लक्ष्य पर लागू नहीं हो सकता।```mermaid
flowchart TB
    HOST[host main reaches patched RVA] --> RJMP[jmp rel32 to wrapper]
    RJMP --> SAVE[save flags + volatile regs + align]
    SAVE --> CALL[call rel32 vm_blob synchronously]
    CALL --> BLOCK[host main thread blocks here for the duration]
    BLOCK --> RET{vm_blob returns?}
    RET -- via ret --> REST[restore rsp, pop volatiles, popfq]
    RET -- via ExitProcess in payload --> DEAD[process terminates, no further code runs]
    REST --> DISP[execute displaced original bytes]
    DISP --> RJMP2[jmp rel32 back to RVA + N_displaced]
    RJMP2 --> HOST_CONT[host continues]

Scan mode: --scan

कोई आउटपुट फ़ाइल नहीं। इनपुट शेलकोड से CFG बनाता है और stderr पर --ranges उम्मीदवारों को प्रिंट करता है। प्रत्येक उम्मीदवार को eligible, coroutine, near-miss, या internal के रूप में वर्गीकृत किया जाता है, जहाँ internal का अर्थ है कि यह एक बड़े eligible उम्मीदवार द्वारा छायांकित है जो पहले से इसे कवर करता है। हाइब्रिड मोड में टूल को फिर से लागू करने से पहले रेंज आर्गुमेंट्स चुनने के लिए इसका उपयोग करें।```mermaid flowchart TB INP[shellcode.bin] --> CFGB[CFGBuilder + recursive descent over the whole input] CFGB --> ITER[for each block that is a call_target or jmp_target] ITER --> BFS[BFS the reachable subgraph from this entry] BFS --> SPAN[compute min_va..max_va span] SPAN --> CONT_CHK{every byte in span belongs to a visited block or to a known insn boundary?} CONT_CHK -- yes --> RET_CHK{any visited block ends with ret?} CONT_CHK -- no --> NM1[near-miss: fragmented or mid-fn data] RET_CHK -- yes --> EXT_CHK{any non-visited block has a successor pointing inside the span?} RET_CHK -- no --> CORO[coroutine candidate, no ret terminator] EXT_CHK -- yes --> NM2[near-miss: native branches to mid-range bytes] EXT_CHK -- no --> SIZE_CHK{span >= 5 bytes for the entry patch?} SIZE_CHK -- yes --> ELIGIBLE[eligible: prints with --ranges hint] SIZE_CHK -- no --> NM3[near-miss: body too short] ELIGIBLE --> DEDUP[shadow dedupe: drop entries whose reachable set is fully contained in an earlier eligible's reachable set] CORO --> DEDUP NM1 --> DEDUP NM2 --> DEDUP NM3 --> DEDUP DEDUP --> PRINT[stderr table sorted by category] PRINT --> END[exit 0]

root@kitploit:~
## प्रति सीड बहुरूपता अक्ष

स्थिर हस्ताक्षर को कितना प्रभावित करते हैं, इस क्रम में मोटे तौर पर सूचीबद्ध।

* सिफर परिवार। ARX, LcgSub, SBoxAdd, FeistelByte में से एक। बिल्ड समय पर उपयोग किए जाने वाले बाइटकोड एन्क्रिप्शन और डिस्पैचर फ़ेच पथ में उत्सर्जित इनलाइन डिक्रिप्ट दोनों को चुनता है। एन्क्रिप्ट और डिक्रिप्ट निर्माण द्वारा मेल खाते हैं।
* रजिस्टर स्लॉट लेआउट। VMState में `reg_count` स्लॉट होते हैं, प्रति सीड आकार 24 से 32। 16 आर्किटेक्चरल GPRs और 4 Tmp regs को प्रत्येक सीड में स्लॉट इंडेक्स का एक नया क्रमपरिवर्तन मिलता है।
* ऑपकोड-टू-हैंडलर मैपिंग। प्रत्येक कोडेक परिवार को प्रत्येक सीड में एक यादृच्छिक ऑपकोड बाइट सौंपा जाता है। 256-प्रविष्टि हैंडलर तालिका ऑपकोड द्वारा अनुक्रमित होती है; एन्कोडेड बाइटकोड मैप किए गए ऑपकोड को संदर्भित करता है।
* डिस्पैचर टोपोलॉजी। थ्रेडेड या सेंट्रल, प्रति सीड चुना गया।
* प्रस्तावना स्व-स्थान रणनीति। `call $+5; pop`, `lea reg, [rip+0]`, या एक jmp/call शफल।
* हैंडलर रजिस्टर अस्थायी। BR_CC हैंडलर अपनी 6 अस्थायी भूमिकाओं को वोलाटाइल पूल में क्रमपरिवर्तित करता है। स्टोर हैंडलर भी ऐसा ही करता है।
* जंक गैजेट घनत्व। 0 से 3, इंटर-हैंडलर कचरा उत्सर्जन को नियंत्रित करता है।
* IR अस्पष्टीकरण पास निर्णय। डेड-IR इंजेक्शन और ओपेक प्रेडिकेट प्रत्येक अपने स्वयं के उप-RNG का उपयोग करते हैं ताकि उनके निर्णय प्रति सीड नियतात्मक हों और अन्य अक्षों को परेशान न करें।
* बाइटकोड एन्क्रिप्शन प्रारंभिक स्थिति। प्रति सीड यादृच्छिक 64-बिट।

## परीक्षण किए गए पेलोड

इस उपकरण को कई Cobalt Strike, MSF, Sliver, और असंख्य अन्य शेलकोड नमूनों के विरुद्ध मान्य किया गया था।

## निर्माण

Visual Studio 2022, CMake 3.21 या नया, और vcpkg की आवश्यकता है। CMake प्रोजेक्ट vcpkg के मैनिफेस्ट मोड के माध्यम से Zydis और fmt को खींचता है।```
cmake -S . -B build
cmake --build build --config Release --target mkpivm

ज्ञात सीमाएँ

  • कोबाल्ट स्टेजर्स के लिए रेंज मोड एक स्टैंडअलोन लीफ के रूप में काम नहीं करता है। स्टेजर के हेल्पर फंक्शन कॉलर द्वारा प्रदान किए गए रजिस्टर स्टेट पर निर्भर करते हैं जो रनर प्रदान नहीं करता है। पूर्ण वर्चुअलाइजेशन या --pack वास्तव में बीकन करने वाले मार्ग हैं।
  • x86 थ्रेडेड डिटूर के लिए आवश्यक है कि टार्गेट में या तो ASLR न हो या जोड़े गए बेस रिलोकेशन एंट्रीज़ को स्वीकार करे, जो टूल मौजूद होने पर उत्सर्जित करता है। यदि टार्गेट का BASERELOC डेटा डीआईआर खराब या अनुपस्थित है, तो टूल इनलाइन मोड पर वापस आ जाता है।
  • लिफ्टर वर्तमान में SSE/AVX रजिस्टर मूव्स, एटॉमिक्स, CMPXCHG, RDMSR, या विशेषाधिकार प्राप्त निर्देशों को कवर नहीं करता है। उनका उपयोग करने वाले शेलकोड के लिए पैक मोड समाधान है।
  • --embed-into आउटपुट पर Authenticode हस्ताक्षर अमान्य कर दिए जाते हैं। PE चेकसम शून्य कर दिया जाता है।
  • आउटपुट ब्लॉब्स को रनटाइम पर RWX की आवश्यकता होती है क्योंकि इन-प्लेस डिक्रिप्शन ब्लॉब के अपने पेजों पर वापस लिखता है। अधिकांश लोडर जो शेलकोड चलाते हैं, वैसे भी RWX आवंटित करते हैं। RX-केवल पर जाने की कोई योजना नहीं है क्योंकि यह व्यापार RX को PEB वॉक और VirtualAlloc कॉल की लागत पर खरीदता है, जो शायद उस RWX पेज की तुलना में एक बुरा सिग्नेचर है जिसे वह बदलता है।
  • डिफ़ॉल्ट मोड के माध्यम से स्टेजलेस पेलोड को वर्चुअलाइज़ करना अभी तक समर्थित नहीं है, क्योंकि उन्हें VM में लपेटना बहुत जटिल है; --pack + --ranges को प्राथमिकता दें।

नोट्स

  • यह प्रोजेक्ट मोटे तौर पर प्रूफ-ऑफ-कॉन्सेप्ट शोध है। यदि इसे अच्छी प्रतिक्रिया मिलती है, तो मैं इसे अनुरोध के अनुसार विस्तारित करूंगा और योगदान का स्वागत करूंगा। हालाँकि, यह परीक्षण किए गए नमूनों के लिए स्थिर लग रहा था।
  • यदि आपका शेलकोड काम नहीं करता है, और आप इसे किसी Issue में डालना नहीं चाहते हैं, तो दुर्भाग्य से मैं आपकी मदद नहीं कर सकता। इसका परीक्षण Sliver, Cobalt Strike 4.12, MSF, Havoc, और कुछ अन्य अघोषित नमूनों पर किया गया था।
  • मेरे परीक्षण में, लाइव प्रक्रियाओं में VM का इंजेक्शन ठीक काम करता था। हालाँकि, जब PEs में एम्बेड करने की बात आती है, तो इसका परीक्षण MS Word जैसे व्यावसायिक सॉफ़्टवेयर से नहीं किया गया था, केवल सिंथेटिक परीक्षण, लेकिन यह शायद काम करता है। यदि नहीं, तो ठीक कर दूंगा।
  • 5/20/2026 तक (ऐसा लगता है अब समाप्त हो गया है), ऐसा प्रतीत होता है कि रेपो बॉट्स से भर गया था। तो, यह अद्भुत है। कृपया सभी खाली Github खातों को अनदेखा करें।
  • मैंने mkPIVM के बारे में कुछ AI-जनरेटेड पोस्ट देखा, जिसमें कहा गया था कि इसकी कमियां थीं:
    • 1). Linux सपोर्ट नहीं है, जो उचित है, और मैं इसे जल्द ही जोड़ूंगा।
    • 2). GUI नहीं है? क्या?
    • मुझे नहीं पता, मुझे लगा कि यह मजाकिया था।

योगदान

यह कुछ शानदार चीज़ है, हकीकत में आओ। यदि आप नए विचारों का योगदान देना चाहते हैं, अपने बग्स को ठीक करना चाहते हैं, मेरे लिए ठीक करने के लिए Issues सबमिट करना चाहते हैं, इत्यादि, तो करें।

टूल डाउनलोड करें