pe_image.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. // Copyright (c) 2010 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. // This file was adapted from GreenBorder's Code.
  5. // To understand what this class is about (for other than well known functions
  6. // as GetProcAddress), a good starting point is "An In-Depth Look into the
  7. // Win32 Portable Executable File Format" by Matt Pietrek:
  8. // http://msdn.microsoft.com/msdnmag/issues/02/02/PE/default.aspx
  9. #ifndef BASE_WIN_PE_IMAGE_H_
  10. #define BASE_WIN_PE_IMAGE_H_
  11. #include <windows.h>
  12. #include <stdint.h>
  13. #if defined(_WIN32_WINNT_WIN8)
  14. // The Windows 8 SDK defines FACILITY_VISUALCPP in winerror.h.
  15. #undef FACILITY_VISUALCPP
  16. #endif
  17. #include <DelayIMP.h>
  18. namespace base {
  19. namespace win {
  20. // This class is a wrapper for the Portable Executable File Format (PE).
  21. // Its main purpose is to provide an easy way to work with imports and exports
  22. // from a file, mapped in memory as image.
  23. class PEImage {
  24. public:
  25. // Callback to enumerate sections.
  26. // cookie is the value passed to the enumerate method.
  27. // Returns true to continue the enumeration.
  28. using EnumSectionsFunction =
  29. bool (*)(const PEImage&, PIMAGE_SECTION_HEADER, PVOID, DWORD, PVOID);
  30. // Callback to enumerate exports.
  31. // function is the actual address of the symbol. If forward is not null, it
  32. // contains the dll and symbol to forward this export to. cookie is the value
  33. // passed to the enumerate method.
  34. // Returns true to continue the enumeration.
  35. using EnumExportsFunction =
  36. bool (*)(const PEImage&, DWORD, DWORD, LPCSTR, PVOID, LPCSTR, PVOID);
  37. // Callback to enumerate import blocks.
  38. // name_table and iat point to the imports name table and address table for
  39. // this block. cookie is the value passed to the enumerate method.
  40. // Returns true to continue the enumeration.
  41. using EnumImportChunksFunction = bool (*)(const PEImage&,
  42. LPCSTR,
  43. PIMAGE_THUNK_DATA,
  44. PIMAGE_THUNK_DATA,
  45. PVOID);
  46. // Callback to enumerate imports.
  47. // module is the dll that exports this symbol. cookie is the value passed to
  48. // the enumerate method.
  49. // Returns true to continue the enumeration.
  50. using EnumImportsFunction = bool (*)(const PEImage&,
  51. LPCSTR,
  52. DWORD,
  53. LPCSTR,
  54. DWORD,
  55. PIMAGE_THUNK_DATA,
  56. PVOID);
  57. // Callback to enumerate delayed import blocks.
  58. // module is the dll that exports this block of symbols. cookie is the value
  59. // passed to the enumerate method.
  60. // Returns true to continue the enumeration.
  61. using EnumDelayImportChunksFunction = bool (*)(const PEImage&,
  62. PImgDelayDescr,
  63. LPCSTR,
  64. PIMAGE_THUNK_DATA,
  65. PIMAGE_THUNK_DATA,
  66. PVOID);
  67. // Callback to enumerate relocations.
  68. // cookie is the value passed to the enumerate method.
  69. // Returns true to continue the enumeration.
  70. using EnumRelocsFunction = bool (*)(const PEImage&, WORD, PVOID, PVOID);
  71. explicit PEImage(HMODULE module) : module_(module) {}
  72. explicit PEImage(const void* module) {
  73. module_ = reinterpret_cast<HMODULE>(const_cast<void*>(module));
  74. }
  75. virtual ~PEImage() = default;
  76. // Gets the HMODULE for this object.
  77. HMODULE module() const;
  78. // Sets this object's HMODULE.
  79. void set_module(HMODULE module);
  80. // Checks if this symbol is actually an ordinal.
  81. static bool IsOrdinal(LPCSTR name);
  82. // Converts a named symbol to the corresponding ordinal.
  83. static WORD ToOrdinal(LPCSTR name);
  84. // Returns the DOS_HEADER for this PE.
  85. PIMAGE_DOS_HEADER GetDosHeader() const;
  86. // Returns the NT_HEADER for this PE.
  87. PIMAGE_NT_HEADERS GetNTHeaders() const;
  88. // Returns number of sections of this PE.
  89. WORD GetNumSections() const;
  90. // Returns the header for a given section.
  91. // returns NULL if there is no such section.
  92. PIMAGE_SECTION_HEADER GetSectionHeader(UINT section) const;
  93. // Returns the size of a given directory entry or 0 if |directory| is out of
  94. // bounds.
  95. DWORD GetImageDirectoryEntrySize(UINT directory) const;
  96. // Returns the address of a given directory entry or NULL if |directory| is
  97. // out of bounds.
  98. PVOID GetImageDirectoryEntryAddr(UINT directory) const;
  99. // Returns the section header for a given address.
  100. // Use: s = image.GetImageSectionFromAddr(a);
  101. // Post: 's' is the section header of the section that contains 'a'
  102. // or NULL if there is no such section.
  103. PIMAGE_SECTION_HEADER GetImageSectionFromAddr(PVOID address) const;
  104. // Returns the section header for a given section.
  105. PIMAGE_SECTION_HEADER GetImageSectionHeaderByName(LPCSTR section_name) const;
  106. // Returns the first block of imports.
  107. PIMAGE_IMPORT_DESCRIPTOR GetFirstImportChunk() const;
  108. // Returns the exports directory.
  109. PIMAGE_EXPORT_DIRECTORY GetExportDirectory() const;
  110. // Retrieves the contents of the image's CodeView debug entry, returning true
  111. // if such an entry is found and is within a section mapped into the current
  112. // process's memory. |guid|, |age|, and |pdb_filename| are each optional and
  113. // may be NULL. |pdb_filename_length| is mandatory if |pdb_filename| is not
  114. // NULL, as the latter is populated with a direct reference to a string in the
  115. // image that is is not guaranteed to be terminated (note: informal
  116. // documentation indicates that it should be terminated, but the data is
  117. // untrusted). Furthermore, owing to its nature of being a string in the
  118. // image, it is only valid while the image is mapped into the process, and the
  119. // caller is not responsible for freeing it. |pdb_filename_length| is
  120. // populated with the string length of |pdb_filename| (not including a
  121. // terminator) and must be used rather than relying on |pdb_filename| being
  122. // properly terminated.
  123. bool GetDebugId(LPGUID guid,
  124. LPDWORD age,
  125. LPCSTR* pdb_filename,
  126. size_t* pdb_filename_length) const;
  127. // Returns a given export entry.
  128. // Use: e = image.GetExportEntry(f);
  129. // Pre: 'f' is either a zero terminated string or ordinal
  130. // Post: 'e' is a pointer to the export directory entry
  131. // that contains 'f's export RVA, or NULL if 'f'
  132. // is not exported from this image
  133. PDWORD GetExportEntry(LPCSTR name) const;
  134. // Returns the address for a given exported symbol.
  135. // Use: p = image.GetProcAddress(f);
  136. // Pre: 'f' is either a zero terminated string or ordinal.
  137. // Post: if 'f' is a non-forwarded export from image, 'p' is
  138. // the exported function. If 'f' is a forwarded export
  139. // then p is the special value -1. In this case
  140. // RVAToAddr(*GetExportEntry) can be used to resolve
  141. // the string that describes the forward.
  142. FARPROC GetProcAddress(LPCSTR function_name) const;
  143. // Retrieves the ordinal for a given exported symbol.
  144. // Returns true if the symbol was found.
  145. bool GetProcOrdinal(LPCSTR function_name, WORD* ordinal) const;
  146. // Enumerates PE sections.
  147. // cookie is a generic cookie to pass to the callback.
  148. // Returns true on success.
  149. bool EnumSections(EnumSectionsFunction callback, PVOID cookie) const;
  150. // Enumerates PE exports.
  151. // cookie is a generic cookie to pass to the callback.
  152. // Returns true on success.
  153. bool EnumExports(EnumExportsFunction callback, PVOID cookie) const;
  154. // Enumerates PE imports.
  155. // cookie is a generic cookie to pass to the callback.
  156. // Returns true on success.
  157. // Use |target_module_name| to ensure the callback is only invoked for the
  158. // specified module.
  159. bool EnumAllImports(EnumImportsFunction callback,
  160. PVOID cookie,
  161. LPCSTR target_module_name) const;
  162. // Enumerates PE import blocks.
  163. // cookie is a generic cookie to pass to the callback.
  164. // Returns true on success.
  165. // Use |target_module_name| to ensure the callback is only invoked for the
  166. // specified module.
  167. bool EnumImportChunks(EnumImportChunksFunction callback,
  168. PVOID cookie,
  169. LPCSTR target_module_name) const;
  170. // Enumerates the imports from a single PE import block.
  171. // cookie is a generic cookie to pass to the callback.
  172. // Returns true on success.
  173. bool EnumOneImportChunk(EnumImportsFunction callback,
  174. LPCSTR module_name,
  175. PIMAGE_THUNK_DATA name_table,
  176. PIMAGE_THUNK_DATA iat,
  177. PVOID cookie) const;
  178. // Enumerates PE delay imports.
  179. // cookie is a generic cookie to pass to the callback.
  180. // Returns true on success.
  181. // Use |target_module_name| to ensure the callback is only invoked for the
  182. // specified module. If this parameter is non-null then all delayloaded
  183. // imports are resolved when the target module is found.
  184. bool EnumAllDelayImports(EnumImportsFunction callback,
  185. PVOID cookie,
  186. LPCSTR target_module_name) const;
  187. // Enumerates PE delay import blocks.
  188. // cookie is a generic cookie to pass to the callback.
  189. // Returns true on success.
  190. // Use |target_module_name| to ensure the callback is only invoked for the
  191. // specified module. If this parameter is non-null then all delayloaded
  192. // imports are resolved when the target module is found.
  193. bool EnumDelayImportChunks(EnumDelayImportChunksFunction callback,
  194. PVOID cookie,
  195. LPCSTR target_module_name) const;
  196. // Enumerates imports from a single PE delay import block.
  197. // cookie is a generic cookie to pass to the callback.
  198. // Returns true on success.
  199. bool EnumOneDelayImportChunk(EnumImportsFunction callback,
  200. PImgDelayDescr delay_descriptor,
  201. LPCSTR module_name,
  202. PIMAGE_THUNK_DATA name_table,
  203. PIMAGE_THUNK_DATA iat,
  204. PVOID cookie) const;
  205. // Enumerates PE relocation entries.
  206. // cookie is a generic cookie to pass to the callback.
  207. // Returns true on success.
  208. bool EnumRelocs(EnumRelocsFunction callback, PVOID cookie) const;
  209. // Verifies the magic values on the PE file.
  210. // Returns true if all values are correct.
  211. bool VerifyMagic() const;
  212. // Converts an rva value to the appropriate address.
  213. virtual PVOID RVAToAddr(uintptr_t rva) const;
  214. // Converts an rva value to an offset on disk.
  215. // Returns true on success.
  216. bool ImageRVAToOnDiskOffset(uintptr_t rva, DWORD* on_disk_offset) const;
  217. // Converts an address to an offset on disk.
  218. // Returns true on success.
  219. bool ImageAddrToOnDiskOffset(LPVOID address, DWORD* on_disk_offset) const;
  220. private:
  221. // Returns a pointer to a data directory, or NULL if |directory| is out of
  222. // range.
  223. const IMAGE_DATA_DIRECTORY* GetDataDirectory(UINT directory) const;
  224. HMODULE module_;
  225. };
  226. // This class is an extension to the PEImage class that allows working with PE
  227. // files mapped as data instead of as image file.
  228. class PEImageAsData : public PEImage {
  229. public:
  230. explicit PEImageAsData(HMODULE hModule) : PEImage(hModule) {}
  231. PVOID RVAToAddr(uintptr_t rva) const override;
  232. };
  233. inline bool PEImage::IsOrdinal(LPCSTR name) {
  234. return reinterpret_cast<uintptr_t>(name) <= 0xFFFF;
  235. }
  236. inline WORD PEImage::ToOrdinal(LPCSTR name) {
  237. return static_cast<WORD>(reinterpret_cast<intptr_t>(name));
  238. }
  239. inline HMODULE PEImage::module() const {
  240. return module_;
  241. }
  242. inline PIMAGE_IMPORT_DESCRIPTOR PEImage::GetFirstImportChunk() const {
  243. return reinterpret_cast<PIMAGE_IMPORT_DESCRIPTOR>(
  244. GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_IMPORT));
  245. }
  246. inline PIMAGE_EXPORT_DIRECTORY PEImage::GetExportDirectory() const {
  247. return reinterpret_cast<PIMAGE_EXPORT_DIRECTORY>(
  248. GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_EXPORT));
  249. }
  250. } // namespace win
  251. } // namespace base
  252. #endif // BASE_WIN_PE_IMAGE_H_