Port to aglib: onegadget (#2564)

* Port to aglib: onegadget

* onegadget: fix error handling
pull/2508/head^2
patryk4815 1 year ago committed by GitHub
parent 0076f108ab
commit 921ba71cf4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -23,6 +23,7 @@ def load_aglib():
import pwndbg.aglib.memory
import pwndbg.aglib.nearpc
import pwndbg.aglib.next
import pwndbg.aglib.onegadget
import pwndbg.aglib.proc
import pwndbg.aglib.qemu
import pwndbg.aglib.regs as regs_mod

@ -10,14 +10,14 @@ from typing import Any
from typing import Dict
from typing import Tuple
import gdb
from tabulate import tabulate
import pwndbg.aglib.arch
import pwndbg.aglib.file
import pwndbg.aglib.memory
import pwndbg.aglib.vmmap
import pwndbg.color.message as M
import pwndbg.gdblib.file
import pwndbg.gdblib.memory
import pwndbg.gdblib.vmmap
import pwndbg.dbg
import pwndbg.glibc
import pwndbg.lib.cache
import pwndbg.lib.tempfile
@ -36,12 +36,12 @@ CAST_PATTERN = re.compile(r"^\([s|u]\d+\)")
XMM_SHIFT = " >> "
CONSTRAINT_SEPARATOR = " || "
CAST_DEREF_MAPPING = {
"(u16)": pwndbg.gdblib.memory.u16,
"(s16)": pwndbg.gdblib.memory.s16,
"(u32)": pwndbg.gdblib.memory.u32,
"(s32)": pwndbg.gdblib.memory.s32,
"(u64)": pwndbg.gdblib.memory.u64,
"(s64)": pwndbg.gdblib.memory.s64,
"(u16)": pwndbg.aglib.memory.u16,
"(s16)": pwndbg.aglib.memory.s16,
"(u32)": pwndbg.aglib.memory.u32,
"(s32)": pwndbg.aglib.memory.s32,
"(u64)": pwndbg.aglib.memory.u64,
"(s64)": pwndbg.aglib.memory.s64,
}
CAST_MAPPING = {
"(u16)": lambda x: ctypes.c_uint16(x).value,
@ -128,7 +128,7 @@ class Lambda:
@property
def gdb_expr(self) -> str:
# TODO: Don't use gdb.parse_and_eval here, directly fetching the value with `pwndbg.gdblib.memory` would be better(?)
# TODO: Don't use gdb.parse_and_eval here, directly fetching the value with `pwndbg.aglib.memory` would be better(?)
obj = self.obj
if isinstance(obj, str):
if obj.startswith("xmm"):
@ -136,6 +136,13 @@ class Lambda:
# https://github.com/david942j/one_gadget/blob/65ce1dade70bf89e7496346ccf452ce5b2d139b3/lib/one_gadget/emulators/x86.rb#L242-L248
# So we can hardcode the shifting :p
# TODO: Handle xmm register in a better way
# TODO: In LLDB this syntax is invalid:
# error: <user expression 62>:1:23: illegal vector component name 'v'
# 1 | ((unsigned long)($xmm0.v2_int64[1]))
# | ^~~~~~~~~
# while parsing (u64)xmm0 >> 64 for argv[1]
bits = pwndbg.aglib.arch.ptrsize * 8
if XMM_SHIFT in obj:
obj = obj.replace(XMM_SHIFT + str(bits), f".v{128 // bits}_int{bits}[1]")
@ -269,9 +276,7 @@ def run_onegadget() -> str:
"""
Run onegadget and return the output
"""
libc_path = pwndbg.gdblib.file.get_file(
pwndbg.glibc.get_libc_filename_from_info_sharedlibrary()
)
libc_path = pwndbg.aglib.file.get_file(pwndbg.glibc.get_libc_filename_from_info_sharedlibrary())
# We need cache because onegadget might be slow
cache_file = os.path.join(ONEGADGET_CACHEDIR, compute_file_hash(libc_path))
if os.path.exists(cache_file):
@ -300,6 +305,7 @@ def parse_expression(expr: str) -> Tuple[int | None, str, str | None]:
lambda_expr = Lambda.parse(expr)
if not isinstance(lambda_expr, Lambda):
return lambda_expr, expr, None
gdb_expr = lambda_expr.gdb_expr
try:
if cast:
@ -307,13 +313,23 @@ def parse_expression(expr: str) -> Tuple[int | None, str, str | None]:
# Remove the first *, we use cast to handle it instead of unsigned long
gdb_expr = gdb_expr.lstrip("*")
# Now gdb_expr is a pointer, we need dereference it with cast
result = CAST_DEREF_MAPPING[cast](int(gdb.parse_and_eval(gdb_expr)))
addr = int(pwndbg.dbg.selected_inferior().evaluate_expression(gdb_expr))
result = CAST_DEREF_MAPPING[cast](addr)
else:
result = CAST_MAPPING[cast](int(gdb.parse_and_eval(gdb_expr)))
addr = int(pwndbg.dbg.selected_inferior().evaluate_expression(gdb_expr))
result = CAST_MAPPING[cast](addr)
else:
result = int(gdb.parse_and_eval(gdb_expr))
addr = int(pwndbg.dbg.selected_inferior().evaluate_expression(gdb_expr))
result = addr
return result, f"{cast}{lambda_expr.color_str}", None
except gdb.error as e:
except pwndbg.dbg_mod.Error as e:
error_message = (
f"Pwndbg encountered an issue while evaluating the expression: {cast}{lambda_expr.color_str}\n"
f"Error details: {str(e)}\n"
f"Consider creating an issue in the pwndbg repository."
)
print(M.warn(error_message))
return None, f"{cast}{lambda_expr.color_str}", str(e)
@ -352,14 +368,14 @@ def check_stack_argv(expr: str) -> Tuple[CheckSatResult, str]:
if n > 1:
return UNKNOWN, output_msg
return SAT, output_msg
page = pwndbg.gdblib.vmmap.find(result)
page = pwndbg.aglib.vmmap.find(result)
if page is None or not page.read:
output_msg += (
f"argv[{n}] = {color_str} = {result:#x}, {color_str} is not a valid address\n"
)
return UNSAT, output_msg
if n > 0:
output_msg += f"argv[{n}] = {color_str} = {result:#x} -> {bytes(pwndbg.gdblib.memory.string(result))!r}\n"
output_msg += f"argv[{n}] = {color_str} = {result:#x} -> {bytes(pwndbg.aglib.memory.string(result))!r}\n"
else:
output_msg += (
f"argv[{n}] = {color_str} = {result:#x}, {color_str} is a readable address\n"
@ -377,15 +393,15 @@ def check_non_stack_argv(expr: str) -> Tuple[CheckSatResult, str]:
argv, color_str, err = parse_expression(expr)
if err is not None:
# We don't have to print the error message here, it should be printed already
return UNSAT, output_msg
return UNSAT, f"{err} while parsing {color_str}\n"
output_msg += f"Assume argv = {color_str} = {argv:#x}, checking the content of argv\n"
n = 0
while True:
try:
argv_n = pwndbg.gdblib.memory.pvoid(argv + n * pwndbg.aglib.arch.ptrsize)
except gdb.MemoryError:
argv_n = pwndbg.aglib.memory.pvoid(argv + n * pwndbg.aglib.arch.ptrsize)
except pwndbg.dbg_mod.Error:
output_msg += f"&argv[{n}] = {argv + n * pwndbg.aglib.arch.ptrsize:#x}, {argv + n * pwndbg.aglib.arch.ptrsize:#x} is a invalid address\n"
return UNSAT, output_msg
if argv_n == 0:
@ -396,11 +412,11 @@ def check_non_stack_argv(expr: str) -> Tuple[CheckSatResult, str]:
# {whatever_but_readable, NULL} is always a valid argv
output_msg += f"argv[{n}] is NULL, {color_str} is a valid argv\n"
return SAT, output_msg
page = pwndbg.gdblib.vmmap.find(argv_n)
page = pwndbg.aglib.vmmap.find(argv_n)
if page is None or not page.read:
output_msg += f"argv[{n}] = {argv_n:#x}, {argv_n:#x} is a invalid address\n"
return UNSAT, output_msg
output_msg += f"argv[{n}] = {argv_n:#x} -> {bytes(pwndbg.gdblib.memory.string(argv_n))!r}\n"
output_msg += f"argv[{n}] = {argv_n:#x} -> {bytes(pwndbg.aglib.memory.string(argv_n))!r}\n"
n += 1
@ -421,10 +437,11 @@ def check_envp(expr: str) -> Tuple[bool, str]:
if expr.startswith("{"):
# Note: we don't have to handle this case for now, but might need to implement it in the future
return False, output_msg
envp, color_str, err = parse_expression(expr)
if err is not None:
# we don't have to print the error message here, it should be printed already
return False, output_msg
return False, f"{err} while parsing {color_str}\n"
output_msg += f"Assume envp = {color_str} = {envp:#x}, checking the content of envp\n"
@ -433,14 +450,14 @@ def check_envp(expr: str) -> Tuple[bool, str]:
n = 0
while True:
try:
envp_n = pwndbg.gdblib.memory.pvoid(envp + n * pwndbg.aglib.arch.ptrsize)
except gdb.MemoryError:
envp_n = pwndbg.aglib.memory.pvoid(envp + n * pwndbg.aglib.arch.ptrsize)
except pwndbg.dbg_mod.Error:
output_msg += f"&envp[{n}] = {envp + n * pwndbg.aglib.arch.ptrsize:#x}, {envp + n * pwndbg.aglib.arch.ptrsize:#x} is a invalid address\n"
return False, output_msg
if envp_n == 0:
output_msg += f"envp[{n}] is NULL, {color_str} is a valid envp\n"
return True, output_msg
page = pwndbg.gdblib.vmmap.find(envp_n)
page = pwndbg.aglib.vmmap.find(envp_n)
if page is None or not page.read:
output_msg += f"envp[{n}] = {envp_n:#x}, {envp_n:#x} is a invalid address\n"
return False, output_msg
@ -481,7 +498,7 @@ def check_constraint(constraint: str) -> Tuple[CheckSatResult, str]:
for expr in exprs.split(", "):
result, color_str, err = parse_expression(expr)
if err is None:
page = pwndbg.gdblib.vmmap.find(result)
page = pwndbg.aglib.vmmap.find(result)
passed = page is not None and page.write
output_msg += f"{color_str} = {result:#x}, {color_str} is {'' if passed else 'not '}writable\n"
else:
@ -493,7 +510,7 @@ def check_constraint(constraint: str) -> Tuple[CheckSatResult, str]:
expr = WRITABLE_COLON_PATTERN.match(constraint).group(1)
result, color_str, err = parse_expression(expr)
if err is None:
page = pwndbg.gdblib.vmmap.find(result)
page = pwndbg.aglib.vmmap.find(result)
passed = page is not None and page.write
output_msg += (
f"{color_str} = {result:#x}, {color_str} is {'' if passed else 'not '}writable\n"
@ -530,9 +547,12 @@ def check_constraint(constraint: str) -> Tuple[CheckSatResult, str]:
elif IS_GOT_ADDRESS_PATTERN.match(constraint):
expr = IS_GOT_ADDRESS_PATTERN.match(constraint).group(1)
result, color_str, err = parse_expression(expr)
got_plt_address = pwndbg.glibc.get_section_address_by_name(".got.plt")
passed = result == got_plt_address
output_msg += f"{color_str} = {result:#x}, {color_str} is {'' if passed else 'not '}the GOT address ({got_plt_address:#x}) of libc\n"
if err is None:
got_plt_address = pwndbg.glibc.get_section_address_by_name(".got.plt")
passed = result == got_plt_address
output_msg += f"{color_str} = {result:#x}, {color_str} is {'' if passed else 'not '}the GOT address ({got_plt_address:#x}) of libc\n"
else:
output_msg += f"{err} while parsing {color_str}\n"
else:
raise ValueError(f"Unsupported constraint: {constraint}")

@ -706,7 +706,6 @@ def load_commands() -> None:
import pwndbg.commands.killthreads
import pwndbg.commands.klookup
import pwndbg.commands.kversion
import pwndbg.commands.onegadget
import pwndbg.commands.pcplist
import pwndbg.commands.peda
import pwndbg.commands.reload
@ -749,6 +748,7 @@ def load_commands() -> None:
import pwndbg.commands.mprotect
import pwndbg.commands.nearpc
import pwndbg.commands.next
import pwndbg.commands.onegadget
import pwndbg.commands.p2p
import pwndbg.commands.patch
import pwndbg.commands.pie

@ -3,9 +3,9 @@ from __future__ import annotations
import argparse
import shutil
import pwndbg.aglib.onegadget
import pwndbg.color.message as M
import pwndbg.commands
import pwndbg.gdblib.onegadget
import pwndbg.glibc
from pwndbg.commands import CommandCategory
@ -38,10 +38,10 @@ def onegadget(show_unsat: bool = False, no_unknown: bool = False, verbose: bool
print(f"Using libc: {M.hint(path)}")
print()
gadgets_count = pwndbg.gdblib.onegadget.find_gadgets(show_unsat, no_unknown, verbose)
gadgets_count = pwndbg.aglib.onegadget.find_gadgets(show_unsat, no_unknown, verbose)
for result, count in gadgets_count.items():
print(f"Found {M.hint(count)} {result} gadgets.")
if not gadgets_count[pwndbg.gdblib.onegadget.SAT] and not show_unsat:
if not gadgets_count[pwndbg.aglib.onegadget.SAT] and not show_unsat:
print(
M.warn(
"No valid gadgets found, you might want to run with --show-unsat again to check unsatisfiable gadgets.\n"

@ -32,7 +32,6 @@ def load_gdblib() -> None:
import pwndbg.gdblib.hooks
import pwndbg.gdblib.kernel
import pwndbg.gdblib.memory
import pwndbg.gdblib.onegadget
import pwndbg.gdblib.prompt
import pwndbg.gdblib.regs as regs_mod
import pwndbg.gdblib.symbol

Loading…
Cancel
Save