吾愛破解 - LCG - LSG |安卓破解|病毒分析|huihengkj.com

 找回密碼
 注冊[Register]

QQ登錄

500彩票邀请码只需一步,快速開始

搜索
查看: 3326|回復: 37

[原創源碼] 【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;
}


vmp編寫流程圖2.png (159.52 KB, 下載次數: 1)

指令加殼流程圖

指令加殼流程圖

vmp編寫流程圖.png (182.77 KB, 下載次數: 0)

handler設計

handler設計

vmp.7z

18.14 KB, 下載次數: 113, 下載積分: 吾愛幣 -1 CB

免費評分

參與人數 27吾愛幣 +32 熱心值 +25 收起 理由
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!
jixun66 + 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 感謝發布原創作品,吾愛破解論壇因你更精彩!

查看全部評分

本帖被以下淘專輯推薦:

發帖前要善用論壇搜索功能,那里可能會有你要找的答案或者已經有人發布過相同內容了,請勿重復發帖。

推薦
知足常樂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
又是一個撥頭發的利器
推薦
chenjingyes 發表于 2020-10-1 23:36
樓主要完整開源嗎?
推薦
jkj 發表于 2020-10-3 13:02
這是個非常精細的活,需要很多時間,很考驗耐心,贊一個!
沙發
ycs 發表于 2020-9-23 20:49
牛人。感謝分享。
3#
度娘灬魂手 發表于 2020-9-23 21:07
論壇里的大佬是真的有時間,我看一下就頭暈了
4#
 樓主| 舒默哦 發表于 2020-9-23 21:23 |樓主
度娘灬魂手 發表于 2020-9-23 21:07
論壇里的大佬是真的有時間,我看一下就頭暈了

我也沒學多久,離大佬差太遠了,努力就有收獲,慢慢趕吧
5#
liu5653250 發表于 2020-9-23 21:47
厲害?? 厲害?? ,我到現在還一頭霧水!
6#
見見不能說 發表于 2020-9-23 21:49
站里大神超多,很棒,有用,收藏起來!!!
7#
yhym599 發表于 2020-9-23 23:36
好文,樓主好有耐心和時間。
8#
度娘灬魂手 發表于 2020-9-23 23:59
舒默哦 發表于 2020-9-23 21:23
我也沒學多久,離大佬差太遠了,努力就有收獲,慢慢趕吧

我光PE結構就學到半途而廢,這些是真的不敢碰了,頭發都快沒了
9#
 樓主| 舒默哦 發表于 2020-9-24 10:19 |樓主
度娘灬魂手 發表于 2020-9-23 23:59
我光PE結構就學到半途而廢,這些是真的不敢碰了,頭發都快沒了

哈哈。。。。
10#
巔峰Clown 發表于 2020-10-1 05:53
站里大神超多,很棒,有用,收藏起來!!!
您需要登錄后才可以回帖 登錄 | 注冊[Register]

本版積分規則 警告:本版塊禁止灌水或回復與主題無關內容,違者重罰!

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

RSS訂閱|小黑屋|處罰記錄|聯系我們|吾愛破解 - LCG - LSG ( )

GMT+8, 2020-10-22 08:12

Powered by Discuz!

500彩票邀请码Copyright © 2001-2020, Tencent Cloud.

快速回復 返回頂部 返回列表

500彩票邀請碼-彩經網