vmprotect-3.5.1/core/il.cc

7841 lines
239 KiB
C++

#include "../runtime/common.h"
#include "../runtime/crypto.h"
#include "objects.h"
#include "osutils.h"
#include "streams.h"
#include "files.h"
#include "processors.h"
#include "lang.h"
#include "core.h"
#include "pefile.h"
#include "packer.h"
#include "dotnet.h"
#include "dotnetfile.h"
#include "il.h"
/**
* ILCommand
*/
ILCommand::ILCommand(IFunction *owner, OperandSize size, uint64_t address)
: BaseCommand(owner), address_(address), size_(size), type_(icUnknown), operand_value_(0), original_dump_size_(0),
section_options_(0), operand_pos_(0), token_reference_(NULL), ext_vm_entry_(NULL), param_(0), fixup_(NULL)
{
if (address_)
include_option(roClearOriginalCode);
}
ILCommand::ILCommand(IFunction *owner, OperandSize size, ILCommandType type, uint64_t operand_value, IFixup *fixup)
: BaseCommand(owner), address_(0), size_(size), type_(type), operand_value_(operand_value), original_dump_size_(0),
section_options_(0), operand_pos_(0), token_reference_(NULL), ext_vm_entry_(NULL), param_(0), fixup_(fixup)
{
}
ILCommand::ILCommand(IFunction *owner, OperandSize size, const std::string &value)
: BaseCommand(owner, value), address_(0), size_(size), type_(icUnknown), operand_value_(0), original_dump_size_(0),
section_options_(0), operand_pos_(0), token_reference_(NULL), ext_vm_entry_(NULL), param_(0), fixup_(NULL)
{
type_ = icData;
}
ILCommand::ILCommand(IFunction *owner, OperandSize size, const Data &value)
: BaseCommand(owner, value), address_(0), size_(size), type_(icUnknown), operand_value_(0), original_dump_size_(0),
section_options_(0), operand_pos_(0), token_reference_(NULL), ext_vm_entry_(NULL), param_(0), fixup_(NULL)
{
type_ = icData;
}
ILCommand::ILCommand(IFunction *owner, const ILCommand &src)
: BaseCommand(owner, src), section_options_(0), ext_vm_entry_(NULL), fixup_(NULL)
{
address_ = src.address_;
size_ = src.size_;
type_ = src.type_;
operand_value_ = src.operand_value_;
original_dump_size_ = src.original_dump_size_;
operand_pos_ = src.operand_pos_;
token_reference_ = src.token_reference_;
param_ = src.param_;
}
void ILCommand::Init(ILCommandType type, uint64_t operand_value, TokenReference *token_reference)
{
type_ = type;
operand_value_ = operand_value;
token_reference_ = token_reference;
}
void ILCommand::clear()
{
type_ = icUnknown;
operand_value_ = 0;
original_dump_size_ = 0;
operand_pos_ = 0;
token_reference_ = NULL;
BaseCommand::clear();
}
void ILCommand::InitUnknown()
{
clear();
type_ = icUnknown;
PushByte(0);
}
void ILCommand::InitComment(const std::string &comment)
{
type_ = icComment;
set_comment(CommentInfo(ttNone, comment));
}
ISEHandler * ILCommand::seh_handler() const
{
throw std::runtime_error("The method or operation is not implemented.");
}
void ILCommand::set_seh_handler(ISEHandler *handler)
{
throw std::runtime_error("The method or operation is not implemented.");
}
std::string ILCommand::text() const
{
std::string res;
const ILOpCode opcode = ILOpCodes[type_];
res = (type_ == icComment) ? comment_text() : opcode.name;
if (type_ == icData) {
for (size_t i = 0; i < dump_size(); i++) {
if (i > 0)
res.append(",");
res.append(string_format(" %.2X", dump(i)));
}
} else {
switch (opcode.operand_type) {
case InlineNone:
case InlinePhi:
case Inline8:
// do nothing
break;
case ShortInlineI:
case ShortInlineVar:
res.append(string_format(" %.2X", static_cast<uint8_t>(operand_value_)));
break;
case InlineVar:
res.append(string_format(" %.4X", static_cast<uint16_t>(operand_value_)));
break;
case InlineI8:
case InlineR:
res.append(string_format(" %.16llX", operand_value_));
break;
case InlineSwitch:
break;
case ShortInlineBrTarget:
case InlineBrTarget:
res.append(string_format(" %.8X", static_cast<uint32_t>(operand_value_)));
break;
default:
res.append(string_format(" %.8X", static_cast<uint32_t>(operand_value_)));
break;
}
}
return res;
}
CommentInfo ILCommand::comment()
{
CommentInfo res = BaseCommand::comment();
if (res.type != ttUnknown)
return res;
res.type = ttNone;
NETArchitecture *file = owner()->owner() ? dynamic_cast<NETArchitecture *>(owner()->owner()->owner()) : NULL;
if (file) {
switch (ILOpCodes[type_].operand_type) {
case InlineBrTarget:
case ShortInlineBrTarget:
res.value = (next_address() > operand_value_) ? char(2) : char(4);
res.type = ttJmp;
break;
case InlineType:
case InlineField:
case InlineTok:
case InlineSig:
case InlineString:
case InlineMethod:
if (ILToken *token = token_reference_ ? token_reference_->owner()->owner() : NULL) {
switch (token->type()) {
case ttTypeRef:
{
ILTypeRef *type = reinterpret_cast<ILTypeRef *>(token);
std::string name = type->full_name(true);
res.value = string_format("%c %s", 3, name.c_str());
res.type = ttImport;
}
break;
case ttTypeDef:
{
ILTypeDef *type = reinterpret_cast<ILTypeDef *>(token);
std::string name = type->full_name();
res.value = string_format("%c %s", 3, name.c_str());
res.type = ttFunction;
}
break;
case ttTypeSpec:
{
ILTypeSpec *type = reinterpret_cast<ILTypeSpec *>(token);
std::string name = type->name(true);
res.value = string_format("%c %s", 3, name.c_str());
res.type = ttFunction;
}
break;
case ttField:
{
ILField *field = reinterpret_cast<ILField *>(token);
std::string name = field->full_name(true);
res.value = string_format("%c %s", 3, name.c_str());
res.type = ttFunction;
}
break;
case ttMemberRef:
{
ILMemberRef *member = reinterpret_cast<ILMemberRef *>(token);
std::string name = member->full_name(true);
res.value = string_format("%c %s", 3, name.c_str());
res.type = (member->declaring_type() && member->declaring_type()->type() == ttTypeRef) ? ttImport : ttFunction;
}
break;
case ttStandAloneSig:
{
ILStandAloneSig *signature = reinterpret_cast<ILStandAloneSig*>(token);
std::string name = signature->name(true);
res.value = string_format("%c %s", 3, name.c_str());
res.type = ttFunction;
}
break;
case ttUserString:
{
ILUserString *str = reinterpret_cast<ILUserString*>(token);
res.value = string_format("%c \"%s\"", 3, str->name().c_str());
res.type = ttString;
}
break;
case ttMethodDef:
{
ILMethodDef *method = reinterpret_cast<ILMethodDef*>(token);
std::string name = method->full_name(true);
res.value = string_format("%c %s", 3, name.c_str());
res.type = ttFunction;
}
break;
case ttMethodSpec:
{
ILMethodSpec *method_spec = reinterpret_cast<ILMethodSpec*>(token);
std::string name = method_spec->full_name(true);
res.value = string_format("%c %s", 3, name.c_str());
res.type = (method_spec->parent() && method_spec->parent()->type() == ttMethodDef) ? ttFunction : ttImport;
}
break;
}
if (res.type == ttFunction && ILOpCodes[type_].operand_type == InlineField)
res.type = ttVariable;
}
break;
}
set_comment(res);
}
return res;
}
void ILCommand::CompileToNative()
{
if (type_ == icComment || type_ == icData)
return;
BaseCommand::clear();
switch (type_) {
case icByte: break;
case icWord: break;
case icDword: break;
case icQword: break;
case icCase: break;
case icNop: PushByte(0x00); break;
case icBreak: PushByte(0x01); break;
case icLdarg_0: PushByte(0x02); break;
case icLdarg_1: PushByte(0x03); break;
case icLdarg_2: PushByte(0x04); break;
case icLdarg_3: PushByte(0x05); break;
case icLdloc_0: PushByte(0x06); break;
case icLdloc_1: PushByte(0x07); break;
case icLdloc_2: PushByte(0x08); break;
case icLdloc_3: PushByte(0x09); break;
case icStloc_0: PushByte(0x0a); break;
case icStloc_1: PushByte(0x0b); break;
case icStloc_2: PushByte(0x0c); break;
case icStloc_3: PushByte(0x0d); break;
case icLdarg_s: PushByte(0x0e); break;
case icLdarga_s: PushByte(0x0f); break;
case icStarg_s: PushByte(0x10); break;
case icLdloc_s: PushByte(0x11); break;
case icLdloca_s: PushByte(0x12); break;
case icStloc_s: PushByte(0x13); break;
case icLdnull: PushByte(0x14); break;
case icLdc_i4_m1: PushByte(0x15); break;
case icLdc_i4_0: PushByte(0x16); break;
case icLdc_i4_1: PushByte(0x17); break;
case icLdc_i4_2: PushByte(0x18); break;
case icLdc_i4_3: PushByte(0x19); break;
case icLdc_i4_4: PushByte(0x1a); break;
case icLdc_i4_5: PushByte(0x1b); break;
case icLdc_i4_6: PushByte(0x1c); break;
case icLdc_i4_7: PushByte(0x1d); break;
case icLdc_i4_8: PushByte(0x1e); break;
case icLdc_i4_s: PushByte(0x1f); break;
case icLdc_i4: PushByte(0x20); break;
case icLdc_i8: PushByte(0x21); break;
case icLdc_r4: PushByte(0x22); break;
case icLdc_r8: PushByte(0x23); break;
case icDup: PushByte(0x25); break;
case icPop: PushByte(0x26); break;
case icJmp: PushByte(0x27); break;
case icCall: PushByte(0x28); break;
case icCalli: PushByte(0x29); break;
case icRet: PushByte(0x2a); break;
case icBr_s: PushByte(0x2b); break;
case icBrfalse_s: PushByte(0x2c); break;
case icBrtrue_s: PushByte(0x2d); break;
case icBeq_s: PushByte(0x2e); break;
case icBge_s: PushByte(0x2f); break;
case icBgt_s: PushByte(0x30); break;
case icBle_s: PushByte(0x31); break;
case icBlt_s: PushByte(0x32); break;
case icBne_un_s: PushByte(0x33); break;
case icBge_un_s: PushByte(0x34); break;
case icBgt_un_s: PushByte(0x35); break;
case icBle_un_s: PushByte(0x36); break;
case icBlt_un_s: PushByte(0x37); break;
case icBr: PushByte(0x38); break;
case icBrfalse: PushByte(0x39); break;
case icBrtrue: PushByte(0x3a); break;
case icBeq: PushByte(0x3b); break;
case icBge: PushByte(0x3c); break;
case icBgt: PushByte(0x3d); break;
case icBle: PushByte(0x3e); break;
case icBlt: PushByte(0x3f); break;
case icBne_un: PushByte(0x40); break;
case icBge_un: PushByte(0x41); break;
case icBgt_un: PushByte(0x42); break;
case icBle_un: PushByte(0x43); break;
case icBlt_un: PushByte(0x44); break;
case icSwitch: PushByte(0x45); break;
case icLdind_i1: PushByte(0x46); break;
case icLdind_u1: PushByte(0x47); break;
case icLdind_i2: PushByte(0x48); break;
case icLdind_u2: PushByte(0x49); break;
case icLdind_i4: PushByte(0x4a); break;
case icLdind_u4: PushByte(0x4b); break;
case icLdind_i8: PushByte(0x4c); break;
case icLdind_i: PushByte(0x4d); break;
case icLdind_r4: PushByte(0x4e); break;
case icLdind_r8: PushByte(0x4f); break;
case icLdind_ref: PushByte(0x50); break;
case icStind_ref: PushByte(0x51); break;
case icStind_i1: PushByte(0x52); break;
case icStind_i2: PushByte(0x53); break;
case icStind_i4: PushByte(0x54); break;
case icStind_i8: PushByte(0x55); break;
case icStind_r4: PushByte(0x56); break;
case icStind_r8: PushByte(0x57); break;
case icAdd: PushByte(0x58); break;
case icSub: PushByte(0x59); break;
case icMul: PushByte(0x5a); break;
case icDiv: PushByte(0x5b); break;
case icDiv_un: PushByte(0x5c); break;
case icRem: PushByte(0x5d); break;
case icRem_un: PushByte(0x5e); break;
case icAnd: PushByte(0x5f); break;
case icOr: PushByte(0x60); break;
case icXor: PushByte(0x61); break;
case icShl: PushByte(0x62); break;
case icShr: PushByte(0x63); break;
case icShr_un: PushByte(0x64); break;
case icNeg: PushByte(0x65); break;
case icNot: PushByte(0x66); break;
case icConv_i1: PushByte(0x67); break;
case icConv_i2: PushByte(0x68); break;
case icConv_i4: PushByte(0x69); break;
case icConv_i8: PushByte(0x6a); break;
case icConv_r4: PushByte(0x6b); break;
case icConv_r8: PushByte(0x6c); break;
case icConv_u4: PushByte(0x6d); break;
case icConv_u8: PushByte(0x6e); break;
case icCallvirt: PushByte(0x6f); break;
case icCpobj: PushByte(0x70); break;
case icLdobj: PushByte(0x71); break;
case icLdstr: PushByte(0x72); break;
case icNewobj: PushByte(0x73); break;
case icCastclass: PushByte(0x74); break;
case icIsinst: PushByte(0x75); break;
case icConv_r_un: PushByte(0x76); break;
case icUnbox: PushByte(0x79); break;
case icThrow: PushByte(0x7a); break;
case icLdfld: PushByte(0x7b); break;
case icLdflda: PushByte(0x7c); break;
case icStfld: PushByte(0x7d); break;
case icLdsfld: PushByte(0x7e); break;
case icLdsflda: PushByte(0x7f); break;
case icStsfld: PushByte(0x80); break;
case icStobj: PushByte(0x81); break;
case icConv_ovf_i1_un: PushByte(0x82); break;
case icConv_ovf_i2_un: PushByte(0x83); break;
case icConv_ovf_i4_un: PushByte(0x84); break;
case icConv_ovf_i8_un: PushByte(0x85); break;
case icConv_ovf_u1_un: PushByte(0x86); break;
case icConv_ovf_u2_un: PushByte(0x87); break;
case icConv_ovf_u4_un: PushByte(0x88); break;
case icConv_ovf_u8_un: PushByte(0x89); break;
case icConv_ovf_i_un: PushByte(0x8a); break;
case icConv_ovf_u_un: PushByte(0x8b); break;
case icBox: PushByte(0x8c); break;
case icNewarr: PushByte(0x8d); break;
case icLdlen: PushByte(0x8e); break;
case icLdelema: PushByte(0x8f); break;
case icLdelem_i1: PushByte(0x90); break;
case icLdelem_u1: PushByte(0x91); break;
case icLdelem_i2: PushByte(0x92); break;
case icLdelem_u2: PushByte(0x93); break;
case icLdelem_i4: PushByte(0x94); break;
case icLdelem_u4: PushByte(0x95); break;
case icLdelem_i8: PushByte(0x96); break;
case icLdelem_i: PushByte(0x97); break;
case icLdelem_r4: PushByte(0x98); break;
case icLdelem_r8: PushByte(0x99); break;
case icLdelem_ref: PushByte(0x9a); break;
case icStelem_i: PushByte(0x9b); break;
case icStelem_i1: PushByte(0x9c); break;
case icStelem_i2: PushByte(0x9d); break;
case icStelem_i4: PushByte(0x9e); break;
case icStelem_i8: PushByte(0x9f); break;
case icStelem_r4: PushByte(0xa0); break;
case icStelem_r8: PushByte(0xa1); break;
case icStelem_ref: PushByte(0xa2); break;
case icLdelem: PushByte(0xa3); break;
case icStelem: PushByte(0xa4); break;
case icUnbox_any: PushByte(0xa5); break;
case icConv_ovf_i1: PushByte(0xb3); break;
case icConv_ovf_u1: PushByte(0xb4); break;
case icConv_ovf_i2: PushByte(0xb5); break;
case icConv_ovf_u2: PushByte(0xb6); break;
case icConv_ovf_i4: PushByte(0xb7); break;
case icConv_ovf_u4: PushByte(0xb8); break;
case icConv_ovf_i8: PushByte(0xb9); break;
case icConv_ovf_u8: PushByte(0xba); break;
case icLdtoken: PushByte(0xd0); break;
case icConv_u2: PushByte(0xd1); break;
case icConv_u1: PushByte(0xd2); break;
case icConv_i: PushByte(0xd3); break;
case icConv_ovf_i: PushByte(0xd4); break;
case icConv_ovf_u: PushByte(0xd5); break;
case icAdd_ovf: PushByte(0xd6); break;
case icAdd_ovf_un: PushByte(0xd7); break;
case icMul_ovf: PushByte(0xd8); break;
case icMul_ovf_un: PushByte(0xd9); break;
case icSub_ovf: PushByte(0xda); break;
case icSub_ovf_un: PushByte(0xdb); break;
case icEndfinally: PushByte(0xdc); break;
case icLeave: PushByte(0xdd); break;
case icLeave_s: PushByte(0xde); break;
case icStind_i: PushByte(0xdf); break;
case icConv_u: PushByte(0xe0); break;
case icArglist: PushByte(0xfe); PushByte(0x00); break;
case icCeq: PushByte(0xfe); PushByte(0x01); break;
case icCgt: PushByte(0xfe); PushByte(0x02); break;
case icCgt_un: PushByte(0xfe); PushByte(0x03); break;
case icClt: PushByte(0xfe); PushByte(0x04); break;
case icClt_un: PushByte(0xfe); PushByte(0x05); break;
case icLdftn: PushByte(0xfe); PushByte(0x06); break;
case icLdvirtftn: PushByte(0xfe); PushByte(0x07); break;
case icLdarg: PushByte(0xfe); PushByte(0x09); break;
case icLdarga: PushByte(0xfe); PushByte(0x0a); break;
case icStarg: PushByte(0xfe); PushByte(0x0b); break;
case icLdloc: PushByte(0xfe); PushByte(0x0c); break;
case icLdloca: PushByte(0xfe); PushByte(0x0d); break;
case icStloc: PushByte(0xfe); PushByte(0x0e); break;
case icLocalloc: PushByte(0xfe); PushByte(0x0f); break;
case icEndfilter: PushByte(0xfe); PushByte(0x11); break;
case icUnaligned: PushByte(0xfe); PushByte(0x12); break;
case icVolatile: PushByte(0xfe); PushByte(0x13); break;
case icTail: PushByte(0xfe); PushByte(0x14); break;
case icInitobj: PushByte(0xfe); PushByte(0x15); break;
case icConstrained: PushByte(0xfe); PushByte(0x16); break;
case icCpblk: PushByte(0xfe); PushByte(0x17); break;
case icInitblk: PushByte(0xfe); PushByte(0x18); break;
case icNo: PushByte(0xfe); PushByte(0x19); break;
case icRethrow: PushByte(0xfe); PushByte(0x1a); break;
case icSizeof: PushByte(0xfe); PushByte(0x1c); break;
case icRefanytype: PushByte(0xfe); PushByte(0x1d); break;
case icReadonly: PushByte(0xfe); PushByte(0x1e); break;
default:
throw std::runtime_error("Runtime error at CompileToNative: " + text());
}
operand_pos_ = dump_size();
switch (ILOpCodes[type_].operand_type) {
case InlineNone:
case InlinePhi:
case Inline8:
// do nothing
break;
case ShortInlineI:
case ShortInlineVar:
PushByte(static_cast<uint8_t>(operand_value_));
break;
case InlineVar:
PushWord(static_cast<uint16_t>(operand_value_));
break;
case InlineI8:
case InlineR:
PushQWord(operand_value_);
break;
case InlineSwitch:
PushDWord(static_cast<uint32_t>(operand_value_));
break;
case ShortInlineBrTarget:
PushByte(static_cast<uint8_t>(operand_value_ - next_address() - 1));
break;
case InlineBrTarget:
PushDWord(static_cast<uint32_t>(operand_value_ - next_address() - 4));
break;
default:
PushDWord(static_cast<uint32_t>(operand_value_));
break;
}
if (options() & roFillNop) {
for (size_t j = dump_size(); j < original_dump_size_; j++) {
PushByte(0x00);
}
}
}
void ILCommand::CompileLink(const CompileContext &ctx)
{
uint64_t value;
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;
}
switch (link()->type()) {
case ltDelta:
value -= address();
break;
case ltCase:
value -= link()->parent_command()->next_address() + reinterpret_cast<ILCommand *>(link()->parent_command())->operand_value() * sizeof(uint32_t);
break;
}
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);
ILVMCommand *vm_command = reinterpret_cast<ILVMCommand *>(internal_link->from_command());
switch (internal_link->type()) {
case vlCRCTableAddress:
value = reinterpret_cast<ILFunctionList *>(ctx.file->function_list())->runtime_crc_table()->entry()->address() - ctx.file->image_base();
break;
case vlCRCTableCount:
value = reinterpret_cast<ILFunctionList *>(ctx.file->function_list())->runtime_crc_table()->region_count();
break;
default:
ILCommand *command = reinterpret_cast<ILCommand*>(internal_link->to_command());
if (!command)
continue;
value = command->vm_address() - ctx.file->image_base();
}
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();
uint64_t image_base = ctx.file->image_base();
switch (link()->type()) {
case ltJmp:
case ltCase:
set_link_value(0, to_command->vm_address() - image_base);
break;
case ltJmpWithFlag:
set_link_value(0, to_command->vm_address() - image_base);
set_link_value(1, next_command->vm_address() - image_base);
break;
case ltOffset:
if (to_command) {
value = (section_options_ & rtLinkedFromOtherType) ? to_command->address() : to_command->vm_address();
set_link_value(0, link()->Encrypt(value));
}
break;
case ltSwitch:
set_link_value(0, vm_links_[4]->address() - image_base);
set_link_value(1, vm_links_[2]->address() - image_base);
set_link_value(3, next_command->vm_address() - image_base);
set_link_value(5, to_command->vm_address() - image_base);
break;
case ltCall:
if (section_options_ & rtLinkedFrom)
set_link_value(0, to_command->vm_address() - image_base);
break;
}
}
}
void ILCommand::PrepareLink(const CompileContext &ctx)
{
bool from_native = block() && (block()->type() & mtExecutable) ? true : owner()->compilation_type() == ctMutation;
ICommand *to_command = link()->to_command();
if (to_command) {
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() == ltJmp && (type_ == icLeave || type_ == icLeave_s))) {
to_command->include_section_option(rtLinkedToExt);
}
else {
to_command->include_section_option(rtLinkedToInt);
}
}
if (from_native)
return;
bool need_next_command = false;
ICommand *next_command;
switch (link()->type()) {
case ltJmpWithFlag:
case ltSwitch:
need_next_command = true;
break;
}
if (need_next_command) {
size_t j = owner()->IndexOf(this) + 1;
if (type_ == icSwitch)
j += static_cast<uint32_t>(operand_value_);
if (j < owner()->count()) {
next_command = owner()->item(j);
include_section_option(rtLinkedNext);
link()->set_next_command(next_command);
next_command->include_section_option(rtLinkedToInt);
}
}
}
void ILCommand::set_link_value(size_t link_index, uint64_t value)
{
ILVMCommand *vm_command = vm_links_[link_index];
vm_command->set_value(value);
vm_command->Compile();
}
void ILCommand::set_operand_value(size_t operand_index, uint64_t value)
{
operand_value_ = value;
}
void ILCommand::set_operand_fixup(IFixup *fixup)
{
fixup_ = fixup;
}
void ILCommand::set_address(uint64_t address)
{
address_ = address;
switch (ILOpCodes[type_].operand_type) {
case ShortInlineBrTarget:
case InlineBrTarget:
CompileToNative();
break;
}
}
void ILCommand::ReadFromBuffer(Buffer &buffer, IArchitecture &file)
{
size_t i, r;
r = buffer.ReadByte();
address_ = buffer.ReadDWord() + file.image_base();
type_ = static_cast<ILCommandType>(buffer.ReadWord());
BaseCommand::ReadFromBuffer(buffer, file);
original_dump_size_ = (r & 0x10) ? buffer.ReadWord() : buffer.ReadByte();
if (type_ == icComment) {
for (i = 0; i < original_dump_size_; i++) {
PushByte(buffer.ReadByte());
}
} else {
for (i = 0; i < original_dump_size_; i++) {
PushByte(0);
}
}
if (r & 1) {
operand_value_ = buffer.ReadQWord();
}
if (r & 0x08) {
uint32_t value = static_cast<uint32_t>(operand_value_);
ILMetaData *meta = dynamic_cast<NETArchitecture &>(file).command_list();
ILToken *token = meta->token(value);
if (!token && TOKEN_TYPE(value) == ttUserString)
token = meta->us_table()->Add(value);
if (token) {
uint64_t reference_address = address() + original_dump_size_ - sizeof(uint32_t);
if (type_ == icComment) {
token_reference_ = token->reference_list()->GetReferenceByAddress(reference_address);
if (!token_reference_)
throw std::runtime_error("Invalid token reference");
}
else
token_reference_ = token->reference_list()->Add(reference_address);
}
}
}
void ILCommand::WriteToFile(IArchitecture &file)
{
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_ + operand_pos_);
}
BaseCommand::WriteToFile(file);
}
void ILCommand::Rebase(uint64_t delta_base)
{
if (!address_)
return;
switch (ILOpCodes[type_].operand_type) {
case ShortInlineBrTarget:
case InlineBrTarget:
operand_value_ += delta_base;
break;
}
address_ += delta_base;
}
ILCommand * ILCommand::Clone(IFunction *owner) const
{
ILCommand *command = new ILCommand(owner, *this);
return command;
}
bool ILCommand::Merge(ICommand *command)
{
return false;
}
bool ILCommand::is_data() const
{
return (type_ == icByte || type_ == icWord || type_ == icDword || type_ == icData);
}
bool ILCommand::is_end() const
{
ILFlowControl flow_type = ILOpCodes[type_].flow_type;
return (flow_type == Branch || flow_type == Return || flow_type == Throw);
}
bool ILCommand::is_prefix() const
{
return (ILOpCodes[type_].opcode_type == Prefix);
}
std::string ILCommand::dump_str() const
{
std::string res;
if (type_ == icUnknown) {
for (size_t i = 0; i < dump_size(); i++) {
res += "??";
}
return res;
}
res = BaseCommand::dump_str();
size_t value_size;
const ILOpCode opcode = ILOpCodes[type_];
switch (opcode.operand_type) {
case InlineNone:
case InlinePhi:
case Inline8:
value_size = 0;
break;
case ShortInlineI:
case ShortInlineVar:
case ShortInlineBrTarget:
value_size = sizeof(uint8_t);
break;
case InlineVar:
value_size = sizeof(uint16_t);
break;
case InlineI8:
case InlineR:
value_size = sizeof(uint64_t);
break;
default:
value_size = sizeof(uint32_t);
break;
}
if (value_size) {
size_t end = dump_size();
while (end > operand_pos_) {
res.insert((end - value_size) * 2, " ");
end -= value_size;
}
}
return res;
}
std::string ILCommand::display_address() const
{
return DisplayValue(size(), address());
}
size_t ILCommand::ReadFromFile(IArchitecture & file)
{
clear();
switch (ReadByte(file)) {
case 0x00: type_ = icNop; break;
case 0x01: type_ = icBreak; break;
case 0x02: type_ = icLdarg_0; break;
case 0x03: type_ = icLdarg_1; break;
case 0x04: type_ = icLdarg_2; break;
case 0x05: type_ = icLdarg_3; break;
case 0x06: type_ = icLdloc_0; break;
case 0x07: type_ = icLdloc_1; break;
case 0x08: type_ = icLdloc_2; break;
case 0x09: type_ = icLdloc_3; break;
case 0x0a: type_ = icStloc_0; break;
case 0x0b: type_ = icStloc_1; break;
case 0x0c: type_ = icStloc_2; break;
case 0x0d: type_ = icStloc_3; break;
case 0x0e: type_ = icLdarg_s; break;
case 0x0f: type_ = icLdarga_s; break;
case 0x10: type_ = icStarg_s; break;
case 0x11: type_ = icLdloc_s; break;
case 0x12: type_ = icLdloca_s; break;
case 0x13: type_ = icStloc_s; break;
case 0x14: type_ = icLdnull; break;
case 0x15: type_ = icLdc_i4_m1; break;
case 0x16: type_ = icLdc_i4_0; break;
case 0x17: type_ = icLdc_i4_1; break;
case 0x18: type_ = icLdc_i4_2; break;
case 0x19: type_ = icLdc_i4_3; break;
case 0x1a: type_ = icLdc_i4_4; break;
case 0x1b: type_ = icLdc_i4_5; break;
case 0x1c: type_ = icLdc_i4_6; break;
case 0x1d: type_ = icLdc_i4_7; break;
case 0x1e: type_ = icLdc_i4_8; break;
case 0x1f: type_ = icLdc_i4_s; break;
case 0x20: type_ = icLdc_i4; break;
case 0x21: type_ = icLdc_i8; break;
case 0x22: type_ = icLdc_r4; break;
case 0x23: type_ = icLdc_r8; break;
// 0x24 reserved for standardization
case 0x25: type_ = icDup; break;
case 0x26: type_ = icPop; break;
case 0x27: type_ = icJmp; break;
case 0x28: type_ = icCall; break;
case 0x29: type_ = icCalli; break;
case 0x2a: type_ = icRet; break;
case 0x2b: type_ = icBr_s; break;
case 0x2c: type_ = icBrfalse_s; break;
case 0x2d: type_ = icBrtrue_s; break;
case 0x2e: type_ = icBeq_s; break;
case 0x2f: type_ = icBge_s; break;
case 0x30: type_ = icBgt_s; break;
case 0x31: type_ = icBle_s; break;
case 0x32: type_ = icBlt_s; break;
case 0x33: type_ = icBne_un_s; break;
case 0x34: type_ = icBge_un_s; break;
case 0x35: type_ = icBgt_un_s; break;
case 0x36: type_ = icBle_un_s; break;
case 0x37: type_ = icBlt_un_s; break;
case 0x38: type_ = icBr; break;
case 0x39: type_ = icBrfalse; break;
case 0x3a: type_ = icBrtrue; break;
case 0x3b: type_ = icBeq; break;
case 0x3c: type_ = icBge; break;
case 0x3d: type_ = icBgt; break;
case 0x3e: type_ = icBle; break;
case 0x3f: type_ = icBlt; break;
case 0x40: type_ = icBne_un; break;
case 0x41: type_ = icBge_un; break;
case 0x42: type_ = icBgt_un; break;
case 0x43: type_ = icBle_un; break;
case 0x44: type_ = icBlt_un; break;
case 0x45: type_ = icSwitch; break;
case 0x46: type_ = icLdind_i1; break;
case 0x47: type_ = icLdind_u1; break;
case 0x48: type_ = icLdind_i2; break;
case 0x49: type_ = icLdind_u2; break;
case 0x4a: type_ = icLdind_i4; break;
case 0x4b: type_ = icLdind_u4; break;
case 0x4c: type_ = icLdind_i8; break;
case 0x4d: type_ = icLdind_i; break;
case 0x4e: type_ = icLdind_r4; break;
case 0x4f: type_ = icLdind_r8; break;
case 0x50: type_ = icLdind_ref; break;
case 0x51: type_ = icStind_ref; break;
case 0x52: type_ = icStind_i1; break;
case 0x53: type_ = icStind_i2; break;
case 0x54: type_ = icStind_i4; break;
case 0x55: type_ = icStind_i8; break;
case 0x56: type_ = icStind_r4; break;
case 0x57: type_ = icStind_r8; break;
case 0x58: type_ = icAdd; break;
case 0x59: type_ = icSub; break;
case 0x5a: type_ = icMul; break;
case 0x5b: type_ = icDiv; break;
case 0x5c: type_ = icDiv_un; break;
case 0x5d: type_ = icRem; break;
case 0x5e: type_ = icRem_un; break;
case 0x5f: type_ = icAnd; break;
case 0x60: type_ = icOr; break;
case 0x61: type_ = icXor; break;
case 0x62: type_ = icShl; break;
case 0x63: type_ = icShr; break;
case 0x64: type_ = icShr_un; break;
case 0x65: type_ = icNeg; break;
case 0x66: type_ = icNot; break;
case 0x67: type_ = icConv_i1; break;
case 0x68: type_ = icConv_i2; break;
case 0x69: type_ = icConv_i4; break;
case 0x6a: type_ = icConv_i8; break;
case 0x6b: type_ = icConv_r4; break;
case 0x6c: type_ = icConv_r8; break;
case 0x6d: type_ = icConv_u4; break;
case 0x6e: type_ = icConv_u8; break;
case 0x6f: type_ = icCallvirt; break;
case 0x70: type_ = icCpobj; break;
case 0x71: type_ = icLdobj; break;
case 0x72: type_ = icLdstr; break;
case 0x73: type_ = icNewobj; break;
case 0x74: type_ = icCastclass; break;
case 0x75: type_ = icIsinst; break;
case 0x76: type_ = icConv_r_un; break;
// 0x77-0x78 reserved for standardization
case 0x79: type_ = icUnbox; break;
case 0x7a: type_ = icThrow; break;
case 0x7b: type_ = icLdfld; break;
case 0x7c: type_ = icLdflda; break;
case 0x7d: type_ = icStfld; break;
case 0x7e: type_ = icLdsfld; break;
case 0x7f: type_ = icLdsflda; break;
case 0x80: type_ = icStsfld; break;
case 0x81: type_ = icStobj; break;
case 0x82: type_ = icConv_ovf_i1_un; break;
case 0x83: type_ = icConv_ovf_i2_un; break;
case 0x84: type_ = icConv_ovf_i4_un; break;
case 0x85: type_ = icConv_ovf_i8_un; break;
case 0x86: type_ = icConv_ovf_u1_un; break;
case 0x87: type_ = icConv_ovf_u2_un; break;
case 0x88: type_ = icConv_ovf_u4_un; break;
case 0x89: type_ = icConv_ovf_u8_un; break;
case 0x8a: type_ = icConv_ovf_i_un; break;
case 0x8b: type_ = icConv_ovf_u_un; break;
case 0x8c: type_ = icBox; break;
case 0x8d: type_ = icNewarr; break;
case 0x8e: type_ = icLdlen; break;
case 0x8f: type_ = icLdelema; break;
case 0x90: type_ = icLdelem_i1; break;
case 0x91: type_ = icLdelem_u1; break;
case 0x92: type_ = icLdelem_i2; break;
case 0x93: type_ = icLdelem_u2; break;
case 0x94: type_ = icLdelem_i4; break;
case 0x95: type_ = icLdelem_u4; break;
case 0x96: type_ = icLdelem_i8; break;
case 0x97: type_ = icLdelem_i; break;
case 0x98: type_ = icLdelem_r4; break;
case 0x99: type_ = icLdelem_r8; break;
case 0x9a: type_ = icLdelem_ref; break;
case 0x9b: type_ = icStelem_i; break;
case 0x9c: type_ = icStelem_i1; break;
case 0x9d: type_ = icStelem_i2; break;
case 0x9e: type_ = icStelem_i4; break;
case 0x9f: type_ = icStelem_i8; break;
case 0xa0: type_ = icStelem_r4; break;
case 0xa1: type_ = icStelem_r8; break;
case 0xa2: type_ = icStelem_ref; break;
case 0xa3: type_ = icLdelem; break;
case 0xa4: type_ = icStelem; break;
case 0xa5: type_ = icUnbox_any; break;
// 0xA6-0xB2 reserved for standardization
case 0xb3: type_ = icConv_ovf_i1; break;
case 0xb4: type_ = icConv_ovf_u1; break;
case 0xb5: type_ = icConv_ovf_i2; break;
case 0xb6: type_ = icConv_ovf_u2; break;
case 0xb7: type_ = icConv_ovf_i4; break;
case 0xb8: type_ = icConv_ovf_u4; break;
case 0xb9: type_ = icConv_ovf_i8; break;
case 0xba: type_ = icConv_ovf_u8; break;
// 0xBB-0xC1 reserved for standardization
case 0xc2: type_ = icRefanyval; break;
case 0xc3: type_ = icCkfinite; break;
// 0xC4-0xC5 reserved for standardization
case 0xc6: type_ = icMkrefany; break;
// 0xC7-0xCF reserved for standardization
case 0xd0: type_ = icLdtoken; break;
case 0xd1: type_ = icConv_u2; break;
case 0xd2: type_ = icConv_u1; break;
case 0xd3: type_ = icConv_i; break;
case 0xd4: type_ = icConv_ovf_i; break;
case 0xd5: type_ = icConv_ovf_u; break;
case 0xd6: type_ = icAdd_ovf; break;
case 0xd7: type_ = icAdd_ovf_un; break;
case 0xd8: type_ = icMul_ovf; break;
case 0xd9: type_ = icMul_ovf_un; break;
case 0xda: type_ = icSub_ovf; break;
case 0xdb: type_ = icSub_ovf_un; break;
case 0xdc: type_ = icEndfinally; break;
case 0xdd: type_ = icLeave; break;
case 0xde: type_ = icLeave_s; break;
case 0xdf: type_ = icStind_i; break;
case 0xe0: type_ = icConv_u; break;
// 0xE1-0xEF reserved for standardization
// 0xF0-0xFB are ecma_experimental
// 0xFC-0xFD reserved for standardization
case 0xfe:
//two-byte opcodes
switch (ReadByte(file)) {
case 0x00: type_ = icArglist; break;
case 0x01: type_ = icCeq; break;
case 0x02: type_ = icCgt; break;
case 0x03: type_ = icCgt_un; break;
case 0x04: type_ = icClt; break;
case 0x05: type_ = icClt_un; break;
case 0x06: type_ = icLdftn; break;
case 0x07: type_ = icLdvirtftn; break;
// 0xFE08 reserved for standardization
case 0x09: type_ = icLdarg; break;
case 0x0a: type_ = icLdarga; break;
case 0x0b: type_ = icStarg; break;
case 0x0c: type_ = icLdloc; break;
case 0x0d: type_ = icLdloca; break;
case 0x0e: type_ = icStloc; break;
case 0x0f: type_ = icLocalloc; break;
// 0xFE10 reserved for standardization
case 0x11: type_ = icEndfilter; break;
case 0x12: type_ = icUnaligned; break;
case 0x13: type_ = icVolatile; break;
case 0x14: type_ = icTail; break;
case 0x15: type_ = icInitobj; break;
case 0x16: type_ = icConstrained; break;
case 0x17: type_ = icCpblk; break;
case 0x18: type_ = icInitblk; break;
case 0x19: type_ = icNo; break;
case 0x1a: type_ = icRethrow; break;
// 0xFE1B reserved for standardization
case 0x1c: type_ = icSizeof; break;
case 0x1d: type_ = icRefanytype; break;
case 0x1e: type_ = icReadonly; break;
}
break;
// 0xFF reserved for standardization
}
operand_pos_ = dump_size();
switch (ILOpCodes[type_].operand_type)
{
case InlineNone: // No operand
case InlinePhi: // Obsolete. The operand is reserved and should not be used.
case Inline8: // not used
// all read already
break;
case ShortInlineI: // 8-bit integer
operand_value_ = static_cast<int8_t>(ReadByte(file));
break;
case ShortInlineVar: // 8-bit integer containing the ordinal of a local variable or an argument
operand_value_ = ReadByte(file);
break;
case InlineVar: // 16-bit integer containing the ordinal of a local variable or an argument
operand_value_ = ReadWord(file);
break;
case InlineI8: // 64-bit integer
case InlineR: // 64-bit IEEE floating point number
operand_value_ = ReadQWord(file);
break;
case InlineSwitch:
operand_value_ = ReadDWord(file);
break;
case ShortInlineBrTarget: // 8-bit integer branch target
operand_value_ = static_cast<int8_t>(ReadByte(file));
operand_value_ += next_address();
break;
case InlineBrTarget: // 32-bit integer branch target
operand_value_ = static_cast<int32_t>(ReadDWord(file));
operand_value_ += next_address();
break;
case InlineField:
case InlineMethod:
case InlineSig:
case InlineTok:
case InlineType:
case InlineString:
operand_value_ = ReadDWord(file);
{
ILToken *token = dynamic_cast<NETArchitecture &>(file).command_list()->token(static_cast<uint32_t>(operand_value_));
if (token)
token_reference_ = token->reference_list()->GetReferenceByAddress(address() + operand_pos_);
}
break;
default: // 4 byte
operand_value_ = ReadDWord(file);
break;
}
original_dump_size_ = dump_size();
return original_dump_size_;
}
uint64_t ILCommand::ReadValueFromFile(IArchitecture &file, OperandSize value_size, bool is_token)
{
switch (value_size) {
case osByte:
type_ = icByte;
operand_value_ = ReadByte(file);
break;
case osWord:
type_ = icWord;
operand_value_ = ReadWord(file);
break;
case osDWord:
type_ = icDword;
operand_value_ = ReadDWord(file);
break;
default:
throw std::runtime_error("Invalid value size");
}
if (is_token) {
ILToken *token = dynamic_cast<NETArchitecture &>(file).command_list()->token(static_cast<uint32_t>(operand_value_));
if (token)
token_reference_ = token->reference_list()->GetReferenceByAddress(address_);
}
return operand_value_;
}
void ILCommand::ReadString(IArchitecture &file, size_t len)
{
type_ = icData;
Read(file, len);
}
void ILCommand::ReadCaseCommand(IArchitecture &file)
{
type_ = icCase;
operand_value_ = DWordToInt64(ReadDWord(file));
}
int ILCommand::GetStackLevel(size_t *pop_ref) const
{
if (type_ == icRet)
return 0;
size_t push = 0;
size_t pop = 0;
if (ILOpCodes[type_].flow_type == Call) {
ILToken *token = token_reference_->owner()->owner();
if (token->type() == ttMethodSpec)
token = reinterpret_cast<ILMethodSpec *>(token)->parent();
ILSignature *signature;
switch (token->type()) {
case ttMethodDef:
signature = reinterpret_cast<ILMethodDef *>(token)->signature();
break;
case ttMemberRef:
signature = reinterpret_cast<ILMemberRef *>(token)->signature();
break;
case ttStandAloneSig:
signature = reinterpret_cast<ILStandAloneSig *>(token)->signature();
break;
default:
throw std::runtime_error("Invalid token type: " + text());
}
if (type_ != icNewobj && signature->has_this() && !signature->explicit_this())
pop += 1;
if (type_ == icCalli)
pop += 1;
pop += static_cast<int>(signature->count());
if (type_ == icNewobj || signature->ret()->type() != ELEMENT_TYPE_VOID)
push += 1;
}
else {
switch (ILOpCodes[type_].pop) {
case Pop0:
break;
case Pop1:
case Popi:
case Popref:
pop += 1;
break;
case Pop1_pop1:
case Popi_pop1:
case Popi_popi:
case Popi_popi8:
case Popi_popr4:
case Popi_popr8:
case Popref_pop1:
case Popref_popi:
pop += 2;
break;
case Popi_popi_popi:
case Popref_popi_popi:
case Popref_popi_popi8:
case Popref_popi_popr4:
case Popref_popi_popr8:
case Popref_popi_popref:
case Popref_popi_pop1:
pop += 3;
break;
}
switch (ILOpCodes[type_].push) {
case Push0:
break;
case Push1:
case Pushi:
case Pushi8:
case Pushr4:
case Pushr8:
case Pushref:
push += 1;
break;
case Push1_push1:
push += 2;
break;
}
}
if (pop_ref)
*pop_ref = pop;
return (int)(push - pop);
}
ILVMCommand *ILCommand::AddVMCommand(const CompileContext &ctx, ILCommandType command_type, uint64_t value, uint32_t options, TokenReference *token_reference, ILCommand *to_command)
{
ILVMCommand *vm_command = NULL;
#ifdef ULTIMATE
if ((owner()->compilation_options() & coLockToKey) && command_type == icLdc_i4 && (options & voNoCryptValue) == 0) {
vm_command = new ILVMCommand(this, command_type, value, token_reference);
vm_command->set_crypt_command(icAdd, osDWord, ctx.options.licensing_manager->product_code());
}
#endif
if (!vm_command)
vm_command = new ILVMCommand(this, command_type, value, token_reference);
AddObject(vm_command);
if (options & voLinkCommand)
vm_links_.push_back(vm_command);
switch (command_type) {
case icBr:
case icRet:
section_options_ |= rtCloseSection;
break;
}
if (to_command)
internal_links_.Add(vlNone, vm_command, to_command);
uint32_t new_options = (options & voSectionCommand);
if (vm_command->crypt_command() == icAdd) {
new_options |= voNoCryptValue;
size_t i;
ILVMCommand *cur_command = vm_command;
ILToken *type = reinterpret_cast<NETArchitecture *>(ctx.file)->command_list()->ImportType(ELEMENT_TYPE_U4);
// add session key
uint64_t address = ctx.runtime->export_list()->GetAddressByType(atLoaderData);
ILFunction *loader_data_func = reinterpret_cast<ILFunction *>(ctx.runtime->function_list()->GetFunctionByAddress(address));
ILCommand *field_command = loader_data_func->item(1);
AddVMCommand(ctx, icLdnull, 0, new_options);
AddVMCommand(ctx, icLdc_i4, field_command->operand_value(), new_options, field_command->token_reference());
AddVMCommand(ctx, icLdfld, 0, new_options);
AddVMCommand(ctx, icLdc_i4, ctx.runtime_var_index[VAR_SESSION_KEY], new_options);
AddVMCommand(ctx, icLdc_i4, type->id(), new_options, type->reference_list()->Add(0));
AddVMCommand(ctx, icLdelem_ref, 0, new_options);
AddVMCommand(ctx, icAdd, 0, new_options);
for (i = 1; i < 4; i++) {
cur_command->set_link_command(AddVMCommand(ctx, icLdc_i4, 0, new_options));
// add session key
AddVMCommand(ctx, icLdnull, 0, new_options);
AddVMCommand(ctx, icLdc_i4, field_command->operand_value(), new_options, field_command->token_reference());
AddVMCommand(ctx, icLdfld, 0, new_options);
AddVMCommand(ctx, icLdc_i4, ctx.runtime_var_index[VAR_SESSION_KEY], new_options);
AddVMCommand(ctx, icLdc_i4, type->id(), new_options, type->reference_list()->Add(0));
AddVMCommand(ctx, icLdelem_ref, 0, new_options);
AddVMCommand(ctx, icAdd, 0, new_options);
cur_command = cur_command->link_command();
}
address = ctx.runtime->export_list()->GetAddressByType(atDecryptBuffer);
ILVMCommand *from_command = AddVMCommand(ctx, icLdc_i4, 0, new_options);
ICommand *to_command = ctx.file->function_list()->GetCommandByAddress(address, true);
if (to_command)
internal_links_.Add(vlNone, from_command, to_command);
AddVMCommand(ctx, icCallvm, 0, new_options);
// add session key
AddVMCommand(ctx, icLdnull, 0, new_options);
AddVMCommand(ctx, icLdc_i4, field_command->operand_value(), new_options, field_command->token_reference());
AddVMCommand(ctx, icLdfld, 0, new_options);
AddVMCommand(ctx, icLdc_i4, ctx.runtime_var_index[VAR_SESSION_KEY], new_options);
AddVMCommand(ctx, icLdc_i4, type->id(), new_options, type->reference_list()->Add(0));
AddVMCommand(ctx, icLdelem_ref, 0, new_options);
AddVMCommand(ctx, icAdd, 0, new_options);
}
return vm_command;
}
void ILCommand::AddCmpSection(const CompileContext &ctx, ILCommandType cmp_command)
{
ILCommandType cmp_type;
switch (cmp_command) {
case icBne_un:
case icClt_un:
case icBlt_un:
case icBle_un:
case icCgt_un:
case icBgt_un:
case icBge_un:
cmp_type = icCmp_un;
break;
default:
cmp_type = icCmp;
break;
}
switch (cmp_command) {
case icCeq:
case icBeq:
AddVMCommand(ctx, icLdc_i4, 1);
AddVMCommand(ctx, cmp_type, 0);
AddVMCommand(ctx, icNot, 0);
AddVMCommand(ctx, icLdc_i4, 1);
AddVMCommand(ctx, icAnd, 0);
break;
case icBne_un:
AddVMCommand(ctx, icLdc_i4, 0);
AddVMCommand(ctx, cmp_type, 0);
AddVMCommand(ctx, icLdc_i4, 1);
AddVMCommand(ctx, icAnd, 0);
break;
case icClt:
case icClt_un:
case icBlt:
case icBlt_un:
AddVMCommand(ctx, icLdc_i4, 1);
AddVMCommand(ctx, cmp_type, 0);
AddVMCommand(ctx, icLdc_i4, 1);
AddVMCommand(ctx, icShr_un, 0);
AddVMCommand(ctx, icLdc_i4, 1);
AddVMCommand(ctx, icAnd, 0);
break;
case icBle:
case icBle_un:
AddVMCommand(ctx, icLdc_i4, 1);
AddVMCommand(ctx, cmp_type, 0);
AddVMCommand(ctx, icLdc_i4, 1);
AddVMCommand(ctx, icAdd, 0);
AddVMCommand(ctx, icNot, 0);
AddVMCommand(ctx, icLdc_i4, 1);
AddVMCommand(ctx, icShr_un, 0);
AddVMCommand(ctx, icLdc_i4, 1);
AddVMCommand(ctx, icAnd, 0);
break;
case icCgt:
case icCgt_un:
case icBgt:
case icBgt_un:
AddVMCommand(ctx, icLdc_i4, static_cast<uint32_t>(-1));
AddVMCommand(ctx, cmp_type, 0);
AddVMCommand(ctx, icNot, 0);
AddVMCommand(ctx, icLdc_i4, 1);
AddVMCommand(ctx, icAdd, 0);
AddVMCommand(ctx, icLdc_i4, 1);
AddVMCommand(ctx, icShr_un, 0);
AddVMCommand(ctx, icLdc_i4, 1);
AddVMCommand(ctx, icAnd, 0);
break;
case icBge:
case icBge_un:
AddVMCommand(ctx, icLdc_i4, static_cast<uint32_t>(-1));
AddVMCommand(ctx, cmp_type, 0);
AddVMCommand(ctx, icNot, 0);
AddVMCommand(ctx, icLdc_i4, 1);
AddVMCommand(ctx, icShr_un, 0);
AddVMCommand(ctx, icLdc_i4, 1);
AddVMCommand(ctx, icAnd, 0);
break;
}
}
void ILCommand::AddJmpWithFlagSection(const CompileContext &ctx, bool is_true)
{
ILToken *type = reinterpret_cast<NETArchitecture *>(ctx.file)->command_list()->ImportType(ELEMENT_TYPE_BOOLEAN);
AddVMCommand(ctx, icLdc_i4, type->id(), 0, type->reference_list()->Add(0));
AddVMCommand(ctx, icConv, 0);
AddVMCommand(ctx, icNeg, 0);
if (!is_true)
AddVMCommand(ctx, icNot, 0);
AddVMCommand(ctx, icLdc_i4, 0, voLinkCommand);
AddVMCommand(ctx, icAnd, 0);
AddVMCommand(ctx, icDup, 0);
AddVMCommand(ctx, icLdc_i4, type->id(), 0, type->reference_list()->Add(0));
AddVMCommand(ctx, icConv, 0);
AddVMCommand(ctx, icNeg, 0);
AddVMCommand(ctx, icNot, 0);
AddVMCommand(ctx, icLdc_i4, 0, voLinkCommand);
AddVMCommand(ctx, icAnd, 0);
AddVMCommand(ctx, icAdd, 0);
AddVMCommand(ctx, icBr, 0);
}
void ILCommand::CompileToVM(const CompileContext &ctx)
{
ILToken *internal_type = NULL;
TokenReference *internal_token_reference = NULL;
switch (type_) {
case icLdelem_i:
case icLdelem_i1:
case icLdelem_i2:
case icLdelem_i4:
case icLdelem_i8:
case icLdelem_u1:
case icLdelem_u2:
case icLdelem_u4:
case icLdelem_r4:
case icLdelem_r8:
case icLdelem_ref:
case icStelem_i:
case icStelem_i1:
case icStelem_i2:
case icStelem_i4:
case icStelem_i8:
case icStelem_r4:
case icStelem_r8:
case icStelem_ref:
case icLdind_i:
case icLdind_i1:
case icLdind_i2:
case icLdind_i4:
case icLdind_i8:
case icLdind_u1:
case icLdind_u2:
case icLdind_u4:
case icLdind_r4:
case icLdind_r8:
case icLdind_ref:
case icStind_i:
case icStind_i1:
case icStind_i2:
case icStind_i4:
case icStind_i8:
case icStind_r4:
case icStind_r8:
case icStind_ref:
case icConv_i:
case icConv_u:
case icConv_i1:
case icConv_u1:
case icConv_i2:
case icConv_u2:
case icConv_i4:
case icConv_u4:
case icConv_i8:
case icConv_u8:
case icConv_r4:
case icConv_r8:
case icConv_r_un:
case icConv_ovf_i:
case icConv_ovf_u:
case icConv_ovf_i1:
case icConv_ovf_u1:
case icConv_ovf_i2:
case icConv_ovf_u2:
case icConv_ovf_i4:
case icConv_ovf_u4:
case icConv_ovf_i8:
case icConv_ovf_u8:
case icConv_ovf_i_un:
case icConv_ovf_u_un:
case icConv_ovf_i1_un:
case icConv_ovf_u1_un:
case icConv_ovf_i2_un:
case icConv_ovf_u2_un:
case icConv_ovf_i4_un:
case icConv_ovf_u4_un:
case icConv_ovf_i8_un:
case icConv_ovf_u8_un:
{
CorElementType element_type;
switch (type_) {
case icLdelem_i1:
case icStelem_i1:
case icLdind_i1:
case icStind_i1:
case icConv_i1:
case icConv_ovf_i1:
case icConv_ovf_i1_un:
element_type = ELEMENT_TYPE_I1;
break;
case icLdelem_i2:
case icStelem_i2:
case icLdind_i2:
case icStind_i2:
case icConv_i2:
case icConv_ovf_i2:
case icConv_ovf_i2_un:
element_type = ELEMENT_TYPE_I2;
break;
case icLdelem_i4:
case icStelem_i4:
case icLdind_i4:
case icStind_i4:
case icConv_i4:
case icConv_ovf_i4:
case icConv_ovf_i4_un:
element_type = ELEMENT_TYPE_I4;
break;
case icLdelem_i8:
case icStelem_i8:
case icLdind_i8:
case icStind_i8:
case icConv_i8:
case icConv_ovf_i8:
case icConv_ovf_i8_un:
element_type = ELEMENT_TYPE_I8;
break;
case icLdelem_u1:
case icLdind_u1:
case icConv_u1:
case icConv_ovf_u1:
case icConv_ovf_u1_un:
element_type = ELEMENT_TYPE_U1;
break;
case icLdelem_u2:
case icLdind_u2:
case icConv_u2:
case icConv_ovf_u2:
case icConv_ovf_u2_un:
element_type = ELEMENT_TYPE_U2;
break;
case icLdelem_u4:
case icLdind_u4:
case icConv_u4:
case icConv_ovf_u4:
case icConv_ovf_u4_un:
element_type = ELEMENT_TYPE_U4;
break;
case icConv_u8:
case icConv_ovf_u8:
case icConv_ovf_u8_un:
element_type = ELEMENT_TYPE_U8;
break;
case icLdelem_r4:
case icStelem_r4:
case icLdind_r4:
case icStind_r4:
case icConv_r4:
element_type = ELEMENT_TYPE_R4;
break;
case icLdelem_r8:
case icStelem_r8:
case icLdind_r8:
case icStind_r8:
case icConv_r8:
case icConv_r_un:
element_type = ELEMENT_TYPE_R8;
break;
case icLdelem_ref:
case icStelem_ref:
case icLdind_ref:
case icStind_ref:
element_type = ELEMENT_TYPE_OBJECT;
break;
case icConv_u:
case icConv_ovf_u:
case icConv_ovf_u_un:
element_type = ELEMENT_TYPE_U;
break;
default:
element_type = ELEMENT_TYPE_I;
break;
}
internal_type = reinterpret_cast<NETArchitecture *>(ctx.file)->command_list()->ImportType(element_type);
internal_token_reference = internal_type->reference_list()->Add(0);
}
break;
}
switch (type_) {
case icNop:
break;
case icLdarg:
case icLdarg_s:
case icLdarg_0:
case icLdarg_1:
case icLdarg_2:
case icLdarg_3:
AddVMCommand(ctx, icLdarg, param_);
break;
case icLdarga:
case icLdarga_s:
AddVMCommand(ctx, icLdarga, param_);
break;
case icStarg:
case icStarg_s:
AddVMCommand(ctx, icStarg, param_);
break;
case icLdloc:
case icLdloc_s:
case icLdloc_0:
case icLdloc_1:
case icLdloc_2:
case icLdloc_3:
AddVMCommand(ctx, icLdarg, param_);
break;
case icLdloca:
case icLdloca_s:
AddVMCommand(ctx, icLdarga, param_);
break;
case icStloc:
case icStloc_s:
case icStloc_0:
case icStloc_1:
case icStloc_2:
case icStloc_3:
AddVMCommand(ctx, icStarg, param_);
break;
case icLdc_i4_0:
AddVMCommand(ctx, icLdc_i4, 0);
break;
case icLdc_i4_1:
AddVMCommand(ctx, icLdc_i4, 1);
break;
case icLdc_i4_2:
AddVMCommand(ctx, icLdc_i4, 2);
break;
case icLdc_i4_3:
AddVMCommand(ctx, icLdc_i4, 3);
break;
case icLdc_i4_4:
AddVMCommand(ctx, icLdc_i4, 4);
break;
case icLdc_i4_5:
AddVMCommand(ctx, icLdc_i4, 5);
break;
case icLdc_i4_6:
AddVMCommand(ctx, icLdc_i4, 6);
break;
case icLdc_i4_7:
AddVMCommand(ctx, icLdc_i4, 7);
break;
case icLdc_i4_8:
AddVMCommand(ctx, icLdc_i4, 8);
break;
case icLdc_i4:
case icLdc_i4_s:
AddVMCommand(ctx, icLdc_i4, operand_value_, (link() && link()->operand_index() == 0) ? voLinkCommand : 0);
break;
case icLdc_i4_m1:
AddVMCommand(ctx, icLdc_i4, static_cast<uint32_t>(-1));
break;
case icLdc_i8:
AddVMCommand(ctx, icLdc_i8, operand_value_);
break;
case icLdc_r4:
AddVMCommand(ctx, icLdc_r4, operand_value_);
break;
case icLdc_r8:
AddVMCommand(ctx, icLdc_r8, operand_value_);
break;
case icLdnull:
AddVMCommand(ctx, icLdnull, 0);
break;
case icConv_i:
case icConv_u:
case icConv_i1:
case icConv_u1:
case icConv_i2:
case icConv_u2:
case icConv_i4:
case icConv_u4:
case icConv_i8:
case icConv_u8:
case icConv_r4:
case icConv_r8:
AddVMCommand(ctx, icLdc_i4, internal_type->id(), 0, internal_token_reference);
AddVMCommand(ctx, icConv, 0);
break;
case icConv_ovf_i:
case icConv_ovf_u:
case icConv_ovf_i1:
case icConv_ovf_u1:
case icConv_ovf_i2:
case icConv_ovf_u2:
case icConv_ovf_i4:
case icConv_ovf_u4:
case icConv_ovf_i8:
case icConv_ovf_u8:
AddVMCommand(ctx, icLdc_i4, internal_type->id(), 0, internal_token_reference);
AddVMCommand(ctx, icConv_ovf, 0);
break;
case icConv_ovf_i_un:
case icConv_ovf_u_un:
case icConv_ovf_i1_un:
case icConv_ovf_u1_un:
case icConv_ovf_i2_un:
case icConv_ovf_u2_un:
case icConv_ovf_i4_un:
case icConv_ovf_u4_un:
case icConv_ovf_i8_un:
case icConv_ovf_u8_un:
case icConv_r_un:
AddVMCommand(ctx, icLdc_i4, internal_type->id(), 0, internal_token_reference);
AddVMCommand(ctx, icConv_ovf_un, 0);
break;
case icRem:
AddVMCommand(ctx, icRem, 0);
break;
case icRem_un:
AddVMCommand(ctx, icRem_un, 0);
break;
case icAdd:
AddVMCommand(ctx, icAdd, 0);
break;
case icSub:
AddVMCommand(ctx, icSub, 0);
break;
case icDiv:
AddVMCommand(ctx, icDiv, 0);
break;
case icDiv_un:
AddVMCommand(ctx, icDiv_un, 0);
break;
case icMul:
AddVMCommand(ctx, icMul, 0);
break;
case icAnd:
AddVMCommand(ctx, icAnd, 0);
break;
case icOr:
AddVMCommand(ctx, icOr, 0);
break;
case icXor:
AddVMCommand(ctx, icXor, 0);
break;
case icShl:
AddVMCommand(ctx, icShl, 0);
break;
case icShr:
AddVMCommand(ctx, icShr, 0);
break;
case icShr_un:
AddVMCommand(ctx, icShr_un, 0);
break;
case icNeg:
AddVMCommand(ctx, icNeg, 0);
break;
case icNot:
AddVMCommand(ctx, icNot, 0);
break;
case icAdd_ovf:
AddVMCommand(ctx, icAdd_ovf, 0);
break;
case icAdd_ovf_un:
AddVMCommand(ctx, icAdd_ovf_un, 0);
break;
case icMul_ovf:
AddVMCommand(ctx, icMul_ovf, 0);
break;
case icMul_ovf_un:
AddVMCommand(ctx, icMul_ovf_un, 0);
break;
case icSub_ovf:
AddVMCommand(ctx, icSub_ovf, 0);
break;
case icSub_ovf_un:
AddVMCommand(ctx, icSub_ovf_un, 0);
break;
case icCeq:
AddCmpSection(ctx, icCeq);
break;
case icClt:
AddCmpSection(ctx, icClt);
break;
case icClt_un:
AddCmpSection(ctx, icClt_un);
break;
case icCgt:
AddCmpSection(ctx, icCgt);
break;
case icCgt_un:
AddCmpSection(ctx, icCgt_un);
break;
case icCall:
if (section_options_ & rtLinkedFrom) {
AddVMCommand(ctx, icLdc_i4, 0, voLinkCommand);
AddVMCommand(ctx, icCallvm, 0);
}
else {
AddVMCommand(ctx, icLdc_i4, operand_value_, 0, token_reference_);
AddVMCommand(ctx, icCall, 0);
}
break;
case icCallvirt:
if (section_options_ & rtLinkedFrom) {
AddVMCommand(ctx, icLdc_i4, 0, voLinkCommand);
AddVMCommand(ctx, icCallvmvirt, 0);
}
else {
AddVMCommand(ctx, icLdc_i4, operand_value_, 0, token_reference_);
AddVMCommand(ctx, icCallvirt, 0);
}
break;
case icNewobj:
AddVMCommand(ctx, icLdc_i4, operand_value_, 0, token_reference_);
AddVMCommand(ctx, icNewobj, 0);
break;
case icNewarr:
AddVMCommand(ctx, icLdc_i4, operand_value_, 0, token_reference_);
AddVMCommand(ctx, icNewarr, 0);
break;
case icInitobj:
AddVMCommand(ctx, icLdc_i4, operand_value_, 0, token_reference_);
AddVMCommand(ctx, icInitobj, 0);
break;
case icConstrained:
AddVMCommand(ctx, icLdc_i4, operand_value_, 0, token_reference_);
AddVMCommand(ctx, icConstrained, 0);
break;
case icStelem_i:
case icStelem_i1:
case icStelem_i2:
case icStelem_i4:
case icStelem_i8:
case icStelem_r4:
case icStelem_r8:
case icStelem_ref:
AddVMCommand(ctx, icLdc_i4, internal_type->id(), 0, internal_token_reference);
AddVMCommand(ctx, icStelem_ref, 0);
break;
case icStelem:
AddVMCommand(ctx, icLdc_i4, operand_value_, 0, token_reference_);
AddVMCommand(ctx, icStelem_ref, 0);
break;
case icLdelem_i:
case icLdelem_i1:
case icLdelem_u1:
case icLdelem_i2:
case icLdelem_u2:
case icLdelem_i4:
case icLdelem_u4:
case icLdelem_i8:
case icLdelem_r4:
case icLdelem_r8:
case icLdelem_ref:
AddVMCommand(ctx, icLdc_i4, internal_type->id(), 0, internal_token_reference);
AddVMCommand(ctx, icLdelem_ref, 0);
break;
case icLdelem:
AddVMCommand(ctx, icLdc_i4, operand_value_, 0, token_reference_);
AddVMCommand(ctx, icLdelem_ref, 0);
break;
case icLdelema:
AddVMCommand(ctx, icLdelema, 0);
break;
case icLdlen:
AddVMCommand(ctx, icLdlen, 0);
break;
case icLdfld:
AddVMCommand(ctx, icLdc_i4, operand_value_, 0, token_reference_);
AddVMCommand(ctx, icLdfld, 0);
break;
case icLdsfld:
AddVMCommand(ctx, icLdnull, 0);
AddVMCommand(ctx, icLdc_i4, operand_value_, 0, token_reference_);
AddVMCommand(ctx, icLdfld, 0);
break;
case icLdflda:
AddVMCommand(ctx, icLdc_i4, operand_value_, 0, token_reference_);
AddVMCommand(ctx, icLdflda, 0);
break;
case icLdsflda:
AddVMCommand(ctx, icLdnull, 0);
AddVMCommand(ctx, icLdc_i4, operand_value_, 0, token_reference_);
AddVMCommand(ctx, icLdflda, 0);
break;
case icStfld:
AddVMCommand(ctx, icLdc_i4, operand_value_, 0, token_reference_);
AddVMCommand(ctx, icStfld, 0);
break;
case icStsfld:
AddVMCommand(ctx, icLdc_i4, operand_value_, 0, token_reference_);
AddVMCommand(ctx, icStsfld, 0);
break;
case icLdstr:
AddVMCommand(ctx, icLdc_i4, operand_value_, 0, token_reference_);
AddVMCommand(ctx, icLdstr, 0);
break;
case icLdftn:
AddVMCommand(ctx, icLdc_i4, operand_value_, 0, token_reference_);
AddVMCommand(ctx, icLdftn, 0);
break;
case icLdvirtftn:
AddVMCommand(ctx, icLdc_i4, operand_value_, 0, token_reference_);
AddVMCommand(ctx, icLdvirtftn, 0);
break;
case icStind_i:
case icStind_i1:
case icStind_i2:
case icStind_i4:
case icStind_i8:
case icStind_r4:
case icStind_r8:
case icStind_ref:
AddVMCommand(ctx, icLdc_i4, internal_type->id(), 0, internal_token_reference);
AddVMCommand(ctx, icStind_ref, 0);
break;
case icStobj:
AddVMCommand(ctx, icLdc_i4, operand_value_, 0, token_reference_);
AddVMCommand(ctx, icStind_ref, 0);
break;
case icLdind_i:
case icLdind_i1:
case icLdind_i2:
case icLdind_i4:
case icLdind_i8:
case icLdind_u1:
case icLdind_u2:
case icLdind_u4:
case icLdind_r4:
case icLdind_r8:
case icLdind_ref:
AddVMCommand(ctx, icLdc_i4, internal_type->id(), 0, internal_token_reference);
AddVMCommand(ctx, icLdind_ref, 0);
break;
case icLdobj:
AddVMCommand(ctx, icLdc_i4, operand_value_, 0, token_reference_);
AddVMCommand(ctx, icLdind_ref, 0);
break;
case icPop:
AddVMCommand(ctx, icPop, 0);
break;
case icDup:
AddVMCommand(ctx, icDup, 0);
break;
case icBox:
AddVMCommand(ctx, icLdc_i4, operand_value_, 0, token_reference_);
AddVMCommand(ctx, icBox, 0);
break;
case icUnbox:
AddVMCommand(ctx, icLdc_i4, operand_value_, 0, token_reference_);
AddVMCommand(ctx, icUnbox, 0);
break;
case icUnbox_any:
AddVMCommand(ctx, icLdc_i4, operand_value_, 0, token_reference_);
AddVMCommand(ctx, icUnbox_any, 0);
break;
case icLdtoken:
AddVMCommand(ctx, icLdc_i4, operand_value_, 0, token_reference_);
AddVMCommand(ctx, icLdtoken, 0);
break;
case icBr:
case icBr_s:
AddVMCommand(ctx, icLdc_i4, 0, voLinkCommand);
AddVMCommand(ctx, icBr, 0);
break;
case icBeq:
case icBeq_s:
AddCmpSection(ctx, icBeq);
AddJmpWithFlagSection(ctx, true);
break;
case icBne_un:
case icBne_un_s:
AddCmpSection(ctx, icBne_un);
AddJmpWithFlagSection(ctx, true);
break;
case icBlt:
case icBlt_s:
AddCmpSection(ctx, icBlt);
AddJmpWithFlagSection(ctx, true);
break;
case icBlt_un:
case icBlt_un_s:
AddCmpSection(ctx, icBlt_un);
AddJmpWithFlagSection(ctx, true);
break;
case icBle:
case icBle_s:
AddCmpSection(ctx, icBle);
AddJmpWithFlagSection(ctx, true);
break;
case icBle_un:
case icBle_un_s:
AddCmpSection(ctx, icBle_un);
AddJmpWithFlagSection(ctx, true);
break;
case icBgt:
case icBgt_s:
AddCmpSection(ctx, icBgt);
AddJmpWithFlagSection(ctx, true);
break;
case icBgt_un:
case icBgt_un_s:
AddCmpSection(ctx, icBgt_un);
AddJmpWithFlagSection(ctx, true);
break;
case icBge:
case icBge_s:
AddCmpSection(ctx, icBge);
AddJmpWithFlagSection(ctx, true);
break;
case icBge_un:
case icBge_un_s:
AddCmpSection(ctx, icBge_un);
AddJmpWithFlagSection(ctx, true);
break;
case icBrtrue:
case icBrtrue_s:
AddJmpWithFlagSection(ctx, true);
break;
case icBrfalse:
case icBrfalse_s:
AddJmpWithFlagSection(ctx, false);
break;
case icLeave:
case icLeave_s:
AddVMCommand(ctx, icLdc_i4, static_cast<uint32_t>(operand_value_ - ctx.file->image_base()));
AddVMCommand(ctx, icLdc_i4, 0, voLinkCommand);
AddVMCommand(ctx, icLeave, 0);
break;
case icSwitch:
AddVMCommand(ctx, icDup, 0);
AddVMCommand(ctx, icLdc_i4, operand_value_);
AddCmpSection(ctx, icBlt_un);
AddJmpWithFlagSection(ctx, true);
AddVMCommand(ctx, icPop, 0, voLinkCommand);
AddVMCommand(ctx, icLdc_i4, 0, voLinkCommand);
AddVMCommand(ctx, icBr, 0);
AddVMCommand(ctx, icLdc_i4, 2, voLinkCommand);
AddVMCommand(ctx, icShl, 0);
AddVMCommand(ctx, icLdc_i4, 0, voLinkCommand);
AddVMCommand(ctx, icAdd, 0);
AddVMCommand(ctx, icLdmem_i4, 0);
AddVMCommand(ctx, icBr, 0);
break;
case icCase:
AddVMCommand(ctx, icDword, 0, voLinkCommand);
break;
case icEndfinally:
AddVMCommand(ctx, icEndfinally, 0);
break;
case icEndfilter:
AddVMCommand(ctx, icEndfilter, 0);
break;
case icRet:
if (operand_value_) {
AddVMCommand(ctx, icLdc_i4, operand_value_, 0, token_reference_);
AddVMCommand(ctx, icBox, 0);
}
else
AddVMCommand(ctx, icLdnull, 0);
AddVMCommand(ctx, icLdc_i4, 0);
if ((ctx.options.flags & cpMemoryProtection) && owner()->tag() != ftLoader) {
ILVMCommand *vm_command = AddVMCommand(ctx, icLdc_i4, 0);
uint64_t address = ctx.runtime->export_list()->GetAddressByType(atRandom);
ICommand *to_command = ctx.file->function_list()->GetCommandByAddress(address, true);
internal_links_.Add(vlNone, vm_command, to_command);
AddVMCommand(ctx, icCallvm, 0);
AddVMCommand(ctx, icLdc_i4, rand32());
AddVMCommand(ctx, icAdd, 0);
vm_command = AddVMCommand(ctx, icLdc_i4, 0);
internal_links_.Add(vlCRCTableCount, vm_command, NULL);
AddVMCommand(ctx, icRem_un, 0);
AddVMCommand(ctx, icLdc_i4, sizeof(CRCInfo::POD));
AddVMCommand(ctx, icMul, 0);
vm_command = AddVMCommand(ctx, icLdc_i4, 0);
internal_links_.Add(vlCRCTableAddress, vm_command, NULL);
AddVMCommand(ctx, icAdd, 0);
AddVMCommand(ctx, icStarg, param_);
AddVMCommand(ctx, icLdarg, param_);
AddVMCommand(ctx, icLdmem_i4, 0);
AddCryptorSection(ctx, ctx.file->function_list()->crc_cryptor(), true);
AddVMCommand(ctx, icLdarg, param_);
AddVMCommand(ctx, icLdc_i4, offsetof(CRCInfo::POD, size));
AddVMCommand(ctx, icAdd, 0);
AddVMCommand(ctx, icLdmem_i4, 0);
AddCryptorSection(ctx, ctx.file->function_list()->crc_cryptor(), true);
vm_command = AddVMCommand(ctx, icLdc_i4, 0);
address = ctx.runtime->export_list()->GetAddressByType(atCalcCRC);
to_command = ctx.file->function_list()->GetCommandByAddress(address, true);
internal_links_.Add(vlNone, vm_command, to_command);
AddVMCommand(ctx, icCallvm, 0);
AddVMCommand(ctx, icLdarg, param_);
AddVMCommand(ctx, icLdc_i4, offsetof(CRCInfo::POD, hash));
AddVMCommand(ctx, icAdd, 0);
AddVMCommand(ctx, icLdmem_i4, 0);
AddVMCommand(ctx, icAdd, 0);
AddVMCommand(ctx, icAdd, 0);
}
AddVMCommand(ctx, icBr, 0);
break;
case icThrow:
AddVMCommand(ctx, icThrow, 0);
break;
case icRethrow:
AddVMCommand(ctx, icRethrow, 0);
break;
case icCastclass:
AddVMCommand(ctx, icLdc_i4, operand_value_, 0, token_reference_);
AddVMCommand(ctx, icCastclass, 0);
break;
case icIsinst:
AddVMCommand(ctx, icLdc_i4, operand_value_, 0, token_reference_);
AddVMCommand(ctx, icIsinst, 0);
break;
case icCkfinite:
AddVMCommand(ctx, icCkfinite, 0);
break;
case icLocalloc:
AddVMCommand(ctx, icLocalloc, 0);
break;
case icSizeof:
AddVMCommand(ctx, icLdc_i4, operand_value_, 0, token_reference_);
AddVMCommand(ctx, icSizeof, 0);
break;
default:
throw std::runtime_error("Runtime error at CompileToVM: " + text());
}
}
void ILCommand::AddExtSection(const CompileContext &ctx)
{
ext_vm_entry_ = AddVMCommand(ctx, icLdc_i4, 0);
AddVMCommand(ctx, icPop, 0);
}
void ILCommand::AddCryptorSection(const CompileContext &ctx, ValueCryptor *cryptor, bool is_decrypt)
{
if (!cryptor)
return;
CompileContext new_ctx = ctx;
new_ctx.options.flags &= ~cpMemoryProtection;
for (size_t i = 0; i < cryptor->count(); i++) {
ValueCommand *value_command = cryptor->item(i);
AddVMCommand(new_ctx, icLdc_i4, value_command->value());
switch (value_command->type(is_decrypt)) {
case ccDec:
AddVMCommand(new_ctx, icSub, 0);
break;
case ccInc:
AddVMCommand(new_ctx, icAdd, 0);
break;
case ccSub:
AddVMCommand(new_ctx, icSub, 0);
break;
case ccAdd:
AddVMCommand(new_ctx, icAdd, 0);
break;
case ccXor:
AddVMCommand(new_ctx, icXor, 0);
break;
default:
throw 1;
}
}
}
/**
* ILVMCommand
*/
ILVMCommand::ILVMCommand(ILCommand *owner, ILCommandType command_type, uint64_t value, TokenReference *token_reference)
: BaseVMCommand(owner), command_type_(command_type), value_(value), token_reference_(token_reference), address_(0),
crypt_command_(icUnknown), crypt_size_(osDWord), crypt_key_(0), link_command_(NULL)
{
}
void ILVMCommand::Compile()
{
reinterpret_cast<ILVirtualMachine *>(owner()->block()->virtual_machine())->CompileCommand(*this);
}
void ILVMCommand::WriteToFile(IArchitecture &file)
{
if (!dump_.size())
return;
file.Write(dump_.data(), dump_.size());
}
/**
* ILFunction
*/
ILFunction::ILFunction(IFunctionList *owner, const FunctionName &name, CompilationType compilation_type, uint32_t compilation_options, bool need_compile, Folder *folder)
: BaseFunction(owner, name, compilation_type, compilation_options, need_compile, folder)
{
}
ILFunction::ILFunction(IFunctionList *owner /*= NULL*/)
: BaseFunction(owner, FunctionName(""), ctVirtualization, 0, true, NULL)
{
}
ILFunction::ILFunction(IFunctionList *owner, OperandSize cpu_address_size, IFunction *parent)
: BaseFunction(owner, cpu_address_size, parent)
{
}
ILFunction::ILFunction(IFunctionList *owner, const ILFunction &src)
: BaseFunction(owner, src)
{
}
bool ILFunction::Prepare(const CompileContext &ctx)
{
size_t i, j;
if (type() == otString) {
IArchitecture *file = from_runtime() ? ctx.runtime : ctx.file;
MapFunction *map_function = file->map_function_list()->GetFunctionByAddress(address());
if (map_function) {
uint64_t address = ctx.runtime->export_list()->GetAddressByType(atDecryptStringA);
if (!address)
return false;
NETRuntimeFunctionList *runtime_function_list = reinterpret_cast<NETRuntimeFunctionList *>(ctx.file->runtime_function_list());
ILMetaData *meta = reinterpret_cast<ILMetaData *>(ctx.runtime->command_list());
ILMethodDef *decrypt_method = meta->GetMethod(address);
if (!decrypt_method)
return false;
ILFunction *decrypt_func = reinterpret_cast<ILFunction*>(ctx.runtime->function_list()->GetFunctionByAddress(address));
if (!decrypt_func)
return false;
size_t orig_count = count();
ILTable *table = meta->table(ttMethodDef);
for (i = 0; i < orig_count; i++) {
ILMethodDef *method = reinterpret_cast<ILMethodDef*>(decrypt_method->Clone(meta, table));
method->set_deleted(false);
method->declaring_type()->AddMethod(method);
size_t old_count = count();
for (j = 0; j < decrypt_func->count(); j++) {
ILCommand *src_command = decrypt_func->item(j);
ILCommand *dst_command = reinterpret_cast<ILCommand*>(src_command->Clone(this));
dst_command->set_address(0);
if (static_cast<uint32_t>(dst_command->operand_value()) == FACE_STORAGE_INFO)
dst_command->set_operand_value(0, item(i)->address() - ctx.file->image_base());
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);
link_list()->AddObject(dst_link);
if (src_link->parent_command())
dst_link->set_parent_command(GetCommandByAddress(src_link->parent_command()->address()));
}
if (dst_command->token_reference()) {
TokenReference *token_reference = dst_command->token_reference()->Clone(dst_command->token_reference()->owner());
token_reference->owner()->AddObject(token_reference);
dst_command->set_token_reference(token_reference);
}
}
for (j = 0; j < decrypt_func->function_info_list()->count(); j++) {
FunctionInfo *src_info = decrypt_func->function_info_list()->item(j);
FunctionInfo *dst_info = src_info->Clone(function_info_list());
function_info_list()->AddObject(dst_info);
if (dst_info->entry())
dst_info->set_entry(item(old_count + decrypt_func->IndexOf(dst_info->entry())));
dst_info->set_source(runtime_function_list->Add(0, 0, 0, method));
}
AddressRange *address_range = function_info_list()->item(0)->Add(0, 0, NULL, NULL, NULL);
for (j = old_count; j < count(); j++) {
ILCommand *command = item(j);
command->set_address_range(address_range);
command->CompileToNative();
}
ILCommand *src_command = item(i);
for (j = 0; j < map_function->reference_list()->count(); j++) {
Reference *reference = map_function->reference_list()->item(j);
if (reference->operand_address() != src_command->address())
continue;
address = reference->address();
ILCommand *command = reinterpret_cast<ILCommand *>(ctx.file->function_list()->GetCommandByAddress(address, true));
if (!command) {
if (!ctx.file->AddressSeek(address))
return false;
CommandBlock *block = AddBlock(count(), true);
block->set_address(address);
command = Add(address);
command->ReadFromFile(*file);
command->set_block(block);
command->exclude_option(roClearOriginalCode);
}
if (command->token_reference())
command->token_reference()->set_deleted(true);
command->Init(icCall, method->id());
command->set_token_reference(method->reference_list()->Add(address + 1));
command->CompileToNative();
}
}
}
}
else {
for (i = 0; i < function_info_list()->count(); i++) {
FunctionInfo *info = function_info_list()->item(i);
if (!info->source())
continue;
std::map<size_t, size_t> variable_map;
NETRuntimeFunction *runtime_func = reinterpret_cast<NETRuntimeFunction *>(info->source());
ILStandAloneSig *locals = runtime_func->method()->locals();
std::vector<ILMethodDef *> method_list = runtime_func->method_list();
if (locals) {
if (locals->reference_list()->count() > 1) {
ILStandAloneSig *old_locals = locals;
locals = locals->Clone(locals->meta(), locals->owner());
locals->owner()->AddObject(locals);
locals->reference_list()->clear();
for (j = 0; j < method_list.size(); j++) {
method_list[j]->set_locals(locals);
}
for (j = old_locals->reference_list()->count(); j > 0; j--) {
TokenReference *token_reference = old_locals->reference_list()->item(j - 1);
if (item(IndexOf(info->entry()) + 1)->token_reference() == token_reference)
token_reference->set_owner(locals->reference_list());
}
}
}
else if (compilation_type() != ctVirtualization) {
ILData data;
data.push_back(stLocal);
data.push_back(0);
locals = runtime_func->method()->meta()->AddStandAloneSig(data);
for (j = 0; j < method_list.size(); j++) {
method_list[j]->set_locals(locals);
}
ILCommand *command = new ILCommand(this, osDWord, icComment, 0);
size_t insert_index = IndexOf(info->entry()) + 1;
InsertObject(insert_index, command);
command->set_token_reference(locals->reference_list()->Add(0));
command->set_address_range(info->entry()->address_range());
uint32_t dump = 0;
command->set_dump(&dump, sizeof(dump));
for (j = 0; j < block_list()->count(); j++) {
CommandBlock *block = block_list()->item(j);
if (block->start_index() >= insert_index) {
block->set_start_index(block->start_index() + 1);
block->set_end_index(block->end_index() + 1);
}
}
}
else
continue;
if (compilation_type() != ctMutation)
locals->set_deleted(true);
ILSignature *signature = locals->signature();
size_t old_count = signature->count();
ILElement *random_variable = new ILElement(locals->meta(), signature);
{
ILData data;
data.push_back(ELEMENT_TYPE_U4);
random_variable->Parse(data);
}
random_variable->set_is_predicate(true);
signature->AddObject(random_variable);
std::vector<ILElement *> element_list;
std::vector<size_t> index_list;
while (signature->count()) {
ILElement *element = signature->item(0);
signature->RemoveObject(element);
index_list.push_back(element_list.size());
element_list.push_back(element);
}
for (j = 0; j < index_list.size(); j++) {
std::swap(index_list[j], index_list[rand() % index_list.size()]);
}
for (j = 0; j < index_list.size(); j++) {
size_t old_index = index_list[j];
if (old_index < old_count)
variable_map[old_index] = j;
signature->AddObject(element_list[old_index]);
}
if (variable_map.empty())
continue;
std::map<size_t, size_t>::const_iterator it;
for (j = IndexOf(info->entry()) + 2; j < count(); j++) {
ILCommand *command = item(j);
switch (command->type()) {
case icLdloc:
case icLdloc_s:
it = variable_map.find(static_cast<uint16_t>(command->operand_value()));
if (it == variable_map.end())
throw std::runtime_error("Invalid variable index");
command->Init(icLdloc, it->second);
command->CompileToNative();
break;
case icLdloca:
case icLdloca_s:
it = variable_map.find(static_cast<uint16_t>(command->operand_value()));
if (it == variable_map.end())
throw std::runtime_error("Invalid variable index");
command->Init(icLdloca, it->second);
command->CompileToNative();
break;
case icStloc:
case icStloc_s:
it = variable_map.find(static_cast<uint16_t>(command->operand_value()));
if (it == variable_map.end())
throw std::runtime_error("Invalid variable index");
command->Init(icStloc, it->second);
command->CompileToNative();
break;
case icLdloc_0:
it = variable_map.find(0);
if (it == variable_map.end())
throw std::runtime_error("Invalid variable index");
command->Init(icLdloc, it->second);
command->CompileToNative();
break;
case icLdloc_1:
it = variable_map.find(1);
if (it == variable_map.end())
throw std::runtime_error("Invalid variable index");
command->Init(icLdloc, it->second);
command->CompileToNative();
break;
case icLdloc_2:
it = variable_map.find(2);
if (it == variable_map.end())
throw std::runtime_error("Invalid variable index");
command->Init(icLdloc, it->second);
command->CompileToNative();
break;
case icLdloc_3:
it = variable_map.find(3);
if (it == variable_map.end())
throw std::runtime_error("Invalid variable index");
command->Init(icLdloc, it->second);
command->CompileToNative();
break;
case icStloc_0:
it = variable_map.find(0);
if (it == variable_map.end())
throw std::runtime_error("Invalid variable index");
command->Init(icStloc, it->second);
command->CompileToNative();
break;
case icStloc_1:
it = variable_map.find(1);
if (it == variable_map.end())
throw std::runtime_error("Invalid variable index");
command->Init(icStloc, it->second);
command->CompileToNative();
break;
case icStloc_2:
it = variable_map.find(2);
if (it == variable_map.end())
throw std::runtime_error("Invalid variable index");
command->Init(icStloc, it->second);
command->CompileToNative();
break;
case icStloc_3:
it = variable_map.find(3);
if (it == variable_map.end())
throw std::runtime_error("Invalid variable index");
command->Init(icStloc, it->second);
command->CompileToNative();
break;
}
if (command->is_data() || command->type() == icComment)
break;
}
}
}
if (tag() == ftProcessor) {
if (ctx.runtime)
return true;
}
return BaseFunction::Prepare(ctx);
}
void ILFunction::CompileLinks(const CompileContext &ctx)
{
BaseFunction::CompileLinks(ctx);
}
void ILFunction::CompileInfo(const CompileContext &ctx)
{
BaseFunction::CompileInfo(ctx);
size_t i;
FunctionInfo *info;
AddressRange *range;
ILCommand *command;
for (i = 0; i < function_info_list()->count(); i++) {
info = function_info_list()->item(i);
if (!info->begin())
continue;
if (info->entry()) {
uint32_t code_size = static_cast<uint32_t>(info->end() - info->begin());
command = reinterpret_cast<ILCommand *>(info->entry());
Data data;
for (size_t k = 0; k < command->dump_size(); k++) {
data.PushByte(command->dump(k));
}
if (command->dump_size() == 1) {
code_size--;
data[0] = CorILMethod_TinyFormat | (code_size << CorILMethod_FormatShift);
} else {
code_size -= (data[1] >> 4) * sizeof(uint32_t);
data.WriteDWord(offsetof(IMAGE_COR_ILMETHOD_FAT, CodeSize), code_size);
}
command->set_dump(data.data(), data.size());
}
}
for (i = 0; i < range_list()->count(); i++) {
range = range_list()->item(i);
info = function_info_list()->GetItemByAddress(range->begin());
if (!info)
continue;
uint64_t base_value = info->begin() + info->base_value();
if (range->begin_entry()) {
command = reinterpret_cast<ILCommand *>(range->begin_entry());
command->set_operand_value(0, range->begin() - base_value);
command->CompileToNative();
}
if (range->size_entry()) {
command = reinterpret_cast<ILCommand *>(range->size_entry());
command->set_operand_value(0, range->end() - range->begin());
command->CompileToNative();
}
}
}
void ILFunction::ReadFromBuffer(Buffer &buffer, IArchitecture &file)
{
BaseFunction::ReadFromBuffer(buffer, file);
}
void ILFunction::ParseBeginCommands(IArchitecture &)
{
}
void ILFunction::ParseEndCommands(IArchitecture &file)
{
if (type() != otString) {
size_t i;
size_t use_address_count = 0;
for (i = 0; i < file.map_function_list()->count(); i++) {
if (file.map_function_list()->item(i)->address() == address()) {
use_address_count++;
}
}
if (use_address_count > 1) {
for (i = 0; i < count(); i++) {
item(i)->exclude_option(roClearOriginalCode);
}
}
}
}
void ILFunction::CreateBlocks()
{
CommandBlock *cur_block = NULL;
for (size_t i = 0; i < count(); i++) {
ILCommand *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->is_end())
cur_block = NULL;
}
}
void ILFunction::CalcStack(std::map<ILCommand *, int> &stack_map)
{
size_t i, j;
ILCommand *command, *entry, *link_command;
std::set<ILCommand *> entry_stack, link_list;
for (i = 0; i < function_info_list()->count(); i++) {
FunctionInfo *info = function_info_list()->item(i);
if (!info->source())
continue;
entry = reinterpret_cast<ILCommand *>(info->entry());
entry_stack.insert(entry);
stack_map[entry] = 0;
}
for (i = 0; i < this->link_list()->count(); i++) {
CommandLink *link = this->link_list()->item(i);
switch (link->type()) {
case ltSEHBlock:
entry = reinterpret_cast<ILCommand *>(link->to_command());
entry_stack.insert(entry);
stack_map[entry] = 1;
break;
case ltFinallyBlock:
entry = reinterpret_cast<ILCommand *>(link->to_command());
entry_stack.insert(entry);
stack_map[entry] = 0;
break;
}
}
int stack;
while (!entry_stack.empty()) {
entry = *entry_stack.begin();
j = IndexOf(entry);
std::map<ILCommand *, int>::const_iterator s = stack_map.find(entry);
if (s == stack_map.end())
throw std::runtime_error("Incorrect stack");
stack = s->second;
for (i = j; i < count(); i++) {
command = item(i);
std::set<ILCommand *>::const_iterator c = entry_stack.find(command);
if (c != entry_stack.end())
entry_stack.erase(c);
if (command->type() == icComment || command->type() == icCase || command->is_data())
continue;
s = stack_map.find(command);
if (s != stack_map.end()) {
if (s->second != stack)
throw std::runtime_error("Incorrect stack");
}
else
stack_map[command] = stack;
stack += command->GetStackLevel();
link_list.clear();
if (command->type() == icSwitch) {
size_t case_count = static_cast<uint32_t>(command->operand_value());
for (j = 0; j < case_count; j++) {
ILCommand *case_command = item(i + 1 + j);
link_list.insert(reinterpret_cast<ILCommand *>(case_command->link()->to_command()));
}
}
else {
if (command->link() && (command->link()->type() == ltJmp || command->link()->type() == ltJmpWithFlag))
link_list.insert(reinterpret_cast<ILCommand *>(command->link()->to_command()));
}
for (std::set<ILCommand *>::const_iterator l = link_list.begin(); l != link_list.end(); l++) {
link_command = *l;
s = stack_map.find(link_command);
if (s != stack_map.end()) {
if (s->second != stack)
throw std::runtime_error("Incorrect stack");
}
else {
entry_stack.insert(link_command);
stack_map[link_command] = stack;
}
}
if (command->is_end())
break;
}
}
}
void ILFunction::Mutate(const CompileContext &ctx)
{
size_t i, j, index;
ILCommand *command, *insert_command, *entry;
std::map<ILCommand *, ILSignature *> variables_map;
uint32_t value, old_value, bit_mask;
std::map<ILCommand *, int> stack_map;
for (i = 0; i < function_info_list()->count(); i++) {
FunctionInfo *info = function_info_list()->item(i);
if (!info->source())
continue;
ILStandAloneSig *locals = reinterpret_cast<NETRuntimeFunction *>(info->source())->method()->locals();
entry = reinterpret_cast<ILCommand *>(info->entry());
variables_map[entry] = locals ? locals->signature() : NULL;
stack_map[entry] = 0;
}
CalcStack(stack_map);
int stack;
std::list<ICommand *> new_command_list;
std::vector<ILCommand *> insert_command_list;
std::vector<size_t> predicate_list;
std::map<size_t, uint32_t> value_list;
std::map<ILCommand *, std::map<size_t, uint32_t> > value_list_map;
ILSignature *variables = NULL;
size_t orig_count = count();
std::vector<CommandLink *> insert_link_list;
for (i = 0; i < orig_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;
if (command->block()) {
CommandBlock *block = command->block();
size_t insert_count = new_command_list.size() - 1 - i;
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;
std::map<ILCommand *, ILSignature *>::const_iterator it = variables_map.find(command);
if (it != variables_map.end()) {
predicate_list.clear();
variables = it->second;
if (variables) {
for (j = 0; j < variables->count(); j++) {
ILElement *variable = variables->item(j);
if (variable->is_predicate())
predicate_list.push_back(j);
}
}
}
if (command->type() == icComment || command->type() == icCase || command->is_data())
continue;
insert_command_list.clear();
new_command_list.pop_back();
AddressRange *address_range = command->address_range();
ILCommand *link_command = (command->link() && (command->link()->type() == ltJmp || command->link()->type() == ltJmpWithFlag)) ? reinterpret_cast<ILCommand *>(command->link()->to_command()) : NULL;
if (command->section_options() & (rtLinkedToInt | rtLinkedToExt)) {
std::map<size_t, uint32_t> dst_value_list;
if ((command->section_options() & rtLinkedToExt) == 0) {
std::map<ILCommand *, std::map<size_t, uint32_t> >::iterator it = value_list_map.find(command);
if (it != value_list_map.end()) {
dst_value_list = it->second;
if (!new_command_list.empty() && !new_command_list.back()->is_end()) {
for (std::map<size_t, uint32_t>::const_iterator d = dst_value_list.begin(); d != dst_value_list.end(); d++) {
index = d->first;
value = d->second;
std::map<size_t, uint32_t>::const_iterator v = value_list.find(index);
if (v == value_list.end()) {
insert_command_list.push_back(AddCommand(icLdc_i4, value));
}
else {
insert_command_list.push_back(AddCommand(icLdloc, index));
old_value = v->second;
if (rand() & 1) {
insert_command_list.push_back(AddCommand(icLdc_i4, value - old_value));
insert_command_list.push_back(AddCommand(icAdd, 0));
}
else {
insert_command_list.push_back(AddCommand(icLdc_i4, value ^ old_value));
insert_command_list.push_back(AddCommand(icXor, 0));
}
}
insert_command_list.push_back(AddCommand(icStloc, index));
}
}
for (j = 0; j < insert_command_list.size(); j++) {
insert_command = insert_command_list[j];
insert_command->set_address_range(address_range);
insert_command->CompileToNative();
insert_command->include_option(roNoProgress);
new_command_list.push_back(insert_command);
}
if (!insert_command_list.empty()) {
insert_command = insert_command_list[0];
for (j = 0; j < link_list()->count(); j++) {
CommandLink *link = link_list()->item(j);
if (link->next_command() == command)
link->set_next_command(insert_command);
}
}
insert_command_list.clear();
}
else if (!value_list.empty()) {
value_list_map[command] = value_list;
dst_value_list = value_list;
}
}
value_list = dst_value_list;
}
if (!predicate_list.empty() && !command->is_end()) {
if (rand() & 1) {
// modify predicate
value = rand32();
bit_mask = 0x1f;
index = predicate_list[rand() % predicate_list.size()];
std::map<size_t, uint32_t>::const_iterator it = value_list.find(index);
if (it != value_list.end()) {
old_value = it->second;
if (rand() & 1) {
insert_command_list.push_back(AddCommand(icLdc_i4, value));
insert_command_list.push_back(AddCommand(icLdloc, index));
}
else {
insert_command_list.push_back(AddCommand(icLdloc, index));
insert_command_list.push_back(AddCommand(icLdc_i4, value));
std::swap(value, old_value);
}
switch (rand() % (8 + (old_value != 0 ? 2 : 0))) {
case 0:
value += old_value;
insert_command_list.push_back(AddCommand(icAdd, 0));
break;
case 1:
value -= old_value;
insert_command_list.push_back(AddCommand(icSub, 0));
break;
case 2:
old_value &= bit_mask;
if (insert_command_list.back()->type() == icLdc_i4)
insert_command_list.back()->set_operand_value(0, old_value);
else {
insert_command_list.push_back(AddCommand(icLdc_i4, bit_mask));
insert_command_list.push_back(AddCommand(icAnd, 0));
}
value >>= old_value;
insert_command_list.push_back(AddCommand(icShr_un, 0));
break;
case 3:
old_value &= bit_mask;
if (insert_command_list.back()->type() == icLdc_i4)
insert_command_list.back()->set_operand_value(0, old_value);
else {
insert_command_list.push_back(AddCommand(icLdc_i4, bit_mask));
insert_command_list.push_back(AddCommand(icAnd, 0));
}
value <<= old_value;
insert_command_list.push_back(AddCommand(icShl, 0));
break;
case 4:
value |= old_value;
insert_command_list.push_back(AddCommand(icOr, 0));
break;
case 5:
value &= old_value;
insert_command_list.push_back(AddCommand(icAnd, 0));
break;
case 6:
value *= old_value;
insert_command_list.push_back(AddCommand(icMul, 0));
break;
case 8:
value /= old_value;
insert_command_list.push_back(AddCommand(icDiv_un, 0));
break;
case 9:
value %= old_value;
insert_command_list.push_back(AddCommand(icRem_un, 0));
break;
default:
value ^= old_value;
insert_command_list.push_back(AddCommand(icXor, 0));
break;
}
}
else {
insert_command_list.push_back(AddCommand(icLdc_i4, value));
}
insert_command_list.push_back(AddCommand(icStloc, index));
value_list[index] = value;
}
}
if (!value_list.empty()) {
index = NOT_ID;
for (std::map<size_t, uint32_t>::const_iterator it = value_list.begin(); it != value_list.end(); it++) {
index = it->first;
if (rand() & 1)
break;
}
value = value_list[index];
if (command->link() == NULL && (command->type() == icLdc_i4 || command->type() == icLdc_i4_s
|| command->type() == icLdc_i4_0 || command->type() == icLdc_i4_1 || command->type() == icLdc_i4_2 || command->type() == icLdc_i4_3
|| command->type() == icLdc_i4_4 || command->type() == icLdc_i4_5 || command->type() == icLdc_i4_6 || command->type() == icLdc_i4_7
|| command->type() == icLdc_i4_8 || command->type() == icLdc_i4_m1)) {
switch (command->type()) {
case icLdc_i4_0:
old_value = 0;
break;
case icLdc_i4_1:
old_value = 1;
break;
case icLdc_i4_2:
old_value = 2;
break;
case icLdc_i4_3:
old_value = 3;
break;
case icLdc_i4_4:
old_value = 4;
break;
case icLdc_i4_5:
old_value = 5;
break;
case icLdc_i4_6:
old_value = 6;
break;
case icLdc_i4_7:
old_value = 7;
break;
case icLdc_i4_8:
old_value = 8;
break;
case icLdc_i4_m1:
old_value = static_cast<uint32_t>(-1);
break;
case icLdc_i4_s:
old_value = static_cast<int8_t>(command->operand_value());
break;
default:
old_value = static_cast<uint32_t>(command->operand_value());
break;
}
insert_command_list.push_back(AddCommand(icLdloc, index));
switch (rand() & 3) {
case 0:
insert_command_list.push_back(AddCommand(icLdc_i4, old_value - value));
insert_command_list.push_back(AddCommand(icAdd, 0));
break;
case 1:
insert_command_list.push_back(AddCommand(icLdc_i4, value - old_value));
insert_command_list.push_back(AddCommand(icSub, 0));
break;
default:
insert_command_list.push_back(AddCommand(icLdc_i4, old_value ^ value));
insert_command_list.push_back(AddCommand(icXor, 0));
break;
}
command->clear();
command->Init(icNop);
}
else if (rand() & 1) {
stack = stack_map[command];
if (stack < 1)
{
ILCommand *random_command = NULL;
for (j = 0; j < orig_count; j++) {
insert_command = item(j);
if (insert_command->type() == icComment || insert_command->type() == icCase || insert_command->is_data())
continue;
if (insert_command != command && insert_command->address_range() == address_range) {
if (stack == stack_map[insert_command]) {
random_command = insert_command;
if (rand() & 1)
break;
}
}
while (insert_command->is_prefix() && j < orig_count) {
insert_command = item(++j);
}
}
if (random_command) {
old_value = rand32();
bit_mask = 0x1f;
if (rand() & 1) {
insert_command_list.push_back(AddCommand(icLdloc, index));
insert_command_list.push_back(AddCommand(icLdc_i4, old_value));
}
else {
insert_command_list.push_back(AddCommand(icLdc_i4, old_value));
insert_command_list.push_back(AddCommand(icLdloc, index));
std::swap(value, old_value);
}
ILCommandType branch_type;
if (rand() & 1) {
switch (rand() % 3) {
case 0:
branch_type = (value < old_value) ? icBge_un : icBlt_un;
break;
case 1:
branch_type = (value > old_value) ? icBle_un : icBgt_un;
break;
default:
branch_type = (value != old_value) ? icBeq : icBne_un;
break;
}
}
else {
switch (rand() % (8 + (old_value != 0 ? 2 : 0))) {
case 0:
value += old_value;
insert_command_list.push_back(AddCommand(icAdd, 0));
break;
case 1:
value -= old_value;
insert_command_list.push_back(AddCommand(icSub, 0));
break;
case 2:
old_value &= bit_mask;
if (insert_command_list.back()->type() == icLdc_i4)
insert_command_list.back()->set_operand_value(0, old_value);
else {
insert_command_list.push_back(AddCommand(icLdc_i4, bit_mask));
insert_command_list.push_back(AddCommand(icAnd, 0));
}
value >>= old_value;
insert_command_list.push_back(AddCommand(icShr_un, 0));
break;
case 3:
old_value &= bit_mask;
if (insert_command_list.back()->type() == icLdc_i4)
insert_command_list.back()->set_operand_value(0, old_value);
else {
insert_command_list.push_back(AddCommand(icLdc_i4, bit_mask));
insert_command_list.push_back(AddCommand(icAnd, 0));
}
value <<= old_value;
insert_command_list.push_back(AddCommand(icShl, 0));
break;
case 5:
value &= old_value;
insert_command_list.push_back(AddCommand(icAnd, 0));
break;
case 6:
value *= old_value;
insert_command_list.push_back(AddCommand(icMul, 0));
break;
case 8:
value /= old_value;
insert_command_list.push_back(AddCommand(icDiv_un, 0));
break;
case 9:
value %= old_value;
insert_command_list.push_back(AddCommand(icRem_un, 0));
break;
default:
value ^= old_value;
insert_command_list.push_back(AddCommand(icXor, 0));
break;
}
branch_type = value ? icBrfalse : icBrtrue;
}
insert_command = AddCommand(branch_type, 0);
insert_link_list.push_back(insert_command->AddLink(0, ltJmpWithFlag, random_command));
insert_command_list.push_back(insert_command);
}
}
}
}
if (command->type() == icSwitch) {
size_t case_count = static_cast<uint32_t>(command->operand_value());
std::set<ILCommand *> link_command_list;
for (j = 0; j < case_count; j++) {
ILCommand *case_command = item(i + 1 + j);
link_command_list.insert(reinterpret_cast<ILCommand *>(case_command->link()->to_command()));
}
for (std::set<ILCommand *>::const_iterator l = link_command_list.begin(); l != link_command_list.end(); l++) {
link_command = *l;
if (link_command && (link_command->section_options() & rtLinkedToExt) == 0) {
std::map<ILCommand *, std::map<size_t, uint32_t> >::const_iterator it = value_list_map.find(link_command);
if (it == value_list_map.end())
value_list_map[link_command] = value_list;
else
value_list_map.erase(it);
}
}
} else if (link_command && (link_command->section_options() & rtLinkedToExt) == 0) {
std::map<ILCommand *, std::map<size_t, uint32_t> >::const_iterator it = value_list_map.find(link_command);
if (it == value_list_map.end())
value_list_map[link_command] = value_list;
else {
// syncronize predicates
std::map<size_t, uint32_t> dst_value_list = it->second;
for (std::map<size_t, uint32_t>::const_iterator d = dst_value_list.begin(); d != dst_value_list.end(); d++) {
index = d->first;
value = d->second;
std::map<size_t, uint32_t>::const_iterator v = value_list.find(index);
if (v == value_list.end()) {
insert_command_list.push_back(AddCommand(icLdc_i4, value));
}
else {
insert_command_list.push_back(AddCommand(icLdloc, index));
old_value = v->second;
if (rand() & 1) {
insert_command_list.push_back(AddCommand(icLdc_i4, value - old_value));
insert_command_list.push_back(AddCommand(icAdd, 0));
}
else {
insert_command_list.push_back(AddCommand(icLdc_i4, value ^ old_value));
insert_command_list.push_back(AddCommand(icXor, 0));
}
}
insert_command_list.push_back(AddCommand(icStloc, index));
value_list[index] = value;
}
}
}
if (!insert_command_list.empty()) {
if (command->type() == icNop) {
new_command_list.push_back(command);
command = NULL;
} else if (command->section_options() & (rtLinkedToInt | rtLinkedToExt)) {
insert_command = command->Clone(this);
if (command->link())
command->link()->set_from_command(insert_command);
command->clear();
command->Init(icNop);
new_command_list.push_back(command);
command = insert_command;
}
for (j = 0; j < insert_command_list.size(); j++) {
insert_command = insert_command_list[j];
insert_command->set_address_range(address_range);
insert_command->CompileToNative();
new_command_list.push_back(insert_command);
}
}
if (command) {
new_command_list.push_back(command);
while (command->is_prefix() && i < orig_count) {
command = item(++i);
new_command_list.push_back(command);
}
if (command->is_end())
value_list.clear();
}
}
assign(new_command_list);
for (i = 0; i < insert_link_list.size(); i++) {
insert_link_list[i]->from_command()->PrepareLink(ctx);
}
}
void ILFunction::CompileToNative(const CompileContext &ctx)
{
size_t i, j, k;
ILCommand *command;
uint16_t variable_index;
uint16_t add_stack = (compilation_type() == ctMutation) ? 20 : 0;
for (i = 0; i < function_info_list()->count(); i++) {
FunctionInfo *info = function_info_list()->item(i);
ILCommand *entry = reinterpret_cast<ILCommand *>(info->entry());
if (entry) {
ILStandAloneSig *locals = reinterpret_cast<NETRuntimeFunction *>(info->source())->method()->locals();
Data data;
if (entry->dump_size() == 1) {
data.PushByte(CorILMethod_InitLocals | CorILMethod_FatFormat);
data.PushByte(0x30);
data.PushWord(0x08 + add_stack);
}
else {
data.PushByte(entry->dump(0));
data.PushByte(entry->dump(1));
data.PushWord(static_cast<uint16_t>(entry->dump_value(2, osWord)) + add_stack);
}
data.PushDWord(0x0);
if (!locals)
data.PushDWord(0x0);
entry->set_dump(data.data(), data.size());
}
ILCommand *data_entry = reinterpret_cast<ILCommand *>(info->data_entry());
if (!data_entry)
continue;
uint32_t flags = static_cast<uint32_t>(data_entry->operand_value());
bool fat = (flags & CorILMethod_Sect_FatFormat) != 0;
if (fat)
continue;
if (flags & CorILMethod_Sect_EHTable) {
// convert EHTable to fat format
uint32_t data_size = fat ? (flags >> 8) : static_cast<uint8_t>(flags >> 8);
uint32_t clauses = (data_size - sizeof(uint32_t)) / (fat ? 24 : 12);
k = IndexOf(data_entry) + 1;
for (j = 0; j < clauses * 6; j++) {
command = item(k + j);
command->Init(icDword, command->operand_value(), command->token_reference());
command->CompileToNative();
}
data_size = sizeof(uint32_t) + clauses * 6 * sizeof(uint32_t);
data_entry->set_operand_value(0, (data_size << 8) | (flags & 0xff) | CorILMethod_Sect_FatFormat);
data_entry->CompileToNative();
}
}
for (i = 0; i < count(); i++) {
command = item(i);
switch (command->type()) {
case icBr_s:
command->Init(icBr, command->operand_value());
command->CompileToNative();
break;
case icBrfalse_s:
command->Init(icBrfalse, command->operand_value());
command->CompileToNative();
break;
case icBrtrue_s:
command->Init(icBrtrue, command->operand_value());
command->CompileToNative();
break;
case icBeq_s:
command->Init(icBeq, command->operand_value());
command->CompileToNative();
break;
case icBge_s:
command->Init(icBge, command->operand_value());
command->CompileToNative();
break;
case icBgt_s:
command->Init(icBgt, command->operand_value());
command->CompileToNative();
break;
case icBle_s:
command->Init(icBle, command->operand_value());
command->CompileToNative();
break;
case icBlt_s:
command->Init(icBlt, command->operand_value());
command->CompileToNative();
break;
case icBne_un_s:
command->Init(icBne_un, command->operand_value());
command->CompileToNative();
break;
case icBge_un_s:
command->Init(icBge_un, command->operand_value());
command->CompileToNative();
break;
case icBgt_un_s:
command->Init(icBgt_un, command->operand_value());
command->CompileToNative();
break;
case icBle_un_s:
command->Init(icBle_un, command->operand_value());
command->CompileToNative();
break;
case icBlt_un_s:
command->Init(icBlt_un, command->operand_value());
command->CompileToNative();
break;
case icLeave_s:
command->Init(icLeave, command->operand_value());
command->CompileToNative();
break;
case icLdloc:
variable_index = static_cast<uint16_t>(command->operand_value());
switch (variable_index) {
case 0:
command->Init(icLdloc_0, 0);
command->CompileToNative();
break;
case 1:
command->Init(icLdloc_1, 0);
command->CompileToNative();
break;
case 2:
command->Init(icLdloc_2, 0);
command->CompileToNative();
break;
case 3:
command->Init(icLdloc_3, 0);
command->CompileToNative();
break;
default:
if (variable_index < 0x100) {
command->Init(icLdloc_s, variable_index);
command->CompileToNative();
}
break;
}
break;
case icLdloca:
variable_index = static_cast<uint16_t>(command->operand_value());
if (variable_index < 0x100) {
command->Init(icLdloca_s, variable_index);
command->CompileToNative();
}
break;
case icStloc:
variable_index = static_cast<uint16_t>(command->operand_value());
switch (variable_index) {
case 0:
command->Init(icStloc_0, 0);
command->CompileToNative();
break;
case 1:
command->Init(icStloc_1, 0);
command->CompileToNative();
break;
case 2:
command->Init(icStloc_2, 0);
command->CompileToNative();
break;
case 3:
command->Init(icStloc_3, 0);
command->CompileToNative();
break;
default:
if (variable_index < 0x100) {
command->Init(icStloc_s, variable_index);
command->CompileToNative();
}
break;
}
break;
}
}
CreateBlocks();
}
bool IsBoxedElementType(CorElementType type)
{
switch (type) {
case ELEMENT_TYPE_BOOLEAN: case ELEMENT_TYPE_CHAR: case ELEMENT_TYPE_I1: case ELEMENT_TYPE_U1:
case ELEMENT_TYPE_I2: case ELEMENT_TYPE_U2: case ELEMENT_TYPE_I4: case ELEMENT_TYPE_U4:
case ELEMENT_TYPE_I8: case ELEMENT_TYPE_U8: case ELEMENT_TYPE_R4: case ELEMENT_TYPE_R8:
case ELEMENT_TYPE_I: case ELEMENT_TYPE_U: case ELEMENT_TYPE_VALUETYPE:
return true;
}
return false;
}
void ILFunction::CompileToVM(const CompileContext &ctx)
{
if (function_info_list()->count() == 0)
return;
struct FunctionEntryInfo {
ILMethodDef *method;
ILToken *ret;
std::vector<ILElement *> param_list;
ILSignature *locals;
ILCommand *data_entry;
FunctionEntryInfo()
: method(NULL), ret(NULL), locals(NULL), data_entry(NULL)
{
}
FunctionEntryInfo(ILMethodDef *method_, ILToken *ret_, std::vector<ILElement *> param_list_, ILSignature *locals_, ILCommand *data_entry_)
{
method = method_;
ret = ret_;
param_list = param_list_;
locals = locals_;
data_entry = data_entry_;
}
};
size_t i, j, c, k;
ILCommand *command, *data_entry;
CommandLink *link;
CommandBlock *cur_block;
std::string type_name;
ILToken *type, *type_ret;
ILSignature *locals;
ILMetaData *meta;
ILElement *element;
ILMethodDef *method;
std::map<ICommand *, FunctionEntryInfo> entry_map;
// create internal links
c = link_list()->count();
for (i = 0; i < count(); i++) {
command = item(i);
if (command->block() || (command->options() & roNeedCompile) == 0)
continue;
switch (command->type()) {
case icSwitch:
command->AddLink(0, ltSwitch, item(i + 1));
break;
}
}
for (i = c; i < link_list()->count(); i++) {
link_list()->item(i)->from_command()->PrepareLink(ctx);
}
ILVirtualMachine *virtual_machine = reinterpret_cast<ILVirtualMachine *>(BaseFunction::virtual_machine(ctx.file->virtual_machine_list(), NULL));
for (k = 0; k < function_info_list()->count(); k++) {
FunctionInfo *info = function_info_list()->item(k);
if (!info->source() || info->entry()->block())
continue;
ICommand *entry = info->entry();
data_entry = reinterpret_cast<ILCommand *>(info->data_entry());
method = reinterpret_cast<NETRuntimeFunction *>(info->source())->method();
ILSignature *signature = method->signature();
if (!signature->ret())
throw std::runtime_error("Invalid method signature");
locals = method->locals() ? method->locals()->signature() : NULL;
meta = method->meta();
ILElement object_element(NULL, NULL);
{
ILData data;
data.push_back(ELEMENT_TYPE_OBJECT);
object_element.Parse(data);
}
ILToken *type_object = meta->ImportType(object_element);
type_ret = (signature->ret()->type() == ELEMENT_TYPE_VOID) ? NULL : meta->ImportType(*signature->ret());
bool need_try_finally = false;
size_t try_start_index = 0;
size_t try_end_index = 0;
size_t finally_start_index = 0;
size_t finally_end_index = 0;
size_t newarr_index = 0;
std::vector<ILElement *> param_list;
for (i = 0; i < signature->count(); i++) {
element = signature->item(i);
if (element->is_ref())
need_try_finally = true;
param_list.push_back(element);
}
if ((method->flags() & mdStatic) == 0)
param_list.insert(param_list.begin(), &object_element);
if (!method->is_deleted()) {
cur_block = AddBlock(count(), true);
// header
Data data;
data.PushByte(CorILMethod_InitLocals | CorILMethod_FatFormat | (need_try_finally ? CorILMethod_MoreSects : 0));
data.PushByte(0x30);
data.PushWord(0x08);
data.PushDWord(0x0);
command = AddCommand(data);
command->set_alignment(sizeof(uint32_t));
info = function_info_list()->Add(info->begin(), info->begin(), btValue, command->dump_size() + sizeof(uint32_t), 0, 0, info->source(), command);
// locals
if (need_try_finally) {
ILData locals_data;
locals_data.push_back(stLocal);
locals_data.push_back(1 + ((signature->ret()->type() == ELEMENT_TYPE_VOID) ? 0 : 1));
locals_data.push_back(ELEMENT_TYPE_SZARRAY);
locals_data.push_back(ELEMENT_TYPE_OBJECT);
if (signature->ret()->type() != ELEMENT_TYPE_VOID)
signature->ret()->WriteToData(locals_data);
ILStandAloneSig *new_locals = meta->AddStandAloneSig(locals_data);
command = AddCommand(icDword, new_locals->id());
command->set_token_reference(new_locals->reference_list()->Add(0));
}
else {
AddCommand(icDword, 0);
}
newarr_index = count();
if (!param_list.empty()) {
// load args
AddCommand(icLdc_i4, param_list.size());
command = AddCommand(icNewarr, type_object->id());
command->set_token_reference(type_object->reference_list()->Add(0));
for (i = 0; i < param_list.size(); i++) {
AddCommand(icDup, 0);
switch (i) {
case 0: AddCommand(icLdc_i4_0, 0); break;
case 1: AddCommand(icLdc_i4_1, 0); break;
case 2: AddCommand(icLdc_i4_2, 0); break;
case 3: AddCommand(icLdc_i4_3, 0); break;
case 4: AddCommand(icLdc_i4_4, 0); break;
case 5: AddCommand(icLdc_i4_5, 0); break;
case 6: AddCommand(icLdc_i4_6, 0); break;
case 7: AddCommand(icLdc_i4_7, 0); break;
case 8: AddCommand(icLdc_i4_8, 0); break;
default: AddCommand(icLdc_i4, i); break;
}
switch (i) {
case 0: AddCommand(icLdarg_0, 0); break;
case 1: AddCommand(icLdarg_1, 0); break;
case 2: AddCommand(icLdarg_2, 0); break;
case 3: AddCommand(icLdarg_3, 0); break;
default: AddCommand(icLdarg_s, i); break;
}
element = param_list[i];
if (element->is_ref()) {
switch (element->type()) {
case ELEMENT_TYPE_BOOLEAN:
case ELEMENT_TYPE_I1:
AddCommand(icLdind_i1, 0);
break;
case ELEMENT_TYPE_U1:
AddCommand(icLdind_u1, 0);
break;
case ELEMENT_TYPE_I2:
AddCommand(icLdind_i2, 0);
break;
case ELEMENT_TYPE_CHAR:
case ELEMENT_TYPE_U2:
AddCommand(icLdind_u2, 0);
break;
case ELEMENT_TYPE_I4:
AddCommand(icLdind_i4, 0);
break;
case ELEMENT_TYPE_U4:
AddCommand(icLdind_u4, 0);
break;
case ELEMENT_TYPE_I8:
AddCommand(icLdind_i8, 0);
break;
case ELEMENT_TYPE_R4:
AddCommand(icLdind_r4, 0);
break;
case ELEMENT_TYPE_R8:
AddCommand(icLdind_r8, 0);
break;
case ELEMENT_TYPE_I:
case ELEMENT_TYPE_U:
AddCommand(icLdind_i, 0);
break;
default:
AddCommand(icLdind_ref, 0);
break;
}
}
type = meta->ImportType(*element);
if (element->type() == ELEMENT_TYPE_PTR) {
uint64_t address = ctx.vm_runtime->export_list()->GetAddressByType(atBoxPointer);
ILFunction *func = reinterpret_cast<ILFunction *>(ctx.vm_runtime->function_list()->GetFunctionByAddress(address));
for (j = 0; j < func->count(); j++) {
ILCommand *src_command = func->item(j);
if (src_command->type() == icComment || src_command->type() == icLdarg_0)
continue;
if (src_command->type() == icRet)
break;
command = src_command->Clone(this);
if (command->type() == icLdtoken) {
command->set_operand_value(0, type->id());
command->set_token_reference(type->reference_list()->Add(0));
} else if (command->token_reference())
command->set_token_reference(command->token_reference()->owner()->Add(0));
AddObject(command);
}
} else if (IsBoxedElementType(element->type())) {
command = AddCommand(icBox, type->id());
command->set_token_reference(type->reference_list()->Add(0));
}
AddCommand(icStelem_ref, 0);
}
if (need_try_finally)
AddCommand(icStloc_0, 0);
}
if (need_try_finally || param_list.empty()) {
try_start_index = count();
command = AddCommand(icNewobj, virtual_machine->ctor()->id());
command->set_token_reference(virtual_machine->ctor()->reference_list()->Add(0));
if (param_list.empty())
AddCommand(icLdnull, 0);
else
AddCommand(icLdloc_0, 0);
}
else {
command = new ILCommand(this, cpu_address_size(), icNewobj, virtual_machine->ctor()->id());
command->set_token_reference(virtual_machine->ctor()->reference_list()->Add(0));
InsertObject(newarr_index, command);
}
command = AddCommand(icLdc_i4, 0);
link = command->AddLink(0, ltOffset, entry);
entry->include_section_option(rtLinkedToExt);
link->set_sub_value(ctx.file->image_base());
command = AddCommand(icCall, virtual_machine->invoke()->id());
command->set_token_reference(virtual_machine->invoke()->reference_list()->Add(0));
if (!type_ret)
AddCommand(icPop, 0);
else {
if (signature->ret()->type() == ELEMENT_TYPE_PTR) {
uint64_t address = ctx.vm_runtime->export_list()->GetAddressByType(atUnboxPointer);
ILFunction *func = reinterpret_cast<ILFunction *>(ctx.vm_runtime->function_list()->GetFunctionByAddress(address));
for (j = 0; j < func->count(); j++) {
ILCommand *src_command = func->item(j);
if (src_command->type() == icComment || src_command->type() == icLdarg_0)
continue;
if (src_command->type() == icRet)
break;
command = src_command->Clone(this);
if (command->token_reference())
command->set_token_reference(command->token_reference()->owner()->Add(0));
AddObject(command);
}
} else {
command = AddCommand(IsBoxedElementType(signature->ret()->type()) ? icUnbox_any : icCastclass, type_ret->id());
command->set_token_reference(type_ret->reference_list()->Add(0));
}
if (need_try_finally)
AddCommand(icStloc_1, 0);
}
if (need_try_finally) {
command = AddCommand(icLeave, 0);
command->AddLink(0, ltJmp);
try_end_index = count() - 1;
if (!param_list.empty()) {
// save out args
finally_start_index = count();
for (i = 0; i < param_list.size(); i++) {
element = param_list[i];
if (!element->is_ref())
continue;
switch (i) {
case 0: AddCommand(icLdarg_0, 0); break;
case 1: AddCommand(icLdarg_1, 0); break;
case 2: AddCommand(icLdarg_2, 0); break;
case 3: AddCommand(icLdarg_3, 0); break;
default: AddCommand(icLdarg_s, i); break;
}
AddCommand(icLdloc_0, 0);
switch (i) {
case 0: AddCommand(icLdc_i4_0, 0); break;
case 1: AddCommand(icLdc_i4_1, 0); break;
case 2: AddCommand(icLdc_i4_2, 0); break;
case 3: AddCommand(icLdc_i4_3, 0); break;
case 4: AddCommand(icLdc_i4_4, 0); break;
case 5: AddCommand(icLdc_i4_5, 0); break;
case 6: AddCommand(icLdc_i4_6, 0); break;
case 7: AddCommand(icLdc_i4_7, 0); break;
case 8: AddCommand(icLdc_i4_8, 0); break;
default: AddCommand(icLdc_i4, i); break;
}
AddCommand(icLdelem_ref, 0);
if (IsBoxedElementType(element->type())) {
type = meta->ImportType(*element);
command = AddCommand(icUnbox_any, type->id());
command->set_token_reference(type->reference_list()->Add(0));
}
switch (element->type()) {
case ELEMENT_TYPE_BOOLEAN:
case ELEMENT_TYPE_I1:
case ELEMENT_TYPE_U1:
AddCommand(icStind_i1, 0);
break;
case ELEMENT_TYPE_CHAR:
case ELEMENT_TYPE_I2:
case ELEMENT_TYPE_U2:
AddCommand(icStind_i2, 0);
break;
case ELEMENT_TYPE_I4:
case ELEMENT_TYPE_U4:
AddCommand(icStind_i4, 0);
break;
case ELEMENT_TYPE_I8:
AddCommand(icStind_i8, 0);
break;
case ELEMENT_TYPE_R4:
AddCommand(icStind_r4, 0);
break;
case ELEMENT_TYPE_R8:
AddCommand(icStind_r8, 0);
break;
case ELEMENT_TYPE_I:
case ELEMENT_TYPE_U:
AddCommand(icStind_i, 0);
break;
default:
AddCommand(icStind_ref, 0);
break;
}
}
AddCommand(icEndfinally, 0);
finally_end_index = count() - 1;
if (type_ret)
AddCommand(icLdloc_1, 0);
}
}
AddCommand(icRet, 0);
AddressRange *address_range = info->Add(0, 0, NULL, NULL, NULL);
for (i = cur_block->start_index(); i < count(); i++) {
command = item(i);
command->set_block(cur_block);
command->set_address_range(address_range);
command->CompileToNative();
cur_block->set_end_index(i);
}
if (need_try_finally) {
item(try_end_index)->link()->set_to_command(item(finally_end_index + 1));
address_range = function_info_list()->Add(info->begin() + 1, info->begin() + 1, btValue, 0, 0, 0, NULL, NULL)->Add(0, 0, NULL, NULL, NULL);
cur_block = AddBlock(count(), true);
command = AddCommand(icDword, (0x1c << 8) | CorILMethod_Sect_FatFormat | CorILMethod_Sect_EHTable);
command->set_alignment(sizeof(uint32_t));
AddCommand(icDword, COR_ILEXCEPTION_CLAUSE_FINALLY);
ILCommand *try_entry = AddCommand(icDword, 0);
ILCommand *try_length = AddCommand(icDword, 0);
ILCommand *finally_entry = AddCommand(icDword, 0);
link = finally_entry->AddLink(0, ltFinallyBlock, item(finally_start_index));
link->set_base_function_info(info);
ILCommand *finally_length = AddCommand(icDword, 0);
AddCommand(icDword, 0);
for (i = cur_block->start_index(); i < count(); i++) {
command = item(i);
command->set_block(cur_block);
command->set_address_range(address_range);
command->CompileToNative();
cur_block->set_end_index(i);
}
address_range = range_list()->Add(0, 0, try_entry, NULL, try_length);
for (i = try_start_index; i <= try_end_index; i++) {
command = item(i);
command->set_address_range(address_range);
}
address_range = range_list()->Add(0, 0, finally_entry, NULL, finally_length);
for (i = finally_start_index; i <= finally_end_index; i++) {
command = item(i);
command->set_address_range(address_range);
}
}
}
entry_map[entry] = FunctionEntryInfo(method, type_ret, param_list, locals, data_entry);
}
cur_block = NULL;
uint64_t image_base = ctx.file->image_base();
std::set<uint64_t> try_list;
std::map<uint32_t, uint32_t> variable_map, param_map;
size_t temp_variable_index = NOT_ID;
for (i = 0; i < count(); i++) {
command = item(i);
if ((command->options() & roNoProgress) == 0)
ctx.file->StepProgress();
if (command->block() || (command->options() & roNeedCompile) == 0) {
cur_block = NULL;
continue;
}
if (command->is_data()) {
cur_block = NULL;
continue;
}
if (!cur_block) {
cur_block = AddBlock(i, false);
cur_block->set_virtual_machine(virtual_machine);
}
cur_block->set_end_index(i);
command->set_block(cur_block);
if (command->type() == icComment) {
if (command->token_reference())
command->token_reference()->set_deleted(true);
std::map<ICommand *, FunctionEntryInfo>::const_iterator it = entry_map.find(command);
if (it != entry_map.end()) {
try_list.clear();
type_ret = it->second.ret;
method = it->second.method;
meta = method->meta();
locals = it->second.locals;
data_entry = it->second.data_entry;
std::vector<ILElement *> param_list = it->second.param_list;
variable_map.clear();
param_map.clear();
if (command->section_options() & rtLinkedToInt) {
command->AddVMCommand(ctx, icWord, param_list.size(), 0);
for (j = param_list.size(); j > 0; j--) {
element = param_list[j - 1];
type = meta->ImportType(*element);
command->AddVMCommand(ctx, icDword, type->id(), 0, type->reference_list()->Add(0));
}
if (type_ret)
command->AddVMCommand(ctx, icDword, type_ret->id(), 0, type_ret->reference_list()->Add(0));
else
command->AddVMCommand(ctx, icDword, 0, 0);
if (command->section_options() & rtLinkedToExt)
command->AddExtSection(ctx);
}
if (data_entry) {
uint32_t flags = static_cast<uint32_t>(data_entry->operand_value());
if (flags & CorILMethod_Sect_EHTable) {
bool fat = (flags & CorILMethod_Sect_FatFormat) != 0;
uint32_t data_size = fat ? (flags >> 8) : static_cast<uint8_t>(flags >> 8);
uint32_t clauses = (data_size - sizeof(uint32_t)) / (fat ? 24 : 12);
k = IndexOf(data_entry) + 1;
for (j = 0; j < clauses; j++) {
ILCommand *catch_flags = item(k++);
ILCommand *catch_try_offset = item(k++);
ILCommand *catch_try_length = item(k++);
ILCommand *catch_handler_offset = item(k++);
ILCommand *catch_handler_length = item(k++);
ILCommand *catch_filter = item(k++);
command->AddVMCommand(ctx, icInitcatchblock, 0);
command->AddVMCommand(ctx, icByte, static_cast<uint8_t>(catch_flags->operand_value()));
uint64_t try_address = method->address() + method->fat_size() + catch_try_offset->operand_value();
try_list.insert(try_address);
command->AddVMCommand(ctx, icDword, static_cast<uint32_t>(try_address - image_base));
command->AddVMCommand(ctx, icDword, static_cast<uint32_t>(try_address - image_base + catch_try_length->operand_value()));
command->AddVMCommand(ctx, icDword, 0, 0, NULL, catch_handler_offset->link() ? reinterpret_cast<ILCommand *>(catch_handler_offset->link()->to_command()) : NULL);
if (catch_filter->link()) {
command->AddVMCommand(ctx, icDword, 0, 0, NULL, reinterpret_cast<ILCommand *>(catch_filter->link()->to_command()));
}
else {
command->AddVMCommand(ctx, icDword, catch_filter->operand_value(), 0, catch_filter->token_reference());
}
}
}
}
// merge params and locals
std::vector<ILElement *> arg_list;
for (j = 0; j < param_list.size(); j++) {
arg_list.push_back(param_list[j]);
}
if (locals) {
for (j = 0; j < locals->count(); j++) {
arg_list.push_back(locals->item(j));
}
}
for (j = 0; j < arg_list.size(); j++) {
std::swap(arg_list[j], arg_list[rand() % arg_list.size()]);
}
for (j = 0; j < arg_list.size(); j++) {
element = arg_list[j];
type = meta->ImportType(*element);
uint32_t index;
std::vector<ILElement *>::const_iterator it = std::find(param_list.begin(), param_list.end(), element);
if (it != param_list.end()) {
index = static_cast<uint32_t>(it - param_list.begin());
command->AddVMCommand(ctx, icDup, 0);
command->AddVMCommand(ctx, icLdc_i4, static_cast<uint32_t>(index));
command->AddVMCommand(ctx, icLdelema, 0);
command->AddVMCommand(ctx, element->is_ref() ? icDup : icLdc_i4, 0);
command->AddVMCommand(ctx, icLdc_i4, type->id(), 0, type->reference_list()->Add(0));
command->AddVMCommand(ctx, icInitarg, 0);
param_map[index] = static_cast<uint32_t>(j);
}
else {
index = static_cast<uint32_t>(locals->IndexOf(element));
command->AddVMCommand(ctx, icLdnull, 0);
command->AddVMCommand(ctx, icLdc_i4, element->is_ref() ? 1 : 0);
command->AddVMCommand(ctx, icLdc_i4, type->id(), 0, type->reference_list()->Add(0));
command->AddVMCommand(ctx, icInitarg, 0);
variable_map[index] = static_cast<uint32_t>(j);
}
}
if ((ctx.options.flags & cpMemoryProtection) && tag() != ftLoader) {
temp_variable_index = arg_list.size();
type = meta->ImportType(ELEMENT_TYPE_I4);
command->AddVMCommand(ctx, icLdnull, 0);
command->AddVMCommand(ctx, icDup, 0);
command->AddVMCommand(ctx, icLdc_i4, type->id(), 0, type->reference_list()->Add(0));
command->AddVMCommand(ctx, icInitarg, 0);
}
command->AddVMCommand(ctx, icPop, 0);
}
continue;
}
else {
std::map<uint32_t, uint32_t>::const_iterator it;
switch (command->type()) {
case icRet:
if (type_ret) {
command->set_operand_value(0, type_ret->id());
command->set_token_reference(type_ret->reference_list()->Add(0));
}
command->set_param(static_cast<uint32_t>(temp_variable_index));
break;
case icLdloc:
case icLdloc_s:
it = variable_map.find(static_cast<uint16_t>(command->operand_value()));
if (it == variable_map.end())
throw std::runtime_error("Invalid variable index");
command->set_param(it->second);
break;
case icLdloca:
case icLdloca_s:
it = variable_map.find(static_cast<uint16_t>(command->operand_value()));
if (it == variable_map.end())
throw std::runtime_error("Invalid variable index");
command->set_param(it->second);
break;
case icStloc:
case icStloc_s:
it = variable_map.find(static_cast<uint16_t>(command->operand_value()));
if (it == variable_map.end())
throw std::runtime_error("Invalid variable index");
command->set_param(it->second);
break;
case icLdloc_0:
it = variable_map.find(0);
if (it == variable_map.end())
throw std::runtime_error("Invalid variable index");
command->set_param(it->second);
break;
case icLdloc_1:
it = variable_map.find(1);
if (it == variable_map.end())
throw std::runtime_error("Invalid variable index");
command->set_param(it->second);
break;
case icLdloc_2:
it = variable_map.find(2);
if (it == variable_map.end())
throw std::runtime_error("Invalid variable index");
command->set_param(it->second);
break;
case icLdloc_3:
it = variable_map.find(3);
if (it == variable_map.end())
throw std::runtime_error("Invalid variable index");
command->set_param(it->second);
break;
case icStloc_0:
it = variable_map.find(0);
if (it == variable_map.end())
throw std::runtime_error("Invalid variable index");
command->set_param(it->second);
break;
case icStloc_1:
it = variable_map.find(1);
if (it == variable_map.end())
throw std::runtime_error("Invalid variable index");
command->set_param(it->second);
break;
case icStloc_2:
it = variable_map.find(2);
if (it == variable_map.end())
throw std::runtime_error("Invalid variable index");
command->set_param(it->second);
break;
case icStloc_3:
it = variable_map.find(3);
if (it == variable_map.end())
throw std::runtime_error("Invalid variable index");
command->set_param(it->second);
break;
case icLdarg:
case icLdarg_s:
it = param_map.find(static_cast<uint16_t>(command->operand_value()));
if (it == param_map.end())
throw std::runtime_error("Invalid param index");
command->set_param(it->second);
break;
case icLdarga:
case icLdarga_s:
it = param_map.find(static_cast<uint16_t>(command->operand_value()));
if (it == param_map.end())
throw std::runtime_error("Invalid param index");
command->set_param(it->second);
break;
case icStarg:
case icStarg_s:
it = param_map.find(static_cast<uint16_t>(command->operand_value()));
if (it == param_map.end())
throw std::runtime_error("Invalid param index");
command->set_param(it->second);
break;
case icLdarg_0:
it = param_map.find(0);
if (it == param_map.end())
throw std::runtime_error("Invalid param index");
command->set_param(it->second);
break;
case icLdarg_1:
it = param_map.find(1);
if (it == param_map.end())
throw std::runtime_error("Invalid param index");
command->set_param(it->second);
break;
case icLdarg_2:
it = param_map.find(2);
if (it == param_map.end())
throw std::runtime_error("Invalid param index");
command->set_param(it->second);
break;
case icLdarg_3:
it = param_map.find(3);
if (it == param_map.end())
throw std::runtime_error("Invalid param index");
command->set_param(it->second);
break;
}
}
std::set<uint64_t>::const_iterator it = try_list.find(command->address());
if (it != try_list.end()) {
command->AddVMCommand(ctx, icLdc_i4, static_cast<uint32_t>(command->address() - image_base));
command->AddVMCommand(ctx, icEntertry, 0);
}
command->CompileToVM(ctx);
if (command->section_options() & rtCloseSection)
cur_block = NULL;
}
}
bool ILFunction::Compile(const CompileContext &ctx)
{
if (compilation_type() != ctMutation) {
for (size_t i = 0; i < function_info_list()->count(); i++) {
FunctionInfo *info = function_info_list()->item(i);
if (!info->source() || info->entry()->block())
continue;
ILSignature *signature = reinterpret_cast<NETRuntimeFunction *>(info->source())->method()->signature();
bool is_generic = (signature->ret()->type() == ELEMENT_TYPE_VAR || signature->ret()->type() == ELEMENT_TYPE_MVAR);
for (size_t j = 0; j < signature->count(); j++) {
ILElement *element = signature->item(j);
if (element->type() == ELEMENT_TYPE_VAR || element->type() == ELEMENT_TYPE_MVAR) {
is_generic = true;
break;
}
}
if (is_generic) {
ctx.file->Notify(mtError, this, "Method with generic parameters can't be virtualized");
return false;
}
}
}
switch (compilation_type()) {
case ctMutation:
Mutate(ctx);
CompileToNative(ctx);
break;
case ctVirtualization:
CompileToVM(ctx);
break;
case ctUltra:
Mutate(ctx);
CompileToVM(ctx);
break;
default:
return false;
}
return BaseFunction::Compile(ctx);
}
void ILFunction::AfterCompile(const CompileContext &ctx)
{
for (size_t i = 0; i < count(); i++) {
ILCommand *command = item(i);
if (!command->block())
continue;
TokenReference *reference = command->token_reference();
if (reference) {
if (command->options() & roClearOriginalCode)
reference->set_address(0);
}
}
BaseFunction::AfterCompile(ctx);
}
ILCommand *ILFunction::ParseCommand(IArchitecture &file, uint64_t address, bool dump_mode /*= false*/)
{
NETRuntimeFunction *runtime_func = reinterpret_cast<NETRuntimeFunction *>(file.runtime_function_list()->GetFunctionByAddress(address));
ILCommand *command;
if (dump_mode) {
command = Add(address);
if (!file.AddressSeek(address))
command->InitUnknown();
else if (!runtime_func || address < runtime_func->start() || (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 (!runtime_func)
return NULL;
if (address == runtime_func->begin() && file.AddressSeek(address)) {
size_t index = count();
command = Add(address);
command->set_alignment(sizeof(uint32_t));
uint8_t format = static_cast<uint8_t>(command->ReadValueFromFile(file, osByte));
FunctionInfo *info = function_info_list()->Add(runtime_func->begin(), runtime_func->end(), btValue, runtime_func->method()->fat_size(), 0, 0, runtime_func, command);
switch (format & CorILMethod_FormatMask) {
case CorILMethod_TinyFormat:
command->InitComment(string_format(".maxstack %d", 8));
break;
case CorILMethod_FatFormat:
{
ILStandAloneSig *locals = runtime_func->method()->locals();
command->ReadValueFromFile(file, osByte);
uint16_t max_stack = static_cast<uint16_t>(command->ReadValueFromFile(file, osWord));
command->ReadValueFromFile(file, osDWord);
if (!locals)
command->ReadValueFromFile(file, osDWord);
command->InitComment(string_format(".maxstack %d", max_stack));
address = command->next_address();
if (locals) {
command = Add(address);
command->ReadValueFromFile(file, osDWord, true);
command->InitComment(string_format(".locals init %s", locals ? locals->name(true).c_str() : "()"));
address = command->next_address();
}
if (format & CorILMethod_MoreSects) {
size_t old_count = count();
uint64_t start_address = address;
address = AlignValue(runtime_func->end(), sizeof(uint32_t));
file.AddressSeek(address);
uint64_t data_address = address;
command = Add(address);
command->set_alignment(sizeof(uint32_t));
uint32_t flags = static_cast<uint32_t>(command->ReadValueFromFile(file, osDWord));
bool fat = (flags & CorILMethod_Sect_FatFormat) != 0;
uint32_t data_size = fat ? (flags >> 8) : static_cast<uint8_t>(flags >> 8);
command->set_comment(CommentInfo(ttComment, string_format("Kind: %.2X; DataSize: %.8X", flags & CorILMethod_Sect_KindMask, data_size)));
address = command->next_address();
info->set_data_entry(command);
if (flags & CorILMethod_Sect_EHTable) {
CommandLink *link;
uint64_t value;
size_t clauses = (data_size - sizeof(uint32_t)) / (fat ? 24 : 12);
for (size_t i = 0; i < clauses; i++) {
command = Add(address);
flags = static_cast<uint32_t>(command->ReadValueFromFile(file, fat ? osDWord : osWord));
command->set_comment(CommentInfo(ttComment, "Flags"));
address = command->next_address();
ILCommand *try_entry = Add(address);
value = try_entry->ReadValueFromFile(file, fat ? osDWord : osWord);
try_entry->set_comment(CommentInfo(ttComment, "TryOffset"));
address = try_entry->next_address();
uint64_t try_begin = start_address + value;
ILCommand *try_size = Add(address);
value = try_size->ReadValueFromFile(file, fat ? osDWord : osByte);
try_size->set_comment(CommentInfo(ttComment, "TryLength"));
address = try_size->next_address();
uint64_t try_end = try_begin + value;
range_list()->Add(try_begin, try_end, try_entry, NULL, try_size);
ILCommand *handler_entry = Add(address);
value = handler_entry->ReadValueFromFile(file, fat ? osDWord : osWord);
handler_entry->set_comment(CommentInfo(ttComment, "HandlerOffset"));
address = handler_entry->next_address();
link = handler_entry->AddLink(0, (flags & COR_ILEXCEPTION_CLAUSE_FINALLY) ? ltFinallyBlock : ltSEHBlock, start_address + value);
link->set_base_function_info(info);
uint64_t handler_begin = start_address + value;
ILCommand *handler_size = Add(address);
value = handler_size->ReadValueFromFile(file, fat ? osDWord : osByte);
handler_size->set_comment(CommentInfo(ttComment, "HandlerLength"));
address = handler_size->next_address();
uint64_t handler_end = handler_begin + value;
range_list()->Add(handler_begin, handler_end, handler_entry, NULL, handler_size);
if (flags & COR_ILEXCEPTION_CLAUSE_FILTER) {
command = Add(address);
value = command->ReadValueFromFile(file, osDWord);
command->set_comment(CommentInfo(ttComment, "FilterOffset"));
address = command->next_address();
link = command->AddLink(0, ltSEHBlock, start_address + value);
link->set_base_function_info(info);
} else {
command = Add(address);
command->ReadValueFromFile(file, osDWord, true);
command->set_comment(CommentInfo(ttComment, "ClassToken"));
address = command->next_address();
}
}
}
function_info_list()->Add(data_address, data_address + data_size, btValue, 0, 0, 0, NULL, NULL);
for (size_t i = old_count; i < count(); i++) {
command = item(i);
//command->exclude_option(roNeedCompile);
command->exclude_option(roClearOriginalCode);
}
}
}
break;
}
return item(index);
}
if (address < runtime_func->start())
address = runtime_func->start();
if (!file.AddressSeek(address))
return NULL;
}
command = Add(address);
command->ReadFromFile(file);
switch (command->type()) {
case icBrfalse_s: case icBrtrue_s: case icBeq_s: case icBge_s: case icBgt_s:
case icBle_s: case icBlt_s: case icBne_un_s: case icBge_un_s: case icBgt_un_s: case icBle_un_s:
case icBlt_un_s: case icBrfalse: case icBrtrue: case icBeq: case icBge: case icBgt:
case icBle: case icBlt: case icBne_un: case icBge_un: case icBgt_un: case icBle_un: case icBlt_un:
command->AddLink(0, ltJmpWithFlag, command->operand_value());
break;
case icBr: case icBr_s: case icJmp: case icLeave: case icLeave_s:
command->AddLink(0, ltJmp, command->operand_value());
break;
case icSwitch:
{
address = command->next_address();
uint32_t case_count = static_cast<uint32_t>(command->operand_value());
uint64_t add_value = address + case_count * sizeof(uint32_t);
ILCommand *case_command = NULL;
for (size_t i = 0; i < case_count; i++) {
case_command = Add(address);
case_command->ReadCaseCommand(file);
case_command->set_comment(CommentInfo(ttComment, "Case"));
CommandLink *link = case_command->AddLink(0, ltCase, case_command->operand_value() + add_value);
link->set_parent_command(command);
address = case_command->next_address();
}
if (case_command)
command = case_command;
}
break;
case icCall: case icCallvirt: case icLdftn: case icLdvirtftn: case icNewobj:
{
ILToken *token = reinterpret_cast<NETArchitecture&>(file).command_list()->token(static_cast<uint32_t>(command->operand_value()));
uint64_t to_address = 0;
LinkType link_type = ltNone;
if (token && token->type() == ttMethodDef) {
ILMethodDef *method = reinterpret_cast<ILMethodDef*>(token);
if ((method->impl_flags() & miCodeTypeMask) == miIL && method->address()) {
to_address = method->address();
if (command->type() == icCall || (command->type() == icCallvirt && (method->flags() & mdVirtual) == 0))
link_type = ltCall;
}
}
if (to_address)
command->AddLink(-1, link_type, to_address);
}
break;
}
return command;
}
ILCommand *ILFunction::AddCommand(const std::string &value)
{
ILCommand *command = new ILCommand(this, cpu_address_size(), value);
AddObject(command);
return command;
}
ILCommand *ILFunction::AddCommand(const Data &value)
{
ILCommand *command = new ILCommand(this, cpu_address_size(), value);
AddObject(command);
return command;
}
ILCommand *ILFunction::AddCommand(OperandSize value_size, uint64_t value)
{
ILCommandType command_type;
switch (value_size) {
case osWord:
command_type = icWord;
break;
case osDWord:
command_type = icDword;
break;
default:
return NULL;
}
return AddCommand(command_type, value);
}
ILCommand *ILFunction::CreateCommand()
{
return new ILCommand(this, cpu_address_size());
}
ILCommand *ILFunction::AddCommand(ILCommandType type, uint64_t operand_value, IFixup *fixup)
{
ILCommand *command = new ILCommand(this, cpu_address_size(), type, operand_value, fixup);
AddObject(command);
return command;
}
ILFunction *ILFunction::Clone(IFunctionList *owner) const
{
ILFunction *func = new ILFunction(owner, *this);
return func;
}
ILCommand *ILFunction::GetCommandByAddress(uint64_t address) const
{
return reinterpret_cast<ILCommand *>(BaseFunction::GetCommandByAddress(address));
}
ILCommand *ILFunction::GetCommandByNearAddress(uint64_t address) const
{
return reinterpret_cast<ILCommand *>(BaseFunction::GetCommandByNearAddress(address));
}
ILCommand *ILFunction::ParseString(IArchitecture &file, uint64_t address, size_t len)
{
if (!file.AddressSeek(address))
return NULL;
ILCommand *command = Add(address);
command->ReadString(file, len);
command->exclude_option(roNeedCompile);
command->exclude_option(roClearOriginalCode);
return command;
}
ILCommand *ILFunction::Add(uint64_t address)
{
ILCommand *command = new ILCommand(this, cpu_address_size(), address);
AddObject(command);
return command;
}
/**
* ILFunctionList
*/
ILFunctionList::ILFunctionList(IArchitecture *owner)
: BaseFunctionList(owner), crc_table_(NULL), runtime_crc_table_(NULL), import_(NULL)
{
crc_cryptor_ = new ValueCryptor();
}
ILFunctionList::ILFunctionList(IArchitecture *owner, const ILFunctionList &src)
: BaseFunctionList(owner, src), crc_table_(NULL), runtime_crc_table_(NULL), import_(NULL)
{
crc_cryptor_ = new ValueCryptor();
}
ILFunctionList::~ILFunctionList()
{
delete crc_cryptor_;
}
ILFunction *ILFunctionList::item(size_t index) const
{
return reinterpret_cast<ILFunction *>(BaseFunctionList::item(index));
}
ILFunction *ILFunctionList::GetFunctionByAddress(uint64_t address) const
{
return reinterpret_cast<ILFunction *>(BaseFunctionList::GetFunctionByAddress(address));
}
bool ILFunctionList::Prepare(const CompileContext &ctx)
{
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) {
ILFunctionList *function_list = reinterpret_cast<ILFunctionList *>(ctx.runtime->function_list());
ILFunction *func;
size_t i, j;
// remove DecryptString template
uint64_t address = ctx.runtime->export_list()->GetAddressByType(atDecryptStringA);
if (address) {
func = function_list->GetFunctionByAddress(address);
if (func)
func->set_need_compile(false);
}
NETArchitecture *runtime = reinterpret_cast<NETArchitecture *>(ctx.runtime);
NETRuntimeFunctionList *runtime_function_list = runtime->runtime_function_list();
for (i = 0; i < function_list->count(); i++) {
func = function_list->item(i);
if (func->compilation_type() != ctMutation && func->entry_type() == etNone) {
NETRuntimeFunction *runtime_func = runtime_function_list->GetFunctionByAddress(func->address());
if (runtime_func) {
std::vector<ILMethodDef *> method_list = runtime_func->method_list();
for (j = 0; j < method_list.size(); j++) {
ILMethodDef *method = method_list[j];
if (method->flags() & mdSpecialName)
return false;
method->set_deleted(true);
}
}
}
}
APIType crc_helpers[] = { atRandom, atCalcCRC };
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->tag() == ftProcessor)
continue;
if (func->need_compile()) {
func = func->Clone(this);
AddObject(func);
if (func->compilation_type() != ctMutation && func->entry_type() == etNone)
func->entry()->include_section_option(rtLinkedToInt);
for (j = 0; j < func->count(); j++) {
ILCommand *command = func->item(j);
if (command->type() == icLdstr) {
ILData dump = runtime->command_list()->GetUserData(TOKEN_VALUE(command->operand_value()), &address);
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 (dump.size() == unicode_message.size() * sizeof(os::unicode_char) && memcmp(dump.data(), unicode_message.c_str(), dump.size()) == 0) {
MapFunction *map_function = runtime->map_function_list()->Add(address, address + dump.size(), otString, FunctionName());
map_function->reference_list()->Add(command->address(), address);
ILFunction *str_function = reinterpret_cast<ILFunction *>(function_list->AddByAddress(address, ctVirtualization, 0, true, NULL));
if (str_function) {
str_function->set_from_runtime(true);
os::unicode_string str = os::FromUTF8(ctx.options.messages[k]);
if (str.empty())
str.push_back(0);
str_function->item(0)->set_dump(reinterpret_cast<const uint8_t*>(str.c_str()), str.size() * sizeof(os::unicode_char));
}
break;
}
}
}
}
for (j = 0; j < func->count(); j++) {
func->item(j)->CompileToNative();
}
} else {
if (func->tag() != ftLoader) {
NETRuntimeFunction *runtime_func = runtime_function_list->GetFunctionByAddress(func->address());
if (runtime_func) {
std::vector<ILMethodDef *> method_list = runtime_func->method_list();
for (j = 0; j < method_list.size(); j++) {
method_list[j]->set_deleted(true);
}
}
}
if (!func->FreeByManager(ctx))
return false;
}
}
for (i = 0; i < _countof(crc_helpers); i++) {
address = ctx.runtime->export_list()->GetAddressByType(crc_helpers[i]);
func = reinterpret_cast<ILFunction *>(ctx.file->function_list()->GetFunctionByAddress(address));
if (!func)
return false;
// exclude from memory protection
func->entry()->include_section_option(rtLinkedToInt);
func->set_tag(ftLoader);
}
AddRuntimeData(cpu_address_size);
}
else {
// remove references to VMProtect.Core
address = ctx.runtime->export_list()->GetAddressByType(atSetupImage);
func = function_list->GetFunctionByAddress(address);
if (!func)
return false;
for (i = 0; i < func->count(); i++) {
ILCommand *command = func->item(i);
if (command->token_reference()) {
ILToken *token = command->token_reference()->owner()->owner();
switch (token->type()) {
case ttField:
if (reinterpret_cast<ILField *>(token)->declaring_type()->full_name() == "VMProtect.Core")
command->Init(icNop);
break;
case ttMethodDef:
if (reinterpret_cast<ILMethodDef *>(token)->declaring_type()->full_name() == "VMProtect.Core")
command->Init(icNop);
break;
}
}
}
if (ctx.options.flags & cpMemoryProtection) {
// add CRC helpers
for (i = 0; i < _countof(crc_helpers); i++) {
address = ctx.runtime->export_list()->GetAddressByType(crc_helpers[i]);
func = function_list->GetFunctionByAddress(address);
if (!func)
return false;
func = func->Clone(this);
AddObject(func);
for (j = 0; j < func->count(); j++) {
ILCommand *command = func->item(j);
command->exclude_option(roClearOriginalCode);
command->CompileToNative();
}
// exclude from memory protection
func->entry()->include_section_option(rtLinkedToInt);
func->set_tag(ftLoader);
}
}
}
}
if (ctx.options.flags & cpImportProtection) {
import_ = AddImport(cpu_address_size);
} else {
import_ = NULL;
}
AddSDK(cpu_address_size);
AddWatermark(cpu_address_size, ctx.options.watermark, ctx.runtime ? 8 : 10);
return BaseFunctionList::Prepare(ctx);
}
void ILFunctionList::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;
}
return BaseFunctionList::CompileLinks(ctx);
}
void ILFunctionList::CompileInfo(const CompileContext &ctx)
{
return BaseFunctionList::CompileInfo(ctx);
}
void ILFunctionList::ReadFromBuffer(Buffer &buffer, IArchitecture &file)
{
BaseFunctionList::ReadFromBuffer(buffer, file);
// add loader stubs
size_t i, j;
std::set<ILTypeDef*> class_list;
for (i = 0; i < count(); i++) {
ILFunction *func = item(i);
if (func->tag() != ftLoader)
continue;
for (j = 0; j < func->count(); j++) {
ILCommand *command = func->item(j);
if (command->token_reference()) {
ILToken *token = command->token_reference()->owner()->owner();
if (token->type() == ttMethodDef)
class_list.insert(reinterpret_cast<ILMethodDef*>(token)->declaring_type());
}
}
}
for (std::set<ILTypeDef*>::const_iterator it = class_list.begin(); it != class_list.end(); ) {
ILTypeDef *type_def = *it;
if (type_def->full_name() == "VMProtect.Core") {
class_list.erase(it++);
continue;
}
it++;
}
ILTable *method_table = reinterpret_cast<NETArchitecture&>(file).command_list()->table(ttMethodDef);
for (i = 0; i < method_table->count(); i++) {
ILMethodDef *method = reinterpret_cast<ILMethodDef*>(method_table->item(i));
uint64_t address = method->address();
if (!address || class_list.find(method->declaring_type()) == class_list.end() || GetFunctionByAddress(address))
continue;
ILFunction *new_func = reinterpret_cast<ILFunction *>(AddByAddress(address, ctMutation, 0, false, NULL));
if (new_func) {
new_func->set_tag(ftLoader);
for (j = 0; j < new_func->count(); j++) {
new_func->item(j)->exclude_option(roClearOriginalCode);
}
}
}
}
ILFunction *ILFunctionList::Add(const std::string &name, CompilationType compilation_type, uint32_t compilation_options, bool need_compile, Folder *folder)
{
ILFunction *func = new ILFunction(this, name, compilation_type, compilation_options, need_compile, folder);
AddObject(func);
return func;
}
ILFunctionList * ILFunctionList::Clone(IArchitecture *owner) const
{
ILFunctionList *list = new ILFunctionList(owner, *this);
return list;
}
IFunction * ILFunctionList::CreateFunction(OperandSize cpu_address_size)
{
return new ILFunction(this, cpu_address_size);
}
bool ILFunctionList::Compile(const CompileContext &ctx)
{
return BaseFunctionList::Compile(ctx);
}
ILSDK *ILFunctionList::AddSDK(OperandSize cpu_address_size)
{
ILSDK *func = new ILSDK(this, cpu_address_size);
AddObject(func);
return func;
}
ILRuntimeData *ILFunctionList::AddRuntimeData(OperandSize cpu_address_size)
{
ILRuntimeData *func = new ILRuntimeData(this, cpu_address_size);
AddObject(func);
return func;
}
ILCRCTable *ILFunctionList::AddCRCTable(OperandSize cpu_address_size)
{
ILCRCTable *func = new ILCRCTable(this, cpu_address_size);
AddObject(func);
return func;
}
ILImport *ILFunctionList::AddImport(OperandSize cpu_address_size)
{
ILImport *func = new ILImport(this, cpu_address_size);
AddObject(func);
return func;
}
ILFunction *ILFunctionList::AddWatermark(OperandSize cpu_address_size, Watermark *watermark, int copy_count)
{
ILFunction *func = new ILFunction(this, cpu_address_size);
func->set_compilation_type(ctMutation);
func->set_memory_type(mtNone);
func->AddWatermark(watermark, copy_count);
AddObject(func);
return func;
}
ILRuntimeCRCTable *ILFunctionList::AddRuntimeCRCTable(OperandSize cpu_address_size)
{
ILRuntimeCRCTable *func = new ILRuntimeCRCTable(this, cpu_address_size);
AddObject(func);
return func;
}
ILVirtualMachineProcessor *ILFunctionList::AddProcessor(OperandSize cpu_address_size)
{
ILVirtualMachineProcessor *func = new ILVirtualMachineProcessor(this, cpu_address_size);
AddObject(func);
return func;
}
/**
* ILSDK
*/
ILSDK::ILSDK(IFunctionList *owner, OperandSize cpu_address_size)
: ILFunction(owner, cpu_address_size)
{
set_compilation_type(ctMutation);
}
bool ILSDK::Init(const CompileContext &ctx)
{
MapFunctionList *map_function_list;
MapFunction *map_function;
IFunctionList *function_list;
size_t i, c, j, n, f;
uint64_t address;
IArchitecture *file;
IImportList *import_list;
IImport *import;
IImportFunction *import_function;
ILCommand *command;
CommandBlock *block;
uint64_t api_address;
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();
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);
if (import_function->type() == atNone)
continue;
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<ILCommand *>(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->token_reference()) {
command->token_reference()->set_deleted(true);
command->set_token_reference(NULL);
}
switch (import_function->type()) {
case atBegin:
command->Init(icPop);
break;
case atEnd:
command->Init(icNop);
break;
case atDecryptStringA:
case atDecryptStringW:
command->Init(icNop);
break;
case atFreeString:
Notify(mtWarning, command, "VMProtect.SDK.FreeString is deprecated");
// fall through
case atIsDebuggerPresent:
case atIsVirtualMachinePresent:
case atIsValidImageCRC:
case atActivateLicense:
case atDeactivateLicense:
case atGetOfflineActivationString:
case atGetOfflineDeactivationString:
case atSetSerialNumber:
case atGetSerialNumberState:
case atGetSerialNumberData:
case atGetCurrentHWID:
case atIsProtected:
if (!ctx.runtime || ctx.runtime->segment_list()->count() == 0) {
switch (import_function->type()) {
case atFreeString:
command->Init(icNop);
break;
case atIsProtected:
command->Init(icLdc_i4_1);
break;
default:
// other APIs can not work without runtime
return false;
}
} else {
api_address = ctx.runtime->export_list()->GetAddressByType(import_function->type());
if (!api_address)
return false;
ILMethodDef *method = reinterpret_cast<ILMetaData *>(ctx.runtime->command_list())->GetMethod(api_address);
if (!method)
return false;
command->set_operand_value(0, method->id());
command->set_token_reference(method->reference_list()->Add(command->address() + 1));
}
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 true;
}
/**
* ILCRCTable
*/
ILCRCTable::ILCRCTable(IFunctionList *owner, OperandSize cpu_address_size)
: ILFunction(owner, cpu_address_size)
{
set_compilation_type(ctMutation);
}
bool ILCRCTable::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();
}
for (i = 0; i < c; i++) {
AddCommand(icDword, 0);
AddCommand(icDword, 0);
AddCommand(icDword, 0);
}
size_entry_ = AddCommand(icDword, 0);
size_entry_->include_option(roCreateNewBlock);
hash_entry_ = AddCommand(icDword, 0);
hash_entry_->include_option(roCreateNewBlock);
for (i = 0; i < count(); i++) {
ILCommand *command = item(i);
command->CompileToNative();
command->include_option(roWritable);
}
return true;
}
/**
* ILRuntimeData
*/
ILRuntimeData::ILRuntimeData(IFunctionList *owner, OperandSize cpu_address_size)
: ILFunction(owner, cpu_address_size), strings_entry_(NULL), strings_size_(0), trial_hwid_entry_(NULL), trial_hwid_size_(0),
resources_entry_(NULL), resources_size_(0)
#ifdef ULTIMATE
, license_data_entry_(NULL), license_data_size_(0)
#endif
{
set_compilation_type(ctMutation);
rc5_key_.Create();
}
bool ILRuntimeData::CommandCompareHelper::operator()(const ILCommand *left, ILCommand *right) const
{
return (left->address() < right->address());
}
bool ILRuntimeData::Init(const CompileContext &ctx)
{
ILFunctionList *function_list;
size_t i, j, index;
std::vector<ILCommand *> string_command_list;
ILCommand *command, *string_command;
CommandLink *link;
ILCommand *key_entry;
Data key;
uint32_t 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;
#ifdef ULTIMATE
if (ctx.options.file_manager) {
FileManager *file_manager = ctx.options.file_manager;
if (!file_manager->OpenFiles())
return false;
InternalFile *internal_file;
index = count();
// write entry
for (i = 0; i < file_manager->count(); i++) {
internal_file = file_manager->item(i);
AddCommand(osDWord, 0);
AddCommand(osDWord, 0);
AddCommand(osDWord, internal_file->stream()->Size());
AddCommand(osDWord, 0);
}
// end entry
AddCommand(osDWord, 0);
AddCommand(osDWord, 0);
AddCommand(osDWord, 0);
AddCommand(osDWord, 0);
resources_entry_ = item(index);
resources_entry_->include_option(roCreateNewBlock);
resources_size_ = static_cast<uint32_t>((count() - index) * OperandSizeToValue(osDWord));
PEFile pe_file;
for (i = 0; i < file_manager->count(); i++) {
internal_file = file_manager->item(i);
std::string file_name = internal_file->absolute_file_name();
std::string assembly_name;
try
{
if (pe_file.Open(file_name.c_str(), foRead | foHeaderOnly) == osSuccess && pe_file.count() > 1)
assembly_name = reinterpret_cast<NETArchitecture *>(pe_file.item(1))->full_name();
}
catch (...)
{
}
pe_file.Close();
if (assembly_name.empty()) {
Notify(mtError, internal_file, string_format(language[lsFileHasIncorrectFormat].c_str(), file_name.c_str(), ".NET"));
file_manager->CloseFiles();
return false;
}
// write name
Data data;
os::unicode_string name = os::FromUTF8(assembly_name.c_str());
const os::unicode_char *p = name.c_str();
for (j = 0; j < name.size() + 1; j++) {
data.PushWord(static_cast<uint16_t>(p[j] ^ (_rotl32(data_key, static_cast<int>(j)) + j)));
}
command = AddCommand(data);
command->include_option(roCreateNewBlock);
link = item(index + i * 4)->AddLink(0, ltOffset, command);
link->set_sub_value(image_base);
// write data
Notify(mtInformation, NULL, string_format("%s %s", language[lsLoading].c_str(), os::ExtractFileName(file_name.c_str()).c_str()));
data.resize(static_cast<size_t>(internal_file->stream()->Size()));
internal_file->stream()->Read(&data[0], data.size());
for (j = 0; j < data.size(); j++) {
data[j] = (data[j] ^ static_cast<uint8_t>(_rotl32(data_key, static_cast<int>(j)) + j));
}
command = AddCommand(data);
command->include_option(roCreateNewBlock);
link = item(index + i * 4 + 1)->AddLink(0, ltOffset, command);
link->set_sub_value(image_base);
}
file_manager->CloseFiles();
}
#endif
if ((ctx.options.flags & cpResourceProtection) && ctx.file->resource_list()->count()) {
std::string assembly_name;
NETArchitecture *file = reinterpret_cast<NETArchitecture *>(ctx.file);
while (true) {
assembly_name = string_format("%.8X", rand32());
if (!file->command_list()->GetAssemblyRef(assembly_name))
break;
}
Data data;
if (file->WriteResources(assembly_name, data)) {
ILAssemblyRef *assembly_ref = file->command_list()->GetAssemblyRef(assembly_name);
if (!assembly_ref)
return false;
if (resources_entry_) {
index = IndexOf(resources_entry_) + (resources_size_ - 4 * sizeof(uint32_t)) / sizeof(uint32_t);
// insert entry
InsertObject(index + 0, new ILCommand(this, cpu_address_size(), icDword, 0));
InsertObject(index + 1, new ILCommand(this, cpu_address_size(), icDword, 0));
InsertObject(index + 2, new ILCommand(this, cpu_address_size(), icDword, data.size()));
InsertObject(index + 3, new ILCommand(this, cpu_address_size(), icDword, 0));
resources_size_ += 4 * sizeof(uint32_t);
}
else {
// write entry
index = count();
AddCommand(osDWord, 0);
AddCommand(osDWord, 0);
AddCommand(osDWord, data.size());
AddCommand(osDWord, 0); // action
// end entry
AddCommand(osDWord, 0);
AddCommand(osDWord, 0);
AddCommand(osDWord, 0);
AddCommand(osDWord, 0);
resources_entry_ = item(index);
resources_entry_->include_option(roCreateNewBlock);
resources_size_ = static_cast<uint32_t>((count() - index) * OperandSizeToValue(osDWord));
}
// write name
Data str;
os::unicode_string name = os::FromUTF8(assembly_ref->full_name().c_str());
const os::unicode_char *p = name.c_str();
for (i = 0; i < name.size() + 1; i++) {
str.PushWord(static_cast<uint16_t>(p[i] ^ (_rotl32(data_key, static_cast<int>(i)) + i)));
}
command = AddCommand(str);
command->include_option(roCreateNewBlock);
link = item(index)->AddLink(0, ltOffset, command);
link->set_sub_value(image_base);
// write data
for (i = 0; i < data.size(); i++) {
data[i] = data[i] ^ static_cast<uint8_t>(_rotl32(data_key, static_cast<int>(i)) + i);
}
command = AddCommand(data);
command->include_option(roCreateNewBlock);
link = item(index + 1)->AddLink(0, ltOffset, command);
link->set_sub_value(image_base);
}
}
function_list = reinterpret_cast<ILFunctionList *>(ctx.file->function_list());
for (i = 0; i < function_list->count(); i++) {
ILFunction *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());
AddCommand(osDWord, 0);
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());
AddCommand(osDWord, 0);
}
strings_entry_ = item(index);
strings_entry_->include_option(roCreateNewBlock);
strings_size_ = static_cast<uint32_t>((count() - index) * OperandSizeToValue(osDWord));
i = AlignValue(strings_size_, 8);
if (i > strings_size_) {
Data tmp;
tmp.resize(i - strings_size_, 0);
AddCommand(tmp);
strings_size_ = (uint32_t)i;
}
// 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 + 2 + i * 4 + 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
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
for (i = 0; i < count(); i++) {
item(i)->CompileToNative();
}
// setup faces for common runtime functions
ILCRCTable *il_crc = reinterpret_cast<ILFunctionList *>(ctx.file->function_list())->crc_table();
for (i = 0; i < function_list->count(); i++) {
ILFunction *func = function_list->item(i);
if (!func->from_runtime())
continue;
for (j = 0; j < func->count(); j++) {
ILCommand *command = func->item(j);
if (command->type() != icLdc_i4)
continue;
uint32_t value = static_cast<uint32_t>(command->operand_value());
if ((value & 0xFFFF0000) == 0xFACE0000) {
switch (value) {
case FACE_STRING_DECRYPT_KEY:
command->set_operand_value(0, data_key);
command->CompileToNative();
break;
case FACE_RC5_P:
command->set_operand_value(0, rc5_key_.P);
command->CompileToNative();
break;
case FACE_RC5_Q:
command->set_operand_value(0, rc5_key_.Q);
command->CompileToNative();
break;
case FACE_KEY_INFO:
if (key_entry) {
link = command->AddLink(0, ltOffset, key_entry);
link->set_sub_value(image_base);
} else {
command->set_operand_value(0, 0);
command->CompileToNative();
}
break;
case FACE_STRING_INFO:
if (strings_entry_) {
link = command->AddLink(0, ltOffset, strings_entry_);
link->set_sub_value(image_base);
} else {
command->set_operand_value(0, 0);
command->CompileToNative();
}
break;
case FACE_RESOURCE_INFO:
if (resources_entry_) {
link = command->AddLink(0, ltOffset, resources_entry_);
link->set_sub_value(image_base);
}
else {
command->set_operand_value(0, 0);
command->CompileToNative();
}
break;
#ifdef ULTIMATE
case FACE_LICENSE_INFO:
if (license_data_entry_) {
link = command->AddLink(0, ltOffset, license_data_entry_);
link->set_sub_value(image_base);
} else {
command->set_operand_value(0, 0);
command->CompileToNative();
}
break;
case FACE_LICENSE_INFO_SIZE:
command->set_operand_value(0, license_data_size_);
command->CompileToNative();
break;
#else
case FACE_LICENSE_INFO:
case FACE_LICENSE_INFO_SIZE:
command->set_operand_value(0, 0);
command->CompileToNative();
break;
#endif
case FACE_TRIAL_HWID:
if (trial_hwid_entry_) {
link = command->AddLink(0, ltOffset, trial_hwid_entry_);
link->set_sub_value(image_base);
} else {
command->set_operand_value(0, 0);
command->CompileToNative();
}
break;
case FACE_TRIAL_HWID_SIZE:
command->set_operand_value(0, trial_hwid_size_);
command->CompileToNative();
break;
case FACE_CRC_TABLE_ENTRY:
if (il_crc) {
link = command->AddLink(0, ltOffset, il_crc->table_entry());
link->set_sub_value(image_base);
} else {
command->set_operand_value(0, 0);
command->CompileToNative();
}
break;
case FACE_CRC_TABLE_SIZE:
if (il_crc) {
link = command->AddLink(0, ltOffset, il_crc->size_entry());
link->set_sub_value(image_base);
} else {
command->set_operand_value(0, 0);
command->CompileToNative();
}
break;
case FACE_CRC_TABLE_HASH:
if (il_crc) {
link = command->AddLink(0, ltOffset, il_crc->hash_entry());
link->set_sub_value(image_base);
} else {
command->set_operand_value(0, 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(0, options);
}
command->CompileToNative();
break;
}
}
}
}
return true;
}
size_t ILRuntimeData::WriteToFile(IArchitecture &file)
{
size_t res = ILFunction::WriteToFile(file);
CipherRC5 cipher(rc5_key_);
for (size_t i = 0; i < 3; i++) {
ILCommand *command;
size_t size;
switch (i) {
case 0:
command = strings_entry_;
size = strings_size_;
break;
case 1:
command = trial_hwid_entry_;
size = trial_hwid_entry_ ? trial_hwid_entry_->dump_size() : 0;
break;
case 2:
command = resources_entry_;
size = resources_size_;
break;
#ifdef ULTIMATE
/*
case 2:
command = license_data_entry_;
size = license_data_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.data(), buff.size());
cipher.Encrypt(buff.data(), buff.size());
file.Seek(pos);
file.Write(buff.data(), buff.size());
}
}
return res;
}
/**
* ILRuntimeCRCTable
*/
ILRuntimeCRCTable::ILRuntimeCRCTable(IFunctionList *owner, OperandSize cpu_address_size)
: ILFunction(owner, cpu_address_size), cryptor_(NULL)
{
set_compilation_type(ctMutation);
}
void ILRuntimeCRCTable::clear()
{
region_info_list_.clear();
ILFunction::clear();
}
bool ILRuntimeCRCTable::Compile(const CompileContext &ctx)
{
ILFunctionList *function_list = reinterpret_cast<ILFunctionList *>(ctx.file->function_list());
cryptor_ = function_list->crc_cryptor();
size_t block_size, i, j, k;
uint64_t block_address;
MemoryManager manager(ctx.file);
for (i = 0; i < function_list->count(); i++) {
ILFunction *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++) {
ILCommand *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();
block_size += command->dump_size();
}
if (block_size)
manager.Add(block_address, block_size, mtReadable);
}
else {
// VM block
block_size = 0;
block_address = 0;
for (k = block->start_index(); k <= block->end_index(); k++) {
ILCommand *command = func->item(k);
if (block_address && (block_address + block_size) != command->vm_address()) {
if (block_size)
manager.Add(block_address, block_size, mtReadable);
block_address = 0;
block_size = 0;
}
if (!block_address)
block_address = command->vm_address();
block_size += command->vm_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(icDword, 0);
AddCommand(icDword, 0);
AddCommand(icDword, 0);
}
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 ILRuntimeCRCTable::WriteToFile(IArchitecture &file)
{
size_t res = ILFunction::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;
}
/**
* ILFileHelper
*/
ILFileHelper::ILFileHelper()
: IObject(), marker_index_(0), marker_name_list_(NULL)
{
}
ILFileHelper::~ILFileHelper()
{
}
void ILFileHelper::Parse(NETArchitecture &file)
{
size_t i, j;
ILToken *token;
ILFunction func(NULL, file.cpu_address_size());
std::set<uint64_t> address_list;
size_t c = file.map_function_list()->count();
file.StartProgress(string_format("%s %s...", language[lsLoading].c_str(), os::ExtractFileName(file.owner()->file_name().c_str()).c_str()), c);
for (i = 0; i < c; i++) {
MapFunction *map_function = file.map_function_list()->item(i);
file.StepProgress();
if (map_function->type() != otCode && map_function->type() != otMarker && map_function->type() != otExport)
continue;
if (address_list.find(map_function->address()) != address_list.end())
continue;
address_list.insert(map_function->address());
func.ReadFromFile(file, map_function->address());
for (j = 0; j < func.count(); j++) {
ILCommand *command = func.item(j);
uint32_t value = static_cast<uint32_t>(command->operand_value());
if (command->type() == icComment) {
if (command->comment().value.substr(0, 7) == ".locals") {
token = file.command_list()->token(value);
if (token)
token->reference_list()->Add(command->address());
}
} else if (command->type() == icDword) {
if (command->comment().value == "ClassToken") {
token = file.command_list()->token(value);
if (token)
token->reference_list()->Add(command->address());
}
} else switch (ILOpCodes[command->type()].operand_type) {
case InlineString:
token = file.command_list()->token(value);
if (!token)
token = file.command_list()->us_table()->Add(value);
command->set_token_reference(token->reference_list()->Add(command->address() + command->operand_pos()));
if (map_function->strings_protection())
AddString(file, static_cast<uint32_t>(command->operand_value()), command->address());
break;
case InlineField:
case InlineMethod:
case InlineSig:
case InlineTok:
case InlineType:
token = file.command_list()->token(value);
if (token) {
command->set_token_reference(token->reference_list()->Add(command->address() + command->operand_pos(), command->type()));
NETImportFunction *import_function = file.import_list()->GetFunctionByToken(value);
if (import_function) {
import_function->map_function()->reference_list()->Add(command->address(), 0);
if (ILOpCodes[command->type()].flow_type == Call) {
if (j > 0 && ILOpCodes[func.item(j - 1)->type()].opcode_type == Prefix)
import_function->include_option(ioHasCallPrefix);
}
if (import_function->owner()->is_sdk()) {
switch (import_function->type()) {
case atDecryptStringA:
case atDecryptStringW:
if (command->type() == icCall && j > 0) {
ILCommand *prev = func.item(j - 1);
if (prev->type() == icLdstr)
AddString(file, static_cast<uint32_t>(prev->operand_value()), prev->address());
}
break;
}
}
}
}
break;
}
}
ILCommandBlock block;
if (block.Parse(func)) {
for (j = 0; j < block.count(); j++) {
ILCommandNode *node = block.item(j);
ILCommand *command = node->command();
switch (command->type()) {
case icCall: case icNewobj:
{
std::string name = node->token_name();
if (name == "instance void System.Runtime.InteropServices.ComAwareEventInfo::.ctor(class System.Type, string)") {
auto stack = node->stack();
token = block.GetTypeOf(stack[0]);
if (token && token->type() == ttTypeDef) {
ILTypeDef *type_def = reinterpret_cast<ILTypeDef*>(token);
if (stack[1]->command()->type() == icLdstr) {
if (ILEvent *event = type_def->GetEvent(reinterpret_cast<ILUserString*>(stack[1]->command()->token_reference()->owner()->owner())->name()))
event->set_can_rename(false);
}
else {
ILTable *ref_table = file.command_list()->table(ttEvent);
for (size_t r = 0; r < ref_table->count(); r++) {
ILEvent *event = reinterpret_cast<ILEvent *>(ref_table->item(r));
if (event->declaring_type() == type_def)
event->set_can_rename(false);
}
}
}
}
else if (name.size() > 58 && name.substr(0, 58) == "string Newtonsoft.Json.JsonConvert::SerializeObject(object") {
auto stack = node->stack();
token = block.GetTypeFromStack(stack[0]);
if (token && token->type() == ttTypeDef) {
ILTypeDef *type_def = reinterpret_cast<ILTypeDef*>(token);
ILTable *ref_table = file.command_list()->table(ttProperty);
for (size_t r = 0; r < ref_table->count(); r++) {
ILProperty *property = reinterpret_cast<ILProperty*>(ref_table->item(r));
if (property->declaring_type() == type_def)
property->set_can_rename(false);
}
}
}
}
break;
}
}
}
}
file.EndProgress();
}
void ILFileHelper::AddString(NETArchitecture &file, uint32_t token, uint64_t reference)
{
if (TOKEN_TYPE(token) != ttUserString)
return;
uint64_t address;
ILData dump = file.command_list()->GetUserData(TOKEN_VALUE(token), &address);
if (dump.empty())
return;
std::string name = "string \"" + file.command_list()->GetUserString(TOKEN_VALUE(token)) + "\"";
MapFunction *map_function = file.map_function_list()->Add(address, address + dump.size(), otString, name);
map_function->reference_list()->Add(reference, address);
}
/**
* ILCommandNode
*/
ILCommandNode::ILCommandNode(ILCommandBlock *owner, ILCommand *command)
: IObject(), owner_(owner), command_(command)
{
}
ILCommandNode::~ILCommandNode()
{
if (owner_)
owner_->RemoveObject(this);
}
std::string ILCommandNode::token_name() const
{
if (command_->token_reference()) {
ILToken *token = command_->token_reference()->owner()->owner();
if (token->type() == ttMethodSpec)
token = reinterpret_cast<ILMethodSpec*>(token)->parent();
switch (token->type()) {
case ttMemberRef:
return reinterpret_cast<ILMemberRef*>(token)->full_name();
}
}
return std::string();
}
/**
* ILCommandBlock
*/
ILCommandBlock::ILCommandBlock()
: ObjectList<ILCommandNode>(), method_(NULL)
{
}
ILCommandNode *ILCommandBlock::Add(ILCommand *command)
{
ILCommandNode *node = new ILCommandNode(this, command);
AddObject(node);
return node;
}
ILCommandNode *ILCommandBlock::GetNodeByCommand(ILCommand *command) const
{
auto it = map_.find(command);
return (it != map_.end()) ? it->second : NULL;
}
void ILCommandBlock::AddObject(ILCommandNode *node)
{
ObjectList<ILCommandNode>::AddObject(node);
if (node->command())
map_[node->command()] = node;
}
ILToken *ILCommandBlock::GetTypeOf(ILCommandNode *node) const
{
if (node->command()->type() == icCall) {
if (node->token_name() == "class System.Type System.Type::GetTypeFromHandle(valuetype System.RuntimeTypeHandle)") {
auto stack = node->stack();
if (stack[0]->command()->type() == icLdtoken)
return stack[0]->command()->token_reference()->owner()->owner();
}
}
return NULL;
}
ILToken *ILCommandBlock::GetTypeFromStack(ILCommandNode *node) const
{
switch (node->command()->type()) {
case icLdarg_0:
if (method_ && method_->signature()->has_this())
return method_->declaring_type();
break;
case icDup:
return GetTypeFromStack(node->stack()[0]);
case icNewobj:
{
ILToken *token = node->command()->token_reference()->owner()->owner();
switch (token->type()) {
case ttMethodDef:
return reinterpret_cast<ILMethodDef*>(token)->declaring_type();
case ttMemberRef:
return reinterpret_cast<ILMemberRef*>(token)->declaring_type();
}
}
break;
}
return NULL;
}
bool ILCommandBlock::Parse(ILFunction &func)
{
size_t i, j, c;
ILCommand *command;
std::set<ILCommand *> entry_list;
std::vector<ILCommandNode *> command_stack;
std::map<ILCommand *, std::vector<ILCommandNode *> > stack_map;
for (i = 0; i < func.function_info_list()->count(); i++) {
FunctionInfo *info = func.function_info_list()->item(i);
if (!info->source())
continue;
command = reinterpret_cast<ILCommand *>(info->entry());
entry_list.insert(command);
method_ = reinterpret_cast<NETRuntimeFunction*>(info->source())->method();
}
command_stack.push_back(NULL);
for (i = 0; i < func.link_list()->count(); i++) {
CommandLink *link = func.link_list()->item(i);
switch (link->type()) {
case ltSEHBlock:
command = func.GetCommandByAddress(link->to_address());
if (command) {
entry_list.insert(command);
stack_map[command] = command_stack;
}
break;
case ltFinallyBlock:
command = func.GetCommandByAddress(link->to_address());
if (command)
entry_list.insert(command);
break;
}
}
while (!entry_list.empty()) {
command = *entry_list.begin();
j = func.IndexOf(command);
auto it = stack_map.find(command);
if (it != stack_map.end())
command_stack = it->second;
else
command_stack.clear();
for (i = j; i < func.count(); i++) {
command = func.item(i);
std::set<ILCommand *>::const_iterator it = entry_list.find(command);
if (it != entry_list.end())
entry_list.erase(it);
ILCommandNode *node = Add(command);
if (command->type() == icRet) {
if (command_stack.size() > 1)
return false;
node->set_stack(command_stack);
break;
}
size_t pop;
int stack = command->GetStackLevel(&pop);
if (pop) {
if (pop > command_stack.size())
return false;
std::vector<ILCommandNode *> node_stack;
node_stack.insert(node_stack.begin(), command_stack.end() - pop, command_stack.end());
command_stack.erase(command_stack.end() - pop, command_stack.end());
node->set_stack(node_stack);
}
for (c = 0; c < stack + pop; c++) {
command_stack.push_back(node);
}
if (command->link() && (command->link()->type() == ltJmp || command->link()->type() == ltJmpWithFlag)) {
if (ILCommand *link_command = func.GetCommandByAddress(command->link()->to_address())) {
if (!GetNodeByCommand(link_command)) {
entry_list.insert(link_command);
stack_map[link_command] = command_stack;
}
}
}
if (command->is_end())
break;
}
}
return true;
}
/**
* ILImport
*/
ILImport::ILImport(IFunctionList *owner, OperandSize cpu_address_size)
: ILFunction(owner, cpu_address_size)
{
set_compilation_type(ctMutation);
}
bool ILImport::Init(const CompileContext &ctx)
{
NETArchitecture *file = reinterpret_cast<NETArchitecture *>(ctx.file);
NETArchitecture *runtime = reinterpret_cast<NETArchitecture *>(ctx.runtime);
ILTypeDef *module = reinterpret_cast<ILTypeDef*>(file->command_list()->token(ttTypeDef | 1));
ILTypeDef *runtime_loader = runtime->command_list()->GetTypeDef("VMProtect.Loader");
if (!runtime_loader)
return false;
ILField *iat_field = runtime_loader->GetField("IAT");
if (!iat_field)
return false;
size_t i, j, k, c;
std::map<ILToken *, bool> value_type_map;
ILTokenType table_types[] = {ttMemberRef, ttStandAloneSig, ttField, ttMethodDef};
for (i = 0; i < _countof(table_types); i++) {
ILTable *table = module->meta()->table(table_types[i]);
for (k = 0; k < table->count(); k++) {
ILToken *token = table->item(k);
ILSignature *signature = NULL;
switch (token->type()) {
case ttMemberRef:
signature = reinterpret_cast<ILMemberRef *>(token)->signature();
break;
case ttStandAloneSig:
signature = reinterpret_cast<ILStandAloneSig *>(token)->signature();
break;
case ttField:
signature = reinterpret_cast<ILField *>(token)->signature();
break;
case ttMethodDef:
signature = reinterpret_cast<ILMethodDef *>(token)->signature();
break;
}
if (!signature)
continue;
std::vector<ILElement *> element_stack;
element_stack.push_back(signature->ret());
for (c = 0; c < signature->count(); c++) {
element_stack.push_back(signature->item(c));
}
for (c = 0; c < element_stack.size(); c++) {
ILElement *element = element_stack[c];
if (element->type() == ELEMENT_TYPE_CLASS)
value_type_map[element->token()] = false;
else if (element->type() == ELEMENT_TYPE_VALUETYPE)
value_type_map[element->token()] = true;
if (element->next())
element_stack.push_back(element->next());
}
}
}
std::vector<NETImportFunction *> import_list;
for (i = 0; i < file->import_list()->count(); i++) {
NETImport *import = file->import_list()->item(i);
// APIs processed by ILSDK
if (import->is_sdk())
continue;
if (import->excluded_from_import_protection())
continue;
for (j = 0; j < import->count(); j++) {
NETImportFunction *import_function = import->item(j);
if (import_function->options() & ioHasCallPrefix)
continue;
import_list.push_back(import_function);
}
}
for (i = 0; i < import_list.size(); i++) {
std::swap(import_list[i], import_list[rand() % import_list.size()]);
}
size_t iat_index = 0;
ILTypeRef *delegate_base_type = NULL;
for (i = 0; i < import_list.size(); i++) {
NETImportFunction *import_function = import_list[i];
ILToken *import_token = file->command_list()->token(import_function->token());
ILSignature *signature;
ILToken *declaring_type;
switch (import_token->type()) {
case ttMemberRef:
signature = reinterpret_cast<ILMemberRef*>(import_token)->signature();
declaring_type = reinterpret_cast<ILMemberRef*>(import_token)->declaring_type();
break;
default:
continue;
}
if (declaring_type->type() != ttTypeRef)
continue;
MapFunction *map_function = import_function->map_function();
ReferenceList *reference_list = map_function->reference_list();
std::map<ILCommandType, ILMethodDef *> proxy_map;
for (j = 0; j < reference_list->count(); j++) {
uint64_t address = reference_list->item(j)->address();
if (!file->AddressSeek(address))
return false;
ILCommand *src_command = reinterpret_cast<ILCommand *>(ctx.file->function_list()->GetCommandByAddress(address, true));
size_t index = count();
ILCommand *ref_command = Add(address);
ref_command->ReadFromFile(*file);
ILCommandType ref_type = static_cast<ILCommandType>(ref_command->type());
if (ref_type != icNewobj && ref_type != icCall && ref_type != icCallvirt && ref_type != icLdsfld && ref_type != icLdfld) {
delete ref_command;
continue;
}
ILMethodDef *proxy_method;
std::map<ILCommandType, ILMethodDef *>::const_iterator it = proxy_map.find(ref_type);
if (it == proxy_map.end()) {
ILSignature *new_signature;
if (signature->is_field()) {
ILData data;
data.push_back(stDefault);
data.push_back(0);
signature->ret()->WriteToData(data);
new_signature = new ILSignature(module->meta());
new_signature->Parse(data);
if (ref_type == icLdfld)
new_signature->set_has_this(true);
}
else {
new_signature = signature->Clone(module->meta());
}
if (new_signature->has_this()) {
std::map<ILToken *, bool>::const_iterator it = value_type_map.find(declaring_type);
if (it == value_type_map.end()) {
delete ref_command;
continue;
}
bool is_value_type = it->second;
ILData data;
if (is_value_type) {
if (ref_type != icNewobj && ref_type != icLdfld)
data.push_back(ELEMENT_TYPE_BYREF);
data.push_back(ELEMENT_TYPE_VALUETYPE);
}
else {
data.push_back(ELEMENT_TYPE_CLASS);
}
uint32_t value = declaring_type->value() << 2;
switch (declaring_type->type()) {
case ttTypeDef:
value |= 0;
break;
case ttTypeRef:
value |= 1;
break;
case ttTypeSpec:
value |= 2;
break;
}
data.push_back(static_cast<uint8_t>(value >> 24) | 0xc0);
data.push_back(static_cast<uint8_t>(value >> 16));
data.push_back(static_cast<uint8_t>(value >> 8));
data.push_back(static_cast<uint8_t>(value));
if (ref_type == icNewobj)
new_signature->ret()->Parse(data);
else {
ILElement *element = new ILElement(module->meta(), new_signature);
element->Parse(data);
new_signature->InsertObject(0, element);
}
}
ILData proxy_signature;
{
ILData data;
data.push_back(ELEMENT_TYPE_OBJECT);
ILElement *element = new_signature->ret();
switch (element->type()) {
case ELEMENT_TYPE_CLASS:
case ELEMENT_TYPE_SZARRAY:
element->Parse(data);
break;
case ELEMENT_TYPE_GENERICINST:
if (element->next()->type() == ELEMENT_TYPE_CLASS)
element->Parse(data);
break;
}
if (new_signature->has_this()) {
new_signature->set_has_this(false);
for (k = 0; k < new_signature->count(); k++) {
element = new_signature->item(k);
switch (element->type()) {
case ELEMENT_TYPE_CLASS:
case ELEMENT_TYPE_SZARRAY:
element->Parse(data);
break;
case ELEMENT_TYPE_GENERICINST:
if (element->next()->type() == ELEMENT_TYPE_CLASS)
element->Parse(data);
break;
}
}
}
}
new_signature->WriteToData(proxy_signature);
delete new_signature;
if (!delegate_base_type) {
ILAssemblyRef *assembly_ref = module->meta()->GetCoreLib();
delegate_base_type = module->meta()->ImportTypeRef(assembly_ref, "System", "MulticastDelegate");
}
ILTypeDef *delegate_type = module->meta()->AddTypeDef(delegate_base_type, "", "", (CorTypeAttr)(tdNotPublic | tdSealed));
file->RenameToken(delegate_type);
ILData ctor_signature; // instance void (object, native int)
ctor_signature.push_back(stDefault | stHasThis);
ctor_signature.push_back(2);
ctor_signature.push_back(ELEMENT_TYPE_VOID);
ctor_signature.push_back(ELEMENT_TYPE_OBJECT);
ctor_signature.push_back(ELEMENT_TYPE_I);
ILMethodDef *delegate_ctor = module->meta()->AddMethod(delegate_type, ".ctor", ctor_signature, (CorMethodAttr)(mdAssem | mdHideBySig | mdRTSpecialName | mdSpecialName), miRuntime);
ILMethodDef *delegate_invoke = module->meta()->AddMethod(delegate_type, "Invoke", proxy_signature, (CorMethodAttr)(mdAssem | mdHideBySig | mdVirtual | mdNewSlot), miRuntime);
delegate_invoke->signature()->set_has_this(true);
uint32_t call_type;
switch (ref_type) {
case icNewobj:
call_type = 1;
break;
case icCallvirt:
call_type = 2;
break;
case icLdsfld:
call_type = 8;
break;
case icLdfld:
call_type = 9;
break;
default:
call_type = 0;
break;
}
info_list_.push_back(ImportDelegateInfo(import_token, delegate_invoke, call_type));
proxy_method = module->meta()->AddMethod(module, "", proxy_signature, (CorMethodAttr)(mdAssem | mdStatic), miIL);
file->RenameToken(proxy_method);
size_t entry_index = count();
// header
ILCommand *command = AddCommand(icComment, 0);
command->include_section_option(rtLinkedToExt);
Data data;
data.PushByte(CorILMethod_TinyFormat);
command->set_dump(data.data(), data.size());
command->set_alignment(sizeof(uint32_t));
// code
command = AddCommand(icLdsfld, 0);
command->set_token_reference(iat_field->reference_list()->Add(0));
AddCommand(icLdc_i4, static_cast<uint32_t>(iat_index++));
AddCommand(icLdelem_ref, 0);
for (k = 0; k < proxy_method->signature()->count(); k++) {
AddCommand(icLdarg, static_cast<uint32_t>(k));
}
command = AddCommand(icCall, 0);
command->set_token_reference(delegate_invoke->reference_list()->Add(0));
AddCommand(icRet, 0);
FunctionInfo *info = function_info_list()->Add(0, 0, btValue, item(entry_index)->dump_size(), 0, 0, runtime->runtime_function_list()->Add(0, 0, 0, proxy_method), item(entry_index));
AddressRange *range = info->Add(0, 0, NULL, NULL, NULL);
for (k = entry_index; k < count(); k++) {
item(k)->set_address_range(range);
}
proxy_map[ref_type] = proxy_method;
}
else {
proxy_method = it->second;
}
if (src_command) {
delete ref_command;
src_command->Init(icCall, 0, src_command->token_reference());
src_command->CompileToNative();
src_command->token_reference()->set_owner(proxy_method->reference_list());
}
else {
ref_command->exclude_option(roClearOriginalCode);
ref_command->Init(icCall, 0, ref_command->token_reference());
ref_command->CompileToNative();
ref_command->token_reference()->set_owner(proxy_method->reference_list());
CommandBlock *block = AddBlock(index, true);
block->set_address(address);
ref_command->set_block(block);
}
}
}
for (i = 0; i < count(); i++) {
item(i)->CompileToNative();
}
return ILFunction::Init(ctx);
}
/**
* ILVirtualMachine
*/
ILVirtualMachine::ILVirtualMachine(ILVirtualMachineList *owner, uint8_t id, ILVirtualMachineProcessor *processor)
: BaseVirtualMachine(owner, id), processor_(processor), ctor_(NULL), invoke_(NULL)
{
}
void ILVirtualMachine::Init(const CompileContext &ctx)
{
processor_->InitCommands(ctx);
ctor_ = processor_->function_info_list()->count() > 0 ? reinterpret_cast<NETRuntimeFunction *>(processor_->function_info_list()->item(0)->source())->method() : NULL;
invoke_ = processor_->function_info_list()->count() > 1 ? reinterpret_cast<NETRuntimeFunction *>(processor_->function_info_list()->item(1)->source())->method() : NULL;
size_t i, j, c;
ILCommand *command;
ILOpcodeInfo *opcode;
size_t template_index, template_count;
template_index = 0;
template_count = 0;
for (i = 0; i < processor_->count(); i++) {
command = processor_->item(i);
if (command->type() != icLdftn)
continue;
template_index = i - 4;
for (j = i; j < processor_->count(); j++) {
command = processor_->item(j);
if (command->type() != icLdftn)
continue;
if (!template_count && j > i)
template_count = j - i;
opcode_list_.Add(static_cast<ILCommandType>(processor_->item(j - 2)->operand_value()), command->token_reference()->owner()->owner());
}
break;
}
for (i = template_index + template_count * opcode_list_.count(); i > template_index + template_count; i--) {
command = processor_->item(i - 1);
if (command->link())
delete command->link();
if (command->token_reference())
delete command->token_reference();
delete command;
}
// randomize opcodes
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->entry());
}
opcode_stack_.clear();
for (i = 0; i < opcode_list_.count(); i++) {
opcode = opcode_list_.item(i);
opcode->set_opcode(static_cast<uint8_t>(i));
opcode_stack_[opcode->Key()].push_back(opcode);
for (j = 0; j < template_count; j++) {
command = processor_->item(template_index + j);
if (i > 0) {
command = command->Clone(processor_);
processor_->InsertObject(template_index + i * template_count + j, command);
}
switch (command->type()) {
case icLdc_i4: case icLdc_i4_s:
command->Init(icLdc_i4, opcode->opcode());
command->CompileToNative();
break;
case icLdftn:
command->set_operand_value(0, opcode->entry()->id());
command->set_token_reference(opcode->entry()->reference_list()->Add(0));
command->CompileToNative();
break;
default:
if (command->token_reference())
command->set_token_reference(command->token_reference()->owner()->Add(0));
}
}
}
}
ILOpcodeInfo *ILVirtualMachine::GetOpcode(ILCommandType command_type)
{
ILOpcodeInfo *res = NULL;
auto it = opcode_stack_.find(command_type);
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 ILVirtualMachine::CompileCommand(ILVMCommand &vm_command)
{
Data dump;
ILOpcodeInfo *opcode = NULL;
uint64_t value = vm_command.value();
if (vm_command.crypt_command() == icAdd) {
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());
ILVMCommand *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();
}
value = crypted_value[3];
}
switch (vm_command.command_type()) {
case icLdarg: case icLdarga:
case icStarg:
case icLdloc: case icLdloca:
case icStloc:
opcode = GetOpcode(vm_command.command_type());
dump.PushWord(static_cast<uint16_t>(vm_command.value()));
break;
case icLdc_i4:
opcode = GetOpcode(vm_command.command_type());
dump.PushDWord(static_cast<uint32_t>(value));
break;
case icLdc_i8:
opcode = GetOpcode(vm_command.command_type());
dump.PushQWord(value);
break;
case icLdc_r4:
opcode = GetOpcode(vm_command.command_type());
dump.PushDWord(static_cast<uint32_t>(value));
break;
case icLdc_r8:
opcode = GetOpcode(vm_command.command_type());
dump.PushQWord(value);
break;
case icByte:
dump.PushByte(static_cast<uint8_t>(vm_command.value()));
break;
case icWord:
dump.PushWord(static_cast<uint16_t>(vm_command.value()));
break;
case icDword:
dump.PushDWord(static_cast<uint32_t>(vm_command.value()));
break;
case icQword:
dump.PushQWord(vm_command.value());
break;
default:
opcode = GetOpcode(vm_command.command_type());
break;
}
if (opcode) {
dump.InsertByte(0, opcode->opcode());
}
else if (!vm_command.is_data()) {
throw std::runtime_error("Runtime error at CompileToVM: " + std::string(ILOpCodes[vm_command.command_type()].name));
}
vm_command.set_dump(dump);
}
/**
* ILOpcodeInfo
*/
ILOpcodeInfo::ILOpcodeInfo(ILOpcodeList *owner, ILCommandType command_type, ILToken *entry)
: IObject(), owner_(owner), command_type_(command_type), entry_(entry), opcode_(0)
{
}
ILOpcodeInfo::~ILOpcodeInfo()
{
if (owner_)
owner_->RemoveObject(this);
}
ILOpcodeInfo *ILOpcodeInfo::circular_queue::Next()
{
ILOpcodeInfo *res = NULL;
if (size())
res = this->operator[](position_++ % size());
return res;
}
/**
* ILOpcodeList
*/
ILOpcodeList::ILOpcodeList()
: ObjectList<ILOpcodeInfo>()
{
}
ILOpcodeInfo *ILOpcodeList::Add(ILCommandType command_type, ILToken *entry)
{
ILOpcodeInfo *opcode = new ILOpcodeInfo(this, command_type, entry);
AddObject(opcode);
return opcode;
}
ILOpcodeInfo *ILOpcodeList::GetOpcodeInfo(ILCommandType command_type) const
{
for (size_t i = 0; i < count(); i++) {
ILOpcodeInfo *opcode = item(i);
if (opcode->command_type() == command_type)
return opcode;
}
return NULL;
}
/**
* ILVirtualMachineList
*/
IVirtualMachineList * ILVirtualMachineList::Clone() const
{
ILVirtualMachineList *list = new ILVirtualMachineList();
return list;
}
void ILVirtualMachineList::Prepare(const CompileContext &ctx)
{
ILFunctionList *function_list = reinterpret_cast<ILFunctionList *>(ctx.file->function_list());
ILVirtualMachineProcessor *processor = function_list->AddProcessor(ctx.file->cpu_address_size());
ILVirtualMachine *virtual_machine = new ILVirtualMachine(this, 1, processor);
AddObject(virtual_machine);
virtual_machine->Init(ctx);
}
/**
* ILVirtualMachineProcessor
*/
ILVirtualMachineProcessor::ILVirtualMachineProcessor(ILFunctionList *owner, OperandSize cpu_address_size)
: ILFunction(owner, cpu_address_size)
{
set_compilation_type(ctMutation);
set_tag(ftProcessor);
}
void ILVirtualMachineProcessor::InitCommands(const CompileContext &ctx)
{
size_t i, j, k;
ILCommand *command, *src_command, *dst_command;
CommandLink *src_link, *dst_link;
ILFunctionList *runtime_function_list = reinterpret_cast<ILFunctionList *>(ctx.vm_runtime->function_list());
for (i = 0; i < runtime_function_list->count(); i++) {
ILFunction *func = runtime_function_list->item(i);
if (func->tag() != ftProcessor)
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()));
}
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);
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()));
if (src_link->base_function_info())
dst_link->set_base_function_info(function_info_list()->GetItemByAddress(src_link->base_function_info()->begin()));
}
}
}
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()));
if (info->data_entry())
info->set_data_entry(GetCommandByAddress(info->data_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 = 0; i < count(); i++) {
command = item(i);
dst_link = command->link();
if (dst_link) {
if (dst_link->to_address())
dst_link->set_to_command(GetCommandByAddress(dst_link->to_address()));
}
if (command->token_reference())
command->token_reference()->set_address(0);
command->exclude_option(roClearOriginalCode);
command->CompileToNative();
}
}
void ILVirtualMachineProcessor::AfterCompile(const CompileContext &ctx)
{
ILFunction::AfterCompile(ctx);
if (ctx.runtime)
set_need_compile(false);
}
void ILVirtualMachineProcessor::CompileLinks(const CompileContext &ctx)
{
if (!need_compile())
return;
ILFunction::CompileLinks(ctx);
}
void ILVirtualMachineProcessor::CompileInfo(const CompileContext &ctx)
{
if (!need_compile())
return;
ILFunction::CompileInfo(ctx);
}
size_t ILVirtualMachineProcessor::WriteToFile(IArchitecture &file)
{
if (!need_compile())
return 0;
return ILFunction::WriteToFile(file);
}
/**
* NETLoader
*/
NETLoader::NETLoader(IFunctionList *owner, OperandSize cpu_address_size)
: ILFunction(owner, cpu_address_size), file_crc_entry_(NULL), file_crc_size_(0),
import_entry_(NULL), import_size_(0), iat_entry_(NULL), iat_size_(0), loader_crc_entry_(NULL), loader_crc_size_(0),
file_crc_size_entry_(NULL), loader_crc_size_entry_(NULL), loader_crc_hash_entry_(NULL),
pe_entry_(NULL), strong_name_signature_entry_(NULL), tls_entry_(NULL), tls_size_(0)
{
set_compilation_type(ctVirtualization);
set_tag(ftLoader);
}
void NETLoader::AddAVBuffer(const CompileContext &ctx)
{
ILCommand *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(icDword, 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);
}
Data EncryptString(const char *str, uint32_t key);
Data EncryptString(const os::unicode_char *str, uint32_t key);
bool NETLoader::Prepare(const CompileContext &ctx)
{
size_t i, j, k, old_count, index, import_index, start_index;
NETArchitecture *file, *runtime;
ILFunctionList *runtime_function_list;
ILFunction *func;
CommandLink *link, *src_link, *dst_link;
ILCommand *src_command, *dst_command, *command;
ILCRCTable *il_crc;
PEImportList new_import_list(NULL);
std::vector<ImportInfo> import_info_list;
std::vector<ImportFunctionInfo> import_function_info_list;
PEImport *import;
PEImportFunction *import_function;
ImportInfo import_info;
PESegment *segment;
ILImport *il_import;
uint64_t tls_index_address;
file = reinterpret_cast<NETArchitecture *>(ctx.file);
runtime = reinterpret_cast<NETArchitecture *>(ctx.runtime);
il_crc = reinterpret_cast<ILFunctionList *>(file->function_list())->crc_table();
il_import = reinterpret_cast<ILFunctionList *>(file->function_list())->import();
PEArchitecture *pe_file = file->pe();
uint32_t string_key = rand32();
ILCommandType value_command_type = (cpu_address_size() == osDWord) ? icDword : icQword;
// create AV signature buffer
AddAVBuffer(ctx);
start_index = count();
import_size_ = 0;
import_entry_ = 0;
PEImportFunction *entry_point_import_function = NULL;
if ((ctx.options.flags & cpPack) && pe_file->import_list()->count()) {
for (i = 0; i < pe_file->import_list()->count(); i++) {
import = pe_file->import_list()->item(i);
new_import_list.AddObject(import->Clone(&new_import_list));
}
const std::string import_name = "mscoree.dll";
const std::string import_function_name = (pe_file->image_type() == itExe) ? "_CorExeMain" : "_CorDllMain";
import = reinterpret_cast<PEImport *>(new_import_list.GetImportByName(import_name));
if (!import) {
import = new PEImport(&new_import_list, import_name);
new_import_list.AddObject(import);
}
entry_point_import_function = NULL;
for (i = 0; i < import->count(); i++) {
import_function = import->item(i);
if (import_function->name() == import_function_name) {
entry_point_import_function = import_function;
break;
}
}
if (!entry_point_import_function) {
entry_point_import_function = new PEImportFunction(import, import_function_name);
import->AddObject(entry_point_import_function);
}
// create import directory
for (i = 0; i < new_import_list.count(); i++) {
import = new_import_list.item(i);
// IMAGE_IMPORT_DESCRIPTOR.OriginalFirstThunk
command = AddCommand(icDword, 0);
command->AddLink(0, ltOffset);
import_info.original_first_thunk = command;
// IMAGE_IMPORT_DESCRIPTOR.TimeDateStamp
AddCommand(icDword, 0);
// IMAGE_IMPORT_DESCRIPTOR.ForwarderChain
AddCommand(icDword, 0);
// IMAGE_IMPORT_DESCRIPTOR.Name
command = AddCommand(icDword, 0);
command->AddLink(0, ltOffset);
import_info.name = command;
// IMAGE_IMPORT_DESCRIPTOR.FirstThunk
command = AddCommand(icDword, 0);
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(icDword, 0);
}
import_size_ = static_cast<uint32_t>((count() - start_index) * sizeof(uint32_t));
import_entry_ = item(start_index);
import_entry_->set_alignment(OperandSizeToValue(pe_file->cpu_address_size()));
// create IAT
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);
index = count();
for (j = 0; j < import->count(); j++) {
import_function = import->item(j);
if (import_function->is_ordinal()) {
command = AddCommand(value_command_type, ordinal_mask | import_function->ordinal());
} else {
command = AddCommand(value_command_type, 0);
command->AddLink(0, ltOffset);
}
ImportFunctionInfo import_function_info(import_function);
import_function_info.name = command;
import_function_info_list.push_back(import_function_info);
}
AddCommand(value_command_type, 0);
import_info_list[i].original_first_thunk->link()->set_to_command(item(index));
}
command = item(name_index);
command->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 (import_function->is_ordinal()) {
command = AddCommand(value_command_type, ordinal_mask | import_function->ordinal());
} else {
command = AddCommand(value_command_type, 0);
command->AddLink(0, ltOffset);
}
import_function_info_list[import_index].thunk = command;
}
if (is_delay_import)
continue;
AddCommand(value_command_type, 0);
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);
// 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);
command = NULL;
for (j = 0; j < i; j++) {
if (new_import_list.item(j)->CompareName(import->name())) {
command = reinterpret_cast<ILCommand *>(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);
for (j = 0; j < import->count(); j++, import_index++) {
import_function = import->item(j);
if (import_function->is_ordinal())
continue;
command = AddCommand(icWord, 0);
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());
}
}
pe_entry_ = NULL;
strong_name_signature_entry_ = NULL;
if ((ctx.options.flags & cpPack)) {
if (pe_file->entry_point()) {
// create native entry point
segment = file->segment_list()->GetSectionByAddress(pe_file->entry_point());
if (segment && !segment->excluded_from_packing()) {
std::vector<ImportFunctionInfo>::const_iterator it = std::find(import_function_info_list.begin(), import_function_info_list.end(), entry_point_import_function);
if (it == import_function_info_list.end())
return false;
index = count();
CommandBlock *block = AddBlock(count(), true);
AddCommand(icWord, 0x25ff);
command = AddCommand(icDword, 0);
command->AddLink(0, ltOffset, it->thunk);
pe_entry_ = item(index);
for (i = index; i < count(); i++) {
command = item(i);
command->set_block(block);
block->set_end_index(i);
}
}
}
IMAGE_DATA_DIRECTORY strong_name_signature = file->header().StrongNameSignature;
if (strong_name_signature.VirtualAddress) {
// create blank StrongNameSignature
segment = file->segment_list()->GetSectionByAddress(strong_name_signature.VirtualAddress + file->image_base());
if (segment && !segment->excluded_from_packing()) {
Data data;
data.resize(strong_name_signature.Size ? strong_name_signature.Size : 0x80);
strong_name_signature_entry_ = AddCommand(data);
strong_name_signature_entry_->include_option(roCreateNewBlock);
strong_name_signature_entry_->set_alignment(sizeof(uint32_t));
}
}
}
// create tls structure
tls_entry_ = NULL;
tls_size_ = 0;
tls_call_back_entry_ = NULL;
tls_index_address = 0;
if (pe_file->tls_directory()->address() && (pe_file->tls_directory()->count() || (ctx.options.flags & cpPack))) {
size_t tls_index = count();
PETLSDirectory *tls_directory = pe_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();
}
ILCommand *start_address_entry = AddCommand(value_command_type, tls_directory->start_address_of_raw_data(), NEED_FIXUP);
ILCommand *end_address_entry = AddCommand(value_command_type, tls_directory->end_address_of_raw_data(), NEED_FIXUP);
AddCommand(value_command_type, tls_directory->address_of_index(), NEED_FIXUP);
ILCommand *call_back_entry = AddCommand(value_command_type, 0);
AddCommand(icDword, tls_directory->size_of_zero_fill());
AddCommand(icDword, tls_directory->characteristics());
if (tls_directory->end_address_of_raw_data() > tls_directory->start_address_of_raw_data()) {
Data data;
data.resize(static_cast<size_t>(tls_directory->end_address_of_raw_data() - tls_directory->start_address_of_raw_data()));
if (file->AddressSeek(tls_directory->start_address_of_raw_data()))
file->Read(&data[0], data.size());
ILCommand *data_entry = AddCommand(data);
start_address_entry->AddLink(0, ltOffset, data_entry);
link = end_address_entry->AddLink(0, ltOffset, data_entry);
link->set_sub_value(0 - (uint64_t)data.size());
}
index = count();
if (pe_file->tls_directory()->count()) {
tls_call_back_entry_ = AddCommand(value_command_type, 0, NEED_FIXUP);
tls_call_back_entry_->AddLink(0, ltGateOffset);
}
for (i = 0; i < tls_directory->count(); i++) {
AddCommand(icDword, tls_directory->item(i)->address(), NEED_FIXUP);
}
if (count() > index) {
AddCommand(value_command_type, 0);
call_back_entry->AddLink(0, ltOffset, item(index));
call_back_entry->set_operand_fixup(NEED_FIXUP);
}
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_ += OperandSizeToValue(command->type() == icDword ? osDWord : osQWord);
}
}
// create watermarks
AddWatermark(ctx.options.watermark, 2);
// create section list for setting WRITABLE flag
std::vector<PESegment *> writable_section_list;
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);
segment = file->segment_list()->GetSectionByAddress(import_function->address());
if (!segment)
continue;
if (std::find(writable_section_list.begin(), writable_section_list.end(), segment) == writable_section_list.end())
writable_section_list.push_back(segment);
}
}
std::vector<PackerInfo> packer_info_list;
PEFixupList loader_fixup_list;
bool pack_resources = false;
ILCommand *packer_props = NULL;
vtable_fixups_entry_ = NULL;
if (ctx.options.flags & cpPack) {
std::set<PESegment *> skip_segment_list;
if (file->header().VTableFixups.VirtualAddress) {
uint64_t address = file->image_base() + file->header().VTableFixups.VirtualAddress;
segment = file->segment_list()->GetSectionByAddress(address);
if (segment && !segment->excluded_from_packing() && file->AddressSeek(address)) {
index = count();
j = file->header().VTableFixups.Size;
for (i = 0; i < j; i += sizeof(IMAGE_COR_VTABLEFIXUP)) {
IMAGE_COR_VTABLEFIXUP fixup;
file->Read(&fixup, sizeof(fixup));
AddCommand(icDword, fixup.RVA);
AddCommand(icWord, fixup.Count);
AddCommand(icWord, fixup.Type);
if (PESegment *tmp = file->segment_list()->GetSectionByAddress(file->image_base() + fixup.RVA))
skip_segment_list.insert(tmp);
}
if (index < count()) {
vtable_fixups_entry_ = item(index);
vtable_fixups_entry_->include_option(roCreateNewBlock);
vtable_fixups_entry_->set_alignment(sizeof(uint64_t));
}
}
}
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.section = segment;
packer_info.address = segment->address();
packer_info.size = static_cast<size_t>(segment->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(), segment) == writable_section_list.end())
writable_section_list.push_back(segment);
}
}
if ((ctx.options.flags & cpStripFixups) == 0) {
PEFixupList *fixup_list = file->pe()->fixup_list();
for (i = 0; i < fixup_list->count(); i++) {
PEFixup *fixup = 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_section_list.begin(), writable_section_list.end(), segment) == writable_section_list.end())
writable_section_list.push_back(segment);
}
}
// 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;
}
// 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->physical_offset() > 0 && segment->physical_size() > 0) {
physical_offset = static_cast<uint32_t>(segment->physical_offset());
break;
}
}
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 (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());
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(icDword, 0);
link = command->AddLink(0, ltOffset, packer_props);
link->set_sub_value(file->image_base());
AddCommand(icDword, packer_props->dump_size());
for (i = 0; i < packer_info_list.size(); i++) {
command = AddCommand(icDword, 0);
link = command->AddLink(0, ltOffset, packer_info_list[i].data);
link->set_sub_value(file->image_base());
AddCommand(icDword, 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(icDword, 0);
for (i = 0; i < 10; i++) {
AddCommand(icDword, 0);
AddCommand(icDword, 0);
AddCommand(icDword, 0);
}
}
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(icDword, 0) : 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 = 20 + new_import_list.count();
if ((ctx.options.flags & cpStripFixups) == 0) {
PEFixupList *fixup_list = file->pe()->fixup_list();
for (i = 0; i < fixup_list->count(); i++) {
PEFixup *fixup = fixup_list->item(i);
if (!fixup->is_deleted())
k++;
}
}
for (i = 0; i < k; i++) {
AddCommand(icDword, 0);
AddCommand(icDword, 0);
AddCommand(icDword, 0);
}
}
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(icDword, 0) : NULL;
if (loader_crc_size_entry_)
loader_crc_size_entry_->include_option(roCreateNewBlock);
loader_crc_hash_entry_ = loader_crc_entry_ ? AddCommand(icDword, 0) : 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_section_list.size(); i++) {
segment = writable_section_list[i];
AddCommand(icDword, segment->address() - file->image_base());
AddCommand(icDword, segment->size());
AddCommand(icDword, 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 (i = 0, import_index = 0; i < new_import_list.count(); i++) {
import = new_import_list.item(i);
if (import->count() == 0)
continue;
import_function = import->item(0);
command = AddCommand(icDword, 0);
link = command->AddLink(0, ltOffset, import_function_info_list[import_index].thunk);
link->set_sub_value(file->image_base());
AddCommand(icDword, import_function->address() - file->image_base());
AddCommand(icDword, import->count() * OperandSizeToValue(file->pe()->cpu_address_size()));
import_index += import->count();
}
command = (count() == index) ? NULL : item(index);
if (command)
command->include_option(roCreateNewBlock);
loader_info_list.push_back(LoaderInfo(command, (count() - index) * OperandSizeToValue(osDWord)));
index = count();
if (il_import) {
std::vector<ImportDelegateInfo> info_list = il_import->info_list();
for (i = 0; i < info_list.size(); i++) {
ImportDelegateInfo info = info_list[i];
AddCommand(icDword, info.method->id() ^ string_key);
AddCommand(icDword, info.invoke->id() ^ string_key);
AddCommand(icDword, info.call_type);
}
}
command = (count() == index) ? NULL : item(index);
if (command)
command->include_option(roCreateNewBlock);
loader_info_list.push_back(LoaderInfo(command, (count() - index) * OperandSizeToValue(osDWord)));
loader_info_list.push_back(LoaderInfo(NULL, 0));
// create memory CRC info for loader
if (il_crc) {
command = il_crc->table_entry();
i = static_cast<size_t>(il_crc->size_entry()->operand_value());
} else {
command = NULL;
i = 0;
}
loader_info_list.push_back(LoaderInfo(command, i));
// create strings for loader
std::map<uint32_t, ILCommand *> 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 {0}").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_NTDLL_NAME] = AddCommand(EncryptString("ntdll.dll", 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_NT_CLOSE] = AddCommand(EncryptString("NtClose", string_key));
loader_string_list[FACE_NT_VIRTUAL_PROTECT_NAME] = AddCommand(EncryptString("NtProtectVirtualMemory", string_key));
loader_string_list[FACE_NT_ALLOCATE_VIRTUAL_MEMORY_NAME] = AddCommand(EncryptString("NtAllocateVirtualMemory", string_key));
loader_string_list[FACE_NT_FREE_VIRTUAL_MEMORY_NAME] = AddCommand(EncryptString("NtFreeVirtualMemory", string_key));
loader_string_list[FACE_NT_UNMAP_VIEW_OF_SECTION] = AddCommand(EncryptString("NtUnmapViewOfSection", string_key));
loader_string_list[FACE_NT_OPEN_FILE_NAME] = AddCommand(EncryptString("NtOpenFile", string_key));
loader_string_list[FACE_NT_RAISE_HARD_ERROR_NAME] = AddCommand(EncryptString("NtRaiseHardError", string_key));
loader_string_list[FACE_NT_CREATE_SECTION_NAME] = AddCommand(EncryptString("NtCreateSection", string_key));
loader_string_list[FACE_KERNEL32_NAME] = AddCommand(EncryptString("kernel32.dll", 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_MAP_VIEW_OF_SECTION] = AddCommand(EncryptString("MapViewOfFile", string_key));
for (std::map<uint32_t, ILCommand *>::const_iterator it = loader_string_list.begin(); it != loader_string_list.end(); it++) {
it->second->include_option(roCreateNewBlock);
}
// append loader
old_count = count();
runtime_function_list = reinterpret_cast<ILFunctionList *>(runtime->function_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()));
}
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);
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()));
if (src_link->base_function_info())
dst_link->set_base_function_info(function_info_list()->GetItemByAddress(src_link->base_function_info()->begin()));
}
command = dst_command;
if (command->type() == icLdc_i4) {
uint32_t value = static_cast<uint32_t>(command->operand_value());
if ((value & 0xFFFF0000) == 0xFACE0000) {
switch (value) {
case FACE_LOADER_OPTIONS:
value = 0;
if (ctx.options.flags & cpMemoryProtection)
value |= LOADER_OPTION_CHECK_PATCH;
if (ctx.options.flags & cpCheckDebugger)
value |= LOADER_OPTION_CHECK_DEBUGGER;
if (ctx.options.flags & cpCheckKernelDebugger)
value |= LOADER_OPTION_CHECK_KERNEL_DEBUGGER;
if (ctx.options.flags & cpCheckVirtualMachine)
value |= LOADER_OPTION_CHECK_VIRTUAL_MACHINE;
command->set_operand_value(0, value);
command->CompileToNative();
break;
case FACE_STRING_DECRYPT_KEY:
command->set_operand_value(0, 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[(value & 0xff) >> 1].data;
if (dst_command) {
link = command->AddLink(0, ltOffset, dst_command);
link->set_sub_value(file->image_base());
} else {
command->set_operand_value(0, 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(0, loader_info_list[(value & 0xff) >> 1].size);
command->CompileToNative();
break;
case FACE_LOADER_CRC_INFO_SIZE:
if (loader_crc_size_entry_) {
link = command->AddLink(0, ltOffset, loader_crc_size_entry_);
link->set_sub_value(file->image_base());
} else {
command->set_operand_value(0, 0);
command->CompileToNative();
}
break;
case FACE_LOADER_CRC_INFO_HASH:
if (loader_crc_hash_entry_) {
link = command->AddLink(0, ltOffset, loader_crc_hash_entry_);
link->set_sub_value(file->image_base());
} else {
command->set_operand_value(0, 0);
command->CompileToNative();
}
break;
case FACE_FILE_CRC_INFO_SIZE:
if (file_crc_size_entry_) {
link = command->AddLink(0, ltOffset, file_crc_size_entry_);
link->set_sub_value(file->image_base());
} else {
command->set_operand_value(0, 0);
command->CompileToNative();
}
break;
case FACE_MEMORY_CRC_INFO_HASH:
command->set_operand_value(0, il_crc ? il_crc->hash_entry()->operand_value() : 0);
command->CompileToNative();
break;
case FACE_CRC_INFO_SALT:
command->set_operand_value(0, file->function_list()->crc_cryptor()->item(0)->value());
command->CompileToNative();
break;
case FACE_FILE_BASE:
command->Init(icLdc_i8, file->image_base());
command->CompileToNative();
break;
case FACE_TLS_INDEX_INFO:
command->set_operand_value(0, 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_SESSION_KEY:
case FACE_VAR_LOADER_STATUS:
case FACE_VAR_SERVER_DATE:
command->set_operand_value(j, ctx.runtime_var_index[(value & 0xff) >> 4]);
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_SERVER_DATE_SALT:
command->set_operand_value(j, ctx.runtime_var_salt[value & 0xff]);
command->CompileToNative();
break;
default:
std::map<uint32_t, ILCommand *>::const_iterator it = loader_string_list.find(value);
if (it != loader_string_list.end()) {
link = command->AddLink(0, ltOffset, it->second);
link->set_sub_value(file->image_base());
} else {
throw std::runtime_error(string_format("Unknown loader string: %X", 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()));
if (info->data_entry())
info->set_data_entry(GetCommandByAddress(info->data_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) {
if (dst_link->to_address())
dst_link->set_to_command(GetCommandByAddress(dst_link->to_address()));
}
}
// create code for <Module>::.cctor()
old_count = count();
command = AddCommand(icComment, 0);
Data data;
data.PushByte(0);
command->set_dump(data.data(), data.size());
command->set_alignment(4);
command = AddCommand(icCall, 0);
command->AddLink(0, ltCall, GetCommandByAddress(runtime->export_list()->GetAddressByType(atSetupImage)));
// search user <Module>::.cctor
ILMethodDef *module_cctor = runtime->entry_point_method();
ILTypeDef *module = module_cctor->declaring_type();
ILTable *table = file->command_list()->table(ttMethodDef);
for (i = table->IndexOf(module->method_list()); i < table->count(); i++) {
ILMethodDef *method = reinterpret_cast<ILMethodDef *>(table->item(i));
if (method->declaring_type() != module || method == module_cctor)
break;
if (method->name() == ".cctor") {
method->set_flags((CorMethodAttr)(method->flags() & ~(mdSpecialName | mdRTSpecialName)));
file->RenameToken(method);
command = AddCommand(icCall, method->id());
break;
}
}
AddCommand(icRet, 0);
FunctionInfo *info = function_info_list()->Add(0, 0, btValue, 1, 0, 0, file->runtime_function_list()->Add(0, 0, 0, runtime->entry_point_method()), item(old_count));
AddressRange *range = info->Add(0, 0, NULL, NULL, NULL);
for (i = old_count; i < count(); i++) {
item(i)->set_address_range(range);
}
for (i = 0; i < count(); i++) {
command = item(i);
command->CompileToNative();
}
// prepare ranges
std::vector<IFunction *> function_list = ctx.file->function_list()->processor_list();
function_list.push_back(this);
for (i = 0; i < function_list.size(); i++) {
ILFunction *func = reinterpret_cast<ILFunction *>(function_list[i]);
func->range_list()->Prepare();
func->function_info_list()->Prepare();
}
PrepareExtCommands(ctx);
for (i = 0; i < link_list()->count(); i++) {
CommandLink *link = link_list()->item(i);
link->from_command()->PrepareLink(ctx);
}
return true;
}
bool NETLoader::Compile(const CompileContext &ctx)
{
size_t i, j;
std::vector<CommandBlock*> block_list;
ILCommand *command;
std::vector<IFunction *> function_list = ctx.file->function_list()->processor_list();
for (i = 0; i < function_list.size(); i++) {
function_list[i]->set_need_compile(true);
}
function_list.push_back(this);
// update tokens
for (i = 0; i < function_list.size(); i++) {
ILFunction *func = reinterpret_cast<ILFunction *>(function_list[i]);
for (j = 0; j < func->count(); j++) {
command = func->item(j);
TokenReference *token_reference = command->token_reference();
if (!token_reference)
continue;
uint32_t id = token_reference->owner()->owner()->id();
if (command->type() == icComment) {
Data data;
data.PushDWord(id);
command->set_dump(data.data(), data.size());
}
else {
command->set_operand_value(0, id);
command->CompileToNative();
}
}
}
if (!ILFunction::Compile(ctx))
return false;
ILFunction::AfterCompile(ctx);
for (i = 0; i < count(); i++) {
command = item(i);
if (!command->block() || (command->block()->type() & mtExecutable) == 0 || !command->token_reference())
continue;
ILToken *token = command->token_reference()->owner()->owner();
if (token->type() == ttStandAloneSig) {
ILTable *table = token->owner();
uint32_t id = token->type() | 1;
for (j = 0; j < table->count(); j++) {
ILToken *tmp = table->item(j);
if (tmp == token)
break;
if (!tmp->is_deleted())
id++;
}
if (token->id() != id) {
token->set_value(TOKEN_VALUE(id));
command->set_operand_value(0, id);
command->CompileToNative();
}
}
}
for (i = 0; i < function_list.size(); i++) {
IFunction *func = function_list[i];
for (j = 0; j < func->block_list()->count(); j++) {
block_list.push_back(func->block_list()->item(j));
}
}
for (i = 0; i < block_list.size(); i++) {
std::swap(block_list[i], block_list[rand() % block_list.size()]);
}
if (ctx.file->runtime_function_list() && ctx.file->runtime_function_list()->count()) {
// sort blocks by address range
std::sort(block_list.begin(), block_list.end(), CommandBlockListCompareHelper());
}
for (i = 0; i < block_list.size(); i++) {
block_list[i]->Compile(*ctx.manager);
}
for (i = 0; i < function_list.size(); i++) {
function_list[i]->CompileInfo(ctx);
}
for (i = 0; i < function_list.size(); i++) {
function_list[i]->CompileLinks(ctx);
}
return true;
}
size_t NETLoader::WriteToFile(IArchitecture &file)
{
size_t res = BaseFunction::WriteToFile(file);
if (pe_entry_) {
PEArchitecture *pe = reinterpret_cast<NETArchitecture &>(file).pe();
if (pe->cpu_address_size() == osDWord) {
IFixup *fixup = pe->fixup_list()->AddDefault(osDWord, true);
fixup->set_address(pe_entry_->address() + pe_entry_->dump_size());
}
}
return res;
}