本文,將分享幾種JS代碼反調試技巧,目標是:實現防止他人調試、動態(tài)分析自己的代碼。
檢測調試,方法一:用console.log檢測代碼:
var c = new RegExp ("1");
c.toString = function () {
alert("檢測到調試")
}
console.log (c);
原理:
當console.log輸出調試信息時,會將非字符串類型數據轉成字符串,于是通過接管toString函數,判斷是否有這樣的行為,而如果沒有打開調試窗口,即不會有console.log輸出,從而識別是否于處調試狀態(tài)。
運行效果:
檢測調試,方法二、通過代碼執(zhí)行時間檢測
代碼:
var startTime = new Date ();
debugger;
var endTime = new Date ();
var isDev = endTime-startTime> 100;
if (isDev){
alert("檢測到調試")
}
原理:
在代碼不同語句間加入debuger指令,debugger會使調試模式暫停,那么暫停將造成延遲。
通過檢測延遲前后果的時間值,從而判斷是否發(fā)生了延時,如果發(fā)生,則表達處于調試狀態(tài)。
運行效果:
debugger觸發(fā)暫停:
檢測到調試:
反調試手段
檢測到調試又該如何呢?
反調試方法一、無限debugger一般情況下,可以用無限循環(huán)的debugger,使不停的暫停代碼執(zhí)行,使調試無法進行。
如:
var c = new RegExp ("1");
c.toString = function () {
alert("檢測到調試")
setInterval(function(){
debugger
},1000);
}
console.log (c);
運行效果:
反調試方法二、內存耗盡
debugger方法雖然效果不錯,但太過直觀,反制效果也過去溫柔。
另有一種“內存耗盡”的方式,會更隱藏、更強大,如:
var startTime = new Date ();
debugger;
var endTime = new Date ();
var isDev = endTime-startTime> 100;
var stack = [];
if (isDev){
while(true){
stack.push(this);
console.log(stack.length,this)
}
}
運行效果:
代碼運行造成的內存占用會越來越大,很快會使瀏覽器崩潰,如下圖:
JS代碼加密
上述幾種方法,已經達到了反調試的效果,但如果他人查看代碼,也可能被找出檢測功能并刪去。
為了防止反調試功能被剔除,我們可以對JS代碼進行混淆加密。
例如本文第一段代碼:
var c = new RegExp ("1");
c.toString = function () {
alert("檢測到調試")
}
console.log (c);
代碼功能很清晰,使用JShaman進行混淆加密:
JShaman是專業(yè)且強力的JS代碼混淆加密工具
混淆加密后的代碼,將成為:
var _0x98ac=["117.","56.","26825.27970.21049.35850.35804."];function _0x(str,dy_key){dy_key=9;var i,k,str2="";k=str.split(".");for(i=0;i<k.length-1;i++){str2+=String.fromCharCode(k[i]^dy_key);}return str2;}function _0xb346gb(vm_opcode){var _array="3|2|1|4|0".split(_0x(_0x98ac[0])),_index=0;while(!![]){switch(+_array[_index++]){case 0:while(ip<vm_opcode.length){ip++;switch(vm_opcode[ip]){case op.push:{ip++;stack.push(vm_opcode[ip]);sp++;break;}case op.add:{var op_1=stack[sp-1];var op_2=stack[sp];var value=function(s,h){return s+h;}(op_1,op_2);stack.push(value);sp++;break;}case op.sub:{var op_1=stack[sp-1];var op_2=stack[sp];var value=function(s,h){return s-h;}(op_1,op_2);stack.push(value);sp++;break;}case op.mul:{var op_1=stack[sp-1];var op_2=stack[sp];var value=function(s,h){return s*h;}(op_1,op_2);stack.push(value);sp++;break;}case op.div:{var op_1=stack[sp-1];var op_2=stack[sp];var value=function(s,h){return s/h;}(op_1,op_2);stack.push(value);sp++;break;}case op.xor:{var op_1=stack[sp-1];var op_2=stack[sp];var value=function(s,h){return s^h;}(op_1,op_2);stack.push(value);sp++;break;}case op.pop:{return stack[sp];}}}continue;case 1:var ip=-1;continue;case 2:var stack=[];continue;case 3:var op={push:32,add:33,sub:34,mul:35,div:36,pop:37,xor:38};continue;case 4:var sp=-1;continue;}break;}}var _0x97b=function(s,h){return s+h;}(_0xb346gb([32,674032,32,674037,38,37]),_0xb346gb([32,651374,32,651368,38,37]));var c=new RegExp(_0x(_0x98ac[1]));_0x97b=function(){return _0xb346gb([32,686171,32,686171,38,37]);}();c['x74x6fx53x74x72x69x6ex67']=function(){alert(_0x(_0x98ac[2]));};console['x6cx6fx67'](c);
這樣的代碼,將很難理解其功能,也就可以防止代碼被修改。
其它的JS功能代碼,同樣可以使用JShaman進行混淆加密,最終使用混淆加密后的安全代碼。