a7a6e91ff1
git-svn-id: svn://kolibrios.org@8602 a494cfbc-eb01-0410-851d-a64ba20cac60
340 lines
14 KiB
C
340 lines
14 KiB
C
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
|
|
#define EPEP_INST
|
|
#include "epep.h"
|
|
|
|
#define ERROR(epep) (printf("Error #%u from EPEP at " __FILE__ ": %u", epep.error_code, __LINE__), 1)
|
|
|
|
int main(int argc, char **argv) {
|
|
if (argc < 2) {
|
|
printf("Usage:\n%s <filename>\n", argv[0]);
|
|
return 0;
|
|
}
|
|
Epep epep = { 0 };
|
|
FILE *fp = fopen(argv[1], "rb");
|
|
if (!fp) {
|
|
printf("File not found: %s\n", argv[1]);
|
|
return 1;
|
|
}
|
|
if (!epep_init(&epep, fp)) {
|
|
printf("Not PE");
|
|
return 1;
|
|
}
|
|
printf("COFF File Header:\n");
|
|
printf(" Machine: %04x\n", epep.coffFileHeader.Machine);
|
|
printf(" NumberOfSections: %04x\n", epep.coffFileHeader.NumberOfSections);
|
|
printf(" TimeDateStamp: %08x\n", epep.coffFileHeader.TimeDateStamp);
|
|
printf(" PointerToSymbolTable: %08x\n", epep.coffFileHeader.PointerToSymbolTable);
|
|
printf(" NumberOfSymbols: %08x\n", epep.coffFileHeader.NumberOfSymbols);
|
|
printf(" SizeOfOptionalHeader: %04x\n", epep.coffFileHeader.SizeOfOptionalHeader);
|
|
printf(" Characteristics: %04x\n", epep.coffFileHeader.Characteristics);
|
|
printf("\n");
|
|
if (epep.coffFileHeader.SizeOfOptionalHeader != 0) {
|
|
printf("Optional Header:\n");
|
|
printf(" Magic: %04x\n", epep.optionalHeader.Magic);
|
|
printf(" MajorLinkerVersion: %02x\n", epep.optionalHeader.MajorLinkerVersion);
|
|
printf(" MinorLinkerVersion: %02x\n", epep.optionalHeader.MinorLinkerVersion);
|
|
printf(" SizeOfCode: %08x\n", epep.optionalHeader.SizeOfCode);
|
|
printf(" SizeOfInitializedData: %08x\n", epep.optionalHeader.SizeOfInitializedData);
|
|
printf(" SizeOfUninitializedData: %08x\n", epep.optionalHeader.SizeOfUninitializedData);
|
|
printf(" AddressOfEntryPoint: %08x\n", epep.optionalHeader.AddressOfEntryPoint);
|
|
printf(" BaseOfCode: %08x\n", epep.optionalHeader.BaseOfCode);
|
|
printf(" BaseOfData: %08x\n", epep.optionalHeader.BaseOfData);
|
|
printf(" ImageBase: %016x\n", epep.optionalHeader.ImageBase);
|
|
printf(" SectionAlignment: %08x\n", epep.optionalHeader.SectionAlignment);
|
|
printf(" FileAlignment: %08x\n", epep.optionalHeader.FileAlignment);
|
|
printf(" MajorOperatingSystemVersion: %04x\n", epep.optionalHeader.MajorOperatingSystemVersion);
|
|
printf(" MinorOperatingSystemVersion: %04x\n", epep.optionalHeader.MinorOperatingSystemVersion);
|
|
printf(" MajorImageVersion: %04x\n", epep.optionalHeader.MajorImageVersion);
|
|
printf(" MinorImageVersion: %04x\n", epep.optionalHeader.MinorImageVersion);
|
|
printf(" MajorSubsystemVersion: %04x\n", epep.optionalHeader.MajorSubsystemVersion);
|
|
printf(" MinorSubsystemVersion: %04x\n", epep.optionalHeader.MinorSubsystemVersion);
|
|
printf(" Win32VersionValue: %08x\n", epep.optionalHeader.Win32VersionValue);
|
|
printf(" SizeOfImage: %08x\n", epep.optionalHeader.SizeOfImage);
|
|
printf(" SizeOfHeaders: %08x\n", epep.optionalHeader.SizeOfHeaders);
|
|
printf(" CheckSum: %08x\n", epep.optionalHeader.CheckSum);
|
|
printf(" Subsystem: %04x\n", epep.optionalHeader.Subsystem);
|
|
printf(" DllCharacteristics: %04x\n", epep.optionalHeader.DllCharacteristics);
|
|
printf(" SizeOfStackReserve: %016x\n", epep.optionalHeader.SizeOfStackReserve);
|
|
printf(" SizeOfStackCommit: %016x\n", epep.optionalHeader.SizeOfStackCommit);
|
|
printf(" SizeOfHeapReserve: %016x\n", epep.optionalHeader.SizeOfHeapReserve);
|
|
printf(" SizeOfHeapCommit: %016x\n", epep.optionalHeader.SizeOfHeapCommit);
|
|
printf(" LoaderFlags: %08x\n", epep.optionalHeader.LoaderFlags);
|
|
printf(" NumberOfRvaAndSizes: %08x\n", epep.optionalHeader.NumberOfRvaAndSizes);
|
|
printf("\n");
|
|
printf("Data directories:\n");
|
|
for (size_t i = 0; i < epep.optionalHeader.NumberOfRvaAndSizes; i++) {
|
|
char *dds[] = {
|
|
"Export Table",
|
|
"Import Table",
|
|
"Resource Table",
|
|
"Exception Table",
|
|
"Certificate Table",
|
|
"Base Relocation Table",
|
|
"Debug",
|
|
"Architecture",
|
|
"Global Ptr",
|
|
"TLS Table",
|
|
"Load Config Table",
|
|
"Bound Import",
|
|
"Import Address Table",
|
|
"Delay Import Descriptor",
|
|
"CLR Runtime Header",
|
|
"Reserved, must be zero"
|
|
};
|
|
EpepImageDataDirectory idd = { 0 };
|
|
if (!epep_get_data_directory_by_index(&epep, &idd, i)) {
|
|
return ERROR(epep);
|
|
}
|
|
printf(" Data directory #%u:\n", i);
|
|
printf(" Type: %s\n", dds[i % 16]);
|
|
printf(" VirtualAddress: %016x\n", idd.VirtualAddress);
|
|
printf(" Size: %016x\n", idd.Size);
|
|
// Certificate table (4'th) data directory's VirtualAddress isn't a real RVA, it's a file offset
|
|
// so it's actually outside of any section, so let's skip section name printing for it
|
|
if (idd.VirtualAddress && i != 4) {
|
|
EpepSectionHeader sh = { 0 };
|
|
if (!epep_get_section_header_by_rva(&epep, &sh, idd.VirtualAddress)) {
|
|
return ERROR(epep);
|
|
}
|
|
printf(" Section: %s\n", sh.Name);
|
|
}
|
|
}
|
|
printf("\n");
|
|
}
|
|
|
|
// Get string table useful to show long names of sections
|
|
size_t string_table_size = 1;
|
|
if (epep.kind == EPEP_OBJECT && !epep_get_string_table_size(&epep, &string_table_size)) {
|
|
return ERROR(epep);
|
|
}
|
|
char *string_table = malloc(string_table_size);
|
|
if (epep.kind == EPEP_OBJECT && !epep_get_string_table(&epep, string_table)) {
|
|
return ERROR(epep);
|
|
}
|
|
|
|
printf("Section Table:\n");
|
|
for (size_t i = 0; i < epep.coffFileHeader.NumberOfSections; i++) {
|
|
EpepSectionHeader sh = { 0 };
|
|
if (!epep_get_section_header_by_index(&epep, &sh, i)) {
|
|
return ERROR(epep);
|
|
}
|
|
printf(" Section #%u\n", i);
|
|
if (epep.kind == EPEP_OBJECT && sh.Name[0] == '/') {
|
|
printf(" Name: %s\n", &string_table[atoi(sh.Name + 1)]);
|
|
} else {
|
|
printf(" Name: %.*s\n", 8, sh.Name);
|
|
}
|
|
printf(" VirtualSize: %08x\n", sh.VirtualSize);
|
|
printf(" VirtualAddress: %08x\n", sh.VirtualAddress);
|
|
printf(" SizeOfRawData: %08x\n", sh.SizeOfRawData);
|
|
printf(" PointerToRawData: %08x\n", sh.PointerToRawData);
|
|
printf(" PointerToRelocations: %08x\n", sh.PointerToRelocations);
|
|
printf(" PointerToLinenumbers: %08x\n", sh.PointerToLinenumbers);
|
|
printf(" NumberOfRelocations: %08x\n", sh.NumberOfRelocations);
|
|
printf(" NumberOfLinenumbers: %08x\n", sh.NumberOfLinenumbers);
|
|
printf(" Characteristics: %08x\n", sh.Characteristics);
|
|
}
|
|
printf("\n");
|
|
if (epep.kind == EPEP_OBJECT && epep.coffFileHeader.NumberOfSymbols != 0) {
|
|
printf("Symbols:\n");
|
|
for (size_t i = 0; i < epep.coffFileHeader.NumberOfSymbols; i++) {
|
|
EpepCoffSymbol sym = { 0 };
|
|
if (!epep_get_symbol_by_index(&epep, &sym, i)) {
|
|
return ERROR(epep);
|
|
}
|
|
printf(" Symbol #%u\n", i);
|
|
if (sym.symbol.Zeroes == 0) {
|
|
printf(" Name: %s\n", &string_table[sym.symbol.Offset]);
|
|
} else {
|
|
printf(" Name: %.*s\n", 8, sym.symbol.ShortName);
|
|
}
|
|
printf(" Value: %08x\n", sym.symbol.Value);
|
|
printf(" SectionNumber: %04x\n", sym.symbol.SectionNumber);
|
|
printf(" Type: %04x\n", sym.symbol.Type);
|
|
printf(" StorageClass: %02x\n", sym.symbol.StorageClass);
|
|
printf(" NumberOfAuxSymbols: %02x\n", sym.symbol.NumberOfAuxSymbols);
|
|
for (size_t j = 0; j < sym.symbol.NumberOfAuxSymbols; j++) {
|
|
i++;
|
|
}
|
|
}
|
|
printf("\n");
|
|
}
|
|
if (epep_has_import_table(&epep)) {
|
|
printf("Import Directory Table:\n");
|
|
for (size_t i = 0; i < 1024; i++) {
|
|
EpepImportDirectory import_directory = { 0 };
|
|
if (!epep_get_import_directory_by_index(&epep, &import_directory, i)) {
|
|
return ERROR(epep);
|
|
}
|
|
if (import_directory.NameRva == 0) {
|
|
break;
|
|
}
|
|
size_t name_max = 1024;
|
|
char name[name_max];
|
|
if (!epep_get_import_directory_name_s(&epep, &import_directory, name, name_max)) {
|
|
return ERROR(epep);
|
|
}
|
|
printf(" Import Directory #%lu:\n", i);
|
|
printf(" Name: %s\n", name);
|
|
printf(" ImportLookupTableRva: %08x\n", import_directory.ImportLookupTableRva);
|
|
printf(" TimeDateStamp: %08x\n", import_directory.TimeDateStamp);
|
|
printf(" ForwarderChain: %08x\n", import_directory.ForwarderChain);
|
|
printf(" ImportAddressTableRva: %08x\n", import_directory.ImportAddressTableRva);
|
|
for (size_t j = 0; j < 1024 * 1024; j++) {
|
|
size_t lookup = 0;
|
|
if (!epep_get_import_directory_lookup_by_index(&epep, &import_directory, &lookup, j)) {
|
|
return ERROR(epep);
|
|
}
|
|
if (lookup == 0) {
|
|
break;
|
|
}
|
|
size_t name_max = 1024;
|
|
char name[name_max];
|
|
if (!epep_get_lookup_name_s(&epep, lookup, name, name_max)) {
|
|
return ERROR(epep);
|
|
}
|
|
printf(" Lookup: %016x (%s)\n", lookup, name);
|
|
}
|
|
}
|
|
printf("\n");
|
|
}
|
|
if (epep_has_export_table(&epep)) {
|
|
if (!epep_read_export_directory(&epep)) {
|
|
return ERROR(epep);
|
|
}
|
|
size_t name_max = 256;
|
|
char name[name_max];
|
|
strcpy(name, "undefined");
|
|
if (!epep_get_dll_name_s(&epep, name, name_max)) {
|
|
return ERROR(epep);
|
|
}
|
|
printf("Export Directory:\n");
|
|
printf(" ExportFlags: %08x\n", epep.export_directory.ExportFlags);
|
|
printf(" TimeDateStamp: %08x\n", epep.export_directory.TimeDateStamp);
|
|
printf(" MajorVersion: %04x\n", epep.export_directory.MajorVersion);
|
|
printf(" MinorVersion: %04x\n", epep.export_directory.MinorVersion);
|
|
printf(" NameRva: %08x (%s)\n", epep.export_directory.NameRva, name);
|
|
printf(" OrdinalBase: %08x\n", epep.export_directory.OrdinalBase);
|
|
printf(" AddressTableEntries: %08x\n", epep.export_directory.AddressTableEntries);
|
|
printf(" NumberOfNamePointers: %08x\n", epep.export_directory.NumberOfNamePointers);
|
|
printf(" ExportAddressTableRva: %08x\n", epep.export_directory.ExportAddressTableRva);
|
|
printf(" NamePointerRva: %08x\n", epep.export_directory.NamePointerRva);
|
|
printf(" OrdinalTableRva: %08x\n", epep.export_directory.OrdinalTableRva);
|
|
printf(" Exports:\n");
|
|
for (size_t i = 0; i < epep.export_directory.AddressTableEntries; i++) {
|
|
printf(" Export #%u:\n", i);
|
|
size_t name_max = 1024;
|
|
char name[name_max];
|
|
printf(" Ordinal: %u\n", epep.export_directory.OrdinalBase + i);
|
|
if (epep_get_export_name_s_by_index(&epep, name, name_max, i)) {
|
|
printf(" Name: %s\n", name);
|
|
}
|
|
EpepExportAddress ea = { 0 };
|
|
if (!epep_get_export_address_by_index(&epep, &ea, i)) {
|
|
return ERROR(epep);
|
|
}
|
|
if (epep_export_address_is_forwarder(&epep, &ea)) {
|
|
size_t forwarder_max = 1024;
|
|
char forwarder[forwarder_max];
|
|
if (!epep_get_export_address_forwarder_s(&epep, &ea, forwarder, forwarder_max)) {
|
|
return ERROR(epep);
|
|
}
|
|
printf(" ForwarderRva: %08x (%s)\n", ea.ForwarderRva, forwarder);
|
|
} else {
|
|
printf(" ExportRva: %08x\n", ea.ExportRva);
|
|
}
|
|
}
|
|
printf("\n");
|
|
}
|
|
if (epep_has_base_relocation_table(&epep)) {
|
|
printf("Base Relocations:\n");
|
|
EpepBaseRelocationBlock brb = { 0 };
|
|
if (!epep_get_first_base_relocation_block(&epep, &brb)) {
|
|
return ERROR(epep);
|
|
}
|
|
for (size_t i = 0; brb.offset; i++) {
|
|
printf(" Base Relocation Block #%u:\n", i);
|
|
printf(" PageRva: %08x\n", brb.PageRva);
|
|
printf(" BlockSize: %08x\n", brb.BlockSize);
|
|
printf(" Relocations:\n");
|
|
for (size_t j = 0; j < ((brb.BlockSize - 8) / 2); j++) {
|
|
char *strs[] = {
|
|
"IMAGE_REL_BASED_ABSOLUTE",
|
|
"IMAGE_REL_BASED_HIGH",
|
|
"IMAGE_REL_BASED_LOW",
|
|
"IMAGE_REL_BASED_HIGHLOW",
|
|
"IMAGE_REL_BASED_HIGHADJ",
|
|
"IMAGE_REL_BASED_MIPS_JMPADDR | IMAGE_REL_BASED_ARM_MOV32 | IMAGE_REL_BASED_RISCV_HIGH20",
|
|
"reserved, must be zero",
|
|
"IMAGE_REL_BASED_THUMB_MOV32 | IMAGE_REL_BASED_RISCV_LOW12I",
|
|
"IMAGE_REL_BASED_RISCV_LOW12S",
|
|
"IMAGE_REL_BASED_MIPS_JMPADDR16",
|
|
"IMAGE_REL_BASED_DIR64",
|
|
};
|
|
printf(" Relocation #%u:\n", j);
|
|
EpepBaseRelocation br = { 0 };
|
|
if (!epep_get_base_relocation_block_base_relocation_by_index(&epep, &brb, &br, j)) {
|
|
return ERROR(epep);
|
|
}
|
|
printf(" Type: %01x (%s)\n", br.Type, strs[br.Type % (sizeof(strs) / sizeof(*strs))]);
|
|
printf(" Offset: %03x (%u)\n", br.Offset, br.Offset);
|
|
}
|
|
if (!epep_get_next_base_relocation_block(&epep, &brb)) {
|
|
return ERROR(epep);
|
|
}
|
|
}
|
|
printf("\n");
|
|
}
|
|
if (epep.kind == EPEP_OBJECT) {
|
|
for (size_t i = 0; i < epep.coffFileHeader.NumberOfSections; i++) {
|
|
EpepSectionHeader sh = { 0 };
|
|
if (!epep_get_section_header_by_index(&epep, &sh, i)) {
|
|
return ERROR(epep);
|
|
}
|
|
printf(" Relocations for section #%u", i);
|
|
if (epep.kind == EPEP_OBJECT && sh.Name[0] == '/') {
|
|
printf(" (%s)\n", &string_table[atoi(sh.Name + 1)]);
|
|
} else {
|
|
printf(" (%.*s)\n", 8, sh.Name);
|
|
}
|
|
for (size_t i = 0; i < sh.NumberOfRelocations; i++) {
|
|
EpepCoffRelocation rel = { 0 };
|
|
if (!epep_get_section_relocation_by_index(&epep, &sh, &rel, i)) {
|
|
return ERROR(epep);
|
|
}
|
|
printf(" COFF Relocation #%u\n", i);
|
|
printf(" VirtualAddress: %08x\n", rel.VirtualAddress);
|
|
printf(" SymbolTableIndex: %08x\n", rel.SymbolTableIndex);
|
|
printf(" Type: %04x\n", rel.Type);
|
|
}
|
|
}
|
|
}
|
|
if (epep.kind == EPEP_OBJECT) {
|
|
for (size_t i = 0; i < epep.coffFileHeader.NumberOfSections; i++) {
|
|
EpepSectionHeader sh = { 0 };
|
|
if (!epep_get_section_header_by_index(&epep, &sh, i)) {
|
|
return ERROR(epep);
|
|
}
|
|
printf(" Linenumbers for section #%u", i);
|
|
if (epep.kind == EPEP_OBJECT && sh.Name[0] == '/') {
|
|
printf(" (%s)\n", &string_table[atoi(sh.Name + 1)]);
|
|
} else {
|
|
printf(" (%.*s)\n", 8, sh.Name);
|
|
}
|
|
for (size_t i = 0; i < sh.NumberOfLinenumbers; i++) {
|
|
EpepCoffLinenumber ln = { 0 };
|
|
if (!epep_get_section_line_number_by_index(&epep, &sh, &ln, i)) {
|
|
return ERROR(epep);
|
|
}
|
|
printf(" COFF Line Number #%u\n", i);
|
|
printf(" Type: %04x\n", ln.Type);
|
|
printf(" Linenumber: %08x\n", ln.Linenumber);
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|