JS逆向- 0基础JS逆向练习题解
前言
JS逆向一直以来都是重难点,挖掘SRC,小程序常常会遇到各种签名与加密,不会JS逆向就寸步难行,但一旦逆向出来,往往会一马平川,发现各种越权漏洞……基于此,笔者找到一个靶场很适合新手师傅们从0到1地去学习JS逆向的各种场景,题目有难有易,覆盖多种实际场景(不是广子)。本文从原始的手工扣代码补环境出发,写了一份0基础题解(1-6),适合想入门JS逆向的师傅看,结合靶场题目动手练习,你会发现JS逆向其实也不难呢~

题一-基础爬虫
直接爬就完了,没有什么说的
1 | import requests |
题二-请求头伪造
需要注意的是要多加几个请求头,只加UA头还是无法绕过反爬机制
1 | import requests |
题三-无限debug
打开f12,本地替换对应的js文件,删掉debug相关代码即可
题四-sign逆向
F12调试翻页接口,发现请求参数携带签名sign和时间戳

如果我们要爬取计算出答案,就需要逆向出sign的生成算法,实时携带有效的sign去请求翻页获取数据
全局搜索sign,定位到生成逻辑

window.token = window.md5("tuling" + timestamp + pageNumber)
sign: window.token
说明sign的生成逻辑就是’tuling’拼接时间戳再拼接页数最后计算整体的md5值

但是要注意的是这个MD5函数,有可能是直接使用第三方官方库那么便简单了,直接调用即可,但是也有可能是自实现的或者进行了魔改加盐,这种情况就需要跟进一下相关函数,进行扣代码补环境,然后本地调用

发现md5函数定义,显然是自实现的,于是我们需要扣代码出来
在两个return处下断,发现走的是下面的支路

调用了l,h函数

后续的算法细节其实可以不必分析了,因为用到的函数都能很容易的找出来,直接开始扣代码,缺什么函数补什么函数就行

首先我们需要计算构造的参数是sign,先扣出最关键的一行生成代码,并把它赋值为sign
1 | const sign = window.md5("tuling" + timestamp + pageNumber) |
然后缺啥补啥
补上timestamp
1 | const timestamp = new Date().getTime() |
pageNumber需要动态传参,于是作为函数参数
1 | function getsign(pageNumber){ |
还缺少md5函数,直接copy过来
1 | window = this, function (n) { |

调试输出一下sign看是否缺少函数
1 | function getsign(pageNumber){ |

ok,到这里其实已经把环境补好了能够正常生成sign了
接下来实现python代码
还是和之前一样,先把架子搭建好,再解决sign的问题
1 | import requests |
可以看到我们python代码是缺少sign和timestamp参数值的,这两个参数需要从js代码里计算后取出,于是需要用到一个py与js交互数据的库,execjs
1 | pip install PyExecJS |
修改js代码,返回sign,timestamp字段
1 | function getsign(pageNumber){ |
修改python代码,读取4.js代码
1 | with open('4.js','r',encoding='utf-8') as f: |
调用getsign函数传入page值,并遍历,接收sign和timestamp再构造发起请求
1 | for page in range(1,21): |
最终脚本如下:
task4.py
1 | import requests |
4.js
1 | window = this, function (n) { |
运行出结果

题五-参数值逆向

可以看到参数值加密了
还是照样,全局搜索”xl”

打上断点验证一下看看数据流

const params = { page: pageNumber, _ts: timestamp, };
JSON.stringify({xl: encryptedQuery})
let encryptedQuery = encrypt(jsonString);
可以得出加密流程是把page和时间戳转为json然后拿给encrypt函数加密,观察encrypt函数

发现题五与题四的区别是加密函数代码被混淆了,但是其实仍然不影响我们直接扣代码

于是还是和之前一样,拿出生成xl的关键代码
1 | const jsonString = JSON.stringify(params); |
补params
1 | function getxl(pageNumber){ |
就差encrypt函数了,直接copy下来
1 | const _0x38addf = _0x66a7; |
还需要注意的是该段代码还调用库CryptoJS

这里有,直接下载crypto-js.js到本地即可

不要忘了使用const CryptoJS = require("crypto-js");导入该库
然后调试输出,成功生成xl的值

接着是python代码,就很简单了,直接在task4.py的基础上修改下就好了
task5.py
1 | import requests |
运行出结果

题六-请求响应逆向

可以看到请求包携带了签名S,以及时间戳Tt
响应也加密了

我们先搞定请求,定位到签名逻辑

hhh对象包含了签名s和tt时间戳

hhh的生成逻辑

我们直接补环境,还是一样,先拿出生成签名的关键代码
1 | function getreq(){ |
再全部把缺少的加密函数复制过来就行
1 | window = this, function (n) { |
还需要下载crypto-js.js到本地,并导入该库
1 | const CryptoJS = require("crypto-js"); |
运行调试一下,生成成功!

继续完整响应数据的解密
分析可得,data包含加密的响应数据t,xxxxoooo函数就是解密函数,接收data.t加密值进行解密

下断调试,运行打印一下就知道了

开始补环境,拿出关键解密代码
1 | function my_encry(data){ |
补齐解密函数和库,运行调试一下
解密成功

然后写py,在原来题5脚本基础上修改即可
先调整js,返回计算值
1 | function getreq(){ |
1 | import requests |
运行出结果

ok就写到这里,先更1-6,后面有空再更新,但其实网上已有完整的题解,只是我自认为我写得比较详细~
感谢师傅们的阅读~


