From 8b232076240dc7e6f8abdfca3d1634ae065c691b Mon Sep 17 00:00:00 2001
From: Jakob
Date: Fri, 1 Sep 2017 16:40:01 -0400
Subject: Process.rtld now returns the base region of the RTLD.
---
README.md | 38 ++++++++-------
hypodermic/main.py | 6 +--
hypodermic/process.py | 126 ++++++++++++++++++++++++++++++++++++++++++++++++
hypodermic/ptrace.py | 129 --------------------------------------------------
4 files changed, 150 insertions(+), 149 deletions(-)
create mode 100644 hypodermic/process.py
delete mode 100644 hypodermic/ptrace.py
diff --git a/README.md b/README.md
index a14d08b..94582fb 100644
--- a/README.md
+++ b/README.md
@@ -14,11 +14,14 @@ redirected. There have been a few attempts at this in the past, such as
This is oftentimes unsuccessful, being very dependent upon how glibc was
compiled.
-The goal of Hypodermic is to find a means of injecting a dynamic library into
-any Linux executable, even ones that are statically-linked, and tranferring this
-method over to [PINCE][2] when it is stable enough.
+The point of Hypodermic is to find a means of injecting a dynamic library into
+any Linux executable, even ones that are statically-linked, and transferring
+this method over to [PINCE][2] when it is stable enough. The current goal is the
+ability to inject an internal cheat into Counter-Strike: Global Offensive, such
+as [AimTux][3]. This will signal that the method has reached a point of
+viability.
-Hypodermic is free software, licensed under the [GNU General Public License.][3]
+Hypodermic is free software, licensed under the [GNU General Public License.][4]
## Current Attempts
@@ -37,20 +40,21 @@ stack in an attempt to trick the RTLD.
## Important Resources
-* [Understanding Linux ELF RTLD internals][4]
-* [Runtime Process Infection][5]
-* [ELF Program Header][6]
-* [Dynamic Loader Operation][7]
-* [About ELF Auxiliary Vectors][8]
-* [Code Injection into Running Linux Application][9]
+* [Understanding Linux ELF RTLD internals][5]
+* [Runtime Process Infection][6]
+* [ELF Program Header][7]
+* [Dynamic Loader Operation][8]
+* [About ELF Auxiliary Vectors][9]
+* [Code Injection into Running Linux Application][10]
[1]: https://github.com/gaffe23/linux-inject
[2]: https://github.com/korcankaraokcu/PINCE
-[3]: https://www.gnu.org/licenses/gpl.html
-[4]: http://s.eresi-project.org/inc/articles/elf-rtld.txt
-[5]: http://phrack.org/issues/59/8.html
-[6]: http://www.sco.com/developers/gabi/latest/ch5.pheader.html
-[7]: https://sourceware.org/glibc/wiki/DynamicLoader
-[8]: http://articles.manugarg.com/aboutelfauxiliaryvectors
-[9]: https://www.codeproject.com/Articles/33340/Code-Injection-into-Running-Linux-Application
+[3]: https://github.com/AimTuxOfficial/AimTux/
+[4]: https://www.gnu.org/licenses/gpl.html
+[5]: http://s.eresi-project.org/inc/articles/elf-rtld.txt
+[6]: http://phrack.org/issues/59/8.html
+[7]: http://www.sco.com/developers/gabi/latest/ch5.pheader.html
+[8]: https://sourceware.org/glibc/wiki/DynamicLoader
+[9]: http://articles.manugarg.com/aboutelfauxiliaryvectors
+[10]: https://www.codeproject.com/Articles/33340/Code-Injection-into-Running-Linux-Application
diff --git a/hypodermic/main.py b/hypodermic/main.py
index 635e3a7..74c4486 100644
--- a/hypodermic/main.py
+++ b/hypodermic/main.py
@@ -21,7 +21,7 @@ import argparse
import sys
import textwrap
-from hypodermic.ptrace import Process
+from hypodermic.process import Process
class CustomHelp(argparse.HelpFormatter):
@@ -106,8 +106,8 @@ def main():
sys.exit(1)
if args.create:
- alert("Creating process at path {}".format(args.create))
+ alert("Creating process at path '{}'...".format(args.create))
p = Process(path=args.create)
else:
- alert("Attaching to process with pid {}".format(args.attach))
+ alert("Attaching to process with pid {}...".format(args.attach))
p = Process(pid=args.attach)
diff --git a/hypodermic/process.py b/hypodermic/process.py
new file mode 100644
index 0000000..6fc1519
--- /dev/null
+++ b/hypodermic/process.py
@@ -0,0 +1,126 @@
+# 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 .
+
+"""ctypes wrapper for ptrace."""
+
+import ctypes
+import os.path
+import re
+
+from hypodermic.memory import Region, maps
+
+
+class Process(object):
+ """Process attached via ptrace.
+
+ Note:
+ The process is implicitly detached from upon destruction of this
+ object, if appropriate.
+
+ Args:
+ pid (:obj:`int`, optional): The pid of the process to attach to.
+ 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 as the target if a pid is not
+ specified, either.
+
+ Raises:
+ 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, if the process could
+ not be created for the given binary, or if any wrapper
+ libraries could not be loaded.
+ """
+
+ def __init__(self, pid=0, path=""):
+ if not isinstance(pid, int):
+ raise TypeError("pid argument must be an int")
+ elif not isinstance(path, str):
+ raise TypeError("path argument must be a string")
+ self._load_ffi_methods()
+
+ if pid != 0:
+ self._is_parent = False
+ if self._attach(ctypes.c_int(pid)):
+ raise OSError("Could not attach to pid {}".format(pid))
+ else:
+ self._is_parent = True
+ self.pid = self._new_proc(ctypes.c_char_p(path.encode()))
+ 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):
+ # setuptools/cython hack.
+ script_path = os.path.abspath(os.path.dirname(__file__))
+
+ for filename in os.listdir(os.path.join(script_path, "..")):
+ if filename.startswith("libhypodermicw"):
+ lib_path = os.path.join(script_path, "..", filename)
+ break
+ else:
+ raise OSError("Could not find wrapper library.")
+
+ self._so = ctypes.cdll.LoadLibrary(lib_path)
+ self._new_proc = self._so.new_proc
+ self._attach = self._so.attach
+ self._detach = self._so.detach
+ self._cont = self._so.cont
+
+ def detach(self):
+ """Explicitly detaches from the process.
+
+ Raises:
+ OSError: If the process cannot be detached from.
+ """
+ if not self._is_parent and self._detach(ctypes.c_int(self.pid)):
+ raise OSError("Could not detach from pid {}".format(self.pid))
+
+ def cont(self):
+ """Continues until the program is haulted.
+
+ Raises:
+ OSError: If the process cannot be continued.
+ """
+ if self._cont(ctypes.c_int(self.pid)):
+ raise OSError("Could not continue")
+
+ @property
+ def maps(self) -> list:
+ """Obtain the process' memory map.
+
+ Returns:
+ A list of Region objects.
+ """
+ return maps(self.pid)
+
+ @property
+ def rtld(self) -> Region:
+ """Obtain the base region of memory for the process' RTLD, if it
+ exists.
+
+ Returns:
+ The Region object belonging to the RTLD, or None if no
+ RTLD was found.
+ """
+ for region in self.maps:
+ if re.search(r"ld.+\.so", region.path) and region.off == 0:
+ return region
diff --git a/hypodermic/ptrace.py b/hypodermic/ptrace.py
deleted file mode 100644
index 714b567..0000000
--- a/hypodermic/ptrace.py
+++ /dev/null
@@ -1,129 +0,0 @@
-# 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 .
-
-"""ctypes wrapper for ptrace."""
-
-import ctypes
-import os.path
-import re
-
-from hypodermic.memory import Region, maps
-
-
-class Process(object):
- """Process attached via ptrace.
-
- Note:
- The process is implicitly detached from upon destruction of this
- object, if appropriate.
-
- Args:
- pid (:obj:`int`, optional): The pid of the process to attach to.
- 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 as the target if a pid is not
- specified, either.
-
- Raises:
- 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, if the process could
- not be created for the given binary, or if any wrapper
- libraries could not be loaded.
- """
-
- def __init__(self, pid=0, path=""):
- if not isinstance(pid, int):
- raise TypeError("pid argument must be an int")
- elif not isinstance(path, str):
- raise TypeError("path argument must be a string")
- self._load_ffi_methods()
-
- if pid != 0:
- self._is_parent = False
- if self._attach(ctypes.c_int(pid)):
- raise OSError("Could not attach to pid {}".format(pid))
- else:
- self._is_parent = True
- self.pid = self._new_proc(ctypes.c_char_p(path.encode()))
- 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):
- # setuptools/cython hack.
- script_path = os.path.abspath(os.path.dirname(__file__))
-
- for filename in os.listdir(os.path.join(script_path, "..")):
- if filename.startswith("libhypodermicw"):
- lib_path = os.path.join(script_path, "..", filename)
- break
- else:
- raise OSError("Could not find wrapper library.")
-
- self._so = ctypes.cdll.LoadLibrary(lib_path)
- self._new_proc = self._so.new_proc
- self._attach = self._so.attach
- self._detach = self._so.detach
- self._cont = self._so.cont
-
- def detach(self):
- """Explicitly detaches from the process.
-
- Raises:
- OSError: If the process cannot be detached from.
- """
- if not self._is_parent and self._detach(ctypes.c_int(self.pid)):
- raise OSError("Could not detach from pid {}".format(self.pid))
-
- def cont(self):
- """Continues until the program is haulted.
-
- Raises:
- OSError: If the process cannot be continued.
- """
- if self._cont(ctypes.c_int(self.pid)):
- raise OSError("Could not continue")
-
- @property
- def maps(self) -> list:
- """Obtain the process' memory map.
-
- Returns:
- A list of Region objects.
- """
- return maps(self.pid)
-
- # FIXME: This approach does not work outside of seeing if the
- # process has an RTLD page. The reality is that the RTLD is
- # broken up into independent several pages.
- @property
- def rtld(self) -> Region:
- """Obtain the region of memory for the process' RTLD, if it
- exists.
-
- Returns:
- The Region object belonging to the RTLD, or None if no
- RTLD was found.
- """
- for region in self.maps:
- if re.search(r"ld.+\.so", region.path):
- return region
--
cgit v1.3