Files
2014-07-14 19:14:13 -05:00

743 lines
25 KiB
Python

# Volatility
# Copyright (C) 2007-2011 Volatile Systems
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or (at
# your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# ELF64 format: http://downloads.openwatcom.org/ftp/devel/docs/elf-64-gen.pdf
import volatility.obj as obj
elf32_vtypes = {
'elf32_hdr' : [ 52, {
'e_ident' : [ 0, ['String', dict(length = 16)]],
'e_type' : [ 16, ['Enumeration', dict(target = 'unsigned short', choices = {
0: 'ET_NONE',
1: 'ET_REL',
2: 'ET_EXEC',
3: 'ET_DYN',
4: 'ET_CORE',
0xff00: 'ET_LOPROC',
0xffff: 'ET_HIPROC'})]],
'e_machine' : [ 18, ['unsigned short']],
'e_version' : [ 20, ['unsigned int']],
'e_entry' : [ 24, ['unsigned int']],
'e_phoff' : [ 28, ['unsigned int']],
'e_shoff' : [ 32, ['unsigned int']],
'e_flags' : [ 36, ['unsigned int']],
'e_ehsize' : [ 40, ['unsigned short']],
'e_phentsize' : [ 42, ['unsigned short']],
'e_phnum' : [ 44, ['unsigned short']],
'e_shentsize' : [ 46, ['unsigned short']],
'e_shnum' : [ 48, ['unsigned short']],
'e_shstrndx' : [ 50, ['unsigned short']],
}],
'elf32_phdr' : [ 32, {
'p_type' : [ 0, ['Enumeration', dict(target = 'unsigned int', choices = {
0: 'PT_NULL',
1: 'PT_LOAD',
2: 'PT_DYNAMIC',
3: 'PT_INTERP',
4: 'PT_NOTE',
5: 'PT_SHLIB',
6: 'PT_PHDR',
7: 'PT_TLS',
0x60000000: 'PT_LOOS',
0x6fffffff: 'PT_HIOS',
0x70000000: 'PT_LOPROC',
0x7fffffff: 'PT_HIPROC'})]],
'p_offset' : [ 4, ['unsigned int']],
'p_vaddr' : [ 8, ['unsigned int']],
'p_paddr' : [ 12, ['unsigned int']],
'p_filesz' : [ 16, ['unsigned int']],
'p_memsz' : [ 20, ['unsigned int']],
'p_flags' : [ 24, ['unsigned int']],
'p_align' : [ 28, ['unsigned int']],
}],
'elf32_shdr' : [40, {
'sh_name' : [0, ['unsigned int']],
'sh_type' : [4, ['unsigned int']],
'sh_flags' : [8, ['unsigned int']],
'sh_addr' : [12, ['unsigned int']],
'sh_offset' : [16, ['unsigned int']],
'sh_size' : [20, ['unsigned int']],
'sh_link' : [24, ['unsigned int']],
'sh_info' : [28, ['unsigned int']],
'sh_addralign' : [32, ['unsigned int']],
'sh_entsize' : [36, ['unsigned int']],
}],
'elf32_dyn' : [ 8, {
'd_tag' : [0, ['int']],
'd_ptr' : [4, ['unsigned int']],
}],
'elf32_note' : [ 12, {
'n_namesz' : [ 0, ['unsigned int']],
'n_descsz' : [ 4, ['unsigned int']],
'n_type' : [ 8, ['unsigned int']],
## FIXME: this must be cast to int() because the base AS (FileAddressSpace) read method doesn't understand NativeType.
## Remove the cast after http://code.google.com/p/volatility/issues/detail?id=350 is fixed.
'namesz' : [ 12, ['String', dict(length = lambda x : int(x.n_namesz))]],
}],
'elf32_link_map' : [0, {
'l_addr' : [0, ['unsigned int']],
'l_name' : [4, ['unsigned int']],
'l_ld' : [8, ['unsigned int']],
'l_next' : [12, ['unsigned int']],
'l_prev' : [16, ['unsigned int']],
}],
'elf32_sym' : [ 16, {
'st_name' : [ 0, ['unsigned int']],
'st_value' : [ 4, ['unsigned int']],
'st_size' : [ 8, ['unsigned int']],
'st_info' : [ 12, ['unsigned char']],
'st_other' : [ 13, ['unsigned char']],
'st_shndx' : [ 14, ['unsigned short']],
}],
'elf32_rel' : [ 8, {
'r_offset' : [ 0, ['unsigned int']],
'r_info' : [ 4, ['unsigned int']],
}],
'elf32_rela' : [ 12, {
'r_offset' : [ 0, ['unsigned int']],
'r_info' : [ 4, ['unsigned int']],
'r_addend' : [ 8, ['int']],
}],
}
elf64_vtypes = {
'elf64_hdr' : [ 64, {
'e_ident' : [ 0, ['String', dict(length = 16)]],
'e_type' : [ 16, ['Enumeration', dict(target = 'unsigned short', choices = {
0: 'ET_NONE',
1: 'ET_REL',
2: 'ET_EXEC',
3: 'ET_DYN',
4: 'ET_CORE',
0xff00: 'ET_LOPROC',
0xffff: 'ET_HIPROC'})]],
'e_machine' : [ 18, ['unsigned short']],
'e_version' : [ 20, ['unsigned int']],
'e_entry' : [ 24, ['unsigned long long']],
'e_phoff' : [ 32, ['unsigned long long']],
'e_shoff' : [ 40, ['unsigned long long']],
'e_flags' : [ 48, ['unsigned int']],
'e_ehsize' : [ 52, ['unsigned short']],
'e_phentsize' : [ 54, ['unsigned short']],
'e_phnum' : [ 56, ['unsigned short']],
'e_shentsize' : [ 58, ['unsigned short']],
'e_shnum' : [ 60, ['unsigned short']],
'e_shstrndx' : [ 62, ['unsigned short']],
}],
'elf64_phdr' : [ 56, {
'p_type' : [ 0, ['Enumeration', dict(target = 'unsigned int', choices = {
0: 'PT_NULL',
1: 'PT_LOAD',
2: 'PT_DYNAMIC',
3: 'PT_INTERP',
4: 'PT_NOTE',
5: 'PT_SHLIB',
6: 'PT_PHDR',
7: 'PT_TLS',
0x60000000: 'PT_LOOS',
0x6fffffff: 'PT_HIOS',
0x70000000: 'PT_LOPROC',
0x7fffffff: 'PT_HIPROC'})]],
'p_flags' : [ 4, ['unsigned int']],
'p_offset' : [ 8, ['unsigned long long']],
'p_vaddr' : [ 16, ['unsigned long long']],
'p_paddr' : [ 24, ['unsigned long long']],
'p_filesz' : [ 32, ['unsigned long long']],
'p_memsz' : [ 40, ['unsigned long long']],
'p_align' : [ 48, ['unsigned long long']],
}],
'elf64_shdr' : [64, {
'sh_name' : [0, ['unsigned int']],
'sh_type' : [4, ['unsigned int']],
'sh_flags' : [8, ['unsigned long long']],
'sh_addr' : [16, ['unsigned long long']],
'sh_offset' : [24, ['unsigned long long']],
'sh_size' : [32, ['unsigned long long']],
'sh_link' : [40, ['unsigned int']],
'sh_info' : [44, ['unsigned int']],
'sh_addralign' : [48, ['unsigned long long']],
'sh_entsize' : [56, ['unsigned long long']],
}],
'elf64_dyn' : [ 16, {
'd_tag' : [0, ['long long']],
'd_ptr' : [8, ['unsigned long long']],
}],
'elf64_note' : [ 12, {
'n_namesz' : [ 0, ['unsigned int']],
'n_descsz' : [ 4, ['unsigned int']],
'n_type' : [ 8, ['unsigned int']],
## FIXME: this must be cast to int() because the base AS (FileAddressSpace) read method doesn't understand NativeType.
## Remove the cast after http://code.google.com/p/volatility/issues/detail?id=350 is fixed.
'namesz' : [ 12, ['String', dict(length = lambda x : int(x.n_namesz))]],
}],
'elf64_sym' : [ 24 , {
'st_name' : [ 0, ['unsigned int']],
'st_info' : [ 4, ['unsigned char']],
'st_other' : [ 5, ['unsigned char']],
'st_shndx' : [ 6, ['unsigned short']],
'st_value' : [ 8, ['unsigned long long']],
'st_size' : [ 16, ['unsigned long long']],
}],
'elf64_link_map' : [0, {
'l_addr' : [0, ['unsigned long long']],
'l_name' : [8, ['unsigned long long']],
'l_ld' : [16, ['unsigned long long']],
'l_next' : [24, ['unsigned long long']],
'l_prev' : [32, ['unsigned long long']],
}],
'elf64_rel' : [ 16, {
'r_offset' : [ 0, ['unsigned long long']],
'r_info' : [ 8, ['unsigned long long']],
}],
'elf64_rela' : [ 24, {
'r_offset' : [ 0, ['unsigned long long']],
'r_info' : [ 8, ['unsigned long long']],
'r_addend' : [ 16, ['long long']],
}],
}
class elf(obj.CType):
def __init__(self, is_header, name32, name64, theType, offset, vm, name = None, **kwargs):
self.name32 = name32
self.name64 = name64
self.elf_obj = None
if is_header:
self._init_cache(offset, vm)
else:
self.size_cache = -39
obj.CType.__init__(self, theType, offset, vm, name, **kwargs)
def is_valid(self):
return self.size_cache in [32, 64, -39]
def _init_cache_from_parent(self):
self.size_cache = self.obj_parent.size_cache
self._make_elf_obj(self.obj_offset, self.obj_vm)
def _make_elf_obj(self, offset, vm):
if self.size_cache == 32:
self.elf_obj = obj.Object(self.name32, offset = offset, vm = vm)
elif self.size_cache == 64:
self.elf_obj = obj.Object(self.name64, offset = offset, vm = vm)
else:
self.elf_obj = None
def _set_size_cache(self, offset, vm):
ei_class = obj.Object("unsigned char", offset = offset + 4, vm = vm)
if ei_class == 1:
self.size_cache = 32
elif ei_class == 2:
self.size_cache = 64
else:
self.size_cache = -42
def _init_cache(self, offset, vm):
self._set_size_cache(offset, vm)
self._make_elf_obj(offset, vm)
def _get_typename(self, typename):
if self.size_cache == -39:
self._init_cache_from_parent()
if self.size_cache == 32:
typename = "elf32_" + typename
else:
typename = "elf64_" + typename
return typename
def __getattr__(self, attr):
if self.size_cache == -39:
self._init_cache_from_parent()
return self.elf_obj.__getattr__(attr)
class elf_hdr(elf):
"""An ELF header"""
def __init__(self, theType, offset, vm, name = None, **kwargs):
# these are populaed on the first call to symbols()
self.cached_symtab = None
self.cached_strtab = None
self.cached_numsyms = 0
elf.__init__(self, 1, "elf32_hdr", "elf64_hdr", theType, offset, vm, name, **kwargs)
def is_valid(self):
return self.elf_obj != None
def program_headers(self):
rtname = self._get_typename("phdr")
rtsize = self.obj_vm.profile.get_obj_size(rtname)
tname = "elf_phdr"
# the buffer of headers
arr_start = self.obj_offset + self.e_phoff
for i in range(self.e_phnum):
# use the real size
idx = i * rtsize
phdr = obj.Object("elf_phdr", offset = arr_start + idx, vm = self.obj_vm, parent = self)
if phdr.is_valid():
yield phdr
def _section_headers(self):
rtname = self._get_typename("shdr")
rtsize = self.obj_vm.profile.get_obj_size(rtname)
tname = "elf_shdr"
# the buffer of headers
arr_start = self.obj_offset + self.e_shoff
return (arr_start, rtsize)
def section_header(self, idx):
(arr_start, rtsize) = self._section_headers()
idx = idx * rtsize
shdr = obj.Object("elf_shdr", offset = arr_start + idx, vm = self.obj_vm, parent = self)
return shdr
def section_headers(self):
(arr_start, rtsize) = self._section_headers()
for i in range(self.e_shnum):
# use the real size
idx = i * rtsize
shdr = obj.Object("elf_shdr", offset = arr_start + idx, vm = self.obj_vm, parent = self)
if shdr.is_valid():
yield shdr
def _find_symbols_program_headers(self):
for phdr in self.program_headers():
if not phdr.is_valid() or str(phdr.p_type) != 'PT_DYNAMIC':
continue
dt_strtab = None
dt_symtab = None
dt_strent = None
for dsec in phdr.dynamic_sections():
if dsec.d_tag == 5:
dt_strtab = dsec.d_ptr
elif dsec.d_tag == 6:
dt_symtab = dsec.d_ptr
elif dsec.d_tag == 11:
dt_strent = dsec.d_ptr
if dt_strtab == None or dt_symtab == None or dt_strent == None:
return None
break
self.cached_symtab = dt_symtab
self.cached_strtab = dt_strtab
if dt_symtab.v() < dt_strtab.v():
self.cached_numsyms = (dt_strtab.v() - dt_symtab.v()) / dt_strent
else:
self.cached_numsyms = 1024
def _find_symbols(self):
self._find_symbols_program_headers()
def symbols(self):
if self.cached_symtab == None:
self._find_symbols()
if self.cached_symtab == None:
return
rtname = self._get_typename("sym")
symtab_arr = obj.Object(theType="Array", targetType=rtname, count=self.cached_numsyms, offset = self.cached_symtab, vm = self.obj_vm)
for sym in symtab_arr:
yield sym
def symbol_at(self, sym_idx):
ret = None
for (cur_idx, sym) in enumerate(self.symbols()):
if cur_idx == sym_idx:
ret = sym
break
return ret
def symbol_name(self, sym):
addr = self.cached_strtab + sym.st_name
name = self.obj_vm.read(addr, 255)
if name:
idx = name.find("\x00")
if idx != -1:
name = name[:idx]
else:
name = "N/A"
return name
def relocation_symbol(self, reloc):
ridx = reloc.relocation_symbol_index()
sym = self.symbol_at(ridx)
return sym
def relocations(self):
for phdr in self.program_headers():
if str(phdr.p_type) != 'PT_DYNAMIC':
continue
dt_jmprel = None
dt_pltrelsz = None
dt_pltrel = None
for dsec in phdr.dynamic_sections():
if dsec.d_tag == 23:
dt_jmprel = dsec.d_ptr
elif dsec.d_tag == 2:
dt_pltrelsz = dsec.d_ptr
elif dsec.d_tag == 20:
dt_pltrel = dsec.d_ptr
if dt_jmprel == None or dt_pltrelsz == None or dt_pltrel == None:
print "needed info missing"
return
if dt_pltrel == 7:
struct_name = "elf_rela"
if self.size_cache == 32:
struct_size = 12
else:
struct_size = 24
elif dt_pltrel == 17:
struct_name = "elf_rel"
if self.size_cache == 32:
struct_size = 8
else:
struct_size = 16
else:
print "unknown relocation type: %d" % dt_pltrel
# arr = obj.Object(theType="Array", targetType=struct_name, parent = self, count = dt_pltrelsz / struct_size, offset = dt_jmprel, vm = self.obj_vm)
count = dt_pltrelsz / struct_size
for idx in range(count + 24):
offset = dt_jmprel + (idx * struct_size)
reloc = obj.Object(struct_name, offset = offset, vm = self.obj_vm, parent = self)
yield reloc
class elf_shdr(elf):
""" An elf section header """
def __init__(self, theType, offset, vm, name = None, **kwargs):
elf.__init__(self, 0, "elf32_shdr", "elf64_shdr", theType, offset, vm, name, **kwargs)
class elf32_shdr(obj.CType):
def __init__(self, theType, offset, vm, name = None, **kwargs):
obj.CType.__init__(self, theType, offset, vm, name, **kwargs)
class elf64_shdr(obj.CType):
def __init__(self, theType, offset, vm, name = None, **kwargs):
obj.CType.__init__(self, theType, offset, vm, name, **kwargs)
class elf_rel(elf):
""" An elf relocation """
def __init__(self, theType, offset, vm, name = None, **kwargs):
elf.__init__(self, 0, "elf32_rel", "elf64_rel", theType, offset, vm, name, **kwargs)
def relocation_type(self):
t = self._get_typename("rel")
if t == "elf32_rel":
ret = self.r_info & 0xff
else:
ret = self.r_info & 0xffffffff
return ret
def relocation_symbol_index(self):
t = self._get_typename("rel")
if t == "elf32_rel":
ret = self.r_info >> 8
else:
ret = self.r_info >> 32
return ret
class elf32_rel(obj.CType):
def __init__(self, theType, offset, vm, name = None, **kwargs):
obj.CType.__init__(self, theType, offset, vm, name, **kwargs)
class elf64_rel(obj.CType):
def __init__(self, theType, offset, vm, name = None, **kwargs):
obj.CType.__init__(self, theType, offset, vm, name, **kwargs)
class elf_rela(elf):
""" An elf relocation """
def __init__(self, theType, offset, vm, name = None, **kwargs):
elf.__init__(self, 0, "elf32_rela", "elf64_rela", theType, offset, vm, name, **kwargs)
def relocation_type(self):
t = self._get_typename("rel")
if t == "elf32_rel":
ret = self.r_info & 0xff
else:
ret = self.r_info & 0xffffffff
return ret
def relocation_symbol_index(self):
t = self._get_typename("rel")
if t == "elf32_rel":
ret = self.r_info >> 8
else:
ret = self.r_info >> 32
return ret
class elf32_rela(obj.CType):
def __init__(self, theType, offset, vm, name = None, **kwargs):
obj.CType.__init__(self, theType, offset, vm, name, **kwargs)
class elf64_rela(obj.CType):
def __init__(self, theType, offset, vm, name = None, **kwargs):
obj.CType.__init__(self, theType, offset, vm, name, **kwargs)
class elf_phdr(elf):
""" An elf program header """
def __init__(self, theType, offset, vm, name = None, **kwargs):
elf.__init__(self, 0, "elf32_phdr", "elf64_phdr", theType, offset, vm, name, **kwargs)
@property
def p_vaddr(self):
ret = self.__getattr__("p_vaddr")
if self.obj_parent.e_type == 3: # ET_DYN
ret = self.obj_parent.obj_offset + ret
return ret
def dynamic_sections(self):
# sanity check
if str(self.p_type) != 'PT_DYNAMIC':
print "failed sanity check"
return
rtname = self._get_typename("dyn")
rtsize = self.obj_vm.profile.get_obj_size(rtname)
tname = "elf_dyn"
# the buffer of array starts at elf_base + our virtual address ( offset )
arr_start = self.p_vaddr
for i in range(256):
# use the real size
idx = i * rtsize
dyn = obj.Object(tname, offset = arr_start + idx, vm = self.obj_vm, parent = self)
yield dyn
if dyn.d_tag == 0:
break
class elf32_phdr(obj.CType):
def __init__(self, theType, offset, vm, name = None, **kwargs):
obj.CType.__init__(self, theType, offset, vm, name, **kwargs)
class elf64_phdr(obj.CType):
def __init__(self, theType, offset, vm, name = None, **kwargs):
obj.CType.__init__(self, theType, offset, vm, name, **kwargs)
class elf_sym(elf):
""" An elf symbol struct"""
def __init__(self, theType, offset, vm, name = None, **kwargs):
elf.__init__(self, 0, "elf32_sym", "elf64_sym", theType, offset, vm, name, **kwargs)
class elf32_sym(obj.CType):
def __init__(self, theType, offset, vm, name = None, **kwargs):
obj.CType.__init__(self, theType, offset, vm, name, **kwargs)
class elf64_sym(obj.CType):
def __init__(self, theType, offset, vm, name = None, **kwargs):
obj.CType.__init__(self, theType, offset, vm, name, **kwargs)
class elf_dyn(elf):
""" An elf dynamic section struct"""
def __init__(self, theType, offset, vm, name = None, **kwargs):
elf.__init__(self, 0, "elf32_dyn", "elf64_dyn", theType, offset, vm, name, **kwargs)
class elf32_dyn(obj.CType):
def __init__(self, theType, offset, vm, name = None, **kwargs):
obj.CType.__init__(self, theType, offset, vm, name, **kwargs)
class elf64_dyn(obj.CType):
def __init__(self, theType, offset, vm, name = None, **kwargs):
obj.CType.__init__(self, theType, offset, vm, name, **kwargs)
class elf_note(elf):
"""An ELF note header"""
def __init__(self, theType, offset, vm, name = None, **kwargs):
elf.__init__(self, 0, "elf32_note", "elf64_note", theType, offset, vm, name, **kwargs)
def cast_descsz(self, obj_type):
"""Cast the descsz member as a specified type.
@param obj_type: name of the object
The descsz member is at a variable offset, which depends
on the length of the namesz string which precedes it. The
string is 8-byte aligned and can be zero.
"""
desc_offset = (self.obj_offset +
self.obj_vm.profile.get_obj_size(self._get_typename("note")) +
((((self.n_namesz - 1) >> 3) + 1) << 3))
return obj.Object(obj_type, offset = desc_offset, vm = self.obj_vm, parent = self)
class elf32_note(obj.CType):
def __init__(self, theType, offset, vm, name = None, **kwargs):
obj.CType.__init__(self, theType, offset, vm, name, **kwargs)
class elf64_note(obj.CType):
def __init__(self, theType, offset, vm, name = None, **kwargs):
obj.CType.__init__(self, theType, offset, vm, name, **kwargs)
class elf_link_map(elf):
""" An libdl link map structure"""
def __init__(self, theType, offset, vm, name = None, **kwargs):
elf.__init__(self, 0, "elf32_link_map", "elf64_link_map", theType, offset, vm, name, **kwargs)
@property
def l_name(self):
saddr = self.__getattr__("l_name")
buf = self.obj_vm.zread(saddr, 256)
idx = buf.find("\x00")
if idx != -1:
buf = buf[:idx]
return str(buf)
@property
def l_next(self):
naddr = self.elf_obj.m("l_next")
tname = "elf_link_map"
return obj.Object(tname, offset = naddr, vm = self.obj_vm, parent = self)
@property
def l_prev(self):
naddr = self.elf_obj.m("l_prev")
tname = "elf_link_map"
return obj.Object(tname, offset = naddr, vm = self.obj_vm, parent = self)
def __iter__(self):
cur = self
while cur:
yield cur
cur = cur.l_next
cur = self
while cur:
yield cur
cur = cur.l_prev
class elf32_link_map(obj.CType):
def __init__(self, theType, offset, vm, name = None, **kwargs):
obj.CType.__init__(self, theType, offset, vm, name, **kwargs)
class elf64_link_map(obj.CType):
def __init__(self, theType, offset, vm, name = None, **kwargs):
obj.CType.__init__(self, theType, offset, vm, name, **kwargs)
class ELFModification(obj.ProfileModification):
def modification(self, profile):
profile.object_classes.update({
'elf' : elf,
'elf_hdr' : elf_hdr,
'elf_note' : elf_note,
'elf_phdr' : elf_phdr,
'elf32_phdr' : elf32_phdr,
'elf64_phdr' : elf64_phdr,
'elf_dyn' : elf_dyn,
'elf32_dyn' : elf32_dyn,
'elf64_dyn' : elf64_dyn,
'elf_shdr' : elf_shdr,
'elf32_shdr' : elf32_shdr,
'elf64_shdr' : elf64_shdr,
'elf_sym' : elf_sym,
'elf32_sym' : elf32_sym,
'elf64_sym' : elf64_sym,
'elf_note' : elf_note,
'elf32_note' : elf32_note,
'elf64_note' : elf64_note,
'elf_link_map' : elf_link_map,
'elf32_link_map' : elf32_link_map,
'elf64_link_map' : elf64_link_map,
'elf_rel' : elf_rel,
'elf32_rel' : elf32_rel,
'elf64_rel' : elf64_rel,
'elf_rela' : elf_rela,
'elf32_rela' : elf32_rela,
'elf64_rela' : elf64_rela
})
class ELF64Modification(obj.ProfileModification):
def modification(self, profile):
profile.vtypes.update(elf64_vtypes)
class ELF32Modification(obj.ProfileModification):
def modification(self, profile):
profile.vtypes.update(elf32_vtypes)