summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md2
-rw-r--r--hypodermic/process.py29
-rw-r--r--hypodermic/shellcode.py40
3 files changed, 70 insertions, 1 deletions
diff --git a/README.md b/README.md
index 94582fb..417aa3e 100644
--- a/README.md
+++ b/README.md
@@ -46,6 +46,7 @@ stack in an attempt to trick the RTLD.
* [Dynamic Loader Operation][8]
* [About ELF Auxiliary Vectors][9]
* [Code Injection into Running Linux Application][10]
+* [Special Sections][11]
[1]: https://github.com/gaffe23/linux-inject
@@ -58,3 +59,4 @@ stack in an attempt to trick the RTLD.
[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
+[11]: http://refspecs.linuxbase.org/LSB_3.0.0/LSB-PDA/LSB-PDA/specialsections.html
diff --git a/hypodermic/process.py b/hypodermic/process.py
index 1e2c1d4..bfb1013 100644
--- a/hypodermic/process.py
+++ b/hypodermic/process.py
@@ -22,7 +22,7 @@ import os.path
import re
from hypodermic.memory import Region, maps
-from hypodermic.shellcode import assemble
+from hypodermic.shellcode import assemble, open_shellcode
_AMD64_INDICES = {
"r15": 0,
@@ -338,6 +338,33 @@ class Process(object):
after = [self.get_register(reg) for reg in preserve]
return before, after
+ def open(self, path: str) -> int:
+ """Attempts to open a file descriptor within the inferior.
+
+ Args:
+ path (str): The path of the file to open.
+
+ Raises:
+ OSError: If the path cannot be opened.
+
+ Returns:
+ The file descriptor.
+ """
+ if self.arch == "x64":
+ old_rax = self.get_register("rax")
+ self.run_code(open_shellcode(path), preserve=["rax"])
+ fd = self.get_register("rax")
+ self.set_register("rax", old_rax)
+ else:
+ old_eax = self.get_register("eax")
+ self.run_code(open_shellcode(path, arch="i386"), preserve=["eax"])
+ fd = self.get_register("eax")
+ self.set_register("eax", old_eax)
+
+ if fd < 0:
+ raise OSError("Couldn't open {}".format(path))
+ return fd
+
@property
def arch(self) -> str:
"""Returns the architecture of the host processor.
diff --git a/hypodermic/shellcode.py b/hypodermic/shellcode.py
index 0a35e0a..75ab4ad 100644
--- a/hypodermic/shellcode.py
+++ b/hypodermic/shellcode.py
@@ -39,3 +39,43 @@ def assemble(code: str, arch="amd64", syntax="att") -> bytes:
ks.syntax = keystone.KS_OPT_SYNTAX_ATT
encoded, _ = ks.asm(code)
return bytes(encoded)
+
+
+# FIXME: Relative addressing is untested in i386.
+def open_shellcode(path: str, flags=0, arch="amd64") -> bytes:
+ """Generates shellcode to open a file descriptor.
+
+ Args:
+ path (str): The path of the file to open.
+ flags (:obj:`int`, optional): Flags to pass to open. Defaults to
+ O_RDONLY.
+ arch (:obj:`str`, optional): The target architecture.
+ Defaults to "amd64".
+
+ Returns:
+ The assembled shellcode, as a `bytes` object.
+ """
+ if arch == "amd64":
+ asm = " jmp __path_end;" \
+ "__path:" \
+ " .asciz \"{}\";" \
+ "__path_end:" \
+ " movq $0x02, %rax;" \
+ " leaq (%rip), %rdi;" \
+ " subq $. - __path, %rdi;" \
+ " movq ${}, %rsi;" \
+ " movq $0x00, %rdx;" \
+ " syscall;".format(path, flags)
+ else:
+ asm = " jmp __path_end;" \
+ "__path:" \
+ " .asciz \"{}\";" \
+ "__path_end:" \
+ " movl $0x05, %eax;" \
+ " call $. + 5;" \
+ " popl %ebx;" \
+ " subl $. - 4 - __path, %ebx;"
+ " movl ${}, %ecx;" \
+ " movl $0x00, %edx;" \
+ " int $0x80;".format(path, flags)
+ return assemble(asm, arch)