Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:30:44

0001 // Copyright 2014 Renato Tegon Forti, Antony Polukhin.
0002 // Copyright Antony Polukhin, 2015-2023.
0003 //
0004 // Distributed under the Boost Software License, Version 1.0.
0005 // (See accompanying file LICENSE_1_0.txt
0006 // or copy at http://www.boost.org/LICENSE_1_0.txt)
0007 
0008 #ifndef BOOST_DLL_DETAIL_WINDOWS_PE_INFO_HPP
0009 #define BOOST_DLL_DETAIL_WINDOWS_PE_INFO_HPP
0010 
0011 #include <boost/dll/config.hpp>
0012 
0013 #ifdef BOOST_HAS_PRAGMA_ONCE
0014 # pragma once
0015 #endif
0016 
0017 #include <cstring>
0018 #include <fstream>
0019 #include <string> // for std::getline
0020 #include <vector>
0021 
0022 #include <boost/assert.hpp>
0023 #include <boost/cstdint.hpp>
0024 
0025 namespace boost { namespace dll { namespace detail {
0026 
0027 // reference:
0028 // http://www.joachim-bauch.de/tutorials/loading-a-dll-from-memory/
0029 // http://msdn.microsoft.com/en-us/magazine/ms809762.aspx
0030 // http://msdn.microsoft.com/en-us/magazine/cc301808.aspx
0031 //
0032 
0033 // Basic Windows typedefs. We can not use <boost/winapi/basic_types.hpp> header
0034 // because that header must be included only on Windows platform
0035 typedef unsigned char BYTE_;
0036 typedef unsigned short WORD_;
0037 typedef boost::uint32_t DWORD_;
0038 typedef boost::int32_t LONG_;
0039 typedef boost::uint32_t ULONG_;
0040 typedef boost::int64_t LONGLONG_;
0041 typedef boost::uint64_t ULONGLONG_;
0042 
0043 struct IMAGE_DOS_HEADER_ { // 32/64 independent header
0044     boost::dll::detail::WORD_   e_magic;        // Magic number
0045     boost::dll::detail::WORD_   e_cblp;         // Bytes on last page of file
0046     boost::dll::detail::WORD_   e_cp;           // Pages in file
0047     boost::dll::detail::WORD_   e_crlc;         // Relocations
0048     boost::dll::detail::WORD_   e_cparhdr;      // Size of header in paragraphs
0049     boost::dll::detail::WORD_   e_minalloc;     // Minimum extra paragraphs needed
0050     boost::dll::detail::WORD_   e_maxalloc;     // Maximum extra paragraphs needed
0051     boost::dll::detail::WORD_   e_ss;           // Initial (relative) SS value
0052     boost::dll::detail::WORD_   e_sp;           // Initial SP value
0053     boost::dll::detail::WORD_   e_csum;         // Checksum
0054     boost::dll::detail::WORD_   e_ip;           // Initial IP value
0055     boost::dll::detail::WORD_   e_cs;           // Initial (relative) CS value
0056     boost::dll::detail::WORD_   e_lfarlc;       // File address of relocation table
0057     boost::dll::detail::WORD_   e_ovno;         // Overlay number
0058     boost::dll::detail::WORD_   e_res[4];       // Reserved words
0059     boost::dll::detail::WORD_   e_oemid;        // OEM identifier (for e_oeminfo)
0060     boost::dll::detail::WORD_   e_oeminfo;      // OEM information; e_oemid specific
0061     boost::dll::detail::WORD_   e_res2[10];     // Reserved words
0062     boost::dll::detail::LONG_   e_lfanew;       // File address of new exe header
0063 };
0064 
0065 struct IMAGE_FILE_HEADER_ { // 32/64 independent header
0066     boost::dll::detail::WORD_   Machine;
0067     boost::dll::detail::WORD_   NumberOfSections;
0068     boost::dll::detail::DWORD_  TimeDateStamp;
0069     boost::dll::detail::DWORD_  PointerToSymbolTable;
0070     boost::dll::detail::DWORD_  NumberOfSymbols;
0071     boost::dll::detail::WORD_   SizeOfOptionalHeader;
0072     boost::dll::detail::WORD_   Characteristics;
0073 };
0074 
0075 struct IMAGE_DATA_DIRECTORY_ { // 32/64 independent header
0076     boost::dll::detail::DWORD_  VirtualAddress;
0077     boost::dll::detail::DWORD_  Size;
0078 };
0079 
0080 struct IMAGE_EXPORT_DIRECTORY_ { // 32/64 independent header
0081     boost::dll::detail::DWORD_  Characteristics;
0082     boost::dll::detail::DWORD_  TimeDateStamp;
0083     boost::dll::detail::WORD_   MajorVersion;
0084     boost::dll::detail::WORD_   MinorVersion;
0085     boost::dll::detail::DWORD_  Name;
0086     boost::dll::detail::DWORD_  Base;
0087     boost::dll::detail::DWORD_  NumberOfFunctions;
0088     boost::dll::detail::DWORD_  NumberOfNames;
0089     boost::dll::detail::DWORD_  AddressOfFunctions;
0090     boost::dll::detail::DWORD_  AddressOfNames;
0091     boost::dll::detail::DWORD_  AddressOfNameOrdinals;
0092 };
0093 
0094 struct IMAGE_SECTION_HEADER_ { // 32/64 independent header
0095     static const std::size_t    IMAGE_SIZEOF_SHORT_NAME_ = 8;
0096 
0097     boost::dll::detail::BYTE_   Name[IMAGE_SIZEOF_SHORT_NAME_];
0098     union {
0099         boost::dll::detail::DWORD_   PhysicalAddress;
0100         boost::dll::detail::DWORD_   VirtualSize;
0101     } Misc;
0102     boost::dll::detail::DWORD_  VirtualAddress;
0103     boost::dll::detail::DWORD_  SizeOfRawData;
0104     boost::dll::detail::DWORD_  PointerToRawData;
0105     boost::dll::detail::DWORD_  PointerToRelocations;
0106     boost::dll::detail::DWORD_  PointerToLinenumbers;
0107     boost::dll::detail::WORD_   NumberOfRelocations;
0108     boost::dll::detail::WORD_   NumberOfLinenumbers;
0109     boost::dll::detail::DWORD_  Characteristics;
0110 };
0111 
0112 
0113 template <class AddressOffsetT>
0114 struct IMAGE_OPTIONAL_HEADER_template {
0115     static const std::size_t IMAGE_NUMBEROF_DIRECTORY_ENTRIES_ = 16;
0116 
0117     boost::dll::detail::WORD_   Magic;
0118     boost::dll::detail::BYTE_   MajorLinkerVersion;
0119     boost::dll::detail::BYTE_   MinorLinkerVersion;
0120     boost::dll::detail::DWORD_  SizeOfCode;
0121     boost::dll::detail::DWORD_  SizeOfInitializedData;
0122     boost::dll::detail::DWORD_  SizeOfUninitializedData;
0123     boost::dll::detail::DWORD_  AddressOfEntryPoint;
0124     union {
0125         boost::dll::detail::DWORD_   BaseOfCode;
0126         unsigned char padding_[sizeof(AddressOffsetT) == 8 ? 4 : 8]; // in x64 version BaseOfData does not exist
0127     } BaseOfCode_and_BaseOfData;
0128 
0129     AddressOffsetT              ImageBase;
0130     boost::dll::detail::DWORD_  SectionAlignment;
0131     boost::dll::detail::DWORD_  FileAlignment;
0132     boost::dll::detail::WORD_   MajorOperatingSystemVersion;
0133     boost::dll::detail::WORD_   MinorOperatingSystemVersion;
0134     boost::dll::detail::WORD_   MajorImageVersion;
0135     boost::dll::detail::WORD_   MinorImageVersion;
0136     boost::dll::detail::WORD_   MajorSubsystemVersion;
0137     boost::dll::detail::WORD_   MinorSubsystemVersion;
0138     boost::dll::detail::DWORD_  Win32VersionValue;
0139     boost::dll::detail::DWORD_  SizeOfImage;
0140     boost::dll::detail::DWORD_  SizeOfHeaders;
0141     boost::dll::detail::DWORD_  CheckSum;
0142     boost::dll::detail::WORD_   Subsystem;
0143     boost::dll::detail::WORD_   DllCharacteristics;
0144     AddressOffsetT              SizeOfStackReserve;
0145     AddressOffsetT              SizeOfStackCommit;
0146     AddressOffsetT              SizeOfHeapReserve;
0147     AddressOffsetT              SizeOfHeapCommit;
0148     boost::dll::detail::DWORD_  LoaderFlags;
0149     boost::dll::detail::DWORD_  NumberOfRvaAndSizes;
0150     IMAGE_DATA_DIRECTORY_       DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES_];
0151 };
0152 
0153 typedef IMAGE_OPTIONAL_HEADER_template<boost::dll::detail::DWORD_>      IMAGE_OPTIONAL_HEADER32_;
0154 typedef IMAGE_OPTIONAL_HEADER_template<boost::dll::detail::ULONGLONG_>  IMAGE_OPTIONAL_HEADER64_;
0155 
0156 template <class AddressOffsetT>
0157 struct IMAGE_NT_HEADERS_template {
0158     boost::dll::detail::DWORD_                      Signature;
0159     IMAGE_FILE_HEADER_                              FileHeader;
0160     IMAGE_OPTIONAL_HEADER_template<AddressOffsetT>  OptionalHeader;
0161 };
0162 
0163 typedef IMAGE_NT_HEADERS_template<boost::dll::detail::DWORD_>      IMAGE_NT_HEADERS32_;
0164 typedef IMAGE_NT_HEADERS_template<boost::dll::detail::ULONGLONG_>  IMAGE_NT_HEADERS64_;
0165 
0166 
0167 template <class AddressOffsetT>
0168 class pe_info {
0169     typedef IMAGE_NT_HEADERS_template<AddressOffsetT>   header_t;
0170     typedef IMAGE_EXPORT_DIRECTORY_                     exports_t;
0171     typedef IMAGE_SECTION_HEADER_                       section_t;
0172     typedef IMAGE_DOS_HEADER_                           dos_t;
0173 
0174     template <class T>
0175     static void read_raw(std::ifstream& fs, T& value, std::size_t size = sizeof(T)) {
0176         fs.read(reinterpret_cast<char*>(&value), size);
0177     }
0178 
0179 public:
0180     static bool parsing_supported(std::ifstream& fs) {
0181         dos_t dos;
0182         fs.seekg(0);
0183         fs.read(reinterpret_cast<char*>(&dos), sizeof(dos));
0184 
0185         // 'MZ' and 'ZM' according to Wikipedia
0186         if (dos.e_magic != 0x4D5A && dos.e_magic != 0x5A4D) {
0187             return false;
0188         }
0189 
0190         header_t h;
0191         fs.seekg(dos.e_lfanew);
0192         fs.read(reinterpret_cast<char*>(&h), sizeof(h));
0193 
0194         return h.Signature == 0x00004550 // 'PE00'
0195                 && h.OptionalHeader.Magic == (sizeof(boost::uint32_t) == sizeof(AddressOffsetT) ? 0x10B : 0x20B);
0196     }
0197 
0198 private:
0199     static header_t header(std::ifstream& fs) {
0200         header_t h;
0201 
0202         dos_t dos;
0203         fs.seekg(0);
0204         read_raw(fs, dos);
0205 
0206         fs.seekg(dos.e_lfanew);
0207         read_raw(fs, h);
0208 
0209         return h;
0210     }
0211 
0212     static exports_t exports(std::ifstream& fs, const header_t& h) {
0213         static const unsigned int IMAGE_DIRECTORY_ENTRY_EXPORT_ = 0;
0214         const std::size_t exp_virtual_address = h.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT_].VirtualAddress;
0215         exports_t exports;
0216 
0217         if (exp_virtual_address == 0) {
0218             // The virtual address can be 0 in case there are no exported symbols
0219             std::memset(&exports, 0, sizeof(exports));
0220             return exports;
0221         }
0222 
0223         const std::size_t real_offset = get_file_offset(fs, exp_virtual_address, h);
0224         BOOST_ASSERT(real_offset);
0225 
0226         fs.seekg(real_offset);
0227         read_raw(fs, exports);
0228 
0229         return exports;
0230     }
0231 
0232     static std::size_t get_file_offset(std::ifstream& fs, std::size_t virtual_address, const header_t& h) {
0233         BOOST_ASSERT(virtual_address);
0234 
0235         section_t image_section_header;
0236         
0237         {   // fs.seekg to the beginning on section headers
0238             dos_t dos;
0239             fs.seekg(0);
0240             read_raw(fs, dos);
0241             fs.seekg(dos.e_lfanew + sizeof(header_t));
0242         }
0243 
0244         for (std::size_t i = 0;i < h.FileHeader.NumberOfSections;++i) {
0245             read_raw(fs, image_section_header);
0246             if (virtual_address >= image_section_header.VirtualAddress 
0247                 && virtual_address < image_section_header.VirtualAddress + image_section_header.SizeOfRawData) 
0248             {
0249                 return image_section_header.PointerToRawData + virtual_address - image_section_header.VirtualAddress;
0250             }
0251         }
0252 
0253         return 0;
0254     }
0255 
0256 public:
0257     static std::vector<std::string> sections(std::ifstream& fs) {
0258         std::vector<std::string> ret;
0259 
0260         const header_t h = header(fs);
0261         ret.reserve(h.FileHeader.NumberOfSections);
0262 
0263         // get names, e.g: .text .rdata .data .rsrc .reloc
0264         section_t image_section_header;
0265         char name_helper[section_t::IMAGE_SIZEOF_SHORT_NAME_ + 1];
0266         std::memset(name_helper, 0, sizeof(name_helper));
0267         for (std::size_t i = 0;i < h.FileHeader.NumberOfSections;++i) {
0268             // There is no terminating null character if the string is exactly eight characters long
0269             read_raw(fs, image_section_header);
0270             std::memcpy(name_helper, image_section_header.Name, section_t::IMAGE_SIZEOF_SHORT_NAME_);
0271             
0272             if (name_helper[0] != '/') {
0273                 ret.push_back(name_helper);
0274             } else {
0275                 // For longer names, image_section_header.Name contains a slash (/) followed by ASCII representation of a decimal number.
0276                 // this number is an offset into the string table.
0277                 // TODO: fixme
0278                 ret.push_back(name_helper);
0279             }
0280         }
0281 
0282         return ret;
0283     }
0284 
0285     static std::vector<std::string> symbols(std::ifstream& fs) {
0286         std::vector<std::string> ret;
0287 
0288         const header_t h = header(fs);
0289         const exports_t exprt = exports(fs, h);
0290         const std::size_t exported_symbols = exprt.NumberOfNames;
0291 
0292         if (exported_symbols == 0) {
0293             return ret;
0294         }
0295 
0296         const std::size_t fixed_names_addr = get_file_offset(fs, exprt.AddressOfNames, h);
0297 
0298         ret.reserve(exported_symbols);
0299         boost::dll::detail::DWORD_ name_offset;
0300         std::string symbol_name;
0301         for (std::size_t i = 0;i < exported_symbols;++i) {
0302             fs.seekg(fixed_names_addr + i * sizeof(name_offset));
0303             read_raw(fs, name_offset);
0304             fs.seekg(get_file_offset(fs, name_offset, h));
0305             std::getline(fs, symbol_name, '\0');
0306             ret.push_back(symbol_name);
0307         }
0308 
0309         return ret;
0310     }
0311 
0312     static std::vector<std::string> symbols(std::ifstream& fs, const char* section_name) {
0313         std::vector<std::string> ret;
0314 
0315         const header_t h = header(fs);
0316         
0317         std::size_t section_begin_addr = 0;
0318         std::size_t section_end_addr = 0;
0319         
0320         {   // getting address range for the section
0321             section_t image_section_header;
0322             char name_helper[section_t::IMAGE_SIZEOF_SHORT_NAME_ + 1];
0323             std::memset(name_helper, 0, sizeof(name_helper));
0324             for (std::size_t i = 0;i < h.FileHeader.NumberOfSections;++i) {
0325                 // There is no terminating null character if the string is exactly eight characters long
0326                 read_raw(fs, image_section_header);
0327                 std::memcpy(name_helper, image_section_header.Name, section_t::IMAGE_SIZEOF_SHORT_NAME_);
0328                 if (!std::strcmp(section_name, name_helper)) {
0329                     section_begin_addr = image_section_header.PointerToRawData;
0330                     section_end_addr = section_begin_addr + image_section_header.SizeOfRawData;
0331                 }
0332             }
0333             
0334             // returning empty result if section was not found
0335             if(section_begin_addr == 0 || section_end_addr == 0)
0336                 return ret;
0337         }
0338 
0339         const exports_t exprt = exports(fs, h);
0340         const std::size_t exported_symbols = exprt.NumberOfFunctions;
0341         const std::size_t fixed_names_addr = get_file_offset(fs, exprt.AddressOfNames, h);
0342         const std::size_t fixed_ordinals_addr = get_file_offset(fs, exprt.AddressOfNameOrdinals, h);
0343         const std::size_t fixed_functions_addr = get_file_offset(fs, exprt.AddressOfFunctions, h);
0344 
0345         ret.reserve(exported_symbols);
0346         boost::dll::detail::DWORD_ ptr;
0347         boost::dll::detail::WORD_ ordinal;
0348         std::string symbol_name;
0349         for (std::size_t i = 0;i < exported_symbols;++i) {
0350             // getting ordinal
0351             fs.seekg(fixed_ordinals_addr + i * sizeof(ordinal));
0352             read_raw(fs, ordinal);
0353 
0354             // getting function addr
0355             fs.seekg(fixed_functions_addr + ordinal * sizeof(ptr));
0356             read_raw(fs, ptr);
0357             ptr = static_cast<boost::dll::detail::DWORD_>( get_file_offset(fs, ptr, h) );
0358 
0359             if (ptr >= section_end_addr || ptr < section_begin_addr) {
0360                 continue;
0361             }
0362 
0363             fs.seekg(fixed_names_addr + i * sizeof(ptr));
0364             read_raw(fs, ptr);
0365             fs.seekg(get_file_offset(fs, ptr, h));
0366             std::getline(fs, symbol_name, '\0');
0367             ret.push_back(symbol_name);
0368         }
0369 
0370         return ret;
0371     }
0372     
0373     // a test method to get dependents modules,
0374     // who my plugin imports (1st level only)
0375     /*
0376     e.g. for myself I get:
0377       KERNEL32.dll
0378       MSVCP110D.dll
0379       boost_system-vc-mt-gd-1_56.dll
0380       MSVCR110D.dll
0381     */
0382     /*
0383     static std::vector<std::string> depend_of(boost::dll::fs::error_code &ec) BOOST_NOEXCEPT {
0384         std::vector<std::string> ret;
0385 
0386         IMAGE_DOS_HEADER* image_dos_header = (IMAGE_DOS_HEADER*)native();
0387         if(!image_dos_header) {
0388             // ERROR_BAD_EXE_FORMAT 
0389             ec = boost::dll::fs::make_error_code(
0390                  boost::dll::fs::errc::executable_format_error
0391                  );
0392 
0393             return ret;
0394         }
0395 
0396         IMAGE_OPTIONAL_HEADER* image_optional_header = (IMAGE_OPTIONAL_HEADER*)((boost::dll::detail::BYTE_*)native() + image_dos_header->e_lfanew + 24);
0397         if(!image_optional_header) {
0398             // ERROR_BAD_EXE_FORMAT 
0399             ec = boost::dll::fs::make_error_code(
0400                  boost::dll::fs::errc::executable_format_error
0401                  );
0402 
0403             return ret;
0404         }
0405 
0406         IMAGE_IMPORT_DESCRIPTOR* image_import_descriptor =  (IMAGE_IMPORT_DESCRIPTOR*)((boost::dll::detail::BYTE_*)native() + image_optional_header->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
0407         if(!image_import_descriptor) {
0408             // ERROR_BAD_EXE_FORMAT 
0409             ec = boost::dll::fs::make_error_code(
0410                  boost::dll::fs::errc::executable_format_error
0411                  );
0412 
0413             return ret;
0414         }
0415 
0416         while(image_import_descriptor->FirstThunk) {
0417            std::string module_name = reinterpret_cast<char*>((boost::dll::detail::BYTE_*)native() + image_import_descriptor->Name);
0418 
0419            if(module_name.size()) {
0420               ret.push_back(module_name);
0421            }
0422                 
0423            image_import_descriptor++;
0424         }
0425 
0426         return ret;
0427     }
0428 */
0429 };
0430 
0431 typedef pe_info<boost::dll::detail::DWORD_>      pe_info32;
0432 typedef pe_info<boost::dll::detail::ULONGLONG_>  pe_info64;
0433 
0434 }}} // namespace boost::dll::detail
0435 
0436 #endif // BOOST_DLL_DETAIL_WINDOWS_PE_INFO_HPP