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.prototypeObject.prototype)来改变对象的默认行为。这是实现 Hook 技术的一个常见方式。
  • 闭包:JavaScript 中的闭包可以让你访问和修改外部函数的变量,即使外部函数已经返回。这使得你可以在原始函数外部“包裹”它,拦截调用,或者在原始函数执行之前或之后执行某些代码。
  • Proxy:从 ES6 开始,JavaScript 引入了 Proxy 对象,允许你通过拦截对对象的基本操作(如属性访问、函数调用等)来创建代理。这使得我们可以非常方便地拦截和修改对象的行为,是实现 Hook 技术的现代方式。
  • 修改全局对象:JavaScript 提供了访问全局对象(windowglobal)的能力,可以修改全局方法(例如 fetchsetTimeoutconsole.log 等)。通过覆写这些全局函数,我们可以插入自定义逻辑,从而达到 Hook 的目的。
  • 客户端拥有 JS 的最高解释权,可以决定在任何时候注入 JS,而服务器无法阻止或干预。服务端只能通过检测和混淆的手段,另 Hook 难度加大,但是无法直接阻止。

1.3为什么Hook

Hook 技术在爬虫中的作用,本质上是通过修改或拦截函数、事件、请求、响应等来模拟用户行为、绕过防护机制、捕获动态数据、以及优化爬虫效率。它为爬虫提供了一种灵活且强大的手段,尤其在面对复杂网页和高级反爬虫机制时,能够提高抓取成功率。

  • 通过拦截网络请求定位加密:当我们捕获到某个接口返回了加密的数据时,往往需要分析加密的过程,看看加密的函数在哪里被调用,或者通过某些特征识别加密算法。利用 Hook 技术,可以截获相关的网络请求、响应或前端脚本中的加密函数。
  • 通过 Hook 跟踪加密算法的执行:通过 Hook 技术,我们可以在 JavaScript 中跟踪加密函数的执行,例如截获加密算法的参数、结果或加密函数调用栈。通过这种方式,我们能够精确地捕获到加密数据的流向。
  • Hook 特定的加密库或函数:很多现代网站使用加密库(如 CryptoJSforgesjcl 等)来进行数据加密,通常这些库会提供一些常用的加密算法,如 AES、RSA 等。如果我们知道使用的加密库,我们可以直接 Hook 该库中的加密函数,从而捕获加密操作。
  • 分析 JavaScript 代码中的加密流:有时,页面使用了复杂的加密流程,例如多层加密或使用了密钥派生算法。通过在 JavaScript 代码中设置多个 Hook,可以帮助我们逐步分析加密流程中的每一个步骤。
  • Hook 调试与浏览器开发者工具结合使用:结合浏览器的 开发者工具Hook 技术,我们可以更高效地分析加密过程。通过在浏览器中设置 XHR 断点DOM 断点JavaScript 断点,再加上 Hook,可以帮助我们快速找到数据加密的代码位置。

1.4Hook步骤

Hook 步骤大致可以总结为以下几个关键点:

  1. 分析目标,定位需要 Hook 的函数或请求。
  2. 设置 Hook,拦截和修改 JavaScript 函数或网络请求。
  3. 调试与分析,跟踪加密过程并分析输入、输出数据。
  4. 模拟解密或绕过,破解或绕过加密步骤。
  5. 后续优化,提高爬虫或逆向过程的效率。

2.Hook方法

地址:https://fanyi.youdao.com/index.html#/TextTranslate

2.1控制台

JSON.parse = function(ps) {
        console.log("Hook JSON.parse ——> ", ps);
        debugger;    
}

在控台重写该方法

image-20250228004336321

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

image-20250228004433002

2.2代码段

hook-json.parse

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

image-20250228003820302

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...inObject.keys)。默认是 false
    • configurable: 布尔值,表示该属性是否可以被删除或者修改其特性(如 writableenumerable)。默认是 false
    • get: 一个函数,作为 getter,当访问属性时会被调用,默认是 undefined
    • set: 一个函数,作为 setter,当修改属性值时会被调用,默认是 undefined
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)

image-20250228005634766

地址:https://q.10jqka.com.cn/

通过 Object.definePropertyhook(拦截)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;
        },
    });
})();

image-20250228010200828

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请求,参数在请求地址上可以获取

image-20250228011319343

代码

(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);
    };
})();

image-20250228010852134

4.2云南省建设监管公共服务平台(Post请求)

地址:https://www.ynjzjgcx.com/dataPub/enterprise

url.indexOf("")这里判断你的请求参数,这里以分页请求/dataServ/findBaseEntDpPage为例

image-20250228013327699

代码

(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);
    };
})();

image-20250228013209386

5.XMLHttpRequest

5.1简介

文档地址:https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest

XMLHttpRequest(XHR)对象用于与服务器交互。通过 XMLHttpRequest 可以在不刷新页面的情况下请求特定 URL,获取数据。这允许网页在不影响用户操作的情况下,更新页面的局部内容。XMLHttpRequestAJAX 编程中被大量使用。

image-20250228014641369

open(method, url, async, user, password)

  • method:HTTP 请求方法(如 'GET''POST''PUT' 等)。
  • url:请求的 URL 地址。
  • async:布尔值,指定是否是异步请求。通常为 true,即异步请求。设置为 false 时会变为同步请求,但会导致阻塞,极不推荐。
  • user:可选,身份验证所需的用户名(适用于需要身份验证的请求)。
  • password:可选,身份验证所需的密码(适用于需要身份验证的请求)。

send(body):该方法用于发送请求。body 参数是请求体(在 POSTPUT 请求中常用),如字符串或 FormData 对象。对于 GET 请求,body 通常为 null

setRequestHeader(header, value):该方法用于设置请求头。你可以通过它来添加 HTTP 请求头(如 Content-TypeAuthorization 等)。

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 对象。

  • 对于 blobarrayBuffer 响应,返回二进制数据。

onreadystatechange:当 readyState 的值发生变化时,会触发 onreadystatechange 事件。你可以为这个事件指定一个回调函数,用来处理请求的响应。

5.2巨潮资源

确定请求和请求参数

# post请求
http://www.cninfo.com.cn/new/disclosure
# 参数
column=szse_latest&pageNum=2&pageSize=30&sortName=&sortType=&clusterFlag=true

image-20250228014129349

编写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')

image-20250228014334310

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

image-20250228014004858

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

image-20250228014225111

6.拦截器

1.1简介

使用 Axios 实现请求和响应拦截器

Axios 是一个基于 Promise 的 HTTP 客户端,常用于浏览器和 Node.js 环境。

  • 请求拦截器:在请求发送前对请求做处理。在发送请求之前或响应之后进行统一处理,常用于添加认证信息、处理响应数据、错误处理等。
  • 响应拦截器:在响应返回后对响应数据进行处理。在请求到达处理函数之前或响应返回之前进行处理,常用于权限验证、日志记录等。

安装包

npm install axios

image-20250228015619370

注意:不是所有的网站都会写拦截器

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))

image-20250228015715726

1.3查找响应拦截器

请求拦截器是异步的,不太好查找,但是请求拦截器和响应拦截器在一起,所以可以尝试查找响应拦截器。

hook网页的xhr,从发送请求send之前开始

image-20250228020803842

这些是发送XMLHttpRequest,接着执行

image-20250228021019986

找到响应拦截器

image-20250228021309540

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

image-20250228021416078

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

image-20250228021647363

发现在执行以下代码的时候数据进行了加密

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

image-20250228021856686

1.4查抄请求拦截器

也可以从Promise方法往下找

image-20250228022325461

也可以找到请求拦截器

image-20250228022758766

1.5执行流程

加载html --> 加载js代码  --> 触发请求接口(ajax)  --> 构造请求对象  --> 请求拦截器 --> 请求服务器 -->  返回数据 --> 响应拦截器 

📌 创作不易,感谢支持!
每一篇内容都凝聚了心血与热情,如果我的内容对您有帮助,欢迎请我喝杯咖啡☕,您的支持是我持续分享的最大动力!

wxzf
posted @ 2025-04-09 16:04  peng_boke  阅读(725)  评论(0)    收藏  举报