当前位置: 新豪天地登录网址 > www.3559.com > 正文

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

时间:2019-09-29 14:42来源:www.3559.com
原标题:JavaScript 反调试技巧 js经验分享 JavaScript反调试技巧,js经验分享 在此之前,我一直都在研究JavaScript相关的反调试技巧。但是当我在网上搜索相关资料时,我发现网上并没有多

原标题:JavaScript 反调试技巧

js经验分享 JavaScript反调试技巧,js经验分享

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

www.3559.com 1

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

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

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

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

  3. 代码完整性控制;

  4. 流完整性控制;

  5. 反模拟;

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

一、函数重定义

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

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

console.log("HelloWorld");
var fake = function() {};
window['console']['log']= fake;
console.log("Youcan't see me!");

运行后我们将会看到:

VM48:1 Hello World

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

console.log("Normalfunction");
//First we save a reference to the original console.log function
var original = 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
var fake = 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!");

如果一切正常的话:

Normal function
VM117:11 This is unaltered
VM117:9 Spoofed!
VM117:11 Bye bye!

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

//Just a normal eval
eval("console.log('1337')");
//Now we repat the process...
var original = eval;
var fake = function(argument) {
  // If the code to be evaluated contains1337...
  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!')");

运行结果如下:

1337
VM146:1We should see this…
VM147:10
VM147:11
VM147:12
VM147:13
VM147:14
VM147:15
VM147:16
VM147:17
VM147:18
VM147:19

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

二、断点

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

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

console.log("Seeme!");
debugger;
console.log("Seeme!");

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

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

三、时间差异

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

演示代码如下:

set Interval(function(){
 var startTime = 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);

四、DevTools检测(Chrome)

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

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

let div = document.createElement('div');
let loop = setInterval(() => {
  console.log(div);
  console.clear();
});
Object.defineProperty(div,"id", {get: () => {
  clearInterval(loop);
  alert("Dev Tools detected!");
}});

五、隐式流完整性控制

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

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

function getCallStack() {
  var stack = "#", total = 0, fn =arguments.callee;
  while ( (fn = fn.caller) ) {
    stack = stack   ""  fn.name;
    total  
  }
  return stack
}
function test1() {
  console.log(getCallStack());
}
function test2() {
  test1();
}
function test3() {
  test2();
}
function test4() {
  test3();
}
test4();

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

六、代理对象

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

const handler = { // Our hook to keep the track
  apply: function (target, thisArg, args){
    console.log("Intercepted a call tocreateElement with args: "   args);
    return target.apply(thisArg, args)
  }
}

document.createElement= new Proxy(document.createElement, handler) // Create our proxy object withour hook ready to intercept
document.createElement('div');

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

VM64:3 Intercepted a call to createElement with args: div

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

//Call a "virgin" createElement:
try {
  document.createElement.toString();
}catch(e){
  console.log("I saw your proxy!");
}

信息如下:

"function createElement() { [native code] }"

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

//Then apply the hook
consthandler = {
  apply: function (target, thisArg, args){
    console.log("Intercepted a call tocreateElement with args: "   args);
    return target.apply(thisArg, args)
  }
}
document.createElement= new Proxy(document.createElement, handler);

//Callour not-so-virgin-after-that-party createElement
try {
  document.createElement.toString();
}catch(e) {
  console.log("I saw your proxy!");
}

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

VM391:13 I saw your proxy!

我们还可以添加toString方法:

const handler = {
  apply: function (target, thisArg, args){
    console.log("Intercepted a call tocreateElement with args: "   args);
    return target.apply(thisArg, args)
  }
}
document.createElement= new Proxy(document.createElement, handler);
document.createElement= Function.prototype.toString.bind(document.createElement); //Add toString
//Callour not-so-virgin-after-that-party createElement
try {
  document.createElement.toString();
}catch(e) {
  console.log("I saw your proxy!");
}

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

"function createElement() { [native code] }"

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

总结

希望我所收集到的这些技巧可以对大家有所帮助,如果你有更好的技巧想跟大家分享,可以直接在文章下方的评论区留言,或者在Twitter上艾特我(@TheXC3LL)。

* 参考来源:x-c3ll,FB小编Alpha_h4ck编译,转载请注明来自FreeBuf.COM

JavaScript反调试技巧,js经验分享 在此之前,我一直都在研究JavaScript相关的反调试技巧。但是当我在网上搜索相关资料时,我发...

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

 

写在前面的话:

www.3559.com 2

1.应用案例:

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

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

  

www.3559.com 3

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

        var Mouse = function () {

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

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

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

  3. 代码完整性控制;

  4. 流完整性控制;

  5. 反模拟;

            // Look! no that = this!

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

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

            this.position = [0, 0];

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

一、函数重定义

            if (document.addEventListener) {

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

  2. 代码完整性控制;

  3. 流完整性控制;

  4. 反模拟;

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

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

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

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

            } else if (document.attachEvent) {

一、函数重定义

console.log("HelloWorld");
var fake = function() {};
window['console']['log']= fake;
console.log("Youcan't see me!");

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

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

运行后我们将会看到:

            }

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

VM48:1 Hello World

 

console.log("HelloWorld");

varfake= function(){};

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

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

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

        };

运行后我们将会看到:

console.log("Normalfunction");
//First we save a reference to the original console.log function
var original = 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
var fake = 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!");

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

VM48:1 Hello World

如果一切正常的话:

            event = window.event || event;

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

Normal function
VM117:11 This is unaltered
VM117:9 Spoofed!
VM117:11 Bye bye!

            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!");

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

        y = event.pageY || event.offsetY;

如果一切正常的话:

//Just a normal eval
eval("console.log('1337')");
//Now we repat the process...
var original = eval;
var fake = function(argument) {
  // If the code to be evaluated contains1337...
  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!')");

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

Normal function

VM117:11Thisisunaltered

VM117:9Spoofed!

VM117:11Bye bye!

运行结果如下:

            this.log(arg1,arg2);

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

1337
VM146:1We should see this…
VM147:10
VM147:11
VM147:12
VM147:13
VM147:14
VM147:15
VM147:16
VM147:17
VM147:18
VM147:19

        };

//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

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

            console.log(this.position);

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

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

        };

二、断点

console.log("Seeme!");
debugger;
console.log("Seeme!");

        new Mouse();

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

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

www.2cto.com

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

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

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

console.log("Seeme!");

debugger;

console.log("Seeme!");

三、时间差异

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

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

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

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

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

演示代码如下:

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

三、时间差异

set Interval(function(){
 var startTime = 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);

    (function () {

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

四、DevTools检测(Chrome)

            var proxy = function (fn, target) {

演示代码如下:

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

                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)

let div = document.createElement('div');
let loop = setInterval(() => {
  console.log(div);
  console.clear();
});
Object.defineProperty(div,"id", {get: () => {
  clearInterval(loop);
  alert("Dev Tools detected!");
}});

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

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

五、隐式流完整性控制

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

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

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

                        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!");

}});

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

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

五、隐式流完整性控制

function getCallStack() {
  var stack = "#", total = 0, fn =arguments.callee;
  while ( (fn = fn.caller) ) {
    stack = stack   ""  fn.name;
    total  
  }
  return stack
}
function test1() {
  console.log(getCallStack());
}
function test2() {
  test1();
}
function test3() {
  test2();
}
function test4() {
  test3();
}
test4();

        -->这里的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();

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

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

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

const handler = { // Our hook to keep the track
  apply: function (target, thisArg, args){
    console.log("Intercepted a call tocreateElement with args: "   args);
    return target.apply(thisArg, args)
  }
}

document.createElement= new Proxy(document.createElement, handler) // Create our proxy object withour hook ready to intercept
document.createElement('div');

 

六、代理对象

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

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

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

VM64:3 Intercepted a call to createElement with args: div

     //->而且这里是把私有的参数放到前面的比如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');

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

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

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

//Call a "virgin" createElement:
try {
  document.createElement.toString();
}catch(e){
  console.log("I saw your proxy!");
}

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

VM64:3 Intercepted a call to with args: div

信息如下:

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

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

"function createElement() { [native code] }"

 

//Call a "virgin" :

try{

document..toString();

}catch(e){

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

}

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

                            return fn.apply(target, args);

信息如下:

//Then apply the hook
consthandler = {
  apply: function (target, thisArg, args){
    console.log("Intercepted a call tocreateElement with args: "   args);
    return target.apply(thisArg, args)
  }
}
document.createElement= new Proxy(document.createElement, handler);

//Callour not-so-virgin-after-that-party createElement
try {
  document.createElement.toString();
}catch(e) {
  console.log("I saw your proxy!");
}

                        }

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

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

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

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

VM391:13 I saw your proxy!

                 //这样这个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!");

}

我们还可以添加toString方法:

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

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

const handler = {
  apply: function (target, thisArg, args){
    console.log("Intercepted a call tocreateElement with args: "   args);
    return target.apply(thisArg, args)
  }
}
document.createElement= new Proxy(document.createElement, handler);
document.createElement= Function.prototype.toString.bind(document.createElement); //Add toString
//Callour not-so-virgin-after-that-party createElement
try {
  document.createElement.toString();
}catch(e) {
  console.log("I saw your proxy!");
}

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

VM391:13 I saw your proxy!

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

                    }

我们还可以添加toString方法:

"function createElement() { [native code] }"

             

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] }"

希望我所收集到的这些技巧可以对大家有所帮助,如果你有更好的技巧想跟大家分享,可以直接在文章下方的评论区留言,或者在Twitter上艾特我(@TheXC3LL)。

                    }

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

* 参考来源:x-c3ll,FB小编Alpha_h4ck编译,转载请注明来自FreeBuf.COM

                }

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

您可能感兴趣的文章:

  • JS高级技巧(简洁版)
  • JS 中可以提升幸福度的小技巧(可以识别更多另类写法)
  • 几个你不知道的技巧助你写出更优雅的vue.js代码
  • js技巧之十几行的代码实现vue.watch代码
  • 让你5分钟掌握9个JavaScript小技巧
  • 9种使用Chrome Firefox 自带调试工具调试javascript技巧
  • 基于JavaScript 性能优化技巧心得(分享)
  • JavaScript实用代码小技巧

                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? }...

编辑:www.3559.com 本文来源:这段js代码得拯救你多少时间,反调试技巧

关键词: www.3559.com