Skip to content

Commit

Permalink
Add an "--all" option to the got command (#1101)
Browse files Browse the repository at this point in the history
## Description

This change adds a `got --all`  option which expands on the existing "got"
command by providing data about relocations in mapped shared object
files in addition to the relocations specific to the main executable.

Particularly for auditing purposes, users may be interested in the state
of all relocations, not only those for the primary executable file.
  • Loading branch information
gordonmessmer committed Jun 1, 2024
1 parent 757f5bb commit f0b6d1d
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 5 deletions.
13 changes: 12 additions & 1 deletion docs/commands/got.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ The `got` command optionally takes function names and filters the output display
matching functions.

```text
gef➤ got
gef➤ got [--all] [filters]
```

`--all` Print the GOT for all shared objects in addition to the executable file

![gef-got](https://i.imgur.com/554ebM3.png)

The applied filter partially matches the name of the functions, so you can do something like this.
Expand All @@ -28,3 +30,12 @@ gef➤ got str get
```

![gef-got-multi-filter](https://i.imgur.com/7L2uLt8.png)

```text
gef➤ got --all str get
```

Print relocatable symbols matching "str" or "get" in the executable and all shared object files.

**Note**: Because gdbserver does not canonicalize paths, the --all option does not work correctly
for remote debugging. See gdb bug [23764](https://sourceware.org/bugzilla/show_bug.cgi?id=23764)
21 changes: 17 additions & 4 deletions gef.py
Original file line number Diff line number Diff line change
Expand Up @@ -9290,11 +9290,24 @@ def build_line(self, name: str, color: str, address_val: int, got_address: int)
return line

@only_if_gdb_running
def do_invoke(self, argv: List[str]) -> None:
@parse_arguments({"symbols": [""]}, {"--all": False})
def do_invoke(self, _: List[str], **kwargs: Any) -> None:
args : argparse.Namespace = kwargs["arguments"]
if args.all:
vmmap = gef.memory.maps
mapfiles = set(mapfile.path for mapfile in vmmap if
pathlib.Path(mapfile.realpath).is_file() and
mapfile.permission & Permission.EXECUTE)
for mapfile in mapfiles:
self.print_got_for(mapfile, args.symbols)
else:
self.print_got_for(str(gef.session.file), args.symbols)

def print_got_for(self, file: str, argv: List[str]) -> None:
readelf = gef.session.constants["readelf"]

elf_file = str(gef.session.file)
elf_virtual_path = str(gef.session.file)
elf_file = file
elf_virtual_path = file

func_names_filter = argv if argv else []
vmmap = gef.memory.maps
Expand All @@ -9318,7 +9331,7 @@ def do_invoke(self, argv: List[str]) -> None:
lines = gef_execute_external([readelf, "--wide", "--relocs", elf_file], as_list=True)
jmpslots = [line for line in lines if "JUMP" in line]

gef_print(f"\nGOT protection: {relro_status} | GOT functions: {len(jmpslots)}\n ")
gef_print(f"{titlify(file)}\n\nGOT protection: {relro_status} | GOT functions: {len(jmpslots)}\n ")

for line in jmpslots:
address, _, _, _, name = line.split()[:5]
Expand Down
33 changes: 33 additions & 0 deletions tests/commands/got.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,36 @@ def test_cmd_got(self):
res = gdb.execute("got printf", to_string=True)
self.assertIn("printf", res)
self.assertNotIn("strcpy", res)
self.assertNotIn("/libc", res)

def checksyms(lines):
if not lines:
return None
if "format-string-helper.out" in lines[0]:
res = ''.join(lines)
self.assertIn(" printf", res)
self.assertNotIn(" strcpy", res)
return "format-string-helper.out"
if "/libc" in lines[0]:
res = ''.join(lines)
self.assertNotIn(" printf", res)
self.assertNotIn(" strcpy", res)
return "libc"
return None

res = gdb.execute("got --all printf", to_string=True)
# Keep a list of output blocks describing files mapped in the process
checked_sections = []
# Iterate over lines of output and assemble blocks. When a new block
# is found, or when the end of output is reached, check the output
# block for symbols expected in that block.
lines = []
for line in res.splitlines():
if line.startswith("─"):
checked_sections.append(checksyms(lines))
lines = []
lines.append(line)
checked_sections.append(checksyms(lines))
# Make sure that both the executable and libc sections were found.
self.assertIn("format-string-helper.out", checked_sections)
self.assertIn("libc", checked_sections)

0 comments on commit f0b6d1d

Please sign in to comment.