preface
In the security battlefield, front-end code is open, so does it make sense to encrypt the front-end? Most people would probably say, no point, don’t create your own encryption algorithm, just use HTTPS. But in fact, it makes sense to know cryptography even if you don’t know it, because the pre-encryption and post-decryption links are not protected. HTTPS protects only the transport layer and nothing else.
The encryption link is divided into:
- Transmission encryption (against link cracking)
- Data encryption (against protocol cracking)
- Code encryption (hiding algorithms, undebugging…)
This article mainly enumerates some I see, I think of some encryption way, in fact, exactly say, should be called confusion, should not be called encryption.
So, what exactly does code obfuscation work? It is simply a matter of removing as much meaningful information from the code as possible, such as comments, line breaks, whitespace, code minus signs, variable renaming, attribute renaming (where possible), useless code removal, and so on. Because the code is public, we must admit that no algorithm can be completely unbreakable, so we can only make it as expensive as possible for an attacker to read the code.
The original address
Syntax tree AST confusion
On the condition that the original functionality of the code is guaranteed, we can change the AST of the code as needed, and then generate a code output after the change, so as to achieve the purpose of confusion. The most commonly used UGlip-JS is to confuse the code in this way. Of course, the confusion of Uglip-JS is mainly about code compression. This is the variable name confusion we’ll talk about next.
Variable name confusion
Confuses variable names into characters that are difficult to read and increases the difficulty of code reading. Uglip-js confuses variables into short names (mainly for code compression), while most safe direction confuses them into hexadecimal variable names. The effect is as follows:
var test = 'hello';
Copy the code
After the confusion:
var _0x7deb = 'hello';
Copy the code
Matters needing attention:
-
The eval function may use the original variable name. If the eval function is not used, it may run an error as follows:
var test = 'hello'; eval('console.log(test)'); Copy the code
If you do not obfuscate console.log(test) in eval, an error is reported. However, if the eval syntax goes beyond static analysis, for example:
var test = 'hello'; var variableName = 'test'; eval('console.log(' + variableName + ') '); Copy the code
To do this, you might have to traverse the AST to find the result and then obfuscate it again, but it seems to be expensive.
-
If the code is exported as an SDK, we need to keep the global variable name unchanged, for example:
<script> var$=function(id) { return document.getElementById(id); }; </script> Copy the code
The $variable is placed globally, and after the confusion looks like this:
<script> var _0x6482fa = function(id) { return document.getElementById(id); }; </script> Copy the code
So if you rely on the module of this code, calling $(‘id’) will naturally return an error because the global variable has been obfuscated.
Constant extract
JS constant extraction to the array, when the array subscript call, so that direct reading basic impossible, or anti-AST processing, or step by step debugging, workload increased.
Take the above code for example:
var test = 'hello';
Copy the code
After the confusion:
var _0x9d2b = ['hello'];
var _0xb7de = function (_0x4c7513) {
var _0x96ade5 = _0x9d2b[_0x4c7513];
return _0x96ade5;
};
var test = _0xb7de(0);
Copy the code
Of course, we can convert an array to a 2-bit array, a 3-dimensional array, etc., as long as we get it where we need it.
Constant confusion
In the above code, although it has been confused after the code, but the Hello string is still in the form of plaintext in the code, you can use JS hexadecimal encoding will directly decode the feature of the key word Unicode hexadecimal encoding. As follows:
var test = 'hello';
Copy the code
Combined with constant extraction, confusion results are obtained:
var _0x9d2b = ['\x68\x65\x6c\x6c\x6f'];
var _0xb7de = function (_0x4c7513) {
_0x4c7513 = _0x4c7513 - 0x0;
var _0x96ade5 = _0x9d2b[_0x4c7513];
return _0x96ade5;
};
var test = _0xb7de('0x0');
Copy the code
In addition to the Unicode auto-parsing feature, you can also customize some encryption and decryption algorithms, such as base64 encoding constants, or other rc4, etc., just need to use when decrypting OK, such as the above code with base64 encoding:
var _0x9d2b = ['aGVsbG8=']; // Base64 encoded string
var _0xaf421 = function (_0xab132) {
// base64 decoding function
var _0x75aed = function(_0x2cf82) {
// TODO:decoding
};
return _0x75aed(_0xab132);
}
var _0xb7de = function (_0x4c7513) {
_0x4c7513 = _0x4c7513 - 0x0;
var _0x96ade5 = _0xaf421(_0x9d2b[_0x4c7513]);
return _0x96ade5;
};
var test = _0xb7de('0x0');
Copy the code
Operation confused
Turning all logical and binary operators into functions is also intended to make the code more difficult to read and not be able to get results directly from static analysis. As follows:
var i = 1 + 2;
var j = i * 2;
var k = j || i;
Copy the code
After the confusion:
var _0x62fae = {
_0xeca4f: function(_0x3c412, _0xae362) {
return _0x3c412 + _0xae362;
},
_0xe82ae: function(_0x63aec, _0x678ec) {
return _0x63aec * _0x678ec;
},
_0x2374a: function(_0x32487, _0x3a461) {
return_0x32487 || _0x3a461; }};var i = _0x62fae._0e8ca4f(1.2);
var j = _0x62fae._0xe82ae(i, 2);
var k = _0x62fae._0x2374a(i, j);
Copy the code
Of course, in addition to logical and binary operators, a similar confusion can be made between function calls and static strings, as follows:
var fun1 = function(name) {
console.log('hello, ' + name);
};
var fun2 = function(name, age) {
console.log(name + ' is ' + age + ' years old');
}
var name = 'xiao.ming';
fun1(name);
fun2(name, 8);
Copy the code
var _0x62fae = {
_0xe82ae: function(_0x63aec, _0x678ec) {
return _0x63aec(_0x678ec);
},
_0xeca4f: function(_0x92352, _0x3c412, _0xae362) {
return _0x92352(_0x3c412, _0xae362)
},
_0x2374a: 'xiao.ming'._0x5482a: 'hello, '._0x837ce: ' is '._0x3226e: ' years old'
};
var fun1 = function(name) {
console.log(_0x62fae._0x5482a + name);
};
var fun2 = function(name, age) {
console.log(name + _0x62fae._0x837ce + age + _0x62fae._0x3226e);
}
var name = _0x62fae._0x2374a;
_0x62fae._0xe82ae(fun1, name);
_0x62fae._0xeca4f(fun2, name, 0x8);
Copy the code
In the above example, the addition of strings in fun1 and fun2 is also obfuscated, and static strings are also extracted from the array by the string extraction mentioned earlier (I’m too lazy to write this part of the code).
Note that each time we encounter the same operator, it is up to us whether we need to regenerate the function to replace it.
Grammar uglification
Confusing our common syntax with our less common syntax without changing the functionality of the code. For example, replace for with do/while, as follows:
for (i = 0; i < n; i++) {
// TODO: do something
}
var i = 0;
do {
if (i >= n) break;
// TODO: do something
i++;
} while (true)
Copy the code
Dynamic execution
Adding dynamic judgment to statically executed code, run-time dynamic decision operators, interferes with static analysis.
As follows:
var c = 1 + 2;
Copy the code
After the confusion:
function _0x513fa(_0x534f6, _0x85766) { return _0x534f6 + _0x85766; }
function _0x3f632(_0x534f6, _0x534f6) { return _0x534f6 - _0x534f6; }
// dynamic decision function
function _0x3fa24() {
return true;
}
var c = _0x3fa24() ? _0x513fa(1.2) : _0x3f632(1.2);
Copy the code
The process confusion
Obfuscation of execution flow, also known as control flow flattening, why obfuscation of execution flow? Because in the process of code development, in order to make the code logic clear, easy to maintain and expand, the code will be written logic is very clear. A piece of code executes sequentially from the input through the various if/else branches to get different results, and we need to confuse the execution flow with the decision flow to make it harder for an attacker to understand our execution logic.
Control flow flattening is divided into sequential flattening and conditional flattening.
The order flattens
As the name implies, the sequential, top-down code is decomposed into several branches for execution, as follows:
(function () {
console.log(1);
console.log(2);
console.log(3);
console.log(4);
console.log(5); }) ();Copy the code
The flow chart is as follows:
After the confusion, the code looks like this:
(function () {
var flow = '3 4 | | 0 | 1 | 2'.split('|'), index = 0;
while(!!!!! []) {switch (flow[index++]) {
case '0':
console.log(3);
continue;
case '1':
console.log(4);
continue;
case '2':
console.log(5);
continue;
case '3':
console.log(1);
continue;
case '4':
console.log(2);
continue;
}
break;
}
}());
Copy the code
The flowchart after the confusion is as follows:
The process looks flat.
The conditions are flat
The effect of conditional flattening is to flat all the if/else branches of the process into one process, with the same entry and exit points in the flowchart.
The following code:
function modexp(y, x, w, n) {
var R, L;
var k = 0;
var s = 1;
while(k < w) {
if (x[k] == 1) {
R = (s * y) % n;
}
else {
R = s;
}
s = R * R % n;
L = R;
k++;
}
return L;
}
Copy the code
In the code above, the flow chart looks like this
The code after control flow flattening is as follows:
function modexp(y, x, w, n) {
var R, L, s, k;
var next = 0;
for(;;) {
switch(next) {
case 0: k = 0; s = 1; next = 1; break;
case 1: if (k < w) next = 2; else next = 6; break;
case 2: if (x[k] == 1) next = 3; else next = 4; break;
case 3: R = (s * y) % n; next = 5; break;
case 4: R = s; next = 5; break;
case 5: s = R * R % n; L = R; k++; next = 1; break;
case 6: returnL; }}}Copy the code
The flowchart after the confusion is as follows:
The intuitive feeling is that the code becomes flat, all the code is crowded into a layer, the advantage of this is that the attacker cannot intuitively, or through the method of static analysis to determine which code is executed first and which is executed later, must be dynamically run to record the execution order, thus increasing the burden of analysis.
It is important to note that in our process, whether sequential or conditional, if a block-scoped variable declaration (const/let) occurs, the process flattening above will cause an error because the switch/case is block-scoped and the expression is assigned to the case. Other cases where a const/let variable declaration is not available will result in an error.
Opaque predicate
The above switch/case judgment is determined by the form of a number (i.e. predicate), and is transparent and visible. For further confusion, we can set the case judgment as an expression, so that it cannot be determined directly. For example, we can use the above code to change the predicate to opaque:
function modexp(y, x, w, n) {
var a = 0, b = 1, c = 2 * b + a;
var R, L, s, k;
var next = 0;
for(;;) {
switch(next) {
case (a * b): k = 0; s = 1; next = 1; break;
case (2 * a + b): if (k < w) next = 2; else next = 6; break;
case (2 * b - a): if (x[k] == 1) next = 3; else next = 4; break;
case (3 * a + b + c): R = (s * y) % n; next = 5; break;
case (2 * b + c): R = s; next = 5; break;
case (2 * c + b): s = R * R % n; L = R; k++; next = 1; break;
case (4 * c - 2 * b): returnL; }}}Copy the code
Predicates are made up of variables A, B, and C, and can even be hidden globally or hidden in an array so that an attacker can’t find them.
Shell script to add
The script is encoded, decoded at runtime, and eval is executed as follows:
eval(................................................ . ........................ ........................... .! @# $% ^ & *........................ ................................................... . ........................ .).
Copy the code
But in practice this doesn’t mean much, because an attacker just needs to expose the alert or console.log
Function/(Function (){}).constructor;
var code = 'console.log("hellow")';
(new Function(code))();
Copy the code
In the code above, you can encrypt and obfuscate code, such as aaencode, and it works the same way. Let’s take an example
alert("Hello, JavaScript");
Copy the code
After using aaencode obfuscation, the code looks like this:
゚ω゚ Blue = / 'M ´) Blue ~ loot and added //*´∇' */ ['_']; O =(゚ * ゚) =_=3; C =(゚ θ ゚) =(゚ 漢 字 ー゚)-(゚ 漢 字); (゚ д ゚)= (゚ θ ゚)= (o^_^o)/ (o^_^o); (゚ д ゚)={゚ θ ゚:'_',゚ω゚ Blue: ((゚ω゚ blue ==3) +'_') [゚ θ ゚],゚ 漢 字 blue :(byte ω blue +'_')[o^_^o -(゚ θ ゚)],゚ д ゚ blue :((port 漢 字 ==3) +'_')[゚ * ゚]}; (゚ д ゚) [゚ θ ゚] =((゚ω blue ==3) +'_') [c^_^o]; (゚ д ゚) ['c'[(゚ д ゚)+'_') [(゚ 漢 詩 ー゚)+(゚ 漢 詩)-(kappa Phi Kappa)]; (゚ д ゚) ['o'[(゚ д ゚)+'_') [゚ θ ゚]; (゚o゚)=(゚ д ゚) ['c'[゚ д ゚]'o']+(゚ω゚ Blue +'_')[゚ θ ゚]+ ((゚ω゚ Blue ==3) +'_'(゚ * ゚] + (゚ д ゚) +'_') [(゚ * ゚)+(゚ * ゚)]+ ((science * ゚==3) +'_') [゚ θ ゚]+((゚ * ゚==3) +'_') [(゚ * ゚) - (゚ θ ゚)]+(д fe) ['c'[(゚ д ゚)+'_') [(゚ * ゚)+(゚ * ゚)]+ (successively blued) ['o']+((゚ * ゚==3) +'_') [゚ θ ゚]; (゚ д ゚) ['_'] =(o^_^o) [゚o゚] [゚o゚]; (゚ε゚)=(゚ * ゚==3) +'_') [゚ θ ゚]+ (゚ д ゚)'_') [(゚ * ゚) +(゚ * ゚)]+((science * ゚==3) +'_') [o^_^o -゚ θ ゚]+((゚ * ゚==3) +'_') [゚ θ ゚]+ (゚ω゚ Blue +'_') [゚ θ ゚]; (゚ * ゚)+=(゚ θ ゚); ゚ д ゚)[゚ε゚]='\ \'; (゚ д ゚).゚ θ ゚ =(alternately alternately alternately)[o^_^o -(occasionally θ ゚)]; (o゚ * ゚o)=(゚ω゚ blue +'_')[c^_^o]; (゚ д ゚) [゚o゚]='\ "'; (゚ д ゚) ['_'[(゚ д ゚) ['_'] (゚ epsilon ゚ + (゚ Д ゚) [゚ ゚] o + (゚ Д ゚) [゚ epsilon ゚] + (゚ Θ ゚) + (゚ ー ゚) + (゚ Θ ゚) + (゚ Д ゚) [゚ epsilon ゚] + (゚ Θ ゚) + ((゚ ー ゚) + (゚ Θ ゚)) + (゚ ー ゚) + (゚ Д ゚) [゚ epsilon ゚] + (゚ Θ ゚) + (゚ ー ゚) + ((゚ ー ゚) + (゚ Θ ゚)) + (゚ Д ゚) [゚ epsilon ゚] + (゚ Θ ゚) + (^_^ o (o) + ^_^ o) (o) + (^_^ o (o) - (゚ Θ ゚)) + (゚ Д ゚) [゚ epsilon ゚] + (゚ Θ ゚) + (^_^ o (o) + ^_^ o) (o) + (゚ ー ゚) + (゚ Д ゚) [゚ epsilon ゚] + ((゚ ー ゚) + (゚ Θ ゚)) + (c ^_^ o) + (゚ Д ゚) [゚ epsilon ゚] + (゚ ー ゚) + (^_^ o (o) - (゚ Θ ゚)) + (゚ Д ゚) [゚ epsilon ゚] + (゚ Θ ゚) + (゚ Θ ゚) + + ^_^ o (c) (゚ Д ゚) [゚ epsilon ゚] + (゚ Θ ゚) + (゚ ー ゚) + ((゚ ー ゚) + (゚ Θ ゚)) + (゚ Д ゚) [゚ epsilon ゚] + (゚ Θ ゚) + ((゚ ー ゚) + (゚ Θ ゚)) + (゚ ー ゚) + (゚ Д ゚) [゚ epsilon ゚] + (゚ Θ ゚) + ((゚ ー ゚) + (゚ Θ ゚)) + (゚ ー ゚) + (゚ Д ゚) [゚ epsilon ゚] + (゚ Θ ゚) + ((゚ ー ゚) + (゚ Θ ゚)) + ((゚ ー ゚) + ^_^ o) (o) + (゚ Д ゚) [゚ epsilon ゚] + ((゚ ー ゚) + (゚ Θ ゚)) + (゚ ー ゚) + (゚ Д ゚) [゚ epsilon ゚] + (゚ ー ゚) + ^_^ o (c) + (゚ Д ゚) [゚ epsilon ゚] + (゚ Θ ゚) + (゚ Θ ゚) + (^_^ o (o) - (゚ Θ ゚)) + (゚ Д ゚) [゚ epsilon ゚] + (゚ Θ ゚) + (゚ ー ゚) + (゚ Θ ゚) + (゚ Д ゚) [゚ epsilon ゚] + (゚ Θ ゚) + (^_^ o (o) ^_^ o + (o)) + (^_^ o (o) + ^_^ o) (o) + (゚ Д ゚) [゚ epsilon ゚] + (゚ Θ ゚) + (゚ ー ゚) + (゚ Θ ゚) + (゚ Д ゚) [゚ epsilon ゚] + (゚ Θ ゚) + (^_^ o (o) - (゚ Θ ゚)) + + ^_^ o (o) (゚ Д ゚) [゚ epsilon ゚] + (゚ Θ ゚) + (゚ ー ゚) + ^_^ o (o) + (゚ Д ゚) [゚ epsilon ゚] + (゚ Θ ゚) + (^_^ o (o) + ^_^ o) (o) + (^_^ o (o) - (゚ Θ ゚)) + (゚ Д ゚) [゚ epsilon ゚] + (゚ Θ ゚) + ((゚ ー ゚) + (゚ Θ ゚)) + (゚ Θ ゚) + (゚ Д ゚) [゚ epsilon ゚] + (゚ Θ ゚) + (^_^ o (o) + ^_^ o) (o) + (c ^_^ o) + (゚ Д ゚) [゚ epsilon ゚] + (゚ Θ ゚) + (^_^ o (o) + ^_^ o) (o) + (゚ ー ゚) + (゚ Д ゚) [゚ epsilon ゚] + (゚ ー ゚) + (^_^ o (o) - (゚ Θ ゚)) + (゚ Д ゚) [゚ epsilon ゚] + ((゚ ー ゚) + (゚ Θ ゚)) + (゚ Θ ゚) + (゚ Д ゚) [゚ o ゚]) (゚ Θ ゚)) ('_');
Copy the code
This code looks weird and doesn’t look like JavaScript code, but it actually declares a 16-bit array (representing hexadecimal positions) using some emotical-looking symbols, and then iterates through code as a string, For each code symbol, string. CharCodeAt takes the 16-bit array subscript and concatenates it into code. This basically means treating the code as a string, replacing the code with a concatenation of these symbols (you can see that the code has a lot of plus signs), and finally, executing it with (new Function(code))(‘_’).
Take a closer look at the above code and remove the (‘_’) at the end of the code. On the run, you’ll see the source code directly, and then Function. Constructor exists in (゚ д ゚) variable for those interested to see for themselves.
In addition to aaencode, JjenCode principle is about the same, not to explain, other more arrogant JSFUCK, these are the code encryption, here will not be introduced in detail.
The debug
Since JavaScript comes with debugger syntax, we can take advantage of an infinite loop of debugger, which allows the page to go into the debugger state indefinitely when it opens the debugger panel.
Regularly perform
Use setInterval to trigger our anti-debug function periodically when the code starts executing.
Random execution
In the code generation stage, we randomly inject our anti-debugging function into part of the function body. When the code is executed to a specific logic, if the debugging panel is in the open state, it will enter the debugging state indefinitely.
Content monitoring
Because our code may have been undebugged, attackers can copy the code to their own local, and then modify, debug, execute, at this time, it is necessary to add some detection to determine, if the normal environment is not executed, then let the code fail.
Code self-inspection
During code generation, a Hash is generated for the function, and before the code is executed, the toString method is used to detect whether the code has been tampered with
function module() {
// Tamper with checksum
if (Hash(module.toString()) ! ='JkYxnHlxHbqKowiuy') {
// Code tampered with!}}Copy the code
Environmental self-inspection
Check the execution environment of the current script, such as whether the current URL is in the allowed whitelist, and whether the current environment is normal browser.
If Nodejs environment, if abnormal environment, even we can start Trojan, long-term tracking.
Dead code injection
Insert code that will never happen, confusing the attacker with useless junk code when analyzing the code and making it harder to read.
Waste logic injection
The useful code represents the logic of the code being executed. At this time, we can collect the logic and add a judgment to decide whether to execute true logic or false logic, as follows:
(function(){
if (true) {
var foo = function () {
console.log('abc');
};
var bar = function () {
console.log('def');
};
var baz = function () {
console.log('ghi');
};
var bark = function () {
console.log('jkl');
};
var hawk = function () {
console.log('mno');
};
foo();
bar();
baz();
bark();
hawk();
}
})();
Copy the code
As you can see, all console. logs are our execution logic. At this point, we can collect all console. logs and make false decisions to execute the real logic code.
(function(){
if (true) {
var foo = function () {
if ('aDas'= = ='aDas') {
console.log('abc');
} else {
console.log('def'); }};var bar = function () {
if ('Mfoi'! = ='daGs') {
console.log('ghi');
} else {
console.log('def'); }};var baz = function () {
if ('yuHo'= = ='yuHo') {
console.log('ghi');
} else {
console.log('abc'); }};var bark = function () {
if ('qu2o'= = ='qu2o') {
console.log('jkl');
} else {
console.log('mno'); }};var hawk = function () {
if ('qCuo'! = ='qcuo') {
console.log('jkl');
} else {
console.log('mno'); }}; foo(); bar(); baz(); bark(); hawk(); }}) ();Copy the code
Decision logic generates some string, without using a string extraction, it can be through code static analysis to get the real execution logic, or we can use the above said executed to determine the dynamic logic, can see use string extraction and the effect after the variable name code, as follows:
var _0x6f5a = [
'abc'.'def'.'caela'.'hmexe'.'ghi'.'aaeem'.'maxex'.'mno'.'jkl'.'ladel'.'xchem'.'axdci'.'acaeh'.'log'
];
(function (_0x22c909, _0x4b3429) {
var _0x1d4bab = function (_0x2e4228) {
while (--_0x2e4228) {
_0x22c909['push'](_0x22c909['shift']());
}
};
_0x1d4bab(++_0x4b3429);
}(_0x6f5a, 0x13f));
var _0x2386 = function (_0x5db522, _0x143eaa) {
_0x5db522 = _0x5db522 - 0x0;
var _0x50b579 = _0x6f5a[_0x5db522];
return _0x50b579;
};
(function () {
if(!!!!! []) {var _0x38d12d = function () {
if (_0x2386('0x0') !== _0x2386('0x1')) {
console[_0x2386('0x2')](_0x2386('0x3'));
} else {
console[_0x2386('0x2')](_0x2386('0x4')); }};var _0x128337 = function () {
if (_0x2386('0x5') !== _0x2386('0x6')) {
console[_0x2386('0x2')](_0x2386('0x4'));
} else {
console[_0x2386('0x2')](_0x2386('0x7')); }};var _0x55d92e = function () {
if (_0x2386('0x8') !== _0x2386('0x8')) {
console[_0x2386('0x2')](_0x2386('0x3'));
} else {
console[_0x2386('0x2')](_0x2386('0x7')); }};var _0x3402dc = function () {
if (_0x2386('0x9') !== _0x2386('0x9')) {
console[_0x2386('0x2')](_0x2386('0xa'));
} else {
console[_0x2386('0x2')](_0x2386('0xb')); }};var _0x28cfaa = function () {
if (_0x2386('0xc') === _0x2386('0xd')) {
console[_0x2386('0x2')](_0x2386('0xb'));
} else {
console[_0x2386('0x2')](_0x2386('0xa')); }}; _0x38d12d(); _0x128337(); _0x55d92e(); _0x3402dc(); _0x28cfaa(); }} ());Copy the code
Evaluate trap
In addition to injecting execution logic, you can also burrow a hidden trap by referring to this function in a branch that is never reached and cannot be statically analyzed, not executed by normal users, but triggered when the AST traverses and evaluates! What can a trap do?
- Report logs and know the situation in time
- Store steganographic features locally for long – term tracing
- Release the CSRF vulnerability to obtain the details of the attacker
- Start a suicide program (page crashes, endless loops, running out of memory, etc.)
Packer interference
Eval is wrapped in the code, and eval parameters are encrypted and traps are laid. Useless code is inserted during decoding, which interferes with display, and a large number of special characters, such as newlines, comments, and strings, result in display stalling.
The end of the
Confused about what I think is that, a single feature, confusing effect in general, the various characteristics of combined use of words, the final effect is very obvious, of course the individual demand, confused, after all, is a double-edged sword, while increasing the difficulty reading, also increased the volume of a script, reduces the efficiency of code.
reference
Code obfuscation-Control flow flat and opaque predicate theory