Subversion Repositories Kolibri OS

Rev

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