Skip to content
KitploitKITPLOIT
도구익스플로잇블로그
Log in
제출
도구익스플로잇블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

피드문의개인정보© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
mkPIVM — 임의의 x86/x64 셸코드로부터 다형적이며 위치 독립적인 가상 머신(PIVM)을 생성합니다. | Kitploit
도구/GitHubGitHub/d7ead/mkpivm
Payload GenerationExploitationReverse EngineeringShellcodeMalware AnalysisRed Teaming
GitHubd7ead/mkpivm

mkPIVM

임의의 x86/x64 셸코드로부터 다형적이며 위치 독립적인 가상 머신(PIVM)을 생성합니다.

저장소 보기
40917221개월 전Kitploit 검토 완료

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유


읽기 연구 논문 (1.0.0용으로 작성됨).

mkPIVM은 Windows x86 및 x64용 다형성 위치 독립 셸코드 가상화기입니다 (Linux 곧 지원 예정).

원시 셸코드를 입력하면 또 다른 원시 blob이 생성됩니다. 이 blob은 원본 명령어의 리프팅된(lifted) 상태로 암호화되어 저장된 버전을 해석하는 작은 가상 머신입니다. 출력 자체는 위치 독립 코드이며, 원본 셸코드가 실행될 수 있는 모든 곳(원격 스레드 로더부터 코드 케이브 디투어까지)에서 동작합니다. 모든 per-seed 노브는 독립적으로 변합니다: cipher family, register slot layout, opcode-to-handler permutation, dispatcher topology, junk-gadget pattern, IR obfuscation insertion points. 동일한 입력에서 생성된 두 빌드는 수만 바이트 중에서 우연히 일치하는 바이트가 백 개 미만입니다.

이유: 네이티브 셸코드는 시그니처를 통한 탐지가 쉽습니다. 이를 per-instance VM에 per-instance 암호로 감싸면 유휴 상태로 남은 유용한 정보가 없으며, 명령어를 바이트코드로 리프팅하여 디스크 바이트와 x86을 아는 디스어셈블러 사이에 또 다른 장벽을 세웁니다. 문헌 조사에 따르면, 이 정확한 파이프라인(원시 PIC 입력, 원시 다형성 VM PIC 출력)을 제공하는 공개 도구는 없는 것으로 보입니다. 그래서 연구 논문에서 요구한 대로 언급했습니다. 솔직히 말해서, 제가 맞다면(공개적으로는 아무도 이 작업을 한 적이 없다고 확신합니다), 꽤 놀랍습니다. 그럼에도 불구하고 즐기시길 바랍니다.

관련 연구 및 계획

  • Linux 지원이 곧 추가될 예정입니다.

빠른 시작```

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

Your PIVM은 뜨겁고 준비되었습니다. 그것이 가장 간단한 경로입니다. 몇 가지 다른 모드는 원래 명령어가 가상화되는 정도, 출력이 독립형 blob인지 패치된 PE인지, 리프트가 전혀 실행되는지 여부를 다르게 합니다.

# Showcase

증거가 있습니다. 아래에서 mkPIVM이 Meterpreter 스테이저 (바닐라 btw)를 완전히 가상화하고, explorer.exe에 인젝션한 후, 저희가 콜백을 캡처하는 동영상을 볼 수 있습니다. 물론 이것은 예시일 뿐이며, 셸코드의 명령어가 지원된다면 mkPIVM은 훨씬 더 많은 곳에 적용될 수 있습니다. 지원되지 않는다면 Issue를 생성하고 셸코드를 보내주세요, 제가 처리하겠습니다.

여기서 [보기](https://github.com/D7EAD/mkPIVM/raw/refs/heads/main/media/mkpivm-showcase.mp4). ./media에 호스팅되어 있으며, 안타깝게도 임베드할 수 없습니다.

다음은 그 정확히 가상화된 샘플에 대한 VirusTotal 보고서입니다 (2026/04/06 기준).

<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">

이 도구의 출력 엔트로피 텔레메트리에 세심한 주의를 기울였으며, 그 결과 (패킹 모드 외) ntdll.dll이나 kernel32.dll과 같은 일반적인 Windows WinAPI DLL보다 낮은 엔트로피의 셸코드가 생성됩니다. 엔트로피 비교는 대략 다음과 같습니다...

| File | Bytes | Entropy |
|------|-------|---------|
| `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** |

## Modes at a glance

| Mode | Flags | What changes |
|------|-------|--------------|
| Default | none | 전체 입력을 리프트합니다. 모든 것이 가상화됩니다. |
| Packer | `--pack` | 리프트하지 않습니다. 입력을 암호화된 데이터로 감싸고, 런타임에 복호화한 후 점프합니다. |
| Hybrid | `--ranges A:B,...` | 선택한 바이트 범위만 리프트합니다. 나머지는 네이티브로 유지됩니다. |
| Stacked | `--pack --ranges A:B` | 하이브리드 blob을 빌드한 후 패킹으로 감쌉니다. |
| Detour | `--embed-into PE --at RVA` | 미리 빌드된 blob을 가져와 PE에 임베드하고, 선택한 RVA에 jmp를 패치합니다. |
| Scan | `--scan` | 입력의 CFG에서 적격한 `--ranges` 후보를 출력한 후 종료합니다. |
| RX | `--rx` | PAGE_EXECUTE_READ blob입니다. 데이터 아일랜드는 저장 시 암호화된 상태로 유지됩니다. blob 내부의 PEB 워커가 VirtualProtect를 해결하고 state_init에서 제자리 복호화합니다. |
| RX w/ Loader | `--rx --rx-loader-vp` | `--rx`와 유사하지만, 로더가 VirtualProtect를 blob의 첫 번째 인자로 전달합니다. PEB 워커가 없습니다. |

모든 모드는 `--seed`, `--arch`, `--input-format` 및 `--format`을 적용합니다. 빌드 파이프라인과 런타임 흐름에 대한 내용은 아래 각 모드 섹션을 참조하세요.

## Default virtualization

리프터는 전체 CFG를 탐색하고 모든 명령어를 사용자 정의 IR로 낮춥니다. IR은 두 개의 난독화 패스를 거친 후, 각 명령어를 시드별 바이트코드 형태로 인코딩하는 코덱을 통과합니다. 블록 테이블, 핸들러 테이블 및 데이터 아일랜드는 바이트코드와 동일한 바이트별 스트림 암호로 암호화됩니다. 런타임에 프롤로그는 이 세 영역을 제자리에서 복호화하고, 디스패처 루프는 바이트코드 바이트를 한 번에 하나씩 가져와 복호화한 후 작업을 수행하는 핸들러로 디스패치합니다.

### Build pipeline

빌드가 원시 셸코드를 출력된 가상화된 blob으로 변환하기 위해 수행하는 단계, 처음부터 끝까지. _아래 모든 그래프는 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에서 방출된 blob을 호출할 때, 프롤로그부터 디스패처 페치 및 다양한 종료 경로까지의 동작을 설명합니다.```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]

런타임 논스 트릭은 핵심 메모리 스캔 방어 기법입니다: 핸들러 테이블은 `rdtsc XOR cipher_init`에서 파생된 값으로 XOR 처리된 상태로 메모리에 위치하므로, 동일한 blob을 로드하는 두 프로세스는 바이트 단위로 서로 다른 핸들러 테이블을 가지게 됩니다. 디스패처는 조회 시 추가 XOR 한 번으로 마스크를 해제합니다.

## 패커 모드: `--pack`
도구 다운로드