抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

引言

在靶场刷题的时候经常会遇到各种涉及到create2操作码的题,这里整理了两个计算脚本(一个用于创建空参构造器的合约,另一个是用于创建带参构造器的合约),都是基于etherjs-v5

注:脚本只是辅助计算,并不是创建合约,创建合约还得通过智能合约来实现。

空参构造器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import { ethers } from "ethers"

const const_num = "0xFF";

const contract_add = "";

let str1 = const_num + contract_add.slice(2,contract_add.length);

const bytecode = "";

const bytecodeToHash = ethers.utils.solidityKeccak256(['bytes'],[bytecode]);

let salt = 0;
const value = ""; // 指定特殊值

while (true) {
let saltToHash = ethers.utils.solidityKeccak256(['uint'],[salt]);
saltToHash = saltToHash.slice(2, saltToHash.length)

let str2 = str1.concat(saltToHash).concat(bytecodeToHash.slice(2,bytecodeToHash.length));

let hash = ethers.utils.solidityKeccak256(['bytes'] ,[str2]);

//按照需求进行过滤
if (hash.slice(hash.length - 2, hash.length) == value) {
console.log(`salt = ${salt}`);
console.log(`address = 0x${hash.slice(26, hash.length)}`);
break;
}
salt++;
}

配合使用的solidity代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    // /* 使用内联汇编自带的 create2() */
function create2NewContractByInline(uint salt) public returns (address) {
// bytes memory code = type(Test).creationCode;
// 如果待部署合约的构造器中有参数,则使用如下方式进行获取code
bytes memory code = abi.encodePacked(type(Test).creationCode, abi.encode(msg.sender, "biyou"));
bytes32 _salt = keccak256(abi.encodePacked(salt));

address result;
assembly {
result := create2(
0, // value 表示要向新合约发送的以太币数量
add(code, 32), // 表示跳过数组长度
mload(code), // 读取code的长度
_salt // 盐
)
}
return result;
}

带参构造器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import { ethers } from "ethers"

const const_num = "0xFF";

const contract_add = ""; // deploy 合约地址

let str1 = const_num + contract_add.slice(2,contract_add.length);

let bytecode = "";
// 等同于 solidity中的 abi.encode()
const variable_code = new ethers.utils.AbiCoder().encode(['type'], [value]);

bytecode = bytecode + variable_code.slice(2,variable_code.length);

const bytecodeToHash = ethers.utils.solidityKeccak256(['bytes'],[bytecode]);

let salt = 0;
const value = ""; // 指定特殊值

while (true) {
let saltToHash = ethers.utils.solidityKeccak256(['uint'],[salt]);
saltToHash = saltToHash.slice(2, saltToHash.length)

let str2 = str1.concat(saltToHash).concat(bytecodeToHash.slice(2,bytecodeToHash.length));

let hash = ethers.utils.solidityKeccak256(['bytes'] ,[str2]);

//按照需求进行过滤
if (hash.slice(hash.length - 2, hash.length) == value) {
console.log(`salt = ${salt}`);
console.log(`address = 0x${hash.slice(26, hash.length)}`);
break;
}
salt++;
}


配合使用的solidity代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function create2NewContractByInline(uint salt) public returns (address) {

/* 如果待部署合约的构造器中有参数,则使用如下方式进行获取code
type():待部署的合约名
abi.encode():部署合约需要传入的参数
*/
bytes memory code = abi.encodePacked(type().creationCode, abi.encode());
bytes32 _salt = keccak256(abi.encodePacked(salt));

address result;
assembly {
result := create2(
0, // value 表示要向新合约发送的以太币数量
add(code, 32), // 表示跳过数组长度
mload(code), // 读取code的长度
_salt // 盐
)
}
return result;
}

补充

以上代码怎么说呢,毕竟是js代码嘛,数字的转化总会有问题,比如算某个地址对某个数取模是否等于某个值之类的,js代码不能轻易实现,反正对我来说不能,于是变自己编写了一个python 版的计算address的脚本。兼容了上述两种情况,完美应对待构建合约空参和有参两种情况。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
from web3 import Web3
from eth_abi import encode

# 固定常量 0xff
const_value = "0xff"

# value of your address(this), delet the `0x`
deployer_address = ""
deployer_address = deployer_address[2:]

# 将前两个值拼接起来
prefixed = const_value + deployer_address

# 这个为待部署合约的字节码
hacker_bytecode = ""

# 这里是构造器的参数,encode(['type'], ['value'])
parameter = encode([''],[""]).hex()

# 拼接 字节码 和 构造器参数
bytecode = "0x" + hacker_bytecode + parameter

# 对 bytecode 进行 hash 运算
bytecode_hash = Web3.solidity_keccak(['bytes'], [bytecode]).hex()
# print(bytecode_hash)

i = 0
while(True):

salt = Web3.solidity_keccak(['uint256'], [i]).hex()

data = prefixed + salt[2:] + bytecode_hash[2:]

hashed = Web3.solidity_keccak(['bytes'], [data]).hex()

# address(uint(uint160(hashed)))
address = hashed[26:]

# 按需求设置
if int(("0x" + address), 16) % 1000 == 137:
print("salt=", i)
print("address=", ("0x" + address))
break
i += 1


用了都说好!!!

版本

package.json:

1
2
3
4
5
6
{
"type": "module",
"dependencies": {
"ethers": "^5.7.2"
}
}

评论



政策 · 统计 | 本站使用 Volantis 主题设计