當前位置:
首頁 > 新聞 > 沒事兒下個副本吧?逆向新手踩坑指南

沒事兒下個副本吧?逆向新手踩坑指南

老規矩,坐下,打開電腦,最好能泡一杯茶,手邊再放一個肉夾饃。。。


由於上一次吃過沒查殼的虧,所以這次要先看一看有沒有殼,用PEiD打開看一看:


很好,沒有殼,先直接運行看一看,找一找關鍵字元串:



這樣,我們就有了關鍵字元串,直接IDA打開(一定要先用IDA打開,高手都是這樣的,即使不是,也要假裝是),然後通過IDA的字元串查看功能(shift+F12)來找我們需要的字元串:



除了我們想要的字元串還有滿滿的意外收穫,先等等再說,直接雙擊「welcome to zsctf」,然後按下X,通過交叉引用來到了我們想要的函數:



這是函數最開始反編譯以後的樣子,很多函數名稱不是很友好,在這裡,我想很多老師傅應該都會上手修改函數名稱,改成對人閱讀友好的名字,舉個例子,第9行和第10行一眼就能看出來這是C裡面的printf函數,這裡,單擊一下這個函數,然後按下n,就會跳出來修改函數名稱的窗口:



直接修改為printf,ok以後,就能看到所有函數名稱一樣的地方全部變成了我們修改的字樣:


通過不斷地雙擊函數,查看函數的功能,修改函數或者變數的名稱,最終修改函數名稱變成了這個樣子:



第17行的函數進入以後是這個樣子的:



好多函數,不可能一一分析,那麼猜測應該是花指令,這段代碼有可能是對輸入進行判斷也有可能是處理輸入字元串,等等再說,先看後面的函數。從第14行我們能得到輸入的字元串長度是24,第20行應該是對處理過的字元串進行驗證,只能是0-9,a-f。會不會是進行了md5加密?不管他,後面還有一個關鍵的函數,check。進入check函數以後,這個check卡了我很長時間,很長時間,有多久往下看:

BOOL __cdecl sub_463480(int a1)
{
 int v1; // ST18_4
 int v2; // ST18_4
 BOOL result; // eax
 int v4; // ST18_4
 int v5; // [esp+D8h] [ebp-38h]
 int v6; // [esp+E4h] [ebp-2Ch]
 int v7; // [esp+F0h] [ebp-20h]
 int v8; // [esp+FCh] [ebp-14h]
 int v9; // [esp+108h] [ebp-8h]

 v9 = 0;
 v6 = 0;
 v5 = 0;
 while ( 2 )
 {
   v1 = v9++;
   if ( v1 >= 12 )
     return v5 == 311;
   if ( (unsigned __int8)sub_45B1C7() )
     j__exit(0);
   v2 = *(char *)(v6++ + a1);
   switch ( v2 )
   {
     case 48:
       v8 = 0;
       goto LABEL_12;
     case 49:
       v8 = 1;
       goto LABEL_12;
     case 50:
       v8 = 2;
       goto LABEL_12;
     case 51:
       v8 = 3;
       goto LABEL_12;
     case 52:
       v8 = 4;
LABEL_12:
       v4 = *(char *)(v6++ + a1);
       switch ( v4 )
       {
         case 53:
           v7 = 5;
           goto LABEL_25;
         case 54:
           v7 = 6;
           goto LABEL_25;
         case 55:
           v7 = 7;
           goto LABEL_25;
         case 56:
           v7 = 8;
           goto LABEL_25;
         case 57:
           v7 = 9;
           goto LABEL_25;
         case 97:
           v7 = 10;
           goto LABEL_25;
         case 98:
           v7 = 11;
           goto LABEL_25;
         case 99:
           v7 = 12;
           goto LABEL_25;
         case 100:
           v7 = 13;
           goto LABEL_25;
         case 101:
           v7 = 14;
           goto LABEL_25;
         case 102:
           v7 = 15;
LABEL_25:
           switch ( byte_541168[v8] )
           {
             case 100:
               sub_45CC4D(&v5, byte_541168[v7] - 48);
               continue;
             case 108:
               sub_45D0A3(&v5, byte_541168[v7] - 48);
               continue;
             case 114:
               sub_45CB0D(&v5, byte_541168[v7] - 48);
               continue;
             case 117:
               sub_45D0E9(&v5, byte_541168[v7] - 48);
               continue;
             default:
               result = 0;
               break;
           }
           break;
         default:
           result = 0;
           break;
       }
       break;
     default:
       result = 0;
       break;
   }
   return result;
 }
}

第一眼看上去簡直複雜得不得了,這還怎麼看???繼續改名字!!!一邊改名字一邊分析各個函數,比如變數a1就是我們輸入的字元串,那麼a2的類型就不是int,應該是char類型的,這裡按下鍵盤上的y來修改變數類型:



修改完以後我們看起來費力的第23行一下子變得簡單起來了,前後對比如下:



按照這樣的思路各種修改同時也是分析程序的各個功能,最終得到這樣的邏輯:經過處理的字元串傳遞進來以後,每兩個字元一組,第一個字元對應第一個switch,第二個字元對應第二個witch。結合此函數的結尾部分:



不難得出,第一個表示方向,第二個表示步長,通過兩個switch語句達到這個功能,byte_541168[]開始的地方是一串字元串【delru0123456789】。在這裡的時候我就疑惑了,從d到9一共15個字元,整個選擇一共有16個,這是什麼意思?搞不懂啊,卡在這裡很久很久····於是放棄思考15與16的問題,打算進入down_check函數看一看:



我基本就歇菜到這四個檢查函數里了,這四個檢查函數大同小異,都是判斷,然而就是這個判斷邏輯搞不懂。做不出來題目就認真玩遊戲,認真玩遊戲,認真玩遊戲,重要的話說三遍!!



於是在我翻車以後我打算繼續逆向,還是回到熟悉的地方重新開始,正好這個時候學了一些東西,get到了以前一直忽略的一個地方,就是函數的類型,不是所有的函數都有返回值,就像這幾個函數一樣:



函數返回以後沒有對其他進行賦值操作,那麼,這四個函數應該都是void類型的函數,然而,在我打開down_check函數的時候,簡直亮瞎我的眼:


怎麼可能是int類型?!!改!單擊sub_462D60以後按下y,改成void以後,世界清晰了許多,感覺人生特別美好,陽光特別燦爛,再來一次翻車都沒問題。



於是,按照這樣的思路依次修改這四個文件,並且把傳遞的參數也進行名字上的修改,一邊改,又一邊分析了程序,然後陽光再次普照大地,還是以down_check為例:



如上圖,傳遞兩個參數,一個是當前已經走的步數,一個是要走幾步,這裡,如果要想將i的值重新賦給*steps,必須滿足兩個條件:



1:i/26<=10


2:dword_540548[i]^dword_540068[i]==0


兩個條件同時滿足才能避免return,並且完成i的自增。這一點非常重要,因為先判斷dword_540548[i]^dword_540068[i]=0以後才進行i的自增。表示先判斷能不能往下走,再把步數加上去。或者說站在迷宮中的一個點的時候先判斷能往哪裡走,再把步數加上來。如果判斷順序顛倒一下,表示在迷宮的一個點可以從哪裡來。這是一個往哪裡走和從哪裡來的問題。


還有值得一提的就是,在對四個函數進行分析的時候,通過他一直和26做除法能推斷出來這個迷宮一行26個,一共12行。沒錯,就是12行!你也許會問:在down_check里明明是i/26>10嘛,你想想,如果你在第12行,你上面至少11行,那麼,這個時候,你是不能down的,只有在第11行的時候,你能down,此時你的i/26取整等於10。

怪不得把我卡得死死的。到這裡,距離我坐下,打開電腦已經三個月過去了,當然,中間有其他事情,還有過年。


現在,我們找到了四個不同方向的檢查函數,問題來了,迷宮呢?!!!四個check函數里做異或的地址都不一樣,這是想幹什麼?這裡又卡了好久好久,真的好久,久到開始懷疑人生。後來又翻了一次車,才想明白一件事情:每個檢查函數里都有做異或的字元串,表示這個點能向哪個方向移動,那麼我把同樣的一個i,對應的四個check函數合併起來,是不是就得到了迷宮!!!迷宮就是一個12×26的矩陣!!!


有了想法立刻行動,直接用IDA的python介面寫腳本,把每個方向的check函數中做異或的地方提取出來,比如提取up_check出來看看:



提取出來是這樣的:



然後把提出來的四個列表合起來,我用Pycharm跑了一次試了試:




顯示效果不好,把他放在notepa++上效果好很多:


問題又來了:我在哪兒?我要去哪兒?回到IDA,找到了這個線索:



最開始的時候steps為0,在20行又有311的數字,結合上面的12×26=312,推斷出就是從迷宮左上角走到右下角了。


路線圖是這樣的:



根據整個switch語句的判斷,能得到這樣的一串數字:【06360836063b0839073e0639】。此時大家別忘了,還有一個函數在孤獨的等著我:



這個函數就是我剛開始懷疑的那個md5加密,因為轉換過後的字元是有限制的。IDA我是不看了,那個太複雜,乾脆動態調試一下試試:


前面就不說怎麼找關鍵位置,直接從定位關鍵字以後開始輸入字元串:


此時根據輸入的字元串定位到加密的地方:



在這裡要根據堆棧段的內容將內存段的地址改過去,方便查看數據的變動,注意地址,0x4EFD58是我們輸入字元串的原始存儲地,0x56D090相當於複製了一份。在一步一步跟的時候發現是先將輸入字元串的第17個字元和1做了異或然後到這裡的。然後繼續F8,一步一步跟,跟到下面這個地方的時候一直在反覆循環,於是我打算在這裡下兩個端點,一個是每次循環,一個是整個循環跳出:



此時要重點關注數據窗口的數據:



此時多按幾次F9,發現數據窗口的內容發生了改變:



這裡看到了第一個字元,再次多按F9的時候,變成了這樣:


數字4的ASCII碼為0x34,用字元串的表示為str[3],第四個字元,數字對上了,根據前面第17個字元先和1做異或,這裡猜測應該是這樣的邏輯:



a=』123456』


a[0]則表示1


a[1]則表示2


那麼


b = a[i]^i


讓程序跑完這一段,得到加密後的字元串:


程序跑完以後再F8幾次,注意寄存器的表示,能發現想下面這樣一樣,把原來存放字元串的地方的值變成了加密後的字元串,也就是0x4EFD58這個地方:



然後繼續F8,看看程序要到哪裡去:



這裡很明顯有四個比較,而且0x30是數字0,0x39是數字9,0x61是字母a,0x66是字母f,返回IDA查看一下我們的宏觀判斷:



我們已經成功跳出了加密函數,進入了字元合法性判斷,還剩下一個就是驗證自己的演算法猜想。


自己寫一段python代碼驗證一下:



猜想得到驗證,搞定這題!


直接上代碼找flag~!



最後把第17個字元替換一下就行。


然而我提交以後發現不對。不對?!!!!!為啥?


此時想到了用程序判斷一次試試,然後我發現我忽略了一個點:



最開始的時候意外收穫的字元串給忘了,程序運行完以後會生成一個flag.png文件,這個文件不完整,我用電腦軟體掃描不出來,後來進入IDA親自手拖這段數據(強迫症是不會用手機直接掃描的)


在這裡直接複製到hex裡面保存。注意png文件的開頭和結尾是:文件頭:89504E47 文件尾:AE426082



最後成功掃描出了結果:



此題逆向至此結束,結合了在IDA里重命名,更改類型,IDA腳本,OD的熟練使用,我都懷疑我殺雞用了牛刀,老師傅有簡單的路子請教教我,畢竟這道題讓我迷了四個月(淚奔吶。。。。)


題目鏈接:


https://pan.baidu.com/s/1mBSysZ6hPcOJYDjuGo_W3Q


密碼: xic3


*本文原創作者:antiuto,本文屬FreeBuf原創獎勵計劃,未經許可禁止轉載


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 FreeBuf 的精彩文章:

看我如何發現Facebook密碼重置漏洞獲得$15000賞金(附POC)
信息收集利器:ZoomEye

TAG:FreeBuf |