def execute(cmd_tokens, syscall_filters): with open(HISTORY_PATH, 'a') as history_file: history_file.write(' '.join(cmd_tokens) + os.linesep) if cmd_tokens: # Extract command name and arguments from tokens cmd_name = cmd_tokens[0] cmd_args = cmd_tokens[1:] DIRFD_ARGUMENTS.clear() SYSCALL_ARG_DICT.clear() ARGUMENT_CALLBACK.clear() # If the command is a built-in command, # invoke its function with arguments if cmd_name in built_in_cmds: return built_in_cmds[cmd_name](cmd_args) # Wait for a kill signal signal.signal(signal.SIGINT, handler_kill) try: # Spawn a child process cmd_tokens[0] = locateProgram(cmd_tokens[0]) pid = createChild(cmd_tokens, False) except Exception as error: print("Error %s executing %s" % (error, cmd_name)) return 1 debugger = ptrace.debugger.PtraceDebugger() debugger.traceFork() debugger.traceExec() process = debugger.addProcess(pid, True) process.syscall() snapshots = None try: snapshots, exit_code = debug_process(debugger, syscall_filters) if exit_code != 0: print('Command unsuccessful - rollbacking changes') snapshots.rollback_all() except Exception as error: print("Error tracing process: %s." % error) return SHELL_STATUS_STOP except KeyboardInterrupt: print("%s terminated by keyboard interrupt." % cmd_name) return SHELL_STATUS_STOP finally: # Cut down all processes no matter what happens # to prevent them from doing any damage debugger.quit() if snapshots is not None: snapshots.clean() # Return status indicating to wait for next command in shell_loop return SHELL_STATUS_RUN
def debugger_example(pid): debugger = ptrace.debugger.PtraceDebugger() print("Attach the running process %s" % pid) process = debugger.addProcess(pid, False) print("syscall()") # ptrace_syscall(pid) # syscall_options = FunctionCallOptions( # write_types=True, # write_argname=True, # string_max_length=300, # replace_socketcall=False, # write_address=True, # max_array_count=20, # ) # state = process.syscall_state # syscall = state.event(syscall_options) # if syscall and (syscall.result is not None): # self.displaySyscall(syscall) for i in range(5): # Break at next syscall # process.syscall() # event = process.waitSyscall() event = debugger.waitProcessEvent() # event = process.waitSignals() # event = process.waitSignals(signal.SIGTRAP) print(event) regs = process.getregs() print("rax = {}".format(ctypes.c_long(regs.rax).value)) print("rdi = {:#x}".format(regs.rdi)) print("rsi = {:#x}".format(regs.rsi)) print("rdx = {:#x}".format(regs.rdx)) process.cont() ip = process.getInstrPointer() print("ip = {:#x}".format(ip)) # res = process.getregs() # print(regs) print("detach()") process.detach() debugger.quit() print("="*8)
def run(self): debugger = debug.SyscallDebugger() # Run entities and collect syscalls. self.prepare() try: log.info("\n*** {} / {} ***\n".format(self.testcase.name, self.name)) try: self.server = self.start(debugger, "server") debugger.set_timeout(35) debugger.wait(self.server, "listen") debugger.set_timeout(5) debugger.wait(self.server, "listen") except debug.Timeout: self.error("Server timeout occured.") try: self.client = self.start(debugger, "client") debugger.set_timeout(20) debugger.wait(self.client) except debug.Timeout: self.error("Client timeout occured.") except BaseException as error: self.error("Python exception {} occured: {}".format(type(error), error)) raise finally: debugger.quit() self.cleanup() self.events = debugger.events del debugger # Process collected events. for event in self.events: if isinstance(event, ptrace.debugger.process_event.ProcessExit): if event.exitcode != self.expected_exitcodes[event.origin]: self.error("Unexpected {} exit code {}.".format(event.origin, event.exitcode)) if event.process == self.server: log.debug("Server exit code is {}.".format(event.exitcode)) if event.process == self.client: log.debug("Client exit code is {}.".format(event.exitcode)) elif event.name == 'listen': if event.origin != 'server': continue self.listeners.append(event.socket) elif event.name == 'connect': if event.origin != 'client': continue if event.socket.domain.value not in (socket.AF_INET, socket.AF_INET6): continue if re.search(" sin6?_port=0, ", event.arguments[1].text): continue conn = event.socket conn.attempted = event.time conn.status = event.result conn.nonblocking = conn.status == errno.EINPROGRESS conn.shutdown = False conn.closed = None self.connections.append(conn) elif event.name == 'getsockopt': if event.origin != 'client': continue if event.arguments[1].value != socket.SOL_SOCKET: continue if event.arguments[2].value != socket.SO_ERROR: continue event.socket.status = event.arguments[3].value elif event.name == 'shutdown' and event.result == 0: event.socket.shutdown = True elif event.name == 'close' and event.result == 0: event.socket.closed = event.time # Postprocess acquired data. self.postprocess()
#!/usr/bin/python3 import subprocess import os import ptrace.debugger import containers containers.pivot_temporary_overlay() containers.netns_with_veth() command = ["ping", "-n", "192.168.0.2"] debugger = ptrace.debugger.PtraceDebugger() process = debugger.addProcess( ptrace.debugger.child.createChild(command, False), True) while True: process.syscall() event = debugger.waitProcessEvent() if isinstance(event, ptrace.debugger.ProcessExit): break elif isinstance(event, ptrace.debugger.ProcessSignal): #print(event.signum) #print(event.name) print( process.syscall_state.event( ptrace.func_call.FunctionCallOptions())) debugger.quit()
def main(): signal.signal(signal.SIGINT, sigint_handler) if len(sys.argv) < 2: logging.error('Usage: %s TARGET_PID' % sys.argv[0]) sys.exit(1) try: pid = int(sys.argv[1]) except: logging.error('Wrong PID: %s' % sys.argv[1]) sys.exit(1) logging.debug("Attach the running process %s" % pid) debugger = ptrace.debugger.PtraceDebugger() process = debugger.addProcess(pid, False) while not stop_script: try: process.syscall() time.sleep(0.001) regs = process.getregs() syscall_num = regs.orig_rax if syscall_num == 45 or syscall_num == 44: fd = regs.rdi buff = regs.rsi bufflen = regs.rdx logging.debug("%s(%d, 0x%x, %d)" % (syscall_names[syscall_num], fd, buff, bufflen)) if syscall_num == 44: x = process.readBytes(buff, bufflen) logging.debug('SEND: %s' % x.encode('hex')) packet = vboxmanage.ipc_unserialize(x) logging.info(packet) process.syscall() time.sleep(0.001) regs = process.getregs() ret = regs.rax if syscall_num == 45 or syscall_num == 44: logging.debug(" = %d" % (ret)) if syscall_num == 45: x = process.readBytes(buff, ret) logging.debug('RECV: %s' % x.encode('hex')) packet = vboxmanage.ipc_unserialize(x) logging.info(packet) except Exception as e: pass process.detach() debugger.quit()
def main(args): root.get_root() # Get parameters from args pid = args.pid patch_path = os.path.abspath(args.patch) # print(patch_path) # Calculating base address shell_base = 0 main_base = 0 proc_map_filename = "/proc/%d/maps" % pid try: fmap = open(proc_map_filename) except IOError as e: print("Couldn't open process map file (%s)!" % e) try: lines = fmap.readlines() except e: print(e) exit(-1) is_first = True lib_installation_path = "/usr/lib/" str_tiger = "libtfix.so" # TODO: 无链接则拒绝 for line in lines: if is_first: end = line.find('-') str_base = line[0:end] main_base = int(str_base, base=16) is_first = False else: it = line.find(str_tiger) if (it != -1): end = line.find('-') str_base = line[0:end] shell_base = int(str_base, base=16) break # x86-64 # nm /usr/lib/libtfix.so | grep do_fix_entry a = open(os.path.join(lib_installation_path, str_tiger), 'rb') elffile_tfix = ef.ELFFile(a) elffile_sym = elffile_tfix.get_section_by_name('.symtab') symbol_name = [x.name for x in elffile_sym.iter_symbols()] if "do_fix_entry" in symbol_name: for x in elffile_sym.iter_symbols(): if x.name == "do_fix_entry": temp_address = x.entry['st_value'] else: raise NameError("do_fix_entry not found") do_fix_entry = shell_base + temp_address # initialize debugger debugger = ptrace.debugger.PtraceDebugger() # attach the running process (pid) process = debugger.addProcess(pid, False) # next syscall # print("wait a syscall") ENOSYS = 38 while True: process.syscall() wait_stopped(pid) # process.waitSignals(signal.SIGSTOP) eax = process.getreg('eax') if eax != -ENOSYS: # if not invalid syscall break # save status old_regs = process.getregs() # set regs new_regs = process.getregs() if platform.architecture()[0] == "64bit": # 64 bit new_regs.rip = do_fix_entry new_regs.rsp = int((new_regs.rsp / 32)) * 32 process.writeBytes(new_regs.rsp - 4096, patch_path.encode()) process.writeBytes(new_regs.rsp - 64, str(main_base).encode()) new_regs.rsp -= 4096 new_regs.rdi = new_regs.rsp new_regs.rbp = new_regs.rsp elif platform.architecture()[0] == "32bit": # 32 bit new_regs.eip = do_fix_entry new_regs.esp = int((new_regs.esp / 32)) * 32 process.writeBytes(new_regs.esp - 4096, patch_path.encode()) process.writeBytes(new_regs.esp - 64, str(main_base).encode()) new_regs.esp -= 4096 new_regs.ebp = new_regs.esp else: raise SystemError("Unsupported architecture\n") # set new regs process.setregs(new_regs) process.cont() # print("wait a trap") # process.waitSignals(signal.SIGTRAP, signal.SIGSTOP) wait_trap(pid) # restore old regs process.setregs(old_regs) # detach and quit process.detach() debugger.quit()
def run(self): # this import is here to be able to run the client_server.py to anything except running tests also without # installed dependencies. To generate SRPM one has to run the client_server.py and it tracebacks without ptrace from . import debug import ptrace.debugger debugger = debug.SyscallDebugger() # Run entities and collect syscalls. self.prepare() try: logger.info("\n*** {} / {} ***\n".format(self.testcase.name, self.name)) try: self.server = self.start(debugger, "server") debugger.set_timeout(35) debugger.wait(self.server, "listen") debugger.set_timeout(5) debugger.wait(self.server, "listen") except debug.Timeout: self.error("Server timeout occured.") try: self.client = self.start(debugger, "client") debugger.set_timeout(20) debugger.wait(self.client) except debug.Timeout: self.error("Client timeout occured.") except BaseException as error: self.error("Python exception {} occured: {}".format( type(error), error)) raise finally: debugger.quit() self.cleanup() self.events = debugger.events del debugger # Process collected events. for event in self.events: if isinstance(event, ptrace.debugger.process_event.ProcessExit): if event.exitcode != self.expected_exitcodes[event.origin]: self.error("Unexpected {} exit code {}.".format( event.origin, event.exitcode)) if event.process == self.server: logger.debug("Server exit code is {}.".format( event.exitcode)) if event.process == self.client: logger.debug("Client exit code is {}.".format( event.exitcode)) elif event.name == 'listen': if event.origin != 'server': continue logger.info( "Server starts listening on family {} socktype {}.".format( event.socket.domain, event.socket.socktype)) self.listeners.append(event.socket) elif event.name == 'connect': if event.origin != 'client': continue if event.socket.domain.value not in (socket.AF_INET, socket.AF_INET6): continue if event.socket.socktype.value not in [ listener.socktype.value for listener in self.listeners ]: continue if re.search(" sin6?_port=0, ", event.arguments[1].text): continue conn = event.socket conn.attempted = event.time conn.status = event.result conn.nonblocking = conn.status == errno.EINPROGRESS conn.shutdown = False conn.closed = None self.connections.append(conn) elif event.name == 'getsockopt': if event.origin != 'client': continue if event.arguments[1].value != socket.SOL_SOCKET: continue if event.arguments[2].value != socket.SO_ERROR: continue event.socket.status = event.arguments[3].value elif event.name == 'shutdown' and event.result == 0: if event.socket: event.socket.shutdown = True elif event.name == 'close' and event.result == 0: event.socket.closed = event.time # Postprocess acquired data. self.postprocess()