add string index lookup operation
This commit is contained in:
parent
d735496641
commit
abd6667a3e
@ -324,6 +324,7 @@
|
|||||||
"Filter",
|
"Filter",
|
||||||
"Head",
|
"Head",
|
||||||
"Tail",
|
"Tail",
|
||||||
|
"String index lookup",
|
||||||
"Count occurrences",
|
"Count occurrences",
|
||||||
"Expand alphabet range",
|
"Expand alphabet range",
|
||||||
"Drop bytes",
|
"Drop bytes",
|
||||||
|
|||||||
89
src/core/operations/StringIndexLookup.mjs
Normal file
89
src/core/operations/StringIndexLookup.mjs
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
/**
|
||||||
|
* @author skyswordw
|
||||||
|
* @copyright Crown Copyright 2026
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Operation from "../Operation.mjs";
|
||||||
|
import Utils from "../Utils.mjs";
|
||||||
|
import { DELIM_OPTIONS } from "../lib/Delim.mjs";
|
||||||
|
import OperationError from "../errors/OperationError.mjs";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* String index lookup operation
|
||||||
|
*/
|
||||||
|
class StringIndexLookup extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* StringIndexLookup constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "String index lookup";
|
||||||
|
this.module = "Default";
|
||||||
|
this.description = "Looks up characters from a source string using an input list of indexes. This is useful for deobfuscating command lines that build strings by indexing into a lookup string.";
|
||||||
|
this.inputType = "string";
|
||||||
|
this.outputType = "string";
|
||||||
|
this.args = [
|
||||||
|
{
|
||||||
|
"name": "Source string",
|
||||||
|
"type": "binaryString",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Delimiter",
|
||||||
|
"type": "option",
|
||||||
|
"value": DELIM_OPTIONS
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Indexing",
|
||||||
|
"type": "option",
|
||||||
|
"value": ["Zero-based", "One-based"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Skip invalid indexes",
|
||||||
|
"type": "boolean",
|
||||||
|
"value": true
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*
|
||||||
|
* @throws {OperationError} if an index is invalid and invalid indexes are not skipped
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
const source = [...(args[0] || "")],
|
||||||
|
delim = Utils.charRep(args[1] || "Space"),
|
||||||
|
indexOffset = args[2] === "One-based" ? 1 : 0,
|
||||||
|
skipInvalid = args[3] !== false;
|
||||||
|
|
||||||
|
return input.split(delim).reduce((output, rawIndex) => {
|
||||||
|
const trimmedIndex = rawIndex.trim();
|
||||||
|
|
||||||
|
if (trimmedIndex.length === 0) return output;
|
||||||
|
|
||||||
|
const parsedIndex = Number(trimmedIndex);
|
||||||
|
|
||||||
|
if (!Number.isInteger(parsedIndex)) {
|
||||||
|
if (skipInvalid) return output;
|
||||||
|
throw new OperationError(`Invalid index: ${trimmedIndex}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const sourceIndex = parsedIndex - indexOffset;
|
||||||
|
if (sourceIndex < 0 || sourceIndex >= source.length) {
|
||||||
|
if (skipInvalid) return output;
|
||||||
|
throw new OperationError(`Index out of range: ${parsedIndex}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return output + source[sourceIndex];
|
||||||
|
}, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default StringIndexLookup;
|
||||||
@ -169,6 +169,7 @@ import "./tests/RC6.mjs";
|
|||||||
// import "./tests/SplitColourChannels.mjs"; // Cannot test operations that use the File type yet
|
// import "./tests/SplitColourChannels.mjs"; // Cannot test operations that use the File type yet
|
||||||
import "./tests/SQLBeautify.mjs";
|
import "./tests/SQLBeautify.mjs";
|
||||||
import "./tests/StrUtils.mjs";
|
import "./tests/StrUtils.mjs";
|
||||||
|
import "./tests/StringIndexLookup.mjs";
|
||||||
import "./tests/StripIPv4Header.mjs";
|
import "./tests/StripIPv4Header.mjs";
|
||||||
import "./tests/StripTCPHeader.mjs";
|
import "./tests/StripTCPHeader.mjs";
|
||||||
import "./tests/StripUDPHeader.mjs";
|
import "./tests/StripUDPHeader.mjs";
|
||||||
|
|||||||
66
tests/operations/tests/StringIndexLookup.mjs
Normal file
66
tests/operations/tests/StringIndexLookup.mjs
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
/**
|
||||||
|
* String index lookup tests.
|
||||||
|
*
|
||||||
|
* @author skyswordw
|
||||||
|
* @copyright Crown Copyright 2026
|
||||||
|
* @licence Apache-2.0
|
||||||
|
*/
|
||||||
|
import TestRegister from "../../lib/TestRegister.mjs";
|
||||||
|
|
||||||
|
TestRegister.addTests([
|
||||||
|
{
|
||||||
|
name: "String index lookup: zero-based semicolon list",
|
||||||
|
input: "0;1;2;3;4;5;6;7;8;9",
|
||||||
|
expectedOutput: "powershell",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "String index lookup",
|
||||||
|
args: ["powershell", "Semi-colon", "Zero-based", false]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "String index lookup: one-based comma list",
|
||||||
|
input: "1, 2, 3, 4, 5",
|
||||||
|
expectedOutput: "abcde",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "String index lookup",
|
||||||
|
args: ["abcde", "Comma", "One-based", false]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "String index lookup: skip invalid indexes",
|
||||||
|
input: "0;99;1;-1;2",
|
||||||
|
expectedOutput: "abc",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "String index lookup",
|
||||||
|
args: ["abc", "Semi-colon", "Zero-based", true]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "String index lookup: default skips invalid tokens",
|
||||||
|
input: "0;foo;1;99;2",
|
||||||
|
expectedOutput: "abc",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "String index lookup",
|
||||||
|
args: ["abc", "Semi-colon", "Zero-based"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "String index lookup: strict out of range",
|
||||||
|
input: "3",
|
||||||
|
expectedOutput: "Index out of range: 3",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "String index lookup",
|
||||||
|
args: ["abc", "Semi-colon", "Zero-based", false]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]);
|
||||||
Loading…
x
Reference in New Issue
Block a user