申请会员ID: randompath【申请通过】
1、申 请 I D :randompath2、个人邮箱:manwu91@gmail.com
3、原创技术文章:这是之前在freebuf投稿的两篇文章
关于行为验证分析的文章:http://www.freebuf.com/web/140693.html
关于hook微信的文章: http://www.freebuf.com/web/156944.html
个人首页:
请看好申请规则,不要只发一个url,把内容发布于论坛审核。 Hmily 发表于 2019-7-31 16:02
请看好申请规则,不要只发一个url,把内容发布于论坛审核。
好的,那两篇文章是两年前的了,这里贴个去年写的关于破解字体加密的。这篇文章之前发布在我的博客上 http://www.wisedream.net/2018/10/10/spider/crack-qxb-font/
在抓取某信宝数据时,发现有几个字段的值与真实值不符,分析发现源码中由class qxb-num修饰的标签数据都是错乱的。
![由qxb-num修饰的标签](http://www.wisedream.net/res/img/spider/qxb_font1.png)
查看qxb-num样式,发现特殊字体
![](http://www.wisedream.net/res/img/spider/qxb_font2.png)
由此断定开发人员是在字体库上动的手脚。
## 字体的绘制与ttf
在查阅[相关文档](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6.html)后,总结字体的绘制过程为:
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
```py
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[-1]
else:
predict += c
return predict
if isinstance(ss, str):
return _decrypt(ss)
else:
return
```
对于打乱的glyf,先标记glyph数据与真实字符,之后通过比对glyph数据找到对应的真实字符就可以了。
```
"""
企信宝字体加密: glyf table应对方案
"""
from fontTools.ttLib import TTFont
import string
def _get_glyph_name(c: str, font):
return font.getBestCmap()
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.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.data
predict += refer_glyph_data
else:
predict += c
return predict
if isinstance(ss, str):
return _decrypt(ss)
else:
return
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()
``` I D:randompath
邮箱:manwu91@gmail.com
申请通过,欢迎光临吾爱破解论坛,期待吾爱破解有你更加精彩,ID和密码自己通过邮件密码找回功能修改,请即时登陆并修改密码!
登陆后请在一周内在此帖报道,否则将删除ID信息。 randompath报到
页:
[1]