xctf-高校战疫-re-Cycle

admin 2022年1月5日23:10:33评论53 views字数 2847阅读9分29秒阅读模式

>

>

xctf-高校战疫-re-Cycle

yuchoxuuan

水平太烂了,就答了这一个题。。。
先拖dia,找字符串
xctf-高校战疫-re-Cycle
ctrl+x 然后F5
先说一下整个题大概的意思,他先是搭建了一个迷宫(或者叫有向图吧),然后用你输入的flag在迷宫里按照他的算法走,如果能走够足够的步数,且走到制定地点那就算OK了。
而迷宫的大概存储结构是酱紫的

入口:(地址是:0xBB3378)
节点1  
       节点数值
       路径1的地址
       路径2的地址
节点2
      节点数值
      ……

简而言之就是一大堆 数字,地址,地址,平铺在一起。
然后看代码

xctf-高校战疫-re-Cycle
可能是构建迷宫的代码,没细看
xctf-高校战疫-re-Cycle
提示输入flag
接下来的代码酱紫的

v4 = dword_403370;  //这是个计数器,显示你走了多少步,后来用得着
  v5 = byte_403374;  //这是个临时变量,用于存储上一步的时候你的flag是啥
  v6 = 5; // 正在测试的字符在flag中的位置,初始化为5,
              //是因为flag{xxxxx}里面很显然是 flag【5】开始才是需要测试的
  v7 = dword_403378; //初始化为 迷宫入口
  //v7 的作用是指示当前我们在迷宫里面的位置,他是指向上面说的某个节点的
  //所以 v7 => 当前节点值
  //        v7+4 => 下一步的节点的的地址1
  //        v7+8 => 下一步的节点的地址2 
  //   也就是说,是两条岔路指向的节点地址,为啥是+4+8 因为他用的_Dword 鸭,四字节
  do
  {
    v11 = *(&flag + v6);   // 等同于 v11 = flag[6]  取得当前测试字符
    if ( *(_DWORD *)v7 + v5 == v11 )  //如果 当前节点+ 上一个字符 = 现在的字符,那么走第一条路
    {
      v7 = *(_DWORD *)(v7 + 4); //将当前位置指针替换为 v7+4的路径1
    }
    else //如果第一条路条件不符合咋整呢?
    {
      if ( v5 - *(_DWORD *)v7 != v11 ) // 上一个字符-当前节点值 = 现在的字符,那么走第二条路 否则,测试失败。
      {
        sub_401020("This is not flag~\n", v10);
        system("pause");
        exit(1);
      }
      v7 = *(_DWORD *)(v7 + 8);
    }
    
    v5 = *(&flag + v6); //把当前字符存到v5 就是咱前面说的,v5存放上一步的字符
                                  // 程序走到这一部 v7已经更新了,所以这一步就变成了上一步。。
    ++v4;
    ++v6;
    byte_403374 = v5;
    dword_403378 = v7; 
    dword_403370 = v4; 
  }
  while ( v6 < 21 ); //这说明必须在21-5=16步之内走出去,否则也别走了。。也就是说 flag体的长度最多16位

走出迷宫之后咋整了

 if ( flag != 102 || v13 != 108 || v14 != 97 || v15 != 103 || v16 != 123 || v17 != 125 )
  {//如果你的结构不是"flag{}" 就别闹了
    v8 = "illegal input~\n";
  }
  //如果v4》16 也就是说 16步之内没走出来,失败 说明flag 就是16位
  //如果v7 != &unk_4034F4 失败,说明不能光走完16步,而且要走完16步之后落在某一个数字上才算过。
  else if ( v4 > 16 || (_UNKNOWN *)v7 != &unk_4034F4 )
  {
    v8 = "This is not flag~\n";
  }
  else
  {
    v8 = "Congratulations!!\n";
  }

接下来的问题就是,
1,迷宫图是啥样的,刚才没看懂
2, &unk_4034F4 是多少。。

这些我都没看出来于是下断点动态调试。

双击v7 看内存

很显然,小数字,两个大数字(地址),小数字,两个大数字(地址)跟咱说的一样。先复制出来
记一下首地址是 3D3380,回头用
然后再看看那个&unk_4034F4
xctf-高校战疫-re-Cycle
发现是5
记下来等会用

接下来就可以模拟这个过程跑了。

#这是我刚复制出来的那堆内存数据,都是转过10进制的,和刚才看着不太一样,不过内容相同,我对Ctrl-V发誓,肯定没问题
arr = [
52, 12268440, 12268428, 2, 12268440, 12268512, 44, 12268428, 12268500, 42, 12268632, 12268692, 6, 12268500, 12268524, 42, 12268440, 12268644, 47, 12268728, 12268788, 42, 12268572, 12268692, 51, 12268464, 12268524, 3,
12268536, 12268572, 2, 12268464, 12268560, 50, 12268668, 12268764, 50, 12268584, 12268536, 50, 12268428, 12268704, 48, 12268416, 12268524, 3, 12268584, 12268704, 1, 12268476, 12268716, 50, 12268500, 12268524, 43, 12268752, 12268728, 2,
12268560, 12268452, 46, 12268752, 12268680, 1, 12268596, 12268488, 2, 12268596, 12268620, 45, 12268440, 12268572, 50, 12268608, 12268500, 4, 12268692, 12268596, 45, 12268776, 12268656, 48, 12268692, 12268428, 49, 12268644, 12268608, 47,
12268524, 12268464, 51, 12268680, 12268548, 5, 12268788, 12268788,
]
L = []
m={}
#接下来我用m={} 模拟了一下内存的状态
#结构是:{地址: 节点,地址1,地址2} 其实没啥科技含量。我相信大家都理解为意思,因为这里面没有内存地址啊所以用字典的key代表一下
for i in range(len(arr)//3):
   pos = i*3
   m[0xBB3380 + 12*i] = (arr[pos],arr[pos+1],arr[pos+2])

# 字母表,跑过一次的我知道他其实就是16进制数,字符集很小,可以跑得快一点
abl="0123456789abcdef-"
#刚才记录的那个头结点的位置
head = 0xBB3380

//用递归的方法跑迷宫,貌似学明叫,深度优先吧。
def chk(s='',v5=0x30,nod=0xBB3380):
   print(s)
   v7 = m[nod][0]
   if len(s) >= 16: print('flag{%s} -> %d'%(s,v7))
   else:
      if(chr(v7+v5)) in abl :
         chk(s+chr(v7+v5),v7+v5, m[nod][1] )
      if(v5>v7) and (chr(v5-v7) in abl):
         chk(s+chr(v5-v7),v5-v7,m[nod][2] )
chk()

结果能走到最后的只有3条,有两条符合最后一步落在5的条件,不过其中一个明显不靠谱,所以捡着那个看着顺眼的提交就好了


fffdy

yuchoxuuan dfs 😁


  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年1月5日23:10:33
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   xctf-高校战疫-re-Cyclehttp://cn-sec.com/archives/720016.html

发表评论

匿名网友 填写信息