首页
社区
课程
招聘
[原创] 看雪 2022 KCTF 秋季赛 第十一题 衣锦昼行
发表于: 2022-12-12 01:59 19108

[原创] 看雪 2022 KCTF 秋季赛 第十一题 衣锦昼行

2022-12-12 01:59
19108

ida打开,main函数是sub_5B4270,没加混淆,但是main函数调用的其他计算函数都加了混淆(大概看了下,与Archaia战队在前几次比赛中用的差不多,难搞)

main函数没有混淆,验证逻辑很容易看出来,大概是对name和serial各做一些计算分别得到两个8字节的值,然后比较两个值是否相等。

比较好的一点是程序没有加壳与反调试,直接动态调试main函数,发现修改中间值的一个bit也会对结果产生巨大的影响,所以似乎只能分析算法逆推。

看了一个小时题目,先去睡觉了(实在不想硬刚代码混淆,再加上昨晚写第十题的wp没怎么睡)

晚上起来发现一血只用了一个半小时,果断开始找非预期。

main函数调用的其他函数由于被混淆了,导致ida识别的函数签名很乱,main函数的F5伪代码观感很差。

还是先修正所有函数的类型,根据汇编里调用函数前的push个数确定参数个数。

修正之后的main函数看上去清爽多了,摘抄如下:("..."中间的代码与前后相同(除了数组偏移),在此略去)

修正函数签名后,交叉引用的查找也会变得更准。“登录成功”的条件是v395和v365相等,对v365查找交叉引用可以定位到上面的sprintf,是从name计算出来的一个值;v395则是从serial计算出来的一个值。

观察代码,发现v70变量贯穿了大部分代码。
在输入serial之前以v365为初始值正向遍历v70进行了22次迭代计算得到v391;在输入serial之后以serial为初始值反向遍历v70进行了22次迭代计算得到v395。
这两块计算给人感觉很像互逆的。输入公开的name,尝试在0x5B6364下断点查看正向迭代22次后的v391,发现此处的v391正好就是公开的serial。

所以最终获得答案的方法很简单,输入KCTF作为name,提取正向迭代22次后的v391,即为对应的serial。

验证通过

 
 
 
 
 
 
 
// bad sp value at call has been detected, the output may be wrong!
int __cdecl main(int argc, const char **argv, const char **envp)
{
  // [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]
 
  memset(v70, 0, 0x1C2u);
  memset(v69, 0, sizeof(v69));
  qmemcpy(v116, "abcdefgh", sizeof(v116));
  memset(name, 0, 0x32u);
  *(_DWORD *)Buffer = 0;
  v406 = 0;
  v207 = 0;
  v208 = 0;
  v209 = 0;
  v210 = 0;
  v326 = 0;
  v327 = 0;
  v328 = 0;
  printf(&Format);                              // "请输入用户名:\n"
  gets((int)name);
  v390 = name;
  v293 = &name[1];
  v390 += strlen(v390);
  v289 = ++v390 - &name[1];
  Value = sub_5AE2D3(name, v390 - &name[1]);
  itoa(Value, Buffer, 16);
 
 
  sub_5AD9F9(v116, Buffer, &v207, &v326);
  *(_DWORD *)v70 = v207;
  *(_DWORD *)&v70[4] = v208;
  *(_DWORD *)v69 = v326;
  *(_DWORD *)&v69[4] = v327;
  qmemcpy(v115, "ijklmnop", sizeof(v115));
  v231 = 0;
  v232 = 0;
  v233 = 0;
  v234 = 0;
  v323 = 0;
  v324 = 0;
  v325 = 0;
  ...
  sub_593D03(v126, Buffer, v77, v277);
  qmemcpy(v127, "abcdefgh", sizeof(v127));
  memset(v76, 0, sizeof(v76));
 
 
  v275[0] = 0;
  v275[1] = 0;
  v276 = 0;
  sub_5937B3(v127, Buffer, v76, v275);
  memset(v365, 0, sizeof(v365));
  v366 = 0;
  v3 = sub_5AE2D3(v69, 192);
  sprintf(v365, "%08x", v3);    // v365
 
  v401[0] = 0;
  v401[1] = 0;
  v402 = 0;
  v403 = 0;
  v404 = 0;
  v391[0] = 0;
  v391[1] = 0;
  v392 = 0;
  v393 = 0;
  v394 = 0;
  sub_592CB9(v70, v365, v401);
  v368 = malloc(8u);
  v4 = v368;
  v5 = v403;
  *v368 = v402;
  v4[1] = v5;
  sub_592CB9(&v70[9], v401, v391);
  ...
  v44 = malloc(8u);
  v387 = v44;
  v45 = v403;
  *v44 = v402;
  v44[1] = v45;
  sub_592CB9(&v70[189], v401, v391);            // here, v391 is the correct serial
 
 
  v44 = malloc(8u);
  v387 = v44;
  v45 = v403;
  *v44 = v402;
  v44[1] = v45;
  sub_592CB9(&v70[189], v401, v391);
  memset(serial, 0, sizeof(serial));
  v288 = 0;
  memset(v399, 0, sizeof(v399));
  v400 = 0;
  memset(v395, 0, sizeof(v395));
  v396 = 0;
  v397 = 0;
  v398 = 0;
  printf(&byte_5D0848);                         // "请输入序列号:\n"
  gets((int)serial);
  v389 = serial;
  v291 = &serial[1];
  v389 += strlen(v389);
  v292 = ++v389 - &serial[1];
  if ( v389 - &serial[1] == 16 )
  {
    sub_592C10(&v70[189], v399, serial);
    v47 = v387[1];
    *(_DWORD *)&v399[8] = *v387;
    *(_DWORD *)&v399[12] = v47;
    ...
    sub_592C10(&v70[9], v399, v395);
    v67 = v368[1];
    *(_DWORD *)&v399[8] = *v368;
    *(_DWORD *)&v399[12] = v67;
    sub_592C10(v70, v395, v399);
 
    for ( i = 0; i < 8; ++i )
    {
      if ( v395[i] != v365[i] )
      {
        printf(&fail_1);                        // "登录失败!\n"
        system(aPause_0);
        return 0;
      }
    }
    printf(&success);                           // "登录成功!\n"
    system(aPause_1);
    return 0;
  }
  else
  {
    printf(&fail_2);                            // "登录失败!\n"
    system(Command);
    return 0;
  }
}
// bad sp value at call has been detected, the output may be wrong!
int __cdecl main(int argc, const char **argv, const char **envp)
{
  // [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]
 
  memset(v70, 0, 0x1C2u);
  memset(v69, 0, sizeof(v69));
  qmemcpy(v116, "abcdefgh", sizeof(v116));
  memset(name, 0, 0x32u);
  *(_DWORD *)Buffer = 0;
  v406 = 0;
  v207 = 0;
  v208 = 0;
  v209 = 0;
  v210 = 0;
  v326 = 0;
  v327 = 0;
  v328 = 0;
  printf(&Format);                              // "请输入用户名:\n"
  gets((int)name);
  v390 = name;
  v293 = &name[1];
  v390 += strlen(v390);
  v289 = ++v390 - &name[1];
  Value = sub_5AE2D3(name, v390 - &name[1]);
  itoa(Value, Buffer, 16);
 
 
  sub_5AD9F9(v116, Buffer, &v207, &v326);
  *(_DWORD *)v70 = v207;
  *(_DWORD *)&v70[4] = v208;
  *(_DWORD *)v69 = v326;
  *(_DWORD *)&v69[4] = v327;
  qmemcpy(v115, "ijklmnop", sizeof(v115));
  v231 = 0;
  v232 = 0;
  v233 = 0;
  v234 = 0;
  v323 = 0;
  v324 = 0;
  v325 = 0;
  ...
  sub_593D03(v126, Buffer, v77, v277);
  qmemcpy(v127, "abcdefgh", sizeof(v127));
  memset(v76, 0, sizeof(v76));
 
 
  v275[0] = 0;
  v275[1] = 0;
  v276 = 0;
  sub_5937B3(v127, Buffer, v76, v275);
  memset(v365, 0, sizeof(v365));
  v366 = 0;
  v3 = sub_5AE2D3(v69, 192);
  sprintf(v365, "%08x", v3);    // v365
 
  v401[0] = 0;
  v401[1] = 0;
  v402 = 0;
  v403 = 0;
  v404 = 0;
  v391[0] = 0;
  v391[1] = 0;
  v392 = 0;

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2022-12-12 02:02 被mb_mgodlfyn编辑 ,原因:
收藏
免费 3
支持
分享
最新回复 (1)
雪    币: 219
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
2
老师讲的真好
2023-2-23 15:25
0
游客
登录 | 注册 方可回帖
返回
//