首页
社区
课程
招聘
[讨论]虚拟机设计 章节的 随书源码有点问题
发表于: 2013-8-28 17:10 17457

[讨论]虚拟机设计 章节的 随书源码有点问题

2013-8-28 17:10
17457
加密与解密 第三版 第17章虚拟机设计 的随书代码 很强大,谢谢作者分享、
今天发现一个小问题。不知道有没有提过。
BOOL CVMFactory::TranslateVM(CodeNode* code)
{
	t_disasm disasm;
	memcpy( &disasm,&code->disasm,sizeof(t_disasm) );
	
	//检测是否为段寄存器
	for(int opidx = 2; opidx > 0; opidx--)
	{
		if( disasm.optype[opidx] == Seg )//为段积存器,暂时不支持
		{
			MessageBox(NULL,"[segment] 对不起,暂时不支持一些操作数.","错误",MB_OK);
			return FALSE;
		}
	}
	VMTable* table = GetVMTableForAlready(disasm.vm_name);
	if( !table )//如果没有收录,则把这句代码放到现实场景中执行.并将当前指令改成指向现实场景的地方
	{
		//执行.....跳转
		CompileUndeclared(&disasm);
		return TRUE;
	}
	for(int opidx = 2; opidx >= 0; opidx--)
	{
		switch(disasm.optype[opidx])
		{
		case Imm://立即数
			{
				AddDPushIMM(opidx,&disasm,m_VMCode);
			}
			break;
		case Reg://寄存器
			{
				AddDPushREG(opidx,&disasm,m_VMCode);
			}
			break;
		case Mem://内存数
			{
				AddDPushMem(opidx,&disasm,m_VMCode);
			}
			break;
		}
	}
	AddVMHandler(&disasm,m_VMCode);//添加真正执行代码的vm指令
	//如果不是跳转指令
	if( !strstr(table->strInstruction,"LOOP") && table->strInstruction[0] != 'J' && table->strInstruction[0] != 'j' &&
		!strstr(table->strInstruction,"CALL") )
	{
			for(int opidx = 0; opidx < 2; opidx++)
			{
				//弹出由辅助指令压入的值
				if( opidx == 0 || table->Reg2Esp )//如果是第1个寄存器或者要求保存第2个寄存器
				{
					switch(disasm.optype[opidx])
					{
					case Imm://立即数
					case Mem://内存数
						{
							AddDFree(opidx,&disasm,m_VMCode);
						}
						break;
					case Reg://寄存器
						{
							AddDPopReg(opidx,&disasm,m_VMCode);
						}
						break;
					}
				}
				else//不是第1个寄存器且不保存第2个寄存器
				{
					AddDFree(opidx,&disasm,m_VMCode);
				}
			}
	}
	if( disasm.reg[0] == RT_Esp )
		AddDRestoreEsp(0,&disasm,m_VMCode);//将VM的ESP的值恢复到EBP
	else
		AddDSaveEsp(0,&disasm,m_VMCode);//将EBP的值保存到VM的ESP

	return TRUE;
}

上面这个函数是把汇编代码转换为虚拟机代码。
首先把指令的操作数压栈然后执行指令的handler,然后恢复栈。
如果 指令是两个操作数 没啥问题。。
但是如果指令是一个操作数 就有问题了。
比如mov指令变成虚拟指令
DPushReg32
DPushImm32
DPushImm32
DPushImm32
DPushImm32
DPushMem32
VMOV_MEM08_REG08
DFree
DFree
VSAVEESP
这个没问题 FREE两次 因为两次压栈
但是INC指令 变成虚拟后:
DPushReg32
VINC_REG32
DPopReg32
DFree
VSAVEESP
它pop后又free了 而且 只push一次。
问题在于
if( !strstr(table->strInstruction,"LOOP") && table->strInstruction[0] != 'J' && table->strInstruction[0] != 'j' &&
		!strstr(table->strInstruction,"CALL") )
	{
			for(int opidx = 0; opidx < 2; opidx++)
			{
				//弹出由辅助指令压入的值
				if( opidx == 0 || table->Reg2Esp )//如果是第1个寄存器或者要求保存第2个寄存器
				{
					switch(disasm.optype[opidx])
					{
					case Imm://立即数
					case Mem://内存数
						{
							AddDFree(opidx,&disasm,m_VMCode);
						}
						break;
					case Reg://寄存器
						{
							AddDPopReg(opidx,&disasm,m_VMCode);
						}
						break;
					}
				}
				else//不是第1个寄存器且不保存第2个寄存器
				{
					AddDFree(opidx,&disasm,m_VMCode);
				}
			}
	}

else//不是第1个寄存器且不保存第2个寄存器

修改如下:
if( !strstr(table->strInstruction,"LOOP") && table->strInstruction[0] != 'J' && table->strInstruction[0] != 'j' &&
		!strstr(table->strInstruction,"CALL") )
	{
			for(int opidx = 0; opidx < 2; opidx++)
			{
				//弹出由辅助指令压入的值
				if( opidx == 0 || table->Reg2Esp )//如果是第1个寄存器或者要求保存第2个寄存器
				{
					switch(disasm.optype[opidx])
					{
					case Imm://立即数
					case Mem://内存数
						{
							AddDFree(opidx,&disasm,m_VMCode);
						}
						break;
					case Reg://寄存器
						{
							AddDPopReg(opidx,&disasm,m_VMCode);
						}
						break;
					}
				}
				else if(disasm.optype[opidx]!= 0xffffffff)//这里修改了
				{
					AddDFree(opidx,&disasm,m_VMCode);
				}
			}
	}


结果:
INC指令:
DPushReg32
VINC_REG32
DPopReg32
VSAVEESP

再次感谢作者。。

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 0
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//