D^3CTF2022 Re复现

经提醒想起有这么个东西,当时在忙着别的事。。。复现真是大开眼界,最大的收获就是知道了好多新名词

Re

d3w0w

int __cdecl main(int argc, const char **argv, const char **envp)
{
  _DWORD v4[11]; // [esp+0h] [ebp-30h] BYREF
  BOOL v5; // [esp+2Ch] [ebp-4h]

  dword_4262F0 = (int)NtCurrentTeb()->WOW32Reserved;
  memset(v4, 0, 0x27u);
  sub_402100("%39s", (const char *)v4);
  v5 = sub_401000(v4, &unk_4262F8) || sub_401220(&unk_4262F8, v4[0]);
  v4[10] = v5;
  if ( v5 )
    sub_402090("you lose\n", v4[0]);
  else
    sub_402090("you win\n", v4[0]);
  return 0;
}

经观察只需逆向sub_401000(v4, &unk_4262F8)sub_401220(&unk_4262F8, v4[0])即可,然后

int __cdecl sub_401000(_BYTE *a1, _DWORD *a2)
{
  int v3; // [esp+0h] [ebp-10h]
  int v4; // [esp+8h] [ebp-8h]
  int v5; // [esp+Ch] [ebp-4h]

  v5 = 0;
  v4 = 0;
  v3 = 6;
  if ( *(_DWORD *)a1 != 'tc3d' )
    return 1;
  if ( *((_WORD *)a1 + 2) != '{f' )
    return 1;
  if ( a1[6] != '2' )
    return 1;
  while ( a1[v3] != '}' )
  {
    switch ( a1[v3] )
    {
      case '1': // 上移
        a2[6 * v5 + v4] |= 8u;
        a2[6 * --v5 + v4] |= 2u;
        goto LABEL_14;
      case '2': // 下移
        a2[6 * v5 + v4] |= 2u;
        a2[6 * ++v5 + v4] |= 8u;
        goto LABEL_14;
      case '3': // 左移
        a2[6 * v5 + v4] |= 4u;
        a2[6 * v5 - 1 + v4--] |= 1u;
        goto LABEL_14;
      case '4': // 右移
        a2[6 * v5 + v4] |= 1u;
        a2[6 * v5 + 1 + v4++] |= 4u;
LABEL_14:
        if ( v5 < 0 || v4 < 0 || v5 > 5 || v4 > 5 )
          return 1;
        ++v3;
        break;
      default:
        return 1;
    }
  }
  return 0;
}

flag的形式应该为d3ctf{[1-4]*},推测又是走迷宫,1-4对应四个方向,flag的长度为39

sub_401220

是WOW64混淆,天堂之门。动调。
动调出了然后卡死了,看emtanling大佬写的wp,当时也想到用64位执行,但pe结构是32位应该改pe结构的。。。
修改128h的magic,这个无符号整数指出了镜像文件的状态。
0x10B表明这是一个32位镜像文件。0x107表明这是一个ROM镜像。0x20B表明这是一个64位镜像文件。所以修改为0x20B
在这里插入图片描述

然后就能看到主要逻辑了

// positive sp value has been detected, the output may be wrong!
__int64 __fastcall ________u_3___V_F__102(__int64 a1, __int64 a2)
{
  _DWORD *v2; // rcx
  __int64 v3; // rcx
  int v5; // [rsp-10h] [rbp-B0h]
  int v6; // [rsp-10h] [rbp-B0h]
  int v7; // [rsp-10h] [rbp-B0h]
  int v8; // [rsp-Ch] [rbp-ACh]
  int v9; // [rsp-Ch] [rbp-ACh]
  int v10; // [rsp-Ch] [rbp-ACh]
  int i; // [rsp-8h] [rbp-A8h]
  int j; // [rsp-4h] [rbp-A4h]
  int v13; // [rsp+0h] [rbp-A0h]
  int v14; // [rsp+4h] [rbp-9Ch]
  int k; // [rsp+8h] [rbp-98h]
  int m; // [rsp+Ch] [rbp-94h]
  unsigned int v17; // [rsp+10h] [rbp-90h]
  unsigned int v18; // [rsp+14h] [rbp-8Ch]
  unsigned int v19; // [rsp+18h] [rbp-88h]
  unsigned int v20; // [rsp+1Ch] [rbp-84h]
  unsigned int v21; // [rsp+20h] [rbp-80h]
  unsigned int v22; // [rsp+24h] [rbp-7Ch]
  int v23[3]; // [rsp+28h] [rbp-78h]
  int v24[10]; // [rsp+38h] [rbp-68h]
  __int64 v25; // [rsp+60h] [rbp-40h]
  __int64 v26; // [rsp+68h] [rbp-38h]
  __int64 v27; // [rsp+70h] [rbp-30h]
  __int64 v28; // [rsp+78h] [rbp-28h]
  __int64 v29; // [rsp+80h] [rbp-20h]
  __int64 v30; // [rsp+88h] [rbp-18h]
  __int64 v31; // [rsp+98h] [rbp-8h]
  _DWORD *savedregs; // [rsp+A0h] [rbp+0h]

  ((void (__fastcall *)(_QWORD, __int64))sub_34000000020510)((unsigned int)v31, a2);
  savedregs = v2;
  v23[0] = 0;
  v23[1] = 14;
  v23[2] = 20;
  v24[0] = 4;
  v24[1] = 13;
  v24[2] = 15;
  v24[3] = 21;
  v24[4] = 24;
  v24[5] = 31;
  v24[6] = 32;
  v24[7] = 41;
  v24[8] = 45;
  v24[9] = 53;
  for ( i = 0; i < 6; ++i )
  {
    for ( j = 0; j < 6; ++j )                   // 6*6方阵
    {
      v3 = j;
      if ( savedregs[6 * i + j] > 15u )         // 不能大于15
        return sub_34000000020521(v3);
      v17 = savedregs[6 * i + j] % 0x10u / 8;
      v25 = j;
      v18 = savedregs[6 * i + j] % 8u / 4 + v17;
      v26 = j;
      v19 = savedregs[6 * i + j] % 4u / 2 + v18;
      v27 = j;
      v3 = savedregs[6 * i + j] % 2u + v19;
      if ( savedregs[6 * i + j] % 2u + v19 > 2 )
        return sub_34000000020521(v3);
      if ( !j )
      {
        v3 = 4i64;
        if ( savedregs[6 * i] % 8u / 4 )        // 不能为4的倍数
          return sub_34000000020521(v3);
      }
      if ( j == 5 )
      {
        v3 = 2i64;
        if ( savedregs[6 * i + 5] % 2u )        // 第6列值为2的倍数
          return sub_34000000020521(v3);
      }
      if ( !i )
      {
        v3 = 8i64;
        if ( savedregs[j] % 0x10u / 8 )         // 第1行数不能为8
          return sub_34000000020521(v3);
      }
      if ( i == 5 )
      {
        v3 = 2i64;
        if ( savedregs[j + 30] % 4u / 2 )       // 第6行的数不能为2
          return sub_34000000020521(v3);
      }
    }
  }
  for ( k = 0; (unsigned __int64)k < 3; ++k )
  {                                             // 黑子坐标
    v5 = v23[k] / 10;                           // 0,1,2
    v8 = v23[k] % 10;                           // 0,4,0
    if ( savedregs[6 * v5 + v8] % 0x10u / 8 )   // 不能为8,2
    {
      v3 = 2i64;
      if ( savedregs[6 * v5 + v8] % 4u / 2 )
        return sub_34000000020521(v3);
    }
    if ( savedregs[6 * v5 + v8] % 8u / 4 )      // 不能为4,1
    {
      v3 = 2i64;
      if ( savedregs[6 * v5 + v8] % 2u )
        return sub_34000000020521(v3);
    }
    v20 = savedregs[6 * v5 + v8] % 0x10u / 8;
    v28 = v8;
    v21 = savedregs[6 * v5 + v8] % 4u / 2 + v20;
    v29 = v8;
    v22 = savedregs[6 * v5 + v8] % 2u + v21;
    v30 = v8;
    v3 = savedregs[6 * v5 + v8] % 8u / 4 + v22;
    if ( savedregs[6 * v5 + v8] % 8u / 4 + v22 != 2 )
      return sub_34000000020521(v3);
    if ( savedregs[6 * v5 + v8] % 0x10u / 8 )   // 不为8, 猜测上一行不为8
      return sub_3400000001F7F0(16i64, 0i64);
    if ( savedregs[6 * v5 + v8] % 4u / 2 )      // 这个位置是2的话,下一行不是2
    {
      v3 = 2i64;
      if ( !(savedregs[6 * v5 + 6 + v8] % 4u / 2) )
        return sub_34000000020521(v3);
    }
    else if ( savedregs[6 * v5 + v8] % 8u / 4 ) // 这个位置为4上一个不为4
    {
      v3 = 4i64;
      if ( !(savedregs[6 * v5 - 1 + v8] % 8u / 4) )
        return sub_34000000020521(v3);
    }
    else if ( savedregs[6 * v5 + v8] % 2u )     // 当前为4下一个不为4
    {
      v3 = 2i64;
      if ( !(savedregs[6 * v5 + 1 + v8] % 2u) )
        return sub_34000000020521(v3);
    }
  }
  for ( m = 0; (unsigned __int64)m < 0xA; ++m )
  {                                             // 白字坐标
    v6 = v24[m] / 10;                           // [0, 1, 1, 2, 2, 3, 3, 4, 4, 5]
    v9 = v24[m] % 10;                           // [4, 3, 5, 1, 4, 1, 2, 1, 5, 3]
    if ( !(savedregs[6 * v6 + v9] % 0x10u / 8) || !(savedregs[6 * v6 + v9] % 4u / 2) )// 2和8
    {
      v3 = 4i64;
      if ( !(savedregs[6 * v6 + v9] % 8u / 4) ) // 1和4
        return sub_34000000020521(v3);
      v3 = 2i64;
      if ( !(savedregs[6 * v6 + v9] % 2u) )     // 不为1
        return sub_34000000020521(v3);
    }
    if ( savedregs[6 * v6 + v9] % 0x10u / 8 )
    {
      if ( savedregs[6 * v6 + v9] % 4u / 2 )    // 2和8
      {
        if ( !(savedregs[6 * v6 - 6 + v9] % 8u / 4)// 上一行4或1或8
          && !(savedregs[6 * v6 - 6 + v9] % 2u)
          && !(savedregs[6 * v6 + 6 + v9] % 8u / 4) )
        {
          v3 = 2i64;
          if ( !(savedregs[6 * v6 + 6 + v9] % 2u) )// 下一行4或1
            return sub_34000000020521(v3);
        }
      }
    }
    if ( savedregs[6 * v6 + v9] % 8u / 4 )
    {
      if ( savedregs[6 * v6 + v9] % 2u )        // 1和4
      {
        if ( !(savedregs[6 * v6 + 1 + v9] % 0x10u / 8)// 右一行2或8
          && !(savedregs[6 * v6 + 1 + v9] % 4u / 2)
          && !(savedregs[6 * v6 - 1 + v9] % 0x10u / 8) )
        {
          v3 = 2i64;
          if ( !(savedregs[6 * v6 - 1 + v9] % 4u / 2) )// 左一行2或8
            return sub_34000000020521(v3);
        }
      }
    }
  }
  v13 = 0;
  v14 = 0;
  v7 = 0;
  v10 = 0;
  if ( *savedregs % 0x10u / 8 )
  {
    v7 = -1;
    while ( 1 )
    {
LABEL_66:
      v3 = 8i64;
      if ( !(savedregs[6 * v7 + v10] % 0x10u / 8) || v7 - 1 == v13 && v10 == v14 )// 8,转向上一行
      {
        v3 = 2i64;
        if ( !(savedregs[6 * v7 + v10] % 4u / 2) || v7 + 1 == v13 && v10 == v14 )// 2下转
        {
          v3 = 4i64;
          if ( !(savedregs[6 * v7 + v10] % 8u / 4) || v7 == v13 && v10 - 1 == v14 )// 4左转
          {
            v3 = 2i64;
            if ( !(savedregs[6 * v7 + v10] % 2u) || v7 == v13 && v10 + 1 == v14 )// 1右转
              return sub_34000000020521(v3);
            v13 = v7;
            v14 = v10++;
          }
          else
          {
            v13 = v7;
            v14 = v10--;
          }
        }
        else
        {
          v13 = v7;
          v14 = v10;
          ++v7;
        }
      }
      else
      {
        v13 = v7;
        v14 = v10;
        --v7;
      }
      if ( !v7 && !v10 )
        return sub_34000000020521(v3);
    }
  }
  if ( *savedregs % 4u / 2 )
  {
    v7 = 1;
    goto LABEL_66;
  }
  if ( *savedregs % 8u / 4 )
  {
    v10 = -1;
    goto LABEL_66;
  }
  v3 = 2i64;
  if ( *savedregs % 2u )
  {
    v10 = 1;
    goto LABEL_66;
  }
  return sub_34000000020521(v3);
}

1对于向上的8,2对于向下的2,3对于向左的4,4对于向右的1。(就是小键盘,除了向右)
然后就是puzzle,masyu,连成一闭合回路就好
在这里插入图片描述
d3ctf{22441442223133324424441111133333}

D3Re

UWP逆向,依赖装不上???win11已弃用???
等之后装好win10虚拟机试试吧。。。

d3hotel

u3d和wasm
本题由两部分组成,包括 luac 逆向以及 wasm 逆向。首先下载得到 BuildWebGL.wasm 和
BuildWebGL.data。
assetstudio解包得到global-metadata.dat

中断,之前分析的被我删了,没有文件了。。。

不过好像是个矩阵的密码题,我也做不出来。。。
看看翻车鱼大佬的吧

d3mug

看了半天才发现是unity3d,(怎么又是u3d)
教你使用IL2CppDumper从Unity il2cpp的二进制文件中获取类型、方法、字段等(反编译)
解压进入目录中,拿到libil2cpp.so与global-metadata.dat。
\lib\armeabi-v7a\libil2cpp.so
\assets\bin\Data\Managed\Metadata\global-metadata.dat
建立input和output文件夹,将上两个文件放入input,建立il2cpp_decompilation.bat 写入..\Il2CppDumper.exe libil2cpp.so global-metadata.dat ..\output双击运行。得到
在这里插入图片描述

进入DummyDll,使用dnSpy分析Assembly-CSharp.dll,
关键函数GameManagerNoteHit (命中数)和 GameManagerNoteMissed (miss数)以及 ScoreScene__Start(得分数)
使用IDA逆向il2cpp.so,用script选择ida_with_struct_py3.py、script.json、il2cpp.h 加载自动分析,
通过IDA分析上述三个函数
打开stringliteral.json
在这里插入图片描述

逻辑没太看懂,就先这样吧

d3thon

首先运行main.py试试,报错
ImportError: byte_analizer.so: undefined symbol: Py_EnterRecursiveCall
Py_EnterRecursiveCall是python3.10.2的,所以安装python3.10.2
在用ipython运行
在这里插入图片描述
通过运行可知start函数输入flag
在这里插入图片描述
测试kuhisCvwaXWfqCs:flag报错ValueError: invalid literal for int() with base 10:即输入的是str型当运行okokok函数不在报错。
可知运行okokok函数是将str转换为int型
在okokokok函数中有四个类型的运算,分别是

IEKMEDdrPpzpdKy
OcKUQCYqhwHXfAgGZH
FLNPsiCIvICFtzpUAR
kuhisCvwaXWfqCs

下面分别对其进行测试:
开始flag为:12345678901324567890
首先运行kuhisCvwaXWfqCs:flag结果为-12345678901234567891
在这里插入图片描述
经过测试结果为取反

s=12345678901234567890
print(~s)
# -12345678901234567891

测试IEKMEDdrPpzpdKy
在这里插入图片描述
加法运算

s=-12345678901234567891
n=10641779330030268582371809187351647903979911439280211955812317507748263879299639
res=10641779330030268582371809187351647903979911439280211955812305162069362644731748
print(res-n)
# res=s+n

测试OcKUQCYqhwHXfAgGZH
在这里插入图片描述
异或运算

s=10641779330030268582371809187351647903979911439280211955812305162069362644731748
n=12658175988133673916668965029924777191548654467512522015899145443664296208583935
res=6335108005929618188748493643939642720594287999173416915586700348266136222075803
print(res^n==s)

测试FLNPsiCIvICFtzpUAR
在这里插入图片描述
减法运算

s=6335108005929618188748493643939642720594287999173416915586700348266136222075803
n=28
res=6335108005929618188748493643939642720594287999173416915586700348266136222075775
print(res==s-n)

脚本

# IEKMEDdrPpzpdKy +
# OcKUQCYqhwHXfAgGZH ^
# FLNPsiCIvICFtzpUAR -
# kuhisCvwaXWfqCs ~
s = []
n = -194952731925593882593246917508862867371733438849523064153861650948471779982880938
with open('./1.txt', 'r') as f: # 将37行复制出来到1.txt逆向操作即可
    s = f.read().split(",")
s.reverse()
for i in s:
    r = i.split(":")
    # print(r)
    if "'IEKMEDdrPpzpdKy" == r[0]:
        num = int(r[2].replace('\'', '')) # 尾部有个单引号
        n -= num
    elif "'FLNPsiCIvICFtzpUAR" == r[0]:
        num = int(r[2].replace('\'', ''))
        n += num
    elif "'OcKUQCYqhwHXfAgGZH" == r[0]:
        num = int(r[2].replace('\'', ''))
        n ^= num
    else:
        n = ~n
print(bytes.fromhex(hex(n)[2:]))

b'4729a4a6bbdd4d78c94e6229257af35e'

d3arm

bin文件猜测是stm32的固件逆向
[原创]使用IDA pro逆向ARM M系核心的Bin固件

在这里插入图片描述
借此可以判断 ram 的基址为 0x20000000,代码段的基址为 0x8000000
SRecord 1.64 下载地址:http://srecord.sourceforge.net/download.html
试了一下用SRecord 将bin转为hex好像没什么用。。。
用ida反编译,架构选择 arm 小端,在 详细设置里面选择 ARMv7-M(但是不知道为什么,mbedOS搜了一下是arm7可能是这个原因?)。

在这里插入图片描述
进一步设置
在这里插入图片描述
然后按c+p,create function,搜索flag,跳转
在这里插入图片描述
dword_2000326C交叉引用,跳转sub_8005E20
发现主要逻辑
因为flag is shown below ,所以byte_200022C8为flag

int sub_8005E20()
{
  if ( dword_20002304 != dword_200022F4 || dword_20002308 != dword_200022F8 )
    return 0;
  if ( dword_2000326C <= 41 )
    byte_200022C8[dword_2000326C] = dword_800DB64[4 * dword_2000326C] ^ byte_20002314;
  return 1;
}
// 可直接得到dword_800DB64
dword_800DB64=[0x20,0x6D,0x50,0x30,0x38,0x48,0x75,0x69,0x50,0x75,0x6B,0x56,0x20,0x6D,0x04,0x26,0x6A,0x51,0x72,0x6B,0x50,0x73,0x38,0x0B,0x74,0x6A,0x57,0x70,0x6E,0x50,0x25,0x3A,0x51,0x22,0x6E,0x56,0x75,0x3D,0x50,0x72,0x6A,0x4E]

然后获取byte_20002314

_DWORD *sub_8005DB0()
{
  _DWORD *result; // r0
  int v1; // r1
  bool v2; // cc
  int *v3; // r1
  int *v4; // r2

  result = (_DWORD *)sub_8007850(12);
  v1 = ++dword_2000326C % 3;
  v2 = (unsigned int)(dword_2000326C % 3) > 2;
  *result = 0;
  result[1] = 0;
  result[2] = 0;
  if ( !v2 )
    byte_20002314 = 0x335E44u >> (8 * v1);
  v3 = &dword_20002304;
  do
  {
    v4 = v3;
    v3 = (int *)v3[2];
  }
  while ( v3 );
  v4[2] = (int)result;
  return result;
}
// sub_8005850 部分
int sub_8005850()
{
  _DWORD *v0; // r4
  _DWORD *v1; // r0

  dword_2000326C = 0;
  byte_20002314 = 0x44;

推测byte_20002314=[0x44,0x5E,0x33];

脚本

s=[0x20,0x6D,0x50,0x30,0x38,0x48,0x75,0x69,0x50,0x75,0x6B,0x56,0x20,0x6D,0x04,0x26,0x6A,0x51,0x72,0x6B,0x50,0x73,0x38,0x0B,0x74,0x6A,0x57,0x70,0x6E,0x50,0x25,0x3A,0x51,0x22,0x6E,0x56,0x75,0x3D,0x50,0x72,0x6A,0x4E]
key=[0x44,0x5e,0x33]
for i in range(len(s)):
	print(chr(s[i]^key[i%3]),end='')
# d3ctf{17c15ed37b4b65c7f804d40cadbf0e1cc64}

ghidra 对固件逆向要更为友好,之后看看拿ghidra分析一下

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值