「收藏」一文教你如何使用圖靈完備的EVM虛擬機

近年來,智能合約成為了區塊鏈安全的重災區,從The DAO到BEC,SocialChain,Hexagon,再到EOS漏洞,智能合約安全漏洞頻現令不少開發者和企業對區塊鏈望而卻步。

12月8日,在迅雷鏈技術沙龍第六站現場,迅雷鏈底層研發工程師胡登啟系統剖析了智能合約安全問題,分析了智能合約中存在的典型漏洞和預防措施,並總結了在合約編程過程中需要注意的幾大安全原則,在現場聽眾間引起了熱烈反響。

區塊鏈虛擬機工作原理

關於虛擬機的運行原理,胡登啟以EVM為例,講解了虛擬機底層是如何實現的,讓開發者對虛擬機有了更全面的認識。

首先,區塊鏈的虛擬機應該包含以下6個特性:

1.安全:這也是最重要的,即代碼在沙盒中運行,一旦發生錯誤,可以回滾掉所有更新;

2.結果明確:結果確定且沒有歧義,在區塊鏈的所有節點執行該邏輯,得到的結果一定是保持一致的;

3.簡單:操作碼低級,結構簡單;

4.具備特定的能力:虛擬機能處理加密運算,比如支持橢圓曲線算法,能訪問交易與鏈狀態,獲取blockhash,tx相關內容等等;

5.易於優化:支持即時編譯(JIT)等;

6.節省空間:虛擬機組件緊湊,便於集成到區塊鏈服務中。

「收藏」一文教你如何使用圖靈完備的EVM虛擬機

通過分析EVM虛擬機,胡登啟總結了通用區塊鏈虛擬機應該是如何運作的:

1.首先開發者會使用 c、c++、或者 solidity等高級語言編寫一個合約,一般情況下這裡包含了很多的複雜的業務邏輯;

2.通過編譯器llvm,或者solidity編譯器,將包含服務業務邏輯的源代碼編譯成與機器無關的中間代碼,也就是我們所說的字節碼;

3.虛擬機在運行時,首先要通過代碼加載器,將字節碼讀入內存,初始化基礎的內存變量;

4.然後由虛擬機的執行引擎將一條一條的字節碼指令翻譯成對應機器平臺的底層指令執行;

5.執行引擎在執行指令的過程中會使用到臨時變量、堆棧區存儲空間,或者讀寫外部文件等,這裡統稱為運行時數據區。

區塊鏈虛擬機的執行流程

「收藏」一文教你如何使用圖靈完備的EVM虛擬機

一個通用的虛擬機執行流程可以抽象成下面這個過程:

1.首先將字節碼加載到內存的代碼段,初始化運行環境,這時程序計數器初始化為0。如上圖所示,這裡有個循環體,循環判斷的結束條件是:是否要終止執行?如果判斷標記為false,則獲取pc執行的操作碼,否則退出執行,返回結果;

2.獲取到pc操作碼後,會校驗參數,比如參數是否足夠,有沒有超過堆棧的最大可用空間等;

3.接下來會執行具體的指令;

4.指令結束後,計數器加一,繼續循環,直到程序設置了終止標記位。

迅雷鏈支持圖靈完備的EVM虛擬機,胡登啟以一個簡單的solidity合約為例,為現場開發者分析了EVM虛擬機是如何運行的。

EVM虛擬機的執行主流程是在Run函數里面的,在循環裡面首先會獲取對應的操作碼,將操作碼關聯到對應的指令,這個指令在執行之前會進行一些數據的校驗。執行指令完之後,可以判斷繼續執行指令還是返回退出。

「收藏」一文教你如何使用圖靈完備的EVM虛擬機

如上圖所示,這個合約只有一個Add函數,計算2個uint8變量的和。

通過solidity編譯器,將合約編譯成bytecode. 虛擬機會將bytecode轉換成對應的opcode。opcode被表示為預定義的標識符。比如 0x60 對應的opcode是 PUSH1, 0x52 對應的opcode是 MSTORE.

「收藏」一文教你如何使用圖靈完備的EVM虛擬機

而上面提到的被預定義的標識符,其實就是操作碼。EVM中將操作碼大致分為四類:

第一類是算術運算,包括最基礎的加減乘除運算指令;

第二類是邏輯運算,包括與、或、非、等於、不等於、大於、小於等;

第三類是與區塊鏈狀態相關指令,具體是指區塊信息如coinbase、區塊時間戳、區塊序號等,還有交易相關的,如交易的發送者,交易轉賬金額等指令;

第四類是跟存儲相關的指令,比如讀取虛擬機運行時內存數據,或者存儲數據到區塊鏈狀態中。

每一個操作碼都對應一個操作指令。操作指令定義了操作碼具體要執行怎樣的操作,操作消耗的gas值,操作需要的參數與返回值的個數,還有操作需要額外空間。同時操作指令中還定義了一些標記位,比如終止運算、跳轉、是否出錯、是否應該返回等。

胡登啟通過展示最簡單的加法操作指令為例,為大家分析了指令結構。EVM虛擬機每個操作指令都會消耗一定的gas值,這麼做的目的一方面是為了避免開發者編寫無限循環的代碼,另一方面是為了給打包交易的節點一點獎勵。

智能合約開發的安全準則

不過胡登啟指出,EVM只是區塊鏈虛擬機的一種實現方式,而且現行的智能合約還是一個在不斷髮展的技術,要想運用好這個技術並不容易。

事實上,在實踐過程中,合約被爆出了各種安全漏洞,這些漏洞可能給項目發行方造成巨大的損失。因為區塊鏈是去中心化的自治系統,往往發現漏洞後,發行方很難去修復這個漏洞,只能任由黑客肆意的攻擊。因此要求開發者在編寫智能合約時,做更加全面的安全測試,儘量避免包含漏洞的代碼發佈到區塊鏈系統中。

胡登啟通過分析智能合約中存在的典型漏洞,向現場聽眾展示了智能合約安全問題的重要性,併為開發者編寫智能合約提供了一些參考。

比如,他以今年年初轟動一時的美鏈BEC合約漏洞為例,講述了智能合約安全的重要性。BEC是美鏈公司發佈的token,於今年2月上線交易, 4月22日該合約被爆出重大漏洞,導致其token市值幾乎歸零。

「收藏」一文教你如何使用圖靈完備的EVM虛擬機

其智能合約中有個批量轉賬的接口,參數是地址數組和轉賬token值。如上圖的第218行代碼,這裡有個乘法運算,用以計算一次交易中轉移token的總值,計算結果使用uint256類型保存。有過c或者c++開發經驗的同學可能會看出,這裡存在整數溢出的問題。

黑客正是利用了這個漏洞,進行BEC token的鉅額增發,最終導致其價值接近歸零。

胡登啟以此作為反面教材,告誡開發者,在合約開發中進行任何數學運算時,都推薦使用SafeMath庫,這樣可以避免溢出的漏洞。比較諷刺的一點是,BEC合約的其他代碼都使用了SafeMath庫,唯獨漏了這一處。可見代碼測試一定要充分,漏了一個點,可能造成巨大損失。

通過對另外數起知名安全漏洞案例的分析,胡登啟總結了智能合約開發的3條安全準則

1.開發者應深入的理解區塊鏈系統的運行原理。

2.希望開發者熟練掌握一門合約語言的特性。

3.要做全面的代碼測試,不能有僥倖心理。


「收藏」一文教你如何使用圖靈完備的EVM虛擬機


胡登啟最後表示,區塊鏈智能合約還是一門比較年輕的技術,需要在開發者的不斷實踐中去完善與提升。因此在目前階段,開發者進行智能合約編程時,尤其需要注意規避漏洞,以保證合約具備足夠的安全性。


分享到:


相關文章: