Kaynağa Gözat

LogicalExpressionControlFlowReplacer + tests

sanex3339 8 yıl önce
ebeveyn
işleme
ef64010fc5
27 değiştirilmiş dosya ile 880 ekleme ve 233 silme
  1. 335 135
      dist/index.js
  2. 3 3
      package.json
  3. 6 1
      src/container/modules/custom-nodes/CustomNodesModule.ts
  4. 5 0
      src/container/modules/node-transformers/NodeControlFlowTransformersModule.ts
  5. 63 0
      src/custom-nodes/control-flow-replacers-nodes/logical-expression-control-flow-replacer-nodes/LogicalExpressionFunctionNode.ts
  6. 6 6
      src/custom-nodes/control-flow-storage-nodes/ControlFlowStorageCallNode.ts
  7. 1 0
      src/enums/container/CustomNodes.ts
  8. 2 1
      src/enums/container/NodeControlFlowReplacers.ts
  9. 3 6
      src/node-transformers/node-control-flow-transformers/FunctionControlFlowTransformer.ts
  10. 103 5
      src/node-transformers/node-control-flow-transformers/control-flow-replacers/AbstractControlFlowReplacer.ts
  11. 13 74
      src/node-transformers/node-control-flow-transformers/control-flow-replacers/BinaryExpressionControlFlowReplacer.ts
  12. 92 0
      src/node-transformers/node-control-flow-transformers/control-flow-replacers/LogicalExpressionControlFlowReplacer.ts
  13. 9 0
      src/node/Node.ts
  14. 12 0
      src/node/NodeUtils.ts
  15. 40 0
      src/node/Nodes.ts
  16. 0 0
      test/fixtures/node-transformers/node-control-flow-transformers/control-flow-replacers/binary-expression-control-flow-replacer/binary-expression-control-flow-replacer-1.js
  17. 0 0
      test/fixtures/node-transformers/node-control-flow-transformers/control-flow-replacers/binary-expression-control-flow-replacer/binary-expression-control-flow-replacer-2.js
  18. 3 0
      test/fixtures/node-transformers/node-control-flow-transformers/control-flow-replacers/logical-expression-control-flow-replacer/logical-expression-control-flow-replacer-1.js
  19. 4 0
      test/fixtures/node-transformers/node-control-flow-transformers/control-flow-replacers/logical-expression-control-flow-replacer/logical-expression-control-flow-replacer-2.js
  20. 5 0
      test/fixtures/node-transformers/node-control-flow-transformers/control-flow-replacers/logical-expression-control-flow-replacer/logical-expression-control-flow-replacer-3.js
  21. 5 0
      test/fixtures/node-transformers/node-control-flow-transformers/control-flow-replacers/logical-expression-control-flow-replacer/logical-expression-control-flow-replacer-prohibited-nodes-1.js
  22. 3 0
      test/fixtures/node-transformers/node-control-flow-transformers/function-control-flow-transformer-zero-threshold.js
  23. 21 0
      test/functional-tests/node-transformers/node-control-flow-transformers/FunctionControlFlowTransformer.spec.ts
  24. 2 2
      test/functional-tests/node-transformers/node-control-flow-transformers/control-flow-replacers/BinaryExpressionControlFlowReplacer.spec.ts
  25. 115 0
      test/functional-tests/node-transformers/node-control-flow-transformers/control-flow-replacers/LogicalExpressionControlFlowReplacer.spec.ts
  26. 1 0
      test/index.spec.ts
  27. 28 0
      test/unit-tests/node/NodeUtils.spec.ts

+ 335 - 135
dist/index.js

@@ -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 () {
@@ -314,6 +314,14 @@ var NodeUtils = function () {
             }
             return NodeUtils.getNodeBlockScopeDepth(parentNode, depth);
         }
+    }, {
+        key: "getUnaryExpressionArgumentNode",
+        value: function getUnaryExpressionArgumentNode(unaryExpressionNode) {
+            if (Node_1.Node.isUnaryExpressionNode(unaryExpressionNode.argument)) {
+                return NodeUtils.getUnaryExpressionArgumentNode(unaryExpressionNode.argument);
+            }
+            return unaryExpressionNode.argument;
+        }
     }, {
         key: "parentize",
         value: function parentize(node) {
@@ -453,6 +461,12 @@ exports.RandomGeneratorUtils = RandomGeneratorUtils;
 
 /***/ },
 /* 10 */
+/***/ function(module, exports) {
+
+module.exports = require("babel-runtime/core-js/map");
+
+/***/ },
+/* 11 */
 /***/ function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -507,12 +521,6 @@ function initializable() {
 }
 exports.initializable = initializable;
 
-/***/ },
-/* 11 */
-/***/ function(module, exports) {
-
-module.exports = require("babel-runtime/core-js/map");
-
 /***/ },
 /* 12 */
 /***/ function(module, exports, __webpack_require__) {
@@ -530,7 +538,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() {
@@ -645,6 +653,11 @@ var Node = function () {
             var parentNodeIsMemberExpressionNode = Node.isMemberExpressionNode(parentNode) && parentNode.computed === false && parentNode.property === node;
             return !parentNodeIsPropertyNode && !parentNodeIsMemberExpressionNode && !Node.isLabelIdentifierNode(node, parentNode);
         }
+    }, {
+        key: "isUnaryExpressionNode",
+        value: function isUnaryExpressionNode(node) {
+            return node.type === NodeType_1.NodeType.UnaryExpression;
+        }
     }, {
         key: "isVariableDeclarationNode",
         value: function isVariableDeclarationNode(node) {
@@ -673,7 +686,7 @@ exports.Node = Node;
 "use strict";
 
 
-var _map = __webpack_require__(11);
+var _map = __webpack_require__(10);
 
 var _map2 = _interopRequireDefault(_map);
 
@@ -895,12 +908,6 @@ exports.AbstractCustomNode = AbstractCustomNode;
 
 /***/ },
 /* 15 */
-/***/ function(module, exports) {
-
-module.exports = require("estraverse");
-
-/***/ },
-/* 16 */
 /***/ function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -942,6 +949,12 @@ exports.NodeType = Utils_1.Utils.strEnumify({
     WhileStatement: 'WhileStatement'
 });
 
+/***/ },
+/* 16 */
+/***/ function(module, exports) {
+
+module.exports = require("estraverse");
+
 /***/ },
 /* 17 */
 /***/ function(module, exports, __webpack_require__) {
@@ -1006,11 +1019,12 @@ var CustomNodes;
     CustomNodes[CustomNodes["DebugProtectionFunctionIntervalNode"] = 5] = "DebugProtectionFunctionIntervalNode";
     CustomNodes[CustomNodes["DebugProtectionFunctionNode"] = 6] = "DebugProtectionFunctionNode";
     CustomNodes[CustomNodes["DomainLockNode"] = 7] = "DomainLockNode";
-    CustomNodes[CustomNodes["NodeCallsControllerFunctionNode"] = 8] = "NodeCallsControllerFunctionNode";
-    CustomNodes[CustomNodes["SelfDefendingUnicodeNode"] = 9] = "SelfDefendingUnicodeNode";
-    CustomNodes[CustomNodes["StringArrayCallsWrapper"] = 10] = "StringArrayCallsWrapper";
-    CustomNodes[CustomNodes["StringArrayNode"] = 11] = "StringArrayNode";
-    CustomNodes[CustomNodes["StringArrayRotateFunctionNode"] = 12] = "StringArrayRotateFunctionNode";
+    CustomNodes[CustomNodes["LogicalExpressionFunctionNode"] = 8] = "LogicalExpressionFunctionNode";
+    CustomNodes[CustomNodes["NodeCallsControllerFunctionNode"] = 9] = "NodeCallsControllerFunctionNode";
+    CustomNodes[CustomNodes["SelfDefendingUnicodeNode"] = 10] = "SelfDefendingUnicodeNode";
+    CustomNodes[CustomNodes["StringArrayCallsWrapper"] = 11] = "StringArrayCallsWrapper";
+    CustomNodes[CustomNodes["StringArrayNode"] = 12] = "StringArrayNode";
+    CustomNodes[CustomNodes["StringArrayRotateFunctionNode"] = 13] = "StringArrayRotateFunctionNode";
 })(CustomNodes = exports.CustomNodes || (exports.CustomNodes = {}));
 
 /***/ },
@@ -1382,7 +1396,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() {
@@ -1512,6 +1526,17 @@ var Nodes = function () {
                 obfuscated: false
             };
         }
+    }, {
+        key: "getLogicalExpressionNode",
+        value: function getLogicalExpressionNode(operator, left, right) {
+            return {
+                type: NodeType_1.NodeType.LogicalExpression,
+                operator: operator,
+                left: left,
+                right: right,
+                obfuscated: false
+            };
+        }
     }, {
         key: "getMemberExpressionNode",
         value: function getMemberExpressionNode(object, property) {
@@ -1550,6 +1575,19 @@ var Nodes = function () {
                 obfuscated: false
             };
         }
+    }, {
+        key: "getUnaryExpressionNode",
+        value: function getUnaryExpressionNode(operator, argument) {
+            var prefix = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
+
+            return {
+                type: NodeType_1.NodeType.UnaryExpression,
+                operator: operator,
+                argument: argument,
+                prefix: prefix,
+                obfuscated: false
+            };
+        }
     }, {
         key: "getReturnStatementNode",
         value: function getReturnStatementNode(argument) {
@@ -1830,6 +1868,7 @@ var CustomNodeGroups;
 var NodeControlFlowReplacers;
 (function (NodeControlFlowReplacers) {
     NodeControlFlowReplacers[NodeControlFlowReplacers["BinaryExpressionControlFlowReplacer"] = 0] = "BinaryExpressionControlFlowReplacer";
+    NodeControlFlowReplacers[NodeControlFlowReplacers["LogicalExpressionControlFlowReplacer"] = 1] = "LogicalExpressionControlFlowReplacer";
 })(NodeControlFlowReplacers = exports.NodeControlFlowReplacers || (exports.NodeControlFlowReplacers = {}));
 
 /***/ },
@@ -1900,7 +1939,7 @@ var _toConsumableArray2 = __webpack_require__(35);
 
 var _toConsumableArray3 = _interopRequireDefault(_toConsumableArray2);
 
-var _map = __webpack_require__(11);
+var _map = __webpack_require__(10);
 
 var _map2 = _interopRequireDefault(_map);
 
@@ -1916,7 +1955,7 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
 
 var tslib_1 = __webpack_require__(3);
 var inversify_1 = __webpack_require__(2);
-var Initializable_1 = __webpack_require__(10);
+var Initializable_1 = __webpack_require__(11);
 var RandomGeneratorUtils_1 = __webpack_require__(9);
 var Utils_1 = __webpack_require__(13);
 var MapStorage = function () {
@@ -2113,7 +2152,7 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
 
 var tslib_1 = __webpack_require__(3);
 var inversify_1 = __webpack_require__(2);
-var Initializable_1 = __webpack_require__(10);
+var Initializable_1 = __webpack_require__(11);
 var ObfuscationResult = function () {
     function ObfuscationResult() {
         (0, _classCallCheck3.default)(this, ObfuscationResult);
@@ -2155,7 +2194,7 @@ exports.ObfuscationResult = ObfuscationResult;
 "use strict";
 
 
-var _map = __webpack_require__(11);
+var _map = __webpack_require__(10);
 
 var _map2 = _interopRequireDefault(_map);
 
@@ -2176,9 +2215,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);
@@ -2636,7 +2675,7 @@ exports.InversifyContainerFacade = InversifyContainerFacade;
 "use strict";
 
 
-var _map = __webpack_require__(11);
+var _map = __webpack_require__(10);
 
 var _map2 = _interopRequireDefault(_map);
 
@@ -2659,6 +2698,7 @@ var DebugProtectionFunctionCallNode_1 = __webpack_require__(68);
 var DebugProtectionFunctionIntervalNode_1 = __webpack_require__(69);
 var DebugProtectionFunctionNode_1 = __webpack_require__(70);
 var DomainLockNode_1 = __webpack_require__(72);
+var LogicalExpressionFunctionNode_1 = __webpack_require__(145);
 var NodeCallsControllerFunctionNode_1 = __webpack_require__(74);
 var SelfDefendingUnicodeNode_1 = __webpack_require__(75);
 var StringArrayCallsWrapper_1 = __webpack_require__(77);
@@ -2673,6 +2713,7 @@ exports.customNodesModule = new inversify_1.ContainerModule(function (bind) {
     bind(ServiceIdentifiers_1.ServiceIdentifiers.Newable__ICustomNode).toConstructor(DebugProtectionFunctionIntervalNode_1.DebugProtectionFunctionIntervalNode).whenTargetNamed(CustomNodes_1.CustomNodes.DebugProtectionFunctionIntervalNode);
     bind(ServiceIdentifiers_1.ServiceIdentifiers.Newable__ICustomNode).toConstructor(DebugProtectionFunctionNode_1.DebugProtectionFunctionNode).whenTargetNamed(CustomNodes_1.CustomNodes.DebugProtectionFunctionNode);
     bind(ServiceIdentifiers_1.ServiceIdentifiers.Newable__ICustomNode).toConstructor(DomainLockNode_1.DomainLockNode).whenTargetNamed(CustomNodes_1.CustomNodes.DomainLockNode);
+    bind(ServiceIdentifiers_1.ServiceIdentifiers.Newable__ICustomNode).toConstructor(LogicalExpressionFunctionNode_1.LogicalExpressionFunctionNode).whenTargetNamed(CustomNodes_1.CustomNodes.LogicalExpressionFunctionNode);
     bind(ServiceIdentifiers_1.ServiceIdentifiers.Newable__ICustomNode).toConstructor(NodeCallsControllerFunctionNode_1.NodeCallsControllerFunctionNode).whenTargetNamed(CustomNodes_1.CustomNodes.NodeCallsControllerFunctionNode);
     bind(ServiceIdentifiers_1.ServiceIdentifiers.Newable__ICustomNode).toConstructor(SelfDefendingUnicodeNode_1.SelfDefendingUnicodeNode).whenTargetNamed(CustomNodes_1.CustomNodes.SelfDefendingUnicodeNode);
     bind(ServiceIdentifiers_1.ServiceIdentifiers.Newable__ICustomNode).toConstructor(StringArrayCallsWrapper_1.StringArrayCallsWrapper).whenTargetNamed(CustomNodes_1.CustomNodes.StringArrayCallsWrapper);
@@ -2712,7 +2753,7 @@ exports.customNodesModule = new inversify_1.ContainerModule(function (bind) {
 "use strict";
 
 
-var _map = __webpack_require__(11);
+var _map = __webpack_require__(10);
 
 var _map2 = _interopRequireDefault(_map);
 
@@ -2722,8 +2763,10 @@ var inversify_1 = __webpack_require__(2);
 var ServiceIdentifiers_1 = __webpack_require__(4);
 var NodeControlFlowReplacers_1 = __webpack_require__(39);
 var BinaryExpressionControlFlowReplacer_1 = __webpack_require__(85);
+var LogicalExpressionControlFlowReplacer_1 = __webpack_require__(142);
 exports.nodeControlFlowTransformersModule = new inversify_1.ContainerModule(function (bind) {
     bind(ServiceIdentifiers_1.ServiceIdentifiers.IControlFlowReplacer).to(BinaryExpressionControlFlowReplacer_1.BinaryExpressionControlFlowReplacer).whenTargetNamed(NodeControlFlowReplacers_1.NodeControlFlowReplacers.BinaryExpressionControlFlowReplacer);
+    bind(ServiceIdentifiers_1.ServiceIdentifiers.IControlFlowReplacer).to(LogicalExpressionControlFlowReplacer_1.LogicalExpressionControlFlowReplacer).whenTargetNamed(NodeControlFlowReplacers_1.NodeControlFlowReplacers.LogicalExpressionControlFlowReplacer);
     bind(ServiceIdentifiers_1.ServiceIdentifiers.Factory__IControlFlowReplacer).toFactory(function (context) {
         var cache = new _map2.default();
         return function (replacerName) {
@@ -2744,7 +2787,7 @@ exports.nodeControlFlowTransformersModule = new inversify_1.ContainerModule(func
 "use strict";
 
 
-var _map = __webpack_require__(11);
+var _map = __webpack_require__(10);
 
 var _map2 = _interopRequireDefault(_map);
 
@@ -2782,7 +2825,7 @@ exports.nodeObfuscatorsModule = new inversify_1.ContainerModule(function (bind)
 "use strict";
 
 
-var _map = __webpack_require__(11);
+var _map = __webpack_require__(10);
 
 var _map2 = _interopRequireDefault(_map);
 
@@ -2841,7 +2884,7 @@ exports.nodeTransformersModule = new inversify_1.ContainerModule(function (bind)
 "use strict";
 
 
-var _map = __webpack_require__(11);
+var _map = __webpack_require__(10);
 
 var _map2 = _interopRequireDefault(_map);
 
@@ -2930,7 +2973,7 @@ var inversify_1 = __webpack_require__(2);
 var ServiceIdentifiers_1 = __webpack_require__(4);
 var format = __webpack_require__(18);
 var ConsoleOutputDisableExpressionTemplate_1 = __webpack_require__(113);
-var Initializable_1 = __webpack_require__(10);
+var Initializable_1 = __webpack_require__(11);
 var AbstractCustomNode_1 = __webpack_require__(14);
 var NodeUtils_1 = __webpack_require__(8);
 var RandomGeneratorUtils_1 = __webpack_require__(9);
@@ -2974,7 +3017,7 @@ exports.ConsoleOutputDisableExpressionNode = ConsoleOutputDisableExpressionNode;
 "use strict";
 
 
-var _map = __webpack_require__(11);
+var _map = __webpack_require__(10);
 
 var _map2 = _interopRequireDefault(_map);
 
@@ -3003,7 +3046,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 Initializable_1 = __webpack_require__(10);
+var Initializable_1 = __webpack_require__(11);
 var CustomNodes_1 = __webpack_require__(20);
 var ObfuscationEvents_1 = __webpack_require__(22);
 var AbstractCustomNodeGroup_1 = __webpack_require__(26);
@@ -3094,7 +3137,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 Initializable_1 = __webpack_require__(10);
+var Initializable_1 = __webpack_require__(11);
 var AbstractCustomNode_1 = __webpack_require__(14);
 var Nodes_1 = __webpack_require__(31);
 var RandomGeneratorUtils_1 = __webpack_require__(9);
@@ -3155,7 +3198,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 Initializable_1 = __webpack_require__(10);
+var Initializable_1 = __webpack_require__(11);
 var AbstractCustomNode_1 = __webpack_require__(14);
 var Nodes_1 = __webpack_require__(31);
 var ControlFlowStorageCallNode = function (_AbstractCustomNode_) {
@@ -3229,7 +3272,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 Initializable_1 = __webpack_require__(10);
+var Initializable_1 = __webpack_require__(11);
 var AbstractCustomNode_1 = __webpack_require__(14);
 var Nodes_1 = __webpack_require__(31);
 var NodeUtils_1 = __webpack_require__(8);
@@ -3299,7 +3342,7 @@ var tslib_1 = __webpack_require__(3);
 var inversify_1 = __webpack_require__(2);
 var ServiceIdentifiers_1 = __webpack_require__(4);
 var format = __webpack_require__(18);
-var Initializable_1 = __webpack_require__(10);
+var Initializable_1 = __webpack_require__(11);
 var DebufProtectionFunctionCallTemplate_1 = __webpack_require__(114);
 var AbstractCustomNode_1 = __webpack_require__(14);
 var NodeUtils_1 = __webpack_require__(8);
@@ -3368,7 +3411,7 @@ var tslib_1 = __webpack_require__(3);
 var inversify_1 = __webpack_require__(2);
 var ServiceIdentifiers_1 = __webpack_require__(4);
 var format = __webpack_require__(18);
-var Initializable_1 = __webpack_require__(10);
+var Initializable_1 = __webpack_require__(11);
 var DebugProtectionFunctionIntervalTemplate_1 = __webpack_require__(115);
 var AbstractCustomNode_1 = __webpack_require__(14);
 var NodeUtils_1 = __webpack_require__(8);
@@ -3437,7 +3480,7 @@ var tslib_1 = __webpack_require__(3);
 var inversify_1 = __webpack_require__(2);
 var ServiceIdentifiers_1 = __webpack_require__(4);
 var format = __webpack_require__(18);
-var Initializable_1 = __webpack_require__(10);
+var Initializable_1 = __webpack_require__(11);
 var DebugProtectionFunctionTemplate_1 = __webpack_require__(116);
 var AbstractCustomNode_1 = __webpack_require__(14);
 var NodeUtils_1 = __webpack_require__(8);
@@ -3480,7 +3523,7 @@ exports.DebugProtectionFunctionNode = DebugProtectionFunctionNode;
 "use strict";
 
 
-var _map = __webpack_require__(11);
+var _map = __webpack_require__(10);
 
 var _map2 = _interopRequireDefault(_map);
 
@@ -3509,7 +3552,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 Initializable_1 = __webpack_require__(10);
+var Initializable_1 = __webpack_require__(11);
 var CustomNodes_1 = __webpack_require__(20);
 var ObfuscationEvents_1 = __webpack_require__(22);
 var AbstractCustomNodeGroup_1 = __webpack_require__(26);
@@ -3608,7 +3651,7 @@ var tslib_1 = __webpack_require__(3);
 var inversify_1 = __webpack_require__(2);
 var ServiceIdentifiers_1 = __webpack_require__(4);
 var format = __webpack_require__(18);
-var Initializable_1 = __webpack_require__(10);
+var Initializable_1 = __webpack_require__(11);
 var DomainLockNodeTemplate_1 = __webpack_require__(117);
 var AbstractCustomNode_1 = __webpack_require__(14);
 var CryptUtils_1 = __webpack_require__(33);
@@ -3663,7 +3706,7 @@ exports.DomainLockNode = DomainLockNode;
 "use strict";
 
 
-var _map = __webpack_require__(11);
+var _map = __webpack_require__(10);
 
 var _map2 = _interopRequireDefault(_map);
 
@@ -3692,7 +3735,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 Initializable_1 = __webpack_require__(10);
+var Initializable_1 = __webpack_require__(11);
 var CustomNodes_1 = __webpack_require__(20);
 var ObfuscationEvents_1 = __webpack_require__(22);
 var AbstractCustomNodeGroup_1 = __webpack_require__(26);
@@ -3785,7 +3828,7 @@ var inversify_1 = __webpack_require__(2);
 var ServiceIdentifiers_1 = __webpack_require__(4);
 var format = __webpack_require__(18);
 var ObfuscationEvents_1 = __webpack_require__(22);
-var Initializable_1 = __webpack_require__(10);
+var Initializable_1 = __webpack_require__(11);
 var SingleNodeCallControllerTemplate_1 = __webpack_require__(112);
 var NoCustomNodes_1 = __webpack_require__(29);
 var AbstractCustomNode_1 = __webpack_require__(14);
@@ -3863,7 +3906,7 @@ var tslib_1 = __webpack_require__(3);
 var inversify_1 = __webpack_require__(2);
 var ServiceIdentifiers_1 = __webpack_require__(4);
 var format = __webpack_require__(18);
-var Initializable_1 = __webpack_require__(10);
+var Initializable_1 = __webpack_require__(11);
 var NoCustomNodes_1 = __webpack_require__(29);
 var SelfDefendingTemplate_1 = __webpack_require__(118);
 var AbstractCustomNode_1 = __webpack_require__(14);
@@ -3910,7 +3953,7 @@ exports.SelfDefendingUnicodeNode = SelfDefendingUnicodeNode;
 "use strict";
 
 
-var _map = __webpack_require__(11);
+var _map = __webpack_require__(10);
 
 var _map2 = _interopRequireDefault(_map);
 
@@ -3939,7 +3982,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 Initializable_1 = __webpack_require__(10);
+var Initializable_1 = __webpack_require__(11);
 var CustomNodes_1 = __webpack_require__(20);
 var ObfuscationEvents_1 = __webpack_require__(22);
 var AbstractCustomNodeGroup_1 = __webpack_require__(26);
@@ -4032,7 +4075,7 @@ var inversify_1 = __webpack_require__(2);
 var ServiceIdentifiers_1 = __webpack_require__(4);
 var format = __webpack_require__(18);
 var StringArrayEncoding_1 = __webpack_require__(30);
-var Initializable_1 = __webpack_require__(10);
+var Initializable_1 = __webpack_require__(11);
 var NoCustomNodes_1 = __webpack_require__(29);
 var AtobTemplate_1 = __webpack_require__(110);
 var Rc4Template_1 = __webpack_require__(111);
@@ -4149,7 +4192,7 @@ var tslib_1 = __webpack_require__(3);
 var inversify_1 = __webpack_require__(2);
 var ServiceIdentifiers_1 = __webpack_require__(4);
 var format = __webpack_require__(18);
-var Initializable_1 = __webpack_require__(10);
+var Initializable_1 = __webpack_require__(11);
 var StringArrayTemplate_1 = __webpack_require__(123);
 var AbstractCustomNode_1 = __webpack_require__(14);
 var NodeUtils_1 = __webpack_require__(8);
@@ -4229,7 +4272,7 @@ var tslib_1 = __webpack_require__(3);
 var inversify_1 = __webpack_require__(2);
 var ServiceIdentifiers_1 = __webpack_require__(4);
 var format = __webpack_require__(18);
-var Initializable_1 = __webpack_require__(10);
+var Initializable_1 = __webpack_require__(11);
 var NoCustomNodes_1 = __webpack_require__(29);
 var SelfDefendingTemplate_1 = __webpack_require__(124);
 var StringArrayRotateFunctionTemplate_1 = __webpack_require__(125);
@@ -4296,7 +4339,7 @@ exports.StringArrayRotateFunctionNode = StringArrayRotateFunctionNode;
 "use strict";
 
 
-var _map = __webpack_require__(11);
+var _map = __webpack_require__(10);
 
 var _map2 = _interopRequireDefault(_map);
 
@@ -4325,7 +4368,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 Initializable_1 = __webpack_require__(10);
+var Initializable_1 = __webpack_require__(11);
 var CustomNodes_1 = __webpack_require__(20);
 var ObfuscationEvents_1 = __webpack_require__(22);
 var AbstractCustomNodeGroup_1 = __webpack_require__(26);
@@ -4461,7 +4504,7 @@ exports.ObfuscationEventEmitter = ObfuscationEventEmitter;
 "use strict";
 
 
-var _map = __webpack_require__(11);
+var _map = __webpack_require__(10);
 
 var _map2 = _interopRequireDefault(_map);
 
@@ -4490,9 +4533,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);
@@ -4556,8 +4599,7 @@ var FunctionControlFlowTransformer = FunctionControlFlowTransformer_1 = function
             }
             var controlFlowStorageCustomNode = this.customNodeFactory(CustomNodes_1.CustomNodes.ControlFlowStorageNode);
             controlFlowStorageCustomNode.initialize(controlFlowStorage);
-            var controlFlowStorageNode = controlFlowStorageCustomNode.getNode();
-            NodeAppender_1.NodeAppender.prependNode(hostNode, controlFlowStorageNode);
+            NodeAppender_1.NodeAppender.prependNode(hostNode, controlFlowStorageCustomNode.getNode());
             this.hostNodesWithControlFlowNode.push(hostNode);
         }
     }], [{
@@ -4580,7 +4622,7 @@ var FunctionControlFlowTransformer = FunctionControlFlowTransformer_1 = function
     }]);
     return FunctionControlFlowTransformer;
 }(AbstractNodeTransformer_1.AbstractNodeTransformer);
-FunctionControlFlowTransformer.controlFlowReplacersMap = new _map2.default([[NodeType_1.NodeType.BinaryExpression, NodeControlFlowReplacers_1.NodeControlFlowReplacers.BinaryExpressionControlFlowReplacer]]);
+FunctionControlFlowTransformer.controlFlowReplacersMap = new _map2.default([[NodeType_1.NodeType.BinaryExpression, NodeControlFlowReplacers_1.NodeControlFlowReplacers.BinaryExpressionControlFlowReplacer], [NodeType_1.NodeType.LogicalExpression, NodeControlFlowReplacers_1.NodeControlFlowReplacers.LogicalExpressionControlFlowReplacer]]);
 FunctionControlFlowTransformer.hostNodeSearchMinDepth = 2;
 FunctionControlFlowTransformer.hostNodeSearchMaxDepth = 10;
 FunctionControlFlowTransformer = FunctionControlFlowTransformer_1 = tslib_1.__decorate([inversify_1.injectable(), tslib_1.__param(0, inversify_1.inject(ServiceIdentifiers_1.ServiceIdentifiers.Factory__TControlFlowStorage)), tslib_1.__param(1, inversify_1.inject(ServiceIdentifiers_1.ServiceIdentifiers.Factory__IControlFlowReplacer)), tslib_1.__param(2, inversify_1.inject(ServiceIdentifiers_1.ServiceIdentifiers.Factory__ICustomNode)), tslib_1.__param(3, inversify_1.inject(ServiceIdentifiers_1.ServiceIdentifiers.IOptions)), tslib_1.__metadata("design:paramtypes", [Function, Function, Function, Object])], FunctionControlFlowTransformer);
@@ -4594,21 +4636,77 @@ var FunctionControlFlowTransformer_1;
 "use strict";
 
 
+var _map = __webpack_require__(10);
+
+var _map2 = _interopRequireDefault(_map);
+
 var _classCallCheck2 = __webpack_require__(0);
 
 var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
 
+var _createClass2 = __webpack_require__(1);
+
+var _createClass3 = _interopRequireDefault(_createClass2);
+
 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
 var tslib_1 = __webpack_require__(3);
 var inversify_1 = __webpack_require__(2);
 var ServiceIdentifiers_1 = __webpack_require__(4);
-var AbstractControlFlowReplacer = function AbstractControlFlowReplacer(options) {
-    (0, _classCallCheck3.default)(this, AbstractControlFlowReplacer);
+var BinaryExpressionControlFlowReplacer_1 = __webpack_require__(85);
+var CustomNodes_1 = __webpack_require__(20);
+var Node_1 = __webpack_require__(12);
+var RandomGeneratorUtils_1 = __webpack_require__(9);
+var AbstractControlFlowReplacer = function () {
+    function AbstractControlFlowReplacer(customNodeFactory, options) {
+        (0, _classCallCheck3.default)(this, AbstractControlFlowReplacer);
 
-    this.options = options;
-};
-AbstractControlFlowReplacer = tslib_1.__decorate([inversify_1.injectable(), tslib_1.__param(0, inversify_1.inject(ServiceIdentifiers_1.ServiceIdentifiers.IOptions)), tslib_1.__metadata("design:paramtypes", [Object])], AbstractControlFlowReplacer);
+        this.replacerDataByControlFlowStorageId = new _map2.default();
+        this.customNodeFactory = customNodeFactory;
+        this.options = options;
+    }
+
+    (0, _createClass3.default)(AbstractControlFlowReplacer, [{
+        key: "getControlFlowStorageCallNode",
+        value: function getControlFlowStorageCallNode(controlFlowStorageId, storageKey, leftExpression, rightExpression) {
+            var controlFlowStorageCallCustomNode = this.customNodeFactory(CustomNodes_1.CustomNodes.ControlFlowStorageCallNode);
+            controlFlowStorageCallCustomNode.initialize(controlFlowStorageId, storageKey, leftExpression, rightExpression);
+            var statementNode = controlFlowStorageCallCustomNode.getNode()[0];
+            if (!statementNode || !Node_1.Node.isExpressionStatementNode(statementNode)) {
+                throw new Error("`controlFlowStorageCallNode.getNode()[0]` should returns array with `ExpressionStatement` node");
+            }
+            return statementNode.expression;
+        }
+    }, {
+        key: "insertCustomNodeToControlFlowStorage",
+        value: function insertCustomNodeToControlFlowStorage(customNode, controlFlowStorage, replacerId, usingExistingIdentifierChance) {
+            var controlFlowStorageId = controlFlowStorage.getStorageId();
+            var storageKeysById = BinaryExpressionControlFlowReplacer_1.BinaryExpressionControlFlowReplacer.getStorageKeysByIdForCurrentStorage(this.replacerDataByControlFlowStorageId, controlFlowStorageId);
+            var storageKeysForCurrentId = storageKeysById.get(replacerId);
+            if (RandomGeneratorUtils_1.RandomGeneratorUtils.getRandomFloat(0, 1) > usingExistingIdentifierChance && storageKeysForCurrentId && storageKeysForCurrentId.length) {
+                return RandomGeneratorUtils_1.RandomGeneratorUtils.getRandomGenerator().pickone(storageKeysForCurrentId);
+            }
+            var storageKey = RandomGeneratorUtils_1.RandomGeneratorUtils.getRandomString(3);
+            storageKeysById.set(replacerId, [storageKey]);
+            this.replacerDataByControlFlowStorageId.set(controlFlowStorageId, storageKeysById);
+            controlFlowStorage.set(storageKey, customNode);
+            return storageKey;
+        }
+    }], [{
+        key: "getStorageKeysByIdForCurrentStorage",
+        value: function getStorageKeysByIdForCurrentStorage(identifierDataByControlFlowStorageId, controlFlowStorageId) {
+            var storageKeysById = void 0;
+            if (identifierDataByControlFlowStorageId.has(controlFlowStorageId)) {
+                storageKeysById = identifierDataByControlFlowStorageId.get(controlFlowStorageId);
+            } else {
+                storageKeysById = new _map2.default();
+            }
+            return storageKeysById;
+        }
+    }]);
+    return AbstractControlFlowReplacer;
+}();
+AbstractControlFlowReplacer = tslib_1.__decorate([inversify_1.injectable(), tslib_1.__param(0, inversify_1.inject(ServiceIdentifiers_1.ServiceIdentifiers.Factory__ICustomNode)), tslib_1.__param(1, inversify_1.inject(ServiceIdentifiers_1.ServiceIdentifiers.IOptions)), tslib_1.__metadata("design:paramtypes", [Function, Object])], AbstractControlFlowReplacer);
 exports.AbstractControlFlowReplacer = AbstractControlFlowReplacer;
 
 /***/ },
@@ -4618,10 +4716,6 @@ exports.AbstractControlFlowReplacer = AbstractControlFlowReplacer;
 "use strict";
 
 
-var _map = __webpack_require__(11);
-
-var _map2 = _interopRequireDefault(_map);
-
 var _getPrototypeOf = __webpack_require__(5);
 
 var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
@@ -4649,61 +4743,27 @@ var inversify_1 = __webpack_require__(2);
 var ServiceIdentifiers_1 = __webpack_require__(4);
 var CustomNodes_1 = __webpack_require__(20);
 var AbstractControlFlowReplacer_1 = __webpack_require__(84);
-var Node_1 = __webpack_require__(12);
-var RandomGeneratorUtils_1 = __webpack_require__(9);
 var BinaryExpressionControlFlowReplacer = BinaryExpressionControlFlowReplacer_1 = function (_AbstractControlFlowR) {
     (0, _inherits3.default)(BinaryExpressionControlFlowReplacer, _AbstractControlFlowR);
 
     function BinaryExpressionControlFlowReplacer(customNodeFactory, options) {
         (0, _classCallCheck3.default)(this, BinaryExpressionControlFlowReplacer);
-
-        var _this = (0, _possibleConstructorReturn3.default)(this, (BinaryExpressionControlFlowReplacer.__proto__ || (0, _getPrototypeOf2.default)(BinaryExpressionControlFlowReplacer)).call(this, options));
-
-        _this.binaryOperatorsDataByControlFlowStorageId = new _map2.default();
-        _this.customNodeFactory = customNodeFactory;
-        return _this;
+        return (0, _possibleConstructorReturn3.default)(this, (BinaryExpressionControlFlowReplacer.__proto__ || (0, _getPrototypeOf2.default)(BinaryExpressionControlFlowReplacer)).call(this, customNodeFactory, options));
     }
 
     (0, _createClass3.default)(BinaryExpressionControlFlowReplacer, [{
         key: "replace",
         value: function replace(binaryExpressionNode, parentNode, controlFlowStorage) {
-            var controlFlowStorageId = controlFlowStorage.getStorageId();
-            var controlFlowStorageCallCustomNode = this.customNodeFactory(CustomNodes_1.CustomNodes.ControlFlowStorageCallNode);
-            var storageKeysByBinaryOperator = BinaryExpressionControlFlowReplacer_1.getStorageKeysByBinaryOperatorForCurrentStorage(this.binaryOperatorsDataByControlFlowStorageId, controlFlowStorageId);
-            var storageKeysForCurrentOperator = storageKeysByBinaryOperator.get(binaryExpressionNode.operator);
-            var storageKey = void 0;
-            if (RandomGeneratorUtils_1.RandomGeneratorUtils.getRandomFloat(0, 1) > BinaryExpressionControlFlowReplacer_1.useExistingOperatorKeyThreshold && storageKeysForCurrentOperator && storageKeysForCurrentOperator.length) {
-                storageKey = RandomGeneratorUtils_1.RandomGeneratorUtils.getRandomGenerator().pickone(storageKeysForCurrentOperator);
-            } else {
-                var binaryExpressionFunctionCustomNode = this.customNodeFactory(CustomNodes_1.CustomNodes.BinaryExpressionFunctionNode);
-                binaryExpressionFunctionCustomNode.initialize(binaryExpressionNode.operator);
-                storageKey = RandomGeneratorUtils_1.RandomGeneratorUtils.getRandomString(3);
-                storageKeysByBinaryOperator.set(binaryExpressionNode.operator, [storageKey]);
-                this.binaryOperatorsDataByControlFlowStorageId.set(controlFlowStorageId, storageKeysByBinaryOperator);
-                controlFlowStorage.set(storageKey, binaryExpressionFunctionCustomNode);
-            }
-            controlFlowStorageCallCustomNode.initialize(controlFlowStorageId, storageKey, binaryExpressionNode.left, binaryExpressionNode.right);
-            var statementNode = controlFlowStorageCallCustomNode.getNode()[0];
-            if (!statementNode || !Node_1.Node.isExpressionStatementNode(statementNode)) {
-                throw new Error("`controlFlowStorageCallNode.getNode()[0]` should returns array with `ExpressionStatement` node");
-            }
-            return statementNode.expression;
-        }
-    }], [{
-        key: "getStorageKeysByBinaryOperatorForCurrentStorage",
-        value: function getStorageKeysByBinaryOperatorForCurrentStorage(binaryOperatorsDataByControlFlowStorageId, controlFlowStorageId) {
-            var storageKeysByBinaryOperator = void 0;
-            if (binaryOperatorsDataByControlFlowStorageId.has(controlFlowStorageId)) {
-                storageKeysByBinaryOperator = binaryOperatorsDataByControlFlowStorageId.get(controlFlowStorageId);
-            } else {
-                storageKeysByBinaryOperator = new _map2.default();
-            }
-            return storageKeysByBinaryOperator;
+            var replacerId = binaryExpressionNode.operator;
+            var binaryExpressionFunctionCustomNode = this.customNodeFactory(CustomNodes_1.CustomNodes.BinaryExpressionFunctionNode);
+            binaryExpressionFunctionCustomNode.initialize(replacerId);
+            var storageKey = this.insertCustomNodeToControlFlowStorage(binaryExpressionFunctionCustomNode, controlFlowStorage, replacerId, BinaryExpressionControlFlowReplacer_1.usingExistingIdentifierChance);
+            return this.getControlFlowStorageCallNode(controlFlowStorage.getStorageId(), storageKey, binaryExpressionNode.left, binaryExpressionNode.right);
         }
     }]);
     return BinaryExpressionControlFlowReplacer;
 }(AbstractControlFlowReplacer_1.AbstractControlFlowReplacer);
-BinaryExpressionControlFlowReplacer.useExistingOperatorKeyThreshold = 0.5;
+BinaryExpressionControlFlowReplacer.usingExistingIdentifierChance = 0.5;
 BinaryExpressionControlFlowReplacer = BinaryExpressionControlFlowReplacer_1 = tslib_1.__decorate([inversify_1.injectable(), tslib_1.__param(0, inversify_1.inject(ServiceIdentifiers_1.ServiceIdentifiers.Factory__ICustomNode)), tslib_1.__param(1, inversify_1.inject(ServiceIdentifiers_1.ServiceIdentifiers.IOptions)), tslib_1.__metadata("design:paramtypes", [Function, Object])], BinaryExpressionControlFlowReplacer);
 exports.BinaryExpressionControlFlowReplacer = BinaryExpressionControlFlowReplacer;
 var BinaryExpressionControlFlowReplacer_1;
@@ -4740,9 +4800,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);
@@ -4807,7 +4867,7 @@ var _getIterator2 = __webpack_require__(21);
 
 var _getIterator3 = _interopRequireDefault(_getIterator2);
 
-var _map = __webpack_require__(11);
+var _map = __webpack_require__(10);
 
 var _map2 = _interopRequireDefault(_map);
 
@@ -4836,9 +4896,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 +5026,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 +5124,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 +5298,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 +5460,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);
@@ -5469,7 +5529,7 @@ var _getIterator2 = __webpack_require__(21);
 
 var _getIterator3 = _interopRequireDefault(_getIterator2);
 
-var _map = __webpack_require__(11);
+var _map = __webpack_require__(10);
 
 var _map2 = _interopRequireDefault(_map);
 
@@ -5498,9 +5558,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);
@@ -5659,7 +5719,7 @@ exports.BooleanLiteralReplacer = BooleanLiteralReplacer;
 "use strict";
 
 
-var _map = __webpack_require__(11);
+var _map = __webpack_require__(10);
 
 var _map2 = _interopRequireDefault(_map);
 
@@ -5738,7 +5798,7 @@ exports.IdentifierReplacer = IdentifierReplacer;
 "use strict";
 
 
-var _map = __webpack_require__(11);
+var _map = __webpack_require__(10);
 
 var _map2 = _interopRequireDefault(_map);
 
@@ -5809,7 +5869,7 @@ exports.NumberLiteralReplacer = NumberLiteralReplacer;
 "use strict";
 
 
-var _map = __webpack_require__(11);
+var _map = __webpack_require__(10);
 
 var _map2 = _interopRequireDefault(_map);
 
@@ -6289,7 +6349,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);
@@ -6407,7 +6467,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);
@@ -6485,7 +6545,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);
@@ -6570,7 +6630,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);
@@ -6713,7 +6773,7 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
 
 var tslib_1 = __webpack_require__(3);
 var inversify_1 = __webpack_require__(2);
-var Initializable_1 = __webpack_require__(10);
+var Initializable_1 = __webpack_require__(11);
 var RandomGeneratorUtils_1 = __webpack_require__(9);
 var ArrayStorage = function () {
     function ArrayStorage() {
@@ -6829,7 +6889,7 @@ exports.ControlFlowStorage = ControlFlowStorage;
 "use strict";
 
 
-var _map = __webpack_require__(11);
+var _map = __webpack_require__(10);
 
 var _map2 = _interopRequireDefault(_map);
 
@@ -7266,6 +7326,146 @@ module.exports = require("reflect-metadata");
 var JavaScriptObfuscator_1 = __webpack_require__(23);
 module.exports = JavaScriptObfuscator_1.JavaScriptObfuscator;
 
+/***/ },
+/* 142 */
+/***/ function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+var _getPrototypeOf = __webpack_require__(5);
+
+var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
+
+var _classCallCheck2 = __webpack_require__(0);
+
+var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
+
+var _createClass2 = __webpack_require__(1);
+
+var _createClass3 = _interopRequireDefault(_createClass2);
+
+var _possibleConstructorReturn2 = __webpack_require__(7);
+
+var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
+
+var _inherits2 = __webpack_require__(6);
+
+var _inherits3 = _interopRequireDefault(_inherits2);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var tslib_1 = __webpack_require__(3);
+var inversify_1 = __webpack_require__(2);
+var ServiceIdentifiers_1 = __webpack_require__(4);
+var CustomNodes_1 = __webpack_require__(20);
+var AbstractControlFlowReplacer_1 = __webpack_require__(84);
+var Node_1 = __webpack_require__(12);
+var NodeUtils_1 = __webpack_require__(8);
+var LogicalExpressionControlFlowReplacer = LogicalExpressionControlFlowReplacer_1 = function (_AbstractControlFlowR) {
+    (0, _inherits3.default)(LogicalExpressionControlFlowReplacer, _AbstractControlFlowR);
+
+    function LogicalExpressionControlFlowReplacer(customNodeFactory, options) {
+        (0, _classCallCheck3.default)(this, LogicalExpressionControlFlowReplacer);
+        return (0, _possibleConstructorReturn3.default)(this, (LogicalExpressionControlFlowReplacer.__proto__ || (0, _getPrototypeOf2.default)(LogicalExpressionControlFlowReplacer)).call(this, customNodeFactory, options));
+    }
+
+    (0, _createClass3.default)(LogicalExpressionControlFlowReplacer, [{
+        key: "replace",
+        value: function replace(logicalExpressionNode, parentNode, controlFlowStorage) {
+            if (this.checkForProhibitedExpressions(logicalExpressionNode.left, logicalExpressionNode.right)) {
+                return logicalExpressionNode;
+            }
+            var replacerId = logicalExpressionNode.operator;
+            var logicalExpressionFunctionCustomNode = this.customNodeFactory(CustomNodes_1.CustomNodes.LogicalExpressionFunctionNode);
+            logicalExpressionFunctionCustomNode.initialize(replacerId);
+            var storageKey = this.insertCustomNodeToControlFlowStorage(logicalExpressionFunctionCustomNode, controlFlowStorage, replacerId, LogicalExpressionControlFlowReplacer_1.usingExistingIdentifierChance);
+            return this.getControlFlowStorageCallNode(controlFlowStorage.getStorageId(), storageKey, logicalExpressionNode.left, logicalExpressionNode.right);
+        }
+    }, {
+        key: "checkForProhibitedExpressions",
+        value: function checkForProhibitedExpressions(leftExpression, rightExpression) {
+            return [leftExpression, rightExpression].some(function (expressionNode) {
+                var nodeForCheck = void 0;
+                if (!Node_1.Node.isUnaryExpressionNode(expressionNode)) {
+                    nodeForCheck = expressionNode;
+                } else {
+                    nodeForCheck = NodeUtils_1.NodeUtils.getUnaryExpressionArgumentNode(expressionNode);
+                }
+                return !Node_1.Node.isLiteralNode(nodeForCheck) && !Node_1.Node.isIdentifierNode(nodeForCheck) && !Node_1.Node.isObjectExpressionNode(nodeForCheck) && !Node_1.Node.isExpressionStatementNode(nodeForCheck);
+            });
+        }
+    }]);
+    return LogicalExpressionControlFlowReplacer;
+}(AbstractControlFlowReplacer_1.AbstractControlFlowReplacer);
+LogicalExpressionControlFlowReplacer.usingExistingIdentifierChance = 0.5;
+LogicalExpressionControlFlowReplacer = LogicalExpressionControlFlowReplacer_1 = tslib_1.__decorate([inversify_1.injectable(), tslib_1.__param(0, inversify_1.inject(ServiceIdentifiers_1.ServiceIdentifiers.Factory__ICustomNode)), tslib_1.__param(1, inversify_1.inject(ServiceIdentifiers_1.ServiceIdentifiers.IOptions)), tslib_1.__metadata("design:paramtypes", [Function, Object])], LogicalExpressionControlFlowReplacer);
+exports.LogicalExpressionControlFlowReplacer = LogicalExpressionControlFlowReplacer;
+var LogicalExpressionControlFlowReplacer_1;
+
+/***/ },
+/* 143 */,
+/* 144 */,
+/* 145 */
+/***/ function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+var _getPrototypeOf = __webpack_require__(5);
+
+var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
+
+var _classCallCheck2 = __webpack_require__(0);
+
+var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
+
+var _createClass2 = __webpack_require__(1);
+
+var _createClass3 = _interopRequireDefault(_createClass2);
+
+var _possibleConstructorReturn2 = __webpack_require__(7);
+
+var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
+
+var _inherits2 = __webpack_require__(6);
+
+var _inherits3 = _interopRequireDefault(_inherits2);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var tslib_1 = __webpack_require__(3);
+var inversify_1 = __webpack_require__(2);
+var ServiceIdentifiers_1 = __webpack_require__(4);
+var Initializable_1 = __webpack_require__(11);
+var AbstractCustomNode_1 = __webpack_require__(14);
+var Nodes_1 = __webpack_require__(31);
+var RandomGeneratorUtils_1 = __webpack_require__(9);
+var LogicalExpressionFunctionNode = function (_AbstractCustomNode_) {
+    (0, _inherits3.default)(LogicalExpressionFunctionNode, _AbstractCustomNode_);
+
+    function LogicalExpressionFunctionNode(options) {
+        (0, _classCallCheck3.default)(this, LogicalExpressionFunctionNode);
+        return (0, _possibleConstructorReturn3.default)(this, (LogicalExpressionFunctionNode.__proto__ || (0, _getPrototypeOf2.default)(LogicalExpressionFunctionNode)).call(this, options));
+    }
+
+    (0, _createClass3.default)(LogicalExpressionFunctionNode, [{
+        key: "initialize",
+        value: function initialize(operator) {
+            this.operator = operator;
+        }
+    }, {
+        key: "getNodeStructure",
+        value: function getNodeStructure() {
+            return [Nodes_1.Nodes.getFunctionDeclarationNode(RandomGeneratorUtils_1.RandomGeneratorUtils.getRandomVariableName(1), [Nodes_1.Nodes.getIdentifierNode('x'), Nodes_1.Nodes.getIdentifierNode('y')], Nodes_1.Nodes.getBlockStatementNode([Nodes_1.Nodes.getReturnStatementNode(Nodes_1.Nodes.getLogicalExpressionNode(this.operator, Nodes_1.Nodes.getIdentifierNode('x'), Nodes_1.Nodes.getIdentifierNode('y')))]))];
+        }
+    }]);
+    return LogicalExpressionFunctionNode;
+}(AbstractCustomNode_1.AbstractCustomNode);
+tslib_1.__decorate([Initializable_1.initializable(), tslib_1.__metadata("design:type", String)], LogicalExpressionFunctionNode.prototype, "operator", void 0);
+LogicalExpressionFunctionNode = tslib_1.__decorate([inversify_1.injectable(), tslib_1.__param(0, inversify_1.inject(ServiceIdentifiers_1.ServiceIdentifiers.IOptions)), tslib_1.__metadata("design:paramtypes", [Object])], LogicalExpressionFunctionNode);
+exports.LogicalExpressionFunctionNode = LogicalExpressionFunctionNode;
+
 /***/ }
 /******/ ]);
 //# sourceMappingURL=index.js.map

+ 3 - 3
package.json

@@ -46,8 +46,8 @@
     "@types/estree": "0.0.34",
     "@types/lodash": "^4.14.44",
     "@types/mkdirp": "0.3.29",
-    "@types/mocha": "2.2.34",
-    "@types/node": "6.0.53",
+    "@types/mocha": "2.2.35",
+    "@types/node": "6.0.54",
     "@types/sinon": "1.16.33",
     "@types/string-template": "1.0.2",
     "awesome-typescript-loader": "3.0.0-beta.17",
@@ -60,7 +60,7 @@
     "istanbul": "1.1.0-alpha.1",
     "mocha": "3.2.0",
     "sinon": "2.0.0-pre.4",
-    "ts-node": "1.7.2",
+    "ts-node": "1.7.3",
     "tslint": "4.2.0",
     "tslint-loader": "^3.3.0",
     "typescript": "2.1.4",

+ 6 - 1
src/container/modules/custom-nodes/CustomNodesModule.ts

@@ -15,13 +15,14 @@ import { SelfDefendingCustomNodeGroup } from '../../../custom-nodes/self-defendi
 import { StringArrayCustomNodeGroup } from '../../../custom-nodes/string-array-nodes/group/StringArrayCustomNodeGroup';
 
 import { BinaryExpressionFunctionNode } from '../../../custom-nodes/control-flow-replacers-nodes/binary-expression-control-flow-replacer-nodes/BinaryExpressionFunctionNode';
-import { ControlFlowStorageCallNode } from '../../../custom-nodes/control-flow-replacers-nodes/binary-expression-control-flow-replacer-nodes/ControlFlowStorageCallNode';
+import { ControlFlowStorageCallNode } from '../../../custom-nodes/control-flow-storage-nodes/ControlFlowStorageCallNode';
 import { ControlFlowStorageNode } from '../../../custom-nodes/control-flow-storage-nodes/ControlFlowStorageNode';
 import { ConsoleOutputDisableExpressionNode } from '../../../custom-nodes/console-output-nodes/ConsoleOutputDisableExpressionNode';
 import { DebugProtectionFunctionCallNode } from '../../../custom-nodes/debug-protection-nodes/DebugProtectionFunctionCallNode';
 import { DebugProtectionFunctionIntervalNode } from '../../../custom-nodes/debug-protection-nodes/DebugProtectionFunctionIntervalNode';
 import { DebugProtectionFunctionNode } from '../../../custom-nodes/debug-protection-nodes/DebugProtectionFunctionNode';
 import { DomainLockNode } from '../../../custom-nodes/domain-lock-nodes/DomainLockNode';
+import { LogicalExpressionFunctionNode } from '../../../custom-nodes/control-flow-replacers-nodes/logical-expression-control-flow-replacer-nodes/LogicalExpressionFunctionNode';
 import { NodeCallsControllerFunctionNode } from '../../../custom-nodes/node-calls-controller-nodes/NodeCallsControllerFunctionNode';
 import { SelfDefendingUnicodeNode } from '../../../custom-nodes/self-defending-nodes/SelfDefendingUnicodeNode';
 import { StringArrayCallsWrapper } from '../../../custom-nodes/string-array-nodes/StringArrayCallsWrapper';
@@ -62,6 +63,10 @@ export const customNodesModule: interfaces.ContainerModule = new ContainerModule
         .toConstructor(DomainLockNode)
         .whenTargetNamed(CustomNodes.DomainLockNode);
 
+    bind<interfaces.Newable<ICustomNode>>(ServiceIdentifiers.Newable__ICustomNode)
+        .toConstructor(LogicalExpressionFunctionNode)
+        .whenTargetNamed(CustomNodes.LogicalExpressionFunctionNode);
+
     bind<interfaces.Newable<ICustomNode>>(ServiceIdentifiers.Newable__ICustomNode)
         .toConstructor(NodeCallsControllerFunctionNode)
         .whenTargetNamed(CustomNodes.NodeCallsControllerFunctionNode);

+ 5 - 0
src/container/modules/node-transformers/NodeControlFlowTransformersModule.ts

@@ -6,12 +6,17 @@ import { IControlFlowReplacer } from '../../../interfaces/node-transformers/ICon
 import { NodeControlFlowReplacers } from '../../../enums/container/NodeControlFlowReplacers';
 
 import { BinaryExpressionControlFlowReplacer } from '../../../node-transformers/node-control-flow-transformers/control-flow-replacers/BinaryExpressionControlFlowReplacer';
+import { LogicalExpressionControlFlowReplacer } from '../../../node-transformers/node-control-flow-transformers/control-flow-replacers/LogicalExpressionControlFlowReplacer';
 
 export const nodeControlFlowTransformersModule: interfaces.ContainerModule = new ContainerModule((bind: interfaces.Bind) => {
     bind<IControlFlowReplacer>(ServiceIdentifiers.IControlFlowReplacer)
         .to(BinaryExpressionControlFlowReplacer)
         .whenTargetNamed(NodeControlFlowReplacers.BinaryExpressionControlFlowReplacer);
 
+    bind<IControlFlowReplacer>(ServiceIdentifiers.IControlFlowReplacer)
+        .to(LogicalExpressionControlFlowReplacer)
+        .whenTargetNamed(NodeControlFlowReplacers.LogicalExpressionControlFlowReplacer);
+
     bind<IControlFlowReplacer>(ServiceIdentifiers.Factory__IControlFlowReplacer)
         .toFactory<IControlFlowReplacer>((context: interfaces.Context) => {
             const cache: Map <NodeControlFlowReplacers, IControlFlowReplacer> = new Map();

+ 63 - 0
src/custom-nodes/control-flow-replacers-nodes/logical-expression-control-flow-replacer-nodes/LogicalExpressionFunctionNode.ts

@@ -0,0 +1,63 @@
+import { injectable, inject } from 'inversify';
+import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
+
+import { LogicalOperator } from 'estree';
+
+import { TStatement } from '../../../types/node/TStatement';
+
+import { IOptions } from '../../../interfaces/options/IOptions';
+
+import { initializable } from '../../../decorators/Initializable';
+
+import { AbstractCustomNode } from '../../AbstractCustomNode';
+import { Nodes } from '../../../node/Nodes';
+import { RandomGeneratorUtils } from '../../../utils/RandomGeneratorUtils';
+
+@injectable()
+export class LogicalExpressionFunctionNode extends AbstractCustomNode {
+    /**
+     * @type {LogicalOperator}
+     */
+    @initializable()
+    private operator: LogicalOperator;
+
+    /**
+     * @param options
+     */
+    constructor (
+        @inject(ServiceIdentifiers.IOptions) options: IOptions
+    ) {
+        super(options);
+    }
+
+    /**
+     * @param operator
+     */
+    public initialize (operator: LogicalOperator): void {
+        this.operator = operator;
+    }
+
+    /**
+     * @returns {TStatement[]}
+     */
+    protected getNodeStructure (): TStatement[] {
+        return [
+            Nodes.getFunctionDeclarationNode(
+                RandomGeneratorUtils.getRandomVariableName(1),
+                [
+                    Nodes.getIdentifierNode('x'),
+                    Nodes.getIdentifierNode('y')
+                ],
+                Nodes.getBlockStatementNode([
+                    Nodes.getReturnStatementNode(
+                        Nodes.getLogicalExpressionNode(
+                            this.operator,
+                            Nodes.getIdentifierNode('x'),
+                            Nodes.getIdentifierNode('y')
+                        )
+                    )
+                ])
+            )
+        ];
+    }
+}

+ 6 - 6
src/custom-nodes/control-flow-replacers-nodes/binary-expression-control-flow-replacer-nodes/ControlFlowStorageCallNode.ts → src/custom-nodes/control-flow-storage-nodes/ControlFlowStorageCallNode.ts

@@ -1,16 +1,16 @@
 import { injectable, inject } from 'inversify';
-import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
+import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
 
 import { Expression } from 'estree';
 
-import { TStatement } from '../../../types/node/TStatement';
+import { TStatement } from '../../types/node/TStatement';
 
-import { IOptions } from '../../../interfaces/options/IOptions';
+import { IOptions } from '../../interfaces/options/IOptions';
 
-import { initializable } from '../../../decorators/Initializable';
+import { initializable } from '../../decorators/Initializable';
 
-import { AbstractCustomNode } from '../../AbstractCustomNode';
-import { Nodes } from '../../../node/Nodes';
+import { AbstractCustomNode } from '../AbstractCustomNode';
+import { Nodes } from '../../node/Nodes';
 
 @injectable()
 export class ControlFlowStorageCallNode extends AbstractCustomNode {

+ 1 - 0
src/enums/container/CustomNodes.ts

@@ -7,6 +7,7 @@ export enum CustomNodes {
     DebugProtectionFunctionIntervalNode,
     DebugProtectionFunctionNode,
     DomainLockNode,
+    LogicalExpressionFunctionNode,
     NodeCallsControllerFunctionNode,
     SelfDefendingUnicodeNode,
     StringArrayCallsWrapper,

+ 2 - 1
src/enums/container/NodeControlFlowReplacers.ts

@@ -1,3 +1,4 @@
 export enum NodeControlFlowReplacers {
-    BinaryExpressionControlFlowReplacer
+    BinaryExpressionControlFlowReplacer,
+    LogicalExpressionControlFlowReplacer
 }

+ 3 - 6
src/node-transformers/node-control-flow-transformers/FunctionControlFlowTransformer.ts

@@ -8,7 +8,6 @@ import { TControlFlowReplacerFactory } from '../../types/container/TControlFlowR
 import { TControlFlowStorageFactory } from '../../types/container/TControlFlowStorageFactory';
 import { TCustomNodeFactory } from '../../types/container/TCustomNodeFactory';
 import { TNodeWithBlockStatement } from '../../types/node/TNodeWithBlockStatement';
-import { TStatement } from '../../types/node/TStatement';
 
 import { ICustomNode } from '../../interfaces/custom-nodes/ICustomNode';
 import { IOptions } from '../../interfaces/options/IOptions';
@@ -30,7 +29,8 @@ export class FunctionControlFlowTransformer extends AbstractNodeTransformer {
      * @type {Map <string, NodeControlFlowReplacers>}
      */
     private static readonly controlFlowReplacersMap: Map <string, NodeControlFlowReplacers> = new Map([
-        [NodeType.BinaryExpression, NodeControlFlowReplacers.BinaryExpressionControlFlowReplacer]
+        [NodeType.BinaryExpression, NodeControlFlowReplacers.BinaryExpressionControlFlowReplacer],
+        [NodeType.LogicalExpression, NodeControlFlowReplacers.LogicalExpressionControlFlowReplacer]
     ]);
 
     /**
@@ -172,10 +172,7 @@ export class FunctionControlFlowTransformer extends AbstractNodeTransformer {
         const controlFlowStorageCustomNode: ICustomNode = this.customNodeFactory(CustomNodes.ControlFlowStorageNode);
 
         controlFlowStorageCustomNode.initialize(controlFlowStorage);
-
-        const controlFlowStorageNode: TStatement[] = controlFlowStorageCustomNode.getNode();
-
-        NodeAppender.prependNode(hostNode, controlFlowStorageNode);
+        NodeAppender.prependNode(hostNode, controlFlowStorageCustomNode.getNode());
         this.hostNodesWithControlFlowNode.push(hostNode);
     }
 }

+ 103 - 5
src/node-transformers/node-control-flow-transformers/control-flow-replacers/AbstractControlFlowReplacer.ts

@@ -3,36 +3,134 @@ import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
 
 import * as ESTree from 'estree';
 
+import { TCustomNodeFactory } from '../../../types/container/TCustomNodeFactory';
+import { TStatement } from '../../../types/node/TStatement';
+
 import { IControlFlowReplacer } from '../../../interfaces/node-transformers/IControlFlowReplacer';
 import { ICustomNode } from '../../../interfaces/custom-nodes/ICustomNode';
 import { IOptions } from '../../../interfaces/options/IOptions';
 import { IStorage } from '../../../interfaces/storages/IStorage';
 
+import { BinaryExpressionControlFlowReplacer } from './BinaryExpressionControlFlowReplacer';
+import { CustomNodes } from '../../../enums/container/CustomNodes';
+import { Node } from '../../../node/Node';
+import { RandomGeneratorUtils } from '../../../utils/RandomGeneratorUtils';
+
 @injectable()
 export abstract class AbstractControlFlowReplacer implements IControlFlowReplacer {
+    /**
+     * @type {TCustomNodeFactory}
+     */
+    protected readonly customNodeFactory: TCustomNodeFactory;
+
     /**
      * @type {IOptions}
      */
     protected readonly options: IOptions;
 
     /**
+     * @type {Map<string, Map<string, string[]>>}
+     */
+    protected readonly replacerDataByControlFlowStorageId: Map <string, Map<string, string[]>> = new Map();
+
+    /**
+     * @param customNodeFactory
      * @param options
      */
     constructor (
+        @inject(ServiceIdentifiers.Factory__ICustomNode) customNodeFactory: TCustomNodeFactory,
         @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
+        this.customNodeFactory = customNodeFactory;
         this.options = options;
     }
 
+    /**
+     * @param identifierDataByControlFlowStorageId
+     * @param controlFlowStorageId
+     * @returns {Map<string, string[]>}
+     */
+    protected static getStorageKeysByIdForCurrentStorage (
+        identifierDataByControlFlowStorageId: Map<string, Map<string, string[]>>,
+        controlFlowStorageId: string
+    ): Map<string, string[]> {
+        let storageKeysById: Map<string, string[]>;
+
+        if (identifierDataByControlFlowStorageId.has(controlFlowStorageId)) {
+            storageKeysById = <Map<string, string[]>>identifierDataByControlFlowStorageId.get(controlFlowStorageId);
+        } else {
+            storageKeysById = new Map <string, string[]> ();
+        }
+
+        return storageKeysById;
+    }
+
     /**
      * @param node
      * @param parentNode
      * @param controlFlowStorage
      * @returns {ESTree.Node}
      */
-    public abstract replace (
-        node: ESTree.Node,
-        parentNode: ESTree.Node,
-        controlFlowStorage: IStorage <ICustomNode>
-    ): ESTree.Node;
+    public abstract replace (node: ESTree.Node, parentNode: ESTree.Node, controlFlowStorage: IStorage <ICustomNode>): ESTree.Node;
+
+    /**
+     * @param controlFlowStorageId
+     * @param storageKey
+     * @param leftExpression
+     * @param rightExpression
+     * @returns {ESTree.Node}
+     */
+    protected getControlFlowStorageCallNode (
+        controlFlowStorageId: string,
+        storageKey: string,
+        leftExpression: ESTree.Expression,
+        rightExpression: ESTree.Expression
+    ): ESTree.Node {
+        const controlFlowStorageCallCustomNode: ICustomNode = this.customNodeFactory(CustomNodes.ControlFlowStorageCallNode);
+
+        controlFlowStorageCallCustomNode.initialize(controlFlowStorageId, storageKey, leftExpression, rightExpression);
+
+        const statementNode: TStatement = controlFlowStorageCallCustomNode.getNode()[0];
+
+        if (!statementNode || !Node.isExpressionStatementNode(statementNode)) {
+            throw new Error(`\`controlFlowStorageCallNode.getNode()[0]\` should returns array with \`ExpressionStatement\` node`);
+        }
+
+        return statementNode.expression;
+    }
+
+    /**
+     * @param customNode
+     * @param controlFlowStorage
+     * @param replacerId
+     * @param usingExistingIdentifierChance
+     * @returns {string}
+     */
+    protected insertCustomNodeToControlFlowStorage (
+        customNode: ICustomNode,
+        controlFlowStorage: IStorage <ICustomNode>,
+        replacerId: string,
+        usingExistingIdentifierChance: number
+    ): string {
+        const controlFlowStorageId: string = controlFlowStorage.getStorageId();
+        const storageKeysById: Map<string, string[]> = BinaryExpressionControlFlowReplacer
+            .getStorageKeysByIdForCurrentStorage(this.replacerDataByControlFlowStorageId, controlFlowStorageId);
+        const storageKeysForCurrentId: string[] | undefined = storageKeysById.get(replacerId);
+
+        if (
+            RandomGeneratorUtils.getRandomFloat(0, 1) > usingExistingIdentifierChance &&
+            storageKeysForCurrentId &&
+            storageKeysForCurrentId.length
+        ) {
+            return RandomGeneratorUtils.getRandomGenerator().pickone(storageKeysForCurrentId);
+        }
+
+        const storageKey: string = RandomGeneratorUtils.getRandomString(3);
+
+        storageKeysById.set(replacerId, [storageKey]);
+        this.replacerDataByControlFlowStorageId.set(controlFlowStorageId, storageKeysById);
+        controlFlowStorage.set(storageKey, customNode);
+
+        return storageKey;
+    }
 }

+ 13 - 74
src/node-transformers/node-control-flow-transformers/control-flow-replacers/BinaryExpressionControlFlowReplacer.ts

@@ -4,7 +4,6 @@ import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
 import * as ESTree from 'estree';
 
 import { TCustomNodeFactory } from '../../../types/container/TCustomNodeFactory';
-import { TStatement } from '../../../types/node/TStatement';
 
 import { ICustomNode } from '../../../interfaces/custom-nodes/ICustomNode';
 import { IOptions } from '../../../interfaces/options/IOptions';
@@ -13,25 +12,13 @@ import { IStorage } from '../../../interfaces/storages/IStorage';
 import { CustomNodes } from '../../../enums/container/CustomNodes';
 
 import { AbstractControlFlowReplacer } from './AbstractControlFlowReplacer';
-import { Node } from '../../../node/Node';
-import { RandomGeneratorUtils } from '../../../utils/RandomGeneratorUtils';
 
 @injectable()
 export class BinaryExpressionControlFlowReplacer extends AbstractControlFlowReplacer {
     /**
      * @type {number}
      */
-    private static readonly useExistingOperatorKeyThreshold: number = 0.5;
-
-    /**
-     * @type {Map<string, Map<ESTree.BinaryOperator, string[]>>}
-     */
-    private readonly binaryOperatorsDataByControlFlowStorageId: Map <string, Map<ESTree.BinaryOperator, string[]>> = new Map();
-
-    /**
-     * @type {TCustomNodeFactory}
-     */
-    private readonly customNodeFactory: TCustomNodeFactory;
+    private static readonly usingExistingIdentifierChance: number = 0.5;
 
     /**
      * @param customNodeFactory
@@ -41,30 +28,7 @@ export class BinaryExpressionControlFlowReplacer extends AbstractControlFlowRepl
         @inject(ServiceIdentifiers.Factory__ICustomNode) customNodeFactory: TCustomNodeFactory,
         @inject(ServiceIdentifiers.IOptions) options: IOptions
     ) {
-        super(options);
-
-        this.customNodeFactory = customNodeFactory;
-    }
-
-    /**
-     * @param binaryOperatorsDataByControlFlowStorageId
-     * @param controlFlowStorageId
-     * @returns {Map<ESTree.BinaryOperator, string[]>}
-     */
-    private static getStorageKeysByBinaryOperatorForCurrentStorage (
-        binaryOperatorsDataByControlFlowStorageId: Map<string, Map<ESTree.BinaryOperator, string[]>>,
-        controlFlowStorageId: string
-    ): Map<ESTree.BinaryOperator, string[]> {
-        let storageKeysByBinaryOperator: Map<ESTree.BinaryOperator, string[]>;
-
-        if (binaryOperatorsDataByControlFlowStorageId.has(controlFlowStorageId)) {
-            storageKeysByBinaryOperator = <Map<ESTree.BinaryOperator, string[]>>binaryOperatorsDataByControlFlowStorageId
-                .get(controlFlowStorageId);
-        } else {
-            storageKeysByBinaryOperator = new Map <ESTree.BinaryOperator, string[]> ();
-        }
-
-        return storageKeysByBinaryOperator;
+        super(customNodeFactory, options);
     }
 
     /**
@@ -78,48 +42,23 @@ export class BinaryExpressionControlFlowReplacer extends AbstractControlFlowRepl
         parentNode: ESTree.Node,
         controlFlowStorage: IStorage <ICustomNode>
     ): ESTree.Node {
-        const controlFlowStorageId: string = controlFlowStorage.getStorageId();
-        const controlFlowStorageCallCustomNode: ICustomNode = this.customNodeFactory(CustomNodes.ControlFlowStorageCallNode);
-        const storageKeysByBinaryOperator: Map<ESTree.BinaryOperator, string[]> = BinaryExpressionControlFlowReplacer
-            .getStorageKeysByBinaryOperatorForCurrentStorage(
-                this.binaryOperatorsDataByControlFlowStorageId,
-                controlFlowStorageId
-            );
-
-        const storageKeysForCurrentOperator: string[] | undefined = storageKeysByBinaryOperator.get(binaryExpressionNode.operator);
-
-        let storageKey: string;
+        const replacerId: string = binaryExpressionNode.operator;
+        const binaryExpressionFunctionCustomNode: ICustomNode = this.customNodeFactory(CustomNodes.BinaryExpressionFunctionNode);
 
-        if (
-            RandomGeneratorUtils.getRandomFloat(0, 1) > BinaryExpressionControlFlowReplacer.useExistingOperatorKeyThreshold &&
-            storageKeysForCurrentOperator &&
-            storageKeysForCurrentOperator.length
-        ) {
-            storageKey = RandomGeneratorUtils.getRandomGenerator().pickone(storageKeysForCurrentOperator);
-        } else {
-            const binaryExpressionFunctionCustomNode: ICustomNode = this.customNodeFactory(CustomNodes.BinaryExpressionFunctionNode);
+        binaryExpressionFunctionCustomNode.initialize(replacerId);
 
-            binaryExpressionFunctionCustomNode.initialize(binaryExpressionNode.operator);
-
-            storageKey = RandomGeneratorUtils.getRandomString(3);
-            storageKeysByBinaryOperator.set(binaryExpressionNode.operator, [storageKey]);
-            this.binaryOperatorsDataByControlFlowStorageId.set(controlFlowStorageId, storageKeysByBinaryOperator);
-            controlFlowStorage.set(storageKey, binaryExpressionFunctionCustomNode);
-        }
+        const storageKey: string = this.insertCustomNodeToControlFlowStorage(
+            binaryExpressionFunctionCustomNode,
+            controlFlowStorage,
+            replacerId,
+            BinaryExpressionControlFlowReplacer.usingExistingIdentifierChance
+        );
 
-        controlFlowStorageCallCustomNode.initialize(
-            controlFlowStorageId,
+        return this.getControlFlowStorageCallNode(
+            controlFlowStorage.getStorageId(),
             storageKey,
             binaryExpressionNode.left,
             binaryExpressionNode.right
         );
-
-        const statementNode: TStatement = controlFlowStorageCallCustomNode.getNode()[0];
-
-        if (!statementNode || !Node.isExpressionStatementNode(statementNode)) {
-            throw new Error(`\`controlFlowStorageCallNode.getNode()[0]\` should returns array with \`ExpressionStatement\` node`);
-        }
-
-        return statementNode.expression;
     }
 }

+ 92 - 0
src/node-transformers/node-control-flow-transformers/control-flow-replacers/LogicalExpressionControlFlowReplacer.ts

@@ -0,0 +1,92 @@
+import { injectable, inject } from 'inversify';
+import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
+
+import * as ESTree from 'estree';
+
+import { TCustomNodeFactory } from '../../../types/container/TCustomNodeFactory';
+
+import { ICustomNode } from '../../../interfaces/custom-nodes/ICustomNode';
+import { IOptions } from '../../../interfaces/options/IOptions';
+import { IStorage } from '../../../interfaces/storages/IStorage';
+
+import { CustomNodes } from '../../../enums/container/CustomNodes';
+
+import { AbstractControlFlowReplacer } from './AbstractControlFlowReplacer';
+import { Node } from '../../../node/Node';
+import { NodeUtils } from '../../../node/NodeUtils';
+
+@injectable()
+export class LogicalExpressionControlFlowReplacer extends AbstractControlFlowReplacer {
+    /**
+     * @type {number}
+     */
+    private static readonly usingExistingIdentifierChance: number = 0.5;
+
+    /**
+     * @param customNodeFactory
+     * @param options
+     */
+    constructor (
+        @inject(ServiceIdentifiers.Factory__ICustomNode) customNodeFactory: TCustomNodeFactory,
+        @inject(ServiceIdentifiers.IOptions) options: IOptions
+    ) {
+        super(customNodeFactory, options);
+    }
+
+    /**
+     * @param logicalExpressionNode
+     * @param parentNode
+     * @param controlFlowStorage
+     * @returns {ESTree.Node}
+     */
+    public replace (
+        logicalExpressionNode: ESTree.LogicalExpression,
+        parentNode: ESTree.Node,
+        controlFlowStorage: IStorage <ICustomNode>
+    ): ESTree.Node {
+        if (this.checkForProhibitedExpressions(logicalExpressionNode.left, logicalExpressionNode.right)) {
+            return logicalExpressionNode;
+        }
+
+        const replacerId: string = logicalExpressionNode.operator;
+        const logicalExpressionFunctionCustomNode: ICustomNode = this.customNodeFactory(CustomNodes.LogicalExpressionFunctionNode);
+
+        logicalExpressionFunctionCustomNode.initialize(replacerId);
+
+        const storageKey: string = this.insertCustomNodeToControlFlowStorage(
+            logicalExpressionFunctionCustomNode,
+            controlFlowStorage,
+            replacerId,
+            LogicalExpressionControlFlowReplacer.usingExistingIdentifierChance
+        );
+
+        return this.getControlFlowStorageCallNode(
+            controlFlowStorage.getStorageId(),
+            storageKey,
+            logicalExpressionNode.left,
+            logicalExpressionNode.right
+        );
+    }
+
+    /**
+     * @param leftExpression
+     * @param rightExpression
+     * @returns {boolean}
+     */
+    private checkForProhibitedExpressions (leftExpression: ESTree.Expression, rightExpression: ESTree.Expression): boolean {
+        return [leftExpression, rightExpression].some((expressionNode: ESTree.Node | ESTree.Expression): boolean => {
+            let nodeForCheck: ESTree.Node | ESTree.Expression;
+
+            if (!Node.isUnaryExpressionNode(expressionNode)) {
+                nodeForCheck = expressionNode;
+            } else {
+                nodeForCheck = NodeUtils.getUnaryExpressionArgumentNode(expressionNode);
+            }
+
+            return !Node.isLiteralNode(nodeForCheck) &&
+                !Node.isIdentifierNode(nodeForCheck) &&
+                !Node.isObjectExpressionNode(nodeForCheck) &&
+                !Node.isExpressionStatementNode(nodeForCheck);
+        });
+    }
+}

+ 9 - 0
src/node/Node.ts

@@ -186,6 +186,15 @@ export class Node {
             !Node.isLabelIdentifierNode(node, parentNode);
     }
 
+    /**
+     *
+     * @param node
+     * @returns {boolean}
+     */
+    public static isUnaryExpressionNode (node: ESTree.Node): node is ESTree.UnaryExpression {
+        return node.type === NodeType.UnaryExpression;
+    }
+
     /**
      *
      * @param node

+ 12 - 0
src/node/NodeUtils.ts

@@ -139,6 +139,18 @@ export class NodeUtils {
         return NodeUtils.getNodeBlockScopeDepth(parentNode, depth);
     }
 
+    /**
+     * @param unaryExpressionNode
+     * @returns {ESTree.Node}
+     */
+    public static getUnaryExpressionArgumentNode (unaryExpressionNode: ESTree.UnaryExpression): ESTree.Node {
+        if (Node.isUnaryExpressionNode(unaryExpressionNode.argument)) {
+            return NodeUtils.getUnaryExpressionArgumentNode(unaryExpressionNode.argument);
+        }
+
+        return unaryExpressionNode.argument;
+    }
+
     /**
      * @param node
      * @return {T}

+ 40 - 0
src/node/Nodes.ts

@@ -175,6 +175,26 @@ export class Nodes {
         };
     }
 
+    /**
+     * @param operator
+     * @param left
+     * @param right
+     * @returns {ESTree.LogicalExpression}
+     */
+    public static getLogicalExpressionNode (
+        operator: ESTree.LogicalOperator,
+        left: ESTree.Expression,
+        right: ESTree.Expression,
+    ): ESTree.LogicalExpression {
+        return {
+            type: NodeType.LogicalExpression,
+            operator,
+            left,
+            right,
+            obfuscated: false
+        };
+    }
+
     /**
      * @param object
      * @param property
@@ -227,6 +247,26 @@ export class Nodes {
         };
     }
 
+    /**
+     * @param operator
+     * @param argument
+     * @param prefix
+     * @returns {ESTree.Literal}
+     */
+    public static getUnaryExpressionNode (
+        operator: ESTree.UnaryOperator,
+        argument: ESTree.Expression,
+        prefix: boolean = true
+    ): ESTree.UnaryExpression {
+        return {
+            type: NodeType.UnaryExpression,
+            operator,
+            argument,
+            prefix,
+            obfuscated: false
+        };
+    }
+
     /**
      * @param argument
      * @return {ReturnStatement}

+ 0 - 0
test/fixtures/node-transformers/node-control-flow-transformers/control-flow-replacers/binary-expression-control-flow-replacer-1.js → test/fixtures/node-transformers/node-control-flow-transformers/control-flow-replacers/binary-expression-control-flow-replacer/binary-expression-control-flow-replacer-1.js


+ 0 - 0
test/fixtures/node-transformers/node-control-flow-transformers/control-flow-replacers/binary-expression-control-flow-replacer-2.js → test/fixtures/node-transformers/node-control-flow-transformers/control-flow-replacers/binary-expression-control-flow-replacer/binary-expression-control-flow-replacer-2.js


+ 3 - 0
test/fixtures/node-transformers/node-control-flow-transformers/control-flow-replacers/logical-expression-control-flow-replacer/logical-expression-control-flow-replacer-1.js

@@ -0,0 +1,3 @@
+(function () {
+    var variable = true && false;
+})();

+ 4 - 0
test/fixtures/node-transformers/node-control-flow-transformers/control-flow-replacers/logical-expression-control-flow-replacer/logical-expression-control-flow-replacer-2.js

@@ -0,0 +1,4 @@
+(function () {
+    var variable1 = true && false;
+    var variable2 = false && true;
+})();

+ 5 - 0
test/fixtures/node-transformers/node-control-flow-transformers/control-flow-replacers/logical-expression-control-flow-replacer/logical-expression-control-flow-replacer-3.js

@@ -0,0 +1,5 @@
+(function () {
+    var expression1 = true;
+    var expression2 = false;
+    var variable = !expression1 && !expression2;
+})();

+ 5 - 0
test/fixtures/node-transformers/node-control-flow-transformers/control-flow-replacers/logical-expression-control-flow-replacer/logical-expression-control-flow-replacer-prohibited-nodes-1.js

@@ -0,0 +1,5 @@
+(function () {
+    var object = {};
+    var name = 'abc';
+    var variable = object[name] && false;
+})();

+ 3 - 0
test/fixtures/node-transformers/node-control-flow-transformers/function-control-flow-transformer-zero-threshold.js

@@ -0,0 +1,3 @@
+(function () {
+    var variable = 1 + 2;
+})();

+ 21 - 0
test/functional-tests/node-transformers/node-control-flow-transformers/FunctionControlFlowTransformer.spec.ts

@@ -169,5 +169,26 @@ describe('FunctionControlFlowTransformer', () => {
                 assert.equal(totalValue, expectedValue);
             });
         });
+
+        describe('variant #6 - no single `control flow storage` node when threshold is 0', () => {
+            const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
+                readFileAsString(
+                    './test/fixtures/node-transformers/node-control-flow-transformers/function-control-flow-transformer-zero-threshold.js'
+                ),
+                {
+                    ...NO_CUSTOM_NODES_PRESET,
+                    controlFlowFlattening: true,
+                    controlFlowFlatteningThreshold: 0
+                }
+            );
+            const obfuscatedCode: string = obfuscationResult.getObfuscatedCode();
+            const controlFlowStorageMatch: RegExp = new RegExp(rootControlFlowStorageNodeMatch);
+            const regexp: RegExp = /var *_0x([a-z0-9]){4,6} *= *0x1 *\+ *0x2;/;
+
+            it('shouldn\'t add `control flow storage` node to the obfuscated code when threshold is 0', () => {
+                assert.match(obfuscatedCode, regexp);
+                assert.notMatch(obfuscatedCode, controlFlowStorageMatch);
+            });
+        });
     });
 });

+ 2 - 2
test/functional-tests/node-transformers/node-control-flow-transformers/control-flow-replacers/BinaryExpressionControlFlowReplacer.spec.ts

@@ -13,7 +13,7 @@ describe('BinaryExpressionControlFlowReplacer', () => {
         describe('variant #1 - single binary expression', () => {
             const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
                 readFileAsString(
-                    './test/fixtures/node-transformers/node-control-flow-transformers/control-flow-replacers/binary-expression-control-flow-replacer-1.js'
+                    './test/fixtures/node-transformers/node-control-flow-transformers/control-flow-replacers/binary-expression-control-flow-replacer/binary-expression-control-flow-replacer-1.js'
                 ),
                 {
                     ...NO_CUSTOM_NODES_PRESET,
@@ -42,7 +42,7 @@ describe('BinaryExpressionControlFlowReplacer', () => {
                 for (let i = 0; i < samplesCount; i++) {
                     const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
                         readFileAsString(
-                            './test/fixtures/node-transformers/node-control-flow-transformers/control-flow-replacers/binary-expression-control-flow-replacer-2.js'
+                            './test/fixtures/node-transformers/node-control-flow-transformers/control-flow-replacers/binary-expression-control-flow-replacer/binary-expression-control-flow-replacer-2.js'
                         ),
                         {
                             ...NO_CUSTOM_NODES_PRESET,

+ 115 - 0
test/functional-tests/node-transformers/node-control-flow-transformers/control-flow-replacers/LogicalExpressionControlFlowReplacer.spec.ts

@@ -0,0 +1,115 @@
+import { assert } from 'chai';
+
+import { IObfuscationResult } from '../../../../../src/interfaces/IObfuscationResult';
+
+import { NO_CUSTOM_NODES_PRESET } from '../../../../../src/options/presets/NoCustomNodes';
+
+import { readFileAsString } from '../../../../helpers/readFileAsString';
+
+import { JavaScriptObfuscator } from '../../../../../src/JavaScriptObfuscator';
+
+describe('LogicalExpressionControlFlowReplacer', () => {
+    describe('replace (logicalExpressionNode: ESTree.LogicalExpression,parentNode: ESTree.Node,controlFlowStorage: IStorage <ICustomNode>)', () => {
+        describe('variant #1 - single logical expression', () => {
+            const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
+                readFileAsString(
+                    './test/fixtures/node-transformers/node-control-flow-transformers/control-flow-replacers/logical-expression-control-flow-replacer/logical-expression-control-flow-replacer-1.js'
+                ),
+                {
+                    ...NO_CUSTOM_NODES_PRESET,
+                    controlFlowFlattening: true,
+                    controlFlowFlatteningThreshold: 1
+                }
+            );
+            const obfuscatedCode: string = obfuscationResult.getObfuscatedCode();
+            const controlFlowStorageCallRegExp: RegExp = /var *_0x([a-z0-9]){4,6} *= *_0x([a-z0-9]){4,6}\['(\\x[a-f0-9]*){3}'\]\(!!\[\], *!\[\]\);/;
+
+            it('should replace logical expression node by call to control flow storage node', () => {
+                assert.match(obfuscatedCode, controlFlowStorageCallRegExp);
+            });
+        });
+
+        describe('variant #2 - multiple logical expressions with threshold = 1', () => {
+            it('should replace logical expression node by call to control flow storage node', function () {
+                this.timeout(4000);
+
+                const samplesCount: number = 200;
+                const expectedValue: number = 0.5;
+                const delta: number = 0.1;
+
+                let equalsValue: number = 0;
+
+                for (let i = 0; i < samplesCount; i++) {
+                    const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
+                        readFileAsString(
+                            './test/fixtures/node-transformers/node-control-flow-transformers/control-flow-replacers/logical-expression-control-flow-replacer/logical-expression-control-flow-replacer-2.js'
+                        ),
+                        {
+                            ...NO_CUSTOM_NODES_PRESET,
+                            controlFlowFlattening: true,
+                            controlFlowFlatteningThreshold: 1
+                        }
+                    );
+                    const obfuscatedCode: string = obfuscationResult.getObfuscatedCode();
+                    const controlFlowStorageCallRegExp1: RegExp = /var *_0x([a-z0-9]){4,6} *= *(_0x([a-z0-9]){4,6}\['(\\x[a-f0-9]*){3}'\])\(!!\[\], *!\[\]\);/;
+                    const controlFlowStorageCallRegExp2: RegExp = /var *_0x([a-z0-9]){4,6} *= *(_0x([a-z0-9]){4,6}\['(\\x[a-f0-9]*){3}'\])\(!\[\], *!!\[\]\);/;
+
+                    const firstMatchArray: RegExpMatchArray | null = obfuscatedCode.match(controlFlowStorageCallRegExp1);
+                    const secondMatchArray: RegExpMatchArray | null = obfuscatedCode.match(controlFlowStorageCallRegExp2);
+
+                    const firstMatch: string | undefined = firstMatchArray ? firstMatchArray[2] : undefined;
+                    const secondMatch: string | undefined = secondMatchArray ? secondMatchArray[2] : undefined;
+
+                    assert.match(obfuscatedCode, controlFlowStorageCallRegExp1);
+                    assert.match(obfuscatedCode, controlFlowStorageCallRegExp2);
+                    assert.isOk(firstMatch);
+                    assert.isOk(secondMatch);
+
+                    if (firstMatch === secondMatch) {
+                        equalsValue++;
+                    }
+                }
+
+                assert.closeTo(equalsValue / samplesCount, expectedValue, delta);
+            });
+        });
+
+        describe('variant #3 - single logical expression with unary expression', () => {
+            const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
+                readFileAsString(
+                    './test/fixtures/node-transformers/node-control-flow-transformers/control-flow-replacers/logical-expression-control-flow-replacer/logical-expression-control-flow-replacer-3.js'
+                ),
+                {
+                    ...NO_CUSTOM_NODES_PRESET,
+                    controlFlowFlattening: true,
+                    controlFlowFlatteningThreshold: 1
+                }
+            );
+            const obfuscatedCode: string = obfuscationResult.getObfuscatedCode();
+            const controlFlowStorageCallRegExp: RegExp = /var *_0x([a-z0-9]){4,6} *= *_0x([a-z0-9]){4,6}\['(\\x[a-f0-9]*){3}'\]\(!_0x([a-z0-9]){4,6}, *!_0x([a-z0-9]){4,6}\);/;
+
+            it('should replace logical expression node with unary expression by call to control flow storage node', () => {
+                assert.match(obfuscatedCode, controlFlowStorageCallRegExp);
+            });
+        });
+
+        describe('prohibited nodes variant #1', () => {
+            const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
+                readFileAsString(
+                    './test/fixtures/node-transformers/node-control-flow-transformers/control-flow-replacers/logical-expression-control-flow-replacer/logical-expression-control-flow-replacer-prohibited-nodes-1.js'
+                ),
+                {
+                    ...NO_CUSTOM_NODES_PRESET,
+                    controlFlowFlattening: true,
+                    controlFlowFlatteningThreshold: .1
+                }
+            );
+            const obfuscatedCode: string = obfuscationResult.getObfuscatedCode();
+            const regExp: RegExp = /var *_0x([a-z0-9]){4,6} *= *_0x([a-z0-9]){4,6}\[_0x([a-z0-9]){4,6}\] *&& *!\[\];/;
+
+            it('shouldn\'t replace prohibited expression nodes', () => {
+                assert.match(obfuscatedCode, regExp);
+            });
+        });
+    });
+});

+ 1 - 0
test/index.spec.ts

@@ -32,6 +32,7 @@ import './functional-tests/custom-nodes/string-array-nodes/StringArrayRotateFunc
 import './functional-tests/custom-nodes/string-array-nodes/StringArrayNode.spec';
 import './functional-tests/node-transformers/node-control-flow-transformers/FunctionControlFlowTransformer.spec';
 import './functional-tests/node-transformers/node-control-flow-transformers/control-flow-replacers/BinaryExpressionControlFlowReplacer.spec';
+import './functional-tests/node-transformers/node-control-flow-transformers/control-flow-replacers/LogicalExpressionControlFlowReplacer.spec';
 import './functional-tests/node-transformers/node-obfuscators/CatchClauseObfuscator.spec';
 import './functional-tests/node-transformers/node-obfuscators/FunctionDeclarationObfuscator.spec';
 import './functional-tests/node-transformers/node-obfuscators/FunctionObfuscator.spec';

+ 28 - 0
test/unit-tests/node/NodeUtils.spec.ts

@@ -281,6 +281,34 @@ describe('NodeUtils', () => {
         });
     });
 
+    describe('getUnaryExpressionArgumentNode (unaryExpressionNode: ESTree.UnaryExpression): ESTree.Node', () => {
+        let expressionStatementNode: ESTree.ExpressionStatement,
+            literalNode: ESTree.Literal,
+            unaryExpressionNode1: ESTree.UnaryExpression,
+            unaryExpressionNode2: ESTree.UnaryExpression,
+            programNode: ESTree.Program;
+
+        beforeEach(() => {
+            literalNode = Nodes.getLiteralNode('test');
+            unaryExpressionNode2 = Nodes.getUnaryExpressionNode('!', literalNode)
+            unaryExpressionNode1 = Nodes.getUnaryExpressionNode('!', unaryExpressionNode2)
+            expressionStatementNode = Nodes.getExpressionStatementNode(unaryExpressionNode1);
+            programNode = Nodes.getProgramNode([
+                expressionStatementNode
+            ]);
+
+            programNode.parentNode = programNode;
+            expressionStatementNode.parentNode = programNode;
+            unaryExpressionNode1.parentNode = expressionStatementNode;
+            unaryExpressionNode2.parentNode = unaryExpressionNode1;
+            literalNode.parentNode = unaryExpressionNode2;
+        });
+
+        it('should return unary expression argument node', () => {
+            assert.deepEqual(NodeUtils.getUnaryExpressionArgumentNode(unaryExpressionNode1), literalNode);
+        });
+    });
+
     describe('parentize (node: ESTree.Node): void', () => {
         let ifStatementNode: ESTree.IfStatement,
             ifStatementBlockStatementNode: ESTree.BlockStatement,