re1
拿到程序以後拖進IDA裏shift+F12看一下:
雙擊跟進去,查看一下交叉引用,F5轉一下僞代碼就出來了:
flag爲:flag{Sign_fDfkl_CTF}}
re2與re3
目前網上仍沒有公佈WP,當時參賽選手都沒解出來...
re4
拖IDA看一下,發現是ELF文件:
看一下main()函數的僞代碼:
這是main()函數的僞代碼:
int __cdecl main(int argc, const char **argv, const char **envp)
{
signed int i; // [esp+20h] [ebp-28h]
char s[17]; // [esp+2Bh] [ebp-1Dh]
unsigned int v6; // [esp+3Ch] [ebp-Ch]
v6 = __readgsdword(0x14u);
memcpy(&password, "IKAWTEQWJHQTVRCF", 0x10u); //初始化password
memset(s, 0, 0x11u);
printf("Enter the password: ");
__isoc99_scanf("%16s", s); //獲取鍵盤輸入的16個字符
for ( i = 0; i <= 15; ++i ) //將字符串放入循環
s[i] = complex_function(s[i], 18 - i); //這裏是重點,將字符串存到s這個數組裏,並調用complex_function()這個函數進行處理,然後在返回到s裏。
if ( check_equals_IKAWTEQWJHQTVRCF(s, 16) ) //這裏調用check_equals_IKAWTEQWJHQTVRCF()函數對處理後的password進行最多16次判斷
puts("Good Job."); //若結果爲真則輸出Good job.
else
puts("Try again."); //若結果爲假則輸出Try again.
return 0;
}
我們在看一下它對我們輸入的password進行了怎樣的處理,也就是看一下complex_function()函數:
簡單分析一下:
int __cdecl complex_function(signed int a1, int a2)
{
if ( a1 <= 64 || a1 > 90 ) //password對應的十進制只能在64~90之間
{
puts("Try again."); //若超出64~90則輸出Try again.
exit(1); //運行到這裏直接結束當前進程
}
return (a1 - 65 + 29 * a2) % 26 + 65; //如果語句沒有執行,那麼passwd經過處理後返回
}
接着我們分析它調用check_equals_IKAWTEQWJHQTVRCF()進行的判斷:
分析一下僞代碼,這裏a1就是經過處理後的password,a2是16:
_BOOL4 __cdecl check_equals_IKAWTEQWJHQTVRCF(int a1, unsigned int a2)
{
int v3; // [esp+8h] [ebp-8h]
unsigned int i; // [esp+Ch] [ebp-4h]
v3 = 0; //定義一個局部變量v3用來存值
for ( i = 0; a2 > i; ++i ) //開始循環,每次循環結束i進行自加,最多循環16次
{
if ( *(_BYTE *)(i + a1) == *(_BYTE *)(i + 0x804C038) ) //這裏是對原password跟處理後的password進行對比,如果相等就執行下面的語句,如果不相等就直接跳出去
++v3; //相等後進行自加
}
return v3 == a2;
}
/**
這裏return v3 == a2的作用我感覺就是把結果轉成0或1,
然後存到eax裏,進行判斷後選擇跳或者不跳,如果程序成功執行了16次,
也就是v3 == a2成立,那麼結果就是0,反之爲1
**/
這是check_equals_IKAWTEQWJHQTVRCF()函數執行後的流程圖,這裏如果jnz判斷不成立,也就是eax爲0,那麼就輸出"Good job.“反之輸出"Try again.”,跟我們分析的一樣:
分析到這裏我們就有解題思路了,有兩種解題方法:
- 從complex_function()函數下手,直接爆破一下加密後的password。
- 從check_equals_IKAWTEQWJHQTVRCF()函數下手,破解程序。
這裏還是爆破比較方便,也比較簡單:
passwd = 'IKAWTEQWJHQTVRCF' #定義原passwd
flag = '' #定義flag用來存值
for i in range(len(passwd)): #返回passwd的長度,也就是16
for a1 in range(64,91): #把64~90依次傳給a1
if (a1 - 65 + (18-i)*29)%26 + 65 == ord(passwd[i]): #如果經過計算後a1的十進制結果如果等於原passwd的十進制結果
flag += chr(a1) #那麼將結果依次轉爲對應的ASCII碼賦值給flag
print('flag{%s}'%(flag)) #輸出flag
成功拿到flag:flag{GLEDDRGPFGSYDCQW}
re5
這題我看流程圖感覺是將輸入的內容進行異或,然後將異或的結果進行判斷,若結果爲真則結束進程,若爲假則輸出“err…"並結束進程:
這是它main()函數的僞代碼
這裏的關鍵就是在sub_400606()這個函數,它的僞代碼非常複雜,很多個循環語句嵌套,水平實在是不夠,分析不了,如果有大牛能分析或者感興趣,私信我一起學習一下!
上一下sub_400606()函數的僞代碼:
__int64 __fastcall sub_400606(signed int *a1)
{
signed __int64 v1; // rax
__int64 result; // rax
int v3; // [rsp+10h] [rbp-10h]
__int16 v4; // [rsp+14h] [rbp-Ch]
*a1 = 0;
do
{
while ( 1 )
{
while ( 1 )
{
while ( 1 )
{
while ( 1 )
{
while ( 1 )
{
while ( 1 )
{
do
{
v1 = *((_QWORD *)a1 + 1) + 6LL * *a1;
v3 = *(_DWORD *)v1;
v4 = *(_WORD *)(v1 + 4);
++*a1;
}
while ( BYTE1(v3) && BYTE1(v3) != a1[1] );
result = (unsigned __int8)v3;
if ( (unsigned __int8)v3 != 7 )
break;
*a1 = *(signed __int16 *)(2LL * SHIWORD(v3) + *((_QWORD *)a1 + 2));
}
if ( (signed int)result > 7 )
break;
if ( (_DWORD)result == 3 )
{
if ( *(_WORD *)(2LL * SHIWORD(v3) + *((_QWORD *)a1 + 2)) == *(_WORD *)(2LL * v4 + *((_QWORD *)a1 + 2)) )
a1[1] = 1;
else
a1[1] = 2;
}
else if ( (signed int)result > 3 )
{
if ( (_DWORD)result == 5 )
{
*(_WORD *)(*((_QWORD *)a1 + 2) + 2LL * SHIWORD(v3)) = *(_WORD *)(2LL * v4 + *((_QWORD *)a1 + 2));
}
else if ( (signed int)result > 5 )
{
*(_WORD *)(*((_QWORD *)a1 + 2) + 2LL * SHIWORD(v3)) = *a1;
}
else
{
*a1 += SHIWORD(v3);
}
}
else if ( (_DWORD)result == 1 )
{
*(_WORD *)(*((_QWORD *)a1 + 2) + 2LL * SHIWORD(v3)) = *(_WORD *)(2LL * SHIWORD(v3) + *((_QWORD *)a1 + 2))
+ *(_WORD *)(2LL * v4 + *((_QWORD *)a1 + 2));
}
else if ( (_DWORD)result == 2 )
{
*(_WORD *)(*((_QWORD *)a1 + 2) + 2LL * SHIWORD(v3)) = *(_WORD *)(2LL * SHIWORD(v3) + *((_QWORD *)a1 + 2))
- *(_WORD *)(2LL * v4 + *((_QWORD *)a1 + 2));
}
}
if ( (_DWORD)result != 10 )
break;
*(_WORD *)(*((_QWORD *)a1 + 2) + 2LL * SHIWORD(v3)) = *((_WORD *)a1
+ *(signed __int16 *)(2LL * v4 + *((_QWORD *)a1 + 2))
+ 8LL
+ 4);
}
if ( (signed int)result > 10 )
break;
if ( (_DWORD)result == 8 )
{
*(_WORD *)(*((_QWORD *)a1 + 2) + 2LL * SHIWORD(v3)) = v4;
}
else if ( (_DWORD)result == 9 )
{
puts("err..");
}
}
if ( (_DWORD)result != 12 )
break;
*(_WORD *)(*((_QWORD *)a1 + 2) + 2LL * SHIWORD(v3)) = *(_WORD *)(2LL * SHIWORD(v3) + *((_QWORD *)a1 + 2)) ^ *(_WORD *)(2LL * v4 + *((_QWORD *)a1 + 2));
}
if ( (signed int)result >= 12 )
break;
*(_WORD *)(*((_QWORD *)a1 + 2) + 2LL * SHIWORD(v3)) = *((_WORD *)a1
+ *(signed __int16 *)(2LL * v4 + *((_QWORD *)a1 + 2))
+ 32LL);
}
}
while ( (_DWORD)result != 255 );
return result;
}
這道題目前網上沒有什麼分析,只有一個解題腳本,也是通過異或試出來的:
a=[0x003C, 0x0030, 0x003F, 0x0007, 0x0019, 0x0012, 0x0000, 0x001E, 0x0018, 0x001A, 0x001A, 0x0042, 0x0046, 0x0010, 0x0010, 0x0010, 0x0014, 0x001F, 0x000C, 0x00FD]
x=90
for i in a:
print(chr(i^x),end='')
x+=2
運行後成功獲得flag:flag{vfvrvt24dfhncr}