-
-
[原创]KCTF 2025 第3题 邪影显现wp
-
发表于: 2025-8-26 06:54 6172
-
放入ida分析主要验证函数, 函数开始就看到几个常数与"KCTF2025"字样, 搜索常数得知是md5:
结合KCTF2025md5_name与md5_name变量的位置看出是拼接出KCTF2025md5(name).
之后的逻辑比较长,调用了很多函数;
先从中间随便点进几个看看在做什么, 找到了一个比较有特征的函数:

在github上搜索MIRACL error from routine 找到了 548K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6E0K9i4u0S2j5$3I4Q4x3V1k6y4d9g2u0m8b7@1H3`.
对照发现该函数为MIRACL/source/mrcore.c中的mr_berror:
该库中的函数大量引用了mr_mip, 用ida File->Load File->Parse C header file加载库中定义了miracl结构的miracl.h来还原mr_mip的符号, 之后发现结构体成员位置不太对, 还需要对比添加一个padding:

MIRACL库中很多函数在入口处使用了MR_IN(x)x为唯一的数字, 长这样:

主要特征是MR_IN(x)对应mr_mip->trace[mr_mip->depth]=x, 于是在反编译代码中看到该特征对应搜索MR_IN(x)就能找到这是什么函数, 之后分析出验证函数中用了MIRACL库的部分流程如下:

做了一个指数为23的指数模逆.
验证函数之后又调用了许多其他未知的函数, 深入点进去找到了又一个特征点:
github上搜索"Integer: division by zero"找到了cryptopp. 这个库中的函数没有上一个库那么有特征, 但是根据其中调用了cpuid的一个函数能够找到DetectX86Features再找到SetFunctionPointers, 对比能够特定其中一些全局变量:
之后根据该信息可以找到RecursiveSquare:
然后可以找到调用了RecursiveSquare的AsymmetricMultiply, 调用了AsymmetricMultiply的PositiveMultiply, 验证函数中使用的一个调用了PositiveMultiply的函数就是Multiply.
类似的从DivideByZero可以链式找到PositiveDivide, Integer::Divide, 以及验证函数中使用的Integer::Modulo函数, 分析出接下来它用cryptopp做了一个29的指数模逆.
之后其他的很多函数还是未知的, 点进去几个看看又找到了个新库libntl:
带着模逆运算的心理预期能够对比找到验证函数中调用的是ntl_gmul与ntl_gmod和InvMod, 确认中间一段做了个37的指数模逆.
之后别的函数又是新的大数库, 在基本确认都在用某个库做指数模逆计算时,可以通过观察找到乘法函数与取模函数的输入输出,结合变量传递关系就可以找出某一段运算的指数, 分析出指数分别为[3,7,11,17,19,23,29,31,37];
对验证函数做逆运算即已知e与n计算x^e mod n的x, 是RSA算法;
从验证函数中找出模数n0x56f67550f16a00390dcf0b2715708e61c5b3f23101862fc1用factordb分解出p与q,计算d=invmod(e, (p-1)(q-1))
即可完成序列号的计算, 注意每轮之后最高位还需要-1:
...v184 = 0;memset(tmp_final, 0, sizeof(tmp_final));memset(reverse_gcd, 0, sizeof(reverse_gcd));a2[0] = 0x5075F656;a2[1] = 0x39006AF1;a2[2] = 0x270BCF0D;a2[3] = 0x618E7015;a2[4] = 0x31F2B3C5;a2[5] = 0xC12F8601;memset(&md5_name, 0, 0xF8u);qmemcpy(KCTF2025md5_name, "KCTF2025", sizeof(KCTF2025md5_name));v258 = 0;*(_QWORD *)&v257.oword4C = 0xEFCDAB8967452301uLL;*((_QWORD *)&v257.oword4C + 1) = 0x1032547698BADCFELL;memset(&v257, 0, 12);sub_41E530(&v257, name, strlen(name));sub_41E660(&v257, &md5_name); // md5(name)......v184 = 0;memset(tmp_final, 0, sizeof(tmp_final));memset(reverse_gcd, 0, sizeof(reverse_gcd));a2[0] = 0x5075F656;a2[1] = 0x39006AF1;a2[2] = 0x270BCF0D;a2[3] = 0x618E7015;a2[4] = 0x31F2B3C5;a2[5] = 0xC12F8601;memset(&md5_name, 0, 0xF8u);qmemcpy(KCTF2025md5_name, "KCTF2025", sizeof(KCTF2025md5_name));v258 = 0;*(_QWORD *)&v257.oword4C = 0xEFCDAB8967452301uLL;*((_QWORD *)&v257.oword4C + 1) = 0x1032547698BADCFELL;memset(&v257, 0, 12);sub_41E530(&v257, name, strlen(name));sub_41E660(&v257, &md5_name); // md5(name)...void mr_berror(_MIPD_ int nerr){ /* Big number error routine */#ifndef MR_STRIPPED_DOWNint i;#endif#ifdef MR_OS_THREADS miracl *mr_mip=get_mip();#endifif (mr_mip->ERCON){ mr_mip->ERNUM=nerr; return;}#ifndef MR_NO_STANDARD_IO#ifndef MR_STRIPPED_DOWNmputs((char *)"\nMIRACL error from routine ");if (mr_mip->depth<MR_MAXDEPTH) mputs(names[mr_mip->trace[mr_mip->depth]]);else mputs((char *)"???");fputc('\n',stdout);for (i=mr_mip->depth-1;i>=0;i--){ mputs((char *)" called from "); if (i<MR_MAXDEPTH) mputs(names[mr_mip->trace[i]]); else mputs((char *)"???"); fputc('\n',stdout);}switch (nerr){case 1 :mputs((char *)"Number base too big for representation\n");break;case 2 :mputs((char *)"Division by zero attempted\n");break;case 3 : mputs((char *)"Overflow - Number too big\n");...void mr_berror(_MIPD_ int nerr){ /* Big number error routine */#ifndef MR_STRIPPED_DOWNint i;#endif#ifdef MR_OS_THREADS miracl *mr_mip=get_mip();#endifif (mr_mip->ERCON){ mr_mip->ERNUM=nerr; return;}#ifndef MR_NO_STANDARD_IO#ifndef MR_STRIPPED_DOWNmputs((char *)"\nMIRACL error from routine ");if (mr_mip->depth<MR_MAXDEPTH) mputs(names[mr_mip->trace[mr_mip->depth]]);else mputs((char *)"???");fputc('\n',stdout);for (i=mr_mip->depth-1;i>=0;i--){ mputs((char *)" called from "); if (i<MR_MAXDEPTH) mputs(names[mr_mip->trace[i]]); else mputs((char *)"???"); fputc('\n',stdout);}switch (nerr){case 1 :mputs((char *)"Number base too big for representation\n");break;case 2 :mputs((char *)"Division by zero attempted\n");break;case 3 : mputs((char *)"Overflow - Number too big\n");...char *__thiscall DivideByZero_407530(char *this){ void *v2; // ecx void *Block[5]; // [esp+10h] [ebp-28h] BYREF unsigned int v5; // [esp+24h] [ebp-14h] int v6; // [esp+34h] [ebp-4h] Block[4] = 0; v5 = 15; LOBYTE(Block[0]) = 0; sub_416C40(Block, "Integer: division by zero", 0x19u); v6 = 0; *(_QWORD *)(this + 4) = 0LL; LOBYTE(v6) = 1; *(_DWORD *)this = &off_45BC60; *((_DWORD *)this + 3) = 6; sub_416DC0(Block); if ( v5 >= 0x10 ) { v2 = Block[0]; if ( v5 + 1 >= 0x1000 ) { v2 = (void *)*((_DWORD *)Block[0] - 1); if ( (unsigned int)((char *)Block[0] - (char *)v2 - 4) > 0x1F ) invalid_parameter_noinfo_noreturn(); } sub_455F72(v2); } *(_DWORD *)this = &off_45BC60; return this;}char *__thiscall DivideByZero_407530(char *this){ void *v2; // ecx void *Block[5]; // [esp+10h] [ebp-28h] BYREF unsigned int v5; // [esp+24h] [ebp-14h] int v6; // [esp+34h] [ebp-4h] Block[4] = 0; v5 = 15; LOBYTE(Block[0]) = 0; sub_416C40(Block, "Integer: division by zero", 0x19u); v6 = 0; *(_QWORD *)(this + 4) = 0LL; LOBYTE(v6) = 1; *(_DWORD *)this = &off_45BC60; *((_DWORD *)this + 3) = 6; sub_416DC0(Block); if ( v5 >= 0x10 ) { v2 = Block[0]; if ( v5 + 1 >= 0x1000 ) { v2 = (void *)*((_DWORD *)Block[0] - 1); if ( (unsigned int)((char *)Block[0] - (char *)v2 - 4) > 0x1F ) invalid_parameter_noinfo_noreturn(); } sub_455F72(v2); } *(_DWORD *)this = &off_45BC60; return this;}void *__thiscall SetFunctionPointers(void *this){ char v2; // al void *result; // eax if ( dword_464A74 ) return this; v2 = g_x86DetectionDone; s_pMul[0] = (int)Baseline_Multiply2; s_pBot0 = (int)Baseline_MultiplyBottom2; s_pSqu0 = (int)Baseline_Square2; s_pTop0 = (int)Baseline_MultiplyTop2; s_pTop1 = (int)Baseline_MultiplyTop4; if ( !g_x86DetectionDone ) { DetectX86Features(); v2 = g_x86DetectionDone; } if ( !byte_464A71 ) { dword_4652A8 = (int)sub_408040; dword_4652AC = (int)sub_4081D0; dword_4652CC = (int)sub_408FF0; dword_4652D0 = (int)sub_4090B0; dword_4652F0 = (int)sub_408850; dword_4652F4 = (int)sub_408A10; dword_465318 = (int)sub_409520; dword_464A74 = (int)sub_407C20; return this; } if ( !v2 ) DetectX86Features(); if ( g_isP4 ) { s_pAdd = SSE2_Add; s_pSub = SSE2_Sub; } result = this; s_recursionLimit = 32;...}void *__thiscall SetFunctionPointers(void *this){ char v2; // al void *result; // eax if ( dword_464A74 ) return this; v2 = g_x86DetectionDone; s_pMul[0] = (int)Baseline_Multiply2; s_pBot0 = (int)Baseline_MultiplyBottom2; s_pSqu0 = (int)Baseline_Square2; s_pTop0 = (int)Baseline_MultiplyTop2; s_pTop1 = (int)Baseline_MultiplyTop4; if ( !g_x86DetectionDone ) { DetectX86Features(); v2 = g_x86DetectionDone; } if ( !byte_464A71 ) { dword_4652A8 = (int)sub_408040; dword_4652AC = (int)sub_4081D0; dword_4652CC = (int)sub_408FF0; dword_4652D0 = (int)sub_4090B0; dword_4652F0 = (int)sub_408850; dword_4652F4 = (int)sub_408A10; dword_465318 = (int)sub_409520; dword_464A74 = (int)sub_407C20; return this;