DDCTF2019 confused WP

前言

  • 有一段时间没更新博客了,主要是事情太多。这是上半年的比赛遗留下的问题,决心好好琢磨一番。后续会更新hackgame2019的部分题解和其他平台上的题解。

分析

  • 这是一道ELF64位的虚拟机逆向。首先通过初始化虚拟机函数:
void *__fastcall init_vm(VM *vm, const void *input)
{
  vm->reg_0 = 0;
  vm->reg_1 = 0;
  vm->reg_2 = 0;
  vm->reg_3 = 0;
  LODWORD(vm->field_10) = 0;
  *&vm->flag = 0;
  LOBYTE(vm->v0) = 0xF0u;
  vm->func_0 = mov_reg0_mem;
  vm->gap30[0] = 0xF1u;
  *&vm->func_1 = xor_reg0_reg1;
  LOBYTE(vm->v2) = 0xF2u;
  vm->func_2 = cmp_reg0_mem;
  LOBYTE(vm->v3) = 0xF4u;
  vm->func_3 = func_add_reg0_reg1;
  LOBYTE(vm->v4) = 0xF5u;
  vm->func_4 = func_sub_reg0_reg1;
  LOBYTE(vm->v5) = 0xF3u;
  vm->func_5 = nullptr;
  LOBYTE(vm->v6) = 0xF6u;
  vm->func_6 = jz_opcode;
  LOBYTE(vm->v7) = 0xF7u;
  vm->func_7 = move_flag_mem;
  LOBYTE(vm->v8) = 0xF8u;
  vm->func_8 = Encode_reg_0;
  ::input = malloc(0x400uLL);
  return memccpy(::input + 48, input, 1, 18uLL);
}
  • 可以建立一个VM结构体
struct VM{
    int reg_0;
    int reg_1;
    int reg_2;
    int reg_3;
    int field_10;
    char* opcode;
    int v0;
    ...
    void* func_0;
    ...
    void* func_1;
    ...
    int v2 ;
    ...
    void* func_2;
    int v3;
    ...
    void* func_3;
    int v4;
    ...
    void* func_4;
    int v5;
    ...
    void* func_5;
    int v6;
    ...
    void* func_6;
    int v7;
    ...
    void* func_7;
    int v8;
    ...
    void* func_8;
    int flag;
};

  • 动态调试,跟一下程序,不难发现其流程:
  • 首先输入19个字符,然后初始化虚拟机。
  • 虚拟机的执行流程如下:
1) vm->reg_0=*(vm->opcode+2),opcode+=6
2) vm->reg_0=Encode(vm->reg_0,2),vm->opcode++//凯撒加密,key=2 
3) vm->field_10=vm->reg_0==input[0],vm->opcode+=2//相等转到(5),否则转到(6)
5) vm->field_0=0,vm->opcode+=2//转到(8)
6) vm->opcode+=*(vm->opcode+1),vm->opcode+=2//转到(7)
7) vm->flag=*(vm->opcode+1),vm->opcode+=5//转到(9)
8) 重复 (1)~(5) 19 次后转到(7)
9) 跳出虚拟机
如果 vm->flag==1 成功,否则失败
  • 可见其实就是执行19Encode(opcode[2+11*i])=input[i]? 的操作。

脚本

code=[\
    240,16,102,0,0,0,248,242,48,246,193,240,16,99,0,0,0,248,242,49,246,182,240,16,106,0,0,0,248,242,50,246,171,240,16,106,0,0,0,248,242,51,246,160,240,16,109,0,0,0,248,242,52,246,149,240,16,87,0,0,0,248,242,53,246,138,240,16,109,0,0,0,248,242,54,246,127,240,16,115,0,0,0,248,242,55,246,116,240,16,69,0,0,0,248,242,56,246,105,240,16,109,0,0,0,248,242,57,246,94,240,16,114,0,0,0,248,242,58,246,83,240,16,82,0,0,0,248,242,59,246,72,240,16,102,0,0,0,248,242,60,246,61,240,16,99,0,0,0,248,242,61,246,50,240,16,68,0,0,0,248,242,62,246,39,240,16,106,0,0,0,248,242,63,246,28,240,16,121,0,0,0,248,242,64,246,17,240,16,101,0,0,0,248,242,65,246,6,247,1,0,0,0,243,247,0,0,0,0,243,93,195,15,31,132,0,0,0,0,0\
]
flag=''

def Encode(v,k):
    v5=False
    if v>64:
        v5=v<=90
    if v5:
        v3=(v+k-65)%26+65
    else:
        v4=False
        if v>96:
            v4=v<=122
        if v4:
            v3=(v+k-97)%26+97
        else:
            v3=v
    return v3

for i in range(19):
    flag+=chr(Encode(code[2+i*11],2))
print flag
  • flag: helloYouGotTheFlag

总结

  • 这是VM逆向中一种类型,即给定了opcode,要求输入的数据要符合opcode的执行结果。在DDCTF2018中还有个刚好反过来的,要求自己构造一个opcode,使虚拟机执行结果与程序给定的一致。目前看来,关于虚拟机的考察我就遇到这两种。
  • 也没什么好的方法,就是先要摸清楚虚拟机的结构,然后跟踪程序,摸清意图。再不行就侧信道吧~

你可能感兴趣的:(逆向)