EVM puzzle
EVM PUZZLE
puzzle 1 CALLVALUE
题目:
pc opcode opcode name 01 38 CODESIZE 02 03 SUB 03 56 JUMP 04 FD REVERT 05 FD REVERT 06 5B JUMPDEST 07 00 STOP 08 FD REVERT 09 FD REVERT
输入恰当的value,使得题目的 opcode 正确执行,直到执行STOP
分析:CALLVALUE实际上就是msg.value,它会将msg.value存储到栈顶,而JUMP会读取栈顶值,并跳转到相应的字节地址,由JUMPDEST承接,所以我们只需要让msg.value==8即可
puzzles 2 CODESIZE
题目:
pc opcode opcode name 00 34 CALLVALUE 01 38 CODESIZE 02 03 SUB 03 56 JUMP 04 FD REVERT 05 FD REVERT 06 5B JUMPDEST 07 00 STOP 08 FD REVERT 09 FD REVERT
msg.value是多少?
分析:CALLVALUE存储值到栈顶,STACK:[x],CODESIZE获取当前EVM环境中的操作码SIZE,每个OPCODE为1byte,我们此时内存中共10个操作码,因此执行CODESIZE后,会向栈顶存入10,STACK:[10, x],SUB会执行减法操作,并将结果如栈,STACK:[10 - x]
JUMP会跳到06字节,因此我们需要 10 - x = 6,推导出:x = 4,即msg.value为4
puzzles 3 CALLDATASIZE
题目:
pc opcode opcode name 00 36 CALLDATASIZE 01 56 JUMP 02 FD REVERT 03 FD REVERT 04 5B JUMPDEST 05 00 STOP
calldata是多少?
分析:JUMPDEST跳转到04,所以我们只要保证calldata到size为4即可,内容不限。即len(msg.data) == 4,msg.data==0x11223344
补充:一个字节代表8位二进制数,一个16进制数代表4位二进制数,所以俩个16进制的数就代表一个字节
puzzles 4 XOR
题目:
pc opcode opcode name 00 34 CALLVALUE 01 38 CODESIZE 02 18 XOR 03 56 JUMP 04 FD REVERT 05 FD REVERT 06 FD REVERT 07 FD REVERT 08 FD REVERT 09 FD REVERT 0A 5B JUMPDEST 0B 00 STOP
value是多少?
分析:CALLVALUE获取数值后入栈,STACK:[x],CODESIZE获取数值为12入栈,STACK:[12, x]
异或操作:
12:0000,1100
0A:0000,1010
x: 0000,0110 =》6,所以答案为:6,即value为6
puzzles 5 JUPM1
题目:
pc opcode opcode name 00 34 CALLVALUE 01 80 DUP1 02 02 MUL 03 610100 PUSH2 0100 06 14 EQ 07 600C PUSH1 0C 09 57 JUMPI 0A FD REVERT 0B FD REVERT 0C 5B JUMPDEST 0D 00 STOP 0E FD REVERT 0F FD REVERT
value是多少?
分析:
- CALLVALUE,STACK-> [x]
- DUP1:STACK-> [x,x]
- MUL:STACK-> [mul_result]
- PUSH2 0100:STACK-> [0100,mul_result]
- EQ:判断stack1和stack2是否相等,若相等,则清除这两个值,并向栈顶存入1,否则存入0
- PUSH1 0C:STACK-> [0C, 1]
- JUMPI:读取stack2的值,如果为1,则跳转到stack1的位置,即0C,满足条件!
因此我们需要使得:0100 = x*x,0x0100十进制为256,所以x = 16,即value为16
puzzles 6 CALLDATALOAD
题目:
pc opcode opcode name 02 35 CALLDATALOAD 04 FD REVERT 05 FD REVERT 06 FD REVERT 07 FD REVERT 08 FD REVERT 09 FD REVERT 0A 5B JUMPDEST 0B 00 STOP
calldataload是 多少?
分析:
- PUSH1 00,STACK:【0x00】
- CALLDATALOAD:获取input的数据,即calldata,参数为0x00,即从第00位置开始加载
- JUMP想跳转到0A处,所以calldata的值为0x0a,如果我们直接输入0x0a,此时会被转化为:a00000000000000000000000000000000000000000000000000000000000000,这是错的;
- 由于calldata的数值总为32字节的倍数,所以此处应该为:0x000000000000000000000000000000000000000000000000000000000000000a
puzzles 7 EXTCODESIZE
题目:
pc opcode opcode name 00 36 CALLDATASIZE 01 6000 PUSH1 00 03 80 DUP1 04 37 CALLDATACOPY 05 36 CALLDATASIZE 06 6000 PUSH1 00 08 6000 PUSH1 00 0A F0 CREATE 0B 3B EXTCODESIZE 0C 6001 PUSH1 01 0E 14 EQ 0F 6013 PUSH1 13 11 57 JUMPI 12 FD REVERT 13 5B JUMPDEST 14 00 STOP
calldata是多少?
分析:逐步分析,
00 36 CALLDATASIZE # [datasize] 01 6000 PUSH1 00 # [00, datasize] 03 80 DUP1 # [00, 00, datasize] 04 37 CALLDATACOPY # [] data被copy到memory中,栈被清空 05 36 CALLDATASIZE # [datasize] 06 6000 PUSH1 00 # [00, datasize] 08 6000 PUSH1 00 # [00, 00, datasize] 0A F0 CREATE # [deployed_address] 栈被清空,从内存中读取数据,创建合约,返回地址 0B 3B EXTCODESIZE # [address_code_size] 输入地址,返回合约的size 0C 6001 PUSH1 01 # [01, address_code_size] 0E 14 EQ # [1] address_code_size必须为1,后续的才成立 0F 6013 PUSH1 13 11 57 JUMPI 12 FD REVERT 13 5B JUMPDEST 14 00 STOP
就是我们传入的数据要的操作码要返回1,利用return操作符
pc opcode opcode name 00 6001 PUSH1 01 04 F3 RETURN
即 msg.data == 0x60016000f3
puzzles 8 SWAP
题目:
pc opcode opcode name 00 36 CALLDATASIZE 01 6000 PUSH1 00 03 80 DUP1 04 37 CALLDATACOPY 05 36 CALLDATASIZE 06 6000 PUSH1 00 08 6000 PUSH1 00 0A F0 CREATE 0B 6000 PUSH1 00 0D 80 DUP1 0E 80 DUP1 0F 80 DUP1 10 80 DUP1 11 94 SWAP5 12 5A GAS 13 F1 CALL 14 6000 PUSH1 00 16 14 EQ 17 601B PUSH1 1B 19 57 JUMPI 1A FD REVERT 1B 5B JUMPDEST 1C 00 STOP
calldata是多少?
分析:
00 36 CALLDATASIZE # [datasize] 01 6000 PUSH1 00 # [00, datasize] 03 80 DUP1 # [00, 00, datasize] 04 37 CALLDATACOPY # [] copy到内存中 05 36 CALLDATASIZE # [datasize],直接生成数据,不需要栈参数 06 6000 PUSH1 00 # [00, datasize] 08 6000 PUSH1 00 # [00, 00, datasize] 0A F0 CREATE # [deployed_address] 0B 6000 PUSH1 00 # [00, deployed_address] 0D 80 DUP1 # [00, 00, deployed_address] 0E 80 DUP1 # [00, 00, 00, deployed_address] 0F 80 DUP1 # [00, 00, 00, 00, deployed_address] 10 80 DUP1 # [00, 00, 00, 00, 00, deployed_address] 11 94 SWAP5 # [deployed_address, 00, 00, 00, 00, 00],兑换1st 和 6th,你没有看错1和6,不是5 12 5A GAS # [gasAvail, deployed_address, 00, 00, 00, 00, 00] // 7个参数 13 F1 CALL # [0或1]调用函数,需要是0,0表示失败,1表示成功!(反推的 14 6000 PUSH1 00 # [00, 0或1],需要是0 16 14 EQ # [0或1],需要是1 17 601B PUSH1 1B # [1B, 0或1],需要是1 19 57 JUMPI 1A FD REVERT 1B 5B JUMPDEST 1C 00 STOP
逐步分析后,可得知我们需要做到call调用失败,这就要我们传入的数据revert,类似于puzzles#7
pc opcode opcode name 00 60FD PUSH1 FD //FD 是revert操作符的编号 02 6000 PUSH1 00 04 53 MSTORE8 05 6001 PUSH1 01 07 6000 PUSH1 00 09 F3 RETURN
即calldata= 0x60fd60005360016000f3
puzzles 9 LT
pc opcode opcode name 00 36 CALLDATASIZE 01 6003 PUSH1 03 03 10 LT 04 6009 PUSH1 09 06 57 JUMPI 07 FD REVERT 08 FD REVERT 09 5B JUMPDEST 0A 34 CALLVALUE 0B 36 CALLDATASIZE 0C 02 MUL 0D 6008 PUSH1 08 0F 14 EQ 10 6014 PUSH1 14 12 57 JUMPI 13 FD REVERT 14 5B JUMPDEST 15 00 STOP
value?
calldata?
分析:就是一个推理题,00-09:datasize>3,0A-12:value*datasize=8,datasize=4,value=2
calldata的字节数为4,随意构造calldata=0x12345678
puzzles 10 ISZERO
题目:
pc opcode opcode name 00 38 CODESIZE 01 34 CALLVALUE 02 90 SWAP1 03 11 GT 04 6008 PUSH1 08 06 57 JUMPI 07 FD REVERT 08 5B JUMPDEST 09 36 CALLDATASIZE 0A 610003 PUSH2 0003 0D 90 SWAP1 0E 06 MOD 0F 15 ISZERO 10 34 CALLVALUE 11 600A PUSH1 0A 13 01 ADD 14 57 JUMPI 15 FD REVERT 16 FD REVERT 17 FD REVERT 18 FD REVERT 19 5B JUMPDEST 1A 00 STOP
value?
calldata?
分析:00-06:value<23;09-0f:calldata mod 3==0;10-14:value+0a=19,注意19为16进制的数,value=15,calldata的字节数为3,随意构造calldta=0x123456
10道EVM puzzles就完成了!!!