7841 lines
239 KiB
C++
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;
|
|
} |