PE Import Table Frage

Hi,

ich untersuche gerade zum Test calc.exe
und lese die VirtualAddress auf DataDirectory[1] aus.

Der Wert beträgt 51afch. Der Offset von DataDirectory beträgt 158h.

Wenn ich nun zu der Position 51c54h springe werden dort
Funktionnamen aus DLLs aufgelistet aber
nach Iczelion's PE Tutorial 6: Import Table

erwarte ich ein Array von folgenden Strukturen
IMAGE_IMPORT_DESCRIPTOR STRUCT
union
Characteristics dd ?
OriginalFirstThunk dd ?
ends
TimeDateStamp dd ?
ForwarderChain dd ?
Name1 dd ?
FirstThunk dd ?
IMAGE_IMPORT_DESCRIPTOR ENDS

Ich sehe aber nur Funktionnamen von DLLs
http://www.bilderload.com/daten/calcJDTA1.png

kann mir jemand nur einen konkreten hinweis geben?
 
und lese die VirtualAddress auf DataDirectory[1] aus.

Der Wert beträgt 51afch. Der Offset von DataDirectory beträgt 158h.

Wenn ich nun zu der Position 51c54h springe
Ja, so geht die Umrechnung von RVA zu FileOffset aber nicht ;)
00050EFC müsste es sein - falls wir über die gleiche calc Version verfügen.

Wichtig: die Angaben im PE-Header sind üblicherweise RVAs, keine VAs (auch wenn in Dokus ab und zu etwas anderes steht). Die VA der Datadirectory wäre bei ASLR/DLLs gar nicht bekannt ;)
Umrechnung "zu Fuß": RVA nehmen, zugehörige Section in Section-Headers suchen, Minus VA(oder VirtualOffset, je nach Dokumentation) der Section, Plus RawOffset dieser Section.

Ansonsten würde ich auch zu Lernzwecken den CFF Explorer empfehlen, da dieser neben einem eingebauten Hexeditor auch das komplette PE Format samt RVA/VA/FileOffset/Disassembly/Ressourcenansicht usw. "kann".
 
Hi,

danke ich werde es überprüfen.

PS: " Noch mal, für alle Pseudo-Geeks: 1+1=0. -> 10 wäre Überlauf!"

Ich denke es geht hier um die reine Informatik ^^
 
Hi,

btw: Wir haben wohl verschiedene calc.exe Versionen nur so mal vorab ^^.

Ich habe wirklich viel recherchiert, verglichen mit meiner wenigen Freizeit, die ich neben meiner Arbeit und meinen anderen Aktivitäten habe.

Ich stecke wirklich in der Zwickmühle und weis nicht mehr weiter.

Kannst du mir bitte nochmal straight zeigen, vorrechnen, wie man zur Import Table kommt?
 
Erwähnen möchte ich die hübsche Grafik bei:
Understanding the Import Address Table

Ansonsten: die offizielle Dokumentation von MS ist
http://download.microsoft.com/download/9/c/5/9c5b2167-8017-4bae-9fde-d599bac8184a/pecoff_v8.docx
Das ist schon mit Offsets und Werten für aufgelistete Konstanten, allerdings etwas umfangreich und die Werte sind für 32/64 Bit angegeben. Eine kompaktere Referenz, auf die ich mich im Folgenden beziehe:
PE executable file format offsets

Vornweg: wie schon gesagt, man sollte ganz strickt zwischen "FileOffset", VA und RVA unterscheiden.
RVA = relativ zu dem "Anfang", gilt aber für eine schon in den Speicher geladene Executable.
VA = "absolute" Adresse im Speicher. Kann prinzipiell aus RVA + (ImageBase Wert) berechnet werden, kann aber bei DLLs oder Exen, die Relocations mitführen variieren (da die ImageBase vom System bestimmt wird => üblich seit "ASLR" bei Exen und schon viel viel viel länger bei DLLs (da bei einem Haufen DLLs öfters vorkommen kann, dass die "gewünschte" aka im PE-Header eingetragene Adresse schon belegt ist)).

FileOffset: Position in der Datei selbst, wird benötigt, wenn man per Hexeditor oder über eigenen Code PE auslesen möchte. Die Angaben im PE Header sind aber _alle_ als RVA zu betrachten. Umrechnung ist nur "umständlich" möglich - über SectionHeader Einträge.

Zu beachten wäre noch, dass die Werte, die man im Hexeditor sieht, im Little-Endian Format vorliegen.

---------------------------------------------------
Konkretes Beispiel: die kompilierte Version (VS 2010, 32-Bit, statisch gelinkt) von
http://www.hackerboard.de/code-kitchen/46624-c-bitmap-erstellen.html
(angehängt)
Mit "Dump" ist ein Ausschnitt aus dem Hexeditor gemeint.
---------------------------------------------------

Part1:
Wo ist der PE Header?
Code:
OLD EXE (MZ header)

+0  WORD e_magic;         // Magic number MZ
 2  WORD e_cblp;          // Bytes on last page of file

28  WORD e_res2[10];      // Reserved words
3C  DWORD e_lfanew;       // File address of new exe header
Dump:
Code:
00000000: 4d 5a 90 00 03 00 00 00 04 00 00 00 ff ff 00 00  MZ..............
00000010: b8 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00  ........@.......
00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00000030: 00 00 00 00 00 00 00 00 00 00 00 00 [COLOR="Red"]e0 00 00 00[/COLOR]  ................
e0 00 00 00 => 0xE0

Wo ist der Verweis auf die ImportDirectory?
Code:
NEW EXE
+0 PE
 4 WORD  Machine;
 6 WORD  NumberOfSections;    
 8 DWORD   TimeDateStamp;
 C DWORD   PointerToSymbolTable;    
10 DWORD   NumberOfSymbols;
14 WORD  SizeOfOptionalHeader;    
...
70 DWORD   LoaderFlags;
74 DWORD   NumberOfRvaAndSizes;

   IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
   /* IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16 */

80 DWORD ImportDirectory RVA
84 DWORD ImportDirectory Size
Die Offsetangaben sowohl hier wie auch in der offiziellen Dokumentation beziehen sich auf den PE-Headerstart .
In unserem Fall wäre das also Adresse von "PE" + 0x80 = 0xE0 + 0x80 = 0x160

An dieser Adresse steht also erstmal der Verweis:
Code:
00000160: [COLOR="red"]4c 12 01 00[/COLOR] 28 00 00 00 00 70 01 00 b4 01 00 00
4c 12 01 => 0x01124C
Das ist eine RVA. Damit kommen wir im Hexeditor nicht weiter. Umrechnung:
(das Suchen der SectionHeaders und das Auslesen der Werte im Hexeditor spare ich mir in diesen Part ;) ):
Code:
->Section Header Table
   1. item:
    Name:                  .text
    VirtualSize:           0x0000D7BA
    VirtualAddress:        0x00001000
    SizeOfRawData:         0x0000D800
    PointerToRawData:      0x00000400

   2. item:
    Name:                  .rdata
    VirtualSize:           0x000028EE
    VirtualAddress:        0x0000F000
    SizeOfRawData:         0x00002A00
    PointerToRawData:      0x0000DC00

   3. item:
    Name:                  .data
    VirtualSize:           0x000047C4
    VirtualAddress:        0x00012000
    SizeOfRawData:         0x00002A00
    PointerToRawData:      0x00010600

   4. item:
    Name:                  .rsrc
    VirtualSize:           0x000001B4
    VirtualAddress:        0x00017000
    SizeOfRawData:         0x00000200
    PointerToRawData:      0x00013000
0x01124C
gehört also zu der 2 Section ".rdata" (startet an 0xF000 und endet an 0xF000+0x2A00 = 0x11A00)
VirtualAddress (so wird es jedenfalls in fast allen PE Editoren und Dokumentationen bezeichnet) ist trotzem eine relative Angabe
pecoff hat gesagt.:
For executable images, the address of the first
byte of the section relative to the image base
when the section is loaded into memory.

RVA - VirtualAddress_der_section = Adresse relativ zu dieser Section.
0x01124C - 0xF000 = 0x224C
Diese Adresse + PointerToRawData_der_section (oder einfach "RawData") = Adresse in der Datei:
0x224C + 0x0000DC00 = 0xFE4C

Dump:
Code:
0000fe40: [COLOR="Silver"]fe ff ff ff 75 e7 40 00 91 e7 40 00 [/COLOR]74 12 01 00  ....u.@...@.t...
0000fe50: 00 00 00 00 00 00 00 00 e0 18 01 00 00 f0 00 00  ................
0000fe60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
0000fe70: 00 00 00 00

Das ist ein ImportDirectory Eintrag:
Code:
Import Directory
+0 DWORD   OriginalFirstThunk;
 4 DWORD   TimeDateStamp;
 8 DWORD   ForwarderChain;
 c DWORD   Name;
10 DWORD   FirstThunk;
also 5 DWORDS = 20 Bytes. Das Ende wird durch eine "leere" Struktur signalisiert - also 5 x 00 00 00 00 (im Dump oben ab 0xfe60).
Also hier nur 1 ImportDir Eintrag.

Jetzt sollte man wissen, dass nicht alle Einträge "Pflichtangaben" sind (OriginalFirstThunk, TimeDataStamp und ForwarderChain sollten optional sein) - meist wird es aber im Zusammenhang mit "nicht-ms" Linkern oder Packern interessant.

Wir können uns die Einträge mal ansehen:
erster Eintrag ist "OriginalFirstThunk"
74 12 01 00 => 0x011274 = RVA (zum Umrechnen nutze ich nun die eingebaute Funktion von CFF Explorer) => FileOffset = 0000FE74
Dumpausschnitt:
Code:
0000fe70: [COLOR="Silver"]00 00 00 00[/COLOR] 9c 13 01 00 ae 13 01 00 c2 13 01 00  ................
0000fe80: d0 13 01 00 e0 13 01 00 f2 13 01 00 08 14 01 00  ................
0000fe90: 1c 14 01 00 30 14 01 00 4c 14 01 00 6a 14 01 00
An import lookup table is an array of 32-bit numbers for PE32 or an array of 64-
bit numbers for PE32+. Each entry uses the bit-field format that is described in the
following table. In this format, bit 31 is the most significant bit for PE32 and bit 63
is the most significant bit for PE32+. The collection of these entries describes all
imports from a given DLL. The last entry is set to zero (NULL) to indicate the end of
the table.
Also einfach eine Liste mit DWORD Werten, die entweder ein Ordinalimporteintrag sind oder auf einen ASCII-String verweisen, terminiert durch 0.
genaues siehe PECOFF, Seite 74

also einfach mal nachschauen, was es ist:
9c 13 01 = 0x139c (RVA) = FileOffset: 0x0000FF9C
Dump:
Code:
0000ff90: [COLOR="silver"]c4 18 01 00 d0 18 01 00 00 00 00 00[/COLOR] 45 02 47 65  ............[COLOR="Lime"]E.[/COLOR][COLOR="Red"]Ge
0000ffa0: 74 50 72 6f 63 41 64 64 72 65 73 73 00[/COLOR] 00 18 02  [COLOR="red"]tProcAddress.[/COLOR]...
Die ersten 2 Bytes sind ein "Hint" zum Suchen des Eintrags in der Exporttabelle der "anbietenden" DLL (interessant nur für den PE-Loader von Windows).
Der nächste Eintrag: ae 13 01 00 =>Fileoffset 0000FFAE:
Code:
18 02  tProcAddress....
0000ffb0: 47 65 74 4d 6f 64 75 6c 65 48 61 6e 64 6c 65 57  GetModuleHandleW
usw.

Der zweite Eintrag in der ImportTable:
Code:
0000fe40: [COLOR="Silver"]fe ff ff ff 75 e7 40 00 91 e7 40 00 [/COLOR]74 12 01 00  ....u.@...@.t...
0000fe50: 00 00 00 00 00 00 00 00 e0 18 01 00 00 f0 00 00  ................
0000fe60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
0000fe70: 00 00 00 00
TimeDateStamp => nicht gesetzt, ebenso ForwarderChain.
Name darf man an e0 18 01 00 = 0x0118e0 => Fileoffset 0x104E0 ablesen:
Code:
000104e0: 4b 45 52 4e 45 4c 33 32 2e 64 6c 6c 00 00 00 00  KERNEL32.dll....
Fertig.
 
Zuletzt bearbeitet:
Zurück
Oben