-
-
[原创]看雪 2025·KCTF 签到题 废材少年觉醒 by 心学
-
发表于: 2025-8-17 21:26 142
-
工具:IDA
一、观察程序运行结果
C:\Users\surface>C:\Users\surface\OneDrive\Crack\CTF\Kanxue\Kanxue2025KCTF\01\A_Case\kctf2025_checkin\checkin.exe Welcome to KCTF 2025! 请输入签到口令: KCTF123456789 签到失败! C:\Users\surface>
程序为 64bit exe。
二、IDA初步分析及尝试调试
主要运行顺序:
start()->sub_7FF61B9A1010()->sub_7FF61B9A1AF0()->sub_7FF61B9C4DA0()->sub_7FF61B9A1450()->sub_7FF61B9A1620()
最后一个才是序列号判断逻辑所在。
再进一步是:sub_7FF61B9A1560(),该函数是序列号的逐位判断,可直接看到正确的序列号(不在数据内存里,而是蕴含在代码的操作数里)。
主要代码(调用关键函数之前)摘选:
__int64 start()
{
unk_7FF61BA7A220 = 0;
return sub_7FF61B9A1010();
}
__int64 sub_7FF61B9A1010()
{
....
result = sub_7FF61B9A1AF0(); // 控制台程序输出信息
....
}
__int64 __fastcall sub_7FF61B9A1AF0()
{
void *v1[3]; // [rsp+28h] [rbp-8h] BYREF
sub_7FF61BA3E7E0();
v1[0] = sub_7FF61B9A1620; // 关键函数
return sub_7FF61B9C4DA0((__int64)v1, (__int64)&unk_7FF61BA41000);// 第一个v1是执行程序地址,第二个是调用某个程序的桩。
}
//下面是继续跟踪执行,兜兜转转,最终会执行 v1 函数,即 sub_7FF61B9A1620
__int64 __fastcall sub_7FF61B9C4DA0(__int64 a1, __int64 a2)
{
....
result = (*(int (__fastcall **)(__int64))(a2 + 0x28))(a1);// 调用该函数:sub_7FF61B9A1450,最终就是调用 a1= sub_7FF61B9A1620
....
//该处伪码有问题,需要调试跟踪或查看汇编代码来获取 esi 的值的变化。
//调用的第二个参数存储在 rdx 中,rdx = 7FF61BA41000
//.text:00007FF61B9C4DAD mov rsi, rdx
//.text:00007FF61B9C4E0F call qword ptr [rsi+28h]
//而 7FF61BA41000+28=7FF61BA41028,该处存放的内容是:50 14 9A 1B F6 7F 00 00,即 7FF61B9A1450。
}
//此时的函数参数为 sub_7FF61B9A1620
__int64 __fastcall sub_7FF659C91450(_QWORD *a1)
{
sub_7FF61B9A1470(*a1);
return 0i64;
}
//此时的函数参数为 sub_7FF61B9A1620
__int64 __fastcall sub_7FF659C91470(__int64 (*a1)(void))
{
return a1();//执行 sub_7FF61B9A1620
}主要代码(关键函数)摘选
__int64 __fastcall sub_7FF61B9A1620()
{
v22 = &off_7FF61BA410A0;//Welcome to KCTF 2025!
....
sub_7FF61B9D1F30((__int64)&v22); // 输出 Welcome to KCTF 2025!
....
v22 = &off_7FF61BA410C8;//// 请输入签到口令:
sub_7FF61B9D1F30((__int64)&v22);// 输出 请输入签到口令:
....
if ( (sub_7FF61B9CE3A0(v29, (__int64)&v26) & 1) != 0 )// 获取用户输入
....
v2 = (char *)lpMem + v28; // 获取的就是用户输入值,下面开始验证
....
if ( sub_7FF61B9A1560((_BYTE *)lpMem + (_QWORD)v7, v3 - v7) )// 此处判断是否等于正确的序列号
{
v29[0] = (volatile signed __int8 *)v30;
v29[1] = (volatile signed __int8 *)sub_7FF61B9A1480;
v22 = (void **)&off_7FF61BA41140; // aFlag db '签到成功!FLAG: ',0Ah,0
v23 = 2i64;
v24 = (__int64)v29;
v25 = 1ui64;
}
else
{
v22 = (void **)&off_7FF61BA41118; // asc_7FF659D31108 db '签到失败!',0Ah
v23 = 1i64;
v24 = 8i64;
v25 = 0i64;
}
result = sub_7FF61B9D1F30((__int64)&v22);
if ( v26 )
return sub_7FF61B9A1B50(lpMem); // lpMem 为 用户输入字符串的指针
return result;
}主要代码(序列号所在处)
bool __fastcall sub_7FF659C91560(_BYTE *a1, __int64 a2)
{
return a2 == 0x19
&& *a1 == 'f'
&& a1[1] == 'l'
&& a1[2] == 'a'
&& a1[3] == 'g'
&& a1[4] == '{'
&& a1[5] == 'k'
&& a1[6] == 'c'
&& a1[7] == 't'
&& a1[8] == 'f'
&& a1[9] == '_'
&& a1[10] == 't'
&& a1[11] == 'i'
&& a1[12] == 'm'
&& a1[13] == 'e'
&& a1[14] == '_'
&& a1[15] == 'l'
&& a1[16] == 'e'
&& a1[17] == 'a'
&& a1[18] == 'p'
&& a1[19] == '_'
&& a1[20] == '2'
&& a1[21] == '0'
&& a1[22] == '2'
&& a1[23] == '5'
&& a1[24] == '}';
}三、序列号
手动拼接:
SN = flag{kctf_time_leap_2025}
赞赏
他的文章
赞赏
雪币:
留言: