-
-
[原创]完美滑块还原笔记
-
发表于: 2026-9-10 13:13 436
-
来源与拼接逻辑
搜索 background-position 可以定位到 mCaptcha.pc.1.0.0.min.js (mCaptcha.beauty.js) 中 MoveCaptcha 的两处关键代码:
getCaptcha 成功后:
o = e.capKey; // 图片文件名,如 2a8d351db51d4d59b11a08da18c3e21a
c = e.imgUrl; // 18dK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6U0j5i4m8@1j5$3S2S2M7#2)9J5k6q4)9J5k6g2)9J5k6g2)9J5k6g2)9J5c8X3y4S2M7s2c8U0K9r3q4K6i4K6u0r3i4K6t1$3L8s2c8Q4x3@1u0U0j5i4m8w2k6i4W2Q4x3U0k6Y4N6q4)9K6b7W2)9J5k6i4m8F1k6H3`.`.
R = JSON.parse(e.data); // 还原数组(40 个 0~39 的整数排列)
s = e.validateUrl;
渲染/拼接时对每个切片 div:
$.each(i /* = R /, function (e, t) {
// t < 20:background-position: -13*t px 0
// t >= 20:background-position: -13(t%20) px -60px
});
几何参数在文件里写死:g=260(宽)、x=120(高)、_=20(每行切片数),所以每片是 13×60,共 40 片:第 019 片在上行,第 2039片在下行。data[j] 的含义是:正常图的第 j 个位置应该放打乱原图里的第 data[j] 片。

以这张为例,从页面上实际拼出的 DOM 提取到:
[39,13,21,12,23,17,24,29,34,14,6,31,22,2,25,27,37,16,5,20,10,18,38,36,32,30,8,3,7,11,19,1,9,0,4,33,28,35,15,26]
这个数组就是该次 data 的等价内容
还原方式:
下载的原始 PNG 实际是 321×120,不是 260×120:
左 0~259 像素是被打乱的背景,40 片 13×60;
右 260~320 像素是 61×120 的拖动块,页面里 .m_sliderCubic 用 background-position: -260px 0 取的就是这块。
所以还原时只切左 260 像素,还原图第 j 片 = 原图第 order[j] 片:
for j, src in enumerate(order):
row, col = divmod(j, 20)
out.paste(cells[src], (col * 13, row * 60))
还原后的图片为:

实际还原代码如下:
from PIL import Image
COLS = 20 # 每行切片数
SW, SH = 13, 60 # 单切片宽高
def restore(image_path, order, output_path):
img = Image.open(image_path).convert("RGB")
cells = []
for f in range(40):
row, col = divmod(f, COLS)
cells.append(
img.crop((col * SW, row * SH, col * SW + SW, row * SH + SH))
)
restored = Image.new("RGB", (COLS * SW, 2 * SH))
for j, src in enumerate(order):
row, col = divmod(j, COLS)
restored.paste(cells[src], (col * SW, row * SH))
restored.save(output_path)
return restored.size
def main():
image_path = r"\captcha_raw_2a8d351db51d4d59b11a08da18c3e21a.png"
order = [
39, 13, 21, 12, 23, 17, 24, 29, 34, 14,
6, 31, 22, 2, 25, 27, 37, 16, 5, 20,
10, 18, 38, 36, 32, 30, 8, 3, 7, 11,
19, 1, 9, 0, 4, 33, 28, 35, 15, 26,
]
output_path = r"\1.png"
size = restore(image_path, order, output_path)
print("还原完成:", output_path, size)
if name == "main":
main()
公众号:JavaScript逆向笔记
来源:186K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6E0M7q4)9J5k6i4N6W2K9i4S2A6L8W2)9J5k6i4q4I4i4K6u0W2j5$3!0E0i4K6u0r3M7#2)9J5c8Y4u0A6K9U0R3J5b7@1k6f1z5h3f1#2y4p5c8u0L8X3E0&6M7X3g2$3N6Y4M7`.
冰与火的战歌:Windows内核攻防实战高级班!从零到实战,融合AI与Windows内核攻防全技术栈,打造具备自动化能力的内核开发高手。