[Reverse]2022弱口令安全招新赛 tea

题目下载地址:tea

数据处理

数据处理分析

做这道题的时候是第一次深入接触tea加密,tea加密后的数据按理来说都应该是32位的大数,而我在查找数据的时候犯了一个很严重的错误:
file
将图中的数据分开来去tea解密,显然这是错误的。
我们不难发现在tea算法中我们需要有一个delta值如图v4所示file我们发现其中的delta值是8位的16进制也就是32位的数据,那么我们就需要手动将str2里面的数据进行还原为8位数据

小端序处理

在我处理这段数据的时候,我又犯了一个很严重的错误(直接按照顺序合并),程序是小端序储存的,所以我们需要反过来合并,例如
0xAA 0xBB 0xCC 0xDD
我们合并成32位数据就是
0xDDCCBBAA
这就是小端序储存
当然我们可以手动一个个将程序还原,显然太麻烦了,我选择使用算法,算法关键代码如下:

int kk[32] =
{
  46,162,154,93,216,119,117,77,224,124,80,69,114,165,248,93,109,14,98,20,102,95,216,91,138,93,196,200,116,32,253,101
};
	unsigned int F[8]={0};
	for(int i = 0 ; i < 32 ; i+=4 )
	{
		unsigned int wei = 0x1000000;
		for(int j = 3 ; j >= 0 ; j -- )
		{
			F[cd]+=kk[i+j]*wei;
			wei/=0x100;
		}
		cd++;
	}

处理过后F数组内储存的值就是我们按照小端序规则还原后的密文了。

tea算法

tea算法简介

TEA算法使用64位的明文分组和128位的密钥,它使用Feistel分组加密框架,需要进行 64 轮迭代,尽管作者认为 32 轮已经足够了。该算法使用了一个神秘常数δ作为倍数,它来源于黄金比率,以保证每一轮加密都不相同。但δ的精确值似乎并不重要,这里 TEA 把它定义为 δ=「(√5 - 1)231」(也就是程序中的 0×9E3779B9)

tea算法加密脚本

#include <stdio.h>
#include <stdint.h>
//加密函数
void encrypt(uint32_t* v, uint32_t* k)
{  
    uint32_t v0=v[0], v1=v[1], sum=0, i;           /* set up */  
    uint32_t delta=0x9e3779b9;                     /* a key schedule constant */  
    uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3];   /* cache key */  
    for (i=0; i < 32; i++)
	{                       /* basic cycle start */
        sum += delta;
        v0 += ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
        v1 += ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
    }                                              /* end cycle */
    v[0]=v0; v[1]=v1;
}

int main()  
{  
    uint32_t v[2]={1,2},k[4]={2,2,3,4};
    // v为要加密的数据是两个32位无符号整数
    // k为加密解密密钥,为4个32位无符号整数,即密钥长度为128位
    printf("加密前原始数据:%u %u\n",v[0],v[1]);
    encrypt(v, k);
    printf("加密后的数据:%u %u\n",v[0],v[1]);
    return 0;
}

tea算法解密脚本

显然异或具有可逆性,我们只需要将加密脚本反过来写,就可以得到解密脚本

void decrypt(uint32_t* v, uint32_t* k)
{
    uint32_t v0=v[0], v1=v[1], sum=0xC6EF3720, i;  /* set up */
	//sum的值为delta的值乘以加密的组数,作者推荐加密32次,这里也是32次,则我们就是乘以32
    uint32_t delta=0x9e3779b9;                     /* a key schedule constant */
    uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3];   /* cache key */
    for (i=0; i<32; i++)
	{                           /* basic cycle start */  
        v1 -= ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
		//v1与v0顺序互换+=改为-=然后逐次递减sum
        v0 -= ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
        sum -= delta;
    }                                             /* end cycle */
    v[0]=v0; v[1]=v1;
} 

正经题解:

file
看到主函数的关键函数段,输入的v9赋值给了Destination数组然后对Destination数组两两一组进行加密,显然由于程序将我们输入的字符储存为了32位数据,每位数据占用了4个字节,所以对应的Destination就是我们输入的前四个字符,和后四个字符,因此我们解密的后序需要将它再次分开。
进入::k可以看到file
1,2,3,4便是我们的密钥
然后我们进入encrypt函数:
file
解密脚本如何构造在上文的tea分析中已经提及
我的解密思想如下:

void decrypt(unsigned int *a1,int *a2)
{
//	char *result; // rax
	int i; // [rsp+10h] [rbp-10h]
	unsigned int v4;
	v4=0xa6768e00;// [rsp+14h] [rbp-Ch]
	unsigned int v5; // [rsp+18h] [rbp-8h]
	unsigned int v6; // [rsp+1Ch] [rbp-4h]
	
	v6 = *a1;
	v5 = a1[1];
	for ( i = 0; i <= 31; ++i )
	{
		v5 -= (v6 + v4) ^ (a2[2] + 16 * v6) ^ ((v6 >> 5) + a2[3]);
		v6 -= (v5 + v4) ^ (a2[0] + 16 * v5) ^ ((v5 >> 5) + a2[1]);
		v4 -= 0xD33B470;	
	}
	*a1 = v6;
	a1[1] = v5;
}

接下来就可以构造我们的解题代码了,str2的处理方式在上文小端序的介绍中已经提及
这里要注意的就是
我们在解密完成后会获得8组32位的大数,我们需要将它们按照小端序的规则分开再进行格式化字符串输出,我的输出思想如下:

	for(int i = 0 ; i < 8 ; i ++ )
	{
		unsigned temp = flag[i];//flag[i]为tea解密后留下的8组32位大数据
		for(int j = 0 ; j < 4 ; j++ )
		{
			int tmp = temp%0x100;
			temp/=0x100;
			printf("%c",tmp);
		}
	}

最后就可以直接构造脚本了

EXP

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<map>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<string>
#include<cstring>
#include<list>
#include<stdlib.h>
#include<windows.h>
using namespace std;
typedef int status;
typedef int selemtype;

int kk[32] =
{
  46,162,154,93,216,119,117,77,224,124,80,69,114,165,248,93,109,14,98,20,102,95,216,91,138,93,196,200,116,32,253,101
};
int a2[4]={1, 2, 3, 4};
void decrypt(unsigned int *a1,int *a2)
{
//	char *result; // rax
	int i; // [rsp+10h] [rbp-10h]
	unsigned int v4;
	v4=0xa6768e00;// [rsp+14h] [rbp-Ch]
	unsigned int v5; // [rsp+18h] [rbp-8h]
	unsigned int v6; // [rsp+1Ch] [rbp-4h]
	
	v6 = *a1;
	v5 = a1[1];
	for ( i = 0; i <= 31; ++i )
	{
		v5 -= (v6 + v4) ^ (a2[2] + 16 * v6) ^ ((v6 >> 5) + a2[3]);
		v6 -= (v5 + v4) ^ (a2[0] + 16 * v5) ^ ((v5 >> 5) + a2[1]);
		v4 -= 0xD33B470;	
	}
	*a1 = v6;
	a1[1] = v5;
}
int main()
{
	unsigned int flag[8],F[8]={0};
	int cd = 0;
	for(int i = 0 ; i < 32 ; i ++ )
	{
		printf("%X ",kk[i]);
	}
	cout<<endl;
	for(int i = 0 ; i < 32 ; i+=4 )
	{
		unsigned int wei = 0x1000000;
		for(int j = 3 ; j >= 0 ; j -- )
		{
			F[cd]+=kk[i+j]*wei;
			wei/=0x100;
		}
		cd++;
	}
	for(int i = 0 ; i < 8 ; i ++ )
	{
		printf("0x%X",F[i]);
		if(i!=7)	cout<<",";
	}
		
	cout<<endl;
	for(int i = 0 ; i<  8 ; i +=2 )
	{
		unsigned int tmp[2];
		tmp[0]=F[i];
		tmp[1]=F[i+1];
		decrypt(tmp,a2);
		flag[i]=tmp[0];
		flag[i+1]=tmp[1];
	}
	cout<<endl;
	for(int i = 0 ; i < 8 ; i ++ )
	{
		unsigned temp = flag[i];
		for(int j = 0 ; j < 4 ; j++ )
		{
			int tmp = temp%0x100;
			temp/=0x100;
			printf("%c",tmp);
		}
	}
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值