Fix plt and gotplt commands (#1576)

* Fix plt and gotplt commands

* Add plt gotplt commands tests

* Fix got and plt commands and test them

* Revert accidental change

* Extend system path

* Hopefully fix PATH problems once and for all?

* fix import

* remove redundant part
pull/1586/head
Disconnect3d 3 years ago committed by GitHub
parent 871a440a50
commit ee832c80d2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -38,11 +38,9 @@ RUN sed -i "s/^git submodule/#git submodule/" ./setup.sh && \
ADD ./setup-dev.sh /pwndbg/
RUN ./setup-dev.sh
RUN echo "source /pwndbg/gdbinit.py" >> ~/.gdbinit.py && \
echo "PYTHON_MINOR=$(python3 -c "import sys;print(sys.version_info.minor)")" >> /root/.bashrc && \
echo "PYTHON_PATH=\"/usr/local/lib/python3.${PYTHON_MINOR}/dist-packages/bin\"" >> /root/.bashrc && \
echo "export PATH=$PATH:$PYTHON_PATH" >> /root/.bashrc
RUN echo "source /pwndbg/gdbinit.py" >> ~/.gdbinit.py
ADD . /pwndbg/
RUN git submodule update --init --recursive

@ -1,11 +1,14 @@
import cProfile
import glob
import locale
import os
import sys
import time
from os import environ
from os import path
import pkg_resources
_profiler = cProfile.Profile()
_start_time = None
@ -75,11 +78,15 @@ directory, file = path.split(__file__)
directory = path.expanduser(directory)
directory = path.abspath(directory)
# Add gdb-pt-dump directory to sys.path so it can be imported
gdbpt = path.join(directory, "gdb-pt-dump")
sys.path.append(directory)
sys.path.append(gdbpt)
# Add the dir where Pwntools binaries might be into PATH
pwntools_bin_dir = os.path.join(pkg_resources.get_distribution("pwntools").location, "bin")
os.environ["PATH"] = os.environ.get("PATH") + os.pathsep + pwntools_bin_dir
# warn if the user has different encoding than utf-8
encoding = locale.getpreferredencoding()

@ -68,9 +68,22 @@ def print_symbols_in_section(section_name, filter_text="") -> None:
start, end = get_section_bounds(section_name)
if start is None:
print(message.error("Could not find section"))
print(message.error(f"Could not find section {section_name}"))
return
elf_header = pwndbg.gdblib.elf.exe()
# If we started the binary and it has PIE, rebase it
if pwndbg.gdblib.proc.alive:
bin_base_addr = pwndbg.gdblib.proc.binary_base_addr
# Rebase the start and end addresses if needed
if start < bin_base_addr:
start += bin_base_addr
end += bin_base_addr
print(message.notice(f"Section {section_name} {start:#x}-{end:#x}:"))
symbols = get_symbols_in_region(start, end, filter_text)
if not symbols:
@ -85,7 +98,7 @@ def get_symbols_in_region(start, end, filter_text=""):
ptr_size = pwndbg.gdblib.typeinfo.pvoid.sizeof
addr = start
while addr < end:
name = pwndbg.gdblib.symbol.get(addr)
name = pwndbg.gdblib.symbol.get(addr, gdb_only=True)
if name != "" and "+" not in name and filter_text in name:
symbols.append((name, addr))
addr += ptr_size

@ -27,16 +27,14 @@ def got(name_filter="") -> None:
return
if "PIE enabled" in pie_status:
bin_base = pwndbg.gdblib.elf.exe().address
bin_base = pwndbg.gdblib.proc.binary_base_addr
relro_color = message.off
if "Partial" in relro_status:
relro_color = message.warn
elif "Full" in relro_status:
relro_color = message.on
print(
"\nGOT protection: %s | GOT functions: %d\n " % (relro_color(relro_status), len(jmpslots))
)
print("GOT protection: %s | GOT functions: %d" % (relro_color(relro_status), len(jmpslots)))
for line in jmpslots:
address, info, rtype, value, name = line.split()[:5]

@ -9,11 +9,13 @@ import sys
from types import ModuleType
from typing import Any
from typing import Callable
from typing import Tuple
import gdb
import pwndbg.gdblib.qemu
import pwndbg.lib.memoize
import pwndbg.lib.memory
class module(ModuleType):
@ -89,6 +91,18 @@ class module(ModuleType):
"""
return gdb.current_progspace().filename
@property
@pwndbg.lib.memoize.reset_on_start
@pwndbg.lib.memoize.reset_on_stop
def binary_base_addr(self) -> int:
return self.binary_vmmap[0].start
@property
@pwndbg.lib.memoize.reset_on_start
@pwndbg.lib.memoize.reset_on_stop
def binary_vmmap(self) -> Tuple[pwndbg.lib.memory.Page, ...]:
return tuple(p for p in pwndbg.gdblib.vmmap.get() if p.objfile == self.exe)
def OnlyWhenRunning(self, func):
@functools.wraps(func)
def wrapper(*a, **kw):

@ -61,14 +61,15 @@ if "/usr/lib/debug" not in _get_debug_file_directory():
@pwndbg.lib.memoize.reset_on_objfile
def get(address: int, gdb_only=False) -> str:
"""
Retrieve the name for the symbol located at `address`
Retrieve the name for the symbol located at `address` - either from GDB or from IDA sync
Passing `gdb_only=True`
"""
# Fast path
if address < pwndbg.gdblib.memory.MMAP_MIN_ADDR or address >= ((1 << 64) - 1):
return ""
# Note: we do not return "" on `address < pwndbg.gdblib.memory.MMAP_MIN_ADDR`
# because this may be used to find out the symbol name on PIE binaries that weren't started yet
# and then their symbol addresses can be found by GDB on their (non-rebased) offsets
# Don't look up stack addresses
if pwndbg.gdblib.stack.find(address):
# Fast path: GDB's `info symbol` returns 'Numeric constant too large' here
if address >= ((1 << 64) - 1):
return ""
# This sucks, but there's not a GDB API for this.

@ -38,8 +38,9 @@ GLIBC_2_33=$(PWD)/glibcs/2.33
.PHONY : all clean
all: $(LINKED) $(LINKED_ASM) $(COMPILED_GO)
CUSTOM_TARGETS = reference_bin_pie.out reference_bin_nopie.out
all: $(LINKED) $(LINKED_ASM) $(COMPILED_GO) $(CUSTOM_TARGETS)
%.out : %.c
@echo "[+] Building '$@'"
@ -97,4 +98,10 @@ clean :
@rm -f $(COMPILED) $(LINKED) $(COMPILED_ASM) $(LINKED_ASM) $(COMPILED_GO)
reference-binary.out: EXTRA_FLAGS := -Dexample=1
reference_bin_pie.out: reference-binary.c
@echo "[+] Building reference_bin_pie.out"
${ZIGCC} -fpie -o reference_bin_pie.out reference-binary.c
reference_bin_nopie.out: reference-binary.c
@echo "[+] Building reference_bin_nopie.out"
${ZIGCC} -fno-pie -o reference_bin_nopie.out reference-binary.c

@ -0,0 +1,70 @@
import re
import gdb
import pytest
import tests
NO_SECTS_BINARY = tests.binaries.get("gosample.x86")
PIE_BINARY_WITH_PLT = "reference_bin_pie.out"
NOPIE_BINARY_WITH_PLT = "reference_bin_nopie.out"
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("gotplt", to_string=True) == "Could not find section .got.plt\n"
# got.py command
assert gdb.execute("got", to_string=True) == "NO JUMP_SLOT entries available in the GOT\n"
@pytest.mark.parametrize(
"binary_name,is_pie", ((PIE_BINARY_WITH_PLT, True), (NOPIE_BINARY_WITH_PLT, False))
)
def test_command_plt(binary_name, is_pie):
binary = tests.binaries.get(binary_name)
gdb.execute(f"file {binary}")
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"0x[0-9a-f]+: puts@plt", out[1])
gdb.execute("starti")
out2 = gdb.execute("plt", to_string=True).splitlines()
if is_pie:
assert out != out2
else:
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"0x[0-9a-f]+: puts@plt", out2[1])
@pytest.mark.parametrize(
"binary_name,is_pie", ((PIE_BINARY_WITH_PLT, True), (NOPIE_BINARY_WITH_PLT, False))
)
def test_command_got(binary_name, is_pie):
binary = tests.binaries.get(binary_name)
gdb.execute(f"file {binary}")
out = gdb.execute("got", to_string=True).splitlines()
assert out == ["got: The program is not being run."]
gdb.execute("starti")
out2 = gdb.execute("got", to_string=True).splitlines()
assert out != out2
assert len(out2) == 2
assert out2[0] == "GOT protection: Full RELRO | GOT functions: 1"
assert re.match(r"\[0x[0-9a-f]+\] puts@GLIBC_[0-9.]+ -> .*", out2[1])
Loading…
Cancel
Save