aboutsummaryrefslogtreecommitdiff
path: root/core/il.cc
diff options
context:
space:
mode:
Diffstat (limited to 'core/il.cc')
-rw-r--r--core/il.cc7841
1 files changed, 7841 insertions, 0 deletions
diff --git a/core/il.cc b/core/il.cc
new file mode 100644
index 0000000..ee8f896
--- /dev/null
+++ b/core/il.cc
@@ -0,0 +1,7841 @@
+#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;
+} \ No newline at end of file