资讯动态

AI逆向实战:猿人学反混淆练习平台第八题加密分析全流程拆解

发布时间:2026/9/29 4:35:42 来源:尧图企业网站定制
1. 猿人学第八题到底卡在哪验证码识别与反混淆的真实场景猿人学反混淆练习平台第八题页面打开后不是直接给你数据而是先弹出一组九宫格验证码提示你按顺序点选目标字符通过之后才能翻页拿数据。很多人第一次做这题会误以为难点在接口加密参数上实际抓包会发现请求体里没有 sign、没有 token只有一个captcha_id和clicks坐标数组。真正的门槛在于验证码图片是 base64 内嵌的目标字符是动态下发的而且每次翻页都可能重新触发验证码校验。这道题适合已经会写基础 requests 脚本、想进阶到「图像预处理 模板匹配 请求状态机」的读者。它不需要你破解复杂的 JS 混淆但需要你把验证码识别、会话保持、翻页重试这三件事串成一个稳定的自动化流程。我试过用纯 OCR 库直接识别准确率很低因为验证码里的字符有旋转、有干扰线、有颜色噪声通用 OCR 模型在这种小样本场景下反而不如自己写特征匹配。核心检索词先明确猿人学第八题、反混淆、加密分析、验证码识别、九宫格点选、Python 逆向脚本。下面从环境准备到可运行脚本逐步拆开每一步都给出可复制的配置和验证动作。2. TaoToken 前置用模型对话辅助分析验证码逻辑在写脚本之前我习惯先用模型对话把接口返回结构和验证码字段含义理清楚。TaoToken 的模型对话入口可以直接贴抓包返回的 JSON让模型帮你归纳字段关系比如targets是目标字符数组、image是 base64 图片、id是本次验证码会话标识。这一步不是必须的但能省掉很多手动比对的时间。你可以打开模型对话页面https://taotoken.net/api?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite 把/api2/8的返回样例贴进去问它「这个 JSON 里每个字段在验证码流程中承担什么角色」。模型会给出字段级解释你再对照自己的抓包结果验证。如果你打算长期做这类逆向练习建议把常用的分析提示词沉淀下来配合 Coding Plan 做脚本迭代https://taotoken.net/api?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite 。接入文档在 https://taotoken.net/api?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite API Key 在 https://taotoken.net/api?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite 控制台里生成。需要说明的是TaoToken 在这里的角色是辅助你理解接口语义和生成脚本骨架不是替你绕过验证码。验证码的识别逻辑仍然要你自己写模型只能帮你把思路结构化。3. 可复制配置会话、请求头与验证码接口参数先把基础请求配置固定下来。这道题的关键请求头有三个User-Agent必须设置为yuanrenxueX-Requested-With设为XMLHttpRequestReferer指向/match/8。Cookie 里需要带上登录后的sessionid否则接口会返回未登录状态。import requests, json, time, base64, io import numpy as np import cv2 from PIL import Image BASE_URL https://match.yuanrenxue.cn SESSION_COOKIE {sessionid: 你的sessionid} USER_AGENT yuanrenxue PAGE_SIZE 10 TOTAL_PAGES 5 session requests.Session() session.headers.update({ User-Agent: USER_AGENT, X-Requested-With: XMLHttpRequest, Referer: f{BASE_URL}/match/8, Accept: application/json, text/javascript, */*; q0.01, }) for k, v in SESSION_COOKIE.items(): session.cookies.set(k, v, domainmatch.yuanrenxue.cn, path/)验证码获取接口是GET /api2/8带一个毫秒时间戳参数t。返回结构里targets是你要点选的目标字符顺序image是 base64 图片id是本次验证码的唯一标识。提交接口是POST /api2/8表单字段为captcha_id和clicksclicks是 JSON 数组每个元素是{x: ..., y: ...}坐标。九宫格坐标计算方式图片按 3x3 切分每个格子中心点坐标用col * cell_size cell_size // 2和row * cell_size cell_size // 2得到。假设图片宽高都是 300则 cell_size 为 100。def cell_center(pos, cell_size100): row, col divmod(pos, 3) return {x: col * cell_size cell_size // 2, y: row * cell_size cell_size // 2}请求频率要控制两次请求间隔至少 0.6 秒遇到 429 就 sleep 3 秒重试。这个限流策略是实测下来比较稳的太快会触发风控太慢又影响调试效率。4. 验证请求与成功结果从验证码识别到翻页求和验证码识别的核心思路是「先探测、再匹配」。第一次遇到某个目标字符时你没有样本只能随机点四个位置提交接口会在返回里告诉你picked字段即你点中的位置对应的真实字符。用这个反馈来积累样本下次遇到相同字符就能做特征匹配。图像预处理步骤把每个格子裁出来去掉边缘 12% 的 margin转 HSV 取饱和度大于 40 且灰度小于 245 的区域作为字符掩码再做开运算和闭运算去噪最后把字符区域缩放到 64x64 的二值图作为特征。def preprocess_cell(cell): h, w cell.shape[:2] margin int(min(h, w) * 0.12) cell cell[margin:h-margin, margin:w-margin] hsv cv2.cvtColor(cell, cv2.COLOR_RGB2HSV) gray cv2.cvtColor(cell, cv2.COLOR_RGB2GRAY) mask np.logical_and(hsv[:,:,1] 40, gray 245).astype(np.uint8) * 255 kernel np.ones((3,3), np.uint8) mask cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel) mask cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel) ys, xs np.where(mask 0) if len(xs) 0: return np.zeros((64,64), dtypenp.uint8) crop mask[ys.min():ys.max()1, xs.min():xs.max()1] side max(crop.shape[:2]) 8 canvas np.zeros((side, side), dtypenp.uint8) oy (side - crop.shape[0]) // 2 ox (side - crop.shape[1]) // 2 canvas[oy:oycrop.shape[0], ox:oxcrop.shape[1]] crop return (cv2.resize(canvas, (64,64), interpolationcv2.INTER_AREA) 32).astype(np.uint8)匹配阶段用曼哈顿距离对每个目标字符计算当前格子特征与已积累样本均值的平均绝对差取最小代价的排列组合。因为目标字符通常只有 3 到 4 个9 选 4 的排列数是 3024暴力枚举完全可行。import itertools def predict_positions(cell_features, targets, samples): costs [] for char in targets: feats samples.get(char, []) if not feats: costs.append([float(inf)] * 9) continue proto np.stack([f.astype(np.float32) for f in feats]).mean(axis0) costs.append([float(np.mean(np.abs(cell_features[p].astype(np.float32) - proto))) for p in range(9)]) best_perm, best_score None, float(inf) for perm in itertools.permutations(range(9), len(targets)): score sum(costs[i][perm[i]] for i in range(len(targets))) if score best_score: best_score, best_perm score, perm return list(best_perm), best_score翻页逻辑是一个状态机请求/api/question/8?pageNpageSize10如果返回里action等于captcha说明需要先过验证码调用解题流程成功后重新请求同一页。拿到数据后累加data数组里的数值最后打印总和。def fetch_page(page): while True: resp session.get(f{BASE_URL}/api/question/8, params{page: page, pageSize: PAGE_SIZE}, timeout20) data resp.json() if data.get(action) ! captcha: return data solve_one_captcha() time.sleep(0.8)运行成功时控制台会依次打印每页的 JSON 数据和最终 sum 值。如果验证码识别正确通常 1 到 3 次尝试就能通过如果样本不足脚本会自动进入探测模式积累样本循环几次后识别率会明显上升。5. 本篇常见错排查验证码失败、429 与坐标偏移第一个高频错误是sessionid过期或未正确设置 domain。表现是接口返回{action: captcha}但验证码提交后一直失败。排查方法打印session.cookies.get_dict()确认sessionid存在且 domain 为match.yuanrenxue.cn。第二个错误是坐标计算用了图片原始尺寸而不是格子尺寸。如果图片不是 300x300cell_size要按width // 3动态计算。表现是提交后返回picked为空或验证码不通过。修正方式在decode_image之后读取image.shape把cell_size传进去。第三个错误是请求间隔太短触发 429。表现是连续几次请求后接口返回 429 状态码。解决方式在请求封装里加一个last_request_at时间戳每次请求前检查间隔不足 0.6 秒就 sleep 补齐。第四个错误是样本缓存文件损坏。match8_cache.pkl在写入过程中如果程序中断可能导致下次加载失败。排查方法在load_cache里加 try/except加载失败就清空样本重新积累。另外注意 pickle 文件不要跨 Python 版本混用。第五个错误是目标字符顺序理解反了。targets数组的顺序就是你要点选的顺序不是集合。比如targets是[A, B, C]你点的第一个格子必须是 A第二个是 B第三个是 C。如果顺序错了即使字符都对也不会通过。6. 语义一致 CTA把脚本跑通之后继续迭代脚本能稳定跑通 1 到 5 页并算出总和之后你可以把验证码识别模块抽出来做成独立类方便复用到其他类似题目。如果后续要接入更多逆向练习建议用 Coding Plan 管理你的脚本迭代和提示词版本https://taotoken.net/api?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite 。遇到接口字段变化或验证码样式调整时回到模型对话里重新分析返回结构https://taotoken.net/api?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite 比翻文档快很多。API Key 管理和接入配置都在控制台完成https://taotoken.net/api?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite 。接入文档里有完整的请求示例和参数说明https://taotoken.net/api?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite 。把这篇的脚本保存好下次遇到九宫格点选类验证码改一下接口路径和坐标计算就能直接套用。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑