感谢南梦师傅博客 南梦爷爷博客

虚拟机保护的pwn

当我们 拿到 一个 虚拟机的 pwn的时候 先看看函数的逻辑

是很多 分支 或者说很多 switch 语句
这样 很大可能说明了 这很有可能是一个 虚拟机 或者是一个 解释器

vm 解释器的 基本认识

寄存器

  1. PC 程序计数器,他存放的是一个内存地址,该地址中存放着 下一条 要执行的计算机指令
  2. SP 指针寄存器,永远指向当前栈顶。
  3. BP 基质指针。也是用于指向栈的某些位置,在调用函数的时候会用到它
  4. AX 通用寄存器,我们的虚拟机中,它用于存放一条指令执行后的结果

在程序中 PC的初始值指向目标代码的 main 函数

指令集

虚拟机定义的时候 会定义一个 全局变量的 枚举类型 里面有我们需要的指令
如 :MOV,ADD 之类的

通过例题学习

ciscn 2019 华东南 pwn Virtual

题目分析

刚开始的 malloc_all 里面会记录我们的 的输入 的不同段开始的地址 和 对应的 参数个数
例如:stack

在 store 函数中 有个 move 函数 会把我们的输入保存到我们 开始时创建的 对应chunk 中

  1. 首先输入nameinstruction
  2. 让进入到主要函数 以\n\r\t被分割 将我们 输入的instruction 分为一组一组的指令
  3. 分别根据 匹配到的指令将 对应的 值 放入ptr 数组中
  4. 程序一共有 push pop add sub mul div load save 这几个指令

分析得到这里是 给虚拟机 布置指令

void __fastcall ins_stack(__int64 some_data, char *ins)
{
  int idx; // [rsp+18h] [rbp-18h]
  int i; // [rsp+1Ch] [rbp-14h]
  const char *part1; // [rsp+20h] [rbp-10h]
  _QWORD *ptr; // [rsp+28h] [rbp-8h]

  if ( some_data )
  {
    ptr = malloc_0(8LL * *(some_data + 8));
    idx = 0;
    for ( part1 = strtok(ins, delim); idx < *(some_data + 8) && part1; part1 = strtok(0LL, delim) )// \n\r\t被分割
                                                // 
    {
      if ( !strcmp(part1, "push") )
      {
        ptr[idx] = 0x11LL;
      }
      else if ( !strcmp(part1, "pop") )
      {
        ptr[idx] = 0x12LL;
      }
      else if ( !strcmp(part1, "add") )
      {
        ptr[idx] = 0x21LL;
      }
      else if ( !strcmp(part1, "sub") )
      {
        ptr[idx] = 0x22LL;
      }
      else if ( !strcmp(part1, "mul") )
      {
        ptr[idx] = 0x23LL;
      }
      else if ( !strcmp(part1, "div") )
      {
        ptr[idx] = 0x24LL;
      }
      else if ( !strcmp(part1, "load") )
      {
        ptr[idx] = 0x31LL;
      }
      else if ( !strcmp(part1, "save") )
      {
        ptr[idx] = 0x32LL;
      }
      else
      {
        ptr[idx] = '\xFF';
      }
      ++idx;
    }
    for ( i = idx - 1; i >= 0 && mov(some_data, ptr[i]); --i )
      ;
    free(ptr);
  }
}

mov 函数

signed __int64 __fastcall mov(chunk *data, __int64 ptr)
{
  int idx; // [rsp+1Ch] [rbp-4h]

  if ( !data )
    return 0LL;
  idx = data->idx + 1;
  if ( idx == data->size )
    return 0LL;
  *(data->section_ptr + 8LL * idx) = ptr;
  data->idx = idx;
  return 1LL;
}
  1. 然后会到另一个函数,给栈上布置参数
  2. 也是用\n\r\t被分割 将我们的输入 然后保存在虚拟的栈上

```

点击收藏 | 1 关注 | 1
登录 后跟帖