
Ein einfacher PoC, um einen verschlüsselten Shellcode mittels eines versteckten Aufrufs aufzurufen.
Ein einfacher PoC, um einen verschlüsselten Shellcode durch einen versteckten Aufruf auszuführen.
Dieser Code verwendet einen einfachen Trick, um die Anweisung zu verstecken, die effektiv zu unserem Shellcode springt. Dies sollte die statische Analyse oder Emulation erschweren.
Wie immer, falls dieses Konzept bereits in anderen Veröffentlichungen erklärt wurde, senden Sie mir eine Nachricht und ich werde es gerne zu den Referenzen hinzufügen.
Das zu verwendende Speicherlayout ist das Standardlayout und in Abbildung 1 beschrieben.
┌───────────────────────────────┐
│ │
│ │
│ │
│ │
│ encrypted shellcode │
│ │
│ │
│ │
│ │
│ │
│ │
├───────────────────────────────┤
│ │
│ │
│ decryption loop │
│ │
│ │
└───────────────────────────────┘
Abbildung 1. Speicherlayout
Die Entschlüsselungsschleife entschlüsselt den Shellcode und springt zu ihm. Die gesamte „Magie“ befindet sich in der Entschlüsselungsschleife, da die Entschlüsselungsschleife nach der Entschlüsselung des Shellcodes beginnt, ihren eigenen Code zu entschlüsseln. Die Entschlüsselung der ersten Anweisung führt zu einem Sprung zu unserem Shellcode, der bei der nächsten Schleifeniteration ausgeführt wird :)
Nachfolgend der relevante Teil:
@decryption:
xor word ptr [eax], 06799h ; <jmp esi bytes> XOR <first two bytes of this instruction>
add eax, sizeof word
dec ecx
loop @decryption
Wie Sie sehen können, enthält die Entschlüsselungsschleife keine Anweisung, die zum entschlüsselten Shellcode springt. Der Assembler-Code wird im folgenden binären Format assembliert:
66:8130 9967 | xor word ptr ds:[eax],6799
83C0 02 | add eax,2
49 | dec ecx
E2 F5 | loop 450006
in diesem Fall muss der Entschlüsselungsschlüssel 06799h sein, da die XOR-Operation zwischen 8166h (den ersten zwei Bytes der ersten Anweisung der Entschlüsselungsschleife) und 6799h (dem XOR-Schlüssel) e6ffh ergibt, was als jmp esi assembliert wird. Mit anderen Worten:
0x8166 (xor word ptr ds:[eax],...) XOR 0x6799 (decryption key) == 0x6eff (jmp esi)
Durch Setzen des ESI-Registers auf den Beginn unseres Shellcodes können wir die Ausführung erreichen :)
Nachfolgend ein Beispiel für das Debugging. Zunächst wird der verschlüsselte Shellcode kopiert, gefolgt vom Code zum Entschlüsseln und Aufrufen des Shellcodes. Es ist zu erkennen, dass nach der dritten Ausführung der Entschlüsselungsschleife die Anweisung xor word ptr ds:[eax],6799 zu jmp esi wechselt.

Die Schritte zur Verwendung dieser Technik sind:
Um den Entschlüsselungscode weniger identifizierbar zu machen, ist es möglich, alternative Methoden zum Aufrufen des Shellcodes zu verwenden. Um mehr Freiheit zu haben, können wir die Chunk-Größe erhöhen, die bei jeder Iteration verschlüsselt wird. In meinem PoC habe ich 2 Bytes verwendet, da jmp esi zwei Bytes benötigt, aber wir können Chunk-Größen von 4 oder 8 Bytes verwenden, was dem Bediener mehr Alternativen bietet, die in 4- oder 8-Byte-Chunks passen. Je nach gewählter Methode zum Aufrufen des Shellcodes ändert sich auch die Verschlüsselungskonstante.