网站字体加密逆向分析
这里以XXU租为例,在抓取商品的套餐价格时,写完代码跑出来发现价格全是空
在浏览器控制台打开发现网页显示的价格,在元素定位里看到是乱码
到源代码中查看,发现价格用的是字符实体(即开头),那么把价格最高位拿去转化一下看是什么结果
结果如图,是乱码,也即是这个字符是开发者自定义的
字符是包含在字体中,所以网站应该是使用了自定义字体,我查看了《前端反爬虫小技巧之字体库加密》(https://zhuanlan.zhihu.com/p/441546113),写的很清晰,正常情况下,同一个字的字码是一致的(十六进制),比如1的字码是31,在所有字体中1的字码都是31。而如果改变了字体的字码,改变字码和字形的映射关系,就能创造出其他程序无法识别的字体。
知道了这个原理就很好办了,
先定位网站价格处使用的字体文件,元素定位到价格,看到class=num使用的字体为PingFangSC-Regular-num,
点击.num样式跳转到样式表,看到PingFangSC-Regular-num字体是d0b77af9.woff的别名
在控制台网络请求中筛选类型为字体,找到d0b77af9.woff请求链接,再复制到浏览器地址栏进行下载
下载后把d0b77af9.woff导入到字体编辑器FontCreator中,可以看到字体的字码都被改变了,并且没有规律,是随机给字形加字形码。
我还想着如果有规律还能用与之用一个普通的字体文件进行一一匹配,没有的话这么一来要把这些数字正确取出来,需要手写一个映射关系,即F461对应数字1,F6EB对应数字2,以此类推。
这里因为实际用到的只有0-9,不需要其他的,所以没把全部字体进行映射,如果需要全部字体映射也不难,打开字体文件后,使用OCR识别一下,再纠正少量错误的字体即可得到全部的自定义字体。
接下来是编码部分:
import re
from fontTools.ttLib import TTFont
class font_decrypt:
# 解码方法
def decrypt(self,word_str):
font_dic = self.font_dic()
res = ''
# 去除实体字符的&#x和结尾的;
word_list = re.split(";", word_str.lower().replace("&#x", ""))
word_list.pop(-1)
# 匹配并组合成一个字符串返回
for word in word_list:
res += font_dic.get(word)
return res
# 字体映射
def font_dic(self):
# 预设要解码的字体,顺序和字体文件保持一致
words = '1234567890'
font_file = r"C:\Users\lonelylizard\Downloads\d0b77af9.woff"
# 传入woff文件名和要解密的字符串
font = TTFont('{}'.format(font_file))
# 这个woff字体文件前面两个无用字符去掉,用不到
lis = font.getGlyphOrder()[2:]
# 构建映射字典
dic = {}
for index, value in enumerate(words):
# 删除font中的uni,保留十六进制字符
string = lis[index].replace('uni', '')
# 构建映射字典
dic.update({string: value})
return dic
if __name__ == '__main__':
font_decrypt = font_decrypt()
# 多个字解码
# res = font_decrypt.decrypt(r"")
# 输出:解密结果:88
# 单个字解码
res = font_decrypt.decrypt(r"")
print("解密结果:",res)
# 输出:解密结果: 8
至此,分析和操作完成,价格也顺利拿到了
总结思路:
1、拿到网站的自定义字体文件
2、下载下来使用FontCreator打开,观察字码规律,字码有规律可以考虑和正常的字体文件做映射。字码无规律,则把该自定义字体文件内的字形按顺序手动写成一个字符串,如果字体非常多,可使用OCR识别来帮助提取文字。
3、用Python的fontTools库读取该字体文件,并和前面组装好的字符串内的字符进行一一匹配(组装成字典),再传入任意加密后的字体字符即可读出正确的结果,见上面的示例代码
注:实体字符诸如其中E6A5即为十六进制字码
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。
评论已关闭