GDOUCTF2023 Reverse题解

题目附件

链接:https://pan.baidu.com/s/1W0GisS4R-rHYHK4Bu167_g?pwd=nw4c

Check_Your_Luck

可以看到五条方程,根据方程可以求解出对应的值

请添加图片描述

Z3库解不出来,所以用了在线解方程云算网(原名云算子)-在线求解线性方程组 (yunsuan.info)

flag: NSSCTF{4544_123_677_1754_777}

TEA

基本逻辑:

  1. 调用show函数,提示输入输出
  2. 以十六进制读取输入,可以得知共10*4=40字符
  3. 设置key数组
  4. 将input复制到arr数组中
  5. tea加密
  6. judge判断是否正确
  7. 输出flag
    请添加图片描述

mainfun代码:

__int64 mainfun()
{
  char *v0; // rdi
  __int64 i; // rcx
  char v3[32]; // [rsp+0h] [rbp-20h] BYREF
  char v4; // [rsp+20h] [rbp+0h] BYREF
  int v5; // [rsp+24h] [rbp+4h]
  int result; // [rsp+44h] [rbp+24h]
  unsigned int key[12]; // [rsp+68h] [rbp+48h] BYREF
  int input[16]; // [rsp+98h] [rbp+78h] BYREF
  int arr[31]; // [rsp+D8h] [rbp+B8h] BYREF
  int j; // [rsp+154h] [rbp+134h]
  int k; // [rsp+174h] [rbp+154h]
  int m; // [rsp+194h] [rbp+174h]

  v0 = &v4;
  for ( i = 102i64; i; --i )//没作用
  {
    *v0 = 0xCCCCCCCC;
    v0 += 4;
  }
  sub_7FF7B3C8137F(&unk_7FF7B3C93009);	//没作用
  v5 = 32;//tea循环次数
  result = 0;
  key[0] = 1234;
  key[1] = 5678;
  key[2] = 9012;
  key[3] = 3456;	//设置key,但是这里设置的值是混淆的,下方会重新设置
  memset(input, 0, 40ui64);
  arr[15] = 0;
  arr[23] = 0;
  show();			//提示flag输入是以0x12345678这样的形式
  for ( j = 0; j < 10; ++j )
    scanf("%x", &input[j]);	//以16进制读取,共10个,所以有10*4=40字符
  setKey(key);		//设置key
  copy(input, arr);		//将input的内容复制到arr
  encode(input, key);	//对input加密
  result = judge(input);	//判断加密后的数组是否正确
  if ( result )	
  {
    printf("you are right\n");
    for ( k = 0; k < 10; ++k )
    {
      for ( m = 3; m >= 0; --m )
        printf("%c", (arr[k] >> (8 * m)));	//如果正确则输出input,即flag
    }
  }
  else
  {
    printf("fault!\nYou can go online and learn the tea algorithm!");
  }
  sub_7FF7B3C81311(v3, &unk_7FF7B3C8AE90);
  return 0i64;
}

show函数

请添加图片描述

setKey函数

请添加图片描述

encode函数(tea算法):

__int64 __fastcall tea(unsigned int *arr, unsigned int *key)
{
  __int64 result; // rax
  int v3; // [rsp+44h] [rbp+24h]
  int i; // [rsp+64h] [rbp+44h]
  unsigned int v5; // [rsp+84h] [rbp+64h]
  unsigned int sum; // [rsp+C4h] [rbp+A4h]

  result = sub_7FF7B3C8137F(&unk_7FF7B3C93009);//没用
  for ( i = 0; i <= 8; ++i )
  {
    v5 = 0;
    sum = 0xF462900 * i;//delta与标准的tea并不同
    v3 = i + 1;
    do
    {
      ++v5;
      arr[i] += sum ^ (arr[v3] + ((arr[v3] >> 5) ^ (16 * arr[v3]))) ^ (sum + key[sum & 3]);
      arr[v3] += (sum + key[(sum >> 11) & 3]) ^ (arr[i] + ((arr[i] >> 5) ^ (16 * arr[i])));
      sum += 0xF462900;//关键算法和tea区别不大
    }
    while ( v5 <= 32 );                         // 注意这里是从0到32,共33次循环
    result = (i + 1);
  }
  return result;
}

judge函数

请添加图片描述

解题脚本

#include <stdio.h>
int main()
{
int v3; // [rsp+44h] [rbp+24h]
int i; // [rsp+64h] [rbp+44h]
unsigned int v5; // [rsp+84h] [rbp+64h]
int sum; // [rsp+C4h] [rbp+A4h]
int key[4] = {2233,4455,6677,8899 };
unsigned int arr[10];
arr[0] = 0x1A800BDA;
arr[1] = 0xF7A6219B;
arr[2] = 0x491811D8;
arr[3] = 0xF2013328;
arr[4] = 0x156C365B;
arr[5] = 0x3C6EAAD8;
arr[6] = 0x84D4BF28;
arr[7] = 0xF11A7EE7;
arr[8] = 0x3313B252;
arr[9] = 0xDD9FE279;
for (i = 8; i >=0; i--)
{
v5 = 0;
sum = 0xF462900 * i;
for (int j = 0; j < 33; j++)
sum += 0xF462900;
v3 = i + 1;
do
{
sum -= 0xF462900;
arr[v3] -= (sum + key[(sum >> 11) & 3]) ^ (arr[i] + ((arr[i] >> 5) ^ (16 * arr[i])));
arr[i] -= sum ^ (arr[v3] + ((arr[v3] >> 5) ^ (16 * arr[v3]))) ^ (sum + key[sum & 3]);
++v5;
} while (v5 <= 32);//33次循环
}
for (int k = 0; k < 10; ++k)
{
    for (int m = 3; m >= 0; --m)
        printf("%c", (arr[k] >> (8 * m)));
}
//HZCTF{hzCtf_94_re666fingcry5641qq}
return 0;

doublegame

进来找不到关键函数,查看strings看到类似迷宫的东西,根据字符串可以定位到关键函数

请添加图片描述
然后一路用交叉引用往上找就可以找到第一和第二个游戏的函数
在这里插入图片描述

snakefun

第一个游戏贪吃蛇
通过patch可以修改得分判断条件,从而进入game2
请添加图片描述
patch在edit>keypatch(或patch progeam)>patcher
在这里插入图片描述
然后会弹出窗口
在这里插入图片描述
修改之后在patch program>apply patches to即可保存修改后的程序(记得改一下程序名)
在这里插入图片描述

__int64 __fastcall snakefun(int a1, int a2)
{
  char *v2; // rdi
  __int64 i; // rcx
  char v5[32]; // [rsp+0h] [rbp-20h] BYREF
  char v6; // [rsp+20h] [rbp+0h] BYREF
  char chr[212]; // [rsp+24h] [rbp+4h] BYREF

  v2 = &v6;
  for ( i = 10i64; i; --i )
  {
    *(_DWORD *)v2 = -858993460;
    v2 += 4;
  }
  sub_7FF6BD89141A((__int64)&unk_7FF6BD8A90A6);
  if ( dword_7FF6BD8A1E60[42 * a2 + 42 * dword_7FF6BD8A0178 + a1 + dword_7FF6BD8A0174] == 2 )
  {
    ++dword_7FF6BD8A0170;
    score += 10;
    sub_7FF6BD8911A9(7i64);
    sub_7FF6BD89130C(0i64, 22i64);
    printf(aD_2, (unsigned int)score);          // 当前得分
    setFood();                                  // 生成食物
  }
  else if ( dword_7FF6BD8A1E60[42 * a2 + 42 * dword_7FF6BD8A0178 + a1 + dword_7FF6BD8A0174] == 1
         || dword_7FF6BD8A1E60[42 * a2 + 42 * dword_7FF6BD8A0178 + a1 + dword_7FF6BD8A0174] == 4 )
  {
    Sleep(0x3E8u);
    system("cls");
    sub_7FF6BD8911A9(7i64);
    sub_7FF6BD89130C(28i64, 8i64);
    sub_7FF6BD8911DB();                         // 分数还差一点
    if ( score > 16 )                           // score13371337
      sub_7FF6BD89136B();                       // jump to game 2
    sub_7FF6BD8910E6();                         // 保存最高记录失败
    sub_7FF6BD89130C(28i64, 11i64);
    printf("GAME OVER");
    while ( 1 )
    {
      sub_7FF6BD89130C(28i64, 14i64);
      printf(asc_7FF6BD89D320);                 // 是否再来一局
      scanf_0("%c", chr);
      if ( chr[0] == 'y' || chr[0] == 'Y' )
        break;
      if ( chr[0] == 'n' || chr[0] == 'N' )
      {
        sub_7FF6BD89130C(28i64, 16i64);
        exit(0);
      }
      sub_7FF6BD89130C(28i64, 16i64);
      printf(asc_7FF6BD89D3A0);                 // 选择错误
    }
    system("cls");
    someidea();                                 // 提示
  }
  return sub_7FF6BD8913B1(v5, &unk_7FF6BD89CFC0);
}

迷宫

第二个游戏走迷宫救猫

这是迷宫图:

请添加图片描述

注意这里多了一堵墙

请添加图片描述

由于patchd的分数要大于16,贪吃蛇游戏吃两个食物撞墙之后即可进入游戏2
游戏2就是走迷宫了,一次输入一个操作符然后回车即可
在这里插入图片描述

下面还有一个大循环

关键循环

v24 = 0;
  key = 0;
  hang = 15;
  lie = 0;
  shang = 7;                                    // 8行
  slie = 20;                                    // 21列
  for ( j = 0; j <= 20; ++j )
    puts(&Buffer[22 * j]);                      // 打印迷宫
  printf("Please to save the cat!\n");
  while ( hang != shang || lie != slie )        // 好像不是走到@的位置
  {
    chr = getchar();
    switch ( chr )
    {
      case 's':
        if ( Buffer[22 * hang + 22 + lie] != '0' )
        {
          Buffer[22 * hang++ + lie] = ' ';
          Buffer[22 * hang + lie] = '@';
        }
        break;
      case 'w':
        if ( Buffer[22 * hang - 22 + lie] != '0' )
        {
          Buffer[22 * hang-- + lie] = ' ';
          Buffer[22 * hang + lie] = '@';
        }
        break;
      case 'a':
        if ( Buffer[22 * hang - 1 + lie] != '0' )
        {
          if ( Buffer[22 * hang - 1 + lie] == '*' )// 先到*这里
            v7[20] = '0';	//设置墙
          Buffer[22 * hang + lie--] = ' ';
          Buffer[22 * hang + lie] = '@';
        }
        break;
      default:
        if ( chr == 'd' && Buffer[22 * hang + 1 + lie] != '0' )
        {
          Buffer[22 * hang + lie++] = ' ';
          Buffer[22 * hang + lie] = '@';
        }
        break;
    }
    system("cls");
    for ( j = 0; j <= 20; ++j )
      puts(&Buffer[22 * j]);                    // 打印迷宫
    puts(&v19[100 * v24]);                      // 请救猫
    if ( v7[20] == '0' )
    {
      key = judge(0i64);                        // 判断key
      if ( key == 13376013 )
      {
        v24 = 1;
        v7[20] = ' ';                           // 打通终点前的墙
        Buffer[22 * hang + lie] = ' ';
        hang = 15;
        lie = 0;
        v11[0] = '@';                           // 回到起点
        ++v24;
      }
      else
      {
        printf("error");
      }
    }
  }

循环功能:

  1. shang,slie是终点;hang,lie是当前位置

  2. 从@的位置出发,经路径dddssssddwwwwddssddwwwwwwddddssa救到小猫后回到起点;同时小猫所在位置由’*‘变为’ ',且第8行第20列的空格变为0

  3. 然后要求输入key,key可以根据judge函数反推出来是13371337

  4. 再从起点出发,经路径dddssssddwwwwddssddwwwwwwddddssaassddddwwwwddwwwwddd走出迷宫

  5. 所以path:dddssssddwwwwddssddwwwwwwddddssaassddddwwwwddwwwwddd key:13371337

  6. 根据提示可以求出flag:NSSCTF{811173b05afff098b4e0757962127eac13371337}

提示函数:

请添加图片描述

L!S!

1.安装BinDiff

这里需要使用到BinDiff,下载地址zynamics.com
在这里插入图片描述
点击msi文件即可下载,如果没反应可以右键复制链接用迅雷等下载工具下载
在这里插入图片描述
安装时注意路径即可,默认在C盘,可以自己修改,他会自动绑定IDA的路径
在这里插入图片描述
这里就不演示BinDiff分析数据库文件了,相对比较麻烦,直接用ida

2.IDA分析

先用ida分别打开ls-original和ls-patched,生成对应数据库文件
在这里插入图片描述
然后打开ls-patched.i64文件,选择Edit>Plugins>BinDiff,
在这里插入图片描述

他会弹出弹窗,选择Diff Database
在这里插入图片描述
再选中ls-original.i64文件
在这里插入图片描述
注意: 文件不能保存在中文路径下,必须是英文路径,否则可能会报错找不到数据库文件
Error while diffing: Export of the secondary database failed: File not found: C:\Users\admin\Desktop\网安比赛\GDOUCTF2023\L!s!\ls-original.i64

在这里插入图片描述

ida分析之后会出现几个新的窗口,最关键的是这个Matched Functions窗口,绿色代表匹配一致,往下翻在最后可以发现extract_dirs_from_files函数的颜色是黄绿色,双击,按f5反汇编(从文件中提取目录)
在这里插入图片描述

反汇编窗口往下翻可以看到关键函数,这个循环的基本功能应该是对lmao数组的数据进行异或,但并不容易的值用于异或的中间值是什么
在这里插入图片描述

参考了大佬的wp可以使用cyberchef工具爆破出来
先拖入From Hex,再拖入XOR Brute Force,运行后在输出窗口找到key=4c即可发现flag

在这里插入图片描述

flag:HZCTF{b1ndiff_1s_a_us3ful_t00l}

参考文章

  1. 2023 | GDOUCTF
  2. 反混淆神器!CyberChef助你秒解混淆脚本
  3. Win10 + Bindiff 6.0 + IDA 7.5 安装教程
  4. BinDiff安装使用教程
  5. [GDOUCTF 2023]L!s! Y0ung的WriteUp
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

OrientalGlass

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值