js逆向-hook
前言
我依旧敢和生活顶撞
敢在逆境里撒野
直面生活的污水
永远乐意为新的一轮月亮和日落欢呼
⚠️声明:本文所涉及的爬虫技术及代码仅用于学习、交流与技术研究目的,禁止用于任何商业用途或违反相关法律法规的行为。若因不当使用造成法律责任,概与作者无关。请尊重目标网站的
robots.txt协议及相关服务条款,共同维护良好的网络环境。
1.Hook技术
1.1简介
JavaScript Hook 技术,通常指的是在 JavaScript 环境中拦截和修改原本的函数或事件处理流程。这种技术在浏览器扩展、调试工具以及一些动态脚本中非常常见。它允许开发者对页面上的交互、事件、API调用进行监控、修改或者增强。
Hook 是一种钩子技术,在系统没有调用函数之前,钩子程序就先得到控制权,这时钩子函数既可以加工处理(改变)该函数的执行行为,也可以强制结束消息的传递。简单来说,修改原有的 JS 代码就是 Hook。
1.2原理
注意:JS 变量是有作用域的,只有当被 hook 函数和 debugger 断点在同一个作用域的时候,才能 hook 成功。
Hook 技术能够实现,主要得益于 JavaScript 的一些特性,包括:
- 动态性:JavaScript 是一种动态语言,意味着它可以在运行时修改、定义和操作代码。你可以动态地修改函数、对象、事件处理程序等,这为 Hook 技术提供了强大的支持。
JS是一种弱类型语言。 - 函数作为一等公民:在 JavaScript 中,函数是“一等公民”,也就是说,函数本身可以作为参数传递给其他函数,可以被赋值给变量,也可以被返回。这使得 Hook 技术可以通过修改或替换函数来拦截原始行为。
 - 原型链与继承:JavaScript 中的对象通过原型链继承方法和属性。你可以通过修改原型对象(如 
Array.prototype、Object.prototype)来改变对象的默认行为。这是实现 Hook 技术的一个常见方式。 - 闭包:JavaScript 中的闭包可以让你访问和修改外部函数的变量,即使外部函数已经返回。这使得你可以在原始函数外部“包裹”它,拦截调用,或者在原始函数执行之前或之后执行某些代码。
 - Proxy:从 ES6 开始,JavaScript 引入了 
Proxy对象,允许你通过拦截对对象的基本操作(如属性访问、函数调用等)来创建代理。这使得我们可以非常方便地拦截和修改对象的行为,是实现 Hook 技术的现代方式。 - 修改全局对象:JavaScript 提供了访问全局对象(
window或global)的能力,可以修改全局方法(例如fetch、setTimeout、console.log等)。通过覆写这些全局函数,我们可以插入自定义逻辑,从而达到 Hook 的目的。 - 客户端拥有 
JS的最高解释权,可以决定在任何时候注入JS,而服务器无法阻止或干预。服务端只能通过检测和混淆的手段,另 Hook 难度加大,但是无法直接阻止。 
1.3为什么Hook
Hook 技术在爬虫中的作用,本质上是通过修改或拦截函数、事件、请求、响应等来模拟用户行为、绕过防护机制、捕获动态数据、以及优化爬虫效率。它为爬虫提供了一种灵活且强大的手段,尤其在面对复杂网页和高级反爬虫机制时,能够提高抓取成功率。
- 通过拦截网络请求定位加密:当我们捕获到某个接口返回了加密的数据时,往往需要分析加密的过程,看看加密的函数在哪里被调用,或者通过某些特征识别加密算法。利用 Hook 技术,可以截获相关的网络请求、响应或前端脚本中的加密函数。
 - 通过 Hook 跟踪加密算法的执行:通过 Hook 技术,我们可以在 JavaScript 中跟踪加密函数的执行,例如截获加密算法的参数、结果或加密函数调用栈。通过这种方式,我们能够精确地捕获到加密数据的流向。
 - Hook 特定的加密库或函数:很多现代网站使用加密库(如 CryptoJS、forge、sjcl 等)来进行数据加密,通常这些库会提供一些常用的加密算法,如 AES、RSA 等。如果我们知道使用的加密库,我们可以直接 Hook 该库中的加密函数,从而捕获加密操作。
 - 分析 JavaScript 代码中的加密流:有时,页面使用了复杂的加密流程,例如多层加密或使用了密钥派生算法。通过在 JavaScript 代码中设置多个 Hook,可以帮助我们逐步分析加密流程中的每一个步骤。
 - Hook 调试与浏览器开发者工具结合使用:结合浏览器的 开发者工具 和 Hook 技术,我们可以更高效地分析加密过程。通过在浏览器中设置 XHR 断点、DOM 断点 和 JavaScript 断点,再加上 Hook,可以帮助我们快速找到数据加密的代码位置。
 
1.4Hook步骤
Hook 步骤大致可以总结为以下几个关键点:
- 分析目标,定位需要 Hook 的函数或请求。
 - 设置 Hook,拦截和修改 JavaScript 函数或网络请求。
 - 调试与分析,跟踪加密过程并分析输入、输出数据。
 - 模拟解密或绕过,破解或绕过加密步骤。
 - 后续优化,提高爬虫或逆向过程的效率。
 
2.Hook方法
地址:https://fanyi.youdao.com/index.html#/TextTranslate
2.1控制台
JSON.parse = function(ps) {
        console.log("Hook JSON.parse ——> ", ps);
        debugger;    
}
在控台重写该方法

再次请求的时候会进入到我们新修改的方法

2.2代码段
hook-json.parse
(function() {
    var _parse = JSON.parse;
    JSON.parse = function(ps) {
        console.log("Hook JSON.parse ——> ", ps);
        debugger;
        return _parse(ps);  // 不改变原有的执行逻辑 
    }
})();

3.Hook Cookie
3.1Object.defineProperty
WEBAPI地址:https://developer.mozilla.org/zh-CN/docs/Web/API
Object.defineProperty 是 JavaScript 中的一个方法,它允许你直接在对象上定义一个新的属性,或者修改现有属性的特性。通过该方法,你可以控制属性的访问行为、是否可以枚举、是否可以被修改等。
Object.defineProperty(obj, prop, descriptor):
obj: 需要添加或修改属性的目标对象。prop: 需要定义或修改的属性名。descriptor: 一个对象,包含关于该属性的配置选项。- value: 属性的值,默认是 
undefined。 - writable: 布尔值,表示该属性的值是否可以被修改。默认是 
false。 - enumerable: 布尔值,表示该属性是否可以出现在对象的枚举操作中(如 
for...in、Object.keys)。默认是false。 - configurable: 布尔值,表示该属性是否可以被删除或者修改其特性(如 
writable、enumerable)。默认是false。 - get: 一个函数,作为 getter,当访问属性时会被调用,默认是 
undefined。 - set: 一个函数,作为 setter,当修改属性值时会被调用,默认是 
undefined。 
- value: 属性的值,默认是 
 
user = {
    name: 'peng',
    age: 18
}
user_name = user.name
Object.defineProperty(user, 'name', {
    get: function () {
        return user_name
    },
    set: function (new_data){
        user_name = new_data
    }
})
console.log(user.name)
user.name='tom'
console.log(user.name)

3.2Hook Cookie
通过 Object.defineProperty 来 hook(拦截)document.cookie 的设置(set)和获取(get)操作。这样做的目的是当你尝试修改 document.cookie 时,能够拦截这个操作并执行自定义逻辑。以下是这段代码的详细解析:
cookieTemp = document.cookie:这行代码初始化了 cookieTemp,它保存了当前页面的 document.cookie 值。
set:当页面代码试图修改 document.cookie 时,实际上会调用这个 set 方法。
if (val.indexOf('v') != -1):如果试图设置的 cookie 值中包含字符 'v'(通过 val.indexOf('v') != -1 判断),则会触发 debugger,在浏览器开发者工具中触发调试断点。
get:当访问 document.cookie 时,实际上会调用这个 get 方法,它返回 cookieTemp 中保存的值,而不是直接访问原始的 document.cookie。
正常
hook cookie操作的时候需要清除下cookie
(function () {
    cookieTemp = document.cookie;
    Object.defineProperty(document, 'cookie', {
        set: function (val) {
            if (val.indexOf('v') != -1) {
                debugger;
            }
            console.log('Hook捕获到cookie设置->', val);
            cookieTemp = val;
        },
        get: function () {
            return cookieTemp;
        },
    });
})();

4.Hook XHR请求
这段代码的目的是 hook XMLHttpRequest.prototype.open 方法,以便拦截所有的 AJAX 请求,并在请求的 URL 中包含 analysis 字符串时触发调试器(debugger)。这对于调试、分析或者监控发送的请求非常有用,特别是在处理 AJAX 请求时。
var open = window.XMLHttpRequest.prototype.open;:这行代码将原始的 XMLHttpRequest.prototype.open 方法保存到 open 变量中,以便我们可以在后续代码中调用它。
window.XMLHttpRequest.prototype.open = function (method, url, async) {...}
:我们重新定义了 XMLHttpRequest.prototype.open 方法,所有通过 XMLHttpRequest 发出的请求都会触发这个新定义的方法。
if (url.indexOf("analysis") != -1):这行代码检查传入的 url 是否包含字符串 "analysis"。如果 URL 包含这个字符串,表示这是一个我们感兴趣的请求,接下来就会触发调试器。
return open.apply(this, arguments);:使用 apply 方法调用原始的 open 方法,确保请求能够继续正常发送,同时将当前的参数传递给原始 open 方法。
// 如果是正数 表示存在里面
// 如果是-1 表示不在里面
(function () {
    var open = window.XMLHttpRequest.prototype.open;
    window.XMLHttpRequest.prototype.open = function (method, url, async) {
        if (url.indexOf("analysis") != -1) {
            debugger;
        }
        return open.apply(this, arguments);
    };
})();
4.1七麦数据(get请求)
地址:https://www.qimai.cn/account/signin/r/%2F
url.indexOf("")这里判断你的请求 参数,这里是analysis
因为是get请求,参数在请求地址上可以获取

代码
(function () {
    var open = window.XMLHttpRequest.prototype.open;
    window.XMLHttpRequest.prototype.open = function (method, url, async) {
        if (url.indexOf("analysis") != -1) {
            debugger;
        }
        return open.apply(this, arguments);
    };
})();

4.2云南省建设监管公共服务平台(Post请求)
地址:https://www.ynjzjgcx.com/dataPub/enterprise
url.indexOf("")这里判断你的请求参数,这里以分页请求/dataServ/findBaseEntDpPage为例

代码
(function () {
    var open = window.XMLHttpRequest.prototype.open;
    window.XMLHttpRequest.prototype.open = function (method, url, async) {
        if (url.indexOf("/dataServ/findBaseEntDpPage") != -1) {
            debugger;
        }
        return open.apply(this, arguments);
    };
})();

5.XMLHttpRequest
5.1简介
文档地址:https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest
XMLHttpRequest(XHR)对象用于与服务器交互。通过 XMLHttpRequest 可以在不刷新页面的情况下请求特定 URL,获取数据。这允许网页在不影响用户操作的情况下,更新页面的局部内容。XMLHttpRequest 在 AJAX 编程中被大量使用。

open(method, url, async, user, password):
method:HTTP 请求方法(如'GET'、'POST'、'PUT'等)。url:请求的 URL 地址。async:布尔值,指定是否是异步请求。通常为true,即异步请求。设置为false时会变为同步请求,但会导致阻塞,极不推荐。user:可选,身份验证所需的用户名(适用于需要身份验证的请求)。password:可选,身份验证所需的密码(适用于需要身份验证的请求)。
send(body):该方法用于发送请求。body 参数是请求体(在 POST 或 PUT 请求中常用),如字符串或 FormData 对象。对于 GET 请求,body 通常为 null。
setRequestHeader(header, value):该方法用于设置请求头。你可以通过它来添加 HTTP 请求头(如 Content-Type、Authorization 等)。
abort():用于取消请求。可以在请求进行时调用,终止该请求。
readyState:表示请求的当前状态,值的范围是 0 到 4,表示不同的请求阶段:
0(UNSENT):open()尚未被调用。1(OPENED):open()已经被调用,但send()尚未被调用。2(HEADERS_RECEIVED):send()已经被调用,响应头已经返回。3(LOADING):响应体数据正在接收中。4(DONE):请求已完成,响应已完全接收。
status:该属性表示请求的状态码(HTTP 响应代码)。例如:
200:请求成功。404:请求的资源未找到。500:服务器内部错误。
statusText:该属性表示与 status 相对应的响应文本(例如 'OK','Not Found')。
responseText:该属性返回响应的内容,通常是字符串格式。可以通过它获取纯文本的响应。
responseXML:如果响应的类型是 XML,responseXML 将包含解析后的 XML 文档。
response:该属性返回整个响应内容。对于不同的响应类型,response 的值会有所不同:
- 
对于
text响应,返回字符串。 - 
对于
json响应,返回解析后的 JavaScript 对象。 - 
对于
blob或arrayBuffer响应,返回二进制数据。 
onreadystatechange:当 readyState 的值发生变化时,会触发 onreadystatechange 事件。你可以为这个事件指定一个回调函数,用来处理请求的响应。
5.2巨潮资源
确定请求和请求参数
# post请求
http://www.cninfo.com.cn/new/disclosure
# 参数
column=szse_latest&pageNum=2&pageSize=30&sortName=&sortType=&clusterFlag=true

编写XMLHttpRequest代码,发送Post请求,设置Header,并且带有参数
var xhr = new XMLHttpRequest()
xhr.open('POST', 'http://www.cninfo.com.cn/new/disclosure', true);
xhr.setRequestHeader('aaaa', '12345')
xhr.onreadystatechange = function () {
    if (xhr.status === 200) {
        console.log(xhr.response)
    }
}
xhr.send('column=szse_latest&pageNum=2&pageSize=30&sortName=&sortType=&clusterFlag=true')

使用控制台发送XMLHttpRequest,数据也成功返回

发送的请求也带上了自己设置的请求头aaaa

6.拦截器
1.1简介
使用 Axios 实现请求和响应拦截器
Axios 是一个基于 Promise 的 HTTP 客户端,常用于浏览器和 Node.js 环境。
- 请求拦截器:在请求发送前对请求做处理。在发送请求之前或响应之后进行统一处理,常用于添加认证信息、处理响应数据、错误处理等。
 - 响应拦截器:在响应返回后对响应数据进行处理。在请求到达处理函数之前或响应返回之前进行处理,常用于权限验证、日志记录等。
 
安装包
npm install axios

注意:不是所有的网站都会写拦截器
1.2代码
// npm install axios
axios = require('axios')
//设置请求拦截器
axios.interceptors.request.use(function (config) {
    console.log('请求拦截器 成功')
    config.headers['sign'] = 'lili'
    return config;
}, function (error) {
    console.log('请求拦截器 失败')
    return Promise.reject(error);
});
//设置响应拦截器
axios.interceptors.response.use(function (response) {
    console.log('响应拦截器 成功')
    console.log('调解密函数进行解密数据')
    //return response;
    return response.data; //修改响应数据
}, function (error) {
    console.log('响应拦截器 失败')
    return Promise.reject(error);
});
//发送请求
axios.get('http://httpbin.org/get').then(res=>console.log(res))

1.3查找响应拦截器
请求拦截器是异步的,不太好查找,但是请求拦截器和响应拦截器在一起,所以可以尝试查找响应拦截器。
hook网页的xhr,从发送请求send之前开始

这些是发送XMLHttpRequest,接着执行

找到响应拦截器

搜索[Wt],找到请求拦截器

找到请求拦截器,在请求拦截器方法开始打上断点,然后重新发送请求,因为需要寻找到加密的方法

发现在执行以下代码的时候数据进行了加密
a = (a += p + t[qt][T](t[Tt], N)) + (p + r) + (p + 3),
                    e = (0,
                    i[Jt])((0,
                    i[Qt])(a, d)),
                    -B == t[qt][O](v) && (t[qt] += (-B != t[qt][O](Bn) ? Nn : Bn) + v + B5 + R[V5](e)),
                    t

1.4查抄请求拦截器
也可以从Promise方法往下找

也可以找到请求拦截器

1.5执行流程
加载html --> 加载js代码  --> 触发请求接口(ajax)  --> 构造请求对象  --> 请求拦截器 --> 请求服务器 -->  返回数据 --> 响应拦截器 
📌 创作不易,感谢支持!
每一篇内容都凝聚了心血与热情,如果我的内容对您有帮助,欢迎请我喝杯咖啡☕,您的支持是我持续分享的最大动力!
                    
                
                
            
        
浙公网安备 33010602011771号