source: trunk/tools/common/kFilePE.cpp@ 5531

Last change on this file since 5531 was 5531, checked in by bird, 24 years ago

Second iteration of the kFile* classes and interfaces.

File size: 14.9 KB
Line 
1/*
2 * kFilePE - PE files.
3 *
4 * Copyright (c) 1999 knut st. osmundsen
5 *
6 */
7
8/*******************************************************************************
9* Defined Constants *
10*******************************************************************************/
11/* emx fixups */
12#ifdef __EMX__
13 #define __stdcall
14 #define max(a,b) (((a) > (b)) ? (a) : (b))
15 #define min(a,b) (((a) < (b)) ? (a) : (b))
16#endif
17
18/******************************************************************************
19* Header Files *
20******************************************************************************/
21#ifdef __EMX__
22#define INT INT_
23#define PCHAR PCHAR_
24#endif
25#include <os2.h>
26#ifdef __EMX__
27#undef PCHAR
28#undef INT
29#endif
30#include <stdio.h>
31#include <stdlib.h>
32#include <string.h>
33#include <malloc.h>
34#include <assert.h>
35#include <peexe.h>
36#include "kFile.h"
37#include "kFileFormatBase.h"
38#include "kInterfaces.h"
39#include "kFilePe.h"
40
41/*******************************************************************************
42* Global Variables *
43*******************************************************************************/
44#if 0
45kFilePE kFilePE((kFile*)NULL);
46#endif
47
48/**
49 * Constructs a kFilePE object for a file.
50 * @param pFile File to create object from.
51 * @remark throws errorcode (TODO: errorhandling.)
52 */
53kFilePE::kFilePE(kFile *pFile) throw(int) : pvBase(NULL),
54 pDosHdr(NULL), pFileHdr(NULL), pOptHdr(NULL), paDataDir(NULL), paSectionHdr(NULL),
55 pExportDir(NULL),
56 pImportDir(NULL),
57 pRsrcDir(NULL),
58 pBRelocDir(NULL),
59 pDebugDir(NULL),
60 pCopyright(NULL),
61 pulGlobalPtr(NULL),
62 pTLSDir(NULL),
63 pLoadConfigDir(NULL),
64 pBoundImportDir(NULL),
65 pIATDir(NULL),
66 pDelayImportDir(NULL)
67{
68 IMAGE_DOS_HEADER doshdr;
69
70 /* read dos-header - assumes there is one */
71 if ( pFile->readAt(&doshdr, sizeof(doshdr), 0)
72 && doshdr.e_magic == IMAGE_DOS_SIGNATURE
73 && doshdr.e_lfanew > sizeof(doshdr)
74 )
75 {
76 IMAGE_NT_HEADERS pehdr;
77
78 /* read pe headers */
79 if ( pFile->readAt(&pehdr, sizeof(pehdr), doshdr.e_lfanew)
80 && pehdr.Signature == IMAGE_NT_SIGNATURE
81 && pehdr.FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER)
82 && pehdr.OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR_MAGIC)
83 {
84 /* create mapping */
85 pvBase = calloc((size_t)pehdr.OptionalHeader.SizeOfImage, 1);
86 if (pvBase != NULL)
87 {
88 /*
89 printf("%ld\n", pehdr.OptionalHeader.SizeOfHeaders);
90 printf("%ld\n", sizeof(IMAGE_NT_HEADERS) + sizeof(IMAGE_SECTION_HEADER) * pehdr.FileHeader.NumberOfSections);
91 assert(pehdr.OptionalHeader.SizeOfHeaders ==
92 sizeof(IMAGE_NT_HEADERS) + sizeof(IMAGE_SECTION_HEADER) * pehdr.FileHeader.NumberOfSections);
93 */
94 if (pFile->readAt(pvBase, pehdr.OptionalHeader.SizeOfHeaders, 0))
95 {
96 /* read sections */
97 for (int i = 0; i < pehdr.FileHeader.NumberOfSections; i++)
98 {
99 ULONG cbSection;
100 PIMAGE_SECTION_HEADER pSectionHdr =
101 #if 0
102 IMAGE_FIRST_SECTION(((ULONG)pvBase + ((PIMAGE_DOS_HEADER)pvBase)->e_lfanew));
103 #else
104 (PIMAGE_SECTION_HEADER) ( (ULONG)pvBase + doshdr.e_lfanew + sizeof(IMAGE_NT_HEADERS) );
105 #endif
106 pSectionHdr += i;
107
108 cbSection = min(pSectionHdr->Misc.VirtualSize, pSectionHdr->SizeOfRawData);
109 if ( cbSection
110 && !pFile->readAt((char*)pvBase + pSectionHdr->VirtualAddress,
111 cbSection,
112 pSectionHdr->PointerToRawData)
113 )
114 {
115 /* error */
116 free(pvBase);
117 pvBase = NULL;
118 throw(6);
119 }
120 }
121
122 /* set pointers */
123 if (*(unsigned short*)pvBase == IMAGE_DOS_SIGNATURE)
124 {
125 pDosHdr = (PIMAGE_DOS_HEADER)pvBase;
126 pFileHdr = (PIMAGE_FILE_HEADER)((DWORD)pvBase + pDosHdr->e_lfanew + 4);
127 }
128 else
129 pFileHdr = (PIMAGE_FILE_HEADER)((DWORD)pvBase + 4);
130
131 pOptHdr = (PIMAGE_OPTIONAL_HEADER)((int)pFileHdr + sizeof(*pFileHdr));
132 paDataDir = (PIMAGE_DATA_DIRECTORY)((int)pOptHdr + pFileHdr->SizeOfOptionalHeader
133 - pOptHdr->NumberOfRvaAndSizes*sizeof(*paDataDir));
134 paSectionHdr = (PIMAGE_SECTION_HEADER)((int)paDataDir +
135 pOptHdr->NumberOfRvaAndSizes*sizeof(*paDataDir));
136
137 //if (paDataDir[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress)
138 // pExportDir = (PIMAGE_EXPORT_DIRECTORY)((int)pvBase + paDataDir[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
139 for (i = 0; i < pOptHdr->NumberOfRvaAndSizes && i < 16; i++)
140 {
141 if (paDataDir[i].VirtualAddress != 0)
142 {
143 if (paDataDir[i].VirtualAddress < pOptHdr->SizeOfImage)
144 ((PULONG)&this->pExportDir)[i] = (int)pvBase + paDataDir[i].VirtualAddress;
145 #ifdef DEBUG
146 else
147 fprintf(stderr, "bad directory pointer %d\n", i);
148 #endif
149 }
150 }
151 }
152 else
153 throw(4);
154 }
155 else
156 throw(3);
157 }
158 else
159 throw(2);
160 }
161 else
162 throw(1);
163}
164
165
166/**
167 * Destructor.
168 */
169kFilePE::~kFilePE()
170{
171 if (pvBase)
172 delete pvBase;
173}
174
175
176/**
177 * Query for the module name.
178 * @returns Success indicator. TRUE / FALSE.
179 * @param pszBuffer Pointer to buffer which to put the name into.
180 * @param cchBuffer Size of the buffer (defaults to 260 chars).
181 */
182BOOL kFilePE::moduleGetName(char *pszBuffer, int cchSize/* = 260*/)
183{
184 if (pExportDir && pExportDir->Name)
185 {
186 char *psz = (char*)((int)pExportDir->Name + (int)pvBase);
187 int cch = strlen(psz) + 1;
188 if (cch > cchSize)
189 return FALSE;
190 memcpy(pszBuffer, psz, cch);
191 }
192 else
193 return FALSE;
194
195 return TRUE;
196}
197
198
199/**
200 * Finds the first exports.
201 * @returns Success indicator. TRUE / FALSE.
202 * @param pExport Pointer to export structure.
203 * @remark
204 */
205BOOL kFilePE::exportFindFirst(kExportEntry *pExport)
206{
207 if (pExportDir && pExportDir->NumberOfFunctions)
208 {
209 memset(pExport, 0, sizeof(kExportEntry));
210 pExport->ulOrdinal = pExportDir->Base - 1;
211 return exportFindNext(pExport);
212 }
213
214 return FALSE;
215}
216
217
218/**
219 * Finds the next export.
220 * @returns Success indicator. TRUE / FALSE.
221 * @param pExport Pointer to export structure.
222 * @remark
223 */
224BOOL kFilePE::exportFindNext(kExportEntry *pExport)
225{
226 if (pExportDir && pExportDir->NumberOfFunctions)
227 {
228 void **ppv = (void**)((int)pExportDir->AddressOfFunctions + (int)pvBase);
229
230 ++pExport->ulOrdinal -= pExportDir->Base;
231 while (ppv[pExport->ulOrdinal] == NULL && pExport->ulOrdinal < pExportDir->NumberOfFunctions)
232 pExport->ulOrdinal++;
233
234 if (pExport->ulOrdinal < pExportDir->NumberOfFunctions)
235 {
236 int iName = 0;
237 unsigned short *pawNameOrdinals = (unsigned short *)
238 ((int)pExportDir->AddressOfNameOrdinals + (int)pvBase);
239
240 /* look for name */
241 while (iName < (int)pExportDir->NumberOfNames &&
242 pawNameOrdinals[iName] != pExport->ulOrdinal)
243 iName++;
244 if (iName < (int)pExportDir->NumberOfNames)
245 strcpy(&pExport->achName[0],
246 (char*)((int)pvBase + ((int*)((int)pvBase + (int)pExportDir->AddressOfNames))[iName]));
247 else
248 pExport->achName[0] = '\0';
249 pExport->ulOrdinal += pExportDir->Base;
250 }
251 else
252 return FALSE;
253 }
254 else
255 return FALSE;
256
257 pExport->ulAddress = pExport->iObject = pExport->ulOffset = ~0UL; /* FIXME/TODO */
258 pExport->achIntName[0] = '\0';
259 pExport->pv = NULL;
260 return TRUE;
261}
262
263
264/**
265 * Frees resources associated with the communicatin area.
266 * It's not necessary to call this when exportFindNext has return FALSE.
267 * (We don't allocate anything so it's not a problem ;-)
268 * @param pExport Communication area which has been successfully
269 * processed by findFirstExport.
270 */
271void kFilePE::exportFindClose(kExportEntry *pExport)
272{
273 pExport = pExport;
274 return;
275}
276
277
278/**
279 * Lookup information on a spesific export given by ordinal number.
280 * @returns Success indicator.
281 * @param pExport Communication area containing export information
282 * on successful return.
283 * @remark stub
284 */
285BOOL kFilePE::exportLookup(unsigned long ulOrdinal, kExportEntry *pExport)
286{
287 assert(!"not implemented.");
288 ulOrdinal = ulOrdinal;
289 pExport = pExport;
290 return FALSE;
291}
292
293/**
294 * Lookup information on a spesific export given by name.
295 * @returns Success indicator.
296 * @param pExport Communication area containing export information
297 * on successful return.
298 * @remark stub
299 */
300BOOL kFilePE::exportLookup(const char * pszName, kExportEntry *pExport)
301{
302 assert(!"not implemented.");
303 pszName = pszName;
304 pExport = pExport;
305 return FALSE;
306}
307
308
309/**
310 * Mini dump function.
311 */
312BOOL kFilePE::dump(kFile *pOut)
313{
314 int i,j,k;
315 int c;
316
317 /*
318 * Dump sections.
319 */
320 pOut->printf("Sections\n"
321 "--------\n");
322 for (i = 0; i < pFileHdr->NumberOfSections; i++)
323 {
324 pOut->printf("%2d %-8.8s VirtSize: 0x%08x RVA: 0x%08x\n"
325 " RawSize: 0x%08x FileOffset: 0x%08x\n"
326 " #Relocs: 0x%08x FileOffset: 0x%08x\n"
327 " #LineNbr: 0x%08x FileOffset: 0x%08x\n"
328 " Characteristics: 0x%08x\n",
329 i,
330 paSectionHdr[i].Name,
331 paSectionHdr[i].Misc.VirtualSize,
332 paSectionHdr[i].VirtualAddress,
333 paSectionHdr[i].PointerToRawData,
334 paSectionHdr[i].PointerToRawData,
335 paSectionHdr[i].NumberOfRelocations,
336 paSectionHdr[i].PointerToRelocations,
337 paSectionHdr[i].NumberOfLinenumbers,
338 paSectionHdr[i].PointerToLinenumbers,
339 paSectionHdr[i].Characteristics
340 );
341 }
342 pOut->printf("\n");
343
344
345 /*
346 * Dump the directories.
347 */
348 pOut->printf("Data Directory\n"
349 "--------------\n");
350 for (i = 0; i < pOptHdr->NumberOfRvaAndSizes; i++)
351 {
352 static const char * apszDirectoryNames[] =
353 {
354 "Export",
355 "Import",
356 "Resource",
357 "Exception",
358 "Security",
359 "Base Reloc",
360 "Debug",
361 "Copyright",
362 "Global Ptr",
363 "TLS",
364 "Load Config",
365 "Bound Import",
366 "IAT",
367 "Delay Import",
368 "COM Descriptor",
369 "unknown",
370 "unknown"
371 };
372
373 pOut->printf("%2d %-16s Size: 0x%08x RVA: 0x%08x\n",
374 i,
375 apszDirectoryNames[i],
376 pOptHdr->DataDirectory[i].Size,
377 pOptHdr->DataDirectory[i].VirtualAddress);
378 }
379 pOut->printf("\n");
380
381
382 /*
383 * Dump Import Directory if present.
384 */
385 if (pImportDir)
386 {
387 pOut->printf("Import Directory\n"
388 "----------------\n");
389
390 PIMAGE_IMPORT_DESCRIPTOR pCur = pImportDir;
391 while (pCur->u.Characteristics != 0)
392 {
393 pOut->printf("%s\n", (char*)pvBase + pCur->Name);
394 pCur++;
395 }
396 }
397
398
399 /*
400 * Dump TLS directory if present
401 */
402 if (pTLSDir)
403 {
404 pOut->printf("TLS Directory\n"
405 "-------------\n");
406 if (pOptHdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size % sizeof(IMAGE_TLS_DIRECTORY))
407 pOut->printf(" Warning! The size directory isn't a multiple of the directory struct!");
408
409 c = (int)(pOptHdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size / sizeof(IMAGE_TLS_DIRECTORY));
410 for (i = 0; i < c; i++)
411 {
412
413 pOut->printf("%2d StartAddressOfRawData %p\n"
414 " EndAddressOfRawData %p\n"
415 " AddressOfIndex %p\n"
416 " AddressOfCallBacks %p\n"
417 " SizeOfZeroFill %p\n"
418 " Characteristics %p\n",
419 i,
420 pTLSDir[i].StartAddressOfRawData,
421 pTLSDir[i].EndAddressOfRawData,
422 pTLSDir[i].AddressOfIndex,
423 pTLSDir[i].AddressOfCallBacks,
424 pTLSDir[i].SizeOfZeroFill,
425 pTLSDir[i].Characteristics);
426
427 /* Print Callbacks */
428 if (pTLSDir[i].AddressOfCallBacks)
429 {
430 PULONG paulIndex;
431 PULONG paulCallback;
432 ULONG ulBorlandRVAFix = 0UL;
433
434 /* Check if the addresses in the TLSDir is RVAs or real addresses */
435 if (pTLSDir[i].StartAddressOfRawData > pOptHdr->ImageBase)
436 ulBorlandRVAFix = pOptHdr->ImageBase;
437
438 j = 0;
439 paulIndex = (PULONG)((ULONG)pTLSDir[i].AddressOfIndex - ulBorlandRVAFix + (ULONG)this->pvBase);
440 paulCallback = (PULONG)((ULONG)pTLSDir[i].AddressOfCallBacks - ulBorlandRVAFix + (ULONG)this->pvBase);
441 if (*paulCallback)
442 {
443 pOut->printf(" Callbacks:\n");
444 for (j = 0; paulCallback[j] != 0; j++)
445 {
446 pOut->printf(" %02d Address: 0x%08x Index: 0x%08x\n",
447 paulIndex[j],
448 paulCallback[j]);
449 }
450 }
451 else
452 pOut->printf(" (Empty callback array!)\n");
453 }
454
455 }
456
457 pOut->printf("\n");
458 }
459
460
461 return TRUE;
462}
463
Note: See TracBrowser for help on using the repository browser.