31494 lines
1.0 MiB
31494 lines
1.0 MiB
#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 <intrin.h>
|
|
|
|
/**
|
|
* 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<uint16_t>(operand->value >> 16), static_cast<uint16_t>(operand->value)));
|
|
break;
|
|
case osDWord:
|
|
str.append(string_format("%.4X:%.8X", static_cast<uint16_t>(operand->value >> 32), static_cast<uint32_t>(operand->value)));
|
|
break;
|
|
}
|
|
} else {
|
|
switch (operand->value_size) {
|
|
case osByte:
|
|
str.append(string_format("%.2X", static_cast<uint8_t>(value)));
|
|
break;
|
|
case osWord:
|
|
str.append(string_format("%.4X", static_cast<uint16_t>(value)));
|
|
break;
|
|
case osDWord:
|
|
str.append(string_format("%.8X", static_cast<uint32_t>(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<uint8_t>(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<uint8_t>(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<uint64_t>(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<uint16_t>(operand->value);
|
|
break;
|
|
case osDWord:
|
|
operand->value = static_cast<uint32_t>(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<uint8_t>(~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<uint8_t>(~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<int32_t>(ReadDataDWord(data, pos));
|
|
if (data.pointer_size() == osQWord)
|
|
return base + static_cast<int64_t>(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<int16_t>(ReadDataWord(data, pos));
|
|
case DW_EH_PE_udata4:
|
|
return base + ReadDataDWord(data, pos);
|
|
case DW_EH_PE_sdata4:
|
|
return base + static_cast<int32_t>(ReadDataDWord(data, pos));
|
|
case DW_EH_PE_udata8:
|
|
return base + ReadDataQWord(data, pos);
|
|
case DW_EH_PE_sdata8:
|
|
return base + static_cast<int64_t>(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<uint8_t> 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<uint32_t>(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<uint8_t>(dump_size());
|
|
if (mem_operand->value_size == osByte && !mem_operand->is_large_value) {
|
|
PushByte(static_cast<uint8_t>(mem_operand->value));
|
|
} else {
|
|
PushDWord(static_cast<uint32_t>(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<uint8_t>(dump_size());
|
|
PushWord(static_cast<uint16_t>(operand->value));
|
|
break;
|
|
|
|
case cmDD:
|
|
operand = &operand_[0];
|
|
operand->value_pos = static_cast<uint8_t>(dump_size());
|
|
PushDWord(static_cast<uint32_t>(operand->value));
|
|
break;
|
|
|
|
case cmDQ:
|
|
operand = &operand_[0];
|
|
operand->value_pos = static_cast<uint8_t>(dump_size());
|
|
PushQWord(operand->value);
|
|
break;
|
|
|
|
case cmUleb:
|
|
operand = &operand_[0];
|
|
operand->value_pos = static_cast<uint8_t>(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<uint8_t>(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<uint8_t>(dump_size());
|
|
if (options() & roFillNop) {
|
|
PushByte(0x0f);
|
|
PushDWord(static_cast<uint32_t>(operand->value));
|
|
}
|
|
else {
|
|
uint32_t value = static_cast<uint32_t>(operand->value);
|
|
if (value < 0x80) {
|
|
PushByte(static_cast<uint8_t>((value << 1) + 0));
|
|
}
|
|
else if (value < 0x80 * 0x80) {
|
|
PushByte(static_cast<uint8_t>((value << 2) + 1));
|
|
PushByte(static_cast<uint8_t>(value >> 6));
|
|
}
|
|
else if (value < 0x80 * 0x80 * 0x80) {
|
|
PushByte(static_cast<uint8_t>((value << 3) + 3));
|
|
PushByte(static_cast<uint8_t>(value >> 5));
|
|
PushByte(static_cast<uint8_t>(value >> 13));
|
|
}
|
|
else if (value < 0x80 * 0x80 * 0x80 * 0x80) {
|
|
PushByte(static_cast<uint8_t>((value << 4) + 7));
|
|
PushByte(static_cast<uint8_t>(value >> 4));
|
|
PushByte(static_cast<uint8_t>(value >> 12));
|
|
PushByte(static_cast<uint8_t>(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<uint8_t>(dump_size());
|
|
switch (operand->value_size) {
|
|
case osByte:
|
|
PushByte(static_cast<uint8_t>(operand->value));
|
|
break;
|
|
case osWord:
|
|
PushWord(static_cast<uint16_t>(operand->value));
|
|
break;
|
|
default:
|
|
PushDWord(static_cast<uint32_t>(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<uint16_t>(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<uint8_t>(dump_size());
|
|
PushDWord(static_cast<uint32_t>(operand->value));
|
|
operand1->value_pos = static_cast<uint8_t>(dump_size());
|
|
PushWord(static_cast<uint16_t>(operand1->value));
|
|
} else if (options() & roFar) {
|
|
PushByte(0xff);
|
|
PushRM(0, 0x28, ctx);
|
|
} else if (operand->type == otValue) {
|
|
PushByte(0xe9);
|
|
operand->value_pos = static_cast<uint8_t>(dump_size());
|
|
PushDWord(static_cast<uint32_t>(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<uint8_t>(dump_size());
|
|
PushDWord(static_cast<uint32_t>(operand->value));
|
|
operand1->value_pos = static_cast<uint8_t>(dump_size());
|
|
PushWord(static_cast<uint16_t>(operand1->value));
|
|
} else if (options() & roFar) {
|
|
PushByte(0xff);
|
|
PushRM(0, 0x18, ctx);
|
|
} else if (operand->type == otValue) {
|
|
PushByte(0xe8);
|
|
operand->value_pos = static_cast<uint8_t>(dump_size());
|
|
PushDWord(static_cast<uint32_t>(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<uint8_t>(dump_size());
|
|
PushDWord(static_cast<uint32_t>(operand->value - next_address() - 4));
|
|
break;
|
|
|
|
case cmLoopne:
|
|
operand = &operand_[0];
|
|
PushByte(0xe0);
|
|
operand->value_pos = static_cast<uint8_t>(dump_size());
|
|
PushByte(static_cast<uint8_t>(operand->value - next_address() - 1));
|
|
break;
|
|
|
|
case cmLoope:
|
|
operand = &operand_[0];
|
|
PushByte(0xe1);
|
|
operand->value_pos = static_cast<uint8_t>(dump_size());
|
|
PushByte(static_cast<uint8_t>(operand->value - next_address() - 1));
|
|
break;
|
|
|
|
case cmLoop:
|
|
operand = &operand_[0];
|
|
PushByte(0xe2);
|
|
operand->value_pos = static_cast<uint8_t>(dump_size());
|
|
PushByte(static_cast<uint8_t>(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<uint8_t>(dump_size());
|
|
PushByte(static_cast<uint8_t>(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<uint8_t>(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<uint8_t>(dump_size());
|
|
switch (operand1->value_size) {
|
|
case osByte:
|
|
PushByte(static_cast<uint8_t>(operand1->value));
|
|
break;
|
|
case osWord:
|
|
PushWord(static_cast<uint16_t>(operand1->value));
|
|
break;
|
|
default:
|
|
PushDWord(static_cast<uint32_t>(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<uint8_t>(dump_size());
|
|
switch (operand1->value_size) {
|
|
case osByte:
|
|
PushByte(static_cast<uint8_t>(operand1->value));
|
|
break;
|
|
case osWord:
|
|
PushWord(static_cast<uint16_t>(operand1->value));
|
|
break;
|
|
default:
|
|
PushDWord(static_cast<uint32_t>(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<uint8_t>(operand->value));
|
|
break;
|
|
case osWord:
|
|
PushWord(static_cast<uint16_t>(operand->value));
|
|
break;
|
|
default:
|
|
PushDWord(static_cast<uint32_t>(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<uint8_t>(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<uint8_t>(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<uint8_t>(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<uint8_t>(0xb0 | (i << 3)), ctx);
|
|
} else {
|
|
PushByte(0xc6 | i);
|
|
PushRM(0, 0, ctx);
|
|
}
|
|
operand1->value_pos = static_cast<uint8_t>(dump_size());
|
|
switch (operand1->value_size) {
|
|
case osByte:
|
|
PushByte(static_cast<uint8_t>(operand1->value));
|
|
break;
|
|
case osWord:
|
|
PushWord(static_cast<uint16_t>(operand1->value));
|
|
break;
|
|
case osDWord:
|
|
PushDWord(static_cast<uint32_t>(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<uint8_t>(dump_size());
|
|
if (size_ == osDWord) {
|
|
PushDWord(static_cast<uint32_t>(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<uint8_t>(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<uint8_t>(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<uint8_t>(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<uint8_t>(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<uint8_t>(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<uint8_t>(operand_[2].value));
|
|
break;
|
|
|
|
case cmPshufd:
|
|
PushBytePrefix(0x66);
|
|
PushByte(0x0f);
|
|
PushByte(0x70);
|
|
PushRegAndRM(0, 1, ctx);
|
|
PushByte(static_cast<uint8_t>(operand_[2].value));
|
|
break;
|
|
|
|
case cmPshuflw:
|
|
PushBytePrefix(0xf2);
|
|
PushByte(0x0f);
|
|
PushByte(0x70);
|
|
PushRegAndRM(0, 1, ctx);
|
|
PushByte(static_cast<uint8_t>(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<uint32_t>(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<IntelCommandType>(buffer.ReadWord());
|
|
BaseCommand::ReadFromBuffer(buffer, file);
|
|
|
|
if (r & 0x8)
|
|
preffix_command_ = static_cast<IntelCommandType>(buffer.ReadWord());
|
|
|
|
original_dump_size_ = (r & 0x10) ? buffer.ReadWord() : buffer.ReadByte();
|
|
|
|
if (r & 0x40)
|
|
base_segment_ = static_cast<IntelSegment>(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<OperandSize>(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<OperandSize>(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<OperandSize>(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<uint8_t>(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<IntelVirtualMachine *>(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<uint32_t>(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<uint32_t>(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<IntelCommand *>(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<IntelFunction*>(owner())->section_cryptor_list();
|
|
SectionCryptor *cur_section_cryptor = NULL;
|
|
IntelCommand *save_cryptor_command = NULL;
|
|
IntelCommand *parent_command = reinterpret_cast<IntelCommand*>(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<IntelCommand*>(to_command->link()->parent_command());
|
|
} else if (link()->type() == ltJmpWithFlag || link()->type() == ltJmpWithFlagNSNA || link()->type() == ltJmpWithFlagNSFS || link()->type() == ltJmpWithFlagNSNS) {
|
|
save_cryptor_command = reinterpret_cast<IntelCommand*>(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<IntelVMCommand *>(internal_link->from_command());
|
|
|
|
switch (internal_link->type()) {
|
|
case vlCRCTableAddress:
|
|
value = reinterpret_cast<IntelFunctionList *>(ctx.file->function_list())->runtime_crc_table()->entry()->address();
|
|
break;
|
|
case vlCRCTableCount:
|
|
value = reinterpret_cast<IntelFunctionList *>(ctx.file->function_list())->runtime_crc_table()->region_count();
|
|
break;
|
|
case vlCRCValue:
|
|
{
|
|
IntelVMCommand *value_command = reinterpret_cast<IntelVMCommand*>(internal_link->to_command());
|
|
uint64_t crc_value = reinterpret_cast<IntelVirtualMachineList *>(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<IntelCommand*>(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<IntelCommand *>(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<const uint32_t *>(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<IntelCommand *>(BaseFunction::GetCommandByAddress(address));
|
|
}
|
|
|
|
IntelCommand *IntelFunction::GetCommandByNearAddress(uint64_t address) const
|
|
{
|
|
return reinterpret_cast<IntelCommand *>(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<uint64_t> 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<uint32_t>(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<uint32_t>(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<uint32_t>(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<uint32_t>(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<uint32_t>(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<uint8_t>(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<size_t>(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<uint16_t> 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<uint16_t>(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<uint16_t>(command->ReadValueFromFile(file, osWord));
|
|
command->set_comment(CommentInfo(ttComment, "Outer"));
|
|
address = command->next_address();
|
|
|
|
command = Add(address);
|
|
uint16_t kind = static_cast<uint16_t>(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<uint8_t>(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<ICommand *> entry_command_list;
|
|
std::vector<ICommand *> 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<size_t> stack;
|
|
stack.insert(k);
|
|
while (!stack.empty()) {
|
|
k = *stack.begin();
|
|
|
|
for (size_t j = k; j < count(); j++) {
|
|
std::set<size_t>::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<uint64_t, IntelCommand *> 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<uint64_t, IntelCommand *>::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<uint64_t, IntelCommand *>::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<IntelCommand *>(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<uint32_t>(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<size_t> entry_stack;
|
|
std::set<IntelCommand *> end_command_list;
|
|
std::set<IntelCommand *> 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<size_t>::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<IntelCommand *>::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<uint8_t>(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<size_t>(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<size_t>(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<size_t>(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<size_t>(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<size_t>(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<size_t>(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<size_t> 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<IntelCommand *> 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<IntelCommand *>(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<ICommand *> entry_command_list;
|
|
std::vector<ICommand *> 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<ICommand *>::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<uint32_t>(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<size_t>(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<IntelFunctionList*>(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<PEArchitecture *>(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<IntelCommand *> 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<IntelCommand *> garbage_command_list;
|
|
insert_count = 0;
|
|
|
|
std::list<ICommand *> 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<OperandSize>(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<IntelCommandType>(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<IntelCommand *>(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<size_t>(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<uint8_t>(op1) >> op2;
|
|
break;
|
|
case osWord:
|
|
result = static_cast<uint16_t>(op1) >> op2;
|
|
break;
|
|
case osDWord:
|
|
result = static_cast<uint32_t>(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<int8_t>(op1) >> op2;
|
|
break;
|
|
case osWord:
|
|
result = static_cast<int16_t>(op1) >> op2;
|
|
break;
|
|
case osDWord:
|
|
result = static_cast<int32_t>(op1) >> op2;
|
|
break;
|
|
default:
|
|
result = static_cast<int64_t>(op1) >> op2;
|
|
break;
|
|
}
|
|
break;
|
|
case cmShl:
|
|
case cmSal:
|
|
op2 &= (size == osQWord) ? 0x3f : 0x1f;
|
|
if (!op2)
|
|
return;
|
|
|
|
switch (size) {
|
|
case osByte:
|
|
result = static_cast<uint8_t>(op1) << op2;
|
|
break;
|
|
case osWord:
|
|
result = static_cast<uint16_t>(op1) << op2;
|
|
break;
|
|
case osDWord:
|
|
result = static_cast<uint32_t>(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<uint8_t>(op1), static_cast<uint8_t>(op2));
|
|
break;
|
|
case osWord:
|
|
result = _rotl16(static_cast<uint16_t>(op1), static_cast<uint8_t>(op2));
|
|
break;
|
|
case osDWord:
|
|
result = _rotl32(static_cast<uint32_t>(op1), static_cast<uint8_t>(op2));
|
|
break;
|
|
default:
|
|
result = _rotl64(op1, static_cast<uint8_t>(op2));
|
|
break;
|
|
}
|
|
break;
|
|
case cmRor:
|
|
op2 &= (size == osQWord) ? 0x3f : 0x1f;
|
|
if (!op2)
|
|
return;
|
|
|
|
switch (size) {
|
|
case osByte:
|
|
result = _rotr8(static_cast<uint8_t>(op1), static_cast<uint8_t>(op2));
|
|
break;
|
|
case osWord:
|
|
result = _rotr16(static_cast<uint16_t>(op1), static_cast<uint8_t>(op2));
|
|
break;
|
|
case osDWord:
|
|
result = _rotr32(static_cast<uint32_t>(op1), static_cast<uint8_t>(op2));
|
|
break;
|
|
default:
|
|
result = _rotr64(op1, static_cast<uint8_t>(op2));
|
|
break;
|
|
}
|
|
break;
|
|
case cmMov:
|
|
case cmLea:
|
|
case cmMovsx:
|
|
case cmMovsxd:
|
|
case cmMovzx:
|
|
result = op2;
|
|
break;
|
|
case cmCbw:
|
|
result = static_cast<int64_t>(static_cast<int8_t>(op2));
|
|
break;
|
|
case cmCwde:
|
|
result = static_cast<int64_t>(static_cast<int16_t>(op2));
|
|
break;
|
|
case cmCdqe:
|
|
result = static_cast<int64_t>(static_cast<int32_t>(op2));
|
|
break;
|
|
case cmCwd:
|
|
result = (static_cast<int16_t>(op2) < 0) ? (uint64_t)-1 : 0;
|
|
break;
|
|
case cmCdq:
|
|
result = (static_cast<int32_t>(op2) < 0) ? (uint64_t)-1 : 0;
|
|
break;
|
|
case cmCqo:
|
|
result = (static_cast<int64_t>(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<uint32_t>(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<uint16_t> 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<uint8_t>(op1) >> (op2 - 1);
|
|
break;
|
|
case osWord:
|
|
tmp = static_cast<uint16_t>(op1) >> (op2 - 1);
|
|
break;
|
|
case osDWord:
|
|
tmp = static_cast<uint32_t>(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<int8_t>(op1) >> (op2 - 1);
|
|
break;
|
|
case osWord:
|
|
tmp = static_cast<int16_t>(op1) >> (op2 - 1);
|
|
break;
|
|
case osDWord:
|
|
tmp = static_cast<int32_t>(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<uint8_t>(op1) << (op2 - 1);
|
|
break;
|
|
case osWord:
|
|
tmp = static_cast<uint16_t>(op1) << (op2 - 1);
|
|
break;
|
|
case osDWord:
|
|
tmp = static_cast<uint32_t>(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>()
|
|
{
|
|
|
|
}
|
|
|
|
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<IntelStackValue *> 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<IntelRegistrValue *>(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<uint32_t>(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<uint8_t>(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<IntelCommandType>(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<uint8_t>(operand->value)) == operand->value) {
|
|
operand->value_size = osByte;
|
|
need_update = true;
|
|
}
|
|
}
|
|
}
|
|
if (need_update)
|
|
command->Init(static_cast<IntelCommandType>(command->type()), new_operand[0], new_operand[1], new_operand[2]);
|
|
|
|
command->CompileToNative();
|
|
if (command->link() && !command->link()->to_command()) {
|
|
std::map<IntelCommand *, size_t>::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<IntelStackValue *>(-1)
|
|
|
|
void IntelObfuscation::AddRandomCommands()
|
|
{
|
|
size_t i, j, c;
|
|
IntelCommand *new_command, *last_command;
|
|
std::vector<IntelCommandType> 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<size_t>(ret_item->value())];
|
|
j = static_cast<size_t>(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<uint32_t>(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<uint32_t>(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<uint8_t>(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<uint8_t>(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<uint8_t>(source_value);
|
|
break;
|
|
case osWord:
|
|
source_value = static_cast<uint16_t>(source_value);
|
|
break;
|
|
case osDWord:
|
|
source_value = static_cast<uint32_t>(source_value);
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
switch (second_operand.size) {
|
|
case osByte:
|
|
source_value = ByteToInt64(static_cast<uint8_t>(source_value));
|
|
break;
|
|
case osWord:
|
|
source_value = WordToInt64(static_cast<uint16_t>(source_value));
|
|
break;
|
|
case osDWord:
|
|
source_value = DWordToInt64(static_cast<uint32_t>(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<uint8_t>(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<uint32_t>(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<IntelVirtualMachine *>(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<IntelCommand *>(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<IntelCommand *>(link->to_command());
|
|
ICommand *next_command = link->next_command();
|
|
IntelCommand *parent_command = reinterpret_cast<IntelCommand *>(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<IntelCommand *>(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<uint32_t>(reinterpret_cast<IntelCommand *>(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<AddressRange *> 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<IntelCommand *>(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<IntelCommand *>(range->end_entry());
|
|
command->set_operand_value(0, range->end() - base_value);
|
|
command->CompileToNative();
|
|
}
|
|
if (range->size_entry()) {
|
|
command = reinterpret_cast<IntelCommand *>(range->size_entry());
|
|
command->set_operand_value(0, range->end() - range->begin());
|
|
if (command->type() == cmDB) {
|
|
uint32_t size = static_cast<uint32_t>(command->operand(0).value);
|
|
Data data;
|
|
if (command->comment().value == "UWOP_EPILOG") {
|
|
uint32_t offset = static_cast<uint8_t>(info->end() - range->begin());
|
|
UNWIND_CODE unwind_code;
|
|
unwind_code.FrameOffset = static_cast<uint16_t>(command->dump_value(0, osWord));
|
|
if (unwind_code.OpInfo & 1) {
|
|
unwind_code.CodeOffset = static_cast<uint8_t>(offset);
|
|
data.PushWord(unwind_code.FrameOffset);
|
|
} else {
|
|
unwind_code.CodeOffset = static_cast<uint8_t>(size);
|
|
data.PushWord(unwind_code.FrameOffset);
|
|
unwind_code.CodeOffset = static_cast<uint8_t>(offset);
|
|
unwind_code.OpInfo = static_cast<uint8_t>(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<uint8_t>(size));
|
|
}
|
|
else if (size <= 0xffff) {
|
|
data.PushByte(DW_CFA_advance_loc2);
|
|
data.PushWord(static_cast<uint16_t>(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<IntelVirtualMachine *>(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<uint16_t>(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<uint8_t>(_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<uint32_t>(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<size_t> 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<size_t>(k, 1);
|
|
break;
|
|
case regEDX:
|
|
k = std::max<size_t>(k, 2);
|
|
break;
|
|
case regR8:
|
|
k = std::max<size_t>(k, 3);
|
|
break;
|
|
case regR9:
|
|
k = std::max<size_t>(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<size_t>(k, 5);
|
|
break;
|
|
case 0x28:
|
|
k = std::max<size_t>(k, 6);
|
|
break;
|
|
case 0x30:
|
|
k = std::max<size_t>(k, 7);
|
|
break;
|
|
case 0x38:
|
|
k = std::max<size_t>(k, 8);
|
|
break;
|
|
case 0x40:
|
|
k = std::max<size_t>(k, 9);
|
|
break;
|
|
case 0x48:
|
|
k = std::max<size_t>(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<int64_t>(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<int64_t>(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<IntelCommandType>(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<SectionCryptor>(), 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<uint64_t, IImportFunction *> 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<uint64_t, IImportFunction *> 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<ELFArchitecture &>(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<size_t>(segment->physical_size());
|
|
if (compiler_function_signatures.count() && (segment->memory_type() & mtExecutable))
|
|
j += static_cast<size_t>(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<size_t>(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<CompilerFunctionType>(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<uint64_t> address_list;
|
|
address_list.insert(command->next_address());
|
|
while (!address_list.empty()) {
|
|
tmp_address = *address_list.begin();
|
|
for (;;) {
|
|
std::set<uint64_t>::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<size_t>(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<IntelCommandType>(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<uint8_t>(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<uint8_t>(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<uint64_t, IImportFunction *>::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<uint64_t>(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<size_t>(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<uint64_t, IImportFunction *>::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<size_t>(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<IntelFunction *>(BaseFunctionList::item(index));
|
|
}
|
|
|
|
IntelFunction *IntelFunctionList::GetFunctionByAddress(uint64_t address) const
|
|
{
|
|
return reinterpret_cast<IntelFunction *>(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<IntelFunction *>(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<IntelFunctionList *>(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<const uint8_t*>(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<const uint8_t*>(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<const uint8_t*>(message.c_str()), message.size() + 1)) {
|
|
std::string str = ctx.options.messages[k];
|
|
command->set_dump(reinterpret_cast<const uint8_t*>(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<PEArchitecture&>(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<IntelFunction *>(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<PEArchitecture *>(ctx.file);
|
|
if (file->image_type() == itDriver) {
|
|
IntelFunctionList *function_list = reinterpret_cast<IntelFunctionList *>(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<uint32_t>(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<APIType, IntelCommand*> 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<size_t>(compiler_function->value(2)));
|
|
ctx.manager->Add(compiler_function->value(3), static_cast<size_t>(compiler_function->value(4)));
|
|
|
|
if ((compiler_function->options() & coUsed) == 0)
|
|
continue;
|
|
|
|
address = compiler_function->address();
|
|
command = reinterpret_cast<IntelCommand *>(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<IntelCommandType>(command->type()));
|
|
|
|
APIType function_type = static_cast<APIType>(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<IntelCommand *>(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<IntelCommandType>(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<APIType, IntelCommand*>::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<PEArchitecture *>(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<PEArchitecture *>(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<PEArchitecture *>((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<IntelCommand *>(ctx.file->function_list()->GetCommandByNearAddress(address, true));
|
|
iat_command = iat_info_list_[i].command;
|
|
|
|
file = reinterpret_cast<PEArchitecture *>((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<IntelCommandType>(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<IntelFunction *>(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<IntelCommand *>(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<IntelFunctionList *>(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<uint32_t>(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<CRCInfo> crc_info_list;
|
|
std::vector<uint8_t> 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<uint8_t *>(&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<uint32_t>(region_info.address - file.image_base()), dump);
|
|
if (cryptor_) {
|
|
crc_info.pod.address = static_cast<uint32_t>(cryptor_->Encrypt(crc_info.pod.address));
|
|
crc_info.pod.size = static_cast<uint32_t>(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<IntelCommand *> 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<PEArchitecture *>(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<PEResource *> 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<uint32_t>((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<FileFolder *> 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<uint32_t>((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<IntelFunctionList *>(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<uint32_t>((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<uint8_t>(_rotl32(data_key_, static_cast<int>(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<uint32_t>(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<char> hwid;
|
|
hwid.resize(size);
|
|
VMProtectGetCurrentHWID(hwid.data(), (int)hwid.size());
|
|
|
|
std::vector<uint8_t> 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<uint32_t>(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<uint8_t> 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<uint32_t>(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<IntelFunctionList *>(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<IntelCommandType>(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<uint32_t>(operand.value))));
|
|
operand = command->operand(1);
|
|
}
|
|
|
|
uint32_t value = static_cast<uint32_t>(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<IntelCommandType>(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<uint8_t> 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<uint32_t*>(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<ICommand *> 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<IFunction *> function_list = ctx.file->function_list()->processor_list();
|
|
for (size_t k = 0; k < function_list.size(); k++) {
|
|
IntelFunction *func = reinterpret_cast<IntelFunction*>(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<IntelFunction*>(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<ICommand *>::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<IntelVirtualMachineList*>(ctx.file->virtual_machine_list());
|
|
virtual_machine_list->ClearCRCMap();
|
|
}
|
|
|
|
if (!IntelFunction::Compile(ctx))
|
|
return false;
|
|
IntelFunction::AfterCompile(ctx);
|
|
|
|
std::vector<IFunction *> function_list = ctx.file->function_list()->processor_list();
|
|
function_list.push_back(this);
|
|
std::vector<CommandBlock*> 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<CommandBlock*> *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<IntelFunctionList *>(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<uint8_t>(_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<uint16_t>(_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<ImportInfo> import_info_list;
|
|
std::vector<ImportFunctionInfo> import_function_info_list;
|
|
PEArchitecture *file, *runtime;
|
|
CommandLink *link;
|
|
IntelFunctionList *runtime_function_list;
|
|
IntelFunction *func;
|
|
std::map<uint64_t, PEImportFunction *> 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<PEArchitecture *>(ctx.file);
|
|
runtime = reinterpret_cast<PEArchitecture *>(ctx.runtime);
|
|
intel_import = reinterpret_cast<IntelFunctionList *>(file->function_list())->import();
|
|
intel_crc = reinterpret_cast<IntelFunctionList *>(file->function_list())->crc_table();
|
|
IntelLoaderData *loader_data = reinterpret_cast<IntelFunctionList*>(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<uint64_t, PEImportFunction *> import_map;
|
|
orig_dll_count = new_import_list.count();
|
|
runtime_function_list = reinterpret_cast<IntelFunctionList *>(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<uint64_t, PEImportFunction *>::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<uint32_t>((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<uint32_t>((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<IntelCommand *>(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<ImportInfo> 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<uint32_t>((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<PESegment *> 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<PackerInfo> 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<size_t>(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<uint32_t>(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<PackerInfo>::iterator it = std::find(packer_info_list.begin(), packer_info_list.end(), section);
|
|
if (it != packer_info_list.end()) {
|
|
physical_size = static_cast<uint32_t>(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<LoaderInfo> 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<IFunction *> 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<IntelFunction *>(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<uint32_t>((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<IntelFunction*>(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<size_t>(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<uint32_t, IntelCommand *> 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<uint32_t, IntelCommand *>::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<IntelCommand*> 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<uint64_t, PEImportFunction *>::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<ImportFunctionInfo>::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<uint32_t>(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<IntelCommandType>(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<IntelCommandType>(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<uint32_t, IntelCommand *>::const_iterator it = loader_string_list.find(static_cast<uint32_t>(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<uint32_t>(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<IntelCommand *>(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<IntelCommand *> 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<uint64_t>(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<size_t>(k, 1);
|
|
break;
|
|
case regEDX:
|
|
k = std::max<size_t>(k, 2);
|
|
break;
|
|
case regR8:
|
|
k = std::max<size_t>(k, 3);
|
|
break;
|
|
case regR9:
|
|
k = std::max<size_t>(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<size_t>(k, 5);
|
|
break;
|
|
case 0x28:
|
|
k = std::max<size_t>(k, 6);
|
|
break;
|
|
case 0x30:
|
|
k = std::max<size_t>(k, 7);
|
|
break;
|
|
case 0x38:
|
|
k = std::max<size_t>(k, 8);
|
|
break;
|
|
case 0x40:
|
|
k = std::max<size_t>(k, 9);
|
|
break;
|
|
case 0x48:
|
|
k = std::max<size_t>(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<IntelVirtualMachineList *>(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<IntelCommand*>(link->from_command())->include_option(roInternal);
|
|
link->from_command()->PrepareLink(ctx);
|
|
}
|
|
|
|
return BaseIntelLoader::Prepare(ctx);
|
|
}
|
|
|
|
std::vector<uint64_t> PEIntelLoader::cfg_address_list() const
|
|
{
|
|
std::vector<uint64_t> 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<MacArchitecture *>(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<IntelCommand *>(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<MacArchitecture *>(owner());
|
|
for (std::map<MacImportFunction *, IntelCommand *>::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<uint64_t, MacImportFunction *> runtime_info_list;
|
|
uint64_t loader_data_address;
|
|
MacSegment *segment;
|
|
|
|
file = reinterpret_cast<MacArchitecture *>(ctx.file);
|
|
runtime = reinterpret_cast<MacArchitecture *>(ctx.runtime);
|
|
IntelCRCTable *intel_crc = reinterpret_cast<IntelFunctionList *>(file->function_list())->crc_table();
|
|
IntelLoaderData *loader_data = reinterpret_cast<IntelFunctionList*>(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<MacSegment *> 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<uint64_t, MacImportFunction *> import_map;
|
|
MacImportList &new_import_list = *file->import_list();
|
|
orig_dll_count = new_import_list.count();
|
|
runtime_function_list = reinterpret_cast<IntelFunctionList *>(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<uint64_t, MacImportFunction *>::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<MacImport *>(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<uint32_t>((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<MacImportFunction*> 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<uint32_t>(address - import_function->address() - 5));
|
|
} else {
|
|
// dd xxxx
|
|
if (cpu_address_size() == osQWord)
|
|
jmp.PushQWord(address);
|
|
else
|
|
jmp.PushDWord(static_cast<uint32_t>(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<uint32_t>(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<uint32_t>(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<uint64_t> 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<uint32_t>(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<uint32_t>(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<uint32_t>((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<MacImportFunction *, IntelCommand *>::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<uint32_t>(end_address - address);
|
|
uint32_t physical_size = std::min(static_cast<uint32_t>(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<uint32_t>(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<MacSegment *> writable_segment_list;
|
|
std::vector<PackerInfo> 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<IntelCommand *> load_command_list;
|
|
if (!objc_segment_list.empty()) {
|
|
size_t value_size = OperandSizeToValue(file->cpu_address_size());
|
|
std::set<uint64_t> address_list;
|
|
objc.GetLoadMethodReferences(address_list);
|
|
for (std::set<uint64_t>::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<MacSegment *> 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<size_t>(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<size_t>(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<uint64_t> 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<uint64_t>::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<PackerInfo>::iterator it = std::find(packer_info_list.begin(), packer_info_list.end(), segment);
|
|
if (it != packer_info_list.end()) {
|
|
physical_size = static_cast<uint32_t>(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<size_t>(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<uint32_t>(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<LoaderInfo> 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<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<IFunction *> 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<IntelFunction *>(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<uint32_t>((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<MacImportFunction *, IntelCommand *>::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<MacFixup *, IntelCommand *>::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<IntelFunction*>(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<size_t>(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<uint32_t, IntelCommand *> 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<uint32_t, IntelCommand *>::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<IntelCommand*> 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<uint64_t, MacImportFunction *>::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<MacImportFunction *, IntelCommand *>::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<uint32_t>(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<IntelCommandType>(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<IntelCommandType>(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<uint32_t, IntelCommand *>::const_iterator it = loader_string_list.find(static_cast<uint32_t>(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<uint32_t>(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<IntelCommand *>(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<size_t>(k, 1);
|
|
break;
|
|
case regESI:
|
|
k = std::max<size_t>(k, 2);
|
|
break;
|
|
case regEDX:
|
|
k = std::max<size_t>(k, 3);
|
|
break;
|
|
case regECX:
|
|
k = std::max<size_t>(k, 4);
|
|
break;
|
|
case regR8:
|
|
k = std::max<size_t>(k, 5);
|
|
break;
|
|
case regR9:
|
|
k = std::max<size_t>(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<size_t>(k, 7);
|
|
break;
|
|
case 0x04:
|
|
k = std::max<size_t>(k, 8);
|
|
break;
|
|
case 0x08:
|
|
k = std::max<size_t>(k, 9);
|
|
break;
|
|
case 0x0c:
|
|
k = std::max<size_t>(k, 10);
|
|
break;
|
|
case 0x10:
|
|
k = std::max<size_t>(k, 11);
|
|
break;
|
|
case 0x14:
|
|
k = std::max<size_t>(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<size_t>(k, 1);
|
|
break;
|
|
case 0x04:
|
|
k = std::max<size_t>(k, 2);
|
|
break;
|
|
case 0x08:
|
|
k = std::max<size_t>(k, 3);
|
|
break;
|
|
case 0x0c:
|
|
k = std::max<size_t>(k, 4);
|
|
break;
|
|
case 0x10:
|
|
k = std::max<size_t>(k, 5);
|
|
break;
|
|
case 0x14:
|
|
k = std::max<size_t>(k, 6);
|
|
break;
|
|
case 0x18:
|
|
k = std::max<size_t>(k, 7);
|
|
break;
|
|
case 0x1c:
|
|
k = std::max<size_t>(k, 8);
|
|
break;
|
|
case 0x20:
|
|
k = std::max<size_t>(k, 9);
|
|
break;
|
|
case 0x24:
|
|
k = std::max<size_t>(k, 10);
|
|
break;
|
|
case 0x28:
|
|
k = std::max<size_t>(k, 11);
|
|
break;
|
|
case 0x2c:
|
|
k = std::max<size_t>(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<IntelCommand*>(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<IFunction *> 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<IntelFunction *>(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<IntelCommand *>(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<IntelCommandType>(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<IntelCommand *>(init_entry_->link()->to_command()) : init_entry_;
|
|
command->set_operand_value(0, entry()->address());
|
|
command->CompileToNative();
|
|
|
|
for (std::map<MacImportFunction *, IntelCommand *>::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<MacFixup *, IntelCommand *>::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<IntelCommand*> 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<ELFArchitecture &>(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<IntelFunction *>(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<uint32_t>(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<PackerInfo> 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<size_t>(segment->physical_size()));
|
|
|
|
if (segment == file->header_segment()) {
|
|
ELFSegment *interp = file->segment_list()->GetSectionByType(PT_INTERP);
|
|
size_t delta = interp ? static_cast<uint32_t>(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<PackerInfo>::iterator it = std::find(packer_info_list.begin(), packer_info_list.end(), segment);
|
|
if (it != packer_info_list.end()) {
|
|
physical_size = static_cast<uint32_t>(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<uint64_t, ELFImportFunction *> runtime_info_list;
|
|
std::map<ELFImportFunction *, IntelCommand *> import_function_info;
|
|
std::map<ELFRelocation *, IntelCommand *> iat_info;
|
|
ELFRelocation *relocation;
|
|
ELFSegment *segment;
|
|
std::map<ELFRelocation *, IntelCommand *> relocation_info;
|
|
|
|
file = reinterpret_cast<ELFArchitecture *>(ctx.file);
|
|
runtime = reinterpret_cast<ELFArchitecture *>(ctx.runtime);
|
|
intel_crc = reinterpret_cast<IntelFunctionList *>(file->function_list())->crc_table();
|
|
IntelLoaderData *loader_data = reinterpret_cast<IntelFunctionList*>(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<uint64_t, ELFImportFunction *> import_map;
|
|
ELFImportList &new_import_list = *file->import_list();
|
|
runtime_function_list = reinterpret_cast<IntelFunctionList *>(runtime->function_list());
|
|
IntelCommandType value_command_type = (cpu_address_size() == osDWord) ? cmDD : cmDQ;
|
|
index = count();
|
|
std::map<ELFRelocation *, ELFImportFunction *> 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<uint64_t, ELFImportFunction *>::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<ELFImport *>(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<uint32_t>((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<uint32_t>(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<size_t>(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<uint32_t>((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<ELFSegment *> 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<PackerInfo> 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<uint32_t>(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<size_t>(segment->physical_size()));
|
|
|
|
if (segment == file->header_segment()) {
|
|
ELFSegment *interp = file->segment_list()->GetSectionByType(PT_INTERP);
|
|
size_t delta = interp ? static_cast<uint32_t>(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<PackerInfo>::iterator it = std::find(packer_info_list.begin(), packer_info_list.end(), segment);
|
|
if (it != packer_info_list.end()) {
|
|
physical_size = static_cast<uint32_t>(it->address - segment->address());
|
|
is_packed = true;
|
|
}
|
|
if (segment->physical_offset() != physical_offset) {
|
|
size_t delta = static_cast<size_t>(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<uint32_t>(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<uint64_t>(physical_offset) & (segment->alignment() - 1)) - (segment->address() & (segment->alignment() - 1));
|
|
segment->Rebase(delta);
|
|
segment->set_size((static_cast<int64_t>(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<LoaderInfo> 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<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;
|
|
if ((ctx.options.flags & cpStripFixups) == 0) {
|
|
std::vector<IFunction *> 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<IntelFunction *>(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<uint32_t>((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<size_t>(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<size_t>(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<ELFRelocation *, IntelCommand *>::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<ELFRelocation *, IntelCommand *>::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<IntelFunction*>(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<size_t>(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<uint64_t>(segment->address(), read_only_segment->address()) < std::min<uint64_t>(segment->address() + segment->size(), read_only_segment->address() + read_only_segment->size())) {
|
|
if (!relro_entry_) {
|
|
index = count();
|
|
size_t page_offset = static_cast<size_t>(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<uint32_t, IntelCommand *> 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<uint32_t, IntelCommand *>::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<IntelCommand*> 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<uint64_t, ELFImportFunction *>::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<ELFImportFunction *, IntelCommand *>::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<uint32_t>(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<IntelCommandType>(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<IntelCommandType>(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<uint32_t, IntelCommand *>::const_iterator it = loader_string_list.find(static_cast<uint32_t>(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<uint32_t>(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<ELFRelocation *, IntelCommand *>::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<IntelCommand *>(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<IntelCommand*>(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<IntelVirtualMachine *> 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<IntelVirtualMachineList *>(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<ICommand *, ICommand *> 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<ICommand *, ICommand *>::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<uint8_t> 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<IntelCommand *> 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<IntelCommand *> 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<IntelCommand *> 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<IntelFunctionList *>(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<OperandSize>(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<OperandSize>(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<OperandSize>(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<OperandSize>(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<IntelSegment>(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<OperandSize>(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<IntelSegment>(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<OperandSize>(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<OperandSize>(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<OperandSize>(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<OperandSize>(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<OperandSize>(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<OperandSize>(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<OperandSize>(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<OperandSize>(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<OperandSize>(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<OperandSize>(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<OperandSize>(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<IntelSegment>(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<uint8_t>(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<uint32_t>(key >> 32);
|
|
uint32_t key1 = static_cast<uint32_t>(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<uint32_t>(value);
|
|
break;
|
|
case osQWord:
|
|
*reinterpret_cast<uint64_t*>(&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<uint8_t>(new_value));
|
|
break;
|
|
case osWord:
|
|
dump.PushWord(backward_direction ? __builtin_bswap16(static_cast<uint16_t>(new_value)) : static_cast<uint16_t>(new_value));
|
|
break;
|
|
case osDWord:
|
|
dump.PushDWord(backward_direction ? __builtin_bswap32(static_cast<uint32_t>(new_value)) : static_cast<uint32_t>(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<uint8_t>(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<uint32_t>(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<IntelVMCommand *>(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<OpcodeCryptor *> IntelVirtualMachine::GetOpcodeCryptorList(IntelVMCommand *command)
|
|
{
|
|
std::vector<OpcodeCryptor *> 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<IntelFunction *>(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<uint32_t>(opcode->entry()->address() - prev_command->opcode()->entry()->address()));
|
|
}
|
|
if (vm_command->options() & voBeginOffset)
|
|
vm_command->set_dump_value(osDWord, 0, static_cast<uint32_t>(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<OpcodeCryptor *> cryptor_list;
|
|
std::vector<IVMCommand *> correct_command_list = block.correct_command_list();
|
|
for (i = 0; i < correct_command_list.size(); i++) {
|
|
IntelVMCommand *vm_command = reinterpret_cast<IntelVMCommand *>(correct_command_list[i]);
|
|
IntelCommand *command = reinterpret_cast<IntelCommand *>(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<IntelFunctionList *>(ctx.file->function_list()) : reinterpret_cast<IntelFunctionList *>(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<IntelCommandType>(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<IntelCommandType>(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<IntelCommandType>(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<IntelCommandType>(command->type()), otNone, command->operand(0).size, true);
|
|
break;
|
|
|
|
case cmRet:
|
|
if (command->options() & roFar)
|
|
visible_opcode_list.Add(static_cast<IntelCommandType>(command->type()), otNone, cpu_address_size, 1);
|
|
break;
|
|
|
|
case cmCpuid:
|
|
if (k == 1)
|
|
visible_opcode_list.Add(static_cast<IntelCommandType>(command->type()), otNone, cpu_address_size, 0);
|
|
break;
|
|
|
|
case cmSyscall:
|
|
if (k == 1)
|
|
visible_opcode_list.Add(static_cast<IntelCommandType>(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<IntelCommandType>(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<IntelFunctionList *>(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<IFunction *> 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<IntelFunction *> 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<uint64_t, ICommand *>::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<uint64_t, ICommand *>::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<uint8_t *>(&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<size_t>(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>()
|
|
{
|
|
|
|
}
|
|
|
|
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> 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<uint8_t>(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<uint8_t>(value);
|
|
break;
|
|
case otValue:
|
|
value_ = value;
|
|
break;
|
|
case otMemory:
|
|
base_segment_ = static_cast<IntelSegment>(value);
|
|
break;
|
|
case otNone:
|
|
subtype_ = static_cast<uint8_t>(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<IntelCommand *>(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<IntelVirtualMachine *>(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<uint16_t>(value));
|
|
break;
|
|
case osDWord:
|
|
value = __builtin_bswap32(static_cast<uint32_t>(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<uint8_t>(value)) == value) ? osByte : osDWord;
|
|
} else {
|
|
value_size = size_;
|
|
}
|
|
} |