(1)本文提出一种不同寻常的混淆,即类似VMP的一种方法,但本文不提供类似VMP的自动工具
(2)本方法主要用于核心算法区域核心加密函数的混淆
(3)但本方法因没有相关辅助开发工具,需要使用汇编的方式
首先,我们写2篇代码,实现一个基于堆栈的虚拟机
#pragma once
//首先就是定义各种操作码的值,程序上进行顺序调整就改变了枚举值的值
//此处枚举值不写值,便于调整打乱
enum CV_ENUM
{
vMark,
vAdd1,
vPushStr,
vGotoIfN,
vPushInt,
vPushVst,
vSub1,
vEnd,
vCmpIntSt,
vGoto,
vPushChar,
vLoadChar,
vSaveChar,
vCalcMod,
vCalcXorChar,
};
#define vSt(x) (x) //表示从栈底找变量
#define vMark(x) (x) //表示跳转位置
enum cVmDType
{
vxtInteger,
vxtString,
vxtReal,
vxtQword,
};
struct cVmData
{
cVmDType vxxxType;
int vxxxSLen;
union
{
__int64 asInteger;
wchar_t* asString;
double asReal;
DWORD64 asQword;
};
};
#define ERR_OUT_OF_INDEX 1
#define ERR_POP_EMPTY_STACK 2
#define ERR_PUSH_FULL_STACK 3
#define ERR_SEH_EXEC_INST 4
#define ERR_UNSUPPORT_INST 5
BOOL CvMachine_ExcuteCode(DWORD_PTR* pCodePtr, int cVmMaxMark, int* m_MarkTable, int cVmMaxStack, cVmData* m_stack, int& IN OUT m_StTop, int & OUT nErr, int& OUT nErrPos);
BOOL CvMachine_ScanMark(DWORD_PTR* pCodePtr, int cVmMaxMark, int* m_MarkTable, int& OUT nErr, int& OUT nErrPos);
bool CvM_ExecuteOnInstruct(int Code, DWORD_PTR* pParams, bool& OUT bEnd, bool& OUT bNeedJump, int& OUT nJumpOffset, int& OUT exceptionErr, int* m_MarkTable, int cVmMaxStack, cVmData* m_stack, int& IN OUT m_StTop);
cVmData& CvM_ref_stack(DWORD_PTR nFromBottom, int cVmMaxStack, cVmData* m_stack);
cVmData CvM_pop(int& IN OUT m_StTop, cVmData* m_stack);
void CvM_push_v(cVmData& cv, int& IN OUT m_StTop, int cVmMaxStack, cVmData* m_stack);
void CvM_push_int(__int64 V, int& IN OUT m_StTop, int cVmMaxStack, cVmData* m_stack);
void CvM_push_str(wchar_t* pStr, int Len, int& IN OUT m_StTop, int cVmMaxStack, cVmData* m_stack);
template<int cVmMaxStack = 128, int cVmMaxMark = 32>
class CvMachine//内部放一个栈,不要动态分配
{
public:
CvMachine()
{
m_StTop = -1;
}
~CvMachine() {}
BOOL ExcuteCode(DWORD_PTR* pCodePtr, int& OUT nErrCode, int& OUT nErrPos)
{
return CvMachine_ExcuteCode(pCodePtr, cVmMaxMark, m_MarkTable, cVmMaxStack, m_stack, m_StTop, nErrCode, nErrPos);
}
private:
cVmData m_stack[cVmMaxStack];//64个栈变量空间1KB,128=2KB
int m_StTop;//放在中间不容易被逆向找到,注意传递引用
int m_MarkTable[cVmMaxMark];//支持这么多的标记点
};
下面是个例子,表示我们实现一个基于此虚拟机的异或函数,这样通过IDA反编译就看不出它的代码
BOOL VxxStringXOR(WCHAR* pText, int lenTxt, WCHAR* pKey, int lenKey)
{
BOOL bRet = 0;
//我们用CodingVM写一个字符串异或加密方法
//for(i = 0; i < lenKey; i++)
//{
// pText[i]=pText[i]^pKey[i%lenKey];
//}
DWORD_PTR vxxCode[] =
{
//先压入参数,记住,栈底0位置为第一个参数
vPushStr, (DWORD_PTR)pText, lenTxt, //v0 Input
vPushStr, (DWORD_PTR)pKey, lenKey, //v1 Key
vPushInt, lenTxt, //v2 lenTxt
vPushInt, lenKey, //v3 lenKey
vEnd,
};
static DWORD_PTR vxxCode2[] =
{
vPushInt, 0, //v4 I
//然后开使进行加密
vMark, 0,//标记跳转点
vPushVst, vSt(4),
vLoadChar, vSt(0), //T[i]到栈顶
//calc I%KeyLen
vPushVst, vSt(4),
vPushVst, vSt(3),
vCalcMod,
vLoadChar, vSt(1), //K[KL%I] 到顶
vCalcXorChar, //top = xor ret
vPushVst, vSt(4),
vSaveChar, vSt(0),
vCmpIntSt, vSt(4), vSt(2),
vGotoIfN, (DWORD_PTR)(-1), 1,
vAdd1, vSt(4),
vGoto, 0,
vMark, 1,
//完成了
//到结束符号停止,若没有结束符号可能崩溃哟
vEnd,
};
CvMachine machine;
if(machine.ExcuteCode(vxxCode))
{
if(machine.ExcuteCode(vxxCode2))
{
bRet = TRUE;
}
}
return bRet;
}
至于如何实现执行这个虚拟指令的代码,能看懂此文的都能自己实现出来,这里就不再写出了