vmprotect-3.5.1/core/pefile.cc

6125 lines
182 KiB
C++

/**
* 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(&section_header, sizeof(section_header));
name_ = std::string(reinterpret_cast<char *>(&section_header.Name), strnlen(reinterpret_cast<char *>(&section_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(&section_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(&section_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);
}