|
|
|
@ -3,6 +3,7 @@ from __future__ import annotations
|
|
|
|
import argparse
|
|
|
|
import argparse
|
|
|
|
import functools
|
|
|
|
import functools
|
|
|
|
import io
|
|
|
|
import io
|
|
|
|
|
|
|
|
import logging
|
|
|
|
from enum import Enum
|
|
|
|
from enum import Enum
|
|
|
|
from typing import Any
|
|
|
|
from typing import Any
|
|
|
|
from typing import Callable
|
|
|
|
from typing import Callable
|
|
|
|
@ -22,12 +23,13 @@ import pwndbg.gdblib.kernel
|
|
|
|
import pwndbg.gdblib.proc
|
|
|
|
import pwndbg.gdblib.proc
|
|
|
|
import pwndbg.gdblib.qemu
|
|
|
|
import pwndbg.gdblib.qemu
|
|
|
|
import pwndbg.gdblib.regs
|
|
|
|
import pwndbg.gdblib.regs
|
|
|
|
from pwndbg.color import message
|
|
|
|
|
|
|
|
from pwndbg.gdblib.heap.ptmalloc import DebugSymsHeap
|
|
|
|
from pwndbg.gdblib.heap.ptmalloc import DebugSymsHeap
|
|
|
|
from pwndbg.gdblib.heap.ptmalloc import GlibcMemoryAllocator
|
|
|
|
from pwndbg.gdblib.heap.ptmalloc import GlibcMemoryAllocator
|
|
|
|
from pwndbg.gdblib.heap.ptmalloc import HeuristicHeap
|
|
|
|
from pwndbg.gdblib.heap.ptmalloc import HeuristicHeap
|
|
|
|
from pwndbg.gdblib.heap.ptmalloc import SymbolUnresolvableError
|
|
|
|
from pwndbg.gdblib.heap.ptmalloc import SymbolUnresolvableError
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
|
|
|
T = TypeVar("T")
|
|
|
|
T = TypeVar("T")
|
|
|
|
P = ParamSpec("P")
|
|
|
|
P = ParamSpec("P")
|
|
|
|
|
|
|
|
|
|
|
|
@ -266,9 +268,9 @@ def OnlyWithFile(function: Callable[P, T]) -> Callable[P, Optional[T]]:
|
|
|
|
return function(*a, **kw)
|
|
|
|
return function(*a, **kw)
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
if pwndbg.gdblib.qemu.is_qemu():
|
|
|
|
if pwndbg.gdblib.qemu.is_qemu():
|
|
|
|
print(message.error("Could not determine the target binary on QEMU."))
|
|
|
|
log.error("Could not determine the target binary on QEMU.")
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
print(message.error(f"{function.__name__}: There is no file loaded."))
|
|
|
|
log.error(f"{function.__name__}: There is no file loaded.")
|
|
|
|
return None
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
return _OnlyWithFile
|
|
|
|
return _OnlyWithFile
|
|
|
|
@ -280,7 +282,7 @@ def OnlyWhenQemuKernel(function: Callable[P, T]) -> Callable[P, Optional[T]]:
|
|
|
|
if pwndbg.gdblib.qemu.is_qemu_kernel():
|
|
|
|
if pwndbg.gdblib.qemu.is_qemu_kernel():
|
|
|
|
return function(*a, **kw)
|
|
|
|
return function(*a, **kw)
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
print(
|
|
|
|
log.error(
|
|
|
|
f"{function.__name__}: This command may only be run when debugging the Linux kernel in QEMU."
|
|
|
|
f"{function.__name__}: This command may only be run when debugging the Linux kernel in QEMU."
|
|
|
|
)
|
|
|
|
)
|
|
|
|
return None
|
|
|
|
return None
|
|
|
|
@ -294,7 +296,7 @@ def OnlyWhenUserspace(function: Callable[P, T]) -> Callable[P, Optional[T]]:
|
|
|
|
if not pwndbg.gdblib.qemu.is_qemu_kernel():
|
|
|
|
if not pwndbg.gdblib.qemu.is_qemu_kernel():
|
|
|
|
return function(*a, **kw)
|
|
|
|
return function(*a, **kw)
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
print(
|
|
|
|
log.error(
|
|
|
|
f"{function.__name__}: This command may only be run when not debugging a QEMU kernel target."
|
|
|
|
f"{function.__name__}: This command may only be run when not debugging a QEMU kernel target."
|
|
|
|
)
|
|
|
|
)
|
|
|
|
return None
|
|
|
|
return None
|
|
|
|
@ -317,9 +319,8 @@ def OnlyWithArch(arch_names: List[str]) -> Callable[[Callable[P, T]], Callable[P
|
|
|
|
return function(*a, **kw)
|
|
|
|
return function(*a, **kw)
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
arches_str = ", ".join(arch_names)
|
|
|
|
arches_str = ", ".join(arch_names)
|
|
|
|
print(
|
|
|
|
log.error(
|
|
|
|
f"%s: This command may only be run on the {arches_str} architecture(s)"
|
|
|
|
f"{function.__name__}: This command may only be run on the {arches_str} architecture(s)"
|
|
|
|
% function.__name__
|
|
|
|
|
|
|
|
)
|
|
|
|
)
|
|
|
|
return None
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
@ -334,7 +335,7 @@ def OnlyWithKernelDebugSyms(function: Callable[P, T]) -> Callable[P, Optional[T]
|
|
|
|
if pwndbg.gdblib.kernel.has_debug_syms():
|
|
|
|
if pwndbg.gdblib.kernel.has_debug_syms():
|
|
|
|
return function(*a, **kw)
|
|
|
|
return function(*a, **kw)
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
print(
|
|
|
|
log.error(
|
|
|
|
f"{function.__name__}: This command may only be run when debugging a Linux kernel with debug symbols."
|
|
|
|
f"{function.__name__}: This command may only be run when debugging a Linux kernel with debug symbols."
|
|
|
|
)
|
|
|
|
)
|
|
|
|
return None
|
|
|
|
return None
|
|
|
|
@ -348,7 +349,7 @@ def OnlyWhenPagingEnabled(function: Callable[P, T]) -> Callable[P, Optional[T]]:
|
|
|
|
if pwndbg.gdblib.kernel.paging_enabled():
|
|
|
|
if pwndbg.gdblib.kernel.paging_enabled():
|
|
|
|
return function(*a, **kw)
|
|
|
|
return function(*a, **kw)
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
print(f"{function.__name__}: This command may only be run when paging is enabled.")
|
|
|
|
log.error(f"{function.__name__}: This command may only be run when paging is enabled.")
|
|
|
|
return None
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
return _OnlyWhenPagingEnabled
|
|
|
|
return _OnlyWhenPagingEnabled
|
|
|
|
@ -360,7 +361,7 @@ def OnlyWhenRunning(function: Callable[P, T]) -> Callable[P, Optional[T]]:
|
|
|
|
if pwndbg.gdblib.proc.alive:
|
|
|
|
if pwndbg.gdblib.proc.alive:
|
|
|
|
return function(*a, **kw)
|
|
|
|
return function(*a, **kw)
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
print(f"{function.__name__}: The program is not being run.")
|
|
|
|
log.error(f"{function.__name__}: The program is not being run.")
|
|
|
|
return None
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
return _OnlyWhenRunning
|
|
|
|
return _OnlyWhenRunning
|
|
|
|
@ -373,7 +374,7 @@ def OnlyWithTcache(function: Callable[P, T]) -> Callable[P, Optional[T]]:
|
|
|
|
if pwndbg.gdblib.heap.current.has_tcache():
|
|
|
|
if pwndbg.gdblib.heap.current.has_tcache():
|
|
|
|
return function(*a, **kw)
|
|
|
|
return function(*a, **kw)
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
print(
|
|
|
|
log.error(
|
|
|
|
f"{function.__name__}: This version of GLIBC was not compiled with tcache support."
|
|
|
|
f"{function.__name__}: This version of GLIBC was not compiled with tcache support."
|
|
|
|
)
|
|
|
|
)
|
|
|
|
return None
|
|
|
|
return None
|
|
|
|
@ -387,7 +388,7 @@ def OnlyWhenHeapIsInitialized(function: Callable[P, T]) -> Callable[P, Optional[
|
|
|
|
if pwndbg.gdblib.heap.current is not None and pwndbg.gdblib.heap.current.is_initialized():
|
|
|
|
if pwndbg.gdblib.heap.current is not None and pwndbg.gdblib.heap.current.is_initialized():
|
|
|
|
return function(*a, **kw)
|
|
|
|
return function(*a, **kw)
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
print(f"{function.__name__}: Heap is not initialized yet.")
|
|
|
|
log.error(f"{function.__name__}: Heap is not initialized yet.")
|
|
|
|
return None
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
return _OnlyWhenHeapIsInitialized
|
|
|
|
return _OnlyWhenHeapIsInitialized
|
|
|
|
@ -400,8 +401,8 @@ def _is_statically_linked() -> bool:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _try2run_heap_command(function: Callable[P, T], *a: P.args, **kw: P.kwargs) -> T | None:
|
|
|
|
def _try2run_heap_command(function: Callable[P, T], *a: P.args, **kw: P.kwargs) -> T | None:
|
|
|
|
e = lambda s: print(message.error(s))
|
|
|
|
e = log.error
|
|
|
|
w = lambda s: print(message.warn(s))
|
|
|
|
w = log.warning
|
|
|
|
# Note: We will still raise the error for developers when exception-* is set to "on"
|
|
|
|
# Note: We will still raise the error for developers when exception-* is set to "on"
|
|
|
|
try:
|
|
|
|
try:
|
|
|
|
return function(*a, **kw)
|
|
|
|
return function(*a, **kw)
|
|
|
|
@ -438,8 +439,8 @@ def _try2run_heap_command(function: Callable[P, T], *a: P.args, **kw: P.kwargs)
|
|
|
|
def OnlyWithResolvedHeapSyms(function: Callable[P, T]) -> Callable[P, T | None]:
|
|
|
|
def OnlyWithResolvedHeapSyms(function: Callable[P, T]) -> Callable[P, T | None]:
|
|
|
|
@functools.wraps(function)
|
|
|
|
@functools.wraps(function)
|
|
|
|
def _OnlyWithResolvedHeapSyms(*a: P.args, **kw: P.kwargs) -> T | None:
|
|
|
|
def _OnlyWithResolvedHeapSyms(*a: P.args, **kw: P.kwargs) -> T | None:
|
|
|
|
e = lambda s: print(message.error(s))
|
|
|
|
e = log.error
|
|
|
|
w = lambda s: print(message.warn(s))
|
|
|
|
w = log.warn
|
|
|
|
if (
|
|
|
|
if (
|
|
|
|
isinstance(pwndbg.gdblib.heap.current, HeuristicHeap)
|
|
|
|
isinstance(pwndbg.gdblib.heap.current, HeuristicHeap)
|
|
|
|
and pwndbg.config.resolve_heap_via_heuristic == "auto"
|
|
|
|
and pwndbg.config.resolve_heap_via_heuristic == "auto"
|
|
|
|
|