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就完成了!!!