From f7e9d62a399408d9c5fb6f1f62eccdae156c0bf7 Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 7 Jul 2024 21:41:11 +0300 Subject: [PATCH] Add missed files --- core/intel.cc | 31494 +++++++++++++++++++++++++++++++++++++++++++ core/processors.cc | 2852 ++++ 2 files changed, 34346 insertions(+) create mode 100644 core/intel.cc create mode 100644 core/processors.cc diff --git a/core/intel.cc b/core/intel.cc new file mode 100644 index 0000000..eba631e --- /dev/null +++ b/core/intel.cc @@ -0,0 +1,31494 @@ +#include "../runtime/common.h" +#include "../runtime/crypto.h" +#include "../runtime/loader.h" +#include "objects.h" +#include "osutils.h" +#include "streams.h" +#include "files.h" +#include "processors.h" +#include "lang.h" +#include "core.h" +#include "dwarf.h" +#include "pefile.h" +#include "macfile.h" +#include "elffile.h" +#include "packer.h" +#include "intel.h" +#include "objc.h" +#include + +/** + * IntelCommand + */ + +IntelCommand::IntelCommand(IFunction *owner, OperandSize size, uint64_t address) + : BaseCommand(owner), address_(address), size_(size), type_(cmUnknown), flags_(0), preffix_command_(cmUnknown), + base_segment_(segDefault), command_pos_(0), original_dump_size_(0), section_options_(0), vex_operand_(0), + ext_vm_entry_(NULL), begin_section_cryptor_(NULL), end_section_cryptor_(NULL), seh_handler_(NULL) +{ + vm_command_info_list_ = new IntelCommandInfoList(size); + if (address_) + include_option(roClearOriginalCode); +#ifdef CHECKED + update_hash(); +#endif +} + +IntelCommand::IntelCommand(IFunction *owner, OperandSize size, IntelCommandType type, IntelOperand operand1, IntelOperand operand2, IntelOperand operand3) + : BaseCommand(owner), address_(0), size_(size), type_(cmUnknown), flags_(0), preffix_command_(cmUnknown), base_segment_(segDefault), + command_pos_(0), original_dump_size_(0), section_options_(0), vex_operand_(0), ext_vm_entry_(NULL), begin_section_cryptor_(NULL), + end_section_cryptor_(NULL), seh_handler_(NULL) +{ + vm_command_info_list_ = new IntelCommandInfoList(size); + type_ = type; + operand_[0] = operand1; + operand_[1] = operand2; + operand_[2] = operand3; + for (size_t i = 0; i < _countof(operand_); i++) { + IntelOperand *operand = &operand_[i]; + if (operand->size == osDefault) + operand->size = size_; + if (operand->address_size == osDefault) + operand->address_size = size_; + } +#ifdef CHECKED + update_hash(); +#endif +} + +IntelCommand::IntelCommand(IFunction *owner, OperandSize size, const std::string &value) + : BaseCommand(owner, value), address_(0), size_(size), type_(cmUnknown), flags_(0), + preffix_command_(cmUnknown), base_segment_(segDefault), command_pos_(0), original_dump_size_(0), section_options_(0), + vex_operand_(0), ext_vm_entry_(NULL), begin_section_cryptor_(NULL), end_section_cryptor_(NULL), seh_handler_(NULL) +{ + vm_command_info_list_ = new IntelCommandInfoList(size); + type_ = cmDB; +#ifdef CHECKED + update_hash(); +#endif +} + +IntelCommand::IntelCommand(IFunction *owner, OperandSize size, const os::unicode_string &value) + : BaseCommand(owner, value), address_(0), size_(size), type_(cmUnknown), flags_(0), + preffix_command_(cmUnknown), base_segment_(segDefault), command_pos_(0), original_dump_size_(0), section_options_(0), + ext_vm_entry_(NULL), begin_section_cryptor_(NULL), end_section_cryptor_(NULL), seh_handler_(NULL) +{ + vm_command_info_list_ = new IntelCommandInfoList(size); + type_ = cmDB; +#ifdef CHECKED + update_hash(); +#endif +} + +IntelCommand::IntelCommand(IFunction *owner, OperandSize size, const Data &value) + : BaseCommand(owner, value), address_(0), size_(size), type_(cmUnknown), flags_(0), + preffix_command_(cmUnknown), base_segment_(segDefault), command_pos_(0), original_dump_size_(0), section_options_(0), + ext_vm_entry_(NULL), begin_section_cryptor_(NULL), end_section_cryptor_(NULL), seh_handler_(NULL) +{ + vm_command_info_list_ = new IntelCommandInfoList(size); + type_ = cmDB; +#ifdef CHECKED + update_hash(); +#endif +} + +void IntelCommand::Init(IntelCommandType type, IntelOperand operand1, IntelOperand operand2, IntelOperand operand3) +{ + type_ = type; + operand_[0] = operand1; + operand_[1] = operand2; + operand_[2] = operand3; + for (size_t i = 0; i < _countof(operand_); i++) { + IntelOperand *operand = &operand_[i]; + if (operand->size == osDefault) + operand->size = size_; + if (operand->address_size == osDefault) + operand->address_size = size_; + } +} + +void IntelCommand::Init(const Data &data) +{ + type_ = cmDB; + set_dump(data.data(), data.size()); +} + +void IntelCommand::InitUnknown() +{ + clear(); + type_ = cmUnknown; + PushByte(0); +} + +IntelCommand::IntelCommand(IFunction *owner, const IntelCommand &src) + : BaseCommand(owner, src), section_options_(0), ext_vm_entry_(NULL), begin_section_cryptor_(NULL), end_section_cryptor_(NULL) +{ + vm_command_info_list_ = new IntelCommandInfoList(src.size()); + address_ = src.address_; + size_ = src.size_; + type_ = src.type_; + flags_ = src.flags_; + preffix_command_ = src.preffix_command_; + base_segment_ = src.base_segment_; + command_pos_ = src.command_pos_; + original_dump_size_ = src.original_dump_size_; + vex_operand_ = src.vex_operand_; + seh_handler_ = src.seh_handler_; + + for (size_t i = 0; i < _countof(operand_); i++) { + operand_[i] = src.operand_[i]; + } +#ifdef CHECKED + update_hash(); +#endif +} + +IntelCommand::~IntelCommand() +{ + delete vm_command_info_list_; +} + +void IntelCommand::clear() +{ + type_ = cmUnknown; + base_segment_ = segDefault; + preffix_command_ = cmUnknown; + flags_ = 0; + command_pos_ = 0; + for (size_t i = 0; i < _countof(operand_); i++) { + operand_[i].Clear(); + } + vm_command_info_list_->clear(); + BaseCommand::clear(); +} + +IntelCommand *IntelCommand::Clone(IFunction *owner) const +{ + IntelCommand *command = new IntelCommand(owner, *this); + return command; +} + +bool IntelCommand::is_data() const +{ + return (type_ == cmDB || type_ == cmDW || type_ == cmDD || type_ == cmDQ || type_ == cmSleb || type_ == cmUleb || type_ == cmDC); +} + +bool IntelCommand::is_end() const +{ + return (type_ == cmRet || type_ == cmIret || type_ == cmJmp || ((type_ == cmCall || type_ == cmJmpWithFlag) && (options() & roUseAsJmp)) || is_data()); +} + +static const char *size_name[] = { + "byte", + "word", + "dword", + "qword", + "tbyte", + "oword", + "xmmword", + "ymmword", + "fword" +}; + +static const char *segment_name[] = { + "es", + "cs", + "ss", + "ds", + "fs", + "gs" +}; + +static const char *registr_name[4][22] = { + {"al","cl","dl","bl","spl","bpl","sil","dil","r8b","r9b","r10b","r11b","r12b","r13b","r14b","r15b","fl","tl","rl","il","kl","el"}, + {"ax","cx","dx","bx","sp","bp","si","di","r8w","r9w","r10w","r11w","r12w","r13w","r14w","r15w","fx","tx","rx","ix","kx","ex"}, + {"eax","ecx","edx","ebx","esp","ebp","esi","edi","r8d","r9d","r10d","r11d","r12d","r13d","r14d","r15d","efx","etx","erx","eix","ekx","eex"}, + {"rax","rcx","rdx","rbx","rsp","rbp","rsi","rdi","r8","r9","r10","r11","r12","r13","r14","r15","rfx","rtx","rrx","rix","rkx","rex"} +}; + +bool IntelCommand::GetOperandText(std::string &str, size_t index) const +{ + const IntelOperand *operand = &operand_[index]; + + if (operand->type == otNone) + return false; + + str.clear(); + if (operand->type & otMemory) { + if (operand->show_size) + str.append(size_name[operand->size]).append(" ptr "); + + if (base_segment_ != segDefault && type_ != cmLea) + str.append(segment_name[base_segment_]).append(":"); + + str.append("["); + if (operand->type & otBaseRegistr) + str.append(registr_name[operand->address_size][operand->base_registr]); + } + + if (operand->type & otRegistr) { + if (operand->type & otMemory) { + if (operand->type & otBaseRegistr) + str.append("+"); + str.append(registr_name[operand->address_size][operand->registr]); + if (operand->scale_registr) + str.append(string_format("*%d", 2 << (operand->scale_registr - 1))); + } else { + str.append(operand->size > osQWord ? "???" : registr_name[operand->size][operand->registr]); + } + } else if (operand->type & otHiPartRegistr) { + str.append(std::string(registr_name[osWord][operand->registr & 3], 1)); + str.append("h"); + } else if (operand->type & otFPURegistr) { + str.append(string_format("st%d", operand->registr)); + } else if (operand->type & otSegmentRegistr) { + str.append(operand->registr > segGS ? "???" : segment_name[operand->registr]); + } else if (operand->type & otControlRegistr) { + str.append(string_format("cr%d", operand->registr)); + } else if (operand->type & otDebugRegistr) { + str.append(string_format("dr%d", operand->registr)); + } else if (operand->type & otMMXRegistr) { + str.append(string_format("mm%d", operand->registr)); + } else if (operand->type & otXMMRegistr) { + str.append(string_format((operand->size == osYMMWord) ? "ymm%d" : "xmm%d", operand->registr)); + } + + if (operand->type & otValue) { + int64_t value = operand->value; + bool is_neg = (value < 0 && (operand->size > operand->value_size || (operand->type & (otMemory | otRegistr | otBaseRegistr)) > otMemory)); + if (is_neg) { + str.append("-"); + value = -value; + } else if (operand->type & (otRegistr | otBaseRegistr)) { + str.append("+"); + } + + if (operand->type == otValue && operand->size == osFWord) { + switch (operand->value_size) { + case osWord: + str.append(string_format("%.4X:%.4X", static_cast(operand->value >> 16), static_cast(operand->value))); + break; + case osDWord: + str.append(string_format("%.4X:%.8X", static_cast(operand->value >> 32), static_cast(operand->value))); + break; + } + } else { + switch (operand->value_size) { + case osByte: + str.append(string_format("%.2X", static_cast(value))); + break; + case osWord: + str.append(string_format("%.4X", static_cast(value))); + break; + case osDWord: + str.append(string_format("%.8X", static_cast(value))); + break; + case osQWord: + str.append(string_format("%.16llX", value)); + break; + } + } + } + + if (operand->type & otMemory) + str.append("]"); + + return true; +} + +std::string IntelCommand::text() const +{ + std::string res, operand_text; + size_t i; + + if (type_ == cmDB) { + res.append(intel_command_name[type_]); + for (i = 0; i < dump_size(); i++) { + if (i > 0) + res.append(","); + res.append(string_format(" %.2X", dump(i))); + } + } else { + if (options() & roLockPrefix) + res.append("lock "); + + if (preffix_command_ != cmUnknown) + res.append(intel_command_name[preffix_command_]).append(" "); + + if (options() & roVexPrefix) + res.append("v"); + + if (type_ == cmJCXZ && operand_[1].size > osWord) { + res.append(operand_[1].size == osDWord ? "jecxz" : "jrcxz"); + } else { + res.append(intel_command_name[type_]); + } + + if (flags_) { + if (options() & roInverseFlag) + res.append("n"); + switch (flags_) { + case fl_O: + res.append("o"); + break; + case fl_C: + res.append("b"); + break; + case fl_Z: + res.append("z"); + break; + case fl_C | fl_Z: + res.append("be"); + break; + case fl_P: + res.append("p"); + break; + case fl_S | fl_O: + res.append("l"); + break; + case fl_S: + res.append("s"); + break; + case fl_Z | fl_S | fl_O: + res.append("le"); + break; + default: + res.append("?"); + break; + } + } + + switch (type_) { + case cmLods: + case cmScas: + case cmCmps: + case cmMovs: + case cmStos: + case cmIns: + case cmOuts: + res.append(std::string(size_name[operand_[0].size], 1)); + break; + case cmPusha: + case cmPopa: + case cmPushf: + case cmPopf: + case cmIret: + if (operand_[0].size > osWord) + res.append(std::string(size_name[operand_[0].size], 1)); + break; + case cmXlat: + res.append(std::string(size_name[osByte], 1)); + break; + case cmRet: + if ((options() & roFar) != 0) + res.append("f"); + break; + } + + for (i = 0; i < _countof(operand_); i++) { + if (vex_operand_ && (vex_operand_ & 0x3) == i) { + res.append(", "); + res.append(string_format((vex_operand_ & 4) ? "ymm%d" : "xmm%d", (vex_operand_ >> 4) & 0x0f)); + } + + if (!GetOperandText(operand_text, i)) + break; + + if (i > 0) + res.append(","); + res.append(" ").append(operand_text); + } + } + + return res; +} + +CommentInfo IntelCommand::comment() +{ + CommentInfo res = BaseCommand::comment(); + if (res.type != ttUnknown) + return res; + + res.type = ttNone; + if ((options() & roFar) == 0) { + IArchitecture *file = owner()->owner()->owner(); + if (file) { + size_t operand_index = NOT_ID; + for (size_t i = 2; i > 0; i--) { + if (operand_[i - 1].type == otValue || operand_[i - 1].type == (otMemory | otValue)) { + operand_index = i - 1; + break; + } + } + if (operand_index != NOT_ID) { + uint64_t address = operand_[operand_index].value; + if (IRelocation *relocation = operand_[operand_index].relocation) { + if (IImportFunction *import_function = file->import_list()->GetFunctionByAddress(relocation->address())) { + res.value = string_format("%c %s", 3, import_function->full_name().c_str()); + res.type = ttImport; + } else if (ISymbol *symbol = relocation->symbol()) { + address = symbol->address(); + res.value = string_format("%c %s", 3, symbol->display_name().c_str()); + if (file->export_list()->GetExportByAddress(address)) + res.type = ttExport; + else if (file->segment_list()->GetMemoryTypeByAddress(address) & mtExecutable) + res.type = ttFunction; + else + res.type = ttVariable; + } + } else if (IImportFunction *import_function = file->import_list()->GetFunctionByAddress(address)) { + res.value = string_format("%c %s", 3, import_function->full_name().c_str()); + res.type = ttImport; + } else if (IRelocation *relocation = file->relocation_list() ? file->relocation_list()->GetRelocationByAddress(address) : NULL) { + if (ISymbol *symbol = relocation->symbol()) { + address = symbol->address(); + res.value = string_format("%c %s", 3, symbol->display_name().c_str()); + if (file->export_list()->GetExportByAddress(address)) + res.type = ttExport; + else if (file->segment_list()->GetMemoryTypeByAddress(address) & mtExecutable) + res.type = ttFunction; + else + res.type = ttVariable; + } + } else if (MapFunction *map_function = file->map_function_list()->GetFunctionByAddress(address)) { + if (map_function->type() == otData) { + if (map_function->name().compare("`string'") == 0) { + std::string str = file->ReadString(address); + if (!str.empty()) { + res.value = string_format("%c string \"%s\"", 3, DisplayString(str).c_str()); + res.type = ttString; + } + } + else { + res.value = string_format("%c %s", 3, map_function->name().c_str()); + res.type = ttVariable; + } + } + else { + res.value = string_format("%c %s", 3, map_function->name().c_str()); + switch (map_function->type()) { + case otString: + res.type = ttString; + break; + case otExport: + res.type = ttExport; + break; + default: + res.type = ttFunction; + break; + } + } + } else if (type_ == cmLea || operand_[operand_index].type == otValue) { + if (type_ == cmCall || type_ == cmJmp || type_ == cmJmpWithFlag || type_ == cmLoope || type_ == cmLoopne || type_ == cmLoop || type_ == cmJCXZ) { + res.value = (next_address() > address) ? char(2) : char(4); + res.type = ttJmp; + } + else { + std::string str = file->ReadString(address); + if (!str.empty()) { + res.value = string_format("%c string \"%s\"", 3, DisplayString(str).c_str()); + res.type = ttString; + } + } + } + } + } + } + + set_comment(res); + + return res; +} + +std::string IntelCommand::dump_str() const +{ + std::string res; + if (type_ == cmUnknown) { + for (size_t i = 0; i < dump_size(); i++) { + res += "??"; + } + return res; + } + + res = BaseCommand::dump_str(); + + size_t i, c; + c = 0; + for (i = 0; i < command_pos_; i++) { + res.insert((i + 1) * 2 + c, ":"); + c++; + } + for (i = 0; i < _countof(operand_); i++) { + const IntelOperand *operand = &operand_[i]; + if (operand->type == otNone) + break; + + if ((operand->type & otValue) && operand->value_pos) { + res.insert(operand->value_pos * 2 + c, " "); + c++; + } + } + + return res; +} + +std::string IntelCommand::display_address() const +{ + return DisplayValue(size(), address()); +} + +bool IntelCommand::is_equal(const IntelCommand &command) const +{ + if (type_ != command.type_) + return false; + for (size_t i = 0; i < _countof(operand_); i++) { + if (operand_[i] != command.operand_[i]) + return false; + } + return true; +} + +IntelOperand *IntelCommand::GetFreeOperand() +{ + for (size_t i = 0; i < _countof(operand_); i++) { + IntelOperand *operand = &operand_[i]; + if (operand->type == otNone) { + operand->Clear(); + return operand; + } + } + + return NULL; +} + +static OperandSize GetOperandSize(uint8_t code, const DisasmContext &ctx) +{ + if ((code & 1) == 0) + return osByte; + if (ctx.rex_prefix & rexW) + return osQWord; + if (ctx.lower_reg) + return osWord; + return osDWord; +} + +static OperandSize GetDefaultOperandSize(const DisasmContext &ctx) +{ + if ((ctx.rex_prefix & rexW) == 0 && ctx.lower_reg) + return osWord; + return ctx.file->cpu_address_size(); +} + +static OperandSize GetAddressSize(const DisasmContext &ctx) +{ + OperandSize cpu_address_size = ctx.file->cpu_address_size(); + + if (ctx.lower_address) + return (cpu_address_size == osQWord) ? osDWord : osWord; + return cpu_address_size; +} + +void IntelCommand::ReadFlags(uint8_t code) +{ + switch ((code >> 1) & 7) { + case 0x00: + flags_ = fl_O; + break; + case 0x01: + flags_ = fl_C; + break; + case 0x02: + flags_ = fl_Z; + break; + case 0x03: + flags_ = fl_C | fl_Z; + break; + case 0x04: + flags_ = fl_S; + break; + case 0x05: + flags_ = fl_P; + break; + case 0x06: + flags_ = fl_S | fl_O; + break; + case 0x07: + flags_ = fl_Z | fl_S | fl_O; + break; + } + + if (code & 1) + include_option(roInverseFlag); +} + +void IntelCommand::ReadReg(uint8_t code, OperandSize operand_size, OperandType operand_type, const DisasmContext &ctx) +{ + IntelOperand *operand = GetFreeOperand(); + if (operand == NULL) + throw std::runtime_error("ReadReg no free operands"); + + operand->type = operand_type; + operand->size = operand_size; + operand->registr = (code & 7); + + if (ctx.rex_prefix && operand_type == otRegistr) { + if (ctx.rex_prefix & rexB) + operand->registr |= 8; + } else if (operand_type == otRegistr && operand_size == osByte && operand->registr >= 4) { + operand->type = otHiPartRegistr; + operand->registr &= 3; + } +} + +void IntelCommand::ReadRegFromRM(uint8_t code, OperandSize operand_size, OperandType operand_type, const DisasmContext &ctx) +{ + IntelOperand *operand = GetFreeOperand(); + if (operand == NULL) + throw std::runtime_error("ReadRegFromRM no free operands"); + + operand->type = operand_type; + operand->size = operand_size; + operand->registr = ((code >> 3) & 7); + + if (ctx.rex_prefix && (operand_type == otRegistr || operand_type == otDebugRegistr || operand_type == otControlRegistr || operand_type == otXMMRegistr)) { + if (ctx.rex_prefix & rexR) + operand->registr |= 8; + } else if (operand_type == otRegistr && operand_size == osByte && operand->registr >= 4) { + operand->type = otHiPartRegistr; + operand->registr &= 3; + } +} + +void IntelCommand::ReadRM(uint8_t code, OperandSize operand_size, OperandType operand_type, bool show_size, const DisasmContext &ctx) +{ + IntelOperand *operand = GetFreeOperand(); + if (operand == NULL) + throw std::runtime_error("ReadRM no free operands"); + + OperandSize value_size = osByte; + uint8_t sib; + + switch (code & 0xc0) { + case 0x00: + if ((!ctx.lower_address && (code & 7) == 5) || (ctx.lower_address && (code & 7) == 6)) { + operand->type = otMemory | otValue; + value_size = GetAddressSize(ctx); + } else { + operand->type = otMemory | otRegistr; + } + break; + case 0x40: + operand->type = otMemory | otRegistr | otValue; + break; + case 0x80: + operand->type = otMemory | otRegistr | otValue; + value_size = GetAddressSize(ctx); + break; + default: + operand->type = operand_type; + break; + } + operand->size = operand_size; + + if (operand->type & otMemory) { + operand->show_size = show_size; + operand->address_size = GetAddressSize(ctx); + + if (operand->address_size == osWord) { + if ((code & 7) < 4) { + operand->base_registr = (code & 2) == 0 ? regEBX : regEBP; + operand->type |= otBaseRegistr; + } + + if (operand->type & otRegistr) { + switch (code & 7) { + case 0x00: + operand->registr = regESI; + operand->base_registr = regEBX; + break; + case 0x01: + operand->registr = regEDI; + operand->base_registr = regEBX; + break; + case 0x02: + operand->registr = regESI; + operand->base_registr = regEBP; + break; + case 0x03: + operand->registr = regEDI; + operand->base_registr = regEBP; + break; + case 0x04: + operand->registr = regESI; + break; + case 0x05: + operand->registr = regEDI; + break; + case 0x06: + operand->registr = regEBP; + break; + case 0x07: + operand->registr = regEBX; + break; + } + } + } else { + if ((code & 7) == 4) { + sib = ReadByte(*ctx.file); + operand->registr = ((sib >> 3) & 7); + operand->base_registr = (sib & 7); + operand->type |= otBaseRegistr; + + if (ctx.rex_prefix) { + if (ctx.rex_prefix & rexB) + operand->base_registr |= 8; + if (ctx.rex_prefix & rexX) + operand->registr |= 8; + } + + if (operand->registr == regESP) + operand->type &= ~otRegistr; + else + operand->scale_registr = (sib >> 6); + + if ((code & 0xc0) == 0 && (operand->base_registr & 7) == regEBP) { + operand->type &= ~otBaseRegistr; + operand->type |= otValue; + } + + if (operand->type & otValue) { + switch (code & 0xc0) { + case 0x00: + value_size = osDWord; + break; + case 0x40: + value_size = osByte; + break; + case 0x80: + value_size = osDWord; + break; + } + } + } else { + operand->registr = (code & 7); + if (ctx.rex_prefix) { + if (ctx.rex_prefix & rexB) + operand->registr |= 8; + } + } + } + + if (operand->type & otValue) { + operand->value_size = value_size; + operand->value_pos = static_cast(dump_size()); + switch (value_size) { + case osByte: + operand->value = ByteToInt64(ReadByte(*ctx.file)); + break; + case osWord: + operand->value = WordToInt64(ReadWord(*ctx.file)); + break; + case osDWord: + operand->value = DWordToInt64(ReadDWord(*ctx.file)); + break; + case osQWord: + operand->value = DWordToInt64(ReadDWord(*ctx.file)); + if (operand->type == (otValue | otMemory)) + operand->is_large_value = true; + break; + } + } + } else { + operand->registr = (code & 7); + if (ctx.rex_prefix && (operand_type == otRegistr || operand_type == otDebugRegistr || operand_type == otControlRegistr || operand_type == otXMMRegistr)) { + if (ctx.rex_prefix & rexB) + operand->registr |= 8; + } else if (operand_type == otRegistr && operand_size == osByte && operand->registr >= 4) { + operand->type = otHiPartRegistr; + operand->registr &= 3; + } + } +} + +IntelOperand *IntelCommand::ReadValue(OperandSize operand_size, OperandSize value_size, const DisasmContext &ctx) +{ + IntelOperand *operand = GetFreeOperand(); + if (operand == NULL) + throw std::runtime_error("ReadValue no free operands"); + + operand->type = otValue; + operand->size = operand_size; + operand->value_size = value_size; + operand->value_pos = static_cast(dump_size()); + + switch (value_size) { + case osByte: + operand->value = ByteToInt64(ReadByte(*ctx.file)); + break; + case osWord: + operand->value = WordToInt64(ReadWord(*ctx.file)); + break; + case osDWord: + operand->value = DWordToInt64(ReadDWord(*ctx.file)); + break; + case osQWord: + operand->value = ReadQWord(*ctx.file); + break; + } + + if (operand_size == osFWord) + operand->value |= static_cast(ReadWord(*ctx.file)) << (value_size == osWord ? 16 : 32); + + return operand; +} + +void IntelCommand::ReadValueAddAddress(OperandSize operand_size, OperandSize value_size, const DisasmContext &ctx) +{ + IntelOperand *operand = ReadValue(operand_size, value_size, ctx); + operand->value += next_address(); + operand->value_size = operand_size; + + switch (operand_size) { + case osWord: + operand->value = static_cast(operand->value); + break; + case osDWord: + operand->value = static_cast(operand->value); + break; + } +} + +uint64_t IntelCommand::ReadValueFromFile(IArchitecture &file, OperandSize value_size) +{ + DisasmContext ctx; + IntelOperand *operand; + + switch (value_size) { + case osByte: + type_ = cmDB; + break; + case osWord: + type_ = cmDW; + break; + case osDWord: + type_ = cmDD; + break; + case osQWord: + type_ = cmDQ; + break; + default: + throw std::runtime_error("Invalid value size"); + } + + ctx.file = &file; + ctx.lower_address = false; + ctx.lower_reg = false; + ctx.rex_prefix = 0; + + operand = ReadValue(value_size, value_size, ctx); + operand->fixup = file.fixup_list()->GetFixupByAddress(address() + operand->value_pos); + + if (file.relocation_list()) + operand->relocation = file.relocation_list()->GetRelocationByAddress(address() + operand->value_pos); + + return operand->value; +} + +enum OperandFlags { + of_None = 0, + + of_Registr = 0x01000000, + of_DebugRegistr = 0x02000000, + of_ControlRegistr = 0x03000000, + of_FPURegistr = 0x04000000, + of_MMXRegistr = 0x05000000, + of_XMMRegistr = 0x06000000, + of_Value = 0x07000000, + of_SegmentRegistr = 0x08000000, + + of_RM = 0x10000000, + of_RegRM = 0x20000000, + of_Reg = 0x30000000, + of_Const = 0x40000000, + of_Relative = 0x50000000, + of_Far = 0x60000000, + of_Memory = 0x70000000, + of_XReg = 0x80000000, + + of_size = 0x00000100, + of_mem_word = 0x00000200, + of_mem_only = 0x00000400, + of_reg_only = 0x00000800, + + of_value_b = 0x00000001, + of_value_w = 0x00000002, + of_value_z = 0x00000003, + of_value_v = 0x00000004, + + of_E = (of_RM | of_Registr), + of_G = (of_RegRM | of_Registr), + of_IB = (of_Value | of_value_b), + of_IW = (of_Value | of_value_w), + of_IZ = (of_Value | of_value_z), + of_IV = (of_Value | of_value_v), + of_M = (of_RM | of_Registr | of_mem_only), + of_J = (of_Value | of_Relative), + of_S = (of_RegRM | of_SegmentRegistr), + of_A = (of_Value | of_Far), + of_O = (of_Value | of_Memory), + of_V = (of_RegRM | of_XMMRegistr), + of_W = (of_RM | of_XMMRegistr), + of_X = (of_XReg | of_XMMRegistr), + of_ST = (of_Const | of_FPURegistr), + of_U = (of_RM | of_XMMRegistr | of_reg_only), + of_C = (of_RegRM | of_ControlRegistr), + of_R = (of_RM | of_Registr | of_reg_only), + of_D = (of_RegRM | of_DebugRegistr), + of_Q = (of_RM | of_MMXRegistr), + of_P = (of_RegRM | of_MMXRegistr), + of_N = (of_RM | of_MMXRegistr | of_reg_only), + of_FI = (of_Const | of_Value), + of_FS = (of_Const | of_SegmentRegistr), + of_FG = (of_Const | of_Registr), + of_Z = (of_Reg | of_Registr), + + of_b = 0x00010000, + of_w = 0x00020000, + of_v = 0x00030000, + of_d = 0x00040000, + of_z = 0x00050000, + of_p = 0x00060000, + of_t = 0x00070000, + of_q = 0x00080000, + of_s = 0x00090000, + of_dq = 0x000E0000, + of_qq = 0x000F0000, + of_o = 0x00130000, + of_x = 0x00150000, + of_vdef = 0x00FC0000, + of_cpu = 0x00FD0000, + of_adr = 0x00FE0000, + of_def = 0x00FF0000, + + of_Eb = (of_E | of_b), + of_Ew = (of_E | of_w), + of_Ed = (of_E | of_d), + of_Eq = (of_E | of_q), + of_Ev = (of_E | of_v), + of_Ex = (of_E | of_x | of_size), + of_Edef = (of_E | of_def), + of_Gb = (of_G | of_b), + of_Gw = (of_G | of_w), + of_Gd = (of_G | of_d), + of_Gv = (of_G | of_v), + of_Gz = (of_G | of_z), + of_Gx = (of_G | of_x), + of_FGb = (of_FG | of_b), + of_FGw = (of_FG | of_w), + of_FGv = (of_FG | of_v), + of_IBb = (of_IB | of_b), + of_IBv = (of_IB | of_v), + of_IZv = (of_IZ | of_v), + of_IVv = (of_IV | of_v), + of_IWw = (of_IW | of_w), + of_Ma = (of_M | of_v), + of_FSdef = (of_FS | of_def), + of_Jb = (of_J | of_b), + of_Jz = (of_J | of_z), + of_Sw = (of_S | of_w), + of_Mb = (of_M | of_b), + of_Mw = (of_M | of_w), + of_Mv = (of_M | of_v), + of_Md = (of_M | of_d), + of_Mq = (of_M | of_q), + of_Mt = (of_M | of_t), + of_Ms = (of_M | of_s), + of_Mp = (of_M | of_p), + of_Mdq = (of_M | of_dq), + of_Mdef = (of_M | of_vdef | of_size), + of_Mx = (of_M | of_x), + of_Ap = (of_A | of_p), + of_Ob = (of_O | of_b), + of_Ov = (of_O | of_v), + of_FIb = (of_FI | of_b), + of_Vdq = (of_V | of_dq), + of_Vqq = (of_V | of_qq), + of_Vdef = (of_V | of_vdef), + of_Ww = (of_W | of_w | of_size), + of_Wd = (of_W | of_d | of_size), + of_Wq = (of_W | of_q | of_size), + of_Wdq = (of_W | of_dq | of_size), + of_Wdef = (of_W | of_vdef | of_size), + of_Xdq = (of_X | of_dq), + of_Xdef = (of_X | of_vdef), + of_Udq = (of_U | of_dq), + of_Udef = (of_U | of_vdef), + of_Nq = (of_N | of_q), + of_Zb = (of_Z | of_b), + of_Zv = (of_Z | of_v), + of_Zdef = (of_Z | of_def), + of_Rcpu = (of_R | of_cpu), + of_Ccpu = (of_C | of_cpu), + of_Dcpu = (of_D | of_cpu), + of_Qd = (of_Q | of_d), + of_Qq = (of_Q | of_q), + of_Pq = (of_P | of_q), +}; + +void IntelCommand::ReadCommand(IntelCommandType type, uint32_t of_1, uint32_t of_2, uint32_t of_3, DisasmContext &ctx) +{ + size_t i; + uint32_t of; + uint8_t code; + OperandSize os; + IntelOperand *operand; + OperandType ot; + bool need_read_code; + uint32_t ofs[] = {of_1, of_2, of_3}; + + type_ = type; + + if (ctx.use_last_byte) { + code = dump(dump_size() - 1); + need_read_code = false; + } else { + code = 0; + need_read_code = true; + } + + for (i = 0; i < _countof(ofs); i++) { + of = ofs[i]; + + if (of == of_None) + break; + + switch (of & 0x00FF0000) { + case of_b: + os = osByte; + break; + case of_w: + os = osWord; + break; + case of_d: + os = osDWord; + break; + case of_q: + os = osQWord; + break; + case of_v: + os = GetOperandSize(1, ctx); + break; + case of_z: + os = ((ctx.rex_prefix & rexW) == 0 && ctx.lower_reg) ? osWord : osDWord; + break; + case of_x: + os = (ctx.rex_prefix & rexW) ? osQWord : osDWord; + break; + case of_adr: + os = GetAddressSize(ctx); + break; + case of_def: + os = GetDefaultOperandSize(ctx); + break; + case of_p: + os = osFWord; + break; + case of_t: + os = osTByte; + break; + case of_cpu: + os = size_; + break; + case of_s: + // FIXME + os = osByte; + break; + case of_o: + os = osOWord; + break; + case of_dq: + os = osXMMWord; + break; + case of_qq: + os = osYMMWord; + break; + case of_vdef: + os = ((options() & roVexPrefix) && (ctx.rex_prefix & 0x80)) ? osYMMWord : osXMMWord; + break; + default: + os = osByte; + break; + } + + switch (of & 0x0F000000) { + case of_Registr: + ot = otRegistr; + break; + case of_DebugRegistr: + ot = otDebugRegistr; + break; + case of_ControlRegistr: + ot = otControlRegistr; + break; + case of_FPURegistr: + ot = otFPURegistr; + break; + case of_MMXRegistr: + ot = otMMXRegistr; + break; + case of_XMMRegistr: + ot = otXMMRegistr; + break; + case of_Value: + ot = otValue; + break; + case of_SegmentRegistr: + ot = otSegmentRegistr; + break; + default: + operand_[i].size = os; + continue; + } + + if (ot == otValue) { + switch (of & 0xF0000000) { + case of_Relative: + ReadValueAddAddress(GetDefaultOperandSize(ctx), os, ctx); + break; + case of_Const: + operand = &operand_[i]; + operand->type = otValue; + operand->size = os; + operand->value_size = os; + operand->value = (of & 0xFF); + break; + case of_Far: + ReadValue(os, GetDefaultOperandSize(ctx), ctx); + break; + case of_Memory: + ReadValue(os, GetAddressSize(ctx), ctx); + operand_[i].type |= otMemory; + break; + default: + switch (of & 0x0F) { + case of_value_b: + ReadValue(os, osByte, ctx); + break; + case of_value_w: + ReadValue(os, osWord, ctx); + break; + case of_value_z: + ReadValue(os, (ctx.lower_reg) ? osWord : osDWord, ctx); + break; + case of_value_v: + ReadValue(os, GetOperandSize(1, ctx), ctx); + break; + } + break; + } + } else { + switch (of & 0xF0000000) { + case of_RM: + if (need_read_code) { + code = ReadByte(*ctx.file); + need_read_code = false; + } + ReadRM(code, os, ot, (of & of_size) != 0, ctx); + operand = &operand_[i]; + if ((operand->type & otMemory) == 0) { + if ((of & of_mem_only) != 0) { + type_ = cmDB; + return; + } + } else { + if ((of & of_reg_only) != 0) { + type_ = cmDB; + return; + } + if ((of & of_mem_word) != 0) + operand->size = osWord; + } + break; + case of_RegRM: + if (need_read_code) { + code = ReadByte(*ctx.file); + need_read_code = false; + } + ReadRegFromRM(code, os, ot, ctx); + break; + case of_Reg: + ReadReg((of & 0xff), os, ot, ctx); + break; + case of_XReg: + code = ReadByte(*ctx.file); + ReadReg((code >> 4), os, ot, ctx); + break; + case of_Const: + operand = &operand_[i]; + operand->type = ot; + operand->size = os; + operand->registr = (of & 7); + break; + } + + operand = &operand_[i]; + switch (operand->type) { + case otSegmentRegistr: + if (operand->registr > segGS) { + type_ = cmDB; + return; + } + break; + case otControlRegistr: + if (operand->registr == 1 + || operand->registr == 5 + || operand->registr == 6 + || operand->registr >= 9) { + type_ = cmDB; + return; + } + break; + case otDebugRegistr: + if (operand->registr >= 8) { + type_ = cmDB; + return; + } + break; + } + } + } +}; + +size_t IntelCommand::ReadFromFile(IArchitecture &file) +{ + uint8_t code, prefix; + OperandSize os; + DisasmContext ctx; + IntelOperand *operand; + uint8_t vex_bytes[2]; + size_t i, vex_operand_index; + + clear(); + size_ = file.cpu_address_size(); + + ctx.file = &file; + ctx.lower_address = false; + ctx.lower_reg = false; + ctx.rex_prefix = 0; + ctx.use_last_byte = false; + ctx.vex_registr = 0; + + vex_operand_index = 0; + prefix = 0; + vex_bytes[0] = 0; + vex_bytes[1] = 0; + while (type_ == cmUnknown) { + command_pos_ = dump_size(); + code = vex_bytes[0] ? vex_bytes[0] : ReadByte(file); + switch (code) { + case 0x00: + ReadCommand(cmAdd, of_Eb, of_Gb, of_None, ctx); + break; + case 0x01: + ReadCommand(cmAdd, of_Ev, of_Gv, of_None, ctx); + break; + case 0x02: + ReadCommand(cmAdd, of_Gb, of_Eb, of_None, ctx); + break; + case 0x03: + ReadCommand(cmAdd, of_Gv, of_Ev, of_None, ctx); + break; + case 0x04: + ReadCommand(cmAdd, of_FGb | regEAX, of_IBb, of_None, ctx); + break; + case 0x05: + ReadCommand(cmAdd, of_FGv | regEAX, of_IZv, of_None, ctx); + break; + case 0x06: + if (size_ == osQWord) { + type_ = cmDB; + } else { + ReadCommand(cmPush, of_FSdef | segES, of_None, of_None, ctx); + } + break; + case 0x07: + if (size_ == osQWord) { + type_ = cmDB; + } else { + ReadCommand(cmPop, of_FSdef | segES, of_None, of_None, ctx); + } + break; + case 0x08: + ReadCommand(cmOr, of_Eb, of_Gb, of_None, ctx); + break; + case 0x09: + ReadCommand(cmOr, of_Ev, of_Gv, of_None, ctx); + break; + case 0x0a: + ReadCommand(cmOr, of_Gb, of_Eb, of_None, ctx); + break; + case 0x0b: + ReadCommand(cmOr, of_Gv, of_Ev, of_None, ctx); + break; + case 0x0c: + ReadCommand(cmOr, of_FGb | regEAX, of_IBb, of_None, ctx); + break; + case 0x0d: + ReadCommand(cmOr, of_FGv | regEAX, of_IZv, of_None, ctx); + break; + case 0x0e: + if (size_ == osQWord) { + type_ = cmDB; + } else { + ReadCommand(cmPush, of_FSdef | segCS, of_None, of_None, ctx); + } + break; + + // Secondary Opcode Map + case 0x0f: + code = vex_bytes[1] ? vex_bytes[1] : ReadByte(file); + switch (code) { + case 0x00: + code = ReadByte(file); + ctx.use_last_byte = true; + switch ((code >> 3) & 7) { + case 0x00: + ReadCommand(cmSldt, of_Ev | of_mem_word, of_None, of_None, ctx); + break; + case 0x01: + ReadCommand(cmStr, of_Ev | of_mem_word, of_None, of_None, ctx); + break; + case 0x02: + ReadCommand(cmLldt, of_Ew, of_None, of_None, ctx); + break; + case 0x03: + ReadCommand(cmLtr, of_Ew, of_None, of_None, ctx); + break; + case 0x04: + ReadCommand(cmVerr, of_Ew, of_None, of_None, ctx); + break; + case 0x05: + ReadCommand(cmVerw, of_Ew, of_None, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x01: + code = ReadByte(file); + ctx.use_last_byte = true; + if (code >= 0xc0) { + switch (code) { + case 0xc1: + type_ = cmVmcall; + break; + case 0xc2: + type_ = cmVmlaunch; + break; + case 0xc3: + type_ = cmVmresume; + break; + case 0xc4: + type_ = cmVmxoff; + break; + case 0xc8: + type_ = cmMonitor; + break; + case 0xc9: + type_ = cmMwait; + break; + case 0xd0: + type_ = cmXgetbv; + break; + case 0xd1: + type_ = cmXsetbv; + break; + case 0xd8: + type_ = cmVmrun; + break; + case 0xd9: + type_ = cmVmmcall; + break; + case 0xda: + type_ = cmVmload; + break; + case 0xdb: + type_ = cmVmsave; + break; + case 0xdc: + type_ = cmStgi; + break; + case 0xdd: + type_ = cmClgi; + break; + case 0xde: + type_ = cmSkinit; + break; + case 0xdf: + type_ = cmInvlpga; + break; + case 0xf8: + type_ = cmSwapgs; + break; + case 0xf9: + type_ = cmRdtscp; + break; + default: + type_ = cmDB; + break; + } + } else { + switch ((code >> 3) & 7) { + case 0x00: + ReadCommand(cmSgdt, of_Ms, of_None, of_None, ctx); + break; + case 0x01: + ReadCommand(cmSidt, of_Ms, of_None, of_None, ctx); + break; + case 0x02: + ReadCommand(cmLgdt, of_Ms, of_None, of_None, ctx); + break; + case 0x03: + ReadCommand(cmLidt, of_Ms, of_None, of_None, ctx); + break; + case 0x04: + ReadCommand(cmSmsw, of_Ev | of_mem_word, of_None, of_None, ctx); + break; + case 0x06: + ReadCommand(cmLmsw, of_Ew, of_None, of_None, ctx); + break; + case 0x07: + ReadCommand(cmInvlpg, of_Mb, of_None, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + } + break; + case 0x02: + ReadCommand(cmLar, of_Gv, of_Ew, of_None, ctx); + break; + case 0x03: + ReadCommand(cmLsl, of_Gv, of_Ew, of_None, ctx); + break; + case 0x05: + type_ = cmSyscall; + break; + case 0x06: + type_ = cmClts; + break; + case 0x07: + type_ = cmSysret; + break; + case 0x08: + type_ = cmInvd; + break; + case 0x09: + type_ = cmWbinvd; + break; + case 0x0b: + type_ = cmUd2; + break; + case 0x0d: + code = ReadByte(file); + ctx.use_last_byte = true; + switch ((code >> 3) & 7) { + case 0x00: + ReadCommand(cmPrefetch, of_Mb, of_None, of_None, ctx); + break; + case 0x01: + ReadCommand(cmPrefetchw, of_Mb, of_None, of_None, ctx); + break; + default: + ReadCommand(cmPrefetch, of_Mb, of_None, of_None, ctx); + break; + } + break; + case 0x0e: + type_ = cmFemms; + break; + case 0x10: + switch (prefix) { + case 0x00: + ReadCommand(cmMovups, of_Vdef, of_Wdef, of_None, ctx); + break; + case 0x66: + ReadCommand(cmMovupd, of_Vdef, of_Wdef, of_None, ctx); + break; + case 0xF2: + preffix_command_ = cmUnknown; + ReadCommand(cmMovsd, of_Vdq, of_Wq, of_None, ctx); + break; + case 0xF3: + preffix_command_ = cmUnknown; + ReadCommand(cmMovss, of_Vdq, of_Wd, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x11: + switch (prefix) { + case 0x00: + ReadCommand(cmMovups, of_Wdef, of_Vdef, of_None, ctx); + break; + case 0x66: + ReadCommand(cmMovupd, of_Wdef, of_Vdef, of_None, ctx); + break; + case 0xF2: + preffix_command_ = cmUnknown; + ReadCommand(cmMovsd, of_Wq, of_Vdq, of_None, ctx); + break; + case 0xF3: + preffix_command_ = cmUnknown; + ReadCommand(cmMovss, of_Wd, of_Vdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + + case 0x12: + switch (prefix) { + case 0x00: + code = ReadByte(file); + ctx.use_last_byte = true; + if ((code & 0xc0) == 0xc0) { + vex_operand_index = 1; + ReadCommand(cmMovhlps, of_Vdq, of_Udq, of_None, ctx); + } else { + vex_operand_index = 1; + ReadCommand(cmMovlps, of_Vdq, of_Mq, of_None, ctx); + } + break; + case 0x66: + vex_operand_index = 1; + ReadCommand(cmMovlpd, of_Vdq, of_Mq, of_None, ctx); + break; + case 0xF2: + preffix_command_ = cmUnknown; + ReadCommand(cmMovddup, of_Vdef, of_Wdef, of_None, ctx); + break; + case 0xF3: + preffix_command_ = cmUnknown; + ReadCommand(cmMovsldup, of_Vdef, of_Wdef, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + + case 0x13: + switch (prefix) { + case 0x00: + ReadCommand(cmMovlps, of_Mq, of_Vdq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmMovlpd, of_Mq, of_Vdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x14: + switch (prefix) { + case 0x00: + vex_operand_index = 1; + ReadCommand(cmUnpcklps, of_Vdef, of_Wdef, of_None, ctx); + break; + case 0x66: + vex_operand_index = 1; + ReadCommand(cmUnpcklpd, of_Vdef, of_Wdef, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x15: + switch (prefix) { + case 0x00: + vex_operand_index = 1; + ReadCommand(cmUnpckhps, of_Vdef, of_Wdef, of_None, ctx); + break; + case 0x66: + vex_operand_index = 1; + ReadCommand(cmUnpckhpd, of_Vdef, of_Wdef, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x16: + switch (prefix) { + case 0x00: + code = ReadByte(file); + ctx.use_last_byte = true; + if ((code & 0xc0) == 0xc0) { + ReadCommand(cmMovlhps, of_Vdq, of_Udq, of_None, ctx); + } else { + ReadCommand(cmMovhps, of_Vdq, of_Mq, of_None, ctx); + } + break; + case 0x66: + ReadCommand(cmMovhpd, of_Vdq, of_Mq, of_None, ctx); + break; + case 0xF3: + preffix_command_ = cmUnknown; + ReadCommand(cmMovshdup, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x17: + switch (prefix) { + case 0x00: + ReadCommand(cmMovhps, of_Mq, of_Vdq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmMovhpd, of_Mq, of_Vdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + + case 0x18: + code = ReadByte(file); + ctx.use_last_byte = true; + switch ((code >> 3) & 7) { + case 0x00: + ReadCommand(cmPrefetchnta, of_Mb, of_None, of_None, ctx); + break; + case 0x01: + ReadCommand(cmPrefetcht0, of_Mb, of_None, of_None, ctx); + break; + case 0x02: + ReadCommand(cmPrefetcht1, of_Mb, of_None, of_None, ctx); + break; + case 0x03: + ReadCommand(cmPrefetcht2, of_Mb, of_None, of_None, ctx); + break; + default: + type_ = cmNop; + break; + } + break; + case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: + ReadCommand(cmNop, of_Ev, of_None, of_None, ctx); + break; + case 0x20: + ReadCommand(cmMov, of_Rcpu, of_Ccpu, of_None, ctx); + break; + case 0x21: + ReadCommand(cmMov, of_Rcpu, of_Dcpu, of_None, ctx); + break; + case 0x22: + ReadCommand(cmMov, of_Ccpu, of_Rcpu, of_None, ctx); + break; + case 0x23: + ReadCommand(cmMov, of_Dcpu, of_Rcpu, of_None, ctx); + break; + case 0x28: + switch (prefix) { + case 0x00: + ReadCommand(cmMovaps, of_Vdq, of_Wdq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmMovapd, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x29: + switch (prefix) { + case 0x00: + ReadCommand(cmMovaps, of_Wdq, of_Vdq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmMovapd, of_Wdq, of_Vdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x2a: + switch (prefix) { + case 0x00: + ReadCommand(cmCvtpi2ps, of_Vdq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmCvtpi2pd, of_Vdq, of_Qq, of_None, ctx); + break; + case 0xF2: + preffix_command_ = cmUnknown; + vex_operand_index = 1; + ReadCommand(cmCvtsi2sd, of_Vdq, of_Ex, of_None, ctx); + break; + case 0xF3: + preffix_command_ = cmUnknown; + vex_operand_index = 1; + ReadCommand(cmCvtsi2ss, of_Vdq, of_Ex, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x2b: + switch (prefix) { + case 0x00: + ReadCommand(cmMovntps, of_Mdef, of_Vdef, of_None, ctx); + break; + case 0x66: + ReadCommand(cmMovntpd, of_Mdef, of_Vdef, of_None, ctx); + break; + case 0xF2: + preffix_command_ = cmUnknown; + ReadCommand(cmMovntsd, of_Mq, of_Vdq, of_None, ctx); + break; + case 0xF3: + preffix_command_ = cmUnknown; + ReadCommand(cmMovntss, of_Md, of_Vdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + + case 0x2c: + switch (prefix) { + case 0x00: + ReadCommand(cmCvttps2pi, of_Pq, of_Wdq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmCvttpd2pi, of_Pq, of_Wdq, of_None, ctx); + break; + case 0xF2: + preffix_command_ = cmUnknown; + ReadCommand(cmCvttsd2si, of_Gx, of_Wq, of_None, ctx); + break; + case 0xF3: + preffix_command_ = cmUnknown; + ReadCommand(cmCvttss2si, of_Gx, of_Wd, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + + case 0x2d: + switch (prefix) { + case 0x00: + ReadCommand(cmCvtps2pi, of_Pq, of_Wq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmCvtpd2pi, of_Pq, of_Wdq, of_None, ctx); + break; + case 0xF2: + preffix_command_ = cmUnknown; + ReadCommand(cmCvtsd2si, of_Gx, of_Wq, of_None, ctx); + break; + case 0xF3: + preffix_command_ = cmUnknown; + ReadCommand(cmCvtss2si, of_Gx, of_Wd, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + + case 0x2e: + switch (prefix) { + case 0x00: + ReadCommand(cmUcomiss, of_Vdq, of_Wd, of_None, ctx); + break; + case 0x66: + ReadCommand(cmUcomisd, of_Vdq, of_Wq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + + case 0x2f: + switch (prefix) { + case 0x00: + ReadCommand(cmComiss, of_Vdq, of_Wdq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmComisd, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + + case 0x30: + type_ = cmWrmsr; + break; + + case 0x31: + type_ = cmRdtsc; + break; + + case 0x32: + type_ = cmRdmsr; + break; + + case 0x33: + type_ = cmRdpmc; + break; + + case 0x34: + if (size_ == osQWord) + type_ = cmDB; + else + type_ = cmSysenter; + break; + + case 0x35: + if (size_ == osQWord) + type_ = cmDB; + else + type_ = cmSysexit; + break; + + case 0x37: + type_ = cmGetsec; + break; + + case 0x38: + code = ReadByte(file); + switch (code) { + case 0x00: + switch (prefix) { + case 0x00: + ReadCommand(cmPshufb, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPshufb, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x01: + switch (prefix) { + case 0x00: + ReadCommand(cmPhaddw, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPhaddw, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x02: + switch (prefix) { + case 0x00: + ReadCommand(cmPhaddd, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPhaddd, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x03: + switch (prefix) { + case 0x00: + ReadCommand(cmPhaddsw, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPhaddsw, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x04: + switch (prefix) { + case 0x00: + ReadCommand(cmPmaddubsw, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPmaddubsw, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x05: + switch (prefix) { + case 0x00: + ReadCommand(cmPhsubw, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPhsubw, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x06: + switch (prefix) { + case 0x00: + ReadCommand(cmPhsubd, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPhsubd, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x07: + switch (prefix) { + case 0x00: + ReadCommand(cmPhsubsw, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPhsubsw, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x08: + switch (prefix) { + case 0x00: + ReadCommand(cmPsignb, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPsignb, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x09: + switch (prefix) { + case 0x00: + ReadCommand(cmPsignw, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPsignw, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x0a: + switch (prefix) { + case 0x00: + ReadCommand(cmPsignd, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPsignd, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x0b: + switch (prefix) { + case 0x00: + ReadCommand(cmPmulhrsw, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPmulhrsw, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x0c: + switch (prefix) { + case 0x66: + if (options() & roVexPrefix) { + vex_operand_index = 1; + ReadCommand(cmVpermilps, of_Vdef, of_Wdef, of_None, ctx); + } else + type_ = cmDB; + break; + default: + type_ = cmDB; + break; + } + break; + case 0x0d: + switch (prefix) { + case 0x66: + if (options() & roVexPrefix) { + vex_operand_index = 1; + ReadCommand(cmVpermilpd, of_Vdef, of_Wdef, of_None, ctx); + } else + type_ = cmDB; + break; + default: + type_ = cmDB; + break; + } + break; + case 0x0e: + switch (prefix) { + case 0x66: + if (options() & roVexPrefix) + ReadCommand(cmVtestps, of_Vdef, of_Wdef, of_None, ctx); + else + type_ = cmDB; + break; + default: + type_ = cmDB; + break; + } + break; + case 0x0f: + switch (prefix) { + case 0x66: + if (options() & roVexPrefix) + ReadCommand(cmVtestpd, of_Vdef, of_Wdef, of_None, ctx); + else + type_ = cmDB; + break; + default: + type_ = cmDB; + break; + } + break; + case 0x10: + switch (prefix) { + case 0x66: + ReadCommand(cmPblendvb, of_Vdef, of_Wdef, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x14: + switch (prefix) { + case 0x66: + ReadCommand(cmPblendps, of_Vdef, of_Wdef, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x15: + switch (prefix) { + case 0x66: + ReadCommand(cmPblendpd, of_Vdef, of_Wdef, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x17: + switch (prefix) { + case 0x66: + ReadCommand(cmPtest, of_Vdef, of_Wdef, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x18: + switch (prefix) { + case 0x66: + ReadCommand(cmVbroadcastss, of_Vdef, of_Wd, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x19: + switch (prefix) { + case 0x66: + if (ctx.rex_prefix & 0x80) + ReadCommand(cmVbroadcastsd, of_Vdef, of_Wq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x1a: + switch (prefix) { + case 0x66: + if (ctx.rex_prefix & 0x80) + ReadCommand(cmVbroadcastf128, of_Vdef, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x1c: + switch (prefix) { + case 0x00: + ReadCommand(cmPabsb, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPabsb, of_Vdef, of_Wdef, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x1d: + switch (prefix) { + case 0x00: + ReadCommand(cmPabsw, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPabsw, of_Vdef, of_Wdef, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x1e: + switch (prefix) { + case 0x00: + ReadCommand(cmPabsd, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPabsd, of_Vdef, of_Wdef, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x20: + switch (prefix) { + case 0x66: + ReadCommand(cmPmovsxbw, of_Vdef, of_Wq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x21: + switch (prefix) { + case 0x66: + ReadCommand(cmPmovsxbd, of_Vdef, of_Wd, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x22: + switch (prefix) { + case 0x66: + ReadCommand(cmPmovsxbq, of_Vdef, of_Ww, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x23: + switch (prefix) { + case 0x66: + ReadCommand(cmPmovsxwd, of_Vdef, of_Wq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x24: + switch (prefix) { + case 0x66: + ReadCommand(cmPmovsxwq, of_Vdef, of_Wd, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x25: + switch (prefix) { + case 0x66: + ReadCommand(cmPmovsxdq, of_Vdef, of_Wq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x28: + switch (prefix) { + case 0x66: + vex_operand_index = 1; + ReadCommand(cmPmuldq, of_Vdef, of_Wdef, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x29: + switch (prefix) { + case 0x66: + vex_operand_index = 1; + ReadCommand(cmPcmpeqq, of_Vdef, of_Wdef, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x2a: + switch (prefix) { + case 0x66: + ReadCommand(cmMovntdqa, of_Vdef, of_Mdef, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x2b: + switch (prefix) { + case 0x66: + vex_operand_index = 1; + ReadCommand(cmPackusdw, of_Vdef, of_Wdef, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x2c: + switch (prefix) { + case 0x66: + vex_operand_index = 1; + ReadCommand(cmMaskmovps, of_Vdef, of_Mdef, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x2d: + switch (prefix) { + case 0x66: + vex_operand_index = 1; + ReadCommand(cmMaskmovpd, of_Vdef, of_Mdef, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x2e: + switch (prefix) { + case 0x66: + vex_operand_index = 1; + ReadCommand(cmMaskmovps, of_Mdef, of_Vdef, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x2f: + switch (prefix) { + case 0x66: + vex_operand_index = 1; + ReadCommand(cmMaskmovpd, of_Mdef, of_Vdef, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x30: + switch (prefix) { + case 0x66: + ReadCommand(cmPmovzxbw, of_Vdq, of_Wq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x31: + switch (prefix) { + case 0x66: + ReadCommand(cmPmovzxbd, of_Vdq, of_Wd, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x32: + switch (prefix) { + case 0x66: + ReadCommand(cmPmovzxbq, of_Vdq, of_Ww, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x33: + switch (prefix) { + case 0x66: + ReadCommand(cmPmovzxwd, of_Vdq, of_Wq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x34: + switch (prefix) { + case 0x66: + ReadCommand(cmPmovzxwq, of_Vdq, of_Wd, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x35: + switch (prefix) { + case 0x66: + ReadCommand(cmPmovzxdq, of_Vdq, of_Wq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x37: + switch (prefix) { + case 0x66: + ReadCommand(cmPcmpgtq, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x38: + switch (prefix) { + case 0x66: + ReadCommand(cmPminsb, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x39: + switch (prefix) { + case 0x66: + ReadCommand(cmPminsd, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x3a: + switch (prefix) { + case 0x66: + ReadCommand(cmPminuw, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x3b: + switch (prefix) { + case 0x66: + ReadCommand(cmPminud, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x3c: + switch (prefix) { + case 0x66: + ReadCommand(cmPmaxsb, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x3d: + switch (prefix) { + case 0x66: + ReadCommand(cmPmaxsd, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x3e: + switch (prefix) { + case 0x66: + ReadCommand(cmPmaxuw, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x3f: + switch (prefix) { + case 0x66: + ReadCommand(cmPmaxud, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x40: + switch (prefix) { + case 0x66: + ReadCommand(cmPmulld, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + + case 0x9d: + switch (prefix) { + case 0x66: + vex_operand_index = 1; + if (ctx.rex_prefix & rexW) + ReadCommand(cmFnmadd132sd, of_Vdq, of_Wq, of_None, ctx); + else + ReadCommand(cmFnmadd132ss, of_Vdq, of_Wd, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + + case 0xad: + switch (prefix) { + case 0x66: + vex_operand_index = 1; + if (ctx.rex_prefix & rexW) + ReadCommand(cmFnmadd213sd, of_Vdq, of_Wq, of_None, ctx); + else + ReadCommand(cmFnmadd213ss, of_Vdq, of_Wd, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + + case 0xbd: + switch (prefix) { + case 0x66: + vex_operand_index = 1; + if (ctx.rex_prefix & rexW) + ReadCommand(cmFnmadd231sd, of_Vdq, of_Wq, of_None, ctx); + else + ReadCommand(cmFnmadd231ss, of_Vdq, of_Wd, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + + case 0xdb: + switch (prefix) { + case 0x66: + ReadCommand(cmAesimc, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xdc: + switch (prefix) { + case 0x66: + ReadCommand(cmAesenc, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xdd: + switch (prefix) { + case 0x66: + ReadCommand(cmAesenclast, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xde: + switch (prefix) { + case 0x66: + ReadCommand(cmAesdec, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xdf: + switch (prefix) { + case 0x66: + ReadCommand(cmAesdeclast, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xf0: + switch (prefix) { + case 0x00: + ReadCommand(cmMovbe, of_Gv, of_Mv, of_None, ctx); + break; + case 0xf2: + preffix_command_ = cmUnknown; + ReadCommand(cmCrc32, of_Gx, of_Mb | of_size, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xf1: + switch (prefix) { + case 0x00: + ReadCommand(cmMovbe, of_Mv, of_Gv, of_None, ctx); + break; + case 0xf2: + preffix_command_ = cmUnknown; + ReadCommand(cmCrc32, of_Gx, of_Mv | of_size, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + + // FIXME + default: + type_ = cmDB; + break; + } + break; + + case 0x3a: + code = ReadByte(file); + switch (code) { + case 0x04: + switch (prefix) { + case 0x66: + if (options() & roVexPrefix) + ReadCommand(cmVpermilps, of_Vdef, of_Wdef, of_IBb, ctx); + else + type_ = cmDB; + break; + default: + type_ = cmDB; + break; + } + break; + case 0x05: + switch (prefix) { + case 0x66: + if (options() & roVexPrefix) + ReadCommand(cmVpermilpd, of_Vdef, of_Wdef, of_IBb, ctx); + else + type_ = cmDB; + break; + default: + type_ = cmDB; + break; + } + break; + case 0x06: + switch (prefix) { + case 0x66: + if (options() & roVexPrefix) { + vex_operand_index = 1; + ReadCommand(cmVperm2f128, of_Vdef, of_Wdef, of_IBb, ctx); + } else + type_ = cmDB; + break; + default: + type_ = cmDB; + break; + } + break; + case 0x08: + switch (prefix) { + case 0x66: + ReadCommand(cmRoundps, of_Vdef, of_Wdef, of_IBb, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x09: + switch (prefix) { + case 0x66: + ReadCommand(cmRoundpd, of_Vdef, of_Wdef, of_IBb, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x0c: + switch (prefix) { + case 0x66: + vex_operand_index = 1; + ReadCommand(cmBlendps, of_Vdef, of_Wdef, of_IBb, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x0d: + switch (prefix) { + case 0x66: + vex_operand_index = 1; + ReadCommand(cmBlendpd, of_Vdef, of_Wdef, of_IBb, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x0e: + switch (prefix) { + case 0x66: + ReadCommand(cmPblendw, of_Vdq, of_Wdq, of_IBb, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x0f: + switch (prefix) { + case 0x00: + ReadCommand(cmPalignr, of_Pq, of_Qq, of_IBb, ctx); + break; + case 0x66: + ReadCommand(cmPalignr, of_Vdq, of_Wdq, of_IBb, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x14: + switch (prefix) { + case 0x66: + ReadCommand(cmPextrb, of_Ed, of_Vdq, of_IBb, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x16: + switch (prefix) { + case 0x66: + if (ctx.rex_prefix & rexW) + ReadCommand(cmPextrq, of_Eq, of_Vdq, of_IBb, ctx); + else + ReadCommand(cmPextrd, of_Ed, of_Vdq, of_IBb, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x18: + switch (prefix) { + case 0x66: + vex_operand_index = 1; + ReadCommand(cmInsertf128, of_Vdef, of_Wdq, of_IBb, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x19: + switch (prefix) { + case 0x66: + ReadCommand(cmExtractf128, of_Wdq, of_Vqq, of_IBb, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x20: + switch (prefix) { + case 0x66: + vex_operand_index = 1; + ReadCommand(cmPinsrb, of_Vdq, of_Eb, of_IBb, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x22: + switch (prefix) { + case 0x66: + vex_operand_index = 1; + if (ctx.rex_prefix & rexW) + ReadCommand(cmPinsrq, of_Vdq, of_Eq, of_IBb, ctx); + else + ReadCommand(cmPinsrd, of_Vdq, of_Ed, of_IBb, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x40: + switch (prefix) { + case 0x66: + vex_operand_index = 1; + ReadCommand(cmDpps, of_Vdef, of_Wdef, of_IBb, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x4a: + switch (prefix) { + case 0x66: + vex_operand_index = 1; + ReadCommand(cmBlendvps, of_Vdef, of_Wdef, of_Xdef, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x4b: + switch (prefix) { + case 0x66: + vex_operand_index = 1; + ReadCommand(cmBlendvpd, of_Vdef, of_Wdef, of_Xdef, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x63: + switch (prefix) { + case 0x66: + ReadCommand(cmPcmpistri, of_Vdq, of_Wdq, of_IBb, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xdf: + switch (prefix) { + case 0x66: + ReadCommand(cmAeskeygenassist, of_Vdq, of_Wdq, of_IBb, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + default: + type_ = cmDB; + } + break; + + case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: + case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f: + ReadFlags(code); + ReadCommand(cmCmov, of_Gv, of_Ev, of_None, ctx); + break; + case 0x50: + switch (prefix) { + case 0x00: + ReadCommand(cmMovmskps, of_Gd, of_Udef, of_None, ctx); + break; + case 0x66: + ReadCommand(cmMovmskpd, of_Gd, of_Udef, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x51: + switch (prefix) { + case 0x00: + ReadCommand(cmSqrtps, of_Vdef, of_Wdef, of_None, ctx); + break; + case 0x66: + ReadCommand(cmSqrtpd, of_Vdef, of_Wdef, of_None, ctx); + break; + case 0xF2: + preffix_command_ = cmUnknown; + ReadCommand(cmSqrtsd, of_Vdq, of_Wq, of_None, ctx); + break; + case 0xF3: + preffix_command_ = cmUnknown; + ReadCommand(cmSqrtss, of_Vdq, of_Wd, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + + case 0x52: + switch (prefix) { + case 0x00: + ReadCommand(cmRsqrtps, of_Vdef, of_Wdef, of_None, ctx); + break; + case 0xF3: + preffix_command_ = cmUnknown; + ReadCommand(cmRsqrtss, of_Vdq, of_Wd, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + + case 0x53: + switch (prefix) { + case 0x00: + ReadCommand(cmRcpps, of_Vdef, of_Wdef, of_None, ctx); + break; + case 0xF3: + preffix_command_ = cmUnknown; + ReadCommand(cmRcpss, of_Vdq, of_Wd, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + + case 0x54: + switch (prefix) { + case 0x00: + vex_operand_index = 1; + ReadCommand(cmAndps, of_Vdef, of_Wdef, of_None, ctx); + break; + case 0x66: + vex_operand_index = 1; + ReadCommand(cmAndpd, of_Vdef, of_Wdef, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + + case 0x55: + switch (prefix) { + case 0x00: + vex_operand_index = 1; + ReadCommand(cmAndnps, of_Vdef, of_Wdef, of_None, ctx); + break; + case 0x66: + vex_operand_index = 1; + ReadCommand(cmAndnpd, of_Vdef, of_Wdef, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + + case 0x56: + switch (prefix) { + case 0x00: + vex_operand_index = 1; + ReadCommand(cmOrps, of_Vdef, of_Wdef, of_None, ctx); + break; + case 0x66: + vex_operand_index = 1; + ReadCommand(cmOrpd, of_Vdef, of_Wdef, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + + case 0x57: + switch (prefix) { + case 0x00: + vex_operand_index = 1; + ReadCommand(cmXorps, of_Vdef, of_Wdq, of_None, ctx); + break; + case 0x66: + vex_operand_index = 1; + ReadCommand(cmXorpd, of_Vdef, of_Wdef, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + + case 0x58: + switch (prefix) { + case 0x00: + vex_operand_index = 1; + ReadCommand(cmAddps, of_Vdef, of_Wdef, of_None, ctx); + break; + case 0x66: + vex_operand_index = 1; + ReadCommand(cmAddpd, of_Vdef, of_Wdef, of_None, ctx); + break; + case 0xF2: + preffix_command_ = cmUnknown; + vex_operand_index = 1; + ReadCommand(cmAddsd, of_Vdq, of_Wq, of_None, ctx); + break; + case 0xF3: + preffix_command_ = cmUnknown; + vex_operand_index = 1; + ReadCommand(cmAddss, of_Vdq, of_Wd, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + + case 0x59: + switch (prefix) { + case 0x00: + vex_operand_index = 1; + ReadCommand(cmMulps, of_Vdef, of_Wdef, of_None, ctx); + break; + case 0x66: + vex_operand_index = 1; + ReadCommand(cmMulpd, of_Vdef, of_Wdef, of_None, ctx); + break; + case 0xF2: + preffix_command_ = cmUnknown; + vex_operand_index = 1; + ReadCommand(cmMulsd, of_Vdq, of_Wq, of_None, ctx); + break; + case 0xF3: + preffix_command_ = cmUnknown; + vex_operand_index = 1; + ReadCommand(cmMulss, of_Vdq, of_Wd, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + + case 0x5a: + switch (prefix) { + case 0x00: + ReadCommand(cmCvtps2pd, of_Vdef, of_Wdq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmCvtpd2ps, of_Vdq, of_Wdef, of_None, ctx); + break; + case 0xF2: + preffix_command_ = cmUnknown; + vex_operand_index = 1; + ReadCommand(cmCvtsd2ss, of_Vdq, of_Wq, of_None, ctx); + break; + case 0xF3: + preffix_command_ = cmUnknown; + vex_operand_index = 1; + ReadCommand(cmCvtss2sd, of_Vdq, of_Wd, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + + case 0x5b: + switch (prefix) { + case 0x00: + ReadCommand(cmCvtdq2ps, of_Vdef, of_Wdef, of_None, ctx); + break; + case 0x66: + ReadCommand(cmCvtps2dq, of_Vdef, of_Wdef, of_None, ctx); + break; + case 0xF3: + preffix_command_ = cmUnknown; + ReadCommand(cmCvttps2dq, of_Vdef, of_Wdef, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + + case 0x5c: + switch (prefix) { + case 0x00: + vex_operand_index = 1; + ReadCommand(cmSubps, of_Vdef, of_Wdef, of_None, ctx); + break; + case 0x66: + vex_operand_index = 1; + ReadCommand(cmSubpd, of_Vdef, of_Wdef, of_None, ctx); + break; + case 0xF2: + preffix_command_ = cmUnknown; + vex_operand_index = 1; + ReadCommand(cmSubsd, of_Vdq, of_Wq, of_None, ctx); + break; + case 0xF3: + preffix_command_ = cmUnknown; + vex_operand_index = 1; + ReadCommand(cmSubss, of_Vdq, of_Wd, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + + case 0x5d: + switch (prefix) { + case 0x00: + vex_operand_index = 1; + ReadCommand(cmMinps, of_Vdef, of_Wdef, of_None, ctx); + break; + case 0x66: + vex_operand_index = 1; + ReadCommand(cmMinpd, of_Vdef, of_Wdef, of_None, ctx); + break; + case 0xF2: + preffix_command_ = cmUnknown; + vex_operand_index = 1; + ReadCommand(cmMinsd, of_Vdq, of_Wq, of_None, ctx); + break; + case 0xF3: + preffix_command_ = cmUnknown; + vex_operand_index = 1; + ReadCommand(cmMinss, of_Vdq, of_Wd, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + + case 0x5e: + switch (prefix) { + case 0x00: + vex_operand_index = 1; + ReadCommand(cmDivps, of_Vdef, of_Wdef, of_None, ctx); + break; + case 0x66: + vex_operand_index = 1; + ReadCommand(cmDivpd, of_Vdef, of_Wdef, of_None, ctx); + break; + case 0xF2: + preffix_command_ = cmUnknown; + vex_operand_index = 1; + ReadCommand(cmDivsd, of_Vdq, of_Wq, of_None, ctx); + break; + case 0xF3: + preffix_command_ = cmUnknown; + vex_operand_index = 1; + ReadCommand(cmDivss, of_Vdq, of_Wd, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + + case 0x5f: + switch (prefix) { + case 0x00: + vex_operand_index = 1; + ReadCommand(cmMaxps, of_Vdef, of_Wdef, of_None, ctx); + break; + case 0x66: + vex_operand_index = 1; + ReadCommand(cmMaxpd, of_Vdef, of_Wdef, of_None, ctx); + break; + case 0xF2: + preffix_command_ = cmUnknown; + vex_operand_index = 1; + ReadCommand(cmMaxsd, of_Vdq, of_Wq, of_None, ctx); + break; + case 0xF3: + preffix_command_ = cmUnknown; + vex_operand_index = 1; + ReadCommand(cmMaxss, of_Vdq, of_Wd, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + + case 0x60: + switch (prefix) { + case 0x00: + ReadCommand(cmPunpcklbw, of_Pq, of_Qd, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPunpcklbw, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + + case 0x61: + switch (prefix) { + case 0x00: + ReadCommand(cmPunpcklwd, of_Pq, of_Qd, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPunpcklwd, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + + case 0x62: + switch (prefix) { + case 0x00: + ReadCommand(cmPunpckldq, of_Pq, of_Qd, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPunpckldq, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + + case 0x63: + switch (prefix) { + case 0x00: + ReadCommand(cmPacksswb, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPacksswb, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x64: + switch (prefix) { + case 0x00: + ReadCommand(cmPcmpgtb, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPcmpgtb, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x65: + switch (prefix) { + case 0x00: + ReadCommand(cmPcmpgtw, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPcmpgtw, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x66: + switch (prefix) { + case 0x00: + ReadCommand(cmPcmpgtd, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPcmpgtd, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x67: + switch (prefix) { + case 0x00: + ReadCommand(cmPackuswb, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPackuswb, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x68: + switch (prefix) { + case 0x00: + ReadCommand(cmPunpckhbw, of_Pq, of_Qd, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPunpckhbw, of_Vdq, of_Wq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x69: + switch (prefix) { + case 0x00: + ReadCommand(cmPunpckhwd, of_Pq, of_Qd, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPunpckhwd, of_Vdq, of_Wq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x6a: + switch (prefix) { + case 0x00: + ReadCommand(cmPunpckhdq, of_Pq, of_Qd, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPunpckhdq, of_Vdq, of_Wq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x6b: + switch (prefix) { + case 0x00: + ReadCommand(cmPackssdw, of_Pq, of_Qd, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPackssdw, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x6c: + switch (prefix) { + case 0x66: + ReadCommand(cmPunpcklqdq, of_Vdq, of_Wq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + + case 0x6d: + switch (prefix) { + case 0x66: + ReadCommand(cmPunpckhqdq, of_Vdq, of_Wq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x6e: + switch (prefix) { + case 0x00: + ReadCommand(cmMovd, of_Pq, of_Ex, of_None, ctx); + break; + case 0x66: + ReadCommand(cmMovd, of_Vdq, of_Ex, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x6f: + switch (prefix) { + case 0x00: + ReadCommand(cmMovq, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmMovdqa, of_Vdq, of_Wdq, of_None, ctx); + break; + case 0xF3: + preffix_command_ = cmUnknown; + ReadCommand(cmMovdqu, of_Vdef, of_Wdef, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x70: + switch (prefix) { + case 0x00: + ReadCommand(cmPshufw, of_Pq, of_Qq, of_IBb, ctx); + break; + case 0x66: + ReadCommand(cmPshufd, of_Vdq, of_Wdq, of_IBb, ctx); + break; + case 0xF2: + preffix_command_ = cmUnknown; + ReadCommand(cmPshuflw, of_Vdq, of_Wdq, of_IBb, ctx); + break; + case 0xF3: + preffix_command_ = cmUnknown; + ReadCommand(cmPshufhw, of_Vdq, of_Wdq, of_IBb, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + + case 0x71: + code = ReadByte(file); + ctx.use_last_byte = true; + switch ((code >> 3) & 7) { + case 0x02: + switch (prefix) { + case 0x00: + ReadCommand(cmPsrlw, of_Nq, of_IBb, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPsrlw, of_Udq, of_IBb, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x04: + switch (prefix) { + case 0x00: + ReadCommand(cmPsraw, of_Nq, of_IBb, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPsraw, of_Udq, of_IBb, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x06: + switch (prefix) { + case 0x00: + ReadCommand(cmPsllw, of_Nq, of_IBb, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPsllw, of_Udq, of_IBb, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + default: + type_ = cmDB; + break; + } + break; + + case 0x72: + code = ReadByte(file); + ctx.use_last_byte = true; + switch ((code >> 3) & 7) { + case 0x02: + switch (prefix) { + case 0x00: + ReadCommand(cmPsrld, of_Nq, of_IBb, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPsrld, of_Udq, of_IBb, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x04: + switch (prefix) { + case 0x00: + ReadCommand(cmPsrad, of_Nq, of_IBb, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPsrad, of_Udq, of_IBb, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x06: + switch (prefix) { + case 0x00: + ReadCommand(cmPslld, of_Nq, of_IBb, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPslld, of_Udq, of_IBb, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + default: + type_ = cmDB; + break; + } + break; + + case 0x73: + code = ReadByte(file); + ctx.use_last_byte = true; + switch ((code >> 3) & 7) { + case 0x02: + switch (prefix) { + case 0x00: + ReadCommand(cmPsrlq, of_Nq, of_IBb, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPsrlq, of_Udq, of_IBb, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x03: + switch (prefix) { + case 0x66: + ReadCommand(cmPsrldq, of_Udq, of_IBb, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x06: + switch (prefix) { + case 0x00: + ReadCommand(cmPsllq, of_Nq, of_IBb, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPsllq, of_Udq, of_IBb, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x07: + switch (prefix) { + case 0x66: + ReadCommand(cmPslldq, of_Udq, of_IBb, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + default: + type_ = cmDB; + break; + } + break; + + case 0x74: + switch (prefix) { + case 0x00: + ReadCommand(cmPcmpeqb, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + vex_operand_index = 1; + ReadCommand(cmPcmpeqb, of_Vdef, of_Wdef, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + + case 0x75: + switch (prefix) { + case 0x00: + ReadCommand(cmPcmpeqw, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + vex_operand_index = 1; + ReadCommand(cmPcmpeqw, of_Vdef, of_Wdef, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + + case 0x76: + switch (prefix) { + case 0x00: + ReadCommand(cmPcmpeqd, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + vex_operand_index = 1; + ReadCommand(cmPcmpeqd, of_Vdef, of_Wdef, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + + case 0x77: + if (prefix == 0) + if (options() & roVexPrefix) { + type_ = ctx.rex_prefix & 0x80 ? cmVzeroall : cmVzeroupper; + } + else { + type_ = cmEmms; + } + else + type_ = cmDB; + break; + + case 0x78: + /* Stick on Intel decoding here; ignore AMD. */ + if (prefix == 0) { + type_ = cmVmread; + os = size_; + code = ReadByte(file); + ReadRM(code, os, otRegistr, false, ctx); + ReadRegFromRM(code, os, otRegistr, ctx); + } else { + type_ = cmDB; + } + break; + + case 0x79: + /* Stick on Intel decoding here; ignore AMD. */ + if (prefix == 0) { + type_ = cmVmwrite; + os = size_; + code = ReadByte(file); + ReadRegFromRM(code, os, otRegistr, ctx); + ReadRM(code, os, otRegistr, false, ctx); + } else { + type_ = cmDB; + } + break; + + case 0x7c: + switch (prefix) { + case 0x66: + vex_operand_index = 1; + ReadCommand(cmHaddpd, of_Vdef, of_Wdef, of_None, ctx); + break; + case 0xF2: + preffix_command_ = cmUnknown; + vex_operand_index = 1; + ReadCommand(cmHaddps, of_Vdef, of_Wdef, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + + case 0x7d: + switch (prefix) { + case 0x66: + vex_operand_index = 1; + ReadCommand(cmHsubpd, of_Vdef, of_Wdef, of_None, ctx); + break; + case 0xF2: + preffix_command_ = cmUnknown; + vex_operand_index = 1; + ReadCommand(cmHsubps, of_Vdef, of_Wdef, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x7e: + switch (prefix) { + case 0x00: + ReadCommand(cmMovd, of_Ex, of_Pq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmMovd, of_Ex, of_Vdq, of_None, ctx); + break; + case 0xF3: + preffix_command_ = cmUnknown; + ReadCommand(cmMovq, of_Vdq, of_Wq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x7f: + switch (prefix) { + case 0x00: + ReadCommand(cmMovq, of_Qq, of_Pq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmMovdqa, of_Wdq, of_Vdq, of_None, ctx); + break; + case 0xF3: + preffix_command_ = cmUnknown; + ReadCommand(cmMovdqu, of_Wdef, of_Vdef, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + + case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87: + case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d: case 0x8e: case 0x8f: + ReadFlags(code); + ReadCommand(cmJmpWithFlag, of_Jz, of_None, of_None, ctx); + break; + + case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97: + case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f: + ReadFlags(code); + ReadCommand(cmSetXX, of_Eb, of_None, of_None, ctx); + break; + case 0xa0: + ReadCommand(cmPush, of_FSdef | segFS, of_None, of_None, ctx); + break; + case 0xa1: + ReadCommand(cmPop, of_FSdef | segFS, of_None, of_None, ctx); + break; + case 0xa2: + type_ = cmCpuid; + break; + case 0xa3: + ReadCommand(cmBt, of_Ev, of_Gv, of_None, ctx); + break; + case 0xa4: + ReadCommand(cmShld, of_Ev, of_Gv, of_IBb, ctx); + break; + case 0xa5: + ReadCommand(cmShld, of_Ev, of_Gv, of_FGb | regECX, ctx); + break; + case 0xa8: + ReadCommand(cmPush, of_FSdef | segGS, of_None, of_None, ctx); + break; + case 0xa9: + ReadCommand(cmPop, of_FSdef | segGS, of_None, of_None, ctx); + break; + case 0xaa: + type_ = cmRsm; + break; + case 0xab: + ReadCommand(cmBts, of_Ev, of_Gv, of_None, ctx); + break; + case 0xac: + ReadCommand(cmShrd, of_Ev, of_Gv, of_IBb, ctx); + break; + case 0xad: + ReadCommand(cmShrd, of_Ev, of_Gv, of_FGb | regECX, ctx); + break; + case 0xae: + code = ReadByte(file); + ctx.use_last_byte = true; + switch ((code >> 3) & 7) { + case 0x00: + ReadCommand(cmFxsave, of_M, of_None, of_None, ctx); + break; + case 0x01: + ReadCommand(cmFxrstor, of_M, of_None, of_None, ctx); + break; + case 0x02: + ReadCommand(cmLdmxcsr, of_Md, of_None, of_None, ctx); + break; + case 0x03: + ReadCommand(cmStmxcsr, of_Md, of_None, of_None, ctx); + break; + case 0x04: + ReadCommand(cmXsave, of_M, of_None, of_None, ctx); + break; + case 0x05: + if ((code & 0xc0) == 0xc0) { + type_ = cmLfence; + } else { + ReadCommand(cmXrstor, of_M, of_None, of_None, ctx); + } + break; + case 0x06: + if ((code & 0xc0) == 0xc0) { + type_ = cmMfence; + } else { + ReadCommand(cmXsaveopt, of_M, of_None, of_None, ctx); + } + break; + case 0x07: + if ((code & 0xc0) == 0xc0) { + type_ = cmSfence; + } else { + ReadCommand(cmClflush, of_M, of_None, of_None, ctx); + } + break; + default: + type_ = cmDB; + break; + } + break; + case 0xaf: + ReadCommand(cmImul, of_Gv, of_Ev, of_None, ctx); + break; + case 0xb0: + ReadCommand(cmCmpxchg, of_Eb, of_Gb, of_None, ctx); + break; + case 0xb1: + ReadCommand(cmCmpxchg, of_Ev, of_Gv, of_None, ctx); + break; + case 0xb2: + ReadCommand(cmLss, of_Gz, of_Mp, of_None, ctx); + break; + case 0xb3: + ReadCommand(cmBtr, of_Ev, of_Gv, of_None, ctx); + break; + case 0xb4: + ReadCommand(cmLfs, of_Gz, of_Mp, of_None, ctx); + break; + case 0xb5: + ReadCommand(cmLgs, of_Gz, of_Mp, of_None, ctx); + break; + case 0xb6: + ReadCommand(cmMovzx, of_Gv, of_Eb | of_size, of_None, ctx); + break; + case 0xb7: + ReadCommand(cmMovzx, of_Gv, of_Ew | of_size, of_None, ctx); + break; + case 0xb8: + switch (prefix) { + case 0xF3: + preffix_command_ = cmUnknown; + ReadCommand(cmPopcnt, of_Gv, of_Ev, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xb9: + switch (prefix) { + case 0x00: + case 0x66: + type_ = cmUd1; + break; + default: + type_ = cmDB; + break; + } + break; + case 0xba: + if (prefix == 0 || prefix == 0x66) { + code = ReadByte(file); + ctx.use_last_byte = true; + switch ((code >> 3) & 7) { + case 0x04: + ReadCommand(cmBt, of_Ev | of_size, of_IBb, of_None, ctx); + break; + case 0x05: + ReadCommand(cmBts, of_Ev | of_size, of_IBb, of_None, ctx); + break; + case 0x06: + ReadCommand(cmBtr, of_Ev | of_size, of_IBb, of_None, ctx); + break; + case 0x07: + ReadCommand(cmBtc, of_Ev | of_size, of_IBb, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + } else { + type_ = cmDB; + } + break; + + case 0xbb: + switch (prefix) { + case 0x00: + case 0x66: + ReadCommand(cmBtc, of_Ev, of_Gv, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + + case 0xbc: + switch (prefix) { + case 0x00: + case 0x66: + ReadCommand(cmBsf, of_Gv, of_Ev, of_None, ctx); + break; + case 0xF3: + preffix_command_ = cmUnknown; + ReadCommand(cmTzcnt, of_Gv, of_Ev, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xbd: + switch (prefix) { + case 0x00: + case 0x66: + ReadCommand(cmBsr, of_Gv, of_Ev, of_None, ctx); + break; + case 0xF3: + preffix_command_ = cmUnknown; + ReadCommand(cmLzcnt, of_Gv, of_Ev, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xbe: + switch (prefix) { + case 0x00: + case 0x66: + ReadCommand(cmMovsx, of_Gv, of_Eb | of_size, of_None, ctx); + break; + default: + type_ = cmDB; + } + break; + case 0xbf: + switch (prefix) { + case 0x00: + case 0x66: + ReadCommand(cmMovsx, of_Gv, of_Ew | of_size, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xc0: + ReadCommand(cmXadd, of_Eb, of_Gb, of_None, ctx); + break; + case 0xc1: + ReadCommand(cmXadd, of_Ev, of_Gv, of_None, ctx); + break; + case 0xc2: + switch (prefix) { + case 0x00: + vex_operand_index = 1; + ReadCommand(cmCmpps, of_Vdef, of_Wdef, of_IBb, ctx); + break; + case 0x66: + vex_operand_index = 1; + ReadCommand(cmCmppd, of_Vdef, of_Wdef, of_IBb, ctx); + break; + case 0xF2: + preffix_command_ = cmUnknown; + vex_operand_index = 1; + ReadCommand(cmCmpsd, of_Vdq, of_Wq, of_IBb, ctx); + break; + case 0xF3: + preffix_command_ = cmUnknown; + vex_operand_index = 1; + ReadCommand(cmCmpss, of_Vdq, of_Wd, of_IBb, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + + case 0xc3: + switch (prefix) { + case 0x00: + ReadCommand(cmMovnti, of_Mx, of_Gx, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + + case 0xc4: + switch (prefix) { + case 0x00: + ReadCommand(cmPinsrw, of_Pq, of_Ew | of_size, of_IBb, ctx); + break; + case 0x66: + ReadCommand(cmPinsrw, of_Vdq, of_Ew | of_size, of_IBb, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + + case 0xc5: + switch (prefix) { + case 0x00: + ReadCommand(cmPextrw, of_Gd, of_Nq, of_IBb, ctx); + break; + case 0x66: + ReadCommand(cmPextrw, of_Gd, of_Udq, of_IBb, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + + case 0xc6: + switch (prefix) { + case 0x00: + vex_operand_index = 1; + ReadCommand(cmShufps, of_Vdef, of_Wdef, of_IBb, ctx); + break; + case 0x66: + vex_operand_index = 1; + ReadCommand(cmShufpd, of_Vdef, of_Wdef, of_IBb, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + + case 0xc7: + code = ReadByte(file); + ctx.use_last_byte = true; + switch ((code >> 3) & 7) { + case 0x01: + ReadCommand(cmCmpxchg8b, of_Mq, of_None, of_None, ctx); + break; + case 0x06: + if (code && 0xc0 == 0xc0) + ReadCommand(cmRdrand, of_Zv | code, of_None, of_None, ctx); + else + ReadCommand(cmVmptrld, of_Mq, of_None, of_None, ctx); + break; + case 0x07: + if (code && 0xc0 == 0xc0) + ReadCommand(cmRdseed, of_Zv | code, of_None, of_None, ctx); + else + ReadCommand(cmVmptrst, of_Mq, of_None, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + + case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf: + ReadCommand(cmBswap, of_Zv | code, of_None, of_None, ctx); + break; + case 0xd0: + switch (prefix) { + case 0x66: + ReadCommand(cmAddsubpd, of_Vdq, of_Wdq, of_None, ctx); + break; + case 0xF2: + preffix_command_ = cmUnknown; + ReadCommand(cmAddsubps, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xd1: + switch (prefix) { + case 0x00: + ReadCommand(cmPsrlw, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPsrlw, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xd2: + switch (prefix) { + case 0x00: + ReadCommand(cmPsrld, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPsrld, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xd3: + switch (prefix) { + case 0x00: + ReadCommand(cmPsrlq, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPsrlq, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xd4: + switch (prefix) { + case 0x00: + ReadCommand(cmPaddq, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPaddq, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xd5: + switch (prefix) { + case 0x00: + ReadCommand(cmPmullw, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPmullw, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xd6: + switch (prefix) { + case 0x66: + ReadCommand(cmMovq, of_Wq, of_Vdq, of_None, ctx); + break; + case 0xF2: + preffix_command_ = cmUnknown; + ReadCommand(cmMovdq2q, of_Pq, of_Udq, of_None, ctx); + break; + case 0xF3: + preffix_command_ = cmUnknown; + ReadCommand(cmMovq2dq, of_Vdq, of_Nq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xd7: + switch (prefix) { + case 0x00: + ReadCommand(cmPmovmskb, of_Gd, of_Nq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPmovmskb, of_Gd, of_Udq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xd8: + switch (prefix) { + case 0x00: + ReadCommand(cmPsubusb, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPsubusb, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xd9: + switch (prefix) { + case 0x00: + ReadCommand(cmPsubusw, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPsubusw, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xda: + switch (prefix) { + case 0x00: + ReadCommand(cmPminub, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPminub, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xdb: + switch (prefix) { + case 0x00: + ReadCommand(cmPand, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPand, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xdc: + switch (prefix) { + case 0x00: + ReadCommand(cmPaddusb, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPaddusb, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xdd: + switch (prefix) { + case 0x00: + ReadCommand(cmPaddusw, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPaddusw, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xde: + switch (prefix) { + case 0x00: + ReadCommand(cmPmaxub, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPmaxub, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xdf: + switch (prefix) { + case 0x00: + ReadCommand(cmPandn, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPandn, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xe0: + switch (prefix) { + case 0x00: + ReadCommand(cmPavgb, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPavgb, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xe1: + switch (prefix) { + case 0x00: + ReadCommand(cmPsraw, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPsraw, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xe2: + switch (prefix) { + case 0x00: + ReadCommand(cmPsrad, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPsrad, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xe3: + switch (prefix) { + case 0x00: + ReadCommand(cmPavgw, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPavgw, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xe4: + switch (prefix) { + case 0x00: + ReadCommand(cmPmulhuw, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPmulhuw, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xe5: + switch (prefix) { + case 0x00: + ReadCommand(cmPmulhw, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPmulhw, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xe6: + switch (prefix) { + case 0x66: + ReadCommand(cmCvttpd2dq, of_Vdq, of_Wdef, of_None, ctx); + break; + case 0xF2: + preffix_command_ = cmUnknown; + ReadCommand(cmCvtpd2dq, of_Vdq, of_Wdef, of_None, ctx); + break; + case 0xF3: + preffix_command_ = cmUnknown; + ReadCommand(cmCvtdq2pd, of_Vdef, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xe7: + switch (prefix) { + case 0x00: + ReadCommand(cmMovntq, of_Mq, of_Pq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmMovntdq, of_Mdq, of_Vdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xe8: + switch (prefix) { + case 0x00: + ReadCommand(cmPsubsb, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPsubsb, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xe9: + switch (prefix) { + case 0x00: + ReadCommand(cmPsubsw, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPsubsw, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xea: + switch (prefix) { + case 0x00: + ReadCommand(cmPminsw, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPminsw, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xeb: + switch (prefix) { + case 0x00: + ReadCommand(cmPor, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPor, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xec: + switch (prefix) { + case 0x00: + ReadCommand(cmPaddsb, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPaddsb, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xed: + switch (prefix) { + case 0x00: + ReadCommand(cmPaddsw, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPaddsw, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xee: + switch (prefix) { + case 0x00: + ReadCommand(cmPmaxsw, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPmaxsw, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xef: + switch (prefix) { + case 0x00: + ReadCommand(cmPxor, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + vex_operand_index = 1; + ReadCommand(cmPxor, of_Vdef, of_Wdef, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + + case 0xf0: + switch (prefix) { + case 0xF2: + preffix_command_ = cmUnknown; + ReadCommand(cmLddqu, of_Vdef, of_Mdef, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + + case 0xf1: + switch (prefix) { + case 0x00: + ReadCommand(cmPsllw, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPsllw, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xf2: + switch (prefix) { + case 0x00: + ReadCommand(cmPslld, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPslld, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xf3: + switch (prefix) { + case 0x00: + ReadCommand(cmPsllq, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPsllq, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xf4: + switch (prefix) { + case 0x00: + ReadCommand(cmPmuludq, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPmuludq, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xf5: + switch (prefix) { + case 0x00: + ReadCommand(cmPmaddwd, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPmaddwd, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xf6: + switch (prefix) { + case 0x00: + ReadCommand(cmPsadbw, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPsadbw, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xf7: + switch (prefix) { + case 0x00: + ReadCommand(cmMaskmovq, of_Pq, of_Nq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmMaskmovdqu, of_Vdq, of_Udq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xf8: + switch (prefix) { + case 0x00: + ReadCommand(cmPsubb, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPsubb, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xf9: + switch (prefix) { + case 0x00: + ReadCommand(cmPsubw, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPsubw, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xfa: + switch (prefix) { + case 0x00: + ReadCommand(cmPsubd, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPsubd, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xfb: + switch (prefix) { + case 0x00: + ReadCommand(cmPsubq, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPsubq, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xfc: + switch (prefix) { + case 0x00: + ReadCommand(cmPaddb, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPaddb, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xfd: + switch (prefix) { + case 0x00: + ReadCommand(cmPaddw, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPaddw, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xfe: + switch (prefix) { + case 0x00: + ReadCommand(cmPaddd, of_Pq, of_Qq, of_None, ctx); + break; + case 0x66: + ReadCommand(cmPaddd, of_Vdq, of_Wdq, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xff: + type_ = cmUd0; + break; + + default: + type_ = cmDB; + break; + } + break; + + // End + + case 0x10: + ReadCommand(cmAdc, of_Eb, of_Gb, of_None, ctx); + break; + case 0x11: + ReadCommand(cmAdc, of_Ev, of_Gv, of_None, ctx); + break; + case 0x12: + ReadCommand(cmAdc, of_Gb, of_Eb, of_None, ctx); + break; + case 0x13: + ReadCommand(cmAdc, of_Gv, of_Ev, of_None, ctx); + break; + case 0x14: + ReadCommand(cmAdc, of_FGb | regEAX, of_IBb, of_None, ctx); + break; + case 0x15: + ReadCommand(cmAdc, of_FGv | regEAX, of_IZv, of_None, ctx); + break; + case 0x16: + if (size_ == osQWord) { + type_ = cmDB; + } else { + ReadCommand(cmPush, of_FSdef | segSS, of_None, of_None, ctx); + } + break; + case 0x17: + if (size_ == osQWord) { + type_ = cmDB; + } else { + ReadCommand(cmPop, of_FSdef | segSS, of_None, of_None, ctx); + } + break; + case 0x18: + ReadCommand(cmSbb, of_Eb, of_Gb, of_None, ctx); + break; + case 0x19: + ReadCommand(cmSbb, of_Ev, of_Gv, of_None, ctx); + break; + case 0x1a: + ReadCommand(cmSbb, of_Gb, of_Eb, of_None, ctx); + break; + case 0x1b: + ReadCommand(cmSbb, of_Gv, of_Ev, of_None, ctx); + break; + case 0x1c: + ReadCommand(cmSbb, of_FGb | regEAX, of_IBb, of_None, ctx); + break; + case 0x1d: + ReadCommand(cmSbb, of_FGv | regEAX, of_IZv, of_None, ctx); + break; + case 0x1e: + if (size_ == osQWord) { + type_ = cmDB; + } else { + ReadCommand(cmPush, of_FSdef | segDS, of_None, of_None, ctx); + } + break; + case 0x1f: + if (size_ == osQWord) { + type_ = cmDB; + } else { + ReadCommand(cmPop, of_FSdef | segDS, of_None, of_None, ctx); + } + break; + case 0x20: + ReadCommand(cmAnd, of_Eb, of_Gb, of_None, ctx); + break; + case 0x21: + ReadCommand(cmAnd, of_Ev, of_Gv, of_None, ctx); + break; + case 0x22: + ReadCommand(cmAnd, of_Gb, of_Eb, of_None, ctx); + break; + case 0x23: + ReadCommand(cmAnd, of_Gv, of_Ev, of_None, ctx); + break; + case 0x24: + ReadCommand(cmAnd, of_FGb | regEAX, of_IBb, of_None, ctx); + break; + case 0x25: + ReadCommand(cmAnd, of_FGv | regEAX, of_IZv, of_None, ctx); + break; + case 0x26: + base_segment_ = segES; + ctx.rex_prefix = 0; + break; + case 0x27: + type_ = (size_ == osQWord) ? cmDB : cmDaa; + break; + case 0x28: + ReadCommand(cmSub, of_Eb, of_Gb, of_None, ctx); + break; + case 0x29: + ReadCommand(cmSub, of_Ev, of_Gv, of_None, ctx); + break; + case 0x2a: + ReadCommand(cmSub, of_Gb, of_Eb, of_None, ctx); + break; + case 0x2b: + ReadCommand(cmSub, of_Gv, of_Ev, of_None, ctx); + break; + case 0x2c: + ReadCommand(cmSub, of_FGb | regEAX, of_IBb, of_None, ctx); + break; + case 0x2d: + ReadCommand(cmSub, of_FGv | regEAX, of_IZv, of_None, ctx); + break; + case 0x2e: + base_segment_ = segCS; ctx.rex_prefix = 0; + break; + case 0x2f: + type_ = (size_ == osQWord) ? cmDB : cmDas; + break; + case 0x30: + ReadCommand(cmXor, of_Eb, of_Gb, of_None, ctx); + break; + case 0x31: + ReadCommand(cmXor, of_Ev, of_Gv, of_None, ctx); + break; + case 0x32: + ReadCommand(cmXor, of_Gb, of_Eb, of_None, ctx); + break; + case 0x33: + ReadCommand(cmXor, of_Gv, of_Ev, of_None, ctx); + break; + case 0x34: + ReadCommand(cmXor, of_FGb | regEAX, of_IBb, of_None, ctx); + break; + case 0x35: + ReadCommand(cmXor, of_FGv | regEAX, of_IZv, of_None, ctx); + break; + case 0x36: + base_segment_ = segSS; + ctx.rex_prefix = 0; + break; + case 0x37: + type_ = (size_ == osQWord) ? cmDB : cmAaa; + break; + case 0x38: + ReadCommand(cmCmp, of_Eb, of_Gb, of_None, ctx); + break; + case 0x39: + ReadCommand(cmCmp, of_Ev, of_Gv, of_None, ctx); + break; + case 0x3a: + ReadCommand(cmCmp, of_Gb, of_Eb, of_None, ctx); + break; + case 0x3b: + ReadCommand(cmCmp, of_Gv, of_Ev, of_None, ctx); + break; + case 0x3c: + ReadCommand(cmCmp, of_FGb | regEAX, of_IBb, of_None, ctx); + break; + case 0x3d: + ReadCommand(cmCmp, of_FGv | regEAX, of_IZv, of_None, ctx); + break; + case 0x3e: + base_segment_ = segDS; + ctx.rex_prefix = 0; + break; + case 0x3f: + type_ = (size_ == osQWord) ? cmDB : cmAas; + break; + case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: + if (size_ == osQWord) { + ctx.rex_prefix = code; + } else { + ReadCommand(cmInc, of_Zdef | code, of_None, of_None, ctx); + } + break; + case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f: + if (size_ == osQWord) { + ctx.rex_prefix = code; + } else { + ReadCommand(cmDec, of_Zdef | code, of_None, of_None, ctx); + } + break; + case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: + ReadCommand(cmPush, of_Zdef | code, of_None, of_None, ctx); + break; + case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f: + ReadCommand(cmPop, of_Zdef | code, of_None, of_None, ctx); + break; + case 0x60: + if (size_ == osQWord) { + type_ = cmDB; + } else { + ReadCommand(cmPusha, of_def, of_None, of_None, ctx); + } + break; + case 0x61: + if (size_ == osQWord) { + type_ = cmDB; + } else { + ReadCommand(cmPopa, of_def, of_None, of_None, ctx); + } + break; + case 0x62: + if (size_ == osQWord) { + type_ = cmDB; + } else { + ReadCommand(cmBound, of_Gv, of_Ma, of_None, ctx); + } + break; + case 0x63: + if (size_ == osQWord) { + ReadCommand(cmMovsxd, of_Gv, of_Ed | of_size, of_None, ctx); + } else { + ReadCommand(cmArpl, of_Ew, of_Gw, of_None, ctx); + } + break; + case 0x64: + base_segment_ = segFS; + ctx.rex_prefix = 0; + break; + case 0x65: + base_segment_ = segGS; + ctx.rex_prefix = 0; + break; + case 0x66: + ctx.lower_reg = true; + if (prefix == 0) + prefix = code; + break; + case 0x67: + ctx.lower_address = true; + break; + case 0x68: + ReadCommand(cmPush, of_IZ | of_def, of_None, of_None, ctx); + break; + case 0x69: + ReadCommand(cmImul, of_Gv, of_Ev, of_IZv, ctx); + break; + case 0x6a: + ReadCommand(cmPush, of_IB | of_def, of_None, of_None, ctx); + break; + case 0x6b: + ReadCommand(cmImul, of_Gv, of_Ev, of_IBv, ctx); + break; + case 0x6c: + ReadCommand(cmIns, of_b, of_adr, of_None, ctx); + break; + case 0x6d: + ReadCommand(cmIns, of_z, of_adr, of_None, ctx); + break; + case 0x6e: + ReadCommand(cmOuts, of_b, of_adr, of_None, ctx); + break; + case 0x6f: + ReadCommand(cmOuts, of_z, of_adr, of_None, ctx); + break; + case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: + case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f: + ReadFlags(code); + ReadCommand(cmJmpWithFlag, of_Jb, of_adr, of_None, ctx); + break; + case 0x80: + code = ReadByte(file); + ctx.use_last_byte = true; + switch ((code >> 3) & 7) { + case 0x00: + ReadCommand(cmAdd, of_Eb | of_size, of_IBb, of_None, ctx); + break; + case 0x01: + ReadCommand(cmOr, of_Eb | of_size, of_IBb, of_None, ctx); + break; + case 0x02: + ReadCommand(cmAdc, of_Eb | of_size, of_IBb, of_None, ctx); + break; + case 0x03: + ReadCommand(cmSbb, of_Eb | of_size, of_IBb, of_None, ctx); + break; + case 0x04: + ReadCommand(cmAnd, of_Eb | of_size, of_IBb, of_None, ctx); + break; + case 0x05: + ReadCommand(cmSub, of_Eb | of_size, of_IBb, of_None, ctx); + break; + case 0x06: + ReadCommand(cmXor, of_Eb | of_size, of_IBb, of_None, ctx); + break; + case 0x07: + ReadCommand(cmCmp, of_Eb | of_size, of_IBb, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x81: + code = ReadByte(file); + ctx.use_last_byte = true; + switch ((code >> 3) & 7) { + case 0x00: + ReadCommand(cmAdd, of_Ev | of_size, of_IZv, of_None, ctx); + break; + case 0x01: + ReadCommand(cmOr, of_Ev | of_size, of_IZv, of_None, ctx); + break; + case 0x02: + ReadCommand(cmAdc, of_Ev | of_size, of_IZv, of_None, ctx); + break; + case 0x03: + ReadCommand(cmSbb, of_Ev | of_size, of_IZv, of_None, ctx); + break; + case 0x04: + ReadCommand(cmAnd, of_Ev | of_size, of_IZv, of_None, ctx); + break; + case 0x05: + ReadCommand(cmSub, of_Ev | of_size, of_IZv, of_None, ctx); + break; + case 0x06: + ReadCommand(cmXor, of_Ev | of_size, of_IZv, of_None, ctx); + break; + case 0x07: + ReadCommand(cmCmp, of_Ev | of_size, of_IZv, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x82: + if (size_ == osQWord) { + type_ = cmDB; + } else { + code = ReadByte(file); + ctx.use_last_byte = true; + switch ((code >> 3) & 7) { + case 0x00: + ReadCommand(cmAdd, of_Eb | of_size, of_IBb, of_None, ctx); + break; + case 0x01: + ReadCommand(cmOr, of_Eb | of_size, of_IBb, of_None, ctx); + break; + case 0x02: + ReadCommand(cmAdc, of_Eb | of_size, of_IBb, of_None, ctx); + break; + case 0x03: + ReadCommand(cmSbb, of_Eb | of_size, of_IBb, of_None, ctx); + break; + case 0x04: + ReadCommand(cmAnd, of_Eb | of_size, of_IBb, of_None, ctx); + break; + case 0x05: + ReadCommand(cmSub, of_Eb | of_size, of_IBb, of_None, ctx); + break; + case 0x06: + ReadCommand(cmXor, of_Eb | of_size, of_IBb, of_None, ctx); + break; + case 0x07: + ReadCommand(cmCmp, of_Eb | of_size, of_IBb, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + } + break; + case 0x83: + code = ReadByte(file); + ctx.use_last_byte = true; + switch ((code >> 3) & 7) { + case 0x00: + ReadCommand(cmAdd, of_Ev | of_size, of_IBv, of_None, ctx); + break; + case 0x01: + ReadCommand(cmOr, of_Ev | of_size, of_IBv, of_None, ctx); + break; + case 0x02: + ReadCommand(cmAdc, of_Ev | of_size, of_IBv, of_None, ctx); + break; + case 0x03: + ReadCommand(cmSbb, of_Ev | of_size, of_IBv, of_None, ctx); + break; + case 0x04: + ReadCommand(cmAnd, of_Ev | of_size, of_IBv, of_None, ctx); + break; + case 0x05: + ReadCommand(cmSub, of_Ev | of_size, of_IBv, of_None, ctx); + break; + case 0x06: + ReadCommand(cmXor, of_Ev | of_size, of_IBv, of_None, ctx); + break; + case 0x07: + ReadCommand(cmCmp, of_Ev | of_size, of_IBv, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x84: + ReadCommand(cmTest, of_Eb, of_Gb, of_None, ctx); + break; + case 0x85: + ReadCommand(cmTest, of_Ev, of_Gv, of_None, ctx); + break; + case 0x86: + ReadCommand(cmXchg, of_Eb, of_Gb, of_None, ctx); + break; + case 0x87: + ReadCommand(cmXchg, of_Ev, of_Gv, of_None, ctx); + break; + case 0x88: + ReadCommand(cmMov, of_Eb, of_Gb, of_None, ctx); + break; + case 0x89: + ReadCommand(cmMov, of_Ev, of_Gv, of_None, ctx); + break; + case 0x8a: + ReadCommand(cmMov, of_Gb, of_Eb, of_None, ctx); + break; + case 0x8b: + ReadCommand(cmMov, of_Gv, of_Ev, of_None, ctx); + break; + case 0x8c: + ReadCommand(cmMov, of_Ev | of_mem_word, of_Sw, of_None, ctx); + break; + case 0x8d: + ReadCommand(cmLea, of_Gv, of_Mv, of_None, ctx); + break; + case 0x8e: + ReadCommand(cmMov, of_Sw, of_Ew, of_None, ctx); + break; + case 0x8f: + code = ReadByte(file); + ctx.use_last_byte = true; + switch ((code >> 3) & 7) { + case 0x00: + ReadCommand(cmPop, of_Edef | of_size, of_None, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0x90: + if (prefix == 0xF3) { + preffix_command_ = cmUnknown; + type_ = cmPause; + } else { + if (size_ == osQWord && (ctx.rex_prefix & rexB) != 0) { + ReadCommand(cmXchg, of_Zv | regEAX, of_FGv | regEAX, of_None, ctx); + } else { + type_ = cmNop; + } + } + break; + case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97: + ReadCommand(cmXchg, of_Zv | code, of_FGv | regEAX, of_None, ctx); + break; + case 0x98: + os = GetOperandSize(1, ctx); + switch (os) { + case osWord: + type_ = cmCbw; + break; + case osDWord: + type_ = cmCwde; + break; + default: + type_ = cmCdqe; + break; + } + break; + case 0x99: + os = GetOperandSize(1, ctx); + switch (os) { + case osWord: + type_ = cmCwd; + break; + case osDWord: + type_ = cmCdq; + break; + default: + type_ = cmCqo; + break; + } + break; + case 0x9a: + if (size_ == osQWord) + type_ = cmDB; + else { + include_option(roFar); + ReadCommand(cmCall, of_Ap, of_None, of_None, ctx); + } + break; + case 0x9b: + type_ = cmWait; + { + Data old_dump; + for (i = 0; i < dump_size(); i++) { + old_dump.PushByte(dump(i)); + } + uint64_t pos = file.Tell(); + code = ReadByte(file); + switch (code) { + case 0xd9: + code = ReadByte(file); + ctx.use_last_byte = true; + if ((code & 0xc0) != 0xc0) { + switch ((code >> 3) & 7) { + case 0x06: + ReadCommand(cmFstenv, of_Mb, of_None, of_None, ctx); + break; + case 0x07: + ReadCommand(cmFstcw, of_Mw | of_size, of_None, of_None, ctx); + break; + } + } + break; + case 0xdb: + code = ReadByte(file); + ctx.use_last_byte = true; + switch (code) { + case 0xe2: + type_ = cmFclex; + break; + case 0xe3: + type_ = cmFinit; + break; + } + break; + case 0xdd: + code = ReadByte(file); + ctx.use_last_byte = true; + if ((code & 0xc0) != 0xc0) { + switch ((code >> 3) & 7) { + case 0x06: + ReadCommand(cmFsave, of_Mb, of_None, of_None, ctx); + break; + case 0x07: + ReadCommand(cmFstsw, of_Mw | of_size, of_None, of_None, ctx); + break; + } + } + break; + case 0xdf: + code = ReadByte(file); + ctx.use_last_byte = true; + if (code == 0xe0) + ReadCommand(cmFstsw, of_FGw | regEAX, of_None, of_None, ctx); + break; + } + if (type_ == cmWait) { + set_dump(old_dump.data(), old_dump.size()); + file.Seek(pos); + } + } + break; + case 0x9c: + ReadCommand(cmPushf, of_def, of_None, of_None, ctx); + break; + case 0x9d: + ReadCommand(cmPopf, of_def, of_None, of_None, ctx); + break; + case 0x9e: + ReadCommand(cmSahf, of_b, of_None, of_None, ctx); + break; + case 0x9f: + ReadCommand(cmLahf, of_b, of_None, of_None, ctx); + break; + case 0xa0: + ReadCommand(cmMov, of_FGb | regEAX, of_Ob, of_None, ctx); + break; + case 0xa1: + ReadCommand(cmMov, of_FGv | regEAX, of_Ov, of_None, ctx); + break; + case 0xa2: + ReadCommand(cmMov, of_Ob, of_FGb | regEAX, of_None, ctx); + break; + case 0xa3: + ReadCommand(cmMov, of_Ov, of_FGv | regEAX, of_None, ctx); + break; + case 0xa4: + ReadCommand(cmMovs, of_b, of_adr, of_None, ctx); + break; + case 0xa5: + ReadCommand(cmMovs, of_v, of_adr, of_None, ctx); + break; + case 0xa6: + ReadCommand(cmCmps, of_b, of_adr, of_None, ctx); + break; + case 0xa7: + ReadCommand(cmCmps, of_v, of_adr, of_None, ctx); + break; + case 0xa8: + ReadCommand(cmTest, of_FGb | regEAX, of_IBb, of_None, ctx); + break; + case 0xa9: + ReadCommand(cmTest, of_FGv | regEAX, of_IZv, of_None, ctx); + break; + case 0xaa: + ReadCommand(cmStos, of_b, of_adr, of_None, ctx); + break; + case 0xab: + ReadCommand(cmStos, of_v, of_adr, of_None, ctx); + break; + case 0xac: + ReadCommand(cmLods, of_b, of_adr, of_None, ctx); + break; + case 0xad: + ReadCommand(cmLods, of_v, of_adr, of_None, ctx); + break; + case 0xae: + ReadCommand(cmScas, of_b, of_adr, of_None, ctx); + break; + case 0xaf: + ReadCommand(cmScas, of_v, of_adr, of_None, ctx); + break; + case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7: + ReadCommand(cmMov, of_Zb | code, of_IBb, of_None, ctx); + break; + case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf: + ReadCommand(cmMov, of_Zv | code, of_IVv, of_None, ctx); + break; + case 0xc0: + code = ReadByte(file); + ctx.use_last_byte = true; + switch ((code >> 3) & 7) { + case 0x00: + ReadCommand(cmRol, of_Eb | of_size, of_IBb, of_None, ctx); + break; + case 0x01: + ReadCommand(cmRor, of_Eb | of_size, of_IBb, of_None, ctx); + break; + case 0x02: + ReadCommand(cmRcl, of_Eb | of_size, of_IBb, of_None, ctx); + break; + case 0x03: + ReadCommand(cmRcr, of_Eb | of_size, of_IBb, of_None, ctx); + break; + case 0x04: + ReadCommand(cmShl, of_Eb | of_size, of_IBb, of_None, ctx); + break; + case 0x05: + ReadCommand(cmShr, of_Eb | of_size, of_IBb, of_None, ctx); + break; + case 0x06: + ReadCommand(cmSal, of_Eb | of_size, of_IBb, of_None, ctx); + break; + case 0x07: + ReadCommand(cmSar, of_Eb | of_size, of_IBb, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xc1: + code = ReadByte(file); + ctx.use_last_byte = true; + switch ((code >> 3) & 7) { + case 0x00: + ReadCommand(cmRol, of_Ev | of_size, of_IBb, of_None, ctx); + break; + case 0x01: + ReadCommand(cmRor, of_Ev | of_size, of_IBb, of_None, ctx); + break; + case 0x02: + ReadCommand(cmRcl, of_Ev | of_size, of_IBb, of_None, ctx); + break; + case 0x03: + ReadCommand(cmRcr, of_Ev | of_size, of_IBb, of_None, ctx); + break; + case 0x04: + ReadCommand(cmShl, of_Ev | of_size, of_IBb, of_None, ctx); + break; + case 0x05: + ReadCommand(cmShr, of_Ev | of_size, of_IBb, of_None, ctx); + break; + case 0x06: + ReadCommand(cmSal, of_Ev | of_size, of_IBb, of_None, ctx); + break; + case 0x07: + ReadCommand(cmSar, of_Ev | of_size, of_IBb, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xc2: + ReadCommand(cmRet, of_IWw, of_None, of_None, ctx); + break; + case 0xc3: + type_ = cmRet; + break; + case 0xc4: + code = ReadByte(file); + if (size_ == osDWord && (code & 0xc0) == 0) { + ctx.use_last_byte = true; + ReadCommand(cmLes, of_Gz, of_Mp, of_None, ctx); + } else { + if (prefix || ctx.rex_prefix || (options() & roLockPrefix)) + type_ = cmDB; + else { + include_option(roVexPrefix); + uint8_t vex_1 = code; + uint8_t vex_2 = ReadByte(file); + switch (vex_1 & 0x1f) { + case 1: + vex_bytes[0] = 0x0f; + break; + case 2: + vex_bytes[0] = 0x0f; + vex_bytes[1] = 0x38; + break; + case 3: + vex_bytes[0] = 0x0f; + vex_bytes[1] = 0x3a; + break; + default: + type_ = cmDB; + } + switch (vex_2 & 3) { + case 1: + prefix = 0x66; + break; + case 2: + prefix = 0xf3; + break; + case 3: + prefix = 0xf2; + break; + } + ctx.rex_prefix = static_cast(~vex_1) >> 5; // REX.RXB + ctx.rex_prefix |= (vex_2 & 0x80) >> 4; // REX.W + ctx.rex_prefix |= (vex_2 & 4) << 5; // VEX.L + ctx.vex_registr = ((~vex_2) >> 3) & 0xf; + } + } + break; + case 0xc5: + code = ReadByte(file); + if (size_ == osDWord && (code & 0xc0) == 0) { + ctx.use_last_byte = true; + ReadCommand(cmLds, of_Gz, of_Mp, of_None, ctx); + } else { + if (prefix || ctx.rex_prefix || (options() & roLockPrefix)) + type_ = cmDB; + else { + include_option(roVexPrefix); + uint8_t vex_1 = code; + vex_bytes[0] = 0x0f; + switch (vex_1 & 3) { + case 1: + prefix = 0x66; + break; + case 2: + prefix = 0xf3; + break; + case 3: + prefix = 0xf2; + break; + } + ctx.rex_prefix = (static_cast(~vex_1) & 0x80) >> 5; // REX.R + ctx.rex_prefix |= (vex_1 & 4) << 5; // VEX.L + ctx.vex_registr = ((~vex_1) >> 3) & 0xf; + } + } + break; + case 0xc6: + code = ReadByte(file); + ctx.use_last_byte = true; + switch ((code >> 3) & 7) { + case 0x00: + ReadCommand(cmMov, of_Eb | of_size, of_IBb, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xc7: + code = ReadByte(file); + ctx.use_last_byte = true; + switch ((code >> 3) & 7) { + case 0x00: + ReadCommand(cmMov, of_Ev | of_size, of_IZv, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xc8: + ReadCommand(cmEnter, of_IWw, of_IBb, of_None, ctx); + break; + case 0xc9: + type_ = cmLeave; + break; + case 0xca: + include_option(roFar); + ReadCommand(cmRet, of_IWw, of_None, of_None, ctx); + break; + case 0xcb: + include_option(roFar); + type_ = cmRet; + break; + case 0xcc: + ReadCommand(cmInt, of_FIb | 3, of_None, of_None, ctx); + break; + case 0xcd: + ReadCommand(cmInt, of_IBb, of_None, of_None, ctx); + break; + case 0xce: + if (size_ == osQWord) { + type_ = cmDB; + } else { + type_ = cmInto; + } + break; + case 0xcf: + ReadCommand(cmIret, of_v, of_None, of_None, ctx); + break; + case 0xd0: + code = ReadByte(file); + ctx.use_last_byte = true; + switch ((code >> 3) & 7) { + case 0x00: + ReadCommand(cmRol, of_Eb | of_size, of_FIb | 1, of_None, ctx); + break; + case 0x01: + ReadCommand(cmRor, of_Eb | of_size, of_FIb | 1, of_None, ctx); + break; + case 0x02: + ReadCommand(cmRcl, of_Eb | of_size, of_FIb | 1, of_None, ctx); + break; + case 0x03: + ReadCommand(cmRcr, of_Eb | of_size, of_FIb | 1, of_None, ctx); + break; + case 0x04: + ReadCommand(cmShl, of_Eb | of_size, of_FIb | 1, of_None, ctx); + break; + case 0x05: + ReadCommand(cmShr, of_Eb | of_size, of_FIb | 1, of_None, ctx); + break; + case 0x06: + ReadCommand(cmSal, of_Eb | of_size, of_FIb | 1, of_None, ctx); + break; + case 0x07: + ReadCommand(cmSar, of_Eb | of_size, of_FIb | 1, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xd1: + code = ReadByte(file); + ctx.use_last_byte = true; + switch ((code >> 3) & 7) { + case 0x00: + ReadCommand(cmRol, of_Ev | of_size, of_FIb | 1, of_None, ctx); + break; + case 0x01: + ReadCommand(cmRor, of_Ev | of_size, of_FIb | 1, of_None, ctx); + break; + case 0x02: + ReadCommand(cmRcl, of_Ev | of_size, of_FIb | 1, of_None, ctx); + break; + case 0x03: + ReadCommand(cmRcr, of_Ev | of_size, of_FIb | 1, of_None, ctx); + break; + case 0x04: + ReadCommand(cmShl, of_Ev | of_size, of_FIb | 1, of_None, ctx); + break; + case 0x05: + ReadCommand(cmShr, of_Ev | of_size, of_FIb | 1, of_None, ctx); + break; + case 0x06: + ReadCommand(cmSal, of_Ev | of_size, of_FIb | 1, of_None, ctx); + break; + case 0x07: + ReadCommand(cmSar, of_Ev | of_size, of_FIb | 1, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xd2: + code = ReadByte(file); + ctx.use_last_byte = true; + switch ((code >> 3) & 7) { + case 0x00: + ReadCommand(cmRol, of_Eb | of_size, of_FGb | regECX, of_None, ctx); + break; + case 0x01: + ReadCommand(cmRor, of_Eb | of_size, of_FGb | regECX, of_None, ctx); + break; + case 0x02: + ReadCommand(cmRcl, of_Eb | of_size, of_FGb | regECX, of_None, ctx); + break; + case 0x03: + ReadCommand(cmRcr, of_Eb | of_size, of_FGb | regECX, of_None, ctx); + break; + case 0x04: + ReadCommand(cmShl, of_Eb | of_size, of_FGb | regECX, of_None, ctx); + break; + case 0x05: + ReadCommand(cmShr, of_Eb | of_size, of_FGb | regECX, of_None, ctx); + break; + case 0x06: + ReadCommand(cmSal, of_Eb | of_size, of_FGb | regECX, of_None, ctx); + break; + case 0x07: + ReadCommand(cmSar, of_Eb | of_size, of_FGb | regECX, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xd3: + code = ReadByte(file); + ctx.use_last_byte = true; + switch ((code >> 3) & 7) { + case 0x00: + ReadCommand(cmRol, of_Ev | of_size, of_FGb | regECX, of_None, ctx); + break; + case 0x01: + ReadCommand(cmRor, of_Ev | of_size, of_FGb | regECX, of_None, ctx); + break; + case 0x02: + ReadCommand(cmRcl, of_Ev | of_size, of_FGb | regECX, of_None, ctx); + break; + case 0x03: + ReadCommand(cmRcr, of_Ev | of_size, of_FGb | regECX, of_None, ctx); + break; + case 0x04: + ReadCommand(cmShl, of_Ev | of_size, of_FGb | regECX, of_None, ctx); + break; + case 0x05: + ReadCommand(cmShr, of_Ev | of_size, of_FGb | regECX, of_None, ctx); + break; + case 0x06: + ReadCommand(cmSal, of_Ev | of_size, of_FGb | regECX, of_None, ctx); + break; + case 0x07: + ReadCommand(cmSar, of_Ev | of_size, of_FGb | regECX, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xd4: + if (size_ == osQWord) { + type_ = cmDB; + } else { + ReadCommand(cmAam, of_IBb, of_None, of_None, ctx); + } + break; + case 0xd5: + if (size_ == osQWord) { + type_ = cmDB; + } else { + ReadCommand(cmAad, of_IBb, of_None, of_None, ctx); + } + break; + case 0xd7: + ReadCommand(cmXlat, of_adr, of_None, of_None, ctx); + break; + case 0xd8: + code = ReadByte(file); + ctx.use_last_byte = true; + if ((code & 0xc0) != 0xc0) { + switch ((code >> 3) & 7) { + case 0x00: + ReadCommand(cmFadd, of_Md | of_size, of_None, of_None, ctx); + break; + case 0x01: + ReadCommand(cmFmul, of_Md | of_size, of_None, of_None, ctx); + break; + case 0x02: + ReadCommand(cmFcom, of_Md | of_size, of_None, of_None, ctx); + break; + case 0x03: + ReadCommand(cmFcomp, of_Md | of_size, of_None, of_None, ctx); + break; + case 0x04: + ReadCommand(cmFsub, of_Md | of_size, of_None, of_None, ctx); + break; + case 0x05: + ReadCommand(cmFsubr, of_Md | of_size, of_None, of_None, ctx); + break; + case 0x06: + ReadCommand(cmFdiv, of_Md | of_size, of_None, of_None, ctx); + break; + case 0x07: + ReadCommand(cmFdivr, of_Md | of_size, of_None, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + } else { + switch ((code >> 3) & 7) { + case 0x00: + ReadCommand(cmFadd, of_ST | 0, of_ST | code, of_None, ctx); + break; + case 0x01: + ReadCommand(cmFmul, of_ST | 0, of_ST | code, of_None, ctx); + break; + case 0x02: + ReadCommand(cmFcom, of_ST | 0, of_ST | code, of_None, ctx); + break; + case 0x03: + ReadCommand(cmFcomp, of_ST | 0, of_ST | code, of_None, ctx); + break; + case 0x04: + ReadCommand(cmFsub, of_ST | 0, of_ST | code, of_None, ctx); + break; + case 0x05: + ReadCommand(cmFsubr, of_ST | 0, of_ST | code, of_None, ctx); + break; + case 0x06: + ReadCommand(cmFdiv, of_ST | 0, of_ST | code, of_None, ctx); + break; + case 0x07: + ReadCommand(cmFdivr, of_ST | 0, of_ST | code, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + } + break; + case 0xd9: + code = ReadByte(file); + ctx.use_last_byte = true; + if ((code & 0xc0) != 0xc0) { + switch ((code >> 3) & 7) { + case 0x00: + ReadCommand(cmFld, of_Md | of_size, of_None, of_None, ctx); + break; + case 0x02: + ReadCommand(cmFst, of_Md | of_size, of_None, of_None, ctx); + break; + case 0x03: + ReadCommand(cmFstp, of_Md | of_size, of_None, of_None, ctx); + break; + case 0x04: + ReadCommand(cmFldenv, of_Mb, of_None, of_None, ctx); + break; + case 0x05: + ReadCommand(cmFldcw, of_Mw | of_size, of_None, of_None, ctx); + break; + case 0x06: + ReadCommand(cmFnstenv, of_Mb, of_None, of_None, ctx); + break; + case 0x07: + ReadCommand(cmFnstcw, of_Mw | of_size, of_None, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + } else { + switch (code) { + case 0xc0: case 0xc1: case 0xc2: case 0xc3: + case 0xc4: case 0xc5: case 0xc6: case 0xc7: + ReadCommand(cmFld, of_ST | 0, of_ST | code, of_None, ctx); + break; + case 0xc8: case 0xc9: case 0xca: case 0xcb: + case 0xcc: case 0xcd: case 0xce: case 0xcf: + ReadCommand(cmFxch, of_ST | 0, of_ST | code, of_None, ctx); + break; + case 0xd0: + type_ = cmFnop; + break; + case 0xd8: case 0xd9: case 0xda: case 0xdb: + case 0xdc: case 0xdd: case 0xde: case 0xdf: + ReadCommand(cmFstp1, of_ST | code, of_None, of_None, ctx); + break; + case 0xe0: + type_ = cmFchs; + break; + case 0xe1: + type_ = cmFabs; + break; + case 0xe4: + type_ = cmFtst; + break; + case 0xe5: + type_ = cmFxam; + break; + case 0xe8: + type_ = cmFld1; + break; + case 0xe9: + type_ = cmFldl2t; + break; + case 0xea: + type_ = cmFldl2e; + break; + case 0xeb: + type_ = cmFldpi; + break; + case 0xec: + type_ = cmFldlg2; + break; + case 0xed: + type_ = cmFldln2; + break; + case 0xee: + type_ = cmFldz; + break; + case 0xf0: + type_ = cmF2xm1; + break; + case 0xf1: + type_ = cmFyl2x; + break; + case 0xf2: + type_ = cmFptan; + break; + case 0xf3: + type_ = cmFpatan; + break; + case 0xf4: + type_ = cmFxtract; + break; + case 0xf5: + type_ = cmFprem1; + break; + case 0xf6: + type_ = cmFdecstp; + break; + case 0xf7: + type_ = cmFincstp; + break; + case 0xf8: + type_ = cmFprem; + break; + case 0xf9: + type_ = cmFyl2xp1; + break; + case 0xfa: + type_ = cmFsqrt; + break; + case 0xfb: + type_ = cmFsincos; + break; + case 0xfc: + type_ = cmFrndint; + break; + case 0xfd: + type_ = cmFscale; + break; + case 0xfe: + type_ = cmFsin; + break; + case 0xff: + type_ = cmFcos; + break; + default: + type_ = cmDB; + break; + } + } + break; + case 0xda: + code = ReadByte(file); + ctx.use_last_byte = true; + if ((code & 0xc0) != 0xc0) { + switch ((code >> 3) & 7) { + case 0x00: + ReadCommand(cmFiadd, of_Md | of_size, of_None, of_None, ctx); + break; + case 0x01: + ReadCommand(cmFimul, of_Md | of_size, of_None, of_None, ctx); + break; + case 0x02: + ReadCommand(cmFicom, of_Md | of_size, of_None, of_None, ctx); + break; + case 0x03: + ReadCommand(cmFicomp, of_Md | of_size, of_None, of_None, ctx); + break; + case 0x04: + ReadCommand(cmFisub, of_Md | of_size, of_None, of_None, ctx); + break; + case 0x05: + ReadCommand(cmFisubr, of_Md | of_size, of_None, of_None, ctx); + break; + case 0x06: + ReadCommand(cmFidiv, of_Md | of_size, of_None, of_None, ctx); + break; + case 0x07: + ReadCommand(cmFidivr, of_Md | of_size, of_None, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + } else { + switch (code) { + case 0xc0: case 0xc1: case 0xc2: case 0xc3: + case 0xc4: case 0xc5: case 0xc6: case 0xc7: + ReadCommand(cmFcmovb, of_ST | 0, of_ST | code, of_None, ctx); + break; + case 0xc8: case 0xc9: case 0xca: case 0xcb: + case 0xcc: case 0xcd: case 0xce: case 0xcf: + ReadCommand(cmFcmove, of_ST | 0, of_ST | code, of_None, ctx); + break; + case 0xd0: case 0xd1: case 0xd2: case 0xd3: + case 0xd4: case 0xd5: case 0xd6: case 0xd7: + ReadCommand(cmFcmovbe, of_ST | 0, of_ST | code, of_None, ctx); + break; + case 0xd8: case 0xd9: case 0xda: case 0xdb: + case 0xdc: case 0xdd: case 0xde: case 0xdf: + ReadCommand(cmFcmovu, of_ST | 0, of_ST | code, of_None, ctx); + break; + case 0xe9: + type_ = cmFucompp; + break; + default: + type_ = cmDB; + break; + } + } + break; + case 0xdb: + code = ReadByte(file); + ctx.use_last_byte = true; + if ((code & 0xc0) != 0xc0) { + switch ((code >> 3) & 7) { + case 0x00: + ReadCommand(cmFild, of_Md | of_size, of_None, of_None, ctx); + break; + case 0x01: + ReadCommand(cmFisttp, of_Md | of_size, of_None, of_None, ctx); + break; + case 0x02: + ReadCommand(cmFist, of_Md | of_size, of_None, of_None, ctx); + break; + case 0x03: + ReadCommand(cmFistp, of_Md | of_size, of_None, of_None, ctx); + break; + case 0x05: + ReadCommand(cmFld, of_Mt | of_size, of_None, of_None, ctx); + break; + case 0x07: + ReadCommand(cmFstp, of_Mt | of_size, of_None, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + } else { + switch (code) { + case 0xc0: case 0xc1: case 0xc2: case 0xc3: + case 0xc4: case 0xc5: case 0xc6: case 0xc7: + ReadCommand(cmFcmovnb, of_ST | 0, of_ST | code, of_None, ctx); + break; + case 0xc8: case 0xc9: case 0xca: case 0xcb: + case 0xcc: case 0xcd: case 0xce: case 0xcf: + ReadCommand(cmFcmovne, of_ST | 0, of_ST | code, of_None, ctx); + break; + case 0xd0: case 0xd1: case 0xd2: case 0xd3: + case 0xd4: case 0xd5: case 0xd6: case 0xd7: + ReadCommand(cmFcmovnbe, of_ST | 0, of_ST | code, of_None, ctx); + break; + case 0xd8: case 0xd9: case 0xda: case 0xdb: + case 0xdc: case 0xdd: case 0xde: case 0xdf: + ReadCommand(cmFcmovnu, of_ST | 0, of_ST | code, of_None, ctx); + break; + case 0xe2: + type_ = cmFnclex; + break; + case 0xe3: + type_ = cmFninit; + break; + case 0xe8: case 0xe9: case 0xea: case 0xeb: + case 0xec: case 0xed: case 0xee: case 0xef: + ReadCommand(cmFucomi, of_ST | 0, of_ST | code, of_None, ctx); + break; + case 0xf0: case 0xf1: case 0xf2: case 0xf3: + case 0xf4: case 0xf5: case 0xf6: case 0xf7: + ReadCommand(cmFcomi, of_ST | 0, of_ST | code, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + } + break; + case 0xdc: + code = ReadByte(file); + ctx.use_last_byte = true; + if ((code & 0xc0) != 0xc0) { + switch ((code >> 3) & 7) { + case 0x00: + ReadCommand(cmFadd, of_Mq | of_size, of_None, of_None, ctx); + break; + case 0x01: + ReadCommand(cmFmul, of_Mq | of_size, of_None, of_None, ctx); + break; + case 0x02: + ReadCommand(cmFcom, of_Mq | of_size, of_None, of_None, ctx); + break; + case 0x03: + ReadCommand(cmFcomp, of_Mq | of_size, of_None, of_None, ctx); + break; + case 0x04: + ReadCommand(cmFsub, of_Mq | of_size, of_None, of_None, ctx); + break; + case 0x05: + ReadCommand(cmFsubr, of_Mq | of_size, of_None, of_None, ctx); + break; + case 0x06: + ReadCommand(cmFdiv, of_Mq | of_size, of_None, of_None, ctx); + break; + case 0x07: + ReadCommand(cmFdivr, of_Mq | of_size, of_None, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + } else { + switch ((code >> 3) & 7) { + case 0x00: + ReadCommand(cmFadd, of_ST | code, of_ST | 0, of_None, ctx); + break; + case 0x01: + ReadCommand(cmFmul, of_ST | code, of_ST | 0, of_None, ctx); + break; + case 0x02: + ReadCommand(cmFcom2, of_ST | code, of_None, of_None, ctx); + break; + case 0x03: + ReadCommand(cmFcomp3, of_ST | code, of_None, of_None, ctx); + break; + case 0x04: + ReadCommand(cmFsubr, of_ST | code, of_ST | 0, of_None, ctx); + break; + case 0x05: + ReadCommand(cmFsub, of_ST | code, of_ST | 0, of_None, ctx); + break; + case 0x06: + ReadCommand(cmFdivr, of_ST | code, of_ST | 0, of_None, ctx); + break; + case 0x07: + ReadCommand(cmFdiv, of_ST | code, of_ST | 0, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + } + break; + case 0xdd: + code = ReadByte(file); + ctx.use_last_byte = true; + if ((code & 0xc0) != 0xc0) { + switch ((code >> 3) & 7) { + case 0x00: + ReadCommand(cmFld, of_Mq | of_size, of_None, of_None, ctx); + break; + case 0x01: + ReadCommand(cmFisttp, of_Mq | of_size, of_None, of_None, ctx); + break; + case 0x02: + ReadCommand(cmFst, of_Mq | of_size, of_None, of_None, ctx); + break; + case 0x03: + ReadCommand(cmFstp, of_Mq | of_size, of_None, of_None, ctx); + break; + case 0x04: + ReadCommand(cmFrstor, of_Mb, of_None, of_None, ctx); + break; + case 0x06: + ReadCommand(cmFnsave, of_Mb, of_None, of_None, ctx); + break; + case 0x07: + ReadCommand(cmFnstsw, of_Mw | of_size, of_None, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + } else { + switch ((code >> 3) & 7) { + case 0x00: + ReadCommand(cmFfree, of_ST | code, of_None, of_None, ctx); + break; + case 0x01: + ReadCommand(cmFxch4, of_ST | code, of_None, of_None, ctx); + break; + case 0x02: + ReadCommand(cmFst, of_ST | code, of_None, of_None, ctx); + break; + case 0x03: + ReadCommand(cmFstp, of_ST | code, of_None, of_None, ctx); + break; + case 0x04: + ReadCommand(cmFucom, of_ST | code, of_None, of_None, ctx); + break; + case 0x05: + ReadCommand(cmFucomp, of_ST | code, of_None, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + } + break; + case 0xde: + code = ReadByte(file); + ctx.use_last_byte = true; + if ((code & 0xc0) != 0xc0) { + switch ((code >> 3) & 7) { + case 0x00: + ReadCommand(cmFiadd, of_Mw | of_size, of_None, of_None, ctx); + break; + case 0x01: + ReadCommand(cmFimul, of_Mw | of_size, of_None, of_None, ctx); + break; + case 0x02: + ReadCommand(cmFicom, of_Mw | of_size, of_None, of_None, ctx); + break; + case 0x03: + ReadCommand(cmFicomp, of_Mw | of_size, of_None, of_None, ctx); + break; + case 0x04: + ReadCommand(cmFisub, of_Mw | of_size, of_None, of_None, ctx); + break; + case 0x05: + ReadCommand(cmFisubr, of_Mw | of_size, of_None, of_None, ctx); + break; + case 0x06: + ReadCommand(cmFidiv, of_Mw | of_size, of_None, of_None, ctx); + break; + case 0x07: + ReadCommand(cmFidivr, of_Mw | of_size, of_None, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + } else { + switch (code) { + case 0xc0: case 0xc1: case 0xc2: case 0xc3: + case 0xc4: case 0xc5: case 0xc6: case 0xc7: + ReadCommand(cmFaddp, of_ST | code, of_ST | 0, of_None, ctx); + break; + case 0xc8: case 0xc9: case 0xca: case 0xcb: + case 0xcc: case 0xcd: case 0xce: case 0xcf: + ReadCommand(cmFmulp, of_ST | code, of_ST | 0, of_None, ctx); + break; + case 0xd0: case 0xd1: case 0xd2: case 0xd3: + case 0xd4: case 0xd5: case 0xd6: case 0xd7: + ReadCommand(cmFcomp5, of_ST | code, of_None, of_None, ctx); + break; + case 0xd9: + type_ = cmFcompp; + break; + case 0xe0: case 0xe1: case 0xe2: case 0xe3: + case 0xe4: case 0xe5: case 0xe6: case 0xe7: + ReadCommand(cmFsubrp, of_ST | code, of_ST | 0, of_None, ctx); + break; + case 0xe8: case 0xe9: case 0xea: case 0xeb: + case 0xec: case 0xed: case 0xee: case 0xef: + ReadCommand(cmFsubp, of_ST | code, of_ST | 0, of_None, ctx); + break; + case 0xf0: case 0xf1: case 0xf2: case 0xf3: + case 0xf4: case 0xf5: case 0xf6: case 0xf7: + ReadCommand(cmFdivrp, of_ST | code, of_ST | 0, of_None, ctx); + break; + case 0xf8: case 0xf9: case 0xfa: case 0xfb: + case 0xfc: case 0xfd: case 0xfe: case 0xff: + ReadCommand(cmFdivp, of_ST | code, of_ST | 0, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + } + break; + case 0xdf: + code = ReadByte(file); + ctx.use_last_byte = true; + if ((code & 0xc0) != 0xc0) { + switch ((code >> 3) & 7) { + case 0x00: + ReadCommand(cmFild, of_Mw | of_size, of_None, of_None, ctx); + break; + case 0x01: + ReadCommand(cmFisttp, of_Mw | of_size, of_None, of_None, ctx); + break; + case 0x02: + ReadCommand(cmFist, of_Mw | of_size, of_None, of_None, ctx); + break; + case 0x03: + ReadCommand(cmFistp, of_Mw | of_size, of_None, of_None, ctx); + break; + case 0x04: + ReadCommand(cmFbld, of_Mt, of_None, of_None, ctx); + break; + case 0x05: + ReadCommand(cmFild, of_Mq | of_size, of_None, of_None, ctx); + break; + case 0x06: + ReadCommand(cmFbstp, of_Mt, of_None, of_None, ctx); + break; + case 0x07: + ReadCommand(cmFistp, of_Mq | of_size, of_None, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + } else { + switch (code) { + case 0xc0: case 0xc1: case 0xc2: case 0xc3: + case 0xc4: case 0xc5: case 0xc6: case 0xc7: + ReadCommand(cmFfreep, of_ST | code, of_None, of_None, ctx); + break; + case 0xc8: case 0xc9: case 0xca: case 0xcb: + case 0xcc: case 0xcd: case 0xce: case 0xcf: + ReadCommand(cmFxch7, of_ST | code, of_None, of_None, ctx); + break; + case 0xd0: case 0xd1: case 0xd2: case 0xd3: + case 0xd4: case 0xd5: case 0xd6: case 0xd7: + ReadCommand(cmFstp8, of_ST | code, of_None, of_None, ctx); + break; + case 0xd8: case 0xd9: case 0xda: case 0xdb: + case 0xdc: case 0xdd: case 0xde: case 0xdf: + ReadCommand(cmFstp9, of_ST | code, of_None, of_None, ctx); + break; + case 0xe0: + ReadCommand(cmFnstsw, of_FGw | regEAX, of_None, of_None, ctx); + break; + case 0xe8: case 0xe9: case 0xea: case 0xeb: + case 0xec: case 0xed: case 0xee: case 0xef: + ReadCommand(cmFucomip, of_ST | 0, of_ST | code, of_None, ctx); + break; + case 0xf0: case 0xf1: case 0xf2: case 0xf3: + case 0xf4: case 0xf5: case 0xf6: case 0xf7: + ReadCommand(cmFcomip, of_ST | 0, of_ST | code, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + } + break; + case 0xe0: + ReadCommand(cmLoopne, of_Jb, of_adr, of_None, ctx); + break; + case 0xe1: + ReadCommand(cmLoope, of_Jb, of_adr, of_None, ctx); + break; + case 0xe2: + ReadCommand(cmLoop, of_Jb, of_adr, of_None, ctx); + break; + case 0xe3: + ReadCommand(cmJCXZ, of_Jb, of_adr, of_None, ctx); + break; + case 0xe4: + ReadCommand(cmIn, of_FGb | regEAX, of_IBb, of_None, ctx); + break; + case 0xe5: + ReadCommand(cmIn, of_FGv | regEAX, of_IBb, of_None, ctx); + break; + case 0xe6: + ReadCommand(cmOut, of_IBb, of_FGb | regEAX, of_None, ctx); + break; + case 0xe7: + ReadCommand(cmOut, of_IBb, of_FGv | regEAX, of_None, ctx); + break; + case 0xe8: + ReadCommand(cmCall, of_Jz, of_None, of_None, ctx); + break; + case 0xe9: + ReadCommand(cmJmp, of_Jz, of_None, of_None, ctx); + break; + case 0xea: + if (size_ == osQWord) + type_ = cmDB; + else { + include_option(roFar); + ReadCommand(cmJmp, of_Ap, of_None, of_None, ctx); + } + break; + case 0xeb: + ReadCommand(cmJmp, of_Jb, of_None, of_None, ctx); + break; + case 0xec: + ReadCommand(cmIn, of_FGb | regEAX, of_FGw | regEDX, of_None, ctx); + break; + case 0xed: + ReadCommand(cmIn, of_FGv | regEAX, of_FGw | regEDX, of_None, ctx); + break; + case 0xee: + ReadCommand(cmOut, of_FGw | regEDX, of_FGb | regEAX, of_None, ctx); + break; + case 0xef: + ReadCommand(cmOut, of_FGw | regEDX, of_FGv | regEAX, of_None, ctx); + break; + case 0xf0: + include_option(roLockPrefix); + break; + case 0xf1: + ReadCommand(cmInt, of_FIb | 1, of_None, of_None, ctx); + break; + case 0xf2: + preffix_command_ = cmRepne; + prefix = code; + break; + case 0xf3: + preffix_command_ = cmRep; + prefix = code; + break; + case 0xf4: + type_ = cmHlt; + break; + case 0xf5: + type_ = cmCmc; + break; + case 0xf6: + code = ReadByte(file); + ctx.use_last_byte = true; + switch ((code >> 3) & 7) { + case 0x00: + case 0x01: + ReadCommand(cmTest, of_Eb | of_size, of_IBb, of_None, ctx); + break; + case 0x02: + ReadCommand(cmNot, of_Eb | of_size, of_None, of_None, ctx); + break; + case 0x03: + ReadCommand(cmNeg, of_Eb | of_size, of_None, of_None, ctx); + break; + case 0x04: + ReadCommand(cmMul, of_Eb | of_size, of_None, of_None, ctx); + break; + case 0x05: + ReadCommand(cmImul, of_Eb | of_size, of_None, of_None, ctx); + break; + case 0x06: + ReadCommand(cmDiv, of_Eb | of_size, of_None, of_None, ctx); + break; + case 0x07: + ReadCommand(cmIdiv, of_Eb | of_size, of_None, of_None, ctx); + break; + } + break; + case 0xf7: + code = ReadByte(file); + ctx.use_last_byte = true; + switch ((code >> 3) & 7) { + case 0x00: + case 0x01: + ReadCommand(cmTest, of_Ev | of_size, of_IZv, of_None, ctx); + break; + case 0x02: + ReadCommand(cmNot, of_Ev | of_size, of_None, of_None, ctx); + break; + case 0x03: + ReadCommand(cmNeg, of_Ev | of_size, of_None, of_None, ctx); + break; + case 0x04: + ReadCommand(cmMul, of_Ev | of_size, of_None, of_None, ctx); + break; + case 0x05: + ReadCommand(cmImul, of_Ev | of_size, of_None, of_None, ctx); + break; + case 0x06: + ReadCommand(cmDiv, of_Ev | of_size, of_None, of_None, ctx); + break; + case 0x07: + ReadCommand(cmIdiv, of_Ev | of_size, of_None, of_None, ctx); + break; + } + break; + case 0xf8: + type_ = cmClc; + break; + case 0xf9: + type_ = cmStc; + break; + case 0xfa: + type_ = cmCli; + break; + case 0xfb: + type_ = cmSti; + break; + case 0xfc: + type_ = cmCld; + break; + case 0xfd: + type_ = cmStd; + break; + case 0xfe: + code = ReadByte(file); + ctx.use_last_byte = true; + switch ((code >> 3) & 7) { + case 0x00: + ReadCommand(cmInc, of_Eb | of_size, of_None, of_None, ctx); + break; + case 0x01: + ReadCommand(cmDec, of_Eb | of_size, of_None, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + case 0xff: + code = ReadByte(file); + ctx.use_last_byte = true; + switch ((code >> 3) & 7) { + case 0x00: + ReadCommand(cmInc, of_Ev | of_size, of_None, of_None, ctx); + break; + case 0x01: + ReadCommand(cmDec, of_Ev | of_size, of_None, of_None, ctx); + break; + case 0x02: + ReadCommand(cmCall, of_Edef | of_size, of_None, of_None, ctx); + break; + case 0x03: + include_option(roFar); + ReadCommand(cmCall, of_Mp | of_size, of_None, of_None, ctx); + break; + case 0x04: + ReadCommand(cmJmp, of_Edef | of_size, of_None, of_None, ctx); + break; + case 0x05: + include_option(roFar); + ReadCommand(cmJmp, of_Mp | of_size, of_None, of_None, ctx); + break; + case 0x06: + ReadCommand(cmPush, of_Edef | of_size, of_None, of_None, ctx); + break; + default: + type_ = cmDB; + break; + } + break; + + default: + type_ = cmDB; + break; + } + } + + if ((options() & roVexPrefix) && vex_operand_index) { + vex_operand_ = (vex_operand_index & 3) | (operand_[0].size == osYMMWord ? 4 : 0) | (ctx.vex_registr << 4); + } + + if (file.seh_handler_list()) + set_seh_handler(file.seh_handler_list()->GetHandlerByAddress(address_)); + + for (i = 0; i < _countof(operand_); i++) { + operand = &operand_[i]; + if (operand->type & otValue) { + if (operand->is_large_value) + operand->value += next_address(); + operand->fixup = file.fixup_list()->GetFixupByAddress(address() + operand->value_pos); + + if (file.relocation_list()) + operand->relocation = file.relocation_list()->GetRelocationByAddress(address() + operand->value_pos); + } + } + + original_dump_size_ = dump_size(); + + return original_dump_size_; +} + +void IntelCommand::ReadArray(IArchitecture &file, size_t len) +{ + type_ = cmDB; + Read(file, len); + original_dump_size_ = dump_size(); +} + +uint8_t IntelCommand::ReadDataByte(EncodedData &data, size_t *pos) +{ + uint8_t res = data.ReadByte(pos); + + Init(cmDB); + set_dump(&res, sizeof(res)); + return res; +} + +uint16_t IntelCommand::ReadDataWord(EncodedData &data, size_t *pos) +{ + uint16_t res = data.ReadWord(pos); + + Init(cmDW, IntelOperand(otValue, osWord, 0, res)); + set_dump(&res, sizeof(res)); + return res; +} + +uint32_t IntelCommand::ReadDataDWord(EncodedData &data, size_t *pos) +{ + uint32_t res = data.ReadDWord(pos); + + Init(cmDD, IntelOperand(otValue, osDWord, 0, res)); + set_dump(&res, sizeof(res)); + return res; +} + +uint64_t IntelCommand::ReadDataQWord(EncodedData &data, size_t *pos) +{ + uint64_t res = data.ReadQWord(pos); + + Init(cmDQ, IntelOperand(otValue, osQWord, 0, res)); + set_dump(&res, sizeof(res)); + return res; +} + +uint64_t IntelCommand::ReadUleb128(EncodedData &data, size_t *pos) +{ + size_t old_pos = *pos; + uint64_t res = data.ReadUleb128(pos); + + Init(cmUleb, IntelOperand(otValue, osQWord, 0, res)); + set_dump(data.data() + old_pos, *pos - old_pos); + + original_dump_size_ = dump_size(); + return res; +} + +int64_t IntelCommand::ReadSleb128(EncodedData &data, size_t *pos) +{ + size_t old_pos = *pos; + int64_t res = data.ReadSleb128(pos); + + Init(cmSleb, IntelOperand(otValue, osQWord, 0, res)); + set_dump(data.data() + old_pos, *pos - old_pos); + return res; +} + +uint64_t IntelCommand::ReadEncoding(EncodedData &data, uint8_t encoding, size_t *pos) +{ + uint64_t base; + switch (encoding & 0x70) { + case DW_EH_PE_pcrel: + base = data.address() + *pos; + break; + case DW_EH_PE_datarel: + base = data.address(); + break; + default: + base = 0; + break; + } + + switch (encoding & 0x0f) { + case DW_EH_PE_absptr: + if (data.pointer_size() == osDWord) + return base + static_cast(ReadDataDWord(data, pos)); + if (data.pointer_size() == osQWord) + return base + static_cast(ReadDataQWord(data, pos)); + break; + case DW_EH_PE_uleb128: + return base + ReadUleb128(data, pos); + case DW_EH_PE_sleb128: + return base + ReadSleb128(data, pos); + case DW_EH_PE_udata2: + return base + ReadDataWord(data, pos); + case DW_EH_PE_sdata2: + return base + static_cast(ReadDataWord(data, pos)); + case DW_EH_PE_udata4: + return base + ReadDataDWord(data, pos); + case DW_EH_PE_sdata4: + return base + static_cast(ReadDataDWord(data, pos)); + case DW_EH_PE_udata8: + return base + ReadDataQWord(data, pos); + case DW_EH_PE_sdata8: + return base + static_cast(ReadDataQWord(data, pos)); + } + throw std::runtime_error("Invalid encoding"); +} + +std::string IntelCommand::ReadString(EncodedData &data, size_t *pos) +{ + std::string res = data.ReadString(pos); + + Init(cmDB); + set_dump(res.c_str(), res.size() + 1); + return res; +} + +void IntelCommand::ReadData(EncodedData &data, size_t size, size_t *pos) +{ + std::vector res; + for (size_t i = 0; i < size; i++) { + res.push_back(data.ReadByte(pos)); + } + + Init(cmDB); + set_dump(res.data(), res.size()); +} + +int32_t IntelCommand::ReadCompressedValue(IArchitecture &file) +{ + uint32_t res; + uint8_t b = ReadByte(file); + if ((b & 1) == 0) + res = b >> 1; + else if ((b & 2) == 0) { + res = b >> 2; + res |= ReadByte(file) << 6; + } + else if ((b & 4) == 0) { + res = b >> 3; + res |= ReadByte(file) << 5; + res |= ReadByte(file) << 13; + } + else if ((b & 8) == 0) { + res = b >> 4; + res |= ReadByte(file) << 4; + res |= ReadByte(file) << 12; + res |= ReadByte(file) << 20; + } + else + res = ReadDWord(file); + + Init(cmDC, IntelOperand(otValue, osDWord, 0, res)); + + return res; +} + +void IntelCommand::set_address(uint64_t address) +{ + address_ = address; + + if (type_ == cmJmp || type_ == cmCall || type_ == cmJmpWithFlag || type_ == cmLoop || type_ == cmLoope || type_ == cmLoopne || type_ == cmJCXZ) { + if (operand_[0].type == otValue) { + CompileToNative(); + return; + } + } + + if (size_ == osQWord) { + for (size_t i = 0; i < _countof(operand_); i++) { + IntelOperand *operand = &operand_[i]; + if (operand->type == otNone) + break; + + if (operand->type == (otMemory | otValue) && operand->is_large_value) + WriteDWord(operand->value_pos, static_cast(operand->value - next_address())); + } + } +} + +void IntelCommand::PushReg(size_t operand_index, uint8_t add_code, AsmContext &ctx) +{ + IntelOperand *operand = &operand_[operand_index]; + uint8_t registr = operand->registr; + + switch (operand->type) { + case otRegistr: + if (registr > 7) { + registr &= 7; + ctx.rex_prefix |= rexB; + } else if (operand->size == osByte && registr > 3) { + ctx.rex_prefix |= 0x40; + } + break; + case otHiPartRegistr: + registr |= 4; + break; + case otControlRegistr: + case otDebugRegistr: + if (registr > 7) { + registr &= 7; + ctx.rex_prefix |= rexB; + } + break; + } + PushByte(add_code | registr); +} + +void IntelCommand::PushRegAndRM(size_t reg_operand_index, size_t rm_operand_index, AsmContext &ctx) +{ + IntelOperand *operand = &operand_[reg_operand_index]; + uint8_t registr = operand->registr; + + switch (operand->type) { + case otRegistr: + if (registr > 7) { + registr &= 7; + ctx.rex_prefix |= rexR; + } else if (operand->size == osByte && registr > 3) { + ctx.rex_prefix |= 0x40; + } + break; + case otHiPartRegistr: + registr |= 4; + break; + case otControlRegistr: + case otDebugRegistr: + case otXMMRegistr: + if (registr > 7) { + registr &= 7; + ctx.rex_prefix |= rexR; + } + break; + case otSegmentRegistr: + case otMMXRegistr: + break; + default: + throw std::runtime_error("Runtime error at PushRegAndRM: " + text()); + } + + PushRM(rm_operand_index, registr << 3, ctx); +} + +void IntelCommand::PushRM(size_t operand_index, uint8_t add_code, AsmContext &ctx) +{ + IntelOperand *operand = &operand_[operand_index]; + uint8_t registr; + + switch (operand->type) { + case otRegistr: + registr = operand->registr; + if (registr > 7) { + registr &= 7; + ctx.rex_prefix |= rexB; + } else if (operand->size == osByte && registr > 3) { + ctx.rex_prefix |= 0x40; + } + PushByte(add_code | 0xc0 | registr); + break; + case otDebugRegistr: + case otControlRegistr: + case otXMMRegistr: + registr = operand->registr; + if (registr > 7) { + registr &= 7; + ctx.rex_prefix |= rexB; + } + PushByte(add_code | 0xc0 | registr); + break; + case otHiPartRegistr: + registr = operand->registr | 4; + PushByte(add_code | 0xc0 | registr); + break; + default: + if (operand->type & otMemory) { + IntelOperand new_operand, *mem_operand = operand; + if (((mem_operand->type & (otBaseRegistr | otRegistr | otValue)) == otRegistr && (mem_operand->registr & 7) == 5) || + ((mem_operand->type & (otBaseRegistr | otRegistr | otValue)) == (otBaseRegistr | otRegistr) && (mem_operand->base_registr & 7) == 5)) { + new_operand = *mem_operand; + mem_operand = &new_operand; + mem_operand->type |= otValue; + mem_operand->value_size = osByte; + mem_operand->value = 0; + } + + if (mem_operand->type & otValue) { + if ((mem_operand->type & (otRegistr | otBaseRegistr)) == 0) { + add_code |= 0x5; + } else { + add_code |= (mem_operand->value_size == osByte) ? 0x40 : 0x80; + } + } + + if (mem_operand->type & otBaseRegistr) { + PushByte(add_code | 0x4); + + if (mem_operand->type & otRegistr) { + registr = mem_operand->registr; + if (registr > 7) { + registr &= 7; + ctx.rex_prefix |= rexX; + } + add_code = (mem_operand->scale_registr << 6) | (registr << 3); + } else { + add_code = 0x20; + } + + registr = mem_operand->base_registr; + if (registr > 7) { + registr &= 7; + ctx.rex_prefix |= rexB; + } + + PushByte(add_code | registr); + } else if (mem_operand->type & otRegistr) { + registr = mem_operand->registr; + if (mem_operand->scale_registr) { + if (registr > 7) { + registr &= 7; + ctx.rex_prefix |= rexX; + } + PushByte((add_code & ~0xc0) | 0x4); + PushByte((mem_operand->scale_registr << 6) | (registr << 3) | 0x5); + } else { + if (registr > 7) { + registr &= 7; + ctx.rex_prefix |= rexB; + } + PushByte(add_code | registr); + if (registr == 4) + PushByte((registr << 3) | 0x4); + } + } else { + PushByte(add_code); + } + + if (mem_operand->type & otValue) { + mem_operand->value_pos = static_cast(dump_size()); + if (mem_operand->value_size == osByte && !mem_operand->is_large_value) { + PushByte(static_cast(mem_operand->value)); + } else { + PushDWord(static_cast(mem_operand->value)); + } + } + } else { + throw std::runtime_error("Runtime error at PushRM: " + text()); + } + } +} + +void IntelCommand::PushBytePrefix(uint8_t prefix) +{ + PushByte(prefix); + command_pos_ = dump_size(); +} + +void IntelCommand::PushWordPrefix() +{ + PushBytePrefix(0x66); +} + +void IntelCommand::PushPrefix(AsmContext &ctx) +{ + switch (operand_[0].size) { + case osWord: + PushWordPrefix(); + break; + case osQWord: + ctx.rex_prefix = rexW; + break; + } +} + +void IntelCommand::PushFlags(uint8_t add_code) +{ + uint8_t b; + + switch (flags_) { + case fl_O: + b = 0; + break; + case fl_C: + b = 2; + break; + case fl_Z: + b = 4; + break; + case fl_C | fl_Z: + b = 6; + break; + case fl_S: + b = 8; + break; + case fl_P: + b = 0xa; + break; + case fl_S | fl_O: + b = 0xc; + break; + case fl_Z | fl_S | fl_O: + b = 0xe; + break; + default: + b = 0; + } + + if ((options() & roInverseFlag) != 0) + b |= 1; + + PushByte(add_code | b); +} + +void IntelCommand::CompileToNative() +{ + if (type() == cmDB) + return; + + BaseCommand::clear(); + + IntelOperand *operand, *operand1, *mem_operand; + AsmContext ctx; + uint8_t i; + uint8_t b; + IntelSegment segment; + + if (options() & roLockPrefix) + PushByte(0xf0); + + switch (preffix_command_) { + case cmRepne: + PushByte(0xf2); + break; + case cmRep: + case cmRepe: + PushByte(0xf3); + break; + } + + if (base_segment_ != segDefault) { + for (i = 0; i < _countof(operand_); i++) { + operand = &operand_[i]; + if (operand->type & otMemory) { + if (operand->type & otBaseRegistr) { + b = operand->base_registr; + } else if (operand->type & otRegistr) { + b = operand->registr; + } else { + b = regEAX; + } + segment = (b == regEBP || b == regESP) ? segSS : segDS; + if (segment != base_segment_) { + switch (base_segment_) { //-V719 + case segES: + PushByte(0x26); + break; + case segSS: + PushByte(0x36); + break; + case segCS: + PushByte(0x2e); + break; + case segDS: + PushByte(0x3e); + break; + case segFS: + PushByte(0x64); + break; + case segGS: + PushByte(0x65); + break; + } + } + } + } + } + + command_pos_ = dump_size(); + ctx.rex_prefix = 0; + switch (type()) { + case cmDW: + operand = &operand_[0]; + operand->value_pos = static_cast(dump_size()); + PushWord(static_cast(operand->value)); + break; + + case cmDD: + operand = &operand_[0]; + operand->value_pos = static_cast(dump_size()); + PushDWord(static_cast(operand->value)); + break; + + case cmDQ: + operand = &operand_[0]; + operand->value_pos = static_cast(dump_size()); + PushQWord(operand->value); + break; + + case cmUleb: + operand = &operand_[0]; + operand->value_pos = static_cast(dump_size()); + { + EncodedData data; + data.WriteUleb128(operand->value); + if (options() & roFillNop) { + for (size_t j = data.size(); j < original_dump_size_ + 1; j++) { + data[j - 1] = data[j - 1] | 0x80; + data.push_back(0); + } + } + for (i = 0; i < data.size(); i++) { + PushByte(data[i]); + } + } + break; + + case cmSleb: + operand = &operand_[0]; + operand->value_pos = static_cast(dump_size()); + { + EncodedData data; + data.WriteSleb128(operand->value); + for (i = 0; i < data.size(); i++) { + PushByte(data[i]); + } + } + break; + + case cmDC: + operand = &operand_[0]; + operand->value_pos = static_cast(dump_size()); + if (options() & roFillNop) { + PushByte(0x0f); + PushDWord(static_cast(operand->value)); + } + else { + uint32_t value = static_cast(operand->value); + if (value < 0x80) { + PushByte(static_cast((value << 1) + 0)); + } + else if (value < 0x80 * 0x80) { + PushByte(static_cast((value << 2) + 1)); + PushByte(static_cast(value >> 6)); + } + else if (value < 0x80 * 0x80 * 0x80) { + PushByte(static_cast((value << 3) + 3)); + PushByte(static_cast(value >> 5)); + PushByte(static_cast(value >> 13)); + } + else if (value < 0x80 * 0x80 * 0x80 * 0x80) { + PushByte(static_cast((value << 4) + 7)); + PushByte(static_cast(value >> 4)); + PushByte(static_cast(value >> 12)); + PushByte(static_cast(value >> 20)); + } + else { + PushByte(0x0f); + PushDWord(value); + } + } + break; + + case cmPush: + operand = &operand_[0]; + if (operand->size == osWord) + PushWordPrefix(); + + switch (operand->type) { + case otRegistr: + PushReg(0, 0x50, ctx); + break; + case otValue: + if (operand->value_size == osByte) { + PushByte(0x6a); + } else { + PushByte(0x68); + } + operand->value_pos = static_cast(dump_size()); + switch (operand->value_size) { + case osByte: + PushByte(static_cast(operand->value)); + break; + case osWord: + PushWord(static_cast(operand->value)); + break; + default: + PushDWord(static_cast(operand->value)); + break; + } + break; + case otSegmentRegistr: + switch (operand->registr) { + case segES: + if (size_ == osDWord) + PushByte(0x06); + break; + case segCS: + if (size_ == osDWord) + PushByte(0x0e); + break; + case segSS: + if (size_ == osDWord) + PushByte(0x16); + break; + case segDS: + if (size_ == osDWord) + PushByte(0x1e); + break; + case segFS: + PushByte(0x0f); + PushByte(0xa0); + break; + case segGS: + PushByte(0x0f); + PushByte(0xa8); + break; + } + break; + default: + if (operand->type & otMemory) { + PushByte(0xff); + PushRM(0, 0x30, ctx); + } + } + break; + + case cmPop: + operand = &operand_[0]; + if (operand->size == osWord) + PushWordPrefix(); + + switch (operand->type) { + case otRegistr: + PushReg(0, 0x58, ctx); + break; + case otSegmentRegistr: + switch (operand->registr) { + case segES: + if (size_ == osDWord) + PushByte(0x07); + break; + case segCS: + if (size_ == osDWord) + PushByte(0x0f); + break; + case segSS: + if (size_ == osDWord) + PushByte(0x17); + break; + case segDS: + if (size_ == osDWord) + PushByte(0x1f); + break; + case segFS: + PushByte(0x0f); + PushByte(0xa1); + break; + case segGS: + PushByte(0x0f); + PushByte(0xa9); + break; + } + break; + default: + if (operand->type & otMemory) { + PushByte(0x8f); + PushRM(0, 0x00, ctx); + } + } + break; + + case cmPusha: + if (size_ == osDWord) { + if (operand_[0].size == osWord) + PushWordPrefix(); + PushByte(0x60); + } + break; + + case cmPopa: + if (size_ == osDWord) { + if (operand_[0].size == osWord) + PushWordPrefix(); + PushByte(0x61); + } + break; + + case cmPushf: + if (operand_[0].size == osWord) + PushWordPrefix(); + PushByte(0x9c); + break; + + case cmPopf: + if (operand_[0].size == osWord) + PushWordPrefix(); + PushByte(0x9d); + break; + + case cmNop: + PushByte(0x90); + break; + + case cmPause: + PushByte(0xf3); + PushByte(0x90); + break; + + case cmRdtsc: + PushByte(0x0f); + PushByte(0x31); + break; + + case cmCpuid: + PushByte(0x0f); + PushByte(0xa2); + break; + + case cmCmc: + PushByte(0xf5); + break; + + case cmClc: + PushByte(0xf8); + break; + + case cmStc: + PushByte(0xf9); + break; + + case cmCld: + PushByte(0xfc); + break; + + case cmStd: + PushByte(0xfd); + break; + + case cmSahf: + PushByte(0x9e); + break; + + case cmLahf: + PushByte(0x9f); + break; + + case cmCbw: + PushByte(0x66); + PushByte(0x98); + break; + + case cmCwde: + PushByte(0x98); + break; + + case cmCdqe: + if (size_ == osQWord) { + PushByte(0x48); + PushByte(0x98); + } + break; + + case cmCwd: + PushByte(0x66); + PushByte(0x99); + break; + + case cmCdq: + PushByte(0x99); + break; + + case cmCqo: + if (size_ == osQWord) { + PushByte(0x48); + PushByte(0x99); + } + break; + + case cmRet: + operand = &operand_[0]; + b = (options() & roFar) ? 8 : 0; + switch (operand->type) { + case otNone: + PushByte(0xc3 | b); + break; + case otValue: + PushByte(0xc2 | b); + PushWord(static_cast(operand->value)); + break; + } + break; + + case cmIret: + if (operand_[0].size == osWord) + PushWordPrefix(); + PushByte(0xcf); + break; + + case cmJmp: + operand = &operand_[0]; + operand1 = &operand_[1]; + if (operand1->type == otValue) { + PushByte(0xea); + operand->value_pos = static_cast(dump_size()); + PushDWord(static_cast(operand->value)); + operand1->value_pos = static_cast(dump_size()); + PushWord(static_cast(operand1->value)); + } else if (options() & roFar) { + PushByte(0xff); + PushRM(0, 0x28, ctx); + } else if (operand->type == otValue) { + PushByte(0xe9); + operand->value_pos = static_cast(dump_size()); + PushDWord(static_cast(operand->value - next_address() - 4)); + } else { + PushByte(0xff); + PushRM(0, 0x20, ctx); + } + break; + + case cmCall: + operand = &operand_[0]; + operand1 = &operand_[1]; + if (operand1->type == otValue) { + PushByte(0x9a); + operand->value_pos = static_cast(dump_size()); + PushDWord(static_cast(operand->value)); + operand1->value_pos = static_cast(dump_size()); + PushWord(static_cast(operand1->value)); + } else if (options() & roFar) { + PushByte(0xff); + PushRM(0, 0x18, ctx); + } else if (operand->type == otValue) { + PushByte(0xe8); + operand->value_pos = static_cast(dump_size()); + PushDWord(static_cast(operand->value - next_address() - 4)); + } else { + PushByte(0xff); + PushRM(0, 0x10, ctx); + } + break; + + case cmSyscall: + PushByte(0x0f); + PushByte(0x05); + break; + + case cmSysenter: + if (size_ == osDWord) { + PushByte(0x0f); + PushByte(0x34); + } + break; + + case cmSetXX: + PushByte(0x0f); + PushFlags(0x90); + PushRM(0, 0, ctx); + break; + + case cmJmpWithFlag: + operand = &operand_[0]; + PushByte(0x0f); + PushFlags(0x80); + operand->value_pos = static_cast(dump_size()); + PushDWord(static_cast(operand->value - next_address() - 4)); + break; + + case cmLoopne: + operand = &operand_[0]; + PushByte(0xe0); + operand->value_pos = static_cast(dump_size()); + PushByte(static_cast(operand->value - next_address() - 1)); + break; + + case cmLoope: + operand = &operand_[0]; + PushByte(0xe1); + operand->value_pos = static_cast(dump_size()); + PushByte(static_cast(operand->value - next_address() - 1)); + break; + + case cmLoop: + operand = &operand_[0]; + PushByte(0xe2); + operand->value_pos = static_cast(dump_size()); + PushByte(static_cast(operand->value - next_address() - 1)); + break; + + case cmJCXZ: + if (operand_[1].size == osWord) + PushBytePrefix(0x67); + operand = &operand_[0]; + PushByte(0xe3); + operand->value_pos = static_cast(dump_size()); + PushByte(static_cast(operand->value - next_address() - 1)); + break; + + case cmMovs: + operand = &operand_[0]; + PushPrefix(ctx); + PushByte((operand->size == osByte) ? 0xa4 : 0xa5); + break; + + case cmCmps: + operand = &operand_[0]; + PushPrefix(ctx); + PushByte((operand->size == osByte) ? 0xa6 : 0xa7); + break; + + case cmStos: + operand = &operand_[0]; + PushPrefix(ctx); + PushByte((operand->size == osByte) ? 0xaa : 0xab); + break; + + case cmLods: + operand = &operand_[0]; + PushPrefix(ctx); + PushByte((operand->size == osByte) ? 0xac : 0xad); + break; + + case cmScas: + operand = &operand_[0]; + PushPrefix(ctx); + PushByte((operand->size == osByte) ? 0xae : 0xaf); + break; + + case cmCmov: + PushPrefix(ctx); + PushByte(0x0f); + PushFlags(0x40); + PushRegAndRM(0, 1, ctx); + break; + + case cmIn: + operand = &operand_[0]; + PushByte(0xec | ((operand->size == osByte) ? 0 : 1)); + break; + + case cmInt: + operand = &operand_[0]; + switch (operand->value) { + case 0: + PushByte(0xce); + break; + case 3: + PushByte(0xcc); + break; + default: + PushByte(0xcd); + PushByte(static_cast(operand->value)); + break; + } + break; + + case cmAdd: case cmOr: case cmAdc: case cmSbb: case cmAnd: case cmSub: case cmXor: case cmCmp: + operand = &operand_[0]; + operand1 = &operand_[1]; + switch (type_) { + case cmAdd: b = 0 << 3; break; + case cmOr: b = 1 << 3; break; + case cmAdc: b = 2 << 3; break; + case cmSbb: b = 3 << 3; break; + case cmAnd: b = 4 << 3; break; + case cmSub: b = 5 << 3; break; + case cmXor: b = 6 << 3; break; + case cmCmp: b = 7 << 3; break; + } + PushPrefix(ctx); + if (operand1->type == otValue) { + i = (operand->size == osByte) ? 0 : 1; + if (operand->type == otRegistr && operand->registr == regEAX && operand->size == operand1->value_size) { + PushByte(b | 0x4 | i); + } else { + if (operand->size != osByte && operand1->value_size == osByte) + i |= 2; + PushByte(0x80 | i); + PushRM(0, b, ctx); + } + + operand1->value_pos = static_cast(dump_size()); + switch (operand1->value_size) { + case osByte: + PushByte(static_cast(operand1->value)); + break; + case osWord: + PushWord(static_cast(operand1->value)); + break; + default: + PushDWord(static_cast(operand1->value)); + break; + } + } else { + i = (operand->type & otMemory) ? 0 : 1; + PushByte(b | (i << 1) | ((operand->size == osByte) ? 0 : 1)); + PushRegAndRM(1 - i, i, ctx); + } + break; + + case cmTest: + operand = &operand_[0]; + operand1 = &operand_[1]; + i = (operand->size == osByte) ? 0 : 1; + PushPrefix(ctx); + if (operand1->type == otValue) { + if (operand->type == otRegistr && operand->registr == regEAX) { + PushByte(0xa8 | i); + } else { + PushByte(0xf6 | i); + PushRM(0, 0, ctx); + } + + operand1->value_pos = static_cast(dump_size()); + switch (operand1->value_size) { + case osByte: + PushByte(static_cast(operand1->value)); + break; + case osWord: + PushWord(static_cast(operand1->value)); + break; + default: + PushDWord(static_cast(operand1->value)); + break; + } + } else { + PushByte(0x84 | i); + i = (operand->type & otMemory) ? 0 : 1; + PushRegAndRM(1 - i, i, ctx); + } + break; + + case cmXchg: + operand = &operand_[0]; + operand1 = &operand_[1]; + PushPrefix(ctx); + if (operand->size != osByte && operand->type == otRegistr && operand1->type == otRegistr && + (operand->registr == regEAX || operand1->registr == regEAX)) { + i = (operand1->registr == regEAX) ? 0 : 1; + PushReg(i, 0x90, ctx); + } else { + i = (operand->type & otMemory) ? 0 : 1; + PushByte(0x86 | ((operand->size == osByte) ? 0 : 1)); + PushRegAndRM(1 - i, i, ctx); + } + break; + + case cmXadd: + operand = &operand_[0]; + PushPrefix(ctx); + PushByte(0x0f); + PushByte(0xc0 | ((operand->size == osByte) ? 0 : 1)); + PushRegAndRM(1, 0, ctx); + break; + + case cmLea: + PushPrefix(ctx); + PushByte(0x8d); + PushRegAndRM(0, 1, ctx); + break; + + case cmNot: case cmNeg: case cmMul: case cmDiv: case cmIdiv: + operand = &operand_[0]; + switch (type_) { + case cmNot: b = 2 << 3; break; + case cmNeg: b = 3 << 3; break; + case cmMul: b = 4 << 3; break; + //unreachable case cmImul: b = 5 << 3; break; + case cmDiv: b = 6 << 3; break; + case cmIdiv: b = 7 << 3; break; + } + i = (operand->size == osByte) ? 0 : 1; + PushPrefix(ctx); + PushByte(0xf6 | i); + PushRM(0, b, ctx); + break; + + case cmImul: + PushPrefix(ctx); + if (operand_[2].type != otNone) { + operand = &operand_[2]; + i = (operand->value_size == osByte) ? 1 : 0; + PushByte(0x69 | (i << 1)); + PushRegAndRM(0, 1, ctx); + switch (operand->value_size) { + case osByte: + PushByte(static_cast(operand->value)); + break; + case osWord: + PushWord(static_cast(operand->value)); + break; + default: + PushDWord(static_cast(operand->value)); + break; + } + } else if (operand_[1].type != otNone) { + PushByte(0x0f); + PushByte(0xaf); + PushRegAndRM(0, 1, ctx); + } else { + operand = &operand_[0]; + i = (operand->size == osByte) ? 0 : 1; + PushByte(0xf6 | i); + PushRM(0, 0x28, ctx); + } + break; + + case cmInc: case cmDec: + operand = &operand_[0]; + b = (type_ == cmInc) ? 0 : 8; + PushPrefix(ctx); + if (operand->type == otRegistr && size_ != osQWord && size_ == operand->size) { + PushReg(0, 0x40 | b, ctx); + } else { + i = (operand->size == osByte) ? 0 : 1; + PushByte(0xfe | i); + PushRM(0, b, ctx); + } + break; + + case cmShl: case cmShr: case cmRol: case cmRor: case cmRcl: case cmRcr: case cmSal: case cmSar: + operand = &operand_[0]; + operand1 = &operand_[1]; + i = (operand->size == osByte) ? 0 : 1; + switch (type_) { + case cmRol: b = 0 << 3; break; + case cmRor: b = 1 << 3; break; + case cmRcl: b = 2 << 3; break; + case cmRcr: b = 3 << 3; break; + case cmShl: b = 4 << 3; break; + case cmShr: b = 5 << 3; break; + case cmSal: b = 6 << 3; break; + case cmSar: b = 7 << 3; break; + } + PushPrefix(ctx); + if (operand1->type == otRegistr && operand1->registr == regECX && operand1->size == osByte) { + PushByte(0xd2 | i); + PushRM(0, b, ctx); + } else if (operand1->type == otValue) { + if (operand1->value == 1) { + PushByte(0xd0 | i); + PushRM(0, b, ctx); + } else { + PushByte(0xc0 | i); + PushRM(0, b, ctx); + PushByte(static_cast(operand1->value)); + } + } + break; + + case cmShld: case cmShrd: + operand = &operand_[2]; + PushPrefix(ctx); + PushByte(0x0f); + PushByte((type_ == cmShld ? 0xa4 : 0xac) | ((operand->type == otValue) ? 0 : 1)); + PushRegAndRM(1, 0, ctx); + if (operand->type == otValue) + PushByte(static_cast(operand->value)); + break; + + case cmBsr: + PushPrefix(ctx); + PushByte(0x0f); + PushByte(0xbd); + PushRegAndRM(0, 1, ctx); + break; + + case cmBsf: + PushPrefix(ctx); + PushByte(0x0f); + PushByte(0xbc); + PushRegAndRM(0, 1, ctx); + break; + + case cmBt: case cmBts: case cmBtr: case cmBtc: + //operand = &operand_[0]; + operand1 = &operand_[1]; + PushPrefix(ctx); + PushByte(0x0f); + if (operand1->type == otValue) { + PushByte(0xba); + switch (type_) { + case cmBt: b = 4 << 3; break; + case cmBts: b = 5 << 3; break; + case cmBtr: b = 6 << 3; break; + case cmBtc: b = 7 << 3; break; + } + PushRM(0, b, ctx); + PushByte(static_cast(operand1->value)); + } else { + switch (type_) { + case cmBt: b = 0 << 3; break; + case cmBts: b = 1 << 3; break; + case cmBtr: b = 2 << 3; break; + case cmBtc: b = 3 << 3; break; + } + PushByte(0xa3 | b); + PushRegAndRM(1, 0, ctx); + } + break; + + case cmMovups: case cmMovupd: case cmMovsd: case cmMovss: + operand = &operand_[0]; + i = (operand->type & otMemory) ? 0 : 1; + switch (type_) { + case cmMovupd: PushBytePrefix(0x66); break; + case cmMovsd: PushBytePrefix(0xf2); break; + case cmMovss: PushBytePrefix(0xf3); break; + } + PushByte(0x0f); + PushByte(0x10 | (1 - i)); + PushRegAndRM(1 - i, i, ctx); + break; + + case cmMovaps: case cmMovapd: + operand = &operand_[0]; + i = (operand->type & otMemory) ? 0 : 1; + switch (type_) { + case cmMovapd: PushBytePrefix(0x66); break; + } + PushByte(0x0f); + PushByte(0x28 | (1 - i)); + PushRegAndRM(1 - i, i, ctx); + break; + + case cmMovsx: + operand1 = &operand_[1]; + if (operand1->size < osDWord) { + PushPrefix(ctx); + PushByte(0x0f); + PushByte(0xbe | ((operand1->size == osWord) ? 1 : 0)); + PushRegAndRM(0, 1, ctx); + } + break; + + case cmMovsxd: + if (size_ == osQWord) { + PushPrefix(ctx); + PushByte(0x63); + PushRegAndRM(0, 1, ctx); + } + break; + + case cmMovzx: + operand1 = &operand_[1]; + if (operand1->size < osDWord) { + PushPrefix(ctx); + PushByte(0x0f); + PushByte(0xb6 | ((operand1->size == osWord) ? 1 : 0)); + PushRegAndRM(0, 1, ctx); + } + break; + + case cmMov: + operand = &operand_[0]; + operand1 = &operand_[1]; + if (operand1->type == otValue) { + PushPrefix(ctx); + i = (operand->size == osByte) ? 0 : 1; + if (operand->type == otRegistr && operand1->value_size == operand->size) { + PushReg(0, static_cast(0xb0 | (i << 3)), ctx); + } else { + PushByte(0xc6 | i); + PushRM(0, 0, ctx); + } + operand1->value_pos = static_cast(dump_size()); + switch (operand1->value_size) { + case osByte: + PushByte(static_cast(operand1->value)); + break; + case osWord: + PushWord(static_cast(operand1->value)); + break; + case osDWord: + PushDWord(static_cast(operand1->value)); + break; + case osQWord: + PushQWord(operand1->value); + break; + } + } else if ((operand->type | operand1->type) & otControlRegistr) { + i = (operand->type == otControlRegistr) ? 1 : 0; + PushByte(0x0f); + PushByte(0x20 | (i << 1)); + PushRegAndRM(1 - i, i, ctx); + } else if ((operand->type | operand1->type) & otDebugRegistr) { + i = (operand->type == otDebugRegistr) ? 1 : 0; + PushByte(0x0f); + PushByte(0x21 | (i << 1)); + PushRegAndRM(1 - i, i, ctx); + } else if ((operand->type | operand1->type) & otSegmentRegistr) { + i = (operand->type == otSegmentRegistr) ? 1 : 0; + if (operand->size == osWord) + PushWordPrefix(); + PushByte(0x8c | (i << 1)); + PushRegAndRM(1 - i, i, ctx); + } else { + i = (operand->type & otMemory) ? 0 : 1; + PushPrefix(ctx); + operand = &operand_[1 - i]; + mem_operand = &operand_[i]; + if (operand->type == otRegistr && operand->registr == regEAX && mem_operand->type == (otValue | otMemory) && !mem_operand->is_large_value) { + PushByte(0xa1 | ((1 - i) << 1)); + mem_operand->value_pos = static_cast(dump_size()); + if (size_ == osDWord) { + PushDWord(static_cast(mem_operand->value)); + } else { + PushQWord(mem_operand->value); + } + } else { + PushByte(0x88 | (i << 1) | ((operand->size == osByte) ? 0 : 1)); + PushRegAndRM(1 - i, i, ctx); + } + } + break; + + case cmMovd: + operand = &operand_[0]; + operand1 = &operand_[1]; + if ((operand->type | operand1->type) & otXMMRegistr) { + i = (operand->type == otXMMRegistr) ? 1 : 0; + PushBytePrefix(0x66); + PushByte(0x0f); + PushByte(i ? 0x6e : 0x7e); + PushRegAndRM(1 - i, i, ctx); + } else if ((operand->type | operand1->type) & otMMXRegistr) { + i = (operand->type == otMMXRegistr) ? 1 : 0; + PushByte(0x0f); + PushByte(i ? 0x6e : 0x7e); + PushRegAndRM(1 - i, i, ctx); + } + break; + + case cmMovdqa: + operand = &operand_[0]; + i = (operand->type == otXMMRegistr) ? 1 : 0; + PushBytePrefix(0x66); + PushByte(0x0f); + PushByte(i ? 0x6f : 0x7f); + PushRegAndRM(1 - i, i, ctx); + break; + + case cmMovq: + operand = &operand_[0]; + operand1 = &operand_[1]; + i = (operand->type & otMemory) ? 0 : 1; + if ((operand->type | operand1->type) & otXMMRegistr) { + PushBytePrefix(i ? 0xf3 : 0x66); + PushByte(0x0f); + PushByte(i ? 0x7e : 0xd6); + PushRegAndRM(1 - i, i, ctx); + } else if ((operand->type | operand1->type) & otMMXRegistr) { + PushByte(0x0f); + PushByte(i ? 0x6f : 0x7f); + PushRegAndRM(1 - i, i, ctx); + } + break; + + case cmMovdqu: + operand = &operand_[0]; + i = (operand->type & otMemory) ? 0 : 1; + PushBytePrefix(0xf3); + PushByte(0x0f); + PushByte(i ? 0x6f : 0x7f); + PushRegAndRM(1 - i, i, ctx); + break; + + case cmPslldq: + PushBytePrefix(0x66); + PushByte(0x0f); + PushByte(0x73); + PushReg(0, 0xc0 | (7 << 3), ctx); + PushByte(static_cast(operand_[1].value)); + break; + + case cmPunpcklqdq: + PushBytePrefix(0x66); + PushByte(0x0f); + PushByte(0x6c); + PushRegAndRM(0, 1, ctx); + break; + + case cmPunpckhqdq: + PushBytePrefix(0x66); + PushByte(0x0f); + PushByte(0x6d); + PushRegAndRM(0, 1, ctx); + break; + + case cmPsrld: + operand = &operand_[0]; + operand1 = &operand_[1]; + if ((operand->type | operand1->type) & otXMMRegistr) + PushBytePrefix(0x66); + if (operand1->type == otValue) { + PushByte(0x0f); + PushByte(0x72); + PushReg(0, 0xc0 | (2 << 3), ctx); + PushByte(static_cast(operand_[1].value)); + } + else { + PushByte(0x0f); + PushByte(0xd2); + PushRegAndRM(0, 1, ctx); + } + break; + + case cmPsrlq: + operand = &operand_[0]; + operand1 = &operand_[1]; + if ((operand->type | operand1->type) & otXMMRegistr) + PushBytePrefix(0x66); + if (operand1->type == otValue) { + PushByte(0x0f); + PushByte(0x73); + PushReg(0, 0xc0 | (2 << 3), ctx); + PushByte(static_cast(operand_[1].value)); + } else { + PushByte(0x0f); + PushByte(0xd3); + PushRegAndRM(0, 1, ctx); + } + break; + + case cmPaddq: + operand = &operand_[0]; + operand1 = &operand_[1]; + if ((operand->type | operand1->type) & otXMMRegistr) + PushBytePrefix(0x66); + PushByte(0x0f); + PushByte(0xd4); + PushRegAndRM(0, 1, ctx); + break; + + case cmPsubq: + operand = &operand_[0]; + operand1 = &operand_[1]; + if ((operand->type | operand1->type) & otXMMRegistr) + PushBytePrefix(0x66); + PushByte(0x0f); + PushByte(0xfb); + PushRegAndRM(0, 1, ctx); + break; + + case cmPand: + operand = &operand_[0]; + operand1 = &operand_[1]; + if ((operand->type | operand1->type) & otXMMRegistr) + PushBytePrefix(0x66); + PushByte(0x0f); + PushByte(0xdb); + PushRegAndRM(0, 1, ctx); + break; + + case cmPinsrw: + operand = &operand_[0]; + operand1 = &operand_[1]; + if ((operand->type | operand1->type) & otXMMRegistr) + PushBytePrefix(0x66); + PushByte(0x0f); + PushByte(0xc4); + PushRegAndRM(0, 1, ctx); + PushByte(static_cast(operand_[2].value)); + break; + + case cmPextrw: + operand = &operand_[0]; + operand1 = &operand_[1]; + if ((operand->type | operand1->type) & otXMMRegistr) + PushBytePrefix(0x66); + PushByte(0x0f); + PushByte(0xc5); + PushRegAndRM(0, 1, ctx); + PushByte(static_cast(operand_[2].value)); + break; + + case cmShufpd: + operand = &operand_[0]; + operand1 = &operand_[1]; + PushBytePrefix(0x66); + PushByte(0x0f); + PushByte(0xc6); + PushRegAndRM(0, 1, ctx); + PushByte(static_cast(operand_[2].value)); + break; + + case cmPshufd: + PushBytePrefix(0x66); + PushByte(0x0f); + PushByte(0x70); + PushRegAndRM(0, 1, ctx); + PushByte(static_cast(operand_[2].value)); + break; + + case cmPshuflw: + PushBytePrefix(0xf2); + PushByte(0x0f); + PushByte(0x70); + PushRegAndRM(0, 1, ctx); + PushByte(static_cast(operand_[2].value)); + break; + + case cmPaddd: + operand = &operand_[0]; + operand1 = &operand_[1]; + if ((operand->type | operand1->type) & otXMMRegistr) + PushBytePrefix(0x66); + PushByte(0x0f); + PushByte(0xfe); + PushRegAndRM(0, 1, ctx); + break; + + case cmPsubd: + operand = &operand_[0]; + operand1 = &operand_[1]; + if ((operand->type | operand1->type) & otXMMRegistr) + PushBytePrefix(0x66); + PushByte(0x0f); + PushByte(0xfa); + PushRegAndRM(0, 1, ctx); + break; + + case cmPunpcklbw: + operand = &operand_[0]; + operand1 = &operand_[1]; + if ((operand->type | operand1->type) & otXMMRegistr) + PushBytePrefix(0x66); + PushByte(0x0f); + PushByte(0x60); + PushRegAndRM(0, 1, ctx); + break; + + case cmPunpcklwd: + operand = &operand_[0]; + operand1 = &operand_[1]; + if ((operand->type | operand1->type) & otXMMRegistr) + PushBytePrefix(0x66); + PushByte(0x0f); + PushByte(0x61); + PushRegAndRM(0, 1, ctx); + break; + + case cmPunpckldq: + operand = &operand_[0]; + operand1 = &operand_[1]; + if ((operand->type | operand1->type) & otXMMRegistr) + PushBytePrefix(0x66); + PushByte(0x0f); + PushByte(0x62); + PushRegAndRM(0, 1, ctx); + break; + + case cmMovlpd: + operand = &operand_[1]; + if (operand->type == otXMMRegistr) { + PushBytePrefix(0x66); + PushByte(0x0f); + PushByte(0x13); + PushRegAndRM(1, 0, ctx); + } + break; + + case cmMovlhps: + PushByte(0x0f); + PushByte(0x16); + PushRegAndRM(0, 1, ctx); + break; + + case cmMovhlps: + PushByte(0x0f); + PushByte(0x12); + PushRegAndRM(0, 1, ctx); + break; + + case cmFld: + operand = &operand_[0]; + if (operand->type == otFPURegistr) { + PushByte(0xd9); + PushReg(0, 0xc0, ctx); + } else { + switch (operand->size) { + case osDWord: + PushByte(0xd9); + PushRM(0, 0, ctx); + break; + case osQWord: + PushByte(0xdd); + PushRM(0, 0, ctx); + break; + case osTByte: + PushByte(0xdb); + PushRM(0, 5 << 3, ctx); + } + } + break; + + case cmFild: + operand = &operand_[0]; + switch (operand->size) { + case osWord: + PushByte(0xdf); + PushRM(0, 0, ctx); + break; + case osDWord: + PushByte(0xdb); + PushRM(0, 0, ctx); + break; + case osQWord: + PushByte(0xdf); + PushRM(0, 5 << 3, ctx); + break; + } + break; + + case cmFadd: + operand = &operand_[0]; + if (operand->type == otFPURegistr) { + if (operand->registr == 0) { + PushByte(0xd8); + PushRM(1, 0xc0, ctx); + } else { + PushByte(0xdc); + PushRM(0, 0xc0, ctx); + } + } else { + switch (operand->size) { + case osDWord: + PushByte(0xd8); + PushRM(0, 0, ctx); + break; + case osQWord: + PushByte(0xdc); + PushRM(0, 0, ctx); + break; + } + } + break; + + case cmFsub: + operand = &operand_[0]; + if (operand->type == otFPURegistr) { + if (operand->registr == 0) { + PushByte(0xd8); + PushRM(1, 0xc0 | (4 << 3), ctx); + } else { + PushByte(0xdc); + PushRM(0, 0xc0 | (5 << 3), ctx); + } + } else { + switch (operand->size) { + case osDWord: + PushByte(0xd8); + PushRM(0, 4 << 3, ctx); + break; + case osQWord: + PushByte(0xdc); + PushRM(0, 4 << 3, ctx); + break; + } + } + break; + + case cmFsubr: + operand = &operand_[0]; + if (operand->type == otFPURegistr) { + if (operand->registr == 0) { + PushByte(0xd8); + PushRM(1, 0xc0 | (5 << 3), ctx); + } else { + PushByte(0xdc); + PushRM(0, 0xc0 | (4 << 3), ctx); + } + } else { + switch (operand->size) { + case osDWord: + PushByte(0xd8); + PushRM(0, 5 << 3, ctx); + break; + case osQWord: + PushByte(0xdc); + PushRM(0, 5 << 3, ctx); + break; + } + } + break; + + case cmFst: + operand = &operand_[0]; + if (operand->type == otFPURegistr) { + PushByte(0xdd); + PushRM(0, 0xc0 | (2 << 3), ctx); + } else { + switch (operand->size) { + case osDWord: + PushByte(0xd9); + PushRM(0, 2 << 3, ctx); + break; + case osQWord: + PushByte(0xdd); + PushRM(0, 2 << 3, ctx); + break; + } + } + break; + + case cmFstp: + operand = &operand_[0]; + if (operand->type == otFPURegistr) { + PushByte(0xdd); + PushRM(0, 0xc0 | (3 << 3), ctx); + } else { + switch (operand->size) { + case osDWord: + PushByte(0xd9); + PushRM(0, 3 << 3, ctx); + break; + case osQWord: + PushByte(0xdd); + PushRM(0, 3 << 3, ctx); + break; + case osTByte: + PushByte(0xdb); + PushRM(0, 7 << 3, ctx); + break; + } + } + break; + + case cmFist: + operand = &operand_[0]; + switch (operand->size) { + case osWord: + PushByte(0xdf); + PushRM(0, 2 << 3, ctx); + break; + case osDWord: + PushByte(0xdb); + PushRM(0, 2 << 3, ctx); + break; + } + break; + + case cmFistp: + operand = &operand_[0]; + switch (operand->size) { + case osWord: + PushByte(0xdf); + PushRM(0, 3 << 3, ctx); + break; + case osDWord: + PushByte(0xdb); + PushRM(0, 3 << 3, ctx); + break; + case osQWord: + PushByte(0xdf); + PushRM(0, 7 << 3, ctx); + break; + } + break; + + case cmFisub: + operand = &operand_[0]; + switch (operand->size) { + case osWord: + PushByte(0xde); + PushRM(0, 4 << 3, ctx); + break; + case osDWord: + PushByte(0xda); + PushRM(0, 4 << 3, ctx); + break; + } + break; + + case cmFdiv: + operand = &operand_[0]; + if (operand->type == otFPURegistr) { + if (operand->registr == 0) { + PushByte(0xd8); + PushRM(1, 0xc0 | (6 << 3), ctx); + } else { + PushByte(0xdc); + PushRM(0, 0xc0 | (7 << 3), ctx); + } + } else { + switch (operand->size) { + case osDWord: + PushByte(0xd8); + PushRM(0, 6 << 3, ctx); + break; + case osQWord: + PushByte(0xdc); + PushRM(0, 6 << 3, ctx); + break; + } + } + break; + + case cmFmul: + operand = &operand_[0]; + if (operand->type == otFPURegistr) { + if (operand->registr == 0) { + PushByte(0xd8); + PushRM(1, 0xc0 | (1 << 3), ctx); + } else { + PushByte(0xdc); + PushRM(0, 0xc0 | (1 << 3), ctx); + } + } else { + switch (operand->size) { + case osDWord: + PushByte(0xd8); + PushRM(0, 1 << 3, ctx); + break; + case osQWord: + PushByte(0xdc); + PushRM(0, 1 << 3, ctx); + break; + } + } + break; + + case cmFcomp: + operand = &operand_[0]; + if (operand->type == otFPURegistr) { + PushByte(0xd8); + PushRM(0, 0xc0 | (3 << 3), ctx); + } else { + switch (operand->size) { + case osDWord: + PushByte(0xd8); + PushRM(0, 3 << 3, ctx); + break; + case osQWord: + PushByte(0xdc); + PushRM(0, 3 << 3, ctx); + break; + } + } + break; + + case cmFnstcw: + PushByte(0xd9); + PushRM(0, 7 << 3, ctx); + break; + + case cmFstcw: + PushByte(0x9b); + PushByte(0xd9); + PushRM(0, 7 << 3, ctx); + break; + + case cmFnstsw: + PushByte(0xdd); + PushRM(0, 7 << 3, ctx); + break; + + case cmFstsw: + PushByte(0x9b); + PushByte(0xdd); + PushRM(0, 7 << 3, ctx); + break; + + case cmFldcw: + PushByte(0xd9); + PushRM(0, 5 << 3, ctx); + break; + + case cmWait: + PushByte(0x9b); + break; + + case cmFchs: + PushByte(0xd9); + PushByte(0xe0); + break; + + case cmFsqrt: + PushByte(0xd9); + PushByte(0xfa); + break; + + case cmF2xm1: + PushByte(0xd9); + PushByte(0xf0); + break; + + case cmFabs: + PushByte(0xd9); + PushByte(0xe1); + break; + + case cmFclex: + PushByte(0x9b); + PushByte(0xdb); + PushByte(0xe2); + break; + + case cmFcos: + PushByte(0xd9); + PushByte(0xff); + break; + + case cmFdecstp: + PushByte(0xd9); + PushByte(0xf6); + break; + + case cmFincstp: + PushByte(0xd9); + PushByte(0xf7); + break; + + case cmFinit: + PushByte(0x9b); + PushByte(0xdb); + PushByte(0xe3); + break; + + case cmFldln2: + PushByte(0xd9); + PushByte(0xed); + break; + + case cmFldz: + PushByte(0xd9); + PushByte(0xee); + break; + + case cmFld1: + PushByte(0xd9); + PushByte(0xe8); + break; + + case cmFldpi: + PushByte(0xd9); + PushByte(0xeb); + break; + + case cmFpatan: + PushByte(0xd9); + PushByte(0xf3); + break; + + case cmFprem: + PushByte(0xd9); + PushByte(0xf8); + break; + + case cmFprem1: + PushByte(0xd9); + PushByte(0xf5); + break; + + case cmFptan: + PushByte(0xd9); + PushByte(0xf2); + break; + + case cmFrndint: + PushByte(0xd9); + PushByte(0xfc); + break; + + case cmFsin: + PushByte(0xd9); + PushByte(0xfe); + break; + + case cmFtst: + PushByte(0xd9); + PushByte(0xe4); + break; + + case cmFyl2x: + PushByte(0xd9); + PushByte(0xf1); + break; + + case cmFldlg2: + PushByte(0xd9); + PushByte(0xec); + break; + + case cmBswap: + operand = &operand_[0]; + if (operand->type == otRegistr) { + PushPrefix(ctx); + PushByte(0x0f); + PushReg(0, 0xc8, ctx); + } + break; + + case cmUd2: + PushByte(0x0f); + PushByte(0x0b); + break; + + case cmPxor: + operand = &operand_[0]; + if (operand->type == otMMXRegistr) { + PushByte(0x0f); + PushByte(0xef); + PushRegAndRM(0, 1, ctx); + } else if (operand->type == otXMMRegistr) { + PushByte(0x66); + PushByte(0x0f); + PushByte(0xef); + PushRegAndRM(0, 1, ctx); + } + break; + + case cmXorps: + operand = &operand_[0]; + if (operand->type == otXMMRegistr) { + PushByte(0x0f); + PushByte(0x57); + PushRegAndRM(0, 1, ctx); + } + break; + + case cmCrc: + PushByte(0xcc); + break; + } + + if (ctx.rex_prefix) { + if (size_ == osQWord) { + InsertByte(command_pos_, 0x40 | ctx.rex_prefix); + command_pos_++; + for (i = 0; i < _countof(operand_); i++) { + operand = &operand_[i]; + if (operand->type == otNone) + break; + if (operand->type & otValue) + operand->value_pos++; + } + } else { + // 32-bit commands can not have REX preffix + command_pos_ = dump_size(); + } + } + + if (command_pos_ == dump_size()) + throw std::runtime_error("Runtime error at CompileToNative: " + text()); + + for (i = 0; i < _countof(operand_); i++) { + operand = &operand_[i]; + if (operand->is_large_value) + WriteDWord(operand->value_pos, static_cast(operand->value - next_address())); + } + + if (options() & roFillNop) { + for (size_t j = dump_size(); j < original_dump_size_; j++) { + PushByte(0x90); + } + } +} + +void IntelCommand::set_operand_value(size_t operand_index, uint64_t value) +{ + operand_[operand_index].value = value; +} + +void IntelCommand::set_operand_fixup(size_t operand_index, IFixup *fixup) +{ + operand_[operand_index].fixup = fixup; +} + +void IntelCommand::set_operand_relocation(size_t operand_index, IRelocation *relocation) +{ + operand_[operand_index].relocation = relocation; +} + +void IntelCommand::set_operand_scale(size_t operand_index, uint8_t value) +{ + operand_[operand_index].scale_registr = value; +} + +void IntelCommand::set_link_value(size_t link_index, uint64_t value) +{ + IntelVMCommand *vm_command = vm_links_[link_index]; + vm_command->set_value(value); + vm_command->Compile(); +} + +void IntelCommand::set_jmp_value(size_t link_index, uint64_t value) +{ + IntelVMCommand *vm_command = jmp_links_[link_index]; + vm_command->set_value(value); + vm_command->Compile(); +} + +void IntelCommand::ReadFromBuffer(Buffer &buffer, IArchitecture &file) +{ + uint8_t b; + uint16_t opt; + size_t i, j, r; + uint32_t dw; + uint64_t add_address = file.image_base(); + + r = buffer.ReadByte(); + address_ = buffer.ReadDWord() + add_address; + type_ = static_cast(buffer.ReadWord()); + BaseCommand::ReadFromBuffer(buffer, file); + + if (r & 0x8) + preffix_command_ = static_cast(buffer.ReadWord()); + + original_dump_size_ = (r & 0x10) ? buffer.ReadWord() : buffer.ReadByte(); + + if (r & 0x40) + base_segment_ = static_cast(buffer.ReadByte()); + + if (r & 0x80) + flags_ = buffer.ReadWord(); + + if (type_ == cmDB) { + for (i = 0; i < original_dump_size_; i++) { + PushByte(buffer.ReadByte()); + } + } else { + for (i = 0; i < original_dump_size_; i++) { + PushByte(0); + } + for (j = 0; j < (r & 3); j++) { + IntelOperand *operand = &operand_[j]; + operand->size = static_cast(buffer.ReadByte()); + opt = buffer.ReadWord(); + operand->type = opt & 0xfff; + + if (operand->type & (otRegistr | otSegmentRegistr | otControlRegistr | otDebugRegistr | otFPURegistr | otHiPartRegistr | otMMXRegistr | otXMMRegistr)) + operand->registr = buffer.ReadByte(); + + if (operand->type & otBaseRegistr) + operand->base_registr = buffer.ReadByte(); + + if (operand->type & otValue) { + operand->value_size = static_cast(buffer.ReadByte()); + if (opt & 0x9000) { + dw = buffer.ReadDWord(); + operand->value = dw + add_address; + } else { + switch (operand->value_size) { + case osByte: + operand->value = ByteToInt64(buffer.ReadByte()); + break; + case osWord: + operand->value = WordToInt64(buffer.ReadWord()); + break; + case osDWord: + operand->value = DWordToInt64(buffer.ReadDWord()); + break; + case osQWord: + operand->value = buffer.ReadQWord(); + break; + } + } + + if (opt & 0x8000) { + b = buffer.ReadByte(); + if (b == 1) { + operand->fixup = NEED_FIXUP; + } else if (b == 2) { + operand->is_large_value = true; + } + } + } + + if (operand->type & otMemory) { + if (opt & 0x4000) + operand->scale_registr = buffer.ReadByte(); + operand->address_size = (opt & 0x2000) ? static_cast(buffer.ReadByte()) : size_; + } + } + } +} + +void IntelCommand::WriteToFile(IArchitecture &file) +{ + for (size_t i = 0; i < _countof(operand_); i++) { + IntelOperand *operand = &operand_[i]; + if (operand->type == otNone) + break; + + if (operand->type & otValue) { + if (operand->fixup) { + if (operand->fixup == NEED_FIXUP) { + ISection *segment = file.segment_list()->GetSectionByAddress(address_); + operand->fixup = file.fixup_list()->AddDefault(file.cpu_address_size(), segment && (segment->memory_type() & mtExecutable) != 0); + } + operand->fixup->set_address(address_ + operand->value_pos); + } + if (operand->relocation) + operand->relocation->set_address(address_ + operand->value_pos); + } + } + + if (seh_handler_) { + if (seh_handler_ == NEED_SEH_HANDLER) { + seh_handler_ = file.seh_handler_list()->Add(address()); + } + else { + seh_handler_->set_address(address()); + } + } + + BaseCommand::WriteToFile(file); +} + +void IntelCommand::Rebase(uint64_t delta_base) +{ + if (!address_) + return; + + if ((type_ == cmJmp || type_ == cmCall || type_ == cmJmpWithFlag) && operand_[0].type == otValue) { + operand_[0].value += delta_base; + } else { + for (size_t i = 0; i < _countof(operand_); i++) { + IntelOperand *operand = &operand_[i]; + if (operand->type == otNone) + break; + + if ((operand->type & otValue) && (operand->fixup || operand->is_large_value)) + operand->value += delta_base; + } + } + + address_ += delta_base; + +#ifdef CHECKED + update_hash(); +#endif +} + +IntelVMCommand *IntelCommand::AddVMCommand(const CompileContext &ctx, IntelCommandType command_type, OperandType operand_type, OperandSize operand_size, uint64_t value, uint32_t options, IFixup *fixup) +{ + bool need_popf = false; + if ((command_type == cmAdd || command_type == cmNor || command_type == cmNand || command_type == cmShr || command_type == cmShl) && !value) { + need_popf = true; + value = true; + } + + IntelVMCommand *vm_command = NULL; +#ifdef ULTIMATE + if ((owner()->compilation_options() & coLockToKey) && command_type == cmPush && operand_type == otValue && (options & voLinkCommand)) { + vm_command = new IntelVMCommand(this, command_type, operand_type, osDWord, value, options); + vm_command->set_crypt_command(cmXadd, operand_size, ctx.options.licensing_manager->product_code()); + } +#endif + if (!vm_command) + vm_command = new IntelVMCommand(this, command_type, operand_type, operand_size, value, options); + + AddObject(vm_command); + if (options & voLinkCommand) + vm_links_.push_back(vm_command); + if (command_type == cmJmp) + jmp_links_.push_back(vm_command); + + uint32_t new_options = options & (voSectionCommand | voNoCRC); + if (need_popf) + AddVMCommand(ctx, cmPop, otRegistr, size_, regEmpty, new_options); + + if ((ctx.options.flags & cpMemoryProtection) && (new_options & voNoCRC) == 0 && vm_command->command_type() == cmPush && vm_command->operand_type() == otValue && vm_command->size() > osByte) { + new_options |= voNoCRC; + IntelVMCommand *address_command = AddVMCommand(ctx, cmPush, otValue, size_, 0, new_options | voFixup); + AddVMCommand(ctx, cmPush, otMemory, vm_command->size(), segDS, new_options); + AddVMCommand(ctx, cmAdd, otNone, vm_command->size(), false, new_options); + + internal_links_.Add(vlCRCValue, address_command, vm_command); + } + + if (vm_command->crypt_command() == cmXadd) { + size_t i; + IntelVMCommand *cur_command = vm_command; + // read session key + uint64_t address = ctx.runtime->export_list()->GetAddressByType(atLoaderData); + IntelVMCommand *from_command = AddVMCommand(ctx, cmPush, otValue, size_, address, new_options | voFixup); + ICommand *to_command = ctx.file->function_list()->GetCommandByAddress(address, true); + if (to_command) + internal_links_.Add(vlNone, from_command, to_command); + AddVMCommand(ctx, cmPush, otMemory, size_, segDS, new_options); + AddVMCommand(ctx, cmPush, otValue, size_, ctx.runtime_var_index[VAR_SESSION_KEY] * OperandSizeToValue(size_), new_options); + AddVMCommand(ctx, cmAdd, otNone, size_, false); + AddVMCommand(ctx, cmPush, otMemory, size_, segDS, new_options); + AddVMCommand(ctx, cmPop, otRegistr, size_, regETX, new_options); + // add session key + AddVMCommand(ctx, cmPush, otRegistr, osDWord, regETX, new_options); + AddVMCommand(ctx, cmAdd, otNone, osDWord, false, new_options); + for (i = 1; i < 4; i++) { + cur_command->set_link_command(AddVMCommand(ctx, cmPush, otValue, osDWord, 0, new_options)); + // add session key + AddVMCommand(ctx, cmPush, otRegistr, osDWord, regETX, new_options); + AddVMCommand(ctx, cmAdd, otNone, osDWord, false, new_options); + cur_command = cur_command->link_command(); + } + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP, new_options); + + address = ctx.runtime->export_list()->GetAddressByType(atDecryptBuffer); + from_command = AddVMCommand(ctx, cmPush, otValue, size_, address, new_options | voFixup); + to_command = ctx.file->function_list()->GetCommandByAddress(address, true); + if (to_command) + internal_links_.Add(vlNone, from_command, to_command); + AddVMCommand(ctx, cmCall, otNone, size_, 1, new_options); + AddVMCommand(ctx, cmPop, otRegistr, size_, regEmpty, new_options); + + // correct stack + if (ctx.file->calling_convention() == ccCdecl) + AddVMCommand(ctx, cmPop, otRegistr, size_, regEmpty, new_options); + if (size_ == osQWord) { + AddVMCommand(ctx, cmPop, otRegistr, osQWord, regEmpty, new_options); + } else { + AddVMCommand(ctx, cmPop, otRegistr, osDWord, regEmpty, new_options); + AddVMCommand(ctx, cmPop, otRegistr, osDWord, regEmpty, new_options); + AddVMCommand(ctx, cmPop, otRegistr, osDWord, regEmpty, new_options); + } + + // add session key + if (size_ == osQWord) { + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP, new_options); + AddVMCommand(ctx, cmPush, otValue, size_, OperandSizeToStack(osDWord), new_options); + AddVMCommand(ctx, cmAdd, otNone, size_, false, new_options); + AddVMCommand(ctx, cmPush, otMemory, osDWord, segSS, new_options); + + AddVMCommand(ctx, cmPush, otRegistr, osDWord, regETX, new_options); + AddVMCommand(ctx, cmAdd, otNone, osDWord, false); + + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP, new_options); + AddVMCommand(ctx, cmPush, otValue, size_, 2 * OperandSizeToStack(osDWord), new_options); + AddVMCommand(ctx, cmAdd, otNone, size_, false, new_options); + AddVMCommand(ctx, cmPop, otMemory, osDWord, segSS, new_options); + } + AddVMCommand(ctx, cmPush, otRegistr, osDWord, regETX, new_options); + AddVMCommand(ctx, cmAdd, otNone, osDWord, false, new_options); + } + + if ((options & voFixup) && (ctx.options.flags & cpStripFixups) == 0) { + if (vm_command->is_data()) { + vm_command->set_fixup(fixup); + } else { + FixupType fixup_type = (fixup && fixup != NEED_FIXUP) ? fixup->type() : ftHighLow; + switch (fixup_type) { + case ftHigh: + AddVMCommand(ctx, cmPush, otRegistr, operand_size, regERX, new_options); + AddVMCommand(ctx, cmPop, otRegistr, osWord, regEmpty, new_options); + AddVMCommand(ctx, cmPush, otValue, osWord, 0, new_options); + if (options & voInverseValue) { + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP, new_options); + AddVMCommand(ctx, cmPush, otMemory, operand_size, segSS, new_options); + AddVMCommand(ctx, cmNor, otNone, operand_size, false, new_options); + AddVMCommand(ctx, cmPush, otValue, operand_size, 1, new_options); + AddVMCommand(ctx, cmAdd, otNone, operand_size, false, new_options); + } + AddVMCommand(ctx, cmAdd, otNone, operand_size, false, new_options); + break; + + case ftLow: + AddVMCommand(ctx, cmPush, otValue, osWord, 0, options); + AddVMCommand(ctx, cmPush, otRegistr, osWord, regERX, new_options); + if (options & voInverseValue) { + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP, new_options); + AddVMCommand(ctx, cmPush, otMemory, operand_size, segSS, new_options); + AddVMCommand(ctx, cmNor, otNone, operand_size, false, new_options); + AddVMCommand(ctx, cmPush, otValue, operand_size, 1, new_options); + AddVMCommand(ctx, cmAdd, otNone, operand_size, false, new_options); + } + AddVMCommand(ctx, cmAdd, otNone, operand_size, false, new_options); + break; + + case ftHighLow: + AddVMCommand(ctx, cmPush, otRegistr, operand_size, regERX, new_options); + if (options & voInverseValue) { + AddVMCommand(ctx, cmPush, otRegistr, operand_size, regERX, new_options); + AddVMCommand(ctx, cmNor, otNone, operand_size, false, new_options); + AddVMCommand(ctx, cmPush, otValue, operand_size, 1, new_options); + AddVMCommand(ctx, cmAdd, otNone, operand_size, false, new_options); + } + AddVMCommand(ctx, cmAdd, otNone, operand_size, false, new_options); + break; + } + } + } + + if (command_type == cmRet || command_type == cmIret || command_type == cmJmp) + section_options_ |= rtCloseSection; + + return vm_command; +} + +void IntelCommand::AddCorrectOperandSizeSection(const CompileContext &ctx, OperandSize src, OperandSize dst) +{ + int i = (int)(OperandSizeToStack(dst) - OperandSizeToStack(src)); + switch (i) { + case -2: + AddVMCommand(ctx, cmPop, otRegistr, osWord, regEmpty); + break; + case -4: + AddVMCommand(ctx, cmPop, otRegistr, osDWord, regEmpty); + break; + case -6: + AddVMCommand(ctx, cmPop, otRegistr, osWord, regEmpty); + AddVMCommand(ctx, cmPop, otRegistr, osDWord, regEmpty); + break; + case 2: + AddVMCommand(ctx, cmPush, otValue, osWord, 0); + break; + case 4: + AddVMCommand(ctx, cmPush, otValue, osDWord, 0); + break; + case 6: + AddVMCommand(ctx, cmPush, otValue, osWord, 0); + AddVMCommand(ctx, cmPush, otValue, osDWord, 0); + break; + } +} + +void IntelCommand::AddRegistrAndValueSection(const CompileContext &ctx, uint8_t registr, OperandSize registr_size, uint64_t value, bool need_pushf) +{ + if (rand() & 1) { + AddVMCommand(ctx, cmPush, otRegistr, registr_size, registr); + AddVMCommand(ctx, cmPush, otRegistr, registr_size, registr); + + AddVMCommand(ctx, (rand() & 1) ? cmNor : cmNand, otNone, registr_size, false); + AddVMCommand(ctx, cmPush, otValue, registr_size, ~value); + AddVMCommand(ctx, cmNor, otNone, registr_size, need_pushf); + } else { + AddVMCommand(ctx, cmPush, otRegistr, registr_size, registr); + AddVMCommand(ctx, cmPush, otValue, registr_size, value); + AddVMCommand(ctx, cmNand, otNone, registr_size, false); + + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); + AddVMCommand(ctx, cmPush, otMemory, registr_size, segSS); + AddVMCommand(ctx, (rand() & 1) ? cmNor : cmNand, otNone, registr_size, need_pushf); + } +} + +void IntelCommand::AddRegistrOrValueSection(const CompileContext &ctx, uint8_t registr, OperandSize registr_size, uint64_t value, bool need_pushf) +{ + AddVMCommand(ctx, cmPush, otRegistr, registr_size, registr); + AddVMCommand(ctx, cmPush, otValue, registr_size, value); + AddVMCommand(ctx, cmNor, otNone, registr_size, false); + + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); + AddVMCommand(ctx, cmPush, otMemory, registr_size, segSS); + AddVMCommand(ctx, (rand() & 1) ? cmNor : cmNand, otNone, registr_size, need_pushf); +} + +void IntelCommand::AddCombineFlagsSection(const CompileContext &ctx, uint16_t mask) +{ + AddRegistrAndValueSection(ctx, regEFX, size_, mask); + AddRegistrAndValueSection(ctx, regEIX, size_, ~mask); + AddVMCommand(ctx, cmAdd, otNone, size_, false); + AddVMCommand(ctx, cmPop, otRegistr, size_, regEFX); +} + +void IntelCommand::AddCorrectFlagSection(const CompileContext &ctx, uint16_t flags) +{ + AddRegistrAndValueSection(ctx, regEFX, size_, flags); + AddVMCommand(ctx, cmPush, otRegistr, size_, regEFX); + AddVMCommand(ctx, cmPush, otValue, size_, flags); + AddVMCommand(ctx, cmNor, otNone, size_, false); + AddVMCommand(ctx, cmNor, otNone, size_, false); + AddVMCommand(ctx, cmPop, otRegistr, size_, regEFX); +} + +void IntelCommand::AddExtractFlagSection(const CompileContext &ctx, uint16_t flags, bool is_inverse, uint8_t extract_to) +{ + bool one_bit = (flags & (flags - 1)) == 0; + uint16_t check_flag = one_bit ? flags : (uint16_t)fl_Z; + int c = 0; + + if (check_flag > extract_to) { + while (check_flag > extract_to) { + c++; + check_flag >>= 1; + } + } else if (check_flag < extract_to) { + while (check_flag < extract_to) { + c--; + check_flag <<= 1; + } + } + if (c != 0) + AddVMCommand(ctx, cmPush, otValue, osWord, abs(c)); + + if (one_bit) { + AddVMCommand(ctx, cmPush, otRegistr, size_, regEFX); + if (!is_inverse) { + AddVMCommand(ctx, cmPush, otRegistr, size_, regEFX); + AddVMCommand(ctx, (rand() & 1) ? cmNor : cmNand, otNone, size_, false); + } + AddVMCommand(ctx, cmPush, otValue, size_ , ~flags); + AddVMCommand(ctx, cmNor, otNone, size_, false); + } else { + bool is_os = (flags & fl_OS) == fl_OS; + if (is_os) { + AddRegistrAndValueSection(ctx, regEFX, size_, fl_S, true); + AddVMCommand(ctx, cmPop, otRegistr, size_, regETX); + AddVMCommand(ctx, cmPop, otRegistr, size_, regEmpty); + + AddRegistrAndValueSection(ctx, regEFX, size_, fl_O, true); + AddVMCommand(ctx, cmPop, otRegistr, size_, regEIX); + AddVMCommand(ctx, cmPop, otRegistr, size_, regEmpty); + + AddVMCommand(ctx, cmPush, otRegistr, size_, regETX); + AddVMCommand(ctx, cmPush, otRegistr, size_, regETX); + AddVMCommand(ctx, (rand() & 1) ? cmNor : cmNand, otNone, size_, false); + + AddVMCommand(ctx, cmPush, otRegistr, size_, regEIX); + AddVMCommand(ctx, cmPush, otRegistr, size_, regEIX); + AddVMCommand(ctx, (rand() & 1) ? cmNor : cmNand, otNone, size_, false); + + AddVMCommand(ctx, cmNor, otNone, size_, false); + AddVMCommand(ctx, cmPush, otRegistr, size_, regETX); + AddVMCommand(ctx, cmPush, otRegistr, size_, regEIX); + AddVMCommand(ctx, cmNor, otNone, size_, false); + + AddVMCommand(ctx, cmNor, otNone, size_, false); + AddVMCommand(ctx, cmPop, otRegistr, size_, regETX); + + if (is_inverse) { + AddVMCommand(ctx, cmPush, otRegistr, size_, regETX); + AddVMCommand(ctx, cmPush, otRegistr, size_, regETX); + AddVMCommand(ctx, (rand() & 1) ? cmNor : cmNand, otNone, size_, false); + AddVMCommand(ctx, cmPop, otRegistr, size_, regETX); + } + check_flag = flags & ~fl_OS; + } else { + check_flag = flags; + } + + if (check_flag) { + AddRegistrAndValueSection(ctx, regEFX, size_, check_flag, true); + AddVMCommand(ctx, cmPop, otRegistr, size_, is_os ? regEIX : regETX); + AddVMCommand(ctx, cmPop, otRegistr, size_, regEmpty); + + if (is_os) { + AddVMCommand(ctx, cmPush, otRegistr, size_, regEIX); + AddVMCommand(ctx, cmPush, otRegistr, size_, regEIX); + AddVMCommand(ctx, (rand() & 1) ? cmNor : cmNand, otNone, size_, false); + + AddVMCommand(ctx, cmPush, otRegistr, size_, regETX); + + if (is_inverse) { + AddVMCommand(ctx, cmPush, otRegistr, size_, regETX); + AddVMCommand(ctx, (rand() & 1) ? cmNor : cmNand, otNone, size_, false); + } + + AddVMCommand(ctx, cmNor, otNone, size_, false); + AddVMCommand(ctx, cmPop, otRegistr, size_, regETX); + } + + if (!is_inverse) { + AddVMCommand(ctx, cmPush, otRegistr, size_, regETX); + AddVMCommand(ctx, cmPush, otRegistr, size_, regETX); + AddVMCommand(ctx, (rand() & 1) ? cmNor : cmNand, otNone, size_, false); + AddVMCommand(ctx, cmPop, otRegistr, size_, regETX); + } + } + + AddRegistrAndValueSection(ctx, regETX, size_, fl_Z); + } + + if (c != 0) + AddVMCommand(ctx, c > 0 ? cmShr : cmShl, otNone, size_, false); +} + +void IntelCommand::AddJmpWithFlagSection(const CompileContext &ctx, IntelCommandType jmp_command_type) +{ + OperandSize os = operand_[1].size; + uint8_t extract_to; +#ifdef DEMO + extract_to = static_cast(OperandSizeToStack(size_)); + + AddVMCommand(ctx, cmPush, otValue, size_, 0, voLinkCommand); + AddVMCommand(ctx, cmPush, otValue, size_, 0, voLinkCommand); + + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); +#else + extract_to = 1; +#endif + + switch (jmp_command_type) { + case cmCmpxchg: + AddExtractFlagSection(ctx, fl_Z, false, extract_to); + break; + + case cmJmpWithFlag: + AddExtractFlagSection(ctx, flags_, (options() & roInverseFlag) != 0, extract_to); + break; + + case cmJCXZ: + AddVMCommand(ctx, cmPush, otRegistr, size_, regEFX); + + AddVMCommand(ctx, cmPush, otValue, os, 0); + AddVMCommand(ctx, cmPush, otRegistr, os, regECX); + AddVMCommand(ctx, cmAdd, otNone, os, true); + AddVMCommand(ctx, cmPop, otRegistr, size_, regEFX); + AddVMCommand(ctx, cmPop, otRegistr, os, regEmpty); + + AddExtractFlagSection(ctx, fl_Z, false, extract_to); + AddVMCommand(ctx, cmPop, otRegistr, size_, regETX); + + AddVMCommand(ctx, cmPop, otRegistr, size_, regEFX); + + AddVMCommand(ctx, cmPush, otRegistr, size_, regETX); + break; + + case cmLoop: case cmRep: + AddVMCommand(ctx, cmPush, otRegistr, size_, regEFX); + + AddVMCommand(ctx, cmPush, otValue, os, -1); + AddVMCommand(ctx, cmPush, otRegistr, os, regECX); + AddVMCommand(ctx, cmAdd, otNone, os, true); + AddVMCommand(ctx, cmPop, otRegistr, size_, regEFX); + AddVMCommand(ctx, cmPop, otRegistr, os, regECX); + + AddExtractFlagSection(ctx, fl_Z, true, extract_to); + AddVMCommand(ctx, cmPop, otRegistr, size_, regETX); + + AddVMCommand(ctx, cmPop, otRegistr, size_, regEFX); + + AddVMCommand(ctx, cmPush, otRegistr, size_, regETX); + break; + + case cmLoopne: case cmRepne: case cmLoope: case cmRepe: + AddVMCommand(ctx, cmPush, otRegistr, size_, regEFX); + + AddVMCommand(ctx, cmPush, otValue, os, -1); + AddVMCommand(ctx, cmPush, otRegistr, os, regECX); + AddVMCommand(ctx, cmAdd, otNone, os, true); + AddVMCommand(ctx, cmPop, otRegistr, size_, regETX); + AddVMCommand(ctx, cmPop, otRegistr, os, regECX); + + if (jmp_command_type == cmLoope || jmp_command_type == cmRepe) { + AddVMCommand(ctx, cmPush, otRegistr, size_, regEFX); + AddVMCommand(ctx, cmPush, otRegistr, size_, regEFX); + AddVMCommand(ctx, cmNor, otNone, size_, false); + AddVMCommand(ctx, cmPop, otRegistr, size_, regEFX); + } + + AddVMCommand(ctx, cmPush, otRegistr, size_, regEFX); + AddVMCommand(ctx, cmPush, otRegistr, size_, regETX); + AddVMCommand(ctx, cmNor, otNone, size_, false); + + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); + AddVMCommand(ctx, cmPush, otMemory, size_, segSS); + + AddVMCommand(ctx, cmNor, otNone, size_, false); + AddVMCommand(ctx, cmPop, otRegistr, size_, regEFX); + + AddExtractFlagSection(ctx, fl_Z, true, extract_to); + AddVMCommand(ctx, cmPop, otRegistr, size_, regETX); + + AddVMCommand(ctx, cmPop, otRegistr, size_, regEFX); + + AddVMCommand(ctx, cmPush, otRegistr, size_, regETX); + break; + } + +#ifdef DEMO + AddVMCommand(ctx, cmAdd, otNone, size_, false); + + AddVMCommand(ctx, cmPush, otMemory, size_, segSS); + + AddVMCommand(ctx, cmPop, otRegistr, size_, regEIX); + AddVMCommand(ctx, cmPop, otRegistr, size_, regEmpty); + AddVMCommand(ctx, cmPop, otRegistr, size_, regEmpty); + + AddVMCommand(ctx, cmPush, otRegistr, size_, regEIX); +#else + AddVMCommand(ctx, cmPush, otValue, size_, (uint64_t)-1); + AddVMCommand(ctx, cmAdd, otNone, size_, false); + AddVMCommand(ctx, cmPop, otRegistr, size_, regEIX); + + // first address AND !condition + AddVMCommand(ctx, cmPush, otValue, size_, 0, voLinkCommand); + AddVMCommand(ctx, cmPush, otRegistr, size_, regEIX); + AddVMCommand(ctx, cmPush, otRegistr, size_, regEIX); + AddVMCommand(ctx, (rand() & 1) ? cmNor : cmNand, otNone, size_, false); + AddVMCommand(ctx, cmNand, otNone, size_, false); + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); + AddVMCommand(ctx, cmPush, otMemory, size_, segSS); + AddVMCommand(ctx, (rand() & 1) ? cmNor : cmNand, otNone, size_, false); + + // second address AND condition + AddVMCommand(ctx, cmPush, otValue, size_, 0, voLinkCommand); + AddVMCommand(ctx, cmPush, otRegistr, size_, regEIX); + AddVMCommand(ctx, cmNand, otNone, size_, false); + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); + AddVMCommand(ctx, cmPush, otMemory, size_, segSS); + AddVMCommand(ctx, (rand() & 1) ? cmNor : cmNand, otNone, size_, false); + + // OR addresses + AddVMCommand(ctx, cmAdd, otNone, size_, false); +#endif + + AddVMCommand(ctx, cmPush, otRegistr, size_, regERX); + AddVMCommand(ctx, cmAdd, otNone, size_, false); + AddEndSection(ctx, cmJmp, 0, voUseEndSectionCryptor); +} + +void IntelCommand::AddBeginSection(const CompileContext &ctx, uint32_t options) +{ + options |= voSectionCommand; + + if (count() == 0) + section_options_ |= rtBeginSection; + + SectionCryptor *section_cryptor; + if (options & voUseBeginSectionCryptor) { + section_cryptor = begin_section_cryptor_; + } else if (options & voUseEndSectionCryptor) { + section_cryptor = end_section_cryptor_; + } else { + section_cryptor = NULL; + } + + ByteList *registr_order = (section_cryptor) ? section_cryptor->end_cryptor()->registr_order() : reinterpret_cast(block()->virtual_machine())->registr_order(); + + AddVMCommand(ctx, cmPop, otRegistr, size_, regERX, options); + options &= ~voLinkCommand; + + for (size_t i = registr_order->size(); i > 0; i--) { + uint8_t reg = registr_order->at(i - 1); + AddVMCommand(ctx, cmPop, otRegistr, size_, reg, options); + } + + AddVMCommand(ctx, cmPop, otRegistr, size_, regEmpty, options); + AddVMCommand(ctx, cmPop, otRegistr, size_, regEmpty, options); +} + +static IntelCommandType CryptorCommandToIntel(CryptCommandType crypt_command) +{ + IntelCommandType res; + switch (crypt_command) { + case ccAdd: + res = cmAdd; + break; + case ccSub: + res = cmSub; + break; + case ccXor: + res = cmXor; + break; + case ccInc: + res = cmInc; + break; + case ccDec: + res = cmDec; + break; + case ccBswap: + res = cmBswap; + break; + case ccRol: + res = cmRol; + break; + case ccRor: + res = cmRor; + break; + case ccNot: + res = cmNot; + break; + case ccNeg: + res = cmNeg; + break; + default: + res = cmUnknown; + break; + } + + return res; +} + +void IntelCommand::AddCryptorSection(const CompileContext &ctx, ValueCryptor *cryptor, bool is_decrypt) +{ + if (!cryptor) + return; + + CompileContext new_ctx = ctx; + new_ctx.options.flags &= ~cpMemoryProtection; + + size_t i; + IntelCommand tmp_command(owner(), size_); + tmp_command.set_block(block()); + tmp_command.include_option(roNoSaveFlags); + IntelOperand first_operand = IntelOperand(otMemory | otRegistr, cryptor->size(), regESP); + size_t c = cryptor->count(); + for (i = 0; i < c; i++) { + ValueCommand *value_command = cryptor->item(is_decrypt ? c - i - 1 : i); + IntelCommandType command_type = CryptorCommandToIntel(value_command->type(is_decrypt)); + if (command_type == cmUnknown) + throw std::runtime_error("Unknown cryptor command"); + + IntelOperand second_operand; + if (command_type == cmAdd || command_type == cmSub || command_type == cmXor || command_type == cmRol || command_type == cmRor) + second_operand = IntelOperand(otValue, (command_type == cmRol || command_type == cmRor) ? osByte : cryptor->size(), 0, value_command->value()); + tmp_command.Init(command_type, first_operand, second_operand); + tmp_command.CompileToVM(new_ctx); + } + for (i = 0; i < tmp_command.count(); i++) { + AddObject(tmp_command.item(i)->Clone(this)); + } +} + +void IntelCommand::AddCheckBreakpointSection(const CompileContext &ctx, OperandSize address_size) +{ + if (address_size < size_) { + AddVMCommand(ctx, cmPop, otRegistr, address_size, regEIX); + AddVMCommand(ctx, cmPush, otRegistr, address_size, regEIX); + AddVMCommand(ctx, cmPush, otValue, osDWord, 0, 0); + AddVMCommand(ctx, cmPush, otRegistr, address_size, regEIX); + } + else { + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); + AddVMCommand(ctx, cmPush, otMemory, address_size, segSS); + } + + AddVMCommand(ctx, cmPush, otMemory, osWord, segDS); + AddVMCommand(ctx, cmPop, otRegistr, osWord, regEIX); + + AddVMCommand(ctx, cmPush, otRegistr, osByte, regEIX); + AddVMCommand(ctx, cmPush, otValue, osByte, 0 - 0xcc); // short "int 03" + AddVMCommand(ctx, cmAdd, otNone, osByte, true); + AddVMCommand(ctx, cmPop, otRegistr, size_, regETX); + AddVMCommand(ctx, cmPop, otRegistr, osByte, regEmpty); + + AddVMCommand(ctx, cmPush, otRegistr, osWord, regEIX); + AddVMCommand(ctx, cmPush, otValue, osWord, 0 - 0x03cd); // long "int 03" + AddVMCommand(ctx, cmAdd, otNone, osWord, true); + AddVMCommand(ctx, cmPush, otRegistr, size_, regETX); + AddVMCommand(ctx, cmNor, otNone, size_, false); + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); + AddVMCommand(ctx, cmPush, otMemory, size_, segSS); + AddVMCommand(ctx, (rand() & 1) ? cmNor : cmNand, otNone, size_, false); + AddVMCommand(ctx, cmPop, otRegistr, size_, regETX); + AddVMCommand(ctx, cmPop, otRegistr, osWord, regEmpty); + + AddVMCommand(ctx, cmPush, otRegistr, osWord, regEIX); + AddVMCommand(ctx, cmPush, otValue, osWord, 0 - 0x0b0f); // "ud2" + AddVMCommand(ctx, cmAdd, otNone, osWord, true); + AddVMCommand(ctx, cmPush, otRegistr, size_, regETX); + AddVMCommand(ctx, cmNor, otNone, size_, false); + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); + AddVMCommand(ctx, cmPush, otMemory, size_, segSS); + AddVMCommand(ctx, (rand() & 1) ? cmNor : cmNand, otNone, size_, false); + AddVMCommand(ctx, cmPop, otRegistr, size_, regETX); + AddVMCommand(ctx, cmPop, otRegistr, osWord, regEmpty); + + // extract Z flag to random value + AddVMCommand(ctx, cmPush, otValue, osWord, 6); + AddVMCommand(ctx, cmPush, otRegistr, address_size, regETX); + AddVMCommand(ctx, cmShr, otNone, address_size, false); + AddVMCommand(ctx, cmPush, otValue, address_size, ~1); + AddVMCommand(ctx, cmNor, otNone, address_size, false); + AddVMCommand(ctx, cmPush, otValue, address_size, (uint64_t)-1); + AddVMCommand(ctx, cmAdd, otNone, address_size, false); + AddVMCommand(ctx, cmPush, otValue, address_size, rand32()); + AddVMCommand(ctx, cmNand, otNone, address_size, false); + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); + AddVMCommand(ctx, cmPush, otMemory, address_size, segSS); + AddVMCommand(ctx, (rand() & 1) ? cmNor : cmNand, otNone, address_size, false); + + AddVMCommand(ctx, cmAdd, otNone, address_size, false); +} + +void IntelCommand::AddCheckCRCSection(const CompileContext &ctx, OperandSize address_size) +{ + AddVMCommand(ctx, cmRdtsc, otNone, size_, 0); + AddVMCommand(ctx, cmAdd, otNone, osDWord, false); + AddVMCommand(ctx, cmPush, otValue, osDWord, rand32()); + AddVMCommand(ctx, cmAdd, otNone, osDWord, false); + AddVMCommand(ctx, cmPop, otRegistr, osDWord, regEIX); + + IntelVMCommand *vm_command = AddVMCommand(ctx, cmPush, otValue, osDWord, 0); + internal_links_.Add(vlCRCTableCount, vm_command, NULL); + AddVMCommand(ctx, cmPush, otRegistr, osDWord, regEIX); + AddVMCommand(ctx, cmPush, otValue, osDWord, 0); + AddVMCommand(ctx, cmDiv, otNone, osDWord, true); + AddVMCommand(ctx, cmPop, otRegistr, size_, regEmpty); + + AddVMCommand(ctx, cmPush, otValue, osDWord, sizeof(CRCInfo::POD)); + AddVMCommand(ctx, cmMul, otNone, osDWord, true); + AddVMCommand(ctx, cmPop, otRegistr, size_, regEmpty); + + AddVMCommand(ctx, cmPop, otRegistr, osDWord, regEmpty); + AddVMCommand(ctx, cmPop, otRegistr, osDWord, regEIX); + + AddVMCommand(ctx, cmPop, otRegistr, osDWord, regEmpty); + + if (size_ == osQWord) + AddVMCommand(ctx, cmPush, otValue, osDWord, 0); + AddVMCommand(ctx, cmPush, otRegistr, osDWord, regEIX); + vm_command = AddVMCommand(ctx, cmPush, otValue, size_, 0, voFixup); + internal_links_.Add(vlCRCTableAddress, vm_command, NULL); + AddVMCommand(ctx, cmAdd, otNone, size_, false); + AddVMCommand(ctx, cmPop, otRegistr, size_, regEIX); + + if (address_size == osQWord) + AddVMCommand(ctx, cmPush, otValue, osDWord, 0); + + if (size_ == osQWord) + AddVMCommand(ctx, cmPush, otValue, osDWord, 0); + AddVMCommand(ctx, cmPush, otRegistr, size_, regEIX); + assert(sizeof(CRCInfo::POD) == 12); + AddVMCommand(ctx, cmPush, otValue, size_, offsetof(CRCInfo::POD, size)); + AddVMCommand(ctx, cmAdd, otNone, size_, false); + AddVMCommand(ctx, cmPush, otMemory, osDWord, segDS); + AddCryptorSection(ctx, ctx.file->function_list()->crc_cryptor(), true); + + if (size_ == osQWord) + AddVMCommand(ctx, cmPush, otValue, osDWord, 0); + AddVMCommand(ctx, cmPush, otRegistr, size_, regEIX); + AddVMCommand(ctx, cmPush, otMemory, osDWord, segDS); + AddCryptorSection(ctx, ctx.file->function_list()->crc_cryptor(), true); + AddVMCommand(ctx, cmPush, otValue, size_, ctx.file->image_base(), voFixup); + AddVMCommand(ctx, cmAdd, otNone, size_, false); + + AddVMCommand(ctx, cmCrc, otNone, size_, 0); + + AddVMCommand(ctx, cmPush, otRegistr, size_, regEIX); + AddVMCommand(ctx, cmPush, otValue, size_, offsetof(CRCInfo::POD, hash)); + AddVMCommand(ctx, cmAdd, otNone, size_, false); + AddVMCommand(ctx, cmPush, otMemory, osDWord, segDS); + + AddVMCommand(ctx, cmAdd, otNone, osDWord, false); + + AddVMCommand(ctx, cmAdd, otNone, address_size, false); +} + +void IntelCommand::AddEndSection(const CompileContext &ctx, IntelCommandType end_command, uint8_t end_value, uint32_t options) +{ + options |= voSectionCommand; + + SectionCryptor *section_cryptor; + if (options & voUseBeginSectionCryptor) { + section_cryptor = begin_section_cryptor_; + } else if (options & voUseEndSectionCryptor) { + section_cryptor = end_section_cryptor_; + } else { + section_cryptor = NULL; + } + + ByteList *registr_order; + if (section_cryptor) + registr_order = section_cryptor->end_cryptor()->registr_order(); + else if (end_command == cmJmp && end_value == 0xff) + registr_order = link()->to_command()->block()->virtual_machine()->registr_order(); + else + registr_order = block()->virtual_machine()->registr_order(); + + switch (end_command) { + case cmRet: + { + OperandSize address_size = (end_value == 1) ? osDWord : size_; + if (ctx.options.flags & cpCheckDebugger) + AddCheckBreakpointSection(ctx, address_size); + if (ctx.options.flags & cpMemoryProtection) + AddCheckCRCSection(ctx, address_size); + } + break; + + case cmJmp: + AddVMCommand(ctx, cmPop, otRegistr, size_, regEIX, options); + AddVMCommand(ctx, cmPush, otRegistr, size_, regEmpty, options); + AddVMCommand(ctx, cmPush, otRegistr, size_, regEmpty, options); + break; + } + + for (size_t i = 0; i < registr_order->size(); i++) { + uint8_t reg = registr_order->at(i); + AddVMCommand(ctx, cmPush, otRegistr, size_, reg, options); + } + + if (end_command != cmRet) + AddVMCommand(ctx, cmPush, otRegistr, size_, regERX, options); + + section_options_ |= rtEndSection; + + if (end_command != cmNop) { + if (end_command == cmJmp) + AddVMCommand(ctx, cmPush, otRegistr, size_, regEIX, options); + AddVMCommand(ctx, end_command, otNone, size_, end_value, options); + } +} + +uint64_t IntelCommand::AddStoreEIPSection(const CompileContext &ctx, uint64_t prev_eip) +{ + if (ctx.file->runtime_function_list() && ctx.file->runtime_function_list()->count()) { + uint64_t value; + AddressRange *range = address_range(); + if (range) { + FunctionInfo *info = range->owner(); + uint64_t end_prolog = info->begin() + info->prolog_size(); + if (range->original_begin() > end_prolog || !address_) { + value = range->original_begin(); + } else if (address_ <= end_prolog) { + value = address_; + } else { + value = end_prolog; + } + } else { + value = 0; + } + if (prev_eip != value) { + AddVMCommand(ctx, cmPush, otValue, size_, value, voFixup); + AddVMCommand(ctx, cmPop, otRegistr, size_, regExtended + 0); + } + return value; + } + return -1; +} + +void IntelCommand::AddStoreExtRegistrSection(const CompileContext &ctx, uint8_t registr) +{ + if (ctx.file->runtime_function_list() && ctx.file->runtime_function_list()->count()) { + uint8_t ext_registr; + if (registr == regESP) { + ext_registr = regExtended + 1; + } else { + if (!address_range() || address_range()->owner()->frame_registr() != registr) + return; + + switch (registr) { + case regEBP: + ext_registr = regExtended + 2; + break; + case regESI: + ext_registr = regExtended + 3; + break; + case regEDI: + ext_registr = regExtended + 4; + break; + case regEBX: + ext_registr = regExtended + 5; + break; + default: + return; + } + } + + AddVMCommand(ctx, cmPush, otRegistr, size_, registr); + AddVMCommand(ctx, cmPop, otRegistr, size_, ext_registr); + } +} + +void IntelCommand::AddStoreExtRegistersSection(const CompileContext &ctx) +{ + if (ctx.file->runtime_function_list() && ctx.file->runtime_function_list()->count()) { + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); + AddVMCommand(ctx, cmPop, otRegistr, size_, regExtended + 1); + + AddVMCommand(ctx, cmPush, otRegistr, size_, regEBP); + AddVMCommand(ctx, cmPop, otRegistr, size_, regExtended + 2); + + AddVMCommand(ctx, cmPush, otRegistr, size_, regESI); + AddVMCommand(ctx, cmPop, otRegistr, size_, regExtended + 3); + + AddVMCommand(ctx, cmPush, otRegistr, size_, regEDI); + AddVMCommand(ctx, cmPop, otRegistr, size_, regExtended + 4); + + AddVMCommand(ctx, cmPush, otRegistr, size_, regEBX); + AddVMCommand(ctx, cmPop, otRegistr, size_, regExtended + 5); + } +} + +void IntelCommand::AddExtSection(const CompileContext &ctx, IntelCommand *next_command) +{ + if (next_command) { + if (ctx.options.flags & cpEncryptBytecode) { + block()->AddCorrectCommand(AddVMCommand(ctx, cmPush, otValue, size_, rand64(), voSectionCommand)); + } else { + AddVMCommand(ctx, cmPush, otRegistr, size(), regEmpty, voSectionCommand); + } + AddVMCommand(ctx, cmPush, otRegistr, size(), regEmpty, voSectionCommand); + end_section_cryptor_ = next_command->begin_section_cryptor_; + AddEndSection(ctx, cmNop, 0, voUseEndSectionCryptor); + item(count() - 1)->include_option(voInitOffset); + } else { + AddBeginSection(ctx, voUseBeginSectionCryptor); + if ((section_options() & rtLinkedToExt) && begin_section_cryptor_) { + if (ctx.options.flags & cpEncryptBytecode) { + block()->AddCorrectCommand(AddVMCommand(ctx, cmPush, otValue, size_, rand64(), voSectionCommand)); + } else { + AddVMCommand(ctx, cmPush, otRegistr, size_, regEmpty, voSectionCommand); + } + AddVMCommand(ctx, cmPush, otRegistr, size_, regEmpty, voSectionCommand); + AddEndSection(ctx, cmNop); + item(count() - 1)->include_option(voInitOffset); + section_options_ &= ~rtEndSection; + size_t c = count(); + AddBeginSection(ctx); + ext_vm_entry_ = item(c); + } + } +} + +void IntelCommand::AddCorrectESPSection(const CompileContext &ctx, OperandSize operand_size, size_t value) +{ + size_t i, j; + IntelVMCommand *vm_command; + + j = 0; + for (i = count(); i > 0; i--) { + vm_command = item(i - 1); + if (vm_command->options() & voSectionCommand) { + j = i; + break; + } + } + + for (i = j; i < count() - 1; i++) { + vm_command = item(i); + value += vm_command->GetStackLevel(); + } + + if (value) { + AddVMCommand(ctx, cmPush, otValue, operand_size, value); + AddVMCommand(ctx, cmAdd, otNone, operand_size, false); + } +} + +void IntelCommand::CompileOperand(const CompileContext &ctx, size_t operand_index, uint32_t options) +{ + IntelOperand *operand = &operand_[operand_index]; + OperandSize operand_size = operand->size; + uint32_t vm_options = 0; + if (operand->type & otValue) { + if (operand->fixup || (options & coFixup) || operand->is_large_value) + vm_options |= voFixup; + if (link() && link()->operand_index() == (int)operand_index) + vm_options |= voLinkCommand; + } + if (options & coAsWord) { + operand_size = osWord; + } else if (options & coAsPointer) { + operand_size = size_; + } + + switch (operand->type) { + case otSegmentRegistr: + if (options & coSaveResult) { + AddVMCommand(ctx, cmPop, otSegmentRegistr, osWord, operand->registr); + AddCorrectOperandSizeSection(ctx, operand_size, osWord); + } else { + AddCorrectOperandSizeSection(ctx, osWord, operand_size); + AddVMCommand(ctx, cmPush, otSegmentRegistr, osWord, operand->registr); + } + break; + + case otDebugRegistr: + if (options & coSaveResult) { + AddVMCommand(ctx, cmPop, otDebugRegistr, operand_size, operand->registr); + } else { + AddVMCommand(ctx, cmPush, otDebugRegistr, operand_size, operand->registr); + } + break; + + case otControlRegistr: + if (options & coSaveResult) { + AddVMCommand(ctx, cmPop, otControlRegistr, operand_size, operand->registr); + } else { + AddVMCommand(ctx, cmPush, otControlRegistr, operand_size, operand->registr); + } + break; + + case otHiPartRegistr: + if (options & coSaveResult) { + AddVMCommand(ctx, cmPop, otHiPartRegistr, operand_size, operand->registr); + } else { + AddVMCommand(ctx, cmPush, otHiPartRegistr, operand_size, operand->registr); + } + break; + + case otRegistr: + if (options & coSaveResult) { + AddVMCommand(ctx, cmPop, otRegistr, operand_size, operand->registr); + if (size_ == osQWord && operand_size == osDWord) { + AddVMCommand(ctx, cmPush, otValue, osDWord, 0); + AddVMCommand(ctx, cmPop, otHiPartRegistr, osDWord, operand->registr); + } + AddStoreExtRegistrSection(ctx, operand->registr); + } else { + AddVMCommand(ctx, cmPush, otRegistr, operand_size, operand->registr); + if (operand->registr == regESP) + AddCorrectESPSection(ctx, operand_size, 0); + } + break; + + case otValue: + if ((options & coInverse) && (vm_options & voFixup) == 0) { + AddVMCommand(ctx, cmPush, otValue, operand_size, ~operand->value, vm_options, operand->fixup); + options &= ~coInverse; + } else + AddVMCommand(ctx, cmPush, otValue, operand_size, operand->value, vm_options, operand->fixup); + break; + + default: + if (operand->type & otMemory) { + if (operand->type & otBaseRegistr) { + AddCorrectOperandSizeSection(ctx, operand->address_size, size_); + AddVMCommand(ctx, cmPush, otRegistr, operand->address_size, operand->base_registr); + if (operand->base_registr == regESP) + AddCorrectESPSection(ctx, size_, type_ == cmPop ? OperandSizeToStack(operand_size) : 0); + } + if (operand->type & otRegistr) { + if (operand->scale_registr > 0) + AddVMCommand(ctx, cmPush, otValue, osWord, operand->scale_registr); + AddCorrectOperandSizeSection(ctx, operand->address_size, size_); + AddVMCommand(ctx, cmPush, otRegistr, operand->address_size, operand->registr); + if (operand->registr == regESP) + AddCorrectESPSection(ctx, size_, type_ == cmPop ? OperandSizeToStack(operand_size) : 0); + if (operand->scale_registr > 0) + AddVMCommand(ctx, cmShl, otNone, size_, false); + if (operand->type & otBaseRegistr) + AddVMCommand(ctx, cmAdd, otNone, size_, false); + } + if (operand->type & otValue) { + AddVMCommand(ctx, cmPush, otValue, size_, operand->value, vm_options, operand->fixup); + if (operand->type & (otBaseRegistr | otRegistr)) + AddVMCommand(ctx, cmAdd, otNone, size_, false); + } + + if ((options & coAsPointer) == 0) { + if (options & coSaveResult) { + AddVMCommand(ctx, cmPop, otMemory, operand_size, operand->effective_base_segment(base_segment_)); + } else { + AddVMCommand(ctx, cmPush, otMemory, operand_size, operand->effective_base_segment(base_segment_)); + } + } + } + } + + if (options & coInverse) { + if (operand->type & otMemory) { + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); + AddVMCommand(ctx, cmPush, otMemory, operand_size, segSS); + } else { + CompileOperand(ctx, operand_index); + } + AddVMCommand(ctx, (rand() & 1) ? cmNor : cmNand, otNone, operand_size, false); + } +} + +void IntelCommand::CompileToVM(const CompileContext &ctx) +{ + if (link() && link()->type() == ltNative) { + AddVMCommand(ctx, cmPush, otValue, size_, 0, voLinkCommand | voFixup); + AddEndSection(ctx, cmRet); + return; + } + + size_t i; + OperandSize os, adr_os; + IntelOperand *operand; + uint16_t flags; + size_t value; + bool save_flags = (options() & roNoSaveFlags) == 0; + + if ((options() & roLockPrefix) && type_ != cmXchg) { + switch (type_) { + case cmAdd: case cmAnd: case cmSub: case cmXor: case cmOr: case cmXadd: + i = (operand_[0].type & otMemory) ? 0 : 1; + CompileOperand(ctx, 1 - i); + CompileOperand(ctx, i, coAsPointer); + AddVMCommand(ctx, type_, otMemory, operand_[0].size, operand_[i].effective_base_segment(base_segment_)); + AddVMCommand(ctx, cmPop, otRegistr, size_, save_flags ? regEFX : regEmpty); + if (type_ == cmXadd) + CompileOperand(ctx, 1 - i, coSaveResult); + break; + default: + throw std::runtime_error("Runtime error at CompileToVM: " + text()); + } + } else + switch (type_) { + case cmBt: case cmBtr: case cmBts: case cmBtc: + uint8_t mask; + switch (operand_[0].size) { + case osWord: mask = 15; break; + case osDWord: mask = 31; break; + default: mask = 63; break; + } + + if (operand_[0].type & otMemory) { + os = osByte; + uint8_t old_mask = mask; + mask = 7; + + if (operand_[1].type == otValue) { + AddVMCommand(ctx, cmPush, otValue, osWord, operand_[1].value & mask); + AddVMCommand(ctx, cmPush, otValue, size_, (operand_[1].value & old_mask) >> 3); + } else { + CompileOperand(ctx, 1, coAsWord); + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); + AddVMCommand(ctx, cmPush, otMemory, osWord, segSS); + AddVMCommand(ctx, cmNor, otNone, osWord, false); + AddVMCommand(ctx, cmPush, otValue, osWord, ~mask); + AddVMCommand(ctx, cmNor, otNone, osWord, false); + + AddVMCommand(ctx, cmPush, otValue, osWord, 3); + AddCorrectOperandSizeSection(ctx, operand_[1].size, size_); + CompileOperand(ctx, 1); + AddVMCommand(ctx, cmShr, otNone, size_, false); + } + + CompileOperand(ctx, 0, coAsPointer); + AddVMCommand(ctx, cmAdd, otNone, size_, false); + AddVMCommand(ctx, cmPop, otRegistr, size_, regETX); + + AddVMCommand(ctx, cmPush, otRegistr, size_, regETX); + AddVMCommand(ctx, cmPush, otMemory, osByte, operand_[0].effective_base_segment(base_segment_)); + AddVMCommand(ctx, cmShr, otNone, os, false); + } else { + os = operand_[0].size; + + if (operand_[1].type == otValue) { + AddVMCommand(ctx, cmPush, otValue, osWord, operand_[1].value & mask); + } else { + CompileOperand(ctx, 1, coAsWord); + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); + AddVMCommand(ctx, cmPush, otMemory, osWord, segSS); + AddVMCommand(ctx, cmNor, otNone, osWord, false); + AddVMCommand(ctx, cmPush, otValue, osWord, ~mask); + AddVMCommand(ctx, cmNor, otNone, osWord, false); + } + + CompileOperand(ctx, 0); + AddVMCommand(ctx, cmShr, otNone, os, false); + } + + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); + AddVMCommand(ctx, cmPush, otMemory, osWord, segSS); + AddVMCommand(ctx, cmNor, otNone, osWord, false); + + AddVMCommand(ctx, cmPush, otValue, osWord, ~fl_C); + AddVMCommand(ctx, cmNor, otNone, osWord, false); + + AddVMCommand(ctx, cmPush, otRegistr, osWord, regEFX); + AddVMCommand(ctx, cmPush, otRegistr, osWord, regEFX); + AddVMCommand(ctx, cmNor, otNone, osWord, false); + AddVMCommand(ctx, cmPush, otValue, osWord, fl_C); + AddVMCommand(ctx, cmNor, otNone, osWord, false); + + AddVMCommand(ctx, cmAdd, otNone, osWord, false); + + AddVMCommand(ctx, cmPop, otRegistr, osWord, regEFX); + + AddCorrectOperandSizeSection(ctx, os, osWord); + + if (type_ != cmBt) { + if (operand_[1].type == otValue) { + if (operand_[0].type & otMemory) { + AddVMCommand(ctx, cmPush, otValue, os, 1ull << (operand_[1].value & 7)); + } else { + AddVMCommand(ctx, cmPush, otValue, os, 1ull << operand_[1].value); + } + } else { + CompileOperand(ctx, 1, coAsWord); + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); + AddVMCommand(ctx, cmPush, otMemory, osWord, segSS); + AddVMCommand(ctx, cmNor, otNone, osWord, false); + AddVMCommand(ctx, cmPush, otValue, osWord, ~mask); + AddVMCommand(ctx, cmNor, otNone, osWord, false); + + AddVMCommand(ctx, cmPush, otValue, os, 1); + AddVMCommand(ctx, cmShl, otNone, os, false); + } + + switch (type_) { + case cmBts: + if (operand_[0].type & otMemory) { + AddVMCommand(ctx, cmPush, otRegistr, size_, regETX); + AddVMCommand(ctx, cmPush, otMemory, osByte, operand_[0].effective_base_segment(base_segment_)); + } else { + CompileOperand(ctx, 0); + } + AddVMCommand(ctx, cmNor, otNone, os, false); + + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); + AddVMCommand(ctx, cmPush, otMemory, os, segSS); + break; + case cmBtr: + if (operand_[0].type & otMemory) { + AddVMCommand(ctx, cmPush, otRegistr, size_, regETX); + AddVMCommand(ctx, cmPush, otMemory, osByte, operand_[0].effective_base_segment(base_segment_)); + + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); + AddVMCommand(ctx, cmPush, otMemory, osByte, segSS); + AddVMCommand(ctx, cmNor, otNone, osByte, false); + } else { + CompileOperand(ctx, 0, coInverse); + } + break; + case cmBtc: + if (operand_[0].type & otMemory) { + AddVMCommand(ctx, cmPush, otRegistr, size_, regETX); + AddVMCommand(ctx, cmPush, otMemory, osByte, operand_[0].effective_base_segment(base_segment_)); + AddVMCommand(ctx, cmNor, otNone, os, false); + + AddVMCommand(ctx, cmPush, otRegistr, size_, regETX); + AddVMCommand(ctx, cmPush, otMemory, osByte, operand_[0].effective_base_segment(base_segment_)); + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); + AddVMCommand(ctx, cmPush, otMemory, osByte, segSS); + AddVMCommand(ctx, cmNor, otNone, osByte, false); + } else { + CompileOperand(ctx, 0); + AddVMCommand(ctx, cmNor, otNone, os, false); + + CompileOperand(ctx, 0, coInverse); + } + + if (operand_[1].type == otValue) { + if (operand_[0].type & otMemory) { + AddVMCommand(ctx, cmPush, otValue, os, ~(1 << (operand_[1].value & 7))); + } else { + AddVMCommand(ctx, cmPush, otValue, os, ~(1 << operand_[1].value)); + } + } else { + CompileOperand(ctx, 1, coAsWord); + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); + AddVMCommand(ctx, cmPush, otMemory, osWord, segSS); + AddVMCommand(ctx, cmNor, otNone, osWord, false); + AddVMCommand(ctx, cmPush, otValue, osWord, ~mask); + AddVMCommand(ctx, cmNor, otNone, osWord, false); + + AddVMCommand(ctx, cmPush, otValue, os, 1); + AddVMCommand(ctx, cmShl, otNone, os, false); + + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); + AddVMCommand(ctx, cmPush, otMemory, os, segSS); + + AddVMCommand(ctx, cmNor, otNone, os, false); + } + AddVMCommand(ctx, cmNor, otNone, os, false); + break; + } + + AddVMCommand(ctx, cmNor, otNone, os, false); + + if (operand_[0].type & otMemory) { + AddVMCommand(ctx, cmPush, otRegistr, size_, regETX); + AddVMCommand(ctx, cmPop, otMemory, osByte, operand_[0].effective_base_segment(base_segment_)); + } else { + CompileOperand(ctx, 0, coSaveResult); + } + } + break; + + case cmPush: + CompileOperand(ctx, 0); + AddStoreExtRegistrSection(ctx, regESP); + break; + + case cmPop: + CompileOperand(ctx, 0, coSaveResult); + AddStoreExtRegistrSection(ctx, regESP); + break; + + case cmMov: + CompileOperand(ctx, 1); + CompileOperand(ctx, 0, coSaveResult); + break; + + case cmLea: + CompileOperand(ctx, 1, coAsPointer); + CompileOperand(ctx, 0, coSaveResult); + AddCorrectOperandSizeSection(ctx, size_, operand_[0].size); + break; + + case cmNot: + CompileOperand(ctx, 0, coInverse); + CompileOperand(ctx, 0, coSaveResult); + break; + + case cmNeg: + CompileOperand(ctx, 0); + + os = operand_[0].size; + AddVMCommand(ctx, cmPush, otValue, os, -1); + AddVMCommand(ctx, cmAdd, otNone, os, true); + AddVMCommand(ctx, cmPop, otRegistr, size_, save_flags ? regEFX : regEmpty); + + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); + AddVMCommand(ctx, cmPush, otMemory, os, segSS); + AddVMCommand(ctx, (rand() & 1) ? cmNor : cmNand, otNone, os, true); + AddVMCommand(ctx, cmPop, otRegistr, size_, save_flags ? regEIX : regEmpty); + + CompileOperand(ctx, 0, coSaveResult); + + if (save_flags) + AddCombineFlagsSection(ctx, fl_P | fl_O | fl_A | fl_C); + break; + + case cmAdd: case cmAdc: case cmXadd: + if (type_ == cmXadd) + CompileOperand(ctx, 0); + CompileOperand(ctx, 1); + + os = operand_[0].size; + if (type_ == cmAdc) { + AddCorrectOperandSizeSection(ctx, osWord, os); + AddRegistrAndValueSection(ctx, regEFX, osWord, fl_C); + AddVMCommand(ctx, cmAdd, otNone, os, true); + AddVMCommand(ctx, cmPop, otRegistr, size_, save_flags ? regEIX : regEmpty); + } + + CompileOperand(ctx, 0); + AddVMCommand(ctx, cmAdd, otNone, os, true); + AddVMCommand(ctx, cmPop, otRegistr, size_, save_flags ? regEFX : regEmpty); + + CompileOperand(ctx, 0, coSaveResult); + + if (type_ == cmXadd) + CompileOperand(ctx, 1, coSaveResult); + + if (type_ == cmAdc && save_flags) { + AddRegistrAndValueSection(ctx, regEIX, size_, fl_C | fl_A | fl_O); + AddVMCommand(ctx, cmPush, otRegistr, size_, regEFX); + AddVMCommand(ctx, cmNor, otNone, size_, false); + + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); + AddVMCommand(ctx, cmPush, otMemory, size_, segSS); + AddVMCommand(ctx, (rand() & 1) ? cmNor : cmNand, otNone, size_, false); + AddVMCommand(ctx, cmPop, otRegistr, size_, regEFX); + } + break; + + case cmSbb: + CompileOperand(ctx, 1); + + os = operand_[0].size; + AddCorrectOperandSizeSection(ctx, osWord, os); + AddRegistrAndValueSection(ctx, regEFX, osWord, fl_C); + AddVMCommand(ctx, cmAdd, otNone, os, false); + + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); + AddVMCommand(ctx, cmPush, otMemory, os, segSS); + AddVMCommand(ctx, (rand() & 1) ? cmNor : cmNand, otNone, os, false); + + AddVMCommand(ctx, cmPush, otValue, os, 1); + AddVMCommand(ctx, cmAdd, otNone, os, false); + + CompileOperand(ctx, 0); + + AddVMCommand(ctx, cmAdd, otNone, os, true); + AddVMCommand(ctx, cmPop, otRegistr, size_, save_flags ? regEFX : regEmpty); + + CompileOperand(ctx, 0, coSaveResult); + + if (save_flags) + AddCorrectFlagSection(ctx, fl_A | fl_C); + break; + + case cmSub: case cmCmp: + CompileOperand(ctx, 1); + CompileOperand(ctx, 0, coInverse); + + os = operand_[0].size; + AddVMCommand(ctx, cmAdd, otNone, os, true); + AddVMCommand(ctx, cmPop, otRegistr, size_, save_flags ? regEFX : regEmpty); + + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); + AddVMCommand(ctx, cmPush, otMemory, os, segSS); + + AddVMCommand(ctx, (rand() & 1) ? cmNor : cmNand, otNone, os, true); + AddVMCommand(ctx, cmPop, otRegistr, size_, save_flags ? regEIX : regEmpty); + + if (type_ == cmCmp) { + AddVMCommand(ctx, cmPop, otRegistr, os, regEmpty); + } else { + CompileOperand(ctx, 0, coSaveResult); + } + + if (save_flags) + AddCombineFlagsSection(ctx, fl_P | fl_O | fl_A | fl_C); + break; + + case cmInc: + os = operand_[0].size; + AddVMCommand(ctx, cmPush, otValue, os, 1); + CompileOperand(ctx, 0); + + AddVMCommand(ctx, cmAdd, otNone, os, true); + AddVMCommand(ctx, cmPop, otRegistr, size_, save_flags ? regEIX : regEmpty); + + CompileOperand(ctx, 0, coSaveResult); + + if (save_flags) + AddCombineFlagsSection(ctx, fl_C); + break; + + case cmDec: + os = operand_[0].size; + AddVMCommand(ctx, cmPush, otValue, os, -1); + CompileOperand(ctx, 0); + + AddVMCommand(ctx, cmAdd, otNone, os, true); + AddVMCommand(ctx, cmPop, otRegistr, size_, save_flags ? regEIX : regEmpty); + + CompileOperand(ctx, 0, coSaveResult); + + if (save_flags) { + AddCombineFlagsSection(ctx, fl_C); + AddCorrectFlagSection(ctx, fl_A); + } + break; + + case cmXlat: + os = operand_[0].size; + AddCorrectOperandSizeSection(ctx, os, size_); + + AddCorrectOperandSizeSection(ctx, osWord, os); + AddVMCommand(ctx, cmPush, otRegistr, osByte, regEAX); + + AddVMCommand(ctx, cmPush, otRegistr, os, regEBX); + AddVMCommand(ctx, cmAdd, otNone, os, false); + AddVMCommand(ctx, cmPush, otMemory, osByte, (base_segment_ == segDefault) ? segDS : base_segment_); + AddVMCommand(ctx, cmPop, otRegistr, osByte, regEAX); + break; + + case cmSetXX: + AddExtractFlagSection(ctx, flags_,(options() & roInverseFlag) != 0, 1); + CompileOperand(ctx, 0, coSaveResult); + AddCorrectOperandSizeSection(ctx, size_, osWord); + break; + + case cmAnd: case cmTest: + os = operand_[0].size; + if (rand() & 1) { + CompileOperand(ctx, 1, coInverse); + CompileOperand(ctx, 0, coInverse); + AddVMCommand(ctx, cmNor, otNone, os, true); + } else { + CompileOperand(ctx, 1); + CompileOperand(ctx, 0); + AddVMCommand(ctx, cmNand, otNone, os, false); + + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); + AddVMCommand(ctx, cmPush, otMemory, os, segSS); + AddVMCommand(ctx, (rand() & 1) ? cmNor : cmNand, otNone, os, true); + } + AddVMCommand(ctx, cmPop, otRegistr, size_, save_flags ? regEFX : regEmpty); + + if (type_ == cmTest) { + AddVMCommand(ctx, cmPop, otRegistr, os, regEmpty); + } else { + CompileOperand(ctx, 0, coSaveResult); + } + break; + + case cmXor: + os = operand_[0].size; + if (rand() & 1) { + CompileOperand(ctx, 1, coInverse); + CompileOperand(ctx, 0, coInverse); + AddVMCommand(ctx, cmNor, otNone, os, false); + + CompileOperand(ctx, 1); + CompileOperand(ctx, 0); + AddVMCommand(ctx, cmNor, otNone, os, false); + + AddVMCommand(ctx, cmNor, otNone, os, true); + } else { + CompileOperand(ctx, 1, coInverse); + CompileOperand(ctx, 0); + AddVMCommand(ctx, cmNand, otNone, os, false); + + CompileOperand(ctx, 1); + CompileOperand(ctx, 0, coInverse); + AddVMCommand(ctx, cmNand, otNone, os, false); + + AddVMCommand(ctx, cmNand, otNone, os, true); + } + AddVMCommand(ctx, cmPop, otRegistr, size_, save_flags ? regEFX : regEmpty); + + CompileOperand(ctx, 0, coSaveResult); + break; + + case cmOr: + os = operand_[0].size; + if (rand() & 1) { + CompileOperand(ctx, 1); + CompileOperand(ctx, 0); + AddVMCommand(ctx, cmNor, otNone, os, false); + + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); + AddVMCommand(ctx, cmPush, otMemory, os, segSS); + AddVMCommand(ctx, (rand() & 1) ? cmNor : cmNand, otNone, os, true); + } else { + CompileOperand(ctx, 1, coInverse); + CompileOperand(ctx, 0, coInverse); + AddVMCommand(ctx, cmNand, otNone, os, true); + } + AddVMCommand(ctx, cmPop, otRegistr, size_, save_flags ? regEFX : regEmpty); + + CompileOperand(ctx, 0, coSaveResult); + break; + + case cmShld: case cmShrd: + CompileOperand(ctx, 2); + CompileOperand(ctx, 1); + CompileOperand(ctx, 0); + + os = operand_[0].size; + if (os == osWord) { + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); + AddVMCommand(ctx, cmPush, otMemory, osDWord, segSS); + } + + AddVMCommand(ctx, type_, otNone, os == osQWord ? osQWord : osDWord, true); + AddVMCommand(ctx, cmPop, otRegistr, size_, save_flags ? regEFX : regEmpty); + + CompileOperand(ctx, 0, coSaveResult); + + if (os == osWord) + AddVMCommand(ctx, cmPop, otRegistr, osWord, regEmpty); + break; + + case cmRol: case cmRor: + CompileOperand(ctx, 1); + CompileOperand(ctx, 0); + + os = operand_[0].size; + switch (os) { + case osByte: + AddVMCommand(ctx, cmPush, otValue, osWord, 8); + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); + AddVMCommand(ctx, cmPush, otValue, size_, 2); + AddVMCommand(ctx, cmAdd, otNone, size_, false); + AddVMCommand(ctx, cmPush, otMemory, osWord, segSS); + AddVMCommand(ctx, cmShl, otNone, osWord, false); + AddVMCommand(ctx, cmAdd, otNone, osWord, false); + + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); + AddVMCommand(ctx, cmPush, otMemory, osWord, segSS); + break; + case osWord: + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); + AddVMCommand(ctx, cmPush, otMemory, osWord, segSS); + break; + } + + adr_os = (os == osQWord) ? osQWord : osDWord; + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); + AddVMCommand(ctx, cmPush, otMemory, adr_os, segSS); + + AddVMCommand(ctx, type_ == cmRol ? cmShld : cmShrd, otNone, adr_os, true); + AddVMCommand(ctx, cmPop, otRegistr, size_, save_flags ? regEIX : regEmpty); + + CompileOperand(ctx, 0, coSaveResult); + + if (os == osByte || os == osWord) + AddVMCommand(ctx, cmPop, otRegistr, osWord, regEmpty); + + if (save_flags) + AddCombineFlagsSection(ctx, fl_P | fl_A | fl_Z | fl_S); + break; + + case cmShl: case cmSal: case cmShr: + CompileOperand(ctx, 1); + CompileOperand(ctx, 0); + + os = operand_[0].size; + AddVMCommand(ctx, type_ == cmShr ? cmShr : cmShl, otNone, os, true); + AddVMCommand(ctx, cmPop, otRegistr, size_, save_flags ? regEFX : regEmpty); + + CompileOperand(ctx, 0, coSaveResult); + break; + + case cmSar: + CompileOperand(ctx, 1); + + os = operand_[0].size; + adr_os = (os == osQWord) ? osQWord : osDWord; + AddVMCommand(ctx, cmPush, otValue, adr_os, 1); + AddVMCommand(ctx, cmPush, otValue, osWord, OperandSizeToValue(os) * 8 - 1); + if (os == osByte || os == osWord) + AddVMCommand(ctx, cmPush, otValue, osWord, 0); + + CompileOperand(ctx, 0); + AddVMCommand(ctx, cmShr, otNone, adr_os, false); + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); + AddVMCommand(ctx, cmPush, otMemory, adr_os, segSS); + AddVMCommand(ctx, (rand() & 1) ? cmNor : cmNand, otNone, adr_os, false); + AddVMCommand(ctx, cmAdd, otNone, adr_os, false); + + switch (os) { + case osByte: + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); + AddVMCommand(ctx, cmPush, otMemory, osWord, segSS); + + AddVMCommand(ctx, cmPush, otValue, osWord, 8); + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); + AddVMCommand(ctx, cmPush, otValue, size_, 2); + AddVMCommand(ctx, cmAdd, otNone, size_, false); + AddVMCommand(ctx, cmPush, otMemory, osWord, segSS); + AddVMCommand(ctx, cmShl, otNone, osWord, false); + + CompileOperand(ctx, 0); + + AddVMCommand(ctx, cmAdd, otNone, osWord, false); + break; + case osWord: + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); + AddVMCommand(ctx, cmPush, otMemory, osWord, segSS); + CompileOperand(ctx, 0); + break; + default: + CompileOperand(ctx, 0); + break; + } + + AddVMCommand(ctx, cmShrd, otNone, adr_os, true); + AddVMCommand(ctx, cmPop, otRegistr, size_, save_flags ? regEFX : regEmpty); + + CompileOperand(ctx, 0, coSaveResult); + + if (os == osByte || os == osWord) + AddVMCommand(ctx, cmPop, otRegistr, osWord, regEmpty); + break; + + case cmRcl: case cmRcr: + AddVMCommand(ctx, cmPush, otValue, osByte, 8); + AddRegistrAndValueSection(ctx, regEFX, osWord, fl_C); + AddVMCommand(ctx, cmShl, otNone, osWord, true); + AddVMCommand(ctx, cmPop, otRegistr, size_, regEmpty); + + os = operand_[0].size; + CompileOperand(ctx, 1); + AddVMCommand(ctx, cmAdd, otNone, osWord, true); + AddVMCommand(ctx, cmPop, otRegistr, size_, regEmpty); + + CompileOperand(ctx, 0); + + AddVMCommand(ctx, type_, otNone, os, true); + AddVMCommand(ctx, cmPop, otRegistr, size_, save_flags ? regEIX : regEmpty); + CompileOperand(ctx, 0, coSaveResult); + + if (save_flags) + AddCombineFlagsSection(ctx, fl_S | fl_Z | fl_A | fl_P); + break; + + case cmCbw: case cmCwde: case cmCwd: case cmCdq: case cmCdqe: case cmCqo: + switch (type_) { + case cmCbw: + os = osByte; + break; + case cmCwde: case cmCwd: + os = osWord; + break; + case cmCdq: case cmCdqe: + os = osDWord; + break; + default: + os = osQWord; + break; + } + AddVMCommand(ctx, cmPush, otValue, os, 1); + + AddVMCommand(ctx, cmPush, otValue, osWord, OperandSizeToValue(os) * 8 - 1); + AddVMCommand(ctx, cmPush, otRegistr, os, regEAX); + AddVMCommand(ctx, cmShr, otNone, os, false); + + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); + AddVMCommand(ctx, cmPush, otMemory, os, segSS); + AddVMCommand(ctx, (rand() & 1) ? cmNor : cmNand, otNone, os, false); + + AddVMCommand(ctx, cmAdd, otNone, os, false); + + switch (type_) { + case cmCbw: + AddVMCommand(ctx, cmPop, otHiPartRegistr, osByte, regEAX); + break; + case cmCwde: + AddVMCommand(ctx, cmPush, otRegistr, osWord, regEAX); + AddVMCommand(ctx, cmPop, otRegistr, osDWord, regEAX); + if (size_ == osQWord) { + AddVMCommand(ctx, cmPush, otValue, osDWord, 0); + AddVMCommand(ctx, cmPop, otHiPartRegistr, osDWord, regEAX); + } + break; + case cmCwd: + AddVMCommand(ctx, cmPop, otRegistr, osWord, regEDX); + break; + case cmCdq: + AddVMCommand(ctx, cmPop, otRegistr, osDWord, regEDX); + if (size_ == osQWord) { + AddVMCommand(ctx, cmPush, otValue, osDWord, 0); + AddVMCommand(ctx, cmPop, otHiPartRegistr, osDWord, regEDX); + } + break; + case cmCdqe: + AddVMCommand(ctx, cmPush, otRegistr, osDWord, regEAX); + AddVMCommand(ctx, cmPop, otRegistr, osQWord, regEAX); + break; + default: + AddVMCommand(ctx, cmPop, otRegistr, osQWord, regEDX); + break; + } + break; + + case cmMovsx: + case cmMovsxd: + if (operand_[1].size == operand_[0].size) { + CompileOperand(ctx, 1); + } else { + AddCorrectOperandSizeSection(ctx, operand_[1].size, operand_[0].size); + CompileOperand(ctx, 1); + + AddVMCommand(ctx, cmPush, otValue, osWord, OperandSizeToValue(operand_[1].size) * 8); + AddVMCommand(ctx, cmPush, otValue, osWord, OperandSizeToValue(operand_[1].size) * 8 - 1); + + os = operand_[0].size; + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); + AddVMCommand(ctx, cmPush, otValue, size_, OperandSizeToValue(osWord) * 2); + AddVMCommand(ctx, cmAdd, otNone, size_, false); + AddVMCommand(ctx, cmPush, otMemory, os, segSS); + + AddVMCommand(ctx, cmShr, otNone, os, false); + + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); + AddVMCommand(ctx, cmPush, otMemory, os, segSS); + AddVMCommand(ctx, (rand() & 1) ? cmNor : cmNand, otNone, os, false); + + AddVMCommand(ctx, cmPush, otValue, os, 1); + AddVMCommand(ctx, cmAdd, otNone, os, false); + + AddVMCommand(ctx, cmShl, otNone, os, false); + + AddVMCommand(ctx, cmAdd, otNone, os, false); + } + + CompileOperand(ctx, 0, coSaveResult); + break; + + case cmMovzx: + AddCorrectOperandSizeSection(ctx, operand_[1].size, operand_[0].size); + CompileOperand(ctx, 1); + CompileOperand(ctx, 0, coSaveResult); + break; + + case cmPushf: + AddVMCommand(ctx, cmPush, otRegistr, operand_[0].size, regEFX); + AddStoreExtRegistrSection(ctx, regESP); + break; + + case cmPopf: + AddVMCommand(ctx, cmPop, otRegistr, operand_[0].size, regEFX); + AddRegistrAndValueSection(ctx, regEFX, size_, ~0x8ff); + AddVMCommand(ctx, cmPopf, otNone, size_, 0); + AddStoreExtRegistrSection(ctx, regESP); + break; + + case cmPusha: + os = operand_[0].size; + + AddVMCommand(ctx, cmPush, otRegistr, os, regEAX); + AddVMCommand(ctx, cmPush, otRegistr, os, regECX); + AddVMCommand(ctx, cmPush, otRegistr, os, regEDX); + AddVMCommand(ctx, cmPush, otRegistr, os, regEBX); + + AddVMCommand(ctx, cmPush, otRegistr, os, regESP); + AddVMCommand(ctx, cmPush, otValue, os, OperandSizeToValue(os) * 4); + AddVMCommand(ctx, cmAdd, otNone, os, false); + + AddVMCommand(ctx, cmPush, otRegistr, os, regEBP); + AddVMCommand(ctx, cmPush, otRegistr, os, regESI); + AddVMCommand(ctx, cmPush, otRegistr, os, regEDI); + AddStoreExtRegistrSection(ctx, regESP); + break; + + case cmPopa: + os = operand_[0].size; + + AddVMCommand(ctx, cmPop, otRegistr, os, regEDI); + AddVMCommand(ctx, cmPop, otRegistr, os, regESI); + AddVMCommand(ctx, cmPop, otRegistr, os, regEBP); + AddVMCommand(ctx, cmPop, otRegistr, os, regEmpty); + AddVMCommand(ctx, cmPop, otRegistr, os, regEBX); + AddVMCommand(ctx, cmPop, otRegistr, os, regEDX); + AddVMCommand(ctx, cmPop, otRegistr, os, regECX); + AddVMCommand(ctx, cmPop, otRegistr, os, regEAX); + AddStoreExtRegistrSection(ctx, regESP); + break; + + case cmLahf: + AddVMCommand(ctx, cmPush, otRegistr, osWord, regEFX); + AddVMCommand(ctx, cmPop, otHiPartRegistr, osByte, regEAX); + break; + + case cmSahf: + flags = fl_C | fl_P | fl_A | fl_Z | fl_S; + + AddVMCommand(ctx, cmPush, otHiPartRegistr, osByte, regEAX); + AddVMCommand(ctx, cmPush, otHiPartRegistr, osByte, regEAX); + AddVMCommand(ctx, cmNor, otNone, osByte, false); + AddVMCommand(ctx, cmPush, otValue, osByte, ~flags); + AddVMCommand(ctx, cmNor, otNone, osByte, false); + + AddRegistrAndValueSection(ctx, regEFX, osWord, ~flags); + AddVMCommand(ctx, cmAdd, otNone, osWord, false); + AddVMCommand(ctx, cmPop, otRegistr, osWord, regEFX); + break; + + case cmXchg: + if ((operand_[0].type | operand_[1].type) & otMemory) { + i = (operand_[0].type & otMemory) ? 0 : 1; + CompileOperand(ctx, 1 - i); + CompileOperand(ctx, i, coAsPointer); + AddVMCommand(ctx, cmXchg, otMemory, operand_[0].size, operand_[i].effective_base_segment(base_segment_)); + CompileOperand(ctx, 1 - i, coSaveResult); + } + else { + operand = &operand_[1]; + if (operand->type == otRegistr && operand->size > osByte && operand->registr == regESP) { + CompileOperand(ctx, 0); + CompileOperand(ctx, 1); + CompileOperand(ctx, 0, coSaveResult); + CompileOperand(ctx, 1, coSaveResult); + } + else { + CompileOperand(ctx, 1); + CompileOperand(ctx, 0); + CompileOperand(ctx, 1, coSaveResult); + CompileOperand(ctx, 0, coSaveResult); + } + } + break; + + case cmFnop: case cmNop: + // do nothing + break; + + case cmClc: + AddRegistrAndValueSection(ctx, regEFX, size_, ~fl_C); + AddVMCommand(ctx, cmPop, otRegistr, size_, regEFX); + break; + + case cmStc: + AddRegistrOrValueSection(ctx, regEFX, size_, fl_C); + AddVMCommand(ctx, cmPop, otRegistr, size_, regEFX); + break; + + case cmCmc: + AddVMCommand(ctx, cmPush, otRegistr, size_, regEFX); + AddVMCommand(ctx, cmPush, otRegistr, size_, regEFX); + AddVMCommand(ctx, cmNor, otNone, size_, false); + + AddVMCommand(ctx, cmPush, otValue, size_, ~fl_C); + AddVMCommand(ctx, cmNor, otNone, size_, false); + + AddVMCommand(ctx, cmPush, otRegistr, size_, regEFX); + AddVMCommand(ctx, cmPush, otValue, size_, fl_C); + AddVMCommand(ctx, cmNor, otNone, size_, false); + + AddVMCommand(ctx, cmNor, otNone, size_, false); + + AddVMCommand(ctx, cmPop, otRegistr, size_, regEFX); + break; + + case cmCld: + AddRegistrAndValueSection(ctx, regEFX, size_, ~fl_D); + AddVMCommand(ctx, cmPop, otRegistr, size_, regEFX); + AddRegistrAndValueSection(ctx, regEFX, size_, ~0x8ff); + AddVMCommand(ctx, cmPopf, otNone, size_, false); + break; + + case cmStd: + AddRegistrOrValueSection(ctx, regEFX, size_, fl_D); + AddVMCommand(ctx, cmPop, otRegistr, size_, regEFX); + AddRegistrAndValueSection(ctx, regEFX, size_, ~0x8ff); + AddVMCommand(ctx, cmPopf, otNone, size_, false); + break; + + case cmBswap: + switch (operand_[0].size) { + case osWord: + AddVMCommand(ctx, cmPush, otValue, osWord, 0); + CompileOperand(ctx, 0, coSaveResult); + break; + case osDWord: + AddVMCommand(ctx, cmPush, otValue, osWord, 8); + CompileOperand(ctx, 0); + AddVMCommand(ctx, cmPop, otRegistr, osWord, regETX); + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); + AddVMCommand(ctx, cmPush, otMemory, osWord, segSS); + AddVMCommand(ctx, cmShl, otNone, osDWord, false); + + AddVMCommand(ctx, cmPush, otValue, osWord, 8); + AddVMCommand(ctx, cmPush, otRegistr, osWord, regETX); + AddVMCommand(ctx, cmPush, otRegistr, osWord, regETX); + AddVMCommand(ctx, cmShl, otNone, osDWord, false); + AddVMCommand(ctx, cmPop, otRegistr, osWord, regEmpty); + + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); + AddVMCommand(ctx, cmPush, otValue, size_, 4); + AddVMCommand(ctx, cmAdd, otNone, size_, false); + AddVMCommand(ctx, cmPush, otMemory, osWord, segSS); + + CompileOperand(ctx, 0, coSaveResult); + + AddVMCommand(ctx, cmPop, otRegistr, osDWord, regEmpty); + break; + case osQWord: + AddVMCommand(ctx, cmPush, otValue, osWord, 8); + CompileOperand(ctx, 0); + AddVMCommand(ctx, cmPop, otRegistr, osDWord, regETX); + AddVMCommand(ctx, cmPop, otRegistr, osDWord, regEmpty); + AddVMCommand(ctx, cmPush, otRegistr, osDWord, regETX); + AddVMCommand(ctx, cmPop, otRegistr, osWord, regEmpty); + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); + AddVMCommand(ctx, cmPush, otMemory, osWord, segSS); + AddVMCommand(ctx, cmShl, otNone, osDWord, false); + + AddVMCommand(ctx, cmPush, otValue, osWord, 8); + AddVMCommand(ctx, cmPush, otRegistr, osWord, regETX); + AddVMCommand(ctx, cmPush, otRegistr, osWord, regETX); + AddVMCommand(ctx, cmShl, otNone, osDWord, false); + AddVMCommand(ctx, cmPop, otRegistr, osWord, regEmpty); + + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); + AddVMCommand(ctx, cmPush, otValue, size_, 4); + AddVMCommand(ctx, cmAdd, otNone, size_, false); + AddVMCommand(ctx, cmPush, otMemory, osWord, segSS); + + AddVMCommand(ctx, cmPush, otValue, osWord, 8); + CompileOperand(ctx, 0); + AddVMCommand(ctx, cmPop, otRegistr, osDWord, regEmpty); + AddVMCommand(ctx, cmPop, otRegistr, osWord, regETX); + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); + AddVMCommand(ctx, cmPush, otMemory, osWord, segSS); + AddVMCommand(ctx, cmShl, otNone, osDWord, false); + + AddVMCommand(ctx, cmPush, otValue, osWord, 8); + AddVMCommand(ctx, cmPush, otRegistr, osWord, regETX); + AddVMCommand(ctx, cmPush, otRegistr, osWord, regETX); + AddVMCommand(ctx, cmShl, otNone, osDWord, false); + AddVMCommand(ctx, cmPop, otRegistr, osWord, regEmpty); + + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); + AddVMCommand(ctx, cmPush, otValue, size_, 4); + AddVMCommand(ctx, cmAdd, otNone, size_, false); + AddVMCommand(ctx, cmPush, otMemory, osWord, segSS); + + AddVMCommand(ctx, cmPop, otRegistr, osDWord, regETX); + AddVMCommand(ctx, cmPop, otRegistr, osDWord, regEmpty); + AddVMCommand(ctx, cmPush, otRegistr, osDWord, regETX); + CompileOperand(ctx, 0, coSaveResult); + AddVMCommand(ctx, cmPop, otRegistr, osDWord, regEmpty); + break; + } + break; + + case cmFstsw: + operand = &operand_[0]; + if (operand->type == (otMemory | otBaseRegistr) && operand->base_registr == regESP) { + AddVMCommand(ctx, cmFstsw, otNone, osWord, 0); + } else { + AddVMCommand(ctx, cmPush, otRegistr, osWord, regEmpty); + AddVMCommand(ctx, cmFstsw, otNone, osWord, 0); + CompileOperand(ctx, 0, coSaveResult); + } + break; + + case cmFldcw: + operand = &operand_[0]; + if (operand->type == (otMemory | otBaseRegistr) && operand->base_registr == regESP) { + AddVMCommand(ctx, cmFldcw, otNone, osWord, 0); + } else { + CompileOperand(ctx, 0); + AddVMCommand(ctx, cmFldcw, otNone, osWord, 0); + AddVMCommand(ctx, cmPop, otRegistr, osWord, regEmpty); + } + break; + + case cmFstcw: + operand = &operand_[0]; + if (operand->type == (otMemory | otBaseRegistr) && operand->base_registr == regESP) { + AddVMCommand(ctx, cmFstcw, otNone, osWord, 0); + } else { + AddVMCommand(ctx, cmPush, otRegistr, osWord, regEmpty); + AddVMCommand(ctx, cmFstcw, otNone, osWord, 0); + CompileOperand(ctx, 0, coSaveResult); + } + break; + + case cmImul: case cmMul: + os = operand_[0].size; + + if (operand_[2].type != otNone) { + CompileOperand(ctx, 2); + CompileOperand(ctx, 1); + } else if (operand_[1].type != otNone) { + CompileOperand(ctx, 1); + CompileOperand(ctx, 0); + } else { + CompileOperand(ctx, 0); + AddVMCommand(ctx, cmPush, otRegistr, os, regEAX); + } + + AddVMCommand(ctx, type_, otNone, os, true); + AddVMCommand(ctx, cmPop, otRegistr, size_, save_flags ? regEIX : regEmpty); + + if (operand_[1].type != otNone) { + if (os > osByte) + AddVMCommand(ctx, cmPop, otRegistr, os, regEmpty); + CompileOperand(ctx, 0, coSaveResult); + } else if (os == osByte) { + AddVMCommand(ctx, cmPop, otRegistr, osWord, regEAX); + } else { + AddVMCommand(ctx, cmPop, otRegistr, os, regEDX); + AddVMCommand(ctx, cmPop, otRegistr, os, regEAX); + if (size_ == osQWord && os == osDWord) { + AddVMCommand(ctx, cmPush, otValue, osDWord, 0); + AddVMCommand(ctx, cmPop, otHiPartRegistr, osDWord, regEAX); + AddVMCommand(ctx, cmPush, otValue, osDWord, 0); + AddVMCommand(ctx, cmPop, otHiPartRegistr, osDWord, regEDX); + } + } + + if (save_flags) + AddCombineFlagsSection(ctx, fl_S | fl_Z | fl_A | fl_P); + break; + + case cmDiv: case cmIdiv: + os = operand_[0].size; + + CompileOperand(ctx, 0); + if (os == osByte) { + AddVMCommand(ctx, cmPush, otRegistr, osWord, regEAX); + } else { + AddVMCommand(ctx, cmPush, otRegistr, os, regEAX); + AddVMCommand(ctx, cmPush, otRegistr, os, regEDX); + } + + AddVMCommand(ctx, type_, otNone, os, true); + AddVMCommand(ctx, cmPop, otRegistr, size_, save_flags ? regEFX : regEmpty); + + if (os == osByte) { + AddVMCommand(ctx, cmPop, otRegistr, osWord, regEAX); + } else { + AddVMCommand(ctx, cmPop, otRegistr, os, regEDX); + AddVMCommand(ctx, cmPop, otRegistr, os, regEAX); + } + + if (size_ == osQWord && os == osDWord) { + AddVMCommand(ctx, cmPush, otValue, osDWord, 0); + AddVMCommand(ctx, cmPop, otHiPartRegistr, osDWord, regEAX); + AddVMCommand(ctx, cmPush, otValue, osDWord, 0); + AddVMCommand(ctx, cmPop, otHiPartRegistr, osDWord, regEDX); + } + break; + + case cmJmpWithFlag: case cmJCXZ: case cmLoop: case cmLoope: case cmLoopne: + AddJmpWithFlagSection(ctx, type_); + if (section_options_ & rtLinkedNext) { + AddBeginSection(ctx, voLinkCommand | voUseEndSectionCryptor); + AddVMCommand(ctx, cmPush, otValue, size_, 0, voLinkCommand | voFixup); + AddEndSection(ctx, cmJmp, 0, voUseEndSectionCryptor); + } else { + AddBeginSection(ctx, voLinkCommand | voUseEndSectionCryptor); + AddVMCommand(ctx, cmPush, otValue, size_, address() + original_dump_size(), voFixup); + AddEndSection(ctx, cmRet); + } + if (section_options_ & rtLinkedFrom) { + AddBeginSection(ctx, voLinkCommand | voUseEndSectionCryptor); + AddVMCommand(ctx, cmPush, otValue, size_, 0, voLinkCommand | voFixup); + AddEndSection(ctx, cmJmp, 0, voUseEndSectionCryptor); + } else { + AddBeginSection(ctx, voLinkCommand | voUseEndSectionCryptor); + AddCorrectOperandSizeSection(ctx, operand_[0].size, size_); + CompileOperand(ctx, 0, coFixup); + AddEndSection(ctx, cmRet); + } + break; + + case cmJmp: + CompileOperand(ctx, 1, coAsPointer); + + operand = &operand_[0]; + if ((options() & roFar) && (operand->type & otMemory)) { + CompileOperand(ctx, 0, coAsPointer); + AddVMCommand(ctx, cmPop, otRegistr, size_, regETX); + + AddVMCommand(ctx, cmPush, otValue, size_, OperandSizeToValue(size_)); + AddVMCommand(ctx, cmPush, otRegistr, size_, regETX); + AddVMCommand(ctx, cmAdd, otNone, size_, false); + AddVMCommand(ctx, cmPush, otMemory, size_, operand->effective_base_segment(base_segment_)); + + AddVMCommand(ctx, cmPush, otRegistr, size_, regETX); + AddVMCommand(ctx, cmPush, otMemory, size_, operand->effective_base_segment(base_segment_)); + } else { + AddCorrectOperandSizeSection(ctx, operand->size, size_); + CompileOperand(ctx, 0, ((options() & roFar) || operand->type != otValue) ? 0 : coFixup); + } + + if (section_options_ & rtLinkedFrom) { + AddEndSection(ctx, cmJmp, (options() & roExternal) ? 0xff : 0, voUseEndSectionCryptor); + } else { + AddEndSection(ctx, cmRet, (options() & roFar) != 0); + } + break; + + case cmCall: + if ((options() & roInternal) && (section_options_ & rtLinkedFrom) == 0) { + uint8_t arg_count = static_cast(operand_[2].value); + switch (ctx.file->calling_convention()) { + case ccMSx64: + if (arg_count > 3) + AddVMCommand(ctx, cmPush, otRegistr, size_, regR9); + if (arg_count > 2) + AddVMCommand(ctx, cmPush, otRegistr, size_, regR8); + if (arg_count > 1) + AddVMCommand(ctx, cmPush, otRegistr, size_, regEDX); + if (arg_count > 0) + AddVMCommand(ctx, cmPush, otRegistr, size_, regECX); + break; + case ccABIx64: + if (arg_count > 5) + AddVMCommand(ctx, cmPush, otRegistr, size_, regR9); + if (arg_count > 4) + AddVMCommand(ctx, cmPush, otRegistr, size_, regR8); + if (arg_count > 3) + AddVMCommand(ctx, cmPush, otRegistr, size_, regECX); + if (arg_count > 2) + AddVMCommand(ctx, cmPush, otRegistr, size_, regEDX); + if (arg_count > 1) + AddVMCommand(ctx, cmPush, otRegistr, size_, regESI); + if (arg_count > 0) + AddVMCommand(ctx, cmPush, otRegistr, size_, regEDI); + break; + } + } else { + if (options() & roFar) { + AddCorrectOperandSizeSection(ctx, osWord, size_); + AddVMCommand(ctx, cmPush, otSegmentRegistr, osWord, segCS); + } + AddVMCommand(ctx, cmPush, otValue, size_, 0, voLinkCommand | voFixup); + CompileOperand(ctx, 1, coAsPointer); + } + + operand = &operand_[0]; + if ((options() & roFar) && (operand->type & otMemory)) { + CompileOperand(ctx, 0, coAsPointer); + AddVMCommand(ctx, cmPop, otRegistr, size_, regETX); + + AddVMCommand(ctx, cmPush, otValue, size_, OperandSizeToValue(size_)); + AddVMCommand(ctx, cmPush, otRegistr, size_, regETX); + AddVMCommand(ctx, cmAdd, otNone, size_, false); + AddVMCommand(ctx, cmPush, otMemory, size_, operand->effective_base_segment(base_segment_)); + + AddVMCommand(ctx, cmPush, otRegistr, size_, regETX); + AddVMCommand(ctx, cmPush, otMemory, size_, operand->effective_base_segment(base_segment_)); + } else { + AddCorrectOperandSizeSection(ctx, operand->size, size_); + CompileOperand(ctx, 0, ((options() & roFar) || operand->type != otValue) ? 0 : coFixup); + } + + if (section_options_ & rtLinkedFrom) { + AddStoreExtRegistersSection(ctx); + AddEndSection(ctx, cmJmp, (options() & roExternal) ? 0xff : 0, voUseEndSectionCryptor); + } else if (options() & roInternal) { + if (ctx.options.flags & cpCheckDebugger) + AddCheckBreakpointSection(ctx, size_); + if (ctx.options.flags & cpMemoryProtection) + AddCheckCRCSection(ctx, size_); + AddVMCommand(ctx, cmCall, otNone, size_, operand_[2].value); + AddVMCommand(ctx, cmPop, otRegistr, size_, regEAX); + } else { + AddEndSection(ctx, cmRet, (options() & roFar) != 0); + } + break; + + case cmSyscall: + { + uint8_t arg_count = static_cast(operand_[2].value); + switch (ctx.file->calling_convention()) { + case ccMSx64: + if (arg_count > 3) + AddVMCommand(ctx, cmPush, otRegistr, size_, regR9); + if (arg_count > 2) + AddVMCommand(ctx, cmPush, otRegistr, size_, regR8); + if (arg_count > 1) + AddVMCommand(ctx, cmPush, otRegistr, size_, regEDX); + if (arg_count > 0) + AddVMCommand(ctx, cmPush, otRegistr, size_, regECX); + break; + } + } + CompileOperand(ctx, 0); + AddVMCommand(ctx, cmSyscall, otNone, size_, operand_[2].value); + AddVMCommand(ctx, cmPop, otRegistr, size_, regEAX); + break; + + case cmCmov: + AddJmpWithFlagSection(ctx, cmJmpWithFlag); + AddBeginSection(ctx, voLinkCommand | voUseEndSectionCryptor); + CompileOperand(ctx, 1); + CompileOperand(ctx, 0, coSaveResult); + + if (section_options_ & rtLinkedNext) { + AddVMCommand(ctx, cmPush, otValue, size_, 0, voLinkCommand | voFixup); + AddEndSection(ctx, cmJmp, 0, voUseEndSectionCryptor); + + AddBeginSection(ctx, voLinkCommand | voUseEndSectionCryptor); + AddVMCommand(ctx, cmPush, otValue, size_, 0, voLinkCommand | voFixup); + AddEndSection(ctx, cmJmp, 0, voUseEndSectionCryptor); + } else { + AddVMCommand(ctx, cmPush, otValue, size_, address() + original_dump_size(), voFixup); + AddEndSection(ctx, cmRet); + + AddBeginSection(ctx, voLinkCommand | voUseEndSectionCryptor); + AddVMCommand(ctx, cmPush, otValue, size_, address() + original_dump_size(), voFixup); + AddEndSection(ctx, cmRet); + } + break; + + case cmLods: case cmStos: case cmScas: case cmMovs: case cmCmps: case cmIns: case cmOuts: + os = operand_[0].size; + adr_os = operand_[1].size; + value = OperandSizeToValue(os); + + if (preffix_command_ == cmRep || preffix_command_ == cmRepe || preffix_command_ == cmRepne) { + if ((section_options_ & rtBeginSection) == 0) + AddBeginSection(ctx, voUseBeginSectionCryptor); + AddJmpWithFlagSection(ctx, cmJCXZ); + AddBeginSection(ctx, voLinkCommand | voUseEndSectionCryptor); + } + + switch (type_) { + case cmLods: + AddCorrectOperandSizeSection(ctx, adr_os, size_); + AddVMCommand(ctx, cmPush, otRegistr, adr_os, regESI); + AddVMCommand(ctx, cmPush, otMemory, os, base_segment_ == segDefault ? segDS : base_segment_); + + AddVMCommand(ctx, cmPop, otRegistr, os, regEAX); + if (size_ == osQWord && os == osDWord) { + AddVMCommand(ctx, cmPush, otValue, osDWord, 0); + AddVMCommand(ctx, cmPop, otHiPartRegistr, osDWord, regEAX); + } + break; + + case cmStos: + AddCorrectOperandSizeSection(ctx, adr_os, size_); + AddVMCommand(ctx, cmPush, otRegistr, os, regEAX); + AddVMCommand(ctx, cmPush, otRegistr, adr_os, regEDI); + AddVMCommand(ctx, cmPop, otMemory, os, segES); + break; + + case cmMovs: + AddCorrectOperandSizeSection(ctx, adr_os, size_); + AddVMCommand(ctx, cmPush, otRegistr, adr_os, regESI); + AddVMCommand(ctx, cmPush, otMemory, os, base_segment_ == segDefault ? segDS : base_segment_); + + AddCorrectOperandSizeSection(ctx, adr_os, size_); + AddVMCommand(ctx, cmPush, otRegistr, adr_os, regEDI); + AddVMCommand(ctx, cmPop, otMemory, os, segES); + break; + + case cmScas: + AddCorrectOperandSizeSection(ctx, adr_os, size_); + AddVMCommand(ctx, cmPush, otRegistr, adr_os, regEDI); + AddVMCommand(ctx, cmPush, otMemory, os, segES); + + AddVMCommand(ctx, cmPush, otRegistr, os, regEAX); + AddVMCommand(ctx, cmPush, otRegistr, os, regEAX); + AddVMCommand(ctx, cmNor, otNone, os, false); + + AddVMCommand(ctx, cmAdd, otNone, os, true); + AddVMCommand(ctx, cmPop, otRegistr, size_, regEFX); + + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); + AddVMCommand(ctx, cmPush, otMemory, os, segSS); + AddVMCommand(ctx, cmNor, otNone, os, true); + AddVMCommand(ctx, cmPop, otRegistr, size_, regEIX); + + AddVMCommand(ctx, cmPop, otRegistr, os, regEmpty); + + AddCombineFlagsSection(ctx, fl_P | fl_O | fl_A | fl_C); + break; + + case cmCmps: + AddCorrectOperandSizeSection(ctx, adr_os, size_); + AddVMCommand(ctx, cmPush, otRegistr, adr_os, regESI); + AddVMCommand(ctx, cmPush, otMemory, os, base_segment_ == segDefault ? segDS : base_segment_); + + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); + AddVMCommand(ctx, cmPush, otMemory, os, segSS); + AddVMCommand(ctx, cmNor, otNone, os, false); + + AddCorrectOperandSizeSection(ctx, adr_os, size_); + AddVMCommand(ctx, cmPush, otRegistr, adr_os, regEDI); + AddVMCommand(ctx, cmPush, otMemory, os, segES); + + AddVMCommand(ctx, cmAdd, otNone, os, true); + AddVMCommand(ctx, cmPop, otRegistr, size_, regEFX); + + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); + AddVMCommand(ctx, cmPush, otMemory, os, segSS); + AddVMCommand(ctx, cmNor, otNone, os, true); + AddVMCommand(ctx, cmPop, otRegistr, size_, regEIX); + + AddVMCommand(ctx, cmPop, otRegistr, os, regEmpty); + + AddCombineFlagsSection(ctx, fl_P | fl_O | fl_A | fl_C); + break; + + case cmIns: + AddCorrectOperandSizeSection(ctx, adr_os, size_); + + AddVMCommand(ctx, cmPush, otRegistr, osWord, regEDX); + AddVMCommand(ctx, cmIn, otNone, os, 0); + + AddVMCommand(ctx, cmPush, otRegistr, adr_os, regEDI); + AddVMCommand(ctx, cmPop, otMemory, os, segES); + break; + + case cmOuts: + AddCorrectOperandSizeSection(ctx, adr_os, size_); + + AddVMCommand(ctx, cmPush, otRegistr, adr_os, regESI); + AddVMCommand(ctx, cmPush, otMemory, os, base_segment_ == segDefault ? segDS : base_segment_); + + AddVMCommand(ctx, cmPush, otRegistr, osWord, regEDX); + AddVMCommand(ctx, cmOut, otNone, os, 0); + break; + } + + AddExtractFlagSection(ctx, fl_D, true, (uint8_t)(value << 1)); + + if (adr_os != size_) { + AddVMCommand(ctx, cmPop, otRegistr, size_, regETX); + AddVMCommand(ctx, cmPush, otRegistr, adr_os, regETX); + } + AddVMCommand(ctx, cmPush, otValue, adr_os, 0 - value); + AddVMCommand(ctx, cmAdd, otNone, adr_os, false); + + switch (type_) { + case cmLods: case cmOuts: + AddVMCommand(ctx, cmPush, otRegistr, adr_os, regESI); + AddVMCommand(ctx, cmAdd, otNone, adr_os, false); + AddVMCommand(ctx, cmPop, otRegistr, adr_os, regESI); + break; + + case cmStos: case cmScas: case cmIns: + AddVMCommand(ctx, cmPush, otRegistr, adr_os, regEDI); + AddVMCommand(ctx, cmAdd, otNone, adr_os, false); + AddVMCommand(ctx, cmPop, otRegistr, adr_os, regEDI); + break; + + case cmMovs: case cmCmps: + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); + AddVMCommand(ctx, cmPush, otMemory, adr_os, segSS); + + AddVMCommand(ctx, cmPush, otRegistr, adr_os, regESI); + AddVMCommand(ctx, cmAdd, otNone, adr_os, false); + AddVMCommand(ctx, cmPop, otRegistr, adr_os, regESI); + + AddVMCommand(ctx, cmPush, otRegistr, adr_os, regEDI); + AddVMCommand(ctx, cmAdd, otNone, adr_os, false); + AddVMCommand(ctx, cmPop, otRegistr, adr_os, regEDI); + break; + } + + if (preffix_command_ == cmRep || preffix_command_ == cmRepe || preffix_command_ == cmRepne) { + AddJmpWithFlagSection(ctx, (type_ == cmScas || type_ == cmCmps) ? preffix_command_ : cmRep); + if ((section_options_ & rtLinkedNext) == 0) { + AddBeginSection(ctx, voLinkCommand | voUseEndSectionCryptor); + AddVMCommand(ctx, cmPush, otValue, size_, address() + original_dump_size(), voFixup); + AddEndSection(ctx, cmRet); + } + } + break; + + case cmRet: + operand = &operand_[0]; + if (operand->type == otValue) { + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); + AddVMCommand(ctx, cmPush, otMemory, size_, segSS); + + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); + AddVMCommand(ctx, cmPush, otValue, size_, operand->value + OperandSizeToStack(size_)); + AddVMCommand(ctx, cmAdd, otNone, size_, false); + AddVMCommand(ctx, cmPop, otMemory, size_, segSS); + + if (options() & roFar) { + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); + AddVMCommand(ctx, cmPush, otValue, size_, OperandSizeToStack(size_)); + AddVMCommand(ctx, cmAdd, otNone, size_, false); + AddVMCommand(ctx, cmPush, otMemory, size_, segSS); + + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); + AddVMCommand(ctx, cmPush, otValue, size_, operand->value + OperandSizeToStack(size_) * 2); + AddVMCommand(ctx, cmAdd, otNone, size_, false); + AddVMCommand(ctx, cmPop, otMemory, size_, segSS); + } + + switch (operand->value) { + case 2: + AddVMCommand(ctx, cmPop, otRegistr, osWord, regEmpty); + break; + case 4: + AddVMCommand(ctx, cmPop, otRegistr, osDWord, regEmpty); + break; + case 8: + AddVMCommand(ctx, cmPop, otRegistr, osDWord, regEmpty); + AddVMCommand(ctx, cmPop, otRegistr, osDWord, regEmpty); + break; + case 10: + AddVMCommand(ctx, cmPop, otRegistr, osWord, regEmpty); + AddVMCommand(ctx, cmPop, otRegistr, osDWord, regEmpty); + AddVMCommand(ctx, cmPop, otRegistr, osDWord, regEmpty); + break; + case 12: + AddVMCommand(ctx, cmPop, otRegistr, osDWord, regEmpty); + AddVMCommand(ctx, cmPop, otRegistr, osDWord, regEmpty); + AddVMCommand(ctx, cmPop, otRegistr, osDWord, regEmpty); + break; + default: + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); + AddVMCommand(ctx, cmPush, otValue, size_, operand->value); + AddVMCommand(ctx, cmAdd, otNone, size_, false); + AddVMCommand(ctx, cmPop, otRegistr, size_, regESP); + break; + } + } + if (options() & roInternal) { + AddEndSection(ctx, cmJmp, 0); + } else { + AddEndSection(ctx, cmRet, (options() & roFar) ? 1 : 0); + } + break; + + case cmIret: + AddEndSection(ctx, cmIret); + break; + + case cmLeave: + AddVMCommand(ctx, cmPush, otRegistr, size_, regEBP); + AddVMCommand(ctx, cmPop, otRegistr, size_, regESP); + AddVMCommand(ctx, cmPop, otRegistr, size_, regEBP); + break; + + case cmLes: case cmLds: case cmLfs: case cmLgs: + os = operand_[0].size; + CompileOperand(ctx, 1, coAsPointer); + + AddVMCommand(ctx, cmPush, otRegistr, osDWord, regESP); + AddVMCommand(ctx, cmPush, otMemory, osDWord, segSS); + AddVMCommand(ctx, cmPush, otValue, osDWord, OperandSizeToStack(os)); + AddVMCommand(ctx, cmAdd, otNone, osDWord, false); + + AddVMCommand(ctx, cmPush, otMemory, osWord, operand_[1].effective_base_segment(base_segment_)); + + switch (type_) { + case cmLes: + AddVMCommand(ctx, cmPop, otSegmentRegistr, osWord, segES); + break; + case cmLds: + AddVMCommand(ctx, cmPop, otSegmentRegistr, osWord, segDS); + break; + case cmLfs: + AddVMCommand(ctx, cmPop, otSegmentRegistr, osWord, segFS); + break; + case cmLgs: + AddVMCommand(ctx, cmPop, otSegmentRegistr, osWord, segGS); + break; + } + + AddVMCommand(ctx, cmPush, otMemory, os, operand_[1].effective_base_segment(base_segment_)); + CompileOperand(ctx, 0, coSaveResult); + break; + + case cmRdtsc: + AddVMCommand(ctx, cmRdtsc, otNone, size_, 0); + AddVMCommand(ctx, cmPop, otRegistr, osDWord, regEDX); + AddVMCommand(ctx, cmPop, otRegistr, osDWord, regEAX); + + if (size_ == osQWord) { + AddVMCommand(ctx, cmPush, otValue, osDWord, 0); + AddVMCommand(ctx, cmPop, otHiPartRegistr, osDWord, regEAX); + AddVMCommand(ctx, cmPush, otValue, osDWord, 0); + AddVMCommand(ctx, cmPop, otHiPartRegistr, osDWord, regEDX); + } + break; + + case cmCpuid: + AddVMCommand(ctx, cmPush, otRegistr, osDWord, regEAX); + AddVMCommand(ctx, cmCpuid, otNone, size_, 0); + AddVMCommand(ctx, cmPop, otRegistr, osDWord, regEDX); + AddVMCommand(ctx, cmPop, otRegistr, osDWord, regECX); + AddVMCommand(ctx, cmPop, otRegistr, osDWord, regEBX); + AddVMCommand(ctx, cmPop, otRegistr, osDWord, regEAX); + + if (size_ == osQWord) { + AddVMCommand(ctx, cmPush, otValue, osDWord, 0); + AddVMCommand(ctx, cmPop, otHiPartRegistr, osDWord, regEAX); + AddVMCommand(ctx, cmPush, otValue, osDWord, 0); + AddVMCommand(ctx, cmPop, otHiPartRegistr, osDWord, regEBX); + AddVMCommand(ctx, cmPush, otValue, osDWord, 0); + AddVMCommand(ctx, cmPop, otHiPartRegistr, osDWord, regECX); + AddVMCommand(ctx, cmPush, otValue, osDWord, 0); + AddVMCommand(ctx, cmPop, otHiPartRegistr, osDWord, regEDX); + } + break; + + case cmF2xm1: case cmFabs: case cmFclex: case cmFcos: case cmFdecstp: case cmFincstp: + case cmFinit: case cmFldln2: case cmFldlg2: case cmFprem: case cmFprem1: case cmFptan: + case cmFrndint: case cmFsin: case cmFtst: case cmFyl2x: case cmFpatan: case cmFldz: case cmFld1: + case cmFldpi: case cmWait: case cmFchs: case cmFsqrt: + AddVMCommand(ctx, type_, otNone, size_, 0); + break; + + case cmFistp: case cmFist: case cmFstp: case cmFst: + os = operand_[0].size; + operand = &operand_[0]; + + if (operand->type == (otMemory | otBaseRegistr) && operand->base_registr == regESP) { + AddVMCommand(ctx, type_, otNone, os, 0); + } else { + switch (os) { + case osWord: + AddVMCommand(ctx, cmPush, otRegistr, osWord, regEmpty); + break; + case osDWord: + AddVMCommand(ctx, cmPush, otRegistr, osDWord, regEmpty); + break; + case osQWord: + if (size_ == osQWord) { + AddVMCommand(ctx, cmPush, otRegistr, osQWord, regEmpty); + } else { + AddVMCommand(ctx, cmPush, otRegistr, osDWord, regEmpty); + AddVMCommand(ctx, cmPush, otRegistr, osDWord, regEmpty); + } + break; + case osTByte: + if (size_ == osQWord) { + AddVMCommand(ctx, cmPush, otRegistr, osQWord, regEmpty); + } else { + AddVMCommand(ctx, cmPush, otRegistr, osDWord, regEmpty); + AddVMCommand(ctx, cmPush, otRegistr, osDWord, regEmpty); + } + AddVMCommand(ctx, cmPush, otRegistr, osWord, regEmpty); + break; + } + + AddVMCommand(ctx, type_, otNone, os, 0); + CompileOperand(ctx, 0, coAsPointer); + + IntelSegment base_segment = operand->effective_base_segment(base_segment_); + switch (os) { + case osWord: + AddVMCommand(ctx, cmPop, otMemory, osWord, base_segment); + break; + case osDWord: + AddVMCommand(ctx, cmPop, otMemory, osDWord, base_segment); + break; + case osQWord: + if (size_ == osQWord) { + AddVMCommand(ctx, cmPop, otMemory, osQWord, base_segment); + } else { + AddVMCommand(ctx, cmPop, otMemory, osDWord, base_segment); + CompileOperand(ctx, 0, coAsPointer); + AddVMCommand(ctx, cmPush, otValue, size_, OperandSizeToValue(osDWord)); + AddVMCommand(ctx, cmAdd, otNone, size_, false); + AddVMCommand(ctx, cmPop, otMemory, osDWord, base_segment); + } + break; + case osTByte: + if (size_ == osQWord) { + AddVMCommand(ctx, cmPop, otMemory, osQWord, base_segment); + } else { + AddVMCommand(ctx, cmPop, otMemory, osDWord, base_segment); + CompileOperand(ctx, 0, coAsPointer); + AddVMCommand(ctx, cmPush, otValue, size_, OperandSizeToValue(osDWord)); + AddVMCommand(ctx, cmAdd, otNone, size_, false); + AddVMCommand(ctx, cmPop, otMemory, osDWord, base_segment); + } + CompileOperand(ctx, 0, coAsPointer); + AddVMCommand(ctx, cmPush, otValue, size_, OperandSizeToValue(osQWord)); + AddVMCommand(ctx, cmAdd, otNone, size_, false); + AddVMCommand(ctx, cmPop, otMemory, osWord, base_segment); + break; + } + } + break; + + case cmFadd: case cmFsub: case cmFisub: case cmFsubr: case cmFdiv: case cmFmul: case cmFcomp: + case cmFild: case cmFld: + os = operand_[0].size; + operand = &operand_[0]; + + if (operand->type == (otMemory | otBaseRegistr) && operand->base_registr == regESP) { + AddVMCommand(ctx, type_, otNone, os, 0); + } else { + CompileOperand(ctx, 0, coAsPointer); + + IntelSegment base_segment = operand->effective_base_segment(base_segment_); + switch (os) { + case osWord: + AddVMCommand(ctx, cmPush, otMemory, osWord, base_segment); + break; + case osDWord: + AddVMCommand(ctx, cmPush, otMemory, osDWord, base_segment); + break; + case osQWord: + if (size_ == osQWord) { + AddVMCommand(ctx, cmPush, otMemory, osQWord, base_segment); + } else { + AddVMCommand(ctx, cmPush, otValue, size_, OperandSizeToValue(osDWord)); + AddVMCommand(ctx, cmAdd, otNone, size_, false); + AddVMCommand(ctx, cmPush, otMemory, osDWord, base_segment); + CompileOperand(ctx, 0, coAsPointer); + AddVMCommand(ctx, cmPush, otMemory, osDWord, base_segment); + } + break; + case osTByte: + AddVMCommand(ctx, cmPush, otValue, size_, OperandSizeToValue(osQWord)); + AddVMCommand(ctx, cmAdd, otNone, size_, false); + AddVMCommand(ctx, cmPush, otMemory, osWord, base_segment); + CompileOperand(ctx, 0, coAsPointer); + if (size_ == osQWord) { + AddVMCommand(ctx, cmPush, otMemory, osQWord, base_segment); + } else { + AddVMCommand(ctx, cmPush, otValue, size_, OperandSizeToValue(osDWord)); + AddVMCommand(ctx, cmAdd, otNone, size_, false); + AddVMCommand(ctx, cmPush, otMemory, osDWord, base_segment); + CompileOperand(ctx, 0, coAsPointer); + AddVMCommand(ctx, cmPush, otMemory, osDWord, base_segment); + } + break; + } + + AddVMCommand(ctx, type_, otNone, os, 0); + + switch (os) { + case osWord: + AddVMCommand(ctx, cmPop, otRegistr, osWord, regEmpty); + break; + case osDWord: + AddVMCommand(ctx, cmPop, otRegistr, osDWord, regEmpty); + break; + case osQWord: + if (size_ == osQWord) { + AddVMCommand(ctx, cmPop, otRegistr, osQWord, regEmpty); + } else { + AddVMCommand(ctx, cmPop, otRegistr, osDWord, regEmpty); + AddVMCommand(ctx, cmPop, otRegistr, osDWord, regEmpty); + } + break; + case osTByte: + if (size_ == osQWord) { + AddVMCommand(ctx, cmPop, otRegistr, osQWord, regEmpty); + } else { + AddVMCommand(ctx, cmPop, otRegistr, osDWord, regEmpty); + AddVMCommand(ctx, cmPop, otRegistr, osDWord, regEmpty); + } + AddVMCommand(ctx, cmPop, otRegistr, osWord, regEmpty); + break; + } + } + break; + + case cmCrc: + switch (ctx.file->calling_convention()) { //-V719 + case ccStdcall: + // do nothing + break; + case ccCdecl: + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); //-V760 + AddVMCommand(ctx, cmPush, otValue, size_, OperandSizeToStack(size_)); + AddVMCommand(ctx, cmAdd, otNone, size_, false); + AddVMCommand(ctx, cmPush, otMemory, size_, segSS); + + AddVMCommand(ctx, cmPush, otRegistr, size_, regESP); + AddVMCommand(ctx, cmPush, otValue, size_, OperandSizeToStack(size_)); + AddVMCommand(ctx, cmAdd, otNone, size_, false); + AddVMCommand(ctx, cmPush, otMemory, size_, segSS); + break; + case ccMSx64: + AddVMCommand(ctx, cmPush, otRegistr, size_, regEDX); + AddVMCommand(ctx, cmPush, otRegistr, size_, regECX); + break; + case ccABIx64: + AddVMCommand(ctx, cmPush, otRegistr, size_, regESI); + AddVMCommand(ctx, cmPush, otRegistr, size_, regEDI); + break; + } + AddVMCommand(ctx, cmCrc, otNone, size_, 0); + AddVMCommand(ctx, cmPop, otRegistr, osDWord, regEAX); + break; + + case cmDD: case cmDQ: + operand = &operand_[0]; + AddVMCommand(ctx, type_, otValue, (type_ == cmDD) ? osDWord : osQWord, operand->value, voLinkCommand | (operand->fixup ? voFixup : voNone), operand->fixup); + break; + + default: + throw std::runtime_error("Runtime error at CompileToVM: " + text()); + break; + } + + GetCommandInfo(*vm_command_info_list_); + for (i = vm_command_info_list_->count(); i > 0 ; i--) { + CommandInfo *command_info = vm_command_info_list_->item(i - 1); + if ((command_info->operand_type() == otRegistr || command_info->operand_type() == otHiPartRegistr) && command_info->value() == regEFX) + delete command_info; + } + for (i = 0; i < count(); i++) { + IntelVMCommand *command = item(i); + if (command->options() & voSectionCommand) { + if (section_options() & rtBeginSection) + continue; + if (section_options() & rtEndSection) + break; + } + + switch (command->command_type()) { + case cmPush: case cmPop: + if ((command->operand_type() == otRegistr || command->operand_type() == otHiPartRegistr) && + (command->registr() == regEFX || command->registr() == regETX || command->registr() == regEIX || (command->registr() & regExtended))) + vm_command_info_list_->Add(command->command_type() == cmPush ? atRead : atWrite, command->registr(), command->operand_type(), command->size()); + break; + case cmCall: + vm_command_info_list_->Add(atWrite, regEAX, otRegistr, size()); + break; + case cmCrc: + vm_command_info_list_->Add(atRead, regESP, otRegistr, size()); + vm_command_info_list_->Add(atWrite, regESP, otRegistr, size()); + vm_command_info_list_->Add(atWrite, regEAX, otRegistr, size()); + break; + } + } +} + +void IntelCommand::PrepareLink(const CompileContext &ctx) +{ + bool from_native = block() && (block()->type() & mtExecutable) ? true : owner()->compilation_type() == ctMutation; + + IntelCommand *to_command = reinterpret_cast(link()->to_command()); + if (to_command) { + if (link()->operand_index() > -1) { + IntelOperand *operand = &operand_[link()->operand_index()]; + if (size_ == osQWord && link()->sub_value() > ctx.file->image_base()) { + if (link()->operand_index() == 1 && (operand->type & otMemory) && operand_[0].size == osDWord && type_ != cmMovsxd) { + if (type_ == cmMov) { + type_ = cmMovsxd; + operand_[0].size = osQWord; + CompileToNative(); + } else { + throw std::runtime_error("Runtime error at PrepareLink: " + text()); + } + } + } + if (operand->type & otMemory) { + if ((operand->type & otValue) == 0) { + operand->type |= otValue; + operand->value = 0; + operand->value_size = osDWord; + CompileToNative(); + } else if (operand->value_size < osDWord) { + operand->value_size = osDWord; + CompileToNative(); + } + } + + if ((operand->type & otValue) == 0) + throw std::runtime_error("Runtime error at PrepareLink: " + text()); + } + + bool to_native = to_command->block() && (to_command->block()->type() & mtExecutable) ? true : to_command->owner()->compilation_type() == ctMutation; + if (from_native == to_native) { + section_options_ |= rtLinkedFrom; + } else { + section_options_ |= rtLinkedFromOtherType; + } + + if ((section_options_ & rtLinkedFromOtherType) + || link()->type() == ltSEHBlock + || link()->type() == ltFinallyBlock + || link()->type() == ltFilterSEHBlock + || link()->type() == ltDualSEHBlock + || link()->type() == ltGateOffset + || link()->type() == ltMemSEHBlock + || link()->type() == ltExtSEHHandler + || link()->type() == ltVBMemSEHBlock) { + to_command->include_section_option(rtLinkedToExt); + } else { + to_command->include_section_option(rtLinkedToInt); + } + } + + if (from_native) + return; + + size_t j; + bool need_next_command = false; + bool need_init_cryptor = false; + ICommand *next_command; + + switch (link()->type()) { + case ltCall: + if ((options() & roUseAsJmp) == 0) + need_next_command = true; + need_init_cryptor = true; + break; + case ltJmp: + if (section_options_ & rtLinkedFrom) + need_init_cryptor = true; + break; + case ltSwitch: + if (section_options_ & rtLinkedFrom) { + if (!end_section_cryptor_) + need_init_cryptor = true; + } + break; + case ltCase: + if (to_command) + need_init_cryptor = true; + break; + case ltNative: + if ((options() & roBreaked) == 0 && type_ != cmJmp) + need_next_command = true; + break; + case ltJmpWithFlagNSNS: + need_next_command = true; + need_init_cryptor = true; + break; + case ltJmpWithFlagNSNA: + need_next_command = true; + need_init_cryptor = true; + break; + case ltJmpWithFlagNSFS: + include_section_option(rtLinkedToInt); + to_command = this; + link()->set_to_command(to_command); + need_next_command = true; + need_init_cryptor = true; + break; + case ltJmpWithFlag: + need_next_command = true; + need_init_cryptor = true; + break; + case ltDualSEHBlock: + if (to_command) { + j = owner()->IndexOf(to_command) + 1; + next_command = owner()->item(j); + link()->set_next_command(next_command); + next_command->include_section_option(rtLinkedToExt); + } + break; + } + + if (need_next_command) { + j = owner()->IndexOf(this) + 1; + if (j < owner()->count()) { + next_command = owner()->item(j); + if (owner()->is_breaked_address(next_command->address())) + next_command = NULL; + else { + if (link()->type() == ltCall) { + if (to_command != next_command) { + include_section_option(rtLinkedNext); + link()->set_next_command(next_command); + next_command->include_section_option(rtLinkedToExt); + } + } else { + include_section_option(rtLinkedNext); + link()->set_next_command(next_command); + next_command->include_section_option(link()->type() == ltNative ? rtLinkedToExt : rtLinkedToInt); + } + } + } + } + + if (need_init_cryptor) { + SectionCryptorList *section_cryptor_list = reinterpret_cast(owner())->section_cryptor_list(); + SectionCryptor *cur_section_cryptor = NULL; + IntelCommand *save_cryptor_command = NULL; + IntelCommand *parent_command = reinterpret_cast(link()->parent_command()); + + if (link()->type() == ltCase) { + cur_section_cryptor = parent_command->end_section_cryptor_; + if (!cur_section_cryptor) { + cur_section_cryptor = section_cryptor_list->Add(); + parent_command->end_section_cryptor_ = cur_section_cryptor; + } + begin_section_cryptor_ = cur_section_cryptor; + save_cryptor_command = to_command; + } else { + if (to_command) { + if (section_options_ & rtLinkedFromOtherType) { + if (link()->type() == ltCall) { + cur_section_cryptor = section_cryptor_list->Add(); + } else { + return; + } + } else { + cur_section_cryptor = to_command->begin_section_cryptor_; + if (!cur_section_cryptor && (options() & roExternal) == 0) { + cur_section_cryptor = section_cryptor_list->Add(); + to_command->begin_section_cryptor_ = cur_section_cryptor; + } + } + } else { + cur_section_cryptor = section_cryptor_list->Add(); + } + end_section_cryptor_ = cur_section_cryptor; + + if (link()->type() == ltSwitch && parent_command) + parent_command->end_section_cryptor_ = cur_section_cryptor; + + if (link()->type() == ltSwitch && to_command && to_command->link() && to_command->link()->parent_command() != this) { + save_cryptor_command = reinterpret_cast(to_command->link()->parent_command()); + } else if (link()->type() == ltJmpWithFlag || link()->type() == ltJmpWithFlagNSNA || link()->type() == ltJmpWithFlagNSFS || link()->type() == ltJmpWithFlagNSNS) { + save_cryptor_command = reinterpret_cast(link()->next_command()); + } + } + + if (save_cryptor_command) { + if (link()->type() == ltSwitch) { + if (save_cryptor_command->end_section_cryptor_ != cur_section_cryptor) { + if (save_cryptor_command->end_section_cryptor_) { + cur_section_cryptor->set_end_cryptor(save_cryptor_command->end_section_cryptor_); + } else { + save_cryptor_command->end_section_cryptor_ = cur_section_cryptor; + } + } + } else { + if (save_cryptor_command->begin_section_cryptor_ != cur_section_cryptor) { + if (save_cryptor_command->begin_section_cryptor_) { + cur_section_cryptor->set_end_cryptor(save_cryptor_command->begin_section_cryptor_); + } else { + save_cryptor_command->begin_section_cryptor_ = cur_section_cryptor; + } + } + } + } + } +} + +void IntelCommand::CompileLink(const CompileContext &ctx) +{ + size_t k; + uint64_t value, value1; + + if (block()->type() & mtExecutable) { + // native block + if (!link() || link()->operand_index() == -1) + return; + + ICommand *to_command = link()->to_command(); + if (to_command) { + value = (to_command->block()->type() & mtExecutable) ? to_command->address() : to_command->ext_vm_address(); + } else if (link()->type() == ltDelta) { + value = link()->to_address(); + } else { + return; + } + + if (link()->type() == ltDelta) + value -= link()->parent_command() ? link()->parent_command()->address() : address(); + set_operand_value(link()->operand_index(), link()->Encrypt(value)); + CompileToNative(); + } else { + // VM block + for (size_t i = 0; i < internal_links_.count(); i++) { + InternalLink *internal_link = internal_links_.item(i); + IntelVMCommand *vm_command = reinterpret_cast(internal_link->from_command()); + + switch (internal_link->type()) { + case vlCRCTableAddress: + value = reinterpret_cast(ctx.file->function_list())->runtime_crc_table()->entry()->address(); + break; + case vlCRCTableCount: + value = reinterpret_cast(ctx.file->function_list())->runtime_crc_table()->region_count(); + break; + case vlCRCValue: + { + IntelVMCommand *value_command = reinterpret_cast(internal_link->to_command()); + uint64_t crc_value = reinterpret_cast(ctx.file->virtual_machine_list())->GetCRCValue(value, OperandSizeToValue(value_command->size())); + value_command->set_sub_value(crc_value); + value_command->Compile(); + } + break; + default: + { + IntelCommand *command = reinterpret_cast(internal_link->to_command()); + if (!command) + continue; + + value = command->is_data() ? command->address() : command->owner()->entry()->address(); + } + break; + } + vm_command->set_value(value); + vm_command->Compile(); + } + + if (vm_links_.empty()) + return; + + ICommand *to_command = link()->to_command(); + ICommand *next_command = link()->next_command(); + ICommand *ext_command; + + switch (link()->type()) { + case ltSEHBlock: case ltFinallyBlock: case ltExtSEHBlock: + if (to_command) + set_link_value(0, link()->gate_command(0)->address()); + break; + + case ltMemSEHBlock: case ltExtSEHHandler: case ltVBMemSEHBlock: + // do nothing + break; + + case ltDualSEHBlock: case ltFilterSEHBlock: + if (to_command) + set_link_value(0, link()->gate_command(0)->address()); + break; + + case ltJmpWithFlag: + k = next_command ? 1 : 0; + + value = vm_links_[2]->address(); + value1 = vm_links_[3 + k]->address(); + set_link_value(0, value1); + set_link_value(1, value); + + if (next_command) { + if (next_command->block()->virtual_machine()->id() == block()->virtual_machine()->id()) + set_link_value(1, next_command->vm_address()); + else { + set_link_value(3, next_command->vm_address()); + set_jmp_value(1, next_command->block()->virtual_machine()->id()); + } + } + if (to_command) { + if (section_options_ & rtLinkedFrom) { + if (to_command->block()->virtual_machine()->id() == block()->virtual_machine()->id()) + set_link_value(0, to_command->vm_address()); + else { + set_link_value(4 + k, to_command->vm_address()); + set_jmp_value(1 + k, to_command->block()->virtual_machine()->id()); + } + } + } + break; + + case ltJmpWithFlagNSNS: + value = vm_links_[2]->address(); + value1 = vm_links_[4]->address(); + + set_link_value(0, value); + set_link_value(1, value1); + + if (next_command) { + value = next_command->vm_address(); + set_link_value(3, value); + set_link_value(5, value); + } + break; + + case ltJmpWithFlagNSNA: + value = vm_links_[2]->address(); + if (next_command) { + value1 = vm_links_[4]->address(); + } else { + value1 = vm_links_[3]->address(); + } + + set_link_value(0, value); + set_link_value(1, value1); + + if (next_command) { + set_link_value(3, next_command->vm_address()); + set_jmp_value(1, next_command->block()->virtual_machine()->id()); + if (next_command->block()->virtual_machine()->id() == block()->virtual_machine()->id()) { + set_link_value(1, next_command->vm_address()); + } else { + set_link_value(5, next_command->vm_address()); + set_jmp_value(2, next_command->block()->virtual_machine()->id()); + } + } + break; + + case ltJmpWithFlagNSFS: + value = vm_links_[2]->address(); + if (next_command) { + value1 = next_command->vm_address(); + } else { + value1 = vm_links_[5]->address(); + } + + set_link_value(0, value1); + set_link_value(1, value); + set_link_value(3, value); + set_link_value(4, value1); + break; + + case ltJmp: + if (to_command) { + if (section_options_ & rtLinkedFromOtherType) { + value = to_command->address(); + } else { + value = to_command->vm_address(); + set_jmp_value(0, to_command->block()->virtual_machine()->id()); + } + set_link_value(0, link()->Encrypt(value)); + } + break; + + case ltCall: + if ((options() & roInternal) && (section_options_ & rtLinkedFrom) == 0) { + k = 0; + } else { + k = 1; + ext_command = link()->gate_command(0); + if (ext_command) { + value = ext_command->address(); + } else if (options() & roInternal) { + value = next_command->ext_vm_address(); + } else { + value = address() + original_dump_size(); + } + set_link_value(0, value); + } + + if (section_options_ & rtLinkedFrom) { + set_link_value(k, to_command->vm_address()); + set_jmp_value(0, to_command->block()->virtual_machine()->id()); + } else if (section_options_ & rtLinkedFromOtherType) { + set_link_value(k, to_command->address()); + } + break; + + case ltNative: + set_link_value(0, link()->gate_command(0)->address()); + break; + + case ltOffset: + if (to_command) { + if ((section_options_ & rtLinkedFromOtherType) || to_command->is_data()) { + value = to_command->address(); + } else { + value = to_command->vm_address(); + } + set_link_value(0, link()->Encrypt(value)); + } + break; + + case ltGateOffset: + if (to_command) { + value = to_command->address(); + set_link_value(0, link()->Encrypt(value)); + } + break; + + case ltSwitch: + if (to_command) { + if (section_options_ & rtLinkedFromOtherType) { + value = to_command->address(); + } else { + value = to_command->vm_address(); + } + set_link_value(0, link()->Encrypt(value)); + } + break; + + case ltCase: + if (to_command) { + ext_command = link()->gate_command(0); + if (section_options_ & rtLinkedFromOtherType) { + ext_command->set_link_value(0, to_command->address()); + value = ext_command->vm_address(); + } else if (ext_command->block()->virtual_machine()->id() != to_command->block()->virtual_machine()->id()) { + ext_command->set_link_value(0, to_command->vm_address()); + ext_command->set_jmp_value(0, to_command->block()->virtual_machine()->id()); + value = ext_command->vm_address(); + } else { + value = to_command->vm_address(); + } + set_link_value(0, link()->Encrypt(value)); + } + break; + } + } +} + +bool IntelCommand::GetCommandInfo(IntelCommandInfoList &command_info_list) const +{ + OperandSize os, adr_os; + + command_info_list.clear(); + command_info_list.set_base_segment(base_segment_); + + switch (type_) { + case cmAaa: case cmAas: + command_info_list.Add(atRead, regEFX, otRegistr, size_); + command_info_list.Add(atWrite, regEFX, otRegistr, size_); + command_info_list.set_need_flags(fl_A); + command_info_list.set_change_flags(fl_O | fl_S | fl_Z | fl_A | fl_P | fl_C); + + command_info_list.Add(atRead, regEAX, otRegistr, osByte); + command_info_list.Add(atWrite, regEAX, otRegistr, osWord); + break; + + case cmAad: + command_info_list.Add(atWrite, regEFX, otRegistr, size_); + command_info_list.set_change_flags(fl_O | fl_S | fl_Z | fl_A | fl_P | fl_C); + + command_info_list.Add(atRead, regEAX, otRegistr, osWord); + command_info_list.Add(atWrite, regEAX, otRegistr, osWord); + break; + + case cmAam: + command_info_list.Add(atWrite, regEFX, otRegistr, size_); + command_info_list.set_change_flags(fl_O | fl_S | fl_Z | fl_A | fl_P | fl_C); + + command_info_list.Add(atRead, regEAX, otRegistr, osByte); + command_info_list.Add(atWrite, regEAX, otRegistr, osWord); + break; + + case cmAdc: + command_info_list.Add(atRead, regEFX, otRegistr, size_); + command_info_list.Add(atWrite, regEFX, otRegistr, size_); + command_info_list.set_need_flags(fl_C); + command_info_list.set_change_flags(fl_O | fl_S | fl_Z | fl_A | fl_P | fl_C); + + command_info_list.AddOperand(operand_[1], atRead); + command_info_list.AddOperand(operand_[0], atRead); + command_info_list.AddOperand(operand_[0], atWrite); + break; + + case cmAdd: case cmAnd: + command_info_list.Add(atWrite, regEFX, otRegistr, size_); + command_info_list.set_change_flags(fl_O | fl_S | fl_Z | fl_A | fl_P | fl_C); + + command_info_list.AddOperand(operand_[1], atRead); + command_info_list.AddOperand(operand_[0], atRead); + command_info_list.AddOperand(operand_[0], atWrite); + break; + + case cmBsf: case cmBsr: + command_info_list.Add(atWrite, regEFX, otRegistr, size_); + command_info_list.set_change_flags(fl_O | fl_S | fl_Z | fl_A | fl_P | fl_C); + + command_info_list.AddOperand(operand_[1], atRead); + command_info_list.AddOperand(operand_[0], atWrite); + break; + + case cmBswap: + command_info_list.AddOperand(operand_[0], atRead); + command_info_list.AddOperand(operand_[0], atWrite); + break; + + case cmBt: + command_info_list.Add(atWrite, regEFX, otRegistr, size_); + command_info_list.set_change_flags(fl_C); + + command_info_list.AddOperand(operand_[1], atRead); + command_info_list.AddOperand(operand_[0], atRead); + break; + + case cmBtc: case cmBtr: case cmBts: + command_info_list.Add(atWrite, regEFX, otRegistr, size_); + command_info_list.set_change_flags(fl_C); + + command_info_list.AddOperand(operand_[1], atRead); + command_info_list.AddOperand(operand_[0], atRead); + command_info_list.AddOperand(operand_[0], atWrite); + break; + + case cmCall: + command_info_list.Add(atRead, regESP, otRegistr, size_); + command_info_list.Add(atWrite, regESP, otRegistr, size_); + command_info_list.Add(atWrite, regEIP, otBaseRegistr, size_); + + command_info_list.AddOperand(operand_[0], atRead); + break; + + case cmSyscall: + command_info_list.Add(atRead, regESP, otRegistr, size_); + command_info_list.Add(atWrite, regESP, otRegistr, size_); + command_info_list.Add(atWrite, regEIP, otBaseRegistr, size_); + break; + + case cmCbw: + command_info_list.Add(atRead, regEAX, otRegistr, osByte); + command_info_list.Add(atWrite, regEAX, otHiPartRegistr, osByte); + break; + + case cmCwde: + command_info_list.Add(atRead, regEAX, otRegistr, osWord); + command_info_list.Add(atWrite, regEAX, otRegistr, osDWord); + break; + + case cmCdqe: + command_info_list.Add(atRead, regEAX, otRegistr, osDWord); + command_info_list.Add(atWrite, regEAX, otRegistr, osQWord); + break; + + case cmCwd: + command_info_list.Add(atRead, regEAX, otRegistr, osWord); + command_info_list.Add(atWrite, regEDX, otRegistr, osWord); + break; + + case cmCdq: + command_info_list.Add(atRead, regEAX, otRegistr, osDWord); + command_info_list.Add(atWrite, regEDX, otRegistr, osDWord); + break; + + case cmCqo: + command_info_list.Add(atRead, regEAX, otRegistr, osQWord); + command_info_list.Add(atWrite, regEDX, otRegistr, osQWord); + break; + + case cmClc: case cmStc: + command_info_list.Add(atWrite, regEFX, otRegistr, size_); + command_info_list.set_change_flags(fl_C); + break; + + case cmCmc: + command_info_list.Add(atRead, regEFX, otRegistr, size_); + command_info_list.Add(atWrite, regEFX, otRegistr, size_); + command_info_list.set_need_flags(fl_C); + command_info_list.set_change_flags(fl_C); + break; + + case cmCld: case cmStd: + command_info_list.Add(atWrite, regEFX, otRegistr, size_); + command_info_list.set_change_flags(fl_D); + break; + + case cmCli: case cmSti: + command_info_list.Add(atWrite, regEFX, otRegistr, size_); + command_info_list.set_change_flags(fl_I); + break; + + case cmCmov: + command_info_list.Add(atRead, regEFX, otRegistr, size_); + command_info_list.set_need_flags(flags_); + + command_info_list.AddOperand(operand_[1], atRead); + command_info_list.AddOperand(operand_[0], atRead); + command_info_list.AddOperand(operand_[0], atWrite); + break; + + case cmCmp: + command_info_list.Add(atWrite, regEFX, otRegistr, size_); + command_info_list.set_change_flags(fl_O | fl_S | fl_Z | fl_A | fl_P | fl_C); + + command_info_list.AddOperand(operand_[1], atRead); + command_info_list.AddOperand(operand_[0], atRead); + break; + + case cmCmps: + command_info_list.Add(atRead, regEFX, otRegistr, size_); + command_info_list.Add(atWrite, regEFX, otRegistr, size_); + command_info_list.set_need_flags(fl_D); + command_info_list.set_change_flags(fl_O | fl_S | fl_Z | fl_A | fl_P | fl_C); + + os = operand_[0].size; + adr_os = operand_[1].size; + + command_info_list.Add(atRead, regESI, otRegistr, adr_os); + command_info_list.Add(atRead, regEDI, otRegistr, adr_os); + command_info_list.Add(atWrite, regESI, otRegistr, adr_os); + command_info_list.Add(atWrite, regEDI, otRegistr, adr_os); + + command_info_list.Add(atRead, segES, otMemory, os); + + if (preffix_command_ == cmRep || preffix_command_ == cmRepe || preffix_command_ == cmRepne) { + command_info_list.Add(atRead, regECX, otRegistr, adr_os); + command_info_list.Add(atWrite, regECX, otRegistr, adr_os); + } + break; + + case cmCmpxchg: + command_info_list.Add(atWrite, regEFX, otRegistr, size_); + command_info_list.set_change_flags(fl_O | fl_S | fl_Z | fl_A | fl_P | fl_C); + + os = operand_[0].size; + command_info_list.Add(atRead, regEAX, otRegistr, os); + command_info_list.Add(atWrite, regEAX, otRegistr, os); + + command_info_list.AddOperand(operand_[1], atRead); + command_info_list.AddOperand(operand_[0], atRead); + command_info_list.AddOperand(operand_[0], atWrite); + break; + + case cmCmpxchg8b: + command_info_list.Add(atWrite, regEFX, otRegistr, size_); + command_info_list.set_change_flags(fl_Z); + + command_info_list.Add(atRead, regEAX, otRegistr, osDWord); + command_info_list.Add(atRead, regEDX, otRegistr, osDWord); + command_info_list.Add(atWrite, regEAX, otRegistr, osDWord); + command_info_list.Add(atWrite, regEDX, otRegistr, osDWord); + + command_info_list.Add(atRead, regEBX, otRegistr, osDWord); + command_info_list.Add(atRead, regECX, otRegistr, osDWord); + + command_info_list.AddOperand(operand_[0], atRead); + command_info_list.AddOperand(operand_[0], atWrite); + break; + + case cmCpuid: + command_info_list.Add(atRead, regEAX, otRegistr, osDWord); + + command_info_list.Add(atWrite, regEAX, otRegistr, osDWord); + command_info_list.Add(atWrite, regECX, otRegistr, osDWord); + command_info_list.Add(atWrite, regEDX, otRegistr, osDWord); + command_info_list.Add(atWrite, regEBX, otRegistr, osDWord); + break; + + case cmDaa: + command_info_list.Add(atRead, regEFX, otRegistr, size_); + command_info_list.Add(atWrite, regEFX, otRegistr, size_); + command_info_list.set_need_flags(fl_A); + command_info_list.set_change_flags(fl_O | fl_S | fl_Z | fl_A | fl_P | fl_C); + + command_info_list.Add(atRead, regEAX, otRegistr, osByte); + command_info_list.Add(atWrite, regEAX, otRegistr, osByte); + break; + + case cmDas: + command_info_list.Add(atRead, regEFX, otRegistr, size_); + command_info_list.Add(atWrite, regEFX, otRegistr, size_); + command_info_list.set_need_flags(fl_A | fl_C); + command_info_list.set_change_flags(fl_O | fl_S | fl_Z | fl_A | fl_P | fl_C); + + command_info_list.Add(atRead, regEAX, otRegistr, osByte); + command_info_list.Add(atWrite, regEAX, otRegistr, osByte); + break; + + case cmDec: case cmInc: + command_info_list.Add(atWrite, regEFX, otRegistr, size_); + command_info_list.set_change_flags(fl_O | fl_S | fl_Z | fl_A | fl_P); + + command_info_list.AddOperand(operand_[0], atRead); + command_info_list.AddOperand(operand_[0], atWrite); + break; + + case cmDiv: case cmIdiv: + command_info_list.Add(atWrite, regEFX, otRegistr, size_); + command_info_list.set_change_flags(fl_O | fl_S | fl_Z | fl_A | fl_P | fl_C); + + command_info_list.AddOperand(operand_[0], atRead); + + os = operand_[0].size; + if (os == osByte) { + command_info_list.Add(atRead, regEAX, otRegistr, osWord); + command_info_list.Add(atWrite, regEAX, otRegistr, osWord); + } else { + command_info_list.Add(atRead, regEAX, otRegistr, os); + command_info_list.Add(atWrite, regEAX, otRegistr, os); + command_info_list.Add(atRead, regEDX, otRegistr, os); + command_info_list.Add(atWrite, regEDX, otRegistr, os); + } + break; + + case cmMul: case cmImul: + command_info_list.Add(atWrite, regEFX, otRegistr, size_); + command_info_list.set_change_flags(fl_O | fl_S | fl_Z | fl_A | fl_P | fl_C); + + os = operand_[0].size; + if (operand_[2].type != otNone) { + command_info_list.AddOperand(operand_[2], atRead); + command_info_list.AddOperand(operand_[1], atRead); + command_info_list.AddOperand(operand_[0], atWrite); + } else if (operand_[1].type != otNone) { + command_info_list.AddOperand(operand_[1], atRead); + command_info_list.AddOperand(operand_[0], atRead); + command_info_list.AddOperand(operand_[0], atWrite); + } else { + command_info_list.AddOperand(operand_[0], atRead); + command_info_list.Add(atRead, regEAX, otRegistr, os); + } + + if (operand_[1].type == otNone) { + if (os == osByte) { + command_info_list.Add(atWrite, regEAX, otRegistr, osWord); + } else { + command_info_list.Add(atWrite, regEAX, otRegistr, os); + command_info_list.Add(atWrite, regEDX, otRegistr, os); + } + } + break; + + case cmJCXZ: + os = operand_[1].size; + command_info_list.Add(atRead, regECX, otRegistr, os); + + command_info_list.Add(atWrite, regEIP, otBaseRegistr, size_); + break; + + case cmJmpWithFlag: + command_info_list.Add(atRead, regEFX, otRegistr, size_); + command_info_list.set_need_flags(flags_); + + command_info_list.Add(atWrite, regEIP, otBaseRegistr, size_); + break; + + case cmJmp: + command_info_list.Add(atWrite, regEIP, otBaseRegistr, size_); + + command_info_list.AddOperand(operand_[0], atRead); + break; + + case cmLahf: + command_info_list.Add(atRead, regEFX, otRegistr, size_); + command_info_list.set_need_flags(fl_S | fl_Z | fl_A | fl_P | fl_C); + + command_info_list.Add(atWrite, regEAX, otHiPartRegistr, osByte); + break; + + case cmLds: + command_info_list.AddOperand(operand_[1], atRead); + command_info_list.AddOperand(operand_[0], atWrite); + + command_info_list.Add(atWrite, segDS, otSegmentRegistr, osWord); + break; + + case cmLes: + command_info_list.AddOperand(operand_[1], atRead); + command_info_list.AddOperand(operand_[0], atWrite); + + command_info_list.Add(atWrite, segES, otSegmentRegistr, osWord); + break; + + case cmLfs: + command_info_list.AddOperand(operand_[1], atRead); + command_info_list.AddOperand(operand_[0], atWrite); + + command_info_list.Add(atWrite, segFS, otSegmentRegistr, osWord); + break; + + case cmLgs: + command_info_list.AddOperand(operand_[1], atRead); + command_info_list.AddOperand(operand_[0], atWrite); + + command_info_list.Add(atWrite, segGS, otSegmentRegistr, osWord); + break; + + case cmLss: + command_info_list.AddOperand(operand_[1], atRead); + command_info_list.AddOperand(operand_[0], atWrite); + + command_info_list.Add(atWrite, segSS, otSegmentRegistr, osWord); + break; + + case cmLea: + { + IntelOperand operand = operand_[1]; + operand.type &= ~otMemory; + command_info_list.AddOperand(operand, atRead); + } + command_info_list.AddOperand(operand_[0], atWrite); + break; + + case cmLeave: + command_info_list.Add(atRead, regESP, otRegistr, size_); + command_info_list.Add(atWrite, regESP, otRegistr, size_); + + command_info_list.Add(atRead, regEBP, otRegistr, size_); + command_info_list.Add(atWrite, regEBP, otRegistr, size_); + break; + + case cmLods: + command_info_list.Add(atRead, regEFX, otRegistr, size_); + command_info_list.set_need_flags(fl_D); + + os = operand_[0].size; + adr_os = operand_[1].size; + + command_info_list.Add(atRead, regESI, otRegistr, adr_os); + command_info_list.Add(atWrite, regESI, otRegistr, adr_os); + + command_info_list.Add(atWrite, regEAX, otRegistr, os); + command_info_list.Add(atRead, (base_segment_ == segDefault) ? segDS : base_segment_, otMemory, os); + + if (preffix_command_ == cmRep || preffix_command_ == cmRepe || preffix_command_ == cmRepne) { + command_info_list.Add(atRead, regECX, otRegistr, adr_os); + command_info_list.Add(atWrite, regECX, otRegistr, adr_os); + } + break; + + case cmLoop: + os = operand_[1].size; + command_info_list.Add(atRead, regECX, otRegistr, os); + command_info_list.Add(atWrite, regECX, otRegistr, os); + + command_info_list.Add(atWrite, regEIP, otBaseRegistr, size_); + break; + + case cmLoope: case cmLoopne: + command_info_list.Add(atRead, regEFX, otRegistr, size_); + command_info_list.set_need_flags(fl_Z); + + os = operand_[1].size; + command_info_list.Add(atRead, regECX, otRegistr, os); + command_info_list.Add(atWrite, regECX, otRegistr, os); + + command_info_list.Add(atWrite, regEIP, otBaseRegistr, size_); + break; + + case cmMov: case cmMovsx: case cmMovsxd: case cmMovzx: + command_info_list.AddOperand(operand_[1], atRead); + command_info_list.AddOperand(operand_[0], atWrite); + break; + + case cmMovs: + command_info_list.Add(atRead, regEFX, otRegistr, size_); + command_info_list.set_need_flags(fl_D); + + os = operand_[0].size; + adr_os = operand_[1].size; + + command_info_list.Add(atRead, regESI, otRegistr, adr_os); + command_info_list.Add(atWrite, regESI, otRegistr, adr_os); + command_info_list.Add(atRead, regEDI, otRegistr, adr_os); + command_info_list.Add(atWrite, regEDI, otRegistr, adr_os); + + command_info_list.Add(atRead, (base_segment_ == segDefault) ? segDS : base_segment_, otMemory, os); + command_info_list.Add(atWrite, segES, otMemory, os); + + if (preffix_command_ == cmRep || preffix_command_ == cmRepe || preffix_command_ == cmRepne) { + command_info_list.Add(atRead, regECX, otRegistr, adr_os); + command_info_list.Add(atWrite, regECX, otRegistr, adr_os); + } + break; + + case cmNeg: + command_info_list.Add(atWrite, regEFX, otRegistr, size_); + command_info_list.set_change_flags(fl_O | fl_S | fl_Z | fl_A | fl_P | fl_C); + + command_info_list.AddOperand(operand_[0], atRead); + command_info_list.AddOperand(operand_[0], atWrite); + break; + + case cmNop: + break; + + case cmNot: + command_info_list.AddOperand(operand_[0], atRead); + command_info_list.AddOperand(operand_[0], atWrite); + break; + + case cmOr: + command_info_list.Add(atWrite, regEFX, otRegistr, size_); + command_info_list.set_change_flags(fl_O | fl_S | fl_Z | fl_A | fl_P | fl_C); + + command_info_list.AddOperand(operand_[1], atRead); + command_info_list.AddOperand(operand_[0], atRead); + command_info_list.AddOperand(operand_[0], atWrite); + break; + + case cmPop: + command_info_list.Add(atRead, regESP, otRegistr, size_); + command_info_list.Add(atWrite, regESP, otRegistr, size_); + + os = operand_[0].size; + command_info_list.Add(atRead, segSS, otMemory, os); + + command_info_list.AddOperand(operand_[0], atWrite); + break; + + case cmPopa: + command_info_list.Add(atRead, regESP, otRegistr, size_); + command_info_list.Add(atWrite, regESP, otRegistr, size_); + + os = operand_[0].size; + command_info_list.Add(atRead, segSS, otMemory, os); + + command_info_list.Add(atWrite, regEAX, otRegistr, os); + command_info_list.Add(atWrite, regECX, otRegistr, os); + command_info_list.Add(atWrite, regEDX, otRegistr, os); + command_info_list.Add(atWrite, regEBX, otRegistr, os); + command_info_list.Add(atWrite, regEBP, otRegistr, os); + command_info_list.Add(atWrite, regESI, otRegistr, os); + command_info_list.Add(atWrite, regEDI, otRegistr, os); + break; + + case cmPopf: + command_info_list.Add(atRead, regESP, otRegistr, size_); + command_info_list.Add(atWrite, regESP, otRegistr, size_); + + os = operand_[0].size; + command_info_list.Add(atRead, segSS, otMemory, os); + + command_info_list.Add(atWrite, regEFX, otRegistr, os); + command_info_list.set_change_flags(0xFFFF); + break; + + case cmPush: + command_info_list.Add(atRead, regESP, otRegistr, size_); + command_info_list.Add(atWrite, regESP, otRegistr, size_); + + os = operand_[0].size; + command_info_list.Add(atWrite, segSS, otMemory, os); + + command_info_list.AddOperand(operand_[0], atRead); + break; + + case cmPusha: + command_info_list.Add(atRead, regESP, otRegistr, size_); + command_info_list.Add(atWrite, regESP, otRegistr, size_); + + os = operand_[0].size; + command_info_list.Add(atWrite, segSS, otMemory, os); + + command_info_list.Add(atRead, regEAX, otRegistr, os); + command_info_list.Add(atRead, regECX, otRegistr, os); + command_info_list.Add(atRead, regEDX, otRegistr, os); + command_info_list.Add(atRead, regEBX, otRegistr, os); + command_info_list.Add(atRead, regEBP, otRegistr, os); + command_info_list.Add(atRead, regESI, otRegistr, os); + command_info_list.Add(atRead, regEDI, otRegistr, os); + break; + + case cmPushf: + command_info_list.Add(atRead, regESP, otRegistr, size_); + command_info_list.Add(atWrite, regESP, otRegistr, size_); + + os = operand_[0].size; + command_info_list.Add(atWrite, segSS, otMemory, os); + + command_info_list.Add(atRead, regEFX, otRegistr, os); + command_info_list.set_need_flags(0xFFFF); + break; + + case cmRet: case cmIret: + command_info_list.Add(atRead, regESP, otRegistr, size_); + command_info_list.Add(atWrite, regESP, otRegistr, size_); + + command_info_list.Add(atRead, segSS, otMemory, size_); + command_info_list.Add(atWrite, regEIP, otBaseRegistr, size_); + break; + + case cmRcl: case cmRcr: + command_info_list.Add(atRead, regEFX, otRegistr, size_); + command_info_list.Add(atWrite, regEFX, otRegistr, size_); + command_info_list.set_need_flags(fl_C); + command_info_list.set_change_flags(fl_O | fl_C); + + command_info_list.AddOperand(operand_[1], atRead); + command_info_list.AddOperand(operand_[0], atRead); + command_info_list.AddOperand(operand_[0], atWrite); + break; + + case cmRdtsc: + command_info_list.Add(atWrite, regEAX, otRegistr, osDWord); + command_info_list.Add(atWrite, regEDX, otRegistr, osDWord); + break; + + case cmRol: case cmRor: + command_info_list.Add(atWrite, regEFX, otRegistr, size_); + command_info_list.set_change_flags(fl_O | fl_C); + + command_info_list.AddOperand(operand_[1], atRead); + command_info_list.AddOperand(operand_[0], atRead); + command_info_list.AddOperand(operand_[0], atWrite); + break; + + case cmSahf: + command_info_list.Add(atWrite, regEFX, otRegistr, size_); + command_info_list.set_change_flags(fl_S | fl_Z | fl_A | fl_P | fl_C); + + command_info_list.Add(atRead, regEAX, otHiPartRegistr, osByte); + break; + + case cmSal: case cmSar: + command_info_list.Add(atWrite, regEFX, otRegistr, size_); + command_info_list.set_change_flags(fl_O | fl_S | fl_Z | fl_A | fl_P | fl_C); + + command_info_list.AddOperand(operand_[1], atRead); + command_info_list.AddOperand(operand_[0], atRead); + command_info_list.AddOperand(operand_[0], atWrite); + break; + + case cmSbb: + command_info_list.Add(atRead, regEFX, otRegistr, size_); + command_info_list.Add(atWrite, regEFX, otRegistr, size_); + command_info_list.set_need_flags(fl_C); + command_info_list.set_change_flags(fl_O | fl_S | fl_Z | fl_A | fl_P | fl_C); + + command_info_list.AddOperand(operand_[1], atRead); + command_info_list.AddOperand(operand_[0], atRead); + command_info_list.AddOperand(operand_[0], atWrite); + break; + + case cmScas: + command_info_list.Add(atRead, regEFX, otRegistr, size_); + command_info_list.Add(atWrite, regEFX, otRegistr, size_); + command_info_list.set_need_flags(fl_D); + command_info_list.set_change_flags(fl_O | fl_S | fl_Z | fl_A | fl_P | fl_C); + + os = operand_[0].size; + adr_os = operand_[1].size; + + command_info_list.Add(atRead, regEDI, otRegistr, adr_os); + command_info_list.Add(atWrite, regEDI, otRegistr, adr_os); + + command_info_list.Add(atRead, regEAX, otRegistr, os); + command_info_list.Add(atRead, segES, otMemory, os); + + if (preffix_command_ == cmRep || preffix_command_ == cmRepe || preffix_command_ == cmRepne) { + command_info_list.Add(atRead, regECX, otRegistr, adr_os); + command_info_list.Add(atWrite, regECX, otRegistr, adr_os); + } + break; + + case cmSetXX: + command_info_list.Add(atRead, regEFX, otRegistr, size_); + command_info_list.set_need_flags(flags_); + + command_info_list.AddOperand(operand_[0], atWrite); + break; + + case cmShl: case cmShr: + command_info_list.Add(atWrite, regEFX, otRegistr, size_); + command_info_list.set_change_flags(fl_O | fl_S | fl_Z | fl_A | fl_P | fl_C); + + command_info_list.AddOperand(operand_[1], atRead); + command_info_list.AddOperand(operand_[0], atRead); + command_info_list.AddOperand(operand_[0], atWrite); + break; + + case cmShld: case cmShrd: + command_info_list.Add(atWrite, regEFX, otRegistr, size_); + command_info_list.set_change_flags(fl_O | fl_S | fl_Z | fl_A | fl_P | fl_C); + + command_info_list.AddOperand(operand_[2], atRead); + command_info_list.AddOperand(operand_[1], atRead); + command_info_list.AddOperand(operand_[0], atRead); + command_info_list.AddOperand(operand_[0], atWrite); + break; + + case cmStos: + command_info_list.Add(atRead, regEFX, otRegistr, size_); + command_info_list.set_need_flags(fl_D); + + os = operand_[0].size; + adr_os = operand_[1].size; + + command_info_list.Add(atRead, regEDI, otRegistr, adr_os); + command_info_list.Add(atWrite, regEDI, otRegistr, adr_os); + + command_info_list.Add(atRead, regEAX, otRegistr, os); + command_info_list.Add(atWrite, segES, otMemory, os); + + if (preffix_command_ == cmRep || preffix_command_ == cmRepe || preffix_command_ == cmRepne) { + command_info_list.Add(atRead, regECX, otRegistr, adr_os); + command_info_list.Add(atWrite, regECX, otRegistr, adr_os); + } + break; + + case cmSub: + command_info_list.Add(atWrite, regEFX, otRegistr, size_); + command_info_list.set_change_flags(fl_O | fl_S | fl_Z | fl_A | fl_P | fl_C); + + command_info_list.AddOperand(operand_[1], atRead); + command_info_list.AddOperand(operand_[0], atRead); + command_info_list.AddOperand(operand_[0], atWrite); + break; + + case cmTest: + command_info_list.Add(atWrite, regEFX, otRegistr, size_); + command_info_list.set_change_flags(fl_O | fl_S | fl_Z | fl_A | fl_P | fl_C); + + command_info_list.AddOperand(operand_[1], atRead); + command_info_list.AddOperand(operand_[0], atRead); + break; + + case cmXadd: + command_info_list.Add(atWrite, regEFX, otRegistr, size_); + command_info_list.set_change_flags(fl_O | fl_S | fl_Z | fl_A | fl_P | fl_C); + + command_info_list.AddOperand(operand_[1], atRead); + command_info_list.AddOperand(operand_[1], atWrite); + command_info_list.AddOperand(operand_[0], atRead); + command_info_list.AddOperand(operand_[0], atWrite); + break; + + case cmXchg: + command_info_list.AddOperand(operand_[1], atRead); + command_info_list.AddOperand(operand_[1], atWrite); + command_info_list.AddOperand(operand_[0], atRead); + command_info_list.AddOperand(operand_[0], atWrite); + break; + + case cmXlat: + adr_os = operand_[0].size; + command_info_list.Add(atRead, regEBX, otRegistr, adr_os); + command_info_list.Add(atRead, regEAX, otRegistr, osByte); + command_info_list.Add(atWrite, regEAX, otRegistr, osByte); + + command_info_list.Add(atRead, (base_segment_ == segDefault) ? segDS : base_segment_, otMemory, osByte); + break; + + case cmXor: + command_info_list.Add(atWrite, regEFX, otRegistr, size_); + command_info_list.set_change_flags(fl_O | fl_S | fl_Z | fl_A | fl_P | fl_C); + + command_info_list.AddOperand(operand_[1], atRead); + command_info_list.AddOperand(operand_[0], atRead); + command_info_list.AddOperand(operand_[0], atWrite); + break; + + // FPU commands + + case cmWait: case cmFabs: case cmFchs: case cmFclex: case cmFcos: case cmFdecstp: + case cmFfree: case cmFincstp: case cmFinit: case cmFld1: case cmFldl2t: case cmFldl2e: + case cmFldlg2: case cmFldln2: case cmFldpi: case cmFldz: + case cmFpatan: case cmFprem: case cmFprem1: case cmFptan: + case cmFrndint: case cmFscale: case cmFsin: case cmFsincos: case cmFsqrt: + case cmFtst: case cmFxam: case cmFxtract: case cmFyl2x: case cmFyl2xp1: + command_info_list.Add(atRead, 0, otFPURegistr, size_); + command_info_list.Add(atWrite, 0, otFPURegistr, size_); + break; + + case cmFadd: case cmFaddp: case cmFiadd: case cmFcom: case cmFcomp: case cmFcompp: case cmFdiv: case cmFidiv: case cmFdivp: + case cmFdivr: case cmFidivr: case cmFdivrp: case cmFicom: case cmFicomp: case cmFild: case cmFld: case cmFmul: case cmFimul: + case cmFmulp: case cmFsub: case cmFisub: case cmFsubp: case cmFsubr: case cmFisubr: case cmFsubrp: case cmFucom: case cmFucomp: + case cmFucompp: case cmFxch: + os = operand_[0].size; + command_info_list.Add(atRead, 0, otFPURegistr, os); + command_info_list.Add(atWrite, 0, otFPURegistr, os); + + command_info_list.AddOperand(operand_[0], atRead); + break; + + case cmFcomi: case cmFcomip: case cmFucomi: case cmFucomip: + os = operand_[0].size; + command_info_list.Add(atRead, 0, otFPURegistr, os); + command_info_list.Add(atWrite, 0, otFPURegistr, os); + + command_info_list.Add(atWrite, regEFX, otRegistr, size_); + command_info_list.set_change_flags(fl_Z | fl_P | fl_C); + + command_info_list.AddOperand(operand_[0], atRead); + break; + + /* + case cmFcmov: + command_info_list.Add(atRead, regEFX, otRegistr, size_); + command_info_list.set_need_flags(flags_); + + OS:=FOperand[0].OperandSize; + command_info_list.Add(atRead, 0, otFPURegistr, OS); + command_info_list.Add(atWrite, 0, otFPURegistr, OS); + break; + */ + + case cmFist: case cmFistp: case cmFst: case cmFstp: case cmFstsw: case cmFstcw: + os = operand_[0].size; + command_info_list.Add(atRead, 0, otFPURegistr, os); + command_info_list.Add(atWrite, 0, otFPURegistr, os); + + command_info_list.AddOperand(operand_[0], atWrite); + break; + + case cmFldcw: + os = operand_[0].size; + command_info_list.Add(atRead, 0, otFPURegistr, os); + command_info_list.Add(atWrite, 0, otFPURegistr, os); + + command_info_list.AddOperand(operand_[0], atRead); + break; + + case cmFnop: + break; + + case cmRdrand: + case cmRdseed: + command_info_list.AddOperand(operand_[0], atWrite); + + command_info_list.Add(atWrite, regEFX, otRegistr, size_); + command_info_list.set_change_flags(fl_O | fl_S | fl_Z | fl_A | fl_P | fl_C); + break; + + case cmMovsd: + case cmMovss: + case cmMovupd: + case cmMovups: + case cmMovdqu: + case cmMovq: + case cmMovlpd: + case cmMovaps: + command_info_list.AddOperand(operand_[1], atRead); + command_info_list.AddOperand(operand_[0], atWrite); + break; + + default: + return false; + } + + return true; +} + +bool IntelCommand::Merge(ICommand *command) +{ + if (count() == 0 || command->count() == 0 || command->owner() != owner() || address_range() != command->address_range()) + return false; + + IntelCommand *dest = reinterpret_cast(command); + size_t i; + for (i = 0; i < vm_command_info_list_->count(); i++) { + CommandInfo *command_info = vm_command_info_list_->item(i); + switch (command_info->operand_type()) { + case otRegistr: + if (command_info->value() == regESP || (command_info->value() & regExtended)) + return false; + break; + case otControlRegistr: + if (command_info->type() == atWrite) + return false; + break; + case otMemory: + if (dest->vm_command_info_list_->GetInfo(atWrite, otRegistr, regESP)) + return false; + break; + } + } + + size_t dest_count = dest->count(); + for (i = 0; i < dest->count(); i++) { + IntelVMCommand *vm_command = dest->item(i); + if (vm_command->command_type() == cmJmp || vm_command->command_type() == cmRet || vm_command->command_type() == cmIret) { + dest_count = i; + break; + } + } + + size_t dest_pos = NOT_ID; + if (owner()->IndexOf(dest) > owner()->IndexOf(this)) { + for (i = 0; i < dest_count; i++) { + if (!dest->item(i)->can_merge(*vm_command_info_list_)) + break; + dest_pos = i; + } + if (dest_pos != NOT_ID) + dest_pos = rand() % (dest_pos + 1); + } else { + for (i = dest_count; i > 0; i--) { + if (!dest->item(i - 1)->can_merge(*vm_command_info_list_)) + break; + dest_pos = i - 1; + } + if (dest_pos != NOT_ID) + dest_pos = dest_pos + rand() % (dest_count - dest_pos); + } + + if (dest_pos == NOT_ID) + return false; + + for (size_t p = 0; p < count(); ) { + IntelVMCommand *vm_command = item(p); + if (vm_command->options() & voSectionCommand) { + if (section_options() & rtBeginSection) { + p++; + continue; + } + if (section_options() & rtEndSection) + break; + } + RemoveObject(vm_command); + vm_command->set_owner(dest); + dest->InsertObject(dest_pos++, vm_command); + } + + for (i = 0; i < vm_command_info_list_->count(); i++) { + CommandInfo *command_info = vm_command_info_list_->item(i); + dest->vm_command_info_list_->Add(command_info->type(), command_info->value(), command_info->operand_type(), command_info->size()); + } + + return true; +} + +/** + * IntelCommandInfoList + */ + +IntelCommandInfoList::IntelCommandInfoList(OperandSize cpu_address_size) + : CommandInfoList(), cpu_address_size_(cpu_address_size), base_segment_(segDefault) +{ + +} + +void IntelCommandInfoList::Add(AccessType access_type, uint8_t value, OperandType operand_type, OperandSize size) +{ + CommandInfoList::Add(access_type, value, operand_type, (cpu_address_size_ == osQWord && access_type == atWrite && operand_type == otRegistr && size == osDWord) ? osQWord : size); +} + +void IntelCommandInfoList::AddOperand(const IntelOperand &operand, AccessType access_type) +{ + static const OperandType operand_types[] = { + otValue, + otRegistr, + otMemory, + otSegmentRegistr, + otControlRegistr, + otDebugRegistr, + otFPURegistr, + otHiPartRegistr, + otBaseRegistr, + otMMXRegistr, + otXMMRegistr + }; + + for (size_t i = 0; i < _countof(operand_types); i++) { + OperandType ot = operand_types[i]; + if ((operand.type & ot) == 0) + continue; + + switch (ot) { //-V719 + case otRegistr: + case otSegmentRegistr: + case otControlRegistr: + case otDebugRegistr: + case otMMXRegistr: + case otXMMRegistr: + if (operand.type & otMemory) { + Add(atRead, operand.registr, ot, operand.address_size); + } else { + Add(access_type, operand.registr, ot, operand.size); + } + break; + + case otHiPartRegistr: + Add(access_type, operand.registr, ot, operand.size); + break; + + case otBaseRegistr: + if (operand.type & otMemory) { + Add(atRead, operand.base_registr, otRegistr, operand.address_size); + } else { + Add(access_type, operand.base_registr, otRegistr, operand.size); + } + break; + + case otFPURegistr: + Add(access_type, 0, ot, operand.size); + break; + + case otMemory: + Add(access_type, operand.effective_base_segment(base_segment_), ot, operand.size); + break; + } + } +} + +#ifdef CHECKED +bool IntelCommand::check_hash() const +{ + return (hash_ == calc_hash()); +} + +void IntelCommand::update_hash() +{ + hash_ = calc_hash(); +} + +uint32_t IntelCommand::calc_hash() const +{ + Data data; + data.PushDWord(type_); + data.PushDWord(preffix_command_); + data.PushDWord(size_); + data.PushDWord(base_segment_); + for (size_t i = 0; i < 3; i++) { + const IntelOperand *operand = &operand_[i]; + data.PushWord(operand->type); + data.PushByte(operand->size); + data.PushByte(operand->registr); + data.PushByte(operand->base_registr); + data.PushByte(operand->scale_registr); + data.PushByte(operand->address_size); + data.PushByte(operand->value_size); + data.PushQWord(operand->value); + } + SHA1 sha; + sha.Input(data.data(), data.size()); + return *reinterpret_cast(sha.Result()); +} +#endif + +/** + * IntelFunction + */ + +IntelFunction::IntelFunction(IFunctionList *owner, const std::string &name, CompilationType compilation_type, uint32_t compilation_options, bool need_compile, Folder *folder) + : BaseFunction(owner, name, compilation_type, compilation_options, need_compile, folder) +{ + section_cryptor_list_ = new SectionCryptorList(this); +} + +IntelFunction::IntelFunction(IFunctionList *owner) + : BaseFunction(owner, FunctionName(""), ctVirtualization, 0, true, NULL) +{ + section_cryptor_list_ = new SectionCryptorList(this); +} + +IntelFunction::IntelFunction(IFunctionList *owner, OperandSize cpu_address_size, IFunction *parent) + : BaseFunction(owner, cpu_address_size, parent) +{ + section_cryptor_list_ = new SectionCryptorList(this); +} + +IntelFunction::IntelFunction(IFunctionList *owner, const IntelFunction &src) + : BaseFunction(owner, src) +{ + section_cryptor_list_ = new SectionCryptorList(this); +} + +IntelFunction *IntelFunction::Clone(IFunctionList *owner) const +{ + IntelFunction *func = new IntelFunction(owner, *this); + return func; +} + +IntelFunction::~IntelFunction() +{ + delete section_cryptor_list_; +} + +void IntelFunction::clear() +{ + break_case_list_.clear(); + BaseFunction::clear(); +} + +IntelCommand *IntelFunction::GetCommandByAddress(uint64_t address) const +{ + return reinterpret_cast(BaseFunction::GetCommandByAddress(address)); +} + +IntelCommand *IntelFunction::GetCommandByNearAddress(uint64_t address) const +{ + return reinterpret_cast(BaseFunction::GetCommandByNearAddress(address)); +} + +IntelCommand *IntelFunction::Add(uint64_t address) +{ + IntelCommand *command = new IntelCommand(this, cpu_address_size(), address); + AddObject(command); + return command; +} + +IntelCommand *IntelFunction::AddCommand(IntelCommandType type, IntelOperand operand1, IntelOperand operand2, IntelOperand operand3) +{ + IntelCommand *command = new IntelCommand(this, cpu_address_size(), type, operand1, operand2, operand3); + AddObject(command); + return command; +} + +IntelCommand *IntelFunction::AddCommand(const std::string &value) +{ + IntelCommand *command = new IntelCommand(this, cpu_address_size(), value); + AddObject(command); + return command; +} + +IntelCommand *IntelFunction::AddCommand(const os::unicode_string &value) +{ + IntelCommand *command = new IntelCommand(this, cpu_address_size(), value); + AddObject(command); + return command; +} + +IntelCommand *IntelFunction::AddCommand(const Data &value) +{ + IntelCommand *command = new IntelCommand(this, cpu_address_size(), value); + AddObject(command); + return command; +} + +IntelCommand *IntelFunction::AddCommand(OperandSize value_size, uint64_t value) +{ + IntelCommandType command_type; + switch (value_size) { + case osWord: + command_type = cmDW; + break; + case osDWord: + command_type = cmDD; + break; + case osQWord: + command_type = cmDQ; + break; + default: + return NULL; + } + + return AddCommand(command_type, IntelOperand(otValue, value_size, 0, value)); +} + +bool IntelFunction::ParseFilterSEH(IArchitecture &file, uint64_t address) +{ + uint32_t table_count; + size_t i, j, c; + uint64_t pos, value; + IntelCommand *command; + + if (file.cpu_address_size() != osDWord || !file.AddressSeek(address)) + return false; + + pos = file.Tell(); + table_count = file.ReadDWord(); + for (i = 0; i < table_count; i++) { + for (j = 0; j < 2; j++) { + value = file.ReadDWord(); + if (value == 0) { + if (j > 0) + return false; + } else { + if (file.segment_list()->GetMemoryTypeByAddress(value) == mtNone || + (file.fixup_list()->count() != 0 && file.fixup_list()->GetFixupByAddress(address + (1 + i * 2 + j) * sizeof(uint32_t)) == NULL)) + return false; + } + } + } + + file.Seek(pos); + + c = count(); + + command = Add(address); + command->ReadValueFromFile(file, osDWord); + command->set_comment(CommentInfo(ttComment, "Count")); + address = command->next_address(); + + for (i = 0; i < table_count; i++) { + command = Add(address); + command->ReadValueFromFile(file, osDWord); + command->set_comment(CommentInfo(ttComment, "Class")); + address = command->next_address(); + + command = Add(address); + value = command->ReadValueFromFile(file, osDWord); + command->set_comment(CommentInfo(ttComment, "Handler")); + address = command->next_address(); + command->AddLink(0, ltMemSEHBlock, value); + } + + for (i = c; i < count(); i++) { + command = item(i); + command->exclude_option(roClearOriginalCode); + } + + return true; +} + +bool IntelFunction::ParseSwitch(IArchitecture &file, uint64_t address, OperandSize value_size, uint64_t add_value, IntelCommand *parent_command, size_t mode, size_t max_table_count) +{ + if (value_size < osDWord || value_size > osQWord) + return false; + + size_t i, table_count, c; + IntelCommand *command; + uint64_t pos, value; + + command = GetCommandByAddress(address); + if (command) { + // CASEs already parsed by previous switch + for (table_count = 0; command && (command->type() == cmDD || command->type() == cmDQ) && command->link() && command->link()->type() == ltCase; table_count++) { + if (command->link()->sub_value() != add_value) { + if (break_case_list_.find(command->address()) != break_case_list_.end()) + break; + break_case_list_.insert(command->address()); + ClearItems(); + return false; + } + command->link()->set_parent_command(parent_command); + command = GetCommandByAddress(command->next_address()); + } + return table_count != 0; + } + + if (!file.AddressSeek(address)) + return false; + + pos = file.Tell(); + std::vector value_list; + for (table_count = 0; table_count <= max_table_count; table_count++) { + uint64_t case_address = address + table_count * OperandSizeToValue(value_size); + bool is_ok = true; + for (i = 0; i < OperandSizeToValue(value_size); i++) { + uint64_t tmp = case_address + i; + if (GetCommandByNearAddress(tmp) || link_list()->GetLinkByToAddress(ltNone, tmp)) { + is_ok = false; + break; + } + } + if (!is_ok) + break; + switch (value_size) { + case osDWord: + { + uint32_t dw = file.ReadDWord(); + value = (mode == 1) ? DWordToInt64(dw) : dw; + } + break; + case osQWord: + value = file.ReadQWord(); + break; + } + if (mode == 2) + value = add_value - value; + else + value = add_value + value; + if (file.cpu_address_size() == osDWord) + value = static_cast(value); + if ((file.segment_list()->GetMemoryTypeByAddress(value) & mtExecutable) == 0) + break; + if (value >= address) + break; + if (table_count > 0 && break_case_list_.find(case_address) != break_case_list_.end()) + break; + value_list.push_back(value); + } + + if (value_list.empty()) + return false; + + file.Seek(pos); + c = count(); + for (i = 0; i < value_list.size(); i++) { + command = Add(address); + command->set_comment(CommentInfo(ttComment, "Case")); + command->ReadValueFromFile(file, value_size); + address = command->next_address(); + + CommandLink *link = command->AddLink(0, ltCase, value_list[i]); + link->set_parent_command(parent_command); + if (add_value) + link->set_sub_value(add_value); + if (mode == 2) + link->set_is_inverse(true); + } + + command = item(c); + command->set_alignment(OperandSizeToValue(value_size)); + command->include_option(roCreateNewBlock); + + return true; +} + +bool IntelFunction::ParseSEH3(IArchitecture &file, uint64_t address) +{ + if (!file.AddressSeek(address)) + return false; + + uint32_t state; + uint64_t pos, value; + size_t i, c, table_count; + IntelCommand *command; + + pos = file.Tell(); + for (table_count = 0;; table_count++) { + state = file.ReadDWord(); + if (state != (uint32_t)-1 && state >= table_count) + break; + + bool is_ok = true; + for (i = 0; i < 2; i++) { + value = file.ReadDWord(); + if (value) { + if ((file.segment_list()->GetMemoryTypeByAddress(value) & mtExecutable) == 0) { + is_ok = false; + break; + } + } else if (i == 1) { + is_ok = false; + break; + } + } + if (!is_ok) + break; + } + + if (!table_count) + return false; + + file.Seek(pos); + c = count(); + for (i = 0; i < table_count; i++) { + command = Add(address); + command->set_comment(CommentInfo(ttComment, "State")); + command->ReadValueFromFile(file, osDWord); + address = command->next_address(); + + command = Add(address); + command->set_comment(CommentInfo(ttComment, "Filter")); + value = command->ReadValueFromFile(file, osDWord); + if (value) { + command->AddLink(0, ltMemSEHBlock, value); + command->include_option(roExternal); + } + address = command->next_address(); + + command = Add(address); + command->set_comment(CommentInfo(ttComment, "Handler")); + value = command->ReadValueFromFile(file, osDWord); + if (value) + command->AddLink(0, ltMemSEHBlock, value); + address = command->next_address(); + } + + command = item(c); + command->set_alignment(OperandSizeToValue(osDWord)); + command->include_option(roCreateNewBlock); + + for (i = c; i < count(); i++) { + command = item(i); + command->exclude_option(roClearOriginalCode); + } + return true; +} + +bool IntelFunction::ParseSEH4(IArchitecture &file, uint64_t address) +{ + if (!file.AddressSeek(address)) + return false; + + uint32_t state; + uint64_t pos, value; + size_t i, c, table_count; + IntelCommand *command; + + pos = file.Tell(); + file.ReadDWord(); + file.ReadDWord(); + file.ReadDWord(); + file.ReadDWord(); + for (table_count = 0;; table_count++) { + state = file.ReadDWord(); + if (state != (uint32_t)-2 && (size_t)state >= table_count) + break; + + bool is_ok = true; + for (i = 0; i < 2; i++) { + value = file.ReadDWord(); + if (value) { + if ((file.segment_list()->GetMemoryTypeByAddress(value) & mtExecutable) == 0) { + is_ok = false; + break; + } + } else if (i == 1) { + is_ok = false; + break; + } + } + if (!is_ok) + break; + } + + if (!table_count) + return false; + + file.Seek(pos); + c = count(); + + command = Add(address); + command->set_comment(CommentInfo(ttComment, "GSCookieOffset")); + command->ReadValueFromFile(file, osDWord); + address = command->next_address(); + + command = Add(address); + command->set_comment(CommentInfo(ttComment, "GSCookieXOROffset")); + command->ReadValueFromFile(file, osDWord); + address = command->next_address(); + + command = Add(address); + command->set_comment(CommentInfo(ttComment, "EHCookieOffset")); + command->ReadValueFromFile(file, osDWord); + address = command->next_address(); + + command = Add(address); + command->set_comment(CommentInfo(ttComment, "EHCookieXOROffset")); + command->ReadValueFromFile(file, osDWord); + address = command->next_address(); + + for (i = 0; i < table_count; i++) { + command = Add(address); + command->set_comment(CommentInfo(ttComment, "State")); + command->ReadValueFromFile(file, osDWord); + address = command->next_address(); + + command = Add(address); + command->set_comment(CommentInfo(ttComment, "Filter")); + value = command->ReadValueFromFile(file, osDWord); + if (value) { + command->AddLink(0, ltMemSEHBlock, value); + command->include_option(roExternal); + } + address = command->next_address(); + + command = Add(address); + command->set_comment(CommentInfo(ttComment, "Handler")); + value = command->ReadValueFromFile(file, osDWord); + if (value) + command->AddLink(0, ltMemSEHBlock, value); + address = command->next_address(); + } + + command = item(c); + command->set_alignment(OperandSizeToValue(osDWord)); + command->include_option(roCreateNewBlock); + + for (i = c; i < count(); i++) { + command = item(i); + command->exclude_option(roClearOriginalCode); + } + return true; +} + +bool IntelFunction::ParseCxxSEH(IArchitecture &file, uint64_t address) +{ + if (!file.AddressSeek(address)) + return false; + + uint64_t pos, unwind_map_entry, try_block_entry, catches_entry, value, map_entry, action_entry; + uint32_t magic, max_state, try_blocks, catches, map_count; + IntelCommand *command; + CommandLink *link; + size_t i, j, c; + + uint64_t add_value = (cpu_address_size() == osDWord) ? 0 : file.image_base(); + pos = file.Tell(); + magic = file.ReadDWord(); + if (magic != 0x19930520 && magic != 0x19930521 && magic != 0x19930522) + return false; + + if (GetCommandByAddress(address)) + return true; + + file.Seek(pos); + + c = count(); + + command = Add(address); + command->set_comment(CommentInfo(ttComment, "Magic")); + command->ReadValueFromFile(file, osDWord); + command->set_alignment(OperandSizeToValue(osDWord)); + command->include_option(roCreateNewBlock); + address = command->next_address(); + + command = Add(address); + command->set_comment(CommentInfo(ttComment, "MaxState")); + max_state = static_cast(command->ReadValueFromFile(file, osDWord)); + address = command->next_address(); + + command = Add(address); + command->set_comment(CommentInfo(ttComment, "UnwindMapEntry")); + unwind_map_entry = command->ReadValueFromFile(file, osDWord); + if (unwind_map_entry) { + unwind_map_entry += add_value; + link = command->AddLink(0, ltOffset, unwind_map_entry); + link->set_sub_value(add_value); + } + address = command->next_address(); + + command = Add(address); + command->set_comment(CommentInfo(ttComment, "TryBlocks")); + try_blocks = static_cast(command->ReadValueFromFile(file, osDWord)); + address = command->next_address(); + + command = Add(address); + command->set_comment(CommentInfo(ttComment, "TryBlockMapEntry")); + try_block_entry = command->ReadValueFromFile(file, osDWord); + if (try_block_entry) { + try_block_entry += add_value; + link = command->AddLink(0, ltOffset, try_block_entry); + link->set_sub_value(add_value); + } + address = command->next_address(); + + command = Add(address); + command->set_comment(CommentInfo(ttComment, "IPMapEntries")); + map_count = static_cast(command->ReadValueFromFile(file, osDWord)); + address = command->next_address(); + + command = Add(address); + command->set_comment(CommentInfo(ttComment, "IPtoStateMap")); + map_entry = command->ReadValueFromFile(file, osDWord); + if (map_entry) { + map_entry += add_value; + link = command->AddLink(0, ltOffset, map_entry); + link->set_sub_value(add_value); + } + address = command->next_address(); + + if (file.cpu_address_size() == osQWord) { + command = Add(address); + command->set_comment(CommentInfo(ttComment, "UnwindHelp")); + command->ReadValueFromFile(file, osDWord); + address = command->next_address(); + } + + if (magic >= 0x19930521) { + command = Add(address); + command->ReadValueFromFile(file, osDWord); + command->set_comment(CommentInfo(ttComment, "ESTypeList")); + address = command->next_address(); + + if (magic == 0x19930522) { + command = Add(address); + command->ReadValueFromFile(file, osDWord); + command->set_comment(CommentInfo(ttComment, "Flags")); + //address = command->next_address(); + } + } + + if (max_state && file.AddressSeek(unwind_map_entry)) { + for (i = 0; i < max_state; i++) { + command = Add(unwind_map_entry); + command->set_comment(CommentInfo(ttComment, "ToState")); + command->ReadValueFromFile(file, osDWord); + unwind_map_entry = command->next_address(); + + command = Add(unwind_map_entry); + command->set_comment(CommentInfo(ttComment, "Action")); + action_entry = command->ReadValueFromFile(file, osDWord); + if (action_entry) { + action_entry += add_value; + link = command->AddLink(0, ltMemSEHBlock, action_entry); + link->set_parsed(true); + link->set_sub_value(add_value); + } + unwind_map_entry = command->next_address(); + } + } + + if (try_blocks && file.AddressSeek(try_block_entry)) { + for (i = 0; i < try_blocks; i++) { + command = Add(try_block_entry); + command->set_comment(CommentInfo(ttComment, "TryLow")); + command->ReadValueFromFile(file, osDWord); + try_block_entry = command->next_address(); + + command = Add(try_block_entry); + command->set_comment(CommentInfo(ttComment, "TryHigh")); + command->ReadValueFromFile(file, osDWord); + try_block_entry = command->next_address(); + + command = Add(try_block_entry); + command->set_comment(CommentInfo(ttComment, "CatchHigh")); + command->ReadValueFromFile(file, osDWord); + try_block_entry = command->next_address(); + + command = Add(try_block_entry); + command->set_comment(CommentInfo(ttComment, "Catches")); + catches = static_cast(command->ReadValueFromFile(file, osDWord)); + try_block_entry = command->next_address(); + + command = Add(try_block_entry); + command->set_comment(CommentInfo(ttComment, "HandlerArray")); + catches_entry = command->ReadValueFromFile(file, osDWord); + if (catches_entry) { + catches_entry += add_value; + link = command->AddLink(0, ltOffset, catches_entry); + link->set_sub_value(add_value); + } + try_block_entry = command->next_address(); + + pos = file.Tell(); + if (catches && file.AddressSeek(catches_entry)) { + for (j = 0; j < catches; j++) { + command = Add(catches_entry); + command->set_comment(CommentInfo(ttComment, "Adjectives")); + command->ReadValueFromFile(file, osDWord); + catches_entry = command->next_address(); + + command = Add(catches_entry); + command->set_comment(CommentInfo(ttComment, "Type")); + command->ReadValueFromFile(file, osDWord); + catches_entry = command->next_address(); + + command = Add(catches_entry); + command->set_comment(CommentInfo(ttComment, "CatchObj")); + command->ReadValueFromFile(file, osDWord); + catches_entry = command->next_address(); + + command = Add(catches_entry); + command->set_comment(CommentInfo(ttComment, "Handler")); + value = command->ReadValueFromFile(file, osDWord); + if (value) { + value += add_value; + link = command->AddLink(0, ltExtSEHHandler, value); + link->set_sub_value(add_value); + } + catches_entry = command->next_address(); + + if (cpu_address_size() == osQWord) { + command = Add(catches_entry); + command->set_comment(CommentInfo(ttComment, "Frame")); + command->ReadValueFromFile(file, osDWord); + catches_entry = command->next_address(); + } + } + file.Seek(pos); + } + } + } + + if (map_count && file.AddressSeek(map_entry)) { + AddressRange *last_range = NULL; + for (i = 0; i < map_count; i++) { + command = Add(map_entry); + command->set_comment(CommentInfo(ttComment, "Ip")); + value = command->ReadValueFromFile(file, osDWord) + add_value; + map_entry = command->next_address(); + + if (last_range && last_range->begin() < value) + last_range->set_end(value); + last_range = range_list()->Add(value, 0, command, NULL, NULL); + + command = Add(map_entry); + command->set_comment(CommentInfo(ttComment, "State")); + command->ReadValueFromFile(file, osDWord); + map_entry = command->next_address(); + } + } + + for (i = c; i < count(); i++) { + command = item(i); + command->exclude_option(roClearOriginalCode); + } + + return true; +} + +bool IntelFunction::ParseCompressedCxxSEH(IArchitecture &file, uint64_t address, uint64_t begin) +{ + // FIXME + return false; + + if (file.cpu_address_size() != osQWord || !file.AddressSeek(address)) + return false; + + uint64_t pos, unwind_map_entry, try_block_entry, catches_entry, value, map_entry, action_entry; + uint32_t max_state, try_blocks, catches, map_count; + IntelCommand *command; + CommandLink *link; + size_t old_count, i, j, k, c; + + uint64_t add_value = (cpu_address_size() == osDWord) ? 0 : file.image_base(); + + pos = file.Tell(); + uint8_t header_flags = file.ReadByte(); + if (header_flags & 4) { + command = Add(address); + command->ReadCompressedValue(file); + delete command; + } + + if (header_flags & 8) { + value = file.ReadDWord(); + if (value && (file.segment_list()->GetMemoryTypeByAddress(value + add_value) & mtReadable) == 0) + return false; + } + if (header_flags & 0x10) { + value = file.ReadDWord(); + if (value && (file.segment_list()->GetMemoryTypeByAddress(value + add_value) & mtReadable) == 0) + return false; + } + value = file.ReadDWord(); + if (file.AddressSeek(value + add_value)) { + map_entry = value + add_value; + command = Add(map_entry); + map_count = command->ReadCompressedValue(file); + + value = begin; + for (i = 0; i < map_count; i++) { + uint32_t ip = command->ReadCompressedValue(file); + command->ReadCompressedValue(file); + value += ip; + if ((file.segment_list()->GetMemoryTypeByAddress(value) & mtExecutable) == 0) { + delete command; + return false; + } + } + delete command; + } else + return false; + + if (GetCommandByAddress(address)) + return true; + + file.Seek(pos); + + old_count = count(); + + command = Add(address); + command->set_comment(CommentInfo(ttComment, "Header")); + command->ReadValueFromFile(file, osByte); + command->include_option(roCreateNewBlock); + address = command->next_address(); + + if (header_flags & 4) { + command = Add(address); + command->set_comment(CommentInfo(ttComment, "Flags")); + command->ReadCompressedValue(file); + address = command->next_address(); + } + + unwind_map_entry = 0; + if (header_flags & 8) { + command = Add(address); + command->set_comment(CommentInfo(ttComment, "UnwindMapEntry")); + unwind_map_entry = command->ReadValueFromFile(file, osDWord); + if (unwind_map_entry) { + unwind_map_entry += add_value; + link = command->AddLink(0, ltOffset, unwind_map_entry); + link->set_sub_value(add_value); + } + address = command->next_address(); + } + + try_block_entry = 0; + if (header_flags & 0x10) { + command = Add(address); + command->set_comment(CommentInfo(ttComment, "TryBlockMapEntry")); + try_block_entry = command->ReadValueFromFile(file, osDWord); + if (try_block_entry) { + try_block_entry += add_value; + link = command->AddLink(0, ltOffset, try_block_entry); + link->set_sub_value(add_value); + } + address = command->next_address(); + } + + command = Add(address); + command->set_comment(CommentInfo(ttComment, "IPtoStateMap")); + map_entry = command->ReadValueFromFile(file, osDWord); + if (map_entry) { + map_entry += add_value; + link = command->AddLink(0, ltOffset, map_entry); + link->set_sub_value(add_value); + } + address = command->next_address(); + + if (header_flags & 1) { + command = Add(address); + command->set_comment(CommentInfo(ttComment, "Frame")); + command->ReadCompressedValue(file); + address = command->next_address(); + } + + if (unwind_map_entry && file.AddressSeek(unwind_map_entry)) { + command = Add(unwind_map_entry); + command->set_comment(CommentInfo(ttComment, "MaxState")); + max_state = command->ReadCompressedValue(file); + unwind_map_entry = command->next_address(); + + for (i = 0; i < max_state; i++) { + command = Add(unwind_map_entry); + command->set_comment(CommentInfo(ttComment, "NextOffset")); + uint32_t offset = command->ReadCompressedValue(file); + unwind_map_entry = command->next_address(); + + uint8_t type = offset & 3; + if (type) { + command = Add(unwind_map_entry); + command->set_comment(CommentInfo(ttComment, "Action")); + action_entry = command->ReadValueFromFile(file, osDWord); + if (action_entry) { + action_entry += add_value; + link = command->AddLink(0, ltMemSEHBlock, action_entry); + link->set_parsed(true); + link->set_sub_value(add_value); + } + unwind_map_entry = command->next_address(); + } + + if (type == 1 || type == 2) { + command = Add(unwind_map_entry); + command->set_comment(CommentInfo(ttComment, "Object")); + command->ReadCompressedValue(file); + unwind_map_entry = command->next_address(); + } + } + } + + if (try_block_entry && file.AddressSeek(try_block_entry)) { + command = Add(try_block_entry); + command->set_comment(CommentInfo(ttComment, "TryBlocks")); + try_blocks = command->ReadCompressedValue(file); + try_block_entry = command->next_address(); + + for (i = 0; i < try_blocks; i++) { + command = Add(try_block_entry); + command->set_comment(CommentInfo(ttComment, "TryLow")); + command->ReadCompressedValue(file); + try_block_entry = command->next_address(); + + command = Add(try_block_entry); + command->set_comment(CommentInfo(ttComment, "TryHigh")); + command->ReadCompressedValue(file); + try_block_entry = command->next_address(); + + command = Add(try_block_entry); + command->set_comment(CommentInfo(ttComment, "CatchHigh")); + command->ReadCompressedValue(file); + try_block_entry = command->next_address(); + + command = Add(try_block_entry); + command->set_comment(CommentInfo(ttComment, "HandlerArray")); + catches_entry = command->ReadValueFromFile(file, osDWord) + add_value; + link = command->AddLink(0, ltOffset, catches_entry); + link->set_sub_value(add_value); + try_block_entry = command->next_address(); + + pos = file.Tell(); + if (file.AddressSeek(catches_entry)) { + command = Add(catches_entry); + command->set_comment(CommentInfo(ttComment, "Catches")); + catches = command->ReadCompressedValue(file); + catches_entry = command->next_address(); + + for (j = 0; j < catches; j++) { + command = Add(catches_entry); + command->set_comment(CommentInfo(ttComment, "Header")); + uint8_t header = static_cast(command->ReadValueFromFile(file, osByte)); + catches_entry = command->next_address(); + + if (header & 1) { + command = Add(catches_entry); + command->set_comment(CommentInfo(ttComment, "Adjectives")); + command->ReadCompressedValue(file); + catches_entry = command->next_address(); + } + + if (header & 2) { + command = Add(catches_entry); + command->set_comment(CommentInfo(ttComment, "Type")); + command->ReadValueFromFile(file, osDWord); + catches_entry = command->next_address(); + } + + if (header & 4) { + command = Add(catches_entry); + command->set_comment(CommentInfo(ttComment, "CatchObj")); + command->ReadCompressedValue(file); + catches_entry = command->next_address(); + } + + command = Add(catches_entry); + command->set_comment(CommentInfo(ttComment, "Handler")); + value = command->ReadValueFromFile(file, osDWord); + if (value) { + value += add_value; + link = command->AddLink(0, ltExtSEHHandler, value); + link->set_sub_value(add_value); + } + catches_entry = command->next_address(); + + switch ((header >> 4) & 3) { + case 1: + c = 1; + break; + case 2: + c = 2; + break; + default: + c = 0; + break; + } + for (k = 0; k < c; k++) { + command = Add(catches_entry); + command->set_comment(CommentInfo(ttComment, "ContinuationAddress")); + if (header & 8) { + value = command->ReadValueFromFile(file, osDWord) + add_value; + link = command->AddLink(0, ltMemSEHBlock, value); + link->set_sub_value(add_value); + } + else { + command->include_option(roFillNop); + value = command->ReadCompressedValue(file) + begin; + link = command->AddLink(0, ltMemSEHBlock, value); + link->set_base_function_info(function_info_list()->GetItemByAddress(begin)); + } + + catches_entry = command->next_address(); + } + } + file.Seek(pos); + } + } + } + + if (file.AddressSeek(map_entry)) { + command = Add(map_entry); + command->set_comment(CommentInfo(ttComment, "IPMapEntries")); + map_count = command->ReadCompressedValue(file); + map_entry = command->next_address(); + + value = begin; + AddressRange *last_range = NULL; + for (i = 0; i < map_count; i++) { + command = Add(map_entry); + command->set_comment(CommentInfo(ttComment, "Ip")); + value += command->ReadCompressedValue(file); + command->include_option(roFillNop); + map_entry = command->next_address(); + + if (last_range) + last_range->set_end(value); + last_range = range_list()->Add(value, 0, command, NULL, NULL); + + command = Add(map_entry); + command->set_comment(CommentInfo(ttComment, "State")); + command->ReadCompressedValue(file); + map_entry = command->next_address(); + } + } + + for (i = old_count; i < count(); i++) { + command = item(i); + command->exclude_option(roClearOriginalCode); + } + + return true; +} + +bool IntelFunction::ParseScopeSEH(IArchitecture &file, uint64_t address, uint32_t table_count) +{ + if (!file.AddressSeek(address)) + return false; + + IntelCommand *command; + CommandLink *link; + size_t i; + uint64_t value; + uint64_t image_base = file.image_base(); + + uint64_t pos = file.Tell(); + + for (i = 0; i < table_count; i++) { //-V756 + for (size_t j = 0; j < 4; j++) { + value = file.ReadDWord(); + if ((j == 0 || j == 1) && (file.segment_list()->GetMemoryTypeByAddress(value + image_base) & mtExecutable) == 0) + return false; + } + } + + if (GetCommandByAddress(address)) + return true; + + file.Seek(pos); + + size_t c = count(); + + for (i = 0; i < table_count; i++) { + IntelCommand *begin_entry = command = Add(address); + begin_entry->set_comment(CommentInfo(ttComment, "Begin")); + uint64_t begin_address = begin_entry->ReadValueFromFile(file, osDWord) + image_base; + address = begin_entry->next_address(); + + IntelCommand *end_entry = Add(address); + end_entry->set_comment(CommentInfo(ttComment, "End")); + uint64_t end_address = end_entry->ReadValueFromFile(file, osDWord) + image_base; + address = end_entry->next_address(); + + range_list()->Add(begin_address, end_address, begin_entry, end_entry, NULL); + + command = Add(address); + command->set_comment(CommentInfo(ttComment, "Filter")); + value = command->ReadValueFromFile(file, osDWord); + if (value > 1) { + value += image_base; + pos = file.Tell(); + if (ParseDelphiSEH(file, value)) { + link = command->AddLink(0, ltOffset, value); + } else { + link = command->AddLink(0, ltMemSEHBlock, value); + command->include_option(roExternal); + } + link->set_sub_value(image_base); + file.Seek(pos); + } + address = command->next_address(); + + command = Add(address); + command->set_comment(CommentInfo(ttComment, "Handler")); + value = command->ReadValueFromFile(file, osDWord); + if (value) { + value += image_base; + link = command->AddLink(0, ltMemSEHBlock, value); + link->set_sub_value(image_base); + } + address = command->next_address(); + }; + + for (i = c; i < count(); i++) { + command = item(i); + command->exclude_option(roClearOriginalCode); + } + + return true; +} + +bool IntelFunction::ParseNewSEH(IArchitecture &file, uint64_t address) +{ + size_t i; + IntelCommand *command; + + IntelFunction func(NULL, cpu_address_size(), this); + func.ReadFromFile(file, address); + command = func.GetCommandByAddress(address); + if (command) { + for (i = func.IndexOf(command) + 1; i < func.count(); i++) { + command = func.item(i); + if (command->type() == cmJmp + && command->operand(0).type == otValue + && (command->operand(0).value < address || func.GetCommandByAddress(command->operand(0).value) == NULL)) { + command = func.item(i - 1); + if (command->type() == cmMov + && command->operand(0).type == otRegistr + && command->operand(0).registr == regEAX + && command->operand(1).type == otValue) { + return ParseCxxSEH(file, command->operand(1).value); + } + } + } + } + + return false; +} + +bool IntelFunction::ParseVB6SEH(IArchitecture &file, uint64_t address) +{ + if (!file.AddressSeek(address)) + return false; + + uint64_t pos = file.Tell(); + + size_t i, k, table_count; + uint32_t flags; + uint64_t value; + IntelCommand *command; + //CommandLink *link; + + flags = file.ReadDWord(); + switch (flags >> 16) { + case 0x04: + case 0x08: + case 0x0c: + case 0x10: + case 0x14: + break; + default: + return false; + } + + k = (flags & 0xffff0007) == 0x80001 ? 1 : 3; + for (table_count = 0;; table_count++) { + bool is_ok = true; + for (i = 0; i < k; i++) { + value = file.ReadDWord(); + if (value != 0 && (file.segment_list()->GetMemoryTypeByAddress(value) & mtExecutable) == 0) { + is_ok = false; + break; + } + } + if (!is_ok) + break; + } + + if (!table_count) + return false; + + file.Seek(pos); + + size_t c = count(); + + command = Add(address); + command->ReadValueFromFile(file, osDWord); + address = command->next_address(); + + for (i = 0; i < k; i++) { + command = Add(address); + value = command->ReadValueFromFile(file, osDWord); + if (value) + command->AddLink(0, ltVBMemSEHBlock, value); + address = command->next_address(); + } + + if (flags & 0x30) { + command = Add(address); + uint64_t ext_info = command->ReadValueFromFile(file, osDWord); + address = command->next_address(); + + command = Add(address); + uint64_t address_info = command->ReadValueFromFile(file, osDWord); + address = command->next_address(); + + if (ext_info && file.AddressSeek(ext_info)) { + address = ext_info; + + command = Add(address); + command->ReadValueFromFile(file, osDWord); + address = command->next_address(); + + command = Add(address); + command->ReadValueFromFile(file, osDWord); + address = command->next_address(); + + command = Add(address); + value = command->ReadValueFromFile(file, osDWord); + if (value) + command->AddLink(0, ltVBMemSEHBlock, value); + address = command->next_address(); + } + + if (address_info && file.AddressSeek(address_info)) { + address = address_info; + + command = Add(address); + size_t array_count = static_cast(command->ReadValueFromFile(file, osDWord)); + address = command->next_address(); + + for (i = 0; i < array_count; i++) { + command = Add(address); + value = command->ReadValueFromFile(file, osDWord); + if (value) + command->AddLink(0, ltVBMemSEHBlock, value); + address = command->next_address(); + } + } + } + + for (i = c; i < count(); i++) { + command = item(i); + command->exclude_option(roClearOriginalCode); + } + + return true; +} + +bool IntelFunction::ParseDelphiSEH(IArchitecture &file, uint64_t address) +{ + if (!file.AddressSeek(address)) + return false; + + IntelCommand *command; + size_t i, j; + uint64_t value; + + size_t c = count(); + uint64_t image_base = file.image_base(); + uint64_t pos = file.Tell(); + + uint32_t table_count = file.ReadDWord(); + for (i = 0; i < table_count; i++) { + for (j = 0; j < 2; j++) { + value = file.ReadDWord(); + if (!value) + continue; + + value += image_base; + if ((file.segment_list()->GetMemoryTypeByAddress(value) & (j == 1 ? mtExecutable : mtReadable)) == 0) + return false; + } + } + + file.Seek(pos); + + command = Add(address); + command->ReadValueFromFile(file, osDWord); + command->set_comment(CommentInfo(ttComment, "Count")); + address = command->next_address(); + + for (size_t i = 0; i < table_count; i++) { + command = Add(address); + command->ReadValueFromFile(file, osDWord); + command->set_comment(CommentInfo(ttComment, "Type")); + address = command->next_address(); + + command = Add(address); + value = command->ReadValueFromFile(file, osDWord); + if (value) { + value += image_base; + CommandLink *link = command->AddLink(0, ltMemSEHBlock, value); + link->set_sub_value(image_base); + } + command->set_comment(CommentInfo(ttComment, "Handler")); + address = command->next_address(); + } + + for (i = c; i < count(); i++) { + command = item(i); + command->exclude_option(roClearOriginalCode); + } + + return true; +} + +bool IntelFunction::ParseBCBSEH(IArchitecture &file, uint64_t address, uint64_t next_address, uint8_t version) +{ + if (!file.AddressSeek(address)) + return false; + + uint64_t base_address = address; + IntelCommand *command; + size_t c = count(); + + if (version == 2) { + command = Add(address); + command->ReadValueFromFile(file, osDWord); + command->set_comment(CommentInfo(ttComment, "ThrowLst")); + address = command->next_address(); + } + + command = Add(address); + command->ReadValueFromFile(file, osDWord); + command->set_comment(CommentInfo(ttComment, "VirtCondOffs")); + address = command->next_address(); + + command = Add(address); + uint64_t bp_offset = command->ReadValueFromFile(file, osDWord); + command->set_comment(CommentInfo(ttComment, "BPoffs")); + + //std::vector ctx_list; + { + uint64_t bcb_seh_operand = IntelOperand(otMemory | otRegistr | otValue, osWord, regEBP, bp_offset + 0x10).encode(); + IntelFunction tmp(NULL, file.cpu_address_size(), this); + address = next_address; + for (;;) { + command = NULL; + if (file.segment_list()->GetMemoryTypeByAddress(address) & mtExecutable) { + if (file.AddressSeek(address)) { + command = tmp.ParseCommand(file, address); + if (command && command->type() == cmMov && command->operand(0).encode() == bcb_seh_operand && command->operand(1).type == otValue) { + uint16_t bcb_ctx = static_cast(command->operand(1).value); + size_t old_count = link_list()->count(); + IntelCommand *orig = command; + while (bcb_ctx) { + address = base_address + bcb_ctx; + + if (GetCommandByAddress(address)) + break; + + if (!file.AddressSeek(address)) + break; + + command = Add(address); + bcb_ctx = static_cast(command->ReadValueFromFile(file, osWord)); + command->set_comment(CommentInfo(ttComment, "Outer")); + address = command->next_address(); + + command = Add(address); + uint16_t kind = static_cast(command->ReadValueFromFile(file, osWord)); + command->set_comment(CommentInfo(ttComment, "Kind")); + address = command->next_address(); + + uint64_t value; + switch (kind) { + case 0: + command = Add(address); + command->ReadValueFromFile(file, osDWord); + command->set_comment(CommentInfo(ttComment, "Reserved")); + address = command->next_address(); + + command = Add(address); + value = command->ReadValueFromFile(file, osDWord); + if (value) + command->AddLink(0, ltMemSEHBlock, value); + command->set_comment(CommentInfo(ttComment, "Handler")); + break; + case 1: + case 2: + command = Add(address); + value = command->ReadValueFromFile(file, osDWord); + if (kind == 1 && value) + command->AddLink(0, ltMemSEHBlock, value); + command->set_comment(CommentInfo(ttComment, "Filter")); + address = command->next_address(); + + command = Add(address); + value = command->ReadValueFromFile(file, osDWord); + if (value) + command->AddLink(0, ltMemSEHBlock, value); + command->set_comment(CommentInfo(ttComment, "Handler")); + break; + case 3: + { + command = Add(address); + address = command->ReadValueFromFile(file, osDWord); + command->set_comment(CommentInfo(ttComment, "Table")); + command->AddLink(0, ltOffset, address); + + if (file.AddressSeek(address)) { + command = Add(address); + command->ReadValueFromFile(file, osDWord); + command->set_comment(CommentInfo(ttComment, "ArgAddr")); + address = command->next_address(); + + command = Add(address); + command->ReadValueFromFile(file, osDWord); + command->set_comment(CommentInfo(ttComment, "ArgSize")); + address = command->next_address(); + + while (true) { + command = Add(address); + value = command->ReadValueFromFile(file, osDWord); + if (value) { + command->AddLink(0, ltMemSEHBlock, value); + } else { + delete command; + break; + } + command->set_comment(CommentInfo(ttComment, "Handler")); + address = command->next_address(); + + command = Add(address); + command->ReadValueFromFile(file, osDWord); + command->set_comment(CommentInfo(ttComment, "TypeID")); + address = command->next_address(); + + command = Add(address); + command->ReadValueFromFile(file, osDWord); + command->set_comment(CommentInfo(ttComment, "Flags")); + address = command->next_address(); + + command = Add(address); + command->ReadValueFromFile(file, osDWord); + command->set_comment(CommentInfo(ttComment, "CctrAddr")); + address = command->next_address(); + + command = Add(address); + command->ReadValueFromFile(file, osDWord); + command->set_comment(CommentInfo(ttComment, "CctrMask")); + address = command->next_address(); + } + } + } + break; + case 4: + break; + case 5: + command = Add(address); + command->ReadValueFromFile(file, osDWord); + command->set_comment(CommentInfo(ttComment, "MinCount")); + address = command->next_address(); + + command = Add(address); + command->ReadValueFromFile(file, osDWord); + command->set_comment(CommentInfo(ttComment, "Table")); + break; + } + } + for (size_t i = old_count; i < link_list()->count(); i++) { + CommandLink *src_link = link_list()->item(i); + CommandLink *dst_link = src_link->Clone(tmp.link_list()); + tmp.link_list()->AddObject(dst_link); + dst_link->set_from_command(tmp.Add(src_link->from_command()->address())); + } + command = orig; + } + } + } + if (!command || command->is_end() || (command->options() & roBreaked) != 0) { + address = tmp.GetNextAddress(file); + if (!address) + break; + } else { + address = command->next_address(); + } + } + } + + for (size_t i = c; i < count(); i++) { + command = item(i); + command->exclude_option(roClearOriginalCode); + } + + return true; +} + +IntelCommand *IntelFunction::ParseString(IArchitecture &file, uint64_t address, size_t len) +{ + if (!file.AddressSeek(address)) + return NULL; + + IntelCommand *command = Add(address); + command->ReadArray(file, len); + command->exclude_option(roNeedCompile); + return command; +} + +void IntelFunction::ParseBeginCommands(IArchitecture &file) +{ + if (type() == otMarker || type() == otAPIMarker) { + CompilerFunction *func = file.compiler_function_list()->GetFunctionByLowerAddress(address()); + if (func && (func->type() == cfCxxSEH || func->type() == cfCxxSEH3 || func->type() == cfCxxSEH4 || func->type() == cfBCBSEH || func->type() == cfVB6SEH)) { + IntelFunction tmp(NULL, cpu_address_size()); + tmp.ReadFromFile(file, func->address()); + if (tmp.GetCommandByAddress(address())) { + switch (func->type()) { + case cfCxxSEH: + ParseNewSEH(file, func->value(0)); + break; + case cfCxxSEH3: + ParseSEH3(file, func->value(0)); + break; + case cfCxxSEH4: + ParseSEH4(file, func->value(0)); + break; + case cfBCBSEH: + ParseBCBSEH(file, func->value(0), address(), static_cast(func->value(1))); + break; + case cfVB6SEH: + ParseVB6SEH(file, func->value(0)); + break; + } + } + } + } +} + +void IntelFunction::ParseEndCommands(IArchitecture &file) +{ + if (type() == otMarker) { + uint64_t len_address = address() + 1; + if (file.AddressSeek(len_address)) { + uint8_t len = file.ReadByte(); + ParseString(file, len_address + 1, len); + } + } + + if (type() == otMarker || type() == otAPIMarker) { + std::vector entry_command_list; + std::vector exclude_command_list; + size_t i, j, k; + + /* + for (i = 0; i < link_list()->count(); i++) { + CommandLink *link = link_list()->item(i); + if (link->type() == ltMemSEHBlock || link->type() == ltExtSEHHandler) { + IntelCommand *command = GetCommandByAddress(link->to_address()); + if (command && std::find(entry_command_list.begin(), entry_command_list.end(), command) == entry_command_list.end()) + entry_command_list.push_back(command); + } + } + */ + + for (i = 0; i < file.end_marker_list()->count(); i++) { + MarkerCommand *marker_command = file.end_marker_list()->item(i); + IntelCommand *command = GetCommandByNearAddress(marker_command->address()); + if (command) { + if (marker_command->type() == otMarker) { + uint64_t len_address = command->address() + 1; + if (file.AddressSeek(len_address)) { + uint8_t len = file.ReadByte(); + command = ParseString(file, len_address + 1, len); + } + } else { + if (!command->is_end()) + command->include_option(roBreaked); + } + command = GetCommandByAddress(command->next_address()); + if (command && std::find(entry_command_list.begin(), entry_command_list.end(), command) == entry_command_list.end()) + entry_command_list.push_back(command); + } else { + for (size_t j = 0; j < link_list()->count(); j++) { + CommandLink *link = link_list()->item(j); + if ((link->type() == ltJmp || link->type() == ltJmpWithFlag) && link->to_address() && link->to_address() > link->from_command()->address() && marker_command->address() > link->from_command()->next_address() && marker_command->address() < link->to_address()) { + command = GetCommandByAddress(link->to_address()); + if (command && std::find(entry_command_list.begin(), entry_command_list.end(), command) == entry_command_list.end()) + entry_command_list.push_back(command); + } + } + } + } + + Sort(); + for (i = 0; i < entry_command_list.size(); i++) { + ICommand *entry_command = entry_command_list[i]; + + size_t n = IndexOf(entry_command); + if (n > 0) { + IntelCommand *command = item(n - 1); + if (!command->is_end()) + command->include_option(roBreaked); + } + for (j = n; j < count(); j++) { + IntelCommand *command = item(j); + + if (std::find(exclude_command_list.begin(), exclude_command_list.end(), command) != exclude_command_list.end()) + break; + + exclude_command_list.push_back(command); + + for (k = 0; k < link_list()->count(); k++) { + CommandLink *link = link_list()->item(k); + if (link->parent_command() == command && std::find(entry_command_list.begin(), entry_command_list.end(), link->from_command()) == entry_command_list.end()) + entry_command_list.push_back(link->from_command()); + } + + CommandLink *link = command->link(); + if (link && link->to_address()) { + IntelCommand *link_command = GetCommandByAddress(link->to_address()); + if (link_command && std::find(entry_command_list.begin(), entry_command_list.end(), link_command) == entry_command_list.end()) + entry_command_list.push_back(link_command); + } + + if (command->is_end()) + break; + } + } + + for (i = 0; i < exclude_command_list.size(); i++) { + ICommand *command = exclude_command_list[i]; + + for (j = 0; j < range_list()->count(); j++) { + AddressRange *range = range_list()->item(j); + if (range->begin_entry() == command) + range->set_begin_entry(NULL); + if (range->end_entry() == command) + range->set_end_entry(NULL); + if (range->size_entry() == command) + range->set_size_entry(NULL); + } + for (j = 0; j < function_info_list()->count(); j++) { + FunctionInfo *info = function_info_list()->item(j); + if (info->entry() == command) + info->set_entry(NULL); + for (k = 0; k < info->count(); k++) { + AddressRange *range = info->item(k); + if (range->begin_entry() == command) + range->set_begin_entry(NULL); + if (range->end_entry() == command) + range->set_end_entry(NULL); + if (range->size_entry() == command) + range->set_size_entry(NULL); + } + } + + if (command->link()) + delete command->link(); + delete command; + } + } +} + +uint64_t IntelFunction::GetNextAddress(IArchitecture &file) +{ + uint64_t res = BaseFunction::GetNextAddress(file); + if (res) + return res; + + size_t c = link_list()->count(); + for (size_t i = 0; i < c; i++) { + CommandLink *link = link_list()->item(i); + switch (link->type()) { + case ltJmp: + if (type() == otMarker && !link->parsed() && link->to_address() == address() + 0x12) { + link->set_parsed(true); + return link->to_address(); + } + break; + case ltDualSEHBlock: + if (!link->next_command()) { + IntelCommand *command = GetCommandByAddress(link->to_address()); + if (command) { + IntelCommand *next_command = GetCommandByAddress(command->next_address()); + if (next_command) + link->set_next_command(next_command); + else + return command->next_address(); + } + } + break; + case ltExtSEHHandler: + if (!link->next_command()) { + size_t k = IndexOf(GetCommandByAddress(link->to_address())); + if (k == NOT_ID) + continue; + + std::set stack; + stack.insert(k); + while (!stack.empty()) { + k = *stack.begin(); + + for (size_t j = k; j < count(); j++) { + std::set::const_iterator it = stack.find(j); + if (it != stack.end()) + stack.erase(it); + + IntelCommand *command = item(j); + if (command->options() & roBreaked) + break; + + if (command->type() == cmJmpWithFlag && command->operand(0).type == otValue) { + IntelCommand *to_command = GetCommandByAddress(command->operand(0).value); + if (to_command) { + k = IndexOf(to_command); + if (k != NOT_ID && k > j) + stack.insert(k); + } + } + + if (command->type() != cmRet && command->type() != cmJmp) + continue; + + if (command->type() == cmJmp && command->operand(0).type == otValue) { + IntelCommand *tmp = GetCommandByAddress(command->operand(0).value - 8); + if (tmp && tmp->type() == cmPush && tmp->operand(0).type == otValue) { + IntelCommand *next = GetCommandByAddress(tmp->next_address()); + if (next && next->type() == cmAdd && next->operand(0).type == (otMemory | otBaseRegistr) && next->operand(0).base_registr == regESP && next->operand(1).type == otRegistr && next->operand(1).registr == regEBX) { + link->set_next_command(tmp); + if (!tmp->link()) + tmp->AddLink(0, ltSEHBlock, tmp->operand(0).value); + } + } + + IntelCommand *to_command = GetCommandByAddress(command->operand(0).value); + if (to_command) { + k = IndexOf(to_command); + if (k != NOT_ID && k > j) { + j = k - 1; + continue; + } + } + } + + for (size_t n = j; n > k; n--) { + command = item(n - 1); + if (command->operand(0).type == otRegistr && command->operand(0).registr == regEAX && command->operand(0).size == cpu_address_size() && + ((command->type() == cmLea && command->operand(1).type == (otMemory | otValue)) || (command->type() == cmMov && command->operand(1).type == otValue))) { + link->set_next_command(command); + if (!command->link()) + command->AddLink(1, ltSEHBlock, command->operand(1).value); + break; + } + } + break; + } + } + } + } + } + if (link_list()->count() > c) + return GetNextAddress(file); + + return 0; +} + +uint64_t IntelFunction::GetRegistrValue(uint8_t reg, size_t end_index) +{ + std::map address_list; + IntelCommand *mov_command = NULL; + IntelCommandInfoList command_info_list(cpu_address_size()); + for (size_t i = 0; i <= end_index; i++) { + IntelCommand *command = item(i); + if (command->is_data()) + continue; + + std::map::iterator it = address_list.find(command->address()); + if (it != address_list.end()) { + if (mov_command && it->second) { + if (mov_command != it->second && !mov_command->is_equal(*it->second)) + mov_command = NULL; + } else { + mov_command = it->second; + } + } + + if (i == end_index) + break; + + CommandLink *link = command->link(); + if (link && link->type() != ltOffset && link->to_address()) { + std::map::iterator it = address_list.find(link->to_address()); + if (it != address_list.end()) { + if (it->second != mov_command) + it->second = NULL; + } else { + address_list[link->to_address()] = mov_command; + } + } + + if (command->is_end() || (command->options() & roBreaked) != 0) + mov_command = NULL; + else if (command->GetCommandInfo(command_info_list) && command_info_list.GetInfo(atWrite, otRegistr, reg)) + mov_command = command; + } + + return (mov_command && mov_command->type() == cmLea && mov_command->operand(1).type == (otValue | otMemory)) ? mov_command->operand(1).value : (uint64_t)-1; +} + +uint64_t IntelFunction::GetRegistrMaxValue(uint8_t reg, size_t end_index, IArchitecture &file) +{ + IntelCommandInfoList command_info_list(cpu_address_size()); + IntelCommand *jmp_command = NULL; + IntelOperand find_operand = IntelOperand(otRegistr, cpu_address_size(), reg); + for (size_t i = end_index; i > 0; i--) { + IntelCommand *command = item(i - 1); + if ((command->options() & roBreaked) || command->is_end()) { + CommandLink *link = link_list()->GetLinkByToAddress(ltJmpWithFlag, item(i)->address()); + if (!link) + link = link_list()->GetLinkByToAddress(ltJmp, item(i)->address()); + if (link) { + command = reinterpret_cast(link->from_command()); + if (link->type() == ltJmpWithFlag && command->flags() == (fl_C | fl_Z) && (command->options() & roInverseFlag) == 0) + jmp_command = command; + size_t index = IndexOf(command); + if (index != NOT_ID) { + i = index + 1; + continue; + } + } + break; + } + switch (command->type()) { + case cmJmpWithFlag: + if (command->flags() == (fl_C | fl_Z) && (command->options() & roInverseFlag)) + jmp_command = command; + break; + case cmCmp: + if (command->operand(0) == find_operand) { + if (command->operand(1).type == otValue && jmp_command) + return command->operand(1).value; + } + break; + case cmMovsx: case cmMovsxd: + if (command->operand(0) == find_operand) + find_operand = command->operand(1); + break; + case cmMov: + case cmMovzx: + if (command->operand(0) == find_operand) { + find_operand = command->operand(1); + if ((command->operand(1).type & otMemory) && command->operand(1).size == osByte) { + uint64_t max_count = GetRegistrMaxValue(command->operand(1).registr, i - 1, file); + if (max_count != (uint64_t)-1) { + uint64_t base_address = 0; + if (command->operand(1).type & otBaseRegistr) { + if (cpu_address_size() == osQWord) { + base_address = GetRegistrValue(command->operand(1).base_registr, i); + } + else { + base_address = file.compiler_function_list()->GetRegistrValue(command->address(), IntelOperand(otRegistr, cpu_address_size(), command->operand(1).base_registr).encode()); + } + if (base_address == (uint64_t)-1) + break; + } + if (!file.AddressSeek(base_address + command->operand(1).value)) + break; + uint8_t res = 0; + for (uint64_t j = 0; j <= max_count; j++) { + uint8_t b = file.ReadByte(); + if (b > res) + res = b; + } + return res; + } + } + } + break; + case cmCall: + if (command->operand(0).type != otValue || command->operand(0).value != command->next_address()) + command = NULL; + break; + case cmAnd: + if (command->operand(0).type == otRegistr && command->operand(0).registr == find_operand.registr && static_cast(command->operand(1).value) == 0xffffffff) + break; + // fall-through + default: + if (!command->GetCommandInfo(command_info_list)) + command = NULL; + else if ((find_operand.type & otRegistr) && command_info_list.GetInfo(atWrite, otRegistr, find_operand.registr)) + command = NULL; + else if ((find_operand.type & otBaseRegistr) && command_info_list.GetInfo(atWrite, otRegistr, find_operand.base_registr)) + command = NULL; + break; + } + if (!command) + break; + } + return (uint64_t)-1; +} + +CompilerFunction *IntelFunction::ParseCompilerFunction(IArchitecture &file, uint64_t address) +{ + CompilerFunction *compiler_function = file.compiler_function_list()->GetFunctionByAddress(address); + if (!compiler_function && (file.segment_list()->GetMemoryTypeByAddress(address) & mtExecutable)) { + IFunction *tmp_parent = this; + size_t stack_depth = 0; + bool in_parent_list = false; + while (tmp_parent) { + if (tmp_parent->GetCommandByAddress(address)) { + in_parent_list = true; + break; + } + tmp_parent = tmp_parent->parent(); + if ((stack_depth++) > 1000) + return NULL; + } + if (in_parent_list) + return NULL; + + IntelFunction func(NULL, cpu_address_size(), this); + func.ReadFromFile(file, address); + IntelCommand *entry = func.GetCommandByAddress(address); + if (entry) { + std::set entry_stack; + std::set end_command_list; + std::set parsed_command_list; + + entry_stack.insert(func.IndexOf(entry)); + while (!entry_stack.empty()) { + for (size_t i = *entry_stack.begin(); i < func.count(); i++) { + IntelCommand *command = func.item(i); + std::set::const_iterator it = entry_stack.find(i); + if (it != entry_stack.end()) + entry_stack.erase(it); + + if (parsed_command_list.find(command) != parsed_command_list.end()) + break; + parsed_command_list.insert(command); + + switch (command->type()) { + case cmRet: + case cmIret: + if (cpu_address_size() == osQWord && i > 0) { + IntelCommand *prev = func.item(i - 1); + if (prev->type() == cmMov && prev->operand(0).type == otRegistr && prev->operand(0).registr == regESP) { + // mov rsp, xxxx + command->include_option(roBreaked); + } + } + end_command_list.insert(command); + break; + case cmJmpWithFlag: + { + IntelCommand *link_command = func.GetCommandByAddress(command->operand(0).value); + if (link_command) + entry_stack.insert(func.IndexOf(link_command)); + } + break; + case cmJmp: + { + bool is_end = true; + compiler_function = file.compiler_function_list()->GetFunctionByAddress(command->address()); + if (compiler_function && (compiler_function->options() & coNoReturn) != 0) + command->include_option(roBreaked); + + if (command->operand(0).type == (otValue | otMemory)) { + if (IRelocation *reloc = file.relocation_list() ? file.relocation_list()->GetRelocationByAddress(command->operand(0).value) : NULL) { + if (reloc->symbol()) { + compiler_function = func.ParseCompilerFunction(file, reloc->symbol()->address()); + if (compiler_function && (compiler_function->options() & coNoReturn) != 0) + command->include_option(roBreaked); + } + } + } + else if (command->operand(0).type == otValue) { + IntelCommand *link_command = func.GetCommandByAddress(command->operand(0).value); + if (link_command) { + entry_stack.insert(func.IndexOf(link_command)); + is_end = false; + } + else { + compiler_function = func.ParseCompilerFunction(file, command->operand(0).value); + if (compiler_function && (compiler_function->options() & coNoReturn) != 0) + command->include_option(roBreaked); + } + } + else if (command->link() && (command->link()->type() == ltSwitch || command->link()->type() == ltOffset)) { + ICommand *parent_command; + if (command->link()->type() == ltSwitch) + parent_command = command; + else { + parent_command = func.GetCommandByAddress(command->link()->to_address()); + parent_command = (parent_command && parent_command->link()) ? parent_command->link()->parent_command() : NULL; + } + + if (parent_command) { + is_end = false; + for (size_t j = 0; j < func.link_list()->count(); j++) { + CommandLink *link = func.link_list()->item(j); + if (link->parent_command() == parent_command) { + IntelCommand *link_command = func.GetCommandByAddress(link->to_address()); + if (link_command) + entry_stack.insert(func.IndexOf(link_command)); + } + } + } + } + + if (is_end) + end_command_list.insert(command); + } + break; + } + + if (command->options() & roBreaked) { + end_command_list.insert(command); + break; + } + + if (command->is_end()) + break; + } + } + + compiler_function = file.compiler_function_list()->Add(cfNone, address); + if (!end_command_list.empty()) { + size_t no_return_count = 0; + for (std::set::const_iterator it = end_command_list.begin(); it != end_command_list.end(); it++) { + IntelCommand *tmp_command = *it; + if (tmp_command->options() & roBreaked) + no_return_count++; + } + + if (no_return_count == end_command_list.size()) + compiler_function->include_option(coNoReturn); + } + } + } + + return compiler_function; +} + +IntelCommand *IntelFunction::ParseCommand(IArchitecture &file, uint64_t address, bool dump_mode) +{ + CommandLink *command_link; + IntelCommand *command, *prev; + size_t i, c; + CommandLinkList *links; + IImportFunction *import_function; + CompilerFunction *compiler_function; + uint64_t base_address; + + if (dump_mode) { + command = Add(address); + if (!file.AddressSeek(address)) + command->InitUnknown(); + else if ((file.selected_segment()->memory_type() & mtExecutable) == 0) + command->ReadValueFromFile(file, osByte); + else { + command->ReadFromFile(file); + switch (command->type()) { + case cmJmp: + case cmCall: + case cmJmpWithFlag: case cmJCXZ: case cmLoop: case cmLoope: case cmLoopne: + if ((command->options() & roFar) == 0 && command->operand(0).type == otValue) + command->AddLink(0, ltNone, command->operand(0).value); + break; + } + } + return command; + } else { + if (!file.AddressSeek(address)) + return NULL; + } + + command = Add(address); + command->ReadFromFile(file); + + links = link_list(); + switch (command->type()) { + case cmDB: + command->include_option(roInvalidOpcode); + break; + + case cmAdd: + if (command->dump_size() == 2 && command->dump(0) == 0 && command->dump(1) == 0) { + delete command; + command = NULL; + } + break; + + case cmCall: + if ((command->options() & roFar) == 0) { + if (command->operand(0).type == otValue && !command->operand(0).relocation) + command->AddLink(0, ltCall, command->operand(0).value); + else + command->AddLink(-1, ltCall); + + if (command->operand(0).type == (otValue | otMemory)) { + // check import + import_function = file.import_list()->GetFunctionByAddress(command->operand(0).value); + if (import_function != NULL && (import_function->options() & ioNoReturn) != 0) + command->include_option(roBreaked); + } else if (command->operand(0).type == otValue) { + // check compiler function + compiler_function = ParseCompilerFunction(file, command->operand(0).value); + if (compiler_function) { + if (compiler_function->options() & coNoReturn) + command->include_option(roBreaked); + + switch (compiler_function->type()) { + case cfInitBCBSEH: + if (compiler_function->value(0)) { + CompilerFunction *func = file.compiler_function_list()->GetFunctionByLowerAddress(address); + if (func && func->type() == cfBCBSEH) + ParseBCBSEH(file, func->value(0), command->next_address(), static_cast(func->value(1))); + } + break; + case cfSEH4Prolog: + if (count() > 1) { + prev = item(count() - 2); + if (prev->type() == cmPush && prev->operand(0).type == otValue) { + if (ParseSEH4(file, prev->operand(0).value)) + prev->AddLink(0, ltOffset, prev->operand(0).value); + } + } + } + } + } + } + break; + + case cmJmp: + if ((command->options() & roFar) == 0) { + if (command->operand(0).type == otValue) { // jmp xxxx + if (!command->operand(0).relocation) + command->AddLink(0, ltJmp, command->operand(0).value); + + if (cpu_address_size() == osDWord) { + if (count() > 1) { + i = count() - 2; + prev = item(i); + if (prev->type() == cmPush && prev->operand(0).type == otValue) { + command_link = links->GetLinkByToAddress(ltVBMemSEHBlock, command->operand(0).value); + if (command_link || (file.AddressSeek(command->operand(0).value) && file.ReadByte() == 0xc3)) + prev->AddLink(0, ltFinallyBlock, prev->operand(0).value); + } + } + + command_link = links->GetLinkByToAddress(ltSEHBlock, command->address()); + if (command_link) { + i = count(); + if (ParseFilterSEH(file, command->next_address())) { + command_link->set_type(ltFilterSEHBlock); + command_link->set_parent_command(item(i)); + } else { + command_link->set_type(ltDualSEHBlock); + } + } + } + } else if (command->operand(0).type == (otValue | otMemory | otRegistr) && command->operand(0).size == cpu_address_size() && command->operand(0).scale_registr == (cpu_address_size() == osDWord ? 2 : 3)) { // jmp dword ptr [reg*4 + xxxx] + if (ParseSwitch(file, command->operand(0).value, command->operand(0).size, 0, command, 0, static_cast(GetRegistrMaxValue(command->operand(0).registr, IndexOf(command), file)))) + command->AddLink(0, ltSwitch, command->operand(0).value); + else if (count() == 0) + return ParseCommand(file, this->address(), dump_mode); + } else if (command->operand(0).type == otRegistr && count() > 1) { // jmp reg + prev = NULL; + IntelCommandInfoList command_info(cpu_address_size()); + if (count() > 2) { + for (i = count() - 2; i > 0; i--) { + IntelCommand *tmp = item(i); + if (!tmp->GetCommandInfo(command_info) || command_info.GetInfo(atWrite, otBaseRegistr, regEIP)) + break; + if (command_info.GetInfo(atWrite, otRegistr, command->operand(0).registr)) { + prev = tmp; + break; + } + } + } + if (prev) { + if ((prev->type() == cmAdd || prev->type() == cmSub) + && prev->operand(0).type == otRegistr + && prev->operand(0).size == cpu_address_size() + && prev->operand(0).registr == command->operand(0).registr) { + uint8_t base_registr; + base_address = 0; + if (prev->operand(1).type == otRegistr) { + base_registr = prev->operand(1).registr; + prev = NULL; + for (c = i; c > 0; c--) { + IntelCommand *tmp = item(c - 1); + if (tmp->type() == cmMov && tmp->operand(0).type == otRegistr && tmp->operand(1).type == otRegistr && tmp->operand(0).registr == base_registr) + base_registr = tmp->operand(1).registr; + else if (tmp->type() == cmLea && tmp->operand(0).type == otRegistr && tmp->operand(1).type == (otMemory | otValue) && tmp->operand(0).registr == base_registr) + base_address = tmp->operand(1).value; + else if ((tmp->type() == cmMov || tmp->type() == cmMovsxd) + && tmp->operand(0).type == otRegistr + && tmp->operand(0).registr == command->operand(0).registr) { + i = c - 1; + prev = tmp; + break; + } + else { + if (!tmp->GetCommandInfo(command_info) || command_info.GetInfo(atWrite, otRegistr, command->operand(0).registr)) + break; + } + } + } + else { + base_registr = prev->operand(0).registr; + } + if (prev) { + if ((prev->operand(1).type & (otMemory | otBaseRegistr | otRegistr)) == (otMemory | otBaseRegistr | otRegistr) + && prev->operand(1).scale_registr == 2 + && prev->operand(1).size == osDWord) { // add/mov/movsx reg, [reg1 + reg2*4 + xxxx] + if (!base_address) { + if (cpu_address_size() == osQWord) { + base_address = GetRegistrValue(prev->operand(1).base_registr, i); + } + else { + IntelOperand base_operand = IntelOperand(otRegistr, cpu_address_size(), base_registr); + if (i > 0) { + IntelCommand *tmp = item(i - 1); + if (tmp->type() == cmMov + && tmp->operand(0).type == otRegistr + && tmp->operand(0).registr == base_registr) { + base_operand = tmp->operand(1); + } + } + base_address = file.compiler_function_list()->GetRegistrValue(command->address(), base_operand.encode()); + } + } + if (base_address != (uint64_t)-1) { + size_t mode; + switch (prev->type()) { + case cmMovsxd: + mode = 1; + break; + case cmSub: + mode = 2; + break; + default: + mode = 0; + break; + } + if (ParseSwitch(file, base_address + prev->operand(1).value, osDWord, base_address, command, mode, static_cast(GetRegistrMaxValue(prev->operand(1).registr, IndexOf(prev), file)))) { + command_link = prev->AddLink(1, ltSwitch, base_address + prev->operand(1).value); + command_link->set_sub_value(base_address); + command->AddLink(-1, ltOffset, command_link->to_address()); + } + else if (count() == 0) + return ParseCommand(file, this->address(), dump_mode); + } + } + else if (prev->type() == cmAdd + && prev->operand(1).type == (otMemory | otRegistr | otValue) + && prev->operand(1).scale_registr == 2 + && prev->operand(1).size == osDWord + && prev->operand(0).registr == base_registr) { // add reg, [reg1*4 + xxxx] + if (cpu_address_size() == osQWord) { + base_address = GetRegistrValue(base_registr, i); + } + else { + IntelOperand base_operand = IntelOperand(otRegistr, cpu_address_size(), base_registr); + if (i > 0) { + IntelCommand *tmp = item(i - 1); + if (tmp->type() == cmMov + && tmp->operand(0).type == otRegistr + && tmp->operand(0).registr == base_registr) { + base_operand = tmp->operand(1); + } + } + base_address = file.compiler_function_list()->GetRegistrValue(command->address(), base_operand.encode()); + } + if (base_address != (uint64_t)-1) { + if (ParseSwitch(file, prev->operand(1).value, osDWord, base_address, command, 0, static_cast(GetRegistrMaxValue(prev->operand(1).registr, IndexOf(prev), file)))) { + command_link = prev->AddLink(1, ltSwitch, prev->operand(1).value); + command->AddLink(-1, ltOffset, command_link->to_address()); + } + else if (count() == 0) + return ParseCommand(file, this->address(), dump_mode); + } + } + else if (prev->type() == cmMov + && prev->operand(1).type == (otMemory | otRegistr | otValue) + && prev->operand(1).scale_registr == 2 + && prev->operand(1).size == osDWord + && prev->operand(0).registr == command->operand(0).registr) { // mov reg, [reg1*4 + xxxx] + if (cpu_address_size() == osQWord) { + base_address = GetRegistrValue(base_registr, i + 1); + } + else { + IntelOperand base_operand = IntelOperand(otRegistr, cpu_address_size(), base_registr); + IntelCommand *tmp = item(i + 1); + if (tmp->type() == cmMov + && tmp->operand(0).type == otRegistr + && tmp->operand(0).registr == base_registr) { + base_operand = tmp->operand(1); + } + base_address = file.compiler_function_list()->GetRegistrValue(command->address(), base_operand.encode()); + } + if (base_address != (uint64_t)-1) { + if (ParseSwitch(file, prev->operand(1).value, osDWord, base_address, command, 0, static_cast(GetRegistrMaxValue(prev->operand(1).registr, IndexOf(prev), file)))) { + command_link = prev->AddLink(1, ltSwitch, prev->operand(1).value); + command->AddLink(-1, ltOffset, command_link->to_address()); + } + else if (count() == 0) + return ParseCommand(file, this->address(), dump_mode); + } + } + } + } + else if (prev->type() == cmMov && prev->operand(1).type == (otValue | otMemory | otRegistr) && prev->operand(1).size == cpu_address_size() && prev->operand(1).scale_registr == (cpu_address_size() == osDWord ? 2 : 3)) { // mov reg1, dword ptr [reg*4 + xxxx] + if (ParseSwitch(file, prev->operand(1).value, prev->operand(1).size, 0, command, 0, static_cast(GetRegistrMaxValue(prev->operand(1).registr, IndexOf(prev), file)))) { + command_link = prev->AddLink(1, ltSwitch, prev->operand(1).value); + command->AddLink(-1, ltOffset, command_link->to_address()); + } + else if (count() == 0) + return ParseCommand(file, this->address(), dump_mode); + } + } + } + } + break; + + case cmPush: + if (cpu_address_size() == osDWord) { + if (command->operand(0).type == otValue) { // push xxxx + if (count() > 1) { + i = count() - 2; + prev = item(i); + if (prev->type() == cmMov + && prev->operand(0).type == (otMemory | otRegistr) + && prev->base_segment() == segFS + && prev->operand(1).type == otRegistr + && prev->operand(1).registr != regESP) // mov fs:[reg], reg1 + command->AddLink(0, ltFinallyBlock, command->operand(0).value); + } + } else if ((command->operand(0).type & otMemory) != 0 && command->base_segment() == segFS) { // push fs:[xxxx] + if (count() >= 2) { + i = count() - 2; + prev = item(i); + if (prev->type() == cmPush && prev->operand(0).type == otValue) // push xxxx + prev->AddLink(0, ltSEHBlock, prev->operand(0).value); + } + } + } + break; + + case cmMov: + if (cpu_address_size() == osDWord) { + if (command->base_segment() == segFS) { + if (command->operand(0).type == otRegistr + && command->operand(1).type == (otMemory | otValue) + && command->operand(1).value == 0) { // mov reg, fs:[00000000] + + uint64_t mem_offset = 0; + uint8_t mem_registr = 0; + { + IntelCommand tmp(NULL, cpu_address_size()); + uint64_t pos = file.Tell(); + for (i = 0; i < 10; i++) { + tmp.ReadFromFile(file); + if (tmp.type() == cmPush + || tmp.type() == cmDB + || tmp.type() == cmJmp + || tmp.type() == cmJmpWithFlag + || tmp.type() == cmRet + || tmp.type() == cmIret + || tmp.type() == cmCall) + break; + if (tmp.type() == cmMov) { + if (tmp.operand(1).type == otRegistr && tmp.operand(1).registr == command->operand(0).registr && tmp.operand(0).type == (otMemory | otRegistr | otValue)) { + mem_offset = tmp.operand(0).value; + mem_registr = tmp.operand(0).registr; + } + break; + } + } + file.Seek(pos); + } + + c = 0; + for (i = count(); i > 0; i--) { + prev = item(i - 1); + if (prev->type() == cmJmp + || prev->type() == cmJmpWithFlag + || prev->type() == cmRet + || prev->type() == cmIret + || prev->type() == cmCall) + break; + + if (prev->type() == cmPush || + (mem_offset && prev->type() == cmMov && prev->operand(0).type == (otMemory | otRegistr | otValue) && prev->operand(0).value == mem_offset + 4 && prev->operand(0).registr == mem_registr && prev->operand(1).type == otValue)) { + c++; + if (mem_offset) + mem_offset += 4; + size_t k = (prev->type() == cmPush) ? 0 : 1; + if (c == 1) { + if (ParseNewSEH(file, prev->operand(k).value)) { + prev->AddLink((int)k, ltOffset, prev->operand(k).value); + break; + } + } else if (c == 2) { + uint64_t version = 0; + if (i > 1) { + IntelCommand *tmp = item(i - 2); + if (tmp->type() == cmPush && tmp->operand(0).type == otValue) + version = tmp->operand(0).value; + } + + if (version == (uint64_t)-2 && ParseSEH4(file, prev->operand(k).value)) + prev->AddLink((int)k, ltOffset, prev->operand(k).value); + else if (version == (uint64_t)-1 && ParseSEH3(file, prev->operand(k).value)) + prev->AddLink((int)k, ltOffset, prev->operand(k).value); + break; + } + } + } + } + } else if (command->operand(0).type == (otMemory | otRegistr | otValue) + && command->operand(0).registr == regEBP + && command->operand(0).size == osDWord + && command->operand(1).type == otValue) { // mov [ebp + xxxx], xxxx + CompilerFunction *func = file.compiler_function_list()->GetFunctionByAddress(address); + if (func && func->type() == cfVB6SEH) { + if (ParseVB6SEH(file, func->value(0))) + command->AddLink(1, ltOffset, func->value(0)); + } + } + } + break; + + case cmInt: + if (command->operand(0).value == 3) + command->include_option(roBreaked); + else if (file.owner()->format_name() == "PE") { + if (command->operand(0).value == 0x29) // __failfast + command->include_option(roBreaked); + } + break; + + case cmHlt: + case cmUd2: + command->include_option(roBreaked); + break; + + case cmJmpWithFlag: case cmJCXZ: case cmLoop: case cmLoope: case cmLoopne: + command->AddLink(0, ltJmpWithFlag, command->operand(0).value); + break; + } + + return command; +} + +IntelCommand *IntelFunction::ReadValidCommand(IArchitecture &file, uint64_t address) +{ + size_t i, f, d; + IntelCommand *command; + IFixupList *fixup_list; + ISectionList *segment_list; + const IFixup *fixup; + bool invalid_fixup; + IntelOperand operand; + + command = ParseCommand(file, address, true); + if (!command) + return NULL; + + fixup_list = file.fixup_list(); + segment_list = file.segment_list(); + + if (fixup_list->count() > 0) { + // need to check fixups for all value operands + d = 0; + while (d < command->dump_size()) { + fixup = fixup_list->GetFixupByNearAddress(address + d); + if (fixup) { + invalid_fixup = true; + f = static_cast(fixup->address() - address); + for (i = 0; i < 3; i++) { + operand = command->operand(i); + if (operand.type & otValue) { + if (command->type() == cmCall || command->type() == cmJmp || command->type() == cmJmpWithFlag) { + if ((operand.type & otMemory) == 0) + break; + } + if (f == operand.value_pos) { + invalid_fixup = false; + break; + } + } + } + if (invalid_fixup) + return NULL; + d += OperandSizeToValue(fixup->size()); + } else { + d++; + } + } + } + + /* + for (i = 0; i < 3; i++) { + operand = command->operand(i); + if (operand.type == (otMemory | otValue)) { + // check fixup + if (fixup_list->count() > 0 && operand.fixup == NULL && !operand.is_large_value) + return NULL; + // check segment type + if ((segment_list->GetMemoryTypeByAddress(operand.value) & mtReadable) == 0) + return NULL; + } + } + */ + + if (command->type() == cmCall || command->type() == cmJmp || command->type() == cmJmpWithFlag) { + operand = command->operand(0); + // check segment type for value operand + if (operand.type == otValue && (segment_list->GetMemoryTypeByAddress(command->operand(0).value) & mtExecutable) == 0) + return NULL; + } + + if (cpu_address_size() == osQWord) { + // calc REX preffixes count + f = 0; + for (i = 0; i < command->command_pos(); i++) { + if ((command->dump(i) & 0xF0) == 0x40) { + f++; + } else { + if (f) + break; + } + } + if (f > 1) + return NULL; + } + + return command; +} + +uint64_t IntelFunction::ParseParam(IArchitecture &file, size_t index, uint64_t ¶m_reference) +{ + size_t i; + IntelCommand *command; + bool need_push_value; + uint8_t registr; + IntelOperand operand; + IntelCommandInfoList command_info(cpu_address_size()); + + CallingConvention calling_convention = file.calling_convention(); + bool use_stack = false; + switch (calling_convention) { + case ccMSx64: + registr = regECX; + break; + case ccABIx64: + registr = regEDI; + break; + default: + registr = 0xFF; + use_stack = true; + } + + need_push_value = true; + for (i = index; i > 0; i--) { + command = item(i - 1); + + // unknown command + if (!command->GetCommandInfo(command_info)) + return 0; + + // commands change EIP can no be found between API`s param and API`s call + if (command_info.GetInfo(atWrite, otBaseRegistr, regEIP)) + return 0; + + param_reference = command->address(); + if (!use_stack) { + if (command->type() == cmLea && command->operand(0).size == cpu_address_size() && command->operand(0).type == otRegistr && command->operand(0).registr == registr) { + // lea reg, [xxxx] + operand = command->operand(1); + if (operand.type == (otMemory | otValue) && operand.is_large_value) + return operand.value; + return 0; + } else if (command->type() == cmMov && (command->operand(0).size == cpu_address_size() || (command->operand(0).size == osDWord && cpu_address_size() == osQWord)) && command->operand(0).type == otRegistr && command->operand(0).registr == registr) { + // mov reg, xxxx + operand = command->operand(1); + if (operand.type == otValue) { + return operand.value; + } else if (operand.type == otRegistr) { + registr = operand.registr; + } else { + return 0; + } + } else if (command_info.GetInfo(atWrite, otRegistr, registr)) { + return 0; + } + + } else { + if ((command->type() == cmPush && need_push_value) || // push xxxx + (command->type() == cmMov && command->operand(0).size == cpu_address_size() && + // mov [esp], xxxx + ((command->operand(0).type == (otMemory | otBaseRegistr) && command->operand(0).base_registr == regESP && need_push_value) || + // mov reg, xxxx + (command->operand(0).type == otRegistr && command->operand(0).registr == registr && !need_push_value)) + )) { + operand = command->operand(command->type() == cmMov); + if (operand.type == otValue) { + return operand.value; + } else if (operand.type == otRegistr) { + need_push_value = false; + registr = operand.registr; + } else { + return 0; + } + } else if (!need_push_value && command->type() == cmLea && command->operand(0).size == cpu_address_size() && command->operand(0).type == otRegistr && command->operand(0).registr == registr && command->operand(1).type == (otValue | otRegistr | otMemory)) { + // lea reg, [reg + xxxx] + IntelOperand base_operand = IntelOperand(otRegistr, cpu_address_size(), command->operand(1).registr); + if (i > 1) { + IntelCommand *tmp = item(i - 2); + if (tmp->type() == cmMov + && tmp->operand(0).type == otRegistr + && tmp->operand(0).registr == base_operand.registr) { + base_operand = tmp->operand(1); + } + } + uint64_t base_address = file.compiler_function_list()->GetRegistrValue(command->address(), base_operand.encode()); + if (base_address != (uint64_t)-1) + return base_address + command->operand(1).value; + } else if (!need_push_value && command_info.GetInfo(atWrite, otRegistr, registr)) { + return 0; + } + } + } + + return 0; +} + +void IntelFunction::ReadMarkerCommands(IArchitecture &file, MarkerCommandList &command_list, uint64_t address, uint32_t options) +{ + uint64_t param_address, param_reference, call_start, call_end, tmp_address; + IntelCommand *command; + ICommand *link_command; + uint8_t api_reg; + std::vector stack; + size_t i, j, cur_index; + bool need_parse_backward, first_call; + + command_list.clear(); + call_start = address; + call_end = address + 1; + + if (options & moForward) { + // forward searching + if (count() == 0) + return; + + command = item(0); + if (command->operand(0).type != otRegistr) + return; + + api_reg = command->operand(0).registr; + ReadFromFile(file, address); + + command = GetCommandByAddress(address); + if (!command) + return; + + cur_index = IndexOf(command) + 1; + need_parse_backward = false; + first_call = true; + IntelCommandInfoList command_info_list(cpu_address_size()); + while (cur_index < count()) { + command = item(cur_index); + bool is_end = command->is_end(); + if ((command->options() & roBreaked) == 0) { + if (command->type() == cmCall && command->operand(0).type == otRegistr && command->operand(0).registr == api_reg) { + // call reg + if (options & moNeedParam) { + param_address = ParseParam(file, cur_index, param_reference); + if (!param_address && first_call) { + need_parse_backward = true; + call_start = command->address(); + call_end = command->next_address(); + } else { + command_list.Add(command->address(), command->next_address(), param_reference, param_address); + } + first_call = false; + } else { + command_list.Add(command->address(), command->next_address(), 0, 0); + } + } else if ((command->type() == cmJmp || command->type() == cmJmpWithFlag || command->type() == cmLoop) && command->link()) { + // add link to stack + link_command = GetCommandByAddress(command->link()->to_address()); + if (link_command) { + i = IndexOf(link_command); + if (i != NOT_ID) + stack.push_back(i); + } + } else if (command->GetCommandInfo(command_info_list)) { + if (command_info_list.GetInfo(atWrite, otRegistr, api_reg)) { + std::vector exclude_command_list; + exclude_command_list.push_back(command); + for (i = 0; i < exclude_command_list.size(); i++) { + for (j = IndexOf(exclude_command_list[i]); j < count(); j++) { + command = item(j); + + if (std::find(exclude_command_list.begin(), exclude_command_list.end(), command) == exclude_command_list.end()) + exclude_command_list.push_back(command); + + for (size_t k = 0; k < link_list()->count(); k++) { + CommandLink *link = link_list()->item(k); + if (link->parent_command() == command && std::find(exclude_command_list.begin(), exclude_command_list.end(), link->from_command()) == exclude_command_list.end()) + exclude_command_list.push_back(reinterpret_cast(link->from_command())); + } + + CommandLink *link = command->link(); + if (link && link->to_address()) { + IntelCommand *link_command = GetCommandByAddress(link->to_address()); + if (link_command && std::find(exclude_command_list.begin(), exclude_command_list.end(), link_command) == exclude_command_list.end()) + exclude_command_list.push_back(link_command); + } + + if (command->is_end()) + break; + } + } + for (i = 0; i < exclude_command_list.size(); i++) { + exclude_command_list[i]->include_option(roBreaked); + } + is_end = true; + } + } else { + is_end = true; + } + } else { + is_end = true; + } + + // the end of branch + if (is_end) { + // delete processed indexes + for (i = stack.size(); i > 0; i--) { + if (stack[i - 1] <= cur_index) + stack.erase(stack.begin() + i - 1); + } + if (stack.empty()) + break; + + // calc minimum index from stack + cur_index = stack[0]; + for (i = 0; i < stack.size(); i++) { + if (cur_index > stack[i]) + cur_index = stack[i]; + } + } else { + cur_index++; + } + } + + if (!need_parse_backward) + return; + } + + if ((options & moNeedParam) == 0) + return; + + // backward searching + SignatureList param_signatures; + if (cpu_address_size() == osDWord) { + for (i = 0; i < file.compiler_function_list()->count(); i++) { + if (file.compiler_function_list()->item(i)->type() == cfBaseRegistr) { + param_signatures.Add("8B"); // mov reg, [reg + xxxx] + break; + } + } + param_signatures.Add("68"); // push xxxx + param_signatures.Add("B?"); // mov reg, xxxx + param_signatures.Add("8D8?"); // lea reg, [xxxx] + param_signatures.Add("C70424"); // mov [esp], xxxx + } else { + param_signatures.Add("4?8D"); // lea reg, [xxxx] + param_signatures.Add("B?"); // mov reg, xxxx + } + + for (i = 0; i < param_signatures.count(); i++) { + Signature *sign = param_signatures.item(i); + for (j = 0x100; j > 0; j--) { + if (!file.AddressSeek(address - j)) + continue; + uint8_t b; + file.Read(&b, sizeof(b)); + if (!sign->SearchByte(b)) + continue; + + clear(); + tmp_address = address - j - sign->size() + 1; + while (tmp_address < address) { + command = ReadValidCommand(file, tmp_address); + // these commands can no be found between API`s param and API`s call + if (command == NULL + || command->type() == cmDB + || command->type() == cmRet + || command->type() == cmIret + || command->type() == cmJmp + || command->type() == cmEnter) { + tmp_address = 0; + break; + } + tmp_address = command->next_address(); + } + + if (tmp_address != address) + continue; + + size_t index = count(); + if (options & moSkipLastCall) { + if (count() > 1) { + command = item(count() - 1); + if (command->type() == cmPush && command->operand(0).type == otRegistr && command->operand(0).registr == regEAX) { + command = item(count() - 2); + if (command->type() == cmCall) + index -= 2; + } + } + } + + param_address = ParseParam(file, index, param_reference); + if (param_address && (file.segment_list()->GetMemoryTypeByAddress(param_address) & mtReadable)) { + command_list.Add(call_start, call_end, param_reference, param_address); + return; + } + } + } +} + +IntelCommand *IntelFunction::CreateCommand() +{ + return new IntelCommand(this, cpu_address_size()); +} + +void IntelFunction::CreateBlocks() +{ + CommandBlock *cur_block = NULL; + for (size_t i = 0; i < count(); i++) { + IntelCommand *command = item(i); + if (command->block() || (command->options() & roNeedCompile) == 0) { + cur_block = NULL; + continue; + } + + if ((!cur_block || (command->options() & roCreateNewBlock) || item(cur_block->end_index())->is_data() != command->is_data())) + cur_block = AddBlock(i, true); + + cur_block->set_end_index(i); + + command->set_block(cur_block); + if (command->type() == cmJmp || command->type() == cmRet || command->type() == cmIret) + cur_block = NULL; + } +} + +bool IntelFunction::Init(const CompileContext &ctx) +{ + if (need_compile()) { + ICommand *command; + CommandLink *link; + size_t i, j, k; + std::vector entry_command_list; + std::vector exclude_command_list; + + // exclude duplicates of exception handlers + for (i = 0; i < link_list()->count(); i++) { + link = link_list()->item(i); + if (link->type() == ltExtSEHHandler || link->type() == ltMemSEHBlock) { + command = GetCommandByAddress(link->to_address()); + if (command && std::find(entry_command_list.begin(), entry_command_list.end(), command) == entry_command_list.end()) { + ICommand *tmp = ctx.file->function_list()->GetCommandByAddress(command->address(), true); + if (tmp && tmp != command) + entry_command_list.push_back(command); + } + } + } + + for (i = 0; i < entry_command_list.size(); i++) { + ICommand *entry_command = entry_command_list[i]; + if (!entry_command) + continue; + + for (j = IndexOf(entry_command); j < count(); j++) { + command = item(j); + + if (std::find(exclude_command_list.begin(), exclude_command_list.end(), command) != exclude_command_list.end()) + break; + + std::vector::iterator it = std::find(entry_command_list.begin(), entry_command_list.end(), command); + if (it != entry_command_list.end()) + *it = NULL; + + exclude_command_list.push_back(command); + + for (k = 0; k < link_list()->count(); k++) { + link = link_list()->item(k); + if (link->parent_command() == command && std::find(entry_command_list.begin(), entry_command_list.end(), link->from_command()) == entry_command_list.end()) + entry_command_list.push_back(link->from_command()); + } + + link = command->link(); + if (link && link->to_address()) { + ICommand *link_command = GetCommandByAddress(link->to_address()); + if (link_command && std::find(entry_command_list.begin(), entry_command_list.end(), link_command) == entry_command_list.end()) + entry_command_list.push_back(link_command); + } + + if (command->is_data() || command->is_end() || (command->options() & roBreaked) != 0) + break; + } + } + + for (i = 1; i < count(); i++) { + command = item(i - 1); + if (!command->is_end() && std::find(exclude_command_list.begin(), exclude_command_list.end(), item(i)) != exclude_command_list.end()) + command->include_option(roBreaked); + } + + for (i = 0; i < exclude_command_list.size(); i++) { + command = exclude_command_list[i]; + if (command->link()) + delete command->link(); + delete command; + if (entry() == command) + set_entry(NULL); + } + + for (i = 0; i < function_info_list()->count(); i++) { + FunctionInfo *info = function_info_list()->item(i); + if (!info->entry()) + continue; + + if (info->entry()->comment().value == "LPStart Encoding") { + size_t c = IndexOf(info->entry()); + for (j = c + 1; j < count(); j++) { + IntelCommand *command = item(j); + if (!command->is_data() || (command->options() & roCreateNewBlock)) + break; + + if (command->comment().value == "TTable Offset") { + command->CompileToNative(); + if (command->link()) + command->link()->set_sub_value(command->link()->sub_value() + command->dump_size() - command->original_dump_size()); + } else if (command->comment().value == "Call Site Encoding" && command->dump_size() == 1 && command->dump(0) == DW_EH_PE_uleb128) { + uint8_t call_size_encoding = DW_EH_PE_udata4; + command->set_dump(&call_size_encoding, sizeof(call_size_encoding)); + + IntelCommand *call_site_entry = item(j + 1); + size_t call_site_length = static_cast(call_site_entry->operand(0).value); + size_t new_call_site_length = 0; + for (k = j + 2; k < count(); k++) { + command = item(k); + call_site_length -= command->dump_size(); + if (command->comment().value != "Action") { + command->Init(cmDD, IntelOperand(command->operand(0))); + command->CompileToNative(); + } + new_call_site_length += command->dump_size(); + if (!call_site_length) + break; + } + call_site_entry->set_operand_value(0, new_call_site_length); + call_site_entry->CompileToNative(); + break; + } + } + } + } + } + + return BaseFunction::Init(ctx); +} + +bool IntelFunction::Prepare(const CompileContext &ctx) +{ + IArchitecture *file = from_runtime() ? ctx.runtime : ctx.file; + if (type() == otString) { + MapFunction *map_function = file->map_function_list()->GetFunctionByAddress(address()); + if (map_function) { + for (size_t i = 0; i < count(); i++) { + IntelCommand *command = item(i); + command->exclude_option(roClearOriginalCode); + + if (command->address()) { + uint64_t end_address = command->address() + command->original_dump_size(); + for (size_t j = 0; j < map_function->reference_list()->count(); j++) { + Reference *reference = map_function->reference_list()->item(j); + if (reference->tag() != 1) + continue; + + if (command->address() <= reference->operand_address() && end_address > reference->operand_address()) + end_address = reference->operand_address(); + } + if (end_address > command->address()) + ctx.manager->Add(command->address(), static_cast(end_address - command->address()), file->segment_list()->GetMemoryTypeByAddress(command->address())); + } + } + } + } else if (address() && count() > 0) { + for (size_t i = 0; i < count(); i++) { + IntelCommand *command = item(i); + if (command->options() & roInvalidOpcode) { + ctx.file->Notify(mtError, command, string_format(language[lsCommandNotSupported].c_str(), command->text().c_str())); + return false; + } + + uint64_t next_address = command->address() + command->original_dump_size(); + if (command->type() == cmCall && (command->options() & roFar) == 0 && command->operand(0).type == otValue && command->operand(0).value != next_address) { + CompilerFunction *compiler_function = file->compiler_function_list()->GetFunctionByAddress(next_address); + if (compiler_function && compiler_function->type() == cfBaseRegistr) { + delete command->link(); + IntelOperand operand; + operand.decode(compiler_function->value(0)); + command->Init(cmLea, operand, IntelOperand(otMemory | otValue, operand.size, 0, next_address, (cpu_address_size() == osDWord) ? NEED_FIXUP : LARGE_VALUE)); + command->CompileToNative(); + } + } + if (!command->is_data() && ((command->options() & roBreaked) || is_breaked_address(next_address))) { + // need add JMP after breaked commands + IntelCommand *jmp_command = new IntelCommand(this, cpu_address_size(), cmJmp, IntelOperand(otValue, cpu_address_size(), 0, next_address)); + jmp_command->AddLink(0, ltJmp, next_address); + jmp_command->set_address_range(function_info_list()->GetRangeByAddress(next_address)); + jmp_command->CompileToNative(); + InsertObject(i + 1, jmp_command); + } + if (is_breaked_address(next_address)) + break; + } + + if (ctx.runtime && compilation_type() != ctMutation && address() && entry_type() != etNone) { + size_t i, c; + IntelCommand *command, *jmp_command, *loop_command, *antitrace_command; + ICommand *loader_data_command = NULL; + uint64_t loader_data_address = 0; + + IntelLoaderData *loader_data = reinterpret_cast(ctx.file->function_list())->loader_data(); + if (loader_data) { + loader_data_command = loader_data->entry(); + } else { + loader_data_address = ctx.runtime->export_list()->GetAddressByType(atLoaderData); + if (!loader_data_address) + return false; + } + + c = count(); + AddCommand(cmPushf); + AddCommand(cmPush, IntelOperand(otRegistr, cpu_address_size(), regEAX)); + AddCommand(cmPush, IntelOperand(otRegistr, cpu_address_size(), regECX)); + AddCommand(cmPush, IntelOperand(otRegistr, cpu_address_size(), regEBX)); + AddCommand(cmPush, IntelOperand(otRegistr, cpu_address_size(), regEDX)); + + // anti trace + antitrace_command = NULL; + if (ctx.runtime && (ctx.options.flags & cpCheckDebugger)) { + Data data; + data.PushByte(0xf3); // rep + data.PushByte(0xf3); // rep + data.PushByte(0xf3); // rep + data.PushByte(0xf3); // rep + data.PushByte(0xf3); // rep + data.PushByte(0x9c); // pushf + command = AddCommand(data); + command->AddLink(-1, ltNative); + AddCommand(cmPop, IntelOperand(otRegistr, cpu_address_size(), regEAX)); + AddCommand(cmTest, IntelOperand(otRegistr, osDWord, regEAX), IntelOperand(otValue, osDWord, 0, fl_T)); + antitrace_command = AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size())); + antitrace_command->set_flags(fl_Z); + antitrace_command->include_option(roInverseFlag); + antitrace_command->AddLink(0, ltJmpWithFlag); + } + + // add CPU hash check + AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regEAX), IntelOperand(otValue, osDWord, 0, 1)); + command = AddCommand(cmCpuid); + command->include_option(roNoNative); + + // Athlon bug + AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regECX), IntelOperand(otRegistr, osDWord, regEAX)); + AddCommand(cmAnd, IntelOperand(otRegistr, osDWord, regECX), IntelOperand(otValue, osDWord, 0, 0xff0)); + AddCommand(cmCmp, IntelOperand(otRegistr, osDWord, regECX), IntelOperand(otValue, osDWord, 0, 0xfe0)); + jmp_command = AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size())); + jmp_command->set_flags(fl_Z); + jmp_command->include_option(roInverseFlag); + jmp_command->AddLink(0, ltJmpWithFlag); + AddCommand(cmXor, IntelOperand(otRegistr, osDWord, regEAX), IntelOperand(otValue, osDWord, 0, 0x20)); + command = AddCommand(cmNop); + jmp_command->link()->set_to_command(command); + + AddCommand(cmAnd, IntelOperand(otRegistr, osDWord, regEBX), IntelOperand(otValue, osDWord, 0, 0x00ffffff)); + AddCommand(cmAdd, IntelOperand(otRegistr, osDWord, regEAX), IntelOperand(otRegistr, osDWord, regEBX)); + if (ctx.file->owner()->format_name() == "PE") { + PEArchitecture *pe = reinterpret_cast(ctx.file); + if (pe->image_type() != itDriver) { + size_t osbuild_offset; + if (cpu_address_size() == osDWord) { + command = AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size(), regEBX), IntelOperand(otMemory | otValue, cpu_address_size(), 0, 0x30)); + command->set_base_segment(segFS); + osbuild_offset = offsetof(PEB32, OSBuildNumber); + } else { + command = AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size(), regEBX), IntelOperand(otMemory | otValue, cpu_address_size(), 0, 0x60)); + command->set_base_segment(segGS); + osbuild_offset = offsetof(PEB64, OSBuildNumber); + } + AddCommand(cmMovzx, IntelOperand(otRegistr, osDWord, regEBX), IntelOperand(otMemory | otRegistr | otValue, osWord, regEBX, osbuild_offset)); + AddCommand(cmShl, IntelOperand(otRegistr, osDWord, regEBX), IntelOperand(otValue, osWord, 0, 7)); + AddCommand(cmAdd, IntelOperand(otRegistr, osDWord, regEAX), IntelOperand(otRegistr, osDWord, regEBX)); + } + } + command = AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size(), regEDX), IntelOperand(otMemory | otValue, cpu_address_size(), 0, loader_data_address, NEED_FIXUP)); + command->AddLink(1, ltOffset, loader_data_command); + AddCommand(cmXor, IntelOperand(otRegistr, osDWord, regEAX), IntelOperand(otRegistr, osDWord, regEDX)); + AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regECX), IntelOperand(otMemory | otRegistr | otValue, osDWord, regEDX, ctx.runtime_var_index[VAR_CPU_COUNT] * OperandSizeToValue(cpu_address_size()))); + AddCommand(cmXor, IntelOperand(otRegistr, osDWord, regECX), IntelOperand(otValue, osDWord, 0, ctx.runtime_var_salt[VAR_CPU_COUNT])); + AddCommand(cmAdd, IntelOperand(otRegistr, cpu_address_size(), regEDX), IntelOperand(otValue, cpu_address_size(), 0, ctx.runtime_var_index[VAR_CPU_HASH] * OperandSizeToValue(cpu_address_size()))); + + command = AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regEBX), IntelOperand(otMemory | otRegistr, osDWord, regEDX, 0)); + AddCommand(cmXor, IntelOperand(otRegistr, osDWord, regEBX), IntelOperand(otValue, osDWord, 0, ctx.runtime_var_salt[VAR_CPU_HASH])); + AddCommand(cmCmp, IntelOperand(otRegistr, osDWord, regEAX), IntelOperand(otRegistr, osDWord, regEBX)); + + jmp_command = AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size())); + jmp_command->set_flags(fl_Z); + jmp_command->AddLink(0, ltJmpWithFlag); + + AddCommand(cmAdd, IntelOperand(otRegistr, cpu_address_size(), regEDX), IntelOperand(otValue, cpu_address_size(), 0, OperandSizeToValue(cpu_address_size()))); + AddCommand(cmDec, IntelOperand(otRegistr, osDWord, regECX)); + loop_command = AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size())); + loop_command->set_flags(fl_Z); + loop_command->include_option(roInverseFlag); + loop_command->AddLink(0, ltJmpWithFlag, command); + + command = AddCommand(cmPop, IntelOperand(otRegistr, cpu_address_size(), regEDX)); + if (antitrace_command) + antitrace_command->link()->set_to_command(command); + AddCommand(cmPop, IntelOperand(otRegistr, cpu_address_size(), regEBX)); + AddCommand(cmPop, IntelOperand(otRegistr, cpu_address_size(), regECX)); + AddCommand(cmPop, IntelOperand(otRegistr, cpu_address_size(), regEAX)); + AddCommand(cmPopf); + AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regEAX), IntelOperand(otValue, osDWord, 0, 0xdeadc0de)); + AddCommand(cmPush, IntelOperand(otValue, cpu_address_size(), 0, 0)); + AddCommand(cmRet); + + command = AddCommand(cmNop); + jmp_command->link()->set_to_command(command); + AddCommand(cmPop, IntelOperand(otRegistr, cpu_address_size(), regEDX)); + AddCommand(cmPop, IntelOperand(otRegistr, cpu_address_size(), regEBX)); + AddCommand(cmPop, IntelOperand(otRegistr, cpu_address_size(), regECX)); + AddCommand(cmPop, IntelOperand(otRegistr, cpu_address_size(), regEAX)); + AddCommand(cmPopf); + command = AddCommand(cmJmp, IntelOperand(otValue, cpu_address_size(), 0, address())); + command->AddLink(0, ltJmp, address()); + + for (i = c; i < count(); i++) { + command = item(i); + command->CompileToNative(); + } + + set_entry(item(c)); + } + } + + return BaseFunction::Prepare(ctx); +} + +bool IntelFunction::PrepareExtCommands(const CompileContext &ctx) +{ + size_t i; + MemoryManager &manager = *ctx.manager; + + ExtCommandList *ext_list = ext_command_list(); + if (type() != otString) { + if (address() && !entry()) { + ctx.file->Notify(mtError, (count()) ? item(0) : NULL, "There are no data for compilation"); + return false; + } + if (entry() && entry_type() != etNone) + ext_list->Add((entry_type() == etDefault) ? address() : 0, entry()); + } + + ext_list->Sort(); + for (i = ext_list->count(); i > 0; i--) { + ExtCommand *ext_command = ext_list->item(i - 1); + if (!ext_command->command() || is_breaked_address(ext_command->address())) + continue; + + if (ext_command->address()) { + if (!manager.Alloc(5, mtNone, ext_command->address())) { + ctx.file->Notify(mtError, ext_command->command(), ext_command->address() == address() ? language[lsMinimalFunctionSize] : language[lsNotEnoughPlace]); + return false; + } + } + ext_command->command()->include_section_option(rtLinkedToExt); + } + + return true; +} + +void IntelFunction::GetFreeRegisters(size_t index, CommandInfoList &free_registr_list) const +{ + CommandInfoList used_registr_list; + IntelCommandInfoList command_info_list(cpu_address_size()); + + uint16_t free_flags = 0; + bool free_flags_extracted = false; + free_registr_list.clear(); + for (size_t i = index; i < count(); i++) { + IntelCommand *command = item(i); + + bool is_end; + if (command->GetCommandInfo(command_info_list)) { + if (!free_flags_extracted) { + if (command_info_list.change_flags()) { + free_flags = command_info_list.change_flags(); + free_flags_extracted = true; + } + if (command_info_list.need_flags()) { + free_flags &= ~command_info_list.need_flags(); + free_flags_extracted = true; + } + } + + for (size_t j = 0; j < command_info_list.count(); j++) { + CommandInfo *command_info = command_info_list.item(j); + if ((command_info->operand_type() == otRegistr || command_info->operand_type() == otHiPartRegistr) && command_info->value() != regESP && command_info->value() != regEIP) { + OperandSize reg_size = command_info->size(); + if (command_info->operand_type() == otHiPartRegistr) + reg_size = (reg_size == osByte) ? osWord : osQWord; + uint8_t reg = command_info->value(); + + if (command_info->type() == atRead) { + used_registr_list.Add(atRead, reg, otRegistr, reg_size); + } else if (!used_registr_list.GetInfo(atRead, otRegistr, reg) && (command_info->operand_type() != otHiPartRegistr || free_registr_list.GetInfo(atWrite, otRegistr, reg))) { + free_registr_list.Add(atWrite, reg, otRegistr, reg_size); + } + } + } + is_end = command_info_list.GetInfo(atWrite, otBaseRegistr, regEIP) != NULL; + } else { + is_end = true; + } + + if (is_end) + break; + } + free_registr_list.set_change_flags(free_flags); +} + +void IntelFunction::Mutate(const CompileContext &ctx, bool for_virtualization) +{ + #define osRandom (OperandSize)0x80 + #define osRandomStartWord (OperandSize)0x81 + + enum { + regFree = 0xf, + flRandom = 0xff + }; + + size_t i, j, insert_count; + IntelCommand *command, *new_command; + + std::vector template_command_list; + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmMov, IntelOperand(otRegistr, osRandom, regFree), IntelOperand(otRegistr, osRandom))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmMov, IntelOperand(otRegistr, osRandom, regFree), IntelOperand(otValue, osRandom))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmMovsx, IntelOperand(otRegistr, osWord, regFree), IntelOperand(otRegistr, osByte))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmMovsx, IntelOperand(otRegistr, osDWord, regFree), IntelOperand(otRegistr, osWord))); + if (cpu_address_size() == osQWord) { + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmMovsx, IntelOperand(otRegistr, osQWord, regFree), IntelOperand(otRegistr, osWord))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmMovsxd, IntelOperand(otRegistr, osQWord, regFree), IntelOperand(otRegistr, osDWord))); + } + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmMovzx, IntelOperand(otRegistr, osWord, regFree), IntelOperand(otRegistr, osByte))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmMovzx, IntelOperand(otRegistr, osDWord, regFree), IntelOperand(otRegistr, osWord))); + if (cpu_address_size() == osQWord) + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmMovzx, IntelOperand(otRegistr, osQWord, regFree), IntelOperand(otRegistr, osWord))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmNot, IntelOperand(otRegistr, osRandom, regFree))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmNeg, IntelOperand(otRegistr, osRandom, regFree))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmInc, IntelOperand(otRegistr, osRandom, regFree))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmDec, IntelOperand(otRegistr, osRandom, regFree))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmCmp, IntelOperand(otRegistr, osRandom), IntelOperand(otRegistr, osRandom))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmCmp, IntelOperand(otRegistr, osRandom), IntelOperand(otValue, osRandom))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmTest, IntelOperand(otRegistr, osRandom), IntelOperand(otRegistr, osRandom))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmTest, IntelOperand(otRegistr, osRandom), IntelOperand(otValue, osRandom))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmAnd, IntelOperand(otRegistr, osRandom, regFree), IntelOperand(otRegistr, osRandom))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmAnd, IntelOperand(otRegistr, osRandom, regFree), IntelOperand(otValue, osRandom))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmOr, IntelOperand(otRegistr, osRandom, regFree), IntelOperand(otRegistr, osRandom))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmOr, IntelOperand(otRegistr, osRandom, regFree), IntelOperand(otValue, osRandom))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmXor, IntelOperand(otRegistr, osRandom, regFree), IntelOperand(otRegistr, osRandom))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmXor, IntelOperand(otRegistr, osRandom, regFree), IntelOperand(otValue, osRandom))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmAdd, IntelOperand(otRegistr, osRandom, regFree), IntelOperand(otRegistr, osRandom))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmAdd, IntelOperand(otRegistr, osRandom, regFree), IntelOperand(otValue, osRandom))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmAdc, IntelOperand(otRegistr, osRandom, regFree), IntelOperand(otRegistr, osRandom))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmAdc, IntelOperand(otRegistr, osRandom, regFree), IntelOperand(otValue, osRandom))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmSub, IntelOperand(otRegistr, osRandom, regFree), IntelOperand(otRegistr, osRandom))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmSub, IntelOperand(otRegistr, osRandom, regFree), IntelOperand(otValue, osRandom))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmShl, IntelOperand(otRegistr, osRandom, regFree), IntelOperand(otRegistr, osByte, regECX))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmShl, IntelOperand(otRegistr, osRandom, regFree), IntelOperand(otValue, osByte))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmShr, IntelOperand(otRegistr, osRandom, regFree), IntelOperand(otRegistr, osByte, regECX))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmShr, IntelOperand(otRegistr, osRandom, regFree), IntelOperand(otValue, osByte))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmSal, IntelOperand(otRegistr, osRandom, regFree), IntelOperand(otRegistr, osByte, regECX))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmSal, IntelOperand(otRegistr, osRandom, regFree), IntelOperand(otValue, osByte))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmSar, IntelOperand(otRegistr, osRandom, regFree), IntelOperand(otRegistr, osByte, regECX))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmSar, IntelOperand(otRegistr, osRandom, regFree), IntelOperand(otValue, osByte))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmRol, IntelOperand(otRegistr, osRandom, regFree), IntelOperand(otRegistr, osByte, regECX))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmRol, IntelOperand(otRegistr, osRandom, regFree), IntelOperand(otValue, osByte))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmRor, IntelOperand(otRegistr, osRandom, regFree), IntelOperand(otRegistr, osByte, regECX))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmRor, IntelOperand(otRegistr, osRandom, regFree), IntelOperand(otValue, osByte))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmShrd, IntelOperand(otRegistr, osRandomStartWord, regFree), IntelOperand(otRegistr, osRandomStartWord), IntelOperand(otRegistr, osByte, regECX))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmShrd, IntelOperand(otRegistr, osRandomStartWord, regFree), IntelOperand(otRegistr, osRandomStartWord), IntelOperand(otValue, osByte))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmShld, IntelOperand(otRegistr, osRandomStartWord, regFree), IntelOperand(otRegistr, osRandomStartWord), IntelOperand(otRegistr, osByte, regECX))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmShld, IntelOperand(otRegistr, osRandomStartWord, regFree), IntelOperand(otRegistr, osRandomStartWord), IntelOperand(otValue, osByte))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmBt, IntelOperand(otRegistr, osRandomStartWord, regFree), IntelOperand(otRegistr, osRandomStartWord))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmBt, IntelOperand(otRegistr, osRandomStartWord, regFree), IntelOperand(otValue, osByte))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmBtc, IntelOperand(otRegistr, osRandomStartWord, regFree), IntelOperand(otRegistr, osRandomStartWord))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmBtc, IntelOperand(otRegistr, osRandomStartWord, regFree), IntelOperand(otValue, osByte))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmBtr, IntelOperand(otRegistr, osRandomStartWord, regFree), IntelOperand(otRegistr, osRandomStartWord))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmBtr, IntelOperand(otRegistr, osRandomStartWord, regFree), IntelOperand(otValue, osByte))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmBts, IntelOperand(otRegistr, osRandomStartWord, regFree), IntelOperand(otRegistr, osRandomStartWord))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmBts, IntelOperand(otRegistr, osRandomStartWord, regFree), IntelOperand(otRegistr, osRandomStartWord))); + + command = new IntelCommand(this, cpu_address_size(), cmSetXX, IntelOperand(otRegistr, osByte, regFree)); + command->set_flags(flRandom); + template_command_list.push_back(command); + + command = new IntelCommand(this, cpu_address_size(), cmCmov, IntelOperand(otRegistr, osRandomStartWord, regFree), IntelOperand(otRegistr, osRandomStartWord)); + command->set_flags(flRandom); + template_command_list.push_back(command); + + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmClc)); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmStc)); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmCmc)); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmCbw)); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmCwde)); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmCwd)); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmCdq)); + if (cpu_address_size() == osQWord) { + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmCdqe)); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmCqo)); + } + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmLahf)); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmBswap, IntelOperand(otRegistr, osRandomStartWord, regFree))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmXchg, IntelOperand(otRegistr, osRandom, regFree), IntelOperand(otRegistr, osRandom, regFree))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmXadd, IntelOperand(otRegistr, osRandom, regFree), IntelOperand(otRegistr, osRandom, regFree))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmJmp, IntelOperand(otValue, cpu_address_size()))); + + // FIXME + /* + command = new IntelCommand(this, cpu_address_size(), cmJmpWithFlag, IntelOperand(otValue, cpu_address_size())); + command->set_flags(flRandom); + template_command_list.push_back(command); + */ + + if (for_virtualization) { + /* + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmJCXZ, IntelOperand(otValue, cpu_address_size()))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmLoop, IntelOperand(otValue, cpu_address_size()))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmLoope, IntelOperand(otValue, cpu_address_size()))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmLoopne, IntelOperand(otValue, cpu_address_size()))); + */ + } else { + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmSbb, IntelOperand(otRegistr, osRandom, regFree), IntelOperand(otRegistr, osRandom))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmSbb, IntelOperand(otRegistr, osRandom, regFree), IntelOperand(otValue, osRandom))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmRcl, IntelOperand(otRegistr, osRandom, regFree), IntelOperand(otRegistr, osByte, regECX))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmRcl, IntelOperand(otRegistr, osRandom, regFree), IntelOperand(otValue, osByte))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmRcr, IntelOperand(otRegistr, osRandom, regFree), IntelOperand(otRegistr, osByte, regECX))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmRcr, IntelOperand(otRegistr, osRandom, regFree), IntelOperand(otValue, osByte))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmBsr, IntelOperand(otRegistr, osRandomStartWord, regFree), IntelOperand(otRegistr, osRandomStartWord))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmBsf, IntelOperand(otRegistr, osRandomStartWord, regFree), IntelOperand(otRegistr, osRandomStartWord))); + template_command_list.push_back(new IntelCommand(this, cpu_address_size(), cmRdtsc)); + } + + size_t link_count = link_list()->count(); + + for (i = 0; i < count(); i++) { + command = item(i); + + switch (command->type()) { + case cmJmp: + case cmJmpWithFlag: + if (command->dump_size() < 5) + command->CompileToNative(); + break; + case cmJCXZ: + case cmLoop: + case cmLoope: + case cmLoopne: + if (!for_virtualization) { + uint64_t next_address = command->next_address(); + uint64_t to_address = command->link()->to_address(); + AddressRange *address_range = command->address_range(); + + new_command = new IntelCommand(this, cpu_address_size(), cmJmp, IntelOperand(otValue, cpu_address_size(), 0, 0)); + new_command->include_option(roNoProgress); + new_command->AddLink(0, ltJmp, command); + new_command->CompileToNative(); + new_command->set_address_range(address_range); + InsertObject(i++, new_command); + + CommandBlock *block = AddBlock(i++, true); + block->set_end_index(block->start_index() + 2); + command->set_block(block); + + new_command = new IntelCommand(this, cpu_address_size(), cmJmp, IntelOperand(otValue, cpu_address_size(), 0, next_address)); + new_command->include_option(roNoProgress); + new_command->AddLink(0, ltJmp, item(i)); + new_command->CompileToNative(); + new_command->set_address_range(address_range); + new_command->set_block(block); + InsertObject(i++, new_command); + + new_command = new IntelCommand(this, cpu_address_size(), cmJmp, IntelOperand(otValue, cpu_address_size(), 0, to_address)); + new_command->include_option(roNoProgress); + new_command->AddLink(0, ltJmp, to_address); + new_command->CompileToNative(); + new_command->set_address_range(address_range); + new_command->set_block(block); + InsertObject(i++, new_command); + if (command->link()) { + if (command->link()->to_command()) { + new_command->link()->set_to_command(command->link()->to_command()); + command->link()->set_to_command(new_command); + } + } + } + break; + case cmCall: + if ((command->options() & roFar) == 0 && command->operand(0).type == otValue && command->operand(0).value == command->next_address()) { + if (cpu_address_size() == osDWord) { + command->Init(cmPush, IntelOperand(otValue, cpu_address_size(), 0, command->next_address(), NEED_FIXUP)); + command->CompileToNative(); + if (command->link()) { + delete command->link(); + link_count--; + } + } else { + uint64_t next_address = command->next_address(); + AddressRange *address_range = command->address_range(); + + command->Init(cmPush, IntelOperand(otRegistr, cpu_address_size(), regEAX)); + command->CompileToNative(); + if (command->link()) { + delete command->link(); + link_count--; + } + + command = new IntelCommand(this, cpu_address_size(), cmLea, IntelOperand(otRegistr, cpu_address_size(), regEAX), IntelOperand(otMemory | otValue, cpu_address_size(), 0, next_address, LARGE_VALUE)); + command->include_option(roNoProgress); + command->CompileToNative(); + command->set_address_range(address_range); + InsertObject(i++, command); + + command = new IntelCommand(this, cpu_address_size(), cmXchg, IntelOperand(otMemory | otRegistr, cpu_address_size(), regESP), IntelOperand(otRegistr, cpu_address_size(), regEAX)); + command->include_option(roNoProgress); + command->CompileToNative(); + command->set_address_range(address_range); + InsertObject(i++, command); + } + } + break; + case cmDC: + command->CompileToNative(); + break; + } + } + + IntelCommandInfoList command_info_list(cpu_address_size()); + CommandInfoList free_registr_list; + std::vector garbage_command_list; + insert_count = 0; + + std::list new_command_list; + for (i = 0; i < count(); i++) { + command = item(i); + new_command_list.push_back(command); + + if ((command->options() & roNoProgress) == 0) + ctx.file->StepProgress(); + + if (is_breaked_address(command->address())) + continue; + + AddressRange *address_range = command->address_range(); + uint32_t src_options = command->options(); + + if (command->block()) { + CommandBlock *block = command->block(); + for (j = block->start_index() + 1; j <= block->end_index(); j++) { + new_command_list.push_back(item(j)); + } + i = block->end_index(); + if (insert_count) { + block->set_start_index(block->start_index() + insert_count); + block->set_end_index(block->end_index() + insert_count); + } + ctx.file->StepProgress(block->end_index() - block->start_index()); + continue; + } else if ((command->options() & roNeedCompile) == 0) + continue; + + bool is_end; + if (command->GetCommandInfo(command_info_list)) { + GetFreeRegisters(i + 1, free_registr_list); + // mutate command + switch (command->type()) { + case cmXor: + if (command->operand(0).type == otRegistr && command->operand(1).type == otRegistr && command->operand(0).registr == command->operand(1).registr && (rand() & 1)) { + // xor reg, reg -> sub reg, reg + command->Init(cmSub, command->operand(0), command->operand(1)); + command->CompileToNative(); + } + break; + + case cmCall: + if ((command->options() & roFar) == 0 && (rand() & 1)) { + } + break; + + case cmAdd: + if (command->operand(0).type == otRegistr && command->operand(0).size == cpu_address_size() + && ((command->operand(1).type == otRegistr && command->operand(1).registr != regESP) || (command->operand(1).type == otValue && cpu_address_size() != osQWord)) + && (rand() & 1)) { + if ((command_info_list.change_flags() & free_registr_list.change_flags()) == command_info_list.change_flags()) { + // add reg, xxxx -> lea reg, [reg + xxxx] + IntelOperand second_operand = command->operand(1); + second_operand.type |= otMemory; + if ((second_operand.type & otValue) && (command->operand(0).registr != regESP)) { + second_operand.type |= otRegistr; + second_operand.registr = command->operand(0).registr; + } else { + second_operand.type |= otBaseRegistr; + second_operand.base_registr = command->operand(0).registr; + if ((second_operand.base_registr & 7) == regEBP) { + second_operand.type |= otValue; + second_operand.value_size = osByte; + second_operand.value = 0; + } + } + + command->Init(cmLea, command->operand(0), second_operand); + command->CompileToNative(); + } + } + break; + + case cmSub: + if (command->operand(0).type == otRegistr && command->operand(0).size == cpu_address_size() + && (command->operand(1).type == otValue && cpu_address_size() != osQWord) + && (rand() & 1)) { + if ((command_info_list.change_flags() & free_registr_list.change_flags()) == command_info_list.change_flags()) { + // sub reg, xxxx -> lea reg, [reg - xxxx] + IntelOperand second_operand = command->operand(1); + second_operand.type |= otMemory; + if (command->operand(0).registr != regESP) { + second_operand.type |= otRegistr; + second_operand.registr = command->operand(0).registr; + } else { + second_operand.type |= otBaseRegistr; + second_operand.base_registr = command->operand(0).registr; + } + second_operand.value = 0 - second_operand.value; + + command->Init(cmLea, command->operand(0), second_operand); + command->CompileToNative(); + } + } + break; + + case cmJmp: + if (!for_virtualization && (command->options() & roFar) == 0 && command->operand(0).type != otValue && (rand() & 1)) { + // jmp xxxx -> push xxxx, ret + command->Init(cmPush, command->operand(0)); + command->CompileToNative(); + + command = new IntelCommand(this, cpu_address_size(), cmRet); + command->include_option(roNoProgress); + command->CompileToNative(); + command->set_address_range(address_range); + + new_command_list.push_back(command); + insert_count++; + } + break; + } + is_end = command_info_list.GetInfo(atWrite, otBaseRegistr, regEIP) != NULL; + } else { + is_end = true; + } + + if (!is_end) { + // add garbage code + garbage_command_list.clear(); + for (j = 0; j < template_command_list.size(); j++) { + command = template_command_list[j]; + if (!command->GetCommandInfo(command_info_list)) + continue; + + bool is_ok = true; + for (size_t k = 0; k < command_info_list.count() && is_ok; k++) { + CommandInfo *command_info = command_info_list.item(k); + if (command_info->type() == atWrite && (command_info->operand_type() == otRegistr || command_info->operand_type() == otHiPartRegistr)) { + if (command_info->value() == regFree) { + if (!free_registr_list.count()) + is_ok = false; + } else if (command_info->value() == regEFX) { + if ((command_info_list.change_flags() & free_registr_list.change_flags()) != command_info_list.change_flags()) + is_ok = false; + } else { + OperandSize registr_size; + if (command_info->operand_type() == otHiPartRegistr) { + switch (command_info->size()) { + case osByte: + registr_size = osWord; + break; + case osWord: + registr_size = osDWord; + break; + default: + registr_size = osQWord; + break; + } + } else { + registr_size = command_info->size(); + } + + CommandInfo *free_registr = free_registr_list.GetInfo(atWrite, otRegistr, command_info->value()); + if (!free_registr || free_registr->size() < registr_size) + is_ok = false; + } + } + } + if (is_ok) + garbage_command_list.push_back(command); + } + + size_t c = rand() % 4; + for (size_t m = 0; m < c && !garbage_command_list.empty(); m++) { + j = rand() % garbage_command_list.size(); + command = garbage_command_list[j]; + garbage_command_list.erase(garbage_command_list.begin() + j); + + IntelOperand operand[3]; + uint8_t registr[3]; + OperandSize min_size = osByte; + OperandSize max_size = cpu_address_size(); + bool is_ok = true; + uint8_t max_registr = 0; + for (size_t k = 0; k < _countof(operand) && is_ok; k++) { + IntelOperand tmp = command->operand(k); + if (tmp.type == otNone) + continue; + + if (tmp.size == osRandomStartWord && min_size < osWord) + min_size = osWord; + + if (tmp.type == otRegistr) { + if (tmp.registr == regFree) { + if (free_registr_list.count()) { + CommandInfo *free_registr = free_registr_list.item(rand() % free_registr_list.count()); + registr[k] = free_registr->value(); + if (max_size > free_registr->size()) + max_size = free_registr->size(); + } else { + is_ok = false; + break; + } + } else if (tmp.registr == 0) { + registr[k] = rand() % ((cpu_address_size() == osDWord) ? 8 : 16); + } else { + registr[k] = tmp.registr; + } + if (max_registr < registr[k]) + max_registr = registr[k]; + if (cpu_address_size() == osDWord && registr[k] > 3 && min_size < osWord) + min_size = osWord; + if (tmp.size & osRandom) { + if (min_size > max_size) + is_ok = false; + } else if (tmp.size < min_size || tmp.size > max_size) + is_ok = false; + } + } + + if (is_ok) { + OperandSize random_size = min_size; + for (int size = min_size; size <= max_size; size++) { + random_size = static_cast(size); + if (rand() & 1) + break; + } + + for (size_t k = 0; k < _countof(operand) && is_ok; k++) { + IntelOperand tmp = command->operand(k); + if (tmp.size & osRandom) + tmp.size = random_size; + if (tmp.type == otRegistr) { + if (tmp.size == osByte && (tmp.registr == regFree || tmp.registr == 0) && max_size > osByte && max_registr < 4 && (rand() & 1)) + tmp.type = otHiPartRegistr; + tmp.registr = registr[k]; + } else if (tmp.type == otValue) { + switch (tmp.size) { + case osByte: + tmp.value = ByteToInt64(rand32() & 0xff); + tmp.value_size = osByte; + break; + case osWord: + tmp.value = WordToInt64(rand32() & 0xffff); + tmp.value_size = osWord; + break; + default: + tmp.value = DWordToInt64(rand32()); + tmp.value_size = osDWord; + break; + } + } + operand[k] = tmp; + } + uint16_t flags = command->flags(); + uint32_t options = command->options(); + command = new IntelCommand(this, cpu_address_size(), static_cast(command->type()), operand[0], operand[1], operand[2]); + if (flags) { + if (flags == flRandom) { + switch (rand() % 8) { + case 0: flags = fl_O; break; + case 1: flags = fl_C; break; + case 2: flags = fl_Z; break; + case 3: flags = fl_C | fl_Z; break; + case 4: flags = fl_S; break; + case 5: flags = fl_P; break; + case 6: flags = fl_S | fl_O; break; + default: flags = fl_Z | fl_S | fl_O; break; + } + if (rand() & 1) + options |= roInverseFlag; + } + command->set_flags(flags); + if (options & roInverseFlag) + command->include_option(roInverseFlag); + } + command->include_option(roNoProgress); + if (src_options & roNeedCRC) + command->include_option(roNeedCRC); + command->CompileToNative(); + command->set_address_range(address_range); + new_command_list.push_back(command); + insert_count++; + + switch (command->type()) { + case cmJmpWithFlag: + // FIXME + /* + command->AddLink(0, ltJmpWithFlag, item(i + 1)); + */ + break; + case cmJmp: + command->AddLink(0, ltJmp, item(i + 1)); + break; + } + } + } + } + } + + for (i = link_count; i < link_list()->count(); i++) { + link_list()->item(i)->from_command()->PrepareLink(ctx); + } + + for (i = 0; i < template_command_list.size(); i++) { + delete template_command_list[i]; + } + + assign(new_command_list); +} + +void IntelFunction::CompileToNative(const CompileContext &ctx) +{ + size_t i, j; + size_t c = link_list()->count(); + for (i = 0; i < c; i++) { + CommandLink *link = link_list()->item(i); + IntelCommand *to_command = reinterpret_cast(link->to_command()); + if (!to_command) + continue; + + switch (link->type()) { + case ltDualSEHBlock: + { + CommandBlock *block = AddBlock(count(), true); + size_t k = IndexOf(to_command); + IntelCommand *next_command = item(k + 1); + IntelCommand *src_command = to_command; + IntelCommand *dst_command = src_command->Clone(this); + AddObject(dst_command); + CommandLink *src_link = src_command->link(); + if (src_link) { + CommandLink *dst_link = src_link->Clone(link_list()); + dst_link->set_from_command(dst_command); + dst_link->set_to_command(src_link->to_command()); + link_list()->AddObject(dst_link); + } + IntelCommand *command = new IntelCommand(this, cpu_address_size(), cmJmp, IntelOperand(otValue, cpu_address_size(), 0, to_command->next_address())); + AddObject(command); + command->AddLink(0, ltJmp, next_command); + + for (size_t j = block->start_index(); j < count(); j++) { + IntelCommand *command = item(j); + command->set_block(block); + command->CompileToNative(); + } + block->set_end_index(count() - 1); + + link->set_to_command(item(block->start_index())); + } + break; + case ltFilterSEHBlock: + { + CommandBlock *block = AddBlock(count(), true); + size_t k = IndexOf(to_command); + IntelCommand *next_command = item(k + 1); + size_t n = static_cast(next_command->operand(0).value * 2 + 2); + for (j = 0; j < n; j++) { + IntelCommand *src_command = item(k + j); + IntelCommand *dst_command = src_command->Clone(this); + AddObject(dst_command); + CommandLink *src_link = src_command->link(); + if (src_link) { + CommandLink *dst_link = src_link->Clone(link_list()); + dst_link->set_from_command(dst_command); + dst_link->set_to_command(src_link->to_command()); + link_list()->AddObject(dst_link); + } + } + + for (size_t j = block->start_index(); j < count(); j++) { + IntelCommand *command = item(j); + command->set_block(block); + command->CompileToNative(); + } + block->set_end_index(count() - 1); + + link->set_to_command(item(block->start_index())); + } + break; + } + } + + Mutate(ctx, false); + + CreateBlocks(); + for (i = 0; i < ext_command_list()->count(); i++) { + ExtCommand *ext_command = ext_command_list()->item(i); + if (!ext_command->command() || is_breaked_address(ext_command->address())) + continue; + + CommandBlock *block = AddBlock(count(), true); + block->set_address(ext_command->address()); + + IntelCommand *command = AddCommand(ext_command->use_call() ? cmCall : cmJmp, IntelOperand(otValue, cpu_address_size())); + command->AddLink(0, ltJmp, ext_command->command()); + command->CompileToNative(); + command->set_block(block); + } +} + +/** +* IntelStackValue +*/ + +IntelStackValue::IntelStackValue(IntelStack *owner, ValueType type, uint64_t value) + : IObject(), owner_(owner), type_(type), value_(value), is_modified_(false) +{ + +} + +IntelStackValue::~IntelStackValue() +{ + if (owner_) + owner_->RemoveObject(this); +} + +void IntelStackValue::Calc(IntelCommandType command_type, uint16_t command_flags, bool inverse_flags, OperandSize size, uint64_t op2, IntelFlagsValue *flags) +{ + if (type_ != vtValue) + throw std::runtime_error("Runtime error at Calc"); + + uint64_t op1 = value_; + uint64_t result; + switch (command_type) { + case cmAdd: + result = op1 + op2; + break; + case cmAdc: + result = op1 + op2 + ((flags->value() & fl_C) ? 1 : 0); + break; + case cmCmp: + case cmSub: + result = op1 - op2; + break; + case cmSbb: + result = op1 - op2 - ((flags->value() & fl_C) ? 1 : 0); + break; + case cmTest: + case cmAnd: + result = op1 & op2; + break; + case cmOr: + result = op1 | op2; + break; + case cmXor: + result = op1 ^ op2; + break; + case cmSetXX: + result = flags->Check(command_flags) ? 1 : 0; + if (inverse_flags) + result = result ? 0 : 1; + break; + case cmCmov: + if (flags->Check(command_flags) != (inverse_flags == false)) + return; + + result = op2; + break; + case cmShr: + op2 &= (size == osQWord) ? 0x3f : 0x1f; + if (!op2) + return; + + switch (size) { + case osByte: + result = static_cast(op1) >> op2; + break; + case osWord: + result = static_cast(op1) >> op2; + break; + case osDWord: + result = static_cast(op1) >> op2; + break; + default: + result = op1 >> op2; + break; + } + break; + case cmSar: + op2 &= (size == osQWord) ? 0x3f : 0x1f; + if (!op2) + return; + + switch (size) { + case osByte: + result = static_cast(op1) >> op2; + break; + case osWord: + result = static_cast(op1) >> op2; + break; + case osDWord: + result = static_cast(op1) >> op2; + break; + default: + result = static_cast(op1) >> op2; + break; + } + break; + case cmShl: + case cmSal: + op2 &= (size == osQWord) ? 0x3f : 0x1f; + if (!op2) + return; + + switch (size) { + case osByte: + result = static_cast(op1) << op2; + break; + case osWord: + result = static_cast(op1) << op2; + break; + case osDWord: + result = static_cast(op1) << op2; + break; + default: + result = op1 << op2; + break; + } + break; + case cmRol: + op2 &= (size == osQWord) ? 0x3f : 0x1f; + if (!op2) + return; + + switch (size) { + case osByte: + result = _rotl8(static_cast(op1), static_cast(op2)); + break; + case osWord: + result = _rotl16(static_cast(op1), static_cast(op2)); + break; + case osDWord: + result = _rotl32(static_cast(op1), static_cast(op2)); + break; + default: + result = _rotl64(op1, static_cast(op2)); + break; + } + break; + case cmRor: + op2 &= (size == osQWord) ? 0x3f : 0x1f; + if (!op2) + return; + + switch (size) { + case osByte: + result = _rotr8(static_cast(op1), static_cast(op2)); + break; + case osWord: + result = _rotr16(static_cast(op1), static_cast(op2)); + break; + case osDWord: + result = _rotr32(static_cast(op1), static_cast(op2)); + break; + default: + result = _rotr64(op1, static_cast(op2)); + break; + } + break; + case cmMov: + case cmLea: + case cmMovsx: + case cmMovsxd: + case cmMovzx: + result = op2; + break; + case cmCbw: + result = static_cast(static_cast(op2)); + break; + case cmCwde: + result = static_cast(static_cast(op2)); + break; + case cmCdqe: + result = static_cast(static_cast(op2)); + break; + case cmCwd: + result = (static_cast(op2) < 0) ? (uint64_t)-1 : 0; + break; + case cmCdq: + result = (static_cast(op2) < 0) ? (uint64_t)-1 : 0; + break; + case cmCqo: + result = (static_cast(op2) < 0) ? (uint64_t)-1 : 0; + break; + case cmNot: + result = ~op1; + break; + case cmNeg: + result = 0 - op1; + break; + case cmBt: + op2 &= (OperandSizeToValue(size) * 8 - 1); + result = op1; + break; + case cmBtr: + op2 &= (OperandSizeToValue(size) * 8 - 1); + result = op1 & ~((uint64_t)1 << op2); + break; + case cmBtc: + op2 &= (OperandSizeToValue(size) * 8 - 1); + result = op1 ^ ((uint64_t)1 << op2); + break; + case cmBts: + op2 &= (OperandSizeToValue(size) * 8 - 1); + result = op1 | ((uint64_t)1 << op2); + break; + case cmBswap: + switch (size) { + case osDWord: + result = __builtin_bswap32(static_cast(op1)); + break; + case osQWord: + result = __builtin_bswap64(op1); + break; + default: + throw std::runtime_error("Runtime error at Calc"); + } + break; + default: + throw std::runtime_error("Runtime error at Calc"); + } + + if (flags) + flags->Calc(command_type, size, op1, op2, result); + + if (command_type == cmCmp || command_type == cmTest || command_type == cmBt) + return; + + memcpy(&value_, &result, OperandSizeToValue(size)); +} + +/** +* IntelFlagsValue +*/ + +IntelFlagsValue::IntelFlagsValue() + : IObject(), mask_(0), value_(0) +{ + +} + +uint16_t IntelFlagsValue::GetRandom() const +{ + std::vector list; + + if (mask_ & fl_Z) + list.push_back(fl_Z); + if (mask_ & fl_S) + list.push_back(fl_S); + if (mask_ & fl_C) + list.push_back(fl_C); + if (mask_ & fl_O) + list.push_back(fl_O); + if ((mask_ & (fl_C | fl_Z)) == (fl_C | fl_Z)) + list.push_back(fl_C | fl_Z); + if ((mask_ & (fl_S | fl_O)) == (fl_S | fl_O)) + list.push_back(fl_S | fl_O); + if ((mask_ & (fl_Z | fl_S | fl_O)) == (fl_Z | fl_S | fl_O)) + list.push_back(fl_Z | fl_S | fl_O); + + return list.empty() ? 0 : list[rand() % list.size()]; +} + +bool IntelFlagsValue::Check(uint16_t flags) const +{ + bool s, z, o; + + switch (flags) { + case (fl_S | fl_O): + s = (value_ & fl_S) != 0; + o = (value_ & fl_O) != 0; + return s != o; + case (fl_Z | fl_S | fl_O): + z = (value_ & fl_Z) != 0; + s = (value_ & fl_S) != 0; + o = (value_ & fl_O) != 0; + return z || (s != o); + default: + return (value_ & flags) != 0; + } +} + +void IntelFlagsValue::exclude(uint16_t mask) +{ + mask_ &= ~mask; + value_ &= ~mask; +} + +void IntelFlagsValue::Calc(IntelCommandType command_type, OperandSize size, uint64_t op1, uint64_t op2, uint64_t result) +{ + uint64_t tmp; + uint64_t sign_mask = (uint64_t)1 << (OperandSizeToValue(size) * 8 - 1); + uint64_t value_mask = sign_mask | (sign_mask - 1); + uint16_t prev_value = value_; + + switch (command_type) { + case cmAdd: + case cmAdc: + exclude(fl_O | fl_S | fl_Z | fl_A | fl_P | fl_C); + + mask_ |= fl_C; + if (command_type == cmAdc && (prev_value & fl_C)) { + if ((result & value_mask) <= (op1 & value_mask)) + value_ |= fl_C; + } + else { + if ((result & value_mask) < (op1 & value_mask)) + value_ |= fl_C; + } + + mask_ |= fl_O; + if ((~(op1 ^ op2) & (op2 ^ result)) & sign_mask) + value_ |= fl_O; + break; + case cmCmp: + case cmSub: + case cmSbb: + exclude(fl_O | fl_S | fl_Z | fl_A | fl_P | fl_C); + + mask_ |= fl_C; + if (command_type == cmSbb && (prev_value & fl_C)) { + if ((op1 & value_mask) <= (result & value_mask)) + value_ |= fl_C; + } + else { + if ((op1 & value_mask) < (op2 & value_mask)) + value_ |= fl_C; + } + + mask_ |= fl_O; + if (((op1 ^ op2) & (op1 ^ result)) & sign_mask) + value_ |= fl_O; + break; + case cmNeg: + exclude(fl_O | fl_S | fl_Z | fl_A | fl_P | fl_C); + + mask_ |= fl_C; + if (result & value_mask) + value_ |= fl_C; + + mask_ |= fl_O; + if ((result & value_mask) == sign_mask) + value_ |= fl_O; + break; + case cmOr: + case cmXor: + case cmAnd: + case cmTest: + exclude(fl_O | fl_S | fl_Z | fl_A | fl_P | fl_C); + + mask_ |= fl_C; + mask_ |= fl_O; + break; + case cmShr: + exclude(fl_O | fl_S | fl_Z | fl_A | fl_P | fl_C); + + switch (size) { + case osByte: + tmp = static_cast(op1) >> (op2 - 1); + break; + case osWord: + tmp = static_cast(op1) >> (op2 - 1); + break; + case osDWord: + tmp = static_cast(op1) >> (op2 - 1); + break; + default: + tmp = op1 >> (op2 - 1); + break; + } + mask_ |= fl_C; + if (tmp & 1) + value_ |= fl_C; + + if (op2 == 1) { + mask_ |= fl_O; + if (op1 & sign_mask) + value_ |= fl_O; + } + break; + + case cmSar: + exclude(fl_O | fl_S | fl_Z | fl_A | fl_P | fl_C); + + switch (size) { + case osByte: + tmp = static_cast(op1) >> (op2 - 1); + break; + case osWord: + tmp = static_cast(op1) >> (op2 - 1); + break; + case osDWord: + tmp = static_cast(op1) >> (op2 - 1); + break; + default: + tmp = op1 >> (op2 - 1); + break; + } + mask_ |= fl_C; + if (tmp & 1) + value_ |= fl_C; + + if (op2 == 1) + mask_ |= fl_O; + break; + + case cmShl: + case cmSal: + exclude(fl_O | fl_S | fl_Z | fl_A | fl_P | fl_C); + + switch (size) { + case osByte: + tmp = static_cast(op1) << (op2 - 1); + break; + case osWord: + tmp = static_cast(op1) << (op2 - 1); + break; + case osDWord: + tmp = static_cast(op1) << (op2 - 1); + break; + default: + tmp = op1 << (op2 - 1); + break; + } + mask_ |= fl_C; + if (tmp & sign_mask) + value_ |= fl_C; + + if (op2 == 1) { + mask_ |= fl_O; + if (((result & sign_mask) != 0) != ((value_ & fl_C) != 0)) + value_ |= fl_O; + } + break; + + + case cmRcl: + case cmRcr: + exclude(fl_O | fl_C); + + // TODO + return; + case cmRol: + exclude(fl_O | fl_C); + + mask_ |= fl_C; + if (result & 1) + value_ |= fl_C; + + if (op2 == 1) { + mask_ |= fl_O; + if (((result & sign_mask) != 0) != ((value_ & fl_C) != 0)) + value_ |= fl_O; + } + return; + case cmRor: + exclude(fl_O | fl_C); + + mask_ |= fl_C; + if (result & sign_mask) + value_ |= fl_C; + + if (op2 == 1) { + mask_ |= fl_O; + if (((result & sign_mask) != 0) != (((result << 1) & sign_mask) != 0)) + value_ |= fl_O; + } + return; + case cmStc: + mask_ |= fl_C; + value_ |= fl_C; + return; + case cmClc: + mask_ |= fl_C; + value_ &= ~fl_C; + return; + case cmCmc: + if (mask_ & fl_C) + value_ ^= fl_C; + return; + case cmBt: + case cmBtr: + case cmBtc: + case cmBts: + exclude(fl_O | fl_S | fl_A | fl_P | fl_C); // fl_Z is unaffected + + mask_ |= fl_C; + if ((op1 >> op2) & 1) + value_ |= fl_C; + return; + default: + return; + } + + mask_ |= fl_Z; + if ((result & value_mask) == 0) + value_ |= fl_Z; + + mask_ |= fl_S; + if (result & sign_mask) + value_ |= fl_S; +} + +/** +* IntelStack +*/ + +IntelStack::IntelStack() + : ObjectList() +{ + +} + +IntelStackValue *IntelStack::Add(ValueType type, uint64_t value) +{ + IntelStackValue *res = new IntelStackValue(this, type, value); + AddObject(res); + return res; +}; + +IntelStackValue *IntelStack::Insert(size_t index, ValueType type, uint64_t value) +{ + IntelStackValue *res = new IntelStackValue(this, type, value); + InsertObject(index, res); + return res; +} + +IntelStackValue *IntelStack::GetRegistr(uint8_t reg) const +{ + for (size_t i = 0; i < count(); i++) { + IntelStackValue *res = item(i); + if (res->type() == vtRegistr && res->value() == reg) + return res; + } + return NULL; +} + +IntelStackValue *IntelStack::GetRandom(uint32_t types) +{ + std::vector list; + for (size_t i = 0; i < count(); i++) { + IntelStackValue *stack_item = item(i); + if (stack_item->type() & types) { + if (stack_item->type() == vtRegistr && (stack_item->value() == regEFX || stack_item->value() == regEmpty)) + continue; + + list.push_back(stack_item); + } + } + return list.empty() ? NULL : list[rand() % list.size()]; +} + +/** +* IntelRegistrStorage +*/ + +IntelRegistrStorage::IntelRegistrStorage() + : IntelStack() +{ + +} + +IntelRegistrValue *IntelRegistrStorage::item(size_t index) const +{ + return reinterpret_cast(IntelStack::item(index)); +} + +IntelRegistrValue *IntelRegistrStorage::GetRegistr(uint8_t reg) const +{ + for (size_t i = 0; i < count(); i++) { + IntelRegistrValue *res = item(i); + if (res->registr() == reg) + return res; + } + return NULL; +}; + +IntelRegistrValue *IntelRegistrStorage::Add(uint8_t reg, uint64_t value) +{ + IntelRegistrValue *res = GetRegistr(reg); + if (res) + res->set_value(value); + else { + res = new IntelRegistrValue(this, reg, value); + AddObject(res); + } + return res; +} + +/** +* IntelObfuscation +*/ + +IntelObfuscation::IntelObfuscation() + : IObject(), func_(NULL) +{ + +} + +IntelCommand *IntelObfuscation::AddCommand(IntelCommandType command_type, IntelOperand operand1, IntelOperand operand2, IntelOperand operand3) +{ + if (command_type != cmLea && registr_values_.count()) { + for (size_t i = 0; i < 2; i++) { + IntelOperand *operand = (i == 0) ? &operand1 : &operand2; + uint16_t type = operand->type & (otMemory | otBaseRegistr | otRegistr); + if (type == (otMemory | otBaseRegistr) || type == (otMemory | otRegistr)) { + IntelRegistrValue *reg_value = registr_values_.item(rand() % registr_values_.count()); + if ((operand->type & otRegistr) && !operand->scale_registr) { + operand->base_registr = operand->registr; + operand->type -= otRegistr; + operand->type |= otBaseRegistr; + } + if (operand->type & otBaseRegistr) { + operand->scale_registr = rand() & 3; + uint64_t tmp = operand->value - (reg_value->value() << operand->scale_registr); + if (DWordToInt64(static_cast(tmp)) == tmp) { + operand->type |= (otRegistr | otValue); + operand->registr = reg_value->registr(); + operand->value = tmp; + operand->value_size = osDWord; + } + } + } + } + } + + IntelCommand *command = new IntelCommand(func_, func_->cpu_address_size(), command_type, operand1, operand2, operand3); + command_list_.push_back(command); + return command; +} + +void IntelObfuscation::AddRestoreStackItem(IntelStackValue *stack_item) +{ + if (stack_item && stack_item->type() == vtRegistr && stack_item->value() != regEmpty) { + if (stack_item->is_modified()) { + uint8_t reg = static_cast(stack_item->value()); + OperandSize cpu_address_size = func_->cpu_address_size(); + uint64_t value = (stack_.count() - 1 - stack_.IndexOf(stack_item)) * OperandSizeToStack(cpu_address_size); + + if (reg == regEFX) { + AddCommand(cmPush, IntelOperand(otMemory | otRegistr | otValue, cpu_address_size, regESP, value)); + AddCommand(cmPopf, IntelOperand(otNone, cpu_address_size, 0)); + + flags_.clear(); + } + else { + AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size, reg), IntelOperand(otMemory | otRegistr | otValue, cpu_address_size, regESP, value)); + + IntelRegistrValue *reg_value = registr_values_.GetRegistr(reg); + if (reg_value) + delete reg_value; + } + } + stack_item->set_value(regEmpty); + stack_item->set_is_modified(false); + } +} + +void IntelObfuscation::AddRestoreRegistr(uint8_t reg) +{ + if (IntelStackValue *stack_item = stack_.GetRegistr(reg)) + AddRestoreStackItem(stack_item); +} + +void IntelObfuscation::AddRestoreStack(size_t to_index) +{ + size_t i; + for (i = stack_.count(); i > to_index; i--) { + IntelStackValue *stack_item = stack_.item(i - 1); + AddRestoreStackItem(stack_item); + } + size_t value = 0; + OperandSize cpu_address_size = func_->cpu_address_size(); + for (i = stack_.count(); i > to_index; i--) { + delete stack_.item(i - 1); + value += OperandSizeToStack(cpu_address_size); + } + if (value) + AddCommand(cmLea, IntelOperand(otRegistr, cpu_address_size, regESP), IntelOperand(otMemory | otRegistr | otValue, cpu_address_size, regESP, value)); +} + +void IntelObfuscation::Compile(IntelFunction *func, size_t index) +{ + func_ = func; + flags_.clear(); + stack_.clear(); + registr_values_.clear(); + + size_t i, j, old_count; + IntelCommand *command; + IntelStackValue *stack_item; + IntelRegistrValue *reg_value; + uint8_t reg; + OperandSize cpu_address_size = func_->cpu_address_size(); + bool need_update; + IntelOperand new_operand[3]; + + while (index < func_->count()) { + command = func_->item(index); + func_->erase(index); + + if (command->section_options() & (rtLinkedToInt | rtLinkedToExt)) + AddRestoreStack(0); + + old_count = command_list_.size(); + + AddRandomCommands(); + + if (stack_.count()) { + switch (command->type()) { + case cmPop: + reg = command->operand(0).registr; + + command->Init(cmMov, IntelOperand(otRegistr, cpu_address_size, reg), IntelOperand(otMemory | otRegistr | otValue, cpu_address_size, regESP, stack_.count() * OperandSizeToStack(cpu_address_size))); + + stack_item = stack_.GetRegistr(reg); + if (stack_item) + stack_item->set_value(regEmpty); + + reg_value = registr_values_.GetRegistr(reg); + if (reg_value) + delete reg_value; + + stack_.Insert(0, vtRegistr, regEmpty); + break; + + case cmPush: + case cmPushf: + stack_item = stack_.item(0); + AddRestoreStackItem(stack_item); + delete stack_item; + + if (command->type() == cmPushf) { + AddCommand(cmPushf, IntelOperand(otNone, cpu_address_size, 0)); + command->Init(cmPop, IntelOperand(otMemory | otRegistr | otValue, cpu_address_size, regESP, stack_.count() * OperandSizeToStack(cpu_address_size))); + } + else { + IntelOperand first_operand = command->operand(0); + if (first_operand.type == otValue) { + if (first_operand.value_size == osQWord) + first_operand.value_size = osDWord; + } + else if (first_operand.type == otRegistr) + AddRestoreRegistr(first_operand.registr); + + command->Init(cmMov, IntelOperand(otMemory | otRegistr | otValue, cpu_address_size, regESP, stack_.count() * OperandSizeToStack(cpu_address_size)), first_operand); + if (command->link() && command->link()->operand_index() == 0) + command->link()->set_operand_index(1); + } + break; + + case cmCall: + if ((command->options() & roUseAsJmp) && command->link()) { + size_t ret_pos = rand() % stack_.count(); + + for (j = stack_.count(); j > 0; j--) { + IntelStackValue *stack_item = stack_.item(j - 1); + AddRestoreStackItem(stack_item); + } + uint64_t value = (stack_.count() - ret_pos - 1) * OperandSizeToStack(cpu_address_size); + if (value) + AddCommand(cmLea, IntelOperand(otRegistr, cpu_address_size, regESP), IntelOperand(otMemory | otRegistr | otValue, cpu_address_size, regESP, value)); + + stack_.clear(); + + command_list_.push_back(command); + + j = command_list_.size(); + AddRandomCommands(); + + stack_item = stack_.GetRegistr(regEFX); + if (!stack_item) { + AddCommand(cmPushf, IntelOperand(otNone, func_->cpu_address_size(), 0)); + stack_item = stack_.Add(vtRegistr, regEFX); + } + stack_item->set_is_modified(true); + + IntelCommand *add_command = AddCommand(cmAdd, IntelOperand(otMemory | otRegistr | otValue, cpu_address_size, regESP, stack_.count() * OperandSizeToStack(cpu_address_size)), + IntelOperand(otValue, cpu_address_size, 0, 0)); + + flags_.clear(); + + CommandLink *link = add_command->AddLink(1, ltDelta, command->link()->to_command()); + link->set_parent_command(command); + link->set_sub_value(5); + + command->link()->set_to_command(command_list_[j]); + + AddRandomCommands(); + + command = new IntelCommand(func_, cpu_address_size, cmRet, ret_pos ? IntelOperand(otValue, osWord, 0, ret_pos * OperandSizeToStack(cpu_address_size)) : IntelOperand()); + } + AddRestoreStack(0); + break; + case cmRet: + case cmJmp: + case cmJmpWithFlag: + AddRestoreStack(0); + break; + } + } + + if (command_list_.size() > old_count && command->section_options() & (rtLinkedToInt | rtLinkedToExt)) { + IntelCommand *dst_command = command_list_[old_count]; + IntelCommandType dst_type = (IntelCommandType)dst_command->type(); + IntelOperand dst_operand[3]; + for (i = 0; i < _countof(dst_operand); i++) { + dst_operand[i] = dst_command->operand(i); + } + uint16_t dst_flags = dst_command->flags(); + uint32_t dst_options = dst_command->options(); + CommandLink *dst_link = dst_command->link(); + if (dst_link) + dst_link->set_from_command(NULL); + + dst_command->Init(static_cast(command->type()), command->operand(0), command->operand(1), command->operand(2)); + dst_command->set_flags(command->flags()); + dst_command->exclude_option((CommandOption)UINT32_MAX); + dst_command->include_option((CommandOption)command->options()); + if (command->link()) + command->link()->set_from_command(dst_command); + + command->Init(dst_type, dst_operand[0], dst_operand[1], dst_operand[2]); + command->set_flags(dst_flags); + command->exclude_option((CommandOption)UINT32_MAX); + command->include_option((CommandOption)dst_options); + if (dst_link) + dst_link->set_from_command(command); + + command_list_[old_count] = command; + command = dst_command; + } + + command_list_.push_back(command); + } + + for (i = 0; i < command_list_.size(); i++) { + command = command_list_[i]; + + // optimize operands + need_update = false; + for (j = 0; j < _countof(new_operand); j++) { + IntelOperand *operand = &new_operand[j]; + *operand = command->operand(j); + + if ((operand->type & (otMemory | otValue)) == (otMemory | otValue) && (operand->type & (otBaseRegistr | otRegistr))) { + if (operand->fixup || operand->is_large_value) + continue; + + if (command->link() && command->link()->operand_index() == (int)j) + continue; + + if (operand->value_size != osByte && ByteToInt64(static_cast(operand->value)) == operand->value) { + operand->value_size = osByte; + need_update = true; + } + } + } + if (need_update) + command->Init(static_cast(command->type()), new_operand[0], new_operand[1], new_operand[2]); + + command->CompileToNative(); + if (command->link() && !command->link()->to_command()) { + std::map::const_iterator it = jmp_command_list_.find(command); + if (it != jmp_command_list_.end()) { + IntelCommand *to_command; + if (command->type() == cmJmpWithFlag && (command->options() & roUseAsJmp) == 0) { + while (true) { + j = rand() % command_list_.size(); + if (j == it->second || j == it->second + 1) + continue; + to_command = command_list_[j]; + break; + } + } + else + to_command = command_list_[it->second]; + command->link()->set_to_command(to_command); + } + } + + func_->AddObject(command); + } +} + +#define NEED_STORE_FLAGS reinterpret_cast(-1) + +void IntelObfuscation::AddRandomCommands() +{ + size_t i, j, c; + IntelCommand *new_command, *last_command; + std::vector template_command_list; + IntelCommandType command_type; + uint8_t reg; + OperandSize cpu_address_size = func_->cpu_address_size(); + uint8_t registr_count = (cpu_address_size == osDWord) ? 8 : 16; + IntelStackValue *stack_item; + IntelRegistrValue *reg_value; + uint16_t command_flags; + uint64_t source_value; + OperandSize size; + + c = 30 + (rand() % 10); + for (i = 0; i < c; i++) { + + last_command = command_list_.empty() ? NULL : command_list_.back(); + + template_command_list.clear(); + template_command_list.push_back(cmPush); + if (stack_.count()) { + template_command_list.push_back(cmPop); + if (stack_.count() < 20) { + template_command_list.push_back(cmPush); + if (last_command && last_command->type() != cmCall) { + template_command_list.push_back(cmCall); + template_command_list.push_back(cmCall); + template_command_list.push_back(cmCall); + template_command_list.push_back(cmCall); + + template_command_list.push_back(cmRet); + template_command_list.push_back(cmRet); + template_command_list.push_back(cmRet); + template_command_list.push_back(cmRet); + template_command_list.push_back(cmRet); + } + } + template_command_list.push_back(cmLea); + template_command_list.push_back(cmMov); + template_command_list.push_back(cmMovsx); + template_command_list.push_back(cmMovzx); + + template_command_list.push_back(cmCbw); + template_command_list.push_back(cmCwde); + template_command_list.push_back(cmCwd); + template_command_list.push_back(cmCdq); + if (cpu_address_size == osQWord) { + template_command_list.push_back(cmCdqe); + template_command_list.push_back(cmCqo); + } + template_command_list.push_back(cmBswap); + + if (last_command && (last_command->type() != cmCmp || flags_.mask() == 0)) { + template_command_list.push_back(cmAdd); + template_command_list.push_back(cmSub); + template_command_list.push_back(cmNeg); + template_command_list.push_back(cmCmp); + + template_command_list.push_back(cmAnd); + template_command_list.push_back(cmTest); + template_command_list.push_back(cmXor); + template_command_list.push_back(cmOr); + template_command_list.push_back(cmNot); + + template_command_list.push_back(cmShr); + template_command_list.push_back(cmShl); + template_command_list.push_back(cmSal); + template_command_list.push_back(cmSar); + template_command_list.push_back(cmRol); + template_command_list.push_back(cmRor); + } + + template_command_list.push_back(cmBt); + template_command_list.push_back(cmBtr); + template_command_list.push_back(cmBtc); + template_command_list.push_back(cmBts); + + if (flags_.mask()) { + template_command_list.push_back(cmJmpWithFlag); + template_command_list.push_back(cmJmpWithFlag); + template_command_list.push_back(cmJmpWithFlag); + template_command_list.push_back(cmJmpWithFlag); + template_command_list.push_back(cmJmpWithFlag); + + template_command_list.push_back(cmSetXX); + template_command_list.push_back(cmCmov); + if (flags_.mask() & fl_C) { + if (last_command && last_command->type() != cmCmc && last_command->type() != cmClc && last_command->type() != cmStc) { + template_command_list.push_back((flags_.value() & fl_C) ? cmClc : cmStc); + template_command_list.push_back(cmCmc); + } + template_command_list.push_back(cmAdc); + template_command_list.push_back(cmSbb); + } + } + } + + command_type = template_command_list[rand() % template_command_list.size()]; + switch (command_type) { + case cmPush: + if (rand() & 1) { + reg = rand() % registr_count; + if (reg == regESP) + reg = regEFX; + + if (!registr_values_.GetRegistr(reg)) { + if (stack_.GetRegistr(reg)) + break; + } + + if (reg == regEFX) + AddCommand(cmPushf, IntelOperand(otNone, func_->cpu_address_size(), 0)); + else + AddCommand(cmPush, IntelOperand(otRegistr, func_->cpu_address_size(), reg)); + + reg_value = registr_values_.GetRegistr(reg); + if (reg_value) + stack_.Add(reg_value->type(), reg_value->value()); + else + stack_.Add(vtRegistr, reg); + } + else { + uint64_t value = DWordToInt64(rand32()); + AddCommand(cmPush, IntelOperand(otValue, cpu_address_size, 0, value)); + stack_.Add(vtValue, value); + } + break; + + case cmPop: + AddRestoreStack(stack_.count() - 1); + break; + + case cmCall: + stack_.Add(vtReturnAddress, command_list_.size()); + + new_command = AddCommand(cmCall, IntelOperand(otValue, cpu_address_size, 0)); + new_command->AddLink(0, ltCall); + new_command->include_option(roUseAsJmp); + + jmp_command_list_[new_command] = command_list_.size(); + break; + + case cmRet: + if (IntelStackValue *ret_item = stack_.GetRandom(vtReturnAddress)) { + size_t ret_pos = stack_.IndexOf(ret_item); + IntelCommand *call_command = command_list_[static_cast(ret_item->value())]; + j = static_cast(call_command->operand(2).value); + if (j == 0) { + stack_item = stack_.GetRegistr(regEFX); + if (!stack_item) { + AddCommand(cmPushf, IntelOperand(otNone, func_->cpu_address_size(), 0)); + stack_item = stack_.Add(vtRegistr, regEFX); + } + stack_item->set_is_modified(true); + + call_command->set_operand_value(2, command_list_.size()); + + AddCommand(cmAdd, IntelOperand(otMemory | otRegistr | otValue, cpu_address_size, regESP, (stack_.count() - 1 - ret_pos) * OperandSizeToStack(cpu_address_size)), + IntelOperand(otValue, cpu_address_size, 0, DWordToInt64(rand32()))); + + flags_.clear(); + } + else { + IntelCommand *add_command = command_list_[j]; + CommandLink *link = add_command->AddLink(1, ltDelta); + link->set_parent_command(call_command); + link->set_sub_value(5); + + AddRestoreStack(ret_pos + 1); + delete ret_item; + + source_value = 0; + for (j = stack_.count(); j > 0; j--) { + stack_item = stack_.item(j - 1); + if (stack_item->type() == vtValue || stack_item->type() == vtReturnAddress || (stack_item->type() == vtRegistr && stack_item->value() == regEmpty)) { + if (rand() & 1) + break; + + delete stack_item; + source_value += OperandSizeToStack(cpu_address_size); + } else + break; + } + if (source_value) + AddCommand(cmRet, IntelOperand(otValue, osWord, 0, source_value)); + else + AddCommand(cmRet); + + jmp_command_list_[add_command] = command_list_.size(); + } + } + break; + + case cmJmpWithFlag: + command_flags = flags_.GetRandom(); + if (!command_flags) + break; + + new_command = AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size, 0)); + new_command->AddLink(0, ltJmpWithFlag); + new_command->set_flags(command_flags); + if (rand() & 1) + new_command->include_option(roInverseFlag); + + if (flags_.Check(new_command->flags()) == ((new_command->options() & roInverseFlag) == 0)) + new_command->include_option(roUseAsJmp); + + jmp_command_list_[new_command] = command_list_.size(); + break; + + case cmCbw: + case cmCwde: + case cmCdqe: + reg_value = registr_values_.GetRegistr(regEAX); + if (!reg_value) + break; + + AddCommand(command_type); + + switch (command_type) { + case cmCbw: + size = osWord; + break; + case cmCwde: + size = osDWord; + break; + default: + size = osQWord; + break; + } + + reg_value->Calc(command_type, 0, false, size, reg_value->value(), &flags_); + if (cpu_address_size == osQWord && size == osDWord) + reg_value->set_value(static_cast(reg_value->value())); + break; + + case cmCwd: + case cmCdq: + case cmCqo: + reg_value = registr_values_.GetRegistr(regEAX); + if (!reg_value) + break; + + source_value = reg_value->value(); + + switch (command_type) { + case cmCwd: + size = osWord; + break; + case cmCdq: + size = osDWord; + break; + default: + size = osQWord; + break; + } + + reg_value = registr_values_.GetRegistr(regEDX); + if (!reg_value) { + if (size != cpu_address_size) + break; + + stack_item = stack_.GetRegistr(regEDX); + if (!stack_item) { + AddCommand(cmPush, IntelOperand(otRegistr, cpu_address_size, regEDX)); + stack_item = stack_.Add(vtRegistr, regEDX); + } + stack_item->set_is_modified(true); + + reg_value = registr_values_.Add(regEDX, 0); + } + + AddCommand(command_type); + + reg_value->Calc(command_type, 0, false, size, source_value, &flags_); + if (cpu_address_size == osQWord && size == osDWord) + reg_value->set_value(static_cast(reg_value->value())); + break; + + case cmStc: + case cmCmc: + case cmClc: + if (flags_.mask() & fl_C) { + stack_item = stack_.GetRegistr(regEFX); + if (!stack_item) + break; + stack_item->set_is_modified(true); + + flags_.Calc(command_type, cpu_address_size, 0, 0, 0); + AddCommand(command_type); + } + break; + + default: + if (IntelStackValue *first_item = stack_.GetRandom(vtRegistr | vtValue)) { + source_value = 0; + + command_flags = 0; + bool inverse_flags = false; + IntelStackValue *flags_item = NULL; + + if (command_type == cmSetXX || command_type == cmCmov) { + command_flags = flags_.GetRandom(); + if (!command_flags) + break; + + if (rand() & 1) + inverse_flags = true; + } + else switch (command_type) { + case cmXor: + case cmAnd: + case cmTest: + case cmOr: + case cmNeg: + case cmAdd: + case cmAdc: + case cmSub: + case cmSbb: + case cmCmp: + case cmRor: + case cmRol: + case cmShr: + case cmShl: + case cmSar: + case cmSal: + case cmDec: + case cmInc: + case cmBt: + case cmBtr: + case cmBtc: + case cmBts: + flags_item = stack_.GetRegistr(regEFX); + if (!flags_item) + flags_item = NEED_STORE_FLAGS; + break; + } + + IntelOperand first_operand, second_operand; + + switch (rand() % 4) { + case 0: + first_operand.size = osByte; + break; + case 1: + first_operand.size = osWord; + break; + case 2: + first_operand.size = osDWord; + break; + default: + first_operand.size = cpu_address_size; + break; + } + + if (first_item->type() == vtRegistr) { + first_operand.type = otRegistr; + first_operand.registr = static_cast(first_item->value()); + + if (!registr_values_.GetRegistr(first_operand.registr)) { + command_type = cmMov; + first_operand.size = cpu_address_size; + } + } + else { + first_operand.type = otMemory | otBaseRegistr | otValue; + first_operand.base_registr = regESP; + first_operand.value = (stack_.count() - 1 - stack_.IndexOf(first_item)) * OperandSizeToStack(cpu_address_size); + if (flags_item == NEED_STORE_FLAGS) + first_operand.value += OperandSizeToStack(cpu_address_size); + } + + if (command_type == cmLea) { + if (first_operand.type != otRegistr || !registr_values_.count()) + break; + + first_operand.size = cpu_address_size; + second_operand.size = first_operand.size; + + reg_value = registr_values_.item(rand() % registr_values_.count()); + + second_operand.type = otMemory | otRegistr | otValue; + second_operand.registr = reg_value->registr(); + second_operand.scale_registr = rand() & 3; + + source_value = reg_value->value(); + if (second_operand.scale_registr) + source_value = source_value << second_operand.scale_registr; + + if (rand() & 1) { + reg_value = registr_values_.item(rand() % registr_values_.count()); + second_operand.type |= otBaseRegistr; + second_operand.base_registr = reg_value->registr(); + source_value = source_value + reg_value->value(); + } + + second_operand.value_size = second_operand.size; + switch (second_operand.size) { + case osByte: + second_operand.value = ByteToInt64(rand32()); + break; + case osWord: + second_operand.value = WordToInt64(rand32()); + break; + default: + second_operand.value = DWordToInt64(rand32()); + second_operand.value_size = osDWord; + break; + } + source_value = source_value + second_operand.value; + } + else if (command_type == cmSetXX) { + first_operand.size = osByte; + } + else if (command_type == cmShr || command_type == cmShl || command_type == cmSal || command_type == cmSar || command_type == cmRol || command_type == cmRor) { + second_operand.size = osByte; + switch (rand() % 2) { + case 0: + reg_value = registr_values_.GetRegistr(regECX); + if (reg_value) { + second_operand.type = otRegistr; + second_operand.registr = reg_value->registr(); + + source_value = reg_value->value(); + break; + } + default: + second_operand.type = otValue; + second_operand.value = static_cast(rand()); + if (!second_operand.value) + second_operand.value = 1; + second_operand.value_size = second_operand.size; + + source_value = second_operand.value; + break; + } + } + else if (command_type != cmNot && command_type != cmNeg && command_type != cmBswap) { + second_operand.size = first_operand.size; + switch (rand() % 3) { + case 0: + if (registr_values_.count()) { + reg_value = registr_values_.item(rand() % registr_values_.count()); + source_value = reg_value->value(); + + second_operand.type = otRegistr; + second_operand.registr = reg_value->registr(); + break; + } + case 1: + if (first_operand.type == otRegistr) { + stack_item = stack_.GetRandom(otValue); + if (stack_item) { + source_value = stack_item->value(); + + second_operand.type = otMemory | otBaseRegistr | otValue; + second_operand.base_registr = regESP; + second_operand.value = (stack_.count() - 1 - stack_.IndexOf(stack_item)) * OperandSizeToStack(cpu_address_size); + if (flags_item == NEED_STORE_FLAGS) + second_operand.value += OperandSizeToStack(cpu_address_size); + break; + } + } + default: + second_operand.type = otValue; + second_operand.value_size = second_operand.size; + switch (second_operand.size) { + case osByte: + second_operand.value = ByteToInt64(rand32()); + break; + case osWord: + second_operand.value = WordToInt64(rand32()); + break; + case osQWord: + if (command_type == cmMov && first_operand.type == otRegistr) { + second_operand.value = rand64(); + break; + } + default: + second_operand.value = DWordToInt64(rand32()); + second_operand.value_size = osDWord; + break; + } + + source_value = second_operand.value; + } + } + + if (command_type == cmCmov) { + if (first_operand.type != otRegistr || first_operand.size == osByte || second_operand.type == otValue) + break; + } + else if (command_type == cmMovsx || command_type == cmMovzx) { + if (first_operand.type != otRegistr || first_operand.size == osByte || second_operand.type == otValue) + break; + + second_operand.size = rand() & 1 ? osByte : osWord; + if (first_operand.size == osQWord && command_type == cmMovsx && (rand() & 1)) { + command_type = cmMovsxd; + second_operand.size = osDWord; + } + + if (command_type == cmMovzx) { + switch (second_operand.size) { + case osByte: + source_value = static_cast(source_value); + break; + case osWord: + source_value = static_cast(source_value); + break; + case osDWord: + source_value = static_cast(source_value); + break; + } + } + else { + switch (second_operand.size) { + case osByte: + source_value = ByteToInt64(static_cast(source_value)); + break; + case osWord: + source_value = WordToInt64(static_cast(source_value)); + break; + case osDWord: + source_value = DWordToInt64(static_cast(source_value)); + break; + } + } + } + else if (command_type == cmBt || command_type == cmBtr || command_type == cmBtc || command_type == cmBts) { + if (first_operand.size == osByte || first_operand.type != otRegistr || (second_operand.type & otMemory)) + break; + + if (second_operand.type == otValue) { + second_operand.size = osByte; + second_operand.value_size = osByte; + second_operand.value = static_cast(second_operand.value); + source_value = second_operand.value; + } + } + else if (command_type == cmBswap) { + if (first_operand.size == osByte || first_operand.size == osWord || first_operand.type != otRegistr) + break; + } + + if (cpu_address_size == osDWord) { + if (first_operand.type == otRegistr && first_operand.size == osByte && first_operand.registr >= 4) + break; + if (second_operand.type == otRegistr && second_operand.size == osByte && second_operand.registr >= 4) + break; + } + + if (flags_item == NEED_STORE_FLAGS) { + AddCommand(cmPushf, IntelOperand(otNone, func_->cpu_address_size(), 0)); + flags_item = stack_.Add(vtRegistr, regEFX); + } + if (flags_item) + flags_item->set_is_modified(true); + + new_command = AddCommand(command_type, first_operand, second_operand); + if (command_flags) { + new_command->set_flags(command_flags); + if (inverse_flags) + new_command->include_option(roInverseFlag); + } + + if (first_operand.type == otRegistr) { + bool is_modified = (command_type != cmCmp && command_type != cmTest && command_type != cmBt); + if (is_modified) + first_item->set_is_modified(true); + reg_value = registr_values_.GetRegistr(first_operand.registr); + if (reg_value) { + reg_value->Calc(command_type, command_flags, inverse_flags, first_operand.size, source_value, &flags_); + if (is_modified) { + if (cpu_address_size == osQWord && first_operand.size == osDWord) + reg_value->set_value(static_cast(reg_value->value())); + } + } + else + registr_values_.Add(first_operand.registr, source_value); + } + else { + first_item->Calc(command_type, command_flags, inverse_flags, first_operand.size, source_value, &flags_); + } + } + break; + } + } +} + +IntelCommand *IntelFunction::AddGate(ICommand *to_command, AddressRange *address_range) +{ + size_t i; + + IntelVirtualMachine *virtual_machine = reinterpret_cast(to_command->block()->virtual_machine()); + size_t old_count = count(); + + IntelCommand *command = AddCommand(cmPush, IntelOperand(otValue, cpu_address_size())); + CommandLink *link = command->AddLink(0, ltJmp, to_command); + link->set_cryptor(virtual_machine->entry_cryptor()); + if (to_command && to_command->seh_handler()) + command->set_seh_handler(NEED_SEH_HANDLER); + + command = AddCommand(cmCall, IntelOperand(otValue, cpu_address_size())); + command->include_option(roUseAsJmp); + command->AddLink(0, ltCall, virtual_machine->entry_command()); +#ifndef DEMO + if (false) + if (virtual_machine->processor()->cpu_address_size() == cpu_address_size()) { + IntelObfuscation engine; + engine.Compile(this, old_count); + } +#endif + + CommandBlock *cur_block = NULL; + for (i = old_count; i < count(); i++) { + if (!cur_block) + cur_block = AddBlock(i, true); + + command = item(i); + command->CompileToNative(); + command->set_block(cur_block); + + cur_block->set_end_index(i); + if (command->is_end()) + cur_block = NULL; + } + + IntelCommand *res = item(old_count); + if (address_range) { + cur_block = res->block(); + for (i = cur_block->start_index(); i <= cur_block->start_index(); i++) { + command = item(i); + command->set_address_range(address_range); + } + } + + return res; +} + +IntelCommand *IntelFunction::AddShortGate(ICommand *to_command, AddressRange *address_range) +{ + CommandBlock *cur_block = AddBlock(count(), true); + + IntelCommand *res = AddCommand(cmJmp, IntelOperand(otValue, cpu_address_size())); + res->AddLink(0, ltJmp, to_command); + if (to_command && to_command->seh_handler()) + res->set_seh_handler(NEED_SEH_HANDLER); + + cur_block->set_end_index(count() - 1); + + for (size_t i = cur_block->start_index(); i <= cur_block->end_index(); i++) { + IntelCommand *command = item(i); + command->CompileToNative(); + command->set_block(cur_block); + if (address_range) + command->set_address_range(address_range); + } + + return res; +} + +void IntelFunction::CompileToVM(const CompileContext &ctx) +{ + size_t i, j, c; + IntelCommand *command; + + // create internal links + c = link_list()->count(); + for (i = 0; i < count(); i++) { + command = item(i); + if (command->block() || (command->options() & roNeedCompile) == 0) + continue; + + if (command->is_data()) { + if (command->link() && command->link()->type() == ltCase) { + // create blocks for CASEs + CommandBlock *cur_block = NULL; + for (j = i; j < count(); j++) { + command = item(j); + if (command->link() && command->link()->type() == ltCase) { + if (command->block() || (command->options() & roNeedCompile) == 0 || is_breaked_address(command->address())) { + cur_block = NULL; + continue; + } + + if (!cur_block || (command->options() & roCreateNewBlock)) { + cur_block = AddBlock(j); + cur_block->set_virtual_machine(virtual_machine(ctx.file->virtual_machine_list(), command)); + } + cur_block->set_end_index(j); + + command->set_block(cur_block); + + command->CompileToVM(ctx); + } else { + break; + } + } + } + continue; + } + + if ((command->options() & roLockPrefix) && (command->options() & roNoNative) == 0) { + command->AddLink(-1, ltNative); + continue; + } else { + bool relocation_found = false; + for (j = 0; j < 3; j++) { + IntelOperand operand = command->operand(j) ; + if (operand.type == otNone) + break; + + if (operand.relocation) { + relocation_found = true; + break; + } + } + if (relocation_found) { + command->AddLink(-1, ltNative); + continue; + } + } + + switch (command->type()) { + case cmJmp: case cmCall: + if (command->options() & roFar) + command->AddLink(-1, ltNative); + break; + case cmLods: case cmMovs: case cmScas: case cmCmps: case cmStos: + if (command->preffix_command() == cmRep || command->preffix_command() == cmRepe || command->preffix_command() == cmRepne) + command->AddLink(-1, ltNative); + break; + case cmCmov: + command->AddLink(-1, ltJmpWithFlagNSNA); + break; + case cmXchg: + if (((command->operand(0).type | command->operand(1).type) & otMemory) && (command->options() & roNoNative) == 0) + command->AddLink(-1, ltNative); + break; + case cmFadd: case cmFsub: case cmFisub: case cmFsubr: case cmFdiv: case cmFmul: + case cmFcomp: case cmFild: case cmFld: case cmFstp: case cmFst: + if (command->operand(0).type == otFPURegistr) + command->AddLink(-1, ltNative); + break; + case cmPush: case cmPop: case cmMov: case cmMovsx: case cmMovsxd: case cmMovzx: + case cmJmpWithFlag: case cmJCXZ: case cmLoop: case cmLoope: case cmLoopne: + case cmRet: case cmIret: + case cmLea: case cmNop: case cmFnop: + case cmNot: case cmNeg: case cmAdd: case cmAdc: case cmXadd: + case cmSub: case cmCmp: case cmInc: case cmDec: case cmXlat: case cmSetXX: + case cmAnd: case cmXor: case cmTest: case cmOr: + case cmShld: case cmShrd: + case cmRol: case cmRor: case cmRcl: case cmRcr: + case cmShl: case cmSal: case cmShr: case cmSar: + case cmCbw: case cmCwde: case cmCwd: case cmCdq: case cmCdqe: case cmCqo: + case cmPushf: case cmPopf: case cmPusha: case cmPopa: + case cmLahf: case cmSahf: + case cmBt: case cmBtr: case cmBts: case cmBtc: + case cmClc: case cmStc: case cmCmc: case cmCld: case cmStd: + case cmBswap: case cmLeave: + case cmImul: case cmMul: case cmDiv: case cmIdiv: + case cmLes: case cmLds: case cmLfs: case cmLgs: + case cmFstsw: case cmFldcw: case cmFstcw: + case cmF2xm1: case cmFabs: case cmFclex: case cmFcos: case cmFdecstp: case cmFincstp: + case cmFinit: case cmFldln2: case cmFldlg2: case cmFprem: case cmFprem1: case cmFptan: + case cmFrndint: case cmFsin: case cmFtst: case cmFyl2x: case cmFpatan: case cmFldz: case cmFld1: case cmFldpi: + case cmWait: case cmFchs: case cmFsqrt: + case cmFistp: case cmFist: case cmRdtsc: + case cmCrc: + // do nothing + break; + + default: + if ((command->options() & roNoNative) == 0) + command->AddLink(-1, ltNative); + break; + } + } + for (i = c; i < link_list()->count(); i++) { + link_list()->item(i)->from_command()->PrepareLink(ctx); + } + + // optimize flags + IntelCommand *flag_command = NULL; + uint64_t flags = 0; + IntelCommandInfoList command_info(cpu_address_size()); + for (i = 0; i < count(); i++) { + command = item(i); + + if ((command->link() && command->link()->type() == ltNative) || !command->GetCommandInfo(command_info) || command_info.GetInfo(atWrite, otBaseRegistr, regEIP)) { + flag_command = NULL; + continue; + } + + if (!flag_command) { + if (command_info.change_flags()) { + flag_command = command; + flags = command_info.change_flags(); + } + } else { + if (command_info.need_flags()) { + if ((command_info.need_flags() & flags) != 0) { + flag_command = NULL; + continue; + } + } + if (command_info.change_flags()) { + if ((command_info.change_flags() & flags) == flags) { + flag_command->include_option(roNoSaveFlags); + flag_command = command; + flags = command_info.change_flags(); + } + } + } + } + + // create VM blocks + CommandBlock *cur_block = NULL; + uint64_t cur_eip = (uint64_t)-1; + for (i = 0; i < count(); i++) { + command = item(i); + if ((command->options() & roNoProgress) == 0) + ctx.file->StepProgress(); + + if (command->block() || (command->options() & roNeedCompile) == 0 || is_breaked_address(command->address())) { + cur_block = NULL; + continue; + } + + bool is_data = command->is_data() && (!command->link() || command->link()->type() != ltNative); + bool new_block = (!cur_block || (command->options() & roCreateNewBlock) || item(cur_block->end_index())->is_data() != is_data); + if (new_block) { + cur_block = AddBlock(i, is_data); + if (!is_data) + cur_block->set_virtual_machine(virtual_machine(ctx.file->virtual_machine_list(), command)); + } + + cur_block->set_end_index(i); + + command->set_block(cur_block); + if (command->seh_handler()) + command->seh_handler()->set_deleted(true); + if (is_data) { + cur_eip = (uint64_t)-1; + } else { + if (command->block()->virtual_machine()->backward_direction()) + command->include_section_option(rtBackwardDirection); + if (new_block || (command->section_options() & (rtLinkedToInt | rtLinkedToExt))) { + command->AddExtSection(ctx, NULL); + cur_eip = (uint64_t)-1; + } + cur_eip = command->AddStoreEIPSection(ctx, cur_eip); + if (command->section_options() & rtLinkedToExt) + command->AddStoreExtRegistersSection(ctx); + } + if (command->options() & roNeedCompile) { + if (is_data) { + command->CompileToNative(); + } else { + command->CompileToVM(ctx); + } + } + + if (!is_data) { + if ((command->section_options() & rtEndSection) == 0 && i < count() - 1 && (item(i + 1)->section_options() & (rtLinkedToInt | rtLinkedToExt))) + command->AddExtSection(ctx, item(i + 1)); + } + + if (command->section_options() & rtCloseSection) + cur_block = NULL; + } + + // create gates for external commands + ExtCommandList *ext_list = ext_command_list(); + for (i = 0; i < ext_list->count(); i++) { + ExtCommand *ext_command = ext_list->item(i); + if (!ext_command->command() || is_breaked_address(ext_command->address())) + continue; + + command = AddGate(ext_command->command(), ext_command->command()->address_range()); + + if (ext_command->address()) { + command = AddShortGate(command, NULL); + command->block()->set_address(ext_command->address()); + } + + if (entry() == ext_command->command()) + set_entry(command); + } +} + +bool IntelFunction::Compile(const CompileContext &ctx) +{ + switch (compilation_type()) { + case ctMutation: //bian yi + CompileToNative(ctx); + break; + case ctVirtualization: //xu ni hua + CompileToVM(ctx); + break; + case ctUltra://xu ni hua + bian yi + Mutate(ctx, true); + CompileToVM(ctx); + break; + default: + return false; + } + + return BaseFunction::Compile(ctx); +} + +void IntelFunction::AfterCompile(const CompileContext &ctx) +{ + size_t i, j, c; + IntelCommand *command, *from_command, *gate_command, *native_command; + CommandBlock *block; + CommandLink *link; + + if (compilation_type() == ctMutation) { + for (i = 0; i < link_list()->count(); i++) { + link = link_list()->item(i); + if (!link->to_command()) + continue; + + from_command = reinterpret_cast(link->from_command()); + if ((from_command->section_options() & rtLinkedFromOtherType) && !link->to_command()->is_data()) + link->set_to_command(AddGate(link->to_command(), NULL)); + + switch (link->type()) { + case ltMemSEHBlock: case ltExtSEHHandler: case ltVBMemSEHBlock: + if (from_command->address()) { + block = AddBlock(count(), true); + command = from_command->Clone(this); + AddObject(command); + command->set_block(block); + block->set_address(command->address()); + + CommandLink *dst_link = command->AddLink(0, ltOffset, link->to_command()); + dst_link->set_sub_value(link->sub_value()); + } + break; + } + } + } else { + // create native gates for links + c = count(); + for (i = 0; i < c; i++) { + from_command = item(i); + link = from_command->link(); + if (!link) + continue; + + IntelCommand *to_command = reinterpret_cast(link->to_command()); + ICommand *next_command = link->next_command(); + IntelCommand *parent_command = reinterpret_cast(link->parent_command()); + + if (to_command && to_command->block() && (to_command->block()->type() & mtExecutable) == 0) { + // to VM block + switch (link->type()) { + case ltGateOffset: + link->set_to_command(AddGate(to_command, to_command->address_range())); + break; + case ltMemSEHBlock: case ltExtSEHHandler: case ltVBMemSEHBlock: + if (to_command) { + if (from_command->address()) { + block = AddBlock(count(), true); + native_command = from_command->Clone(this); + AddObject(native_command); + native_command->set_block(block); + block->set_address(native_command->address()); + } + else { + native_command = NULL; + } + + gate_command = AddGate(to_command, to_command->address_range()); + + if (native_command) { + CommandLink *dst_link = native_command->AddLink(0, ltOffset, gate_command); + dst_link->set_sub_value(link->sub_value()); + } + + link->set_to_command(gate_command); + } + break; + } + } + + if (from_command->block() && (from_command->block()->type() & mtExecutable) == 0) { + // from VM block + switch (link->type()) { + case ltSEHBlock: case ltFinallyBlock: case ltExtSEHBlock: + if (to_command) + link->AddGateCommand(AddGate(to_command, to_command->address_range())); + break; + + case ltCall: + if (next_command && (from_command->options() & roInternal) == 0) { + if (from_command->address_range()) { + Data data; + data.PushByte(rand()); + command = AddCommand(data); + command->set_address_range(from_command->address_range()); + gate_command = AddGate(next_command, next_command->address_range()); + command->set_block(gate_command->block()); + command->block()->set_start_index(command->block()->start_index() - 1); + } + else { + gate_command = AddGate(next_command, next_command->address_range()); + } + } + else { + gate_command = NULL; + } + + link->AddGateCommand(gate_command); + break; + + case ltNative: + native_command = from_command->Clone(this); + AddObject(native_command); + + if (next_command) { + gate_command = AddGate(next_command, native_command->address_range()); + } + else { + gate_command = AddShortGate(NULL, native_command->address_range()); + gate_command->set_operand_value(0, from_command->address() + from_command->original_dump_size()); + gate_command->CompileToNative(); + } + block = gate_command->block(); + block->set_start_index(block->start_index() - 1); + native_command->set_block(block); + + link->AddGateCommand(native_command); + break; + + case ltDualSEHBlock: + if (to_command) { + block = AddBlock(count(), true); + gate_command = reinterpret_cast(to_command->Clone(this)); + AddObject(gate_command); + CommandLink *src_link = to_command->link(); + if (src_link) { + CommandLink *dst_link = src_link->Clone(link_list()); + dst_link->set_from_command(gate_command); + dst_link->set_to_command(src_link->to_command()); + link_list()->AddObject(dst_link); + } + command = new IntelCommand(this, cpu_address_size(), cmJmp, IntelOperand(otValue, cpu_address_size(), 0, link->to_address() + 5)); + AddObject(command); + command->AddLink(0, ltJmp, next_command); + block->set_end_index(count() - 1); + + if (gate_command->link()->to_command()) + gate_command->link()->set_to_command(AddGate(gate_command->link()->to_command(), gate_command->address_range())); + + if (command->link()->to_command()) + command->link()->set_to_command(AddGate(command->link()->to_command(), command->address_range())); + + for (j = block->start_index(); j <= block->end_index(); j++) { + command = item(j); + command->set_block(block); + command->CompileToNative(); + } + + link->AddGateCommand(gate_command); + } + break; + + case ltFilterSEHBlock: + if (to_command) { + block = AddBlock(count(), true); + size_t index = IndexOf(to_command); + size_t n = 2 + static_cast(reinterpret_cast(link->parent_command())->operand(0).value) * 2; + for (j = 0; j < n; j++) { + native_command = item(index + j); + command = native_command->Clone(this); + AddObject(command); + CommandLink *src_link = native_command->link(); + if (src_link) { + CommandLink *dst_link = src_link->Clone(link_list()); + dst_link->set_from_command(command); + dst_link->set_to_command(src_link->to_command()); + link_list()->AddObject(dst_link); + } + command->set_block(block); + } + block->set_end_index(count() - 1); + for (j = block->start_index(); j <= block->end_index(); j++) { + CommandLink *src_link = item(j)->link(); + if (!src_link || !src_link->to_command()) + continue; + + src_link->set_to_command(AddGate(src_link->to_command(), src_link->from_command()->address_range())); + } + gate_command = item(block->start_index()); + link->AddGateCommand(gate_command); + } + break; + + case ltCase: + if (to_command) { + block = AddBlock(count()); + block->set_virtual_machine(parent_command->block()->virtual_machine()); + + command = AddCommand(cmJmp); + command->AddLink(-1, ltNone); + command->include_section_option(rtLinkedToInt); + command->set_block(block); + if (command->block()->virtual_machine()->backward_direction()) + command->include_section_option(rtBackwardDirection); + + command->AddBeginSection(ctx); + if (from_command->section_options() & rtLinkedFrom) { + command->AddVMCommand(ctx, cmPush, otValue, cpu_address_size(), 0, voLinkCommand | voFixup); + command->AddEndSection(ctx, cmJmp, 0); + } + else { + command->AddVMCommand(ctx, cmPush, otValue, cpu_address_size(), 0, voLinkCommand | voFixup); + command->AddEndSection(ctx, cmRet); + } + link->AddGateCommand(command); + } + break; + } + } + } + } + + for (i = 0; i < count(); i++) { + command = item(i); + if (!command->block()) + continue; + + for (j = 0; j < 3; j++) { + IntelOperand operand = command->operand(j); + if (operand.type == otNone) + break; + + IFixup *fixup = operand.fixup; + if (fixup && fixup != NEED_FIXUP) { + if (command->options() & roClearOriginalCode) + fixup->set_deleted(true); + if (command->block()->type() & mtExecutable) { + if (command->block()->address()) { + fixup->set_deleted(false); + } + else { + fixup = fixup->Clone(ctx.file->fixup_list()); + ctx.file->fixup_list()->AddObject(fixup); + fixup->set_deleted(false); + command->set_operand_fixup(j, fixup); + } + } + else { + for (size_t k = 0; k < command->count(); k++) { + IntelVMCommand *vm_command = command->item(k); + if (vm_command->fixup()) { + fixup = fixup->Clone(ctx.file->fixup_list()); + ctx.file->fixup_list()->AddObject(fixup); + fixup->set_deleted(false); + vm_command->set_fixup(fixup); + } + } + } + } + } + } + + if (function_info_list()->count()) { + std::set range_list; + + for (i = 0; i < block_list()->count(); i++) { + CommandBlock *block = block_list()->item(i); + if ((block->type() & mtExecutable) == 0) + continue; + + AddressRange *block_range = item(block->start_index())->address_range(); + if (block_range) + range_list.insert(block_range); + + for (j = block->start_index(); j <= block->end_index(); j++) { + AddressRange *range = item(j)->address_range(); + if (range && range != block_range) + range_list.insert(range); + } + } + + for (i = 0; i < function_info_list()->count(); i++) { + FunctionInfo *info = function_info_list()->item(i); + for (size_t j = 0; j < info->count(); j++) { + AddressRange *range = info->item(j); + if (range_list.find(range) == range_list.end()) { + Data data; + data.PushByte(rand()); + + CommandBlock *block = AddBlock(count(), true); + ICommand *command = AddCommand(data); + command->set_block(block); + command->set_address_range(range); + } + } + } + } +} + +void IntelFunction::CompileInfo(const CompileContext &ctx) +{ + BaseFunction::CompileInfo(ctx); + + size_t i; + FunctionInfo *info; + AddressRange *range; + uint64_t base_value; + IntelCommand *command; + + for (i = 0; i < range_list()->count(); i++) { + range = range_list()->item(i); + info = range->link_info(); + if (!info) + continue; + + switch (info->base_type()) { + case btImageBase: + base_value = ctx.file->image_base(); + break; + case btFunctionBegin: + base_value = info->begin(); + break; + default: + base_value = info->base_value(); + break; + } + + if (range->begin_entry()) { + command = reinterpret_cast(range->begin_entry()); + if (command->type() == cmDC) { + AddressRange *prev = NULL; + for (size_t j = 0; j < i; j++) { + AddressRange *tmp = range_list()->item(j); + if (tmp->link_info() == info && tmp->original_end() == range->original_begin() && tmp->begin_entry()) { + prev = tmp; + break; + } + } + base_value = prev ? prev->begin() : info->begin(); + } + command->set_operand_value(0, range->begin() - base_value); + command->CompileToNative(); + } + if (range->end_entry()) { + command = reinterpret_cast(range->end_entry()); + command->set_operand_value(0, range->end() - base_value); + command->CompileToNative(); + } + if (range->size_entry()) { + command = reinterpret_cast(range->size_entry()); + command->set_operand_value(0, range->end() - range->begin()); + if (command->type() == cmDB) { + uint32_t size = static_cast(command->operand(0).value); + Data data; + if (command->comment().value == "UWOP_EPILOG") { + uint32_t offset = static_cast(info->end() - range->begin()); + UNWIND_CODE unwind_code; + unwind_code.FrameOffset = static_cast(command->dump_value(0, osWord)); + if (unwind_code.OpInfo & 1) { + unwind_code.CodeOffset = static_cast(offset); + data.PushWord(unwind_code.FrameOffset); + } else { + unwind_code.CodeOffset = static_cast(size); + data.PushWord(unwind_code.FrameOffset); + unwind_code.CodeOffset = static_cast(offset); + unwind_code.OpInfo = static_cast(offset >> 8); + data.PushWord(unwind_code.FrameOffset); + } + command->set_dump(data.data(), data.size()); + } else if (command->comment().value.substr(0, 18) == "DW_CFA_advance_loc") { + if (size <= 0x3f) { + data.PushByte(DW_CFA_advance_loc | (size & 0x3f)); + } + else if (size <= 0xff) { + data.PushByte(DW_CFA_advance_loc1); + data.PushByte(static_cast(size)); + } + else if (size <= 0xffff) { + data.PushByte(DW_CFA_advance_loc2); + data.PushWord(static_cast(size)); + } + else { + data.PushByte(DW_CFA_advance_loc4); + data.PushDWord(size); + } + command->set_dump(data.data(), data.size()); + } + } else + command->CompileToNative(); + } + } +} + +void IntelFunction::CompileLinks(const CompileContext &ctx) +{ + BaseFunction::CompileLinks(ctx); + + bool need_encrypt = (ctx.options.flags & cpEncryptBytecode) != 0; + for (size_t i = 0; i < block_list()->count(); i++) { + CommandBlock *block = block_list()->item(i); + + // skip native blocks + if (block->type() & mtExecutable) + continue; + + IntelVirtualMachine *virtual_machine = reinterpret_cast(block->virtual_machine()); + virtual_machine->CompileBlock(*block, need_encrypt); + } +} + +void IntelFunction::AddWatermarkReference(uint64_t address, const std::string &value) +{ + IntelCommand *ref_command = GetCommandByAddress(address); + if (!ref_command || value.empty()) + return; + + uint32_t key = rand32(); + uint16_t len = static_cast(value.size()); + Data data; + data.PushDWord(key); + data.PushWord(len); + for (size_t i = 0; i < value.size(); i++) { + data.PushByte(value[i] ^ static_cast(_rotl32(key, (int)i) + i)); + } + IntelCommand *data_command = AddCommand(data); + + switch (ref_command->type()) { + case cmLea: + { + IntelCommand *mem_command = AddCommand(cpu_address_size() == osDWord ? cmDD : cmDQ, IntelOperand(otValue, cpu_address_size(), 0, 0, NEED_FIXUP)); + mem_command->AddLink(0, ltOffset, data_command); + mem_command->CompileToNative(); + + ref_command->AddLink(1, ltOffset, mem_command); + } + break; + case cmMov: + ref_command->Init(cmLea, ref_command->operand(0), ref_command->operand(1)); + ref_command->AddLink(1, ltOffset, data_command); + break; + default: + throw std::runtime_error("Unknown reference command"); + } +} + +void IntelFunction::ReadFromBuffer(Buffer &buffer, IArchitecture &file) +{ + BaseFunction::ReadFromBuffer(buffer, file); + + size_t i, j, k; + IntelCommand *command; + bool syscall_found = false; + + for (i = 0; i < count(); i++) { + command = item(i); + if (command->type() == cmCpuid || command->type() == cmSbb) + command->include_option(roNoNative); + else if (command->type() == cmPopf) { + Data data; + command->CompileToNative(); + for (k = 0; k < command->dump_size(); k++) { + data.PushByte(command->dump(k)); + } + command->Init(cmNop); + + for (j = i; j < count(); j++) { + command = item(j); + if (command->type() == cmCpuid || command->type() == cmRdtsc) { + command->CompileToNative(); + for (k = 0; k < command->dump_size(); k++) { + data.PushByte(command->dump(k)); + } + data.PushByte(0x90); + command->Init(data); + command->AddLink(-1, ltNative); + break; + } + } + } else if (command->operand(1).type == otValue && static_cast(command->operand(1).value) == FACE_SYSCALL) { + command->set_operand_value(1, 0); + command->CompileToNative(); + IntelOperand operand = command->operand(0); + IntelCommandInfoList command_info_list(cpu_address_size()); + size_t cur_index = i + 1; + std::vector stack; + + while (cur_index < count()) { + command = item(cur_index); + bool is_end = command->is_end(); + if (command->type() == cmMov) { + if (operand.type == otRegistr && command->operand(1) == operand) { + operand = command->operand(0); + cur_index++; + continue; + } + } else if (command->type() == cmCall) { + if (command->operand(0) == operand) { + command->Init(cmSyscall, command->operand(0)); + command->CompileToNative(); + command->include_option(roNoNative); + syscall_found = true; + } + if (operand.type != otRegistr || operand.registr == regEAX) + is_end = true; + } else if ((command->type() == cmJmp || command->type() == cmJmpWithFlag) && command->link()) { + IntelCommand *link_command = GetCommandByAddress(command->link()->to_address()); + if (link_command) { + k = IndexOf(link_command); + if (k != NOT_ID) + stack.push_back(k); + } + } + if (command->GetCommandInfo(command_info_list)) { + if (operand.type == otRegistr && command_info_list.GetInfo(atWrite, otRegistr, operand.registr)) + is_end = true; + } else { + is_end = true; + } + + if (is_end) { + for (k = stack.size(); k > 0; k--) { + if (stack[k - 1] <= cur_index) + stack.erase(stack.begin() + k - 1); + } + if (stack.empty()) + break; + + cur_index = stack[0]; + for (k = 0; k < stack.size(); k++) { + if (cur_index > stack[k]) + cur_index = stack[k]; + } + } else { + cur_index++; + } + } + } + } + + if (syscall_found) { + CallingConvention calling_convention = file.calling_convention(); + for (i = 0; i < count(); i++) { + command = item(i); + if (command->type() != cmSyscall) + continue; + + IntelCommand *next_command = item(i + 1); + if (next_command->type() == cmAdd && next_command->operand(0).type == otRegistr && next_command->operand(0).registr == regESP) + continue; + + k = 0; + for (j = i; j > 0; j--) { + IntelCommand *param_command = item(j - 1); + + switch (param_command->type()) { + case cmPush: + if (calling_convention == ccStdcall) { + k++; + } + else { + param_command = NULL; + } + break; + case cmMov: case cmLea: case cmXor: case cmMovsxd: + if (calling_convention == ccMSx64) { + if (param_command->operand(0).type == otRegistr) { + switch (param_command->operand(0).registr) { + case regECX: + k = std::max(k, 1); + break; + case regEDX: + k = std::max(k, 2); + break; + case regR8: + k = std::max(k, 3); + break; + case regR9: + k = std::max(k, 4); + break; + } + } + else if (param_command->operand(0).type == (otMemory | otBaseRegistr | otValue) && param_command->operand(0).base_registr == regESP) { + switch (param_command->operand(0).value) { + case 0x20: + k = std::max(k, 5); + break; + case 0x28: + k = std::max(k, 6); + break; + case 0x30: + k = std::max(k, 7); + break; + case 0x38: + k = std::max(k, 8); + break; + case 0x40: + k = std::max(k, 9); + break; + case 0x48: + k = std::max(k, 10); + break; + default: + if (param_command->operand(0).value >= 0x50) + k = NOT_ID; + break; + } + } + } + break; + case cmCall: case cmJmp: case cmJmpWithFlag: case cmRet: + param_command = NULL; + break; + } + if (!param_command || link_list()->GetLinkByToAddress(ltNone, param_command->address())) + break; + } + if (k == NOT_ID) + continue; + + command->include_option(roInternal); + command->set_operand_value(2, k); + } + } + + if (file.owner()->format_name() != "PE" && compilation_type() != ctMutation && cpu_address_size() == osQWord) { + // clang can use stack less than RSP + bool is_use_rbp = false; + uint64_t delta_rsp = 0; + uint64_t sub_rsp_value = 0; + for (j = 0; j < count(); j++) { + command = item(j); + switch (command->type()) { + case cmMov: + if (command->operand(0).type == otRegistr && command->operand(0).registr == regEBP && command->operand(1).type == otRegistr && command->operand(1).registr == regESP) { + is_use_rbp = true; + } else if (is_use_rbp && ((command->operand(0).type == (otMemory | otRegistr | otValue) && command->operand(0).registr == regEBP) + || ((command->operand(0).type & (otMemory | otBaseRegistr | otValue)) == (otMemory | otBaseRegistr | otValue) && command->operand(0).base_registr == regEBP))) { + uint64_t value = command->operand(0).value; + if (static_cast(value) < 0 && 0 - value > delta_rsp) { + sub_rsp_value = std::max((0 - value) - delta_rsp, sub_rsp_value); + } + } else if (((command->operand(0).type == (otMemory | otRegistr | otValue) && command->operand(0).registr == regESP) + || ((command->operand(0).type & (otMemory | otBaseRegistr | otValue)) == (otMemory | otBaseRegistr | otValue) && command->operand(0).base_registr == regESP))) { + uint64_t value = command->operand(0).value; + if (static_cast(value) < 0) + sub_rsp_value = std::max((0 - value), sub_rsp_value); + } + break; + case cmPush: + if (is_use_rbp) + delta_rsp += OperandSizeToValue(cpu_address_size()); + break; + case cmSub: + if (is_use_rbp && command->operand(0).type == otRegistr && command->operand(0).registr == regESP && command->operand(1).type == otValue) { + delta_rsp += command->operand(1).value; + } + break; + } + } + if (sub_rsp_value) { + size_t push_index = 0; + size_t pop_index = 0; + for (j = 0; j < count(); j++) { + IntelCommand *command = item(j); + + for (i = 0; i < 3; i++) { + IntelOperand operand = command->operand(i); + if (operand.type == otNone) + break; + + if (((operand.type & (otMemory | otRegistr)) == (otMemory | otRegistr) && operand.registr == regESP) + || ((operand.type & (otMemory | otBaseRegistr)) == (otMemory | otBaseRegistr) && operand.base_registr == regESP)) { + command->set_operand_value(i, operand.value + sub_rsp_value); + command->CompileToNative(); + } + } + + switch (command->type()) { + case cmPush: + push_index = j; + break; + case cmMov: + if (command->operand(0).type == otRegistr && command->operand(0).registr == regEBP && command->operand(1).type == otRegistr && command->operand(1).registr == regESP) + push_index = j; + break; + case cmPop: + case cmRet: + if (!pop_index) + pop_index = j; + break; + } + } + + command = new IntelCommand(this, cpu_address_size(), cmSub, IntelOperand(otRegistr, cpu_address_size(), regESP), IntelOperand(otValue, cpu_address_size(), 0, sub_rsp_value)); + command->CompileToNative(); + InsertObject(push_index + 1, command); + + if (pop_index > push_index) + pop_index++; + + IntelCommand *pop_command = item(pop_index); + + command = new IntelCommand(this, cpu_address_size(), static_cast(pop_command->type()), pop_command->operand(0), pop_command->operand(1)); + command->CompileToNative(); + InsertObject(pop_index + 1, command); + + pop_command->Init(cmAdd, IntelOperand(otRegistr, cpu_address_size(), regESP), IntelOperand(otValue, cpu_address_size(), 0, sub_rsp_value)); + pop_command->CompileToNative(); + } + } + +#ifdef CHECKED + for (i = 0; i < count(); i++) { + item(i)->update_hash(); + } +#endif +} + +/** + * SectionCryptor + */ + +SectionCryptor::SectionCryptor(SectionCryptorList *owner, OperandSize cpu_address_size) + : owner_(owner), parent_cryptor_(NULL) +{ + size_t i; + + registr_order_.push_back(regEFX); + registr_order_.push_back(regEAX); + registr_order_.push_back(regECX); + registr_order_.push_back(regEDX); + registr_order_.push_back(regEBX); + registr_order_.push_back(regEBP); + registr_order_.push_back(regESI); + registr_order_.push_back(regEDI); + if (cpu_address_size == osQWord) { + for (i = 8; i < 16; i++) { + registr_order_.push_back((uint8_t)i); + } + } + for (i = 0; i < registr_order_.size(); i++) { + std::swap(registr_order_[i], registr_order_[rand() % registr_order_.size()]); + } +} + +SectionCryptor::~SectionCryptor() +{ + if (owner_) + owner_->RemoveObject(this); +} + +void SectionCryptor::set_end_cryptor(SectionCryptor *cryptor) +{ + if (cryptor == this || cryptor->end_cryptor() == this) + return; + + if (parent_cryptor_) + parent_cryptor_->set_end_cryptor(cryptor); + else + parent_cryptor_ = cryptor; +} + +SectionCryptor *SectionCryptor::end_cryptor() +{ + SectionCryptor *cur_cryptor = this; + while (cur_cryptor->parent_cryptor_) { + cur_cryptor = cur_cryptor->parent_cryptor_; + } + return cur_cryptor; +} + +/** + * SectionCryptorList + */ + +SectionCryptorList::SectionCryptorList(IFunction *owner) + : ObjectList(), owner_(owner) +{ + +} + +SectionCryptor *SectionCryptorList::Add() +{ + SectionCryptor *section_cryptor = new SectionCryptor(this, owner_->cpu_address_size()); + AddObject(section_cryptor); + return section_cryptor; +} + +/** + * IntelFileHelper + */ + +IntelFileHelper::IntelFileHelper() + : IObject(), marker_index_(0) +{ + marker_name_list_ = new MapFunctionList(NULL); +} + +IntelFileHelper::~IntelFileHelper() +{ + delete marker_name_list_; +} + +void IntelFileHelper::AddMarker(IArchitecture &file, uint64_t address, uint64_t name_reference, uint64_t name_address, ObjectType type, uint8_t tag, bool is_unicode) +{ + if (type == otUnknown) + return; + + std::string marker_name; + MapFunction *map_function; + size_t name_length = 0; + if (name_address) { + // read marker name + if (file.AddressSeek(name_address)) { + if (is_unicode) { + os::unicode_string wname; + for (;;) { + os::unicode_char w = file.ReadWord(); + if (w == 0) + break; + wname.push_back(w); + } + name_length = (wname.size() + 1) * sizeof(os::unicode_char); + marker_name = os::ToUTF8(wname); + } else { + for (;;) { + char c = file.ReadByte(); + if (c == 0) + break; + marker_name.push_back(c); + } + name_length = marker_name.size() + 1; + marker_name = file.ANSIToUTF8(marker_name); + } + } + + map_function = marker_name_list_->GetFunctionByAddress(name_address); + if (!map_function) { + map_function = marker_name_list_->Add(name_address, name_address + name_length, otString, marker_name); + // need add marker name to string_list for string references searching + string_list_.push_back(map_function); + } + map_function->reference_list()->Add(name_reference, 0); + } + + std::string name = marker_name.empty() ? string_format("VMProtectMarker%d", ++marker_index_) : string_format("VMProtectMarker \"%s\"", marker_name.c_str()); + + map_function = file.map_function_list()->GetFunctionByAddress(address); + if (!map_function) { + map_function = file.map_function_list()->Add(address, 0, type, name); + } else { + map_function->set_type(type); + map_function->set_name(name); + } + map_function->set_name_address(name_address); + map_function->set_name_length(name_length); + switch (tag & 0x7f) { + case 1: + map_function->set_compilation_type(ctVirtualization); + break; + case 2: + map_function->set_compilation_type(ctMutation); + break; + case 3: + map_function->set_compilation_type(ctUltra); + break; + } + if (tag & 0x80) + map_function->set_lock_to_key(true); +} + +void IntelFileHelper::AddString(IArchitecture &file, uint64_t address, uint64_t reference, bool is_unicode) +{ + uint64_t end_address; + std::string name; + os::unicode_string wname; + char c; + os::unicode_char w; + MapFunction *map_function; + + if (!file.AddressSeek(address)) + return; + + // read string from file + if (is_unicode) { + for (;;) { + w = file.ReadWord(); + if (w == 0) + break; + wname.push_back(w); + } + end_address = address + (wname.size() + 1) * sizeof(w); + name = os::ToUTF8(wname); + } else { + for (;;) { + c = file.ReadByte(); + if (c == 0) + break; + name.push_back(c); + } + end_address = address + name.size() + 1; + name = file.ANSIToUTF8(name); + } + name = "string \"" + name + "\""; + + map_function = file.map_function_list()->Add(address, end_address, otString, name); + map_function->reference_list()->Add(reference, address); + + if (std::find(string_list_.begin(), string_list_.end(), map_function) == string_list_.end()) + string_list_.push_back(map_function); +} + +void IntelFileHelper::AddEndMarker(IArchitecture &file, uint64_t address, uint64_t next_address, ObjectType type) +{ + file.end_marker_list()->Add(address, next_address, 0, 0, type); +} + +void IntelFileHelper::Parse(IArchitecture &file) +{ + SignatureList asm_signatures, import_signatures, string_signatures, compiler_function_signatures; + ISectionList *segment_list; + size_t i, k, j, r, n, pointer_size, c; + ISection *segment; + uint64_t read_size, address, buf_address, operand_address, tmp_address, pointer_value, last_operand_address; + uint8_t buf[4096], b, registr; + Signature *sign; + IntelFunctionList function_list(NULL); + IntelFunction command_list(NULL, file.cpu_address_size()); + IntelCommand *command, *tmp_command; + IImportFunction *import_function; + IntelOperand operand, tmp_operand; + IFixupList *fixup_list; + IImportList *import_list; + std::map jmp_references; + MarkerCommandList marker_command_list; + MarkerCommand *marker_command; + MapFunction *map_function; + MapFunctionList *map_function_list; + CompilerFunctionList *compiler_function_list; + bool is_data_reference; + std::map call_import_function_map; + + asm_signatures.Add("EB10564D50726F7465637420626567696E0?"); // "VMProtect begin" + asm_signatures.Add("EB0E564D50726F7465637420656E6400"); // "VMProtect end" + + import_signatures.Add("FF15"); // call dword ptr [xxxx] + import_signatures.Add("FF25"); // jmp dword ptr [xxxx] + import_signatures.Add("FF2425");// jmp dword ptr [xxxx] + import_signatures.Add("E8"); // call xxxx + import_signatures.Add("A1"); // mov eax, [xxxx] + import_signatures.Add((file.cpu_address_size() == osQWord) ? "4?8B" : "8B"); // mov reg, [xxxx] + import_signatures.Add((file.cpu_address_size() == osQWord) ? "4?8D" : "8D"); // lea reg, [xxxx] + uint64_t plt_got_address = 0; + + if (file.cpu_address_size() == osDWord) { + // patch TlsAlloc in Delphi6 + compiler_function_signatures.Add("5352BA????????89C38B5203B8????????8B12B905000000", cfPatchImport); + + // base registr + compiler_function_signatures.Add("E8000000005?", cfBaseRegistr); + + // get base registr + compiler_function_signatures.Add("8B1C24C3", cfGetBaseRegistr); + compiler_function_signatures.Add("8B3424C3", cfGetBaseRegistr); + compiler_function_signatures.Add("8B0424C3", cfGetBaseRegistr); + compiler_function_signatures.Add("8B0C24C3", cfGetBaseRegistr); + compiler_function_signatures.Add("8B1424C3", cfGetBaseRegistr); + + // DllFunctionCall in VB6 + compiler_function_signatures.Add("A1????????0BC07402FFE068????????B8????????FFD0FFE0", cfDllFunctionCall); + + // CxxSEH + compiler_function_signatures.Add("6AFF68????????64A100000000", cfCxxSEH); + compiler_function_signatures.Add("6AFF68????????68????????64A100000000", cfCxxSEH3); + compiler_function_signatures.Add("6AFE68????????68????????64A100000000", cfCxxSEH4); + compiler_function_signatures.Add("68????????64FF3500000000", cfSEH4Prolog); + + // VB6SEH + compiler_function_signatures.Add("83EC??68????????64A1000000005064892500000000", cfVB6SEH); + compiler_function_signatures.Add("81EC??????68????????64A1000000005064892500000000", cfVB6SEH); + + // __InitExceptBlockLDTC in BCB + compiler_function_signatures.Add("538BDD03580?8943088D44240889430CC74304????????66C74310000066C743120000C7431C000000006467A1000089036467891E00005BC3", cfInitBCBSEH); + + // _pei386_runtime_relocator in MinGW + compiler_function_signatures.Add("C705????????01000000B8????????2D????????83F8077EDDBB????????83F80B7E618B3D????????85FF750B8B35????????85F6743D", cfRelocatorMinGW); + compiler_function_signatures.Add("C705????????01000000E8????????8D04408D04851E00000083E0F0E8????????C705????????0000000029C48D44241F83E0F0A3????????B8????????2D????????83F8070F8E??00000083F80B0F8E??010000A1????????85C00F85??000000A1????????85C00F85??000000", cfRelocatorMinGW); + compiler_function_signatures.Add("C705????????01000000E8????????8D04408D04851E000000C1E804C1E004E8????????C705????????0000000029C48D44241F83E0F0A3????????B8????????2D????????83F807", cfRelocatorMinGW); + + if (file.owner()->format_name() == "ELF") { + import_signatures.Add("E9"); // jmp xxxx + if (ELFDirectory *plt_got = reinterpret_cast(file).command_list()->GetCommandByType(DT_PLTGOT)) { + plt_got_address = plt_got->value(); + import_signatures.Add("FFA3"); // jmp dword ptr [ebx + xxxx] + } + } + } + else { + compiler_function_signatures.Add("554889E55DE9????????", cfJmpFunction); + } + + segment_list = file.segment_list(); + fixup_list = file.fixup_list(); + import_list = file.import_list(); + map_function_list = file.map_function_list(); + compiler_function_list = file.compiler_function_list(); + + for (i = 0; i < import_list->count(); i++) { + IImport *import = import_list->item(i); + for (j = 0; j < import->count(); j++) { + import_function = import->item(j); + if (import_function->options() & ioIsRelative) { + import_function->map_function()->reference_list()->Add(import_function->address(), import_function->address() + 1); + jmp_references[import_function->address()] = import_function; + } + } + } + + j = 0; + for (i = 0; i < segment_list->count(); i++) { + segment = segment_list->item(i); + if (!segment->need_parse()) + continue; + + j += static_cast(segment->physical_size()); + if (compiler_function_signatures.count() && (segment->memory_type() & mtExecutable)) + j += static_cast(segment->physical_size()); + } + std::string arch_name = (file.owner()->visible_count() > 1) ? string_format(" (%s)", file.name().c_str()) : ""; + file.StartProgress(string_format("%s %s%s...", language[lsLoading].c_str(), os::ExtractFileName(file.owner()->file_name().c_str()).c_str(), arch_name.c_str()), j); + + if (compiler_function_signatures.count()) { + // search compiler functions + for (i = 0; i < segment_list->count(); i++) { + segment = segment_list->item(i); + if (!segment->need_parse() || (segment->memory_type() & mtExecutable) == 0) + continue; + + compiler_function_signatures.InitSearch(); + read_size = 0; + while (read_size < segment->physical_size()) { + file.Seek(segment->physical_offset() + read_size); + n = file.Read(buf, std::min(static_cast(segment->physical_size() - read_size), sizeof(buf))); + file.StepProgress(n); + for (k = 0; k < n; k++) { + b = buf[k]; + buf_address = segment->address() + read_size + k + 1; + + for (j = 0; j < compiler_function_signatures.count(); j++) { + sign = compiler_function_signatures.item(j); + if (sign->SearchByte(b)) { + address = buf_address - sign->size(); + CompilerFunctionType func_type = static_cast(sign->tag()); + switch (func_type) { + case cfBaseRegistr: + { + IntelOperand base_operand = IntelOperand(otRegistr, command_list.cpu_address_size(), b & 7); + uint64_t value = 0; + command = command_list.ReadValidCommand(file, address + sign->size()); + if (command) { + if (command->type() == cmMov && command->operand(1).type == otRegistr && command->operand(1).registr == base_operand.registr && (command->operand(0).type & otMemory)) + base_operand = command->operand(0); // mov [xxxx], reg + else { + if (command->type() == cmAdd && command->operand(0).type == otRegistr && command->operand(0).registr == base_operand.registr && command->operand(1).type == otValue) + value = command->operand(1).value; // add reg, xxxx + + IntelCommandInfoList command_info_list(file.cpu_address_size()); + std::set address_list; + address_list.insert(command->next_address()); + while (!address_list.empty()) { + tmp_address = *address_list.begin(); + for (;;) { + std::set::const_iterator it = address_list.find(tmp_address); + if (it != address_list.end()) + address_list.erase(it); + + command = command_list.ReadValidCommand(file, tmp_address); + if (!command || (command->options() & roBreaked) || command->is_data()) + break; + + if ((command->type() == cmJmp && command->operand(0).type == otValue) || command->type() == cmJmpWithFlag) { + if (command->operand(0).value > tmp_address) + address_list.insert(command->operand(0).value); + } + + if (command->type() == cmJmp || command->type() == cmRet || command->type() == cmIret || command->type() == cmCall) + break; + + if (!command->GetCommandInfo(command_info_list) || command_info_list.GetInfo(atWrite, otRegistr, base_operand.registr)) + break; + + if (command->type() == cmMov && command->operand(1).type == otRegistr && command->operand(1).registr == base_operand.registr && (command->operand(0).type & otMemory)) { + base_operand = command->operand(0); // mov [xxxx], reg + address_list.clear(); + break; + } + + tmp_address = command->next_address(); + } + } + } + } + address += 5; + CompilerFunction *compiler_function = compiler_function_list->Add(func_type, address); + compiler_function->add_value(base_operand.encode()); + if (value) + compiler_function->add_value(value); + } + break; + + case cfDllFunctionCall: + command_list.ReadFromFile(file, address); + if (command_list.count() == 8) { + if (file.AddressSeek(command_list.item(4)->operand(0).value)) { + std::string dll_name; + std::string func_name; + uint32_t dll_name_address = file.ReadDWord(); + uint32_t func_name_address = file.ReadDWord(); + if (file.AddressSeek(dll_name_address)) + dll_name = file.ReadString(); + if (file.AddressSeek(func_name_address)) + func_name = file.ReadString(); + std::transform(dll_name.begin(), dll_name.end(), dll_name.begin(), tolower); + if (dll_name.find('.') == NOT_ID) + dll_name += ".dll"; + if (dll_name == "vmprotectsdk32.dll") { + const ImportInfo *import_info = file.import_list()->GetSDKInfo(func_name); + if (import_info) { + CompilerFunction *compiler_function = compiler_function_list->Add(func_type, address); + compiler_function->add_value(import_info->encode()); + compiler_function->add_value(dll_name_address); + compiler_function->add_value(dll_name.size() + 1); + compiler_function->add_value(func_name_address); + compiler_function->add_value(func_name.size() + 1); + } + } + } + } + break; + + case cfCxxSEH: + case cfCxxSEH3: + case cfCxxSEH4: + command = command_list.ReadValidCommand(file, address + 2); + if (command) { + CompilerFunction *compiler_function = compiler_function_list->Add(func_type, address); + compiler_function->add_value(command->operand(0).value); + } + break; + + case cfVB6SEH: + { + command = command_list.ReadValidCommand(file, address); + uint64_t offset = 4 - command->operand(1).value; + for (;;) { + command = command_list.ReadValidCommand(file, address); + if (!command || command->is_end()) + break; + + if (command->operand(0).type == (otMemory | otRegistr | otValue) + && command->operand(0).registr == regEBP + && command->operand(0).size == osDWord + && command->operand(0).value == offset + && command->operand(1).type == otValue) { // mov [ebp + xxxx], xxxx + CompilerFunction *compiler_function = compiler_function_list->Add(cfVB6SEH, command->address()); + compiler_function->add_value(command->operand(1).value); + break; + } + address = command->next_address(); + } + } + break; + + case cfInitBCBSEH: + { + CompilerFunction *compiler_function = compiler_function_list->Add(cfInitBCBSEH, address); + if (file.AddressSeek(address + 5)) { + b = file.ReadByte(); + if (b == 8) + compiler_function->add_value(2); + else if (b == 4) + compiler_function->add_value(1); + } + } + break; + + case cfRelocatorMinGW: + { + command_list.clear(); + size_t d; + switch (sign->size()) { + case 73: + d = 11; + break; + case 111: + d = 10; + break; + default: + d = 0; + break; + } + + while (command_list.count() < 13 + d) { + command = command_list.ReadValidCommand(file, address); + if (!command) + break; + + address = command->next_address(); + } + + if (command_list.count() == 13 + d) { + CompilerFunction *compiler_function = compiler_function_list->Add(cfRelocatorMinGW, address); + compiler_function->add_value(command_list.item(0)->operand(0).value); + compiler_function->add_value(command_list.item(d + 2)->operand(1).value); + compiler_function->add_value(command_list.item(d + 1)->operand(1).value); + } + } + break; + + case cfPatchImport: + command = command_list.ReadValidCommand(file, address + 2); + if (command && file.AddressSeek(command->operand(1).value + 3)) { + import_function = import_list->GetFunctionByAddress(file.ReadDWord()); + if (import_function) + import_function->include_option(ioHasDataReference); + } + break; + + case cfJmpFunction: + command = command_list.ReadValidCommand(file, address + 5); + if (command && file.segment_list()->GetMemoryTypeByAddress(command->operand(0).value) & mtExecutable) { + CompilerFunction *compiler_function = compiler_function_list->Add(cfJmpFunction, address); + compiler_function->add_value(command->operand(0).value); + } + break; + + case cfGetBaseRegistr: + command = command_list.ReadValidCommand(file, address); + if (command) { + CompilerFunction *compiler_function = compiler_function_list->Add(cfGetBaseRegistr, address); + compiler_function->add_value(command->operand(0).registr); + } + break; + + default: + compiler_function_list->Add(func_type, address); + break; + } + } + } + } + read_size += n; + } + } + } + + pointer_size = OperandSizeToValue(file.cpu_address_size()); + for (i = 0; i < segment_list->count(); i++) { + segment = segment_list->item(i); + if (!segment->need_parse()) + continue; + + asm_signatures.InitSearch(); + import_signatures.InitSearch(); + read_size = 0; + pointer_value = 0; + last_operand_address = 0; + while (read_size < segment->physical_size()) { + file.Seek(segment->physical_offset() + read_size); + n = file.Read(buf, std::min(static_cast(segment->physical_size() - read_size), sizeof(buf))); + file.StepProgress(n); + for (k = 0; k < n; k++) { + b = buf[k]; + buf_address = segment->address() + read_size + k + 1; + + if (segment->memory_type() & mtExecutable) { + // search asm markers + for (j = 0; j < asm_signatures.count(); j++) { + sign = asm_signatures.item(j); + if (sign->SearchByte(b)) { + address = buf_address - sign->size(); + switch (j) { + case 0: + AddMarker(file, address, 0, 0, otMarker, b, false); + break; + case 1: + AddEndMarker(file, address, address + sign->size(), otMarker); + break; + } + } + } + + // search references to import + for (j = 0; j < import_signatures.count(); j++) { + sign = import_signatures.item(j); + if (sign->SearchByte(b)) { + address = buf_address - sign->size(); + command_list.clear(); + command = command_list.ReadValidCommand(file, address); + if (!command) + continue; + + IntelCommandType ref_command = static_cast(command->type()); + operand = command->operand((ref_command == cmJmp || ref_command == cmCall) ? 0 : 1); + if ((operand.type & otValue) == 0) + continue; + + operand_address = address + operand.value_pos; + uint64_t next_address = command->next_address(); + + import_function = NULL; + if (j == 3 && !operand.relocation) { + // check compiler function + CompilerFunction *compiler_function = compiler_function_list->GetFunctionByAddress(operand.value); + if (compiler_function) { + switch (compiler_function->type()) { + case cfGetBaseRegistr: + registr = static_cast(compiler_function->value(0)); + compiler_function = compiler_function_list->Add(cfBaseRegistr, next_address); + compiler_function->add_value(IntelOperand(otRegistr, command_list.cpu_address_size(), registr).encode()); + tmp_address = command->next_address(); + for (;;) { + tmp_command = command_list.ReadValidCommand(file, tmp_address); + if (tmp_command && tmp_command->type() == cmAdd && tmp_command->operand(0).type == otRegistr) { + if (tmp_command->operand(0).registr == registr) { + compiler_function->add_value(tmp_command->operand(1).value); + break; + } + tmp_address = tmp_command->next_address(); + } else { + break; + } + } + break; + + case cfDllFunctionCall: + compiler_function->include_option(coUsed); + ImportInfo sdk_info; + sdk_info.decode(compiler_function->value(0)); + switch (sdk_info.type) { + case atBegin: + { + b = 0; + if (sdk_info.options & ioHasCompilationType) + b = 1 + sdk_info.compilation_type; + if (sdk_info.options & ioLockToKey) + b |= 0x80; + + command_list.ReadMarkerCommands(file, marker_command_list, address, moNeedParam | moSkipLastCall); + if (marker_command_list.count() == 0) { + AddMarker(file, address, 0, 0, otAPIMarker, b, true); + } else { + marker_command_list.Sort(); + for (r = 0; r < marker_command_list.count(); r++) { + marker_command = marker_command_list.item(r); + AddMarker(file, marker_command->address(), + marker_command->name_reference(), + marker_command->name_address(), + otAPIMarker, b, true); + } + } + } + break; + + case atEnd: + AddEndMarker(file, address, next_address, otAPIMarker); + break; + case atDecryptStringW: + command_list.ReadMarkerCommands(file, marker_command_list, address, moNeedParam | moSkipLastCall); + for (r = 0; r < marker_command_list.count(); r++) { + marker_command = marker_command_list.item(r); + AddString(file, marker_command->name_address(), marker_command->name_reference(), true); + } + break; + } + break; + + case cfInitBCBSEH: + { + uint8_t version = static_cast(compiler_function->value(0)); + if (version) { + for (size_t d = 0x30; d > 0; d--) { + if (!file.AddressSeek(address - d)) + continue; + + command_list.clear(); + tmp_address = address - d; + while (tmp_address < address) { + command = command_list.ReadValidCommand(file, tmp_address); + // these commands can no be found between API`s param and API`s call + if (command == NULL + || command->type() == cmDB + || command->type() == cmRet + || command->type() == cmIret + || command->type() == cmJmp + || command->type() == cmEnter) { + tmp_address = 0; + break; + } + tmp_address = command->next_address(); + if (command->type() == cmCall) + command_list.clear(); + } + + if (tmp_address != address) + continue; + + for (size_t c = command_list.count(); c > 0; c--) { + command = command_list.item(i); + if (command->type() == cmMov && command->operand(0).type == otRegistr && command->operand(0).registr == regEAX) { + if (command->operand(1).type == otValue) { + compiler_function = compiler_function_list->Add(cfBCBSEH, address); + compiler_function->add_value(command->operand(1).value); + compiler_function->add_value(version); + } + d = 1; + } + } + } + } + } + break; + + case cfJmpFunction: + operand.value = compiler_function->value(0); + break; + } + } + + // try to search import_function by jmp references + std::map::const_iterator it = jmp_references.find(operand.value); + if (it != jmp_references.end()) + import_function = it->second; + + if (!import_function) { + tmp_address = operand.value; + for (;;) { + // try parse jmp branches + tmp_command = command_list.ReadValidCommand(file, tmp_address); + if (tmp_command) { + if (tmp_command->type() == cmJmp && (tmp_command->options() & roFar) == 0) { + // jmp xxxx + tmp_operand = tmp_command->operand(0); + if (tmp_operand.type == otValue) { + if (command_list.GetCommandByNearAddress(tmp_operand.value) == NULL) { + tmp_address = tmp_operand.value; + continue; + } + } + else if (tmp_operand.type == (otMemory | otValue)) { + import_function = import_list->GetFunctionByAddress(tmp_operand.value); + } + } + else if (tmp_command->type() == cmNop) { + // rep nop xxxx + tmp_address = tmp_command->next_address(); + continue; + } + } + break; + } + } + } else if (j == 8) + import_function = import_list->GetFunctionByAddress(plt_got_address + operand.value); + else + import_function = import_list->GetFunctionByAddress(operand.relocation ? operand_address : operand.value); + + if (import_function) { + if ((ref_command == cmJmp || j == 3) && (import_function->options() & ioNoReturn)) { + tmp_address = (j == 3) ? command->operand(0).value : address; + CompilerFunction *compiler_function = compiler_function_list->GetFunctionByAddress(tmp_address); + if (!compiler_function) + compiler_function = compiler_function_list->Add(cfNone, tmp_address); + compiler_function->include_option(coNoReturn); + } + + // check data reference to import function + if (ref_command == cmMov) { + is_data_reference = true; + registr = command->operand(0).registr; + tmp_address = command->next_address(); + while (segment_list->GetMemoryTypeByAddress(tmp_address) & mtExecutable) { + command = command_list.ReadValidCommand(file, tmp_address); + if (!command) + break; + + tmp_address = command->next_address(); + if (command->operand(0).type == otRegistr && command->operand(0).registr == registr) { + if (command->type() == cmJmp || command->type() == cmCall) + is_data_reference = false; + break; + } else if (command->type() == cmJmp && command->operand(0).type == otValue && command->operand(0).value >= tmp_address) { + tmp_address = command->operand(0).value; + } else if (command->type() == cmDB + || command->type() == cmJmp + || command->type() == cmCall + || command->type() == cmRet + || command->type() == cmIret) + break; + } + if (is_data_reference) + import_function->include_option(ioHasDataReference); + } + + switch (import_function->type()) { + case atBegin: + if (ref_command != cmJmp) { + command_list.ReadMarkerCommands(file, marker_command_list, address, moNeedParam | (ref_command == cmMov ? moForward : 0)); + + b = 0; + if ((import_function->options() & ioHasCompilationType) != 0) + b = 1 + import_function->compilation_type(); + if ((import_function->options() & ioLockToKey) != 0) + b |= 0x80; + + if (marker_command_list.count() == 0) { + AddMarker(file, address, 0, 0, otAPIMarker, b, false); + } else { + marker_command_list.Sort(); + for (r = 0; r < marker_command_list.count(); r++) { + marker_command = marker_command_list.item(r); + AddMarker(file, marker_command->address(), + marker_command->name_reference(), + marker_command->name_address(), + otAPIMarker, b, false); + } + } + } + break; + + case atEnd: + if (ref_command == cmMov) { + command_list.ReadMarkerCommands(file, marker_command_list, address, (ref_command == cmMov ? moForward : 0)); //-V547 + if (marker_command_list.count()) { + marker_command_list.Sort(); + for (r = 0; r < marker_command_list.count(); r++) { + marker_command = marker_command_list.item(r); + AddEndMarker(file, marker_command->address(), + marker_command->operand_address(), + otAPIMarker); + } + } + } else if (ref_command != cmJmp) + AddEndMarker(file, address, next_address, otAPIMarker); + break; + + case atDecryptStringA: case atDecryptStringW: + command_list.ReadMarkerCommands(file, marker_command_list, address, moNeedParam | (ref_command == cmMov ? moForward : 0)); + for (r = 0; r < marker_command_list.count(); r++) { + marker_command = marker_command_list.item(r); + AddString(file, marker_command->name_address(), marker_command->name_reference(), import_function->type() == atDecryptStringW); + call_import_function_map[marker_command->address()] = import_function; + } + break; + } + if (j == 3 || j == 7) { + if (import_function->address() == operand_address) + import_function->map_function()->reference_list()->Add(address, operand_address); + } else { + last_operand_address = operand_address; + import_function->map_function()->reference_list()->Add(address, operand_address); + // add jmp_reference for next searching + if (ref_command == cmJmp) + jmp_references[address] = import_function; + } + } + } + } + } + + // check data reference + pointer_value >>= 8; + pointer_value |= static_cast(b) << ((pointer_size - 1) * 8); + if (buf_address >= segment->address() + pointer_size - 1) { + tmp_address = buf_address - pointer_size; + if ((segment_list->GetMemoryTypeByAddress(pointer_value) & mtReadable) && (fixup_list->count() == 0 || fixup_list->GetFixupByAddress(tmp_address))) { + import_function = import_list->GetFunctionByAddress(pointer_value); + if (import_function && last_operand_address != tmp_address) + import_function->include_option(ioHasDataReference); + } + } + } + read_size += n; + } + } + + // search references to strings + if (string_list_.size() > 0) { + if (file.cpu_address_size() == osQWord) { + string_signatures.Add("4?8D"); // lea reg, [xxxxxxxx] + string_signatures.Add("48B?"); // mov reg, xxxxxxxx + } else { + string_signatures.Add("B?"); // mov reg, xxxxxxxx + string_signatures.Add("C7"); // mov [xxxxxxxx], xxxxxxxx + string_signatures.Add("8D"); // lea reg, [xxxxxxxx] + string_signatures.Add("68"); // push xxxxxxxx + } + + for (i = 0; i < segment_list->count(); i++) { + segment = segment_list->item(i); + if (!segment->need_parse() || (segment->memory_type() & mtExecutable) == 0) + continue; + + string_signatures.InitSearch(); + read_size = 0; + while (read_size < segment->physical_size()) { + file.Seek(segment->physical_offset() + read_size); + n = file.Read(buf, std::min(static_cast(segment->physical_size() - read_size), sizeof(buf))); + for (k = 0; k < n; k++) { + b = buf[k]; + buf_address = segment->address() + read_size + k + 1; + + for (j = 0; j < string_signatures.count(); j++) { + sign = string_signatures.item(j); + if (sign->SearchByte(b)) { + address = buf_address - sign->size(); + command_list.clear(); + command = command_list.ReadValidCommand(file, address); + if (!command) + continue; + + uint64_t delta_offset = (uint64_t)-1; + if (command->operand(0).type == otRegistr) { + tmp_command = command_list.ReadValidCommand(file, command->next_address()); + if (tmp_command && tmp_command->type() == cmLea && tmp_command->operand(1).type == (otMemory | otRegistr | otValue) && tmp_command->operand(1).registr == command->operand(0).registr) + delta_offset = tmp_command->operand(1).value; + } + + operand = command->operand(command->type() != cmPush); + if ((operand.type & otValue) == 0) + continue; + + tmp_command = command_list.ReadValidCommand(file, command->next_address()); + if (tmp_command && tmp_command->type() == cmJmp && tmp_command->operand(0).type == otValue) { + tmp_command = command_list.ReadValidCommand(file, tmp_command->operand(0).value); + if (tmp_command && tmp_command->type() == cmCall) { + std::map::const_iterator it = call_import_function_map.find(tmp_command->address()); + if (it != call_import_function_map.end()) { + import_function = it->second; + if (import_function->type() == atDecryptStringA || import_function->type() == atDecryptStringW) { + uint64_t param_reference; + if (command_list.ParseParam(file, 1, param_reference)) + AddString(file, operand.value, command->address(), import_function->type() == atDecryptStringW); + } + } + } + } + + for (r = 0; r < string_list_.size(); r++) { + map_function = string_list_[r]; + bool is_match = false; + if (map_function->address() <= operand.value && map_function->end_address() > operand.value) + is_match = true; + else for (c = 0; c < map_function->equal_address_list()->count(); c++) { + Reference *reference = map_function->equal_address_list()->item(c); + if (reference->address() <= operand.value && reference->operand_address() > operand.value) { + is_match = true; + break; + } + } + + if (is_match) { + if (map_function->reference_list()->GetReferenceByAddress(address) == NULL && (delta_offset == (uint64_t)-1 || delta_offset < map_function->end_address() - map_function->address())) + map_function->reference_list()->Add(address, operand.value, 1); + break; + } + } + } + } + } + read_size += n; + } + } + + // check references to marker_names + for (i = 0; i < map_function_list->count(); i++) { + map_function = map_function_list->item(i); + if (map_function->type() == otAPIMarker) { + MapFunction *name_function = NULL; + for (j = 0; j < string_list_.size(); j++) { + if (string_list_[j]->address() == map_function->name_address() || string_list_[j]->equal_address_list()->GetReferenceByAddress(map_function->name_address())) { + name_function = string_list_[j]; + break; + } + } + if (name_function && name_function->reference_list()->count() > 1) { + uint64_t end_name_address = map_function->name_address() + map_function->name_length(); + for (j = 0; j < name_function->reference_list()->count(); j++) { + Reference *reference = name_function->reference_list()->item(j); + if (reference->tag() != 1) + continue; + + if (map_function->name_address() <= reference->operand_address() && end_name_address > reference->operand_address()) + end_name_address = reference->operand_address(); + } + if (end_name_address > map_function->name_address()) + map_function->set_name_length(static_cast(end_name_address - map_function->name_address())); + else + map_function->set_name_address(0); + } + } + } + } + + // check import functions without references + for (i = 0; i < import_list->count(); i++) { + IImport *import = import_list->item(i); + for (j = 0; j < import->count(); j++) { + import_function = import->item(j); + if ((import_function->options() & ioHasDataReference) == 0 && import_function->map_function()->reference_list()->count() == 0) + import_function->include_option(ioNoReferences); + } + } + + file.EndProgress(); +}; + +/** + * IntelFunctionList + */ + +IntelFunctionList::IntelFunctionList(IArchitecture *owner) + : BaseFunctionList(owner), import_(NULL), crc_table_(NULL), loader_data_(NULL), runtime_crc_table_(NULL) +{ + crc_cryptor_ = new ValueCryptor(); +} + +IntelFunctionList::IntelFunctionList(IArchitecture *owner, const IntelFunctionList &src) + : BaseFunctionList(owner, src), import_(NULL), crc_table_(NULL), loader_data_(NULL), runtime_crc_table_(NULL) +{ + crc_cryptor_ = new ValueCryptor(); +} + +IntelFunctionList::~IntelFunctionList() +{ + delete crc_cryptor_; +} + +IntelFunctionList *IntelFunctionList::Clone(IArchitecture *owner) const +{ + IntelFunctionList *list = new IntelFunctionList(owner, *this); + return list; +} + +IntelFunction *IntelFunctionList::Add(const std::string &name, CompilationType compilation_type, uint32_t compilation_options, bool need_compile, Folder *folder) +{ + IntelFunction *func = new IntelFunction(this, name, compilation_type, compilation_options, need_compile, folder); + AddObject(func); + return func; +} + +IntelFunction *IntelFunctionList::CreateFunction(OperandSize cpu_address_size) +{ + return new IntelFunction(this, cpu_address_size); +} + +IntelFunction *IntelFunctionList::item(size_t index) const +{ + return reinterpret_cast(BaseFunctionList::item(index)); +} + +IntelFunction *IntelFunctionList::GetFunctionByAddress(uint64_t address) const +{ + return reinterpret_cast(BaseFunctionList::GetFunctionByAddress(address)); +} + +IntelSDK *IntelFunctionList::AddSDK(OperandSize cpu_address_size) +{ + IntelSDK *func = new IntelSDK(this, cpu_address_size); + AddObject(func); + return func; +} + +IntelImport *IntelFunctionList::AddImport(OperandSize cpu_address_size) +{ + IntelImport *func = new IntelImport(this, cpu_address_size); + AddObject(func); + return func; +} + +IntelRuntimeData *IntelFunctionList::AddRuntimeData(OperandSize cpu_address_size) +{ + IntelRuntimeData *func = new IntelRuntimeData(this, cpu_address_size); + AddObject(func); + return func; +} + +IntelCRCTable *IntelFunctionList::AddCRCTable(OperandSize cpu_address_size) +{ + IntelCRCTable *func = new IntelCRCTable(this, cpu_address_size); + AddObject(func); + return func; +} + +IntelLoaderData *IntelFunctionList::AddLoaderData(OperandSize cpu_address_size) +{ + IntelLoaderData *func = new IntelLoaderData(this, cpu_address_size); + AddObject(func); + return func; +} + +IntelFunction *IntelFunctionList::AddWatermark(OperandSize cpu_address_size, Watermark *watermark, int copy_count) +{ + IntelFunction *func = new IntelFunction(this, cpu_address_size); + func->set_compilation_type(ctMutation); + func->set_memory_type(mtNone); + func->AddWatermark(watermark, copy_count); + AddObject(func); + return func; +} + +IntelRuntimeCRCTable *IntelFunctionList::AddRuntimeCRCTable(OperandSize cpu_address_size) +{ + IntelRuntimeCRCTable *func = new IntelRuntimeCRCTable(this, cpu_address_size); + AddObject(func); + return func; +} + +IntelVirtualMachineProcessor *IntelFunctionList::AddProcessor(OperandSize cpu_address_size) +{ + IntelVirtualMachineProcessor *func = new IntelVirtualMachineProcessor(this, cpu_address_size); + AddObject(func); + return func; +} + +void IntelFunctionList::ReadFromBuffer(Buffer &buffer, IArchitecture &file) +{ + BaseFunctionList::ReadFromBuffer(buffer, file); + + // add loader stubs + size_t c = count(); + for (size_t i = 0; i < c; i++) { + IntelFunction *func = item(i); + if (func->tag() != ftLoader) + continue; + + for (size_t j = 0; j < func->count(); j++) { + IntelCommand *command = func->item(j); + if (command->type() == cmCall && command->operand(0).type == otValue) { + uint64_t address = command->operand(0).value; + if (address == command->next_address() || GetFunctionByAddress(address)) + continue; + + IntelFunction *new_func = reinterpret_cast(AddByAddress(address, ctMutation, 0, false, NULL)); + if (new_func) { + new_func->set_tag(ftLoader); + for (size_t k = 0; k < new_func->count(); k++) { + IntelCommand *command = new_func->item(k); + command->exclude_option(roClearOriginalCode); +#ifdef CHECKED + command->update_hash(); +#endif + } + } + } + } + } +} + +bool IntelFunctionList::Prepare(const CompileContext &ctx) +{ + IntelFunction *func; + IntelCommand *command; + size_t i, j; + OperandSize cpu_address_size = ctx.file->cpu_address_size(); + + crc_cryptor_->clear(); + crc_cryptor_->set_size(osDWord); + crc_cryptor_->Add(ccXor, rand32()); + + if ((ctx.options.flags | ctx.options.sdk_flags) & cpMemoryProtection) { + crc_table_ = AddCRCTable(cpu_address_size); + } else { + crc_table_ = NULL; + } + + if (ctx.runtime) { + // remove CalcCRC function + IntelFunctionList *function_list = reinterpret_cast(ctx.runtime->function_list()); + uint64_t calc_crc_address = ctx.runtime->export_list()->GetAddressByType(atCalcCRC); + if (!calc_crc_address) + return false; + func = function_list->GetFunctionByAddress(calc_crc_address); + if (!func) + return false; + func->set_need_compile(false); + for (i = 0; i < function_list->count(); i++) { + func = function_list->item(i); + for (j = 0; j < func->count(); j++) { + command = func->item(j); + if (command->type()== cmCall && command->operand(0).type == otValue && command->operand(0).value == calc_crc_address) { + delete command->link(); + command->Init(cmCrc); +#ifdef CHECKED + command->update_hash(); +#endif + } + } + } + + if (ctx.runtime->segment_list()->count() > 0) { + // add runtime functions + for (i = 0; i < function_list->count(); i++) { + func = function_list->item(i); + + if (func->need_compile()) { + func = func->Clone(this); + AddObject(func); + + if (func->type() == otString) { + for (j = 0; j < func->count(); j++) { + command = func->item(j); + for (size_t k = 0; k < MESSAGE_COUNT; k++) { + os::unicode_string unicode_message = +#ifdef VMP_GNU + os::FromUTF8(default_message[k]); +#else + default_message[k]; +#endif + if (command->CompareDump(reinterpret_cast(unicode_message.c_str()), (unicode_message.size() + 1) * sizeof(os::unicode_char))) { + os::unicode_string str = os::FromUTF8(ctx.options.messages[k]); + command->set_dump(reinterpret_cast(str.c_str()), (str.size() + 1) * sizeof(os::unicode_char)); + } else { + std::string message = +#ifdef VMP_GNU + default_message[k]; +#else + os::ToUTF8(default_message[k]); +#endif + if (command->CompareDump(reinterpret_cast(message.c_str()), message.size() + 1)) { + std::string str = ctx.options.messages[k]; + command->set_dump(reinterpret_cast(str.c_str()), str.size() + 1); + } + } + } + } + } + + for (j = 0; j < func->count(); j++) { + func->item(j)->CompileToNative(); + } + } else { + // need delete import references + for (j = 0; j < ctx.runtime->map_function_list()->count(); j++) { + ReferenceList *reference_list = ctx.runtime->map_function_list()->item(j)->reference_list(); + for (size_t k = reference_list->count(); k > 0; k--) { + Reference *reference = reference_list->item(k - 1); + command = func->GetCommandByNearAddress(reference->address()); + if (command && (command->options() & roClearOriginalCode)) + delete reference; + } + } + if (!func->FreeByManager(ctx)) + return false; + } + } + + AddRuntimeData(cpu_address_size); + } + } + + if (ctx.options.flags & cpImportProtection) { + import_ = AddImport(cpu_address_size); + } else { + import_ = NULL; + } + + AddSDK(cpu_address_size); + + if (ctx.runtime && ctx.runtime->segment_list()->count() == 0) { + loader_data_ = AddLoaderData(cpu_address_size); + } else { + loader_data_ = NULL; + } + + AddWatermark(cpu_address_size, ctx.options.watermark, ctx.runtime ? 8 : 10); + + return BaseFunctionList::Prepare(ctx); +} + +void IntelFunctionList::CompileLinks(const CompileContext &ctx) +{ + if (ctx.options.flags & cpMemoryProtection) { + runtime_crc_table_ = AddRuntimeCRCTable(ctx.file->cpu_address_size()); + runtime_crc_table_->Compile(ctx); + } else { + runtime_crc_table_ = NULL; + } + + BaseFunctionList::CompileLinks(ctx); +} + +bool IntelFunctionList::GetRuntimeOptions() const +{ + for (size_t i = 0; i < count(); i++) { + IntelFunction *func = item(i); + if (func->tag() != ftLoader) + continue; + + for (size_t j = 0; j < func->count(); j++) { + IntelCommand *command = func->item(j); + + if (command->link() && command->link()->to_address()) { + if (!GetCommandByAddress(command->link()->to_address(), false)) + return true; + } else { + for (size_t k = 0; k < 3; k++) { + IntelOperand operand = command->operand(k); + if (operand.type == otNone) + break; + + if ((operand.type & otValue) && (operand.fixup || operand.is_large_value)) { + if (owner()->image_base() == operand.value || owner()->import_list()->GetFunctionByAddress(operand.value)) + continue; + + if (!GetCommandByAddress(operand.value, false)) + return true; + } + } + } + } + } + return false; +} + +/** + * PEIntelFunctionList + */ + +PEIntelFunctionList::PEIntelFunctionList(IArchitecture *owner) + : IntelFunctionList(owner) +{ + +} + +PEIntelFunctionList::PEIntelFunctionList(IArchitecture *owner, const PEIntelFunctionList &src) + : IntelFunctionList(owner, src) +{ + +} + +PEIntelFunctionList *PEIntelFunctionList::Clone(IArchitecture *owner) const +{ + PEIntelFunctionList *list = new PEIntelFunctionList(owner, *this); + return list; +} + +IntelSDK *PEIntelFunctionList::AddSDK(OperandSize cpu_address_size) +{ + IntelSDK *func = new PEIntelSDK(this, cpu_address_size); + AddObject(func); + return func; +} + +PEIntelExport *PEIntelFunctionList::AddExport(OperandSize cpu_address_size) +{ + PEIntelExport *func = new PEIntelExport(this, cpu_address_size); + AddObject(func); + return func; +} + +void PEIntelFunctionList::ReadFromBuffer(Buffer &buffer, IArchitecture &file) +{ + IntelFunctionList::ReadFromBuffer(buffer, file); + + if (file.cpu_address_size() == osDWord && reinterpret_cast(file).image_type() == itDriver) { + // add exception handler + IntelFunction *except_handler = NULL; + for (size_t i = 0; i < count(); i++) { + IntelFunction *func = item(i); + if (func->tag() != ftLoader) + continue; + + for (size_t j = 0; j < func->count(); j++) { + IntelCommand *command = func->item(j); + if (command->base_segment() == segFS && command->operand(0).type == otRegistr && command->operand(1).type == (otMemory | otValue) && command->operand(1).value == 0) { + // mov reg, fs:[00000000] + command = func->item(j - 1); + uint64_t address = command->operand(0).value; + command->AddLink(0, ltOffset, address); + if (!GetFunctionByAddress(address)) { + IntelFunction *new_func = reinterpret_cast(AddByAddress(address, ctMutation, 0, false, NULL)); + if (new_func) { + new_func->set_tag(ftLoader); + for (size_t k = 0; k < new_func->count(); k++) { + IntelCommand *command = new_func->item(k); + command->exclude_option(roClearOriginalCode); + if (command->seh_handler()) + command->set_seh_handler(NEED_SEH_HANDLER); +#ifdef CHECKED + command->update_hash(); +#endif + } + } + } + } + } + } + } +} + +bool PEIntelFunctionList::Prepare(const CompileContext &ctx) +{ + if (ctx.runtime) { + PEArchitecture *file = reinterpret_cast(ctx.file); + if (file->image_type() == itDriver) { + IntelFunctionList *function_list = reinterpret_cast(ctx.runtime->function_list()); + for (size_t i = 0; i < function_list->count(); i++) { + IntelFunction *func = function_list->item(i); + for (size_t j = 0; j < func->count(); j++) { + IntelCommand *command = func->item(j); + for (size_t k = 0; k < 3; k++) { + IntelOperand operand = command->operand(k); + if (operand.type == otNone) + break; + + if ((operand.type & otValue) == 0) + continue; + + uint32_t value = static_cast(operand.value); + if ((value & 0xFFFF0000) == 0xFACE0000) { + switch (value) { + case FACE_NON_PAGED_POOL_NX: + // NonPagedPoolNx + command->set_operand_value(k, file->operating_system_version() >= 0x060002 ? 512 : 0); + command->CompileToNative(); + break; + case FACE_DEFAULT_MDL_PRIORITY: + // MdlMappingNoExecute | HighPagePriority + command->set_operand_value(k, file->operating_system_version() >= 0x060002 ? 0x40000020 : 0x20); + command->CompileToNative(); + break; + } + } + } + } + } + } + + if (file->entry_point()) { + IntelFunction *entry_point_func = GetFunctionByAddress(file->entry_point()); + if (entry_point_func) { + entry_point_func->set_entry_type(etNone); + entry_point_func->entry()->include_section_option(rtLinkedToInt); + } + } + } + + return IntelFunctionList::Prepare(ctx); +} + +/** + * IntelSDK + */ + +IntelSDK::IntelSDK(IFunctionList *owner, OperandSize cpu_address_size) + : IntelFunction(owner, cpu_address_size) +{ + set_compilation_type(ctMutation); +} + +bool IntelSDK::Init(const CompileContext &ctx) +{ + MapFunctionList *map_function_list; + MapFunction *map_function; + IFunctionList *function_list; + size_t i, c, j, k, /*old_count,*/ n, f; + uint64_t address; + IArchitecture *file; + IImportList *import_list; + IImport *import; + IImportFunction *import_function; + IntelCommand *command, *ret_command, *mem_command, *api_entry; + CommandBlock *block; + uint64_t api_address; + std::map map_api_entry; + + CallingConvention calling_convention = ctx.file->calling_convention(); + + f = (ctx.runtime && ctx.runtime->segment_list()->count() > 0) ? 2 : 1; + for (n = 0; n < f; n++) { + file = (n == 0) ? ctx.file : ctx.runtime; + map_function_list = file->map_function_list(); + function_list = file->function_list(); + for (i = 0; i < map_function_list->count(); i++) { + map_function = map_function_list->item(i); + switch (map_function->type()) { + case otAPIMarker: + // need clear marker name + if (map_function->name_address()) + ctx.manager->Add(map_function->name_address(), map_function->name_length(), file->segment_list()->GetMemoryTypeByAddress(map_function->name_address())); + break; + case otMarker: + // need clear "VMProtect begin" from asm markers + ICommand *command = function_list->GetCommandByAddress(map_function->address() + 2, true); + if (!command) + ctx.manager->Add(map_function->address() + 2, 0x10, file->segment_list()->GetMemoryTypeByAddress(map_function->name_address())); + break; + } + } + + // need clear "VMProtect end" from asm markers + for (i = 0; i < file->end_marker_list()->count(); i++) { + MarkerCommand *marker_command = file->end_marker_list()->item(i); + if (marker_command->type() != otMarker) + continue; + + ICommand *command = function_list->GetCommandByAddress(marker_command->address() + 2, true); + if (!command) + ctx.manager->Add(marker_command->address() + 2, 0x0e, file->segment_list()->GetMemoryTypeByAddress(map_function->name_address())); + } + + for (i = 0; i < file->compiler_function_list()->count(); i++) { + CompilerFunction *compiler_function = file->compiler_function_list()->item(i); + if (compiler_function->type() == cfDllFunctionCall) { + // clear names + ctx.manager->Add(compiler_function->value(1), static_cast(compiler_function->value(2))); + ctx.manager->Add(compiler_function->value(3), static_cast(compiler_function->value(4))); + + if ((compiler_function->options() & coUsed) == 0) + continue; + + address = compiler_function->address(); + command = reinterpret_cast(ctx.file->function_list()->GetCommandByNearAddress(address, true)); + if (command) { + delete command->link(); + } else { + if (!file->AddressSeek(address)) + return false; + + block = AddBlock(count(), true); + block->set_address(address); + + command = Add(address); + command->ReadFromFile(*file); + command->set_block(block); + command->include_option(roFillNop); + command->exclude_option(roClearOriginalCode); + } + + // need delete fixups + for (k = 0; k < 3; k++) { + IntelOperand operand = command->operand(k); + if (operand.type == otNone) + break; + + IFixup *fixup = operand.fixup; + if (fixup && fixup != NEED_FIXUP) + fixup->set_deleted(true); + } + // need clear operands + command->Init(static_cast(command->type())); + + APIType function_type = static_cast(compiler_function->value(0) & 0xff); + switch (function_type) { + case atBegin: + command->Init(cmRet, IntelOperand(otValue, osWord, 0, OperandSizeToValue(cpu_address_size()))); + break; + case atEnd: + command->Init(cmRet); + break; + default: + if (!ctx.runtime) + return false; + api_address = ctx.runtime->export_list()->GetAddressByType(function_type); + if (!api_address) + return false; + + command->Init(cmJmp, IntelOperand(otValue, cpu_address_size(), 0, api_address)); + command->AddLink(0, ltJmp, api_address); + break; + } + + command->CompileToNative(); + } + } + + import_list = file->import_list(); + for (i = 0; i < import_list->count(); i++) { + import = import_list->item(i); + if (!import->is_sdk()) + continue; + + for (j = 0; j < import->count(); j++) { + import_function = import->item(j); + + map_function = import_function->map_function(); + for (c = 0; c < map_function->reference_list()->count(); c++) { + address = map_function->reference_list()->item(c)->address(); + + command = reinterpret_cast(ctx.file->function_list()->GetCommandByNearAddress(address, true)); + if (command) { + delete command->link(); + } else { + if (!file->AddressSeek(address)) + return false; + + block = AddBlock(count(), true); + block->set_address(address); + + command = Add(address); + command->ReadFromFile(*file); + command->set_block(block); + command->include_option(roFillNop); + command->exclude_option(roClearOriginalCode); + } + + if (command->type() != cmMov) { + // need delete fixups + for (k = 0; k < 3; k++) { + IntelOperand operand = command->operand(k); + if (operand.type == otNone) + break; + + IFixup *fixup = operand.fixup; + if (fixup && fixup != NEED_FIXUP) + fixup->set_deleted(true); + } + // need clear operands + command->Init(static_cast(command->type())); + } + + switch (import_function->type()) { + case atBegin: + switch (command->type()) { + case cmCall: + if (calling_convention == ccStdcall) { + command->Init(cmLea, IntelOperand(otRegistr, cpu_address_size(), regESP), + IntelOperand(otMemory | otRegistr | otValue, cpu_address_size(), regESP, OperandSizeToValue(cpu_address_size()))); + } else { + command->Init(cmNop); + } + break; + case cmMov: + if (calling_convention == ccStdcall) { + ret_command = AddCommand(cmRet, IntelOperand(otValue, osWord, 0, OperandSizeToValue(cpu_address_size()))); + } else { + ret_command = AddCommand(cmRet); + } + + mem_command = AddCommand((cpu_address_size() == osDWord) ? cmDD : cmDQ, IntelOperand(otValue, cpu_address_size(), 0, 0, NEED_FIXUP)); + mem_command->AddLink(0, ltOffset, ret_command); + + command->AddLink(1, ltOffset, mem_command); + break; + default: + if (calling_convention == ccStdcall) { + command->Init(cmRet, IntelOperand(otValue, osWord, 0, OperandSizeToValue(cpu_address_size()))); + } else { + command->Init(cmRet); + } + break; + } + break; + + case atEnd: + switch (command->type()) { + case cmCall: + command->Init(cmNop); + break; + case cmMov: + ret_command = AddCommand(cmRet); + + mem_command = AddCommand((cpu_address_size() == osDWord) ? cmDD : cmDQ, IntelOperand(otValue, cpu_address_size(), 0, 0, NEED_FIXUP)); + mem_command->AddLink(0, ltOffset, ret_command); + + command->AddLink(1, ltOffset, mem_command); + break; + default: + command->Init(cmRet); + break; + } + break; + + case atDecryptStringA: + case atDecryptStringW: + case atFreeString: + case atIsDebuggerPresent: + case atIsVirtualMachinePresent: + case atIsValidImageCRC: + case atActivateLicense: + case atDeactivateLicense: + case atGetOfflineActivationString: + case atGetOfflineDeactivationString: + case atSetSerialNumber: + case atGetSerialNumberState: + case atGetSerialNumberData: + case atGetCurrentHWID: + case atIsProtected: + api_entry = NULL; + api_address = 0; + if (!ctx.runtime || ctx.runtime->segment_list()->count() == 0) { + std::map::const_iterator it = map_api_entry.find(import_function->type()); + if (it != map_api_entry.end()) + api_entry = it->second; + else { + switch (import_function->type()) { + case atDecryptStringA: + case atDecryptStringW: + if (calling_convention == ccMSx64) + api_entry = AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size(), regEAX), IntelOperand(otRegistr, cpu_address_size(), regECX)); + else if (calling_convention == ccABIx64) + api_entry = AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size(), regEAX), IntelOperand(otRegistr, cpu_address_size(), regEDI)); + else + api_entry = AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size(), regEAX), IntelOperand(otMemory | otRegistr | otValue, cpu_address_size(), regESP, OperandSizeToValue(cpu_address_size()))); + if (calling_convention == ccStdcall) + AddCommand(cmRet, IntelOperand(otValue, osWord, 0, OperandSizeToValue(cpu_address_size()))); + else + AddCommand(cmRet); + break; + case atFreeString: + api_entry = AddCommand(cmXor, IntelOperand(otRegistr, osDWord, regEAX), IntelOperand(otRegistr, osDWord, regEAX)); + if (calling_convention == ccStdcall) + AddCommand(cmRet, IntelOperand(otValue, osWord, 0, OperandSizeToValue(cpu_address_size()))); + else + AddCommand(cmRet); + break; + case atIsProtected: + api_entry = AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regEAX), IntelOperand(otValue, osDWord, 0, 1)); + AddCommand(cmRet); + break; + default: + // other APIs can not work without runtime + return false; + } + map_api_entry[import_function->type()] = api_entry; + } + } else { + api_address = ctx.runtime->export_list()->GetAddressByType(import_function->type()); + if (!api_address) + return false; + } + + switch (command->type()) { + case cmCall: + command->Init(cmCall, IntelOperand(otValue, cpu_address_size(), 0, api_address)); + if (api_entry) + command->AddLink(0, ltCall, api_entry); + else + command->AddLink(0, ltCall, api_address); + break; + case cmMov: + mem_command = AddCommand((cpu_address_size() == osDWord) ? cmDD : cmDQ, IntelOperand(otValue, cpu_address_size(), 0, api_address, NEED_FIXUP)); + if (api_entry) + mem_command->AddLink(0, ltOffset, api_entry); + else + mem_command->AddLink(0, ltOffset, api_address); + command->AddLink(1, ltOffset, mem_command); + break; + default: + command->Init(cmJmp, IntelOperand(otValue, cpu_address_size(), 0, api_address)); + if (api_entry) + command->AddLink(0, ltJmp, api_entry); + else + command->AddLink(0, ltJmp, api_address); + break; + } + break; + + default: + throw std::runtime_error("Unknown API from SDK: " + import_function->name()); + } + + command->CompileToNative(); + } + } + } + } + + for (i = 0; i < count(); i++) { + item(i)->CompileToNative(); + } + + return IntelFunction::Init(ctx); +} + +/** + * PEIntelSDK + */ + +PEIntelSDK::PEIntelSDK(IFunctionList *parent, OperandSize cpu_address_size) + : IntelSDK(parent, cpu_address_size) +{ + +} + +bool PEIntelSDK::Init(const CompileContext &ctx) +{ + if (!IntelSDK::Init(ctx)) + return false; + + PEArchitecture *file = reinterpret_cast(ctx.file); + if (file->import_list()->has_sdk() && ctx.runtime == NULL) { + // remove SDK from import + PEDirectory *dir = file->command_list()->GetCommandByType(IMAGE_DIRECTORY_ENTRY_IMPORT); + if (!dir) + return false; + + size_t i, j; + IntelCommand *command; + uint64_t address = dir->address(); + + CommandBlock *block = AddBlock(count(), true); + block->set_address(address); + + for (i = 0; i < file->import_list()->count(); i++) { + PEImport *import = file->import_list()->item(i); + if (import->is_sdk()) { + import->FreeByManager(*ctx.manager, true); + } else { + if (!file->AddressSeek(address)) + return false; + + for (j = 0; j < 5; j++) { + command = Add(0); + command->ReadValueFromFile(*file, osDWord); + command->include_option(roWritable); + } + } + address += 5 * sizeof(uint32_t); + } + for (j = 0; j < 5; j++) { + command = AddCommand(cmDD, IntelOperand(otValue, osDWord)); + command->CompileToNative(); + } + block->set_end_index(count() - 1); + + for (i = block->start_index(); i <= block->end_index(); i++) { + item(i)->set_block(block); + } + } + + return true; +} + +/** + * PEIntelExport + */ + +PEIntelExport::PEIntelExport(IFunctionList *owner, OperandSize cpu_address_size) + : IntelFunction(owner, cpu_address_size), size_(0) +{ + set_compilation_type(ctMutation); +} + +bool PEIntelExport::Init(const CompileContext &ctx) +{ + PEArchitecture *file = reinterpret_cast(ctx.file); + size_ = file->export_list()->WriteToData(*this, file->image_base()); + if (count()) + set_entry(item(0)); + + return IntelFunction::Init(ctx); +} + +bool PEIntelExport::Compile(const CompileContext &ctx) +{ + CreateBlocks(); + block_list()->CompileBlocks(*ctx.manager); + CompileLinks(ctx); + return true; +} + +/** + * IntelImport + */ + +IntelImport::IntelImport(IFunctionList *owner, OperandSize cpu_address_size) + : IntelFunction(owner, cpu_address_size) +{ + set_compilation_type(ctMutation); +} + +IntelCommand *IntelImport::GetIATCommand(PEImportFunction *import_function) const +{ + size_t i; + + for (i = 0; i < iat_info_list_.size(); i++) { + if (iat_info_list_[i].import_function->address() == import_function->address()) { + return iat_info_list_[i].command; + } + } + + return NULL; +} + +bool IntelImport::Init(const CompileContext &ctx) +{ + IntelCommandType value_type, rand_type, ref_type; + size_t i, j, n, k, c, index, r; + PEImportList *import_list; + PEImport *import; + PEImportFunction *import_function; + IATInfo iat_info; + IntelCommand *command, *src_command, *iat_command, *ref_command; + ReferenceList call_references; + MapFunction *map_function; + uint64_t address, rand_value; + PEArchitecture *file; + uint8_t mov_registr, rand_registr; + bool is_mov_command; + CommandLink *link; + + value_type = (cpu_address_size() == osDWord) ? cmDD : cmDQ; + k = (ctx.runtime && ctx.runtime->segment_list()->count() > 0) ? 2 : 1; + for (n = 0; n < k; n++) { + file = reinterpret_cast((n == 0) ? ctx.file : ctx.runtime); + import_list = file->import_list(); + for (i = 0; i < import_list->count(); i++) { + import = import_list->item(i); + + // APIs processed by IntelSDK + if (import->is_sdk()) + continue; + + if (import->excluded_from_import_protection()) + continue; + + for (j = 0; j < import->count(); j++) { + import_function = import->item(j); + + if (import_function->options() & (ioHasDataReference | ioNoReferences)) + continue; + + iat_info.import_function = import_function; + iat_info.command = NULL; + iat_info.from_runtime = (n > 0); + iat_info_list_.push_back(iat_info); + } + } + } + + index = count(); + for (i = 0; i < iat_info_list_.size(); i++) { + import_function = iat_info_list_[i].import_function; + + command = AddCommand(value_type, IntelOperand(otValue, cpu_address_size(), 0, (value_type == cmDD) ? rand32() : rand64())); + // second operand is a key for decrypt IAT value + command->set_operand_value(1, (import_function->options() & ioNative) ? 0 : DWordToInt64(rand32())); + command->include_option(roCreateNewBlock); + command->include_option(roWritable); + + iat_info_list_[i].command = command; + + map_function = import_function->map_function(); + + call_references.clear(); + for (r = 0; r < 2; r++) { + ReferenceList *reference_list = (r == 0) ? map_function->reference_list() : &call_references; + + for (n = 0; n < reference_list->count(); n++) { + address = reference_list->item(n)->address(); + + src_command = reinterpret_cast(ctx.file->function_list()->GetCommandByNearAddress(address, true)); + iat_command = iat_info_list_[i].command; + + file = reinterpret_cast((iat_info_list_[i].from_runtime) ? ctx.runtime : ctx.file); + + if (file == NULL || !file->AddressSeek(address)) + return false; + + ref_command = Add(address); + ref_command->ReadFromFile(*file); + if (ref_command->type() == cmInt) { + // reference command from runtime + if (!src_command) + throw std::runtime_error("Runtime error at Init"); + + delete ref_command; + ref_command = src_command->Clone(this); + AddObject(ref_command); + } + + // delete fixups + for (k = 0; k < 3; k++) { + IntelOperand operand = ref_command->operand(k); + if (operand.type == otNone) + break; + + IFixup *fixup = operand.fixup; + if (fixup && fixup != NEED_FIXUP) + fixup->set_deleted(true); + } + + is_mov_command = (ref_command->type() == cmMov && ref_command->operand(0).type == otRegistr && ref_command->operand(0).size == cpu_address_size()); + ref_type = static_cast(ref_command->type()); + mov_registr = ref_command->operand(0).registr; + rand_registr = rand() % 8; + if (rand_registr == regESP) + rand_registr = regEAX; + + c = ref_command->original_dump_size(); + if (src_command == NULL && c > 5) { + IntelCommand *push_command; + switch (rand() % (is_mov_command ? 3 : 2)) { + case 2: + rand_type = cmPop; + AddCommand(cmXchg, IntelOperand(otMemory | otRegistr, cpu_address_size(), regESP), IntelOperand(otRegistr, cpu_address_size(), mov_registr)); + push_command = AddCommand(cmPush, IntelOperand(otRegistr, cpu_address_size(), mov_registr)); + break; + case 1: + rand_type = cmPush; + push_command = AddCommand(cmPop, IntelOperand(otRegistr, cpu_address_size(), rand_registr)); + AddCommand(cmXchg, IntelOperand(otMemory | otRegistr, cpu_address_size(), regESP), IntelOperand(otRegistr, cpu_address_size(), rand_registr)); + break; + default: + rand_type = cmNop; + push_command = NULL; + break; + } + if (push_command) { + push_command->CompileToNative(); + c -= push_command->dump_size(); + } + } else { + rand_type = cmUnknown; + c = 0; + } + + if (is_mov_command && mov_registr == rand_registr) { + if (c > 5) { + AddCommand(cmPop, IntelOperand(otRegistr, cpu_address_size(), rand_registr)); + AddCommand(cmLea, IntelOperand(otRegistr, cpu_address_size(), rand_registr), + IntelOperand(otMemory | otRegistr | otValue, cpu_address_size(), rand_registr, c - 5)); + AddCommand(cmPush, IntelOperand(otRegistr, cpu_address_size(), rand_registr)); + } + } else { + AddCommand(cmPush, IntelOperand(otRegistr, cpu_address_size(), rand_registr)); + if (c > 5 && ref_type != cmJmp) { + AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size(), rand_registr), + IntelOperand(otMemory | otRegistr | otValue, cpu_address_size(), regESP, OperandSizeToValue(cpu_address_size()))); + AddCommand(cmLea, IntelOperand(otRegistr, cpu_address_size(), rand_registr), + IntelOperand(otMemory | otRegistr | otValue, cpu_address_size(), rand_registr, c - 5)); + AddCommand(cmMov, IntelOperand(otMemory | otRegistr | otValue, cpu_address_size(), regESP, OperandSizeToValue(cpu_address_size())), + IntelOperand(otRegistr, cpu_address_size(), rand_registr)); + } + } + + rand_value = file->segment_list()->item(0)->address() + rand32() % file->segment_list()->item(0)->size(); + if (cpu_address_size() == osDWord) { + AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size(), rand_registr), + IntelOperand(otValue, cpu_address_size(), 0, rand_value, NEED_FIXUP)); + } else { + AddCommand(cmLea, IntelOperand(otRegistr, cpu_address_size(), rand_registr), + IntelOperand(otMemory | otValue, cpu_address_size(), 0, rand_value, LARGE_VALUE)); + } + + // read random registr from IAT + command = AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size(), rand_registr), + IntelOperand(otMemory | otRegistr | otValue, cpu_address_size(), rand_registr, 0x80000000)); + link = command->AddLink(1, ltOffset, iat_command); + link->set_sub_value(rand_value); + + // decrypt API`s address in random registr + AddCommand(cmLea, IntelOperand(otRegistr, cpu_address_size(), rand_registr), + IntelOperand(otMemory | otRegistr | otValue, cpu_address_size(), rand_registr, iat_command->operand(1).value)); + + // restore random registr + if (ref_type == cmJmp || ref_type == cmCall) { + AddCommand(cmXchg, IntelOperand(otMemory | otRegistr, cpu_address_size(), regESP), IntelOperand(otRegistr, cpu_address_size(), rand_registr)); + } else if (is_mov_command && mov_registr != rand_registr){ + IntelOperand ref_operand = ref_command->operand(0); + if ((ref_operand.type & otBaseRegistr) && ref_operand.base_registr == regESP) { + ref_operand.type |= otValue; + ref_operand.value += OperandSizeToValue(cpu_address_size()); + } + + AddCommand(cmMov, ref_operand, IntelOperand(otRegistr, ref_operand.size, rand_registr)); + AddCommand(cmPop, IntelOperand(otRegistr, cpu_address_size(), rand_registr)); + } + + if (ref_type == cmJmp) { + AddCommand(cmRet, IntelOperand(otValue, osWord, 0, OperandSizeToValue(cpu_address_size()))); + } else { + AddCommand(cmRet); + } + + // clear operands + ref_command->Init(cmNop); + ref_command->set_address(0); + ref_command->set_address_range(NULL); + + if (src_command) { + delete src_command->link(); + src_command->Init(cmCall, IntelOperand(otValue, cpu_address_size())); + if (ref_type == cmJmp) + src_command->include_option(roUseAsJmp); + src_command->AddLink(0, ltCall, ref_command); + } else { + c = ref_command->original_dump_size(); + if (rand_type == cmPush || rand_type == cmPop) { + CommandBlock *block = AddBlock(index, true); + block->set_address(address); + + command = new IntelCommand(this, cpu_address_size(), rand_type, IntelOperand(otRegistr, cpu_address_size(), (rand_type == cmPop) ? mov_registr : rand_registr)); + command->CompileToNative(); + command->set_block(block); + InsertObject(index++, command); + + address += command->dump_size(); + c -= command->dump_size(); + } + + ctx.manager->Add(address, c, file->segment_list()->GetMemoryTypeByAddress(address), this); + + ext_command_list()->Add(address, ref_command, true); + } + + if (ref_type == cmJmp) { + address = reference_list->item(n)->address(); + + for (j = 0; j < ctx.file->function_list()->count(); j++) { + IntelFunction *func = reinterpret_cast(ctx.file->function_list()->item(j)); + if (!func->need_compile()) + continue; + + for (k = 0; k < func->link_list()->count(); k++) { + CommandLink *link = func->link_list()->item(k); + if (link->type() != ltCall) + continue; + + command = reinterpret_cast(link->from_command()); + if (command->type() == cmCall && command->operand(0).type == otValue && command->operand(0).value == address) + call_references.Add(command->address(), 0); + } + } + } + } + } + } + + for (i = 0; i < count(); i++) { + item(i)->CompileToNative(); + } + + return IntelFunction::Init(ctx); +} + +/** + * IntelCRCTable + */ + +IntelCRCTable::IntelCRCTable(IFunctionList *owner, OperandSize cpu_address_size) + : IntelFunction(owner, cpu_address_size) +{ + set_compilation_type(ctMutation); +} + +bool IntelCRCTable::Init(const CompileContext &ctx) +{ + size_t i, c, n, f; + + c = 10; + f = (ctx.runtime && ctx.runtime->segment_list()->count() > 0) ? 2 : 1; + for (n = 0; n < f; n++) { + IArchitecture *file = (n == 0) ? ctx.file : ctx.runtime; + c += ctx.file->segment_list()->count(); + if ((ctx.options.flags & cpStripFixups) == 0) + c += file->fixup_list()->count(); + if (ctx.options.flags & cpImportProtection) { + IImportList *import_list = file->import_list(); + for (i = 0; i < import_list->count(); i++) { + c += import_list->item(i)->count(); + } + } else { + c += file->import_list()->count(); + } + } + + for (i = 0; i < c; i++) { + AddCommand(cmDD, IntelOperand(otValue, osDWord)); + AddCommand(cmDD, IntelOperand(otValue, osDWord)); + AddCommand(cmDD, IntelOperand(otValue, osDWord)); + } + + size_entry_ = AddCommand(cmDD, IntelOperand(otValue, osDWord)); + size_entry_->include_option(roCreateNewBlock); + + hash_entry_ = AddCommand(cmDD, IntelOperand(otValue, osDWord)); + hash_entry_->include_option(roCreateNewBlock); + + for (i = 0; i < count(); i++) { + IntelCommand *command = item(i); + command->CompileToNative(); + command->include_option(roWritable); + } + + return IntelFunction::Init(ctx); +} + +/** + * IntelRuntimeCRCTable + */ + +IntelRuntimeCRCTable::IntelRuntimeCRCTable(IFunctionList *owner, OperandSize cpu_address_size) + : IntelFunction(owner, cpu_address_size), cryptor_(NULL) +{ + set_compilation_type(ctMutation); +} + +void IntelRuntimeCRCTable::clear() +{ + region_info_list_.clear(); + IntelFunction::clear(); +} + +bool IntelRuntimeCRCTable::Compile(const CompileContext &ctx) +{ + IntelFunctionList *function_list = reinterpret_cast(ctx.file->function_list()); + cryptor_ = function_list->crc_cryptor(); + + size_t block_size, i, j, k, end_operand_index; + uint64_t block_address; + bool check_fixups = (ctx.options.flags & cpStripFixups) == 0; + MemoryManager manager(ctx.file); + + for (i = 0; i < function_list->count(); i++) { + IntelFunction *func = function_list->item(i); + if (!func->need_compile()) + continue; + + for (j = 0; j < func->block_list()->count(); j++) { + CommandBlock *block = func->block_list()->item(j); + if (block->type() & mtExecutable) { + // native block + block_size = 0; + block_address = 0; + for (k = block->start_index(); k <= block->end_index(); k++) { + IntelCommand *command = func->item(k); + if (command->options() & roWritable) + continue; + + if (block_address && (block_address + block_size) != command->address()) { + if (block_size) + manager.Add(block_address, block_size, mtReadable); + block_address = 0; + block_size = 0; + } + if (!block_address) + block_address = command->address(); + + end_operand_index = NOT_ID; + for (size_t n = 0; n < 3; n++) { + IntelOperand operand = command->operand(n); + if (operand.type == otNone) + break; + + if ((operand.type & otValue) && ((check_fixups && operand.fixup) || operand.relocation)) { + end_operand_index = n; + break; + } + } + block_size += (end_operand_index == NOT_ID) ? command->dump_size() : command->operand(end_operand_index).value_pos; + } + if (block_size) + manager.Add(block_address, block_size, mtReadable); + } else { + // VM block + IntelCommand *command = func->item(block->end_index()); + block_size = 0; + if (command->section_options() & rtBackwardDirection) { + block_address = command->vm_address() - command->vm_dump_size(); + for (k = command->count(); k > 0; k--) { + IntelVMCommand *vm_command = command->item(k - 1); + if (check_fixups && vm_command->fixup()) + break; + block_size += vm_command->dump_size(); + } + } else { + block_address = command->vm_address(); + for (k = 0; k < command->count(); k++) { + IntelVMCommand *vm_command = command->item(k); + if (check_fixups && vm_command->fixup()) + break; + block_size += vm_command->dump_size(); + } + } + if (block_size) + manager.Add(block_address, block_size, mtReadable); + } + } + } + if (manager.count() == 0) + return true; + + manager.Pack(); + + for (i = 0; i < manager.count(); i++) { + MemoryRegion *region = manager.item(i); + uint64_t block_address = region->address(); + + size_t region_size, block_size; + for (region_size = region->size(); region_size != 0; region_size -= block_size, block_address += block_size) { + block_size = 0x1000 - (rand() & 0xff); + if (block_size > region_size) + block_size = region_size; + + region_info_list_.push_back(RegionInfo(block_address, static_cast(block_size), false)); + } + } + + for (i = 0; i < region_info_list_.size(); i++) { + std::swap(region_info_list_[i], region_info_list_[rand() % region_info_list_.size()]); + } + + size_t self_crc_offset = 0; + size_t self_crc_size = 0; + for (i = 0; i < region_info_list_.size(); i++) { + self_crc_size += sizeof(CRCInfo::POD); + if (self_crc_size > 0x1000 && (rand() & 1)) { + region_info_list_.insert(region_info_list_.begin() + i + 1, RegionInfo(self_crc_offset, (uint32_t)self_crc_size, true)); + self_crc_offset += self_crc_size; + self_crc_size = 0; + } + } + if (self_crc_size) + region_info_list_.push_back(RegionInfo(self_crc_offset, (uint32_t)self_crc_size, true)); + + for (i = 0; i < region_info_list_.size(); i++) { + AddCommand(cmDD, IntelOperand(otValue, osDWord)); + AddCommand(cmDD, IntelOperand(otValue, osDWord)); + AddCommand(cmDD, IntelOperand(otValue, osDWord)); + } + set_entry(item(0)); + for (i = 0; i < count(); i++) { + item(i)->CompileToNative(); + } + + CreateBlocks(); + + for (i = 0; i < block_list()->count(); i++) { + block_list()->item(i)->Compile(*ctx.manager); + } + + return true; +} + +size_t IntelRuntimeCRCTable::WriteToFile(IArchitecture &file) +{ + size_t res = IntelFunction::WriteToFile(file); + + if (entry()) { + uint64_t address = entry()->address(); + std::vector crc_info_list; + std::vector dump; + for (size_t i = 0; i < region_info_list_.size(); i++) { + RegionInfo region_info = region_info_list_[i]; + + dump.resize(region_info.size); + if (region_info.is_self_crc) { + memcpy(&dump[0], reinterpret_cast(&crc_info_list[0]) + region_info.address, dump.size()); + region_info.address += address; + } else { + file.AddressSeek(region_info.address); + file.Read(&dump[0], dump.size()); + } + + CRCInfo crc_info(static_cast(region_info.address - file.image_base()), dump); + if (cryptor_) { + crc_info.pod.address = static_cast(cryptor_->Encrypt(crc_info.pod.address)); + crc_info.pod.size = static_cast(cryptor_->Encrypt(crc_info.pod.size)); + } + crc_info.pod.hash = 0 - crc_info.pod.hash; + crc_info_list.push_back(crc_info); + } + + file.AddressSeek(address); + file.Write(&crc_info_list[0], crc_info_list.size() * sizeof(CRCInfo::POD)); + } + + return res; +} + +/** + * IntelLoaderData + */ + +IntelLoaderData::IntelLoaderData(IFunctionList *owner, OperandSize cpu_address_size) + : IntelFunction(owner, cpu_address_size) +{ + set_compilation_type(ctMutation); +} + +bool IntelLoaderData::Init(const CompileContext &ctx) +{ + IntelCommand *command = AddCommand(cpu_address_size(), 0); + if (!command) + return false; + + command->CompileToNative(); + command->include_option(roWritable); + set_entry(command); + set_entry_type(etNone); + + return IntelFunction::Init(ctx); +} + +/** + * IntelRuntimeData + */ + +IntelRuntimeData::IntelRuntimeData(IFunctionList *owner, OperandSize cpu_address_size) + : IntelFunction(owner, cpu_address_size), strings_entry_(NULL), strings_size_(0), resources_entry_(NULL), resources_size_(0), + trial_hwid_entry_(NULL), trial_hwid_size_(0), data_key_(0) +#ifdef ULTIMATE + , license_data_entry_(NULL), license_data_size_(0), files_entry_(NULL), files_size_(0), + registry_entry_(NULL), registry_size_(0) +#endif +{ + set_compilation_type(ctMutation); + rc5_key_.Create(); +} + +bool IntelRuntimeData::CommandCompareHelper::operator()(const IntelCommand *left, IntelCommand *right) const +{ + return (left->address() < right->address()); +} + +bool IntelRuntimeData::Init(const CompileContext &ctx) +{ + IntelFunctionList *function_list; + size_t i, j, index, k; + std::vector string_command_list; + IntelCommand *command, *string_command; + CommandLink *link; + IntelCommand *key_entry; + Data key; + uint64_t image_base = ctx.file->image_base(); + + key.PushBuff(rc5_key_.Value, sizeof(rc5_key_.Value)); + data_key_ = key.ReadDWord(0); + + resources_entry_ = NULL; + resources_size_ = 0; + if ((ctx.options.flags & cpResourceProtection) && ctx.file->resource_list() && ctx.file->resource_list()->count()) { + PEArchitecture *file = reinterpret_cast(ctx.file); + PEResourceList resource_list(NULL); + for (i = 0; i < file->resource_list()->count(); i++) { + PEResource *resource = file->resource_list()->item(i); + if (resource->need_store()) + continue; + + resource_list.AddObject(resource->Clone(&resource_list)); + } + + if (resource_list.count()) { + index = count(); + + std::vector list; + PEResource *resource; + + // create resource list + for (i = 0; i < resource_list.count(); i++) { + list.push_back(resource_list.item(i)); + } + + for (i = 0; i < list.size(); i++) { + resource = list[i]; + for (j = 0; j < resource->count(); j++) { + list.push_back(resource->item(j)); + } + } + + // create root directory + uint32_t number_of_id_entries = 0; + uint32_t number_of_named_entries = 0; + for (i = 0; i < resource_list.count(); i++) { + if (resource_list.item(i)->has_name()) { + number_of_named_entries++; + } else { + number_of_id_entries++; + } + } + AddCommand(osDWord, number_of_named_entries); + AddCommand(osDWord, number_of_id_entries); + + for (i = 0; i < resource_list.count(); i++) { + resource_list.item(i)->WriteEntry(*this); + } + + for (i = 0; i < list.size(); i++) { + list[i]->WriteHeader(*this); + } + + resources_entry_ = item(index); + resources_entry_->include_option(roCreateNewBlock); + resources_size_ = static_cast((count() - index) * OperandSizeToValue(osDWord)); + + for (i = 0; i < list.size(); i++) { + list[i]->WriteName(*this, index, data_key_); + } + + for (i = 0; i < list.size(); i++) { + list[i]->WriteData(*this, *file, data_key_); + } + } + } + +#ifdef ULTIMATE + files_entry_ = NULL; + files_size_ = 0; + if (ctx.options.file_manager) { + FileManager *file_manager = ctx.options.file_manager; + if (!file_manager->OpenFiles()) + return false; + + std::vector folder_list; + for (i = 0; i < file_manager->folder_list()->count(); i++) { + folder_list.push_back(file_manager->folder_list()->item(i)); + } + for (i = 0; i < folder_list.size(); i++) { + FileFolder *file_folder = folder_list[i]; + for (j = 0; j < file_folder->count(); j++) { + folder_list.push_back(file_folder->item(j)); + } + } + + // create root directory + index = count(); + AddCommand(osDWord, file_manager->count() + folder_list.size()); + + for (i = 0; i < file_manager->count(); i++) { + file_manager->item(i)->WriteEntry(*this); + } + for (i = 0; i < folder_list.size(); i++) { + folder_list[i]->WriteEntry(*this); + } + + files_entry_ = item(index); + files_entry_->include_option(roCreateNewBlock); + files_size_ = static_cast((count() - index) * OperandSizeToValue(osDWord)); + + for (i = 0; i < file_manager->count(); i++) { + file_manager->item(i)->WriteName(*this, image_base, data_key_); + } + for (i = 0; i < folder_list.size(); i++) { + folder_list[i]->WriteName(*this, image_base, data_key_); + } + + for (i = 0; i < file_manager->count(); i++) { + InternalFile *internal_file = file_manager->item(i); + Notify(mtInformation, NULL, string_format("%s %s", language[lsLoading].c_str(), os::ExtractFileName(internal_file->absolute_file_name().c_str()).c_str())); + internal_file->WriteData(*this, image_base, data_key_); + } + + file_manager->CloseFiles(); + } + + registry_entry_ = NULL; + registry_size_ = 0; + if (ctx.options.file_manager && ctx.options.file_manager->server_count()) { + index = count(); + + // create root directory + AddCommand(osDWord, 0); + AddCommand(osDWord, 0); + + registry_entry_ = item(index); + registry_entry_->include_option(roCreateNewBlock); + for (i = index; i < count(); i++) { + command = item(i); + registry_size_ += (command->type() == cmDB) ? (uint32_t)command->dump_size() : OperandSizeToValue(command->operand(0).size); + } + + i = AlignValue(registry_size_, 8); + if (i > registry_size_) { + Data tmp; + tmp.resize(i - registry_size_, 0); + AddCommand(tmp); + registry_size_ = (uint32_t)i; + } + } +#endif + + function_list = reinterpret_cast(ctx.file->function_list()); + for (i = 0; i < function_list->count(); i++) { + IntelFunction *func = function_list->item(i); + if (func->need_compile() && func->type() == otString) { + for (j = 0; j < func->count(); j++) { + string_command_list.push_back(func->item(j)); + } + } + } + + key_entry = AddCommand(key); + key_entry->include_option(roCreateNewBlock); + + strings_entry_ = NULL; + strings_size_ = 0; + if (string_command_list.size()) { + std::sort(string_command_list.begin(), string_command_list.end(), CommandCompareHelper()); + index = count(); + + // create directory + AddCommand(osDWord, string_command_list.size()); + + for (i = 0; i < string_command_list.size(); i++) { + string_command = string_command_list[i]; + + // create string entry + AddCommand(osDWord, string_command->address() - ctx.file->image_base()); + command = AddCommand(osDWord, 0); + link = command->AddLink(0, ltOffset); + link->set_sub_value(ctx.file->image_base()); + AddCommand(osDWord, string_command->dump_size()); + } + strings_entry_ = item(index); + strings_entry_->include_option(roCreateNewBlock); + strings_size_ = static_cast((count() - index) * OperandSizeToValue(osDWord)); + + // create string values + Data data; + for (i = 0; i < string_command_list.size(); i++) { + string_command = string_command_list[i]; + + data.clear(); + for (j = 0; j < string_command->dump_size(); j++) { + data.PushByte(string_command->dump(j) ^ static_cast(_rotl32(data_key_, static_cast(j)) + j)); + } + + command = AddCommand(data); + command->include_option(roCreateNewBlock); + + item(index + 1 + i * 3 + 1)->link()->set_to_command(command); + } + } + +#ifdef ULTIMATE + license_data_entry_ = NULL; + license_data_size_ = 0; + if (ctx.options.licensing_manager) { + Data license_data; + if (ctx.options.licensing_manager->GetLicenseData(license_data)) { + license_data_entry_ = AddCommand(license_data); + license_data_entry_->include_option(roCreateNewBlock); + license_data_size_ = static_cast(license_data.size()); + } + } +#endif + + VMProtectBeginVirtualization("Trial HWID"); + trial_hwid_entry_ = NULL; + trial_hwid_size_ = 0; +#ifdef DEMO + if (true) +#else + if (ctx.options.flags & cpUnregisteredVersion) +#endif + { + size_t size = VMProtectGetCurrentHWID(NULL, 0); + std::vector hwid; + hwid.resize(size); + VMProtectGetCurrentHWID(hwid.data(), (int)hwid.size()); + + std::vector binary; + binary.resize(size); + Base64Decode(hwid.data(), hwid.size(), binary.data(), size); + + Data data; + data.PushBuff(binary.data(), binary.size()); + data.resize(64); + + trial_hwid_size_ = static_cast(std::min(size, data.size())); + trial_hwid_entry_ = AddCommand(data); + trial_hwid_entry_->include_option(roCreateNewBlock); + } +#ifdef ULTIMATE + else if (!ctx.options.hwid.empty()) { + std::string hwid = ctx.options.hwid; + size_t size = hwid.size(); + + std::vector binary; + binary.resize(size); + Base64Decode(hwid.data(), hwid.size(), binary.data(), size); + if (size & 3) { + Notify(mtError, NULL, "Invalid HWID"); + return false; + } + + Data data; + data.PushBuff(binary.data(), binary.size()); + data.resize(64); + + trial_hwid_size_ = static_cast(std::min(size, data.size())); + trial_hwid_entry_ = AddCommand(data); + trial_hwid_entry_->include_option(roCreateNewBlock); + } +#endif + VMProtectEnd(); + + for (i = 0; i < count(); i++) { + item(i)->CompileToNative(); + } + + // setup faces for common runtime functions + IntelCRCTable *intel_crc = reinterpret_cast(ctx.file->function_list())->crc_table(); + for (k = 0; k < function_list->count(); k++) { + IntelFunction *func = function_list->item(k); + if (!func->from_runtime() || func->tag() == ftLoader) + continue; + + for (i = 0; i < func->count(); i++) { + IntelCommand *command = func->item(i); + for (j = 0; j < 3; j++) { + IntelOperand operand = command->operand(j); + if (operand.type == otNone) + break; + + if ((operand.type & otValue) == 0) + continue; + + if (operand.size == osQWord && ((operand.value >> 32) & 0xFFFF0000) == 0xFACE0000) { + command->Init(static_cast(command->type()), command->operand(0), IntelOperand(otValue, operand.size, 0, operand.value >> 32)); + func->InsertObject(i + 1, new IntelCommand(func, func->cpu_address_size(), cmShl, command->operand(0), IntelOperand(otValue, osWord, 0, 32))); + func->InsertObject(i + 2, new IntelCommand(func, func->cpu_address_size(), cmAdd, command->operand(0), IntelOperand(otValue, operand.size, 0, static_cast(operand.value)))); + operand = command->operand(1); + } + + uint32_t value = static_cast(operand.value); + // clang optimization + if (value == FACE_RC5_P + FACE_RC5_Q) { + command->set_operand_value(j, rc5_key_.P + rc5_key_.Q); + command->CompileToNative(); + continue; + } + if (value == FACE_RC5_P + FACE_RC5_Q + FACE_RC5_Q) { + command->set_operand_value(j, rc5_key_.P + rc5_key_.Q + rc5_key_.Q); + command->CompileToNative(); + continue; + } + + bool is_neg = false; + if ((value & 0xFFFF0000) != 0xFACE0000) { + value = 0 - value; + is_neg = true; + } + + if ((value & 0xFFFF0000) == 0xFACE0000) { + switch (value) { + case FACE_STRING_INFO: + if (strings_entry_) { + link = command->AddLink((int)j, ltOffset, strings_entry_); + link->set_sub_value(image_base); + } else { + command->set_operand_value(j, 0); + command->CompileToNative(); + } + break; + case FACE_RESOURCE_INFO: + if (resources_entry_) { + link = command->AddLink((int)j, ltOffset, resources_entry_); + link->set_sub_value(image_base); + } else { + command->set_operand_value(j, 0); + command->CompileToNative(); + } + break; + case FACE_KEY_INFO: + if (key_entry) { + link = command->AddLink((int)j, ltOffset, key_entry); + link->set_sub_value(image_base); + } else { + command->set_operand_value(j, 0); + command->CompileToNative(); + } + break; +#ifdef ULTIMATE + case FACE_STORAGE_INFO: + if (files_entry_) { + link = command->AddLink((int)j, ltOffset, files_entry_); + link->set_sub_value(image_base); + } else { + command->set_operand_value(j, 0); + command->CompileToNative(); + } + break; + case FACE_REGISTRY_INFO: + if (registry_entry_) { + link = command->AddLink((int)j, ltOffset, registry_entry_); + link->set_sub_value(image_base); + } else { + command->set_operand_value(j, 0); + command->CompileToNative(); + } + break; + case FACE_LICENSE_INFO: + if (license_data_entry_) { + link = command->AddLink((int)j, ltOffset, license_data_entry_); + link->set_sub_value(image_base); + } else { + command->set_operand_value(j, 0); + command->CompileToNative(); + } + break; + case FACE_LICENSE_INFO_SIZE: + command->set_operand_value(j, license_data_size_); + command->CompileToNative(); + break; +#else + case FACE_STORAGE_INFO: + case FACE_REGISTRY_INFO: + case FACE_LICENSE_INFO: + case FACE_LICENSE_INFO_SIZE: + command->set_operand_value(j, 0); + command->CompileToNative(); + break; +#endif + case FACE_TRIAL_HWID: + if (trial_hwid_entry_) { + link = command->AddLink((int)j, ltOffset, trial_hwid_entry_); + link->set_sub_value(image_base); + } else { + command->set_operand_value(j, 0); + command->CompileToNative(); + } + break; + case FACE_TRIAL_HWID_SIZE: + command->set_operand_value(j, trial_hwid_size_); + command->CompileToNative(); + break; + case FACE_RC5_P: + command->set_operand_value(j, is_neg ? 0 - rc5_key_.P : rc5_key_.P); + command->CompileToNative(); + break; + case FACE_RC5_Q: + command->set_operand_value(j, is_neg ? 0 - rc5_key_.Q : rc5_key_.Q); + command->CompileToNative(); + break; + case FACE_CRC_INFO_SALT: + command->set_operand_value(j, function_list->crc_cryptor()->item(0)->value()); + command->CompileToNative(); + break; + case FACE_IMAGE_BASE: + if (command->operand(0).size != cpu_address_size()) { + IntelOperand first = command->operand(0); + IntelOperand second = command->operand(1); + first.size = cpu_address_size(); + second.size = cpu_address_size(); + command->Init(static_cast(command->type()), first, second); + } + command->set_operand_value(j, image_base); + command->set_operand_fixup(j, NEED_FIXUP); + command->CompileToNative(); + break; + case FACE_CRC_TABLE_ENTRY: + if (intel_crc) { + link = command->AddLink((int)j, ltOffset, intel_crc->table_entry()); + link->set_sub_value(image_base); + } else { + command->set_operand_value(j, 0); + command->CompileToNative(); + } + break; + case FACE_CRC_TABLE_SIZE: + if (intel_crc) { + link = command->AddLink((int)j, ltOffset, intel_crc->size_entry()); + link->set_sub_value(image_base); + } else { + command->set_operand_value(j, 0); + command->CompileToNative(); + } + break; + case FACE_CRC_TABLE_HASH: + if (intel_crc) { + link = command->AddLink((int)j, ltOffset, intel_crc->hash_entry()); + link->set_sub_value(image_base); + } else { + command->set_operand_value(j, 0); + command->CompileToNative(); + } + break; + case FACE_CORE_OPTIONS: + { + uint32_t options = 0; + if (ctx.options.flags & cpInternalMemoryProtection) + options |= CORE_OPTION_MEMORY_PROTECTION; + if (ctx.options.flags & cpCheckDebugger) + options |= CORE_OPTION_CHECK_DEBUGGER; + command->set_operand_value(j, options); + } + command->CompileToNative(); + break; + case FACE_VAR_IS_PATCH_DETECTED: + case FACE_VAR_IS_DEBUGGER_DETECTED: + case FACE_VAR_LOADER_CRC_INFO: + case FACE_VAR_LOADER_CRC_INFO_SIZE: + case FACE_VAR_LOADER_CRC_INFO_HASH: + case FACE_VAR_CPU_HASH: + case FACE_VAR_SESSION_KEY: + case FACE_VAR_DRIVER_UNLOAD: + case FACE_VAR_CRC_IMAGE_SIZE: + case FACE_VAR_LOADER_STATUS: + case FACE_VAR_SERVER_DATE: + case FACE_VAR_OS_BUILD_NUMBER: + command->set_operand_value(j, ctx.runtime_var_index[(value & 0xff) >> 4] * OperandSizeToValue(cpu_address_size())); + command->CompileToNative(); + break; + case FACE_VAR_IS_PATCH_DETECTED_SALT: + case FACE_VAR_IS_DEBUGGER_DETECTED_SALT: + case FACE_VAR_LOADER_CRC_INFO_SALT: + case FACE_VAR_LOADER_CRC_INFO_SIZE_SALT: + case FACE_VAR_LOADER_CRC_INFO_HASH_SALT: + case FACE_VAR_CPU_HASH_SALT: + case FACE_VAR_DRIVER_UNLOAD_SALT: + case FACE_VAR_CRC_IMAGE_SIZE_SALT: + case FACE_VAR_SERVER_DATE_SALT: + case FACE_VAR_OS_BUILD_NUMBER_SALT: + command->set_operand_value(j, ctx.runtime_var_salt[value & 0xff]); + command->CompileToNative(); + break; + } + } + } + } + } + + return IntelFunction::Init(ctx); +} + +size_t IntelRuntimeData::WriteToFile(IArchitecture &file) +{ + size_t res = IntelFunction::WriteToFile(file); + + CipherRC5 cipher(rc5_key_); + for (size_t i = 0; i < 6; i++) { + IntelCommand *command; + size_t size; + + switch (i) { + case 0: + command = resources_entry_; + size = resources_size_; + break; + case 1: + command = strings_entry_; + size = strings_size_; + break; + case 2: + command = trial_hwid_entry_; + size = AlignValue(trial_hwid_size_, 8); + break; +#ifdef ULTIMATE + case 3: + command = license_data_entry_; + size = license_data_size_; + break; + case 4: + command = files_entry_; + size = files_size_; + break; + case 5: + command = registry_entry_; + size = registry_size_; + break; +#endif + default: + command = NULL; + size = 0; + } + + if (size) { + std::vector buff; + buff.resize(size); + file.AddressSeek(command->address()); + uint64_t pos = file.Tell(); + file.Read(&buff[0], buff.size()); +#ifdef ULTIMATE + if (command == trial_hwid_entry_) { + cipher.Encrypt(buff.data(), buff.size()); + } else if (command == license_data_entry_) { + size_t crc_pos = buff.size() - 16; + cipher.Encrypt(buff.data(), crc_pos); + SHA1 sha1; + sha1.Input(buff.data(), crc_pos); + const uint8_t *p = sha1.Result(); + for (size_t j = crc_pos; j < buff.size(); j++) { + buff[j] = p[j - crc_pos]; + } + cipher.Encrypt(buff.data() + crc_pos, 16); + } else +#endif + { + uint32_t *p = reinterpret_cast(buff.data()); + for (size_t j = 0; j < size / sizeof(uint32_t); j++) { + p[j] ^= data_key_; + } + } + file.Seek(pos); + file.Write(buff.data(), buff.size()); + } + } + + return res; +} + +/** + * BaseIntelLoader + */ + +BaseIntelLoader::BaseIntelLoader(IntelFunctionList *owner, OperandSize cpu_address_size) + : IntelFunction(owner, cpu_address_size), data_segment_address_(0), import_segment_address_(0) +{ + set_tag(ftLoader); +} + +void BaseIntelLoader::AddAVBuffer(const CompileContext &ctx) +{ + IntelCommand *command; + uint32_t sum = 0; + CommandBlock *block = AddBlock(count(), true); + for (size_t i = 0; i < 64; i++) { + uint32_t value = (i == 0) ? 0 : rand32(); + sum += value; + command = AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, value)); + command->CompileToNative(); + command->set_block(block); + } + block->set_end_index(count() - 1); + command = item(block->start_index()); + command->set_operand_value(0, 0xB7896EB5 - sum); + command->CompileToNative(); + uint64_t address = ctx.manager->Alloc((block->end_index() - block->start_index() + 1) * sizeof(uint32_t), mtReadable); + block->set_address(address); +} + +bool BaseIntelLoader::Prepare(const CompileContext &ctx) +{ + size_t i, j; + + if (ctx.file->virtual_machine_list()->count() > 1) { + std::set call_list; + + for (i = 0; i < count(); i++) { + IntelCommand *command = item(i); + if (command->type() == cmCall && (command->options() & roInternal)) { + ICommand *to_command = command->link()->to_command(); + if (!to_command) + continue; + + call_list.insert(to_command); + command_group_.insert(item(i + 1)); + } + } + if (!call_list.empty()) { + for (i = 0; i < count(); i++) { + IntelCommand *command = item(i); + if (command->type() == cmRet && (command->options() & roInternal)) { + IntelCommand *block_command = NULL; + for (j = i; j > 0; j--) { + command = item(j - 1); + if (!block_command) { + if ((command->type() == cmCall && ((command->section_options() & rtLinkedFrom) || (command->options() & roInternal) == 0)) + || command->type() == cmJmp || command->type() == cmJmpWithFlag || command->type() == cmCmov || command->type() == cmRet || command->is_data()) + block_command = item(j); + } + if (call_list.find(command) != call_list.end()) { + command_group_.insert(block_command ? block_command : command); + break; + } + } + } + } + } + } + + // prepare loader's VM + std::vector function_list = ctx.file->function_list()->processor_list(); + for (size_t k = 0; k < function_list.size(); k++) { + IntelFunction *func = reinterpret_cast(function_list[k]); + for (i = 0; i < func->count(); i++) { + IntelCommand *command = func->item(i); + for (j = 0; j < 3; j++) { + IntelOperand operand = command->operand(j); + if (operand.type == otNone) + break; + + if (operand.fixup) + command->set_operand_fixup(j, NEED_FIXUP); + } + } + for (i = 0; i < func->function_info_list()->count(); i++) { + FunctionInfo *info = func->function_info_list()->item(i); + for (size_t j = 0; j < info->count(); j++) { + AddressRange *address_range = info->item(j); + address_range->set_begin(0); + address_range->set_end(0); + } + } + } + + // prepare ranges + function_list.push_back(this); + for (i = 0; i < function_list.size(); i++) { + IntelFunction *func = reinterpret_cast(function_list[i]); + func->range_list()->Prepare(); + func->function_info_list()->Prepare(); + } + + return PrepareExtCommands(ctx); +} + +IVirtualMachine *BaseIntelLoader::virtual_machine(IVirtualMachineList *virtual_machine_list, ICommand *command) const +{ + if (command_group_.find(command) != command_group_.end()) { + for (std::set::const_iterator it = command_group_.begin(); it != command_group_.end(); it++) { + command = *it; + if (command->block()) + return command->block()->virtual_machine(); + } + } + + return IntelFunction::virtual_machine(virtual_machine_list, command); +} + +bool BaseIntelLoader::Compile(const CompileContext &ctx) +{ + size_t i, j; + + if (ctx.options.flags & cpMemoryProtection) { + IntelVirtualMachineList *virtual_machine_list = reinterpret_cast(ctx.file->virtual_machine_list()); + virtual_machine_list->ClearCRCMap(); + } + + if (!IntelFunction::Compile(ctx)) + return false; + IntelFunction::AfterCompile(ctx); + + std::vector function_list = ctx.file->function_list()->processor_list(); + function_list.push_back(this); + std::vector data_block_list[2], block_list; + for (i = 0; i < function_list.size(); i++) { + IFunction *func = function_list[i]; + for (j = 0; j < func->block_list()->count(); j++) { + CommandBlock *block = func->block_list()->item(j); + uint32_t command_options = block->function()->item(block->start_index())->options(); + if (command_options & roImportSegment) + data_block_list[0].push_back(block); + else if (command_options & roDataSegment) + data_block_list[1].push_back(block); + else + block_list.push_back(block); + } + } + + 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()); + } + + for (i = 0; i < block_list.size(); i++) { + block_list[i]->Compile(*ctx.manager); + } + + for (j = 0; j < 2; j++) { + std::vector *list = &data_block_list[j]; + if (list->empty()) + continue; + + MemoryRegion *last_region = ctx.manager->item(ctx.manager->count() - 1); + uint64_t address = last_region->address(); + uint64_t segment_address = AlignValue(address, ctx.file->segment_alignment()); + if (j == 0) + import_segment_address_ = segment_address; + else + data_segment_address_ = segment_address; + if (segment_address > address) + last_region->Alloc(segment_address - address, mtNone); + for (i = 0; i < ctx.manager->count(); i++) { + MemoryRegion *region = ctx.manager->item(i); + if (region->address() < segment_address) + region->exclude_type(mtReadable); + } + for (i = 0; i < list->size(); i++) { + list->at(i)->Compile(*ctx.manager); + } + } + + for (i = 0; i < function_list.size(); i++) { + function_list[i]->CompileInfo(ctx); + } + + if (ctx.options.flags & cpMemoryProtection) { + IntelFunctionList *function_list = reinterpret_cast(ctx.file->function_list()); + IntelRuntimeCRCTable *runtime_crc_table = function_list->runtime_crc_table(); + for (i = 0; i < function_list->count(); i++) { + IntelFunction *func = function_list->item(i); + if (func == runtime_crc_table || func->tag() == ftProcessor || func == this) + continue; + + func->set_need_compile(false); + } + runtime_crc_table->clear(); + runtime_crc_table->Compile(ctx); + } + + for (i = 0; i < function_list.size(); i++) { + IFunction *func = function_list[i]; + if (func->compilation_type() != ctMutation) + continue; + + func->CompileLinks(ctx); + } + + for (i = 0; i < function_list.size(); i++) { + IFunction *func = function_list[i]; + if (func->compilation_type() == ctMutation) + continue; + + func->CompileLinks(ctx); + } + + return true; +} + +/** + * PEIntelLoader + */ + +PEIntelLoader::PEIntelLoader(IntelFunctionList *owner, OperandSize cpu_address_size) + : BaseIntelLoader(owner, cpu_address_size), import_entry_(NULL), import_size_(0), iat_entry_(NULL), iat_size_(0), + name_entry_(NULL), resource_section_info_(NULL), resource_packer_info_(NULL), export_entry_(NULL), export_size_(0), + tls_entry_(NULL), tls_size_(0), file_crc_entry_(NULL), file_crc_size_(0), loader_crc_entry_(NULL), loader_crc_size_(0), + delay_import_entry_(NULL), delay_import_size_(0), tls_call_back_entry_(NULL), iat_address_(0), + loader_crc_size_entry_(NULL), loader_crc_hash_entry_(NULL), file_crc_size_entry_(NULL), security_cookie_(0), cfg_check_function_entry_(NULL) +{ + +} + +Data EncryptString(const char *str, uint32_t key) +{ + Data data; + for (size_t i = 0; ; i++) { + data.PushByte(str[i] ^ static_cast(_rotl32(key, (int)i) + i)); + if (!str[i]) + break; + } + return data; +} + +Data EncryptString(const os::unicode_char *str, uint32_t key) +{ + Data data; + for (size_t i = 0; ; i++) { + data.PushWord(str[i] ^ static_cast(_rotl32(key, (int)i) + i)); + if (!str[i]) + break; + } + return data; +} + +bool PEIntelLoader::Prepare(const CompileContext &ctx) +{ + size_t i, j, k, index, old_count, import_index, orig_dll_count, file_dll_count, start_index; + PEImportList new_import_list(NULL); + PEImport *import; + PEImportFunction *import_function; + IntelCommandType value_command_type; + IntelCommand *command, *iat_command, *src_command, *dst_command, *setup_image_entry, *free_image_entry; + ImportInfo import_info; + std::vector import_info_list; + std::vector import_function_info_list; + PEArchitecture *file, *runtime; + CommandLink *link; + IntelFunctionList *runtime_function_list; + IntelFunction *func; + std::map runtime_info_list; + CommandLink *src_link, *dst_link; + std::string dll_name; + IntelImport *intel_import; + IntelCRCTable *intel_crc; + uint64_t loader_data_address, tls_index_address; + + file = reinterpret_cast(ctx.file); + runtime = reinterpret_cast(ctx.runtime); + intel_import = reinterpret_cast(file->function_list())->import(); + intel_crc = reinterpret_cast(file->function_list())->crc_table(); + IntelLoaderData *loader_data = reinterpret_cast(file->function_list())->loader_data(); + loader_data_address = (loader_data) ? loader_data->entry()->address() : runtime->export_list()->GetAddressByType(atLoaderData); + if (!loader_data_address) + return false; + + // create AV signature buffer + AddAVBuffer(ctx); + start_index = count(); + + ICommand *entry_point_command = NULL; + if (file->entry_point()) { + IFunction *entry_point_func = ctx.file->function_list()->GetFunctionByAddress(file->entry_point()); + if (entry_point_func) + entry_point_command = entry_point_func->entry(); + } + import_index = 0; + file_dll_count = 0; + k = (runtime->segment_list()->count() > 0) ? 2 : 1; + for (j = 0; j < k; j++) { + PEArchitecture *source_file = (j == 0) ? file : runtime; + for (i = 0; i < source_file->import_list()->count(); i++) { + import = source_file->import_list()->item(i); + if (import->is_sdk()) + continue; + + new_import_list.AddObject(import->Clone(&new_import_list)); + import_index += import->count(); + } + + if (j == 0) + file_dll_count = new_import_list.count(); + } + + // need move native APIs to the top of vector + if (ctx.options.flags & cpImportProtection) { + for (i = 0; i < new_import_list.count(); i++) { + import = new_import_list.item(i); + + k = NOT_ID; + for (j = 0; j < import->count(); j++) { + import_function = import->item(j); + if (import_function->options() & ioNative) { + if (k == NOT_ID) + continue; + import->SwapObjects(k, j); + k++; + } else { + if (k == NOT_ID) + k = j; + } + } + } + } + + // add loader import + std::map import_map; + orig_dll_count = new_import_list.count(); + runtime_function_list = reinterpret_cast(runtime->function_list()); + for (i = 0; i < runtime_function_list->count(); i++) { + func = runtime_function_list->item(i); + if (func->tag() != ftLoader) + continue; + + for (j = 0; j < func->count(); j++) { + command = func->item(j); + import_function = NULL; + switch (command->type()) { + case cmCall: + case cmJmp: + case cmMov: + k = (command->type() == cmMov) ? 1 : 0; + if (command->operand(k).type == (otMemory | otValue)) + import_function = runtime->import_list()->GetFunctionByAddress(command->operand(k).value); + break; + } + if (!import_function) + continue; + + std::map::const_iterator it = import_map.find(import_function->address()); + PEImportFunction *new_import_function = (it != import_map.end()) ? it->second : NULL; + if (!new_import_function) { + dll_name = import_function->owner()->name(); + import = NULL; + for (k = orig_dll_count; k < new_import_list.count(); k++) { + if (new_import_list.item(k)->CompareName(dll_name)) { + import = new_import_list.item(k); + break; + } + } + if (!import) { + import = new PEImport(&new_import_list, dll_name); + new_import_list.AddObject(import); + } + new_import_function = import_function->Clone(import); + import->AddObject(new_import_function); + import_map[import_function->address()] = new_import_function; + } + runtime_info_list[command->address()] = new_import_function; + } + } + + // create import directory + for (i = 0; i < new_import_list.count(); i++) { + import = new_import_list.item(i); + +#ifdef ULTIMATE + if (ctx.options.file_manager && i < file_dll_count) { + bool is_delay_import = false; + for (j = 0; j < ctx.options.file_manager->count(); j++) { + if (import->CompareName(ctx.options.file_manager->item(j)->name())) { + is_delay_import = true; + break; + } + } + + if (is_delay_import) { + import_info.original_first_thunk = NULL; + import_info.name = NULL; + import_info.first_thunk = NULL; + + import_info_list.push_back(import_info); + continue; + } + } +#endif + + // IMAGE_IMPORT_DESCRIPTOR.OriginalFirstThunk + command = AddCommand(cmDD, IntelOperand(otValue, osDWord)); + command->AddLink(0, ltOffset); + import_info.original_first_thunk = command; + + // IMAGE_IMPORT_DESCRIPTOR.TimeDateStamp + AddCommand(cmDD, IntelOperand(otValue, osDWord)); + + // IMAGE_IMPORT_DESCRIPTOR.ForwarderChain + AddCommand(cmDD, IntelOperand(otValue, osDWord)); + + // IMAGE_IMPORT_DESCRIPTOR.Name + command = AddCommand(cmDD, IntelOperand(otValue, osDWord)); + command->AddLink(0, ltOffset); + import_info.name = command; + + // IMAGE_IMPORT_DESCRIPTOR.FirstThunk + command = AddCommand(cmDD, IntelOperand(otValue, osDWord)); + command->AddLink(0, ltOffset); + import_info.first_thunk = command; + + import_info_list.push_back(import_info); + } + + // end of import directory + for (j = 0; j < 5; j++) { + AddCommand(cmDD, IntelOperand(otValue, osDWord)); + } + + import_size_ = static_cast((count() - start_index) * sizeof(uint32_t)); + import_entry_ = item(start_index); + import_entry_->set_alignment(OperandSizeToValue(cpu_address_size())); + + // create IAT + value_command_type = (cpu_address_size() == osDWord) ? cmDD : cmDQ; + uint64_t ordinal_mask = (cpu_address_size() == osDWord) ? IMAGE_ORDINAL_FLAG32 : IMAGE_ORDINAL_FLAG64; + size_t name_index = count(); + for (i = 0; i < new_import_list.count(); i++) { + import = new_import_list.item(i); + + bool is_delay_import = (import_info_list[i].name == NULL); + + index = count(); + for (j = 0; j < import->count(); j++) { + import_function = import->item(j); + + if (is_delay_import) { + command = NULL; + } else + // for import protection need only one API for each DLL + if ((ctx.options.flags & cpImportProtection) && i < orig_dll_count && (import_function->options() & ioNative) == 0 && j > 0) { + command = NULL; + } else if (import_function->is_ordinal()) { + command = AddCommand(value_command_type, IntelOperand(otValue, cpu_address_size(), 0, ordinal_mask | import_function->ordinal())); + } else { + command = AddCommand(value_command_type, IntelOperand(otValue, cpu_address_size())); + command->AddLink(0, ltOffset); + } + ImportFunctionInfo import_function_info(import_function); + import_function_info.name = command; + + import_function_info_list.push_back(import_function_info); + } + + if (is_delay_import) + continue; + + AddCommand(value_command_type, IntelOperand(otValue, cpu_address_size())); + + import_info_list[i].original_first_thunk->link()->set_to_command(item(index)); + } + name_entry_ = item(name_index); + name_entry_->set_alignment(OperandSizeToValue(cpu_address_size())); + + size_t iat_index = count(); + for (i = 0, import_index = 0; i < new_import_list.count(); i++) { + import = new_import_list.item(i); + + bool is_delay_import = (import_info_list[i].name == NULL); + + index = count(); + for (j = 0; j < import->count(); j++, import_index++) { + import_function = import->item(j); + + if (is_delay_import) { + command = NULL; + } else + // for import protection need only one API for each DLL + if ((ctx.options.flags & cpImportProtection) && i < orig_dll_count && (import_function->options() & ioNative) == 0 && j > 0) { + command = NULL; + } else if (import_function->is_ordinal()) { + command = AddCommand(value_command_type, IntelOperand(otValue, cpu_address_size(), 0, ordinal_mask | import_function->ordinal())); + } else { + command = AddCommand(value_command_type, IntelOperand(otValue, cpu_address_size())); + command->AddLink(0, ltOffset); + } + + import_function_info_list[import_index].thunk = command; + } + + if (is_delay_import) + continue; + + AddCommand(value_command_type, IntelOperand(otValue, cpu_address_size())); + + import_info_list[i].first_thunk->link()->set_to_command(item(index)); + } + + iat_entry_ = item(iat_index); + iat_size_ = static_cast((count() - iat_index) * OperandSizeToValue(cpu_address_size())); + iat_entry_->set_alignment(file->segment_alignment()); + iat_entry_->include_option(roCreateNewBlock); + + if (iat_address_) { + CommandBlock *block = AddBlock(iat_index, true); + block->set_address(iat_address_); + for (i = iat_index; i < count(); i++) { + block->set_end_index(i); + item(i)->set_block(block); + } + } + else { + // IAT size must be aligned by page size + j = AlignValue(iat_size_, file->segment_alignment()); + if (j > iat_size_) { + std::string buffer; + buffer.resize(j - iat_size_, 0); + AddCommand(buffer); + } + } + + // create import DLL names + uint32_t string_key = rand32(); + for (i = 0; i < new_import_list.count(); i++) { + import = new_import_list.item(i); + + bool is_delay_import = (import_info_list[i].name == NULL); + + if (is_delay_import) { + command = AddCommand(EncryptString(import->name().c_str(), string_key)); + command->include_option(roCreateNewBlock); + + import_info_list[i].loader_name = command; + continue; + } + + if ((ctx.options.flags & cpImportProtection) && i < orig_dll_count) { + command = AddCommand(EncryptString(import->name().c_str(), string_key)); + command->include_option(roCreateNewBlock); + + import_info_list[i].loader_name = command; + } + + command = NULL; + for (j = 0; j < i; j++) { + if (new_import_list.item(j)->CompareName(import->name())) { + command = reinterpret_cast(import_info_list[j].name->link()->to_command()); + break; + } + } + if (command == NULL) { + command = AddCommand(import->name()); + command->include_option(roCreateNewBlock); + command->set_alignment(sizeof(uint16_t)); + } + + import_info_list[i].name->link()->set_to_command(command); + } + + // create import function names + for (i = 0, import_index = 0; i < new_import_list.count(); i++) { + import = new_import_list.item(i); + + bool is_delay_import = (import_info_list[i].name == NULL); + + for (j = 0; j < import->count(); j++, import_index++) { + import_function = import->item(j); + if (import_function->is_ordinal()) + continue; + + if (is_delay_import) { + command = AddCommand(EncryptString(import_function->name().c_str(), string_key)); + command->include_option(roCreateNewBlock); + + import_function_info_list[import_index].loader_name = command; + continue; + } + + // for import protection need only one API for each DLL + if ((ctx.options.flags & cpImportProtection) && i < orig_dll_count && (import_function->options() & ioNative) == 0) { + command = AddCommand(EncryptString(import_function->name().c_str(), string_key)); + command->include_option(roCreateNewBlock); + + import_function_info_list[import_index].loader_name = command; + + if (j > 0) + continue; + } + + command = AddCommand(cmDW, IntelOperand(otValue, osWord)); + command->include_option(roCreateNewBlock); + command->set_alignment(sizeof(uint16_t)); + + AddCommand(import_function->name()); + + import_function_info_list[import_index].name->link()->set_to_command(command); + import_function_info_list[import_index].thunk->link()->set_to_command(command); + } + } + + // update links for PE structures + for (i = 0; i < count(); i++) { + link = item(i)->link(); + if (!link) + continue; + + link->set_sub_value(file->image_base()); + } + + // create export + export_entry_ = NULL; + export_size_ = 0; + if (ctx.options.flags & cpPack) { + index = count(); + export_size_ = file->export_list()->WriteToData(*this, file->image_base()); + export_entry_ = (count() == index) ? AddCommand(osDWord, 0) : item(index); + } + + // create delay import + delay_import_entry_ = NULL; + delay_import_size_ = 0; + if (file->delay_import_list()->count()) { + std::vector delay_import_info; + PEDelayImport *delay_import; + PEDelayImportFunction *delay_import_function; + + size_t delay_index = count(); + for (i = 0; i < file->delay_import_list()->count(); i++) { + delay_import = file->delay_import_list()->item(i); + + index = count(); + AddCommand(osDWord, delay_import->flags()); + + import_info.name = AddCommand(osDWord, 0); + import_info.name->AddLink(0, ltOffset); + + AddCommand(osDWord, delay_import->module()); + AddCommand(osDWord, delay_import->iat()); + + import_info.first_thunk = AddCommand(osDWord, 0); + import_info.first_thunk->AddLink(0, ltOffset); + + AddCommand(osDWord, delay_import->bound_iat()); + AddCommand(osDWord, delay_import->unload_iat()); + AddCommand(osDWord, delay_import->time_stamp()); + + for (j = index + 1; j < count() - 1; j++) { + command = item(j); + if (delay_import->flags() & 1) { + if (command->link()) + command->link()->set_sub_value(file->image_base()); + else if (command->operand(0).value) + command->set_operand_value(0, command->operand(0).value - file->image_base()); + } else { + if (command->link() || command->operand(0).value) + command->set_operand_fixup(0, NEED_FIXUP); + } + } + + delay_import_info.push_back(import_info); + } + + // end of delay import + for (j = 0; j < 8; j++) { + AddCommand(osDWord, 0); + } + + delay_import_entry_ = item(delay_index); + delay_import_entry_->include_option(roCreateNewBlock); + delay_import_entry_->set_alignment(OperandSizeToValue(osDWord)); + delay_import_size_ = static_cast((count() - delay_index) * sizeof(uint32_t)); + + for (i = 0; i < file->delay_import_list()->count(); i++) { + delay_import = file->delay_import_list()->item(i); + + index = count(); + for (j = 0; j < delay_import->count(); j++) { + delay_import_function = delay_import->item(j); + if (delay_import_function->is_ordinal()) { + command = AddCommand(cpu_address_size(), ordinal_mask | delay_import_function->ordinal()); + } else { + command = AddCommand(cpu_address_size(), 0); + link = command->AddLink(0, ltOffset); + if (delay_import->flags() & 1) + link->set_sub_value(file->image_base()); + else + command->set_operand_fixup(0, NEED_FIXUP); + } + } + AddCommand(cpu_address_size(), 0); + + command = item(index); + delay_import_info[i].first_thunk->link()->set_to_command(command); + delay_import_info[i].original_first_thunk = command; + } + + for (i = 0; i < file->delay_import_list()->count(); i++) { + delay_import = file->delay_import_list()->item(i); + import_info = delay_import_info[i]; + + command = AddCommand(delay_import->name()); + command->include_option(roCreateNewBlock); + import_info.name->link()->set_to_command(command); + + index = IndexOf(import_info.original_first_thunk); + for (j = 0; j < delay_import->count(); j++) { + delay_import_function = delay_import->item(j); + if (delay_import_function->is_ordinal()) + continue; + + command = AddCommand(osWord, 0); + command->include_option(roCreateNewBlock); + command->set_alignment(sizeof(uint16_t)); + AddCommand(delay_import_function->name()); + + item(index + j)->link()->set_to_command(command); + } + } + } + + // create tls structure + tls_entry_ = NULL; + tls_size_ = 0; + tls_call_back_entry_ = NULL; + tls_index_address = 0; + if (file->tls_directory()->address() && (file->tls_directory()->count() || (ctx.options.flags & cpPack))) { + size_t tls_index = count(); + + PETLSDirectory *tls_directory = file->tls_directory(); + if (ctx.options.flags & cpPack) { + if (file->AddressSeek(tls_directory->address_of_index()) && !file->selected_segment()->excluded_from_packing()) + tls_index_address = tls_directory->address_of_index(); + } + + AddCommand(value_command_type, IntelOperand(otValue, cpu_address_size(), 0, tls_directory->start_address_of_raw_data(), NEED_FIXUP)); + AddCommand(value_command_type, IntelOperand(otValue, cpu_address_size(), 0, tls_directory->end_address_of_raw_data(), NEED_FIXUP)); + AddCommand(value_command_type, IntelOperand(otValue, cpu_address_size(), 0, tls_directory->address_of_index(), NEED_FIXUP)); + IntelCommand *call_back_entry = AddCommand(value_command_type, IntelOperand(otValue, cpu_address_size(), 0, 0)); + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, tls_directory->size_of_zero_fill())); + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, tls_directory->characteristics())); + + tls_entry_ = item(tls_index); + tls_entry_->include_option(roCreateNewBlock); + tls_entry_->set_alignment(OperandSizeToValue(cpu_address_size())); + for (i = tls_index; i < count(); i++) { + command = item(i); + tls_size_ += (command->type() == cmDB) ? (uint32_t)command->dump_size() : OperandSizeToValue(command->operand(0).size); + } + + index = count(); + if (file->tls_directory()->count()) { + tls_call_back_entry_ = AddCommand(value_command_type, IntelOperand(otValue, cpu_address_size(), 0, 0, NEED_FIXUP)); + tls_call_back_entry_->AddLink(0, ltGateOffset); + } + for (i = 0; i < tls_directory->count(); i++) { + AddCommand(value_command_type, IntelOperand(otValue, cpu_address_size(), 0, tls_directory->item(i)->address(), NEED_FIXUP)); + } + if (count() > index) { + AddCommand(value_command_type, IntelOperand(otValue, cpu_address_size(), 0, 0)); + call_back_entry->AddLink(0, ltOffset, item(index)); + call_back_entry->set_operand_fixup(0, NEED_FIXUP); + } + } + + // create watermarks + AddWatermark(ctx.options.watermark, 2); + + // create section list for setting WRITABLE flag + PESegment *section; + std::vector writable_section_list; + uint64_t address; + section = file->segment_list()->GetSectionByAddress(loader_data_address); + if (section) + writable_section_list.push_back(section); + for (i = 0; i < orig_dll_count; i++) { + import = new_import_list.item(i); + for (j = 0; j < import->count(); j++) { + import_function = import->item(j); + address = import_function->address(); + if (ctx.options.flags & cpImportProtection) { + iat_command = intel_import->GetIATCommand(import_function); + if (iat_command) + address = iat_command->address(); + } + section = file->segment_list()->GetSectionByAddress(address); + if (!section) + continue; + + if (std::find(writable_section_list.begin(), writable_section_list.end(), section) == writable_section_list.end()) + writable_section_list.push_back(section); + } + } + + for (i = 0; i < file->relocation_list()->count(); i++) { + PERelocation *relocation = file->relocation_list()->item(i); + + section = file->segment_list()->GetSectionByAddress(relocation->address()); + if (!section) + continue; + + if (std::find(writable_section_list.begin(), writable_section_list.end(), section) == writable_section_list.end()) + writable_section_list.push_back(section); + } + + std::vector packer_info_list; + PEFixupList loader_fixup_list; + bool pack_resources = false; + IntelCommand *packer_props = NULL; + if (ctx.options.flags & cpPack) { + PackerInfo packer_info; + for (i = 0; i < file->segment_list()->count(); i++) { + section = file->segment_list()->item(i); + if (section->excluded_from_packing()) + continue; + + bool can_be_packed = true; + if ((section->memory_type() & (mtWritable | mtShared)) == (mtWritable | mtShared)) { + can_be_packed = false; + } + + if (!can_be_packed) { + //file->Notify(mtWarning, NULL, string_format(language[lsSegmentCanNotBePacked].c_str(), section->name().c_str())); + continue; + } + + if (section->physical_size()) { + packer_info.section = section; + packer_info.address = section->address(); + packer_info.size = static_cast(section->physical_size()); + packer_info.data = NULL; + packer_info_list.push_back(packer_info); + + // need add packed section into WRITABLE section list + if (std::find(writable_section_list.begin(), writable_section_list.end(), section) == writable_section_list.end()) + writable_section_list.push_back(section); + } + } + + if ((ctx.options.flags & cpStripFixups) == 0) { + for (i = 0; i < file->fixup_list()->count(); i++) { + PEFixup *fixup = file->fixup_list()->item(i); + if (fixup->is_deleted()) + continue; + + section = file->segment_list()->GetSectionByAddress(fixup->address()); + if (!section || std::find(packer_info_list.begin(), packer_info_list.end(), section) == packer_info_list.end()) + continue; + + loader_fixup_list.AddObject(fixup->Clone(&loader_fixup_list)); + fixup->set_deleted(true); + + // need add section into WRITABLE section list + if (std::find(writable_section_list.begin(), writable_section_list.end(), section) == writable_section_list.end()) + writable_section_list.push_back(section); + } + } + + // packing sections + j = 0; + for (i = 0; i < packer_info_list.size(); i++) { + j += packer_info_list[i].size; + } + if (file->resource_list()->size() > file->resource_list()->store_size()) + j += file->resource_list()->size() - file->resource_list()->store_size(); + file->StartProgress(string_format("%s...", language[lsPacking].c_str()), j); + + Data data; + Packer packer; + + if (!packer.WriteProps(&data)) + throw std::runtime_error("Packer error"); + packer_props = AddCommand(data); + packer_props->include_option(roCreateNewBlock); + + for (i = 0; i < packer_info_list.size(); i++) { + packer_info = packer_info_list[i]; + if (!file->AddressSeek(packer_info.address)) + return false; + + if (!packer.Code(file, packer_info.size, &data)) + throw std::runtime_error("Packer error"); + + command = AddCommand(data); + command->include_option(roCreateNewBlock); + packer_info_list[i].data = command; + } + + if (file->resource_list()->size() > file->resource_list()->store_size()) { + Data res_data; + file->resource_list()->WritePackData(res_data); + + if (!packer.Code(file, &res_data, &data)) + return false; + + command = AddCommand(data); + command->include_option(roCreateNewBlock); + + packer_info.address = 0; + packer_info.size = res_data.size(); + packer_info.data = command; + packer_info.section = NULL; + packer_info_list.push_back(packer_info); + pack_resources = true; + } + + // remove packed sections from file + uint32_t physical_offset = 0; + for (i = 0; i < file->segment_list()->count(); i++) { + section = file->segment_list()->item(i); + if (section->physical_offset() > 0 && section->physical_size() > 0) { + physical_offset = static_cast(section->physical_offset()); + break; + } + } + + for (i = 0; i < file->segment_list()->count(); i++) { + section = file->segment_list()->item(i); + uint32_t physical_size = section->physical_size(); + bool is_packed = false; + std::vector::iterator it = std::find(packer_info_list.begin(), packer_info_list.end(), section); + if (it != packer_info_list.end()) { + physical_size = static_cast(it->address - section->address()); + is_packed = true; + } + + if (physical_size > 0 && section->physical_offset() != physical_offset) { + uint8_t *buff = new uint8_t[physical_size]; + file->Seek(section->physical_offset()); + file->Read(buff, physical_size); + file->Seek(physical_offset); + file->Write(buff, physical_size); + delete [] buff; + } + + section->set_physical_offset(physical_offset); + section->set_physical_size(physical_size); + + if (is_packed) { + j = physical_offset + physical_size; + file->Seek(j); + physical_offset = (uint32_t)AlignValue(j, file->file_alignment()); + for (k = j; k < physical_offset; k++) { + file->WriteByte(0); + } + } else { + physical_offset += physical_size; + } + } + file->Resize(physical_offset); + } + + // create packer info for loader + std::vector loader_info_list; + index = count(); + if (packer_props) { + command = AddCommand(cmDD, IntelOperand(otValue, osDWord)); + link = command->AddLink(0, ltOffset, packer_props); + link->set_sub_value(file->image_base()); + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, packer_props->dump_size())); + + for (i = 0; i < packer_info_list.size(); i++) { + command = AddCommand(cmDD, IntelOperand(otValue, osDWord)); + link = command->AddLink(0, ltOffset, packer_info_list[i].data); + link->set_sub_value(file->image_base()); + + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, packer_info_list[i].address - file->image_base())); + } + } + if (pack_resources) { + resource_packer_info_ = item(count() - 1); + } else { + resource_packer_info_ = NULL; + } + command = (count() == index) ? NULL : item(index); + if (command) + command->include_option(roCreateNewBlock); + loader_info_list.push_back(LoaderInfo(command, (count() - index) * OperandSizeToValue(osDWord))); + + // create file CRC info for loader + index = count(); + if (((ctx.options.flags | ctx.options.sdk_flags) & cpMemoryProtection) && file->image_type() != itDriver) { + AddCommand(cmDD, IntelOperand(otValue, osDWord)); + for (i = 0; i < 10; i++) { + AddCommand(cmDD, IntelOperand(otValue, osDWord)); + AddCommand(cmDD, IntelOperand(otValue, osDWord)); + AddCommand(cmDD, IntelOperand(otValue, osDWord)); + } + } + file_crc_entry_ = (count() == index) ? NULL : item(index); + if (file_crc_entry_) + file_crc_entry_->include_option(roCreateNewBlock); + file_crc_size_ = (uint32_t)((count() - index) * OperandSizeToValue(osDWord)); + loader_info_list.push_back(LoaderInfo(file_crc_entry_, file_crc_size_)); + + file_crc_size_entry_ = file_crc_entry_ ? AddCommand(cmDD, IntelOperand(otValue, osDWord)) : NULL; + if (file_crc_size_entry_) + file_crc_size_entry_->include_option(roCreateNewBlock); + + // create header and loader CRC info for loader + index = count(); + if (((ctx.options.flags | ctx.options.sdk_flags) & cpMemoryProtection) || (ctx.options.flags & cpLoaderCRC)) { + // calc CRC blocks count + k = 30 + new_import_list.count(); + if ((ctx.options.flags & cpStripFixups) == 0) { + std::vector function_list = ctx.file->function_list()->processor_list(); + function_list.push_back(this); + for (i = 0; i < runtime_function_list->count(); i++) { + func = runtime_function_list->item(i); + if (func->tag() != ftLoader) + continue; + + if (func->compilation_type() == ctMutation) + function_list.push_back(func); + } + + for (i = 0; i < function_list.size(); i++) { + func = reinterpret_cast(function_list[i]); + for (j = 0; j < func->count(); j++) { + command = func->item(j); + for (size_t c = 0; c < 3; c++) { + IntelOperand operand = command->operand(c); + if (operand.type == otNone) + break; + if (operand.fixup) + k++; + } + } + } + } + for (i = 0; i < k; i++) { + AddCommand(cmDD, IntelOperand(otValue, osDWord)); + AddCommand(cmDD, IntelOperand(otValue, osDWord)); + AddCommand(cmDD, IntelOperand(otValue, osDWord)); + } + } + loader_crc_entry_ = (count() == index) ? NULL : item(index); + if (loader_crc_entry_) + loader_crc_entry_->include_option(roCreateNewBlock); + loader_crc_size_ = static_cast((count() - index) * OperandSizeToValue(osDWord)); + loader_info_list.push_back(LoaderInfo(loader_crc_entry_, loader_crc_size_)); + + loader_crc_size_entry_ = loader_crc_entry_ ? AddCommand(cmDD, IntelOperand(otValue, osDWord)) : NULL; + if (loader_crc_size_entry_) + loader_crc_size_entry_->include_option(roCreateNewBlock); + loader_crc_hash_entry_ = loader_crc_entry_ ? AddCommand(cmDD, IntelOperand(otValue, osDWord)) : NULL; + if (loader_crc_hash_entry_) + loader_crc_hash_entry_->include_option(roCreateNewBlock); + + // create section info for loader + bool skip_writable_sections = (file->image_type() != itDriver); + index = count(); + for (i = 0; i < writable_section_list.size(); i++) { + section = writable_section_list[i]; + if (skip_writable_sections && section->memory_type() & mtWritable) + continue; + + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, section->address() - file->image_base())); + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, section->size())); + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, section->flags())); + } + // add runtime's WRITABLE sections + for (i = 0; i < runtime->segment_list()->count(); i++) { + section = runtime->segment_list()->item(i); + if (section->memory_type() & mtWritable) { + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, section->address() - file->image_base())); + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, section->size())); + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, section->flags())); + } + } + if (pack_resources) { + resource_section_info_ = AddCommand(cmDD, IntelOperand(otValue, osDWord)); + AddCommand(cmDD, IntelOperand(otValue, osDWord)); + AddCommand(cmDD, IntelOperand(otValue, osDWord)); + } else { + resource_section_info_ = NULL; + } + command = (count() == index) ? NULL : item(index); + if (command) + command->include_option(roCreateNewBlock); + loader_info_list.push_back(LoaderInfo(command, (count() - index) * OperandSizeToValue(osDWord))); + + // create fixup info for loader + if (loader_fixup_list.count() > 0) { + Data data; + loader_fixup_list.WriteToData(data, file->image_base()); + command = AddCommand(data); + } else { + command = NULL; + } + if (command) + command->include_option(roCreateNewBlock); + loader_info_list.push_back(LoaderInfo(command, (command) ? command->dump_size() : 0)); + + // create relocation info for loader + if (file->relocation_list()->count() > 0) { + Data data; + file->relocation_list()->WriteToData(data, file->image_base()); + command = AddCommand(data); + } else { + command = NULL; + } + if (command) + command->include_option(roCreateNewBlock); + loader_info_list.push_back(LoaderInfo(command, (command) ? command->dump_size() : 0)); + + // create IAT info for loader + index = count(); + for (i = 0, import_index = 0; i < orig_dll_count; i++) { + import = new_import_list.item(i); + if (import->count() == 0) + continue; + + if (ctx.options.flags & cpImportProtection) { + for (j = 0; j < import->count(); j++, import_index++) { + import_function = import->item(j); + if ((import_function->options() & ioNative) == 0) + continue; + + iat_command = intel_import->GetIATCommand(import_function); + + command = AddCommand(cmDD, IntelOperand(otValue, osDWord)); + link = command->AddLink(0, ltOffset, import_function_info_list[import_index].thunk); + link->set_sub_value(file->image_base()); + + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, ((iat_command) ? iat_command->address() : import_function->address()) - file->image_base())); + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, OperandSizeToValue(cpu_address_size()))); + } + } else { + import_function = import->item(0); + command = AddCommand(cmDD, IntelOperand(otValue, osDWord)); + link = command->AddLink(0, ltOffset, import_function_info_list[import_index].thunk); + link->set_sub_value(file->image_base()); + + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, import_function->address() - file->image_base())); + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, import->count() * OperandSizeToValue(cpu_address_size()))); + + import_index += import->count(); + } + } + if (security_cookie_) { + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, security_cookie_ - file->image_base())); + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, file->load_config_directory()->security_cookie() - file->image_base())); + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, OperandSizeToValue(cpu_address_size()))); + } + command = (count() == index) ? NULL : item(index); + if (command) + command->include_option(roCreateNewBlock); + loader_info_list.push_back(LoaderInfo(command, (count() - index) * OperandSizeToValue(osDWord))); + + // create import info for loader + index = count(); + if (ctx.options.flags & cpImportProtection) { + for (i = 0, import_index = 0; i < orig_dll_count; i++) { + import = new_import_list.item(i); + if (import->count() == 0) + continue; + + if (import_info_list[i].name == NULL) { + // delay import + import_index += import->count(); + continue; + } + + // DLL name + command = AddCommand(cmDD, IntelOperand(otValue, osDWord)); + link = command->AddLink(0, ltOffset, import_info_list[i].loader_name); + link->set_sub_value(file->image_base()); + + for (j = 0; j < import->count(); j++, import_index++) { + import_function = import->item(j); + if (import_function->options() & ioNative) + continue; + + if (import_function->IsInternal(ctx)) + continue; + + iat_command = intel_import->GetIATCommand(import_function); + + // API name + if (import_function->is_ordinal()) { + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, IMAGE_ORDINAL_FLAG32 | import_function->ordinal())); + } else { + command = AddCommand(cmDD, IntelOperand(otValue, osDWord)); + link = command->AddLink(0, ltOffset, import_function_info_list[import_index].loader_name); + link->set_sub_value(file->image_base()); + } + + // IAT + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, ((iat_command) ? iat_command->address() : import_function->address()) - file->image_base())); + + // decrypt value + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, (iat_command) ? iat_command->operand(1).value : 0)); + } + + // end of DLL + AddCommand(cmDD, IntelOperand(otValue, osDWord)); + } + } + command = (count() == index) ? NULL : item(index); + if (command) + command->include_option(roCreateNewBlock); + loader_info_list.push_back(LoaderInfo(command, (count() - index) * OperandSizeToValue(osDWord))); + + // create internal import info for loader + index = count(); + for (i = 0; i < orig_dll_count; i++) { + import = new_import_list.item(i); + for (j = 0; j < import->count(); j++) { + import_function = import->item(j); + + if (!import_function->IsInternal(ctx)) + continue; + + iat_command = (intel_import) ? intel_import->GetIATCommand(import_function) : NULL; + + address = runtime->export_list()->GetAddressByType(import_function->type()); + func = reinterpret_cast(file->function_list()->GetFunctionByAddress(address)); + if (func && func->entry()) + address = func->entry()->address(); + + // address + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, address - file->image_base())); + // IAT + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, ((iat_command) ? iat_command->address() : import_function->address()) - file->image_base())); + // decrypt value + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, (iat_command) ? iat_command->operand(1).value : 0)); + } + } + command = (count() == index) ? NULL : item(index); + if (command) + command->include_option(roCreateNewBlock); + loader_info_list.push_back(LoaderInfo(command, (count() - index) * OperandSizeToValue(osDWord))); + + // create memory CRC info for loader + if (intel_crc) { + command = intel_crc->table_entry(); + i = static_cast(intel_crc->size_entry()->operand(0).value); + } else { + command = NULL; + i = 0; + } + loader_info_list.push_back(LoaderInfo(command, i)); + + // create delay import info for loader + index = count(); +#ifdef ULTIMATE + for (i = 0, import_index = 0; i < orig_dll_count; i++) { + import = new_import_list.item(i); + if (import->count() == 0) + continue; + + if (import_info_list[i].name) { + import_index += import->count(); + continue; + } + + // DLL name + command = AddCommand(cmDD, IntelOperand(otValue, osDWord)); + link = command->AddLink(0, ltOffset, import_info_list[i].loader_name); + link->set_sub_value(file->image_base()); + + for (j = 0; j < import->count(); j++, import_index++) { + import_function = import->item(j); + if (import_function->options() & ioNative) + continue; + + if (import_function->IsInternal(ctx)) + continue; + + iat_command = (intel_import) ? intel_import->GetIATCommand(import_function) : NULL; + + // API name + if (import_function->is_ordinal()) { + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, IMAGE_ORDINAL_FLAG32 | import_function->ordinal())); + } else { + command = AddCommand(cmDD, IntelOperand(otValue, osDWord)); + link = command->AddLink(0, ltOffset, import_function_info_list[import_index].loader_name); + link->set_sub_value(file->image_base()); + } + + // IAT + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, ((iat_command) ? iat_command->address() : import_function->address()) - file->image_base())); + + // decrypt value + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, (iat_command) ? iat_command->operand(1).value : 0)); + } + + // end of DLL + AddCommand(cmDD, IntelOperand(otValue, osDWord)); + } +#endif + command = (count() == index) ? NULL : item(index); + if (command) + command->include_option(roCreateNewBlock); + loader_info_list.push_back(LoaderInfo(command, (count() - index) * OperandSizeToValue(osDWord))); + + // create strings for loader + std::map loader_string_list; + loader_string_list[FACE_FILE_CORRUPTED] = AddCommand(EncryptString((ctx.options.flags & cpMemoryProtection) ? os::FromUTF8(ctx.options.messages[MESSAGE_FILE_CORRUPTED]).c_str() : os::unicode_string().c_str(), string_key)); + loader_string_list[FACE_DEBUGGER_FOUND] = AddCommand(EncryptString(os::FromUTF8(ctx.options.messages[MESSAGE_DEBUGGER_FOUND]).c_str(), string_key)); + loader_string_list[FACE_VIRTUAL_MACHINE_FOUND] = AddCommand(EncryptString(os::FromUTF8(ctx.options.messages[MESSAGE_VIRTUAL_MACHINE_FOUND]).c_str(), string_key)); + loader_string_list[FACE_INITIALIZATION_ERROR] = AddCommand(EncryptString(os::FromUTF8("Initialization error %d").c_str(), string_key)); + VMProtectBeginVirtualization("Loader Strings"); + loader_string_list[FACE_UNREGISTERED_VERSION] = AddCommand(EncryptString( +#ifdef DEMO + true +#else + (ctx.options.flags & cpUnregisteredVersion) +#endif + ? os::FromUTF8(VMProtectDecryptStringA("This application is protected with unregistered version of VMProtect.")).c_str() : os::unicode_string().c_str(), string_key)); + VMProtectEnd(); + loader_string_list[FACE_SICE_NAME] = AddCommand(EncryptString("sice.sys", string_key)); + loader_string_list[FACE_SIWVID_NAME] = AddCommand(EncryptString("siwvid.sys", string_key)); + loader_string_list[FACE_NTICE_NAME] = AddCommand(EncryptString("ntice.sys", string_key)); + loader_string_list[FACE_ICEEXT_NAME] = AddCommand(EncryptString("iceext.sys", string_key)); + loader_string_list[FACE_SYSER_NAME] = AddCommand(EncryptString("syser.sys", string_key)); + if (file->image_type() == itDriver) { + loader_string_list[FACE_PROC_NOT_FOUND] = AddCommand(EncryptString(os::FromUTF8("The procedure entry point %c could not be located in the module %c").c_str(), string_key)); + loader_string_list[FACE_ORDINAL_NOT_FOUND] = AddCommand(EncryptString(os::FromUTF8("The ordinal %d could not be located in the module %c").c_str(), string_key)); + loader_string_list[FACE_DRIVER_FORMAT_VALUE] = AddCommand("%ws\n"); + loader_string_list[FACE_NTOSKRNL_NAME] = AddCommand(EncryptString("ntoskrnl.exe", string_key)); + loader_string_list[FACE_HAL_NAME] = AddCommand(EncryptString("hal.dll", string_key)); + } else { + loader_string_list[FACE_PROC_NOT_FOUND] = AddCommand(EncryptString(os::FromUTF8("The procedure entry point %c could not be located in the dynamic link library %c").c_str(), string_key)); + loader_string_list[FACE_ORDINAL_NOT_FOUND] = AddCommand(EncryptString(os::FromUTF8("The ordinal %d could not be located in the dynamic link library %c").c_str(), string_key)); + loader_string_list[FACE_USER32_NAME] = AddCommand(EncryptString("user32.dll", string_key)); + loader_string_list[FACE_MESSAGE_BOX_NAME] = AddCommand(EncryptString("MessageBoxW", string_key)); + loader_string_list[FACE_KERNEL32_NAME] = AddCommand(EncryptString("kernel32.dll", string_key)); + loader_string_list[FACE_CLOSE_HANDLE_NAME] = AddCommand(EncryptString("CloseHandle", string_key)); + loader_string_list[FACE_IS_WOW64_PROCESS_NAME] = AddCommand(EncryptString("IsWow64Process", string_key)); + loader_string_list[FACE_WINE_GET_VERSION_NAME] = AddCommand(EncryptString("wine_get_version", string_key)); + loader_string_list[FACE_WTSAPI32_NAME] = AddCommand(EncryptString("wtsapi32.dll", string_key)); + loader_string_list[FACE_WTS_SEND_MESSAGE_NAME] = AddCommand(EncryptString("WTSSendMessageW", string_key)); + loader_string_list[FACE_NTDLL_NAME] = AddCommand(EncryptString("ntdll.dll", string_key)); + loader_string_list[FACE_NT_QUERY_INFORMATION_NAME] = AddCommand(EncryptString("NtQuerySystemInformation", string_key)); + loader_string_list[FACE_NT_SET_INFORMATION_THREAD_NAME] = AddCommand(EncryptString("NtSetInformationThread", string_key)); + loader_string_list[FACE_NT_QUERY_INFORMATION_PROCESS_NAME] = AddCommand(EncryptString("NtQueryInformationProcess", string_key)); + loader_string_list[FACE_SBIEDLL_NAME] = AddCommand(EncryptString("sbiedll.dll", string_key)); + loader_string_list[FACE_QUERY_VIRTUAL_MEMORY_NAME] = AddCommand(EncryptString("NtQueryVirtualMemory", string_key)); + loader_string_list[FACE_ENUM_SYSTEM_FIRMWARE_NAME] = AddCommand(EncryptString("EnumSystemFirmwareTables", string_key)); + loader_string_list[FACE_GET_SYSTEM_FIRMWARE_NAME] = AddCommand(EncryptString("GetSystemFirmwareTable", string_key)); + loader_string_list[FACE_NT_VIRTUAL_PROTECT_NAME] = AddCommand(EncryptString("NtProtectVirtualMemory", string_key)); + loader_string_list[FACE_NT_OPEN_FILE_NAME] = AddCommand(EncryptString("NtOpenFile", string_key)); + loader_string_list[FACE_NT_CREATE_SECTION_NAME] = AddCommand(EncryptString("NtCreateSection", string_key)); + loader_string_list[FACE_NT_OPEN_SECTION_NAME] = AddCommand(EncryptString("NtOpenSection", string_key)); + loader_string_list[FACE_NT_MAP_VIEW_OF_SECTION] = AddCommand(EncryptString("NtMapViewOfSection", string_key)); + loader_string_list[FACE_NT_UNMAP_VIEW_OF_SECTION] = AddCommand(EncryptString("NtUnmapViewOfSection", string_key)); + loader_string_list[FACE_NT_CLOSE] = AddCommand(EncryptString("NtClose", string_key)); + loader_string_list[FACE_NT_SET_INFORMATION_PROCESS_NAME] = AddCommand(EncryptString("NtSetInformationProcess", string_key)); + loader_string_list[FACE_NT_RAISE_HARD_ERROR_NAME] = AddCommand(EncryptString("NtRaiseHardError", string_key)); + } + for (std::map::const_iterator it = loader_string_list.begin(); it != loader_string_list.end(); it++) { + it->second->include_option(roCreateNewBlock); + } + + cfg_check_function_entry_ = NULL; + if (file->load_config_directory()->cfg_check_function()) { + // work around check in LdrpCfgProcessLoadConfig + PESegment *segment = file->segment_list()->GetSectionByAddress(file->load_config_directory()->cfg_check_function()); + if (segment && std::find(packer_info_list.begin(), packer_info_list.end(), segment) != packer_info_list.end()) { + CommandBlock *block = AddBlock(count(), true); + cfg_check_function_entry_ = AddCommand(value_command_type, IntelOperand(otValue, cpu_address_size(), 0, file->load_config_directory()->cfg_check_function(), NEED_FIXUP)); + cfg_check_function_entry_->set_block(block); + } + } + + // append loader + old_count = count(); + std::vector internal_entry_list; + for (size_t n = 0; n < 2; n++) { + for (i = 0; i < runtime_function_list->count(); i++) { + func = runtime_function_list->item(i); + if (func->tag() != ftLoader) + continue; + + if (func->compilation_type() == ctMutation) { + if (n != 0) + continue; + } else { + if (n != 1) + continue; + } + + func->Init(ctx); + + size_t orig_function_info_count = function_info_list()->count(); + for (j = 0; j < func->function_info_list()->count(); j++) { + FunctionInfo *info = func->function_info_list()->item(j); + function_info_list()->AddObject(info->Clone(function_info_list())); + } + for (j = 0; j < func->range_list()->count(); j++) { + AddressRange *range = func->range_list()->item(j); + range_list()->AddObject(range->Clone(range_list())); + } + + bool is_internal = (func->compilation_type() != ctMutation && func->entry_type() == etNone); + for (j = 0; j < func->link_list()->count(); j++) { + src_link = func->link_list()->item(j); + if (src_link->type() != ltMemSEHBlock) + continue; + + src_link->from_command()->set_address(0); + if (!is_internal || (src_link->from_command()->options() & roExternal) == 0) + continue; + + src_command = func->GetCommandByAddress(src_link->to_address()); + if (!src_command) + continue; + + for (k = func->IndexOf(src_command); k < func->count(); k++) { + src_command = func->item(k); + if (src_command->type() == cmRet) { + src_command->include_option(roExternal); + break; + } + } + } + + for (j = 0; j < func->count(); j++) { + src_command = func->item(j); + dst_command = src_command->Clone(this); + AddressRange *address_range = src_command->address_range(); + if (address_range) { + FunctionInfo *info = function_info_list()->item(orig_function_info_count + func->function_info_list()->IndexOf(address_range->owner())); + dst_command->set_address_range(info->item(address_range->owner()->IndexOf(address_range))); + } + + AddObject(dst_command); + if (is_internal) { + if (j == 0) + internal_entry_list.push_back(dst_command); + if (dst_command->type() == cmRet && (dst_command->options() & roExternal) == 0) + dst_command->include_option(roInternal); + } + + src_link = src_command->link(); + if (src_link) { + dst_link = src_link->Clone(link_list()); + dst_link->set_from_command(dst_command); + link_list()->AddObject(dst_link); + + if (src_link->parent_command()) + dst_link->set_parent_command(GetCommandByAddress(src_link->parent_command()->address())); + } + + std::map::const_iterator it_import = runtime_info_list.find(dst_command->address()); + if (it_import != runtime_info_list.end()) { + if (dst_command->type() == cmCall) { + IntelOperand operand = dst_command->operand(0); + dst_command->Init(cmMov, IntelOperand(otRegistr, operand.size, regEAX), operand); + + command = new IntelCommand(this, cpu_address_size(), cmCall, IntelOperand(otRegistr, operand.size, regEAX)); + if (dst_command->link()) + dst_command->link()->set_from_command(command); + AddObject(command); + } + dst_link = dst_command->AddLink((dst_command->operand(1).type != otNone) ? 1 : 0, ltOffset); + std::vector::iterator it = std::find(import_function_info_list.begin(), import_function_info_list.end(), it_import->second); + if (it != import_function_info_list.end()) + dst_link->set_to_command(it->thunk); + } + + command = dst_command; + for (k = 0; k < 3; k++) { + IntelOperand operand = command->operand(k); + if (operand.type == otNone) + break; + + if ((operand.type & otValue) == 0) + continue; + + if ((operand.value & 0xFFFF0000) == 0xFACE0000) { + switch (static_cast(operand.value)) { + case FACE_LOADER_OPTIONS: + operand.value = 0; + if (ctx.options.flags & cpMemoryProtection) + operand.value |= LOADER_OPTION_CHECK_PATCH; + if (ctx.options.flags & cpCheckDebugger) + operand.value |= LOADER_OPTION_CHECK_DEBUGGER; + if (ctx.options.flags & cpCheckKernelDebugger) + operand.value |= LOADER_OPTION_CHECK_KERNEL_DEBUGGER; + if (ctx.options.flags & cpCheckVirtualMachine) + operand.value |= LOADER_OPTION_CHECK_VIRTUAL_MACHINE; + if (file->image_type() == itExe) + operand.value |= LOADER_OPTION_EXIT_PROCESS; + command->set_operand_value(k, operand.value); + command->CompileToNative(); + break; + case FACE_LOADER_DATA: + command->set_operand_value(k, loader_data_address - file->image_base()); + command->CompileToNative(); + break; + case FACE_RUNTIME_ENTRY: + command->set_operand_value(k, runtime->segment_list()->count() ? runtime->entry_point() - file->image_base() : 0); + command->CompileToNative(); + break; + case FACE_STRING_DECRYPT_KEY: + command->set_operand_value(k, string_key); + command->CompileToNative(); + break; + case FACE_PACKER_INFO: + case FACE_FILE_CRC_INFO: + case FACE_LOADER_CRC_INFO: + case FACE_SECTION_INFO: + case FACE_FIXUP_INFO: + case FACE_RELOCATION_INFO: + case FACE_IAT_INFO: + case FACE_IMPORT_INFO: + case FACE_INTERNAL_IMPORT_INFO: + case FACE_MEMORY_CRC_INFO: + case FACE_DELAY_IMPORT_INFO: + dst_command = loader_info_list[(operand.value & 0xff) >> 1].data; + if (dst_command) { + link = command->AddLink((int)k, ltOffset, dst_command); + link->set_sub_value(file->image_base()); + } else { + command->set_operand_value(k, 0); + command->CompileToNative(); + } + break; + case FACE_PACKER_INFO_SIZE: + case FACE_SECTION_INFO_SIZE: + case FACE_FIXUP_INFO_SIZE: + case FACE_RELOCATION_INFO_SIZE: + case FACE_IAT_INFO_SIZE: + case FACE_IMPORT_INFO_SIZE: + case FACE_INTERNAL_IMPORT_INFO_SIZE: + case FACE_MEMORY_CRC_INFO_SIZE: + case FACE_DELAY_IMPORT_INFO_SIZE: + command->set_operand_value(k, loader_info_list[(operand.value & 0xff) >> 1].size); + command->CompileToNative(); + break; + case FACE_LOADER_CRC_INFO_SIZE: + if (loader_crc_size_entry_) { + link = command->AddLink((int)k, ltOffset, loader_crc_size_entry_); + link->set_sub_value(file->image_base()); + } else { + command->set_operand_value(k, 0); + command->CompileToNative(); + } + break; + case FACE_LOADER_CRC_INFO_HASH: + if (loader_crc_hash_entry_) { + link = command->AddLink((int)k, ltOffset, loader_crc_hash_entry_); + link->set_sub_value(file->image_base()); + } else { + command->set_operand_value(k, 0); + command->CompileToNative(); + } + break; + case FACE_FILE_CRC_INFO_SIZE: + if (file_crc_size_entry_) { + link = command->AddLink((int)k, ltOffset, file_crc_size_entry_); + link->set_sub_value(file->image_base()); + } else { + command->set_operand_value(k, 0); + command->CompileToNative(); + } + break; + case FACE_MEMORY_CRC_INFO_HASH: + command->set_operand_value(k, intel_crc ? intel_crc->hash_entry()->operand(0).value : 0); + command->CompileToNative(); + break; + case FACE_CRC_INFO_SALT: + command->set_operand_value(k, file->function_list()->crc_cryptor()->item(0)->value()); + command->CompileToNative(); + break; + case FACE_IMAGE_BASE: + if (command->operand(0).size != cpu_address_size()) { + IntelOperand first = command->operand(0); + IntelOperand second = command->operand(1); + first.size = cpu_address_size(); + second.size = cpu_address_size(); + command->Init(static_cast(command->type()), first, second); + } + command->set_operand_value(k, file->image_base()); + command->set_operand_fixup(k, NEED_FIXUP); + command->CompileToNative(); + break; + case FACE_FILE_BASE: + if (command->operand(0).size != cpu_address_size()) { + IntelOperand first = command->operand(0); + IntelOperand second = command->operand(1); + first.size = cpu_address_size(); + second.size = cpu_address_size(); + command->Init(static_cast(command->type()), first, second); + } + command->set_operand_value(k, file->image_base()); + command->CompileToNative(); + break; + case FACE_TLS_INDEX_INFO: + command->set_operand_value(k, tls_index_address ? tls_index_address - file->image_base() : 0); + command->CompileToNative(); + break; + case FACE_VAR_IS_PATCH_DETECTED: + case FACE_VAR_IS_DEBUGGER_DETECTED: + case FACE_VAR_LOADER_CRC_INFO: + case FACE_VAR_LOADER_CRC_INFO_SIZE: + case FACE_VAR_LOADER_CRC_INFO_HASH: + case FACE_VAR_CPU_HASH: + case FACE_VAR_CPU_COUNT: + case FACE_VAR_SESSION_KEY: + case FACE_VAR_DRIVER_UNLOAD: + case FACE_VAR_CRC_IMAGE_SIZE: + case FACE_VAR_LOADER_STATUS: + case FACE_VAR_SERVER_DATE: + case FACE_VAR_OS_BUILD_NUMBER: + command->set_operand_value(k, ctx.runtime_var_index[(operand.value & 0xff) >> 4] * OperandSizeToValue(cpu_address_size())); + command->CompileToNative(); + break; + case FACE_VAR_IS_PATCH_DETECTED_SALT: + case FACE_VAR_IS_DEBUGGER_DETECTED_SALT: + case FACE_VAR_LOADER_CRC_INFO_SALT: + case FACE_VAR_LOADER_CRC_INFO_SIZE_SALT: + case FACE_VAR_LOADER_CRC_INFO_HASH_SALT: + case FACE_VAR_CPU_HASH_SALT: + case FACE_VAR_CPU_COUNT_SALT: + case FACE_VAR_DRIVER_UNLOAD_SALT: + case FACE_VAR_CRC_IMAGE_SIZE_SALT: + case FACE_VAR_SERVER_DATE_SALT: + case FACE_VAR_OS_BUILD_NUMBER_SALT: + command->set_operand_value(k, ctx.runtime_var_salt[operand.value & 0xff]); + command->CompileToNative(); + break; + default: + std::map::const_iterator it = loader_string_list.find(static_cast(operand.value)); + if (it != loader_string_list.end()) { + if (command->type() == cmMov) { + operand = command->operand(0); + operand.size = cpu_address_size(); + if (operand.type == otRegistr) { + command->Init(cmLea, operand, IntelOperand(otMemory | otValue, cpu_address_size(), 0, 0, (cpu_address_size() == osDWord) ? NEED_FIXUP : LARGE_VALUE)); + } else { + command->Init(cmMov, operand, IntelOperand(otValue, cpu_address_size(), 0, 0, NEED_FIXUP)); + } + } else { + command->Init(cmPush, IntelOperand(otValue, cpu_address_size(), 0, 0, NEED_FIXUP)); + } + command->AddLink((int)k, ltOffset, it->second); + } else { + throw std::runtime_error(string_format("Unknown loader string: %X", static_cast(operand.value))); + } + } + } + } + } + } + if (n == 0) { + // create native blocks + for (j = 0; j < count(); j++) { + item(j)->include_option(roNoProgress); + } + CompileToNative(ctx); + for (j = 0; j < count(); j++) { + item(j)->exclude_option(roNoProgress); + } + } + } + for (i = 0; i < function_info_list()->count(); i++) { + FunctionInfo *info = function_info_list()->item(i); + if (info->entry()) + info->set_entry(GetCommandByAddress(info->entry()->address())); + for (j = 0; j < info->count(); j++) { + AddressRange *dest = info->item(j); + for (k = 0; k < range_list()->count(); k++) { + AddressRange *range = range_list()->item(k); + if (range->begin() <= dest->begin() && range->end() > dest->begin()) + dest->AddLink(range); + } + } + } + for (i = 0; i < range_list()->count(); i++) { + AddressRange *range = range_list()->item(i); + if (range->begin_entry()) + range->set_begin_entry(GetCommandByAddress(range->begin_entry()->address())); + if (range->end_entry()) + range->set_end_entry(GetCommandByAddress(range->end_entry()->address())); + if (range->size_entry()) + range->set_size_entry(GetCommandByAddress(range->size_entry()->address())); + } + for (i = old_count; i < count(); i++) { + command = item(i); + dst_link = command->link(); + if (!dst_link) { + // search references to LoaderAlloc/LoaderFree/FreeImage + for (k = 0; k < 2; k++) { + IntelOperand operand = command->operand(k); + if (operand.type == otNone) + break; + + if (cpu_address_size() == osDWord) { + if (!operand.fixup) + continue; + } else { + if (!operand.is_large_value) + continue; + } + + dst_command = reinterpret_cast(GetCommandByAddress(operand.value)); + if (dst_command) { + dst_link = command->AddLink((int)k, dst_command->block() ? ltOffset : ltGateOffset, dst_command); + break; + } + } + } else { + if (dst_link->to_address()) + dst_link->set_to_command(GetCommandByAddress(dst_link->to_address())); + } + } + setup_image_entry = GetCommandByAddress(runtime->export_list()->GetAddressByType(atSetupImage)); + if (!setup_image_entry) + return false; + + free_image_entry = GetCommandByAddress(runtime->export_list()->GetAddressByType(atFreeImage)); + if (!free_image_entry) + return false; + +/* +BOOL LoaderDllMain(HANDLE module, DWORD reason, LPVOID reserved) +{ + BOOL status; + if (reason == DLL_PROCESS_ATTACH) { + status = SetupImage(); + if (status == TRUE) { + status = DllMain(module, reason, reserved); + } else { + FreeImage(); + } + } else { + status = DllMain(module, reason, reserved); + if (reason == DLL_PROCESS_DETACH) + FreeImage(); + } + return status; +} + +NTSTATUS LoaderDriverEntry(driver_object, registry_path) +{ + NTSTATUS status = SetupImage(true, driver_object); + if (status == STATUS_SUCCESS) { + status = DriverEntry(driver_object, registry_path); + if (status == STATUS_SUCCESS) { + SetupImage(false, driver_object); + } else { + FreeImage(driver_object); + } + } else { + FreeImage(driver_object); + } + return status; +} +*/ + + // create entry commands + std::vector end_command_list; + old_count = count(); + size_t stack = 0x20; + if (file->image_type() != itExe && cpu_address_size() == osQWord) { + AddCommand(cmMov, IntelOperand(otMemory | otRegistr | otValue, cpu_address_size(), regESP, OperandSizeToValue(cpu_address_size()) * 1), IntelOperand(otRegistr, cpu_address_size(), regECX)); + AddCommand(cmMov, IntelOperand(otMemory | otRegistr | otValue, cpu_address_size(), regESP, OperandSizeToValue(cpu_address_size()) * 2), IntelOperand(otRegistr, cpu_address_size(), regEDX)); + AddCommand(cmMov, IntelOperand(otMemory | otRegistr | otValue, cpu_address_size(), regESP, OperandSizeToValue(cpu_address_size()) * 3), IntelOperand(otRegistr, cpu_address_size(), regR8)); + } + AddCommand(cmPush, IntelOperand(otRegistr, cpu_address_size(), regEBP)); + if (cpu_address_size() == osDWord) { + AddCommand(cmSub, IntelOperand(otRegistr, cpu_address_size(), regESP), IntelOperand(otValue, cpu_address_size(), 0, stack)); + AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size(), regEBP), IntelOperand(otRegistr, cpu_address_size(), regESP)); + } else { + AddCommand(cmLea, IntelOperand(otRegistr, cpu_address_size(), regEBP), IntelOperand(otMemory | otRegistr| otValue, cpu_address_size(), regESP, 0 - static_cast(stack))); + AddCommand(cmSub, IntelOperand(otRegistr, cpu_address_size(), regESP), IntelOperand(otValue, cpu_address_size(), 0, stack + 0x20)); + } + + IntelCommand *skip_loader_command = NULL; + if (file->image_type() == itLibrary) { + // check DLL_PROCESS_ATTACH + AddCommand(cmCmp, IntelOperand(otMemory | otRegistr | otValue, osDWord, regEBP, stack + OperandSizeToValue(cpu_address_size()) * 3), IntelOperand(otValue, osDWord, 0, DLL_PROCESS_ATTACH)); + skip_loader_command = AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size())); + skip_loader_command->set_flags(fl_Z); + skip_loader_command->include_option(roInverseFlag); + skip_loader_command->AddLink(0, ltJmpWithFlag); + } + + // call SetupImage + if (file->image_type() == itDriver) { + if (cpu_address_size() == osQWord) { + AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size(), regEDX), IntelOperand(otMemory | otRegistr | otValue, cpu_address_size(), regEBP, stack + OperandSizeToValue(cpu_address_size()) * 2)); + AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regECX), IntelOperand(otValue, osDWord, 0, true)); + } else { + AddCommand(cmPush, IntelOperand(otMemory | otRegistr | otValue, cpu_address_size(), regEBP, stack + OperandSizeToValue(cpu_address_size()) * 2)); + AddCommand(cmPush, IntelOperand(otValue, cpu_address_size(), 0, true)); + } + } + command = AddCommand(cmCall, IntelOperand(otValue, cpu_address_size())); + command->AddLink(0, ltCall, setup_image_entry); + + // check loader error code + AddCommand(cmCmp, IntelOperand(otRegistr, osDWord, regEAX), IntelOperand(otValue, osDWord, 0, (file->image_type() == itDriver) ? 0 : TRUE)); + IntelCommand *check_loader_command = AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size())); + check_loader_command->set_flags(fl_Z); + check_loader_command->AddLink(0, ltJmpWithFlag); + + switch (file->image_type()) { + case itExe: + // call FreeImage + command = AddCommand(cmCall, IntelOperand(otValue, cpu_address_size())); + command->AddLink(0, ltCall, free_image_entry); + + // need convert FALSE into exit code + AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regEAX), IntelOperand(otValue, osDWord, 0, 0xDEADC0DE)); + break; + case itLibrary: + // do nothing + break; + case itDriver: + AddCommand(cmMov, IntelOperand(otMemory | otRegistr | otValue, cpu_address_size(), regEBP), IntelOperand(otRegistr, cpu_address_size(), regEAX)); + + // call FreeImage + if (cpu_address_size() == osQWord) { + AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size(), regECX), IntelOperand(otMemory | otRegistr | otValue, cpu_address_size(), regEBP, stack + OperandSizeToValue(cpu_address_size()) * 2)); + } else { + AddCommand(cmPush, IntelOperand(otMemory | otRegistr | otValue, cpu_address_size(), regEBP, stack + OperandSizeToValue(cpu_address_size()) * 2)); + } + command = AddCommand(cmCall, IntelOperand(otValue, cpu_address_size())); + command->AddLink(0, ltCall, free_image_entry); + + AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size(), regEAX), IntelOperand(otMemory | otRegistr | otValue, cpu_address_size(), regEBP)); + break; + } + + command = AddCommand(cmJmp, IntelOperand(otValue, cpu_address_size())); + command->AddLink(0, ltJmp); + end_command_list.push_back(command); + + command = AddCommand(cmNop); + check_loader_command->link()->set_to_command(command); + if (skip_loader_command) + skip_loader_command->link()->set_to_command(command); + + // call file EntryPoint + IntelCommand *jmp_entry_point_command = NULL; + if (file->entry_point()) { + switch (file->image_type()) { + case itExe: + AddCommand(cmAdd, IntelOperand(otRegistr, cpu_address_size(), regESP), IntelOperand(otValue, cpu_address_size(), 0, stack + ((cpu_address_size() == osQWord) ? 0x20 : 0))); + AddCommand(cmPop, IntelOperand(otRegistr, cpu_address_size(), regEBP)); + jmp_entry_point_command = AddCommand(cmJmp, IntelOperand(otValue, cpu_address_size(), 0, file->entry_point())); + jmp_entry_point_command->AddLink(0, ltJmp, file->entry_point()); + break; + + case itLibrary: + { + // check loader status + AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size(), regEAX), IntelOperand(otMemory | otValue, cpu_address_size(), 0, loader_data_address, (cpu_address_size() == osDWord) ? NEED_FIXUP : LARGE_VALUE)); + AddCommand(cmOr, IntelOperand(otRegistr, cpu_address_size(), regEAX), IntelOperand(otRegistr, cpu_address_size(), regEAX)); + IntelCommand *jmp_command = AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size())); + jmp_command->set_flags(fl_Z); + jmp_command->AddLink(0, ltJmpWithFlag); + + AddCommand(cmCmp, IntelOperand(otMemory | otRegistr | otValue, osDWord, regEAX, ctx.runtime_var_index[VAR_LOADER_STATUS] * OperandSizeToValue(cpu_address_size())), IntelOperand(otValue, osDWord, 0, TRUE)); + IntelCommand *jmp_status_command = AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size())); + jmp_status_command->set_flags(fl_Z); + jmp_status_command->include_option(roInverseFlag); + jmp_status_command->AddLink(0, ltJmpWithFlag); + + // call EntryPoint + if (cpu_address_size() == osQWord) { + AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size(), regR8), IntelOperand(otMemory | otRegistr | otValue, cpu_address_size(), regEBP, stack + OperandSizeToValue(cpu_address_size()) * 4)); + AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size(), regEDX), IntelOperand(otMemory | otRegistr | otValue, cpu_address_size(), regEBP, stack + OperandSizeToValue(cpu_address_size()) * 3)); + AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size(), regECX), IntelOperand(otMemory | otRegistr | otValue, cpu_address_size(), regEBP, stack + OperandSizeToValue(cpu_address_size()) * 2)); + } else { + AddCommand(cmPush, IntelOperand(otMemory | otRegistr | otValue, cpu_address_size(), regEBP, stack + OperandSizeToValue(cpu_address_size()) * 4)); + AddCommand(cmPush, IntelOperand(otMemory | otRegistr | otValue, cpu_address_size(), regEBP, stack + OperandSizeToValue(cpu_address_size()) * 3)); + AddCommand(cmPush, IntelOperand(otMemory | otRegistr | otValue, cpu_address_size(), regEBP, stack + OperandSizeToValue(cpu_address_size()) * 2)); + } + jmp_entry_point_command = AddCommand(cmCall, IntelOperand(otValue, cpu_address_size(), 0, file->entry_point())); + jmp_entry_point_command->AddLink(0, ltCall, file->entry_point()); + + command = AddCommand(cmNop); + jmp_command->link()->set_to_command(command); + jmp_status_command->link()->set_to_command(command); + } + break; + + case itDriver: + if (cpu_address_size() == osQWord) { + AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size(), regEDX), IntelOperand(otMemory | otRegistr | otValue, cpu_address_size(), regEBP, stack + OperandSizeToValue(cpu_address_size()) * 3)); + AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size(), regECX), IntelOperand(otMemory | otRegistr | otValue, cpu_address_size(), regEBP, stack + OperandSizeToValue(cpu_address_size()) * 2)); + } else { + AddCommand(cmPush, IntelOperand(otMemory | otRegistr | otValue, cpu_address_size(), regEBP, stack + OperandSizeToValue(cpu_address_size()) * 3)); + AddCommand(cmPush, IntelOperand(otMemory | otRegistr | otValue, cpu_address_size(), regEBP, stack + OperandSizeToValue(cpu_address_size()) * 2)); + } + jmp_entry_point_command = AddCommand(cmCall, IntelOperand(otValue, cpu_address_size(), 0, file->entry_point())); + jmp_entry_point_command->AddLink(0, ltCall, file->entry_point()); + + // store error code + AddCommand(cmMov, IntelOperand(otMemory | otRegistr | otValue, cpu_address_size(), regEBP), IntelOperand(otRegistr, cpu_address_size(), regEAX)); + + { + // check error code + AddCommand(cmCmp, IntelOperand(otRegistr, osDWord, regEAX), IntelOperand(otValue, osDWord, 0, 0)); + command = AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size())); + command->set_flags(fl_Z); + command->include_option(roInverseFlag); + command->AddLink(0, ltJmpWithFlag); + IntelCommand *cmp_command = command; + + // call SetupImage + if (cpu_address_size() == osQWord) { + AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size(), regEDX), IntelOperand(otMemory | otRegistr | otValue, cpu_address_size(), regEBP, stack + OperandSizeToValue(cpu_address_size()) * 2)); + AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regECX), IntelOperand(otValue, osDWord, 0, false)); + } else { + AddCommand(cmPush, IntelOperand(otMemory | otRegistr | otValue, cpu_address_size(), regEBP, stack + OperandSizeToValue(cpu_address_size()) * 2)); + AddCommand(cmPush, IntelOperand(otValue, cpu_address_size(), 0, false)); + } + command = AddCommand(cmCall, IntelOperand(otValue, cpu_address_size())); + command->AddLink(0, ltCall, setup_image_entry); + + IntelCommand *jmp_command = AddCommand(cmJmp, IntelOperand(otValue, cpu_address_size(), 0, 0)); + jmp_command->AddLink(0, ltJmp); + + command = AddCommand(cmNop); + cmp_command->link()->set_to_command(command); + + // call FreeImage + if (cpu_address_size() == osQWord) { + AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size(), regECX), IntelOperand(otMemory | otRegistr | otValue, cpu_address_size(), regEBP, stack + OperandSizeToValue(cpu_address_size()) * 2)); + } else { + AddCommand(cmPush, IntelOperand(otMemory | otRegistr | otValue, cpu_address_size(), regEBP, stack + OperandSizeToValue(cpu_address_size()) * 2)); + } + command = AddCommand(cmCall, IntelOperand(otValue, cpu_address_size())); + command->AddLink(0, ltCall, free_image_entry); + + // restore error code + command = AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size(), regEAX), IntelOperand(otMemory | otRegistr | otValue, cpu_address_size(), regEBP)); + jmp_command->link()->set_to_command(command); + } + break; + } + } + + if (file->image_type() == itLibrary) { + // check DLL_PROCESS_DETACH + AddCommand(cmCmp, IntelOperand(otMemory | otRegistr | otValue, osDWord, regEBP, stack + OperandSizeToValue(cpu_address_size()) * 3), IntelOperand(otValue, osDWord, 0, DLL_PROCESS_DETACH)); + command = AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size())); + command->set_flags(fl_Z); + command->include_option(roInverseFlag); + command->AddLink(0, ltJmpWithFlag); + end_command_list.push_back(command); + + // call FreeImage + command = AddCommand(cmCall, IntelOperand(otValue, cpu_address_size())); + command->AddLink(0, ltCall, free_image_entry); + + AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regEAX), IntelOperand(otValue, osDWord, 0, TRUE)); + } + + command = AddCommand(cmAdd, IntelOperand(otRegistr, cpu_address_size(), regESP), IntelOperand(otValue, cpu_address_size(), 0, stack + ((cpu_address_size() == osQWord) ? 0x20 : 0))); + for (i = 0; i < end_command_list.size(); i++) { + end_command_list[i]->link()->set_to_command(command); + } + AddCommand(cmPop, IntelOperand(otRegistr, cpu_address_size(), regEBP)); + + IntelOperand ret_operand; + if (cpu_address_size() == osDWord) { + switch (file->image_type()) { + case itDriver: + ret_operand = IntelOperand(otValue, osWord, 0, 2 * OperandSizeToValue(cpu_address_size())); + break; + case itLibrary: + ret_operand = IntelOperand(otValue, osWord, 0, 3 * OperandSizeToValue(cpu_address_size())); + break; + } + } + AddCommand(cmRet, ret_operand); + if (jmp_entry_point_command && entry_point_command) + jmp_entry_point_command->link()->set_to_command(entry_point_command); + + command = item(old_count); + set_entry(command); + + if (tls_call_back_entry_) { + index = count(); + + AddCommand(cmPush, IntelOperand(otRegistr, cpu_address_size(), regEBP)); + if (cpu_address_size() == osDWord) { + AddCommand(cmSub, IntelOperand(otRegistr, cpu_address_size(), regESP), IntelOperand(otValue, cpu_address_size(), 0, stack)); + AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size(), regEBP), IntelOperand(otRegistr, cpu_address_size(), regESP)); + } else { + AddCommand(cmLea, IntelOperand(otRegistr, cpu_address_size(), regEBP), IntelOperand(otMemory | otRegistr| otValue, cpu_address_size(), regESP, 0 - stack)); + AddCommand(cmSub, IntelOperand(otRegistr, cpu_address_size(), regESP), IntelOperand(otValue, cpu_address_size(), 0, stack + 0x20)); + } + + // call loader + command = AddCommand(cmCall, IntelOperand(otValue, cpu_address_size())); + command->AddLink(0, ltCall, setup_image_entry); + + // check loader error code + AddCommand(cmCmp, IntelOperand(otRegistr, osDWord, regEAX), IntelOperand(otValue, osDWord, 0, (file->image_type() == itDriver) ? 0 : TRUE)); + IntelCommand *check_loader_command = AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size())); + check_loader_command->set_flags(fl_Z); + check_loader_command->AddLink(0, ltJmpWithFlag); + + // call FreeImage + command = AddCommand(cmCall, IntelOperand(otValue, cpu_address_size())); + command->AddLink(0, ltCall, free_image_entry); + + command = AddCommand(cmNop); + check_loader_command->link()->set_to_command(command); + + AddCommand(cmAdd, IntelOperand(otRegistr, cpu_address_size(), regESP), IntelOperand(otValue, cpu_address_size(), 0, stack + ((cpu_address_size() == osQWord) ? 0x20 : 0))); + AddCommand(cmPop, IntelOperand(otRegistr, cpu_address_size(), regEBP)); + + IntelOperand ret_operand; + if (cpu_address_size() == osDWord) + ret_operand = IntelOperand(otValue, osWord, 0, 3 * OperandSizeToValue(cpu_address_size())); + AddCommand(cmRet, ret_operand); + + tls_call_back_entry_->link()->set_to_command(item(index)); + } + + for (i = 0; i < count(); i++) { + command = item(i); + command->CompileToNative(); + } + + // search API calls + for (i = 0; i < count(); i++) { + command = item(i); + if (command->block()) + continue; + + if (command->type() == cmCall) { + if (command->operand(0).type == otValue) + continue; + } else if (command->type() != cmSyscall) + continue; + + IntelCommand *next_command = item(i + 1); + if (next_command->type() == cmAdd && next_command->operand(0).type == otRegistr && next_command->operand(0).registr == regESP) + continue; + + k = 0; + for (j = i; j > 0; j--) { + IntelCommand *param_command = item(j - 1); + + switch (param_command->type()) { + case cmPush: + if (cpu_address_size() == osDWord) { + k++; + } else { + param_command = NULL; + } + break; + case cmMov: case cmLea: case cmXor: case cmMovsxd: + if (cpu_address_size() == osQWord) { + if (param_command->operand(0).type == otRegistr) { + switch (param_command->operand(0).registr) { + case regECX: + k = std::max(k, 1); + break; + case regEDX: + k = std::max(k, 2); + break; + case regR8: + k = std::max(k, 3); + break; + case regR9: + k = std::max(k, 4); + break; + } + } else if (param_command->operand(0).type == (otMemory | otBaseRegistr | otValue) && param_command->operand(0).base_registr == regESP) { + switch (param_command->operand(0).value) { + case 0x20: + k = std::max(k, 5); + break; + case 0x28: + k = std::max(k, 6); + break; + case 0x30: + k = std::max(k, 7); + break; + case 0x38: + k = std::max(k, 8); + break; + case 0x40: + k = std::max(k, 9); + break; + case 0x48: + k = std::max(k, 10); + break; + default: + if (param_command->operand(0).value >= 0x50) + k = NOT_ID; + break; + } + } + } + break; + case cmCall: case cmJmp: case cmJmpWithFlag: case cmRet: + param_command = NULL; + break; + } + if (!param_command || link_list()->GetLinkByToAddress(ltNone, param_command->address())) + break; + } + if (k == NOT_ID) + continue; + + command->include_option(roInternal); + command->set_operand_value(2, k); + } + + if (entry_point_command && entry_point_command->block()->virtual_machine() && jmp_entry_point_command) { + jmp_entry_point_command->include_option(roExternal); + uint8_t id = entry_point_command->block()->virtual_machine()->id(); + IntelVirtualMachineList *virtual_machine_list = reinterpret_cast(ctx.file->virtual_machine_list()); + for (i = 0; i < virtual_machine_list->count(); i++) { + IntelVirtualMachine *virtual_machine = virtual_machine_list->item(i); + if (virtual_machine->processor()->cpu_address_size() == cpu_address_size()) + virtual_machine->AddExtJmpCommand(id); + } + } + + for (i = 0; i < link_list()->count(); i++) { + CommandLink *link = link_list()->item(i); + if (link->from_command()->type() == cmCall && std::find(internal_entry_list.begin(), internal_entry_list.end(), link->to_command()) != internal_entry_list.end()) + reinterpret_cast(link->from_command())->include_option(roInternal); + link->from_command()->PrepareLink(ctx); + } + + return BaseIntelLoader::Prepare(ctx); +} + +std::vector PEIntelLoader::cfg_address_list() const +{ + std::vector res; + res.push_back(entry()->address()); + if (tls_call_back_entry_) + res.push_back(tls_call_back_entry_->link()->to_command()->address()); + std::sort(res.begin(), res.end()); + return res; +} + +/** + * MacIntelFunctionList + */ + +MacIntelFunctionList::MacIntelFunctionList(IArchitecture *owner) + : IntelFunctionList(owner) +{ + +} + +MacIntelFunctionList::MacIntelFunctionList(IArchitecture *owner, const MacIntelFunctionList &src) + : IntelFunctionList(owner, src) +{ + +} + +MacIntelFunctionList *MacIntelFunctionList::Clone(IArchitecture *owner) const +{ + MacIntelFunctionList *list = new MacIntelFunctionList(owner, *this); + return list; +} + +IntelSDK *MacIntelFunctionList::AddSDK(OperandSize cpu_address_size) +{ + IntelSDK *func = new MacIntelSDK(this, cpu_address_size); + AddObject(func); + return func; +} + +bool MacIntelFunctionList::Prepare(const CompileContext &ctx) +{ + MacArchitecture *file = reinterpret_cast(owner()); + for (size_t i = 0; i < file->import_list()->count(); i++) { + MacImport *import = file->import_list()->item(i); + size_t old_count = import->count(); + for (size_t j = 0; j < old_count; j++) { + MacImportFunction *import_func = import->item(j); + IntelCommand *command = reinterpret_cast(GetCommandByAddress(import_func->address(), true)); + if (!command) + continue; + + import_func = import_func->Clone(import); + import->AddObject(import_func); + relocation_list_[import_func] = command; + } + } + + return IntelFunctionList::Prepare(ctx); +} + +bool MacIntelFunctionList::Compile(const CompileContext &ctx) +{ + if (!IntelFunctionList::Compile(ctx)) + return false; + + MacArchitecture *file = reinterpret_cast(owner()); + for (std::map::const_iterator it = relocation_list_.begin(); it != relocation_list_.end(); it++) { + MacImportFunction *import_func = it->first; + IntelCommand *command = it->second; + import_func->set_address(command->address()); + } + + return true; +} + +/** + * MacIntelSDK + */ + +MacIntelSDK::MacIntelSDK(IFunctionList *parent, OperandSize cpu_address_size) + : IntelSDK(parent, cpu_address_size) +{ + +} + +/** + * MacIntelLoader + */ + +MacIntelLoader::MacIntelLoader(IntelFunctionList *owner, OperandSize cpu_address_size) + : BaseIntelLoader(owner, cpu_address_size), import_entry_(NULL), import_size_(0), + jmp_table_entry_(NULL), jmp_table_size_(0), init_entry_(NULL), init_size_(0), term_entry_(NULL), term_size_(0), + file_crc_entry_(NULL), file_crc_size_(0), loader_crc_entry_(NULL), loader_crc_size_(0), file_entry_(NULL), + patch_section_entry_(NULL), loader_crc_size_entry_(NULL), loader_crc_hash_entry_(NULL), file_crc_size_entry_(NULL), + lazy_import_entry_(NULL), lazy_import_size_(0), thread_variables_entry_(NULL), thread_variables_size_(0), + thread_data_entry_(NULL), thread_data_size_(0) +{ + +} + +bool MacIntelLoader::Prepare(const CompileContext &ctx) +{ + MacArchitecture *file, *runtime; + size_t i, j, k, index, orig_dll_count, old_count, start_index; + IntelCommand *command, *src_command, *dst_command, *setup_image_entry, *free_image_entry; + CommandLink *link, *src_link, *dst_link; + IntelFunctionList *runtime_function_list; + IntelFunction *func; + MacImportFunction *import_function; + MacImport *import; + uint64_t address; + std::map runtime_info_list; + uint64_t loader_data_address; + MacSegment *segment; + + file = reinterpret_cast(ctx.file); + runtime = reinterpret_cast(ctx.runtime); + IntelCRCTable *intel_crc = reinterpret_cast(file->function_list())->crc_table(); + IntelLoaderData *loader_data = reinterpret_cast(file->function_list())->loader_data(); + loader_data_address = (loader_data) ? loader_data->entry()->address() : runtime->export_list()->GetAddressByType(atLoaderData); + if (!loader_data_address) + return false; + + // create AV signature buffer + AddAVBuffer(ctx); + start_index = count(); + + ICommand *entry_point_command = NULL; + if (file->entry_point()) { + IFunction *entry_point_func = ctx.file->function_list()->GetFunctionByAddress(file->entry_point()); + if (entry_point_func) + entry_point_command = entry_point_func->entry(); + } + + segment = file->segment_list()->GetBaseSegment(); + uint64_t max_header_address = segment ? segment->address() + file->max_header_size() : 0; + + // parse objc segment + Objc objc; + std::vector objc_segment_list; + if (objc.ReadFromFile(*file)) { + objc_segment_list = objc.segment_list(); + for (i = 0; i < file->import_list()->count(); i++) { + import = file->import_list()->item(i); + for (j = 0; j < import->count(); j++) { + import_function = import->item(j); + MacSection *section = file->section_list()->GetSectionByAddress(import_function->address()); + if (section && find(objc_segment_list.begin(), objc_segment_list.end(), section->parent()) != objc_segment_list.end() && section->type() != S_NON_LAZY_SYMBOL_POINTERS) + import_function->include_option(ioHasDirectReference); + } + } + } + + // add loader import + std::map import_map; + MacImportList &new_import_list = *file->import_list(); + orig_dll_count = new_import_list.count(); + runtime_function_list = reinterpret_cast(runtime->function_list()); + IntelCommandType value_command_type = (cpu_address_size() == osDWord) ? cmDD : cmDQ; + index = count(); + int max_library_ordinal = 0; + for (i = 0; i < new_import_list.count(); i++) { + import = new_import_list.item(i); + if (max_library_ordinal < import->library_ordinal()) + max_library_ordinal = import->library_ordinal(); + } + for (i = 0; i < runtime_function_list->count(); i++) { + func = runtime_function_list->item(i); + if (func->tag() != ftLoader) + continue; + + for (j = 0; j < func->count(); j++) { + command = func->item(j); + import_function = NULL; + switch (command->type()) { + case cmCall: + case cmJmp: + case cmMov: + k = (command->type() == cmMov) ? 1 : 0; + if (command->operand(k).type == (otMemory | otValue)) + import_function = runtime->import_list()->GetFunctionByAddress(command->operand(k).value); + break; + } + if (!import_function) + continue; + + std::map::const_iterator it = import_map.find(import_function->address()); + MacImportFunction *new_import_function = (it != import_map.end()) ? it->second : NULL; + if (!new_import_function) { + MacImport *src_import = reinterpret_cast(import_function->owner()); + import = new_import_list.GetImportByName(src_import->name()); + if (!import) { + import = new MacImport(&new_import_list, ++max_library_ordinal, src_import->name(), src_import->current_version(), src_import->compatibility_version()); + new_import_list.AddObject(import); + } + + MacSymbol *symbol = import_function->symbol()->Clone(file->symbol_list()); + file->symbol_list()->AddObject(symbol); + symbol->set_library_ordinal(import->library_ordinal()); + + new_import_function = import->Add(0, BIND_TYPE_POINTER, 0, import_function->name(), 0, 0, false, symbol); + import_map[import_function->address()] = new_import_function; + } + runtime_info_list[command->address()] = new_import_function; + } + } + + // create IAT + old_count = file->indirect_symbol_list()->count(); + for (i = 0; i < file->import_list()->count(); i++) { + import = file->import_list()->item(i); + for (j = 0; j < import->count(); j++) { + import_function = import->item(j); + if (import_function->is_lazy() || (import_function->options() & ioHasDirectReference)) + continue; + + bool is_found = false; + if (import_function->address()) { + for (k = 0; k < old_count; k++) { + MacIndirectSymbol *indirect_symbol = file->indirect_symbol_list()->item(k); + if (indirect_symbol->symbol() == import_function->symbol()) { + file->indirect_symbol_list()->AddObject(indirect_symbol->Clone(file->indirect_symbol_list())); + indirect_symbol->set_symbol(NULL); + indirect_symbol->set_value(INDIRECT_SYMBOL_ABS); + is_found = true; + break; + } + } + } + if (!is_found) + file->indirect_symbol_list()->Add(0, 0, import_function->symbol()); + + command = AddCommand(value_command_type, IntelOperand(otValue, cpu_address_size())); + import_function_info_[import_function] = command; + } + } + import_entry_ = item(start_index); + import_entry_->set_operand_value(1, old_count); + import_entry_->include_option(roCreateNewBlock); + import_entry_->include_option(roDataSegment); + import_entry_->set_alignment(OperandSizeToValue(cpu_address_size())); + import_size_ = static_cast((count() - start_index) * OperandSizeToValue(cpu_address_size())); + + // create jump table + jmp_table_entry_ = NULL; + jmp_table_size_ = 0; + lazy_import_entry_ = NULL; + lazy_import_size_ = 0; + std::vector jmp_import_list; + bool need_convert_runtime = (runtime->segment_list()->count() && !file->dyld_info()->cmd); + for (i = 0; i < file->import_list()->count(); i++) { + import = file->import_list()->item(i); + for (j = 0; j < import->count(); j++) { + import_function = import->item(j); + if (import_function->options() & ioFromRuntime) { + if (!need_convert_runtime || !import_function->is_lazy()) + continue; + } else { + if ((import_function->options() & ioIsRelative) == 0) + continue; + } + + jmp_import_list.push_back(import_function); + } + } + if (!jmp_import_list.empty()) { + index = count(); + size_t indirect_symbol_index = file->indirect_symbol_list()->count(); + address = ctx.manager->Alloc(jmp_import_list.size() * (cpu_address_size() == osDWord ? 5 : 6), mtReadable); + + CommandBlock *block = AddBlock(count(), true); + block->set_address(address); + + for (i = 0; i < jmp_import_list.size(); i++) { + import_function = jmp_import_list[i]; + + file->indirect_symbol_list()->Add(0, 0, import_function->symbol()); + + if (cpu_address_size() == osDWord) { + command = AddCommand(cmJmp, IntelOperand(otValue, osDWord)); + command->CompileToNative(); + command->AddLink(0, ltJmp); + } + else { + command = AddCommand(cmJmp, IntelOperand(otMemory | otValue, osQWord, 0, 0, LARGE_VALUE)); + command->CompileToNative(); + command->AddLink(0, ltOffset); + } + command->set_address(address); + command->set_block(block); + + Data jmp; + if (import_function->options() & ioIsRelative) { + // jmp xxxx + jmp.PushByte(0xe9); + jmp.PushDWord(static_cast(address - import_function->address() - 5)); + } else { + // dd xxxx + if (cpu_address_size() == osQWord) + jmp.PushQWord(address); + else + jmp.PushDWord(static_cast(address)); + + segment = file->segment_list()->GetSectionByAddress(import_function->address()); + MacFixup *fixup = file->fixup_list()->AddDefault(cpu_address_size(), segment && (segment->memory_type() & mtExecutable) != 0); + fixup->set_address(import_function->address()); + } + + file->AddressSeek(import_function->address()); + file->Write(jmp.data(), jmp.size()); + + address += command->dump_size(); + } + block->set_end_index(count() - 1); + + if (cpu_address_size() == osDWord) { + old_count = count(); + Data data; + data.resize(5, 0xf4); + for (i = 0; i < jmp_import_list.size(); i++) { + command = AddCommand(data); + item(index + i)->link()->set_to_command(command); + } + + jmp_table_entry_ = item(old_count); + jmp_table_entry_->set_operand_value(1, indirect_symbol_index); + jmp_table_entry_->include_option(roCreateNewBlock); + jmp_table_entry_->include_option(roImportSegment); + jmp_table_size_ = static_cast(jmp_import_list.size() * data.size()); + } else { + old_count = count(); + for (i = 0; i < jmp_import_list.size(); i++) { + command = AddCommand(value_command_type, IntelOperand(otValue, cpu_address_size(), 0, 0, NEED_FIXUP)); + command->AddLink(0, ltOffset); + item(index + i)->link()->set_to_command(command); + } + + lazy_import_entry_ = item(old_count); + lazy_import_entry_->set_operand_value(1, indirect_symbol_index); + lazy_import_entry_->include_option(roCreateNewBlock); + lazy_import_entry_->include_option(roDataSegment); + lazy_import_entry_->set_alignment(OperandSizeToValue(cpu_address_size())); + lazy_import_size_ = static_cast(jmp_import_list.size() * OperandSizeToValue(cpu_address_size())); + + address = 0; + MacSegment *data_segment = file->segment_list()->GetSectionByName(SEG_DATA); + if (data_segment) { + MacSection *section = file->section_list()->GetSectionByName(data_segment, SECT_DYLD); + if (section) + address = section->address(); + } + if (!address) + throw std::runtime_error("Section \"__dyld\" not found"); + + IntelCommand *dyld_entry = AddCommand(cmPush, IntelOperand(otRegistr, osQWord, regR11, 0)); + AddCommand(cmLea, IntelOperand(otRegistr, osQWord, regR11, 0), IntelOperand(otMemory | otValue, osQWord, 0, file->image_base(), LARGE_VALUE)); + AddCommand(cmPush, IntelOperand(otRegistr, osQWord, regR11, 0)); + AddCommand(cmJmp, IntelOperand(otMemory | otValue, osQWord, 0, address, LARGE_VALUE)); + + index = old_count; + old_count = count(); + for (i = 0; i < jmp_import_list.size(); i++) { + command = AddCommand(cmLea, IntelOperand(otRegistr, osQWord, regR11, 0), IntelOperand(otMemory | otValue, osQWord, 0, 0, LARGE_VALUE)); + command->AddLink(1, ltOffset, item(index + i)); + item(index + i)->link()->set_to_command(command); + command = AddCommand(cmJmp, IntelOperand(otValue, osQWord, 0, 0)); + command->AddLink(0, ltJmp, dyld_entry); + } + } + } + else { + for (i = 0; i < file->import_list()->count(); i++) { + import = file->import_list()->item(i); + for (j = 0; j < import->count(); j++) { + import_function = import->item(j); + if ((import_function->options() & ioFromRuntime) && import_function->is_lazy()) + jmp_import_list.push_back(import_function); + } + } + if (!jmp_import_list.empty()) { + // move S_LAZY_SYMBOL_POINTERS to data segment + std::vector address_list; + index = count(); + size_t indirect_symbol_index = file->indirect_symbol_list()->count(); + address = ctx.manager->Alloc(jmp_import_list.size() * (cpu_address_size() == osDWord ? 5 : 6), mtReadable); + + CommandBlock *block = AddBlock(count(), true); + block->set_address(address); + + for (i = 0; i < jmp_import_list.size(); i++) { + import_function = jmp_import_list[i]; + + file->indirect_symbol_list()->Add(0, 0, import_function->symbol()); + + if (cpu_address_size() == osDWord) { + command = AddCommand(cmJmp, IntelOperand(otValue, osDWord)); + command->CompileToNative(); + command->AddLink(0, ltJmp); + } + else { + command = AddCommand(cmJmp, IntelOperand(otMemory | otValue, cpu_address_size(), 0, 0, LARGE_VALUE)); + command->CompileToNative(); + command->AddLink(0, ltOffset); + } + + command->set_address(address); + command->set_block(block); + + file->AddressSeek(import_function->address()); + if (cpu_address_size() == osDWord) { + address_list.push_back(file->ReadDWord()); + file->AddressSeek(import_function->address()); + file->WriteDWord(static_cast(address)); + } + else { + address_list.push_back(file->ReadQWord()); + file->AddressSeek(import_function->address()); + file->WriteQWord(address); + } + + address += command->dump_size(); + } + block->set_end_index(count() - 1); + + if (cpu_address_size() == osDWord) { + old_count = count(); + for (i = 0; i < jmp_import_list.size(); i++) { + command = AddCommand(cmJmp, IntelOperand(otMemory | otValue, cpu_address_size(), 0, 0, NEED_FIXUP)); + command->CompileToNative(); + command->AddLink(0, ltOffset); + item(index + i)->link()->set_to_command(command); + } + index = old_count; + } + + old_count = count(); + for (i = 0; i < jmp_import_list.size(); i++) { + import_function = jmp_import_list[i]; + command = AddCommand(value_command_type, IntelOperand(otValue, cpu_address_size(), 0, address_list[i], NEED_FIXUP)); + item(index + i)->link()->set_to_command(command); + + import_function->set_address(0); + import_function_info_[import_function] = command; + } + + lazy_import_entry_ = item(old_count); + lazy_import_entry_->set_operand_value(1, indirect_symbol_index); + lazy_import_entry_->include_option(roCreateNewBlock); + lazy_import_entry_->include_option(roDataSegment); + lazy_import_entry_->set_alignment(OperandSizeToValue(cpu_address_size())); + lazy_import_size_ = static_cast(jmp_import_list.size() * OperandSizeToValue(cpu_address_size())); + } + } + + // create init module function list + index = count(); + AddCommand(value_command_type, IntelOperand(otValue, cpu_address_size(), 0, 0, NEED_FIXUP)); + for (i = 0; i < file->section_list()->count(); i++) { + MacSection *section = file->section_list()->item(i); + if (section->type() != S_MOD_INIT_FUNC_POINTERS) + continue; + + file->AddressSeek(section->address()); + for (j = 0; j < section->size(); j += OperandSizeToValue(cpu_address_size())) { + command = Add(section->address() + j); + command->ReadValueFromFile(*file, cpu_address_size()); + } + } + init_entry_ = item(index); + init_entry_->include_option(roCreateNewBlock); + init_entry_->include_option(roDataSegment); + init_entry_->set_alignment(OperandSizeToValue(cpu_address_size())); + init_size_ = static_cast((count() - index) * OperandSizeToValue(cpu_address_size())); + + // work around MacOSX >= 10.13 - init function must be point within __TEXT segment + if (max_header_address) { + max_header_address -= 5; + CommandBlock *block = AddBlock(count(), true); + block->set_address(max_header_address); + command = AddCommand(cmJmp, IntelOperand(otValue, cpu_address_size(), 0, 0)); + command->set_address(max_header_address); + command->set_block(block); + init_entry_->AddLink(0, ltOffset, command); + } + + // create termination module function list + index = count(); + AddCommand(value_command_type, IntelOperand(otValue, cpu_address_size(), 0, 0, NEED_FIXUP)); + for (i = 0; i < file->section_list()->count(); i++) { + MacSection *section = file->section_list()->item(i); + if (section->type() != S_MOD_TERM_FUNC_POINTERS) + continue; + + file->AddressSeek(section->address()); + for (j = 0; j < section->size(); j += OperandSizeToValue(cpu_address_size())) { + command = Add(section->address() + j); + command->ReadValueFromFile(*file, cpu_address_size()); + } + } + term_entry_ = item(index); + term_entry_->include_option(roCreateNewBlock); + term_entry_->include_option(roDataSegment); + term_entry_->set_alignment(OperandSizeToValue(cpu_address_size())); + term_entry_->AddLink(0, ltGateOffset); + term_size_ = (uint32_t)((count() - index) * OperandSizeToValue(cpu_address_size())); + + // create S_THREAD_LOCAL_VARIABLES section + index = count(); + if (file->flags() & MH_HAS_TLV_DESCRIPTORS) { + for (i = 0; i < file->section_list()->count(); i++) { + MacSection *section = file->section_list()->item(i); + if (section->type() != S_THREAD_LOCAL_VARIABLES) + continue; + + if ((ctx.options.flags & cpPack) && !section->parent()->excluded_from_packing()) { + file->AddressSeek(section->address()); + for (j = 0; j < section->size(); j += OperandSizeToValue(cpu_address_size())) { + command = Add(section->address() + j); + command->ReadValueFromFile(*file, cpu_address_size()); + if (j == 0) + command->set_operand_value(1, section->size()); + } + } + else { + for (j = 0; j < section->size(); j += OperandSizeToValue(cpu_address_size())) { + import_function = file->import_list()->GetFunctionByAddress(section->address() + j); + if (import_function) { + std::map::const_iterator it = import_function_info_.find(import_function); + if (it != import_function_info_.end()) + import_function_info_.erase(it); + } + } + } + } + } + thread_variables_entry_ = (count() == index) ? NULL : item(index); + thread_variables_size_ = (uint32_t)((count() - index) * OperandSizeToValue(cpu_address_size())); + if (thread_variables_entry_) { + thread_variables_entry_->include_option(roCreateNewBlock); + thread_variables_entry_->include_option(roDataSegment); + thread_variables_entry_->set_alignment(OperandSizeToValue(cpu_address_size())); + } + + // create S_THREAD_LOCAL_REGULAR section + index = count(); + if (ctx.options.flags & cpPack) { + address = 0; + uint64_t end_address = 0; + for (i = 0; i < file->section_list()->count(); i++) { + MacSection *section = file->section_list()->item(i); + if (section->type() == S_THREAD_LOCAL_REGULAR || section->type() == S_THREAD_LOCAL_ZEROFILL) { + if (!address) + address = section->address(); + end_address = section->address() + section->size(); + } + } + if (address) { + segment = file->segment_list()->GetSectionByAddress(address); + if (segment && !segment->excluded_from_packing()) { + uint32_t size = static_cast(end_address - address); + uint32_t physical_size = std::min(static_cast(segment->address() + segment->physical_size() - address), size); + if (physical_size) { + file->AddressSeek(address); + Data data; + data.resize(size); + file->Read(&data[0], physical_size); + AddCommand(data); + } + } + } + } + thread_data_entry_ = (count() == index) ? NULL : item(index); + thread_data_size_ = 0; + if (thread_data_entry_) { + for (i = index; i < count(); i++) { + thread_data_size_ += static_cast(item(i)->dump_size()); + } + thread_data_entry_->include_option(roCreateNewBlock); + thread_data_entry_->include_option(roDataSegment); + thread_data_entry_->set_alignment(OperandSizeToValue(cpu_address_size())); + } + + // create watermarks + AddWatermark(ctx.options.watermark, 2); + + // create segment list for setting WRITABLE flag + std::vector writable_segment_list; + std::vector packer_info_list; + MacFixupList loader_fixup_list; + segment = file->segment_list()->GetSectionByAddress(loader_data_address); + if (segment) + writable_segment_list.push_back(segment); + + if ((file->runtime_functions_section() && file->runtime_functions_section()->name() == SECT_EH_FRAME) || file->unwind_info_section()) { + segment = file->segment_list()->GetBaseSegment(); + if (segment) + writable_segment_list.push_back(segment); + } + + // parse objc load methods + std::vector load_command_list; + if (!objc_segment_list.empty()) { + size_t value_size = OperandSizeToValue(file->cpu_address_size()); + std::set address_list; + objc.GetLoadMethodReferences(address_list); + for (std::set::const_iterator it = address_list.begin(); it != address_list.end(); it++) { + if (!file->AddressSeek(*it)) + continue; + + uint64_t pos = file->Tell(); + uint64_t value = 0; + file->Read(&value, value_size); + + CommandBlock *block = AddBlock(count(), true); + + command = AddCommand(cmJmp, IntelOperand(otValue, cpu_address_size(), 0, 0)); + command->AddLink(0, ltGateOffset); + command->set_operand_value(1, value); + command->set_block(block); + command->CompileToNative(); + + address = ctx.manager->Alloc(command->dump_size(), mtReadable); + block->set_address(address); + command->set_address(address); + + value = address; + file->Seek(pos); + file->Write(&value, value_size); + + load_command_list.push_back(command); + } + } + + IntelCommand *packer_props = NULL; + if (ctx.options.flags & cpPack) { + std::set skip_segment_list; + for (i = 0; i < objc_segment_list.size(); i++) { + skip_segment_list.insert(objc_segment_list[i]); + } + MacSegment *data_segment = file->segment_list()->GetSectionByName(SEG_DATA); + if (data_segment) { + // skip sections with vars + if (file->section_list()->GetSectionByName(data_segment, SECT_DYLD) || + file->section_list()->GetSectionByName(data_segment, SECT_PROGRAM_VARS)) { + skip_segment_list.insert(data_segment); + } + } + + PackerInfo packer_info; + for (i = 0; i < file->segment_list()->count(); i++) { + segment = file->segment_list()->item(i); + if (segment->excluded_from_packing()) + continue; + + bool can_be_packed = true; + if ((segment->memory_type() & (mtWritable | mtShared)) == (mtWritable | mtShared)) { + can_be_packed = false; + } else if (skip_segment_list.find(segment) != skip_segment_list.end()) { + can_be_packed = false; + } + + if (!can_be_packed) { + //file->Notify(mtWarning, NULL, string_format(language[lsSegmentCanNotBePacked].c_str(), segment->name().c_str())); + continue; + } + + if (segment->physical_size()) { + packer_info = PackerInfo(segment, segment->address(), static_cast(segment->physical_size())); + + if (segment == data_segment) { + ISection *section = file->section_list()->GetSectionByName(data_segment, SECT_DYLD); + if (section && section->address() + section->size() >= packer_info.address) { + size_t delta = static_cast(section->address() + section->size() - packer_info.address); + packer_info.address += delta; + if (packer_info.size > delta) { + packer_info.size -= delta; + } else { + packer_info.size = 0; + } + } + } else if (segment == file->header_segment()) { + size_t delta = file->max_header_size(); + packer_info.address += delta; + if (packer_info.size > delta) { + packer_info.size -= delta; + } else { + packer_info.size = 0; + } + } + + if (!packer_info.size) + continue; + + packer_info_list.push_back(packer_info); + packed_segment_list_.push_back(segment); + + // need add packed section into WRITABLE section list + if (std::find(writable_segment_list.begin(), writable_segment_list.end(), segment) == writable_segment_list.end()) + writable_segment_list.push_back(segment); + } + } + + // parse objc structures + if (!objc_segment_list.empty()) { + size_t value_size = OperandSizeToValue(file->cpu_address_size()); + std::set address_list; + objc.GetStringReferences(address_list); + for (i = 0; i < file->section_list()->count(); i++) { + MacSection *section = file->section_list()->item(i); + if (find(objc_segment_list.begin(), objc_segment_list.end(), section->parent()) != objc_segment_list.end()) { + switch (section->type()) { + case S_LITERAL_POINTERS: + for (j = 0; j < section->size(); j += value_size) { + address_list.insert(section->address() + j); + } + break; + } + } + } + + index = count(); + for (std::set::const_iterator it = address_list.begin(); it != address_list.end(); it++) { + if (!file->AddressSeek(*it)) + continue; + + // move strings to loader segment + uint64_t pos = file->Tell(); + uint64_t value = 0; + file->Read(&value, value_size); + segment = file->segment_list()->GetSectionByAddress(value); + if (!segment || std::find(packer_info_list.begin(), packer_info_list.end(), segment) == packer_info_list.end()) + continue; + + command = NULL; + for (i = index; i < count(); i++) { + if (item(i)->operand(0).value == value) { + command = item(i); + break; + } + } + if (!command) { + file->AddressSeek(value); + std::string str = file->ReadString(); + + CommandBlock *block = AddBlock(count(), true); + + command = AddCommand(str); + command->set_block(block); + command->set_operand_value(0, value); + + address = ctx.manager->Alloc(command->dump_size(), mtReadable); + block->set_address(address); + command->set_address(address); + } + + file->Seek(pos); + value = command->address(); + file->Write(&value, value_size); + } + } + + // packing sections + j = 0; + for (i = 0; i < packer_info_list.size(); i++) { + j += packer_info_list[i].size; + } + file->StartProgress(string_format("%s...", language[lsPacking].c_str()), j); + + Data data; + Packer packer; + + if (!packer.WriteProps(&data)) + throw std::runtime_error("Packer error"); + packer_props = AddCommand(data); + packer_props->include_option(roCreateNewBlock); + + for (i = 0; i < packer_info_list.size(); i++) { + packer_info = packer_info_list[i]; + if (!file->AddressSeek(packer_info.address)) + return false; + + if (!packer.Code(file, packer_info.size, &data)) + throw std::runtime_error("Packer error"); + + command = AddCommand(data); + command->include_option(roCreateNewBlock); + packer_info_list[i].data = command; + } + + // remove packed sections from file + uint32_t physical_offset = 0; + for (i = 0; i < file->segment_list()->count(); i++) { + segment = file->segment_list()->item(i); + uint32_t physical_size = segment->physical_size(); + bool is_packed = false; + std::vector::iterator it = std::find(packer_info_list.begin(), packer_info_list.end(), segment); + if (it != packer_info_list.end()) { + physical_size = static_cast(it->address - segment->address()); + is_packed = true; + if (segment == file->header_segment() && file->file_type() == MH_DYLIB) { + file->Seek(physical_size); + j = physical_size; + physical_size = AlignValue(physical_size, file->segment_alignment()); + for (k = j; k < physical_size; k++) { + file->WriteByte(0); + } + } + } + if (segment->physical_offset() != physical_offset) { + size_t delta = static_cast(physical_offset - segment->physical_offset()); + for (j = 0; j < file->section_list()->count(); j++) { + MacSection *section = file->section_list()->item(j); + if (section->parent() == segment && section->physical_offset()) + section->set_physical_offset(static_cast(section->physical_offset() + delta)); + } + } + + if (physical_size > 0 && segment->physical_offset() != physical_offset) { + uint8_t *buff = new uint8_t[physical_size]; + file->Seek(segment->physical_offset()); + file->Read(buff, physical_size); + file->Seek(physical_offset); + file->Write(buff, physical_size); + delete [] buff; + } + + segment->set_physical_offset(physical_offset); + segment->set_physical_size(physical_size); + + if (is_packed) { + j = physical_offset + physical_size; + file->Seek(j); + physical_offset = (uint32_t)AlignValue(j, file->file_alignment()); + if (!physical_size && j == physical_offset) + physical_offset += file->file_alignment(); + for (k = j; k < physical_offset; k++) { + file->WriteByte(0); + } + } else { + physical_offset += physical_size; + } + } + file->Resize(physical_offset); + } + + for (i = 0; i < file->fixup_list()->count(); i++) { + MacFixup *fixup = file->fixup_list()->item(i); + if (fixup->is_deleted()) + continue; + + segment = file->segment_list()->GetSectionByAddress(fixup->address()); + if (!segment) + continue; + + if (std::find(packer_info_list.begin(), packer_info_list.end(), segment) == packer_info_list.end()) { + if ((segment->memory_type() & (mtExecutable | mtWritable)) != mtExecutable || segment->name() == SEG_TEXT) + continue; + } + + if (fixup->symbol()) { + // external relocation + // FIXME + continue; + command = AddCommand(value_command_type, IntelOperand(otValue, cpu_address_size())); //-V779 + relocation_info_[fixup] = command; + } + else { + // local relocation + if (ctx.options.flags & cpStripFixups) + continue; + + loader_fixup_list.AddObject(fixup->Clone(&loader_fixup_list)); + fixup->set_deleted(true); + } + + // need add section into WRITABLE section list + if (std::find(writable_segment_list.begin(), writable_segment_list.end(), segment) == writable_segment_list.end()) + writable_segment_list.push_back(segment); + } + + // create packer info for loader + std::vector loader_info_list; + index = count(); + if (packer_props) { + command = AddCommand(cmDD, IntelOperand(otValue, osDWord)); + link = command->AddLink(0, ltOffset, packer_props); + link->set_sub_value(file->image_base()); + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, packer_props->dump_size())); + + for (i = 0; i < packer_info_list.size(); i++) { + command = AddCommand(cmDD, IntelOperand(otValue, osDWord)); + link = command->AddLink(0, ltOffset, packer_info_list[i].data); + link->set_sub_value(file->image_base()); + + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, packer_info_list[i].address - file->image_base())); + } + } + command = (count() == index) ? NULL : item(index); + if (command) + command->include_option(roCreateNewBlock); + loader_info_list.push_back(LoaderInfo(command, (count() - index) * OperandSizeToValue(osDWord))); + + // create file CRC info for loader + index = count(); + if ((ctx.options.flags | ctx.options.sdk_flags) & cpMemoryProtection) { + AddCommand(cmDD, IntelOperand(otValue, osDWord)); + for (i = 0; i < 4; i++) { + AddCommand(cmDD, IntelOperand(otValue, osDWord)); + AddCommand(cmDD, IntelOperand(otValue, osDWord)); + AddCommand(cmDD, IntelOperand(otValue, osDWord)); + } + } + file_crc_entry_ = (count() == index) ? NULL : item(index); + if (file_crc_entry_) + file_crc_entry_->include_option(roCreateNewBlock); + file_crc_size_ = static_cast((count() - index) * OperandSizeToValue(osDWord)); + loader_info_list.push_back(LoaderInfo(file_crc_entry_, file_crc_size_)); + + file_crc_size_entry_ = file_crc_entry_ ? AddCommand(cmDD, IntelOperand(otValue, osDWord)) : NULL; + if (file_crc_size_entry_) + file_crc_size_entry_->include_option(roCreateNewBlock); + + // create header and loader CRC info for loader + index = count(); + if (((ctx.options.flags | ctx.options.sdk_flags) & cpMemoryProtection) || (ctx.options.flags & cpLoaderCRC)) { + // calc CRC blocks count + k = 30 + new_import_list.count(); + if ((ctx.options.flags & cpStripFixups) == 0) { + std::vector function_list = ctx.file->function_list()->processor_list(); + function_list.push_back(this); + for (i = 0; i < runtime_function_list->count(); i++) { + func = runtime_function_list->item(i); + if (func->tag() != ftLoader) + continue; + + if (func->compilation_type() == ctMutation) + function_list.push_back(func); + } + + for (i = 0; i < function_list.size(); i++) { + func = reinterpret_cast(function_list[i]); + for (j = 0; j < func->count(); j++) { + command = func->item(j); + for (size_t c = 0; c < 3; c++) { + IntelOperand operand = command->operand(c); + if (operand.type == otNone) + break; + if (operand.fixup) + k++; + } + } + } + } + for (i = 0; i < k; i++) { + AddCommand(cmDD, IntelOperand(otValue, osDWord)); + AddCommand(cmDD, IntelOperand(otValue, osDWord)); + AddCommand(cmDD, IntelOperand(otValue, osDWord)); + } + } + loader_crc_entry_ = (count() == index) ? NULL : item(index); + if (loader_crc_entry_) + loader_crc_entry_->include_option(roCreateNewBlock); + loader_crc_size_ = static_cast((count() - index) * OperandSizeToValue(osDWord)); + loader_info_list.push_back(LoaderInfo(loader_crc_entry_, loader_crc_size_)); + + loader_crc_size_entry_ = loader_crc_entry_ ? AddCommand(cmDD, IntelOperand(otValue, osDWord)) : NULL; + if (loader_crc_size_entry_) + loader_crc_size_entry_->include_option(roCreateNewBlock); + loader_crc_hash_entry_ = loader_crc_entry_ ? AddCommand(cmDD, IntelOperand(otValue, osDWord)) : NULL; + if (loader_crc_hash_entry_) + loader_crc_hash_entry_->include_option(roCreateNewBlock); + + // create section info for loader + index = count(); + for (i = 0; i < writable_segment_list.size(); i++) { + segment = writable_segment_list[i]; + if ((segment->memory_type() & mtWritable) && ((segment->memory_type() & mtExecutable) == 0 || segment->physical_size())) + continue; + + segment->include_maxprot(VM_PROT_WRITE); + + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, segment->address() - file->image_base())); + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, segment->size())); + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, segment->flags())); + } + // add runtime's WRITABLE sections + for (i = 0; i < runtime->segment_list()->count(); i++) { + segment = runtime->segment_list()->item(i); + if (segment->memory_type() & mtWritable) { + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, segment->address() - file->image_base())); + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, segment->size())); + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, segment->flags())); + } + } + command = (count() == index) ? NULL : item(index); + if (command) + command->include_option(roCreateNewBlock); + loader_info_list.push_back(LoaderInfo(command, (count() - index) * OperandSizeToValue(osDWord))); + + // create fixup info for loader + if (loader_fixup_list.count() > 0) { + Data data; + loader_fixup_list.WriteToData(data, file->image_base()); + command = AddCommand(data); + } else { + command = NULL; + } + if (command) + command->include_option(roCreateNewBlock); + loader_info_list.push_back(LoaderInfo(command, (command) ? command->dump_size() : 0)); + + // create relocation info for loader + loader_info_list.push_back(LoaderInfo(NULL, 0)); + + // create IAT info for loader + index = count(); + for (std::map::iterator it = import_function_info_.begin(); it != import_function_info_.end(); it++) { + import_function = it->first; + if (!import_function->address()) + continue; + + command = AddCommand(cmDD, IntelOperand(otValue, osDWord)); + link = command->AddLink(0, ltOffset, it->second); + link->set_sub_value(file->image_base()); + + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, import_function->address() - file->image_base())); + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, OperandSizeToValue(cpu_address_size()))); + } + for (std::map::iterator it = relocation_info_.begin(); it != relocation_info_.end(); it++) { + MacFixup *fixup = it->first; + + command = AddCommand(cmDD, IntelOperand(otValue, osDWord)); + link = command->AddLink(0, ltOffset, it->second); + link->set_sub_value(file->image_base()); + + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, fixup->address() - file->image_base())); + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, OperandSizeToValue(cpu_address_size()))); + } + if (thread_variables_entry_) { + size_t c = thread_variables_size_ / OperandSizeToValue(cpu_address_size()); + j = IndexOf(thread_variables_entry_); + for (i = 0; i < c; i++) { + src_command = item(j + i); + if (!src_command->operand(1).value) + continue; + + command = AddCommand(cmDD, IntelOperand(otValue, osDWord)); + link = command->AddLink(0, ltOffset, src_command); + link->set_sub_value(file->image_base()); + + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, src_command->address() - file->image_base())); + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, src_command->operand(1).value)); + } + } + size_t patch_section_index = count(); + if (file->runtime_functions_section() && file->runtime_functions_section()->name() == SECT_EH_FRAME) { + AddCommand(cmDD, IntelOperand(otValue, osDWord)); + AddCommand(cmDD, IntelOperand(otValue, osDWord)); + AddCommand(cmDD, IntelOperand(otValue, osDWord)); + } + if (file->unwind_info_section()) { + AddCommand(cmDD, IntelOperand(otValue, osDWord)); + AddCommand(cmDD, IntelOperand(otValue, osDWord)); + AddCommand(cmDD, IntelOperand(otValue, osDWord)); + } + patch_section_entry_ = (count() == patch_section_index) ? NULL : item(patch_section_index); + command = (count() == index) ? NULL : item(index); + if (command) + command->include_option(roCreateNewBlock); + loader_info_list.push_back(LoaderInfo(command, (count() - index) * OperandSizeToValue(osDWord))); + + // create import info for loader + index = count(); + /* + if (ctx.options.flags & cpImportProtection) { + for (i = 0, import_index = 0; i < orig_dll_count; i++) { + import = new_import_list.item(i); + if (import->count() == 0) + continue; + + // DLL name + command = AddCommand(cmDD, IntelOperand(otValue, osDWord)); + link = command->AddLink(0, ltOffset, import_info_list[i].loader_name); + link->set_sub_value(file->image_base()); + + for (j = 0; j < import->count(); j++, import_index++) { + import_function = import->item(j); + if (import_function->options() & ioNative) + continue; + + if (ctx.options.flags & cpResourceProtection) { + // internal API + if ((import_function->options() & ioFromRuntime) == 0 && import_function->type() >= atLoadResource && import_function->type() <= atEnumResourceTypesW) + continue; + } + + iat_command = intel_import->GetIATCommand(import_function); + + // API name + if (import_function->is_ordinal()) { + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, IMAGE_ORDINAL_FLAG32 | import_function->ordinal())); + } else { + command = AddCommand(cmDD, IntelOperand(otValue, osDWord)); + link = command->AddLink(0, ltOffset, import_function_info_list[import_index].loader_name); + link->set_sub_value(file->image_base()); + } + + // IAT + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, ((iat_command) ? iat_command->address() : import_function->address()) - file->image_base())); + + // decrypt value + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, (iat_command) ? iat_command->operand(1).value : 0)); + } + + // end of DLL + AddCommand(cmDD, IntelOperand(otValue, osDWord)); + } + } + */ + command = (count() == index) ? NULL : item(index); + if (command) + command->include_option(roCreateNewBlock); + loader_info_list.push_back(LoaderInfo(command, (count() - index) * OperandSizeToValue(osDWord))); + + // create internal import info for loader + index = count(); + /* + if (ctx.options.flags & cpResourceProtection) { + for (i = 0; i < orig_dll_count; i++) { + import = new_import_list.item(i); + for (j = 0; j < import->count(); j++) { + import_function = import->item(j); + + if ((import_function->options() & ioFromRuntime) || import_function->type() < atLoadResource || import_function->type() > atEnumResourceTypesW) + continue; + + iat_command = (intel_import) ? intel_import->GetIATCommand(import_function) : NULL; + + address = runtime->export_list()->GetAddressByType(import_function->type()); + func = reinterpret_cast(file->function_list()->GetFunctionByAddress(address)); + if (func && func->entry()) + address = func->entry()->address(); + + // address + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, address - file->image_base())); + // IAT + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, ((iat_command) ? iat_command->address() : import_function->address()) - file->image_base())); + // decrypt value + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, (iat_command) ? iat_command->operand(1).value : 0)); + } + } + } + */ + command = (count() == index) ? NULL : item(index); + if (command) + command->include_option(roCreateNewBlock); + loader_info_list.push_back(LoaderInfo(command, (count() - index) * OperandSizeToValue(osDWord))); + + // create memory CRC info for loader + if (intel_crc) { + command = intel_crc->table_entry(); + i = static_cast(intel_crc->size_entry()->operand(0).value); + } else { + command = NULL; + i = 0; + } + loader_info_list.push_back(LoaderInfo(command, i)); + + // create delay import info for loader + index = count(); + command = (count() == index) ? NULL : item(index); + if (command) + command->include_option(roCreateNewBlock); + loader_info_list.push_back(LoaderInfo(command, (count() - index) * OperandSizeToValue(osDWord))); + + // create strings for loader + uint32_t string_key = rand32(); + std::map loader_string_list; + loader_string_list[FACE_FILE_CORRUPTED] = AddCommand(EncryptString((ctx.options.flags & cpMemoryProtection) ? ctx.options.messages[MESSAGE_FILE_CORRUPTED].c_str() : std::string().c_str(), string_key)); + loader_string_list[FACE_DEBUGGER_FOUND] = AddCommand(EncryptString(ctx.options.messages[MESSAGE_DEBUGGER_FOUND].c_str(), string_key)); + loader_string_list[FACE_VIRTUAL_MACHINE_FOUND] = AddCommand(EncryptString(ctx.options.messages[MESSAGE_VIRTUAL_MACHINE_FOUND].c_str(), string_key)); + loader_string_list[FACE_PROC_NOT_FOUND] = AddCommand(EncryptString("The procedure entry point %c could not be located in the module %c", string_key)); + loader_string_list[FACE_ORDINAL_NOT_FOUND] = AddCommand(EncryptString("The ordinal %d could not be located in the module %c", string_key)); + loader_string_list[FACE_INITIALIZATION_ERROR] = AddCommand(EncryptString("Initialization error %d", string_key)); + VMProtectBeginVirtualization("Loader Strings"); + loader_string_list[FACE_UNREGISTERED_VERSION] = AddCommand(EncryptString( +#ifdef DEMO + true +#else + (ctx.options.flags & cpUnregisteredVersion) +#endif + ? VMProtectDecryptStringA("This application is protected with unregistered version of VMProtect.") : "", string_key)); + VMProtectEnd(); + loader_string_list[FACE_MACOSX_FORMAT_VALUE] = AddCommand("%s\n"); + loader_string_list[FACE_GNU_PTRACE] = AddCommand("ptrace"); + for (std::map::const_iterator it = loader_string_list.begin(); it != loader_string_list.end(); it++) { + it->second->include_option(roCreateNewBlock); + } + + file_entry_ = NULL; + if (file->entry_point() && max_header_address) { + segment = file->segment_list()->GetSectionByAddress(file->entry_point()); + if (segment && std::find(packer_info_list.begin(), packer_info_list.end(), segment) != packer_info_list.end()) { + // work around MacOSX >= 10.13 - entry point function must be point within __TEXT segment + max_header_address -= 5; + CommandBlock *block = AddBlock(count(), true); + block->set_address(max_header_address); + file_entry_ = AddCommand(cmJmp, IntelOperand(otValue, cpu_address_size(), 0, file->entry_point())); + file_entry_->set_address(max_header_address); + file_entry_->set_block(block); + } + } + + // append loader + old_count = count(); + std::vector internal_entry_list; + for (size_t n = 0; n < 2; n++) { + for (i = 0; i < runtime_function_list->count(); i++) { + func = runtime_function_list->item(i); + if (func->tag() != ftLoader) + continue; + + if (func->compilation_type() == ctMutation) { + if (n != 0) + continue; + } else { + if (n != 1) + continue; + } + + bool is_internal = (func->compilation_type() != ctMutation && func->entry_type() == etNone); + for (j = 0; j < func->count(); j++) { + src_command = func->item(j); + + dst_command = src_command->Clone(this); + AddObject(dst_command); + if (is_internal) { + if (j == 0) + internal_entry_list.push_back(dst_command); + if (dst_command->type() == cmRet) + dst_command->include_option(roInternal); + } + + src_link = src_command->link(); + if (src_link) { + dst_link = src_link->Clone(link_list()); + dst_link->set_from_command(dst_command); + link_list()->AddObject(dst_link); + + if (src_link->parent_command()) + dst_link->set_parent_command(GetCommandByAddress(src_link->parent_command()->address())); + } + + uint64_t ref_address = (dst_command->type() == cmCall && dst_command->operand(0).type == otValue && func->compilation_type() != ctMutation) ? dst_command->operand(0).value : dst_command->address(); + std::map::const_iterator it_import = runtime_info_list.find(ref_address); + if (it_import != runtime_info_list.end()) { + if (dst_command->type() == cmCall) { + IntelOperand operand = dst_command->operand(0); + if (operand.type == otValue) { + command = GetCommandByAddress(dst_command->operand(0).value); + operand = command->operand(0); + delete dst_command->link(); + dst_command->AddLink(-1, ltCall); + } + dst_command->Init(cmMov, IntelOperand(otRegistr, operand.size, regEAX), operand); + + command = new IntelCommand(this, cpu_address_size(), cmCall, IntelOperand(otRegistr, operand.size, regEAX)); + if (dst_command->link()) + dst_command->link()->set_from_command(command); + AddObject(command); + } + dst_link = dst_command->AddLink((dst_command->operand(1).type != otNone) ? 1 : 0, ltOffset); + std::map::iterator it = import_function_info_.find(it_import->second); + if (it != import_function_info_.end()) + dst_link->set_to_command(it->second); + } + + if (!dst_command->is_data() && (dst_command->options() & roBreaked)) { + // need add JMP after breaked commands + IntelCommand *jmp_command = new IntelCommand(this, cpu_address_size(), cmJmp, IntelOperand(otValue, cpu_address_size(), 0, dst_command->next_address())); + jmp_command->AddLink(0, ltJmp, dst_command->next_address()); + jmp_command->set_address_range(dst_command->address_range()); + jmp_command->CompileToNative(); + AddObject(jmp_command); + } + + command = dst_command; + for (k = 0; k < 3; k++) { + IntelOperand operand = command->operand(k); + if (operand.type == otNone) + break; + + if ((operand.type & otValue) == 0) + continue; + + if ((operand.value & 0xFFFF0000) == 0xFACE0000) { + switch (static_cast(operand.value)) { + case FACE_LOADER_OPTIONS: + operand.value = 0; + if (ctx.options.flags & cpMemoryProtection) + operand.value |= LOADER_OPTION_CHECK_PATCH; + if (ctx.options.flags & cpCheckDebugger) + operand.value |= LOADER_OPTION_CHECK_DEBUGGER; + if (ctx.options.flags & cpCheckVirtualMachine) + operand.value |= LOADER_OPTION_CHECK_VIRTUAL_MACHINE; + command->set_operand_value(k, operand.value); + command->CompileToNative(); + break; + case FACE_LOADER_DATA: + command->set_operand_value(k, loader_data_address - file->image_base()); + command->CompileToNative(); + break; + case FACE_RUNTIME_ENTRY: + if (runtime->segment_list()->count()) { + uint64_t runtime_init_address = runtime->export_list()->GetAddressByType(atRuntimeInit); + if (!runtime_init_address) + return false; + command->set_operand_value(k, runtime_init_address - file->image_base()); + } else { + command->set_operand_value(k, 0); + } + command->CompileToNative(); + break; + case FACE_STRING_DECRYPT_KEY: + command->set_operand_value(k, string_key); + command->CompileToNative(); + break; + case FACE_PACKER_INFO: + case FACE_FILE_CRC_INFO: + case FACE_LOADER_CRC_INFO: + case FACE_SECTION_INFO: + case FACE_FIXUP_INFO: + case FACE_RELOCATION_INFO: + case FACE_IAT_INFO: + case FACE_IMPORT_INFO: + case FACE_INTERNAL_IMPORT_INFO: + case FACE_MEMORY_CRC_INFO: + case FACE_DELAY_IMPORT_INFO: + dst_command = loader_info_list[(operand.value & 0xff) >> 1].data; + if (dst_command) { + link = command->AddLink((int)k, ltOffset, dst_command); + link->set_sub_value(file->image_base()); + } else { + command->set_operand_value(k, 0); + command->CompileToNative(); + } + break; + case FACE_PACKER_INFO_SIZE: + case FACE_SECTION_INFO_SIZE: + case FACE_FIXUP_INFO_SIZE: + case FACE_RELOCATION_INFO_SIZE: + case FACE_IAT_INFO_SIZE: + case FACE_IMPORT_INFO_SIZE: + case FACE_INTERNAL_IMPORT_INFO_SIZE: + case FACE_MEMORY_CRC_INFO_SIZE: + case FACE_DELAY_IMPORT_INFO_SIZE: + command->set_operand_value(k, loader_info_list[(operand.value & 0xff) >> 1].size); + command->CompileToNative(); + break; + case FACE_LOADER_CRC_INFO_SIZE: + if (loader_crc_size_entry_) { + link = command->AddLink((int)k, ltOffset, loader_crc_size_entry_); + link->set_sub_value(file->image_base()); + } else { + command->set_operand_value(k, 0); + command->CompileToNative(); + } + break; + case FACE_LOADER_CRC_INFO_HASH: + if (loader_crc_hash_entry_) { + link = command->AddLink((int)k, ltOffset, loader_crc_hash_entry_); + link->set_sub_value(file->image_base()); + } else { + command->set_operand_value(k, 0); + command->CompileToNative(); + } + break; + case FACE_FILE_CRC_INFO_SIZE: + if (file_crc_size_entry_) { + link = command->AddLink((int)k, ltOffset, file_crc_size_entry_); + link->set_sub_value(file->image_base()); + } else { + command->set_operand_value(k, 0); + command->CompileToNative(); + } + break; + case FACE_MEMORY_CRC_INFO_HASH: + command->set_operand_value(k, intel_crc ? intel_crc->hash_entry()->operand(0).value : 0); + command->CompileToNative(); + break; + case FACE_CRC_INFO_SALT: + command->set_operand_value(k, file->function_list()->crc_cryptor()->item(0)->value()); + command->CompileToNative(); + break; + case FACE_IMAGE_BASE: + if (command->operand(0).size != cpu_address_size()) { + IntelOperand first = command->operand(0); + IntelOperand second = command->operand(1); + first.size = cpu_address_size(); + second.size = cpu_address_size(); + command->Init(static_cast(command->type()), first, second); + } + command->set_operand_value(k, file->image_base()); + command->set_operand_fixup(k, NEED_FIXUP); + command->CompileToNative(); + break; + case FACE_FILE_BASE: + if (command->operand(0).size != cpu_address_size()) { + IntelOperand first = command->operand(0); + IntelOperand second = command->operand(1); + first.size = cpu_address_size(); + second.size = cpu_address_size(); + command->Init(static_cast(command->type()), first, second); + } + command->set_operand_value(k, file->image_base()); + command->CompileToNative(); + break; + case FACE_VAR_IS_PATCH_DETECTED: + case FACE_VAR_IS_DEBUGGER_DETECTED: + case FACE_VAR_LOADER_CRC_INFO: + case FACE_VAR_LOADER_CRC_INFO_SIZE: + case FACE_VAR_LOADER_CRC_INFO_HASH: + case FACE_VAR_CPU_HASH: + case FACE_VAR_CPU_COUNT: + case FACE_VAR_SESSION_KEY: + case FACE_VAR_DRIVER_UNLOAD: + case FACE_VAR_CRC_IMAGE_SIZE: + case FACE_VAR_LOADER_STATUS: + case FACE_VAR_SERVER_DATE: + command->set_operand_value(k, ctx.runtime_var_index[(operand.value & 0xff) >> 4] * OperandSizeToValue(cpu_address_size())); + command->CompileToNative(); + break; + case FACE_VAR_IS_PATCH_DETECTED_SALT: + case FACE_VAR_IS_DEBUGGER_DETECTED_SALT: + case FACE_VAR_LOADER_CRC_INFO_SALT: + case FACE_VAR_LOADER_CRC_INFO_SIZE_SALT: + case FACE_VAR_LOADER_CRC_INFO_HASH_SALT: + case FACE_VAR_CPU_HASH_SALT: + case FACE_VAR_CPU_COUNT_SALT: + case FACE_VAR_DRIVER_UNLOAD_SALT: + case FACE_VAR_CRC_IMAGE_SIZE_SALT: + case FACE_VAR_SERVER_DATE_SALT: + command->set_operand_value(k, ctx.runtime_var_salt[operand.value & 0xff]); + command->CompileToNative(); + break; + case FACE_VAR_CPU_COUNT_SALT ^ 1: + command->set_operand_value(k, ctx.runtime_var_salt[VAR_CPU_COUNT] ^ 1); + command->CompileToNative(); + break; + default: + std::map::const_iterator it = loader_string_list.find(static_cast(operand.value)); + if (it != loader_string_list.end()) { + if (command->type() == cmMov) { + operand = command->operand(0); + operand.size = cpu_address_size(); + if (operand.type == otRegistr) { + command->Init(cmLea, operand, IntelOperand(otMemory | otValue, cpu_address_size(), 0, 0, (cpu_address_size() == osDWord) ? NEED_FIXUP : LARGE_VALUE)); + } else { + command->Init(cmMov, operand, IntelOperand(otValue, cpu_address_size(), 0, 0, NEED_FIXUP)); + } + } else { + command->Init(cmPush, IntelOperand(otValue, cpu_address_size(), 0, 0, NEED_FIXUP)); + } + command->AddLink((int)k, ltOffset, it->second); + } else { + throw std::runtime_error(string_format("Unknown loader string: %X", static_cast(operand.value))); + } + } + } + } + } + } + if (n == 0) { + // create native blocks + for (j = 0; j < count(); j++) { + item(j)->include_option(roNoProgress); + } + CompileToNative(ctx); + for (j = 0; j < count(); j++) { + item(j)->exclude_option(roNoProgress); + } + } + } + + IntelOperand base_operand; + uint64_t base_address = 0; + for (i = old_count; i < count(); i++) { + command = item(i); + dst_link = command->link(); + + // search references to LoaderAlloc/LoaderFree + if (command->type() == cmRet) { + base_operand.type = otNone; + } else if (command->type() == cmCall && command->operand(0).type == otValue && command->operand(0).value == command->next_address()) { + base_address = command->next_address(); + IntelCommand *next_command = item(i + 1); + IntelCommand *next_command2 = item(i + 2); + if (next_command->type() == cmPop && next_command->operand(0).type == otRegistr && + next_command2->type() == cmMov && next_command2->operand(1).type == otRegistr && next_command2->operand(1).registr == next_command->operand(0).registr) { + base_operand = next_command2->operand(0); + } else { + base_operand.type = otNone; + } + + if (command->block()) { + command->Init(cmPush, IntelOperand(otValue, cpu_address_size(), 0, command->next_address(), NEED_FIXUP)); + command->CompileToNative(); + delete command->link(); + continue; + } + } else if (base_operand.type != otNone) { + if (command->type() == cmMov && command->operand(1).type == base_operand.type && command->operand(1).value == base_operand.value) { + uint8_t registr = command->operand(0).registr; + for (j = i + 1; j < count(); j++) { + IntelCommand *next_command = item(j); + if (next_command->type() == cmLea && next_command->operand(1).type == (otMemory | otRegistr | otValue) && next_command->operand(1).registr == registr) { + address = base_address + next_command->operand(1).value; + ICommand *to_command = GetCommandByAddress(address); + if (to_command) { + CommandLink *link = next_command->AddLink(1, ltOffset, to_command); + link->set_sub_value(base_address); + if (next_command->operand(0).registr == registr) + break; + } + } + } + } + } + if (!dst_link) { + for (k = 0; k < 2; k++) { + IntelOperand operand = command->operand(k); + if (operand.type == otNone) + break; + + if (cpu_address_size() == osDWord) { + if (!operand.fixup) + continue; + } else { + if (!operand.is_large_value) + continue; + } + + dst_command = reinterpret_cast(GetCommandByAddress(operand.value)); + if (dst_command && !dst_command->is_data()) { + dst_link = command->AddLink((int)k, ltOffset, dst_command); + break; + } + } + } else { + if (dst_link->to_address()) + dst_link->set_to_command(GetCommandByAddress(dst_link->to_address())); + } + } + setup_image_entry = GetCommandByAddress(runtime->export_list()->GetAddressByType(atSetupImage)); + if (!setup_image_entry) + return false; + + free_image_entry = GetCommandByAddress(runtime->export_list()->GetAddressByType(atFreeImage)); + if (!free_image_entry) + return false; + + // create entry commands + load_command_list.push_back(NULL); + for (i = 0; i < load_command_list.size(); i++) { + IntelCommand *load_command = load_command_list[i]; + + old_count = count(); + size_t stack = 0x20; + AddCommand(cmPush, IntelOperand(otRegistr, cpu_address_size(), regEBP)); + if (load_command && cpu_address_size() == osQWord) { + AddCommand(cmPush, IntelOperand(otRegistr, cpu_address_size(), regEDI)); + AddCommand(cmPush, IntelOperand(otRegistr, cpu_address_size(), regESI)); + } + AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size(), regEBP), IntelOperand(otRegistr, cpu_address_size(), regESP)); + AddCommand(cmAnd, IntelOperand(otRegistr, cpu_address_size(), regESP), IntelOperand(otValue, cpu_address_size(), 0, -0x10)); + AddCommand(cmSub, IntelOperand(otRegistr, cpu_address_size(), regESP), IntelOperand(otValue, cpu_address_size(), 0, stack)); + + // call SetupImage + command = AddCommand(cmCall, IntelOperand(otValue, cpu_address_size())); + command->AddLink(0, ltCall, setup_image_entry); + + // check loader error code + AddCommand(cmCmp, IntelOperand(otRegistr, osDWord, regEAX), IntelOperand(otValue, osDWord, 0, TRUE)); + IntelCommand *check_loader_command = AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size())); + check_loader_command->set_flags(fl_Z); + check_loader_command->AddLink(0, ltJmpWithFlag); + + // call FreeImage + command = AddCommand(cmCall, IntelOperand(otValue, cpu_address_size())); + command->AddLink(0, ltCall, free_image_entry); + + command = AddCommand(cmNop); + check_loader_command->link()->set_to_command(command); + + AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size(), regESP), IntelOperand(otRegistr, cpu_address_size(), regEBP)); + if (load_command && cpu_address_size() == osQWord) { + AddCommand(cmPop, IntelOperand(otRegistr, cpu_address_size(), regESI)); + AddCommand(cmPop, IntelOperand(otRegistr, cpu_address_size(), regEDI)); + } + AddCommand(cmPop, IntelOperand(otRegistr, cpu_address_size(), regEBP)); + + if (load_command) { + AddCommand(cmJmp, IntelOperand(otValue, cpu_address_size(), 0, load_command->operand(1).value)); + load_command->link()->set_to_command(item(old_count)); + } else { + AddCommand(cmRet); + set_entry(item(old_count)); + } + } + + // create term commands + if (term_entry_) { + old_count = count(); + + AddCommand(cmPush, IntelOperand(otRegistr, cpu_address_size(), regEBP)); + AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size(), regEBP), IntelOperand(otRegistr, cpu_address_size(), regESP)); + AddCommand(cmAnd, IntelOperand(otRegistr, cpu_address_size(), regESP), IntelOperand(otValue, cpu_address_size(), 0, -0x10)); + + // call FreeImage + command = AddCommand(cmCall, IntelOperand(otValue, cpu_address_size())); + command->AddLink(0, ltCall, free_image_entry); + + AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size(), regESP), IntelOperand(otRegistr, cpu_address_size(), regEBP)); + AddCommand(cmPop, IntelOperand(otRegistr, cpu_address_size(), regEBP)); + AddCommand(cmRet); + + term_entry_->link()->set_to_command(item(old_count)); + } + + for (i = 0; i < count(); i++) { + command = item(i); + command->CompileToNative(); + } + + // search API calls + for (i = 0; i < count(); i++) { + command = item(i); + if (command->block() || command->type() != cmCall || command->operand(0).type == otValue) + continue; + + k = 0; + for (j = i; j > 0; j--) { + IntelCommand *param_command = item(j - 1); + + switch (param_command->type()) { + case cmMov: case cmLea: case cmXor: case cmMovsxd: + if (cpu_address_size() == osQWord) { + if (param_command->operand(0).type == otRegistr) { + switch (param_command->operand(0).registr) { + case regEDI: + k = std::max(k, 1); + break; + case regESI: + k = std::max(k, 2); + break; + case regEDX: + k = std::max(k, 3); + break; + case regECX: + k = std::max(k, 4); + break; + case regR8: + k = std::max(k, 5); + break; + case regR9: + k = std::max(k, 6); + break; + } + } else if ((param_command->operand(0).type & (otMemory | otBaseRegistr)) == (otMemory | otBaseRegistr) && param_command->operand(0).base_registr == regESP) { + switch (param_command->operand(0).value) { + case 0x00: + k = std::max(k, 7); + break; + case 0x04: + k = std::max(k, 8); + break; + case 0x08: + k = std::max(k, 9); + break; + case 0x0c: + k = std::max(k, 10); + break; + case 0x10: + k = std::max(k, 11); + break; + case 0x14: + k = std::max(k, 12); + break; + default: + if (param_command->operand(0).value >= 0x18) + k = NOT_ID; + break; + } + } + } else if ((param_command->operand(0).type & (otMemory | otBaseRegistr)) == (otMemory | otBaseRegistr) && param_command->operand(0).base_registr == regESP) { + switch (param_command->operand(0).value) { + case 0x00: + k = std::max(k, 1); + break; + case 0x04: + k = std::max(k, 2); + break; + case 0x08: + k = std::max(k, 3); + break; + case 0x0c: + k = std::max(k, 4); + break; + case 0x10: + k = std::max(k, 5); + break; + case 0x14: + k = std::max(k, 6); + break; + case 0x18: + k = std::max(k, 7); + break; + case 0x1c: + k = std::max(k, 8); + break; + case 0x20: + k = std::max(k, 9); + break; + case 0x24: + k = std::max(k, 10); + break; + case 0x28: + k = std::max(k, 11); + break; + case 0x2c: + k = std::max(k, 12); + break; + default: + if (param_command->operand(0).value >= 0x30) + k = NOT_ID; + break; + } + } + break; + case cmCall: case cmJmp: case cmJmpWithFlag: case cmRet: + param_command = NULL; + break; + } + if (!param_command || link_list()->GetLinkByToAddress(ltNone, param_command->address())) + break; + } + if (k == NOT_ID) + continue; + + command->include_option(roInternal); + command->set_operand_value(2, k); + } + + + for (i = 0; i < link_list()->count(); i++) { + CommandLink *link = link_list()->item(i); + if (link->from_command()->type() == cmCall && std::find(internal_entry_list.begin(), internal_entry_list.end(), link->to_command()) != internal_entry_list.end()) + reinterpret_cast(link->from_command())->include_option(roInternal); + link->from_command()->PrepareLink(ctx); + } + + return BaseIntelLoader::Prepare(ctx); +} + +bool MacIntelLoader::Compile(const CompileContext &ctx) +{ + if ((ctx.options.flags & cpStripFixups) == 0) { + // convert fixups into PIC code + size_t i, j, k; + std::vector function_list = ctx.file->function_list()->processor_list(); + function_list.push_back(this); + for (i = 0; i < function_list.size(); i++) { + IntelFunction *func = reinterpret_cast(function_list[i]); + OperandSize cpu_address_size = func->cpu_address_size(); + for (j = 0; j < func->count(); j++) { + IntelCommand *src_command = func->item(j); + CommandBlock *block = src_command->block(); + if (!block || (block->type() & mtExecutable) == 0 || (func->item(block->start_index())->options() & roDataSegment)) + continue; + + size_t fixup_index = NOT_ID; + for (k = 0; k < 3; k++) { + IntelOperand operand = src_command->operand(k); + if (operand.type == otNone) + break; + + if ((operand.type & otValue) && operand.fixup) { + fixup_index = k; + break; + } + } + + if (fixup_index != NOT_ID) { + IntelCommand *command, *ref_command; + + bool is_case = src_command->link() && src_command->link()->type() == ltCase; + if (is_case) { + src_command->set_operand_fixup(0, NULL); + command = reinterpret_cast(src_command->link()->parent_command()); + if (command->link()->to_command() == src_command) { + if (command->type() == cmJmp && (command->operand(0).type & otMemory)) + src_command = command; + else { + src_command = NULL; + for (k = func->IndexOf(command); k < func->count(); k++) { + command = func->item(k); + if (command->type() == cmJmp && command->operand(0).type == otValue) { + k = func->IndexOf(command->link()->to_command()); + if (k == NOT_ID) + break; + k--; + } else if (command->link() && command->link()->type() == ltJmp && command->link()->operand_index() == -1) { + src_command = command; + break; + } else if (command->type() == cmRet) + break; + } + if (!src_command) + throw std::runtime_error("Runtime error at MacIntelLoader::Compile"); + } + } + else + continue; + } + + block = func->AddBlock(func->count(), true); + + IntelRegistrList registr_list; + registr_list.push_back(regEAX); + registr_list.push_back(regECX); + registr_list.push_back(regEDX); + registr_list.push_back(regEBX); + registr_list.push_back(regEBP); + registr_list.push_back(regESI); + registr_list.push_back(regEDI); + + IntelOperand new_operand[3]; + for (k = 0; k < 3; k++) { + IntelOperand operand = src_command->operand(k); + if (operand.type == otNone) + break; + + if (operand.type & otRegistr) + registr_list.remove(operand.registr); + if (operand.type & otBaseRegistr) + registr_list.remove(operand.base_registr); + if (operand.fixup) + operand.fixup = NULL; + new_operand[k] = operand; + } + + uint8_t reg1 = registr_list.GetRandom(); + uint8_t reg2 = registr_list.GetRandom(); + IntelCommand *link_command = NULL; + CommandLink *src_link = src_command->link(); + + func->AddCommand(cmPush, IntelOperand(otRegistr, cpu_address_size, reg1)); + func->AddCommand(cmPush, IntelOperand(otRegistr, cpu_address_size, reg2)); + if (cpu_address_size == osQWord) { + ref_command = func->AddCommand(cmLea, IntelOperand(otRegistr, cpu_address_size, reg1), IntelOperand(otMemory | otValue, cpu_address_size, 0, 0, LARGE_VALUE)); + ref_command->AddLink(1, ltOffset, ref_command); + } + else { + command = func->AddCommand(cmCall, IntelOperand(otValue, cpu_address_size)); + command->AddLink(0, ltCall); + ref_command = func->AddCommand(cmPop, IntelOperand(otRegistr, cpu_address_size, reg1)); + command->link()->set_to_command(ref_command); + } + + command = func->AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size, reg2), IntelOperand(otValue, cpu_address_size)); + command->AddLink(1, ltOffset, ref_command); + command = func->AddCommand(cmSub, IntelOperand(otRegistr, cpu_address_size, reg1), IntelOperand(otRegistr, cpu_address_size, reg2)); + + if (src_command->type() != cmLea && (new_operand[fixup_index].type & otMemory)) { + IntelOperand mov_operand = new_operand[fixup_index]; + OperandSize mov_size = mov_operand.size; + mov_operand.size = cpu_address_size; + command = func->AddCommand(cmLea, IntelOperand(otRegistr, cpu_address_size, reg2), mov_operand); + if (src_link) { + link_command = command; + if (src_link->operand_index() != -1) + func->AddCommand(cmAdd, IntelOperand(otRegistr, cpu_address_size, reg2), IntelOperand(otRegistr, cpu_address_size, reg1)); + } + new_operand[fixup_index] = IntelOperand(otRegistr, mov_size, reg2); + func->AddCommand(cmMov, new_operand[fixup_index], IntelOperand(otMemory | otRegistr, mov_size, reg2)); + } + + switch (src_command->type()) { + case cmPush: + command = func->AddCommand(link_command ? cmMov : cmAdd, IntelOperand(otRegistr, cpu_address_size, reg1), new_operand[0]); + break; + case cmJmp: + command = func->AddCommand(link_command && !is_case ? cmMov : cmAdd, IntelOperand(otRegistr, cpu_address_size, reg1), new_operand[0]); + break; + default: + command = func->AddCommand(static_cast(src_command->type()), new_operand[0], new_operand[1]); + if (!link_command) + func->AddCommand(cmAdd, new_operand[0], IntelOperand(otRegistr, new_operand[0].size, reg1)); + break; + } + if (!link_command) + link_command = command; + + if (src_link) { + if (src_link->operand_index() == -1) + src_link->set_from_command(link_command); + else { + link_command->AddLink(1, src_link->type(), src_link->to_command()); + delete src_link; + } + } + + func->AddCommand(cmPop, IntelOperand(otRegistr, cpu_address_size, reg2)); + + switch (src_command->type()) { + case cmPush: + func->AddCommand(cmXchg, IntelOperand(otMemory | otRegistr, cpu_address_size, regESP), IntelOperand(otRegistr, cpu_address_size, reg1)); + break; + case cmJmp: + func->AddCommand(cmXchg, IntelOperand(otMemory | otRegistr, cpu_address_size, regESP), IntelOperand(otRegistr, cpu_address_size, reg1)); + func->AddCommand(cmRet); + break; + default: + func->AddCommand(cmPop, IntelOperand(otRegistr, cpu_address_size, reg1)); + break; + } + + if (src_command->type() != cmJmp) { + command = func->AddCommand(cmJmp, IntelOperand(otValue, func->cpu_address_size())); + command->AddLink(0, ltJmp, func->item(func->IndexOf(src_command) + 1)); + } + src_command->Init(cmJmp, IntelOperand(otValue, cpu_address_size, 0)); + src_command->AddLink(0, ltJmp, func->item(block->start_index())); + src_command->CompileToNative(); + for (k = block->start_index(); k < func->count(); k++) { + command = func->item(k); + command->set_block(block); + command->CompileToNative(); + block->set_end_index(k); + } + } + } + } + } + + if (!BaseIntelLoader::Compile(ctx)) + return false; + + IntelCommand *command = init_entry_->link() ? reinterpret_cast(init_entry_->link()->to_command()) : init_entry_; + command->set_operand_value(0, entry()->address()); + command->CompileToNative(); + + for (std::map::iterator it = import_function_info_.begin(); it != import_function_info_.end(); it++) { + MacImportFunction *import_function = it->first; + IntelCommand *command = it->second; + import_function->set_address(command->address()); + } + + for (std::map::iterator it = relocation_info_.begin(); it != relocation_info_.end(); it++) { + MacFixup *fixup = it->first; + IntelCommand *command = it->second; + fixup->set_address(command->address()); + } + + return true; +} + +/** + * ELFIntelFunctionList + */ + +ELFIntelFunctionList::ELFIntelFunctionList(IArchitecture *owner) + : IntelFunctionList(owner) +{ + +} + +ELFIntelFunctionList::ELFIntelFunctionList(IArchitecture *owner, const ELFIntelFunctionList &src) + : IntelFunctionList(owner, src) +{ + +} + +ELFIntelFunctionList *ELFIntelFunctionList::Clone(IArchitecture *owner) const +{ + ELFIntelFunctionList *list = new ELFIntelFunctionList(owner, *this); + return list; +} + +IntelSDK *ELFIntelFunctionList::AddSDK(OperandSize cpu_address_size) +{ + IntelSDK *func = new ELFIntelSDK(this, cpu_address_size); + AddObject(func); + return func; +} + +void ELFIntelFunctionList::ReadFromBuffer(Buffer &buffer, IArchitecture &file) +{ + IntelFunctionList::ReadFromBuffer(buffer, file); + + std::vector memory_ref_list; + size_t i, j, k; + IntelCommand *command, *mem_command; + size_t c = count(); + OperandSize cpu_address_size = file.cpu_address_size(); + ELFDirectory *plt_got = reinterpret_cast(file).command_list()->GetCommandByType(DT_PLTGOT); + uint64_t plt_got_address = plt_got ? plt_got->value() : 0; + for (i = 0; i < c; i++) { + IntelFunction *func = item(i); + if (func->tag() != ftLoader) + continue; + + for (j = 0; j < func->count(); j++) { + command = func->item(j); + + if (command->type() == cmMovaps) { + for (k = 0; k < 3; k++) { + IntelOperand operand = command->operand(k); + if (operand.type == otNone) + break; + + if ((operand.type & otValue) == 0) + continue; + + if (operand.type == (otMemory | otValue)) { + if (cpu_address_size == osQWord && operand.is_large_value) { + memory_ref_list.push_back(command); + } + } else if (operand.type == (otMemory | otRegistr | otValue) && plt_got_address) { + if (cpu_address_size == osDWord) + memory_ref_list.push_back(command); + } + } + } + } + } + + if (memory_ref_list.size()) { + for (i = 0; i < memory_ref_list.size(); i++) { + command = memory_ref_list[i]; + IntelFunction *func = reinterpret_cast(command->owner()); + + IntelOperand operand = command->operand(1); + uint64_t address = operand.value; + if (operand.type & otRegistr) { + address += plt_got_address; + if (cpu_address_size == osDWord) + address = static_cast(address); + } + if (!func->GetCommandByAddress(address)) { + file.AddressSeek(address); + mem_command = func->Add(address); + mem_command->ReadArray(file, OperandSizeToValue(operand.size)); + mem_command->include_option(roCreateNewBlock); + if (operand.size == osXMMWord) + mem_command->set_alignment(0x10); +#ifdef CHECKED + mem_command->update_hash(); +#endif + } + CommandLink *link = command->AddLink(1, ltOffset, address); + if (operand.type & otRegistr) + link->set_sub_value(plt_got_address); + } + } +} + +/** + * ELFIntelSDK + */ + +ELFIntelSDK::ELFIntelSDK(IFunctionList *parent, OperandSize cpu_address_size) + : IntelSDK(parent, cpu_address_size) +{ + +} + +/** + * ELFIntelLoader + */ + +ELFIntelLoader::ELFIntelLoader(IntelFunctionList *owner, OperandSize cpu_address_size) + : BaseIntelLoader(owner, cpu_address_size), import_entry_(NULL), import_size_(0), file_crc_entry_(NULL), + file_crc_size_(0), file_crc_size_entry_(NULL), loader_crc_entry_(NULL), loader_crc_size_(0), loader_crc_size_entry_(NULL), + loader_crc_hash_entry_(NULL), term_entry_(NULL), preinit_entry_(NULL), preinit_size_(0), init_entry_(NULL), tls_entry_(NULL), + relro_entry_(NULL) +{ + //set_compilation_type(ctMutation); +} + +uint32_t ELFIntelLoader::GetPackedSize(ELFArchitecture *file) const +{ + size_t i; + PackerInfo packer_info; + ELFSegment *segment; + std::vector packer_info_list; + uint32_t physical_size; + + for (i = 0; i < file->segment_list()->count(); i++) { + segment = file->segment_list()->item(i); + if (segment->type() != PT_LOAD || segment->excluded_from_packing()) + continue; + + bool can_be_packed = true; + if ((segment->memory_type() & (mtWritable | mtShared)) == (mtWritable | mtShared)) { + can_be_packed = false; + } + + if (!can_be_packed) + continue; + + if (segment->physical_size()) { + packer_info = PackerInfo(segment, segment->address(), static_cast(segment->physical_size())); + + if (segment == file->header_segment()) { + ELFSegment *interp = file->segment_list()->GetSectionByType(PT_INTERP); + size_t delta = interp ? static_cast(interp->address() + interp->size() - segment->address()) : file->max_header_size(); + packer_info.address += delta; + if (packer_info.size > delta) { + packer_info.size -= delta; + } + else { + packer_info.size = 0; + } + } + + if (!packer_info.size) + continue; + + packer_info_list.push_back(packer_info); + } + } + + uint32_t physical_offset = 0; + for (i = 0; i < file->segment_list()->count(); i++) { + segment = file->segment_list()->item(i); + if (segment->type() != PT_LOAD) + continue; + + std::vector::iterator it = std::find(packer_info_list.begin(), packer_info_list.end(), segment); + if (it != packer_info_list.end()) { + physical_size = static_cast(it->address - segment->address()); + physical_offset = (uint32_t)AlignValue(physical_offset + physical_size, file->file_alignment()); + } + else { + physical_size = segment->physical_size(); + physical_offset += physical_size; + } + } + return physical_offset; +} + +bool ELFIntelLoader::Prepare(const CompileContext &ctx) +{ + ELFArchitecture *file, *runtime; + size_t i, j, k, index, old_count, start_index; + IntelCommand *command, *src_command, *dst_command, *setup_image_entry, *free_image_entry; + CommandLink *link, *src_link, *dst_link; + uint64_t loader_data_address; + IntelFunctionList *runtime_function_list; + IntelFunction *func; + IntelCRCTable *intel_crc; + ELFImport *import; + ELFImportFunction *import_function; + std::map runtime_info_list; + std::map import_function_info; + std::map iat_info; + ELFRelocation *relocation; + ELFSegment *segment; + std::map relocation_info; + + file = reinterpret_cast(ctx.file); + runtime = reinterpret_cast(ctx.runtime); + intel_crc = reinterpret_cast(file->function_list())->crc_table(); + IntelLoaderData *loader_data = reinterpret_cast(file->function_list())->loader_data(); + loader_data_address = (loader_data) ? loader_data->entry()->address() : runtime->export_list()->GetAddressByType(atLoaderData); + if (!loader_data_address) + return false; + + // create AV signature buffer + AddAVBuffer(ctx); + start_index = count(); + + ICommand *entry_point_command = NULL; + if (file->entry_point()) { + IFunction *entry_point_func = ctx.file->function_list()->GetFunctionByAddress(file->entry_point()); + if (entry_point_func) + entry_point_command = entry_point_func->entry(); + } + + // add loader import + std::map import_map; + ELFImportList &new_import_list = *file->import_list(); + runtime_function_list = reinterpret_cast(runtime->function_list()); + IntelCommandType value_command_type = (cpu_address_size() == osDWord) ? cmDD : cmDQ; + index = count(); + std::map relocation_map; + ELFDirectory *plt_got = runtime->command_list()->GetCommandByType(DT_PLTGOT); + uint64_t plt_got_address = plt_got ? plt_got->value() : 0; + for (i = 0; i < runtime_function_list->count(); i++) { + func = runtime_function_list->item(i); + if (func->tag() != ftLoader) + continue; + + for (j = 0; j < func->count(); j++) { + command = func->item(j); + import_function = NULL; + switch (command->type()) { + case cmCall: + case cmJmp: + case cmMov: + k = (command->type() == cmMov) ? 1 : 0; + if (command->operand(k).type == (otMemory | otValue)) + import_function = runtime->import_list()->GetFunctionByAddress(command->operand(k).value); + else if (command->type() != cmMov && command->operand(k).type == (otMemory | otRegistr | otValue) && command->operand(k).registr == regEBX && plt_got_address) + import_function = runtime->import_list()->GetFunctionByAddress(plt_got_address + command->operand(k).value); + break; + } + if (!import_function) + continue; + + std::map::const_iterator it = import_map.find(import_function->address()); + ELFImportFunction *new_import_function = (it != import_map.end()) ? it->second : NULL; + if (!new_import_function) { + ELFImport *src_import = reinterpret_cast(import_function->owner()); + import = new_import_list.GetImportByName(src_import->name()); + if (!import) { + import = new ELFImport(&new_import_list, src_import->name()); + new_import_list.AddObject(import); + } + + ELFSymbol *symbol = import_function->symbol()->Clone(file->dynsymbol_list()); + symbol->set_version(0); + file->dynsymbol_list()->AddObject(symbol); + + ELFRelocation *src_relocation = runtime->relocation_list()->GetRelocationByAddress(import_function->address()); + relocation = src_relocation->Clone(file->relocation_list()); + if (relocation->type() == R_386_JMP_SLOT) + relocation->set_type(R_386_GLOB_DAT); + relocation->set_address(0); + relocation->set_symbol(symbol); + file->relocation_list()->AddObject(relocation); + + new_import_function = import->Add(0, import_function->name(), symbol); + import_map[import_function->address()] = new_import_function; + relocation_map[relocation] = new_import_function; + } + runtime_info_list[command->address()] = new_import_function; + } + } + + // create IAT + for (i = 0; i < new_import_list.count(); i++) { + import = new_import_list.item(i); + for (j = 0; j < import->count(); j++) { + import_function = import->item(j); + if (!import_function) + continue; + + relocation = file->relocation_list()->GetRelocationByAddress(import_function->address()); + relocation_map[relocation] = import_function; + } + } + AddCommand(value_command_type, IntelOperand(otValue, cpu_address_size())); + AddCommand(value_command_type, IntelOperand(otValue, cpu_address_size())); + AddCommand(value_command_type, IntelOperand(otValue, cpu_address_size())); + for (i = 0; i < file->relocation_list()->count(); i++) { + relocation = file->relocation_list()->item(i); + if (relocation->type() != R_386_JMP_SLOT) + continue; + + command = AddCommand(value_command_type, IntelOperand(otValue, cpu_address_size())); + command->AddLink(0, ltOffset); + command->set_operand_relocation(0, relocation); + command->CompileToNative(); + + import_function = relocation_map[relocation]; + if (import_function) + import_function_info[import_function] = command; + } + import_entry_ = item(start_index); + import_entry_->include_option(roCreateNewBlock); + import_entry_->set_alignment(OperandSizeToValue(cpu_address_size())); + import_size_ = static_cast((count() - start_index) * OperandSizeToValue(cpu_address_size())); + for (i = 0; i < file->relocation_list()->count(); i++) { + relocation = file->relocation_list()->item(i); + if (relocation->type() == R_386_JMP_SLOT) + continue; + + if (relocation->address()) { + if ((ctx.options.flags & cpPack) == 0) + continue; + if (cpu_address_size() == osDWord) { + if (relocation->type() == R_386_IRELATIVE) { + relocation_info[relocation] = NULL; + continue; + } + } + else { + if (relocation->type() == R_X86_64_IRELATIVE) { + relocation_info[relocation] = NULL; + continue; + } + } + segment = file->segment_list()->GetSectionByAddress(relocation->address()); + if (!segment || segment->excluded_from_packing() || segment->address() + segment->physical_size() <= relocation->address()) + continue; + } + + command = AddCommand(value_command_type, IntelOperand(otValue, cpu_address_size(), 0, (relocation->type() == R_386_PC32) ? 0 : relocation->value())); + command->set_operand_relocation(0, relocation); + command->CompileToNative(); + + import_function = relocation_map[relocation]; + if (import_function) + import_function_info[import_function] = command; + + if (relocation->address()) { + if (relocation->type() == R_386_PC32) + relocation_info[relocation] = command; + else { + iat_info[relocation] = command; + if (relocation->type() == R_386_COPY && relocation->symbol()->size() > command->dump_size()) { + Data data; + data.resize(AlignValue(relocation->symbol()->size(), command->dump_size()) - command->dump_size()); + AddCommand(data); + } + } + } + } + + // create jump table + IntelCommand *jmp_table_entry = AddCommand(cmPush, IntelOperand(otMemory | otValue, cpu_address_size(), 0, 0, (cpu_address_size() == osDWord) ? NEED_FIXUP : LARGE_VALUE)); + jmp_table_entry->AddLink(0, ltOffset, item(start_index + 1)); + command = AddCommand(cmJmp, IntelOperand(otMemory | otValue, cpu_address_size(), 0, 0, (cpu_address_size() == osDWord) ? NEED_FIXUP : LARGE_VALUE)); + command->AddLink(0, ltOffset, item(start_index + 2)); + k = 1; + index = 0; + for (i = 0; i < file->relocation_list()->count(); i++) { + relocation = file->relocation_list()->item(i); + if (relocation->type() != R_386_JMP_SLOT) + continue; + + IntelCommand *iat_command = item(start_index + 3 + index); + if (relocation->address()) { + CommandBlock *block = AddBlock(count(), true); + + command = AddCommand(cmJmp, IntelOperand(otMemory | otValue, cpu_address_size(), 0, 0, (cpu_address_size() == osDWord) ? NEED_FIXUP : LARGE_VALUE)); + command->AddLink(0, ltOffset, iat_command); + command->CompileToNative(); + command->set_block(block); + + uint64_t address = ctx.manager->Alloc(command->dump_size(), mtReadable); + block->set_address(address); + + file->AddressSeek(relocation->address()); + if (cpu_address_size() == osDWord) + file->WriteDWord(static_cast(address)); + else + file->WriteQWord(address); + + file->fixup_list()->Add(relocation->address(), cpu_address_size()); + } + + size_t offset = index * k; + if (cpu_address_size() == osDWord) + offset *= sizeof(Elf32_Rel); + command = AddCommand(cmPush, IntelOperand(otValue, cpu_address_size(), 0, offset)); + iat_command->link()->set_to_command(command); + + command = AddCommand(cmJmp, IntelOperand(otValue, cpu_address_size())); + command->AddLink(0, ltJmp, jmp_table_entry); + + index++; + } + + ELFDirectory *dir = file->command_list()->GetCommandByType(DT_PREINIT_ARRAY); + if (dir) { + // create preinit module function list + uint64_t address = dir->value(); + if (file->AddressSeek(address)) { + dir = file->command_list()->GetCommandByType(DT_PREINIT_ARRAYSZ); + if (dir) { + index = count(); + AddCommand(value_command_type, IntelOperand(otValue, cpu_address_size(), 0, 0, NEED_FIXUP)); + for (j = 0; j < static_cast(dir->value()); j += OperandSizeToValue(cpu_address_size())) { + command = Add(address + j); + command->ReadValueFromFile(*file, cpu_address_size()); + } + preinit_entry_ = item(index); + preinit_entry_->include_option(roCreateNewBlock); + preinit_entry_->set_alignment(OperandSizeToValue(cpu_address_size())); + preinit_entry_->AddLink(0, ltGateOffset); + preinit_size_ = static_cast((count() - index) * OperandSizeToValue(cpu_address_size())); + } + } + } + term_entry_ = AddCommand(value_command_type, IntelOperand(otValue, cpu_address_size())); + term_entry_->include_option(roCreateNewBlock); + term_entry_->AddLink(0, ltGateOffset); + + if (file->file_type() == ET_DYN) { + init_entry_ = AddCommand(cmJmp, IntelOperand(otValue, cpu_address_size())); + init_entry_->AddLink(0, ltGateOffset); + } + + // create watermarks + AddWatermark(ctx.options.watermark, 2); + + // create segment list for setting WRITABLE flag + std::vector writable_segment_list; + segment = file->segment_list()->GetSectionByAddress(loader_data_address); + if (segment) + writable_segment_list.push_back(segment); + for (i = 0; i < file->relocation_list()->count(); i++) { + ELFRelocation *relocation = file->relocation_list()->item(i); + if (!relocation->address()) + continue; + + segment = file->segment_list()->GetSectionByAddress(relocation->address()); + if (!segment) + continue; + + if (std::find(writable_segment_list.begin(), writable_segment_list.end(), segment) == writable_segment_list.end()) + writable_segment_list.push_back(segment); + } + + std::vector packer_info_list; + ELFFixupList loader_fixup_list; + bool pack_resources = false; + IntelCommand *packer_props = NULL; + if (ctx.options.flags & cpPack) { + ELFSegment *tls_segment = file->segment_list()->GetSectionByType(PT_TLS); + if (tls_segment && tls_segment->physical_size()) { + segment = file->segment_list()->GetSectionByAddress(tls_segment->address()); + if (segment && !segment->excluded_from_packing() && file->AddressSeek(tls_segment->address())) { + Data data; + for (i = 0; i < tls_segment->physical_size(); i++) { + data.PushByte(file->ReadByte()); + } + tls_entry_ = AddCommand(data); + tls_entry_->include_option(roCreateNewBlock); + tls_entry_->set_alignment(static_cast(tls_segment->alignment())); + } + } + + PackerInfo packer_info; + for (i = 0; i < file->segment_list()->count(); i++) { + segment = file->segment_list()->item(i); + if (segment->type() != PT_LOAD || segment->excluded_from_packing()) + continue; + + bool can_be_packed = true; + if ((segment->memory_type() & (mtWritable | mtShared)) == (mtWritable | mtShared)) { + can_be_packed = false; + } + + if (!can_be_packed) { + //file->Notify(mtWarning, NULL, string_format(language[lsSegmentCanNotBePacked].c_str(), section->name().c_str())); + continue; + } + + if (segment->physical_size()) { + packer_info = PackerInfo(segment, segment->address(), static_cast(segment->physical_size())); + + if (segment == file->header_segment()) { + ELFSegment *interp = file->segment_list()->GetSectionByType(PT_INTERP); + size_t delta = interp ? static_cast(interp->address() + interp->size() - segment->address()) : file->max_header_size(); + packer_info.address += delta; + if (packer_info.size > delta) { + packer_info.size -= delta; + } else { + packer_info.size = 0; + } + } + + if (!packer_info.size) + continue; + + packer_info_list.push_back(packer_info); + + // need add packed section into WRITABLE section list + if (std::find(writable_segment_list.begin(), writable_segment_list.end(), segment) == writable_segment_list.end()) + writable_segment_list.push_back(segment); + } + } + + if ((ctx.options.flags & cpStripFixups) == 0) { + for (i = 0; i < file->fixup_list()->count(); i++) { + ELFFixup *fixup = file->fixup_list()->item(i); + if (fixup->is_deleted()) + continue; + + segment = file->segment_list()->GetSectionByAddress(fixup->address()); + if (!segment || std::find(packer_info_list.begin(), packer_info_list.end(), segment) == packer_info_list.end()) + continue; + + loader_fixup_list.AddObject(fixup->Clone(&loader_fixup_list)); + fixup->set_deleted(true); + + // need add section into WRITABLE section list + if (std::find(writable_segment_list.begin(), writable_segment_list.end(), segment) == writable_segment_list.end()) + writable_segment_list.push_back(segment); + } + } + + // packing sections + j = 0; + for (i = 0; i < packer_info_list.size(); i++) { + j += packer_info_list[i].size; + } + file->StartProgress(string_format("%s...", language[lsPacking].c_str()), j); + + Data data; + Packer packer; + + if (!packer.WriteProps(&data)) + throw std::runtime_error("Packer error"); + packer_props = AddCommand(data); + packer_props->include_option(roCreateNewBlock); + + for (i = 0; i < packer_info_list.size(); i++) { + packer_info = packer_info_list[i]; + if (!file->AddressSeek(packer_info.address)) + return false; + + if (!packer.Code(file, packer_info.size, &data)) + throw std::runtime_error("Packer error"); + + command = AddCommand(data); + command->include_option(roCreateNewBlock); + packer_info_list[i].data = command; + } + + // remove packed sections from file + uint32_t physical_offset = 0; + for (i = 0; i < file->segment_list()->count(); i++) { + segment = file->segment_list()->item(i); + if (segment->type() != PT_LOAD) + continue; + + uint32_t physical_size = segment->physical_size(); + bool is_packed = false; + std::vector::iterator it = std::find(packer_info_list.begin(), packer_info_list.end(), segment); + if (it != packer_info_list.end()) { + physical_size = static_cast(it->address - segment->address()); + is_packed = true; + } + if (segment->physical_offset() != physical_offset) { + size_t delta = static_cast(physical_offset - segment->physical_offset()); + for (j = 0; j < file->section_list()->count(); j++) { + ELFSection *section = file->section_list()->item(j); + if (section->parent() == segment && section->physical_offset()) + section->set_physical_offset(static_cast(section->physical_offset() + delta)); + } + } + + if (physical_size > 0 && segment->physical_offset() != physical_offset) { + uint8_t *buff = new uint8_t[physical_size]; + file->Seek(segment->physical_offset()); + file->Read(buff, physical_size); + file->Seek(physical_offset); + file->Write(buff, physical_size); + delete [] buff; + } + + if (segment->physical_offset() != physical_offset) { + uint64_t delta = (static_cast(physical_offset) & (segment->alignment() - 1)) - (segment->address() & (segment->alignment() - 1)); + segment->Rebase(delta); + segment->set_size((static_cast(delta) > 0 && segment->size() < delta) ? 0 : segment->size() - delta); + } + segment->set_physical_offset(physical_offset); + segment->set_physical_size(physical_size); + + if (is_packed) { + j = physical_offset + physical_size; + file->Seek(j); + physical_offset = (uint32_t)AlignValue(j, file->file_alignment()); + for (k = j; k < physical_offset; k++) { + file->WriteByte(0); + } + } else { + physical_offset += physical_size; + } + } + file->Resize(physical_offset); + } + + // create packer info for loader + std::vector loader_info_list; + index = count(); + if (packer_props) { + command = AddCommand(cmDD, IntelOperand(otValue, osDWord)); + link = command->AddLink(0, ltOffset, packer_props); + link->set_sub_value(file->image_base()); + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, packer_props->dump_size())); + + for (i = 0; i < packer_info_list.size(); i++) { + command = AddCommand(cmDD, IntelOperand(otValue, osDWord)); + link = command->AddLink(0, ltOffset, packer_info_list[i].data); + link->set_sub_value(file->image_base()); + + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, packer_info_list[i].address - file->image_base())); + } + } + command = (count() == index) ? NULL : item(index); + if (command) + command->include_option(roCreateNewBlock); + loader_info_list.push_back(LoaderInfo(command, (count() - index) * OperandSizeToValue(osDWord))); + + // create file CRC info for loader + index = count(); + if ((ctx.options.flags | ctx.options.sdk_flags) & cpMemoryProtection) { + AddCommand(cmDD, IntelOperand(otValue, osDWord)); + for (i = 0; i < 4; i++) { + AddCommand(cmDD, IntelOperand(otValue, osDWord)); + AddCommand(cmDD, IntelOperand(otValue, osDWord)); + AddCommand(cmDD, IntelOperand(otValue, osDWord)); + } + } + file_crc_entry_ = (count() == index) ? NULL : item(index); + if (file_crc_entry_) + file_crc_entry_->include_option(roCreateNewBlock); + file_crc_size_ = static_cast((count() - index) * OperandSizeToValue(osDWord)); + loader_info_list.push_back(LoaderInfo(file_crc_entry_, file_crc_size_)); + + file_crc_size_entry_ = file_crc_entry_ ? AddCommand(cmDD, IntelOperand(otValue, osDWord)) : NULL; + if (file_crc_size_entry_) + file_crc_size_entry_->include_option(roCreateNewBlock); + + // create header and loader CRC info for loader + index = count(); + if (((ctx.options.flags | ctx.options.sdk_flags) & cpMemoryProtection) || (ctx.options.flags & cpLoaderCRC)) { + // calc CRC blocks count + k = 30; + if ((ctx.options.flags & cpStripFixups) == 0) { + std::vector function_list = ctx.file->function_list()->processor_list(); + function_list.push_back(this); + for (i = 0; i < runtime_function_list->count(); i++) { + func = runtime_function_list->item(i); + if (func->tag() != ftLoader) + continue; + + if (func->compilation_type() == ctMutation) + function_list.push_back(func); + } + + for (i = 0; i < function_list.size(); i++) { + func = reinterpret_cast(function_list[i]); + for (j = 0; j < func->count(); j++) { + command = func->item(j); + for (size_t c = 0; c < 3; c++) { + IntelOperand operand = command->operand(c); + if (operand.type == otNone) + break; + if (operand.fixup) + k++; + } + } + } + } + for (i = 0; i < k; i++) { + AddCommand(cmDD, IntelOperand(otValue, osDWord)); + AddCommand(cmDD, IntelOperand(otValue, osDWord)); + AddCommand(cmDD, IntelOperand(otValue, osDWord)); + } + } + loader_crc_entry_ = (count() == index) ? NULL : item(index); + if (loader_crc_entry_) + loader_crc_entry_->include_option(roCreateNewBlock); + loader_crc_size_ = static_cast((count() - index) * OperandSizeToValue(osDWord)); + loader_info_list.push_back(LoaderInfo(loader_crc_entry_, loader_crc_size_)); + + loader_crc_size_entry_ = loader_crc_entry_ ? AddCommand(cmDD, IntelOperand(otValue, osDWord)) : NULL; + if (loader_crc_size_entry_) + loader_crc_size_entry_->include_option(roCreateNewBlock); + loader_crc_hash_entry_ = loader_crc_entry_ ? AddCommand(cmDD, IntelOperand(otValue, osDWord)) : NULL; + if (loader_crc_hash_entry_) + loader_crc_hash_entry_->include_option(roCreateNewBlock); + + // create section info for loader + index = count(); + for (i = 0; i < writable_segment_list.size(); i++) { + segment = writable_segment_list[i]; + if (segment->memory_type() & mtWritable) + continue; + + size_t page_offset = static_cast(segment->address() & (ELF_PAGE_SIZE - 1)); + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, segment->address() - page_offset - file->image_base())); + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, segment->size() + page_offset)); + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, segment->prot())); + } + // add runtime's WRITABLE sections + for (i = 0; i < runtime->segment_list()->count(); i++) { + segment = runtime->segment_list()->item(i); + if ((segment->memory_type() & mtWritable) == 0) + continue; + + size_t page_offset = static_cast(segment->address() & (ELF_PAGE_SIZE - 1)); + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, segment->address() - page_offset - file->image_base())); + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, segment->size() + page_offset)); + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, segment->prot())); + } + command = (count() == index) ? NULL : item(index); + if (command) + command->include_option(roCreateNewBlock); + loader_info_list.push_back(LoaderInfo(command, (count() - index) * OperandSizeToValue(osDWord))); + + // create fixup info for loader + if (loader_fixup_list.count() > 0) { + Data data; + loader_fixup_list.WriteToData(data, file->image_base()); + command = AddCommand(data); + } else { + command = NULL; + } + if (command) + command->include_option(roCreateNewBlock); + loader_info_list.push_back(LoaderInfo(command, (command) ? command->dump_size() : 0)); + + // create relocation info for loader + index = count(); + for (std::map::const_iterator it = relocation_info.begin(); it != relocation_info.end(); it++) { + relocation = it->first; + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, relocation->address() - file->image_base())); + switch (relocation->type()) { + case R_386_PC32: + command = AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, 0)); + link = command->AddLink(0, ltOffset, it->second); + link->set_sub_value(file->image_base()); + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, 1)); + relocation->set_type(R_386_32); + break; + default: + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, relocation->addend() - file->image_base())); + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, 0)); + delete relocation; + break; + } + } + command = (count() == index) ? NULL : item(index); + if (command) + command->include_option(roCreateNewBlock); + loader_info_list.push_back(LoaderInfo(command, (count() - index) * OperandSizeToValue(osDWord))); + + // create IAT info for loader + index = count(); + for (std::map::iterator it = iat_info.begin(); it != iat_info.end(); it++) { + relocation = it->first; + + command = AddCommand(cmDD, IntelOperand(otValue, osDWord)); + link = command->AddLink(0, ltOffset, it->second); + link->set_sub_value(file->image_base()); + + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, relocation->address() - file->image_base())); + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, (relocation->type() == R_386_COPY) ? relocation->symbol()->size() : OperandSizeToValue(cpu_address_size()))); + } + command = (count() == index) ? NULL : item(index); + if (command) + command->include_option(roCreateNewBlock); + loader_info_list.push_back(LoaderInfo(command, (count() - index) * OperandSizeToValue(osDWord))); + + // create import info for loader + index = count(); + /* + if (ctx.options.flags & cpImportProtection) { + for (i = 0, import_index = 0; i < orig_dll_count; i++) { + import = new_import_list.item(i); + if (import->count() == 0) + continue; + + // DLL name + command = AddCommand(cmDD, IntelOperand(otValue, osDWord)); + link = command->AddLink(0, ltOffset, import_info_list[i].loader_name); + link->set_sub_value(file->image_base()); + + for (j = 0; j < import->count(); j++, import_index++) { + import_function = import->item(j); + if (import_function->options() & ioNative) + continue; + + if (ctx.options.flags & cpResourceProtection) { + // internal API + if ((import_function->options() & ioFromRuntime) == 0 && import_function->type() >= atLoadResource && import_function->type() <= atEnumResourceTypesW) + continue; + } + + iat_command = intel_import->GetIATCommand(import_function); + + // API name + if (import_function->is_ordinal()) { + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, IMAGE_ORDINAL_FLAG32 | import_function->ordinal())); + } else { + command = AddCommand(cmDD, IntelOperand(otValue, osDWord)); + link = command->AddLink(0, ltOffset, import_function_info_list[import_index].loader_name); + link->set_sub_value(file->image_base()); + } + + // IAT + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, ((iat_command) ? iat_command->address() : import_function->address()) - file->image_base())); + + // decrypt value + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, (iat_command) ? iat_command->operand(1).value : 0)); + } + + // end of DLL + AddCommand(cmDD, IntelOperand(otValue, osDWord)); + } + } + */ + command = (count() == index) ? NULL : item(index); + if (command) + command->include_option(roCreateNewBlock); + loader_info_list.push_back(LoaderInfo(command, (count() - index) * OperandSizeToValue(osDWord))); + + // create internal import info for loader + index = count(); + /* + if (ctx.options.flags & cpResourceProtection) { + for (i = 0; i < orig_dll_count; i++) { + import = new_import_list.item(i); + for (j = 0; j < import->count(); j++) { + import_function = import->item(j); + + if ((import_function->options() & ioFromRuntime) || import_function->type() < atLoadResource || import_function->type() > atEnumResourceTypesW) + continue; + + iat_command = (intel_import) ? intel_import->GetIATCommand(import_function) : NULL; + + address = runtime->export_list()->GetAddressByType(import_function->type()); + func = reinterpret_cast(file->function_list()->GetFunctionByAddress(address)); + if (func && func->entry()) + address = func->entry()->address(); + + // address + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, address - file->image_base())); + // IAT + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, ((iat_command) ? iat_command->address() : import_function->address()) - file->image_base())); + // decrypt value + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, (iat_command) ? iat_command->operand(1).value : 0)); + } + } + } + */ + command = (count() == index) ? NULL : item(index); + if (command) + command->include_option(roCreateNewBlock); + loader_info_list.push_back(LoaderInfo(command, (count() - index) * OperandSizeToValue(osDWord))); + + // create memory CRC info for loader + if (intel_crc) { + command = intel_crc->table_entry(); + i = static_cast(intel_crc->size_entry()->operand(0).value); + } else { + command = NULL; + i = 0; + } + loader_info_list.push_back(LoaderInfo(command, i)); + + // create delay import info for loader + index = count(); + command = (count() == index) ? NULL : item(index); + if (command) + command->include_option(roCreateNewBlock); + loader_info_list.push_back(LoaderInfo(command, (count() - index) * OperandSizeToValue(osDWord))); + + // process PT_GNU_RELRO segments + for (i = file->segment_list()->count(); i > 0; i--) { + ELFSegment *read_only_segment = file->segment_list()->item(i - 1); + if (read_only_segment->type() != PT_GNU_RELRO) + continue; + + for (j = 0; j < writable_segment_list.size(); j++) { + segment = writable_segment_list[j]; + if (std::max(segment->address(), read_only_segment->address()) < std::min(segment->address() + segment->size(), read_only_segment->address() + read_only_segment->size())) { + if (!relro_entry_) { + index = count(); + size_t page_offset = static_cast(read_only_segment->address() & (ELF_PAGE_SIZE - 1)); + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, read_only_segment->address() - page_offset - file->image_base())); + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, read_only_segment->size() + page_offset)); + AddCommand(cmDD, IntelOperand(otValue, osDWord, 0, PROT_READ)); + relro_entry_ = item(index); + relro_entry_->include_option(roCreateNewBlock); + } + delete read_only_segment; + break; + } + } + } + + // create strings for loader + uint32_t string_key = rand32(); + std::map loader_string_list; + loader_string_list[FACE_FILE_CORRUPTED] = AddCommand(EncryptString((ctx.options.flags & cpMemoryProtection) ? ctx.options.messages[MESSAGE_FILE_CORRUPTED].c_str() : std::string().c_str(), string_key)); + loader_string_list[FACE_DEBUGGER_FOUND] = AddCommand(EncryptString(ctx.options.messages[MESSAGE_DEBUGGER_FOUND].c_str(), string_key)); + loader_string_list[FACE_VIRTUAL_MACHINE_FOUND] = AddCommand(EncryptString(ctx.options.messages[MESSAGE_VIRTUAL_MACHINE_FOUND].c_str(), string_key)); + loader_string_list[FACE_PROC_NOT_FOUND] = AddCommand(EncryptString("The procedure entry point %c could not be located in the module %c", string_key)); + loader_string_list[FACE_ORDINAL_NOT_FOUND] = AddCommand(EncryptString("The ordinal %d could not be located in the module %c", string_key)); + loader_string_list[FACE_INITIALIZATION_ERROR] = AddCommand(EncryptString("Initialization error %d", string_key)); + VMProtectBeginVirtualization("Loader Strings"); + loader_string_list[FACE_UNREGISTERED_VERSION] = AddCommand(EncryptString( +#ifdef DEMO + true +#else + (ctx.options.flags & cpUnregisteredVersion) +#endif + ? VMProtectDecryptStringA("This application is protected with unregistered version of VMProtect.") : "", string_key)); + VMProtectEnd(); + loader_string_list[FACE_MACOSX_FORMAT_VALUE] = AddCommand("%s\n"); + loader_string_list[FACE_GNU_PTRACE] = AddCommand("ptrace"); + for (std::map::const_iterator it = loader_string_list.begin(); it != loader_string_list.end(); it++) { + it->second->include_option(roCreateNewBlock); + } + + // append loader + old_count = count(); + std::vector internal_entry_list; + for (size_t n = 0; n < 2; n++) { + for (i = 0; i < runtime_function_list->count(); i++) { + func = runtime_function_list->item(i); + if (func->tag() != ftLoader) + continue; + + if (func->compilation_type() == ctMutation) { + if (n != 0) + continue; + } else { + if (n != 1) + continue; + } + + func->Init(ctx); + + bool is_internal = (func->compilation_type() != ctMutation && func->entry_type() == etNone); + for (j = 0; j < func->link_list()->count(); j++) { + src_link = func->link_list()->item(j); + if (src_link->type() != ltMemSEHBlock) + continue; + + src_link->from_command()->set_address(0); + } + + for (j = 0; j < func->count(); j++) { + src_command = func->item(j); + + dst_command = src_command->Clone(this); + AddObject(dst_command); + if (is_internal) { + if (j == 0) + internal_entry_list.push_back(dst_command); + if (dst_command->type() == cmRet) + dst_command->include_option(roInternal); + } + + src_link = src_command->link(); + if (src_link) { + dst_link = src_link->Clone(link_list()); + dst_link->set_from_command(dst_command); + link_list()->AddObject(dst_link); + + if (src_link->parent_command()) + dst_link->set_parent_command(GetCommandByAddress(src_link->parent_command()->address())); + } + + std::map::const_iterator it_import = runtime_info_list.find(dst_command->address()); + if (it_import != runtime_info_list.end()) { + if (dst_command->type() == cmCall) { + IntelOperand operand = dst_command->operand(0); + dst_command->Init(cmMov, IntelOperand(otRegistr, operand.size, regEAX), operand); + + command = new IntelCommand(this, cpu_address_size(), cmCall, IntelOperand(otRegistr, operand.size, regEAX)); + if (dst_command->link()) + dst_command->link()->set_from_command(command); + AddObject(command); + } + k = (dst_command->operand(1).type != otNone) ? 1 : 0; + dst_link = dst_command->AddLink((int)k, ltOffset); + if (dst_command->operand(k).type & otRegistr) + dst_link->set_sub_value(plt_got_address); + std::map::iterator it = import_function_info.find(it_import->second); + if (it != import_function_info.end()) + dst_link->set_to_command(it->second); + } + + if (dst_command->type() == cmCall && (dst_command->options() & roFar) == 0 && dst_command->operand(0).type == otValue) { + uint64_t next_address = dst_command->address() + dst_command->original_dump_size(); + CompilerFunction *compiler_function = runtime->compiler_function_list()->GetFunctionByAddress(next_address); + if (compiler_function && compiler_function->type() == cfBaseRegistr) { + delete dst_command->link(); + IntelOperand operand; + operand.decode(compiler_function->value(0)); + dst_command->Init(cmLea, operand, IntelOperand(otMemory | otValue, operand.size, 0, next_address, (cpu_address_size() == osDWord) ? NEED_FIXUP : LARGE_VALUE)); + } + } + if (!dst_command->is_data() && (dst_command->options() & roBreaked)) { + // need add JMP after breaked commands + IntelCommand *jmp_command = new IntelCommand(this, cpu_address_size(), cmJmp, IntelOperand(otValue, cpu_address_size(), 0, dst_command->next_address())); + jmp_command->AddLink(0, ltJmp, dst_command->next_address()); + jmp_command->set_address_range(dst_command->address_range()); + jmp_command->CompileToNative(); + AddObject(jmp_command); + } + + command = dst_command; + for (k = 0; k < 3; k++) { + IntelOperand operand = command->operand(k); + if (operand.type == otNone) + break; + + if ((operand.type & otValue) == 0) + continue; + + if ((operand.value & 0xFFFF0000) == 0xFACE0000) { + switch (static_cast(operand.value)) { + case FACE_LOADER_OPTIONS: + operand.value = 0; + if (ctx.options.flags & cpMemoryProtection) + operand.value |= LOADER_OPTION_CHECK_PATCH; + if (ctx.options.flags & cpCheckDebugger) + operand.value |= LOADER_OPTION_CHECK_DEBUGGER; + if (ctx.options.flags & cpCheckVirtualMachine) + operand.value |= LOADER_OPTION_CHECK_VIRTUAL_MACHINE; + command->set_operand_value(k, operand.value); + command->CompileToNative(); + break; + case FACE_LOADER_DATA: + command->set_operand_value(k, loader_data_address - file->image_base()); + command->CompileToNative(); + break; + case FACE_RUNTIME_ENTRY: + if (runtime->segment_list()->count()) { + uint64_t runtime_init_address = runtime->export_list()->GetAddressByType(atRuntimeInit); + if (!runtime_init_address) + return false; + command->set_operand_value(k, runtime_init_address - file->image_base()); + } else { + command->set_operand_value(k, 0); + } + command->CompileToNative(); + break; + case FACE_STRING_DECRYPT_KEY: + command->set_operand_value(k, string_key); + command->CompileToNative(); + break; + case FACE_PACKER_INFO: + case FACE_FILE_CRC_INFO: + case FACE_LOADER_CRC_INFO: + case FACE_SECTION_INFO: + case FACE_FIXUP_INFO: + case FACE_RELOCATION_INFO: + case FACE_IAT_INFO: + case FACE_IMPORT_INFO: + case FACE_INTERNAL_IMPORT_INFO: + case FACE_MEMORY_CRC_INFO: + case FACE_DELAY_IMPORT_INFO: + dst_command = loader_info_list[(operand.value & 0xff) >> 1].data; + if (dst_command) { + link = command->AddLink((int)k, ltOffset, dst_command); + link->set_sub_value(file->image_base()); + } else { + command->set_operand_value(k, 0); + command->CompileToNative(); + } + break; + case FACE_PACKER_INFO_SIZE: + case FACE_SECTION_INFO_SIZE: + case FACE_FIXUP_INFO_SIZE: + case FACE_RELOCATION_INFO_SIZE: + case FACE_IAT_INFO_SIZE: + case FACE_IMPORT_INFO_SIZE: + case FACE_INTERNAL_IMPORT_INFO_SIZE: + case FACE_MEMORY_CRC_INFO_SIZE: + case FACE_DELAY_IMPORT_INFO_SIZE: + command->set_operand_value(k, loader_info_list[(operand.value & 0xff) >> 1].size); + command->CompileToNative(); + break; + case FACE_LOADER_CRC_INFO_SIZE: + if (loader_crc_size_entry_) { + link = command->AddLink((int)k, ltOffset, loader_crc_size_entry_); + link->set_sub_value(file->image_base()); + } else { + command->set_operand_value(k, 0); + command->CompileToNative(); + } + break; + case FACE_LOADER_CRC_INFO_HASH: + if (loader_crc_hash_entry_) { + link = command->AddLink((int)k, ltOffset, loader_crc_hash_entry_); + link->set_sub_value(file->image_base()); + } else { + command->set_operand_value(k, 0); + command->CompileToNative(); + } + break; + case FACE_FILE_CRC_INFO_SIZE: + if (file_crc_size_entry_) { + link = command->AddLink((int)k, ltOffset, file_crc_size_entry_); + link->set_sub_value(file->image_base()); + } else { + command->set_operand_value(k, 0); + command->CompileToNative(); + } + break; + case FACE_MEMORY_CRC_INFO_HASH: + command->set_operand_value(k, intel_crc ? intel_crc->hash_entry()->operand(0).value : 0); + command->CompileToNative(); + break; + case FACE_CRC_INFO_SALT: + command->set_operand_value(k, file->function_list()->crc_cryptor()->item(0)->value()); + command->CompileToNative(); + break; + case FACE_IMAGE_BASE: + if (command->operand(0).size != cpu_address_size()) { + IntelOperand first = command->operand(0); + IntelOperand second = command->operand(1); + first.size = cpu_address_size(); + second.size = cpu_address_size(); + command->Init(static_cast(command->type()), first, second); + } + command->set_operand_value(k, file->image_base()); + command->set_operand_fixup(k, NEED_FIXUP); + command->CompileToNative(); + break; + case FACE_FILE_BASE: + if (command->operand(0).size != cpu_address_size()) { + IntelOperand first = command->operand(0); + IntelOperand second = command->operand(1); + first.size = cpu_address_size(); + second.size = cpu_address_size(); + command->Init(static_cast(command->type()), first, second); + } + command->set_operand_value(k, file->image_base()); + command->CompileToNative(); + break; + case FACE_GNU_RELRO_INFO: + if (relro_entry_) { + link = command->AddLink((int)k, ltOffset, relro_entry_); + link->set_sub_value(file->image_base()); + } + else { + command->set_operand_value(k, 0); + command->CompileToNative(); + } + break; + case FACE_VAR_IS_PATCH_DETECTED: + case FACE_VAR_IS_DEBUGGER_DETECTED: + case FACE_VAR_LOADER_CRC_INFO: + case FACE_VAR_LOADER_CRC_INFO_SIZE: + case FACE_VAR_LOADER_CRC_INFO_HASH: + case FACE_VAR_CPU_HASH: + case FACE_VAR_CPU_COUNT: + case FACE_VAR_SESSION_KEY: + case FACE_VAR_DRIVER_UNLOAD: + case FACE_VAR_CRC_IMAGE_SIZE: + case FACE_VAR_LOADER_STATUS: + case FACE_VAR_SERVER_DATE: + command->set_operand_value(k, ctx.runtime_var_index[(operand.value & 0xff) >> 4] * OperandSizeToValue(cpu_address_size())); + command->CompileToNative(); + break; + case FACE_VAR_IS_PATCH_DETECTED_SALT: + case FACE_VAR_IS_DEBUGGER_DETECTED_SALT: + case FACE_VAR_LOADER_CRC_INFO_SALT: + case FACE_VAR_LOADER_CRC_INFO_SIZE_SALT: + case FACE_VAR_LOADER_CRC_INFO_HASH_SALT: + case FACE_VAR_CPU_HASH_SALT: + case FACE_VAR_CPU_COUNT_SALT: + case FACE_VAR_DRIVER_UNLOAD_SALT: + case FACE_VAR_CRC_IMAGE_SIZE_SALT: + case FACE_VAR_SERVER_DATE_SALT: + command->set_operand_value(k, ctx.runtime_var_salt[operand.value & 0xff]); + command->CompileToNative(); + break; + case FACE_VAR_CPU_COUNT_SALT ^ 1: + command->set_operand_value(k, ctx.runtime_var_salt[VAR_CPU_COUNT] ^ 1); + command->CompileToNative(); + break; + default: + std::map::const_iterator it = loader_string_list.find(static_cast(operand.value)); + if (it != loader_string_list.end()) { + if (command->type() == cmMov) { + operand = command->operand(0); + operand.size = cpu_address_size(); + if (operand.type == otRegistr) { + command->Init(cmLea, operand, IntelOperand(otMemory | otValue, cpu_address_size(), 0, 0, (cpu_address_size() == osDWord) ? NEED_FIXUP : LARGE_VALUE)); + } else { + command->Init(cmMov, operand, IntelOperand(otValue, cpu_address_size(), 0, 0, NEED_FIXUP)); + } + } else { + command->Init(cmPush, IntelOperand(otValue, cpu_address_size(), 0, 0, NEED_FIXUP)); + } + command->AddLink((int)k, ltOffset, it->second); + } else { + throw std::runtime_error(string_format("Unknown loader string: %X", static_cast(operand.value))); + } + } + } + } + } + } + if (n == 0) { + // create native blocks + for (j = 0; j < count(); j++) { + item(j)->include_option(roNoProgress); + } + CompileToNative(ctx); + for (j = 0; j < count(); j++) { + item(j)->exclude_option(roNoProgress); + } + } + } + + for (i = old_count; i < count(); i++) { + command = item(i); + dst_link = command->link(); + + if (command->type() == cmCall && command->operand(0).type == otValue && command->operand(0).value == command->next_address()) { + uint64_t base_address = command->next_address(); + IntelCommand *next_command = item(i + 1); + IntelCommand *next_command2 = item(i + 2); + if (next_command->type() == cmPop && next_command->operand(0).type == otRegistr && + next_command2->type() == cmAdd && next_command2->operand(0).type == otRegistr && next_command2->operand(0).registr == next_command->operand(0).registr) { + base_address += next_command2->operand(1).value; + } + else { + base_address = 0; + } + if (base_address) { + for (j = i + 1; j < count(); j++) { + IntelCommand *next_command = item(j); + if (next_command->type() == cmLea && next_command->operand(1).type == (otMemory | otRegistr | otValue) && (next_command->operand(1).registr == regEBX || next_command->operand(1).registr == regESI)) { + uint64_t address = base_address + next_command->operand(1).value; + ICommand *to_command = GetCommandByAddress(address); + if (to_command) { + link = next_command->AddLink(1, ltOffset, to_command); + link->set_sub_value(base_address); + } + } else if (next_command->type() == cmMov && next_command->operand(1).type == (otMemory | otRegistr | otValue) && next_command->operand(1).registr == regEDI) { + uint64_t address = base_address + next_command->operand(1).value; + for (std::map::const_iterator it = iat_info.begin(); it != iat_info.end(); it++) { + if (it->first->address() == address) { + if (it->first->symbol()->bind() == STB_LOCAL) { + next_command->Init(cmLea, next_command->operand(0), next_command->operand(1)); + link = next_command->AddLink(1, ltGateOffset, it->first->symbol()->value()); + link->set_sub_value(base_address); + } + break; + } + } + } else if (command->type() == cmRet) { + break; + } + } + } + } + + if (!dst_link) { + // search references to LoaderAlloc/LoaderFree/FreeImage + for (k = 0; k < 2; k++) { + IntelOperand operand = command->operand(k); + if (operand.type == otNone) + break; + + if (cpu_address_size() == osDWord) { + if (!operand.fixup) + continue; + } else { + if (!operand.is_large_value) + continue; + } + if (command->address() + command->original_dump_size() == operand.value) + continue; + + dst_command = reinterpret_cast(GetCommandByAddress(operand.value)); + if (dst_command && !dst_command->is_data()) { + dst_link = command->AddLink((int)k, dst_command->block() ? ltOffset : ltGateOffset, dst_command); + break; + } + } + } else { + if (dst_link->to_address()) + dst_link->set_to_command(GetCommandByAddress(dst_link->to_address())); + } + } + setup_image_entry = GetCommandByAddress(runtime->export_list()->GetAddressByType(atSetupImage)); + if (!setup_image_entry) + return false; + + free_image_entry = GetCommandByAddress(runtime->export_list()->GetAddressByType(atFreeImage)); + if (!free_image_entry) + return false; + + // create entry command + for (i = 0; i < 2; i++) { + uint64_t jmp_address; + if (i == 0) + jmp_address = file->entry_point(); + else { + if (file->file_type() == ET_EXEC) + continue; + + ELFDirectory *dir = file->command_list()->GetCommandByType(DT_INIT); + jmp_address = dir ? dir->value() : 0; + } + + old_count = count(); + AddCommand(cmPush, IntelOperand(otRegistr, cpu_address_size(), regEBP)); + AddCommand(cmPush, IntelOperand(otRegistr, cpu_address_size(), regEDX)); + AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size(), regEBP), IntelOperand(otRegistr, cpu_address_size(), regESP)); + AddCommand(cmAnd, IntelOperand(otRegistr, cpu_address_size(), regESP), IntelOperand(otValue, cpu_address_size(), 0, -0x10)); + + // call SetupImage + command = AddCommand(cmCall, IntelOperand(otValue, cpu_address_size())); + command->AddLink(0, ltCall, setup_image_entry); + + // check loader error code + AddCommand(cmCmp, IntelOperand(otRegistr, osDWord, regEAX), IntelOperand(otValue, osDWord, 0, TRUE)); + IntelCommand *check_loader_command = AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size())); + check_loader_command->set_flags(fl_Z); + check_loader_command->AddLink(0, ltJmpWithFlag); + + // call FreeImage + command = AddCommand(cmCall, IntelOperand(otValue, cpu_address_size())); + command->AddLink(0, ltCall, free_image_entry); + + command = AddCommand(cmNop); + check_loader_command->link()->set_to_command(command); + + AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size(), regESP), IntelOperand(otRegistr, cpu_address_size(), regEBP)); + AddCommand(cmPop, IntelOperand(otRegistr, cpu_address_size(), regEDX)); + AddCommand(cmPop, IntelOperand(otRegistr, cpu_address_size(), regEBP)); + + if (jmp_address) { + command = AddCommand(cmJmp, IntelOperand(otValue, cpu_address_size(), 0, jmp_address)); + command->AddLink(0, ltJmp, jmp_address); + } else { + AddCommand(cmRet); + } + + if (i == 0) + set_entry(item(old_count)); + else + init_entry_->link()->set_to_command(item(old_count)); + } + + // create preinit command + if (preinit_entry_) { + old_count = count(); + AddCommand(cmPush, IntelOperand(otRegistr, cpu_address_size(), regEBP)); + AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size(), regEBP), IntelOperand(otRegistr, cpu_address_size(), regESP)); + AddCommand(cmAnd, IntelOperand(otRegistr, cpu_address_size(), regESP), IntelOperand(otValue, cpu_address_size(), 0, -0x10)); + + // call SetupImage + command = AddCommand(cmCall, IntelOperand(otValue, cpu_address_size())); + command->AddLink(0, ltCall, setup_image_entry); + + // check loader error code + AddCommand(cmCmp, IntelOperand(otRegistr, osDWord, regEAX), IntelOperand(otValue, osDWord, 0, TRUE)); + IntelCommand *check_loader_command = AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size())); + check_loader_command->set_flags(fl_Z); + check_loader_command->AddLink(0, ltJmpWithFlag); + + // call FreeImage + command = AddCommand(cmCall, IntelOperand(otValue, cpu_address_size())); + command->AddLink(0, ltCall, free_image_entry); + + command = AddCommand(cmNop); + check_loader_command->link()->set_to_command(command); + + AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size(), regESP), IntelOperand(otRegistr, cpu_address_size(), regEBP)); + AddCommand(cmPop, IntelOperand(otRegistr, cpu_address_size(), regEBP)); + AddCommand(cmRet); + + preinit_entry_->link()->set_to_command(item(old_count)); + } + + // create term command + if (term_entry_) { + old_count = count(); + AddCommand(cmPush, IntelOperand(otRegistr, cpu_address_size(), regEBP)); + AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size(), regEBP), IntelOperand(otRegistr, cpu_address_size(), regESP)); + AddCommand(cmAnd, IntelOperand(otRegistr, cpu_address_size(), regESP), IntelOperand(otValue, cpu_address_size(), 0, -0x10)); + + ELFDirectory *fini = file->command_list()->GetCommandByType(DT_FINI); + if (fini) { + command = AddCommand(cmCall, IntelOperand(otValue, cpu_address_size(), 0, fini->value())); + command->AddLink(0, ltCall, fini->value()); + } + + // call FreeImage + command = AddCommand(cmCall, IntelOperand(otValue, cpu_address_size())); + command->AddLink(0, ltCall, free_image_entry); + + AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size(), regESP), IntelOperand(otRegistr, cpu_address_size(), regEBP)); + AddCommand(cmPop, IntelOperand(otRegistr, cpu_address_size(), regEBP)); + AddCommand(cmRet); + + term_entry_->link()->set_to_command(item(old_count)); + } + + for (i = 0; i < count(); i++) { + command = item(i); + command->CompileToNative(); + } + + for (i = 0; i < link_list()->count(); i++) { + CommandLink *link = link_list()->item(i); + if (link->from_command()->type() == cmCall && std::find(internal_entry_list.begin(), internal_entry_list.end(), link->to_command()) != internal_entry_list.end()) + reinterpret_cast(link->from_command())->include_option(roInternal); + link->from_command()->PrepareLink(ctx); + } + + return BaseIntelLoader::Prepare(ctx); +} + +bool ELFIntelLoader::Compile(const CompileContext &ctx) +{ + if (!BaseIntelLoader::Compile(ctx)) + return false; + + return true; +} + +/** + * IntelVirtualMachine + */ + +IntelVirtualMachine::IntelVirtualMachine(IntelVirtualMachineList *owner, VirtualMachineType type, uint8_t id, IntelVirtualMachineProcessor *processor) + : BaseVirtualMachine(owner, id), type_(type), processor_(processor), entry_command_(NULL), init_command_(NULL), ext_jmp_command_(NULL), command_cryptor_(NULL), + stack_registr_(0), pcode_registr_(0), jmp_registr_(0), crypt_registr_(0) +{ + backward_direction_ = (rand() & 1) == 0; +} + +IntelVirtualMachine::~IntelVirtualMachine() +{ + delete ext_jmp_command_; + delete command_cryptor_; + for (size_t i = 0; i < cryptor_list_.size(); i++) { + delete cryptor_list_[i]; + } +} + +void IntelVirtualMachine::Init(const CompileContext &ctx, const IntelOpcodeList &visible_opcode_list) +{ + InitCommands(ctx, visible_opcode_list); + + opcode_stack_.clear(); + for (size_t i = 0; i < opcode_list_.count(); i++) { + IntelOpcodeInfo *item = opcode_list_.item(i); + opcode_stack_[item->Key()].push_back(item); + } +} + +void IntelVirtualMachine::Prepare(const CompileContext &ctx) +{ + size_t i; + std::vector virtual_machine_list; + OperandSize cpu_address_size = processor_->cpu_address_size(); + for (i = 0; i < ctx.file->virtual_machine_list()->count(); i++) { + IntelVirtualMachine *virtual_machine = reinterpret_cast(ctx.file->virtual_machine_list())->item(i); + if (virtual_machine->processor()->cpu_address_size() == cpu_address_size) + virtual_machine_list.push_back(virtual_machine); + } + + // setup VMs cross references + for (i = 0; i < vm_links_.size(); i++) { + IntelVirtualMachine *virtual_machine = virtual_machine_list[i]; + + IntelCommand *command = vm_links_[i]; + command->link()->set_to_command(virtual_machine->init_command()); + + size_t j = processor_->IndexOf(command); + uint8_t stack_registr = stack_registr_; + uint8_t pcode_registr = processor_->item(j - 2)->operand(0).registr; + if (virtual_machine->pcode_registr_ != pcode_registr) { + if (virtual_machine->pcode_registr_ == stack_registr_) { + command = new IntelCommand(processor_, cpu_address_size, cmXchg, IntelOperand(otRegistr, cpu_address_size, virtual_machine->pcode_registr_), IntelOperand(otRegistr, cpu_address_size, pcode_registr)); + stack_registr = pcode_registr; + } else + command = new IntelCommand(processor_, cpu_address_size, cmMov, IntelOperand(otRegistr, cpu_address_size, virtual_machine->pcode_registr_), IntelOperand(otRegistr, cpu_address_size, pcode_registr)); + command->CompileToNative(); + processor_->InsertObject(j++, command); + } + if (virtual_machine->stack_registr_ != stack_registr) { + command = new IntelCommand(processor_, cpu_address_size, cmMov, IntelOperand(otRegistr, cpu_address_size, virtual_machine->stack_registr_), IntelOperand(otRegistr, cpu_address_size, stack_registr)); + command->CompileToNative(); + processor_->InsertObject(j, command); + } + } +} + +IntelCommand *IntelVirtualMachine::AddReadCommand(OperandSize size, OpcodeCryptor *command_cryptor, uint8_t registr) +{ + size_t c = processor_->count(); + OperandSize mov_size = (size < osDWord) ? osDWord : size; + if (backward_direction_) { + processor_->AddCommand(cmSub, IntelOperand(otRegistr, processor_->cpu_address_size(), pcode_registr_), IntelOperand(otValue, processor_->cpu_address_size(), 0, OperandSizeToValue(size))); + processor_->AddCommand((mov_size == size) ? cmMov : cmMovzx, IntelOperand(otRegistr, mov_size, registr), IntelOperand(otMemory | otRegistr, size, pcode_registr_)); + } + else { + processor_->AddCommand((mov_size == size) ? cmMov : cmMovzx, IntelOperand(otRegistr, mov_size, registr), IntelOperand(otMemory | otRegistr, size, pcode_registr_)); + processor_->AddCommand(cmAdd, IntelOperand(otRegistr, processor_->cpu_address_size(), pcode_registr_), IntelOperand(otValue, processor_->cpu_address_size(), 0, OperandSizeToValue(size))); + } + + if (command_cryptor) { + IntelCommandType command_type = CryptorCommandToIntel(command_cryptor->type()); + OperandSize size = command_cryptor->size(); + + processor_->AddCommand(command_type, IntelOperand(otRegistr, size, registr), IntelOperand(otRegistr, size, crypt_registr_)); + for (size_t i = 0; i < command_cryptor->count(); i++) { + AddValueCommand(*command_cryptor->item(i), false, registr); + } + if (processor_->cpu_address_size() == osQWord && size == osDWord) { + processor_->AddCommand(cmPush, IntelOperand(otRegistr, osQWord, crypt_registr_)); + processor_->AddCommand(command_type, IntelOperand(otMemory | otRegistr, size, regESP), IntelOperand(otRegistr, size, registr)); + processor_->AddCommand(cmPop, IntelOperand(otRegistr, osQWord, crypt_registr_)); + } + else { + processor_->AddCommand(command_type, IntelOperand(otRegistr, size, crypt_registr_), IntelOperand(otRegistr, size, registr)); + } + } + + return processor_->item(c); +} + +void IntelVirtualMachine::AddValueCommand(ValueCommand &value_command, bool is_decrypt, uint8_t registr) +{ + IntelCommandType command_type = CryptorCommandToIntel(value_command.type(is_decrypt)); + IntelOperand second_operand; + if (command_type == cmAdd || command_type == cmSub || command_type == cmXor || command_type == cmRol || command_type == cmRor) + second_operand = IntelOperand(otValue, (command_type == cmRol || command_type == cmRor) ? osByte : value_command.size(), 0, value_command.value()); + processor_->AddCommand(command_type, IntelOperand(otRegistr, value_command.size(), registr), second_operand); +} + +void IntelVirtualMachine::AddEndHandlerCommands(IntelCommand *to_command, OpcodeCryptor *command_cryptor) +{ + IntelCommand *command; + if (type_ == vtAdvanced) { + IntelRegistrList registr_list = free_registr_list_; + uint8_t reg1 = registr_list.GetRandom(); + AddReadCommand(osDWord, command_cryptor, reg1); + if (processor_->cpu_address_size() == osQWord) + processor_->AddCommand(cmMovsxd, IntelOperand(otRegistr, processor_->cpu_address_size(), reg1), IntelOperand(otRegistr, osDWord, reg1)); + processor_->AddCommand(cmAdd, IntelOperand(otRegistr, processor_->cpu_address_size(), jmp_registr_), IntelOperand(otRegistr, processor_->cpu_address_size(), reg1)); + if (to_command) { + command = processor_->AddCommand(cmJmp, IntelOperand(otValue, processor_->cpu_address_size())); + command->AddLink(0, ltJmp, to_command); + } + else { + command = processor_->AddCommand(cmJmp, IntelOperand(otRegistr, processor_->cpu_address_size(), jmp_registr_)); + command->AddLink(-1, ltJmp); + } + } + else { + command = processor_->AddCommand(cmJmp, IntelOperand(otValue, processor_->cpu_address_size())); + command->AddLink(0, ltJmp, to_command); + } +} + +IntelCommand *IntelVirtualMachine::CloneHandler(IntelCommand *handler) +{ + size_t i, c, j; + std::map command_map; + + c = processor_->count(); + j = processor_->IndexOf(handler); + for (i = j; i < c; i++) { + IntelCommand *src_command = processor_->item(i); + IntelCommand *dst_command = src_command->Clone(processor_); + processor_->AddObject(dst_command); + + command_map[src_command] = dst_command; + + CommandLink *src_link = src_command->link(); + if (src_link) { + CommandLink *dst_link = src_link->Clone(processor_->link_list()); + dst_link->set_from_command(dst_command); + dst_link->set_to_command(src_link->to_command()); + processor_->link_list()->AddObject(dst_link); + } + + if (src_command->type() == cmJmp && src_link && src_link->to_command()) { + if (j > processor_->IndexOf(src_link->to_command())) + break; + } + else if (src_command->is_end()) + break; + } + + for (i = c; i < processor_->count(); i++) { + IntelCommand *command = processor_->item(i); + CommandLink *link = command->link(); + if (!link || !link->to_command()) + continue; + + std::map::const_iterator it = command_map.find(link->to_command()); + if (it != command_map.end()) + link->set_to_command(it->second); + } + + return processor_->item(c); +} + +void IntelVirtualMachine::AddCallCommands(CallingConvention calling_convention, IntelCommand *call_entry, uint8_t registr) +{ + std::vector registr_list; + IntelCommand *command; + size_t i; + + OperandSize cpu_address_size = processor_->cpu_address_size(); + OperandSize arg_address_size = (calling_convention == ccStdcallToMSx64) ? osDWord : processor_->cpu_address_size(); + + switch (calling_convention) { //-V719 + case ccMSx64: + case ccStdcallToMSx64: + registr_list.push_back(regECX); + registr_list.push_back(regEDX); + registr_list.push_back(regR8); + registr_list.push_back(regR9); + break; + case ccABIx64: + registr_list.push_back(regEDI); + registr_list.push_back(regESI); + registr_list.push_back(regEDX); + registr_list.push_back(regECX); + registr_list.push_back(regR8); + registr_list.push_back(regR9); + break; + } + + // push common registers + processor_->AddCommand(cmPush, IntelOperand(otRegistr, cpu_address_size, pcode_registr_)); + if (jmp_registr_) + processor_->AddCommand(cmPush, IntelOperand(otRegistr, cpu_address_size, jmp_registr_)); + if (crypt_registr_) + processor_->AddCommand(cmPush, IntelOperand(otRegistr, cpu_address_size, crypt_registr_)); + if (stack_registr_ != regEBP) + processor_->AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size, regEBP), IntelOperand(otRegistr, cpu_address_size, stack_registr_)); + + if (registr != regEBX) + processor_->AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regEBX), IntelOperand(otRegistr, osDWord, registr)); + processor_->AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regEDX), IntelOperand(otRegistr, osDWord, regEBX)); + if (!registr_list.empty()) { + processor_->AddCommand(cmXor, IntelOperand(otRegistr, osDWord, regECX), IntelOperand(otRegistr, osDWord, regECX)); + processor_->AddCommand(cmCmp, IntelOperand(otRegistr, osDWord, regEBX), IntelOperand(otValue, osDWord, 0, registr_list.size())); + IntelCommand *jmp_no_stack_args = processor_->AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size)); + jmp_no_stack_args->set_flags(fl_C | fl_Z); + jmp_no_stack_args->AddLink(0, ltJmpWithFlag); + if (calling_convention != ccStdcallToMSx64) + processor_->AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regEDX), IntelOperand(otValue, osDWord, 0, registr_list.size())); + processor_->AddCommand(cmLea, IntelOperand(otRegistr, osDWord, regECX), IntelOperand(otMemory | otRegistr | otValue, osDWord, regEBX, 0 - registr_list.size())); + command = processor_->AddCommand(cmShl, IntelOperand(otRegistr, osDWord, regECX), IntelOperand(otValue, osByte, 0, cpu_address_size == osDWord ? 2 : 3)); + jmp_no_stack_args->link()->set_to_command(command); + } + processor_->AddCommand(cmShl, IntelOperand(otRegistr, osDWord, regEDX), IntelOperand(otValue, osByte, 0, arg_address_size == osDWord ? 2 : 3)); + if (calling_convention != ccCdecl) { + processor_->AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size, regEAX), IntelOperand(otRegistr, cpu_address_size, regEBP)); + processor_->AddCommand(cmAdd, IntelOperand(otRegistr, cpu_address_size, regEAX), IntelOperand(otRegistr, cpu_address_size, regEDX)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otBaseRegistr | otValue, cpu_address_size, regEBP << 4, 0 - OperandSizeToValue(cpu_address_size)), IntelOperand(otRegistr, cpu_address_size, regEAX)); + } + if (calling_convention != ccStdcall) { + // align stack + processor_->AddCommand(cmMov, IntelOperand(otMemory | otBaseRegistr | otValue, cpu_address_size, regEBP << 4, 0 - OperandSizeToValue(cpu_address_size) * 2), IntelOperand(otRegistr, cpu_address_size, regESP)); + processor_->AddCommand(cmSub, IntelOperand(otRegistr, cpu_address_size, regESP), IntelOperand(otRegistr, cpu_address_size, registr_list.empty() ? regEDX : regECX)); + processor_->AddCommand(cmAnd, IntelOperand(otRegistr, cpu_address_size, regESP), IntelOperand(otValue, cpu_address_size, 0, -16)); + processor_->AddCommand(cmAdd, IntelOperand(otRegistr, cpu_address_size, regESP), IntelOperand(otRegistr, cpu_address_size, registr_list.empty() ? regEDX : regECX)); + } else if (call_entry) + processor_->AddCommand(cmMov, IntelOperand(otMemory | otBaseRegistr | otValue, cpu_address_size, regEBP << 4, 0 - OperandSizeToValue(cpu_address_size) * 2), IntelOperand(otRegistr, cpu_address_size, regESP)); + + processor_->AddCommand(cmTest, IntelOperand(otRegistr, osDWord, regEBX), IntelOperand(otRegistr, osDWord, regEBX)); + IntelCommand *jmp_end_store = processor_->AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size)); + jmp_end_store->set_flags(fl_Z); + jmp_end_store->AddLink(0, ltJmpWithFlag); + + IntelCommand *load_arg = processor_->AddCommand(cmMov, IntelOperand(otRegistr, arg_address_size, regEAX), IntelOperand(otMemory | otBaseRegistr | otRegistr | otValue, arg_address_size, (regEBP << 4) | regEBX)); + load_arg->set_operand_scale(1, arg_address_size == osDWord ? 2 : 3); + + std::vector jmp_loop_arg; + IntelCommand *jmp_arg_command = NULL; + if (!registr_list.empty()) { + // store arg in register + for (i = 0; i < registr_list.size(); i++) { + command = processor_->AddCommand(cmCmp, IntelOperand(otRegistr, osDWord, regEBX), IntelOperand(otValue, osDWord, 0, i + 1)); + if (jmp_arg_command) + jmp_arg_command->link()->set_to_command(command); + + jmp_arg_command = processor_->AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size)); + jmp_arg_command->set_flags(fl_Z); + jmp_arg_command->include_option(roInverseFlag); + jmp_arg_command->AddLink(0, ltJmpWithFlag); + + processor_->AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size, registr_list[i]), IntelOperand(otRegistr, cpu_address_size, regEAX)); + command = processor_->AddCommand(cmJmp, IntelOperand(otValue, cpu_address_size)); + command->AddLink(0, ltJmp); + jmp_loop_arg.push_back(command); + } + } + + // store arg in stack + if (calling_convention == ccMSx64) { + command = processor_->AddCommand(cmPush, IntelOperand(otMemory | otBaseRegistr | otRegistr | otValue, cpu_address_size, (regEBP << 4) | regEBX, 0x20)); + command->set_operand_scale(0, 3); + } else + command = processor_->AddCommand(cmPush, IntelOperand(otRegistr, cpu_address_size, regEAX)); + if (jmp_arg_command) + jmp_arg_command->link()->set_to_command(command); + + // loop arg + command = processor_->AddCommand(cmSub, IntelOperand(otRegistr, osDWord, regEBX), IntelOperand(otValue, osDWord, 0, 1)); + for (i = 0; i < jmp_loop_arg.size(); i++) { + jmp_loop_arg[i]->link()->set_to_command(command); + } + command = processor_->AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size)); + command->set_flags(fl_Z); + command->include_option(roInverseFlag); + command->AddLink(0, ltJmpWithFlag, load_arg); + + // end store + command = processor_->AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size, regEAX), IntelOperand(otMemory | otBaseRegistr | otValue, cpu_address_size, regEBP << 4, 0)); + jmp_end_store->link()->set_to_command(command); + + if (calling_convention == ccStdcallToMSx64) { + // convert input args + std::vector jmp_end_convert; + processor_->AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regR10), IntelOperand(otRegistr, osDWord, regEAX)); + processor_->AddCommand(cmShr, IntelOperand(otRegistr, osDWord, regR10), IntelOperand(otValue, osByte, 0, 24)); + IntelCommand *jmp_command = processor_->AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size)); + jmp_command->set_flags(fl_Z); + jmp_command->AddLink(0, ltJmpWithFlag); + jmp_end_convert.push_back(jmp_command); + + // NtProtectVirtualMemory + processor_->AddCommand(cmCmp, IntelOperand(otRegistr, osByte, regR10), IntelOperand(otValue, osByte, 0, 1)); + IntelCommand *cmp_command = processor_->AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size)); + cmp_command->set_flags(fl_Z); + cmp_command->include_option(roInverseFlag); + cmp_command->AddLink(0, ltJmpWithFlag); + + processor_->AddCommand(cmCmp, IntelOperand(otRegistr, osDWord, regECX), IntelOperand(otValue, osDWord, 0, (uint32_t)-1)); // NtCurrentProcess + jmp_command = processor_->AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size)); + jmp_command->set_flags(fl_Z); + jmp_command->include_option(roInverseFlag); + jmp_command->AddLink(0, ltJmpWithFlag); + processor_->AddCommand(cmMovsxd, IntelOperand(otRegistr, osQWord, regECX), IntelOperand(otRegistr, osDWord, regECX)); + + command = processor_->AddCommand(cmTest, IntelOperand(otRegistr, osDWord, regEDX), IntelOperand(otRegistr, osDWord, regEDX)); + jmp_command->link()->set_to_command(command); + jmp_command = processor_->AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size)); + jmp_command->set_flags(fl_Z); + jmp_command->AddLink(0, ltJmpWithFlag); + processor_->AddCommand(cmLea, IntelOperand(otRegistr, cpu_address_size, regR10), IntelOperand(otMemory | otBaseRegistr | otValue, cpu_address_size, regEBP << 4, 0 - OperandSizeToValue(cpu_address_size) * 3)); + processor_->AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regEDX), IntelOperand(otMemory | otRegistr, osDWord, regEDX)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr, cpu_address_size, regR10), IntelOperand(otRegistr, cpu_address_size, regEDX)); + processor_->AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size, regEDX), IntelOperand(otRegistr, cpu_address_size, regR10)); + + command = processor_->AddCommand(cmTest, IntelOperand(otRegistr, osDWord, regR8), IntelOperand(otRegistr, osDWord, regR8)); + jmp_command->link()->set_to_command(command); + jmp_command = processor_->AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size)); + jmp_command->set_flags(fl_Z); + jmp_command->AddLink(0, ltJmpWithFlag); + processor_->AddCommand(cmLea, IntelOperand(otRegistr, cpu_address_size, regR10), IntelOperand(otMemory | otBaseRegistr | otValue, cpu_address_size, regEBP << 4, 0 - OperandSizeToValue(cpu_address_size) * 4)); + processor_->AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regR8), IntelOperand(otMemory | otRegistr, osDWord, regR8)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr, cpu_address_size, regR10), IntelOperand(otRegistr, cpu_address_size, regR8)); + processor_->AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size, regR8), IntelOperand(otRegistr, cpu_address_size, regR10)); + command = processor_->AddCommand(cmJmp, IntelOperand(otValue, cpu_address_size)); + jmp_command->link()->set_to_command(command); + command->AddLink(0, ltJmp); + jmp_end_convert.push_back(command); + + // NtSetInformationThread + command = processor_->AddCommand(cmCmp, IntelOperand(otRegistr, osByte, regR10), IntelOperand(otValue, osByte, 0, 2)); + cmp_command->link()->set_to_command(command); + cmp_command = processor_->AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size)); + cmp_command->set_flags(fl_Z); + cmp_command->include_option(roInverseFlag); + cmp_command->AddLink(0, ltJmpWithFlag); + + processor_->AddCommand(cmCmp, IntelOperand(otRegistr, osDWord, regECX), IntelOperand(otValue, osDWord, 0, (uint32_t)-2)); // NtCurrentThread + jmp_command = processor_->AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size)); + jmp_command->set_flags(fl_Z); + jmp_command->include_option(roInverseFlag); + jmp_command->AddLink(0, ltJmpWithFlag); + processor_->AddCommand(cmMovsxd, IntelOperand(otRegistr, osQWord, regECX), IntelOperand(otRegistr, osDWord, regECX)); + command = processor_->AddCommand(cmJmp, IntelOperand(otValue, cpu_address_size)); + jmp_command->link()->set_to_command(command); + command->AddLink(0, ltJmp); + jmp_end_convert.push_back(command); + + // NtQueryInformationProcess + command = processor_->AddCommand(cmCmp, IntelOperand(otRegistr, osByte, regR10), IntelOperand(otValue, osByte, 0, 3)); + cmp_command->link()->set_to_command(command); + cmp_command = processor_->AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size)); + cmp_command->set_flags(fl_Z); + cmp_command->include_option(roInverseFlag); + cmp_command->AddLink(0, ltJmpWithFlag); + + processor_->AddCommand(cmCmp, IntelOperand(otRegistr, osDWord, regECX), IntelOperand(otValue, osDWord, 0, (uint32_t)-1)); // NtCurrentProcess + jmp_command = processor_->AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size)); + jmp_command->set_flags(fl_Z); + jmp_command->include_option(roInverseFlag); + jmp_command->AddLink(0, ltJmpWithFlag); + processor_->AddCommand(cmMovsxd, IntelOperand(otRegistr, osQWord, regECX), IntelOperand(otRegistr, osDWord, regECX)); + + command = processor_->AddCommand(cmCmp, IntelOperand(otRegistr, osDWord, regEDX), IntelOperand(otValue, osDWord, 0, 0x7)); // ProcessDebugPort + jmp_command->link()->set_to_command(command); + jmp_command = processor_->AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size)); + jmp_command->set_flags(fl_Z); + jmp_command->include_option(roInverseFlag); + jmp_command->AddLink(0, ltJmpWithFlag); + processor_->AddCommand(cmLea, IntelOperand(otRegistr, cpu_address_size, regR10), IntelOperand(otMemory | otBaseRegistr | otValue, cpu_address_size, regEBP << 4, 0 - OperandSizeToValue(cpu_address_size) * 3)); + processor_->AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size, regR8), IntelOperand(otRegistr, cpu_address_size, regR10)); + processor_->AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regR9), IntelOperand(otValue, osDWord, 0, OperandSizeToValue(cpu_address_size))); + command = processor_->AddCommand(cmJmp, IntelOperand(otValue, cpu_address_size)); + command->AddLink(0, ltJmp); + jmp_end_convert.push_back(command); + + command = processor_->AddCommand(cmCmp, IntelOperand(otRegistr, osDWord, regEDX), IntelOperand(otValue, osDWord, 0, 0x1e)); // ProcessDebugObjectHandle + jmp_command->link()->set_to_command(command); + jmp_command = processor_->AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size)); + jmp_command->set_flags(fl_Z); + jmp_command->include_option(roInverseFlag); + jmp_command->AddLink(0, ltJmpWithFlag); + processor_->AddCommand(cmLea, IntelOperand(otRegistr, cpu_address_size, regR10), IntelOperand(otMemory | otBaseRegistr | otValue, cpu_address_size, regEBP << 4, 0 - OperandSizeToValue(cpu_address_size) * 3)); + processor_->AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size, regR8), IntelOperand(otRegistr, cpu_address_size, regR10)); + processor_->AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regR9), IntelOperand(otValue, osDWord, 0, OperandSizeToValue(cpu_address_size))); + command = processor_->AddCommand(cmJmp, IntelOperand(otValue, cpu_address_size)); + jmp_command->link()->set_to_command(command); + command->AddLink(0, ltJmp); + jmp_end_convert.push_back(command); + + // NtMapViewOfSection + command = processor_->AddCommand(cmCmp, IntelOperand(otRegistr, osByte, regR10), IntelOperand(otValue, osByte, 0, 4)); + cmp_command->link()->set_to_command(command); + cmp_command = processor_->AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size)); + cmp_command->set_flags(fl_Z); + cmp_command->include_option(roInverseFlag); + cmp_command->AddLink(0, ltJmpWithFlag); + + processor_->AddCommand(cmCmp, IntelOperand(otRegistr, osDWord, regEDX), IntelOperand(otValue, osDWord, 0, (uint32_t)-1)); // NtCurrentProcess + jmp_command = processor_->AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size)); + jmp_command->set_flags(fl_Z); + jmp_command->include_option(roInverseFlag); + jmp_command->AddLink(0, ltJmpWithFlag); + processor_->AddCommand(cmMovsxd, IntelOperand(otRegistr, osQWord, regEDX), IntelOperand(otRegistr, osDWord, regEDX)); + + command = processor_->AddCommand(cmTest, IntelOperand(otRegistr, osDWord, regR8), IntelOperand(otRegistr, osDWord, regR8)); + jmp_command->link()->set_to_command(command); + jmp_command = processor_->AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size)); + jmp_command->set_flags(fl_Z); + jmp_command->AddLink(0, ltJmpWithFlag); + processor_->AddCommand(cmLea, IntelOperand(otRegistr, cpu_address_size, regR10), IntelOperand(otMemory | otBaseRegistr | otValue, cpu_address_size, regEBP << 4, 0 - OperandSizeToValue(cpu_address_size) * 3)); + processor_->AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regR8), IntelOperand(otMemory | otRegistr, osDWord, regR8)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr, cpu_address_size, regR10), IntelOperand(otRegistr, cpu_address_size, regR8)); + processor_->AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size, regR8), IntelOperand(otRegistr, cpu_address_size, regR10)); + + command = processor_->AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regR11), IntelOperand(otMemory | otRegistr | otValue, cpu_address_size, regESP, OperandSizeToValue(cpu_address_size) * 2)); + processor_->AddCommand(cmTest, IntelOperand(otRegistr, osDWord, regR11), IntelOperand(otRegistr, osDWord, regR11)); + jmp_command->link()->set_to_command(command); + jmp_command = processor_->AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size)); + jmp_command->set_flags(fl_Z); + jmp_command->AddLink(0, ltJmpWithFlag); + processor_->AddCommand(cmLea, IntelOperand(otRegistr, cpu_address_size, regR10), IntelOperand(otMemory | otBaseRegistr | otValue, cpu_address_size, regEBP << 4, 0 - OperandSizeToValue(cpu_address_size) * 4)); + processor_->AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regR11), IntelOperand(otMemory | otRegistr, osDWord, regR11)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr, cpu_address_size, regR10), IntelOperand(otRegistr, cpu_address_size, regR11)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr | otValue, cpu_address_size, regESP, OperandSizeToValue(cpu_address_size) * 2), IntelOperand(otRegistr, cpu_address_size, regR10)); + command = processor_->AddCommand(cmJmp, IntelOperand(otValue, cpu_address_size)); + jmp_command->link()->set_to_command(command); + command->AddLink(0, ltJmp); + jmp_end_convert.push_back(command); + + // NtUnmapViewOfSection + command = processor_->AddCommand(cmCmp, IntelOperand(otRegistr, osByte, regR10), IntelOperand(otValue, osByte, 0, 5)); + cmp_command->link()->set_to_command(command); + cmp_command = processor_->AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size)); + cmp_command->set_flags(fl_Z); + cmp_command->include_option(roInverseFlag); + cmp_command->AddLink(0, ltJmpWithFlag); + + processor_->AddCommand(cmCmp, IntelOperand(otRegistr, osDWord, regECX), IntelOperand(otValue, osDWord, 0, (uint32_t)-1)); // NtCurrentProcess + jmp_command = processor_->AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size)); + jmp_command->set_flags(fl_Z); + jmp_command->include_option(roInverseFlag); + jmp_command->AddLink(0, ltJmpWithFlag); + processor_->AddCommand(cmMovsxd, IntelOperand(otRegistr, osQWord, regECX), IntelOperand(otRegistr, osDWord, regECX)); + command = processor_->AddCommand(cmJmp, IntelOperand(otValue, cpu_address_size)); + jmp_command->link()->set_to_command(command); + command->AddLink(0, ltJmp); + jmp_end_convert.push_back(command); + + // NtOpenFile + command = processor_->AddCommand(cmCmp, IntelOperand(otRegistr, osByte, regR10), IntelOperand(otValue, osByte, 0, 6)); + cmp_command->link()->set_to_command(command); + cmp_command = processor_->AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size)); + cmp_command->set_flags(fl_Z); + cmp_command->include_option(roInverseFlag); + cmp_command->AddLink(0, ltJmpWithFlag); + + command = processor_->AddCommand(cmTest, IntelOperand(otRegistr, osDWord, regECX), IntelOperand(otRegistr, osDWord, regECX)); + jmp_command->link()->set_to_command(command); + jmp_command = processor_->AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size)); + jmp_command->set_flags(fl_Z); + jmp_command->AddLink(0, ltJmpWithFlag); + processor_->AddCommand(cmLea, IntelOperand(otRegistr, cpu_address_size, regECX), IntelOperand(otMemory | otBaseRegistr | otValue, cpu_address_size, regEBP << 4, 0 - OperandSizeToValue(cpu_address_size) * 3)); + + command = processor_->AddCommand(cmTest, IntelOperand(otRegistr, osDWord, regR9), IntelOperand(otRegistr, osDWord, regR9)); + jmp_command->link()->set_to_command(command); + jmp_command = processor_->AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size)); + jmp_command->set_flags(fl_Z); + jmp_command->AddLink(0, ltJmpWithFlag); + processor_->AddCommand(cmLea, IntelOperand(otRegistr, cpu_address_size, regR9), IntelOperand(otMemory | otBaseRegistr | otValue, cpu_address_size, regEBP << 4, 0 - OperandSizeToValue(cpu_address_size) * 5)); + + command = processor_->AddCommand(cmTest, IntelOperand(otRegistr, osDWord, regR8), IntelOperand(otRegistr, osDWord, regR8)); + jmp_command->link()->set_to_command(command); + jmp_command = processor_->AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size)); + jmp_command->set_flags(fl_Z); + jmp_command->AddLink(0, ltJmpWithFlag); + processor_->AddCommand(cmLea, IntelOperand(otRegistr, cpu_address_size, regR10), IntelOperand(otMemory | otBaseRegistr | otValue, cpu_address_size, regEBP << 4, 0 - OperandSizeToValue(cpu_address_size) * 10)); + processor_->AddCommand(cmAnd, IntelOperand(otRegistr, cpu_address_size, regR10), IntelOperand(otValue, cpu_address_size, 0, (uint64_t)-16)); + processor_->AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regR11), IntelOperand(otValue, osDWord, 0, 0x30)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr, osQWord, regR10), IntelOperand(otRegistr, osQWord, regR11)); + processor_->AddCommand(cmXor, IntelOperand(otRegistr, osDWord, regR11), IntelOperand(otRegistr, osDWord, regR11)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr | otValue, osQWord, regR10, 0x08), IntelOperand(otRegistr, osQWord, regR11)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr | otValue, osQWord, regR10, 0x10), IntelOperand(otRegistr, osQWord, regR11)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr | otValue, osQWord, regR10, 0x20), IntelOperand(otRegistr, osQWord, regR11)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr | otValue, osQWord, regR10, 0x28), IntelOperand(otRegistr, osQWord, regR11)); + processor_->AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regR11), IntelOperand(otMemory | otRegistr | otValue, osDWord, regR8, 0x0c)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr | otValue, osQWord, regR10, 0x18), IntelOperand(otRegistr, osQWord, regR11)); + processor_->AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regR11), IntelOperand(otMemory | otRegistr | otValue, osDWord, regR8, 0x08)); + processor_->AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size, regR8), IntelOperand(otRegistr, cpu_address_size, regR10)); + + processor_->AddCommand(cmTest, IntelOperand(otRegistr, osDWord, regR11), IntelOperand(otRegistr, osDWord, regR11)); + IntelCommand *jmp_command2 = processor_->AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size)); + jmp_command2->set_flags(fl_Z); + jmp_command2->AddLink(0, ltJmpWithFlag); + + processor_->AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regR10), IntelOperand(otMemory | otRegistr, osDWord, regR11)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr | otValue, osQWord, regR8, 0 - OperandSizeToValue(cpu_address_size) * 2), IntelOperand(otRegistr, osQWord, regR10)); + processor_->AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regR10), IntelOperand(otMemory | otRegistr | otValue, osDWord, regR11, 4)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr | otValue, osQWord, regR8, 0 - OperandSizeToValue(cpu_address_size)), IntelOperand(otRegistr, osQWord, regR10)); + processor_->AddCommand(cmLea, IntelOperand(otRegistr, cpu_address_size, regR10), IntelOperand(otMemory | otRegistr | otValue, cpu_address_size, regR8, 0 - OperandSizeToValue(cpu_address_size) * 2)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr | otValue, osQWord, regR8, 0x10), IntelOperand(otRegistr, osQWord, regR10)); + + command = processor_->AddCommand(cmJmp, IntelOperand(otValue, cpu_address_size)); + jmp_command->link()->set_to_command(command); + jmp_command2->link()->set_to_command(command); + command->AddLink(0, ltJmp); + jmp_end_convert.push_back(command); + + // NtCreateSection + command = processor_->AddCommand(cmCmp, IntelOperand(otRegistr, osByte, regR10), IntelOperand(otValue, osByte, 0, 7)); + cmp_command->link()->set_to_command(command); + cmp_command = processor_->AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size)); + cmp_command->set_flags(fl_Z); + cmp_command->include_option(roInverseFlag); + cmp_command->AddLink(0, ltJmpWithFlag); + + command = processor_->AddCommand(cmTest, IntelOperand(otRegistr, osDWord, regECX), IntelOperand(otRegistr, osDWord, regECX)); + jmp_command->link()->set_to_command(command); + jmp_command = processor_->AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size)); + jmp_command->set_flags(fl_Z); + jmp_command->AddLink(0, ltJmpWithFlag); + processor_->AddCommand(cmLea, IntelOperand(otRegistr, cpu_address_size, regECX), IntelOperand(otMemory | otBaseRegistr | otValue, cpu_address_size, regEBP << 4, 0 - OperandSizeToValue(cpu_address_size) * 3)); + + command = processor_->AddCommand(cmTest, IntelOperand(otRegistr, osDWord, regR8), IntelOperand(otRegistr, osDWord, regR8)); + jmp_command->link()->set_to_command(command); + jmp_command = processor_->AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size)); + jmp_command->set_flags(fl_Z); + jmp_command->AddLink(0, ltJmpWithFlag); + processor_->AddCommand(cmLea, IntelOperand(otRegistr, cpu_address_size, regR10), IntelOperand(otMemory | otBaseRegistr | otValue, cpu_address_size, regEBP << 4, 0 - OperandSizeToValue(cpu_address_size) * 8)); + processor_->AddCommand(cmAnd, IntelOperand(otRegistr, cpu_address_size, regR10), IntelOperand(otValue, cpu_address_size, 0, (uint64_t)-16)); + processor_->AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regR11), IntelOperand(otValue, osDWord, 0, 0x30)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr, osQWord, regR10), IntelOperand(otRegistr, osQWord, regR11)); + processor_->AddCommand(cmXor, IntelOperand(otRegistr, osDWord, regR11), IntelOperand(otRegistr, osDWord, regR11)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr | otValue, osQWord, regR10, 0x08), IntelOperand(otRegistr, osQWord, regR11)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr | otValue, osQWord, regR10, 0x10), IntelOperand(otRegistr, osQWord, regR11)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr | otValue, osQWord, regR10, 0x20), IntelOperand(otRegistr, osQWord, regR11)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr | otValue, osQWord, regR10, 0x28), IntelOperand(otRegistr, osQWord, regR11)); + processor_->AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regR11), IntelOperand(otMemory | otRegistr | otValue, osDWord, regR8, 0x0c)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr | otValue, osQWord, regR10, 0x18), IntelOperand(otRegistr, osQWord, regR11)); + processor_->AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regR11), IntelOperand(otMemory | otRegistr | otValue, osDWord, regR8, 0x08)); + processor_->AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size, regR8), IntelOperand(otRegistr, cpu_address_size, regR10)); + + processor_->AddCommand(cmTest, IntelOperand(otRegistr, osDWord, regR11), IntelOperand(otRegistr, osDWord, regR11)); + jmp_command2 = processor_->AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size)); + jmp_command2->set_flags(fl_Z); + jmp_command2->AddLink(0, ltJmpWithFlag); + + processor_->AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regR10), IntelOperand(otMemory | otRegistr, osDWord, regR11)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr | otValue, osQWord, regR8, 0 - OperandSizeToValue(cpu_address_size) * 2), IntelOperand(otRegistr, osQWord, regR10)); + processor_->AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regR10), IntelOperand(otMemory | otRegistr | otValue, osDWord, regR11, 4)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr | otValue, osQWord, regR8, 0 - OperandSizeToValue(cpu_address_size)), IntelOperand(otRegistr, osQWord, regR10)); + processor_->AddCommand(cmLea, IntelOperand(otRegistr, cpu_address_size, regR10), IntelOperand(otMemory | otRegistr | otValue, cpu_address_size, regR8, 0 - OperandSizeToValue(cpu_address_size) * 2)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr | otValue, osQWord, regR8, 0x10), IntelOperand(otRegistr, osQWord, regR10)); + + command = processor_->AddCommand(cmJmp, IntelOperand(otValue, cpu_address_size)); + jmp_command->link()->set_to_command(command); + jmp_command2->link()->set_to_command(command); + command->AddLink(0, ltJmp); + jmp_end_convert.push_back(command); + + // NtQueryVirtualMemory + command = processor_->AddCommand(cmCmp, IntelOperand(otRegistr, osByte, regR10), IntelOperand(otValue, osByte, 0, 8)); + cmp_command->link()->set_to_command(command); + cmp_command = processor_->AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size)); + cmp_command->set_flags(fl_Z); + cmp_command->include_option(roInverseFlag); + cmp_command->AddLink(0, ltJmpWithFlag); + + processor_->AddCommand(cmCmp, IntelOperand(otRegistr, osDWord, regECX), IntelOperand(otValue, osDWord, 0, (uint32_t)-1)); // NtCurrentProcess + jmp_command = processor_->AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size)); + jmp_command->set_flags(fl_Z); + jmp_command->include_option(roInverseFlag); + jmp_command->AddLink(0, ltJmpWithFlag); + processor_->AddCommand(cmMovsxd, IntelOperand(otRegistr, osQWord, regECX), IntelOperand(otRegistr, osDWord, regECX)); + + command = processor_->AddCommand(cmTest, IntelOperand(otRegistr, osDWord, regR9), IntelOperand(otRegistr, osDWord, regR9)); + jmp_command->link()->set_to_command(command); + jmp_command = processor_->AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size)); + jmp_command->set_flags(fl_Z); + jmp_command->AddLink(0, ltJmpWithFlag); + processor_->AddCommand(cmLea, IntelOperand(otRegistr, cpu_address_size, regR10), IntelOperand(otMemory | otBaseRegistr | otValue, cpu_address_size, regEBP << 4, 0 - OperandSizeToValue(cpu_address_size) * 8)); + processor_->AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size, regR9), IntelOperand(otRegistr, cpu_address_size, regR10)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr | otValue, osDWord, regESP), IntelOperand(otValue, osDWord, 0, 0x30)); + command = processor_->AddCommand(cmJmp, IntelOperand(otValue, cpu_address_size)); + jmp_command->link()->set_to_command(command); + command->AddLink(0, ltJmp); + jmp_end_convert.push_back(command); + + command = processor_->AddCommand(cmAnd, IntelOperand(otRegistr, osDWord, regEAX), IntelOperand(otValue, osDWord, 0, WOW64_FLAG - 1)); + cmp_command->link()->set_to_command(command); + for (i = 0; i < jmp_end_convert.size(); i++) { + jmp_end_convert[i]->link()->set_to_command(command); + } + } + + if (calling_convention == ccMSx64 || calling_convention == ccStdcallToMSx64) + processor_->AddCommand(cmSub, IntelOperand(otRegistr, cpu_address_size, regESP), IntelOperand(otValue, cpu_address_size, 0, 0x20)); + if (call_entry) { + command = processor_->AddCommand(cmCall, IntelOperand(otValue, cpu_address_size)); + command->AddLink(0, ltCall, call_entry); + } else + processor_->AddCommand(cmCall, IntelOperand(otRegistr, cpu_address_size, regEAX)); + + if (calling_convention == ccStdcallToMSx64) { + // convert output args + std::vector jmp_end_convert; + processor_->AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regR10), IntelOperand(otMemory | otBaseRegistr | otValue, osDWord, regEBP << 4, 0)); + processor_->AddCommand(cmShr, IntelOperand(otRegistr, osDWord, regR10), IntelOperand(otValue, osByte, 0, 24)); + IntelCommand *jmp_command = processor_->AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size)); + jmp_command->set_flags(fl_Z); + jmp_command->AddLink(0, ltJmpWithFlag); + jmp_end_convert.push_back(jmp_command); + + // NtProtectVirtualMemory + processor_->AddCommand(cmCmp, IntelOperand(otRegistr, osByte, regR10), IntelOperand(otValue, osByte, 0, 1)); + IntelCommand *cmp_command = processor_->AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size)); + cmp_command->set_flags(fl_Z); + cmp_command->include_option(roInverseFlag); + cmp_command->AddLink(0, ltJmpWithFlag); + + processor_->AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regECX), IntelOperand(otMemory | otBaseRegistr | otValue, arg_address_size, regEBP << 4, OperandSizeToValue(arg_address_size) * 2)); + processor_->AddCommand(cmTest, IntelOperand(otRegistr, osDWord, regECX), IntelOperand(otRegistr, osDWord, regECX)); + jmp_command = processor_->AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size)); + jmp_command->set_flags(fl_Z); + jmp_command->AddLink(0, ltJmpWithFlag); + processor_->AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regR10), IntelOperand(otMemory | otBaseRegistr | otValue, osDWord, regEBP << 4, 0 - OperandSizeToValue(cpu_address_size) * 3)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr, osDWord, regECX), IntelOperand(otRegistr, osDWord, regR10)); + + command = processor_->AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regECX), IntelOperand(otMemory | otBaseRegistr | otValue, arg_address_size, regEBP << 4, OperandSizeToValue(arg_address_size) * 3)); + jmp_command->link()->set_to_command(command); + processor_->AddCommand(cmTest, IntelOperand(otRegistr, osDWord, regECX), IntelOperand(otRegistr, osDWord, regECX)); + jmp_command = processor_->AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size)); + jmp_command->set_flags(fl_Z); + jmp_command->AddLink(0, ltJmpWithFlag); + + processor_->AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regR10), IntelOperand(otMemory | otBaseRegistr | otValue, osDWord, regEBP << 4, 0 - OperandSizeToValue(cpu_address_size) * 4)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr, osDWord, regECX), IntelOperand(otRegistr, osDWord, regR10)); + command = processor_->AddCommand(cmJmp, IntelOperand(otValue, cpu_address_size)); + jmp_command->link()->set_to_command(command); + command->AddLink(0, ltJmp); + jmp_end_convert.push_back(command); + + // NtQueryInformationProcess + command = processor_->AddCommand(cmCmp, IntelOperand(otRegistr, osByte, regR10), IntelOperand(otValue, osByte, 0, 3)); + cmp_command->link()->set_to_command(command); + cmp_command = processor_->AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size)); + cmp_command->set_flags(fl_Z); + cmp_command->include_option(roInverseFlag); + cmp_command->AddLink(0, ltJmpWithFlag); + + command = processor_->AddCommand(cmCmp, IntelOperand(otMemory | otBaseRegistr | otValue, arg_address_size, regEBP << 4, OperandSizeToValue(arg_address_size) * 2), IntelOperand(otValue, osDWord, 0, 0x7)); // ProcessDebugPort + jmp_command->link()->set_to_command(command); + jmp_command = processor_->AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size)); + jmp_command->set_flags(fl_Z); + jmp_command->include_option(roInverseFlag); + jmp_command->AddLink(0, ltJmpWithFlag); + + processor_->AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regECX), IntelOperand(otMemory | otBaseRegistr | otValue, arg_address_size, regEBP << 4, OperandSizeToValue(arg_address_size) * 3)); + processor_->AddCommand(cmCmp, IntelOperand(otRegistr, osDWord, regECX), IntelOperand(otMemory | otBaseRegistr | otValue, arg_address_size, regEBP << 4, OperandSizeToValue(arg_address_size) * 5)); + IntelCommand *jmp_command2 = processor_->AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size)); + jmp_command2->set_flags(fl_Z); + jmp_command2->AddLink(0, ltJmpWithFlag); + + processor_->AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regR10), IntelOperand(otMemory | otBaseRegistr | otValue, osDWord, regEBP << 4, 0 - OperandSizeToValue(cpu_address_size) * 3)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr, osDWord, regECX), IntelOperand(otRegistr, osDWord, regR10)); + command = processor_->AddCommand(cmJmp, IntelOperand(otValue, cpu_address_size)); + jmp_command2->link()->set_to_command(command); + command->AddLink(0, ltJmp); + jmp_end_convert.push_back(command); + + command = processor_->AddCommand(cmCmp, IntelOperand(otMemory | otBaseRegistr | otValue, arg_address_size, regEBP << 4, OperandSizeToValue(arg_address_size) * 2), IntelOperand(otValue, osDWord, 0, 0x1e)); // ProcessDebugObjectHandle + jmp_command->link()->set_to_command(command); + jmp_command = processor_->AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size)); + jmp_command->set_flags(fl_Z); + jmp_command->include_option(roInverseFlag); + jmp_command->AddLink(0, ltJmpWithFlag); + + processor_->AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regECX), IntelOperand(otMemory | otBaseRegistr | otValue, arg_address_size, regEBP << 4, OperandSizeToValue(arg_address_size) * 3)); + processor_->AddCommand(cmCmp, IntelOperand(otRegistr, osDWord, regECX), IntelOperand(otMemory | otBaseRegistr | otValue, arg_address_size, regEBP << 4, OperandSizeToValue(arg_address_size) * 5)); + jmp_command2 = processor_->AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size)); + jmp_command2->set_flags(fl_Z); + jmp_command2->AddLink(0, ltJmpWithFlag); + + processor_->AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regR10), IntelOperand(otMemory | otBaseRegistr | otValue, osDWord, regEBP << 4, 0 - OperandSizeToValue(cpu_address_size) * 3)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr, osDWord, regECX), IntelOperand(otRegistr, osDWord, regR10)); + command = processor_->AddCommand(cmJmp, IntelOperand(otValue, cpu_address_size)); + jmp_command->link()->set_to_command(command); + jmp_command2->link()->set_to_command(command); + command->AddLink(0, ltJmp); + jmp_end_convert.push_back(command); + + // NtMapViewOfSection + command = processor_->AddCommand(cmCmp, IntelOperand(otRegistr, osByte, regR10), IntelOperand(otValue, osByte, 0, 4)); + cmp_command->link()->set_to_command(command); + cmp_command = processor_->AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size)); + cmp_command->set_flags(fl_Z); + cmp_command->include_option(roInverseFlag); + cmp_command->AddLink(0, ltJmpWithFlag); + + processor_->AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regECX), IntelOperand(otMemory | otBaseRegistr | otValue, arg_address_size, regEBP << 4, OperandSizeToValue(arg_address_size) * 3)); + processor_->AddCommand(cmTest, IntelOperand(otRegistr, osDWord, regECX), IntelOperand(otRegistr, osDWord, regECX)); + jmp_command->link()->set_to_command(command); + jmp_command = processor_->AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size)); + jmp_command->set_flags(fl_Z); + jmp_command->AddLink(0, ltJmpWithFlag); + processor_->AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regR10), IntelOperand(otMemory | otBaseRegistr | otValue, osDWord, regEBP << 4, 0 - OperandSizeToValue(cpu_address_size) * 3)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr, osDWord, regECX), IntelOperand(otRegistr, osDWord, regR10)); + + processor_->AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regECX), IntelOperand(otMemory | otBaseRegistr | otValue, arg_address_size, regEBP << 4, OperandSizeToValue(arg_address_size) * 7)); + jmp_command->link()->set_to_command(command); + processor_->AddCommand(cmTest, IntelOperand(otRegistr, osDWord, regECX), IntelOperand(otRegistr, osDWord, regECX)); + jmp_command->link()->set_to_command(command); + jmp_command = processor_->AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size)); + jmp_command->set_flags(fl_Z); + jmp_command->AddLink(0, ltJmpWithFlag); + + processor_->AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regR10), IntelOperand(otMemory | otBaseRegistr | otValue, osDWord, regEBP << 4, 0 - OperandSizeToValue(cpu_address_size) * 4)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr, osDWord, regECX), IntelOperand(otRegistr, osDWord, regR10)); + command = processor_->AddCommand(cmJmp, IntelOperand(otValue, cpu_address_size)); + jmp_command->link()->set_to_command(command); + command->AddLink(0, ltJmp); + jmp_end_convert.push_back(command); + + // NtOpenFile + command = processor_->AddCommand(cmCmp, IntelOperand(otRegistr, osByte, regR10), IntelOperand(otValue, osByte, 0, 6)); + cmp_command->link()->set_to_command(command); + cmp_command = processor_->AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size)); + cmp_command->set_flags(fl_Z); + cmp_command->include_option(roInverseFlag); + cmp_command->AddLink(0, ltJmpWithFlag); + + processor_->AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regECX), IntelOperand(otMemory | otBaseRegistr | otValue, arg_address_size, regEBP << 4, OperandSizeToValue(arg_address_size))); + processor_->AddCommand(cmTest, IntelOperand(otRegistr, osDWord, regECX), IntelOperand(otRegistr, osDWord, regECX)); + jmp_command = processor_->AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size)); + jmp_command->set_flags(fl_Z); + jmp_command->AddLink(0, ltJmpWithFlag); + processor_->AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regR10), IntelOperand(otMemory | otBaseRegistr | otValue, osDWord, regEBP << 4, 0 - OperandSizeToValue(cpu_address_size) * 3)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr, osDWord, regECX), IntelOperand(otRegistr, osDWord, regR10)); + command = processor_->AddCommand(cmJmp, IntelOperand(otValue, cpu_address_size)); + jmp_command->link()->set_to_command(command); + command->AddLink(0, ltJmp); + jmp_end_convert.push_back(command); + + // NtCreateSection + command = processor_->AddCommand(cmCmp, IntelOperand(otRegistr, osByte, regR10), IntelOperand(otValue, osByte, 0, 7)); + cmp_command->link()->set_to_command(command); + cmp_command = processor_->AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size)); + cmp_command->set_flags(fl_Z); + cmp_command->include_option(roInverseFlag); + cmp_command->AddLink(0, ltJmpWithFlag); + + processor_->AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regECX), IntelOperand(otMemory | otBaseRegistr | otValue, arg_address_size, regEBP << 4, OperandSizeToValue(arg_address_size))); + processor_->AddCommand(cmTest, IntelOperand(otRegistr, osDWord, regECX), IntelOperand(otRegistr, osDWord, regECX)); + jmp_command = processor_->AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size)); + jmp_command->set_flags(fl_Z); + jmp_command->AddLink(0, ltJmpWithFlag); + processor_->AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regR10), IntelOperand(otMemory | otBaseRegistr | otValue, osDWord, regEBP << 4, 0 - OperandSizeToValue(cpu_address_size) * 3)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr, osDWord, regECX), IntelOperand(otRegistr, osDWord, regR10)); + command = processor_->AddCommand(cmJmp, IntelOperand(otValue, cpu_address_size)); + jmp_command->link()->set_to_command(command); + command->AddLink(0, ltJmp); + jmp_end_convert.push_back(command); + + // NtQueryVirtualMemory + command = processor_->AddCommand(cmCmp, IntelOperand(otRegistr, osByte, regR10), IntelOperand(otValue, osByte, 0, 8)); + cmp_command->link()->set_to_command(command); + cmp_command = processor_->AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size)); + cmp_command->set_flags(fl_Z); + cmp_command->include_option(roInverseFlag); + cmp_command->AddLink(0, ltJmpWithFlag); + + processor_->AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regECX), IntelOperand(otMemory | otBaseRegistr | otValue, arg_address_size, regEBP << 4, OperandSizeToValue(arg_address_size) * 4)); + processor_->AddCommand(cmTest, IntelOperand(otRegistr, osDWord, regECX), IntelOperand(otRegistr, osDWord, regECX)); + jmp_command = processor_->AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size)); + jmp_command->set_flags(fl_Z); + jmp_command->AddLink(0, ltJmpWithFlag); + processor_->AddCommand(cmLea, IntelOperand(otRegistr, osDWord, regR10), IntelOperand(otMemory | otBaseRegistr | otValue, osDWord, regEBP << 4, 0 - OperandSizeToValue(cpu_address_size) * 8)); + processor_->AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regR11), IntelOperand(otMemory | otRegistr, osDWord, regR10)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr, osDWord, regECX), IntelOperand(otRegistr, osDWord, regR11)); + processor_->AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regR11), IntelOperand(otMemory | otRegistr | otValue, osDWord, regR10, OperandSizeToValue(cpu_address_size))); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr | otValue, osDWord, regECX, OperandSizeToValue(arg_address_size)), IntelOperand(otRegistr, osDWord, regR11)); + processor_->AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regR11), IntelOperand(otMemory | otRegistr | otValue, osDWord, regR10, OperandSizeToValue(cpu_address_size) * 2)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr | otValue, osDWord, regECX, OperandSizeToValue(arg_address_size) * 2), IntelOperand(otRegistr, osDWord, regR11)); + processor_->AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regR11), IntelOperand(otMemory | otRegistr | otValue, osDWord, regR10, OperandSizeToValue(cpu_address_size) * 3)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr | otValue, osDWord, regECX, OperandSizeToValue(arg_address_size) * 3), IntelOperand(otRegistr, osDWord, regR11)); + processor_->AddCommand(cmMov, IntelOperand(otRegistr, osQWord, regR11), IntelOperand(otMemory | otRegistr | otValue, osQWord, regR10, OperandSizeToValue(cpu_address_size) * 4)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr | otValue, osQWord, regECX, OperandSizeToValue(arg_address_size) * 4), IntelOperand(otRegistr, osQWord, regR11)); + processor_->AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regR11), IntelOperand(otMemory | otRegistr | otValue, osDWord, regR10, OperandSizeToValue(cpu_address_size) * 5)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr | otValue, osDWord, regECX, OperandSizeToValue(arg_address_size) * 6), IntelOperand(otRegistr, osDWord, regR11)); + + command = processor_->AddCommand(cmJmp, IntelOperand(otValue, cpu_address_size)); + jmp_command->link()->set_to_command(command); + command->AddLink(0, ltJmp); + jmp_end_convert.push_back(command); + + command = processor_->AddCommand(cmNop); + cmp_command->link()->set_to_command(command); + for (i = 0; i < jmp_end_convert.size(); i++) { + jmp_end_convert[i]->link()->set_to_command(command); + } + } + + // correct stack + if (calling_convention != ccStdcall) + processor_->AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size, regESP), IntelOperand(otMemory | otBaseRegistr | otValue, cpu_address_size, regEBP << 4, 0 - OperandSizeToValue(cpu_address_size) * 2)); + else if (call_entry) + processor_->AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size, regESP), IntelOperand(otMemory | otBaseRegistr | otValue, cpu_address_size, regEBP << 4, 0 - OperandSizeToValue(cpu_address_size) * 2)); + if (calling_convention != ccCdecl) + processor_->AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size, regEBP), IntelOperand(otMemory | otBaseRegistr | otValue, cpu_address_size, regEBP << 4, 0 - OperandSizeToValue(cpu_address_size))); + + // save result + processor_->AddCommand(cmMov, IntelOperand(otMemory | otBaseRegistr | otValue, arg_address_size, regEBP << 4, 0), IntelOperand(otRegistr, arg_address_size, regEAX)); + + // pop common registers + if (stack_registr_ != regEBP) + processor_->AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size, stack_registr_), IntelOperand(otRegistr, cpu_address_size, regEBP)); + if (crypt_registr_) + processor_->AddCommand(cmPop, IntelOperand(otRegistr, cpu_address_size, crypt_registr_)); + if (jmp_registr_) + processor_->AddCommand(cmPop, IntelOperand(otRegistr, cpu_address_size, jmp_registr_)); + processor_->AddCommand(cmPop, IntelOperand(otRegistr, cpu_address_size, pcode_registr_)); +} + +bool IntelVirtualMachine::IsRegistrUsed(uint8_t registr) +{ + return (registr == stack_registr_ || registr == pcode_registr_ || (jmp_registr_ && registr == jmp_registr_) || (crypt_registr_ && registr == crypt_registr_)); +} + +void IntelVirtualMachine::InitCommands(const CompileContext &ctx, const IntelOpcodeList &visible_opcode_list) +{ + IntelCommand *command, *read_opcode, *check_stack, *opcode_entry, *switch_entry, *jmp_command; + uint8_t seg, s, reg1, reg2, reg3, reg4; + OperandSize size, mov_size; + size_t i, operand_size, result_size, j, c; + IntelCommandType command_type; + OpcodeCryptor *value_cryptor, *registr_cryptor, *end_cryptor; + IntelOpcodeInfo *opcode; + OperandSize cpu_address_size = processor_->cpu_address_size(); + IntelFunctionList *function_list = reinterpret_cast(processor_->owner()); + + IntelRegistrList wrong_registr_list; + switch (ctx.file->calling_convention()) { + case ccMSx64: + case ccABIx64: + wrong_registr_list.push_back(regR12); + wrong_registr_list.push_back(regR13); + wrong_registr_list.push_back(regR14); + wrong_registr_list.push_back(regR15); + break; + } + + // init registers + if +#ifdef DEMO + (true) +#else + (ctx.options.flags & cpUnregisteredVersion) +#endif + { + crypt_registr_ = (ctx.options.flags & cpEncryptBytecode) ? regEBX : 0; + pcode_registr_ = regESI; + stack_registr_ = regEBP; + if (type_ == vtAdvanced) + jmp_registr_ = regEDI; + else if (cpu_address_size == osQWord) + jmp_registr_ = regR11; + else + jmp_registr_ = 0; + } + else { + IntelRegistrList work_registr_list; + work_registr_list.push_back(regEBX); + work_registr_list.push_back(regEBP); + work_registr_list.push_back(regESI); + work_registr_list.push_back(regEDI); + if (cpu_address_size == osQWord) { + for (i = 8; i < 16; i++) { + work_registr_list.push_back((uint8_t)i); + } + } + work_registr_list.remove(wrong_registr_list); + + crypt_registr_ = 0; + if (ctx.options.flags & cpEncryptBytecode) { + if (cpu_address_size == osDWord) { + crypt_registr_ = regEBX; + work_registr_list.remove(crypt_registr_); + } + else + crypt_registr_ = work_registr_list.GetRandom(); + } + pcode_registr_ = work_registr_list.GetRandom(); + stack_registr_ = work_registr_list.GetRandom(); + jmp_registr_ = (type_ == vtAdvanced || cpu_address_size == osQWord) ? work_registr_list.GetRandom() : 0; + } + + free_registr_list_.push_back(regEAX); + free_registr_list_.push_back(regECX); + free_registr_list_.push_back(regEDX); + free_registr_list_.push_back(regEBX); + free_registr_list_.push_back(regEBP); + free_registr_list_.push_back(regESI); + free_registr_list_.push_back(regEDI); + if (cpu_address_size == osQWord) { + for (i = 8; i < 16; i++) { + free_registr_list_.push_back((uint8_t)i); + } + } + free_registr_list_.remove(wrong_registr_list); + free_registr_list_.remove(pcode_registr_); + free_registr_list_.remove(stack_registr_); + if (jmp_registr_) + free_registr_list_.remove(jmp_registr_); + if (crypt_registr_) + free_registr_list_.remove(crypt_registr_); + + // init cryptors + entry_cryptor_.Init(osDWord); + if (ctx.options.flags & cpEncryptBytecode) { + command_cryptor_ = new OpcodeCryptor(); + command_cryptor_->Init((type_ == vtAdvanced) ? osDWord : osByte); + } + value_cryptor = NULL; + registr_cryptor = NULL; + end_cryptor = NULL; + + // init registr list + registr_order_.clear(); + registr_order_.push_back(regEFX); + registr_order_.push_back(regEAX); + registr_order_.push_back(regECX); + registr_order_.push_back(regEDX); + registr_order_.push_back(regEBX); + registr_order_.push_back(regEBP); + registr_order_.push_back(regESI); + registr_order_.push_back(regEDI); + if (cpu_address_size == osQWord) { + for (i = 8; i < 16; i++) { + registr_order_.push_back((uint8_t)i); + } + } + for (i = 0; i < registr_order_.size(); i++) { + std::swap(registr_order_[i], registr_order_[rand() % registr_order_.size()]); + } + + // create commands + c = processor_->count(); + for (i = 0; i < registr_order_.size(); i++) { + uint8_t reg = registr_order_[i]; + if (reg == regEFX) { + processor_->AddCommand(cmPushf); + } + else { + processor_->AddCommand(cmPush, IntelOperand(otRegistr, cpu_address_size, reg)); + } + } + entry_command_ = processor_->item(c); + entry_command_->include_section_option(rtLinkedToInt); + + size_t context_registr_count = (cpu_address_size == osQWord) ? 24 : 16; + if (ctx.file->runtime_function_list() && ctx.file->runtime_function_list()->count()) + context_registr_count += 8; + { + IntelRegistrList registr_list = free_registr_list_; + reg1 = registr_list.GetRandom(); + } + if (ctx.file->cpu_address_size() != cpu_address_size && cpu_address_size == osQWord) + processor_->AddCommand(cmLea, IntelOperand(otRegistr, cpu_address_size, reg1), IntelOperand(otMemory | otValue, cpu_address_size, 0, 0, LARGE_VALUE)); + else + processor_->AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size, reg1), IntelOperand(otValue, cpu_address_size, 0, 0, NEED_FIXUP)); + processor_->AddCommand(cmPush, IntelOperand(otRegistr, cpu_address_size, reg1)); + processor_->AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size, pcode_registr_), IntelOperand(otMemory | otRegistr | otValue, cpu_address_size, regESP, (registr_order_.size() + 2) * OperandSizeToValue(cpu_address_size))); + for (i = entry_cryptor_.count(); i > 0; i--) { + AddValueCommand(*entry_cryptor_.item(i - 1), true, pcode_registr_); + } + processor_->AddCommand(cmAdd, IntelOperand(otRegistr, cpu_address_size, pcode_registr_), IntelOperand(otRegistr, cpu_address_size, reg1)); + if (cpu_address_size == osQWord) { + if (ctx.file->image_base() >> 32) { + IntelRegistrList registr_list = free_registr_list_; + reg1 = registr_list.GetRandom(); + processor_->AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size, reg1), IntelOperand(otValue, cpu_address_size, 0, ctx.file->image_base() & 0xffffffff00000000ull)); + processor_->AddCommand(cmAdd, IntelOperand(otRegistr, cpu_address_size, pcode_registr_), IntelOperand(otRegistr, cpu_address_size, reg1)); + } + processor_->AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size, stack_registr_), IntelOperand(otRegistr, cpu_address_size, regESP)); + processor_->AddCommand(cmSub, IntelOperand(otRegistr, cpu_address_size, regESP), IntelOperand(otValue, cpu_address_size, 0, 128 + context_registr_count * OperandSizeToValue(cpu_address_size))); + processor_->AddCommand(cmAnd, IntelOperand(otRegistr, cpu_address_size, regESP), IntelOperand(otValue, cpu_address_size, 0, -16)); + } + else { + processor_->AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size, stack_registr_), IntelOperand(otRegistr, cpu_address_size, regESP)); + processor_->AddCommand(cmSub, IntelOperand(otRegistr, cpu_address_size, regESP), IntelOperand(otValue, cpu_address_size, 0, 128 + context_registr_count * OperandSizeToValue(cpu_address_size))); + } + + c = processor_->count(); + if (crypt_registr_) { + IntelRegistrList registr_list = free_registr_list_; + reg1 = registr_list.GetRandom(); + processor_->AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size, crypt_registr_), IntelOperand(otRegistr, cpu_address_size, pcode_registr_)); + if (ctx.file->cpu_address_size() != cpu_address_size && cpu_address_size == osQWord) + processor_->AddCommand(cmLea, IntelOperand(otRegistr, cpu_address_size, reg1), IntelOperand(otMemory | otValue, cpu_address_size, 0, 0, LARGE_VALUE)); + else + processor_->AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size, reg1), IntelOperand(otValue, cpu_address_size, 0, 0, NEED_FIXUP)); + processor_->AddCommand(cmSub, IntelOperand(otRegistr, cpu_address_size, crypt_registr_), IntelOperand(otRegistr, cpu_address_size, reg1)); + } + if (type_ == vtAdvanced) { + opcode_entry = processor_->AddCommand(cmLea, IntelOperand(otRegistr, cpu_address_size, jmp_registr_), IntelOperand(otMemory | otValue, cpu_address_size, 0, 0, (cpu_address_size == osDWord) ? NEED_FIXUP : LARGE_VALUE)); + opcode_entry->AddLink(1, ltOffset, opcode_entry); + AddEndHandlerCommands(NULL, command_cryptor_); + opcode_list_.Add(cmNop, otNone, cpu_address_size, 0, opcode_entry, NULL, command_cryptor_); + } + else if (cpu_address_size == osQWord) { + command = processor_->AddCommand(cmLea, IntelOperand(otRegistr, cpu_address_size, jmp_registr_), IntelOperand(otMemory | otValue, cpu_address_size, 0, 0, LARGE_VALUE)); + command->AddLink(1, ltOffset); + switch_entry = command; + } + else if (c == processor_->count()) + processor_->AddCommand(cmNop); + init_command_ = processor_->item(c); + + read_opcode = NULL; + if (type_ == vtAdvanced) { + command = processor_->AddCommand(cmJmp, IntelOperand(otRegistr, cpu_address_size, jmp_registr_)); + command->AddLink(-1, ltJmp); + } + else { + IntelRegistrList registr_list = free_registr_list_; + reg1 = registr_list.GetRandom(cpu_address_size == osDWord); + read_opcode = AddReadCommand(osByte, command_cryptor_, reg1); + if (cpu_address_size == osQWord) { + command = processor_->AddCommand(cmJmp, IntelOperand(otMemory | otBaseRegistr | otRegistr, cpu_address_size, (jmp_registr_ << 4) | reg1, 0)); + command->set_operand_scale(0, 3); + command->AddLink(-1, ltJmp); + } + else { + command = processor_->AddCommand(cmJmp, IntelOperand(otMemory | otRegistr | otValue, cpu_address_size, reg1, 0, NEED_FIXUP)); + command->set_operand_scale(0, 2); + command->AddLink(0, ltSwitch); + switch_entry = command; + } + } + + // check stack + { + IntelRegistrList registr_list = free_registr_list_; + reg1 = registr_list.GetRandom(); + check_stack = processor_->AddCommand(cmLea, IntelOperand(otRegistr, cpu_address_size, reg1), IntelOperand(otMemory | otRegistr | otValue, cpu_address_size, regESP, (context_registr_count + 8) * OperandSizeToValue(cpu_address_size))); + processor_->AddCommand(cmCmp, IntelOperand(otRegistr, cpu_address_size, stack_registr_), IntelOperand(otRegistr, cpu_address_size, reg1)); + jmp_command = processor_->AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size)); + jmp_command->set_flags(fl_C | fl_Z); + jmp_command->include_option(roInverseFlag); + jmp_command->AddLink(0, ltJmpWithFlag); + + registr_list = free_registr_list_; + registr_list.remove(regESI); + registr_list.remove(regEDI); + registr_list.remove(regECX); + reg1 = registr_list.GetRandom(); + reg2 = registr_list.GetRandom(); + processor_->AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size, reg2), IntelOperand(otRegistr, cpu_address_size, regESP)); + processor_->AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size, regECX), IntelOperand(otValue, cpu_address_size, 0, context_registr_count * OperandSizeToValue(cpu_address_size))); + processor_->AddCommand(cmLea, IntelOperand(otRegistr, cpu_address_size, reg1), IntelOperand(otMemory | otBaseRegistr | otValue, cpu_address_size, stack_registr_ << 4, -128)); + processor_->AddCommand(cmAnd, IntelOperand(otRegistr, cpu_address_size, reg1), IntelOperand(otValue, cpu_address_size, 0, (cpu_address_size == osQWord) ? -16 : -4)); + processor_->AddCommand(cmSub, IntelOperand(otRegistr, cpu_address_size, reg1), IntelOperand(otRegistr, cpu_address_size, regECX)); + processor_->AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size, regESP), IntelOperand(otRegistr, cpu_address_size, reg1)); + if (IsRegistrUsed(regEDI)) + processor_->AddCommand(cmPush, IntelOperand(otRegistr, cpu_address_size, regEDI)); + if (IsRegistrUsed(regESI)) + processor_->AddCommand(cmPush, IntelOperand(otRegistr, cpu_address_size, regESI)); + processor_->AddCommand(cmPushf); + processor_->AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size, regESI), IntelOperand(otRegistr, cpu_address_size, reg2)); + processor_->AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size, regEDI), IntelOperand(otRegistr, cpu_address_size, reg1)); + processor_->AddCommand(cmCld); + command = processor_->AddCommand(cmMovs, IntelOperand(otRegistr, osByte)); + command->set_preffix_command(cmRep); + processor_->AddCommand(cmPopf); + if (IsRegistrUsed(regESI)) + processor_->AddCommand(cmPop, IntelOperand(otRegistr, cpu_address_size, regESI)); + if (IsRegistrUsed(regEDI)) + processor_->AddCommand(cmPop, IntelOperand(otRegistr, cpu_address_size, regEDI)); + if (type_ == vtAdvanced) { + command = processor_->AddCommand(cmJmp, IntelOperand(otRegistr, cpu_address_size, jmp_registr_)); + command->AddLink(-1, ltJmp); + jmp_command->link()->set_to_command(command); + } + else { + command = processor_->AddCommand(cmJmp, IntelOperand(otValue, cpu_address_size)); + command->AddLink(0, ltJmp, read_opcode); + jmp_command->link()->set_to_command(read_opcode); + } + } + + // push registr + for (s = osByte; s <= cpu_address_size; s++) { + size = static_cast(s); + IntelRegistrList registr_list = free_registr_list_; + reg1 = registr_list.GetRandom(cpu_address_size == osDWord); + reg2 = registr_list.GetRandom(); + mov_size = (size == osByte) ? osWord : size; + if (ctx.options.flags & cpEncryptBytecode) { + registr_cryptor = new OpcodeCryptor(); + cryptor_list_.push_back(registr_cryptor); + registr_cryptor->Init(osByte); + if (type_ == vtAdvanced) { + end_cryptor = new OpcodeCryptor(); + cryptor_list_.push_back(end_cryptor); + end_cryptor->Init(osDWord); + } + } + opcode_entry = AddReadCommand(osByte, registr_cryptor, reg1); + processor_->AddCommand((mov_size == size) ? cmMov : cmMovzx, IntelOperand(otRegistr, mov_size, reg2), IntelOperand(otMemory | otBaseRegistr | otRegistr, size, (regESP << 4) | reg1)); + operand_size = 0; + result_size = OperandSizeToValue(mov_size); + if (result_size > operand_size) + processor_->AddCommand(cmSub, IntelOperand(otRegistr, cpu_address_size, stack_registr_), IntelOperand(otValue, cpu_address_size, 0, result_size - operand_size)); + else if (result_size < operand_size) //-V547 + processor_->AddCommand(cmAdd, IntelOperand(otRegistr, cpu_address_size, stack_registr_), IntelOperand(otValue, cpu_address_size, 0, operand_size - result_size)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr, mov_size, stack_registr_), IntelOperand(otRegistr, mov_size, reg2)); + AddEndHandlerCommands((result_size > operand_size) ? check_stack : read_opcode, end_cryptor); + opcode_list_.Add(cmPush, otRegistr, size, 0, opcode_entry, registr_cryptor, end_cryptor); + } + + // pop registr + for (s = osByte; s <= cpu_address_size; s++) { + size = static_cast(s); + IntelRegistrList registr_list = free_registr_list_; + reg1 = registr_list.GetRandom(size == osByte && cpu_address_size == osDWord); + reg2 = registr_list.GetRandom(cpu_address_size == osDWord); + mov_size = (size == osByte) ? osWord : size; + if (ctx.options.flags & cpEncryptBytecode) { + registr_cryptor = new OpcodeCryptor(); + cryptor_list_.push_back(registr_cryptor); + registr_cryptor->Init(osByte); + if (type_ == vtAdvanced) { + end_cryptor = new OpcodeCryptor(); + cryptor_list_.push_back(end_cryptor); + end_cryptor->Init(osDWord); + } + } + opcode_entry = processor_->AddCommand(cmMov, IntelOperand(otRegistr, mov_size, reg1), IntelOperand(otMemory | otRegistr, mov_size, stack_registr_)); + operand_size = OperandSizeToValue(mov_size); + result_size = 0; + if (result_size > operand_size) //-V547 + processor_->AddCommand(cmSub, IntelOperand(otRegistr, cpu_address_size, stack_registr_), IntelOperand(otValue, cpu_address_size, 0, result_size - operand_size)); + else if (result_size < operand_size) + processor_->AddCommand(cmAdd, IntelOperand(otRegistr, cpu_address_size, stack_registr_), IntelOperand(otValue, cpu_address_size, 0, operand_size - result_size)); + AddReadCommand(osByte, registr_cryptor, reg2); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otBaseRegistr | otRegistr, size, (regESP << 4) | reg2), IntelOperand(otRegistr, size, reg1)); + AddEndHandlerCommands((result_size > operand_size) ? check_stack : read_opcode, end_cryptor); //-V547 + opcode_list_.Add(cmPop, otRegistr, size, 0, opcode_entry, registr_cryptor, end_cryptor); + } + + // push value + for (s = osByte; s <= cpu_address_size; s++) { + size = static_cast(s); + IntelRegistrList registr_list = free_registr_list_; + reg1 = registr_list.GetRandom(size == osByte && cpu_address_size == osDWord); + if (ctx.options.flags & cpEncryptBytecode) { + value_cryptor = new OpcodeCryptor(); + cryptor_list_.push_back(value_cryptor); + value_cryptor->Init(size); + if (type_ == vtAdvanced) { + end_cryptor = new OpcodeCryptor(); + cryptor_list_.push_back(end_cryptor); + end_cryptor->Init(osDWord); + } + } + opcode_entry = AddReadCommand(size, value_cryptor, reg1); + mov_size = (size == osByte) ? osWord : size; + operand_size = 0; + result_size = OperandSizeToValue(mov_size); + if (result_size > operand_size) + processor_->AddCommand(cmSub, IntelOperand(otRegistr, cpu_address_size, stack_registr_), IntelOperand(otValue, cpu_address_size, 0, result_size - operand_size)); + else if (result_size < operand_size) //-V547 + processor_->AddCommand(cmAdd, IntelOperand(otRegistr, cpu_address_size, stack_registr_), IntelOperand(otValue, cpu_address_size, 0, operand_size - result_size)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr, mov_size, stack_registr_), IntelOperand(otRegistr, mov_size, reg1)); + AddEndHandlerCommands((result_size > operand_size) ? check_stack : read_opcode, end_cryptor); + opcode_list_.Add(cmPush, otValue, size, 0, opcode_entry, value_cryptor, end_cryptor); + } + + // push [address] + for (s = osByte; s <= cpu_address_size; s++) { + size = static_cast(s); + mov_size = (size == osByte) ? osWord : size; + for (seg = segES; seg <= segGS; seg++) { + if (seg != segDS && seg != segSS && !visible_opcode_list.GetOpcodeInfo(cmPush, otMemory, size, seg)) + continue; + + IntelRegistrList registr_list = free_registr_list_; + reg1 = registr_list.GetRandom(); + reg2 = registr_list.GetRandom(); + if (ctx.options.flags & cpEncryptBytecode) { + if (type_ == vtAdvanced) { + end_cryptor = new OpcodeCryptor(); + cryptor_list_.push_back(end_cryptor); + end_cryptor->Init(osDWord); + } + } + opcode_entry = processor_->AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size, reg1), IntelOperand(otMemory | otRegistr, cpu_address_size, stack_registr_)); + command = processor_->AddCommand((mov_size == size) ? cmMov : cmMovzx, IntelOperand(otRegistr, mov_size, reg2), IntelOperand(otMemory | otRegistr, size, reg1)); + if (seg != segDS) + command->set_base_segment(static_cast(seg)); + operand_size = OperandSizeToValue(cpu_address_size); + result_size = OperandSizeToValue(mov_size); + if (result_size > operand_size) + processor_->AddCommand(cmSub, IntelOperand(otRegistr, cpu_address_size, stack_registr_), IntelOperand(otValue, cpu_address_size, 0, result_size - operand_size)); + else if (result_size < operand_size) + processor_->AddCommand(cmAdd, IntelOperand(otRegistr, cpu_address_size, stack_registr_), IntelOperand(otValue, cpu_address_size, 0, operand_size - result_size)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr, mov_size, stack_registr_), IntelOperand(otRegistr, mov_size, reg2)); + AddEndHandlerCommands((result_size > operand_size) ? check_stack : read_opcode, end_cryptor); + opcode_list_.Add(cmPush, otMemory, size, seg, opcode_entry, NULL, end_cryptor); + } + } + + // pop [address] + for (s = osByte; s <= cpu_address_size; s++) { + size = static_cast(s); + mov_size = (size == osByte) ? osWord : size; + for (seg = segES; seg <= segGS; seg++) { + if (seg != segDS && seg != segSS && !visible_opcode_list.GetOpcodeInfo(cmPop, otMemory, size, seg)) + continue; + + IntelRegistrList registr_list = free_registr_list_; + reg1 = registr_list.GetRandom(); + reg2 = registr_list.GetRandom(size == osByte && cpu_address_size == osDWord); + if (ctx.options.flags & cpEncryptBytecode) { + if (type_ == vtAdvanced) { + end_cryptor = new OpcodeCryptor(); + cryptor_list_.push_back(end_cryptor); + end_cryptor->Init(osDWord); + } + } + opcode_entry = processor_->AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size, reg1), IntelOperand(otMemory | otRegistr, cpu_address_size, stack_registr_)); + processor_->AddCommand(cmMov, IntelOperand(otRegistr, size, reg2), IntelOperand(otMemory | otRegistr | otValue, size, stack_registr_, OperandSizeToValue(cpu_address_size))); + operand_size = OperandSizeToValue(cpu_address_size) + OperandSizeToValue(mov_size); + result_size = 0; + if (result_size > operand_size) //-V547 + processor_->AddCommand(cmSub, IntelOperand(otRegistr, cpu_address_size, stack_registr_), IntelOperand(otValue, cpu_address_size, 0, result_size - operand_size)); + else if (result_size < operand_size) + processor_->AddCommand(cmAdd, IntelOperand(otRegistr, cpu_address_size, stack_registr_), IntelOperand(otValue, cpu_address_size, 0, operand_size - result_size)); + command = processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr, size, reg1), IntelOperand(otRegistr, size, reg2)); + if (seg != segDS) + command->set_base_segment(static_cast(seg)); + AddEndHandlerCommands((result_size > operand_size) ? check_stack : read_opcode, end_cryptor); //-V547 + opcode_list_.Add(cmPop, otMemory, size, seg, opcode_entry, NULL, end_cryptor); + } + } + + // push segment registr + for (seg = segES; seg <= segGS; seg++) { + if (!visible_opcode_list.GetOpcodeInfo(cmPush, otSegmentRegistr, osWord, seg)) + continue; + + IntelRegistrList registr_list = free_registr_list_; + reg1 = registr_list.GetRandom(); + if (ctx.options.flags & cpEncryptBytecode) { + if (type_ == vtAdvanced) { + end_cryptor = new OpcodeCryptor(); + cryptor_list_.push_back(end_cryptor); + end_cryptor->Init(osDWord); + } + } + opcode_entry = processor_->AddCommand(cmMov, IntelOperand(otRegistr, osWord, reg1), IntelOperand(otSegmentRegistr, osWord, seg)); + operand_size = 0; + result_size = OperandSizeToValue(osWord); + if (result_size > operand_size) + processor_->AddCommand(cmSub, IntelOperand(otRegistr, cpu_address_size, stack_registr_), IntelOperand(otValue, cpu_address_size, 0, result_size - operand_size)); + else if (result_size < operand_size) //-V547 + processor_->AddCommand(cmAdd, IntelOperand(otRegistr, cpu_address_size, stack_registr_), IntelOperand(otValue, cpu_address_size, 0, operand_size - result_size)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr, osWord, stack_registr_), IntelOperand(otRegistr, osWord, reg1)); + AddEndHandlerCommands((result_size > operand_size) ? check_stack : read_opcode, end_cryptor); + opcode_list_.Add(cmPush, otSegmentRegistr, osWord, seg, opcode_entry, NULL, end_cryptor); + } + + // pop segment registr + for (seg = segES; seg <= segGS; seg++) { + if (seg == segCS || !visible_opcode_list.GetOpcodeInfo(cmPop, otSegmentRegistr, osWord, seg)) + continue; + + IntelRegistrList registr_list = free_registr_list_; + reg1 = registr_list.GetRandom(); + if (ctx.options.flags & cpEncryptBytecode) { + if (type_ == vtAdvanced) { + end_cryptor = new OpcodeCryptor(); + cryptor_list_.push_back(end_cryptor); + end_cryptor->Init(osDWord); + } + } + opcode_entry = processor_->AddCommand(cmMov, IntelOperand(otRegistr, osWord, reg1), IntelOperand(otMemory | otRegistr, osWord, stack_registr_)); + operand_size = OperandSizeToValue(osWord); + result_size = 0; + if (result_size > operand_size) //-V547 + processor_->AddCommand(cmSub, IntelOperand(otRegistr, cpu_address_size, stack_registr_), IntelOperand(otValue, cpu_address_size, 0, result_size - operand_size)); + else if (result_size < operand_size) + processor_->AddCommand(cmAdd, IntelOperand(otRegistr, cpu_address_size, stack_registr_), IntelOperand(otValue, cpu_address_size, 0, operand_size - result_size)); + processor_->AddCommand(cmMov, IntelOperand(otSegmentRegistr, osWord, seg), IntelOperand(otRegistr, osWord, reg1)); + AddEndHandlerCommands((result_size > operand_size) ? check_stack : read_opcode, end_cryptor); //-V547 + opcode_list_.Add(cmPop, otSegmentRegistr, osWord, seg, opcode_entry, NULL, end_cryptor); + } + + size_t debug_reg_count = 8; + + // push debug registr + for (i = 0; i < debug_reg_count; i++) { + if (!visible_opcode_list.GetOpcodeInfo(cmPush, otDebugRegistr, cpu_address_size, (uint8_t)i)) + continue; + + IntelRegistrList registr_list = free_registr_list_; + reg1 = registr_list.GetRandom(); + if (ctx.options.flags & cpEncryptBytecode) { + if (type_ == vtAdvanced) { + end_cryptor = new OpcodeCryptor(); + cryptor_list_.push_back(end_cryptor); + end_cryptor->Init(osDWord); + } + } + opcode_entry = processor_->AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size, reg1), IntelOperand(otDebugRegistr, cpu_address_size, (uint8_t)i)); + operand_size = 0; + result_size = OperandSizeToValue(cpu_address_size); + if (result_size > operand_size) + processor_->AddCommand(cmSub, IntelOperand(otRegistr, cpu_address_size, stack_registr_), IntelOperand(otValue, cpu_address_size, 0, result_size - operand_size)); + else if (result_size < operand_size) //-V547 + processor_->AddCommand(cmAdd, IntelOperand(otRegistr, cpu_address_size, stack_registr_), IntelOperand(otValue, cpu_address_size, 0, operand_size - result_size)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr, cpu_address_size, stack_registr_), IntelOperand(otRegistr, cpu_address_size, reg1)); + AddEndHandlerCommands((result_size > operand_size) ? check_stack : read_opcode, end_cryptor); + opcode_list_.Add(cmPush, otDebugRegistr, cpu_address_size, (uint8_t)i, opcode_entry, NULL, end_cryptor); + } + + // pop debug registr + for (i = 0; i < debug_reg_count; i++) { + if (!visible_opcode_list.GetOpcodeInfo(cmPop, otDebugRegistr, cpu_address_size, (uint8_t)i)) + continue; + + IntelRegistrList registr_list = free_registr_list_; + reg1 = registr_list.GetRandom(); + if (ctx.options.flags & cpEncryptBytecode) { + if (type_ == vtAdvanced) { + end_cryptor = new OpcodeCryptor(); + cryptor_list_.push_back(end_cryptor); + end_cryptor->Init(osDWord); + } + } + opcode_entry = processor_->AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size, reg1), IntelOperand(otMemory | otRegistr, cpu_address_size, stack_registr_)); + operand_size = OperandSizeToValue(cpu_address_size); + result_size = 0; + if (result_size > operand_size) //-V547 + processor_->AddCommand(cmSub, IntelOperand(otRegistr, cpu_address_size, stack_registr_), IntelOperand(otValue, cpu_address_size, 0, result_size - operand_size)); + else if (result_size < operand_size) + processor_->AddCommand(cmAdd, IntelOperand(otRegistr, cpu_address_size, stack_registr_), IntelOperand(otValue, cpu_address_size, 0, operand_size - result_size)); + command = processor_->AddCommand(cmMov, IntelOperand(otDebugRegistr, cpu_address_size, (uint8_t)i), IntelOperand(otRegistr, cpu_address_size, reg1)); + AddEndHandlerCommands((result_size > operand_size) ? check_stack : read_opcode, end_cryptor); //-V547 + opcode_list_.Add(cmPop, otDebugRegistr, cpu_address_size, (uint8_t)i, opcode_entry, NULL, end_cryptor); + } + + size_t control_reg_count = cpu_address_size == osDWord ? 8 : 9; + + // push control registr + for (i = 0; i < control_reg_count; i++) { + if (!visible_opcode_list.GetOpcodeInfo(cmPush, otControlRegistr, cpu_address_size, (uint8_t)i)) + continue; + + IntelRegistrList registr_list = free_registr_list_; + reg1 = registr_list.GetRandom(); + if (ctx.options.flags & cpEncryptBytecode) { + if (type_ == vtAdvanced) { + end_cryptor = new OpcodeCryptor(); + cryptor_list_.push_back(end_cryptor); + end_cryptor->Init(osDWord); + } + } + opcode_entry = processor_->AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size, reg1), IntelOperand(otControlRegistr, cpu_address_size, (uint8_t)i)); + operand_size = 0; + result_size = OperandSizeToValue(cpu_address_size); + if (result_size > operand_size) + processor_->AddCommand(cmSub, IntelOperand(otRegistr, cpu_address_size, stack_registr_), IntelOperand(otValue, cpu_address_size, 0, result_size - operand_size)); + else if (result_size < operand_size) //-V547 + processor_->AddCommand(cmAdd, IntelOperand(otRegistr, cpu_address_size, stack_registr_), IntelOperand(otValue, cpu_address_size, 0, operand_size - result_size)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr, cpu_address_size, stack_registr_), IntelOperand(otRegistr, cpu_address_size, reg1)); + AddEndHandlerCommands((result_size > operand_size) ? check_stack : read_opcode, end_cryptor); + opcode_list_.Add(cmPush, otControlRegistr, cpu_address_size, (uint8_t)i, opcode_entry, NULL, end_cryptor); + } + + // pop control registr + for (i = 0; i < control_reg_count; i++) { + if (!visible_opcode_list.GetOpcodeInfo(cmPop, otControlRegistr, cpu_address_size, (uint8_t)i)) + continue; + + IntelRegistrList registr_list = free_registr_list_; + reg1 = registr_list.GetRandom(); + if (ctx.options.flags & cpEncryptBytecode) { + if (type_ == vtAdvanced) { + end_cryptor = new OpcodeCryptor(); + cryptor_list_.push_back(end_cryptor); + end_cryptor->Init(osDWord); + } + } + opcode_entry = processor_->AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size, reg1), IntelOperand(otMemory | otRegistr, cpu_address_size, stack_registr_)); + operand_size = OperandSizeToValue(cpu_address_size); + result_size = 0; + if (result_size > operand_size) //-V547 + processor_->AddCommand(cmSub, IntelOperand(otRegistr, cpu_address_size, stack_registr_), IntelOperand(otValue, cpu_address_size, 0, result_size - operand_size)); + else if (result_size < operand_size) + processor_->AddCommand(cmAdd, IntelOperand(otRegistr, cpu_address_size, stack_registr_), IntelOperand(otValue, cpu_address_size, 0, operand_size - result_size)); + command = processor_->AddCommand(cmMov, IntelOperand(otControlRegistr, cpu_address_size, (uint8_t)i), IntelOperand(otRegistr, cpu_address_size, reg1)); + AddEndHandlerCommands((result_size > operand_size) ? check_stack : read_opcode, end_cryptor); //-V547 + opcode_list_.Add(cmPop, otControlRegistr, cpu_address_size, (uint8_t)i, opcode_entry, NULL, end_cryptor); + } + + // push ESP + for (s = osWord; s <= cpu_address_size; s++) { + size = static_cast(s); + IntelRegistrList registr_list = free_registr_list_; + reg1 = registr_list.GetRandom(); + if (ctx.options.flags & cpEncryptBytecode) { + if (type_ == vtAdvanced) { + end_cryptor = new OpcodeCryptor(); + cryptor_list_.push_back(end_cryptor); + end_cryptor->Init(osDWord); + } + } + opcode_entry = processor_->AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size, reg1), IntelOperand(otRegistr, cpu_address_size, stack_registr_)); + operand_size = 0; + result_size = OperandSizeToValue(size); + if (result_size > operand_size) + processor_->AddCommand(cmSub, IntelOperand(otRegistr, cpu_address_size, stack_registr_), IntelOperand(otValue, cpu_address_size, 0, result_size - operand_size)); + else if (result_size < operand_size) //-V547 + processor_->AddCommand(cmAdd, IntelOperand(otRegistr, cpu_address_size, stack_registr_), IntelOperand(otValue, cpu_address_size, 0, operand_size - result_size)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr, size, stack_registr_), IntelOperand(otRegistr, size, reg1)); + AddEndHandlerCommands((result_size > operand_size) ? check_stack : read_opcode, end_cryptor); + opcode_list_.Add(cmPush, otRegistr, size, 0xFF, opcode_entry, NULL, end_cryptor); + } + + // pop ESP + for (s = osWord; s <= cpu_address_size; s++) { + if (ctx.options.flags & cpEncryptBytecode) { + if (type_ == vtAdvanced) { + end_cryptor = new OpcodeCryptor(); + cryptor_list_.push_back(end_cryptor); + end_cryptor->Init(osDWord); + } + } + size = static_cast(s); + opcode_entry = processor_->AddCommand(cmMov, IntelOperand(otRegistr, size, stack_registr_), IntelOperand(otMemory | otRegistr, size, stack_registr_)); + AddEndHandlerCommands(check_stack, end_cryptor); + opcode_list_.Add(cmPop, otRegistr, size, 0xFF, opcode_entry, NULL, end_cryptor); + } + + // add + for (s = osByte; s <= cpu_address_size; s++) { + size = static_cast(s); + IntelRegistrList registr_list = free_registr_list_; + reg1 = registr_list.GetRandom(size == osByte && cpu_address_size == osDWord); + reg2 = registr_list.GetRandom(size == osByte && cpu_address_size == osDWord); + if (ctx.options.flags & cpEncryptBytecode) { + if (type_ == vtAdvanced) { + end_cryptor = new OpcodeCryptor(); + cryptor_list_.push_back(end_cryptor); + end_cryptor->Init(osDWord); + } + } + mov_size = (size == osByte) ? osWord : size; + opcode_entry = processor_->AddCommand((mov_size == size) ? cmMov : cmMovzx, IntelOperand(otRegistr, mov_size, reg1), IntelOperand(otMemory | otRegistr, size, stack_registr_)); + processor_->AddCommand(cmMov, IntelOperand(otRegistr, size, reg2), IntelOperand(otMemory | otRegistr | otValue, size, stack_registr_, OperandSizeToValue(mov_size))); + operand_size = OperandSizeToValue(mov_size); + result_size = OperandSizeToValue(cpu_address_size); + if (result_size > operand_size) + processor_->AddCommand(cmSub, IntelOperand(otRegistr, cpu_address_size, stack_registr_), IntelOperand(otValue, cpu_address_size, 0, result_size - operand_size)); + else if (result_size < operand_size) + processor_->AddCommand(cmAdd, IntelOperand(otRegistr, cpu_address_size, stack_registr_), IntelOperand(otValue, cpu_address_size, 0, operand_size - result_size)); + processor_->AddCommand(cmAdd, IntelOperand(otRegistr, size, reg1), IntelOperand(otRegistr, size, reg2)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr | otValue, mov_size, stack_registr_, OperandSizeToValue(cpu_address_size)), IntelOperand(otRegistr, mov_size, reg1)); + processor_->AddCommand(cmPushf, IntelOperand(otNone, cpu_address_size)); + processor_->AddCommand(cmPop, IntelOperand(otMemory | otRegistr, cpu_address_size, stack_registr_)); + AddEndHandlerCommands((result_size > operand_size) ? check_stack : read_opcode, end_cryptor); + opcode_list_.Add(cmAdd, otNone, size, true, opcode_entry, NULL, end_cryptor); + } + + // nor + for (s = osByte; s <= cpu_address_size; s++) { + size = static_cast(s); + IntelRegistrList registr_list = free_registr_list_; + reg1 = registr_list.GetRandom(size == osByte && cpu_address_size == osDWord); + reg2 = registr_list.GetRandom(size == osByte && cpu_address_size == osDWord); + if (ctx.options.flags & cpEncryptBytecode) { + if (type_ == vtAdvanced) { + end_cryptor = new OpcodeCryptor(); + cryptor_list_.push_back(end_cryptor); + end_cryptor->Init(osDWord); + } + } + mov_size = (size == osByte) ? osWord : size; + opcode_entry = processor_->AddCommand((mov_size == size) ? cmMov : cmMovzx, IntelOperand(otRegistr, mov_size, reg1), IntelOperand(otMemory | otRegistr, size, stack_registr_)); + processor_->AddCommand(cmMov, IntelOperand(otRegistr, size, reg2), IntelOperand(otMemory | otRegistr | otValue, size, stack_registr_, OperandSizeToValue(mov_size))); + operand_size = OperandSizeToValue(mov_size); + result_size = OperandSizeToValue(cpu_address_size); + if (result_size > operand_size) + processor_->AddCommand(cmSub, IntelOperand(otRegistr, cpu_address_size, stack_registr_), IntelOperand(otValue, cpu_address_size, 0, result_size - operand_size)); + else if (result_size < operand_size) + processor_->AddCommand(cmAdd, IntelOperand(otRegistr, cpu_address_size, stack_registr_), IntelOperand(otValue, cpu_address_size, 0, operand_size - result_size)); + processor_->AddCommand(cmNot, IntelOperand(otRegistr, size, reg1)); + processor_->AddCommand(cmNot, IntelOperand(otRegistr, size, reg2)); + processor_->AddCommand(cmAnd, IntelOperand(otRegistr, size, reg1), IntelOperand(otRegistr, size, reg2)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr | otValue, mov_size, stack_registr_, OperandSizeToValue(cpu_address_size)), IntelOperand(otRegistr, mov_size, reg1)); + processor_->AddCommand(cmPushf, IntelOperand(otNone, cpu_address_size)); + processor_->AddCommand(cmPop, IntelOperand(otMemory | otRegistr, cpu_address_size, stack_registr_)); + AddEndHandlerCommands((result_size > operand_size) ? check_stack : read_opcode, end_cryptor); + opcode_list_.Add(cmNor, otNone, size, true, opcode_entry, NULL, end_cryptor); + } + + // nand + for (s = osByte; s <= cpu_address_size; s++) { + size = static_cast(s); + IntelRegistrList registr_list = free_registr_list_; + reg1 = registr_list.GetRandom(size == osByte && cpu_address_size == osDWord); + reg2 = registr_list.GetRandom(size == osByte && cpu_address_size == osDWord); + if (ctx.options.flags & cpEncryptBytecode) { + if (type_ == vtAdvanced) { + end_cryptor = new OpcodeCryptor(); + cryptor_list_.push_back(end_cryptor); + end_cryptor->Init(osDWord); + } + } + mov_size = (size == osByte) ? osWord : size; + opcode_entry = processor_->AddCommand((mov_size == size) ? cmMov : cmMovzx, IntelOperand(otRegistr, mov_size, reg1), IntelOperand(otMemory | otRegistr, size, stack_registr_)); + processor_->AddCommand(cmMov, IntelOperand(otRegistr, size, reg2), IntelOperand(otMemory | otRegistr | otValue, size, stack_registr_, OperandSizeToValue(mov_size))); + operand_size = OperandSizeToValue(mov_size); + result_size = OperandSizeToValue(cpu_address_size); + if (result_size > operand_size) + processor_->AddCommand(cmSub, IntelOperand(otRegistr, cpu_address_size, stack_registr_), IntelOperand(otValue, cpu_address_size, 0, result_size - operand_size)); + else if (result_size < operand_size) + processor_->AddCommand(cmAdd, IntelOperand(otRegistr, cpu_address_size, stack_registr_), IntelOperand(otValue, cpu_address_size, 0, operand_size - result_size)); + processor_->AddCommand(cmNot, IntelOperand(otRegistr, size, reg1)); + processor_->AddCommand(cmNot, IntelOperand(otRegistr, size, reg2)); + processor_->AddCommand(cmOr, IntelOperand(otRegistr, size, reg1), IntelOperand(otRegistr, size, reg2)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr | otValue, mov_size, stack_registr_, OperandSizeToValue(cpu_address_size)), IntelOperand(otRegistr, mov_size, reg1)); + processor_->AddCommand(cmPushf, IntelOperand(otNone, cpu_address_size)); + processor_->AddCommand(cmPop, IntelOperand(otMemory | otRegistr, cpu_address_size, stack_registr_)); + AddEndHandlerCommands((result_size > operand_size) ? check_stack : read_opcode, end_cryptor); + opcode_list_.Add(cmNand, otNone, size, true, opcode_entry, NULL, end_cryptor); + } + + // shl, shr + for (i = 0; i < 2; i++) { + command_type = (i == 0) ? cmShl : cmShr; + for (s = osByte; s <= cpu_address_size; s++) { + size = static_cast(s); + IntelRegistrList registr_list = free_registr_list_; + registr_list.remove(regECX); + reg1 = registr_list.GetRandom(size == osByte && cpu_address_size == osDWord); + if (ctx.options.flags & cpEncryptBytecode) { + if (type_ == vtAdvanced) { + end_cryptor = new OpcodeCryptor(); + cryptor_list_.push_back(end_cryptor); + end_cryptor->Init(osDWord); + } + } + mov_size = (size == osByte) ? osWord : size; + opcode_entry = processor_->AddCommand((mov_size == size) ? cmMov : cmMovzx, IntelOperand(otRegistr, mov_size, reg1), IntelOperand(otMemory | otRegistr, size, stack_registr_)); + processor_->AddCommand(cmMov, IntelOperand(otRegistr, osByte, regECX), IntelOperand(otMemory | otRegistr | otValue, osByte, stack_registr_, OperandSizeToValue(mov_size))); + operand_size = OperandSizeToValue(osWord); + result_size = OperandSizeToValue(cpu_address_size); + if (result_size > operand_size) + processor_->AddCommand(cmSub, IntelOperand(otRegistr, cpu_address_size, stack_registr_), IntelOperand(otValue, cpu_address_size, 0, result_size - operand_size)); + else if (result_size < operand_size) + processor_->AddCommand(cmAdd, IntelOperand(otRegistr, cpu_address_size, stack_registr_), IntelOperand(otValue, cpu_address_size, 0, operand_size - result_size)); + processor_->AddCommand(command_type, IntelOperand(otRegistr, size, reg1), IntelOperand(otRegistr, osByte, regECX)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr | otValue, mov_size, stack_registr_, OperandSizeToValue(cpu_address_size)), IntelOperand(otRegistr, mov_size, reg1)); + processor_->AddCommand(cmPushf, IntelOperand(otNone, cpu_address_size)); + processor_->AddCommand(cmPop, IntelOperand(otMemory | otRegistr, cpu_address_size, stack_registr_)); + AddEndHandlerCommands((result_size > operand_size) ? check_stack : read_opcode, end_cryptor); + opcode_list_.Add(command_type, otNone, size, true, opcode_entry, NULL, end_cryptor); + } + } + + // rcl, rcr + for (i = 0; i < 2; i++) { + command_type = (i == 0) ? cmRcl : cmRcr; + for (s = osByte; s <= cpu_address_size; s++) { + size = static_cast(s); + if (!visible_opcode_list.GetOpcodeInfo(command_type, otNone, size, true)) + continue; + + IntelRegistrList registr_list = free_registr_list_; + registr_list.remove(regECX); + reg1 = registr_list.GetRandom(size == osByte && cpu_address_size == osDWord); + if (ctx.options.flags & cpEncryptBytecode) { + if (type_ == vtAdvanced) { + end_cryptor = new OpcodeCryptor(); + cryptor_list_.push_back(end_cryptor); + end_cryptor->Init(osDWord); + } + } + mov_size = (size == osByte) ? osWord : size; + opcode_entry = processor_->AddCommand((mov_size == size) ? cmMov : cmMovzx, IntelOperand(otRegistr, mov_size, reg1), IntelOperand(otMemory | otRegistr, size, stack_registr_)); + processor_->AddCommand(cmMov, IntelOperand(otRegistr, osWord, regECX), IntelOperand(otMemory | otRegistr | otValue, osWord, stack_registr_, OperandSizeToValue(mov_size))); + operand_size = OperandSizeToValue(osWord); + result_size = OperandSizeToValue(cpu_address_size); + if (result_size > operand_size) + processor_->AddCommand(cmSub, IntelOperand(otRegistr, cpu_address_size, stack_registr_), IntelOperand(otValue, cpu_address_size, 0, result_size - operand_size)); + else if (result_size < operand_size) + processor_->AddCommand(cmAdd, IntelOperand(otRegistr, cpu_address_size, stack_registr_), IntelOperand(otValue, cpu_address_size, 0, operand_size - result_size)); + processor_->AddCommand(cmShr, IntelOperand(otHiPartRegistr, osByte, regECX), IntelOperand(otValue, osByte, 0, 1)); + processor_->AddCommand(command_type, IntelOperand(otRegistr, size, reg1), IntelOperand(otRegistr, osByte, regECX)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr | otValue, mov_size, stack_registr_, OperandSizeToValue(cpu_address_size)), IntelOperand(otRegistr, mov_size, reg1)); + processor_->AddCommand(cmPushf, IntelOperand(otNone, cpu_address_size)); + processor_->AddCommand(cmPop, IntelOperand(otMemory | otRegistr, cpu_address_size, stack_registr_)); + AddEndHandlerCommands((result_size > operand_size) ? check_stack : read_opcode, end_cryptor); + opcode_list_.Add(command_type, otNone, size, true, opcode_entry, NULL, end_cryptor); + } + } + + // shld, shrd + for (i = 0; i < 2; i++) { + command_type = (i == 0) ? cmShld : cmShrd; + for (s = osDWord; s <= cpu_address_size; s++) { + size = static_cast(s); + IntelRegistrList registr_list = free_registr_list_; + registr_list.remove(regECX); + reg1 = registr_list.GetRandom(size == osByte && cpu_address_size == osDWord); + reg2 = registr_list.GetRandom(size == osByte && cpu_address_size == osDWord); + if (ctx.options.flags & cpEncryptBytecode) { + if (type_ == vtAdvanced) { + end_cryptor = new OpcodeCryptor(); + cryptor_list_.push_back(end_cryptor); + end_cryptor->Init(osDWord); + } + } + opcode_entry = processor_->AddCommand(cmMov, IntelOperand(otRegistr, size, reg1), IntelOperand(otMemory | otRegistr, size, stack_registr_)); + processor_->AddCommand(cmMov, IntelOperand(otRegistr, size, reg2), IntelOperand(otMemory | otRegistr | otValue, size, stack_registr_, OperandSizeToValue(size))); + processor_->AddCommand(cmMov, IntelOperand(otRegistr, osByte, regECX), IntelOperand(otMemory | otRegistr | otValue, osByte, stack_registr_, OperandSizeToValue(size) * 2)); + operand_size = OperandSizeToValue(size) + OperandSizeToValue(osWord); + result_size = OperandSizeToValue(cpu_address_size); + if (result_size > operand_size) + processor_->AddCommand(cmSub, IntelOperand(otRegistr, cpu_address_size, stack_registr_), IntelOperand(otValue, cpu_address_size, 0, result_size - operand_size)); + else if (result_size < operand_size) + processor_->AddCommand(cmAdd, IntelOperand(otRegistr, cpu_address_size, stack_registr_), IntelOperand(otValue, cpu_address_size, 0, operand_size - result_size)); + processor_->AddCommand(command_type, IntelOperand(otRegistr, size, reg1), IntelOperand(otRegistr, size, reg2), IntelOperand(otRegistr, osByte, regECX)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr | otValue, size, stack_registr_, OperandSizeToValue(cpu_address_size)), IntelOperand(otRegistr, size, reg1)); + processor_->AddCommand(cmPushf, IntelOperand(otNone, cpu_address_size)); + processor_->AddCommand(cmPop, IntelOperand(otMemory | otRegistr, cpu_address_size, stack_registr_)); + AddEndHandlerCommands((result_size > operand_size) ? check_stack : read_opcode, end_cryptor); + opcode_list_.Add(command_type, otNone, size, true, opcode_entry, NULL, end_cryptor); + } + } + + // div, idiv + for (i = 0; i < 2; i++) { + command_type = (i == 0) ? cmDiv : cmIdiv; + for (s = osByte; s <= cpu_address_size; s++) { + size = static_cast(s); + if (!visible_opcode_list.GetOpcodeInfo(command_type, otNone, size, true)) + continue; + + if (ctx.options.flags & cpEncryptBytecode) { + if (type_ == vtAdvanced) { + end_cryptor = new OpcodeCryptor(); + cryptor_list_.push_back(end_cryptor); + end_cryptor->Init(osDWord); + } + } + mov_size = (size == osByte) ? osWord : size; + if (size == osByte) { + opcode_entry = processor_->AddCommand(cmMovzx, IntelOperand(otRegistr, mov_size, regEAX), IntelOperand(otMemory | otRegistr, size, stack_registr_)); + processor_->AddCommand(cmMov, IntelOperand(otRegistr, size, regECX), IntelOperand(otMemory | otRegistr | otValue, size, stack_registr_, OperandSizeToValue(mov_size))); + } + else { + opcode_entry = processor_->AddCommand(cmMov, IntelOperand(otRegistr, size, regEAX), IntelOperand(otMemory | otRegistr | otValue, size, stack_registr_, OperandSizeToValue(size))); + processor_->AddCommand(cmMov, IntelOperand(otRegistr, size, regEDX), IntelOperand(otMemory | otRegistr, size, stack_registr_)); + processor_->AddCommand(cmMov, IntelOperand(otRegistr, size, regECX), IntelOperand(otMemory | otRegistr | otValue, size, stack_registr_, OperandSizeToValue(size) * 2)); + } + operand_size = OperandSizeToValue(mov_size); + result_size = OperandSizeToValue(cpu_address_size); + if (result_size > operand_size) + processor_->AddCommand(cmSub, IntelOperand(otRegistr, cpu_address_size, stack_registr_), IntelOperand(otValue, cpu_address_size, 0, result_size - operand_size)); + else if (result_size < operand_size) + processor_->AddCommand(cmAdd, IntelOperand(otRegistr, cpu_address_size, stack_registr_), IntelOperand(otValue, cpu_address_size, 0, operand_size - result_size)); + processor_->AddCommand(command_type, IntelOperand(otRegistr, size, regECX)); + if (size == osByte) { + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr | otValue, mov_size, stack_registr_, OperandSizeToValue(cpu_address_size)), IntelOperand(otRegistr, mov_size, regEAX)); + } + else { + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr | otValue, mov_size, stack_registr_, OperandSizeToValue(cpu_address_size)), IntelOperand(otRegistr, size, regEDX)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr | otValue, mov_size, stack_registr_, OperandSizeToValue(cpu_address_size) + OperandSizeToValue(mov_size)), IntelOperand(otRegistr, size, regEAX)); + } + processor_->AddCommand(cmPushf, IntelOperand(otNone, cpu_address_size)); + processor_->AddCommand(cmPop, IntelOperand(otMemory | otRegistr, cpu_address_size, stack_registr_)); + AddEndHandlerCommands((result_size > operand_size) ? check_stack : read_opcode, end_cryptor); + opcode_list_.Add(command_type, otNone, size, true, opcode_entry, NULL, end_cryptor); + } + } + + // mul, imul + for (i = 0; i < 2; i++) { + command_type = (i == 0) ? cmMul : cmImul; + for (s = osByte; s <= cpu_address_size; s++) { + size = static_cast(s); + if (!visible_opcode_list.GetOpcodeInfo(command_type, otNone, size, true)) + continue; + + if (ctx.options.flags & cpEncryptBytecode) { + if (type_ == vtAdvanced) { + end_cryptor = new OpcodeCryptor(); + cryptor_list_.push_back(end_cryptor); + end_cryptor->Init(osDWord); + } + } + mov_size = (size == osByte) ? osWord : size; + opcode_entry = processor_->AddCommand((mov_size == size) ? cmMov : cmMovzx, IntelOperand(otRegistr, mov_size, regEAX), IntelOperand(otMemory | otRegistr | otValue, size, stack_registr_, OperandSizeToValue(mov_size))); + processor_->AddCommand(cmMov, IntelOperand(otRegistr, size, regEDX), IntelOperand(otMemory | otRegistr, size, stack_registr_)); + operand_size = (size == osByte) ? OperandSizeToValue(mov_size) : 0; + result_size = OperandSizeToValue(cpu_address_size); + if (result_size > operand_size) + processor_->AddCommand(cmSub, IntelOperand(otRegistr, cpu_address_size, stack_registr_), IntelOperand(otValue, cpu_address_size, 0, result_size - operand_size)); + else if (result_size < operand_size) + processor_->AddCommand(cmAdd, IntelOperand(otRegistr, cpu_address_size, stack_registr_), IntelOperand(otValue, cpu_address_size, 0, operand_size - result_size)); + processor_->AddCommand(command_type, IntelOperand(otRegistr, size, regEDX)); + if (size == osByte) { + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr | otValue, mov_size, stack_registr_, OperandSizeToValue(cpu_address_size)), IntelOperand(otRegistr, mov_size, regEAX)); + } + else { + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr | otValue, mov_size, stack_registr_, OperandSizeToValue(cpu_address_size)), IntelOperand(otRegistr, mov_size, regEDX)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr | otValue, mov_size, stack_registr_, OperandSizeToValue(cpu_address_size) + OperandSizeToValue(mov_size)), IntelOperand(otRegistr, mov_size, regEAX)); + } + processor_->AddCommand(cmPushf, IntelOperand(otNone, cpu_address_size)); + processor_->AddCommand(cmPop, IntelOperand(otMemory | otRegistr, cpu_address_size, stack_registr_)); + AddEndHandlerCommands((result_size > operand_size) ? check_stack : read_opcode, end_cryptor); + opcode_list_.Add(command_type, otNone, size, true, opcode_entry, NULL, end_cryptor); + } + } + + // fild, fld, fadd, fsub, fsubr, fstp, fst, fist, fistp, fdiv, fmul, fcomp, fstcw, fldcw, fstsw + for (i = 0; i < 33; i++) { + switch (i) { + case 0: + command_type = cmFild; + size = osWord; + break; + case 1: + command_type = cmFild; + size = osDWord; + break; + case 2: + command_type = cmFild; + size = osQWord; + break; + case 3: + command_type = cmFld; + size = osDWord; + break; + case 4: + command_type = cmFld; + size = osQWord; + break; + case 5: + command_type = cmFld; + size = osTByte; + break; + case 6: + command_type = cmFadd; + size = osDWord; + break; + case 7: + command_type = cmFadd; + size = osQWord; + break; + case 8: + command_type = cmFsub; + size = osDWord; + break; + case 9: + command_type = cmFsub; + size = osQWord; + break; + case 10: + command_type = cmFsubr; + size = osDWord; + break; + case 11: + command_type = cmFsubr; + size = osQWord; + break; + case 12: + command_type = cmFstp; + size = osDWord; + break; + case 13: + command_type = cmFstp; + size = osQWord; + break; + case 14: + command_type = cmFstp; + size = osTByte; + break; + case 15: + command_type = cmFst; + size = osDWord; + break; + case 16: + command_type = cmFst; + size = osQWord; + break; + case 17: + command_type = cmFist; + size = osWord; + break; + case 18: + command_type = cmFist; + size = osDWord; + break; + case 19: + command_type = cmFistp; + size = osWord; + break; + case 20: + command_type = cmFistp; + size = osDWord; + break; + case 21: + command_type = cmFistp; + size = osQWord; + break; + case 22: + command_type = cmFisub; + size = osWord; + break; + case 23: + command_type = cmFisub; + size = osDWord; + break; + case 24: + command_type = cmFdiv; + size = osDWord; + break; + case 25: + command_type = cmFdiv; + size = osQWord; + break; + case 26: + command_type = cmFmul; + size = osDWord; + break; + case 27: + command_type = cmFmul; + size = osQWord; + break; + case 28: + command_type = cmFcomp; + size = osDWord; + break; + case 29: + command_type = cmFcomp; + size = osQWord; + break; + case 30: + command_type = cmFstcw; + size = osWord; + break; + case 31: + command_type = cmFldcw; + size = osWord; + break; + case 32: + command_type = cmFstsw; + size = osWord; + break; + } + if (!visible_opcode_list.GetOpcodeInfo(command_type, otNone, size, 0)) + continue; + + if (ctx.options.flags & cpEncryptBytecode) { + if (type_ == vtAdvanced) { + end_cryptor = new OpcodeCryptor(); + cryptor_list_.push_back(end_cryptor); + end_cryptor->Init(osDWord); + } + } + opcode_entry = processor_->AddCommand(command_type, IntelOperand(otMemory | otRegistr, size, stack_registr_)); + AddEndHandlerCommands(read_opcode, end_cryptor); + opcode_list_.Add(command_type, otNone, size, 0, opcode_entry, NULL, end_cryptor); + } + + // wait, fchs, fsqrt, f2xm1, fabs, fclex, fcos, fdecstp, fincstp, finit, fldln2, fldz, fld1, fldpi, fpatan, fprem, fprem1, fptan, frndint, fsin, ftst, fyl2x, fldlg2 + for (i = 0; i < 24; i++) { + switch (i) { + case 0: + command_type = cmWait; + break; + case 1: + command_type = cmFchs; + break; + case 2: + command_type = cmFsqrt; + break; + case 3: + command_type = cmF2xm1; + break; + case 4: + command_type = cmFabs; + break; + case 5: + command_type = cmFclex; + break; + case 6: + command_type = cmFcos; + break; + case 7: + command_type = cmFdecstp; + break; + case 8: + command_type = cmFincstp; + break; + case 9: + command_type = cmFinit; + break; + case 10: + command_type = cmFldln2; + break; + case 12: + command_type = cmFldz; + break; + case 13: + command_type = cmFld1; + break; + case 14: + command_type = cmFldpi; + break; + case 15: + command_type = cmFpatan; + break; + case 16: + command_type = cmFprem; + break; + case 17: + command_type = cmFprem1; + break; + case 18: + command_type = cmFptan; + break; + case 19: + command_type = cmFrndint; + break; + case 20: + command_type = cmFsin; + break; + case 21: + command_type = cmFtst; + break; + case 22: + command_type = cmFyl2x; + break; + case 23: + command_type = cmFldlg2; + break; + } + if (!visible_opcode_list.GetOpcodeInfo(command_type, otNone, cpu_address_size, 0)) + continue; + + if (ctx.options.flags & cpEncryptBytecode) { + if (type_ == vtAdvanced) { + end_cryptor = new OpcodeCryptor(); + cryptor_list_.push_back(end_cryptor); + end_cryptor->Init(osDWord); + } + } + opcode_entry = processor_->AddCommand(command_type); + AddEndHandlerCommands(read_opcode, end_cryptor); + opcode_list_.Add(command_type, otNone, cpu_address_size, 0, opcode_entry, NULL, end_cryptor); + } + + // ret, iret + for (j = 0; j < 3; j++) { + command_type = (j == 1) ? cmIret : cmRet; + if (j > 0 && !visible_opcode_list.GetOpcodeInfo(command_type, otNone, cpu_address_size, (j == 2) ? 1 : 0)) + continue; + + opcode_entry = processor_->AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size, regESP), IntelOperand(otRegistr, cpu_address_size, stack_registr_)); + + for (i = registr_order_.size(); i > 0; i--) { + uint8_t reg = registr_order_[i - 1]; + if (reg == regEFX) { + processor_->AddCommand(cmPopf); + } + else { + processor_->AddCommand(cmPop, IntelOperand(otRegistr, cpu_address_size, reg)); + } + } + + command = processor_->AddCommand(command_type); + if (j == 2) + command->include_option(roFar); + opcode_list_.Add(command_type, otNone, cpu_address_size, (command->options() & roFar) ? 1 : 0, opcode_entry); + } + + // popf + { + if (ctx.options.flags & cpEncryptBytecode) { + if (type_ == vtAdvanced) { + end_cryptor = new OpcodeCryptor(); + cryptor_list_.push_back(end_cryptor); + end_cryptor->Init(osDWord); + } + } + opcode_entry = processor_->AddCommand(cmPush, IntelOperand(otMemory | otRegistr, cpu_address_size, stack_registr_)); + operand_size = OperandSizeToValue(cpu_address_size); + result_size = 0; + if (result_size > operand_size) //-V547 + processor_->AddCommand(cmSub, IntelOperand(otRegistr, cpu_address_size, stack_registr_), IntelOperand(otValue, cpu_address_size, 0, result_size - operand_size)); + else if (result_size < operand_size) + processor_->AddCommand(cmAdd, IntelOperand(otRegistr, cpu_address_size, stack_registr_), IntelOperand(otValue, cpu_address_size, 0, operand_size - result_size)); + processor_->AddCommand(cmPopf, IntelOperand(otNone, cpu_address_size)); + AddEndHandlerCommands((result_size > operand_size) ? check_stack : read_opcode, end_cryptor); //-V547 + opcode_list_.Add(cmPopf, otNone, cpu_address_size, 0, opcode_entry, NULL, end_cryptor); + } + + // jmp + for (i = 0; i < ctx.options.vm_count; i++) { + IntelRegistrList registr_list = free_registr_list_; + reg1 = registr_list.GetRandom(); + opcode_entry = processor_->AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size, reg1), IntelOperand(otMemory | otRegistr, cpu_address_size, stack_registr_)); + processor_->AddCommand(cmAdd, IntelOperand(otRegistr, cpu_address_size, stack_registr_), IntelOperand(otValue, cpu_address_size, 0, OperandSizeToStack(cpu_address_size))); + command = processor_->AddCommand(cmJmp, IntelOperand(otValue, cpu_address_size)); + command->AddLink(0, ltJmp); + vm_links_.push_back(command); + + opcode_list_.Add(cmJmp, otNone, cpu_address_size, (uint8_t)i + 1, opcode_entry); + } + + // rdtsc + if (visible_opcode_list.GetOpcodeInfo(cmRdtsc, otNone, cpu_address_size, 0)) { + if (ctx.options.flags & cpEncryptBytecode) { + if (type_ == vtAdvanced) { + end_cryptor = new OpcodeCryptor(); + cryptor_list_.push_back(end_cryptor); + end_cryptor->Init(osDWord); + } + } + opcode_entry = processor_->AddCommand(cmRdtsc); + operand_size = 0; + result_size = OperandSizeToValue(osDWord) * 2; + if (result_size > operand_size) + processor_->AddCommand(cmSub, IntelOperand(otRegistr, cpu_address_size, stack_registr_), IntelOperand(otValue, cpu_address_size, 0, result_size - operand_size)); + else if (result_size < operand_size) //-V547 + processor_->AddCommand(cmAdd, IntelOperand(otRegistr, cpu_address_size, stack_registr_), IntelOperand(otValue, cpu_address_size, 0, operand_size - result_size)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr, osDWord, stack_registr_), IntelOperand(otRegistr, osDWord, regEDX)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr | otValue, osDWord, stack_registr_, OperandSizeToValue(osDWord)), IntelOperand(otRegistr, osDWord, regEAX)); + AddEndHandlerCommands((result_size > operand_size) ? check_stack : read_opcode, end_cryptor); + opcode_list_.Add(cmRdtsc, otNone, cpu_address_size, 0, opcode_entry, NULL, end_cryptor); + } + + // cpuid + if (visible_opcode_list.GetOpcodeInfo(cmCpuid, otNone, cpu_address_size, 0)) { + if (stack_registr_ == regEBX) { + IntelRegistrList registr_list = free_registr_list_; + registr_list.remove(regEAX); + registr_list.remove(regEBX); + registr_list.remove(regECX); + registr_list.remove(regEDX); + reg1 = registr_list.GetRandom(); + } + else + reg1 = stack_registr_; + if (ctx.options.flags & cpEncryptBytecode) { + if (type_ == vtAdvanced) { + end_cryptor = new OpcodeCryptor(); + cryptor_list_.push_back(end_cryptor); + end_cryptor->Init(osDWord); + } + } + opcode_entry = processor_->AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regEAX), IntelOperand(otMemory | otRegistr, osDWord, stack_registr_)); + if (reg1 != stack_registr_) + processor_->AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size, reg1), IntelOperand(otRegistr, cpu_address_size, stack_registr_)); + if (IsRegistrUsed(regEBX)) + processor_->AddCommand(cmPush, IntelOperand(otRegistr, cpu_address_size, regEBX)); + processor_->AddCommand(cmCpuid); + operand_size = OperandSizeToValue(osDWord); + result_size = OperandSizeToValue(osDWord) * 4; + if (result_size > operand_size) + processor_->AddCommand(cmSub, IntelOperand(otRegistr, cpu_address_size, reg1), IntelOperand(otValue, cpu_address_size, 0, result_size - operand_size)); + else if (result_size < operand_size) + processor_->AddCommand(cmAdd, IntelOperand(otRegistr, cpu_address_size, reg1), IntelOperand(otValue, cpu_address_size, 0, operand_size - result_size)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr | otValue, osDWord, reg1, OperandSizeToValue(osDWord) * 3), IntelOperand(otRegistr, osDWord, regEAX)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr | otValue, osDWord, reg1, OperandSizeToValue(osDWord) * 2), IntelOperand(otRegistr, osDWord, regEBX)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr | otValue, osDWord, reg1, OperandSizeToValue(osDWord)), IntelOperand(otRegistr, osDWord, regECX)); + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr, osDWord, reg1), IntelOperand(otRegistr, osDWord, regEDX)); + if (IsRegistrUsed(regEBX)) + processor_->AddCommand(cmPop, IntelOperand(otRegistr, cpu_address_size, regEBX)); + if (reg1 != stack_registr_) + processor_->AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size, stack_registr_), IntelOperand(otRegistr, cpu_address_size, reg1)); + AddEndHandlerCommands((result_size > operand_size) ? check_stack : read_opcode, end_cryptor); + opcode_list_.Add(cmCpuid, otNone, cpu_address_size, 0, opcode_entry, NULL, end_cryptor); + } + + // call + if (visible_opcode_list.GetOpcodeInfo(cmCall, otNone, cpu_address_size, 0)) { + IntelRegistrList registr_list = free_registr_list_; + registr_list.remove(regEBP); + reg1 = registr_list.GetRandom(cpu_address_size == osDWord); + if (ctx.options.flags & cpEncryptBytecode) { + value_cryptor = new OpcodeCryptor(); + cryptor_list_.push_back(value_cryptor); + value_cryptor->Init(osByte); + if (type_ == vtAdvanced) { + end_cryptor = new OpcodeCryptor(); + cryptor_list_.push_back(end_cryptor); + end_cryptor->Init(osDWord); + } + } + opcode_entry = AddReadCommand(osByte, value_cryptor, reg1); + AddCallCommands(ctx.file->calling_convention(), NULL, reg1); + AddEndHandlerCommands(read_opcode, end_cryptor); + opcode_list_.Add(cmCall, otNone, cpu_address_size, 0, opcode_entry, value_cryptor, end_cryptor); + } + + // syscall + if (visible_opcode_list.GetOpcodeInfo(cmSyscall, otNone, cpu_address_size, 0)) { + IntelRegistrList registr_list = free_registr_list_; + registr_list.remove(regEBP); + reg1 = registr_list.GetRandom(cpu_address_size == osDWord); + if (ctx.options.flags & cpEncryptBytecode) { + value_cryptor = new OpcodeCryptor(); + cryptor_list_.push_back(value_cryptor); + value_cryptor->Init(osByte); + if (type_ == vtAdvanced) { + end_cryptor = new OpcodeCryptor(); + cryptor_list_.push_back(end_cryptor); + end_cryptor->Init(osDWord); + } + } + c = processor_->count(); + if (cpu_address_size == osDWord) { + // x32 + IntelVirtualMachineProcessor *new_processor = function_list->AddProcessor(osDWord); + new_processor->set_compilation_type(ctVirtualization); + + command = new_processor->AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size, regEDX), IntelOperand(otRegistr, cpu_address_size, regESP)); + new_processor->AddCommand(cmSysenter); + new_processor->AddCommand(cmRet); + + IntelCommand *sysenter_entry = new_processor->AddCommand(cmCall, IntelOperand(otValue, cpu_address_size)); + sysenter_entry->AddLink(0, ltCall, command); + new_processor->AddCommand(cmRet); + + IntelVirtualMachineProcessor *old_processor = processor_; + processor_ = new_processor; + + opcode_entry = AddReadCommand(osByte, value_cryptor, reg1); + processor_->AddCommand(cmTest, IntelOperand(otMemory | otRegistr, osDWord, stack_registr_), IntelOperand(otValue, osDWord, 0, WOW64_FLAG)); + IntelCommand *cmp_command = processor_->AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size)); + cmp_command->set_flags(fl_Z); + cmp_command->include_option(roInverseFlag); + cmp_command->AddLink(0, ltJmpWithFlag); + AddCallCommands(ctx.file->calling_convention(), sysenter_entry, reg1); + AddEndHandlerCommands(read_opcode, end_cryptor); + + jmp_command = processor_->AddCommand(cmJmp, IntelOperand(otValue, cpu_address_size)); + jmp_command->AddLink(0, ltJmp); + cmp_command->link()->set_to_command(jmp_command); + + size_t old_count = processor_->count(); + command = processor_->AddCommand(cmPush, IntelOperand(otSegmentRegistr, cpu_address_size, segCS, 0)); + jmp_command->link()->set_to_command(command); + IntelCommand *ret_offset_command = processor_->AddCommand(cmPush, IntelOperand(otValue, cpu_address_size, 0, 0, NEED_FIXUP)); + ret_offset_command->AddLink(0, ltOffset); + IntelCommand *far_call = processor_->AddCommand(cmJmp, IntelOperand(otValue, cpu_address_size, 0, 0, NEED_FIXUP), IntelOperand(otValue, osWord, 0, 0x33)); + far_call->AddLink(0, ltGateOffset); + far_call->include_option(roFar); + command = processor_->AddCommand(cmNop); + ret_offset_command->link()->set_to_command(command); + + // AMD bug + processor_->AddCommand(cmMov, IntelOperand(otRegistr, osWord, regECX), IntelOperand(otSegmentRegistr, osWord, segSS)); + processor_->AddCommand(cmMov, IntelOperand(otSegmentRegistr, osWord, segSS), IntelOperand(otRegistr, osWord, regECX)); + jmp_command = processor_->AddCommand(cmJmp, IntelOperand(otValue, cpu_address_size)); + jmp_command->AddLink(0, ltGateOffset); + + CommandBlock *block = NULL; + for (i = old_count; i < processor_->count(); i++) { + if (!block) + block = processor_->AddBlock(i, true); + command = processor_->item(i); + command->set_block(block); + block->set_end_index(i); + if (command->is_end()) + block = NULL; + } + + old_count = processor_->count(); + AddEndHandlerCommands(read_opcode, end_cryptor); + jmp_command->link()->set_to_command(processor_->item(old_count)); + + // x64 + new_processor = function_list->AddProcessor(osQWord); + new_processor->set_compilation_type(ctVirtualization); + + IntelCommand *syscall_entry = new_processor->AddCommand(cmMov, IntelOperand(otRegistr, osQWord, regR10), IntelOperand(otRegistr, osQWord, regECX)); + new_processor->AddCommand(cmSyscall); + new_processor->AddCommand(cmRet); + + processor_ = new_processor; + + old_count = new_processor->count(); + AddCallCommands(ccStdcallToMSx64, syscall_entry, reg1); + command = processor_->AddCommand(cmRet); + command->include_option(roFar); + far_call->link()->set_to_command(processor_->item(old_count)); + + processor_ = old_processor; + + jmp_command = processor_->AddCommand(cmJmp, IntelOperand(otValue, cpu_address_size)); + jmp_command->AddLink(0, ltJmp, opcode_entry); + opcode_entry = jmp_command; + } + else { + IntelVirtualMachineProcessor *new_processor = function_list->AddProcessor(osQWord); + new_processor->set_compilation_type(ctVirtualization); + IntelVirtualMachineProcessor *old_processor = processor_; + processor_ = new_processor; + + IntelCommand *call_entry = processor_->AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size, regR10), IntelOperand(otRegistr, cpu_address_size, regECX)); + processor_->AddCommand(cmSyscall); + processor_->AddCommand(cmRet); + + opcode_entry = AddReadCommand(osByte, value_cryptor, reg1); + AddCallCommands(ctx.file->calling_convention(), call_entry, reg1); + AddEndHandlerCommands(read_opcode, end_cryptor); + + processor_ = old_processor; + + jmp_command = processor_->AddCommand(cmJmp, IntelOperand(otValue, cpu_address_size)); + jmp_command->AddLink(0, ltJmp, opcode_entry); + opcode_entry = jmp_command; + } + opcode_list_.Add(cmSyscall, otNone, cpu_address_size, 0, opcode_entry, value_cryptor, end_cryptor); + } + + // crc + if (visible_opcode_list.GetOpcodeInfo(cmCrc, otNone, cpu_address_size, 0)) { + c = (type_ == vtAdvanced) ? 10 : 1; + for (size_t k = 0; k < c; k++) { + j = processor_->count(); + uint32_t crc_table_salt = rand32(); + for (i = 0; i < _countof(crc32_table); i++) { + command = processor_->AddCommand(osDWord, crc32_table[i] ^ crc_table_salt); + command->include_option(roNeedCRC); + } + IntelCommand *crc_table_entry = processor_->item(j); + crc_table_entry->include_option(roCreateNewBlock); + crc_table_entry->set_alignment(OperandSizeToValue(cpu_address_size)); + + IntelRegistrList registr_list = free_registr_list_; + registr_list.remove(regESI); + reg1 = registr_list.GetRandom(); + reg2 = registr_list.GetRandom(); + reg3 = registr_list.GetRandom(); + reg4 = 0; + if (ctx.options.flags & cpEncryptBytecode) { + if (type_ == vtAdvanced) { + end_cryptor = new OpcodeCryptor(); + cryptor_list_.push_back(end_cryptor); + end_cryptor->Init(osDWord); + } + } + + opcode_entry = processor_->AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size, reg1), IntelOperand(otMemory | otRegistr, cpu_address_size, stack_registr_)); + processor_->AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size, reg2), IntelOperand(otMemory | otRegistr | otValue, cpu_address_size, stack_registr_, OperandSizeToValue(cpu_address_size))); + operand_size = OperandSizeToValue(cpu_address_size) * 2; + result_size = OperandSizeToValue(osDWord); + if (result_size > operand_size) + processor_->AddCommand(cmSub, IntelOperand(otRegistr, cpu_address_size, stack_registr_), IntelOperand(otValue, cpu_address_size, 0, result_size - operand_size)); + else if (result_size < operand_size) + processor_->AddCommand(cmAdd, IntelOperand(otRegistr, cpu_address_size, stack_registr_), IntelOperand(otValue, cpu_address_size, 0, operand_size - result_size)); + + //processor_->AddCommand(cmInt, IntelOperand(otValue, osWord, 0, 3)); + + processor_->AddCommand(cmXor, IntelOperand(otRegistr, osDWord, reg3), IntelOperand(otRegistr, osDWord, reg3)); + processor_->AddCommand(cmTest, IntelOperand(otRegistr, cpu_address_size, reg2), IntelOperand(otRegistr, cpu_address_size, reg2)); + IntelCommand *jmp_command = processor_->AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size, 0, 0)); + jmp_command->set_flags(fl_Z); + jmp_command->AddLink(0, ltJmpWithFlag); + + if (cpu_address_size == osQWord) { + reg4 = registr_list.GetRandom(); + command = processor_->AddCommand(cmLea, IntelOperand(otRegistr, cpu_address_size, reg4), IntelOperand(otMemory | otValue, cpu_address_size, 0, 0, LARGE_VALUE)); + command->AddLink(1, ltOffset, crc_table_entry); + } + if (IsRegistrUsed(regESI)) + processor_->AddCommand(cmPush, IntelOperand(otRegistr, cpu_address_size, regESI)); + + IntelCommand *loop_command = processor_->AddCommand(cmMovzx, IntelOperand(otRegistr, osDWord, regESI), IntelOperand(otMemory | otRegistr, osByte, reg1)); + processor_->AddCommand(cmXor, IntelOperand(otRegistr, osDWord, regESI), IntelOperand(otRegistr, osDWord, reg3)); + processor_->AddCommand(cmAnd, IntelOperand(otRegistr, osDWord, regESI), IntelOperand(otValue, osDWord, 0, 0xff)); + + if (cpu_address_size == osQWord) { + command = processor_->AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regESI), IntelOperand(otMemory | otBaseRegistr | otRegistr, osDWord, (reg4 << 4) | regESI, 0)); + command->set_operand_scale(1, 2); + } + else { + command = processor_->AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regESI), IntelOperand(otMemory | otRegistr | otValue, osDWord, regESI, 0, NEED_FIXUP)); + command->set_operand_scale(1, 2); + command->AddLink(1, ltOffset, crc_table_entry); + } + + processor_->AddCommand(cmShr, IntelOperand(otRegistr, osDWord, reg3), IntelOperand(otValue, osByte, 0, 8)); + processor_->AddCommand(cmXor, IntelOperand(otRegistr, osDWord, reg3), IntelOperand(otRegistr, osDWord, regESI)); + processor_->AddCommand(cmInc, IntelOperand(otRegistr, cpu_address_size, reg1)); + processor_->AddCommand(cmXor, IntelOperand(otRegistr, osDWord, reg3), IntelOperand(otValue, osDWord, 0, crc_table_salt)); + processor_->AddCommand(cmDec, IntelOperand(otRegistr, cpu_address_size, reg2)); + + command = processor_->AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size, 0, 0)); + command->set_flags(fl_Z); + command->include_option(roInverseFlag); + command->AddLink(0, ltJmpWithFlag, loop_command); + + if (IsRegistrUsed(regESI)) + processor_->AddCommand(cmPop, IntelOperand(otRegistr, cpu_address_size, regESI)); + + command = processor_->AddCommand(cmNot, IntelOperand(otRegistr, osDWord, reg3)); + jmp_command->link()->set_to_command(command); + + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr, osDWord, stack_registr_), IntelOperand(otRegistr, osDWord, reg3)); + + AddEndHandlerCommands(read_opcode, end_cryptor); + opcode_list_.Add(cmCrc, otNone, cpu_address_size, 0, opcode_entry, NULL, end_cryptor); + } + } + + if (ctx.options.flags & cpMemoryProtection) { + for (i = 0; i < opcode_list_.count(); i++) { + IntelOpcodeInfo *opcode = opcode_list_.item(i); + if (opcode->command_type() == cmCpuid || opcode->command_type() == cmRdtsc || opcode->command_type() == cmCrc || opcode->command_type() == cmSyscall) { + for (j = processor_->IndexOf(opcode->entry()); j < processor_->count(); j++) { + command = processor_->item(j); + bool need_crc = true; + if ((ctx.options.flags & cpStripFixups) == 0) { + for (c = 0; c < 3; c++) { + IntelOperand operand = command->operand(c); + if (operand.type == otNone) + break; + + if ((operand.type & otValue) && operand.fixup) { + need_crc = false; + break; + } + } + } + + if (need_crc) + command->include_option(roNeedCRC); + if (command->type() == cmJmp || command->type() == cmRet || command->type() == cmIret) + break; + } + } + } + } + + // lock + for (i = 0; i < 7; i++) { + switch (i) { + case 0: + command_type = cmAdd; + break; + case 1: + command_type = cmSub; + break; + case 2: + command_type = cmAnd; + break; + case 3: + command_type = cmXor; + break; + case 4: + command_type = cmOr; + break; + case 5: + command_type = cmXchg; + break; + case 6: + command_type = cmXadd; + break; + } + for (s = osByte; s <= cpu_address_size; s++) { + size = static_cast(s); + mov_size = (size == osByte) ? osWord : size; + for (seg = segES; seg <= segGS; seg++) { + if (!visible_opcode_list.GetOpcodeInfo(command_type, otMemory, size, seg)) + continue; + + IntelRegistrList registr_list = free_registr_list_; + reg1 = registr_list.GetRandom(size == osByte && cpu_address_size == osDWord); + reg2 = registr_list.GetRandom(size == osByte && cpu_address_size == osDWord); + if (ctx.options.flags & cpEncryptBytecode) { + if (type_ == vtAdvanced) { + end_cryptor = new OpcodeCryptor(); + cryptor_list_.push_back(end_cryptor); + end_cryptor->Init(osDWord); + } + } + + opcode_entry = processor_->AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size, reg1), IntelOperand(otMemory | otRegistr, cpu_address_size, stack_registr_)); + processor_->AddCommand(cmMov, IntelOperand(otRegistr, size, reg2), IntelOperand(otMemory | otRegistr | otValue, size, stack_registr_, OperandSizeToValue(cpu_address_size))); + operand_size = OperandSizeToValue(cpu_address_size) + OperandSizeToValue(mov_size); + result_size = (command_type == cmXchg) ? 0 : OperandSizeToValue(cpu_address_size); + if (command_type == cmXchg || command_type == cmXadd) + result_size += OperandSizeToValue(mov_size); + if (result_size > operand_size) + processor_->AddCommand(cmSub, IntelOperand(otRegistr, cpu_address_size, stack_registr_), IntelOperand(otValue, cpu_address_size, 0, result_size - operand_size)); + else if (result_size < operand_size) + processor_->AddCommand(cmAdd, IntelOperand(otRegistr, cpu_address_size, stack_registr_), IntelOperand(otValue, cpu_address_size, 0, operand_size - result_size)); + command = processor_->AddCommand(command_type, IntelOperand(otMemory | otRegistr, size, reg1), IntelOperand(otRegistr, size, reg2)); + command->include_option(roLockPrefix); + if (seg != segDS) + command->set_base_segment(static_cast(seg)); + if (command_type == cmXchg) + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr, mov_size, stack_registr_), IntelOperand(otRegistr, mov_size, reg2)); + else { + if (command_type == cmXadd) + processor_->AddCommand(cmMov, IntelOperand(otMemory | otRegistr | otValue, mov_size, stack_registr_, OperandSizeToValue(cpu_address_size)), IntelOperand(otRegistr, mov_size, reg2)); + processor_->AddCommand(cmPushf, IntelOperand(otNone, cpu_address_size)); + processor_->AddCommand(cmPop, IntelOperand(otMemory | otRegistr, cpu_address_size, stack_registr_)); + } + AddEndHandlerCommands((result_size > operand_size) ? check_stack : read_opcode, end_cryptor); + opcode_list_.Add(command_type, otMemory, size, seg, opcode_entry, NULL, end_cryptor); + } + } + } + + // randomize opcodes + if (type_ == vtAdvanced) { + c = opcode_list_.count(); + for (i = 0; i < c; i++) { + opcode = opcode_list_.item(i); + if (opcode->command_type() == cmNop || opcode->command_type() == cmJmp || opcode->command_type() == cmCrc) + continue; + + for (j = 0; j < 10; j++) { + opcode_list_.Add(opcode->command_type(), opcode->operand_type(), opcode->size(), opcode->value(), CloneHandler(opcode->entry()), opcode->value_cryptor(), opcode->end_cryptor()); + } + } + } + else { + c = opcode_list_.count(); + for (i = 0; i < opcode_list_.count(); i++) { + opcode_list_.SwapObjects(i, rand() % c); + } + for (i = opcode_list_.count(); i < 0x100; i++) { + opcode = opcode_list_.item(rand() % i); + opcode_list_.Add(opcode->command_type(), opcode->operand_type(), opcode->size(), opcode->value(), (opcode->command_type() == cmJmp) ? opcode->entry() : CloneHandler(opcode->entry()), opcode->value_cryptor(), opcode->end_cryptor()); + } + + // CASEs + c = processor_->count(); + command_type = (cpu_address_size == osDWord) ? cmDD : cmDQ; + for (i = 0; i < opcode_list_.count(); i++) { + IntelOpcodeInfo *opcode = opcode_list_.item(i); + opcode->set_opcode(static_cast(i)); + command = processor_->AddCommand(command_type, IntelOperand(otValue, cpu_address_size, 0, 0, NEED_FIXUP)); + CommandLink *link = command->AddLink(0, ltCase, opcode->entry()); + link->set_parent_command(switch_entry); + } + command = processor_->item(c); + command->set_alignment(OperandSizeToValue(cpu_address_size)); + switch_entry->link()->set_to_command(command); + } +} + +IntelOpcodeInfo *IntelVirtualMachine::GetOpcode(IntelCommandType command_type, OperandType operand_type, OperandSize size, uint8_t value) +{ + IntelOpcodeInfo *res = NULL; + uint64_t key = IntelOpcodeInfo::Key(command_type, operand_type, size, value); + auto it = opcode_stack_.find(key); + if (it != opcode_stack_.end()) + res = it->second.Next(); + return res; +} + +static void EncryptBuffer(uint32_t *buffer, uint64_t key) +{ + uint32_t key0 = static_cast(key >> 32); + uint32_t key1 = static_cast(key); + buffer[0] = _rotr32(buffer[0] - key0, 7) ^ key1; + buffer[1] = _rotr32(buffer[1] - key0, 11) ^ key1; + buffer[2] = _rotr32(buffer[2] - key0, 17) ^ key1; + buffer[3] = _rotr32(buffer[3] - key0, 23) ^ key1; +} + +void IntelVirtualMachine::CompileCommand(IntelVMCommand &vm_command) +{ + IntelCommandType command_type = vm_command.command_type(); + OperandType operand_type = vm_command.operand_type(); + uint8_t registr = vm_command.registr(); + OperandSize size = vm_command.size(); + uint64_t value = vm_command.value(); + CommandBlock *block = vm_command.owner()->block(); + Data dump; + bool backward_direction = (vm_command.owner()->section_options() & rtBackwardDirection) != 0; + IntelOpcodeInfo *opcode = NULL; + + switch (command_type) { + case cmPush: + switch (operand_type) { + case otRegistr: + if (registr == regESP && (size == osWord || size == osDWord || size == osQWord)) { + opcode = GetOpcode(cmPush, otRegistr, size, 0xFF); + } else { + opcode = GetOpcode(cmPush, otRegistr, size, 0); + dump.PushByte(block->GetRegistr(size, registr, false)); + } + break; + case otHiPartRegistr: + opcode = GetOpcode(cmPush, otRegistr, size, 0); + dump.PushByte((uint8_t)(block->GetRegistr(size, registr, false) + OperandSizeToValue(size))); + break; + case otMemory: + opcode = GetOpcode(cmPush, otMemory, size, vm_command.base_segment()); + break; + case otSegmentRegistr: + opcode = GetOpcode(cmPush, otSegmentRegistr, size, registr); + break; + case otDebugRegistr: + opcode = GetOpcode(cmPush, otDebugRegistr, size, registr); + break; + case otControlRegistr: + opcode = GetOpcode(cmPush, otControlRegistr, size, registr); + break; + case otValue: + opcode = GetOpcode(cmPush, otValue, size, 0); + + uint64_t new_value; + if (vm_command.crypt_command() == cmXadd) { + uint32_t crypted_value[4]; + size_t i; + for (i = 0; i < _countof(crypted_value); i++) { + crypted_value[i] = rand32(); + } + switch (vm_command.crypt_size()) { + case osDWord: + crypted_value[3] = static_cast(value); + break; + case osQWord: + *reinterpret_cast(&crypted_value[2]) = value; + break; + } + uint32_t dw = 0; + for (i = 1; i < 4; i++) { + dw += crypted_value[i]; + } + crypted_value[0] = 0 - dw; + EncryptBuffer(crypted_value, vm_command.crypt_key()); + IntelVMCommand *link_command = vm_command.link_command(); + for (i = 3; i > 0; i--) { + link_command->set_value(crypted_value[i - 1]); + link_command->Compile(); + link_command = link_command->link_command(); + } + new_value = crypted_value[3]; + } else { + new_value = value; + } + + new_value -= vm_command.sub_value(); + + switch (size) { + case osByte: + dump.PushByte(static_cast(new_value)); + break; + case osWord: + dump.PushWord(backward_direction ? __builtin_bswap16(static_cast(new_value)) : static_cast(new_value)); + break; + case osDWord: + dump.PushDWord(backward_direction ? __builtin_bswap32(static_cast(new_value)) : static_cast(new_value)); + break; + case osQWord: + dump.PushQWord(backward_direction ? __builtin_bswap64(new_value) : new_value); + break; + } + break; + } + break; + + case cmPop: + switch (operand_type) { + case otRegistr: + if (registr == regESP && (size == osWord || size == osDWord || size == osQWord)) { + opcode = GetOpcode(cmPop, otRegistr, size, 0xFF); + } else { + opcode = GetOpcode(cmPop, otRegistr, size, 0); + dump.PushByte(block->GetRegistr(size, registr, true)); + } + break; + case otHiPartRegistr: + opcode = GetOpcode(cmPop, otRegistr, size, 0); + dump.PushByte((uint8_t)(block->GetRegistr(size, registr, true) + OperandSizeToValue(size))); + break; + case otMemory: + opcode = GetOpcode(cmPop, otMemory, size, vm_command.base_segment()); + break; + case otSegmentRegistr: + opcode = GetOpcode(cmPop, otSegmentRegistr, size, registr); + break; + case otDebugRegistr: + opcode = GetOpcode(cmPop, otDebugRegistr, size, registr); + break; + case otControlRegistr: + opcode = GetOpcode(cmPop, otControlRegistr, size, registr); + break; + } + break; + + case cmCall: + opcode = GetOpcode(cmCall, otNone, size, 0); + dump.PushByte(vm_command.subtype()); + break; + + case cmSyscall: + opcode = GetOpcode(cmSyscall, otNone, size, 0); + dump.PushByte(vm_command.subtype()); + break; + + case cmJmp: + if (vm_command.subtype()) + opcode = GetOpcode(command_type, otNone, size, vm_command.subtype()); + else + opcode = GetOpcode(command_type, otNone, size, (vm_command.value() == 0) ? id() : static_cast(vm_command.value())); + break; + + case cmAdd: case cmSub: case cmXor: case cmOr: case cmXchg: case cmAnd: case cmXadd: + if (vm_command.operand_type() == otMemory) + opcode = GetOpcode(command_type, otMemory, size, vm_command.base_segment()); + else + opcode = GetOpcode(command_type, otNone, size, vm_command.subtype()); + break; + + case cmNor: case cmNand: case cmCrc: case cmShld: case cmShrd: case cmShl: case cmShr: case cmDiv: + case cmIdiv: case cmMul: case cmImul: case cmRcl: case cmRcr: + case cmPopf: case cmIret: case cmRet: + case cmFadd: case cmFsub: case cmFisub: case cmFsubr: case cmFdiv: case cmFmul: case cmFcomp: + case cmFstp: case cmFst: case cmFild: case cmFld: case cmFstcw: case cmFldcw: case cmFistp: case cmFist: + case cmWait: case cmFstsw: case cmFchs: case cmFsqrt: case cmRdtsc: case cmCpuid: + case cmF2xm1: case cmFabs: case cmFclex: case cmFcos: case cmFdecstp: case cmFincstp: + case cmFinit: case cmFldln2: case cmFldlg2: case cmFprem: case cmFprem1: case cmFptan: + case cmFrndint: case cmFsin: case cmFtst: case cmFyl2x: case cmFpatan: case cmFldz: case cmFld1: case cmFldpi: + opcode = GetOpcode(command_type, otNone, size, vm_command.subtype()); + break; + + case cmDD: + dump.PushDWord(static_cast(value)); + break; + + case cmDQ: + dump.PushQWord(value); + break; + + default: + opcode = NULL; + break; + } + + if (opcode) { + vm_command.set_opcode(opcode); + if (type() == vtAdvanced) { + size_t i = vm_command.owner()->IndexOf(&vm_command); + bool need_begin_offset; + if (i == 0) { + need_begin_offset = (vm_command.owner()->section_options() & (rtLinkedToInt | rtLinkedToExt)) != 0; + } else { + IntelVMCommand *prev_command = reinterpret_cast(vm_command.owner()->item(i - 1)); + need_begin_offset = prev_command->is_end() || (prev_command->options() & voInitOffset); + } + + if (need_begin_offset) { + vm_command.include_option(voBeginOffset); + uint32_t value = 0; + dump.InsertBuff(0, &value, sizeof(value)); + } + + if (!vm_command.is_end()) { + vm_command.include_option(voEndOffset); + dump.PushDWord(0); + } + } else { + dump.InsertByte(0, opcode->opcode()); + } + } else if (!vm_command.is_data()) { + throw std::runtime_error("Runtime error at CompileToVM: " + std::string(intel_command_name[command_type])); + } + + vm_command.set_dump(dump); +} + +std::vector IntelVirtualMachine::GetOpcodeCryptorList(IntelVMCommand *command) +{ + std::vector res; + if (type_ == vtAdvanced) { + if (command->options() & voBeginOffset) + res.push_back(command_cryptor_); + } + else { + res.push_back(command_cryptor_); + } + if (command->opcode()->value_cryptor()) + res.push_back(command->opcode()->value_cryptor()); + if (command->opcode()->end_cryptor()) + res.push_back(command->opcode()->end_cryptor()); + return res; +} + +void IntelVirtualMachine::CompileBlock(CommandBlock &block, bool need_encrypt) +{ + size_t i, j, k, d, c; + IntelFunction *func = reinterpret_cast(block.function()); + if (type() == vtAdvanced) { + IntelVMCommand *prev_command = NULL; + IntelOpcodeInfo *nop_opcode = GetOpcode(cmNop, otNone, processor_->cpu_address_size(), 0); + if (nop_opcode == NULL) + throw std::runtime_error("Runtime error at CompileBlock/nop_opcode"); + + for (i = block.start_index(); i <= block.end_index(); i++) { + IntelCommand *command = func->item(i); + for (j = 0; j < command->count(); j++) { + IntelVMCommand *vm_command = command->item(j); + if (vm_command->is_data()) + continue; + + if (prev_command && (prev_command->options() & voEndOffset)) { + IntelOpcodeInfo *opcode = (prev_command->options() & voInitOffset) ? nop_opcode : vm_command->opcode(); + prev_command->set_dump_value(osDWord, prev_command->dump_size() - 4, static_cast(opcode->entry()->address() - prev_command->opcode()->entry()->address())); + } + if (vm_command->options() & voBeginOffset) + vm_command->set_dump_value(osDWord, 0, static_cast(vm_command->opcode()->entry()->address() - nop_opcode->entry()->address())); + prev_command = vm_command; + } + } + } + + if (!need_encrypt) + return; + + struct CRC { + uint64_t Value; + CRC() + : Value(0) + { + + } + uint64_t GetValue(OperandSize size) const + { + uint64_t res = 0; + memcpy(&res, &Value, OperandSizeToValue(size)); + return res; + } + void SetValue(OperandSize size, uint64_t value) + { + memcpy(&Value, &value, OperandSizeToValue(size)); + } + }; + + CRC crc, crc2; + OperandSize os; + OpcodeCryptor *cryptor; + std::vector cryptor_list; + std::vector correct_command_list = block.correct_command_list(); + for (i = 0; i < correct_command_list.size(); i++) { + IntelVMCommand *vm_command = reinterpret_cast(correct_command_list[i]); + IntelCommand *command = reinterpret_cast(vm_command->owner()); + IntelVMCommand *ext_vm_entry = command->ext_vm_entry(); + bool use_ext_entry = ext_vm_entry && command->IndexOf(vm_command) < command->IndexOf(ext_vm_entry); + + size_t n = func->IndexOf(command) + 1; + for (size_t r = n; r > block.start_index(); r--) { + IntelCommand *cur_command = func->item(r - 1); + if ((cur_command->section_options() & rtBeginSection) == 0) + continue; + + crc.Value = cur_command->vm_address(); + crc2.Value = use_ext_entry ? command->ext_vm_address() : func->item(n)->vm_address(); + + for (j = r - 1; j < n ; j++) { + IntelCommand *tmp_command = func->item(j); + for (k = 0; k < tmp_command->count(); k++) { + IntelVMCommand *cur_vm_command = tmp_command->item(k); + + cryptor_list = GetOpcodeCryptorList(cur_vm_command); + d = 0; + for (c = 0; c < cryptor_list.size(); c++) { + cryptor = cryptor_list[c]; + os = cryptor->size(); + crc.SetValue(os, cryptor->EncryptOpcode(crc.GetValue(os), cur_vm_command->dump_value(os, d))); + d += OperandSizeToValue(os); + } + + if (vm_command == cur_vm_command) + break; + } + } + + size_t e = use_ext_entry ? command->IndexOf(ext_vm_entry) : command->count(); + + for (k = e; k > 0; k--) { + IntelVMCommand *cur_vm_command = command->item(k - 1); + if (vm_command == cur_vm_command) + break; + + cryptor_list = GetOpcodeCryptorList(cur_vm_command); + d = cur_vm_command->dump_size(); + for (c = cryptor_list.size(); c > 0; c--) { + cryptor = cryptor_list[c - 1]; + os = cryptor->size(); + crc2.SetValue(os, cryptor->DecryptOpcode(crc2.GetValue(os), cur_vm_command->dump_value(os, d - OperandSizeToValue(os)))); + d -= OperandSizeToValue(os); + } + } + + break; + } + + if (type() == vtAdvanced) { + j = (vm_command->options() & voBeginOffset) ? 4 : 0; + } else { + j = 1; + } + cryptor = vm_command->opcode()->value_cryptor(); + vm_command->set_dump_value(vm_command->size(), j, cryptor->EncryptOpcode(cryptor->DecryptOpcode(vm_command->dump_value(vm_command->size(), j), crc.Value), crc2.Value)); + } + + for (i = block.start_index(); i <= block.end_index(); i++) { + IntelCommand *command = func->item(i); + uint64_t address = command->vm_address(); + if (command->section_options() & rtBeginSection) + crc.Value = command->vm_address(); + for (j = 0; j < command->count(); j++) { + IntelVMCommand *vm_command = command->item(j); + if (vm_command->is_data()) + continue; + + cryptor_list = GetOpcodeCryptorList(vm_command); + d = 0; + for (c = 0; c < cryptor_list.size(); c++) { + cryptor = cryptor_list[c]; + os = cryptor->size(); + uint64_t old_value = vm_command->dump_value(os, d); + vm_command->set_dump_value(os, d, cryptor->DecryptOpcode(cryptor->Decrypt(old_value), crc.Value)); + crc.SetValue(os, cryptor->EncryptOpcode(crc.Value, old_value)); + d += OperandSizeToValue(os); + } + + if (vm_command->is_end()) { + if (command->section_options() & rtBackwardDirection) { + crc.Value = address - vm_command->dump_size(); + } else { + crc.Value = address + vm_command->dump_size(); + } + } + + if (command->section_options() & rtBackwardDirection) { + address -= vm_command->dump_size(); + } else { + address += vm_command->dump_size(); + } + } + } +} + +void IntelVirtualMachine::AddExtJmpCommand(uint8_t id) +{ + IntelOpcodeInfo *opcode = GetOpcode(cmJmp, otNone, processor_->cpu_address_size(), id); + if (!opcode) + throw std::runtime_error("Runtime error at AddExtJmpCommand"); + if (type_ == vtAdvanced) { + ext_jmp_command_ = new IntelCommand(NULL, processor_->cpu_address_size()); + ext_jmp_command_->set_address(opcode->entry()->address()); + } + IntelOpcodeInfo *ext_jmp_opcode = opcode_list_.Add(cmJmp, otNone, processor_->cpu_address_size(), 0xff, (type() == vtAdvanced) ? ext_jmp_command_ : opcode->entry()); + ext_jmp_opcode->set_opcode(opcode->opcode()); + opcode_stack_[ext_jmp_opcode->Key()].push_back(ext_jmp_opcode); +} + +/** + * IntelVirtualMachineList + */ + +IntelVirtualMachineList::IntelVirtualMachineList() + : IVirtualMachineList() +{ + crc_manager_ = new MemoryManager(NULL); +} + +IntelVirtualMachineList::~IntelVirtualMachineList() +{ + delete crc_manager_; +} + +IntelVirtualMachineList *IntelVirtualMachineList::Clone() const +{ + IntelVirtualMachineList *list = new IntelVirtualMachineList(); + return list; +} + +void IntelVirtualMachineList::Prepare(const CompileContext &ctx) +{ + size_t i; + IntelOpcodeList visible_opcode_list; + OperandSize cpu_address_size = ctx.file->cpu_address_size(); + + VirtualMachineType type = +#ifdef DEMO + true +#else + ((ctx.options.flags & cpUnregisteredVersion) != 0 || ((ctx.options.vm_flags & 1) != 0)) +#endif + ? vtClassic : vtAdvanced; + + if (ctx.runtime) { + visible_opcode_list.Add(cmCall, otNone, cpu_address_size, 0); + visible_opcode_list.Add(cmCpuid, otNone, cpu_address_size, 0); + visible_opcode_list.Add(cmCrc, otNone, cpu_address_size, 0); + } + + if (ctx.options.flags & cpMemoryProtection) { + visible_opcode_list.Add(cmRdtsc, otNone, cpu_address_size, 0); + visible_opcode_list.Add(cmDiv, otNone, osDWord, true); + visible_opcode_list.Add(cmMul, otNone, osDWord, true); + } + + IntelCommandInfoList command_info_list(cpu_address_size); + + size_t n = ctx.runtime ? 2 : 1; + for (size_t k = 0; k < n; k++) { + IntelFunctionList *function_list = (k == 0) ? reinterpret_cast(ctx.file->function_list()) : reinterpret_cast(ctx.runtime->function_list()); + + for (size_t i = 0; i < function_list->count(); i++) { + IntelFunction *func = function_list->item(i); + + if (func->compilation_type() == ctMutation || (k == 1 && func->tag() != ftLoader)) + continue; + + if (func->compilation_options() & coLockToKey) + visible_opcode_list.Add(cmCall, otNone, cpu_address_size, 0); + + for (size_t j = 0; j < func->count(); j++) { + IntelCommand *command = func->item(j); + if (command->link() && command->link()->type() == ltNative) + continue; + + if ((command->options() & roLockPrefix) && command->type() != cmXchg) { + if (type == vtAdvanced) { //-V547 + bool native_found = true; + switch (command->type()) { + case cmAdd: case cmSub: case cmAnd: case cmOr: case cmXor: case cmXadd: + if (command->operand(0).type & otMemory) + native_found = false; + break; + } + if (!native_found) { + command->include_option(roNoNative); + size_t n = (command->operand(0).type & otMemory) ? 0 : 1; + visible_opcode_list.Add(static_cast(command->type()), otMemory, command->operand(0).size, command->operand(n).effective_base_segment(command->base_segment())); + } + } + continue; + } + else + switch (command->type()) { + case cmWait: case cmFchs: case cmFsqrt: case cmF2xm1: + case cmFabs: case cmFclex: case cmFcos: case cmFdecstp: + case cmFincstp: case cmFinit: case cmFldln2: case cmFldz: + case cmFld1: case cmFldpi: case cmFpatan: case cmFprem: + case cmFprem1: case cmFptan: case cmFrndint: case cmFsin: + case cmFtst: case cmFyl2x: case cmFldlg2: + case cmRdtsc: case cmPopf: case cmIret: + visible_opcode_list.Add(static_cast(command->type()), otNone, cpu_address_size, 0); + break; + + case cmFild: case cmFld: case cmFadd: case cmFsub: case cmFsubr: + case cmFstp: case cmFst: case cmFdiv: case cmFmul: case cmFcomp: + case cmFistp: case cmFist: case cmFisub: + case cmFstsw: case cmFldcw: case cmFstcw: + visible_opcode_list.Add(static_cast(command->type()), otNone, command->operand(0).size, 0); + break; + + case cmDiv: case cmIdiv: case cmMul: case cmImul: case cmRcl: case cmRcr: + visible_opcode_list.Add(static_cast(command->type()), otNone, command->operand(0).size, true); + break; + + case cmRet: + if (command->options() & roFar) + visible_opcode_list.Add(static_cast(command->type()), otNone, cpu_address_size, 1); + break; + + case cmCpuid: + if (k == 1) + visible_opcode_list.Add(static_cast(command->type()), otNone, cpu_address_size, 0); + break; + + case cmSyscall: + if (k == 1) + visible_opcode_list.Add(static_cast(command->type()), otNone, cpu_address_size, 0); + break; + + case cmXchg: + if (((command->operand(0).type | command->operand(1).type) & otMemory) && type == vtAdvanced) { + command->include_option(roNoNative); + size_t n = (command->operand(0).type & otMemory) ? 0 : 1; + visible_opcode_list.Add(static_cast(command->type()), otMemory, command->operand(0).size, command->operand(n).effective_base_segment(command->base_segment())); + } + break; + } + + if (command->GetCommandInfo(command_info_list)) { + for (size_t n = 0; n < command_info_list.count(); n++) { + CommandInfo *command_info = command_info_list.item(n); + IntelCommandType command_type = (command_info->type() == atRead) ? cmPush : cmPop; + + switch (command_info->operand_type()) { + case otSegmentRegistr: + visible_opcode_list.Add(command_type, command_info->operand_type(), osWord, command_info->value()); + break; + case otControlRegistr: + case otDebugRegistr: + visible_opcode_list.Add(command_type, command_info->operand_type(), cpu_address_size, command_info->value()); + break; + case otMemory: + if (command_info->size() > cpu_address_size) { + visible_opcode_list.Add(command_type, command_info->operand_type(), cpu_address_size, command_info->value()); + if (command_info->size() == osTByte) + visible_opcode_list.Add(command_type, command_info->operand_type(), osWord, command_info->value()); + } + else { + visible_opcode_list.Add(command_type, command_info->operand_type(), command_info->size(), command_info->value()); + } + break; + } + } + } + } + } + } + + IntelFunctionList *function_list = reinterpret_cast(ctx.file->function_list()); + IntelVirtualMachineProcessor *processor = function_list->AddProcessor(cpu_address_size); + for (i = 0; i < ctx.options.vm_count; i++) { + IntelVirtualMachine *virtual_machine = new IntelVirtualMachine(this, type, (uint8_t)i + 1, processor); + AddObject(virtual_machine); + virtual_machine->Init(ctx, visible_opcode_list); + } + + std::vector processor_list = function_list->processor_list(); + for (i = 0; i < processor_list.size(); i++) { + IFunction *func = processor_list[i]; + if (func->compilation_type() != ctMutation && func->cpu_address_size() != cpu_address_size) { + IntelVirtualMachineProcessor *new_processor = function_list->AddProcessor(func->cpu_address_size()); + IntelVirtualMachine *virtual_machine = new IntelVirtualMachine(this, type, 1, new_processor); + AddObject(virtual_machine); + CompileContext new_ctx; + new_ctx.options.vm_count = 1; +#ifndef DEMO + new_ctx.options.flags = ctx.options.flags & (cpUnregisteredVersion | cpEncryptBytecode); +#endif + new_ctx.file = ctx.file; + visible_opcode_list.clear(); + visible_opcode_list.Add(cmRet, otNone, osQWord, 1); + if (ctx.options.flags & cpMemoryProtection) { + visible_opcode_list.Add(cmRdtsc, otNone, osQWord, 0); + visible_opcode_list.Add(cmDiv, otNone, osDWord, true); + visible_opcode_list.Add(cmMul, otNone, osDWord, true); + visible_opcode_list.Add(cmCrc, otNone, osQWord, 0); + } + virtual_machine->Init(new_ctx, visible_opcode_list); + break; + } + } + + for (i = 0; i < count(); i++) { + item(i)->Prepare(ctx); + } +} + +uint64_t IntelVirtualMachineList::GetCRCValue(uint64_t &crc_address, size_t size) +{ + size_t i, j; + + if (map_.empty()) { + std::set processor_list; + for (i = 0; i < count(); i++) { + IntelFunction *processor = item(i)->processor(); + if (processor_list.find(processor) != processor_list.end()) + continue; + + processor_list.insert(processor); + for (j = 0; j < processor->count(); j++) { + IntelCommand *command = processor->item(j); + if (command->options() & roNeedCRC) + map_[command->address()] = command; + } + } + } + + crc_address = crc_manager_->Alloc(size, mtReadable); + if (!crc_address) { + crc_manager_->clear(); + for (std::map::const_iterator it = map_.begin(); it != map_.end(); it++) { + ICommand *command = it->second; + crc_manager_->Add(command->address(), command->dump_size(), mtReadable); + } + crc_manager_->Pack(); + crc_address = crc_manager_->Alloc(size, mtReadable); + } + + if (crc_address) { + std::map::const_iterator it = map_.upper_bound(crc_address); + if (it != map_.begin()) + it--; + + uint64_t address = crc_address; + uint64_t value = 0; + uint8_t *ptr = reinterpret_cast(&value); + uint8_t *ptr_end = ptr + size; + while (it != map_.end()) { + ICommand *command = it->second; + if (command->address() <= address && command->next_address() > address) { + for (j = static_cast(address - command->address()); j < command->dump_size(); j++) { + *ptr = command->dump(j); + ptr++; + address++; + if (ptr == ptr_end) + return value; + } + } + it++; + } + } + + throw std::runtime_error("Runtime error at GetCRCValue"); +} + +void IntelVirtualMachineList::ClearCRCMap() +{ + map_.clear(); + crc_manager_->clear(); +} + +/** + * IntelOpcodeInfo + */ + +IntelOpcodeInfo::IntelOpcodeInfo(IntelOpcodeList *owner, IntelCommandType command_type, OperandType operand_type, OperandSize size, uint8_t value, + IntelCommand *entry, OpcodeCryptor *value_cryptor, OpcodeCryptor *end_cryptor) + : IObject(), owner_(owner), command_type_(command_type), operand_type_(operand_type), size_(size), value_(value), entry_(entry), + value_cryptor_(value_cryptor), end_cryptor_(end_cryptor), opcode_(0) +{ + +} + +IntelOpcodeInfo::~IntelOpcodeInfo() +{ + if (owner_) + owner_->RemoveObject(this); +} + +uint64_t IntelOpcodeInfo::Key() +{ + return Key(command_type(), operand_type(), size(), value_); +} + +uint64_t IntelOpcodeInfo::Key(IntelCommandType command_type, OperandType operand_type, OperandSize size, uint8_t value) +{ + union + { + uint64_t result; + struct + { + uint32_t + command_type: 10, + operand_type: 14, + value: 8; + uint32_t + size: 3, + unused: 29; + }; + } key; + + key.result = 0; + + assert(command_type < (1 << 10)); + key.command_type = command_type; + assert(operand_type < (1 << 14)); + key.operand_type = operand_type; + key.value = value; + + assert(size < (1 << 3)); + key.size = size; + + return key.result; +} + +IntelOpcodeInfo *IntelOpcodeInfo::circular_queue::Next() +{ + IntelOpcodeInfo *res = NULL; + if (size()) + res = this->operator[](position_++ % size()); + return res; +} + +/** + * IntelOpcodeInfoList + */ + +IntelOpcodeList::IntelOpcodeList() + : ObjectList() +{ + +} + +IntelOpcodeInfo *IntelOpcodeList::Add(IntelCommandType command_type, OperandType operand_type, OperandSize size, uint8_t value, IntelCommand *entry, OpcodeCryptor *value_cryptor, OpcodeCryptor *end_cryptor) +{ + if (!entry && GetOpcodeInfo(command_type, operand_type, size, value)) + return NULL; + + IntelOpcodeInfo *opcode = new IntelOpcodeInfo(this, command_type, operand_type, size, value, entry, value_cryptor, end_cryptor); + AddObject(opcode); + return opcode; +} + +IntelOpcodeInfo *IntelOpcodeList::GetOpcodeInfo(IntelCommandType command_type, OperandType operand_type, OperandSize size, uint8_t value) const +{ + for (size_t i = 0; i < count(); i++) { + IntelOpcodeInfo *opcode = item(i); + if (opcode->command_type() == command_type && opcode->operand_type() == operand_type && opcode->size() == size && opcode->value() == value) + return opcode; + } + return NULL; +} + +/** + * IntelVirtualMachineProcessor + */ + +IntelVirtualMachineProcessor::IntelVirtualMachineProcessor(IntelFunctionList *owner, OperandSize cpu_address_size) + : IntelFunction(owner, cpu_address_size) +{ + set_compilation_type(ctMutation); + set_tag(ftProcessor); +} + +bool IntelVirtualMachineProcessor::Prepare(const CompileContext &ctx) +{ + if (cpu_address_size() == ctx.file->cpu_address_size() && ctx.file->runtime_function_list()) + AddExceptionHandler(ctx); + + for (size_t i = 0; i < count(); i++) { + IntelCommand *command = item(i); + command->CompileToNative(); + } + + return IntelFunction::Prepare(ctx); +} + +void IntelVirtualMachineProcessor::AddExceptionHandler(const CompileContext &ctx) +{ + size_t c = count(); + if (c == 0) + return; + + switch (ctx.file->calling_convention()) { + case ccMSx64: + { + // RCX: ExceptionRecord + // RDX: EstablisherFrame + // R8: ContextRecord + // R9: DispatcherContext + + IntelCommand *command; + size_t i, k; + size_t context_registr_count = ((cpu_address_size() == osQWord) ? 24 : 16) + 8; + + IntelCommand *empty_unwind_command = AddCommand(cmRet); + empty_unwind_command->include_option(roCreateNewBlock); + + IntelCommand *handler_entry = AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size(), regEAX), IntelOperand(otMemory | otRegistr | otValue, cpu_address_size(), regEDX, (context_registr_count - 8 + 0) * OperandSizeToValue(cpu_address_size()))); + AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size(), regECX), IntelOperand(otMemory | otRegistr | otValue, cpu_address_size(), regEDX, (context_registr_count - 8 + 1) * OperandSizeToValue(cpu_address_size()))); + + AddCommand(cmSub, IntelOperand(otRegistr, cpu_address_size(), regECX), IntelOperand(otValue, cpu_address_size(), 0, 8)); + AddCommand(cmMov, IntelOperand(otMemory | otRegistr, cpu_address_size(), regECX), IntelOperand(otRegistr, cpu_address_size(), regEAX)); + + command = AddCommand(cmAdd, IntelOperand(otRegistr, cpu_address_size(), regEDX), IntelOperand(otValue, cpu_address_size(), 0, (context_registr_count - 8 + 6) * OperandSizeToValue(cpu_address_size()))); + command = AddCommand(cmLea, IntelOperand(otRegistr, cpu_address_size(), regEAX), IntelOperand(otMemory | otValue, cpu_address_size(), 0, 0, LARGE_VALUE)); + command->AddLink(1, ltOffset, empty_unwind_command); + IntelCommand *cmp_command = AddCommand(cmCmp, IntelOperand(otRegistr, cpu_address_size(), regECX), IntelOperand(otRegistr, cpu_address_size(), regEDX)); + IntelCommand *jmp_command = AddCommand(cmJmpWithFlag, IntelOperand(otValue, cpu_address_size())); + jmp_command->set_flags(fl_C | fl_Z); + jmp_command->AddLink(0, ltJmpWithFlag); + AddCommand(cmSub, IntelOperand(otRegistr, cpu_address_size(), regECX), IntelOperand(otValue, cpu_address_size(), 0, 8)); + AddCommand(cmMov, IntelOperand(otMemory | otRegistr, cpu_address_size(), regECX), IntelOperand(otRegistr, cpu_address_size(), regEAX)); + command = AddCommand(cmJmp, IntelOperand(otValue, cpu_address_size())); + command->AddLink(0, ltJmp, cmp_command); + + command = AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size(), regECX), IntelOperand(otMemory | otRegistr | otValue, cpu_address_size(), regR9, 0x28)); // DISPATCHER_CONTEXT.ContextRecord + jmp_command->link()->set_to_command(command); + AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size(), regEAX), IntelOperand(otMemory | otRegistr | otValue, cpu_address_size(), regECX, offsetof(CONTEXT64, Rsp))); + AddCommand(cmMov, IntelOperand(otRegistr, cpu_address_size(), regEAX), IntelOperand(otMemory | otRegistr, cpu_address_size(), regEAX)); + AddCommand(cmMov, IntelOperand(otMemory | otRegistr | otValue, cpu_address_size(), regECX, offsetof(CONTEXT64, Rip)), IntelOperand(otRegistr, cpu_address_size(), regEAX)); + + command = AddCommand(cmMov, IntelOperand(otRegistr, osDWord, regEAX), IntelOperand(otValue, osDWord, 0, ExceptionContinueSearch)); + AddCommand(cmRet); + + k = count(); + + UNWIND_CODE unwind_code; + std::vector unwind_code_list; + + unwind_code.CodeOffset = 5; + unwind_code.UnwindOp = UWOP_ALLOC_LARGE; + unwind_code.OpInfo = 0; + unwind_code_list.push_back(unwind_code); + + unwind_code.FrameOffset = (USHORT)(context_registr_count - 8 + 2); + unwind_code_list.push_back(unwind_code); + + unwind_code.CodeOffset = 4; + unwind_code.UnwindOp = UWOP_PUSH_NONVOL; + unwind_code.OpInfo = regEBP; + unwind_code_list.push_back(unwind_code); + + unwind_code.CodeOffset = 3; + unwind_code.UnwindOp = UWOP_PUSH_NONVOL; + unwind_code.OpInfo = regESI; + unwind_code_list.push_back(unwind_code); + + unwind_code.CodeOffset = 2; + unwind_code.UnwindOp = UWOP_PUSH_NONVOL; + unwind_code.OpInfo = regEDI; + unwind_code_list.push_back(unwind_code); + + unwind_code.CodeOffset = 1; + unwind_code.UnwindOp = UWOP_PUSH_NONVOL; + unwind_code.OpInfo = regEBX; + unwind_code_list.push_back(unwind_code); + + UNWIND_INFO unwind_info = UNWIND_INFO(); + unwind_info.Version = 1; + unwind_info.Flags = UNW_FLAG_EHANDLER; + unwind_info.CountOfCodes = static_cast(unwind_code_list.size()); + + union UNWIND_INFO_HELPER { + UNWIND_INFO info; + uint32_t value; + }; + + UNWIND_INFO_HELPER unwind_info_helper; + unwind_info_helper.info = unwind_info; + + // unwind data + IntelCommand *unwind_data_command = AddCommand(osDWord, unwind_info_helper.value); + unwind_data_command->include_option(roCreateNewBlock); + unwind_data_command->set_alignment(OperandSizeToValue(osDWord)); + for (i = 0; i < unwind_code_list.size(); i++) { + AddCommand(osWord, unwind_code_list[i].FrameOffset); + } + if (unwind_code_list.size() & 1) + AddCommand(osWord, 0); + + // handler + command = AddCommand(osDWord, 0); + CommandLink *link = command->AddLink(0, ltOffset, handler_entry); + link->set_sub_value(ctx.file->image_base()); + // handler data + AddCommand(osDWord, 0); + + uint64_t info_address = owner()->IndexOf(this) * 10; + FunctionInfo *info = function_info_list()->Add(info_address, info_address, btImageBase, 0, 0, unwind_info.FrameRegister, 0, unwind_data_command); + AddressRange *address_range = info->Add(0, 0, NULL, NULL, NULL); + for (i = 0; i < c; i++) { + item(i)->set_address_range(address_range); + } + + unwind_info = UNWIND_INFO(); + unwind_info.Version = 1; + unwind_info.Flags = UNW_FLAG_NHANDLER; + + unwind_info_helper.info = unwind_info; + unwind_data_command = AddCommand(osDWord, unwind_info_helper.value); + unwind_data_command->include_option(roCreateNewBlock); + unwind_data_command->set_alignment(OperandSizeToValue(osDWord)); + + info = function_info_list()->Add(info_address + 1, info_address + 1, btImageBase, 0, 0, 0, 0, unwind_data_command); + address_range = info->Add(0, 0, NULL, NULL, NULL); + empty_unwind_command->set_address_range(address_range); + + unwind_info = UNWIND_INFO(); + unwind_info.Version = 1; + unwind_info.Flags = UNW_FLAG_NHANDLER; + + unwind_info_helper.info = unwind_info; + unwind_data_command = AddCommand(osDWord, unwind_info_helper.value); + unwind_data_command->include_option(roCreateNewBlock); + unwind_data_command->set_alignment(OperandSizeToValue(osDWord)); + + info = function_info_list()->Add(info_address + 2, info_address + 2, btImageBase, 0, 0, 0, 0, unwind_data_command); + address_range = info->Add(0, 0, NULL, NULL, NULL); + for (i = IndexOf(handler_entry); i < k; i++) { + item(i)->set_address_range(address_range); + } + } + break; + } +} + +/** + * IntelVMCommand + */ + +IntelVMCommand::IntelVMCommand(IntelCommand *owner, IntelCommandType command_type, OperandType operand_type, OperandSize size, uint64_t value, uint32_t options) + : BaseVMCommand(owner), address_(0), command_type_(command_type), operand_type_(operand_type), size_(size), value_(0), registr_(0), subtype_(0), base_segment_(segDefault), options_(options), + crypt_command_(cmUnknown), crypt_size_(osDefault), crypt_key_(0), link_command_(NULL), opcode_(NULL), sub_value_(0), fixup_(NULL) +{ + switch (operand_type_) { //-V719 + case otBaseRegistr: + case otRegistr: + case otHiPartRegistr: + case otSegmentRegistr: + case otDebugRegistr: + case otControlRegistr: + registr_ = static_cast(value); + break; + case otValue: + value_ = value; + break; + case otMemory: + base_segment_ = static_cast(value); + break; + case otNone: + subtype_ = static_cast(value); + break; + } +}; + +IntelVMCommand::IntelVMCommand(IntelCommand *owner, const IntelVMCommand &src) + : BaseVMCommand(owner), address_(0), link_command_(NULL) +{ + command_type_ = src.command_type_; + operand_type_ = src.operand_type_; + size_ = src.size_; + value_ = src.value_; + registr_ = src.registr_; + subtype_ = src.subtype_; + base_segment_ = src.base_segment_; + options_ = src.options_; + crypt_command_ = src.crypt_command_; + crypt_size_ = src.crypt_size_; + crypt_key_ = src.crypt_key_; + dump_ = src.dump_; + opcode_ = src.opcode_; + sub_value_ = src.sub_value_; + fixup_ = src.fixup_; +} + +IntelVMCommand *IntelVMCommand::Clone(IntelCommand *owner) +{ + IntelVMCommand *vm_command = new IntelVMCommand(owner, *this); + return vm_command; +} + +void IntelVMCommand::WriteToFile(IArchitecture &file) +{ + if (!dump_.size()) + return; + + if (fixup_) { + if (fixup_ == NEED_FIXUP) { + ISection *segment = file.segment_list()->GetSectionByAddress(address_); + fixup_ = file.fixup_list()->AddDefault(file.cpu_address_size(), segment && (segment->memory_type() & mtExecutable) != 0); + } + fixup_->set_address(address_); + } + + if (owner()->section_options() & rtBackwardDirection) { + for (size_t i = dump_.size(); i > 0; i--) { + file.WriteByte(dump_[i - 1]); + } + } else { + file.Write(dump_.data(), dump_.size()); + } +} + +int IntelVMCommand::GetStackLevel() const +{ + int res = 0; + OperandSize cpu_address_size = reinterpret_cast(owner())->size(); + + switch (command_type_) { + case cmPush: + if (operand_type_ == otMemory) + res -= OperandSizeToStack(cpu_address_size); + res += OperandSizeToStack(size_); + break; + case cmPop: + if (operand_type_ == otMemory) + res -= OperandSizeToStack(cpu_address_size); + res -= OperandSizeToStack(size_); + break; + case cmJmp: + res -= OperandSizeToStack(size_); + break; + case cmNor: case cmNand: + res -= OperandSizeToStack(size_); + res += OperandSizeToStack(cpu_address_size); + break; + case cmShl: case cmShr: case cmRcl: case cmRcr: + res -= OperandSizeToStack(osWord); + res += OperandSizeToStack(cpu_address_size); + break; + case cmPopf: + res -= OperandSizeToStack(cpu_address_size); + break; + case cmShld: case cmShrd: + res -= OperandSizeToStack(size_); + res -= OperandSizeToStack(osWord); + res += OperandSizeToStack(cpu_address_size); + break; + case cmDiv: case cmIdiv: case cmMul: case cmImul: + if (size_ == osByte) + res -= OperandSizeToStack(size_); + res += OperandSizeToStack(cpu_address_size); + break; + case cmRdtsc: + res -= OperandSizeToStack(osDWord) * 2; + break; + case cmCpuid: + res -= OperandSizeToStack(osDWord); + res += OperandSizeToStack(osDWord) * 4; + break; + case cmCall: case cmSyscall: + res -= OperandSizeToStack(cpu_address_size) * subtype_; + break; + case cmCrc: + res -= OperandSizeToStack(cpu_address_size) * 2; + res += OperandSizeToStack(osDWord); + break; + case cmAnd: case cmSub: case cmAdd: case cmOr: case cmXor: case cmXchg: case cmXadd: + if (operand_type_ == otMemory) { + res -= OperandSizeToStack(size_); + res -= OperandSizeToStack(cpu_address_size); + if (command_type_ == cmXchg) + res += OperandSizeToStack(size_); + else { + res += OperandSizeToStack(cpu_address_size); + if (command_type_ == cmXadd) + res += OperandSizeToStack(size_); + } + } else { + res -= OperandSizeToStack(size_); + res += OperandSizeToStack(cpu_address_size); + } + break; + } + + return res; +} + +void IntelVMCommand::Compile() +{ + reinterpret_cast(owner()->block()->virtual_machine())->CompileCommand(*this); +} + +uint64_t IntelVMCommand::CorrectDumpValue(OperandSize size, uint64_t value) const +{ + if (owner()->section_options() & rtBackwardDirection) { + 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; + } + } + + return value; +} + +uint64_t IntelVMCommand::dump_value(OperandSize size, size_t pos) const +{ + if (pos + OperandSizeToValue(size) > dump_.size()) + throw std::runtime_error("Index out of bounds"); + uint64_t res = 0; + memcpy(&res, &dump_[pos], OperandSizeToValue(size)); + return CorrectDumpValue(size, res); +} + +void IntelVMCommand::set_dump_value(OperandSize size, size_t pos, uint64_t value) +{ + if (pos + OperandSizeToValue(size) > dump_.size()) + throw std::runtime_error("Index out of bounds"); + value = CorrectDumpValue(size, value); + memcpy(&dump_[pos], &value, OperandSizeToValue(size)); +} + +bool IntelVMCommand::can_merge(CommandInfoList &command_info_list) const +{ + CommandInfo *command_info; + switch (command_type_) { + case cmPush: + switch (operand_type_) { + case otRegistr: + if (registr_ != regEmpty) { + if (command_info_list.GetInfo(atWrite, otRegistr, registr_)) + return false; + + command_info = command_info_list.GetInfo(atWrite, otHiPartRegistr, registr_); + if (command_info && size_ > command_info->size()) + return false; + } + break; + + case otHiPartRegistr: + if (registr_ != regEmpty) { + command_info = command_info_list.GetInfo(atWrite, otRegistr, registr_); + if (command_info && size_ < command_info->size()) + return false; + + command_info = command_info_list.GetInfo(atWrite, otHiPartRegistr, registr_); + if (command_info && size_ == command_info->size()) + return false; + } + break; + + case otSegmentRegistr: case otControlRegistr: case otDebugRegistr: + if (command_info_list.GetInfo(atWrite, operand_type_, registr_)) + return false; + break; + + case otMemory: + if (base_segment_ == segFS || base_segment_ == segGS) + return false; + + if (command_info_list.GetInfo(atWrite, otMemory)) + return false; + + break; + } + break; + + case cmPop: + switch (operand_type_) { + case otRegistr: + if (registr_ == regESP || (registr_ & regExtended)) + return false; + if (registr_ != regEmpty) { + for (size_t i = 0; i < command_info_list.count(); i++) { + command_info = command_info_list.item(i); + if (command_info->operand_type() == otRegistr && command_info->value() == registr_) { + return false; + } else if (command_info->operand_type() == otHiPartRegistr && command_info->value() == registr_) { + if (size_ > command_info->size()) + return false; + } + } + } + break; + + case otHiPartRegistr: + if (registr_ == regESP) + return false; + if (registr_ != regEmpty) { + for (size_t i = 0; i < command_info_list.count(); i++) { + command_info = command_info_list.item(i); + if (command_info->operand_type() == otRegistr && command_info->value() == registr_) { + if (size_ < command_info->size()) + return false; + } else if (command_info->operand_type() == otHiPartRegistr && command_info->value() == registr_) { + if (size_ == command_info->size()) + return false; + } + } + } + break; + + case otSegmentRegistr: case otControlRegistr: case otDebugRegistr: + return false; + break; + + case otMemory: + if (base_segment_ == segFS || base_segment_ == segGS) + return false; + + if (command_info_list.GetInfo(otMemory)) + return false; + + break; + } + + break; + + case cmPopf: + if (command_info_list.GetInfo(atWrite, otRegistr, regEFX)) + return false; + break; + + case cmF2xm1: case cmFabs: case cmFclex: case cmFcos: case cmFdecstp: case cmFincstp: + case cmFinit: case cmFldln2: case cmFldlg2: case cmFprem: case cmFprem1: case cmFptan: + case cmFrndint: case cmFsin: case cmFtst: case cmFyl2x: case cmFpatan: case cmFldz: case cmFld1: case cmFldpi: + case cmWait: case cmFchs: case cmFsqrt: case cmFstsw: + case cmFistp: case cmFstp: case cmFst: case cmFist: case cmFadd: case cmFsub: case cmFisub: case cmFsubr: case cmFdiv: case cmFmul: case cmFcomp: + case cmFild: case cmFld: + if (command_info_list.GetInfo(otFPURegistr)) + return false; + break; + + case cmAdd: case cmSub: case cmAnd: case cmXor: case cmOr: case cmXchg: case cmXadd: + if (operand_type_ == otMemory) { + if (base_segment_ == segFS || base_segment_ == segGS) + return false; + + if (command_info_list.GetInfo(otMemory)) + return false; + } + break; + } + + return true; +} + +bool IntelVMCommand::is_end() const +{ + return (command_type_ == cmJmp || command_type_ == cmRet || command_type_ == cmIret); +} + +IntelOperand::IntelOperand(uint32_t type_, OperandSize size_, uint8_t registr_ /*= 0*/, uint64_t value_ /*= 0*/, IFixup *fixup_ /*= NULL*/) +{ + Clear(); + + if (type_ == (otMemory | otRegistr) && registr_ == regEBP) { + type_ = otMemory | otBaseRegistr |otValue; + registr_ <<= 4; + } + + type = type_; + size = size_; + registr = registr_ & 0x0f; + base_registr = (registr_ & 0xf0) >> 4; + value = value_; + if (fixup_ == LARGE_VALUE) { + is_large_value = true; + value_size = osDWord; + } else if (fixup_) { + fixup = fixup_; + value_size = (fixup == NEED_FIXUP) ? size_ : fixup->size(); + } else if ((type & (otMemory | otValue)) == (otMemory | otValue) && (type & (otRegistr | otBaseRegistr))) { + value_size = (ByteToInt64(static_cast(value)) == value) ? osByte : osDWord; + } else { + value_size = size_; + } +} \ No newline at end of file diff --git a/core/processors.cc b/core/processors.cc new file mode 100644 index 0000000..e7ace85 --- /dev/null +++ b/core/processors.cc @@ -0,0 +1,2852 @@ +#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); +} \ No newline at end of file