首页
社区
课程
招聘
[原创] KCTF 2021 Win. 第二题 排排坐
发表于: 2021-11-17 23:23 21301

[原创] KCTF 2021 Win. 第二题 排排坐

HHHso 活跃值
22
2021-11-17 23:23
21301

排排坐

【摘要】

    正向检验算法还算直观,其唯一解的数学原理未知,但不妨碍我们直接爆破。


第1节 正向算法

1.1 着力点

    我们直接关注图1-1中代码,通过GetDlgItemTextA交叉索引得到。

    通过基本分析,我们得到:

(1)Hi_this_obuf_icode_len__hex2bytes 将输入的32字节长lv_code通过16进制转换胃16字节,应该注意lv_code与转换后的Hi_codeLH的差异性,如

input code hex:= "0123456789ABCDEF" +  "0123456789ABCDEF"
经过转换
inner code bin:=  1032547698BADCFE  ::  1032547698BADCFE
unsigned char inner_code_bin[0x10] = {0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, ...}
即'01'转换为0x10,'23'转换为0x32,以此类推。

(2)转换后的16字节Hi_codeLH ,我们分为codeL,codeH高低(各8字节)两部分,其中抵8字节codeL填充了codeLSalt数组;

(3)Hi_last_check函数是核心检验函数。


图1-1 着手代码片段

1.2 核心校验框架

    如Hi_last_check的伪码和图1-2,代码框架分割为四部分。

(1)第一部分,检测codeLSalt的有效性,codeLSalt大小为0x100字节,如上所述,前8字节来自输入的codeL。

(2)第二部分,对codeLSalt进行变换;

(3)第三部分,利用codeLSalt和codeH对bsuk进行变换,bsuk初始值为codeLsalt前8字节;

(4)第四部分,变换后的bsuk是否为“GoodJob~”。


图1-2 Hi_last_check主要业务逻辑

int __thiscall Hi_last_check(HWND *this, char *codeH)
{
  int lv_i; // ebp
  char *v3; // eax
  int *v4; // esi
  char *btsx; // ecx
  int v6; // edi
  _BYTE *v7; // ecx
  int v8; // edx
  char *v9; // eax
  int v10; // ecx
  int v11; // esi
  int v12; // eax
  unsigned __int8 v13; // dl
  int v14; // edi
  int v15; // eax
  int v16; // ecx
  int chi; // esi
  int i; // eax
  char v19; // dl
  char lv_a; // [esp+10h] [ebp-Ch]
  char lv_b; // [esp+11h] [ebp-Bh]
  char lv_c; // [esp+12h] [ebp-Ah]
  unsigned __int8 lv_d; // [esp+13h] [ebp-9h]
  char (*lv_gbsptr)[256]; // [esp+14h] [ebp-8h]

  //-----------------第一部分开始
  lv_a = 0;
  lv_b = 0;
  lv_c = 0;
  lv_d = 0;
  lv_i = 1;
  lv_gbsptr = Hi_gbsA;
  do
  {
    Hi_bts[0] = codeLSalt[lv_i - 1];
    Hi_bts[1] = lv_i;
    v3 = Hi_bts;
    v4 = &Hi_cns;
    btsx = &Hi_bts[Hi_cns];
    do
    {
      v6 = *v4;
      if ( *v4 > 0 )
      {
        do
        {
          v7 = btsx + 1;
          *(v7 - 1) = codeLSalt[(unsigned __int8)*v3];
          *v7 = *v3 + 1;
          btsx = v7 + 1;
          ++v3;
          --v6;
        }
        while ( v6 );
      }
      ++v4;
    }
    while ( (int)v4 < (int)&Hi_cns_end );
    v8 = 256;
    do
    {
      ++(*lv_gbsptr)[(unsigned __int8)*v3++];
      --v8;
    }
    while ( v8 );
    ++lv_i;
    ++lv_gbsptr;
  }
  while ( lv_i - 1 < 256 );
  v9 = &Hi_gbsA[0][40];
  v10 = 256;
  do
  {
    if ( *(v9 - 40) )
      ++lv_a;
    if ( *(v9 - 26) )
      ++lv_b;
    if ( *v9 )
      ++lv_c;
    if ( v9[39] )
      ++lv_d;
    v9 += 256;
    --v10;
  }
  while ( v10 );
  if ( lv_a == (char)0xA9 && lv_b == (char)0xAC && lv_c == (char)0xA7 && lv_d > 0xC8u )
  {
    //-------------------------第二部分开始
    v11 = 0;
    while ( 2 )
    {
      v12 = 0;
      while ( (unsigned __int8)codeLSalt[v12] != v11 )
      {
        if ( ++v12 >= 256 )
          goto LABEL_32;
      }
      v13 = codeLSalt[v11];
      v14 = 0;
      v15 = v11;
      if ( v11 != v13 )
      {
        do
        {
          ++v14;
          v16 = (unsigned __int8)codeLSalt[v15];
          codeLSalt[v15] = codeLSalt[v16];
          v15 = v16;
          if ( v14 >= 256 )
            return 0;
        }
        while ( v11 != (unsigned __int8)codeLSalt[v16] );
      }
      codeLSalt[v15] = v13;
LABEL_32:
      if ( ++v11 < 256 )
        continue;
      break;
    }
    //------------------------------第三部分开始
    chi = 0;
    *(_QWORD *)&bsuk = *(_QWORD *)codeLSalt;
    do
    {
      for ( i = 0; i < 8; ++i )
      {
        if ( chi >= 8 )
        {
          if ( !i || i == 7 )
            --*(&bsuk + i);
        }
        else
        {
          if ( (codeH[i] & 1) != 0 )
            v19 = *(&bsuk + i) + 1;
          else
            v19 = codeLSalt[(unsigned __int8)*(&bsuk + i)];
          *(&bsuk + i) = v19;
          codeH[i] = (unsigned __int8)codeH[i] >> 1;
        }
      }
      ++chi;
    }
    while ( chi < 9 );
    //-------------------------------第四部分开始,作最后检测校对
    if ( !Hi_strncmp(&bsuk, bsC, 8) )
    {
      MessageBoxA(this[1], bsC, Caption, 0x40u);
      return 1;
    }
  }
  return 0;
}

第2节 直接爆破

    针对核心算法操作的四个部分(忽略最后的strncmp,实际是三部分)进行爆破。

2.1 有效的codeLSalt

    如图1-3,对codeLSalt的有效性检测,实际也分为四各小步骤,基本算法描述为:

(1)定义全局变量
unsigned char codeLSalt[0x100] = {...};
unsigned char bts[0x200] = {0}; //细分各小段长度依次为 0x02+0x04+0x08+0x10+0x20+0x40+0x80+0x100+0x02 
int cns[8]={0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x00} //
unsigned char gbsA[0x100][0x100] = {...};

(2)演化
对于每个codeLSalt[i],其中i=0,1,...0xFF
bts[0]=codeLSalt[i],bts[1]=i+1; 即初始化bts最开始的两字节片段,
然后利用codeLSalt和cns,逐段衍生后续片段,直到完成bts中最后0x100大小片段的衍生

(3)统计
对于每个i对应codeLSaolt[i]衍生的最后0x100大小片段中出现的数字,进行个数统计,记录仔gbsA[i]中,


(3.1)举例说明

假如codeSalt[0x100]={
  0x4B,0x6D,0x28,0x8C,0xFB,0xD2,0x1E,0xA3,0xA2,0x9B,0xF4,0xDF,0xAC,0x7C,0xA1,0xC6,
  0x16,0xD0,0x0F,0xDD,0xDC,0x73,0xC5,0x6B,0xD1,0x96,0x47,0xC2,0x26,0x67,0x4E,0x41,
  0x82,0x20,0x56,0x9A,0x6E,0x33,0x92,0x88,0x29,0xB5,0xB4,0x71,0xA9,0xCE,0xC3,0x34,
  0x50,0x59,0xBF,0x2D,0x57,0x22,0xA6,0x30,0x04,0xB2,0xCD,0x36,0xD5,0x68,0x4D,0x5B,
  0x45,0x9E,0x85,0xCF,0x9D,0xCC,0x61,0x78,0x32,0x76,0x31,0xE3,0x80,0xAD,0x39,0x4F,
  0xFA,0x72,0x83,0x4C,0x86,0x60,0xB7,0xD7,0x63,0x0C,0x44,0x35,0xB3,0x7B,0x19,0xD4,
  0x69,0x08,0x0B,0x1F,0x3D,0x11,0x79,0xD3,0xEE,0x93,0x42,0xDE,0x23,0x3B,0x5D,0x8D,
  0xA5,0x77,0x5F,0x58,0xDB,0x97,0xF6,0x7A,0x18,0x52,0x15,0x74,0x25,0x62,0x2C,0x05,
  0xE8,0x0D,0x98,0x2A,0x43,0xE2,0xEF,0x48,0x87,0x49,0x1C,0xCA,0x2B,0xA7,0x8A,0x09,
  0x81,0xE7,0x53,0xAA,0xFF,0x6F,0x8E,0x91,0xF1,0xF0,0xA4,0x46,0x3A,0x7D,0x54,0xEB,
  0x2F,0xC1,0xC0,0x0E,0xBD,0xE1,0x6C,0x64,0xBE,0xE4,0x02,0x3C,0x5A,0xA8,0x9F,0x37,
  0xAF,0xA0,0x13,0xED,0x1B,0xEC,0x8B,0x3E,0x7E,0x27,0x99,0x75,0xAB,0xFE,0xD9,0x3F,
  0xF3,0xEA,0x70,0xF7,0x95,0xBA,0x1D,0x40,0xB0,0xF9,0xE5,0xF8,0x06,0xBC,0xB6,0x03,
  0xC9,0x10,0x9C,0x2E,0x89,0x5C,0x7F,0xB1,0x1A,0xD6,0x90,0xAE,0xDA,0xE6,0x5E,0xB9,
  0x84,0xE9,0x55,0xBB,0xC7,0x0A,0xE0,0x66,0xF2,0xD8,0xCB,0x00,0x12,0xB8,0x17,0x94,
  0x6A,0x4A,0x01,0x24,0x14,0x51,0x07,0x65,0x21,0xC8,0x38,0xFD,0x8F,0xC4,0xF5,0xFC,
};



对于i=0,则有bts[0x200] = {
4B 01 
      E3 4C 6D 02 
                  BB E4 80 4D 3B 6E 28 03 
                                          75 BC
C7 E5 E8 81 AD 4E 36 3C 5D 6F 29 29 8C 04 
                                          97 76
AB BD 40 C8 0A E6 F2 E9 0D 82 A8 AE 39 4F A6 37
D5 3D 7B 5E 8D 70 B5 2A B5 2A 2B 8D FB 05 
                                          91 98
F6 77 3C AC FE BE 45 41 B0 C9 F4 0B E0 E7 01 F3
D8 EA 7C 0E 98 83 BE A9 9F AF B2 3A 4F 50 6C A7
30 38 5C D6 68 3E 74 7C 19 5F A7 8E A5 71 EC B6
B4 2B EC B6 B4 2B 71 2C A7 8E FD FC D2 06 
                                          E7 92
F1 99 07 F7 7A 78 D5 3D 5A AD F5 FF D9 BF CC 46
9E 42 AF B1 F9 CA 14 F5 DF 0C 84 E1 66 E8 6D 02
24 F4 1A D9 CB EB 25 7D A1 0F F1 99 2A 84 D9 BF
E4 AA EB A0 37 B0 13 B3 CD 3B 4F 50 FA 51 23 6D
64 A8 50 31 04 39 B3 5D 7F D7 EE 69 4D 3F DB 75
25 7D 96 1A D4 60 64 A8 8A 8F E1 A6 77 72 12 ED
8B B7 1B B5 71 2C 12 ED 8B B7 1B B5 71 2C 77 72
A9 2D 64 A8 8A 8F C4 FE 8F FD 9C D3 1E 07 
                                          66 E8
53 93 4A F2 F0 9A A3 08 65 F8 15 7B 18 79 5C D6
68 3E 44 5B A8 AE 51 F6 FC 00 D6 DA 3F C0 06 CD
61 47 54 9F 85 43 37 B0 A0 B2 C8 FA E5 CB DC 15
51 F6 B9 E0 AC 0D 43 85 E9 E2 79 67 F2 E9 3B 6E
28 03 6E 25 14 F5 47 1B D6 DA F8 CC 00 EC 33 26
62 7E C1 A2 C6 10 4A F2 F0 9A B4 2B 43 85 D6 DA
3F C0 C7 E5 02 AB 00 EC 2F A1 30 38 AF B1 DD 14
ED B4 BC CE 36 3C 4F 50 FA 51 38 FB 72 52 9A 24
3B 6E 3D 65 BE A9 FA 51 59 32 FB 05 B2 3A ED B4
7B 5E 05 80 B1 D8 17 EF 93 6A AD 4E 5B 40 AE DC
97 76 33 26 62 7E 8E 97 47 1B 89 D5 69 61 3D 65
BE A9 1C 8B 09 90 E9 E2 6C A7 7A 78 5F 73 0F 13
B8 EE CA 8C 3E B8 C2 1C EC B6 77 72 A9 2D 0F 13
B8 EE CA 8C 3E B8 C2 1C EC B6 77 72 A9 2D 7A 78
5F 73 E4 AA CE 2E 3D 65 BE A9 1C 8B 09 90 95 C5
F5 FF 09 90 C4 FE 3A 9D 2E D4 4E 1F A3 08 
                                          00 00
}

因为,对于i=0,
bts[0x200]第1片段为0x02字节长,为codeLSalt[i],i+1,则对应 4B 01;
然后利用codeLSalt和cns[0] = 2,得到codeLSalt[0x4B],0x4B+1,codeLSalt[0x01],0x01+1,则对应 E3 4C 6D 02;
同理,利用codeLSalt和cns[1] = 0x04,得到BB E4 80 4D 3B 6E 28 03 ;
以此类推,直到得到最后0x100长的片段。

由最后0x100长片段,我们得到gbsA[i];
其中 gbsA[i][0] = 0x03,表示统计最后0x100长片段中0x00出现了3次,
同理,通过统计,0x01没有出现,所以gbsA[i][1]==0x00,以此类推

gbsA[i][] = {
03 00 01 01 00 02 01 00 02 03 00 00 00 01 00 02
01 00 00 02 02 02 00 01 01 00 00 02 04 00 00 01
00 00 00 00 01 01 02 00 01 00 00 01 00 02 02 01
01 00 01 02 00 00 01 01 02 00 02 02 01 03 03 02
01 00 00 03 01 00 00 03 00 00 02 00 00 00 02 01
01 04 01 01 01 00 00 00 00 01 00 02 01 00 01 02
00 02 02 00 00 04 01 01 01 01 01 00 01 00 03 00
00 00 03 02 00 00 01 02 02 02 02 02 00 00 02 00
01 00 00 00 00 03 00 00 00 01 00 02 02 00 01 00
03 00 00 02 00 01 00 02 00 00 03 00 00 01 00 01
01 01 01 02 00 00 00 01 01 05 01 01 01 01 02 01
01 02 02 00 03 00 02 00 04 01 00 00 01 00 03 00
02 01 02 00 01 01 01 01 01 00 02 01 01 01 02 00
00 00 00 00 01 01 04 00 01 00 03 00 02 01 00 00
01 00 02 00 01 02 00 00 01 03 00 00 04 02 02 01
02 00 03 00 00 02 02 00 02 00 03 02 01 00 01 01
}

(4)针对性统计,校对
针对通过所有的gbsA[i][],其中i=0,1,..0xFF
统计所有衍生的最后0x100长度片段中,0, 14, 40, 79分别出现的总此书,依次记录为a,b,c,d
要求a == 0xA9 && b == 0xAC && c == 0xA7 && d > 0xC8,如果满足,则codeLSalt有效

图1-3 codeLSalt有效性


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
免费 4
支持
分享
最新回复 (1)
雪    币: 2516
活跃值: (4154)
能力值: ( LV6,RANK:81 )
在线值:
发帖
回帖
粉丝
2
膜拜大佬
2021-11-18 18:33
0
游客
登录 | 注册 方可回帖
返回