Skip to content

The Ethernaut writeups: 18 - Magic Number

Posted on:February 14, 2022

Hi mọi người!

Đã rất lâu rồi chúng ta mới có dịp quay lại với chuỗi bài Ethernaut, giờ đây đã có thêm 8 bài mới. Chúng ta hãy lần lượt đi tìm lời giải cho các bài toán mới nhé!

18. Magic Number

Nhiệm vụ: Viết một contract siêu ngắn tối đa 10 opcodes để trả về con số được mệnh danh là The Meaning of Life - con số 42.

Về con số 42, bạn có thể đọc thêm tại đây

// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;

contract MagicNum {

  address public solver;

  constructor() public {}

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

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

Phân tích

Về bytecode và opcode

contract-creation

Vậy tóm lại ta sẽ cần một chuỗi gồm:

EVM = Stack Machine

EVM là một stack machine, các phép toán được đưa vào dưới dạng hậu tố và thực hiện theo quy tắc Last In First Out của stack.

Vì thế khi tạo chuỗi opcodes ta cũng sẽ đưa nó vào chuỗi theo cấu trúc stack.

Solution

Tạo runtime bytecode

Ta cần trả về giá trị 42 với không quá 10 opcodes.

#StackOPCODEÝ nghĩabytecode
00<empty>PUSH1(60) 2apush 2a (hex) = 42 (dec) vào stack602a
022aPUSH1(60) 00push 00 vào stack6000
0500, 2aMSTORE(52)mstore(0, 2a), lưu trữ 2a = 42 vào vị trí 0 trong memory52
06<empty>PUSH1(60) 20push 20 (hex) = 32 (dec) vào stack (vì mỗi slot nhớ là 32 bytes)6020
0820PUSH1(60) 00push 00 vào stack6000
1000, 20RETURN(f3)return(0, 20), trả về 32 bytes ở vị trí 0f3

Ta được chuỗi runtime bytecodes602a60005260206000f3 có độ dài 10 opcodes.

Tạo creation bytecode

StackOPCODEÝ nghĩabytecode
<empty>PUSH10(69) 602a60005260206000f3push 10 bytes của runtime codes vào stack69602a60005260206000f3
602a60005260206000f3PUSH1(60) 00push 0 vào trong stack6000
00, 602a60005260206000f3MSTORE(52)lưu trữ runtime codes vào vị trí 00 trong memory52
<empty>PUSH1(60) 0apush 0a (hex) = 10 (dec) vào stack600a
0aPUSH1(60) 16push 16 (hex) = 22 (dec) vào stack6016
16, 0aRETURN(f3)trả về 10 bytes từ vị trí 22f3

Ta được chuỗi creation codes69602a60005260206000f3600052600a6016f3

Deploy & Set Solver

sendTransaction({
  from: player,
  data: `69602a60005260206000f3600052600a6016f3`,
});

transction hoàn thành sẽ tạo ra một contract mới, trong trường hợp của mình là 0x0F9F67f93D846fb2406De62195A8A50bd901d548

parseInt(await web3.eth.call({ to: '0x0F9F67f93D846fb2406De62195A8A50bd901d548', data: '0x' }));
> 42
contract.setSolver("0x0F9F67f93D846fb2406De62195A8A50bd901d548");

completed

Tham khảo