公開されてないSolidityのコードを分析してみよう!
こちらの記事でEtherscanのDecompile機能を使ってみた際に、他に似たようなサービスがないかと思って、こちらのOnline Solidity Decompilerを見つけたので使い方を備忘録的に残します。
手順
こちらにコントラクトアドレスと、ネットワークを設定してDecompileをクリックします。
すると、下記のように分析結果が確認できるページが生成されます。
早速中身を見てみましょう。
分析結果の確認
Public MethodはEtherscanでは復元できていなかったgetUserNameという関数が取得できています。
また、Internal Methodも別途表示されてわかりやすいです。
Assemblyの情報も出てきます。こちらも参考情報として使えそうです。
メインとなる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も知りたいな、と思って調べていたらこちらのツールでは確認できたので、併せてどうぞ!