前言
在刷chainflag-opcode-BoxGame发现这个很有趣,记录下。
Log1
用法
log1(offset, size, topic)
:
offset
: byte offset in the memory in bytes.size
: byte size to copy.topic1
: 32-byte value.以
event NewValue(uint256)
为例,offsize为 NewValue参数所在的位置,size为参数的长度,这里是 32bytes,topic1则是事件的hash即keccak256(abi.encodePacked("NewValue(uint256)"))
代码举例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 contract Logic {
event NewValue(uint newValue);
function captureFlag() public {
uint256 value = 0x999999999999999999999999999999999999999999;
bytes32 eventHash = keccak256(abi.encodePacked("NewValue(uint256)"));
assembly {
// To emit an event we first need to store the value in memory.
mstore(0xa0, value)
// Now to emit the event we use the log1 opcode.
// First arg is the memory address, second is the number of bytes and the third is the hashed event signature
log1(0xa0, 0x20, eventHash)
}
}
}结果:成功触发事件
触发其他类型的也行,如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 pragma solidity ^0.8.0;
contract Logic {
event SendFlag(address);
function captureFlag() public {
address owner = msg.sender;
bytes32 eventHash = keccak256(abi.encodePacked("SendFlag(address)"));
assembly {
mstore(0xa0, owner)
log1(0xa0, 0x20, eventHash)
}
}
}
同理,也可以触发多个参数的event
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 pragma solidity ^0.8.0;
contract Logic {
event NewValue(address, uint);
function captureFlag() public {
address owner = msg.sender;
uint256 value = 0x999999999999999999999999999999999999999999;
bytes32 eventHash = keccak256(abi.encodePacked("NewValue(address,uint256)"));
assembly {
mstore(0x80, owner)
mstore(0xa0, value)
log1(0x80, 0x40, eventHash)
}
}
}
📌 注:size一定要是32byres的倍数,即使
event SendFlag(address)
中的参数是20bytes,但是也要将长度的写成0x20
,其实这里只要是32的bytes即可,0x40也ok的。
奇怪的事
比如我在A合约中并没定义某个事件,而是在B合约中定义了,在A合约也可以触发事件,如下所示:
但是,如果将 Proxy中的合约 event注视掉,则不会触发该事件,就感觉很神奇。
如果不使用内联汇编的话,这里很明显会报错,如下: