diff --git a/docs/commands/index.md b/docs/commands/index.md index 2883dff57..e6a6cca81 100644 --- a/docs/commands/index.md +++ b/docs/commands/index.md @@ -103,7 +103,7 @@ - [linkmap](linux_libc_elf/linkmap.md) - Show the state of the Link Map - [onegadget](linux_libc_elf/onegadget.md) - Find gadgets which single-handedly give code execution. - [piebase](linux_libc_elf/piebase.md) - Calculate VA of RVA from PIE base. -- [plt](linux_libc_elf/plt.md) - Prints any symbols found in the .plt section if it exists. +- [plt](linux_libc_elf/plt.md) - Prints any symbols found in Procedure Linkage Table sections if any exist. - [strings](linux_libc_elf/strings.md) - Extracts and displays ASCII strings from readable memory pages of the debugged process. - [threads](linux_libc_elf/threads.md) - List all threads belonging to the selected inferior. - [tls](linux_libc_elf/tls.md) - Print out base address of the current Thread Local Storage (TLS). diff --git a/docs/commands/linux_libc_elf/plt.md b/docs/commands/linux_libc_elf/plt.md index 9d4ccc8e0..1feac91d7 100644 --- a/docs/commands/linux_libc_elf/plt.md +++ b/docs/commands/linux_libc_elf/plt.md @@ -11,7 +11,7 @@ usage: plt [-h] ``` -Prints any symbols found in the .plt section if it exists. +Prints any symbols found in Procedure Linkage Table sections if any exist. ### Optional arguments |Short|Long|Help| diff --git a/pwndbg/commands/elf.py b/pwndbg/commands/elf.py index 0300f3d80..5454c5f79 100644 --- a/pwndbg/commands/elf.py +++ b/pwndbg/commands/elf.py @@ -1,5 +1,8 @@ from __future__ import annotations +from typing import List +from typing import Tuple + from elftools.elf.elffile import ELFFile import pwndbg.commands @@ -42,15 +45,72 @@ def gotplt() -> None: print_symbols_in_section(".got.plt", "@got.plt") +# These are all the section names associated with PLTs. +# .plt.sec and .plt.bnd are associated with control flow transfer integrity. +# These are derived from this list that GDB recognizes: https://github.com/bminor/binutils-gdb/blob/38d726a24c1a85abdb606e7ab6cefad17872aad7/bfd/elf64-x86-64.c#L5775-L5780 +PLT_SECTION_NAMES = (".plt", ".plt.sec", ".plt.got", ".plt.bnd") + + @pwndbg.commands.Command( - "Prints any symbols found in the .plt section if it exists.", category=CommandCategory.LINUX + "Prints any symbols found in Procedure Linkage Table sections if any exist.", + category=CommandCategory.LINUX, ) @pwndbg.commands.OnlyWithFile def plt() -> None: - print_symbols_in_section(".plt", "@plt") + local_path = pwndbg.aglib.file.get_proc_exe_file() + + bin_base_addr = 0 + # If we started the binary and it has PIE, rebase it + if pwndbg.aglib.proc.alive: + bin_base_addr = pwndbg.aglib.proc.binary_base_addr + + # List of (Section name, start_addr, end_addr) + sections_found: List[Tuple[str, int, int]] = [] + + with open(local_path, "rb") as f: + elffile = ELFFile(f) + + for section_name in PLT_SECTION_NAMES: + section = elffile.get_section_by_name(section_name) + + if section: + start: int = section["sh_addr"] + size: int = section["sh_size"] + + if start is None: + continue + + end = start + size + + # Rebase the start and end addresses if needed + if start < bin_base_addr: + start += bin_base_addr + end += bin_base_addr + + sections_found.append((section_name, start, end)) + + # Sort by the start address so we print from lowest to highest + sections_found.sort(key=lambda x: x[1]) + + for section_name, start, end in sections_found: + symbols = get_symbols_in_region(start, end, "@plt") + + print(message.notice(f"Section {section_name} {start:#x} - {end:#x}:")) + + if not symbols: + print(message.error(f"No symbols found in section {section_name}")) + + stuff: List[Tuple[int, str]] = [] + + for symbol, addr in symbols: + stuff.append((addr, symbol)) + print(hex(int(addr)) + ": " + symbol) + + if len(sections_found) == 0: + print(message.error("No .plt.* sections found")) -def get_section_bounds(section_name): +def get_section_bounds(section_name: str): local_path = pwndbg.aglib.file.get_proc_exe_file() with open(local_path, "rb") as f: @@ -93,8 +153,8 @@ def print_symbols_in_section(section_name, filter_text="") -> None: print(hex(int(addr)) + ": " + symbol) -def get_symbols_in_region(start, end, filter_text=""): - symbols = [] +def get_symbols_in_region(start: int, end: int, filter_text="") -> List[Tuple[str, int]]: + symbols: List[Tuple[str, int]] = [] ptr_size = pwndbg.aglib.typeinfo.pvoid.sizeof addr = start while addr < end: diff --git a/tests/gdb-tests/tests/test_commands_elf.py b/tests/gdb-tests/tests/test_commands_elf.py index ec335878f..6fb1eaa6e 100644 --- a/tests/gdb-tests/tests/test_commands_elf.py +++ b/tests/gdb-tests/tests/test_commands_elf.py @@ -18,7 +18,7 @@ def test_commands_plt_gotplt_got_when_no_sections(start_binary): start_binary(NO_SECTS_BINARY) # elf.py commands - assert gdb.execute("plt", to_string=True) == "Could not find section .plt\n" + assert gdb.execute("plt", to_string=True) == "No .plt.* sections found\n" assert gdb.execute("gotplt", to_string=True) == "Could not find section .got.plt\n" # got.py command @@ -40,7 +40,7 @@ def test_command_plt(binary_name, is_pie): out = gdb.execute("plt", to_string=True).splitlines() assert len(out) == 2 - assert re.match(r"Section \.plt 0x[0-9a-f]+-0x[0-9a-f]+:", out[0]) + assert re.match(r"Section \.plt 0x[0-9a-f]+ - 0x[0-9a-f]+:", out[0]) assert re.match(r"0x[0-9a-f]+: puts@plt", out[1]) gdb.execute("starti") @@ -53,7 +53,7 @@ def test_command_plt(binary_name, is_pie): assert out == out2 assert len(out2) == 2 - assert re.match(r"Section \.plt 0x[0-9a-f]+-0x[0-9a-f]+:", out2[0]) + assert re.match(r"Section \.plt 0x[0-9a-f]+ - 0x[0-9a-f]+:", out2[0]) assert re.match(r"0x[0-9a-f]+: puts@plt", out2[1])