zoukankan      html  css  js  c++  java
  • 破解字体加密

    前言

      字体加密在源代码中是乱码的,但在浏览器显示是正常的。

      本博文仅供学习研究。

    加密

      字体加密的大概流程:

        1、在后端返回数据到前端时,将一个unicode编码与被加密字符映射并生成字体文件;

        2、此时后端返回的数据是与被加密字符映射的unicode,此unicode与加密字符并无关系,根据编码表转换是转换成其他字符;

        3、前端接收到数据,根据字体文件的映射解析数据,显示到界面。

      此流程为本人猜想,并未实践过。

    解密

      以 58 为例,

      待解密字符:驋驋龤;

      解密思路:按照浏览器解析行为

        1、找到字体文件

        2、根据待解密字符的unicode编码找到此unicode编码的真正映射字符

    • 手动解密

        1、找到待解密字符的字体文件,可以通过css样式找到;

          58字体文件为base64:

        

        2、将base64 转码并存储为 .ttf 文件:

          在此(https://www.motobit.com/util/base64-decoder-encoder.asp)网站可解码base64并存储为二进制数据的 .bin 文件,将下载的二进制数据的 .bin 文件后缀更改为 .ttf,

          

        3、通过 FontCreator 软件打开字体文件,可看到字符与unicode的映射关系:

          

        

        4、将待解密字符转换为unicode编码:驋驋龤:驋驋龤

          可通过此网站(https://www.css-js.com/tools/unicode.html)在线转换,得到结果:

          

        5、根据待解密字符的unicode编码(驋驋龤)在FontCreator 软件中查找对应的字符,得知 驋驋龤 解密后为 220。

          

    • 代码解密

        python为例:

        

     1 from fontTools.ttLib import TTFont
     2 import base64
     3 
     4 
     5 
     6 # 模块依赖:
     7     # base64 :解码base64
     8     # TTFont :解析字体文件
     9 
    10 
    11 # 存储的ttf文件路径及名称
    12 filePath = 'decode.ttf'
    13 
    14 # 字体文件的base64
    15 base64str = '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'
    16 
    17 # 待解密字符
    18 encodestr = u'驋驋龤'
    19 
    20 
    21 # 存储文件(以二进制方式)
    22 # filePath :存储的文件路径及名称
    23 # data :需要存储的数据
    24 def writeTTFFile(filePath, data):
    25     #print(encodestr.encode("unicode_escape").decode())
    26     #print(int(encodestr.encode("unicode_escape")[2:], 16))
    27     with open(filePath, 'wb') as f:
    28         f.write(data)
    29 
    30 # 解析字体并解密待解密字符
    31 # filePath :字体文件的路径及名称
    32 # str :待解密字符
    33 # return :返回解密后的字符
    34 def TTFDecode(filePath, encodestr):
    35     font = TTFont(filePath)
    36     strRes = font.getBestCmap()
    37     print(strRes)
    38     glypDict = font.getReverseGlyphMap()
    39     print(glypDict)
    40     ret = ''
    41     for ch in encodestr:  #遍历待解密字符,挨个解密
    42         strResKey = int(ch.encode("unicode_escape")[2:], 16)  #将单个字符转换为unicode并截取16进制部分,并转换为10进制数字
    43         glypDictKey = strRes[strResKey]  #通过转换出的10进制数字在 'strRes' 里查找对应的glyph资源
    44         ret = ret + str(glypDict[glypDictKey] - 1)  #在 'strRes' 查找出的值在 'glypDict' 里查找出对应的字符并拼接,得到解密后的字符, 这里减1 是58加密时的规则,其他网站的加密可能不是这样
    45     return ret
    46 
    47 writeTTFFile(filePath, base64.b64decode(base64str))
    48 decodestr = TTFDecode(filePath, encodestr)
    49 print(decodestr)

        代码重点在 34、35行,这两行解析了字体文件的映射关系;

          print(strRes) 输出为:{38006: 'glyph00009', 38287: 'glyph00004', 39228: 'glyph00002', 39499: 'glyph00003', 40506: 'glyph00010', 40611: 'glyph00007', 40804: 'glyph00008', 40850: 'glyph00005', 40868: 'glyph00001', 40869: 'glyph00006'}

          print(glypDict):{'glyph00000': 0, 'glyph00001': 1, 'glyph00002': 2, 'glyph00003': 3, 'glyph00004': 4, 'glyph00005': 5, 'glyph00006': 6, 'glyph00007': 7, 'glyph00008': 8, 'glyph00009': 9, 'glyph00010': 10}

          例如:待解密字符:驋 的unicode编码的10进制为 39499 ,那么在 strRes 中查找对应的值为 glyph00003 ,glyph00003 在 glypDict 中查找对应的值为 3,再减 1就是2,得到解密后的字符就是 2。

          减 1 操作是58网站的加密规则,可通过对比观察得到。

        

        可以将 ttf 文件转为 ttx 文件,ttx 文件直观展示了映射关系,通过代码:TTFont('encode.ttf').saveXML('decode.ttx'),转换;

         font.getBestCmap():这段代码就是解析得到

     

         font.getReverseGlyphMap():这段代码就是解析得到:

    • 其他演示

        待解密字符: ;

        字体文件:http://qidian.gtimg.com/qd_anti_spider/PUNzUOms.woff

     1 def decode():
     2     encodestr = ''
     3     glypDict = {
     4         'zero': '0',
     5         'one': '1',
     6         'two': '2',
     7         'three': '3',
     8         'four': '4',
     9         'five': '5',
    10         'six': '6',
    11         'seven': '7',
    12         'eight': '8',
    13         'nine': '9',
    14         'period': '.'
    15 
    16     }
    17     strRes = TTFont(BytesIO(requests.get('http://qidian.gtimg.com/qd_anti_spider/PUNzUOms.woff').content)).getBestCmap()
    18     print(strRes)
    19     ret = ''
    20     for ch in encodestr:
    21         ret = ret + glypDict[strRes[int(ch.encode('unicode_escape')[2:], 16)]]
    22     return ret
    23 print(decode())

        与58不同,字体文件是 .woff,但原理一样,在解密时,应手动解密一遍,配合 FontCreator 软件,或转成 xml格式,仔细观察。

     

    Welcome to my blog!
  • 相关阅读:
    手写编译器之词法分析器一
    手写编译器之前
    PAT(A) 1005. Spell It Right (20)
    PAT(A) 1001. A+B Format (20)
    PAT(A) 1073. Scientific Notation (20)
    PAT(A) 1061. Dating (20)
    PAT(A) 1058. A+B in Hogwarts (20)
    PAT(A) 1027. Colors in Mars (20)
    PAT(A) 1019. General Palindromic Number (20)
    PAT(A) 1031. Hello World for U (20)
  • 原文地址:https://www.cnblogs.com/blogCblog/p/12497035.html
Copyright © 2011-2022 走看看