这题用到的知识点很多,我们先一步步分析。
放到exeinfo和peid里面发现是32位无壳程序。
ida32打开。
首先看主函数:
int __cdecl main(int argc, const char **argv, const char **envp)
{
HMODULE v3; // eax
int v4; // eax
_DWORD *v5; // eax
unsigned int v6; // edx
_DWORD *v7; // ecx
unsigned int v8; // ebx
char *v9; // edi
unsigned int v10; // esi
unsigned int v11; // esi
bool v12; // cf
unsigned __int8 v13; // al
unsigned __int8 v14; // al
unsigned __int8 v15; // al
int v16; // esi
void *v17; // ecx
void *v18; // ecx
const char *v19; // edx
int v20; // eax
void *Block[5]; // [esp+10h] [ebp-70h] BYREF
unsigned int v23; // [esp+24h] [ebp-5Ch]
void *v24[5]; // [esp+28h] [ebp-58h] BYREF
unsigned int v25; // [esp+3Ch] [ebp-44h]
char Src[48]; // [esp+40h] [ebp-40h] BYREF
int v27; // [esp+7Ch] [ebp-4h]
v3 = GetModuleHandleW(0);
sub_402320(v3); //对.SCTF段数据SMC成可执行代码
sub_4024A0(); //调用SMC后的代码
v4 = sub_402870(std::cout, "welcome to 2019 sctf");
std::ostream::operator<<(v4, sub_402AC0);
sub_402870(std::cout, "please input your ticket:");
sub_402AF0(std::cin, Src);
v24[4] = 0;
v25 = 15;
LOBYTE(v24[0]) = 0;
sub_401D30(v24, Src, strlen(Src));
v27 = 0;
v5 = sub_4020D0(Block, v24); // aes加密算法,CBC模式,密码为sycloversyclover,偏移量为sctfsctfsctfsctf。
v6 = strlen(aPvfqyc4ttc2uxr); // 获取字符串长度
v7 = v5;
if ( v5[5] >= 0x10u )
v7 = *v5;
v8 = v5[4];
v9 = aPvfqyc4ttc2uxr;
v10 = v8;
if ( v6 < v8 )
v10 = v6;
v12 = v10 < 4;
v11 = v10 - 4;
if ( v12 )
{
LABEL_8:
if ( v11 == -4 )
goto LABEL_17;
}
else
{
while ( *v7 == *v9 ) // 加密后的字符串与字符串aPvfqyc4ttc2uxr作比较
{
++v7; // v7是双字,v9是char型,v7自增1读取,v9就自增4
v9 += 4;
v12 = v11 < 4;
v11 -= 4;
if ( v12 )
goto LABEL_8;
}
}
v12 = *v7 < *v9; // v12==0
if ( *v7 != *v9
|| v11 != -3
&& ((v13 = *(v7 + 1), v12 = v13 < v9[1], v13 != v9[1])
|| v11 != -2
&& ((v14 = *(v7 + 2), v12 = v14 < v9[2], v14 != v9[2])
|| v11 != -1 && (v15 = *(v7 + 3), v12 = v15 < v9[3], v15 != v9[3]))) )// *v7==*v9 。且v11==-3或者
// if里的条件不能为1
{
v16 = v12 ? -1 : 1;
goto LABEL_18;
}
LABEL_17:
v16 = 0;
LABEL_18:
if ( !v16 )
{
if ( v6 <= v8 )
v16 = v6 < v8; // v6==v8
else
v16 = -1;
}
if ( v23 >= 0x10 )
{
v17 = Block[0];
if ( v23 + 1 >= 0x1000 )
{
v17 = *(Block[0] - 1);
if ( (Block[0] - v17 - 4) > 0x1F )
invalid_parameter_noinfo_noreturn();
}
sub_402F05(v17);
}
v27 = -1;
Block[4] = 0;
v23 = 15;
LOBYTE(Block[0]) = 0;
if ( v25 >= 0x10 )
{
v18 = v24[0];
if ( v25 + 1 >= 0x1000 )
{
v18 = *(v24[0] - 1);
if ( (v24[0] - v18 - 4) > 0x1F )
invalid_parameter_noinfo_noreturn();
}
sub_402F05(v18);
}
v19 = "Have fun!";
if ( v16 ) // v16==0
v19 = "A forged ticket!!";
v20 = sub_402870(std::cout, v19);
std::ostream::operator<<(v20, sub_402AC0);
system("pause");
return 0;
}
首先看sub_402320和sub_4024A0这两个函数,
首先我们注意到byte_404000是数据,但却在return后面作为函数运行,我们可以猜测是这里是smc。
对于sub_402320,我们结合汇编代码可以发现在DebugBreak函数和return之间有一段代码引用。
参考一些博主的wp我了解到sub_402320这个函数原来是通过调试器附加的方式来SMC修改。
程序运行过程中,该函数搜索到.SCTF区段后执行loc_4023EF代码,并在loc_4023EF中进行SMC。
要想运行那段代码需要结合OD。我们直接OD打开,因为有反调试,所以我们修改EIP为402421跳过反调试函数,然后运行loc_4023EF部分的代码,如下:
我们还可以进一步判断是402450函数进行SMC操作,单步步过修改数据为代码后,
接下来走出sub_402320这个函数,进入sub_4024A0函数,这个函数有两个跳转语句,一个跳到int 3中断,一个是exit函数,同样是反调试,修改EIP。
修改EIP后先不急着走出,我们可以进入smc后的404000函数,如下:
我们看寄存器窗口可以发现,这个smc后的函数一直在对字符串>pvfqYc,4tTc2UxRmlJ,sB{Fh4Ck2:CFOb4ErhtIcoLo操作,这个字符串其实是我们后面加密过后待比较的字符串,直接运行出看这个函数对该字符串进行了怎样的处理。
我们发现这个字符串变成了nKnbHsgqD3aNEB91jB3gEzAr+IklQwT1bSs3+bXpeuo=
接下来就可以分析加密函数sub_4020D0和sub_401690了,
int __thiscall sub_401690(int this, int a2, int a3, int a4, int a5)
{
int v5; // ebx
int v6; // eax
int v7; // eax
BOOL v8; // eax
int v9; // ecx
int v10; // esi
int v11; // eax
int v12; // ecx
char *v13; // edx
int v14; // edx
char *v15; // esi
const char *v16; // esi
int v17; // kr04_4
int *v18; // edx
int result; // eax
int v20; // edi
int v21; // ebx
int v22; // eax
int v23; // edx
int v24; // ecx
int v25; // esi
int v26; // edi
int v27; // eax
int v28; // eax
int v29; // et2
int v30; // ecx
int v31; // edx
char *v32; // eax
int v33; // ecx
int v34; // ecx
int v35; // edx
int v36; // eax
int v37; // eax
int v38; // edx
int v39; // ecx
int v40; // edx
int v41; // ecx
int v42; // eax
_DWORD *v43; // ecx
__int64 v44; // rax
__int64 v45; // rt2
int v46; // ecx
int *v47; // edx
int *v48; // esi
int v49; // edi
int v50; // edx
int v52; // [esp+Ch] [ebp-18h]
int v53; // [esp+Ch] [ebp-18h]
int v54; // [esp+10h] [ebp-14h]
int *v55; // [esp+10h] [ebp-14h]
int *v56; // [esp+14h] [ebp-10h]
_DWORD *v57; // [esp+14h] [ebp-10h]
int *v58; // [esp+18h] [ebp-Ch]
char *v59; // [esp+18h] [ebp-Ch]
int v60; // [esp+1Ch] [ebp-8h]
int v61; // [esp+20h] [ebp-4h]
v5 = this;
*(this + 972) = 16;
*(this + 968) = 16;
*(this + 980) = xmmword_407360;
memcpy((this + 1012), &xmmword_407360, *(this + 972));
v6 = *(v5 + 968);
if ( v6 == 16 )
{
v9 = *(v5 + 972);
if ( v9 == 16 )
{
v7 = 10;
goto LABEL_9;
}
v8 = v9 != 24;
}
else
{
if ( v6 != 24 )
{
v7 = 14;
goto LABEL_9;
}
v8 = *(v5 + 972) == 32;
}
v7 = 2 * v8 + 12;
LABEL_9:
*(v5 + 976) = v7;
v10 = 0;
v11 = *(v5 + 976);
v12 = *(v5 + 972) / 4;
v61 = v12;
if ( v11 >= 0 )
{
v13 = (v5 + 8);
do
{
if ( v12 > 0 )
{
memset(v13, 0, 4 * v12);
v12 = v61;
}
v11 = *(v5 + 976);
++v10;
v13 += 32;
}
while ( v10 <= v11 );
}
v14 = 0;
if ( v11 >= 0 )
{
v15 = (v5 + 488);
do
{
if ( v12 > 0 )
{
memset(v15, 0, 4 * v12);
v12 = v61;
}
v11 = *(v5 + 976);
++v14;
v15 += 32;
}
while ( v14 <= v11 );
}
v16 = "sycloversyclover";
v60 = v12 * (v11 + 1);
v17 = *(v5 + 968);
v18 = (v5 + 1044);
result = v17 / 4;
v20 = v5 + 1044;
v54 = v17 / 4;
v56 = (v5 + 1044);
if ( v17 / 4 > 0 )
{
v21 = v17 / 4;
do
{
v22 = *v16;
v16 += 4;
v22 <<= 24;
v20 += 4;
*(v20 - 4) = v22;
v23 = v22 | (*(v16 - 3) << 16);
*(v20 - 4) = v23;
v24 = v23 | (*(v16 - 2) << 8);
*(v20 - 4) = v24;
result = v24 | *(v16 - 1);
*(v20 - 4) = result;
--v21;
}
while ( v21 );
v5 = this;
v12 = v61;
v18 = v56;
}
v25 = v17 / 4;
v26 = 0;
if ( v54 > 0 )
{
v58 = v18;
do
{
if ( v26 >= v60 )
goto LABEL_44;
v27 = v26++;
v29 = v27 % v12;
v28 = v27 / v12;
*(v5 + 4 * (v29 + 8 * v28) + 8) = *v58;
v25 = v17 / 4;
v30 = v29 + 8 * (*(v5 + 976) - v28);
result = *v58;
*(v5 + 4 * v30 + 488) = *v58;
v12 = v61;
++v58;
}
while ( v26 < v54 );
}
if ( v26 < v60 )
{
v59 = &unk_406B40;
do
{
v31 = *(v5 + 4 * v25 + 1040);
v32 = v59++;
v33 = RijnDael_AES_LONG_405DE0[HIBYTE(v31)] ^ ((RijnDael_AES_LONG_405DE0[v31] ^ ((RijnDael_AES_LONG_405DE0[BYTE1(v31)] ^ ((*v32 ^ RijnDael_AES_LONG_405DE0[BYTE2(v31)]) << 8)) << 8)) << 8);
result = v5 + 1044;
*(v5 + 1044) ^= v33;
if ( v25 == 8 )
{
v37 = v5 + 1048;
v38 = 3;
do
{
v39 = *(v37 - 4);
v37 += 4;
*(v37 - 4) ^= v39;
--v38;
}
while ( v38 );
v40 = 3;
*(v5 + 1060) ^= RijnDael_AES_LONG_405DE0[*(v5 + 1056)] ^ ((RijnDael_AES_LONG_405DE0[BYTE1(*(v5 + 1056))] ^ ((RijnDael_AES_LONG_405DE0[BYTE2(*(v5 + 1056))] ^ (RijnDael_AES_LONG_405DE0[HIBYTE(*(v5 + 1056))] << 8)) << 8)) << 8);
v41 = v5 + 1064;
do
{
v42 = *(v41 - 4);
v41 += 4;
*(v41 - 4) ^= v42;
--v40;
}
while ( v40 );
}
else
{
if ( v25 <= 1 )
goto LABEL_39;
v34 = v5 + 1048;
v35 = v25 - 1;
do
{
v36 = *(v34 - 4);
v34 += 4;
*(v34 - 4) ^= v36;
--v35;
}
while ( v35 );
}
result = v5 + 1044;
LABEL_39:
v52 = 0;
if ( v25 > 0 )
{
v43 = result;
v57 = result;
while ( v26 < v60 )
{
v44 = v26++;
v45 = v44 % v61;
LODWORD(v44) = v44 / v61;
*(v5 + 4 * (v45 + 8 * v44) + 8) = *v43;
v25 = v17 / 4;
*(v5 + 4 * (v45 + 8 * (*(v5 + 976) - v44)) + 488) = *v57;
result = v52 + 1;
v43 = v57 + 1;
v52 = result;
++v57;
if ( result >= v54 )
goto LABEL_43;
}
break;
}
LABEL_43:
;
}
while ( v26 < v60 );
}
LABEL_44:
v46 = 1;
v53 = 1;
if ( *(v5 + 976) <= 1 )
{
*(v5 + 4) = 1;
}
else
{
result = v61;
v47 = (v5 + 520);
v55 = (v5 + 520);
do
{
if ( result > 0 )
{
v48 = v47;
v49 = result;
do
{
v50 = *v48++;
*(v48 - 1) = dword_406B60[v50] ^ dword_4066E0[BYTE1(v50)] ^ dword_405EE0[BYTE2(v50)] ^ dword_406F60[HIBYTE(v50)];
--v49;
}
while ( v49 );
result = v61;
v46 = v53;
v47 = v55;
}
++v46;
v47 += 8;
v53 = v46;
v55 = v47;
}
while ( v46 < *(v5 + 976) );
*(v5 + 4) = 1;
}
return result;
}
我们不难看出是aes加密算法,CBC模式,密码为sycloversyclover,偏移量为sctfsctfsctfsctf,
在线解密得flag
flag{Ae3_C8c_I28_pKcs79ad4}