re学习(31)BUUCTF-xx(多层加密)

news2025/1/22 18:45:34

参考文章:
【BUUCTF逆向 [2019红帽杯]xx】_nb_What_DG的博客-CSDN博客

re学习笔记(26)BUUCTF-re-[2019红帽杯]xx_Forgo7ten的博客-CSDN博客 

还有B站 水番正文

IDA64位载入
shift+F12查看字符串

 

交叉引用找到关键代码

 

使用findcrypt插件找到加密算法为tea系列,进函数内部查看知道为xxtea 

 

// 代码审计(正向开发经验)
int __cdecl main(int argc, const char **argv, const char **envp)
{
  __int64 flaglen2; // rbx
  __int64 flaglen1; // rax
  __int128 *malloc5; // rax
  __int64 data; // r11
  __int128 *malloc7; // r14
  int v8; // edi
  __int128 *malloc9; // rsi
  char tmp; // r10
  int v11; // edx
  __int64 v12; // r8
  unsigned __int64 datalen; // rcx
  __int64 v14; // rcx
  unsigned __int64 v15; // rax
  unsigned __int64 i; // rax
  __int64 encodeflag; // rax
  size_t encodeflaglen; // rsi
  _BYTE *enflag; // rbx
  _BYTE *v20; // r9
  int I; // r11d
  char *data1; // r8
  __int64 n; // rcx
  char v24; // al
  __int64 v25; // r9
  __int64 v26; // rdx
  __int64 v27; // rax
  size_t Size; // [rsp+20h] [rbp-48h] BYREF
  __int128 v30; // [rsp+28h] [rbp-40h] BYREF
  int v31; // [rsp+38h] [rbp-30h]
  int v32; // [rsp+3Ch] [rbp-2Ch]
  int flag[4]; // [rsp+40h] [rbp-28h] BYREF
  int v34; // [rsp+50h] [rbp-18h]

  *(_OWORD *)flag = 0i64;
  v34 = 0;
  sub_1400018C0(std::cin, argv, flag);          // 在C++中,std其实就是standard标准的意思。
                                                //  例如std::cin就是标准输入,std::cout就是标准输出的意思。
  flaglen2 = -1i64;
  flaglen1 = -1i64;
  do
    ++flaglen1;
  while ( *((_BYTE *)flag + flaglen1) );
  if ( flaglen1 != 19 )                         // flag 为 19位
  {
    sub_140001620((__int64 *)std::cout, (__int64)"error\n");
    _exit((int)flag);
  }
  malloc5 = (__int128 *)operator new(5ui64);    // operator new申请内存(operator new后面将进行详细说明,这里理解为C语言中的malloc)
  data = *(_QWORD *)&Code;                      // 将Code数据给data,
                                                // Code为"qwertyuiopasdfghjklzxcvbnm1234567890"
  malloc7 = malloc5;
  v8 = 0;
  malloc9 = malloc5;
  do
  {
    tmp = *((_BYTE *)malloc9 + (char *)flag - (char *)malloc5);
    v11 = 0;
    *(_BYTE *)malloc9 = tmp;
    v12 = 0i64;
    datalen = -1i64;
    do
      ++datalen;
    while ( *(_BYTE *)(data + datalen) );
    if ( datalen )
    {
      do
      {
        if ( tmp == *(_BYTE *)(data + v12) )
          break;
        ++v11;
        ++v12;
      }
      while ( v11 < datalen );
    }
    v14 = -1i64;
    do
      ++v14;
    while ( *(_BYTE *)(data + v14) );
    if ( v11 == v14 )
      _exit(data);
    malloc9 = (__int128 *)((char *)malloc9 + 1);// 下一位
  }
  while ( (char *)malloc9 - (char *)malloc5 < 4 );
  *((_BYTE *)malloc5 + 4) = 0;
  do
    ++flaglen2;
  while ( *((_BYTE *)flag + flaglen2) );
  v15 = 0i64;
  v30 = *malloc7;
  while ( *((_BYTE *)&v30 + v15) )
  {
    if ( !*((_BYTE *)&v30 + v15 + 1) )
    {
      ++v15;
      break;
    }
    if ( !*((_BYTE *)&v30 + v15 + 2) )
    {
      v15 += 2i64;
      break;
    }
    if ( !*((_BYTE *)&v30 + v15 + 3) )
    {
      v15 += 3i64;
      break;
    }
    v15 += 4i64;
    if ( v15 >= 0x10 )
      break;
  }
  for ( i = v15 + 1; i < 0x10; ++i )
    *((_BYTE *)&v30 + i) = 0;                   // 全部赋值为0
  encodeflag = (__int64)sub_140001AB0((__int64)flag, flaglen2, (unsigned __int8 *)&v30, &Size);
  encodeflaglen = Size;
  enflag = (_BYTE *)encodeflag;
  v20 = operator new(Size);                     // v20开辟一块内存区域
  I = 1;
  *v20 = enflag[2];
  data1 = v20 + 1;                              // v22与v20指向了同一片内存区域
  v20[1] = *enflag;
  v20[2] = enflag[3];
  v20[3] = enflag[1];
  v20[4] = enflag[6];
  v20[5] = enflag[4];
  v20[6] = enflag[7];
  v20[7] = enflag[5];
  v20[8] = enflag[10];
  v20[9] = enflag[8];
  v20[10] = enflag[11];
  v20[11] = enflag[9];
  v20[12] = enflag[14];
  v20[13] = enflag[12];
  v20[14] = enflag[15];
  v20[15] = enflag[13];
  v20[16] = enflag[18];
  v20[17] = enflag[16];
  v20[18] = enflag[19];
  v20[19] = enflag[17];
  v20[20] = enflag[22];
  v20[21] = enflag[20];
  v20[22] = enflag[23];
  for ( v20[23] = enflag[21]; I < encodeflaglen; ++data1 )// 异或操作
  {
    n = 0i64;
    if ( I / 3 > 0 )                            // I从3开始
    {
      v24 = *data1;
      do
      {
        v24 ^= v20[n++];                        // v22^v20
        *data1 = v24;
      }
      while ( n < I / 3 );                      // I/3是跟前多少位...
    }
    ++I;
  }
  *(_QWORD *)&v30 = 0xC0953A7C6B40BCCEui64;
  v25 = v20 - (_BYTE *)&v30;
  *((_QWORD *)&v30 + 1) = 0x3502F79120209BEFi64;
  v26 = 0i64;
  v31 = 0xC8021823;
  v32 = 0xFA5656E7;
  do
  {
    if ( *((_BYTE *)&v30 + v26) != *((_BYTE *)&v30 + v26 + v25) )
      _exit(v8 * v8);
    ++v8;
    ++v26;
  }
  while ( v26 < 24 );
  v27 = (__int64)sub_140001620((__int64 *)std::cout, (__int64)"You win!");
  std::ostream::operator<<(v27, sub_1400017F0);
  return 0;
}

 

流程为

  1. 先判断输入的字符串是否都在程序实现存储的数据Code中
  2. 然后取前四个字符作为xxtea的密钥,(不满位数右端补零)
  3. 然后对输入的字符串进行加密
  4. 之后对加密的字符串打乱顺序
  5. 之后异或操作
  6. 再与存储的数据进行比对

其中第6部存储的数据为

 

v30,v30+1,v31,v32在栈上存放的位置相连。小端序存放,需将其反过来写。 

 开始写脚本:

一.逆异或  二.正序

data0 = "CEBC406B7C3A95C0EF9B202091F70235231802C8E75656FA"#为提取出来的v29,v29+1,v30,v31
data = []
for i in range(0,len(data0),2):
    data.append(int(data0[i]+data0[i+1],16))#每两位为整体,将16进制转换为10进制
print(data)
for i in range(len(data)-1,-1,-1):
    for j in range(i//3):
        data[i] ^= data[j]
        #1.进行的异或操作
print(data)
biao = [2,0,3,1,6,4,7,5,10,8,11,9,14,12,15,13,18,16,19,17,22,20,23,21]#置换表
shuju = [1]*24
for i in range(24):
    shuju[biao[i]] = data[i]#2.将其按照一定顺序置换
print(shuju)
print(len(shuju))

三.得到加密数据 密钥key xxtea解密

 因为用户输入的为19位字符,也就是38位十六进制字符串,而上面生成了40位,所以要去掉最后两位,也就是去掉13。

#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include "encode.h"
int main()
{
	int i,j,data[] = { 188, 165, 206, 64, 244, 178, 178, 231, 169, 18, 157, 18, 174, 16, 200, 91, 61, 215, 6, 29, 220, 112, 248, 220 };
	for (i = 1; i <= 6; i++)//3.导出加密的数据,将其转换为十六进制并用小端序来表示
	{
		printf("0x");
		for (j = i * 4 - 1; j > (i - 1) * 4 - 1; j--)
			printf("%x", data[j]);
		printf(",");
	}
	printf("\n0x");
	int key[] = { 'f','l','a','g' };//导出密钥,将其转换为十六进制并用小端序来表示
	for (i = 3; i >= 0; i--)
		printf("%x", key[i]);
	printf(",");
	for (i = 0; i < 3; i++)//密钥为4个32位的数,1个字符4bit,4个字符为32bit,还差3个32bit的数
		printf("0x0,");
}

 图片展示

 

#include <stdio.h>
#include <stdint.h>
#define DELTA 0x9e3779b9
#define MX (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z)))
void btea(uint32_t *v, int n, uint32_t const key[4])
{
    uint32_t y, z, sum;
    unsigned p, rounds, e;
    if (n > 1)            /* Coding Part */
    {
        rounds = 6 + 52/n;
        sum = 0;
        z = v[n-1];
        do
        {
            sum += DELTA;
            e = (sum >> 2) & 3;
            for (p=0; p<n-1; p++)
            {
                y = v[p+1];
                z = v[p] += MX;
            }
            y = v[0];
            z = v[n-1] += MX;
        }
        while (--rounds);
    }
    else if (n < -1)      /* Decoding Part */
    {
        n = -n;
        rounds = 6 + 52/n;
        sum = rounds*DELTA;
        y = v[0];
        do
        {
            e = (sum >> 2) & 3;
            for (p=n-1; p>0; p--)
            {
                z = v[p-1];
                y = v[p] -= MX;
            }
            z = v[n-1];
            y = v[0] -= MX;
            sum -= DELTA;
        }
        while (--rounds);
    }
}


int main()
{
    uint32_t v[6]= {0x40cea5bc,0xe7b2b2f4,0x129d12a9,0x5bc810ae,0x1d06d73d,0xdcf870dc};
    uint32_t const k[4]= {0x67616c66,0,0,0};
    int n= 6; //n的绝对值表示v的长度,取正表示加密,取负表示解密
    // v为要加密的数据是两个32位无符号整数
    // k为加密解密密钥,为4个32位无符号整数,即密钥长度为128位
    //printf("加密前原始数据:%u %u\n",v[0],v[1]);
    //btea(v, n, k);
    //printf("加密后的数据:%u %u\n",v[0],v[1]);
    btea(v, -n, k);
    for (int i = 0 ; i < 6;i++){
        printf("%x",v[i]);
        printf(" ");
    }
    return 0;
}

m = [0x67616c66,0x5858437b,0x646e615f,0x742b2b5f,0x7d6165]

四.最后将生成的十六进制数用小端序表示

m = [0x67616c66,0x5858437b,0x646e615f,0x742b2b5f,0x7d6165]
flag = ''
for i in m:
    flag += libnum.n2s(i).decode()[::-1]
    
print(flag)
#flag{CXX_and_++tea}

 

总结:
1.如果涉及多字节了,应该考虑字节的顺序,比如这个题,就应该将处理的数据都转换为小端序

2.这个题的加密步骤有多步(3步:xxtea/乱序/异或)

3.要增强python工具,提高代码能力

 

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/883494.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

H13-922题库 HCIP-GaussDB-OLAP V1.5

**H13-922 V1.5 GaussDB(DWS) OLAP题库 华为认证GaussDB OLAP数据库高级工程师HCIP-GaussDB-OLAP V1.0自2019年10月18日起&#xff0c;正式在中国区发布。当前版本V1.5 考试前提&#xff1a; 掌握基本的数据库基础知识、掌握数据仓库运维的基础知识、掌握基本Linux运维知识、…

互联网发展历程:速度与效率,交换机的登场

互联网的演进就像一场追求速度与效率的竞赛&#xff0c;每一次的技术升级都为我们带来更快、更高效的网络体验。然而&#xff0c;在网络的初期阶段&#xff0c;人们面临着数据传输速度不够快的问题。一项关键的技术应运而生&#xff0c;那就是“交换机”。 速度不足的困境&…

SpringBoot + Mybatis多数据源

一、配置文件 spring: # datasource: # username: root # password: 123456 # url: jdbc:mysql://127.0.0.1:3306/jun01?characterEncodingutf-8&serverTimezoneUTC # driver-class-name: com.mysql.cj.jdbc.Driverdatasource:# 数据源1onedata:jdbc-url: j…

希尔排序【Java算法】

文章目录 1. 概念2. 思路3. 代码实现 1. 概念 希尔排序也是一种插入排序&#xff0c;它是简单插入排序经过改进之后的一个更高效的版本&#xff0c;也称为缩小增量排序。希尔排序在数组中采用跳跃式分组的策略&#xff0c;通过某个增量将数组元素划分为若干组&#xff0c;然后分…

linux学习(自写shell)[11]

打印出提示信息获取用户键盘输入 cmd_line[NUM];用来保存完整的命令行 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/wait.h>#define NUM 1024 char cmd_line[NUM]; //shell int main() {wh…

AI Chat 设计模式:15. 桥接模式

本文是该系列的第十五篇&#xff0c;采用问答式的方式展开&#xff0c;问题由我提出&#xff0c;答案由 Chat AI 作出&#xff0c;灰色背景的文字则主要是我的一些思考和补充。 问题列表 Q.1 如果你是第一次接触桥接模式&#xff0c;那么你会有哪些疑问呢&#xff1f;A.1Q.2 什…

FreeRTOS(独立看门狗监测任务执行与低功耗Tickless模式)

资料来源于硬件家园&#xff1a;资料汇总 - FreeRTOS实时操作系统课程(多任务管理) 目录 一、独立看门狗介绍 二、看门狗监测多任务执行思路 1、监测目标 2、监测方案 3、应用注意事项 三、看门狗监测多任务编程 1、STM32cubeMX配置 2、代码编写 四、低功耗Tickless模…

QT笔记——QProcess学习

我们常常想通过某一个类&#xff0c;来启动一个外部进程 本文将讲解如何通过QProcess来进行启动外部进程 一&#xff1a;了解QProcess QProcess是Qt框架提供的一个类&#xff0c;用于在应用程序中执行外部进程。它提供了一系列函数来启动、控制和与外部进程进行交互 1.启动进程…

02 基于51单片机的LED闪烁实验

目录 前言 一、整体目录结构 二、代码展示 三、main.c代码解析 四、下载到单片机中 总结 前言 前面我们已经学会了点亮一个led的实验&#xff0c;今天我们来实现LED闪烁。前面我们讲到想要让LED亮的话&#xff0c;只要给单片机引脚高电平就好了&#xff0c;如果给LED低电平的话…

Flink之Task解析

Flink之Task解析 对Flink的Task进行解析前,我们首先要清楚几个角色TaskManager、Slot、Task、Subtask、TaskChain分别是什么 角色注释TaskManager在Flink中TaskManager就是一个管理task的进程,每个节点只有一个TaskManagerSlotSlot就是TaskManager中的槽位,一个TaskManager中可…

Vue2-配置脚手架、分析脚手架、render函数、ref属性、props配置项、mixin配置项、scoped样式、插件

&#x1f954;:总有一段付出了没有回报的日子 是在扎根 更多Vue知识请点击——Vue.js VUE2-Day6 配置脚手架脚手架结构render函数vue.js与vue.runtime.xxx.js的区别引入render函数为什么要引入残缺的vue呢&#xff1f; 脚手架默认配置ref属性props配置项传递数据接收数据注意点…

elementui form组件出现英文提示

今天让解决一个bug&#xff0c;是表单组件提示词会出现英文。 问题情景如下&#xff1a; 有时会出现中文&#xff0c;有时会出现英文。 解决方法&#xff1a; 经查看&#xff0c;代码采用的是elementui的form组件&#xff0c;在el-form-item中使用了required属性&#xff0c;同…

企业权限管理(十)-用户详情

用户详情 UserController findById方法 Controller RequestMapping("/user") public class UserController {Autowiredprivate IUserService userService;//查询指定id的用户RequestMapping("/findById.do")public ModelAndView findById(String id) thro…

Python面向对象进阶教程,Python面向对象进阶知识笔记

类方法、静态方法 1. 类方法 第一个形参是类对象的方法需要用装饰器classmethod来标识其为类方法&#xff0c;对于类方法&#xff0c;第一个参数必须是类对象&#xff0c;一般以cls作为第一个参数。 class Dog(object): __type "狗" # 类方法&#xff0c;用class…

数据结构中公式前中后缀表达式-二叉树应用

目录 数据结构中公式前中后缀表达式-二叉树应用 数据结构中公式前中后缀表达式-二叉树应用 什么是前缀表达式、中缀表达式、后缀表达式 前缀表达式、中缀表达式、后缀表达式&#xff0c;是通过树来存储和计算表达式的三种不同方式 以如下公式为例 通过树来存储该公式&#x…

Avalonia 11 WebAssembly中文乱码

文章目录 0x00 原因0x01 解决方法FontForge 0x02 使用自定义字体App.axaml控件使用效果 0x00 原因 新建的Avalonia 11 WebAssembly项目&#xff0c;直接运行的话&#xff0c;会发现中文都是乱码&#xff0c;并且直接在控件上修改FontFamily属性是无法生效的。 0x01 解决方法…

MySQL学习笔记 - 进阶部分

MySQL进阶部分 字符集的相关操作&#xff1a;字符集和比较规则&#xff1a;utf8与utf8mb4&#xff1a;比较规则&#xff1a;常见的字符集和对应的Maxlen&#xff1a; Centos7中linux下配置字符集&#xff1a;各个级别的字符集&#xff1a;执行show variables like %character%语…

matlab画图中多个图例分开绘制

在matlab绘图中&#xff0c;线条较多时导致图例较长回遮挡原图/将图例分类&#xff0c;解决方案将图例分为多个。 一、多个图例一起显示 r 10; a 0; b 0; t0:0.1:2.1*pi; xar*cos(t); ybr*sin(t); plot(x,y,r,linewidth,4);hold on axis equal plot([0 0],[1 10],b,linewi…

双碳目标下基于“遥感+”多技术融合在碳储量、碳排放、碳循环、温室气体等领域应用教程

详情点击链接&#xff1a;双碳目标下基于“遥感”多技术融合在碳储量、碳排放、碳循环、温室气体等领域应用教程 一&#xff1a;双碳视角下遥感技术的研究方向 1.双碳背景及遥感的现实需求 2.全球碳库、碳收支及碳循环现状 3.碳储量、碳收支与碳循环中的遥感技术 4.ENVI及ArcG…

海龟绘图——n个正方形组成的图案

运行结果&#xff1a; 代码&#xff1a; import turtle# 创建海龟对象 nint(input()) t turtle.Turtle()# 设置海龟的颜色和线条粗细 t.color(blue) t.pensize(3)# 画四条直线lengths10 for j in range(n):for i in range(4):lengths20t.forward(lengths)# 旋转90度t.left(90)…