题目下载地址:tea
数据处理
数据处理分析
做这道题的时候是第一次深入接触tea加密,tea加密后的数据按理来说都应该是32位的大数,而我在查找数据的时候犯了一个很严重的错误:
将图中的数据分开来去tea解密,显然这是错误的。
我们不难发现在tea算法中我们需要有一个delta值如图v4所示我们发现其中的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;
}
正经题解:
看到主函数的关键函数段,输入的v9赋值给了Destination数组然后对Destination数组两两一组进行加密,显然由于程序将我们输入的字符储存为了32位数据,每位数据占用了4个字节,所以对应的Destination就是我们输入的前四个字符,和后四个字符,因此我们解密的后序需要将它再次分开。
进入::k可以看到
1,2,3,4便是我们的密钥
然后我们进入encrypt函数:
解密脚本如何构造在上文的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);
}
}
}