
Простой PoC для вызова зашифрованного shellcode с помощью скрытого вызова.
Простая PoC для вызова зашифрованного шеллкода с помощью скрытого вызова.
Этот код использует простой трюк для скрытия инструкции, которая фактически перейдёт к нашему шеллкоду. Это должно сделать статический анализ или эмуляцию более сложными.
Как всегда, если эта концепция уже была объяснена в других статьях, просто отправьте мне сообщение, и я с радостью добавлю её в список ссылок.
Макет памяти для использования этой техники является стандартным и описан на Рисунке 1.
┌───────────────────────────────┐
│ │
│ │
│ │
│ │
│ encrypted shellcode │
│ │
│ │
│ │
│ │
│ │
│ │
├───────────────────────────────┤
│ │
│ │
│ decryption loop │
│ │
│ │
└───────────────────────────────┘
Рисунок 1. Макет памяти
Цикл дешифрования расшифрует шеллкод и перейдёт к нему. Вся «магия» находится внутри цикла дешифрования, так как после завершения расшифровки шеллкода цикл дешифрования начнёт расшифровывать свой собственный код. Расшифровка первой инструкции приведёт к переходу к нашему шеллкоду, который будет выполнен на следующей итерации цикла :)
Ниже релевантная часть:
@decryption:
xor word ptr [eax], 06799h ; <jmp esi bytes> XOR <first two bytes of this instruction>
add eax, sizeof word
dec ecx
loop @decryption
Как видите, цикл дешифрования не содержит ни одной инструкции, которая переходит на расшифрованный шеллкод. Ассемблерный код собран в следующем двоичном формате:
66:8130 9967 | xor word ptr ds:[eax],6799
83C0 02 | add eax,2
49 | dec ecx
E2 F5 | loop 450006
в этом случае ключ дешифрования должен быть 06799h, так как операция XOR между 8166h (первые два байта первой инструкции цикла дешифрования) и 6799h (ключ XOR) даёт e6ffh, который ассемблируется как jmp esi. Другими словами:
0x8166 (xor word ptr ds:[eax],...) XOR 0x6799 (decryption key) == 0x6eff (jmp esi)
Установив регистр ESI на начало нашего шеллкода, мы можем добиться выполнения :)
Ниже пример отладки. Изначально копируется зашифрованный шеллкод, за которым следует код, используемый для расшифровки и вызова шеллкода. Можно заметить, что после третьего выполнения цикла дешифрования инструкция xor word ptr ds:[eax],6799 изменяется на jmp esi.

Шаги для использования этой техники:
Чтобы сделать код дешифрования менее узнаваемым, можно использовать альтернативные методы вызова шеллкода. Для большей свободы мы можем рассмотреть возможность увеличения размера чанка, который шифруется на каждой итерации. В моём PoC я использовал 2 байта, потому что jmp esi требует двух байтов, но мы можем использовать размер чанка 4 или 8 байтов, что даёт оператору больше альтернатив, умещающихся в чанк размером 4 или 8 байтов. В зависимости от выбранного способа вызова шеллкода константа шифрования также изменится.