Rekonstruktion einer Programmdatei (2)
Wenn Sie den ersten Teil dieser Anleitung durchgearbeitet haben, dann fragen Sie sich vielleicht, ob es nicht auch einen einfacheren Weg gibt, die Programmdatei wiederherzustellen. Den gibt es, natürlich.
Das Prinzip hinter dem im ersten Teil beschriebenen Prozess ist recht einfach:
- den EPROCESS Datensatz finden
- den Beginn der Programmdatei im Speicherabbild mit Hilfe des PEB lokalisieren
- die erste Speicherseite mit dem PE-Header extrahieren und in einer Datei speichern
- für jede der im Header genannten Sektionen den entsprechenden Bereich des virtuellen Speichers extrahieren und speichern.
Wirklich lästig sind jedoch die notwendigen Umrechnungen zwischen virtuellen und physischen Adressen und das seitenweise Markieren und Kopieren des Speicherinhalts. Hier kann das Skript memdump.pl helfen! Alles, was Sie benötigen ist das Speicherabbild und die Page Directory Base Address des jeweiligen Prozesses. Die kennen Sie bereits aus dem ersten Teil, es ist 0x01d9e000.
Führen Sie nun memdump aus: ./memdump.pl dfrws2005-physical-memory1.dmp 0x01d9e000
Wenn alles fehlerfrei abläuft, dann finden Sie anschließend zwei Dateien in Ihrem Arbeitsverzeichnis:
- 0x1d9e000.map ordnet virtuelle Adressen des Prozesses den Offsets in dem gerade erstellten Prozess-Speicherabbild zu
- 0x1d9e000.mem enthält eben dieses Speicherabbild
Als nächsten Schritt müssen Sie den PEB finden. Aus dem ersten Teil wissen Sie bereits, dass er sich an der virtuellen Adresse 0x7ffdf000 befindet. Ein Blick in die MAP-Datei verrät:
virt. addr. file offset size ------------ ------------ -------- 0x7ffdf000 0x107000 0x1000
Der PDB befindet sich also am Offset 0x107000 in der Datei 0x1d9e000.mem. Acht bytes weiter finden Sie dann die ImageBaseAddress. Gut zu sehen, dass das unabhängig vom Lösungsweg immer noch 0x0400000 ist.
Für die weitere Rekonstruktion benötigen Sie die den Header der Programmdatei. Extrahieren Sie also die erste Speicherseite (an der Adresse 0x0400000, also dem Offset 0x26000). Rekonstruieren Sie anschließend alle im Header angegebenen Sektionen. Auch das lässt sich mit dem Wissen aus dem ersten Teil natürlich etwas abkürzen. Hier ist der entsprechende Ausschnitt aus der MAP Datei:
virt. addr. file offset size
------------ ------------ --------
0x400000 0x26000 0x1000
0x401000 0x27000 0x1000
0x402000 0x28000 0x1000
0x403000 0x29000 0x1000
0x404000 0x2a000 0x1000
0x405000 0x2b000 0x1000
0x406000 0x2c000 0x1000
0x407000 0x2d000 0x1000
0x408000 0x2e000 0x1000
0x409000 0x2f000 0x1000
0x40a000 0x30000 0x1000
0x40b000 0x31000 0x1000
0x40c000 0x32000 0x1000
0x40d000 0x33000 0x1000
Zu tun bleibt nur noch, 14 Speicherseiten (14 * 4096 Bytes = 57344 Bytes) ab Offset 0x26000 (38 Seiten oder 155648 Bytes in Dezimaldarstellung) aus der MEM Datei in eine neue Datei zu kopieren. Ich habe das wie üblich mit dem 010 Editor gemacht, Sie können hierzu aber auch dd verwenden:dd if=0x1d9e000.mem of=reconstructed.exe bs=4096 skip=38 count=14
Nun, war das nicht erheblich einfacher?
Harlan Carvey hat ebenfalls zu diesem Thema etwas in seinem Blog geschrieben. Vielleicht arbeitet er ja an einer automatisierten Lösung für dieses problem? Sein Perl Modul für den PE Header wird hierbei auf jeden Fall sehr nützlich sein.