re學習筆記(45)[ACTF2020]tea

新手一枚,如有錯誤(不足)請指正,謝謝!!
個人博客:點擊進入
題目的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}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章