
Un semplice PoC per invocare uno shellcode crittografato tramite una chiamata nascosta
Un semplice PoC per invocare uno shellcode crittografato utilizzando una chiamata nascosta.
Questo codice utilizza un semplice trucco per nascondere l'istruzione che effettivamente salterà al nostro shellcode. Questo dovrebbe rendere l'analisi statica o l'emulazione più impegnative.
Come sempre, se questo concetto è già stato spiegato in altri articoli, inviami un messaggio e lo aggiungerò volentieri ai riferimenti.
Il layout di memoria per utilizzare questa tecnica è quello standard ed è descritto in Figura 1.
┌───────────────────────────────┐
│ │
│ │
│ │
│ │
│ encrypted shellcode │
│ │
│ │
│ │
│ │
│ │
│ │
├───────────────────────────────┤
│ │
│ │
│ decryption loop │
│ │
│ │
└───────────────────────────────┘
Figure1. Memory Layout
Il ciclo di decifratura decifrerà lo shellcode e salterà ad esso. Tutta la "magia" è dentro il ciclo di decifratura, poiché dopo aver finito di decifrare lo shellcode, il ciclo di decifratura inizierà a decifrare il proprio codice. La decifratura della prima istruzione risulterà in un salto al nostro shellcode che viene eseguito alla successiva iterazione del ciclo :)
Di seguito la parte rilevante:
@decryption:
xor word ptr [eax], 06799h ; <jmp esi bytes> XOR <first two bytes of this instruction>
add eax, sizeof word
dec ecx
loop @decryption
Come puoi vedere, il ciclo di decifratura non contiene alcuna istruzione che salti allo shellcode decifrato. Il codice assembly è assemblato nel seguente formato binario:
66:8130 9967 | xor word ptr ds:[eax],6799
83C0 02 | add eax,2
49 | dec ecx
E2 F5 | loop 450006
in questo caso, la chiave di decifratura deve essere 06799h, poiché l'operazione XOR tra 8166h (i primi due byte della prima istruzione del ciclo di decifratura) e 6799h (la chiave XOR) è e6ffh che viene assemblata in jmp esi. In altre parole:
0x8166 (xor word ptr ds:[eax],...) XOR 0x6799 (decryption key) == 0x6eff (jmp esi)
Impostando il registro ESI all'inizio del nostro shellcode, possiamo ottenere l'esecuzione :)
Di seguito un esempio di debug. Inizialmente lo shellcode crittografato viene copiato, seguito dal codice utilizzato per decifrare e chiamare lo shellcode. È possibile notare che dopo la terza esecuzione del ciclo di decifratura, l'istruzione xor word ptr ds:[eax],6799 cambia in jmp esi.

I passaggi per utilizzare questa tecnica sono:
Per rendere il codice di decifratura meno identificabile, è possibile utilizzare metodi alternativi per chiamare lo shellcode. Per avere più libertà, possiamo considerare di aumentare la dimensione del blocco che viene crittografato durante ogni iterazione. Nel mio PoC ho usato 2 byte perché jmp esi richiede due byte, ma possiamo usare blocchi da 4 o 8 byte, consentendo all'operatore di avere più alternative che si adattano a blocchi da 4 o 8 byte. A seconda del metodo scelto per chiamare lo shellcode, anche la costante di crittografia cambierà.