/** * Support of PE executable files. */ #include "../runtime/common.h" #include "../runtime/crypto.h" #include "objects.h" #include "osutils.h" #include "streams.h" #include "files.h" #include "pefile.h" #include "dotnetfile.h" #include "processors.h" #include "intel.h" #include "lang.h" #include "core.h" #include "script.h" #include "pdb.h" #ifdef DEMO #include "win_runtime32demo.dll.inc" #include "win_runtime64demo.dll.inc" #include "win_runtime32demo.sys.inc" #include "win_runtime64demo.sys.inc" #else #include "win_runtime32.dll.inc" #include "win_runtime64.dll.inc" #include "win_runtime32.sys.inc" #include "win_runtime64.sys.inc" #endif #include "dotnet20_runtime32.dll.inc" #include "dotnet20_runtime64.dll.inc" #include "dotnet40_runtime32.dll.inc" #include "dotnet40_runtime64.dll.inc" #include "netstandard_runtime32.dll.inc" #include "netstandard_runtime64.dll.inc" #include "netcore_runtime32.dll.inc" #include "netcore_runtime64.dll.inc" /** * PESegment */ PESegment::PESegment(PESegmentList *owner) : BaseSection(owner), address_(0), size_(0), physical_offset_(0), physical_size_(0), flags_(0) { } PESegment::PESegment(PESegmentList *owner, uint64_t address, uint32_t size, uint32_t physical_offset, uint32_t physical_size, uint32_t flags, const std::string &name) : BaseSection(owner), name_(name), address_(address), size_(size), physical_offset_(physical_offset), physical_size_(physical_size), flags_(flags) { } PESegment::PESegment(PESegmentList *owner, const PESegment &src) : BaseSection(owner, src) { address_ = src.address_; size_ = src.size_; physical_offset_ = src.physical_offset_; physical_size_ = src.physical_size_; flags_ = src.flags_; name_ = src.name_; } PESegment *PESegment::Clone(ISectionList *owner) const { PESegment *section = new PESegment(reinterpret_cast(owner), *this); return section; } void PESegment::ReadFromFile(PEArchitecture &file) { IMAGE_SECTION_HEADER section_header; file.Read(§ion_header, sizeof(section_header)); name_ = std::string(reinterpret_cast(§ion_header.Name), strnlen(reinterpret_cast(§ion_header.Name), sizeof(section_header.Name))); size_ = section_header.Misc.VirtualSize; address_ = section_header.VirtualAddress + file.image_base(); physical_offset_ = section_header.PointerToRawData; physical_size_ = section_header.SizeOfRawData; flags_ = section_header.Characteristics; } void PESegment::WriteToFile(PEArchitecture &file) const { IMAGE_SECTION_HEADER section_header = IMAGE_SECTION_HEADER(); memcpy(section_header.Name, name_.c_str(), std::min(name_.size(), sizeof(section_header.Name))); section_header.Misc.VirtualSize = size_; section_header.VirtualAddress = static_cast(address_ - file.image_base()); section_header.PointerToRawData = (physical_size_) ? physical_offset_ : 0; section_header.SizeOfRawData = physical_size_; section_header.Characteristics = flags_; file.Write(§ion_header, sizeof(section_header)); } uint32_t PESegment::memory_type() const { uint32_t res = mtNone; if (flags_ & IMAGE_SCN_MEM_READ) res |= mtReadable; if (flags_ & IMAGE_SCN_MEM_WRITE) res |= mtWritable; if (flags_ & IMAGE_SCN_MEM_EXECUTE) res |= mtExecutable; if (flags_ & IMAGE_SCN_MEM_DISCARDABLE) res |= mtDiscardable; if (flags_ & IMAGE_SCN_MEM_NOT_PAGED) res |= mtNotPaged; if (flags_ & IMAGE_SCN_MEM_SHARED) res |= mtShared; return res; } void PESegment::update_type(uint32_t mt) { if (mt & mtReadable) { flags_ |= IMAGE_SCN_MEM_READ; if ((mt & mtExecutable) == 0) flags_ |= IMAGE_SCN_CNT_INITIALIZED_DATA; } if (mt & mtWritable) flags_ |= IMAGE_SCN_MEM_WRITE; if (mt & mtExecutable) flags_ |= IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE; if ((mt & (mtDiscardable | mtNotDiscardable)) == mtDiscardable) flags_ |= IMAGE_SCN_MEM_DISCARDABLE; else flags_ &= ~IMAGE_SCN_MEM_DISCARDABLE; if (mt & mtNotPaged) flags_ |= IMAGE_SCN_MEM_NOT_PAGED; if (mt & mtShared) flags_ |= IMAGE_SCN_MEM_SHARED; } void PESegment::Rebase(uint64_t delta_base) { address_ += delta_base; } /** * PESegmentList */ PESegmentList::PESegmentList(PEArchitecture *owner) : BaseSectionList(owner), header_segment_(NULL) { } PESegmentList::PESegmentList(PEArchitecture *owner, const PESegmentList &src) : BaseSectionList(owner, src), header_segment_(NULL) { if (src.header_segment_) header_segment_ = src.header_segment_->Clone(NULL); } PESegmentList::~PESegmentList() { delete header_segment_; } PESegmentList *PESegmentList::Clone(PEArchitecture *owner) const { PESegmentList *section_list = new PESegmentList(owner, *this); return section_list; } PESegment *PESegmentList::Add() { PESegment *section = new PESegment(this); AddObject(section); return section; } PESegment *PESegmentList::Add(uint64_t address, uint32_t size, uint32_t physical_offset, uint32_t physical_size, uint32_t flags, const std::string &name) { PESegment *section = new PESegment(this, address, size, physical_offset, physical_size, flags, name); AddObject(section); return section; } PESegment *PESegmentList::item(size_t index) const { return reinterpret_cast(BaseSectionList::item(index)); } PESegment *PESegmentList::GetSectionByAddress(uint64_t address) const { PESegment *res = reinterpret_cast(BaseSectionList::GetSectionByAddress(address)); if (!res && header_segment_ && address >= header_segment_->address() && address < header_segment_->address() + header_segment_->size()) res = header_segment_; return res; } PESegment *PESegmentList::last() const { return reinterpret_cast(BaseSectionList::last()); } void PESegmentList::ReadFromFile(PEArchitecture &file, uint32_t count) { Reserve(count); for (size_t i = 0; i < count; i++) { Add()->ReadFromFile(file); } if (header_segment_) { delete header_segment_; header_segment_ = NULL; } if (this->count()) { PESegment *first_segment = item(0); header_segment_ = new PESegment(NULL, file.image_base(), static_cast(first_segment->address() - file.image_base()), 0, first_segment->physical_offset(), 0, ".header"); } } void PESegmentList::WriteToFile(PEArchitecture &file) const { for (size_t i = 0; i < count(); i++) { item(i)->WriteToFile(file); } } /** * PESection */ PESection::PESection(PESectionList *owner, PESegment *parent, uint64_t address, uint64_t size, const std::string &name) : BaseSection(owner), name_(name), address_(address), size_(size), parent_(parent) { } PESection::PESection(PESectionList *owner, const PESection &src) : BaseSection(owner, src) { address_ = src.address_; size_ = src.size_; name_ = src.name_; parent_ = src.parent_; } PESection *PESection::Clone(ISectionList *owner) const { PESection *section = new PESection(reinterpret_cast(owner), *this); return section; } void PESection::Rebase(uint64_t delta_base) { address_ += delta_base; } /** * PESectionList */ PESectionList::PESectionList(PEArchitecture *owner) : BaseSectionList(owner) { } PESectionList::PESectionList(PEArchitecture *owner, const PESectionList &src) : BaseSectionList(owner, src) { } PESectionList *PESectionList::Clone(PEArchitecture *owner) const { PESectionList *section_list = new PESectionList(owner, *this); return section_list; } PESection *PESectionList::item(size_t index) const { return reinterpret_cast(BaseSectionList::item(index)); } PESection *PESectionList::Add(PESegment *parent, uint64_t address, uint64_t size, const std::string &name) { PESection *section = new PESection(this, parent, address, size, name); AddObject(section); return section; } /** * PEDirectory */ PEDirectory::PEDirectory(PEDirectoryList *owner, uint32_t type) : BaseLoadCommand(owner), address_(0), size_(0), type_(type), physical_size_(0) { } PEDirectory::PEDirectory(PEDirectoryList *owner, const PEDirectory &src) : BaseLoadCommand(owner, src) { address_ = src.address_; size_ = src.size_; type_ = src.type_; physical_size_ = src.physical_size_; } PEDirectory *PEDirectory::Clone(ILoadCommandList *owner) const { PEDirectory *dir = new PEDirectory(reinterpret_cast(owner), *this); return dir; } void PEDirectory::clear() { address_ = 0; size_ = 0; physical_size_ = 0; } void PEDirectory::ReadFromFile(PEArchitecture &file) { IMAGE_DATA_DIRECTORY dir; file.Read(&dir, sizeof(IMAGE_DATA_DIRECTORY)); address_ = (dir.VirtualAddress == 0) ? 0 : dir.VirtualAddress + file.image_base(); size_ = dir.Size; } void PEDirectory::WriteToFile(PEArchitecture &file) const { IMAGE_DATA_DIRECTORY dir; dir.VirtualAddress = address_ ? static_cast(address_ - file.image_base()) : 0; dir.Size = size_; file.Write(&dir, sizeof(IMAGE_DATA_DIRECTORY)); } std::string PEDirectory::name() const { switch (type_) { case IMAGE_DIRECTORY_ENTRY_EXPORT: return std::string("Export"); case IMAGE_DIRECTORY_ENTRY_IMPORT: return std::string("Import"); case IMAGE_DIRECTORY_ENTRY_RESOURCE: return std::string("Resource"); case IMAGE_DIRECTORY_ENTRY_EXCEPTION: return std::string("Exception"); case IMAGE_DIRECTORY_ENTRY_SECURITY: return std::string("Security"); case IMAGE_DIRECTORY_ENTRY_BASERELOC: return std::string("Relocation"); case IMAGE_DIRECTORY_ENTRY_DEBUG: return std::string("Debug"); case IMAGE_DIRECTORY_ENTRY_ARCHITECTURE: return std::string("Architecture"); case IMAGE_DIRECTORY_ENTRY_GLOBALPTR: return std::string("Reserved"); case IMAGE_DIRECTORY_ENTRY_TLS: return std::string("Thread Local Storage"); case IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG: return std::string("Configuration"); case IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT: return std::string("Bound Import"); case IMAGE_DIRECTORY_ENTRY_IAT: return std::string("Import Address Table"); case IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT: return std::string("Delay Import"); case IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR: return std::string(".NET MetaData"); } return BaseLoadCommand::name(); } void PEDirectory::Rebase(uint64_t delta_base) { if (address_) address_ += delta_base; } void PEDirectory::FreeByManager(MemoryManager &manager) { if (!address() || !physical_size()) return; size_t size = physical_size(); manager.Add(address_, size); IArchitecture *file = manager.owner(); for (size_t i = 0; i < size; i++) { IFixup *fixup = file->fixup_list()->GetFixupByAddress(address_ + i); if (fixup) fixup->set_deleted(true); } } /** * PEDirectoryList */ PEDirectoryList::PEDirectoryList(PEArchitecture *owner) : BaseCommandList(owner) { } PEDirectoryList::PEDirectoryList(PEArchitecture *owner, const PEDirectoryList &src) : BaseCommandList(owner, src) { } PEDirectory *PEDirectoryList::item(size_t index) const { return reinterpret_cast(BaseCommandList::item(index)); } PEDirectoryList *PEDirectoryList::Clone(PEArchitecture *owner) const { PEDirectoryList *directory_list = new PEDirectoryList(owner, *this); return directory_list; } PEDirectory *PEDirectoryList::Add(uint32_t type) { PEDirectory *dir = new PEDirectory(this, type); AddObject(dir); return dir; } PEDirectory *PEDirectoryList::GetCommandByType(uint32_t type) const { return reinterpret_cast(BaseCommandList::GetCommandByType(type)); } PEDirectory *PEDirectoryList::GetCommandByAddress(uint64_t address) const { for (size_t i = 0; i < count(); i++) { PEDirectory *dir = item(i); if (dir->address() == address) return dir; } return NULL; } void PEDirectoryList::ReadFromFile(PEArchitecture &file, uint32_t count) { for (uint32_t i = 0; i < count; i++) { Add(i)->ReadFromFile(file); } } void PEDirectoryList::WriteToFile(PEArchitecture &file) const { for (size_t i = 0; i < count(); i++) { item(i)->WriteToFile(file); } } /** * PEImportFunction */ PEImportFunction::PEImportFunction(PEImport *owner) : BaseImportFunction(owner), name_address_(0), address_(0), is_ordinal_(false), ordinal_(0) { } PEImportFunction::PEImportFunction(PEImport *owner, const std::string &name) : BaseImportFunction(owner), name_(name), name_address_(0), address_(0), is_ordinal_(false), ordinal_(0) { } PEImportFunction::PEImportFunction(PEImport *owner, uint64_t address, APIType type, MapFunction *map_function) : BaseImportFunction(owner), name_address_(0), address_(address), ordinal_(0), is_ordinal_(false) { set_type(type); set_map_function(map_function); } PEImportFunction::PEImportFunction(PEImport *owner, const PEImportFunction &src) : BaseImportFunction(owner, src) { name_ = src.name_; name_address_ = src.name_address_; address_ = src.address_; is_ordinal_ = src.is_ordinal_; ordinal_ = src.ordinal_; } PEImportFunction *PEImportFunction::Clone(IImport *owner) const { PEImportFunction *func = new PEImportFunction(reinterpret_cast(owner), *this); return func; } bool PEImportFunction::ReadFromFile(PEArchitecture &file, uint32_t &rva) { address_ = rva + file.image_base(); if (file.cpu_address_size() == osDWord) { IMAGE_THUNK_DATA32 thunk; file.Read(&thunk, sizeof(thunk)); name_address_ = thunk.u1.AddressOfData; if (!name_address_) return false; is_ordinal_ = IMAGE_SNAP_BY_ORDINAL32(name_address_); rva += sizeof(uint32_t); } else { IMAGE_THUNK_DATA64 thunk; file.Read(&thunk, sizeof(thunk)); name_address_ = thunk.u1.AddressOfData; if (!name_address_) return false; is_ordinal_ = IMAGE_SNAP_BY_ORDINAL64(name_address_); rva += sizeof(uint64_t); } if (is_ordinal_) { ordinal_ = IMAGE_ORDINAL32(name_address_); name_address_ = 0; name_ = string_format("Ordinal: %.4X", ordinal_); } else { name_address_ += file.image_base(); uint64_t pos = file.Tell(); if (!file.AddressSeek(name_address_ + sizeof(WORD))) throw std::runtime_error("Format error"); name_ = file.ReadString(); file.Seek(pos); } return true; } void PEImportFunction::FreeByManager(MemoryManager &manager, bool free_iat) { if (name_address_) manager.Add(name_address_, sizeof(uint16_t) + name_.size() + 1); if (address_ && free_iat && (options() & (ioHasDataReference | ioNoReferences)) == 0) manager.Add(address_, OperandSizeToValue(manager.owner()->cpu_address_size())); } void PEImportFunction::Rebase(uint64_t delta_base) { if (name_address_) name_address_ += delta_base; if (address_) address_ += delta_base; } bool PEImportFunction::IsInternal(const CompileContext &ctx) const { if ((options() & ioFromRuntime) == 0) { if (ctx.options.flags & cpResourceProtection) { if (type() >= atLoadResource && type() <= atEnumResourceTypesW) return true; } } return false; } std::string PEImportFunction::display_name(bool show_ret) const { return DemangleName(name_).display_name(show_ret); } /** * PEImport */ PEImport::PEImport(PEImportList *owner) : BaseImport(owner), name_address_(0), is_sdk_(false), original_first_thunk_address_(0), first_thunk_address_(0), time_stamp_(0), forwarder_chain_(0) { } PEImport::PEImport(PEImportList *owner, bool is_sdk) : BaseImport(owner), name_address_(0), is_sdk_(is_sdk), original_first_thunk_address_(0), first_thunk_address_(0), time_stamp_(0), forwarder_chain_(0) { } PEImport::PEImport(PEImportList *owner, const std::string &name) : BaseImport(owner), name_(name), name_address_(0), is_sdk_(false), original_first_thunk_address_(0), first_thunk_address_(0), time_stamp_(0), forwarder_chain_(0) { } PEImport::PEImport(PEImportList *owner, const PEImport &src) : BaseImport(owner, src) { name_ = src.name_; is_sdk_ = src.is_sdk_; name_address_ = src.name_address_; original_first_thunk_address_ = src.original_first_thunk_address_; first_thunk_address_ = src.first_thunk_address_; time_stamp_ = src.time_stamp_; forwarder_chain_ = src.forwarder_chain_; } PEImport *PEImport::Clone(IImportList *owner) const { PEImport *import = new PEImport(reinterpret_cast(owner), *this); return import; } PEImportFunction *PEImport::item(size_t index) const { return reinterpret_cast(IImport::item(index)); } bool PEImport::ReadFromFile(PEArchitecture &file) { static const ImportInfo kernel32_info[] = { {atLoadResource, "LoadResource", ioNone, ctNone}, {atFindResourceA, "FindResourceA", ioNone, ctNone}, {atFindResourceExA, "FindResourceExA", ioNone, ctNone}, {atFindResourceW, "FindResourceW", ioNone, ctNone}, {atFindResourceExW, "FindResourceExW", ioNone, ctNone}, {atEnumResourceNamesA, "EnumResourceNamesA", ioNone, ctNone}, {atEnumResourceNamesW, "EnumResourceNamesW", ioNone, ctNone}, {atEnumResourceLanguagesA, "EnumResourceLanguagesA", ioNone, ctNone}, {atEnumResourceLanguagesW, "EnumResourceLanguagesW", ioNone, ctNone}, {atEnumResourceTypesA, "EnumResourceTypesA", ioNone, ctNone}, {atEnumResourceTypesW, "EnumResourceTypesW", ioNone, ctNone}, {atNone, "ExitProcess", ioNoReturn, ctNone}, {atNone, "ExitThread", ioNoReturn, ctNone}, {atNone, "FreeLibraryAndExitThread", ioNoReturn, ctNone}, {atNone, "GetVersion", ioNative, ctNone}, {atNone, "GetVersionExA", ioNative, ctNone}, {atNone, "GetVersionExW", ioNative, ctNone} }; static const ImportInfo user32_info[] = { {atLoadStringA, "LoadStringA", ioNone, ctNone}, {atLoadStringW, "LoadStringW", ioNone, ctNone} }; static const ImportInfo msvbvm_info[] = { {atNone, "__vbaError", ioNoReturn, ctNone}, {atNone, "__vbaErrorOverflow", ioNoReturn, ctNone}, {atNone, "__vbaStopExe", ioNoReturn, ctNone}, {atNone, "__vbaFailedFriend", ioNoReturn, ctNone}, {atNone, "__vbaEnd", ioNoReturn, ctNone}, {atNone, "__vbaFPException", ioNoReturn, ctNone}, {atNone, "__vbaGenerateBoundsError", ioNoReturn, ctNone}, {atNone, "Ordinal: 0064", ioNoReturn, ctNone}, }; static const ImportInfo default_info[] = { {atNone, "@System@@Halt0$qqrv", ioNoReturn, ctNone}, {atNone, "exit", ioNoReturn, ctNone}, {atNone, "abort", ioNoReturn, ctNone}, {atNone, "?terminate@@YAXXZ", ioNoReturn, ctNone}, {atNone, "?unexpected@@YAXXZ", ioNoReturn, ctNone}, {atNone, "__std_terminate", ioNoReturn, ctNone}, {atNone, "?_Xout_of_range@std@@YAXPEBD@Z", ioNoReturn, ctNone}, {atNone, "?_Xlength_error@std@@YAXPEBD@Z", ioNoReturn, ctNone}, {atNone, "_CxxThrowException", ioNoReturn, ctNone}, }; IMAGE_IMPORT_DESCRIPTOR import_descriptor; uint64_t pos; PEImportFunction *func; size_t i, j; std::string dll_name; file.Read(&import_descriptor, sizeof(import_descriptor)); if (!import_descriptor.FirstThunk) return false; pos = file.Tell(); name_address_ = import_descriptor.Name + file.image_base(); if (!file.AddressSeek(name_address_)) throw std::runtime_error("Format error"); name_ = file.ReadString(); original_first_thunk_address_ = import_descriptor.u.OriginalFirstThunk; if (original_first_thunk_address_) original_first_thunk_address_ += file.image_base(); first_thunk_address_ = import_descriptor.FirstThunk; if (first_thunk_address_) first_thunk_address_ += file.image_base(); if (!file.AddressSeek((original_first_thunk_address_ != 0) ? original_first_thunk_address_ : first_thunk_address_)) throw std::runtime_error("Format error"); time_stamp_ = import_descriptor.TimeDateStamp; forwarder_chain_ = import_descriptor.ForwarderChain; uint32_t rva = import_descriptor.FirstThunk; while (true) { func = new PEImportFunction(this); if (!func->ReadFromFile(file, rva)) { delete func; break; } AddObject(func); } file.Seek(pos); dll_name = name_; std::transform(dll_name.begin(), dll_name.end(), dll_name.begin(), tolower); std::string sdk_name; if (file.image_type() == itDriver) { if (dll_name.find('.') == (size_t)-1) dll_name += ".sys"; sdk_name = string_format("vmprotectddk%d.sys", (file.cpu_address_size() == osDWord) ? 32 : 64); } else { if (dll_name.find('.') == (size_t)-1) dll_name += ".dll"; sdk_name = string_format("vmprotectsdk%d.dll", (file.cpu_address_size() == osDWord) ? 32 : 64); } if (dll_name.compare(sdk_name) == 0) { is_sdk_ = true; for (i = 0; i < count(); i++) { func = item(i); const ImportInfo *import_info = owner()->GetSDKInfo(func->name()); if (import_info) { func->set_type(import_info->type); if (import_info->options & ioHasCompilationType) { func->include_option(ioHasCompilationType); func->set_compilation_type(import_info->compilation_type); if (import_info->options & ioLockToKey) func->include_option(ioLockToKey); } } } } else { size_t c; const ImportInfo *import_info; if (dll_name.compare("kernel32.dll") == 0) { import_info = kernel32_info; c = _countof(kernel32_info); } else if (dll_name.compare("user32.dll") == 0) { import_info = user32_info; c = _countof(user32_info); } else if (dll_name.compare("msvbvm50.dll") == 0 || dll_name.compare("msvbvm60.dll") == 0) { import_info = msvbvm_info; c = _countof(msvbvm_info); } else { import_info = default_info; c = _countof(default_info); } if (import_info) { for (i = 0; i < count(); i++) { func = item(i); for (j = 0; j < c; j++) { if (func->name().compare(import_info[j].name) == 0) { func->set_type(import_info[j].type); if (import_info[j].options & ioNative) func->include_option(ioNative); if (import_info[j].options & ioNoReturn) func->include_option(ioNoReturn); break; } } } } } return true; } bool PEImport::FreeByManager(MemoryManager &manager, bool free_iat) { if (!name_address_) return false; manager.Add(name_address_, name_.size() + 1); for (size_t i = 0; i < count(); i++) { item(i)->FreeByManager(manager, free_iat); } if (original_first_thunk_address_ && original_first_thunk_address_ != first_thunk_address_) manager.Add(original_first_thunk_address_, count() * OperandSizeToValue(manager.owner()->cpu_address_size())); return true; } void PEImport::Rebase(uint64_t delta_base) { BaseImport::Rebase(delta_base); if (name_address_) name_address_ += delta_base; if (original_first_thunk_address_) original_first_thunk_address_ += delta_base; if (first_thunk_address_) first_thunk_address_ += delta_base; } PEImportFunction *PEImport::Add(uint64_t address, APIType type, MapFunction *map_function) { PEImportFunction *import_function = new PEImportFunction(this, address, type, map_function); AddObject(import_function); return import_function; } void PEImport::WriteToFile(PEArchitecture &file) const { IMAGE_IMPORT_DESCRIPTOR import_descriptor; import_descriptor.u.OriginalFirstThunk = original_first_thunk_address_ ? static_cast(original_first_thunk_address_ - file.image_base()) : 0; import_descriptor.TimeDateStamp = time_stamp_; import_descriptor.ForwarderChain = forwarder_chain_; import_descriptor.Name = static_cast(name_address_ - file.image_base()); import_descriptor.FirstThunk = first_thunk_address_ ? static_cast(first_thunk_address_ - file.image_base()) : 0; file.Write(&import_descriptor, sizeof(import_descriptor)); } /** * PEImportList */ PEImportList::PEImportList(PEArchitecture *owner) : BaseImportList(owner), address_(0) { } PEImportList::PEImportList(PEArchitecture *owner, const PEImportList &src) : BaseImportList(owner, src) { address_ = src.address_; } PEImportList *PEImportList::Clone(PEArchitecture *owner) const { PEImportList *import_list = new PEImportList(owner, *this); return import_list; } PEImport *PEImportList::item(size_t index) const { return reinterpret_cast(BaseImportList::item(index)); } PEImportFunction *PEImportList::GetFunctionByAddress(uint64_t address) const { return reinterpret_cast(BaseImportList::GetFunctionByAddress(address)); } void PEImportList::ReadFromFile(PEArchitecture &file, PEDirectory &dir) { if (!dir.address()) return; address_ = dir.address(); if (!file.AddressSeek(address_)) throw std::runtime_error("Format error"); while (true) { PEImport *imp = new PEImport(this); if (!imp->ReadFromFile(file)) { delete imp; break; } AddObject(imp); } } void PEImportList::WriteToFile(PEArchitecture &file, bool skip_sdk) const { PEDirectory *dir = file.command_list()->GetCommandByType(IMAGE_DIRECTORY_ENTRY_IMPORT); if (!dir) return; if (!file.AddressSeek(dir->address())) return; for (size_t i = 0; i < count(); i++) { PEImport *import = item(i); if (skip_sdk && import->is_sdk()) continue; import->WriteToFile(file); } IMAGE_IMPORT_DESCRIPTOR import_descriptor = IMAGE_IMPORT_DESCRIPTOR(); file.Write(&import_descriptor, sizeof(import_descriptor)); } void PEImportList::FreeByManager(MemoryManager &manager, bool free_iat) { if (!address_) return; size_t c = 0; for (size_t i = 0; i < count(); i++) { if (item(i)->FreeByManager(manager, free_iat)) c++; } manager.Add(address_, c * sizeof(IMAGE_IMPORT_DESCRIPTOR)); } void PEImportList::Rebase(uint64_t delta_base) { if (!address_) return; BaseImportList::Rebase(delta_base); address_ += delta_base; } PEImport *PEImportList::AddSDK() { PEImport *sdk = new PEImport(this, true); AddObject(sdk); return sdk; } /** * PEDelayImportFunction */ PEDelayImportFunction::PEDelayImportFunction(PEDelayImport *owner) : IObject(), owner_(owner), is_ordinal_(false), ordinal_(0) { } PEDelayImportFunction::PEDelayImportFunction(PEDelayImport *owner, const PEDelayImportFunction &src) : IObject(), owner_(owner) { name_ = src.name_; is_ordinal_ = src.is_ordinal_; ordinal_ = src.ordinal_; } PEDelayImportFunction::~PEDelayImportFunction() { if (owner_) owner_->RemoveObject(this); } PEDelayImportFunction *PEDelayImportFunction::Clone(PEDelayImport *owner) const { PEDelayImportFunction *func = new PEDelayImportFunction(owner, *this); return func; } bool PEDelayImportFunction::ReadFromFile(PEArchitecture &file, uint64_t add_value) { uint64_t name_address; if (file.cpu_address_size() == osDWord) { IMAGE_THUNK_DATA32 thunk; file.Read(&thunk, sizeof(thunk)); name_address = thunk.u1.AddressOfData; if (!name_address) return false; is_ordinal_ = IMAGE_SNAP_BY_ORDINAL32(name_address); } else { IMAGE_THUNK_DATA64 thunk; file.Read(&thunk, sizeof(thunk)); name_address = thunk.u1.AddressOfData; if (!name_address) return false; is_ordinal_ = IMAGE_SNAP_BY_ORDINAL64(name_address); } if (is_ordinal_) { ordinal_ = IMAGE_ORDINAL32(name_address); name_address = 0; name_ = string_format("Ordinal: %.4X", ordinal_); } else { name_address += add_value; uint64_t pos = file.Tell(); if (!file.AddressSeek(name_address + sizeof(uint16_t))) throw std::runtime_error("Format error"); name_ = file.ReadString(); file.Seek(pos); } return true; } /** * PEDelayImport */ PEDelayImport::PEDelayImport(PEDelayImportList *owner) : ObjectList(), owner_(owner) { } PEDelayImport::PEDelayImport(PEDelayImportList *owner, const PEDelayImport &src) : ObjectList(), owner_(owner) { for (size_t i = 0; i < src.count(); i++) { AddObject(src.item(i)->Clone(this)); } name_ = src.name_; flags_ = src.flags_; module_ = src.module_; iat_ = src.iat_; bound_iat_ = src.bound_iat_; unload_iat_ = src.unload_iat_; time_stamp_ = src.time_stamp_; } PEDelayImport::~PEDelayImport() { if (owner_) owner_->RemoveObject(this); } PEDelayImport *PEDelayImport::Clone(PEDelayImportList *owner) const { PEDelayImport *imp = new PEDelayImport(owner, *this); return imp; } bool PEDelayImport::ReadFromFile(PEArchitecture &file) { IMAGE_DELAY_IMPORT_DESCRIPTOR import_descriptor; file.Read(&import_descriptor, sizeof(import_descriptor)); if (!import_descriptor.DllName) return false; flags_ = import_descriptor.Attrs; uint64_t name_address = import_descriptor.DllName; module_ = import_descriptor.Hmod; iat_ = import_descriptor.IAT; uint64_t address = import_descriptor.INT; bound_iat_ = import_descriptor.BoundIAT; unload_iat_ = import_descriptor.UnloadIAT; time_stamp_ = import_descriptor.TimeStamp; uint64_t add_value; if (flags_ & 1) { add_value = file.image_base(); if (name_address) name_address += add_value; if (module_) module_ += add_value; if (iat_) iat_ += add_value; if (address) address += add_value; if (bound_iat_) bound_iat_ += add_value; if (unload_iat_) unload_iat_ += add_value; } else { if (file.cpu_address_size() != osDWord) throw std::runtime_error("Format error"); add_value = 0; } uint64_t pos = file.Tell(); if (!file.AddressSeek(name_address)) throw std::runtime_error("Format error"); name_ = file.ReadString(); if (!file.AddressSeek(address)) throw std::runtime_error("Format error"); while (true) { PEDelayImportFunction *func = new PEDelayImportFunction(this); if (!func->ReadFromFile(file, add_value)) { delete func; break; } AddObject(func); } file.Seek(pos); return true; } /** * PEDelayImportList */ PEDelayImportList::PEDelayImportList() : ObjectList() { } PEDelayImportList::PEDelayImportList(const PEDelayImportList &src) : ObjectList() { for (size_t i = 0; i < src.count(); i++) { AddObject(src.item(i)->Clone(this)); } } PEDelayImportList *PEDelayImportList::Clone() const { PEDelayImportList *import_list = new PEDelayImportList(*this); return import_list; } void PEDelayImportList::ReadFromFile(PEArchitecture &file, PEDirectory &dir) { if (!dir.address()) return; if (!file.AddressSeek(dir.address())) throw std::runtime_error("Format error"); for (size_t i = 0; i < dir.size(); i += sizeof(IMAGE_DELAY_IMPORT_DESCRIPTOR)) { PEDelayImport *imp = new PEDelayImport(this); if (!imp->ReadFromFile(file)) { delete imp; break; } AddObject(imp); } } /** * PEExport */ PEExport::PEExport(PEExportList *owner, uint64_t address, uint32_t ordinal) : BaseExport(owner), address_(address), ordinal_(ordinal), address_of_name_(0) { } PEExport::PEExport(PEExportList *owner, const PEExport &src) : BaseExport(owner, src) { address_ = src.address_; ordinal_ = src.ordinal_; name_ = src.name_; forwarded_name_ = src.forwarded_name_; address_of_name_ = src.address_of_name_; } PEExport *PEExport::Clone(IExportList *owner) const { PEExport *exp = new PEExport(reinterpret_cast(owner), *this); return exp; } int PEExport::CompareWith(const IObject &obj) const { const PEExport &exp = reinterpret_cast(obj); if (ordinal() < exp.ordinal()) return -1; if (ordinal() > exp.ordinal()) return 1; return 0; } void PEExport::ReadFromFile(PEArchitecture &file, uint64_t address_of_name, bool is_forwarded) { address_of_name_ = address_of_name; if (address_of_name_) { if (!file.AddressSeek(address_of_name_)) throw std::runtime_error("Format error"); name_ = file.ReadString(); } if (is_forwarded) { if (!file.AddressSeek(address_)) throw std::runtime_error("Format error"); forwarded_name_ = file.ReadString(); } } void PEExport::FreeByManager(MemoryManager &manager) { if (!forwarded_name_.empty()) manager.Add(address_, forwarded_name_.size() + 1); if (address_of_name_) manager.Add(address_of_name_, name_.size() + 1); } void PEExport::Rebase(uint64_t delta_base) { if (address_) address_ += delta_base; if (address_of_name_) address_of_name_ += delta_base; } std::string PEExport::display_name(bool show_ret) const { return DemangleName(name_).display_name(show_ret); } /** * PEExportList */ PEExportList::PEExportList(PEArchitecture *owner) : BaseExportList(owner), address_(0), name_address_(0), characteristics_(0), time_date_stamp_(0), major_version_(0), minor_version_(0), number_of_functions_(0), address_of_functions_(0), number_of_names_(0), address_of_names_(0), address_of_name_ordinals_(0) { } PEExportList::PEExportList(PEArchitecture *owner, const PEExportList &src) : BaseExportList(owner, src) { address_ = src.address_; name_address_ = src.name_address_; characteristics_ = src.characteristics_; time_date_stamp_ = src.time_date_stamp_; major_version_ = src.major_version_; minor_version_ = src.minor_version_; name_ = src.name_; number_of_functions_ = src.number_of_functions_; address_of_functions_ = src.address_of_functions_; number_of_names_ = src.number_of_names_; address_of_names_ = src.address_of_names_; address_of_name_ordinals_ = src.address_of_name_ordinals_; } PEExportList *PEExportList::Clone(PEArchitecture *owner) const { PEExportList *export_list = new PEExportList(owner, *this); return export_list; } PEExport *PEExportList::item(size_t index) const { return reinterpret_cast(IExportList::item(index)); } PEExport *PEExportList::Add(uint64_t address, uint32_t ordinal) { PEExport *exp = new PEExport(this, address, ordinal); AddObject(exp); return exp; } void PEExportList::AddAntidebug() { size_t i; PEExport *exp; std::map map; for (i = 0; i < count(); i++) { exp = item(i); map[exp->ordinal()] = exp; } uint32_t free_ordinal = 0; for (uint32_t ordinal = 1; ordinal <= 0xffff; ordinal++) { if (map.find(ordinal) == map.end()) { free_ordinal = ordinal; break; } } if (!free_ordinal) return; exp = Add(0, free_ordinal); std::string name; name.resize(3100); for (i = 0; i < name.size(); i++) { name[i] = 1 + rand() % 0xff; } exp->set_name(name); } PEExport *PEExportList::GetExportByOrdinal(uint32_t ordinal) { for (size_t i = 0; i < count(); i++) { PEExport *exp = item(i); if (exp->ordinal() == ordinal) return exp; } return NULL; } void PEExportList::ReadFromFile(PEArchitecture &file, PEDirectory &dir) { IMAGE_EXPORT_DIRECTORY export_directory; uint32_t i; uint32_t rva; PEExport *export_function; std::vector name_info_list; if (!dir.address()) return; address_ = dir.address(); if (!file.AddressSeek(address_)) throw std::runtime_error("Format error"); file.Read(&export_directory, sizeof(export_directory)); characteristics_ = export_directory.Characteristics; time_date_stamp_ = export_directory.TimeDateStamp; major_version_ = export_directory.MajorVersion; minor_version_ = export_directory.MinorVersion; name_address_ = export_directory.Name; if (name_address_) { name_address_ += file.image_base(); if (!file.AddressSeek(name_address_)) throw std::runtime_error("Format error"); name_ = file.ReadString(); } number_of_functions_ = export_directory.NumberOfFunctions; if (number_of_functions_) { address_of_functions_ = export_directory.AddressOfFunctions + file.image_base(); if (!file.AddressSeek(address_of_functions_)) throw std::runtime_error("Format error"); for (i = 0; i < number_of_functions_; i++) { rva = file.ReadDWord(); if (rva) Add(rva + file.image_base(), export_directory.Base + i); } } number_of_names_ = export_directory.NumberOfNames; if (number_of_names_) { address_of_names_ = export_directory.AddressOfNames + file.image_base(); if (!file.AddressSeek(address_of_names_)) throw std::runtime_error("Format error"); for (i = 0; i < number_of_names_; i++) { NameInfo name_info; name_info.address_of_name = file.ReadDWord(); name_info.ordinal_index = 0; name_info_list.push_back(name_info); } address_of_name_ordinals_ = export_directory.AddressOfNameOrdinals + file.image_base(); if (!file.AddressSeek(address_of_name_ordinals_)) throw std::runtime_error("Format error"); for (i = 0; i < number_of_names_; i++) { name_info_list[i].ordinal_index = export_directory.Base + file.ReadWord(); } } for (i = 0; i < count(); i++) { export_function = item(i); std::vector::iterator it = std::find(name_info_list.begin(), name_info_list.end(), export_function->ordinal()); export_function->ReadFromFile(file, (it == name_info_list.end()) ? 0 : it->address_of_name + file.image_base(), (export_function->address() >= dir.address() && export_function->address() < dir.address() + dir.size())); } } void PEExportList::FreeByManager(MemoryManager &manager) { if (!address_) return; manager.Add(address_, sizeof(IMAGE_EXPORT_DIRECTORY)); if (name_address_) manager.Add(name_address_, name_.size() + 1); if (number_of_functions_) manager.Add(address_of_functions_, number_of_functions_ * sizeof(uint32_t)); if (number_of_names_) { manager.Add(address_of_names_, number_of_names_ * sizeof(uint32_t)); manager.Add(address_of_name_ordinals_, number_of_names_ * sizeof(uint16_t)); } for (size_t i = 0; i < count(); i++) { item(i)->FreeByManager(manager); } } void PEExportList::ReadFromBuffer(Buffer &buffer, IArchitecture &file) { static const APIType export_function_types[] = { atSetupImage, atFreeImage, atDecryptStringA, atDecryptStringW, atFreeString, atSetSerialNumber, atGetSerialNumberState, atGetSerialNumberData, atGetCurrentHWID, atActivateLicense, atDeactivateLicense, atGetOfflineActivationString, atGetOfflineDeactivationString, atIsValidImageCRC, atIsDebuggerPresent, atIsVirtualMachinePresent, atDecryptBuffer, atIsProtected, atCalcCRC, atLoaderData, atLoadResource, atFindResourceA, atFindResourceExA, atFindResourceW, atFindResourceExW, atLoadStringA, atLoadStringW, atEnumResourceNamesA, atEnumResourceNamesW, atEnumResourceLanguagesA, atEnumResourceLanguagesW, atEnumResourceTypesA, atEnumResourceTypesW }; BaseExportList::ReadFromBuffer(buffer, file); assert(count() == _countof(export_function_types)); for (size_t i = 0; i < count(); i++) { item(i)->set_type(export_function_types[i]); } } uint32_t PEExportList::WriteToData(IFunction &data, uint64_t image_base) { if (!count()) return 0; IntelFunction &func = reinterpret_cast(data); // export functions must be sorted by ordinals Sort(); size_t start_index = func.count(); uint32_t ordinal_base = item(0)->ordinal(); func.AddCommand(osDWord, characteristics_); func.AddCommand(osDWord, time_date_stamp_); func.AddCommand(osWord, major_version_); func.AddCommand(osWord, minor_version_); IntelCommand *name_command = func.AddCommand(osDWord, 0); func.AddCommand(osDWord, ordinal_base); IntelCommand *functions_count = func.AddCommand(osDWord, 0); functions_count->AddLink(0, ltOffset); IntelCommand *name_pointers_count = func.AddCommand(osDWord, 0); name_pointers_count->AddLink(0, ltOffset); IntelCommand *address_table = func.AddCommand(osDWord, 0); address_table->AddLink(0, ltOffset); IntelCommand *name_pointers = func.AddCommand(osDWord, 0); name_pointers->AddLink(0, ltOffset); IntelCommand *ordinal_table = func.AddCommand(osDWord, 0); ordinal_table->AddLink(0, ltOffset); // create ordinals size_t index = func.count(); uint32_t last_ordinal = ordinal_base; std::vector export_name_list; PEExport *export_function; IntelCommand *command; size_t i, j; for (i = 0; i < count(); i++) { export_function = item(i); if (!export_function->name().empty()) export_name_list.push_back(ExportInfo(export_function)); for (j = last_ordinal; j < export_function->ordinal(); j++) { func.AddCommand(osDWord, 0); } command = func.AddCommand(osDWord, export_function->address() ? export_function->address() - image_base : 0); if (!export_function->forwarded_name().empty()) command->AddLink(0, ltOffset); last_ordinal = export_function->ordinal() + 1; } address_table->link()->set_to_command(func.item(index)); functions_count->set_operand_value(0, func.count() - index); // create forwarded names for (i = 0; i < count(); i++) { export_function = item(i); if (export_function->forwarded_name().empty()) continue; command = func.AddCommand(export_function->forwarded_name()); func.item(index + export_function->ordinal() - ordinal_base)->link()->set_to_command(command); } if (!export_name_list.empty()) { // names must be sorted std::sort(export_name_list.begin(), export_name_list.end()); // create ordinal table index = func.count(); for (i = 0; i < export_name_list.size(); i++) { export_function = export_name_list[i].export_function; func.AddCommand(osWord, export_function->ordinal() - ordinal_base); } name_pointers_count->set_operand_value(0, export_name_list.size()); ordinal_table->link()->set_to_command(func.item(index)); // create names index = func.count(); for (i = 0; i < export_name_list.size(); i++) { command = func.AddCommand(osDWord, 0); command->AddLink(0, ltOffset); } for (i = 0; i < export_name_list.size(); i++) { export_function = export_name_list[i].export_function; command = func.AddCommand(export_function->name()); func.item(index + i)->link()->set_to_command(command); } name_pointers->link()->set_to_command(func.item(index)); } // create DLL name if (!name().empty()) { command = func.AddCommand(name()); name_command->AddLink(0, ltOffset, command); } command = func.item(start_index); command->include_option(roCreateNewBlock); command->set_alignment(OperandSizeToValue(func.cpu_address_size())); uint32_t res = 0; for (i = start_index; i < func.count(); i++) { command = func.item(i); if (command->link()) command->link()->set_sub_value(image_base); command->CompileToNative(); res += (uint32_t)command->dump_size(); } return res; } /** * PEFixup */ PEFixup::PEFixup(PEFixupList *owner, uint64_t address, uint8_t type) : BaseFixup(owner), address_(address), type_(type) { } PEFixup::PEFixup(PEFixupList *owner, const PEFixup &src) : BaseFixup(owner, src) { address_ = src.address_; type_ = src.type_; } PEFixup *PEFixup::Clone(IFixupList *owner) const { PEFixup *fixup = new PEFixup(reinterpret_cast(owner), *this); return fixup; } FixupType PEFixup::type() const { switch (type_) { case IMAGE_REL_BASED_HIGH: return ftHigh; case IMAGE_REL_BASED_LOW: return ftLow; case IMAGE_REL_BASED_HIGHLOW: case IMAGE_REL_BASED_DIR64: return ftHighLow; default: return ftUnknown; } } OperandSize PEFixup::size() const { return type_ == IMAGE_REL_BASED_DIR64 ? osQWord : osDWord; } void PEFixup::Rebase(IArchitecture &file, uint64_t delta_base) { if (!file.AddressSeek(address_)) return; uint64_t pos = file.Tell(); uint64_t value; switch (type_) { case IMAGE_REL_BASED_LOW: value = file.ReadWord(); value += delta_base; file.Seek(pos); file.WriteWord(static_cast(value)); break; case IMAGE_REL_BASED_HIGH: value = file.ReadWord(); value += delta_base >> 16; file.Seek(pos); file.WriteWord(static_cast(value)); break; case IMAGE_REL_BASED_HIGHLOW: value = file.ReadDWord(); value += delta_base; file.Seek(pos); file.WriteDWord(static_cast(value)); break; case IMAGE_REL_BASED_DIR64: value = file.ReadQWord(); value += delta_base; file.Seek(pos); file.WriteQWord(value); break; } address_ += delta_base; } /** * PEFixupList */ PEFixupList::PEFixupList() : BaseFixupList() { } PEFixupList::PEFixupList(const PEFixupList &src) : BaseFixupList(src) { } PEFixup *PEFixupList::item(size_t index) const { return reinterpret_cast(BaseFixupList::item(index)); } PEFixupList *PEFixupList::Clone() const { PEFixupList *fixup_list = new PEFixupList(*this); return fixup_list; } PEFixup *PEFixupList::Add(uint64_t address, uint8_t type) { PEFixup *fixup = new PEFixup(this, address, type); AddObject(fixup); return fixup; } IFixup *PEFixupList::AddDefault(OperandSize cpu_address_size, bool is_code) { return Add(0, (cpu_address_size == osDWord) ? IMAGE_REL_BASED_HIGHLOW : IMAGE_REL_BASED_DIR64); } void PEFixupList::ReadFromFile(PEArchitecture &file, PEDirectory &dir) { if (!dir.address()) return; if (!file.AddressSeek(dir.address())) throw std::runtime_error("Invalid address of the base relocation table"); IMAGE_BASE_RELOCATION reloc; for (uint32_t processed = 0; processed < dir.size(); processed += reloc.SizeOfBlock) { file.Read(&reloc, sizeof(reloc)); if (reloc.SizeOfBlock == 0) break; if (reloc.SizeOfBlock < sizeof(IMAGE_BASE_RELOCATION) || (reloc.SizeOfBlock & 1) != 0) throw std::runtime_error("Invalid size of the base relocation block"); size_t c = (reloc.SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) >> 1; for (size_t i = 0; i < c; i++) { uint16_t type_offset = file.ReadWord(); uint8_t type = (type_offset >> 12); if (type == IMAGE_REL_BASED_ABSOLUTE) continue; PEFixup *fixup = Add(reloc.VirtualAddress + file.image_base() + (type_offset & 0xfff), type); if (fixup->type() == ftUnknown) throw std::runtime_error("Invalid base relocation type"); } } } void PEFixupList::WriteToData(Data &data, uint64_t image_base) { Sort(); size_t size_pos = 0; IMAGE_BASE_RELOCATION reloc = IMAGE_BASE_RELOCATION(); uint16_t empty_offset = 0; for (size_t i = 0; i < count(); i++) { PEFixup *fixup = item(i); uint32_t rva = static_cast(fixup->address() - image_base); uint32_t block_rva = rva & 0xfffff000; if (reloc.SizeOfBlock == 0 || block_rva != reloc.VirtualAddress) { if (reloc.SizeOfBlock) { if (reloc.SizeOfBlock & 3) { data.PushWord(empty_offset); reloc.SizeOfBlock += sizeof(empty_offset); } data.WriteDWord(size_pos, reloc.SizeOfBlock); } size_pos = data.size() + 4; reloc.VirtualAddress = block_rva; reloc.SizeOfBlock = sizeof(reloc); data.PushBuff(&reloc, sizeof(reloc)); empty_offset = (static_cast(rva - block_rva) & 0xf00) << 4 | IMAGE_REL_BASED_ABSOLUTE; } uint16_t type_offset = (static_cast(rva - block_rva) & 0xfff) << 4 | fixup->internal_type(); data.PushWord(type_offset); reloc.SizeOfBlock += sizeof(type_offset); } if (reloc.SizeOfBlock) { if (reloc.SizeOfBlock & 3) { data.PushWord(empty_offset); reloc.SizeOfBlock += sizeof(empty_offset); } data.WriteDWord(size_pos, reloc.SizeOfBlock); } } size_t PEFixupList::WriteToFile(PEArchitecture &file) { Sort(); Data data; size_t size_pos = 0; IMAGE_BASE_RELOCATION reloc = IMAGE_BASE_RELOCATION(); uint16_t empty_offset = 0; for (size_t i = 0; i < count(); i++) { PEFixup *fixup = item(i); uint32_t rva = static_cast(fixup->address() - file.image_base()); uint32_t block_rva = rva & 0xfffff000; if (reloc.SizeOfBlock == 0 || block_rva != reloc.VirtualAddress) { if (reloc.SizeOfBlock) { if (reloc.SizeOfBlock & 3) { data.PushWord(empty_offset); reloc.SizeOfBlock += sizeof(empty_offset); } data.WriteDWord(size_pos, reloc.SizeOfBlock); } size_pos = data.size() + 4; reloc.VirtualAddress = block_rva; reloc.SizeOfBlock = sizeof(reloc); data.PushBuff(&reloc, sizeof(reloc)); empty_offset = IMAGE_REL_BASED_ABSOLUTE << 12 | (static_cast(rva - block_rva) & 0xf00); } uint16_t type_offset = fixup->internal_type() << 12 | (static_cast(rva - block_rva) & 0xfff); data.PushWord(type_offset); reloc.SizeOfBlock += sizeof(type_offset); } if (reloc.SizeOfBlock) { if (reloc.SizeOfBlock & 3) { data.PushWord(empty_offset); reloc.SizeOfBlock += sizeof(empty_offset); } data.WriteDWord(size_pos, reloc.SizeOfBlock); } return file.Write(data.data(), data.size()); } /** * PERelocation */ PERelocation::PERelocation(PERelocationList *owner, uint64_t address, uint64_t source, OperandSize size, uint32_t addend) : BaseRelocation(owner, address, size), source_(source), addend_(addend) { } PERelocation::PERelocation(PERelocationList *owner, const PERelocation &src) : BaseRelocation(owner, src) { source_ = src.source_; addend_ = src.addend_; } PERelocation *PERelocation::Clone(IRelocationList *owner) const { PERelocation *relocation = new PERelocation(reinterpret_cast(owner), *this); return relocation; } /** * PERelocationList */ PERelocationList::PERelocationList() : BaseRelocationList(), address_(0), mem_address_(0) { } PERelocationList::PERelocationList(const PERelocationList &src) : BaseRelocationList(src) { address_ = src.address_; mem_address_ = src.mem_address_; } PERelocationList *PERelocationList::Clone() const { PERelocationList *list = new PERelocationList(*this); return list; } PERelocation *PERelocationList::item(size_t index) const { return reinterpret_cast(IRelocationList::item(index)); } PERelocation *PERelocationList::Add(uint64_t address, uint64_t target, OperandSize size, uint32_t addend) { PERelocation *relocation = new PERelocation(this, address, target, size, addend); AddObject(relocation); return relocation; } void PERelocationList::ParseMinGW(PEArchitecture &file, uint64_t address, uint64_t start, uint64_t end) { if ((end < start) || (end - start < 8) || ((file.segment_list()->GetMemoryTypeByAddress(address) & mtWritable) == 0) || ((file.segment_list()->GetMemoryTypeByAddress(start) & mtReadable) == 0)) return; struct RelocationHeader { uint32_t magic1; uint32_t magic2; uint32_t version; }; struct RelocationV1 { uint32_t addend; uint32_t target; }; struct RelocationV2 { uint32_t sym; uint32_t target; uint32_t flags; }; file.AddressSeek(start); RelocationHeader header; header.magic1 = 0; header.magic2 = 0; header.version = 0; if (end - start >= sizeof(header)) { uint64_t pos = file.Tell(); file.Read(&header, sizeof(header)); if (header.magic1 == 0 && header.magic2 == 0) { start += sizeof(header); } else { file.Seek(pos); header.version = 0; } } address_ = address; switch (header.version) { case 0: while (start < end) { RelocationV1 item; file.Read(&item, sizeof(item)); start += sizeof(item); Add(file.image_base() + item.target, 0, file.cpu_address_size(), item.addend); } break; case 1: while (start < end) { RelocationV2 item; file.Read(&item, sizeof(item)); start += sizeof(item); OperandSize item_size; switch (item.flags) { case 8: item_size = osByte; break; case 16: item_size = osWord; break; case 32: item_size = osDWord; break; case 64: if (file.cpu_address_size() == osQWord) item_size = osQWord; else throw std::runtime_error("Invalid relocation flags"); break; default: throw std::runtime_error("Invalid relocation flags"); } Add(file.image_base() + item.target, file.image_base() + item.sym, item_size, 0); } break; default: return; } } void PERelocationList::ReadFromFile(PEArchitecture &file) { for (size_t i = 0; i < file.compiler_function_list()->count(); i++) { CompilerFunction *compiler_function = file.compiler_function_list()->item(i); if (compiler_function->type() == cfRelocatorMinGW) ParseMinGW(file, compiler_function->value(0), compiler_function->value(1), compiler_function->value(2)); } for (size_t i = 0; i < count(); i++) { PERelocation *relocation = item(i); if (relocation->source()) { IImportFunction *import_function = file.import_list()->GetFunctionByAddress(relocation->source()); if (import_function) { import_function->exclude_option(ioNoReferences); import_function->include_option(ioHasDataReference); } } } } void PERelocationList::WriteToData(Data &data, uint64_t image_base) { for (size_t i = 0; i < count(); i++) { PERelocation *relocation = item(i); data.PushDWord(static_cast(relocation->address() - image_base)); if (!relocation->source()) { data.PushDWord(relocation->addend()); data.PushDWord(0); } else { data.PushDWord(static_cast(relocation->source() - image_base)); data.PushDWord(relocation->size() + 1); } } if (address_) { data.PushDWord(static_cast(address_ - image_base)); data.PushDWord(1); data.PushDWord(0); } } /** * PESEHandler */ PESEHandler::PESEHandler(ISEHandlerList *owner, uint64_t address) : BaseSEHandler(owner), address_(address), deleted_(false) { } PESEHandler::PESEHandler(ISEHandlerList *owner, const PESEHandler &src) : BaseSEHandler(owner) { address_ = src.address_; deleted_ = src.deleted_; } PESEHandler *PESEHandler::Clone(ISEHandlerList *owner) const { PESEHandler *handler = new PESEHandler(owner, *this); return handler; } void PESEHandler::Rebase(uint64_t delta_base) { address_ += delta_base; } /** * PESEHandlerList */ PESEHandlerList::PESEHandlerList() : BaseSEHandlerList() { } PESEHandlerList::PESEHandlerList(const PESEHandlerList &src) : BaseSEHandlerList(src) { } PESEHandlerList *PESEHandlerList::Clone() const { PESEHandlerList *list = new PESEHandlerList(*this); return list; } PESEHandler *PESEHandlerList::item(size_t index) const { return reinterpret_cast(BaseSEHandlerList::item(index)); } PESEHandler *PESEHandlerList::Add(uint64_t address) { PESEHandler *handler = new PESEHandler(this, address); AddObject(handler); return handler; } void PESEHandlerList::Rebase(uint64_t delta_base) { for (size_t i = 0; i < count(); i++) { item(i)->Rebase(delta_base); } } void PESEHandlerList::Pack() { for (size_t i = count(); i > 0; i--) { PESEHandler *handler = item(i - 1); if (handler->is_deleted()) delete handler; } } /** * PELoadConfigDirectory */ PELoadConfigDirectory::PELoadConfigDirectory() : IObject(), seh_table_address_(0), security_cookie_(0), cfg_table_address_(0), guard_flags_(0), cfg_check_function_(0) { seh_handler_list_ = new PESEHandlerList(); cfg_address_list_ = new PECFGAddressTable(); } PELoadConfigDirectory::PELoadConfigDirectory(const PELoadConfigDirectory &src) : IObject(src) { seh_table_address_ = src.seh_table_address_; security_cookie_ = src.security_cookie_; cfg_table_address_ = src.cfg_table_address_; guard_flags_ = src.guard_flags_; cfg_check_function_ = src.cfg_check_function_; seh_handler_list_ = src.seh_handler_list_->Clone(); cfg_address_list_ = src.cfg_address_list_->Clone(); } PELoadConfigDirectory::~PELoadConfigDirectory() { delete seh_handler_list_; delete cfg_address_list_; } PELoadConfigDirectory *PELoadConfigDirectory::Clone() const { PELoadConfigDirectory *list = new PELoadConfigDirectory(*this); return list; } void PELoadConfigDirectory::ReadFromFile(PEArchitecture &file, PEDirectory &dir) { if (!dir.address()) return; if (!file.AddressSeek(dir.address())) throw std::runtime_error("Invalid address of the load config directory"); size_t handler_count; size_t cfg_table_count; uint64_t pos = file.Tell(); size_t size = file.ReadDWord(); file.Seek(pos); if (file.cpu_address_size() == osQWord) { IMAGE_LOAD_CONFIG_DIRECTORYEX64 load_config_directory = IMAGE_LOAD_CONFIG_DIRECTORYEX64(); file.Read(&load_config_directory, std::min(sizeof(load_config_directory), size)); security_cookie_ = load_config_directory.SecurityCookie; if (load_config_directory.Size > dir.physical_size()) dir.set_physical_size(load_config_directory.Size); seh_table_address_ = load_config_directory.SEHandlerTable; handler_count = static_cast(load_config_directory.SEHandlerCount); cfg_check_function_ = load_config_directory.GuardCFCheckFunctionPointer; cfg_table_address_ = load_config_directory.GuardCFFunctionTable; cfg_table_count = static_cast(load_config_directory.GuardCFFunctionCount); guard_flags_ = load_config_directory.GuardFlags; } else { IMAGE_LOAD_CONFIG_DIRECTORYEX32 load_config_directory = IMAGE_LOAD_CONFIG_DIRECTORYEX32(); file.Read(&load_config_directory, std::min(sizeof(load_config_directory), size)); security_cookie_ = load_config_directory.SecurityCookie; if (load_config_directory.Size > dir.physical_size()) dir.set_physical_size(load_config_directory.Size); seh_table_address_ = load_config_directory.SEHandlerTable; handler_count = load_config_directory.SEHandlerCount; cfg_check_function_ = load_config_directory.GuardCFCheckFunctionPointer; cfg_table_address_ = load_config_directory.GuardCFFunctionTable; cfg_table_count = load_config_directory.GuardCFFunctionCount; guard_flags_ = load_config_directory.GuardFlags; } if (seh_table_address_) { if (!file.AddressSeek(seh_table_address_)) throw std::runtime_error("Invalid address of seh handler table"); for (size_t i = 0; i < handler_count; i++) { seh_handler_list_->Add(file.ReadDWord() + file.image_base()); } } if (cfg_table_address_) { if (!file.AddressSeek(cfg_table_address_)) throw std::runtime_error("Invalid address of cfg handler table"); size_t data_size = (guard_flags_ & IMAGE_GUARD_CF_FUNCTION_TABLE_SIZE_MASK) >> IMAGE_GUARD_CF_FUNCTION_TABLE_SIZE_SHIFT; std::vector data; data.resize(data_size); for (size_t i = 0; i < cfg_table_count; i++) { PECFGAddress *cfg_address = cfg_address_list_->Add(file.ReadDWord() + file.image_base()); if (data_size) { file.Read(data.data(), data.size()); cfg_address->set_data(data); } } } } size_t PELoadConfigDirectory::WriteToFile(PEArchitecture &file) { PEDirectory *dir = file.command_list()->GetCommandByType(IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG); if (!dir || !dir->address()) return 0; size_t res = 0; PESegment *last_section = file.segment_list()->last(); if (seh_table_address_) { seh_handler_list_->Pack(); seh_handler_list_->Sort(); seh_table_address_ = last_section->address() + file.Resize(AlignValue(file.size(), 0x10)) - last_section->physical_offset(); for (size_t i = 0; i < seh_handler_list_->count(); i++) { res += file.WriteDWord(static_cast(seh_handler_list_->item(i)->address() - file.image_base())); } } if (cfg_table_address_) { cfg_table_address_ = last_section->address() + file.Resize(AlignValue(file.size(), 0x10)) - last_section->physical_offset(); size_t data_size = (guard_flags_ & IMAGE_GUARD_CF_FUNCTION_TABLE_SIZE_MASK) >> IMAGE_GUARD_CF_FUNCTION_TABLE_SIZE_SHIFT; for (size_t i = 0; i < cfg_address_list_->count(); i++) { PECFGAddress *cfg_address = cfg_address_list_->item(i); res += file.WriteDWord(static_cast(cfg_address->address() - file.image_base())); if (data_size) { std::vector data = cfg_address->data(); if (data.empty()) data.resize(data_size); res += file.Write(data.data(), data.size()); } } } uint64_t pos = file.Tell(); if (file.AddressSeek(dir->address())) { uint64_t config_pos = file.Tell(); size_t size = file.ReadDWord(); file.Seek(config_pos); if (file.cpu_address_size() == osQWord) { IMAGE_LOAD_CONFIG_DIRECTORYEX64 load_config_directory = IMAGE_LOAD_CONFIG_DIRECTORYEX64(); size = std::min(sizeof(load_config_directory), size); file.Read(&load_config_directory, size); load_config_directory.SecurityCookie = security_cookie_; load_config_directory.SEHandlerTable = seh_table_address_; load_config_directory.SEHandlerCount = seh_table_address_ ? seh_handler_list_->count() : 0; load_config_directory.GuardCFCheckFunctionPointer = cfg_check_function_; load_config_directory.GuardCFFunctionTable = cfg_table_address_; load_config_directory.GuardCFFunctionCount = cfg_table_address_ ? cfg_address_list_->count() : 0; file.Seek(config_pos); file.Write(&load_config_directory, size); } else { IMAGE_LOAD_CONFIG_DIRECTORYEX32 load_config_directory = IMAGE_LOAD_CONFIG_DIRECTORYEX32(); size = std::min(sizeof(load_config_directory), size); file.Read(&load_config_directory, size); load_config_directory.SecurityCookie = static_cast(security_cookie_); load_config_directory.SEHandlerTable = static_cast(seh_table_address_); load_config_directory.SEHandlerCount = seh_table_address_ ? static_cast(seh_handler_list_->count()) : 0; load_config_directory.GuardCFCheckFunctionPointer = static_cast(cfg_check_function_); load_config_directory.GuardCFFunctionTable = static_cast(cfg_table_address_); load_config_directory.GuardCFFunctionCount = cfg_table_address_ ? static_cast(cfg_address_list_->count()) : 0; file.Seek(config_pos); file.Write(&load_config_directory, size); } } file.Seek(pos); return res; } void PELoadConfigDirectory::FreeByManager(MemoryManager &manager) { if (seh_table_address_ && seh_handler_list_->count()) manager.Add(seh_table_address_, OperandSizeToValue(osDWord) * seh_handler_list_->count()); if (cfg_table_address_ && cfg_address_list_->count()) { size_t data_size = (guard_flags_ & IMAGE_GUARD_CF_FUNCTION_TABLE_SIZE_MASK) >> IMAGE_GUARD_CF_FUNCTION_TABLE_SIZE_SHIFT; manager.Add(cfg_table_address_, (OperandSizeToValue(osDWord) + data_size) * cfg_address_list_->count()); } } void PELoadConfigDirectory::Rebase(uint64_t delta_base) { if (seh_table_address_) seh_table_address_ += delta_base; if (cfg_table_address_) cfg_table_address_ += delta_base; seh_handler_list_->Rebase(delta_base); cfg_address_list_->Rebase(delta_base); } /** * PECFGAddress */ PECFGAddress::PECFGAddress(PECFGAddressTable *owner, uint64_t address) : IObject(), owner_(owner), address_(address) { } PECFGAddress::PECFGAddress(PECFGAddressTable *owner, const PECFGAddress &src) : IObject(), owner_(owner) { address_ = src.address_; data_ = src.data_; } PECFGAddress::~PECFGAddress() { if (owner_) owner_->RemoveObject(this); } PECFGAddress *PECFGAddress::Clone(PECFGAddressTable *owner) const { PECFGAddress *res = new PECFGAddress(owner, *this); return res; } void PECFGAddress::Rebase(uint64_t delta_base) { address_ += delta_base; } /** * PECFGAddressTable */ PECFGAddressTable::PECFGAddressTable() : ObjectList() { } PECFGAddressTable::PECFGAddressTable(const PECFGAddressTable &src) : ObjectList() { for (size_t i = 0; i < src.count(); i++) { AddObject(src.item(i)->Clone(this)); } } PECFGAddressTable *PECFGAddressTable::Clone() const { return new PECFGAddressTable(*this); } PECFGAddress *PECFGAddressTable::Add(uint64_t address) { PECFGAddress *res = new PECFGAddress(this, address); AddObject(res); return res; } void PECFGAddressTable::Rebase(uint64_t delta_base) { for (size_t i = 0; i < count(); i++) { item(i)->Rebase(delta_base); } } /** * PEResource */ PEResource::PEResource(IResource *owner, PEResourceType type, uint32_t name_offset, uint32_t data_offset) : BaseResource(owner), type_(type), name_offset_(name_offset), data_offset_(data_offset), address_(0), entry_offset_(0), data_entry_offset_(0) { memset(&data_, 0, sizeof(data_)); } PEResource::PEResource(IResource *owner, const PEResource &src) : BaseResource(owner, src) { type_ = src.type_; name_offset_ = src.name_offset_; data_offset_ = src.data_offset_; data_ = src.data_; name_ = src.name_; address_ = src.address_; entry_offset_ = src.entry_offset_; data_entry_offset_ = src.data_entry_offset_; } PEResource *PEResource::Clone(IResource *owner) const { PEResource *resource = new PEResource(owner, *this); return resource; } PEResource *PEResource::item(size_t index) const { return reinterpret_cast(IResource::item(index)); } PEResource *PEResource::GetResourceByName(const std::string &name) const { for (size_t i = 0; i < count(); i++) { PEResource *resource = item(i); if (resource->has_name() && resource->name_ == name) return resource; } return NULL; } PEResource *PEResource::Add(PEResourceType type, uint32_t name_offset, uint32_t data_offset) { PEResource *resource = new PEResource(this, type, name_offset, data_offset); AddObject(resource); return resource; } void PEResource::ReadFromFile(PEArchitecture &file, uint64_t root_address) { if (has_name()) { // name_offset is a string if (!file.AddressSeek(root_address + (name_offset_ & ~IMAGE_RESOURCE_NAME_IS_STRING))) throw std::runtime_error("Format error"); uint16_t len = file.ReadWord(); os::unicode_string wname; wname.resize(len); if (!wname.empty()) file.Read(&wname[0], wname.size() * sizeof(os::unicode_char)); name_ = os::ToUTF8(wname); } else { // name_offset is an Id name_ = string_format("%d", name_offset_); } if (!file.AddressSeek(root_address + (data_offset_ & ~IMAGE_RESOURCE_DATA_IS_DIRECTORY))) throw std::runtime_error("Format error"); if (is_directory()) { // read resource directory IMAGE_RESOURCE_DIRECTORY_ENTRY dir_entry; size_t i; file.Read(&data_.dir, sizeof(data_.dir)); for (i = 0; i < static_cast(data_.dir.NumberOfIdEntries + data_.dir.NumberOfNamedEntries); i++) { file.Read(&dir_entry, sizeof(dir_entry)); Add(type_, dir_entry.u.Name, dir_entry.u2.OffsetToData); } for (i = 0; i < count(); i++) { item(i)->ReadFromFile(file, root_address); } } else { // read resource item file.Read(&data_.item, sizeof(data_.item)); address_ = file.image_base() + data_.item.OffsetToData; } } void PEResource::WriteHeader(Data &data) { size_t i; if (is_directory()) { // write resource directory data_offset_ = (uint32_t)(data.size() | IMAGE_RESOURCE_DATA_IS_DIRECTORY); data.WriteDWord(entry_offset_ + sizeof(uint32_t), data_offset_); data_.dir.NumberOfIdEntries = 0; data_.dir.NumberOfNamedEntries = 0; for (i = 0; i < count(); i++) { if (item(i)->has_name()) { data_.dir.NumberOfNamedEntries++; } else { data_.dir.NumberOfIdEntries++; } } data.PushBuff(&data_.dir, sizeof(data_.dir)); for (i = 0; i < static_cast(data_.dir.NumberOfIdEntries + data_.dir.NumberOfNamedEntries); i++) { item(i)->WriteEntry(data); } } else { // write resource item data_entry_offset_ = data.size(); data.WriteDWord(entry_offset_ + sizeof(uint32_t), (uint32_t)data_entry_offset_); data.PushBuff(&data_.item, sizeof(data_.item)); } } void PEResource::WriteHeader(IFunction &data) { size_t i, size; IntelFunction &func = reinterpret_cast(data); size = 0; for (i = 0; i < func.count(); i++) { IntelCommand *command = func.item(i); size += OperandSizeToValue(command->operand(0).size); } if (is_directory()) { // write resource directory func.item(entry_offset_ + 1)->set_operand_value(0, size | IMAGE_RESOURCE_DATA_IS_DIRECTORY); data_.dir.NumberOfIdEntries = 0; data_.dir.NumberOfNamedEntries = 0; for (i = 0; i < count(); i++) { if (item(i)->has_name()) { data_.dir.NumberOfNamedEntries++; } else { data_.dir.NumberOfIdEntries++; } } func.AddCommand(osDWord, data_.dir.NumberOfNamedEntries); func.AddCommand(osDWord, data_.dir.NumberOfIdEntries); for (i = 0; i < static_cast(data_.dir.NumberOfIdEntries + data_.dir.NumberOfNamedEntries); i++) { item(i)->WriteEntry(data); } } else { // write resource item func.item(entry_offset_ + 1)->set_operand_value(0, size); data_entry_offset_ = func.count(); func.AddCommand(osDWord, 0); func.AddCommand(osDWord, data_.item.Size); func.AddCommand(osDWord, data_.item.CodePage); func.AddCommand(osDWord, data_.item.Reserved); } } void PEResource::WriteEntry(Data &data) { IMAGE_RESOURCE_DIRECTORY_ENTRY dir_entry; entry_offset_ = data.size(); dir_entry.u.Name = name_offset_; dir_entry.u2.OffsetToData = data_offset_; data.PushBuff(&dir_entry, sizeof(dir_entry)); } void PEResource::WriteEntry(IFunction &data) { IntelFunction &func = reinterpret_cast(data); entry_offset_ = func.count(); func.AddCommand(osDWord, name_offset_); func.AddCommand(osDWord, 0); } void PEResource::WriteName(Data &data) { if (!has_name()) return; name_offset_ = (uint32_t)(data.size() | IMAGE_RESOURCE_NAME_IS_STRING); data.WriteDWord(entry_offset_, name_offset_); os::unicode_string wname = os::FromUTF8(name_); data.PushWord(static_cast(wname.size())); data.PushBuff(wname.c_str(), wname.size() * sizeof(os::unicode_char)); } void PEResource::WriteName(IFunction &data, size_t root_index, uint32_t key) { if (!has_name()) return; IntelFunction &func = reinterpret_cast(data); size_t i, size; size = 0; for (i = root_index; i < func.count(); i++) { IntelCommand *command = func.item(i); size += (command->type() == cmDB) ? command->dump_size() : OperandSizeToValue(command->operand(0).size); } func.item(entry_offset_)->set_operand_value(0, size | IMAGE_RESOURCE_NAME_IS_STRING); os::unicode_string unicode_name = os::FromUTF8(name_); const os::unicode_char *p = unicode_name.c_str(); Data str; for (size_t i = 0; i < unicode_name.size() + 1; i++) { str.PushWord(static_cast(p[i] ^ (_rotl32(key, static_cast(i)) + i))); } func.AddCommand(str); } size_t PEResource::WriteData(Data &data, PEArchitecture &file) { if (is_directory()) return -1; if (!file.AddressSeek(address())) throw std::runtime_error("Invalid data address"); // resource data must be aligned size_t new_size = data.size(); new_size = AlignValue(new_size, OperandSizeToValue(file.cpu_address_size())); for (size_t i = data.size(); i < new_size; i++) { data.PushByte(0); } std::vector buf; buf.resize(data_.item.Size); file.Read(buf.data(), buf.size()); data.WriteDWord(data_entry_offset_, static_cast(data.size())); data.PushBuff(buf.data(), buf.size()); return data_entry_offset_; } void PEResource::WriteData(IFunction &func, PEArchitecture &file, uint32_t key) { if (is_directory() || !data_.item.Size) return; if (!file.AddressSeek(address())) throw std::runtime_error("Invalid data address"); std::vector buf; buf.resize(data_.item.Size); file.Read(buf.data(), buf.size()); Data d; for (size_t i = 0; i < buf.size(); i++) { d.PushByte(buf[i] ^ static_cast(_rotl32(key, static_cast(i)) + i)); } ICommand *command = func.AddCommand(d); command->include_option(roCreateNewBlock); CommandLink *link = func.item(data_entry_offset_)->AddLink(0, ltOffset, command); link->set_sub_value(file.image_base()); } bool PEResource::need_store() const { switch (type_) { case rtIcon: case rtGroupIcon: case rtVersionInfo: case rtManifest: case rtMessageTable: case rtHTML: return true; case rtUnknown: const IResource *resource = this; while (resource->owner() && resource->owner()->type() != (uint32_t)-1) { resource = resource->owner(); } std::string tmp = resource->name(); std::transform(tmp.begin(), tmp.end(), tmp.begin(), toupper); return (tmp.compare("\"TYPELIB\"") == 0 || tmp.compare("\"REGISTRY\"") == 0 || tmp.compare("\"MUI\"") == 0); } return false; } std::string PEResource::id() const { std::string res; const PEResource *resource = this; while (resource->owner()) { res = resource->name() + (res.empty() ? "" : "\\") + res; resource = reinterpret_cast(resource->owner()); } return res; } /** * PEResourceList */ PEResourceList::PEResourceList(PEArchitecture *owner) : BaseResourceList(owner), store_size_(0) { memset(&dir_, 0, sizeof(dir_)); } PEResourceList::PEResourceList(PEArchitecture *owner, const PEResourceList &src) : BaseResourceList(owner, src) { dir_ = src.dir_; store_size_ = src.store_size_; } PEResource *PEResourceList::item(size_t index) const { return reinterpret_cast(IResourceList::item(index)); } PEResourceList *PEResourceList::Clone(PEArchitecture *owner) const { PEResourceList *list = new PEResourceList(owner, *this); return list; } PEResource *PEResourceList::Add(PEResourceType type, uint32_t name_offset, uint32_t data_offset) { PEResource *resource = new PEResource(this, type, name_offset, data_offset); AddObject(resource); return resource; } void PEResourceList::ReadFromFile(PEArchitecture &file, PEDirectory &directory) { if (!directory.address()) return; if (!file.AddressSeek(directory.address())) throw std::runtime_error("Format error"); size_t i; IMAGE_RESOURCE_DIRECTORY_ENTRY dir_entry; file.Read(&dir_, sizeof(dir_)); for (i = 0; i < static_cast(dir_.NumberOfNamedEntries) + static_cast(dir_.NumberOfIdEntries); i++) { file.Read(&dir_entry, sizeof(dir_entry)); Add(dir_entry.u.s.NameIsString ? rtUnknown : static_cast(dir_entry.u.Id), dir_entry.u.Name, dir_entry.u2.OffsetToData); } for (i = 0; i < count(); i++) { PEResource *resource = item(i); resource->ReadFromFile(file, directory.address()); switch (resource->type()) { case rtCursor: resource->set_name("Cursor"); break; case rtBitmap: resource->set_name("Bitmap"); break; case rtIcon: resource->set_name("Icon"); break; case rtMenu: resource->set_name("Menu"); break; case rtDialog: resource->set_name("Dialog"); break; case rtStringTable: resource->set_name("String Table"); break; case rtFontDir: resource->set_name("Font Directory"); break; case rtFont: resource->set_name("Font"); break; case rtAccelerators: resource->set_name("Accelerators"); break; case rtRCData: resource->set_name("RCData"); break; case rtMessageTable: resource->set_name("Message Table"); break; case rtGroupCursor: resource->set_name("Cursor Group"); break; case rtGroupIcon: resource->set_name("Icon Group"); break; case rtVersionInfo: resource->set_name("Version Info"); break; case rtDlgInclude: resource->set_name("DlgInclude"); break; case rtPlugPlay: resource->set_name("Plug Play"); break; case rtVXD: resource->set_name("VXD"); break; case rtAniCursor: resource->set_name("Animated Cursor"); break; case rtAniIcon: resource->set_name("Animated Icon"); break; case rtHTML: resource->set_name("HTML"); break; case rtManifest: resource->set_name("Manifest"); break; case rtDialogInit: resource->set_name("Dialog Init"); break; case rtToolbar: resource->set_name("Toolbar"); break; } } } void PEResourceList::Compile(PEArchitecture &file, bool for_packing) { std::vector list; size_t i, j, c, pos; PEResource *resource; data_.clear(); link_list_.clear(); // create resource list for (i = 0; i < count(); i++) { list.push_back(item(i)); } for (i = 0; i < list.size(); i++) { resource = list[i]; for (j = 0; j < resource->count(); j++) { list.push_back(resource->item(j)); } } // write root directory dir_.NumberOfIdEntries = 0; dir_.NumberOfNamedEntries = 0; for (i = 0; i < count(); i++) { if (item(i)->has_name()) { dir_.NumberOfNamedEntries++; } else { dir_.NumberOfIdEntries++; } } data_.PushBuff(&dir_, sizeof(dir_)); for (i = 0; i < static_cast(dir_.NumberOfIdEntries + dir_.NumberOfNamedEntries); i++) { item(i)->WriteEntry(data_); } // write items for (i = 0; i < list.size(); i++) { list[i]->WriteHeader(data_); } for (i = 0; i < list.size(); i++) { list[i]->WriteName(data_); } store_size_ = 0; c = for_packing ? 2 : 1; for (j = 0; j < c; j++) { for (i = 0; i < list.size(); i++) { resource = list[i]; if (for_packing) { if (resource->excluded_from_packing() || resource->need_store()) { if (j != 0) continue; } else { if (j == 0) continue; } } pos = resource->WriteData(data_, file); if (pos != (size_t)-1) link_list_.push_back(pos); } if (j == 0) store_size_ = data_.size(); } } size_t PEResourceList::WriteToFile(PEArchitecture &file, uint64_t address) { size_t i, pos; Data out = data_; uint32_t rva = static_cast(address - file.image_base()); for (i = 0; i < link_list_.size(); i++) { pos = link_list_[i]; out.WriteDWord(pos, out.ReadDWord(pos) + rva); } return file.Write(out.data(), (store_size_) ? store_size_ : out.size()); } void PEResourceList::WritePackData(Data &data) { data.PushBuff(data_.data() + store_size_, data_.size() - store_size_); } /** * PERuntimeFunction */ PERuntimeFunction::PERuntimeFunction(PERuntimeFunctionList *owner, uint64_t address, uint64_t begin, uint64_t end, uint64_t unwind_address) : BaseRuntimeFunction(owner), address_(address), begin_(begin), end_(end), unwind_address_(unwind_address) { } PERuntimeFunction::PERuntimeFunction(PERuntimeFunctionList *owner, const PERuntimeFunction &src) : BaseRuntimeFunction(owner) { address_ = src.address_; begin_ = src.begin_; end_ = src.end_; unwind_address_ = src.unwind_address_; } PERuntimeFunction *PERuntimeFunction::Clone(IRuntimeFunctionList *owner) const { PERuntimeFunction *func = new PERuntimeFunction(reinterpret_cast(owner), *this); return func; } void PERuntimeFunction::Rebase(uint64_t delta_base) { address_ += delta_base; begin_ += delta_base; end_ += delta_base; unwind_address_ += delta_base; } void PERuntimeFunction::Parse(IArchitecture &file, IFunction &dest) { union UNWIND_INFO_HELPER { UNWIND_INFO info; uint32_t value; }; IntelFunction &func = reinterpret_cast(dest); uint64_t address = address_; if (!file.AddressSeek(address) || func.GetCommandByAddress(address)) return; size_t i; size_t c = func.count(); IntelCommand *command; CommandLink *link; uint64_t image_base = file.image_base(); command = func.Add(address); command->set_comment(CommentInfo(ttComment, "Begin")); command->ReadValueFromFile(file, osDWord); address = command->next_address(); command = func.Add(address); command->set_comment(CommentInfo(ttComment, "End")); command->ReadValueFromFile(file, osDWord); address = command->next_address(); command = func.Add(address); command->set_comment(CommentInfo(ttComment, "UnwindData")); address = command->ReadValueFromFile(file, osDWord); if (address) { address += image_base; link = command->AddLink(0, ltOffset, address); link->set_sub_value(image_base); } for (i = c; i < func.count(); i++) { command = func.item(i); command->exclude_option(roClearOriginalCode); command->exclude_option(roNeedCompile); } if (address) { command = func.GetCommandByAddress(address); if (command) { UNWIND_INFO_HELPER unwind_info_helper; unwind_info_helper.value = static_cast(command->dump_value(0, osDWord)); UNWIND_INFO unwind_info = unwind_info_helper.info; func.function_info_list()->Add(begin(), end(), btImageBase, 0, unwind_info.SizeOfProlog, unwind_info.FrameRegister ? unwind_info.FrameRegister : 0xff, this, command); } else if (file.AddressSeek(address)) { UNWIND_INFO_HELPER unwind_info_helper; command = func.Add(address); unwind_info_helper.value = static_cast(command->ReadValueFromFile(file, osDWord)); UNWIND_INFO unwind_info = unwind_info_helper.info; command->set_comment(CommentInfo(ttComment, string_format("Version: %.2X; Flags: %.2X; SizeOfProlog: %.2X; CountOfCodes: %.2X; FrameRegister: %.2X; FrameOffset: %.2X", unwind_info.Version, unwind_info.Flags, unwind_info.SizeOfProlog, unwind_info.CountOfCodes, unwind_info.FrameRegister, unwind_info.FrameOffset))); command->set_alignment(OperandSizeToValue(osDWord)); command->include_option(roCreateNewBlock); address = command->next_address(); func.function_info_list()->Add(begin(), end(), btImageBase, 0, unwind_info.SizeOfProlog, unwind_info.FrameRegister ? unwind_info.FrameRegister : 0xff, this, command); for (i = 0; i < unwind_info.CountOfCodes; i++) { command = func.Add(address); UNWIND_CODE unwind_code; bool is_epilog = false; file.Read(&unwind_code, sizeof(unwind_code)); Data data; data.InsertBuff(0, &unwind_code, sizeof(unwind_code)); switch (unwind_code.UnwindOp) { case UWOP_PUSH_NONVOL: command->set_comment(CommentInfo(ttComment, "UWOP_PUSH_NONVOL")); break; case UWOP_ALLOC_LARGE: data.PushWord(file.ReadWord()); i++; if (unwind_code.OpInfo == 1) { data.PushWord(file.ReadWord()); i++; } command->set_comment(CommentInfo(ttComment, "UWOP_ALLOC_LARGE")); break; case UWOP_ALLOC_SMALL: command->set_comment(CommentInfo(ttComment, "UWOP_ALLOC_SMALL")); break; case UWOP_SET_FPREG: command->set_comment(CommentInfo(ttComment, "UWOP_SET_FPREG")); break; case UWOP_SAVE_NONVOL: data.PushWord(file.ReadWord()); i++; command->set_comment(CommentInfo(ttComment, "UWOP_SAVE_NONVOL")); break; case UWOP_SAVE_NONVOL_FAR: data.PushWord(file.ReadWord()); data.PushWord(file.ReadWord()); i += 2; command->set_comment(CommentInfo(ttComment, "UWOP_SAVE_NONVOL_FAR")); break; case UWOP_EPILOG: if (unwind_info.Version == 2) { is_epilog = true; if (unwind_code.CodeOffset) { uint64_t range_begin, range_end; if ((unwind_code.OpInfo & 1)) { range_begin = end() - unwind_code.CodeOffset; range_end = end(); } else { UNWIND_CODE next_code; file.Read(&next_code, sizeof(next_code)); data.PushWord(next_code.FrameOffset); i++; range_begin = end() - ((next_code.OpInfo << 8) + next_code.CodeOffset); range_end = range_begin + unwind_code.CodeOffset; } func.range_list()->Add(range_begin, range_end, NULL, NULL, command); } command->set_comment(CommentInfo(ttComment, "UWOP_EPILOG")); } else { data.PushWord(file.ReadWord()); i++; command->set_comment(CommentInfo(ttComment, "UWOP_SAVE_XMM128")); } break; case UWOP_SAVE_XMM128: data.PushWord(file.ReadWord()); i++; command->set_comment(CommentInfo(ttComment, "UWOP_SAVE_XMM128")); break; case UWOP_SAVE_XMM128_FAR: data.PushWord(file.ReadWord()); data.PushWord(file.ReadWord()); i += 2; command->set_comment(CommentInfo(ttComment, "UWOP_SAVE_XMM128_FAR")); break; case UWOP_PUSH_MACHFRAME: command->set_comment(CommentInfo(ttComment, "UWOP_PUSH_MACHFRAME")); break; } command->Init(data); address = command->next_address(); if (!is_epilog) func.range_list()->Add(begin(), begin() + unwind_code.CodeOffset, NULL, NULL, NULL); } if (unwind_info.CountOfCodes & 1) { // align to DWORD command = func.Add(address); command->ReadArray(file, sizeof(UNWIND_CODE)); address = command->next_address(); } IntelCommand *handler_data_command = NULL; if (unwind_info.Flags & UNW_FLAG_CHAININFO) { command = func.Add(address); command->set_comment(CommentInfo(ttComment, "Begin")); command->ReadValueFromFile(file, osDWord); address = command->next_address(); command = func.Add(address); command->set_comment(CommentInfo(ttComment, "End")); command->ReadValueFromFile(file, osDWord); address = command->next_address(); command = func.Add(address); command->set_comment(CommentInfo(ttComment, "UnwindData")); address = command->ReadValueFromFile(file, osDWord); if (address) { address += image_base; link = command->AddLink(0, ltOffset, address); link->set_sub_value(image_base); } } else if (unwind_info.Flags & (UNW_FLAG_EHANDLER | UNW_FLAG_UHANDLER)) { command = func.Add(address); command->set_comment(CommentInfo(ttComment, "Handler")); address = command->ReadValueFromFile(file, osDWord); if (address) { address += image_base; CommentInfo res; res.type = ttNone; MapFunction *map_function = file.map_function_list()->GetFunctionByAddress(address); if (map_function) { res.value = string_format("%c %s", 3, map_function->name().c_str()); switch (map_function->type()) { case otString: res.type = ttString; break; case otExport: res.type = ttExport; break; default: res.type = ttFunction; break; } command->set_comment(res); } link = command->AddLink(0, ltOffset, address); link->set_sub_value(image_base); } address = command->next_address(); handler_data_command = func.Add(address); handler_data_command->ReadValueFromFile(file, osDWord); handler_data_command->set_comment(CommentInfo(ttComment, "HandlerData")); } for (i = c; i < func.count(); i++) { command = func.item(i); command->exclude_option(roClearOriginalCode); } if (handler_data_command) { uint32_t handler_data = static_cast(handler_data_command->operand(0).value); if (func.ParseCxxSEH(file, handler_data + image_base)) { link = handler_data_command->AddLink(0, ltOffset, handler_data + image_base); link->set_sub_value(image_base); address = handler_data_command->next_address(); } else if (func.ParseScopeSEH(file, handler_data_command->next_address(), handler_data)) { handler_data_command->set_comment(CommentInfo(ttComment, "Count")); address = handler_data_command->next_address() + handler_data * 0x10; } else if (func.ParseCompressedCxxSEH(file, handler_data + image_base, begin())) { link = handler_data_command->AddLink(0, ltOffset, handler_data + image_base); link->set_sub_value(image_base); address = handler_data_command->next_address(); } else address = 0; if (address) { if (!func.GetCommandByAddress(address) && !file.runtime_function_list()->GetFunctionByUnwindAddress(address) && file.AddressSeek(address)) { command = func.Add(address); uint32_t value = static_cast(command->ReadValueFromFile(file, osDWord)); command->set_comment(CommentInfo(ttComment, string_format("EHandler: %.2X; UHandler: %.2X; HasAlignment: %.2X; CookieOffset: %.8X", value & 1, (value & 2) >> 1, (value & 4) >> 2, value & 0xFFFFFFF8))); command->exclude_option(roClearOriginalCode); if (value & 4) { command = func.Add(command->next_address()); command->set_comment(CommentInfo(ttComment, "AlignedBaseOffset")); command->ReadValueFromFile(file, osDWord); command->exclude_option(roClearOriginalCode); command = func.Add(command->next_address()); command->set_comment(CommentInfo(ttComment, "Alignment")); command->ReadValueFromFile(file, osDWord); command->exclude_option(roClearOriginalCode); } } } } } } } /** * PERuntimeFunctionList */ PERuntimeFunctionList::PERuntimeFunctionList() : BaseRuntimeFunctionList(), address_(0) { } PERuntimeFunctionList::PERuntimeFunctionList(const PERuntimeFunctionList &src) : BaseRuntimeFunctionList(src), address_(0) { address_ = src.address_; } PERuntimeFunctionList *PERuntimeFunctionList::Clone() const { PERuntimeFunctionList *list = new PERuntimeFunctionList(*this); return list; } PERuntimeFunction *PERuntimeFunctionList::Add(uint64_t address, uint64_t begin, uint64_t end, uint64_t unwind_address, IRuntimeFunction *source, const std::vector &call_frame_instructions) { PERuntimeFunction *func = new PERuntimeFunction(this, address, begin, end, unwind_address); AddObject(func); return func; } void PERuntimeFunctionList::ReadFromFile(PEArchitecture &file, PEDirectory &directory) { if (!directory.address()) return; if (!file.AddressSeek(directory.address())) throw std::runtime_error("Format error"); address_ = directory.address(); uint64_t image_base = file.image_base(); RUNTIME_FUNCTION data; std::vector call_frame_instructions; for (size_t i = 0; i < directory.size(); i += sizeof(data)) { file.Read(&data, sizeof(data)); Add(address_ + i, data.BeginAddress + image_base, data.EndAddress + image_base, data.UnwindData + image_base, 0, call_frame_instructions); } } size_t PERuntimeFunctionList::WriteToFile(PEArchitecture &file) { Sort(); size_t res = 0; uint64_t image_base = file.image_base(); RUNTIME_FUNCTION data; for (size_t i = 0; i < count(); i++) { PERuntimeFunction *runtime_function = item(i); data.BeginAddress = static_cast(runtime_function->begin() - image_base); data.EndAddress = static_cast(runtime_function->end() - image_base); data.UnwindData = static_cast(runtime_function->unwind_address() - image_base); res += file.Write(&data, sizeof(data)); } return res; } PERuntimeFunction *PERuntimeFunctionList::GetFunctionByAddress(uint64_t address) const { return reinterpret_cast(BaseRuntimeFunctionList::GetFunctionByAddress(address)); } PERuntimeFunction *PERuntimeFunctionList::item(size_t index) const { return reinterpret_cast(BaseRuntimeFunctionList::item(index)); } uint64_t PERuntimeFunctionList::RebaseDWord(IArchitecture &file, uint32_t delta_rva) { uint64_t pos = file.Tell(); uint64_t value = file.ReadDWord(); if (value > 1) { uint64_t address = file.AddressTell() - sizeof(uint32_t); IntelCommand *command = reinterpret_cast(file.function_list()->GetCommandByAddress(address, false)); if (command && command->type() == cmDD) { command->set_operand_value(0, command->operand(0).value + delta_rva); if (command->link()) command->link()->set_sub_value(command->link()->sub_value() - delta_rva); } file.Seek(pos); file.WriteDWord(static_cast(value) + delta_rva); value += file.image_base(); } return value; } void PERuntimeFunctionList::RebaseByFile(IArchitecture &file, uint64_t target_image_base, uint64_t delta_base) { if (!address_) return; uint32_t delta_rva = static_cast(file.image_base() + delta_base - target_image_base); std::set address_list; std::set handler_list; size_t i, j, k; for (i = 0; i < count(); i++) { PERuntimeFunction *func = item(i); if (!file.AddressSeek(func->unwind_address()) || address_list.find(func->unwind_address()) != address_list.end()) continue; address_list.insert(func->unwind_address()); union UNWIND_INFO_HELPER { UNWIND_INFO info; uint32_t value; }; UNWIND_INFO_HELPER unwind_info_helper; unwind_info_helper.value = file.ReadDWord(); UNWIND_INFO unwind_info = unwind_info_helper.info; size_t count_of_codes = unwind_info.CountOfCodes; if (count_of_codes & 1) { // align to DWORD count_of_codes++; } for (j = 0; j < count_of_codes; j++) { file.ReadWord(); } if (unwind_info.Flags & UNW_FLAG_CHAININFO) { RebaseDWord(file, delta_rva); RebaseDWord(file, delta_rva); RebaseDWord(file, delta_rva); } else if (unwind_info.Flags & (UNW_FLAG_EHANDLER | UNW_FLAG_UHANDLER)) { RebaseDWord(file, delta_rva); uint64_t handler_data_address = file.AddressTell(); uint32_t handler_data = file.ReadDWord(); bool is_cxx_handler = false; bool is_scope_table = false; if (file.AddressSeek(handler_data + file.image_base())) { uint32_t magic = file.ReadDWord(); if (magic == 0x19930520 || magic == 0x19930521 || magic == 0x19930522) is_cxx_handler = true; } if (!is_cxx_handler && file.AddressSeek(handler_data_address + sizeof(handler_data))) { is_scope_table = true; for (j = 0; j < handler_data; j++) { for (size_t k = 0; k < 4; k++) { uint64_t value = file.ReadDWord(); if (!value || (k == 2 && value == 1)) continue; if ((file.segment_list()->GetMemoryTypeByAddress(value + file.image_base()) & mtExecutable) == 0) { is_scope_table = false; break; } } if (!is_scope_table) break; } } if (is_cxx_handler) { file.AddressSeek(handler_data_address); RebaseDWord(file, delta_rva); handler_data_address = handler_data + file.image_base(); if (handler_list.find(handler_data_address) != handler_list.end()) continue; handler_list.insert(handler_data_address); file.AddressSeek(handler_data_address); file.ReadDWord(); uint32_t max_state = file.ReadDWord(); uint64_t unwind_map_entry = RebaseDWord(file, delta_rva); uint32_t try_blocks = file.ReadDWord(); uint64_t try_blocks_entry = RebaseDWord(file, delta_rva); uint32_t map_count = file.ReadDWord(); uint64_t map_entry = RebaseDWord(file, delta_rva); if (max_state && file.AddressSeek(unwind_map_entry)) { for (j = 0; j < max_state; j++) { file.ReadDWord(); RebaseDWord(file, delta_rva); } } if (try_blocks && file.AddressSeek(try_blocks_entry)) { for (j = 0; j < try_blocks; j++) { file.ReadDWord(); file.ReadDWord(); file.ReadDWord(); uint32_t catches = file.ReadDWord(); uint64_t catches_entry = RebaseDWord(file, delta_rva); uint64_t pos = file.Tell(); if (catches && file.AddressSeek(catches_entry)) { for (k = 0; k < catches; k++) { file.ReadDWord(); file.ReadDWord(); file.ReadDWord(); RebaseDWord(file, delta_rva); if (file.cpu_address_size() == osQWord) file.ReadDWord(); } file.Seek(pos); } } } if (map_count && file.AddressSeek(map_entry)) { for (j = 0; j < map_count; j++) { RebaseDWord(file, delta_rva); file.ReadDWord(); } } } else if (is_scope_table) { file.AddressSeek(handler_data_address + sizeof(handler_data)); for (j = 0; j < handler_data; j++) { RebaseDWord(file, delta_rva); RebaseDWord(file, delta_rva); RebaseDWord(file, delta_rva); RebaseDWord(file, delta_rva); } } } } address_ += delta_base; BaseRuntimeFunctionList::Rebase(delta_base); } void PERuntimeFunctionList::FreeByManager(MemoryManager &manager) { if (!address_) return; if (count()) manager.Add(address_, sizeof(RUNTIME_FUNCTION) * count()); } /** * PETLSDirectory */ PETLSDirectory::PETLSDirectory() : ReferenceList(), address_(0), start_address_of_raw_data_(0), end_address_of_raw_data_(0), address_of_index_(0), address_of_call_backs_(0), size_of_zero_fill_(0), characteristics_(0) { } PETLSDirectory *PETLSDirectory::Clone() const { PETLSDirectory *dir = new PETLSDirectory(*this); return dir; } PETLSDirectory::PETLSDirectory(const PETLSDirectory &src) : ReferenceList(src) { address_ = src.address_; start_address_of_raw_data_ = src.start_address_of_raw_data_; end_address_of_raw_data_ = src.end_address_of_raw_data_; address_of_index_ = src.address_of_index_; address_of_call_backs_ = src.address_of_call_backs_; size_of_zero_fill_ = src.size_of_zero_fill_; characteristics_ = src.characteristics_; } void PETLSDirectory::ReadFromFile(PEArchitecture &file, PEDirectory &directory) { if (!directory.address()) return; if (!file.AddressSeek(directory.address())) throw std::runtime_error("Format error"); address_ = directory.address(); if (file.cpu_address_size() == osDWord) { IMAGE_TLS_DIRECTORY32 tls; file.Read(&tls, sizeof(tls)); start_address_of_raw_data_ = tls.StartAddressOfRawData; end_address_of_raw_data_ = tls.EndAddressOfRawData; address_of_index_ = tls.AddressOfIndex; address_of_call_backs_ = tls.AddressOfCallBacks; size_of_zero_fill_ = tls.SizeOfZeroFill; characteristics_ = tls.Characteristics; } else { IMAGE_TLS_DIRECTORY64 tls; file.Read(&tls, sizeof(tls)); start_address_of_raw_data_ = tls.StartAddressOfRawData; end_address_of_raw_data_ = tls.EndAddressOfRawData; address_of_index_ = tls.AddressOfIndex; address_of_call_backs_ = tls.AddressOfCallBacks; size_of_zero_fill_ = tls.SizeOfZeroFill; characteristics_ = tls.Characteristics; } if (!address_of_call_backs_) return; if (!file.AddressSeek(address_of_call_backs_)) throw std::runtime_error("Format error"); size_t value_size = OperandSizeToValue(file.cpu_address_size()); uint64_t call_back = 0; while (true) { file.Read(&call_back, value_size); if (!call_back) break; Add(call_back, 0); } } void PETLSDirectory::FreeByManager(MemoryManager &manager) { if (!address_) return; PEArchitecture *file = reinterpret_cast(manager.owner()); size_t value_size = OperandSizeToValue(file->cpu_address_size()); manager.Add(address_, value_size * 4 + sizeof(uint32_t) * 2); for (size_t i = 0; i < 4; i++) { IFixup *fixup = file->fixup_list()->GetFixupByAddress(address_ + value_size * i); if (fixup) fixup->set_deleted(true); } if (address_of_call_backs_) { manager.Add(address_of_call_backs_, value_size * (count() + 1)); for (size_t i = 0; i < count(); i++) { IFixup *fixup = file->fixup_list()->GetFixupByAddress(address_of_call_backs_ + value_size * i); if (fixup) fixup->set_deleted(true); } } } /** * PEDebugData */ PEDebugData::PEDebugData(PEDebugDirectory *owner) : IObject(), owner_(owner), characteristics_(0), time_date_stamp_(0), major_version_(0), minor_version_(0), type_(0), size_(0), address_(0), offset_(0) { } PEDebugData::PEDebugData(PEDebugDirectory *owner, const PEDebugData &src) : IObject(), owner_(owner) { characteristics_ = src.characteristics_; time_date_stamp_ = src.time_date_stamp_; major_version_ = src.major_version_; minor_version_ = src.minor_version_; type_ = src.type_; size_ = src.size_; address_ = src.address_; offset_ = src.offset_; } PEDebugData::~PEDebugData() { if (owner_) owner_->RemoveObject(this); } PEDebugData *PEDebugData::Clone(PEDebugDirectory *owner) const { PEDebugData *data = new PEDebugData(owner, *this); return data; } void PEDebugData::ReadFromFile(PEArchitecture &file) { IMAGE_DEBUG_DIRECTORY data; file.Read(&data, sizeof(data)); characteristics_ = data.Characteristics; time_date_stamp_ = data.TimeDateStamp; major_version_ = data.MajorVersion; minor_version_ = data.MinorVersion; type_ = data.Type; size_ = data.SizeOfData; address_ = data.AddressOfRawData ? data.AddressOfRawData + file.image_base() : 0; offset_ = data.PointerToRawData; } void PEDebugData::WriteToFile(PEArchitecture &file) { IMAGE_DEBUG_DIRECTORY data; data.Characteristics = characteristics_; data.TimeDateStamp = time_date_stamp_; data.MajorVersion = major_version_; data.MinorVersion = minor_version_; data.Type = type_; data.SizeOfData = size_; data.AddressOfRawData = address_ ? static_cast(address_ - file.image_base()) : 0; data.PointerToRawData = offset_; file.Write(&data, sizeof(data)); } /** * PEDebugDirectory */ PEDebugDirectory::PEDebugDirectory() : ObjectList(), address_(0) { } PEDebugDirectory::PEDebugDirectory(const PEDebugDirectory &src) : ObjectList(src) { address_ = src.address_; for (size_t i = 0; i < src.count(); i++) { AddObject(src.item(i)->Clone(this)); } } PEDebugDirectory *PEDebugDirectory::Clone() const { PEDebugDirectory *res = new PEDebugDirectory(*this); return res; } PEDebugData *PEDebugDirectory::Add() { PEDebugData *data = new PEDebugData(this); AddObject(data); return data; } void PEDebugDirectory::ReadFromFile(PEArchitecture &file, PEDirectory &directory) { if (!directory.address()) return; if (!file.AddressSeek(directory.address())) throw std::runtime_error("Format error"); address_ = directory.address(); size_t c = directory.size() / sizeof(IMAGE_DEBUG_DIRECTORY); for (size_t i = 0; i < c; i++) { PEDebugData *data = Add(); data->ReadFromFile(file); } } void PEDebugDirectory::WriteToFile(PEArchitecture &file) { for (size_t i = 0; i < count(); i++) { item(i)->WriteToFile(file); } } void PEDebugDirectory::FreeByManager(MemoryManager &manager) const { if (!address_) return; manager.Add(address_, count() * sizeof(IMAGE_DEBUG_DIRECTORY)); for (size_t i = 0; i < count(); i++) { PEDebugData *data = item(i); if (data->address() && data->size()) manager.Add(data->address(), data->size()); } } /** * PEFile */ PEFile::PEFile(ILog *log) : IFile(log), runtime_(NULL) { } PEFile::PEFile(const PEFile &src, const char *file_name) : IFile(src, file_name), runtime_(NULL) { for (size_t i = 0; i < src.count(); i++) AddObject(src.item(i)->Clone(this)); } PEFile::~PEFile() { delete runtime_; } OpenStatus PEFile::ReadHeader(uint32_t open_mode) { PEArchitecture *arch = new PEArchitecture(this, 0, size()); AddObject(arch); return arch->ReadFromFile(open_mode); } std::string PEFile::format_name() const { return std::string("PE"); } bool PEFile::WriteHeader() { for (size_t i = 0 ; i < count(); i++) { if (!item(i)->WriteToFile()) return false; } return true; } PEFile *PEFile::Clone(const char *file_name) const { PEFile *file = new PEFile(*this, file_name); return file; } bool PEFile::Compile(CompileOptions &options) { const ResourceInfo runtime_info[] = { {win_runtime32_dll_file, sizeof(win_runtime32_dll_file), win_runtime32_dll_code}, {win_runtime64_dll_file, sizeof(win_runtime64_dll_file), win_runtime64_dll_code}, {win_runtime32_sys_file, sizeof(win_runtime32_sys_file), win_runtime32_sys_code}, {win_runtime64_sys_file, sizeof(win_runtime64_sys_file), win_runtime64_sys_code}, {dotnet20_runtime32_dll_file, sizeof(dotnet20_runtime32_dll_file), dotnet20_runtime32_dll_code}, {dotnet20_runtime64_dll_file, sizeof(dotnet20_runtime64_dll_file), dotnet20_runtime64_dll_code}, {dotnet40_runtime32_dll_file, sizeof(dotnet40_runtime32_dll_file), dotnet40_runtime32_dll_code}, {dotnet40_runtime64_dll_file, sizeof(dotnet40_runtime64_dll_file), dotnet40_runtime64_dll_code}, {netstandard_runtime32_dll_file, sizeof(netstandard_runtime32_dll_file), netstandard_runtime32_dll_code}, {netstandard_runtime64_dll_file, sizeof(netstandard_runtime64_dll_file), netstandard_runtime64_dll_code}, {netcore_runtime32_dll_file, sizeof(netcore_runtime32_dll_file), netcore_runtime32_dll_code}, {netcore_runtime64_dll_file, sizeof(netcore_runtime64_dll_file), netcore_runtime64_dll_code}, }; size_t index; if (count() > 1) { FrameworkInfo info = reinterpret_cast(item(1))->command_list()->framework(); switch (info.type) { case fwFramework: index = (info.version.major >= 4) ? 6 : 4; break; case fwStandard: index = 8; break; default: index = 10; break; } } else index = (arch_pe()->image_type() == itDriver) ? 2 : 0; ResourceInfo info = runtime_info[index + (arch_pe()->cpu_address_size() == osDWord ? 0 : 1)]; if (info.size > 1) { runtime_ = new PEFile(NULL); if (!runtime_->OpenResource(info.file, info.size, true) || count() != runtime_->count()) throw std::runtime_error("Runtime error at OpenResource"); Buffer buffer(info.code); IArchitecture *arch = runtime_->item(runtime_->count() - 1); arch->ReadFromBuffer(buffer); for (size_t i = 0; i < arch->function_list()->count(); i++) { arch->function_list()->item(i)->set_from_runtime(true); } for (size_t i = 0; i < arch->import_list()->count(); i++) { IImport *import = arch->import_list()->item(i); for (size_t j = 0; j < import->count(); j++) { import->item(j)->include_option(ioFromRuntime); } } } return IFile::Compile(options); } std::string PEFile::version() const { struct VERSION_INFO { uint16_t wLength; uint16_t wValueLength; uint16_t wType; uint16_t szKey[1]; }; if (count() == 1) { IArchitecture *file = item(0); IResource *resource = file->resource_list()->GetResourceByType(rtVersionInfo); if (resource) resource = resource->GetResourceByName("1"); if (resource && resource->count()) { resource = resource->item(0); if (resource->size() && file->AddressSeek(resource->address())) { uint8_t *data = new uint8_t[resource->size()]; file->Read(data, resource->size()); size_t len = 0; while (reinterpret_cast(data)->szKey[len]) len++; VS_FIXEDFILEINFO *file_info = reinterpret_cast(data + AlignValue(offsetof(VERSION_INFO, szKey) + (len + 1) * sizeof(uint16_t), sizeof(uint32_t))); std::string res = string_format("%d.%d.%d.%d", static_cast(file_info->dwFileVersionMS >> 16), static_cast(file_info->dwFileVersionMS), static_cast(file_info->dwFileVersionLS >> 16), static_cast(file_info->dwFileVersionLS)); delete [] data; return res; } } } return IFile::version(); } bool PEFile::is_executable() const { #ifdef __unix__ return false; #elif __APPLE__ return false; #else for (size_t i = 0; i < count(); i++) { if (item(i)->is_executable()) return true; } #endif return false; } uint32_t PEFile::disable_options() const { uint32_t res = 0; if (count() == 1) { PEArchitecture *arch = arch_pe(); if (arch->segment_alignment() < 0x1000) res |= cpPack; if (arch->image_type() != itExe) res |= cpStripFixups; if (arch->image_type() == itDriver) { res |= cpResourceProtection; res |= cpVirtualFiles; } } else { res |= cpStripFixups; } return res; } bool PEFile::GetCheckSum(uint32_t *check_sum) { Flush(); return os::FileGetCheckSum(file_name(true).c_str(), check_sum); } std::string PEFile::exec_command() const { if (count() > 1 && reinterpret_cast(item(1))->command_list()->framework().type == fwCore) return "dotnet.exe"; return std::string(); } /** * PEArchitecture */ PEArchitecture::PEArchitecture(PEFile *owner, uint64_t offset, uint64_t size) : BaseArchitecture(owner, offset, size), function_list_(NULL), virtual_machine_list_(NULL), cpu_(0), cpu_address_size_(osDWord), time_stamp_(0), entry_point_(0), image_base_(0), header_offset_(0), header_size_(0), segment_alignment_(0), file_alignment_(0), resource_section_(NULL), fixup_section_(NULL), optimized_section_count_(0), image_type_(itExe), characterictics_(0), check_sum_(0), low_resize_header_(0), resize_header_(0), operating_system_version_(0), subsystem_version_(0), dll_characteristics_(0) { directory_list_ = new PEDirectoryList(this); segment_list_ = new PESegmentList(this); section_list_ = new PESectionList(this); import_list_ = new PEImportList(this); export_list_ = new PEExportList(this); fixup_list_ = new PEFixupList(); relocation_list_ = new PERelocationList(); resource_list_ = new PEResourceList(this); load_config_directory_ = new PELoadConfigDirectory(); runtime_function_list_ = new PERuntimeFunctionList(); tls_directory_ = new PETLSDirectory(); debug_directory_ = new PEDebugDirectory(); delay_import_list_ = new PEDelayImportList(); } PEArchitecture::PEArchitecture(PEFile *owner, const PEArchitecture &src) : BaseArchitecture(owner, src), function_list_(NULL), virtual_machine_list_(NULL), resource_section_(NULL), fixup_section_(NULL) { size_t i, j, k; cpu_ = src.cpu_; cpu_address_size_ = src.cpu_address_size_; entry_point_ = src.entry_point_; image_base_ = src.image_base_; header_offset_ = src.header_offset_; header_size_ = src.header_size_; segment_alignment_ = src.segment_alignment_; file_alignment_ = src.file_alignment_; characterictics_ = src.characterictics_; image_type_ = src.image_type_; check_sum_ = src.check_sum_; low_resize_header_ = src.low_resize_header_; resize_header_ = src.resize_header_; operating_system_version_ = src.operating_system_version_; subsystem_version_ = src.subsystem_version_; dll_characteristics_ = src.dll_characteristics_; time_stamp_ = src.time_stamp_; directory_list_ = src.directory_list_->Clone(this); segment_list_ = src.segment_list_->Clone(this); section_list_ = src.section_list_->Clone(this); import_list_ = src.import_list_->Clone(this); export_list_ = src.export_list_->Clone(this); fixup_list_ = src.fixup_list_->Clone(); relocation_list_ = src.relocation_list_->Clone(); resource_list_ = src.resource_list_->Clone(this); load_config_directory_ = src.load_config_directory_->Clone(); runtime_function_list_ = src.runtime_function_list_->Clone(); tls_directory_ = src.tls_directory_->Clone(); debug_directory_ = src.debug_directory_->Clone(); delay_import_list_ = src.delay_import_list_->Clone(); if (src.function_list_) function_list_ = src.function_list_->Clone(this); if (src.virtual_machine_list_) virtual_machine_list_ = src.virtual_machine_list_->Clone(); if (src.resource_section_) resource_section_ = segment_list_->item(src.segment_list_->IndexOf(src.resource_section_)); if (src.fixup_section_) fixup_section_ = segment_list_->item(src.segment_list_->IndexOf(src.fixup_section_)); for (i = 0; i < src.section_list()->count(); i++) { PESegment *segment = src.section_list()->item(i)->parent(); if (segment) section_list_->item(i)->set_parent(segment_list_->item(src.segment_list_->IndexOf(segment))); } for (i = 0; i < src.import_list_->count(); i++) { PEImport *import = src.import_list_->item(i); for (j = 0; j < import->count(); j++) { MapFunction *map_function = import->item(j)->map_function(); if (map_function) import_list_->item(i)->item(j)->set_map_function(map_function_list()->item(src.map_function_list()->IndexOf(map_function))); } } if (function_list_) { for (i = 0; i < function_list_->count(); i++) { IntelFunction *func = reinterpret_cast(function_list_->item(i)); for (j = 0; j < func->count(); j++) { IntelCommand *command = func->item(j); if (command->seh_handler()) command->set_seh_handler(seh_handler_list()->GetHandlerByAddress(command->address())); for (k = 0; k < 3; k++) { IntelOperand operand = command->operand(k); if (operand.type == otNone) break; if (operand.fixup) command->set_operand_fixup(k, fixup_list_->GetFixupByAddress(operand.fixup->address())); if (operand.relocation) command->set_operand_relocation(k, relocation_list_->GetRelocationByAddress(operand.relocation->address())); } } for (j = 0; j < func->function_info_list()->count(); j++) { FunctionInfo *info = func->function_info_list()->item(j); if (info->source()) info->set_source(runtime_function_list_->GetFunctionByAddress(info->source()->begin())); } } } } PEArchitecture::~PEArchitecture() { delete export_list_; delete import_list_; delete segment_list_; delete section_list_; delete directory_list_; delete fixup_list_; delete relocation_list_; delete resource_list_; delete load_config_directory_; delete runtime_function_list_; delete function_list_; delete virtual_machine_list_; delete tls_directory_; delete debug_directory_; delete delay_import_list_; } PEArchitecture *PEArchitecture::Clone(IFile *file) const { PEArchitecture *arch = new PEArchitecture(dynamic_cast(file), *this); return arch; } std::string PEArchitecture::name() const { switch (cpu_) { case IMAGE_FILE_MACHINE_I386: return std::string("i386"); case IMAGE_FILE_MACHINE_R3000: case IMAGE_FILE_MACHINE_R4000: case IMAGE_FILE_MACHINE_R10000: case IMAGE_FILE_MACHINE_MIPS16: case IMAGE_FILE_MACHINE_MIPSFPU: case IMAGE_FILE_MACHINE_MIPSFPU16: return std::string("mips"); case IMAGE_FILE_MACHINE_WCEMIPSV2: return std::string("mips_wce_v2"); case IMAGE_FILE_MACHINE_ALPHA: return std::string("alpha_axp"); case IMAGE_FILE_MACHINE_SH3: case IMAGE_FILE_MACHINE_SH3DSP: return std::string("sh3"); case IMAGE_FILE_MACHINE_SH3E: return std::string("sh3e"); case IMAGE_FILE_MACHINE_SH4: return std::string("sh4"); case IMAGE_FILE_MACHINE_SH5: return std::string("sh5"); case IMAGE_FILE_MACHINE_ARM: return std::string("arm"); case IMAGE_FILE_MACHINE_THUMB: return std::string("thumb"); case IMAGE_FILE_MACHINE_AM33: return std::string("am33"); case IMAGE_FILE_MACHINE_POWERPC: case IMAGE_FILE_MACHINE_POWERPCFP: return std::string("ppc"); case IMAGE_FILE_MACHINE_IA64: return std::string("ia64"); case IMAGE_FILE_MACHINE_ALPHA64: return std::string("alpha64"); case IMAGE_FILE_MACHINE_TRICORE: return std::string("infineon"); case IMAGE_FILE_MACHINE_CEF: return std::string("cef"); case IMAGE_FILE_MACHINE_EBC: return std::string("ebc"); case IMAGE_FILE_MACHINE_AMD64: return std::string("amd64"); case IMAGE_FILE_MACHINE_M32R: return std::string("m32r"); case IMAGE_FILE_MACHINE_CEE: return std::string("cee"); default: return string_format("unknown 0x%X", cpu_); } } OpenStatus PEArchitecture::ReadFromFile(uint32_t mode) { Seek(0); IMAGE_DOS_HEADER dos_header; if (size() < sizeof(dos_header)) return osUnknownFormat; Read(&dos_header, sizeof(dos_header)); if (dos_header.e_magic != IMAGE_DOS_SIGNATURE) return osUnknownFormat; Seek(dos_header.e_lfanew); uint32_t signature = ReadDWord(); if (signature != IMAGE_NT_SIGNATURE) return osUnknownFormat; IMAGE_FILE_HEADER image_header; Read(&image_header, sizeof(image_header)); cpu_ = image_header.Machine; if (cpu_ != IMAGE_FILE_MACHINE_I386 && cpu_ != IMAGE_FILE_MACHINE_AMD64) return osUnsupportedCPU; uint16_t magic = ReadWord(); assert(sizeof(magic) == sizeof(IMAGE_OPTIONAL_HEADER32().Magic)); assert(sizeof(magic) == sizeof(IMAGE_OPTIONAL_HEADER64().Magic)); uint16_t subsystem; uint32_t dir_count; switch (magic) { case IMAGE_NT_OPTIONAL_HDR32_MAGIC: { IMAGE_OPTIONAL_HEADER32 pe_header = IMAGE_OPTIONAL_HEADER32(); Read(&pe_header.MajorLinkerVersion, sizeof(pe_header) - sizeof(magic) - sizeof(pe_header.DataDirectory)); dir_count = pe_header.NumberOfRvaAndSizes; entry_point_ = pe_header.AddressOfEntryPoint; image_base_ = pe_header.ImageBase; segment_alignment_ = pe_header.SectionAlignment; file_alignment_ = pe_header.FileAlignment; cpu_address_size_ = osDWord; subsystem = pe_header.Subsystem; check_sum_ = pe_header.CheckSum; operating_system_version_ = (pe_header.MajorOperatingSystemVersion << 16) | pe_header.MinorOperatingSystemVersion; subsystem_version_= (pe_header.MajorSubsystemVersion << 16) | pe_header.MinorSubsystemVersion; dll_characteristics_ = pe_header.DllCharacteristics; } break; case IMAGE_NT_OPTIONAL_HDR64_MAGIC: { IMAGE_OPTIONAL_HEADER64 pe_header = IMAGE_OPTIONAL_HEADER64(); Read(&pe_header.MajorLinkerVersion, sizeof(pe_header) - sizeof(magic) - sizeof(pe_header.DataDirectory)); dir_count = pe_header.NumberOfRvaAndSizes; entry_point_ = pe_header.AddressOfEntryPoint; image_base_ = pe_header.ImageBase; segment_alignment_ = pe_header.SectionAlignment; file_alignment_ = pe_header.FileAlignment; cpu_address_size_ = osQWord; subsystem = pe_header.Subsystem; check_sum_ = pe_header.CheckSum; operating_system_version_ = (pe_header.MajorOperatingSystemVersion << 16) | pe_header.MinorOperatingSystemVersion; subsystem_version_= (pe_header.MajorSubsystemVersion << 16) | pe_header.MinorSubsystemVersion; dll_characteristics_ = pe_header.DllCharacteristics; } break; default: return osInvalidFormat; } time_stamp_ = image_header.TimeDateStamp; characterictics_ = image_header.Characteristics; switch (subsystem) { case IMAGE_SUBSYSTEM_NATIVE: image_type_ = itDriver; break; case IMAGE_SUBSYSTEM_WINDOWS_GUI: case IMAGE_SUBSYSTEM_WINDOWS_CUI: image_type_ = (characterictics_ & IMAGE_FILE_DLL) ? itLibrary : itExe; break; default: return osUnsupportedSubsystem; } if (entry_point_) entry_point_ += image_base_; header_offset_ = dos_header.e_lfanew; header_size_ = image_header.SizeOfOptionalHeader; directory_list_->ReadFromFile(*this, dir_count); Seek(header_offset_ + offsetof(IMAGE_NT_HEADERS32, OptionalHeader) + header_size_); segment_list_->ReadFromFile(*this, image_header.NumberOfSections); // read long section names from the COFF string table if (image_header.PointerToSymbolTable) { Seek(image_header.PointerToSymbolTable + image_header.NumberOfSymbols * sizeof(IMAGE_SYMBOL)); COFFStringTable string_table; string_table.ReadFromFile(*this); for (size_t i = 0; i < segment_list_->count(); i++) { PESegment *segment = segment_list_->item(i); const std::string &segment_name = segment->name(); if (segment_name.length() && segment_name[0] == '/') { char *endptr = NULL; uint32_t name_offset = strtoul(segment_name.c_str() + 1, &endptr, 10); if (endptr && *endptr == 0) segment->set_name(string_table.GetString(name_offset)); } } } resource_section_ = NULL; fixup_section_ = NULL; for (size_t i = 0; i < directory_list_->count(); i++) { PEDirectory *dir = directory_list_->item(i); switch (dir->type()) { case IMAGE_DIRECTORY_ENTRY_EXPORT: export_list_->ReadFromFile(*this, *dir); break; case IMAGE_DIRECTORY_ENTRY_IMPORT: import_list_->ReadFromFile(*this, *dir); break; case IMAGE_DIRECTORY_ENTRY_RESOURCE: resource_list_->ReadFromFile(*this, *dir); if (dir->address()) { resource_section_ = segment_list_->GetSectionByAddress(dir->address()); if (!resource_section_) return osInvalidFormat; if (resource_section_->address() != dir->address() || resource_section_ == segment_list_->header_segment()) resource_section_ = NULL; } break; case IMAGE_DIRECTORY_ENTRY_BASERELOC: fixup_list_->ReadFromFile(*this, *dir); if (dir->address()) { fixup_section_ = segment_list_->GetSectionByAddress(dir->address()); if (!fixup_section_) return osInvalidFormat; if (fixup_section_->address() != dir->address() || fixup_section_ == segment_list_->header_segment()) fixup_section_ = NULL; } break; case IMAGE_DIRECTORY_ENTRY_DEBUG: debug_directory_->ReadFromFile(*this, *dir); break; case IMAGE_DIRECTORY_ENTRY_TLS: tls_directory_->ReadFromFile(*this, *dir); break; case IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG: load_config_directory_->ReadFromFile(*this, *dir); break; case IMAGE_DIRECTORY_ENTRY_EXCEPTION: runtime_function_list_->ReadFromFile(*this, *dir); break; case IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT: delay_import_list_->ReadFromFile(*this, *dir); break; case IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR: if (dir->address()) { NETArchitecture *net = new NETArchitecture(reinterpret_cast(owner())); owner()->AddObject(net); OpenStatus res = net->ReadFromFile(mode); return res; /* if (res != osSuccess) return res; if ((net->header().Flags & COMIMAGE_FLAGS_ILONLY) == 0) { switch (cpu_) { case IMAGE_FILE_MACHINE_I386: case IMAGE_FILE_MACHINE_AMD64: function_list_ = new PEIntelFunctionList(this); break; default: return osUnsupportedCPU; } if ((mode & foHeaderOnly) == 0) { map_function_list()->ReadFromFile(*this); IntelFileHelper helper; helper.Parse(*this); } } return osSuccess; */ } break; } } if (fixup_section_) fixup_section_->set_need_parse(false); if (resource_section_) resource_section_->set_need_parse(false); if ((mode & foHeaderOnly) == 0) { if (!owner()->file_name().empty()) { std::vector segments; for (size_t i = 0; i < segment_list()->count(); i++) { segments.push_back(segment_list()->item(i)->address()); } if (std::find(segments.begin(), segments.end(), 0) == segments.end()) segments.insert(segments.begin(), 0); for (size_t i = 0; i < 3; i++) { if (i == 0) { MapFile map_file; if (map_file.Parse(map_file_name().c_str(), segments)) { ReadMapFile(map_file); break; } } else if (i == 1) { PDBFile pdb_file; if (pdb_file.Parse(pdb_file_name().c_str(), segments)) { std::vector guid; if (pdb_file.guid().size()) { for (size_t j = 0; j < debug_directory_->count(); j++) { PEDebugData *data = debug_directory_->item(j); if (data->type() == IMAGE_DEBUG_TYPE_CODEVIEW) { if (AddressSeek(data->address())) { struct PdbInfo { uint32_t Signature; GUID Guid; uint32_t Age; // char PdbFileName[1]; } pi; Read(&pi, sizeof(pi)); if (pi.Signature == 0x53445352) // RSDS guid.insert(guid.begin(), reinterpret_cast(&pi.Guid), reinterpret_cast(&pi.Guid) + sizeof(pi.Guid)); } break; } } } if (guid == pdb_file.guid()) { pdb_file.set_time_stamp(time_stamp_); ReadMapFile(pdb_file); } else Notify(mtWarning, NULL, string_format(language[lsMAPFileHasIncorrectTimeStamp].c_str(), os::ExtractFileName(pdb_file.file_name().c_str()).c_str())); break; } } else if (image_header.PointerToSymbolTable) { COFFFile coff_file; if (coff_file.Parse(owner()->file_name().c_str(), segments)) { ReadMapFile(coff_file); break; } } } } map_function_list()->ReadFromFile(*this); } switch (cpu_) { case IMAGE_FILE_MACHINE_I386: case IMAGE_FILE_MACHINE_AMD64: function_list_ = new PEIntelFunctionList(this); virtual_machine_list_ = new IntelVirtualMachineList(); if ((mode & foHeaderOnly) == 0) { IntelFileHelper helper; helper.Parse(*this); relocation_list_->ReadFromFile(*this); } break; default: return osUnsupportedCPU; } return osSuccess; } std::string PEArchitecture::pdb_file_name() const { if (!owner()) return std::string(); return os::ChangeFileExt(owner()->file_name().c_str(), ".pdb"); } bool PEArchitecture::ReadMapFile(IMapFile &map_file) { if (!BaseArchitecture::ReadMapFile(map_file)) return false; MapSection *sections = map_file.GetSectionByType(msSections); if (sections) { for (size_t i = 0; i < sections->count(); i++) { MapObject *section = sections->item(i); uint64_t address = section->address(); PESegment *segment; if (section->segment() != (size_t)-1) { if (section->segment() == 0 || section->segment() > segment_list_->count()) continue; segment = segment_list_->item(section->segment() - 1); } else { segment = segment_list_->GetSectionByAddress(address); if (!segment) continue; } section_list_->Add(segment, address, section->size(), section->name()); } } return true; } void PEArchitecture::WriteCheckSum() { if (check_sum_ && reinterpret_cast(owner())->GetCheckSum(&check_sum_)) { Seek(header_offset_ + sizeof(uint32_t) + sizeof(IMAGE_FILE_HEADER) + ((cpu_address_size() == osDWord) ? offsetof(IMAGE_OPTIONAL_HEADER32, CheckSum) : offsetof(IMAGE_OPTIONAL_HEADER64, CheckSum))); WriteDWord(check_sum_); } } bool PEArchitecture::WriteToFile() { IMAGE_FILE_HEADER image_header; IMAGE_OPTIONAL_HEADER32 pe_header32; IMAGE_OPTIONAL_HEADER64 pe_header64; uint32_t image_size, header_size; PESegment *last_section; // read header Seek(header_offset_ + sizeof(uint32_t)); Read(&image_header, sizeof(image_header)); image_header.PointerToSymbolTable = 0; image_header.NumberOfSymbols = 0; image_header.NumberOfSections = static_cast(segment_list_->count()); if (cpu_address_size_ == osDWord) { Read(&pe_header32, sizeof(pe_header32) - sizeof(pe_header32.DataDirectory)); } else { Read(&pe_header64, sizeof(pe_header64) - sizeof(pe_header64.DataDirectory)); } // write header directory_list_->WriteToFile(*this); segment_list_->WriteToFile(*this); header_size = AlignValue(static_cast(Tell()), file_alignment_); last_section = segment_list_->last(); image_size = (last_section) ? AlignValue(static_cast(last_section->address() - image_base() + last_section->size()), segment_alignment_) : 0; Seek(header_offset_ + sizeof(uint32_t)); image_header.Characteristics = characterictics_; Write(&image_header, sizeof(image_header)); if (cpu_address_size_ == osDWord) { pe_header32.AddressOfEntryPoint = (entry_point_) ? static_cast(entry_point_ - image_base_) : 0; pe_header32.SizeOfImage = image_size; if (header_size > pe_header32.SizeOfHeaders) pe_header32.SizeOfHeaders = header_size; pe_header32.MajorOperatingSystemVersion = operating_system_version_ >> 16; pe_header32.MinorOperatingSystemVersion = static_cast(operating_system_version_); pe_header32.MajorSubsystemVersion = subsystem_version_ >> 16; pe_header32.MinorSubsystemVersion = static_cast(subsystem_version_); pe_header32.DllCharacteristics = dll_characteristics_; Write(&pe_header32, sizeof(pe_header32) - sizeof(pe_header32.DataDirectory)); } else { pe_header64.AddressOfEntryPoint = (entry_point_) ? static_cast(entry_point_ - image_base_) : 0; pe_header64.SizeOfImage = image_size; if (header_size > pe_header64.SizeOfHeaders) pe_header64.SizeOfHeaders = header_size; pe_header64.MajorOperatingSystemVersion = operating_system_version_ >> 16; pe_header64.MinorOperatingSystemVersion = static_cast(operating_system_version_); pe_header64.MajorSubsystemVersion = subsystem_version_ >> 16; pe_header64.MinorSubsystemVersion = static_cast(subsystem_version_); pe_header64.DllCharacteristics = dll_characteristics_; Write(&pe_header64, sizeof(pe_header64) - sizeof(pe_header64.DataDirectory)); } return true; } bool PEArchitecture::Prepare(CompileContext &ctx) { if ((ctx.options.flags & cpPack) && segment_alignment_ < 0x1000) { ctx.options.flags &= ~cpPack; Notify(mtWarning, NULL, language[lsFileCanNotBePacked].c_str()); } if (image_type() == itExe && (dll_characteristics_ & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE) == 0) ctx.options.flags |= cpStripFixups; if (image_type() != itDriver) { if (ctx.options.flags & cpMemoryProtection) ctx.options.flags |= cpInternalMemoryProtection; if (ctx.options.flags & cpResourceProtection) { std::vector resources = resource_list()->GetResourceList(); bool need_resource_protection = false; for (size_t i = 0; i < resources.size(); i++) { IResource *resource = resources[i]; if (!resource->excluded_from_packing() && !resource->need_store()) { need_resource_protection = true; break; } } if (!need_resource_protection) ctx.options.flags &= ~cpResourceProtection; } } else { if (ctx.options.flags & cpResourceProtection) ctx.options.flags &= ~cpResourceProtection; #ifdef ULTIMATE if (ctx.options.file_manager) ctx.options.file_manager = NULL; #endif } if (!BaseArchitecture::Prepare(ctx)) return false; size_t i; PESegment *section; std::vector optimized_section_list; // optimize sections if (resource_section_) optimized_section_list.push_back(resource_section_); if (fixup_section_) optimized_section_list.push_back(fixup_section_); if (ctx.options.flags & cpStripDebugInfo) { for (i = 0; i < segment_list_->count(); i++) { section = segment_list_->item(i); if ((section->flags() & (IMAGE_SCN_MEM_DISCARDABLE | IMAGE_SCN_LNK_INFO)) == IMAGE_SCN_MEM_DISCARDABLE && section->name().substr(0, 6) == ".debug") optimized_section_list.push_back(section); } } optimized_section_count_ = segment_list_->count(); for (i = segment_list_->count(); i > 0; i--) { section = segment_list_->item(i - 1); std::vector::iterator it = std::find(optimized_section_list.begin(), optimized_section_list.end(), section); if (it != optimized_section_list.end()) { optimized_section_list.erase(it); optimized_section_count_--; } else { break; } } // calc new header size uint32_t new_section_count = static_cast(optimized_section_count_ + 1); if ((ctx.options.flags & cpStripFixups) == 0) new_section_count++; if (resource_list_->count()) new_section_count++; if (ctx.runtime) new_section_count += 2; // calc header resizes uint32_t new_header_size = header_offset_ + offsetof(IMAGE_NT_HEADERS32, OptionalHeader) + header_size_ + new_section_count * sizeof(IMAGE_SECTION_HEADER); low_resize_header_ = 0; if ((ctx.options.flags & cpStripDebugInfo) && header_offset_ > MIN_HEADER_OFFSET) { low_resize_header_ = header_offset_ - MIN_HEADER_OFFSET; new_header_size -= low_resize_header_; } for (i = 0; i < directory_list_->count(); i++) { PEDirectory *dir = directory_list_->item(i); if (!dir->visible() || dir->type() == IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT) continue; uint32_t rva = static_cast(dir->address() - image_base_); if (low_resize_header_ == 0 && new_header_size > rva && header_offset_ > MIN_HEADER_OFFSET) { low_resize_header_ = header_offset_ - MIN_HEADER_OFFSET; new_header_size -= low_resize_header_; } if (new_header_size > rva) { Notify(mtError, NULL, language[lsCreateSegmentError]); return false; } } uint32_t aligned_header_size = AlignValue(new_header_size, file_alignment_); resize_header_ = 0; for (i = 0; i < segment_list_->count(); i++) { section = segment_list_->item(i); if (section->physical_size() == 0 || section->physical_offset() == 0 || aligned_header_size <= section->physical_offset()) continue; uint32_t rva = static_cast(section->address() - image_base_); if (low_resize_header_ == 0 && aligned_header_size > rva && header_offset_ > MIN_HEADER_OFFSET) { low_resize_header_ = header_offset_ - MIN_HEADER_OFFSET; new_header_size -= low_resize_header_; aligned_header_size = AlignValue(new_header_size, file_alignment_); } if (aligned_header_size > rva) { Notify(mtError, NULL, language[lsCreateSegmentError]); return false; } if (aligned_header_size > section->physical_offset()) resize_header_ = std::max(resize_header_, aligned_header_size - section->physical_offset()); } for (i = 0; i < optimized_section_list.size(); i++) { section = optimized_section_list[i]; ctx.manager->Add(section->address(), std::min(static_cast(section->size()), section->physical_size()), section->memory_type()); } if (optimized_section_count_ > 0) { section = segment_list_->item(optimized_section_count_ - 1); if (ctx.runtime) { PEArchitecture *runtime = reinterpret_cast(ctx.runtime); if (runtime->segment_list()->count()) { runtime->Rebase(image_base(), AlignValue(section->address() + section->size(), segment_alignment()) - runtime->segment_list()->item(0)->address()); MemoryManager runtime_manager(runtime); if (runtime->segment_list()->last() == runtime->fixup_section_) { delete runtime->fixup_section_; runtime->fixup_section_ = NULL; } if (runtime->load_config_directory()->seh_table_address()) { section = runtime->segment_list()->last(); if (section->address() == runtime->load_config_directory()->seh_table_address()) delete section; } if (runtime->runtime_function_list()->address()) { section = runtime->segment_list()->last(); if (section->address() == runtime->runtime_function_list()->address()) delete section; else runtime->runtime_function_list()->FreeByManager(runtime_manager); } runtime->import_list()->FreeByManager(runtime_manager, (ctx.options.flags & cpImportProtection) != 0); runtime_manager.Pack(); for (i = 0; i < runtime_manager.count(); i++) { MemoryRegion *region = runtime_manager.item(i); ctx.manager->Add(region->address(), region->size(), region->type()); } section = runtime->segment_list()->last(); } else { runtime->Rebase(image_base(), image_base() - runtime->image_base()); } } // add new section assert(section); ctx.manager->Add(AlignValue(section->address() + section->size(), segment_alignment()), UINT32_MAX, mtReadable | mtExecutable | mtWritable | mtNotPaged | (runtime_function_list()->count() ? mtSolid : mtNone)); } if (ctx.runtime) import_list_->FreeByManager(*ctx.manager, (ctx.options.flags & cpImportProtection) != 0); if (ctx.options.flags & cpPack) { export_list_->FreeByManager(*ctx.manager); tls_directory_->FreeByManager(*ctx.manager); PEDirectory *dir = directory_list_->GetCommandByType(IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG); if (dir) dir->FreeByManager(*ctx.manager); dir = directory_list_->GetCommandByType(IMAGE_DIRECTORY_ENTRY_ARCHITECTURE); if (dir) dir->FreeByManager(*ctx.manager); } if (ctx.options.flags & (cpPack | cpStripDebugInfo)) debug_directory_->FreeByManager(*ctx.manager); load_config_directory_->FreeByManager(*ctx.manager); runtime_function_list_->FreeByManager(*ctx.manager); return true; } bool PEArchitecture::Compile(CompileOptions &options, IArchitecture *runtime) { return visible() ? BaseArchitecture::Compile(options, runtime) : true; } void PEArchitecture::Save(CompileContext &ctx) { PEDirectory *dir; PESegment *last_section, *section, *vmp_section; uint64_t pos, address, resource_section_info, resource_packer_info, file_crc_address, loader_crc_address, name_table, loader_crc_size_address, loader_crc_hash_address, file_crc_size_address; uint32_t size, file_crc_size, loader_crc_size, name_table_size; size_t i, j, c; MemoryRegion *region; uint32_t resource_section_flags, fixup_section_flags; std::string resource_section_name, fixup_section_name; int vmp_index; MemoryManager *manager = memory_manager(); // erase sections area { IMAGE_SECTION_HEADER section_header = IMAGE_SECTION_HEADER(); Seek(header_offset_ + offsetof(IMAGE_NT_HEADERS32, OptionalHeader) + header_size_); for (i = 0; i < segment_list_->count(); i++) { Write(§ion_header, sizeof(section_header)); } } // resize header if (low_resize_header_ || resize_header_) { uint32_t new_header_offset = header_offset_ - low_resize_header_; size_t total_header_size = offsetof(IMAGE_NT_HEADERS32, OptionalHeader) + header_size_ + segment_list_->count() * sizeof(IMAGE_SECTION_HEADER); const PEArchitecture *src = dynamic_cast(source()); if (low_resize_header_) { Seek(offsetof(IMAGE_DOS_HEADER, e_lfanew)); WriteDWord(new_header_offset); src->Seek(header_offset_); Seek(new_header_offset); CopyFrom(*src, total_header_size); for (i = 0; i < low_resize_header_; i++) { WriteByte(0); } } if (resize_header_) { src->Seek(header_offset_ + total_header_size); Seek(header_offset_ + total_header_size); for (i = 0; i < resize_header_; i++) { WriteByte(0); } CopyFrom(*src, this->size() - src->Tell()); section = segment_list_->header_segment(); if (section) section->set_physical_size(section->physical_size() + resize_header_); for (i = 0; i < segment_list_->count(); i++) { section = segment_list_->item(i); if (section->physical_offset()) section->set_physical_offset(section->physical_offset() + resize_header_); } if ((ctx.options.flags & (cpPack | cpStripDebugInfo)) == 0) { if (debug_directory_->address()) { for (i = 0; i < debug_directory_->count(); i++) { PEDebugData *data = debug_directory_->item(i); data->set_offset(data->offset() + resize_header_); } AddressSeek(debug_directory_->address()); debug_directory_->WriteToFile(*this); } } } header_offset_ = new_header_offset; } // add antidebug export if ((ctx.options.flags & cpCheckDebugger) && image_type() != itDriver && !import_list()->GetImportByName("dbghelp.dll")) export_list_->AddAntidebug(); // compile modified objects if ((ctx.options.flags & cpPack) == 0) { if (source() && !export_list()->is_equal(*source()->export_list())) { const PEArchitecture *src = dynamic_cast(source()); if(src == NULL) throw std::runtime_error("Runtime error at Save"); src->export_list()->FreeByManager(*manager); PEIntelExport *pe_export = reinterpret_cast(function_list())->AddExport(cpu_address_size()); pe_export->Init(ctx); pe_export->Compile(ctx); PEDirectory *dir = directory_list_->GetCommandByType(IMAGE_DIRECTORY_ENTRY_EXPORT); if (dir) { if (pe_export->entry()) { dir->set_address(pe_export->entry()->address()); dir->set_size(pe_export->size()); } else { dir->clear(); } } } } // calc progress maximum c = 0; if (ctx.runtime) c += ctx.runtime->segment_list()->count(); for (i = 0; i < function_list_->count(); i++) { IFunction *func = function_list_->item(i); for (j = 0; j < func->block_list()->count(); j++) { CommandBlock *block = func->block_list()->item(j); c += block->end_index() - block->start_index() + 1; } } StartProgress(string_format("%s...", language[lsSaving].c_str()), c); if (resource_list_->count()) { if (ctx.options.flags & cpResourceProtection) { for (i = resource_list_->count(); i > 0; i--) { PEResource *resource = resource_list_->item(i - 1); if (!resource->need_store()) delete resource; } } resource_list_->Compile(*this, (resource_section_ && resource_section_->excluded_from_packing()) ? false : (ctx.options.flags & cpPack) != 0); } resource_section_flags = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA; resource_section_name = ".rsrc"; fixup_section_flags = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE | IMAGE_SCN_CNT_INITIALIZED_DATA; fixup_section_name = ".reloc"; // need erase optimized sections for (i = segment_list_->count(); i > optimized_section_count_; i--) { section = segment_list_->item(i - 1); if (resource_section_ == section) { resource_section_flags = section->flags(); resource_section_name = section->name(); resource_section_ = NULL; } else if (fixup_section_ == section) { fixup_section_flags = section->flags(); fixup_section_name = section->name(); fixup_section_ = NULL; } delete section; } // need truncate optimized sections and overlay for (i = segment_list_->count(); i > 0; i--) { section = segment_list_->item(i - 1); if (section->physical_size() > 0) { Resize(section->physical_offset() + section->physical_size()); break; } } last_section = segment_list_->last(); address = AlignValue(last_section->address() + last_section->size(), segment_alignment_); pos = Resize(AlignValue(this->size(), file_alignment_)); vmp_section = segment_list_->Add(address, UINT32_MAX, static_cast(pos), UINT32_MAX, IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE, ""); // merge runtime objects PEArchitecture *runtime = reinterpret_cast(ctx.runtime); if (runtime && runtime->segment_list()->count()) { // merge sections SignatureList patch_signatures; if (image_type() != itDriver) { if (cpu_address_size() == osDWord) patch_signatures.Add("817DD800000001741B83C8FF8B4DF0", 0); } for (i = 0; i < runtime->segment_list()->count(); i++) { section = runtime->segment_list()->item(i); if (section->physical_offset() && section->physical_size()) { runtime->Seek(section->physical_offset()); size = static_cast(section->physical_size()); uint8_t *buffer = new uint8_t[size]; runtime->Read(buffer, size); if ((section->memory_type() & mtExecutable) && patch_signatures.count()) { patch_signatures.InitSearch(); for (c = 0; c < size; c++) { uint8_t b = buffer[c]; for (j = 0; j < patch_signatures.count(); j++) { Signature *sign = patch_signatures.item(j); if (sign->SearchByte(b)) { size_t p = c + 1 - sign->size(); buffer[p + 7] = 0xeb; } } } } Write(buffer, size); delete [] buffer; } size = static_cast(AlignValue(section->size(), runtime->segment_alignment()) - section->physical_size()); for (j = 0; j < size; j++) { WriteByte(0); } uint32_t memory_type = section->memory_type(); if (image_type_ != itDriver) memory_type &= ~mtWritable; vmp_section->include_write_type(memory_type); StepProgress(); } // merge fixups for (i = 0; i < runtime->fixup_list()->count(); i++) { PEFixup *fixup = runtime->fixup_list()->item(i); fixup_list_->AddObject(fixup->Clone(fixup_list_)); } // merge seh handlers for (i = 0; i < runtime->seh_handler_list()->count(); i++) { PESEHandler *handler = runtime->seh_handler_list()->item(i); load_config_directory_->seh_handler_list()->Add(handler->address()); } // merge CFG addresses PECFGAddressTable *cfg_address_list = runtime->load_config_directory_->cfg_address_list(); for (i = 0; i < cfg_address_list->count(); i++) { load_config_directory_->cfg_address_list()->Add(cfg_address_list->item(i)->address()); } // merge runtime functions for (i = 0; i < runtime->runtime_function_list()->count(); i++) { PERuntimeFunction *runtime_function = runtime->runtime_function_list()->item(i); runtime_function_list_->AddObject(runtime_function->Clone(runtime_function_list_)); } } // write functions for (i = 0; i < function_list_->count(); i++) { function_list_->item(i)->WriteToFile(*this); } // erase not used memory regions if (manager->count() > 1) { // need skip last big region for (i = 0; i < manager->count() - 1; i++) { region = manager->item(i); if (!AddressSeek(region->address())) continue; for (j = 0; j < region->size(); j++) { WriteByte((ctx.options.flags & cpDebugMode) ? 0xcc : rand()); } } } vmp_index = 0; // need update fixup and resource sections if they are not optimized if (fixup_section_) { fixup_section_->set_name(string_format("%s%d", ctx.options.section_name.c_str(), vmp_index++)); if (fixup_section_->write_type()) { fixup_section_->set_flags(IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE | IMAGE_SCN_CNT_INITIALIZED_DATA); fixup_section_->update_type(fixup_section_->write_type()); } fixup_section_ = NULL; } if (resource_section_) { resource_section_->set_name(string_format("%s%d", ctx.options.section_name.c_str(), vmp_index++)); if (resource_section_->write_type()) { resource_section_->set_flags(IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE | IMAGE_SCN_CNT_INITIALIZED_DATA); resource_section_->update_type(resource_section_->write_type()); } resource_section_ = NULL; } if (!runtime) { last_section = segment_list_->last(); if (import_list_->has_sdk()) import_list_->WriteToFile(*this, true); if (load_config_directory_->WriteToFile(*this)) last_section->include_write_type(mtReadable | mtNotDiscardable); dir = directory_list_->GetCommandByType(IMAGE_DIRECTORY_ENTRY_EXCEPTION); if (dir) { pos = Resize(AlignValue(this->size(), 0x10)); address = last_section->address() + pos - last_section->physical_offset(); size = static_cast(runtime_function_list_->WriteToFile(*this)); if (size) { last_section->include_write_type(mtReadable | mtNotDiscardable | mtNotPaged); dir->set_address(address); dir->set_size(size); } else { dir->clear(); } } } if (vmp_section->write_type() == mtNone) { delete vmp_section; } else { vmp_section->set_name(string_format("%s%d", ctx.options.section_name.c_str(), vmp_index++)); size = static_cast(this->size() - vmp_section->physical_offset()); vmp_section->set_size(size); vmp_section->set_physical_size(AlignValue(size, file_alignment_)); vmp_section->update_type(vmp_section->write_type()); Resize(vmp_section->physical_offset() + vmp_section->physical_size()); } if ((ctx.options.flags & cpPack) && ctx.options.script) ctx.options.script->DoBeforePackFile(); // write memory CRC table if (function_list_->crc_table()) { IntelCRCTable *intel_crc = reinterpret_cast(function_list_->crc_table()); CRCTable crc_table(function_list_->crc_cryptor(), intel_crc->table_size()); // add non writable sections for (i = 0; i < segment_list_->count(); i++) { section = segment_list_->item(i); if ((section->memory_type() & (mtReadable | mtWritable)) != mtReadable || section->excluded_from_memory_protection()) continue; size = std::min(static_cast(section->size()), section->physical_size()); if (size) { crc_table.Add(section->address(), size); if (ctx.options.sdk_flags & cpMemoryProtection) section->update_type(mtNotPaged); } } // skip writable runtime's sections if (runtime) { for (i = 0; i < runtime->segment_list()->count(); i++) { section = runtime->segment_list()->item(i); if (section->memory_type() & mtWritable) crc_table.Remove(section->address(), static_cast(section->size())); } } // skip IAT IntelImport *intel_import = reinterpret_cast(function_list_)->import(); size = OperandSizeToValue(cpu_address_size()); size_t k = (runtime && runtime->segment_list()->count() > 0) ? 2 : 1; for (size_t n = 0; n < k; n++) { PEImportList *import_list = (n == 0) ? import_list_ : runtime->import_list(); for (i = 0; i < import_list->count(); i++) { PEImport *import = import_list->item(i); if (ctx.options.flags & cpImportProtection) { for (j = 0; j < import->count(); j++) { PEImportFunction *import_function = import->item(j); address = import_function->address(); IntelCommand *iat_command = intel_import->GetIATCommand(import_function); if (iat_command) address = iat_command->address(); crc_table.Remove(address, size); } } else { if (import->count() > 0) crc_table.Remove(import->item(0)->address(), size * import->count()); } } } // skip fixups if ((ctx.options.flags & cpStripFixups) == 0) { for (i = 0; i < fixup_list_->count(); i++) { PEFixup *fixup = fixup_list_->item(i); if (!fixup->is_deleted()) crc_table.Remove(fixup->address(), OperandSizeToValue(fixup->size())); } } // skip relocations for (i = 0; i < relocation_list_->count(); i++) { PERelocation *relocation = relocation_list_->item(i); crc_table.Remove(relocation->address(), OperandSizeToValue(relocation->size())); } // skip loader_data IntelFunction *loader_data = reinterpret_cast(function_list_)->loader_data(); if (loader_data) crc_table.Remove(loader_data->entry()->address(), loader_data->entry()->dump_size()); // skip memory CRC table crc_table.Remove(intel_crc->table_entry()->address(), intel_crc->table_size()); crc_table.Remove(intel_crc->size_entry()->address(), sizeof(uint32_t)); crc_table.Remove(intel_crc->hash_entry()->address(), sizeof(uint32_t)); // write to file AddressSeek(intel_crc->table_entry()->address()); uint32_t hash; size = static_cast(crc_table.WriteToFile(*this, false, &hash)); AddressSeek(intel_crc->size_entry()->address()); WriteDWord(size); AddressSeek(intel_crc->hash_entry()->address()); WriteDWord(hash); intel_crc->size_entry()->set_operand_value(0, size); intel_crc->hash_entry()->set_operand_value(0, hash); } EndProgress(); resource_section_info = 0; resource_packer_info = 0; file_crc_address = 0; file_crc_size = 0; file_crc_size_address = 0; loader_crc_address = 0; loader_crc_size = 0; loader_crc_size_address = 0; loader_crc_hash_address = 0; name_table = 0; name_table_size = 0; if (runtime) { uint64_t iat_address = 0; uint64_t security_cookie_address = 0; last_section = segment_list_->last(); address = AlignValue(last_section->address() + last_section->size(), segment_alignment_); pos = Resize(AlignValue(this->size(), file_alignment_)); size = 0; // create segment for IAT { size_t iat_count = 0; for (j = 0; j < 2; j++) { PEArchitecture *source_file = (j == 0) ? this : runtime; for (i = 0; i < source_file->import_list()->count(); i++) { IImport *import = source_file->import_list()->item(i); if (import->is_sdk()) continue; iat_count += import->count(); if (j == 1 && runtime->segment_list()->count()) iat_count += import->count(); } } if (iat_count) { iat_count++; iat_address = address + size; size += static_cast(iat_count) * OperandSizeToValue(cpu_address_size()); } } // create segment for security_cookie if ((ctx.options.flags & cpPack) && image_type() == itDriver && load_config_directory_->security_cookie() && AddressSeek(load_config_directory_->security_cookie())) { section = segment_list_->GetSectionByAddress(load_config_directory_->security_cookie()); if (!(section && section->excluded_from_packing())) { uint32_t value_size = OperandSizeToValue(cpu_address_size()); uint64_t security_cookie_value = 0; Read(&security_cookie_value, value_size); Resize(pos + size); Write(&security_cookie_value, value_size); security_cookie_address = address + size; size += value_size; } } // create segment for tls data if ((ctx.options.flags & cpPack) && tls_directory_->end_address_of_raw_data() > tls_directory_->start_address_of_raw_data()) { uint32_t data_size = static_cast(tls_directory_->end_address_of_raw_data() - tls_directory_->start_address_of_raw_data()); Data data; data.resize(data_size); if (AddressSeek(tls_directory_->start_address_of_raw_data())) Read(&data[0], data.size()); Resize(pos + size); Write(data.data(), data.size()); uint64_t tls_data_address = address + size; for (i = 0; i < data_size; i++) { if (IFixup *fixup = fixup_list()->GetFixupByAddress(tls_directory_->start_address_of_raw_data() + i)) fixup->set_address(tls_data_address + i); } tls_directory_->set_start_address_of_raw_data(tls_data_address); tls_directory_->set_end_address_of_raw_data(tls_data_address + data_size); size += data_size; } if (size) { section = segment_list_->Add(address, size, static_cast(pos), AlignValue(size, file_alignment_), IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_CNT_INITIALIZED_DATA, string_format("%s%d", ctx.options.section_name.c_str(), vmp_index++)); section->set_excluded_from_packing(true); Resize(section->physical_offset() + section->physical_size()); } std::vector processor_list = function_list_->processor_list(); IntelRuntimeCRCTable *runtime_crc_table = reinterpret_cast(function_list_)->runtime_crc_table(); PEIntelLoader *loader = new PEIntelLoader(NULL, cpu_address_size()); if (security_cookie_address) loader->set_security_cookie(security_cookie_address); if (iat_address) loader->set_iat_address(iat_address); last_section = segment_list_->last(); address = AlignValue(last_section->address() + last_section->size(), segment_alignment_); manager->clear(); manager->Add(address, UINT32_MAX, mtReadable | mtExecutable | mtWritable | mtNotPaged | (runtime_function_list()->count() ? mtSolid : mtNone)); if (!loader->Prepare(ctx)) { delete loader; throw std::runtime_error("Runtime error at Save"); } size_t write_count = loader->count() + 10000; size_t processor_count = 0; for (i = 0; i < processor_list.size(); i++) { processor_count += processor_list[i]->count(); } ctx.file->StartProgress(string_format("%s...", language[lsSavingStartupCode].c_str()), loader->count() + write_count + processor_count); loader->Compile(ctx); pos = Resize(AlignValue(this->size(), file_alignment_)); section = segment_list_->Add(address, UINT32_MAX, static_cast(pos), UINT32_MAX, IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_CNT_CODE, string_format("%s%d", ctx.options.section_name.c_str(), vmp_index++)); c = loader->WriteToFile(*this); section->update_type(section->write_type() | ((ctx.options.sdk_flags & cpMemoryProtection) ? mtNotPaged : mtNone)); for (i = 0; i < processor_list.size(); i++) { processor_list[i]->WriteToFile(*this); } if (runtime_crc_table) c += runtime_crc_table->WriteToFile(*this); // correct progress position write_count -= c; if (write_count) StepProgress(write_count); // copy directories { IArchitecture *source = const_cast(this->source()); last_section = segment_list_->last(); const uint32_t copy_dir_types[] = {IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, IMAGE_DIRECTORY_ENTRY_ARCHITECTURE}; for (j = 0; j < _countof(copy_dir_types); j++) { if (copy_dir_types[j] != IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG && (ctx.options.flags & cpPack) == 0) continue; dir = directory_list_->GetCommandByType(copy_dir_types[j]); if (dir && dir->address() && dir->physical_size() && source->AddressSeek(dir->address())) { size = dir->physical_size(); pos = Resize(AlignValue(this->size(), 0x10)); CopyFrom(*source, size); address = last_section->address() + pos - last_section->physical_offset(); for (i = 0; i < size; i++) { PEFixup *fixup = reinterpret_cast(source->fixup_list()->GetFixupByAddress(dir->address() + i)); if (fixup) { fixup = fixup->Clone(fixup_list_); fixup->set_address(address + i); fixup_list_->AddObject(fixup); } } dir->set_address(address); } } if ((ctx.options.flags & (cpPack | cpStripDebugInfo)) == cpPack) { if (debug_directory_->address()) { for (i = 0; i < debug_directory_->count(); i++) { PEDebugData *data = debug_directory_->item(i); if (source->Seek(data->offset())) { size = data->size(); pos = Resize(AlignValue(this->size(), 0x10)); CopyFrom(*source, size); address = last_section->address() + pos - last_section->physical_offset(); data->set_offset(static_cast(pos)); data->set_address(address); } } pos = Resize(AlignValue(this->size(), 0x10)); address = last_section->address() + pos - last_section->physical_offset(); debug_directory_->WriteToFile(*this); dir = directory_list_->GetCommandByType(IMAGE_DIRECTORY_ENTRY_DEBUG); if (dir) dir->set_address(address); } } } dir = directory_list_->GetCommandByType(IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG); if (dir) { if (security_cookie_address) load_config_directory_->set_security_cookie(security_cookie_address); std::vector cfg_address_list = loader->cfg_address_list(); for (i = 0; i < cfg_address_list.size(); i++) { load_config_directory_->cfg_address_list()->Add(cfg_address_list[i]); } if (loader->cfg_check_function_entry()) load_config_directory_->set_cfg_check_function(loader->cfg_check_function_entry()->address()); load_config_directory_->WriteToFile(*this); } dir = directory_list_->GetCommandByType(IMAGE_DIRECTORY_ENTRY_EXCEPTION); if (dir) { pos = Resize(AlignValue(this->size(), 0x10)); address = section->address() + pos - section->physical_offset(); size = static_cast(runtime_function_list_->WriteToFile(*this)); if (size) { section->update_type(mtReadable | mtNotDiscardable | mtNotPaged); dir->set_address(address); dir->set_size(size); } else { dir->clear(); } } size = static_cast(this->size() - section->physical_offset()); section->set_size(size); section->set_physical_size(AlignValue(size, file_alignment_)); Resize(section->physical_offset() + section->physical_size()); dir = directory_list_->GetCommandByType(IMAGE_DIRECTORY_ENTRY_IMPORT); if (dir) { dir->set_address(loader->import_entry()->address()); dir->set_size(loader->import_size()); } dir = directory_list_->GetCommandByType(IMAGE_DIRECTORY_ENTRY_IAT); if (dir) { dir->set_address(loader->iat_entry()->address()); dir->set_size(loader->iat_size()); } if (loader->export_entry()) { dir = directory_list_->GetCommandByType(IMAGE_DIRECTORY_ENTRY_EXPORT); if (dir) { if (loader->export_size()) { dir->set_address(loader->export_entry()->address()); dir->set_size(loader->export_size()); } else { dir->clear(); } } } if (loader->tls_entry()) { dir = directory_list_->GetCommandByType(IMAGE_DIRECTORY_ENTRY_TLS); if (dir) { if (loader->tls_size()) { dir->set_address(loader->tls_entry()->address()); dir->set_size(loader->tls_size()); } else { dir->clear(); } } } if (loader->delay_import_entry()) { dir = directory_list_->GetCommandByType(IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT); if (dir) { if (loader->delay_import_size()) { dir->set_address(loader->delay_import_entry()->address()); dir->set_size(loader->delay_import_size()); } else { dir->clear(); } } } entry_point_ = loader->entry()->address(); if (loader->resource_section_info()) { resource_section_info = loader->resource_section_info()->address(); resource_packer_info = loader->resource_packer_info()->address(); } if (loader->file_crc_entry()) { file_crc_address = loader->file_crc_entry()->address(); file_crc_size = loader->file_crc_size(); file_crc_size_address = loader->file_crc_size_entry()->address(); } if (loader->loader_crc_entry()) { loader_crc_address = loader->loader_crc_entry()->address(); loader_crc_size = loader->loader_crc_size(); loader_crc_size_address = loader->loader_crc_size_entry()->address(); loader_crc_hash_address = loader->loader_crc_hash_entry()->address(); } if (loader->name_entry()) { name_table = loader->name_entry()->address(); name_table_size = loader->name_size(); } delete loader; // update versions if (operating_system_version_ < runtime->operating_system_version_) operating_system_version_ = runtime->operating_system_version_; if (subsystem_version_ < runtime->subsystem_version_) subsystem_version_ = runtime->subsystem_version_; ctx.file->EndProgress(); } // save fixups dir = directory_list_->GetCommandByType(IMAGE_DIRECTORY_ENTRY_BASERELOC); if (dir) { if (fixup_list_->Pack() == 0 || (ctx.options.flags & cpStripFixups) != 0) { dir->clear(); fixup_section_ = NULL; } else { last_section = segment_list_->last(); address = AlignValue(last_section->address() + last_section->size(), segment_alignment_); pos = Resize(AlignValue(this->size(), file_alignment_)); size = static_cast(fixup_list_->WriteToFile(*this)); section = segment_list_->Add(address, size, static_cast(pos), AlignValue(size, file_alignment_), fixup_section_flags, fixup_section_name); fixup_section_ = section; Resize(section->physical_offset() + section->physical_size()); dir->set_address(address); dir->set_size(size); } } // save resources dir = directory_list_->GetCommandByType(IMAGE_DIRECTORY_ENTRY_RESOURCE); if (dir) { if (resource_list_->count() == 0) { dir->clear(); resource_section_ = NULL; } else { last_section = segment_list_->last(); address = AlignValue(last_section->address() + last_section->size(), segment_alignment_); pos = Resize(AlignValue(this->size(), file_alignment_)); address = AlignValue(last_section->address() + last_section->size(), segment_alignment_); size = static_cast(resource_list_->WriteToFile(*this, address)); section = segment_list_->Add(address, (uint32_t)resource_list_->size(), static_cast(pos), AlignValue(size, file_alignment_), resource_section_flags, resource_section_name); resource_section_ = section; Resize(section->physical_offset() + section->physical_size()); dir->set_address(address); dir->set_size((uint32_t)resource_list_->size()); if (resource_section_info) { pos = Tell(); AddressSeek(resource_section_info); WriteDWord(static_cast(address - image_base_)); WriteDWord(static_cast(resource_list_->size())); WriteDWord(section->flags()); AddressSeek(resource_packer_info); WriteDWord(static_cast(address - image_base_ + resource_list_->store_size())); Seek(pos); } } } // clear directories { const uint32_t clear_dir_types[] = {IMAGE_DIRECTORY_ENTRY_SECURITY, IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT}; for (i = 0; i < _countof(clear_dir_types); i++) { dir = directory_list_->GetCommandByType(clear_dir_types[i]); if (dir) dir->clear(); } if (ctx.options.flags & cpStripDebugInfo) { dir = directory_list_->GetCommandByType(IMAGE_DIRECTORY_ENTRY_DEBUG); if (dir) dir->clear(); } } // check discardable sections for (i = segment_list_->count(); i > 1; i--) { section = segment_list_->item(i - 1); if ((section->flags() & IMAGE_SCN_MEM_DISCARDABLE) == 0) { for (j = i - 1; j > 0; j--) { section = segment_list_->item(j - 1); section->set_flags(section->flags() & ~IMAGE_SCN_MEM_DISCARDABLE); } break; } } if (ctx.options.script) ctx.options.script->DoAfterSaveFile(); // write header if (ctx.options.flags & cpStripFixups) { characterictics_ |= IMAGE_FILE_RELOCS_STRIPPED; dll_characteristics_ &= ~IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE; } if ((ctx.options.flags | ctx.options.sdk_flags) & (cpCheckDebugger | cpCheckVirtualMachine)) dll_characteristics_ &= ~IMAGE_DLLCHARACTERISTICS_NO_SEH; WriteToFile(); // write header and loader CRC table if (loader_crc_address) { CRCTable crc_table(function_list_->crc_cryptor(), loader_crc_size); uint64_t resources_address = 0; if (resource_list()->size() > resource_list()->store_size()) { dir = directory_list_->GetCommandByType(IMAGE_DIRECTORY_ENTRY_RESOURCE); if (dir) resources_address = dir->address(); } // add header crc_table.Add(image_base_, header_offset_ + sizeof(uint32_t) + sizeof(IMAGE_FILE_HEADER) + ((cpu_address_size() == osDWord) ? offsetof(IMAGE_OPTIONAL_HEADER32, DataDirectory) : offsetof(IMAGE_OPTIONAL_HEADER64, DataDirectory)) + directory_list_->count() * sizeof(IMAGE_DATA_DIRECTORY) + segment_list_->count() * sizeof(IMAGE_SECTION_HEADER)); // add loader sections j = segment_list_->IndexOf(segment_list_->GetSectionByAddress(loader_crc_address)); if (j != NOT_ID) { c = (ctx.options.flags & cpLoaderCRC) ? j + 1 : segment_list_->count(); for (i = j; i < c; i++) { section = segment_list_->item(i); if (section->memory_type() & mtWritable) continue; if (resources_address && section->address() == resources_address) { size = (uint32_t)(resource_list()->store_size()); } else { size = std::min(static_cast(section->size()), section->physical_size()); } if (size) crc_table.Add(section->address(), size); } } // skip IMAGE_DOS_HEADER.e_res crc_table.Remove(image_base_ + offsetof(IMAGE_DOS_HEADER, e_res), sizeof(uint16_t) * 4); // skip IMAGE_OPTIONAL_HEADER.CheckSum crc_table.Remove(image_base_ + header_offset_ + sizeof(uint32_t) + sizeof(IMAGE_FILE_HEADER) + ((cpu_address_size() == osDWord) ? offsetof(IMAGE_OPTIONAL_HEADER32, CheckSum) : offsetof(IMAGE_OPTIONAL_HEADER64, CheckSum)), sizeof(uint32_t)); // skip IMAGE_OPTIONAL_HEADER.ImageBase crc_table.Remove(image_base_ + header_offset_ + sizeof(uint32_t) + sizeof(IMAGE_FILE_HEADER) + ((cpu_address_size() == osDWord) ? offsetof(IMAGE_OPTIONAL_HEADER32, ImageBase) : offsetof(IMAGE_OPTIONAL_HEADER64, ImageBase)), OperandSizeToValue(cpu_address_size())); // skip security directory crc_table.Remove(image_base_ + header_offset_ + sizeof(uint32_t) + sizeof(IMAGE_FILE_HEADER) + ((cpu_address_size() == osDWord) ? offsetof(IMAGE_OPTIONAL_HEADER32, DataDirectory) : offsetof(IMAGE_OPTIONAL_HEADER64, DataDirectory)) + IMAGE_DIRECTORY_ENTRY_SECURITY * sizeof(IMAGE_DATA_DIRECTORY), sizeof(IMAGE_DATA_DIRECTORY)); // skip IAT directory dir = directory_list_->GetCommandByType(IMAGE_DIRECTORY_ENTRY_IAT); if (dir) crc_table.Remove(dir->address(), dir->size()); if (image_type_ == itDriver) { // skip part of import table if (name_table) crc_table.Remove(name_table, name_table_size); } else { // skip IMAGE_IMPORT_DESCRIPTOR.TimeDateStamp and IMAGE_IMPORT_DESCRIPTOR.ForwarderChain for each import DLL dir = directory_list_->GetCommandByType(IMAGE_DIRECTORY_ENTRY_IMPORT); if (dir) { address = dir->address(); for (i = 0; i < dir->size()/sizeof(IMAGE_IMPORT_DESCRIPTOR); i++, address += sizeof(IMAGE_IMPORT_DESCRIPTOR)) { crc_table.Remove(address + offsetof(IMAGE_IMPORT_DESCRIPTOR, TimeDateStamp), sizeof(uint32_t) * 2); } } } if (load_config_directory_->cfg_check_function()) crc_table.Remove(load_config_directory_->cfg_check_function(), OperandSizeToValue(cpu_address_size())); // skip fixups if ((ctx.options.flags & cpStripFixups) == 0) { for (i = 0; i < fixup_list_->count(); i++) { PEFixup *fixup = fixup_list_->item(i); crc_table.Remove(fixup->address(), OperandSizeToValue(fixup->size())); } } // skip loader CRC table crc_table.Remove(loader_crc_address, loader_crc_size); crc_table.Remove(loader_crc_size_address, sizeof(uint32_t)); crc_table.Remove(loader_crc_hash_address, sizeof(uint32_t)); // skip file CRC table if (file_crc_address) crc_table.Remove(file_crc_address, file_crc_size); if (file_crc_size_address) crc_table.Remove(file_crc_size_address, sizeof(uint32_t)); // write to file AddressSeek(loader_crc_address); uint32_t hash; size = static_cast(crc_table.WriteToFile(*this, false, &hash)); AddressSeek(loader_crc_size_address); WriteDWord(size); AddressSeek(loader_crc_hash_address); WriteDWord(hash); } // write file CRC table if (file_crc_address) { CRCTable crc_table(function_list_->crc_cryptor(), file_crc_size - sizeof(uint32_t)); // add file range crc_table.Add(1, static_cast(this->size()) - 1); // skip IMAGE_OPTIONAL_HEADER.CheckSum crc_table.Remove(header_offset_ + sizeof(uint32_t) + sizeof(IMAGE_FILE_HEADER) + ((cpu_address_size() == osDWord) ? offsetof(IMAGE_OPTIONAL_HEADER32, CheckSum) : offsetof(IMAGE_OPTIONAL_HEADER64, CheckSum)), sizeof(uint32_t)); // skip position of security directory crc_table.Remove(header_offset_ + sizeof(uint32_t) + sizeof(IMAGE_FILE_HEADER) + ((cpu_address_size() == osDWord) ? offsetof(IMAGE_OPTIONAL_HEADER32, DataDirectory) : offsetof(IMAGE_OPTIONAL_HEADER64, DataDirectory)) + IMAGE_DIRECTORY_ENTRY_SECURITY * sizeof(IMAGE_DATA_DIRECTORY), sizeof(IMAGE_DATA_DIRECTORY)); // skip file CRC table if (AddressSeek(file_crc_address)) crc_table.Remove(Tell(), file_crc_size); if (AddressSeek(file_crc_size_address)) crc_table.Remove(Tell(), sizeof(uint32_t)); // write to file AddressSeek(file_crc_address); size = static_cast(this->size()); WriteDWord(size); size = static_cast(crc_table.WriteToFile(*this, true)); AddressSeek(file_crc_size_address); WriteDWord(size); } WriteCheckSum(); EndProgress(); } void PEArchitecture::Rebase(uint64_t target_image_base, uint64_t delta_base) { BaseArchitecture::Rebase(delta_base); fixup_list_->Rebase(*this, delta_base); import_list_->Rebase(delta_base); export_list_->Rebase(delta_base); directory_list_->Rebase(delta_base); load_config_directory_->Rebase(delta_base); runtime_function_list_->RebaseByFile(*this, target_image_base, delta_base); segment_list_->Rebase(delta_base); section_list_->Rebase(delta_base); function_list_->Rebase(delta_base); if (entry_point_) entry_point_ += delta_base; image_base_ += delta_base; } bool PEArchitecture::is_executable() const { return image_type() == itExe; } std::string PEArchitecture::ANSIToUTF8(const std::string &str) const { #ifndef VMP_GNU if (!os::ValidateUTF8(str)) return os::ToUTF8(os::FromACP(str)); #endif return str; } void PEArchitecture::ReadFromBuffer(Buffer &buffer) { BaseArchitecture::ReadFromBuffer(buffer); PECFGAddressTable *cfg_address_list = load_config_directory_->cfg_address_list(); size_t c = buffer.ReadDWord(); for (size_t i = 0; i < c; i++) { cfg_address_list->Add(buffer.ReadDWord() + image_base()); } } /** * PDBFile */ PDBFile::PDBFile() : BaseMapFile(), time_stamp_(0) { } bool PDBFile::Parse(const char *file_name, const std::vector &segments) { clear(); guid_.clear(); time_stamp_ = 0; file_name_ = file_name; PdbFileStream fs; if (!fs.Open(file_name, fmOpenRead | fmShareDenyNone)) return false; segments_ = segments; size_t sign_len2 = sizeof(pdb2) - 1, sign_len7 = sizeof(pdb7) - 1; size_t sign_len = std::max(sign_len2, sign_len7); std::vector head(sign_len); if (fs.RawRead(0, &head)) { if (!memcmp(&head[0], pdb2, sign_len2)) { pdb_jg_reader reader(fs); if (!reader.init()) return false; time_stamp_ = reader.root->TimeDateStamp; return ReadSymbols(reader); } else if (!memcmp(&head[0], pdb7, sign_len7)) { pdb_ds_reader reader(fs); if (!reader.init()) return false; guid_.insert(guid_.begin(), reinterpret_cast(&reader.root->guid), reinterpret_cast(&reader.root->guid) + sizeof(reader.root->guid)); return ReadSymbols(reader); } } return false; } bool PDBFile::ReadSymbols(pdb_reader &reader) { // read types if (reader.read_file(PDB_STREAM_TPI, types_data_)) { PDB_TYPES *types = reinterpret_cast(types_data_.data()); size_t offset; if (types->version < 19960000) { const PDB_TYPES_OLD *types_old = reinterpret_cast(types); offset = sizeof(PDB_TYPES_OLD); types_first_index_ = types_old->first_index; } else { offset = types->type_offset; types_first_index_ = types->first_index; } int length; for (size_t i = offset; i < types_data_.size(); i += length) { const union codeview_type *type = reinterpret_cast(types_data_.data() + i); length = type->generic.len + 2; if (!type->generic.id || length < 4) break; types_offset_.push_back(type); } } PDB_SYMBOLS *symbols; std::vector vsymbols, vmodimage; if (!reader.read_file(PDB_STREAM_DBI, vsymbols)) return false; symbols = reinterpret_cast(vsymbols.data()); // read global symbol table if (reader.read_file(symbols->gsym_file, vmodimage)) codeview_dump_symbols(vmodimage, 0); // read per-module symbol / linenumber tables const char *file = reinterpret_cast(symbols) + sizeof(PDB_SYMBOLS); while (static_cast(file - reinterpret_cast(symbols)) < sizeof(PDB_SYMBOLS) + symbols->module_size) { int file_nr, symbol_size; const char* file_name; if (symbols->version < 19970000) { const PDB_SYMBOL_FILE* sym_file = reinterpret_cast(file); file_nr = sym_file->file; file_name = sym_file->filename; symbol_size = sym_file->symbol_size; } else { const PDB_SYMBOL_FILE_EX* sym_file = reinterpret_cast(file); file_nr = sym_file->file; file_name = sym_file->filename; symbol_size = sym_file->symbol_size; } if (symbol_size && reader.read_file(file_nr, vmodimage)) codeview_dump_symbols(vmodimage, sizeof(uint32_t)); file_name += strlen(file_name) + 1; file = reinterpret_cast(reinterpret_cast(file_name + strlen(file_name) + 1 + 3) & ~3); } return true; } void PDBFile::AddSymbol(size_t segment, size_t offset, const std::string &name) { if (!segment || segment >= segments_.size()) return; uint64_t address = segments_[segment] + offset; std::pair key(address, name); if (map_.find(key) != map_.end()) return; map_.insert(key); MapSection *section = GetSectionByType(msFunctions); if (!section) section = Add(msFunctions); section->Add(NOT_ID, address, 0, name); } void PDBFile::AddSection(size_t segment, size_t offset, uint64_t size, const std::string &name) { if (segment >= segments_.size()) return; MapSection *section = GetSectionByType(msSections); if (!section) section = Add(msSections); section->Add(segment, segments_[segment] + offset, size, name); } size_t leaf_length(const uint16_t *type) { size_t res = sizeof(*type); switch (*type++) { case LF_CHAR: res += 1; break; case LF_SHORT: case LF_USHORT: res += 2; break; case LF_LONG: case LF_ULONG: res += 4; break; case LF_REAL32: res += 4; break; case LF_REAL48: res += 6; break; case LF_REAL80: res += 10; break; case LF_REAL128: res += 16; break; case LF_QUADWORD: case LF_UQUADWORD: res += 8; break; case LF_COMPLEX32: res += 4; break; case LF_COMPLEX80: res += 10; break; case LF_COMPLEX128: res += 16; break; case LF_VARSTRING: res += 2 + *type; break; } return res; } std::string PDBFile::GetTypeName(size_t data_type, const std::string &name) { std::string res; const p_string *p_str; if (data_type < types_first_index_) { switch (data_type) { case T_VOID: res = "void"; break; case T_CHAR: res = "char"; break; case T_SHORT: res = "short"; break; case T_LONG: res = "long"; break; case T_QUAD: res = "__int64"; break; case T_UCHAR: res = "unsigned char"; break; case T_USHORT: res = "unsigned short"; break; case T_ULONG: res = "unsigned long"; break; case T_UQUAD: res = "unsigned __int64"; break; case T_BOOL08: case T_BOOL16: case T_BOOL32: case T_BOOL64: res = "bool"; break; case T_REAL32: res = "float"; break; case T_REAL64: res = "double"; break; case T_REAL80: res = "long double"; break; case T_RCHAR: res = "char"; break; case T_INT4: res = "int"; break; case T_UINT4: res = "unsigned int"; break; case T_WCHAR: res = "wchar_t"; break; case T_CHAR16: res = "char16_t"; break; case T_CHAR32: res = "char32_t"; break; case T_PVOID: case T_PCHAR: case T_PSHORT: case T_PLONG: case T_PQUAD: case T_PUCHAR: case T_PUSHORT: case T_PULONG: case T_PUQUAD: case T_PBOOL08: case T_PBOOL16: case T_PBOOL32: case T_PBOOL64: case T_PREAL32: case T_PREAL64: case T_PREAL80: case T_PREAL128: case T_PREAL48: case T_PCPLX32: case T_PCPLX64: case T_PCPLX80: case T_PCPLX128: case T_PRCHAR: case T_PWCHAR: case T_PINT2: case T_PUINT2: case T_PINT4: case T_PUINT4: case T_PINT8: case T_PUINT8: case T_PCHAR16: case T_PCHAR32: case T_PFVOID: case T_PFCHAR: case T_PFSHORT: case T_PFLONG: case T_PFQUAD: case T_PFUCHAR: case T_PFUSHORT: case T_PFULONG: case T_PFUQUAD: case T_PFBOOL08: case T_PFBOOL16: case T_PFBOOL32: case T_PFBOOL64: case T_PFREAL32: case T_PFREAL64: case T_PFREAL80: case T_PFREAL128: case T_PFREAL48: case T_PFCPLX32: case T_PFCPLX64: case T_PFCPLX80: case T_PFCPLX128: case T_PFRCHAR: case T_PFWCHAR: case T_PFINT2: case T_PFUINT2: case T_PFINT4: case T_PFUINT4: case T_PFINT8: case T_PFUINT8: case T_PFCHAR16: case T_PFCHAR32: case T_PHVOID: case T_PHCHAR: case T_PHSHORT: case T_PHLONG: case T_PHQUAD: case T_PHUCHAR: case T_PHUSHORT: case T_PHULONG: case T_PHUQUAD: case T_PHBOOL08: case T_PHBOOL16: case T_PHBOOL32: case T_PHBOOL64: case T_PHREAL32: case T_PHREAL64: case T_PHREAL80: case T_PHREAL128: case T_PHREAL48: case T_PHCPLX32: case T_PHCPLX64: case T_PHCPLX80: case T_PHCPLX128: case T_PHRCHAR: case T_PHWCHAR: case T_PHINT2: case T_PHUINT2: case T_PHINT4: case T_PHUINT4: case T_PHINT8: case T_PHUINT8: case T_PHCHAR16: case T_PHCHAR32: case T_32PVOID: case T_32PCHAR: case T_32PSHORT: case T_32PLONG: case T_32PQUAD: case T_32PUCHAR: case T_32PUSHORT: case T_32PULONG: case T_32PUQUAD: case T_32PBOOL08: case T_32PBOOL16: case T_32PBOOL32: case T_32PBOOL64: case T_32PREAL32: case T_32PREAL64: case T_32PREAL80: case T_32PREAL128: case T_32PREAL48: case T_32PCPLX32: case T_32PCPLX64: case T_32PCPLX80: case T_32PCPLX128: case T_32PRCHAR: case T_32PWCHAR: case T_32PINT2: case T_32PUINT2: case T_32PINT4: case T_32PUINT4: case T_32PINT8: case T_32PUINT8: case T_32PCHAR16: case T_32PCHAR32: case T_32PFVOID: case T_32PFCHAR: case T_32PFSHORT: case T_32PFLONG: case T_32PFQUAD: case T_32PFUCHAR: case T_32PFUSHORT: case T_32PFULONG: case T_32PFUQUAD: case T_32PFBOOL08: case T_32PFBOOL16: case T_32PFBOOL32: case T_32PFBOOL64: case T_32PFREAL32: case T_32PFREAL64: case T_32PFREAL80: case T_32PFREAL128: case T_32PFREAL48: case T_32PFCPLX32: case T_32PFCPLX64: case T_32PFCPLX80: case T_32PFCPLX128: case T_32PFRCHAR: case T_32PFWCHAR: case T_32PFINT2: case T_32PFUINT2: case T_32PFINT4: case T_32PFUINT4: case T_32PFINT8: case T_32PFUINT8: case T_32PFCHAR16: case T_32PFCHAR32: case T_64PVOID: case T_64PCHAR: case T_64PSHORT: case T_64PLONG: case T_64PQUAD: case T_64PUCHAR: case T_64PUSHORT: case T_64PULONG: case T_64PUQUAD: case T_64PBOOL08: case T_64PBOOL16: case T_64PBOOL32: case T_64PBOOL64: case T_64PREAL32: case T_64PREAL64: case T_64PREAL80: case T_64PREAL128: case T_64PREAL48: case T_64PCPLX32: case T_64PCPLX64: case T_64PCPLX80: case T_64PCPLX128: case T_64PRCHAR: case T_64PWCHAR: case T_64PINT2: case T_64PUINT2: case T_64PINT4: case T_64PUINT4: case T_64PINT8: case T_64PUINT8: case T_64PCHAR16: case T_64PCHAR32: return GetTypeName(data_type & T_BASICTYPE_MASK, (!name.empty() && name.front() != '*' ? "* " : "*") + name); } } else if (data_type - types_first_index_ < types_offset_.size()) { const union codeview_type* type = types_offset_[data_type - types_first_index_]; switch (type->generic.id) { case LF_MODIFIER_V1: if (type->modifier_v1.attribute & 0x01) res += "const "; if (type->modifier_v1.attribute & 0x02) res += "volatile "; if (type->modifier_v1.attribute & 0x04) res += "unaligned "; if (type->modifier_v1.attribute & ~0x07) res += "unknown "; if (!res.empty()) res.pop_back(); res = GetTypeName(type->modifier_v1.type, res); case LF_MODIFIER_V2: if (type->modifier_v2.attribute & 0x01) res += "const "; if (type->modifier_v2.attribute & 0x02) res += "volatile "; if (type->modifier_v2.attribute & 0x04) res += "unaligned "; if (type->modifier_v2.attribute & ~0x07) res += "unknown "; if (!res.empty()) res.pop_back(); res = GetTypeName(type->modifier_v2.type, res); break; case LF_POINTER_V1: return GetTypeName(type->pointer_v1.datatype, (!name.empty() && name.front() != '*' ? "* " : "*") + name); case LF_POINTER_V2: if (type->pointer_v2.attribute & 0x80) res = "&&"; else if (type->pointer_v2.attribute & 0x20) res = '&'; else res = '*'; if (!name.empty() && name.front() != res.back()) res += ' '; return GetTypeName(type->pointer_v2.datatype, res + name); case LF_ARRAY_V1: return GetTypeName(type->array_v1.elemtype, (!name.empty() && name.front() != '*' ? "* " : "*") + name); case LF_ARRAY_V2: return GetTypeName(type->array_v2.elemtype, (!name.empty() && name.front() != '*' ? "* " : "*") + name); case LF_ARRAY_V3: return GetTypeName(type->array_v3.elemtype, (!name.empty() && name.front() != '*' ? "* " : "*") + name); case LF_STRUCTURE_V1: case LF_CLASS_V1: p_str = reinterpret_cast(reinterpret_cast(&type->struct_v1.structlen) + leaf_length(&type->struct_v1.structlen)); res = (type->generic.id == LF_CLASS_V1 ? "class " : "struct ") + std::string(p_str->name, p_str->namelen); break; case LF_STRUCTURE_V2: case LF_CLASS_V2: p_str = reinterpret_cast(reinterpret_cast(&type->struct_v2.structlen) + leaf_length(&type->struct_v2.structlen)); res = (type->generic.id == LF_CLASS_V2 ? "class " : "struct ") + std::string(p_str->name, p_str->namelen); break; case LF_STRUCTURE_V3: case LF_CLASS_V3: res = (type->generic.id == LF_CLASS_V3 ? "class " : "struct ") + std::string(reinterpret_cast(&type->struct_v3.structlen) + leaf_length(&type->struct_v3.structlen)); break; case LF_ARGLIST_V1: { const union codeview_reftype *ref_type = reinterpret_cast(type); if (ref_type->arglist_v2.num == 0) res = GetTypeName(T_VOID, ""); else for (size_t i = 0; i < ref_type->arglist_v1.num; i++) { if (i > 0) res += ','; res += GetTypeName(ref_type->arglist_v1.args[i], ""); } } break; case LF_ARGLIST_V2: { const union codeview_reftype *ref_type = reinterpret_cast(type); if (ref_type->arglist_v2.num == 0) res = GetTypeName(T_VOID, ""); else for (size_t i = 0; i < ref_type->arglist_v2.num; i++) { if (i > 0) res += ','; res += GetTypeName(ref_type->arglist_v2.args[i], ""); } } break; case LF_PROCEDURE_V1: return GetTypeName(type->procedure_v1.rvtype, '(' + name + ')' + '(' + GetTypeName(type->procedure_v1.arglist, "") + ')'); case LF_PROCEDURE_V2: return GetTypeName(type->procedure_v2.rvtype, '(' + name + ')' + '(' + GetTypeName(type->procedure_v2.arglist, "") + ')'); case LF_UNION_V1: p_str = reinterpret_cast(reinterpret_cast(&type->union_v1.un_len) + leaf_length(&type->union_v1.un_len)); res = "union " + std::string(p_str->name, p_str->namelen); break; case LF_UNION_V2: p_str = reinterpret_cast(reinterpret_cast(&type->union_v2.un_len) + leaf_length(&type->union_v2.un_len)); res = "union " + std::string(p_str->name, p_str->namelen); break; case LF_UNION_V3: res = "union " + std::string(reinterpret_cast(&type->union_v3.un_len) + leaf_length(&type->union_v3.un_len)); break; case LF_ENUM_V1: res = "enum " + std::string(type->enumeration_v1.p_name.name, type->enumeration_v1.p_name.namelen); break; case LF_ENUM_V2: res = "enum " + std::string(type->enumeration_v2.p_name.name, type->enumeration_v2.p_name.namelen); break; case LF_ENUM_V3: res = "enum " + std::string(type->enumeration_v3.name); break; default: res = "???"; } } if (!res.empty() && !name.empty()) res += ' '; return res + name; } void PDBFile::codeview_dump_symbols(const std::vector &root, size_t offset) { size_t i; int length; for (i = offset; i < root.size(); i += length) { const union codeview_symbol* sym = reinterpret_cast(&root[0] + i); length = sym->generic.len + 2; if (!sym->generic.id || length < 4) break; switch (sym->generic.id) { case S_GDATA_V2: case S_LDATA_V2: AddSymbol(sym->data_v2.segment, sym->data_v2.offset, GetTypeName(sym->data_v2.symtype, std::string(sym->data_v2.p_name.name, sym->data_v2.p_name.namelen))); break; case S_LDATA_V3: case S_GDATA_V3: AddSymbol(sym->data_v3.segment, sym->data_v3.offset, GetTypeName(sym->data_v3.symtype, std::string(sym->data_v3.name))); break; case S_PUB_V2: AddSymbol(sym->public_v2.segment, sym->public_v2.offset, std::string(sym->public_v2.p_name.name, sym->public_v2.p_name.namelen)); break; case S_PUB_V3: AddSymbol(sym->public_v3.segment, sym->public_v3.offset, std::string(sym->public_v3.name)); break; case S_THUNK_V1: AddSymbol(sym->thunk_v1.segment, sym->thunk_v1.offset, std::string(sym->thunk_v1.p_name.name, sym->thunk_v1.p_name.namelen)); break; case S_THUNK_V3: AddSymbol(sym->thunk_v3.segment, sym->thunk_v3.offset, std::string(sym->thunk_v3.name)); break; //case S_GPROC_V1: case S_LPROC_V1: AddSymbol(sym->proc_v1.segment, sym->proc_v1.offset, std::string(sym->proc_v1.p_name.name, sym->proc_v1.p_name.namelen)); break; //case S_GPROC_V2: case S_LPROC_V2: AddSymbol(sym->proc_v2.segment, sym->proc_v2.offset, std::string(sym->proc_v2.p_name.name, sym->proc_v2.p_name.namelen)); break; case S_LPROC_V3: //case S_GPROC_V3: AddSymbol(sym->proc_v3.segment, sym->proc_v3.offset, std::string(sym->proc_v3.name)); break; case S_SUBSECTINFO_V3: AddSection(*reinterpret_cast(reinterpret_cast(sym) + 16), *reinterpret_cast(reinterpret_cast(sym) + 12), *reinterpret_cast(reinterpret_cast(sym) + 4), std::string(reinterpret_cast(sym) + 18)); break; case S_LTHREAD_V1: case S_GTHREAD_V1: AddSymbol(sym->thread_v1.segment, sym->thread_v1.offset, std::string(sym->thread_v1.p_name.name, sym->thread_v1.p_name.namelen)); break; case S_LTHREAD_V2: case S_GTHREAD_V2: AddSymbol(sym->thread_v2.segment, sym->thread_v2.offset, std::string(sym->thread_v2.p_name.name, sym->thread_v2.p_name.namelen)); break; case S_LTHREAD_V3: case S_GTHREAD_V3: AddSymbol(sym->thread_v3.segment, sym->thread_v3.offset, std::string(sym->thread_v3.name)); break; case S_PROCREF_V1: case S_DATAREF_V1: case S_LPROCREF_V1: length += (*(reinterpret_cast(sym) + length) + 1 + 3) & ~3; break; } } } /** * COFFStringTable */ std::string COFFStringTable::GetString(uint32_t pos) const { if (pos < sizeof(uint32_t)) throw std::runtime_error("Invalid index for string table"); if (pos >= data_.size()) throw std::runtime_error("Invalid index for string table"); size_t i, len; len = data_.size() - pos; for (i = 0; i < len; i++) { if (data_[pos + i] == 0) { len = i; break; } } if (len == data_.size() - pos) throw std::runtime_error("Invalid format"); return std::string(&data_[pos], len); } void COFFStringTable::ReadFromFile(PEArchitecture &file) { uint32_t size = file.ReadDWord(); if (size < sizeof(size)) throw std::runtime_error("Invalid format"); data_.resize(size); file.Read(data_.data() + sizeof(uint32_t), data_.size() - sizeof(uint32_t)); } void COFFStringTable::ReadFromFile(FileStream &file) { uint32_t size = 0; file.Read(&size, sizeof(size)); if (size < sizeof(size)) throw std::runtime_error("Invalid format"); data_.resize(size); file.Read(data_.data() + sizeof(uint32_t), data_.size() - sizeof(uint32_t)); } /** * COFFFile */ bool COFFFile::Parse(const char *file_name, const std::vector &segments) { clear(); time_stamp_ = 0; file_name_ = file_name; FileStream fs; if (!fs.Open(file_name, fmOpenRead | fmShareDenyNone)) return false; segments_ = segments; IMAGE_DOS_HEADER dos_header; if (fs.Read(&dos_header, sizeof(dos_header)) == sizeof(dos_header) && dos_header.e_magic == IMAGE_DOS_SIGNATURE) { if (fs.Seek(dos_header.e_lfanew, soBeginning) != (uint64_t)-1) { uint32_t signature = 0; fs.Read(&signature, sizeof(signature)); if (signature == IMAGE_NT_SIGNATURE) { IMAGE_FILE_HEADER image_header = IMAGE_FILE_HEADER(); fs.Read(&image_header, sizeof(image_header)); if (image_header.PointerToSymbolTable) { time_stamp_ = image_header.TimeDateStamp; if (fs.Seek(image_header.PointerToSymbolTable + image_header.NumberOfSymbols * sizeof(IMAGE_SYMBOL), soBeginning) != (uint64_t)-1) { COFFStringTable string_table; string_table.ReadFromFile(fs); fs.Seek(image_header.PointerToSymbolTable, soBeginning); for (size_t i = 0; i < image_header.NumberOfSymbols; i++) { std::string name; IMAGE_SYMBOL sym; fs.Read(&sym, sizeof(sym)); switch (sym.StorageClass) { case IMAGE_SYM_CLASS_EXTERNAL: case IMAGE_SYM_CLASS_STATIC: if (sym.N.Name.Short == 0) { name = string_table.GetString(sym.N.Name.Long); } else { name = std::string(reinterpret_cast(&sym.N.ShortName), strnlen(reinterpret_cast(&sym.N.ShortName), sizeof(sym.N.ShortName))); } AddSymbol(sym.SectionNumber, sym.Value, name); } } return true; } } } } } return false; } void COFFFile::AddSymbol(size_t segment, size_t offset, const std::string &name) { if (!segment || segment >= segments_.size()) return; uint64_t address = segments_[segment] + offset; MapSection *section = GetSectionByType(msFunctions); if (!section) section = Add(msFunctions); section->Add(NOT_ID, address, 0, name); }