MagicNumber

题目网站:Ethernaut (openzeppelin.com)

通关条件

部署一个只有 10 个 opcode 的合约,该合约在调用后返回 42

题目合约

pragma solidity ^0.5.0;

contract MagicNum {

  address public solver;

  constructor() public {}

  function setSolver(address _solver) public {
    solver = _solver;
  }

  /*
    ____________/\\\_______/\\\\\\\\\_____
     __________/\\\\\_____/\\\///\\\___
      ________/\\\/\\\____\///______\//\\\__
       ______/\\\/\/\\\______________/\\\/___
        ____/\\\/__\/\\\___________/\\\//_____
         __/\\\\\\\\\\\\\\\\_____/\\\//________
          _\///\\\//____/\\\/___________
           ___________\/\\\_____/\\\\\\\\\\\\\\\_
            ___________\///_____\///__
  */
}

解题过程

创建合约的交易的 bytecode 主要由初始化代码和运行时代码两部分组成。初始化代码用于创建合约,并存储运行时代码;运行时代码则是合约的实际逻辑。

首先考虑运行时代码。我们需要将 42(0x2A)存放到内存中,再返回给调用者。第一个步骤需要使用 MSTORE(0x52,用于将一个 (u)int256 写入内存,0x52),第二个步骤需要使用 RETURN(0xF3,返回合约调用的结果)。

第一步:

PUSH1 0x2A(PUSH1,0x60,用于将 1 byte 的值推入插槽栈中。这里我们需要存储 42)
PUSH1 0x80(我们将 0x2A 存入 slot 0x80)
MSTORE(以前两个元素作为参数调用 MSTORE)

所以该步骤的代码为 0x602A608052

第二步:

PUSH1 0x20(返回值的长度,我们设置为 32 bytes)
PUSH1 0x80(返回值存储在 slot 0x80)
RETURN(以前两个元素为参数调用 RETURN)

所以该步骤的代码为 0x60206080F3

两个步骤结合起来得到我们的运行时代码 0x602A60805260206080F3,刚好 10 个 opcode,同时也是 10 bytes。

现在考虑初始化代码。初始化代码需要拷贝运行时代码并返回给 EVM。第一个步骤需要使用 CODECOPY(0x39,用于拷贝运行时代码),第二个步骤也是 RETURN。

执行第一步:

PUSH1 0x0A(运行时代码的大小,10 bytes)
PUSH1 0x??(运行时代码目前的位置,现在还是未知)
PUSH1 0x00(运行时代码存储的目标位置,我们设定为 slot 0x00)
CODECOPY(以前三个元素为参数调用 CODECOPY)

所以该步骤代码为 0x600A60??600039

执行第二步:

PUSH1 0x0A(运行时代码的长度,10 bytes)
PUSH1 0x00(运行时代码存储的位置,slot 0x00)
RETURN(以前两个元素为参数调用 RETURN)

所以该步骤代码为 0x600A6000F3

结合以上两步我们可以得到初始化代码一共 12 bytes,运行时代码会接在初始化代码之后,所以上面的 0x?? 实际上是 0x0C(运行时代码在 bytecode 中的起始索引为 12)。由此得到我们的初始化代码 0x600A600C600039600A6000F3

将初始化代码和运行时代码组合起来就得到了我们的 bytecode:0x600A600C600039600A6000F3602A60805260206080F3

接下来部署我们的合约并设置为 Solver:

let bytecode = "0x600A600C600039600A6000F3602A60805260206080F3";
web3.eth.sendTransaction({from: player, data: bytecode});
// 通关 Etherscan 得到合约地址 contractAddress
await contract.setSolver("contractAddress");

另一篇参考文献:Ethernaut Lvl 19 MagicNumber Walkthrough: How to deploy contracts using raw assembly opcodes | by Nicole Zhu | Coinmonks | Medium

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值