
Système de protection par machine virtuelle ARM64 ELF
Système de Protection par Machine Virtuelle pour ELF ARM64
Traduit les instructions natives ARM64 en bytecode VM personnalisé pour une protection au niveau des fonctions
🇨🇳 中文文档 • Fonctionnalités • Architecture • Démarrage rapide • Utilisation • Licence
VMPacker est un système de Protection par Machine Virtuelle (VMP) pour les binaires ELF Linux ARM64 (AArch64). Il décode les instructions natives ARM64 de la fonction cible en une représentation intermédiaire, les traduit en bytecode VM personnalisé et injecte un interpréteur VM embarqué dans le fichier ELF. À l'exécution, les fonctions protégées sont exécutées par l'interpréteur VM au lieu de nativement.
Code natif ARM64 → Décodage → Traduction → Bytecode VM personnalisé
↓
ELF original ← Injection ← Stub de l'interpréteur VM
vmp/
├── cmd/vmpacker/ # Point d'entrée CLI
│ ├── main.go # Analyse des arguments CLI + orchestration
│ └── vm_interp.bin # Interpréteur VM compilé (GCC, go:embed)
│
├── pkg/ # Bibliothèque principale Go
│ ├── arch/arm64/ # Support de l'architecture ARM64
│ │ ├── decoder.go # Décodeur d'instructions piloté par tables (implémente vm.Decoder)
│ │ ├── decode_*.go # Tables de motifs de décodage (DP-IMM/DP-REG/Branch/LdSt)
│ │ ├── translator.go # Traducteur ARM64 → bytecode VM
│ │ ├── tr_alu.go # Traduction des instructions ALU
│ │ ├── tr_branch.go # Traduction des instructions de branchement
│ │ ├── tr_loadstore.go # Traduction des instructions mémoire
│ │ ├── tr_bitfield.go # Traduction des instructions de champ de bits
│ │ └── tr_special.go # Instructions spéciales (ADRP/ADR)
│ ├── vm/ # Définitions de l'ISA VM
│ │ ├── types.go # Types partagés + interfaces (Decoder/Translator/Packer)
│ │ ├── opcodes.go # 58+ définitions d'opcodes VM (valeurs mappées aléatoirement)
│ │ └── disasm.go # Désassembleur de bytecode VM
│ └── binary/elf/ # Manipulation des binaires ELF
│ ├── packer.go # Injection VMP ELF (détournement PT_NOTE, génération de trampoline)
│ └── trampoline.go # Génération de code de trampoline
│
├── stub/ # Interpréteur VM en C (compilé en binaire plat PIC)
│ ├── vm_interp_clean.c # Boucle principale de l'interpréteur + points d'entrée
│ ├── vm_types.h # Contexte CPU VM (vm_ctx_t)
│ ├── vm_opcodes.h # Définitions d'opcodes côté C (synchronisées avec opcodes.go)
│ ├── vm_decode.h # Utilitaires de lecture du bytecode
│ ├── vm_token.h # Encodage/décodage des jetons + table de descripteurs
│ ├── vm_dispatch.h # Table de distribution indirecte
│ ├── vm_crc.h # Vérification d'intégrité CRC32
│ ├── vm_sections.h # Macros de dispersion des sections de gestionnaires
│ ├── vm_interp.lds # Script de l'éditeur de liens
│ └── vm_handlers/ # Gestionnaires d'instructions modulaires
│ ├── h_alu.h # Opérations arithmétiques/logiques
│ ├── h_mem.h # Accès mémoire
│ ├── h_branch.h # Branchement/saut
│ ├── h_cmp.h # Comparaison/conditionnel
│ ├── h_mov.h # Mouvement de données
│ ├── h_stack.h # Pile (PUSH/POP)
│ └── h_system.h # Système (SVC/MRS/BLR/BR/RET)
│
├── vmp-gui/ # Interface graphique Wails
│ ├── frontend/ # Vue 3 + Element Plus
│ └── backend/ # Liaisons Go backend
│
└── build/ # Outils pré-compilés + artefacts de test
Le projet utilise une architecture modulaire pilotée par interfaces, ce qui facilite l'extension à de nouveaux ISA et formats binaires :
// Interface du décodeur d'architecture — extensible à x86, RISC-V
type Decoder interface {
Decode(raw uint32, offset int) Instruction
InstName(op int) string
}
// Interface du traducteur de bytecode
type Translator interface {
Translate(instructions []Instruction) (*TranslateResult, error)
}
// Interface de l'injecteur de format binaire — extensible à PE, Mach-O
type Packer interface {
Process() error
}
graph LR
A[ELF d'entrée] --> B[Localiser la fonction cible]
B --> C[Extraire les instructions ARM64]
C --> D[Décoder ARM64]
D --> E[Traduire en bytecode VM]
E --> F[Chiffrer le bytecode par XOR]
F --> G[Injecter l'interpréteur VM]
G --> H[Générer le trampoline]
H --> I[Remplacer l'entrée de la fonction]
I --> J[ELF protégé en sortie]
git clone https://github.com/LeoChen-CoreMind/VMPacker.git
cd VMPacker
make all
# Protéger une seule fonction
./vmpacker -func check_license -v -o protected.elf original.elf
# Protéger plusieurs fonctions
./vmpacker -func "check_license,verify_token" -v -o protected.elf original.elf
# Spécifier une plage d'adresses
./vmpacker -addr "0x4006AC-0x400790:main" -v -o protected.elf original.elf
# Mode mixte
./vmpacker -addr "0x4006AC-0x400790:main" -func verify -o protected.elf original.elf
./vmpacker -info input.elf
# Construction standard (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 définit une architecture de jeu d'instructions (ISA) personnalisée avec des valeurs d'opcodes mappées aléatoirement pour augmenter la difficulté de rétro-ingénierie.
📖 Pour la table complète des opcodes avec les détails d'encodage, voir la documentation chinoise.
Les contributions sont les bienvenues ! Veuillez suivre ces directives :
git checkout -b feature/nouvelle-archgit commit -m 'feat: ajout du décodeur x86_64'git push origin feature/nouvelle-archNous suivons les Commits Conventionnels :
feat: Nouvelle fonctionnalitéfix: Correction de bugrefactor: Refactorisation du codedocs: Documentationtest: TestsCe projet est sous licence AGPL-3.0.
Pourquoi AGPL-3.0 :
CE LOGICIEL EST FOURNI "EN L'ÉTAT", SANS GARANTIE D'AUCUNE SORTE, EXPLICITE OU IMPLICITE, Y COMPRIS MAIS SANS S'Y LIMITER LES GARANTIES DE QUALITÉ MARCHANDE, D'ADÉQUATION À UN USAGE PARTICULIER ET D'ABSENCE DE CONTREFAÇON. EN AUCUN CAS LES AUTEURS OU TITULAIRES DU DROIT D'AUTEUR NE POURRONT ÊTRE TENUS RESPONSABLES DE TOUTE RÉCLAMATION, DOMMAGE OU AUTRE RESPONSABILITÉ, QUE CE SOIT DANS LE CADRE D'UNE ACTION CONTRACTUELLE, DÉLICTUELLE OU AUTRE, DÉCOULANT DE, OU EN RELATION AVEC LE LOGICIEL OU SON UTILISATION OU AUTRE INTERACTION AVEC LE LOGICIEL.
Ce projet est conçu pour fournir une protection légitime de la propriété intellectuelle aux développeurs de logiciels, aidant à protéger les algorithmes fondamentaux et le code critique dans les logiciels commerciaux contre la rétro-ingénierie ou le vol non autorisé.
Avis à l'utilisateur :
- Vous devez respecter toutes les lois et réglementations applicables dans votre juridiction lors de l'utilisation de ce logiciel
- Il est strictement interdit d'utiliser ce logiciel à des fins illégales, y compris mais sans s'y limiter : développement de logiciels malveillants, contournement d'audits de sécurité, violation des droits de propriété intellectuelle d'autrui, ou compromission de la sécurité des systèmes informatiques
- Le(s) auteur(s) ne pourra(ont) être tenu(s) responsable(s) des conséquences directes ou indirectes résultant de l'utilisation de ce logiciel par quiconque
- En téléchargeant, utilisant ou distribuant ce logiciel, vous reconnaissez avoir lu et accepté les termes ci-dessus
LeoChen — @LeoChen-CoreMind
Copyright © 2026 LeoChen. Tous droits réservés.
| Couche | Technique | Description |
|---|
| Protection VM | ISA personnalisé | Opcodes mappés aléatoirement — les rétro-ingénieurs ne peuvent pas identifier directement la sémantique des instructions |
| OpcodeCryptor | Chiffrement par instruction | enc[pc] = op[pc] ^ (key ^ (pc * 0x9E3779B9)) |
| Inversion du bytecode | Inversion de l'ordre d'exécution | Instructions stockées dans l'ordre inverse ; l'interpréteur parcourt en arrière |
| Entrée tokenisée | Trampoline à 3 instructions | La fonction originale est remplacée par une entrée tokenisée, masquant l'emplacement réel du bytecode |
| Distribution indirecte | Table de pointeurs de fonction | Remplie à l'exécution sur la pile, brisant les références croisées IDA |
![]() | ![]() | ![]() |
| Liste des fonctions | Analyse et sélection | Options de protection |
![]() | ![]() | |
| Logs en temps réel | Protection terminée |
| Option | Défaut | Description |
|---|
-func | — | Nom(s) de fonction(s) à protéger (séparés par des virgules) |
-addr | — | Protection par adresse (0xDEBUT-0xFIN[:nom]) |
-o | input.vmp | Chemin du fichier de sortie |
-v | false | Sortie verbeuse (afficher le désassemblage) |
-strip | true | Supprimer la table des symboles |
-debug | false | Générer un fichier de correspondance de débogage ARM64 → bytecode VM |
-token | true | Mode d'entrée par jeton |
-info | false | Afficher uniquement les informations ELF |
| Catégorie | Nombre | Description |
|---|
| Mouvement de données | 3 | MOV_IMM64, MOV_IMM32, MOV_REG |
| Arithmétique/Logique | 21 | ADD, SUB, MUL, XOR, AND, OR, SHL, SHR, ASR, NOT, ROR, UMULH + variantes _IMM |
| Accès mémoire | 8 | LOAD/STORE 8/16/32/64 |
| Branchement/Saut | 13 | JMP, JE, JNE, JL, JGE, JGT, JLE, JB, JAE, JBE, JA, TBZ, TBNZ |
| Comparaison | 6 | CMP, CMP_IMM, CCMP_REG, CCMP_IMM, CCMN_REG, CCMN_IMM |
| Pile | 2 | PUSH, POP |
| Système/Spécial | 8 | NOP, HALT, RET, CALL_NATIVE, CALL_REG, BR_REG, SVC, MRS |
| SIMD | 2 | VLD16, VST16 |
| Total | 63 |