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
@ -17,7 +17,7 @@ class CpuFactory(object):
def get_function_abi(cpu, os, machine):
if os == 'linux' and machine == 'i386':
return I386CdeclAbi(cpu)
elif os == 'linux' and machine == 'amd64':
elif (os == 'linux' or os == 'netbsd') and machine == 'amd64':
return SystemVAbi(cpu)
elif os == 'linux' and machine == 'armv7':
return Armv7CdeclAbi(cpu)
@ -32,5 +32,7 @@ class CpuFactory(object):
return AMD64LinuxSyscallAbi(cpu)
elif os == 'linux' and machine == 'armv7':
return Armv7LinuxSyscallAbi(cpu)
elif os == 'netbsd' and machine == 'amd64':
return AMD64NetBSDSyscallAbi(cpu)
else:
return NotImplementedError("OS and machine combination not supported: {}/{}".format(os, machine))

View File

@ -5952,6 +5952,25 @@ class AMD64LinuxSyscallAbi(SyscallAbi):
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):
'''
i386 cdecl function call semantics

View File

@ -11,16 +11,17 @@ from contextlib import contextmanager
from threading import Timer
# FIXME: remove this three
# FIXME: remove these
import elftools
from elftools.elf.elffile import ELFFile
from elftools.elf.sections import NoteSection
from elftools.elf.sections import SymbolTableSection
from .core.executor import Executor
from .core.state import State, TerminateState
from .core.smtlib import solver, ConstraintSet
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.nointerrupt import WithKeyboardInterruptAs
from .utils.event import Eventful
@ -76,6 +77,19 @@ def make_decree(program, concrete_start='', **kwargs):
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=''):
env = {} if env is None else env
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
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):
if 'disasm' in kwargs:
if kwargs.get('disasm') == "binja-il":
@ -128,8 +186,8 @@ def make_initial_state(binary_path, **kwargs):
del kwargs['disasm']
magic = file(binary_path).read(4)
if magic == '\x7fELF':
# Linux
state = make_linux(binary_path, **kwargs)
# ELF
state = make_elf(binary_path, **kwargs)
elif magic == '\x7fCGC':
# Decree
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",
}