Files
txspector-new/bin/decompile_geth
T
2024-06-15 11:27:29 +08:00

168 lines
5.8 KiB
Python
Executable File

#!/usr/bin/env python3
# BSD 3-Clause License
#
# Copyright (c) 2020, The Ohio State Univerisity. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# * Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# Standard lib imports
import argparse
import logging
import sys
from os.path import abspath, dirname, join
# Prepend .. to $PATH so the project modules can be imported below
# 用于将以太坊虚拟机(EVM)字节码反汇编为三地址代码进行程序分析
src_path = join(dirname(abspath(__file__)), "..")
sys.path.insert(0, src_path)
# Local project imports
import src.exporter as exporter
import src.tac_efg as tac_efg
import src.settings as settings
# Version string to display with -v
VERSION = """\
+------------------------------+
| TxSpector Detector v0.0.1 |
| (c) The Ohio State University |
+------------------------------+\
"""
# Define a version() function in case we want dynamic version strings later
def version():
return VERSION
# Configure argparse
parser = argparse.ArgumentParser(
description="An EVM bytecode disassembly that generates"
"three-address code for program analysis.")
parser.add_argument("-t",
"--tsv",
nargs="?",
const="",
metavar="DIR",
default=None,
help="generate tab-separated .facts files for Souffle "
"and write files to the specified directory, which "
"will be recursively created if it does not exist "
"(current working directory by default).")
parser.add_argument("-o",
"--opcodes",
nargs="*",
default=[],
metavar="OPCODE",
help="If producing tsv output, also include relations "
"encoding all occurrences of the specified "
"list of opcodes. Opcode X will be stored in "
"op_X.facts.")
parser.add_argument("-v",
"--verbose",
action="store_true",
help="emit verbose debug output to stderr.")
parser.add_argument("-vv",
"--prolix",
action="store_true",
help="higher verbosity level, including extra debug "
"messages from dataflow analysis and elsewhere.")
parser.add_argument("-n",
"--no_out",
action="store_true",
help="do not output decompiled graph.")
parser.add_argument("-V",
"--version",
action="store_true",
help="show program's version number and exit.")
parser.add_argument("infile",
nargs="?",
type=argparse.FileType("r"),
default=sys.stdin,
help="file from which decompiler input should be read "
"(stdin by default).")
parser.add_argument("outfile",
nargs="?",
type=argparse.FileType("w"),
default=sys.stdout,
help="file to which decompiler output should be written "
"(stdout by default).")
# Parse the arguments.
args = parser.parse_args()
# Set up logger, with appropriate log level depending on verbosity.
log_level = logging.WARNING
if args.prolix:
log_level = logging.DEBUG
elif args.verbose:
log_level = logging.INFO
logging.basicConfig(format='%(levelname)s: %(message)s', level=log_level)
# Handle --version
if args.version:
sys.exit(1)
# Always show version for log_level >= LOW
logging.info("\n" + version())
# Build TAC EFG from input file
try:
logging.info("Reading from '%s'.", args.infile.name)
efg = tac_efg.TACGraph.from_opcode(args.infile)
logging.info("Initial EFG generation completed.")
# Catch a Control-C and exit with UNIX failure status 1
except KeyboardInterrupt:
logging.critical("\nInterrupted by user")
sys.exit(1)
# Generate output using the requested exporter(s)
# blocks, textual version of efg
if not args.no_out:
logging.info("Writing string output.")
print(exporter.EFGStringExporter(efg).export(), file=args.outfile)
# Generate facts file
if args.tsv is not None:
logging.info("Writing TSV output.")
exporter.EFGTsvExporter(efg).export(output_dir=args.tsv,
out_opcodes=args.opcodes)