📜 ⬆️ ⬇️

Hiding, obfuscating and crypting the client side of web applications

Obfuscation is the reduction of the source code of a program to a form that preserves its functionality, but complicates the analysis, understanding of the operation algorithms and modification during decompilation. For JavaScript, this technology is used in such types of online shadow business as downloads (iframe), spam and SEO. Our task for today is to study all the methods of hiding the JS-code, which I hope you will use only for the good.

Obfuscated script


Theory


First, we will answer some questions for ourselves:
1. What are we going to hide?
We will hide only the client part of the web-applications, that is, what eventually a regular user will download to his computer.
The following technologies can be attributed to this type:2. From whom to hide? It’s reasonable to hide all this information from:3. How can you be sure of hidden information security?
Sure can not be.
Why? Because all the information that the user loads is still performed by the browser. This means that even if the information is encrypted / hidden in a very complex way, it will not mean that your code cannot be read. Read it will be possible in any case, you can only make it difficult to read. We will talk about these methods of difficulty.
4. How is the crypto / obfuscation process in principle?
There are two different stages: the creation of obfuscated / encrypted code and its decryption for normal execution by the browser. We will generate the obfuscated code with the help of PHP scripts, although this can be done with the help of anything. But decoding the execution of the code you need to write in JavaScript: in this case, the script, in fact, decrypts and executes itself.

JJEncode work


Basic HTML / CSS Encryption


What if we need to encrypt HTML or CSS code? It's simple: encrypt in JavaScript, and after decryption insert as HTML code.
Insert example (no encryption / crypt / obfuscation):

<html> <script> var html = '<center><h3> -</h3></center>'; //    "html" ,    document.getElementsByTagName('html')[0].innerHTML = html; //    <html>  </html> </script> </html> 

We will do the same with CSS styles:
')
 <html><script> var css = 'body{margin:0px;}.subcl{padding:5px;}'; //    "css" ,    document.getElementsByTagName('html')[0].innerHTML = '<style>'+css+'</style>'; //    <html>  </html> </script> </html> 

Now we will try to abstract from HTML and CSS and talk only about the essence - first, hide and then JavaScript encryption.
Before anyone wants to see and decipher our code, he will try to find it. Below you will find some effective methods of hiding the code from the eyes of curious users.

Hide the word "] [akep" in the body of the document


Replacing the attributes of the tag <script>


Everything is very simple, but this cannot be considered a good or even medium defense, as it is focused on the carelessness of users.
The principle itself is utterly simple. We have a page (“index.html”) and a JavaScript file whose code we want to hide (“script.js”). On the page "index.html" we have indicated:

 <script type="text/javascript" src="./script.js"></script> 

And now just create a folder "text", in which we put our script ("script.js") under the name "javascript" and swap attributes. It will look like this:

 <script src="text/javascript" type="./script.js"></script> 

For the best effect, we will immediately divert the user's attention to the path. For example:

 <script src="text/javascript" type="http://host.com/////////script.js"></script> 

Tested on personal experience: works fine! In this way, I myself wound the affiliate program on clicks, as I had to use a twist on JavaScript. The administration of the affiliate program never saw him :).

Javascript handlers


This method is also not a universal means for hiding the JS-code, but still I will talk about it. The main idea is to hide the code inside onLoad, onClick, etc. event handlers. That is, approximately in the following constructions:

 <body onLoad="alert(1);"></body> <textarea onClick="alert(1);"></textarea> 

For example, for the body and frameset tags there is an onLoad handler that will run the prescribed code in it after the page / frame is loaded.
I note that not all objects handlers are the same.

Cookie, Referrer and Address


JavaScript can also be hidden in such non-standard places as a cookie (document.cookie), a referrer (document.referrer) and a page address (location.href). In this case, the code will be stored as plain text, and executed using the eval () function, which takes the text as an argument and executes it as JavaScript code.
As an example, we will accept the following assumption that we already have the following cookies:

 cookievalue=||alert(1);|| 

Now execute this alert as follows:

 <script>eval(unescape(document.cookie).split("||")[1]);</script> 

Here we take the text of all the cookie-records for our host and divide it into parts in places where there is a “||”. Then we take the second element ([1]) and run it through eval ().
This method is not so bad, because the code that we want to execute is not visible on the page itself, and also because we can force the code to delete itself! Example of implementation:

 <?php //    JavaScript- +   (  123) setcookie('cook', '||alert(1);document.cookie="cook=123";||'); ?> <script> //    . eval(unescape(document.cookie).split('||')[1]); </script> 

Similarly, you can use other strings available via JavaScript, such as location.href and document.referrer.

Ajax code hiding


In this case, the code will be in a separate file, and its launch will be carried out by reading this file and executing its contents with the eval () function.
We will need to create a page with hidden code, as well as a page with the function to run this code:
  1. The page with the code that we want to hide (with the name "l"):
     alert(1); 
  2. Code calling page:
     <script>function x(){try{return new XMLHttpRequest();}catch(e){try{return new ActiveXObject('Msxml2.XMLHTTP');}catch(e){try{return new ActiveXObject('Microsoft.XMLHTTP');}catch(e){return null;}}}};function y(){var z=x();if(z){z.open('get','./l');z.onreadystatechange=function(){if(z.readyState==4){ eval(z.responseText);}};z.send(null);}};y();</script> 
This method hides the code in a separate file (in our case "l"). Of course, you can find the path of the file and open it, but when obfuscating such a code, finding the file name is quite difficult.

Nullbyte attacks Opera


This method is simple and effective enough, but, unfortunately, it is designed only for the Opera browser. The essence of the method is to put the so-called nullbyte before the hidden code (nullbyte or nullbyte is a character with the ASCII code “0”). What for? Then, that Opera simply does not show the code in the built-in viewer after this symbol. Example:

 <html> - </html> <?php echo(chr(0)); ?> <script>alert(1); /*     */</script> 

In this example, first comes the normal code, which we do not need to hide. Then, using PHP, we insert a null byte, and after it comes the hidden code.

Hiding in the HTML code and comments


The code can be easily hidden in HTML, then processed and executed. For example, like this:

 <body><img src="./pict.jpg" a="al" b="er" c="t(1);"></body> <script>a = document.body.innerHTML; eval(a.split('a="')[1].split('"')[0]+a.split('b="')[1].split('"')[0]+a.split(' c="')[1].split('"')[0]);</script> 

In this case, we hid the code in the attributes of the img tag, and then processed the code of the entire page, collecting scattered pieces. In the same way, you can hide text in HTML / JavaScript comments:

   HTML: <!-- alert(1); -->   JavaScript: // alert(1); /* alert(1); */ 

Separately, it is worth noting that it is very effective to hide the code inside popular frameworks - for example, jQuery, mooTools and the like. These files are not suspicious, and their research will take a long time (although there is always the possibility of automatic comparison of the original and the modified file).
Now, I think, we can talk about what the security expert sees, after all, and about what antiviruses are researching. Below read about the most popular methods of encrypting and obfuscation of JS-code.

Substitution of standard JavaScript functions / methods


This method is intended to substitute its own variables instead of standard JavaScript functions or methods:

  : <script>document.getElementsByTagName("html")[0].innerHTML = document.getElementsByTagName("body")[0].length;</script>  : <script>a=document;c='getElementsByTagName';a[c]("html").innerHTML = a[c]("body")[0].innerHTML.length;</script> 

In this case, we replaced the “document” object with the variable “a”, and the getElementsByTagName method replaced the variable “c”. It should be noted that methods (what starts with a dot, for example, .length or .getElementsByTagName) can also be replaced by defining a key in an array (if we consider an object as an array). If we have a document object, and there is a getElementsByTagName element in it, this means that we can call it in two ways:
  1. document.getElementsByTagName
  2. document['getElementsByTagName']
From this it follows that in the second method we use string data (“getElementsByTagName”), therefore, they can be replaced with a variable containing a string - the name of the method.
The substitution is useful in the case of frequent use of the same standard object / function / variable. This greatly changes the code, and also compresses it.

Flood comments and code


This method is designed to insert in obfusciable code flood, that is, something that does not carry the semantic load for the script code. Flood can be both code and comments:

  : <script>/* pOIEPGpmkG13Pg */ a /* PGpmkG13Pggweg */ = /* mkG13Pg */ 'hahaha' /* pOIE13Pg */ ; /* wegEGoh */ alert /* oiwboierhper */ ( /* igwepreorh */ a /* wbnponrhR */ ) /* inboierh */ ; /* roinero */</script>  : <script> weoibog = 'gwrobgoerh'; a = 'hahaha'; bfionb = 'wgeogioweg'; alert(a); 

In this case, the flood comments are too dense, although in fact the code was very simple: “ a = "hahaha"; alert(a); a = "hahaha"; alert(a); ".
Flood code can also interfere with flooding comments. If you wish, you can write a PHP function to add flooding to the JavaScript code. Personally, I took some article from an English blog, parsed words, and the function added a random number of these words in the comments.
By the way, it is also desirable to use multi-line comments in the form of a “fake close”:

 /*/ alert(1); /*/ alert(2); /*/ alert(3); /*/ 

Which number will show the alert? :)

Obfuscated Alert Job


Replacing text with hexadecimal codes


I wanted to refer to this paragraph and some other ways to convert the text, but left only this one, since this is the only encryption method that does not require help functions to decrypt:

 <script> alert(document["\x63\x6F\x6F\x6B\x69\x65"]); </script> 

In this case, we firstly used the internal variable “cookie” of the “document” object as an element of the array. Secondly, we translated its name in hexadecimal format. If we used the cookie variable through a dot, that is, as document.cookie, we would not be able to translate the call to it in hexadecimal format, since this applies only to strings (in the array, the key is a string), and in document. no cookie strings.
PHP translation function in hexadecimal format:

 <?php function cescape($s) { foreach (str_split($s,1) as $sym) { $d = dechex(ord($sym)); $c[] = (strlen($d) == 1) ? '0'.$d : $d; } return (''.'\\'.implode(''.'\\',$c)); } ?> 

The trick with non-existent features


As we already know from the above, in JavaScript, you can call methods as elements of the object: document.getElementById and document ['getElementById']. Both options are actually the same, the only difference is in the record - in the second version we use the string.
One evening I came up with a very interesting way to get these lines. For example, we need to encrypt the above-mentioned “getElementById”. Let us take a look at a short explanation of this method using the following example:

 <script> a = b(c(d())); </script> 

This script will not work because the b, c, and d functions have not been previously declared. Now we will try to make this code work, for this we will use the sandbox of the try {} catch () {} structure:

 <script> try{a = b(c(d()))}catch(e){alert(e);} </script> 

After the launch, we will see an error, which means that, although the code is not working, it did not stop the execution of the remaining correct part.
And now we ask ourselves how such a scheme can be associated with the encryption of the string “getElementById”? That's how:

 <script>try{(getE(leme(ntB(yId()))))}catch(e){x = (e+'').split('(').slice(1,5).join('');}</script> 

After executing this code, we get the string “getElementById” contained in the variable “x”.
What is the salt of this method? The fact that the heuristic analysis of antiviruses when finding functions will swear that they do not exist. Thus, we obfuscate the code not at the level of encryption of strings in different ways, but at the level of receiving data strings from JavaScript itself.

Numbers using the operator "~"


The operator "~" (tilde) is a bit negative and is used like this: "alert (~ 13);". This code will bring us "-14". This operator works by the principle “- (number + 1)”.
Imagine that we want to assign a number to a variable, and nowhere to write this number: “a = ~ []”;
This code will assign the number “-1” to the variable “a”. Why? Because the array is a neutral element with a numeric value of "0", therefore, ~ 0 is equivalent to "- (0 + 1)", that is -1.
Examples of other transformations:

 a = ~[]; // -1 a = -~[]; // 1 a = []^[]; // 0 a = ~~[]; // 0 a = ~true; // -2 a = ~false; // -1 a = -~[]*(""+-~[]+-~-~-~-~-~[]+-~-~true); // 153 

Letters and strings without string data


Sometimes you want to get a letter / character or some text without writing it explicitly. One JavaScript feature allows you to do this. In this language, there are various internal system messages that can be converted to text, and then this text processed.
For example, imagine that we need to get the text “code”. This string is contained in the names of methods such as charCodeAt (), fromCharCode (), and others. You can get the text as follows:

 a = (alert+'').split("ive ")[1].substr(0,4); 

In this example, the variable "a" will contain the text "code". We will analyze in more detail. Try to execute the following code: "alert (alert +"); ". You will see something like "function alert () {[native code]}". Thus, using only the alert () function twice, we got completely different characters.
Now we will try to understand how this all works. Imagine that every object, function, and everything else in JavaScript has a certain “description”. To access it, you need to explicitly change the type of this object or function to a string, attaching, for example, an empty string (+ "").

String encryption


There are several useful functions for encrypting / decrypting strings in JavaScript. Let us examine some of them:

 escape(); //    URL unescape(); //  URL- encodeURI(); //    URI decodeURI(); //  URI- 

There are also two String object methods that work with converting a character to ASCII code and vice versa:

 a = String.fromCharCode(97); b = "b".charCodeAt(); 

It should be noted that strings can also be converted with regular expressions in combination with the .match and .replace methods. Other methods can be attributed, rather, to search by string.

Object / Variable Conversion


The names of objects and variables can also be converted to a string (for example, in order to encrypt this string later). Conversion takes place on the same principle as the conversion of method names, that is, by moving from the form “.method” to the form “[method]”. For the correct conversion, you need to find an element that is even higher in the object hierarchy and that has the word “document” inside it. His name is this. According to JavaScript standards, this is not an object, but an operator that returns a reference to an object. As a result, we can now safely use getElementById as follows: “this [“ document ”] [“ getElementById ”]”.

Code binding


Sometimes it is necessary to write code so that it is executed only after certain conditions are met. For example, we created JavaScript code and want to sell it, but we want to sell it with a domain binding so that it cannot be run on other sites.
I repeat: no absolute protection can be invented in principle, there are only some ways that make the copying / decoupling difficult.
Here are several types of such bindings + the data on which they depend:

Avoiding Suspicious Functions


I also advise you to avoid using eval (), document.write (), and others explicitly. When searching for a real code, people often use the alert () substitution method instead of these functions, since after that the code can be read the way we began to encrypt it, therefore, the whole point of obfuscation disappears. How to execute the code without using the eval () function?
Recall the fact that at the head of everything is the operator this. Using it, the eval () function can be turned into this code:

 a = this["\x65\x76\x61\x6C"]; 

After this conversion, we can safely use “a ()” instead of “eval ()”.

Change to unreadable lines


In the obfuscated code, the following symbols and their combinations should be used to denote identifiers:
  1. "o", "O", "0"
  2. "i", "I", "l", "1"
  3. "_" (and options "__" , "___" ...)
  4. "$" (and options "$$" , "$$$" ...)
After using these characters, the code becomes extremely difficult to read, especially if you squeeze it, removing extra spaces and line breaks.

Code encryption


There are an unlimited number of ways to encrypt text, although they are all based on the use of any text / numeric functions. The construction often works: eval () + decryption function () + encrypted_string. I will try to show one of such methods without any extra water.
Suppose we need to encrypt the string "alert (1);". It occurred to me to take two characters from it, translate them into numbers (ASCII code), read them and put the first character next to it in a clean (without translation) form. Only it is worth considering that, dividing the code into such two-letter parts, we get the code about 2-2.5 times the original, and we must not forget that it is better to somehow divide such blocks (as an element of an array or through a separator). For the separator, we take the “%” sign, since it makes the encrypted string look like a URL string. Let's write a simple PHP script:

 <?php $a = "alert(1);"; $a = str_split($a, 2); $e = ''; foreach ($a as $v) { $e .= '%' . $v[0] . (ord($v[0])+ord($v[1])); } echo($e); ?> 

This is what we got: " %a205%e215%t156%190%;59 ".
And now we will write the code interpreter of this code in JavaScript:

 function d(s) { s = s.split('%').slice(1); c = ''; for (i = 0; i < s.length; i++) { c += s[0] + String.fromCharCode(s.substr(1)-s[0].charCodeAt()); } return c; } 

Calling the code in this case will look like this: "eval (d ('% a205% e215% t156% 190%; 59'));".

Now it only remains to obfuscate the whole of this script. We will not use all the methods described, but will only touch on some of them:

 z = '73706C697421736C696365216C656E6774682166726F6D43686172436F6465217375627374722163686172436F64654174'; _=''; for(__=0;__<z.length/2;__++){_+=unescape('%'+z[__*2]+z[__*2+1]);} _=_[_[0]+_[1]+_[2]+_[3]+_[4]]('!');function ___(__){__ = __[_[0]]('\x25')[_[1]](-~[]); _I='';for (_l=0;_l<__[_[2]];_l++){_I+=__[_l][0]+String[_[3]](__[_l][_[4]](1)-__[_l][0][_[5]]());}return _I;} this['\x65\x76\x61\x6C'](___('%a205%e215%t156%190%;59')); 

Let us take a closer look at the process of how this seemingly unreadable code works:
  1. z = '....' Here the variable is assigned the text that was obtained by translating the string split! slice! length! fromCharCode! substr! charCodeAt into hexadecimal form (\ x73 \ x70 \ x6C \ x69 \ x74 ...) without "\ x ";
  2. _='';for(...} Here we translate split! slice! length! fromCharCode! substr! charCodeAt into the variable "_";
  3. _=_...('!'); We divide the line in those places where there is a symbol "!";
  4. function ___(__){...} The d () function described above is obfuscated;
  5. this['\x65\x76\x61\x6C'](....); Decode line and run code.

At last


Well, let's summarize. With a combination of all these methods, you can be 100% sure that a simple or even average user will not be able to read or copy your code to yourself. But since computer security experts are well aware of most of these tricks, and also because I post this information for everyone to see, I can assume that these methods will become more popular and well-known. I hope you can use the information provided for good purposes.

Making the script readable



image
Hacker Magazine, September (09) 152
| qbz | (lopuxin.iv@yandex.ru, http://essenzo.net ) .

Subscribe to "Hacker"

Source: https://habr.com/ru/post/128741/


All Articles