Skip to content

Commit

Permalink
[pattern-search] Make sure pattern is correctly built (#858)
Browse files Browse the repository at this point in the history
* issue #857 [pattern-search] better handling of how the search pattern is built for non-default values

* fixed tests, also make sur period cannot be higher than `ptrsize`
  • Loading branch information
hugsy committed Jun 29, 2022
1 parent dbcd859 commit 091e298
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 36 deletions.
42 changes: 21 additions & 21 deletions gef.py
Expand Up @@ -8689,18 +8689,23 @@ class PatternSearchCommand(GenericCommand):

_cmdline_ = "pattern search"
_syntax_ = f"{_cmdline_} [-h] [-n N] [--max-length MAX_LENGTH] [pattern]"
_example_ = (f"\n{_cmdline_} $pc"
f"\n{_cmdline_} 0x61616164"
f"\n{_cmdline_} aaab")
_example_ = [f"{_cmdline_} $pc",
f"{_cmdline_} 0x61616164",
f"{_cmdline_} aaab"]
_aliases_ = ["pattern offset"]

@only_if_gdb_running
@parse_arguments({"pattern": ""}, {("-n", "--n"): 0, ("-l", "--max-length"): 0})
@parse_arguments({"pattern": ""}, {("--period", "-n"): 0, ("--max-length", "-l"): 0})
def do_invoke(self, _: List[str], **kwargs: Any) -> None:
args = kwargs["arguments"]
if not args.pattern:
warn("No pattern provided")
return
max_length = args.max_length or gef.config["pattern.length"]
n = args.n or gef.arch.ptrsize
info(f"Searching for '{args.pattern}'")
n = args.period or gef.arch.ptrsize
if n not in (2, 4, 8) or n > gef.arch.ptrsize:
err("Incorrect value for period")
return
self.search(args.pattern, max_length, n)
return

Expand All @@ -8710,39 +8715,34 @@ def search(self, pattern: str, size: int, period: int) -> None:
# 1. check if it's a symbol (like "$sp" or "0x1337")
symbol = safe_parse_and_eval(pattern)
if symbol:
addr = int(symbol)
addr = int(abs(symbol))
dereferenced_value = dereference(addr)
# 1-bis. try to dereference
if dereferenced_value:
addr = int(dereferenced_value)
struct_packsize = {
2: "H",
4: "I",
8: "Q",
}
pattern_be = struct.pack(f">{struct_packsize[gef.arch.ptrsize]}", addr)
pattern_le = struct.pack(f"<{struct_packsize[gef.arch.ptrsize]}", addr)
addr = int(abs(dereferenced_value))
mask = (1<<(8 * period))-1
addr &= mask
pattern_le = addr.to_bytes(period, 'little')
pattern_be = addr.to_bytes(period, 'big')
else:
# 2. assume it's a plain string
pattern_be = gef_pybytes(pattern)
pattern_le = gef_pybytes(pattern[::-1])

info(f"Searching for '{pattern_le.hex()}'/'{pattern_be.hex()}' with period={period}")
cyclic_pattern = generate_cyclic_pattern(size, period)
found = False
off = cyclic_pattern.find(pattern_le)
if off >= 0:
ok(f"Found at offset {off:d} (little-endian search) "
f"{Color.colorify('likely', 'bold red') if gef.arch.endianness == Endianness.LITTLE_ENDIAN else ''}")
found = True
return

off = cyclic_pattern.find(pattern_be)
if off >= 0:
ok(f"Found at offset {off:d} (big-endian search) "
f"{Color.colorify('likely', 'bold green') if gef.arch.endianness == Endianness.BIG_ENDIAN else ''}")
found = True
return

if not found:
err(f"Pattern '{pattern}' not found")
err(f"Pattern '{pattern}' not found")
return


Expand Down
37 changes: 22 additions & 15 deletions tests/commands/pattern.py
Expand Up @@ -3,13 +3,7 @@
"""
import pytest

from tests.utils import (
gdb_run_cmd,
_target,

ARCH,
GefUnitTestGeneric,
)
from tests.utils import ARCH, GefUnitTestGeneric, _target, gdb_run_cmd, is_64b


class PatternCommand(GefUnitTestGeneric):
Expand All @@ -34,11 +28,15 @@ def test_cmd_pattern_search(self):
if ARCH == "aarch64":
lookup_register = "$x30"
expected_offsets = (16, 16, 5, 9)
elif ARCH == "armv7l":
lookup_register = "$r11"
expected_offsets = (8, 8, 5, 9)
elif ARCH == "x86_64":
lookup_register = "$rbp"
expected_offsets = (8, 8, 5, 9)
elif ARCH == "i686":
lookup_register = "$ebp"
# expected_offsets = (16, None, 5, 9)
expected_offsets = (16, 16, 5, 9)
else:
raise ValueError("Invalid architecture")
Expand All @@ -51,11 +49,12 @@ def test_cmd_pattern_search(self):
self.assertIn(f"Found at offset {expected_offsets[0]} (little-endian search) likely", res)

#1
cmd = f"pattern search -n 8 {lookup_register}"
before = ("set args aaaaaaaabaaaaaaacaaaaaaadaaaaaaa", "run")
res = gdb_run_cmd(cmd, before=before, target=target)
self.assertNoException(res)
self.assertIn(f"Found at offset {expected_offsets[1]} (little-endian search) likely", res)
if is_64b():
cmd = f"pattern search -n 8 {lookup_register}"
before = ("set args aaaaaaaabaaaaaaacaaaaaaadaaaaaaa", "run")
res = gdb_run_cmd(cmd, before=before, target=target)
self.assertNoException(res)
self.assertIn(f"Found at offset {expected_offsets[1]} (little-endian search) likely", res)

#2
cmd = "pattern search -n 4 caaa"
Expand All @@ -65,9 +64,17 @@ def test_cmd_pattern_search(self):
self.assertIn(f"Found at offset {expected_offsets[2]} (little-endian search) likely", res)

#3
cmd = "pattern search -n 8 caaaaaaa"
before = ("set args aaaaaaaabaaaaaaacaaaaaaadaaaaaaa", "run")
if is_64b():
cmd = "pattern search -n 8 caaaaaaa"
before = ("set args aaaaaaaabaaaaaaacaaaaaaadaaaaaaa", "run")
res = gdb_run_cmd(cmd, before=before, target=target)
self.assertNoException(res)
self.assertIn(f"Found at offset {expected_offsets[3]} (little-endian search) likely", res)

#4
cmd = "pattern search -n 4 JUNK"
before = ("set args aaaabaaacaaadaaaeaaafaaagaaahaaa", "run")
res = gdb_run_cmd(cmd, before=before, target=target)
self.assertNoException(res)
self.assertIn(f"Found at offset {expected_offsets[3]} (little-endian search) likely", res)
self.assertIn(f"not found", res)

0 comments on commit 091e298

Please sign in to comment.