main生成个固定seed,之后进入sub_402D47做check,run时发现不会进入branch,先忽略。
接着读输入Key,进入func_proc1,完成后与加密flag做xor,最后进入func_proc2。
一共做666次Chanllenges,全部正确即可拿到flag。
Proc_1:
可以明显看出是个解smc,调用,再复原smc的过程。
设计到有个0x120大小的数据结构
![QQ截图20180914125757.png-45.5kB][1]
一共Check33个函数,意味着就33个这样的结构体。
我们可以手动跑一下得到解smc的函数。
使用脚本:
可以拿到复原后的33个函数。
不难发现,这33个函数分为了7个种类:
于是,我们可以手动解一下(1/666)的Key
这样,Proc1分析完成。
那么现在就有这样的问题:
1/666的check与n/666的Check的不同。
猜测:
难度依次递增。
Proc2:
黑箱测试:Proc2的作用是重写33个数据结构,并且会在进下一轮Proc1之前,将改动写回文件当中。
当完成(1/666)的Proc1,我们就拿到了Proc2的bin,再用脚本还原,可以发现:
函数虽然smc的地址改变了,但函数类型不变,都在这7种。
那么我们就必要硬逆Proc2的算法了。
让我们梳理下执行逻辑:
1.生成seed为proc_2更新做准备
2.输入key 共666轮
3.Proc_1 Check
4.解密flag 共666轮
5.Proc_2 更新文件(本地写)
6.loop到[2], 直到666轮完成,输出解密flag
那么我们可以在proc_2更新之前,复制出来一份。这一份的我们可以用来手动解smc从而得到33个函数,而不影响正常的proc_2过程。
就算得到了33个函数,那如何实现自动化生成key呢?根据Proc_2的结果我们知道33个函数均在7种类型内,这样就可以通过某一地址上的值两两不同去识别。比如:
以上是以0x30为起点的4字节值,可以注意到0x32地址上值两两不同,即可用于识别函数。
这样,Crack思路就很清晰了:
1.手动解smc,识别33个函数属于的种类
2.根据种类,执行对应的解密算法
3.使用pwntools完成recv和send的自动化。
完整的Crack脚本:
最后,因为Flare-on5直到Oct.5才结束,所以以上的脚本都被我轻微的改动了一下。
本人仅仅提供一点点思路,还请各位Cracker斧正。
更新了附件, password: infected
![QQ截图20180914131835.png-1.1kB][2]
signed __int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
unsigned __int64 v3; // rax
unsigned __int64 len; // rax
__int64 *v6; // [rsp+0h] [rbp-1E0h]
unsigned int seed; // [rsp+1Ch] [rbp-1C4h]
unsigned int i; // [rsp+20h] [rbp-1C0h]
unsigned int j; // [rsp+20h] [rbp-1C0h]
unsigned int k; // [rsp+24h] [rbp-1BCh]
char input_s[128]; // [rsp+40h] [rbp-1A0h]
char a3a; // [rsp+C0h] [rbp-120h]
char arr_1[72]; // [rsp+140h] [rbp-A0h]
char v14; // [rsp+188h] [rbp-58h]
unsigned __int64 v15; // [rsp+1C8h] [rbp-18h]
v15 = __readfsqword(0x28u);
seed = 0;
memset(input_s, 0, sizeof(input_s));
memset(&a3a, 0, 0x80uLL);
*arr_1 = 0x45123A7920755C24LL;
*&arr_1[8] = 0x17263719711D201ELL;
*&arr_1[16] = 0x4A7C67303E100367LL;
*&arr_1[24] = 0x11621308555E1B11LL;
*&arr_1[32] = 0x122C17445A7C6C68LL;
*&arr_1[40] = 0x576D0C6324095979LL;
*&arr_1[48] = 0x265D0F6A0C27651FLL;
*&arr_1[56] = 0xA375C1433594643LL;
*&arr_1[64] = 0x2C16022663LL;
memset(&v14, 0, 0x38uLL);
for ( i = 0; i < strlen("Run, Forrest, run!!"); i += 4 )
seed ^= *&aRunForrestRun[i];
srand(seed);
if ( sub_402D47() )
{
v3 = strlen(a2[1]);
func_proc1(a2[1], v3, &a3a);
func_proc2(*a2);
puts("Generated first permutation!");
exit(0);
}
puts("Welcome to the ever changing magic mushroom!");
printf("%d trials lie ahead of you!\n", 666LL, a2);
for ( j = 0; j < 666; ++j )
{
printf("Challenge %d/%d. Enter key: ", j + 1, 666LL);
if ( !fgets(input_s, 128, unk_617630) )
return 0xFFFFFFFFLL;
len = strlen(input_s);
func_proc1(input_s, len, &a3a);
for ( k = 0; k < strlen(input_s); ++k )
arr_1[k] ^= input_s[k];
func_proc2(*v6);
}
printf("Congrats! Here is your price:\n%s\n", arr_1);
return 0LL;
}
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2019-2-2 11:19
被kanxue编辑
,原因: