From 26c1ba09d4ae16e702210eb869baffb726d9845b Mon Sep 17 00:00:00 2001 From: Roi Martin Date: Tue, 29 May 2018 17:01:40 +0200 Subject: [PATCH 1/8] Initial implementation of RAP protocol --- pyrebox/ipython_shell.py | 32 ++++++ pyrebox/r2.py | 211 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 243 insertions(+) create mode 100644 pyrebox/r2.py diff --git a/pyrebox/ipython_shell.py b/pyrebox/ipython_shell.py index 6f98f8ce..5513371c 100644 --- a/pyrebox/ipython_shell.py +++ b/pyrebox/ipython_shell.py @@ -59,6 +59,7 @@ import api from cpus import X86CPU from cpus import X64CPU +from r2 import RapServer from utils import ConfigurationManager as conf_m from utils import pp_print from utils import pp_debug @@ -1594,6 +1595,7 @@ def list_commands(self, line): unmon - Stop monitoring process savevm - Save vm status loadvm - Load vm status + rap - Start a radare2 RAP server quit - Exit this prompt q - Exit this prompt cont - Exit this prompt @@ -1732,6 +1734,36 @@ def custom(self, line): args = " ".join(elements[1:]) run_custom_command(cmd, args) + @line_magic + def rap(self, line): + ''' + Start a radare2 RAP server + Usage: rap :1234 - start a RAP server listening on localhost:1234 + rap 0.0.0.0:1234 - start a RAP server listening on 0.0.0.0:1234 + ''' + + elements = line.split(":") + if len(elements) != 2: + self.do_help("rap") + return + + rap_host = elements[0] + rap_port = int(elements[1]) + + if rap_host == "": + rap_host = "localhost" + + try: + rs = RapServer(rap_host, rap_port) + + pp_print("RAP server listening on {}:{}\n".format(rap_host, rap_port)) + rs.serve_forever() + except KeyboardInterrupt: + pp_print("Killing RAP server\n") + rs.shutdown() + except Exception as ex: + pp_error("RAP server error: {}\n".format(ex)) + class CustomCommand(IPyAutocall): rewrite = False diff --git a/pyrebox/r2.py b/pyrebox/r2.py new file mode 100644 index 00000000..edb03e0f --- /dev/null +++ b/pyrebox/r2.py @@ -0,0 +1,211 @@ +import SocketServer +import struct + +import api +from utils import find_procs +from utils import pp_print +from utils import pp_debug +from utils import pp_warning +from utils import pp_error + +class BaseRapHandler(SocketServer.BaseRequestHandler): + def handle(self): + while True: + try: + self.handle_packet() + except EOFError: + pp_debug("Closed connection\n") + break + except Exception as e: + pp_error("Protocol error: {}\n".format(e)) + break + + def handle_packet(self): + buf = self.request.recv(1) + + if len(buf) == 0: + raise EOFError + + packet_type = ord(buf) + + if packet_type == RapServer.RAP_OPEN: + buf = self.request.recv(2) + (flags, size) = struct.unpack(">BB", buf) + name = self.request.recv(size) + fd = self.rap_open(name, flags) + buf = struct.pack(">BI", RapServer.RAP_OPEN|RapServer.RAP_REPLY, fd) + self.request.sendall(buf) + + elif packet_type == RapServer.RAP_READ: + buf = self.request.recv(4) + (size,) = struct.unpack(">I", buf) + ret = self.rap_read(size) + buf = struct.pack(">BI", RapServer.RAP_READ|RapServer.RAP_REPLY, len(ret)) + self.request.sendall(buf + ret) + + elif packet_type == RapServer.RAP_WRITE: + buf = self.request.recv(4) + (size,) = struct.unpack(">I", buf) + buf = self.request.recv(size) + ret = self.rap_write(buf) + buf = struct.pack(">BI", RapServer.RAP_WRITE|RapServer.RAP_REPLY, ret) + self.request.sendall(buf) + + elif packet_type == RapServer.RAP_SEEK: + buf = self.request.recv(9) + (whence, offset) = struct.unpack(">BQ", buf) + ret = self.rap_seek(offset, whence) + buf = struct.pack(">BQ", RapServer.RAP_SEEK|RapServer.RAP_REPLY, ret) + self.request.sendall(buf) + + elif packet_type == RapServer.RAP_CLOSE: + buf = self.request.recv(4) + (fd,) = struct.unpack(">I", buf) + self.rap_close(fd) + buf = struct.pack(">B", RapServer.RAP_CLOSE|RapServer.RAP_REPLY) + self.request.sendall(buf) + + elif packet_type == RapServer.RAP_SYSTEM: + buf = self.request.recv(4) + (size,) = struct.unpack(">I", buf) + buf = self.request.recv(size) + ret = self.rap_system(buf) + buf = struct.pack(">BI", RapServer.RAP_SYSTEM|RapServer.RAP_REPLY, len(ret)) + self.request.sendall(buf + ret) + + elif packet_type == RapServer.RAP_CMD: + buf = self.request.recv(4) + (size,) = struct.unpack(">I", buf) + buf = self.request.recv(size) + ret = self.rap_cmd(buf) + buf = struct.pack(">BI", RapServer.RAP_CMD|RapServer.RAP_REPLY, len(ret)) + self.request.sendall(buf + ret) + + else: + raise "unknown RAP packet type" + + def rap_open(self, name, flags): + raise NotImplementedError + + def rap_read(self, size): + raise NotImplementedError + + def rap_write(self, data): + raise NotImplementedError + + def rap_seek(self, offset, whence): + raise NotImplementedError + + def rap_close(self, fd): + raise NotImplementedError + + def rap_system(self, cmd): + raise NotImplementedError + + def rap_cmd(self, cmd): + raise NotImplementedError + + +class DefaultRapHandler(BaseRapHandler): + def __init__(self, *args, **kwargs): + self.pid = 0 + self.pgd = 0 + self.pname = "" + self.base = 0 + self.size = 0 + self.curseek = 0 + + BaseRapHandler.__init__(self, *args, **kwargs) + + def rap_open(self, name, flags): + procs = find_procs(name) + if len(procs) == 0: + pp_warning("Process not found: {}\n".format(name)) + return 0 + + (self.pid, self.pgd, self.pname) = procs[0] + + module_list = api.get_module_list(self.pgd) + for m in module_list: + if m["name"] != self.pname: + continue + self.base = m["base"] + self.size = m["size"] + + pp_debug("Selecting name={} pid={} base={:#x} size={}\n".format( + self.pid, self.pname, self.base, self.size)) + + return 0 + + def rap_read(self, size): + try: + data = api.r_va(self.pgd, self.curseek, size) + except Exception: + pp_error("Cannot read memory at {:#x}\n".format(self.curseek)) + data = "" + + return data + + def rap_write(self, data): + try: + api.w_va(self.pgd, self.curseek, data, len(data)) + size = len(data) + except Exception: + pp_error("Cannot write memory at {:#x}\n".format(self.curseek)) + size = 0 + + return size + + def rap_seek(self, offset, whence): + if whence == RapServer.RAP_SEEK_SET: + self.curseek = offset + elif whence == RapServer.RAP_SEEK_CUR: + self.curseek = self.curseek + offset + elif whence == RapServer.RAP_SEEK_END: + self.curseek = self.base + self.size - offset + + return self.curseek + + def rap_close(self, fd): + self.pid = 0 + self.pgd = 0 + self.pname = "" + self.base = 0 + self.size = 0 + self.curseek = 0 + + def rap_system(self, cmd): + pp_debug("system not implemented\n") + return "" + + def rap_cmd(self, cmd): + pp_debug("cmd not implemented\n") + return "" + + +class RapServer(): + # Packet types + RAP_OPEN = 1 + RAP_READ = 2 + RAP_WRITE = 3 + RAP_SEEK = 4 + RAP_CLOSE = 5 + RAP_SYSTEM = 6 + RAP_CMD = 7 + RAP_REPLY = 0x80 + + # Seek whence + RAP_SEEK_SET = 0 + RAP_SEEK_CUR = 1 + RAP_SEEK_END = 2 + + + def __init__(self, host, port, handler_class=DefaultRapHandler): + self.server = SocketServer.TCPServer((host, port), handler_class) + + def serve_forever(self): + self.server.serve_forever() + + def shutdown(self): + self.server.shutdown() + self.server.server_close() From a32b41383ee02e536e6fb8836d904f9f9cd49843 Mon Sep 17 00:00:00 2001 From: Roi Martin Date: Tue, 29 May 2018 21:28:38 +0200 Subject: [PATCH 2/8] Allow proc selection by pid or name --- pyrebox/r2.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/pyrebox/r2.py b/pyrebox/r2.py index edb03e0f..d3cb5de3 100644 --- a/pyrebox/r2.py +++ b/pyrebox/r2.py @@ -118,13 +118,16 @@ def __init__(self, *args, **kwargs): BaseRapHandler.__init__(self, *args, **kwargs) def rap_open(self, name, flags): - procs = find_procs(name) - if len(procs) == 0: - pp_warning("Process not found: {}\n".format(name)) + for proc in api.get_process_list(): + if (name.isdigit() and int(name) == proc["pid"]) or (name in proc["name"]): + self.pid = proc["pid"] + self.pgd = proc["pgd"] + self.pname = proc["name"] + break + else: + pp_error("Process not found: {}\n".format(name)) return 0 - (self.pid, self.pgd, self.pname) = procs[0] - module_list = api.get_module_list(self.pgd) for m in module_list: if m["name"] != self.pname: @@ -133,7 +136,7 @@ def rap_open(self, name, flags): self.size = m["size"] pp_debug("Selecting name={} pid={} base={:#x} size={}\n".format( - self.pid, self.pname, self.base, self.size)) + self.pname, self.pid, self.base, self.size)) return 0 From d5fe8610cbbb13be40ec42ab7989a7f9c90793b1 Mon Sep 17 00:00:00 2001 From: Roi Martin Date: Wed, 30 May 2018 01:22:52 +0200 Subject: [PATCH 3/8] Remove upper limit on seek --- pyrebox/r2.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyrebox/r2.py b/pyrebox/r2.py index d3cb5de3..01833a44 100644 --- a/pyrebox/r2.py +++ b/pyrebox/r2.py @@ -8,6 +8,7 @@ from utils import pp_warning from utils import pp_error + class BaseRapHandler(SocketServer.BaseRequestHandler): def handle(self): while True: @@ -165,7 +166,7 @@ def rap_seek(self, offset, whence): elif whence == RapServer.RAP_SEEK_CUR: self.curseek = self.curseek + offset elif whence == RapServer.RAP_SEEK_END: - self.curseek = self.base + self.size - offset + self.curseek = ((1<<64) - 1) - offset return self.curseek From f71de817a22032b55af076387c40661a3d40e008 Mon Sep 17 00:00:00 2001 From: Roi Martin Date: Wed, 30 May 2018 12:01:12 +0200 Subject: [PATCH 4/8] Move rap to custom command --- pyrebox/ipython_shell.py | 31 ---------------- radare2/__init__.py | 0 pyrebox/r2.py => radare2/rap.py | 63 ++++++++++++++++++++++++++------- 3 files changed, 50 insertions(+), 44 deletions(-) create mode 100644 radare2/__init__.py rename pyrebox/r2.py => radare2/rap.py (79%) diff --git a/pyrebox/ipython_shell.py b/pyrebox/ipython_shell.py index 5513371c..99f63796 100644 --- a/pyrebox/ipython_shell.py +++ b/pyrebox/ipython_shell.py @@ -59,7 +59,6 @@ import api from cpus import X86CPU from cpus import X64CPU -from r2 import RapServer from utils import ConfigurationManager as conf_m from utils import pp_print from utils import pp_debug @@ -1734,36 +1733,6 @@ def custom(self, line): args = " ".join(elements[1:]) run_custom_command(cmd, args) - @line_magic - def rap(self, line): - ''' - Start a radare2 RAP server - Usage: rap :1234 - start a RAP server listening on localhost:1234 - rap 0.0.0.0:1234 - start a RAP server listening on 0.0.0.0:1234 - ''' - - elements = line.split(":") - if len(elements) != 2: - self.do_help("rap") - return - - rap_host = elements[0] - rap_port = int(elements[1]) - - if rap_host == "": - rap_host = "localhost" - - try: - rs = RapServer(rap_host, rap_port) - - pp_print("RAP server listening on {}:{}\n".format(rap_host, rap_port)) - rs.serve_forever() - except KeyboardInterrupt: - pp_print("Killing RAP server\n") - rs.shutdown() - except Exception as ex: - pp_error("RAP server error: {}\n".format(ex)) - class CustomCommand(IPyAutocall): rewrite = False diff --git a/radare2/__init__.py b/radare2/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/pyrebox/r2.py b/radare2/rap.py similarity index 79% rename from pyrebox/r2.py rename to radare2/rap.py index 01833a44..0cabad0f 100644 --- a/pyrebox/r2.py +++ b/radare2/rap.py @@ -2,23 +2,21 @@ import struct import api -from utils import find_procs -from utils import pp_print -from utils import pp_debug -from utils import pp_warning -from utils import pp_error +# Printer +pyrebox_print = None + class BaseRapHandler(SocketServer.BaseRequestHandler): def handle(self): while True: try: self.handle_packet() except EOFError: - pp_debug("Closed connection\n") + pyrebox_print("Connection closed\n") break except Exception as e: - pp_error("Protocol error: {}\n".format(e)) + pyrebox_print("Protocol error: {}\n".format(e)) break def handle_packet(self): @@ -126,7 +124,7 @@ def rap_open(self, name, flags): self.pname = proc["name"] break else: - pp_error("Process not found: {}\n".format(name)) + pyrebox_print("Process not found: {}\n".format(name)) return 0 module_list = api.get_module_list(self.pgd) @@ -136,7 +134,7 @@ def rap_open(self, name, flags): self.base = m["base"] self.size = m["size"] - pp_debug("Selecting name={} pid={} base={:#x} size={}\n".format( + pyrebox_print("Selecting name={} pid={} base={:#x} size={}\n".format( self.pname, self.pid, self.base, self.size)) return 0 @@ -145,7 +143,7 @@ def rap_read(self, size): try: data = api.r_va(self.pgd, self.curseek, size) except Exception: - pp_error("Cannot read memory at {:#x}\n".format(self.curseek)) + pyrebox_print("Cannot read memory at {:#x}\n".format(self.curseek)) data = "" return data @@ -155,7 +153,7 @@ def rap_write(self, data): api.w_va(self.pgd, self.curseek, data, len(data)) size = len(data) except Exception: - pp_error("Cannot write memory at {:#x}\n".format(self.curseek)) + pyrebox_print("Cannot write memory at {:#x}\n".format(self.curseek)) size = 0 return size @@ -179,11 +177,11 @@ def rap_close(self, fd): self.curseek = 0 def rap_system(self, cmd): - pp_debug("system not implemented\n") + pyrebox_print("system not implemented\n") return "" def rap_cmd(self, cmd): - pp_debug("cmd not implemented\n") + pyrebox_print("cmd not implemented\n") return "" @@ -213,3 +211,42 @@ def serve_forever(self): def shutdown(self): self.server.shutdown() self.server.server_close() + + +def initialize_callbacks(module_hdl, printer): + global pyrebox_print + pyrebox_print = printer + + +def clean(): + pass + + +def do_rap(line): + '''Start a radare2 RAP server + + Usage: custom rap :1234 - start a RAP server listening on localhost:1234 + custom rap 0.0.0.0:1234 - start a RAP server listening on 0.0.0.0:1234 + ''' + + elements = line.split(":") + if len(elements) != 2: + pyrebox_print(do_rap.__doc__) + return + + rap_host = elements[0] + rap_port = int(elements[1]) + + if rap_host == "": + rap_host = "localhost" + + try: + rs = RapServer(rap_host, rap_port) + + pyrebox_print("RAP server listening on {}:{}\n".format(rap_host, rap_port)) + rs.serve_forever() + except KeyboardInterrupt: + pyrebox_print("Killing RAP server\n") + rs.shutdown() + except Exception as ex: + pyrebox_print("RAP server error: {}\n".format(ex)) From 6a7588014b0667acdf14a888fd15d6c8b38502f7 Mon Sep 17 00:00:00 2001 From: Roi Martin Date: Wed, 30 May 2018 12:05:49 +0200 Subject: [PATCH 5/8] Remove RAP help from ipython_shell.py --- pyrebox/ipython_shell.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pyrebox/ipython_shell.py b/pyrebox/ipython_shell.py index 99f63796..6f98f8ce 100644 --- a/pyrebox/ipython_shell.py +++ b/pyrebox/ipython_shell.py @@ -1594,7 +1594,6 @@ def list_commands(self, line): unmon - Stop monitoring process savevm - Save vm status loadvm - Load vm status - rap - Start a radare2 RAP server quit - Exit this prompt q - Exit this prompt cont - Exit this prompt From 8845840f751f56ebe8a90c78a2c62a859a0da065 Mon Sep 17 00:00:00 2001 From: Roi Martin Date: Wed, 30 May 2018 12:44:31 +0200 Subject: [PATCH 6/8] Replace calls to recvs with a read method --- radare2/rap.py | 39 +++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/radare2/rap.py b/radare2/rap.py index 0cabad0f..17de7601 100644 --- a/radare2/rap.py +++ b/radare2/rap.py @@ -7,6 +7,7 @@ # Printer pyrebox_print = None + class BaseRapHandler(SocketServer.BaseRequestHandler): def handle(self): while True: @@ -20,7 +21,7 @@ def handle(self): break def handle_packet(self): - buf = self.request.recv(1) + buf = self._read_request(1) if len(buf) == 0: raise EOFError @@ -28,54 +29,54 @@ def handle_packet(self): packet_type = ord(buf) if packet_type == RapServer.RAP_OPEN: - buf = self.request.recv(2) + buf = self._read_request(2) (flags, size) = struct.unpack(">BB", buf) - name = self.request.recv(size) + name = self._read_request(size) fd = self.rap_open(name, flags) buf = struct.pack(">BI", RapServer.RAP_OPEN|RapServer.RAP_REPLY, fd) self.request.sendall(buf) elif packet_type == RapServer.RAP_READ: - buf = self.request.recv(4) + buf = self._read_request(4) (size,) = struct.unpack(">I", buf) ret = self.rap_read(size) buf = struct.pack(">BI", RapServer.RAP_READ|RapServer.RAP_REPLY, len(ret)) self.request.sendall(buf + ret) elif packet_type == RapServer.RAP_WRITE: - buf = self.request.recv(4) + buf = self._read_request(4) (size,) = struct.unpack(">I", buf) - buf = self.request.recv(size) + buf = self._read_request(size) ret = self.rap_write(buf) buf = struct.pack(">BI", RapServer.RAP_WRITE|RapServer.RAP_REPLY, ret) self.request.sendall(buf) elif packet_type == RapServer.RAP_SEEK: - buf = self.request.recv(9) + buf = self._read_request(9) (whence, offset) = struct.unpack(">BQ", buf) ret = self.rap_seek(offset, whence) buf = struct.pack(">BQ", RapServer.RAP_SEEK|RapServer.RAP_REPLY, ret) self.request.sendall(buf) elif packet_type == RapServer.RAP_CLOSE: - buf = self.request.recv(4) + buf = self._read_request(4) (fd,) = struct.unpack(">I", buf) self.rap_close(fd) buf = struct.pack(">B", RapServer.RAP_CLOSE|RapServer.RAP_REPLY) self.request.sendall(buf) elif packet_type == RapServer.RAP_SYSTEM: - buf = self.request.recv(4) + buf = self._read_request(4) (size,) = struct.unpack(">I", buf) - buf = self.request.recv(size) + buf = self._read_request(size) ret = self.rap_system(buf) buf = struct.pack(">BI", RapServer.RAP_SYSTEM|RapServer.RAP_REPLY, len(ret)) self.request.sendall(buf + ret) elif packet_type == RapServer.RAP_CMD: - buf = self.request.recv(4) + buf = self._read_request(4) (size,) = struct.unpack(">I", buf) - buf = self.request.recv(size) + buf = self._read_request(size) ret = self.rap_cmd(buf) buf = struct.pack(">BI", RapServer.RAP_CMD|RapServer.RAP_REPLY, len(ret)) self.request.sendall(buf + ret) @@ -104,6 +105,20 @@ def rap_system(self, cmd): def rap_cmd(self, cmd): raise NotImplementedError + def _read_request(self, sz, recvsz=1024): + buf = '' + + while len(buf) < sz: + if recvsz > sz - len(buf): + recvsz = sz - len(buf) + + chunk = self.request.recv(recvsz) + if len(chunk) == 0: + break + buf += chunk + + return buf + class DefaultRapHandler(BaseRapHandler): def __init__(self, *args, **kwargs): From 698ae1112f8995b9f4bc28fcfdac84d7bc44a8b9 Mon Sep 17 00:00:00 2001 From: Roi Martin Date: Wed, 30 May 2018 14:24:59 +0200 Subject: [PATCH 7/8] Rename _read_request() to _request_read() --- radare2/rap.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/radare2/rap.py b/radare2/rap.py index 17de7601..c7b348e1 100644 --- a/radare2/rap.py +++ b/radare2/rap.py @@ -21,7 +21,7 @@ def handle(self): break def handle_packet(self): - buf = self._read_request(1) + buf = self._request_read(1) if len(buf) == 0: raise EOFError @@ -29,54 +29,54 @@ def handle_packet(self): packet_type = ord(buf) if packet_type == RapServer.RAP_OPEN: - buf = self._read_request(2) + buf = self._request_read(2) (flags, size) = struct.unpack(">BB", buf) - name = self._read_request(size) + name = self._request_read(size) fd = self.rap_open(name, flags) buf = struct.pack(">BI", RapServer.RAP_OPEN|RapServer.RAP_REPLY, fd) self.request.sendall(buf) elif packet_type == RapServer.RAP_READ: - buf = self._read_request(4) + buf = self._request_read(4) (size,) = struct.unpack(">I", buf) ret = self.rap_read(size) buf = struct.pack(">BI", RapServer.RAP_READ|RapServer.RAP_REPLY, len(ret)) self.request.sendall(buf + ret) elif packet_type == RapServer.RAP_WRITE: - buf = self._read_request(4) + buf = self._request_read(4) (size,) = struct.unpack(">I", buf) - buf = self._read_request(size) + buf = self._request_read(size) ret = self.rap_write(buf) buf = struct.pack(">BI", RapServer.RAP_WRITE|RapServer.RAP_REPLY, ret) self.request.sendall(buf) elif packet_type == RapServer.RAP_SEEK: - buf = self._read_request(9) + buf = self._request_read(9) (whence, offset) = struct.unpack(">BQ", buf) ret = self.rap_seek(offset, whence) buf = struct.pack(">BQ", RapServer.RAP_SEEK|RapServer.RAP_REPLY, ret) self.request.sendall(buf) elif packet_type == RapServer.RAP_CLOSE: - buf = self._read_request(4) + buf = self._request_read(4) (fd,) = struct.unpack(">I", buf) self.rap_close(fd) buf = struct.pack(">B", RapServer.RAP_CLOSE|RapServer.RAP_REPLY) self.request.sendall(buf) elif packet_type == RapServer.RAP_SYSTEM: - buf = self._read_request(4) + buf = self._request_read(4) (size,) = struct.unpack(">I", buf) - buf = self._read_request(size) + buf = self._request_read(size) ret = self.rap_system(buf) buf = struct.pack(">BI", RapServer.RAP_SYSTEM|RapServer.RAP_REPLY, len(ret)) self.request.sendall(buf + ret) elif packet_type == RapServer.RAP_CMD: - buf = self._read_request(4) + buf = self._request_read(4) (size,) = struct.unpack(">I", buf) - buf = self._read_request(size) + buf = self._request_read(size) ret = self.rap_cmd(buf) buf = struct.pack(">BI", RapServer.RAP_CMD|RapServer.RAP_REPLY, len(ret)) self.request.sendall(buf + ret) @@ -105,7 +105,7 @@ def rap_system(self, cmd): def rap_cmd(self, cmd): raise NotImplementedError - def _read_request(self, sz, recvsz=1024): + def _request_read(self, sz, recvsz=1024): buf = '' while len(buf) < sz: From 3b76fb93784c38f08f7e86cf1eae161a62c29380 Mon Sep 17 00:00:00 2001 From: Roi Martin Date: Sat, 2 Jun 2018 22:55:34 +0200 Subject: [PATCH 8/8] Launch rap server in background. Implement RAP_CMD --- radare2/rap.py | 120 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 85 insertions(+), 35 deletions(-) diff --git a/radare2/rap.py b/radare2/rap.py index c7b348e1..0cd40723 100644 --- a/radare2/rap.py +++ b/radare2/rap.py @@ -1,12 +1,18 @@ import SocketServer +import threading import struct +import string import api +from utils import find_procs # Printer pyrebox_print = None +# RAP server +rs = None + class BaseRapHandler(SocketServer.BaseRequestHandler): def handle(self): @@ -14,10 +20,10 @@ def handle(self): try: self.handle_packet() except EOFError: - pyrebox_print("Connection closed\n") + pyrebox_print("Client disconnected") break except Exception as e: - pyrebox_print("Protocol error: {}\n".format(e)) + pyrebox_print("Protocol error: {}".format(e)) break def handle_packet(self): @@ -82,7 +88,7 @@ def handle_packet(self): self.request.sendall(buf + ret) else: - raise "unknown RAP packet type" + raise Exception("unknown RAP packet type") def rap_open(self, name, flags): raise NotImplementedError @@ -106,7 +112,7 @@ def rap_cmd(self, cmd): raise NotImplementedError def _request_read(self, sz, recvsz=1024): - buf = '' + buf = "" while len(buf) < sz: if recvsz > sz - len(buf): @@ -139,8 +145,7 @@ def rap_open(self, name, flags): self.pname = proc["name"] break else: - pyrebox_print("Process not found: {}\n".format(name)) - return 0 + raise Exception("Process not found: {}".format(name)) module_list = api.get_module_list(self.pgd) for m in module_list: @@ -149,7 +154,7 @@ def rap_open(self, name, flags): self.base = m["base"] self.size = m["size"] - pyrebox_print("Selecting name={} pid={} base={:#x} size={}\n".format( + pyrebox_print("Selecting name={} pid={} base={:#x} size={}".format( self.pname, self.pid, self.base, self.size)) return 0 @@ -158,7 +163,7 @@ def rap_read(self, size): try: data = api.r_va(self.pgd, self.curseek, size) except Exception: - pyrebox_print("Cannot read memory at {:#x}\n".format(self.curseek)) + pyrebox_print("Cannot read memory at {:#x}".format(self.curseek)) data = "" return data @@ -168,7 +173,7 @@ def rap_write(self, data): api.w_va(self.pgd, self.curseek, data, len(data)) size = len(data) except Exception: - pyrebox_print("Cannot write memory at {:#x}\n".format(self.curseek)) + pyrebox_print("Cannot write memory at {:#x}".format(self.curseek)) size = 0 return size @@ -192,13 +197,33 @@ def rap_close(self, fd): self.curseek = 0 def rap_system(self, cmd): - pyrebox_print("system not implemented\n") + pyrebox_print("RAP_SYSTEM not implemented") return "" def rap_cmd(self, cmd): - pyrebox_print("cmd not implemented\n") + cmd = cmd.strip(string.whitespace + "\x00") + if len(cmd) == 0: + pyrebox_print("RAP_CMD: malformed command") + + argv = cmd.split(" ") + for element in dir(self): + if element == "_cmd_{}".format(argv[0]): + return getattr(self, element)(argv[1:]) + + pyrebox_print("RAP_CMD: cmd '{}' not implemented".format(argv[0])) return "" + def _cmd_lm(self, args): + ret = "" + + try: + for m in sorted(api.get_module_list(self.pgd), key=lambda k: k['base']): + ret += "name={} base={:#x} size={:#x}\n".format(m["name"], m["base"], m["size"]) + except Exception as e: + return "error: {}\n".format(e) + + return ret + class RapServer(): # Packet types @@ -218,50 +243,75 @@ class RapServer(): def __init__(self, host, port, handler_class=DefaultRapHandler): + self.host = host + self.port = port self.server = SocketServer.TCPServer((host, port), handler_class) - def serve_forever(self): - self.server.serve_forever() + def serve(self): + server_thread = threading.Thread(target=self.server.serve_forever) + server_thread.start() def shutdown(self): self.server.shutdown() self.server.server_close() -def initialize_callbacks(module_hdl, printer): - global pyrebox_print - pyrebox_print = printer +def serve(host, port): + global rs + if rs: + pyrebox_print("RAP server already running on {}:{}".format(rs.host, rs.port)) + return + + try: + rs = RapServer(host, port) + rs.serve() + pyrebox_print("RAP server listening on {}:{}".format(host, port)) + except Exception as ex: + pyrebox_print("RAP server error: {}".format(ex)) -def clean(): - pass + +def shutdown(): + global rs + + if not rs: + pyrebox_print("RAP server not running") + return + + pyrebox_print("Closing RAP server (waiting for clients to disconnect)...") + rs.shutdown() + rs = None + pyrebox_print("RAP server closed") def do_rap(line): '''Start a radare2 RAP server - Usage: custom rap :1234 - start a RAP server listening on localhost:1234 - custom rap 0.0.0.0:1234 - start a RAP server listening on 0.0.0.0:1234 + Usage: custom rap :1234 - start a RAP server listening on localhost:1234 + custom rap 0.0.0.0:1234 - start a RAP server listening on 0.0.0.0:1234 + custom rap shutdown - close the running RAP server ''' elements = line.split(":") - if len(elements) != 2: + if len(elements) == 1 and elements[0] == "shutdown": + # custom rap shutdown + shutdown() + elif len(elements) == 2: + # custom rap [hostname]:port + host = elements[0] + port = int(elements[1]) + if host == "": + host = "localhost" + serve(host, port) + else: + # Unknown cmdline pyrebox_print(do_rap.__doc__) - return - rap_host = elements[0] - rap_port = int(elements[1]) - if rap_host == "": - rap_host = "localhost" +def initialize_callbacks(module_hdl, printer): + global pyrebox_print + pyrebox_print = printer - try: - rs = RapServer(rap_host, rap_port) - pyrebox_print("RAP server listening on {}:{}\n".format(rap_host, rap_port)) - rs.serve_forever() - except KeyboardInterrupt: - pyrebox_print("Killing RAP server\n") - rs.shutdown() - except Exception as ex: - pyrebox_print("RAP server error: {}\n".format(ex)) +def clean(): + shutdown()