吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2692|回复: 27
收起左侧

[Web逆向] 某股票网ab_sr参数逆向分析

  [复制链接]
szh12123 发表于 2026-6-25 21:36
本帖最后由 szh12123 于 2026-6-25 21:41 编辑

本文章中所有内容仅供学习交流使用,不用于其他任何目的,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关!若有侵权,请联系作者删除。

目标网址:aHR0cHM6Ly9maW5hbmNlLmJhaWR1LmNvbS8=

获取最新股价信息需要两个关键参数一个是headers里面的acs-token,一个是cookies里面的ab_sr,acs-token以前的帖子讲过了,本次介绍ab_sr参数详细解析。

ab_sr需要通过这个网址请求https://xxxx.com/abdr?_o=https%3A%2F%2Fxxxxx.com,并且传入三个参数,主要就在于分析data是如何加密的,

image.png

当然如果只是为了获取信息的话,直接用密文请求ab_sr就行了,感觉没有时间戳验证,同一个密文可以一直用。
常规搜索data、abdr等关键词都搜不到,最后通过encodeURIComponent搜到,虽然搜索结果很多,但仔细一看不难发现abclite_2108的嫌疑最大,因为就他是混淆过后的,打几个断点,发现了密文位置,

image.png

但这里的混淆太多不好分析,于是简单写几个替换,先把b函数代码抠出来,保存到b.js,在python中调用b(),将原js文件中所有使用b()的正则匹配替换为运行结果,

[Python] 纯文本查看 复制代码
def func2str(text):
    rs = re.findall(r"(b\('0x[0-9a-fA-F]+'\))", text)
    rs = set(rs)
    with open('./b.js', 'r', encoding='utf-8') as f:
        js_code = f.read()
    ctx = execjs.compile(js_code)
    for i in rs:
        result = ctx.call('b', i[3:-2])
        if "'" in result:
            result = '"' + result + '"'
        else:
            result = "'" + result + "'"
        text = text.replace(i, result)
    return text


再将\x75\x72等转为字符串,

[Python] 纯文本查看 复制代码
def ascii2str(text):
    rs2 = re.findall(r"('\\x[0-9a-fA-F]+(?:\\x[0-9a-fA-F]+)*')", text)
    rs2 = set(rs2)
    rs2 = list(rs2)
    rs2.sort(key=len, reverse=True)
    for i in rs2:
        if i == r"'\x0a'":
            continue
        m = i.replace('\\x', '%')
        m = unquote(m)
        if "'" in m[1:-1]:
            m = '"' + m[1:-1] + '"'
        text = text.replace(i, m)
    return text


替换指定的字典常量,

[Python] 纯文本查看 复制代码
def dict2str(ph,text):
    for k, v in ph.items():
        text = text.replace(f"ph['{k}']", str(v))
    return text


这样就有了一个可读性良好的文件,

image.png

这样直接就搜索'data',很容易就找到了,

image.png

分析得知bM是AES-CBC加密,4个参数是明文,key,iv,bool控制输出hex字符还是base64字符。明文里面有好几十个参数,

image.png

每个参数值的设置位置直接搜索key值就可以直接找到,

image.png

分析不难但是有点繁琐,然后他是异步获取,懂一点递归的话理解起来很容易,就不一一分析了,直接放结果,下面是所有参数的含义:

[JavaScript] 纯文本查看 复制代码
var plaintext = {
    //运行document['createElement']('canvas')['getContext']('2d'),成功返回1,失败返回0
    "1": 1,
    //创建canvas添加各种参数,最后转str再用sha1加密,是固定值
    "3": "ea990cbXXXXX7dba9c",
    //screen['colorDepth']
    "4": 24,
    //屏幕总尺寸 screen['width'] + 'x' + screen['height']
    "5": "2560x1440",
    //屏幕可用尺寸 screen['availWidth'] + 'x' + screen['availHeight'])
    "6": "2560x1400",
    //屏幕X分辨率 [screen['deviceXDPI'] || '', screen['j'] || '']['join']()
    "7": ",",
    //浏览器所有插件navigator['plugins']的name值
    "8": "AdobXXXXXPlugin",
    //媒体类型标识符 navigator['mimeTypes']的description值
    "9": "npaXXXXXefox,,,,,,,,",
    //判断浏览器永久本地存储window['localStorage']是否存在
    "11": 1,
    //判断浏览器当前页本地存储window['sessionStorage']是否存在
    "12": 1,
    //获取值navigator['cookieEnabled']
    "13": true,
    //获取本地时间与 UTC 时间相差多少分钟 new Date()['getTimezoneOffset']()
    "14": -480,
    //获取值navigator['language']
    "15": "zh-CN",
    //获取值navigator['Va']
    "16": "",
    //判断媒体 MIME 类型是否支持,[存在document['createElement']('video')['canPlayType'],支持mp4,支持webm-vp8,支持webm-vp9,支持x-mpegURL]['join']()
    "17": "1,0,1,1,1,0",
    //获取设备物理像素与 CSS 像素的比率值window['devicePixelRatio']
    "18": 1,
    //获取CPU线程数navigator['hardwareConcurrency']
    "19": 12,
    //判断document['getElementsByClassName']('adsbox')[0]['offsetHeight']的值是否为0
    "20": 0,
    //不知道什么值,返回空
    "21": "",
    //获取值 [navigator['product'], navigator['productSub'], navigator['vendor'], navigator['vendorSub'], navigator['appCodeName'], navigator['appName'], navigator['platform']]['join']() 
    "22": "GecXXXXXn32",
    //获取值 [支持几个手指同时触屏, document['createEvent']('TouchEvent')是否存在, 手指是否触碰屏幕]['join']()
    "23": "0,0,0",
    //判断浏览器内置的本地数据库window['indexedDB']是否存在
    "24": 1,
    //获取 GPU 的真实供应商和渲染器型号字符串 [获取供应商,获取渲染器]['join']() 
    "25": "GooglXXXXX3D11)",
    //获取值navigator['userAgent']
    "27": "MozillXXXXXafari/537.36",
    //获取值 [判断document['getBoxObjectFor']是否存在, 判断window['opera']是否存在]['join']() 
    "28": "false,false",
    //获取值 ['undefined' == typeof window['eval']['prototype'], 'eval' === window['eval']['name'], -1 != window['eval']['toString']()['indexOf']('native')]['join']() 
    "29": "true,true,true",
    //判断document['body']['addBehavior']是否存在
    "30": 0,
    //获取内存大小值navigator['deviceMemory']
    "31": 8,
    //当前时间减去设置103时的时间
    "32": 122,
    //获取值navigator['platform']
    "34": "Win32",
    //获取值 [!!(navigator['D'] || navigator['I'] || navigator['va']),获取电量navigator['getBattery']是否存在]['join']() 
    "35": "false,true",
    //获取值电池是否充电 navigator['getBattery']()['charging'],超时返回-1
    "41": true,
    //获取值电池完全充满还需的时间 navigator['getBattery']()['chargingTime'],超时返回-1
    "42": 0,
    //获取值电池耗尽当前电量的时间 navigator['getBattery']()['dischargingTime'],超时返回-1
    "43": Infinity,
    //获取值电池电量 navigator['getBattery']()['level'],超时返回-1
    "44": 1,
    //返回空
    "58": "",
    //返回空
    "60": "",
    //返回空
    "61": "",
    //返回空
    "62": "",
    //判断 'webdriver' in navigator 
    "63": true,
    //判断navigator['ta']是否存在
    "64": false,
    //判断window['H']是否存在
    "65": false,
    //获取值 存在Object['getOwnPropertyDescriptor'](navigator,'webdriver'),则返回字符串长度,否则返回0
    "69": 0,
    //返回0
    "70": 0,
    //返回空
    "71": "",
    //获取值navigator['language']
    "72": "zh-CN,zh",
    //返回空
    "73": "",
    //返回空
    "74": "",
    //判断window中是否存在其中之一['cc11001100_hook', 'vpn_set_obj', 'vpn_get_obj', 'vpn_fn_call']
    "76": 0,
    //获取值 "[3, 8, 19, 25, 34] + [5, 6, 9, 14, 15, 27]中随机取两个作为key,取该字典对应的value值组成的列表,随机打乱顺序再sha1加密" + "_" + "前面value值对应的key值组成的列表合并再AES-CBC加密结果取hex"
    "78": "30e6XXXXX7ba7c_1a65XXXXX46dc",
    //判断这些属性是否是函数,是则返回获取的字符串长度,不是返回0,func = Object['getOwnPropertyDescriptor'];  [func(navigator['plugins']['name'])所有插件最后相加,func(screen['availWidth'])+func(screen['availHeight']),func(screen['width'])+func(screen['height']),func(navigator['hardwareConcurrency']),func(navigator['platform'])]['join']()
    "79": "0,0,0,0,0",
    //获取值 [0,0,0,判断navigator['maxTouchPoints']或navigator['msMaxTouchPoints']是否为函数,0]['join']() 
    "80": "0,0,0,0,0",
    //判断cookie是否包含指定的字符串,不包含返回1 window['RegExp']('function\s?\(\)\{return\sdocument')['test'](document['cookie']) 
    "81": 1,
    //通过_00la的所有代码判断_00la是否被篡改的sha1加密,是固定值
    "82": "54c7XXXXXe3b93",
    //该字典的key为[78, 101, 103, 82]的对应的值用'_'合并再sha1加密
    "85": "b97XXXXXd160c6",
    //'anti-bot-df' + Math['random']() + document['URL'] + document['referrer'] + navigator['userAgent'] + 该字典[103],再整体sha1加密
    "101": "62b1cXXXXX2892ac",
    //获取当前时间 new Date().getTime() 
    "103": 1780000000000,
    //固定值
    "106": 2108,
    //固定值
    "107": "3.11.4",
    //获取值 document['URL'] 
    "108": "https://xxxxx.com/",
    //获取值 document['referrer'] 
    "109": "",
    //获取值 window['__abbaidu_2108_zidgetf'] 
    "112": "",
    //获取值 window['__abbaidu_2108_bidgetf'] 
    "113": "",
    //获取值 window['__abbaidu_2108_subidgetf']或window['__abbaidu_20180315_subidgetf'] 
    "114": "",
    //获取值 window['__abbaidu_2108_extra_datagetf'] 
    "115": "",
    //'lid' + Math['random']() + document['URL'] + document['referrer'] + navigator['userAgent'] + new Date()['getTime'](),再sha1加密
    "116": "2904a8xxxxx155a9e",
    //固定值
    "130": "[]",
    //判断document['getElementsByTagName']('iframe')是否存在属性值,应返回"[]"
    "136": "[]",
    //获取值 window['eval']['toString']()['length']
    "198": 33,
    //获取值 navigator['H'] || '' 
    "199": "",
    //固定值
    "200": 1,
    //固定值,一个包含很多数学运算的列表用sha1加密,再取前8位
    "300": "d47288f3",
    //固定值,navigator的所有属性名称排序再合并,用sha1加密,再取前16位
    "301": "7ad0xxxxx4e20",
    //固定值,window的所有属性名称
    "302": "$BAxxxxxngth",
    //固定值
    "402": ""
};


他获取了很多信息,但最后发现有用的并不多,初始固定值只需要这些,很多信息还可以为空,

image.png

然后加上103、78、101、85、116的获取,就可以获取到股价信息,但这里如果只保留106和200两个参数也可以获取到ab_sr的值,但是在后续获取股价信息时,会请求失败。

image.png

抠代码分析参数加密过程,还有补环境,总共几大百行,简化成python后加上请求信息也就100来行。整体来说不算难,参数较多比较繁琐,当然也可能是这个网站没有太多的验证机制,很多参数并没有用上。

image.png

最后放一张请求成功图。

免费评分

参与人数 11威望 +1 吾爱币 +29 热心值 +10 收起 理由
wuai3456 + 1 + 1 谢谢@Thanks!
ioyr5995 + 1 + 1 我很赞同!
星绪173 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
junjia215 + 1 + 1 用心讨论,共获提升!
allspark + 1 + 1 用心讨论,共获提升!
zhangdashuaibi + 1 + 1 我很赞同!
gushengzhu + 1 谢谢@Thanks!
111mz + 1 我很赞同!
涛之雨 + 1 + 20 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
shiyue2925 + 1 + 1 谢谢@Thanks!
liuxuming3303 + 1 + 1 我很赞同!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

Shoto 发表于 2026-6-30 00:02
本帖最后由 Shoto 于 2026-6-30 00:29 编辑

大佬,请教一下里面的82.85是怎么分析出来的呀?我最近分析某度翻译的时候,有个接口跟这个一样。他主要是异步调用,分析堆栈或单步调试,调试了好久结果突然就出来了,求解答:
 楼主| szh12123 发表于 2026-6-30 12:53
Shoto 发表于 2026-6-30 00:02
大佬,请教一下里面的82.85是怎么分析出来的呀?我最近分析某度翻译的时候,有个接口跟这个一样。他主要是 ...

代码还原之后,搜数字就能收到他set的地方,异步调用前会先把要调用的函数传为参数,只是到运行时候再调用而已
AiGuoZhe66 发表于 2026-6-26 18:20
Saucerman 发表于 2026-6-26 18:28
支持技术贴
leader20 发表于 2026-6-26 21:10
但是他们家好用的数据不多吧
lizy169 发表于 2026-6-26 23:32
同道中人,大神辛苦了
zqz120 发表于 2026-6-27 06:58
感谢分享
netqing 发表于 2026-6-27 08:42
这个干嘛用的
XTDR12 发表于 2026-6-27 08:44
楼主大佬厉害,分析的透彻,学习了
半醉半醒半疯癫 发表于 2026-6-27 10:16
看着厉害,大佬。
天迹云间 发表于 2026-6-27 10:53
厉害👍🏻受教了
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-7-10 19:40

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表