2010-06-04 10 views
10

Obecnie piszę parser PE/loader. Udało mi się załadować plik PE do pamięci przy użyciu standardowego pliku c io, pobranych ważnych nagłówków DOS i PE (nagłówek opcjonalny), a także uzyskując dostęp do sekcji PE. Moim następnym celem jest uzyskanie dostępu do tabeli eksportu w celu pobrania wyeksportowanych symboli. Aby to zrobić, użyłem RVA przechowywanego w opcjonalnej tablicy słowników danych nagłówka w indeksie 0 (co moim zdaniem wskazuje na tabelę eksportu) i dodałem ten adres do adresu pliku PE załadowanego do pamięci programu, a następnie odlałem to do poprawnego nagłówka tabeli eksportu. Pojawiają się NULL adresy i dane, kiedy to robię. tutaj jest mały fragment kodu;Rozwiązywanie problemów RVA dla tabel importu i eksportu w pliku PE

// RVA from optional headers data dictionaries array cast to Export directory type 
    IMAGE_EXPORT_DIRECTORY* ied(
    (IMAGE_EXPORT_DIRECTORY*)((void*) 
    ((unsigned char*)buffer + ioh->DataDirectory[0].VirtualAddress))); 

Czy muszę użyć pamięci IO zmapowanej w pamięci, aby zrobić to poprawnie? Czy źle wyliczam adres? Informacje na temat PE RVA wydają się rzadkie. z góry dzięki.

+0

Zbiór artykułów wskazał w tym SO odpowiedzi może być pomocne: http://stackoverflow.com/questions/2307754/within-a-dll-how-is-function-table-structured/2307850#2307850 –

Odpowiedz

0

Nie wszystkie obrazy PE będą miały tabelę katalogu eksportu. Musisz sprawdzić pole "NumberOfRvaAndSizes" opcjonalnego nagłówka Windows. Jeśli jest on mniejszy lub równy IMAGE_DIRECTORY_ENTRY_EXPORT (0), wówczas nie ma tabeli katalogu eksportu (tj. Nie ma prawidłowej lokalizacji pod adresem ioh->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]).

Zobacz odpowiedź na this question dla przykładu.

13

Otworzyłem jeden mój stary projekt od czasu jak podoba Ci się zbadać strukturę katalogów importu i eksportu (IMAGE_DIRECTORY_ENTRY_EXPORT, IMAGE_DIRECTORY_ENTRY_IMPORT, IMAGE_DIRECTORY_ENTRY_IAT i IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT). Mogę w skrócie wyjaśnić część, w której masz problem. Mam na myśli część, w jaki sposób dowiedzieć się wskaźnik do np. IMAGE_EXPORT_DIRECTORY wewnątrz PE.

Przede wszystkim, bo to jest możliwe użycie operacji odczytu plików/Zapis do analizy pliku PE, ale jest o wiele łatwiejsze w użyciu pliku mapowania jak następuje:

hSrcFile = CreateFile (pszSrcFilename, GENERIC_READ, FILE_SHARE_READ, 
         NULL, OPEN_EXISTING, 0, NULL); 
hMapSrcFile = CreateFileMapping (hSrcFile, NULL, PAGE_READONLY, 0, 0, NULL); 
pSrcFile = (PBYTE) MapViewOfFile (hMapSrcFile, FILE_MAP_READ, 0, 0, 0); 

po mamy wskaźnik pSrcFile które wskazują na plik PE, możemy znaleźć inne ważne miejsca w PE:

pDosHeader = (IMAGE_DOS_HEADER *)pSrcFile; 
IMAGE_NT_HEADERS32 *pNtHdr = (IMAGE_NT_HEADERS32 *) 
    ((PBYTE)pDosHeader + pDosHeader->e_lfanew); 
IMAGE_SECTION_HEADER *pFirstSectionHeader = (IMAGE_SECTION_HEADER *) 
    ((PBYTE)&pNtHdr->OptionalHeader + 
    pNtHdr->FileHeader.SizeOfOptionalHeader); 

Teraz mamy wszystkie potrzebne adresy wirtualne dowolnego katalogu. Na przykład:

pNtHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress 

to wirtualny adres katalogu eksportu. Następnie, aby przekonwertować adres wirtualny na wskaźnik pamięci, , powinniśmy znaleźć sekcję PE, która ma ten wirtualny adres wewnątrz.Aby to zrobić, możemy wyliczyć sekcje PE i znaleźć i tarce lub równa 0 i mniej niż pNtHdr->FileHeader.NumberOfSection s gdzie

pFirstSectionHeader[i].VirtualAddress <= 
pNtHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress 

i jednocześnie

pNtHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress 
< pFirstSectionHeader[i].VirtualAddress + pFirstSectionHeader[i].Misc.VirtualSize 

następnie należy wyszukać dane eksportu w sekcji pFirstSectionHeader[i]:

IMAGE_SECTION_HEADER *pSectionHeader = &pFirstSectionHeader[i]; 
IMAGE_EXPORT_DIRECTORY *pExportDirectory = 
    (IMAGE_EXPORT_DIRECTORY *)((PBYTE)pbyFile + pSectionHeader->PointerToRawData + 
    pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress - 
    pSectionHeader->VirtualAddress); 

Taką samą procedurę należy powtórzyć, aby znaleźć (IMAGE_IMPORT_DESCRIPTOR *) WH ich odpowiada IMAGE_DIRECTORY_ENTRY_IMPORT i (IMAGE_BOUND_IMPORT_DESCRIPTOR *), co odpowiada IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT w celu zrzucenia informacji o imporcie włącznie z informacją o powiązaniu (jeśli istnieje).

Aby zrzucić dane z IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT (odpowiada (ImgDelayDescr *) określonym w delayimp.h) należy użyć także informacje z IMAGE_DIRECTORY_ENTRY_IAT (odpowiada (IMAGE_THUNK_DATA32 *)).

Aby uzyskać więcej informacji na temat PE polecam http://msdn.microsoft.com/en-us/magazine/cc301808.aspx

+0

Po prostu dla wyjaśnienia, czy możesz powiedzieć skąd pochodzi 'pbyFile'? –

+0

@DebugErr: Jest taki sam, jak wcześniej użyto 'pSrcFile'. Nie trzeba czytać całego pliku EXE/DLL w pamięci. Wystarczy skorzystać z metod mapowania pamięci, aby uzyskać do niego dostęp. – Oleg

+0

Rozumiem, piszę to w C#, więc jestem teraz trochę leniwy i właśnie potrzebowałem adresu w pliku (pSrcFile byłoby po prostu 0, a następnie do obliczeń). Zaimplementowałem twoją funkcję, ale z wyjątkiem pola TimeDateStamp, wszystkie moje inne pola ExportDataDirectory wyglądają okropnie źle :( –

0

Istnieje makro zdefiniowane dostać pierwszy odcinek

PIMAGE_SECTION_HEADER FisrtSection = IMAGE_FIRST_SECTION(NtHeaders)

Powiązane problemy