zoukankan      html  css  js  c++  java
  • JS中注入eval, Function等系统函数截获动态代码

    正文
    现在很多网站都上了各种前端反爬手段,无论手段如何,最重要的是要把包含反爬手段的前端javascript代码加密隐藏起来,然后在运行时实时解密动态执行。
    动态执行js代码无非两种方法,即eval和Function。那么,不管网站加密代码写的多牛,我们只要将这两个方法hook住,即可获取到解密后的可执行js代码。
    注意,有些网站会检测eval和Function这两个方法是否原生,因此需要一些小花招来忽悠过去。

    挂钩代码
    首先是eval的挂钩代码:

    (function() {
        if (window.__cr_eval) return
        window.__cr_eval = window.eval
        var myeval = function (src) {
            console.log("================ eval begin: length=" + src.length + ",caller=" + (myeval.caller && myeval.caller.name) + " ===============")
            console.log(src);
            console.log("================ eval end ================")
            return window.__cr_eval(src)
        }
        var _myeval = myeval.bind(null)  // 注意:这句和下一句就是小花招本招了!
        _myeval.toString = window.__cr_eval.toString
        Object.defineProperty(window, 'eval', { value: _myeval })
        console.log(">>>>>>>>>>>>>> eval injected: " + document.location + " <<<<<<<<<<<<<<<<<<<")
    })();
    

    这段代码执行后,之后所有的eval操作都会在控制台打印输出将要执行的js源码。
    同理可以写出Function的挂钩代码:

    (function() {
        if (window.__cr_fun) return
        window.__cr_fun = window.Function
        var myfun = function () {
            var args = Array.prototype.slice.call(arguments, 0, -1).join(","), src = arguments[arguments.length - 1]
            console.log("================ Function begin: args=" + args + ", length=" + src.length + ",caller=" + (myfun.caller && myfun.caller.name) + " ===============")
            console.log(src);
            console.log("================ Function end ================")
            return window.__cr_fun.apply(this, arguments)
        }
        myfun.toString = function() { return window.__cr_fun + "" } // 小花招
        Object.defineProperty(window, 'Function', { value: myfun })
        console.log(">>>>>>>>>>>>>> Function injected: " + document.location + " <<<<<<<<<<<<<<<<<<<")
    })();
    

    注意:和eval不同,Function是个有变长参数的构造方法,需要处理this

    另外,有些网站还会用类似的机制加密页面内容,然后通过document.write输出动态解密的内容,因此同样可以挂钩document.write,挂钩方法类似eval,这里就不重复了。

    注入方式
    另外,还有个问题需要关注,就是挂钩代码的注入方法。
    最简单的就是F12调出控制台,直接执行上面的代码,但这样只能hook住执行之后的eval调用,如果希望从页面刚加载时就注入,那么可以用以下几种方式:

    油猴注入,油猴可以监听文档加载的几种不同状态,并在特定时刻执行js代码。我没有太多研究,具体请参见油猴手册
    代理注入,修改应答数据,在<head>标签内的第一个位置插入<script>节点,确保在其它js加载执行前注入;Fiddler, anyproxy等都可以编写外部规则,具体请参见附录部分
    使用chrome-devtools-protocol, 通过Page.addScriptToEvaluateOnNewDocument注入外部js代码
    附录
    不少人没用过代理规则,这里写一下Fiddler和anyproxy的规则编写方法:

    1. 如何添加Fiddler代理规则
      Fiddler菜单里Rules > Customize Rules 打开脚本编辑器
      在脚本编辑器里找OnBeforeResponse方法,方法内添加下面C#代码:
    if (oSession.oResponse.headers.ExistsAndContains("Content-Type", "html")){
        oSession.utilDecodeResponse(); // Remove any compression or chunking
        var b = System.Text.Encoding.UTF8.GetString(oSession.responseBodyBytes);
        var r = /<head[^>]*>/i;
        var js = "..."; // 要注入的js源码,见正文
        b = b.replace(r, "$0<script>" + js + "</script>");
        oSession.utilSetResponseBody(b); // Set the response body back
    }
    

    这样就会在所有html文档头部自动添加js代码了
    2. 如何添加anyproxy代理规则
    编辑一个rule.js保存在anyproxy根目录下,内容如下:

    function injectEval() {
        if (window.__cr_eval) return
        ... // 见正文,此处略
        console.log(">>>>>>>>>>>>>> eval injected: " + document.location + " <<<<<<<<<<<<<<<<<<<")
    }
    module.exports = {
      summary: 'a rule to hook all eval',
      *beforeSendResponse(requestDetail, {response}) {
        if (response.header["Content-Type"].indexOf("text/html") >= 0) {
          response.body = (response.body + "").replace(/<head[^>]*>/i, `$&<script>(${injectEval})();</script>`)
          return {response}
        }
      },
    };
    

    带规则启动anyproxy

    anyproxy -r rule.js
    

    可以看到,使用基于js的工具链有其天然优势,即注入代码可以以源码而不是字符串形式和规则代码共存,这样可以利用到IDE的语法检查、自动完成等机制,能够大大提高生产力。

    出处:https://segmentfault.com/a/1190000018742189

  • 相关阅读:
    Benelux Algorithm Programming Contest 2016 Preliminary K. Translators’ Dinner(思路)
    Benelux Algorithm Programming Contest 2016 Preliminary Target Practice
    Benelux Algorithm Programming Contest 2016 Preliminary I. Rock Band
    Benelux Algorithm Programming Contest 2016 Preliminary A. Block Game
    ICPC Northeastern European Regional Contest 2019 Apprentice Learning Trajectory
    ICPC Northeastern European Regional Contest 2019 Key Storage
    2018 ACM ICPC Asia Regional
    2018 ACM ICPC Asia Regional
    Mybatis入库出现异常后,如何捕捉异常
    优雅停止 SpringBoot 服务,拒绝 kill -9 暴力停止
  • 原文地址:https://www.cnblogs.com/c-x-a/p/11733677.html
Copyright © 2011-2022 走看看