猿人学之雪碧图样式干扰

篇幅有限

完整内容及源码关注公众号:ReverseCode,发送

题目

https://match.yuanrenxue.com/match/4

image-20210917162428942

抓包

https://match.yuanrenxue.com/api/match/4

image-20210917162624937

分析

image-20210917162856315

该页面每个td中img个数和实际展示个数不一致,且部分img被display: none;属性隐藏后个数一致,但img排列组合顺序和实际展示不一致,目测和style中的left属性有关。

通过抓包分析以上请求中返回的info属性,通过html格式化后,发现是多个td中包裹多个img标签,不过个数和展示的个数不一致,且src中的内容是data:image/png;base64,开头的图片转为base64形式。通过分析将对应的图片转为数字字典如下

1
2
3
4
5
6
7
8
9
10
11
12
image_dict = {
'data:image/png;base64,iVBORw0KGgoAAAANSUh...': 0,
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABUAAAAd...': 6,
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAdCAY...': 8,
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABUAAAAcCAYAAAC...': 1,
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQA...': 9,
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABUAAAAbC...': 4,
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAdCA...': 2,
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQA...': 3,
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAeCAYAAAAsEj5...': 7,
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABUAAAAcCAY...': 5
}

将格式化后的html中的base64图片转为数字

image-20210917164659843

对比得到两个结论,首先class中去除一个加密字符串的属性,且style中部分标签加上了display: none;属性。说明拿到服务端返回结果后,js中为style加上了display为none的属性。

全局搜索'display','none'或者'display', 'none'

image-20210917173431738

其中data.info就是获取返回内容中info的部分,也就是<td>标签里面的内容,通过JQuery的选择器,选择标签中有number的元素,并将<td>标签的内容添加进去,通过获取data中key和value中的值,并替换一些字符,最后经过md5算法加密,得到一串密文,在密文前面加上一个.,并赋值给变量j_key,通过选择器,选择有密文这个属性的标签,并将其样式设置成display:none,最终再删除属性中的密文

爬虫

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
image_dict = {
'data:image/png;base64,iVBORw0KGgoAAAANSUh...': 0,
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABUAAAAd...': 6,
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAdCAY...': 8,
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABUAAAAcCAYAAAC...': 1,
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQA...': 9,
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABUAAAAbC...': 4,
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAdCA...': 2,
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQA...': 3,
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAeCAYAAAAsEj5...': 7,
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABUAAAAcCAY...': 5
}

answer_num_list = []


def get_base64_data(page_num):
url = 'http://match.yuanrenxue.com/api/match/4?page={}'.format(page_num)
headers = {
'Host': 'match.yuanrenxue.com',
'Pragma': 'no-cache',
'Referer': 'http://match.yuanrenxue.com/match/4',
'User-Agent': 'yuanrenxue.project',
'X-Requested-With': 'XMLHttpRequest'
}
res = requests.get(url=url, headers=headers)
# print(res.text)
return res.json()['info'], res.json()['key'], res.json()['value']


def b642jpg(b64str, name):
data = base64.b64decode(b64str)
with open('{}.jpg'.format(name), 'wb') as f:
f.write(data)
print('打印完毕')


# var j_key = '.' + hex_md5(btoa(data.key + data.value).replace(/=/g, ''));
# 利用key和value计算出属性为display=none的md5索引值
def get_j_key(key, value):
return hashlib.md5(base64.b64encode((key + value).encode()).replace(b'=', b'')).hexdigest()


# 获取td中4个图片
def parse_every_group_nums(info_data):
pattern = re.compile(r'<td>(.*?)</td>')
every_group_nums_list = pattern.findall(info_data)
return every_group_nums_list


# 利用j_key和每个图片对应的hash值,确定出要被用的所有数字子图片,及其相对位置偏移值
def parse_real_use_num_info(every_group_nums, j_key):
# 找到base64
pattern = re.compile(r'img_number (.*?)"')
img_number_list = pattern.findall(every_group_nums)
# 找到图片
pattern = re.compile(r'base64,(.*?)"')
ba64_str_list = pattern.findall(every_group_nums)
# 找到样式
pattern = re.compile(r'style="(.*?)"')
number_style_list = pattern.findall(every_group_nums)

# 寻找所有要用的子图
ba64_str_list = [ba64_str_list[index] for index, img_number in enumerate(img_number_list) if img_number != j_key]
num_list = [image_dict['data:image/png;base64,' + __] for __ in ba64_str_list]

# 匹配每个子图实际对应的偏移量 6801 -> ['0', '11.5', '-11.5', '0.0']
number_style_list = [number_style_list[index].replace('left:', '').replace('px', '') for index, img_number in
enumerate(img_number_list) if img_number != j_key]

# 根据偏移值,计算真实的数字顺序
ture_order_list = caculate_css_left(number_style_list, num_list)

# 将每小组数字拼接并保存
temp_num = 0
for index, num in enumerate(ture_order_list[::-1]):
temp_num += num * 10 ** index
answer_num_list.append(temp_num)


# 根据图片映射的数字和图片的偏移值,计算出数字的真实顺序,列表排序返回
def caculate_css_left(number_style_list, num_list):
# [0, 1, -1, 0]
number_style_list = [round(float(__) / 11) for __ in number_style_list]
# 定义数组
ture_order_list = ['']*len(number_style_list)
for index, number_style in enumerate(number_style_list):
ture_order_list[int(index + number_style)] = num_list[index]
return ture_order_list


if __name__ == '__main__':
# info, _, __ = get_base64_data(1)
# # <td>有10组 left有63个 display有0个,需要md5计算进行拼接base64 ed501a5e229d41330bee8399441bfbfb有39次 57feebf056bfb527e9ad8561e0694b0a有24次
# '''
# b642jpg(b64str, 'test')
for page_num in range(1, 6):
info_data, key, value = get_base64_data(page_num)
j_key = get_j_key(key, value)
every_group_nums_list = parse_every_group_nums(info_data)
for every_group_nums in every_group_nums_list:
parse_real_use_num_info(every_group_nums, j_key)
print(sum(answer_num_list))
文章作者: J
文章链接: http://onejane.github.io/2021/09/17/猿人学之雪碧图样式干扰/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 万物皆可逆向
支付宝打赏
微信打赏