#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_; } }