广西CTF-labyrinth WP

前言

  • 这是一个另类的迷宫模型。在我第一次拿到手上分析的时候,因为没有注意到程序的名字,尽管代码量很小,输入和校验都比较集中,也能看懂,但依然是不知道该怎么逆。花了一天的时间,后面搜了一下 “labyrinth” 才知道是 迷宫、曲径 的意思。再结合程序的代码,一下子就确定了算法的模型——迷宫。
  • 为何说它另类,且看代码。

代码

在这里插入图片描述在这里插入图片描述

  • 在初始化函数中,随机生成了一张迷宫图。但是解是唯一的,说明迷宫图中有些地方是固定的。多运行几下,把每次生成的图做个比较,最后发现迷宫图大致如下:
{0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0} 
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} 
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} 
{0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0} 
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} 
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} 
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0}
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
{0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0}
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
{0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1}
  • 据经验,走的肯定是1的位置,但问题来了,与以往不同的地方就是1不是连续成若干条路径的。
  • 带着这个疑惑,再来分析程序的Check流程:
int __cdecl sub_4013A0(char *a1)
{
  char v2; // [sp+Ch] [bp-74h]@1
  int v3; // [sp+4Ch] [bp-34h]@11
  char *input; // [sp+50h] [bp-30h]@1
  int v5; // [sp+54h] [bp-2Ch]@23
  int v6; // [sp+58h] [bp-28h]@14
  int v7; // [sp+5Ch] [bp-24h]@11
  int v8; // [sp+60h] [bp-20h]@8
  int v9; // [sp+64h] [bp-1Ch]@4
  int v10; // [sp+68h] [bp-18h]@3
  int v11; // [sp+6Ch] [bp-14h]@3
  int column; // [sp+70h] [bp-10h]@3
  int ch1; // [sp+74h] [bp-Ch]@3
  int row; // [sp+78h] [bp-8h]@3
  int v15; // [sp+7Ch] [bp-4h]@3

  memset(&v2, 0xCCu, 0x74u);
  input = a1;
  if ( strlen(a1) & 1 )
    return 0;
  ch1 = *a1;
  v15 = 0;
  row = 0;
  column = 0;
  v11 = -1;
  v10 = 0;
  if ( !*a1 )
    goto end;
  v9 = 0;
  do
  {
    if ( ch1 < 'a' || ch1 > 'd' )
      goto LABEL_10;
    v8 = input[1] - 101;
    if ( v8 > 21 )
    {
      input = a1;
LABEL_10:
      ++v15;
      goto LABEL_19;
    }
    v7 = v11;
    v3 = ch1 - 97;
    switch ( ch1 )
    {
      case 'a':                                 // 左
        v11 = 0;
        column = (column - v8) % 22;
        v9 = *(&maze[22 * row] + column);
        break;
      case 'b':                                 // 右
        v11 = 0;
        column = (column + v8) % 22;
        goto LABEL_17;
      case 'c':                                 // 上
        v6 = row - v8;
        goto LABEL_16;
      case 'd':                                 // 下
        v6 = row + v8;
LABEL_16:
        v11 = 1;
        row = v6 % 22;
LABEL_17:
        v9 = *(&maze[22 * row] + column);
        break;
      default:
        break;
    }
    *(&maze[22 * row] + column) = 0;
    v15 = (v7 == v11) + (v9 ^ 1) + v10;
    input = a1;
LABEL_19:
    ch1 = input[2];
    input += 2;
    v10 = v15;
    a1 = input;
  }
  while ( ch1 );
  if ( row != 21 || column != 21 )
end:
    ++v15;
  v5 = v15 <= 0;
  return v15 <= 0;
}
  • 根据经验,可以分辨出 abcd 控制的是什么方向,然后从解密输出flag的函数中,可以确定输入的字符串长度为 16 字节。
    在这里插入图片描述
  • 回到Check函数中,根据逻辑,可以断定每次都必须走到 1 的位置,并且每次只能走 直线,不能有 折角,最后出口在 (21,21) 处,共走 8 个点。因此,可以确定走的路径就是
    在这里插入图片描述
  • 坐标序列:{11,0},{11,16} ,{3,16},{3,7 },{18,7},{18,11},{21,11},{21,21}

脚本

#include<iostream>

using namespace std;

struct Point {
	int x;
	int y;
};


int main()
{
	Point p[] = { {11,0},{11,16} ,{3,16},{3,7 },{18,7},{18,11},{21,11},{21,21} };
	int r = 0, c = 0;
	string ans="";
	char ch;
	for (int i = 0; i < 8; i++) {
		if (p[i].x - r>0) {//下
			cout << "d" << (char)(101 + p[i].x - r);
			r = p[i].x;
		}
		else if(p[i].x - r < 0){//上
			cout << "c" << (char)(101 - (p[i].x - r));
			r = p[i].x;
		}
		else if(p[i].y - c > 0)//向右
		{
			cout << "b" << (char)(101 + (p[i].y - c));
			c = p[i].y;
		}
		else if (p[i].y - c < 0)//向左
		{
			cout << "a" << (char)(101 - (p[i].y - c));
			c = p[i].y;
		}
	}
	cout << endl;
	return 0;
}

  • 得到key:dpbucmandtbidhbo
    在这里插入图片描述

总结

  • 在没有知道这个算法模型的情况下,逆了一天也逆不出来。究其原因就是思考的方向不对,凭空很难靠到正确思路上。说明思维很重要,像我智商不高的人做逆向主要是靠经验,这又是一次新的经验!

版权声明:本文为qq_41252520原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。