Skip to content

Commit

Permalink
first run of pr feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
hugsy committed Jan 12, 2022
1 parent bf70642 commit bdea715
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 46 deletions.
11 changes: 5 additions & 6 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@ Here is the most basic skeleton for creating a new `GEF` command named `newcmd`:
class NewCommand(GenericCommand):
"""Dummy new command."""
_cmdline_ = "newcmd"
_syntax_ = f"{_cmdline_:s}"
_syntax_ = f"{_cmdline_}"

@only_if_gdb_running # not required, ensures that the debug session is started
def do_invoke(self, argv):
# let's say we want to print some info about the architecture of the current binary
print(f"{gef.arch=}")
print(f"gef.arch={gef.arch}")
# or showing the current $pc
print(f"{gef.arch.pc=:#x}")
print(f"gef.arch.pc={gef.arch.pc:#x}")
return

register_external_command(NewCommand())
Expand Down Expand Up @@ -154,13 +154,12 @@ gef ➤ pi print('\n'.join([ f"{x.page_start:#x} -> {x.page_end:#x}" for x in ge
```


The API also offers a number of decorators to simply the creation of new/existing commands, such as:
The API also offers a number of decorators to simplify the creation of new/existing commands, such as:
- `@only_if_gdb_running` to execute only if a GDB session is running.
- `@only_if_gdb_target_local` to check if the current GDB session is local i.e. not debugging using GDB `remote`.
- `@only_if_gdb_target_local` to check if the target is local i.e. not debugging using GDB `remote`.
- and many more...



### Reference

For a complete reference of the API offered by GEF, visit [`docs/api/gef.md`](api/gef.md).
Expand Down
6 changes: 3 additions & 3 deletions docs/compat.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ This matrix indicates the version of Python and/or GDB

| GEF version | GDB Python compatibility* | Python compatibility* |
|:--:|:--:|:--:|
| [2018.02](https://github.com/hugsy/gef/releases/tag/2018.02) | 7.2 | Python 2.7, Python 3.4 |
| [2020.03](https://github.com/hugsy/gef/releases/tag/2020.03) | 7.4 | Python 2.7, Python 3.4 |
| [2022.01](https://github.com/hugsy/gef/releases/tag/2021.01) | 7.7 | Python 3.4 |
| [2018.02](https://github.com/hugsy/gef/releases/tag/2018.02) | 7.2 | Python 2.7, Python 3.4+ |
| [2020.03](https://github.com/hugsy/gef/releases/tag/2020.03) | 7.4 | Python 2.7, Python 3.4+ |
| [2022.01](https://github.com/hugsy/gef/releases/tag/2021.01) | 7.7 | Python 3.4+ |
| [Current](https://github.com/hugsy/gef/tree/master) | 8.0+ | Python 3.6+ |


Expand Down
67 changes: 37 additions & 30 deletions gef.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@
from io import StringIO
from types import ModuleType
from typing import (List, Dict, Tuple, Optional, Sequence, Union, Generator, Any, Iterator,
Callable, ByteString, Set, Type)
Callable, ByteString, Set, Type, NoReturn)
from urllib.request import urlopen


Expand Down Expand Up @@ -153,10 +153,10 @@ def update_gef(argv: List[str]) -> int:
GEF_PROMPT_OFF = f"\001\033[1;31m\002{GEF_PROMPT}\001\033[0m\002"


gef : "Gef" = None
__registered_commands__ : List["GenericCommand"] = []
__registered_functions__ : List["GenericFunction"] = []
__registered_architectures__ : Dict[Union[int, str], "Architecture"] = {}
gef : "Gef" = None
__registered_commands__ : List[Type["GenericCommand"]] = []
__registered_functions__ : List[Type["GenericFunction"]] = []
__registered_architectures__ : Dict[Union[int, str], Type["Architecture"]] = {}


def reset_all_caches() -> None:
Expand Down Expand Up @@ -234,7 +234,7 @@ def bufferize(f: Callable) -> Callable:
"""Store the content to be printed for a function in memory, and flush it on function exit."""

@functools.wraps(f)
def wrapper(*args: Tuple, **kwargs: Dict) -> Any:
def wrapper(*args: Any, **kwargs: Any) -> Any:
global gef

if gef.ui.stream_buffer:
Expand Down Expand Up @@ -335,7 +335,7 @@ def only_if_gdb_running(f: Callable) -> Callable:
"""Decorator wrapper to check if GDB is running."""

@functools.wraps(f)
def wrapper(*args: Tuple, **kwargs: Dict) -> Any:
def wrapper(*args: Any, **kwargs: Any) -> Any:
if is_alive():
return f(*args, **kwargs)
else:
Expand All @@ -348,7 +348,7 @@ def only_if_gdb_target_local(f: Callable) -> Callable:
"""Decorator wrapper to check if GDB is running locally (target not remote)."""

@functools.wraps(f)
def wrapper(*args: Tuple, **kwargs: Dict) -> Any:
def wrapper(*args: Any, **kwargs: Any) -> Any:
if not is_remote_debug():
return f(*args, **kwargs)
else:
Expand Down Expand Up @@ -427,7 +427,7 @@ def wrapped_f(*args: Tuple, **kwargs: Dict) -> Any:
return wrap


def FakeExit(*args, **kwargs) -> None:
def FakeExit(*args, **kwargs) -> NoReturn:
raise RuntimeWarning

sys.exit = FakeExit
Expand All @@ -438,7 +438,7 @@ def parse_arguments(required_arguments: Dict, optional_arguments: Dict) -> Optio
def int_wrapper(x: str) -> int: return int(x, 0)

def decorator(f: Callable) -> Optional[Callable]:
def wrapper(*args: Tuple, **kwargs: Dict) -> Optional[Callable]:
def wrapper(*args: Any, **kwargs: Any) -> Optional[Callable]:
parser = argparse.ArgumentParser(prog=args[0]._cmdline_, add_help=True)
for argname in required_arguments:
argvalue = required_arguments[argname]
Expand All @@ -455,10 +455,10 @@ def wrapper(*args: Tuple, **kwargs: Dict) -> Optional[Callable]:
parser.add_argument(argname, type=argtype, required=True, default=argvalue)
else:
if argtype in (list, tuple):
nargs = '*'
nargs = "*"
argtype = type(argvalue[0])
else:
nargs = '?'
nargs = "?"
# positional args
parser.add_argument(argname, type=argtype, default=argvalue, nargs=nargs)

Expand Down Expand Up @@ -598,7 +598,7 @@ class Permission:
EXECUTE = 4
ALL = READ | WRITE | EXECUTE

def __init__(self, **kwargs) -> None:
def __init__(self, **kwargs: Any) -> None:
self.value = kwargs.get("value", 0)
return

Expand All @@ -625,7 +625,7 @@ def __str__(self) -> str:
return perm_str

@staticmethod
def from_info_sections(*args: List[str]):
def from_info_sections(*args: List[str]) -> "Permission":
perm = Permission()
for arg in args:
if "READONLY" in arg:
Expand All @@ -637,7 +637,7 @@ def from_info_sections(*args: List[str]):
return perm

@staticmethod
def from_process_maps(perm_str: str):
def from_process_maps(perm_str: str) -> "Permission":
perm = Permission()
if perm_str[0] == "r":
perm.value += Permission.READ
Expand Down Expand Up @@ -681,7 +681,8 @@ def realpath(self) -> str:
return self.path if gef.session.remote is None else f"/tmp/gef/{gef.session.remote:d}/{self.path}"

def __str__(self) -> str:
return f"Section({self.page_start:#x}, {self.page_end:#x}, {self.permission!s})"
return (f"Section(page_start={self.page_start:#x}, page_end={self.page_end:#x}, "
f"permissions={self.permission!s})")


Zone = collections.namedtuple("Zone", ["name", "zone_start", "zone_end", "filename"])
Expand Down Expand Up @@ -934,7 +935,7 @@ class Shdr:
sh_addralign = None
sh_entsize = None

def __init__(self, elf, off) -> None:
def __init__(self, elf: Optional[Elf], off: int) -> None:
if elf is None:
return
elf.seek(off)
Expand Down Expand Up @@ -1001,16 +1002,22 @@ def is_valid(self) -> bool:

@lru_cache()
def search_for_main_arena(to_string: bool = False) -> Union[int, str]:
malloc_hook_addr = parse_address("(void *)&__malloc_hook")
"""A helper function to find the libc `main_arena` address, either from symbol or from its offset
from `__malloc_hook`."""
try:
addr = int(parse_address(f"&{LIBC_HEAP_MAIN_ARENA_DEFAULT_NAME}"))

if is_x86():
addr = align_address_to_size(malloc_hook_addr + gef.arch.ptrsize, 0x20)
elif is_arch(Elf.AARCH64):
addr = malloc_hook_addr - gef.arch.ptrsize*2 - MallocStateStruct("*0").struct_size
elif is_arch(Elf.ARM):
addr = malloc_hook_addr - gef.arch.ptrsize - MallocStateStruct("*0").struct_size
else:
raise OSError(f"Cannot find main_arena for {gef.arch.arch}")
except gdb.error:
malloc_hook_addr = parse_address("(void *)&__malloc_hook")

if is_x86():
addr = align_address_to_size(malloc_hook_addr + gef.arch.ptrsize, 0x20)
elif is_arch(Elf.AARCH64):
addr = malloc_hook_addr - gef.arch.ptrsize*2 - MallocStateStruct("*0").struct_size
elif is_arch(Elf.ARM):
addr = malloc_hook_addr - gef.arch.ptrsize - MallocStateStruct("*0").struct_size
else:
raise OSError(f"Cannot find main_arena for {gef.arch.arch}")

if to_string:
addr = f"*{addr:#x}"
Expand Down Expand Up @@ -1679,12 +1686,12 @@ def is_debug() -> bool:
return gef.config["gef.debug"] is True

def hide_context() -> bool:
""" Helper function to hide the context pane """
"""Helper function to hide the context pane."""
gef.ui.context_hidden = True
return True

def unhide_context() -> bool:
""" Helper function to unhide the context pane """
"""Helper function to unhide the context pane."""
gef.ui.context_hidden = False
return True

Expand Down Expand Up @@ -4590,7 +4597,7 @@ def do_invoke(self, argv: List) -> None:
class PrintFormatCommand(GenericCommand):
"""Print bytes format in commonly used formats, such as literals in high level languages."""

valid_formats = ("py", "c", "js", "asm")
valid_formats = ("py", "c", "js", "asm", "hex")
valid_bitness = (8, 16, 32, 64)

_cmdline_ = "print-format"
Expand Down Expand Up @@ -4655,7 +4662,7 @@ def do_invoke(self, argv: List, *args: Tuple[Any, ...], **kwargs: Dict[str, Any]
asm_type = self.format_matrix[args.bitlen][2]
out = "buf {0} {1}".format(asm_type, sdata)
elif args.lang == "hex":
out = binascii.hexlify(read_memory(start_addr, end_addr-start_addr)).decode()
out = binascii.hexlify(gef.memory.read(start_addr, end_addr-start_addr)).decode()

if args.clip:
if copy_to_clipboard(gef_pybytes(out)):
Expand Down
22 changes: 18 additions & 4 deletions tests/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,13 +161,27 @@ def _target(name: str, extension: str = ".out") -> Path:
return target


def start_gdbserver(exe=_target("default"), port=1234):
def start_gdbserver(exe : Union[str, Path]=_target("default"), port : int=1234) -> subprocess.Popen:
"""Start a gdbserver on the target binary.
Args:
exe (str, optional): the binary to execute. Defaults to _target("default").
port (int, optional): the port to make gdbserver listen on. Defaults to 1234.
Returns:
subprocess.Popen: a Popen object for the gdbserver process.
"""
return subprocess.Popen(["gdbserver", f":{port}", exe],
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)

def stop_gdbserver(gdbserver):
"""Stops the gdbserver and waits until it is terminated if it was
still running. Needed to make the used port available again."""

def stop_gdbserver(gdbserver: subprocess.Popen) -> None:
"""Stop the gdbserver and waits until it is terminated if it was
still running. Needed to make the used port available again.
Args:
gdbserver (subprocess.Popen): the gdbserver process to stop.
"""
if gdbserver.poll() is None:
gdbserver.kill()
gdbserver.wait()
Expand Down
6 changes: 3 additions & 3 deletions tests/runtests.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ def test_cmd_heap_chunks(self):
self.assertIn("Chunk(addr=", res)
self.assertIn("top chunk", res)

cmd = "python gdb.execute('heap chunks 0x{:x}'.format(int(list(gef.heap.arenas)[1])))"
cmd = "python gdb.execute(f'heap chunks {int(list(gef.heap.arenas)[1]):#x}')"
target = _target("heap-non-main")
res = gdb_run_silent_cmd(cmd, target=target)
self.assertNoException(res)
Expand All @@ -258,7 +258,7 @@ def test_cmd_heap_chunks(self):
return

def test_cmd_heap_chunks_mult_heaps(self):
py_cmd = 'gdb.execute("heap set-arena 0x{:x}".format(int(list(gef.heap.arenas)[1])))'
py_cmd = 'gdb.execute(f"heap set-arena 0x{int(list(gef.heap.arenas)[1]):x}")'
before = ['run', 'python ' + py_cmd]
cmd = "heap chunks"
target = _target("heap-multiple-heaps")
Expand Down Expand Up @@ -894,7 +894,7 @@ def test_func_parse_address(self):

def test_func_download_file(self):
gdbsrv = start_gdbserver(BIN_LS)
func = f"download_file('{str(BIN_LS)}')"
func = f"download_file('{BIN_LS!s}')"
res = gdb_test_python_method(func)
stop_gdbserver(gdbsrv)
self.assertNoException(res)
Expand Down

0 comments on commit bdea715

Please sign in to comment.