网站地址:aHR0cHM6Ly9iei56enptaC5jbi9pbmRleA==
今天分析了极简壁纸的js逆向,学习记录一下。
一、抓包
打开F12并点击翻页,直接开始抓包,筛选XHR的请求
![](http://maplestory.yueeronline.xyz/wp-content/uploads/2023/10/image-1024x441.png)
getData就是翻页的请求,查看一下返回的数据
![](http://maplestory.yueeronline.xyz/wp-content/uploads/2023/10/image-1-1024x155.png)
数据被加密了,接下来进行分析解密
二、断点分析
下一个getData接口的XHR断点,并点击翻页,定位到断点位置
![](http://maplestory.yueeronline.xyz/wp-content/uploads/2023/10/image-3-1024x322.png)
![](http://maplestory.yueeronline.xyz/wp-content/uploads/2023/10/image-2.png)
一路单步调试,可以看到醒目的'JSON["parse"]'、'["data"]["result"]'
![](http://maplestory.yueeronline.xyz/wp-content/uploads/2023/10/image-4-1024x482.png)
这里其实就是开始解密的位置,可以把鼠标放上去看一下变量值,就是getData接口返回的密文值
![](http://maplestory.yueeronline.xyz/wp-content/uploads/2023/10/image-5-1024x249.png)
而JSON.parse是解析json字符串的函数,那么解密函数就是这个_0x1addfb['a']['decipher']了,我们可以进去下断点,并继续运行跳到断点处
![](http://maplestory.yueeronline.xyz/wp-content/uploads/2023/10/image-7.png)
![](http://maplestory.yueeronline.xyz/wp-content/uploads/2023/10/image-9-1024x48.png)
可以看到是一个A(B(C(D)))的函数调用,而D就是需要解密的密文,三个函数都可以通过在Console里打印跳过去下断点
![](http://maplestory.yueeronline.xyz/wp-content/uploads/2023/10/image-10-1024x109.png)
其实他们就在嵌套函数的上面,可以分别进去单步调试,但可以发现这里并不是一些常规的MD5、AES等加密,而是纯算法运算,那就把这三个函数抠出来分析,为了方便称他们为A、B、C函数
![](http://maplestory.yueeronline.xyz/wp-content/uploads/2023/10/image-13-1024x479.png)
![](http://maplestory.yueeronline.xyz/wp-content/uploads/2023/10/image-14.png)
代码还原
根据调用顺序分析,先看C函数
![](http://maplestory.yueeronline.xyz/wp-content/uploads/2023/10/image-21.png)
C函数很简单,参数就是接口返回的密文。先用atob对密文进行了base64的解码,然后用charCodeAt将每一个字符转换为Unicode,并依次放进一个int8Array数组中
转换成Python代码
import base64
import numpy as np
# 编码转换
plaintext = base64.b64decode(ciphertext.encode("utf8")).decode("latin1")
# 构造int8Array数组
big_list = np.zeros(len(plaintext), dtype=np.int8)
for i in range(len(plaintext)):
big_list[i] = ord(plaintext[i])
这里JS的atob用python的base64库代替,JS的int8Array用numpy库的np.zeros(len(plaintext), dtype=np.int8)代替,需要注意的是base64解码后是字节类型,因为有很多特殊字符,用utf-8来decode会报错,要用"latin1"来解码。
运行结果对比
![](http://maplestory.yueeronline.xyz/wp-content/uploads/2023/10/image-22-1024x236.png)
![](http://maplestory.yueeronline.xyz/wp-content/uploads/2023/10/image-23-1024x93.png)
然后看B函数
![](http://maplestory.yueeronline.xyz/wp-content/uploads/2023/10/image-24-1024x377.png)
B函数里有很多十六进制的值,先用AST将其还原,将代码放入AST Explorer,通过选中值可以看到十六进制的值都是有一个extra属性的,而十进制的值是在value属性里,那么只需要删除所有NumericLiteral节点的extra属性,即可让十六进制的值转为十进制,方便分析
![](http://maplestory.yueeronline.xyz/wp-content/uploads/2023/10/image-25-1024x438.png)
对应AST函数
// 替换十六进制为十进制
function replace_0x0(path){
var node = path.node
if (node.extra === undefined){
return;
}
delete node.extra
}
还原后的代码
![](http://maplestory.yueeronline.xyz/wp-content/uploads/2023/10/image-26-1024x389.png)
将B函数中的代码略做调整,将每个逗号表达式都换成分号,转成一行新的代码
![](http://maplestory.yueeronline.xyz/wp-content/uploads/2023/10/image-27-1024x478.png)
按照格式和运算符,直接转成Python代码即可,语法上只有js的push函数要换成python的append方法,big_list变量是C函数的返回值
![](http://maplestory.yueeronline.xyz/wp-content/uploads/2023/10/image-28.png)
测试一下输出,结果一模一样
![](http://maplestory.yueeronline.xyz/wp-content/uploads/2023/10/image-29-1024x439.png)
![](http://maplestory.yueeronline.xyz/wp-content/uploads/2023/10/image-30-1024x87.png)
最后看A函数,做了大量的三元运算符的计算,并且计算的值都是十六进制的
![](http://maplestory.yueeronline.xyz/wp-content/uploads/2023/10/image-15-1024x630.png)
三元运算符、十六进制都可以用AST来进行还原,但还原之前先把代码做一下调整,这个函数里有一个for循环,这个for循环没有花括号,其实只有一行代码,把花括号加上,并把这一行代码里的前两个逗号换成分号,让这两个赋值语句和三元表达式不在同一条代码,方便后面用AST进行处理
![](http://maplestory.yueeronline.xyz/wp-content/uploads/2023/10/image-18-1024x472.png)
![](http://maplestory.yueeronline.xyz/wp-content/uploads/2023/10/image-16.png)
AST十六进制的处理和B函数处理时一致,而三元表达式需要转换为if else的形式,方便进行分析,即将所有ConditionalExpression节点替换为ifStatement节点
![](http://maplestory.yueeronline.xyz/wp-content/uploads/2023/10/image-19-1024x340.png)
对应AST处理
// 替换三元表达式为if else
function replace_conditional(path){
const {test, consequent, alternate} = path.node;
let ifstate = t.BlockStatement([t.ExpressionStatement(consequent)], [])
let elsestate = t.BlockStatement([t.ExpressionStatement(alternate)], [])
path.replaceWithMultiple(t.ifStatement(test, ifstate, elsestate));
}
替换完成后,A函数就变成了这个样子
![](http://maplestory.yueeronline.xyz/wp-content/uploads/2023/10/image-20-1024x597.png)
继续分析A函数代码,在循环中,是遍历B函数返回值的每一个元素赋值给_0x481fd7,然后进行 _0x481fd7 >>> 7 === 0的运算,无符号右移7位,并判断是否等于0,根据之前的运算,传入A函数的数组元素值的范围都在0~127之间,在这之间的所有值>>>7后结果都是0,也就是说这个嵌套if else结构只需要将第一个if中的语句提取出来就可以了
![](http://maplestory.yueeronline.xyz/wp-content/uploads/2023/10/image-31.png)
转换成Python代码就是很简单的将数组元素全部用chr从数字转换为字符,并拼接到一起,data变量为传入A函数的参数
![](http://maplestory.yueeronline.xyz/wp-content/uploads/2023/10/image-32.png)
分别运行对比一下
![](http://maplestory.yueeronline.xyz/wp-content/uploads/2023/10/image-33-1024x551.png)
![](http://maplestory.yueeronline.xyz/wp-content/uploads/2023/10/image-34-1024x123.png)
结果一致,加密数据被解密成了json字符串,那么这个混淆后的A(B(C))就已经完成反混淆并转换为Python代码了。
最后
分析这个站仅是为了达到学习的目的,由于极简壁纸是个人维护的免费网站,为了避免给站长造成不必要的困扰,就不贴完整代码了。
Comments | NOTHING