summaryrefslogtreecommitdiff
path: root/hypodermic/process.py
diff options
context:
space:
mode:
authorjakob <jakob@memeware.net>2017-09-10 14:12:54 -0400
committerjakob <jakob@memeware.net>2017-09-10 14:12:54 -0400
commitd801868006f94acc6e3313332c55331710171172 (patch)
tree9748047178f5503b198d52d07db75ded2e95c73c /hypodermic/process.py
parent81e47a4dba4a44624ec56708c1655206ae19cbfc (diff)
Initial invocation of _dl_open in the RTLD
Diffstat (limited to 'hypodermic/process.py')
-rw-r--r--hypodermic/process.py74
1 files changed, 72 insertions, 2 deletions
diff --git a/hypodermic/process.py b/hypodermic/process.py
index e26978b..35b8c1d 100644
--- a/hypodermic/process.py
+++ b/hypodermic/process.py
@@ -18,11 +18,16 @@
"""ctypes wrapper for ptrace."""
import ctypes
-import os.path
+import os
import re
+from elftools.elf.elffile import ELFFile
+from elftools.elf.sections import SymbolTableSection
+
from hypodermic.memory import Region, maps
-from hypodermic.shellcode import assemble, open_shellcode
+from hypodermic.shellcode import (assemble, close_shellcode, dlopen_shellcode,
+ mmap_shellcode, munmap_shellcode,
+ open_shellcode)
_AMD64_INDICES = {
"r15": 0,
@@ -436,6 +441,35 @@ class Process(object):
else:
self.run_code(munmap_shellcode(addr, size, arch="i386"))
+ def dlopen(self, path: str) -> int:
+ """Maps a shared object into the process address space.
+
+ Args:
+ path (str): The path of the shared object to inject.
+
+ Raises:
+ OSError: If the process does not have a usable RTLD.
+
+ Returns:
+ The address at which the library was loaded.
+ """
+ if not self.rtld:
+ raise OSError("Process does not have a usable RTLD")
+
+ if self.arch == "x64":
+ old_rax = self.get_register("rax")
+ self.run_code(dlopen_shellcode(self.rtld_dl_open_addr, path),
+ preserve=["rax"])
+ addr = self.get_register("rax")
+ self.set_register("rax", old_rax)
+ else:
+ old_eax = self.get_register("eax")
+ self.run_code(dlopen_shellcode(self.rtld_dl_open_addr, path,
+ arch="i386"), preserve=["eax"])
+ addr = self.get_register("eax")
+ self.set_register("eax", old_eax)
+ return addr
+
def page_start(self, addr: int) -> int:
return addr & ~(self.page_size - 1)
@@ -467,6 +501,32 @@ class Process(object):
return "x64" if self._isamd64 else "x86"
@property
+ def rtld_dl_open_addr(self) -> int:
+ """Obtain the absolute address of _dl_open in main memory.
+
+ Raises:
+ OSError: If either the process has no instance of the RTLD,
+ or the RTLD lacks sufficient symbols.
+
+ Returns:
+ An integer containing the address.
+ """
+ if self.rtld is None:
+ raise OSError("Process has no RTLD instance")
+
+ with open(self.rtld.path, "rb") as rtld:
+ elf = ELFFile(rtld)
+ symtab = elf.get_section_by_name(".symtab")
+
+ if not isinstance(symtab, SymbolTableSection):
+ raise OSError("RTLD has no usable symbol table")
+
+ res = symtab.get_symbol_by_name("_dl_open")
+ if len(res) < 1:
+ raise OSError("RTLD has no _dl_open symbol")
+ return self.rtld.start + res[0].entry.st_value
+
+ @property
def maps(self) -> list:
"""Obtain the process' memory map.
@@ -475,6 +535,16 @@ class Process(object):
"""
return maps(self.pid)
+ # TODO: Return something more detailed than the list of open fds.
+ @property
+ def fds(self) -> list:
+ """Obtain currently open file descriptors for the process.
+
+ Returns:
+ A list of integer file descriptors.
+ """
+ return [int(fd) for fd in os.listdir("/proc/{}/fd/".format(self.pid))]
+
@property
def rtld(self) -> Region:
"""Obtain the base region of memory for the process' RTLD, if it