Skip to main content

xctf2020-高校战役

·500 words·3 mins
Table of Contents

xctf-cycle graph #

没有其他乱七八糟的东西,就是算法


int __usercall sub_401080@(char a1@)
{
  void *Graph; // ecx@1
  int v2; // edx@1
  int v3; // eax@2
  signed int t; // edx@3
  char b; // al@3
  signed int i; // edi@3
  int a; // ecx@3
  const char *v8; // eax@17
  char v10; // [sp-Ch] [bp-30h]@3
  int x; // [sp+0h] [bp-24h]@4
  char flag; // [sp+8h] [bp-1Ch]@3
  char v13; // [sp+9h] [bp-1Bh]@10
  char v14; // [sp+Ah] [bp-1Ah]@11
  char v15; // [sp+Bh] [bp-19h]@12
  char v16; // [sp+Ch] [bp-18h]@13
  char v17; // [sp+1Dh] [bp-7h]@14

  ::t = 0;
  Graph = &unk_403384;
  ::b = 48;
  v2 = 0;
  ::a = (int)&address;
  do
  {
    v3 = root[v2];
    ++v2;
    *((_DWORD *)Graph - 1) = v3;
    *(_DWORD *)Graph = (char *)&address + 12 * branch1[v2];
    *((_DWORD *)Graph + 1) = (char *)&address + 12 * branch2[v2];
    Graph = (char *)Graph + 12;
  }
  while ( (signed int)Graph < (signed int)&end );//生成图
  sub_401020("You need a flag to get out of this:\n", a1);
  sub_401050("%s", (unsigned int)&flag);
  t = ::t;
  b = ::b;
  i = 5;
  a = ::a;
  do
  {
    x = *(&flag + i);
    if ( *(_DWORD *)a + b == x )//将根的信息与flag比较
    {
      a = *(_DWORD *)(a + 4);//走 branch1 、更新根的地址
    }
    else
    {
      if ( b - *(_DWORD *)a != x )
      {
        sub_401020("This is not flag~\n", v10);
        system("pause");
        exit(1);
      }
      a = *(_DWORD *)(a + 8);//走 branch2 、更新根的地址
    }
    b = *(&flag + i);
    ++t;
    ++i;
    ::b = b;
    ::a = a;
    ::t = t;
  }
  while ( i < 21 );
  if ( flag != 102 || v13 != 108 || v14 != 97 || v15 != 103 || v16 != 123 || v17 != 125 )
  {
    v8 = "illegal input~\n";
  }
  else if ( t > 16 || (_UNKNOWN *)a != &end1 )//判断位置
  {
    v8 = "This is not flag~\n";
  }
  else
  {
    v8 = "Congratulations!!\n";
  }
  sub_401020(v8, x);
  system("pause");
  return 0;
}

这个图的结构还是有点意思,把一个大数组三个三个分开形成根节点和有向的路:


  0      1      3        ......
root  branch1  branch2   ......

拿到图的第一个反应就是该题不限步数的话一定有多解,完了还要还要检查ascii码的范围,最后我还是决定用寻路算法常用的递归

撸代码: #


#include <iostream>
#include <stdlib.h>
using namespace std;
int root[90] = {0x34, 0x2, 0x2c, 0x2a, 0x6, 0x2a, 0x2f, 0x2a, 0x33, 0x3, 0x2, 0x32, 0x32, 0x32, 0x30, 0x3, 0x1, 0x32, 0x2b, 0x2, 0x2e, 0x1, 0x2, 0x2d, 0x32, 0x4, 0x2d, 0x30, 0x31, 0x2f, 0x33, 0x5};
int b1[90] = {0x2, 0x2, 0x1, 0x12, 0x7, 0x2, 0x1a, 0xd, 0x4, 0xa, 0x4, 0x15, 0xe, 0x1, 0x0, 0xe, 0x5, 0x7, 0x1c, 0xc, 0x1c, 0xf, 0xf, 0x2, 0x10, 0x17, 0x1e, 0x17, 0x13, 0x9, 0x16, 0x1f};
int b2[90] = {0x1, 0x8, 0x7, 0x17, 0x9, 0x13, 0x1f, 0x17, 0x9, 0xd, 0xc, 0x1d, 0xa, 0x18, 0x9, 0x18, 0x19, 0x9, 0x1a, 0x3, 0x16, 0x6, 0x11, 0xd, 0x7, 0xf, 0x14, 0x1, 0x10, 0x4, 0xb, 0x1f};
int b[90];
int ans[90];
int dir[90];
int flag[90];
void cheak()
{
    int a = 48;
    int c;
    for(int i=0;i<16;i++)
    {
        if(dir[i] == 1)
        {
            c = a + b[i];
            if (c<33 || c>126)
                return;
        }
        if(dir[i] == 2)
        {
            c = a - b[i];
            if (c<33 || c>126)
                return;
        }
        a = c;
        flag[i]=c;
    }
    cout<<"flag{";
    for(int i=0;i<16;i++)
    {   
        printf("%c",flag[i]);
    }
    cout<<"}";
    cout<

万万没想到终点的两个有向路居然指向自己,所以算出来确实有两个解,由于代码过于抽\象才过一天就已经快看不懂了。