
Un virtualiseur de code x86-64 pour l'obfuscation basée sur VM
Un virtualiseur de code x86-64 pour l'obfuscation basée sur une machine virtuelle.
*La prise en charge de PE n'a été testée que sur des binaires compilés via MinGW-w64
CMake récupérera toutes ces dépendances, vous n'avez donc pas besoin de les installer vous-même.
| Nom | Version |
|---|
| CMake | 3.25+ |
| Zydis | 4.1.0+ |
| zasm | Dernière |
| LIEF | 0.15.1+ |
Un compilateur compatible C++23 est nécessaire pour compiler.
git clone https://github.com/dmaivel/covirt.git
cd covirt
mkdir build
cd build
cmake ..
cmake --build . --config Release
Si vous compilez sur Windows via Visual Studio, vous devez utiliser clang-cl : cmake .. -T ClangCL -A x64.
Usage: covirt [--help] [--version] [--output OUTPUT_PATH] [--vm_code_size MAX] [--vm_stack_size SIZE] [--no_self_modifying_code] [--no_mixed_boolean_arith] [--show_dump_table] INPUT_PATH
Code virtualizer for x86-64 ELF & PE binaries
Positional arguments:
INPUT_PATH chemin vers le binaire d'entrée à virtualiser
Optional arguments:
-h, --help affiche le message d'aide et quitte
-v, --version affiche les informations de version et quitte
-o, --output OUTPUT_PATH spécifie le fichier de sortie [par défaut : INPUT_PATH.covirt]
-vcode, --vm_code_size MAX spécifie la taille totale maximale autorisée des instructions levées (lifted bytes) [par défaut : 2048]
-vstack, --vm_stack_size SIZE spécifie la taille de la pile virtuelle [par défaut : 2048]
-no_smc, --no_self_modifying_code désactive le passage SMC
-no_mba, --no_mixed_boolean_arith désactive le passage MBA
-d, --show_dump_table affiche le désassemblage des instructions de la VM
Pour que covirt sache quelles fonctions doivent être virtualisées, vous devez ajouter les marqueurs de début et de fin dans votre code source, comme ceci :
#include "covirt_stub.h"
int my_function(...)
{
int result = 0;
__covirt_vm_start();
// ...
__covirt_vm_end();
return result;
}
[!IMPORTANT]
- Ne placez pas
__covirt_vm_enddans des emplacements inaccessibles (par exemple après un return), car cela empêcherait l'émission du stub de fin.- Les stubs
__covirt_vm_...();ne fonctionneront pas avecMSVCcar ils utilisent l'assembleur inline.- La prise en charge de
SSE4est requise.

#include <covirt_stub.h>
#include <stdio.h>
int calculate(int a, int b)
{
int result = 0;
__covirt_vm_start();
for (int i = 0; i < 10; i++)
if (i > 5)
result += result + a;
else
result += (result >> 1) + b;
printf("result = %d\n", result);
__covirt_vm_end();
return result;
}
int main()
{
calculate(5, 12);
}
L'application exemple ci-dessus a été virtualisée en utilisant covirt a.out -d, ce qui affiche un dump des instructions de la VM après l'obfuscation et la virtualisation. L'implémentation actuelle de la VM pousse la plupart des opérandes sur la pile pour les traiter, réduisant ainsi la complexité du codage des instructions de la VM. Pour les instructions qui n'ont pas de gestionnaire défini dans la VM, elles seront exécutées nativement (vm_exit -> instruction native -> vm_enter). L'appel de fonctions suit le même pipeline : on sort, on appelle la fonction, puis on rentre à nouveau dans la VM. Ensemble, ces transformations augmentent considérablement la taille des binaires :
a.out en tant qu'ELF : 15.5 kB -> 1.0 MBa.out en tant que PE : 259.3 kB -> 1.3 MB| Description | IDA |
|---|---|
Décompilation IDA de vm_entry, obfusquée uniquement avec le passage MBA. Plus de 27k lignes de code ont été générées par le décompilateur. | ![]() |
Désassemblage IDA de vm_entry, obfusquée avec les passages MBA et SMC. La décompilation ne fonctionne pas. | ![]() |