pe_image.h 12 KB

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