stringLiteralReplacer refactoring + fix of incorrect cache of value with stringArrayThreshold chance

This commit is contained in:
sanex3339
2016-12-26 18:06:32 +03:00
parent 6aba608f36
commit 8f73014d28
5 changed files with 128 additions and 84 deletions
+59 -49
View File
@@ -198,8 +198,8 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
var escodegen = __webpack_require__(25);
var esprima = __webpack_require__(48);
var estraverse = __webpack_require__(15);
var NodeType_1 = __webpack_require__(16);
var estraverse = __webpack_require__(16);
var NodeType_1 = __webpack_require__(15);
var Node_1 = __webpack_require__(12);
var NodeUtils = function () {
@@ -530,7 +530,7 @@ var _createClass3 = _interopRequireDefault(_createClass2);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var NodeType_1 = __webpack_require__(16);
var NodeType_1 = __webpack_require__(15);
var Node = function () {
function Node() {
@@ -895,12 +895,6 @@ exports.AbstractCustomNode = AbstractCustomNode;
/***/ },
/* 15 */
/***/ function(module, exports) {
module.exports = require("estraverse");
/***/ },
/* 16 */
/***/ function(module, exports, __webpack_require__) {
"use strict";
@@ -942,6 +936,12 @@ exports.NodeType = Utils_1.Utils.strEnumify({
WhileStatement: 'WhileStatement'
});
/***/ },
/* 16 */
/***/ function(module, exports) {
module.exports = require("estraverse");
/***/ },
/* 17 */
/***/ function(module, exports, __webpack_require__) {
@@ -1382,7 +1382,7 @@ var _createClass3 = _interopRequireDefault(_createClass2);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var escodegen = __webpack_require__(25);
var NodeType_1 = __webpack_require__(16);
var NodeType_1 = __webpack_require__(15);
var Nodes = function () {
function Nodes() {
@@ -2176,9 +2176,9 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
var tslib_1 = __webpack_require__(3);
var inversify_1 = __webpack_require__(2);
var ServiceIdentifiers_1 = __webpack_require__(4);
var estraverse = __webpack_require__(15);
var estraverse = __webpack_require__(16);
var NodeTransformers_1 = __webpack_require__(40);
var NodeType_1 = __webpack_require__(16);
var NodeType_1 = __webpack_require__(15);
var ObfuscationEvents_1 = __webpack_require__(22);
var VisitorDirection_1 = __webpack_require__(81);
var Node_1 = __webpack_require__(12);
@@ -4490,9 +4490,9 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
var tslib_1 = __webpack_require__(3);
var inversify_1 = __webpack_require__(2);
var ServiceIdentifiers_1 = __webpack_require__(4);
var estraverse = __webpack_require__(15);
var estraverse = __webpack_require__(16);
var CustomNodes_1 = __webpack_require__(20);
var NodeType_1 = __webpack_require__(16);
var NodeType_1 = __webpack_require__(15);
var AbstractNodeTransformer_1 = __webpack_require__(17);
var Node_1 = __webpack_require__(12);
var NodeAppender_1 = __webpack_require__(24);
@@ -4740,9 +4740,9 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
var tslib_1 = __webpack_require__(3);
var inversify_1 = __webpack_require__(2);
var ServiceIdentifiers_1 = __webpack_require__(4);
var estraverse = __webpack_require__(15);
var estraverse = __webpack_require__(16);
var NodeObfuscatorsReplacers_1 = __webpack_require__(19);
var NodeType_1 = __webpack_require__(16);
var NodeType_1 = __webpack_require__(15);
var AbstractNodeTransformer_1 = __webpack_require__(17);
var Node_1 = __webpack_require__(12);
var NodeUtils_1 = __webpack_require__(8);
@@ -4836,9 +4836,9 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
var tslib_1 = __webpack_require__(3);
var inversify_1 = __webpack_require__(2);
var ServiceIdentifiers_1 = __webpack_require__(4);
var estraverse = __webpack_require__(15);
var estraverse = __webpack_require__(16);
var NodeObfuscatorsReplacers_1 = __webpack_require__(19);
var NodeType_1 = __webpack_require__(16);
var NodeType_1 = __webpack_require__(15);
var AbstractNodeTransformer_1 = __webpack_require__(17);
var Node_1 = __webpack_require__(12);
var NodeUtils_1 = __webpack_require__(8);
@@ -4966,9 +4966,9 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
var tslib_1 = __webpack_require__(3);
var inversify_1 = __webpack_require__(2);
var ServiceIdentifiers_1 = __webpack_require__(4);
var estraverse = __webpack_require__(15);
var estraverse = __webpack_require__(16);
var NodeObfuscatorsReplacers_1 = __webpack_require__(19);
var NodeType_1 = __webpack_require__(16);
var NodeType_1 = __webpack_require__(15);
var AbstractNodeTransformer_1 = __webpack_require__(17);
var Node_1 = __webpack_require__(12);
var NodeUtils_1 = __webpack_require__(8);
@@ -5064,9 +5064,9 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
var tslib_1 = __webpack_require__(3);
var inversify_1 = __webpack_require__(2);
var ServiceIdentifiers_1 = __webpack_require__(4);
var estraverse = __webpack_require__(15);
var estraverse = __webpack_require__(16);
var NodeObfuscatorsReplacers_1 = __webpack_require__(19);
var NodeType_1 = __webpack_require__(16);
var NodeType_1 = __webpack_require__(15);
var AbstractNodeTransformer_1 = __webpack_require__(17);
var Node_1 = __webpack_require__(12);
var NodeUtils_1 = __webpack_require__(8);
@@ -5238,7 +5238,7 @@ var inversify_1 = __webpack_require__(2);
var ServiceIdentifiers_1 = __webpack_require__(4);
var escodegen = __webpack_require__(25);
var NodeObfuscatorsReplacers_1 = __webpack_require__(19);
var NodeType_1 = __webpack_require__(16);
var NodeType_1 = __webpack_require__(15);
var AbstractNodeTransformer_1 = __webpack_require__(17);
var Node_1 = __webpack_require__(12);
var MemberExpressionObfuscator = function (_AbstractNodeTransfor) {
@@ -5400,7 +5400,7 @@ var tslib_1 = __webpack_require__(3);
var inversify_1 = __webpack_require__(2);
var ServiceIdentifiers_1 = __webpack_require__(4);
var escodegen = __webpack_require__(25);
var NodeType_1 = __webpack_require__(16);
var NodeType_1 = __webpack_require__(15);
var AbstractNodeTransformer_1 = __webpack_require__(17);
var Node_1 = __webpack_require__(12);
var Utils_1 = __webpack_require__(13);
@@ -5498,9 +5498,9 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
var tslib_1 = __webpack_require__(3);
var inversify_1 = __webpack_require__(2);
var ServiceIdentifiers_1 = __webpack_require__(4);
var estraverse = __webpack_require__(15);
var estraverse = __webpack_require__(16);
var NodeObfuscatorsReplacers_1 = __webpack_require__(19);
var NodeType_1 = __webpack_require__(16);
var NodeType_1 = __webpack_require__(15);
var AbstractNodeTransformer_1 = __webpack_require__(17);
var Node_1 = __webpack_require__(12);
var NodeUtils_1 = __webpack_require__(8);
@@ -5861,20 +5861,18 @@ var StringLiteralReplacer = StringLiteralReplacer_1 = function (_AbstractReplace
(0, _createClass3.default)(StringLiteralReplacer, [{
key: "replace",
value: function replace(nodeValue) {
var replaceWithStringArrayFlag = nodeValue.length >= StringLiteralReplacer_1.minimumLengthForStringArray && RandomGeneratorUtils_1.RandomGeneratorUtils.getRandomFloat(0, 1) <= this.options.stringArrayThreshold;
var usingStringArray = this.options.stringArray && nodeValue.length >= StringLiteralReplacer_1.minimumLengthForStringArray && RandomGeneratorUtils_1.RandomGeneratorUtils.getRandomFloat(0, 1) <= this.options.stringArrayThreshold;
var cacheKey = nodeValue + "-" + String(usingStringArray);
if (this.stringLiteralCache.has(cacheKey) && this.options.stringArrayEncoding !== StringArrayEncoding_1.StringArrayEncoding.rc4) {
return this.stringLiteralCache.get(cacheKey);
}
var result = void 0;
if (this.options.stringArray && replaceWithStringArrayFlag) {
if (this.stringLiteralCache.has(nodeValue) && this.options.stringArrayEncoding !== StringArrayEncoding_1.StringArrayEncoding.rc4) {
return this.stringLiteralCache.get(nodeValue);
}
if (usingStringArray) {
result = this.replaceStringLiteralWithStringArrayCall(nodeValue);
} else {
if (this.stringLiteralCache.has(nodeValue)) {
return this.stringLiteralCache.get(nodeValue);
}
result = "'" + Utils_1.Utils.stringToUnicodeEscapeSequence(nodeValue, !this.options.unicodeEscapeSequence) + "'";
}
this.stringLiteralCache.set(nodeValue, result);
this.stringLiteralCache.set(cacheKey, result);
return result;
}
}, {
@@ -5896,24 +5894,36 @@ var StringLiteralReplacer = StringLiteralReplacer_1 = function (_AbstractReplace
return hexadecimalIndex;
}
}, {
key: "replaceStringLiteralWithStringArrayCall",
value: function replaceStringLiteralWithStringArrayCall(value) {
var rc4Key = '';
key: "getEncodedValue",
value: function getEncodedValue(value) {
var encodedValue = void 0,
key = void 0;
switch (this.options.stringArrayEncoding) {
case StringArrayEncoding_1.StringArrayEncoding.rc4:
rc4Key = RandomGeneratorUtils_1.RandomGeneratorUtils.getRandomGenerator().pickone(StringLiteralReplacer_1.rc4Keys);
value = CryptUtils_1.CryptUtils.btoa(CryptUtils_1.CryptUtils.rc4(value, rc4Key));
key = RandomGeneratorUtils_1.RandomGeneratorUtils.getRandomGenerator().pickone(StringLiteralReplacer_1.rc4Keys);
encodedValue = CryptUtils_1.CryptUtils.btoa(CryptUtils_1.CryptUtils.rc4(value, key));
break;
case StringArrayEncoding_1.StringArrayEncoding.base64:
value = CryptUtils_1.CryptUtils.btoa(value);
encodedValue = CryptUtils_1.CryptUtils.btoa(value);
break;
default:
encodedValue = value;
}
value = Utils_1.Utils.stringToUnicodeEscapeSequence(value, !this.options.unicodeEscapeSequence);
var hexadecimalIndex = this.getArrayHexadecimalIndex(value);
encodedValue = Utils_1.Utils.stringToUnicodeEscapeSequence(encodedValue, !this.options.unicodeEscapeSequence);
return { encodedValue: encodedValue, key: key };
}
}, {
key: "replaceStringLiteralWithStringArrayCall",
value: function replaceStringLiteralWithStringArrayCall(value) {
var _getEncodedValue = this.getEncodedValue(value),
encodedValue = _getEncodedValue.encodedValue,
key = _getEncodedValue.key;
var hexadecimalIndex = this.getArrayHexadecimalIndex(encodedValue);
var rotatedStringArrayStorageId = Utils_1.Utils.stringRotate(this.stringArrayStorage.getStorageId(), 1);
var stringArrayStorageCallsWrapperName = "_" + Utils_1.Utils.hexadecimalPrefix + rotatedStringArrayStorageId;
if (this.options.stringArrayEncoding === StringArrayEncoding_1.StringArrayEncoding.rc4) {
return stringArrayStorageCallsWrapperName + "('" + hexadecimalIndex + "', '" + Utils_1.Utils.stringToUnicodeEscapeSequence(rc4Key, !this.options.unicodeEscapeSequence) + "')";
if (key) {
return stringArrayStorageCallsWrapperName + "('" + hexadecimalIndex + "', '" + Utils_1.Utils.stringToUnicodeEscapeSequence(key, !this.options.unicodeEscapeSequence) + "')";
}
return stringArrayStorageCallsWrapperName + "('" + hexadecimalIndex + "')";
}
@@ -6279,7 +6289,7 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
var tslib_1 = __webpack_require__(3);
var inversify_1 = __webpack_require__(2);
var ServiceIdentifiers_1 = __webpack_require__(4);
var estraverse = __webpack_require__(15);
var estraverse = __webpack_require__(16);
var CalleeDataExtractors_1 = __webpack_require__(37);
var Node_1 = __webpack_require__(12);
var NodeUtils_1 = __webpack_require__(8);
@@ -6397,7 +6407,7 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
var tslib_1 = __webpack_require__(3);
var inversify_1 = __webpack_require__(2);
var estraverse = __webpack_require__(15);
var estraverse = __webpack_require__(16);
var AbstractCalleeDataExtractor_1 = __webpack_require__(32);
var Node_1 = __webpack_require__(12);
var NodeUtils_1 = __webpack_require__(8);
@@ -6475,7 +6485,7 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
var tslib_1 = __webpack_require__(3);
var inversify_1 = __webpack_require__(2);
var estraverse = __webpack_require__(15);
var estraverse = __webpack_require__(16);
var AbstractCalleeDataExtractor_1 = __webpack_require__(32);
var Node_1 = __webpack_require__(12);
var NodeUtils_1 = __webpack_require__(8);
@@ -6560,7 +6570,7 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
var tslib_1 = __webpack_require__(3);
var inversify_1 = __webpack_require__(2);
var estraverse = __webpack_require__(15);
var estraverse = __webpack_require__(16);
var Node_1 = __webpack_require__(12);
var NodeUtils_1 = __webpack_require__(8);
var AbstractCalleeDataExtractor_1 = __webpack_require__(32);
+2 -2
View File
@@ -29,10 +29,10 @@
"esprima": "3.1.3",
"estraverse": "4.2.0",
"inversify": "^3.0.0-rc.2",
"lodash": "^4.17.2",
"lodash": "^4.17.3",
"mkdirp": "0.5.1",
"reflect-metadata": "^0.1.9",
"source-map-support": "0.4.7",
"source-map-support": "0.4.8",
"string-template": "^1.0.0",
"tslib": "^1.4.0"
},
+4
View File
@@ -0,0 +1,4 @@
export interface IEncodedValue {
encodedValue: string;
key?: string;
}
@@ -2,6 +2,7 @@ import { injectable, inject } from 'inversify';
import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
import { ICustomNodeGroup } from '../../../interfaces/custom-nodes/ICustomNodeGroup';
import { IEncodedValue } from '../../../interfaces/node-transformers/IEncodedValue';
import { IOptions } from '../../../interfaces/options/IOptions';
import { IStorage } from '../../../interfaces/storages/IStorage';
@@ -66,32 +67,26 @@ export class StringLiteralReplacer extends AbstractReplacer {
* @returns {string}
*/
public replace (nodeValue: string): string {
const replaceWithStringArrayFlag: boolean = (
nodeValue.length >= StringLiteralReplacer.minimumLengthForStringArray
&& RandomGeneratorUtils.getRandomFloat(0, 1) <= this.options.stringArrayThreshold
const usingStringArray: boolean = (
this.options.stringArray &&
nodeValue.length >= StringLiteralReplacer.minimumLengthForStringArray &&
RandomGeneratorUtils.getRandomFloat(0, 1) <= this.options.stringArrayThreshold
);
const cacheKey: string = `${nodeValue}-${String(usingStringArray)}`;
if (this.stringLiteralCache.has(cacheKey) && this.options.stringArrayEncoding !== StringArrayEncoding.rc4) {
return <string>this.stringLiteralCache.get(cacheKey);
}
let result: string;
if (this.options.stringArray && replaceWithStringArrayFlag) {
/**
* we can't use values from cache with `stringArrayEncoding: rc4`
* because rc4 key will be the same for same values
*/
if (this.stringLiteralCache.has(nodeValue) && this.options.stringArrayEncoding !== StringArrayEncoding.rc4) {
return <string>this.stringLiteralCache.get(nodeValue);
}
if (usingStringArray) {
result = this.replaceStringLiteralWithStringArrayCall(nodeValue);
} else {
if (this.stringLiteralCache.has(nodeValue)) {
return <string>this.stringLiteralCache.get(nodeValue);
}
result = `'${Utils.stringToUnicodeEscapeSequence(nodeValue, !this.options.unicodeEscapeSequence)}'`;
}
this.stringLiteralCache.set(nodeValue, result);
this.stringLiteralCache.set(cacheKey, result);
return result;
}
@@ -125,32 +120,45 @@ export class StringLiteralReplacer extends AbstractReplacer {
/**
* @param value
* @returns {string}
* @returns {IEncodedValue}
*/
private replaceStringLiteralWithStringArrayCall (value: string): string {
let rc4Key: string = '';
private getEncodedValue (value: string): IEncodedValue {
let encodedValue: string,
key: string | undefined;
switch (this.options.stringArrayEncoding) {
case StringArrayEncoding.rc4:
rc4Key = RandomGeneratorUtils.getRandomGenerator().pickone(StringLiteralReplacer.rc4Keys);
value = CryptUtils.btoa(CryptUtils.rc4(value, rc4Key));
key = RandomGeneratorUtils.getRandomGenerator().pickone(StringLiteralReplacer.rc4Keys);
encodedValue = CryptUtils.btoa(CryptUtils.rc4(value, key));
break;
case StringArrayEncoding.base64:
value = CryptUtils.btoa(value);
encodedValue = CryptUtils.btoa(value);
break;
default:
encodedValue = value;
}
value = Utils.stringToUnicodeEscapeSequence(value, !this.options.unicodeEscapeSequence);
encodedValue = Utils.stringToUnicodeEscapeSequence(encodedValue, !this.options.unicodeEscapeSequence);
const hexadecimalIndex: string = this.getArrayHexadecimalIndex(value);
return { encodedValue, key };
}
/**
* @param value
* @returns {string}
*/
private replaceStringLiteralWithStringArrayCall (value: string): string {
const { encodedValue, key }: IEncodedValue = this.getEncodedValue(value);
const hexadecimalIndex: string = this.getArrayHexadecimalIndex(encodedValue);
const rotatedStringArrayStorageId: string = Utils.stringRotate(this.stringArrayStorage.getStorageId(), 1);
const stringArrayStorageCallsWrapperName: string = `_${Utils.hexadecimalPrefix}${rotatedStringArrayStorageId}`;
if (this.options.stringArrayEncoding === StringArrayEncoding.rc4) {
return `${stringArrayStorageCallsWrapperName}('${hexadecimalIndex}', '${Utils.stringToUnicodeEscapeSequence(rc4Key, !this.options.unicodeEscapeSequence)}')`;
if (key) {
return `${stringArrayStorageCallsWrapperName}('${hexadecimalIndex}', '${Utils.stringToUnicodeEscapeSequence(key, !this.options.unicodeEscapeSequence)}')`;
}
return `${stringArrayStorageCallsWrapperName}('${hexadecimalIndex}')`;
@@ -21,7 +21,7 @@ describe('LiteralObfuscator', () => {
assert.match(obfuscationResult.getObfuscatedCode(), /^var *test *= *'\\x74\\x65\\x73\\x74';$/);
});
it('should replace literal node value with unicode escape sequence from unicode array', () => {
it('should replace literal node value with unicode escape sequence from string array', () => {
let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
`var test = 'test';`,
{
@@ -38,7 +38,7 @@ describe('LiteralObfuscator', () => {
assert.match(obfuscationResult.getObfuscatedCode(), /var *test *= *_0x([a-z0-9]){4}\('0x0'\);/);
});
it('should replace literal node value with raw value from unicode array if `unicodeEscapeSequence` is disabled', () => {
it('should replace literal node value with raw value from string array if `unicodeEscapeSequence` is disabled', () => {
let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
`var test = 'test';`,
{
@@ -56,7 +56,7 @@ describe('LiteralObfuscator', () => {
assert.match(obfuscationResult.getObfuscatedCode(), /var *test *= *_0x([a-z0-9]){4}\('0x0'\);/);
});
it('should replace literal node value with raw value from unicode array if `unicodeEscapeSequence` and `stringArray` are disabled', () => {
it('should replace literal node value with raw value from string array if `unicodeEscapeSequence` and `stringArray` are disabled', () => {
let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
`var test = 'test';`,
{
@@ -83,7 +83,7 @@ describe('LiteralObfuscator', () => {
));
});
it('shouldn\'t replace short literal node value with unicode array value', () => {
it('shouldn\'t replace short literal node value with value from string array', () => {
let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
`var test = 'te';`,
{
@@ -96,7 +96,7 @@ describe('LiteralObfuscator', () => {
assert.match(obfuscationResult.getObfuscatedCode(), /var *test *= *'\\x74\\x65';/);
});
it('should replace literal node value with unicode array value encoded using base64', () => {
it('should replace literal node value with value from string array encoded using base64', () => {
let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
`var test = 'test';`,
{
@@ -114,7 +114,7 @@ describe('LiteralObfuscator', () => {
assert.match(obfuscationResult.getObfuscatedCode(), /var *test *= *_0x([a-z0-9]){4}\('0x0'\);/);
});
it('should replace literal node value with unicode array value encoded using rc4', () => {
it('should replace literal node value with value from string array encoded using rc4', () => {
let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
`var test = 'test';`,
{
@@ -130,6 +130,28 @@ describe('LiteralObfuscator', () => {
/var *test *= *_0x([a-z0-9]){4}\('0x0', '(\\x[a-f0-9]*){4}'\);/
);
});
it('should replace literal node value with value from string array with `stringArrayThreshold` chance', () => {
const samples: number = 1000;
const stringArrayThreshold: number = 0.5;
const delta: number = 0.1;
const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
`var test = 'test';\n`.repeat(samples),
{
...NO_CUSTOM_NODES_PRESET,
stringArray: true,
stringArrayThreshold: stringArrayThreshold
}
);
const regExp1: RegExp = /var *test *= *_0x([a-z0-9]){4}\('0x0'\);/g;
const regExp2: RegExp = /var *test *= *'\\x74\\x65\\x73\\x74';/g;
const stringArrayMatchesLength = obfuscationResult.getObfuscatedCode().match(regExp1)!.length;
const noStringArrayMatchesLength = obfuscationResult.getObfuscatedCode().match(regExp2)!.length;
assert.closeTo(stringArrayMatchesLength / samples, stringArrayThreshold, delta);
assert.closeTo(noStringArrayMatchesLength / samples, stringArrayThreshold, delta);
});
});
it('should obfuscate literal node with boolean value', () => {