summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjakob <jakob@memeware.net>2017-08-29 15:19:54 -0400
committerjakob <jakob@memeware.net>2017-08-29 15:19:54 -0400
commita0aac5609c87443ea12d04ffb280234c24d13e3f (patch)
tree0d509580be6e30a3ff6a26e55a2f46472c91afcd
parente687f96e883af18ef293b6844ef28f0c829d6e3c (diff)
Implemented parsing for procfs maps
-rw-r--r--.gitignore2
-rw-r--r--hypodermic/main.py75
-rw-r--r--hypodermic/memory.py111
-rw-r--r--hypodermic/ptrace.py21
-rw-r--r--wrapper/Makefile4
-rw-r--r--wrapper/ptrace.c4
6 files changed, 202 insertions, 15 deletions
diff --git a/.gitignore b/.gitignore
index e7ffb10..e2fad71 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,4 +10,4 @@ dist/
*.egg-info
*.pyc
*.egg
-libptracew.so
+libhypodermicw.so
diff --git a/hypodermic/main.py b/hypodermic/main.py
index 05d467a..b0d709b 100644
--- a/hypodermic/main.py
+++ b/hypodermic/main.py
@@ -15,6 +15,79 @@
# You should have received a copy of the GNU General Public License along
# with Hypodermic. If not, see <http://www.gnu.org/licenses/>.
+"""Command-line interface to Hypodermic."""
+
+import argparse
+import sys
+import textwrap
+import pprint #
+
+from hypodermic.memory import maps
+from hypodermic.ptrace import Process
+
+
+class CustomHelp(argparse.HelpFormatter):
+ """Modifications to argparse's default HelpFormatter."""
+ def _fill_text(self, text, width, indent):
+ filled = []
+ for line in text.splitlines(keepends=True):
+ filled.append(indent + line)
+ return "".join(filled)
+
+ def _split_lines(self, text, width):
+ return text.splitlines()
+
+ def add_usage(self, usage, actions, groups, prefix=None):
+ prefix = prefix or "Usage: "
+ both = super(CustomHelp, self)
+ return both.add_usage(usage, actions, groups, prefix)
+
def main():
- print("Don't share needles, brah!")
+ parser = argparse.ArgumentParser(
+ add_help=False,
+ formatter_class=CustomHelp,
+ usage="%(prog)s [-a pid] [-c path] [options]",
+ description="Don't share needles, brah!"
+ )
+
+ doc = parser.add_argument_group("Documentation")
+ doc.add_argument(
+ "-h",
+ "--help",
+ action="help",
+ help="Display this help page and exit."
+ )
+ doc.add_argument(
+ "-V",
+ "--version",
+ action="version",
+ version="What version?",
+ help="Display the currently installed version and exit."
+ )
+
+ proc = parser.add_argument_group("Process Manipulation")
+ meth = proc.add_mutually_exclusive_group()
+ proc.add_argument(
+ "-a",
+ "--attach",
+ metavar="PID",
+ help="The pid of a process to attach to."
+ )
+ proc.add_argument(
+ "-c",
+ "--create",
+ metavar="BIN",
+ help="The path of a binary to execute and attach to."
+ )
+
+ args = parser.parse_args()
+
+ if args.attach is None and args.create is None:
+ print("No action specified. Quitting!")
+ sys.exit(1)
+
+ if args.create:
+ p = Process(path=args.create)
+ else:
+ p = Process(pid=args.attach)
diff --git a/hypodermic/memory.py b/hypodermic/memory.py
new file mode 100644
index 0000000..6ffa5d1
--- /dev/null
+++ b/hypodermic/memory.py
@@ -0,0 +1,111 @@
+# Copyright (C) 2017 Jakob Kreuze, All Rights Reserved.
+#
+# This file is part of Hypodermic.
+#
+# Hypodermic 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 3 of the License, or (at your
+# option) any later version.
+#
+# Hypodermic 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 Hypodermic. If not, see <http://www.gnu.org/licenses/>.
+
+"""Parsing of a program's memory mapping info from procfs."""
+
+import collections
+import re
+
+
+Device = collections.namedtuple(
+ "Device",
+ ["major", "minor"]
+)
+
+Perms = collections.namedtuple(
+ "Perms",
+ ["r", "w", "x", "s"]
+)
+
+Region = collections.namedtuple(
+ "Region",
+ ["start", "end", "perms", "off", "dev", "inode", "path"]
+)
+
+
+def parse_device(line: str) -> Device:
+ """Converts a device line of the form "maj:min" into a Device
+ object.
+
+ Args:
+ line(str): The line to parse.
+
+ Returns:
+ The parsed Device object.
+ """
+ major, minor = line.split(':')
+ return Device(major, minor)
+
+
+def parse_perms(line: str) -> Perms:
+ """Converts a permissions line of the form "rwxp" into a Perms
+ object.
+
+ Args:
+ line(str): The line to parse.
+
+ Returns:
+ The parsed Perms object.
+ """
+ return Perms(line[0] == 'r', line[1] == 'w', line[2] == 'x', line[3] == 's')
+
+
+def parse_region(line: str) -> Region:
+ """Converts a line of text from the "maps" file into a Region
+ object.
+
+ Args:
+ line(str): The line to parse.
+
+ Returns:
+ The parsed Region object.
+ """
+ ret = re.split(r"\s+", line.strip())
+ if len(ret) == 6:
+ address, perms, off, dev, inode, path = ret
+ else:
+ address, perms, off, dev, inode = ret
+ path = ""
+ start, end = address.split('-')
+ return Region(int(start, 16), int(end, 16), parse_perms(perms),
+ int(off, 16), parse_device(dev), int(inode), path)
+
+
+def maps(pid: int) -> list:
+ """Gets memory mapping information for a given pid.
+
+ Args:
+ pid (int): The pid of the process to get memory mapping
+ information for.
+
+ Raises:
+ TypeError: If the pid argument is not an int.
+ PermissionError: If the mapping information cannot be read.
+
+ Returns:
+ A list of Region objects.
+ """
+ if not isinstance(pid, int):
+ raise TypeError("pid argument must be an int")
+
+ regions = []
+
+ with open("/proc/{}/maps".format(pid)) as maps:
+ for line in maps:
+ regions.append(parse_region(line))
+
+ return regions
diff --git a/hypodermic/ptrace.py b/hypodermic/ptrace.py
index d073930..7a14dea 100644
--- a/hypodermic/ptrace.py
+++ b/hypodermic/ptrace.py
@@ -15,28 +15,31 @@
# You should have received a copy of the GNU General Public License along
# with Hypodermic. If not, see <http://www.gnu.org/licenses/>.
-"""Wrapper for the ptrace system call, since python-ptrace sucks."""
+"""ctypes wrapper for ptrace."""
import ctypes
-# TODO: Instantiate from binary path, as well.
class Process(object):
"""Process attached via ptrace.
Note:
The process is implicitly detached from upon destruction of this
- object.
+ object, if appropriate.
Args:
pid (:obj:`int`, optional): The pid of the process to attach to.
- Defaults to 0, which means that it will not be used.
+ Defaults to 0, which means that the argument will not be
+ used.
path (:obj:`str`, optional): The path of the binary to run.
- Defaults to "", which will be used if no pid is specified.
+ Defaults to "", which will as the target if a pid is not
+ specified, either.
Raises:
- TypeError: If the pid argument is not an int.
- OSError: If the pid cannot be attached to.
+ TypeError: If the pid argument is not an int, or if the path
+ argument is not a string.
+ OSError: If the pid cannot be attached to, or if the process
+ could not be created for the given binary.
"""
def __init__(self, pid=0, path=""):
@@ -56,14 +59,12 @@ class Process(object):
if self.pid < 0:
raise OSError("Could not create process {}".format(path))
-
def __del__(self):
if hasattr(self, "_is_parent") and not self._is_parent:
self.detach()
def _load_ffi_methods(self):
- # FIXME: How are we going to deal with the path?
- self._so = ctypes.cdll.LoadLibrary("/tmp/libptracew.so")
+ self._so = ctypes.cdll.LoadLibrary("/tmp/libhypodermicw.so")
self._new_proc = self._so.new_proc
self._attach = self._so.attach
self._detach = self._so.detach
diff --git a/wrapper/Makefile b/wrapper/Makefile
index 026f4ba..19fa189 100644
--- a/wrapper/Makefile
+++ b/wrapper/Makefile
@@ -6,7 +6,7 @@ CFLAGS += $(USER_CFLAGS)
LDFLAGS = -shared
LDFLAGS += $(USER_LDFLAGS)
-all: libptracew.so
+all: libhypodermicw.so
-libptracew.so: ptrace.c
+libhypodermicw.so: ptrace.c
$(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS)
diff --git a/wrapper/ptrace.c b/wrapper/ptrace.c
index caf510f..706b13e 100644
--- a/wrapper/ptrace.c
+++ b/wrapper/ptrace.c
@@ -1,4 +1,6 @@
-/* Copyright (C) 2017 Jakob Kreuze, All Rights Reserved.
+/* ptrace.c - Wrappers for the ptrace system call.
+
+ Copyright (C) 2017 Jakob Kreuze, All Rights Reserved.
This file is part of Hypodermic.