Skip to content
KitploitKITPLOIT
工具博客
提交
工具博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

··订阅源·联系·隐私·© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
z80-sans — 能够反汇编Z80指令的OpenType字体 | Kitploit
工具/GitHubGitHub/nevesnunes/z80-sans
逆向工程模糊测试CTF硬件安全二进制分析学习与教育
GitHubnevesnunes/z80-sans

z80-sans

能够反汇编Z80指令的OpenType字体

查看仓库
50631年前Kitploit 审核通过

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享

Z80 无衬线

你最喜欢的反汇编器是什么?我喜欢的是一个字体:

https://github.com/user-attachments/assets/bb6ceb18-c2fd-40a9-be4f-202321a214d9

这个字体通过大量使用 OpenType 的 字形替换表(GSUB) 和 字形定位表(GPOS),将十六进制小写字符序列转换为反汇编后的 Z80 指令。

如果你只是想试试,可以在 ./test/z80-sans.ttf 找到一份副本。

安装

在 Debian GNU/Linux 12 上测试通过。注意,该 Debian 版本自带 ruby 版本 3,而 fontcustom 是为 ruby 版本 2 编写的,与更高版本不兼容(例如语法错误)。ruby 安装还需要兼容的 OpenSSL 版本。因此,可以使用 RVM 来管理 ruby 和本地安装的 OpenSSL。

root@kitploit:~
apt install imagemagick potrace
pip install fonttools

git submodule update --init --recursive

# fontforge
(
cd ./modules/fontforge/
git checkout 4f4907d9541857b135bd0b361099e778325b4e28
git apply ../../resources/fontforge.diff
mkdir -p build
cd build
cmake -GNinja ..
ninja
ninja install
)

# woff2
(
cd ./modules/woff2/
make clean all
)

# fontcustom
rvm use 2.7
rvm pkg install openssl
rvm install 2.4 --with-openssl-dir=$HOME/.rvm/usr
gem update --system 3.3.22
(
export PATH=$PWD/modules/woff2/build:$PATH
cd ./modules/fontcustom/
git apply ../../resources/fontcustom.diff
gem build fontcustom.gemspec
gem install ./fontcustom-2.0.0.gem
)

运行

root@kitploit:~
cp ./resources/droid-sans-mono.ttf /tmp/base.ttf
./gen.py ./resources/instructions.json

生成的 .ttf 字体文件会复制到 ~/.local/share/fonts/,该目录被 LibreOffice 等软件使用。

设计

与其他“诅咒字体”相比,Z80 无衬线面临以下挑战:

  • 多字符渲染:逐个手动定义所有替换规则来渲染是不现实的,因此我们可以创建组合多个字面量的字形(例如 CALL 等助记符),但这又引出了下一点……
  • 多种组合:记住,某些 Z80 指令可以接受 16 位地址和寄存器作为操作数,这意味着一条指令最多有 65536 * 7 = 458752 种可能组合;
  • 操作数乱序:例如,寄存器和偏移量可以按一种顺序编码为十六进制字节,但反汇编时却按另一种顺序,这给回溯/向前查找规则带来了复杂性;
  • 小端地址:最低有效字节的字符需要先于最高有效字节渲染;
  • 有符号偏移:范围 0x80..0xff 内的所有偏移都需要渲染为负的补码数;

这一切都呼唤一种程序化解决方案。虽然 fontcustom 和 ImageMagick 负责生成字形,但编写查找规则的一种方便格式似乎是 .fea,不过我找不到将其与 fonttools 的 .ttx 格式(基本上是 xml)集成的方法。我采用了最低公分母的方法,直接编辑 Noto Sans Mono 的 .ttx(尽管字形形状是从 Droid Sans Mono 计算得出的,因为修补 FontForge 时我从它开始)。

使用递归下降解析器生成所有可能的字形,这有助于评估编码中的表达式(例如 SET b,(IX+o) 接受一个位和一个偏移量,编码为表达式 DD CB o C6+8*b)。然后将这些编码展开为操作数可能取的所有值,最后将 1 个或多个十六进制字节关联到每个扩展指令所需的反汇编字形。

关于 OpenType 特性有一些不错的参考资料,但它们通常写得比较高层,或是 .fea 格式:

  • OpenType Feature File Specification | afdko
  • GSUB — Glyph Substitution Table (OpenType 1.9.1) - Typography | Microsoft Learn
  • Fonts and Layout for Global Scripts
  • GitHub - brew/opentype-feature-intro: An introduction to OpenType features for type designers.
  • Features, part 3: advanced contextual alternates | Glyphs
  • Opentype subtitution many by many (different number) - Glyphs Forum

如何将它们转换为 .ttx 总是不太清楚,所以最后我直接转换了整个 Noto Sans 系列,并使用了老式的“通过例子学习”的暴力方法。这比听起来更有趣,因为从 .ttx 转换为 .ttf 时会有大量无声的失败,查找规则由于某些未被 fonttools 验证的假设(例如上下文链式替换的类定义必须至少有一个覆盖字形且 class 值为 "1")而无法匹配。

大多数挑战都是通过上下文链式规则解决的。为了处理地址,每个在 0..f 范围内的半字节都用不同的字形编码,并使用间距字符来逐字符创建多个替换。位移还有额外的有符号变体。这使数字的总字形数达到 (4 + 2) * 16 个。这样已经足够将字体文件保持在 65536 个字形的限制以下。

最糟糕的部分当然是操作数乱序。不过,由于它们在指令中的变体数量有限,可以通过与编码前缀模糊的指令相同的策略来处理,例如

root@kitploit:~
["SET b,(IX+o)", "DD CB o C6+8*b"],
["SET b,(IY+o)", "FD CB o C6+8*b"],

可以由与以下指令相同的查找规则覆盖:

root@kitploit:~
["SRA (IX+o)", "DD CB o 2E"],
["SRA (IY+o)", "FD CB o 2E"],
["SRL (IX+o)", "DD CB o 3E"],
["SRL (IY+o)", "FD CB o 3E"],

Z80 ISA 中一个有趣的特性是位和寄存器最多有 8 种变体,而这些乱序情况只涉及偏移量和这些特定操作数之一。因此,我们可以将位或寄存器编码为字面量。通过足够的向前查找,我们可以匹配到最后一个十六进制字节,并为每种情况创建专门的查找规则。最后的字面量可以通过生成一个匹配后缀字形的连字来减少。最终结果是为这些情况额外生成了几十个查找规则(可能可以分组以减少数量)。

已知问题

  • 尽管所有原始指令集都应该能反汇编,但某些指令存在小瑕疵:
    • LD (IX+o),r 渲染为 LD (IX+o r),;
    • SET b,(IX+o) 渲染为 SET b,(IX+o));
  • “CTF 质量”的代码 😅;

未来工作

FontForge 支持使用命令 GenerateFeatureFile() 和 MergeFeature() 以脚本方式修改特性(在 The Terrible Secret of OpenType Glyph Substitution - Ansuz - mskala's home page 中简要介绍)。在完成基于 .ttx 的实现后我才知道它,但它可能可以避免摆弄 .ttx 文件。

对于更复杂的指令集,另一种约束较少的方法是使用字体整形器。一些例子:

  • fuglede/llama.ttf: A font for writing tiny stories;
  • hsfzxjy/handwriter.ttf: Handwriting synthesis with Harfbuzz WASM.;

致谢

  • Droid Sans Mono 和 Noto Sans Mono 被用作 Z80 无衬线的基础;
  • ./resources/instructions.json 改编自 maziac/z80-instruction-set;
  • GSUB 替换的灵感来源:
    • Font with Built-In Syntax Highlighting;
    • Fontemon,特别是 "How I did it";
    • Addition Font;
    • Sans Bullshit Sans;

许可

  • Droid Sans Mono 采用 Apache 许可证;
  • Noto Sans Mono 采用 开放字体许可证;
  • ./resources/instructions.json 采用 GNU 较宽松通用公共许可证第3版;
  • 其他文件采用 MIT 许可证;
下载工具