Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve GEF running under winedbg #1100

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 73 additions & 1 deletion gef.py
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,14 @@ def is_alive() -> bool:
return False


def is_wine() -> bool:
"""Check we're running under winedbg."""
try:
return "hwnd" in gdb.execute("monitor wnd", to_string=True)
except Exception:
return False


def calling_function() -> Optional[str]:
"""Return the name of the calling function"""
try:
Expand Down Expand Up @@ -646,6 +654,15 @@ def from_monitor_info_mem(cls, perm_str: str) -> "Permission":
if perm_str[2] == "w": perm |= Permission.WRITE
return perm

@classmethod
def from_monitor_mem(cls, perm_str: str) -> "Permission":
perm = cls(0)
perm_str = perm_str.ljust(3)
if perm_str[0] == "R": perm |= Permission.READ
if perm_str[1] == "W": perm |= Permission.WRITE
if perm_str[2] == "X": perm |= Permission.EXECUTE
return perm

@classmethod
def from_info_mem(cls, perm_str: str) -> "Permission":
perm = cls(0)
Expand Down Expand Up @@ -2833,7 +2850,7 @@ def is_branch_taken(self, insn: Instruction) -> Tuple[bool, str]:


class X86(Architecture):
aliases: Tuple[Union[str, Elf.Abi], ...] = ("X86", Elf.Abi.X86_32)
aliases: Tuple[Union[str, Elf.Abi], ...] = ("X86", "i386", Elf.Abi.X86_32)
arch = "X86"
mode = "32"

Expand Down Expand Up @@ -3771,6 +3788,8 @@ def reset_architecture(arch: Optional[str] = None) -> None:
# check for bin running
if is_alive():
gdb_arch = gdb.selected_frame().architecture().name()
if gdb_arch in arches:
gef.arch = arches[gdb_arch]()
preciser_arch = next((a for a in arches.values() if a.supports_gdb_arch(gdb_arch)), None)
if preciser_arch:
gef.arch = preciser_arch()
Expand Down Expand Up @@ -7512,6 +7531,9 @@ def do_invoke(self, argv: List[str]) -> None:
if not self["enable"] or gef.ui.context_hidden:
return

if type(gef.arch) == GenericArchitecture:
return

if not all(_ in self.layout_mapping for _ in argv):
self.usage()
return
Expand Down Expand Up @@ -10632,6 +10654,11 @@ def __parse_maps(self) -> Optional[List[Section]]:
except:
pass

try:
return list(self.parse_monitor_mem())
except:
pass

raise RuntimeError("Failed to get memory layout")

@classmethod
Expand Down Expand Up @@ -10747,6 +10774,37 @@ def parse_monitor_info_mem(cls) -> Generator[Section, None, None]:
offset=off,
permission=perm)

@classmethod
def parse_monitor_mem(cls) -> Generator[Section, None, None]:
"""If we're running under winedbg, we can use `monitor mem` to get memory mappings
This can raise an exception, which the memory manager takes to mean
that this method does not work to get a map.
"""

# Expected output format:
# Address Size State Type RWX
# 00000000 00110000 free
# 00110000 00003000 commit mapped R X
# ...

stream = StringIO(gdb.execute("monitor mem", to_string=True))
for line in stream:
if line.startswith("Address"):
continue
try:
start, size, _, _, perms = line.split(maxsplit=5)
start = int(start, 16)
size = int(size, 16)
perms = perms.ljust(3)
end = start + size
except ValueError:
continue

perm = Permission.from_monitor_mem(perms)
yield Section(page_start=start,
page_end=end,
permission=perm)

@staticmethod
def parse_info_mem():
"""Get the memory mapping from GDB's command `info mem`. This can be
Expand Down Expand Up @@ -11104,6 +11162,8 @@ def auxiliary_vector(self) -> Optional[Dict[str, int]]:
return None
if is_qemu_system():
return None
if is_wine():
return None
if not self._auxiliary_vector:
auxiliary_vector = {}
auxv_info = gdb.execute("info auxv", to_string=True) or ""
Expand Down Expand Up @@ -11221,6 +11281,7 @@ class RemoteMode(enum.IntEnum):
GDBSERVER = 0
QEMU = 1
RR = 2
WINEDBG = 3

def __str__(self):
return self.name
Expand All @@ -11235,6 +11296,8 @@ def prompt_string(self) -> str:
return Color.boldify("(rr) ")
if self == GefRemoteSessionManager.RemoteMode.GDBSERVER:
return Color.boldify("(remote) ")
if self == GefRemoteSessionManager.RemoteMode.WINEDBG:
return Color.boldify("(winedbg) ")
raise AttributeError("Unknown value")

def __init__(self, host: str, port: int, pid: int =-1, qemu: Optional[pathlib.Path] = None) -> None:
Expand All @@ -11249,6 +11312,8 @@ def __init__(self, host: str, port: int, pid: int =-1, qemu: Optional[pathlib.Pa
self._mode = GefRemoteSessionManager.RemoteMode.QEMU
elif os.environ.get("GDB_UNDER_RR", None) == "1":
self._mode = GefRemoteSessionManager.RemoteMode.RR
elif is_wine():
self._mode = GefRemoteSessionManager.RemoteMode.WINEDBG
else:
self._mode = GefRemoteSessionManager.RemoteMode.GDBSERVER

Expand Down Expand Up @@ -11354,6 +11419,9 @@ def setup(self) -> bool:
elif self.mode == GefRemoteSessionManager.RemoteMode.RR:
dbg(f"Setting up as rr session")
self.__setup_rr()
elif self.mode == GefRemoteSessionManager.RemoteMode.WINEDBG:
dbg(f"Setting up as winedbg session")
self.__setup_winedbg()
elif self.mode == GefRemoteSessionManager.RemoteMode.GDBSERVER:
dbg(f"Setting up as remote session")
self.__setup_remote()
Expand Down Expand Up @@ -11415,6 +11483,10 @@ def __setup_remote(self) -> bool:

return True

def __setup_winedbg(self) -> bool:
reset_architecture()
return True

def __setup_rr(self) -> bool:
#
# Simply override the local root path, the binary must exist
Expand Down
Loading