char* str = "this is string!haha";
__declspec(naked) func2()
{
  VMPBEGIN
  MessageBox(0,"1","",MB_OK);
  _asm
  {
    retn
  }
  VMPEND
}
DWORD tmp = 0;
DWORD Eeax = 0;
_declspec(naked) func3()
{
  VMPBEGIN
  _asm
  {
    mov eax,Eeax
    jmp [eax]
  }
  VMPEND
}
_declspec(naked) func()
{
  VMPBEGIN
  goto begin;
rets:
  func2();
  goto ends;
begin:
  _asm
  {
    lea ebx,rets
    mov tmp,ebx
  }
  Eeax = (DWORD)&tmp;
  _asm
  {
    jmp func3
  }
ends:
  _asm
  {
    retn
  }
  VMPEND
}

int _tmain(int argc, _TCHAR* argv[])
{
  DWORD ss = Eeax;
  func();
  getchar();
  return 0;
}
以为jmp [eax]这种方法可以刁难Vmprotect了.
没想到它更胜一筹..
再找看看还有没能强奸它的语法.
************************************************************************************************************
稍微变了下代码
  VMPBEGIN
  
  goto begin;
rets:
  _asm
  {
    push func2
    retn
  }
  goto ends;
begin:
  _asm
  {
    lea ecx,rets
    mov tmp,ecx
    lea ebx,tmp
    mov Eeax,ebx
    mov eax,Eeax
    jmp [eax]
  }
ends:
  _asm
  {
    retn
  }
  VMPEND
发现顺利的挂了.
原因如下.
vmprotect在解释call时会先判断是否有其他代码引用当前地址.当没有引用时就直接编译为字节码,有引用时就将call放在原处.其他地址引用时也就不会出现错误了.
而改为push func2时就想也没想的把这里编译为字节码了,后面的 jmp [eax] 理所当然的就出问题了.

如果说要让vmprotect连这种类似自修改代码都支持的话的确有点困难.

不过.VC编译switch代码时会出现
jmp [401000+ebx] 跳到case语句去.
像这种不知道vmprotect的支持性怎么样...