-
-
[讨论]虚拟机设计 章节的 随书源码有点问题
-
发表于: 2013-8-28 17:10 17457
-
加密与解密 第三版 第17章虚拟机设计 的随书代码 很强大,谢谢作者分享、
今天发现一个小问题。不知道有没有提过。
上面这个函数是把汇编代码转换为虚拟机代码。
首先把指令的操作数压栈然后执行指令的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一次。
问题在于
修改如下:
结果:
INC指令:
DPushReg32
VINC_REG32
DPopReg32
VSAVEESP
再次感谢作者。。
今天发现一个小问题。不知道有没有提过。
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
再次感谢作者。。
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
赞赏
他的文章
看原图
赞赏
雪币:
留言: