分道扬镳

这题很好玩。首先是PEID查壳,32位的无壳程序,拖入IDA,找到关键代码

char *sub_401020()
{
  char *result; // eax@19
  char v1; // [sp+Ch] [bp-110h]@1
  char v2; // [sp+4Ch] [bp-D0h]@11
  char *v3; // [sp+50h] [bp-CCh]@1
  char v4; // [sp+54h] [bp-C8h]@1
  char v5; // [sp+5Dh] [bp-BFh]@1
  char v6; // [sp+94h] [bp-88h]@15
  char v7; // [sp+98h] [bp-84h]@1
  char v8; // [sp+99h] [bp-83h]@1
  __int16 v9; // [sp+10Dh] [bp-Fh]@1
  char v10; // [sp+10Fh] [bp-Dh]@1
  char v11; // [sp+110h] [bp-Ch]@11
  char v12; // [sp+114h] [bp-8h]@5
  int v13; // [sp+118h] [bp-4h]@4

  memset(&v1, 0xCCu, 0x110u);
  v7 = 0;
  memset(&v8, 0, 0x74u);
  v9 = 0;
  v10 = 0;
  qmemcpy(&v4, "********* *    ** * ** ** * ** ** * #* ** **** **      *********", 0x41u);
  v3 = &v5;
  printf("Please input your key:\n");
  gets(&v7);
  if ( strlen(&v7) != 22 )                      // 长度为22
  {
    printf("Sorry you are wrong!\n");
    system("pause");
    exit(1);
  }
  v13 = 0;
  do
  {
    v12 = *(&v7 + v13);
    if ( v12 != 107 && v12 != 106 && v12 != 104 && v12 != 108 )  // 只能输入这几个数
    {
      printf("Sorry you are wrong!\n");
      system("pause");
      exit(2);
    }
    v11 = *(&v7 + v13);
    v2 = v11;
    // 不同的输入对应不同的走法
    if ( v11 == 104 )
    {
      if ( --v3 < &v4 || v3 > &v6 || (result = (char *)*v3, result == (char *)42) )
      {
        printf("Sorry you are wrong!\n");
        system("pause");
        exit(3);
      }
      if ( *v3 == 35 )
      {
LABEL_41:
        printf("Good!\n");
        system("pause");
        exit(0);
      }
    }
    else if ( v2 == 106 )
    {
      v3 += 8;
      if ( v3 < &v4 || v3 > &v6 || *v3 == 42 )
      {
        printf("Sorry you are wrong!\n");
        system("pause");
        exit(3);
      }
      result = (char *)*v3;
      if ( result == (char *)35 )
        goto LABEL_41;
    }
    else if ( v2 == 107 )
    {
      v3 -= 8;
      if ( v3 < &v4 || v3 > &v6 || *v3 == 42 )
      {
        printf("Sorry you are wrong!\n");
        system("pause");
        exit(3);
      }
      result = v3;
      if ( *v3 == 35 )
        goto LABEL_41;
    }
    else
    {
      if ( ++v3 < &v4 || v3 > &v6 || *v3 == 42 )
      {
        printf("Sorry you are wrong!\n");
        system("pause");
        exit(4);
      }
      result = v3;
      if ( *v3 == 35 )
        goto LABEL_41;
    }
    ++v13;
  }
  while ( v13 < 25 );
  return result;
}

上面的代码首先给出了一段字符********* * ** * ** ** * ** ** * #* ** **** ** *********,现在要求输入一段字符串,只能包含四种字符,分别是h,j,k,l,长度是22位。这四种字符都对应一种走法。现在我们的起始地址在第十位,要求通过这几种走法,不可以经过*,走到#,我们要找的就是这样一种走法。可以通过深度优先搜索解决(DFS),遍历所有可能走法,最后跳出一种满足条件的走法,给出代码:

#include <iostream>
#include <stdio.h>
#include <string>
#include <string.h>
using namespace std;
char  num[25];
int dfsmap[70]={1,1,1,1,1,1,1,1,1,0,1,0,0,0,0,1,1,0,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,0,1,0,0,1,0,1,1,0,1,1,1,1,0,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1};
void dfs(int x,int sumn)
{
    int i,j,k;
    if(sumn==22)
    {
        if(x==36) // 满足条件就输出
        {
           for(i=0;i<=21;i++)
           {
               cout<<num[i];
           }
           cout<<endl;
        }
        return;
    }
    // 四种走法
    if(x-1>=0&&dfsmap[x-1]!=1)
    {
        num[sumn]='h';
        dfs(x-1,sumn+1);
        num[sumn]=0;
    }
    if(x+8<=63&&dfsmap[x+8]!=1)
    {
        num[sumn]='j';
        dfs(x+8,sumn+1);
        num[sumn]=0;
    }
    if(x-8>=0&&dfsmap[x-8]!=1)
    {
        num[sumn]='k';
        dfs(x-8,sumn+1);
        num[sumn]=0;
    }
    if(x+1<=63&&dfsmap[x+1]!=1)
    {
        num[sumn]='l';
        dfs(x+1,sumn+1);
        num[sumn]=0;
    }
    return;
}
int main()
{
    dfs(9,0);
    return 0;
}

结果是******kkkhhhjjjl

转自实验吧,原文作者实验吧ID chih1e