
先明白物理机三级流水线概念,分为读取、解析、执行。读取什么?字符串!解析是什么?解释器!执行是什么?CPU!
然后寻找定量,再执行过程中什么想对固定?CPU指令集、原生解释器、原生字符串。
最后提高静态分析原生字符串难度,则会其进行转换。转换过程涉及映射表和解释器,则称为VMP。
在实际寻找映射表和编译器中,肯定会遇到防护手段。
一位老师傅写好简单的编译器如下,这是一套简易版的编译器,使用JNI接口。实现比较经典,首先定义映射表,就是Compute[] 部分,然后Java_com_vmpprotect_Compute_compute使用JNI接口调用myinterpreter,myinterpreter函数中进行解释器。
#include#include // Raw code_item. struct CodeItem { uint16_t registers_size_; // the number of registers used by this code // (locals + parameters) uint16_t ins_size_; // the number of words of incoming arguments to the method // that this code is for uint16_t outs_size_; // the number of words of outgoing argument space required // by this code for method invocation uint16_t tries_size_; // the number of try_items for this instance. If non-zero, // then these appear as the tries array just after the // insns in this instance. uint32_t debug_info_off_; // file offset to debug info stream uint32_t insns_size_in_code_units_; // size of the insns array, in 2 byte code units uint16_t insns_[1]; // actual array of bytecode. }; //90 20 //91 21 //92 22 //93 23 const unsigned char Compute[] = {0x08, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x77, 0x14,0x00, 0x0d, 0x00, 0x00, 0x00, 0x22, 0x00, 0x06, 0x06, 0x22, 0x01,0x06, 0x07, 0x21, 0x02, 0x06, 0x07, 0x23, 0x03, 0x06, 0x07, 0x20,0x04, 0x00, 0x01, 0xb0, 0x24, 0xb0, 0x34, 0x0f, 0x04}; extern "C" JNIEXPORT jstring JNICALL Java_com_kanxue_vmpprotect_MainActivity_stringFromJNI( JNIEnv *env, jobject ) { std::string hello = "Hello from C++"; return env->NewStringUTF(hello.c_str()); } int myinterpreter(JNIEnv *env, jobject obj, jint a, jint b) { CodeItem *codeItem = (CodeItem *) Compute; int registersize = codeItem->registers_size_; int result = 0; int *VREG = reinterpret_cast (malloc(sizeof(int) * registersize)); if (VREG != nullptr) { memset(VREG, 0, registersize * sizeof(int)); int insNum = codeItem->ins_size_;//参数的个数 int startIndex = registersize - insNum;//总的寄存器数量减去参数个数,剩下的才是解释器能自由使用的寄存器个数 VREG[startIndex] = 0; VREG[++startIndex] = a; VREG[++startIndex] = b; int pc = 0; unsigned long address = (unsigned long) Compute; unsigned char *opOffset = reinterpret_cast (address + 16);//指令集的地址 while (true) { unsigned char op = *opOffset; switch (op) { case 0x20: {//90040001 |0008: add-int v4, v0, v1 unsigned char des = *(opOffset + 1); unsigned char arg0 = *(opOffset + 2); unsigned char arg1 = *(opOffset + 3); VREG[des] = VREG[arg0] + VREG[arg1]; opOffset = opOffset + 4; break; } case 0x21: {//91020607 |0004: sub-int v2, v6, v7 unsigned char des = *(opOffset + 1); unsigned char arg0 = *(opOffset + 2); unsigned char arg1 = *(opOffset + 3); VREG[des] = VREG[arg0] - VREG[arg1]; opOffset = opOffset + 4; break; } case 0x22: {//92010607 |0002: mul-int v1, v6, v7 unsigned char des = *(opOffset + 1); unsigned char arg0 = *(opOffset + 2); unsigned char arg1 = *(opOffset + 3); VREG[des] = VREG[arg0] * VREG[arg1]; opOffset = opOffset + 4; break; } case 0x23: {//93030607 |0006: div-int v3, v6, v7 unsigned char des = *(opOffset + 1); unsigned char arg0 = *(opOffset + 2); unsigned char arg1 = *(opOffset + 3); VREG[des] = VREG[arg0] / VREG[arg1]; opOffset = opOffset + 4; break; } case 0xb0: {//b024 |000a: add-int/2addr v4, v2 unsigned char des = *(opOffset + 1); int arg0 = des & 0x0F; int arg1 = des >> 4; VREG[arg0] = VREG[arg0] + VREG[arg1]; opOffset = opOffset + 2; break; } case 0x0f: {//123cf4: 0f04 |000c: return v4*/ unsigned char des = *(opOffset + 1); return VREG[des]; } } } } } extern "C" JNIEXPORT jint JNICALL Java_com_vmpprotect_Compute_compute(JNIEnv *env, jobject obj, jint a, jint b) { int result = myinterpreter(env, obj, a, b); return result; }