JS逆向入门加密参数定位与算法还原实战写给刚入行、看到加密参数就发懵的同学。不讲虚的从这个参数到底是怎么来的到我把它在本地跑出来一条完整链路走通。目录一、JS逆向到底是什么1.1 一个你一定遇到过的场景1.2 JS逆向到底要做什么1.3 哪些情况说明你该上JS逆向了二、动手前的工具准备2.1 浏览器开发者工具核心武器2.2 抓包工具2.3 本地运行环境三、JS逆向的标准五步流程3.1 第一步抓包找出可疑的加密参数3.2 第二步定位加密代码的位置3.3 第三步断点调试理清加密逻辑3.4 第四步扣取代码本地还原3.5 第五步验证结果是否一致四、加密参数定位的5种实用方法4.1 关键字搜索法最常用4.2 XHR断点法抓请求最直接4.3 调用栈追踪法顺着藤摸瓜4.4 事件监听断点法4.5 Hook拦截法高级但好用五、常见加密算法识别与还原5.1 编码类Base645.2 哈希类MD55.3 对称加密AES5.4 非对称加密RSA5.5 加密特征速查表六、实战案例还原一个真实的签名参数6.1 案例背景6.2 抓包定位6.3 分析加密逻辑6.4 本地还原代码6.5 用Python调用还原结果七、新手最容易踩的4个坑7.1 代码被混淆完全看不懂7.2 一打断点就跳走反调试7.3 扣出来的代码报错补环境7.4 本地算出来的值和网站不一致八、进阶方向与学习建议8.1 学完基础往哪走8.2 推荐学习资源写在最后一、JS逆向到底是什么1.1 一个你一定遇到过的场景你写了个爬虫想抓某个网站的数据。用 requests 请求接口结果返回的是请求非法或者一堆乱码。但你打开浏览器看同样的接口明明能返回正常数据。你对比了一下发现浏览器请求里带了一个你请求里没有的参数比如sign3a8f9c2e1b...长得像一串加密后的密文。这个sign是哪来的服务器怎么校验它的你的 requests 模拟不出来所以被拦了。这个找出 sign 怎么生成、然后在自己代码里复现它的过程就是 JS 逆向。1.2 JS逆向到底要做什么说白了就一件事搞清楚网页里那段 JavaScript 是怎么把明文变成加密参数的然后把这套逻辑搬到自己的代码里跑。它不是黑客技术也不是破解密码本身。加密算法比如 AES、RSA本身是公开的、安全的你破不了。你逆向的是网站用了哪个算法、传了什么参数、按什么顺序调用的这套调用逻辑。1.3 哪些情况说明你该上JS逆向了遇到下面任意一种基本都要考虑 JS 逆向现象说明请求参数里有sign、signature、token、enc_data这类看不懂的值大概率是前端加密生成的同一个接口浏览器能访问代码访问返回 403/412缺了某个校验参数返回的数据是一串密文页面却能正常显示响应被加密了需要逆向解密逻辑登录密码明文传输被拒密码在前端做了 RSA/AES 加密有滑块验证、风控参数如acw_sc__v2、_signature风控参数是 JS 算出来的二、动手前的工具准备2.1 浏览器开发者工具核心武器JS 逆向 90% 的工作在浏览器里完成。Chrome / Edge 按F12打开重点掌握四个面板面板干什么用Network网络抓包看请求参数、响应数据找加密参数Sources源代码看 JS 代码、下断点、调试逆向的主战场Console控制台直接执行 JS 代码测试函数、打印变量Application应用看 Cookie、LocalStorage判断哪些是本地生成的新手第一课打开任意网页按 F12在 Console 里输入document.title回车你会看到当前页面标题。这就是在浏览器里直接操作页面的感觉。2.2 抓包工具浏览器自带的 Network 面板够用 80% 的场景。需要更强大功能时上专业工具Fiddler / Charles能改请求、改响应、断点拦截适合调试mitmproxy命令行抓包适合做自动化Wireshark抓底层协议爬虫用得少新手先用浏览器 Network 面板熟了再上 Fiddler。2.3 本地运行环境把扣出来的 JS 代码跑起来需要本地环境Node.js直接node xxx.js运行最常用Python 的 PyExecJS / execjs在 Python 里调用 JS适合和爬虫代码整合PyV8 / mini-racer高性能 JS 引擎适合大量调用推荐组合逆向分析用浏览器 Node.js最终落地用 Python execjs。三、JS逆向的标准五步流程不管什么网站JS 逆向基本都走这五步。记住这个框架遇到新网站不慌。抓包定位加密参数 → 找到加密代码位置 → 断点调试理清逻辑 → 扣取代码本地还原 → 验证结果3.1 第一步抓包找出可疑的加密参数F12 打开 Network 面板勾选Preserve log保留日志跳转页面后不清空操作页面触发数据加载翻页、搜索、登录等找到返回目标数据的那个请求一般是 XHR/Fetch 类型看Headers里的请求参数、Payload里的表单数据挑出看不懂的、像加密的参数比如signa3f8e...、tokeneyJhb...经验参数名带sign、sig、signature、token、enc、secret、key、data且值是乱码的优先怀疑。3.2 第二步定位加密代码的位置知道哪个参数是加密的接下来要找到是谁生成它的。第五章会详细讲 5 种方法最常用的是关键字搜索和XHR 断点。目标在 Sources 面板里找到那行生成加密参数的 JS 代码。3.3 第三步断点调试理清加密逻辑找到代码位置后下断点重新触发操作让代码停在断点处。然后F8继续执行到下一个断点F10单步执行不进入函数内部F11单步执行进入函数内部关键顺着加密函数往里走Watch面板监听变量值的变化Call Stack看调用栈理清谁调用了谁这一步的目标是搞清楚输入是什么、经过哪些函数处理、输出是什么。3.4 第四步扣取代码本地还原理清逻辑后把关键的加密函数和相关依赖扣出来放到本地 JS 文件里运行。这就是常说的扣代码。扣代码的原则从加密入口函数开始缺什么补什么。调用了外部函数就一起扣用了第三方库如 CryptoJS就 npm 装一个。3.5 第五步验证结果是否一致本地跑一遍把生成的加密参数和浏览器里真实的参数对比完全一致 → 成功不一致 → 检查是不是少了时间戳、随机数、环境变量时间戳类参数每次都不一样验证时要用相同的时间戳对比别被这个误导。四、加密参数定位的5种实用方法这是 JS 逆向的核心技能。掌握这 5 种方法90% 的网站都能搞定。4.1 关键字搜索法最常用最简单直接在 Sources 面板里搜加密参数的名字。操作步骤Sources 面板Ctrl Shift F全局搜索输入参数名比如sign、signature看搜索结果找赋值的地方比如data.sign xxx点进去下断点验证搜索技巧参数名太短如sign噪音多可以加上点号或等号sign:、.sign 、sign搜接口 URL 的一部分也行比如接口是/api/list搜api/list或list搜加密关键词encrypt、md5、AES、setPublicKey4.2 XHR断点法抓请求最直接不知道参数在哪生成但知道是哪个请求带的用 XHR 断点请求一发出就断住直接看调用栈。操作步骤Sources 面板右侧找到XHR/fetch Breakpoints点输入请求 URL 的一部分比如api/list重新触发请求代码会断在发送请求的那行看Call Stack调用栈从上往下点找到拼参数的地方这是定位请求级加密参数最快的方法强烈推荐新手优先用。4.3 调用栈追踪法顺着藤摸瓜XHR 断点断住后或者 Initiator 里有调用栈时从栈顶往下逐层查看找到真正生成加密参数的函数。操作步骤Network 面板点目标请求看Initiator栏展开调用栈从上往下点每一层会跳到 Sources 对应代码行找到拼接请求参数的那层加密函数就在附近4.4 事件监听断点法参数是某个事件点击、提交触发的但搜索和 XHR 断点都不好用时上事件监听断点。操作步骤Sources 面板右侧Event Listener Breakpoints勾选对应事件比如Mouse click或Control submit触发操作代码断在事件处理函数单步往下走找到加密逻辑4.5 Hook拦截法高级但好用前面 4 种是找代码Hook 是拦截数据。适合参数被 set 到某处比如 Cookie、header时拦截。经典场景Cookie 里的某个值是 JS 生成的但搜不到赋值语句因为用的是document.cookie 这种。Hook 写法在 Console 里执行// Hook document.cookie 的 set打印谁设置了 cookievarcookieDescObject.getOwnPropertyDescriptor(Document.prototype,cookie)||Object.getOwnPropertyDescriptor(HTMLDocument.prototype,cookie);if(cookieDesccookieDesc.set){varoriginSetcookieDesc.set;cookieDesc.setfunction(val){console.log(有人设置了 cookie:,val);debugger;// 断住看调用栈originSet.call(this,val);};Object.defineProperty(document,cookie,cookieDesc);}执行后再触发操作谁设置 cookie 就会断住调用栈里就能看到加密函数。Hook 还能用Tampermonkey油猴插件注入页面刷新后自动生效更方便。五、常见加密算法识别与还原网站加密无非那几种算法。学会看一眼就知道是什么加密逆向效率翻倍。5.1 编码类Base64特征识别由A-Z a-z 0-9 /组成结尾可能有或长度是 4 的倍数例aGVsbG8解码后是helloJS 里常见调用btoa(hello)// 编码aGVsbG8atob(aGVsbG8)// 解码helloPython 还原importbase64 encodedbase64.b64encode(hello.encode()).decode()# aGVsbG8decodedbase64.b64decode(aGVsbG8).decode()# hello注意很多网站会魔改 Base64换字母表、加盐看到结构像但解不出明文先怀疑是不是改过。5.2 哈希类MD5特征识别固定 32 位十六进制或 16 位只能加密不能解密单向例md5(123456)e10adc3949ba59abbe56e057f20f883eJS 里常见调用一般用 CryptoJS 库CryptoJS.MD5(123456).toString()Python 还原importhashlib md5_valhashlib.md5(123456.encode()).hexdigest()# e10adc3949ba59abbe56e057f20f883eMD5 常用于生成签名sign md5(参数 时间戳 密钥)。看懂拼接顺序就赢了。5.3 对称加密AES特征识别密文是 Base64 或十六进制字符串需要密钥key和偏移量iv模式通常为 CBC 或 ECBJS 里一般用CryptoJS.AES.encrypt()JS 里常见调用varkeyCryptoJS.enc.Utf8.parse(1234567890abcdef);varivCryptoJS.enc.Utf8.parse(abcdef9876543210);varencryptedCryptoJS.AES.encrypt(明文,key,{iv:iv,mode:CryptoJS.mode.CBC,padding:CryptoJS.pad.Pkcs7});varciphertextencrypted.toString();// Base64 密文Python 还原fromCrypto.CipherimportAESfromCrypto.Util.Paddingimportpadimportbase64 keyb1234567890abcdef# 16字节ivbabcdef9876543210cipherAES.new(key,AES.MODE_CBC,iv)ciphertextbase64.b64encode(cipher.encrypt(pad(bmingwen,16))).decode()逆向 AES 的关键是拿到 key 和 iv。它们通常硬编码在 JS 里搜enc.Utf8.parse能找到。5.4 非对称加密RSA特征识别密文较长128/256 字节JS 里常见JSEncrypt、setPublicKey、encrypt关键词通常用于加密登录密码、生成 token公钥加密私钥解密前端只有公钥JS 里常见调用varencryptnewJSEncrypt();encrypt.setPublicKey(-----BEGIN PUBLIC KEY-----\nMIGfMA0G...\n-----END PUBLIC KEY-----);varencryptedencrypt.encrypt(password123);// Base64 密文Python 还原fromCrypto.PublicKeyimportRSAfromCrypto.CipherimportPKCS1_v1_5importbase64 public_keyMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC...# 从JS里抠出来的keyRSA.import_key(base64.b64decode(public_key))cipherPKCS1_v1_5.new(key)encryptedbase64.b64encode(cipher.encrypt(bpassword123)).decode()RSA 逆向重点是抠出公钥加密模式一般是 PKCS1_v1_5。5.5 加密特征速查表看到密文先对照这张表快速判断加密类型特征可能的加密方式32位十六进制MD540位十六进制SHA164位十六进制SHA256末尾有或A-Za-z0-9/Base64长密文JS里有CryptoJS.AESAESJS里有setPublicKey、JSEncryptRSAJS里有CryptoJS.DESDESeyJ开头JWTBase64编码的JSON一串十六进制长度固定可能是哈希或对称加密密文 搜 JS 代码里的关键词也能快速定位搜MD5、AES、encrypt、CryptoJS、JSEncrypt。六、实战案例还原一个真实的签名参数光说不练假把式。下面走一个完整的实战从抓包到 Python 还原一步步来。6.1 案例背景假设有个网站示例非真实站点列表接口/api/article/list带了一个sign参数。浏览器能正常返回数据用 Python requests 模拟就被拒绝。我们的目标搞清楚 sign 怎么生成的用 Python 复现它。6.2 抓包定位F12 → Network → 勾选 Preserve log刷新列表页找到/api/article/list请求看 Payload发现参数page: 1 timestamp: 1719720000 nonce: a3f8e2c1 sign: 9c4f2a8e6b1d7f3c5e0a9b8c7d6e5f4apage和timestamp一眼看懂nonce是随机串sign是 32 位十六进制——经典 MD5 签名。6.3 分析加密逻辑用 XHR 断点法定位Sources → XHR/fetch Breakpoints → 添加article/list重新翻页代码断在发送请求处看 Call Stack往下点几层找到拼接参数的地方看到这段代码functiongenerateSign(params){vartimestampMath.floor(Date.now()/1000);varnoncerandomString(8);varrawparams.pagetimestampnonceSECRET_KEY_2024;varsignmd5(raw);return{timestamp:timestamp,nonce:nonce,sign:sign};}逻辑一目了然拼接顺序page timestamp nonce 固定密钥算法MD5密钥SECRET_KEY_2024在 JS 里硬编码6.4 本地还原代码逻辑搞清楚了直接用 Python 还原不需要扣 JS 代码因为是标准 MD5importhashlibimportrandomimportstringimporttimedefgenerate_sign(page):timestampint(time.time())nonce.join(random.choices(string.ascii_lowercasestring.digits,k8))rawf{page}{timestamp}{nonce}SECRET_KEY_2024signhashlib.md5(raw.encode()).hexdigest()return{page:page,timestamp:timestamp,nonce:nonce,sign:sign}print(generate_sign(1))# {page: 1, timestamp: 1719720000, nonce: a3f8e2c1, sign: 9c4f2a8e6b1d7f3c5e0a9b8c7d6e5f4a}6.5 用Python调用还原结果把签名生成整合进爬虫importrequestsdeffetch_article_list(page):paramsgenerate_sign(page)urlhttps://example.com/api/article/listheaders{User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...,Referer:https://example.com/}resprequests.get(url,paramsparams,headersheaders)returnresp.json()# 翻页抓取forpageinrange(1,11):datafetch_article_list(page)print(f第{page}页:{len(data[list])}条数据)time.sleep(1)# 别忘了控制频率实战中遇到用标准算法MD5/AES/RSA的优先用 Python 库还原比扣 JS 代码稳定得多。只有魔改算法或自定义加密才需要扣 JS 用 execjs 跑。七、新手最容易踩的4个坑7.1 代码被混淆完全看不懂现象打开 JS 文件全是_0x1a2b这种变量名还挤在一行根本没法读。解决格式化Sources 面板左下角点{}按钮自动格式化缩进找入口不纠结每一行直接搜加密参数名从入口往里看用反混淆工具javascript-obfuscator的反混淆obf-io.deobfuscate.ioAST 解混淆用 Babel 写脚本批量还原变量名动态调试 静态阅读看不懂就下断点跑一遍变量值一清二楚经验别试图读懂整个混淆文件只关心加密链路。能跑通就够了能扣出来就是胜利。7.2 一打断点就跳走反调试现象下断点后代码不停或者直接跳到debugger死循环没法调试。解决条件断点右键断点行号 → Add condition写false跳过debugger语句Never pause here右键debugger那行 → Never pause here禁用所有断点后单步先禁用断点跳过反调试到目标位置再启用用 Overrides 替换文件把含反调试的 JS 下载到本地删掉debugger语句用 Local Overrides 替换反调试常见形式setInterval(function(){debugger;},100);// 定时 debugger// 或functioncheck(){debugger;setTimeout(check,100);}7.3 扣出来的代码报错补环境现象把 JS 代码扣到 Node 里运行报window is not defined、document is not defined之类。原因JS 代码里用了浏览器才有的对象window、document、navigatorNode 里没有。解决补环境// 最简单的补环境缺啥补啥varwindowglobal;vardocument{cookie:,createElement:function(){return{getContext:function(){returnnull;}};},getElementById:function(){returnnull;}};varnavigator{userAgent:Mozilla/5.0 (Windows NT 10.0; Win64; x64),platform:Win32,language:zh-CN};varlocation{href:https://example.com,hostname:example.com};进阶方案手动补太累时jsdomnpm install jsdom自动模拟整套浏览器环境Selenium / Puppeteer直接用真浏览器跑环境最真实但慢RPC浏览器和本地建通信通道直接调用浏览器里的加密函数不用扣代码7.4 本地算出来的值和网站不一致现象本地跑出来的 sign 和浏览器里的对不上。排查清单拼接顺序对吗abc还是cba少一个字符都不行密钥对吗密钥是不是动态的、从别处取的编码对吗MD5 之前是不是要 UTF-8 编码有没有转小写有没有时间戳/随机数这类参数每次都变要用同一组值对比是不是多重加密先 MD5 再 Base64先 AES 再 MD5环境差异浏览器里某些对象的值如navigator.userAgent和本地不一样最稳的验证方法在浏览器断点处把加密函数的输入参数抄下来本地用完全相同的输入跑对比输出。八、进阶方向与学习建议8.1 学完基础往哪走基础流程跑通后可以往这些方向深入方向内容难度Webpack 逆向网站用 Webpack 打包模块化加载需要理清模块调用关系⭐⭐⭐AST 反混淆用 Babel 写脚本自动化还原混淆代码⭐⭐⭐⭐JSVMP 还原虚拟机保护的 JS如某数的 vmp需要还原指令集⭐⭐⭐⭐⭐风控参数逆向滑块轨迹、设备指纹、_signature等风控参数⭐⭐⭐⭐App 逆向转战 AppFrida、XposedJS 逆向技能可迁移⭐⭐⭐⭐RPC 方案不扣代码直接调用浏览器里的函数省时省力⭐⭐⭐8.2 推荐学习资源文档与教程Chrome DevTools 官方文档https://developer.chrome.com/docs/devtools/MDN JavaScript 指南https://developer.mozilla.org/zh-CN/docs/Web/JavaScriptBabel HandbookAST 必读https://github.com/jamiebuilds/babel-handbook练习平台自建练习环境找几个开源的加密 demo 网站练手看公开案例CSDN、掘金、博客园搜JS逆向实战有很多 walkthrough工具收藏CryptoJS前端加密库识别它就知道大概率是 AES/DESJSEncryptRSA 加密库Tampermonkey油猴脚本注入 Hookastexplorer.net在线看 AST 结构学 AST 必备学习节奏建议第一周熟练用浏览器调试工具会下断点、看调用栈第二周练习 5 种参数定位方法每个都跑一遍第三周找 3-5 个简单网站实战MD5 签名类的第四周挑战一个 AES/RSA 加密的完整走通 Python 还原之后遇魔改加密学扣代码遇混淆学 AST写在最后JS 逆向看着神秘拆开就是一套固定流程抓包 → 定位 → 调试 → 还原 → 验证。新手最大的坎不是技术难而是不知道下一步该干嘛。记住几句话先抓包再逆向——连加密参数都没找到谈不上逆向动态调试优于静态阅读——看不懂的代码跑一遍就懂了标准算法用 Python 还原魔改算法才扣 JS——别什么都要扣代码从简单网站练起——别上来就挑风控最严的那个先建立信心每个成功还原的参数都是一次正反馈——积累多了你就入门了逆向是一门练出来的技能不是看会的。这篇文章给你一张地图路还得自己走。打开浏览器随便找个带sign参数的接口照着五步流程走一遍——你会发现没想象中那么难。如果这篇文章帮到了刚入行的你点个赞收个藏让更多同行看到。有疑问欢迎评论区交流我看到都会回。