
ARM64 ELF 가상 머신 보호 시스템
ARM64 ELF 가상 머신 보호 시스템
ARM64 네이티브 명령어를 사용자 정의 VM 바이트코드로 변환하여 함수 수준의 코드 보호를 제공합니다.
🇨🇳 中文文档 • 기능 • 아키텍처 • 빠른 시작 • 사용법 • 라이선스
VMPacker는 ARM64 (AArch64) Linux ELF 바이너리를 위한 가상 머신 보호 (VMP) 시스템입니다. 대상 함수의 네이티브 ARM64 명령어를 중간 표현으로 디코딩하고, 이를 사용자 정의 VM 바이트코드로 변환한 후, ELF 파일에 임베디드 VM 인터프리터를 주입합니다. 런타임 시 보호된 함수는 네이티브로 실행되지 않고 VM 인터프리터에 의해 실행됩니다.
ARM64 Native Code → Decode → Translate → Custom VM Bytecode
↓
Original ELF ← Inject ← VM Interpreter Stub
| 계층 | 기술 | 설명 |
|---|---|---|
| VM 보호 | 사용자 정의 ISA | 무작위로 매핑된 opcode — 리버스 엔지니어가 명령어 의미를 직접 식별할 수 없음 |
| OpcodeCryptor | 명령어별 opcode 암호화 | enc[pc] = op[pc] ^ (key ^ (pc * 0x9E3779B9)) |
| 바이트코드 역순 | 실행 순서 역전 | 명령어가 역순으로 저장됨; 인터프리터가 역방향으로 탐색 |
| 토큰 진입 | 3-명령어 트램펄린 | 원본 함수가 토큰화된 진입점으로 대체되어 실제 바이트코드 위치 숨김 |
| 간접 디스패치 | 함수 포인터 점프 테이블 | 런타임 시 스택에 채워져 IDA 크로스 레퍼런스 차단 |
![]() |
![]() |
![]() |
| 함수 목록 | 분석 및 선택 | 보호 옵션 |
![]() |
![]() |
|
| 실시간 로그 | 보호 완료 |
vmp/
├── cmd/vmpacker/ # CLI 진입점
│ ├── main.go # CLI 인수 파싱 + 조정
│ └── vm_interp.bin # 컴파일된 VM 인터프리터 (GCC, go:embed)
│
├── pkg/ # Go 핵심 라이브러리
│ ├── arch/arm64/ # ARM64 아키텍처 지원
│ │ ├── decoder.go # 테이블 기반 명령어 디코더 (vm.Decoder 구현)
│ │ ├── decode_*.go # 디코드 패턴 테이블 (DP-IMM/DP-REG/Branch/LdSt)
│ │ ├── translator.go # ARM64 → VM 바이트코드 변환기
│ │ ├── tr_alu.go # ALU 명령어 변환
│ │ ├── tr_branch.go # 분기 명령어 변환
│ │ ├── tr_loadstore.go # 메모리 명령어 변환
│ │ ├── tr_bitfield.go # 비트필드 명령어 변환
│ │ └── tr_special.go # 특수 명령어 (ADRP/ADR)
│ ├── vm/ # VM ISA 정의
│ │ ├── types.go # 공유 타입 + 인터페이스 (Decoder/Translator/Packer)
│ │ ├── opcodes.go # 58+ VM opcode 정의 (무작위 매핑된 값)
│ │ └── disasm.go # VM 바이트코드 디스어셈블러
│ └── binary/elf/ # ELF 바이너리 조작
│ ├── packer.go # ELF VMP 주입 (PT_NOTE 하이재킹, 트램펄린 생성)
│ └── trampoline.go # 트램펄린 코드 생성
│
├── stub/ # C VM 인터프리터 (PIC 플랫 바이너리로 컴파일)
│ ├── vm_interp_clean.c # 인터프리터 메인 루프 + 진입점
│ ├── vm_types.h # VM CPU 컨텍스트 (vm_ctx_t)
│ ├── vm_opcodes.h # C 측 opcode 정의 (opcodes.go와 동기화)
│ ├── vm_decode.h # 바이트코드 읽기 유틸리티
│ ├── vm_token.h # 토큰 인코딩/디코딩 + 디스크립터 테이블
│ ├── vm_dispatch.h # 간접 디스패치 점프 테이블
│ ├── vm_crc.h # CRC32 무결성 검사
│ ├── vm_sections.h # 핸들러 섹션 분산 매크로
│ ├── vm_interp.lds # 링커 스크립트
│ └── vm_handlers/ # 모듈식 명령어 핸들러
│ ├── h_alu.h # 산술/논리 연산
│ ├── h_mem.h # 메모리 접근
│ ├── h_branch.h # 분기/점프
│ ├── h_cmp.h # 비교/조건부
│ ├── h_mov.h # 데이터 이동
│ ├── h_stack.h # 스택 (PUSH/POP)
│ └── h_system.h # 시스템 (SVC/MRS/BLR/BR/RET)
│
├── vmp-gui/ # Wails GUI 프론트엔드
│ ├── frontend/ # Vue 3 + Element Plus
│ └── backend/ # Go 백엔드 바인딩
│
└── build/ # 사전 컴파일된 도구 + 테스트 아티팩트
이 프로젝트는 인터페이스 기반 모듈형 아키텍처를 사용하여 새로운 ISA 및 바이너리 형식으로 쉽게 확장할 수 있습니다:
// 아키텍처 디코더 인터페이스 — x86, RISC-V로 확장 가능
type Decoder interface {
Decode(raw uint32, offset int) Instruction
InstName(op int) string
}
// 바이트코드 변환기 인터페이스
type Translator interface {
Translate(instructions []Instruction) (*TranslateResult, error)
}
// 바이너리 형식 주입기 인터페이스 — PE, Mach-O로 확장 가능
type Packer interface {
Process() error
}
graph LR
A[입력 ELF] --> B[대상 함수 찾기]
B --> C[ARM64 명령어 추출]
C --> D[ARM64 디코딩]
D --> E[VM 바이트코드로 변환]
E --> F[XOR 바이트코드 암호화]
F --> G[VM 인터프리터 주입]
G --> H[트램펄린 생성]
H --> I[함수 진입점 교체]
I --> J[보호된 ELF 출력]
git clone https://github.com/LeoChen-CoreMind/VMPacker.git
cd VMPacker
make all
# 단일 함수 보호
./vmpacker -func check_license -v -o protected.elf original.elf
# 여러 함수 보호
./vmpacker -func "check_license,verify_token" -v -o protected.elf original.elf
# 주소 범위 지정
./vmpacker -addr "0x4006AC-0x400790:main" -v -o protected.elf original.elf
# 혼합 모드
./vmpacker -addr "0x4006AC-0x400790:main" -func verify -o protected.elf original.elf
./vmpacker -info input.elf
| 옵션 | 기본값 | 설명 |
|---|---|---|
-func | — | 보호할 함수 이름 (쉼표로 구분) |
-addr | — | 주소로 보호 (0xSTART-0xEND[:name]) |
-o | input.vmp | 출력 파일 경로 |
-v | false | 상세 출력 (디스어셈블리 표시) |
-strip | true | 심볼 테이블 제거 |
-debug | false | ARM64 → VM 바이트코드 디버그 매핑 파일 생성 |
-token | true | 토큰 기반 진입 모드 |
-info | false | ELF 정보만 출력 |
# 표준 빌드 (GCC)
aarch64-linux-gnu-gcc -Os -nostdlib -fPIC -ffreestanding \
-o stub.elf stub/vm_interp_clean.c \
-T stub/vm_interp.lds
aarch64-linux-gnu-objcopy -O binary stub.elf vm_interp.bin
go build -o vmpacker ./cmd/vmpacker/
cd vmpacker
make gui
VMPacker는 무작위로 매핑된 opcode 값을 가진 사용자 정의 명령어 집합 아키텍처(ISA)를 정의하여 리버스 엔지니어링 난이도를 높입니다.
📖 전체 opcode 테이블과 인코딩 상세 내용은 중국어 문서를 참조하세요.