智慧合約安全系列文章反彙編·下篇

前言

上篇我們詳細分析了智慧合約反彙編後的程式碼內容,包括多個反彙編指令的含義,資料在棧中的儲存方式,並透過上下文關聯關係梳理程式碼邏輯。本篇我們將繼續分析上篇遺留的反彙編程式碼,透過上篇學習我們已對反彙編指令在棧和記憶體儲存的有了一定了解,該篇我們將重點來分析反彙編指令表示的程式碼邏輯。

反彙編內容

合約原始碼

pragma solidity ^0.4.24;

contract tee {
    
    uint256 private c;

    function a() public returns (uint256) { self(2); }
    
    function b() public { c++; }

    function self(uint n) internal returns (uint256) {
        
        if (n <= 1) { return 1; }

        return n * self(n - 1);
    }
}

上篇文章中,我們對下圖中藍色框中的內容進行了詳細分析,本篇我們分析紅色框中的內容以及之後的反彙編指令。

反彙編分析

我們從label_004e開始分析,從反彙編上篇文章中可知,執行0x4e是上一步中判斷後證明該函式簽名是為a()函式,接下來我們來看0x4e中指令的主要含義:

(callvalue)獲取交易中的轉賬金額,(dup1)複製轉賬金額值到棧頂,(iszero)把棧頂轉賬金額值出棧,如果該值是0則把1入棧,否則把0入棧。(jumpi)這裡如果轉賬金額值為0,(push2 0x59)該段指令就會跳轉到0x59;如果轉賬金額不為0,則順序執行下一行指令。由此可知該段指令主要是為了判斷a()函式是否存在轉賬操作。

執行完後,目前棧中就只存在一條資料:轉賬金額值

這裡我們先來看label_004e順序執行:

透過上圖0055部分可以看出,push2 0x00和dup1指令在這裡均無實際意義,這部分最終結果為停止執行,回滾狀態。

接下來,我們來看跳轉後0059指令內容:(pop)把棧頂值出棧,也就是轉賬金額值;(push2 0x60和push2 0x8a)將0x60和0x8a依次壓入棧中;(jump)跳轉到棧頂0x8a位置。

如圖008a指令處,依次壓入0x00,0x94,0x02,0xab,目前棧中佈局如下:

4:0xab
3:0x02
2:0x94
1:0x00
0:0x60

之後jump指令將跳轉至00ab,如上圖。該段指令中:(push2 0x00,push2 0x01)依次將0x00和0x01壓入棧;(dup3)複製當前棧中第三個值0x02放入棧頂;(gt)把棧頂兩個值出棧,先出棧的值0x02大於後出棧的值0x01,把1入棧;(iszero)把棧頂值1出棧,該值不是0把0入棧;繼續(iszero)把棧頂值1出棧,該值是0把1入棧;(jumpi)這裡棧頂值為1,(push2 0xbe)跳轉到0xbe。

這裡注意壓入的0x02就是a()函式中呼叫self(2)函式傳入的值。

接下來我們對a()函式的內部操作進行一個全面的梳理

下圖為a()函式呼叫self()函式並賦值後的反彙編指令程式碼邏輯圖:

上圖的反彙編指令運算元值在棧中的佈局如下所示:

以上兩張圖中指令執行邏輯均已進行標註,對於每個指令的操作含義就不一一介紹,我們直接來看分析之後,重點的指令操作。透過008a段中push2 0x02將2壓入棧中;00ab段中dup3將2複製到棧頂,並利用gt指令將2和1進行了對比;00be段中dup4將2複製到棧頂,並利用sub指令達到(2-1),最終得到相減的數值後繼續跳轉到00ab中對該值和1進行對比;接下來00b7段和00cd段沒有實際意義,只是對一些數值進行調整;繼續看00c8段中dup3將複製到棧頂,並利用mul指令將2和1(也就是2-1的值)進行相乘,並將所得值壓入棧中,之後的0094段和0060段含義是將棧中數值進行調整,並將計算偏移量最終輸出返回值。

故此我們可以得出a()函式的輸入值後的程式碼邏輯為以下:

  function a() public returns (uint256) { self(2); }
  
  function self(uint n) internal returns (uint256) {
        
        if (n <= 1) { return 1; }

        return n * self(n - 1);
  }

由於彙編指令較多,這裡就不進行全面分析,需要深入學習的同學可移步反彙編二:反彙編2

總結

本篇文章我們分享瞭如何透過反彙編指令分析得到智慧合約原始碼邏輯,看似一段簡單的智慧合約程式碼,但反彙編出來的彙編指令卻非常多。我們在之前的文章中也分享了透過分析反編譯程式碼得到智慧合約原始碼邏輯,所以對於智慧合約編譯部署後的opcode,建議大家選擇適合自己的逆向方式。

solidity智慧合約逆向工具推薦:

https://ethervm.io/decompile
https://contract-library.com/
https://github.com/crytic/ida-evm
https://github.com/comaeio/porosity
https://github.com/meyer9/ethdasm


免責聲明:

  1. 本文版權歸原作者所有,僅代表作者本人觀點,不代表鏈報觀點或立場。
  2. 如發現文章、圖片等侵權行爲,侵權責任將由作者本人承擔。
  3. 鏈報僅提供相關項目信息,不構成任何投資建議

推荐阅读