【Android安全】VMP加壳示例

一个很好的、通俗易懂的安卓VMP原理介绍
参见:https://www.cnblogs.com/theseventhson/p/14933920.html

VMP中的解释器的完整代码:

#include <jni.h>
#include <string>

// 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.
};
/*123cdc: 92000606            |0000: mul-int v0, v6, v6
123ce0: 92010607            |0002: mul-int v1, v6, v7
123ce4: 91020607            |0004: sub-int v2, v6, v7
123ce8: 93030607            |0006: div-int v3, v6, v7
123cec: 90040001            |0008: add-int v4, v0, v1
123cf0: b024                |000a: add-int/2addr v4, v2
123cf2: b034                |000b: add-int/2addr v4, v3
123cf4: 0f04                |000c: return v4*/
//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};
/*const unsigned char Compute[] = { 0x08, 0x00,  //寄存器使用的个数
                                    0x03, 0x00,  //参数个数
                                    0x00, 0x00,  //调用其他方法时使用寄存器的个数
                                    0x00, 0x00,  //try catch个数
                                    0x6e, 0x77, 0x14,0x00,  //指令调试信息偏移
                                    0x0d, 0x00, 0x00, 0x00, //指令集个数,以2字节为单位;这里是d,那么指令总长度是13*2=26个字节,可以用这个确认函数结尾
                                    0x92, 0x00, 0x06, 0x06, //指令开始了
                                    0x92, 0x01, 0x06, 0x07,
                                    0x91, 0x02, 0x06, 0x07,
                                    0x93, 0x03, 0x06, 0x07,
                                    0x90,  0x04, 0x00, 0x01,
                                    0xb0, 0x24,
                                    0xb0, 0x34,
                                    0x0f, 0x04};
*/
extern "C" JNIEXPORT jstring JNICALL
Java_com_kanxue_vmpprotect_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {
    
    
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

int myinterpreter(JNIEnv *env, jobject obj, jint a, jint b) {
    
    
/*          .prologue
            .insnsSize 13 (16-bit)
            .registers 8 [ v0  v1  v2  v3  v4  v5  v6  v7  ]*/

    CodeItem *codeItem = (CodeItem *) Compute;
    int registersize = codeItem->registers_size_;
    int result = 0;
    int *VREG = reinterpret_cast<int *>(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<unsigned char *>(address + 16);//指令集的地址
        while (true) {
    
    
            unsigned char op = *opOffset;
            switch (op) {
    
    
                /*case 0x90: {//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 0x91: {//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 0x92: {//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 0x93: {//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 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;
}

猜你喜欢

转载自blog.csdn.net/qq_39441603/article/details/134002821