Security analysis tool for EVM bytecode. Supports smart contracts built for Ethereum, Hedera, Quorum, Vechain, Roostock, Tron and other EVM-compatible blockchains.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
mythril/ether/asm.py

142 lines
2.8 KiB

import sys
7 years ago
import re
import codecs
from ethereum import opcodes
7 years ago
regex_PUSH = re.compile('^PUSH(\d*)$')
def disassembly_to_easm(disassembly):
easm = ""
for instruction in disassembly:
easm += instruction['opcode']
if 'argument' in instruction:
easm += " 0x" + codecs.decode(instruction['argument'], 'utf-8')
7 years ago
easm += "\n"
return easm
def easm_to_disassembly(easm):
regex_CODELINE = re.compile('^([A-Z0-9]+)(?:\s+([0-9a-fA-Fx]+))?$')
disassembly = []
codelines = easm.split('\n')
for line in codelines:
m = re.search(regex_CODELINE, line)
if not m:
# Invalid code line
continue
instruction = {}
instruction['opcode'] = m.group(1)
if m.group(2):
instruction['argument'] = m.group(2)[2:]
disassembly.append(instruction)
return disassembly
def get_opcode_from_name(name):
for opcode, value in opcodes.opcodes.items():
if name == value[0]:
return opcode
raise RuntimeError("Unknown opcode")
def find_opcode_sequence(pattern, disassembly):
match_indexes = []
pattern_length = len(pattern)
for i in range(0, len(disassembly) - pattern_length):
if disassembly[i]['opcode'] == pattern[0]:
matched = True
for j in range(1, len(pattern)):
if not (disassembly[i + j]['opcode'] == pattern[j]):
matched = False
break
if (matched):
match_indexes.append(i)
return match_indexes
7 years ago
def disassemble(bytecode):
7 years ago
disassembly = []
i = 0
while i < len(bytecode):
instruction = {}
try:
if (sys.version_info > (3, 0)):
opcode = opcodes.opcodes[bytecode[i]]
else:
opcode = opcodes.opcodes[ord(bytecode[i])]
7 years ago
except KeyError:
7 years ago
# invalid opcode
disassembly.append({'opcode': "INVALID"})
i += 1
continue
instruction['opcode'] = opcode[0]
m = re.search(regex_PUSH, opcode[0])
if m:
argument = bytecode[i+1:i+1+int(m.group(1))]
instruction['argument'] = codecs.encode(argument, "hex_codec")
7 years ago
i += int(m.group(1))
disassembly.append(instruction)
i += 1
return disassembly
def assemble(disassembly):
7 years ago
bytecode = b""
7 years ago
for instruction in disassembly:
try:
opcode = get_opcode_from_name(instruction['opcode'])
except RuntimeError:
opcode = 0xbb
bytecode += opcode.to_bytes(1, byteorder='big')
7 years ago
if 'argument' in instruction:
bytecode += codecs.decode(instruction['argument'], 'hex_codec')
7 years ago
return bytecode