SolidityのコードをDecompileして分析するOnline Solidity Decompilerの使い方

## 公開されてないSolidityのコードを分析してみよう！

[こちらの記事でEtherscanのDecompile機能を使ってみた](https://qiita.com/taijusanagi/items/8747fc650918f03a95ca)際に、他に似たようなサービスがないかと思って、こちらの[Online Solidity Decompiler](https://ethervm.io/decompile)を見つけたので使い方を備忘録的に残します。

## 手順
こちらにコントラクトアドレスと、ネットワークを設定してDecompileをクリックします。

![Screen Shot 2022-02-03 at 14.47.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258956/f1da8a33-85b7-929d-153c-4d6297cba6ed.png)

すると、下記のように分析結果が確認できるページが生成されます。

https://ethervm.io/decompile/0xb8fa8adc4f1a62613461183871382909a5ab5433

早速中身を見てみましょう。

## 分析結果の確認

Public MethodはEtherscanでは復元できていなかったgetUserNameという関数が取得できています。

![Screen Shot 2022-02-03 at 14.49.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258956/471d0c64-0741-5402-9f35-b3c4a5fa628b.png)

また、Internal Methodも別途表示されてわかりやすいです。

![Screen Shot 2022-02-03 at 14.49.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258956/29b2c447-dcf3-fa29-e543-e73641207969.png)

Assemblyの情報も出てきます。こちらも参考情報として使えそうです。

![Screen Shot 2022-02-03 at 14.51.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258956/01c6afc4-92e9-3bf9-f58b-7bf57a3d8f99.png)


メインとなるDecompileの結果は参考に全文記載します。

```
contract Contract {
    function main() {
        memory[0x40:0x60] = 0x60;
    
        if (msg.data.length < 0x04) { revert(memory[0x00:0x00]); }
    
        var var0 = msg.data[0x00:0x20] / 0x0100000000000000000000000000000000000000000000000000000000 & 0xffffffff;
    
        if (var0 == 0x1d34866f) {
            // Dispatch table entry for 0x1d34866f (unknown)
            if (msg.value) { revert(memory[0x00:0x00]); }
        
            var var1 = 0x00cd;
            var temp0 = msg.data[0x04:0x24] + 0x04;
            var temp1 = msg.data[temp0:temp0 + 0x20];
            var temp2 = memory[0x40:0x60];
            memory[0x40:0x60] = temp2 + (temp1 + 0x1f) / 0x20 * 0x20 + 0x20;
            memory[temp2:temp2 + 0x20] = temp1;
            memory[temp2 + 0x20:temp2 + 0x20 + temp1] = msg.data[temp0 + 0x20:temp0 + 0x20 + temp1];
            var var2 = temp2;
            var1 = func_02E4(var2);
            var temp3 = memory[0x40:0x60];
            memory[temp3:temp3 + 0x20] = !!var1;
            var temp4 = memory[0x40:0x60];
            return memory[temp4:temp4 + (temp3 + 0x20) - temp4];
        } else if (var0 == 0x704f1b94) {
            // Dispatch table entry for registerUser(string)
            if (msg.value) { revert(memory[0x00:0x00]); }
        
            var1 = 0x0142;
            var temp5 = msg.data[0x04:0x24] + 0x04;
            var temp6 = msg.data[temp5:temp5 + 0x20];
            var temp7 = memory[0x40:0x60];
            memory[0x40:0x60] = temp7 + (temp6 + 0x1f) / 0x20 * 0x20 + 0x20;
            memory[temp7:temp7 + 0x20] = temp6;
            memory[temp7 + 0x20:temp7 + 0x20 + temp6] = msg.data[temp5 + 0x20:temp5 + 0x20 + temp6];
            var2 = temp7;
            registerUser(var2);
            stop();
        } else if (var0 == 0xbf40fac1) {
            // Dispatch table entry for getAddress(string)
            if (msg.value) { revert(memory[0x00:0x00]); }
        
            var1 = 0x019f;
            var temp8 = msg.data[0x04:0x24] + 0x04;
            var temp9 = msg.data[temp8:temp8 + 0x20];
            var temp10 = memory[0x40:0x60];
            memory[0x40:0x60] = temp10 + (temp9 + 0x1f) / 0x20 * 0x20 + 0x20;
            memory[temp10:temp10 + 0x20] = temp9;
            memory[temp10 + 0x20:temp10 + 0x20 + temp9] = msg.data[temp8 + 0x20:temp8 + 0x20 + temp9];
            var2 = temp10;
            var1 = getAddress(var2);
            var temp11 = memory[0x40:0x60];
            memory[temp11:temp11 + 0x20] = var1 & 0xffffffffffffffffffffffffffffffffffffffff;
            var temp12 = memory[0x40:0x60];
            return memory[temp12:temp12 + (temp11 + 0x20) - temp12];
        } else if (var0 == 0xd84f55ee) {
            // Dispatch table entry for getUserName(address)
            if (msg.value) { revert(memory[0x00:0x00]); }
        
            var1 = 0x0218;
            var2 = msg.data[0x04:0x24] & 0xffffffffffffffffffffffffffffffffffffffff;
            var1 = getUserName(var2);
            var temp13 = memory[0x40:0x60];
            var2 = temp13;
            var var3 = var2;
            var temp14 = var3 + 0x20;
            memory[var3:var3 + 0x20] = temp14 - var3;
            var temp15 = var1;
            memory[temp14:temp14 + 0x20] = memory[temp15:temp15 + 0x20];
            var var4 = temp14 + 0x20;
            var var5 = temp15 + 0x20;
            var var6 = memory[temp15:temp15 + 0x20];
            var var7 = var6;
            var var8 = var4;
            var var9 = var5;
            var var10 = 0x00;
        
            if (var10 >= var7) {
            label_0258:
                var temp16 = var6;
                var4 = temp16 + var4;
                var5 = temp16 & 0x1f;
            
                if (!var5) {
                    var temp17 = memory[0x40:0x60];
                    return memory[temp17:temp17 + var4 - temp17];
                } else {
                    var temp18 = var5;
                    var temp19 = var4 - temp18;
                    memory[temp19:temp19 + 0x20] = ~(0x0100 ** (0x20 - temp18) - 0x01) & memory[temp19:temp19 + 0x20];
                    var temp20 = memory[0x40:0x60];
                    return memory[temp20:temp20 + (temp19 + 0x20) - temp20];
                }
            } else {
            label_0246:
                var temp21 = var10;
                memory[var8 + temp21:var8 + temp21 + 0x20] = memory[var9 + temp21:var9 + temp21 + 0x20];
                var10 = temp21 + 0x20;
            
                if (var10 >= var7) { goto label_0258; }
                else { goto label_0246; }
            }
        } else if (var0 == 0xed3db67c) {
            // Dispatch table entry for 0xed3db67c (unknown)
            if (msg.value) { revert(memory[0x00:0x00]); }
        
            var1 = 0x02ca;
            var2 = msg.data[0x04:0x24] & 0xffffffffffffffffffffffffffffffffffffffff;
            var1 = func_0652(var2);
            var temp22 = memory[0x40:0x60];
            memory[temp22:temp22 + 0x20] = !!var1;
            var temp23 = memory[0x40:0x60];
            return memory[temp23:temp23 + (temp22 + 0x20) - temp23];
        } else { revert(memory[0x00:0x00]); }
    }
    
    function func_02E4(var arg0) returns (var r0) {
        var var0 = 0x00;
        var var1 = var0 & 0xffffffffffffffffffffffffffffffffffffffff;
        var var2 = 0x01;
        var temp0 = arg0;
        var var3 = temp0;
        var var4 = memory[0x40:0x60];
        var var5 = var4;
        var var7 = memory[var3:var3 + 0x20];
        var var6 = var3 + 0x20;
        var var8 = var7;
        var var9 = var5;
        var var10 = var6;
    
        if (var8 < 0x20) {
        label_0335:
            var temp1 = 0x0100 ** (0x20 - var8) - 0x01;
            var temp2 = var9;
            memory[temp2:temp2 + 0x20] = (memory[var10:var10 + 0x20] & ~temp1) | (memory[temp2:temp2 + 0x20] & temp1);
            var temp3 = var7 + var5;
            memory[temp3:temp3 + 0x20] = var2;
            var temp4 = memory[0x40:0x60];
        
            if (storage[keccak256(memory[temp4:temp4 + (temp3 + 0x20) - temp4])] & 0xffffffffffffffffffffffffffffffffffffffff != var1) { return var0; }
            else { return 0x01; }
        } else {
        label_031B:
            var temp5 = var10;
            var temp6 = var9;
            memory[temp6:temp6 + 0x20] = memory[temp5:temp5 + 0x20];
            var9 = temp6 + 0x20;
            var10 = temp5 + 0x20;
            var8 = var8 - 0x20;
        
            if (var8 < 0x20) { goto label_0335; }
            else { goto label_031B; }
        }
    }
    
    function registerUser(var arg0) {
        var var0 = 0x03b8;
        var var1 = msg.sender;
        var0 = func_0652(var1);
    
        if (!var0) { revert(memory[0x00:0x00]); }
    
        var0 = 0x03cc;
        var1 = arg0;
        var0 = func_02E4(var1);
    
        if (!var0) { revert(memory[0x00:0x00]); }
    
        var temp0 = arg0;
        memory[0x00:0x20] = msg.sender;
        memory[0x20:0x40] = 0x00;
        var0 = 0x0429;
        var1 = keccak256(memory[0x00:0x40]);
        var var3 = memory[temp0:temp0 + 0x20];
        var var2 = temp0 + 0x20;
        var0 = func_0723(var1, var2, var3);
        var0 = msg.sender;
        var1 = 0x01;
        var temp1 = arg0;
        var2 = temp1;
        var3 = memory[0x40:0x60];
        var var4 = var3;
        var var6 = memory[var2:var2 + 0x20];
        var var5 = var2 + 0x20;
        var var7 = var6;
        var var8 = var4;
        var var9 = var5;
    
        if (var7 < 0x20) {
        label_0463:
            var temp2 = 0x0100 ** (0x20 - var7) - 0x01;
            var temp3 = var8;
            memory[temp3:temp3 + 0x20] = (memory[var9:var9 + 0x20] & ~temp2) | (memory[temp3:temp3 + 0x20] & temp2);
            var temp4 = var6 + var4;
            memory[temp4:temp4 + 0x20] = var1;
            var temp5 = memory[0x40:0x60];
            var temp6 = keccak256(memory[temp5:temp5 + (temp4 + 0x20) - temp5]);
            storage[temp6] = (var0 & 0xffffffffffffffffffffffffffffffffffffffff) | (storage[temp6] & ~0xffffffffffffffffffffffffffffffffffffffff);
            return;
        } else {
        label_0449:
            var temp7 = var9;
            var temp8 = var8;
            memory[temp8:temp8 + 0x20] = memory[temp7:temp7 + 0x20];
            var8 = temp8 + 0x20;
            var9 = temp7 + 0x20;
            var7 = var7 - 0x20;
        
            if (var7 < 0x20) { goto label_0463; }
            else { goto label_0449; }
        }
    }
    
    function getAddress(var arg0) returns (var r0) {
        var var0 = 0x00;
        var var1 = 0x01;
        var temp0 = arg0;
        var var2 = temp0;
        var var3 = memory[0x40:0x60];
        var var4 = var3;
        var var6 = memory[var2:var2 + 0x20];
        var var5 = var2 + 0x20;
        var var7 = var6;
        var var8 = var4;
        var var9 = var5;
    
        if (var7 < 0x20) {
        label_0511:
            var temp1 = 0x0100 ** (0x20 - var7) - 0x01;
            var temp2 = var8;
            memory[temp2:temp2 + 0x20] = (memory[var9:var9 + 0x20] & ~temp1) | (memory[temp2:temp2 + 0x20] & temp1);
            var temp3 = var6 + var4;
            memory[temp3:temp3 + 0x20] = var1;
            var temp4 = memory[0x40:0x60];
            return storage[keccak256(memory[temp4:temp4 + (temp3 + 0x20) - temp4])] & 0xffffffffffffffffffffffffffffffffffffffff;
        } else {
        label_04F7:
            var temp5 = var9;
            var temp6 = var8;
            memory[temp6:temp6 + 0x20] = memory[temp5:temp5 + 0x20];
            var8 = temp6 + 0x20;
            var9 = temp5 + 0x20;
            var7 = var7 - 0x20;
        
            if (var7 < 0x20) { goto label_0511; }
            else { goto label_04F7; }
        }
    }
    
    function getUserName(var arg0) returns (var r0) {
        var var0 = 0x0574;
        var0 = func_07A3();
        memory[0x00:0x20] = arg0 & 0xffffffffffffffffffffffffffffffffffffffff;
        memory[0x20:0x40] = 0x00;
        var temp0 = keccak256(memory[0x00:0x40]);
        var temp1 = storage[temp0];
        var temp2 = (!(temp1 & 0x01) * 0x0100 - 0x01 & temp1) / 0x02;
        var temp3 = memory[0x40:0x60];
        memory[0x40:0x60] = temp3 + (temp2 + 0x1f) / 0x20 * 0x20 + 0x20;
        var var1 = temp3;
        var var2 = temp0;
        var var3 = temp2;
        memory[var1:var1 + 0x20] = var3;
        var var4 = var1 + 0x20;
        var var5 = var2;
        var temp4 = storage[var5];
        var var6 = (!(temp4 & 0x01) * 0x0100 - 0x01 & temp4) / 0x02;
    
        if (!var6) {
        label_0646:
            return var1;
        } else if (0x1f < var6) {
            var temp5 = var4;
            var temp6 = temp5 + var6;
            var4 = temp6;
            memory[0x00:0x20] = var5;
            var temp7 = keccak256(memory[0x00:0x20]);
            memory[temp5:temp5 + 0x20] = storage[temp7];
            var5 = temp7 + 0x01;
            var6 = temp5 + 0x20;
        
            if (var4 <= var6) { goto label_063D; }
        
        label_0629:
            var temp8 = var5;
            var temp9 = var6;
            memory[temp9:temp9 + 0x20] = storage[temp8];
            var5 = temp8 + 0x01;
            var6 = temp9 + 0x20;
        
            if (var4 > var6) { goto label_0629; }
        
        label_063D:
            var temp10 = var4;
            var temp11 = temp10 + (var6 - temp10 & 0x1f);
            var6 = temp10;
            var4 = temp11;
            goto label_0646;
        } else {
            var temp12 = var4;
            memory[temp12:temp12 + 0x20] = storage[var5] / 0x0100 * 0x0100;
            var4 = temp12 + 0x20;
            var6 = var6;
            goto label_0646;
        }
    }
    
    function func_0652(var arg0) returns (var r0) {
        var var0 = 0x00;
        var temp0 = memory[0x40:0x60];
        var var1 = keccak256(memory[temp0:temp0 + memory[0x40:0x60] - temp0]);
        memory[0x00:0x20] = arg0 & 0xffffffffffffffffffffffffffffffffffffffff;
        memory[0x20:0x40] = 0x00;
        var var2 = keccak256(memory[0x00:0x40]);
        var var3 = memory[0x40:0x60];
        var var4 = var3;
        var var5 = var2;
        var temp1 = storage[var5];
        var var6 = (!(temp1 & 0x01) * 0x0100 - 0x01 & temp1) / 0x02;
    
        if (!var6) {
        label_0702:
            var temp2 = memory[0x40:0x60];
        
            if (keccak256(memory[temp2:temp2 + var4 - temp2]) != var1) { return var0; }
            else { return 0x01; }
        } else if (0x1f < var6) {
            var temp3 = var4;
            var temp4 = temp3 + var6;
            var4 = temp4;
            memory[0x00:0x20] = var5;
            var temp5 = keccak256(memory[0x00:0x20]);
            memory[temp3:temp3 + 0x20] = storage[temp5];
            var5 = temp5 + 0x01;
            var6 = temp3 + 0x20;
        
            if (var4 <= var6) { goto label_0702; }
        
        label_06EE:
            var temp6 = var5;
            var temp7 = var6;
            memory[temp7:temp7 + 0x20] = storage[temp6];
            var5 = temp6 + 0x01;
            var6 = temp7 + 0x20;
        
            if (var4 > var6) { goto label_06EE; }
            else { goto label_0702; }
        } else {
            var temp8 = var4;
            memory[temp8:temp8 + 0x20] = storage[var5] / 0x0100 * 0x0100;
            var temp9 = var6 + temp8;
            var6 = var6;
            var4 = temp9;
            goto label_0702;
        }
    }
    
    function func_0723(var arg0, var arg1, var arg2) returns (var r0) {
        var temp0 = arg0;
        var temp1 = storage[temp0];
        memory[0x00:0x20] = temp0;
        var var0 = keccak256(memory[0x00:0x20]);
        var var1 = arg1;
        arg1 = var0 + ((!(temp1 & 0x01) * 0x0100 - 0x01 & temp1) / 0x02 + 0x1f) / 0x20;
    
        if (0x1f < arg2) {
            var temp2 = arg2;
            storage[arg0] = temp2 + temp2 + 0x01;
        
            if (!temp2) {
            label_0792:
                var temp3 = arg1;
                arg1 = 0x079f;
                var0 = var0;
                arg2 = temp3;
                arg1 = func_07B7(arg2, var0);
                return arg0;
            } else {
                var temp4 = arg2;
                var temp5 = var1;
                arg2 = temp5;
                var1 = arg2 + temp4;
            
                if (var1 <= arg2) {
                label_0791:
                    goto label_0792;
                } else {
                label_077F:
                    var temp6 = arg2;
                    var temp7 = var0;
                    storage[temp7] = memory[temp6:temp6 + 0x20];
                    arg2 = temp6 + 0x20;
                    var0 = temp7 + 0x01;
                    var1 = var1;
                
                    if (var1 <= arg2) { goto label_0791; }
                    else { goto label_077F; }
                }
            }
        } else {
            var temp8 = arg2;
            storage[arg0] = temp8 + temp8 | (memory[var1:var1 + 0x20] & ~0xff);
            goto label_0792;
        }
    }
    
    function func_07A3() returns (var r0) {
        var temp0 = memory[0x40:0x60];
        memory[0x40:0x60] = temp0 + 0x20;
        memory[temp0:temp0 + 0x20] = 0x00;
        return temp0;
    }
    
    function func_07B7(var arg0, var arg1) returns (var r0) {
        var temp0 = arg0;
        arg0 = 0x07d9;
        var temp1 = arg1;
        var var0 = temp1;
        arg1 = temp0;
    
        if (arg1 <= var0) { return func_07D5(arg1, var0); }
    
    label_07C6:
        var temp2 = var0;
        storage[temp2] = 0x00;
        var0 = temp2 + 0x01;
    
        if (arg1 > var0) { goto label_07C6; }
    
        arg0 = func_07D5(arg1, var0);
        // Error: Could not resolve method call return address!
    }
    
    function func_07D5(var arg0, var arg1) returns (var r0) { return arg0; }
}
```

NFTやマーケットのコントラクトが公開されてない場合に分析したい、ようなケースでも使えるので、ぜひ使ってみてください！

こちらもなかなか使えそうなツールでした！また、今回のツールでsolidityのcompilerのversionも知りたいな、と思って調べていたらこちらのツールでは確認できたので、併せてどうぞ！

https://qiita.com/taijusanagi/items/2c9f742bd091bdba1912