summaryrefslogtreecommitdiff
path: root/hypodermic
diff options
context:
space:
mode:
Diffstat (limited to 'hypodermic')
-rw-r--r--hypodermic/process.py29
-rw-r--r--hypodermic/shellcode.py40
2 files changed, 68 insertions, 1 deletions
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)