前言
网站的 JavaScript 代码设置了越来越多的保护措施,常见的有 JavaScript 压缩、混淆和加密等,我们需要通过逆向 JavaScript 代码,找出其中的加密逻辑,从而直接对加密逻辑进行爬取,这过程中常需要追踪某些方法的堆栈调用情况,但很多情况下难以对其进行捕捉,这里引出被称为逆向分析之“花”的 Hook 技术。
Hook 技术简介
Hook 技术又称为钩子技术,他是一种特殊的消息处理机制,可以监视系统或者进程中的各种事件消息,截获发往目标窗口的消息并进行处理,因为 Windows 操作系统是建立在事件驱动机制上的,通过消息传递实现,而 Hook 相当于对其的拦截。例如程序运行的过程中,在系统还没有调用函数执行前,Hook 程序就先捕获该消息,得到程序的控制权,改变函数的执行行为,在原方法前后加入自定义方法,从而实现对方法的重写。简而言之 Hook 过程就是半路截胡,改头换面(不影响原有方法效果的前提下,自定义新的功能)。
Hook 技术:https://www.jianshu.com/p/3382cc765b39
Tempermonkey
在浏览器中,Hook 操作可以通过 Tampermonkey 插件来实现,Tampermonkey 是脚本管理器 Greasemonkey(GM 油猴)中的一种,知名的油猴管理器有很多:Tampermonkey、Greasemonkey、Violentmonkey,其中对各大浏览器平台适配的最好的就是 Tampermonkey,他是一款免费的浏览器扩展和最为流行的用户脚本管理器,它适用于 Chrome、Microsoft Edge、 Safari、Opera Next 和 Firefox 。
相关文档可查看:Tampermonkey • FAQ
下载
下载方式一:
官网地址:Tampermonkey • Home ,Stable 为稳定版,Beta 为测试版
下载方式二:
Chrome 应用商店
下载方式三:
百度云链接:https://pan.baidu.com/s/19vbhHGhMsEXvJzPratUe-A?pwd=Rose
提取码:Rose
使用
将下载好的如 Tampermonkey.crx 文件直接拖入 Chrome 扩展程序页面(右上角三点 → 更多工具 → 扩展程序)即可:
打开管理面板即可新建自定义脚本:
可下载于 Tampermonkey 中的实用脚本推荐:
点击加号即可创建新的脚本:
初始页面:
// ==UserScript==
// @name New Userscript
// @namespace http://tampermonkey.net/
// @version 0.1
// @description try to take over the world!
// @author You
// @match https://www.tampermonkey.net/faq.php?ext=dhdg
// @grant none
// ==/UserScript==
(function() {
'use strict';
// Your code here...
})();
'use strict':表明代码使用的 JavaScript 的严格模式,在此模式下,可以消除 JavaScript 语法的一些不合理、不严谨之处,保证代码运行安全,提高运行编译速度;// Your code here... 处及编写脚本代码。
- @name:脚本的名称,即在控制面板中显示的脚本名称
- @namespace:脚本的命名空间
- @version:脚本的版本
- @description:脚本描述
- @author:作者名称
- @match:生效页面,可以配置多个
- @grant:用于添加 GM 函数到白名单,相当于授权某些 GM 函数的使用权限
eg:
//@grant GM_setValue
//@grant GM_setClipbpoard
//@grant window.close
- GM_log:将日志输出到控制台
- GM_setValue:将参数内容保存到浏览器存储中
- GM_addValueChangeListener:为某个变量添加监听,当这个变量的值改变时,就会触发回调
- GM_xmlhttpRequest:发起 Ajax 请求
- GM_download:下载某个文件到磁盘
- GM_setClipboard:将某个内容保存到粘贴板
更多相关 API 可查看:Tampermonkey • Documentation 了解
更多相关用法可阅读:https://zhuanlan.zhihu.com/p/99390731
简单实战分析使用
分析
分析网站:https://login1.scrape.center/
账号、密码皆为 admin,输入后点击登录,F12 → Network → login1.scrape.center → Payload 可以发现,提交的账号密码信息,POST 请求后变成了一个 token(身份验证,经过加密的字符串):
由此可知,网站将账户名和密码混为了一个新的字符串,然后经过了 Base64 编码,并赋值给 token 进行数据提交,网站 JavaScript 源码也经过打包工具进行了混淆,可读性较差:
Hook 定位入口
综上所述,我们需要寻找到 token 的入口,这里通过 Tampermonkey 自定义 JavaScript 脚本代码,实现 JavaScript 方法的 Hook 从而快速定位入口,上述分析,token 是以 Base-64 编码的,即需要找到 Base-64 编码的位置,在 JavaScript 中使用的是 btoa 方法将字符串编码成 Base-64 字符串(atob() 方法用于解码使用 base-64 编码的字符串):
JavaScript 中 btoa 方法可参考:https://www.cnblogs.com/lxg0/p/7543991.html
JavaScript Base-64 的编码及解码:https://blog.csdn.net/weixin_42420703
因此 Hook 到网站 JavaScript 脚本中的 btoa 方法即可,在 Tampermonkey 中编写:
// ==UserScript==
// @name HookBase64
// @namespace https://login1.scrape.center/
// @version 0.1
// @description Hook Base64 encode function
// @author Yy_Rose
// @match https://login1.scrape.center/
// @grant none
// ==/UserScript==
(function() {
'use strict';
function hook(object, attr){
var func = object[attr]
object[attr] = function(){
console.log('hooked', object, attr)
var ret = func.apply(object, arguments)
debugger
return ret
}
}
hook(window, 'btoa')
})();
这里定义了一个 hook
方法,传入 object
和 attr
参数,意思就是 Hook object
对象的 attr
参数。我们想要 Hook Base64 的编码方法,即 Hook window
对象的 btoa
方法。var func = object[attr]
,相当于我们先把它赋值为一个变量,我们调用 func
方法就可以实现和原来相同的功能,接着,改写这个方法的定义,将 object[attr]
改写成一个新的方法,在新的方法中,通过 func.apply
方法又重新调用了原来的方法,apply 方法会把集合中的元素作为参数传递给被调用的函数:
var func = function (a, b, c) {
console.log ([a, b, c]); // 输出 [1, 2, 3]
};
func.apply(null, [1, 2, 3]); // 数组中的 1,2,3 分别对应参数列表中的 a,b,c
这样我们就可以保证前后方法的执行效果不受影响的,而是在 func
方法执行的前后,再加入自己的代码,如 console.log
将信息输出到控制台,debugger
进入断点等,最后,调用 hook
方法,传入 window
对象和 btoa
字符串即可。
Hook 过程:
保存原有 func 方法 → 定义新方法接管控制权 → 增加新代码实现新功能 → 回调回 func 方法
编写完成后 ctrl + s 即可保存,上方会显示操作成功完成:
此时刷新网站页面,F12 → Sources → Page → Tampermonkey 即会发现我们编写的脚本文件被执行了,同时 Tampermonkey 也是启用状态,HookBase64 为我们编写的脚本文件并已被启用:
此时再输入用户名、密码,点击登录按钮,即会发现出现 Paused in debugger 提示,进入断点调试模式,并停了下来,Hook 成功,说明 JavaScript 代码在执行过程中调用到了 btoa 方法:
控制台 Console 输出了 btoa 和 window 对象,Hook 成功:
由下图可见,ret 就是 btoa 方法加密后的返回结果,arguments 就是指传给 btoa 方法的参数,是用户名、密码通过 JSON 序列化后的字符串,再经过 Base-64 编码之后 Ajax 请求参数 token 的值:
在 Call Stack(调用栈)中找到 onSubmit 方法的处理源码:
JSON.stringify(value[, replacer[, space]])
- 第一个参数是 value ,这是要字符串化的对象
- 第二个和第三个参数是可选的,若要自定义其编码方式(如分隔符和缩进),可以使用该参数
由上可知,encode 处调用了 btoa 方法,将表单中的内容进行了格式化处理,并进行了 Base-64 编码,可在此处添加断点进行验证,F8 或点击 此按钮恢复执行,跳过上一个 debugger 断点位置,重新点击登录,会停在刚刚打的断点位置,在右侧 Watch(监听)面板点击加号输入 this.form,发现此处向表单中添加了用户名和密码:
F10 或点击 按钮进行逐步调试,下一步即调到了我们之前 Hook 的 debugger 处,表明调用了 btoa 方法,Watch 中可看到返回的结果正好为 token 的值,成功定位到加密入口的位置:
总结
上述为 JavaScript 逆向中 Hook 技术的学习使用总结,如有错误或见解欢迎评论区指正交流~
参考资料:
https://www.cnblogs.com/lxg0/p/7543991.html
https://cuiqingcai.com/2022113.html
https://blog.csdn.net/hjxwudiha931721/article/details/76064165