add strings.yield_in_page, refactor strings command (#2843)

* add strings.yield_in_page, refactor strings command

This commit adds a `pwndbg.aglib.strings.yield_in_page` function that yields all strings in a given memory page.

It also refactors the `pwndbg.commands.strings` command to use this feature.

* fixes

* fixes

* fix
pull/2829/head
Disconnect3d 8 months ago committed by GitHub
parent 00928004c4
commit 261fac8543
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -5,10 +5,13 @@ the debuggee's address space.
from __future__ import annotations
import re
import string
from typing import Iterator
import pwndbg
import pwndbg.aglib.memory
from pwndbg.lib.memory import Page
length = 15
@ -51,3 +54,16 @@ def get(address: int, maxlen: int | None = None, maxread: int | None = None) ->
return sz
return sz[:maxlen] + "..."
def yield_in_page(page: Page, n=4) -> Iterator[str]:
"""Yields strings of length >= n found in a given vmmap page"""
try:
data = pwndbg.aglib.memory.read(addr=page.vaddr, count=page.memsz, partial=True)
except pwndbg.dbg_mod.Error:
# E.g. we cannot read [vvar] page even though it has a READ permission
return
for match in re.finditer(rb"[ -~]{%d,}" % n, data):
decoded_str = match.group().decode("ascii", errors="ignore")
yield decoded_str

@ -1,14 +1,12 @@
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."
@ -33,30 +31,18 @@ parser.add_argument(
@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]
# Get only readable pages and those that match the page_names filter
pages = (
p
for p in pwndbg.aglib.vmmap.get()
if p.read and ((not page_names) or any(name in p.objfile for name in page_names))
)
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
f = open(save_as, "w") if save_as else None
count = page.memsz
start_address = page.vaddr
for page in pages:
for string in pwndbg.aglib.strings.yield_in_page(page, n):
print(string, file=f)
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)
if f:
f.close()

Loading…
Cancel
Save