EtherscanのDecompile機能
過去に開発したイーサリアムのプロジェクトを復元する際に、ソースコードが残っておらす、Etherscanで検証・公開するのも忘れていて、となって困っていた時に、EtherscanのDecompile機能がとても便利だったので備忘録として残します。
EtherscanのDecompileは公開されてないコントラクトロジックを、完全ではないですが少しわかりやすいように分析してくれるツールです。それでは早速やってみましょう!
手順
今回は僕が初めてメインネットにデプロイしたコントラクトの復元をおこなっていきます。
こちらはコードの検証・公開を忘れていたため、Etherscanからソースコードにアクセスすることができません。そんな時はDecompile Bytecodeをクリックして
こちらのEVM bytecode decompilerというページにアクセスして、Decompileをクリックします。30秒後にリフレッシュして結果を見てね、という指示に従って、リフレッシュ後にもう一度Decompile Bytecodeをクリックします。
すると、下記のようにDecompileされたコードにアクセスすることができます。
こちら復元したコードをコピーして記載しておきます。
# Decompiled source of 0xB8fA8Adc4f1a62613461183871382909a5Ab5433
#
# Let's make the world open source
#
def storage:
unknownd84f55ee is array of struct at storage 0
stor99 is mapping of addr at storage 99
def unknownd84f55ee(addr _param1): # not payable
return uint256(unknownd84f55ee[addr(_param1)][0 len unknownd84f55ee[addr(_param1)].length].field_0)
#
# Regular functions
#
def _fallback() payable: # default function
revert
def unknowned3db67c(addr _param1): # not payable
mem[96] = uint256(unknownd84f55ee[addr(_param1)].field_0)
idx = 96
s = 0
while unknownd84f55ee[addr(_param1)].length + 96 > idx + 32:
mem[idx + 32] = uint256(unknownd84f55ee[addr(_param1)][s].field_256)
idx = idx + 32
s = s + 1
continue
if sha3(mem[96 len unknownd84f55ee[addr(_param1)].length]) != sha3(None):
return 0
return 1
def unknown1d34866f(array _param1): # not payable
mem[128 len _param1.length] = _param1[all]
mem[ceil32(_param1.length) + 128 len floor32(_param1.length)] = call.data[_param1 + 36 len floor32(_param1.length)]
mem[ceil32(_param1.length) + floor32(_param1.length) + -(_param1.length % 32) + 160 len _param1.length % 32] = mem[floor32(_param1.length) + -(_param1.length % 32) + 160 len _param1.length % 32]
mem[_param1.length + ceil32(_param1.length) + 128] = 1
if stor[mem[ceil32(_param1.length) + floor32(_param1.length) + 128 len (_param1.length % 32) + 32]][call.data[_param1 + 36 len floor32(_param1.length)]]:
return 0
return 1
def getAddress(string _key): # not payable
mem[128 len _key.length] = _key[all]
mem[ceil32(_key.length) + 128 len floor32(_key.length)] = call.data[_key + 36 len floor32(_key.length)]
mem[ceil32(_key.length) + floor32(_key.length) + -(_key.length % 32) + 160 len _key.length % 32] = mem[floor32(_key.length) + -(_key.length % 32) + 160 len _key.length % 32]
mem[_key.length + ceil32(_key.length) + 128] = 1
mem[ceil32(_key.length) + 128] = stor[mem[ceil32(_key.length) + floor32(_key.length) + 128 len (_key.length % 32) + 32]][call.data[_key + 36 len floor32(_key.length)]]
return memory
from ceil32(_key.length) + 128
len 32
def registerUser(string _name): # not payable
mem[128 len _name.length] = _name[all]
mem[ceil32(_name.length) + 128] = uint256(unknownd84f55ee[caller].field_0)
idx = ceil32(_name.length) + 128
s = 0
while ceil32(_name.length) + unknownd84f55ee[caller].length + 128 > idx + 32:
mem[idx + 32] = uint256(unknownd84f55ee[caller][s].field_256)
idx = idx + 32
s = s + 1
continue
require sha3(mem[ceil32(_name.length) + 128 len unknownd84f55ee[caller].length]) == sha3(None)
mem[ceil32(_name.length) + 128 len floor32(_name.length)] = call.data[_name + 36 len floor32(_name.length)]
mem[ceil32(_name.length) + floor32(_name.length) + -(_name.length % 32) + 160 len _name.length % 32] = mem[floor32(_name.length) + -(_name.length % 32) + 160 len _name.length % 32]
mem[_name.length + ceil32(_name.length) + 128] = 1
require not stor[mem[ceil32(_name.length) + floor32(_name.length) + 128 len (_name.length % 32) + 32]][call.data[_name + 36 len floor32(_name.length)]]
uint256(unknownd84f55ee[caller][].field_0) = Array(len=_name.length, data=_name[all])
mem[ceil32(_name.length) + 128 len floor32(_name.length)] = call.data[_name + 36 len floor32(_name.length)]
mem[ceil32(_name.length) + floor32(_name.length) + -(_name.length % 32) + 160 len _name.length % 32] = mem[floor32(_name.length) + -(_name.length % 32) + 160 len _name.length % 32]
mem[_name.length + ceil32(_name.length) + 128] = 1
stor[mem[ceil32(_name.length) + floor32(_name.length) + 128 len (_name.length % 32) + 32]][call.data[_name + 36 len floor32(_name.length)]] = caller
公開されていないNFTや、マーケットのロジックを分析する際にも使えるのでぜひ試してみてください!
また、こちらで紹介しているツールは、より詳細に分析できるようなのでこちらも併せてどうぞ!