From 81e47a4dba4a44624ec56708c1655206ae19cbfc Mon Sep 17 00:00:00 2001 From: jakob Date: Sat, 9 Sep 2017 15:41:20 -0400 Subject: Implemented more syscall wrappers. --- hypodermic/process.py | 90 ++++++++++++++++++++++++++++++++++++++++++++++--- hypodermic/shellcode.py | 85 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 169 insertions(+), 6 deletions(-) (limited to 'hypodermic') diff --git a/hypodermic/process.py b/hypodermic/process.py index c2c7409..e26978b 100644 --- a/hypodermic/process.py +++ b/hypodermic/process.py @@ -361,10 +361,95 @@ class Process(object): fd = self.get_register("eax") self.set_register("eax", old_eax) + # FIXME: fd is parsed as a ctypes.c_ulonglong... if fd < 0: raise OSError("Couldn't open {}".format(path)) return fd + def close(self, fd: int): + """Attempts to close a file descriptor within the inferior. + + Args: + fd (int): The file descriptor to close. + """ + if self.arch == "x64": + self.run_code(close_shellcode(fd)) + else: + self.run_code(close_shellcode(fd, arch="i386")) + + def mmap(self, addr=0, size=0, prot=0, flags=0, fd=-1, off=0) -> int: + """Introduce a new mapping to the process' address space. + + Args: + addr (:obj:`int`, optional): The address, or 0 if + unimportant. + size (:obj:`int`, optional): The desired size of the + mapping. + prot (:obj:`int`, optional): The protections for the + mapping. + flags (:obj:`int`, optional): Any other flags for the + mapping. + fd (:obj:`int`, optional): A file descriptor to map. + off (:obj:`int`, optional): An offset in the file + descriptor. + + Raises: + OSError: If the mapping cannot be made. + + Returns: + The address the mapping was made at. + """ + if self.arch == "x64": + old_rax = self.get_register("rax") + self.run_code(mmap_shellcode(addr, size, prot, flags, fd, off, path), + preserve=["rax"]) + res = self.get_register("rax") + self.set_register("rax", old_rax) + else: + old_eax = self.get_register("eax") + self.run_code(mmap_shellcode(addr, size, prot, flags, fd, off, path, + arch="i386"), preserve=["eax"]) + res = self.get_register("eax") + self.set_register("eax", old_eax) + + # FIXME: fd is parsed as a ctypes.c_ulonglong... + if res == -1: + raise OSError("Couldn't complete mapping.") + return res + + def munmap(self, addr=0, size=0): + """Removes a mapping from the process' address space. + + Args: + addr (:obj:`int`, optional): The address, or 0 if + unimportant. + size (:obj:`int`, optional): The desired size of the + mapping. + Raises: + OSError: If the mapping cannot be made. + + Returns: + The address the mapping was made at. + """ + if self.arch == "x64": + self.run_code(munmap_shellcode(addr, size)) + else: + self.run_code(munmap_shellcode(addr, size, arch="i386")) + + def page_start(self, addr: int) -> int: + return addr & ~(self.page_size - 1) + + def page_offset(self, addr: int) -> int: + return addr & (self.page_size - 1) + + def page_align(self, addr: int) -> int: + return (addr + self.page_size - 1) & ~(self.page_size - 1) + + # FIXME: Not tested on i386. + @property + def page_size(self) -> int: + return 4096 + @property def arch(self) -> str: """Returns the architecture of the host processor. @@ -381,11 +466,6 @@ class Process(object): """ return "x64" if self._isamd64 else "x86" - # FIXME: Not tested on i386. - @property - def page_size(self) -> int: - return 4096 - @property def maps(self) -> list: """Obtain the process' memory map. diff --git a/hypodermic/shellcode.py b/hypodermic/shellcode.py index 75ab4ad..ceaf7a7 100644 --- a/hypodermic/shellcode.py +++ b/hypodermic/shellcode.py @@ -74,8 +74,91 @@ def open_shellcode(path: str, flags=0, arch="amd64") -> bytes: " movl $0x05, %eax;" \ " call $. + 5;" \ " popl %ebx;" \ - " subl $. - 4 - __path, %ebx;" + " subl $. - 4 - __path, %ebx;" \ " movl ${}, %ecx;" \ " movl $0x00, %edx;" \ " int $0x80;".format(path, flags) return assemble(asm, arch) + + +def close_shellcode(fd: int, arch="amd64") -> bytes: + """Generates shellcode to close a file descriptor. + + Args: + fd (int): The file descriptor to close. + arch (:obj:`str`, optional): The target architecture. + Defaults to "amd64". + + Returns: + The assembled shellcode, as a `bytes` object. + """ + if arch == "amd64": + asm = " movq $0x03, %rax;" \ + " movq ${}, %rdi;" \ + " syscall;".format(fd) + else: + asm = " movq $0x06, %eax;" \ + " movq ${}, %ebx;" \ + " int $0x80;;".format(fd) + return assemble(asm, arch) + + +# FIXME: Syscall number may be incorrect for i386. +def mmap_shellcode(addr=0, size=0, prot=0, flags=0, fd=-1, off=0, arch="amd64"): + """Generates shellcode to map a region of memory. + + Args: + addr (:obj:`int`, optional): The address, or 0 if unimportant. + size (:obj:`int`, optional): The desired size of the mapping. + prot (:obj:`int`, optional): The protections for the mapping. + flags (:obj:`int`, optional): Any other flags for the mapping. + fd (:obj:`int`, optional): A file descriptor to map. + off (:obj:`int`, optional): An offset in the file descriptor. + arch (:obj:`str`, optional): The target architecture. + + Returns: + The assembled shellcode, as a `bytes` object. + """ + if arch == "amd64": + asm = " movq $0x09, %rax;" \ + " movq ${}, %rdi;" \ + " movq ${}, %rsi;" \ + " movq ${}, %rdx;" \ + " movq ${}, %r10;" \ + " movq ${}, %r8;" \ + " movq ${}, %r9;" \ + " syscall;".format(addr, size, prot, flags, fd, off) + else: + asm = " movl $0x5a, %eax;" \ + " movl ${}, %ebx;" \ + " movl ${}, %ecx;" \ + " movl ${}, %edx;" \ + " movl ${}, %esi;" \ + " movl ${}, %edi;" \ + " movl ${}, %ebp;" \ + " int $0x80;".format(addr, size, prot, flags, fd, off) + return assemble(asm, arch) + + +def munmap_shellcode(addr=0, size=0, arch="amd64"): + """Generates shellcode to map a region of memory. + + Args: + addr (:obj:`int`, optional): The address of the mapping. + size (:obj:`int`, optional): The size of the mapping. + arch (:obj:`str`, optional): The target architecture. + + Returns: + The assembled shellcode, as a `bytes` object. + """ + if arch == "amd64": + asm = " movq $0x0b, %rax;" \ + " movq ${}, %rdi;" \ + " movq ${}, %rsi;" \ + " syscall;".format(addr, size) + else: + asm = " movl $0x5b, %eax;" \ + " movl ${}, %ebx;" \ + " movl ${}, %ecx;" \ + " int $0x80;".format(addr, size) + return assemble(asm, arch) -- cgit v1.3