如何基于JS截获动态代码


Posted in Javascript onDecember 25, 2019

这篇文章主要介绍了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的语法检查、自动完成等机制,能够大大提高生产力。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
javascript在一段文字中的光标处插入其他文字
Aug 26 Javascript
使用jquery中height()方法获取各种高度大全
Apr 02 Javascript
基于JavaScript实现瀑布流布局(二)
Jan 26 Javascript
js调用屏幕宽度的简单方法
Nov 14 Javascript
JS 组件系列之 bootstrap treegrid 组件封装过程
Apr 28 Javascript
jQuery条件分页 代替离线查询(附代码)
Aug 17 jQuery
Angular4开发解决跨域问题详解
Aug 28 Javascript
VueJs组件prop验证简单介绍
Sep 12 Javascript
Angular2进阶之如何避免Dom误区
Apr 02 Javascript
js与jQuery实现获取table中的数据并拼成json字符串操作示例
Jul 12 jQuery
Vue实现用户自定义字段显示数据的方法
Aug 28 Javascript
JS面试题大坑之隐式类型转换实例代码
Oct 14 Javascript
通过微信公众平台获取公众号文章的方法示例
Dec 25 #Javascript
vue远程加载sfc组件思路详解
Dec 25 #Javascript
node实现mock-plugin中间件的方法
Dec 25 #Javascript
微信小程序停止其他视频播放当前视频的实例代码
Dec 25 #Javascript
vue分页插件的使用方法
Dec 25 #Javascript
继承行为在 ES5 与 ES6 中的区别详解
Dec 24 #Javascript
在JavaScript中实现链式调用的实现
Dec 24 #Javascript
You might like
PHP树的深度编历生成迷宫及A*自动寻路算法实例分析
2015/03/10 PHP
php里array_work用法实例分析
2015/07/13 PHP
PHP代码判断设备是手机还是平板电脑(两种方法)
2015/10/19 PHP
php微信浏览器分享设置以及回调详解
2016/08/01 PHP
PHP 用session与gd库实现简单验证码生成与验证的类方法
2016/11/15 PHP
PHP使用 Imagick 扩展实现图片合成,圆角处理功能示例
2019/09/09 PHP
js查找父节点的简单方法
2008/06/28 Javascript
Jquery 改变radio/checkbox选中状态,获取选中的值(示例代码)
2013/12/12 Javascript
JQuery中绑定事件(bind())和移除事件(unbind())
2015/02/27 Javascript
Angularjs制作简单的路由功能demo
2015/04/14 Javascript
JavaScript多图片上传案例
2015/09/28 Javascript
图解JavaScript中的this关键字
2020/05/28 Javascript
仅9张思维导图帮你轻松学习Javascript 就这么简单
2016/06/01 Javascript
Bootstrap导航条可点击和鼠标悬停显示下拉菜单的实现代码
2016/06/23 Javascript
AngularJS入门教程之Scope(作用域)
2016/07/27 Javascript
React Native实现简单的登录功能(推荐)
2016/09/19 Javascript
javascript 使用正则test( )第一次是 true,第二次是false
2017/02/22 Javascript
JS正则验证多个邮箱完整实例【邮箱用分号隔开】
2017/04/19 Javascript
jQuery实现frame之间互通的方法
2017/06/26 jQuery
js实现金山打字通小游戏
2020/07/24 Javascript
Python实时获取cmd的输出
2015/12/13 Python
Python实现简单的列表冒泡排序和反转列表操作示例
2019/07/10 Python
python 用Matplotlib作图中有多个Y轴
2020/11/28 Python
加拿大时尚潮流大码女装购物网站:Addition Elle
2018/04/02 全球购物
Juice Beauty官网:有机美容产品,护肤与化妆品
2020/06/13 全球购物
Bloomingdale’s阿联酋:选购奢华时尚、美容及更多
2020/09/22 全球购物
家长给幼儿园的表扬信
2014/01/09 职场文书
详细的大学生创业计划书模板
2014/01/27 职场文书
安全生产月演讲稿
2014/05/09 职场文书
班组建设经验交流材料
2014/05/12 职场文书
2014高中生入党思想汇报范文
2014/09/13 职场文书
2014领导班子四风问题对照检查材料思想汇报
2014/09/21 职场文书
小学德育工作总结2015
2015/05/12 职场文书
欠款起诉书范文
2015/05/19 职场文书
经营场所使用证明
2015/06/19 职场文书
创业计划书之DIY自助厨房
2019/09/06 职场文书