Kindle Paperwhite 2代 自定义字体分析

11月23日:html

因为Kindle界面使用的是Java,因此我一开始考虑自定字体时就是从Java入手的。(之前没用过Kindle,KPW2算是个人第一台电纸书)
反汇编 /opt/amazon/ebook/lib/kindlet-2.2.jar 文件,能够看到UI字体配置选项java

/opt/amazon/ebook/lib/portability.jar 文件的 com.amazon.ebook.pl.service 包里面的 FontService.class 定义了基本的字体配置工厂类。(Java Beans的一种写法,通常在设计模式中叫作工厂模式。)git

/opt/amazon/ebook/lib/ReaderContentSDK.jar 里面的 resource 的 FontPreferencesResources 定义了所有的字体列表,可是没有圆体。由于圆体是经过更在外面添加的。查看 /usr/bin 下面的脚本很容易发现玄机。web

继续搜索,在 /usr/java/lib 内发现文字镜像 fonts.cramfs.img 和配置文件fontconfig.properties 。挂载镜像后能够看到Kindle自带的所有字体,可是此处的字体引用须要在Java的程序中自行定义,修改量很大,天文数字般,要重打包,反汇编jar包,修改30多个类里面的引用。所此处放弃直接的程序修改。设计模式

继续查看Webkit部分发现自定义字体的更新代码,查看 /usr/share/webkit-1.0/pillow/updating_content_package_fonts.html文件代码,发现其为Kindle系统的显示界面定义,放弃。缓存

找到配置文件 /usr/lib/font/manifests/manifest_zh-Hans 其定义了外置的字体文件和字体文件的Hash Code,找到可能的破解方法之一。服务器

{
  "languages": "zh-Hans",
  "type": "font",
  "uniqueIdentifier": "zh-Hans",
  "files": "zh-Hans.font",
  "zh-Hans.font.md5": "37824a7650fc8f1fd952413fc5fad029",
  "STKaiMedium.ttf.md5": "0a3083d601f3c2fea59930ecfe664c2a",
  "STKaiBold.ttf.md5": "7e26a55e24fe35c98b2c89ceb7244cf3",
  "STYuanMedium.ttf.md5": "1cafad348452f68baccc1df5e80e1165",
  "version": 20130808,
  "fonts.zh-Hans": "stkai,styuan",
  "font.stkai.display": "\u6977\u4f53",
  "font.styuan.display": "\u5706\u4f53"
}

在走了前面那么多弯路后继续回来看 system/fonts 文件夹下面的*.font文件。因为我没有日语字体的推送,因此打开一本日语的Kindle电子书,而后等待字体更新。可是一直没有推送,因而我切换为日语重启后惊奇地发现有了更新的字体。因此咱们能够猜想,其实字体的推送安装只须要拷贝文件,而后重启。(但后面的测试彷佛不是如此,须要联网下载完毕后系统自动在未重启前安装更新,而非重启,在重启前其实就安装完了,以后的重启只是为了更新字体缓存。)app

查看了字体的打包格式,cramfs打包的,这个工具源码在Kindle的源码包里面是有的。编译安装后解包字体,自定义字体的庐山真面目出现了。框架

11月25号:函数

成功截取日语字体更新文件,ja.bin,一会解包分析。(bin文件的下载地址后面有给出)
奇怪的是,解包的字体和安装成功后的字体文件类型不一致,目前更新包的字体没法解包,查阅脚本,在 /usr/lib/contentpack/ 下发现玄机。原来更新包内的字体实际上是封装好的,而后在系统内进行转码为cramfs格式的font镜像,目前专心于解包更新包里面的字体镜像中……(在dalvik帮助下12月6日更正)

查看相关字体更新脚本,列表以下:
/usr/lib/contentpack/csp_functions

/usr/sbin/csp-update-props
update font.properties using font manifests
此脚本首先调用 /etc/upstat/bundlefuncs 其内部定义更新方法,而后调用前面的那个csp_functions脚本(其中的基本是更新中组件的共有方法)。

/usr/sbin/csp-instbundle
installs the bundle contents
usaage: csp-instbundle [path_to_bundle_1] [path_to_bundle_2] ...
if the bundle path is not specified, it scans the download directory

/usr/sbin/csp-unbundle
unbundles Content Support Pack bundle

/var/local/system/下面的fontBundle.checksum的内容:ce369e7dc775c5a71c4005ebce93adfa,暂时不知道作什么的。

查看脚本 csp_functions 找到安装包里面的字体解包方法 extract_bundle,如今在查找字体的解包脚本,在 /etc/upstat/bundlefuncs 中找到具体的解包方法。
继续查阅脚本,在bundlefuncs里面331行找到解包脚本,坑爹的解包方法。决定另辟它径,采用最麻烦的打包。(同时还在看LinkFont脚本)

12月1日:

找到字体镜像安装脚本 /usr/sbin/csp-instbundle 开始阅读:

19~29 行引入基本的组件功能,Unix小既是美的设计。(坑爹的代码查找)

24行 mount_directory 函数阅读,函数有2个参数,第一个是将要挂载的文件,后面一个是挂载的目标目录。

30~46行首先检测挂载的目标目录是否存在,若是存在的话,检测此文件夹是否被挂载。若是被挂载,强制进行卸载,卸载成功后,将 _mounted 变量设为0。

在卸载成功后48~72行进行挂载,50行调用csp_functions脚本里面的 ensure_directory 代码,经过3步判断,保证,最后执行的时候是一个同名文件夹。

56行调用 /usr/sbin/get_free_loop_device 脚原本查看是否还能挂载镜像,挂载地址0为用户文件,挂载地址1为waveform,也就是EInk显示屏文件,这一块有兴趣的本身看:
http://hi.baidu.com/black/item/c754a348fe0be50d6cc2f066

这是因为Linux下面挂载镜像的个数是有限的。我推测你们在切换官方更新的另外2种字体失败的缘由也就是没有空闲的loop device,而后字体镜像挂载失败的缘故。当达到最大挂载数时,按照 /etc/upstart/system.conf 里面的定义,会自动加一。

63行开始挂载,此函数基本结束。

80~100行为设置字体清单,首先按照题头的注释,意味将字体清单源文件夹 /usr/lib/font/manifests 的清单文件拷贝到工做时使用的清单文件夹 /var/local/font/manifests

85行获取文字镜像的名字不包括.font这个扩展名,86行将文字镜像名前加上manifest_,而后分别在 /var/local/font/manifests/usr/lib/font/manifests 上进行查找,直到找到同名文件,获取路径。

87~97行中,若是manifests的清单文件位于 /usr/lib/font/manifests 中的话,在签名核对正确的状况下,将清单文件拷贝至 /var/local/font/manifests 文件夹。

102~115行计算文字镜像的MD5值和Manifest里面的是否相同。

117~139行对字体文件夹进行检查,其中会检查cache这个字体缓存文件夹,还有字体镜像文件夹font

189~247行开始对字体进行挂载,首先经过manifest对字体镜像文件核对,而后添加至镜像列表目录。而后调用前面24行的方法将字体镜像列表中的字体镜像挂载至 /var/local/font/mnt/ 镜像名 _font 这样子格式的目录。

249~270行的代码为临时挂载。

278行正式脚本代码开始……

280~315,本人智商问题,看得只知其一;不知其二,能够理解为设备状态检测。只挂载模式调用前面的189行的挂载方法mount_only。

343~362行检测已经挂载的字体的字体镜像,若是镜像挂载,文件却没了,就会自动卸载镜像删除。这也是前面测试的时候删除ja.font文件后那个字体马上没有的缘由。

364~379行核对字体清单,在缺失字体镜像的状况下会自动删除清单。

目前进入死胡同。

12月2日:

手动打包后字体不显示,查看 /var/log/message 日志记录发现:csp-instbundle[3420]: Font manifest with name "zh-lth" exists, but the image is missing.查看对应脚本位置,寻求解决方法。发现本身打包的文件名写错了,坑爹啊 = =、修改文件名后从新挂载。

后面发现字体挂载后不显示,结果发现,坑爹的XML配置脚本写错了一个地方,坑爹的马大哈。修改从新打包,重启,出现正在安装字体的更新界面。可是依旧没出现字体选择菜单,查看字体conf脚本和实际的字体属性,发现问题,坑爹的方正兰亭黑,其粗体的属性居然有问题(不是一个字族的)。

很奇怪,明明应该有字体挂载成功了,结果字体选择菜单中没有,查看后发现最关键的问题了, /var/local/java/prefs/master.manifest 中须要配置字体选择目录。
日语字体的更新文件下载地址为:http://amzdigitaldownloads.edgesuite.net/eink/b07b507e8c6d1bc3ebb6ef0a11218410/ja.bin
中文字体的更新文件下载地址为:http://amzdigitaldownloads.edgesuite.net/eink/7c5fc7918b6bb5afcd916bf210c552c8/zh-Hans.bin

成功发现字体配置属性中的Indentify属性值的由来,开始修改master.manifest从新配置打包。系统重启中……失败,实在是无力了,决定挺而走险修改zh-Hans.font
修改失败,成功出现新增的字体选择菜单,可是字体切换后无效果。(坑爹的fc-cache)

查阅脚本,找到 /etc/fonts/conf.d/70-lab126-altfonts.conf 彷佛和当年的USE_ALT_FONT方法相似,查阅相关历史脚本中。
开始测试自定义字体方法,此文档注释详细说明了是用于自定义字体,可是此方法其实已经失效,在此再也不累述。

12月6日

在论坛dalvik的帮助下成功解包了font字体,发现了其实一切都是打包好的。因此判断出主要的问题在于脚本中manifest文件的安装上,其安装步骤中向系统进行注册。因此目前须要打包安装镜像自定义字体,目前研究解包打包中。

首先先解包原版更新镜像zh-Hans.bin文件,日志以下:

Bundle         SP01 (Signing Envelope)
Cert number    2
Cert file      pubprodkey02.pem (Official 2K)
Bundle         FL01 (Language [lang])
Bundle Type    OTA V2
Minimum OTA    1
Target OTA     2
Devices        1
Device         Kindle 1
Critical       0
Padding Byte   36 (0x24)
MD5 Hash       b67f4424bc5d8f38fb55696c57e1d0a5
Metadata       0
x update-zh-Hans_font.dat
x zh-Hans.font
x manifest

使用Kindletool打包时参照上面的参数写打包参数:kindletool create ota2 --device k1 --bundle FL01 --cert 2 zh-Tests.tar.gz update_a.bin
挂载Kindle,删除/mnt/us/system/font/zh-Hans.font

重启Kindle,已经没有了中文里面的另外2个字体。虽然文件校验显示打包后的字体和原版彻底不同,可是我依旧尝试安装,拷贝字体文件,强行重启,字体的安装主要是校验Cert Key文件,结果失败。因为使用指定的Cert key打包的文件没法解包,因而挂载UBSNET将Kindle下面的默认key文件拷贝出来做为参数,可是依旧没法打包,这致使全部的重打包字体若是想要安装成功就必需要越狱。

新的打包示例:kindletool create ota2 --device k1 --bundle FL01 --tgtrev 2 zh-Hans/zh-Hans.tar.gz update_zh-Hans.bin(后面测试成功)
拷贝过去重启后奇怪的是字体没有安装,更新文件也没有删除,莫非字体更新镜像须要系统手动下载更新?思考良久决定试试看,将字体文件上传至本身的服务器,而后修改master.manifest中字体更新文件地址。

可是修改后忘了去除w权限,下载地址还原,第二次修改后去除了w了权限,目前暂未发现字体下载地址被修改。成功联网下载了我从新打包的字体,系统重启安装更新中,卡在字体更新界面一会系统并未重启,字体安装成功(第一步解包打包成功,Yayness)。

第二步测试,核心的更新文件是3个:manifest、update-zh-Hans_font.dat、zh-Hans.font。能够解包转换的文件分别是:manifes、zh-Hans.font这两个文件,将解包转换后从新打包,此步骤尝试成功后便有了打包更新文件的可能。

12月7日(二度解包打包):

首先开始zh-Hans.font的还原:kindletool convert -w zh-Hans.bin(因为kindletool参数问题将font改成bin):

Bundle         SP01 (Signing Envelope)
Cert number    2
Cert file      pubprodkey02.pem (Official 2K)

解包出来的是zh-Hans.font,其属性为: Linux Compressed ROM File System data, little endian size 30789632 version #2 sorted_dirs CRC 0xfec5cf0b, edition 0, 11802 blocks, 9 files。文件指纹为:37824a7650fc8f1fd952413fc5fad029

从新混淆:kindletool create sig --bundle SP01 --unsigned --userdata --cert 0 zh-Hans.tgz data.stgz(无视最后的2个参数)

将混淆后的文件解包:`kindletool convert -w data.stgz

Bundle         SP01 (Signing Envelope)
Cert number    0
Cert file      pubdevkey01.pem (Developer)

解包后的data_unwrapped.tgz和以前的zh-Hans.font 彻底一致。

其次是manifest的还原:kindletool convert -w manifest.bin(坑爹的kindletool参数)

日志以下:

Bundle         SP01 (Signing Envelope)
Cert number    2
Cert file      pubprodkey02.pem (Official 2K)

按照解包日志写重打包参数:kindletool create sig --bundle SP01 --unsigned --userdata --cert 0 manifest.tgz data.stgz(坑爹的输入输出参数)

实验成功后我将zh-Hans.font用cramfsck解包,而后从新用mkcramfs打包。而后完整打包成一个镜像,这时候这个文字更新包彻底不一样了。修改好对应的坑爹的/usr/lib/font/manifest里面的脚本的Hash值。修改好更新脚本里面的更新Hash值,使用第一步的方法打包。依旧是和6号同样的更新方法上传,依旧是安装字体更新的界面,卡上1分钟后更新成功。

以上的步骤说明了自定义字体的可行性,下面将要作的就是在原字体包上的修改,添加新字体了。

从新打包字体文件:

添加了方正准雅宋字体,删除楷体的粗体版,修改image_manifestmanifest_zh-Hans文件,二者的却别在于后者多了一个zh-Hans.font的校验。
照着范例修改好字体的conf文件,字体的family属性使用TTFEdit查看编辑。USBNET链接Kindle,在指定位置拷贝字体,fc-cache.sh生成须要的字体缓存文件。

打包zh-Hans.font镜像,在字体的文件夹内执行mkcramfs . ../zh-Hans.tgz
混淆字体镜像,kindletool create sig --bundle SP01 --unsigned --userdata --cert 0 zh-Hans.tgz data.stgz。而后mv data.stgz zh-Hans.font

这样子,字体打包就OK了,打包好配置文件,而后压缩为tar.gz文件,打包为更新文件。
用自定义的manifest_zh-Hans脚本覆盖默认文件 /usr/lib/font/manifest/manifest_zh-Hans ,等待推送更新。
更新开始,缓慢地卡着字体安装界面,而后卡了字体框架,手动进入USBNET重启。

12月8号,单独的字体更新包测试:

还原原来的中文字体镜像,挂载USBNET后拷贝master.manifest编辑,而后开始按照上面的规则打包镜像,等待系统自动联网下载更新,发现更新推送周期好久,若是想要马上更新的方法就是删除已经存在的中文字体重启,而后重启后联网下看一看中文书,设置里面检查一下更新就开始推送字体了。

字体推送完毕,系统同时安装2个中文字体更新包(一个原版,一个个人修改版),卡了1分钟,自动重启。

字体未安装成功,后台显示依旧在下载字体,提示更新后系统未自动重启,字体选择框内有了后面添加的字体,可是前面添加的2个官方的圆体、楷体却没有了。

强制重启,依旧只有1个自定义准雅宋。没法单独的更新包打包么,发愁中……仔细查看master.manifest脚本,同时查看了启动日志和更新日志,发现问题。ContentPackages.preferences文件中,将zh-Zys当作locales,坑爹啊,知道问题了。从新编辑打包更新文件,修改了语言区域标识。

依旧更新安装失败,manifest没法在系统中注册。因为一个语言只能安装一个额外的文字更新包,因此很遗憾,我没法建立出单独的文字更新镜像。

这样子的结果很是糟糕,目前的自定义字体方法不适合绝大对数人,我已经将个人思路反馈给外国的大神,坐等他们的研究。
有技术,爱折腾的人能够等待我后面的字体重打包教程,打包添加本身的字体。固然我也会提供一份打包镜像给越狱事后的需求不是很高的用户,我会添加3~4个最受欢迎的字体在里面。

12月8日晚开始打包:
首选选择即将打包的字体,在官方的2个字体基础上增长了4个字体:信黑体、冬青黑体、方正准雅宋、方正准圆。

将字体拷贝进Kindle建立缓存的时候发现挂载的位置空间不够,决定建立符号链接解决。成功创建字体缓存,开始打包。

发现 /var/local/java/prefs/master.manifest 文件老是被系统自动还原,后面发现还原缘由是手动删除ContentPackages.preferences的缘由,这个时候系统会自动重置字体一块,可是离线删除后master.manifest却不会还原,会在联网后马上还原。

备注: ln -s /mnt/us/fonts/* /var/local/font/mnt/zh-Hans_font/fonts/ 字体缓存符号连接
挂载系统: mount -o rw,remount /
字体font镜像打包: mkcramfs . ../zh-Hans.font
字体font镜像混淆:

mv zh-Hans.font zh-Hans.tgz
    kindletool create sig --bundle SP01 --unsigned --userdata --cert 0 zh-Hans.tgz data.stgz
    mv data.stgz zh-Hans.font

manifest生成:

mv manifest_zh-Hans manifest.tgz
    kindletool create sig --bundle SP01 --unsigned --userdata --cert 0 manifest.tgz data.stgz
    mv data.stgz manifest
相关文章
相关标签/搜索