CTF

VM

in CTF'Re

Posted by pic4xiu on May 28, 2019

What is VM

different from virtualbox…

这种虚拟机类似于自己用一套自己定义的操作码实现了完整的逻辑,当然用的指令不太多,不然会很困难且效率很低,显得没有必要。必要的定义有

  • 虚拟机的初始化
  • 一套自己定义的操作码
  • 对应各个操作码的解释器

初次接触也许很生疏,我们从一套题目看起,这是2018NCTF WcyVM,网上wp很多,我在这里通过这道题来详细说明一下虚拟机在逆向方面的各种思路

Analysis

Some differences

__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
  setbuf(stdin, 0LL);
  setbuf(stdout, 0LL);
  printf("This is a %s\nplz input your flag:", aWcyvm1);
  if ( sub_400DAB() )
    puts("flag is your input");
  else
    puts("didixingwei");
  return 0LL;
}

看到主函数逻辑极其简单,我们跟sub_400DAB(),会发现是一个while嵌套switch的一套代码,先看循环以上本函数的初始化

  v11 = __readfsqword(0x28u);
  v1 = 0;
  dest = malloc(0x200uLL);
  v3 = malloc(0x1400uLL);
  memset(&v4, 0, 0x30uLL);
  memcpy(dest, &unk_6021C0, 0x190uLL);
  v4 = malloc(0x38uLL);
  v5 = v4 + 1;
  v6 = v4 + 2;
  v7 = v4 + 3;
  v8 = v3 + 5120;
  v9 = v3 + 5120;
  v10 = dest;
LABEL_26:

定义了许多变量,我们只需要注意v8即可,这是一个堆栈指针,在以后有大用,我们看一下后边的case指令,例如下方

 case 8:
        sub_40082B((&v4)[v10[1] - 1], v10[2], &v10);
        goto LABEL_26;
//本函数
_QWORD *__fastcall sub_40082B(_DWORD *a1, int a2, _QWORD *a3)
{
  _QWORD *result; // rax

  *a1 = a2;
  result = a3;
  *result += 12LL;
  return result;
}

我们看下这个函数,它做的便是把a2的值赋给了a1,然后把指针向后移,所以可以简单理解为mov a1,a2,而堆栈指针的使用在下边,我们举例说明

      case 9:
        sub_40096D((&v4)[v10[1] - 1], &v8, &v10);
        goto LABEL_26;
       
_QWORD *__fastcall sub_40096D(_DWORD *a1, _DWORD **a2, _QWORD *a3)
{
  _QWORD *result; // rax

  *a1 = **a2;
  ++*a2;
  result = a3;
  *result += 8LL;
  return result;
}

可以看到函数在直接把a2的值给了a1,之后a2自增,之后与之前的函数类似,这显然就是一个典型的pop a1操作,而且v8正是我们是我们假定的栈顶指针

这题就是这样需要一步一步逆出指令集即可进行解题,没有别的自动化方法,我们把我们要做的操作码用idc搞出来

auto i,start,end,num;
start = 0x6021c0;
end = 0x60234f;
Message("\n---------\n");
for(i=start;i<end;i=i+4)
{
    Message("%d,",Dword(i));
}

然后硬着头皮,像转换一样把它填进去就行,例如根据得到的数据

8,1,0,8,3,70,14,21,10,1,9,2,11,10,1,10,2,9,1,17,1,13,1,3,15,8,8,1,0,8,3,71,14,70,10,1,26,2,6,29,1,4,20,2,1,25,1,2,27,1,1,29,1,110,19,1,99,21,1,116,19,1,102,28,2,1,9,1,17,1,13,1,3,15,34,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,

8,1,0就是mov (&v4)[v10[1] - 1],0

9,1就是pop (&v4)[v10[1] - 1]

很难受的题,不过这种逆向确实很有趣

正向出题

下面自己完成一套虚拟机,通过正向来看一下 vm 层面需要什么