You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
134 lines
4.5 KiB
134 lines
4.5 KiB
#!/usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
#
|
|
# Copyright (C) 2011 Loic Jaquemet loic.jaquemet+python@gmail.com
|
|
#
|
|
|
|
from __future__ import print_function
|
|
import ctypes
|
|
import logging
|
|
|
|
import os
|
|
import pickle
|
|
|
|
from haystack.mappings.process import make_process_memory_handler
|
|
|
|
log = logging.getLogger('libdl')
|
|
|
|
|
|
class Dl_info(ctypes.Structure):
|
|
_fields_ = [
|
|
# Pathname of shared object that contains address
|
|
('dli_fname', ctypes.c_char_p),
|
|
# Address at which shared object is loaded
|
|
('dli_fbase', ctypes.c_void_p),
|
|
# Name of nearest symbol with address lower than addr
|
|
('dli_sname', ctypes.c_char_p),
|
|
# Exact address of symbol named in dli_sname
|
|
('dli_saddr', ctypes.c_void_p)
|
|
]
|
|
|
|
|
|
class Dummy():
|
|
pass
|
|
|
|
|
|
def getMappings():
|
|
me = Dummy()
|
|
me.pid = os.getpid()
|
|
return make_process_memory_handler(me)
|
|
|
|
# TODO FIXME: make a non-batch version
|
|
|
|
|
|
def reverseLocalFonctionPointerNames(context):
|
|
"""
|
|
reverse fn pointer names by trying to rebase the ptr value to a local ld_open.
|
|
|
|
load local memdump
|
|
map all librairies
|
|
go through all pointers in librairies
|
|
try to dl_addr the pointers by rebasing.
|
|
:param context:
|
|
:return:
|
|
"""
|
|
fsave = context.config.getCacheFilename(
|
|
context.config.CACHE_FUNCTION_NAMES,
|
|
context.dumpname)
|
|
if os.access(fsave, os.F_OK):
|
|
vtable = pickle.load(file(fsave, 'rb'))
|
|
for x in vtable.items():
|
|
yield x
|
|
raise StopIteration
|
|
|
|
IGNORES = ['None', '[heap]', '[stack]', '[vdso]']
|
|
|
|
# XXX this is not portable.
|
|
libdl = ctypes.CDLL('libdl.so')
|
|
|
|
def getname(fnaddr):
|
|
info = Dl_info()
|
|
ret = libdl.dladdr(fnaddr, ctypes.byref(info))
|
|
return info.dli_sname.string, info.dli_saddr
|
|
|
|
mappings = context.mappings
|
|
ldso = dict()
|
|
for m in mappings:
|
|
if m.pathname not in IGNORES and m.pathname not in ldso:
|
|
try:
|
|
ldso[m.pathname] = ctypes.CDLL(m.pathname)
|
|
except OSError as e:
|
|
IGNORES.append(m.pathname)
|
|
|
|
# looking in [heap] pointing to elsewhere
|
|
all_ptrs = context.listPointerValueInHeap()
|
|
log.debug('[+] %d pointers in heap to elsewhere ' % (len(all_ptrs)))
|
|
|
|
localmappings = getMappings()
|
|
vtable = dict()
|
|
|
|
for ptr in set(all_ptrs):
|
|
# get dump mmap
|
|
m = mappings.get_mapping_for_address(ptr)
|
|
if m.pathname not in IGNORES:
|
|
# find the right localmmap
|
|
localmaps = localmappings._get_mapping(m.pathname)
|
|
found = False
|
|
for localm in localmaps:
|
|
if localm.offset == m.offset and localm.permissions == m.permissions:
|
|
# found it
|
|
found = True
|
|
caddr = ptr - m.start + localm.start # rebase
|
|
dl_name, fnaddr = getname(caddr)
|
|
if dl_name is not None:
|
|
if fnaddr == caddr: # reverse check
|
|
log.debug('[+] REBASE 0x%x -> 0x%x p:%s|%s|=%s off:%x|%x|=%s %s fn: %s @%x' % (
|
|
ptr, caddr, m.permissions, localm.permissions, localm.permissions == m.permissions,
|
|
m.offset, localm.offset, m.offset == localm.offset, m.pathname, dl_name, fnaddr))
|
|
vtable[ptr] = dl_name
|
|
yield (ptr, dl_name)
|
|
else:
|
|
continue
|
|
print('[-] MIDDLE 0x%x -> 0x%x p:%s|%s|=%s off:%x|%x|=%s %s fn: %s @%x' % (
|
|
ptr, caddr, m.permissions, localm.permissions, localm.permissions == m.permissions,
|
|
m.offset, localm.offset, m.offset == localm.offset, m.pathname, dl_name, fnaddr))
|
|
else:
|
|
continue
|
|
print('FAIL REBASE (not public ?) 0x%x -> 0x%x p:%s|%s|=%s off:%x|%x|=%s %s fn: %s ' % (
|
|
ptr, caddr, m.permissions, localm.permissions, localm.permissions == m.permissions,
|
|
m.offset, localm.offset, m.offset == localm.offset, m.pathname, dl_name))
|
|
pass
|
|
break
|
|
if not found:
|
|
continue
|
|
print('[+] not a fn pointer %x\n' % (ptr), m, '\n ---dump Vs local ---- \n',
|
|
'\n'.join(map(str, localmaps)))
|
|
# pass
|
|
for name, lib in ldso.items():
|
|
ret = libdl.dlclose(lib._handle)
|
|
|
|
import pickle
|
|
pickle.dump(vtable, file(fsave, 'wb'))
|
|
|
|
raise StopIteration
|