1. 程式人生 > 實用技巧 >【攻防世界】maze

【攻防世界】maze

IDA反彙編的結果:

看上去確實挺草的,一堆goto和奇怪的函式,再加上題目名為迷宮,感覺很害怕

不過其實goto的結構並不混亂,函式也很簡單

四個函式總共有兩個功能:++x<8和x-->0

四個goto其實是每次執行完函式之後就直接跳到指定位置,把函式返回值儲存下來

那麼相應的,可以把v6和v9改個名,改成mark和mark2,方便觀察

(善用ida的改名和註釋功能啊,不要偷懶,不改完全沒法看,但是改著改著就懂了)

分支結構清楚了之後,可以看一下迴圈結構,其實就是從第5個字元開始,一直到倒數第二個字元

相當於把'nctf{'和'}'拿掉,只考慮裡邊包著的部分,串長24,還剩18個未知字元

那麼v4可以改成i,v5=*(&s1 + v4)可以改成ci

接下來仔細看迴圈程式碼的細節

可以看到,四個分治結構分別在ci等於四個值的時候進入,把4個值轉成char可以發現是四個非常有趣的字元

'o', 'O', '0','.'

針不輟……

當進入字元對應的操作後,會讓v10或者v10的下一個位元組+1或-1(不知道為啥,點進函式前是v10,但是如果進去看一眼就變成v9了,第二個引數v3也無了==)

那麼&v10和&v10+1相當於兩個計數器,把它們分別叫做cnt和cnt2

迴圈程式碼的最後出現了一個奇怪的字串,只由'*', ' ', '#'組成,把它稱為wbwb

那麼如果wbwb[cnt+8*cnt2]=='*',就會跳轉到Wrong flag,我們可以把這裡的label重新命名為gg

此外,當所有內容串遍歷完了之後,如果mark==0(cnt和cnt2不在0-7的範圍內)或者wbwb[cnt+8*cnt2]!='#'也會gg

那至此這個程式的意圖就很明顯了,通過一個長度為18的'oO0.'串,操控一個指標在字串上移動,使得避開'*'的情況下到達'#'

整理完後的反彙編程式碼是這樣的:

(這裡的HIDWORD和SHIDWORD是取cnt這個64位int的高32位,其實和(int *)&cnt + 1是一樣的)

狀態數看上去不是很多,可以寫個搜尋爆破

程式碼:

 1 #include<iostream>
 2 #include<cstdio>
 3
#include<cstring> 4 using namespace std; 5 char s[110]; 6 int m=0; 7 int q[110]; 8 int n=18; 9 void dfs(int x,int y,int z,int w){ 10 if(w<0 || w>=m) return ; 11 if(s[w]=='*') return ; 12 if(x==n+1){ 13 if(s[w]!='#') return ; 14 for(int i=1;i<=n;++i){ 15 char tmp=' '; 16 if(q[i]==1) tmp='o'; 17 else if(q[i]==2) tmp='O'; 18 else if(q[i]==3) tmp='0'; 19 else tmp='.'; 20 printf("%c",tmp); 21 } 22 printf("\n"); 23 return ; 24 } 25 q[x]=1; 26 dfs(x+1,y+1,z,w+1); 27 q[x]=2; 28 dfs(x+1,y-1,z,w-1); 29 q[x]=3; 30 dfs(x+1,y,z+1,w+8); 31 q[x]=4; 32 dfs(x+1,y,z-1,w-8); 33 } 34 int main(){ 35 char ch=getchar(); 36 while(ch!='\n'){ 37 s[m++]=ch; 38 ch=getchar(); 39 } 40 dfs(1,0,0,0); 41 return 0; 42 }
View Code

跑得很快,只有一解,這就是flag

做完這題之後看了一下攻防世界的WP,裡邊說這其實就是個8*8的迷宮,cnt+-1是往上下走,cnt2+-1是往左右走,'*'不能走,'#'是目標

現在我終於知道題面裡的迷宮是指啥了

原來這題這麼簡單的嗎囧