快捷搜索:

您的位置:金莎娱乐 > 互联网 > 这段js代码得拯救你多少时间,反调试技巧

这段js代码得拯救你多少时间,反调试技巧

发布时间:2019-10-30 08:24编辑:互联网浏览(51)

    原标题:JavaScript 反调试技巧

     

    写在前面的话:

    1.应用案例:

    在此之前,我一直都在研究Java相关的反调试技巧。但是当我在网上搜索相关资料时,我发现网上并没有多少关于这方面的文章,而且就算有也是非常不完整的那种。所以在这篇文章中,我打算跟大家总结一下关于Java反调试技巧方面的内容。值得一提的是,其中有些方法已经被网络犯罪分子广泛应用到恶意软件之中了。

      

    澳门金莎 1

            var Mouse = function () {

    对于Java来说,你只需要花一点时间进行调试和分析,你就能够了解到Java代码段的功能逻辑。而我们所要讨论的内容,可以给那些想要分析你Java代码的人增加一定的难度。不过我们的技术跟代码混淆无关,我们主要针对的是如何给代码主动调试增加困难。

                // Look! no that = this!

    本文所要介绍的技术方法大致如下:

                this.position = [0, 0];

    1. 检测未知的执行环境(我们的代码只想在浏览器中被执行);

                if (document.addEventListener) {

    1. 检测调试工具(例如DevTools);

    2. 代码完整性控制;

    3. 流完整性控制;

    4. 反模拟;

                    document.addEventListener('mousemove', ?);   //this.move?  

    简而言之,如果我们检测到了“不正常”的情况,程序的运行流程将会改变,并跳转到伪造的代码块,并“隐藏”真正的功能代码。

                } else if (document.attachEvent) {

    一、函数重定义

                    document.attachEvent("onmousemove", ?);     //this.move?怎么放进去

    这是一种最基本也是最常用的代码反调试技术了。在Java中,我们可以对用于收集信息的函数进行重定义。比如说,console.log()函数可以用来收集函数和变量等信息,并将其显示在控制台中。如果我们重新定义了这个函数,我们就可以修改它的行为,并隐藏特定信息或显示伪造的信息。

                }

    我们可以直接在DevTools中运行这个函数来了解其功能:

     

    console.log("HelloWorld");

    varfake= function(){};

    window['console']['log']= fake;

    console.log("Youcan't see me!");

            };

    运行后我们将会看到:

            Mouse.prototype.move = function (arg1,arg2,event) {

    VM48:1 Hello World

                event = window.event || event;

    你会发现第二条信息并没有显示,因为我们重新定义了这个函数,即“禁用”了它原本的功能。但是我们也可以让它显示伪造的信息。比如说这样:

                var x = event.pageX || event.offsetX,

    console.log("Normalfunction");

    //First we save a reference to the original console.log function

    varoriginal= window['console']['log'];

    //Next we create our fake function

    //Basicly we check the argument and if match we call original function with otherparam.

    // If there is no match pass the argument to the original function

    varfake= function(argument){

    if(argument=== "Ka0labs"){

    original("Spoofed!");

    }else{

    original(argument);

    }

    }

    // We redefine now console.log as our fake function

    window['console']['log']= fake;

    //Then we call console.log with any argument

    console.log("Thisis unaltered");

    //Now we should see other text in console different to "Ka0labs"

    console.log("Ka0labs");

    //Aaaand everything still OK

    console.log("Byebye!");

            y = event.pageY || event.offsetY;

    如果一切正常的话:

                this.position = position = [x, y];

    Normal function

    VM117:11Thisisunaltered

    VM117:9Spoofed!

    VM117:11Bye bye!

                this.log(arg1,arg2);

    实际上,为了控制代码的执行方式,我们还能够以更加聪明的方式来修改函数的功能。比如说,我们可以基于上述代码来构建一个代码段,并重定义eval函数。我们可以把Java代码传递给eval函数,接下来代码将会被计算并执行。如果我们重定义了这个函数,我们就可以运行不同的代码了:

            };

    //Just a normal eval

    澳门金莎,eval("console.log('1337')");

    //Now we repat the process...

    varoriginal= eval;

    varfake= function(argument){

    // If the code to be evaluated contains1337...

    style="font-size: 16px;">if(argument.indexOf("1337")!==-1){

    // ... we just execute a different code

    original("for (i = 0; i < 10;i ) { console.log(i);}");

    }

    else{

    original(argument);

    }

    }

    eval= fake;

    eval("console.log('Weshould see this...')");

    //Now we should see the execution of a for loop instead of what is expected

    eval("console.log('Too1337 for you!')");

            Mouse.prototype.log = function (arg1, arg2) {

    运行结果如下:

                console.log(arg1 "," arg2);

    1337

    VM146:1Weshould see this…

    VM147:10

    VM147:11

    VM147:12

    VM147:13

    VM147:14

    VM147:15

    VM147:16

    VM147:17

    VM147:18

    VM147:19

                console.log(this.position);

    正如之前所说的那样,虽然这种方法非常巧妙,但这也是一种非常基础和常见的方法,所以比较容易被检测到。

            };

    二、断点

            new Mouse();

    为了帮助我们了解代码的功能,Java调试工具(例如DevTools)都可以通过设置断点的方式阻止脚本代码执行,而断点也是代码调试中最基本的了。

    www.2cto.com

    如果你研究过调试器或者x86架构,你可能会比较熟悉0xCC指令。在Java中,我们有一个名叫debugger的类似指令。当我们在代码中声明了debugger函数后,脚本代码将会在debugger指令这里停止运行。比如说:

    上面你知道'?'号那里要干嘛了吗?我想给document的mousemove绑定我的move方法,但是遇到难题了,这样的话,Mouse.prototype.move

    console.log("Seeme!");

    debugger;

    console.log("Seeme!");

    里的this就不会指向Mouse的对象,相信大家经常碰到这种问题.也许你早知道了怎么解决,但是有更快更简单的方法吗?答案是:

    很多商业产品会在代码中定义一个无限循环的debugger指令,不过某些浏览器会屏蔽这种代码,而有些则不会。这种方法的主要目的就是让那些想要调试你代码的人感到厌烦,因为无限循环意味着代码会不断地弹出窗口来询问你是否要继续运行脚本代码:

      Function.prototype.bind()这个神奇的玩意,但是ie6 7 8都不支持,一般现代浏览器都支持了,我们接下来要做的就是模仿他,

    setTimeout(function(){while (true) {eval("debugger")

     这么好的方法当然要模仿它,怎么模仿见下面nothing的原创方法

    三、时间差异

        (function () {

    这是一种从传统反逆向技术那里借鉴过来的基于时间的反调试技巧。当脚本在DevTools等工具环境下执行时,运行速度会非常慢(时间久),所以我们就可以根据运行时间来判断脚本当前是否正在被调试。比如说,我们可以通过测量代码中两个设置点之间的运行时间,然后用这个值作为参考,如果运行时间超过这个值,说明脚本当前在调试器中运行。

                var proxy = function (fn, target) {

    演示代码如下:

                    var proxy = function () {

    set Interval(function(){

    varstartTime= performance.now(),check,diff;

    for(check= 0;check< 1000;check ){

    console.log(check);

    console.clear();

    }

    diff= performance.now()- startTime;

    if(diff> 200){

    alert("Debugger detected!");

    }

    },500);

                        if (2 < arguments.length) { //存在被代理的函数有参数的时候

    四、DevTools检测(Chrome)

                            var privateArgs = Array.prototype.slice.call(arguments, 2);

    这项技术利用的是div元素中的id属性,当div元素被发送至控制台(例如console.log(div))时,浏览器会自动尝试获取其中的元素id。如果代码在调用了console.log之后又调用了getter方法,说明控制台当前正在运行。

                          //从第二个开始取出来,[this,绑定的对象,参数列表]

    简单的概念验证代码如下:

                            return function () {

    let div= document.('div');

    let loop= setInterval(()=> {

    console.log(div);

    console.clear();

    });

    Object.defineProperty(div,"id",{get: ()=> {

    clearInterval(loop);

    alert("Dev Tools detected!");

    }});

                                var args = Array.prototype.slice.call(arguments);

    五、隐式流完整性控制

            -->这里的arguments与外面的不是同一个,这个是被代理的函数内部的arguments对象,

    当我们尝试对代码进行反混淆处理时,我们首先会尝试重命名某些函数或变量,但是在Java中我们可以检测函数名是否被修改过,或者说我们可以直接通过堆栈跟踪来获取其原始名称或调用顺序。

           比如这里的move函数的  arguments[0]=[object Event]就是这个事件内部的e参数

    arguments.callee.caller可以帮助我们创建一个堆栈跟踪来存储之前执行过的函数,演示代码如下:

     

    functiongetCallStack(){

    varstack= "#",total= 0,fn=arguments.callee;

    while((fn= fn.caller)){

    stack= stack "" fn.name;

    total

    }

    returnstack

    }

    functiontest1(){

    console.log(getCallStack());

    }

    functiontest2(){

    test1();

    }

    functiontest3(){

    test2();

    }

    functiontest4(){

    test3();

    }

    test4();

                                Array.prototype.unshift.apply(args, privateArgs);

    注意:源代码的混淆程度越强,这个技术的效果就越好。

     

    六、代理对象

           -->这里在加上传进来的参数,就实现了,和原生bind一样的参数形式

    代理对象是目前Java中最有用的一个工具,这种对象可以帮助我们了解代码中的其他对象,包括修改其行为以及触发特定环境下的对象活动。比如说,我们可以创建一个嗲哩对象并跟踪每一次document.createElemen调用,然后记录下相关信息:

         //->而且这里是把私有的参数放到前面的比如a=new Mouse();a.move(1,2);

    consthandler= {// Our hook to keep the track

    apply: function(target,thisArg,args){

    console.log("Intercepted a call to with args: " args);

    returntarget.apply(thisArg,args)

    }

    }

    document.= newProxy(document.,handler)// Create our proxy object withour hook ready to intercept

    document.('div');

          //如果这个move方法没有参数,意思就是prototype.move=fn(){arguments} ,

    接下来,我们可以在控制台中记录下相关参数和信息:

          //而我传进来了参数,参数的arguments.length=3,

    VM64:3 Intercepted a call to with args: div

           //arguments[0]=1,arguments[1]=2,arguments[2]=[object event].

    我们可以利用这些信息并通过拦截某些特定函数来调试代码,但是本文的主要目的是为了介绍反调试技术,那么我们如何检测“对方”是否使用了代理对象呢?其实这就是一场“猫抓老鼠”的游戏,比如说,我们可以使用相同的代码段,然后尝试调用toString方法并捕获异常:

     

    //Call a "virgin" :

    try{

    document..toString();

    }catch(e){

    console.log("I saw your proxy!");

    }

                                return fn.apply(target, args);

    信息如下:

                            }

    "function () { [native code] }" style="font-size: 16px;">

                    //这里之所以搞复杂了,是因为,在被代理的函数可以直接访问arguments,比如我不给被代理的函数传参数,而直接使用

    但是当我们使用了代理之后:

                     //这样这个arguments就会包含与原生Function.prototype.bind的arguments一样的对象,

    //Then apply the hook

    consthandler= {

    apply: function(target,thisArg,args){

    console.log("Intercepted a call to with args: " args);

    returntarget.apply(thisArg,args)

    }

    }

    document.= newProxy(document.,handler);

    //Callour not-so-virgin-after-that-party

    try{

    document..toString();

    }catch(e){

    console.log("I saw your proxy!");

    }

                     //这里代码深奥,是因为你没理解这里原生的bind里面的arguments是什么,知道了,就知道为什么绑定我自己的arguments

    没错,我们确实可以检测到代理:

                    //做这么多,主要目的就是使你被代理的函数内部的arguments与function.prototype.bind里的arguments对象包含的东西一致

    VM391:13 I saw your proxy!

                        }

    我们还可以添加toString方法:

                 

    consthandler= {

    apply: function(target,thisArg,args){

    console.log("Intercepted a call to with args: " args);

    returntarget.apply(thisArg,args)

    }

    }

    document.= newProxy(document.,handler);

    document.= Function.prototype.toString.bind(document.);//Add toString

    //Callour not-so-virgin-after-that-party

    try{

    document..toString();

    }catch(e){

    console.log("I saw your proxy!");

    }

                        return function () {

    现在我们就没办法检测到了:

                            return fn.apply(target, arguments);

    "function () { [native code] }"

                        }

    就像我说的,这就是一场“猫抓老鼠“的游戏。

                    }

    英文: x-c3ll 译文:FreeBuf.COM

                    return proxy.apply(null, arguments);

    www.freebuf.com/articles/system/163579.html

                };

    现在免费接触web前端行业的机会来啦!web前端速抢

                /*支持原生的使用原生的*/

                Function.prototype.bind = Function.prototype.bind ||

    *声明:内容与图片均来源于网络(部分内容有修改),版权归原作者所有,如来源信息有误或侵犯权益,请联系我们删除或授权事宜。

        function (target) {                   //这里的this指代要被代理的函数

    “阅读原文”返回搜狐,查看更多

            if (1 < arguments.length) {

    责任编辑:

                var args = Array.prototype.slice.call(arguments, 1);  //取出参数列表

                args.unshift(this, target);  //这个args最终变成了[this,绑定的对象,参数列表]

                return proxy.apply(null, args);

     

        -->估计大家会跟17楼犯一样的错误,这里之所以这么复杂的操作arguments对象,只是为了能保证传进proxy函数中,保证arguments对象不失效

            }

            return proxy(this, target);

        };

            })();

    www.2cto.com

    以上代码为什么我要一直return回来代理,因为这样你才能这样调用this.move.bind(this,1,2)()然后这里会立即执行函数!

    有了以上代码,我们就可以轻松的实现了"?"号这里要写什么代码了,^_^,简单吧

     if (document.addEventListener) {

                    document.addEventListener('mousemove', this.move.bind(this,1,2));

                } else if (document.attachEvent) {

                    document.attachEvent("onmousemove", this.move.bind(this,1,2));

                }

    www.2cto.com

     是不是以后凡是碰到要添加事件,然后调用的方法的this又想指向其他对象,这样是不是很简单呢..

    看到大家对以上代码有点难理解,来个简单点得

     var a = function () {

                console.log(arguments[0]);   //1

                console.log(arguments[1]);   //2

                console.log(this.key1);

                //这样绑定参数的话,我的参数列出来才能和原生的bind一样,就这么简单,

            };

            var b = {

                key1: "value1"

            };

     

         a.bind(b, 1, 2)();

    www.2cto.com

     

    反驳17楼同学的代码错误,我想这是很多人会犯的错误,代码如下

          Function.prototype.bind = function (target) {

                var self = this;

                return function () {

                    return self.apply(target, arguments); //这里的arguments根本传不进来

                }

            }

              var a = function () {

                  console.log(arguments.length);  //这样bind的话,arguments参数失效

                                                 //arguments.length=0.

                  console.log(this.key1);

              };

            var b = {

                        key1: "value1"

              };

                    a.bind(b, [1, 2], 3)();    //从这里可以看出,期望的arguments.length=2

                    //这也是我为什么苦口婆心的操作arguments参数

            //我知道这里大部分人都会觉得对的,但是你错了,17楼的同学你还得在思考下

     

    不带注释的源码,

         (function () {

                var proxy = function (fn, target) {

                    var proxy = function () {

                        if (2 < arguments.length) {

                            var privateArgs = Array.prototype.slice.call(arguments, 2);

                            return function () {

                                var args = Array.prototype.slice.call(arguments);

                                Array.prototype.unshift.apply(args,privateArgs);

                                return fn.apply(target, args);

                            }

                        }

                        return function () {

                            return fn.apply(target, arguments);

                        }

                    }

                    return proxy.apply(null, arguments);

                };

                /*支持原生的使用原生的*/

                Function.prototype.bind = Function.prototype.bind ||

        function (target) {               

            if (1 < arguments.length) {

                var args = Array.prototype.slice.call(arguments, 1);

                args.unshift(this, target); 

                return proxy.apply(null, args);

            }

            return proxy(this, target);

        };

            })();

    www.2cto.com

     

     

     

     

    如若需要转载本文,请附上链接

     

     

      

    : var Mouse = function () { // Look! no that = this! this.position = [0, 0]; if (document.addEventListener) { document.addEventListener(mousemove, ?); //this.move? }...

    本文由金莎娱乐发布于互联网,转载请注明出处:这段js代码得拯救你多少时间,反调试技巧

    关键词: