Files
manticore/binary/__init__.py
2017-02-13 12:04:15 -05:00

236 lines
8.1 KiB
Python

''' Common binary formats interface
Ideally you should be able to do something like
from binary import Binary
binary = Binary(filename)
assert cpu.machine == binary.arch, "Not matching cpu"
logger.info("Loading %s as a %s elf"%(filename, binary.arch))
for mm in binary.maps():
cpu.mem.mmapFile( mm )
for th in binary.threads():
setup(th)
But there are difference between format that makes it difficult to find a siple and common API.
interpreters? linkers? linked dlls?
'''
class Binary(object):
magics = { }
def __new__(cls, path):
if cls is Binary:
cl = cls.magics[file(path).read(4)]
return cl(path)
else:
return super(Binary, cls).__new__(cls, path)
def __init__(self, path):
self.path = path
self.magic = Binary.magics[file(path).read(4)]
def arch(self):
pass
def maps(self):
pass
def threads(self):
pass
from elf.elftools.elf.elffile import ELFFile
class CGCElf(Binary):
def __init__(self, filename):
super(CGCElf, self).__init__(filename)
self.elf = ELFFile(file(filename))
self.arch = {'x86':'i386','x64':'amd64'}[self.elf.get_machine_arch()]
assert 'i386' == self.arch
assert self.elf.header.e_type in ['ET_EXEC']
def maps(self):
for elf_segment in self.elf.iter_segments():
if elf_segment.header.p_type not in ['PT_LOAD', 'PT_NULL', 'PT_PHDR', 'PT_CGCPOV2']:
raise Exception("Not Supported Section")
if elf_segment.header.p_type != 'PT_LOAD' or elf_segment.header.p_memsz == 0:
continue
flags = elf_segment.header.p_flags
#PF_X 0x1 Execute - PF_W 0x2 Write - PF_R 0x4 Read
perms = [' ', ' x', ' w ', ' wx', 'r ', 'r x', 'rw ', 'rwx'][flags&7]
if 'r' not in perms:
raise Exception("Not readable map from cgc elf not supported")
#CGCMAP--
assert elf_segment.header.p_filesz != 0 or elf_segment.header.p_memsz != 0
yield((elf_segment.header.p_vaddr,
elf_segment.header.p_memsz,
perms,
elf_segment.stream.name, elf_segment.header.p_offset, elf_segment.header.p_filesz))
def threads(self):
yield(('Running', {'EIP': self.elf.header.e_entry}))
class Elf(Binary):
def __init__(self, filename):
super(Elf, self).__init__(filename)
self.elf = ELFFile(file(filename))
self.arch = {'x86':'i386','x64':'amd64'}[self.elf.get_machine_arch()]
assert self.elf.header.e_type in ['ET_DYN', 'ET_EXEC', 'ET_CORE']
#Get interpreter elf
self.interpreter = None
for elf_segment in self.elf.iter_segments():
if elf_segment.header.p_type != 'PT_INTERP':
continue
self.interpreter = Elf(elf_segment.data()[:-1])
break
if not self.interpreter is None:
assert self.interpreter.arch == self.arch
assert self.interpreter.elf.header.e_type in ['ET_DYN', 'ET_EXEC']
def maps(self):
for elf_segment in self.elf.iter_segments():
if elf_segment.header.p_type != 'PT_LOAD' or elf_segment.header.p_memsz == 0:
continue
flags = elf_segment.header.p_flags
#PF_X 0x1 Execute - PF_W 0x2 Write - PF_R 0x4 Read
perms = [' ', ' x', ' w ', ' wx', 'r ', 'r x', 'rw ', 'rwx'][flags&7]
if 'r' not in perms:
raise Exception("Not readable map from cgc elf not supported")
#CGCMAP--
assert elf_segment.header.p_filesz != 0 or elf_segment.header.p_memsz != 0
yield((elf_segment.header.p_vaddr,
elf_segment.header.p_memsz,
perms,
elf_segment.stream.name, elf_segment.header.p_offset, elf_segment.header.p_filesz))
def getInterpreter(self):
return self.interpreter
def threads(self):
yield(('Running', {'EIP': self.elf.header.e_entry}))
from grr.snapshot import Grr
class CGCGrr(Binary):
def __init__(self, filename):
HEADERSIZE = 16384
self.grr = Grr.from_buf(file(filename).read(HEADERSIZE))
self.arch = 'i386'
assert ''.join(self.grr.magic) == 'GRRS'
assert self.grr.exe_num <= 16
assert self.grr.ranges[0].fd_offs == 16384
#TODO more asserts
super(CGCGrr, self).__init__(filename)
def maps(self):
for r in self.grr.ranges:
assert r.end>=r.begin
assert (r.end-r.begin)&0xfff == 0
assert r.fd_offs&0xfff == 0
if r.end-r.begin == 0:
continue
perms = ''
perms += r.is_r and 'r'or' '
perms += r.is_w and 'w'or' '
perms += r.is_x and 'x'or' '
if 'r' not in perms:
raise Exception("Not readable map from grr snapshot elf not supported")
yield((r.begin, r.end-r.begin, perms, self.path, r.fd_offs, r.end-r.begin))
def threads(self):
#Basic
regs = ['r15','r14','r13','r12','rbp','rbx','r11','r10','r9','r8','rax',
'rcx','rdx','rsi','rdi','rip','cs','eflags','rsp','ss','ds','es','fs','gs']
registers = dict([(name.upper(), getattr(self.grr.gregs, name)) for name in regs])
#XMM
for name in ['xmm0', 'xmm1', 'xmm2', 'xmm3', 'xmm4', 'xmm5', 'xmm6', 'xmm7', 'xmm8',
'xmm9', 'xmm10', 'xmm11', 'xmm12', 'xmm13', 'xmm14', 'xmm15' ]:
registers[name.upper()] = getattr(self.grr.fpregs.xmm_space, name).high << 64 | \
getattr(self.grr.fpregs.xmm_space, name).low
#FPU
for i in xrange(8):
registers['FP%d'%i] = ( getattr(self.grr.fpregs.st_space,'st%d'%i).mantissa,
getattr(self.grr.fpregs.st_space,'st%d'%i).exponent )
yield ('Running', registers)
class Minidump(Binary):
def __init__(self, filename):
self.md = minidump.MiniDump(path)
assert self.md.get_architecture() == "x86"
self.arch = 'i386'
major, minor = map(int, self.md.version.split(' ')[0].split('.'))
if major == 6:
self.flavor = "Windows7SP%d"%minor
elif major == 10:
self.flavor = "Windows10SP%d"%minor
else:
raise NotImplemented() #"Windows version not supported")
super(Minidump, self).__init__(filename)
def maps(self):
# Setting up memory maps
query = self.md.get_memory_map()
data = self.get_memory_data()
for addr in data:
perms, size = query[addr]
offsetofdatainminidump = 0
yield((addr&0xffffffff, size, perms, self.path, offsetofdatainminidump, len(data[addr]) ) )
def threads(self):
selectedThreadId = self.md.get_threads()[0].ThreadId
for thread in self.md.get_threads():
cxt = md.get_register_context_by_tid(thread.ThreadId)
#Let's just ignore all extra threads for now
status = 'Sleeping'
if selectedThreadId == thread.ThreadId:
status = 'Running'
registers = { 'EIP': cxt.Eip,
'ESP': cxt.Esp,
'EBP': cxt.Ebp,
'EAX': cxt.Eax,
'EBX': cxt.Ebx,
'ECX': cxt.Ecx,
'EDX': cxt.Edx,
'ESI': cxt.Esi,
'EDI': cxt.Edi,
'FS': cxt.SegFs}
if (additional_context and 'registers' in additional_context):
for name, value in additional_context['registers'].iteritems():
registers[name]= value
yield((status, registers))
Binary.magics= { '\x7fCGC': CGCElf,
'\x7fELF': Elf,
'GRRS': CGCGrr,
'MDMP': Minidump}
if __name__ == '__main__':
import sys
print list(Binary(sys.argv[1]).threads())
print list(Binary(sys.argv[1]).maps())