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