Solidity
如何在 evm 字節碼中分離函式?
我想從智能合約的字節碼建構控制流圖(CFG)(假設它是通過編譯 Solidity 源文件獲得的)。這個CFG還應該區分智能合約的不同方法。
有沒有辦法這樣做?
如何在 evm 字節碼中分離函式?
Solidity 將在字節碼的開頭為函式呼叫創建一個調度程序塊。類似於 if .. elseif .. elseif .. else
單個函式呼叫將遵循以下重複模式:
DUP1 PUSH4 <4-byte function signature> EQ PUSH2 <jumpdestination for the function> JUMPI
從這個塊中,您可以重構函式並找到它們的跳轉目的地,但是,您將只有 4 字節的簽名,並且沒有原始碼中的名稱。
例如對於這個智能合約程式碼:
contract X { uint x; uint y; function a(uint u) public { x = u; } function b(uint v) public { y = v; } function t(uint v) public { a(v); b(v); } function () { t(1); } }
調度程序將如下所示:
... 054 DUP1 055 PUSH4 afe29f71 060 EQ 061 PUSH2 0070 064 JUMPI 065 DUP1 066 PUSH4 cd580ff3 071 EQ 072 PUSH2 009d 075 JUMPI 076 DUP1 077 PUSH4 f0fdf834 082 EQ 083 PUSH2 00ca 086 JUMPI ...
如果可以直接用字節碼編寫智能合約,那麼就可以讀取和分析它。考慮到字節碼類似於帶有 LIFO 堆棧的彙程式序,閱讀起來並不友好。沒有函式的名稱,變數的名稱,名稱根本不存在。這是關於彙程式序的類似問題https://reverseengineering.stackexchange.com/questions/10604/how-to-generate-cfg-from-assembly-instructions。
為了做到這一點,我會:
- 學習操作碼http://gavwood.com/paper.pdf
- 檢查 Remix,編譯後有很棒的字節碼概述(可能很有用)
- 檢查項目https://github.com/comaeio/porosity以了解如何解析它
例如:
- 定義操作碼的位置
- 檢測可能的標籤
JUMPDEST
- 檢測跳轉
PUSH2 0x.... JUMP
(可以假設為函式呼叫)注意不同版本的編譯器編譯相同程式碼後結果可能不同,這意味著控制流可能不同。
孔隙度CFG
porosity.exe --code 0x60... --cfg