• 玻利维亚发生交通事故30多人死伤 2019-11-09
  • 停车收费新政首日举报量攀升 2019-11-08
  • 指尖触碰 你我结缘丨浙江新闻4周年 我们再出发 2019-11-08
  • 图解2017:为网络空间“岁月静好” 网信工作不骛虚声 2019-10-29
  • 警方出重拳 守护个人信息安全 2019-10-25
  • 广州今年建成1500公里污水管网 2019-10-25
  • 湖南提前一年全面建立河长制 地表水水质监测总体为优 2019-10-23
  • 又高又壮的男人易患前列腺癌 2019-10-23
  • 杨梅:谣言太多伤不起 2019-10-18
  • 陈毓圭:引领新的社会阶层人士服务中国特色社会主义事业 2019-10-18
  • 快讯:博格巴破门 法国2 2019-10-13
  • “四大发明”是什么制? 2019-10-09
  • 池州:上千名幼儿及家长共同诵读古今经典(图) 2019-10-09
  • [微笑]正是因为土地是属于全民的,你个人要使用就必须付钱,不然就占了大家的便宜。 2019-10-08
  • 西部网(陕西新闻网)www.cnwest.com 2019-10-06
  • 吾爱破解 - LCG - LSG |安卓破解|病毒分析|破解软件|北京pk10最稳办法 www.yhhjx.com

     找回密码
     注册[Register]

    QQ登录

    只需一步,快速开始

    搜索
    查看: 21196|回复: 118
    上一主题 下一主题

    网赌pk10输惨了经历: [CTF] 2019腾讯游戏安全竞赛PC版分析

      [复制链接]
    跳转到指定楼层
    楼主
    二娃 发表于 2019-6-10 19:37 回帖奖励
    本帖最后由 二娃 于 2019-6-11 21:39 编辑

    北京pk10最稳办法 www.yhhjx.com 文章刚写完,论坛刚好开了。。

    首先感谢littleNA大佬的文章https://bbs.pediy.com/thread-230312.htm,看完这篇文章后事半功倍。

    第一题 EasyJob

    首先为了方便动静结合调试,我先修改了PE文件头部使之跳过重定位。使用工具DIE

    这样修改之后,使用IDA和其他调试工具的时候地址就能对得上了,告别aslr。

    用ida打开程序后,看一下main函数,确定sub_45F650sub_460050分别为检查request codeverification code的函数,做一下重命名。

    值得注意的是check_request_codecheck_verification_code有同一个参数,我把它命名为req_code_stru。在后面的分析过程中,我得出该变量类型的结构体

    struct req_code_stru
    {
      vector request_code_part;
      __int64 num1;
      __int64 num2;
      __int64 num3;
      __int64 num4;
    };

    其中vector结构可以参考上面littleNA大佬的文章,在这个结构体中应该是vector<string>,每个成员的作用会在后面讲到。

    进入check_request_code函数后,发现字符串

    很明显是一个正则表达式,于是推测request code需要符合该正则表达式。打开程序随便输入了一个符合该表达式的request code,比如1111-2222-3333-4444,输入后程序提示继续输入verification code,表明推测是正确的。通过调试后还发现该函数会把request code通过字符-分成4个string插入到req_code_stru->request_code_part中。

    接下来看一下check_vertification_code。通过浏览后发现一个比较关键的函数sub_45F960,通过req_code_stru->request_code_part计算出4个num,具体代码如下

    int __thiscall sub_45F960(req_code_stru *req_code_stru)
    {
      char *v1_part1; // esi
      char *v2_part1; // eax
      char *v3_part4; // ebx
      char *v4_part4; // ecx
      int v5; // edi
      char *v6_part1; // ecx
      char *v7_part4; // eax
      int v8; // edi
      char *v9_part1; // edx
      char *v10_part4; // eax
      int v11; // edi
      char *v12_part1; // edx
      char *v13_part4; // eax
      char *v14_part2; // eax
      char *v15_part3; // edi
      char *v16_part3; // ecx
      char *v17_part2; // edx
      char *v18_part3; // eax
      char *v19_part2; // edx
      char *v20_part3; // eax
      char *v21_part1; // edx
      char *v22_part3; // eax
      char *v23_part1; // edx
      char *v24_part1; // eax
      char *v25_part2; // eax
      char *v26_part2; // edx
      char *v27_part3; // ecx
      char *v28_part3; // eax
      int v29; // ecx
      char *v30_part4; // edx
      char *v31_part4; // eax
      char *v32_part1; // ecx
      char *v33_part4; // eax
      char *v34_part2; // edx
      char *v35_part3; // eax
      char *v36_part2; // eax
      int v37; // eax
      int v38; // edx
      int v39; // ST24_4
      int v40; // ecx
      __int64 v41; // rdi
      bool v42; // cf
      unsigned __int64 v43; // rt0
      __int64 v44; // kr38_8
      __int64 v45; // rax
      unsigned int v46; // ecx
      unsigned int v47; // ecx
      signed __int64 v48; // rax
      int v49; // ecx
      req_code_stru *v51_reg_code_stru; // [esp+10h] [ebp-18h]
      int v52; // [esp+14h] [ebp-14h]
      int v53; // [esp+14h] [ebp-14h]
      int v54; // [esp+18h] [ebp-10h]
      int v55; // [esp+1Ch] [ebp-Ch]
      int v56; // [esp+24h] [ebp-4h]
      int v57; // [esp+24h] [ebp-4h]
      int v58; // [esp+24h] [ebp-4h]
      int v59; // [esp+24h] [ebp-4h]
      int v60; // [esp+24h] [ebp-4h]
      int v61; // [esp+24h] [ebp-4h]
    
      v1_part1 = req_code_stru->request_code_part._Myfirst;
      v51_reg_code_stru = req_code_stru;
      if ( *((_DWORD *)req_code_stru->request_code_part._Myfirst + 5) < 0x10u )
        v2_part1 = req_code_stru->request_code_part._Myfirst;
      else
        v2_part1 = *(char **)v1_part1;
      v3_part4 = v1_part1 + 72;
      if ( *((_DWORD *)v1_part1 + 23) < 0x10u )
        v4_part4 = v1_part1 + 72;
      else
        v4_part4 = *(char **)v3_part4;
      v5 = (*v4_part4 ^ *v2_part1) << 8;            // v5=(part4[0]^part1[0])<<8
      if ( *((_DWORD *)v1_part1 + 5) < 0x10u )
        v6_part1 = v1_part1;
      else
        v6_part1 = *(char **)v1_part1;
      if ( *((_DWORD *)v1_part1 + 23) < 0x10u )
        v7_part4 = v1_part1 + 72;
      else
        v7_part4 = *(char **)v3_part4;
      v8 = v6_part1[1] * v7_part4[1] + v5;          // v8=part1[1]*part4[1]+v5
      if ( *((_DWORD *)v1_part1 + 5) < 0x10u )
        v9_part1 = v1_part1;
      else
        v9_part1 = *(char **)v1_part1;
      if ( *((_DWORD *)v1_part1 + 23) < 0x10u )
        v10_part4 = v1_part1 + 72;
      else
        v10_part4 = *(char **)v3_part4;
      v11 = v9_part1[2] / v10_part4[2] + v8;        // v11=part1[2]/part4[2]+v8
      if ( *((_DWORD *)v1_part1 + 5) < 0x10u )
        v12_part1 = v1_part1;
      else
        v12_part1 = *(char **)v1_part1;
      if ( *((_DWORD *)v1_part1 + 23) < 0x10u )
        v13_part4 = v1_part1 + 72;
      else
        v13_part4 = *(char **)v3_part4;
      v54 = v11 + v12_part1[2] % v13_part4[2];      // v54=part1[2]%part4[2]+v11
      v14_part2 = v1_part1 + 24;
      if ( *((_DWORD *)v1_part1 + 11) >= 0x10u )
        v14_part2 = *(char **)v14_part2;
      v15_part3 = v1_part1 + 48;
      if ( *((_DWORD *)v1_part1 + 17) < 0x10u )
        v16_part3 = v1_part1 + 48;
      else
        v16_part3 = *(char **)v15_part3;
      v56 = *v16_part3 * *v14_part2 << 8;           // v56=part3[0]*part2[0]<<8
      if ( *((_DWORD *)v1_part1 + 11) < 0x10u )
        v17_part2 = v1_part1 + 24;
      else
        v17_part2 = (char *)*((_DWORD *)v1_part1 + 6);
      if ( *((_DWORD *)v1_part1 + 17) < 0x10u )
        v18_part3 = v1_part1 + 48;
      else
        v18_part3 = *(char **)v15_part3;
      v57 = (char)(v17_part2[1] ^ v18_part3[1]) + v56;// v57=(part2[1]^part3[1])+v56
      if ( *((_DWORD *)v1_part1 + 11) < 0x10u )
        v19_part2 = v1_part1 + 24;
      else
        v19_part2 = (char *)*((_DWORD *)v1_part1 + 6);
      if ( *((_DWORD *)v1_part1 + 17) < 0x10u )
        v20_part3 = v1_part1 + 48;
      else
        v20_part3 = *(char **)v15_part3;
      v58 = v19_part2[2] % v20_part3[2] + 32 + v57; // v58=part2[2]%part3[2]+32+v57
      if ( *((_DWORD *)v1_part1 + 5) < 0x10u )
        v21_part1 = v1_part1;
      else
        v21_part1 = *(char **)v1_part1;
      if ( *((_DWORD *)v1_part1 + 17) < 0x10u )
        v22_part3 = v1_part1 + 48;
      else
        v22_part3 = *(char **)v15_part3;
      v55 = v58 + v21_part1[2] / v22_part3[2];      // v55=part1[2]/part3[2]+v58
      if ( *((_DWORD *)v1_part1 + 5) < 0x10u )
        v23_part1 = v1_part1;
      else
        v23_part1 = *(char **)v1_part1;
      if ( *((_DWORD *)v1_part1 + 5) < 0x10u )
        v24_part1 = v1_part1;
      else
        v24_part1 = *(char **)v1_part1;
      v59 = v23_part1[1] % v24_part1[3] << 8;       // v59=part1[1]%part1[3]<<8
      v25_part2 = v1_part1 + 24;
      if ( *((_DWORD *)v1_part1 + 11) < 0x10u )
        v26_part2 = v1_part1 + 24;
      else
        v26_part2 = *(char **)v25_part2;
      if ( *((_DWORD *)v1_part1 + 11) >= 0x10u )
        v25_part2 = *(char **)v25_part2;
      v60 = v26_part2[1] / v25_part2[3] + v59;      // v60=part2[1]/part2[3]+v59
      if ( *((_DWORD *)v1_part1 + 17) < 0x10u )
        v27_part3 = v1_part1 + 48;
      else
        v27_part3 = *(char **)v15_part3;
      if ( *((_DWORD *)v1_part1 + 17) < 0x10u )
        v28_part3 = v1_part1 + 48;
      else
        v28_part3 = *(char **)v15_part3;
      v29 = v27_part3[1] * v28_part3[3] + 8 + v60;  // v29=part3[1]*part3[3]+8+v60
      if ( *((_DWORD *)v1_part1 + 23) < 0x10u )
        v30_part4 = v1_part1 + 72;
      else
        v30_part4 = *(char **)v3_part4;
      if ( *((_DWORD *)v1_part1 + 23) < 0x10u )
        v31_part4 = v1_part1 + 72;
      else
        v31_part4 = *(char **)v3_part4;
      v61 = v29 + (char)(v30_part4[1] ^ v31_part4[3]);// v61=(part4[1]^part4[3])+v29
      if ( *((_DWORD *)v1_part1 + 5) < 0x10u )
        v32_part1 = v1_part1;
      else
        v32_part1 = *(char **)v1_part1;
      if ( *((_DWORD *)v1_part1 + 23) < 0x10u )
        v33_part4 = v1_part1 + 72;
      else
        v33_part4 = *(char **)v3_part4;
      v52 = (*v32_part1 ^ v33_part4[3]) << 8;       // v52=(part1[0]^part4[3])<<8
      if ( *((_DWORD *)v1_part1 + 11) < 0x10u )
        v34_part2 = v1_part1 + 24;
      else
        v34_part2 = (char *)*((_DWORD *)v1_part1 + 6);
      if ( *((_DWORD *)v1_part1 + 17) < 0x10u )
        v35_part3 = v1_part1 + 48;
      else
        v35_part3 = *(char **)v15_part3;
      v53 = v34_part2[1] / v35_part3[2] + v52;      // v53=part2[1]/part3[2]+v52
      if ( *((_DWORD *)v1_part1 + 17) >= 0x10u )
        v15_part3 = *(char **)v15_part3;
      v36_part2 = v1_part1 + 24;
      if ( *((_DWORD *)v1_part1 + 11) >= 0x10u )
        v36_part2 = *(char **)v36_part2;
      v37 = v15_part3[2] * v36_part2[1];            // v37=part3[2]*part2[1]
      if ( *((_DWORD *)v1_part1 + 23) >= 0x10u )
        v3_part4 = *(char **)v3_part4;
      if ( *((_DWORD *)v1_part1 + 5) >= 0x10u )
        v1_part1 = *(char **)v1_part1;
      v38 = v37 + v53 + v3_part4[3] % *v1_part1;    // v38=part4[3]%part1[0]+v37+v53
      v39 = v38;
      v40 = (unsigned __int64)(unsigned int)v38 >> 29;
      LODWORD(v41) = 20 * (v54 + 2 * v61);          // v41=20*(v54+2*v61)
      v42 = __CFADD__(8 * v38, v38);
      v38 *= 9;
      HIDWORD(v43) = v40 + v42;
      LODWORD(v43) = v38;
      HIDWORD(v41) = v43 >> 29;
      v51_reg_code_stru->num1 = 30i64 * (unsigned int)v55
                              + __PAIR__(20 * ((unsigned int)v54 + 2 * (unsigned __int64)(unsigned int)v61) >> 32, 8 * v38)
                              + v41;                // num1=30*v55+20*(v54+2*v61)+72*v38
      v51_reg_code_stru->num2 = 23i64 * (unsigned int)v54
                              + 32i64 * (unsigned int)v55
                              + 42i64 * (unsigned int)v61
                              + 54i64 * (unsigned int)v39;// num2=23*v54+32*v55+42*v61+54*v39
      LODWORD(v41) = 25 * v55 + 38 * v61 + 67 * v39;
      HIDWORD(v43) = ((unsigned __int64)(unsigned int)v54 >> 29) + __CFADD__(8 * v54, v54);
      LODWORD(v43) = 9 * v54;
      HIDWORD(v41) = v43 >> 31;
      v44 = __PAIR__(
              (25i64 * (unsigned int)v55 + 38i64 * (unsigned int)v61 + 67 * (unsigned __int64)(unsigned int)v39) >> 32,
              18 * v54)
          + v41;
      HIDWORD(v41) = v51_reg_code_stru;
      v51_reg_code_stru->num3 = v44;
      HIDWORD(v43) = ((unsigned __int64)(unsigned int)v54 >> 31) + __CFADD__(2 * v54, v54);
      LODWORD(v43) = 3 * v54;
      LODWORD(v41) = (__PAIR__(v43 >> 30, 12 * v54)
                    + 45i64 * (unsigned int)v55
                    + 33i64 * (unsigned int)v39
                    + ((unsigned __int64)(unsigned int)v61 << 6)) >> 32;
      v45 = SHIDWORD(v51_reg_code_stru->num1);
      v46 = HIDWORD(v45) ^ LODWORD(v51_reg_code_stru->num1);
      v42 = v46 < HIDWORD(v45);
      LODWORD(v51_reg_code_stru->num1) = v46 - HIDWORD(v45);
      v47 = v51_reg_code_stru->num2;
      HIDWORD(v51_reg_code_stru->num1) = (HIDWORD(v45) ^ v45) - (v42 + HIDWORD(v45));
      *(_QWORD *)(HIDWORD(v41) + 24) = __PAIR__(
                                         (*(_DWORD *)(HIDWORD(v41) + 28) >> 31) ^ *(_DWORD *)(HIDWORD(v41) + 28),
                                         (*(_DWORD *)(HIDWORD(v41) + 28) >> 31) ^ v47)
                                     - __PAIR__(*(_DWORD *)(HIDWORD(v41) + 28) >> 31, *(_DWORD *)(HIDWORD(v41) + 28) >> 31);
      v51_reg_code_stru->num3 = (signed __int64)(__PAIR__(
                                                   (*(_DWORD *)(HIDWORD(v41) + 36) >> 31) ^ *(_DWORD *)(HIDWORD(v41) + 36),
                                                   (*(_DWORD *)(HIDWORD(v41) + 36) >> 31) ^ *(_DWORD *)(HIDWORD(v41) + 32))
                                               - __PAIR__(
                                                   *(_DWORD *)(HIDWORD(v41) + 36) >> 31,
                                                   *(_DWORD *)(HIDWORD(v41) + 36) >> 31))
                              % 20;                 // num3=(25*v55+38*v61+67*v39+18*v54)%20
      v48 = (signed __int64)(__PAIR__(
                               ((signed int)v41 >> 31) ^ (unsigned int)v41,
                               ((signed int)v41 >> 31) ^ (unsigned int)(12 * v54 + 45 * v55 + 33 * v39 + (v61 << 6)))
                           - __PAIR__((signed int)v41 >> 31, (signed int)v41 >> 31))
          % 20;                                     // num4=(12*v54+45*v55+33*v39+v61*64)%20
      v51_reg_code_stru->num4 = v48;
      if ( SHIDWORD(v51_reg_code_stru->num3) >= SHIDWORD(v48) )
      {
        if ( SHIDWORD(v51_reg_code_stru->num3) > SHIDWORD(v48)// 如果num3>num4就互相交换
          || (LODWORD(v48) = v51_reg_code_stru->num3, (unsigned int)v48 > LODWORD(v51_reg_code_stru->num4)) )
        {
          v49 = v51_reg_code_stru->num3;
          HIDWORD(v48) = HIDWORD(v51_reg_code_stru->num3);
          LODWORD(v51_reg_code_stru->num3) = v51_reg_code_stru->num4;
          LODWORD(v48) = HIDWORD(v51_reg_code_stru->num4);
          HIDWORD(v51_reg_code_stru->num3) = v48;
          LODWORD(v51_reg_code_stru->num4) = v49;
          HIDWORD(v51_reg_code_stru->num4) = HIDWORD(v48);
        }
      }
      return v48;
    }

    F5后看起来很乱,需要结合汇编一起分析。

    接下来在sub_45FE00计算出num5

    num5等于request_code每个数字相加,比如1111-2222-3333-4444计算出来的num5就是40

    接下来回到check_request_code中把得到的4个part和5个num拼接

    这里看F5可能看不太懂,可以看汇编

    这里是先把4个operator<<的参数全部压栈再一个个call,应该是编译器优化的结果。得到的结果就是一个字符串s=part1+part2+part3+part4+num1+num2+num3+num4+num5

    最后将得到的字符串再做一个以part1keyhmac_sha256计算

    因为用ida看了字符串发现OpenSSL 1.0.2m  2 Nov 2017的字样所以事先用Rizzo打上了OpenSSL的符号。关于OpenSSL编译可以看https://cloud.tencent.com/developer/article/1343632。不过遗憾的是打上了符号也没办法识别出这个hmac使用的hash算法是什么,后来我是通过动态调试获得一组输入和输出暴力跑出了hashsha256,做完hmac_sha256后得到的结果即为verification_code。

    附上python3注册机代码

    import re
    import hmac
    
    def hmac_sha256(key,s):
        return hmac.new(key.encode('utf-8'), s.encode('utf-8'), 'SHA256').hexdigest()
    
    def get_verification_code(part1,part2,part3,part4):
        v5=(ord(part4[0])^ord(part1[0]))<<8
        v8=ord(part1[1])*ord(part4[1])+v5
        v11=ord(part1[2])//ord(part4[2])+v8
        v54=ord(part1[2])%ord(part4[2])+v11
        v56=ord(part3[0])*ord(part2[0])<<8
        v57=(ord(part2[1])^ord(part3[1]))+v56
        v58=ord(part2[2])%ord(part3[2])+32+v57
        v55=ord(part1[2])//ord(part3[2])+v58
        v59=ord(part1[1])%ord(part1[3])<<8
        v60=ord(part2[1])//ord(part2[3])+v59
        v29=ord(part3[1])*ord(part3[3])+8+v60
        v61=(ord(part4[1])^ord(part4[3]))+v29
        v52=(ord(part1[0])^ord(part4[3]))<<8
        v53=ord(part2[1])//ord(part3[2])+v52
        v37=ord(part3[2])*ord(part2[1])
        v38=ord(part4[3])%ord(part1[0])+v37+v53
        v39=v38
        v38=v38*9
        v41=12*v54+45*v55+33*v39
        num1=30*v55+20*(v54+2*v61)+8*v38
        num2=23*v54+32*v55+42*v61+54*v39
        num3=(25*v55+38*v61+67*v39+18*v54)%20
        num4=(12*v54+45*v55+33*v39+v61*64)%20
        if num3>num4:
            num3,num4=num4,num3
        num5=0
        for i in range(4):
            num5+=int(part1[i])+int(part2[i])+int(part3[i])+int(part4[i])
        code=part1+part2+part3+part4+str(num1)+str(num2)+str(num3)+str(num4)+str(num5)
        return hmac_sha256(part1,code)
    
    if __name__=='__main__':
        request_code=input('input request code: ')
        reobj=re.fullmatch('(\\d{4})-(\\d{4})-(\\d{4})-(\\d{4})',request_code)
        if reobj!=None:
            part1=reobj.group(1)
            part2=reobj.group(2)
            part3=reobj.group(3)
            part4=reobj.group(4)
            print(get_verification_code(part1,part2,part3,part4))
        else:
            print('[+] Invalid code!')

    第二题 Rotate

    第二题和第一题相差不大,不同的地方是多了一个num6以及hmac_sha256key不同??匆幌碌既氡?,发现一些opencv的函数

    为了方便分析,去抠了一下cv::Mat的结构体。

    struct cvMat
    {
      int flags;
      int dims;
      int rows;
      int cols;
      unsigned __int8 *data;
      unsigned __int8 *datastart;
      unsigned __int8 *dataend;
      unsigned __int8 *datalimit;
      void *allocator;
      void *u;
      int *size_p;
      unsigned __int64 *step_p;
      unsigned __int64 step_buf[2];
    };
    

    其中MatStepMatSize被我拆了,影响不是很大。

    首先在check_verification_code中使用cv::imread读取了题目目录下的flag.jpg

    这里应该是个cv::Mat构造函数,被编译器优化成内联函数了。

    接下来在sub_14007A2C0中进行图像的旋转。

    通过cv::getRotationMatrix2D获得旋转的矩阵再用cv::warpAffine进行仿射变换。

    sub_140079C50进行图像的处理并计算num6,首先是图像的处理

    分别调用了cv::cvtColor cv::resizecv::dct

    然后根据图像的数据计算num6

      v9 = *Dst.step_p;                             // 一行元素的字节数
      v10 = &v45;
      v11 = (double *)(Dst.data + 24);
      do
      {
        v12 = *(v11 - 3);
        *((double *)v10 - 1) = v12;
        v13 = *(v11 - 2);
        *(double *)v10 = v13;
        v14 = *(v11 - 1);
        *((double *)v10 + 1) = v14;
        v15 = *v11;
        v10[2] = *(_QWORD *)v11;
        v16 = v11[1];
        *((double *)v10 + 3) = v16;
        v17 = v11[2];
        *((double *)v10 + 4) = v17;
        v18 = v11[3];
        *((double *)v10 + 5) = v18;
        v19 = v11[4];
        *((double *)v10 + 6) = v19;
        v5 = v12 * 0.015625                         // 图像数据的平均数
           + v5
           + v13 * 0.015625
           + v14 * 0.015625
           + v15 * 0.015625
           + v16 * 0.015625
           + v17 * 0.015625
           + v18 * 0.015625
           + v19 * 0.015625;
        v10 += 8;
        v11 = (double *)((char *)v11 + v9);         // 下一行
        --v8;
      }
      while ( v8 );                                 // 8次
      v20 = 0i64;
      do                                            // 图像每一点的数据与平均数对比
                                                    // 如果数值小于平均数则为0否则为1
                                                    // 得到一个长度为64格式为二进制的字符串
      {
        if ( *((double *)&v44 + v20) < v5 )
        {
          if ( v4->_Myres < 0x10 )
            v22 = v4;
          else
            v22 = *(string **)v4->_Buf;
          v22->_Buf[v20] = '0';
        }
        else
        {
          if ( v4->_Myres < 0x10 )
            v21 = v4;
          else
            v21 = *(string **)v4->_Buf;
          v21->_Buf[v20] = '1';
        }
        if ( *((double *)&v45 + v20) < v5 )
        {
          if ( v4->_Myres < 0x10 )
            v24 = v4;
          else
            v24 = *(string **)v4->_Buf;
          v24->_Buf[v20 + 1] = '0';
        }
        else
        {
          if ( v4->_Myres < 0x10 )
            v23 = v4;
          else
            v23 = *(string **)v4->_Buf;
          v23->_Buf[v20 + 1] = '1';
        }
        if ( *((double *)&v46 + v20) < v5 )
        {
          if ( v4->_Myres < 0x10 )
            v26 = v4;
          else
            v26 = *(string **)v4->_Buf;
          v26->_Buf[v20 + 2] = '0';
        }
        else
        {
          if ( v4->_Myres < 0x10 )
            v25 = v4;
          else
            v25 = *(string **)v4->_Buf;
          v25->_Buf[v20 + 2] = '1';
        }
        if ( *(double *)&v47[v20] < v5 )
        {
          if ( v4->_Myres < 0x10 )
            v28 = v4;
          else
            v28 = *(string **)v4->_Buf;
          v28->_Buf[v20 + 3] = '0';
        }
        else
        {
          if ( v4->_Myres < 0x10 )
            v27 = v4;
          else
            v27 = *(string **)v4->_Buf;
          v27->_Buf[v20 + 3] = '1';
        }
        v20 += 4i64;
      }
      while ( v20 < 64 );                           // 总共有8*8=64个数

    得到的长度为64的字符串即为num6

    最后拼接partnum得到字符串s=part1+part2+part3+part4+num1+num2+num3+num4+num5+num6再以num6keyhmac_sha256得到verification code,相关代码与第一题一致。

    附上python3注册机

    import re
    import hmac
    import cv2
    import numpy as np
    
    def hmac_sha256(key,s):
        return hmac.new(key.encode('utf-8'), s.encode('utf-8'), 'SHA256').hexdigest()
    
    def get_num6(part1,part2,part3,part4):
        img=cv2.imread('.\\flag.jpg',cv2.IMREAD_COLOR)
        center=(img.shape[1]*0.5,img.shape[0]*0.5)
        angle=0
        for i in range(4):
            angle+=int(part1[i])+int(part2[i])+int(part3[i])+int(part4[i])
        scale=1.0
        trans=cv2.getRotationMatrix2D(center,angle,scale)
        dsize=(img.shape[1],img.shape[0])
        img=cv2.warpAffine(img,trans,dsize)
        img=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
        img=np.float64(img)
        dsize=(8,8)
        img=cv2.resize(img,dsize)
        img=cv2.dct(img)
        total=0
        for i in img:
            for j in i:
                total+=j
        average=total/64
        num6=''
        for i in img:
            for j in i:
                if j<average:
                    num6+='0'
                else:
                    num6+='1'
        return num6
    
    def get_verification_code(part1,part2,part3,part4):
        v5=(ord(part4[0])^ord(part1[0]))<<8
        v8=ord(part1[1])*ord(part4[1])+v5
        v11=ord(part1[2])//ord(part4[2])+v8
        v54=ord(part1[2])%ord(part4[2])+v11
        v56=ord(part3[0])*ord(part2[0])<<8
        v57=(ord(part2[1])^ord(part3[1]))+v56
        v58=ord(part2[2])%ord(part3[2])+32+v57
        v55=ord(part1[2])//ord(part3[2])+v58
        v59=ord(part1[1])%ord(part1[3])<<8
        v60=ord(part2[1])//ord(part2[3])+v59
        v29=ord(part3[1])*ord(part3[3])+8+v60
        v61=(ord(part4[1])^ord(part4[3]))+v29
        v52=(ord(part1[0])^ord(part4[3]))<<8
        v53=ord(part2[1])//ord(part3[2])+v52
        v37=ord(part3[2])*ord(part2[1])
        v38=ord(part4[3])%ord(part1[0])+v37+v53
        v39=v38
        v38=v38*9
        v41=12*v54+45*v55+33*v39
        num1=30*v55+20*(v54+2*v61)+8*v38
        num2=23*v54+32*v55+42*v61+54*v39
        num3=(25*v55+38*v61+67*v39+18*v54)%20
        num4=(12*v54+45*v55+33*v39+v61*64)%20
        if num3>num4:
            num3,num4=num4,num3
        num5=0
        for i in range(4):
            num5+=int(part1[i])+int(part2[i])+int(part3[i])+int(part4[i])
        num6=get_num6(part1,part2,part3,part4)
        code=part1+part2+part3+part4+str(num1)+str(num2)+str(num3)+str(num4)+str(num5)+num6
        return hmac_sha256(num6,code)
    
    if __name__=='__main__':
        request_code=input('input request code: ')
        reobj=re.fullmatch('(\\d{4})-(\\d{4})-(\\d{4})-(\\d{4})',request_code)
        if reobj!=None:
            part1=reobj.group(1)
            part2=reobj.group(2)
            part3=reobj.group(3)
            part4=reobj.group(4)
            print(get_verification_code(part1,part2,part3,part4))
        else:
            print('[+] Invalid code!')

    第三题 Invisiable

    该题目录下的文件

    打开Invisiable.exe,首先看到有个tlscallback反调试

    通过NtQueryInformationProcess查了DebugPort,如果程序被调试了这个DebugPort就不为0。检测到没有被调试后程序修改了某个函数,把这个函数填充成nop。当然这个反调试没什么影响,因为我用了SharpOD插件,所以基本不用管。

    看一下main中的主要部分

    验证输入的函数并不是直接调用的,ida看起来也不方便,所以我选择通过动态调试获取了3个step的验证输入的函数

    first step

    sub_404180中判断number-2019000是否为水仙花数。

    如果是的话就就执行接下来的操作

    读取题目目录下的invisiable.mp3文件数据,然后通过sub_401C20解密得到真实的文件decode.py

    解密函数sub_401C20如下

    将原文件数据的每个字节与字符串ReverseEngineerIsEasy的每个字符循环异或,得到真实文件数据,然后写回硬盘上。

    然后对目录下的文件flag也做了同样的事情,解密后得到nice.png文件。

    最后做了一个谜之操作,修改了main.dll

    看了一下main.dll偏移0x46c处正是它的导出函数的位置,这里修改成了ret C。

    到这里first step就结束了

    second step

    首先判断了一下输入

    如果符合条件就执行接下来的操作

    读取目录下1.txt的数据

    然后判断文本内容

    也就是说1.txt的文本内容格式需要为xxxx-xxxx,part1长度暂时未知。

    然后对这两个part进行了和first step解密文件很像的操作,buf1buf2分别为part1part2

    然后将得到的结果做base64encode计算,得到的结果需要是VFxQXkljVFo=

    VFxQXkljVFo=base64decode后得到T\P^IcTZ,也就是说我们的part1长度必须为8。

    然后就是写脚本跑一个符合该要求的输入出来了

    def xor_asc(l):
        s='T\\P^IcTZ'
        a=[ord(x) for x in s]
        b=[0 for i in range(8)]
        for i in range(8):
            b[i]=a[i]^l[i%len(l)]
        return b
    
    def inc_asc(l):
        for i in range(len(l)):
            l[len(l)-i-1]+=1
            if l[len(l)-i-1]==ord('-'):
                l[len(l)-i-1]+=1
            if l[len(l)-i-1]>126:
                l[len(l)-i-1]=33
            else:
                break
        return l
    
    def check_asc(l):
        for i in l:
            if i>126 or i<33:
                return False
        return True
    
    def create_txt():
        part1=[]
        part2=[33,33,33,33]
        while(True):
            part1=xor_asc(part2)
            if check_asc(part1):
                s1=''.join([chr(x) for x in part1])
                s2=''.join([chr(x) for x in part2])
                s=s1+'-'+s2
                print(s)
            part2=inc_asc(part2)
    
    if __name__=='__main__':
        create_txt()
        #u}6uhB2q-!!f+

    为了方便输入,所以只取了可视的ascii字符(不包括空格)。这个脚本不会停,所以请自行ctrl+c强制结束。随便取了一个结果u}6uhB2q-!!f+保存到1.txt后,再输入一个符合要求的number,second step就结束了。

    third step

    sub_404220中对输入的number进行了验证

    需要输入一个长度为6的数字,然后每两个为一组拆成3个2位数,这3个数需要符合一个方程,解的结果为744110。

    输入正确结果后,程序加载main.dll

    如果仅仅是这样,那么恭喜,程序崩溃。

    还记得在first step中修改了main.dll的导出函数吗?这就是程序崩溃的原因。为了能够得到正确结果,在third step输入数字前需要把未修改的main.dll替换回去。最后符合题目要求,程序输出了flag。

    但是我感觉这里过于诡异,所以不知道算不算正解。又看了一遍题目,要求输出的flag形式为flag{xxxxxxx}。。。也就是说1.txtpart1的前五位是可以确定的,但是我不想改了,就这样吧。

    还有一个诡异的地方就是,first step中创建的decode.pynice.png在后面没用到,贴一下decode.py的代码

    # coding=utf-8
    import cv2
    import numpy as np
    import random
    import os
    from argparse import ArgumentParser
    ALPHA = 5
    
    def build_parser():
        parser = ArgumentParser()
        parser.add_argument('--original', dest='ori', required=True)
        parser.add_argument('--image', dest='img', required=True)
        parser.add_argument('--result', dest='res', required=True)
        parser.add_argument('--alpha', dest='alpha', default=ALPHA)
        return parser
    
    def main():
        parser = build_parser()
        options = parser.parse_args()
        ori = options.ori
        img = options.img
        res = options.res
        alpha = float(options.alpha)
        if not os.path.isfile(ori):
            parser.error("original image %s does not exist." % ori)
        if not os.path.isfile(img):
            parser.error("image %s does not exist." % img)
        decode(ori, img, res, alpha)
    
    def decode(ori_path, img_path, res_path, alpha):
        ori = cv2.imread(ori_path)
        img = cv2.imread(img_path)
        ori_f = np.fft.fft2(ori)
        img_f = np.fft.fft2(img)
        height, width = ori.shape[0], ori.shape[1]
        watermark = (ori_f - img_f) / alpha
        watermark = np.real(watermark)
        res = np.zeros(watermark.shape)
        random.seed(height + width)
        x = range(height / 2)
        y = range(width)
        random.shuffle(x)
        random.shuffle(y)
        for i in range(height / 2):
            for j in range(width):
                res[x][y[j]] = watermark[i][j]
        cv2.imwrite(res_path, res, [int(cv2.IMWRITE_JPEG_QUALITY), 100])
    
    if __name__ == '__main__':
        main()

    这就超出我的能力范围了(怎么还有快速傅里叶变换呢)。试着用了一下这个脚本

    py -2 decode.py --original nice.png --image out.png --result res.png

    得到图片

    nice.pngout.png分别为

    看了这几张图,总感觉第三题还有一点门路。然而小弟能力有限,只能到这了,希望大佬们能指导指导。



    题目太大,上传不了,有兴趣的可以自行去下载。

    免费评分

    参与人数 36吾爱币 +37 热心值 +33 收起 理由
    Harvey丶 + 1 + 1 我很赞同!
    dashan22222 + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
    canglangshui + 1 + 1 热心回复!
    Kings_jk + 1 热心回复!
    15291037368 + 1 鼓励转贴优秀软件安全工具和文档!
    樊洋昊 + 1 谢谢@Thanks!
    PGdcJco + 1 + 1 用心讨论,共获提升!
    siuhoapdou + 1 + 1 热心回复!
    Fa1sePRoMiSe + 1 + 1 用心讨论,共获提升!
    ZHANGtao6344863 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
    纳新德白蛇 + 1 + 1 谢谢@Thanks!
    当你丶 + 1 + 1 好厉害?。。?!
    zmyzzx + 1 + 1 谢谢@Thanks!
    擎仁杰 + 1 + 1 用心讨论,共获提升!
    yld911 + 1 + 1 大神,膜拜
    xiatanren + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
    xuzhouwangchen + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
    杀猪用牛刀 + 1 + 1 谢谢@Thanks!
    Cloudx + 1 + 1 谢谢@Thanks!
    迷雾v + 1 谢谢@Thanks!
    orangewinnie + 1 + 1 谢谢@Thanks!
    大大带师兄 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
    can0a + 1 用心讨论,共获提升!
    yixi + 1 + 1 谢谢@Thanks!
    fu90 + 1 + 1 热心回复!
    s3568753 + 1 + 1 一脸懵逼来,一脸懵逼去,大神威武!
    凌霄公子 + 1 + 1 用心讨论,共获提升!
    梦游枪手 + 2 + 1 用心讨论,共获提升!
    洛熏 + 1 热心回复!
    笙若 + 1 + 1 谢谢@Thanks!
    XhyEax + 2 + 1 热心回复!
    静一静 + 1 + 1 用心讨论,共获提升!
    65302666 + 2 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
    海盗小K + 3 + 1 虽然看不懂,但分还是要给的。
    陈世界 + 1 + 1 用心讨论,共获提升!
    Smallhorse + 2 + 1 用心讨论,共获提升!

    查看全部评分

    发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

    推荐
    kikkki 发表于 2019-7-4 23:49
    膜拜大神,小白我看来这辈子都学不会。。太强大了。去培训了4个月的JAVA,到头来,连最基本的增删改都不会。我这猪脑,啥时候能变得和楼主一样优秀,有一门拿得出手的技术。
    推荐
     楼主| 二娃 发表于 2019-9-30 19:58 <
    こ_浅唱沵给旳恐 发表于 2019-9-30 00:21
    怎么看出来 那里就是串文本.....

    IDA直接按A转出来的很奇怪.....

    这个仔细看看就知道是这串文本了 按A很奇怪是因为这里不是整个字符串

    第三题解完了 但是我这里其实不是正解
    需要用到那个解码出来的图片上的数字2019作为一个xorkey 我当时解完了都还不知道这个2019是干什么的 后来整明白了 不过这篇文章就没改了 具体可以看//www.yhhjx.com/thread-908932-1-1.html底下的回复
    4#
     楼主| 二娃 发表于 2019-6-10 19:42 <
    5#
    Checkon 发表于 2019-6-10 19:58
    完全就根本
    看不懂
    6#
    不诉离殇 发表于 2019-6-10 19:59
    完全看不懂。。
    7#
    57558938 发表于 2019-6-10 20:06
    看不懂+1
    8#
     楼主| 二娃 发表于 2019-6-10 20:09 <
    对不起我的表达能力太差了。如果没看过题目的话可能确实是看不懂 = =
    9#
    _小白 发表于 2019-6-10 20:19
    顶一下楼主
    10#
    chiao 发表于 2019-6-10 20:28
    厉害,顶一下
    11#
    vethenc 发表于 2019-6-10 20:33
    村长喊你回来放牛
    12#
    焰火 发表于 2019-6-10 20:35
    虽然没看过题目,但是楼主思路表达了出来,看有人说看不懂,感觉是楼主没有说明白一些细节问题,因为所以就直接跳转过去讲了
    您需要登录后才可以回帖 登录 | 注册[Register]

    本版积分规则 警告:禁止回复与主题无关内容,违者重罚!

    快速回复 收藏帖子 返回列表 搜索

    RSS订阅|小黑屋|联系我们|北京pk10最稳办法 ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

    GMT+8, 2019-11-15 14:03

    Powered by Discuz!

    © 2001-2017 Comsenz Inc.

    快速回复 北京pk10最稳办法 返回列表
  • 玻利维亚发生交通事故30多人死伤 2019-11-09
  • 停车收费新政首日举报量攀升 2019-11-08
  • 指尖触碰 你我结缘丨浙江新闻4周年 我们再出发 2019-11-08
  • 图解2017:为网络空间“岁月静好” 网信工作不骛虚声 2019-10-29
  • 警方出重拳 守护个人信息安全 2019-10-25
  • 广州今年建成1500公里污水管网 2019-10-25
  • 湖南提前一年全面建立河长制 地表水水质监测总体为优 2019-10-23
  • 又高又壮的男人易患前列腺癌 2019-10-23
  • 杨梅:谣言太多伤不起 2019-10-18
  • 陈毓圭:引领新的社会阶层人士服务中国特色社会主义事业 2019-10-18
  • 快讯:博格巴破门 法国2 2019-10-13
  • “四大发明”是什么制? 2019-10-09
  • 池州:上千名幼儿及家长共同诵读古今经典(图) 2019-10-09
  • [微笑]正是因为土地是属于全民的,你个人要使用就必须付钱,不然就占了大家的便宜。 2019-10-08
  • 西部网(陕西新闻网)www.cnwest.com 2019-10-06
  • 学生党打字赚钱的方法 抢庄牛牛怎么玩 广东彩票快乐十分走势图 快乐扑克3高手交流 北京赛车开奖网站 单机三张牌炸金花下载 广东快乐十分任五规律 p3开机号云 廣東中国福利彩票36选7 x幸运赛车 极速飞艇一分钟的是不是正规 一码中特免费公开 北京pk10计划两期qq群 十一选五任八稳赚 pk10手动稳赚模式