From 63b988a997543e8d3ce0f3dee605331c68954fdc Mon Sep 17 00:00:00 2001 From: Gulshan Singh Date: Sat, 8 Oct 2022 21:07:15 -0700 Subject: [PATCH] Move file.py to gdblib and improve procinfo test (#1258) --- docs/source/api/file.rst | 4 ++-- pwndbg/arguments.py | 2 +- pwndbg/commands/elf.py | 4 ++-- pwndbg/commands/got.py | 2 +- pwndbg/commands/mprotect.py | 2 +- pwndbg/commands/pie.py | 6 +++--- pwndbg/commands/procinfo.py | 12 +++++------ pwndbg/commands/radare2.py | 2 +- pwndbg/commands/vmmap.py | 2 +- pwndbg/elf.py | 2 +- pwndbg/gdblib/android.py | 4 ++-- pwndbg/{ => gdblib}/file.py | 2 +- pwndbg/gdblib/net.py | 24 +++++++++++++++++++++ pwndbg/gdblib/proc.py | 2 +- pwndbg/lib/net.py | 11 ++++------ pwndbg/symbol.py | 6 +++--- pwndbg/vmmap.py | 8 +++---- pwndbg/wrappers/checksec.py | 2 +- pwndbg/wrappers/readelf.py | 2 +- tests/binaries/reference-binary.c | 36 +++++++++++++++++++++++++++---- tests/test_command_procinfo.py | 5 +++++ 21 files changed, 97 insertions(+), 43 deletions(-) rename pwndbg/{ => gdblib}/file.py (97%) mode change 100755 => 100644 create mode 100644 pwndbg/gdblib/net.py diff --git a/docs/source/api/file.rst b/docs/source/api/file.rst index 90704c676..81ee84cb1 100644 --- a/docs/source/api/file.rst +++ b/docs/source/api/file.rst @@ -1,5 +1,5 @@ -:mod:`pwndbg.file` --- pwndbg.file +:mod:`pwndbg.gdblib.file` --- pwndbg.gdblib.file ============================================= -.. automodule:: pwndbg.file +.. automodule:: pwndbg.gdblib.file :members: diff --git a/pwndbg/arguments.py b/pwndbg/arguments.py index 6cc642704..52ee79285 100644 --- a/pwndbg/arguments.py +++ b/pwndbg/arguments.py @@ -210,7 +210,7 @@ def format_args(instruction): # Enhance args display if arg.name == "fd" and isinstance(value, int): - path = pwndbg.file.readlink("/proc/%d/fd/%d" % (pwndbg.gdblib.proc.pid, value)) + path = pwndbg.gdblib.file.readlink("/proc/%d/fd/%d" % (pwndbg.gdblib.proc.pid, value)) if path: pretty += " (%s)" % path diff --git a/pwndbg/commands/elf.py b/pwndbg/commands/elf.py index e43afa26c..c1a57e39b 100755 --- a/pwndbg/commands/elf.py +++ b/pwndbg/commands/elf.py @@ -7,7 +7,7 @@ from pwndbg.color import message @pwndbg.commands.ArgparsedCommand("Prints the section mappings contained in the ELF header.") @pwndbg.commands.OnlyWithFile def elfheader(): - local_path = pwndbg.file.get_file(pwndbg.gdblib.proc.exe) + local_path = pwndbg.gdblib.file.get_file(pwndbg.gdblib.proc.exe) with open(local_path, "rb") as f: elffile = ELFFile(f) @@ -41,7 +41,7 @@ def plt(): def get_section_bounds(section_name): - local_path = pwndbg.file.get_file(pwndbg.gdblib.proc.exe) + local_path = pwndbg.gdblib.file.get_file(pwndbg.gdblib.proc.exe) with open(local_path, "rb") as f: elffile = ELFFile(f) diff --git a/pwndbg/commands/got.py b/pwndbg/commands/got.py index 1de16ed3b..6e49a87b3 100644 --- a/pwndbg/commands/got.py +++ b/pwndbg/commands/got.py @@ -3,7 +3,7 @@ import argparse import pwndbg.chain import pwndbg.commands import pwndbg.enhance -import pwndbg.file +import pwndbg.gdblib.file import pwndbg.lib.which import pwndbg.wrappers.checksec import pwndbg.wrappers.readelf diff --git a/pwndbg/commands/mprotect.py b/pwndbg/commands/mprotect.py index d01b1cc4c..0e2163825 100644 --- a/pwndbg/commands/mprotect.py +++ b/pwndbg/commands/mprotect.py @@ -7,7 +7,7 @@ from pwnlib import asm import pwndbg.chain import pwndbg.commands import pwndbg.enhance -import pwndbg.file +import pwndbg.gdblib.file import pwndbg.lib.which import pwndbg.wrappers.checksec import pwndbg.wrappers.readelf diff --git a/pwndbg/commands/pie.py b/pwndbg/commands/pie.py index 5da76bd38..443de5418 100644 --- a/pwndbg/commands/pie.py +++ b/pwndbg/commands/pie.py @@ -26,7 +26,7 @@ def get_exe_name(): # On the other hand, the vmmap, if taken from /proc/pid/maps will contain # the absolute and real path of the binary (after symlinks). # And so we have to read this path here. - real_path = pwndbg.file.readlink(path) + real_path = pwndbg.gdblib.file.readlink(path) if real_path == "": # the `path` was not a symlink real_path = path @@ -84,7 +84,7 @@ parser.add_argument( def piebase(offset=None, module=None): offset = int(offset) if not module: - # Note: we do not use `pwndbg.file.get_file(module)` here as it is not needed. + # Note: we do not use `pwndbg.gdblib.file.get_file(module)` here as it is not needed. # (as we do need the actual path that is in vmmap, not the file itself) module = get_exe_name() @@ -113,7 +113,7 @@ parser.add_argument( def breakrva(offset=0, module=None): offset = int(offset) if not module: - # Note: we do not use `pwndbg.file.get_file(module)` here as it is not needed. + # Note: we do not use `pwndbg.gdblib.file.get_file(module)` here as it is not needed. # (as we do need the actual path that is in vmmap, not the file itself) module = get_exe_name() addr = translate_addr(offset, module) diff --git a/pwndbg/commands/procinfo.py b/pwndbg/commands/procinfo.py index dd02215ce..5a2a108e8 100644 --- a/pwndbg/commands/procinfo.py +++ b/pwndbg/commands/procinfo.py @@ -2,10 +2,10 @@ import string import pwndbg.auxv import pwndbg.commands -import pwndbg.file +import pwndbg.gdblib.file +import pwndbg.gdblib.net import pwndbg.gdblib.proc import pwndbg.lib.memoize -import pwndbg.lib.net """ PEDA prints it out like this: @@ -79,13 +79,13 @@ class Process: @pwndbg.lib.memoize.reset_on_stop def selinux(self): path = "/proc/%i/task/%i/attr/current" % (self.pid, self.tid) - raw = pwndbg.file.get(path) + raw = pwndbg.gdblib.file.get(path) return raw.decode().rstrip("\x00").strip() @property @pwndbg.lib.memoize.reset_on_stop def status(self): - raw = pwndbg.file.get("/proc/%i/task/%i/status" % (self.pid, self.tid)) + raw = pwndbg.gdblib.file.get("/proc/%i/task/%i/status" % (self.pid, self.tid)) status = {} for line in raw.splitlines(): @@ -144,7 +144,7 @@ class Process: fds = {} for i in range(self.fdsize): - link = pwndbg.file.readlink("/proc/%i/fd/%i" % (pwndbg.gdblib.proc.pid, i)) + link = pwndbg.gdblib.file.readlink("/proc/%i/fd/%i" % (pwndbg.gdblib.proc.pid, i)) if link: fds[i] = link @@ -160,7 +160,7 @@ class Process: socket = "socket:[" result = [] - functions = [pwndbg.lib.net.tcp, pwndbg.lib.net.unix, pwndbg.lib.net.netlink] + functions = [pwndbg.gdblib.net.tcp, pwndbg.gdblib.net.unix, pwndbg.gdblib.net.netlink] for fd, path in fds.items(): if socket not in path: diff --git a/pwndbg/commands/radare2.py b/pwndbg/commands/radare2.py index 067ee10c7..a0b95ed92 100644 --- a/pwndbg/commands/radare2.py +++ b/pwndbg/commands/radare2.py @@ -18,7 +18,7 @@ parser.add_argument("arguments", nargs="*", type=str, help="Arguments to pass to @pwndbg.commands.ArgparsedCommand(parser, aliases=["radare2"]) @pwndbg.commands.OnlyWithFile def r2(arguments, no_seek=False, no_rebase=False): - filename = pwndbg.file.get_file(pwndbg.gdblib.proc.exe) + filename = pwndbg.gdblib.file.get_file(pwndbg.gdblib.proc.exe) # Build up the command line to run cmd = ["radare2"] diff --git a/pwndbg/commands/vmmap.py b/pwndbg/commands/vmmap.py index fbdfb80dc..97a029053 100644 --- a/pwndbg/commands/vmmap.py +++ b/pwndbg/commands/vmmap.py @@ -137,7 +137,7 @@ parser.add_argument( @pwndbg.commands.ArgparsedCommand(parser) def vmmap_load(filename): if filename is None: - filename = pwndbg.file.get_file(pwndbg.gdblib.proc.exe) + filename = pwndbg.gdblib.file.get_file(pwndbg.gdblib.proc.exe) print('Load "%s" ...' % filename) diff --git a/pwndbg/elf.py b/pwndbg/elf.py index 1d106682c..3bfa5e0b2 100644 --- a/pwndbg/elf.py +++ b/pwndbg/elf.py @@ -87,7 +87,7 @@ def get_elf_info(filepath): Adds various calculated properties to the ELF header, segments and sections. Such added properties are those with prefix 'x_' in the returned dicts. """ - local_path = pwndbg.file.get_file(filepath) + local_path = pwndbg.gdblib.file.get_file(filepath) with open(local_path, "rb") as f: elffile = ELFFile(f) header = dict(elffile.header) diff --git a/pwndbg/gdblib/android.py b/pwndbg/gdblib/android.py index fb73ce9b3..a2e4d8e9a 100644 --- a/pwndbg/gdblib/android.py +++ b/pwndbg/gdblib/android.py @@ -1,8 +1,8 @@ import gdb import pwndbg.color.message as message -import pwndbg.file import pwndbg.gdblib.events +import pwndbg.gdblib.file import pwndbg.gdblib.qemu import pwndbg.lib.memoize @@ -14,7 +14,7 @@ def is_android(): return False try: - if pwndbg.file.get("/system/etc/hosts"): + if pwndbg.gdblib.file.get("/system/etc/hosts"): return True except OSError: pass diff --git a/pwndbg/file.py b/pwndbg/gdblib/file.py old mode 100755 new mode 100644 similarity index 97% rename from pwndbg/file.py rename to pwndbg/gdblib/file.py index 92734f2ac..3f4181ae7 --- a/pwndbg/file.py +++ b/pwndbg/gdblib/file.py @@ -72,7 +72,7 @@ def get_file(path): else: print( message.warn( - "pwndbg.file.get(%s) returns local path as we can't download file from QEMU" + "pwndbg.gdblib.file.get(%s) returns local path as we can't download file from QEMU" % path ) ) diff --git a/pwndbg/gdblib/net.py b/pwndbg/gdblib/net.py new file mode 100644 index 000000000..475ceb3db --- /dev/null +++ b/pwndbg/gdblib/net.py @@ -0,0 +1,24 @@ +import pwndbg.gdblib.file +import pwndbg.lib.net + + +def tcp(): + # For reference, see: + # https://www.kernel.org/doc/Documentation/networking/proc_net_tcp.txt + """ + It will first list all listening TCP sockets, and next list all established + TCP connections. A typical entry of /proc/net/tcp would look like this (split + up into 3 parts because of the length of the line): + """ + data = pwndbg.gdblib.file.get("/proc/net/tcp").decode() + return pwndbg.lib.net.tcp(data) + + +def unix(): + data = pwndbg.gdblib.file.get("/proc/net/unix").decode() + return pwndbg.lib.net.unix(data) + + +def netlink(): + data = pwndbg.gdblib.file.get("/proc/net/netlink").decode() + return pwndbg.lib.net.netlink(data) diff --git a/pwndbg/gdblib/proc.py b/pwndbg/gdblib/proc.py index 52207409d..c5e126f0a 100644 --- a/pwndbg/gdblib/proc.py +++ b/pwndbg/gdblib/proc.py @@ -67,7 +67,7 @@ class module(ModuleType): 2. gdb -ex "target remote :1234" -ex "pi pwndbg.gdblib.proc.exe" If you need to process the debugged file use: - `pwndbg.file.get_file(pwndbg.gdblib.proc.exe)` + `pwndbg.gdblib.file.get_file(pwndbg.gdblib.proc.exe)` """ return gdb.current_progspace().filename diff --git a/pwndbg/lib/net.py b/pwndbg/lib/net.py index 36791b67b..826a2d184 100644 --- a/pwndbg/lib/net.py +++ b/pwndbg/lib/net.py @@ -6,8 +6,8 @@ remote debugging sessions. import binascii import socket -import pwndbg.file import pwndbg.gdblib.arch +import pwndbg.gdblib.file # http://students.mimuw.edu.pl/lxr/source/include/net/tcp_states.h TCP_STATUSES = { @@ -65,7 +65,7 @@ class UnixSocket(inode): return "UnixSocket(%s)" % self -def tcp(): +def tcp(data: str): # For reference, see: # https://www.kernel.org/doc/Documentation/networking/proc_net_tcp.txt """ @@ -73,7 +73,6 @@ def tcp(): TCP connections. A typical entry of /proc/net/tcp would look like this (split up into 3 parts because of the length of the line): """ - data = pwndbg.file.get("/proc/net/tcp").decode() if not data: return [] @@ -142,8 +141,7 @@ def tcp(): return result -def unix(): - data = pwndbg.file.get("/proc/net/unix").decode() +def unix(data: str): if not data: return [] @@ -199,8 +197,7 @@ class Netlink(inode): return "Netlink(%s)" % self -def netlink(): - data = pwndbg.file.get("/proc/net/netlink").decode() +def netlink(data: str): if not data: return [] diff --git a/pwndbg/symbol.py b/pwndbg/symbol.py index 1ef192073..01bce5423 100644 --- a/pwndbg/symbol.py +++ b/pwndbg/symbol.py @@ -15,10 +15,10 @@ import elftools.elf.segments import gdb import pwndbg.elf -import pwndbg.file import pwndbg.gdblib.android import pwndbg.gdblib.arch import pwndbg.gdblib.events +import pwndbg.gdblib.file import pwndbg.gdblib.memory import pwndbg.gdblib.qemu import pwndbg.gdblib.remote @@ -79,7 +79,7 @@ def autofetch(): if pwndbg.gdblib.android.is_android(): return - remote_files_dir = pwndbg.file.remote_files_dir() + remote_files_dir = pwndbg.gdblib.file.remote_files_dir() if remote_files_dir not in get_directory().split(":"): add_directory(remote_files_dir) @@ -98,7 +98,7 @@ def autofetch(): print(msg, end="") try: - data = pwndbg.file.get(objfile) + data = pwndbg.gdblib.file.get(objfile) print("\r" + msg + ": OK") except OSError: # The file could not be downloaded :( diff --git a/pwndbg/vmmap.py b/pwndbg/vmmap.py index 20a06941e..b4877f485 100644 --- a/pwndbg/vmmap.py +++ b/pwndbg/vmmap.py @@ -11,9 +11,9 @@ import os import gdb import pwndbg.elf -import pwndbg.file import pwndbg.gdblib.abi import pwndbg.gdblib.events +import pwndbg.gdblib.file import pwndbg.gdblib.memory import pwndbg.gdblib.proc import pwndbg.gdblib.qemu @@ -338,7 +338,7 @@ def proc_pid_maps(): for location in locations: try: - data = pwndbg.file.get(location).decode() + data = pwndbg.gdblib.file.get(location).decode() break except (OSError, gdb.error): continue @@ -624,7 +624,7 @@ def check_aslr(): # Systemwide ASLR is disabled try: - data = pwndbg.file.get("/proc/sys/kernel/randomize_va_space") + data = pwndbg.gdblib.file.get("/proc/sys/kernel/randomize_va_space") if b"0" in data: return False, "kernel.randomize_va_space == 0" except Exception as e: @@ -633,7 +633,7 @@ def check_aslr(): # Check the personality of the process if pwndbg.gdblib.proc.alive: try: - data = pwndbg.file.get("/proc/%i/personality" % pwndbg.gdblib.proc.pid) + data = pwndbg.gdblib.file.get("/proc/%i/personality" % pwndbg.gdblib.proc.pid) personality = int(data, 16) return (personality & 0x40000 == 0), "read status from process' personality" except Exception: diff --git a/pwndbg/wrappers/checksec.py b/pwndbg/wrappers/checksec.py index e848ccd47..74a63b06d 100644 --- a/pwndbg/wrappers/checksec.py +++ b/pwndbg/wrappers/checksec.py @@ -11,7 +11,7 @@ cmd_pwntools = ["pwn", "checksec"] @pwndbg.wrappers.OnlyWithCommand(cmd_name, cmd_pwntools) @pwndbg.lib.memoize.reset_on_objfile def get_raw_out(): - local_path = pwndbg.file.get_file(pwndbg.gdblib.proc.exe) + local_path = pwndbg.gdblib.file.get_file(pwndbg.gdblib.proc.exe) try: return pwndbg.wrappers.call_cmd(get_raw_out.cmd + ["--file=" + local_path]) except CalledProcessError: diff --git a/pwndbg/wrappers/readelf.py b/pwndbg/wrappers/readelf.py index 25b4cb79c..42195b7ac 100644 --- a/pwndbg/wrappers/readelf.py +++ b/pwndbg/wrappers/readelf.py @@ -5,7 +5,7 @@ cmd_name = "readelf" @pwndbg.wrappers.OnlyWithCommand(cmd_name) def get_jmpslots(): - local_path = pwndbg.file.get_file(pwndbg.gdblib.proc.exe) + local_path = pwndbg.gdblib.file.get_file(pwndbg.gdblib.proc.exe) cmd = get_jmpslots.cmd + ["--relocs", local_path] readelf_out = pwndbg.wrappers.call_cmd(cmd) diff --git a/tests/binaries/reference-binary.c b/tests/binaries/reference-binary.c index 4f53cd46d..4e1caad85 100644 --- a/tests/binaries/reference-binary.c +++ b/tests/binaries/reference-binary.c @@ -1,8 +1,36 @@ +#include #include -void foo() {} +#define PORT 80 -int main() { - puts("Hello world"); - foo(); +void break_here() {}; + +int main(int argc, char const* argv[]) { + puts("Hello World"); + + int sock = 0, client_fd; + struct sockaddr_in serv_addr; + + if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + perror("socket"); + return -1; + } + + serv_addr.sin_family = AF_INET; + serv_addr.sin_port = htons(PORT); + + if (inet_pton(AF_INET, "1.1.1.1", &serv_addr.sin_addr) <= 0) { + perror("inet_pton"); + return -1; + } + + if ((client_fd = connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr))) < 0) { + perror("connect"); + return -1; + } + + break_here(); + + close(client_fd); + return 0; } diff --git a/tests/test_command_procinfo.py b/tests/test_command_procinfo.py index 3fb94fa6c..076b36a12 100644 --- a/tests/test_command_procinfo.py +++ b/tests/test_command_procinfo.py @@ -10,11 +10,16 @@ def test_command_procinfo(start_binary): bin_path = gdb.execute("pi pwndbg.gdblib.proc.exe", to_string=True).strip("\n") pid = gdb.execute("pi pwndbg.gdblib.proc.pid", to_string=True).strip("\n") + + gdb.execute("break break_here") + gdb.execute("continue") + result = gdb.execute("procinfo", to_string=True) res_list = result.split("\n") assert bin_path in res_list[0] assert pid in res_list[1] + assert "1.1.1.1:80" in result def test_command_procinfo_before_binary_start():