首页
社区
课程
招聘
[原创]2021看雪KCTF逆向WP
发表于: 2021-5-21 15:11 8208

[原创]2021看雪KCTF逆向WP

2021-5-21 15:11
8208

分析:

(查看添加的注释)

使用z3爆破:

拖入IDA分析:

图片描述

关键就是这个if条件里面的两个函数,后面的只是根据输入的serial序列号执行代码的正确逻辑而已

逐渐分析代码:
sub_941240函数部分:

图片描述

将一些数据加载到数组中,这里就是我们后面用到的table

这一段就是将我们的输入进行的关键转换的地方,从上面的table中找下标,然后%9 + 1之后存储到另外一个连续的地址空间(数组),并在每行的最后加上一个数字,这个数字等于用9来减去添加到那个地址空间中字符的数目(不理解的话仔细查看我添加的注释)

check_sudu函数部分:

图片描述

我们逐段进行分析:

每次循环的逻辑(共循环9次)就是,如果if判断给的本来的九宫格的每一行中元素为0,就填充我们上一个函数得到的那个连续地址空间(数组)中的元素

这一段主要就是检测每一行9个元素中是否有元素相等

这一段是检测每一列中是否有元素相等

最后一段是检测,九宫格中的小九宫是否满足:9个元素是否是互不相等且是1-9

很明显第二个函数就是用来检测将我们的数据填充之后的9*9数组是否满足数独

得到:

图片描述

最后得到序列号serial为:
:u$YBPf2pa]Dt4#QM^H4ic'j0`w2y{d-Zzo2%/n_s@+2<UW)e4AR;F.4=-qEkvC2

 
int __cdecl main(int argc, const char **argv, const char **envp)
{
  char input_element; // al
  int input_index; // esi
  int table_index; // ecx
  int v7; // edx
  int v8; // eax
  unsigned int col_index; // ecx
  int v10; // eax
  int i; // edx
  int v12; // eax
  char *v13; // eax
  char *addr; // eax
  int judge_number; // edx
  char *line_end_addr; // ecx
  int v17; // eax
  int v18; // eax
  int v19; // eax
  int v20; // [esp+1Ch] [ebp-60h]
  unsigned int line_index; // [esp+20h] [ebp-5Ch]
  unsigned int v22; // [esp+24h] [ebp-58h]
  char table_element; // [esp+2Bh] [ebp-51h]
  int v24; // [esp+2Ch] [ebp-50h]
  char input_code[76]; // [esp+30h] [ebp-4Ch] BYREF
 
  sub_40AD70();
  sub_4AF840((int)&dword_4B8860, "Input your code: ");
  sub_4B0AB0((int)&dword_4B8680, input_code);   // 输入
  if ( strlen(input_code) <= 0x30 )             // 长度小于48
  {
    input_element = input_code[0];              // code首字符
    if ( input_code[0] )
    {
      input_index = 0;
      line_index = 0;
      v22 = 0;
      v24 = dword_4B7020;                       // v24 = 0x24(36)
      table_element = table[0];                 // '0'-'9''A'-'Z'(总共36个字符)
LABEL_4:
      if ( v24 > 0 )                            // 当v24>0时执行,必执行
      {
        table_index = 0;
        if ( table_element == input_element )   // 当输入的code的字符是table中的字符的时候
        {
LABEL_11:
          v7 = (input_index + table_index / 6) % 6;
          v8 = table_index + input_index;
          col_index = v22;
          v20 = v7;
          v10 = 5 - v8 % 6;                     // 这里v10最开始进入时是由v8更新的
          for ( i = 0; ; i = 1 )                // 这个循环会执行两次,第一次i=0执行完了之后i才会更新为1
                                                // 然后for循环里面那有个判断条件if(i==1)里面有两个goto,必然会执行一个
                                                // 就说明第二次执行for循环的时候才会退出,第一次循环结束后v10是被v20更新的
          {
            switch ( v10 )
            {
              case 1:
                ++col_index;                    // 列数加一,即往右移
                break;
              case 2:
                v17 = (line_index++ & 1) == 0// 当行为奇行时(比如说第一行,下标为0的行),行列都要加一,即往右下角移动
                col_index += v17;               // 当行为偶行时(比如说第二行,下标为1的行),只是行加一,即往下移
                break;
              case 3:
                v12 = (line_index++ & 1) != 0// 当行为奇行时(比如说第一行,下标为0的行),行加一,即往下移
 
                col_index -= v12;               // 当行为偶行时(比如说第二行,下标为1的行),行+1,列-1,即往左下角移
                break;
              case 4:
                --col_index;                    // 列数减一,即往左移
                break;
              case 5:
                v19 = (line_index-- & 1) != 0// 当行为奇行时(比如说第3行,下标为2的行),行数减一,即向上移
                col_index -= v19;               // 当行为偶行时(比如说第4行,下标为3的行),行列都减一,即往左上角移
                break;
              default:
                v18 = (line_index-- & 1) == 0// 当行为奇行时(比如说第3行,下标为2的行),行减一,列加一,即往右上角移
                col_index += v18;               // 当行为偶行时(比如说第4行,下标为3的行),行减一,即往上移
                break;
            }
            if ( col_index > 9 )                // 规定了列数的下标不能大于9,说明每列就10个元素
              break;
            if ( line_index > 8 )               // 规定了行数的下标不能超过8,就说明有9
              break;
            v13 = &maze[10 * line_index + col_index];// 取数组中元素对应的地址赋给v13
            if ( *v13 )                         // 这里就是迷宫
              break;
            *v13 = 1;                           // 意思就是每走一步,走到哪就把那个位置填为1
            if ( i == 1 )
            {
              ++input_index;
              v22 = col_index;
              input_element = input_code[input_index];
              if ( input_element )
                goto LABEL_4;
              goto LABEL_19;
            }                                   // 每个输入的code的字符都执行完了上面的过程,才执行这个goto LABEL_19
                                                // LABEL_19是最后要执行的
            v10 = v20;
          }
        }
        else
        {
          while ( v24 != ++table_index )
          {
            if ( table[table_index] == input_element )// 若发现table中字符和输入的code的字符相等,v5是对应的index
              goto LABEL_11;
          }
        }
      }                                         // if ( v24 > 0 )的}
    }                                           // if ( v25[0] )的}
    else
    {
LABEL_19:
      addr = maze;                              // 先取迷宫的首地址赋给addr
      judge_number = 0;
      do                                        // 这两个嵌套的dowhile循环意思就是判断迷宫是不是全部被填为1
      {
        line_end_addr = addr + 10;              // 取每一行的最后一个的地址给v16
        do
          judge_number += *addr++ == 0;         // 下面v15要为0,那么说明addr地址对应的值要全为1
        while ( line_end_addr != addr );        // 这个do while是当每一行没完的时候循环,用每一行的最后一个元素的地址判断的
      }
      while ( &unk_4B70DA != (_UNKNOWN *)line_end_addr );// 这个do while是当迷宫没走完的时候循环,用迷宫的最后一个地址来进行判断的
      if ( !judge_number )                      // 当v15为0的时候
      {
        sub_4ABF30(&dword_4B8860, (int)"Good job!", 9);
        sub_4AD980(&dword_4B8860);
        return 0;
      }
    }
  }
  sub_4ABF30(&dword_4B8860, (int)"Try again...", 12);// 如果长度不满足(strlen(v25) <= 0x30)则执行
  sub_4AD980(&dword_4B8860);
  return 0;
}
int __cdecl main(int argc, const char **argv, const char **envp)
{
  char input_element; // al
  int input_index; // esi
  int table_index; // ecx
  int v7; // edx
  int v8; // eax
  unsigned int col_index; // ecx
  int v10; // eax
  int i; // edx
  int v12; // eax
  char *v13; // eax
  char *addr; // eax
  int judge_number; // edx
  char *line_end_addr; // ecx
  int v17; // eax
  int v18; // eax
  int v19; // eax
  int v20; // [esp+1Ch] [ebp-60h]
  unsigned int line_index; // [esp+20h] [ebp-5Ch]
  unsigned int v22; // [esp+24h] [ebp-58h]
  char table_element; // [esp+2Bh] [ebp-51h]
  int v24; // [esp+2Ch] [ebp-50h]
  char input_code[76]; // [esp+30h] [ebp-4Ch] BYREF
 
  sub_40AD70();
  sub_4AF840((int)&dword_4B8860, "Input your code: ");
  sub_4B0AB0((int)&dword_4B8680, input_code);   // 输入
  if ( strlen(input_code) <= 0x30 )             // 长度小于48
  {
    input_element = input_code[0];              // code首字符
    if ( input_code[0] )
    {
      input_index = 0;
      line_index = 0;
      v22 = 0;
      v24 = dword_4B7020;                       // v24 = 0x24(36)
      table_element = table[0];                 // '0'-'9''A'-'Z'(总共36个字符)
LABEL_4:
      if ( v24 > 0 )                            // 当v24>0时执行,必执行
      {
        table_index = 0;
        if ( table_element == input_element )   // 当输入的code的字符是table中的字符的时候
        {
LABEL_11:
          v7 = (input_index + table_index / 6) % 6;
          v8 = table_index + input_index;
          col_index = v22;
          v20 = v7;
          v10 = 5 - v8 % 6;                     // 这里v10最开始进入时是由v8更新的
          for ( i = 0; ; i = 1 )                // 这个循环会执行两次,第一次i=0执行完了之后i才会更新为1
                                                // 然后for循环里面那有个判断条件if(i==1)里面有两个goto,必然会执行一个
                                                // 就说明第二次执行for循环的时候才会退出,第一次循环结束后v10是被v20更新的
          {
            switch ( v10 )
            {
              case 1:
                ++col_index;                    // 列数加一,即往右移
                break;
              case 2:
                v17 = (line_index++ & 1) == 0// 当行为奇行时(比如说第一行,下标为0的行),行列都要加一,即往右下角移动
                col_index += v17;               // 当行为偶行时(比如说第二行,下标为1的行),只是行加一,即往下移
                break;
              case 3:
                v12 = (line_index++ & 1) != 0// 当行为奇行时(比如说第一行,下标为0的行),行加一,即往下移
 
                col_index -= v12;               // 当行为偶行时(比如说第二行,下标为1的行),行+1,列-1,即往左下角移
                break;
              case 4:
                --col_index;                    // 列数减一,即往左移
                break;
              case 5:
                v19 = (line_index-- & 1) != 0// 当行为奇行时(比如说第3行,下标为2的行),行数减一,即向上移
                col_index -= v19;               // 当行为偶行时(比如说第4行,下标为3的行),行列都减一,即往左上角移
                break;
              default:
                v18 = (line_index-- & 1) == 0// 当行为奇行时(比如说第3行,下标为2的行),行减一,列加一,即往右上角移
                col_index += v18;               // 当行为偶行时(比如说第4行,下标为3的行),行减一,即往上移
                break;
            }
            if ( col_index > 9 )                // 规定了列数的下标不能大于9,说明每列就10个元素
              break;
            if ( line_index > 8 )               // 规定了行数的下标不能超过8,就说明有9
              break;
            v13 = &maze[10 * line_index + col_index];// 取数组中元素对应的地址赋给v13
            if ( *v13 )                         // 这里就是迷宫
              break;
            *v13 = 1;                           // 意思就是每走一步,走到哪就把那个位置填为1
            if ( i == 1 )
            {
              ++input_index;
              v22 = col_index;
              input_element = input_code[input_index];
              if ( input_element )
                goto LABEL_4;
              goto LABEL_19;
            }                                   // 每个输入的code的字符都执行完了上面的过程,才执行这个goto LABEL_19
                                                // LABEL_19是最后要执行的
            v10 = v20;
          }
        }
        else
        {
          while ( v24 != ++table_index )
          {
            if ( table[table_index] == input_element )// 若发现table中字符和输入的code的字符相等,v5是对应的index
              goto LABEL_11;
          }
        }
      }                                         // if ( v24 > 0 )的}
    }                                           // if ( v25[0] )的}
    else
    {
LABEL_19:
      addr = maze;                              // 先取迷宫的首地址赋给addr
      judge_number = 0;
      do                                        // 这两个嵌套的dowhile循环意思就是判断迷宫是不是全部被填为1
      {
        line_end_addr = addr + 10;              // 取每一行的最后一个的地址给v16
        do
          judge_number += *addr++ == 0;         // 下面v15要为0,那么说明addr地址对应的值要全为1
        while ( line_end_addr != addr );        // 这个do while是当每一行没完的时候循环,用每一行的最后一个元素的地址判断的
      }
      while ( &unk_4B70DA != (_UNKNOWN *)line_end_addr );// 这个do while是当迷宫没走完的时候循环,用迷宫的最后一个地址来进行判断的
      if ( !judge_number )                      // 当v15为0的时候
      {
        sub_4ABF30(&dword_4B8860, (int)"Good job!", 9);
        sub_4AD980(&dword_4B8860);
        return 0;
      }
    }
  }
  sub_4ABF30(&dword_4B8860, (int)"Try again...", 12);// 如果长度不满足(strlen(v25) <= 0x30)则执行
  sub_4AD980(&dword_4B8860);
  return 0;
}
# 打印出迷宫
maze = [0x53, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00,
    0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x01,
    0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00,
    0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01,
    0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01,
    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00]
for i in range(len(maze)):
    if (i+1) % 10 == 0:
        print(maze[i])
    else:
        if i != 0:
            print(maze[i], end=' ')
        else:
            print(chr(maze[i]), end=' ')
 
# 使用z3进行解题
from z3 import *
circle_one = [1, 3, 3, 1, 3, 3, 1, 0, 2, 0, 5, 5, 3, 5, 5, 1, 1, 1, 1, 3, 3, 2, 2]
circle_two = [2, 4, 2, 2, 4, 2, 1, 1, 1, 0, 0, 4, 4, 0, 0, 2, 0, 2, 2, 4, 2, 3, 1]
table = [48,49,50,51,52,53,54,55,56,57,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90]
x = Int('index')
for i in range(len(circle_one)):#每个code字符会操作两次位移
    solve(circle_one[i] == (5 - (i + x) % 6), circle_two[i] == ((i + x / 6) % 6), x >= 0, x < 36)
 
index_table = [16,19,0,31,4,21,10,4,31,20,14,31,26,35,28,31,12,23,16,19,0,0,23]
code = ''
for i in range(len(index_table)):
    code += chr(table[index_table[i]])
print("输入的序列号为: "+code)
# 打印出迷宫
maze = [0x53, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00,
    0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x01,
    0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00,
    0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01,
    0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01,
    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00]
for i in range(len(maze)):
    if (i+1) % 10 == 0:
        print(maze[i])
    else:
        if i != 0:
            print(maze[i], end=' ')
        else:
            print(chr(maze[i]), end=' ')
 
# 使用z3进行解题
from z3 import *
circle_one = [1, 3, 3, 1, 3, 3, 1, 0, 2, 0, 5, 5, 3, 5, 5, 1, 1, 1, 1, 3, 3, 2, 2]
circle_two = [2, 4, 2, 2, 4, 2, 1, 1, 1, 0, 0, 4, 4, 0, 0, 2, 0, 2, 2, 4, 2, 3, 1]
table = [48,49,50,51,52,53,54,55,56,57,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90]
x = Int('index')
for i in range(len(circle_one)):#每个code字符会操作两次位移
    solve(circle_one[i] == (5 - (i + x) % 6), circle_two[i] == ((i + x / 6) % 6), x >= 0, x < 36)
 
index_table = [16,19,0,31,4,21,10,4,31,20,14,31,26,35,28,31,12,23,16,19,0,0,23]
code = ''
for i in range(len(index_table)):
    code += chr(table[index_table[i]])
print("输入的序列号为: "+code)
 
 
if ( serial_length <= 64
    && sub_941240(serial_length, (int)serial, base_addr) == 1
    && check_sudu(base_addr, serial_length - 9) == 1 )
if ( serial_length <= 64
    && sub_941240(serial_length, (int)serial, base_addr) == 1
    && check_sudu(base_addr, serial_length - 9) == 1 )
 
arr[0] = (__int128)_mm_load_si128((const __m128i *)&xmmword_956280);
  j = 0;
  arr[1] = (__int128)_mm_load_si128((const __m128i *)&xmmword_9562A0);
  serial_index = 0;
  v11 = serial_length;
  v10 = serial;
  v14 = 113;
  arr[2] = (__int128)_mm_load_si128((const __m128i *)&xmmword_956270);
  arr[3] = (__int128)_mm_load_si128((const __m128i *)&xmmword_956290);
  arr[4] = (__int128)_mm_load_si128((const __m128i *)&xmmword_956260);// 加载进v13
  if ( serial_length <= 0 )                     // 长度不能<=0
    return 1;
  k = 0;
arr[0] = (__int128)_mm_load_si128((const __m128i *)&xmmword_956280);
  j = 0;
  arr[1] = (__int128)_mm_load_si128((const __m128i *)&xmmword_9562A0);
  serial_index = 0;
  v11 = serial_length;
  v10 = serial;
  v14 = 113;
  arr[2] = (__int128)_mm_load_si128((const __m128i *)&xmmword_956270);
  arr[3] = (__int128)_mm_load_si128((const __m128i *)&xmmword_956290);
  arr[4] = (__int128)_mm_load_si128((const __m128i *)&xmmword_956260);// 加载进v13
  if ( serial_length <= 0 )                     // 长度不能<=0
    return 1;
  k = 0;
while ( 1 )
  {
    serial_char = *(_BYTE *)(serial_index + serial);
    if ( serial_char > '0' && serial_char <= '9' )// 输入的code是数字时退出while循环
      break;
    arr_index = k;                              // 这个k决定了从arr开始偏移多少个字节开始查找
    if ( k >= 81 )                              // k不能大于等于81
      return 0;
    while ( serial_char != *((_BYTE *)arr + arr_index) )// 当输入的单个字符不等于那个arr中的字符的时候循环
                                                // 这个循环的意思就是遍历然后获取我们输入的单个字符在arr中的下标
    {
      if ( (unsigned int)++arr_index >= 81 )
        return 0;
    }
    v9 = arr_index % 9 + 1;
    if ( v9 == -1 )                             // 判断v9
      return 0;
    *a3 = v9;                                   // 从a3对应的地址开始逐渐储存我们的v9
    serial = v10;
    ++j;                                        // j是数字字符之前的其它字符的数量,也代表了a3对应的地址开始储存了多少个数据
    ++a3;                                       // a3对应的地址++
    serial_length = v11;
LABEL_13:
    if ( ++serial_index >= serial_length )
      return 1;                                 // 这里必须返回1
  }
  if ( j + serial_char == '9' )                 // 数字必须满足这个逻辑,是数字的时候(9-j就代表了这个数字之前有多少个其它字符)
  {
    j = 0;                                      // 填充了最后一个数字就将j重新置为0
    k += 9;                                     // 必须满足这个if条件,然后将arr开始查找的地方向后偏移9个字节
    goto LABEL_13;
  }                                             // 代表每行剩余了多少个位置没填就补充一个什么数字
  return -1;                                    // 如果数字没有满足这个条件就返回-1,失败
}
while ( 1 )
  {
    serial_char = *(_BYTE *)(serial_index + serial);
    if ( serial_char > '0' && serial_char <= '9' )// 输入的code是数字时退出while循环
      break;
    arr_index = k;                              // 这个k决定了从arr开始偏移多少个字节开始查找
    if ( k >= 81 )                              // k不能大于等于81
      return 0;
    while ( serial_char != *((_BYTE *)arr + arr_index) )// 当输入的单个字符不等于那个arr中的字符的时候循环
                                                // 这个循环的意思就是遍历然后获取我们输入的单个字符在arr中的下标
    {
      if ( (unsigned int)++arr_index >= 81 )
        return 0;
    }
    v9 = arr_index % 9 + 1;
    if ( v9 == -1 )                             // 判断v9
      return 0;
    *a3 = v9;                                   // 从a3对应的地址开始逐渐储存我们的v9
    serial = v10;
    ++j;                                        // j是数字字符之前的其它字符的数量,也代表了a3对应的地址开始储存了多少个数据
    ++a3;                                       // a3对应的地址++
    serial_length = v11;
LABEL_13:
    if ( ++serial_index >= serial_length )
      return 1;                                 // 这里必须返回1
  }
  if ( j + serial_char == '9' )                 // 数字必须满足这个逻辑,是数字的时候(9-j就代表了这个数字之前有多少个其它字符)
  {
    j = 0;                                      // 填充了最后一个数字就将j重新置为0
    k += 9;                                     // 必须满足这个if条件,然后将arr开始查找的地方向后偏移9个字节
    goto LABEL_13;
  }                                             // 代表每行剩余了多少个位置没填就补充一个什么数字
  return -1;                                    // 如果数字没有满足这个条件就返回-1,失败
}
 
 
 
i = 0;
  v3 = &MEMORY[0x9587C4];
  do
  {
    if ( !*(v3 - 1) )
    {
      v4 = base_addr[i++];
      *(v3 - 1) = v4;
    }
    if ( !*v3 )
    {
      v5 = base_addr[i++];
      *v3 = v5;
    }
    if ( !v3[1] )
    {
      v6 = base_addr[i++];
      v3[1] = v6;
    }
    if ( !v3[2] )
    {
      v7 = base_addr[i++];
      v3[2] = v7;
    }
    if ( !v3[3] )
    {
      v8 = base_addr[i++];
      v3[3] = v8;
    }
    if ( !v3[4] )
    {
      v9 = base_addr[i++];
      v3[4] = v9;
    }
    if ( !v3[5] )
    {
      v10 = base_addr[i++];
      v3[5] = v10;
    }
    if ( !v3[6] )
    {
      v11 = base_addr[i++];
      v3[6] = v11;
    }
    if ( !v3[7] )
    {
      v12 = base_addr[i++];
      v3[7] = v12;
    }
    if ( i >= serial_length_9 )
      break;
    v3 += 9;                                    // 偏移9
  }
  while ( (int)v3 < (int)&dword_958908 );       // 一:第一个dowhile循环改变9*9数组的值(加载第一个函数处理后的数组),就是将给的数组为0的值填为对应的输入转换出来的元素
                                                // (我们解开这个数独之后,那些值可以得到,然后就可以得到那个第一函数转换之后的数组)
i = 0;
  v3 = &MEMORY[0x9587C4];
  do
  {
    if ( !*(v3 - 1) )
    {
      v4 = base_addr[i++];
      *(v3 - 1) = v4;
    }
    if ( !*v3 )
    {
      v5 = base_addr[i++];
      *v3 = v5;
    }
    if ( !v3[1] )
    {
      v6 = base_addr[i++];
      v3[1] = v6;
    }
    if ( !v3[2] )
    {
      v7 = base_addr[i++];
      v3[2] = v7;
    }
    if ( !v3[3] )
    {
      v8 = base_addr[i++];
      v3[3] = v8;
    }
    if ( !v3[4] )
    {
      v9 = base_addr[i++];
      v3[4] = v9;
    }
    if ( !v3[5] )
    {
      v10 = base_addr[i++];
      v3[5] = v10;
    }
    if ( !v3[6] )
    {
      v11 = base_addr[i++];
      v3[6] = v11;
    }
    if ( !v3[7] )
    {
      v12 = base_addr[i++];
      v3[7] = v12;
    }
    if ( i >= serial_length_9 )
      break;
    v3 += 9;                                    // 偏移9
  }
  while ( (int)v3 < (int)&dword_958908 );       // 一:第一个dowhile循环改变9*9数组的值(加载第一个函数处理后的数组),就是将给的数组为0的值填为对应的输入转换出来的元素
                                                // (我们解开这个数独之后,那些值可以得到,然后就可以得到那个第一函数转换之后的数组)
v13 = arr1_base_addr;
  index0 = 0;
  v41 = arr1_base_addr;
  while ( 2 )
  {                                             // 二:这个while循环就是检测每一行是否有相同的元素
    count = 1;
    addr = v13;
    do
    {
      index1 = count;
      if ( count < 9 )
      {
        v18 = *addr;
        while ( v18 )
        {
          v19 = arr1_base_addr[index0 + index1];
          if ( !v19 || v18 == v19 )             // 查找9个元素的后8个和每次+9后的首地址对应的值(第1个)相等的值,若有相等,则返回0
            break;                              // 不能执行这个break
          if ( ++index1 >= 9 )
            goto LABEL_30;                      // 循环检测完了第一个和另外8个是否相等之后,再goto 30
        }
        return 0;
      }
LABEL_30:
      ++count;
      ++addr;                                   // addr地址++,偏移到第二个元素,然后之后再次循环,到中间那个地方又去比较第二个元素和另外8个是否相等
    }
    while ( count < 10 );
    index0 += 9;                                // 偏移index0
    v13 = v41 + 9;
    v41 = v13;                                  // 地址向后偏移9个字节
    if ( (int)v13 < (int)&unk_958904 )          // 判断是否到达了最后的地址
      continue;
    break;
  }
  v20 = &MEMORY[0x9587E4];
  v39 = &MEMORY[0x9587E4];
v13 = arr1_base_addr;
  index0 = 0;
  v41 = arr1_base_addr;
  while ( 2 )
  {                                             // 二:这个while循环就是检测每一行是否有相同的元素
    count = 1;
    addr = v13;

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

收藏
免费 2
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//