VMProtect/core/processors.cc

2852 lines
70 KiB
C++

#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 <intrin.h>
/**
* 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<AddressRange>(), 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<AddressRange>(), 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<AddressRange>(), 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<uint8_t> 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<FunctionInfo>()
{
}
FunctionInfoList::FunctionInfoList(const FunctionInfoList &src)
: ObjectList<FunctionInfo>()
{
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<uint8_t>(value);
break;
case osWord:
value_ = static_cast<uint16_t>(value);
break;
case osDWord:
value_ = static_cast<uint32_t>(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<uint16_t>(value));
break;
case osDWord:
value = __builtin_bswap32(static_cast<uint32_t>(value));
break;
case osQWord:
value = __builtin_bswap64(value);
break;
}
break;
case ccRol:
switch (size_) {
case osByte:
value = _rotl8(static_cast<uint8_t>(value), static_cast<int>(value_));
break;
case osWord:
value = _rotl16(static_cast<uint16_t>(value), static_cast<int>(value_));
break;
case osDWord:
value = _rotl32(static_cast<uint32_t>(value), static_cast<int>(value_));
break;
case osQWord:
value = _rotl64(value, static_cast<int>(value_));
break;
}
break;
case ccRor:
switch (size_) {
case osByte:
value = _rotr8(static_cast<uint8_t>(value), static_cast<int>(value_));
break;
case osWord:
value = _rotr16(static_cast<uint16_t>(value), static_cast<int>(value_));
break;
case osDWord:
value = _rotr32(static_cast<uint32_t>(value), static_cast<int>(value_));
break;
case osQWord:
value = _rotr64(value, static_cast<int>(value_));
break;
}
break;
}
return value;
}
/**
* ValueCryptor
*/
ValueCryptor::ValueCryptor()
: ObjectList<ValueCommand>(), size_(osByte)
{
}
ValueCryptor::ValueCryptor(const ValueCryptor &src)
: ObjectList<ValueCommand>(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<CryptCommandType>(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<CommandLink>()
{
}
CommandLinkList::CommandLinkList(const CommandLinkList &src)
: ObjectList<CommandLink>(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<ExtCommand>(), owner_(owner)
{
}
ExtCommandList::ExtCommandList(IFunction *owner, const ExtCommandList &src)
: ObjectList<ExtCommand>(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<ExtCommand>::AddObject(ext_command);
if (owner_)
owner_->Notify(mtAdded, ext_command);
}
void ExtCommandList::RemoveObject(ExtCommand *ext_command)
{
ObjectList<ExtCommand>::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<CommandBlock>(), owner_(owner)
{
}
CommandBlockList::CommandBlockList(IFunction *owner, const CommandBlockList &src)
: ObjectList<CommandBlock>(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<ICommand *> 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<ICommand>::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<size_t>(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<size_t>(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<uint64_t> 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<uint64_t>::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<CompilationType>(b & 0xf);
type_ = static_cast<ObjectType>(buffer.ReadByte());
cpu_address_size_ = static_cast<OperandSize>(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<AddressBaseType>(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<ICommand *> 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<LinkType>(buffer.ReadByte());
int operand_index = static_cast<int8_t>(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<uint32_t *>(ptr);
uint16_t len = *reinterpret_cast<uint16_t *>(ptr + 4);
value.resize(len);
for (size_t i = 0; i < value.size(); i++) {
value[i] = ptr[6 + i] ^ static_cast<uint8_t>(_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<uint32_t>(break_address() - address()) : 0);
res.PushDWord(static_cast<uint32_t>(ext_command_list()->count()));
for (size_t i = 0; i < ext_command_list()->count(); i++) {
res.PushDWord(static_cast<uint32_t>(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<IVirtualMachine *> 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>()
{
}
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<Folder*> 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<Folder*>::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<IFunction *> 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<CommandBlock *> 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<FunctionInfo *> 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<IFunction *> BaseFunctionList::processor_list() const
{
std::vector<IFunction *> 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<CommandInfo>(), 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<OperandSize>(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<OperandSize>(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<CommandInfo>::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);
}