构造出一个返回值与code相等的字节码

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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
// SPDX-License-Identifier: UNLICENSED

pragma solidity 0.8.16;

contract Deployer {
constructor(bytes memory code) { assembly { return (add(code, 0x20), mload(code)) } }
}

contract Challenge {

bool public solved = false;

function safe(bytes memory code) private pure returns (bool) {
uint i = 0;
while (i < code.length) {
uint8 op = uint8(code[i]);

if (op >= 0x30 && op <= 0x48) {
return false;
}

if (
op == 0x54 // SLOAD
|| op == 0x55 // SSTORE
|| op == 0xF0 // CREATE
|| op == 0xF1 // CALL
|| op == 0xF2 // CALLCODE
|| op == 0xF4 // DELEGATECALL
|| op == 0xF5 // CREATE2
|| op == 0xFA // STATICCALL
|| op == 0xFF // SELFDESTRUCT
) return false;

if (op >= 0x60 && op < 0x80) i += (op - 0x60) + 1;

i++;
}

return true;
}

function solve(bytes memory code) external {
require(code.length > 0);
require(safe(code), "deploy/code-unsafe");
address target = address(new Deployer(code));
(bool ok, bytes memory result) = target.staticcall("");
require(
ok &&
keccak256(code) == target.codehash &&
keccak256(result) == target.codehash
);
solved = true;
}
}
contract Setup {

Challenge public challenge;

constructor() {
challenge = new Challenge();
}

function isSolved() public view returns (bool) {
return challenge.solved();
}
}

原理
如果没有require(safe(code), “deploy/code-unsafe”);
CODE: 0x600C6000600039600C6000F3

PUSH1: ?? 600C 指要COPY的code的长度
PUSH1: 00 6000 指要从哪个位置开始COPY
PUSH1: 00 6000 指要COPY到内存的哪个位置
CODECOPY 39

PUSH1 ?? 600C 指要读取的数据的长度
PUSH1 00 6000 指要从内存的指定位置开始读取
RETURN F3 F3

当有require(safe(code), “deploy/code-unsafe”);
CODE: 7F80607F60005360015260215260416000F300000000000000000000000000000080607F60005360015260215260416000F3000000000000000000000000000000

PUSH32 (??) 7F(??)
DUP1 80 80 复制一份

PUSH1 7F 607F 要存入内存的数据
PUSH1 00 6000 存入内存的地点
MSTORE8 53 53

PUSH1 01 6001
MSTORE 52 52

PUSH1 21 6021
MSTORE 52 52

PUSH1 41 6041
PUSH1 00 6000
RETURN F3 F3
STOP(*15) 00

CODE:7F(??)80607F60005360015260215260416000F3 000000000000000000000000000000
memory:7F(??)(??)
题目主要考察EVM字节码的构造,需要熟知才能运用自如