以太坊 Input Data 解析
摘要: 我们经常在区块链浏览器中看到的 input Data 到底是什么?
正常情况下简单的消息调用如调用转账函数时需要填写你要转账的地址 _to 和你要转账的数量 _amount,这些基本信息都包含在 input data 里面。
我们通过一个调用合约的转账交易具体分析,来理解消息调用时 input data 的结构。
0xa9059cbb
:函数标识符000000000000000000000000345d8e3a1f62ee6b1d483890976fd66168e390f2
: 第一个参数为 address 即你要转账的地址,并补位到 32 字节即 64 个 16 进制字符0000000000000000000000000000000000000000000054b7d8ed70650b290000
: 第二个参数为 value 即你要转账的数量,并补位到 32 字节即 64 个 16 进制字符
通过对比分析我们可以发现 input data 的基本结构为函数标识符
+参数
bytess4(keccake256("transfer(adddress,uint256)"))
或者在线工具获取这种函数签名。下图可以看出加密结果的前四个字节 (a9059cbb) 跟 input data 中函数标识符一致。
在 evm 执行字节码的约定中,静态类型左补齐零至 64 长度,而动态类型则是右补齐零至 64 长度。
归纳下常见的静态类型:uint,bool,Address,bytes[0-32], 动态数组类型:bytes,string,address[],bytes32[].....
我们通过 pyethereum的ABI编码函数 来研究不同数据类型的编码方式。
静态类型
先导入 encode_abi 函数
from ethereum.abi import encode_abi
我们以函数 transfer(address,uint 256) 为例
000000000000000000000000345d8e3a1f62ee6b1d483890976fd66168e390f2
0000000000000000000000000000000000000000000000000000000000000001
对于小于 32 字节的定长数组会被自动填充到 32 字节:
// 自动填充 0
0000000000000000000000000000000000000000000000000000000000000001
0000000000000000000000000000000000000000000000000000000000000002
0000000000000000000000000000000000000000000000000000000000000003
动态类型
动态类型编码要稍微复杂一些,需要先计算偏移量进行占位处理,我们通过一个简单的例子来具体说明。
["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。
攻击过程如下:
函数标识符:a9059cbb
转账地址:
000000000000000000000000641988625108585185752230bde001b3ebd0fc
转账金额:
00000000000000000000000000000000000000000000000000000000000000001
由于 EVM 的补位规则,解析结果为:
0xa9059cbb000000000000000000000000641988625108585185752230bde001b3ebd0fc0000000000000000000000000000000000000000000000000000000000000000100
我们分解后发现,转账金额已经多了两位也就是多了一个字节,即为原来转账的 256倍
函数标识符:a9059cbb
转账地址:
000000000000000000000000641988625108585185752230bde001b3ebd0fc00
转账金额:
00000000000000000000000000000000000000000000000000000000000000100
我们以 MetaMask 钱包为例展示如何通过转账在 input data 字段附着一些额外的信息。
2、在转账时将你要附着的信息通过十六进制编码后填入下方十六进制数据中,记得在开头加上 0x 然后进行转账
3、转账成功后在 etherscan 中就能够看到附着信息
作者:创宇区块链安全实验室;来自链得得内容开放平台“得得号”,本文仅代表作者观点,不代表链得得官方立场凡“得得号”文章,原创性和内容的真实性由投稿人保证,如果稿件因抄袭、作假等行为导致的法律后果,由投稿人本人负责得得号平台发布文章,如有侵权、违规及其他不当言论内容,请广大读者监督,一经证实,平台会立即下线。如遇文章内容问题,请联系微信:chaindd123
评论(0)
Oh! no
您是否确认要删除该条评论吗?