0xD009
6788 字
34 分钟
RCTF2024赛后复现(上)

2048#

play 2048 to win the flag!

远程题,赛后无法访问了。

当时看了以下附件,就是纯 2048 ,然后可以下注,从一个初始的成本积分赢到指定积分即可获得 flag ,亏空则失败。

由于本人 2048 技术还行,加之这版 2048 经过魔改,新块的值是 16 ,比原游戏的 2 和 4 简单不少,而且还不是随机出现,所以我选择直接手打,最后也是一次不输直接拿到了 flag 。

至于自动化的解法,笔者没有多想,感兴趣可以参考 Arr3stY0u 的解法(看了之后感觉选择手摇是正确的)。

不过官方是这么说的: 确实没发现,还是目标设置的太低了。

Dr.Akira#

Wrap the obtained string around RCTF{}

查壳,发现有壳:

官方链接:https://www.oreans.com/Themida.php

自己试了一下手动脱壳,发现还有反调试,遂找到这个 Github Repo,还挺开箱即用的,好评。

不过它这个脱出来是运行不了的,只能静态看看,通过运行程序发现提示:

看来跟注册表有关,在 IDA 中查找这个字符串,找到了如下的函数:

__int64 __fastcall sub_1001A2BB0(__int64 a1, __int64 a2)
{
  _QWORD *v3; // rbx
  __int64 v5; // [rsp+30h] [rbp-10h] BYREF
  __int64 v6; // [rsp+38h] [rbp-8h] BYREF
  __int64 savedregs; // [rsp+40h] [rbp+0h] BYREF

  v6 = 0i64;
  v5 = 0i64;
  sub_100008FA0(&v5, "Software\\DrAkira");
  v3 = (_QWORD *)sub_10000E180(&unk_10024A2D0, 1i64);
  if ( (unsigned __int8)sub_1001A31F0(*v3, v5) )
  {
    sub_1001A3270(*v3, &v6, v5, "MyKeys");
    if ( !v6 )
      sub_100145EB0("MyKeys value not found.");
  }
  else
  {
    sub_100145EB0("Registry key not found.");
  }
  sub_100008FA0(a2, v6);
  return sub_1001A2B80(&savedregs);
}

应该就是在读注册表,之后进行一些处理,不过这处理不是很看得明白,还是得调试一下,当时跟着 B 站这个视频教程做的(看视频教程太抽象了我说,总结一下,要过五个点:

  1. PEB.BeingDebugged 置 0
  2. PEB.NtGlobalFlag 置 0
  3. NtSetInformationThread
  4. NtQueryInformationProcess
  5. 调试器窗口检测

前两个属于老生常谈了,修改标志位,PEB 结构体在 gs:[60],偏移 +2 处为 BeingDebugged ,偏移 +0xBC 处为 NtGlobalFlag,直接通过 x64dbg 的“隐藏调试器”也能过掉,具体可以参考下面几个链接: https://xz.aliyun.com/t/14554?time__1311=GqAhDKYIMYGXwdxUxYuemqg4jxWqwvmD#toc-10 https://jev0n.com/2021/11/18/debug-1.html https://crackmes.cn/doc/107/

好像有些链接也提到了后面的几种反调试,这个是很少看到介绍 NtSetInformationThread 的。

绕过方法即,在这个函数下条件断点,如果 rdx == 0x11,那么断下,把 rdx 置为 3 (参考 https://www.geoffchappell.com/studies/windows/km/ntoskrnl/api/ps/psquery/class.htm ),或者把句柄改为 -1 (0xFFFFFFFFFFFFFFFF),可能是代表无效线程 。

接下来是 NtQueryInformationProcess ,看这篇: https://www.cnblogs.com/Sna1lGo/p/15206766.html 同样设置条件断点,针对第二个参数,当 rdx == 7 || rdx == 0x1E 时断下,然后在返回前把 r8 置 0 (因为函数通过形参传址的方式返回),如果 rdx 为 0x1E ,还要把返回值置为 0xC0000353(STATUS_PORT_NOT_SET)。

最后是调试器窗口检测,获取窗口句柄之后,写一个 C 程序死循环 SetWindowTextW 重命名窗口名即可。

#include <iostream>
#include <Windows.h>
#include <thread>
#include <chrono>

int main() {
    HWND hwnd_dbg = (HWND)0x009D0B10;
    HWND hwnd_ida = (HWND)0x0041094C;

    while (true) {
        SetWindowTextW(hwnd_dbg, L"hahaha");
        SetWindowTextW(hwnd_ida, L"hehehe");

        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }

    return 0;
}

至此终于完成了所有的反调试绕过。后来看有师傅的 wp 说只用 Sharpod 插件就行,先 mark 一下:https://github.com/A-new/x64dbg_plugin

调试后得到 check 点在这里:

char __fastcall sub_1001A5A10(__int64 a1)
{
  __int64 v1; // rax
  __int64 v2; // rax
  __int64 v3; // rax
  __int64 v4; // rax
  __int64 v5; // rax
  unsigned int v6; // edi
  int v7; // ebx
  int v8; // esi
  __int64 v9; // rax
  __int64 v10; // rax
  char v11; // si
  __int64 v12; // rax
  __int64 v13; // rax
  int v14; // eax
  int v15; // ebx
  int v16; // ebx
  __int64 v18[5]; // [rsp+40h] [rbp-50h]
  char v19[19]; // [rsp+68h] [rbp-28h]
  char v20[13]; // [rsp+7Bh] [rbp-15h] BYREF
  __int64 v21; // [rsp+88h] [rbp-8h]
  __int64 savedregs; // [rsp+90h] [rbp+0h] BYREF

  v21 = a1;
  sub_10000D720(a1);
  v1 = sub_1001A5C60(&unk_10024A610, 1i64);
  if ( v1 )
    v1 += 32i64;
  v18[0] = v1;
  v2 = sub_1001A5D70(&unk_10024A738, 1i64);
  if ( v2 )
    v2 += 40i64;
  v18[1] = v2;
  v3 = sub_1001A5EC0(&unk_10024A860, 1i64);
  if ( v3 )
    v3 += 40i64;
  v18[2] = v3;
  v4 = sub_1001A6010(&unk_10024A988, 1i64);
  if ( v4 )
    v4 += 32i64;
  v18[3] = v4;
  v5 = sub_1001A6150(&unk_10024AAB0, 1i64);
  if ( v5 )
    v5 += 32i64;
  v18[4] = v5;
  v6 = 0;
  v7 = -1;
  do
  {
    v8 = byte_1001C6EA0[++v7] - 1;
    if ( v8 >= 0 && v8 < 5i64 )
    {
      sub_1001A31B0();
      v9 = sub_10000D650(v21);
      (*(void (__fastcall **)(__int64, __int64, __int64, _QWORD))(*(_QWORD *)v18[v8] + 8i64))(v18[v8], v21, v9, v6);
      v10 = sub_10000D650(v21);
      v6 = (**(__int64 (__fastcall ***)(__int64, __int64, __int64, _QWORD))v18[v8])(v18[v8], v21, v10, v6);
    }
  }
  while ( v7 < 12 );
  v11 = 1;
  v19[0] = 69;
  v19[1] = -85;
  v19[2] = -67;
  v19[3] = -66;
  v19[4] = -81;
  v19[5] = -85;
  v19[6] = 70;
  v19[7] = 70;
  v19[8] = 39;
  v19[9] = 93;
  v19[10] = -120;
  v19[11] = -103;
  v19[12] = -98;
  v19[13] = 113;
  v19[14] = 126;
  v19[15] = -104;
  v19[16] = 0;
  v19[17] = -110;
  v19[18] = -105;
  qmemcpy(v20, "j#", 2);
  v20[2] = 127;
  v20[3] = 123;
  v20[4] = 87;
  v20[5] = -52;
  v20[6] = 109;
  v20[7] = 100;
  v20[8] = 120;
  v20[9] = -32;
  v20[10] = 97;
  v12 = v21;
  if ( v21 )
    v12 = *(_QWORD *)(v21 - 8) + 1i64;
  if ( v12 <= 30 )
  {
    LODWORD(v13) = v21;
    if ( v21 )
      v13 = *(_QWORD *)(v21 - 8) + 1i64;
    v14 = v13 - 1;
    if ( v14 >= 0 )
    {
      v15 = -1;
      do
      {
        ++v15;
        if ( *(_BYTE *)(v21 + v15) != v19[v15] )
          v11 = 0;
      }
      while ( v14 > v15 );
    }
  }
  else
  {
    v11 = 0;
  }
  v16 = -1;
  do
    v18[++v16] = 0i64;
  while ( v16 < 4 );
  sub_1001A59E0(&savedregs);
  return v11;
}

大概知道它是拿着几个函数按一定调用次序做的加密,但总跟我静态看的对不上,索性直接动态看,然后 z3 求解了,说到这不得不吐槽一下官方 wp 了:

前面直接“逆向处理”一把带过了。。。

以下是我的脚本。

n = [
    0xFE, 0x11, 0xFA, 0x9D, 0xE2, 0x02, 0x97, 0xCA, 0x95, 0x2A, 0x5C, 0x9F, 0x0D, 0x86, 0xF6, 0x42,
    0x5C, 0x74, 0xFF, 0x77, 0x49, 0x2B, 0x9D, 0x28, 0xC5, 0xD3, 0x89, 0x94, 0xB7, 0xA8, 0x69, 0x82
]
hexstr = '45ABBDBEAFAB4646275D88999E717E980092976A237F7B57CC6D6478E061'

cip = bytes.fromhex(hexstr)

from z3 import *

s = Solver()

flag = [BitVec(f'flag_{i}', 8) for i in range(0x1E)]

n = [flag[i] for i in range(0x1E)]

for i in range(0x1E):
    n[i] ^= 0x8

for i in range(1, 6):
    n[i] -= 0xBE
    n[i] &= 0xFF

for i in range(5, 11):
    n[i] += 0xEF
    n[i] &= 0xFF

for i in range(10, 15):
    n[i] -= 0xBE
    n[i] &= 0xFF

n[0x13] ^= 0x44

n[0x10] ^= 0x80

for i in range(13, 19):
    n[i] += 0xEF
    n[i] &= 0xFF

n[0x18] ^= 0x80

n[0x14] ^= 0x44

for i in range(0x1E):
    n[i] ^= 0x8

for i in range(15, 20):
    n[i] -= 0xBE
    n[i] &= 0xFF

n[0x1C] ^= 0x80

for i in range(0x1E):
    n[i] ^= 0x8

for i in range(0x1E):
    s.add(n[i] == cip[i])

if s.check() == sat:
    m = s.model()
    k = bytes([m[flag[i]].as_long() for i in range(0x1E)])
print(k)

检验成功后,会用注册表中的值去做文件解密,接下来转过头去看:

__int64 __fastcall rsa(__int64 a1, _QWORD *a2, __int64 a3)
{
  __int64 v4; // rbx
  __int64 v5; // rsi
  __int64 v6; // rdi
  __int64 v7; // rax
  int v8; // eax
  int i; // edx
  __int64 v11; // [rsp+48h] [rbp-218h] BYREF
  char *v12; // [rsp+50h] [rbp-210h] BYREF
  char v13[512]; // [rsp+58h] [rbp-208h] BYREF
  __int64 v14; // [rsp+258h] [rbp-8h]
  __int64 savedregs; // [rsp+260h] [rbp+0h] BYREF

  v14 = a3;
  sub_10000D720(a3);
  v12 = 0i64;
  v4 = sub_1001A56C0(&unk_10024A3F8, 1i64, 1024i64);
  v5 = sub_1001A56C0(&unk_10024A3F8, 1i64, 1024i64);
  v6 = sub_1001A56C0(&unk_10024A3F8, 1i64, 1024i64);
  sub_1001A5800(v4, &unk_1001C6D90, 129i64);
  sub_1001A5800(v5, &unk_1001C6E20, 128i64);
  sub_100003030(v13, 512i64, 0i64);
  sub_1001A5840(v6, v13, 512i64);
  LODWORD(v7) = v14;
  if ( v14 )
    v7 = *(_QWORD *)(v14 - 8) + 1i64;
  v8 = v7 - 1;
  if ( v8 >= 0 )
  {
    for ( i = -1; i < v8; v13[i] = *(_BYTE *)(v14 + i) )
      ++i;
  }
  sub_1001A5800(v6, v13, 512i64);
  sub_1001A5890(v6, v5, v4);
  sub_100003030(v13, 512i64, 0i64);
  sub_1001A5840(v6, v13, 512i64);
  sub_10000D670(&v12, &unk_10024A0B8);
  v11 = 512i64;
  sub_10000D7C0(&v12, (__int64)&unk_10024A0B8, 1i64, &v11);
  qmemcpy(v12, v13, 0x200ui64);
  sub_10000D770(a2, (__int64)v12, (__int64)&unk_10024A0B8);
  return sub_1001A2C70(&savedregs);
}

这是在做 RSA ,比赛时真没看出来,最后是 Ichild 爷看出来的,因为有 1024b 的素数,不过不是 p 和 q 而是 n 和 d ,还要做 Crypto ,这里 d 是过大的,那么 e 可能就是过小的,使用Wiener’s attack

from RSAwienerHacker import hack_RSA
from Crypto.Util.number import bytes_to_long, long_to_bytes

n = bytes_to_long(bytes.fromhex('3F68386D7C52FBB3DFE3CCACC3DCFD1BA66CAAC7A5FC040F7CC0E55BF1ABEB92330BA492AC81084791CBD70B97A545A1CF9D0CC87E159C286964B906955C798830D36F18DCB003B8B477CE3E5AB1576C5484A6F6D1D79718BDA50BDC3C1A5910DFE6F0DC90080B3F2913C2419FDA4691ED6D7C2A3E7CF92C3FCD60D5560368E901')[::-1])
e = bytes_to_long(bytes.fromhex('C5B38CCE2D27139C5B552C93F8FE3D6CFB2B03F70E27BC80BBD178C991E910DB553A6329636B74B4106FC209CBFB6B00434F03B2D9B7EE0CE2F816D14F68BEAE891CA3AE6C1F13772F1C9D2F4854BB9AD81250EE1E1D3A4039144710814911A24B1A9D59ED9F04A256632D7ECED4AA3FBBB962CDB9047FDF83A904F6D6892D24')[::-1])

d = hack_RSA(e, n)

c = bytes_to_long(b'Master__0f__THE_Windows_Delphi'[::-1])
m = pow(c, d, n)
k = long_to_bytes(m)[::-1]

with open('diary.secret', 'rb') as f:
    data = f.read()

with open('diary.me', 'wb') as f:
    f.write(bytes([data[i] ^ k[i % len(k)] for i in range(len(data))]))

最后解出来是一张 jpg 图片:

blocker_vm#

Is it VM, is it anti-debugging?

主函数,父进程(稍后讲为什么是父进程)走不触发这个错误的分支:

接下来是一个根据错误号出的平坦化控制流;

int sub_421A10()
{
  HMODULE ModuleHandleW; // eax
  char v1; // al
  char LastError; // al
  size_t v4; // eax
  char v5; // [esp+0h] [ebp-A5Ch]
  char v6; // [esp+0h] [ebp-A5Ch]
  char v7; // [esp+0h] [ebp-A5Ch]
  unsigned int k; // [esp+320h] [ebp-73Ch]
  void *lpBaseAddress; // [esp+32Ch] [ebp-730h]
  size_t j; // [esp+338h] [ebp-724h]
  size_t i; // [esp+344h] [ebp-718h]
  int v12; // [esp+350h] [ebp-70Ch]
  int v13; // [esp+35Ch] [ebp-700h]
  char Buffer[264]; // [esp+3A4h] [ebp-6B8h] BYREF
  CONTEXT Context; // [esp+4ACh] [ebp-5B0h] BYREF
  struct _DEBUG_EVENT DebugEvent; // [esp+780h] [ebp-2DCh] BYREF
  struct _PROCESS_INFORMATION ProcessInformation; // [esp+7E8h] [ebp-274h] BYREF
  struct _STARTUPINFOW StartupInfo; // [esp+800h] [ebp-25Ch] BYREF
  WCHAR Filename[262]; // [esp+84Ch] [ebp-210h] BYREF

  __CheckForDebuggerJustMyCode(&unk_42D0AC);
  j_memset(Filename, 0, 0x208u);
  StartupInfo.cb = 0x44;
  j_memset(&StartupInfo.lpReserved, 0, 0x40u);
  memset(&ProcessInformation, 0, sizeof(ProcessInformation));
  j_memset(&DebugEvent, 0, sizeof(DebugEvent));
  j_memset(&Context, 0, sizeof(Context));
  j_memset(Buffer, 0, 0xFFu);
  sub_4210EB("please input your flag:\n", v5);
  sub_421037("%s", (char)Str);
  if ( j_strlen(Str) != 25 || Str[24] != 125 )
    exit(0);
  Str[25] = 0;
  ModuleHandleW = GetModuleHandleW(0);
  GetModuleFileNameW(ModuleHandleW, Filename, 0x104u);
  if ( CreateProcessW(0, Filename, 0, 0, 0, 3u, 0, 0, &StartupInfo, &ProcessInformation) )
  {
    v13 = -3;
    v12 = 1;
    while ( 1 )
    {
      j_memset(&DebugEvent, 0, sizeof(DebugEvent));
      if ( !WaitForDebugEvent(&DebugEvent, 0xFFFFFFFF) )
        break;
      if ( DebugEvent.dwDebugEventCode == 1 )
      {
        switch ( DebugEvent.u.Exception.ExceptionRecord.ExceptionCode )
        {
          case 0xC0000094:
            for ( i = 0; i < j_strlen(Str); ++i )
              Str[i] ^= 0x7Du;
            Context.ContextFlags = 0x10007;
            GetThreadContext(ProcessInformation.hThread, &Context);
            Context.Eip += 2;
            SetThreadContext(ProcessInformation.hThread, &Context);
            break;
          case 0xC0000096:
            for ( j = 0; j < j_strlen(Str); ++j )
              byte_42B26C[j] = (Str[j] << 6) | (Str[j] >> 2) & 0x3F;
            Context.ContextFlags = 65543;
            GetThreadContext(ProcessInformation.hThread, &Context);
            ++Context.Eip;
            SetThreadContext(ProcessInformation.hThread, &Context);
            break;
          case 0xC000008E:
            Context.ContextFlags = 65543;
            GetThreadContext(ProcessInformation.hThread, &Context);
            Context.Eip += 4;
            SetThreadContext(ProcessInformation.hThread, &Context);
            break;
          case 0xC0000005:
            v4 = j_strlen(Str);
            sub_42100F(byte_42B26C, v4, aThisisyoursecr, 18);
            Context.ContextFlags = 65543;
            GetThreadContext(ProcessInformation.hThread, &Context);
            Context.Eip += 2;
            SetThreadContext(ProcessInformation.hThread, &Context);
            break;
          case 0x80000003:
            if ( ++v13 < 0 )
            {
              if ( v13 == -1 )
              {
                Context.ContextFlags = 65543;
                GetThreadContext(ProcessInformation.hThread, &Context);
                lpBaseAddress = (void *)Context.Eip;
                SetThreadContext(ProcessInformation.hThread, &Context);
                ReadProcessMemory(ProcessInformation.hProcess, lpBaseAddress, Buffer, 0xD6u, 0);
                for ( k = 0; k < 0xD6; ++k )
                  Buffer[k] ^= 0x44u;
                WriteProcessMemory(ProcessInformation.hProcess, lpBaseAddress, Buffer, 0xD6u, 0);
                ReadProcessMemory(ProcessInformation.hProcess, lpBaseAddress, Buffer, 0xD6u, 0);
              }
            }
            else
            {
              v12 = ((unsigned __int8)byte_42B26C[v13] == dword_42B018[v13]) & (unsigned __int8)v12;
            }
            break;
        }
      }
      else if ( DebugEvent.dwDebugEventCode == 5 )
      {
        goto LABEL_35;
      }
      ContinueDebugEvent(DebugEvent.dwProcessId, DebugEvent.dwThreadId, 0x10002u);
    }
    LastError = GetLastError();
    sub_4210EB("WaitForDebugEvent() failed! [%d]n", LastError);
LABEL_35:
    sub_4210EB("\n", v6);
    if ( v12 )
      return sub_4210EB("Congratulations! flag is your input\n", v7);
    else
      return sub_4210EB("try again\n", v7);
  }
  else
  {
    v1 = GetLastError();
    return sub_4210EB("CreateProcess() failed! [%d]n", v1);
  }
}

CreateProcessW 创建了一个新的子进程,进程运行的程序就是本程序,新进程执行到 main 函数时,会走另一个分支,然后触发错误,引起 SMC ,将 214 个代码段字节全部异或 0x44 ,就可以看到一段代码,这段代码在不断触发错误,使父进程根据错误来进行字符串处理。

随便看了一下,包含 RC4, 循环左移 6 位,异或 0x7D :

cip = b'\x80\x05\xe3/\x18/\xc5\x8c%p\xbc\x05\x1cO\xf2\x02\xe5>\x02/\xe5\x11\xa3\xc0'

def RC4_GenBox(box, key):
    for i in range(256):
        box[i] = i
    i = 0
    for j in range(256):
        i = (box[j] + i + key[j % len(key)]) & 0xff
        tmp = box[j]
        box[j] = box[i]
        box[i] = tmp

def RC4_Encrypt(box, data, out):
    k = 0
    j = 0
    for i in range(len(data)):
        k = k + 1
        j = (box[k] + j) & 0xff
        tmp = box[k]
        box[k] = box[j]
        box[j] = tmp
        a = box[(box[k] + box[j]) & 0xff]
        out[i] = a ^ data[i]

box = [0] * 256
out = [0] * len(cip)

key = b'thisisyoursecretke'

RC4_GenBox(box, key)
RC4_Encrypt(box, cip, out)

cip = out
flag = b''

for i in range(24):
    tmp = cip[i]
    tmp = (tmp << 2 | tmp >> 6) & 0xFF
    tmp = tmp ^ 0x7D
    flag += bytes([tmp])

print(bytes(flag) + b'}')

# RCTF{a_baby_debug_bloker}

这里面有一个很弱智的点在于 RC4 的 key 在 IDA 中是 19 位的,但是传参的时候长度传的是 18 ,导致最后一位没有用上,不知道是不是出题人有意为之,如果是的话可以说非常逆天了。

PPTT#

Conventional

本题和树相关,关于树的部分不详细介绍了,说一下大致逻辑:对 24 位的输入进行层序建树,然后前序遍历、中序遍历树,生成两个串,对中序遍历的串再进行一波置换,包括循环内也是一种置换。

int __cdecl main_0(int argc, const char **argv, const char **envp)
{
  int v3; // eax
  int v5; // eax
  __int64 v6; // rax
  unsigned __int64 v7; // kr00_8
  int v8; // eax
  int v9; // eax
  __int64 v10; // [esp+1C4h] [ebp-214h]
  int v11; // [esp+1CCh] [ebp-20Ch]
  int v12; // [esp+1D0h] [ebp-208h]
  int v13; // [esp+1D4h] [ebp-204h]
  int v14; // [esp+1D8h] [ebp-200h]
  int v15; // [esp+1DCh] [ebp-1FCh]
  int v16; // [esp+1E0h] [ebp-1F8h]
  __int64 v17; // [esp+204h] [ebp-1D4h]
  __int64 v18; // [esp+214h] [ebp-1C4h]
  __int64 v19; // [esp+224h] [ebp-1B4h]
  __int64 v20; // [esp+234h] [ebp-1A4h]
  int j; // [esp+264h] [ebp-174h]
  int i; // [esp+270h] [ebp-168h]
  char v23[24]; // [esp+27Ch] [ebp-15Ch] BYREF
  char tmp; // [esp+29Fh] [ebp-139h]
  char v25[64]; // [esp+2A8h] [ebp-130h] BYREF
  char pre_traverse_str[72]; // [esp+2F0h] [ebp-E8h] BYREF
  char mid_traverse_str[72]; // [esp+338h] [ebp-A0h] BYREF
  tree *root; // [esp+380h] [ebp-58h]
  int v29; // [esp+38Ch] [ebp-4Ch]
  char input[36]; // [esp+398h] [ebp-40h] BYREF
  int v31; // [esp+3BCh] [ebp-1Ch]
  _DWORD *(__cdecl *v32)(_DWORD *, int, int); // [esp+3C0h] [ebp-18h]
  int v33; // [esp+3D4h] [ebp-4h]

  v31 = 0;
  v32 = hook;
  sub_A71532(input);
  v33 = 0;
  print(std::cout, "Enter a string: ");
  scan(std::cin, input);
  v32 = hook;
  if ( str_len(input) == 24 )
  {
    v5 = print(std::cout, "In confirmation...");
    std::ostream::operator<<(v5, sub_A7106E);
    evil_value = 0xA7C0D2;
    v29 = 0;
    root = build_tree(input);
    j_memset(mid_traverse_str, 0, 0x40u);
    j_memset(pre_traverse_str, 0, 0x40u);
    j_pre_traverse(root, pre_traverse_str);
    pre_traverse_str[24] = 0;
    idx = 0;
    j_mid_traverse(root, mid_traverse_str);
    j_memset(v25, 0, sizeof(v25));
    tmp = mid_traverse_str[15];
    mid_traverse_str[15] = mid_traverse_str[16];
    mid_traverse_str[16] = tmp;
    sleep(SLOBYTE(root->value));
    tmp = mid_traverse_str[7];
    mid_traverse_str[7] = mid_traverse_str[17];
    mid_traverse_str[17] = tmp;
    tmp = mid_traverse_str[18];
    mid_traverse_str[18] = mid_traverse_str[8];
    mid_traverse_str[8] = tmp;
    tmp = mid_traverse_str[3];
    mid_traverse_str[3] = mid_traverse_str[19];
    mid_traverse_str[19] = tmp;
    tmp = mid_traverse_str[20];
    mid_traverse_str[20] = mid_traverse_str[9];
    mid_traverse_str[9] = tmp;
    tmp = mid_traverse_str[21];
    mid_traverse_str[21] = mid_traverse_str[22];
    mid_traverse_str[22] = tmp;
    tmp = mid_traverse_str[10];
    mid_traverse_str[10] = mid_traverse_str[4];
    mid_traverse_str[4] = tmp;
    tmp = mid_traverse_str[1];
    mid_traverse_str[1] = mid_traverse_str[23];
    mid_traverse_str[23] = tmp;
    tmp = mid_traverse_str[11];
    mid_traverse_str[11] = mid_traverse_str[12];
    mid_traverse_str[12] = tmp;
    tmp = mid_traverse_str[5];
    mid_traverse_str[5] = mid_traverse_str[13];
    mid_traverse_str[13] = tmp;
    tmp = mid_traverse_str[14];
    mid_traverse_str[14] = mid_traverse_str[6];
    mid_traverse_str[6] = tmp;
    tmp = mid_traverse_str[2];
    mid_traverse_str[2] = mid_traverse_str[0];
    mid_traverse_str[0] = tmp;
    memset(v23, 0, sizeof(v23));
    for ( i = 0; i < 3; ++i )                   // 分成 3 个 int64 遍历
    {
      for ( j = 0; j < 8; ++j )
      {
        LODWORD(v6) = *(_DWORD *)&v23[8 * i];
        HIDWORD(v6) = *(_DWORD *)&v23[8 * i + 4];
        v6 <<= 8;
        *(_DWORD *)&v23[8 * i] = v6;
        *(_DWORD *)&v23[8 * i + 4] = HIDWORD(v6);
        v7 = __PAIR64__(*(_DWORD *)&v23[8 * i + 4], *(_DWORD *)&v23[8 * i])
           + (unsigned int)mid_traverse_str[8 * i + 7 - j];
        *(_DWORD *)&v23[8 * i] = v7;
        *(_DWORD *)&v23[8 * i + 4] = HIDWORD(v7);
      }
    }
    v20 = *(_QWORD *)&v23[8] & *(_QWORD *)v23;
    v19 = (*(_QWORD *)&v23[8] & *(_QWORD *)v23 | *(_QWORD *)&v23[16] & *(_QWORD *)v23) + 0x10086i64;
    v18 = (*(_QWORD *)&v23[16] & *(_QWORD *)v23 ^ *(_QWORD *)&v23[16] & *(_QWORD *)&v23[8]) - 0x114514i64;
    v17 = *(_QWORD *)&v23[8] & *(_QWORD *)v23 ^ *(_QWORD *)&v23[16] & *(_QWORD *)v23;
    v10 = 0i64;
    v11 = 0;
    v12 = 0;
    v13 = 0;
    v14 = 0;
    v15 = 0;
    v16 = 0;
    if ( (*(_QWORD *)&v23[8] & *(_QWORD *)v23 & (~(*(_QWORD *)&v23[8] | *(_QWORD *)v23) | *(_QWORD *)&v23[16] & *(_QWORD *)v23 | *(_QWORD *)&v23[16] & *(_QWORD *)&v23[8] & ~v18) | *(_QWORD *)&v23[16] & *(_QWORD *)&v23[8] & v18) == 0x67437616 )
      LODWORD(v10) = 1;
    if ( (*(_QWORD *)v23 ^ (v20 & ~v18 | v20 & ~v19 | v17 & v19 | *(_QWORD *)&v23[16] & *(_QWORD *)v23 & ~v18)) == 0x400010000622000i64 )
      HIDWORD(v10) = 1;
    if ( (v18 ^ (v19 - v20)) == 0x2100A0203EFBB8Bi64 )
      v11 = 1;
    if ( (v17 ^ v19 ^ v20) == 0x4083102108Ei64 )
      v12 = 1;
    if ( (v19 ^ v17) - v18 == 0x1551566F3C6485EDi64 )
      v13 = 1;
    if ( (v18 ^ v19 ^ *(_QWORD *)&v23[16] & *(_QWORD *)&v23[8]) == 0x40836ECAB9Ai64 )
      v14 = 1;
    if ( (v17 ^ v20) - v18 == 0x3E51566F3C718563i64 )
      v15 = 1;
    if ( *(_QWORD *)v23 - *(_QWORD *)&v23[8] == 0x1AEFF6FDFC121BF1i64 )
      v16 = 1;
    if ( v10
      && v11
      && v14
      && v12
      && v13
      && v15
      && v16
      && !(_DWORD)v10
      && !j_strcmp("tyeuaTsm}qjrp", &pre_traverse_str[11])
      && (*(_QWORD *)&v23[16] + *(_QWORD *)&v23[8] + *(_QWORD *)v23) % 10i64 == 8 )
    {
      v8 = print(std::cout, "you are right");
      std::ostream::operator<<(v8, sub_A7106E);
    }
    else
    {
      v9 = print(std::cout, "Man!Haha,You are wrong");
      std::ostream::operator<<(v9, sub_A7106E);
    }
    system("pause");
    ExitProcess(0);
  }
  v3 = print(std::cout, "flag's length is wrong");
  std::ostream::operator<<(v3, sub_A7106E);
  system("pause");
  v33 = -1;
  sub_A71497(input);
  return 0;
}

然后给出了一些约束,需要约束求解。

不算一道难题,但是有两个逆天的反调试很难注意到,一是利用错误处理机制,跳过了第一次 swap:

这里 xor eax, eax 会将 eax 清零,接着取该地址的值,就会触发错误,直接跳过一段,交叉引用 00A8944C 处的一个整型(即我所重命名的 evil_value),即可发现这个错误处理函数:

PEXCEPTION_RECORD *__cdecl sub_A78200(PEXCEPTION_RECORD a1, int a2, PCONTEXT context)
{
  PEXCEPTION_RECORD *result; // eax
  DWORD flOldProtect[2]; // [esp+D0h] [ebp-8h] BYREF

  __CheckForDebuggerJustMyCode(&unk_A8C038);
  if ( a1->ExceptionCode == EXCEPTION_ACCESS_VIOLATION )
  {
    VirtualProtect((LPVOID)context->Eip, 2u, 0x40u, flOldProtect);
    *(_BYTE *)(context->Eip + 1) = 0x90;
    VirtualProtect((LPVOID)context->Eip, 2u, flOldProtect[0], flOldProtect);
    ++context->Eip;
    context->EFlags |= 0x100u;
    return 0;
  }
  else
  {
    result = (PEXCEPTION_RECORD *)a1;
    if ( a1->ExceptionCode == EXCEPTION_SINGLE_STEP )
    {
      context->Eip = evil_value;
      ++dword_A89450;
      return 0;
    }
  }
  return result;
}

如果在 IDA 中调试,可以选择 pass to app 来调用这个错误处理函数,像上面这样把形参类型修改以下,会更好看些;在 x64dbg 里则是设置该错误由被调试对象处理,然后查看 SEH链

我们会触发两次错误,第一次是 EXCEPTION_ACCESS_VIOLATION,触发后 SMC ,改了个 nop,然后 eip+1 ,置位 Trap Flag ,返回之后马上就会触发第二次 EXCEPTION_SINGLE_STEP 错误,进行一次跳转,跳过第一次 swap 。

第二个反调试是全局 hook 了 strcmp 函数,在比较时会将 11 位置的字符 +1 :

int sub_A78370()
{
  HMODULE ModuleHandleA; // [esp+DCh] [ebp-8h]

  __CheckForDebuggerJustMyCode(&unk_A8C038);
  ModuleHandleA = GetModuleHandleA(0);
  sub_A71357((int)ModuleHandleA, "strcmp", (int)sub_A71285);
  return 0;
}

这个藏在 initterm 的全局初始化函数中。

最后完整的解法如下:

from z3 import *
from Crypto.Util.number import long_to_bytes

s = Solver()

v1 = BitVec('v1', 64)
v2 = BitVec('v2', 64)
v3 = BitVec('v3', 64)

v17 = BitVec('v17', 64)
v18 = BitVec('v18', 64)
v19 = BitVec('v19', 64)
v20 = BitVec('v20', 64)

s.add(v20 == v2 & v1)
s.add(v19 == (v2 & v1 | v3 & v1) + 0x10086)
s.add(v18 == (v3 & v1 ^ v3 & v2) - 0x114514)
s.add(v17 == (v2 & v1 ^ v3 & v1))

# s.add(v2 & v1 & (~(v2 | v1) | v3 & v1 | v3 & v2 & ~v18) | (v3 & v2 & v18) == 0x67437616)
s.add(v1 ^ (v20 & ~v18 | v20 & ~v19 | v17 & v19 | v3 & v1 & ~v18) == 0x400010000622000)
s.add(v18 ^ (v19 - v20) == 0x2100A0203EFBB8B)
s.add(v17 ^ v19 ^ v20 == 0x4083102108E)
s.add((v19 ^ v17) - v18 == 0x1551566F3C6485ED)
s.add(v18 ^ v19 ^ v3 & v2 == 0x40836ECAB9A)
s.add((v17 ^ v20) - v18 == 0x3E51566F3C718563)
s.add(v1 - v2 == 0x1AEFF6FDFC121BF1)
s.add((v1 + v2 + v3) % 10 == 8)

part2 = '?' * 11 + 'tyeuaTsm}qjsp'
dummy = '1234567890qwertyuiopasdf'
ret_dummy = 'utyeaqdw63is59o1f2p407r8'
pre_dummy = '1248yu9io50paqsd36wfe7rt'

'''
                      1
            2                    3
      4           5          6       7
  8     9     0     q      w   e   r   t  
y  u  i  o  p  a  s   d  f

                      ?
            ?                    T
      ?           ?          s       j
  ?     ?     ?     e      m   q   r   p  
?  ?  ?  ?  t  y  u   a  }
'''

# const = ''
# for i in range(24):
#     const += part2[pre_dummy.index(dummy[i])]
# print(const)
# ??T??sj???emqrp????tyua}

# ret_const = ''
# for i in range(24):
#     ret_const += const[dummy.index(ret_dummy[i])]
# print(ret_const)
# ?p?qyeam sT?u???? }?t??js?

s.add((v1 >> 56) & 0xff == ord('m'))
s.add((v1 >> 48) & 0xff == ord('a'))
s.add((v1 >> 40) & 0xff == ord('e'))
s.add((v1 >> 32) & 0xff == ord('y'))
s.add((v1 >> 24) & 0xff == ord('q'))
s.add((v1 >> 8) & 0xff == ord('p'))

s.add((v2 >> 24) & 0xff == ord('u'))
s.add((v2 >> 8) & 0xff == ord('T'))
s.add((v2 >> 0) & 0xff == ord('s'))

s.add((v3 >> 0) & 0xff == ord('}'))
s.add((v3 >> 48) & 0xff == ord('s'))
s.add((v3 >> 40) & 0xff == ord('j'))
s.add((v3 >> 16) & 0xff == ord('t'))

while s.check() == sat:
    m = s.model()
    s.add(Or(v1 != m[v1], v2 != m[v2], v3 != m[v3]))

    flag = b''
    flag += long_to_bytes(m[v1].as_long())[::-1]
    flag += long_to_bytes(m[v2].as_long())[::-1]
    flag += long_to_bytes(m[v3].as_long())[::-1]
    if all([c < 128  for c in flag]):
        res = ''
        for i in range(24):
            res += chr(flag[ret_dummy.index(dummy[i])])
        if "RCTF" in res:
            print(res)

# RCTF{sjknwemqspsdaqtyua}

re1#

recover the alg flag hash : c67186f87422544aaac6844eda5c25e8

本题的输出长度与输入长度相同,而且对于同一输入,有不同的输出对应。

可以合理怀疑是 RC4 的算法,不过每次输出不同这事还值得推敲。整个逻辑比较难看,找到 main 之后除了两处明显的数组赋值和一处 ./enc 文件写入之外几乎不能获得任何额外信息,这边选择对输入内容下内存断点,第一次断下:

输入被传入这个函数做处理了,不过看起来没什么计算。

第一个 while 循环,循环次数与输入长度一致:

在循环内探了几个函数,发现 tree node 字样,可能是在建树:

还原一下树的类型: 建树之后用树生成了一个 v102 字符。

接下来到第二个循环:

重点盯着最后的异或,发现异或出了 RCTF_2024_fighting 字样,倒推的话,就是上面两个 18 位数组逐位异或出来的,可能是 key 。

之后直接来到最后:

这里第一个断点的函数把 key 传入,又传入了 v102 ,v102 是什么暂时不得而知,但是也是通过树生成的一个变量。函数内部有混淆,控制流平坦化,但是还是能发现一些 RC4 的特征,比如函数里第一个循环是在把 key 不断重复,第二个循环构造了 RC4 的 box ,第三个循环被控制流平坦化了,直接下断点在几处异或上。

大致是这个意思:

cipher[i] ^= cipher[(i-1)] ^ RC4_xor_value[i]

cipher 还是一个不知来历的串,即 v102 ,回到前面出 v102 的函数去看,是一个递归函数,猜测可能是什么树序遍历,但是还穿插着加密…

同样想办法下内存断点,找到这两个关键点:

马后炮一下,第一个断点是前序异或,第二个断点是对第一个字符特殊处理,应该是随机异或了一个值,毕竟每次都不一样(不过发现下硬件断点之后那个地方的值就不会被更新,不是很理解为什么)。

输入一个无重复字符串,然后在这个地方读置乱后的字符,然后打表,即可解决置乱问题。

最后完整的解题脚本如下:

from hashlib import md5

def RC4_GenBox(box, key):
    for i in range(256):
        box[i] = i
    i = 0
    for j in range(256):
        i = (box[j] + i + key[j % len(key)]) & 0xff
        tmp = box[j]
        box[j] = box[i]
        box[i] = tmp

def RC4_Encrypt(box, data, out):
    k = 0
    j = 0
    for i in range(len(data)):
        k = k + 1
        j = (box[k] + j) & 0xff
        tmp = box[k]
        box[k] = box[j]
        box[j] = tmp
        a = box[(box[k] + box[j]) & 0xff]
        out[i] = a ^ data[i]

key = b'RCTF_2024_fighting'
box = [0] * 256
data = b'\0' * 36
out = [0] * len(data)

RC4_GenBox(box, key)
RC4_Encrypt(box, data, out)

with open('enc.bak', 'rb') as f:
    cip = f.read()

dummy = b'1234567890qwertyuiopasdfghjklzxcvbnm'
ret = b'vtnqhzrc1agwu9mdop53ysbxlk62i7j40ef8'

cip = list(cip)
for i in range(len(cip)-1, -1, -1):
    cip[i] = cip[i] ^ cip[(i-1)%36] ^ out[i]

for i in range(len(cip)-1, 0, -1):
    cip[i] = cip[i] ^ cip[i-1]

for i in range(256):
    tmp = [i] + cip[1:]
    flag = b''
    for j in range(len(tmp)):
        flag += bytes([tmp[ret.index(dummy[j])]])
    if md5(bytes(flag)).hexdigest() == 'c67186f87422544aaac6844eda5c25e8':
        print(flag)
        break

# b'RCTF{obf1nR4st_15_@@@_Hav3@g00dTim3}'

官方 wp 又是纯纯逆天,简单写了两句,生怕别人学会了,提示给的哈希也不说个哈希函数类型。

re2#

flag is wrapped with RCTF{}

进到主函数,有错误处理:

try 块里调用函数抛出错误,所以 catch 这边必然被执行,然而事情没有那么简单,这函数里还有错误处理:

参考这篇博客:https://bbs.kanxue.com/thread-271891-1.htm ,这里应该是藏了 DWARF opcode 。

readelf -wf ./re2 来直接读取,果然发现有问题,code 如下:

Contents of the .eh_frame section:


00000000 0000000000000014 00000000 CIE
  Version:               1
  Augmentation:          "zR"
  Code alignment factor: 1
  Data alignment factor: -8
  Return address column: 16
  Augmentation data:     1b
  DW_CFA_def_cfa: r7 (rsp) ofs 8
  DW_CFA_offset: r16 (rip) at cfa-8
  DW_CFA_nop
  DW_CFA_nop

00000018 0000000000000010 0000001c FDE cie=00000000 pc=00000000004010b0..00000000004010df
  DW_CFA_advance_loc: 4 to 00000000004010b4
  DW_CFA_undefined: r16 (rip)

0000002c 0000000000000010 00000030 FDE cie=00000000 pc=00000000004010e0..00000000004010e5
  DW_CFA_nop
  DW_CFA_nop
  DW_CFA_nop

00000040 0000000000000024 00000044 FDE cie=00000000 pc=0000000000401020..00000000004010b0
  DW_CFA_def_cfa_offset: 16
  DW_CFA_advance_loc: 6 to 0000000000401026
  DW_CFA_def_cfa_offset: 24
  DW_CFA_advance_loc: 10 to 0000000000401030
  DW_CFA_def_cfa_expression (DW_OP_breg7 (rsp): 8; DW_OP_breg16 (rip): 0; DW_OP_lit15; DW_OP_and; DW_OP_lit11; DW_OP_ge; DW_OP_lit3; DW_OP_shl; DW_OP_plus)
  DW_CFA_nop
  DW_CFA_nop
  DW_CFA_nop
  DW_CFA_nop

00000068 000000000000001c 0000006c FDE cie=00000000 pc=0000000000401210..00000000004013f8
  DW_CFA_advance_loc: 1 to 0000000000401211
  DW_CFA_def_cfa_offset: 16
  DW_CFA_offset: r6 (rbp) at cfa-16
  DW_CFA_advance_loc: 3 to 0000000000401214
  DW_CFA_def_cfa_register: r6 (rbp)
  DW_CFA_advance_loc2: 483 to 00000000004013f7
  DW_CFA_def_cfa: r7 (rsp) ofs 8
  DW_CFA_nop

00000088 000000000000001c 00000000 CIE
  Version:               1
  Augmentation:          "zPLR"
  Code alignment factor: 1
  Data alignment factor: -8
  Return address column: 16
  Augmentation data:     03 80 10 40 00 03 1b
  DW_CFA_def_cfa: r7 (rsp) ofs 8
  DW_CFA_offset: r16 (rip) at cfa-8
  DW_CFA_nop
  DW_CFA_nop

000000a8 00000000000a0080 00000024 FDE cie=00000088 pc=00000000004011a0..000000000040120b
  Augmentation data:     48 23 4a 00
  DW_CFA_advance_loc: 1 to 00000000004011a1
  DW_CFA_def_cfa_offset: 16
  DW_CFA_offset: r6 (rbp) at cfa-16
  DW_CFA_advance_loc: 3 to 00000000004011a4
  DW_CFA_def_cfa_register: r6 (rbp)
  DW_CFA_advance_loc: 4 to 00000000004011a8
  DW_CFA_val_expression: r13 (r13) (DW_OP_lit11; DW_OP_lit22; DW_OP_constu: 33; DW_OP_constu: 44; DW_OP_constu: 2654435769; DW_OP_reg15 (r15); DW_OP_reg14 (r14); DW_OP_lit0; DW_OP_pick: 3; DW_OP_skip: 8; DW_OP_le; (Unknown location op 0xae))
  DW_CFA_advance_loc1: 89 to 0000000000401201
  DW_CFA_def_cfa: r7 (rsp) ofs 8
  DW_CFA_advance_loc: 1 to 0000000000401202
  DW_CFA_def_cfa: r6 (rbp) ofs 16
  DW_CFA_nop

000a012c 0000000000000030 000a00a8 FDE cie=00000088 pc=0000000000401400..0000000000401504
  Augmentation data:     60 23 4a 00
  DW_CFA_advance_loc: 1 to 0000000000401401
  DW_CFA_def_cfa_offset: 16
  DW_CFA_offset: r6 (rbp) at cfa-16
  DW_CFA_advance_loc: 3 to 0000000000401404
  DW_CFA_def_cfa_register: r6 (rbp)
  DW_CFA_advance_loc: 10 to 000000000040140e
  DW_CFA_offset: r13 (r13) at cfa-40
  DW_CFA_offset: r14 (r14) at cfa-32
  DW_CFA_offset: r15 (r15) at cfa-24
  DW_CFA_advance_loc1: 236 to 00000000004014fa
  DW_CFA_def_cfa: r7 (rsp) ofs 8
  DW_CFA_advance_loc: 1 to 00000000004014fb
  DW_CFA_def_cfa: r6 (rbp) ofs 16
  DW_CFA_nop
  DW_CFA_nop
  DW_CFA_nop
  DW_CFA_nop
  DW_CFA_nop
  DW_CFA_nop
  DW_CFA_nop

000a0160 0000000000000044 000a0164 FDE cie=00000000 pc=0000000000401510..0000000000401575
  DW_CFA_advance_loc: 6 to 0000000000401516
  DW_CFA_def_cfa_offset: 16
  DW_CFA_offset: r15 (r15) at cfa-16
  DW_CFA_advance_loc: 9 to 000000000040151f
  DW_CFA_def_cfa_offset: 24
  DW_CFA_offset: r14 (r14) at cfa-24
  DW_CFA_advance_loc: 5 to 0000000000401524
  DW_CFA_def_cfa_offset: 32
  DW_CFA_offset: r13 (r13) at cfa-32
  DW_CFA_advance_loc: 5 to 0000000000401529
  DW_CFA_def_cfa_offset: 40
  DW_CFA_offset: r12 (r12) at cfa-40
  DW_CFA_advance_loc: 4 to 000000000040152d
  DW_CFA_def_cfa_offset: 48
  DW_CFA_offset: r6 (rbp) at cfa-48
  DW_CFA_advance_loc: 8 to 0000000000401535
  DW_CFA_def_cfa_offset: 56
  DW_CFA_offset: r3 (rbx) at cfa-56
  DW_CFA_advance_loc: 7 to 000000000040153c
  DW_CFA_def_cfa_offset: 64
  DW_CFA_advance_loc: 46 to 000000000040156a
  DW_CFA_def_cfa_offset: 56
  DW_CFA_advance_loc: 1 to 000000000040156b
  DW_CFA_def_cfa_offset: 48
  DW_CFA_advance_loc: 1 to 000000000040156c
  DW_CFA_def_cfa_offset: 40
  DW_CFA_advance_loc: 2 to 000000000040156e
  DW_CFA_def_cfa_offset: 32
  DW_CFA_advance_loc: 2 to 0000000000401570
  DW_CFA_def_cfa_offset: 24
  DW_CFA_advance_loc: 2 to 0000000000401572
  DW_CFA_def_cfa_offset: 16
  DW_CFA_advance_loc: 2 to 0000000000401574
  DW_CFA_def_cfa_offset: 8
  DW_CFA_nop

000a01a8 0000000000000010 000a01ac FDE cie=00000000 pc=0000000000401580..0000000000401585
  DW_CFA_nop
  DW_CFA_nop
  DW_CFA_nop

000a01bc ZERO terminator

可以在 expression 那一行找到了 tea 的常数,但是后面会分析错误,明显是注意到前面的 skip 指令,这里可能是花指令,所以我们查表:https://bbs.kanxue.com/thread-271891-1.htm 来验证:

接下来 nop 掉 8 个字节:

然后又有一个 skip 8,再 nop 8 字节,得到:

DW_CFA_val_expression: r13 (r13) (DW_OP_lit11; DW_OP_lit22; DW_OP_constu: 33; DW_OP_constu: 44; DW_OP_constu: 2654435769; DW_OP_reg15 (r15); DW_OP_reg14 (r14); DW_OP_lit0; DW_OP_pick: 3; DW_OP_skip: 8; DW_OP_nop; DW_OP_nop; DW_OP_nop; DW_OP_nop; DW_OP_nop; DW_OP_nop; DW_OP_nop; DW_OP_nop; DW_OP_plus; DW_OP_skip: 8; DW_OP_nop; DW_OP_nop; DW_OP_nop; DW_OP_nop; DW_OP_nop; DW_OP_nop; DW_OP_nop; DW_OP_nop; DW_OP_dup; DW_OP_pick: 3; DW_OP_dup; DW_OP_constu: 9246453814144344100; DW_OP_constu: 3482419137767051305; DW_OP_or; DW_OP_swap; DW_OP_drop; DW_OP_constu: 3355170828548290441; DW_OP_constu: 12456870883039105005; DW_OP_xor; DW_OP_constu: 4477389553097641651; DW_OP_constu: 9968540155626566145; DW_OP_plus; DW_OP_or; DW_OP_or; DW_OP_constu: 6566728863938945187; DW_OP_constu: 7069261731658804302; DW_OP_constu: 36037647752298496; DW_OP_rot; DW_OP_drop; DW_OP_drop; DW_OP_not; DW_OP_dup; DW_OP_constu: 8065301406029491942; DW_OP_constu: 7444708234667757800; DW_OP_plus; DW_OP_swap; DW_OP_drop; DW_OP_and; DW_OP_and; DW_OP_constu: 2307581073500952624; DW_OP_constu: 1337886306024301600; DW_OP_or; DW_OP_constu: 2907440737931433652; DW_OP_constu: 7750317548280162958; DW_OP_swap; DW_OP_drop; DW_OP_constu: 576777446557518912; DW_OP_constu: 5044381261713178656; DW_OP_or; DW_OP_rot; DW_OP_drop; DW_OP_drop; DW_OP_constu: 834623556763612763; DW_OP_constu: 9376331576319671347; DW_OP_xor; DW_OP_constu: 5143454248041115628; DW_OP_constu: 311295192153538522; DW_OP_plus; DW_OP_constu: 17293522833515708330; DW_OP_constu: 9187331307879709880; DW_OP_and; DW_OP_rot; DW_OP_drop; DW_OP_drop; DW_OP_dup; DW_OP_constu: 8561182633499816978; DW_OP_swap; DW_OP_drop; DW_OP_constu: 12647788648620021111; DW_OP_not; DW_OP_and; DW_OP_rot; DW_OP_drop; DW_OP_drop; DW_OP_constu: 11854054328811413493; DW_OP_constu: 17208493391257034461; DW_OP_swap; DW_OP_drop; DW_OP_constu: 5207518994298876016; DW_OP_constu: 17164217795910464951; DW_OP_swap; DW_OP_drop; DW_OP_minus; DW_OP_constu: 15490668501480074512; DW_OP_constu: 1096067580601619248; DW_OP_minus; DW_OP_constu: 11674528431521164290; DW_OP_constu: 47765866140870983; DW_OP_or; DW_OP_constu: 6196953164671942660; DW_OP_constu: 1406275679548699910; DW_OP_or; DW_OP_rot; DW_OP_drop; DW_OP_drop; DW_OP_constu: 10376302337624519184; DW_OP_constu: 1170971104670585408; DW_OP_or; DW_OP_constu: 8088474070986851121; DW_OP_constu: 5765411268721119792; DW_OP_or; DW_OP_or; DW_OP_rot; DW_OP_drop; DW_OP_drop; DW_OP_or; DW_OP_minus; DW_OP_constu: 612489970497620240; DW_OP_constu: 9835866276549890833; DW_OP_or; DW_OP_constu: 10762869371487497996; DW_OP_constu: 5270159741086233040; DW_OP_plus; DW_OP_or; DW_OP_not; DW_OP_not; DW_OP_dup; DW_OP_constu: 4818355031839368916; DW_OP_constu: 251112809558497648; DW_OP_constu: 15140812885716250335; DW_OP_rot; DW_OP_drop; DW_OP_drop; DW_OP_constu: 15793633358447679032; DW_OP_constu: 5199648258385913403; DW_OP_swap; DW_OP_drop; DW_OP_constu: 13980299163331532100; DW_OP_constu: 15170672274881253744; DW_OP_or; DW_OP_rot; DW_OP_drop; DW_OP_drop; DW_OP_swap; DW_OP_drop; DW_OP_constu: 3679316165496325069; DW_OP_constu: 14387433162335890031; DW_OP_plus; DW_OP_constu: 291639868642560039; DW_OP_constu: 985336657705773426; DW_OP_or; DW_OP_xor; DW_OP_not; DW_OP_plus; DW_OP_dup; DW_OP_constu: 13275565177638082811; DW_OP_constu: 14915179630389741107; DW_OP_constu: 16554744048929225322; DW_OP_rot; DW_OP_drop; DW_OP_drop; DW_OP_constu: 8407587180091755195; DW_OP_constu: 8024346620616453741; DW_OP_and; DW_OP_dup; DW_OP_constu: 16867896941848469861; DW_OP_swap; DW_OP_drop; DW_OP_rot; DW_OP_drop; DW_OP_drop; DW_OP_swap; DW_OP_drop; DW_OP_constu: 9337830232363609437; DW_OP_constu: 3456144407888382565; DW_OP_xor; DW_OP_constu: 6814966833910456739; DW_OP_constu: 10776151854821374637; DW_OP_minus; DW_OP_swap; DW_OP_drop; DW_OP_constu: 16591522517313354392; DW_OP_not; DW_OP_constu: 207906381668224774; DW_OP_constu: 12739491465602272587; DW_OP_swap; DW_OP_drop; DW_OP_swap; DW_OP_drop; DW_OP_constu: 12738463890597737111; DW_OP_not; DW_OP_constu: 4548630614695693957; DW_OP_constu: 3523040882251724690; DW_OP_swap; DW_OP_drop; DW_OP_plus; DW_OP_rot; DW_OP_drop; DW_OP_drop; DW_OP_plus; DW_OP_rot; DW_OP_drop; DW_OP_drop; DW_OP_minus; DW_OP_constu: 5145313397659684528; DW_OP_constu: 12647911838428931100; DW_OP_plus; DW_OP_not; DW_OP_constu: 5350277731764535297; DW_OP_constu: 16204533255852593408; DW_OP_or; DW_OP_not; DW_OP_swap; DW_OP_drop; DW_OP_not; DW_OP_dup; DW_OP_constu: 9478274390389657227; DW_OP_swap; DW_OP_drop; DW_OP_constu: 10628314040719041556; DW_OP_constu: 1397651140586458754; DW_OP_swap; DW_OP_drop; DW_OP_minus; DW_OP_constu: 7325947719534443917; DW_OP_constu: 12756610081009003334; DW_OP_constu: 2959164027579666752; DW_OP_rot; DW_OP_drop; DW_OP_drop; DW_OP_constu: 13370896036671900368; DW_OP_constu: 9227229786454116816; DW_OP_minus; DW_OP_or; DW_OP_or; DW_OP_constu: 8138421546826592496; DW_OP_constu: 7449203773552589229; DW_OP_swap; DW_OP_drop; DW_OP_constu: 9325284844740759573; DW_OP_constu: 9389632835213575388; DW_OP_swap; DW_OP_drop; DW_OP_xor; DW_OP_constu: 18134162023263502205; DW_OP_constu: 16765775020962940409; DW_OP_and; DW_OP_constu: 17994732817211405176; DW_OP_constu: 4056731758822652564; DW_OP_minus; DW_OP_xor; DW_OP_xor; DW_OP_xor; DW_OP_plus; DW_OP_not; DW_OP_and; DW_OP_dup; DW_OP_dup; DW_OP_constu: 8919742661078911302; DW_OP_constu: 9893671013996955128; DW_OP_constu: 6092805988491668690; DW_OP_rot; DW_OP_drop; DW_OP_drop; DW_OP_swap; DW_OP_drop; DW_OP_constu: 13167088660230700797; DW_OP_constu: 16410175668783674811; DW_OP_and; DW_OP_constu: 8748829291807508723; DW_OP_constu: 9170237588609828506; DW_OP_constu: 5406453892900421230; DW_OP_rot; DW_OP_drop; DW_OP_drop; DW_OP_xor; DW_OP_minus; DW_OP_constu: 9103550073850754537; DW_OP_constu: 6051786455950369300; DW_OP_and; DW_OP_constu: 12683843361760159573; DW_OP_constu: 12371885691865990417; DW_OP_minus; DW_OP_or; DW_OP_constu: 9223368976946127571; DW_OP_constu: 13237734968453734775; DW_OP_and; DW_OP_constu: 16623851704195380919; DW_OP_constu: 7171751303043348948; DW_OP_swap; DW_OP_drop; DW_OP_plus; DW_OP_constu: 918989879468278212; DW_OP_constu: 13625728335638972778; DW_OP_minus; DW_OP_constu: 17648845772178624309; DW_OP_constu: 2611288732337654524; DW_OP_minus; DW_OP_constu: 8109188663392815396; DW_OP_constu: 432778594301775393; DW_OP_or; DW_OP_rot; DW_OP_drop; DW_OP_drop; DW_OP_rot; DW_OP_drop; DW_OP_drop; DW_OP_swap; DW_OP_drop; DW_OP_swap; DW_OP_drop; DW_OP_constu: 1396050308861093359; DW_OP_constu: 297768883488600332; DW_OP_swap; DW_OP_drop; DW_OP_constu: 14703720468417790009; DW_OP_constu: 18022590731466461556; DW_OP_xor; DW_OP_or; DW_OP_not; DW_OP_dup; DW_OP_constu: 2157507164472362668; DW_OP_swap; DW_OP_drop; DW_OP_constu: 4190558415241252293; DW_OP_constu: 8296329441025534468; DW_OP_xor; DW_OP_swap; DW_OP_drop; DW_OP_dup; DW_OP_constu: 11069801948728006343; DW_OP_swap; DW_OP_drop; DW_OP_constu: 16059932642876795174; DW_OP_constu: 2442181783212738058; DW_OP_constu: 16880804627168157827; DW_OP_rot; DW_OP_drop; DW_OP_drop; DW_OP_plus; DW_OP_constu: 12774909125348980341; DW_OP_not; DW_OP_not; DW_OP_rot; DW_OP_drop; DW_OP_drop; DW_OP_minus; DW_OP_dup; DW_OP_constu: 13532171086042492748; DW_OP_constu: 5316732948882325373; DW_OP_and; DW_OP_swap; DW_OP_drop; DW_OP_constu: 10739811699505903851; DW_OP_not; DW_OP_constu: 13912457963645954629; DW_OP_constu: 16939863945808272318; DW_OP_constu: 17905857878912659942; DW_OP_rot; DW_OP_drop; DW_OP_drop; DW_OP_plus; DW_OP_constu: 9322149875253172733; DW_OP_not; DW_OP_not; DW_OP_rot; DW_OP_drop; DW_OP_drop; DW_OP_dup; DW_OP_constu: 4702634614293841069; DW_OP_swap; DW_OP_drop; DW_OP_constu: 15203266091741727357; DW_OP_constu: 3596826945239439546; DW_OP_minus; DW_OP_plus; DW_OP_dup; DW_OP_constu: 14873448173346004895; DW_OP_swap; DW_OP_drop; DW_OP_constu: 16704134310482830579; DW_OP_constu: 4440131263892908886; DW_OP_xor; DW_OP_plus; DW_OP_constu: 2817034960377362; DW_OP_constu: 2324988206006792; DW_OP_or; DW_OP_constu: 16657011814755729259; DW_OP_constu: 14796604882503743490; DW_OP_and; DW_OP_or; DW_OP_rot; DW_OP_drop; DW_OP_drop; DW_OP_swap; DW_OP_drop; DW_OP_xor; DW_OP_plus; DW_OP_constu: 53979802746970789; DW_OP_constu: 15570312165650957895; DW_OP_constu: 597149176513962082; DW_OP_rot; DW_OP_drop; DW_OP_drop; DW_OP_constu: 2023303807973566590; DW_OP_constu: 6635618871486812020; DW_OP_xor; DW_OP_or; DW_OP_constu: 1517900520905080280; DW_OP_constu: 12388546135782790442; DW_OP_constu: 1585373731209873806; DW_OP_rot; DW_OP_drop; DW_OP_drop; DW_OP_dup; DW_OP_constu: 3756922518058850691; DW_OP_swap; DW_OP_drop; DW_OP_or; DW_OP_constu: 7077526760041775408; DW_OP_constu: 2541364082271093426; DW_OP_minus; DW_OP_constu: 4397516808434294558; DW_OP_constu: 7277439334959213389; DW_OP_xor; DW_OP_and; DW_OP_rot; DW_OP_drop; DW_OP_drop; DW_OP_constu: 18372625423469384332; DW_OP_constu: 2394768107539208995; DW_OP_plus; DW_OP_constu: 18301367143230351292; DW_OP_constu: 9828321967323362288; DW_OP_constu: 6178618706477491838; DW_OP_rot; DW_OP_drop; DW_OP_drop; DW_OP_minus; DW_OP_dup; DW_OP_constu: 15989718217962125858; DW_OP_not; DW_OP_swap; DW_OP_drop; DW_OP_plus; DW_OP_plus; DW_OP_not; DW_OP_dup; DW_OP_constu: 1171846700680671729; DW_OP_constu: 5522305039071955043; DW_OP_plus; DW_OP_not; DW_OP_not; DW_OP_dup; DW_OP_constu: 16131887268078763466; DW_OP_constu: 16384016209128889689; DW_OP_and; DW_OP_constu: 11566718676472764947; DW_OP_not; DW_OP_constu: 17162792621353323984; DW_OP_constu: 14152529327814332278; DW_OP_plus; DW_OP_rot; DW_OP_drop; DW_OP_drop; DW_OP_swap; DW_OP_drop; DW_OP_plus; DW_OP_swap; DW_OP_drop; DW_OP_and; DW_OP_xor; DW_OP_constu: 12268344557851134264; DW_OP_not; DW_OP_constu: 17884668708305198748; DW_OP_constu: 6671072876979404297; DW_OP_plus; DW_OP_xor; DW_OP_dup; DW_OP_constu: 1167285890662884919; DW_OP_swap; DW_OP_drop; DW_OP_constu: 8410188484364576830; DW_OP_constu: 12120638754722834549; DW_OP_plus; DW_OP_dup; DW_OP_constu: 13638024478139881085; DW_OP_swap; DW_OP_drop; DW_OP_rot; DW_OP_drop; DW_OP_drop; DW_OP_plus; DW_OP_dup; DW_OP_dup; DW_OP_constu: 9392838735902082224; DW_OP_constu: 9497081495274802077; DW_OP_xor; DW_OP_swap; DW_OP_drop; DW_OP_swap; DW_OP_drop; DW_OP_minus; DW_OP_constu: 12186572480519207065; DW_OP_constu: 10932841397634794849; DW_OP_swap; DW_OP_drop; DW_OP_constu: 6197074045647089651; DW_OP_constu: 10939377665665577209; DW_OP_minus; DW_OP_swap; DW_OP_drop; DW_OP_dup; DW_OP_constu: 5506140233666181230; DW_OP_swap; DW_OP_drop; DW_OP_constu: 12646751697396730368; DW_OP_constu: 8884856673116173423; DW_OP_xor; DW_OP_swap; DW_OP_drop; DW_OP_and; DW_OP_dup; DW_OP_constu: 2713633632996689478; DW_OP_swap; DW_OP_drop; DW_OP_constu: 757204635076264448; DW_OP_constu: 5163947267633711144; DW_OP_or; DW_OP_constu: 4612679427188508800; DW_OP_not; DW_OP_rot; DW_OP_drop; DW_OP_drop; DW_OP_constu: 8070447215190703260; DW_OP_constu: 15343691086700432542; DW_OP_and; DW_OP_constu: 4000630648099348534; DW_OP_constu: 4978689864376562614; DW_OP_xor; DW_OP_xor; DW_OP_and; DW_OP_xor; DW_OP_xor; DW_OP_not; DW_OP_constu: 2533904197481511799; DW_OP_constu: 1946287827275815167; DW_OP_constu: 575760215792541830; DW_OP_rot; DW_OP_drop; DW_OP_drop; DW_OP_constu: 5260134759761854358; DW_OP_not; DW_OP_constu: 3516184542641942320; DW_OP_constu: 16120202155126675423; DW_OP_swap; DW_OP_drop; DW_OP_rot; DW_OP_drop; DW_OP_drop; DW_OP_dup; DW_OP_constu: 4902699016174964414; DW_OP_swap; DW_OP_drop; DW_OP_constu: 11294205910547495810; DW_OP_constu: 4302194200344111223; DW_OP_minus; DW_OP_xor; DW_OP_and; DW_OP_dup; DW_OP_constu: 2319811639987894990; DW_OP_constu: 10300189288263269088; DW_OP_minus; DW_OP_swap; DW_OP_drop; DW_OP_constu: 191226629326314382; DW_OP_constu: 16773800991079921626; DW_OP_xor; DW_OP_constu: 5645303198672800848; DW_OP_constu: 5116473026635599372; DW_OP_swap; DW_OP_drop; DW_OP_swap; DW_OP_drop; DW_OP_plus; DW_OP_swap; DW_OP_drop; DW_OP_dup; DW_OP_dup; DW_OP_constu: 10389240456235939256; DW_OP_swap; DW_OP_drop; DW_OP_constu: 1236878166197613653; DW_OP_constu: 11348221471697696282; DW_OP_xor; DW_OP_plus; DW_OP_swap; DW_OP_drop; DW_OP_constu: 14780127890240057715; DW_OP_constu: 2335305486635868435; DW_OP_plus; DW_OP_constu: 7491304052337358403; DW_OP_constu: 8242604637416786397; DW_OP_constu: 18048637315251841891; DW_OP_rot; DW_OP_drop; DW_OP_drop; DW_OP_plus; DW_OP_constu: 14503681412420506767; DW_OP_constu: 10449340247926752243; DW_OP_xor; DW_OP_constu: 18077127131107644902; DW_OP_constu: 4010523246600862; DW_OP_plus; DW_OP_constu: 49319699644481564; DW_OP_constu: 16364606251106104167; DW_OP_xor; DW_OP_rot; DW_OP_drop; DW_OP_drop; DW_OP_and; DW_OP_swap; DW_OP_drop; DW_OP_swap; DW_OP_drop; DW_OP_dup; DW_OP_dup; DW_OP_constu: 15561756403168178175; DW_OP_swap; DW_OP_drop; DW_OP_constu: 5707315299993809845; DW_OP_constu: 11135717403856178634; DW_OP_xor; DW_OP_and; DW_OP_constu: 11895373583975767100; DW_OP_constu: 15598136490944073747; DW_OP_constu: 8986639126440100094; DW_OP_rot; DW_OP_drop; DW_OP_drop; DW_OP_not; DW_OP_and; DW_OP_constu: 15460536247262581615; DW_OP_not; DW_OP_not; DW_OP_constu: 6800014348965755609; DW_OP_constu: 4005384508924753458; DW_OP_swap; DW_OP_drop; DW_OP_constu: 169444985846641449; DW_OP_not; DW_OP_plus; DW_OP_constu: 10982025100208603434; DW_OP_constu: 18417605090935581358; DW_OP_plus; DW_OP_constu: 18049930453345124574; DW_OP_constu: 15162333281378012559; DW_OP_xor; DW_OP_xor; DW_OP_rot; DW_OP_drop; DW_OP_drop; DW_OP_or; DW_OP_swap; DW_OP_drop; DW_OP_swap; DW_OP_drop; DW_OP_constu: 3326134158970580896; DW_OP_constu: 8370177562483109809; DW_OP_minus; DW_OP_dup; DW_OP_constu: 17112262193788468191; DW_OP_swap; DW_OP_drop; DW_OP_and; DW_OP_constu: 1555027848348720; DW_OP_not; DW_OP_constu: 1046358727755934736; DW_OP_not; DW_OP_and; DW_OP_xor; DW_OP_dup; DW_OP_dup; DW_OP_constu: 9060380398247604159; DW_OP_swap; DW_OP_drop; DW_OP_dup; DW_OP_constu: 15260974739873773933; DW_OP_swap; DW_OP_drop; DW_OP_and; DW_OP_swap; DW_OP_drop; DW_OP_or; DW_OP_constu: 15713234901815691645; DW_OP_not; DW_OP_constu: 14130123517051801625; DW_OP_constu: 14236363126501281938; DW_OP_or; DW_OP_or; DW_OP_dup; DW_OP_constu: 2784869846744336156; DW_OP_swap; DW_OP_drop; DW_OP_constu: 3390092092484082191; DW_OP_constu: 8808493508132722388; DW_OP_plus; DW_OP_plus; DW_OP_and; DW_OP_dup; DW_OP_constu: 17085728165571031500; DW_OP_constu: 6216681842869496386; DW_OP_xor; DW_OP_swap; DW_OP_drop; DW_OP_not; DW_OP_minus; DW_OP_xor; DW_OP_dup; DW_OP_constu: 2138429953341508361; DW_OP_constu: 9917648750106618459; DW_OP_constu: 975164001913095318; DW_OP_rot; DW_OP_drop; DW_OP_drop; DW_OP_not; DW_OP_constu: 1028259923349273708; DW_OP_constu: 4351112771774120294; DW_OP_xor; DW_OP_not; DW_OP_plus; DW_OP_swap; DW_OP_drop; DW_OP_dup; DW_OP_constu: 16513207128006295859; DW_OP_constu: 4640148151211203868; DW_OP_minus; DW_OP_not; DW_OP_constu: 16967157524761406299; DW_OP_constu: 15131869794203489118; DW_OP_and; DW_OP_constu: 3136720902279215258; DW_OP_constu: 5304982965181059094; DW_OP_minus; DW_OP_xor; DW_OP_constu: 17152515690392753874; DW_OP_constu: 18393616877360793224; DW_OP_constu: 2086151513937411567; DW_OP_rot; DW_OP_drop; DW_OP_drop; DW_OP_dup; DW_OP_constu: 15812768855500078761; DW_OP_swap; DW_OP_drop; DW_OP_and; DW_OP_rot; DW_OP_drop; DW_OP_drop; DW_OP_swap; DW_OP_drop; DW_OP_plus; DW_OP_minus; DW_OP_rot; DW_OP_drop; DW_OP_drop; DW_OP_rot; DW_OP_drop; DW_OP_drop; DW_OP_bra: -3242; DW_OP_skip: 1; DW_OP_drop; DW_OP_plus; DW_OP_pick: 3; DW_OP_lit4; DW_OP_skip: 6; DW_OP_convert <0x68>; DW_OP_ge; (Unknown location op 0xcd))

未免太长了。。。 后面还有花指令,先到这里吧,剩下部分和另外几题都放下篇写了,不过可能要🕊一段时间。

RCTF2024赛后复现(上)
https://0xd009.github.io/posts/rctf2024赛后复现上/
作者
0xD009
发布于
2024-10-03
许可协议
CC BY-NC-SA 4.0