diff --git a/src/core/config/Categories.js b/src/core/config/Categories.js index f04b5fd9..09f0187c 100755 --- a/src/core/config/Categories.js +++ b/src/core/config/Categories.js @@ -66,6 +66,7 @@ const Categories = [ "Encode text", "Decode text", "Swap endianness", + "PHP Deserialize", ] }, { diff --git a/src/core/config/OperationConfig.js b/src/core/config/OperationConfig.js index 9caa4f91..469a98c1 100755 --- a/src/core/config/OperationConfig.js +++ b/src/core/config/OperationConfig.js @@ -35,6 +35,7 @@ import StrUtils from "../operations/StrUtils.js"; import Tidy from "../operations/Tidy.js"; import Unicode from "../operations/Unicode.js"; import URL_ from "../operations/URL.js"; +import PhpSerialization from "../operations/PhpSerialization.js"; /** @@ -3845,6 +3846,19 @@ const OperationConfig = { } ] }, + "PHP Deserialize": { + module: "Default", + description: "PHP Deserialize a given input.

This function does not support object tags.

Output valid JSON: JSON doesn't support integers as keys, where as PHP serialization does. Enabling this will cast these integers to strings. This will also escape backslashes.", + inputType: "string", + outputType: "string", + args: [ + { + name: "Output valid JSON", + type: "boolean", + value: PhpSerialization.OUTPUT_VALID_JSON + } + ] + }, }; diff --git a/src/core/config/modules/Default.js b/src/core/config/modules/Default.js index 682db223..8c13cfd2 100644 --- a/src/core/config/modules/Default.js +++ b/src/core/config/modules/Default.js @@ -27,7 +27,7 @@ import StrUtils from "../../operations/StrUtils.js"; import Tidy from "../../operations/Tidy.js"; import Unicode from "../../operations/Unicode.js"; import UUID from "../../operations/UUID.js"; - +import PhpSerialization from "../../operations/PhpSerialization"; /** * Default module. @@ -155,6 +155,7 @@ OpModules.Default = { "Conditional Jump": FlowControl.runCondJump, "Return": FlowControl.runReturn, "Comment": FlowControl.runComment, + "PHP Deserialize": PhpSerialization.PhpDeserialize, /* diff --git a/src/core/operations/PhpSerialization.js b/src/core/operations/PhpSerialization.js new file mode 100644 index 00000000..1d4394c8 --- /dev/null +++ b/src/core/operations/PhpSerialization.js @@ -0,0 +1,128 @@ +/** + * Php Serialization operations. + * This Javascript implementation is based on the Python + * implementation by Armin Ronacher (2016). + * See: https://github.com/mitsuhiko/phpserialize/ + * + * @author Jarmo van Lenthe [github.com/jarmovanlenthe] + * @copyright Crown Copyright 2017 + * @license BSD-3-Clause + * + * @namespace + */ + +const PhpSerialization = { + + /** + * @constant + * @default + */ + OUTPUT_VALID_JSON: true, + + PhpDeserialize: function (input, args) { + function handleInput() { + function read(length) { + let result = ""; + for (let idx = 0; idx < length; idx++) { + let char = inputPart.shift(); + if (char === undefined) { + throw "End of input reached before end of script"; + } + result += char; + } + return result; + } + + function readUntil(until) { + let result = ""; + while (true) { + let char = read(1); + if (char === until) { + break; + } + else { + result += char; + } + } + return result; + + } + + function expect(expect) { + let result = read(expect.length); + if (result !== expect) { + throw "Unexpected input found"; + } + return result; + } + + function handleArray() { + let items = parseInt(readUntil(':')) * 2; + expect('{'); + let result = []; + let isKey = true; + let last_item = null; + for (let idx = 0; idx < items; idx++) { + let item = handleInput(); + if (isKey) { + last_item = item; + isKey = false; + } else { + let numberCheck = last_item.match(/[0-9]+/); + if (args[0] && numberCheck && numberCheck[0].length === last_item.length) + { + result.push('"' + last_item + '": ' + item); + } else { + result.push(last_item + ': ' + item); + } + isKey = true; + } + } + expect('}'); + return result; + } + + + let kind = read(1).toLowerCase(); + + switch (kind) { + case 'n': + expect(';'); + return ''; + + case 'i': + case 'd': + case 'b': + expect(':'); + let data = readUntil(';'); + if (kind === 'b') + return (parseInt(data) !== 0); + return data; + + + case 'a': + expect(':'); + return '{' + handleArray() + '}'; + + case 's': + expect(':'); + let length = readUntil(':'); + expect('"'); + let value = read(length); + expect('";'); + if (args[0]) + return '"' + value.replace(/"/g, '\\"') + '"'; + else + return '"' + value + '"'; + + default: + throw "Unknown type: " + kind; + } + } + + let inputPart = input.split(''); + return handleInput(); + } +}; + +export default PhpSerialization;