Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

532 lines
15 KiB

  1. //--------------------
  2. // PROGRAM: PEDUMP
  3. // FILE: EXEDUMP.C
  4. // AUTHOR: Matt Pietrek - 1993
  5. //--------------------
  6. #include <windows.h>
  7. #include <stdio.h>
  8. #include "common.h"
  9. #include "extrnvar.h"
  10. typedef PIMAGE_COFF_SYMBOLS_HEADER PIMAGE_DEBUG_INFO;
  11. PIMAGE_DEBUG_INFO PCOFFDebugInfo = 0;
  12. char *SzDebugFormats[] = {
  13. "UNKNOWN/BORLAND","COFF","CODEVIEW","FPO","MISC","EXCEPTION","FIXUP" };
  14. //
  15. // Dump the debug directory in a PE file.
  16. //
  17. void DumpDebugDirectory(DWORD base, PIMAGE_NT_HEADERS pNTHeader)
  18. {
  19. PIMAGE_DEBUG_DIRECTORY debugDir;
  20. PIMAGE_SECTION_HEADER header;
  21. unsigned cDebugFormats, i;
  22. DWORD offsetInto_rdata;
  23. DWORD va_debug_dir;
  24. PSTR szDebugFormat;
  25. // This line was so long that we had to break it up
  26. va_debug_dir = pNTHeader->OptionalHeader.
  27. DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].
  28. VirtualAddress;
  29. if ( va_debug_dir == 0 )
  30. return;
  31. // If we found a .debug section, and the debug directory is at the
  32. // beginning of this section, it looks like a Borland file
  33. header = GetSectionHeader(".debug", pNTHeader);
  34. if ( header && (header->VirtualAddress == va_debug_dir) )
  35. {
  36. debugDir = (PIMAGE_DEBUG_DIRECTORY)(header->PointerToRawData+base);
  37. cDebugFormats = pNTHeader->OptionalHeader.
  38. DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size;
  39. }
  40. else // Look for microsoft debug directory in the .rdata section
  41. {
  42. header = GetSectionHeader(".rdata", pNTHeader);
  43. if ( !header )
  44. return;
  45. // See if there's even any debug directories to speak of...
  46. cDebugFormats = pNTHeader->OptionalHeader.
  47. DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size
  48. / sizeof(IMAGE_DEBUG_DIRECTORY);
  49. if ( cDebugFormats == 0 )
  50. return;
  51. offsetInto_rdata = va_debug_dir - header->VirtualAddress;
  52. debugDir = MakePtr(PIMAGE_DEBUG_DIRECTORY, base,
  53. header->PointerToRawData + offsetInto_rdata);
  54. }
  55. printf(
  56. "Debug Formats in File\n"
  57. " Type Size Address FilePtr Charactr TimeData Version\n"
  58. " --------------- -------- -------- -------- -------- -------- --------\n"
  59. );
  60. for ( i=0; i < cDebugFormats; i++ )
  61. {
  62. szDebugFormat = (debugDir->Type <= 6)
  63. ? SzDebugFormats[debugDir->Type] : "???";
  64. printf(" %-15s %08X %08X %08X %08X %08X %u.%02u\n",
  65. szDebugFormat, debugDir->SizeOfData, debugDir->AddressOfRawData,
  66. debugDir->PointerToRawData, debugDir->Characteristics,
  67. debugDir->TimeDateStamp, debugDir->MajorVersion,
  68. debugDir->MinorVersion);
  69. // If COFF debug info, save its address away for later. We
  70. // do the check for "PointerToSymbolTable" because some files
  71. // have bogus values for the COFF header offset.
  72. if ( (debugDir->Type == IMAGE_DEBUG_TYPE_COFF) &&
  73. pNTHeader->FileHeader.PointerToSymbolTable )
  74. {
  75. PCOFFDebugInfo =
  76. (PIMAGE_DEBUG_INFO)(base+ debugDir->PointerToRawData);
  77. }
  78. debugDir++;
  79. }
  80. }
  81. // Function prototype (necessary because two functions recurse)
  82. void DumpResourceDirectory
  83. (
  84. PIMAGE_RESOURCE_DIRECTORY resDir, DWORD resourceBase,
  85. DWORD level, DWORD resourceType
  86. );
  87. // The predefined resource types
  88. char *SzResourceTypes[] = {
  89. "???_0", "CURSOR", "BITMAP", "ICON", "MENU", "DIALOG", "STRING", "FONTDIR",
  90. "FONT", "ACCELERATORS", "RCDATA", "MESSAGETABLE", "GROUP_CURSOR",
  91. "???_13", "GROUP_ICON", "???_15", "VERSION"
  92. };
  93. // Get an ASCII string representing a resource type
  94. void GetResourceTypeName(DWORD type, PSTR buffer, UINT cBytes)
  95. {
  96. if ( type <= 16 )
  97. strncpy(buffer, SzResourceTypes[type], cBytes);
  98. else
  99. wsprintf(buffer, "%X", type);
  100. }
  101. //
  102. // If a resource entry has a string name (rather than an ID), go find
  103. // the string and convert it from unicode to ascii.
  104. //
  105. void GetResourceNameFromId
  106. (
  107. DWORD id, DWORD resourceBase, PSTR buffer, UINT cBytes
  108. )
  109. {
  110. PIMAGE_RESOURCE_DIR_STRING_U prdsu;
  111. // If it's a regular ID, just format it.
  112. if ( !(id & IMAGE_RESOURCE_NAME_IS_STRING) )
  113. {
  114. wsprintf(buffer, "%X", id);
  115. return;
  116. }
  117. id &= 0x7FFFFFFF;
  118. prdsu = (PIMAGE_RESOURCE_DIR_STRING_U)(resourceBase + id);
  119. // prdsu->Length is the number of unicode characters
  120. WideCharToMultiByte(CP_ACP, 0, prdsu->NameString, prdsu->Length,
  121. buffer, cBytes, 0, 0);
  122. buffer[ min(cBytes-1,prdsu->Length) ] = 0; // Null terminate it!!!
  123. }
  124. //
  125. // Dump the information about one resource directory entry. If the
  126. // entry is for a subdirectory, call the directory dumping routine
  127. // instead of printing information in this routine.
  128. //
  129. void DumpResourceEntry
  130. (
  131. PIMAGE_RESOURCE_DIRECTORY_ENTRY resDirEntry,
  132. DWORD resourceBase,
  133. DWORD level
  134. )
  135. {
  136. UINT i;
  137. char nameBuffer[128];
  138. if ( resDirEntry->OffsetToData & IMAGE_RESOURCE_DATA_IS_DIRECTORY )
  139. {
  140. DumpResourceDirectory( (PIMAGE_RESOURCE_DIRECTORY)
  141. ((resDirEntry->OffsetToData & 0x7FFFFFFF) + resourceBase),
  142. resourceBase, level, resDirEntry->Name);
  143. return;
  144. }
  145. // Spit out the spacing for the level indentation
  146. for ( i=0; i < level; i++ )
  147. printf(" ");
  148. if ( resDirEntry->Name & IMAGE_RESOURCE_NAME_IS_STRING )
  149. {
  150. GetResourceNameFromId(resDirEntry->Name, resourceBase, nameBuffer,
  151. sizeof(nameBuffer));
  152. printf("Name: %s Offset: %08X\n",
  153. nameBuffer, resDirEntry->OffsetToData);
  154. }
  155. else
  156. {
  157. printf("ID: %08X Offset: %08X\n",
  158. resDirEntry->Name, resDirEntry->OffsetToData);
  159. }
  160. }
  161. //
  162. // Dump the information about one resource directory.
  163. //
  164. void DumpResourceDirectory
  165. (
  166. PIMAGE_RESOURCE_DIRECTORY resDir,
  167. DWORD resourceBase,
  168. DWORD level,
  169. DWORD resourceType
  170. )
  171. {
  172. PIMAGE_RESOURCE_DIRECTORY_ENTRY resDirEntry;
  173. char szType[64];
  174. UINT i;
  175. // Spit out the spacing for the level indentation
  176. for ( i=0; i < level; i++ )
  177. printf(" ");
  178. // Level 1 resources are the resource types
  179. if ( level == 1 && !(resourceType & IMAGE_RESOURCE_NAME_IS_STRING) )
  180. {
  181. GetResourceTypeName( resourceType, szType, sizeof(szType) );
  182. }
  183. else // Just print out the regular id or name
  184. {
  185. GetResourceNameFromId( resourceType, resourceBase, szType,
  186. sizeof(szType) );
  187. }
  188. printf(
  189. "ResDir (%s) Named:%02X ID:%02X TimeDate:%08X Vers:%u.%02u Char:%X\n",
  190. szType, resDir->NumberOfNamedEntries, resDir->NumberOfIdEntries,
  191. resDir->TimeDateStamp, resDir->MajorVersion,
  192. resDir->MinorVersion,resDir->Characteristics);
  193. resDirEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resDir+1);
  194. for ( i=0; i < resDir->NumberOfNamedEntries; i++, resDirEntry++ )
  195. DumpResourceEntry(resDirEntry, resourceBase, level+1);
  196. for ( i=0; i < resDir->NumberOfIdEntries; i++, resDirEntry++ )
  197. DumpResourceEntry(resDirEntry, resourceBase, level+1);
  198. }
  199. //
  200. // Top level routine called to dump out the entire resource hierarchy
  201. //
  202. void DumpResourceSection(DWORD base, PIMAGE_NT_HEADERS pNTHeader)
  203. {
  204. PIMAGE_RESOURCE_DIRECTORY resDir;
  205. resDir = GetSectionPtr(".rsrc", pNTHeader, (DWORD)base);
  206. if ( !resDir )
  207. return;
  208. printf("Resources\n");
  209. DumpResourceDirectory(resDir, (DWORD)resDir, 0, 0);
  210. }
  211. //
  212. // Dump the imports table (the .idata section) of a PE file
  213. //
  214. void DumpImportsSection(DWORD base, PIMAGE_NT_HEADERS pNTHeader)
  215. {
  216. PIMAGE_IMPORT_DESCRIPTOR importDesc;
  217. PIMAGE_SECTION_HEADER header;
  218. PIMAGE_THUNK_DATA thunk;
  219. PIMAGE_IMPORT_BY_NAME pOrdinalName;
  220. DWORD exportsStartRVA, exportsEndRVA;
  221. INT delta;
  222. header = GetSectionHeader(".idata", pNTHeader);
  223. if ( !header )
  224. return;
  225. importDesc = MakePtr(PIMAGE_IMPORT_DESCRIPTOR, base,
  226. header->PointerToRawData);
  227. delta = (INT)(header->VirtualAddress - header->PointerToRawData);
  228. printf("Imports Table:\n");
  229. while ( 1 )
  230. {
  231. // See if we've reached an empty IMAGE_IMPORT_DESCRIPTOR
  232. if ( (importDesc->TimeDateStamp==0 ) && (importDesc->Name==0) )
  233. break;
  234. printf(" %s\n", (PBYTE)(importDesc->Name) - delta + base);
  235. printf(" Hint/Name Table: %08X\n", importDesc->Characteristics);
  236. printf(" TimeDateStamp: %08X\n", importDesc->TimeDateStamp);
  237. printf(" ForwarderChain: %08X\n", importDesc->ForwarderChain);
  238. printf(" First thunk RVA: %08X\n", importDesc->FirstThunk);
  239. thunk = (PIMAGE_THUNK_DATA)importDesc->FirstThunk;
  240. thunk = (PIMAGE_THUNK_DATA)( (PBYTE)thunk - delta + base);
  241. // If the pointer that thunk points to is outside of the .idata
  242. // section, it looks like this file is "pre-fixed up" with regards
  243. // to the thunk table. In this situation, we'll need to fall back
  244. // to the hint-name (aka, the "Characteristics") table.
  245. exportsStartRVA = header->VirtualAddress;
  246. exportsEndRVA= exportsStartRVA + header->SizeOfRawData;
  247. if ( (*(PDWORD)thunk <= exportsStartRVA) ||
  248. (*(PDWORD)thunk >= exportsEndRVA) )
  249. {
  250. if ( importDesc->Characteristics == 0 ) // Borland doesn't have
  251. return; // this table!!!
  252. thunk = (PIMAGE_THUNK_DATA)importDesc->Characteristics;
  253. if ( ((DWORD)thunk <= exportsStartRVA) ||
  254. ((DWORD)thunk >= exportsEndRVA) )
  255. return;
  256. thunk = (PIMAGE_THUNK_DATA)( (PBYTE)thunk - delta + base);
  257. }
  258. printf(" Ordn Name\n");
  259. while ( 1 ) // Loop forever (or until we break out)
  260. {
  261. if ( thunk->u1.AddressOfData == 0 )
  262. break;
  263. if ( thunk->u1.Ordinal & IMAGE_ORDINAL_FLAG )
  264. {
  265. printf(" %4u\n", thunk->u1.Ordinal & 0xFFFF);
  266. break;
  267. }
  268. else
  269. {
  270. pOrdinalName = thunk->u1.AddressOfData;
  271. pOrdinalName = (PIMAGE_IMPORT_BY_NAME)
  272. ((PBYTE)pOrdinalName - delta + base);
  273. printf(" %4u %s\n", pOrdinalName->Hint, pOrdinalName->Name);
  274. }
  275. thunk++; // Advance to next thunk
  276. }
  277. importDesc++; // advance to next IMAGE_IMPORT_DESCRIPTOR
  278. printf("\n");
  279. }
  280. }
  281. //
  282. // Dump the exports table (the .edata section) of a PE file
  283. //
  284. void DumpExportsSection(DWORD base, PIMAGE_NT_HEADERS pNTHeader)
  285. {
  286. PIMAGE_EXPORT_DIRECTORY exportDir;
  287. PIMAGE_SECTION_HEADER header;
  288. INT delta;
  289. PSTR filename;
  290. DWORD i;
  291. PDWORD functions;
  292. PWORD ordinals;
  293. PSTR *name;
  294. header = GetSectionHeader(".edata", pNTHeader);
  295. if ( !header )
  296. return;
  297. exportDir = MakePtr(PIMAGE_EXPORT_DIRECTORY, base,
  298. header->PointerToRawData);
  299. delta = (INT)(header->VirtualAddress - header->PointerToRawData);
  300. filename = (PSTR)(exportDir->Name - delta + base);
  301. printf("exports table:\n\n");
  302. printf(" Name: %s\n", filename);
  303. printf(" Characteristics: %08X\n", exportDir->Characteristics);
  304. printf(" TimeDateStamp: %08X\n", exportDir->TimeDateStamp);
  305. printf(" Version: %u.%02u\n", exportDir->MajorVersion,
  306. exportDir->MinorVersion);
  307. printf(" Ordinal base: %08X\n", exportDir->Base);
  308. printf(" # of functions: %08X\n", exportDir->NumberOfFunctions);
  309. printf(" # of Names: %08X\n", exportDir->NumberOfNames);
  310. functions = (PDWORD)((DWORD)exportDir->AddressOfFunctions - delta + base);
  311. ordinals = (PWORD)((DWORD)exportDir->AddressOfNameOrdinals - delta + base);
  312. name = (PSTR *)((DWORD)exportDir->AddressOfNames - delta + base);
  313. printf("\n Entry Pt Ordn Name\n");
  314. for ( i=0; i < exportDir->NumberOfNames; i++ )
  315. {
  316. printf(" %08X %4u %s\n", *functions,
  317. *ordinals + exportDir->Base,
  318. (*name - delta + base));
  319. name++; // Bump each pointer to the next array element
  320. ordinals++;
  321. functions++;
  322. }
  323. }
  324. // The names of the available base relocations
  325. char *SzRelocTypes[] = {
  326. "ABSOLUTE","HIGH","LOW","HIGHLOW","HIGHADJ","MIPS_JMPADDR",
  327. "I860_BRADDR","I860_SPLIT" };
  328. //
  329. // Dump the base relocation table of a PE file
  330. //
  331. void DumpBaseRelocationsSection(DWORD base, PIMAGE_NT_HEADERS pNTHeader)
  332. {
  333. PIMAGE_BASE_RELOCATION baseReloc;
  334. baseReloc = GetSectionPtr(".reloc", pNTHeader, base);
  335. if ( !baseReloc )
  336. return;
  337. printf("base relocations:\n\n");
  338. while ( baseReloc->SizeOfBlock != 0 )
  339. {
  340. unsigned i,cEntries;
  341. PWORD pEntry;
  342. char *szRelocType;
  343. WORD relocType;
  344. cEntries = (baseReloc->SizeOfBlock-sizeof(*baseReloc))/sizeof(WORD);
  345. pEntry = MakePtr( PWORD, baseReloc, sizeof(*baseReloc) );
  346. printf("Virtual Address: %08X size: %08X\n",
  347. baseReloc->VirtualAddress, baseReloc->SizeOfBlock);
  348. for ( i=0; i < cEntries; i++ )
  349. {
  350. // Extract the top 4 bits of the relocation entry. Turn those 4
  351. // bits into an appropriate descriptive string (szRelocType)
  352. relocType = (*pEntry & 0xF000) >> 12;
  353. szRelocType = relocType < 8 ? SzRelocTypes[relocType] : "unknown";
  354. printf(" %08X %s\n",
  355. (*pEntry & 0x0FFF) + baseReloc->VirtualAddress,
  356. szRelocType);
  357. pEntry++; // Advance to next relocation entry
  358. }
  359. baseReloc = MakePtr( PIMAGE_BASE_RELOCATION, baseReloc,
  360. baseReloc->SizeOfBlock);
  361. }
  362. }
  363. //
  364. // Dump the COFF debug information header
  365. //
  366. void DumpCOFFHeader(PIMAGE_DEBUG_INFO pDbgInfo)
  367. {
  368. printf("COFF Debug Info Header\n");
  369. printf(" NumberOfSymbols: %08X\n", pDbgInfo->NumberOfSymbols);
  370. printf(" LvaToFirstSymbol: %08X\n", pDbgInfo->LvaToFirstSymbol);
  371. printf(" NumberOfLinenumbers: %08X\n", pDbgInfo->NumberOfLinenumbers);
  372. printf(" LvaToFirstLinenumber: %08X\n", pDbgInfo->LvaToFirstLinenumber);
  373. printf(" RvaToFirstByteOfCode: %08X\n", pDbgInfo->RvaToFirstByteOfCode);
  374. printf(" RvaToLastByteOfCode: %08X\n", pDbgInfo->RvaToLastByteOfCode);
  375. printf(" RvaToFirstByteOfData: %08X\n", pDbgInfo->RvaToFirstByteOfData);
  376. printf(" RvaToLastByteOfData: %08X\n", pDbgInfo->RvaToLastByteOfData);
  377. }
  378. //
  379. // top level routine called from PEDUMP.C to dump the components of a PE file
  380. //
  381. void DumpExeFile( PIMAGE_DOS_HEADER dosHeader )
  382. {
  383. PIMAGE_NT_HEADERS pNTHeader;
  384. DWORD base = (DWORD)dosHeader;
  385. pNTHeader = MakePtr( PIMAGE_NT_HEADERS, dosHeader,
  386. dosHeader->e_lfanew );
  387. // First, verify that the e_lfanew field gave us a reasonable
  388. // pointer, then verify the PE signature.
  389. if ( IsBadReadPtr(pNTHeader, sizeof(IMAGE_NT_HEADERS)) ||
  390. pNTHeader->Signature != IMAGE_NT_SIGNATURE )
  391. {
  392. printf("Unhandled EXE type, or invalid .EXE\n");
  393. return;
  394. }
  395. DumpHeader((PIMAGE_FILE_HEADER)&pNTHeader->FileHeader);
  396. printf("\n");
  397. DumpOptionalHeader((PIMAGE_OPTIONAL_HEADER)&pNTHeader->OptionalHeader);
  398. printf("\n");
  399. DumpSectionTable( (PIMAGE_SECTION_HEADER)(pNTHeader+1),
  400. pNTHeader->FileHeader.NumberOfSections, TRUE);
  401. printf("\n");
  402. DumpDebugDirectory(base, pNTHeader);
  403. printf("\n");
  404. DumpResourceSection(base, pNTHeader);
  405. printf("\n");
  406. DumpImportsSection(base, pNTHeader);
  407. printf("\n");
  408. DumpExportsSection(base, pNTHeader);
  409. printf("\n");
  410. if ( fShowRelocations )
  411. {
  412. DumpBaseRelocationsSection(base, pNTHeader);
  413. printf("\n");
  414. }
  415. //
  416. // Initialize these vars here since we'll need them in DumpLineNumbers
  417. //
  418. PCOFFSymbolTable = MakePtr(PIMAGE_SYMBOL, base,
  419. pNTHeader->FileHeader.PointerToSymbolTable);
  420. COFFSymbolCount = pNTHeader->FileHeader.NumberOfSymbols;
  421. if ( fShowSymbolTable && PCOFFDebugInfo )
  422. {
  423. DumpCOFFHeader( PCOFFDebugInfo );
  424. printf("\n");
  425. }
  426. if ( fShowLineNumbers && PCOFFDebugInfo )
  427. {
  428. DumpLineNumbers( MakePtr(PIMAGE_LINENUMBER, PCOFFDebugInfo,
  429. PCOFFDebugInfo->LvaToFirstLinenumber),
  430. PCOFFDebugInfo->NumberOfLinenumbers);
  431. printf("\n");
  432. }
  433. if ( fShowSymbolTable )
  434. {
  435. if ( pNTHeader->FileHeader.NumberOfSymbols
  436. && pNTHeader->FileHeader.PointerToSymbolTable)
  437. {
  438. DumpSymbolTable(PCOFFSymbolTable, COFFSymbolCount);
  439. printf("\n");
  440. }
  441. }
  442. if ( fShowRawSectionData )
  443. {
  444. DumpRawSectionData( (PIMAGE_SECTION_HEADER)(pNTHeader+1),
  445. dosHeader,
  446. pNTHeader->FileHeader.NumberOfSections);
  447. }
  448. }