#include "../runtime/crypto.h" #include "objects.h" #include "osutils.h" #include "streams.h" #include "files.h" #include "core.h" #include "processors.h" #include "lang.h" #include /** * AddressRange */ AddressRange::AddressRange(FunctionInfo *owner, uint64_t begin, uint64_t end, ICommand *begin_entry, ICommand *end_entry, ICommand *size_entry) : IObject(), owner_(owner), begin_(begin), end_(end), original_begin_(0), original_end_(0), begin_entry_(begin_entry), end_entry_(end_entry), size_entry_(size_entry), link_info_(NULL) { } AddressRange::AddressRange(FunctionInfo *owner, const AddressRange &src) : IObject(), owner_(owner) { begin_ = src.begin_; end_ = src.end_; begin_entry_ = src.begin_entry_; end_entry_ = src.end_entry_; size_entry_ = src.size_entry_; original_begin_ = src.original_begin_; original_end_ = src.original_end_; link_info_ = src.link_info_; } AddressRange::~AddressRange() { if (owner_) owner_->RemoveObject(this); } AddressRange *AddressRange::Clone(FunctionInfo *owner) const { AddressRange *range = new AddressRange(owner, *this); return range; } void AddressRange::Add(uint64_t address, size_t size) { if (!begin_ || begin_ > address) begin_ = address; if (!end_ || end_ < address + size) end_ = address + size; for (size_t i = 0; i < link_list_.size(); i++) { link_list_[i]->Add(address, size); } } void AddressRange::Prepare() { original_begin_ = begin_; original_end_ = end_; begin_ = 0; end_ = 0; } void AddressRange::Rebase(uint64_t delta_base) { if (begin_) begin_ += delta_base; if (end_) end_ += delta_base; } /** * FunctionInfo */ FunctionInfo::FunctionInfo() : ObjectList(), owner_(NULL), begin_(0), end_(0), base_type_(btValue), base_value_(0), prolog_size_(0), entry_(NULL), frame_registr_(0), source_(NULL), data_entry_(NULL) { } FunctionInfo::FunctionInfo(FunctionInfoList *owner, uint64_t begin, uint64_t end, AddressBaseType base_type, uint64_t base_value, size_t prolog_size, uint8_t frame_registr, IRuntimeFunction *source, ICommand *entry) : ObjectList(), owner_(owner), begin_(begin), end_(end), base_type_(base_type), base_value_(base_value), prolog_size_(prolog_size), entry_(entry), frame_registr_(frame_registr), source_(source), data_entry_(NULL) { } FunctionInfo::FunctionInfo(FunctionInfoList *owner, const FunctionInfo &src) : ObjectList(), owner_(owner) { begin_ = src.begin_; end_ = src.end_; base_type_ = src.base_type_; base_value_ = src.base_value_; prolog_size_ = src.prolog_size_; source_ = src.source_; entry_ = src.entry_; data_entry_ = src.data_entry_; frame_registr_ = src.frame_registr_; unwind_opcodes_ = src.unwind_opcodes_; for (size_t i = 0; i < src.count(); i++) { AddObject(src.item(i)->Clone(this)); } } FunctionInfo::~FunctionInfo() { if (owner_) owner_->RemoveObject(this); } FunctionInfo *FunctionInfo::Clone(FunctionInfoList *owner) const { FunctionInfo *info = new FunctionInfo(owner, *this); return info; } AddressRange *FunctionInfo::Add(uint64_t begin, uint64_t end, ICommand *begin_entry, ICommand *end_entry, ICommand *size_entry) { AddressRange *range = new AddressRange(this, begin, end, begin_entry, end_entry, size_entry); AddObject(range); return range; } AddressRange *FunctionInfo::GetRangeByAddress(uint64_t address) const { for (size_t i = 0; i < count(); i++) { AddressRange *range = item(i); if (range->begin() <= address && range->end() > address) return range; } return NULL; } void FunctionInfo::Prepare() { for (size_t i = 0; i < count(); i++) { item(i)->Prepare(); } } void FunctionInfo::Compile() { begin_ = 0; end_ = 0; for (size_t i = 0; i < count(); i++) { AddressRange *range = item(i); if (!range->begin()) continue; if (!begin_ || begin_ > range->begin()) begin_ = range->begin(); if (!end_ || end_ < range->end()) end_ = range->end(); } } void FunctionInfo::WriteToFile(IArchitecture &file) { if (begin_) { std::vector call_frame_instructions;; for (size_t i = 0; i < unwind_opcodes_.size(); i++) { ICommand *command = unwind_opcodes_[i]; for (size_t j = 0; j < command->dump_size(); j++) { call_frame_instructions.push_back(command->dump(j)); } } file.runtime_function_list()->Add(0, begin_, end_, entry_ ? entry_->address() : 0, source_, call_frame_instructions); } } void FunctionInfo::Rebase(uint64_t delta_base) { for (size_t i = 0; i < count(); i++) { item(i)->Rebase(delta_base); } if (begin_) begin_ += delta_base; if (end_) end_ += delta_base; } /** * FunctionInfoList */ FunctionInfoList::FunctionInfoList() : ObjectList() { } FunctionInfoList::FunctionInfoList(const FunctionInfoList &src) : ObjectList() { for (size_t i = 0; i < src.count(); i++) { AddObject(src.item(i)->Clone(this)); } } FunctionInfoList *FunctionInfoList::Clone() const { FunctionInfoList *list = new FunctionInfoList(*this); return list; } FunctionInfo *FunctionInfoList::GetItemByAddress(uint64_t address) const { for (size_t i = 0; i < count(); i++) { FunctionInfo *info = item(i); if (info->begin() <= address && info->end() > address) return info; } return NULL; } AddressRange *FunctionInfoList::GetRangeByAddress(uint64_t address) const { FunctionInfo *info = GetItemByAddress(address); return info ? info->GetRangeByAddress(address) : NULL; } FunctionInfo *FunctionInfoList::Add(uint64_t begin, uint64_t end, AddressBaseType base_type, uint64_t base_value, size_t prolog_size, uint8_t frame_registr, IRuntimeFunction *source, ICommand *entry) { FunctionInfo *info = new FunctionInfo(this, begin, end, base_type, base_value, prolog_size, frame_registr, source, entry); AddObject(info); return info; }; void FunctionInfoList::Prepare() { for (size_t i = 0; i < count(); i++) { item(i)->Prepare(); } } void FunctionInfoList::Compile() { for (size_t i = 0; i < count(); i++) { item(i)->Compile(); } } void FunctionInfoList::WriteToFile(IArchitecture &file) { for (size_t i = 0; i < count(); i++) { item(i)->WriteToFile(file); } } void FunctionInfoList::Rebase(uint64_t delta_base) { for (size_t i = 0; i < count(); i++) { item(i)->Rebase(delta_base); } } /** * BaseVMCommand */ BaseVMCommand::BaseVMCommand(ICommand *owner) : IVMCommand(), owner_(owner) { } BaseVMCommand::~BaseVMCommand() { if (owner_) owner_->RemoveObject(this); } /** * InternalLink */ InternalLink::InternalLink(InternalLinkList *owner, InternalLinkType type, IVMCommand *from_command, IObject *to_command) : owner_(owner), type_(type), from_command_(from_command), to_command_(to_command) { } InternalLink::~InternalLink() { if (owner_) owner_->RemoveObject(this); } /** * InternalLinkList */ InternalLink *InternalLinkList::Add(InternalLinkType type, IVMCommand *from_command, IObject *to_command) { InternalLink *link = new InternalLink(this, type, from_command, to_command); AddObject(link); return link; } /** * BaseCommand */ BaseCommand::BaseCommand(IFunction *owner) : ICommand(), owner_(owner), link_(NULL), block_(NULL), vm_address_(0), address_range_(NULL), alignment_(0), options_(roNeedCompile) { } BaseCommand::BaseCommand(IFunction *owner, const std::string &value) : ICommand(), owner_(owner), link_(NULL), block_(NULL), vm_address_(0), address_range_(NULL), alignment_(0), options_(roNeedCompile) { dump_.PushBuff(value.c_str(), value.size()); dump_.PushByte(0); } BaseCommand::BaseCommand(IFunction *owner, const os::unicode_string &value) : ICommand(), owner_(owner), link_(NULL), block_(NULL), vm_address_(0), address_range_(NULL), alignment_(0), options_(roNeedCompile) { dump_.PushBuff(value.c_str(), value.size() * sizeof(os::unicode_char)); dump_.PushWord(0); } BaseCommand::BaseCommand(IFunction *owner, const Data &value) : ICommand(), owner_(owner), link_(NULL), block_(NULL), vm_address_(0), address_range_(NULL), alignment_(0), options_(roNeedCompile) { dump_.PushBuff(value.data(), value.size()); } BaseCommand::BaseCommand(IFunction *owner, const BaseCommand &src) : ICommand(), owner_(owner), link_(NULL), block_(NULL) { dump_ = src.dump_; address_range_ = src.address_range_; comment_ = src.comment_; vm_address_ = src.vm_address_; alignment_ = src.alignment_; options_ = src.options_; } BaseCommand::~BaseCommand() { if (owner_) owner_->RemoveObject(this); } void BaseCommand::clear() { dump_.clear(); } void BaseCommand::Read(IArchitecture &file, size_t len) { uint8_t *p = new uint8_t[len]; file.Read(p, len); dump_.PushBuff(p, len); delete [] p; } uint8_t BaseCommand::ReadByte(IArchitecture &file) { uint8_t res = file.ReadByte(); PushByte(res); return res; } uint16_t BaseCommand::ReadWord(IArchitecture &file) { uint16_t res = file.ReadWord(); PushWord(res); return res; } uint32_t BaseCommand::ReadDWord(IArchitecture &file) { uint32_t res = file.ReadDWord(); PushDWord(res); return res; } uint64_t BaseCommand::ReadQWord(IArchitecture &file) { uint64_t res = file.ReadQWord(); PushQWord(res); return res; } void BaseCommand::PushByte(uint8_t value) { dump_.PushByte(value); } void BaseCommand::PushWord(uint16_t value) { dump_.PushWord(value); } void BaseCommand::PushDWord(uint32_t value) { dump_.PushDWord(value); } void BaseCommand::PushQWord(uint64_t value) { dump_.PushQWord(value); } void BaseCommand::InsertByte(size_t position, uint8_t value) { dump_.InsertByte(position, value); } void BaseCommand::WriteDWord(size_t position, uint32_t value) { dump_.WriteDWord(position, value); } void BaseCommand::CompileInfo() { if (address_range_) address_range_->Add(address(), dump_size()); } void BaseCommand::ReadFromBuffer(Buffer &buffer, IArchitecture &file) { options_ = buffer.ReadDWord() & (roNeedCompile | roInverseFlag | roClearOriginalCode | roCreateNewBlock | roLockPrefix | roExternal | roBreaked | roVexPrefix); alignment_ = buffer.ReadByte(); } void BaseCommand::WriteToFile(IArchitecture &file) { file.Write(dump_.data(), dump_.size()); } CommandLink *BaseCommand::AddLink(int operand_index, LinkType type, uint64_t to_address) { return owner_->link_list()->Add(this, operand_index, type, to_address); } CommandLink *BaseCommand::AddLink(int operand_index, LinkType type, ICommand *to_command) { return owner_->link_list()->Add(this, operand_index, type, to_command); } size_t BaseCommand::vm_dump_size() const { size_t res = 0; for (size_t i = 0; i < count(); i++) { res += item(i)->dump_size(); } return res; } void BaseCommand::set_vm_address(uint64_t address) { vm_address_ = address; bool backward_direction = (section_options() & rtBackwardDirection) != 0; for (size_t i = 0; i < count(); i++) { IVMCommand *vm_command = item(i); vm_command->set_address(address); if (backward_direction) { address -= vm_command->dump_size(); } else { address += vm_command->dump_size(); } } } void BaseCommand::set_dump(const void *buffer, size_t size) { dump_.clear(); dump_.PushBuff(buffer, size); } bool BaseCommand::CompareDump(const uint8_t *buffer, size_t size) const { if (dump_.size() != size) return false; for (size_t i = 0; i < size; i++) { if (dump_[i] != buffer[i]) return false; } return true; } std::string BaseCommand::dump_str() const { std::string res; for (size_t i = 0; i < dump_size(); i++) { res += string_format("%.2X", dump(i)); } return res; } uint64_t BaseCommand::dump_value(size_t pos, OperandSize size) const { if (size > osQWord) throw std::runtime_error("Invalid value size"); uint64_t res = 0; memcpy(&res, &dump_[pos], OperandSizeToValue(size)); return res; } /** * ValueCommand */ ValueCommand::ValueCommand(ValueCryptor *owner, OperandSize size, CryptCommandType type, uint64_t value) : IObject(), owner_(owner), type_(type), size_(size) { switch (size_) { case osByte: value_ = static_cast(value); break; case osWord: value_ = static_cast(value); break; case osDWord: value_ = static_cast(value); break; default: value_ = value; } } ValueCommand::ValueCommand(ValueCryptor *owner, const ValueCommand &src) : IObject(), owner_(owner) { size_ = src.size_; type_ = src.type_; value_ = src.value_; } ValueCommand *ValueCommand::Clone(ValueCryptor *owner) const { ValueCommand *command = new ValueCommand(owner, *this); return command; } ValueCommand::~ValueCommand() { if (owner_) owner_->RemoveObject(this); } CryptCommandType ValueCommand::type(bool is_decrypt) const { CryptCommandType command = type_; if (is_decrypt) { switch (command) { case ccAdd: command = ccSub; break; case ccSub: command = ccAdd; break; case ccInc: command = ccDec; break; case ccDec: command = ccInc; break; case ccRol: command = ccRor; break; case ccRor: command = ccRol; break; } } return command; } uint64_t ValueCommand::Encrypt(uint64_t value) { return Calc(value, false); } uint64_t ValueCommand::Decrypt(uint64_t value) { return Calc(value, true); } uint64_t ValueCommand::Calc(uint64_t value, bool is_decrypt) { switch (type(is_decrypt)) { case ccAdd: case ccInc: value += value_; break; case ccSub: case ccDec: value -= value_; break; case ccXor: value ^= value_; break; case ccNot: value = ~value; break; case ccNeg: value = 0 - value; break; case ccBswap: switch (size_) { case osWord: value = __builtin_bswap16(static_cast(value)); break; case osDWord: value = __builtin_bswap32(static_cast(value)); break; case osQWord: value = __builtin_bswap64(value); break; } break; case ccRol: switch (size_) { case osByte: value = _rotl8(static_cast(value), static_cast(value_)); break; case osWord: value = _rotl16(static_cast(value), static_cast(value_)); break; case osDWord: value = _rotl32(static_cast(value), static_cast(value_)); break; case osQWord: value = _rotl64(value, static_cast(value_)); break; } break; case ccRor: switch (size_) { case osByte: value = _rotr8(static_cast(value), static_cast(value_)); break; case osWord: value = _rotr16(static_cast(value), static_cast(value_)); break; case osDWord: value = _rotr32(static_cast(value), static_cast(value_)); break; case osQWord: value = _rotr64(value, static_cast(value_)); break; } break; } return value; } /** * ValueCryptor */ ValueCryptor::ValueCryptor() : ObjectList(), size_(osByte) { } ValueCryptor::ValueCryptor(const ValueCryptor &src) : ObjectList(src) { for (size_t i = 0; i < src.count(); i++) { AddObject(src.item(i)->Clone(this)); } size_ = src.size_; } ValueCryptor *ValueCryptor::Clone() const { ValueCryptor *cryptor = new ValueCryptor(*this); return cryptor; } uint64_t ValueCryptor::Encrypt(uint64_t value) { size_t i; for (i = 0; i < count(); i++) { value = item(i)->Encrypt(value); } return value; } uint64_t ValueCryptor::Decrypt(uint64_t value) { size_t i; for (i = count(); i > 0; i--) { value = item(i - 1)->Decrypt(value); } return value; } void ValueCryptor::Init(OperandSize size) { clear(); size_ = size; CryptCommandType last_command = ccUnknown; for (;;) { CryptCommandType command = static_cast(rand() % ccUnknown); if (command == last_command) continue; uint64_t value = 0; switch (command) { case ccAdd: case ccSub: if (last_command == ccAdd || last_command == ccSub || last_command == ccInc || last_command == ccDec) continue; value = DWordToInt64(rand32()); break; case ccInc: case ccDec: if (last_command == ccAdd || last_command == ccSub || last_command == ccInc || last_command == ccDec) continue; value = 1; break; case ccXor: value = DWordToInt64(rand32()); break; case ccBswap: if (size_ == osByte || size_ == osWord) continue; break; case ccRol: case ccRor: if (last_command == ccRol || last_command == ccRor) continue; value = rand() % BYTES_TO_BITS(OperandSizeToValue(size_)); if (!value) value = 1; break; } last_command = command; Add(command, value); size_t c = count(); if (c > 100 || (c > 3 && (rand() & 1))) break; } } void ValueCryptor::Add(CryptCommandType command, uint64_t value) { AddObject(new ValueCommand(this, size_, command, value)); } /** * OpcodeCryptor */ OpcodeCryptor::OpcodeCryptor() : ValueCryptor(), type_(ccUnknown) { } void OpcodeCryptor::Init(OperandSize size) { //static CryptCommandType opcode_commands[] = {ccAdd, ccSub, ccXor}; //type_ = opcode_commands[rand() % _countof(opcode_commands)]; type_ = ccXor; ValueCryptor::Init(size); } uint64_t OpcodeCryptor::EncryptOpcode(uint64_t value1, uint64_t value2) { return Calc(value1, value2, false); } uint64_t OpcodeCryptor::DecryptOpcode(uint64_t value1, uint64_t value2) { return Calc(value1, value2, true); } uint64_t OpcodeCryptor::Calc(uint64_t value1, uint64_t value2, bool is_decrypt) { CryptCommandType command = type_; if (is_decrypt) { switch (command) { case ccAdd: command = ccSub; break; case ccSub: command = ccAdd; break; } } switch (command) { case ccAdd: return value1 + value2; case ccSub: return value1 - value2; case ccXor: return value1 ^ value2; } return 0; } /** * CommandLink */ CommandLink::CommandLink(CommandLinkList *owner, ICommand *from_command, int operand_index, LinkType type, uint64_t to_address) : IObject(), owner_(owner), parsed_(false), from_command_(from_command), parent_command_(NULL), to_command_(NULL), next_command_(NULL), type_(type), to_address_(to_address), operand_index_(operand_index), sub_value_(0), cryptor_(NULL), base_function_info_(NULL), is_inverse_(false) { if (from_command_) from_command_->set_link(this); } CommandLink::CommandLink(CommandLinkList *owner, ICommand *from_command, int operand_index, LinkType type, ICommand *to_command) : IObject(), owner_(owner), parsed_(false), from_command_(from_command), parent_command_(NULL), to_command_(to_command), next_command_(NULL), type_(type), to_address_(0), operand_index_(operand_index), sub_value_(0), cryptor_(NULL), base_function_info_(NULL), is_inverse_(false) { if (from_command_) from_command_->set_link(this); } CommandLink::CommandLink(CommandLinkList *owner, const CommandLink &src) : IObject(src), owner_(owner), from_command_(NULL), parent_command_(NULL), to_command_(NULL), next_command_(NULL) { parsed_ = src.parsed_; type_ = src.type_; to_address_ = src.to_address_; operand_index_ = src.operand_index_; sub_value_ = src.sub_value_; cryptor_ = src.cryptor_; base_function_info_ = src.base_function_info_; is_inverse_ = src.is_inverse_; } CommandLink::~CommandLink() { if (from_command_) from_command_->set_link(NULL); if (owner_) owner_->RemoveObject(this); delete cryptor_; } CommandLink *CommandLink::Clone(CommandLinkList *owner) const { CommandLink *link = new CommandLink(owner, *this); return link; } void CommandLink::set_from_command(ICommand *command) { if (from_command_ == command) return; if (from_command_) from_command_->set_link(NULL); from_command_ = command; if (from_command_) from_command_->set_link(this); } void CommandLink::Rebase(uint64_t delta_base) { if (sub_value_) sub_value_ += delta_base; if (to_address_) to_address_ += delta_base; } void CommandLink::set_cryptor(ValueCryptor *cryptor) { if (cryptor) { cryptor_ = cryptor->Clone(); } else { delete cryptor_; cryptor_ = NULL; } } uint64_t CommandLink::Encrypt(uint64_t value) const { uint64_t sub_value = base_function_info_ ? base_function_info_->begin() + base_function_info_->base_value() : sub_value_; if (is_inverse_) value = sub_value - value; else value = value - sub_value; if (cryptor_) value = cryptor_->Encrypt(value); return value; } /** * CommandLinkList */ CommandLinkList::CommandLinkList() : ObjectList() { } CommandLinkList::CommandLinkList(const CommandLinkList &src) : ObjectList(src) { for (size_t i = 0; i < src.count(); i++) { AddObject(src.item(i)->Clone(this)); } } CommandLinkList *CommandLinkList::Clone() const { CommandLinkList *list = new CommandLinkList(*this); return list; } CommandLink *CommandLinkList::Add(ICommand *from_command, int operand_index, LinkType type, uint64_t to_address) { CommandLink *link = new CommandLink(this, from_command, operand_index, type, to_address); AddObject(link); return link; }; CommandLink *CommandLinkList::Add(ICommand *from_command, int operand_index, LinkType type, ICommand *to_command) { CommandLink *link = new CommandLink(this, from_command, operand_index, type, to_command); AddObject(link); return link; }; CommandLink *CommandLinkList::GetLinkByToAddress(LinkType type, uint64_t to_address) { for (size_t i = 0; i < count(); i++) { CommandLink *link = item(i); if (link->to_address() == to_address && (type == ltNone || link->type() == type)) return link; } return NULL; } void CommandLinkList::Rebase(uint64_t delta_base) { for (size_t i = 0; i < count(); i++) { item(i)->Rebase(delta_base); } } /** * ExtCommand */ ExtCommand::ExtCommand(ExtCommandList *owner, uint64_t address, ICommand *command, bool use_call) : IObject(), owner_(owner), address_(address), command_(command), use_call_(use_call) { } ExtCommand::ExtCommand(ExtCommandList *owner, const ExtCommand &src) : IObject(src), owner_(owner) { address_ = src.address_; command_ = src.command_; use_call_ = src.use_call_; } ExtCommand::~ExtCommand() { if (owner_) owner_->RemoveObject(this); } ExtCommand *ExtCommand::Clone(ExtCommandList *owner) const { ExtCommand *ext_command = new ExtCommand(owner, *this); return ext_command; } int ExtCommand::CompareWith(const ExtCommand &obj) const { if (address() < obj.address()) return -1; if (address() > obj.address()) return 1; return 0; } /** * ExtCommandList */ ExtCommandList::ExtCommandList(IFunction *owner) : ObjectList(), owner_(owner) { } ExtCommandList::ExtCommandList(IFunction *owner, const ExtCommandList &src) : ObjectList(src), owner_(owner) { for (size_t i = 0; i < src.count(); i++) { AddObject(src.item(i)->Clone(this)); } } ExtCommandList *ExtCommandList::Clone(IFunction *owner) const { ExtCommandList *list = new ExtCommandList(owner, *this); return list; } ExtCommand *ExtCommandList::GetCommandByAddress(uint64_t address) const { for (size_t i = 0; i < count(); i++) { ExtCommand *ext_command = item(i); if (ext_command->address() == address) return ext_command; } return NULL; } ExtCommand *ExtCommandList::Add(uint64_t address, ICommand *command, bool use_call) { ExtCommand *ext_command = new ExtCommand(this, address, command, use_call); AddObject(ext_command); return ext_command; } ExtCommand *ExtCommandList::Add(uint64_t address) { ExtCommand *ext_command = GetCommandByAddress(address); if (ext_command) return ext_command; if (owner_->address() == address || owner_->type() == otString) return NULL; ICommand *command = owner_->GetCommandByAddress(address); if (!command) return NULL; return Add(address, command); } void ExtCommandList::AddObject(ExtCommand *ext_command) { ObjectList::AddObject(ext_command); if (owner_) owner_->Notify(mtAdded, ext_command); } void ExtCommandList::RemoveObject(ExtCommand *ext_command) { ObjectList::RemoveObject(ext_command); if (owner_) owner_->Notify(mtDeleted, ext_command); } /** * CommandBlock */ CommandBlock::CommandBlock(CommandBlockList *owner, uint32_t type, size_t start_index) : AddressableObject(), owner_(owner), type_(type), start_index_(start_index), end_index_(start_index), virtual_machine_(NULL), sort_index_(0) { registr_count_ = (function()->cpu_address_size() == osDWord) ? 16 : 24; memset(registr_indexes_, 0xff, sizeof(registr_indexes_)); } CommandBlock::CommandBlock(CommandBlockList *owner, const CommandBlock &src) : AddressableObject(src), owner_(owner), virtual_machine_(NULL), sort_index_(0) { type_ = src.type_; start_index_ = src.start_index_; end_index_ = src.end_index_; registr_count_ = src.registr_count_; } CommandBlock::~CommandBlock() { if (owner_) owner_->RemoveObject(this); } CommandBlock *CommandBlock::Clone(CommandBlockList *owner) { CommandBlock *block = new CommandBlock(owner, *this); return block; } IFunction *CommandBlock::function() const { return owner_->owner(); } void CommandBlock::Compile(MemoryManager &manager) { size_t i, memory_size, alignment; ICommand *command; uint64_t address; IFunction *func = function(); memory_size = 0; if (type_ & mtExecutable) { alignment = func->item(start_index_)->alignment(); for (i = start_index_; i <= end_index_; i++) { command = func->item(i); memory_size += command->dump_size(); } } else { alignment = 0; #ifndef DEMO ICommand *stor_command = NULL; for (i = start_index_; i <= end_index_; i++) { command = func->item(i); if (command->is_data()) { stor_command = NULL; } else if (!stor_command || (command->section_options() & rtBeginSection)) { stor_command = command; } else if (command->section_options() & rtEndSection) { stor_command->Merge(command); stor_command = NULL; } else if (!command->Merge(stor_command)) { stor_command->Merge(command); stor_command = command; } } #endif for (i = start_index_; i <= end_index_; i++) { command = func->item(i); for (size_t j = 0; j < command->count(); j++) { command->item(j)->Compile(); } memory_size += command->vm_dump_size(); } } if (memory_size) { address = (address_) ? address_ : manager.Alloc(memory_size, type_, 0, alignment); if (type_ & mtExecutable) { // native block for (i = start_index_; i <= end_index_; i++) { command = func->item(i); command->set_address(address); address += command->dump_size(); } } else { // VM block bool backward_direction = (func->item(start_index_)->section_options() & rtBackwardDirection) != 0; if (backward_direction) address += memory_size; for (i = start_index_; i <= end_index_; i++) { command = func->item(i); command->set_vm_address(address); if (backward_direction) { address -= command->vm_dump_size(); } else { address += command->vm_dump_size(); } } } } } void CommandBlock::CompileInfo() { IFunction *func = function(); for (size_t i = start_index_; i <= end_index_; i++) { ICommand *command = func->item(i); command->CompileInfo(); } } void CommandBlock::CompileLinks(const CompileContext &ctx) { IFunction *func = function(); for (size_t i = start_index_; i <= end_index_; i++) { ICommand *command = func->item(i); command->CompileLink(ctx); } } size_t CommandBlock::WriteToFile(IArchitecture &file) { size_t i, j; ICommand *command; IVMCommand *vm_command; uint32_t update_type; IFunction *func = function(); update_type = type_; if (func->memory_type() != mtNone && (update_type & mtDiscardable) == 0) update_type |= mtNotDiscardable; if (type_ & mtExecutable) { // native block for (i = start_index_; i <= end_index_; i++) { file.StepProgress(); command = func->item(i); if (!file.AddressSeek(command->address())) throw std::runtime_error("Invalid command address"); file.selected_segment()->include_write_type(update_type); command->WriteToFile(file); } } else { // VM block if (func->item(start_index_)->section_options() & rtBackwardDirection) { for (i = end_index_ + 1; i > start_index_ ; i--) { file.StepProgress(); command = func->item(i - 1); if (!file.AddressSeek(command->vm_address() - command->vm_dump_size())) throw std::runtime_error("Invalid command address"); for (j = command->count(); j > 0; j--) { vm_command = command->item(j - 1); file.selected_segment()->include_write_type(update_type); vm_command->WriteToFile(file); } } } else { for (i = start_index_; i <= end_index_; i++) { file.StepProgress(); command = func->item(i); if (!file.AddressSeek(command->vm_address())) throw std::runtime_error("Invalid command address"); for (j = 0; j < command->count(); j++) { vm_command = command->item(j); file.selected_segment()->include_write_type(update_type); vm_command->WriteToFile(file); } } } } return end_index_ - start_index_ + 1; } uint8_t CommandBlock::GetRegistr(OperandSize size, uint8_t registr, bool is_write) { uint8_t res; OperandSize cpu_address_size = function()->cpu_address_size(); if (registr & regExtended) { res = (uint8_t)(registr_count_ + (registr & 0xf)); } else if (registr == regEmpty && !is_write) { res = (uint8_t)(rand() % registr_count_); } else { if(registr >= _countof(registr_indexes_)) throw std::runtime_error("Runtime error at GetRegistr"); res = registr_indexes_[registr]; if (res == 0xff || (is_write && size == cpu_address_size)) { uint8_t empty_registr[_countof(registr_indexes_)]; size_t empty_registr_count = 0; for (size_t i = 0; i < registr_count_; i++) { bool is_found = false; for (size_t j = 0; j < regEmpty; j++) { if (registr_indexes_[j] == i) { is_found = true; break; } } if (!is_found) { empty_registr[empty_registr_count] = (uint8_t)i; empty_registr_count++; } } if (empty_registr_count) { res = empty_registr[rand() % empty_registr_count]; if (registr != regEmpty) registr_indexes_[registr] = res; } else if (res == 0xff) throw std::runtime_error("Runtime error at GetRegistr"); } } return (uint8_t)(res * OperandSizeToValue(cpu_address_size)); } /** * CommandBlockList */ CommandBlockList::CommandBlockList(IFunction *owner) : ObjectList(), owner_(owner) { } CommandBlockList::CommandBlockList(IFunction *owner, const CommandBlockList &src) : ObjectList(src), owner_(owner) { for (size_t i = 0; i < src.count(); i++) { AddObject(src.item(i)->Clone(this)); } } CommandBlockList *CommandBlockList::Clone(IFunction *owner) const { CommandBlockList *list = new CommandBlockList(owner, *this); return list; } CommandBlock *CommandBlockList::Add(uint32_t memory_type, size_t start_index) { CommandBlock *block = new CommandBlock(this, memory_type, start_index); AddObject(block); return block; } void CommandBlockList::CompileBlocks(MemoryManager &manager) { for (size_t i = 0; i < count(); i++) { item(i)->Compile(manager); } } void CommandBlockList::CompileInfo() { for (size_t i = 0; i < count(); i++) { CommandBlock *block = item(i); if (block->type() & mtExecutable) block->CompileInfo(); } } void CommandBlockList::CompileLinks(const CompileContext &ctx) { size_t i; CommandBlock *block; for (i = 0; i < count(); i++) { block = item(i); if ((block->type() & mtExecutable) == 0) continue; block->CompileLinks(ctx); } for (i = 0; i < count(); i++) { block = item(i); if ((block->type() & mtExecutable) != 0) continue; block->CompileLinks(ctx); } } size_t CommandBlockList::WriteToFile(IArchitecture &file) { size_t res = 0; for (size_t i = 0; i < count(); i++) { CommandBlock *block = item(i); res += block->WriteToFile(file); } return res; } /** * BaseFunction */ BaseFunction::BaseFunction(IFunctionList *owner, const FunctionName &name, CompilationType compilation_type, uint32_t compilation_options, bool need_compile, Folder *folder) : IFunction(), owner_(owner), name_(name), address_(0), break_address_(0), type_(otUnknown), cpu_address_size_(osDefault), compilation_type_(compilation_type), compilation_options_(compilation_options), internal_lock_to_key_(false), default_compilation_type_(ctNone), need_compile_(need_compile), folder_(folder), memory_type_(mtNone), tag_(0), entry_(NULL), entry_type_(etDefault), from_runtime_(false), parent_(NULL) { link_list_ = new CommandLinkList(); ext_command_list_ = new ExtCommandList(this); block_list_ = new CommandBlockList(this); function_info_list_ = new FunctionInfoList(); range_list_ = new FunctionInfo(); } BaseFunction::BaseFunction(IFunctionList *owner, OperandSize cpu_address_size, IFunction *parent) : IFunction(), owner_(owner), address_(0), break_address_(0), type_(otCode), cpu_address_size_(cpu_address_size), compilation_type_(ctVirtualization), compilation_options_(0), internal_lock_to_key_(false), default_compilation_type_(ctNone), need_compile_(true), folder_(NULL), memory_type_(mtReadable), tag_(0), entry_(NULL), entry_type_(etDefault), from_runtime_(false), parent_(parent) { link_list_ = new CommandLinkList(); ext_command_list_ = new ExtCommandList(this); block_list_ = new CommandBlockList(this); function_info_list_ = new FunctionInfoList(); range_list_ = new FunctionInfo(); } BaseFunction::BaseFunction(IFunctionList *owner, const BaseFunction &src) : IFunction(src), owner_(owner), folder_(NULL), parent_(NULL) { size_t i, j; address_ = src.address_; type_ = src.type_; entry_ = NULL; entry_type_ = src.entry_type_; break_address_ = src.break_address_; name_ = src.name_; cpu_address_size_ = src.cpu_address_size_; need_compile_ = src.need_compile_; compilation_type_ =src.compilation_type_; compilation_options_ = src.compilation_options_; internal_lock_to_key_ = src.internal_lock_to_key_; default_compilation_type_ = src.default_compilation_type_; memory_type_ = src.memory_type_; tag_ = src.tag_; from_runtime_ = src.from_runtime_; link_list_ = src.link_list_->Clone(); ext_command_list_ = src.ext_command_list_->Clone(this); block_list_ = src.block_list_->Clone(this); function_info_list_ = src.function_info_list_->Clone(); range_list_ = src.range_list_->Clone(NULL); for (i = 0; i < src.count(); i++) { ICommand *command = src.item(i)->Clone(this); AddObject(command); AddressRange *address_range = command->address_range(); if (address_range) { FunctionInfo *info = function_info_list_->item(src.function_info_list()->IndexOf(address_range->owner())); command->set_address_range(info->item(address_range->owner()->IndexOf(address_range))); } } for (i = 0; i < range_list_->count(); i++) { AddressRange *range = range_list_->item(i); if (range->begin_entry()) range->set_begin_entry(item(src.IndexOf(range->begin_entry()))); if (range->end_entry()) range->set_end_entry(item(src.IndexOf(range->end_entry()))); if (range->size_entry()) range->set_size_entry(item(src.IndexOf(range->size_entry()))); } for (i = 0; i < function_info_list()->count(); i++) { FunctionInfo *info = function_info_list()->item(i); if (info->entry()) info->set_entry(item(src.IndexOf(info->entry()))); if (info->data_entry()) info->set_data_entry(item(src.IndexOf(info->data_entry()))); std::vector unwind_opcodes = *info->unwind_opcodes(); for (j = 0; j < unwind_opcodes.size(); j++) { unwind_opcodes[j] = item(src.IndexOf(unwind_opcodes[j])); } info->set_unwind_opcodes(unwind_opcodes); } if (src.entry_) entry_ = item(src.IndexOf(src.entry_)); for (i = 0; i < src.count(); i++) { CommandLink *src_link = src.item(i)->link(); if (!src_link) continue; CommandLink *link = link_list_->item(src.link_list()->IndexOf(src_link)); link->set_from_command(item(i)); if (src_link->parent_command()) link->set_parent_command(item(src.IndexOf(src_link->parent_command()))); if (src_link->base_function_info()) link->set_base_function_info(function_info_list()->item(src.function_info_list()->IndexOf(src_link->base_function_info()))); } for (i = 0; i < src.ext_command_list()->count(); i++) { ExtCommand *ext_command = src.ext_command_list()->item(i); if (!ext_command->command()) continue; ext_command_list_->item(i)->set_command(item(src.IndexOf(ext_command->command()))); } } BaseFunction::~BaseFunction() { if (owner_) owner_->RemoveObject(this); delete link_list_; delete ext_command_list_; delete block_list_; delete function_info_list_; delete range_list_; } void BaseFunction::AddObject(ICommand *command) { ObjectList::AddObject(command); if (command->address()) map_[command->address()] = command; } void BaseFunction::RemoveObject(ICommand *command) { for (map_command_list_t::iterator it = map_.begin(); it != map_.end(); it++) { if (it->second == command) { map_.erase(it); break; } } IFunction::RemoveObject(command); } ICommand *BaseFunction::GetCommandByLowerAddress(uint64_t address) const { if (map_.empty()) return NULL; map_command_list_t::const_iterator it = map_.upper_bound(address); if (it != map_.begin()) it--; return it->first > address ? NULL : it->second; } ICommand *BaseFunction::GetCommandByUpperAddress(uint64_t address) const { if (map_.empty()) return NULL; map_command_list_t::const_iterator it = map_.upper_bound(address); if (it == map_.end()) return NULL; return it->second; } ICommand *BaseFunction::GetCommandByNearAddress(uint64_t address) const { ICommand *command = GetCommandByLowerAddress(address); if (command && command->address() <= address && command->address() + command->original_dump_size() > address) return command; return NULL; } ICommand *BaseFunction::GetCommandByAddress(uint64_t address) const { ICommand *command = GetCommandByLowerAddress(address); if (command && command->address() == address) return command; return NULL; } uint64_t BaseFunction::GetNextAddress(IArchitecture &file) { size_t i, j; uint64_t max_address; CommandLink *link; LinkType link_type; uint64_t to_address; for (i = 0; i < link_list_->count(); i++) { link = link_list_->item(i); link_type = link->type(); if (link->parsed() || link_type == ltCall) continue; to_address = link->to_address(); if (link_type == ltNone || link_type == ltOffset || link_type == ltDelta || GetCommandByNearAddress(to_address)) { link->set_parsed(true); } else if (to_address < address_) { link->set_parsed(true); if (parent() && (link_type == ltJmp || link_type == ltJmpWithFlag)) { IFunction *func = parent(); while (func) { if (to_address > func->address()) { address_ = to_address; return to_address; } func = func->parent(); } } } else if (link_type == ltJmp) { if (file.runtime_function_list()) { IRuntimeFunction *runtime_function = file.runtime_function_list()->GetFunctionByAddress(link->from_command()->address()); if (runtime_function && to_address >= runtime_function->begin() && to_address < runtime_function->end()) { link->set_parsed(true); return to_address; } } } else { link->set_parsed(true); return to_address; } } max_address = address_; for (i = 0; i < link_list_->count(); i++) { link = link_list_->item(i); switch (link->type()) { case ltSEHBlock: case ltFinallyBlock: case ltDualSEHBlock: case ltFilterSEHBlock: case ltJmpWithFlag: if (link->to_address() > max_address) max_address = link->to_address(); break; } } for (i = 0; i < link_list_->count(); i++) { link = link_list_->item(i); if (link->parsed()) continue; to_address = link->to_address(); if (link->type() == ltJmp && to_address < max_address) { link->set_parsed(true); return to_address; } } for (i = 0; i < link_list_->count(); i++) { link = link_list_->item(i); if (link->parsed() || link->type() != ltJmp) continue; // backward/forward jump bool res = false; to_address = link->to_address(); if (parent()) { res = true; } else { bool is_forward_aligned = to_address > link->from_command()->address() && (to_address & 0x0f) == 0; IFunction *temp_func = CreateFunction(this); temp_func->ReadFromFile(file, to_address); for (j = 0; j < temp_func->count(); j++) { ICommand *command = temp_func->item(j); CommandLink *temp_link = command->link(); if (temp_link && (temp_link->type() == ltJmp || temp_link->type() == ltJmpWithFlag)) { if (GetCommandByAddress(temp_link->to_address()) || (is_forward_aligned && temp_link->to_address() == to_address) || (temp_link->type() == ltJmpWithFlag && temp_link->to_address() == link->from_command()->next_address())) { res = true; break; } } if (command->is_data() || command->is_end() || (command->options() & roBreaked)) continue; if (command->next_address() == to_address) { res = true; break; } } delete temp_func; } if (res) { link->set_parsed(true); return to_address; } } return 0; } void BaseFunction::clear() { address_ = 0; break_address_ = 0; type_ = otUnknown; entry_ = NULL; entry_type_ = etDefault; name_.clear(); internal_lock_to_key_ = false; default_compilation_type_ = ctNone; ClearItems(); } void BaseFunction::ClearItems() { map_.clear(); link_list_->clear(); ext_command_list_->clear(); block_list_->clear(); function_info_list_->clear(); range_list_->clear(); IFunction::clear(); } size_t BaseFunction::ReadFromFile(IArchitecture &file, uint64_t address) { MapFunction *map_function; ICommand *command; ISectionList *segment_list; uint64_t def_parsed_address, parsed_address; size_t i; Reference *ref; ReferenceList *reference_list; clear(); address_ = address; cpu_address_size_ = file.cpu_address_size(); memory_type_ = file.segment_list()->GetMemoryTypeByAddress(address); map_function = file.map_function_list()->GetFunctionByAddress(address); if (map_function) { default_compilation_type_ = map_function->compilation_type(); internal_lock_to_key_ = map_function->lock_to_key(); name_ = map_function->full_name(); type_ = map_function->type(); } else { name_.clear(); type_ = otCode; } ParseBeginCommands(file); if (type_ == otString) { if (map_function) { ParseString(file, address_, static_cast(map_function->end_address() - address_)); reference_list = map_function->equal_address_list(); for (i = 0; i < reference_list->count(); i++) { ref = reference_list->item(i); ParseString(file, ref->address(), static_cast(ref->operand_address() - ref->address())); } } } else { segment_list = file.segment_list(); def_parsed_address = -1; parsed_address = def_parsed_address; IRuntimeFunctionList *runtime_function_list = file.runtime_function_list(); IRuntimeFunction *runtime_function = NULL; for (;;) { command = NULL; if (address < parsed_address && (segment_list->GetMemoryTypeByAddress(address) & mtExecutable)) { if (runtime_function_list) { if (runtime_function && (address < runtime_function->begin() || address >= runtime_function->end())) runtime_function = NULL; if (!runtime_function) runtime_function = runtime_function_list->GetFunctionByAddress(address); if (runtime_function) runtime_function->Parse(file, *this); } command = ParseCommand(file, address); } if (!command || command->is_end() || (command->options() & roBreaked) != 0) { address = GetNextAddress(file); if (!address) break; command = GetCommandByUpperAddress(address); parsed_address = command ? command->address() : def_parsed_address; } else { address = command->next_address(); } } } ParseEndCommands(file); Sort(); if (type_ != otString) entry_ = GetCommandByAddress(address_); return count(); } bool BaseFunction::FreeByManager(const CompileContext &ctx) { MemoryManager *manager = ctx.manager; uint64_t block_address = 0; size_t block_size = 0; uint32_t block_memory_type = mtNone; ISectionList *segment_list = (from_runtime() ? ctx.runtime : ctx.file)->segment_list(); for (size_t i = 0; i < count(); i++) { ICommand *command = item(i); if (command->address() && (command->options() & roClearOriginalCode) && !is_breaked_address(command->address())) { for (size_t j = 0; j < command->original_dump_size(); j++) { MemoryRegion *region = manager->GetRegionByAddress(command->address() + j); if (region) { IFunction *func = region->parent_function(); uint64_t func_address; std::string func_name; if (func) { func_name = func->name(); func_address = func->address(); } else { func_name.clear(); func_address = region->address(); } if (func_name.empty()) func_name = string_format("%.8llX", func_address); ctx.file->Notify(mtError, command, string_format(language[lsAddressUsedByFunction].c_str(), func_name.c_str())); return false; } } uint32_t command_memory_type = segment_list->GetMemoryTypeByAddress(command->address()); if (block_address && ((block_address + block_size) != command->address() || block_memory_type != command_memory_type)) { if (block_size) manager->Add(block_address, block_size, block_memory_type, this); block_address = 0; block_size = 0; block_memory_type = mtNone; } if (!block_address) { block_address = command->address(); block_memory_type = command_memory_type; } block_size += command->original_dump_size(); } } if (block_size) manager->Add(block_address, block_size, block_memory_type, this); return true; } bool BaseFunction::PrepareExtCommands(const CompileContext &ctx) { return true; } bool BaseFunction::PrepareLinks(const CompileContext &ctx) { IFunctionList *function_list = ctx.file->function_list(); for (size_t i = 0; i < link_list_->count(); i++) { CommandLink *link = link_list_->item(i); if (link->type() == ltNone) continue; if (link->to_address()) { ICommand *command = function_list->GetCommandByAddress(link->to_address(), true); if (is_breaked_address(link->from_command()->address())) { if (command && command->owner()->address() != link->to_address() && !command->owner()->ext_command_list()->GetCommandByAddress(link->to_address())) ctx.file->Notify(mtWarning, link->from_command(), string_format(language[lsJumpToInternalAddress].c_str(), link->to_address())); continue; } else { if (!command && function_list->GetCommandByNearAddress(link->to_address(), true)) { ctx.file->Notify(mtError, link->from_command(), language[lsJumpToCommandPart]); return false; } link->set_to_command(command && (command->options() & roNeedCompile) ? command : NULL); } } link->from_command()->PrepareLink(ctx); } return true; } bool BaseFunction::Init(const CompileContext &/*ctx*/) { ICommand *command; size_t i; if (function_info_list()->count()) { std::set address_list; FunctionInfo *info; AddressRange *range; for (i = 0; i < function_info_list_->count(); i++) { info = function_info_list_->item(i); address_list.insert(info->begin()); address_list.insert(info->end()); } for (i = 0; i < range_list_->count(); i++) { range = range_list_->item(i); info = function_info_list_->GetItemByAddress(range->begin()); if (!info) continue; range->set_link_info(info); if (!range->end()) range->set_end(info->end()); address_list.insert(range->begin()); address_list.insert(range->end()); } uint64_t begin = 0; for (std::set::const_iterator it = address_list.begin(); it != address_list.end(); it++) { if (begin) { uint64_t end = *it; info = function_info_list_->GetItemByAddress(begin); if (info) { AddressRange *dest = info->Add(begin, end, NULL, NULL, NULL); for (i = 0; i < range_list_->count(); i++) { range = range_list_->item(i); if (range->begin() <= begin && range->end() > begin) dest->AddLink(range); } } } begin = *it; } for (i = 0; i < count(); i++) { command = item(i); if (command->address_range()) continue; command->set_address_range(function_info_list_->GetRangeByAddress(command->address())); } } return true; } bool BaseFunction::Prepare(const CompileContext &ctx) { if (!FreeByManager(ctx)) return false; range_list()->Prepare(); function_info_list()->Prepare(); return true; } bool BaseFunction::Compile(const CompileContext &ctx) { return true; } void BaseFunction::AfterCompile(const CompileContext &ctx) { } void BaseFunction::CompileInfo(const CompileContext &ctx) { block_list()->CompileInfo(); function_info_list()->Compile(); } void BaseFunction::CompileLinks(const CompileContext &ctx) { block_list()->CompileLinks(ctx); } size_t BaseFunction::WriteToFile(IArchitecture &file) { size_t res = block_list_->WriteToFile(file); function_info_list_->WriteToFile(file); return res; } void BaseFunction::ReadFromBuffer(Buffer &buffer, IArchitecture &file) { size_t i, j, c; ICommand *command; uint64_t add_address = file.image_base(); tag_ = buffer.ReadByte(); uint8_t b = buffer.ReadByte(); switch (b & 0x30) { case 0x10: entry_type_ = etNone; break; case 0x20: entry_type_ = etRandomAddress; break; } compilation_type_ =static_cast(b & 0xf); type_ = static_cast(buffer.ReadByte()); cpu_address_size_ = static_cast(buffer.ReadByte()); address_ = buffer.ReadDWord() + add_address; c = buffer.ReadDWord(); for (i = 0; i < c; i++) { command = CreateCommand(); command->ReadFromBuffer(buffer, file); AddObject(command); } c = buffer.ReadDWord(); for (i = 0; i < c; i++) { uint32_t begin = buffer.ReadDWord(); uint32_t end = buffer.ReadDWord(); AddressBaseType base_type = static_cast(buffer.ReadByte()); uint32_t base_value = (base_type == btValue) ? buffer.ReadDWord() : 0; size_t prolog_size = buffer.ReadDWord(); uint8_t frame_registr = buffer.ReadByte(); uint32_t index = buffer.ReadDWord(); uint32_t data_index = buffer.ReadDWord(); std::vector unwind_opcodes; unwind_opcodes.resize(buffer.ReadDWord()); for (j = 0; j < unwind_opcodes.size(); j++) { unwind_opcodes[j] = item(buffer.ReadDWord() - 1); } FunctionInfo *info = function_info_list()->Add(begin + add_address, end + add_address, base_type, base_value, prolog_size, frame_registr, file.runtime_function_list()->GetFunctionByAddress(begin + add_address), (index != 0) ? item(index - 1) : NULL); if (data_index != 0) info->set_data_entry(item(data_index - 1)); info->set_unwind_opcodes(unwind_opcodes); } c = buffer.ReadDWord(); for (i = 0; i < c; i++) { uint32_t begin = buffer.ReadDWord(); uint32_t end = buffer.ReadDWord(); uint32_t begin_index = buffer.ReadDWord(); uint32_t end_index = buffer.ReadDWord(); uint32_t size_index = buffer.ReadDWord(); range_list_->Add(begin + add_address, end + add_address, begin_index != 0 ? item(begin_index - 1) : NULL, end_index != 0 ? item(end_index - 1) : NULL, size_index != 0 ? item(size_index - 1) : NULL); } c = buffer.ReadDWord(); for (i = 0; i < c; i++) { uint32_t dw = buffer.ReadDWord(); LinkType link_type = static_cast(buffer.ReadByte()); int operand_index = static_cast(buffer.ReadByte()); uint8_t opt = buffer.ReadByte(); uint64_t qw = (opt & 1) ? buffer.ReadDWord() + add_address : 0; CommandLink *link = item(dw - 1)->AddLink(operand_index, link_type, qw); if (opt & 2) link->set_sub_value(buffer.ReadDWord() + add_address); if (opt & 4) { dw = buffer.ReadDWord(); if (dw != 0) link->set_parent_command(item(dw - 1)); } if (opt & 8) { dw = buffer.ReadDWord(); if (dw != 0) link->set_base_function_info(function_info_list()->item(dw - 1)); } } memory_type_ = owner_->owner()->segment_list()->GetMemoryTypeByAddress(address_); if (type_ != otString) entry_ = GetCommandByAddress(address_); } CommandBlock *BaseFunction::AddBlock(size_t start_index, bool is_executable) { return block_list_->Add((memory_type_ & (mtDiscardable | mtNotPaged)) | (is_executable ? mtExecutable : mtReadable), start_index); } uint8_t *version_watermark = NULL; uint8_t *owner_watermark = NULL; void BaseFunction::AddWatermark(Watermark *watermark, int copy_count) { Watermark secure_watermark(NULL); std::string value; uint8_t *internal_watermarks[] = {version_watermark, owner_watermark}; for (size_t k = 0; k < 1 + _countof(internal_watermarks); k++) { if (k == 0) { if (!watermark) continue; } else { uint8_t *ptr = internal_watermarks[k - 1]; if (!ptr) continue; uint32_t key = *reinterpret_cast(ptr); uint16_t len = *reinterpret_cast(ptr + 4); value.resize(len); for (size_t i = 0; i < value.size(); i++) { value[i] = ptr[6 + i] ^ static_cast(_rotl32(key, (int)i) + i); } secure_watermark.set_value(value); watermark = &secure_watermark; } for (int i = 0; i < copy_count; i++) { watermark->Compile(); ICommand *command = AddCommand(Data(watermark->dump())); command->include_option(roCreateNewBlock); } } } void BaseFunction::Rebase(uint64_t delta_base) { map_.clear(); for (size_t i = 0; i < count(); i++) { ICommand *command = item(i); command->Rebase(delta_base); if (command->address()) map_[command->address()] = command; } link_list_->Rebase(delta_base); range_list_->Rebase(delta_base); function_info_list_->Rebase(delta_base); if (address_) address_ += delta_base; } void BaseFunction::Notify(MessageType type, IObject *sender, const std::string &message) const { if (owner_) owner_->Notify(type, sender, message); } void BaseFunction::set_compilation_type(CompilationType compilation_type) { if (default_compilation_type_ != ctNone) return; if (compilation_type_ != compilation_type) { compilation_type_ = compilation_type; Notify(mtChanged, this); } } void BaseFunction::set_compilation_options(uint32_t compilation_options) { if (compilation_options_ != compilation_options) { compilation_options_ = compilation_options; Notify(mtChanged, this); } } void BaseFunction::set_need_compile(bool need_compile) { if (need_compile_ != need_compile) { need_compile_ = need_compile; Notify(mtChanged, this); } } void BaseFunction::set_folder(Folder *folder) { if (folder_ != folder) { folder_ = folder; Notify(mtChanged, this); } } void BaseFunction::set_break_address(uint64_t break_address) { if (type_ == otString) return; if (break_address_ != break_address) { break_address_ = break_address; Notify(mtChanged, this); } } std::string BaseFunction::display_address(const std::string &arch_name) const { std::string res; if (type() != otUnknown) res.append(arch_name).append(DisplayValue(cpu_address_size(), address())); if (type() == otString) { for (size_t i = 1; i < count(); i++) { res.append(", ").append(arch_name).append(DisplayValue(cpu_address_size(), item(i)->address())); } } return res; } Data BaseFunction::hash() const { Data res; bool is_unknown = (type() == otUnknown); res.PushBuff(name().c_str(), name().size() + 1); res.PushByte(need_compile()); res.PushByte(is_unknown); res.PushDWord(is_unknown ? tag() : -1); res.PushByte(compilation_type()); res.PushDWord(compilation_options()); res.PushDWord(break_address() ? static_cast(break_address() - address()) : 0); res.PushDWord(static_cast(ext_command_list()->count())); for (size_t i = 0; i < ext_command_list()->count(); i++) { res.PushDWord(static_cast(ext_command_list()->item(i)->address() - address())); } return res; } #ifdef CHECKED bool BaseFunction::check_hash() const { for (size_t i = 0; i < count(); i++) { if (!item(i)->check_hash()) return false; } return true; } #endif IVirtualMachine *BaseFunction::virtual_machine(IVirtualMachineList *virtual_machine_list, ICommand *command) const { if (virtual_machine_list) { std::vector list; for (size_t i = 0; i < virtual_machine_list->count(); i++) { IVirtualMachine *virtual_machine = virtual_machine_list->item(i); if (virtual_machine->processor()->cpu_address_size() == cpu_address_size()) list.push_back(virtual_machine); } return list[rand() % list.size()]; } return NULL; } /** * Signature */ Signature::Signature(SignatureList *owner, const std::string &value, uint32_t tag) : IObject(), owner_(owner), value_(value), tag_(tag) { Init(); } Signature::~Signature() { if (owner_) owner_->RemoveObject(this); } void Signature::Init() { size_t i, p; uint8_t m, b; char c; dump_.clear(); mask_.clear(); if (value_.size() == 0) return; for (i = 0; i < value_.size(); i++) { p = i / 2; if (p >= dump_.size()) { dump_.push_back(0); mask_.push_back(0); } m = 0xff; c = value_[i]; if ((c >= '0') && (c <= '9')) { b = c - '0'; } else if ((c >= 'A') && (c <= 'F')) { b = c - 'A' + 0x0a; } else if ((c >= 'a') && (c <= 'f')) { b = c - 'a' + 0x0a; } else { m = 0; b = 0; } if ((i & 1) == 0) { dump_[p] = (dump_[p] & 0x0f) | (b << 4); mask_[p] = (mask_[p] & 0x0f) | (m << 4); } else { dump_[p] = (dump_[p] & 0xf0) | (b & 0x0f); mask_[p] = (mask_[p] & 0xf0) | (m & 0x0f); } } } bool Signature::SearchByte(uint8_t value) { int i; size_t p; bool res; if (dump_.size() == 0) return false; res = false; for (i = (int)pos_.size() - 1; i >= -1; i--) { p = (i == -1) ? 0 : pos_[i]; if ((dump_[p] & mask_[p]) == (value & mask_[p])) { p++; if (p == dump_.size()) { res = true; if (i > -1) pos_.erase(pos_.begin() + i); } else if (i == -1) { pos_.push_back(p); } else { pos_[i] = p; } } else if (i > -1) { pos_.erase(pos_.begin() + i); } } return res; } /** * SignatureList */ SignatureList::SignatureList() : ObjectList() { } Signature *SignatureList::Add(const std::string &value, uint32_t tag) { Signature *sign = new Signature(this, value, tag); AddObject(sign); return sign; } void SignatureList::InitSearch() { for (size_t i = 0; i < count(); i++) { item(i)->InitSearch(); } } /** * BaseFunctionList */ BaseFunctionList::BaseFunctionList(IArchitecture *owner) : IFunctionList(), owner_(owner) { } BaseFunctionList::BaseFunctionList(IArchitecture *owner, const BaseFunctionList &src) : IFunctionList(src), owner_(owner) { size_t i; std::vector src_folders, folders; Folder *folder; for (i = 0; i < src.count(); i++) { AddObject(src.item(i)->Clone(this)); } src_folders = src.owner()->owner()->folder_list()->GetFolderList(); FolderList *folder_list = NULL; if (owner && owner->owner()) folder_list = owner->owner()->folder_list(); if (folder_list) folders = folder_list->GetFolderList(); for (i = 0; i < src.count(); i++) { std::vector::const_iterator it = std::find(src_folders.begin(), src_folders.end(), src.item(i)->folder()); folder = (it == src_folders.end()) ? folder_list : *it; if (folder) item(i)->set_folder(folder); } } IFunction *BaseFunctionList::AddUnknown(const std::string &name, CompilationType compilation_type, uint32_t compilation_options, bool need_compile, Folder *folder) { IFunction *func = GetUnknownByName(name); if (!func) { func = Add(name, compilation_type, compilation_options, need_compile, folder); if (func) Notify(mtAdded, func); } else { func->set_compilation_type(compilation_type); func->set_compilation_options(compilation_options); func->set_need_compile(need_compile); func->set_folder(folder); } return func; }; IFunction *BaseFunctionList::AddByAddress(uint64_t address, CompilationType compilation_type, uint32_t compilation_options, bool need_compile, Folder *folder) { IFunction *func = GetFunctionByAddress(address); if (!func) { // check address uint32_t memory_type = owner_->segment_list()->GetMemoryTypeByAddress(address); if ((memory_type & mtExecutable) == 0) { MapFunction *map_function = owner_->map_function_list()->GetFunctionByAddress(address); if (!map_function || map_function->type() != otString) return NULL; } func = Add("", compilation_type, compilation_options, need_compile, folder); if (func) { func->ReadFromFile(*owner_, address); Notify(mtAdded, func); } } else { func->set_compilation_type(compilation_type); func->set_compilation_options(compilation_options); func->set_need_compile(need_compile); func->set_folder(folder); } return func; }; IFunction *BaseFunctionList::GetFunctionByAddress(uint64_t address) const { for (size_t i = 0; i < count(); i++) { IFunction *func = item(i); if (func->address() == address) return func; } return NULL; } IFunction *BaseFunctionList::GetFunctionByName(const std::string &name) const { for (size_t i = 0; i < count(); i++) { IFunction *func = item(i); if (func->name().compare(name) == 0 && func->type() != otUnknown) return func; } return NULL; } IFunction *BaseFunctionList::GetUnknownByName(const std::string &name) const { for (size_t i = 0; i < count(); i++) { IFunction *func = item(i); if (func->name().compare(name) == 0 && func->type() == otUnknown) return func; } return NULL; } ICommand *BaseFunctionList::GetCommandByAddress(uint64_t address, bool need_compile) const { for (size_t i = 0; i < count(); i++) { IFunction *func = item(i); if (need_compile && !func->need_compile()) continue; ICommand *command = func->GetCommandByAddress(address); if (command) return (need_compile && func->is_breaked_address(command->address())) ? NULL : command; } return NULL; } ICommand *BaseFunctionList::GetCommandByNearAddress(uint64_t address, bool need_compile) const { for (size_t i = 0; i < count(); i++) { IFunction *func = item(i); if (need_compile && !func->need_compile()) continue; ICommand *command = func->GetCommandByNearAddress(address); if (command) return (need_compile && func->is_breaked_address(command->address())) ? NULL : command; } return NULL; } bool BaseFunctionList::Prepare(const CompileContext &ctx) { size_t i, j; bool need_machines = (ctx.runtime != NULL); uint32_t memory_type = mtReadable | mtDiscardable; for (i = count(); i > 0; i--) { IFunction *func = item(i - 1); if (!func->need_compile()) delete func; else if (func->type() != otUnknown && func->compilation_type() != ctMutation) { if ((func->memory_type() & mtDiscardable) == 0) memory_type &= ~mtDiscardable; if (func->memory_type() & mtNotPaged) memory_type |= mtNotPaged; need_machines = true; } } if (need_machines) { IVirtualMachineList *virtual_machine_list = ctx.file->virtual_machine_list(); virtual_machine_list->Prepare(ctx); std::vector processor_list = ctx.file->function_list()->processor_list(); for (i = 0; i < processor_list.size(); i++) { processor_list[i]->set_memory_type(memory_type); } } for (j = 0; j < 4; j++) { for (i = 0; i < count(); i++) { IFunction *func = item(i); switch (j) { case 0: if (func->type() == otUnknown) { ctx.file->Notify(mtWarning, func, string_format(language[lsFunctionNotFound].c_str(), func->name().c_str())); continue; } if (!func->Init(ctx)) return false; break; case 1: if (!func->Prepare(ctx)) return false; break; case 2: if (!func->PrepareExtCommands(ctx)) return false; break; case 3: if (!func->PrepareLinks(ctx)) return false; break; } } } return true; } bool BaseFunctionList::Compile(const CompileContext &ctx) { size_t i, j, k; IFunction *func; CommandBlock *block; std::vector block_list; j = 0; auto jjj = count(); for (i = 0; i < count(); i++) { func = item(i); j += func->count(); if (func->compilation_type() == ctUltra) j += func->count(); } ctx.file->StartProgress(string_format("%s...", language[lsCompiling].c_str()), j); for (i = 0; i < count(); i++) { func = item(i); if (!func->Compile(ctx)) return false; } for (i = 0; i < count(); i++) { func = item(i); func->AfterCompile(ctx); if (!func->need_compile()) continue; for (j = 0; j < func->block_list()->count(); j++) { block_list.push_back(func->block_list()->item(j)); } } for (i = 0; i < block_list.size(); i++) { std::swap(block_list[i], block_list[rand() % block_list.size()]); } if (ctx.file->runtime_function_list() && ctx.file->runtime_function_list()->count()) { // sort blocks by address range for (i = 0; i < block_list.size(); i++) { block_list[i]->set_sort_index(i); } std::sort(block_list.begin(), block_list.end(), CommandBlockListCompareHelper()); // add prolog blocks std::set function_info_list; Data data; for (i = 0; i < block_list.size(); i++) { block = block_list[i]; if ((block->type() & mtExecutable) == 0) continue; AddressRange *address_range = block->function()->item(block->start_index())->address_range(); if (!address_range) continue; FunctionInfo *function_info = address_range->owner(); if (!function_info->prolog_size() || function_info_list.find(function_info) != function_info_list.end()) continue; func = block->function(); size_t prolog_size = 0; for (j = block->start_index(); j <= block->end_index(); j++) { prolog_size += func->item(j)->dump_size(); } if (prolog_size < function_info->prolog_size()) { size_t size = function_info->prolog_size() - prolog_size; data.resize(size); for (k = 0; k < data.size(); k++) { data[k] = rand(); } CommandBlock *new_block = func->AddBlock(func->count(), true); ICommand *command = func->AddCommand(data); command->set_block(new_block); command->set_address_range(address_range); block_list.insert(block_list.begin() + i + 1, new_block); } function_info_list.insert(function_info); } } for (i = 0; i < block_list.size(); i++) { block_list[i]->Compile(*ctx.manager); } CompileInfo(ctx); CompileLinks(ctx); ctx.file->EndProgress(); return true; } void BaseFunctionList::CompileInfo(const CompileContext &ctx) { for (size_t i = 0; i < count(); i++) { item(i)->CompileInfo(ctx); } } void BaseFunctionList::CompileLinks(const CompileContext &ctx) { for (size_t i = 0; i < count(); i++) { IFunction *func = item(i); if (func->compilation_type() != ctMutation) continue; func->CompileLinks(ctx); } for (size_t i = 0; i < count(); i++) { IFunction *func = item(i); if (func->compilation_type() == ctMutation) continue; func->CompileLinks(ctx); } } void BaseFunctionList::ReadFromBuffer(Buffer &buffer, IArchitecture &file) { size_t c = buffer.ReadDWord(); for (size_t i = 0; i < c; i++) { IFunction *func = CreateFunction(); AddObject(func); func->ReadFromBuffer(buffer, file); } } void BaseFunctionList::Rebase(uint64_t delta_base) { for (size_t i = 0; i < count(); i++) { item(i)->Rebase(delta_base); } } void BaseFunctionList::RemoveObject(IFunction *func) { Notify(mtDeleted, func); IFunctionList::RemoveObject(func); } void BaseFunctionList::Notify(MessageType type, IObject *sender, const std::string &message) const { if (owner_) owner_->Notify(type, sender, message); } std::vector BaseFunctionList::processor_list() const { std::vector res; for (size_t i = 0; i < count(); i++) { IFunction *func = item(i); if (func->tag() == ftProcessor) res.push_back(func); } return res; } #ifdef CHECKED bool BaseFunctionList::check_hash() const { for (size_t i = 0; i < count(); i++) { if (!item(i)->check_hash()) return false; } return true; } #endif /** * CommandInfo */ CommandInfo::CommandInfo(CommandInfoList *owner, AccessType type, uint8_t value, OperandType operand_type, OperandSize size) : IObject(), owner_(owner), type_(type), value_(value), operand_type_(operand_type), size_(size) { } CommandInfo::~CommandInfo() { if (owner_) owner_->RemoveObject(this); } /** * CommandInfoList */ CommandInfoList::CommandInfoList() : ObjectList(), need_flags_(0), change_flags_(0) { } void CommandInfoList::Add(AccessType type, uint8_t value, OperandType operand_type, OperandSize size) { CommandInfo *command_info = GetInfo(type, operand_type, value); if (command_info) { if (operand_type == otHiPartRegistr) { if (size == command_info->size()) return; } else { if (size > command_info->size()) command_info->set_size(size); return; } } if (operand_type == otRegistr) { command_info = GetInfo(type, otHiPartRegistr, value); if (command_info) { if (size > command_info->size()) { delete command_info; } else if (size == command_info->size()) { delete command_info; size = static_cast(size + 1); } } } else if (operand_type == otHiPartRegistr) { command_info = GetInfo(type, otRegistr, value); if (command_info) { if (size < command_info->size()) return; if (size == command_info->size()) { command_info->set_size(static_cast(size + 1)); return; } } } command_info = new CommandInfo(this, type, value, operand_type, size); AddObject(command_info); } CommandInfo *CommandInfoList::GetInfo(AccessType type, OperandType operand_type, uint8_t value) const { for (size_t i = 0; i < count(); i++) { CommandInfo *command_info = item(i); if (command_info->type() == type && command_info->value() == value && command_info->operand_type() == operand_type) return command_info; } return NULL; } CommandInfo *CommandInfoList::GetInfo(AccessType type, OperandType operand_type) const { for (size_t i = 0; i < count(); i++) { CommandInfo *command_info = item(i); if (command_info->type() == type && command_info->operand_type() == operand_type) return command_info; } return NULL; } CommandInfo *CommandInfoList::GetInfo(OperandType operand_type) const { for (size_t i = 0; i < count(); i++) { CommandInfo *command_info = item(i); if (command_info->operand_type() == operand_type) return command_info; } return NULL; } void CommandInfoList::clear() { need_flags_ = 0; change_flags_ = 0; ObjectList::clear(); } bool CommandBlockListCompareHelper::operator()(const CommandBlock *block1, const CommandBlock *block2) const { AddressRange *range1 = (block1->type() & mtExecutable) ? block1->function()->item(block1->start_index())->address_range() : NULL; AddressRange *range2 = (block2->type() & mtExecutable) ? block2->function()->item(block2->start_index())->address_range() : NULL; FunctionInfo *info1 = range1 ? range1->owner() : NULL; FunctionInfo *info2 = range2 ? range2->owner() : NULL; bool res; if (info1 == info2 && range1 && range2) { if (range1->original_begin() == range2->original_begin()) res = range1->original_begin() ? block1->start_index() < block2->start_index() : block1->sort_index() < block2->sort_index(); else res = range1->original_begin() < range2->original_begin(); } else { uint64_t value1 = info1 ? info1->begin() : 0; uint64_t value2 = info2 ? info2->begin() : 0; res = (value1 == value2) ? block1->sort_index() < block2->sort_index() : (value1 < value2); } return res; } /** * BaseVirtualMachine */ BaseVirtualMachine::BaseVirtualMachine(IVirtualMachineList *owner, uint8_t id) : IVirtualMachine(), owner_(owner), id_(id) { } BaseVirtualMachine::~BaseVirtualMachine() { if (owner_) owner_->RemoveObject(this); }