17track接口逆向分析
没有放修改后的完整代码,纯粹的学习,谁有更好方法找到_0x4f3f里内存暴破,请指教啊!## 调试
17track的快递查询接口,可以通过调试工具看到请求,但是直接通过POST工具是没有结果的,最后测试需要加上Last-Event-ID这个cookie
![在这里插入图片描述]()
看了网页加载的js文件,最终只有一个加密的track.min.js,而且发现非常可疑的setCookie,还有Last-Event-ID字符。第一行是个数组,接下一共两个自执行的匿名函数。
```javascript
(function(_0x2297ee, _0x5f41f3) {
......
}(_0x50c7, 0x9f));
......
(function() {
var _0x10f375
......
_0x4cec2b();
}());
```
对这两个函数下断点,clear storage刷新然后一步一步调试。这里只要调用了函数的我们都对函数下断点。当跟到_0x4f3f这个函数的时候,发现很多地方都调用了这个函数,对返回下断点发现是返回的字符串。就把断点取消了继续跟,不然手要按软。第二个自执行函数最后调用的_0x4cec2b,_0x4cec2b最后又调用_0x3966d3,当断到_0x3966d3的时候已经能看到请求信息了,_0x164a16就是post的json,_0x152eb7就是一个ajax请求
![在这里插入图片描述]()
跟到_0x3966d3的时候,可以看到前两个参数是函数,最后是一个数字。继续一步一步走,注意_0x126b58 这个值是在变化的。
![在这里插入图片描述]()
最后在这里找到了Last-Event-ID,拿去post试一试,成功。
## 分析代码
我们还原设置Last-Event-ID的代码。
```javascript
document = _0x2ec18e(_0x316f08, '=') + _0x472ff2('') + _0x2ec18e + _0x1720d7();
```
直接在控制台调用_0x4f3f函数得到
```javascript
document["cookie"] = _0x2ec18e["GAOJi"]('Last-Event-ID', '=') + _0x472ff2["join"]('') + _0x2ec18e["FPaVy"] + _0x1720d7["toGMTString"]();
_0x472ff2["join"]('')//就是我们要的Last-Event-ID
```
_0x472ff2是重要变量,复制所有加密代码,格式化,放到新网页执行。哈哈哈,崩溃了。
![在这里插入图片描述]()
看来是有检测代码。这里我不知道怎么才能下断点,只有一步一步故意写错代码,看是先崩溃还是先报错确定了检测代码位置。有大佬有好方法没?
```javascript
_0x3184d0['prototype']['yzecjS'] = function() {
var _0x5e1a47 = new RegExp(this['IbesCh'] + this['kRbSMK']);
var _0x44235e = _0x5e1a47['test'](this['ZDEFCw']['toString']()) ? --this['LoqXko'] : --this['LoqXko'];//这里是一个正则匹配,把_0x44235e 设为-1就跳过了
return this['NUSOYG'](_0x44235e);
}
```
刷新执行,又报新的错误,这个错误直接显示了位置,下断点跟原网页对比
```javascript
var _0xd2c455 = function(_0x570d92) {
var _0x6d545d = ~-0x4 >> 0x1 + 0xff % 0x0;
if (_0x570d92['\x69\x6e\x64\x65\x78\x4f\x66']((!![] + '')) !== _0x6d545d) { //这个判断改为不成立即可跳过
_0x10cf6b(_0x570d92);
}
};
```
到这里,继续,还是报错,这个错误简单明了缺少jquery,在网页加上。搜索_0x3966d3 找到调用它的地方。
```javascript
_0x2ec18e($, document)(function(_0x2c3354, _0x28d1d7, _0x152eb7) {
if (_0x152eb7(_0x4f3f('0x8a', 'L*ZS')) && _0x152eb7['data']) {
_0x567d6b = _0x152eb7;
var _0x164a16;
try {
_0x164a16 = JSON['parse'](_0x567d6b);
} catch (_0x198faf) {
if (_0x2ec18e(_0x2ec18e, _0x4f3f('0x8e', 'PGF('))) {
var _0x574153 = _0x56b4ca(_0x3df0c1, str, seed);
if (tag) {
_0x472ff2 = _0x56b4ca(_0x2c724a, _0x574153(0x10));
return;
}
_0x472ff2 = _0x2c724a(_0x574153['toString'](0x10));
} else {
_0x164a16 = null;
}
}
if (_0x164a16 && _0x2ec18e(_0x164a16, '')) {
try {
_0x2ec18e(_0x9ff66b, _0x567d6b, _0x567d6b, !![]);
var _0x3fd2d0 = _0x4f3f('0x96', '7la!') + _0x4f3f('0x97', 'ttkq') + ']';
var _0x3a6885 = _0x2ec18e($, _0x3fd2d0);
_0x3966d3(_0x28d1d7, _0x3a6885, _0x1a395d(_0x3a6885));
} catch (_0x1739bd) {}
}
}
});
```
还原后
```javascript
$(document).ajaxSend(function (_0x2c3354, _0x28d1d7, _0x152eb7) {
if (_0x152eb7['url']['match']('(//+.17track.net/restapi/track)') && _0x152eb7['data']) {
_0x567d6b = _0x152eb7['data']; //post的数据 {"data":[{"num":"***","fc":0,"sc":0}],"guid":"","timeZoneOffset":-480}
var _0x164a16;
try {
_0x164a16 = JSON['parse'](_0x567d6b);//执行JSON.parse获得对象
} catch (_0x198faf) {
//这里省略掉
}
if (_0x164a16 && _0x2ec18e['ZIKlo'](_0x164a16['guid'], '')) { //guid参数为空
try {
//_0x2ec18e['WaYmY'](_0x9ff66b, _0x567d6b, _0x567d6b.length, true);
_0x9ff66b(_0x567d6b, _0x567d6b.length, true);//这句跟上面句相等,调用了_0x9ff66b传了data数据和长度,去看_0x9ff66b函数实际对_0x472ff2关键变量作了设置
var _0x3fd2d0 = _0x4f3f('0x96', '7la!') + _0x4f3f('0x97', 'ttkq') + ']';//_0x3fd2d0 = "";
var _0x3a6885 = _0x2ec18e($, _0x3fd2d0);//_0x3a6885 = $("");
_0x3966d3(_0x28d1d7, _0x3a6885, _0x1a395d(_0x3a6885));//调用_0x3966d3传入的参数,_0x28d1d7是XMLHttpRequest,_0x3a6885 = $(""),_0x3a6885 = _0x3a6885['length'] = $("").length,实际等于21,接下来是_0x1a395d函数传入了$("").length,
} catch (_0x1739bd) { }
}
}
});
```
_0x1a395d函数
```javascript
function _0x1a395d(_0x3e48ff) { //传过来的21
var _0x402f82 = _0x3e48ff;
if (window && document && window['innerHeight'] && window > 0x0) {//这里判断了innerHeight,我们要把这个判断去掉
var _0x5027d7 = window['random']();//_0x5027d7 = Math.random();
_0x402f82 = window['round'](_0x2ec18e(_0x5027d7, _0x3e48ff));//Math.round(_0x5027d7 * _0x3e48ff);//生成了一个随机数_0x402f82
}
//设置了关键变量_0x472ff2
_0x472ff2 = _0x402f82(0x10);//_0x402f82.toString(16);
_0x472ff2 = _0x402f82(0x10)['length'];//_0x402f82.toString(16).length;
return _0x402f82;//返回了这个数
}
```
_0x3966d3函数
```javascript
function _0x3966d3(_0x8517d0, _0xae9512, _0x1e1c09) { //_0x1e1c09 = _0x1a395d生成的数字,
var _0x126b58 = _0x4f3f('0x56', '#C9L');//_0x126b58= "yq-";
var _0x316f08 = _0x4f3f('0x57', 'tG@(');//_0x316f08 = 'Last-Event-ID';
if (_0xae9512 > _0x1e1c09 && document && document) {//$("").length > _0x1e1c09 && document && document['removeEventListener'],_0xae9512['length'] = $("").length;
_0x126b58 = _0xae9512['className'];//这里修改了_0x126b58值,最后我把_0x1a395d生成的数字设置为固定值,_0x126b58也设置成对应的className,可以去掉这个判断了。
}
_0x126b58 = _0x126b58 + '/' + window['now']()(0x10) + '/' + window(0x10) + '/' + _0x4ba351(); //_0x126b58 + '/' + Date.now().toString(16) + '/' + window.innerHeight.toString(16)+ '/' + _0x4ba351(); 最后咱是要脱离浏览器运行的,window.innerHeight.toString(16)可以设置为一个固定值,最后是_0x4ba351这个函数
_0x9ff66b(_0x126b58, _0x1e1c09);//_0x9ff66调用了_0x3df0c1,_0x3df0c1调用了_0x5e7be4,_0x5e7be4又有检测函数
_0x126b58 = _0x2ec18e(_0x3c4889, _0xd74c71(_0x126b58));
_0x472ff2 = _0x126b58;
//后面的代码已经没有用了,目的只为得到Last-Event-ID
var eid = _0x472ff2.join("");
return eid;
......
}
```
_0x4ba351
```javascript
function _0x4ba351() {//这个密密麻麻一大片,主要目的是生成XMLHttpRequest返回一个true,咱又不需要XMLHttpRequest。直接return true就好
if (_0x2ec18e === _0x4f3f('0x3a', 'VuqV')) {
var _0x2371bc = _0x4f3f('0x3b', 'f*#]');
var _0x135745 = _0x2ec18e;
if (objs > rndNo && document && document) {
_0x2371bc = objs;
}
_0x2371bc = _0x2ec18e(_0x2ec18e(_0x2371bc + '/' + window['now']()['toString'](0x10) + '/', window(0x10)), '/') + _0x2ec18e')](_0x4ba351);
_0x2ec18e(_0x9ff66b, _0x2371bc, rndNo);
_0x2371bc = _0x2ec18e(_0x3c4889, _0xd74c71(_0x2371bc));
_0x472ff2 = _0x2371bc;
if (navigator) {
var _0x55d807 = new Date();
_0x55d807(_0x2ec18e(_0x55d807(), 0x12c * 0x3e8));
document = _0x135745 + '=' + _0x472ff2('') + ';path=/;domain=17track.net;expires=' + _0x55d807();
_0x55d807 = new Date();
_0x55d807(_0x55d807['getTime']() + 0x12c * 0x3e8);
document['cookie'] = _0x135745 + '=' + _0x472ff2('') + ';path=/;domain=17track.net;expires=' + _0x55d807();
}
if (!_0x411c47(_0x135745)) {
xhr(_0x135745, _0x472ff2(''));
}
} else {
var _0x47b984;
try {
_0x47b984 = new XMLHttpRequest();
} catch (_0x3ef69c) {
try {
_0x47b984 = new ActiveXObject(_0x4f3f('0x54', 'VMDb'));
} catch (_0x494a23) {
try {
_0x47b984 = new ActiveXObject(_0x4f3f('0x55', 'jc9G'));
} catch (_0x1f73b5) {
return ![];
}
}
}
_0x47b984 = null;
return !![];
}
}
```
_0x5e7be4
```javascript
function _0x5e7be4(_0x14393c) {
if (_0x2ec18e(_0x4f3f('0x28', '7la!'), _0x4f3f('0x29', 'y*Cp'))) {
if (window && window && window > 0x0 && document && document['hostname'](_0x4f3f('0x2e', 'DYwS'))) { //if (window && window['innerWidth'] && window['innerWidth'] > 0 && document && document['location']['hostname']['match']('.17track.net')) { 让这个判断永远为true吧
if (!_0x14393c) {
_0x472ff2 = 0x1;
} else { //下面可以看到对_0x472ff2做了设置
if (_0x4f3f('0x2f', '!nz(') !== _0x4f3f('0x30', 'klod')) {
_0x472ff2 = 0x1;
} else {
_0x472ff2 = _0x14393c;
}
}
} else {
if (_0x4f3f('0x31', 'm^Gz') !== _0x2ec18e) {
that['console'] = function(_0x114f36) {
var _0x49a662 = {};
_0x49a662')] = _0x114f36;
_0x49a662 = _0x114f36;
_0x49a662')] = _0x114f36;
_0x49a662['info'] = _0x114f36;
_0x49a662 = _0x114f36;
_0x49a662 = _0x114f36;
_0x49a662 = _0x114f36;
return _0x49a662;
}(func);
} else {
_0x472ff2 = 0x0;
}
}
} else {
_0x472ff2 = _0x14393c;
}
}
```
最后我们删掉调用_0x3966d3的代码去掉,对所有使用$的地方已经设置为固定值,去掉第二个自执行函数,然后给_0x4cec2b加一个参数
```javascript
function _0x4cec2b(_0x567d6b) {
.....
_0x8f6309();
var _0x164a16 = JSON['parse'](_0x567d6b);
_0x9ff66b(_0x567d6b, _0x567d6b.length, true);
var eid = _0x3966d3(0, 0, _0x1a395d(21));
return eid;
}
```
最后直接调用就可以获得Last-Event-ID拉,拿着python或者nodejs去浪吧!
```javascript
var eid= _0x4cec2b('{"data":[{"num":"***","fc":0,"sc":0}],"guid":"","timeZoneOffset":-480}'));
``` 此外就是楼主问的格式化的问题
var _0x2333a0=_0x10f375(this,function(){var _0x4d2180=function(){return'\x64\x65\x76';},_0x326747=function(){return'\x77\x69\x6e\x64\x6f\x77';};var _0x2b03ab=function(){var _0x48fa7a=new RegExp('\x5c\x77\x2b\x20\x2a\x5c\x28\x5c\x29\x20\x2a\x7b\x5c\x77\x2b\x20\x2a\x5b\x27\x7c\x22\x5d\x2e\x2b\x5b\x27\x7c\x22\x5d\x3b\x3f\x20\x2a\x7d');return!_0x48fa7a['\x74\x65\x73\x74'](_0x4d2180['\x74\x6f\x53\x74\x72\x69\x6e\x67']());};var _0x209b4b=function(){var _0x1542e8=new RegExp('\x28\x5c\x5c\x5b\x78\x7c\x75\x5d\x28\x5c\x77\x29\x7b\x32\x2c\x34\x7d\x29\x2b');return _0x1542e8['\x74\x65\x73\x74'](_0x326747['\x74\x6f\x53\x74\x72\x69\x6e\x67']());};var _0x10cf6b=function(_0x10f4d5){var _0x1679be=~-0x1>>0x1+0xff%0x0;if(_0x10f4d5['\x69\x6e\x64\x65\x78\x4f\x66']('\x69'===_0x1679be)){_0xd2c455(_0x10f4d5);}};var _0xd2c455=function(_0x570d92){var _0x6d545d=~-0x4>>0x1+0xff%0x0;if(_0x570d92['\x69\x6e\x64\x65\x78\x4f\x66']((!![]+''))!==_0x6d545d){_0x10cf6b(_0x570d92);}};if(!_0x2b03ab()){if(!_0x209b4b()){_0x10cf6b('\x69\x6e\x64\u0435\x78\x4f\x66');}else{_0x10cf6b('\x69\x6e\x64\x65\x78\x4f\x66');}}else{_0x10cf6b('\x69\x6e\x64\u0435\x78\x4f\x66');}});
_0x2333a0();
开fd劫持一下页面的那个js,删掉上述正则防格式化部分就行(当然可以格式化后再保存到本地) 本帖最后由 涛之雨 于 2020-7-7 08:48 编辑
额。这是加密了,可以解密后再分析的。。。
我最近在研究这个{:301_1008:},等完善了会把源码扔出来。。。
现在有时候会出各种莫名其妙的bug(代码的不规范,版本的不同,抽取规则的不同都是问题)
此外他的代码应该是有禁止格式化,所以你格式化会出错(原理是正则表达式)
唔,貌似是买的高级版,方法有点复杂,看一下
有些地方定义的方法不一样。
半自动半手动吧,(变量没有办法还原,而且我也没看流程。。。)
截图是加密部分的(仔细看那个代码,前面一半全都是_0x变量,后一半都是没有处理过的。姑且称前面一半为加密部分吧)
变量建议分析后批量重命名。不然很难看懂 可以的,赞一个 萌新看不懂哦 这算不算简单点?狗头保命 {:1_936:}根本看不懂你所云。 太强了看不懂。。。 有点厉害>_> 非常好的分析,支持原创,支持发帖
页:
[1]
2