Work-in-Progress support for NetBSD/amd64 binaries

This commit is contained in:
Pierre Pronchery 2018-05-12 17:23:44 +02:00
parent 07740c2fc7
commit f22afeb235
5 changed files with 2665 additions and 6 deletions

View File

@ -1,4 +1,4 @@
from .x86 import AMD64Cpu, I386Cpu, AMD64LinuxSyscallAbi, I386LinuxSyscallAbi, I386CdeclAbi, SystemVAbi from .x86 import AMD64Cpu, I386Cpu, AMD64LinuxSyscallAbi, AMD64NetBSDSyscallAbi, I386LinuxSyscallAbi, I386CdeclAbi, SystemVAbi
from .arm import Armv7Cpu, Armv7CdeclAbi, Armv7LinuxSyscallAbi from .arm import Armv7Cpu, Armv7CdeclAbi, Armv7LinuxSyscallAbi
@ -17,7 +17,7 @@ class CpuFactory(object):
def get_function_abi(cpu, os, machine): def get_function_abi(cpu, os, machine):
if os == 'linux' and machine == 'i386': if os == 'linux' and machine == 'i386':
return I386CdeclAbi(cpu) return I386CdeclAbi(cpu)
elif os == 'linux' and machine == 'amd64': elif (os == 'linux' or os == 'netbsd') and machine == 'amd64':
return SystemVAbi(cpu) return SystemVAbi(cpu)
elif os == 'linux' and machine == 'armv7': elif os == 'linux' and machine == 'armv7':
return Armv7CdeclAbi(cpu) return Armv7CdeclAbi(cpu)
@ -32,5 +32,7 @@ class CpuFactory(object):
return AMD64LinuxSyscallAbi(cpu) return AMD64LinuxSyscallAbi(cpu)
elif os == 'linux' and machine == 'armv7': elif os == 'linux' and machine == 'armv7':
return Armv7LinuxSyscallAbi(cpu) return Armv7LinuxSyscallAbi(cpu)
elif os == 'netbsd' and machine == 'amd64':
return AMD64NetBSDSyscallAbi(cpu)
else: else:
return NotImplementedError("OS and machine combination not supported: {}/{}".format(os, machine)) return NotImplementedError("OS and machine combination not supported: {}/{}".format(os, machine))

View File

@ -5952,6 +5952,25 @@ class AMD64LinuxSyscallAbi(SyscallAbi):
self._cpu.RAX = result self._cpu.RAX = result
class AMD64NetBSDSyscallAbi(SyscallAbi):
'''
AMD64 NetBSD system call ABI
'''
# TODO(yan): Floating point or wide arguments that deviate from the norm are
# not yet supported.
def syscall_number(self):
return self._cpu.RAX
def get_arguments(self):
for reg in ('RDI', 'RSI', 'RDX', 'R10', 'R8', 'R9'):
yield reg
def write_result(self, result):
self._cpu.RAX = result
class I386CdeclAbi(Abi): class I386CdeclAbi(Abi):
''' '''
i386 cdecl function call semantics i386 cdecl function call semantics

View File

@ -11,16 +11,17 @@ from contextlib import contextmanager
from threading import Timer from threading import Timer
# FIXME: remove this three # FIXME: remove these
import elftools import elftools
from elftools.elf.elffile import ELFFile from elftools.elf.elffile import ELFFile
from elftools.elf.sections import NoteSection
from elftools.elf.sections import SymbolTableSection from elftools.elf.sections import SymbolTableSection
from .core.executor import Executor from .core.executor import Executor
from .core.state import State, TerminateState from .core.state import State, TerminateState
from .core.smtlib import solver, ConstraintSet from .core.smtlib import solver, ConstraintSet
from .core.workspace import ManticoreOutput from .core.workspace import ManticoreOutput
from .platforms import linux, decree, evm from .platforms import linux, netbsd, decree, evm
from .utils.helpers import issymbolic, is_binja_disassembler from .utils.helpers import issymbolic, is_binja_disassembler
from .utils.nointerrupt import WithKeyboardInterruptAs from .utils.nointerrupt import WithKeyboardInterruptAs
from .utils.event import Eventful from .utils.event import Eventful
@ -76,6 +77,19 @@ def make_decree(program, concrete_start='', **kwargs):
return initial_state return initial_state
def make_elf(program, argv=None, env=None, entry_symbol=None, symbolic_files=None, concrete_start=''):
#with open(program, 'rb') as f:
with open(program, 'rb') as f:
for sect in ELFFile(f).iter_sections():
if not isinstance(sect, NoteSection):
continue
for note in sect.iter_notes():
if note['n_name'] == 'NetBSD':
logger.info("NetBSD binary detected")
return make_netbsd(program, argv, env, entry_symbol, symbolic_files, concrete_start)
return make_linux(program, argv, env, entry_symbol, symbolic_files, concrete_start)
def make_linux(program, argv=None, env=None, entry_symbol=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 env = {} if env is None else env
argv = [] if argv is None else argv argv = [] if argv is None else argv
@ -120,6 +134,50 @@ def make_linux(program, argv=None, env=None, entry_symbol=None, symbolic_files=N
return initial_state return initial_state
def make_netbsd(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()]
logger.info('Loading program %s', program)
constraints = ConstraintSet()
platform = netbsd.SNetBSD(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)
if concrete_start != '':
logger.info('Starting with concrete input: %s', concrete_start)
for i, arg in enumerate(argv):
argv[i] = initial_state.symbolicate_buffer(arg, label='ARGV%d' % (i + 1))
for i, evar in enumerate(env):
env[i] = initial_state.symbolicate_buffer(evar, label='ENV%d' % (i + 1))
# If any of the arguments or environment refer to symbolic values, re-
# initialize the stack
if any(issymbolic(x) for val in argv + env for x in val):
platform.setup_stack([program] + argv, env)
platform.input.write(concrete_start)
# set stdin input...
platform.input.write(initial_state.symbolicate_buffer('+' * 256,
label='STDIN'))
return initial_state
def make_initial_state(binary_path, **kwargs): def make_initial_state(binary_path, **kwargs):
if 'disasm' in kwargs: if 'disasm' in kwargs:
if kwargs.get('disasm') == "binja-il": if kwargs.get('disasm') == "binja-il":
@ -128,8 +186,8 @@ def make_initial_state(binary_path, **kwargs):
del kwargs['disasm'] del kwargs['disasm']
magic = file(binary_path).read(4) magic = file(binary_path).read(4)
if magic == '\x7fELF': if magic == '\x7fELF':
# Linux # ELF
state = make_linux(binary_path, **kwargs) state = make_elf(binary_path, **kwargs)
elif magic == '\x7fCGC': elif magic == '\x7fCGC':
# Decree # Decree
state = make_decree(binary_path, **kwargs) state = make_decree(binary_path, **kwargs)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,27 @@
amd64 = {
1: "sys_exit",
2: "sys_fork",
3: "sys_read",
4: "sys_write",
5: "sys_open",
6: "sys_close",
9: "sys_link",
10: "sys_unlink",
12: "sys_chdir",
15: "sys_chmod",
17: "sys_brk",
20: "sys_getpid",
22: "sys_unmount",
23: "sys_setuid",
24: "sys_getuid",
25: "sys_geteuid",
26: "sys_ptrace",
33: "sys_access",
36: "sys_sync",
37: "sys_kill",
39: "sys_getppid",
41: "sys_dup",
42: "sys_pipe",
58: "sys_readlink",
92: "sys_fcntl",
}