【最新猿人学】 动态字体,随风漂移 woff字体解密,XML文件读取

0 阅读5分钟

暗号:aHR0cHM6Ly9tYXRjaC55dWFucmVueHVlLmNuL21hdGNoLzc=

 

题目为:

image.png

先抓包分析接口,发现参数和请求头中均无加密值:

image.png

再看获取到的数据,得到了woff 和 data 两条数据,这里的woff肯定就是字体的base64加密格式,而data就是数据,但是需要将数据使用这里的woff字体进行解密

image.png

所以接下来访问接口,并且将woff数据保存为woff字体格式,以下提供python函数可直接将base64 数据传入函数,保存为woff字体文件

def woff_file(base):

    woff\_binary\_data = base64.b64decode(base)

    # 将二进制数据写入文件

    output\_filename = "font.woff"

    with open(output\_filename, "wb") as f:

        f.write(woff\_binary\_data)

        

之后在当前目录下就能看到font.woff 这个字体文件了,然后使用打开字体的软件将字体打开(这里我是用的是FontForge , 免费的)

文件里面大部分都是空的,编码了数字的文本左上角都有一段“unia 数字 ”这种样式

image.png

所以推测后面的数字和浏览器中得到的data数据中的数字相关,接下来手动复制一段浏览器获取到的woff base64文本传入函数,生成woff文件:

image.png

再使用fontforge打开该文件,一对比就发现数字确实是有关联的,浏览器中的2的数字是241,字体文件中的2后面的数字也是241

image.png

image.png

对比其他的数字也有这个规律,所以接下来我们只需要将后面的数字进行对比了以后,就能够正确解密data数据,于是使用下面这段代码生成XML 格式的字体描述文件

\#path是woff文件的路径

def get\_woff\_data(path):

    font = TTFont(path)
    
    font.saveXML("font.xml")

 

接下来打开xml文件查找数据规律,但发现很多地方都是没有规律的:

image.png

image.png

但找到一个地方,就是TTGlyph ,这里的on参数的值不会修改,再根据前面的x,y推测,这里应该是字形的坐标,所以将on的值全部记录下来

image.png

并且根据unia后面的数字先手动还原对应的数字,得到一个列表:

font = {"10010101001110101011010101010101000100100": 9,

            "111111111111111": 4,

            '1111111': 7,

            '100110101001010101011110101000': 2,

            '1001101111': 1,

            '101010101101010001010101101010101010010010010101001000010': 8,

            '10101100101000111100010101011010100101010100': 3,

            '10100100100101010010010010': 0,

            '10101010100001010111010101101010010101000': 6,

            '1110101001001010110101010100101011111': 5,

            }

列表中记录了on的值与对应的阿拉伯数字,

接下来访问接口,每次都将woff文件保存为xml 文件,并且读取TTGlyph 中每一个数字编码( unia数字 ) 与里面的 on组成的数字串,使用font数组将其还原成数字,最终得到结果

image.png

附上python代码,注意请求头、cookie等参数已删除,请自行添加:

import requests

import base64

from fontTools.ttLib import TTFont

 

def woff\_file(base):

    woff\_binary\_data = base64.b64decode(base)

    # 将二进制数据写入文件

    output\_filename = "font.woff"

    with open(output\_filename, "wb") as f:

        f.write(woff\_binary\_data)

 

def get\_woff\_data(path):

    font = TTFont(path)

    font.saveXML("font.xml")

def get():

    font = {"10010101001110101011010101010101000100100": 9,

            "111111111111111": 4,

            '1111111': 7,

            '100110101001010101011110101000': 2,

            '1001101111': 1,

            '101010101101010001010101101010101010010010010101001000010': 8,

            '10101100101000111100010101011010100101010100': 3,

            '10100100100101010010010010': 0,

            '10101010100001010111010101101010010101000': 6,

            '1110101001001010110101010100101011111': 5,

            }

    nfont = {}

    with open("font.xml", "rb") as file:

        content = file.read()

 

    from lxml import etree

    tree = etree.fromstring(content)

 

    for i in tree.xpath('./glyf/TTGlyph')\[1:]:

        k = ""

        for j in i.xpath('./contour'):

            for t in j.xpath('pt/@on'):

                k += t

        nfont\[i.xpath('./@name')\[0]\[-3:]] = font\[k]

    return nfont

sum = 0

for i in range(1,6):

    headers = {

 

    }

    cookies = {

 

    }

    url = "<https://match.yuanrenxue.cn/api/question/7>"

    params = {

        "page": str(i),

        "pageSize": "10",

        "kw": ""

    }

    if i==5:

        headers\['user-agent'] = 'yuanrenxue'

    response = requests.get(url, headers=headers, cookies=cookies, params=params).json()

 

    woff = response\['woff']

    woff\_file(woff)

    get\_woff\_data("font.woff")

 

    sz = get()

    print(sz)

    for i in response\['data']:

        num = 0

        for j in i.split('\&#'):

            a = j\[-3:]

            if a == '':

                 continue

            num = num\*10 + sz\[str(a)]

        print(num)

        sum += num

print(sum)