Skip to content

Commit

Permalink
Merge branch 'dev' of github.com:hugsy/gef into allow_new_file_format
Browse files Browse the repository at this point in the history
  • Loading branch information
hugsy committed Jun 26, 2022
2 parents 09b2f13 + d594eb3 commit 7925b0a
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 30 deletions.
71 changes: 50 additions & 21 deletions gef.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
import platform
import re
import shutil
import site
import socket
import string
import struct
Expand All @@ -80,8 +81,9 @@
from functools import lru_cache
from io import StringIO, TextIOWrapper
from types import ModuleType
from typing import (Any, ByteString, Callable, Dict, Generator, IO, Iterable, Iterator, List,
NoReturn, Optional, Sequence, Set, Tuple, Type, Union)
from typing import (Any, ByteString, Callable, Dict, Generator, Iterable,
Iterator, List, NoReturn, Optional, Sequence, Tuple, Type,
Union)
from urllib.request import urlopen


Expand Down Expand Up @@ -9409,6 +9411,7 @@ def load_plugin(fpath: pathlib.Path) -> bool:
return True

nb_added = -1
start_time = time.perf_counter()
try:
nb_inital = len(__registered_commands__)
directories: List[str] = gef.config["gef.extra_plugins_dir"].split(";") or []
Expand All @@ -9430,8 +9433,10 @@ def load_plugin(fpath: pathlib.Path) -> bool:
nb_added = len(__registered_commands__) - nb_inital
if nb_added > 0:
self.load()
end_time = time.perf_counter()
load_time = end_time - start_time
ok(f"{Color.colorify(str(nb_added), 'bold green')} extra commands added from "
f"'{Color.colorify(', '.join(directories), 'bold blue')}'")
f"'{Color.colorify(', '.join(directories), 'bold blue')}' in {load_time:.2f} seconds")
except gdb.error as e:
err(f"failed: {e}")
return nb_added
Expand Down Expand Up @@ -9470,6 +9475,7 @@ def load(self) -> None:
current_functions = set( self.functions.keys() )
new_functions = set([x._function_ for x in __registered_functions__]) - current_functions
self.missing.clear()
self.__load_time_ms = time.perf_counter_ns()

# load all new functions
for name in sorted(new_functions):
Expand All @@ -9496,6 +9502,8 @@ def load(self) -> None:

except Exception as reason:
self.missing[name] = reason

self.__load_time_ms = (time.perf_counter_ns() - self.__load_time_ms) / 1000
return


Expand All @@ -9507,7 +9515,7 @@ def show_banner(self) -> None:
ver = f"{sys.version_info.major:d}.{sys.version_info.minor:d}"
gef_print(f"{Color.colorify(str(len(self.commands)), 'bold green')} commands loaded "
f"and {Color.colorify(str(len(self.functions)), 'bold blue')} functions added for "
f"GDB {Color.colorify(gdb.VERSION, 'bold yellow')} "
f"GDB {Color.colorify(gdb.VERSION, 'bold yellow')} in {self.__load_time_ms:.2f}ms "
f"using Python engine {Color.colorify(ver, 'bold red')}")

nb_missing = len(self.missing)
Expand Down Expand Up @@ -10349,60 +10357,78 @@ def malloc_align_address(self, address: int) -> int:

class GefSetting:
"""Basic class for storing gef settings as objects"""
READ_ACCESS = 0
WRITE_ACCESS = 1

def __init__(self, value: Any, cls: Optional[type] = None, description: Optional[str] = None, hooks: Optional[Dict[str, Callable]] = None) -> None:
self.value = value
self.type = cls or type(value)
self.description = description or ""
self.hooks: Tuple[List[Callable]] = ([], [])
self.hooks: Tuple[List[Callable], List[Callable]] = ([], [])
if hooks:
for access, func in hooks.items():
if access not in ("on_read", "on_write"):
raise ValueError(f"access not in (on_read, on_write)")
if access == "on_read":
idx = GefSetting.READ_ACCESS
elif access == "on_write":
idx = GefSetting.WRITE_ACCESS
else:
raise ValueError
if not callable(func):
raise ValueError(f"hook is not callable")
idx = 0 if (access == "on_read") else 1
self.hooks[idx].append(func)
return

def __str__(self) -> str:
return f"Setting(type={self.type.__name__}, value='{self.value}', desc='{self.description[:10]}...', "\
f"read_hooks={len(self.hooks[GefSetting.READ_ACCESS])}, write_hooks={len(self.hooks[GefSetting.READ_ACCESS])})"


class GefSettingsManager(dict):
"""
GefSettings acts as a dict where the global settings are stored and can be read, written or deleted as any other dict.
For instance, to read a specific command setting: `gef.config[mycommand.mysetting]`
"""
def __getitem__(self, name: str) -> Any:
setting : GefSetting = dict.__getitem__(self, name)
self.invoke_hooks(True, setting)
setting : GefSetting = super().__getitem__(name)
self.__invoke_read_hooks(setting)
return setting.value

def __setitem__(self, name: str, value: Any) -> None:
# check if the key exists
if dict.__contains__(self, name):
if super().__contains__(name):
# if so, update its value directly
setting = dict.__getitem__(self, name)
setting = super().__getitem__(name)
if not isinstance(setting, GefSetting): raise ValueError
setting.value = setting.type(value)
dict.__setitem__(self, name, setting)
self.invoke_hooks(False, setting)
else:
# if not, `value` must be a GefSetting
if not isinstance(value, GefSetting): raise Exception("Invalid argument")
if not value.type: raise Exception("Invalid type")
if not value.description: raise Exception("Invalid description")
dict.__setitem__(self, name, value)
setting = value
super().__setitem__(name, setting)
self.__invoke_write_hooks(setting)
return

def __delitem__(self, name: str) -> None:
dict.__delitem__(self, name)
super().__delitem__(name)
return

def raw_entry(self, name: str) -> GefSetting:
return dict.__getitem__(self, name)
return super().__getitem__(name)

def invoke_hooks(self, is_read: bool, setting: GefSetting) -> None:
def __invoke_read_hooks(self, setting: GefSetting) -> None:
self.__invoke_hooks(is_write=False, setting=setting)
return

def __invoke_write_hooks(self, setting: GefSetting) -> None:
self.__invoke_hooks(is_write=True, setting=setting)
return

def __invoke_hooks(self, is_write: bool, setting: GefSetting) -> None:
if not setting.hooks:
return
idx = 0 if is_read else 1
idx = int(is_write)
if setting.hooks[idx]:
for callback in setting.hooks[idx]:
callback()
Expand Down Expand Up @@ -10848,12 +10874,15 @@ def reset_caches(self) -> None:
except gdb.error:
pass

# load GEF
# load GEF, set up the managers and load the plugins, functions,
reset()
gef.gdb.load()
gef.gdb.show_banner()

# setup prompt
# load config
gef.gdb.load_extra_plugins()

# setup gdb prompt
gdb.prompt_hook = __gef_prompt__

# gdb events configuration
Expand Down
16 changes: 7 additions & 9 deletions tests/commands/print_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,29 +14,27 @@ def test_cmd_print_format(self):
self.assertFailIfInactiveSession(gdb_run_cmd("print-format"))
res = gdb_start_silent_cmd("print-format $sp")
self.assertNoException(res)
self.assertTrue("buf = [" in res)
self.assertIn("buf = [" , res)
res = gdb_start_silent_cmd("print-format --lang js $sp")
self.assertNoException(res)
self.assertTrue("var buf = [" in res)
self.assertIn("var buf = [" , res)
res = gdb_start_silent_cmd("set *((int*)$sp) = 0x41414141",
after=["print-format --lang hex $sp"])
self.assertNoException(res)
self.assertTrue("41414141" in res, f"{res}")
self.assertIn("41414141", res, f"{res}")
res = gdb_start_silent_cmd("print-format --lang iDontExist $sp")
self.assertNoException(res)
self.assertTrue("Language must be in:" in res)
self.assertIn("Language must be in:" , res)


def test_cmd_print_format_bytearray(self):
res = gdb_start_silent_cmd("set *((int*)$sp) = 0x41414141",
after=["print-format --lang bytearray -l 4 $sp"])
self.assertNoException(res)
try:
gef_var = res.split('$_gef')[1].split("'")[0]
except:
self.assertTrue(False)
gef_var = res.split('$_gef')[1].split("'")[0]
self.assertTrue("\x41\x41\x41\x41" in res)
res = gdb_start_silent_cmd("set *((int*)$sp) = 0x41414141",
after=["print-format --lang bytearray -l 4 $sp", "p $_gef" + gef_var])
self.assertNoException(res)
self.assertTrue("0x41, 0x41, 0x41, 0x41" in res)
self.assertIn(
f"Saved data b'AAAA'... in '$_gef{gef_var}'", res)

0 comments on commit 7925b0a

Please sign in to comment.