agid])) {
foreach ($g_flag_thread[$flagid] as &$val) {
flag_thread_filter($val);
}
flag_thread_set($flagid, $g_flag_thread[$flagid]);
}
}
return $g_flag_thread[$flagid];
}
// 设置缓存 $key = flagid / $val = flagid下tid数组
function flag_thread_set($key, $val)
{
global $g_flag_thread;
FALSE === $g_flag_thread and $g_flag_thread = website_get('flag_thread');
empty($g_flag_thread) and $g_flag_thread = array();
$g_flag_thread[$key] = $val;
return website_set('flag_thread', $g_flag_thread);
}
// 删除flag下tid缓存
function flag_thread_delete_cache($flagid)
{
global $g_flag_thread;
FALSE === $g_flag_thread and $g_flag_thread = website_get('flag_thread');
empty($g_flag_thread) and $g_flag_thread = array();
if (isset($g_flag_thread[$flagid])) {
unset($g_flag_thread[$flagid]);
website_set('flag_thread', $g_flag_thread);
}
return TRUE;
}
// Delete by tid / 通过tid删除flag下的主题和对应flagid缓存
function flag_thread_delete_by_tid($tid)
{
global $g_flag_thread;
FALSE === $g_flag_thread and $g_flag_thread = website_get('flag_thread');
if (empty($g_flag_thread)) {
$g_flag_thread = array();
} else {
$thread = well_thread_read_cache($tid);
$arrlist = flag_thread_find($tid, 1, $thread['flags']);
$flagarr = $ids = array();
foreach ($arrlist as $val) {
$flagarr[] = $val['flagid'];
$ids[] = $val['id'];
if (isset($g_flag_thread[$val['flagid']])) unset($g_flag_thread[$val['flagid']]);
}
website_set('flag_thread', $g_flag_thread);
// 主键更新
flag_update($flagarr, array('count-' => 1));
// 主键删除
flag_thread_delete($ids);
}
return TRUE;
}
// 主键删除 通过$flagid删除flag下的主题和对应flagid缓存
function flag_thread_delete_by_flagid($flagid)
{
global $g_flag_thread;
FALSE === $g_flag_thread and $g_flag_thread = website_get('flag_thread');
$read = flag_read_cache($flagid);
if (empty($read)) return TRUE;
$arrlist = flag_thread_find_by_flagid($flagid, 1, $read['count']);
if (empty($arrlist)) return TRUE;
$flagarr = $ids = array();
$n = 0;
foreach ($arrlist as $val) {
++$n;
$flagarr[] = $val['flagid'];
$ids[] = $val['id'];
if (isset($g_flag_thread[$flagid])) unset($g_flag_thread[$flagid]);
}
website_set('flag_thread', $g_flag_thread);
// 主键更新
flag_update($flagarr, array('count-' => $n));
// 主键删除
$r = flag_thread_delete($ids);
return $r;
}
?>break;
}
$r = array('filesize' => filesize($tmpfile), 'width' => $des_width, 'height' => $des_height);;
copy($tmpfile, $destfile);
is_file($tmpfile) && unlink($tmpfile);
imagedestroy($img_dst);
return $r;
}
/**
* 图片裁切
*
* @param string $sourcefile 原图片路径(绝对路径/abc.jpg)
* @param string $destfile 裁切后生成新名称(绝对路径/rename.jpg)
* @param int $clipx 被裁切图片的X坐标
* @param int $clipy 被裁切图片的Y坐标
* @param int $clipwidth 被裁区域的宽度
* @param int $clipheight 被裁区域的高度
* image_clip('xxx/x.jpg', 'xxx/newx.jpg', 10, 40, 150, 150)
*/
function well_image_clip($sourcefile, $destfile, $clipx, $clipy, $clipwidth, $clipheight, $getimgsize = '')
{
global $conf;
empty($getimgsize) AND $getimgsize = getimagesize($sourcefile);
if (empty($getimgsize)) {
return 0;
} else {
$imgwidth = $getimgsize[0];
$imgheight = $getimgsize[1];
if (0 == $imgwidth || 0 == $imgheight) {
return 0;
}
}
if (!function_exists('imagecreatefromjpeg')) {
copy($sourcefile, $destfile);
return filesize($destfile);
}
switch ($getimgsize[2]) {
case 1 :
$imgcolor = imagecreatefromgif($sourcefile);
break;
case 2 :
$imgcolor = imagecreatefromjpeg($sourcefile);
break;
case 3 :
$imgcolor = imagecreatefrompng($sourcefile);
break;
case 15: // WBMP
$imgcolor = imagecreatefromwbmp($sourcefile);
break;
case 18: // WEBP
$imgcolor = imagecreatefromwebp($sourcefile);
break;
}
if (!$imgcolor) return 0;
$img_dst = imagecreatetruecolor($clipwidth, $clipheight);
imagefill($img_dst, 0, 0, 0xFFFFFF);
imagecopyresampled($img_dst, $imgcolor, 0, 0, $clipx, $clipy, $imgwidth, $imgheight, $imgwidth, $imgheight);
$tmppath = isset($conf['tmp_path']) ? $conf['tmp_path'] : ini_get('upload_tmp_dir') . '/';
'/' == $tmppath AND $tmppath = './tmp/';
$tmpfile = $tmppath . md5($destfile) . '.tmp';
imagejpeg($img_dst, $tmpfile, 75);
$n = filesize($tmpfile);
copy($tmpfile, $destfile);
is_file($tmpfile) && unlink($tmpfile);
return $n;
}
function well_image_ext($filename) {
return strtolower(substr(strrchr($filename, '.'), 1));
}
?>
js逆向-腾讯滑块collect参数-软件玩家 - 软件改变生活!
目录
一、案例分析
提示:此篇文章并没有解决整个滑块部分,如明文如何生成都未研究,只是在已有明文的基础下,去研究了jsvmp执行的流程与插桩的尝试过程,仅仅是思路过程学习记录网址如下,研究的是这个接口aHR0cHM6Ly9tYWlsLnFxLmNvbS8= 下的collect参数和vData参数
二、collect参数定位与分析
搜索关键词collectdata定位,然后打上断点,然后滑动滑块,如图断住了
console界面输出x()函数,如图即生成了collect参数
在console界面打印x函数,点击进入发现collect其实就是a.getData(!0)生成的
仅接着打印a.getData函数,即进入jsvmp的代码里,最终在return __TENCENT_CHAOS_VM(x, U, T, M, c, E, Y, B)这里返回collect参数
单步调试进入__TENCENT_CHAOS_VM函数,我们会发现在如图位置反复执行,然后我们在266行这里插桩JSON.stringify(j.slice(-2)),输出日志,以及网上日志查看,根据经验先大概的猜测,长数字转乱码小串拼接,乱码小串base64得到collect
在反复调试的过程中,你会发现D是一个大数组,里面几乎都是函数,而U[w]决定了取哪个函数进行执行操作,而贯穿的j数组则是在j[j.length-2] 与 j.pop()反复的进行覆盖以及算术操作等,大致执行流程熟悉后,我们开始正式的插桩分析
第一次插桩打日志点,如下图,我是将线上的slide.js的js文件保存到本地为tencent.js,然后添加了部分插桩日志内容,然后用fiddler进行了替换输出
j[ j. length - 2 ] = j[ j. length - 2 ] + j. pop ( )
if ( typeof j[ j. length - 1 ] == "string" ) {
console. log ( "j栈的输出" , j[ j. length - 1 ] ) ;
}
如图,刷新后,线上console界面输出如下,可以知道collect由4个超长的字符串拼接而成,console界面输出的collect将所有的"+"替换为空collect.replace(/\+/g, " ") ,则和请求参数界面一致
第一组长串可知,超长串是由超长乱码串base64加密而得
超长的乱码串是由小的乱码串拼接而成,小的乱码串其实是由长数字转换而得
第二次插桩打断点,可以知道 Ç^ÿ °>乱码小串是由这个类似String.fromCharCode.apply(String, [199, 16, 94, 255])转换而得,下面就是要知道[199, 16, 94, 255]这个数字是怎么来的
"quality的输出" , M [ 0 ] [ M [ 1 ] ] , M [ 0 ] , F , quality
第三次添加条件断点M[0]==='{"cd' ,然后跳到这里停住后,继续加其它的日志
第四次加如下这些日志,在& / >>, j[j.length - 2], ">>>", j.slice(-1), "result is", j[j.length - 2]>>> j.slice(-1)[0],以及一些其它的日志断点,这些日志断点建议等条件断点断住后,再开放这些日志断点输出
"quality的输出" , M [ 0 ] [ M [ 1 ] ] , M [ 0 ] , F , quality
"fit" , fit, "F[0]" , F [ 0 ]
"shipment" , shipment
[199, 16, 94, 255]的由来如图,至此我们得到第一个算法函数LongNumToCode,长数字转成乱码小串,接下来就是研究[-10612537,1051754885]这个长数字是怎么来的,这个是最难的部分,是由另一个长数字经过tea算法转换而得
function LongNumToCode ( long_num ) {
var offsets = [ 0 , 8 , 16 , 24 ] ;
var codes = [ ] ;
for ( var a of offsets) {
codes. push ( long_num >> a & 255 ) ;
}
return String. fromCharCode . apply ( String, codes) ;
}
接着前面的输出日志继续分析,如图得到第二个算法函数StrToLongNum,这里得到两个长数字[ 1684218491, 811285026 ],与我们前面需要的长数字不一致,继续分析[ 1684218491, 811285026 ]接下来是干什么了
function StrToLongNum ( str ) {
var offsets = [ 0 , 8 , 16 , 24 ] ;
var long_num = 0 ;
for ( let i = 0 ; i < str. length; i++ ) {
long_num = long_num | ( str. charCodeAt ( i) << offsets[ i] ) ;
}
return long_num
}
继续分析,可以得到第二个算法函数tea加密算法,在图中会发现一个特征数字2654435769经常出现,此为tea加密算法 ,以及该大佬的文章也有说,还有逆向简史的大佬也有讲到,如图已知长数字[ 1684218491, 811285026 ],得到了新的长数字[-10612537,1051754885]
function teaEncryptBlock ( num_lis, key ) {
var num1 = num_lis[ 0 ] ;
var num2 = num_lis[ 1 ] ;
var sum = 0 ;
// 1194941531 '+' [592134] 'result is' 1195533665
// 1214603871 '+' [394760] 'result is' 1214998631
key = [ 1195533665 , 1214998631 , 1416189259 , 1481725512 ] ;
var delta = 2654435769 ;
for ( var i = 0 ; i < 32 ; i++ ) {
num1 += ( ( ( num2 << 4 ) ^ ( num2 >>> 5 ) ) + num2) ^ ( sum + key[ sum & 3 ] ) ;
// console.log("num1", num1)
sum += delta;
// console.log("sum", sum)
num2 += ( ( ( num1 << 4 ) ^ ( num1 >>> 5 ) ) + num1) ^ ( sum + key[ ( sum >> 11 ) & 3 ] ) ;
// console.log("num2", num2)
}
return [ num1, num2] ;
}
将前面分析的算法函数进行梳理下,然后输出如下,与网页结果保持一致,至此collect参数分析完毕,但是这些明文/轨迹的生成未研究,也是最难的部分,感兴趣可以自行试试
本文标签:
腾讯 滑块 参数 JS collect
发表评论