吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 11178|回复: 56
收起左侧

[C&C++ 原创] 【VC】【笔记】自写vmp壳子编写报告(一)

  [复制链接]
舒默哦 发表于 2020-9-23 19:36
本帖最后由 舒默哦 于 2020-9-24 10:35 编辑



前言:
  • 第一次设计vmp框架和编写,因设计得有点匆忙,导致后面茶饭不思,一直在改bug,现在基本上处理好了。在这里吐槽一下,如果时间充足,至少框架会设计的更好一点。
  • 因为要兼容64位,汇编引擎我用的是XEDParse,反汇编引擎用的BeaEngine。另外,这个vmp不能对驱动加vm,驱动vm的话,一些处理方法会不一样。
  • 在vmp设计中,我定义了几个模块:指令分析器,垃圾块指令构造器,IAT加密模块,反调试模块。
  • 这几个模块的说明篇幅有点长,这篇文章把指令分析器和垃圾块指令构造器做个说明。



0x00  有些问题的说明。
1、有些奇葩的指令现在仍然无法处理,如下:
[Asm] 纯文本查看 复制代码
mov eax,nextcall   //nextcall是函数地址
mov ecx,nextaddr   //nextaddr是jmp ecx下一行的地址
push ecx
jmp eax
add esp,4

上面这些指令等价于:
mov eax,nextcall
call eax
add esp,4
都是可以处理的,归类于不可模拟指令。

但是下面这种情况,处理起来就有问题
mov ecx,nextaddr //nextaddr是jmp ecx下一行的地址
jmp ecx
add esp,4
....
这个jmp ecx是在函数内跳转,不能归于不可模拟指令。

在函数内跳转,一般情况是 jmp 后面跟的地址,比如
mov eax,nextcall
mov ecx,nextaddr
jmp L11
add esp,4
L11:
    ret
标号L11其实就是地址标号,在vm指令解析器解析指令的时候,L11是随着活动的进行可以传递的属性,方便加了垃圾指令之后,让新地址和旧地址进行匹配,
然后进行回填。而jmp ecx,“ecx”只是一个寄存器,不是地址,即使进行传递,那么在新地址和旧地址进行匹配的时候(即新地址和“ecx”匹配),无法匹配,会出BUG。

2、把一个函数vm的时候,要写开始地址和结尾地址,不写结尾地址的话,那么就要写一个函数来自动识别要vm的函数的结尾地址。以下函数就是自动识别要vm的函数的结尾地址,
主要功能是遇到跳转指令比如JCC或者JMP指令,就记录下来,与后面遇到的ret指令所在的地址进行比较,如果小于ret指令所在的地址,那么,这条ret就是结束地址,否则继续往下判断。
[C++] 纯文本查看 复制代码
struct FUNCANDINSLENGTH
{
    int inslen = 0;//记录指令的条数
    int hcodelength = 0;//记录硬编码长度
    bool istrue = true;//读取指令是否成功
};

//计算函数的长度
FUNCANDINSLENGTH Disassembler_(DWORD virtualaddr,DWORD instruction)
{
    FUNCANDINSLENGTH fuclen;
    int inslength = 0;//记录指令的条数

    vector<DWORD>JccAddr;//记录JCC后面的地址

    DISASM disAsm = { 0 };

    // 3. 配置结构体,初始化反汇编的opcode
    disAsm.EIP = (UIntPtr)instruction; 
    disAsm.VirtualAddr = virtualaddr; // opcode 指令的地址
    disAsm.Archi = 0; // 0 => 32 , 1 => 64
    disAsm.Options = 0x000; // masm 汇编指令格式

    int nCount = 0;// 用于记录在循环当中,反汇编了多少个字节
    int nLen = 0; // 用于记录当前的汇编指令的字节数

    while (true)
    {
        nLen = Disasm(&disAsm); // 每次只反汇编一条汇编指令, 并且返回当前得到的汇编指令的长度
        unsigned int uAddr = disAsm.VirtualAddr;

        printf("%08X | ", uAddr); // 打印地址
        printOpcode((const unsigned char*)disAsm.EIP, nLen); // 打印opcode
        printf(" | %s\n", disAsm.CompleteInstr); // 打印反汇编指令

        if (inslength == 0x1000)
        {//防止死循环
            MessageBoxA(NULL, "未知错误,读取指令失败!!", "提示", MB_OK);
            fuclen.istrue = false;
            return fuclen;
        }

        ++inslength;//记录指令的条数,为后面申请内存提供依据
        nCount += nLen; // 累加已经反汇编的字节数
        disAsm.EIP += nLen; // 定位到下一条汇编指令
        disAsm.VirtualAddr += nLen; // 设置到下一条汇编指令的地址

        //如果遇到jcc指令或者jmp指令,记录后面的地址
        for (int i = 0; i < JCCNUMSS; i++)
        {
            if (0 == stricmp(disAsm.Instruction.Mnemonic, JCCSTR[i]))
            {
                DWORD tempaddr = 0;
                sscanf_s(disAsm.Argument1.ArgMnemonic, "%X", &tempaddr);
                JccAddr.push_back(tempaddr);
                break;
            }
        }

        if (
            (0 == stricmp(disAsm.Instruction.Mnemonic, "ret ")) || 
            (0 == stricmp(disAsm.Instruction.Mnemonic, "retn ")) ||
            (0 == stricmp(disAsm.Instruction.Mnemonic, "int3 "))
            )
        {
            int isretn = 1;
            for (int i = 0; i < JccAddr.size(); i++)
            {
                if ((*(JccAddr.begin()+i)) > disAsm.VirtualAddr- nLen)
                {
                    isretn = 0;
                    break;
                }
            }
            if (isretn || (0 == stricmp(disAsm.Instruction.Mnemonic, "int3 ")))
            {
                fuclen.hcodelength = nCount;
                fuclen.inslen = inslength;
                return fuclen;
            }
        }
    }
}

3、没有处理异常。另外,如果要保护的函数里有检查堆栈的函数,一定要注意标志寄存器的处理问题,比如退出虚拟机的时候,出栈完成了,
后面还有改变标志寄存器的指令,则可以使用xor ecx,ecx(返回值一般是eax,所有可以用ecx寄存器)这指令再平衡回来,因为检查堆栈的函数只检查ZF标志位。


0x01 指令分析器
1、指令分析器的功能就是把要保护的指令,翻译为中间表示,可以用一个结构体来保存这些中间表示和一些需要传递的属性,当然,也可以把指令分析器理解为一个有穷自动机(接收指令 -> 解析指令 -> 中间表示)。我用的是BeaEngine引擎,构造自动机来解析指令的时候就要遵循BeaEngine反汇编引擎的规则,指令分析器的主框架如下:
[Asm] 纯文本查看 复制代码
//解析要保护的指令,翻译为中间表示
void MiddleRepresent(DISASM disAsm)
{
/*----------------------------------------------------------------------------------*/
/*        1、是否有操作3                                                           */
/*----------------------------------------------------------------------------------*/
        if (NO_ARGUMENT != disAsm.Argument3.ArgType)
        {
                switch (disAsm.Argument3.ArgType & 0xF0000000)
                {
                case REGISTER_TYPE: //寄存器
                        break;
                case MEMORY_TYPE: //内存
                        break;
                case CONSTANT_TYPE://常数
                        break;
                default:
                        break;
                }
        }
 
 /*----------------------------------------------------------------------------------*/
/*        2、是否有操作2                                                           */
/*----------------------------------------------------------------------------------*/
        if (NO_ARGUMENT != disAsm.Argument2.ArgType)
        {
                switch (disAsm.Argument2.ArgType & 0xF0000000)
                {
                case REGISTER_TYPE: //寄存器
                        break;
                case MEMORY_TYPE: //内存
                        break;
                case CONSTANT_TYPE://常数
                        break;
                default:
                        break;
                }
        }
 
 /*----------------------------------------------------------------------------------*/
/*        3、是否有操作1                                                           */
/*----------------------------------------------------------------------------------*/
        if (NO_ARGUMENT != disAsm.Argument1.ArgType)
        {
                switch (disAsm.Argument1.ArgType & 0xF0000000)
                {
                case REGISTER_TYPE: //寄存器
                        break;
                case MEMORY_TYPE: //内存
                        break;
                case CONSTANT_TYPE://常数
                        break;
                default:
                        break;
                }
        }
 
 
 /*----------------------------------------------------------------------------------*/
/*        4、处理普通handler                                                           */
/*----------------------------------------------------------------------------------*/

//省略...

/*----------------------------------------------------------------------------------*/
/*        5、判断是否有辅助handler                                                           */
/*----------------------------------------------------------------------------------*/
        if (
                0x10000000 != disAsm.Argument1.ArgType ||
                0x10000000 != disAsm.Argument2.ArgType ||
                0x10000000 != disAsm.Argument3.ArgType
                )
        {

            if (NO_ARGUMENT != disAsm.Argument1.ArgType)
                {
                    switch (disAsm.Argument1.ArgType & 0xF0000000)
                    {
                    case REGISTER_TYPE: //寄存器
                            break;
                    case MEMORY_TYPE: //内存
                            break;
                    case CONSTANT_TYPE://常数
                            break;
                    default:
                            break;
                    }
            }

     }
}

2、指令是从右往左解析的,比如:
[Asm] 纯文本查看 复制代码
mov eax,ecx
翻译为中间表示就是
vPushReg  VR_ecx  //操作2
vPushReg  VR_eax //操作1
vMOV            //普通handler
vPopReg   VR_eax //辅助handler

3、整个指令解析器的构造,如下:
[Asm] 纯文本查看 复制代码
//处理内存操作,把内存翻译为中间表示
void VMLoader2::MemoryMiddle(DISASM disAsm,MEMORYTYPE memtype)
{
        /*
        * vPushImm4
        * vPushReg
        * vMUL_MEM //内存操作专用乘法handler
        * vPushReg
        * vAdd
        * vPushImm4
        * vAdd
        * vWriteMemDs4/2/1
        */
        MIDDLESTRUCT midstr;
        DATATABLE datatbl;
        midstr.originaddr = disAsm.VirtualAddr;
        if (memtype.Scale!=0)
        {
                char vpushreg4[] = "vPushImm4 ";
                printf("%s\n", vpushreg4);
                memcpy(midstr.vmfunc, vpushreg4, sizeof(vpushreg4));
                m_middle.push_back(midstr);//操作码压入中间表示        


                datatbl.data = memtype.Scale;
                datatbl.recodeOaddr = disAsm.VirtualAddr;
                m_datatable.push_back(datatbl);//数据压入数据表

                for (int i = 0; i < REGNUMS; i++)
                {
                        if (memtype.IndexRegister == tempreg[i].index)
                        {
                                char vpushreg4[] = "vPushReg4 ";
                                printf("%s\n", vpushreg4);
                                memcpy(midstr.vmfunc, vpushreg4, sizeof(vpushreg4));
                                m_middle.push_back(midstr);//操作码压入中间表示        

                                DATATABLE datatbl;
                                datatbl.data = i;
                                datatbl.recodeOaddr = disAsm.VirtualAddr;
                                m_datatable.push_back(datatbl);//数据压入数据表

                                break;
                        }
                }

                char vmul_mem[] = "vMUL_MEM ";
                printf("%s\n", vmul_mem);
                memcpy(midstr.vmfunc, vmul_mem, sizeof(vmul_mem));
                m_middle.push_back(midstr);//操作码压入中间表示        
        }
        
        int i = 0;
        for (; i < REGNUMS; i++)
        {
                if (memtype.BaseRegister == tempreg[i].index)
                {
                        char vpushreg4[] = "vPushReg4 ";
                        printf("%s\n", vpushreg4);
                        memcpy(midstr.vmfunc, vpushreg4, sizeof(vpushreg4));
                        m_middle.push_back(midstr);//操作码压入中间表示        

                        DATATABLE datatbl;
                        datatbl.data = i;
                        datatbl.recodeOaddr = disAsm.VirtualAddr;
                        m_datatable.push_back(datatbl);//数据压入数据表
                        break;
                }
        }

        if ((memtype.Scale != 0) && (i != REGNUMS))
        {
                char vadd[] = "vAdd4 ";
                printf("%s\n", vadd);
                memcpy(midstr.vmfunc, vadd, sizeof(vadd));
                m_middle.push_back(midstr);//操作码压入中间表示
        }
        

        if (0 != memtype.Displacement)
        {
                char vpushreg4[] = "vPushImm4 ";
                printf("%s\n", vpushreg4);
                memcpy(midstr.vmfunc, vpushreg4, sizeof(vpushreg4));
                m_middle.push_back(midstr);//操作码压入中间表示        

                datatbl.data = memtype.Displacement;
                m_datatable.push_back(datatbl);//数据压入数据表
        }
        

        if ((0 != memtype.Displacement) && (i != REGNUMS))
        {
                char vadd[] = "vAdd4 ";
                printf("%s\n", vadd);
                memcpy(midstr.vmfunc, vadd, sizeof(vadd));
                m_middle.push_back(midstr);//操作码压入中间表示
        }
}

//解析要保护的指令,翻译为中间表示
void VMLoader2::MiddleRepresent(DISASM disAsm)
{
        MIDDLESTRUCT midstr;
        midstr.originaddr = disAsm.VirtualAddr;
        bool IsSimulation = true;

        //vm的环境准备
        if (start_bool)
        {                
                char vresumestart[] = "VMStartVM_2 ";
                printf("%s\n", vresumestart);
                memcpy(midstr.vmfunc, vresumestart, sizeof(vresumestart));
                m_middle.push_back(midstr);//压入VMStartVM_2
                start_bool = false;
        }
        

/*----------------------------------------------------------------------------------*/
/*        0、判断是否是不可模拟                                                           */
/*----------------------------------------------------------------------------------*/
        for (int i = 0; i < FUNNUMS; i++)
        {
                if (stricmp(disAsm.Instruction.Mnemonic, g_FunName[i].s_opecode) == 0)
                {                        
                        IsSimulation = false;
                        break;
                }
        }
        if (0 == stricmp(disAsm.Instruction.Mnemonic, "jmp ") && ((disAsm.Argument1.ArgType & 0xF0000000)== MEMORY_TYPE)||
                0 == stricmp(disAsm.Instruction.Mnemonic, "push ") && ((disAsm.Argument2.ArgType & 0xF0000000) == MEMORY_TYPE)||
                0 == stricmp(disAsm.Instruction.Mnemonic, "pop ") && ((disAsm.Argument1.ArgType & 0xF0000000) == MEMORY_TYPE)
                )
        {
                IsSimulation = true;
        }
        //0、1 如果是不可模拟指令,处理好后直接返回
        if (IsSimulation)
        {
                char retnotaddr[] = "vRetnNOT_ ";
                printf("%s\n", retnotaddr);
                memcpy(midstr.vmfunc, retnotaddr, sizeof(retnotaddr));
                m_middle.push_back(midstr);//先压入vRetnNOT

                char notsimulate[] = "vNotSimulate ";
                char vresumestartaddr[OPECODELENGTH];
                sprintf(vresumestartaddr, "%X", m_vmps.vresumestartaddr);

                printf("%s\n", notsimulate);
                memcpy(midstr.vmfunc, notsimulate, sizeof(notsimulate));
                memcpy(midstr.param1, disAsm.CompleteInstr, STRUCTIONLENGTH);
                memcpy(midstr.param2, vresumestartaddr, OPECODELENGTH);
                m_middle.push_back(midstr);//再压入不可模拟指令的handler
                
                char vresumestart[] = "vResumeStart_ ";
                printf("%s\n", vresumestart);
                memcpy(midstr.vmfunc, vresumestart, sizeof(vresumestart));
                m_middle.push_back(midstr);//压入vResumeStart_

                return;
        }

/*----------------------------------------------------------------------------------*/
/*        1、是否有操作3                                                           */
/*----------------------------------------------------------------------------------*/
        if (NO_ARGUMENT != disAsm.Argument3.ArgType)
        {
                switch (disAsm.Argument3.ArgType & 0xF0000000)
                {
                case REGISTER_TYPE: //寄存器
                        break;
                case MEMORY_TYPE: //内存
                        break;
                case CONSTANT_TYPE://常数
                        break;
                default:
                        break;
                }
        }

/*----------------------------------------------------------------------------------*/
/*        2、是否有操作2                                                           */
/*----------------------------------------------------------------------------------*/
        if (NO_ARGUMENT != disAsm.Argument2.ArgType)
        {
                switch (disAsm.Argument2.ArgType & 0xF0000000)
                {
                case REGISTER_TYPE: //寄存器
                {
                        for (int i = 0; i < REGNUMS; i++)
                        {
                                if (tempreg[i].index == (disAsm.Argument2.ArgType & 0xFFFF))
                                {
                                        if (0x20 == disAsm.Argument2.ArgSize)
                                        {//32位
                                                char vpushreg4[] = "vPushReg4 ";
                                                printf("%s\n", vpushreg4);
                                                memcpy(midstr.vmfunc, vpushreg4, sizeof(vpushreg4));
                                                m_middle.push_back(midstr);//操作码压入中间表示                                                        
                                        }
                                        else if (0x10 == disAsm.Argument2.ArgSize)
                                        {//16位
                                                char vpushreg4[] = "vPushReg2 ";
                                                printf("%s\n", vpushreg4);
                                                memcpy(midstr.vmfunc, vpushreg4, sizeof(vpushreg4));
                                                m_middle.push_back(midstr);//操作码压入中间表示        
                                        }
                                        else
                                        {//8位(要判断高位还是低位)
                                                for (int i = 0; i < 14; i++)
                                                {
                                                        if (stricmp(disAsm.Argument2.ArgMnemonic, regname_[0][i]) == 0)
                                                        {
                                                                if (i<=3)//小于等于3是低位
                                                                {
                                                                        char vpushreg4[] = "vPushReg1_low ";
                                                                        printf("%s\n", vpushreg4);
                                                                        memcpy(midstr.vmfunc, vpushreg4, sizeof(vpushreg4));
                                                                        m_middle.push_back(midstr);//操作码压入中间表示        
                                                                }
                                                                else
                                                                {
                                                                        char vpushreg4[] = "vPushReg1_above ";
                                                                        printf("%s\n", vpushreg4);
                                                                        memcpy(midstr.vmfunc, vpushreg4, sizeof(vpushreg4));
                                                                        m_middle.push_back(midstr);//操作码压入中间表示        
                                                                }
                                                                break;
                                                        }
                                                }
                                        }
                                        DATATABLE datatbl;
                                        datatbl.data = i;
                                        datatbl.recodeOaddr = disAsm.VirtualAddr;
                                        m_datatable.push_back(datatbl);//数据压入数据表
                                        break;
                                }
                        }
                        
                }
                        break;
                case MEMORY_TYPE: //内存
                {
                        if (0 == stricmp("pop ", disAsm.Instruction.Mnemonic)) break;
                        if (0 == stricmp("ret ", disAsm.Instruction.Mnemonic)) break;

                        MemoryMiddle(disAsm, disAsm.Argument2.Memory);
                        
                        if (0x20 == disAsm.Argument2.ArgSize)
                        {//32位
                                char vReadMem[] = "vReadMemDs4 ";
                                printf("%s\n", vReadMem);
                                memcpy(midstr.vmfunc, vReadMem, sizeof(vReadMem));
                        }
                        else if (0x10 == disAsm.Argument2.ArgSize)
                        {//16位
                                char vReadMem[] = "vReadMemDs2 ";
                                printf("%s\n", vReadMem);
                                memcpy(midstr.vmfunc, vReadMem, sizeof(vReadMem));
                        }
                        else
                        {//8位
                                char vReadMem[] = "vReadMemDs1 ";
                                printf("%s\n", vReadMem);
                                memcpy(midstr.vmfunc, vReadMem, sizeof(vReadMem));
                        }

                        memcpy(midstr.param1, disAsm.Instruction.Mnemonic, 16);//参数一
                        memcpy(midstr.param2, disAsm.Argument2.ArgMnemonic, 32);//参数二
                        m_middle.push_back(midstr);//操作码压入中间表示
                }
                        break;
                case CONSTANT_TYPE://常数
                {
                        DWORD constnums = 0;
                        sscanf(disAsm.Argument2.ArgMnemonic, "%X", &constnums);

                        char vpushimm4[] = "vPushImm4 ";
                        printf("%s\n", vpushimm4);

                        memcpy(midstr.vmfunc, vpushimm4, sizeof(vpushimm4));
                        m_middle.push_back(midstr);//操作码压入中间表示

                        DATATABLE datatbl;
                        datatbl.data = constnums;
                        datatbl.recodeOaddr = disAsm.VirtualAddr;
                        m_datatable.push_back(datatbl);//数据压入数据表

                }
                        break;
                default:
                        break;
                }
        }

/*----------------------------------------------------------------------------------*/
/*        3、是否有操作1                                                           */
/*----------------------------------------------------------------------------------*/
        if (NO_ARGUMENT != disAsm.Argument1.ArgType)
        {
                switch (disAsm.Argument1.ArgType & 0xF0000000)
                {
                case REGISTER_TYPE: //寄存器
                {
                        for (int i = 0; i < REGNUMS; i++)
                        {
                                if (tempreg[i].index == (disAsm.Argument1.ArgType & 0xFFFF))
                                {
                                        if (0x20 == disAsm.Argument1.ArgSize)
                                        {//32位
                                                char vpushreg4[] = "vPushReg4 ";
                                                printf("%s\n", vpushreg4);
                                                memcpy(midstr.vmfunc, vpushreg4, sizeof(vpushreg4));
                                                m_middle.push_back(midstr);//操作码压入中间表示                                                
                                        }
                                        else if (0x10 == disAsm.Argument1.ArgSize)
                                        {//16位
                                                char vpushreg4[] = "vPushReg2 ";
                                                printf("%s\n", vpushreg4);
                                                memcpy(midstr.vmfunc, vpushreg4, sizeof(vpushreg4));
                                                m_middle.push_back(midstr);//操作码压入中间表示
                                        }
                                        else
                                        {//8位(要判断高位还是低位)
                                                for (int i = 0; i < 14; i++)
                                                {
                                                        if (stricmp(disAsm.Argument1.ArgMnemonic, regname_[0][i]) == 0)
                                                        {
                                                                if (i <= 3)//小于等于3是低位
                                                                {
                                                                        char vpushreg4[] = "vPushReg1_low ";
                                                                        printf("%s\n", vpushreg4);
                                                                        memcpy(midstr.vmfunc, vpushreg4, sizeof(vpushreg4));
                                                                        m_middle.push_back(midstr);//操作码压入中间表示        
                                                                }
                                                                else
                                                                {
                                                                        char vpushreg4[] = "vPushReg1_above ";
                                                                        printf("%s\n", vpushreg4);
                                                                        memcpy(midstr.vmfunc, vpushreg4, sizeof(vpushreg4));
                                                                        m_middle.push_back(midstr);//操作码压入中间表示        
                                                                }
                                                                break;
                                                        }
                                                }
                                        }
                                        DATATABLE datatbl;
                                        datatbl.data = i;
                                        datatbl.recodeOaddr = disAsm.VirtualAddr;
                                        m_datatable.push_back(datatbl);//数据压入数据表
                                        break;
                                }
                        }
                }
                        break;
                case MEMORY_TYPE: //内存(操作数1如果是内存,且操作数2不为空,则处理好后直接退出)
                {
                        if (0 == stricmp("push ",disAsm.Instruction.Mnemonic)) break;
        
                        MemoryMiddle(disAsm, disAsm.Argument1.Memory);                        

                        if (NO_ARGUMENT == disAsm.Argument2.ArgType) break;//这步是对待单个操作数的

                        if (0x20 == disAsm.Argument1.ArgSize)
                        {//32位
                                char vWriteMem[] = "vWriteMemDs4 ";
                                printf("%s\n", vWriteMem);
                                memcpy(midstr.vmfunc, vWriteMem, sizeof(vWriteMem));                                
                        }
                        else if (0x10 == disAsm.Argument1.ArgSize)
                        {//16位
                                char vWriteMem[] = "vWriteMemDs2 ";
                                printf("%s\n", vWriteMem);
                                memcpy(midstr.vmfunc, vWriteMem, sizeof(vWriteMem));
                        }
                        else
                        {//8位
                                char vWriteMem[] = "vWriteMemDs1 ";
                                printf("%s\n", vWriteMem);
                                memcpy(midstr.vmfunc, vWriteMem, sizeof(vWriteMem));
                        }
                        
                        memcpy(midstr.param1, disAsm.Instruction.Mnemonic, 16);//参数一
                        memcpy(midstr.param2, disAsm.Argument1.ArgMnemonic, 32);//参数二
                        m_middle.push_back(midstr);//操作码压入中间表示

                        return;
                }
                        break;
                case CONSTANT_TYPE://常数
                {
                        DWORD constnums = 0;
                        sscanf(disAsm.Argument1.ArgMnemonic, "%X", &constnums);

                        char vpushimm4[] = "vPushImm4 ";
                        printf("%s\n", vpushimm4);

                        memcpy(midstr.vmfunc, vpushimm4, sizeof(vpushimm4));
                        m_middle.push_back(midstr);//操作码压入中间表示

                        DATATABLE datatbl;
                        datatbl.data = constnums;
                        datatbl.recodeOaddr = disAsm.VirtualAddr;
                        m_datatable.push_back(datatbl);//数据压入数据表
                }
                        break;
                default:
                        break;
                }
        }

/*----------------------------------------------------------------------------------*/
/*        4、处理普通handler                                                           */
/*----------------------------------------------------------------------------------*/
        //4、1 如果是ret,直接返回
        if (0 == stricmp("ret ", disAsm.Instruction.Mnemonic))
        {
                if (disAsm.Argument1.ArgType == 0x10000000)
                {
                        char vpushreg[] = "vPushImm4 ";
                        printf("%s\n", vpushreg);
                        memcpy(midstr.vmfunc, vpushreg, sizeof(vpushreg));
                        m_middle.push_back(midstr);//压入vPushReg4

                        DATATABLE datatbl;
                        datatbl.data = 0;
                        datatbl.recodeOaddr = disAsm.VirtualAddr;
                        m_datatable.push_back(datatbl);//数据压入数据表
                }
                char callmem[] = "vRETN ";
                printf("%s\n", callmem);
                memcpy(midstr.vmfunc, callmem, sizeof(callmem));
                m_middle.push_back(midstr);//压入vRETN
                return;
        }


        //4、2 如果操作数2是内存(针对的是二地址指令),m_middle链表最后两个元素互换
        if ((disAsm.Argument2.ArgType & 0xF0000000) == MEMORY_TYPE)
        {
                if (0 != stricmp("pop ", disAsm.Instruction.Mnemonic))
                {
                        swap(m_middle[m_middle.size()-1], m_middle[m_middle.size() - 2]);
                        
                }
                goto ttttt__;
        }

        //4、3 如果是调用函数,则处理好后,直接返回
        if (0 == stricmp("call ", disAsm.Instruction.Mnemonic))
        {                
                //如果操作数1是内存
                if ((disAsm.Argument1.ArgType & 0xF0000000) == MEMORY_TYPE)
                {                        
                        char callmem[] = "vCallMem ";
                        printf("%s\n", callmem);
                        memcpy(midstr.vmfunc, callmem, sizeof(callmem));
                        m_middle.push_back(midstr);//先压入vCallMem
                }
                else
                {
                        //删除vPushImm4
                        m_middle.pop_back();
                }
                char retnotaddr[] = "vRetnNOT_ ";
                printf("%s\n", retnotaddr);
                memcpy(midstr.vmfunc, retnotaddr, sizeof(retnotaddr));
                m_middle.push_back(midstr);//压入vRetnNOT

                char vcall[] = "vCALL ";
                printf("%s\n", vcall);
                memcpy(midstr.vmfunc, vcall, sizeof(vcall));
                m_middle.push_back(midstr);

                char vresumestart[] = "vResumeStart_ ";
                printf("%s\n", vresumestart);
                memcpy(midstr.vmfunc, vresumestart, sizeof(vresumestart));
                m_middle.push_back(midstr);//压入vResumeStart_
                return;
        }

        //4、4 处理普通handler
        for (int i = 0; i < FUNNUMS; i++)
        {
                if (0 == stricmp(g_FunName[i].s_opecode,disAsm.Instruction.Mnemonic))
                {
                        printf("%s\n", g_FunName[i].vm_opcoed);
                        memcpy(midstr.vmfunc, g_FunName[i].vm_opcoed,OPECODELENGTH);
                        m_middle.push_back(midstr);//操作码压入中间表示
                        break;
                }

        }

/*----------------------------------------------------------------------------------*/
/*        5、判断是否有辅助handler                                                           */
/*----------------------------------------------------------------------------------*/
        if (
                0x10000000 != disAsm.Argument1.ArgType ||
                0x10000000 != disAsm.Argument2.ArgType ||
                0x10000000 != disAsm.Argument3.ArgType
                )
        {
                ttttt__:
                //5.1 判断这条指令是否改变操作数1的值,比如cmp和test操作数就不会改变操作数1的值,直接返回        
                for (int i = 0; i < NOTREGNUMS; i++)
                {
                        if (stricmp(cmp_opecode[i], disAsm.Instruction.Mnemonic) == 0)
                        {
                                return;
                        }
                }
                
                //5.2 判断是否是JCC或者JMP指令,是则处理好后直接返回
                for (int i = 0; i < JCCNUMS; i++)
                {//判断是否是JCC指令
                        if (0 == stricmp(disAsm.Instruction.Mnemonic, JCCstr[i]))
                        {
                                //改变数据表的数据
                                m_datatable.at(m_datatable.size() - 1).originaddr = disAsm.VirtualAddr;
                                
                                //多压入一个空数据到数据表
                                DATATABLE datatbl;
                                datatbl.data = 0;
                                m_datatable.push_back(datatbl);//数据压入数据表

                                //再压入一个空数据到数据表
                                datatbl.data = 0;
                                m_datatable.push_back(datatbl);//数据压入数据表

                                //JCC指令前插入两个vPushImm4
                                char vpushimm4[] = "vPushImm4 ";
                                printf("%s\n", vpushimm4);
                                memcpy(midstr.vmfunc, vpushimm4, sizeof(vpushimm4));
                                m_middle.insert(m_middle.end()-1, midstr);//操作码压入中间表示
                                m_middle.insert(m_middle.end() - 1, midstr);//操作码压入中间表示
                                return;
                        }
                }

                //5.2 处理普通辅助handler
                switch (disAsm.Argument1.ArgType & 0xF0000000)
                {
                case REGISTER_TYPE://寄存器
                {
                        for (int i = 0; i < REGNUMS; i++)
                        {
                                if (tempreg[i].index == (disAsm.Argument1.ArgType & 0xFFFF))
                                {
                                        if (0x20 == disAsm.Argument1.ArgSize)
                                        {//32位
                                                char vpopreg4[] = "vPopReg4 ";
                                                printf("%s\n", vpopreg4);
                                                memcpy(midstr.vmfunc, vpopreg4, sizeof(vpopreg4));
                                                m_middle.push_back(midstr);//操作码压入中间表示                                                
                                        }
                                        else if (0x10 == disAsm.Argument1.ArgSize)
                                        {//16位
                                                char vpopreg4[] = "vPopReg2 ";
                                                printf("%s\n", vpopreg4);
                                                memcpy(midstr.vmfunc, vpopreg4, sizeof(vpopreg4));
                                                m_middle.push_back(midstr);//操作码压入中间表示        
                                        }
                                        else
                                        {//8位(要判断高位还是低位)
                                                for (int i = 0; i < 14; i++)
                                                {
                                                        if (stricmp(disAsm.Argument1.ArgMnemonic, regname_[0][i]) == 0)
                                                        {
                                                                if (i <= 3)//小于等于3是低位
                                                                {
                                                                        char vpushreg4[] = "vPopReg1_low ";
                                                                        printf("%s\n", vpushreg4);
                                                                        memcpy(midstr.vmfunc, vpushreg4, sizeof(vpushreg4));
                                                                        m_middle.push_back(midstr);//操作码压入中间表示        
                                                                }
                                                                else
                                                                {
                                                                        char vpushreg4[] = "vPopReg1_above ";
                                                                        printf("%s\n", vpushreg4);
                                                                        memcpy(midstr.vmfunc, vpushreg4, sizeof(vpushreg4));
                                                                        m_middle.push_back(midstr);//操作码压入中间表示        
                                                                }
                                                                break;
                                                        }
                                                }
                                        }
                                        DATATABLE datatbl;
                                        datatbl.data = i;
                                        m_datatable.push_back(datatbl);//数据压入数据表
                                }
                        }

                        //如果操作1是esp,即改变栈大小,比如指令sub esp,0x100,
                        //则要调用vCheckESP()函数,检查VMContext是否被覆盖
                        if (16 == (disAsm.Argument1.ArgType & 0xFFFF))
                        {//16在BegEngine反汇编引擎约定的是esp寄存器
                                char vcheckesp[] = "VCheckESP ";
                                printf("%s\n", vcheckesp);
                                memcpy(midstr.vmfunc, vcheckesp, sizeof(vcheckesp));
                                m_middle.push_back(midstr);//操作码压入中间表示
                        }
                        //如果操作码是pop,把vPOP添加到m_middle链表,然后返回
                        if (0 == stricmp("pop ",disAsm.Instruction.Mnemonic))
                        {
                                if (0x20 == disAsm.Argument1.ArgSize)
                                {
                                        char vpushreg4[] = "vPOP4 ";
                                        printf("%s\n", vpushreg4);
                                        memcpy(midstr.vmfunc, vpushreg4, sizeof(vpushreg4));
                                        m_middle.push_back(midstr);//操作码压入中间表示        
                                }
                                else
                                {
                                        char vpushreg4[] = "vPOP2 ";
                                        printf("%s\n", vpushreg4);
                                        memcpy(midstr.vmfunc, vpushreg4, sizeof(vpushreg4));
                                        m_middle.push_back(midstr);//操作码压入中间表示        
                                }
                                return;
                        }
                }
                        break;

                case MEMORY_TYPE://内存
                {
                        //
                }
                break;
                case CONSTANT_TYPE:
                {
                        //
                }
                break;
                }                
        }
}


4、绝大多数情况下,都是零地址指令、一地址指令、二地址指令,很少有三地址指令,所以把操作3省略没有处理。
5、把handler操作和数据分开保存,如:
[Asm] 纯文本查看 复制代码
mov eax,ecx
翻译为中间表示就是
vPushReg  VR_ecx  //操作2
vPushReg  VR_eax //操作1
vMOV            //普通handler
vPopReg   VR_eax //辅助handler

把VR_ecx、VR_eax、VR_eax分离出来保存在一个数据表的结构体中。
翻译就可以这样表示了:
vPushReg
vPushReg 
vMOV           
vPopReg
    

6、内存操作处理起来比较麻烦,MemoryMiddle函数用来专门处理内存操作。例如这条指令 mov dword ptr[eax+ecx*4+0x401000],eax,可以译成如下的中间表示:
[Asm] 纯文本查看 复制代码
vPushReg   //eax
vPushImm4  //4
vPushReg4  //ecx
vMUL_MEM  //*
vPushReg4 //eax
vAdd4    //+
vPushImm4 //0x401000
vAdd     //+
vWriteMemDs4

4 ecx * 可以理解为后缀表示法,其实这是和handler设计和堆栈操作有关的。

7、局部变量的操作,如 mov dword ptr[ebp-0x8],eax,仍然用MemoryMiddle函数来翻译:
[Asm] 纯文本查看 复制代码
vPushImm4  //0xFFFFFFF8
vPushReg4 //ebp
vAdd4
负8会被BeaEngine引擎解析为0xFFFFFFF8,ebp-0x8与0xFFFFFFF8+ebp是等价的

8、下面举个完整的例子:
[Asm] 纯文本查看 复制代码
void _declspec(naked) _stdcall  code_vm_test(int x)
{
    //MessageBoxA(NULL, 0, 0, 0);
    _asm { 
        sub esp,0x150
        push eax
        push ecx
        push edx
        lea ecx, code_vm_test
        add ecx,10h       
        push ecx
        pop dword ptr[g_num + 4]
        jmp L14
        sub esp,0x150
        L14:      
        mov ecx,1        
        xor eax,eax
        mov ah,10h
        mov bl,30h
        L13:
        add ecx,1
        add ah,bl
        cmp ecx,0x10
        jle L13
        //je L11
        add eax,0x432
       mov ebx,4
       mov ecx,1
       mov byte ptr[g_num + ebx + ecx * 4],ah
        //mov word ptr[g_num + ebx + ecx * 4],ax        
        //mov dword ptr[g_num+ebx+ecx*4],eax
        jmp L12
       //L11:
        mov g_num,eax

        call test2
       L12:
        mov eax, 01h   //eax=1:取CPU序列号
        xor edx, edx
        cpuid
        mov acpuid, eax
        mov dl,byte ptr[acpuid]
        mov lcpuid, edx

        pop edx
        pop ecx
        pop eax
        add esp,0x150
        retn 4
    }
}

上面这个函数,翻译为中间表示如下:
[Asm] 纯文本查看 复制代码
VMStartVM_2
vPushImm4
vPushReg4
vSUB4
vPopReg4
VCheckESP
vPushReg4
vPUSH
vPushReg4
vPUSH
vPushReg4
vPUSH
vPushImm4
vReadMemDs4
vPushReg4
vPopReg4
vPushImm4
vPushReg4
vAdd4
vPopReg4
vPushReg4
vPUSH
vRetnNOT_
vNotSimulate
vResumeStart_
vPushImm4
vJMP
vPushImm4
vPushImm4
vPushReg4
vSUB4
vPopReg4
VCheckESP
vPushImm4
vPushReg4
vMOV4
vPopReg4
vPushReg4
vPushReg4
vXOR4
vPopReg4
vPushImm4
vPushReg1_above
vMOV4
vPopReg1_above
vPushImm4
vPushReg1_low
vMOV4
vPopReg1_low
vPushImm4
vPushReg4
vAdd4
vPopReg4
vPushReg1_low
vPushReg1_above
vAdd4
vPopReg1_above
vPushImm4
vPushReg4
vCMP
vPushImm4
vJLE
vPushImm4
vPushImm4
vPushReg4
vAdd4
vPopReg4
vPushImm4
vPushReg4
vMOV4
vPopReg4
vPushImm4
vPushReg4
vMOV4
vPopReg4
vPushReg1_above
vPushImm4
vPushReg4
vMUL_MEM
vPushReg4
vAdd4
vPushImm4
vAdd4
vWriteMemDs1
vPushImm4
vJMP
vPushImm4
vPushReg4
vPushImm4
vWriteMemDs4
vPushImm4
vRetnNOT_
vCALL
vResumeStart_
vPushImm4
vPushReg4
vMOV4
vPopReg4
vPushReg4
vPushReg4
vXOR4
vPopReg4
vRetnNOT_
vNotSimulate
vResumeStart_
vPushReg4
vPushImm4
vWriteMemDs4
vPushImm4
vReadMemDs1
vPushReg1_low
vPopReg1_low
vPushReg4
vPushImm4
vWriteMemDs4
vPushReg4
vPopReg4
vPOP4
vPushReg4
vPopReg4
vPOP4
vPushReg4
vPopReg4
vPOP4
vPushImm4
vPushReg4
vAdd4
vPopReg4
VCheckESP
vPushImm4
vRETN

9、中间表示的设计非常的重要,它牵涉到后面的一系列的操作,需要好好考虑,这个指令解析器其实可以推翻重新设计的,我总感觉有点混乱,但时间原因,没弄了。
或者先不分离数据到数据表,把数据放到中间表示的数据结构里面,到后面再处理?
见仁见智,有初学者看到这篇文章的话可以少走一些弯路。


0x02 垃圾指令构造器
垃圾指令构造器的设计非常简单,难点在于垃圾指令的选择,有些指令是不能作为垃圾指令的,改变普通寄存器的指令不能用,比如AAA指令,会改变eax寄存器的值。具体参考Intel手册。
下面是垃圾指令的构造器
[C++] 纯文本查看 复制代码
//VMTABEL表的元素个数
#define VMTABLEMAXLEN                                0x1000
//没有用到寄存器
#define NONE        -1
//操作数类型

#define SEG_UNDEF     -1                           //没有段寄存器
#define SEG_ES         0               // Indexes of segment/selector registers
#define SEG_CS         1
#define SEG_SS         2
#define SEG_DS         3
#define SEG_FS         4
#define SEG_GS         5

enum optype
{
        NONETYPE,
        IMMTYPE,
        REGTYPE,
        MEMTYPE,
        CSTYPE,
        DSTYPE,
        ESTYPE,
        SSTYPE,
        FSTYPE,
        GSTYPE,
};

struct VMTable
{
        char        VMInstrName[VMNAMELEN];                //VM命令名称
        char        strInstruction[16];                        //相对的汇编指令
        int                OperandNum;                                        //操作数个数
        int                Segment;                                        //段前缀
        int                optype[2];                                        //操作类型(寄存器,立即数,内存数)
        int                bitnum[2];                                        //位数

        int                NeedReg[4];                                        //执行命令前要使用的寄存器
        int                SaveReg[4];                                        //执行命令后要保存的指令
        BOOL        Reg2Esp;                                        //第2个寄存器是否恢复,一般为0不恢复
};

VMTable vmtable32[VMTABLEMAXLEN] =
{   
    //MOV
        {"VMOV_REG08_REG08","MOV",2, SEG_UNDEF, REGTYPE, REGTYPE,8,8,          NONE,NONE,NONE,NONE,                NONE,NONE,NONE,NONE },
        {"VMOV_REG16_REG16","MOV",2, SEG_UNDEF, REGTYPE, REGTYPE,16,16,          NONE,NONE,NONE,NONE,                NONE,NONE,NONE,NONE },
        {"VMOV_REG32_REG32","MOV",2, SEG_UNDEF, REGTYPE, REGTYPE,32,32,          NONE,NONE,NONE,NONE,                NONE,NONE,NONE,NONE },
        {"VMOV_REG08_IMM32","MOV",2, SEG_UNDEF, REGTYPE, IMMTYPE,8,8,          NONE,NONE,NONE,NONE,                NONE,NONE,NONE,NONE },
        {"VMOV_REG16_IMM32","MOV",2, SEG_UNDEF, REGTYPE, IMMTYPE,16,16,          NONE,NONE,NONE,NONE,                NONE,NONE,NONE,NONE },
        {"VMOV_REG32_IMM32","MOV",2, SEG_UNDEF, REGTYPE, IMMTYPE,32,32,          NONE,NONE,NONE,NONE,                NONE,NONE,NONE,NONE },
        {"VMOV_REG08_MEM08","MOV",2, SEG_UNDEF, REGTYPE, MEMTYPE,8,8,          NONE,NONE,NONE,NONE,                NONE,NONE,NONE,NONE },
        {"VMOV_REG16_MEM16","MOV",2, SEG_UNDEF, REGTYPE, MEMTYPE,16,16,          NONE,NONE,NONE,NONE,                NONE,NONE,NONE,NONE },
        {"VMOV_REG32_MEM32","MOV",2, SEG_UNDEF, REGTYPE, MEMTYPE,32,32,          NONE,NONE,NONE,NONE,                NONE,NONE,NONE,NONE },
        {"VMOV_MEM08_REG08","MOV",2, SEG_UNDEF, MEMTYPE, REGTYPE,8,8,          NONE,NONE,NONE,NONE,                NONE,NONE,NONE,NONE },
        {"VMOV_MEM16_REG16","MOV",2, SEG_UNDEF, MEMTYPE, REGTYPE,16,16,          NONE,NONE,NONE,NONE,                NONE,NONE,NONE,NONE },
        {"VMOV_MEM32_REG32","MOV",2, SEG_UNDEF, MEMTYPE, REGTYPE,32,32,          NONE,NONE,NONE,NONE,                NONE,NONE,NONE,NONE },
        {"VMOV_MEM08_IMM32","MOV",2, SEG_UNDEF, MEMTYPE, IMMTYPE,8,8,          NONE,NONE,NONE,NONE,                NONE,NONE,NONE,NONE },
        {"VMOV_MEM16_IMM32","MOV",2, SEG_UNDEF, MEMTYPE, IMMTYPE,16,16,          NONE,NONE,NONE,NONE,                NONE,NONE,NONE,NONE },
        {"VMOV_MEM32_IMM32","MOV",2, SEG_UNDEF, MEMTYPE, IMMTYPE,32,32,          NONE,NONE,NONE,NONE,                NONE,NONE,NONE,NONE },
        {"VMOV_FSMEM08_IMM32","MOV",2, SEG_FS, MEMTYPE, IMMTYPE,8,8,          NONE,NONE,NONE,NONE,                NONE,NONE,NONE,NONE },
        {"VMOV_FSMEM16_IMM32","MOV",2, SEG_FS, MEMTYPE, IMMTYPE,16,16,          NONE,NONE,NONE,NONE,                NONE,NONE,NONE,NONE },
        {"VMOV_FSMEM32_IMM32","MOV",2, SEG_FS, MEMTYPE, IMMTYPE,32,32,          NONE,NONE,NONE,NONE,                NONE,NONE,NONE,NONE },
        {"VMOV_GSMEM08_IMM32","MOV",2, SEG_GS, MEMTYPE, IMMTYPE,8,8,          NONE,NONE,NONE,NONE,                NONE,NONE,NONE,NONE },
        {"VMOV_GSMEM16_IMM32","MOV",2, SEG_GS, MEMTYPE, IMMTYPE,16,16,          NONE,NONE,NONE,NONE,                NONE,NONE,NONE,NONE },
        {"VMOV_GSMEM32_IMM32","MOV",2, SEG_GS, MEMTYPE, IMMTYPE,32,32,          NONE,NONE,NONE,NONE,                NONE,NONE,NONE,NONE },
        {"VMOV_REG08_FSMEM08","MOV",2, SEG_FS, REGTYPE, MEMTYPE,8,8,          NONE,NONE,NONE,NONE,                NONE,NONE,NONE,NONE },
        {"VMOV_REG16_FSMEM16","MOV",2, SEG_FS, REGTYPE, MEMTYPE,16,16,          NONE,NONE,NONE,NONE,                NONE,NONE,NONE,NONE },
        {"VMOV_REG32_FSMEM32","MOV",2, SEG_FS, REGTYPE, MEMTYPE,32,32,          NONE,NONE,NONE,NONE,                NONE,NONE,NONE,NONE },
        {"VMOV_REG08_GSMEM08","MOV",2, SEG_GS, REGTYPE, MEMTYPE,8,8,          NONE,NONE,NONE,NONE,                NONE,NONE,NONE,NONE },
        {"VMOV_REG16_GSMEM16","MOV",2, SEG_GS, REGTYPE, MEMTYPE,16,16,          NONE,NONE,NONE,NONE,                NONE,NONE,NONE,NONE },
        {"VMOV_REG32_GSMEM32","MOV",2, SEG_GS, REGTYPE, MEMTYPE,32,32,          NONE,NONE,NONE,NONE,                NONE,NONE,NONE,NONE },
        {"VMOV_FSMEM08_REG08","MOV",2, SEG_FS, MEMTYPE, REGTYPE,8,8,          NONE,NONE,NONE,NONE,                NONE,NONE,NONE,NONE },
        {"VMOV_FSMEM16_REG16","MOV",2, SEG_FS, MEMTYPE, REGTYPE,16,16,          NONE,NONE,NONE,NONE,                NONE,NONE,NONE,NONE },
        {"VMOV_FSMEM32_REG32","MOV",2, SEG_FS, MEMTYPE, REGTYPE,32,32,          NONE,NONE,NONE,NONE,                NONE,NONE,NONE,NONE },
        {"VMOV_GSMEM08_REG08","MOV",2, SEG_GS, MEMTYPE, REGTYPE,8,8,          NONE,NONE,NONE,NONE,                NONE,NONE,NONE,NONE },
        {"VMOV_GSMEM16_REG16","MOV",2, SEG_GS, MEMTYPE, REGTYPE,16,16,          NONE,NONE,NONE,NONE,                NONE,NONE,NONE,NONE },
        {"VMOV_GSMEM32_REG32","MOV",2, SEG_GS, MEMTYPE, REGTYPE,32,32,          NONE,NONE,NONE,NONE,                NONE,NONE,NONE,NONE },
     
     { "VCMC","CMC",0, SEG_UNDEF, NONETYPE, NONETYPE,0,0,          NONE,NONE,NONE,NONE,                NONE,NONE,NONE,NONE },
        { "VNOP","NOP",0, SEG_UNDEF, NONETYPE, NONETYPE,0,0,          NONE,NONE,NONE,NONE,                NONE,NONE,NONE,NONE },
        { "VSTC","STC",0, SEG_UNDEF, NONETYPE, NONETYPE,0,0,          NONE,NONE,NONE,NONE,                NONE,NONE,NONE,NONE },
        { "VSTD","STD",0, SEG_UNDEF, NONETYPE, NONETYPE,0,0,          NONE,NONE,NONE,NONE,                NONE,NONE,NONE,NONE },
        { "VCLC","CLC",0, SEG_UNDEF, NONETYPE, NONETYPE,0,0,          RT_Eax,NONE,NONE,NONE,                RT_Eax,NONE,NONE,NONE },
     { "VNOT","NOT",1, SEG_UNDEF, REGTYPE, NONETYPE,8,0,           NONE,NONE,NONE,NONE,                NONE,NONE,NONE,NONE },
        { "VNOT","NOT",1, SEG_UNDEF, REGTYPE, NONETYPE,16,0,          NONE,NONE,NONE,NONE,                NONE,NONE,NONE,NONE },
        { "VNOT","NOT",1, SEG_UNDEF, REGTYPE, NONETYPE,32,0,          NONE,NONE,NONE,NONE,                NONE,NONE,NONE,NONE },
        { "VCLD","CLD",0, SEG_UNDEF, NONETYPE, NONETYPE,0,0,          NONE,NONE,NONE,NONE,                NONE,NONE,NONE,NONE },
 
 
 ......等等
 
         //结束标志
        {"end","end",0, 0, 0, 0,0x520000,0,0,0,0,0,0,0,0,0 }
}


//获取随机数(范围在Min_到MAX_)
        DWORD SrandNum(int Min_, int Max_)
        {
                return rand() % (Max_ - Min_) + Min_;
        }
 
 //求vmtable32结构体数组的长度
int VMLoader2::VMLength()
{
        for (int i = 0; i < VMTABLEMAXLEN; i++)
        {
                if (vmtable32[i].bitnum[0] == 0x520000)
                {
                        return i;
                }
        }
        return 0;
}
 
//vmtable32结构体数组的长度
        int m_vmlength = 0;
 
//生成垃圾指令
CString VMLoader2::ProduceRubbishOpecode(char* reg04, char* reg05)
{
        VMTable vmtbl = vmtable32[SrandNum(0, m_vmlength)];
        CString str = vmtbl.strInstruction;
        //1、目的操作
        switch (vmtbl.optype[0])
        {
        case NONETYPE://没有操作数
                break;
        case IMMTYPE://立即数
        {
                if (8 == vmtbl.bitnum[0])
                {
                        str = str + " " + 4;
                }
                else if (16 == vmtbl.bitnum[0])
                {
                        str = str + " " + 4;
                }
                else
                {
                        str = str + " " + 8;
                }
                
        }
                break;
        case REGTYPE://寄存器
        {

                if (8 == vmtbl.bitnum[0])
                {
                        for (int i = 0; i < 14; i++)
                        {
                                if (stricmp(reg04, regname_[2][i]) == 0)
                                {
                                        str = str + " " + regname_[0][i];
                                        break;
                                }
                        }                        
                }
                else if (16 == vmtbl.bitnum[0])
                {
                        for (int i = 0; i < 14; i++)
                        {
                                if (stricmp(reg05, regname_[2][i]) == 0)
                                {
                                        str = str + " " + regname_[1][i];
                                        break;
                                }
                        }
                }
                else
                {
                        str = str + " " + reg05;
                }
        }
                break;
        case MEMTYPE://内存
        {//随机选择vmp1节中没有用到的内存
                DWORD dnum = SrandNum(m_vmps.vmp1_startaddr+0x4000, m_vmps.vmp1_startaddr+0x5000);
                CString memstr = dnum;
                if (8 == vmtbl.bitnum[0])
                {
                        str = str + " byte ptr[" + memstr.GetString() + "]";
                }
                else if (16 == vmtbl.bitnum[0])
                {
                        str = str + " word ptr[" + memstr.GetString() + "]";
                }
                else
                {
                        str = str + " dword ptr[" + memstr.GetString() + "]";
                }
        }
                break;
        default:
                break;
        }

        //2、源操作数
        switch (vmtbl.optype[1])
        {
        case NONETYPE://没有操作数
                break;
        case IMMTYPE://立即数
        {
                if (8 == vmtbl.bitnum[1])
                {
                        str = str + "," + 4;
                }
                else if (16 == vmtbl.bitnum[1])
                {
                        str = str + "," + 8;
                }
                else
                {
                        str = str + "," + 4;
                }
        }
                break;
        case REGTYPE://寄存器(操作数2的寄存器可以在8个寄存器中任意选择)
        {
                if (0 == stricmp(vmtbl.strInstruction,"xchg"))
                {//如果是xchg,寄存器则选择reg04,或者reg05
                        if (8 == vmtbl.bitnum[1])
                        {
                                for (int i = 0; i < 14; i++)
                                {
                                        if (stricmp(reg05, regname_[2][i]) == 0)
                                        {
                                                str = str + "," + regname_[0][i];
                                                break;
                                        }
                                }

                        }
                        else if (16 == vmtbl.bitnum[1])
                        {
                                for (int i = 0; i < 14; i++)
                                {
                                        if (stricmp(reg04, regname_[2][i]) == 0)
                                        {
                                                str = str + "," + regname_[1][i];
                                                break;
                                        }
                                }
                        }
                        else
                        {
                                str = str + "," + reg04;
                        }
                        break;
                }
                if (8 == vmtbl.bitnum[1])
                {
                        str = str + "," + regname_[0][SrandNum(0, 8)];
                }
                else if (16 == vmtbl.bitnum[1])
                {
                        str = str + "," + regname_[1][SrandNum(0, 8)];
                }
                else
                {
                        str = str + "," + regname_[2][SrandNum(0, 8)];
                }
        }
                break;
        case MEMTYPE://内存
        {//随机选择vmp1节内的地址,或者选esp寄存器
                DWORD dnum = SrandNum(m_vmps.vmp1_startaddr, m_vmps.vmstartaddr);
                CString memstr = dnum;
                const char* memchr[5] = { memstr.GetString(),"esp+20","esp+28","esp+0x30","esp+0x14" };
                const char* srandstr = memchr[SrandNum(0, 5)];

                if (8 == vmtbl.bitnum[1])
                {
                        str = str + ",byte ptr[" + srandstr + "]";
                }
                else if (16 == vmtbl.bitnum[1])
                {
                        str = str + ",word ptr[" + srandstr + "]";
                }
                else
                {
                        str = str + ",dword ptr[" + srandstr + "]";
                }
        }
                break;
        default:
                break;
        }

        return str;
}

每调用一次ProduceRubbishOpecode就可以构造一条垃圾指令,其实这个垃圾指令构造器还可以细化。想要怎么设计,看需求。


0x03
handler的设计可以把要用到的handler放到一个表格中归类。
举个vJAE的例子,如下:
[Asm] 纯文本查看 复制代码
CString vJAE(char* VR0, char* VR1)//jae jnc jnb(无符号 大于等于跳转 CF=0)
{
        CString str = "push dword ptr[edi+0x20]\n";
        str = str + "pop "+ VR0 +"\n";
        str = str + "mov " + VR1 + ",0\n";

        str = str + "and "+ VR0 +",1\n";
        str = str + "mov "+ VR0 +",dword ptr[esp+4]\n";
        str = str + "cmove " + VR1 + ",dword ptr[esp]\n";
        str = str + "cmove "+ VR0 +",dword ptr[esp+8]\n";
        str = str + "add ebp," + VR1 + "\n";
        str = str + "add esi,"+ VR0 +"\n";
        str = str + "add esp,0xC\n";
        return str;
}


指令加壳流程图

指令加壳流程图

handler设计

handler设计

vmp.7z

18.14 KB, 下载次数: 220, 下载积分: 吾爱币 -1 CB

免费评分

参与人数 34吾爱币 +37 热心值 +31 收起 理由
xiao_xiong + 1 热心回复!
007nbqaq + 1 热心回复!
luochunyan + 1 + 1 谢谢@Thanks!
wjn + 1 + 1 学习了~
自强 + 1 + 1 谢谢@Thanks!
楓萧 + 1 + 1 用心讨论,共获提升!
漫步海底 + 1 热心回复!
lihai3310 + 1 我很赞同!
SinnerDusk + 1 + 1 用心讨论,共获提升!
wlsk888 + 1 + 1 我很赞同!
joseph + 1 + 1 我很赞同!
FJFJ + 1 + 1 用心讨论,共获提升!
生有涯知无涯 + 1 + 1 仰望大神,流下了没有技术的泪水
0615 + 1 + 1 热心回复!
imsnail + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
无奈· + 1 + 1 我很赞同!
迷魂 + 1 + 1 谢谢@Thanks!
爱飞的猫 + 3 + 1 我很赞同!
gaosld + 1 + 1 谢谢@Thanks!
又红又专 + 1 + 1 dl
804635611 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
156608225 + 1 + 1 鼓励转贴优秀软件安全工具和文档!
antiol + 3 + 1 我很赞同!
fengbolee + 1 + 1 用心讨论,共获提升!
女萝岩 + 1 + 1 我很赞同!
yixi + 1 + 1 谢谢@Thanks!
Jack2002 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
liphily + 1 + 1 你的编译原理应该是考满分了。。。
lookerJ + 1 + 1 用心讨论,共获提升!
Lixinist + 1 + 1 谢谢@Thanks!
yhym599 + 1 + 1 用心讨论,共获提升!
nj001 + 1 + 1 热心回复!
度娘灬魂手 + 2 + 1 用心讨论,共获提升!
ycs + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

佚名24 发表于 2020-11-5 16:49
感谢大佬
wanghualina 发表于 2020-10-25 10:43
知足常乐999 发表于 2020-10-20 09:00
gh0st_ 发表于 2020-10-18 07:55
厉害大佬 学习了
wlsk888 发表于 2020-10-16 16:53
厉害,即使我确实看明白了些理论。。。然而这辈子估计是没有这个动力和耐心了。。。
加油加油,52pj大神!
menggg 发表于 2020-10-14 08:42
大神真厉害,感谢分享
aikoz88 发表于 2020-10-7 10:00
感谢分享 起码我就做不到
leonalewis 发表于 2020-10-6 10:38
膜拜…学习一波
yuelingge 发表于 2020-10-4 21:59
站里大神超多,很棒,有用,收藏起来!!!
紫娑之 发表于 2020-10-5 09:47
又是一个拨头发的利器
ycs 发表于 2020-9-23 20:49
牛人。感谢分享。
度娘灬魂手 发表于 2020-9-23 21:07
论坛里的大佬是真的有时间,我看一下就头晕了
 楼主| 舒默哦 发表于 2020-9-23 21:23
度娘灬魂手 发表于 2020-9-23 21:07
论坛里的大佬是真的有时间,我看一下就头晕了

我也没学多久,离大佬差太远了,努力就有收获,慢慢赶吧
liu5653250 发表于 2020-9-23 21:47
厉害?? 厉害?? ,我到现在还一头雾水!
见见不能说 发表于 2020-9-23 21:49
站里大神超多,很棒,有用,收藏起来!!!
yhym599 发表于 2020-9-23 23:36
好文,楼主好有耐心和时间。
度娘灬魂手 发表于 2020-9-23 23:59
舒默哦 发表于 2020-9-23 21:23
我也没学多久,离大佬差太远了,努力就有收获,慢慢赶吧

我光PE结构就学到半途而废,这些是真的不敢碰了,头发都快没了
 楼主| 舒默哦 发表于 2020-9-24 10:19
度娘灬魂手 发表于 2020-9-23 23:59
我光PE结构就学到半途而废,这些是真的不敢碰了,头发都快没了

哈哈。。。。
巅峰Clown 发表于 2020-10-1 05:53
站里大神超多,很棒,有用,收藏起来!!!
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-4-19 22:56

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表