<menu id="guoca"></menu>
<nav id="guoca"></nav><xmp id="guoca">
  • <xmp id="guoca">
  • <nav id="guoca"><code id="guoca"></code></nav>
  • <nav id="guoca"><code id="guoca"></code></nav>

    被隱藏的真實

    這題本來單純地以為是很簡單的題,聽歐佳俊師傅講了一下出題思路才發現他的想法真的比答題人多得多……

    main函數里調用了三次get_pwd()這個函數來check輸入

    get_pwd中接受輸入,然后對count自增,調用了Bitcoin對象的一個函數來校驗輸入

    如果熟悉C++逆向的話,一眼就能看出來這是在調用虛函數

    因為v2是對象的空間,在C++的對象構造中,開頭4個字節指向的是虛函數表

    v2指向的是虛函數表,*v2就是虛函數表的第一個函數了

    (圖片引自C++對象模型詳解釋https://www.cnblogs.com/tgycoder/p/5426628.html)

    做題的時候不是很熟悉C++的模型,以及虛函數反編譯的不是很明顯,直接動態調試做的。初始狀態這個虛函數是init,其中調用了verify,第一次直接返回輸入,對應輸出列表的需求,要輸入0xdeadbeef的小端序表示”efbeadde”。如果純靜態逆向,會繼續往下看verify函數的第二、三次校驗,但事實上第二次就沒有調用init了。

    我在做的時候因為不熟悉虛函數,所以動態調試直接跟進函數,發現進入了sub_4046D7這個函數,其中的核心函數b58e乍看起來很復雜,但其實通過其中的24(實際上是256)、%58,和題目內的信息描述很容易想到比特幣地址轉換方法–base58

    直接進行解密獲得bytes類型即可通關(注意最后4字節是sha256的驗算字節,不可提交,否則會導致flag的sha256計算錯誤。因為第二關僅截取19個字符送入,但跟flag有關的sha256卻會把所有input全部進行運算,導致最后提示Correct實際上的flag卻不對)

    話是這么說,直接套來的腳本解密出來其實沒看懂,還是自己查資料從加密到解密走了一趟才get到應該是hex格式。第三小關本來以為是腦洞題了,其實是誤打誤撞做出來的,運氣是真的好OTZ

    這次虛函數又回到了verify,將Input進行兩次sha256然后逆序與結果比較,當時的想法是結合提示語:

    查了一下發現這條地址是中本聰在開始比特幣時記錄的第一個塊–創世塊,剛開始想到的是根據創世塊向區塊鏈后端爆破,某個區塊的sha將會滿足要求。不過查了一下好像也沒什么適合計算的,總不能自己重復一遍挖礦過程吧233

    卡了許久,代碼中突然發現一個關鍵點

    長度80是個很關鍵的提示!

    于是去找了區塊鏈結構解析,發現區塊頭的長度正好是80個字節 https://webbtc.com/block/000000000019d6689...

    在這里得到了創世塊的頭部信息,提交即可獲得flag

    事實上在經過家俊師傅的講解后,再回頭逆才發現這里的memcmp被覆蓋到了sub_404A36函數

    這個函數中通過異或生成了一個串,然后將輸入的字符串與做過兩次sha256再逆序的輸入進行memcmp。這個兩次sha256再逆序的操作,在之前的查資料過程中發現就是比特幣的哈希方法,把異或生成的串dump出來去搜索。

    IDC>auto i;for(i=0;i<80;i++){Message(%02x”, Byte(0x6d0a00+i));}000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f4e61復制

    發現是創世塊的哈希值,由此倒推出原輸入是創世塊。

    比賽的時候從一個長度猜到創世塊頭部,不得不感嘆自己的運氣真的是……

    最后再分析一下虛函數的覆蓋,和家俊師傅挖下的種種坑

    首先注意到虛函數表中的第一個函數在初始情況下是Init

    逐步跟蹤,發現Bitcoin在構造函數中就有玄機

    這里跳轉到了0x6D0F88處,過去看看

    這時是直接一個leave和retn返回了

    但是后面有很多不可識別的臟數據,暫且先放著不管,繼續往后走

    get_pwd函數中就如之前分析的一樣,沒什么問題

    問題在于析構函數里

    乍一看好像沒什么問題哦,delete釋放空間嘛

    注意這里的(this+3)指向的就是剛才跳轉的0x6D0F88

    再點進delete內一看

    ?!

    跟正常調用free的delete完全不一樣,左邊function列表中也竟然出現了兩個同名的函數

    另外一個才是調用free的原delete,這個是冒牌的!

    這里利用的是IDA的重命名機制–C++編譯器為了區分重載函數,會對函數生成一些其他字符來修飾。delete函數被修飾以后的名稱是”_ZdaPv”,但是冒牌delete函數的原名是”__ZdaPv”,IDA同樣也會將其重命名為delete,導致被忽視。

    這個delete中將參數指向的空間寫為0x90,即NOP的機器碼

    因此可以將剛才的leave、retn和大量臟數據全部寫成NOP,從而使下一次調用構造函數的時候可以執行一些其他代碼,而這個機密的函數就是臟數據之后的代碼,sub_6D1048

    這里的a1是rbp,頻繁調用的a1-8就是this指針

    可以看到,每次調用都會覆蓋一次虛函數

    另外當第三次執行的時候會將memcmp重寫

    整個理透以后這個題目學到的應該是最多的,各種陰險技術,真的很有意思23333

    可惜做的時候動態跟過去會忽視掉這里的大量重寫,比較可惜

    本文章首發在 網安wangan.com 網站上。

    上一篇 下一篇
    討論數量: 0
    只看當前版本


    暫無話題~
    亚洲 欧美 自拍 唯美 另类