吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 5616|回复: 4
收起左侧

[会员申请] 申请会员ID: randompath【申请通过】

[复制链接]
吾爱游客  发表于 2019-7-31 12:12
1、申 请 I D :  randompath
2、个人邮箱:manwu91@gmail.com
3、原创技术文章:  这是之前在freebuf投稿的两篇文章
关于行为验证分析的文章:http://www.freebuf.com/web/140693.html
关于hook微信的文章: http://www.freebuf.com/web/156944.html
个人首页:

fb首页

fb首页




发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

Hmily 发表于 2019-7-31 16:02
请看好申请规则,不要只发一个url,把内容发布于论坛审核。
吾爱游客  发表于 2019-8-1 09:50
Hmily 发表于 2019-7-31 16:02
请看好申请规则,不要只发一个url,把内容发布于论坛审核。

好的,那两篇文章是两年前的了,这里贴个去年写的关于破解字体加密的。这篇文章之前发布在我的博客上 http://www.wisedream.net/2018/10/10/spider/crack-qxb-font/

在抓取某信宝数据时,发现有几个字段的值与真实值不符,分析发现源码中由class qxb-num修饰的标签数据都是错乱的。
由qxb-num修饰的标签
查看qxb-num样式,发现特殊字体

由此断定开发人员是在字体库上动的手脚。

字体的绘制与ttf

在查阅相关文档后,总结字体的绘制过程为:

  1. 根据字符的unicode编码找到glyph名称
  2. 根据glyph名称找到glyph
  3. 使用glyph进行绘制

A TrueType font file consists of a sequence of concatenated tables. A table is a sequence of words. Each table must be long aligned and padded with zeroes if necessary.

一个TrueType Font字体库包含几个table。这里需要用到的两个table如下(tag为table的名称)

tag table
cmap character to glyph mapping
glyf glyph data

破解过程

根据字体的绘制过程,可以猜测有两种方式实现字体加密

  1. 打乱字符编码与glyph映射(即cmap table)
  2. 打乱glyph名称与glyph数据(即glyf table)

利用fonttools,使用如下代码将字体转为xml

from fontTools.ttLib import TTFont
from io import BytesIO
import requests

font_content = requests.get('https://cache.qixin.com/pcweb/font-awesome-qxb-1bd55e43.woff2').content
font_file = BytesIO(font_content)
font = TTFont(font_file)
font.saveXML('font.xml')

查看生成的xml文件,发现cmap节点部分数据

      <map code="0x30" name="icon-number_9"/><!-- DIGIT ZERO -->
      <map code="0x31" name="icon-number_3"/><!-- DIGIT ONE -->
      <map code="0x32" name="icon-number_7"/><!-- DIGIT TWO -->
      <map code="0x33" name="icon-number_2"/><!-- DIGIT THREE -->
      <map code="0x34" name="icon-number_0"/><!-- DIGIT FOUR -->
      <map code="0x35" name="icon-number_1"/><!-- DIGIT FIVE -->
      <map code="0x36" name="icon-number_5"/><!-- DIGIT SIX -->
      <map code="0x37" name="icon-number_8"/><!-- DIGIT SEVEN -->
      <map code="0x38" name="icon-number_6"/><!-- DIGIT EIGHT -->
      <map code="0x39" name="icon-number_4"/><!-- DIGIT NINE -->
      <map code="0x41" name="icon-upper_S"/><!-- LATIN CAPITAL LETTER A -->
      <map code="0x42" name="icon-upper_Q"/><!-- LATIN CAPITAL LETTER B -->
      <map code="0x43" name="icon-upper_K"/><!-- LATIN CAPITAL LETTER C -->

由此可以断定这个字体库通过打乱cmap table实现实体加密。

破解

对于打乱的cmap,只要找到字符对应的glyph名称就可以了

"""
企信宝字体加密: cmap table应对方案
"""

def decrypt(ss, font_file):
    """
    根据字体文件解密字符串
    :param ss: str or list of str
    :param font_file: file like object or file path
    :return:
    """
    with TTFont(font_file) as font:
        cmap = font['cmap'].getBestCmap()

    def _decrypt(s):
        predict = ''
        for c in s:
            if c in PLAIN_CHARS:
                predict += cmap[ord(c)][-1]
            else:
                predict += c
        return predict

    if isinstance(ss, str):
        return _decrypt(ss)
    else:
        return [_decrypt(s) for s in ss]

对于打乱的glyf,先标记glyph数据与真实字符,之后通过比对glyph数据找到对应的真实字符就可以了。


"""
企信宝字体加密: glyf table应对方案
"""

from fontTools.ttLib import TTFont
import string

def _get_glyph_name(c: str, font):
    return font.getBestCmap()[ord(c)]

PLAIN_BOOK = string.ascii_uppercase + string.ascii_lowercase + '1234567890'

def _load_refer_glyph_data():
    """
    加载已知宋体库,取得真实的glyphdata与name字典
    :return: {glyphdata->bytes: char_name}
    """
    import os.path
    font_file = os.path.join(os.path.dirname(__file__), 'font-awesome-qxb-5ffe2d46.woff2')
    with TTFont(font_file) as font:
        cipherbook = 'XSQRTWFCZHDIN' \
                     'LAKEUGBMPOVJY' \
                     'rpfcbtdnajuhg' \
                     'zyikxovqleswm' \
                     '7658419203'
        glyphset = font['glyf'].glyphs
        return {glyphset[_get_glyph_name(p, font)].data: c for p, c in zip(PLAIN_BOOK, cipherbook)}

refer_glyph_data = _load_refer_glyph_data()

def decrypt(ss, font_file):
    """
    根据字体文件解密字符串
    :param ss: str or list of str
    :param font_file: file like object or file path
    :return:
    """
    font = TTFont(font_file)
    glyphs = font['glyf'].glyphs

    def _decrypt(s):
        predict = ''
        for c in s:
            if c in PLAIN_BOOK:
                glyph_data = glyphs[_get_glyph_name(c, font)].data
                predict += refer_glyph_data[glyph_data]
            else:
                predict += c
        return predict

    if isinstance(ss, str):
        return _decrypt(ss)
    else:
        return [_decrypt(s) for s in ss]

def _test():
    import os
    cipher = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890'
    plain = 'XSQRTWFCZHDINLAKEUGBMPOVJYrpfcbtdnajuhgzyikxovqleswm7658419203'
    predict = decrypt(cipher, os.path.join(os.path.dirname(__file__), 'font-awesome-qxb-5ffe2d46.woff2'))
    print(predict)
    print(predict == plain)

if __name__ == '__main__':
    _test()
Hmily 发表于 2019-8-1 14:31
I D:randompath
邮箱:manwu91@gmail.com

申请通过,欢迎光临吾爱破解论坛,期待吾爱破解有你更加精彩,ID和密码自己通过邮件密码找回功能修改,请即时登陆并修改密码!
登陆后请在一周内在此帖报道,否则将删除ID信息。
randompath 发表于 2019-8-1 15:35
randompath报到
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-15 10:04

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表