DEV Community

WangLiwen
WangLiwen

Posted on • Edited on

JavaScript Magic Tricks: Invalid breakpoint

Under normal conditions, JavaScript code can be breakpointed in a runtime environment, for example:

<html>
<script>
var array = ["JShaman","javascript","Obfuscator"];
for(i=0 ;i< array.length; i++){
    console.log(array[i]);
}
</script>
</html>
Enter fullscreen mode Exit fullscreen mode

Image description

But do you know that there are some techniques in JS programming that can effectively make breakpoints useless? For example, by rewriting the code above as:

<html>
<script>
var array = ["JShaman","javascript","Obfuscator"];
array.forEach(console.log);
</script>
</html>
Enter fullscreen mode Exit fullscreen mode

If you set a breakpoint and run it at this time, you will find that: the breakpoint will only occur inside forEach, but console.log will not be interrupted:

Image description

This method also applies in Node.JS and Visual Studio Code environments, as shown in the following two figures:

Image description

Image description

Another example:

<html>
<script>
    window.onclick = function() {
        document.bgColor = "#ccc";
    }
</script>
</html>
Enter fullscreen mode Exit fullscreen mode

This code snippet is used to set the background color of a webpage with document.bgColor = "#ccc";. This line of code can be set as a breakpoint. If you do not want it to be interrupted by a breakpoint, you can modify the code to the following format:

<html>
<script>
window.onclick = Object.getOwnPropertyDescriptor(Document.prototype, "bgColor").set.bind(document, "#ccc");
</script>
</html>
Enter fullscreen mode Exit fullscreen mode

Object.getOwnPropertyDescriptor() is a method added to the Object object in the ES6 specification, allowing the retrieval of a descriptor for a specified property of an object. The method takes two parameters: the first is the object that contains the property, and the second is the name of the property. It returns an object. In the code mentioned above, it is used to retrieve the descriptor of the bgColor property in the document and bind it to an onclick event. When the onclick event is triggered, it will set the background color, but the set.bind(document, "#ccc") operation will not be paused by a breakpoint, and breakpoints are ineffective on it.

Another example:

<html>
<script>
    var obj = {
        name : "tom"
    };
    obj.name = "ais";
    console.log(obj);
</script>
</html>
Enter fullscreen mode Exit fullscreen mode

If you do not want the breakpoint to be set for the statement obj.name = "ais" that assigns a value to name, you can make the following adjustments:
Change to:

Reflect.apply(Reflect.set, null, [obj, “name”, “ais”]);
Enter fullscreen mode Exit fullscreen mode

Reflect is a new API provided in ES6 for object manipulation, which offers methods to intercept JavaScript operations:
Reflect.apply(target, thisArg, args), the apply method calls a function with a given this value and an array of arguments. The code snippet above is equivalent to obj.name = "ais".
However, breakpoints can still be set here, and the bind method can be used further:
Reflect.apply.bind(null, Reflect.set, null, [obj, "name", "aix"]);

Finally:


<html>
<script>
    var obj = {
        name : "tom"
    };
    window.onclick= Reflect.apply.bind(null, Reflect.set, null, [obj, "name", "aix"]);
    console.log(obj);
</script>
</html>
Enter fullscreen mode Exit fullscreen mode

At this point, a breakpoint can be set on the line with Reflect.apply.bind, but the execution will not pause or interrupt when window.onclick is triggered.

Image description

This method can be used to protect the code that is most afraid of debugging in certain situations.
Furthermore, if the code modified using this method is then obfuscated and encrypted, it may even be impossible to locate the location of the breakpoint. As shown in the following image, encrypting the preceding code with JS-Obfuscator will result in the following form

<html>
<script>
    function _0x4bfaa1(_0x4f04df,_0x46ffc7,_0x157578,_0x297168,_0x5a371e){return _0x497c(_0x46ffc7- -0x1f8,_0x297168);}function _0x40ba00(_0x265865,_0x51dc79,_0x267b51,_0x3b1913,_0x2ac5f5){return _0x497c(_0x267b51-0xcc,_0x3b1913);}(function(_0x15f460,_0x18170b){function _0x3440c3(_0x3f98c7,_0x197e80,_0x48af91,_0x537374,_0x4fa527){return _0x497c(_0x48af91-0x2d6,_0x197e80);}var _0x40fdd0=_0x15f460();function _0xc97ade(_0x1c2d14,_0x273c74,_0x2d7a20,_0x2347d2,_0x4fe5df){return _0x497c(_0x2d7a20-0x2b5,_0x4fe5df);}function _0x551607(_0x3e01fd,_0x110b1d,_0x2eeec9,_0x17b1d5,_0x145826){return _0x497c(_0x3e01fd- -0x22d,_0x110b1d);}function _0xa1f138(_0x387226,_0x1f0366,_0x1b6130,_0xb0bfb3,_0x2b254a){return _0x497c(_0x2b254a- -0x2b1,_0x1f0366);}function _0x486f8e(_0x173deb,_0x592ea4,_0xb13e25,_0xb03b2e,_0x14e4f9){return _0x497c(_0xb13e25- -0x3bb,_0xb03b2e);}while(!![]){try{var _0x2d2b91=parseInt(_0x551607(-0x22a,-0x227,-0x229,-0x22b,-0x221))/0x1+-parseInt(_0xc97ade(0x2be,0x2c4,0x2c6,0x2bf,0x2c4))/0x2*(-parseInt(_0xc97ade(0x2b9,0x2ad,0x2b5,0x2b9,0x2b0))/0x3)+parseInt(_0xa1f138(-0x2a4,-0x2ab,-0x2af,-0x2af,-0x2aa))/0x4+-parseInt(_0x3440c3(0x2e2,0x2e1,0x2e3,0x2e3,0x2e5))/0x5+parseInt(_0x3440c3(0x2d7,0x2d8,0x2e0,0x2da,0x2e6))/0x6+-parseInt(_0xc97ade(0x2bc,0x2bb,0x2ba,0x2b4,0x2b3))/0x7*(parseInt(_0xa1f138(-0x2ab,-0x2a7,-0x2a9,-0x2a3,-0x2a2))/0x8)+-parseInt(_0x3440c3(0x2de,0x2e1,0x2e4,0x2ec,0x2dd))/0x9*(-parseInt(_0x486f8e(-0x3be,-0x3b6,-0x3b7,-0x3be,-0x3b0))/0xa);if(_0x2d2b91===_0x18170b){break;}else{_0x40fdd0["\u0070\u0075\u0073\u0068"](_0x40fdd0["\u0073\u0068\u0069\u0066\u0074"]());}}catch(_0x45ceea){_0x40fdd0["\u0070\u0075\u0073\u0068"](_0x40fdd0["\u0073\u0068\u0069\u0066\u0074"]());}}})(_0x5a63,0x95c8c);function _0x5a63(){var _0x45b434=["\u0034\u0031\u0035\u0030\u0031\u0039\u0032\u0050\u0043\u0065\u0050\u0050\u0054","\u006c\u006f\u0067","dnib".split("").reverse().join(""),"\u0031\u0032\u0034\u0038\u0031\u0032\u0036\u0079\u0065\u0069\u004c\u0048\u0066","eman".split("").reverse().join(""),"\u0061\u0069\u0078","WrBRpq0878165".split("").reverse().join(""),"yxfsXT01521".split("").reverse().join(""),"\u0032\u0033\u0032\u0078\u0062\u004a\u0069\u0067\u0058","\u0061\u0070\u0070\u006c\u0079","GvgsnD41".split("").reverse().join(""),"LoNwch907911".split("").reverse().join(""),"mot".split("").reverse().join(""),"kcilcno".split("").reverse().join(""),"thpllB6243101".split("").reverse().join(""),"szBFSp023".split("").reverse().join(""),"pytQaz290402".split("").reverse().join(""),"tes".split("").reverse().join("")];_0x5a63=function(){return _0x45b434;};return _0x5a63();}var _0xc=0x4+0x1;var obj={"\u006e\u0061\u006d\u0065":_0x4bfaa1(-0x1f1,-0x1f7,-0x1f6,-0x1f8,-0x1f5)};_0xc=0x2+0x7;function _0x7b3856(_0x298c79,_0x37904f,_0x2e5981,_0x37e404,_0x363429){return _0x497c(_0x37e404-0x250,_0x363429);}function _0x497c(_0x2e43ba,_0x5a63b9){var _0x497cff=_0x5a63();_0x497c=function(_0x6145ca,_0x364243){_0x6145ca=_0x6145ca-0x0;var _0x46f7f9=_0x497cff[_0x6145ca];return _0x46f7f9;};return _0x497c(_0x2e43ba,_0x5a63b9);}window["\u006f\u006e\u0063\u006c\u0069\u0063\u006b"]=Reflect["\u0061\u0070\u0070\u006c\u0079"]["\u0062\u0069\u006e\u0064"](null,Reflect["\u0073\u0065\u0074"],null,[obj,_0x7b3856(0x25b,0x261,0x257,0x25b,0x25a),_0x7b3856(0x259,0x253,0x25c,0x25c,0x257)]);console["\u006c\u006f\u0067"](obj);
</script>
</html>

Enter fullscreen mode Exit fullscreen mode

Image description

Top comments (0)