區塊鏈頭條
  • 法規
  • 財經
  • 區塊鏈
  • 數位藝術
  • 投稿專區
  • 時事話題
  • 幣動幣咚
  • 加密貨幣落地應用
    • 新手必讀
    • 獨立觀點
    • 數據報告
區塊鏈頭條
No Result
View All Result
Home 區塊鏈

深入EVM:合約分類這件小事背後的風險

2023 年 6 月 5 日
leadingblockby leadingblock
深入EVM:合約分類這件小事背後的風險

合約分類是交易所、錢包、區塊鏈瀏覽器、數據分析平台等的基石。

撰文:十四君

在智能合約領域,「以太坊虛擬機EVM」以及其算法和數據結構就是第一性原理。

本文從合約為什麼要分類出發,結合每個場景可能面對怎樣的惡意攻擊,最終給出一套達成相對安全的合約分類分析算法。

雖然技術含量較高,但亦可作為雜談讀物,一覽去中心化系統間博弈的黑暗森林。

1、合約為什麼要分類?

因為太重要了,可謂是交易所、錢包、區塊鏈瀏覽器、數據分析平台等等Dapp 的基石!

一筆交易之所以是ERC20 轉賬,是因為他的行為符合ERC20 標準,至少得有:

  1. 交易的狀態是成功
  2. To 地址為某個符合ERC20 標準的合約
  3. 調用了Transfer 函數,其特點是該交易CallData 的前4 位為0xa9059cbb
  4. 執行後,在該To 地址上發出了transfer的事件

分類有誤則交易行為會誤判

以交易行為為基石,則To 地址能否被準確分類則對其CallData 的判斷會有截然不然的結論。對Dapp 而言,鏈上鍊下的信息溝通高度依賴於交易事件的監聽,而同樣的事件編碼也只有在符合標準的合約中發出,才具有可信度。

分類有誤則交易會誤入黑洞

如果用戶進行一筆Token 轉移,轉入到某個合約中,如果該合約沒有預設Token 轉出的函數方法,則資金會雷同於Burn 一樣被鎖定,無法控制

且如今大量項目開始增加內置的錢包支持,要為用戶管理錢包也就不可避免的,需要時刻從鏈上實時分類出最新部署的合約,是否能夠吻合資產標準。

拓展閱讀第1 段:【合約解讀】CryptoPunk 世界上最早的去中心化NFT 交易市場

2、分類會有怎樣的風險?

鏈上是一個沒有身份沒有法治的地方,你無法制止一筆正常的交易,哪怕他是惡意的。

他可以是冒充外婆的狼,做出多數符合你預期的外婆行為,但目的是進屋搶劫。

聲明標準,但可能實質不符合

常見的分類方式是直接採用EIP-165 標準,讀取該地址是否支持ERC20 等,當然,這是一個高效率的方法,但是畢竟合約是對方控制,所以終究是可以偽造出一份申明。

165 標準的查詢,只是在鏈上有限的操作碼中,用最低成本去防止資金轉入黑洞的方法。

這也是為什麼我們之前分析NFT 的時候,特地提及標準中會有一類SafeTransferFrom的方法,其中Safe就是指代了採用165 標準判斷出對方聲明自己具備了NFT 的轉移能力。

拓展閱讀第2.2 段:【源碼解讀】你買的NFT 到底是什麼?

唯有從合約字節碼出發,做源碼層面的靜態分析,從合約預期的行為出發才有更精準的可能性。

3、合約分類方案設計

接下來咱們將系統的分析整體方案,注意我們的目的是「精度」和「效率」兩項核心指標。

要知道即使方向是對的,但要抵達大洋的彼岸路途也並不明朗,要做字節碼分析的第一站是獲取代碼。

3.1、如何獲取到代碼?

從上鍊後的角度講有getCode,一個RPC 方法,可以從鏈上指定的地址裡獲取到字節碼,單論讀取的話這是非常快捷的,因為從EVM 的賬號結構中就把codeHash 放在最頂端的位置。

但是這個方法等於是單獨對某個地址做獲取,想要進一步提升精度和效率呢?

如果是部署合約的交易,如何在其剛執行完甚至他還在內存池中便獲取部署的代碼?

如果該筆交易是合約工廠的模式,則交易的Calldata 裡是否存在源碼呢?

最後的我的方式是,是分類進行一種類似篩子的模式

  1. 對於非合約部署的交易,則直接用getCode獲取其中涉及的地址進行分類,
  2. 對於最新內存池的交易,篩選出to 地址為空的交易,其CallData 則是帶有構造函數的源代碼
  3. 對於合約工廠模式的交易,由於其中可能是合約部署出的合約再循環調用其他合約來執行部署,則遞歸的去分析該筆交易的子交易,記錄每個type 為CREATE或者為CREATE2的Call。

我做了個demo 實現的時候,發現還好現在rpc 的版本比較高,因為整個過程最難的便是執行3 的時候,如何遞歸找到指定type 的call,最底層的方式是通過opcode 還原上下文,我吃了一驚!

還好現在的geth 版本里有debug_traceTransaction 方法,他可以幫助解決在通過opcode 操作碼中梳理每一個call 的上下文信息,整理出核心的字段。

最終可以對多種部署模式的(直接部署,工廠模式單部署,工廠模式批量部署)的原始字節碼都獲取到。

3.2、如何從代碼分類?

最最簡單但不安全的方式,是把code 直接做字符串匹配,以ERC20 為例符合標準的函數則有

在函數名之後的,則是該函數的函數簽名,之前在分析的時候提及,交易都是依賴匹配callData 的前4 位找到目標函數的,拓展閱讀:

所以合約字節碼裡必然存儲有這6 個函數的簽名。

當然,這種方法非常快捷6 個都查到就完事的,但不安全的因素則是,如果我採用solidity 合約中,單獨設計一個變量,存儲值為0x18160ddd 那麼他也會將認為我有了這個函數。

3.3、準確率提升1- 反編譯

那進一步的準確方法則是做Opcode 的反編譯!反編譯則是將獲取到的字節碼轉到操作碼的過程,更高級的反編譯則是再轉成偽代碼,更利於人的閱讀,這次我們用不上,反編譯的方法列於文末的附錄中。

solidity(高級語言)->bytecode( 字節碼)->opcode( 操作碼 )

我們就可以清晰的發現一個特徵,函數簽名都會被PUSH4 這個操作碼所執行,所以進一步的方法則是從全文中提取PUSH4 後的內容,與函數標準做匹配。

我也簡單做了下性能實驗,不得不說Go 語言的效率很強大,1W 次反編譯只需要220ms。

接下來的內容會有一定難度。

3.4、準確率提升2- 找代碼塊

上文中準確率有所提升但還不夠,因為是全文搜索PUSH4的,因為我們仍然可以構建一個變量,是byte4的類型,這樣一來也會觸發PUSH4的指令。

在我苦惱的時候,想到一些開源項目的實現,ETL 是一個讀取鏈上數據做分析的工具,其中會解析出ERC20、721 的轉移單獨成表,所以必然具備分類合約的能力。

分析下來,可以發現他是基於代碼塊的分類,只處理第一個basic_blocks[0]裡的push4指令

那問題來到了,如何準確判斷代碼塊了

代碼塊的概念源於REVERT + JUMPDEST 這2 個連續的操作碼,這裡必然需要連續的2 個,因為在整個函數選取器的opcode 區間裡,如果函數數量過多,則會出現翻頁的邏輯,那也會出現JUMPDEST 這個指令。

3.5、準確率提升3- 找函數選擇器

函數選擇器的作用是,讀取該筆交易的Calldata 的前4 位字節,並與代碼中預設有的合約函數簽名進行匹配,協助指令跳轉到存儲了該函數方法指定的內存位置。

讓我們嘗試一個最小的模擬執行

這部分是兩個函數的選擇器store(uint 256) 和retrieve(),可算出簽名是2e64cec1,6057361d

60003560e01c80632e64cec11461003b5780636057361d1461005957

進行反編譯後,則會得到如下的操作碼串,可以說分兩個部分

第一部分:

在編譯器中在合約中僅函數選擇器部分會去獲取到callData 的內容,寓意是獲取其CallData 的函數調用簽名,註釋如下圖。

我們可以通過模擬EVM 的內存池變化來看看效果

第二部分:

判斷是否與選擇器的值匹配的過程

  • 將retrieve() 的4 字節函數簽名(0x2e64cec1) 傳入stack 上,
  • EQ 操作碼從stack 區彈出2 個變量,即0x2e64cec1 和0x6057361d,並檢查它們是否相等
  • PUSH2 將2 個字節的數據( 這里為0x003b,十進制為59) 傳入stack,stack 區有一個叫做程序計數器的東西,它規定了下一個執行命令在字節碼中的位置。這裡我們設置59,因為那是retrieve() 字節碼的起始位置
  • JUMPI 代表「如果…,則跳轉至…」,它從stack 中彈出2 個值作為輸入,如果條件為真,程序計數器將被更新至59。

這就是EVM 是如何根據合約中的函數調用,來確定它需要執行的函數字節碼的位置的原理。

實際上,這只是一組簡單的「if 語句」,用於合約中的每個函數以及它們的跳轉位置。

4、方案總結

整體簡述如下

  1. 每個合約地址可以通過rpc  getcode或者debug_traceTransaction,獲取到部署後的bytecode,採用GO 中VM 和ASM 庫,反編譯後即獲取到opcode
  2. 合約在EVM運行原理中,會有以下特徵
  3. 採用REVERT+JUMPDEST這2 個連續的 opcode 作為代碼塊的區分
  4. 合約必然具備函數選擇器的功能,該功能也必然在第一個代碼塊上
  5. 函數選擇器中,其函數方法均採用PUSH4作為opcode,
  6. 該選擇器所包含的opcode 中,會出現連續的PUSH1 00; CALLDATALOAD; PUSH1 e0; SHR; DUP1,核心功能是加載callDate 數據並進行位移操作,從合約功能上其他語法不會產生
  7. 對應的函數簽名在eip中定義,並且有必选和可選的明確說明

4.1、唯一性證明

走到這裡我們就可以說,基本實現高效率,高準確率的合約分析方法了,當然既然已經嚴謹了這麼久,不妨再嚴謹一些,我們上文方案里中基於REVER+JUMPDEST 來做代碼塊的區分,結合其中必然的CallDate 加載和位移來做唯一性判斷,那是否存在,我可以用solidity 合約也實現出類似的操作碼序列呢?

我做了下對照實驗,從solidity語法層面雖然亦有msg.sig等獲取CallData的方法,但編譯後其opcode的實現方法不同

5、總結

洋洋灑灑這麼分析下來,3 天時間就過去了。

雖然非常的細緻,雖然日常中會遇到合約採用byte4來惡意混淆自己是否符合標準的合約可能是九牛一毛。

所以,實際上這3 天投入分析的ROI 是非常低的。但是在無盡的時間長河裡,概率再小的事情,也終將發生。

怀揣不信任原則才能在web3 的世界裡,走的更遠。

今天有好友問我一個很有思考深度的話題,作為產業KOL 的終局是什麼?你的商業模式是什麼?

雖然我知道技術的文章,總是流量慘淡,但流量本就不是目的,我希望始終都在最初的願景上:

 💡 以技術的視角,洞察產業發展的關鍵變化,分享產業發展中的過往經驗與未來機會,為新時代的建設者提供差異化的幫助。

附錄

如需opcode 樣例以及Go 進行反編譯的樣例代碼,可公眾號後台回复「合約分類」獲取。

依賴庫:
https://pkg.go.dev/github.com/ethereum/[email protected]/core/asm#Compiler.Feed
https://pkg.go.dev/github.com/ethereum/[email protected]/core/vm

原理解析:
https://whileydave.com/2023/01/04/disassembling-evm-bytecode-the-basics/
https://yanniss.github.io/elipmoc-oopsla22.pdf
https://yanniss.github.io/gigahorse-icse19.pdf
https://www.evm.codes/?fork=shanghai
https://learnblockchain.cn/article/4800
https://learnblockchain.cn/article/3647

開源項目源碼參考:
https://github.com/blockchain-etl/ethereum-etl/blob/2da9d050f4ae4fa4e818bbfb22d5cfb5234b2e29/ethereumetl/service/eth_contract_service.py#L29-L43
https://github.com/ethereum/evmdasmhttps://github.com/tintinweb/ethereum-dasm/blob/master/ethereum_dasm/evmdasm.py#L342

圖片與文章來自:(https://foresightnews.pro/article/detail/34580)

最新文章

第11屆公司治理評鑑頒獎典禮圓滿成功

第11屆公司治理評鑑頒獎典禮圓滿成功

2025 年 6 月 12 日
高雄人氣壽喜燒必吃 美麗島站平價美食 涮出道地日式風味

高雄人氣壽喜燒必吃 美麗島站平價美食 涮出道地日式風味

2025 年 6 月 12 日
拜登罹患晚期攝護腺癌引關注 多機轉藥物合併治療為末期患者帶來新希望

拜登罹患晚期攝護腺癌引關注 多機轉藥物合併治療為末期患者帶來新希望

2025 年 6 月 12 日
在家就能洗腎!腹膜透析搭配遠距監控 治療與生活品質大幅提升

在家就能洗腎!腹膜透析搭配遠距監控 治療與生活品質大幅提升

2025 年 6 月 12 日
找韓國Kia汽車業務 台中首選丹尼斯叔叔

找韓國Kia汽車業務 台中首選丹尼斯叔叔

2025 年 6 月 12 日
慶豐富5月營收報喜

慶豐富5月營收報喜

2025 年 6 月 12 日
Next Post
L2 頭部流動性定制DEX 機制分析:Trader Joe、Izumi、Maverick

L2 頭部流動性定制DEX 機制分析:Trader Joe、Izumi、Maverick

Starknet 將推出v0.12.0 版本,專注於提高網絡吞吐量

Starknet 將推出v0.12.0 版本,專注於提高網絡吞吐量

關於我們

『區塊鏈頭條』成立於比特14年,是一個領先各大媒體的媒體平台,注重於金融科技、區塊鏈技術及 Cryptocurrency 的相關議題,致力於建構簡單易用的去中心化入口,幫助人們了解相關領域的最新消息,把看似複雜遙遠的web3.0,用最簡單理解的方式,帶領大家通往Metaverse的多重宇宙!爲維持「元宇宙」源源不斷的輸送新資訊,也邀請各大創作者一起投稿。

藉由全世界行業內的先驅,區塊鏈頭條分享實戰經驗及機構資源,旨在成為快速提供專業資訊且減緩知識落差的媒體平台。

熱門標籤

標籤

AI BNB BNB Chain BRC-20 BTC chaebol DAO DEFI DePIN ETF ETH FTX GameFi Layer1 Layer2 meme NFT ORDI Ordinals POW ProEx Solana WEB3 乙太坊 交易所 以太坊 俄羅斯 元宇宙 加密貨幣 區塊鏈 去中心化 幣安 投稿 數據 智能合约 比特幣 比特幣生態 法規 牛市 空投 美國 財經 銘文 鏈遊 香港

社群媒體

No Result
View All Result
  • 法規
  • 財經
  • 區塊鏈
  • 數位藝術
  • 投稿專區
  • 時事話題
  • 加密貨幣落地應用
    • 新手必讀
    • 獨立觀點
    • 數據報告

© 2022 區塊鏈頭條