本文章中所有内容仅供学习交流,抓包内容、敏感网址、数据接口均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关,若有侵权,请联系我立即删除!
最近闲来无事 搞一下数美滑块。可能很简单。搞过的人可以划走了。但是自己去搞。不看教程 说实话还是有点废心神的。
如下图所示
其实所需要逆向的就两个接口
我们来看看其中有哪些参数以及返回的参数
captchaUuid: 生成的UUID 32位随机字符串
capchaUuID的算法如下:
def getcapcha_uuid():
total_string = "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678"
part = "".join([random.choice(total_string) for _ in range(18)])
ctime = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
captcha_uuid = f"{ctime}{part}"
return captcha_uuid
organization:每个站点的captchaUuid是固定的,姑且可以看成固定的组织ID
其他参数:model 为模式 模式分为:slide
滑块、auto_slide
无感验证、select
文字点选、icon_select
图标点选、seq_select
语序点选、spatial_select
空间推理
然后伪造参数请求就可以了。
然后看下请求响应的值。
bg: 背景图片
k,l,rid: 接口返回的值 方便verify 参数调用。
这里我们看下请求参数
下文划横线的 12个加密值都是JS返回的。不包括之前的 organization以及captchaUuid。
其中mu为最长的参数。 为轨迹加密。
再看看返回值。
根据riskLevel 。pass即通过。
这里在逆向前需要做个准备。本文不涉及任何解混淆。 就是干
这里要注意。数美这个滑块做了格式化检测。你一旦替换 或者 格式化了 js 控制台就会卡死 。这里要注意。
只有当你替换完之后重新压缩代码 才会成功。
这里直接断点打在下图位置。这个是请求传参。参数已经生成。往上找栈。
然后发现这个是封装的请求。搜索一下这个参数:_0x28800d
然后搜索到了 定义的地方。
如下文代码:
_0x28800d = _0x2460cd[_0x6f9c3c[_0x2c1c24(0x5f0)]][_0x2c1c24(0x7c1)]((_0x1fe1cf = {
'organization': _0x49bb92
},
(-0x1be8 + 0x20f2 + -0x50a,
_0x1f0d12[_0x6f9c3c[_0x2c1c24(0x5f0)]])(_0x1fe1cf, 'mp', this['getEncryptContent'](_0x20df23, _0x6f9c3c[_0x2c1c24(0xaa2)])),
(0xd * 0x103 + 0x2 * 0x3a + 0x2b * -0x51,
_0x1f0d12[_0x6f9c3c[_0x2c1c24(0x5f0)]])(_0x1fe1cf, 'oc', this[_0x2c1c24(0x553)](_0x4143cf, _0x2c1c24(0x800))),
(-0x81e + -0x166 * 0x10 + -0x6 * -0x515,
_0x1f0d12['default'])(_0x1fe1cf, 'xy', this[_0x2c1c24(0x553)](_0x7306d7, _0x6f9c3c[_0x2c1c24(0x3bf)])),
(-0x10a5 + -0xafb + -0x2 * -0xdd0,
_0x1f0d12[_0x2c1c24(0x9f1)])(_0x1fe1cf, 'jo', this[_0x2c1c24(0x553)](_0x49f479, _0x6f9c3c[_0x2c1c24(0x6b2)])),
(-0x279 * 0x1 + -0xa9 * 0x10 + 0xd09,
_0x1f0d12[_0x6f9c3c[_0x2c1c24(0x5f0)]])(_0x1fe1cf, _0x6f9c3c[_0x2c1c24(0x6f3)], _0x3717b1),
(-0xf82 + -0x3ee + -0x10 * -0x137,
_0x1f0d12[_0x6f9c3c[_0x2c1c24(0x5f0)]])(_0x1fe1cf, _0x6f9c3c[_0x2c1c24(0x2a6)], _0x435e2e),
(-0x2 * 0xf16 + 0x1d69 + 0xc3,
_0x1f0d12[_0x6f9c3c['Nlbsb']])(_0x1fe1cf, _0x6f9c3c[_0x2c1c24(0x361)], _0x294474),
(-0x18 * -0x60 + 0x1 * 0x1147 + -0x1a47,
_0x1f0d12[_0x6f9c3c['Nlbsb']])(_0x1fe1cf, _0x6f9c3c[_0x2c1c24(0x41a)], _0x2c1c24(0x7d0)),
(-0x14 * -0x22 + 0x53 * -0x75 + -0xb * -0x335,
_0x1f0d12[_0x6f9c3c[_0x2c1c24(0x5f0)]])(_0x1fe1cf, _0x2c1c24(0x734), _0x528bd),
_0x1fe1cf), _0x298b01);
主打就是一手硬撸。直接去给他解混淆(手撸)搞出来、
_0x28800d = _0x2460cd["default"]["extend"]((_0x1fe1cf = {
'organization': "xQsKB7v2qSFLFxnvmjdO"
},
(0, _0x1f0d12["default"])(_0x1fe1cf, 'mp', this['getEncryptContent']("default", "9cc268c1")),
(0, _0x1f0d12["default"])(_0x1fe1cf, 'oc', this["getEncryptContent"]("DEFAULT", "c2659527")),
(0, _0x1f0d12['default'])(_0x1fe1cf, 'xy', this["getEncryptContent"]("zh-cn", "b1807581")),
(0, _0x1f0d12['default'])(_0x1fe1cf, 'jo', this["getEncryptContent"]("11", "6d005958")),
(0, _0x1f0d12["default"])(_0x1fe1cf, "rid", "20240512211048b398271a522323d31e"),
(0, _0x1f0d12["default"])(_0x1fe1cf, "rversion", "1.0.4"),
(0, _0x1f0d12["default"])(_0x1fe1cf, "sdkver", "1.1.3"),
(0, _0x1f0d12["default"])(_0x1fe1cf, "protocol", "180"),
(0, _0x1f0d12["default"])(_0x1fe1cf, "ostype", "web"),
_0x1fe1cf), _0x298b01);
ok 这里可以发现 mp,oc,xy,jo 都是由 getEncryptContent这个方法加密得来的。
而剩下8个参数在哪里呢。答案是**_0x298b01**
如下图所示
剩下就是追这个函数的栈了。
然后发现这是个控制流。
根据mode 模式的不同走不同的case。这里mode指的是滑块 点选等等等。自己慢慢研究即可。
然后这里getEncryptContent 函数可以自己扣。也可以自己去python还原。
其实断点打在这里。可以明显看出 第一个值是加密的值。第二个值是密钥。
这里有个小坑: mu是轨迹。在使用轨迹生成的时候。识别图片得到的距离需要 / 2 。至于为什么 请看下图
这里看下结果。
响应返回 PASS 代表成功返回
响应返回 REJECT代表参数错误或者轨迹错误
有兴趣的同学可以关注下我的个人公众号和星球