x86 Applikation modifizieren

  • C#
  • .NET (FX) 4.5–4.8

Es gibt 10 Antworten in diesem Thema. Der letzte Beitrag () ist von hal2000.

    x86 Applikation modifizieren

    Hallo liebes Forum,

    ich habe einen Debugger gefunden ( ollydebugger) mit dem es möglich ist x86 Applikationen zu "zerlegen" um eben die asm- Anweisungen auszulesen
    oder gar zu modifizieren.

    Das Problem ist folgende:
    Ich habe _ gucken wollen was geschieht wenn ich die Datei( die als byte-array vorliegt) entsprechend in C# modifiziere.
    Gemeint ist exemplarisch diese Instruktion:
    PUSH 00040303

    Ist irgendetwas Willkürliches.
    Habe _ dann eben folgendes in C# _ geschrieben:

    C#-Quellcode

    1. static void Main(string[] args)
    2. {
    3. byte[] data = File.ReadAllBytes(@"c:\users\dev\desktop\x86.exe");
    4. bool _lock = false;
    5. int _count = 0;
    6. int index = 0;
    7. byte[] hex = new byte[] { 0x68, 0xC3, 0x40, 0x00, 0x00 };
    8. int amount = hex.Length;
    9. for (int i = 0; i < data.Length - 1; i++)
    10. {
    11. if (data[i] == 0 && data[i + 1] == 0)
    12. {
    13. _lock = true;
    14. }
    15. else if(data[i]!= 0 || data[i+1]!=0)
    16. {
    17. _lock = false;
    18. _count = 0;
    19. }
    20. if (_lock)
    21. _count++;
    22. if(_count > amount)
    23. {
    24. index = i - amount;
    25. Console.WriteLine("Cave_offset:" + index);
    26. break;
    27. }
    28. }
    29. if (index == 0)
    30. return;
    31. for (int i = index; i < hex.Length + index; i++)
    32. {
    33. data[i] = hex[i - index];
    34. }
    35. File.WriteAllBytes(@"c:\users\dev\desktop\x86modified.exe", data);
    36. Console.Read();
    37. }


    Ich habe angenommen das die Code-Caves im Form von 0x00 im byte-array vorliegen.
    Habe dann den Code in ein code-cave Areal injiziert das die Länge vom hex-array hat.

    Finde aber( via cntrl+f bei ollydbg) nicht den Befehl PUSH 00040303

    Missverstehe ich da irgendwas?

    Liebe Grüße.
    Und Gott alleine weiß alles am allerbesten und besser.

    φConst schrieb:

    ich habe einen Debugger gefunden ( ollydebugger) mit dem es möglich ist x86 Applikationen zu "zerlegen" um eben die asm- Anweisungen auszulesen oder gar zu modifizieren.

    Ich glaube nicht. Mit ollydebugger siehst du den Programmcode im Arbeitsspeicher. Es ist wichtig zu wissen, dass der Code im Arbeitsspeicher, der ausgeführt wird nicht 1 zu 1 so in der Exe steht. Beim starten der Exe baust sich diese eher das Programm erst im Arbeitsspeicher richtig zusammen. Es gibt es oftmals am Anfang der Exe eine kleinen Loader der dann den komprimierten Code entpackt (wenn er komprimiert ist) und passend zusammen setzt. Du kannst also den OP-Code im Arbeitsspeicher editieren, aber nicht einfach in die Exe packen.


    PS: Ich hoffe ich hab jetzt hier keinen Quatsch erzählt, bin nicht mehr so ganz drin im Thema. Ist schon etwas länger her :) . Bitte korrigieren wenn das nicht richtig ist.
    Ach, stimmt, das macht sehr Sinn!
    Wieso sonst soll ja die Applikation gestartet werden...

    Lieben Dank, habe dann ein neuen Verständnis-Ansatz.
    Hast du denn irgendwelche Referenzen wie Windows das macht?

    Und Gott alleine weiß alles am allerbesten und besser.
    Du kannst auch einfach eine modifizierte exe mit ollydgb erstellen.
    Bilder
    • Unbenannt.png

      20,93 kB, 509×454, 152 mal angesehen
    Cloud Computer? Nein Danke! Das ist nur ein weiterer Schritt zur totalen Überwachung.
    „Wer die Freiheit aufgibt, um Sicherheit zu gewinnen, wird am Ende beides verlieren.“
    Benjamin Franklin
    Hallo, danke für deinen Beitrag.
    Ja, das ist mir bewusst.

    Wollte aber wissen ob eben die exe auf der Festplatte bereits alle Instruktionen beinhaltet.
    Anscheinend eben nur komprimiert, dass durch den Loader dann zusammengesetzt(assembled) wird ( deswegen wohl auch dis-assembler).

    Grüße.
    Und Gott alleine weiß alles am allerbesten und besser.
    Was du in der exe vorliegen hast, ist IL Code, der nicht nur anders aussieht, als der C# oder VB.NET Code, sondern auch bereits "optimiert" wurde. Dieser wiederum wird dann zur Laufzeit JIT-compiliert, wodurch dann erst der Code vorliegt, der tatsächlich ausgeführt wird. Du musst also IL "beherrschen" und dann wissen, was daraus für Maschinencode erzeugt wird.
    Bist du sicher das jede Anwendung im Form von IL vorliegt?
    Auch z.B putty oder irgend eine in C++ entwickelte Applikation?

    Hab angenommen nur .NET Code wird zunächst IL und dieser dann in Maschinensprache überführt.

    Gruß
    Und Gott alleine weiß alles am allerbesten und besser.
    Wie alles in den Speicher geladen wird, kannst du dem "Sections Table" entnehmen.

    Das könnte für dich noch interessant sein.
    osdever.net/documents/PECOFF.pdf
    imgur.com/a/t33Rr#2vWH5
    Cloud Computer? Nein Danke! Das ist nur ein weiterer Schritt zur totalen Überwachung.
    „Wer die Freiheit aufgibt, um Sicherheit zu gewinnen, wird am Ende beides verlieren.“
    Benjamin Franklin

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „NoIde“ ()

    Wenn man reines C++ nimmt (ohne CLI), dann wird der Code direkt in Maschinenanweisungen übersetzt. (Weiß nicht, wie das mit UWP-Apps aussieht.)

    Wenn du dann die einzelnen Anweisungen haben möchtest, musst du das Programm disassemblieren. Das geht mit einem (Dis-)Assembler, also einem Programm, dass aus deinem ASM-Code die EXE baut. Ich nutze hierfür gerne mit NASM (bzw. NDisASM). Du kannst diese Anweisungen dann natürlich auch wieder zurück in eine EXE assemblen, nur das zurückwandeln in den Code der Ursprugssprache ist nahezu unmöglich. Es gibt Programme dazu, aber die spucken meist unleserlichen Code aus.
    In derRegel enthält die EXE dann auch direkt ihren code in Maschinenanweisugen. Natürlich kann sie auch einen Loader enthalten, aber das ist eher unüblich und wird ja gerne bei Viren eingesetzt.

    Edit: Wenn es sich aber um eine .NET-Assembly handelt, dann hast du tatsächlich nur einen nativen Loader, der dann deinen IL-Code an die Runtime schickt. Mit Reflection kannst du .NET-Assemblys ziemlich gut zerlegen und mit CodeDom sogar aus deinem Programm heraus eine neue Assembly kompilieren.

    Edit 2: mit beiden kannst du aber die Assembly nicht dekompilieren. Dafür brauchst du ein Programm wie ILSpy oder dotPeek.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „ichduersie“ ()

    .exe ist ein Containerformat für ausführbaren Code. Äquivalent dazu wäre .avi für Audio/Video oder .zip für komprimierte Daten. Die meisten Dateiformate bestehen aus Header und Payload, was bei .exe schon arg vereinfacht ausgedrückt ist. Welcher Codetyp letztlich enthalten ist, bestimmen Flags in einem der enthaltenen Header. Dann folgen Code und Daten in entsprechenden Strukturen. Die Dokumentation des Dateiformats gibt es hier: msdn.microsoft.com/en-us/libra…op/ms680547(v=vs.85).aspx

    Soviel erstmal zur Struktur, wie Code und Daten auf der Festplatte abgelegt sind. Soll das enthaltene Programm ausgeführt werden, lädt eine spezielle Routine des Betriebssystems (der PE-Loader) den Inhalt der Datei in den Speicher. Er legt dazu einen eigenen Adressraum für den neuen Prozess an (= reserviert Arbeitsspeicher dafür) und erzeugt eine Prozess-ID. Dann kopiert, vereinfacht gesagt, der Loader den Inhalt verschiedener Stücke innerhalb der Datei (= Sections) zunächst 1:1 in den Speicher. Das Programm ist dann noch nicht ausführbar, weil die verwendeten Bibliotheken fehlen (es sei denn, es ist statisch gelinkt -> anderes Thema). Der Loader lädt also zusätzlich alle Referenzen in denselben Adressraum. Ein Beispiel dafür kann jeder im Process explorer unter "Loaded Modules" sehen. Das erste ist die exe, alle weiteren sind Bibliotheken.

    Nun sind alle erforderlichen Daten vorhanden, aber das Programm läuft immer noch nicht, weil externe Sprungadressen nicht passen. Der Loader muss diese korrigieren, damit Aufrufe an Bibliotheken an der richtigen Speicheradresse landen - dieser Prozess heißt "Fixup". Ist das abgeschlossen, übergibt der Loader die Kontrolle an das geladene Programm, indem er den definierten Einsprungpunkt aufruft. Das ist übrigens der Grund, warum alle Programme eine Main-Funktion definieren müssen.

    Der Code innerhalb der .exe-Datei findet sich 1:1 im Arbeitsspeicher wieder. Das kannst du verifizieren, indem du einen Memorydump des Prozesses erzeugst (Taskmanager -> Create Dump File) und das Codesegment mit dem Textsegment der .exe vergleichst. Beispiel notepad auf Win7 x64:
    notepad.exe .text offset 0x600 len 0xB000
    notepad.dmp .text offset 0x1CB75AB (dieser Wert wird immer anders sein -> ASLR!)

    Aber: Die Bereiche in der .exe von 0x600 bis 0xAFFF und in der .dmp von 0x1CB75AB bis 0x1CC25AA sind exakt gleich - hier zu sehen an der ersten Zeile:
    vs.

    Der Beweis, dass das für den Rest auch gilt, sei dem Leser überlassen.

    Das, was auf obigen Bildern zu sehen ist, kann der Prozessor 1:1 so verarbeiten. Damit Menschen das auch "verarbeiten" (= lesen) können, gibt es Programme, die den Zahlensalat in eine textuelle Darstellung bringen, sonst aber nichts verändern. Der Hexeditor macht auch nichts anderes, interpretiert dabei aber nichts und zeigt nur eine lesbare Darstellung von Rohdaten. Der Interpretationsvorgang heißt "Disassemblieren". Für die Mathematiker: Es handelt sich hier um eine bijektive Abbildung. Eins dieser Programme ist OllyDbg, dessen Hauptaufgabe jedoch nicht das Disassemblieren ist - es tut dies nur, damit es von Menschen bedienbar wird. Nötig wäre das nicht, wenn man weiß, dass 0xC3 für die "ret"-Instruktion steht und das auch noch flüssig lesen kann - sinnvoll ist aber was anderes.

    Zum Verändern des Codes sind zwei Dinge wichtig: Offset und Alignment. Du kannst nicht einfach eine Folge von Bytes an irgendeine Stelle der Datei schreiben und erwarten, dass die gewünschte Instruktion dabei herauskommt. Das funktionert nur dann, wenn die Bytes an der richtigen Stelle stehen (= Offset) und sich gleichzeitig im richtigen Kontext befinden (= Alignment). Das alles zu erklären würde hier deutlich zu weit führen. Für ein kleines Erfolgserlebnis kannst Du aber folgendes tun: Schreibe die Bytefolge "C3 90 90 90" in der Datei notepad.exe an Offset 0x600. C3 ist die neue Instruktion, "90 90 90" das Alignment. Sieh dir das Ergebnis in OllyDbg an. Vorher steht dort "cmp word ptr [rbx], 9", danach nur noch "ret". Das Programm funktioniert danach natürlich nicht mehr.
    Gruß
    hal2000