T2
主要是代码混淆,需要处理,处理后发现:典型MD5,但是验证不通过,魔改版本。
function getSign(input) {
// 关键改动:输入加盐
input = input + "\xA3\xAC\xA1\xA3fdjf,jkgfkl";
return md5(input);
}
function md5(str) {
return hex(md5_cycle(str2binl(str), str.length * 8));
}
function md5_cycle(x, len) {
let a = 1732584193;
let b = -271733879;
let c = -1732584194;
let d = 271733878;
// 填充
x[len >> 5] |= 0x80 << (len % 32);
x[(((len + 64) >>> 9) << 4) + 14] = len;
for (let i = 0; i < x.length; i += 16) {
let olda = a, oldb = b, oldc = c, oldd = d;
a = ff(a, b, c, d, x[i + 0], 7, -680876936);
d = ff(d, a, b, c, x[i + 1], 12, -389564586);
c = ff(c, d, a, b, x[i + 2], 17, 606105819);
b = ff(b, c, d, a, x[i + 3], 22, -1044525330);
a = ff(a, b, c, d, x[i + 4], 7, -176418897);
d = ff(d, a, b, c, x[i + 5], 12, 1200080426);
c = ff(c, d, a, b, x[i + 6], 17, -1473231341);
b = ff(b, c, d, a, x[i + 7], 22, -45705983);
a = ff(a, b, c, d, x[i + 8], 7, 1770035416);
d = ff(d, a, b, c, x[i + 9], 12, -1958414417);
c = ff(c, d, a, b, x[i + 10], 17, -42063);
b = ff(b, c, d, a, x[i + 11], 22, -1990404162);
a = ff(a, b, c, d, x[i + 12], 7, 1804603682);
d = ff(d, a, b, c, x[i + 13], 12, -40341101);
c = ff(c, d, a, b, x[i + 14], 17, -1502002290);
b = ff(b, c, d, a, x[i + 15], 22, 1236535329);
...
a = add(a, olda);
b = add(b, oldb);
c = add(c, oldc);
d = add(d, oldd);
}
return [a, b, c, d];
}
结果

T3
(1)
https://www.spiderdemo.cn/static/protos/challenge.proto 生成一个 .proto 文件
转换为 python 调用 (authentication_pb2.py)
计算 signature
function get_sign(){
const timestamp = Date['now']()
const timestampStr = timestamp["toString"]();
const signature = md_sign['OooO'](timestampStr);
return [timestamp,signature]
}
其中 加密函数md_sign 一看四个初始值,然后跟md5类似一样,只有48轮,一般MD5还有循环左移,哎不扣了,全抠出来就完事了。
然后就是 protobuf 请求: 大概这样 类似 (所有人代码肯定存在差异,大胆修改)
request_msg = authentication_pb2.ChallengeRequest()
request_msg.page = page
request_msg.challengetype = "surwrexibfkdoohqjh"
request_msg.timestamp = timestamp # 确保是 int 类型
request_msg.signature = signature # 确保是 string 类型
自己按自己的思路写就可以了
# 1. 本地序列化
data = request_msg.SerializeToString()
try:
test_msg = authentication_pb2.ChallengeRequest()
test_msg.ParseFromString(data)
except Exception as e:
print(f"本地反序列化失败!Protobuf 格式错误: {e}")
结果:

T7 CSS1_challenge
“”"
7649“”"
(1) 计算style 中的函数 (有的没有style)
① 没有style
if '</style>' not in html_code:
html_code = re.sub(r'<span.*?>', '', html_code)
style = re.sub(r'</span>', '', html_code).strip()
digits_with_offset = [(digit, 0) for digit in re.findall(r'[0-9]', html_code)]
return move_by_offset(digits_with_offset)
move_by_offset 是根据当前位置进行移动操作
② 处理style
类似下面的一些处理方法:
def eval_calc(self, expr):
expr = expr.strip()
expr = self.replace_chinese_numerals(expr)
var_pattern = r'var\(--[^)]+\)'
while re.search(var_pattern, expr):
var_match = re.search(var_pattern, expr)
var_name = var_match.group(0)[4:-1] # 提取变量名
var_value = self.variables.get(var_name, 0)
expr = expr.replace(var_match.group(0), str(var_value))
try:
# 替换运算符号周围的空格
expr = re.sub(r'\s*([+\-*/()])\s*', r'\1', expr)
expr = expr.replace('px','')
return self.parse_number(str(eval(expr)))
except Exception as e:
print(f"计算表达式错误: {expr}, 错误: {e}")
return 0
def parse_number(self, s):
s = s.strip().replace('px', '') # 移除单位
if s.startswith('0x'):
return int(s, 16)
elif s.startswith('0b'):
return int(s, 2)
else:
return float(s) if '.' in s else int(s)
def parse_number(self, s):
s = s.strip().replace('px', '') # 移除单位
if s.startswith('0x'):
return int(s, 16)
elif s.startswith('0b'):
return int(s, 2)
else:
return float(s) if '.' in s else int(s)
def extract_digits(html_code):
soup = BeautifulSoup(html_code, 'html.parser')
digits_with_offset = []
evaluator = CSSEvaluator()
if '</style>' not in html_code:
# style = re.sub(r'<span.*?>', '', html_code,flags=re.DOTALL)
html_code_no = re.sub(r'<span.*?>', '', html_code)
style = re.sub(r'</span>', '', html_code_no).strip()
digits_with_offset = [(digit, 0) for digit in re.findall(r'[0-9]', style)]
return move_by_offset(digits_with_offset)
# 解析CSS变量
style_tag = soup.find('style')
if style_tag and style_tag.string:
evaluator.parse_css_variables(style_tag.string)
# print(evaluator.variables)
html_code1 = re.sub(r'<style.*?</style>', '', html_code)
# print(html_code1)
result = html_code1.split('</span>')
start_num,end_num,digit,style = '','','',''
for item in result:
# print('item',item.strip())
if item == '':
continue
if item.strip().isdigit():
# print('end',item)
end_num = item.strip()
else:
if item.strip()[0].isdigit():
start_num = item.split('<span')[0]
# print('start',item)
if item.strip()[-1].isdigit():
digit = item.strip()[-1]
style = item.strip()
# print('digit',digit,style)
if start_num and start_num.isdigit():
for s1 in start_num:
digits_with_offset.append((s1, 0))
start_num = ''
# digits_with_offset.append((start_num, 0))
if style:
if '"position:relative' not in style and end_num.strip() == '':
digits_with_offset.append((digit, 0))
continue
# 提取偏移量变量
if end_num.strip().isdigit():
pass
else:
offset_match = re.search(r'left:var\(([^)]+)\)', style)
if not offset_match:
offset_match = re.search(r'right:var\(([^)]+)\)', style)
offset_var = offset_match.group(1)
offset = evaluator.variables.get(offset_var, 0)
offset = -offset
else:
offset_var = offset_match.group(1)
offset = evaluator.variables.get(offset_var, 0)
# 按原始需求进行15px单位转换
offset = int(offset / 15) if offset != 0 else 0
digits_with_offset.append((digit, offset))
digit,style = '',''
if end_num and end_num.strip().isdigit(): # 添加结束数字
for s2 in end_num: # 添加结束数字
# print('s2',s2)
digits_with_offset.append((s2, 0))
end_num = ''
print(digits_with_offset)
return move_by_offset(digits_with_offset)
…
(2) 处理文本的数据
① 获取数字和位置信息
这里 处理需要注意很多细节,比如 很多数据没有 在span标签中,如何处理,
"position:relative’ 是否存在 ,left: 还是right: 等
3.结果

T9 font_sprites_challenge (一种思路)
- 获取图片 分隔
- 计算相似度
- 细节处理

def calculate_hash(image_path):
"""计算图片的感知哈希值"""
img = cv2.imread(image_path)
if img is None:
raise ValueError(f"无法读取图片: {image_path}")
img = cv2.resize(img, (8, 8), interpolation=cv2.INTER_AREA)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
avg = gray.mean()
hash_str = ""
for i in range(8):
for j in range(8):
# 如果像素值大于平均值则为1,否则为0
hash_str += "1" if gray[i, j] > avg else "0"
return hash_str
def hamming_distance(hash1, hash2):
if len(hash1) != len(hash2):
raise ValueError("两个哈希值长度必须相同")
return sum(c1 != c2 for c1, c2 in zip(hash1, hash2))
T10 font_svg_challenge
- 通过获取的数据,整理一份字典
- 计算相似度
def parse_data(data):
paths = re.findall('<path d="(.*?)"', data['svg_content'], re.S)
result = ""
for path in paths:
min_dist = float("inf")
matched_digit = ""
for digit, ref_path in ref_paths.items():
dist = Levenshtein.distance(path, ref_path)
if dist < min_dist:
min_dist = dist
matched_digit = digit
result += matched_digit
result = [int(result[i:i + 4]) for i in range(0, len(result), 4)]
print("识别结果:", result)
return result
- 细节处理

T16 slide_scratch_challenge
- 获取图片
2 通过提示词,和物体信息 计算移动距离
由于下载的图片可以看见信息 这里首先对提示词整理,大概十几个类别,同时对物体信息检测分隔(yolo)。
计算这里 可以训练分类模型 ,或者相似度模型
3.验证token
4. 处理细节 请求结果

T17 slide_puzzle_challenge
- 获取图片
2 计算距离
这里分隔图片 上下,使用边缘算子,计算拼接相似度,每次移动一个像素。选择最合理的距离
def calculate_distance(image_path, split_y=99):
img = cv2.imread(image_path)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
upper = gray[:split_y, :] # 上半部分(需要移动的区域)
lower = gray[split_y:, :] # 下半部分(固定区域)
upper_edges = cv2.Canny(upper, xxxx, xxxxxx) #自己参数调整
contours, _ = cv2.findContours(upper_edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
if not contours:
raise ValueError("未检测到上半部分轮廓,请调整边缘检测参数")
cnt = max(contours, key=lambda c: cv2.contourArea(c))
x, y, w, h = cv2.boundingRect(cnt) # 上半部分轮廓的边界框
print(x, y, w, h )
result = cv2.matchTemplate(lower, upper_edges, cv2.TM_CCOEFF_NORMED)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
match_x, _ = max_loc # 匹配到的水平坐标
distance = match_x - x
return distance
- 验证token
- 处理细节 获取结果

T18 cap6_challenge
- 获取图片
- 通过cv2 或者dddd 计算两次距离
- 计算结果

T19 slide_cylinder_challenge
上一篇已经写了。
ef get_distince():
# 读取图像
image = cv2.imread('img.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# Canny边缘检测
edges = cv2.Canny(gray, 50, 150)
# 寻找轮廓(用于确定人物区域)
contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
person_x = 100
# 假设最大的轮廓是人物(实际需根据图像情况调整)
if contours:
largest_contour = max(contours, key=cv2.contourArea)
x, y, w, h = cv2.boundingRect(largest_contour)
person_x = x
else:
print("未检测到轮廓")
return person_x
补充点:
(1)计算轨迹(x,y,t) tracks = track[:-50]
(2) 计算的轨迹 的编码不是标准的

T20 cap8_challenge
- 获取图片
目标检测 分隔图片
图片标注
进行相似度模型训练
计算获取结果
可以借鉴这个帖子(https://www.52pojie.cn/forum.php?mod=viewthread&tid=1888314)
3 请求 注意细节

T26 click_stitch_challenge
- 获取图片
- 计算旋转角度
def solve_puzzle_fixed_layout(img_path, inner_gap=8, outer_gap=8, strip=5):
“”"
逻辑:
- 固定 [1,2,3,4] 位置,只尝试每块的旋转角度。
- 先拼接 (1,2),计算水平边缘匹配;
- 拼接 (3,4),计算水平边缘匹配;
- 拼接 (上半, 下半),计算垂直边缘匹配;
- 得分 = 上下+左右总相关系数。
“”" - 验证token
- 处理细节 获取结果

总结:
写到后面,突然需要些的太多,直接粘贴代码也不可取,那就简单提示一下吧.






