diff --git a/gef.py b/gef.py index fa41c5c2b..6846c2b8d 100644 --- a/gef.py +++ b/gef.py @@ -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 @@ -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 diff --git a/tests/commands/pattern.py b/tests/commands/pattern.py index 37ce4940b..172830784 100644 --- a/tests/commands/pattern.py +++ b/tests/commands/pattern.py @@ -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): @@ -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") @@ -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" @@ -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)