LuckyStar hctf2018
阅读原文时间:2023年07月09日阅读:1

LuckyStar hctf2018

程序注册有TLS回调函数

char __stdcall TlsCallback_0(int a1, int a2, int a3)
{
char result; // al
HMODULE v4; // eax
HMODULE v5; // eax
HMODULE v6; // eax
int (__usercall *ptr_main)@(int@); // esi
signed int v8; // edi
HANDLE v9; // eax

result = a2;
if ( a2 == 1 )
{
v4 = GetModuleHandleA("ntdll.dll");
dword_407378 = sub_401360(v4, "a7d7bcc95a86a6df3b0a1ccb3c69d440");//此处应该是获取库中的某个函数,我们动态调试的时候看一下
v5 = GetModuleHandleA("ntdll.dll");
dword_407380 = (int (__stdcall *)(_DWORD, _DWORD, _DWORD, _DWORD))sub_401360(v5, "8eb35a28209979fe6a9983cff0d23c5a");
v6 = GetModuleHandleA("kernel32.dll");
dword_407374 = sub_401360(v6, "05577e1568efa10b8166728bfb414c59");
srand(0x61616161u);//设置随机数的种子(影响后面main函数中的rand)
ptr_main = main_401780;//main函数,IDA载入发现已经加密,无法正常解析。
v8 = 440;
do
{
ptr_main = (int (__usercall *)@(int@))((char *)ptr_main + 1);
result = byte_417000[rand() % 8216];
*((_BYTE *)ptr_main - 1) ^= result;//对main进行异或解密
--v8;
}
while ( v8 );
}
else if ( a2 == 3 )
{
v9 = GetCurrentThread();
result = dword_407380(v9, 17, 0, 0);
}
return result;
}

我们动态调试,查看前面要用到库中的哪些函数,并且在main函数解密完成后dump文件,以备后面IDA分析。

发现前面获取的库函数与反调试相关。

重命名后的TLS

char __stdcall TlsCallback_0(int a1, int a2, int a3)
{
char result; // al
HMODULE v4; // eax
HMODULE v5; // eax
HMODULE v6; // eax
int (__usercall *ptr_main)@(int@); // esi
signed int v8; // edi
HANDLE v9; // eax

result = a2;
if ( a2 == 1 )
{
v4 = GetModuleHandleA("ntdll.dll");
NtQuerySystemInformation = sub_401360((int)v4, "a7d7bcc95a86a6df3b0a1ccb3c69d440");
v5 = GetModuleHandleA("ntdll.dll");
NtSetInformationThread = (int (__stdcall *)(_DWORD, _DWORD, _DWORD, _DWORD))sub_401360(
(int)v5,
"8eb35a28209979fe6a9983cff0d23c5a");
v6 = GetModuleHandleA("kernel32.dll");
*(_DWORD *)CheckRemoteDebuggerPresent = sub_401360((int)v6, "05577e1568efa10b8166728bfb414c59");
srand(0x61616161u);
ptr_main = main_401780;
v8 = 440;
do
{
ptr_main = (int (__usercall *)@(int@))((char *)ptr_main + 1);
result = byte_417000[rand() % 8216];
*((_BYTE *)ptr_main - 1) ^= result;
--v8;
}
while ( v8 );
}
else if ( a2 == 3 )
{
v9 = GetCurrentThread();
result = NtSetInformationThread(v9, 17, 0, 0);
}
return result;
}

IDA分析mian解密完成时dump的文件

int __usercall sub_401780@(int a1@, int a2@, int a3@)
{
signed int v3; // esi
int v4; // ST08_4
int v5; // ST0C_4
int v6; // ST10_4
int v7; // ST14_4
int v8; // ST18_4
int v9; // ST1C_4
int v10; // ST20_4
int v11; // ST24_4
int v12; // ST28_4
int v13; // ST2C_4
int v14; // ecx
const char *v15; // eax
int v17; // [esp-CCh] [ebp-D8h]
int v18; // [esp-C8h] [ebp-D4h]
int v19; // [esp-C4h] [ebp-D0h]
int v20; // [esp-C0h] [ebp-CCh]
int v21; // [esp-BCh] [ebp-C8h]
int v22; // [esp-B8h] [ebp-C4h]
int v23; // [esp-B4h] [ebp-C0h]
int v24; // [esp-B0h] [ebp-BCh]
int v25; // [esp-ACh] [ebp-B8h]
int v26; // [esp-A8h] [ebp-B4h]
int v27; // [esp-A4h] [ebp-B0h]
int v28; // [esp-A0h] [ebp-ACh]
int v29; // [esp-9Ch] [ebp-A8h]
int v30; // [esp-98h] [ebp-A4h]
int v31; // [esp-94h] [ebp-A0h]
int v32; // [esp-90h] [ebp-9Ch]
int v33; // [esp-8Ch] [ebp-98h]
int v34; // [esp-88h] [ebp-94h]
int v35; // [esp-84h] [ebp-90h]
int v36; // [esp-80h] [ebp-8Ch]
int v37; // [esp-7Ch] [ebp-88h]
int v38; // [esp-78h] [ebp-84h]
int v39; // [esp-74h] [ebp-80h]
int v40; // [esp-70h] [ebp-7Ch]
int v41; // [esp-6Ch] [ebp-78h]
int v42; // [esp-68h] [ebp-74h]
int v43; // [esp-64h] [ebp-70h]
int v44; // [esp-60h] [ebp-6Ch]
int v45; // [esp-5Ch] [ebp-68h]
int v46; // [esp-58h] [ebp-64h]
int v47; // [esp-54h] [ebp-60h]
int v48; // [esp-50h] [ebp-5Ch]
int v49; // [esp-4Ch] [ebp-58h]
int v50; // [esp-48h] [ebp-54h]
int v51; // [esp-44h] [ebp-50h]
int v52; // [esp-40h] [ebp-4Ch]
int v53; // [esp-3Ch] [ebp-48h]
int v54; // [esp-38h] [ebp-44h]
int v55; // [esp-34h] [ebp-40h]
__int128 v56; // [esp-30h] [ebp-3Ch]
__int64 v57; // [esp-20h] [ebp-2Ch]
int v58; // [esp-18h] [ebp-24h]
__int16 v59; // [esp-14h] [ebp-20h]
unsigned int v60; // [esp-4h] [ebp-10h]
int v61; // [esp+0h] [ebp-Ch]
int v62; // [esp+4h] [ebp-8h]
int retaddr; // [esp+Ch] [ebp+0h]

v61 = a1;
v62 = retaddr;
v60 = (unsigned int)&v61 ^ __security_cookie;
v17 = a3;
CreateThread(0, 0, StartAddress, 0, 0, 0); // 播放歌曲,
printf_401020("%s\n", (unsigned int)aMmmmmmmmmmmmmm);
while ( !song_final_sign_40737C )
{
Sleep(0x7D0u);
printf_401020(">");
}
printf_401020("\n");
v3 = 0;
do
*((_BYTE *)&loc_4015E0 + v3++) ^= byte_417000[rand() % 8216];// main中解密输入的加密处理函数
while ( v3 < 383 );
printf_401020("Shining!\n", a2, v17);
system("cls");
v58 = 0;
v56 = 0i64;
v57 = 0i64;
v59 = 0;
memset(&v38, 0, 0x46u);
printf_401020("My Darling Darling Please!\ninput your key!\n");
scanf_401050("%29s", &v56);
((void (__stdcall *)(__int128 *, int *, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, _DWORD))loc_4015E0)(
&v56,
&v38,
v4,
v5,
v6,
v7,
v8,
v9,
v10,
v11,
v12,
v13,
v18,
v19,
v20,
v21,
v22,
v23,
v24,
v25,
v26,
v27,
v28,
v29,
v30,
v31,
v32,
v33,
v34,
v35,
v36,
v37,
v38,
v39,
v40,
v41,
v42,
v43,
v44,
v45,
v46,
v47,
v48,
v49,
v50,
v51,
v52,
v53,
v54,
v55,
v56);
*(_OWORD *)&v20 = xmmword_403520; // 0DEF0A07232EEBC954C11473ABD57E649
*(_OWORD *)&v24 = xmmword_403530; // 5CCC8CA3C67C5A6A96E49835683F2AC
v36 = 0;
LOWORD(v37) = 0;
*(_OWORD *)&v28 = 0i64;
*(_OWORD *)&v32 = 0i64;
v14 = strcmp((const char *)&v38, (const char *)&v20);
if ( v14 )
v14 = -(v14 < 0) | 1;
v15 = "Maybe next year";
if ( !v14 )
v15 = "Nice Job~";
printf_401020(v15);
system("pause");
return 0;
}

发现main中对loc_4015E0函数进行了解密,后面用他来加密输入。动态调试,解密后dump

loc_4015E0函数

char __cdecl encode_4015E0(const char *myinput, const char *en_temp)
{
int v2; // esi
unsigned int size; // kr00_4
signed int v4; // edi
int v5; // ecx
const char *v6; // eax
int v7; // eax
char v8; // al
int v9; // ecx
int v10; // ecx
unsigned int v11; // ecx
int v12; // eax
char v13; // al
signed int v14; // edi
char result; // al
signed int v16; // esi
char v17; // al
char v18; // cl
signed int v19; // [esp+Ch] [ebp-8h]
signed int v20; // [esp+10h] [ebp-4h]

v2 = 0;
size = strlen(myinput);
v4 = 0;
v20 = 4 * size / 3;
if ( v20 > 0 )
{
do
{
v5 = v4 & 3;
if ( v4 & 3 )
{
v8 = myinput[v2 - 1];
if ( v5 == 1 )
{
v9 = myinput[v2++];
v7 = (v9 >> 4) | 16 * (v8 & 3);
}
else if ( v5 == 2 )
{
v10 = myinput[v2++];
v7 = (v10 >> 6) | 4 * (v8 & 0xF);
}
else
{
v7 = v8 & 0x3F;
}
}
else
{
v6 = &myinput[v2++];
v7 = *v6 >> 2;
}
en_temp[v4++] = base64_table_4033C8[v7]; // abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/
}                          
while ( v4 < v20 ); } if ( strlen(myinput) % 3 == 1 ) { v11 = 4 * size / 3; v12 = 16 * (myinput[v2 - 1] & 3); *(_WORD *)&en_temp[v20 + 1] = '=='; v13 = base64_table_4033C8[v12]; //魔改base64,编码表将大写字母与小写字母替换了位置。 } else { if ( strlen(myinput) % 3 != 2 ) goto LABEL_15; v11 = 4 * size / 3; v13 = base64_table_4033C8[4 * (myinput[v2 - 1] & 0xF)]; en_temp[v20 + 1] = 61; } en_temp[v11] = v13; LABEL_15: en_temp[strlen(en_temp)] = 0; v14 = 0; v19 = strlen(en_temp); if ( v19 > 0 )
{
do
{
v16 = 6;
do
{
v17 = rand() % 4;
v18 = v16;
v16 -= 2;
result = v17 << v18; en_temp[v14] ^= result; // 获取伪随机序列,输入进行魔改base64编码后与伪随机序列进行了异或操作。 } while ( v16 > -2 );
++v14;
}
while ( v14 < v19 );
}
return result;
}

最终main函数

int __usercall sub_401780@(int a1@)
{
signed int v1; // esi
int v2; // ecx
const char *v3; // eax
__int128 tg; // [esp-C0h] [ebp-CCh]
__int128 v6; // [esp-B0h] [ebp-BCh]
__int128 v7; // [esp-A0h] [ebp-ACh]
__int128 v8; // [esp-90h] [ebp-9Ch]
int v9; // [esp-80h] [ebp-8Ch]
__int16 v10; // [esp-7Ch] [ebp-88h]
int temp_str; // [esp-78h] [ebp-84h]
__int128 myinput; // [esp-30h] [ebp-3Ch]
__int64 v13; // [esp-20h] [ebp-2Ch]
int v14; // [esp-18h] [ebp-24h]
__int16 v15; // [esp-14h] [ebp-20h]
unsigned int v16; // [esp-4h] [ebp-10h]
int v17; // [esp+0h] [ebp-Ch]
int v18; // [esp+4h] [ebp-8h]
int retaddr; // [esp+Ch] [ebp+0h]

v17 = a1;
v18 = retaddr;
v16 = (unsigned int)&v17 ^ __security_cookie;
printf_401020("%s\n", aMmmmmmmmmmmmmm);
printf_401020("\n");
v1 = 0;
do
*((_BYTE *)encode_4015E0 + v1++) ^= byte_417000[rand() % 8216];
while ( v1 < 383 );
printf_401020("Shining!\n");
system("cls");
v14 = 0;
myinput = 0i64;
v13 = 0i64;
v15 = 0;
memset(&temp_str, 0, 0x46u);
printf_401020("My Darling Darling Please!\ninput your key!\n");
scanf_401050("%29s", &myinput);
encode_4015E0((const char *)&myinput, (const char *)&temp_str);// 魔改base64编码 +异或伪随机序列
tg = xmmword_403520; // 0DEF0A07232EEBC954C11473ABD57E649
v6 = xmmword_403530; // 5CCC8CA3C67C5A6A96E49835683F2AC
v9 = 0;
v10 = 0;
v7 = 0i64;
v8 = 0i64;
v2 = strcmp((const char *)&temp_str, (const char *)&tg);// {
// 0x49, 0xE6, 0x57, 0xBD, 0x3A, 0x47, 0x11, 0x4C, 0x95, 0xBC, 0xEE, 0x32, 0x72, 0xA0, 0xF0, 0xDE,
// 0xAC, 0xF2, 0x83, 0x56, 0x83, 0x49, 0x6E, 0xA9, 0xA6, 0xC5, 0x67, 0x3C, 0xCA, 0xC8, 0xCC, 0x05
// };
if ( v2 )
v2 = -(v2 < 0) | 1;
v3 = "Maybe next year";
if ( !v2 )
v3 = "Nice Job~";
printf_401020(v3);
system("pause");
return nullsub_2((unsigned int)&v17 ^ v16);
}

魔改base64与标准base64编码只存在字母大小写的不同,好解决,关键在于后面与伪随机序列的获取。

方案1、动态调试,在base64编码后,进行异或操作时,编写脚本,将每一位异或数据记录下来。

方案2、先获取魔改base64编码后的结果,然后在函数结束后获得异或加密结果,将二者进行异或,便可得到得到伪随机序列

程序最后将输入的加密结果进行比较,动态调试时dump比较数据。

wp:

import base64
tg=[0x49, 0xE6, 0x57, 0xBD, 0x3A, 0x47, 0x11, 0x4C, 0x95, 0xBC, 0xEE, 0x32, 0x72, 0xA0, 0xF0, 0xDE,
0xAC, 0xF2, 0x83, 0x56, 0x83, 0x49, 0x6E, 0xA9, 0xA6, 0xC5, 0x67, 0x3C, 0xCA, 0xC8, 0xCC, 0x05]
order=[0x08,0x81,0x39,0x8d,0x40,0x09,0x42,0x14,0xd0,0xf2,0x98,0x66,0x33,0xd6,0xc9,0xb2,0xc1,0x95,0xb6,0x1e,0xc7,0x2d,0x1c,0xef,0xd2,0xb2,0x5f,0x66,0x8c,0xb9,0xf1,0x38,0x14,0x08,0x8f,0xce,0xe9,0x7f,0x0d,0x05,]

b64=''
for i in range(len(tg)):
b64+=chr(order[i]^tg[i])
print(b64)
t=''
for c in b64:
n=ord(c)
if n>=ord('A') and n<=ord('Z'): t+=chr(n|0x20) elif n>=ord('a') and n<=ord('z'):
t+=chr(n&0xdf)
else:
t+=c
print(t)
flag=base64.b64decode(t.encode()).decode()
print(flag)

hctf{1zumi_K0nat4_Mo3}

攻防世界里提交失败 0.0 Orz