EVM-Puzzles 通关笔记
22小时前 750
这里我们就需要从 JUMP
去跳转到 JUMPDEST
的位置,也就是08的地方。否则就是 REVERT
我们来分析这个EVM字节码
这里我们要跳转到08的位置,使用https://www.evm.codes/playground 模拟一下
这里JUMP之后就会跳转到JUMPDEST位置
成功走入这个位置。
这一关和第一关很像,也是需要我们利用JUMP去跳转到JUMPDEST的位置,但是在CALLVALUE之后又有一个CODESIZE,它的意思是将当前合约的代码大小压入栈中,这里很明显会压入一个 a
。然后调用SUB去做减法。
我们这里是要跳转到 06
的位置,现在已经确定了: a - ? = 6
,那么我们只需要CALLVALUE传入4 wei即可。
减完之后就等于6,然后JUMP就会跳转成功
和第一关如出一辙,只是这里不是 CALLVALUE
而是 CALLDATASIZE
,它是会将CALLDATA的字节大小压入栈中
calldata 是一个编码的十六进制数字块,其中包含有关我们要调用的合约函数及其参数或数据的信息。简而言之,它包含一个“函数 id”,它是通过散列函数签名(截断为前四个字节)后跟打包参数数据生成的。
这里我们随意的传入一个4 bytes数据即可
这里用到的几个EVM ByteCode我们再来回顾一下:
1 2 3 |
|
因为栈是LIFO队列,所以异或的时候是这样的: XOR(CODESIZE,CALLVALUE)
我们已知CODESIZE = 0xC ,结果是0xA,所以我们这里就需要将0xc ^ 0xa = 0x6
这次的几个字节码有几个很陌生,我们来解释一下:
1 2 3 4 5 6 7 |
|
解题思路
我们的msg.value 的值的平方需要等于0x100,这样才能保证后面eq之后结果为1,让后面的JUMPI可以成功跳转到0xc的位置,所以这里0x100开根号的结果是16
介绍一下新引入的字节码:
1 |
|
这里假设我们的calldata为0x1234,如果在calldataload之前我们去push1 00 ,这就意味着偏移为0. 那么我们在栈中就会得到:
1234000000000000000000000000000000000000000000000000000000000000
如果PUSH1 01的话,偏移就是1.我们在栈中就会得到
3400000000000000000000000000000000000000000000000000000000000000
所以这一关,我们就需要给它传入一个:
0x000000000000000000000000000000000000000000000000000000000000000A
这一关的字节码明显比之前的复杂很多,我们在这里将这一关所用到的字节码都再次回顾一遍:
1 2 3 4 |
|
destOffset
:内存中的字节偏移量,复制操作的结果将被复制到此。offset
:Calldata中的字节偏移量size
: 复制到内存中的calldata数据的字节大小。1 |
|
value
: 发送到新账户的valueoffset
:你想从哪里开始复制新合约的代码的字节偏移。input3: size
: 从内存偏移量开始复制指令的字节大小。
EXTCODESIZE
:从栈中弹出一个值,作为20字节的地址使用。这个地址将被用来 "查询 "目标合约,并得到合约代码的字节大小作为结果。结果被推回堆栈
我们先随便传入一些数据看一下执行到后面是什么情况。
也就是说我们只需要满足 EXTCODESIZE
的结果是1就可以了。这样就需要保证我们返回的运行时代码只有一条指令。
RETURN指令
从栈中获取两个值作为输入
第一个参数:为运行时代码在内存的起始位置
第二个参数:截取长度
1 2 3 4 5 6 |
|
在0内存写入1,然后return的内容为内存0的位置,长度为1
这样返回的就是1了,这段代码的字节码为: 600160005360016000f3
,那我们msg.data = 0x600160005360016000f3
尝试传入
成功解题
这次引入了几个新的字节码,我们来看一下是什么意思
SWAP1
的意思是:栈顶[a,b]变成[b,a]。那么SWAP5的意思就是[a,x,x,x,x,b]变成[b,x,x,x,x,a]。CALL:调用合约,有七个参数:
retLen
若交易成功 将 1 写入栈顶,若失败,将0写入栈顶。
分析一下逻辑
一、 先部署合约
1 2 3 4 5 6 7 8 |
|
二、调用合约
1 2 3 4 5 6 7 8 |
|
三、对比结果调用
1 2 3 4 |
|
通过这些信息我们可以看出来,第二步的CALL合约交易需要失败才可以对比成功。如何让交易失败呢?
REVERT → 0xfd
我们返回一个异常给他即可,还是利用我们第七关的代码
1 2 3 4 5 6 7 |
|
这里可以看到call之后返回了0
又有几个新的字节码引入:
分析程序
1 2 3 4 5 |
|
这里只需要保证我们传入大于3个字节的数据即可。
1 2 3 4 5 6 7 8 |
|
这里是检查我们传入的wei与我们传入的字节相乘是否等于8,假设我们刚才传入的是 0x12345678
也就是四个字节,这里我们再传入的是2wei即可。
又有几个新的字节码引入:
分析
1 2 3 4 5 6 |
|
这里要求我们传入的wei小于1b才可以通过
1 2 3 4 5 6 7 8 9 10 11 12 |
|
这里满足跳转的条件是跳转到19,也就是ADD(0xA,CALLVALUE) == 19,我们就需要传入15(十六进制0xF)
前面的判断CALLDATA为空就可以过,或者CALLDATASIZE是3的倍数。
撒花完结~