Strings command (#2505)

* added working strings command; no args

* added n, mapping_name and save-as arguments to strings command

* removed unnecessary whitespaces and imports (checked with ruff)

* simplified command function decorator and improve file handling

* accept multiple page names and improve argument handling

* Fix lint

* Update strings.py

* Fix lint

* Fix lint

* Update strings.py

---------

Co-authored-by: Disconnect3d <dominik.b.czarnota@gmail.com>
pull/2593/head
Kacper Wojtowicz 1 year ago committed by GitHub
parent 1980aba40d
commit 1df92cb766
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -790,6 +790,7 @@ def load_commands() -> None:
import pwndbg.commands.sigreturn
import pwndbg.commands.spray
import pwndbg.commands.start
import pwndbg.commands.strings
import pwndbg.commands.telescope
import pwndbg.commands.tls
import pwndbg.commands.valist

@ -0,0 +1,62 @@
from __future__ import annotations
import argparse
import re
from typing import List
import pwndbg
import pwndbg.aglib.memory
import pwndbg.commands
from pwndbg.commands import CommandCategory
from pwndbg.lib.memory import Page
parser = argparse.ArgumentParser(
description="Extracts and displays ASCII strings from readable memory pages of the debugged process."
)
parser.add_argument("-n", type=int, default=4, help="Minimum length of ASCII strings to include")
parser.add_argument(
"page_names",
type=str,
nargs="*",
default=[],
help="Mapping to search [e.g. libc].\nCan be used with multiple mappings [e.g libc heap stack]",
)
parser.add_argument(
"--save-as",
type=str,
default=None,
help="Sets the filename for the output of this command [e.g. --save-as='out.txt']",
)
@pwndbg.commands.ArgparsedCommand(parser, category=CommandCategory.LINUX)
@pwndbg.commands.OnlyWhenRunning
def strings(n: int = 4, page_names: List[str] = [], save_as: str = None):
# Extract pages with PROT_READ permission
readable_pages: List[Page] = [page for page in pwndbg.aglib.vmmap.get() if page.read]
for page in readable_pages:
if page_names and not any(name in page.objfile for name in page_names):
continue # skip if page does not belong to any of the specified mappings
count = page.memsz
start_address = page.vaddr
try:
data = pwndbg.aglib.memory.read(addr=start_address, count=count)
except pwndbg.dbg_mod.Error as e:
print(f"Skipping inaccessible page at {start_address:#x}: {e}")
continue # skip if access is denied
# all strings in the `data`
strings: List[bytes] = re.findall(rb"[ -~]{%d,}" % n, data)
decoded_strings: List[str] = [s.decode("ascii", errors="ignore") for s in strings]
if not save_as:
for string in decoded_strings:
print(string)
continue
with open(save_as, "w") as f:
f.writelines(string + "\n" for string in decoded_strings)
Loading…
Cancel
Save