skuukzky
文章12
标签0
分类2

文章分类

抖音滑块分析

抖音滑块分析

抖音滑块分析

代码插装

在堆栈中查看,其中有一处很明显的 captcha.js,应该是 captchabody 生成的关键 js,我们进入查看,整体预览 js 代码,发现 webpack+switch 控制流+vmp。接着查桩,先在 switch 处插桩,看看大概都做了什么。

switch 插装点

image-20250313095214533

apply 插装点

然后对于 vmp 这种,最好是在 call 和 apply 的地方下断点,这里 v(431)也是 apply,同理也插上断点。

image-20250313095349806

日志分析

这里我们进行验证码的提交,同时打下 xhr 断点,以防太多日志造成干扰和卡顿,然后观察日志。

image-20250313095651368

然后这里放入 爬虫工具库 分析格式

image-20250313095859065

这些参数分析下都是什么,首先有 id,是获取验证码图片的接口返回的,MMtJ2Xt 是验证码中点击的位置,v7VR5s 是鼠标在验证码图片里移动的轨迹和时间戳,env 包括了一些浏览器的环境。

接着往下查看日志。

image-20250313100137842

这里看到了 sha-512 的字样,看样子是把 JSON.stringify 提交的参数进行了 sha-512 的加密。我们来验证一下是否为标准的算法。

image-20250313100318475

符合我们的猜想且为标准的 sha-512 算法。继续看查看日志。

image-20250313100412982

发现生成了个 32 位的随机数,最后用经过了一些算法在 join 成了一个字符串。然后同时也在进行 sha-512

image-20250313100553696

发现他拼接了一个3c032864bb1f8479f92da1b57aa0553f36bb1ed83b2eab6c7ac9e8b08b50d518f444d4b6d2261f158b2ad27a72f804f058fcb31ba1404cdf78f63cb80ed86290然后又做了 sha-512 算法。这里可以多次断点触发几次,观察是固定的,应该是就是 salt 了。

那么就清楚了,流程应该是对随机生成的 32 位数字做 sha-512,拼接 salt,做 from hex 在进行 sha-512。我们这里验证一下。

image-20250313104000225

没错,符合我们的猜想。

接着观察发现 对这加密后的结果进行了字符串切割取值 上图也能看到,

image-20250313110154417

然后打断点分析下这里的代码,看到了 aes 的这样,猜测且上文分割的两个值很有可能是切分后的的 key 和 iv。

image-20250313111141539

这里他转化成了 Uint8Array 的形式,我们查看内容,发现他是一部分乱码加明文的格式,明文很好理解,是我们最开始观察到的参数,而乱码是什么呢,我们可以去日志一搜,发现是我们明文格式的sha-512的结果,那么加密的内容应该就是如下操作

1
2
3
4
data = {"modified_img_width":340,"id":"d3f7872be063c42ea4ea760d32dc46361a6a9f0e","mode":"3d","MMtJ2Xt":[{"x":213,"y":136,"time":1741830854441,"t":0,"relative_time":1741830854441},{"x":261,"y":161,"time":1741830855008,"t":0,"relative_time":1741830855008}],"JKWR":[],"v7VR5s":{"6Jbg":{"x":266,"y":303,"time":1741830852841},"MYE":{},"AREm":[{"x":378,"y":300,"time":1741830221614},{"x":88,"y":177,"time":1741830221648},{"x":293,"y":207,"time":1741830276079},{"x":12,"y":224,"time":1741830410110},{"x":12,"y":224,"time":1741830410181},{"x":89,"y":233,"time":1741830410514},{"x":265,"y":226,"time":1741830489006},{"x":261,"y":255,"time":1741830489040},{"x":252,"y":296,"time":1741830489074},{"x":266,"y":303,"time":1741830852841},{"x":245,"y":224,"time":1741830852877},{"x":237,"y":213,"time":1741830852911},{"x":229,"y":206,"time":1741830852945},{"x":228,"y":205,"time":1741830853087},{"x":241,"y":235,"time":1741830853121},{"x":295,"y":295,"time":1741830853155},{"x":353,"y":303,"time":1741830853189},{"x":368,"y":302,"time":1741830853223},{"x":368,"y":302,"time":1741830853375},{"x":367,"y":303,"time":1741830853467},{"x":365,"y":300,"time":1741830853501},{"x":355,"y":289,"time":1741830853535},{"x":311,"y":245,"time":1741830853569},{"x":287,"y":230,"time":1741830853603},{"x":278,"y":222,"time":1741830853637},{"x":277,"y":217,"time":1741830853672},{"x":277,"y":216,"time":1741830853711},{"x":278,"y":216,"time":1741830853782},{"x":280,"y":218,"time":1741830853816},{"x":281,"y":217,"time":1741830853916},{"x":281,"y":217,"time":1741830853955},{"x":276,"y":217,"time":1741830853989},{"x":269,"y":215,"time":1741830854023},{"x":260,"y":211,"time":1741830854057},{"x":253,"y":210,"time":1741830854092},{"x":251,"y":210,"time":1741830854127},{"x":250,"y":209,"time":1741830854165},{"x":247,"y":208,"time":1741830854199},{"x":241,"y":205,"time":1741830854233},{"x":234,"y":204,"time":1741830854269},{"x":234,"y":204,"time":1741830854497},{"x":243,"y":211,"time":1741830854531},{"x":258,"y":219,"time":1741830854565},{"x":270,"y":222,"time":1741830854599},{"x":273,"y":222,"time":1741830854670},{"x":275,"y":223,"time":1741830854706},{"x":276,"y":223,"time":1741830854740},{"x":277,"y":224,"time":1741830854774},{"x":279,"y":227,"time":1741830854808},{"x":281,"y":229,"time":1741830854845},{"x":281,"y":229,"time":1741830855060},{"x":292,"y":247,"time":1741830855094},{"x":310,"y":272,"time":1741830855128},{"x":323,"y":286,"time":1741830855162},{"x":325,"y":288,"time":1741830855196},{"x":325,"y":291,"time":1741830855230},{"x":325,"y":295,"time":1741830855264},{"x":325,"y":296,"time":1741830855320},{"x":325,"y":296,"time":1741830855373},{"x":326,"y":296,"time":1741830855420},{"x":326,"y":296,"time":1741830855511},{"x":326,"y":296,"time":1741830855549}],"vCystNSrL":[],"pkxVs4vwG":[{"x":213,"y":136,"time":1741830854441,"t":0,"relative_time":1741830854441},{"x":261,"y":161,"time":1741830855008,"t":0,"relative_time":1741830855008}],"G1uH":[]},"env":{"canvas_hash":"7cc5134d09b75886012094f92c7e0d66","webgl_hash":"52497e308a4259f66bf07a8977e40d65","font_hash":"1ba687496000143eef07302e43853b43ad797cb8ab46","audio_hash":197.04346607114712,"time_offset":-480,"time_zone":"Asia/Shanghai","languages":["zh-CN"],"plugins":["PDF Viewer","Chrome PDF Viewer","Chromium PDF Viewer","Microsoft Edge PDF Viewer","WebKit built-in PDF"],"platform":"MacIntel","max_touch_points":0,"webdriver":False,"touch_actions":[],"mouse_actions":["1,1","1,1","1,1","1,1","1,1","1,1","1,1","1,1","1,1"],"device":{"model":"Macintosh","vendor":"Apple"},"os":{"name":"Mac OS","version":"10.15.7"},"browser":{"name":"Chrome","version":"134.0.0.0"},"engine":{"name":"Blink","version":"134.0.0.0"},"gpu":{"vendor":"Google Inc. (Apple)","renderer":"ANGLE (Apple, ANGLE Metal Renderer: Apple M3 Max, Unspecified Version)"},"fps":117,"resolution":"1728,1117","browser_size":"1728,985","page_size":"1728,619","captcha_origin":"0,0","captcha_size":"380, 348","mask_time":174182900776854,"loading_time":1741829007935,"ready_time":1741829008113,"detectors":{"RegToString":{"enabled":False,"value":0},"DefineId":{"enabled":True,"value":0},"DateToString":{"enabled":True,"value":0},"FuncToString":{"enabled":True,"value":0},"Debugger":{"enabled":False,"value":0},"Performance":{"enabled":True,"value":1},"DebugLib":{"enabled":True,"value":0}}},"a":24,"b":44}

v8 = json.dumps(data, separators=(",", ":")).encode()
v11 = SHA512.new(v8).digest() + v8

往下翻到看看这样的字样,然后下断查看。

image-20250313111952355

到现在分析可知,key 是截取的[0,64],nonce 是[64,88]。而加密方式则是AES.MODE_GCM

我们结合 python 进行加密看看是否对得上

整合后的代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
from Crypto.Hash import SHA512
from Crypto.Cipher import AES
import base64
import json
# 提交的参数
data = {"modified_img_width":340,"id":"ed9e4c7362511be8651121bb23573f3c254dbc94","mode":"3d","MMtJ2Xt":[{"x":229,"y":138,"time":1741836451318,"t":0,"relative_time":1741836451318},{"x":274,"y":174,"time":1741836452256,"t":0,"relative_time":1741836452256}],"JKWR":[],"v7VR5s":{"6Jbg":{"x":5,"y":308,"time":1741836450172},"MYE":{},"AREm":[{"x":5,"y":308,"time":1741836450172},{"x":145,"y":230,"time":1741836450206},{"x":149,"y":227,"time":1741836450289},{"x":143,"y":229,"time":1741836450325},{"x":143,"y":236,"time":1741836450469},{"x":145,"y":235,"time":1741836450519},{"x":158,"y":228,"time":1741836450553},{"x":160,"y":227,"time":1741836450618},{"x":161,"y":233,"time":1741836450653},{"x":163,"y":235,"time":1741836450691},{"x":167,"y":235,"time":1741836450725},{"x":178,"y":228,"time":1741836450759},{"x":192,"y":222,"time":1741836450794},{"x":195,"y":220,"time":1741836450828},{"x":197,"y":219,"time":1741836450866},{"x":204,"y":217,"time":1741836450900},{"x":218,"y":214,"time":1741836450934},{"x":231,"y":211,"time":1741836450968},{"x":237,"y":209,"time":1741836451002},{"x":238,"y":209,"time":1741836451046},{"x":238,"y":208,"time":1741836451089},{"x":240,"y":207,"time":1741836451125},{"x":244,"y":207,"time":1741836451160},{"x":247,"y":207,"time":1741836451194},{"x":249,"y":206,"time":1741836451337},{"x":249,"y":211,"time":1741836451371},{"x":258,"y":221,"time":1741836451405},{"x":265,"y":232,"time":1741836451439},{"x":271,"y":240,"time":1741836451473},{"x":272,"y":242,"time":1741836451507},{"x":276,"y":250,"time":1741836451541},{"x":287,"y":255,"time":1741836451575},{"x":296,"y":258,"time":1741836451609},{"x":306,"y":261,"time":1741836451643},{"x":311,"y":263,"time":1741836451686},{"x":311,"y":263,"time":1741836451733},{"x":309,"y":264,"time":1741836451770},{"x":306,"y":263,"time":1741836451804},{"x":306,"y":258,"time":1741836451841},{"x":306,"y":254,"time":1741836451876},{"x":306,"y":250,"time":1741836451910},{"x":305,"y":248,"time":1741836451946},{"x":303,"y":248,"time":1741836451980},{"x":301,"y":247,"time":1741836452014},{"x":300,"y":247,"time":1741836452050},{"x":299,"y":245,"time":1741836452084},{"x":297,"y":244,"time":1741836452120},{"x":295,"y":243,"time":1741836452155},{"x":295,"y":242,"time":1741836452297},{"x":299,"y":253,"time":1741836452331},{"x":302,"y":272,"time":1741836452365},{"x":310,"y":292,"time":1741836452399},{"x":322,"y":301,"time":1741836452433},{"x":329,"y":303,"time":1741836452467},{"x":337,"y":304,"time":1741836452503},{"x":346,"y":306,"time":1741836452537},{"x":346,"y":306,"time":1741836452573},{"x":343,"y":304,"time":1741836452608},{"x":343,"y":301,"time":1741836452645},{"x":343,"y":300,"time":1741836452680},{"x":341,"y":300,"time":1741836452717},{"x":340,"y":300,"time":1741836452757},{"x":338,"y":300,"time":1741836452791},{"x":336,"y":299,"time":1741836452828}],"vCystNSrL":[],"pkxVs4vwG":[{"x":229,"y":138,"time":1741836451318,"t":0,"relative_time":1741836451318},{"x":274,"y":174,"time":1741836452256,"t":0,"relative_time":1741836452256}],"G1uH":[]},"env":{"canvas_hash":"7cc5134d09b75886012094f92c7e0d66","webgl_hash":"52497e308a4259f66bf07a8977e40d65","font_hash":"1ba64c68b28f0bc8f8741a960400143eef07302e43853b43ad797cb8ab46","audio_hash":197.04346607114712,"time_offset":-480,"time_zone":"Asia/Shanghai","languages":["zh-CN"],"plugins":["PDF Viewer","Chrome PDF Viewer","Chromium PDF Viewer","Microsoft Edge PDF Viewer","WebKit built-in PDF"],"platform":"MacIntel","max_touch_points":0,"webdriver":False,"touch_actions":[],"mouse_actions":["1,1","1,1","1,1","1,1","1,1","1,1","1,1","1,1","1,1","1,1"],"device":{"model":"Macintosh","vendor":"Apple"},"os":{"name":"Mac OS","version":"10.15.7"},"browser":{"name":"Chrome","version":"134.0.0.0"},"engine":{"name":"Blink","version":"134.0.0.0"},"gpu":{"vendor":"Google Inc. (Apple)","renderer":"ANGLE (Apple, ANGLE Metal Renderer: Apple M3 Max, Unspecified Version)"},"fps":117,"resolution":"1728,1117","browser_size":"1728,985","page_size":"1728,619","captcha_origin":"0,0","captcha_size":"380, 348","mask_time":174182900776843,"loading_time":1741829007935,"ready_time":1741829008113,"detectors":{"RegToString":{"enabled":False,"value":0},"DefineId":{"enabled":True,"value":0},"DateToString":{"enabled":True,"value":0},"FuncToString":{"enabled":True,"value":0},"Debugger":{"enabled":False,"value":0},"Performance":{"enabled":True,"value":1},"DebugLib":{"enabled":True,"value":0}}},"a":24,"b":39}

v8 = json.dumps(data, separators=(",", ":")).encode()
v11 = SHA512.new(v8).digest() + v8
slat = 'uWOdyotVVplUj49mdJRLpDxQswzgWfPi' #32位随机值的生成
v12 = SHA512.new(
            bytes.fromhex(
                SHA512.new(slat.encode()).hexdigest()
                + "3c032864bb1f8479f92da1b57aa0553f36bb1ed83b2eab6c7ac9e8b08b50d518f444d4b6d2261f158b2ad27a72f804f058fcb31ba1404cdf78f63cb80ed86290"
            )
        ).hexdigest()
print(v12)

crypto = AES.new(
    key=bytes.fromhex(v12[:64]),
    mode=AES.MODE_GCM,
    nonce=bytes.fromhex(v12[64:88]),
)
ciphertext, mac = crypto.encrypt_and_digest(v11)
captchabody = base64.b64encode(
    bytes([116, 99, 6, 16, 0, 0]) + slat.encode() + ciphertext + mac
).decode()
print(captchabody)

发现是一致的,至此 captchabody 的分析就结束了,整体适中,如果有实力可以尝试 ast 还原,会让分析变得更流畅。最后请求的时候最好要 sleep 几秒钟,不然有概率无法通过。

滑块

3d空间推理

参考链接

感谢晨哥指导。

本文作者:skuukzky
本文链接:https://lpy30m.github.io/skuukzky.github.io/2025/03/13/%E9%AA%8C%E8%AF%81%E7%A0%81%E8%AF%86%E5%88%AB/%E6%8A%96%E9%9F%B3%E6%BB%91%E5%9D%97%E5%88%86%E6%9E%90/
版权声明:本文采用 CC BY-NC-SA 3.0 CN 协议进行许可