#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(operand_value_))); break; case InlineVar: res.append(string_format(" %.4X", static_cast(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(operand_value_))); break; default: res.append(string_format(" %.8X", static_cast(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(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(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(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(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(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(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(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(token); res.value = string_format("%c \"%s\"", 3, str->name().c_str()); res.type = ttString; } break; case ttMethodDef: { ILMethodDef *method = reinterpret_cast(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(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(operand_value_)); break; case InlineVar: PushWord(static_cast(operand_value_)); break; case InlineI8: case InlineR: PushQWord(operand_value_); break; case InlineSwitch: PushDWord(static_cast(operand_value_)); break; case ShortInlineBrTarget: PushByte(static_cast(operand_value_ - next_address() - 1)); break; case InlineBrTarget: PushDWord(static_cast(operand_value_ - next_address() - 4)); break; default: PushDWord(static_cast(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(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(internal_link->from_command()); switch (internal_link->type()) { case vlCRCTableAddress: value = reinterpret_cast(ctx.file->function_list())->runtime_crc_table()->entry()->address() - ctx.file->image_base(); break; case vlCRCTableCount: value = reinterpret_cast(ctx.file->function_list())->runtime_crc_table()->region_count(); break; default: ILCommand *command = reinterpret_cast(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(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(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(operand_value_); ILMetaData *meta = dynamic_cast(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(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(ReadByte(file)); operand_value_ += next_address(); break; case InlineBrTarget: // 32-bit integer branch target operand_value_ = static_cast(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(file).command_list()->token(static_cast(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(file).command_list()->token(static_cast(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(token)->parent(); ILSignature *signature; switch (token->type()) { case ttMethodDef: signature = reinterpret_cast(token)->signature(); break; case ttMemberRef: signature = reinterpret_cast(token)->signature(); break; case ttStandAloneSig: signature = reinterpret_cast(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(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(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(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(-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(-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(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(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(-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(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(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(ctx.file->runtime_function_list()); ILMetaData *meta = reinterpret_cast(ctx.runtime->command_list()); ILMethodDef *decrypt_method = meta->GetMethod(address); if (!decrypt_method) return false; ILFunction *decrypt_func = reinterpret_cast(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(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(src_command->Clone(this)); dst_command->set_address(0); if (static_cast(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(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 variable_map; NETRuntimeFunction *runtime_func = reinterpret_cast(info->source()); ILStandAloneSig *locals = runtime_func->method()->locals(); std::vector 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 element_list; std::vector 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::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(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(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(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(info->end() - info->begin()); command = reinterpret_cast(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(range->begin_entry()); command->set_operand_value(0, range->begin() - base_value); command->CompileToNative(); } if (range->size_entry()) { command = reinterpret_cast(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 &stack_map) { size_t i, j; ILCommand *command, *entry, *link_command; std::set 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(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(link->to_command()); entry_stack.insert(entry); stack_map[entry] = 1; break; case ltFinallyBlock: entry = reinterpret_cast(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::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::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(command->operand_value()); for (j = 0; j < case_count; j++) { ILCommand *case_command = item(i + 1 + j); link_list.insert(reinterpret_cast(case_command->link()->to_command())); } } else { if (command->link() && (command->link()->type() == ltJmp || command->link()->type() == ltJmpWithFlag)) link_list.insert(reinterpret_cast(command->link()->to_command())); } for (std::set::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 variables_map; uint32_t value, old_value, bit_mask; std::map 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(info->source())->method()->locals(); entry = reinterpret_cast(info->entry()); variables_map[entry] = locals ? locals->signature() : NULL; stack_map[entry] = 0; } CalcStack(stack_map); int stack; std::list new_command_list; std::vector insert_command_list; std::vector predicate_list; std::map value_list; std::map > value_list_map; ILSignature *variables = NULL; size_t orig_count = count(); std::vector 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::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(command->link()->to_command()) : NULL; if (command->section_options() & (rtLinkedToInt | rtLinkedToExt)) { std::map dst_value_list; if ((command->section_options() & rtLinkedToExt) == 0) { std::map >::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::const_iterator d = dst_value_list.begin(); d != dst_value_list.end(); d++) { index = d->first; value = d->second; std::map::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::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::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(-1); break; case icLdc_i4_s: old_value = static_cast(command->operand_value()); break; default: old_value = static_cast(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(command->operand_value()); std::set link_command_list; for (j = 0; j < case_count; j++) { ILCommand *case_command = item(i + 1 + j); link_command_list.insert(reinterpret_cast(case_command->link()->to_command())); } for (std::set::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 >::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 >::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 dst_value_list = it->second; for (std::map::const_iterator d = dst_value_list.begin(); d != dst_value_list.end(); d++) { index = d->first; value = d->second; std::map::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(info->entry()); if (entry) { ILStandAloneSig *locals = reinterpret_cast(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(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(info->data_entry()); if (!data_entry) continue; uint32_t flags = static_cast(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(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(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(command->operand_value()); if (variable_index < 0x100) { command->Init(icLdloca_s, variable_index); command->CompileToNative(); } break; case icStloc: variable_index = static_cast(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 param_list; ILSignature *locals; ILCommand *data_entry; FunctionEntryInfo() : method(NULL), ret(NULL), locals(NULL), data_entry(NULL) { } FunctionEntryInfo(ILMethodDef *method_, ILToken *ret_, std::vector 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 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(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(info->data_entry()); method = reinterpret_cast(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 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(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(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 try_list; std::map 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::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 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(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(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(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(try_address - image_base)); command->AddVMCommand(ctx, icDword, static_cast(try_address - image_base + catch_try_length->operand_value())); command->AddVMCommand(ctx, icDword, 0, 0, NULL, catch_handler_offset->link() ? reinterpret_cast(catch_handler_offset->link()->to_command()) : NULL); if (catch_filter->link()) { command->AddVMCommand(ctx, icDword, 0, 0, NULL, reinterpret_cast(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 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::const_iterator it = std::find(param_list.begin(), param_list.end(), element); if (it != param_list.end()) { index = static_cast(it - param_list.begin()); command->AddVMCommand(ctx, icDup, 0); command->AddVMCommand(ctx, icLdc_i4, static_cast(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(j); } else { index = static_cast(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(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::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(temp_variable_index)); break; case icLdloc: case icLdloc_s: it = variable_map.find(static_cast(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(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(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(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(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(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::const_iterator it = try_list.find(command->address()); if (it != try_list.end()) { command->AddVMCommand(ctx, icLdc_i4, static_cast(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(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(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(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(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(command->ReadValueFromFile(file, osDWord)); bool fat = (flags & CorILMethod_Sect_FatFormat) != 0; uint32_t data_size = fat ? (flags >> 8) : static_cast(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(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(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(file).command_list()->token(static_cast(command->operand_value())); uint64_t to_address = 0; LinkType link_type = ltNone; if (token && token->type() == ttMethodDef) { ILMethodDef *method = reinterpret_cast(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(BaseFunction::GetCommandByAddress(address)); } ILCommand *ILFunction::GetCommandByNearAddress(uint64_t address) const { return reinterpret_cast(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(BaseFunctionList::item(index)); } ILFunction *ILFunctionList::GetFunctionByAddress(uint64_t address) const { return reinterpret_cast(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(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(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 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(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(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 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(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(token)->declaring_type()->full_name() == "VMProtect.Core") command->Init(icNop); break; case ttMethodDef: if (reinterpret_cast(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 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(token)->declaring_type()); } } } for (std::set::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(file).command_list()->table(ttMethodDef); for (i = 0; i < method_table->count(); i++) { ILMethodDef *method = reinterpret_cast(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(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(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(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 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((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(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(p[j] ^ (_rotl32(data_key, static_cast(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(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(_rotl32(data_key, static_cast(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(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((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(p[i] ^ (_rotl32(data_key, static_cast(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(_rotl32(data_key, static_cast(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(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((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(_rotl32(data_key, static_cast(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(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 hwid; hwid.resize(size); VMProtectGetCurrentHWID(hwid.data(), (int)hwid.size()); std::vector binary; binary.resize(size); Base64Decode(hwid.data(), hwid.size(), binary.data(), size); Data data; data.PushBuff(binary.data(), binary.size()); data.resize(64); trial_hwid_size_ = static_cast(std::min(size, data.size())); trial_hwid_entry_ = AddCommand(data); trial_hwid_entry_->include_option(roCreateNewBlock); } #ifdef ULTIMATE else if (!ctx.options.hwid.empty()) { std::string hwid = ctx.options.hwid; size_t size = hwid.size(); std::vector binary; binary.resize(size); Base64Decode(hwid.data(), hwid.size(), binary.data(), size); if (size & 3) { Notify(mtError, NULL, "Invalid HWID"); return false; } Data data; data.PushBuff(binary.data(), binary.size()); data.resize(64); trial_hwid_size_ = static_cast(std::min(size, data.size())); trial_hwid_entry_ = AddCommand(data); trial_hwid_entry_->include_option(roCreateNewBlock); } #endif for (i = 0; i < count(); i++) { item(i)->CompileToNative(); } // setup faces for common runtime functions ILCRCTable *il_crc = reinterpret_cast(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(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 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(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(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 crc_info_list; std::vector dump; for (size_t i = 0; i < region_info_list_.size(); i++) { RegionInfo region_info = region_info_list_[i]; dump.resize(region_info.size); if (region_info.is_self_crc) { memcpy(&dump[0], reinterpret_cast(&crc_info_list[0]) + region_info.address, dump.size()); region_info.address += address; } else { file.AddressSeek(region_info.address); file.Read(&dump[0], dump.size()); } CRCInfo crc_info(static_cast(region_info.address - file.image_base()), dump); if (cryptor_) { crc_info.pod.address = static_cast(cryptor_->Encrypt(crc_info.pod.address)); crc_info.pod.size = static_cast(cryptor_->Encrypt(crc_info.pod.size)); } crc_info.pod.hash = 0 - crc_info.pod.hash; crc_info_list.push_back(crc_info); } file.AddressSeek(address); file.Write(&crc_info_list[0], crc_info_list.size() * sizeof(CRCInfo::POD)); } return res; } /** * 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 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(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(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(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(token); if (stack[1]->command()->type() == icLdstr) { if (ILEvent *event = type_def->GetEvent(reinterpret_cast(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(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(token); ILTable *ref_table = file.command_list()->table(ttProperty); for (size_t r = 0; r < ref_table->count(); r++) { ILProperty *property = reinterpret_cast(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(token)->parent(); switch (token->type()) { case ttMemberRef: return reinterpret_cast(token)->full_name(); } } return std::string(); } /** * ILCommandBlock */ ILCommandBlock::ILCommandBlock() : ObjectList(), 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::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(token)->declaring_type(); case ttMemberRef: return reinterpret_cast(token)->declaring_type(); } } break; } return NULL; } bool ILCommandBlock::Parse(ILFunction &func) { size_t i, j, c; ILCommand *command; std::set entry_list; std::vector command_stack; std::map > 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(info->entry()); entry_list.insert(command); method_ = reinterpret_cast(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::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 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(ctx.file); NETArchitecture *runtime = reinterpret_cast(ctx.runtime); ILTypeDef *module = reinterpret_cast(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 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(token)->signature(); break; case ttStandAloneSig: signature = reinterpret_cast(token)->signature(); break; case ttField: signature = reinterpret_cast(token)->signature(); break; case ttMethodDef: signature = reinterpret_cast(token)->signature(); break; } if (!signature) continue; std::vector 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 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(import_token)->signature(); declaring_type = reinterpret_cast(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 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(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(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::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::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(value >> 24) | 0xc0); data.push_back(static_cast(value >> 16)); data.push_back(static_cast(value >> 8)); data.push_back(static_cast(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(iat_index++)); AddCommand(icLdelem_ref, 0); for (k = 0; k < proxy_method->signature()->count(); k++) { AddCommand(icLdarg, static_cast(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(processor_->function_info_list()->item(0)->source())->method() : NULL; invoke_ = processor_->function_info_list()->count() > 1 ? reinterpret_cast(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(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(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(key >> 32); uint32_t key1 = static_cast(key); buffer[0] = _rotr32(buffer[0] - key0, 7) ^ key1; buffer[1] = _rotr32(buffer[1] - key0, 11) ^ key1; buffer[2] = _rotr32(buffer[2] - key0, 17) ^ key1; buffer[3] = _rotr32(buffer[3] - key0, 23) ^ key1; } void 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(value); break; case osQWord: *reinterpret_cast(&crypted_value[2]) = value; break; } uint32_t dw = 0; for (i = 1; i < 4; i++) { dw += crypted_value[i]; } crypted_value[0] = 0 - dw; EncryptBuffer(crypted_value, vm_command.crypt_key()); 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(vm_command.value())); break; case icLdc_i4: opcode = GetOpcode(vm_command.command_type()); dump.PushDWord(static_cast(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(value)); break; case icLdc_r8: opcode = GetOpcode(vm_command.command_type()); dump.PushQWord(value); break; case icByte: dump.PushByte(static_cast(vm_command.value())); break; case icWord: dump.PushWord(static_cast(vm_command.value())); break; case icDword: dump.PushDWord(static_cast(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 *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(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(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 import_info_list; std::vector 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(ctx.file); runtime = reinterpret_cast(ctx.runtime); il_crc = reinterpret_cast(file->function_list())->crc_table(); il_import = reinterpret_cast(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(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((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((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(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::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(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 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 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 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(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(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::iterator it = std::find(packer_info_list.begin(), packer_info_list.end(), segment); if (it != packer_info_list.end()) { physical_size = static_cast(it->address - segment->address()); is_packed = true; } if (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 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((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((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 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(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 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::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(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(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::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 ::.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 ::.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(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 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(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 block_list; ILCommand *command; std::vector 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(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(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; }