本篇文章仅用作学习使用,不可用于其他违法操作,如要搬运请声明出处
抖音WEB端加密参数逆向:
前置:
- 了解浏览器的一些断点调试方法,比如条件断点、日志断点、以及XHR/提取断点等
- 掌握一些js基本知识
- 浏览器开发者模式的使用
- 注意 apply和send
分析过程:
1. 选取接口
这里我选择的是抖音的关键词搜索接口(/aweme/v1/web/general/search/single
),可以选择其他的接口,原理相同
2. 接口分析
-
打开开发者模式,点击菜单栏
网络
选项,刷新页面,在网路面板上找到自己需要的接口请求,复制其cURL(bash)
,在https://curlconverter.com/
网站生成对应的接口爬虫 -
分析其请求参数,可以看到变化的未知参数包括 msToken、a_bogus等,将其分别注释掉进行请求发现,缺失掉任何一个参数都无法获取数据,在这里我们选择a_bogus进行分析
图 2.1 基础爬虫测试(分析参数)
3. a_bogus字段分析
使用全局搜索来搜索关键字
a_bogus
,发现js代码进行了混淆,没有搜索结果
通过源代码断点分析来获取a_bogus参数的计算:
-
使用XHR\提取断点来定位接口请求发送的位置(接口路径唯一)
设置断点后刷新页面即可
图 3.1 XHR断点设置
-
分析堆栈调用,定位
a_bogus
可能的生成位置堆栈的执行是从下到上,因此我们定位接口发送位置后从当前堆栈往前分析调用
*
a_bogus
参数的生成位置应该在携带a_bogus
*参数和未携带a_bogus
参数的堆栈调用之间,因此我们需要找到这两个堆栈-
在逐个分析堆栈调用的过程中需要注意作用域中是否存在
a_bogus
字段(一定要仔细,而且不要找到第一个就停下有可能是因为在这个堆栈下执行的是其他操作没有调用)
图 3.2.1 堆栈调用分析
-
最终我们定位到下面图所示的位置,可以看到第一幅图的
g
对象中还存在a_bogus
参数,但第二幅图中的t
对象中params字段中包含了其他的参数,但就是没有a_bogus
参数,因此我们大概定位到这两个位置中间。
图 3.2.2 加密位置定位1
图 3.2.3 加密位置定位2
-
从当前不存在
a_bogus
参数的堆栈位置进行调试(建议使用单步调试不会漏掉,调试过程中要注意url, params等字段中是否存在a_bogus
参数)图 3.2.4.1 加密位置追踪
调试后我们定位到了最先找到不存在
a_bogus
参数的位置,可以看到此处的代码做了混淆,因此我们要着重进行分析图 3.2.4.2 加密函数调用位置
-
-
第二步我们已经找出了可能的位置,而且此处的代码做了jsvmp混淆,因此我们对此处的代码进行进一步的分析,
-
大概读一下代码可以看到此处
s.apply(b, u)
函数进行了循环执行,为了更加方便的查看函数的返回值我们可以在此处设置一个日志断点
,如下图所示我们在此函数位置设置一个日志断点,日志的输出值就改为函数输出(注意一定要把本行的其他不相关断点去除,例如图中的灰色断点)
图 3.3.1.1 日志点分析代码运行
接下来我们刷新页面,查看控制台的日志信息,可以看到函数的输出包括了true、false、数字以及一长一短的字符串,仔细观察就可以发现这两段字符串是成对出现的,而且长的字符串是我们的请求参数中除了
a_bogus
之外的其他所有参数,因此我们猜想另一个字符串就是我们所需要的a_bogus
参数值,而且a_bogus
参数的生成与剩下的其他参数有关图 3.3.1.2 日志点结果分析1
-
尝试去查看
a_bogus
参数的长度是否为固定值或者其他,结果如下图所示,基本都在160左右的长度图 3.3.2 日志点结果分析2
-
因为函数每次执行的结果都不固定,因此并不是
s
对应的函数就是我们的目标函数;我们需要在函数结果为a_bogus
时进行进一步判断,因此我们可以使用条件断点来定位生成a_bogus
参数的时候。而条件断点的条件就可以使用我们上一步发现的长度特征(可以多尝试几个值),也可以像下图所示直接给定大概范围(推荐)。图 3.3.3.1 进一步分析函数调用
刷新定位到即将生成
a_bogus
参数的时候,此时的s
函数对应的才是我们的目标函数最终的目标函数如下图所示
e
图 3.3.3.2 最终定位结果
-
-
第三步我们已经定位到了生成
a_bogus
参数的函数,且函数在bdms.js文件中,因此我们将此文件复制到本地,接下来就是运行js文件根据报错信息进行补环境
的操作(报错缺什么就补什么),只需要添加下面的代码即可//初始测试文件执行时补的环境 window = global; delete global; delete Buffer; window.requestAnimationFrame = function(){}; XMLHttpRequest = function() {}; // 分析导出自定义加密函数的补环境 document = {} navigator = {}; screen = { availHeight: 816, availLeft: 0, availTop: 0, availWidth: 1536, colorDepth: 24, height: 864 }
-
补环境完成后,我们就需要写出调用的函数
-
根据上述
图 3.3.3.2
分析结果定位到e
函数,将e
函数体内的代码复制到我们新建的函数中 -
s.apply(b,u)
其中s即为被b调用的函数e
,b为null,u
即为 传给e
的参数,因此我们将u
的内容替换你给e
函数的arguments
即可 -
e
函数中调用了e
对象,因此我们需要将e
对象变为全局对象,方便我们重写的e
函数的调用,而 u = e , 因此我们只需要在对应位置添加window.sign_z = u
(可以自行替换只是为了方便调用) 即可function getSign(u) { var r = window.sign_z._v; return (0,window.sign_z._u)(r[0], u, r[1], r[2], this) }
-
查看传递参数
u
的结构可以看到u中的变量其实就是我们之前的params,也就是请求参数中除去
a_bogus
以外的其他参数,因此我们直接将u
的其他部分变为固定部分,传参只需要传 params部分即可{ 0, 1, 14, "device_platform=webapp&aid=6383&channel=channel_pc_web&update_version_code=170400&pc_client_type=1&version_code=170400&version_name=17.4.0&cookie_enabled=true&screen_width=1536&screen_height=864&browser_language=zh-CN&browser_platform=Win32&browser_name=Edge&browser_version=124.0.0.0&browser_online=true&engine_name=Blink&engine_version=124.0.0.0&os_name=Windows&os_version=10&cpu_core_num=8&device_memory=8&platform=PC&downlink=10&effective_type=4g&round_trip_time=50&webid=7372443638851700278&msToken=RAN6gBw2k5zWgxEMr76NR0Y_cOXURITuC-Mfs3x_fXfErJxuG2RgY7vDI_Ufn8fyen2tiabQOudk5mm9E6V4HxCV5M6Q3Yy1DWMvzuLzN3KDdT2IpuptBKXquSRtWw%3D%3D", "", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0" }
-
最终代码
function getSign(params) { u = [ 0, 1, 14, params, "", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0" ] var r = window.sign_z._v; return (0,window.sign_z._u)(r[0], u, r[1], r[2], this) }
-
4. 最终测试代码
import requests
import execjs
import urllib.parse
headers = {
'accept': 'application/json, text/plain, */*',
'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
'cookie': 'SEARCH_RESULT_LIST_TYPE=%22single%22; csrf_session_id=317e9b5acd9f05e6772b67308797f1d2; bd_ticket_guard_client_web_domain=2; passport_csrf_token=4686e09bbb44d3c2d83aaa91f51c9402; passport_csrf_token_default=4686e09bbb44d3c2d83aaa91f51c9402; douyin.com; device_web_cpu_core=8; device_web_memory_size=8; architecture=amd64; dy_swidth=1536; dy_sheight=864; strategyABtestKey=%221716534550.113%22; volume_info=%7B%22isUserMute%22%3Afalse%2C%22isMute%22%3Atrue%2C%22volume%22%3A0.5%7D; xgplayer_user_id=403702046813; s_v_web_id=verify_lwkccp8o_HtjPb5ZW_KL6c_4hMu_AjLQ_yPizGCdW7mb8; FORCE_LOGIN=%7B%22videoConsumedRemainSeconds%22%3A180%2C%22isForcePopClose%22%3A1%7D; ttwid=1%7CXWiikvNYNxGT0F8soSTmw8P2MRtmuqZT8GKUPnhAqB4%7C1716534827%7C3e92408d24b444549fb2c9f931009491a3ac237067ae4560a7399cc09b08c785; download_guide=%223%2F20240524%2F1%22; pwa2=%220%7C0%7C3%7C1%22; d_ticket=f2594b57383111683f6597a63eb6014482a6c; n_mh=ikF1CQAkKX8T0ML1Rxc_sHggzoy1weYGKP1if7n4_Cw; toutiao_sso_user=f2ff9d05a898b735a27d483393ce0e3a; toutiao_sso_user_ss=f2ff9d05a898b735a27d483393ce0e3a; passport_auth_status=7e3849102daddd1496bf51e64efc8405%2C; passport_auth_status_ss=7e3849102daddd1496bf51e64efc8405%2C; _bd_ticket_crypt_doamin=2; _bd_ticket_crypt_cookie=5065920b118cd8c05d7bad162272b798; __security_server_data_status=1; publish_badge_show_info=%220%2C0%2C0%2C1716541601140%22; store-region=cn-sc; store-region-src=uid; xg_device_score=7.611647058823529; stream_recommend_feed_params=%22%7B%5C%22cookie_enabled%5C%22%3Atrue%2C%5C%22screen_width%5C%22%3A1536%2C%5C%22screen_height%5C%22%3A864%2C%5C%22browser_online%5C%22%3Atrue%2C%5C%22cpu_core_num%5C%22%3A8%2C%5C%22device_memory%5C%22%3A8%2C%5C%22downlink%5C%22%3A5.35%2C%5C%22effective_type%5C%22%3A%5C%224g%5C%22%2C%5C%22round_trip_time%5C%22%3A50%7D%22; stream_player_status_params=%22%7B%5C%22is_auto_play%5C%22%3A0%2C%5C%22is_full_screen%5C%22%3A0%2C%5C%22is_full_webscreen%5C%22%3A0%2C%5C%22is_mute%5C%22%3A1%2C%5C%22is_speed%5C%22%3A1%2C%5C%22is_visible%5C%22%3A0%7D%22; FOLLOW_NUMBER_YELLOW_POINT_INFO=%22MS4wLjABAAAAEHgKGKT20MdR05_FwWjiHnfPH_KzqfJqq-c6klkPJRY%2F1716566400000%2F0%2F0%2F1716549476684%22; FOLLOW_LIVE_POINT_INFO=%22MS4wLjABAAAAEHgKGKT20MdR05_FwWjiHnfPH_KzqfJqq-c6klkPJRY%2F1716566400000%2F0%2F1716549542897%2F0%22; bd_ticket_guard_client_data=eyJiZC10aWNrZXQtZ3VhcmQtdmVyc2lvbiI6MiwiYmQtdGlja2V0LWd1YXJkLWl0ZXJhdGlvbi12ZXJzaW9uIjoxLCJiZC10aWNrZXQtZ3VhcmQtcmVlLXB1YmxpYy1rZXkiOiJCSkJOMXpQbG15aTMveDRtdWVpVndCdm9NTWt0NTRseGJSdVV6Q1VaM2JOOS9PdW1LcHB5Tk5tb1NwNGlTSzltSk5kVmJoL2tibjE0SEk4YXRCQURWTEU9IiwiYmQtdGlja2V0LWd1YXJkLXdlYi12ZXJzaW9uIjoxfQ%3D%3D; WallpaperGuide=%7B%22showTime%22%3A1716530847301%2C%22closeTime%22%3A0%2C%22showCount%22%3A1%2C%22cursor1%22%3A19%2C%22cursor2%22%3A0%7D; sso_uid_tt=1d434655becb60b0564f06e89a46a451; sso_uid_tt_ss=1d434655becb60b0564f06e89a46a451; sid_ucp_sso_v1=1.0.0-KDVkYjhhMzA5NTIzMjM2MjNmYjFlOTliNDlhZWQyZmNkNTk1ZGMyODcKCRC-8cGyBhjvMRoCbGYiIGYyZmY5ZDA1YTg5OGI3MzVhMjdkNDgzMzkzY2UwZTNh; ssid_ucp_sso_v1=1.0.0-KDVkYjhhMzA5NTIzMjM2MjNmYjFlOTliNDlhZWQyZmNkNTk1ZGMyODcKCRC-8cGyBhjvMRoCbGYiIGYyZmY5ZDA1YTg5OGI3MzVhMjdkNDgzMzkzY2UwZTNh; odin_tt=497d1750c301927eab9ed0e4879def3f93a4ecfd0c3f3c65c98666913feb2585; sid_guard=89cd0873d3d7420dedc0149afbe7194d%7C1716549822%7C21600%7CFri%2C+24-May-2024+17%3A23%3A42+GMT; uid_tt=9d5d0ee0dff3567517e25b978a6a7634; uid_tt_ss=9d5d0ee0dff3567517e25b978a6a7634; sid_tt=89cd0873d3d7420dedc0149afbe7194d; sessionid=89cd0873d3d7420dedc0149afbe7194d; sessionid_ss=89cd0873d3d7420dedc0149afbe7194d; sid_ucp_v1=1.0.0-KGU4NWI0ODM0MDU4NzY1ZGIxNDFjNTY1MGExNmZiODkxMmJlNmU0ZGQKCBC-8cGyBhgNGgJsZiIgODljZDA4NzNkM2Q3NDIwZGVkYzAxNDlhZmJlNzE5NGQ; ssid_ucp_v1=1.0.0-KGU4NWI0ODM0MDU4NzY1ZGIxNDFjNTY1MGExNmZiODkxMmJlNmU0ZGQKCBC-8cGyBhgNGgJsZiIgODljZDA4NzNkM2Q3NDIwZGVkYzAxNDlhZmJlNzE5NGQ; msToken=bHe60zpNfK8rd1b5UtEiOCAX4sV28HyGpriYneduMIsES4P1_z2yHiAmlSdTSZEhjAZmtkC30cQlwOl_-3XwjZSWR6dn4-TF3OndtHx1YvIlwgRJdVhypbGiQokGjA==; __ac_nonce=066507aed000078a99068; __ac_signature=_02B4Z6wo00f01RPmNAgAAIDB5Y89LCvvdPETxjCAACKs73; home_can_add_dy_2_desktop=%220%22; IsDouyinActive=true',
'priority': 'u=1, i',
'referer': 'https://www.douyin.com/search/%E7%AC%AC%E4%BA%8C%E5%8D%81%E6%9D%A1?aid=20948ce1-0daf-4288-a8a2-f480c49134b0&type=general',
'sec-ch-ua': '"Chromium";v="124", "Microsoft Edge";v="124", "Not-A.Brand";v="99"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"Windows"',
'sec-fetch-dest': 'empty',
'sec-fetch-mode': 'cors',
'sec-fetch-site': 'same-origin',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0',
}
params = {
'device_platform': 'webapp',
'aid': '6383',
'channel': 'channel_pc_web',
'search_channel': 'aweme_general',
'enable_history': '1',
'keyword': '飞驰人生2',
'search_source': 'normal_search',
'query_correct_type': '1',
'is_filter_search': '0',
'from_group_id': '',
'offset': '0',
'count': '10',
'need_filter_settings': '1',
'update_version_code': '170400',
'pc_client_type': '1',
'version_code': '190600',
'version_name': '19.6.0',
'cookie_enabled': 'true',
'screen_width': '1536',
'screen_height': '864',
'browser_language': 'zh-CN',
'browser_platform': 'Win32',
'browser_name': 'Edge',
'browser_version': '124.0.0.0',
'browser_online': 'true',
'engine_name': 'Blink',
'engine_version': '124.0.0.0',
'os_name': 'Windows',
'os_version': '10',
'cpu_core_num': '8',
'device_memory': '8',
'platform': 'PC',
'downlink': '10',
'effective_type': '4g',
'round_trip_time': '50',
'webid': '7372443638851700278',
'msToken': '_R4c-Yhg7pcsL1rLNy-fel-hfY4cycTP4SfwfwyqVIcTDPphTo2pjY5SQuppK4qTG1rzGa_YDATa7csKTogDfJbagoloAjHipeFXnhF1hooK5vYOpOyS8dca85xU7g==',
'a_bogus': 'mXmZMdzgdDfiDDWX5VcLfY3q6WB3Y/R30CPYMD2f7dVrng39HMOH9exoM3zvDpRjLG/lIeujy4hbO3KprQVHMZwf9W0L/252sESkKl5Q5xSSs1X9eghgJ0hwmkt5SMx2RvB-rOXgqwlHFmym09oHmhK4bIOwu3GMEE==',
}
params_str = urllib.parse.urlencode(params)
ctx = execjs.compile(open('douyin.js').read())
a_bogus = ctx.call('getSign', params_str)
params['a_bogus'] = a_bogus
response = requests.get('https://www.douyin.com/aweme/v1/web/general/search/single/', params=params, headers=headers)
print(response.text)