01. Version check
02. Install the program
03. Create a sample
04. Add some code
Worker.js starts out with a string variable. They are a classic attack target – if a ROM is to be decoded, the assembler usually starts out by looking for tables containing string sequences. Furthermore, encryption is performed using a set of variables with very 'speaking' names.
05. Implement the encryption
As this is not intended as an encryption 101, we should settle on a comparatively simple substitution cipher. ROT13 is not difficult, but it can be programmed quite verbosely. Dsoares' implementation comes with a set of 'speaking' variables and provides lots of food for our obfuscator.
06. First obfuscation
07. Redirect output
08. Analyse the results
Dive into the 'obfusca' folder and open the new version of worker.js to feast your eyes on the abomination that is shown accompanying this step. The code's formatting was mangled badly. Method names, however, remained the same, as they are needed for external invocations. Furthermore, strings now sit in an array where an attacker can harvest them conveniently.
09. Prevent string harvesting
10. Look at the results again
At this point, our obfuscator's output looks different – the array at the top of the file now is much less readable. This, however, does not solve all problems. If you perform a few obfuscation cycles, you will eventually end up with mark-up similar to the one accompanying this step:
11. Understanding randomisation
Obfuscators work in a pressure field between high performance and code protection. One way to address the problem involves 'randomising' elements. The runtime-expensive obfuscations are not added to all nodes, but only to a subset. Detecting if nodes are affected or not is usually done via a random number generator, whose sensitivity can be tuned.
12. Go after strings
The above-mentioned random number generator emits numbers ranging from zero to one. If the number is larger than the threshold, the modification will not take place. Setting stringArrayThreshold to a value of one means that all numbers are smaller than the threshold, ensuring that each and every string gets mangled.
13. Inject random code
14. Enjoy the chaos
15. Aggressively modify program flow
Breaking code into an AST allows for deep transformations. Setting the controlFlowFlattening attribute to true tells the program that it can de-inline function calls. This leads to a significant expansion of the generated code – keep in mind that the results can take a 150 per cent performance hit.
16. Annoy the debugger
Artefacts from debugging are the world's greatest gift to hackers. A few calls to console.log() and its friends can give an attacker valuable information on what happens inside the program – a good example would be the snippet shown:
17. Evaluate technical problems
We can attempt to re-obfuscate the program with the command below. It disables the string caching feature and should disable console logging via redirection.
18. Play cat and mouse games
Obfuscator and browser vendors fight a long and bitter battle about the debugger function. Due to this, 'aggressive' measures, such as console redirection of the program flow interruptors shown accompanying this step, usually don't work for long.
19. Quick online obfuscation
Installing the entire Node.js package for obfuscating one or two files is pointless. Visit obfuscator.io to access an online version of the program that lives in your browser. Check and comboboxes below the main input let you modify program behaviour as outlined in the steps above.
20. Learn more
The developer team maintains relatively detailed documentation explaining the way the various command line parameters interact with one another. Simply visit head here if the 'short help' output shown above does not help you reach your goal.
21. An obfuscator's mortal enemy
The ETH Zurich provides a de-obfuscation service hosted at jsnice.org. It uses neural networks and a knowledge database made up of existing code to determine variable names. While sprucing up the formatting usually works pretty well, some of the names – such as pixelSizeTargetMax in the encryption routine accompanying this step – can be rather amusing.