VNCTF2022 wp复现


BabyMaze

直接去看原文吧:转自: https://ppppz.net/2022/02/08/BabyMaze/

CM1

gda打开apk.(jadx看不到FileUtils源码)

加载了 classes.dex, 传入FileUtils 和 进行了某些操作然后就变成了ooo。

在 assets中找到 ooo 导出。根据源码用vn2022循环异或 1024为一组。

生成新的dex文件。用jadx打开。

很明显XXTEA。直接解密。。

    k = [0x50703448, 0x4E565F59, 0x21465443, 0x4F764F21]
    res = [0x6CA42744, 0xC948EEAE, 0x0B26C84A, 0xD861543C, 0xAE634757, 0xB92F6878, 0x2100C7C6, 0xD9D4262A, 0x5CFE71C4, 0x32B376B5, 0x96202B87]

CM狗

参考链接贴上,慢慢复现

https://blog.shi1011.cn/ctf/2162#cm狗
https://blog.csdn.net/qq_52974719/article/details/123100965#t2
https://blog.csdn.net/m0_51911432/article/details/122914413#t4
http://s0rry.cn/archives/vnctf2022re-fu-xian#toc-head-6

struct REG
{
  _DWORD R[21]; // 21个寄存器
};

struct func
{
  void *call; // call 地址
  vm *ptr; // vm
};


struct vm
{
  REG reg; // 寄存器
  _DWORD Memory[1000];
  _DWORD rip; // VM下一个执行地址
  _DWORD index;
  void *data; // opcode
  func *func[100];
  _QWORD isExit;
};

下图是offset 值,看一下转的对不对。

右击 a1 转为 struct格式

void __golang main___ptr_MzVm__run(vm *a1)
{
  vm *v1; // rbx
  _DWORD *data; // rsi
  unsigned __int64 rip; // rax
  unsigned __int64 op1; // rdi
  unsigned __int64 v5; // r8
  unsigned int op2; // er8
  unsigned __int64 v7; // rax
  unsigned int op3; // esi
  __int64 v9; // [rsp+0h] [rbp-18h]
  void *retaddr; // [rsp+18h] [rbp+0h] BYREF

  while ( (unsigned __int64)&retaddr <= *(_QWORD *)(*(_QWORD *)NtCurrentTeb()->NtTib.ArbitraryUserPointer + 16LL) )
    runtime_morestack_noctxt();
  v1 = a1;
  while ( !LOBYTE(v1->isExit) )
  {
    data = v1->data;
    rip = (unsigned int)v1->rip;
    if ( rip >= 0xBB8 )
      runtime_panicIndex(v9);
    op1 = (unsigned int)data[rip];
    v5 = (unsigned int)(rip + 1);
    if ( v5 >= 0xBB8 )
      runtime_panicIndex(v9);
    op2 = data[v5];
    v7 = (unsigned int)(rip + 2);
    if ( v7 >= 0xBB8 )
      runtime_panicIndex(v9);
    op3 = data[v7];
    if ( op1 >= 0x64 )
      runtime_panicIndex(v9);
    v9 = __PAIR64__(op3, op2);
    ((void (*)(void))v1->func[op1]->call)();
    v1 = a1;
    a1->rip += 3;
  }
}

双击data来到opcode,每轮使用3个操作数。在ida中这样设置一下看清每一轮。

op=1

rip + 8返回了也没啥

__int64 __usercall main___ptr_MzVm__init_func2@(__int64 a1)
{
  __int64 v1; // rdx
  __int64 v2; // rdx
  __int64 result; // rax
  __int64 v4; // [rsp+0h] [rbp-18h]

  v2 = *(_QWORD *)(v1 + 8);
  result = (unsigned int)a1;
  if ( (unsigned int)a1 >= 0x15uLL )
    runtime_panicIndex(v4);
  *(_DWORD *)(v2 + 4LL * (unsigned int)a1) = HIDWORD(a1);
  return result;
}
CTF