新手一枚,如有错误(不足)请指正,谢谢!!
<mark>个人博客:点击进入</mark>
题目的git仓库链接:点击进入
题目分析
IDA载入,shift+F12查看字符串,根据字符串找到关键代码
上面IDA自动给生成的Str的长度为4,下面验证str的长度为22,于是我们手动更改Str的类型为char Str[23],就能正常显示
题目为tea,用IDA的Findcrypt插件查找一下,果然是tea系列的加密算法
分析出a1为加密数,a2为长度,a3为加密的密钥
先返回之前的主函数继续分析。
然后分析一下sub_4017DC函数
其中sub_40192B函数
然后下面就是xxtea的函数了,其中sub_401410函数是输出字符串,与flag没太大关系
其中sub_4019DA将v11用作加密,v12当作密钥,长度为2
a2=2 >1 执行的是xxtea解密函数
之后将加密后的数据与 在栈上存储的数据与100+下标异或后的数据 进行比对,若相等则成功。
梳理一下程序流程:
用户输入长度要等于22
前五位要为flag{,最后一位要为}
然后判断{}内的字符是否都在“ace_yunTh5”内
之后对{}中的字符进行移位,然后将每两位字符转换为一位字符
之后进行xxtea解密
再与栈上的存储的数据与100+j异或后的数据相比对,如果都匹配上则成功。
编写脚本
先算出加密后的八位字符。
#include <stdio.h>
#include <stdint.h>
#define tea_DELTA 0x9e3779b9
#define xxtea_MX (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z)))
void xxtea(uint32_t* origin, int n, uint32_t const key[4]);
int main()
{
unsigned char data[] = { 0x1F,0xF2,0x6E,0x94,0xAF,0x91,0xCD,0x58 };
int i, j;
for (i = 0; i < 8; i++)
{
data[i] ^= 100 + i;
}
uint32_t* encode = (uint32_t *)data;
uint32_t const key[4] = { (unsigned int)0x67616c66,(unsigned int)0x0,(unsigned int)0x0,(unsigned int)0x0 };
//key的值为将flag转换为小端序,并且其后用0填充
xxtea(encode, 2, key);
for (i = 0; i < 8; i++)
printf("%d,", data[i]);
}
void xxtea(uint32_t* origin, 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 = origin[n - 1];
do
{
sum += tea_DELTA;
e = (sum >> 2) & 3;
for (p = 0; p < n - 1; p++)
{
y = origin[p + 1];
z = origin[p] += xxtea_MX;
}
y = origin[0];
z = origin[n - 1] += xxtea_MX;
} while (--rounds);
}
else if (n < -1) /* Decoding Part */
{
n = -n;
rounds = 6 + 52 / n;
sum = rounds * tea_DELTA;
y = origin[0];
do
{
e = (sum >> 2) & 3;
for (p = n - 1; p > 0; p--)
{
z = origin[p - 1];
y = origin[p] -= xxtea_MX;
}
z = origin[n - 1];
y = origin[0] -= xxtea_MX;
sum -= tea_DELTA;
} while (--rounds);
}
}
由于二位字符表示一位字符的过程不可逆,因为我们知道两个字符的范围都是0~9,所以采用爆破法。
另外交换位置那部分可以采用IDA伪代码简单变换,因为正向逆向加密是没区别的,正向再交换一次就交换回来了。
#include <stdio.h>
#include <string.h>
void sub_4018CA(char* str);
int main()
{
unsigned char str1[] = { 18,95,63,30,94,20,20,37 };
char str0[] = "ace_yunTh5";
char str2[17] = { 0 };
int i, j, k;
for (i = 0; i < 8; i++)
{
for (j = 0; j < 10; j++)
{
for (k = 0; k < 10; k++)
{
if (j * 10 + k == str1[i])
{
str2[2 * i] = str0[j];
str2[2 * i + 1] = str0[k];
}
}
}
}
sub_4018CA(str2);
sub_4018CA(str2 + 1);
puts(str2);
return 0;
}
void sub_4018CA(char* str)
{
int i;
char k;
for (i = 0; i < strlen(str); i += 4)
{
k = str[i];
str[i] = str[i + 2];
str[i + 2] = k;
}
}
这样就得到{}内部的字符串,最后包上flag{}
即最终的flag为flag{5uch_an_ea5y_Tea}