Created
September 2, 2017 01:38
-
-
Save patmigliaccio/3ff42251a1e4487be6408cd9b1112f9d to your computer and use it in GitHub Desktop.
patmigliaccio.com/client-side-security 7/27/17
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Reverses basic obfuscation techniques used by the JavaScript Obfuscator. | |
* | |
* Reference: https://javascriptobfuscator.com/ | |
* | |
* @param {string} data String representation of a JavaScript file | |
* @returns {string} | |
*/ | |
function reverseObfuscation(data) { | |
return replaceArrayReferences(replaceHexArrayValues(replaceHexVariables(data))); | |
} | |
/** | |
* Replaces all hex values with `_0x` prefix, 4 characters following, | |
* and an optional `x#` value to letter(s) representation. | |
* | |
* e.g. `_0xcd03` -> `a` or `_0xea02x8` -> `ab` | |
* | |
* @param {string} data JavaScript file text | |
* @returns | |
*/ | |
function replaceHexVariables(data) { | |
// Match all hex values | |
let matches = data.match(/_0x.{4}(x[0-9a-z]+)?/g); | |
// Filters out only unique hex values. | |
// Reference: https://stackoverflow.com/a/9229821/5199198 | |
var detected = {}; | |
matches | |
.filter(value => detected.hasOwnProperty(value) ? false : (detected[value] = true)) | |
.forEach((hexValue, i) => { | |
// Replaces hex value with character | |
data = data.replace(new RegExp(hexValue, "g"), numberToLetters(i)); | |
}); | |
return data; | |
} | |
/** | |
* Converts hex values `\x??` found in arrays to their ASCII equivalent. | |
* | |
* e.g. `\x63` -> `c` | |
* | |
* @param {string} data JavaScript file text | |
* @returns {string} | |
*/ | |
function replaceHexArrayValues(data) { | |
return data = data.replace(/\\x.{2}/g, value => String.fromCharCode(parseInt(value.substr(2), 16))); | |
} | |
/** | |
* Replaces array reference values with the property name stored in an array. | |
* | |
* e.g. `e[a[6]]()` -> `e['trim']()` | |
* | |
* @param {string} data JavaScript file text | |
*/ | |
function replaceArrayReferences(data) { | |
let arrays = {}; | |
// Extracts basic array declarations created by the obfuscator into the `arrays` object. | |
const arraySyntaxPattern = /var\s(.+)\s=\s(\[.+\]);/g; | |
data.replace(arraySyntaxPattern, (match, arrayName, arrayString) => { | |
// Be wary of the use of `eval` here | |
// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval | |
arrays[arrayName] = eval(arrayString); | |
}); | |
// Replaces array references with the corresponding value from the `arrays` object. | |
const arrayReferenceSyntaxPattern = /([a-z]+)\[([0-9]+)\]/g; | |
data = data.replace(arrayReferenceSyntaxPattern, (match, arrayName, indexValue) => { | |
return Array.isArray(arrays[arrayName]) && arrays[arrayName][indexValue] !== undefined ? `'${arrays[arrayName][indexValue]}'` : match; | |
}); | |
return data; | |
} | |
/** | |
* Converts integers to multi-character strings. | |
* | |
* e.g. `0` -> a or `26` -> `aa` | |
* | |
* Reference: https://stackoverflow.com/a/32007970/5199198 | |
* | |
* @param {number} i Position of value | |
* @returns {string} | |
*/ | |
function numberToLetters(i) { | |
return (i >= 26 ? numberToLetters((i / 26 >> 0) - 1) : '') + 'abcdefghijklmnopqrstuvwxyz'[i % 26 >> 0]; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment