import sys
import ctypes
import optparse
import re
import tabulate
from six import viewkeys
from . import add_common_options, parse_options
from ..cpu.instructions import DuckyInstructionSet, get_instruction_set
from ..mm import u16_t, u32_t, UINT16_FMT, SIZE_FMT, UINT32_FMT, UINT8_FMT
from ..mm.binary import File, SectionTypes, SECTION_TYPES, SYMBOL_DATA_TYPES, SymbolDataTypes, RelocFlags, SymbolFlags, SectionFlags
from ..cpu.coprocessor.math_copro import MathCoprocessorInstructionSet # noqa
[docs]def show_sections(logger, f):
logger.info('=== Sections ===')
logger.info('')
f_header = f.get_header()
table = [
['Index', 'Name', 'Type', 'Flags', 'Base', 'Items', 'Data size', 'File size', 'Offset']
]
for i in range(0, f_header.sections):
header, content = f.get_section(i)
header_flags = SectionFlags.from_encoding(header.flags)
table.append([
header.index,
f.string_table.get_string(header.name),
SECTION_TYPES[header.type],
'%s (%s)' % (header_flags.to_string(), UINT16_FMT(header_flags.to_int())),
UINT32_FMT(header.base),
header.items,
SIZE_FMT(header.data_size),
SIZE_FMT(header.file_size),
SIZE_FMT(header.offset)
])
logger.table(table)
logger.info('')
[docs]def show_disassemble(logger, f):
logger.info('=== Disassemble ==')
logger.info('')
instruction_set = DuckyInstructionSet
f_header = f.get_header()
for i in range(0, f_header.sections):
header, content = f.get_section(i)
if header.type != SectionTypes.TEXT:
continue
logger.info(' Section %s', f.string_table.get_string(header.name))
csp = header.base
for raw_inst in content:
csp_str = UINT32_FMT(csp)
csp += 4
inst, desc, opcode = instruction_set.decode_instruction(logger, raw_inst.value)
logger.info(' %s (%s) %s', csp_str, UINT32_FMT(raw_inst), instruction_set.disassemble_instruction(logger, raw_inst.value))
if opcode == DuckyInstructionSet.opcodes.SIS:
instruction_set = get_instruction_set(inst.immediate)
logger.info('')
[docs]def show_reloc(logger, f):
logger.info('=== Reloc entries ===')
logger.info('')
f_header = f.get_header()
table = [
['Name', 'Flags', 'Patch section', 'Patch address', 'Patch offset', 'Patch size']
]
for i in range(0, f_header.sections):
header, content = f.get_section(i)
if header.type != SectionTypes.RELOC:
continue
for index, entry in enumerate(content):
_header, _content = f.get_section(entry.patch_section)
table.append([
f.string_table.get_string(entry.name),
RelocFlags.from_encoding(entry.flags).to_string(),
f.string_table.get_string(_header.name),
UINT32_FMT(entry.patch_address),
entry.patch_offset,
entry.patch_size
])
logger.table(table)
logger.info('')
[docs]def show_symbols(logger, f):
ascii_replacements = {
'\n': '\\n',
'\r': '\\r',
'\x00': '\\0'
}
def ascii_replacer(m):
return ascii_replacements[m.group(0)]
ascii_replace = re.compile(r'|'.join(viewkeys(ascii_replacements)))
logger.info('=== Symbols ===')
logger.info('')
f_header = f.get_header()
table = [
['Name', 'Section', 'Flags', 'Address', 'Type', 'Size', 'File', 'Line', 'Content']
]
for i in range(0, f_header.sections):
header, content = f.get_section(i)
if header.type != SectionTypes.SYMBOLS:
continue
for index, entry in enumerate(content):
_header, _content = f.get_section(entry.section)
table_row = [
f.string_table.get_string(entry.name),
f.string_table.get_string(_header.name),
SymbolFlags.from_encoding(entry.flags).to_string(),
UINT32_FMT(entry.address),
'%s (%i)' % (SYMBOL_DATA_TYPES[entry.type], entry.type),
SIZE_FMT(entry.size),
f.string_table.get_string(entry.filename),
entry.lineno
]
symbol_content = ''
if _header.flags.bss == 1:
pass
else:
if entry.type == SymbolDataTypes.INT:
def __get(i):
return _content[entry.address - _header.base + i].value << (8 * i)
symbol_content = u32_t(__get(0) | __get(1) | __get(2) | __get(3))
symbol_content = UINT32_FMT(symbol_content.value)
elif entry.type == SymbolDataTypes.SHORT:
def __get(i):
return _content[entry.address - _header.base + i].value << (8 * i)
symbol_content = u16_t(__get(0) | __get(1))
symbol_content = UINT16_FMT(symbol_content.value)
elif entry.type in (SymbolDataTypes.BYTE, SymbolDataTypes.CHAR):
symbol_content = UINT8_FMT(_content[entry.address - _header.base].value)
elif entry.type == SymbolDataTypes.ASCII:
symbol_content = ''.join(['%s' % chr(c.value) for c in _content[entry.address - _header.base:entry.address - _header.base + entry.size]])
elif entry.type == SymbolDataTypes.STRING:
symbol_content = ''.join(['%s' % chr(c.value) for c in _content[entry.address - _header.base:entry.address - _header.base + entry.size]])
if entry.type == SymbolDataTypes.ASCII or entry.type == SymbolDataTypes.STRING:
if len(symbol_content) > 32:
symbol_content = symbol_content[0:29] + '...'
symbol_content = '"' + ascii_replace.sub(ascii_replacer, symbol_content) + '"'
table_row.append(symbol_content)
table.append(table_row)
for line in tabulate.tabulate(table, headers = 'firstrow', tablefmt = 'simple', numalign = 'right').split('\n'):
logger.info(line)
logger.info('')
[docs]def main():
parser = optparse.OptionParser()
add_common_options(parser)
parser.add_option('-i', dest = 'file_in', action = 'append', default = [], help = 'File to inspect')
parser.add_option('-H', dest = 'header', default = False, action = 'store_true', help = 'Show file header')
parser.add_option('-D', dest = 'disassemble', default = False, action = 'store_true', help = 'Disassemble TEXT sections')
parser.add_option('-s', dest = 'symbols', default = False, action = 'store_true', help = 'List symbols')
parser.add_option('-r', dest = 'reloc', default = False, action ='store_true', help = 'List reloc entries')
parser.add_option('-S', dest = 'sections', default = False, action = 'store_true', help = 'List sections')
parser.add_option('-a', dest = 'all', default = False, action = 'store_true', help = 'All of above')
options, logger = parse_options(parser)
if not options.file_in:
parser.print_help()
sys.exit(1)
if options.all:
options.header = options.disassemble = options.symbols = options.sections = options.reloc = True
for file_in in options.file_in:
logger.info('Input file: %s', file_in)
with File.open(logger, file_in, 'r') as f_in:
f_in.load()
logger.info('')
if options.header:
show_file_header(logger, f_in)
if options.sections:
show_sections(logger, f_in)
if options.symbols:
show_symbols(logger, f_in)
if options.reloc:
show_reloc(logger, f_in)
if options.disassemble:
show_disassemble(logger, f_in)