首页
社区
课程
招聘
[原创] KCTF 2023 第十二题 wp - 98k
发表于: 2023-9-29 19:36 9528

[原创] KCTF 2023 第十二题 wp - 98k

2023-9-29 19:36
9528

程序中的一些关键函数加了混淆,直接把 0x49A0E8 处 patch 为 double 类型的 100.0 ,再声明其类型为 const double 这样 ida F5 就能直接去除无关的逻辑。

题目实现了一个虚拟机,程序启动后会先解密得到虚拟机执行的命令,之后来到函数 0x460D0E 执行:

v1->vtable + 15 就是虚表中的第 15 项,地址为 0x4525EB 。

相关数据结构:

将解密之后的指令所在的内存 dump 出来,写脚本恢复原始指令:

得到输出:

求解:

char __thiscall global_vtable_2_func_18(C *this)
{
  C *v1; // ebx
  int _pc; // esi
  B *ins_start; // edi MAPDST
  char *v6; // esi
  _DWORD *v7; // eax
  const char *v8; // ecx
  unsigned int v9; // edx
  unsigned int v10; // edi
  _BYTE *v11; // ebx
  char v12; // al
  int v14; // [esp+8h] [ebp-6Ch]
  char v16[88]; // [esp+1Ch] [ebp-58h] BYREF
 
  v1 = this;
  if ( v1->instructions.start == v1->instructions.finish )
    return 0;
  this->pc = 0;
  ins_start = this->instructions.start;
  if ( v1->instructions.finish - ins_start > 0 )
  {
    _pc = 0;
    ins_start = v1->instructions.start;
    do
    {
      if ( _pc == -1 )
      {
        v1->pc = 0;
        _pc = 0;
      }
      if ( !(*((unsigned __int8 (__thiscall **)(C *, B *))v1->vtable + 15))(v1, &ins_start[_pc]) )
      {
        // show error message
      }
      _pc = v1->pc + 1;
      v1->pc = _pc;
      ins_start = v1->instructions.start;
    }
    while ( _pc < v1->instructions.finish - ins_start );
  }
  return 1;
}
char __thiscall global_vtable_2_func_18(C *this)
{
  C *v1; // ebx
  int _pc; // esi
  B *ins_start; // edi MAPDST
  char *v6; // esi
  _DWORD *v7; // eax
  const char *v8; // ecx
  unsigned int v9; // edx
  unsigned int v10; // edi
  _BYTE *v11; // ebx
  char v12; // al
  int v14; // [esp+8h] [ebp-6Ch]
  char v16[88]; // [esp+1Ch] [ebp-58h] BYREF
 
  v1 = this;
  if ( v1->instructions.start == v1->instructions.finish )
    return 0;
  this->pc = 0;
  ins_start = this->instructions.start;
  if ( v1->instructions.finish - ins_start > 0 )
  {
    _pc = 0;
    ins_start = v1->instructions.start;
    do
    {
      if ( _pc == -1 )
      {
        v1->pc = 0;
        _pc = 0;
      }
      if ( !(*((unsigned __int8 (__thiscall **)(C *, B *))v1->vtable + 15))(v1, &ins_start[_pc]) )
      {
        // show error message
      }
      _pc = v1->pc + 1;
      v1->pc = _pc;
      ins_start = v1->instructions.start;
    }
    while ( _pc < v1->instructions.finish - ins_start );
  }
  return 1;
}
struct A
{
  int field_0;
  std::string s0;
  int i1;
  int i2;
  int i3;
  std::string s4;
  std::string s5;
  std::string s6;
};
 
struct std::vector$A$
{
  A *start;
  A *finish;
  A *end_of_storage;
};
 
struct B
{
  int is_label;
  int field_4;
  std::string s1;
  std::string s2;
  std::vector$A$ vector;
};
 
struct std::vector$B$
{
  B *start;
  B *finish;
  B *end_of_storage;
};
 
struct RBTree // std::map<std::string, std::string>
{
  struct RBTree *left;
  struct RBTree *parent;
  struct RBTree *right;
  char color;
  char isnil;
  char padding[2];
  std::string key;
  std::string value;
};
 
struct C
{
  int **vtable;
  RBTree *tree;
  int node_count;
  std::vector$B$ instructions;
  int pc;
  char valid_data;
};
struct A
{
  int field_0;
  std::string s0;
  int i1;
  int i2;
  int i3;
  std::string s4;
  std::string s5;
  std::string s6;
};
 
struct std::vector$A$
{
  A *start;
  A *finish;
  A *end_of_storage;
};
 
struct B
{
  int is_label;
  int field_4;
  std::string s1;
  std::string s2;
  std::vector$A$ vector;
};
 
struct std::vector$B$
{
  B *start;
  B *finish;
  B *end_of_storage;
};
 
struct RBTree // std::map<std::string, std::string>
{
  struct RBTree *left;
  struct RBTree *parent;
  struct RBTree *right;
  char color;
  char isnil;
  char padding[2];
  std::string key;
  std::string value;
};
 
struct C
{
  int **vtable;
  RBTree *tree;
  int node_count;
  std::vector$B$ instructions;
  int pc;
  char valid_data;
};
def vm(ins):
    opcode = int(ins[2])
    operands = ins[3]
    if opcode == 0x21344D4938CE0640:
        print('system({0})'.format(repr(operands[0][0].decode())))
    elif opcode == 0x3820EA1739C3E154:
        print('map[{0}] = hex(vigenere(map[{0}], "恭喜发财".encode("gbk")))'.format(repr(operands[0][4])))
    elif opcode == 0x4B0134D06B40680:
        print('if (len(map[{0}]) {1} {2}) goto {3}'.format(repr(operands[0][4]), operands[1][5].decode(), operands[2][1], operands[3][6].decode()))
    elif opcode == 0x5304FD305CA8C22A:
        print('sleep({})'.format(operands[0][1]))
    elif opcode == 0x5AC009C0F14B76E8:
        print('map[{0}] = input()'.format(repr(operands[0][4])))
    elif opcode == 0x6975C7A3C07CD226:
        print('map[{0}] += {1}'.format(repr(operands[0][4]), repr(operands[1][0])))
    elif opcode == 0x7929CBF0A1496FB0:
        print('map[{0}] = base64encode(map[{0}])'.format(repr(operands[0][4])))
    elif opcode == 0x885F75A1461ECEBB:
        print('if (map[{0}] == map[{1}]) goto {2}'.format(repr(operands[0][4]), repr(operands[1][4]), operands[2][6].decode()))
    elif opcode == 0x8DB9D83D80004137:
        print('print({})'.format(repr(operands[0][0].replace(b'\\n', b'\n').decode('gbk'))))
    elif opcode == 0xA43CBF9D015186F1:
        if len(operands): code = operands[0][1]
        else: code = 0
        print('exit({0})'.format(code))
    elif opcode == 0xAA9C8E70F01F8D61:
        print('map[{0}] = map[{1}]'.format(repr(operands[0][4]), repr(operands[1][4])))
    elif opcode == 0xDDEEFF2200112233:
        print('nop')
    elif opcode == 0xE56D33B21C50A892:
        print('goto {0}'.format(operands[0][6].decode()))
    elif opcode == 0xF4CC06C2E34200F0:
        print('nop 0')
    elif opcode == 0xF4CC06F2E3420459:
        print('nop 1')
    elif opcode == 0xFD1D1DFB19850CA1:
        print('map[{0}] = md5(map[{0}])'.format(repr(operands[0][4])))
    else:
        assert False, hex(opcode)
 
mem_offset = 0xea0000
mem_size = 0x20000
mem_dump = open('MEM_00EA0000_00020000.mem', 'rb').read()
 
ins_start = 0xeb4b00
ins_end = 0xeb62a4
 
def read_dword(addr):
    assert mem_offset <= addr < mem_offset + mem_size
    return int.from_bytes(mem_dump[addr - mem_offset: addr - mem_offset + 4], 'little')
 
def read_data(addr, size):
    assert mem_offset <= addr < mem_offset + mem_size - size
    return mem_dump[addr - mem_offset: addr - mem_offset + size]
 
def read_str(addr):
    size = read_dword(addr + 0x10)
    cap = read_dword(addr + 0x14)
    if cap > 0x10: addr = read_dword(addr)
    return read_data(addr, size)
 
def read_A(addr):
    return (read_str(addr + 4), read_dword(addr + 0x1c), read_dword(addr + 0x20), read_dword(addr + 0x24), read_str(addr + 0x28), read_str(addr + 0x40), read_str(addr + 0x58))
 
def read_B(addr):
    B = (read_dword(addr), read_dword(addr + 4), read_str(addr + 0x20), [])
    A_start = read_dword(addr + 0x38)
    A_end = read_dword(addr + 0x3c)
    for addr in range(A_start, A_end, 0x70):
        B[-1].append(read_A(addr))
    return B
 
ins = []
for addr in range(ins_start, ins_end, 0x44):
    ins.append(read_B(addr))
 
for i in range(len(ins)):
    t = ins[i]
    if t[0]:
        print(t[3][0][6].decode() + ':')
    else:
        # print(i, end=': ')
        print('    ', end='')
        vm(ins[i])
def vm(ins):
    opcode = int(ins[2])
    operands = ins[3]
    if opcode == 0x21344D4938CE0640:
        print('system({0})'.format(repr(operands[0][0].decode())))
    elif opcode == 0x3820EA1739C3E154:
        print('map[{0}] = hex(vigenere(map[{0}], "恭喜发财".encode("gbk")))'.format(repr(operands[0][4])))
    elif opcode == 0x4B0134D06B40680:
        print('if (len(map[{0}]) {1} {2}) goto {3}'.format(repr(operands[0][4]), operands[1][5].decode(), operands[2][1], operands[3][6].decode()))
    elif opcode == 0x5304FD305CA8C22A:
        print('sleep({})'.format(operands[0][1]))
    elif opcode == 0x5AC009C0F14B76E8:
        print('map[{0}] = input()'.format(repr(operands[0][4])))
    elif opcode == 0x6975C7A3C07CD226:
        print('map[{0}] += {1}'.format(repr(operands[0][4]), repr(operands[1][0])))
    elif opcode == 0x7929CBF0A1496FB0:
        print('map[{0}] = base64encode(map[{0}])'.format(repr(operands[0][4])))
    elif opcode == 0x885F75A1461ECEBB:
        print('if (map[{0}] == map[{1}]) goto {2}'.format(repr(operands[0][4]), repr(operands[1][4]), operands[2][6].decode()))
    elif opcode == 0x8DB9D83D80004137:
        print('print({})'.format(repr(operands[0][0].replace(b'\\n', b'\n').decode('gbk'))))
    elif opcode == 0xA43CBF9D015186F1:
        if len(operands): code = operands[0][1]
        else: code = 0
        print('exit({0})'.format(code))
    elif opcode == 0xAA9C8E70F01F8D61:
        print('map[{0}] = map[{1}]'.format(repr(operands[0][4]), repr(operands[1][4])))
    elif opcode == 0xDDEEFF2200112233:
        print('nop')
    elif opcode == 0xE56D33B21C50A892:
        print('goto {0}'.format(operands[0][6].decode()))
    elif opcode == 0xF4CC06C2E34200F0:
        print('nop 0')
    elif opcode == 0xF4CC06F2E3420459:
        print('nop 1')
    elif opcode == 0xFD1D1DFB19850CA1:
        print('map[{0}] = md5(map[{0}])'.format(repr(operands[0][4])))
    else:
        assert False, hex(opcode)
 
mem_offset = 0xea0000
mem_size = 0x20000
mem_dump = open('MEM_00EA0000_00020000.mem', 'rb').read()
 
ins_start = 0xeb4b00

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 3
支持
分享
最新回复 (3)
雪    币: 214
活跃值: (283)
能力值: ( LV5,RANK:77 )
在线值:
发帖
回帖
粉丝
2
太强了吧
2023-10-1 15:43
0
雪    币: 3070
活跃值: (30876)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
感谢分享
2023-10-1 21:15
1
雪    币: 3159
活跃值: (2839)
能力值: ( LV12,RANK:383 )
在线值:
发帖
回帖
粉丝
4
太强了,脚本原文都还原出来了
2023-10-2 10:38
0
游客
登录 | 注册 方可回帖
返回
//