手机版

js经验分享JavaScript反调试技巧

时间:2021-09-01 来源:互联网 编辑:宝哥软件园 浏览:

在此之前,我一直在学习与JavaScript相关的反调试技巧。然而,当我在网上搜索相关信息时,我发现网上的文章并不多,即使有,也非常不完整。因此,在本文中,我将与您一起总结关于JavaScript反调试的技巧。值得一提的是,其中一些方法已被网络犯罪分子广泛用于恶意软件。

至于JavaScript,只需要花一点时间调试和分析,就可以了解JavaScript代码段的功能逻辑。我们将要讨论的内容可能会让那些想要分析您的JavaScript代码的人更加困难。然而,我们的技术与代码混淆无关。我们主要关注如何让主动调试代码变得更加困难。

本文介绍的技术方法如下:

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

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

3.代码完整性控制;

4.流量完整性控制;

5.逆向模拟;

简而言之,如果我们检测到一个“异常”情况,程序的运行过程就会发生变化,跳转到伪代码块,并“隐藏”真实的函数代码。

1.函数的重新定义

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

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

console . log(' hello world ');var fake=function(){ };window[' console '][' log ']=false;“你看不见我!”);运行后,我们会看到:

你好,世界

你会发现第二条消息没有显示,因为我们重新定义了这个功能,也就是“禁用”它原来的功能。但我们也可以让它显示虚假信息。例如,像这样:

console . log(' Normal function ');//首先我们保存对原始控制台的引用. log functionvar original=window[' console '][' log '];//接下来我们创建我们的伪函数//基本上,我们检查参数,如果匹配,我们用otherparam调用原始函数。//如果不匹配,则将参数传递给原始functionvar fake=function(参数){ if(参数==='Ka0labs') { original('欺骗!');} else { original(参数);}}//我们现在重新定义console.log为我们的假函数window[' console '][' log ']=false;//然后我们用任何argumentconsole.log调用console . log(‘thistis unchanged’);//现在我们应该在console中看到不同于‘Ka0labs’console . log(‘Ka0labs’)的其他文本;//Aaaand一切照旧OKconsole.log('拜拜!' );如果一切正常:

正常功能VM117:11这是不允许的117:9欺骗!VM117:11拜拜!

事实上,为了控制代码的执行模式,我们也可以用更聪明的方式修改函数。例如,我们可以基于上面的代码构建一个代码段,并重新定义eval函数。我们可以将JavaScript代码传递给eval函数,然后计算并执行代码。如果我们重新定义这个函数,我们可以运行不同的代码:

//只是一个普通的eval(' console . log(' 1337 ')');//现在我们重新开始这个过程.var original=evalvar fake=function(参数){ //如果要评估的代码包含1337.if (argument.indexOf('1337 ')!==-1) { //.我们只是执行不同的原始代码(' for(I=0;i 10I){ console . log(I);}');} else { original(参数);} } eval=fakeeval('console.log('我们应该看看这个.')');//现在我们应该看到for循环的执行,而不是期望的值(' console.log('Too1337 for you!')');运行结果如下:

1337VM146:1We我们应该看到这个…vm147:10 vm147336011 vm147336012 VMM 147:13 vm147336014 vm147336015 vm147336016 vm147336017 vm147336017 vm147336018 vm147:18 vm147:0

如前所述,这种方法虽然很巧妙,但也是一种非常基础和常见的方法,所以很容易被检测到。

二、断点

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

如果你学过调试器或者x86架构,可能对0xCC指令比较熟悉。在JavaScript中,我们有一个类似的指令叫做调试器。当我们在代码中声明调试器函数时,脚本代码将在调试器指令处停止运行。例如:

console.log('Seeme!');调试器;console.log('Seeme!');许多商业产品会在代码中定义一个无限循环调试器指令,但是有些浏览器会阻止这段代码,而有些则不会。这个方法的主要目的是让那些想要调试代码的人厌烦,因为无限循环意味着代码会不断弹出窗口询问您是否要继续运行脚本代码:

setTimeout(函数(){while (true) {eval('调试器')

第三,时差

这是借鉴传统逆向技术的基于时间的反调试技巧。当一个脚本在DevTools等工具环境中执行时,运行速度会非常慢(很长时间),所以我们可以根据运行时间来判断这个脚本当前是否正在调试。例如,我们可以测量代码中两个设定点之间的运行时间,然后使用该值作为参考。如果运行时间超过该值,则意味着脚本当前正在调试器中运行。

演示代码如下:

设置Interval(函数(){ var startTime=performance.now()),check,difffor(check=0;检查1000;check ){ console.log(检查);console . clear();} diff=performance . now()-start time;if (diff 200){警报('检测到调试器!');}},500);四.开发工具检测(Chrome)

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

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

let div=document . create element(' div ');let loop=setInterval(()={ console . log(div);console . clear();});object . defineperOperty(div,' id ',{get: ()={ clearInterval(循环);警报('检测到开发工具!');}});5.隐式流完整性控制

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

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

函数getCallStack() { var stack='# ',total=0,fn=arguments . calleeper;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={ //我们的钩子保留了轨道应用:函数(target,thisArg,args){ console.log('截获了对带有args: ' args的标签名的调用);返回target.apply(thisArg,args)} }文档。createelement=新代理(文档。createelement,handler) //创建我们的代理对象,而不需要准备拦截文件。create element(' div ');接下来,我们可以在控制台中记录下相关参数和信息:

VM64:3截获了对参数为:分区的标签名的调用

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

//调用"处女createelements :尝试{ document。createelement。tostring();{ catch(e){ console。日志('我看到了你的代理服务器!');}信息如下:

函数createElement(){[本机代码] } '但是当我们使用了代理之后:

//然后应用hookconsthandler={ apply:函数(target,thisArg,args){ console.log('截获了对带有args: ' args的标签名的调用);返回target.apply(thisArg,args)} }文档。创建元素=新代理(文档。创建元素,处理程序);//Callour非处女后党createElementtry { document。createelement。tostring();{ catch(e){ console。日志('我看到了你的代理服务器!');}没错,我们确实可以检测到代理:

VM391:13我看到你的代理了!

我们还可以添加转换对象为字符串方法:

const handler={ apply :函数(target,thisArg,args){ console.log('截获了对带有args: ' args的标签名的调用);返回target.apply(thisArg,args)} }文档。创建元素=新代理(文档。创建元素,处理程序);文件。createelement=函数。原型。tostring。绑定(文档。create element);//添加到字符串//Callour非处女后党createElementtry { document。createelement。to string();{ catch(e){ console。日志('我看到了你的代理服务器!');}现在我们就没办法检测到了:

函数createElement(){[本机代码] } '就像我说的,这就是一场"猫抓老鼠"的游戏。

总结

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

* 参考来源:x-c3ll,FB小编Alpha_h4ck编译,转载请注明来自FreeBuf .计算机输出缩微胶片

版权声明:js经验分享JavaScript反调试技巧是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。