'); }

KCTF_英雄救美


这题主要是对if()内的两个函数进行分析,

image-20210915214157709第一个函数

int __usercall sub_321240@<eax>(int a1@<edx>, byte *a2@<ecx>, int *a3)
{
  int v3; // ebx
  int i; // esi
  unsigned int m; // edi
  char v6; // al
  signed int j; // ecx
  int v9; // ecx
  byte *v10; // [esp+0h] [ebp-64h]
  int v11; // [esp+4h] [ebp-60h]
  __int128 arr[5]; // [esp+Ch] [ebp-58h]
  char v14; // [esp+5Ch] [ebp-8h]

  arr[0] = (__int128)_mm_load_si128((const __m128i *)&xmmword_336280);
  v3 = 0;
  arr[1] = (__int128)_mm_load_si128((const __m128i *)&xmmword_3362A0);
  i = 0;
  v11 = a1;
  v10 = a2;
  v14 = 113;
  arr[2] = (__int128)_mm_load_si128((const __m128i *)&xmmword_336270);
  arr[3] = (__int128)_mm_load_si128((const __m128i *)&xmmword_336290);
  arr[4] = (__int128)_mm_load_si128((const __m128i *)&xmmword_336260);// 并不是顺序存储,动调获取结果
  if ( a1 <= 0 )
    return 1;
  m = 0;
  while ( 1 )
  {
    v6 = a2[i];
    if ( v6 > '0' && v6 <= '9' )
      break;
    j = m;
    if ( m >= 0x51 )
      return 0;
    while ( v6 != *((_BYTE *)arr + j) )
    {
      if ( (unsigned int)++j >= 81 )            // 获取下标
        return 0;
    }
    v9 = j % 9 + 1;                             // 存储范围:1~9
    if ( v9 == -1 )
      return 0;
    *a3 = v9;                                   // 最终结果保存到a3中
    a2 = v10;
    ++v3;
    ++a3;
    a1 = v11;
LABEL_13:
    if ( ++i >= a1 )                            //说明要遍历一遍输入的值,判断是否符合条件
      return 1;
  }
  if ( v3 + v6 == '9' )                         // 每成功取一个值,下一次起点偏移+9
  {
    v3 = 0;
    m += 9;                                     // 9个为一组
    goto LABEL_13;
  }
  return -1;
}

目前还不能看出究竟在做什么,

第二个函数

可以知道这是一个数独

它先是将第一个函数获取的内容填充到数独表中

do                                            // 插入由第一个函数获取的值
  {
    if ( !*(v3 - 1) )
    {
      v4 = *(_DWORD *)&a1[4 * v2++];
      *(v3 - 1) = v4;
    }
    if ( !*v3 )
    {
      v5 = *(_DWORD *)&a1[4 * v2++];
      *v3 = v5;
    }
    if ( !v3[1] )
    {
      v6 = *(_DWORD *)&a1[4 * v2++];
      v3[1] = v6;
    }
    if ( !v3[2] )
    {
      v7 = *(_DWORD *)&a1[4 * v2++];
      v3[2] = v7;
    }
    if ( !v3[3] )
    {
      v8 = *(_DWORD *)&a1[4 * v2++];
      v3[3] = v8;
    }
    if ( !v3[4] )
    {
      v9 = *(_DWORD *)&a1[4 * v2++];
      v3[4] = v9;
    }
    if ( !v3[5] )
    {
      v10 = *(_DWORD *)&a1[4 * v2++];
      v3[5] = v10;
    }
    if ( !v3[6] )
    {
      v11 = *(_DWORD *)&a1[4 * v2++];
      v3[6] = v11;
    }
    if ( !v3[7] )
    {
      v12 = *(_DWORD *)&a1[4 * v2++];
      v3[7] = v12;
    }
    if ( v2 >= a2 )
      break;
    v3 += 9;                                    // +9说明9个数据为一行
  }
  while ( (int)v3 < (int)&ByteEnd );            // 结束位置

然后分别进行判断

行判断

 while ( 2 )                                   // 判断每一行的值是否都不相等
  {
    v15 = 1;
    v16 = v13;
    do
    {
      v17 = v15;
      if ( v15 < 9 )
      {
        v18 = *v16;
        while ( v18 )
        {
          v19 = ByteStart[v14 + v17];
          if ( !v19 || v18 == v19 )             // 同一排的值不能相等
            break;
          if ( ++v17 >= 9 )
            goto LABEL_30;
        }
        return 0;
      }
LABEL_30:
      ++v15;
      ++v16;
    }
    while ( v15 < 10 );                         // 一共81位
    v14 += 9;
    v13 = v41 + 9;
    v41 = v13;
    if ( (int)v13 < (int)&unk_338904 )
      continue;
    break;
  }

列判断

while ( 2 )                                   // 判断每一列的值是否都不相等
  {
    v21 = 1;
    v42 = v20;
    v22 = v20 - 9;
    v23 = v20;
    do
    {
      v24 = v21;
      if ( v21 < 9 )
      {
        v25 = *v22;
        while ( v25 && *v23 && v25 != *v23 )    // 比较
        {
          ++v24;
          v23 += 9;
          if ( v24 >= 9 )
          {
            v23 = v42;
            goto LABEL_41;
          }
        }
        return 0;
      }
LABEL_41:
      ++v21;
      v23 += 9;
      v22 += 9;
      v42 = v23;
    }
    while ( v21 < 10 );
    v20 = v39 + 4;
    v39 = (char *)v20;
    if ( (int)v20 < (int)&unk_338808 )
      continue;
    break;
  }

小九宫格判断

LABEL_45:                                       // 这里开始到最后,判断每个小九宫格是否每个数都不一致
    i = 0;
LABEL_46:
    *(_QWORD *)v26 = 0i64;
    v26[4] = 0;
    if ( !__OFSUB__(v27, v27 + 3) )             // 减
    {
      v30 = 3;
      v31 = &ByteStart[j + i];
      v40 = 3;
      do
      {
        if ( !__OFSUB__(i, i + 3) )
        {
          v32 = v31;                            // 取byte[]
          v33 = 3;
          do
          {
            v34 = *v32++;                       // byte[i++]
            ++*((_BYTE *)v26 + v34);            // v34++
            --v33;
          }
          while ( v33 );
          v30 = v40;
        }
        v31 += 9;                               // 一排一排的查看
        v40 = --v30;
      }
      while ( v30 );
      v27 = v43;
      j = v38;
    }
    if ( !*(_BYTE *)v26 )
    {
      v35 = 0;
      v36 = 1;
      while ( *((char *)v26 + v36) <= 1 )
      {
        ++v36;
        ++v35;
        if ( v36 >= 10 )
        {
          if ( v35 != 9 )
            break;
          i += 3;
          if ( i < 9 )
            goto LABEL_46;
          j += 27;
          v27 += 3;
          v43 = v27;
          v38 = j;
          if ( j < 81 )
            goto LABEL_45;
          free(v26);
          return 1;                             // 当所有判断都成立后,返回1
        }
      }
    }
    free(v26);
  }
  return 0;

两个函数总的意思:将输入的值获取处于指定字符串中的下标,然后转换成1~9之间的数,并填充到数独表中,然后进行数独的行,列以及小九宫格的判断

解题

通过网上的数独在线工具,获得内容

image-20210915215952353

然后就快乐的搓脚本

arr=[0x24, 0x42, 0x50, 0x56, 0x3A, 0x75, 0x62, 0x66, 0x59, 0x70, 
  0x7D, 0x5D, 0x44, 0x74, 0x4E, 0x3E, 0x61, 0x54, 0x5E, 0x4D, 
  0x47, 0x6D, 0x4A, 0x51, 0x23, 0x2A, 0x48, 0x72, 0x60, 0x4F, 
  0x27, 0x77, 0x6A, 0x69, 0x63, 0x30, 0x21, 0x68, 0x64, 0x79, 
  0x7B, 0x6F, 0x5A, 0x7A, 0x2D, 0x40, 0x6E, 0x2B, 0x3F, 0x26, 
  0x25, 0x73, 0x5F, 0x2F, 0x67, 0x3C, 0x65, 0x5B, 0x57, 0x29, 
  0x58, 0x55, 0x78, 0x52, 0x46, 0x53, 0x4C, 0x52, 0x41, 0x3B, 
  0x2E, 0x6C, 0x3D, 0x43, 0x45, 0x6B, 0x76, 0x4B, 0x2D, 0x28, 
  0x71, 0xF7, 0x2A]
sudu=[[5,6,1,9,2,3,8],[1,8,3,4,5],[7,6,2,1,9],[7,8,4,6,9,2,5],[4,5,3,9,7,8,6],[6,9,2,8,7,1,3],[2,8,5,6,3],[6,1,7,2,8],[1,7,9,3,4,5,2]]
for i in range(len(sudu)):
    tmp=len(sudu[i])
    for j in range(tmp):
        for x in range(i*9,len(arr)):
            if(x%9+1==sudu[i][j]):
                print(chr(arr[x]),end="")
                break
    print(9-tmp,end="")

获得flag:

:u$YBPf2pa]Dt4#QM^H4ic'j0`w2y{d-Zzo2%/n_s@+2<UW)e4AR;F.4=-qEkvC2

  目录