diff --git a/README.md b/README.md index aa04fb8c..9dffba47 100755 --- a/README.md +++ b/README.md @@ -100,6 +100,6 @@ CyberChef is released under the [Apache 2.0 Licence](https://www.apache.org/lice [5]: https://gchq.github.io/CyberChef/#recipe=From_Hexdump()Gunzip()&input=MDAwMDAwMDAgIDFmIDhiIDA4IDAwIDEyIGJjIGYzIDU3IDAwIGZmIDBkIGM3IGMxIDA5IDAwIDIwICB8Li4uLi6881cu/y7HwS4uIHwKMDAwMDAwMTAgIDA4IDA1IGQwIDU1IGZlIDA0IDJkIGQzIDA0IDFmIGNhIDhjIDQ0IDIxIDViIGZmICB8Li7QVf4uLdMuLsouRCFb/3wKMDAwMDAwMjAgIDYwIGM3IGQ3IDAzIDE2IGJlIDQwIDFmIDc4IDRhIDNmIDA5IDg5IDBiIDlhIDdkICB8YMfXLi6%2BQC54Sj8uLi4ufXwKMDAwMDAwMzAgIDRlIGM4IDRlIDZkIDA1IDFlIDAxIDhiIDRjIDI0IDAwIDAwIDAwICAgICAgICAgICB8TshObS4uLi5MJC4uLnw [6]: https://gchq.github.io/CyberChef/#recipe=RC4(%7B'option':'UTF8','string':'secret'%7D,'Hex','Hex')Disassemble_x86('64','Full%20x86%20architecture',16,0,true,true)&input=MjFkZGQyNTQwMTYwZWU2NWZlMDc3NzEwM2YyYTM5ZmJlNWJjYjZhYTBhYWJkNDE0ZjkwYzZjYWY1MzEyNzU0YWY3NzRiNzZiM2JiY2QxOTNjYjNkZGZkYmM1YTI2NTMzYTY4NmI1OWI4ZmVkNGQzODBkNDc0NDIwMWFlYzIwNDA1MDcxMzhlMmZlMmIzOTUwNDQ2ZGIzMWQyYmM2MjliZTRkM2YyZWIwMDQzYzI5M2Q3YTVkMjk2MmMwMGZlNmRhMzAwNzJkOGM1YTZiNGZlN2Q4NTlhMDQwZWVhZjI5OTczMzYzMDJmNWEwZWMxOQ [7]: https://gchq.github.io/CyberChef/#recipe=Fork('%5C%5Cn','%5C%5Cn',false)From_UNIX_Timestamp('Seconds%20(s)')&input=OTc4MzQ2ODAwCjEwMTI2NTEyMDAKMTA0NjY5NjQwMAoxMDgxMDg3MjAwCjExMTUzMDUyMDAKMTE0OTYwOTYwMA - [8]: https://gchq.github.io/CyberChef/#recipe=Fork('%5C%5Cn','%5C%5Cn',false)Conditional_Jump('1',2,10)To_Hex('Space')Return()To_Base64('A-Za-z0-9%2B/%3D')&input=U29tZSBkYXRhIHdpdGggYSAxIGluIGl0ClNvbWUgZGF0YSB3aXRoIGEgMiBpbiBpdA + [8]: https://gchq.github.ioeCyberChef/#recipe=Fork('%5C%5Cn','%5C%5Cn',false)Conditional_Jump('1',false,'base64',10)To_Hex('Space')Return()Label('base64')To_Base64('A-Za-z0-9%2B/%3D')&input=U29tZSBkYXRhIHdpdGggYSAxIGluIGl0ClNvbWUgZGF0YSB3aXRoIGEgMiBpbiBpdA [9]: https://gchq.github.io/CyberChef/#recipe=Register('key%3D(%5B%5C%5Cda-f%5D*)',true,false)Find_/_Replace(%7B'option':'Regex','string':'.*data%3D(.*)'%7D,'$1',true,false,true)RC4(%7B'option':'Hex','string':'$R0'%7D,'Hex','Latin1')&input=aHR0cDovL21hbHdhcmV6LmJpei9iZWFjb24ucGhwP2tleT0wZTkzMmE1YyZkYXRhPThkYjdkNWViZTM4NjYzYTU0ZWNiYjMzNGUzZGIxMQ [10]: https://gchq.github.io/CyberChef/#recipe=XOR(%7B'option':'Hex','string':'3a'%7D,'',false)To_Hexdump(16,false,false)&input=VGhlIGFuc3dlciB0byB0aGUgdWx0aW1hdGUgcXVlc3Rpb24gb2YgbGlmZSwgdGhlIFVuaXZlcnNlLCBhbmQgZXZlcnl0aGluZyBpcyA0Mi4 diff --git a/src/core/FlowControl.js b/src/core/FlowControl.js index 4a94ffdf..bba5eaf1 100755 --- a/src/core/FlowControl.js +++ b/src/core/FlowControl.js @@ -170,18 +170,14 @@ const FlowControl = { */ runJump: function(state) { let ings = state.opList[state.progress].getIngValues(), - jumpNum = ings[0], + jmpIndex = FlowControl._getLabelIndex(ings[0], state), maxJumps = ings[1]; - if (jumpNum < 0) { - jumpNum--; - } - - if (state.numJumps >= maxJumps) { + if (state.numJumps >= maxJumps || jmpIndex === -1) { return state; } - state.progress += jumpNum; + state.progress = jmpIndex; state.numJumps++; return state; }, @@ -201,20 +197,20 @@ const FlowControl = { let ings = state.opList[state.progress].getIngValues(), dish = state.dish, regexStr = ings[0], - jumpNum = ings[1], - maxJumps = ings[2]; + invert = ings[1], + jmpIndex = FlowControl._getLabelIndex(ings[2], state), + maxJumps = ings[3]; - if (jumpNum < 0) { - jumpNum--; - } - - if (state.numJumps >= maxJumps) { + if (state.numJumps >= maxJumps || jmpIndex === -1) { return state; } - if (regexStr !== "" && dish.get(Dish.STRING).search(regexStr) > -1) { - state.progress += jumpNum; - state.numJumps++; + if (regexStr !== "") { + let strMatch = dish.get(Dish.STRING).search(regexStr) > -1; + if (!invert && strMatch || invert && !strMatch) { + state.progress = jmpIndex; + state.numJumps++; + } } return state; @@ -249,6 +245,26 @@ const FlowControl = { return state; }, + + /** + * Returns the index of a label. + * + * @param {Object} state + * @param {string} name + * @returns {number} + */ + _getLabelIndex: function(name, state) { + for (let o = 0; o < state.opList.length; o++) { + let operation = state.opList[o]; + if (operation.name === "Label"){ + let ings = operation.getIngValues(); + if (name === ings[0]) { + return o; + } + } + } + return -1; + }, }; export default FlowControl; diff --git a/src/core/config/Categories.js b/src/core/config/Categories.js index 3bc672b7..69ef5155 100755 --- a/src/core/config/Categories.js +++ b/src/core/config/Categories.js @@ -320,6 +320,7 @@ const Categories = [ "Fork", "Merge", "Register", + "Label", "Jump", "Conditional Jump", "Return", diff --git a/src/core/config/OperationConfig.js b/src/core/config/OperationConfig.js index 43072558..56b6cca1 100755 --- a/src/core/config/OperationConfig.js +++ b/src/core/config/OperationConfig.js @@ -137,15 +137,15 @@ const OperationConfig = { }, "Jump": { module: "Default", - description: "Jump forwards or backwards over the specified number of operations.", + description: "Jump forwards or backwards to the specified Label", inputType: "string", outputType: "string", flowControl: true, args: [ { - name: "Number of operations to jump over", - type: "number", - value: 0 + name: "Label name", + type: "string", + value: "" }, { name: "Maximum jumps (if jumping backwards)", @@ -156,7 +156,7 @@ const OperationConfig = { }, "Conditional Jump": { module: "Default", - description: "Conditionally jump forwards or backwards over the specified number of operations based on whether the data matches the specified regular expression.", + description: "Conditionally jump forwards or backwards to the specified Label based on whether the data matches the specified regular expression.", inputType: "string", outputType: "string", flowControl: true, @@ -167,9 +167,14 @@ const OperationConfig = { value: "" }, { - name: "Number of operations to jump over if match found", - type: "number", - value: 0 + name: "Invert match", + type: "boolean", + value: false + }, + { + name: "Label name", + type: "shortString", + value: "" }, { name: "Maximum jumps (if jumping backwards)", @@ -178,6 +183,20 @@ const OperationConfig = { } ] }, + "Label": { + module: "Default", + description: "Provides a location for conditional and fixed jumps to redirect execution to.", + inputType: "string", + outputType: "string", + flowControl: true, + args: [ + { + name: "Name", + type: "shortString", + value: "" + } + ] + }, "Return": { module: "Default", description: "End execution of operations at this point in the recipe.", diff --git a/src/core/config/modules/Default.js b/src/core/config/modules/Default.js index dec015a5..19d6c803 100644 --- a/src/core/config/modules/Default.js +++ b/src/core/config/modules/Default.js @@ -151,6 +151,7 @@ OpModules.Default = { "Fork": FlowControl.runFork, "Merge": FlowControl.runMerge, "Register": FlowControl.runRegister, + "Label": FlowControl.runComment, "Jump": FlowControl.runJump, "Conditional Jump": FlowControl.runCondJump, "Return": FlowControl.runReturn, diff --git a/src/web/html/index.html b/src/web/html/index.html index 66dfcc80..b6289772 100755 --- a/src/web/html/index.html +++ b/src/web/html/index.html @@ -428,7 +428,7 @@
  • Convert data from a hexdump, then decompress
  • Decrypt and disassemble shellcode
  • Display multiple timestamps as full dates
  • -
  • Carry out different operations on data of different types
  • +
  • Carry out different operations on data of different types
  • Use parts of the input as arguments to operations
  • diff --git a/test/tests/operations/FlowControl.js b/test/tests/operations/FlowControl.js index 42a4bfd3..04ed93eb 100644 --- a/test/tests/operations/FlowControl.js +++ b/test/tests/operations/FlowControl.js @@ -60,14 +60,15 @@ TestRegister.addTests([ expectedOutput: "U29tZSBkYXRhIHdpdGggYSAxIGluIGl0\n53 6f 6d 65 20 64 61 74 61 20 77 69 74 68 20 61 20 32 20 69 6e 20 69 74\n", recipeConfig: [ {"op": "Fork", "args": ["\\n", "\\n", false]}, - {"op": "Conditional Jump", "args": ["1", "2", "10"]}, + {"op": "Conditional Jump", "args": ["1", false, "skipReturn", "10"]}, {"op": "To Hex", "args": ["Space"]}, {"op": "Return", "args": []}, + {"op": "Label", "args": ["skipReturn"]}, {"op": "To Base64", "args": ["A-Za-z0-9+/="]} ] }, { - name: "Jump: skips 0", + name: "Jump: Empty Label", input: [ "should be changed", ].join("\n"), @@ -77,7 +78,7 @@ TestRegister.addTests([ recipeConfig: [ { op: "Jump", - args: [0, 10], + args: ["", 10], }, { op: "Find / Replace", @@ -105,7 +106,7 @@ TestRegister.addTests([ recipeConfig: [ { op: "Jump", - args: [1, 10], + args: ["skipReplace", 10], }, { op: "Find / Replace", @@ -120,6 +121,10 @@ TestRegister.addTests([ true, ], }, + { + op: "Label", + args: ["skipReplace"] + }, ], }, { @@ -137,7 +142,7 @@ TestRegister.addTests([ recipeConfig: [ { op: "Conditional Jump", - args: ["match", 0, 0], + args: ["match", false, "", 0], }, { op: "Find / Replace", @@ -212,7 +217,7 @@ TestRegister.addTests([ recipeConfig: [ { op: "Conditional Jump", - args: ["match", 1, 10], + args: ["match", false, "skip match", 10], }, { op: "Find / Replace", @@ -227,6 +232,9 @@ TestRegister.addTests([ true, ], }, + { + op: "Label", args: ["skip match"], + }, { op: "Find / Replace", args: [ @@ -251,9 +259,13 @@ TestRegister.addTests([ "replaced", ].join("\n"), recipeConfig: [ + { + op: "Label", + args: ["back to the beginning"], + }, { op: "Jump", - args: [1], + args: ["skip replace"], }, { op: "Find / Replace", @@ -268,9 +280,13 @@ TestRegister.addTests([ true, ], }, + { + op: "Label", + args: ["skip replace"], + }, { op: "Conditional Jump", - args: ["match", -2, 10], + args: ["match", false, "back to the beginning", 10], }, ], },