| 329 | } |
| 330 | |
| 331 | ByteBuf format_proc_strings(const Engine& eng, const Process& p) { |
| 332 | StringExtractStats stats{}; |
| 333 | auto hits = extract_strings(eng, p, /*min_len=*/6, /*max_hits=*/0, &stats); |
| 334 | std::string out; |
| 335 | out.reserve(std::min<std::size_t>(64 * 1024 + hits.size() * 64, 8 * 1024 * 1024)); |
| 336 | out += fmt::format( |
| 337 | "# /proc/{}/strings.txt - printable ASCII strings (>=6 chars) from the\n" |
| 338 | "# readable VMAs of pid {} ({}).\n" |
| 339 | "# Scan order is by forensic interest: heap / stack / anonymous data and\n" |
| 340 | "# anon-executable (commands, env, secrets, injected code) FIRST, then\n" |
| 341 | "# file-backed regions, read-only library code LAST.\n" |
| 342 | "# limit: none; oversized VMA guard: > 256 MiB skipped.\n" |
| 343 | "# {} strings extracted; {} VMA(s) scanned; {} oversized VMA(s) skipped\n" |
| 344 | "# ({} bytes); {} unreadable page/range skip(s).\n" |
| 345 | "#\n" |
| 346 | "# vma_start hit_va string\n" |
| 347 | "# ----------------+----------------+----------\n", |
| 348 | p.pid, p.pid, p.comm, hits.size(), stats.scanned_vmas, |
| 349 | stats.skipped_oversized_vmas, stats.skipped_oversized_bytes, |
| 350 | stats.unreadable_ranges); |
| 351 | for (const auto& h : hits) { |
| 352 | out += fmt::format("{:#016x} {:#016x} {}\n", |
| 353 | h.vma_start, h.hit_va, h.text); |
| 354 | } |
| 355 | return ByteBuf(out.begin(), out.end()); |
| 356 | } |
| 357 | ByteBuf format_global_iocs(const Engine& eng) { |
| 358 | // Per-process IOC scan with global hit cap so output stays bounded |
| 359 | // even on a dump with thousands of processes. |
no test coverage detected