/** * @author n1474335 [n1474335@gmail.com] * @copyright Crown Copyright 2016 * @license Apache-2.0 */ import Operation from "../Operation.mjs"; import XRegExp from "xregexp"; import { search } from "../lib/Extract.mjs"; import { caseInsensitiveSort } from "../lib/Sort.mjs"; /** * Strings operation */ class Strings extends Operation { /** * Strings constructor */ constructor() { super(); this.name = "Strings"; this.module = "Regex"; this.description = "Extracts all strings from the input."; this.infoURL = "https://wikipedia.org/wiki/Strings_(Unix)"; this.inputType = "string"; this.outputType = "string"; this.args = [ { name: "Encoding", type: "option", value: ["Single byte", "16-bit littleendian", "16-bit bigendian", "All"] }, { name: "Minimum length", type: "number", value: 4 }, { name: "Match", type: "option", value: [ "[ASCII]", "Alphanumeric + punctuation (A)", "All printable chars (A)", "Null-terminated strings (A)", "[Unicode]", "Alphanumeric + punctuation (U)", "All printable chars (U)", "Null-terminated strings (U)" ] }, { name: "Display total", type: "boolean", value: false }, { name: "Sort", type: "boolean", value: false }, { name: "Unique", type: "boolean", value: false } ]; } /** * @param {string} input * @param {Object[]} args * @returns {string} */ run(input, args) { const [encoding, minLen, matchType, displayTotal, sort, unique] = args, alphanumeric = "A-Z\\d", punctuation = "/\\-:.,_$%'\"()<>= !\\[\\]{}@", printable = "\x20-\x7e", uniAlphanumeric = "\\pL\\pN", uniPunctuation = "\\pP\\pZ", uniPrintable = "\\pL\\pM\\pZ\\pS\\pN\\pP"; let strings = ""; switch (matchType) { case "Alphanumeric + punctuation (A)": strings = `[${alphanumeric + punctuation}]`; break; case "All printable chars (A)": case "Null-terminated strings (A)": strings = `[${printable}]`; break; case "Alphanumeric + punctuation (U)": strings = `[${uniAlphanumeric + uniPunctuation}]`; break; case "All printable chars (U)": case "Null-terminated strings (U)": strings = `[${uniPrintable}]`; break; } // UTF-16 support is hacked in by allowing null bytes on either side of the matched chars switch (encoding) { case "All": strings = `(\x00?${strings}\x00?)`; break; case "16-bit littleendian": strings = `(${strings}\x00)`; break; case "16-bit bigendian": strings = `(\x00${strings})`; break; case "Single byte": default: break; } strings = `${strings}{${minLen},}`; if (matchType.includes("Null-terminated")) { strings += "\x00"; } const regex = new XRegExp(strings, "ig"); const results = search( input, regex, null, sort ? caseInsensitiveSort : null, unique ); if (displayTotal) { return `Total found: ${results.length}\n\n${results.join("\n")}`; } else { return results.join("\n"); } } } export default Strings;