作者:TheWeiJun
来源:逆向与爬虫的故事
今天给大家带来一个干货分享,由于想要查看某些APP的详细信息,需要通过APP名称去某麦网站进行搜索查看。而整个过程中涉及到逆向分析,为了方便大家学习,本次完整流程记录如下:
目录
一、确定要获取的内容
二、确定需要还原的参数
三、JS断点调试
四、JS算法还原
一、确定要获取的内容
首先我们要查询指定内容,如下:
我们想要获取APP信息,需要去获取这个搜索接口。具体链接不方便展示!考虑到安全问题。
通过浏览器Network分析,我们可以定位到数据地址如上!
二、确定需要还原的参数
其次我们通过分析url及参数信息如下:
params = (
('analysis', 'bFYNRVQDfUh+f1V/ChxadAxdXHhfG1lxV3ENXncQGhddVERTWB9ZXlRVG3cQBFcIBgcCBwgJAgUEIxQC'),
('country', 'cn'),
('search', '\u738B\u8005\u8363\u8000'),
('version', 'ios14'),
)
通过分析params参数,确定加密参数为: analysis
初次分析怀疑analysis应该是一个base64加密,故做如下尝试:
哈哈,果然不出我所料,没有想象的这么简单,那么接下来我们就要进行分析了,这个参数是如何产生的。
三、JS断点调试及算法还原
1. 查询指定关键字,定位参数坐标
在Network下点击搜索按钮进行查询,初次定位是不是通过接口返回的参数,搜索结果如下:
查看搜索结果,我们发现查询的内容不在response返回体内!那么我们就要看看是不是在sources搜索框中,可查看下图:
说明:经过查询,发现也定位不到关键字,那么搜索关键字analysis定位可以忽略掉了,我们可以肯定的是代码中没有用到这个变量名,但是加密的方式我们可以去搜索下,初步怀疑是base64,那么就搜下base64试试吧。搜索如下:
果然能查询到base64加密的js内容,那么这么多文件,我们如何查找是哪个呢?首先可以排除css格式结尾的文件,可以直接查看js格式的文件。
通过搜索,定位到了base64加密的坐标,如上图所示。那么我们接下来就要进行断点调试了!
2. 对js内容进行断点调试
先给如上js函数打断点,断点打完如下图所示:
查看断点内容,我们发现变量e即为我们要搜索的内容,可以肯定这个加密和函数h关系很大。
然后通过断点调试定位问题,可以查看如下展示:
通过分析上面两张图片,可以判断第一张图片的a属性与第二张图片的analysis的值是一致的,都是:
"bFYNRVQDfUh+f1V/ChxadAxdXHhfG1lxV39VLF4YXCVQUF9+XxtZcVdxXgpzFktLUFdCU1gfU1hVAFx7VBd5RUZZVHATAQMAUA4BDFIBAwAEcBMB"
可以证明,这个js变量a就是我们要查找的加密值analysis。那么我们接下来要做的就是算法还原了!
三、JS算法还原
/* r = 'Y25pb3MxNOeOi+iAheiNo+iAgOeOi+iAheiNo+iAgA==@#/search/checkHasAppid@#130392969664@#1';
说明:js中r的结果为上面,r的算法如下。
1. 通过js Console打印d的值为:'@#'
2. 通过js Console打印e.url.replace(e.baseURL, "")的值为:/search/checkHasAppid
3. 通过算法逆推,可以得出。
r = (0,
n.cv)(r);的结果为:Y25pb3MxNOeOi+iAheiNo+iAgOeOi+iAheiNo+iAgA==
4. 查看n.cv发现是对指定内容进行一个base64加密,解密得到结果如下:
r = "cnios14王者荣耀王者荣耀"; 也就是r = r.sort().join("") == "cnios14王者荣耀王者荣耀";
*/
var a, o = +new Date - true - 1515125653845, r = [];
o = 130392969664; // 将o的值与js调试的值保持一致
var r_ori = 'Y25pb3MxNOeOi+iAheiNo+iAgOeOi+iAheiNo+iAgA==@#/search/checkHasAppid@#130392969664@#1';
var r = "cnios14王者荣耀王者荣耀";
var e = "/search/checkHasAppid";
var d = "@#";
r = (0,
n.cv)(r),
r += d + e,
r += d + o,
r += d + 1;
console.log(r);
console.log(r_ori);
通过打印展示初始的加密值和人工还原的加密值,对比结果如下:
Y25pb3MxNOeOi+iAheiNo+iAgOeOi+iAheiNo+iAgA==@#/search/checkHasAppid@#130392969664@#1
Y25pb3MxNOeOi+iAheiNo+iAgOeOi+iAheiNo+iAgA==@#/search/checkHasAppid@#130392969664@#1
对比发现,r变量的值和原始值完全一致,那证明我们的r算法还原没有任何问题。接下来,我们分析一下a变量的生成!
/*
a 的值为:'bFYNRVQDfUh+f1V/ChxadAxdXHhfG1lxV39VLF4YXCVQUF9+XxtZcVdxXgpzFktLUFdCU1gfU1hVAFx7VBd5RUZZVHATAQMAUA4BDFIBAwAEcBMB'
说明:js中a的值为上面的结果,a的算法如下。
1. 通过js Console打印l的值为:"0000000c735d856",经过多次调试,这个值为固定值。
2. n.cv方法为base64加密。
3. n.oZ方法我们要进行还原,代码如下:
*/
// a = (0,
// n.cv)((0,
// n.oZ)(r, l));
var a_ori = 'bFYNRVQDfUh+f1V/ChxadAxdXHhfG1lxV39VLF4YXCVQUF9+XxtZcVdxXgpzFktLUFdCU1gfU1hVAFx7VBd5RUZZVHATAQMAUA4BDFIBAwAEcBMB';
var l = "0000000c735d856";
a = (0,
n.cv)((0,
n.oZ)(r, l));
console.log(a_ori);
console.log(a);
代码已经构造完成,我们直接打印结果,展示内容如下:
我们发现和原始的变量a值结果一致,那么整合算法如下:
var n = {};
function i(e) {
var t, a = (t = "",
["66", "72", "6f", "6d", "43", "68", "61", "72", "43", "6f", "64", "65"].forEach((function (e) {
t += unescape("%u00" + e)
}
)),
t);
return String[a](e)
}
function h(e) {
return function (e) {
try {
return btoa(e)
} catch (t) {
return base64(e)
}
}(encodeURIComponent(e).replace(/%([0-9A-F]{2})/g, (function (e, t) {
return i("0x" + t)
}
)))
}
function g(e, t) {
t || (t = s());
for (var a = (e = e.split("")).length, n = t.length, o = "charCodeAt", r = 0; r < a; r++)
e[r] = i(e[r][o](0) ^ t[(r + 10) % n][o](0));
return e.join("")
}
n.cv = h;
n.oZ = g;
function get_encdata(keyword) {
var l = "0000000c735d856";
var d = "@#";
var o = +new Date - 1515125653845;
var r = ["cn", "ios14", keyword];
r = r.sort().join("");
console.log(r);
r = n.cv(r);
var s = "/search/index"; // 根据url路径变动
r += d + s + d + o + d + 1;
a = (0,
n.cv)((0,
n.oZ)(r, l));
console.log(a);
return a
}
直接上python代码
headers = {
'sec-ch-ua': '" Not A;Brand";v="99", "Chromium";v="96", "Google Chrome";v="96"',
'accept': 'application/json, text/plain, */*',
'sec-ch-ua-mobile': '?0',
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.93 Safari/537.36',
'sec-ch-ua-platform': '"macOS"',
'sec-fetch-site': 'same-site',
'sec-fetch-mode': 'cors',
'sec-fetch-dest': 'empty',
'accept-language': 'zh-CN,zh;q=0.9',
}
ctx = js_load()
keyword = "王者荣耀"
params = (
('analysis', ctx.call("get_encdata", keyword)),
('country', 'cn'),
('search', keyword),
('version', 'ios14'),
)
response = requests.get('https://xxxxx/search/index', headers=headers, params=params, proxies=get_proxy())
print(response.text)
打印结果如下图所示:
本次分析到这里就结束了,欢迎大家阅读和交流!
我是TheWeiJun,分享工作或日常学习中关于爬虫、逆向和分析的一些思路,文中若有错误的地方,恳请大家联系我进行批评指正!
做一个爱分享的程序员,做一个爱学习的程序员!⛽️⛽️⛽️
如果喜欢我的文章,可以进学习群一起交流哦。
文章来源:逆向与爬虫的故事
微信搜:逆向与爬虫的故事;给我一个关注!