Skip to content
KitploitKITPLOIT
StrumentiExploitsBlog
Log in
Invia
StrumentiExploitsBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

··Feed·Contatto·Privacy·© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
VMProtect-devirtualization — Giocando con la protezione software VMProtect. Deoffuscazione automatica di funzioni pure utilizzando esecuzione simbolica e LLVM. | Kitploit
Strumenti/GitHubGitHub/jonathansalwan/vmprotect-devirtualization
Analisi StaticaAnalisi Dinamica (Sandboxing)Reverse EngineeringFuzzingAnalisi di Binari
GitHubjonathansalwan/vmprotect-devirtualization

VMProtect-devirtualization

Giocando con la protezione software VMProtect. Deoffuscazione automatica di funzioni pure utilizzando esecuzione simbolica e LLVM.

Vedi Repository

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →
1.5k208164 anni faRevisionato da Kitploit
Condividi

Devirtualizzazione VMProtect

Un approccio dinamico sperimentale per devirtualizzare funzioni pure protette da VMProtect 3.x

 

 

  • TL;DR
  • Introduzione
  • L'approccio
    • Esempio 1: Una semplice operazione bit a bit protetta
    • Esempio 2: Un'operazione MBA protetta
    • Esempio 3: Più di un blocco di base
  • Conclusioni e limitazioni
  • Riferimenti

 

 

TL;DR

Condivido alcune note su un approccio dinamico per devirtualizzare funzioni pure protette da VMProtect. Questo approccio ha mostrato risultati molto buoni se la funzione virtualizzata contiene un solo blocco di base (indipendentemente dalla sua dimensione). Si tratta di uno scenario comune quando i binari proteggono operazioni aritmetiche. Tuttavia, questo approccio è un po' più sperimentale quando la funzione target contiene più di un blocco di base. Cionondimeno, siamo riusciti a devirtualizzare e ricostruire il codice binario da campioni che contengono 2 blocchi di base, il che suggerisce che è possibile devirtualizzare completamente piccole funzioni in modo dinamico.

Introduzione

VMProtect è una protezione software che protegge il codice eseguendolo attraverso una macchina virtuale con architettura non standard. Questa protezione è un ottimo campo di gioco per gli amanti dell'assembly [0, 1, 2, 3, 4, 5, 6, 11]. Inoltre, esistono già numerosi strumenti che attaccano questa protezione [7, 8, 9, 12, 13]. Nel 2016 abbiamo dato un'occhiata alla soluzione di protezione software Tigress e siamo riusciti a sconfiggere la sua virtualizzazione utilizzando l'esecuzione simbolica e LLVM. Questo approccio è stato presentato a DIMVA 2018 [10] e volevo testarlo su VMProtect. Nota che non esiste una soluzione magica che funzioni su tutti i binari, ci sono sempre compromessi a seconda del target e dei tuoi obiettivi. Questo modesto contributo mira a fornire un esempio di attacco dinamico contro funzioni pure che sono virtualizzate da VMProtect. Il principale vantaggio di un attacco dinamico è che sconfigge per progettazione alcune protezioni statiche di VMProtect come il codice auto-modificante, la crittografia delle chiavi e degli operandi, ecc.

Consideriamo una funzione pura una funzione con un numero finito di percorsi e che non ha effetti collaterali. Possono esserci diversi input ma un solo output. Di seguito è riportato un esempio di funzione pura:```cpp int secret(int x, int y) { int r = x ^ y; return r; }

# L'approccio

Ci basiamo sull'intuizione chiave che una traccia offuscata T' (dal codice offuscato P') combina istruzioni originali del codice originale P (la traccia T corrispondente a T' nel codice originale) e istruzioni della macchina virtuale VM tali che T' = T + VM(T). Se siamo in grado di distinguere tra queste due sottosequenze di istruzioni T e VM(T), possiamo quindi ricostruire un percorso del programma originale P a partire da una traccia T'. Ripetendo questa operazione per coprire tutti i percorsi del programma virtualizzato, saremo in grado di ricostruire il programma originale P. Nel nostro esempio pratico, il codice originale ha un numero finito di percorsi eseguibili, cosa che accade in molte situazioni che coinvolgono la protezione della proprietà intellettuale. Per fare ciò, procediamo con i seguenti passaggi:

1. Identificare la funzione virtualizzata e i suoi argomenti
2. Generare una traccia VMProtect del target
3. Rieseguire la traccia VMP e costruire espressioni simboliche per ottenere la relazione tra input e output
4. Applicare ottimizzazioni sulle espressioni simboliche per evitare il più possibile le istruzioni della VM
5. Elevare la nostra rappresentazione simbolica a LLVM-IR per costruire una nuova versione non protetta del target

## Esempio 1: Una semplice operazione bit a bit

Prendiamo come primo esempio la seguente funzione: prende due input e restituisce `x ^ y` che è protetta da VMProtect.

```c
int xor(int x, int y) {
  return x ^ y;
}
``````cpp
int secret(int x, int y) {
  VMProtectBegin("secret");
  int r = x ^ y;
  VMProtectEnd();
  return r;
}

Iniziamo identificando dove le funzioni utilizzano VMProtect e quanti argomenti hanno. Per il nostro esempio, potremmo avere qualcosa come il seguente:

Solo dalla lettura del codice sappiamo che la funzione inizia all'indirizzo 0x4011c0, ha due argomenti a 32 bit (edi e esi) e termina a 0x4011ef. Questo è tutto il reverse-engineering di cui abbiamo bisogno. Le parti successive saranno automatiche. Ora dobbiamo generare una traccia di esecuzione di questa funzione virtualizzata. Per farlo, utilizziamo un Pintool. Necessita solo di un indirizzo start e uno end (per il nostro esempio, 0x4011c0 e 0x4011ef) che rappresentano l'intervallo di strumentazione. Si noti che qualsiasi tipo di DBI o emulatore potrebbe svolgere questo compito.``` $ ./pin/pin -t ./pin/source/tools/VMP_Trace/obj-intel64/VMP_Trace.so -start 4198848 -end 4198895 -- ./vmp_binaries/binaries/sample2.vmp.bin 1 2 &> ./vmp_traces/sample2.vmp.trace

Puoi vedere il risultato [qui](https://github.com/jonathansalwan/vmprotect-devirtualization/blob/main/vmp_traces/sample2.vmp.trace). Il formato delle tracce utilizza tre tipi di operazioni: `mr`, `r` e `i`.
`mr` è un accesso in lettura alla memoria eseguito dall'istruzione `i`, e `r` sono i registri della CPU. Per esempio:```
mr:0x7ffda459d718:8:0x227db4f8
r:0x40200a:0x0:0x7ffda459f571:0x2:0x40200a:0x0:0x0:0x7ffda459d688:0x0:0x0:0x7feee9b80ac0:0x7feee9b8000f:0xad1c3e:0x0:0x0:0x0
i:0x89173e:8:488BB42490000000

Abbiamo una lettura di memoria che carica una costante di 8 byte 0x227db4f8 dall'indirizzo 0x7ffda459d718. L'istruzione viene eseguita all'indirizzo 0x89173e e il suo opcode lungo 8 byte è 488BB42490000000 che è un mov rsi, qword ptr [rsp + 0x90]. Lo stato dei registri prima dell'esecuzione è il seguente:

Scarica lo strumento