int __cdecl main(int argc, const char **argv, const char **envp)
{
int v3; // ecx
int *v4; // eax
int v5; // ecx
int *v6; // eax
char *v7; // esi
int v8; // edi
unsigned int v9; // kr00_4
void **v10; // ecx
__int128 *v11; // ecx
int *v12; // ecx
char *input_crypto2; // edx
unsigned int v14; // edi
int v15; // eax
int v16; // eax
bool v17; // cf
unsigned __int8 v18; // al
unsigned __int8 v19; // al
unsigned __int8 v20; // al
const char *v21; // edx
int *v22; // eax
char *v23; // eax
int v25; // [esp-14h] [ebp-D8h]
int v26; // [esp-10h] [ebp-D4h]
void *input[4]; // [esp+24h] [ebp-A0h] BYREF
int input_lenth; // [esp+34h] [ebp-90h]
unsigned int v29; // [esp+38h] [ebp-8Ch]
char v30[32]; // [esp+3Ch] [ebp-88h] BYREF
int v31; // [esp+5Ch] [ebp-68h]
__int128 input_; // [esp+60h] [ebp-64h] BYREF
__int128 v33; // [esp+70h] [ebp-54h]
int v34; // [esp+80h] [ebp-44h]
char str[16]; // [esp+84h] [ebp-40h] BYREF
int test[8]; // [esp+94h] [ebp-30h] BYREF
int v37; // [esp+C0h] [ebp-4h]
input_lenth = 0;
v29 = 0xF;
LOBYTE(input[0]) = 0;
v37 = 1;
v4 = printf(v3, "Please input your flag: ");
sub_403050((int)v4);
scanf(&dword_430068, input);
strcpy(str, "SWPU_2019_CTF");
if ( input_lenth == 0x20 )
{
test[4] = 0xBA143D17;
test[5] = 0x1D730350;
test[6] = 0x9404607A;
test[7] = 0x290AF070;
v8 = 0;
input_ = 0i64;
v34 = 0;
v33 = 0i64;
v9 = strlen(str);
do // 对input进行加密
{
v10 = input;
if ( v29 >= 0x10 )
v10 = (void **)input[0];
*((_BYTE *)v10 + v8) ^= str[v8 % v9];
++v8;
}
while ( v8 < 0x20 );
v11 = (__int128 *)input; // 这里可以推出input加密后的数据
v7 = (char *)input[0];
if ( v29 >= 0x10 )
v11 = (__int128 *)input[0];
v31 = 0;
memset(v30, 0, sizeof(v30));
input_ = *v11;
v33 = v11[1];
sub_4025C0(v25, v26, 0x100, (char *)&input_, (unsigned int)v30);
test[0] = 0xF80F37B3;
test[1] = 0x5DAEBCBC;
v12 = test;
test[2] = 0x864D5ABA;
input_crypto2 = v30;
test[3] = 0xD3629744;
v14 = 0x1C;
test[4] = 0x1624BA4F;
test[5] = 0x1A729F0B;
test[6] = 0x266D6865;
test[7] = 0x67C86BBA;
while ( 1 )
{
v15 = *v12;
if ( *v12 != *(_DWORD *)input_crypto2 )
break;
++v12;
input_crypto2 += 4;
v17 = v14 < 4;
v14 -= 4;
if ( v17 )
{
v16 = 0;
goto LABEL_19;
}
}
v17 = (unsigned __int8)v15 < (unsigned __int8)*input_crypto2;
if ( (_BYTE)v15 == *input_crypto2
&& (v18 = *((_BYTE *)v12 + 1), v17 = v18 < (unsigned __int8)input_crypto2[1], v18 == input_crypto2[1])
&& (v19 = *((_BYTE *)v12 + 2), v17 = v19 < (unsigned __int8)input_crypto2[2], v19 == input_crypto2[2])
&& (v20 = *((_BYTE *)v12 + 3), v17 = v20 < (unsigned __int8)input_crypto2[3], v20 == input_crypto2[3]) )
{
v16 = 0;
}
else
{
v16 = v17 ? 0xFFFFFFFF : 1;
}
LABEL_19:
if ( v16 )
v21 = "Try again!\r\n";
else
v21 = "Congratulations! I always knew you could do it.";
v22 = printf((int)v12, v21);
sub_403050((int)v22);
system((int)"pause");
}
else
{
v6 = printf(v5, "Try again!\r\n");
sub_403050((int)v6);
system((int)"pause");
v7 = (char *)input[0];
}
if ( v29 >= 0x10 )
{
v23 = v7;
if ( v29 + 1 >= 0x1000 )
{
v7 = (char *)*((_DWORD *)v7 + 0xFFFFFFFF);
if ( (unsigned int)(v23 - v7 - 4) > 0x1F )
_invalid_parameter_noinfo_noreturn();
}
sub_4064DE(v7);
}
return 0;
}
总体下来有两个异或加密,第一个异或加密是
do // 对input进行加密
{
v10 = input;
if ( v29 >= 0x10 )
v10 = (void **)input[0];
*((_BYTE *)v10 + v8) ^= str[v8 % v9];
++v8;
}
while ( v8 < 0x20 );
这个就是逐字节异或,没啥好说的
下来就是一个函数
sub_4025C0(v25, v26, 0x100, (char *)&input_, (unsigned int)v30);
不得不说,如果仅是靠IDA去纯肉眼看,那必然是非常消耗时间的,这个函数的作用是,将input作为参数输入,然后输出v30
但是我们点进去函数细看:
void __cdecl sub_4025C0(int a1, int a2, int a3, char *input, unsigned int a5)
{
int v5; // ecx
unsigned int v6; // ebx
int v7; // esi
unsigned int v8; // edi
unsigned int v9; // esi
unsigned int v10; // edx
char *v11; // esi
char *v12; // ecx
char *v13; // eax
int v14; // ebx
int v15; // esi
__m128i v16; // xmm0
__m128i v17; // xmm1
__m128i v18; // xmm0
__m128i v19; // xmm1
__m128i v20; // xmm0
__m128i v21; // xmm1
__m128i v22; // xmm0
__m128i v23; // xmm1
int v24; // ebx
char *v25; // eax
int v26; // esi
unsigned int v27; // edi
int v28; // ecx
signed int v29; // [esp+20h] [ebp-20h]
int v30; // [esp+24h] [ebp-1Ch]
char *Block; // [esp+28h] [ebp-18h]
int v32[4]; // [esp+2Ch] [ebp-14h] BYREF
v6 = a5;
v7 = v5;
v8 = (unsigned int)(a3 + 0x1F) >> 5;
v30 = 4 * v8;
Block = (char *)malloc(4 * v8);
v32[0] = 0x92540366;
v32[1] = 0x78;
v32[2] = 0x92540366;
v32[3] = 0x78;
sub_402270(v7, v32);
sub_4020E0();
sub_402150();
sub_401F80();
v29 = 0;
if ( v8 )
{
do
{
dword_430D94 = (2 * dword_430DA4) ^ (unsigned __int16)(dword_430DBC ^ (2 * dword_430DA4));
dword_430D78 = (dword_430DB8 << 0x10) | ((unsigned int)dword_430DAC >> 0xF);
v9 = (dword_430D70 << 0x10) | ((unsigned int)dword_430D90 >> 0xF);
dword_430D8C = (dword_430D68 << 0x10) | ((unsigned int)dword_430D84 >> 0xF);
dword_430D7C = v9;
*(_DWORD *)&Block[4 * v29] = v9 ^ sub_402150();
sub_401F80();
++v29;
}
while ( v29 < (int)v8 );
v6 = a5;
}
v10 = 0;
if ( v8 )
{
v11 = input;
if ( v8 < 0x10 || v6 <= (unsigned int)&input[v30 - 4] && v6 + v30 - 4 >= (unsigned int)input )
{
v12 = Block;
}
else
{
v12 = Block;
if ( v6 > (unsigned int)&Block[4 * v8 - 4] || v6 + v30 - 4 < (unsigned int)Block )
{
v13 = input + 0x10;
v12 = Block;
v14 = v6 + 0x20;
v15 = Block - input;
do
{
v16 = *((__m128i *)v13 + 0xFFFFFFFF);
v13 += 0x40;
v14 += 0x40;
v17 = _mm_xor_si128(*(__m128i *)&Block[4 * v10], v16);
v18 = *((__m128i *)v13 + 0xFFFFFFFC);
*(__m128i *)(v14 - 0x60) = v17;
v19 = _mm_xor_si128(*(__m128i *)&v13[v15 - 0x40], v18);
v20 = *((__m128i *)v13 + 0xFFFFFFFD);
*(__m128i *)&v13[a5 - (_DWORD)input - 0x40] = v19;
v15 = Block - input;
v21 = _mm_xor_si128(*(__m128i *)&Block[v14 - a5 - 0x40], v20);
v22 = *((__m128i *)v13 + 0xFFFFFFFE);
*(__m128i *)(v14 - 0x40) = v21;
v23 = *(__m128i *)&Block[4 * v10 + 0x30];
v10 += 0x10;
*(__m128i *)(v14 - 0x30) = _mm_xor_si128(v23, v22);
}
while ( v10 < (v8 & 0xFFFFFFF0) );
v6 = a5;
v11 = input;
}
}
if ( v10 < v8 )
{
v24 = v6 - (_DWORD)input;
v25 = &v11[4 * v10];
v26 = v12 - input;
v27 = v8 - v10;
do
{
v28 = *(_DWORD *)&v25[v26];
v25 += 4;
*(_DWORD *)&v25[v24 - 4] = *((_DWORD *)v25 + 0xFFFFFFFF) ^ v28;
--v27;
}
while ( v27 );
}
}
free(Block);
}
就是让人眼乱,里面还参杂着一些函数,鬼知道会不会给你来一个对v30的值的改变
这时候我们不一定要用IDA,可以用x32dbg下硬件写入断点帮我们看看具体是咋整的
参数从右到左push进去,因此v30变量的地址就是 [ebp - 0x88],于是乎我们在这个地址下硬件写入断点
然后运行跑起来:
然后发现断在这个地方,这是一个循环,调试后很容易发现,是将input与一个固定值进行异或加密
或者说看汇编难受,可以转到IDA看
就是单纯的一个异或操作
下面是解题脚本:
#include <iostream>
#include <windows.h>
using namespace std;
unsigned char m_data[32] = {
};
char str[20] = "SWPU_2019_CTF";
unsigned int m_data3[8] = {
0xF80F37B3, 0x5DAEBCBC, 0x864D5ABA, 0xD3629744, 0x1624BA4F, 0x1A729F0B, 0x266D6865, 0x67C86BBA
};
unsigned int m_data2[8] = {
0xCA3E0C86, 0x19AED798, 0xA66B77E2, 0xB077A16A, 0x05379169, 0x307BF97A, 0x104B5A43, 0x28D47D86
};
unsigned int m_data4[8] = {};
char flag[32] = {};
int main()
{
for (int i = 0; i < 8; i++)
{
m_data4[i] = m_data3[i] ^ m_data2[i];
}
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 4; j++)
{
m_data[4 * i + j] = m_data4[i] & 0xff;
m_data4[i] = m_data4[i] >>8;
}
}
for (int i = 0; i < 0x20; i++)
{
flag[i] = m_data[i] ^ str[i % 13];
}
cout << flag << endl;
}