From 7b5362192d2a4e4c05649b5a45cb03999ffc8905 Mon Sep 17 00:00:00 2001 From: ValekoZ Date: Wed, 29 May 2024 23:45:07 +0200 Subject: [PATCH 1/8] [cmd] Allow for filtering about maps permissions in `vmmap` --- docs/commands/vmmap.md | 2 +- gef.py | 20 +++++++++++++++----- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/docs/commands/vmmap.md b/docs/commands/vmmap.md index 597decb8d..142aa8074 100644 --- a/docs/commands/vmmap.md +++ b/docs/commands/vmmap.md @@ -10,7 +10,7 @@ place). For example, you can learn that ELF running on SPARC architectures alway and `heap` sections set as Read/Write/Execute. `vmmap` can accept multiple arguments, either patterns to match again mapping names, or addresses -to determine which section it belongs to: +to determine which section it belongs to, or the permissions of the sections to match: 1. `-a` / `--addr`: - filter by address -> parses the next argument as an integer or asks gdb to interpret the value diff --git a/gef.py b/gef.py index c31ee9009..a18146023 100644 --- a/gef.py +++ b/gef.py @@ -8895,7 +8895,9 @@ class VMMapCommand(GenericCommand): _example_ = f"{_cmdline_} libc" @only_if_gdb_running - @parse_arguments({"unknown_types": [""]}, {("--addr", "-a"): [""], ("--name", "-n"): [""]}) + @parse_arguments({"unknown_types": [""]}, {("--addr", "-a"): [""], + ("--name", "-n"): [""], + ("--perms", "-p"): [""]}) def do_invoke(self, _: List[str], **kwargs: Any) -> None: args : argparse.Namespace = kwargs["arguments"] vmmap = gef.memory.maps @@ -8905,6 +8907,7 @@ def do_invoke(self, _: List[str], **kwargs: Any) -> None: addrs: Dict[str, int] = {x: parse_address(x) for x in args.addr} names: List[str] = [x for x in args.name] + perms: List[Permission] = [Permission.from_process_maps(x) for x in args.perms] for arg in args.unknown_types: if not arg: @@ -8916,12 +8919,18 @@ def do_invoke(self, _: List[str], **kwargs: Any) -> None: addr = safe_parse_and_eval(arg) if addr is None: + if arg[0] in 'r-' and \ + arg[1] in 'w-' and \ + arg[2] in 'x-': + perms.append(Permission.from_process_maps(arg)) + continue + names.append(arg) warn(f"`{arg}` has no type specified. We guessed it was a name filter.") else: addrs[arg] = int(addr) warn(f"`{arg}` has no type specified. We guessed it was an address filter.") - warn("You can use --name or --addr before the filter value for specifying its type manually.") + warn("You can use --name, --addr or --perms before the filter value for specifying its type manually.") gef_print() if not gef.config["gef.disable_color"]: @@ -8938,12 +8947,13 @@ def do_invoke(self, _: List[str], **kwargs: Any) -> None: names_filter = [f"name = '{x}'" for x in names if x in entry.path] addrs_filter = [f"addr = {self.format_addr_filter(arg, addr)}" for arg, addr in addrs.items() if entry.page_start <= addr < entry.page_end] - filter_content = f"[{' & '.join([*names_filter, *addrs_filter])}]" + perms_filter = [f"perms = {x}" for x in perms if entry.permission == x] + filter_content = f"[{' & '.join([*names_filter, *addrs_filter, *perms_filter])}]" - if not names and not addrs: + if not names and not addrs and not perms: self.print_entry(entry) - elif names_filter or addrs_filter: + elif names_filter or addrs_filter or perms_filter: if filter_content != last_printed_filter: gef_print() # skip a line between different filters gef_print(Color.greenify(filter_content)) From 95d14fe52b45009c0bcf040d20ba75daf64e5f13 Mon Sep 17 00:00:00 2001 From: ValekoZ Date: Sun, 2 Jun 2024 23:43:23 +0200 Subject: [PATCH 2/8] Add `?` char for perms filtering --- gef.py | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/gef.py b/gef.py index a18146023..39175b073 100644 --- a/gef.py +++ b/gef.py @@ -665,6 +665,30 @@ def from_info_mem(cls, perm_str: str) -> "Permission": if "x" in perm_str: perm |= Permission.EXECUTE return perm + @classmethod + def from_filter_repr(cls, filter_str: str) -> List["Permission"]: + perms = [cls(0)] + if perm_str[0] == "r": + for i, x in enumerate(perms): + perms[i] = x | Permission.READ + elif perm_str[0] == "?": + for x in perms: + perms.append(x | Permission.READ) + if perm_str[1] == "w": + for i, x in enumerate(perms): + perms[i] = x | Permission.WRITE + elif perm_str[1] == "?": + for x in perms: + perms.append(x | Permission.WRITE) + if perm_str[2] == "x": + for i, x in enumerate(perms): + perms[i] = x | Permission.EXECUTE + elif perm_str[2] == "?": + for x in perms: + perms.append(x | Permission.EXECUTE) + return perm + + class Section: """GEF representation of process memory sections.""" @@ -8907,7 +8931,10 @@ def do_invoke(self, _: List[str], **kwargs: Any) -> None: addrs: Dict[str, int] = {x: parse_address(x) for x in args.addr} names: List[str] = [x for x in args.name] - perms: List[Permission] = [Permission.from_process_maps(x) for x in args.perms] + perms: Set[Permission] = {} + + for x in args.perms: + perms.union(Permission.from_filter_repr(x)) for arg in args.unknown_types: if not arg: @@ -8922,7 +8949,7 @@ def do_invoke(self, _: List[str], **kwargs: Any) -> None: if arg[0] in 'r-' and \ arg[1] in 'w-' and \ arg[2] in 'x-': - perms.append(Permission.from_process_maps(arg)) + perms.union(Permission.from_filter_repr(arg)) continue names.append(arg) From d68a6dda76007ab36caf1784b4dd700b1c73a529 Mon Sep 17 00:00:00 2001 From: ValekoZ Date: Sun, 2 Jun 2024 23:49:54 +0200 Subject: [PATCH 3/8] Add tests --- tests/commands/vmmap.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/commands/vmmap.py b/tests/commands/vmmap.py index fbc00a46a..acdfec2ce 100644 --- a/tests/commands/vmmap.py +++ b/tests/commands/vmmap.py @@ -27,6 +27,10 @@ def test_cmd_vmmap(self): assert "`$pc` has no type specified. We guessed it was an address filter." in res self.assertEqual(len(res.splitlines()), 8) + res = gdb.execute("vmmap r-?", to_string=True) + assert "`r-?` has no type specified. We guessed it was a perm filter." in res + self.assertGreater(len(res.splitlines()), 3) + def test_cmd_vmmap_addr(self): gef, gdb = self._gef, self._gdb gdb.execute("start") @@ -48,3 +52,20 @@ def test_cmd_vmmap_name(self): res = gdb.execute("vmmap --name stack", to_string=True) self.assertEqual(len(res.splitlines()), 5) + + def test_cmd_vmmap_perm(self): + gdb = self._gdb + gdb.execute("start") + + res = gdb.execute("vmmap -p r?-", to_string=True) + self.assertEqual(len(res.splitlines()), 5) + + res = gdb.execute("vmmap --perms r?-", to_string=True) + self.assertEqual(len(res.splitlines()), 5) + + res = gdb.execute("vmmap -p rw-", to_string=True) + self.assertEqual(len(res.splitlines()), 5) + + res = gdb.execute("vmmap --perms rw-", to_string=True) + self.assertEqual(len(res.splitlines()), 5) + From 10cb8faebeaeeb98e92b2cabef11816c4e143c4c Mon Sep 17 00:00:00 2001 From: ValekoZ Date: Sun, 10 Nov 2024 15:56:31 +0100 Subject: [PATCH 4/8] fix missing handling of ? --- gef.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gef.py b/gef.py index 39175b073..3003a8d36 100644 --- a/gef.py +++ b/gef.py @@ -8946,9 +8946,9 @@ def do_invoke(self, _: List[str], **kwargs: Any) -> None: addr = safe_parse_and_eval(arg) if addr is None: - if arg[0] in 'r-' and \ - arg[1] in 'w-' and \ - arg[2] in 'x-': + if arg[0] in 'r-?' and \ + arg[1] in 'w-?' and \ + arg[2] in 'x-?': perms.union(Permission.from_filter_repr(arg)) continue From ad16e98b7fae028d0b21d39fb8f9cd76381b456d Mon Sep 17 00:00:00 2001 From: ValekoZ Date: Sun, 10 Nov 2024 16:08:40 +0100 Subject: [PATCH 5/8] fix wrong handling of ? --- gef.py | 45 +++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/gef.py b/gef.py index 3003a8d36..5fb726507 100644 --- a/gef.py +++ b/gef.py @@ -668,25 +668,25 @@ def from_info_mem(cls, perm_str: str) -> "Permission": @classmethod def from_filter_repr(cls, filter_str: str) -> List["Permission"]: perms = [cls(0)] - if perm_str[0] == "r": - for i, x in enumerate(perms): - perms[i] = x | Permission.READ - elif perm_str[0] == "?": - for x in perms: - perms.append(x | Permission.READ) - if perm_str[1] == "w": - for i, x in enumerate(perms): - perms[i] = x | Permission.WRITE - elif perm_str[1] == "?": - for x in perms: - perms.append(x | Permission.WRITE) - if perm_str[2] == "x": - for i, x in enumerate(perms): - perms[i] = x | Permission.EXECUTE - elif perm_str[2] == "?": - for x in perms: - perms.append(x | Permission.EXECUTE) - return perm + if filter_str[0] == "r": + for i in range(len(perms)): + perms[i] |= Permission.READ + elif filter_str[0] == "?": + for i in range(len(perms)): + perms.append(perms[i] | Permission.READ) + if filter_str[1] == "w": + for i in range(len(perms)): + perms[i] |= Permission.WRITE + elif filter_str[1] == "?": + for i in range(len(perms)): + perms.append(perms[i] | Permission.WRITE) + if filter_str[2] == "x": + for i in range(len(perms)): + perms[i] |= Permission.EXECUTE + elif filter_str[2] == "?": + for i in range(len(perms)): + perms.append(perms[i] | Permission.EXECUTE) + return perms @@ -8931,10 +8931,10 @@ def do_invoke(self, _: List[str], **kwargs: Any) -> None: addrs: Dict[str, int] = {x: parse_address(x) for x in args.addr} names: List[str] = [x for x in args.name] - perms: Set[Permission] = {} + perms: Set[Permission] = set() for x in args.perms: - perms.union(Permission.from_filter_repr(x)) + perms = perms.union(Permission.from_filter_repr(x)) for arg in args.unknown_types: if not arg: @@ -8949,7 +8949,8 @@ def do_invoke(self, _: List[str], **kwargs: Any) -> None: if arg[0] in 'r-?' and \ arg[1] in 'w-?' and \ arg[2] in 'x-?': - perms.union(Permission.from_filter_repr(arg)) + perms = perms.union(Permission.from_filter_repr(arg)) + warn(f"`{arg}` has no type specified. We guessed it was a perm filter.") continue names.append(arg) From 3ed4e36ac49ec1eca6cdf7cf5ef3190b4c242b41 Mon Sep 17 00:00:00 2001 From: ValekoZ Date: Sun, 10 Nov 2024 16:46:00 +0100 Subject: [PATCH 6/8] fix formatting --- tests/commands/vmmap.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/commands/vmmap.py b/tests/commands/vmmap.py index acdfec2ce..f37028864 100644 --- a/tests/commands/vmmap.py +++ b/tests/commands/vmmap.py @@ -68,4 +68,3 @@ def test_cmd_vmmap_perm(self): res = gdb.execute("vmmap --perms rw-", to_string=True) self.assertEqual(len(res.splitlines()), 5) - From ba8330660fbb90d9ba46f1f35ae4020d190e8d44 Mon Sep 17 00:00:00 2001 From: ValekoZ Date: Sun, 10 Nov 2024 16:47:51 +0100 Subject: [PATCH 7/8] fix tests --- tests/commands/vmmap.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/commands/vmmap.py b/tests/commands/vmmap.py index f37028864..6102a8117 100644 --- a/tests/commands/vmmap.py +++ b/tests/commands/vmmap.py @@ -58,13 +58,13 @@ def test_cmd_vmmap_perm(self): gdb.execute("start") res = gdb.execute("vmmap -p r?-", to_string=True) - self.assertEqual(len(res.splitlines()), 5) + self.assertGreater(len(res.splitlines()), 5) res = gdb.execute("vmmap --perms r?-", to_string=True) - self.assertEqual(len(res.splitlines()), 5) + self.assertGreater(len(res.splitlines()), 5) res = gdb.execute("vmmap -p rw-", to_string=True) - self.assertEqual(len(res.splitlines()), 5) + self.assertGreater(len(res.splitlines()), 5) res = gdb.execute("vmmap --perms rw-", to_string=True) - self.assertEqual(len(res.splitlines()), 5) + self.assertGreater(len(res.splitlines()), 5) From e604c6ee71e6a606e093a8d2c08ab8ce716e2a10 Mon Sep 17 00:00:00 2001 From: ValekoZ Date: Tue, 12 Nov 2024 10:29:37 +0100 Subject: [PATCH 8/8] Clean code for `from_filter_repr --- docs/commands/vmmap.md | 2 ++ gef.py | 25 ++++++++----------------- 2 files changed, 10 insertions(+), 17 deletions(-) diff --git a/docs/commands/vmmap.md b/docs/commands/vmmap.md index 142aa8074..adb2158e0 100644 --- a/docs/commands/vmmap.md +++ b/docs/commands/vmmap.md @@ -16,6 +16,8 @@ to determine which section it belongs to, or the permissions of the sections to - filter by address -> parses the next argument as an integer or asks gdb to interpret the value 2. `-n` / `--name`: - filter based on section name +2. `-p` / `--perms`: + - filter based on section permissions 3. If nothing is specified, it prints a warning and guesses the type ![vmmap-grep](https://github.com/hugsy/gef/assets/11377623/a3dbaa3e-88b0-407f-a0dd-07e65c4a3f73) diff --git a/gef.py b/gef.py index 5fb726507..69002cabc 100644 --- a/gef.py +++ b/gef.py @@ -668,24 +668,15 @@ def from_info_mem(cls, perm_str: str) -> "Permission": @classmethod def from_filter_repr(cls, filter_str: str) -> List["Permission"]: perms = [cls(0)] - if filter_str[0] == "r": - for i in range(len(perms)): - perms[i] |= Permission.READ - elif filter_str[0] == "?": - for i in range(len(perms)): - perms.append(perms[i] | Permission.READ) - if filter_str[1] == "w": - for i in range(len(perms)): - perms[i] |= Permission.WRITE - elif filter_str[1] == "?": - for i in range(len(perms)): - perms.append(perms[i] | Permission.WRITE) - if filter_str[2] == "x": - for i in range(len(perms)): - perms[i] |= Permission.EXECUTE - elif filter_str[2] == "?": + + for k in range(3): for i in range(len(perms)): - perms.append(perms[i] | Permission.EXECUTE) + p = cls(1 << (2-k)) + if filter_str[k] == "rwx"[k]: + perms[i] |= p + elif filter_str[k] == "?": + perms.append(perms[i] | p) + return perms