js 破解某些web应用的反调试逻辑

最近想看某个网站的逻辑, 用了混淆和反调试, 各种阻碍, 不得不想办法绕过它:

function _0x1b1e27(_0x5d8113) {
    function _0x44deab(_0xb1966e) {
        var _0x51479f = _0x5611;
        if (typeof _0xb1966e === _0x51479f(0xf4))
            return function(_0x28565d) {}
            [_0x51479f(0xc4)]('while\x20(true)\x20{}')[_0x51479f(0xf9)]('counter');
        else
            ('' + _0xb1966e / _0xb1966e)[_0x51479f(0x109)] !== -0x7c9 * 0x3 + 0x865 + 0xef7 * 0x1 || _0xb1966e % (-0x1881 + 0x79 * -0x41 + 0x374e) === -0x262e + 0xea + 0x212 * 0x12 ? function() {
                return !![];
            }
            [_0x51479f(0xc4)]('debu' + _0x51479f(0xab))[_0x51479f(0xc9)](_0x51479f(0xe0)) : function() {
                return ![];
            }
            [_0x51479f(0xc4)](_0x51479f(0xe1) + _0x51479f(0xab))[_0x51479f(0xf9)]('stateObject');
        _0x44deab(++_0xb1966e);
    }
    try {
        if (_0x5d8113)
            return _0x44deab;
        else
            _0x44deab(-0x8a9 * -0x2 + 0x2e4 + 0xd * -0x18e);
    } catch (_0x4c0048) {}
}

很难读懂,人工翻译它, 初版:

function getDebugger(outArg) {
    function innerFunc(inArg) {
        if (typeof inArg === 'string'){
            return function(a) {}['constructor']('while (true) {}')["apply"]('counter');
        }
        else{
            function(){ return true;}['constructor']('debugger')['call']('action')
        }
        innerFunc(++inArg);
    }
    try {
        if (outArg)
            return innerFunc;
        else
            innerFunc(0);
    } catch (err) {}
}

先分析这个语句:function(){ return true;}['constructor']('debugger')['call']('action')

这个语句function() { return true; }['constructor']   相当于Function对象

然后是Function('debugger') 相当于function anonymous(\n) {\ndebugger\n}

 然后是anonymous['call']('action') 相当于触发debugger, 经过这个分析

第二次改写:

function getDebugger(outArg) {
    function innerFunc(inArg) {
        if (typeof inArg === 'string'){
            return eval('while (true) {}');
        }
        else{
            eval('debugger');
        }
        innerFunc(++inArg);
    }
    try {
        if (outArg)
            return innerFunc;
        else
            innerFunc(0);
    } catch (err) {}
}

看到这个逻辑就比较清晰了, 
inArg是字符串,那么就死循环, 卡死
非字符串,那么就是触发调试

看到这个地方, 有一个破解方式,将innerFunc改为空方法, getDebugger(true)=function(){}

 

实际情况, 这个方法还是_0x开头,不是getDebugger。  

我想到了错误使用错误堆栈来获取调用者, 然后在hook这个调用者:

 获取到方法名,就好解决了, 直接eval(`${funcName}=function(){}`)

实际测试,debugger次数没有那么频繁了,但依旧存在!
理想很丰满现实很骨感, 这个hook确实生效了, 但是曾经拿到过这个闭包的方法引用依旧存在,

所以换种方案:

省了过程,直接上价值1个亿的代码(手动狗头):

var oldconstructor = Function.prototype.constructor;
var proconstructor = function(a) {
  if (a === 'debugger' || a.startsWith('while '))
      return function() {}
  else
      return oldconstructor.apply(this, Array.from(arguments));
}
proconstructor.prototype = oldconstructor.prototype;
Function.prototype.constructor = proconstructor;

妈妈再也不担心我调试不了, 哈哈。。。。。。

 

posted @ 2025-01-10 17:28  浪浪辛  阅读(195)  评论(0)    收藏  举报