diff options
Diffstat (limited to 'core/pefile.cc')
-rw-r--r-- | core/pefile.cc | 6125 |
1 files changed, 6125 insertions, 0 deletions
diff --git a/core/pefile.cc b/core/pefile.cc new file mode 100644 index 0000000..7c0288b --- /dev/null +++ b/core/pefile.cc @@ -0,0 +1,6125 @@ +/** + * 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<PESegmentList *>(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<char *>(§ion_header.Name), strnlen(reinterpret_cast<char *>(§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<uint32_t>(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<PESegment *>(BaseSectionList::item(index)); +} + +PESegment *PESegmentList::GetSectionByAddress(uint64_t address) const +{ + PESegment *res = reinterpret_cast<PESegment *>(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<PESegment *>(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<uint32_t>(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<PESectionList *>(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<PESection *>(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<PEDirectoryList *>(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<uint32_t>(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<PEDirectory *>(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<PEDirectory *>(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<PEImport *>(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<PEImportList *>(owner), *this); + return import; +} + +PEImportFunction *PEImport::item(size_t index) const +{ + return reinterpret_cast<PEImportFunction *>(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<uint32_t>(original_first_thunk_address_ - file.image_base()) : 0; + import_descriptor.TimeDateStamp = time_stamp_; + import_descriptor.ForwarderChain = forwarder_chain_; + import_descriptor.Name = static_cast<uint32_t>(name_address_ - file.image_base()); + import_descriptor.FirstThunk = first_thunk_address_ ? static_cast<uint32_t>(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<PEImport *>(BaseImportList::item(index)); +} + +PEImportFunction *PEImportList::GetFunctionByAddress(uint64_t address) const +{ + return reinterpret_cast<PEImportFunction*>(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<PEDelayImportFunction>(), owner_(owner) +{ + +} + +PEDelayImport::PEDelayImport(PEDelayImportList *owner, const PEDelayImport &src) + : ObjectList<PEDelayImportFunction>(), 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<PEDelayImport>() +{ + +} + +PEDelayImportList::PEDelayImportList(const PEDelayImportList &src) + : ObjectList<PEDelayImport>() +{ + 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<PEExportList *>(owner), *this); + return exp; +} + +int PEExport::CompareWith(const IObject &obj) const +{ + const PEExport &exp = reinterpret_cast<const PEExport &>(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<PEExport *>(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<uint32_t, PEExport *> 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<NameInfo> 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<NameInfo>::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<IntelFunction &>(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<ExportInfo> 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<PEFixupList *>(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<uint16_t>(value)); + break; + case IMAGE_REL_BASED_HIGH: + value = file.ReadWord(); + value += delta_base >> 16; + file.Seek(pos); + file.WriteWord(static_cast<uint16_t>(value)); + break; + case IMAGE_REL_BASED_HIGHLOW: + value = file.ReadDWord(); + value += delta_base; + file.Seek(pos); + file.WriteDWord(static_cast<uint32_t>(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<PEFixup *>(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<uint32_t>(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<uint16_t>(rva - block_rva) & 0xf00) << 4 | IMAGE_REL_BASED_ABSOLUTE; + } + uint16_t type_offset = (static_cast<uint16_t>(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<uint32_t>(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<uint16_t>(rva - block_rva) & 0xf00); + } + uint16_t type_offset = fixup->internal_type() << 12 | (static_cast<uint16_t>(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<PERelocationList *>(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<PERelocation *>(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<uint32_t>(relocation->address() - image_base)); + if (!relocation->source()) { + data.PushDWord(relocation->addend()); + data.PushDWord(0); + } else { + data.PushDWord(static_cast<uint32_t>(relocation->source() - image_base)); + data.PushDWord(relocation->size() + 1); + } + } + + if (address_) { + data.PushDWord(static_cast<uint32_t>(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<PESEHandler*>(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<size_t>(load_config_directory.SEHandlerCount); + cfg_check_function_ = load_config_directory.GuardCFCheckFunctionPointer; + cfg_table_address_ = load_config_directory.GuardCFFunctionTable; + cfg_table_count = static_cast<size_t>(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<uint8_t> 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<uint32_t>(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<uint32_t>(cfg_address->address() - file.image_base())); + if (data_size) { + std::vector<uint8_t> 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<uint32_t>(security_cookie_); + load_config_directory.SEHandlerTable = static_cast<uint32_t>(seh_table_address_); + load_config_directory.SEHandlerCount = seh_table_address_ ? static_cast<uint32_t>(seh_handler_list_->count()) : 0; + load_config_directory.GuardCFCheckFunctionPointer = static_cast<uint32_t>(cfg_check_function_); + load_config_directory.GuardCFFunctionTable = static_cast<uint32_t>(cfg_table_address_); + load_config_directory.GuardCFFunctionCount = cfg_table_address_ ? static_cast<uint32_t>(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<PECFGAddress>() +{ + +} + +PECFGAddressTable::PECFGAddressTable(const PECFGAddressTable &src) + : ObjectList<PECFGAddress>() +{ + 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<PEResource *>(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<size_t>(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<size_t>(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<IntelFunction &>(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<size_t>(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<IntelFunction &>(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<uint16_t>(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<IntelFunction &>(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<uint16_t>(p[i] ^ (_rotl32(key, static_cast<int>(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<uint8_t> buf; + buf.resize(data_.item.Size); + file.Read(buf.data(), buf.size()); + + data.WriteDWord(data_entry_offset_, static_cast<uint32_t>(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<uint8_t> 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<uint8_t>(_rotl32(key, static_cast<int>(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<PEResource*>(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<PEResource *>(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<size_t>(dir_.NumberOfNamedEntries) + static_cast<size_t>(dir_.NumberOfIdEntries); i++) { + file.Read(&dir_entry, sizeof(dir_entry)); + Add(dir_entry.u.s.NameIsString ? rtUnknown : static_cast<PEResourceType>(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<PEResource *> 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<size_t>(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<uint32_t>(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<PERuntimeFunctionList *>(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<IntelFunction &>(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<uint32_t>(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<uint32_t>(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<uint32_t>(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<uint32_t>(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<uint8_t> &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<uint8_t> 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<uint32_t>(runtime_function->begin() - image_base); + data.EndAddress = static_cast<uint32_t>(runtime_function->end() - image_base); + data.UnwindData = static_cast<uint32_t>(runtime_function->unwind_address() - image_base); + res += file.Write(&data, sizeof(data)); + } + + return res; +} + +PERuntimeFunction *PERuntimeFunctionList::GetFunctionByAddress(uint64_t address) const +{ + return reinterpret_cast<PERuntimeFunction *>(BaseRuntimeFunctionList::GetFunctionByAddress(address)); +} + +PERuntimeFunction *PERuntimeFunctionList::item(size_t index) const +{ + return reinterpret_cast<PERuntimeFunction *>(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<IntelCommand *>(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<uint32_t>(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<uint32_t>(file.image_base() + delta_base - target_image_base); + std::set<uint64_t> address_list; + std::set<uint64_t> 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<PEArchitecture *>(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<uint32_t>(address_ - file.image_base()) : 0; + data.PointerToRawData = offset_; + file.Write(&data, sizeof(data)); +} + +/** + * PEDebugDirectory + */ + +PEDebugDirectory::PEDebugDirectory() + : ObjectList<PEDebugData>(), address_(0) +{ + +} + +PEDebugDirectory::PEDebugDirectory(const PEDebugDirectory &src) + : ObjectList<PEDebugData>(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<NETArchitecture *>(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<VERSION_INFO*>(data)->szKey[len]) + len++; + VS_FIXEDFILEINFO *file_info = reinterpret_cast<VS_FIXEDFILEINFO *>(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<uint16_t>(file_info->dwFileVersionMS >> 16), static_cast<uint16_t>(file_info->dwFileVersionMS), static_cast<uint16_t>(file_info->dwFileVersionLS >> 16), static_cast<uint16_t>(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<NETArchitecture *>(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<IntelFunction *>(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<PEFile *>(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<PEFile *>(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<uint64_t> 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<uint8_t> 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<const uint8_t *>(&pi.Guid), reinterpret_cast<const uint8_t *>(&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<PEFile*>(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<uint16_t>(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<uint32_t>(Tell()), file_alignment_); + + last_section = segment_list_->last(); + image_size = (last_section) ? AlignValue(static_cast<uint32_t>(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<uint32_t>(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<uint16_t>(operating_system_version_); + pe_header32.MajorSubsystemVersion = subsystem_version_ >> 16; + pe_header32.MinorSubsystemVersion = static_cast<uint16_t>(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<uint32_t>(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<uint16_t>(operating_system_version_); + pe_header64.MajorSubsystemVersion = subsystem_version_ >> 16; + pe_header64.MinorSubsystemVersion = static_cast<uint16_t>(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<IResource*> 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<PESegment *> 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<PESegment *>::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<uint32_t>(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<uint32_t>(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<uint32_t>(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<uint32_t>(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<PEArchitecture *>(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<const PEArchitecture *>(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<const PEArchitecture *>(source()); + if(src == NULL) + throw std::runtime_error("Runtime error at Save"); + + src->export_list()->FreeByManager(*manager); + + PEIntelExport *pe_export = reinterpret_cast<PEIntelFunctionList *>(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<uint32_t>(pos), UINT32_MAX, IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE, ""); + + // merge runtime objects + PEArchitecture *runtime = reinterpret_cast<PEArchitecture*>(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<uint32_t>(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<uint32_t>(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<uint32_t>(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<uint32_t>(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<IntelCRCTable *>(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<uint32_t>(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<uint32_t>(section->size())); + } + } + + // skip IAT + IntelImport *intel_import = reinterpret_cast<IntelFunctionList *>(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<IntelFunctionList *>(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<uint32_t>(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<uint32_t>(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<uint32_t>(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<uint32_t>(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<IFunction *> processor_list = function_list_->processor_list(); + IntelRuntimeCRCTable *runtime_crc_table = reinterpret_cast<IntelFunctionList *>(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<uint32_t>(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<IArchitecture *>(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<PEFixup *>(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<uint32_t>(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<uint64_t> 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<uint32_t>(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<uint32_t>(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<uint32_t>(fixup_list_->WriteToFile(*this)); + section = segment_list_->Add(address, size, static_cast<uint32_t>(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<uint32_t>(resource_list_->WriteToFile(*this, address)); + section = segment_list_->Add(address, (uint32_t)resource_list_->size(), static_cast<uint32_t>(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<uint32_t>(address - image_base_)); + WriteDWord(static_cast<uint32_t>(resource_list_->size())); + WriteDWord(section->flags()); + + AddressSeek(resource_packer_info); + WriteDWord(static_cast<uint32_t>(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<uint32_t>(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<uint32_t>(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<size_t>(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<uint32_t>(this->size()); + WriteDWord(size); + size = static_cast<uint32_t>(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<uint64_t> &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<uint8_t> 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<const uint8_t *>(&reader.root->guid), reinterpret_cast<const uint8_t *>(&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<PDB_TYPES *>(types_data_.data()); + + size_t offset; + if (types->version < 19960000) { + const PDB_TYPES_OLD *types_old = reinterpret_cast<const PDB_TYPES_OLD *>(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<const union codeview_type*>(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<uint8_t> vsymbols, vmodimage; + + if (!reader.read_file(PDB_STREAM_DBI, vsymbols)) + return false; + symbols = reinterpret_cast<PDB_SYMBOLS*>(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<const char*>(symbols) + sizeof(PDB_SYMBOLS); + while (static_cast<size_t>(file - reinterpret_cast<const char*>(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<const PDB_SYMBOL_FILE*>(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<const PDB_SYMBOL_FILE_EX*>(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<char*>(reinterpret_cast<size_t>(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<uint64_t, std::string> 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<const p_string *>(reinterpret_cast<const char *>(&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<const p_string *>(reinterpret_cast<const char *>(&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<const char *>(&type->struct_v3.structlen) + leaf_length(&type->struct_v3.structlen)); + break; + case LF_ARGLIST_V1: + { + const union codeview_reftype *ref_type = reinterpret_cast<const union codeview_reftype *>(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<const union codeview_reftype *>(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<const p_string *>(reinterpret_cast<const char *>(&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<const p_string *>(reinterpret_cast<const char *>(&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<const char *>(&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<uint8_t> &root, size_t offset) +{ + size_t i; + int length; + for (i = offset; i < root.size(); i += length) + { + const union codeview_symbol* sym = reinterpret_cast<const union codeview_symbol*>(&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<const unsigned short*>(reinterpret_cast<const char*>(sym) + 16), + *reinterpret_cast<const unsigned*>(reinterpret_cast<const char*>(sym) + 12), + *reinterpret_cast<const unsigned*>(reinterpret_cast<const char*>(sym) + 4), + std::string(reinterpret_cast<const char*>(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<const char *>(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<uint64_t> &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<char *>(&sym.N.ShortName), strnlen(reinterpret_cast<char *>(&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); +}
\ No newline at end of file |