反调试方法的分类
显性
显性的反调试方法一般有:
•debugger•死循环 debugger 比较好理解,而死循环的方式有很多,例如通过循环语句、无限递归、两个方法互相调用、计时器(setInterval)、打开新页面(window.open("xxx"))、写历史记录、操作 url 地址等等等等。
隐性 (暗桩)
发现在被调试之后给出错误逻辑
实现方式
键盘监听 F12
document.addEventListener('keydown', function(e) {
if (e.keyCode == 123) {
alert('禁止调试!');
}
});
用浏览器打开,当按下 F12 时会弹窗:
window .innerheight 内高和外高的差值
var heightDiff = window.outerHeight - window.innerHeight;
if (heightDiff > 200) {
alert('禁止调试!');
}
打开 debug 页面后刷新,重新加载后检测到高度差过大,弹窗:
检测 console.log 调用的次数
var logCount = 0;
var oldLog = console.log;
console.log = function() {
logCount++;
if (logCount > 2) {
alert('禁止调试!');
} else {
oldLog.apply(console, arguments);
}
};
打开浏览器,在 console 中调用 console.log:
超过两次就会弹窗。
代码运行的时间差
var start = new Date();
for (var i = 0; i < 1000000; i++) {
...
}
var end = new Date();
var timeDiff = end - start;
if (timeDiff > 1000) { // 假设大于1秒则视为调试
alert('禁止调试!');
}
打断点,运行:
toString 检测
当我们打断点调试时,当鼠标放到一个方法或者值上时,就会默认执行 toString 方法,查看其内容,可以根据这一点进行反调试。
以百度为例,随便找一个 js 文件,打好断点:
在 console 中执行:
var aaa = createLocalRequire.toString;
createLocalRequire.toString = function(){console.log("debugging!"); return aaa();}
鼠标移上去查看其值:
console 中已经进行了打印:
除此之外,还有很多检测方式,例如检测非浏览器环境,检测栈的层数 caller 等等。
解决方法
一般分为虚拟机和非虚拟机两种。
虚拟机是指使用 eval 或者 Function 开启了一个新上下文,剩下的称之为非虚拟机。
过 debugger(显性)
非虚拟机 :
以下面的代码为例:
function xx(){
debugger;
console.log(1);
}
function ry4n(){
xx();
}
ry4n();
直接运行会在 debugger 处断住:
编辑断点
可以先打断点,再将其属性设置为 false:
此时可以成功过:
替换代码
override
首先在 override 处添加文件夹,并给予权限:
接着把想修改的 js 发到 override:
即可进行任意修改:
fiddler
还有一种方式就是利用 fiddler。 打开监听,将想替换的数据包拖到 autoresponder:
通过 find a file,选择想替换的目标文件即可。
虚拟机
如果是虚拟机的情况,可以通过类似
Function.prototype.constructor = function(X){if(X) xxx}
的方法,进行代码或者执行逻辑的修改。
隐性
看浏览器正常堆栈和本地堆栈。
原文始发于微信公众号(Crush Sec):js 逆向系列06-反调试
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论