网站在正在建设中,邢台市建设局安全监督管理网站,免费的网站空间,企业网站管理系统推荐题目#xff1a;抓取全部5页直播间热度#xff0c;计算前5名直播间热度的加和 地址#xff1a;https://match.yuanrenxue.cn/match/5
cookie中m值分析
首先打开开发者工具进行抓包分析#xff0c;从抓到的包来看#xff0c;参数传递了查询参数m与f#xff0c;同时页面中…题目抓取全部5页直播间热度计算前5名直播间热度的加和 地址https://match.yuanrenxue.cn/match/5
cookie中m值分析
首先打开开发者工具进行抓包分析从抓到的包来看参数传递了查询参数m与f同时页面中给了提示说cookie仅有50秒的有效期所以逆向参数可以直接通过cookie入手(在没有页面提示的情况下可以通过fd或者Charles抓包补全参数进行分析)。 那么现在就是需要找到m与RM4hZBv0dDon443M的生成逻辑直接搜索是肯定无法搜索的所以我们hook一下cookie进行跟栈。 第一次hook到cookie中m的值跟栈进入到上图箭头所指栈如下图。 明显地可以看到_$Fe值为字符串cookie那么在此处打上断点然后刷新页面跟一下_0x474032这个函数。之后会跟进一个虚拟机文件这里我们选择的是暂时在此处打上断点然后将这个文件中的代码全部复制下来放到本地的文本文件中方便后面我们查找相应的函数位置。 现在就可以开始抠代码了初步代码如下
function _0x474032(_0x233f82, _0xe2ed33, _0x3229f9) {return _0xe2ed33 ? _0x3229f9 ? v(_0xe2ed33, _0x233f82) : y(_0xe2ed33, _0x233f82) : _0x3229f9 ? _0x41873d(_0x233f82) : _0x37614a(_0x233f82);
}var _$Wa 1692681442000; // 时间戳从浏览器中复制而来完善后是动态生成的
var cookie_m _0x474032(_$Wa);接下来就是补函数了缺哪一个函数就补哪一个函数就可以。 后续过程重复不一一展示但是抠的时候需要注意源代码的先后顺序涉及到环境重置函数顺序抠错的话可能会导致后续结果不正确从而无法获取到数据。直到出现ReferenceError: _$UH is not defined这个异常。也就是补完_0x35f5f2这个函数之后 那么这个时候我们就需要去找一下这个_$UH究竟是怎样生成的一个变量了。首先来到浏览器console中简单查看一下(注意要同步跟栈)。 很明显其是一个固定的数组也就是说此处我们只要将这个_$UH数组抠下来声明一下。按照下图格式补齐。 补齐之后一共是四个键值对。
var _$UH {108: length,15: charCodeAt,31: toString,276: fromCharCode
};然后执行代码出现如下错误。 该错误是说history对象没有定义那么找的话就不用找它是在哪里声明的了因为history对象是浏览器中的历史浏览记录对象而这个对象自然就是存在于window之中那么就是说接下来我们要去补window环境是吗没错这里我们可能就疑惑了浏览器中有浏览记录但问题是现在我们是在本地啊历史个啥所以这里的逻辑可能就是在扯淡我们来通读一下。 首先这段逻辑是js中的异常处理代码块其中由于
op _0x4e96b4[$_zw][_$UH[0x6c]];这段代码出现异常导致代码执行进入了catch分支中那么我们就来浏览器调试一下op这个参数是个什么样子的情况。 先打上断点跟过来然后在console中一个个查看参数。 这样是不是就很明显了无非就是计算一个固定数组的长度赋值给op那么就是说正常情况下此处根本不会走到catch分支所以再来看下面的if语句。 在这里我们已经知道op的值为27而0x14的值为20所以这一大段逻辑说白了就是要给b64pad这个参数赋值。所以我们只要取得这个b64pad的值然后干掉这一大段代码就OK。 所以直接将b64pad 1赋值如下 之后再执行代码就又回到补函数阶段了。 直到_0x4e96b4这里此处根据源代码定义需要补window环境。 var _0x4e96b4 window {};之后又正常补函数补参数即可这里就可以直接补到最后补完了。输出结果查看一下。 看起来没什么大问题。但是我们来和浏览器中对比一下先这明显看起来是md5算法就算不是原装也不会影响同一内容加密结果不变。 很明显完全不一样那么也就意味着中间可能有一些东西影响了最终的结果至于是什么影响的其实很容易猜到那就是环境由于浏览器和nodejs环境的不同可能会导致部分逻辑走到另一条道路。而这里最容易走岔路的就是刚刚我们修改b64pad那个地方所以我们回过头来查看一下。 同样的首先查看一下此处的异常处理通过本地debug调试很明显可以看到他是走到了catch分支。 但是实际在浏览器中是否走的是catch分支呢老规矩找到对应位置下断点调试。记得要刷新页面。 断下来后按一下F10 很明显的并没有走catch分支那么也就是说此处也可直接修改修改之后如下。 再执行代码可以发现值已经发生了变化但是仍然和浏览器中的不同所以结果还是不对那么我们就要接着往下观察。紧接着下面还有一个异常处理的代码块这里其实就是对_0x4e96b4[_$6_]这个属性值的声明每一次进来的时候如果这个值已经存在了那就删除否则就重新赋值不管是出不出现异常也好都是对其进行赋值。但现在问题就是这个值从一开始的时候是存在还是不存在呢回到浏览器调试一下看看。 很明显他走到了else中而这是第一次请求因为我们一直都是在第一次请求中调试的即便刚刚重新打了断点我们也是刷新了页面的。所以这里其实就是将_0x4e96b4[_$6_]进行赋值。为了方便理解我们直接声明并赋值如下(在开头声明同时删除此处的异常处理逻辑)
_$6_ 0x20dc5d57f;值再一次发生变化但是明显与浏览器中仍然不同那么我们继续往下看。回到刚才那个函数。 在这里我们很容易能够看到一个对于_0x4e96b4[_$6_]的调用除此之外就在这个函数中往下翻还能够看到类似的两个参数。 所以此时这三个参数并没有值在本地那么就需要我们对其进行赋值刚刚_$6_已经赋值过所以只要进行修改即可另外的两个就需要我们去查找其对应的值然后再进行修改了。 在源文件中我们可以看到其是两个固定值所以我们只需要将这两个值进行全局声明即可。不要忘了函数中传参的时候修改。 改完之后再执行代码就会发现其值与浏览器中一致了那就是说关于cookie中参数m的生成逻辑我们已经完美实现了。 cookie中RM4hZBv0dDon443M值分析
接下来就是对另一个参数进行分析了。首先取消所有断点只留下一个cookie赋值处的断点然后刷新页面同时直接搜索RM4hZBv0dDon443M。 会发现根本搜不到值那怎么办呢结合代码混淆的特征来看这些字符可能是分开了的也可能是通过其他进制来表示了所以我们就把他们一个个拆分进行搜索例如搜一下首字母R但是很明显只搜一个R的话会出现很多个搜索结果所以我们可以添加引号来缩小搜索范围因为字符串要拼接的话肯定是有引号标识的。 三个搜索结果我们就可以一个一个去进行查看了。 检索到这里就发现有一点东西了那么我们先打上断点看一下代码是否能够在此处断下。 很明显代码完全能够在此处断下
_0x3d0f3f[_$Fe] R M 4 h Z B v 0 d D o n 4 4 3 M _0x4e96b4[_$ss] ;\x20path/;那么接下来我们就同样地来跟栈查看一下呢。当我们想要跟_0x4e96b4[_$ss]值的时候会发现它早已生成。按F8代码会在此断点处执行直到将cookie值赋值。 那么线索到这里就断了接下来怎么办呢既然此处已经是直接赋值到_0x4e96b4对象了那我就直接来找一下_$ss属性对应的值生成逻辑嘛这里就不太容易搜索了在不知情的情况下我们只能是大胆尝试先尝试一下搜_$(我是先搜了一下_$ss但是没有实际有用的结果然后又搜了一下_$还有只有一个引号的情况都是有很多干扰的结果最后搜_$才匹配上了) 定位到这里就先打上一个断点再说。然后把其他断点取消(因为已经没用了前面分析完了)然后刷新页面。 直接断下接下来我们就要来还原一下这段逻辑了。首先是入口处。 _0x4e96b4[_$ _$UH[0x348][0x1] _$UH[0x353][0x1]] _0x29dd83[_$UH[0x1f]]();将这一段代码还原一下将里面的符号放到console执行就能直接还原成更直观的代码了。 接下来就是改写放到本地的js代码中。然后就是来看一下_0x29dd83这个对象了。 刚好就是挨着的到这里其实基本上形式很明了了关键词mode、padding再加上上面又出现了一个A这十有八九就是AES加密了老规矩还是先来还原一下代码。 改写后写到本地代码中。 现在就缺_$Ww与_$qf两个参数了这两个参数前者为需要加密的内容后者为AES加密的密钥。依次跟一下这两个参数。_$Ww就在这段代码上方所以我们取出来还原一下先。
_$Ww _$Tk[enc][Utf8][parse](_0x4e96b4[_$pr][toString]())然后进一步跟一下_0x4e96b4[_$pr] 发现已经是生成好并添加到数组中了的所以接下来就是要找一下其值是什么时候添加到数组中的。这里其实还算明显的添加了五个元素这五个元素看起来都像是md5加密的结果所以我们大胆猜测它可能是前面生成的m的值。那么来搜索一下关键词_$pr 定位到刚才m值生成出明显可以看到当m值生成并赋值之后便将_0x474032(_0x3986ae)的结果也就是m值添加到了数组之中。那问题来了为什么是5个元素呢我们刷新页面继续来hook跟一下。 上面是刷新后第一次抓到的m的值之后一直F8直到代码在AES加密处断下。然后再来到控制台查看_0x4e96b4[_$pr]的值会发现刚好就是捕获到的5次m的值。 那么猜想验证正确所以在本地代码中我们就需要添加一个循环来将这五个值添加到数组之中了。代码如下图 接下来就是要找密钥了直接搜索_$qF 一步到位抠下来再慢慢还原。
_0x4e96b4[_$qF] CryptoJS[enc][Utf8][_$UH[0xff]](_0x4e96b4[btoa](_0x4e96b4[_$is])[slice](0x0, 0x10));改写为本地如下
_$qF _$Tk[enc][Utf8][parse](btoa(_$is)[slice](0x0, 0x10))接下来就只剩下一个_$is参数了 是一个时间戳精度到毫秒(验证比较简单搜索_$is就行文章中就不再演示了)。但是现在的问题就是这个时间戳是最开始的时间还是最后的时间这个必须要弄准确。所以还是直接搜索_$is定位过去。 这就很明显了每一次的_$is都是重新生成的也就是说这里是最新的时间戳也就是本地代码最后一次循环之后生成的。时间戳生成的代码如下
var _$is new Date().valueOf().toString();ok到这里我们就可以导入AES加密需要用到的模块了如果没有的话记得先npm install crypt-js下载安装一下。 接下来就是查询参数(params)中的m和f两个参数了。 这个其实就用不着分析了一看就知道是两个时间戳一个是起始时一个是最后cookie生成结束时的时间戳验证的话一样的hook一下跟下栈就很明显了。所以我们还需要记录一下任务开始时的时间戳以及任务结束后的时间戳。直接声明一个数组将每一次循环生成的时间戳添加到数组中最后去取值就ok。然后我们将代码改写一下添加一个入口函数代码如下
function run() {var _$Tk require(crypto-js)var _$pr new Array();var _$tt new Array();for (i0; i5; i){var _$is new Date().valueOf().toString();_$tt.push(_$is)var cookie_m _0x474032(_$Wa);_$pr.push(cookie_m)}_$Ww _$Tk[enc][Utf8][parse](_$pr[toString]());_$qF _$Tk[enc][Utf8][parse](btoa(_$is)[slice](0x0, 0x10));_0x29dd83 _$Tk[AES][encrypt](_$Ww, _$qF, {mode: _$Tk[mode][ECB],padding: _$Tk[pad][Pkcs7]});var cookie_ss _0x29dd83[toString]();return {cookie_m: cookie_m, cookie_RM4: cookie_ss, f: _$tt[0], m: _$is}
}接下来就去python中调用然后请求一下(完整代码最后提供现在先看分析)。 问题来了发现只有第一页有数据而后面几页的数据是没有成功获取的那么原因是什么呢很明显问题出在抠下来的js代码上。但是有一个我们能够确定的问题那就是代码的调用逻辑肯定是抠对的那么问题会出现在哪里呢
其实hook的时候我们已经知道cookie中m值的生成经历了5次那么每一次调用的逻辑难道都是一样的吗这一点从我们分析源代码的时候就能够看到源代码中是有多处地方对cookie进行赋值的所以我们又要回过头来看下每一次cookie在赋值的时候是否都是完全一致的呢直接刷新页面hook一下重新跟栈。 这是第一次捕获到m值的时候调用的堆栈跟进后如下 按F8跟第二次 与第一次是同一个栈所以问题肯定不是出在这里。
直到第四次捕获到m值的时候发现此时调用栈发生变化了它来到了一个与之前都不同的逻辑。 两边对比一下会发现两个逻辑的不同点就在于_$tT和_$Jy这两个参数是否有进行删除然后重新生成。其他时刻(除了第四次之外)_$Jy的值就是实时的时间戳但是_$tT的值明显就不太对了因为两个相邻的时间戳相减差距顶多只有几百毫秒而已所以_$tT的值我们还有待商议。现在现在将_$Jy搞定刚刚已经说了它在除了第四次之外就是一个实时的时间戳所以我们要找到在第四次的时候它的值为多少这里就直接搜索_$Jy就可以了。 这里第四个搜索结果打上断点然后按F8(不用再刷新界面)就会发现代码在这里直接断下那么也就是说这里的逻辑是调用了的同时还意外地发现了_$tT的值在第四次的时候也是一个固定值所以我们就可以将这二者直接写上了。
那么问题又来了如果不是在第四次的时候$_tT的值又是多少呢同样的办法搜索 定位到第7和第8个搜索结果打上断点这里就需要刷新页面了刷新后按F8看代码是否会断在这两个断点的其中之一。但是调试的时候明显是段不下来的然而我们来看这个条件是做了什么还原之后的条件代码如下
$_qp[$_qp[$_zw][0x9](window[$_zw][25][23])][protocol] http:这是不是就又来电了这不就是判断一下请求协议嘛如果是http的话就走if否则就else而这也直接导致了_$tT值的不同从而直接影响参数的生成结果。而requests库是一个基于urllib编写的用于发送http请求的模块所以此处必然不会出现异常的情况那么问题来了什么时候用if中的值什么时候用else中的值呢这里我们直接来对应第四次时的_$Jy值就OK如下图 此处调用(第四次捕获)时_$tT的值与if中一致所以第四次捕获时用的是if中的值其余时候用else。代码部分截图如下 到这里是否就成功了呢当然不是别忘了除了这两个比较特殊的变量之外我们还有一个特殊的变量那就是_$6_ 这个变量有没有可能也弄出点什么猫腻呢搜一下直接定位到最后一个结果 打上断点很惊喜的发现他成功在第四次捕获时断下(藏得有点深)那不就是说这个值被修改了嘛所以接下来直接把它也安排在第四次循环内就完事。最终修改后入口函数代码如下
function run() {var _$Tk require(crypto-js)var _$pr new Array(); // 会多出来一个空数组所以取值的时候要注意索引值var _$tt new Array();for (i0; i5; i){var _$is new Date().valueOf().toString();_$tt.push(_$is)var cookie_m _0x474032(_$is);_$pr.push(cookie_m)delete _$Jy;delete _$tT;if (i 3) {_$Jy -0x182c0438;_$tT -0x275e197f;_$6_ -0x173848aa} else {_$Jy new Date().valueOf();_$tT -0x2ac06b5b;}}_$Ww _$Tk[enc][Utf8][parse](_$pr[toString]());_$qF _$Tk[enc][Utf8][parse](btoa(_$is)[slice](0x0, 0x10));_0x29dd83 _$Tk[AES][encrypt](_$Ww, _$qF, {mode: _$Tk[mode][ECB],padding: _$Tk[pad][Pkcs7]});var cookie_ss _0x29dd83[toString]();return {cookie_m: cookie_m, cookie_RM4: cookie_ss, f: _$tt[1], m: _$is}
}成功撒花 完整代码请移步https://gitee.com/shuailiuquan/spider-code/tree/master
有任何疑惑请及时私聊本人处理
有任何疑惑请及时私聊本人处理
有任何疑惑请及时私聊本人处理