GDOUCTF2023 Reverse题解

news/2024/5/19 21:26:17 标签: Reverse, Tea加密算法, keypatch, GDOUCTF2023, CTF

文章目录

  • 题目附件
  • Check_Your_Luck
  • TEA
    • 基本逻辑:
    • show函数
    • setKey函数
    • encode函数(tea算法):
    • judge函数
    • 解题脚本
  • doublegame
    • snakefun
    • 迷宫
    • 关键循环

题目附件

链接: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
请添加图片描述

__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);
}
/* Orphan comments:
打破最高记录
继续加油,最高记录分为
*/

迷宫

这是迷宫图:

请添加图片描述

注意这里多了一堵墙

请添加图片描述

下面还有一个大循环

关键循环

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}

提示函数:

请添加图片描述

位置由’*‘变为’ ',且第8行第20列的空格变为0

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

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

  3. 所以path:dddssssddwwwwddssddwwwwwwddddssaassddddwwwwddwwwwddd key:13371337

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


http://www.niftyadmin.cn/n/233483.html

相关文章

Java多线程之线程池

文章目录1. 线程池的作用2. 使用线程池的好处3. 线程池的七个参数4. 线程池执行任务的流程5. Java 标准库中的线程池1&#xff09;newFixedThreadPool2&#xff09;newCachedThreadPool3&#xff09;newScheduleThreadPool4&#xff09;newSingleThreadExecutor6. 对比两种提交…

2023 年 18 种最佳 Android 测试工具

随着时间的推移&#xff0c;应用程序市场变得竞争异常激烈。在竞争激烈的市场中&#xff0c;开发人员脱颖而出的一种方法是构建和生产功能强大、可靠且无错误的移动应用程序。虽然功能是开发人员需要解决的问题&#xff0c;但在移动自动化测试的帮助下制作无错误的应用程序变得…

Redis高可用

最近离职后还没开始找工作&#xff0c;在找工作前去学习一下Redis高可用方案。 目录Redis高可用高可用的概念实现方式持久化主从复制简单结构优化结构优缺点哨兵模式&#xff08;Sentinel&#xff09;哨兵进程的作用自动故障迁移(Automatic failover)优缺点集群优缺点Redis高可…

SSM整合的基本思路梳理

SSM整合的简单思路流程 基本思路 我在整合的时候一般习惯从MyBatis开始向上构建&#xff0c;也就是在开始一个项目的时候先将DAO层搭建起来&#xff0c;再向上整合Spring以及SpringMVC。按照这个流程&#xff0c;可以做出一个比较简单的大致流程作为参考&#xff0c;帮助我们…

涨点技巧:IOU篇---Yolov8引入WIoU,SIoU,EIoU,α-IoU,不同数据集验证能涨点

1.IOU介绍 IoU其实是Intersection over Union的简称,也叫‘交并比’。IoU在目标检测以及语义分割中,都有着至关重要的作用。 首先,我们先来了解一下IoU的定义: 我们可以把IoU的值定为为两个图形面积的交集和并集的比值,如下图所示: 1.1 Yolov8自带IOU方法 GIoU, DIoU,…

什么是js混淆加密

JavaScript是一种广泛使用的编程语言&#xff0c;可以在客户端和服务器端使用。由于其易于学习和使用的特点&#xff0c;JavaScript被广泛应用于Web开发中。然而&#xff0c;JavaScript的代码是开放的&#xff0c;易受到攻击和盗用。因此&#xff0c;为了保护JavaScript代码&am…

初识 Service Worker

简介 Service Worker 是一种在 Web 平台上运行的脚本&#xff0c;它能够拦截和处理网络请求、管理应用程序的缓存、实现离线访问等功能。使用 service worker&#xff0c;你可以将 app 设置为首先使用缓存资源&#xff0c;从而即使在离线状态&#xff0c;也可以提供默认的体验…

Qt音视频开发38-ffmpeg视频暂停录制的设计

一、前言 基本上各种播放器提供的录制视频接口&#xff0c;都是只有开始录制和结束录制两个&#xff0c;当然一般用的最多的也是这两个接口&#xff0c;但是实际使用过程中&#xff0c;还有一种可能需要中途暂停录制&#xff0c;暂停以后再次继续录制&#xff0c;将中间部分视…