Loads shared ELF to analyze a function (#861)
* Loads shared ELF to analyze a function See #69 * Bring in recent changes to concolic.py * Loads shared ELF to analyze a function * Fix the 'linux' class method prototype
This commit is contained in:
parent
b9a515ccfe
commit
44ef97ec6c
@ -36,6 +36,11 @@ def parse_arguments():
|
||||
help=argparse.SUPPRESS)
|
||||
parser.add_argument('--env', type=str, nargs=1, default=[], action='append',
|
||||
help='Specify symbolic environment variable VARNAME=++++++')
|
||||
#TODO allow entry as an address
|
||||
#parser.add_argument('--entry', type=str, default=None,
|
||||
# help='address as entry point')
|
||||
parser.add_argument('--entrysymbol', type=str, default=None,
|
||||
help='symbol as entry point')
|
||||
parser.add_argument('--file', type=str, default=[], action='append', dest='files',
|
||||
help='Specify symbolic input file, \'+\' marks symbolic bytes')
|
||||
parser.add_argument('--names', type=str, default=None,
|
||||
@ -115,7 +120,7 @@ def main():
|
||||
|
||||
env = {key: val for key, val in map(lambda env: env[0].split('='), args.env)}
|
||||
|
||||
m = Manticore(args.argv[0], argv=args.argv[1:], env=env, workspace_url=args.workspace, policy=args.policy, disasm=args.disasm, concrete_start=args.data)
|
||||
m = Manticore(args.argv[0], argv=args.argv[1:], env=env, entry_symbol=args.entrysymbol, workspace_url=args.workspace, policy=args.policy, disasm=args.disasm, concrete_start=args.data)
|
||||
|
||||
# Fixme(felipe) remove this, move to plugin
|
||||
m.coverage_file = args.coverage
|
||||
|
||||
@ -76,7 +76,7 @@ def make_decree(program, concrete_start='', **kwargs):
|
||||
return initial_state
|
||||
|
||||
|
||||
def make_linux(program, argv=None, env=None, symbolic_files=None, concrete_start=''):
|
||||
def make_linux(program, argv=None, env=None, entry_symbol=None, symbolic_files=None, concrete_start=''):
|
||||
env = {} if env is None else env
|
||||
argv = [] if argv is None else argv
|
||||
env = ['%s=%s' % (k, v) for k, v in env.items()]
|
||||
@ -86,6 +86,15 @@ def make_linux(program, argv=None, env=None, symbolic_files=None, concrete_start
|
||||
constraints = ConstraintSet()
|
||||
platform = linux.SLinux(program, argv=argv, envp=env,
|
||||
symbolic_files=symbolic_files)
|
||||
if entry_symbol is not None:
|
||||
entry_pc = platform._find_symbol(entry_symbol)
|
||||
if entry_pc is None:
|
||||
logger.error("No symbol for '%s' in %s", entry_symbol, program)
|
||||
raise Exception("Symbol not found")
|
||||
else:
|
||||
logger.info("Found symbol '%s' (%x)", entry_symbol, entry_pc)
|
||||
#TODO: use argv as arguments for function
|
||||
platform.set_entry(entry_pc)
|
||||
|
||||
initial_state = State(constraints, platform)
|
||||
|
||||
@ -249,7 +258,7 @@ class Manticore(Eventful):
|
||||
plugin.manticore = None
|
||||
|
||||
@classmethod
|
||||
def linux(cls, path, argv=None, envp=None, symbolic_files=None, concrete_start='', **kwargs):
|
||||
def linux(cls, path, argv=None, envp=None, entry_symbol=None, symbolic_files=None, concrete_start='', **kwargs):
|
||||
"""
|
||||
Constructor for Linux binary analysis.
|
||||
|
||||
@ -258,6 +267,8 @@ class Manticore(Eventful):
|
||||
:type argv: list[str]
|
||||
:param envp: Environment to provide to the binary
|
||||
:type envp: dict[str, str]
|
||||
:param entry_symbol: Entry symbol to resolve to start execution
|
||||
:type envp: str
|
||||
:param symbolic_files: Filenames to mark as having symbolic input
|
||||
:type symbolic_files: list[str]
|
||||
:param str concrete_start: Concrete stdin to use before symbolic inputt
|
||||
@ -266,7 +277,7 @@ class Manticore(Eventful):
|
||||
:rtype: Manticore
|
||||
"""
|
||||
try:
|
||||
return cls(make_linux(path, argv, envp, symbolic_files, concrete_start), **kwargs)
|
||||
return cls(make_linux(path, argv, envp, entry_symbol, symbolic_files, concrete_start), **kwargs)
|
||||
except elftools.common.exceptions.ELFError:
|
||||
raise Exception('Invalid binary: {}'.format(path))
|
||||
|
||||
|
||||
@ -10,6 +10,8 @@ import socket
|
||||
|
||||
# Remove in favor of binary.py
|
||||
from elftools.elf.elffile import ELFFile
|
||||
from elftools.elf.sections import SymbolTableSection
|
||||
from elftools.elf.descriptions import describe_symbol_type
|
||||
|
||||
from ..core.cpu.abstractcpu import Interruption, Syscall, ConcretizeArgument
|
||||
from ..core.cpu.cpufactory import CpuFactory
|
||||
@ -447,6 +449,21 @@ class Linux(Platform):
|
||||
self._function_abi = CpuFactory.get_function_abi(cpu, 'linux', arch)
|
||||
self._syscall_abi = CpuFactory.get_syscall_abi(cpu, 'linux', arch)
|
||||
|
||||
def _find_symbol(self, name):
|
||||
symbol_tables = (s for s in self.elf.iter_sections()
|
||||
if isinstance(s, SymbolTableSection))
|
||||
|
||||
for section in symbol_tables:
|
||||
if section['sh_entsize'] == 0:
|
||||
continue
|
||||
|
||||
for symbol in section.iter_symbols():
|
||||
if describe_symbol_type(symbol['st_info']['type']) == 'FUNC':
|
||||
if symbol.name == name:
|
||||
return symbol['st_value']
|
||||
|
||||
return None
|
||||
|
||||
def _execve(self, program, argv, envp):
|
||||
'''
|
||||
Load `program` and establish program state, such as stack and arguments.
|
||||
@ -798,6 +815,13 @@ class Linux(Platform):
|
||||
# ARGC
|
||||
cpu.push_int(len(argvlst))
|
||||
|
||||
def set_entry(self, entryPC):
|
||||
elf_entry = entryPC
|
||||
if self.elf.header.e_type == 'ET_DYN':
|
||||
elf_entry += self.load_addr
|
||||
self.current.PC = elf_entry
|
||||
logger.debug("Entry point updated: %016x", elf_entry)
|
||||
|
||||
def load(self, filename):
|
||||
'''
|
||||
Loads and an ELF program in memory and prepares the initial CPU state.
|
||||
@ -826,7 +850,10 @@ class Linux(Platform):
|
||||
continue
|
||||
interpreter_filename = elf_segment.data()[:-1]
|
||||
logger.info('Interpreter filename: %s', interpreter_filename)
|
||||
interpreter = ELFFile(file(interpreter_filename))
|
||||
try:
|
||||
interpreter = ELFFile(open(interpreter_filename))
|
||||
except IOError:
|
||||
logger.warning('Interpreter not loaded: %s', interpreter_filename)
|
||||
break
|
||||
if interpreter is not None:
|
||||
assert interpreter.get_machine_arch() == elf.get_machine_arch()
|
||||
@ -848,7 +875,7 @@ class Linux(Platform):
|
||||
end_code = 0
|
||||
end_data = 0
|
||||
elf_brk = 0
|
||||
load_addr = 0
|
||||
self.load_addr = 0
|
||||
|
||||
for elf_segment in elf.iter_segments():
|
||||
if elf_segment.header.p_type != 'PT_LOAD':
|
||||
@ -879,8 +906,8 @@ class Linux(Platform):
|
||||
logger.debug("Loading elf offset: %08x addr:%08x %08x %s" % (offset, base + vaddr, base + vaddr + memsz, perms))
|
||||
base = cpu.memory.mmapFile(hint, memsz, perms, elf_segment.stream.name, offset) - vaddr
|
||||
|
||||
if load_addr == 0:
|
||||
load_addr = base + vaddr
|
||||
if self.load_addr == 0:
|
||||
self.load_addr = base + vaddr
|
||||
|
||||
k = base + vaddr + filesz
|
||||
if k > elf_bss:
|
||||
@ -895,7 +922,7 @@ class Linux(Platform):
|
||||
|
||||
elf_entry = elf.header.e_entry
|
||||
if elf.header.e_type == 'ET_DYN':
|
||||
elf_entry += load_addr
|
||||
elf_entry += self.load_addr
|
||||
entry = elf_entry
|
||||
real_elf_brk = elf_brk
|
||||
|
||||
@ -1014,7 +1041,7 @@ class Linux(Platform):
|
||||
at_execfn = cpu.push_bytes(filename + '\x00')
|
||||
|
||||
self.auxv = {
|
||||
'AT_PHDR': load_addr + elf.header.e_phoff, # Program headers for program
|
||||
'AT_PHDR': self.load_addr + elf.header.e_phoff, # Program headers for program
|
||||
'AT_PHENT': elf.header.e_phentsize, # Size of program header entry
|
||||
'AT_PHNUM': elf.header.e_phnum, # Number of program headers
|
||||
'AT_PAGESZ': cpu.memory.page_size, # System page size
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user