
Um PoC simples para invocar um shellcode cifrado usando uma chamada oculta
Um PoC simples para invocar um shellcode criptografado usando uma chamada oculta.
Este código usa um truque simples para ocultar a instrução que efetivamente saltará para o nosso shellcode. Isso deve tornar a análise estática ou emulação mais desafiadora.
Como sempre, se este conceito já foi explicado em outros artigos, envie-me uma mensagem e eu adicionarei com prazer às referências.
O layout de memória para usar esta técnica é o padrão e descrito na Figura 1.
┌───────────────────────────────┐
│ │
│ │
│ │
│ │
│ encrypted shellcode │
│ │
│ │
│ │
│ │
│ │
│ │
├───────────────────────────────┤
│ │
│ │
│ decryption loop │
│ │
│ │
└───────────────────────────────┘
Figura 1. Layout de Memória
O loop de descriptografia irá descriptografar o shellcode e saltar para ele. Toda a "mágica" está dentro do loop de descriptografia, pois após terminar de descriptografar o shellcode, o loop de descriptografia começará a descriptografar seu próprio código. A descriptografia da primeira instrução resultará em um salto para o nosso shellcode que é executado na próxima iteração do loop :)
Abaixo a parte relevante:
@decryption:
xor word ptr [eax], 06799h ; <jmp esi bytes> XOR <first two bytes of this instruction>
add eax, sizeof word
dec ecx
loop @decryption
Como você pode ver, o loop de descriptografia não contém nenhuma instrução que salte para o shellcode descriptografado. O código assembly é montado no seguinte formato binário:
66:8130 9967 | xor word ptr ds:[eax],6799
83C0 02 | add eax,2
49 | dec ecx
E2 F5 | loop 450006
neste caso, a chave de descriptografia deve ser 06799h, pois a operação XOR entre 8166h (os dois primeiros bytes da primeira instrução do loop de descriptografia) e 6799h (a chave XOR) é e6ffh que é montada como jmp esi. Em outras palavras:
0x8166 (xor word ptr ds:[eax],...) XOR 0x6799 (decryption key) == 0x6eff (jmp esi)
Ao definir o registrador ESI para o início do nosso shellcode, podemos alcançar a execução :)
Abaixo um exemplo de depuração. Inicialmente, o shellcode criptografado é copiado, seguido pelo código usado para descriptografar e chamar o shellcode. É possível notar que após a terceira execução do loop de descriptografia, a instrução xor word ptr ds:[eax],6799 muda para jmp esi.

Os passos para usar esta técnica são:
Para tornar o código de descriptografia menos identificável, é possível usar métodos alternativos para chamar o shellcode. Para ter mais liberdade, podemos considerar aumentar o tamanho do bloco que é criptografado durante cada iteração. No meu PoC, usei 2 bytes porque jmp esi precisa de dois bytes, mas podemos usar tamanhos de bloco de 4 ou 8 bytes, permitindo que o operador tenha mais alternativas que caibam em blocos de 4 ou 8 bytes. De acordo com a forma escolhida para chamar o shellcode, a constante de criptografia também mudará.