以太坊上的智能合约几乎都是开源的,没有开源的智能合约就无从信任。但有些智能合约没有开源,反编译是研究的重要方式,可通过直接研究EVM的ByteCode。
如何对合约进行逆向分析,下面结合ctf实例介绍区块链合约逆向如何开展,希望区块链入门者能从中学到知识。


ctf实例1

给了bytecode字节码及交互记录

ByteCode:

0x60806040526004361061006d576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806304618359146100725780631cbeae5e1461009f578063890eba68146100cc578063a2da82ab146100f7578063f0fdf83414610127575b600080fd5b34801561007e57600080fd5b5061009d60048036038101908080359060200190929190505050610154565b005b3480156100ab57600080fd5b506100ca6004803603810190808035906020019092919050505061015e565b005b3480156100d857600080fd5b506100e1610171565b6040518082815260200191505060405180910390f35b34801561010357600080fd5b50610125600480360381019080803560ff169060200190929190505050610177565b005b34801561013357600080fd5b50610152600480360381019080803590602001909291905050506101bb565b005b8060008190555050565b6000548114151561016e57600080fd5b50565b60005481565b60008060009150600090505b60108110156101ab576008829060020a0291508260ff16821891508080600101915050610183565b8160005418600081905550505050565b8060036000540201600081905550505600a165627a7a7230582012c9c1368a7902a818e339b8db79b7130db8795bd2a793898b509dc020d960d20029

交互日志:

log1:func_0177
0xa2da82ab0000000000000000000000000000000000000000000000000000000000000009

log2: #a()
0xf0fdf83400000000000000000000000000000000000000000000000000000000deadbeaf

log3: #func_0177
0xa2da82ab0000000000000000000000000000000000000000000000000000000000000007

log4: #flag()
secret.flag
{
    "0": "uint256: 36269314025157789027829875601337027084"
}

在线反编译

https://ethervm.io/decompile 反编译bytecode
直接输入bytecode(不要加0x,输入十六进制值即可)

反编译得到

contract Contract {
    function main() {
        memory[0x40:0x60] = 0x80;

        if (msg.data.length < 0x04) { revert(memory[0x00:0x00]); }

        var var0 = msg.data[0x00:0x20] / 0x0100000000000000000000000000000000000000000000000000000000 & 0xffffffff;

        if (var0 == 0x04618359) {
            // Dispatch table entry for 0x04618359 (unknown)
            var var1 = msg.value;

            if (var1) { revert(memory[0x00:0x00]); }

            var1 = 0x009d;
            var var2 = msg.data[0x04:0x24];
            func_0154(var2);
            stop();
        } else if (var0 == 0x1cbeae5e) {
            // Dispatch table entry for winner(uint256)
            var1 = msg.value;

            if (var1) { revert(memory[0x00:0x00]); }

            var1 = 0x00ca;
            var2 = msg.data[0x04:0x24];
            winner(var2);
            stop();
        } else if (var0 == 0x890eba68) {
            // Dispatch table entry for flag()
            var1 = msg.value;

            if (var1) { revert(memory[0x00:0x00]); }

            var1 = 0x00e1;
            var2 = flag();
            var temp0 = memory[0x40:0x60];
            memory[temp0:temp0 + 0x20] = var2;
            var temp1 = memory[0x40:0x60];
            return memory[temp1:temp1 + (temp0 + 0x20) - temp1];
        } else if (var0 == 0xa2da82ab) {
            // Dispatch table entry for 0xa2da82ab (unknown)
            var1 = msg.value;

            if (var1) { revert(memory[0x00:0x00]); }

            var1 = 0x0125;
            var2 = msg.data[0x04:0x24] & 0xff;
            func_0177(var2);
            stop();
        } else if (var0 == 0xf0fdf834) {
            // Dispatch table entry for a(uint256)
            var1 = msg.value;

            if (var1) { revert(memory[0x00:0x00]); }

            var1 = 0x0152;
            var2 = msg.data[0x04:0x24];
            a(var2);
            stop();
        } else { revert(memory[0x00:0x00]); }
    }

    function func_0154(var arg0) {
        storage[0x00] = arg0;
    }

    function winner(var arg0) {
        if (arg0 == storage[0x00]) { return; }
        else { revert(memory[0x00:0x00]); }
    }

    function flag() returns (var r0) { return storage[0x00]; }

    function func_0177(var arg0) {
        var var0 = 0x00;
        var var1 = 0x00;

        if (var1 >= 0x10) {
        label_01AB:
            storage[0x00] = storage[0x00] ~ var0; //这里~符号应为异或 xor
            return;
        } else {
        label_018D:
            var0 = var0 * 0x02 ** 0x08 ~ (arg0 & 0xff); 
            var1 = var1 + 0x01;

            if (var1 >= 0x10) { goto label_01AB; }
            else { goto label_018D; }
        }
    }

    function a(var arg0) {
        storage[0x00] = storage[0x00] * 0x03 + arg0;
    }
}

ethervm.io也给出了函数的调用情况

--Public Methods
Method names cached from 4byte.directory.
点击收藏 | 2 关注 | 1
  • 动动手指,沙发就是你的了!
登录 后跟帖