Frage:
Was ist die Verschleierung von "überlappenden Anweisungen"?
perror
2013-04-03 13:11:29 UTC
view on stackexchange narkive permalink

Ich habe einige Binärdateien in x86 / x86-64 mit einigen Verschleierungstricks analysiert. Eine wurde als überlappende Anweisung bezeichnet. Kann jemand erklären, wie diese Verschleierung funktioniert und wie man sie umgeht?

Ich habe mich gefragt, was der richtige Begriff dafür ist. Ich habe gehört, dass "Anweisungsspaltung" ziemlich häufig verwendet wird.
Ich stoße auf verschiedene Arten, über diese Technik zu sprechen. Es ist jedoch wahr, dass keine von der Gemeinschaft weitgehend übernommen wurde. "_Overlaping Instructions_" war die am häufigsten verwendete, die ich seitdem finden kann. Aber ich habe vielleicht nur einen kleinen Teil der vorhandenen Dokumentation darüber gelesen.
Vier antworten:
#1
+28
Remko
2013-04-03 13:25:43 UTC
view on stackexchange narkive permalink

Das Papier Statische Analyse von x86 Executables erklärt überlappende Anweisungen recht gut. Das folgende Beispiel wird daraus entnommen (Seite 28):

  0000: B8 00 03 C1 BB mov eax, 0xBBC103000005: B9 00 00 00 05 mov ecx, 0x05000000000A: 03 C1 add eax, ecx000C : EB F4 jmp $ -10000E: 03 C3 add eax, ebx0010: C3 ret  

Beim Betrachten des Codes ist nicht ersichtlich, wie hoch der Wert von eax bei der Rückgabeanweisung sein wird ( oder dass die Rückgabeanweisung jemals erreicht wird). Dies ist auf den Sprung von 000C nach 0002 zurückzuführen, eine Adresse, die in der Auflistung nicht explizit vorhanden ist (jmp $ -10 bezeichnet einen relativen Sprung vom aktuellen Programmzählerwert, der 0xC und 0xC10 = 2 ist). Dieser Sprung überträgt die Steuerung auf das dritte Byte des fünf Byte langen Bewegungsbefehls an Adresse 0000. Durch Ausführen der Bytesequenz ab Adresse 0002 wird ein völlig neuer Befehlsstrom entfaltet:

  0000: B8 00 03 C1 BB mov eax, 0xBBC103000005: B9 00 00 00 05 mov ecx, 0x05000000000A: 03 C1 add eax, ecx000C: EB F4 jmp $ -100002: 03 C1 add eax, ecx0004: BB B9 00 00 00 mov ebx, 0xB90009: 05 03 C1 EB F4 add eax, 0xF4EBC103000E: 03 C3 add eax, ebx0010: C3 ret  

Es wäre interessant zu wissen, ob / wie Ida Pro und insbesondere das Hex Rays-Plugin damit umgehen. Vielleicht kann @IgorSkochinsky dies kommentieren ...

#2
+16
Ange
2013-04-08 19:47:54 UTC
view on stackexchange narkive permalink

Es wird auch als "Sprung in die Mitte" -Trick bezeichnet.

Erklärung

Ausführungsregeln

  • Die meisten Anweisungen benötigen mehr als ein Byte um codiert zu werden
    • können sie auf modernen CPUs bis zu 15 Bytes benötigen
  • Die Ausführung kann an jeder Position beginnen, solange Berechtigungen gültig sind

So kann jedes Byte, das auf das erste eines Befehls folgt, erneut verwendet werden, um einen anderen Befehl zu starten.

Missbrauch von Disassemblern

  • Unkomplizierte Disassembler starten das nächste Anweisung direkt nach dem Ende der letzten.

Solche Disassembler (die nicht dem Fluss folgen) verbergen die Anweisung, die sich in der Mitte befindet eines sichtbaren .

Beispiele

trivial

  00: EB 01 jmp 302: 68 c3 90 90 90 Push 0x909090c3  

wird effektiv ausgeführt als

  00: EB 01 jmp 303: C3 retn ...  

Wenn der erste jmp das erste Byte 68 (der einen sofortigen Push codiert) der folgenden Anweisung.

mehrere Überlappungen

von diesem Beispiel, 69 84 definiert einen imul -Befehl, der bis zu 11 Bytes aufnehmen kann. Auf diese Weise können Sie mehrere Befehlszeilen in die 'falschen' Operanden einfügen.

  00: EB02 jmp 402: 69846A40682C104000EB02 imul eax, [edx + ebp * 2 + 0102C6840], 0x002EB00400D: ...  

wird tatsächlich ausgeführt als

  00: EB02 jmp 404: 6A40 push 04006: 682C104000 push 0x40102C0B: EB02 jmp 0xF0F: ...  

Befehl überlappt sich

Der Befehl springt in das 2. Byte von sich selbst:

  00: EBFF jmp 102: C0C300 rol bl, 0  

wird tatsächlich ausgeführt als

  00: EBFF jmp 101: FFC0 inc eax03: C3 retn  

verschiedene CPU-Modi

Diese Verschleierung kann erweitert werden, um zur gleichen EIP zu springen, jedoch in verschiedenen CPU-Modi:

  • 64b-CPUs unterstützen weiterhin 32b-Anweisungen
  • Der 64b-Modus verwendet 0x33 für cs
  • einige Anweisungen sind Nur in einem bestimmten Modus verfügbar:
    • arpl im 32b-Modus
    • movsxd im 64b-Modus

, damit Sie zum gleichen EIP , jedoch mit einem anderen CS springen und unterschiedliche Anweisungen erhalten können.

In diesem Beispiel wird dieser Code zuerst im 32b-Modus ausgeführt:

  00: 63D8 arpl ax, bx02: 48 dec eax03: 01C0 add eax, eax05: CB retf  

und dann im 64-Bit-Modus erneut ausgeführt als:

  00: 63D8 movsxd rbx, eax02: 4801C0 add rax, rax05: CB retf  

In diesem Fall überlappen sich die Anweisungen nicht aufgrund einer anderen EIP, sondern weil die CPU vorübergehend vom 32b- in den 64b-Modus gewechselt ist.

Ist es möglich, vom 32- in den 64-Bit-Modus als Programm zu wechseln, das auf allen wichtigen Betriebssystemen im Benutzerbereich ausgeführt wird?
@Dougall ja. Unter Windows erfolgt dies über "X86SwitchTo64BitMode ()" (oder manuell mit einem Fernaufruf / Sprung mit der Segmentauswahl 33). Ich bin mir jedoch ziemlich sicher, dass dies spezifisch für die Windows WOW64-Implementierung ist und in einem anderen Betriebssystem nicht anwendbar ist.
@Ange, können Sie den Link https://code.google.com/p/corkami/source/browse/trunk/src/CoST/CoST.asm?r=1593#2247 aktualisieren? Vielen Dank!
#3
+8
joxeankoret
2013-04-03 14:19:39 UTC
view on stackexchange narkive permalink

Fast jeder Multi-Byte-Befehl kann in x86 / x86_64 als überlappender Befehl verwendet werden. Der Grund ist sehr einfach: x86- und x86_64-Befehlssätze sind CISC. Dies bedeutet unter anderem, dass die Anweisungen keine feste Länge haben. Da die Anweisungen eine variable Länge haben und diesen Maschinencode sorgfältig schreiben, kann jede Anweisung überlappende Anweisungen verbergen.

Geben Sie beispielsweise den folgenden Code an:

  [ 0x00408210: 0x00a31e10] > b0x000050f5 (01) 56 PUSH ESI 0x000050f6 (04) 8b742408 MOV ESI, [ESP + 0x8] 0x000050fa (01) 57 PUSH EDI 0x000050fb (03) c0e03 ESI + 0x40a058] 0x00005104 (01) 57 PUSH EDI 0x00005105 (06) ff15f4804000 CALL 0x004080f4; 1 KERNEL32.dll! GetModuleHandleA0x0000510b (02) 85c0 TEST EAX, EAX 0x0000510d (02) 750b JNZ 0x0000511a; 2  

Nehmen wir an, dass irgendwo nach dem letzten Befehl ein Sprung in die Mitte eines Befehls im angezeigten Code erfolgt, beispielsweise zum 2. Byte im MOV ESI ... Anweisung:

  [0x000050f7: 0x00405cf7] > c0x000050f7 (02) 7424 JZ 0x0000511d; 1 0x000050f7 -------------------------------------------- ---------------------- 0x000050f9 (03) 0857c1 ODER [EDI-0x3f], DL 0x000050fc (02) e603 OUT 0x3, AL  

Es stellt sich heraus, dass sich diese Anweisung in eine JZ ändert. Welches ist gültig. Springe zum 3. Byte ...

  [0x000050f7: 0x00405cf7] > s +1 [0x000050f8: 0x00405cf8] > c0x000050f8 (02) 2408 UND AL, 0x8 0x000050fa (01) 57 Px (03) c1e603 SHL ESI, 0x3 0x000050fe (06) 8bbe58a04000 MOV EDI, [ESI + 0x40a058]  

Springen zum 2. Byte des CALL-Befehls:

  [0x000050f5: 0x00405cf5] > s 0x5106 [0x00005106: 0x00405d06] > c0x00005106 (05) 15f4804000 ADf; '\ x8e \ x91'0x0000510b (02) 85c0 TEST EAX, EAX 0x0000510d (02) 750b JNZ 0x0000511a; 1  

Wie Sie sehen können, kann praktisch jeder Multibyte-Befehl als überlappender Befehl verwendet werden.

Dieser Anti-Reversing-Trick wird häufig verwendet undurchsichtige Prädikate, um das Flussdiagramm zu ficken.

Sie meinen also, dass es keine Möglichkeit gibt, eine solche Liste zu erstellen? Ein weiterer Punkt, der mich an x86 / x86-64-Opcodes sehr überrascht, ist die Fähigkeit, nach einer Weile wieder mit dem ursprünglichen Befehlsfluss zu synchronisieren. Diese Eigenschaft hilft auch sehr dabei, Anweisungen zu überlappen. Ich habe jedoch keine Ahnung, warum die Resynchronisation so gut funktioniert.
#4
+3
Dougall
2013-04-08 20:16:04 UTC
view on stackexchange narkive permalink

Da x86-Befehle beliebig lang sein können und nicht ausgerichtet werden müssen, kann der unmittelbare Wert eines Befehls insgesamt ein anderer Befehl sein. Beispiel:

  00000000 0531C0EB01 eax hinzufügen, 0x1ebc03100000005 055090EB01 eax hinzufügen, 0x1eb90500000000A 05B010EB01 eax hinzufügen, 0x1eb10b00000000F EBF0 jmp short 0x1  
bis zum Sprung. Wenn es springt, wird der unmittelbare Wert, der zu eax hinzugefügt wird, zu einer Anweisung, sodass der Code wie folgt aussieht:
  00000000 05 db 500000001 31C0 xor ax, ax xor ax, ax00000003 EB01 jmp short 0x600000005 05 db 500000006 50 Push Axe Push Ax00000007 90 nop00000008 EB01 jmp short 0xb0000000A 05 db 50000000B B010 mov al, 0x10 mov al, 0x10 ....  

Die Anweisungen, die tatsächlich von Bedeutung sind, werden rechts angezeigt -hand Spalte. In diesem Beispiel werden Kurzsprunganweisungen verwendet, um den Teil add eax der Anweisung ( 05 ) zu überspringen. Es sollte beachtet werden, dass dies effektiver durchgeführt werden könnte, indem ein Einzelbyte verwendet wird, um die 05 s zu essen, wie 3C05 , das cmp al, 0x5 ist Code> und wäre harmlos in Code, der sich nicht um die Flags kümmert.

Im obigen Muster können Sie alle 05 s einfach durch 90 (nop), um die korrekte Demontage anzuzeigen. Dies kann schwieriger werden, indem die 05 als unmittelbare Werte für versteckten Code verwendet werden (von dem die Ausführung abhängt). In der Realität würde die Person, die den Code verschleiert, wahrscheinlich nicht immer wieder add eax verwenden und möglicherweise die Ausführungsreihenfolge ändern, um die Nachverfolgung unübersichtlicher zu machen.

Ich habe eine Probe nach dem obigen Muster vorbereitet. Dies ist eine 32-Bit-Linux-ELF-Datei in base64. Der Effekt des versteckten Codes ist execve ("// usr / bin / python", 0, 0) . Ich schlage vor, Sie führen keine zufälligen Binärdateien aus SE-Antworten aus. Sie können es jedoch verwenden, um Ihre Disassembler zu testen. IDA, Hopper und objdump alle kläglich auf den ersten Blick nicht, obwohl ich denke, Sie IDA bekommen kann, es zu tun richtig irgendwie.

  f0VMRgEBAQAAAAAAAAAAAAIAAwABAAAAYIAECDQAAAAoAQAAAAAAADQAIAABACgAAwACAAEAAAAAAAAAAIAECACABAgUAQAAFAEAAAUAAAAAEAAAAAAAAAAAAAAAAAAABTHA6wEFUJDrAQWwEOsBBffg6wEF9 + DrAQWJw + sBBbRu6wEFsG / rAQX34 + sBBbRo6wEFsHTrAQVQkOsBBbR56wEFsHDrAQX34 + sBBbQv6wEFsG7rAQVQkOsBBbRp6wEFsGLrAQX34 + sBBbQv6wEFsHLrAQVQkOsBBbRz6wEFsHXrAQX34 + sBBbQv6wEFsC + / rAQVQkOsBBTHJ6wEF9 HrAQWJ4 + sBBbAL6wEFzYDrAelN //// AC5zaHN0cnRhYgAudGV4dAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACwAAAAEAAAAGAAAAYIAECGAAAAC0AAAAAAAAAAAAAAAQAAAAAAAAAAEAAAADAAAAAAAAAAAAAAAUAQAAEQAAAAAAAAAAAAAAAQAAAAAAAAA =  


Diese Fragen und Antworten wurden automatisch aus der englischen Sprache übersetzt.Der ursprüngliche Inhalt ist auf stackexchange verfügbar. Wir danken ihm für die cc by-sa 3.0-Lizenz, unter der er vertrieben wird.
Loading...