From 8509af210530fc92ca9f57b24972cd2eb34d8c9a Mon Sep 17 00:00:00 2001 From: Didier Stevens Date: Sun, 25 Dec 2022 10:41:45 +0100 Subject: [PATCH 1/4] Add new operation: Insert bytes --- src/core/config/Categories.json | 1 + src/core/operations/InsertBytes.mjs | 81 ++++++++++++++++++++++++++ tests/operations/index.mjs | 1 + tests/operations/tests/InsertBytes.mjs | 78 +++++++++++++++++++++++++ 4 files changed, 161 insertions(+) create mode 100644 src/core/operations/InsertBytes.mjs create mode 100644 tests/operations/tests/InsertBytes.mjs diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index 075e8d66..71c41a0c 100644 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -265,6 +265,7 @@ "Expand alphabet range", "Drop bytes", "Take bytes", + "Insert bytes", "Pad lines", "Find / Replace", "Regular expression", diff --git a/src/core/operations/InsertBytes.mjs b/src/core/operations/InsertBytes.mjs new file mode 100644 index 00000000..ea07e935 --- /dev/null +++ b/src/core/operations/InsertBytes.mjs @@ -0,0 +1,81 @@ +/** + * @author Didier Stevens [didier.stevens@gmail.com] + * @copyright Crown Copyright 2022 + * @license Apache-2.0 + */ + +import Operation from "../Operation.mjs"; +import OperationError from "../errors/OperationError.mjs"; +import {BITWISE_OP_DELIMS} from "../lib/BitwiseOp.mjs"; +import Utils from "../Utils.mjs"; + +/** + * Insert bytes operation + */ +class InsertBytes extends Operation { + + /** + * InsertBytes constructor + */ + constructor() { + super(); + + this.name = "Insert bytes"; + this.module = "Default"; + this.description = "Insert bytes at arbitrary position. Options 'from end' and 'overwrite' available."; + this.infoURL = ""; + this.inputType = "byteArray"; + this.outputType = "byteArray"; + this.args = [ + { + "name": "Bytes", + "type": "toggleString", + "value": "", + "toggleValues": BITWISE_OP_DELIMS + }, + { + "name": "Start", + "type": "number", + "value": 0 + }, + { + "name": "From end", + "type": "boolean", + "value": false + }, + { + "name": "Overwrite", + "type": "boolean", + "value": false + } + ]; + } + + /** + * @param {byteArray} input + * @param {Object[]} args + * @returns {byteArray} + */ + run(input, args) { + const value = Utils.convertToByteArray(args[0].string || "", args[0].option); + let start = args[1]; + const fromend = args[2]; + const overwrite = args[3]; + + if (start < 0) + throw new OperationError("Start must not be negative"); + if (start > input.length) + throw new OperationError("Start must not be bigger than input"); + if (fromend) + start = input.length - start; + const left = input.slice(0, start); + let right = input.slice(start); + if (overwrite) + right = right.slice(value.length); + + return left.concat(value, right); + } + +} + +export default InsertBytes; diff --git a/tests/operations/index.mjs b/tests/operations/index.mjs index 7a3361f2..04cc3f1d 100644 --- a/tests/operations/index.mjs +++ b/tests/operations/index.mjs @@ -130,6 +130,7 @@ import "./tests/FletcherChecksum.mjs"; import "./tests/CMAC.mjs"; import "./tests/AESKeyWrap.mjs"; import "./tests/Rabbit.mjs"; +import "./tests/InsertBytes.mjs"; // Cannot test operations that use the File type yet // import "./tests/SplitColourChannels.mjs"; diff --git a/tests/operations/tests/InsertBytes.mjs b/tests/operations/tests/InsertBytes.mjs new file mode 100644 index 00000000..8eca3973 --- /dev/null +++ b/tests/operations/tests/InsertBytes.mjs @@ -0,0 +1,78 @@ +/** + * InsertBytes test. + * + * @author Didier Stevens [didier.stevens@gmail.com] + * @copyright Crown Copyright 2022 + * @license Apache-2.0 + */ +import TestRegister from "../../lib/TestRegister.mjs"; + +TestRegister.addTests([ + { + name: "Insert bytes - test 1", + input: "This is a test", + expectedOutput: "This is a test", + recipeConfig: [ + { + op: "Insert bytes", + args: [{"string": "", "option": "Hex"}, 0, false, false], + }, + ], + }, + { + name: "Insert bytes - test 2", + input: "This is a test", + expectedOutput: "AThis is a test", + recipeConfig: [ + { + op: "Insert bytes", + args: [{"string": "41", "option": "Hex"}, 0, false, false], + }, + ], + }, + { + name: "Insert bytes - test 3", + input: "This is a test", + expectedOutput: "This is a testA", + recipeConfig: [ + { + op: "Insert bytes", + args: [{"string": "41", "option": "Hex"}, 0, true, false], + }, + ], + }, + { + name: "Insert bytes - test 4", + input: "This is a test", + expectedOutput: "Ahis is a test", + recipeConfig: [ + { + op: "Insert bytes", + args: [{"string": "41", "option": "Hex"}, 0, false, true], + }, + ], + }, + { + name: "Insert bytes - test 5", + input: "This is a test", + expectedOutput: "This is a tesA", + recipeConfig: [ + { + op: "Insert bytes", + args: [{"string": "41", "option": "Hex"}, 1, true, true], + }, + ], + }, + { + name: "Insert bytes - test 6", + input: "This is a test", + expectedOutput: "This is not a test", + recipeConfig: [ + { + op: "Insert bytes", + args: [{"string": "not ", "option": "Latin1"}, 8, false, false], + }, + ], + }, + +]); From a61feb00d1a91e0a62ea23380feef6f75a03c8aa Mon Sep 17 00:00:00 2001 From: Didier Stevens Date: Sun, 25 Dec 2022 12:23:07 +0100 Subject: [PATCH 2/4] Operation Change IP Format: added Little Endian format --- src/core/operations/ChangeIPFormat.mjs | 18 ++++++++-- tests/operations/tests/ChangeIPFormat.mjs | 40 +++++++++++++++++++++++ 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/src/core/operations/ChangeIPFormat.mjs b/src/core/operations/ChangeIPFormat.mjs index c9adc5d8..a7e72708 100644 --- a/src/core/operations/ChangeIPFormat.mjs +++ b/src/core/operations/ChangeIPFormat.mjs @@ -29,12 +29,12 @@ class ChangeIPFormat extends Operation { { "name": "Input format", "type": "option", - "value": ["Dotted Decimal", "Decimal", "Octal", "Hex"] + "value": ["Dotted Decimal", "Decimal", "Decimal (Little Endian)", "Octal", "Octal (Little Endian)", "Hex"] }, { "name": "Output format", "type": "option", - "value": ["Dotted Decimal", "Decimal", "Octal", "Hex"] + "value": ["Dotted Decimal", "Decimal", "Decimal (Little Endian)", "Octal", "Octal (Little Endian)", "Hex"] } ]; } @@ -71,9 +71,15 @@ class ChangeIPFormat extends Operation { case "Decimal": baIp = this.fromNumber(lines[i].toString(), 10); break; + case "Decimal (Little Endian)": + baIp = Utils.intToByteArray(parseInt(lines[i].toString(), 10), 4, "little"); + break; case "Octal": baIp = this.fromNumber(lines[i].toString(), 8); break; + case "Octal (Little Endian)": + baIp = Utils.intToByteArray(parseInt(lines[i].toString(), 8), 4, "little"); + break; case "Hex": baIp = fromHex(lines[i]); break; @@ -98,10 +104,18 @@ class ChangeIPFormat extends Operation { decIp = ((baIp[0] << 24) | (baIp[1] << 16) | (baIp[2] << 8) | baIp[3]) >>> 0; output += decIp.toString() + "\n"; break; + case "Decimal (Little Endian)": + decIp = Utils.byteArrayToInt(baIp, "little"); + output += decIp.toString() + "\n"; + break; case "Octal": decIp = ((baIp[0] << 24) | (baIp[1] << 16) | (baIp[2] << 8) | baIp[3]) >>> 0; output += "0" + decIp.toString(8) + "\n"; break; + case "Octal (Little Endian)": + decIp = Utils.byteArrayToInt(baIp, "little"); + output += "0" + decIp.toString(8) + "\n"; + break; case "Hex": hexIp = ""; for (j = 0; j < baIp.length; j++) { diff --git a/tests/operations/tests/ChangeIPFormat.mjs b/tests/operations/tests/ChangeIPFormat.mjs index d92ffb79..26c92124 100644 --- a/tests/operations/tests/ChangeIPFormat.mjs +++ b/tests/operations/tests/ChangeIPFormat.mjs @@ -48,5 +48,45 @@ TestRegister.addTests([ args: ["Octal", "Decimal"], }, ], + }, { + name: "Change IP format: Decimal (Little Endian) to Dotted Decimal", + input: "16885952", + expectedOutput: "192.168.1.1", + recipeConfig: [ + { + op: "Change IP format", + args: ["Decimal (Little Endian)", "Dotted Decimal"], + }, + ], + }, { + name: "Change IP format: Dotted Decimal to Decimal (Little Endian)", + input: "192.168.1.1", + expectedOutput: "16885952", + recipeConfig: [ + { + op: "Change IP format", + args: ["Dotted Decimal", "Decimal (Little Endian)"], + }, + ], + }, { + name: "Change IP format: Octal (Little Endian) to Dotted Decimal", + input: "0100324300", + expectedOutput: "192.168.1.1", + recipeConfig: [ + { + op: "Change IP format", + args: ["Octal (Little Endian)", "Dotted Decimal"], + }, + ], + }, { + name: "Change IP format: Dotted Decimal to Octal (Little Endian)", + input: "192.168.1.1", + expectedOutput: "0100324300", + recipeConfig: [ + { + op: "Change IP format", + args: ["Dotted Decimal", "Octal (Little Endian)"], + }, + ], }, ]); From b54c009798ef82459e462960186e041c36a81f7e Mon Sep 17 00:00:00 2001 From: Didier Stevens Date: Sun, 16 Feb 2025 19:37:59 +0100 Subject: [PATCH 3/4] Update index.mjs --- tests/operations/index.mjs | 158 ++++++++++++++++++++++--------------- 1 file changed, 94 insertions(+), 64 deletions(-) diff --git a/tests/operations/index.mjs b/tests/operations/index.mjs index 04cc3f1d..8d470da7 100644 --- a/tests/operations/index.mjs +++ b/tests/operations/index.mjs @@ -17,123 +17,153 @@ import { } from "../lib/utils.mjs"; import TestRegister from "../lib/TestRegister.mjs"; -import "./tests/BCD.mjs"; -import "./tests/BSON.mjs"; +import "./tests/AESKeyWrap.mjs"; +import "./tests/AvroToJSON.mjs"; import "./tests/BaconCipher.mjs"; import "./tests/Base45.mjs"; import "./tests/Base58.mjs"; -import "./tests/Base64.mjs"; import "./tests/Base62.mjs"; +import "./tests/Base64.mjs"; import "./tests/Base85.mjs"; +import "./tests/Base92.mjs"; +import "./tests/BCD.mjs"; import "./tests/BitwiseOp.mjs"; +import "./tests/BLAKE2b.mjs"; +import "./tests/BLAKE2s.mjs"; +import "./tests/Bombe.mjs"; +import "./tests/BSON.mjs"; import "./tests/ByteRepr.mjs"; +import "./tests/CaesarBoxCipher.mjs"; +import "./tests/CaretMdecode.mjs"; import "./tests/CartesianProduct.mjs"; -import "./tests/CetaceanCipherEncode.mjs"; +import "./tests/CBORDecode.mjs"; +import "./tests/CBOREncode.mjs"; import "./tests/CetaceanCipherDecode.mjs"; +import "./tests/CetaceanCipherEncode.mjs"; import "./tests/ChaCha.mjs"; -import "./tests/CharEnc.mjs"; import "./tests/ChangeIPFormat.mjs"; +import "./tests/CharEnc.mjs"; import "./tests/Charts.mjs"; import "./tests/Checksum.mjs"; import "./tests/Ciphers.mjs"; +import "./tests/CipherSaber2.mjs"; +import "./tests/CMAC.mjs"; import "./tests/Code.mjs"; +import "./tests/Colossus.mjs"; import "./tests/Comment.mjs"; import "./tests/Compress.mjs"; import "./tests/ConditionalJump.mjs"; +import "./tests/ConvertCoordinateFormat.mjs"; +import "./tests/ConvertLeetSpeak.mjs"; +import "./tests/ConvertToNATOAlphabet.mjs"; import "./tests/Crypt.mjs"; import "./tests/CSV.mjs"; import "./tests/DateTime.mjs"; +import "./tests/DefangIP.mjs"; +import "./tests/DropNthBytes.mjs"; +import "./tests/ECDSA.mjs"; +import "./tests/ELFInfo.mjs"; +import "./tests/Enigma.mjs"; import "./tests/ExtractEmailAddresses.mjs"; +import "./tests/ExtractHashes.mjs"; +import "./tests/Float.mjs"; +import "./tests/FileTree.mjs"; +import "./tests/FletcherChecksum.mjs"; import "./tests/Fork.mjs"; import "./tests/FromDecimal.mjs"; import "./tests/GenerateAllHashes.mjs"; -import "./tests/Gzip.mjs"; +import "./tests/GenerateDeBruijnSequence.mjs"; +import "./tests/GetAllCasings.mjs"; +import "./tests/GOST.mjs"; import "./tests/Gunzip.mjs"; +import "./tests/Gzip.mjs"; import "./tests/Hash.mjs"; +import "./tests/HASSH.mjs"; import "./tests/HaversineDistance.mjs"; import "./tests/Hex.mjs"; import "./tests/Hexdump.mjs"; +import "./tests/HKDF.mjs"; import "./tests/Image.mjs"; +import "./tests/InsertBytes.mjs"; import "./tests/IndexOfCoincidence.mjs"; -import "./tests/Jump.mjs"; +import "./tests/JA3Fingerprint.mjs"; +import "./tests/JA4.mjs"; +import "./tests/JA3SFingerprint.mjs"; import "./tests/JSONBeautify.mjs"; import "./tests/JSONMinify.mjs"; import "./tests/JSONtoCSV.mjs"; +import "./tests/Jump.mjs"; +import "./tests/JWK.mjs"; import "./tests/JWTDecode.mjs"; import "./tests/JWTSign.mjs"; import "./tests/JWTVerify.mjs"; -import "./tests/MS.mjs"; +import "./tests/LevenshteinDistance.mjs"; +import "./tests/Lorenz.mjs"; +import "./tests/LS47.mjs"; +import "./tests/LuhnChecksum.mjs"; +import "./tests/LZNT1Decompress.mjs"; +import "./tests/LZString.mjs"; import "./tests/Magic.mjs"; +import "./tests/Media.mjs"; +import "./tests/MIMEDecoding.mjs"; +import "./tests/Modhex.mjs"; import "./tests/MorseCode.mjs"; +import "./tests/MS.mjs"; +import "./tests/MultipleBombe.mjs"; +import "./tests/MurmurHash3.mjs"; import "./tests/NetBIOS.mjs"; import "./tests/NormaliseUnicode.mjs"; +import "./tests/NTLM.mjs"; import "./tests/OTP.mjs"; +import "./tests/ParseIPRange.mjs"; +import "./tests/ParseObjectIDTimestamp.mjs"; +import "./tests/ParseQRCode.mjs"; +import "./tests/ParseSSHHostKey.mjs"; +import "./tests/ParseTCP.mjs"; +import "./tests/ParseTLSRecord.mjs"; +import "./tests/ParseTLV.mjs"; +import "./tests/ParseUDP.mjs"; +import "./tests/PEMtoHex.mjs"; import "./tests/PGP.mjs"; import "./tests/PHP.mjs"; -import "./tests/ParseIPRange.mjs"; -import "./tests/ParseQRCode.mjs"; -import "./tests/PEMtoHex.mjs"; import "./tests/PowerSet.mjs"; +import "./tests/Protobuf.mjs"; +import "./tests/PubKeyFromCert.mjs"; +import "./tests/PubKeyFromPrivKey.mjs"; +import "./tests/Rabbit.mjs"; +import "./tests/RAKE.mjs"; import "./tests/Regex.mjs"; import "./tests/Register.mjs"; +import "./tests/RisonEncodeDecode.mjs"; import "./tests/Rotate.mjs"; +import "./tests/RSA.mjs"; +import "./tests/Salsa20.mjs"; +import "./tests/XSalsa20.mjs"; import "./tests/SeqUtils.mjs"; import "./tests/SetDifference.mjs"; import "./tests/SetIntersection.mjs"; import "./tests/SetUnion.mjs"; -import "./tests/SM4.mjs"; -import "./tests/StrUtils.mjs"; -import "./tests/SymmetricDifference.mjs"; -import "./tests/TextEncodingBruteForce.mjs"; -import "./tests/TranslateDateTimeFormat.mjs"; -import "./tests/Magic.mjs"; -import "./tests/ParseTLV.mjs"; -import "./tests/Media.mjs"; -import "./tests/ToFromInsensitiveRegex.mjs"; -import "./tests/YARA.mjs"; -import "./tests/ConvertCoordinateFormat.mjs"; -import "./tests/Enigma.mjs"; -import "./tests/Bombe.mjs"; -import "./tests/MultipleBombe.mjs"; -import "./tests/Typex.mjs"; -import "./tests/BLAKE2b.mjs"; -import "./tests/BLAKE2s.mjs"; -import "./tests/Protobuf.mjs"; -import "./tests/ParseSSHHostKey.mjs"; -import "./tests/DefangIP.mjs"; -import "./tests/ParseUDP.mjs"; -import "./tests/ParseTCP.mjs"; -import "./tests/AvroToJSON.mjs"; -import "./tests/Lorenz.mjs"; -import "./tests/LuhnChecksum.mjs"; -import "./tests/CipherSaber2.mjs"; -import "./tests/Colossus.mjs"; -import "./tests/ParseObjectIDTimestamp.mjs"; -import "./tests/Unicode.mjs"; -import "./tests/RSA.mjs"; -import "./tests/CBOREncode.mjs"; -import "./tests/CBORDecode.mjs"; -import "./tests/JA3Fingerprint.mjs"; -import "./tests/JA3SFingerprint.mjs"; -import "./tests/HASSH.mjs"; -import "./tests/GetAllCasings.mjs"; -import "./tests/SIGABA.mjs"; -import "./tests/ELFInfo.mjs"; -import "./tests/Subsection.mjs"; -import "./tests/CaesarBoxCipher.mjs"; -import "./tests/UnescapeString.mjs"; -import "./tests/LS47.mjs"; -import "./tests/LZString.mjs"; -import "./tests/NTLM.mjs"; import "./tests/Shuffle.mjs"; -import "./tests/FletcherChecksum.mjs"; -import "./tests/CMAC.mjs"; -import "./tests/AESKeyWrap.mjs"; -import "./tests/Rabbit.mjs"; -import "./tests/InsertBytes.mjs"; - -// Cannot test operations that use the File type yet -// import "./tests/SplitColourChannels.mjs"; +import "./tests/SIGABA.mjs"; +import "./tests/SM4.mjs"; +// import "./tests/SplitColourChannels.mjs"; // Cannot test operations that use the File type yet +import "./tests/StrUtils.mjs"; +import "./tests/StripIPv4Header.mjs"; +import "./tests/StripTCPHeader.mjs"; +import "./tests/StripUDPHeader.mjs"; +import "./tests/Subsection.mjs"; +import "./tests/SwapCase.mjs"; +import "./tests/SymmetricDifference.mjs"; +import "./tests/TakeNthBytes.mjs"; +import "./tests/TextEncodingBruteForce.mjs"; +import "./tests/ToFromInsensitiveRegex.mjs"; +import "./tests/TranslateDateTimeFormat.mjs"; +import "./tests/Typex.mjs"; +import "./tests/UnescapeString.mjs"; +import "./tests/Unicode.mjs"; +import "./tests/YARA.mjs"; +import "./tests/ParseCSR.mjs"; +import "./tests/XXTEA.mjs"; const testStatus = { allTestsPassing: true, @@ -149,4 +179,4 @@ const logOpsTestReport = logTestReport.bind(null, testStatus); (async function() { const results = await TestRegister.runTests(); logOpsTestReport(results); -})(); +})(); \ No newline at end of file From 20b2f56039826eb10c0e048eaffca015562de5dc Mon Sep 17 00:00:00 2001 From: Didier Stevens Date: Sun, 16 Feb 2025 19:40:10 +0100 Subject: [PATCH 4/4] Update index.mjs --- tests/operations/index.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/operations/index.mjs b/tests/operations/index.mjs index 8d470da7..68fef734 100644 --- a/tests/operations/index.mjs +++ b/tests/operations/index.mjs @@ -179,4 +179,4 @@ const logOpsTestReport = logTestReport.bind(null, testStatus); (async function() { const results = await TestRegister.runTests(); logOpsTestReport(results); -})(); \ No newline at end of file +})();