Subversion Repositories Kolibri OS

Rev

Rev 8948 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. // Dependencies:
  2. // <assert.h> or any another source of assert()
  3. // <stdint.h> or any another source of uint64_t, uint32_t, uint16_t, uint8_t, size_t
  4.  
  5. #ifndef EPEP_ASSERT
  6. #include <assert.h>
  7. #define EPEP_ASSERT(x) assert(x)
  8. #endif
  9.  
  10. #ifndef EPEP_READER
  11. #include <stdio.h>
  12. #define EPEP_READER FILE *
  13. #define EPEP_READER_GET(preader) getc(*preader)
  14. #define EPEP_READER_SEEK(preader, offset) fseek(*preader, offset, SEEK_SET)
  15. #define EPEP_READER_TELL(preader) ftell(*preader)
  16. #define EPEP_READER_GET_BLOCK(preader, size, buf) fread(buf, 1, size, *preader);
  17. #endif
  18.  
  19. //
  20. // Constants
  21. //
  22.  
  23. typedef enum {
  24.         EPEP_INVALID,
  25.         EPEP_IMAGE,
  26.         EPEP_OBJECT,
  27. } EpepKind;
  28.  
  29. typedef enum {
  30.         EPEP_ERR_SUCCESS,
  31.         EPEP_ERR_DATA_DIRECTORY_INDEX_IS_INVALID,
  32.         EPEP_ERR_SECTION_HEADER_INDEX_IS_INVALID,
  33.         EPEP_ERR_SYMBOL_INDEX_IS_INVALID,
  34.         EPEP_ERR_NOT_AN_OBJECT,
  35.         EPEP_ERR_ADDRESS_IS_OUT_OF_SECTION_RAW_DATA,
  36.         EPEP_ERR_OUTPUT_CAPACITY_IS_ZERO,
  37.         EPEP_ERR_OUTPUT_IS_NULL,
  38.         EPEP_ERR_ADDRESS_IS_OUT_OF_ANY_SECTION,
  39.         EPEP_ERR_EXPORT_ADDRESS_TABLE_ENTRY_NAME_NOT_FOUND,
  40.         EPEP_ERR_NO_BASE_RELOCATION_TABLE,
  41.         EPEP_ERR_BASE_RELOCATION_IS_ALREADY_END,
  42. } EpepError;
  43.  
  44. //
  45. // Generic
  46. //
  47.  
  48. typedef struct {
  49.         EPEP_READER reader;
  50.         EpepKind kind;
  51.         EpepError error_code;
  52.         size_t signature_offset_offset;
  53.         size_t signature_offset;
  54.         size_t first_data_directory_offset;
  55.         size_t first_section_header_offset;
  56.         size_t export_table_offset;
  57.         size_t import_table_offset;
  58.         size_t base_relocation_table_offset;
  59.         size_t base_relocation_table_end_offset;
  60.         struct {
  61.                 uint16_t Machine;
  62.                 uint16_t NumberOfSections;
  63.                 uint32_t TimeDateStamp;
  64.                 uint32_t PointerToSymbolTable;
  65.                 uint32_t NumberOfSymbols;
  66.                 uint16_t SizeOfOptionalHeader;
  67.                 uint16_t Characteristics;
  68.         } coffFileHeader;
  69.         struct {
  70.                 // Standard fields
  71.                 uint16_t Magic;
  72.                 uint8_t MajorLinkerVersion;
  73.                 uint8_t MinorLinkerVersion;
  74.                 uint32_t SizeOfCode;
  75.                 uint32_t SizeOfInitializedData;
  76.                 uint32_t SizeOfUninitializedData;
  77.                 uint32_t AddressOfEntryPoint;
  78.                 uint32_t BaseOfCode;
  79.                 uint32_t BaseOfData; // PE32-only
  80.                 // Windows-specific fields
  81.                 uint64_t ImageBase;
  82.                 uint32_t SectionAlignment;
  83.                 uint32_t FileAlignment;
  84.                 uint16_t MajorOperatingSystemVersion;
  85.                 uint16_t MinorOperatingSystemVersion;
  86.                 uint16_t MajorImageVersion;
  87.                 uint16_t MinorImageVersion;
  88.                 uint16_t MajorSubsystemVersion;
  89.                 uint16_t MinorSubsystemVersion;
  90.                 uint32_t Win32VersionValue;
  91.                 uint32_t SizeOfImage;
  92.                 uint32_t SizeOfHeaders;
  93.                 uint32_t CheckSum;
  94.                 uint16_t Subsystem;
  95.                 uint16_t DllCharacteristics;
  96.                 uint64_t SizeOfStackReserve;
  97.                 uint64_t SizeOfStackCommit;
  98.                 uint64_t SizeOfHeapReserve;
  99.                 uint64_t SizeOfHeapCommit;
  100.                 uint32_t LoaderFlags;
  101.                 uint32_t NumberOfRvaAndSizes;
  102.         } optionalHeader;
  103.         struct {
  104.                 uint32_t ExportFlags;
  105.                 uint32_t TimeDateStamp;
  106.                 uint16_t MajorVersion;
  107.                 uint16_t MinorVersion;
  108.                 uint32_t NameRva;
  109.                 uint32_t OrdinalBase;
  110.                 uint32_t AddressTableEntries;
  111.                 uint32_t NumberOfNamePointers;
  112.                 uint32_t ExportAddressTableRva;
  113.                 uint32_t NamePointerRva;
  114.                 uint32_t OrdinalTableRva;
  115.         } export_directory;
  116. } Epep;
  117.  
  118. /// Constructor of the general information container
  119. int epep_init(Epep *epep, EPEP_READER reader);
  120.  
  121. /// Gives file offset corresponding to RVA is any, returns 0 othervice
  122. int epep_get_file_offset_by_rva(Epep *epep, size_t *offset, size_t addr);
  123.  
  124. //
  125. // Data Directories
  126. //
  127.  
  128. typedef struct {
  129.         uint32_t VirtualAddress;
  130.         uint32_t Size;
  131. } EpepImageDataDirectory;
  132.  
  133. /// Gives Data Directiry by its index
  134. int epep_get_data_directory_by_index(Epep *epep, EpepImageDataDirectory *idd, size_t index);
  135.  
  136. //
  137. // Sections
  138. //
  139.  
  140. typedef struct {
  141.         char Name[8];
  142.         uint32_t VirtualSize;
  143.         uint32_t VirtualAddress;
  144.         uint32_t SizeOfRawData;
  145.         uint32_t PointerToRawData;
  146.         uint32_t PointerToRelocations;
  147.         uint32_t PointerToLinenumbers;
  148.         uint16_t NumberOfRelocations;
  149.         uint16_t NumberOfLinenumbers;
  150.         uint32_t Characteristics;
  151. } EpepSectionHeader;
  152.  
  153. /// Gives Section Header by its index
  154. int epep_get_section_header_by_index(Epep *epep, EpepSectionHeader *sh, size_t index);
  155.  
  156. /// Gives section header by RVA
  157. int epep_get_section_header_by_rva(Epep *epep, EpepSectionHeader *sh, size_t addr);
  158.  
  159. /// Gives section contents by Section Header
  160. int epep_get_section_contents(Epep *epep, EpepSectionHeader *sh, void *buf);
  161.  
  162. //
  163. // COFF Symbols (object file symbols)
  164. //
  165.  
  166. typedef union {
  167.         struct {
  168.                 union {
  169.                         char ShortName[8];
  170.                         struct {
  171.                                 uint32_t Zeroes;
  172.                                 uint32_t Offset;
  173.                         };
  174.                 };
  175.                 uint32_t Value;
  176.                 uint16_t SectionNumber;
  177.                 uint16_t Type;
  178.                 uint8_t StorageClass;
  179.                 uint8_t NumberOfAuxSymbols;
  180.         } symbol;
  181.         struct {
  182.                 uint32_t TagIndex;
  183.                 uint32_t TotalSize;
  184.                 uint32_t PointerToLinenumber;
  185.                 uint32_t PointerToNextFunction;
  186.                 uint16_t Unused;
  187.         } auxFunctionDefinition;
  188.         struct {
  189.                 uint8_t Unused0[4];
  190.                 uint16_t Linenumber;
  191.                 uint8_t Unused1[6];
  192.                 uint32_t PointerToNextFunction;
  193.                 uint8_t Unused2[2];
  194.         } auxBfOrEfSymbol;
  195.         struct {
  196.                 uint32_t TagIndex;
  197.                 uint32_t Characteristics;
  198.                 uint8_t Unused[10];
  199.         } auxWeakExternal;
  200.         struct {
  201.                 char FileName[18];
  202.         } auxFile;
  203.         struct {
  204.                 uint32_t Length;
  205.                 uint16_t NumberOfRelocations;
  206.                 uint16_t NumberOfLinenumbers;
  207.                 uint32_t CheckSum;
  208.                 uint16_t Number;
  209.                 uint8_t  Selection;
  210.                 uint8_t Unused[3];
  211.         } auxSectionDefinition;
  212. } EpepCoffSymbol;
  213.  
  214. /// Gives COFF string table size
  215. int epep_get_string_table_size(Epep *epep, size_t *size);
  216.  
  217. /// Gives COFF string table
  218. int epep_get_string_table(Epep *epep, char *string_table);
  219.  
  220. /// Gives COFF Symbol by its index
  221. int epep_get_symbol_by_index(Epep *epep, EpepCoffSymbol *sym, size_t index);
  222.  
  223. //
  224. // Imports
  225. //
  226.  
  227. typedef struct {
  228.         uint32_t ImportLookupTableRva;
  229.         uint32_t TimeDateStamp;
  230.         uint32_t ForwarderChain;
  231.         uint32_t NameRva;
  232.         uint32_t ImportAddressTableRva;
  233. } EpepImportDirectory;
  234.  
  235. /// Returns non-zero if import table exists in the file
  236. int epep_has_import_table(Epep *epep);
  237.  
  238. /// Places offset of import table into epep structure
  239. int epep_read_import_table_offset(Epep *epep);
  240.  
  241. /// Gives Import Directory by index
  242. int epep_get_import_directory_by_index(Epep *epep, EpepImportDirectory *import_directory, size_t index);
  243.  
  244. /// Gives name of Import Directory (library)
  245. int epep_get_import_directory_name_s(Epep *epep, EpepImportDirectory *import_directory, char *name, size_t name_max);
  246.  
  247. /// Gives Import Lookup (imported symbol) by import directory and index
  248. int epep_get_import_directory_lookup_by_index(Epep *epep, EpepImportDirectory *import_directory, size_t *lookup, size_t index);
  249.  
  250. /// Gives name of Import Directory Lookup (imported symbol) or nothing if imported by ordinal
  251. int epep_get_lookup_name_s(Epep *epep, size_t lookup, char *name, size_t name_max);
  252.  
  253. //
  254. // Exports
  255. //
  256.  
  257. typedef union {
  258.         uint32_t ExportRva;
  259.         uint32_t ForwarderRva;
  260. } EpepExportAddress;
  261.  
  262. /// Returns non-zero if export table exists in the file
  263. int epep_has_export_table(Epep *epep);
  264.  
  265. /// Palces offset of export table into epep structrue
  266. int epep_read_export_table_offset(Epep *epep);
  267.  
  268. /// Palces export table into epep structrue
  269. //! Needs to be called before next export functions
  270. int epep_read_export_directory(Epep *epep);
  271.  
  272. /// Gives name of the DLL
  273. //! epep_read_export_directory needs to be called before
  274. int epep_get_dll_name_s(Epep *epep, char *name, size_t name_max);
  275.  
  276. /// Gives entry from Export Name Pointer Table by its index
  277. //! epep_read_export_directory needs to be called before
  278. int epep_get_export_name_pointer_by_index(Epep *epep, size_t *name_rva, size_t index);
  279.  
  280. /// Gives export name by its index in Export Address Table (receives name buffer length)
  281. //! epep_read_export_directory needs to be called before
  282. int epep_get_export_name_s_by_index(Epep *epep, char *name, size_t name_max, size_t index);
  283.  
  284. /// Gives export address by its index in Export Address Table
  285. //! epep_read_export_directory needs to be called before
  286. int epep_get_export_address_by_index(Epep *epep, EpepExportAddress *export_address, size_t index);
  287.  
  288. /// Gives forwarder string of Export Address
  289. //! epep_read_export_directory needs to be called before
  290. int epep_get_export_address_forwarder_s(Epep *epep, EpepExportAddress *export_address, char *forwarder, size_t forwarder_max);
  291.  
  292. /// Returns non-zero if the export address specifies forwarder string
  293. //! epep_read_export_directory needs to be called before
  294. int epep_export_address_is_forwarder(Epep *epep, EpepExportAddress *export_address);
  295.  
  296. //
  297. // DLL Base Relocations
  298. //
  299.  
  300. typedef struct {
  301.         size_t offset;
  302.         uint32_t PageRva;
  303.         uint32_t BlockSize;
  304.         uint16_t BaseRelocation[0];
  305. } EpepBaseRelocationBlock;
  306.  
  307. typedef union {
  308.         struct {
  309.                 uint16_t Offset: 12,
  310.                         Type: 4;
  311.         };
  312.         uint16_t u16;
  313. } EpepBaseRelocation;
  314.  
  315. /// Returns non-zero if the file contains Base Relocations
  316. int epep_has_base_relocation_table(Epep *epep);
  317.  
  318. /// Places offset to Base Relocation Table into epep structure
  319. int epep_read_base_relocation_table_offset(Epep *epep);
  320.  
  321. /// Gives first Base Relocation Block
  322. int epep_get_first_base_relocation_block(Epep *epep, EpepBaseRelocationBlock *brb);
  323.  
  324. /// Gives next Base Relocation Block (replaces contents of the given block)
  325. int epep_get_next_base_relocation_block(Epep *epep, EpepBaseRelocationBlock *it);
  326.  
  327. /// Gives Base Relocation by its index in Base Relocation Block
  328. int epep_get_base_relocation_block_base_relocation_by_index(Epep *epep, EpepBaseRelocationBlock *brb, EpepBaseRelocation *br, size_t index);
  329.  
  330. //
  331. // COFF Relocations
  332. //
  333.  
  334. typedef struct {
  335.         uint32_t VirtualAddress;
  336.         uint32_t SymbolTableIndex;
  337.         uint16_t Type;
  338. } EpepCoffRelocation;
  339.  
  340. int epep_get_section_relocation_by_index(Epep *epep, EpepSectionHeader *sh, EpepCoffRelocation *rel, size_t index);
  341.  
  342. //
  343. // COFF Line Numbers
  344. //
  345.  
  346. typedef struct {
  347.         union {
  348.                 uint32_t SymbolTableIndex;
  349.                 uint32_t VirtualAddress;
  350.         } Type;
  351.         uint16_t Linenumber;
  352. } EpepCoffLinenumber;
  353.  
  354. int epep_get_section_line_number_by_index(Epep *epep, EpepSectionHeader *sh, EpepCoffLinenumber *ln, size_t index);
  355.  
  356. #ifdef EPEP_INST
  357.  
  358. //
  359. // Private functions
  360. //
  361.  
  362. static int epep_seek(Epep *epep, size_t offset) {
  363.         EPEP_READER_SEEK(&epep->reader, offset);
  364.         return 1;
  365. }
  366.  
  367. static int epep_read_block(Epep *epep, size_t size, void *block) {
  368.         EPEP_READER_GET_BLOCK(&epep->reader, size, block);
  369.         return 1;
  370. }
  371.  
  372. static int is_pe32(Epep *epep) {
  373.         return epep->optionalHeader.Magic == 0x10b;
  374. }
  375.  
  376. static int is_pe32p(Epep *epep) {
  377.         return epep->optionalHeader.Magic == 0x20b;
  378. }
  379.  
  380. static uint8_t epep_read_u8(Epep *epep) {
  381.         return EPEP_READER_GET(&epep->reader);
  382. }
  383.  
  384. static uint16_t epep_read_u16(Epep *epep) {
  385.         unsigned l = epep_read_u8(epep);
  386.         unsigned h = epep_read_u8(epep);
  387.         return l | (h << 8);
  388. }
  389.  
  390. static uint32_t epep_read_u32(Epep *epep) {
  391.         unsigned b0 = epep_read_u8(epep);
  392.         unsigned b1 = epep_read_u8(epep);
  393.         unsigned b2 = epep_read_u8(epep);
  394.         unsigned b3 = epep_read_u8(epep);
  395.         return b0 | (b1 << 8) | (b2 << 16) | (b3 << 24);
  396. }
  397.  
  398. static uint64_t epep_read_u64(Epep *epep) {
  399.         uint64_t res = 0;
  400.         for (unsigned i = 0; i < 64; i += 8) {
  401.                 res |= epep_read_u8(epep) << i;
  402.         }
  403.         return res;
  404. }
  405.  
  406. static uint64_t epep_read_ptr(Epep *epep) {
  407.         return is_pe32(epep) ? epep_read_u32(epep) : epep_read_u64(epep);
  408. }
  409.  
  410. //
  411. // Generic
  412. //
  413.  
  414. int epep_init(Epep *epep, EPEP_READER reader) {
  415.         *epep = (Epep){ 0 };
  416.         epep->kind = EPEP_IMAGE;
  417.         epep->reader = reader;
  418.         epep->error_code = EPEP_ERR_SUCCESS;
  419.         epep->signature_offset_offset = 0x3c;
  420.         epep_seek(epep, epep->signature_offset_offset);
  421.         epep->signature_offset = 0;
  422.         epep->signature_offset |= epep_read_u8(epep);
  423.         epep->signature_offset |= epep_read_u8(epep) << 8;
  424.         epep->signature_offset |= epep_read_u8(epep) << 16;
  425.         epep->signature_offset |= epep_read_u8(epep) << 24;
  426.         epep_seek(epep, epep->signature_offset);
  427.         char signature_buf[4];
  428.         signature_buf[0] = epep_read_u8(epep);
  429.         signature_buf[1] = epep_read_u8(epep);
  430.         signature_buf[2] = epep_read_u8(epep);
  431.         signature_buf[3] = epep_read_u8(epep);
  432.         if (signature_buf[0] != 'P' || signature_buf[1] != 'E' ||
  433.                 signature_buf[2] != '\0' || signature_buf[3] != '\0') {
  434.                 epep->kind = EPEP_OBJECT;
  435.                 epep_seek(epep, 0);
  436.         }
  437.         epep->coffFileHeader.Machine = epep_read_u16(epep);
  438.         epep->coffFileHeader.NumberOfSections = epep_read_u16(epep);
  439.         epep->coffFileHeader.TimeDateStamp = epep_read_u32(epep);
  440.         epep->coffFileHeader.PointerToSymbolTable = epep_read_u32(epep);
  441.         epep->coffFileHeader.NumberOfSymbols = epep_read_u32(epep);
  442.         epep->coffFileHeader.SizeOfOptionalHeader = epep_read_u16(epep);
  443.         epep->coffFileHeader.Characteristics = epep_read_u16(epep);
  444.         if (epep->coffFileHeader.SizeOfOptionalHeader != 0) {
  445.                 // Standard fields
  446.                 epep->optionalHeader.Magic = epep_read_u16(epep);
  447.                 epep->optionalHeader.MajorLinkerVersion = epep_read_u8(epep);
  448.                 epep->optionalHeader.MinorLinkerVersion = epep_read_u8(epep);
  449.                 epep->optionalHeader.SizeOfCode = epep_read_u32(epep);
  450.                 epep->optionalHeader.SizeOfInitializedData = epep_read_u32(epep);
  451.                 epep->optionalHeader.SizeOfUninitializedData = epep_read_u32(epep);
  452.                 epep->optionalHeader.AddressOfEntryPoint = epep_read_u32(epep);
  453.                 epep->optionalHeader.BaseOfCode = epep_read_u32(epep);
  454.                 if (is_pe32(epep)) {
  455.                         epep->optionalHeader.BaseOfData = epep_read_u32(epep);
  456.                 }
  457.                 // Windows-specific fields
  458.                 epep->optionalHeader.ImageBase = epep_read_ptr(epep);
  459.                 epep->optionalHeader.SectionAlignment = epep_read_u32(epep);
  460.                 epep->optionalHeader.FileAlignment = epep_read_u32(epep);
  461.                 epep->optionalHeader.MajorOperatingSystemVersion = epep_read_u16(epep);
  462.                 epep->optionalHeader.MinorOperatingSystemVersion = epep_read_u16(epep);
  463.                 epep->optionalHeader.MajorImageVersion = epep_read_u16(epep);
  464.                 epep->optionalHeader.MinorImageVersion = epep_read_u16(epep);
  465.                 epep->optionalHeader.MajorSubsystemVersion = epep_read_u16(epep);
  466.                 epep->optionalHeader.Win32VersionValue = epep_read_u32(epep);
  467.                 epep->optionalHeader.MinorSubsystemVersion = epep_read_u16(epep);
  468.                 epep->optionalHeader.SizeOfImage = epep_read_u32(epep);
  469.                 epep->optionalHeader.SizeOfHeaders = epep_read_u32(epep);
  470.                 epep->optionalHeader.CheckSum = epep_read_u32(epep);
  471.                 epep->optionalHeader.Subsystem = epep_read_u16(epep);
  472.                 epep->optionalHeader.DllCharacteristics = epep_read_u16(epep);
  473.                 epep->optionalHeader.SizeOfStackReserve = epep_read_ptr(epep);
  474.                 epep->optionalHeader.SizeOfStackCommit = epep_read_ptr(epep);
  475.                 epep->optionalHeader.SizeOfHeapReserve = epep_read_ptr(epep);
  476.                 epep->optionalHeader.SizeOfHeapCommit = epep_read_ptr(epep);
  477.                 epep->optionalHeader.LoaderFlags = epep_read_u32(epep);
  478.                 epep->optionalHeader.NumberOfRvaAndSizes = epep_read_u32(epep);
  479.                 epep->first_data_directory_offset = EPEP_READER_TELL(&epep->reader);
  480.         }
  481.         epep->first_section_header_offset = EPEP_READER_TELL(&epep->reader);
  482.         if (epep->coffFileHeader.SizeOfOptionalHeader != 0) {
  483.                 epep->first_section_header_offset += epep->optionalHeader.NumberOfRvaAndSizes * sizeof(EpepImageDataDirectory);
  484.         }
  485.         return 1;
  486. }
  487.  
  488. int epep_get_file_offset_by_rva(Epep *epep, size_t *offset, size_t addr) {
  489.         EpepSectionHeader sh = { 0 };
  490.         if (!epep_get_section_header_by_rva(epep, &sh, addr)) {
  491.                 return 0;
  492.         }
  493.         size_t diff = addr - sh.VirtualAddress;
  494.         if (diff >= sh.SizeOfRawData) {
  495.                 epep->error_code = EPEP_ERR_ADDRESS_IS_OUT_OF_SECTION_RAW_DATA;
  496.                 return 0;
  497.         }
  498.         *offset = sh.PointerToRawData + diff;
  499.         return 1;
  500. }
  501.  
  502. //
  503. // Data Directories
  504. //
  505.  
  506. int epep_get_data_directory_by_index(Epep *epep, EpepImageDataDirectory *idd, size_t index) {
  507.         if (index >= epep->optionalHeader.NumberOfRvaAndSizes) {
  508.                 epep->error_code = EPEP_ERR_DATA_DIRECTORY_INDEX_IS_INVALID;
  509.                 return 0;
  510.         }
  511.         epep_seek(epep, epep->first_data_directory_offset + sizeof(EpepImageDataDirectory) * index);
  512.         idd->VirtualAddress = epep_read_u32(epep);
  513.         idd->Size = epep_read_u32(epep);
  514.         return 1;
  515. }
  516.  
  517. //
  518. // Sections
  519. //
  520.  
  521. int epep_get_section_header_by_index(Epep *epep, EpepSectionHeader *sh, size_t index) {
  522.         if (index >= epep->coffFileHeader.NumberOfSections) {
  523.                 epep->error_code = EPEP_ERR_SECTION_HEADER_INDEX_IS_INVALID;
  524.                 return 0;
  525.         }
  526.         epep_seek(epep, epep->first_section_header_offset + sizeof(EpepSectionHeader) * index);
  527.         for (int i = 0; i < 8; i++) {
  528.                 sh->Name[i] = epep_read_u8(epep);
  529.         }
  530.         sh->VirtualSize = epep_read_u32(epep);
  531.         sh->VirtualAddress = epep_read_u32(epep);
  532.         sh->SizeOfRawData = epep_read_u32(epep);
  533.         sh->PointerToRawData = epep_read_u32(epep);
  534.         sh->PointerToRelocations = epep_read_u32(epep);
  535.         sh->PointerToLinenumbers = epep_read_u32(epep);
  536.         sh->NumberOfRelocations = epep_read_u16(epep);
  537.         sh->NumberOfLinenumbers = epep_read_u16(epep);
  538.         sh->Characteristics = epep_read_u32(epep);
  539.         return 1;
  540. }
  541.  
  542. int epep_get_section_header_by_rva(Epep *epep, EpepSectionHeader *sh, size_t addr) {
  543.         EpepSectionHeader sh0 = { 0 };
  544.         for (size_t i = 0; i < epep->coffFileHeader.NumberOfSections; i++) {
  545.                 epep_get_section_header_by_index(epep, &sh0, i);
  546.                 if (addr >= sh0.VirtualAddress && addr < (sh0.VirtualAddress + sh0.VirtualSize)) {
  547.                         *sh = sh0;
  548.                         return 1;
  549.                 }
  550.         }
  551.         epep->error_code = EPEP_ERR_ADDRESS_IS_OUT_OF_ANY_SECTION;
  552.         return 0;
  553. }
  554.  
  555. int epep_get_section_contents(Epep *epep, EpepSectionHeader *sh, void *buf) {
  556.         size_t size_of_raw_data = sh->SizeOfRawData;
  557.         epep_seek(epep, sh->PointerToRawData);
  558.         epep_read_block(epep, size_of_raw_data, buf);
  559.         return 1;
  560. }
  561.  
  562. //
  563. // COFF Symbols
  564. //
  565.  
  566. int epep_get_string_table_size(Epep *epep, size_t *size) {
  567.         epep_seek(epep, epep->coffFileHeader.PointerToSymbolTable + 18 * epep->coffFileHeader.NumberOfSymbols);
  568.         *size = epep_read_u32(epep);
  569.         return 1;
  570. }
  571.  
  572. int epep_get_string_table(Epep *epep, char *string_table) {
  573.         size_t size = 0;
  574.         if (!epep_get_string_table_size(epep, &size)) {
  575.                 return 0;
  576.         }
  577.         // A COFF strings table starts with its size
  578.         *string_table++ = (size & 0x000000ff) >> 0;
  579.         *string_table++ = (size & 0x0000ff00) >> 8;
  580.         *string_table++ = (size & 0x00ff0000) >> 16;
  581.         *string_table++ = (size & 0xff000000) >> 24;
  582.         epep_read_block(epep, size - 4, string_table);
  583.         return 1;
  584. }
  585.  
  586. int epep_get_symbol_by_index(Epep *epep, EpepCoffSymbol *sym, size_t index) {
  587.         if (epep->kind != EPEP_OBJECT) {
  588.                 epep->error_code = EPEP_ERR_NOT_AN_OBJECT;
  589.                 return 0;
  590.         }
  591.         if (index >= epep->coffFileHeader.NumberOfSymbols) {
  592.                 epep->error_code = EPEP_ERR_SYMBOL_INDEX_IS_INVALID;
  593.                 return 0;
  594.         }
  595.         epep_seek(epep, epep->coffFileHeader.PointerToSymbolTable + 18 * index);
  596.         for (size_t i = 0; i < 18; i++) {
  597.                 sym->auxFile.FileName[i] = epep_read_u8(epep);
  598.         }
  599.         return 1;
  600. }
  601.  
  602. //
  603. // Imports
  604. //
  605.  
  606. int epep_has_import_table(Epep *epep) {
  607.         if (epep->kind != EPEP_IMAGE) {
  608.                 return 0;
  609.         }
  610.         EpepImageDataDirectory idd = { 0 };
  611.         if (!epep_get_data_directory_by_index(epep, &idd, 1)) {
  612.                 return 0;
  613.         }
  614.         return idd.VirtualAddress;
  615. }
  616.  
  617. int epep_read_import_table_offset(Epep *epep) {
  618.         EpepImageDataDirectory import_table_dd = { 0 };
  619.         if (!epep_get_data_directory_by_index(epep, &import_table_dd, 1)) {
  620.                 return 0;
  621.         }
  622.         if (!epep_get_file_offset_by_rva(epep, &epep->import_table_offset, import_table_dd.VirtualAddress)) {
  623.                 return 0;
  624.         }
  625.         return 1;
  626. }
  627.  
  628. int epep_get_import_directory_by_index(Epep *epep, EpepImportDirectory *import_directory, size_t index) {
  629.         if (epep->import_table_offset == 0) {
  630.                 if (!epep_read_import_table_offset(epep)) {
  631.                         return 0;
  632.                 }
  633.         }
  634.         epep_seek(epep, epep->import_table_offset + index * sizeof(*import_directory));
  635.         epep_read_block(epep, sizeof(*import_directory), import_directory);
  636.         return 1;
  637. }
  638.  
  639. int epep_get_import_directory_name_s(Epep *epep, EpepImportDirectory *import_directory, char *name, size_t name_max) {
  640.         size_t name_rva = import_directory->NameRva;
  641.         size_t name_offset = 0;
  642.         if (!epep_get_file_offset_by_rva(epep, &name_offset, name_rva)) {
  643.                 return 0;
  644.         }
  645.         epep_seek(epep, name_offset);
  646.         epep_read_block(epep, name_max, name);
  647.         return 1;
  648. }
  649.  
  650. int epep_get_import_directory_lookup_by_index(Epep *epep, EpepImportDirectory *import_directory, size_t *lookup, size_t index) {
  651.         size_t first_lookup_offset = 0;
  652.         if (!epep_get_file_offset_by_rva(epep, &first_lookup_offset, import_directory->ImportLookupTableRva)) {
  653.                 return 0;
  654.         }
  655.         size_t size_of_lookup = is_pe32(epep) ? 4 : 8;
  656.         size_t lookup_offset = first_lookup_offset + size_of_lookup * index;
  657.         epep_seek(epep, lookup_offset);
  658.         epep_read_block(epep, size_of_lookup, lookup);
  659.         return 1;
  660. }
  661.  
  662. int epep_get_lookup_name_s(Epep *epep, size_t lookup, char *name, size_t name_max) {
  663.         if (name_max == 0) {
  664.                 epep->error_code = EPEP_ERR_OUTPUT_CAPACITY_IS_ZERO;
  665.                 return 0;
  666.         }
  667.         if (name == NULL) {
  668.                 epep->error_code = EPEP_ERR_OUTPUT_IS_NULL;
  669.                 return 0;
  670.         }
  671.         uint64_t mask = is_pe32(epep) ? 0x80000000 : 0x8000000000000000;
  672.         if (lookup & mask) {
  673.                 name[0] = '\0';
  674.                 return 1;
  675.         }
  676.         size_t name_rva = lookup;
  677.         size_t name_offset = 0;
  678.         if (!epep_get_file_offset_by_rva(epep, &name_offset, name_rva)) {
  679.                 return 0;
  680.         }
  681.         // skip 2 bytes (Name Table :: Hint)
  682.         name_offset += 2;
  683.         epep_seek(epep, name_offset);
  684.         epep_read_block(epep, name_max, name);
  685.         return 1;
  686. }
  687.  
  688. //
  689. // Exports
  690. //
  691.  
  692. int epep_has_export_table(Epep *epep) {
  693.         if (epep->kind != EPEP_IMAGE) {
  694.                 return 0;
  695.         }
  696.         EpepImageDataDirectory idd = { 0 };
  697.         if (!epep_get_data_directory_by_index(epep, &idd, 0)) {
  698.                 return 0;
  699.         }
  700.         return idd.VirtualAddress;
  701. }
  702.  
  703. int epep_read_export_table_offset(Epep *epep) {
  704.         EpepImageDataDirectory export_table_dd = { 0 };
  705.         if (!epep_get_data_directory_by_index(epep, &export_table_dd, 0)) {
  706.                 return 0;
  707.         }
  708.         if (!epep_get_file_offset_by_rva(epep, &epep->export_table_offset, export_table_dd.VirtualAddress)) {
  709.                 return 0;
  710.         }
  711.         return 1;
  712. }
  713.  
  714. int epep_read_export_directory(Epep *epep) {
  715.         if (epep->export_table_offset == 0) {
  716.                 if (!epep_read_export_table_offset(epep)) {
  717.                         return 0;
  718.                 }
  719.         }
  720.         epep_seek(epep, epep->export_table_offset);
  721.         epep_read_block(epep, sizeof(epep->export_directory), &epep->export_directory);
  722.         return 1;
  723. }
  724.  
  725. int epep_get_dll_name_s(Epep *epep, char *name, size_t name_max) {
  726.         size_t offset = 0;
  727.         if (!epep_get_file_offset_by_rva(epep, &offset, epep->export_directory.NameRva)) {
  728.                 return 0;
  729.         }
  730.         epep_seek(epep, offset);
  731.         epep_read_block(epep, name_max, name);
  732.         return 1;
  733. }
  734.  
  735. int epep_get_export_name_pointer_by_index(Epep *epep, size_t *name_rva, size_t index) {
  736.         size_t name_pointer_table_rva = epep->export_directory.NamePointerRva;
  737.         size_t name_pointer_table_offset = 0;
  738.         if (!epep_get_file_offset_by_rva(epep, &name_pointer_table_offset, name_pointer_table_rva)) {
  739.                 return 0;
  740.         }
  741.         epep_seek(epep, name_pointer_table_offset + sizeof(uint32_t) * index);
  742.         *name_rva = epep_read_u32(epep);       
  743.         return 1;
  744. }
  745.  
  746. int epep_get_export_name_s_by_index(Epep *epep, char *name, size_t name_max, size_t index) {
  747.         size_t ordinal_table_offset = 0;
  748.         if (!epep_get_file_offset_by_rva(epep, &ordinal_table_offset, epep->export_directory.OrdinalTableRva)) {
  749.                 return 0;
  750.         }
  751.         epep_seek(epep, ordinal_table_offset);
  752.         for (size_t i = 0; i < epep->export_directory.NumberOfNamePointers; i++) {
  753.                 uint16_t ordinal = epep_read_u16(epep);
  754.                 if (ordinal == index) { // SPEC_VIOL: Why should not epep->export_directory.OrdinalBase be substracted?
  755.                         size_t name_rva = 0;
  756.                         if (!epep_get_export_name_pointer_by_index(epep, &name_rva, i)) {
  757.                                 return 0;
  758.                         }
  759.                         size_t name_offset = 0;
  760.                         if (!epep_get_file_offset_by_rva(epep, &name_offset, name_rva)) {
  761.                                 return 0;
  762.                         }
  763.                         epep_seek(epep, name_offset);
  764.                         epep_read_block(epep, name_max, name);
  765.                         return 1;
  766.                 }
  767.         }
  768.         epep->error_code = EPEP_ERR_EXPORT_ADDRESS_TABLE_ENTRY_NAME_NOT_FOUND;
  769.         return 0;
  770. }
  771.  
  772. int epep_get_export_address_by_index(Epep *epep, EpepExportAddress *export_address, size_t index) {
  773.         size_t export_address_table_offset = 0;
  774.         if (!epep_get_file_offset_by_rva(epep, &export_address_table_offset, epep->export_directory.ExportAddressTableRva)) {
  775.                 return 0;
  776.         }
  777.         EPEP_ASSERT(sizeof(EpepExportAddress) == sizeof(uint32_t));
  778.         epep_seek(epep, export_address_table_offset + sizeof(EpepExportAddress) * index);
  779.         epep_read_block(epep, sizeof(*export_address), export_address);
  780.         return 1;
  781. }
  782.  
  783. int epep_get_export_address_forwarder_s(Epep *epep, EpepExportAddress *export_address, char *forwarder, size_t forwarder_max) {
  784.         size_t forwarder_offset = 0;
  785.         if (!epep_get_file_offset_by_rva(epep, &forwarder_offset, export_address->ForwarderRva)) {
  786.                 return 0;
  787.         }
  788.         epep_seek(epep, forwarder_offset);
  789.         epep_read_block(epep, forwarder_max, forwarder);
  790.         return 1;
  791. }
  792.  
  793. int epep_export_address_is_forwarder(Epep *epep, EpepExportAddress *export_address) {
  794.         EpepImageDataDirectory edd = { 0 };
  795.         if (!epep_get_data_directory_by_index(epep, &edd, 0)) {
  796.                 return 0;
  797.         }
  798.         if (export_address->ForwarderRva >= edd.VirtualAddress && export_address->ForwarderRva < edd.VirtualAddress + edd.Size) {
  799.                 return 1;
  800.         }
  801.         return 0;
  802. }
  803.  
  804. //
  805. // DLL Base Relocaions
  806. //
  807.  
  808. int epep_has_base_relocation_table(Epep *epep) {
  809.         EpepImageDataDirectory brtdd = { 0 };
  810.         if (!epep_get_data_directory_by_index(epep, &brtdd, 5)) {
  811.                 return 0;
  812.         }
  813.         if (brtdd.VirtualAddress == 0) {
  814.                 return 0;
  815.         }
  816.         return 1;
  817. }
  818.  
  819. int epep_read_base_relocation_table_offset(Epep *epep) {
  820.         EpepImageDataDirectory brtdd = { 0 };
  821.         if (!epep_get_data_directory_by_index(epep, &brtdd, 5)) {
  822.                 return 0;
  823.         }
  824.         if (!epep_get_file_offset_by_rva(epep, &epep->base_relocation_table_offset, brtdd.VirtualAddress)) {
  825.                 return 0;
  826.         }
  827.         epep->base_relocation_table_end_offset = epep->base_relocation_table_offset + brtdd.Size;
  828.         return 1;
  829. }
  830.  
  831. int epep_get_first_base_relocation_block(Epep *epep, EpepBaseRelocationBlock *brb) {
  832.         if (epep->base_relocation_table_offset == 0) {
  833.                 if (!epep_read_base_relocation_table_offset(epep)) {
  834.                         return 0;
  835.                 }
  836.         }
  837.         if (epep->base_relocation_table_offset == 0) {
  838.                 epep->error_code = EPEP_ERR_NO_BASE_RELOCATION_TABLE;
  839.                 return 0;
  840.         }
  841.         if (!epep_seek(epep, epep->base_relocation_table_offset)) {
  842.                 return 0;
  843.         }
  844.         brb->offset = epep->base_relocation_table_offset;
  845.         brb->PageRva = epep_read_u32(epep);
  846.         brb->BlockSize = epep_read_u32(epep);
  847.         return 1;
  848. }
  849.  
  850. int epep_get_next_base_relocation_block(Epep *epep, EpepBaseRelocationBlock *it) {
  851.         if (it->offset == 0) {
  852.                 epep->error_code = EPEP_ERR_BASE_RELOCATION_IS_ALREADY_END;
  853.                 return 0;
  854.         }
  855.         it->offset = it->offset + it->BlockSize;
  856.         if (it->offset >= epep->base_relocation_table_end_offset) {
  857.                 *it = (EpepBaseRelocationBlock){ 0 };
  858.                 return 1;
  859.         }
  860.         if (!epep_seek(epep, it->offset)) {
  861.                 return 0;
  862.         }
  863.         it->PageRva = epep_read_u32(epep);
  864.         it->BlockSize = epep_read_u32(epep);
  865.         return 1;
  866. }
  867.  
  868. int epep_get_base_relocation_block_base_relocation_by_index(Epep *epep, EpepBaseRelocationBlock *brb, EpepBaseRelocation *br, size_t index) {
  869.         if (!epep_seek(epep, brb->offset + 8 + sizeof(EpepBaseRelocation) * index)) {
  870.                 return 0;
  871.         }
  872.         br->u16 = epep_read_u16(epep);
  873.         return 1;
  874. }
  875.  
  876. //
  877. // COFF Relocations
  878. //
  879.  
  880. int epep_get_section_relocation_by_index(Epep *epep, EpepSectionHeader *sh, EpepCoffRelocation *rel, size_t index) {
  881.         size_t relocationsOffset = sh->PointerToRelocations;
  882.         epep_seek(epep, relocationsOffset + 10 * index);
  883.         epep_read_block(epep, 10, rel);
  884.         return 1;
  885. }
  886.  
  887. //
  888. // COFF Line Numbers
  889. //
  890.  
  891. int epep_get_section_line_number_by_index(Epep *epep, EpepSectionHeader *sh, EpepCoffLinenumber *ln, size_t index) {
  892.         size_t LinenumbersOffset = sh->PointerToLinenumbers;
  893.         epep_seek(epep, LinenumbersOffset + 6 * index);
  894.         epep_read_block(epep, 6, ln);
  895.         return 1;
  896. }
  897.  
  898. #endif // EPEP_INST
  899.