以太坊 Input Data 解析

2021-10-13 15:10:27

前段時間,Poly Network 被盜事件的一個小插曲,一地址向黑客地址轉账在 input data 中告知其 USDT 已被凍結,不要使用 USDT,黑客知曉後向該地址轉账 13.37 ETH。

事後很多人便通過 input Data 在區塊鏈上“聊天”向黑客“索要”虛擬貨幣,那么我們經常在區塊鏈瀏覽器中看到的 input Data 到底是什么?知道創宇區塊鏈安全實驗室 為您解答。

以太坊 Input Data 解析

input data

在以太坊協議中,當交易(transaction)為合約創建時,input data 是账戶初始化程序的 EVM 代碼;

而當交易(transaction)為消息調用時,input data 是合約函數調用數據。
正常情況下簡單的消息調用如調用轉账函數時需要填寫你要轉账的地址 _to 和你要轉账的數量 _amount,這些基本信息都包含在 input data 裏面。
我們通過一個調用合約的轉账交易具體分析,來理解消息調用時 input data 的結構。

以太坊 Input Data 解析

解析形式:

以太坊 Input Data 解析

原始形式:

以太坊 Input Data 解析

我們將原始的 input data 分為三個部分進行分析:

  • 0xa9059cbb:函數標識符

  • 000000000000000000000000345d8e3a1f62ee6b1d483890976fd66168e390f2: 第一個參數為 address 即你要轉账的地址,並補位到 32 字節即 64 個 16 進制字符

  • 0000000000000000000000000000000000000000000054b7d8ed70650b290000: 第二個參數為 value 即你要轉账的數量,並補位到 32 字節即 64 個 16 進制字符

 通過對比分析我們可以發現 input data 的基本結構為函數標識符+參數

函數標識符

這裏的函數標識符即為函數選擇器,根據官方文檔可知函數選擇器是某個函數籤名的 Keccak(SHA-3)哈希的前 4 字節(高位在左的大端序)。

我們可以通過代碼

bytess4(keccake256("transfer(adddress,uint256)"))或者在线工具獲取這種函數籤名。
下圖可以看出加密結果的前四個字節 (a9059cbb) 跟 input data 中函數標識符一致。

以太坊 Input Data 解析

這裏之所以要將函數籤名截斷到四個字節是考慮到 Gas 成本問題。

在一筆交易中0字節需要支付 4 gas,而非0字節需要 68 gas 也就是 0 字節的 17 倍。在 SHA-3 加密中生成的 32 字節隨機字符串更傾向於多的非 0 字節,所以大概成本是32x68=2176 gas,而截斷成本大概為 4x68=272 gas,可見截斷到四個字節能夠節省約 8 倍的 gas 費。

而函數標識符的作用是指定調用哪一個函數,在同一個合約中兩個不同函數的 SHA-3 籤名的前 4 字節相同的概率是十分小的,所以截斷到四個字節實際不會影響函數調用。

參 數

在 evm 執行字節碼的約定中,靜態類型左補齊零至 64 長度,而動態類型則是右補齊零至 64 長度。
歸納下常見的靜態類型:uint,bool,Address,bytes[0-32], 動態數組類型:bytes,string,address[],bytes32[].....
我們通過 pyethereum的ABI編碼函數 來研究不同數據類型的編碼方式。
靜態類型
先導入 encode_abi 函數

import rlp  
from ethereum.abi import encode_abi

我們以函數 transfer(address,uint 256) 為例

> encode_abi(["address", "uint256"],[345d8e3a1f62ee6b1d483890976fd66168e390f2,1]).hex()
000000000000000000000000345d8e3a1f62ee6b1d483890976fd66168e390f2
0000000000000000000000000000000000000000000000000000000000000001

對於小於 32 字節的定長數組會被自動填充到 32 字節:

> encode_abi(["int8[3]"],[[1, 2, 3]).hex()
// 自動填充 0
0000000000000000000000000000000000000000000000000000000000000001
0000000000000000000000000000000000000000000000000000000000000002
0000000000000000000000000000000000000000000000000000000000000003


動態類型
動態類型編碼要稍微復雜一些,需要先計算偏移量進行佔位處理,我們通過一個簡單的例子來具體說明。

> encode_abi(
 ["uint256[]", "uint256[]", "uint256[]"],
 [[0xa1, 0xa2, 0xa3], [0xb1, 0xb2, 0xb3], [0xc1, 0xc2, 0xc3]]
).hex()
// 參數 1 的偏移量:32*3=96 十六進制 0x60
0000000000000000000000000000000000000000000000000000000000000060
// 參數2的偏移量=參數 1 偏移量+參數 1 數據部分長度=96+32*4=224 十六進制0xE0
00000000000000000000000000000000000000000000000000000000000000e0
// 參數3的偏移量=參數 2 偏移量+參數 2 數據部分長度=224+32*4=352 十六進制0x160
0000000000000000000000000000000000000000000000000000000000000160
// 偏移量 0x60 位置开始傳入參數 1 的數據
0000000000000000000000000000000000000000000000000000000000000003//元素個數
00000000000000000000000000000000000000000000000000000000000000a1//第一個數組元素
00000000000000000000000000000000000000000000000000000000000000a2//第二個數組元素
00000000000000000000000000000000000000000000000000000000000000a3//第三個數組元素
// 0xe0位置。參數 2 的數據
0000000000000000000000000000000000000000000000000000000000000003
00000000000000000000000000000000000000000000000000000000000000b1
00000000000000000000000000000000000000000000000000000000000000b2
00000000000000000000000000000000000000000000000000000000000000b3
//0x160 位置。參數 3 的數據
0000000000000000000000000000000000000000000000000000000000000003
00000000000000000000000000000000000000000000000000000000000000c1
00000000000000000000000000000000000000000000000000000000000000c2
00000000000000000000000000000000000000000000000000000000000000c3


短地址攻擊
經過前面的分析當靜態類型如 address 長度不足 32 字節時 EVM 會根據規則將長度補齊到 32 字節,如果當轉账的地址以00結尾,如0x641988625108585185752230bde001b3ebd0fc00,轉账時將地址後面的兩個零去掉,EVM 依然會認為 address_to是 32 位的,所以它會從_value的高位取 0 來補充,amount的位數會多兩位也就是會乘以256。
攻擊過程如下:

將惡意轉账地址最後一個字節的 0 去掉
函數標識符:a9059cbb
轉账地址:
000000000000000000000000641988625108585185752230bde001b3ebd0fc

轉账金額:
00000000000000000000000000000000000000000000000000000000000000001

由於 EVM 的補位規則,解析結果為:
0xa9059cbb000000000000000000000000641988625108585185752230bde001b3ebd0fc0000000000000000000000000000000000000000000000000000000000000000100
我們分解後發現,轉账金額已經多了兩位也就是多了一個字節,即為原來轉账的 256倍
函數標識符:a9059cbb
轉账地址:
000000000000000000000000641988625108585185752230bde001b3ebd0fc00

轉账金額:
00000000000000000000000000000000000000000000000000000000000000100

如何在 input data 附着信息

在以太坊中直接進行轉账交易的 input data 字段默認是沒有內容的,但是我們可以通過設置錢包實現文章开頭的“聊天功能”。
我們以 MetaMask 錢包為例展示如何通過轉账在 input data 字段附着一些額外的信息。

1、首先我們需要打开錢包高級選項的顯示十六進制數據开關

以太坊 Input Data 解析

2、在轉账時將你要附着的信息通過十六進制編碼後填入下方十六進制數據中,記得在开頭加上 0x 然後進行轉账

以太坊 Input Data 解析

3、轉账成功後在 etherscan 中就能夠看到附着信息

以太坊 Input Data 解析

總結

我們能夠通過交易中的 input data 將一些信息永久存儲在區塊鏈中,可以通過此項技術在食品藥品監管部門的產品防僞溯源、財稅部門的電子票據打假驗真、學術成果存證等方面實現應用落地。

鄭重聲明:本文版權歸原作者所有,轉載文章僅為傳播信息之目的,不構成任何投資建議,如有侵權行為,請第一時間聯絡我們修改或刪除,多謝。

推薦文章

btc日內再次下跌 短线應當如何處理?

盡管以太坊現貨ETF獲批是個好消息,但市場反應卻不如預期。在消息公布後,以太坊價格出現了小幅下跌,...

加密蓮
66 1個月前

7月23日、BTC(合約)ETH(合約)行情分析及操作策略

昨日收益還是不錯的,日內給出的現價空單分別止盈我們目標點位,恭喜跟上的朋友喫肉。時間一晃到月底了,...

倪老師
66 1個月前

幣圈院士:血與淚的教訓!交易者為何總是撞死在同一棵樹上?

幣圈院士談。交易市場中的幾種“死法” 在幣圈市場鱗次櫛比的海洋,風起雲湧,時常讓人感到驚手不及。在...

幣圈院士
58 1個月前

7月23:Mt. Gox 比特幣錢包在市場緊縮的情況下轉移了價值 28.2 億美元的 BTC

7月23:Mt. Gox 比特幣錢包在市場緊縮的情況下轉移了價值 28.2 億美元的 BTC一個引...

168超神
65 1個月前

悅盈:比特幣68000的空完美落地反彈繼續看跌 以太坊破前高看回撤

一個人的自律中,藏着無限的可能性,你自律的程度,決定着你人生的高度。 人生沒有近路可走,但你走的每...

我是周悅盈
56 1個月前

btc完美盈利 晚間波動較大注意

昨日btc空單完美給到,最大化走出一千七百點空間~ btc: 日內开盤下跌繼續測試66000一线,...

加密蓮
59 1個月前