本次主要分析对象网址(base64):aHR0cHM6Ly93d3cubWVpeC5jb20vaXJlc2VhcmNoL3BhbmVsL2FsbE1lZXRpbmc=

一、对网站页面进行分析
分析浏览器抓包数据
第一步:检查静态html源码数据:
没有数据,只有一个框架,所有数据都是动态的
第二步:检查XHR请求接口数据:
有5个post请求,并且请求都是同一个地址;
每个请求携带的参数都进行了算法的加密;
每个请求返回的响应数据也是进行了算法加密的
注:该网站的数据就是从这5个接口获取的
第三步:确定首页会议活动数据接口位置:
滚动页面数据刷新,所以该页面是通过懒加载技术进行翻页的;
我们先清空XHR的所有网络日志记录,然后滚动页面,发现了一个新的接口;
经过多次测试,都只有这个接口产生,由此基本确定该接口即为我们需要获取数据的对象



二、加密入口分析
1)、通过上面确定的接口网址,全局搜索 “forword/all”;发现只有一个js文件包含 “forword/all”,降低我们的工作量;我们直接点进去进入js源码,从js文件名称可以知道该项目是由umi(乌米)前端开发框架开发的(不重要,了解就好,管他什么框架,与我无关!)

2)、打个断点,然后滚动页面,发送请求,定位断点

3)、发送post请求后,在这个接口断住了,发现这个a就是我们的请求参数

4)、往上找,发现a是一个对象
a = { // 这是一个js的三元运算符 a ? b : c (如果a为真,则取b,反之去c)
clientstr: 1 != m.enabled ? JSON.stringify(n) : f(n),
oldUrlFix: 1 != m.enabled ? e : f(e),
enabled: m.enabled
};

5)、我们得确定 “1 != m.enabled” 判断是真还是假:

1、往上找,发现 m 是一个对象,并且 “enabled = p”;
2、往上找 ,又是一个三元运算符 “p = d ? 0 : 1”;
3、往上找, d = "devtest.meix.com" === location.host
|| "demotest.meix.com" === location.host
|| "dev.meix.com" === location.host
|| "demo.meix.com" === location.host
这是判断当前host是否有全等
6)、在控制台中检测发现 "location.host"是等于’www.meix.com’

7)、经过以上分析得出:1 != m.enabled 是假;所以4) 中的 a 为如下:
a = {
clientstr: f(n),
oldUrlFix: f(e),
enabled: 1
};
8)、接下来,我们需要找出 加密函数 f、参数 n 和 e;打上断点;鼠标移动到 f,进入实际调用的方法里面;很明显里面的两个加密解密函数就是我们需要的


9)、确定 n 的生成逻辑;往上找,定义了n的生成逻辑;其实根据经验判断,这个 n就是跟翻页有关的参数对象了,我们也不需要再里面找怎么生成的逻辑,直接多翻页几次,把每次的 n拿出来比较久行了

10)、很明显参数里面只有页码在变化,这个页码我们可以自己传;并且在测试的时候也同时发现 e 这个参数是一个常量 “/pc/activity/getActivityList.do”

加密入口及参数都已经分析完了,接下来就是进入到了扣js代码环节
三、扣代码阶段
1)、把之前分析的, a对象、n对象、e、以及f 函数抠出来;
function encrypt(t) {
var a = JSON.stringify(t)
, o = i.AES.encrypt(a, u, {
iv: s,
mode: i.mode.CBC,
padding: i.pad.ZeroPadding
});
return console.log("0000", a),
console.log("11111", o.toString()),
console.log("222", e.decrypt(o.toString())),
o.toString()
}
var n = {
"currentPage": 1,
"showNum": 20,
"label": 0,
"orderType": 1,
"mapFlag": 1,
"activityRange": 0,
"stockRange": 0,
"activityType": 7,
"industry": [],
"companyCodes": []
}
var a = {
clientstr: encrypt(n),
oldUrlFix: encrypt("/pc/activity/getActivityList.do"),
enabled: 1
}
console.log(a)
2)、执行js后报 “i is not defined”;这是正常现象,很明显使用的是AES对称加密;那我们需要导入加密库;我们使用crypto-js,因为它提供了许多常见的加密算法;我们修改该一下代码,如下:
const CryptoJS = require("crypto-js");
function encrypt(t) {
var a = JSON.stringify(t)
, o = CryptoJS.AES.encrypt(a, u, {
iv: s,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.ZeroPadding
});
return console.log("0000", a),
console.log("11111", o.toString()),
console.log("222", e.decrypt(o.toString())),
o.toString()
}
3)、执行js后报 “u 未定义”;我们在源码中往上找,可以找到明文秘钥,以及后面的s也有;直接搞下来就行

function encrypt(t) {
var a = JSON.stringify(t)
, u = CryptoJS.enc.Latin1.parse("12345645678iaweb")
, s = CryptoJS.enc.Latin1.parse("1234567812345678")
, o = CryptoJS.AES.encrypt(a, u, {
iv: s,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.ZeroPadding
});
return console.log("0000", a),
console.log("11111", o.toString()),
console.log("222", e.decrypt(o.toString())),
o.toString()
}
4)、再次执行js,又报e未定义;不用慌,我们看看代码可以发现,e没有实际作用,只是打印,删掉这些没用的东西就好了
function encrypt(t) {
var a = JSON.stringify(t)
, u = CryptoJS.enc.Latin1.parse("12345645678iaweb")
, s = CryptoJS.enc.Latin1.parse("1234567812345678")
, o = CryptoJS.AES.encrypt(a, u, {
iv: s,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.ZeroPadding
});
return o.toString()
}
5)、再次执行,出现了我们想要的结果了,参数加密已经解决了;

6)、同理解密函数也是一样操作;断点,调试;解密我们已经解决了

7)、加密解密都解决了,剩下的就用python的模拟请求获取数据了
文章详细描述了对一个石油招标投标网站的深入分析,包括抓包、动态接口识别、AES对称加密解密过程,以及如何通过逆向工程找到并解决加密和解密函数。
1163

被折叠的 条评论
为什么被折叠?



