首页
社区
课程
招聘
[原创]第二题 南冥神功
发表于: 2021-5-12 15:38 4920

[原创]第二题 南冥神功

2021-5-12 15:38
4920

IDA分析,结构很清晰。

for循环两次,正确的情况下,输入的一个字符将会把byte_4B7080两个不同地方的0变为1

让我有许多疑惑的就是for循环中的switch结构,一开始我猜测byte_4B7080是一个迷宫数据,然后我被v9v21给迷惑住了,以为迷宫是v9*v21的一个长度,但这显然与最后的判定循环次数为90次不符,然后又猜测是不是v9*10,这样确实是符合了数据长度,接下来我以9*10的形式dumpbyte_4B7080数据:

这个迷宫数据很特别,要怎么走取决于switch结构的运算,在动态调试的时候也不是很明白switch中控制的方向如何,它不是常见的上、下、左、右四种方向,尤其是switch中的位运算,给我一种乱糟糟的感觉。我看不懂方向,所以没法手动去画出路线,这是一个拖我节奏的地方了。也正是看不懂方向,甚至让我怀疑这不是一道迷宫题,而只是另一种算法题——要求在位置不重复的情况下,通过switch结构,将byte_4B7080序列中的0全变为1

然后,我将伪代码翻译成python代码,并在某些地方做了一些剪枝,试图利用递归去解决这个问题。我通过计数byte_4B7080中的0确定了输入的长度为23。下面是我的解题脚本:

很遗憾,我算法太弱了,这道题我卡在了算法和逆向走迷宫的方向上,超时了2个半小时才解出来,比赛中没能做出来。T口T.

int __cdecl main(int argc, const char **argv, const char **envp)
{
...
  printf_0((int)&dword_4B8860, "Input your code: ");
  scanf((int)&dword_4B8680, input);//接受用户输入
  if ( strlen(input) <= 0x30 )//长度不能超过0x30
  {
    v3 = input[0];
    if ( input[0] )
    {
      v4 = 0;
      v21 = 0;
      v22 = 0;
      v24 = dword_4B7020;                       // 0x24
      v23 = byte_4B7040[0];
LABEL_4:
      if ( v24 > 0 )
      {
        v5 = 0;
        if ( v23 == v3 )
        {
LABEL_11:                        //这是一个循环结构的循环首,循环次数为input的长度
          v7 = (v4 + v5 / 6) % 6;
          v8 = v5 + v4;
          v9 = v22;
          v20 = v7;
          v10 = 5 - v8 % 6;
          for ( i = 0; ; i = 1 )//实际循环两次
          {
            switch ( v10 )
            {
              case 1:
                ++v9;
                break;
              case 2:
                v17 = (v21++ & 1) == 0;
                v9 += v17;
                break;
              case 3:
                v12 = (v21++ & 1) != 0;
                v9 -= v12;
                break;
              case 4:
                --v9;
                break;
              case 5:
                v19 = (v21-- & 1) != 0;
                v9 -= v19;
                break;
              default:
                v18 = (v21-- & 1) == 0;
                v9 += v18;
                break;
            }
            if ( v9 > 9 )//v9大于9结束最外层循环
              break;
            if ( v21 > 8 )//v21大于8结束最外层循环
              break;
            v13 = &byte_4B7080[10 * v21 + v9];
            if ( *v13 )                         // 这里的v13必须==0,否则直接转到输出Try again!
              break;
            *v13 = 1;//修改byte_4B7080[10 * v21 + v9]=1,标志该地方已经走过
            if ( i == 1 )
            {
              ++v4;//最外层循环的控制变量
              v22 = v9;
              v3 = input[v4];//依次取出input
              if ( v3 )
                goto LABEL_4;//到循环首
              goto LABEL_19;//到判定结果的起始位置
            }
            v10 = v20;
          }
        }
        else
        {
          while ( v24 != ++v5 )
          {
            if ( byte_4B7040[v5] == v3 )
                //v3是input中的某个字符,该循环实际是取得v3字符在byte_4B7040中的下标位置
                //如果v3不存在byte_4B7040中,那么直接转到输出Try again
              goto LABEL_11;
          }
        }
      }
    }
    else
    {
LABEL_19:
      v14 = byte_4B7080;
      v15 = 0;
      do
      {
        v16 = v14 + 10;
        do
          v15 += *v14++ == 0;
        while ( v16 != v14 );//循环10
      }                                         // 内层循环表示v14[0:10]全为1
      while ( &dword_4B70DA != (_UNKNOWN *)v16 );//一共循环90
      //所以判定输入正确的条件为byte_4B7080[0:90]均为1
      if ( !v15 )
      {
        sub_4ABF30(&dword_4B8860, "Good job!", 9);
        sub_4AD980(&dword_4B8860);
        return 0;
      }
    }
  }
  sub_4ABF30(&dword_4B8860, "Try again...", 12);
  sub_4AD980(&dword_4B8860);
  return 0;
}
int __cdecl main(int argc, const char **argv, const char **envp)
{
...
  printf_0((int)&dword_4B8860, "Input your code: ");
  scanf((int)&dword_4B8680, input);//接受用户输入
  if ( strlen(input) <= 0x30 )//长度不能超过0x30
  {
    v3 = input[0];
    if ( input[0] )
    {
      v4 = 0;
      v21 = 0;
      v22 = 0;
      v24 = dword_4B7020;                       // 0x24
      v23 = byte_4B7040[0];
LABEL_4:
      if ( v24 > 0 )
      {
        v5 = 0;
        if ( v23 == v3 )
        {
LABEL_11:                        //这是一个循环结构的循环首,循环次数为input的长度
          v7 = (v4 + v5 / 6) % 6;
          v8 = v5 + v4;
          v9 = v22;
          v20 = v7;
          v10 = 5 - v8 % 6;
          for ( i = 0; ; i = 1 )//实际循环两次
          {
            switch ( v10 )
            {
              case 1:
                ++v9;
                break;
              case 2:
                v17 = (v21++ & 1) == 0;
                v9 += v17;
                break;
              case 3:
                v12 = (v21++ & 1) != 0;
                v9 -= v12;
                break;
              case 4:
                --v9;
                break;
              case 5:
                v19 = (v21-- & 1) != 0;
                v9 -= v19;
                break;
              default:
                v18 = (v21-- & 1) == 0;
                v9 += v18;
                break;
            }
            if ( v9 > 9 )//v9大于9结束最外层循环
              break;
            if ( v21 > 8 )//v21大于8结束最外层循环
              break;
            v13 = &byte_4B7080[10 * v21 + v9];
            if ( *v13 )                         // 这里的v13必须==0,否则直接转到输出Try again!
              break;
            *v13 = 1;//修改byte_4B7080[10 * v21 + v9]=1,标志该地方已经走过
            if ( i == 1 )
            {
              ++v4;//最外层循环的控制变量
              v22 = v9;
              v3 = input[v4];//依次取出input
              if ( v3 )
                goto LABEL_4;//到循环首
              goto LABEL_19;//到判定结果的起始位置
            }
            v10 = v20;
          }
        }
        else
        {
          while ( v24 != ++v5 )
          {
            if ( byte_4B7040[v5] == v3 )
                //v3是input中的某个字符,该循环实际是取得v3字符在byte_4B7040中的下标位置
                //如果v3不存在byte_4B7040中,那么直接转到输出Try again
              goto LABEL_11;
          }
        }
      }
    }
    else
    {
LABEL_19:
      v14 = byte_4B7080;
      v15 = 0;
      do
      {
        v16 = v14 + 10;
        do

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

最后于 2021-5-14 21:08 被kanxue编辑 ,原因:
收藏
免费 1
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//