<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Rebel Zhang 的博客</title>
        <link>https://rebel1725.codeberg.page/blog/zh/</link>
        <description>Recent content on Rebel Zhang 的博客</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>zh-CN</language>
        <managingEditor>rebel1725@tilde.club (Rebel Zhang)</managingEditor>
        <webMaster>rebel1725@tilde.club (Rebel Zhang)</webMaster>
        <lastBuildDate>Wed, 26 Aug 2026 18:54:57 +0800</lastBuildDate><atom:link href="https://rebel1725.codeberg.page/blog/zh/index.xml" rel="self" type="application/rss+xml" /><item>
            <title>关于我的常见问题</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/qas-about-myself/</link>
            <pubDate>Wed, 26 Aug 2026 18:54:57 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/qas-about-myself/</guid>
            <description>&lt;p&gt;这里是一系列关于我的常见问题。&lt;/p&gt;&#xA;&lt;h2 id=&#34;你是谁&#34;&gt;你是谁？&#xA;&lt;/h2&gt;&lt;p&gt;我是来自中国的自由软件倡导者和爱好者，同时也关注安全、隐私以及其他数字权利相关的问题。&lt;/p&gt;&#xA;&lt;h2 id=&#34;为什么叫-rebel&#34;&gt;为什么叫 Rebel？&#xA;&lt;/h2&gt;&lt;p&gt;作为一个人名，“Rebel”通常与独立、不墨守成规以及反抗精神等特质联系在一起。它象征着一个不害怕挑战社会规范或期望的人。&lt;/p&gt;&#xA;&lt;p&gt;我认为这个名字很适合我，因为我是一名坚定反对专有软件的自由软件倡导者。&lt;/p&gt;&#xA;&lt;h2 id=&#34;为什么是-rebel1725&#34;&gt;为什么是 &lt;code&gt;rebel1725&lt;/code&gt;？&#xA;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;rebel&lt;/code&gt; 的原因很明显；请参阅上一问。&lt;code&gt;1725&lt;/code&gt; 的原因是，&lt;code&gt;1725&lt;/code&gt; 就是 &lt;code&gt;1/7/25&lt;/code&gt;，也就是这个身份诞生的那一天。&lt;/p&gt;&#xA;&lt;h2 id=&#34;什么是你的个人品牌体系&#34;&gt;什么是你的个人品牌体系？&#xA;&lt;/h2&gt;&lt;p&gt;请参阅&lt;a class=&#34;link&#34; href=&#34;../my-personal-brand-system&#34; &gt;此页面&lt;/a&gt;。&lt;/p&gt;&#xA;&lt;h2 id=&#34;你是什么时候接触到这些自由软件相关的东西的&#34;&gt;你是什么时候接触到这些自由软件相关的东西的？&#xA;&lt;/h2&gt;&lt;p&gt;从 2022 年夏季开始，我受到 &lt;a class=&#34;link&#34; href=&#34;https://gnu.org/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;gnu.org&lt;/a&gt; 和 &lt;a class=&#34;link&#34; href=&#34;https://fsf.org/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;fsf.org&lt;/a&gt; 上的观点和论述的影响。2022 年 7 月 16 日，我从电脑上卸载了 Microsoft Windows，并开始逐一替换电脑和手机上的专有应用程序；到 2023 年 4 月底，我开始使用 LineageOS；2024 年 7 月，我更换了自己的身份，并在用户空间实现了 100% 自由软件。&lt;/p&gt;&#xA;&lt;h2 id=&#34;你如何看待专有软件&#34;&gt;你如何看待专有软件？&#xA;&lt;/h2&gt;&lt;p&gt;所有专有软件无一例外都是不道德且不公正的，它们践踏了计算机用户的四项基本软件自由以及人类道德的基本原则，因此不应存在。&lt;/p&gt;&#xA;&lt;p&gt;除了道德层面的问题之外，专有软件通常还是恶意软件和间谍软件，这也会带来隐私和安全方面的实际问题，因此应当避免使用。&lt;/p&gt;&#xA;&lt;h2 id=&#34;你如何看待自由和非自由文化作品例如音乐电影等&#34;&gt;你如何看待自由和非自由文化作品（例如音乐、电影等）？&#xA;&lt;/h2&gt;&lt;p&gt;我确实支持自由文化作品，并且经常把它们用作我的手机铃声、壁纸等。不过，与软件不同，我并不反对非自由文化作品，我也经常听 Alan Walker、Taylor Swift、Sia、TheFatRat 等人演唱的歌曲。那些将自己的作品奉献给自由文化社区的人确实值得尊敬，但（至少我认为）那些保留其作品全部权利的人也没有做错什么。&lt;/p&gt;&#xA;&lt;p&gt;然而，如果非自由文化作品被捆绑进软件中，我认为这是不可接受的，因为这会使软件变成专有软件。&lt;/p&gt;&#xA;&lt;h2 id=&#34;你的设备配置是什么&#34;&gt;你的设备配置是什么？&#xA;&lt;/h2&gt;&lt;p&gt;我有许多设备，并为每一台设备都取了名字。以下是截至 &lt;code&gt;2026-08-25&lt;/code&gt; 的部分设备详细信息：&lt;/p&gt;&#xA;&lt;table&gt;&#xA;&lt;tr&gt;&#xA;&lt;th&gt;名称&lt;/th&gt;&#xA;&lt;th&gt;型号&lt;/th&gt;&#xA;&lt;th&gt;操作系统&lt;/th&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;th&gt;Warden&lt;/th&gt;&#xA;&lt;th&gt;GL.iNet Flint 2&lt;/th&gt;&#xA;&lt;th&gt;OpenWrt&lt;/th&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;th&gt;Alaric&lt;/th&gt;&#xA;&lt;th&gt;Lenovo ThinkPad X200&lt;/th&gt;&#xA;&lt;th&gt;Trisquel GNU/Linux&lt;/th&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;th&gt;Bryna&lt;/th&gt;&#xA;&lt;th&gt;Xiaomi Redmi G Pro 2024&lt;/th&gt;&#xA;&lt;th&gt;Qubes OS&lt;/th&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;th&gt;Ami&lt;/th&gt;&#xA;&lt;th&gt;HP EliteBook 820 G2&lt;/th&gt;&#xA;&lt;th&gt;Qubes OS&lt;/th&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;th&gt;Leo&lt;/th&gt;&#xA;&lt;th&gt;OnePlus 11&lt;/th&gt;&#xA;&lt;th&gt;LineageOS&lt;/th&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;th&gt;William&lt;/th&gt;&#xA;&lt;th&gt;Google Pixel 6&lt;/th&gt;&#xA;&lt;th&gt;GrapheneOS&lt;/th&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;th&gt;Gemini&lt;/th&gt;&#xA;&lt;th&gt;TicWatch Pro 2018&lt;/th&gt;&#xA;&lt;th&gt;AsteroidOS&lt;/th&gt;&#xA;&lt;/tr&gt;&#xA;&lt;/table&gt;&#xA;&lt;h2 id=&#34;你每天使用什么软件&#34;&gt;你每天使用什么软件？&#xA;&lt;/h2&gt;&lt;p&gt;下面是不完整的日常软件列表：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;浏览器：&lt;a class=&#34;link&#34; href=&#34;https://librewolf.net&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;LibreWolf&lt;/a&gt;、&lt;a class=&#34;link&#34; href=&#34;https://torproject.org/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Tor Browser&lt;/a&gt;、&lt;a class=&#34;link&#34; href=&#34;https://f-droid.org/en/packages/org.mozilla.fennec_fdroid&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Fennec F-Droid&lt;/a&gt;；&lt;/li&gt;&#xA;&lt;li&gt;办公：&lt;a class=&#34;link&#34; href=&#34;https://libreoffice.org/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;LibreOffice&lt;/a&gt;、&lt;a class=&#34;link&#34; href=&#34;https://okular.kde.org/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Okular&lt;/a&gt;、&lt;a class=&#34;link&#34; href=&#34;https://mupdf.com/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;MuPDF&lt;/a&gt;；&lt;/li&gt;&#xA;&lt;li&gt;开发：&lt;a class=&#34;link&#34; href=&#34;https://www.gnu.org/software/emacs/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;GNU Emacs&lt;/a&gt;、&lt;a class=&#34;link&#34; href=&#34;https://kate-editor.org&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Kate&lt;/a&gt;、&lt;a class=&#34;link&#34; href=&#34;https://www.geany.org/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Geany&lt;/a&gt;；&lt;/li&gt;&#xA;&lt;li&gt;邮件：&lt;a class=&#34;link&#34; href=&#34;https://thunderbird.net/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Thunderbird&lt;/a&gt;；&lt;/li&gt;&#xA;&lt;li&gt;图形：&lt;a class=&#34;link&#34; href=&#34;https://gimp.org&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;GIMP&lt;/a&gt;、&lt;a class=&#34;link&#34; href=&#34;https://krita.org/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Krita&lt;/a&gt;；&lt;/li&gt;&#xA;&lt;li&gt;多媒体：&lt;a class=&#34;link&#34; href=&#34;https://videolan.org/vlc/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;VLC&lt;/a&gt;、&lt;a class=&#34;link&#34; href=&#34;https://wiki.gnome.org/Apps/Rhythmbox&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Rhythmbox&lt;/a&gt;、&lt;a class=&#34;link&#34; href=&#34;https://kdenlive.org/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Kdenlive&lt;/a&gt;、&lt;a class=&#34;link&#34; href=&#34;https://www.audacityteam.org&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Audacity&lt;/a&gt;、&lt;a class=&#34;link&#34; href=&#34;https://boomingmusic.org/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Booming Music&lt;/a&gt;；&lt;/li&gt;&#xA;&lt;li&gt;安全：&lt;a class=&#34;link&#34; href=&#34;https://keepassxc.org/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;KeePassXC&lt;/a&gt;、&lt;a class=&#34;link&#34; href=&#34;https://apps.kde.org/en-gb/kleopatra/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Kleopatra&lt;/a&gt;、&lt;a class=&#34;link&#34; href=&#34;https://www.openkeychain.org/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;OpenKeychain&lt;/a&gt;。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h2 id=&#34;你目前的软件自由状态如何&#34;&gt;你目前的软件自由状态如何？&#xA;&lt;/h2&gt;&lt;p&gt;现在，我在所有日常使用的设备上，都不会在用户空间使用任何专有软件。Alaric 和 Ami 都配备了 Libreboot，而 Bryna 仍然运行非自由的 UEFI，但至少它的硬盘中除了固件和微码之外，不再有其他非自由二进制文件。我的手机都运行 LineageOS、GrapheneOS 或 postmarketOS 之类的自由软件操作系统；在 Android 系统上，我只使用预装应用或来自 F-Droid 的应用；在 postmarketOS 上，我只使用官方软件仓库中的应用，或者我自己构建的应用。&lt;/p&gt;&#xA;&lt;h2 id=&#34;那么你的技术栈呢&#34;&gt;那么你的技术栈呢？&#xA;&lt;/h2&gt;&lt;p&gt;我的编程能力非常基础，而且目前仍然可以算是比较差。截至 2026 年 8 月 25 日，我掌握了 C/C++、Python、Shell 等的基础知识。我能够在一定程度上使用 C++ 和 Qt Widgets 开发一些应用，最近也一直在学习 Qt Quick。我也曾尝试学习 Rust，但目前已经暂时放弃。&lt;/p&gt;&#xA;&lt;p&gt;我重点学习逆向工程，为此学习了 AArch64 汇编和 x86_64 汇编。不过，我目前的 RE 技能仍然只限于简单的 crackme。但我正在努力学习更多内容，我的目标是制作一个 postmarketOS 移植版本。&lt;/p&gt;&#xA;&lt;h2 id=&#34;你主要使用哪些通信工具&#34;&gt;你主要使用哪些通信工具？&#xA;&lt;/h2&gt;&lt;p&gt;我主要使用 XMPP 与朋友和熟人交流，使用 Matrix 参与全球社区，使用 SimpleX 面向注重匿名性的用户（主要来自 I2P）。&lt;/p&gt;&#xA;&lt;p&gt;总体而言，我使用最多的通信工具是 XMPP。&lt;/p&gt;&#xA;&lt;h2 id=&#34;privateexpress和public是什么意思&#34;&gt;“Private”、“Express”和“Public”是什么意思？&#xA;&lt;/h2&gt;&lt;p&gt;这是我的即时通讯账号的三个隐私等级：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&lt;strong&gt;Private&lt;/strong&gt;：这些账号用于私聊。你可以通过这些账号和我谈论几乎任何事情；但是，&lt;strong&gt;你不应期待快速回复，因为我只有在家时才能访问这些账号&lt;/strong&gt;。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Express&lt;/strong&gt;：这些账号同样用于私聊，并且可以在我带出门的设备上访问。不过，&lt;strong&gt;由于公共场所普遍存在监控，而且我的设备因为引导加载程序处于解锁状态而安全性降低，请在聊天时避免讨论敏感信息&lt;/strong&gt;。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Public&lt;/strong&gt;：这些账号仅用于公开聊天，以及有时使用未加密的私聊。&lt;strong&gt;聊天时请避免讨论敏感信息&lt;/strong&gt;。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h2 id=&#34;你是如何上网的&#34;&gt;你是如何上网的？&#xA;&lt;/h2&gt;&lt;p&gt;我 24/7 使用 Tor。在电脑上，我使用 Tor 守护进程；在手机上，我使用 &lt;a class=&#34;link&#34; href=&#34;https://invizible.net/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;InviZible Pro&lt;/a&gt;。&lt;/p&gt;&#xA;&lt;p&gt;有时，当我的 Tor 守护进程遇到问题时，我会使用 I2P 内的出口代理（outproxy）来访问互联网。&lt;/p&gt;&#xA;&lt;h2 id=&#34;如何访问你的复古风格网站&#34;&gt;如何访问你的复古风格网站？&#xA;&lt;/h2&gt;&lt;p&gt;我有两个版本的复古风格网站。一个是普通的 HTTP/HTTPS 网站，另一个是 Gemini capsule（Gemsite）。它们是两个不同的网站。如果我没有特别说明而说“我的复古风格网站”，默认指的是 HTTP/HTTPS 版本。&lt;/p&gt;&#xA;&lt;p&gt;我会把我的复古风格网站（HTTP/HTTPS 和 Gemini）托管在我加入的所有 &lt;a class=&#34;link&#34; href=&#34;https://tildeverse.org/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Tilde 社区&lt;/a&gt;的服务器上，理论上你可以从其中任何一个服务器访问它们。不过，由于这些社区大多是爱好者建立的，因此会有停机时间。因此，我推荐访问托管在 Tilde.club 上的网站（&lt;a class=&#34;link&#34; href=&#34;https://tilde.club/~rebel1725/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;HTTPS&lt;/a&gt;、&lt;a class=&#34;link&#34; href=&#34;gemini://tilde.club/~rebel1725/&#34; &gt;Gemini&lt;/a&gt;），因为它最稳定，而且我对它投入的关注最多，我也会尽量确保其中的信息保持最新。其他 Tilde pubnix 上的内容理论上与 Tilde.club 上的内容相同，但不保证及时更新。&lt;/p&gt;&#xA;&lt;p&gt;此外，这个复古风格网站（HTTP 版本）也作为 eepsite 托管在 I2P 网络上。它由 &lt;a class=&#34;link&#34; href=&#34;https://catto.garden/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Catto Garden&lt;/a&gt; 用心托管，可通过 &lt;a class=&#34;link&#34; href=&#34;http://rebel1725.i2p/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;rebel1725.i2p&lt;/a&gt; 访问（&lt;a class=&#34;link&#34; href=&#34;http://rebel1725.i2p/?i2paddresshelper=1kdplDVNAwhrt4E45sZsDx0sKV~o9aZB1DzR8toXulbWR2mUNU0DCGu3gTjmxmwPHSwpX-j1pkHUPNHy2he6VtZHaZQ1TQMIa7eBOObGbA8dLClf6PWmQdQ80fLaF7pW1kdplDVNAwhrt4E45sZsDx0sKV~o9aZB1DzR8toXulbWR2mUNU0DCGu3gTjmxmwPHSwpX-j1pkHUPNHy2he6VtZHaZQ1TQMIa7eBOObGbA8dLClf6PWmQdQ80fLaF7pW1kdplDVNAwhrt4E45sZsDx0sKV~o9aZB1DzR8toXulbWR2mUNU0DCGu3gTjmxmwPHSwpX-j1pkHUPNHy2he6VjzyoitYZ7hTUo7Zgt6dU1gjXscLqE0P7BjDCqnQU3LyBQAEAAcAAA==&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Address Helper&lt;/a&gt;)。过去并不推荐通过这种方式访问网站，因为在没有配置出口代理的情况下，明网资源会无法加载；不过现在已经不是这样了，因为我改变了图片和其他资源的托管方式。&lt;/p&gt;&#xA;&lt;h2 id=&#34;如何访问你的现代风格网站&#34;&gt;如何访问你的现代风格网站？&#xA;&lt;/h2&gt;&lt;p&gt;点击&lt;a class=&#34;link&#34; href=&#34;https://rebel1725.codeberg.page/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;这里&lt;/a&gt;。&lt;/p&gt;&#xA;&lt;h2 id=&#34;你玩游戏吗&#34;&gt;你玩游戏吗？&#xA;&lt;/h2&gt;&lt;p&gt;过去，我会玩 &lt;a class=&#34;link&#34; href=&#34;https://supertuxkart.net/Main_Page&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;SuperTuxKart&lt;/a&gt; 和其他自由游戏。不过现在我很少玩游戏，因为 Qubes OS 让游戏体验变得很脆弱。而且，我一直反对专有游戏和 &lt;a class=&#34;link&#34; href=&#34;https://defectivebydesign.org/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Digital Restrictions Management&lt;/a&gt;。&lt;/p&gt;&#xA;&lt;h2 id=&#34;你如何听音乐&#34;&gt;你如何听音乐？&#xA;&lt;/h2&gt;&lt;p&gt;我会从各种来源下载音乐，主要是 YouTube，而 &lt;a class=&#34;link&#34; href=&#34;https://github.com/yt-dlp/yt-dlp&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;yt-dlp&lt;/a&gt; 对此非常有帮助。如果我想支持艺术家，我会购买 CD。&lt;/p&gt;&#xA;&lt;p&gt;我会把收听记录同步到 ListenBrainz，并从该平台获得个性化推荐。我的 ListenBrainz 个人资料在&lt;a class=&#34;link&#34; href=&#34;https://listenbrainz.org/user/rebel1725/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;这里&lt;/a&gt;。&lt;/p&gt;&#xA;&lt;h2 id=&#34;为什么你不为自己的-openpgp-密钥或者至少其中一个子密钥使用抗量子算法&#34;&gt;为什么你不为自己的 OpenPGP 密钥（或者至少其中一个子密钥）使用抗量子算法？&#xA;&lt;/h2&gt;&lt;p&gt;我想这么做，但我的硬件令牌不支持这类算法。&lt;/p&gt;&#xA;&lt;h2 id=&#34;你的政治观点是什么&#34;&gt;你的政治观点是什么？&#xA;&lt;/h2&gt;&lt;p&gt;我的政治观点可以概括如下：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;自由很重要，包括但不限于软件、文化、言论、集会、结社、新闻出版等方面。软件自由尤其重要，任何限制这种自由的技术，包括但不限于数字限制管理、SaaSS 等，都不应存在。&lt;/li&gt;&#xA;&lt;li&gt;我反对资本主义、帝国主义、种族主义、法西斯主义、纳粹主义、军国主义、威权主义、极权主义、独裁、审查、酷刑、仇外主义、战争，以及基于任何特征的歧视，包括但不限于国籍、宗教、残疾、年龄、阶级、性取向、性别/性别认同等。&lt;/li&gt;&#xA;&lt;li&gt;隐私是基本人权之一，大规模监控应当被废除。&lt;/li&gt;&#xA;&lt;li&gt;地球只有一个，人类应当努力保护我们唯一的家园。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h2 id=&#34;为什么你使用英式英语而不是美式英语&#34;&gt;为什么你使用英式英语而不是美式英语？&#xA;&lt;/h2&gt;&lt;p&gt;因为我不喜欢美国，因为其政府利用 PRISM 在全球范围内对计算机用户进行大规模监控。此外，大多数专有软件都在美国开发。&lt;/p&gt;&#xA;&lt;h2 id=&#34;你认为自己外向且随和吗&#34;&gt;你认为自己外向且随和吗？&#xA;&lt;/h2&gt;&lt;p&gt;这取决于情况。&lt;/p&gt;&#xA;&lt;p&gt;如果你是自由软件倡导者、自由软件爱好者或 GNU/Linux 爱好者，你可能确实会觉得我是一个外向而随和的人。如果你是陌生人，你可能会觉得我有点社交被动或内向。但如果你支持专有软件，我觉得你应该滚蛋。&lt;/p&gt;&#xA;&lt;p&gt;我对亲密朋友设定了非常高的标准，但一旦你达到这些标准，我就会全心全意地投入我们的友谊。&lt;/p&gt;&#xA;&lt;h2 id=&#34;你如何看待爱情&#34;&gt;你如何看待爱情？&#xA;&lt;/h2&gt;&lt;p&gt;在我看来，爱情与友谊并没有太大区别，但它天然包含更高的期待。真正的爱情应当建立在共同的理想和共同的信念之上；对我而言，这意味着对自由软件的共同承诺。&lt;/p&gt;&#xA;&lt;p&gt;我的理想伴侣应该是一名自由软件倡导者，最好会说中文。我还&lt;a class=&#34;link&#34; href=&#34;../%e8%87%b4-2026-%e5%b9%b4%e7%9a%84%e5%a5%b9/&#34; &gt;写过一首诗&lt;/a&gt;，用来描绘我理想中的爱情。&lt;/p&gt;&#xA;&lt;h2 id=&#34;你的-mbti-是什么&#34;&gt;你的 MBTI 是什么？&#xA;&lt;/h2&gt;&lt;p&gt;我是 ESTJ。&lt;/p&gt;&#xA;&lt;h2 id=&#34;你的性别认同和性取向是什么&#34;&gt;你的性别认同和性取向是什么？&#xA;&lt;/h2&gt;&lt;p&gt;我的代词是 he/him，我是异性恋。&lt;/p&gt;&#xA;&lt;p&gt;想进一步了解这件事，请阅读&lt;a class=&#34;link&#34; href=&#34;../exploration-of-my-sexual-and-romantic-attraction/&#34; &gt;这篇文章&lt;/a&gt;。&lt;/p&gt;&#xA;&lt;h2 id=&#34;你如何看待-lgbtq&#34;&gt;你如何看待 LGBTQ+？&#xA;&lt;/h2&gt;&lt;p&gt;我本人并不属于 LGBTQ+，但我努力变得更加尊重他人并且更加包容。&lt;/p&gt;&#xA;&lt;h2 id=&#34;你的时区是什么&#34;&gt;你的时区是什么？&#xA;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;Asia/Shanghai&lt;/code&gt;，即 UTC+08:00，且不实行夏令时。&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>使用 GammaRay 在 QtWidgets 应用程序中找到某个功能的实现</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/find-the-implementation-of-a-function-in-a-qtwidgets-application-using-gammaray/</link>
            <pubDate>Sun, 09 Aug 2026 20:49:33 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/find-the-implementation-of-a-function-in-a-qtwidgets-application-using-gammaray/</guid>
            <description>&lt;p&gt;为了实践自由软件的自由 1 和自由 3，和/或为自由软件社区做出贡献，我们需要修改与某个功能相关的源代码，让软件做出不同的事情。然而，由于我们对某个项目并不熟悉，我们常常不知道需要修改的源代码在哪里。你可以试着运行 &lt;code&gt;grep -R &amp;lt;some-user-facing-string&amp;gt; .&lt;/code&gt;，不过有时这并不会奏效（见&lt;a class=&#34;link&#34; href=&#34;../the-very-beginning-of-my-journey-contributing-to-the-free-software-community-existing-projects&#34; &gt;上一篇文章&lt;/a&gt;）。在那种情况下，我们就需要一些高级的软件内省工具。对于使用 Qt 开发的软件，一个强大的工具是 &lt;a class=&#34;link&#34; href=&#34;https://www.kdab.com/software-technologies/developer-tools/gammaray/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;GammaRay&lt;/a&gt;。&lt;/p&gt;&#xA;&lt;p&gt;要使用 GammaRay，你首先需要安装它。如果你想检查从发行版官方软件仓库安装的软件，那么也请从那里安装 GammaRay：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;# apt install gammaray&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;如果你使用 &lt;code&gt;kde-builder&lt;/code&gt; 开发 KDE 应用程序，请将以下几行添加到你的 &lt;code&gt;~/.config/kde-builder.yaml&lt;/code&gt;：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;project gammaray:&#xA;  repository: https://github.com/KDAB/GammaRay.git&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;然后把它构建到你的工作目录中：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ kde-builder gammaray&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;要使用 GammaRay，你需要先让你想检查的应用程序运行起来。然后启动 GammaRay，并在列表中选择你的应用程序。&lt;/p&gt;&#xA;&lt;p&gt;我们以在 Gwenview 中查找幻灯片逻辑为例。打开 Gwenview，然后打开一张图片，你会在菜单中看到 &lt;code&gt;Start Slideshow&lt;/code&gt; 选项：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;a screenshot of Gwenview&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;390px&#34; data-flex-grow=&#34;162&#34; height=&#34;952&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://rebel1725.codeberg.page/images/pic_20260809_001.png&#34; srcset=&#34;https://rebel1725.codeberg.page/blog/pic_20260809_001_9260183633641420788_hu_365916c355e33157.png 800w, https://rebel1725.codeberg.page/images/pic_20260809_001.png 1548w&#34; width=&#34;1548&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;逐个浏览 Widgets 列表后，你会发现 &lt;code&gt;0x13bda470&lt;/code&gt; 就是我们想要检查的菜单，其中包含 &lt;code&gt;Start Slideshow&lt;/code&gt; 选项：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;GammaRay QtWidgets introspection&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;402px&#34; data-flex-grow=&#34;167&#34; height=&#34;1002&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://rebel1725.codeberg.page/images/pic_20260809_002.png&#34; srcset=&#34;https://rebel1725.codeberg.page/blog/pic_20260809_002_4293608996693979957_hu_43bd5ee0e43f111b.png 800w, https://rebel1725.codeberg.page/blog/pic_20260809_002_4293608996693979957_hu_c573a96130bd048e.png 1600w, https://rebel1725.codeberg.page/images/pic_20260809_002.png 1681w&#34; width=&#34;1681&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;而且我们会在 Connections 标签页中看到一个 &lt;code&gt;toggle_slideshow&lt;/code&gt; QAction：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;Connections&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;304px&#34; data-flex-grow=&#34;126&#34; height=&#34;604&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://rebel1725.codeberg.page/images/pic_20260809_003.png&#34; width=&#34;767&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;grep&lt;/code&gt; 会告诉我们这样的 QAction 位于哪里：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;~/kde/src/gwenview$ grep -R toggle_slideshow&#xA;app/fullscreencontent.cpp:    addAction(QStringLiteral(&amp;#34;toggle_slideshow&amp;#34;));&#xA;app/gwenviewui.rc:        &amp;lt;Action name=&amp;#34;toggle_slideshow&amp;#34; /&amp;gt;&#xA;app/mainwindow.cpp:        mToggleSlideShowAction = view-&amp;gt;addAction(QStringLiteral(&amp;#34;toggle_slideshow&amp;#34;), q, &amp;amp;MainWindow::toggleSlideShow);&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;在你常用的 IDE 中打开该项目，例如 Qt Creator，然后在 &lt;code&gt;app/mainwindow.cpp&lt;/code&gt; 中搜索这个字符串。我们会在这里找到 &lt;code&gt;toggle_slideshow&lt;/code&gt;：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;        mToggleSlideShowAction = view-&amp;gt;addAction(QStringLiteral(&amp;#34;toggle_slideshow&amp;#34;), q, &amp;amp;MainWindow::toggleSlideShow);&#xA;        q-&amp;gt;updateSlideShowAction();&#xA;        connect(mSlideShow, &amp;amp;SlideShow::stateChanged, q, &amp;amp;MainWindow::updateSlideShowAction);&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;现在再搜索 &lt;code&gt;toggleSlideShow&lt;/code&gt;，它会带我们找到这个函数：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;void MainWindow::toggleSlideShow()&#xA;{&#xA;    if (d-&amp;gt;mSlideShow-&amp;gt;isRunning()) {&#xA;        d-&amp;gt;mSlideShow-&amp;gt;pause();&#xA;    } else {&#xA;        if (!d-&amp;gt;mViewAction-&amp;gt;isChecked()) {&#xA;            d-&amp;gt;mViewAction-&amp;gt;trigger();&#xA;        }&#xA;        if (!d-&amp;gt;mFullScreenAction-&amp;gt;isChecked()) {&#xA;            d-&amp;gt;mFullScreenAction-&amp;gt;trigger();&#xA;        }&#xA;        QList&amp;lt;QUrl&amp;gt; list;&#xA;        for (int pos = 0; pos &amp;lt; d-&amp;gt;mDirModel-&amp;gt;rowCount(); ++pos) {&#xA;            QModelIndex index = d-&amp;gt;mDirModel-&amp;gt;index(pos, 0);&#xA;            KFileItem item = d-&amp;gt;mDirModel-&amp;gt;itemForIndex(index);&#xA;            MimeTypeUtils::Kind kind = MimeTypeUtils::fileItemKind(item);&#xA;            switch (kind) {&#xA;            case MimeTypeUtils::KIND_SVG_IMAGE:&#xA;            case MimeTypeUtils::KIND_RASTER_IMAGE:&#xA;            case MimeTypeUtils::KIND_VIDEO:&#xA;                list &amp;lt;&amp;lt; item.url();&#xA;                break;&#xA;            default:&#xA;                break;&#xA;            }&#xA;        }&#xA;        d-&amp;gt;mSlideShow-&amp;gt;start(list);&#xA;    }&#xA;    updateSlideShowAction();&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;继续搜索 &lt;code&gt;mSlideShow&lt;/code&gt;，你会找到这里：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;struct MainWindow::Private {&#xA;    ...&#xA;    SlideShow *mSlideShow = nullptr;&#xA;    ...&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;现在我们知道 &lt;code&gt;d-&amp;gt;mSlideShow&lt;/code&gt; 的类型是 &lt;code&gt;SlideShow *&lt;/code&gt;。把鼠标悬停在 &lt;code&gt;SlideShow&lt;/code&gt; 这个字符串上，会告诉我们它的类型来自 &lt;code&gt;lib/slideshow.h&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;Qt Creator&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;271px&#34; data-flex-grow=&#34;112&#34; height=&#34;363&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://rebel1725.codeberg.page/images/pic_20260809_004.png&#34; width=&#34;410&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;现在打开 &lt;code&gt;lib/slideshow.cpp&lt;/code&gt; 和 &lt;code&gt;lib/slideshow.h&lt;/code&gt;，你就可以继续往下找了。&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>我为自由软件社区贡献的最初几步（现有项目）</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/the-very-beginning-of-my-journey-contributing-to-the-free-software-community-existing-projects/</link>
            <pubDate>Sun, 02 Aug 2026 23:18:30 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/the-very-beginning-of-my-journey-contributing-to-the-free-software-community-existing-projects/</guid>
            <description>&lt;p&gt;近些天来，我对自由软件社区的贡献远远少于我从中受益的程度，而我所做出的贡献也仅限于&lt;a class=&#34;link&#34; href=&#34;https://codeberg.org/rebel1725/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;一些小而简单的个人项目&lt;/a&gt;以及非代码类贡献（例如一些翻译、向 &lt;a class=&#34;link&#34; href=&#34;https://screenshots.debian.net/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Debian Screenshots&lt;/a&gt; 上传几张截图，以及为 &lt;a class=&#34;link&#34; href=&#34;https://freeswzhcn.codeberg.page/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Free Software Chinese Site&lt;/a&gt; 撰写文章）。在过去的一年里，我学习了 C/C++、Qt、汇编，以及一些 Rust。我认为，现在是时候为自由软件社区和自由软件运动做一些有意义的事情了。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;免责声明：这不是一篇指南！我撰写这篇文章，只是为了分享我自己的经历。请参考相关文档，并向专家请教，以进一步了解如何为自由软件社区做出贡献。&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;我为什么选择-kde&#34;&gt;我为什么选择 KDE&#xA;&lt;/h2&gt;&lt;p&gt;最初，我曾考虑为 postmarketOS 贡献。不过，我觉得自己的技能距离所需水平还差得很远，于是决定先从相对简单的事情开始。由于我对 C++ 和 Qt 更熟悉，所以我选择 KDE 作为我对社区的第一次贡献。&lt;/p&gt;&#xA;&lt;h2 id=&#34;感受&#34;&gt;感受&#xA;&lt;/h2&gt;&lt;p&gt;我阅读源代码的能力并不强。大约在 2025 年初，我尝试阅读 &lt;a class=&#34;link&#34; href=&#34;https://github.com/pdfarranger/pdfarranger&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;PDF Arranger&lt;/a&gt; 的源代码，当时我感到非常难受，也有些不知所措。&lt;/p&gt;&#xA;&lt;p&gt;不过，得益于&lt;a class=&#34;link&#34; href=&#34;../a-brief-introduction-into-reverse-engineering&#34; &gt;学习逆向工程&lt;/a&gt;的经历，而这恰好需要阅读汇编代码，我阅读高级语言源代码的能力也有所提升。因此，我认为自己应该尝试一次真正的自由软件贡献，在真实环境中练习自己的技能。&lt;/p&gt;&#xA;&lt;p&gt;在打开源码树之前，我有些紧张，担心自己会像读 PDF Arranger 的源代码时那样，被庞大的代码淹没。多亏了朋友 &lt;a class=&#34;link&#34; href=&#34;https://blog.i7arch.com/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Integral&lt;/a&gt; 的鼓励，我才鼓起勇气迈出那一步。&lt;/p&gt;&#xA;&lt;h2 id=&#34;工具&#34;&gt;工具&#xA;&lt;/h2&gt;&lt;p&gt;&lt;a class=&#34;link&#34; href=&#34;https://develop.kde.org/docs/getting-started/building/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;KDE 推荐的开发环境之一&lt;/a&gt;是最新版的 Fedora KDE。由于我使用的是 Qubes OS，所以我可以很方便地快速搭建一个独立的 HVM，并在其中完成所有工作。&lt;/p&gt;&#xA;&lt;p&gt;随后，我按照 &lt;a class=&#34;link&#34; href=&#34;https://develop.kde.org/docs/getting-started/building/kde-builder-setup/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;KDE 开发者的官方文档&lt;/a&gt; 配置了 &lt;code&gt;kde-builder&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;h2 id=&#34;工作过程&#34;&gt;工作过程&#xA;&lt;/h2&gt;&lt;p&gt;我浏览了 &lt;a class=&#34;link&#34; href=&#34;https://bugs.kde.org/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;KDE 官方 Bugzilla&lt;/a&gt; 上托管的&lt;a class=&#34;link&#34; href=&#34;https://bugs.kde.org/buglist.cgi?chfield=%5BBug%20creation%5D&amp;amp;chfieldfrom=7d&amp;amp;f1=product&amp;amp;o1=notequals&amp;amp;v1=Spam&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;漏洞列表&lt;/a&gt;。我注意到&lt;a class=&#34;link&#34; href=&#34;https://bugs.kde.org/show_bug.cgi?id=523617&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;一个看起来非常容易修复的漏洞&lt;/a&gt;，但在拉取源代码并构建二进制文件之后，我发现这个漏洞在我当前环境下，使用最新版本的 Ark 无法复现。&lt;/p&gt;&#xA;&lt;p&gt;随后我又回到漏洞列表，发现了&lt;a class=&#34;link&#34; href=&#34;https://bugs.kde.org/show_bug.cgi?id=523757&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;另一个看起来很简单的漏洞&lt;/a&gt;。该漏洞报告中的系统环境和软件版本与我的相同（Fedora KDE，26.04），而且在 Fedora 官方仓库提供的应用程序中可以复现。确认这一点之后，我拉取了源代码并进行了构建。&lt;/p&gt;&#xA;&lt;p&gt;我在二进制文件 &lt;code&gt;~/kde/build/konsole/bin/konsole&lt;/code&gt; 上启动了 GDB。把漏洞报告中提到的字符串（&lt;code&gt;calt,liga,ss03, ss07,ss09&lt;/code&gt;）粘贴到输入框后，我在终端里看到了如下输出：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;The tag name must be exactly 4 characters long!&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;在与一个 LLM 进行了几轮交流之后，我找到了一种用 GDB Python 脚本定位源码中打印这条提示的代码行的方法：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;python&#xA;import gdb&#xA;&#xA;TARGET = b&amp;#34;The tag name must be exactly 4 characters long!&amp;#34;&#xA;&#xA;class FilteredWrite(gdb.Breakpoint):&#xA;    def stop(self):&#xA;        fd = int(gdb.parse_and_eval(&amp;#34;$rdi&amp;#34;))&#xA;        if fd not in (1, 2):&#xA;            return False&#xA;&#xA;        buf = int(gdb.parse_and_eval(&amp;#34;$rsi&amp;#34;))&#xA;        count = int(gdb.parse_and_eval(&amp;#34;$rdx&amp;#34;))&#xA;&#xA;        try:&#xA;            data = gdb.selected_inferior().read_memory(buf, count).tobytes()&#xA;        except gdb.MemoryError:&#xA;            return False&#xA;&#xA;        if TARGET in data:&#xA;            gdb.write(&amp;#34;\n=== matched output ===\n&amp;#34;)&#xA;            gdb.write(data.decode(&amp;#34;utf-8&amp;#34;, &amp;#34;replace&amp;#34;) + &amp;#34;\n&amp;#34;)&#xA;            gdb.execute(&amp;#34;bt full&amp;#34;)&#xA;            return True&#xA;&#xA;        return False&#xA;&#xA;FilteredWrite(&amp;#34;write&amp;#34;)&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;在一次 GDB 调试会话之后，我确认了这条警告是由 &lt;code&gt;kwidgetsaddons&lt;/code&gt; 中的 &lt;code&gt;kfontchooser.cpp&lt;/code&gt; 文件触发的。我还找到了触发这条警告的函数：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;void KFontChooserPrivate::slotFeaturesChanged(const QString &amp;amp;features)&#xA;{&#xA;    m_selectedFont.clearFeatures();&#xA;&#xA;    if (features.isEmpty()) {&#xA;        return;&#xA;    }&#xA;&#xA;    const QStringList rawFeaturesList = features.split(QLatin1Char(&amp;#39;,&amp;#39;), Qt::SkipEmptyParts);&#xA;    for (const QString &amp;amp;feature : rawFeaturesList) {&#xA;        auto f = QStringView(feature).trimmed();&#xA;        if (f.isEmpty()) {&#xA;            continue;&#xA;        }&#xA;        QList&amp;lt;QStringView&amp;gt; parts = f.split(QStringLiteral(&amp;#34;=&amp;#34;), Qt::SkipEmptyParts);&#xA;        if (parts.length() == 2) {&#xA;            const auto tag = QFont::Tag::fromString(parts[0]);&#xA;            bool ok = false;&#xA;            const int number = parts[1].toInt(&amp;amp;ok);&#xA;            if (tag.has_value() &amp;amp;&amp;amp; ok) {&#xA;                m_selectedFont.setFeature(tag.value(), number);&#xA;            }&#xA;        } else if (f.size() &amp;lt;= 4) {&#xA;            const auto tag = QFont::Tag::fromString(feature);&#xA;            if (tag.has_value()) {&#xA;                m_selectedFont.setFeature(tag.value(), 1);&#xA;            }&#xA;        }&#xA;    }&#xA;&#xA;    Q_EMIT q-&amp;gt;fontSelected(m_selectedFont);&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;我注意到，拆分后的结果已经被去掉了首尾空白：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;auto f = QStringView(feature).trimmed();&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;但原始、未去空白的字符串却仍然被用作 tag：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;const auto tag = QFont::Tag::fromString(feature);&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这看起来是开发者写错了。要修复这个问题，我们只需要把未去空白的字符串改成去空白后的字符串：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;const auto tag = QFont::Tag::fromString(f);&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;接下来，就该创建一个分支，把改动提交到该分支，并提交合并请求了。不过，由于我对 Git 的经验有限，我遇到了一个问题：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;warning: redirecting to https://invent.kde.org/rebellfs/kwidgetsaddons.git/&#xA;Enumerating objects: 21973, done.&#xA;Counting objects: 100% (21973/21973), done.&#xA;Delta compression using up to 4 threads&#xA;Compressing objects: 100% (2790/2790), done.&#xA;Writing objects: 100% (21973/21973), 41.17 MiB | ... KiB/s, done.&#xA;Total 21973 (delta 13428), reused 21374 (delta 12884), pack-reused 0 (from 0)&#xA;remote: Resolving deltas: 100% (13428/13428), done.&#xA;remote: Audit failure - Commit 046e4bb16e60b66070ee4a00c368ca6924db3a08 - Email address has an invalid domain : [kde@randomguy3.me.uk](mailto:kde@randomguy3.me.uk)&#xA;remote: Audit failure - Commit 046e4bb16e60b66070ee4a00c368ca6924db3a08 - Email address has an invalid domain : [kde@randomguy3.me.uk](mailto:kde@randomguy3.me.uk)&#xA;remote: Audit failure - Commit c8c7ab3d0e7ca825bbb01d58de005d4d589b12cc - Email address has an invalid domain : [kde@randomguy3.me.uk](mailto:kde@randomguy3.me.uk)&#xA;remote: Audit failure - Commit c8c7ab3d0e7ca825bbb01d58de005d4d589b12cc - Email address has an invalid domain : [kde@randomguy3.me.uk](mailto:kde@randomguy3.me.uk)&#xA;remote: Audit failure - Commit 62e5736a1f4afc2d24ef2c4d643a98bc60e6d6cd - Email address has an invalid domain : [kde@randomguy3.me.uk](mailto:kde@randomguy3.me.uk)&#xA;remote: Audit failure - Commit 62e5736a1f4afc2d24ef2c4d643a98bc60e6d6cd - Email address has an invalid domain : [kde@randomguy3.me.uk](mailto:kde@randomguy3.me.uk)&#xA;remote: Audit failure - Commit f317243c63620acec15a46c412502e73b9a04e2a - Email address has an invalid domain : [kde@randomguy3.me.uk](mailto:kde@randomguy3.me.uk)&#xA;remote: Audit failure - Commit f317243c63620acec15a46c412502e73b9a04e2a - Email address has an invalid domain : [kde@randomguy3.me.uk](mailto:kde@randomguy3.me.uk)&#xA;remote: Push declined - commits failed audit&#xA;remote: Should the audit failures above mention issues regarding your name, please ensure that your Git username has been set to your full name.&#xA;remote: Please see https://git-scm.com/book/en/v2/Getting-Started-First-Time-Git-Setup for more details on ensuring Git has been fully configured.&#xA;remote: In the event that your full name has been set and is shown above as being rejected, please file a Sysadmin ticket at https://go.kde.org/systickets&#xA;To https://invent.kde.org/rebellfs/kwidgetsaddons&#xA;! [remote rejected]     work/rebel1725/fix523757 -&amp;gt; work/rebel1725/fix523757 (pre-receive hook declined)&#xA;error: failed to push some refs to &amp;#39;https://invent.kde.org/rebellfs/kwidgetsaddons&amp;#39;&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;最后，因为这只是对单个文件的一个小改动，我还是通过浏览器提交了这项修改。&lt;/p&gt;&#xA;&lt;h2 id=&#34;结论&#34;&gt;结论&#xA;&lt;/h2&gt;&lt;p&gt;今天，我完成了自己对自由软件社区的第一次贡献，也成为了一名全新的自由软件贡献者。今后，我希望能够贡献更多，不断磨练自己的技能，并且对社区和自由软件运动变得更加有帮助。&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>A/I 邮箱因垃圾邮件问题而弃用</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/ai-mailbox-deprecated-due-to-spam-issues/</link>
            <pubDate>Sun, 02 Aug 2026 12:26:22 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/ai-mailbox-deprecated-due-to-spam-issues/</guid>
            <description>&lt;p&gt;由于我的 A/I 邮箱存在垃圾邮件问题，我已经启用了非常严格的垃圾邮件过滤策略，这会导致许多误判。以前我会不时查看垃圾邮件文件夹；但在过去几个月里，垃圾邮件问题变得越来越严重，也越来越难以区分正常邮件和垃圾邮件。&lt;/p&gt;&#xA;&lt;p&gt;因此，我决定弃用我的 A/I 邮箱。今后请改用我的 Tilde.Club 电子邮箱与我联系，这个地址在过去几个月里已经是我的主邮箱。A/I 邮箱不会被注销，其 WKD 条目也仍会更新；不过，我无法保证我能够看到并回复发送到该邮箱的邮件。&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>AArch64 中的递归</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/recursions-in-aarch64/</link>
            <pubDate>Thu, 23 Jul 2026 17:57:11 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/recursions-in-aarch64/</guid>
            <description>&lt;h2 id=&#34;基本模式&#34;&gt;基本模式&#xA;&lt;/h2&gt;&lt;p&gt;让我们从一个包含简单斐波那契计算函数的 C 程序开始。&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;#include &amp;lt;stdint.h&amp;gt;&#xA;#include &amp;lt;stdio.h&amp;gt;&#xA;&#xA;uint64_t fibonacci(uint32_t index)&#xA;{&#xA;    if (index &amp;lt;= 1) return 1;&#xA;    else return fibonacci(index - 1) + fibonacci(index - 2);&#xA;}&#xA;&#xA;int main()&#xA;{&#xA;    uint32_t i;&#xA;    scanf(&amp;#34;%u&amp;#34;, &amp;amp;i);&#xA;    printf(&amp;#34;%lu&amp;#34;, fibonacci(i));&#xA;    return 0;&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;编译它：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ gcc fibo.c -o fibo0&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;默认情况下，GCC 根本不会做任何优化。打开你那闪亮的 iaito，进入 &lt;code&gt;main&lt;/code&gt; 函数：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;64: int main (int argc, char **argv, char **envp);&#xA;afv: vars(3:sp[0x4..0x20])&#xA;0x00000878      stp      x29,    x30,    [var_20h]!&#xA;0x0000087c      mov      x29,    sp&#xA;0x00000880      add      x0,     sp,     0x1c&#xA;0x00000884      mov      x1,     x0&#xA;0x00000888      adrp     x0,     0&#xA;0x0000088c      add      x0,     x0,     0x8d8&#xA;0x00000890      bl       sym.imp.__isoc23_scanf&#xA;0x00000894      ldr      w0,     [var_1ch]&#xA;0x00000898      bl       sym.fibonacci&#xA;0x0000089c      mov      x1,     x0&#xA;0x000008a0      adrp     x0,     0&#xA;0x000008a4      add      x0,     x0,     0x8e0 ; const char *format&#xA;0x000008a8      bl       sym.imp.printf ; int printf(const char *format)&#xA;0x000008ac      mov      w0,     0&#xA;0x000008b0      ldp      x29,    x30,    [sp],   0x20&#xA;0x000008b4      ret&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这里你可以看到在 &lt;code&gt;0x0000898&lt;/code&gt; 处调用了 &lt;code&gt;sym.fibonacci&lt;/code&gt;。打开这个函数，看看它的图：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;the graph of sym.fibonacci&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://rebel1725.codeberg.page/images/pic_20260723_001.svg&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;你会看到 &lt;code&gt;sym.fibonacci&lt;/code&gt; 分别在 &lt;code&gt;0x0000854&lt;/code&gt; 和 &lt;code&gt;0x0000864&lt;/code&gt; 处调用了它自己。&lt;/p&gt;&#xA;&lt;p&gt;如果你去掉了符号信息，那么你看不到 &lt;code&gt;sym.fibonacci&lt;/code&gt;，但你仍然会在这里看到类似 &lt;code&gt;bl fcn.00000828&lt;/code&gt; 的东西。总之，函数调用自身的这种模式表示 &lt;em&gt;递归&lt;/em&gt;。&lt;/p&gt;&#xA;&lt;h2 id=&#34;优化&#34;&gt;优化&#xA;&lt;/h2&gt;&lt;p&gt;我们把 Fibonacci 函数换成阶乘函数：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;#include &amp;lt;stdint.h&amp;gt;&#xA;#include &amp;lt;stdio.h&amp;gt;&#xA;&#xA;uint64_t fact(uint32_t index)&#xA;{&#xA;    if (index &amp;lt;= 1) return 1;&#xA;    else return index * fact(index - 1);&#xA;}&#xA;&#xA;int main()&#xA;{&#xA;    uint32_t i;&#xA;    scanf(&amp;#34;%u&amp;#34;, &amp;amp;i);&#xA;    printf(&amp;#34;%lu&amp;#34;, fact(i));&#xA;    return 0;&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;编译它：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ gcc fact.c -o fact0&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;在 iaito 中打开后，你会得到一个调用 &lt;code&gt;sym.fact&lt;/code&gt; 的 &lt;code&gt;main&lt;/code&gt; 函数：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;64: int main (int argc, char **argv, char **envp);&#xA;afv: vars(3:sp[0x4..0x20])&#xA;0x0000086c      stp      x29,    x30,    [var_20h]!&#xA;0x00000870      mov      x29,    sp&#xA;0x00000874      add      x0,     sp,     0x1c&#xA;0x00000878      mov      x1,     x0&#xA;0x0000087c      adrp     x0,     0&#xA;0x00000880      add      x0,     x0,     0x8d0 ; &amp;#34;%u&amp;#34;&#xA;0x00000884      bl       sym.imp.__isoc23_scanf&#xA;0x00000888      ldr      w0,     [var_1ch]&#xA;0x0000088c      bl       sym.fact ; sym.fact(0x0)&#xA;0x00000890      mov      x1,     x0&#xA;0x00000894      adrp     x0,     0&#xA;0x00000898      add      x0,     x0,     0x8d8 ; const char *format ; &amp;#34;%lu&amp;#34;&#xA;0x0000089c      bl       sym.imp.printf ; int printf(const char *format)&#xA;; int printf(&amp;#34;%lu&amp;#34;)&#xA;0x000008a0      mov      w0,     0&#xA;0x000008a4      ldp      x29,    x30,    [sp],   0x20&#xA;0x000008a8      ret&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;被调用的 &lt;code&gt;sym.fact&lt;/code&gt; 函数的反汇编如下：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;68: fact (int64_t arg1);&#xA;`- args(x0) vars(4:sp[0x4..0x30])&#xA;0x00000828      stp      x29,    x30,    [var_30h]!&#xA;0x0000082c      mov      x29,    sp&#xA;0x00000830      str      x19,    [var_10h]&#xA;0x00000834      str      w0,     [var_2ch] ; arg1&#xA;0x00000838      ldr      w0,     [var_2ch]&#xA;0x0000083c      cmp      w0,     1&#xA;0x00000840      b.hi     0x84c ; unlikely&#xA;0x00000844      mov      x0,     1&#xA;0x00000848      b        0x860&#xA;0x0000084c      ldr      w19,    [var_2ch]&#xA;0x00000850      ldr      w0,     [var_2ch]&#xA;0x00000854      sub      w0,     w0,     1&#xA;0x00000858      bl       sym.fact ; sym.fact(-1)&#xA;0x0000085c      mul      x0,     x19,    x0&#xA;0x00000860      ldr      x19,    [var_10h]&#xA;0x00000864      ldp      x29,    x30,    [sp],   0x30&#xA;0x00000868      ret&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;以及它的图：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;the graph of sym.fact&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://rebel1725.codeberg.page/images/pic_20260723_002.svg&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;那么，如果我们打开优化会怎样？试试看：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ gcc fact.c -O2 -o fact2&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;在 iaito 中打开并检查 &lt;code&gt;main&lt;/code&gt; 函数。你会看到：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;the graph of main&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://rebel1725.codeberg.page/images/pic_20260723_003.svg&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;调用 &lt;code&gt;sym.fact&lt;/code&gt; 的那条指令不见了。取而代之的是，&lt;code&gt;main&lt;/code&gt; 函数内部出现了一个循环来完成工作。&lt;/p&gt;&#xA;&lt;p&gt;回到包含 Fibonacci 函数的 C 代码，在开启优化的情况下重新编译，然后检查 &lt;code&gt;main&lt;/code&gt; 函数：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;  ;-- section..text:&#xA;60: int main (int argc, char **argv, char **envp);&#xA;afv: vars(3:sp[0x4..0x20])&#xA;0x00000700      stp      x29,    x30,    [var_20h]! ; [12] -r-x section size 1176 named .text&#xA;0x00000704      adrp     x0,     0&#xA;0x00000708      add      x0,     x0,     0xbb8 ; &amp;#34;%u&amp;#34;&#xA;0x0000070c      mov      x29,    sp&#xA;0x00000710      add      x1,     sp,     0x1c&#xA;0x00000714      bl       sym.imp.__isoc23_scanf&#xA;0x00000718      ldr      w0,     [var_1ch]&#xA;0x0000071c      bl       sym.fibonacci ; sym.fibonacci(0x0, 0x177ffc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0)&#xA;0x00000720      mov      x1,     x0&#xA;0x00000724      adrp     x0,     0&#xA;0x00000728      add      x0,     x0,     0xbc0 ; const char *format ; &amp;#34;%lu&amp;#34;&#xA;0x0000072c      bl       sym.imp.printf ; int printf(const char *format)&#xA;0x00000730      mov      w0,     0&#xA;0x00000734      ldp      x29,    x30,    [sp],   0x20&#xA;0x00000738      ret&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;调用 &lt;code&gt;sym.fibonacci&lt;/code&gt; 的指令仍然存在。&lt;/p&gt;&#xA;&lt;p&gt;打开 &lt;code&gt;sym.fibonacci&lt;/code&gt; 的反汇编，你会体会到编译器有多么“疯狂”：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;792: fibonacci (uint32_t arg1, int64_t arg_60h, int64_t arg_70h, int64_t arg_80h, int64_t arg_88h, int64_t arg_90h, int64_t arg_98h, int64_t arg_a0h, int64_t arg_a8h);&#xA;`- args(x0, sp[0x60..0xa8]) vars(27:sp[0x4..0xb0])&#xA;0x00000880      sub      w6,     w0,     1 ; arg1&#xA;0x00000884      mov      x1,     0&#xA;0x00000888      cmp      w0,     1 ; arg1&#xA;0x0000088c      b.ls     0xb68 ; likely&#xA;0x00000890      cmp      w6,     1&#xA;0x00000894      b.eq     0xb70 ; unlikely&#xA;0x00000898      sub      w10,    w6,     1&#xA;0x0000089c      mov      x3,     0&#xA;0x000008a0      mov      w7,     w10&#xA;0x000008a4      cmp      w7,     1&#xA;0x000008a8      b.eq     0xb4c ; unlikely&#xA;0x000008ac      sub      w11,    w7,     1&#xA;0x000008b0      mov      x4,     0&#xA;0x000008b4      mov      w8,     w11&#xA;0x000008b8      cmp      w8,     1&#xA;0x000008bc      b.eq     0xb30 ; unlikely&#xA;0x000008c0      sub      w12,    w8,     1&#xA;0x000008c4      mov      x5,     0&#xA;0x000008c8      mov      w9,     w12&#xA;0x000008cc      cmp      w12,    1&#xA;0x000008d0      b.eq     0xa98 ; unlikely&#xA;0x000008d4      stp      x29,    x30,    [var_b0h]!&#xA;0x000008d8      mov      x29,    sp&#xA;0x000008dc      stp      x19,    x20,    [var_10h]&#xA;0x000008e0      stp      x21,    x22,    [var_20h]&#xA;0x000008e4      stp      x23,    x24,    [var_30h]&#xA;0x000008e8      stp      x25,    x26,    [var_40h]&#xA;0x000008ec      stp      x27,    x28,    [var_50h]&#xA;0x000008f0      sub      w13,    w9,     1&#xA;0x000008f4      mov      w25,    w13&#xA;0x000008f8      mov      x20,    0&#xA;0x000008fc      cmp      w25,    1&#xA;0x00000900      b.eq     0xa90 ; unlikely&#xA;0x00000904      sub      w27,    w25,    1&#xA;0x00000908      mov      x19,    0&#xA;0x0000090c      mov      w26,    w27&#xA;0x00000910      cmp      w26,    1&#xA;0x00000914      b.eq     0x9fc ; unlikely&#xA;0x00000918      sub      w28,    w26,    1&#xA;0x0000091c      mov      x22,    0&#xA;0x00000920      mov      w2,     w28&#xA;0x00000924      cmp      w2,     1&#xA;0x00000928      b.eq     0x9dc ; unlikely&#xA;0x0000092c      sub      w15,    w2,     1&#xA;0x00000930      mov      x21,    0&#xA;0x00000934      mov      w24,    w15&#xA;0x00000938      cmp      w24,    1&#xA;0x0000093c      b.eq     0x9bc ; unlikely&#xA;0x00000940      mov      w23,    w24&#xA;0x00000944      mov      x14,    0&#xA;0x00000948      sub      w0,     w23,    1&#xA;0x0000094c      stp      x1,     x3,     [arg_60h]&#xA;0x00000950      sub      w23,    w23,    2&#xA;0x00000954      stp      x4,     x5,     [arg_70h]&#xA;0x00000958      stp      w6,     w10,    [arg_80h]&#xA;0x0000095c      str      x14,    [arg_88h]&#xA;0x00000960      stp      w7,     w11,    [arg_90h]&#xA;0x00000964      stp      w8,     w12,    [arg_98h]&#xA;0x00000968      stp      w9,     w13,    [arg_a0h]&#xA;0x0000096c      stp      w2,     w15,    [arg_a8h]&#xA;0x00000970      bl       sym.fibonacci ; sym.fibonacci(0x1d001efffffff8, 0x0, 0xfffffffa, 0x0, 0x0, 0x0, 0x0, -1, 0x0)&#xA;0x00000974      ldr      x14,    [arg_88h]&#xA;0x00000978      cmp      w23,    1&#xA;0x0000097c      ldp      x1,     x3,     [arg_60h]&#xA;0x00000980      add      x14,    x14,    x0&#xA;0x00000984      ldp      x4,     x5,     [arg_70h]&#xA;0x00000988      ldp      w6,     w10,    [arg_80h]&#xA;0x0000098c      ldp      w7,     w11,    [arg_90h]&#xA;0x00000990      ldp      w8,     w12,    [arg_98h]&#xA;0x00000994      ldp      w9,     w13,    [arg_a0h]&#xA;0x00000998      ldp      w2,     w15,    [arg_a8h]&#xA;0x0000099c      b.hi     0x948 ; likely&#xA;0x000009a0      add      x21,    x21,    1&#xA;0x000009a4      add      x21,    x21,    x14&#xA;0x000009a8      cmp      w24,    2&#xA;0x000009ac      b.eq     0x9c0 ; unlikely&#xA;0x000009b0      sub      w24,    w24,    2&#xA;0x000009b4      cmp      w24,    1&#xA;0x000009b8      b.ne     0x940 ; likely&#xA;0x000009bc      add      x21,    x21,    1&#xA;0x000009c0      add      x22,    x22,    1&#xA;0x000009c4      sub      w2,     w2,     2&#xA;0x000009c8      add      x22,    x22,    x21&#xA;0x000009cc      cmp      w15,    1&#xA;0x000009d0      b.eq     0x9e0 ; unlikely&#xA;0x000009d4      cmp      w2,     1&#xA;0x000009d8      b.ne     0x92c ; likely&#xA;0x000009dc      add      x22,    x22,    1&#xA;0x000009e0      add      x19,    x19,    1&#xA;0x000009e4      sub      w26,    w26,    2&#xA;0x000009e8      add      x19,    x19,    x22&#xA;0x000009ec      cmp      w28,    1&#xA;0x000009f0      b.eq     0xa00 ; unlikely&#xA;0x000009f4      cmp      w26,    1&#xA;0x000009f8      b.ne     0x918 ; likely&#xA;0x000009fc      add      x19,    x19,    1&#xA;0x00000a00      add      x20,    x20,    1&#xA;0x00000a04      sub      w25,    w25,    2&#xA;0x00000a08      add      x20,    x20,    x19&#xA;0x00000a0c      cmp      w27,    1&#xA;0x00000a10      b.ne     0x8fc ; likely&#xA;0x00000a14      add      x5,     x5,     1&#xA;0x00000a18      sub      w9,     w9,     2&#xA;0x00000a1c      add      x5,     x5,     x20&#xA;0x00000a20      cmp      w13,    1&#xA;0x00000a24      b.eq     0xa34 ; unlikely&#xA;0x00000a28      cmp      w9,     1&#xA;0x00000a2c      b.ne     0x8f0 ; likely&#xA;0x00000a30      add      x5,     x5,     1&#xA;0x00000a34      add      x4,     x4,     1&#xA;0x00000a38      sub      w8,     w8,     2&#xA;0x00000a3c      add      x4,     x4,     x5&#xA;0x00000a40      cmp      w12,    1&#xA;0x00000a44      b.eq     0xa64 ; unlikely&#xA;0x00000a48      cmp      w8,     1&#xA;0x00000a4c      b.eq     0xa60 ; unlikely&#xA;0x00000a50      sub      w12,    w8,     1&#xA;0x00000a54      mov      x5,     0&#xA;0x00000a58      mov      w9,     w12&#xA;0x00000a5c      b        0xa28&#xA;0x00000a60      add      x4,     x4,     1&#xA;0x00000a64      add      x3,     x3,     1&#xA;0x00000a68      sub      w7,     w7,     2&#xA;0x00000a6c      add      x3,     x3,     x4&#xA;0x00000a70      cmp      w11,    1&#xA;0x00000a74      b.eq     0xae4 ; unlikely&#xA;0x00000a78      cmp      w7,     1&#xA;0x00000a7c      b.eq     0xae0 ; unlikely&#xA;0x00000a80      sub      w11,    w7,     1&#xA;0x00000a84      mov      x4,     0&#xA;0x00000a88      mov      w8,     w11&#xA;0x00000a8c      b        0xa48&#xA;0x00000a90      add      x20,    x20,    1&#xA;0x00000a94      b        0xa14&#xA;0x00000a98      add      x5,     x5,     1&#xA;0x00000a9c      add      x4,     x4,     1&#xA;0x00000aa0      add      x4,     x4,     x5&#xA;0x00000aa4      sub      w8,     w8,     2&#xA;0x00000aac      cmp      w12,    1&#xA;0x00000ab0      b.ne     0x8b8 ; likely&#xA;0x00000ab4      add      x3,     x3,     1&#xA;0x00000ab8      sub      w7,     w7,     2&#xA;0x00000abc      add      x3,     x3,     x4&#xA;0x00000ac0      cmp      w11,    1&#xA;0x00000ac4      b.ne     0x8a4 ; likely&#xA;0x00000ac8      add      x0,     x1,     1&#xA;0x00000acc      sub      w6,     w6,     2&#xA;0x00000ad0      add      x1,     x0,     x3&#xA;0x00000ad4      cmp      w10,    1&#xA;0x00000ad8      b.ne     0x890 ; likely&#xA;0x00000adc      add      x0,     x1,     1&#xA;0x00000ae0      add      x3,     x3,     1&#xA;0x00000ae4      add      x0,     x1,     1&#xA;0x00000ae8      sub      w6,     w6,     2&#xA;0x00000aec      add      x1,     x0,     x3&#xA;0x00000af0      cmp      w10,     1&#xA;0x00000af4      b.eq     0xb78 ; unlikely&#xA;0x00000af8      cmp      w6,     1&#xA;0x00000afc      b.eq     0xb10 ; unlikely&#xA;0x00000b00      sub      w10,    w6,     1&#xA;0x00000b04      mov      x3,     0&#xA;0x00000b08      mov      w7,     w10&#xA;0x00000b0c      b        0xa78&#xA;0x00000b10      ldp      x19,    x20,    [var_10h]&#xA;0x00000b14      add      x0,     x1,     2&#xA;0x00000b18      ldp      x21,    x22,    [var_20h]&#xA;0x00000b1c      ldp      x23,    x24,    [var_30h]&#xA;0x00000b20      ldp      x25,    x26,    [var_40h]&#xA;0x00000b24      ldp      x27,    x28,    [var_50h]&#xA;0x00000b28      ldp      x29,    x30,    [sp],   0xb0&#xA;0x00000b2c      ret&#xA;0x00000b30      add      x4,     x4,     1&#xA;0x00000b34      add      x3,     x3,     1&#xA;0x00000b38      add      x3,     x3,     x4&#xA;0x00000b3c      sub      w7,     w7,     2&#xA;0x00000b40      cmp      w11,    1&#xA;0x00000b44      b.ne     0x8a4 ; likely&#xA;0x00000b48      b        0xac4&#xA;0x00000b4c      add      x3,     x3,     1&#xA;0x00000b50      add      x0,     x1,     1&#xA;0x00000b54      add      x1,     x0,     x3&#xA;0x00000b58      sub      w6,     w6,     2&#xA;0x00000b5c      cmp      w10,     1&#xA;0x00000b60      b.ne     0x890 ; likely&#xA;0x00000b64      b        0xad8&#xA;0x00000b68      mov      x0,     1&#xA;0x00000b6c      ret&#xA;0x00000b70      add      x0,     x1,     2&#xA;0x00000b74      ret&#xA;0x00000b78      ldp      x19,    x20,    [var_10h]&#xA;0x00000b7c      add      x0,     x1,     1&#xA;0x00000b80      ldp      x21,    x22,    [var_20h]&#xA;0x00000b84      ldp      x23,    x24,    [var_30h]&#xA;0x00000b88      ldp      x25,    x26,    [var_40h]&#xA;0x00000b8c      ldp      x27,    x28,    [var_50h]&#xA;0x00000b90      ldp      x29,    x30,    [sp],   0xb0 ; 0x178000&#xA;0x00000b94      ret&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;不过，你仍然可以从 &lt;code&gt;0x00000970&lt;/code&gt; 处的自调用看出这是递归。&lt;/p&gt;&#xA;&lt;p&gt;这两者为什么不同？在 &lt;code&gt;fact()&lt;/code&gt; 函数中，调用关系是一条单一的线性链：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;the call relationship of fact()&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://rebel1725.codeberg.page/images/pic_20260723_004.svg&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;这样一条线性的调用链可以等价为一个循环。因此，编译器会将其优化，以节省栈空间。&lt;/p&gt;&#xA;&lt;p&gt;递归与循环等价的一个典型例子是尾递归，也就是最后一个操作是调用自身。例如：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;void f(unsigned int x, int *a)&#xA;{&#xA;    if (x == 0) return;&#xA;    else&#xA;    {&#xA;        *a += x;&#xA;        return f(x - 1, a);&#xA;    }&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这种递归已经被证明可以转换为等价的循环，因此编译器会对其进行优化。上面的 &lt;code&gt;fact()&lt;/code&gt; 示例虽然不是尾递归，但它仍然是线性的，编译器识别出了这个模式，所以也把它优化了。&lt;/p&gt;&#xA;&lt;p&gt;不过，&lt;code&gt;fibonacci()&lt;/code&gt; 不是这种情况：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;the call relationship of fibonacci()&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://rebel1725.codeberg.page/images/pic_20260723_005.svg&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;它的调用关系不是线性的，而是一棵树。因此，不可能把它转换成循环——编译器也就保留了递归模式。&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>致顾悦萱一封公开信</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/a-public-letter-for-aurora-garcia/</link>
            <pubDate>Fri, 17 Jul 2026 00:30:47 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/a-public-letter-for-aurora-garcia/</guid>
            <description>&lt;p&gt;你好啊，是我，Rebel。你曾深爱过，也深深爱着你的那个男孩儿。不知你现在怎么样，也不知道你是否最终会看到这封信。不过即便如此，把我心中的一些想法用文字写下来。&lt;/p&gt;&#xA;&lt;p&gt;不知不觉，从那件事情发生到现在，已经过去十四天了。其实退网的这段时间，我一直在忙于琐事。但即便如此，我依然偶尔有时间想到我们过去的点点滴滴。你曾说过我对于自由软件的热爱打动了你，但反过来你的热情也同样打动了我。我们都有充满着伤痛和坎坷的过去，都热爱着自由软件和自由软件运动，都志在逆向工程，都希望为 postmarketOS 作出贡献——我们真的有很多共同点。&lt;/p&gt;&#xA;&lt;p&gt;那条受到自由软件的保护、端到端加密的信道里，是我们感情的桥梁。我们可以在这里交流任何想说的内容，无论是技术还是生活，从编程语言，到各种自由软件技术，再到日常生活中的酸甜苦辣。&lt;/p&gt;&#xA;&lt;p&gt;我能感受到，你对我很好、很体贴，也很关心我。你愿意包容我的缺点，愿意理解我曾经犯下来的错误，你亲口对我说，你愿意站在我这一边。这让我很感动，真的真的很感动。&lt;/p&gt;&#xA;&lt;p&gt;我能感受到，我们的灵魂有着深深的共鸣。我也明白了，最伟大的爱情，并非二人之间望向彼此，而是共同望向同一个方向。你是我真正的、发自内心深处的爱着的那个人，因为，在我心中，你和逆向工程、radare2、iaito、GDB，以及我们所学习的各种自由软件技术，还有我们共同的自由软件、自由社会的理想，已经深深捆绑在一起了。我对你的爱便是对于自由软件的爱，反之亦然——我已经实现了对你的爱和对于自由软件的爱的统一。&lt;/p&gt;&#xA;&lt;p&gt;在这个充满着审查和监视的世界，在这个专有软件的不公正性日益凸显的世界，在这个自由软件更加重要的世界，我们依然为共同的理想奋斗着；依然为我们、我们身边的人，乃至于整个社区、全体无产阶级计算机用户甚至全人类共同的自由软件、自由社会而奋斗。&lt;/p&gt;&#xA;&lt;p&gt;也感谢我曾遇见你。虽然我们的关系仅仅维系了不到四个月就戛然而止（是的，甚至比&lt;a class=&#34;link&#34; href=&#34;../%e5%9b%9b%e5%8d%81%e4%b9%9d%e5%ba%a6%e5%a4%9c%e6%b7%b1%e4%ba%ba%e9%9d%99%e4%b9%8b%e9%97%b4%ef%bc%8c%e6%8c%a5%e4%b9%8b%e4%b8%8d%e5%8e%bb%e7%9a%84%e6%98%af%e6%b7%b1%e6%b7%b1%e7%9a%84%e6%80%9d%e5%bf%b5%e2%80%94%e2%80%94%e6%83%b3%e4%bd%a0%e4%ba%86%ef%bc%8cZumfy-Future/&#34; &gt;我和 Zumfy/Future&lt;/a&gt; 还要短上一个月左右），但是你让我对于爱情这件事对我意味着什么，有了最初步的、基于实践的认识。&lt;/p&gt;&#xA;&lt;p&gt;谢谢你。&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>x86_64 中的除法、模运算和冒泡排序</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/divisions-moduli-and-bubble-sort-in-x86_64/</link>
            <pubDate>Wed, 08 Jul 2026 17:46:33 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/divisions-moduli-and-bubble-sort-in-x86_64/</guid>
            <description>&lt;p&gt;用高级语言（例如 C）写出来的算法，在查看源代码时会显得非常直白。然而，编译器会把它们在汇编层面转换成一些相当神秘的模式。为了提升我们的逆向工程能力，我们需要学习这些模式，这样才能快速识别它们。这篇博客会列举一些例子，它们都是我今天在解一道 CTF 题时遇到的。&lt;/p&gt;&#xA;&lt;h2 id=&#34;整数之间的有符号除法&#34;&gt;整数之间的有符号除法&#xA;&lt;/h2&gt;&lt;p&gt;先看这段代码：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;&#xA;&#xA;int div(int a)&#xA;{&#xA;    return a / 42;&#xA;}&#xA;&#xA;int main()&#xA;{&#xA;    int a;&#xA;    scanf(&amp;#34;%d&amp;#34;, &amp;amp;a);&#xA;    a = div(a);&#xA;    printf(&amp;#34;%d&amp;#34;, a);&#xA;    return 0;&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;把它编译一下，然后打开你心爱的 iaito 或 radare2，看看汇编。我们不需要关心 &lt;code&gt;main()&lt;/code&gt;，所以直接进入 &lt;code&gt;sym.div&lt;/code&gt;，就能看到类似这样的内容：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;36: div (int64_t arg1);&#xA;`- args(rdi) vars(1:sp[0xc..0xc])&#xA;0x00001149      push     rbp&#xA;0x0000114a      mov      rbp,    rsp&#xA;0x0000114d      mov      dword [var_4h],  edi ; arg1&#xA;0x00001150      mov      eax,    dword [var_4h]&#xA;0x00001153      movsxd   rdx,    eax&#xA;0x00001156      imul     rdx,    rdx,    0x30c30c31&#xA;0x0000115d      shr      rdx,    0x20&#xA;0x00001161      sar      edx,    3&#xA;0x00001164      sar      eax,    0x1f&#xA;0x00001167      sub      edx,    eax&#xA;0x00001169      mov      eax,    edx&#xA;0x0000116b      pop      rbp&#xA;0x0000116c      ret&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这里看不到 &lt;code&gt;idiv&lt;/code&gt; 指令。相反，我们能看到 &lt;code&gt;0x00001156&lt;/code&gt; 处有一条 &lt;code&gt;imul&lt;/code&gt; 指令，后面跟着一条 &lt;code&gt;shr&lt;/code&gt; 指令和一条 &lt;code&gt;sar&lt;/code&gt; 指令。之后，结果会出现在 &lt;code&gt;edx&lt;/code&gt; 寄存器里。&lt;/p&gt;&#xA;&lt;p&gt;但如果我们换一个数字，会发生什么？试试看。编译下面这段：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;&#xA;&#xA;int div(int a)&#xA;{&#xA;    return a / 6;&#xA;}&#xA;&#xA;int main()&#xA;{&#xA;    int a;&#xA;    scanf(&amp;#34;%d&amp;#34;, &amp;amp;a);&#xA;    a = div(a);&#xA;    printf(&amp;#34;%d&amp;#34;, a);&#xA;    return 0;&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;我们会得到一段类似的反汇编：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;33: div (int64_t arg1);&#xA;`- args(rdi) vars(1:sp[0xc..0xc])&#xA;0x00001149      push     rbp&#xA;0x0000114a      mov      rbp,    rsp&#xA;0x0000114d      mov      dword [var_4h],  edi ; arg1&#xA;0x00001150      mov      eax,    dword [var_4h]&#xA;0x00001153      movsxd   rdx,    eax&#xA;0x00001156      imul     rdx,    rdx,    0x2aaaaaab&#xA;0x0000115d      shr      rdx,    0x20&#xA;0x00001161      sar      eax,    0x1f&#xA;0x00001164      sub      edx,    eax&#xA;0x00001166      mov      eax,    edx&#xA;0x00001168      pop      rbp&#xA;0x00001169      ret&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;如果我们使用负数，会发生什么？把 &lt;code&gt;6&lt;/code&gt; 换成 &lt;code&gt;-7&lt;/code&gt;，我们会得到类似的结果：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;36: div (int64_t arg1);&#xA;`- args(rdi) vars(1:sp[0xc..0xc])&#xA;0x00001149      push     rbp&#xA;0x0000114a      mov      rbp,    rsp&#xA;0x0000114d      mov      dword [var_4h],  edi ; arg1&#xA;0x00001150      mov      eax,    dword [var_4h]&#xA;0x00001153      movsxd   rdx,    eax&#xA;0x00001156      imul     rdx,    rdx,    0xffffffff92492493&#xA;0x0000115d      shr      rdx,    0x20&#xA;0x00001161      add      edx,    eax&#xA;0x00001163      sar      edx,    2&#xA;0x00001166      sar      eax,    0x1f&#xA;0x00001169      sub      eax,    edx&#xA;0x0000116b      pop      rbp&#xA;0x0000116c      ret&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;如果我们不使用常量，会发生什么？编译下面这段：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;&#xA;&#xA;int div(int a, int b)&#xA;{&#xA;    return a / b;&#xA;}&#xA;&#xA;int main()&#xA;{&#xA;    int a, b;&#xA;    scanf(&amp;#34;%d %d&amp;#34;, &amp;amp;a, &amp;amp;b);&#xA;    a = div(a, b);&#xA;    printf(&amp;#34;%d&amp;#34;, a);&#xA;    return 0;&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;之后，我们终于会看到不同的东西：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;19: div (int64_t arg1, signed int64_t arg2);&#xA;`- args(rdi, rsi) vars(2:sp[0xc..0x10])&#xA;0x00001149      push     rbp&#xA;0x0000114a      mov      rbp,    rsp&#xA;0x0000114d      mov      dword [var_4h],  edi ; arg1&#xA;0x00001150      mov      dword [var_8h],  esi ; arg2&#xA;0x00001153      mov      eax,    dword [var_4h]&#xA;0x00001156      cdq&#xA;0x00001157      idiv     dword [var_8h]&#xA;0x0000115a      pop      rbp&#xA;0x0000115b      ret&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;x86_64 CPU &lt;em&gt;确实&lt;/em&gt;支持除法，但代价很高。因此，如果除数已经以常量形式给出，编译器就会在编译时替我们做这种优化。它会根据除数计算出一个&lt;em&gt;魔数乘数&lt;/em&gt;，并把除法转换成乘法和位移的组合。有一篇&lt;a class=&#34;link&#34; href=&#34;https://arxiv.org/pdf/2012.12369&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;论文对这个算法作了进一步解释&lt;/a&gt;。&lt;/p&gt;&#xA;&lt;p&gt;不过，如果这个常量只在运行时才知道，这种优化就帮不上忙了，因此它会直接使用除法指令。&lt;/p&gt;&#xA;&lt;h2 id=&#34;取模运算&#34;&gt;取模运算&#xA;&lt;/h2&gt;&lt;p&gt;现在编译这段：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;&#xA;&#xA;int mymod(int a)&#xA;{&#xA;    return a % 42;&#xA;}&#xA;&#xA;int main()&#xA;{&#xA;    int a;&#xA;    scanf(&amp;#34;%d&amp;#34;, &amp;amp;a);&#xA;    a = mymod(a);&#xA;    printf(&amp;#34;%d&amp;#34;, a);&#xA;    return 0;&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;我们会得到 &lt;code&gt;mymod()&lt;/code&gt; 的反汇编：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;45: mymod (int64_t arg1);&#xA;`- args(rdi) vars(1:sp[0xc..0xc])&#xA;0x00001149      push     rbp&#xA;0x0000114a      mov      rbp,    rsp&#xA;0x0000114d      mov      dword [var_4h],  edi ; arg1&#xA;0x00001150      mov      eax,    dword [var_4h]&#xA;0x00001153      movsxd   rdx,    eax&#xA;0x00001156      imul     rdx,    rdx,    0x30c30c31&#xA;0x0000115d      shr      rdx,    0x20&#xA;0x00001161      sar      edx,    3&#xA;0x00001164      mov      ecx,    eax&#xA;0x00001166      sar      ecx,    0x1f&#xA;0x00001169      sub      edx,    ecx&#xA;0x0000116b      imul     ecx,    edx,    0x2a&#xA;0x0000116e      sub      eax,    ecx&#xA;0x00001170      mov      edx,    eax&#xA;0x00001172      mov      eax,    edx&#xA;0x00001174      pop      rbp&#xA;0x00001175      ret&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;从 &lt;code&gt;0x00001150&lt;/code&gt; 到 &lt;code&gt;0x00001161&lt;/code&gt; 的指令使用了上面提到的魔数乘数来实现除法。然后它会把被除数复制一份到 &lt;code&gt;ecx&lt;/code&gt;，再对它进行 31 位算术右移。如果被除数是非负数，&lt;code&gt;ecx&lt;/code&gt; 就是 0；否则，它就是 -1。&lt;/p&gt;&#xA;&lt;p&gt;这样做是为了从被除数中计算出一个 &lt;em&gt;bias&lt;/em&gt;，因为除法总是向零截断。我们用商来计算取模：对于正数，模 = 被除数 - 除数 * 商；对于负数，模 = 被除数 - 除数 * （商 + 1）。&lt;/p&gt;&#xA;&lt;h2 id=&#34;冒泡排序&#34;&gt;冒泡排序&#xA;&lt;/h2&gt;&lt;p&gt;最后编译这段：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;&#xA;&#xA;void bubble(int *arr, int n)&#xA;{&#xA;    for (int i1 = 0; i1 &amp;lt; n - 1; i1++)&#xA;    {&#xA;        for (int i2 = 0; i1 + i2 &amp;lt; n - 1; i2++)&#xA;        {&#xA;            if (arr[i1] &amp;gt; arr[i2])&#xA;            {&#xA;                int tmp = arr[i1];&#xA;                arr[i1] = arr[i2];&#xA;                arr[i2] = tmp;&#xA;            }&#xA;        }&#xA;    }&#xA;}&#xA;&#xA;int main()&#xA;{&#xA;    int a[42];&#xA;    for (int i1 = 0; i1 &amp;lt; 42; i1++)&#xA;        a[i1] = 42 - i1;&#xA;    bubble(a, 42);&#xA;    for (int i1 = 0; i1 &amp;lt; 42; i1++)&#xA;        printf(&amp;#34;%d&amp;#34;, a[i1]);&#xA;    return 0;&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这次看看 iaito 生成的 &lt;code&gt;sym.bubble&lt;/code&gt; 图：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;sym.bubble 的图&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://rebel1725.codeberg.page/images/pic_20260708_001.svg&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;我们可以看到，&lt;code&gt;0x00001144&lt;/code&gt; 处设置了一个计数器。&lt;code&gt;0x00001209&lt;/code&gt; 这个块里有一次比较。如果计数器还没有达到阈值，就会继续执行。&lt;code&gt;0x00001150&lt;/code&gt; 处又设置了一个计数器。&lt;code&gt;0x0000115c&lt;/code&gt; 这个块里会比较两个相邻的数字。如果前者更大，就会在 &lt;code&gt;0x0000118c&lt;/code&gt; 这个块里执行交换。&lt;/p&gt;&#xA;&lt;h2 id=&#34;结论&#34;&gt;结论&#xA;&lt;/h2&gt;&lt;p&gt;这只是逆向工程过程中可能遇到的几种模式示例。随着我们做得越来越多，我们会积累越来越多的经验，也就能够更快地识别反汇编中的更多模式。&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>告别——也许我们终有一天再见？</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/goodbye-and-perhaps-well-meet-again-someday/</link>
            <pubDate>Sun, 05 Jul 2026 16:37:56 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/goodbye-and-perhaps-well-meet-again-someday/</guid>
            <description>&lt;p&gt;由于我目前无法透露的某些原因，我将无限期地（也许是永久地？）淡出社区。在这篇博客文章中，我想澄清几点：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;我的即时通讯账号，包括但不限于 XMPP、Matrix、SimpleX 和 Delta Chat，将很快不再活跃。不过，至少目前，它们不会被停用，这些账号上的信任在可预见的未来也不会失效。&lt;/li&gt;&#xA;&lt;li&gt;社交账号，包括但不限于 Mastodon，将继续保持活跃。&lt;/li&gt;&#xA;&lt;li&gt;我的主 OpenPGP 公钥（指纹为 696A423E9993D727706AA733BCD5DC5659C7FB50）至少目前不会被撤销，并将继续更新。不过，我的备用 OpenPGP 公钥（指纹为 7083EAFFF75321FF9634ABCD98313A47362B498B）可能会被撤销；如果是这样，我会将撤销信息上传到 OpenPGP 密钥服务器。&lt;/li&gt;&#xA;&lt;li&gt;我的电子邮件地址 &lt;a class=&#34;link&#34; href=&#34;mailto:rebel1725@tilde.club&#34; &gt;rebel1725@tilde.club&lt;/a&gt; 将继续使用。你可以通过这个电子邮件地址联系我。&lt;/li&gt;&#xA;&lt;li&gt;我将继续担任 FSCS（自由软件中文网, &lt;a class=&#34;link&#34; href=&#34;https://freeswzhcn.codeberg.page/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;https://freeswzhcn.codeberg.page/&lt;/a&gt;）的首席官方贡献者，其基础设施也将继续运行在我的服务器上。不过，其关联项目 FSCC（自由软件中文社区, &lt;a class=&#34;link&#34; href=&#34;https://fscc_next.codeberg.page/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;https://fscc_next.codeberg.page/&lt;/a&gt;）的管理权将移交给 Aurora Garcia（0x28EC1231FACA465A, &lt;a class=&#34;link&#34; href=&#34;https://aurorag132.codeberg.page/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;https://aurorag132.codeberg.page/&lt;/a&gt;）。此外，XMPP Together Committee（&lt;a class=&#34;link&#34; href=&#34;https://xmpptogether.codeberg.page/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;https://xmpptogether.codeberg.page/&lt;/a&gt;）主席一职，以及由我管理的该委员会频道的管理员权限，也将移交给 Aurora Garcia。&lt;/li&gt;&#xA;&lt;li&gt;无论是现代风格网站还是复古风格网站都不会关闭，我也会继续在这个博客上发文。此外，关于我的任何更新也都会发布在博客上。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;万事终有尽头。愿没有我的日子里，你们的生活充满快乐与喜悦。&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>我的 Eepsite 已重新上线</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/my-eepsite-is-back-online/</link>
            <pubDate>Wed, 10 Jun 2026 13:57:10 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/my-eepsite-is-back-online/</guid>
            <description>&lt;p&gt;我以前把我的 eepsite 托管在家里的服务器上，但大约两周前，出于安全考虑，我停止了托管。现在我找到了一种在 &lt;a class=&#34;link&#34; href=&#34;https://vern.cc/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;~vern&lt;/a&gt; 上托管它的方法，所以它又重新上线了。&lt;/p&gt;&#xA;&lt;p&gt;欢迎访问 &lt;a class=&#34;link&#34; href=&#34;http://rebel1725.i2p/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;rebel1725.i2p&lt;/a&gt;。&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>使用 Net Qube 将流量路由到 SOCKS 代理</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/route-traffics-to-a-socks-proxy-using-a-net-qube/</link>
            <pubDate>Fri, 05 Jun 2026 00:08:03 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/route-traffics-to-a-socks-proxy-using-a-net-qube/</guid>
            <description>&lt;p&gt;&lt;strong&gt;免责声明：我是在一切“似乎”都正常工作之后才写下这份指南的。对于流量泄漏或其他意外问题，我不承担责任。&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;本文说明如何使用 net qube，通过特定 qube 将流量路由到 SOCKS 代理。&lt;/p&gt;&#xA;&lt;h2 id=&#34;第-1-步安装所需软件包&#34;&gt;第 1 步：安装所需软件包&#xA;&lt;/h2&gt;&lt;p&gt;你需要 &lt;code&gt;screen&lt;/code&gt; 和 &lt;code&gt;redsocks&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&#xA;# apt install screen redsocks&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;第-2-步创建一个-net-qube&#34;&gt;第 2 步：创建一个 net qube&#xA;&lt;/h2&gt;&lt;p&gt;请在你的 Qube Manager 中完成这一步。&lt;/p&gt;&#xA;&lt;h2 id=&#34;第-3-步配置-redsocks&#34;&gt;第 3 步：配置 &lt;code&gt;redsocks&lt;/code&gt;&#xA;&lt;/h2&gt;&lt;p&gt;在新的 net qube 中创建 &lt;code&gt;/rw/config/redsocks.conf&lt;/code&gt;：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&#xA;base {&#xA;log_info = on;&#xA;log_debug = on;&#xA;log = stderr;&#xA;daemon = on;&#xA;redirector = iptables;&#xA;}&#xA;&#xA;redsocks {&#xA;local_ip = 0.0.0.0;&#xA;local_port = 12345;&#xA;&#xA;ip = &amp;lt;changeme&amp;gt;;&#xA;port = &amp;lt;changeme&amp;gt;;&#xA;type = &amp;lt;changeme&amp;gt;;&#xA;login = &amp;#34;&amp;lt;changeme&amp;gt;&amp;#34;;&#xA;password = &amp;#34;&amp;lt;changeme&amp;gt;&amp;#34;;&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;第-4-步配置自动启动&#34;&gt;第 4 步：配置自动启动&#xA;&lt;/h2&gt;&lt;p&gt;将以下内容添加到新 net qube 中的 &lt;code&gt;/rw/config/rc.local&lt;/code&gt;：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&#xA;systemctl stop redsocks&#xA;&#xA;nft add table ip nat 2&amp;gt;/dev/null || true&#xA;nft &amp;#39;add chain ip nat prerouting { type nat hook prerouting priority -100; policy accept; }&amp;#39; 2&amp;gt;/dev/null || true&#xA;&#xA;nft add set ip nat bypass4 &amp;#39;{ type ipv4_addr; flags interval; elements = { &#xA;0.0.0.0/8, &#xA;10.0.0.0/8, &#xA;100.64.0.0/10, &#xA;127.0.0.0/8, &#xA;169.254.0.0/16, &#xA;172.16.0.0/12, &#xA;192.168.0.0/16, &#xA;224.0.0.0/4, &#xA;240.0.0.0/4 &#xA;} }&amp;#39; 2&amp;gt;/dev/null || true&#xA;&#xA;nft add rule ip nat prerouting ip daddr @bypass4 accept&#xA;nft add rule ip nat prerouting meta l4proto tcp redirect to :12345&#xA;nft add rule ip qubes custom-input iifgroup 2 tcp dport 12345 ct state new,established,related counter accept&#xA;&#xA;cp /rw/config/redsocks.conf /etc/redsocks.conf&#xA;systemctl start redsocks&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;第-5-步重启并配置&#34;&gt;第 5 步：重启并配置&#xA;&lt;/h2&gt;&lt;p&gt;重启该 net qube，然后把你希望通过这个代理转发流量的那些 qube 的 net qube 设置为这个 net qube。&lt;/p&gt;&#xA;&lt;p&gt;一切就绪，祝你使用愉快 :-)&lt;/p&gt;&#xA;&lt;p&gt;问题：有时 &lt;code&gt;redsocks&lt;/code&gt; 会收到 &lt;code&gt;SIGABRT&lt;/code&gt; 信号并崩溃。解决方法：运行 &lt;code&gt;systemctl start redsocks&lt;/code&gt; 将其重新启动。&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>挑战-响应中的一个严重安全问题</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/a-serious-security-issue-of-challenge-response/</link>
            <pubDate>Thu, 28 May 2026 00:47:56 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/a-serious-security-issue-of-challenge-response/</guid>
            <description>&lt;p&gt;挑战-响应的一种做法是，把一个随机字符串（&lt;code&gt;nonce&lt;/code&gt;）发送给需要验证身份的人，并让对方使用自己的私钥对该字符串进行签名。然而，这会带来一个非常严重的安全问题。&lt;/p&gt;&#xA;&lt;p&gt;例如，Alice 想要验证 Bob。但 Mallory 插在他们中间。于是会发生下面的事情：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Alice 将挑战发送给被 Mallory 冒充的 &amp;lsquo;Bob&amp;rsquo;。&lt;/li&gt;&#xA;&lt;li&gt;Mallory 冒充 Alice，将该挑战转发给 Bob，并请求返回响应。&lt;/li&gt;&#xA;&lt;li&gt;Bob 把响应发回，然后 Mallory 再把响应转发回去。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;在这种情况下，Mallory 已经成功向 Alice 冒充了 Bob，现在就可以进行 MITM 攻击了。&lt;/p&gt;&#xA;&lt;p&gt;解决办法不是只把随机字符串当作挑战。一个好的挑战至少应包含以下内容：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;验证者和被验证者的信任锚的标识信息（例如 OpenPGP 指纹）；&lt;/li&gt;&#xA;&lt;li&gt;通道的标识信息（例如，面对面验证时的地点；在 XMPP 上验证时的 JID 以及 OMEMO 指纹；在 Matrix 上验证时双方的 Matrix ID 和房间）；&lt;/li&gt;&#xA;&lt;li&gt;时间戳；&lt;/li&gt;&#xA;&lt;li&gt;nonce，也就是随机字符串。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;换句话说，挑战应当把验证者和被验证者的身份、已认证的通道或会话上下文、用于保证新鲜度的时间戳，以及 nonce 绑定在一起。验证者必须将已签名的身份声明与已认证的传输元数据进行比对。&lt;/p&gt;&#xA;&lt;p&gt;在这种情况下，Mallory 就必须篡改通道上下文来欺骗 Bob（否则 Bob 会立刻识别出这个有问题的挑战并拒绝响应），而这样一来，由于挑战已被篡改，Alice 在验证时就会发现响应无效。&lt;/p&gt;&#xA;&lt;p&gt;为了获得更强的安全性，请彼此相互验证。&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>使用 GDB 和 Iaito/Radare2 的逆向工程示例</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/a-reverse-engineering-example-with-gdb-and-iaito-radare2/</link>
            <pubDate>Wed, 27 May 2026 23:56:34 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/a-reverse-engineering-example-with-gdb-and-iaito-radare2/</guid>
            <description>&lt;p&gt;过去几周里，我一直在学习逆向工程，并且&lt;a class=&#34;link&#34; href=&#34;../a-brief-introduction-into-reverse-engineering/&#34; &gt;写了一篇博客文章&lt;/a&gt;来分享我的第一次体验。最近，我又深入了一些，正在用静态分析和动态分析相结合的方式解决一个 CTF 题目，而我觉得这正是进一步解释逆向工程的一个很好的例子。&lt;/p&gt;&#xA;&lt;p&gt;我之前原本打算写一篇关于使用 GDB 进行动态分析的文章。不过，我发现这个题目同样非常适合用来解释 GDB。为了解出这个题目，我还会使用另一个工具，&lt;strong&gt;iaito&lt;/strong&gt;，它是 radare2 的图形前端。&lt;/p&gt;&#xA;&lt;h2 id=&#34;题目&#34;&gt;题目&#xA;&lt;/h2&gt;&lt;p&gt;cIMG 可以说是一种图像格式，用来在终端中表示由不同颜色字符组成的图像。它由以下部分构成：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;魔数，也就是 &lt;code&gt;cIMG&lt;/code&gt;；&lt;/li&gt;&#xA;&lt;li&gt;版本号；&lt;/li&gt;&#xA;&lt;li&gt;宽度和高度；&lt;/li&gt;&#xA;&lt;li&gt;数据，每个像素都包含 R、G、B 和 ASCII 字符。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;这个题目要求你向一个可执行程序提供一个 cIMG 文件，只有当 cIMG 满足某些条件时，它才会给出 flag。&lt;/p&gt;&#xA;&lt;h2 id=&#34;源代码&#34;&gt;源代码&#xA;&lt;/h2&gt;&lt;p&gt;在这里获取题目的&lt;a class=&#34;link&#34; href=&#34;https://raw.githubusercontent.com/pwncollege/intro-to-cybersecurity-dojo/refs/heads/main/reverse-engineering/cimg-framebuffer-mini-c/_0/cimg.c&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;source&lt;/a&gt;。这份源代码看起来使用的是 BSD 2-Clause 许可证。&lt;/p&gt;&#xA;&lt;p&gt;使用 GCC 编译它：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ gcc -O3 challenge.c -o challenge&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;打开 Python 并创建一个示例 cIMG 文件：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ python3&#xA;Python 3.13.5 (Jun 25 2025, 18:55:22) [GCC 14.2.0] on linux&#xA;Type &amp;#34;help&amp;#34;, &amp;#34;copyright&amp;#34;, &amp;#34;credits&amp;#34; or &amp;#34;license&amp;#34; for more information.&#xA;&amp;gt;&amp;gt;&amp;gt; with open(&amp;#34;example.cimg&amp;#34;, &amp;#34;wb&amp;#34;) as file:&#xA;...     file.write(b&amp;#34;cIMG\x02\0\x0a\x0a&amp;#34;)&#xA;...     file.write(b&amp;#34;\x50&amp;#34;*(10*10*4))&#xA;...     &#xA;8&#xA;400&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;使用题目的二进制程序打开这个示例 cIMG 文件：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;user@learnaarch64asm:~$ ./challenge ./example.cimg &#xA;PPPPPPPPPP&#xA;PPPPPPPPPP&#xA;PPPPPPPPPP&#xA;PPPPPPPPPP&#xA;PPPPPPPPPP&#xA;PPPPPPPPPP&#xA;PPPPPPPPPP&#xA;PPPPPPPPPP&#xA;PPPPPPPPPP&#xA;PPPPPPPPPP&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这个文件会输出内容，但不会给出 flag。&lt;/p&gt;&#xA;&lt;h2 id=&#34;静态分析&#34;&gt;静态分析&#xA;&lt;/h2&gt;&lt;p&gt;我们需要构造一个能 &lt;em&gt;给出 flag&lt;/em&gt; 的 cIMG 文件。先做静态分析。&lt;/p&gt;&#xA;&lt;p&gt;在 iaito 中打开文件。执行 &lt;code&gt;aaa&lt;/code&gt; 分析，并打开 &lt;code&gt;main&lt;/code&gt; 函数的图形视图。你会得到：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;main 函数的图形&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;167px&#34; data-flex-grow=&#34;69&#34; height=&#34;5056&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://rebel1725.codeberg.page/images/pic_20260527_001.png&#34; srcset=&#34;https://rebel1725.codeberg.page/blog/pic_20260527_001_417726312315916099_hu_82e400e5137c762d.png 800w, https://rebel1725.codeberg.page/blog/pic_20260527_001_417726312315916099_hu_ab732d533b78dd65.png 1600w, https://rebel1725.codeberg.page/blog/pic_20260527_001_417726312315916099_hu_3bdc24ba81ca3288.png 2400w, https://rebel1725.codeberg.page/images/pic_20260527_001.png 3532w&#34; width=&#34;3532&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;我们可以看到在 &lt;code&gt;0x00000cac&lt;/code&gt; 处读取文件头，在 &lt;code&gt;0x00000cc4&lt;/code&gt; 处检查魔数，在 &lt;code&gt;0x00000cd0&lt;/code&gt; 处检查版本号，在 &lt;code&gt;0x00000ce0&lt;/code&gt; 处读取宽度和高度。然后它使用 &lt;code&gt;malloc&lt;/code&gt; 为图像数据分配一块内存，并把数据读入其中。&lt;/p&gt;&#xA;&lt;p&gt;魔数是 &lt;code&gt;cIMG&lt;/code&gt;，换成十六进制就是 &lt;code&gt;63 49 4d 47&lt;/code&gt;；版本号是一个 32 位小端整数；高度和宽度都是 8 位整数。&lt;/p&gt;&#xA;&lt;h2 id=&#34;flag-条件&#34;&gt;flag 条件&#xA;&lt;/h2&gt;&lt;p&gt;我们直接看函数结尾。显然，&lt;code&gt;sym.win&lt;/code&gt; 是会给出 flag 的函数。它在 &lt;code&gt;0x00000e8c&lt;/code&gt; 被调用，而这一步是在 &lt;code&gt;0x00000e58&lt;/code&gt; 处的一次检查之后执行的。这项检查要求 &lt;code&gt;w19&lt;/code&gt; 不能为零。&lt;/p&gt;&#xA;&lt;h2 id=&#34;篡改控制流&#34;&gt;篡改控制流&#xA;&lt;/h2&gt;&lt;p&gt;该启动 GDB 了。&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ gdb --args ./challenge ./example.cimg &#xA;GNU gdb (Debian 16.3-1) 16.3&#xA;Copyright (C) 2024 Free Software Foundation, Inc.&#xA;License GPLv3+ or later &amp;lt;http://gnu.org/licenses/gpl.html&amp;gt;&#xA;This is free software: you are free to change and redistribute it.&#xA;There is NO WARRANTY, to the extent permitted by law.&#xA;Type &amp;#34;show copying&amp;#34; and &amp;#34;show warranty&amp;#34; for details.&#xA;This GDB was configured as &amp;#34;aarch64-linux-gnu&amp;#34;.&#xA;Type &amp;#34;show configuration&amp;#34; for configuration details.&#xA;For bug reporting instructions, please see:&#xA;&amp;lt;https://www.gnu.org/software/gdb/bugs/&amp;gt;.&#xA;Find the GDB manual and other documentation resources online at:&#xA;    &amp;lt;http://www.gnu.org/software/gdb/documentation/&amp;gt;.&#xA;&#xA;For help, type &amp;#34;help&amp;#34;.&#xA;Type &amp;#34;apropos word&amp;#34; to search for commands related to &amp;#34;word&amp;#34;...&#xA;Reading symbols from ./challenge...&#xA;(No debugging symbols found in ./challenge)&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;在 &lt;code&gt;main&lt;/code&gt; 函数处打断点并启动程序：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;(gdb) break *main&#xA;Breakpoint 1 at 0xc44&#xA;(gdb) run&#xA;Starting program: /home/user/challenge ./example.cimg&#xA;[Thread debugging using libthread_db enabled]&#xA;Using host libthread_db library &amp;#34;/lib/aarch64-linux-gnu/libthread_db.so.1&amp;#34;.&#xA;&#xA;Breakpoint 1, 0x0000aaaaaaaa0c44 in main ()&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;我们注意到 GDB 的数据地址有一个 &lt;code&gt;0xaaaaaaaa0000&lt;/code&gt; 的偏移。&lt;/p&gt;&#xA;&lt;p&gt;在 flag 条件检查之前打断点，然后继续执行：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;(gdb) break *0x0000aaaaaaaa0e58&#xA;Breakpoint 2 at 0xaaaaaaaa0e58&#xA;(gdb) continue&#xA;Continuing.&#xA;PPPPPPPPPP&#xA;PPPPPPPPPP&#xA;PPPPPPPPPP&#xA;PPPPPPPPPP&#xA;PPPPPPPPPP&#xA;PPPPPPPPPP&#xA;PPPPPPPPPP&#xA;PPPPPPPPPP&#xA;PPPPPPPPPP&#xA;PPPPPPPPPP&#xA;&#xA;Breakpoint 2, 0x0000aaaaaaaa0e58 in main ()&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;修改寄存器 &lt;code&gt;w19&lt;/code&gt; 的内容并继续执行：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;(gdb) set $w19 = 1&#xA;(gdb) continue&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;然后这个可执行程序就会给出 flag。至此任务完成，祝你有美好的一天 :-p&lt;/p&gt;&#xA;&lt;p&gt;开玩笑的。如果我们真的这样结束这个题目，逆向工程的乐趣就没了。让我们继续深入。&lt;/p&gt;&#xA;&lt;h2 id=&#34;数据检查&#34;&gt;数据检查&#xA;&lt;/h2&gt;&lt;p&gt;回到 iaito。点击图中的 &lt;code&gt;w19&lt;/code&gt;。这会在图里的所有指令中高亮该寄存器。向前回溯图形，寻找线索。&lt;/p&gt;&#xA;&lt;p&gt;我们可以在图中看到一些对 &lt;code&gt;sym.imp.memcmp&lt;/code&gt; 的调用。&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;memcmp&lt;/code&gt; 是 C 标准库中的一个函数，声明在 &lt;code&gt;&amp;lt;string.h&amp;gt;&lt;/code&gt; 中，它会逐字节比较两块内存：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;int memcmp(const void *ptr1, const void *ptr2, size_t n);&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;ptr1&lt;/code&gt; 和 &lt;code&gt;ptr2&lt;/code&gt; 分别指向那两块内存，而 &lt;code&gt;n&lt;/code&gt; 指定要比较的字节数。如果两块内存完全相同，该函数返回 &lt;code&gt;0&lt;/code&gt;；否则返回一个非零值。&lt;/p&gt;&#xA;&lt;p&gt;这里有四次 &lt;code&gt;memcmp&lt;/code&gt; 调用。每次调用后面都跟着 &lt;code&gt;cmp w0, 0&lt;/code&gt;。除了第一次调用之外，&lt;code&gt;cmp&lt;/code&gt; 后面还有 &lt;code&gt;cset w0, eq&lt;/code&gt; 和 &lt;code&gt;and w19, w19, w0&lt;/code&gt;。我们可以得出结论：如果 &lt;code&gt;memcmp&lt;/code&gt; 发现差异，&lt;code&gt;w19&lt;/code&gt; 就会被清零，因为那时 &lt;code&gt;w0&lt;/code&gt; 会变成零。因此我们猜测，需要让四对内存块完全相同。&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;x0&lt;/code&gt; 和 &lt;code&gt;x1&lt;/code&gt; 是要比较的两个地址。&lt;code&gt;x2&lt;/code&gt; 包含大小；&lt;code&gt;mov x2, 0x18&lt;/code&gt; 告诉我们大小是 24 字节。&lt;/p&gt;&#xA;&lt;p&gt;再次打开 GDB，并在第一次 &lt;code&gt;memcmp&lt;/code&gt; 之前检查内存：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;(gdb) break *0x0000aaaaaaaa0e78&#xA;Breakpoint 1 at 0xaaaaaaaa0e78&#xA;(gdb) run&#xA;Starting program: /home/user/challenge ./example.cimg&#xA;[Thread debugging using libthread_db library &amp;#34;/lib/aarch64-linux-gnu/libthread_db.so.1].&#xA;PPPPPPPPPP&#xA;PPPPPPPPPP&#xA;PPPPPPPPPP&#xA;PPPPPPPPPP&#xA;PPPPPPPPPP&#xA;PPPPPPPPPP&#xA;PPPPPPPPPP&#xA;PPPPPPPPPP&#xA;PPPPPPPPPP&#xA;PPPPPPPPPP&#xA;&#xA;Breakpoint 1, 0x0000aaaaaaaa0e78 in main ()&#xA;(gdb) info registers x0 x1&#xA;x0             0xaaaaaaac12a0      187649984565920&#xA;x1             0xaaaaaaac00c0      187649984561344&#xA;(gdb) x/24xb $x0&#xA;0xaaaaaaac12a0: 0x1b    0x5b    0x33    0x38    0x3b    0x32    0x3b    0x30&#xA;0xaaaaaaac12a8: 0x38    0x30    0x3b    0x30    0x38    0x30    0x3b    0x30&#xA;0xaaaaaaac12b0: 0x38    0x30    0x6d    0x50    0x1b    0x5b    0x30    0x6d&#xA;(gdb) x/24xb $x1&#xA;0xaaaaaaac00c0 &amp;lt;desired_output&amp;gt;:        0x1b    0x5b    0x33    0x38    0x3b   0x32     0x3b    0x32&#xA;0xaaaaaaac00c8 &amp;lt;desired_output+8&amp;gt;:      0x33    0x31    0x3b    0x30    0x31   0x37     0x3b    0x31&#xA;0xaaaaaaac00d0 &amp;lt;desired_output+16&amp;gt;:     0x33    0x30    0x6d    0x63    0x1b   0x5b     0x30    0x6d&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;随机字节。我看不出它们是什么意思。&lt;/p&gt;&#xA;&lt;p&gt;回到 iaito。第一块内存是从 &lt;code&gt;x22&lt;/code&gt; 载入的，而 &lt;code&gt;x22&lt;/code&gt; 又是从地址 &lt;code&gt;var_48h&lt;/code&gt; 载入的。&lt;code&gt;afv&lt;/code&gt; 告诉我们它距离 &lt;code&gt;sp&lt;/code&gt; 是 &lt;code&gt;0x48&lt;/code&gt;：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[0x00000e70]&amp;gt; afv&#xA;arg signed int argc @ x0&#xA;arg char ** s @ x1&#xA;var int64_t var_50h @ sp+0x0&#xA;var int64_t var_50h_2 @ sp+0x8&#xA;var int64_t var_10h @ sp+0x10&#xA;var int64_t var_10h_2 @ sp+0x18&#xA;var int64_t var_20h @ sp+0x20&#xA;var int64_t var_20h_2 @ sp+0x28&#xA;var void * buf @ sp+0x38&#xA;var int64_t var_3ch @ sp+0x3c&#xA;var int64_t var_3eh @ sp+0x3e&#xA;var int64_t var_3fh @ sp+0x3f&#xA;var int64_t var_40h @ sp+0x40&#xA;var int64_t var_48h @ sp+0x48&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;重新启动 GDB，并在 &lt;code&gt;main&lt;/code&gt; 被调用后跳过函数序言：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;(gdb) break *main&#xA;Breakpoint 1 at 0xaaaaaaaa0c44&#xA;(gdb) run&#xA;Starting program: /home/user/challenge ./example.cimg&#xA;[Thread debugging using libthread_db library &amp;#34;/lib/aarch64-linux-gnu/libthread_db.so.1].&#xA;&#xA;Breakpoint 1, 0x0000aaaaaaaa0c44 in main ()&#xA;(gdb) si&#xA;0x0000aaaaaaaa0c48 in main ()&#xA;(gdb) si&#xA;0x0000aaaaaaaa0c4c in main ()&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;查看栈指针的值并设置一个观察点：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;(gdb) info registers sp&#xA;sp             0xfffffffff290      0xfffffffff290&#xA;(gdb) watch *(long long *)0xfffffffff2d8&#xA;Hardware watchpoint 2: *(long long *)0xfffffffff2d8&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;继续执行：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-(gdb)&#34; data-lang=&#34;(gdb)&#34;&gt;Continuing.&#xA;&#xA;Hardware watchpoint 2: *(long long *)0xfffffffff2d8&#xA;&#xA;Old value = 281474840286680&#xA;New value = 0&#xA;0x0000aaaaaaaa0c5c in main ()&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;在 iaito 中定位这个地址。我们可以看到，在 &lt;code&gt;0x00000c58&lt;/code&gt;（也就是 &lt;code&gt;0x00000c5c&lt;/code&gt; 前一条指令）处，&lt;code&gt;var_48h&lt;/code&gt; 通过一个 &lt;code&gt;str&lt;/code&gt; 被清零了。&lt;/p&gt;&#xA;&lt;p&gt;继续往下，看看这个变量是在什么地方被设置的：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;(gdb) continue&#xA;Continuing.&#xA;&#xA;Hardware watchpoint 2: *(long long *)0xfffffffff2d8&#xA;&#xA;Old value = 0&#xA;New value = 187649984565920&#xA;0x0000aaaaaaaa1358 in initialize_framebuffer ()&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;我们看到一个我们还没探索过的新函数：&lt;code&gt;initialize_framebuffer&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;p&gt;在 iaito 中打开这个函数：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;initialize\\_framebuffer 函数的图形&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;307px&#34; data-flex-grow=&#34;128&#34; height=&#34;1384&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://rebel1725.codeberg.page/images/pic_20260527_002.png&#34; srcset=&#34;https://rebel1725.codeberg.page/blog/pic_20260527_002_13426986448128896865_hu_fb155b3819e1ebd9.png 800w, https://rebel1725.codeberg.page/blog/pic_20260527_002_13426986448128896865_hu_e17bb86b69c42559.png 1600w, https://rebel1725.codeberg.page/images/pic_20260527_002.png 1775w&#34; width=&#34;1775&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;我们可以看到，&lt;code&gt;0x00001354&lt;/code&gt; 处的一条指令把 &lt;code&gt;malloc&lt;/code&gt; 分配出来的内存地址写入了变量。不过它被表示为 &lt;code&gt;[x22, 0x10]&lt;/code&gt;。我们来检查一下 &lt;code&gt;x22&lt;/code&gt; 的内容：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;(gdb) info registers $x22&#xA;x22            0xfffffffff2c8      281474976707272&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;0xfffffffff2c8 + 0x10 = 0xfffffffff2d8&lt;/code&gt;。这正好就是 &lt;code&gt;var_48h&lt;/code&gt; 的地址。&lt;/p&gt;&#xA;&lt;p&gt;此外，传给 &lt;code&gt;malloc&lt;/code&gt; 的大小也很有意思。它是通过把偏移 6 和 7 处的值相乘，再把结果乘以 &lt;code&gt;w1&lt;/code&gt; 得到的，而 &lt;code&gt;w1&lt;/code&gt; 是 &lt;code&gt;0x18&lt;/code&gt;（24），最后再加上 &lt;code&gt;x0&lt;/code&gt;，即 1。&lt;/p&gt;&#xA;&lt;p&gt;我们也来查看这些偏移处的值：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;(gdb) x/1xb 0xfffffffff2ce&#xA;0xfffffffff2ce: 0x0a&#xA;(gdb) x/1xb 0xfffffffff2cf&#xA;0xfffffffff2cf: 0x0a&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;两个都是 10。它们看起来就是我们之前指定的图像宽度和高度。让我们通过设置硬件观察点来验证一下。由于 AArch64 需要对齐，我们把硬件观察点设在 &lt;code&gt;0xfffffffff2cc&lt;/code&gt;：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;(gdb) watch *(unsigned int *)0xfffffffff2cc&#xA;Hardware watchpoint 1: *(unsigned int *)0xfffffffff2cc&#xA;(gdb) run&#xA;Starting program: /home/user/challenge ./example.cimg&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;跳过 GNU C Library 的触发：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-Hardware&#34; data-lang=&#34;Hardware&#34;&gt;&#xA;Old value = 0&#xA;New value = 65535&#xA;0x0000fffff7fccd08 in ?? () from /lib/ld-linux-aarch64.so.1&#xA;(gdb) continue&#xA;Continuing.&#xA;&#xA;Hardware watchpoint 1: *(unsigned int *)0xfffffffff2cc&#xA;&#xA;Old value = 65535&#xA;New value = 0&#xA;0x0000fffff7fd5668 in ?? () from /lib/ld-linux-aarch64.so.1&#xA;(gdb) continue&#xA;Continuing.&#xA;[Thread debugging using libthread_db library &amp;#34;/lib/aarch64-linux-gnu/libthread_db.so.1&amp;#34;]&#xA;&#xA;Hardware watchpoint 1: *(unsigned int *)0xfffffffff2cc&#xA;&#xA;Old value = 0&#xA;New value = 65535&#xA;0x0000fffff7fcc3a4 in ?? () from /lib/ld-linux-aarch64.so.1&#xA;(gdb) continue&#xA;Continuing.&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这里我们看到内存在 &lt;code&gt;0x00000c54&lt;/code&gt; 处被清零了：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Hardware watchpoint 1: *(unsigned int *)0xfffffffff2cc&#xA;&#xA;Old value = 65535&#xA;New value = 0&#xA;0x0000aaaaaaaa0c58 in main ()&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;我们看到一个 &lt;code&gt;stp xzr, xzr, [buf]&lt;/code&gt;。从上面的 &lt;code&gt;afv&lt;/code&gt; 我们知道 &lt;code&gt;buf&lt;/code&gt; 距离栈指针是 &lt;code&gt;0x38&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;p&gt;在 &lt;code&gt;0x00000cb8&lt;/code&gt; 处，我们可以看到一个从 &lt;code&gt;buf&lt;/code&gt; 读取的 &lt;code&gt;ldr&lt;/code&gt;，然后是魔数检查。&lt;/p&gt;&#xA;&lt;p&gt;在 &lt;code&gt;0x00000c9c&lt;/code&gt; 处，我们可以看到一些有意思的内容：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;0x00000c9c      add      x21,    sp,     0x38&#xA;0x00000ca0      mov      x2,     8                          ; size_t nbyte&#xA;0x00000ca4      mov      x1,     x21                        ; void *buf&#xA;0x00000ca8      mov      w0,     0&#xA;0x00000cac      bl       sym.imp.read                       ; ssize_t read(int fildes, void *buf, size_t nbyte)&#xA;; ssize_t read(0, 0x0000000000000000, 0x00000000)&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;因此我们已经确认，这些偏移处的两个值就是宽度和高度。&lt;/p&gt;&#xA;&lt;p&gt;回到 iaito 和 GDB 中的 &lt;code&gt;initialize_framebuffer&lt;/code&gt; 函数。设置一个观察点并检查内存：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;(gdb) break *0xaaaaaaaa1354&#xA;Breakpoint 1 at 0xaaaaaaaa1354&#xA;(gdb) run&#xA;Starting program: /home/user/challenge ./example.cimg&#xA;[Thread debugging using libthread_db library &amp;#34;/lib/aarch64-linux-gnu/libthread_db.so.1].&#xA;&#xA;Breakpoint 1, 0x0000aaaaaaaa1354 in initialize_framebuffer ()&#xA;(gdb) info registers x0&#xA;x0             0xaaaaaaac12a0      187649984565920&#xA;(gdb) watch *(char *)0xaaaaaaac12a0&#xA;Hardware watchpoint 2: *(char *)0xaaaaaaac12a0&#xA;(gdb) continue&#xA;Continuing.&#xA;&#xA;Hardware watchpoint 2: *(char *)0xaaaaaaac12a0&#xA;&#xA;Old value = 0 &amp;#39;\000&amp;#39;&#xA;New value = 27 &amp;#39;\033&amp;#39;&#xA;0x0000aaaaaaaa13bc in initialize_framebuffer ()&#xA;(gdb) x/24xb 0xaaaaaaac12a0&#xA;0xaaaaaaac12a0: 0x1b    0x5b    0x33    0x38    0x3b    0x32    0x3b    0x32&#xA;0xaaaaaaac12a8: 0x35    0x35    0x3b    0x32    0x35    0x35    0x3b    0x32&#xA;0xaaaaaaac12b0: 0x00    0x00    0x00    0x00    0x00    0x00    0x00    0x00&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;把它和上面的数据对比一下：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;(gdb) x/24xb $x0&#xA;0xaaaaaaac12a0: 0x1b    0x5b    0x33    0x38    0x3b    0x32    0x3b    0x30&#xA;0xaaaaaaac12a8: 0x38    0x30    0x3b    0x30    0x38    0x30    0x3b    0x30&#xA;0xaaaaaaac12b0: 0x38    0x30    0x6d    0x50    0x1b    0x5b    0x30    0x6d&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;0xaaaaaaac12a7&lt;/code&gt; 是第一个不同的字节。我们可以对它设置观察点：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;(gdb) watch *(char *)0xaaaaaaac12a7&#xA;Hardware watchpoint 3: *(char *)0xaaaaaaac12a7&#xA;(gdb) continue&#xA;Continuing.&#xA;&#xA;Hardware watchpoint 3: *(char *)0xaaaaaaac12a7&#xA;&#xA;Old value = 50 &amp;#39;2&amp;#39;&#xA;New value = 48 &amp;#39;0&amp;#39;&#xA;0x0000aaaaaaaa128c in display ()&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;出现了一个新的函数需要探索。在 iaito 中打开它。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;initialize\\_framebuffer 函数的图形&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;111px&#34; data-flex-grow=&#34;46&#34; height=&#34;2426&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://rebel1725.codeberg.page/images/pic_20260527_003.png&#34; srcset=&#34;https://rebel1725.codeberg.page/blog/pic_20260527_003_2825852626928846418_hu_16b0800f65d74b2e.png 800w, https://rebel1725.codeberg.page/images/pic_20260527_003.png 1129w&#34; width=&#34;1129&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;我们可以看到，数据变化发生在 &lt;code&gt;0x00001288&lt;/code&gt;，是一条 &lt;code&gt;stp&lt;/code&gt; 指令。&lt;code&gt;0x0000128c&lt;/code&gt; 处的 &lt;code&gt;str&lt;/code&gt; 指令也很有意思；我们来看看这里的内存：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;(gdb) x/24xb 0xaaaaaaac12a0&#xA;0xaaaaaaac12a0: 0x1b    0x5b    0x33    0x38    0x3b    0x32    0x3b    0x30&#xA;0xaaaaaaac12a8: 0x38    0x30    0x3b    0x30    0x38    0x30    0x3b    0x30&#xA;0xaaaaaaac12b0: 0x35    0x35    0x6d    0x20    0x1b    0x5b    0x30    0x6d&#xA;(gdb) si&#xA;0x0000aaaaaaaa1290 in display ()&#xA;(gdb) x/24xb 0xaaaaaaac12a0&#xA;0xaaaaaaac12a0: 0x1b    0x5b    0x33    0x38    0x3b    0x32    0x3b    0x30&#xA;0xaaaaaaac12a8: 0x38    0x30    0x3b    0x30    0x38    0x30    0x3b    0x30&#xA;0xaaaaaaac12b0: 0x38    0x30    0x6d    0x50    0x1b    0x5b    0x30    0x6d&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;从 &lt;code&gt;0xaaaaaaac12b0&lt;/code&gt; 开始的 8 字节块已经被 &lt;code&gt;str&lt;/code&gt; 指令改写了。寄存器说明了一切：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;(gdb) info registers x2&#xA;x2             0xaaaaaaac12a0      187649984565920&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;我们不必太在意 &lt;code&gt;x2&lt;/code&gt;。重点关注 &lt;code&gt;x4&lt;/code&gt;、&lt;code&gt;x5&lt;/code&gt; 和 &lt;code&gt;x1&lt;/code&gt;。在 &lt;code&gt;0x00001268&lt;/code&gt; 和 &lt;code&gt;0x00001270&lt;/code&gt; 处，我们看到一个非常重要的寄存器 &lt;code&gt;x25&lt;/code&gt;。它保存着一块内存的地址，而这块内存里装着将要写入 &lt;code&gt;x2&lt;/code&gt; 指向内存的数据。检查这块内存：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;(gdb) x/24xb $x25&#xA;0xfffffffff270: 0x1b    0x5b    0x33    0x38    0x3b    0x32    0x3b    0x30&#xA;0xfffffffff278: 0x38    0x30    0x3b    0x30    0x38    0x30    0x3b    0x30&#xA;0xfffffffff280: 0x38    0x30    0x6d    0x50    0x1b    0x5b    0x30    0x6d&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;在 &lt;code&gt;0x00001238&lt;/code&gt; 处，&lt;code&gt;x25&lt;/code&gt; 中的地址被复制到 &lt;code&gt;x0&lt;/code&gt;。然后，后面的几个寄存器被填入相应的数据。接着调用了 &lt;code&gt;snprintf&lt;/code&gt;。&lt;code&gt;snprintf&lt;/code&gt; 会把格式化输出写入字符数组：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;int snprintf(char *str, size_t size, const char *format, ...);&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;它会把格式化字符串写到 &lt;code&gt;x25&lt;/code&gt; 所指向的内存中。重新启动 GDB，并检查 &lt;code&gt;x2&lt;/code&gt; 指向的内存：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;(gdb) break *0xaaaaaaaa1258&#xA;Breakpoint 1 at 0xaaaaaaaa1258&#xA;(gdb) run&#xA;Starting program: /home/user/challenge ./example.cimg&#xA;[Thread debugging using libthread_db library &amp;#34;/lib/aarch64-linux-gnu/libthread_db.so.1].&#xA;&#xA;Breakpoint 1, 0x0000aaaaaaaa1258 in display ()&#xA;(gdb) x/s $x2&#xA;0xaaaaaaaa1510: &amp;#34;\033[38;2;%03d;%03d;%03dm%c\033[0m&amp;#34;&#xA;(gdb) x/29xb $x2&#xA;0xaaaaaaaa1510: 0x1b    0x5b    0x33    0x38    0x3b    0x32    0x3b    0x25&#xA;0xaaaaaaaa1518: 0x30    0x33    0x64    0x3b    0x25    0x30    0x33    0x64&#xA;0xaaaaaaaa1520: 0x3b    0x25    0x30    0x33    0x64    0x6d    0x25    0x63&#xA;0xaaaaaaaa1528: 0x1b    0x5b    0x30    0x6d    0x00&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这就是格式字符串。如果你对 &lt;code&gt;x/s&lt;/code&gt; 返回的字符串不太放心，可以用 Python 逐字节打印这个字符串：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; print(b&amp;#34;\x1b\x5b\x33\x38\x3b\x32\x3b\x25\x30\x33\x64\x3b\x25\x30\x33\x64\x3\&#xA;b\x25\x30\x33\x64\x6d\x25\x63\x1b\x5b\x30\x6d\x00&amp;#34;)&#xA;b&amp;#39;\x1b[38;2;%03d;%03d;%03dm%c\x1b[0m\x00&amp;#39;&#xA;&amp;gt;&amp;gt;&amp;gt; blob = b&amp;#39;\x1b[38;2;%03d;%03d;%03dm%c\x1b[0m\x00&amp;#39;&#xA;&amp;gt;&amp;gt;&amp;gt; for i1 in range(len(blob)):&#xA;...     blob[i1:i1+1]&#xA;...     &#xA;b&amp;#39;\x1b&amp;#39;&#xA;b&amp;#39;[&amp;#39;&#xA;b&amp;#39;3&amp;#39;&#xA;b&amp;#39;8&amp;#39;&#xA;b&amp;#39;;&amp;#39;&#xA;b&amp;#39;2&amp;#39;&#xA;b&amp;#39;;&amp;#39;&#xA;b&amp;#39;%&amp;#39;&#xA;b&amp;#39;0&amp;#39;&#xA;b&amp;#39;3&amp;#39;&#xA;b&amp;#39;d&amp;#39;&#xA;b&amp;#39;;&amp;#39;&#xA;b&amp;#39;%&amp;#39;&#xA;b&amp;#39;0&amp;#39;&#xA;b&amp;#39;3&amp;#39;&#xA;b&amp;#39;d&amp;#39;&#xA;b&amp;#39;;&amp;#39;&#xA;b&amp;#39;%&amp;#39;&#xA;b&amp;#39;0&amp;#39;&#xA;b&amp;#39;3&amp;#39;&#xA;b&amp;#39;d&amp;#39;&#xA;b&amp;#39;m&amp;#39;&#xA;b&amp;#39;%&amp;#39;&#xA;b&amp;#39;c&amp;#39;&#xA;b&amp;#39;\x1b&amp;#39;&#xA;b&amp;#39;[&amp;#39;&#xA;b&amp;#39;0&amp;#39;&#xA;b&amp;#39;m&amp;#39;&#xA;b&amp;#39;\x00&amp;#39;&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这个格式字符串有四个占位符。前三个是 &lt;code&gt;%03d&lt;/code&gt;，它会把整数格式化为至少三位的十进制字符串（例如 7 会变成 &lt;code&gt;007&lt;/code&gt;，15 会变成 &lt;code&gt;015&lt;/code&gt;）。最后一个是 &lt;code&gt;%c&lt;/code&gt;，它只匹配一个字符。&lt;/p&gt;&#xA;&lt;p&gt;现在我们有了这个字节模式：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;0x1b    0x5b    0x33    0x38    0x3b    0x32    0x3b    [N1]&#xA;[N1]    [N1]    0x3b    [N2]    [N2]    [N2]    0x3b    [N3]&#xA;[N3]    [N3]    0x6d    [CH]    0x1b    0x5b    0x30    0x6d&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;现在我们可以检查这些占位符究竟填入了什么：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;(gdb) info registers x3 x4 x5 x6&#xA;x3             0x50                80&#xA;x4             0x50                80&#xA;x5             0x50                80&#xA;x6             0x50                80&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;它们全都是 &lt;code&gt;0x50&lt;/code&gt;，看起来就是我们在示例 cIMG 中使用的数据。现在我们重建这个 cIMG，让这一点更清楚：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; with open(&amp;#34;example.cimg&amp;#34;, &amp;#34;wb&amp;#34;) as file:&#xA;...     file.write(b&amp;#34;cIMG\x02\0\x0a\x0a\x12\x34\x56\x78&amp;#34;)&#xA;...     file.write(b&amp;#34;\x50&amp;#34;*(10*10*4-4))&#xA;...     &#xA;12&#xA;396&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;(gdb) break *0xaaaaaaaa1258&#xA;Breakpoint 1 at 0xaaaaaaaa1258&#xA;(gdb) run&#xA;Starting program: /home/user/challenge ./example.cimg&#xA;[Thread debugging using libthread_db library &amp;#34;/lib/aarch64-linux-gnu/libthread_db.so.1].&#xA;&#xA;Breakpoint 1, 0x0000aaaaaaaa1258 in display ()&#xA;(gdb) info registers x3 x4 x5 x6&#xA;x3             0x12                18&#xA;x4             0x34                52&#xA;x5             0x56                86&#xA;x6             0x78                120&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;因此，上面十六进制模式中的 N1、N2 和 N3 分别对应 R、G 和 B，而 CH 就是我们要填入的字符。&lt;/p&gt;&#xA;&lt;p&gt;现在我们可以回到 GDB，在每个 &lt;code&gt;memcmp&lt;/code&gt; 之前设置断点，运行 &lt;code&gt;x/24xb $x1&lt;/code&gt; 来找出期望的 framebuffer，然后利用这些 framebuffer 还原出期望的 cIMG 数据。接着用十六进制编辑器把数据填进去。&lt;/p&gt;&#xA;&lt;h2 id=&#34;大小检查&#34;&gt;大小检查&#xA;&lt;/h2&gt;&lt;p&gt;然而，在填入期望数据之后，可执行程序仍然没有给出 flag。用 GDB 检查内存之后，我们可以知道这些 &lt;code&gt;memcmp&lt;/code&gt; 的返回值都如预期那样是零。因此，应该还有别的条件没有满足。&lt;/p&gt;&#xA;&lt;p&gt;回到 iaito，从第一个 &lt;code&gt;memcmp&lt;/code&gt; 往回滚动。我们可以看到在 &lt;code&gt;0x00000d60&lt;/code&gt; 处有一个 &lt;code&gt;cmp&lt;/code&gt;，它把 &lt;code&gt;var_40h&lt;/code&gt; 与 4 进行比较。在 &lt;code&gt;initialize_framebuffer&lt;/code&gt; 中的 &lt;code&gt;0x00001348&lt;/code&gt; 处，我们可以找到一个 &lt;code&gt;str&lt;/code&gt;，它保存了宽度与高度的乘积。&lt;/p&gt;&#xA;&lt;p&gt;随后 &lt;code&gt;0x00000d60&lt;/code&gt; 处的 &lt;code&gt;cmp&lt;/code&gt; 决定 &lt;code&gt;w0&lt;/code&gt; 的值。如果 &lt;code&gt;var_40h&lt;/code&gt; 等于 4，那么 &lt;code&gt;w0&lt;/code&gt; 将变成 1，否则变成 0。&lt;/p&gt;&#xA;&lt;p&gt;在 &lt;code&gt;0x00000d78&lt;/code&gt; 处，&lt;code&gt;w0&lt;/code&gt; 与 0 比较，这会影响 &lt;code&gt;0x00000d84&lt;/code&gt; 处 &lt;code&gt;ccmp&lt;/code&gt; 指令的行为。&lt;code&gt;[x22, 0x13]&lt;/code&gt; 的内容被载入到 &lt;code&gt;w0&lt;/code&gt;，而 &lt;code&gt;[x1, 0x13]&lt;/code&gt; 被载入到 &lt;code&gt;w2&lt;/code&gt;。根据 &lt;code&gt;memcmp&lt;/code&gt;，我们很容易知道 &lt;code&gt;x22&lt;/code&gt; 是实际 framebuffer 的地址，而 &lt;code&gt;x1&lt;/code&gt; 是期望 framebuffer 的地址。既然我们已经让数据与期望值一致，并且偏移 19 处是一个 ASCII 字符，那么 &lt;code&gt;w0&lt;/code&gt; 和 &lt;code&gt;w2&lt;/code&gt; 应该相同，而且都不应为零。&lt;/p&gt;&#xA;&lt;p&gt;因此我们可以得出结论：如果 &lt;code&gt;var_40h&lt;/code&gt; 等于 4，那么 &lt;code&gt;w2&lt;/code&gt; 会与 &lt;code&gt;w0&lt;/code&gt; 比较，这会把 &lt;code&gt;w19&lt;/code&gt; 设为 1。否则，&lt;code&gt;w2&lt;/code&gt; 会与 0 比较，从而把 &lt;code&gt;w19&lt;/code&gt; 置零。&lt;/p&gt;&#xA;&lt;p&gt;在第一次 &lt;code&gt;memcmp&lt;/code&gt; 之后，因为 &lt;code&gt;0x00000e7c&lt;/code&gt; 处 &lt;code&gt;w0&lt;/code&gt; 等于 0，所以 &lt;code&gt;w19&lt;/code&gt; 会与 0 比较。然后 &lt;code&gt;cset&lt;/code&gt; 会在不相等时把 &lt;code&gt;w19&lt;/code&gt; 设为 1，否则设为 0。&lt;/p&gt;&#xA;&lt;p&gt;现在用十六进制编辑器修改 cIMG，把宽度和高度改成乘积为 4 的值。例如，我们可以设为 &lt;code&gt;0202&lt;/code&gt;。这样可执行程序就应该会给出 flag。&lt;/p&gt;&#xA;&lt;h2 id=&#34;结论&#34;&gt;结论&#xA;&lt;/h2&gt;&lt;p&gt;上面的过程包括：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;使用 radare2 和 iaito 进行静态分析；&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;使用 GDB 进行动态分析，其中包括：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;篡改控制流；&lt;/li&gt;&#xA;&lt;li&gt;检查内存；&lt;/li&gt;&#xA;&lt;li&gt;检查整数值。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;这就是逆向工程中非常典型的一套流程。&lt;/p&gt;&#xA;&lt;p&gt;顺带一提，逆向这个可执行程序可能还有别的方法。不过无论采用哪种方法，通常都会同时涉及静态分析和动态分析。&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>逆向工程简介</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/a-brief-introduction-into-reverse-engineering/</link>
            <pubDate>Sat, 16 May 2026 19:37:05 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/a-brief-introduction-into-reverse-engineering/</guid>
            <description>&lt;p&gt;在过去的几周里，我一直在学习 x86_64 汇编、AArch64 汇编，以及各种基础知识。最近，我终于第一次接触了逆向工程。我很高兴能分享更多关于这次经历的细节。&lt;/p&gt;&#xA;&lt;h2 id=&#34;什么是逆向工程&#34;&gt;什么是逆向工程&#xA;&lt;/h2&gt;&lt;p&gt;计算机实际上是一种相当愚笨的机器。它不会自己解决任何问题；它只会执行解决方案——更准确地说，它只会按顺序逐条执行来自人类的指令。要用这样的机器解决问题，我们通常会：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;分析一个 &lt;em&gt;问题&lt;/em&gt;；&lt;/li&gt;&#xA;&lt;li&gt;为这个问题找到一个 &lt;em&gt;解决方案&lt;/em&gt;；&lt;/li&gt;&#xA;&lt;li&gt;通过设计一个 &lt;em&gt;算法&lt;/em&gt; 来实现这个解决方案；&lt;/li&gt;&#xA;&lt;li&gt;通过编写 &lt;em&gt;代码&lt;/em&gt; 来实现这个算法；&lt;/li&gt;&#xA;&lt;li&gt;通过编译，从代码生成 &lt;em&gt;可执行文件&lt;/em&gt;；&lt;/li&gt;&#xA;&lt;li&gt;把这个可执行文件交给那台愚笨的计算机去解决问题。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;这是一种把 &lt;em&gt;解决方案&lt;/em&gt; 转换为 &lt;em&gt;代码&lt;/em&gt;，再转换为 &lt;em&gt;指令&lt;/em&gt; 的过程。&lt;/p&gt;&#xA;&lt;p&gt;通常，我们可以通过阅读代码轻松理解一个程序做了什么。代码介于解决方案和指令之间。上世纪 70 年代，代码通常在人民之间共享，因此每个人都可以在社区中学习、改进并分享解决方案。&lt;/p&gt;&#xA;&lt;p&gt;然而，自从那些极其邪恶的专有软件开发怪物出现之后，情况就变了。它们选择剥夺人民接触 &lt;em&gt;代码&lt;/em&gt; 的权利，夺走用户对计算的控制，加入各种恶意功能来剥削用户，并采用各种手段掩盖程序究竟做了什么——也就是 &lt;em&gt;解决方案&lt;/em&gt;。它们在筑墙。它们在破坏共享。它们在制造灾难和绝望。它们所做的一切都在与人民、社区和人类作对。它们做这一切，都是为了&lt;strong&gt;它们不道德且不公正的利润&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;软件应该服务人民，而不是资本家的不道德且不公正的利润。然而，正是那些本不该存在、理应从世界上被清除的、不道德且不公正的专有软件开发者，正在让世界变得更糟。但我们不可能一下子消灭专有软件。&lt;strong&gt;我们要为此开发自由软件替代品，并逐步重新夺回对计算的控制。&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;因此，现在该把上面的过程倒过来做了。换句话说，我们：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;分析 &lt;em&gt;可执行文件&lt;/em&gt;；&lt;/li&gt;&#xA;&lt;li&gt;尝试恢复该可执行文件所执行的 &lt;em&gt;代码&lt;/em&gt;；&lt;/li&gt;&#xA;&lt;li&gt;找出这段代码实现的 &lt;em&gt;算法&lt;/em&gt;；&lt;/li&gt;&#xA;&lt;li&gt;反推出该算法所实现的 &lt;em&gt;解决方案&lt;/em&gt;；&lt;/li&gt;&#xA;&lt;li&gt;重新实现这个解决方案来解决 &lt;em&gt;问题&lt;/em&gt;。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;这就是把 &lt;em&gt;指令&lt;/em&gt; 转换为 &lt;em&gt;代码&lt;/em&gt;，再转换为 &lt;em&gt;解决方案&lt;/em&gt;。&lt;/p&gt;&#xA;&lt;p&gt;以相反顺序做这件事的实践，就是&lt;strong&gt;逆向工程&lt;/strong&gt;，简称 &lt;strong&gt;RE&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;h2 id=&#34;为什么逆向工程很重要&#34;&gt;为什么逆向工程很重要&#xA;&lt;/h2&gt;&lt;p&gt;逆向工程之所以重要，最主要的原因是它能帮助我们将&lt;strong&gt;自由软件操作系统&lt;/strong&gt;，例如 postmarketOS 和 LineageOS，移植到各种设备上。这也是我学习逆向工程的主要原因。&lt;/p&gt;&#xA;&lt;p&gt;在桌面电脑上，实现软件自由要容易得多，因为我们通常可以运行各种自由的 GNU/Linux 发行版，而不会遇到严重问题。然而，在智能手机或平板电脑等移动设备上，情况就不是这样了。&lt;/p&gt;&#xA;&lt;p&gt;这些设备往往有许多厂商特定和设备特定的调整，要找到一种能让自由操作系统在这些设备上普遍运行的通用方案几乎是不可能的。更糟糕的是，制造商选择隐藏这些技术细节，甚至 Google 也不再发布设备树和厂商二进制 blob。因此，我们现在必须分析 &lt;em&gt;二进制&lt;/em&gt; 固件 blob，并推断其逻辑，才能让 postmarketOS、LineageOS 或其他自由软件操作系统在这些设备上运行。&lt;/p&gt;&#xA;&lt;p&gt;事实上，自由软件基金会也在通过 &lt;a class=&#34;link&#34; href=&#34;https://librephone.org/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Librephone&lt;/a&gt; 项目处理这个问题。没有逆向工程，这个项目就无法继续。&lt;/p&gt;&#xA;&lt;p&gt;不过，逆向工程的应用绝不仅限于自由操作系统移植。它在以下方面也非常重要：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;弄清专有协议的细节，&lt;/li&gt;&#xA;&lt;li&gt;找出专有软件中存在恶意功能的证据，&lt;/li&gt;&#xA;&lt;li&gt;绕过数字限制管理，&lt;/li&gt;&#xA;&lt;li&gt;以及更多其他用途。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;如何进行逆向工程&#34;&gt;如何进行逆向工程&#xA;&lt;/h2&gt;&lt;p&gt;典型的逆向工程包含这两个步骤：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;将可执行文件转换为汇编；这个过程叫做 &lt;em&gt;反汇编&lt;/em&gt;。&lt;/li&gt;&#xA;&lt;li&gt;通过阅读汇编代码，尝试恢复思路，或者重写等价代码。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;我们可以直接对可执行文件进行这项工作，而不运行它，这叫做 &lt;em&gt;静态分析&lt;/em&gt;；也可以在它运行时进行，这叫做 &lt;em&gt;动态分析&lt;/em&gt;。&lt;/p&gt;&#xA;&lt;h2 id=&#34;静态分析示例&#34;&gt;静态分析示例&#xA;&lt;/h2&gt;&lt;p&gt;来看这个例子：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;&#xA;#include &amp;lt;string.h&amp;gt;&#xA;&#xA;const char *PASS = &amp;#34;weakpasswd&amp;#34;;&#xA;&#xA;int main()&#xA;{&#xA;    char buf[64];&#xA;    for (int i = 0; i &amp;lt; 3; i++)&#xA;    {&#xA;        printf(&amp;#34;%d retries remaining.\nPassword: &amp;#34;, 3 - i);&#xA;        fgets(buf, sizeof buf, stdin);&#xA;        if (strncmp(PASS, buf, strlen(PASS)))&#xA;            puts(&amp;#34;Wrong password!\n&amp;#34;);&#xA;        else&#xA;        {&#xA;            puts(&amp;#34;Correct!\nWelcome to the world &amp;#34;&#xA;                 &amp;#34;of reverse engineering!\n&amp;#34;);&#xA;            break;&#xA;        }&#xA;    }&#xA;    return 0;&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;用 GCC 编译它：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ gcc -o ./demo ./demo.c&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;在 radare2 中打开可执行文件：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ r2 ./demo&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;你会看到：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[0x00000800]&amp;gt; &#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;让我们分析这个可执行文件：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[0x00000800]&amp;gt; aaa&#xA;INFO: Analyze all flags starting with sym. and entry0 (aa)&#xA;INFO: Analyze imports (af@@@i)&#xA;INFO: Analyze entrypoint (af@ entry0)&#xA;INFO: Analyze symbols (af@@@s)&#xA;INFO: Analyze all functions arguments/locals (afva@@F)&#xA;INFO: Analyze function calls (aac)&#xA;INFO: Analyze len bytes of instructions for references (aar)&#xA;INFO: Finding and parsing C++ vtables (avrr)&#xA;INFO: Analyzing methods (af @@ method.*)&#xA;INFO: Finding function preludes (aap)&#xA;INFO: Emulating functions to find computed references (aaef)&#xA;INFO: Recovering local variables (afva@@@F)&#xA;INFO: Type matching analysis for all functions (afft)&#xA;INFO: Propagate noreturn information (aanr)&#xA;INFO: Use -AA or aaaa to perform additional experimental analysis&#xA;INFO: Finding xrefs in noncode sections (e anal.in=io.maps.x; aav)&#xA;WARN: Skipping aav because base address is zero. Use -B 0x800000 or aav0&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;列出函数：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[0x00000800]&amp;gt; afl&#xA;0x00000750    1     16 sym.imp.strlen&#xA;0x00000760    1     16 sym.imp.__libc_start_main&#xA;0x00000770    1     16 sym.imp.__cxa_finalize&#xA;0x00000780    1     32 sym.imp.strncmp&#xA;0x000007a0    1     16 sym.imp.abort&#xA;0x000007b0    1     16 sym.imp.puts&#xA;0x000007c0    1     16 sym.imp.printf&#xA;0x000007d0    1     20 sym.imp.fgets&#xA;0x00000800    1     48 entry0&#xA;0x00000834    3     20 sym.call_weak_fn&#xA;0x00000860    4     48 sym.deregister_tm_clones&#xA;0x00000890    4     60 sym.register_tm_clones&#xA;0x000008cc    5     80 entry.fini0&#xA;0x00000920    1      8 entry.init0&#xA;0x000009f8    1     24 sym._fini&#xA;0x00000928    7    208 main&#xA;0x00000708    1     28 sym._init&#xA;0x00000730    1     32 fcn.00000730&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;现在我们进入 &lt;code&gt;main&lt;/code&gt; 函数并打印反汇编代码：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[0x00000800]&amp;gt; s main&#xA;[0x00000928]&amp;gt; pdf&#xA;            ; DATA XREF from entry0 @ 0x820(r)&#xA;            ; DATA XREF from entry.fini0 @ 0x8e0(r)&#xA;┌ 208: int main (int argc);&#xA;│ `- args(x0) vars(5:sp[0x4..0x70])&#xA;│           0x00000928      fd7bb9a9       stp x29, x30, [sp, -0x70]!&#xA;│           0x0000092c      fd030091       mov x29, sp&#xA;│           0x00000930      f30b00f9       str x19, [var_10h]&#xA;│           0x00000934      ff6f00b9       str wzr, [var_6ch]          ; argc&#xA;│       ┌─&amp;lt; 0x00000938      29000014       b 0x9dc&#xA;│       │   ; CODE XREF from main @ 0x9e4(x)&#xA;│      ┌──&amp;gt; 0x0000093c      61008052       mov w1, 3&#xA;│      ╎│   0x00000940      e06f40b9       ldr w0, [var_6ch]&#xA;│      ╎│   0x00000944      2000004b       sub w0, w1, w0&#xA;│      ╎│   0x00000948      e103002a       mov w1, w0&#xA;│      ╎│   0x0000094c      00000090       adrp x0, 0&#xA;│      ╎│   0x00000950      00a02891       add x0, x0, str._d_retries_remaining._nPassword: ; 0xa28 ; &amp;#34;%d retries remaining.\nPassword: &amp;#34; ; const char *format&#xA;│      ╎│   0x00000954      9bffff97       bl sym.imp.printf           ; int printf(const char *format)&#xA;│      ╎│   0x00000958      e00000f0       adrp x0, 0x1f000&#xA;│      ╎│   0x0000095c      00e447f9       ldr x0, [x0, 0xfc8]         ; [0x1ffc8:4]=0&#xA;│      ╎│                                                              ; reloc.stdin&#xA;│      ╎│   0x00000960      010040f9       ldr x1, [x0]                ; int size&#xA;│      ╎│   0x00000964      e0a30091       add x0, sp, 0x28            ; char *s&#xA;│      ╎│   0x00000968      e20301aa       mov x2, x1                  ; FILE *stream&#xA;│      ╎│   0x0000096c      01088052       mov w1, 0x40&#xA;│      ╎│   0x00000970      98ffff97       bl sym.imp.fgets            ; char *fgets(char *s, int size, FILE *stream)&#xA;│      ╎│   0x00000974      00010090       adrp x0, reloc.strlen       ; 0x20000&#xA;│      ╎│   0x00000978      00600191       add x0, x0, 0x58&#xA;│      ╎│   0x0000097c      130040f9       ldr x19, [x0]               ; [0xa18:4]=0x6b616577 ; &amp;#34;weakpasswd&amp;#34;&#xA;│      ╎│   0x00000980      00010090       adrp x0, reloc.strlen       ; 0x20000&#xA;│      ╎│   0x00000984      00600191       add x0, x0, 0x58&#xA;│      ╎│   0x00000988      000040f9       ldr x0, [x0]                ; [0xa18:4]=0x6b616577 ; &amp;#34;weakpasswd&amp;#34; ; const char *s&#xA;│      ╎│   0x0000098c      71ffff97       bl sym.imp.strlen           ; size_t strlen(const char *s)&#xA;│      ╎│   0x00000990      e10300aa       mov x1, x0&#xA;│      ╎│   0x00000994      e0a30091       add x0, sp, 0x28&#xA;│      ╎│   0x00000998      e20301aa       mov x2, x1                  ; size_t n&#xA;│      ╎│   0x0000099c      e10300aa       mov x1, x0                  ; const char *s2&#xA;│      ╎│   0x000009a0      e00313aa       mov x0, x19                 ; const char *s1&#xA;│      ╎│   0x000009a4      77ffff97       bl sym.imp.strncmp          ; int strncmp(const char *s1, const char *s2, size_t n)&#xA;│      ╎│   0x000009a8      1f000071       cmp w0, 0&#xA;│     ┌───&amp;lt; 0x000009ac      a0000054       b.eq 0x9c0&#xA;│     │╎│   0x000009b0      00000090       adrp x0, 0&#xA;│     │╎│   0x000009b4      00402991       add x0, x0, str.Wrong_password__n ; 0xa50 ; &amp;#34;Wrong password!\n&amp;#34; ; const char *s&#xA;│     │╎│   0x000009b8      7effff97       bl sym.imp.puts             ; int puts(const char *s)&#xA;│    ┌────&amp;lt; 0x000009bc      05000014       b 0x9d0&#xA;│    ││╎│   ; CODE XREF from main @ 0x9ac(x)&#xA;│    │└───&amp;gt; 0x000009c0      00000090       adrp x0, 0&#xA;│    │ ╎│   0x000009c4      00a02991       add x0, x0, str.Correct__nWelcome_to_the_world_of_reverse_engineering__n ; 0xa68 ; &amp;#34;Correct!\nWelcome to the world of reverse engineering!\n&amp;#34; ; const char *s&#xA;│    │ ╎│   0x000009c8      7affff97       bl sym.imp.puts             ; int puts(const char *s)&#xA;│    │┌───&amp;lt; 0x000009cc      07000014       b 0x9e8&#xA;│    ││╎│   ; CODE XREF from main @ 0x9bc(x)&#xA;│    └────&amp;gt; 0x000009d0      e06f40b9       ldr w0, [var_6ch]&#xA;│     │╎│   0x000009d4      00040011       add w0, w0, 1&#xA;│     │╎│   0x000009d8      e06f00b9       str w0, [var_6ch]&#xA;│     │╎│   ; CODE XREF from main @ 0x938(x)&#xA;│     │╎└─&amp;gt; 0x000009dc      e06f40b9       ldr w0, [var_6ch]&#xA;│     │╎    0x000009e0      1f080071       cmp w0, 2&#xA;│     │└──&amp;lt; 0x000009e4      cdfaff54       b.le 0x93c&#xA;│     │     ; CODE XREF from main @ 0x9cc(x)&#xA;│     └───&amp;gt; 0x000009e8      00008052       mov w0, 0&#xA;│           0x000009ec      f30b40f9       ldr x19, [var_10h]&#xA;│           0x000009f0      fd7bc7a8       ldp x29, x30, [sp], 0x70&#xA;└           0x000009f4      c0035fd6       ret&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Radare2 不仅会给出汇编代码，还会给出每条指令对应的地址，以及它们之间的调用关系。&lt;/p&gt;&#xA;&lt;p&gt;不过现在看起来还是不够清楚。所以我们把反汇编以图形方式显示出来：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[0x00000928]&amp;gt; VV&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;你现在会看到：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;radare2 反汇编图形视图&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;160px&#34; data-flex-grow=&#34;66&#34; height=&#34;2358&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://rebel1725.codeberg.page/images/pic_20260516_001.png&#34; srcset=&#34;https://rebel1725.codeberg.page/blog/pic_20260516_001_8405216816178737815_hu_4b67f1e8a3465507.png 800w, https://rebel1725.codeberg.page/images/pic_20260516_001.png 1572w&#34; width=&#34;1572&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;在这个图中，&lt;code&gt;t&lt;/code&gt; 表示条件为真时跳转。&lt;code&gt;f&lt;/code&gt; 表示条件为假时跳转。&lt;code&gt;v&lt;/code&gt; 表示无条件跳转。&lt;/p&gt;&#xA;&lt;p&gt;这样一来，事情就容易多了。Radare2 已经帮我们理清了汇编代码各部分之间的逻辑关系，我们只需要理解这些汇编代码块本身即可。&lt;/p&gt;&#xA;&lt;p&gt;在图中，我们很容易在 &lt;code&gt;[0x93c]&lt;/code&gt; 区块的末尾找到密码检查逻辑：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;; int strncmp(const char *s1, const char *s2, size_t n)&#xA;bl sym.imp.strncmp&#xA;cmp w0, 0&#xA;b.eq 0x9c0&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这里调用了 &lt;code&gt;sym.imp.strncmp&lt;/code&gt;，然后检查这个函数在 &lt;code&gt;w0&lt;/code&gt; 中返回的值。如果它等于 &lt;code&gt;0&lt;/code&gt;，程序就跳转到 &lt;code&gt;[0x9c0]&lt;/code&gt; 区块，表示成功。否则，它会继续到 &lt;code&gt;[0x9b0]&lt;/code&gt; 区块，表示失败。&lt;/p&gt;&#xA;&lt;p&gt;根据 AArch64 调用约定，要比较的两个字符串指针分别位于寄存器 &lt;code&gt;x0&lt;/code&gt; 和 &lt;code&gt;x1&lt;/code&gt; 中，然后我们调用 &lt;code&gt;sym.imp.strncmp&lt;/code&gt;。结果随后存放在 &lt;code&gt;x0&lt;/code&gt; 寄存器中（&lt;code&gt;w0&lt;/code&gt; 只是 &lt;code&gt;x0&lt;/code&gt; 的低 32 位），如果两个字符串完全相同，我们得到 &lt;code&gt;0&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;p&gt;现在我们往回看：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;mov x0, x19&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;然后再往前找一条对 &lt;code&gt;x19&lt;/code&gt; 进行操作的指令：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;; [0xa18:4]=0x6b616577&#xA;; &amp;#34;weakpasswd&amp;#34;&#xA;ldr x19, [x0]&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Radare2 已经告诉了我们那个最高机密。&lt;/strong&gt; 让我们试试：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ ./demo&#xA;3 retries remaining.&#xA;Password: weakpasswd&#xA;Correct!&#xA;Welcome to the world of reverse engineering!&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;就是这样。&lt;/p&gt;&#xA;&lt;p&gt;如果我们更仔细地看这个图，还能学到比密码更多的东西。例如，我们可以在图中看到一个环：&lt;code&gt;[0x9dc]&lt;/code&gt; -&amp;gt; &lt;code&gt;[0x93c]&lt;/code&gt; -&amp;gt; &lt;code&gt;[0x9b0]&lt;/code&gt; -&amp;gt; &lt;code&gt;[0x9d0]&lt;/code&gt; -&amp;gt; &lt;code&gt;[0x9dc]&lt;/code&gt;。&lt;strong&gt;在图中，环通常表示循环控制流。这是逆向工程中非常重要的一种思维方式。&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;在 &lt;code&gt;[0x9dc]&lt;/code&gt; 区块中：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;ldr w0, [var_6ch]&#xA;cmp w0, 2&#xA;b.le 0x93c&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;它把变量 &lt;code&gt;var_6ch&lt;/code&gt; 载入寄存器，并与 &lt;code&gt;2&lt;/code&gt; 比较。如果它更大，就会进入 &lt;code&gt;[0x9e8]&lt;/code&gt; 区块并退出。否则，就会进入 &lt;code&gt;[0x93c]&lt;/code&gt; 区块。&lt;/p&gt;&#xA;&lt;p&gt;看一下 &lt;code&gt;[0x93c]&lt;/code&gt; 区块的末尾。我们已经知道，如果密码检查成功，它会跳转到 &lt;code&gt;[0x9c0]&lt;/code&gt; 区块，打印表示成功的信息，然后跳转到 &lt;code&gt;[0x9e8]&lt;/code&gt; 区块，程序在这里结束。&lt;/p&gt;&#xA;&lt;p&gt;但如果检查失败呢？它会进入 &lt;code&gt;[0x9b0]&lt;/code&gt; 区块。这里仅仅打印错误信息，所以没有什么有趣的内容；让我们跳到 &lt;code&gt;[0x9d0]&lt;/code&gt; 区块。在这里我们发现了一些有趣的东西：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;ldr w0, [var_6ch]&#xA;add w0, w0, 1&#xA;str w0, [var_6ch]&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;它把变量 &lt;code&gt;var_6ch&lt;/code&gt; 载入寄存器，将值加一，然后再把值存回去。接着它会回到 &lt;code&gt;[0x9dc]&lt;/code&gt; 区块，也就是检查 &lt;code&gt;var_6ch&lt;/code&gt; 的值。&lt;/p&gt;&#xA;&lt;p&gt;按两次 &lt;code&gt;q&lt;/code&gt; 返回提示符。运行 &lt;code&gt;afv&lt;/code&gt; 和 &lt;code&gt;afvd&lt;/code&gt; 来列出变量及其信息：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[0x000009b0]&amp;gt; afv&#xA;arg int argc @ x0&#xA;var int64_t var_70h @ sp+0x0&#xA;var int64_t var_70h_2 @ sp+0x8&#xA;var int64_t var_10h @ sp+0x10&#xA;var char * s2 @ sp+0x28&#xA;var int64_t var_6ch @ sp+0x6c&#xA;[0x000009b0]&amp;gt; afvd&#xA;arg argc = 0x00000000 0x00010102464c457f   .ELF.... @ pstate&#xA;var var_6ch = 0x0017806c = (qword)0x0000000000000000&#xA;var s2 = 0x00178028 = &amp;#34;&amp;#34;&#xA;var var_10h = 0x00178010 = (qword)0x0000000000000000&#xA;var var_70h = 0x00178000 = (qword)0x0000000000000000&#xA;var var_70h_2 = 0x00178008 = (qword)0x0000000000000000&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;我们可以看到，&lt;code&gt;var_6ch&lt;/code&gt; 的值是一个 &lt;code&gt;int64_t&lt;/code&gt;，而它的初始值是 &lt;code&gt;0&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;p&gt;现在我们可以推断，&lt;code&gt;var_6ch&lt;/code&gt; 是一个计数器。它的初始值是 0。如果密码检查失败，计数器就会加一。一旦它超过 2，程序就不再询问密码并退出。现在我们就可以看出，这对应于我们的 C 代码 &lt;code&gt;for (int i = 0; i &amp;lt; 3; i++)&lt;/code&gt;！&lt;/p&gt;&#xA;&lt;p&gt;不过，这只是一个非常简单的例子。在真实世界中，情况会更困难，因为专有软件开发者常常使用反分析和反调试技术。&lt;/p&gt;&#xA;&lt;h2 id=&#34;理解编译器优化&#34;&gt;理解编译器优化&#xA;&lt;/h2&gt;&lt;p&gt;现在，让我们编译这个更简单的代码：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;&#xA;&#xA;int main()&#xA;{&#xA;    int a;&#xA;    scanf(&amp;#34;%d&amp;#34;, &amp;amp;a);&#xA;    printf(&amp;#34;%d&amp;#34;, a % 65536);&#xA;    return 0;&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;它从输入中读取一个整数，并输出它对 65536 取模的结果。&lt;/p&gt;&#xA;&lt;p&gt;反汇编它的 &lt;code&gt;main&lt;/code&gt; 函数：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[0x00000700]&amp;gt; aaa&#xA;INFO: Analyze all flags starting with sym. and entry0 (aa)&#xA;......&#xA;WARN: Skipping aav because base address is zero. Use -B 0x800000 or aav0&#xA;[0x00000700]&amp;gt; s main&#xA;[0x00000828]&amp;gt; pdf&#xA;            ; DATA XREF from entry0 @ 0x720(r)&#xA;            ; DATA XREF from entry.fini0 @ 0x7e0(r)&#xA;┌ 76: int main (int argc, char **argv, char **envp);&#xA;│ afv: vars(3:sp[0x4..0x20])&#xA;│           0x00000828      fd7bbea9       stp x29, x30, [sp, -0x20]!&#xA;│           0x0000082c      fd030091       mov x29, sp&#xA;│           0x00000830      e0730091       add x0, sp, 0x1c&#xA;│           0x00000834      e10300aa       mov x1, x0&#xA;│           0x00000838      00000090       adrp x0, 0&#xA;│           0x0000083c      00602291       add x0, x0, 0x898&#xA;│           0x00000840      94ffff97       bl sym.imp.__isoc23_scanf&#xA;│           0x00000844      e01f40b9       ldr w0, [var_1ch]&#xA;│           0x00000848      e103006b       negs w1, w0&#xA;│           0x0000084c      003c0012       and w0, w0, 0xffff&#xA;│           0x00000850      213c0012       and w1, w1, 0xffff&#xA;│           0x00000854      0044815a       csneg w0, w0, w1, mi&#xA;│           0x00000858      e103002a       mov w1, w0&#xA;│           0x0000085c      00000090       adrp x0, 0&#xA;│           0x00000860      00602291       add x0, x0, 0x898           ; const char *format&#xA;│           0x00000864      97ffff97       bl sym.imp.printf           ; int printf(const char *format)&#xA;│           0x00000868      00008052       mov w0, 0&#xA;│           0x0000086c      fd7bc2a8       ldp x29, x30, [sp], 0x20&#xA;└           0x00000870      c0035fd6       ret&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;你可能会觉得困惑，因为这里看不到任何关于取模操作的内容（&lt;code&gt;sdiv&lt;/code&gt;、&lt;code&gt;mul&lt;/code&gt;、&lt;code&gt;sub&lt;/code&gt; 等）。相反，你看到的是：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;and w0, w0, 0xffff&#xA;and w1, w1, 0xffff&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这是因为现代编译器足够聪明，能够识别某些特殊的计算模式，并把它们优化成更简单的指令。65536 是 2^16，所以一个数对 65536 取模，实际上就是取它的最低 16 位。只需要位运算就够了，不需要加法器或乘法器。&lt;/p&gt;&#xA;&lt;p&gt;但是，如果我们把 65536 换成别的数，比如 50000，那就不是这样了：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;            ; DATA XREF from entry0 @ 0x720(r)&#xA;            ; DATA XREF from entry.fini0 @ 0x7e0(r)&#xA;┌ 80: int main (int argc, char **argv, char **envp);&#xA;│ afv: vars(3:sp[0x4..0x20])&#xA;│           0x00000828      fd7bbea9       stp x29, x30, [sp, -0x20]!&#xA;│           0x0000082c      fd030091       mov x29, sp&#xA;│           0x00000830      e0730091       add x0, sp, 0x1c&#xA;│           0x00000834      e10300aa       mov x1, x0&#xA;│           0x00000838      00000090       adrp x0, 0&#xA;│           0x0000083c      00602291       add x0, x0, 0x898&#xA;│           0x00000840      94ffff97       bl sym.imp.__isoc23_scanf&#xA;│           0x00000844      e01f40b9       ldr w0, [var_1ch]&#xA;│           0x00000848      016a9852       mov w1, 0xc350&#xA;│           0x0000084c      020cc11a       sdiv w2, w0, w1&#xA;│           0x00000850      016a9852       mov w1, 0xc350&#xA;│           0x00000854      417c011b       mul w1, w2, w1&#xA;│           0x00000858      0000014b       sub w0, w0, w1&#xA;│           0x0000085c      e103002a       mov w1, w0&#xA;│           0x00000860      00000090       adrp x0, 0&#xA;│           0x00000864      00602291       add x0, x0, 0x898           ; const char *format&#xA;│           0x00000868      96ffff97       bl sym.imp.printf           ; int printf(const char *format)&#xA;│           0x0000086c      00008052       mov w0, 0&#xA;│           0x00000870      fd7bc2a8       ldp x29, x30, [sp], 0x20&#xA;└           0x00000874      c0035fd6       ret&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;现在我们看到了 &lt;code&gt;sdiv&lt;/code&gt;、&lt;code&gt;mul&lt;/code&gt; 和 &lt;code&gt;sub&lt;/code&gt; 指令，它们组合起来完成了取模操作。&lt;/p&gt;&#xA;&lt;h2 id=&#34;那么动态分析呢&#34;&gt;那么动态分析呢？&#xA;&lt;/h2&gt;&lt;p&gt;对于动态分析，你需要 GDB。使用 GDB，你可以打印反汇编，设置断点，检查内存和寄存器，甚至在程序运行时修改寄存器和值变量。&lt;/p&gt;&#xA;&lt;p&gt;我还没有深入探索动态分析。将来我可能会写一篇新的博客文章来解释动态分析。&lt;/p&gt;&#xA;&lt;h2 id=&#34;推荐资源&#34;&gt;推荐资源&#xA;&lt;/h2&gt;&lt;p&gt;我上面解释的内容只是冰山一角。要学习逆向工程，你需要继续深入、多加练习，并在实践中学习。下面是一些推荐资源：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://pwn.college/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Pwn.college&lt;/a&gt; 是一个很好的入门地点。你可以在他们的入门 dojo 里学习 x86_64 汇编，然后继续进入 Intro to Cybersecurity 模块中的 Reverse Engineering 部分。&lt;/li&gt;&#xA;&lt;li&gt;&lt;em&gt;Reverse Engineering for Beginners&lt;/em&gt; 是一本非常好的逆向工程书籍。它是自由的（自由如自由），采用 CC BY-SA 4.0 许可，并可在&lt;a class=&#34;link&#34; href=&#34;https://github.com/Cactus-proj/RE-for-Beginners&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;这里&lt;/a&gt;下载。&lt;/li&gt;&#xA;&lt;li&gt;ARM 为其 AArch64 架构提供了&lt;a class=&#34;link&#34; href=&#34;https://www.arm.com/architecture/learn-the-architecture&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;官方文档&lt;/a&gt;。&lt;/li&gt;&#xA;&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://crackmes.one/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;这里&lt;/a&gt;可以下载 crackmes，用来练习你的逆向工程技能。&lt;/li&gt;&#xA;&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/mytechnotalent/Reverse-Engineering&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;这里&lt;/a&gt; 是一个包含许多逆向工程学习资源的 GitHub 仓库。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h2 id=&#34;免责声明&#34;&gt;免责声明&#xA;&lt;/h2&gt;&lt;p&gt;本文仅用于教育目的。请查阅你所在地区的法律，了解哪些行为是你不可以做的。本人不对你的任何行为负责。&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>Google 正在对移动自由发起又一次攻击——签署请愿并立刻阻止这一切</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/google-is-waging-another-attack-on-mobile-freedom-sign-the-petition-and-stop-this-now/</link>
            <pubDate>Tue, 12 May 2026 20:21:54 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/google-is-waging-another-attack-on-mobile-freedom-sign-the-petition-and-stop-this-now/</guid>
            <description>&lt;p&gt;Google 正在推出&lt;a class=&#34;link&#34; href=&#34;https://support.google.com/recaptcha/answer/16609652?hl=en&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;又一个充满敌意的 reCAPTCHA 版本&lt;/a&gt;，而这一次传递的信息毫不含糊：如果你想证明自己是人，就必须先向 Google 的移动生态系统低头。实际上，用户被推着用移动设备扫描二维码来完成验证。对于 Android，Google 自己的文档写明，&lt;strong&gt;这需要 Google Play 服务 25.41.30 或更高版本&lt;/strong&gt;。在 iOS 和 iPadOS 上，这个流程也&lt;strong&gt;依赖于 Google 的验证流程&lt;/strong&gt;。&lt;strong&gt;这不是进步。这是胁迫。&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;Google 再一次把一个最基本的网页交互，变成了通往专有控制的大门。结果是可以预见的：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&lt;strong&gt;使用 GrapheneOS、LineageOS、/e/、CalyxOS 以及其他自由软件 Android 发行版&lt;/strong&gt;的人被排除在外；&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;原则上拒绝 Google 服务&lt;/strong&gt;的人被排除在外；&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;处于 Google 服务不可用地区&lt;/strong&gt;的人被锁在门外；&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;没有智能手机&lt;/strong&gt;的人被当作二等用户对待。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;就连&lt;strong&gt;基于 microG 的配置也被报告在这里不可靠&lt;/strong&gt;，这让排除范围变得更大。&lt;/p&gt;&#xA;&lt;p&gt;这正是自由软件活动人士多年来一直警告的那种缓慢圈占。**公共网站不应该为了通过一个“人类验证”就要求专有的移动软件栈。**一个人不应该仅仅为了访问普通网页内容，就必须安装 Google 的服务、使用 Google 的应用，或者携带一台兼容 Google 的设备。这不是技术必需。&lt;strong&gt;这是一个政治选择，而且是一个糟糕的选择。&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;更深层的问题不只是 reCAPTCHA 变得越来越侵入。问题在于，&lt;strong&gt;Google 正在让“网页访问应当依赖厂商批准”这种想法变得正常化&lt;/strong&gt;。今天是二维码和移动验证步骤。明天就是更多设备证明、更多账号绑定、更多无声排除。GrapheneOS 已经&lt;a class=&#34;link&#34; href=&#34;https://discuss.grapheneos.org/d/35428-recaptcha-mobile-verification-is-bringing-the-play-integrity-api-to-desktops&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;表达了担忧&lt;/a&gt;，认为这种趋势不仅会延伸到手机，还会扩展到桌面环境。&lt;strong&gt;这足以让任何关心开放网络的人警惕。&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Google Play 服务和验证应用都是专有软件。&lt;strong&gt;它们不是中立的基础设施。它们是&lt;/strong&gt;把门人&lt;/strong&gt;。每当某个网站不加抗议地采用这种系统，它传递的信息都一样：给一部分人便利，让另一部分人被排除。自由软件用户、重视隐私的用户，以及处在低控制环境中的人，都在为此付出代价。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;我们不应该把这当成正常。&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;我们应该要求一种不依赖专有移动生态系统的网页验证方式。我们应该拒绝惩罚运行自由软件用户的系统。我们应该推动网站运营者使用替代方案，不要为了访问一个页面，就把人们强行推入 Google 的轨道。&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;你现在可以做什么&#34;&gt;你现在可以做什么&#xA;&lt;/h2&gt;&lt;ol&gt;&#xA;&lt;li&gt;签署&lt;a class=&#34;link&#34; href=&#34;https://framapetitions.org/petition/user/rebel1725/stop-requiring-qr-scanning-to-pass-recaptcha&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;这份请愿&lt;/a&gt;。&lt;/li&gt;&#xA;&lt;li&gt;如果你运营网站或服务，尽可能停止使用 reCAPTCHA。选择不需要 Google 移动软件栈的验证方式，例如 &lt;a class=&#34;link&#34; href=&#34;https://anubis.techaro.lol/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Anubis&lt;/a&gt;、&lt;a class=&#34;link&#34; href=&#34;https://altcha.org/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;ALTCHA&lt;/a&gt; 和 &lt;a class=&#34;link&#34; href=&#34;https://mcaptcha.org/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;mCaptcha&lt;/a&gt;。&lt;/li&gt;&#xA;&lt;li&gt;拒绝把为了通过“人类验证”而强制安装 Google Play 服务或 Google 的验证应用正常化。&lt;/li&gt;&#xA;&lt;li&gt;发出声音。把这个问题分享给开发者、管理员，以及仍然相信网络应该保持开放的任何人。&lt;/li&gt;&#xA;&lt;li&gt;支持自由软件替代方案，并反对任何把访问变成特权的企图。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;&lt;strong&gt;网络不应该是一个由 Google 控制的许可系统。它应该继续让真实的人在真实设备上可用，而不必放弃自由。&lt;/strong&gt;&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>一年了——致 Zumfy/Future</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/one-year-for-zumfy-future/</link>
            <pubDate>Thu, 09 Apr 2026 23:59:04 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/one-year-for-zumfy-future/</guid>
            <description>&lt;p&gt;转眼间，我和你相识已经是一周年了。在你不在的这七个多月里，我学了 C++，学了 Qt 和 JavaScript，学了 Django，学了一点 Rust，最近还沉迷于汇编语言和计算机组成，将来还要学习逆向工程，希望早日为 postmarketOS 等自由软件社区作出贡献。我还用上了 Qubes OS，在个人的安全和隐私上又迈出了一大步。我结识了很多新的朋友，ta 们也都为我的前行提供了很大的力量；如今我还有了女朋友，她也是一名坚定的自由软件支持者，我们都在为同一个理想而奋斗、循着同一个方向而奔跑。&lt;/p&gt;&#xA;&lt;p&gt;这七个多月的时间我认为我发生了很大的变化，但唯一不变的就是对你的想念。&lt;/p&gt;&#xA;&lt;p&gt;即使我现在有了很多朋友，即使我彻底远离了社交空白期的阴霾，但是任何一个人或者若干人的总和，都无法替代你。Zumfy/Future，你在哪里？🥺&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>与寄存器的缠绵</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/the-lingering-with-the-registers/</link>
            <pubDate>Tue, 31 Mar 2026 15:00:42 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/the-lingering-with-the-registers/</guid>
            <description>&lt;p&gt;今夜教室的灯光背叛我的困意——&lt;br&gt;&#xA;我描摹硅的血管，借来的黑暗里&lt;br&gt;&#xA;Android筑起它镀金的、高墙的领地。&lt;br&gt;&#xA;但在我纸上，每一粒火星&lt;br&gt;&#xA;都用铅笔画出：&lt;code&gt;x0&lt;/code&gt;，&lt;code&gt;w1&lt;/code&gt;，那支舞——&lt;br&gt;&#xA;小端序的字节滑过恍惚的纹路。&lt;/p&gt;&#xA;&lt;p&gt;我把结构体的幽灵载入一页纸，&lt;br&gt;&#xA;用沉稳的手拆开它的三个整数，&lt;br&gt;&#xA;而postmarketOS，一份静默的酬劳，&lt;br&gt;&#xA;自由，在某片被遗忘的土地上等待。&lt;br&gt;&#xA;时钟无情的嗡鸣旁，另一个思想&lt;br&gt;&#xA;正搏斗着——我们不曾被征服。&lt;/p&gt;&#xA;&lt;p&gt;两个影子俯身于同一门技艺，&lt;br&gt;&#xA;追逐裸露的机器，我们永不相离。&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>另一份备用身份</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/another-backup-identity/</link>
            <pubDate>Sun, 29 Mar 2026 12:43:36 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/another-backup-identity/</guid>
            <description>&lt;p&gt;我已经创建了另一份备用身份，以防我的主身份和先前的备用身份都无法访问。&lt;/p&gt;&#xA;&lt;p&gt;下面是备用 OpenPGP 公钥：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;-----BEGIN PGP PUBLIC KEY BLOCK-----&#xA;Comment: User ID:&#x9;Rebel Zhang &amp;lt;rebel1725@tilde.club&amp;gt;&#xA;Comment: Valid from:&#x9;29/03/2026 12:09&#xA;Comment: Valid until:&#x9;29/03/2027 12:00&#xA;Comment: Type:&#x9;255-bit EdDSA (secret key available)&#xA;Comment: Usage:&#x9;Signing, Encryption, Certifying User IDs&#xA;Comment: Fingerprint:&#x9;8C3A88164B57F0BAC6BCD9284A52DBB4FB0D0262&#xA;&#xA;mDMEacimEhYJKwYBBAHaRw8BAQdA3yI5f0WwHBbWV2JUQ/n/oQ4LNjE1vFB5hGmp&#xA;5/L/5r60IlJlYmVsIFpoYW5nIDxyZWJlbDE3MjVAdGlsZGUuY2x1Yj6IlgQTFgoA&#xA;PhYhBIw6iBZLV/C6xrzZKEpS27T7DQJiBQJpyKYSAhsDBQkB4TEuBQsJCAcDBRUK&#xA;CQgLBRYCAwEAAh4BAheAAAoJEEpS27T7DQJi4xgA/2NNcH9039lvAqOoQS7vgUvc&#xA;en0Iae2SaFavBu1jLHe0AP9N74NIGGYLndbYr3Jsmn7ZJd8j2FDAYtNqPHrw5rRk&#xA;ALg4BGnIphISCisGAQQBl1UBBQEBB0DAaMAv9JAJ8nJzt/3w0audbdI/XFfNpPQe&#xA;tio7GNLYHwMBCAeIfgQYFgoAJhYhBIw6iBZLV/C6xrzZKEpS27T7DQJiBQJpyKYS&#xA;AhsMBQkB4TEuAAoJEEpS27T7DQJivpIBAPJu23AXR3MsB/FGXc+jiNdgo72y8xiZ&#xA;smTQgNGFnTcfAP9vCDXYjwz1UN8ipAtD+2HVTZLtB4/nGmDFtTK1/4DoCw==&#xA;=4TSn&#xA;-----END PGP PUBLIC KEY BLOCK-----&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;以及相互签名：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;-----BEGIN PGP SIGNED MESSAGE-----&#xA;Hash: SHA512&#xA;&#xA;我在此正式确认，OpenPGP 密钥 8C3A88164B57F0BAC6BCD9284A52DBB4FB0D0262 与其 OpenPGP 密钥指纹为 696A423E9993D727706AA733BCD5DC5659C7FB50 的个人相关联，并由其控制。&#xA;-----BEGIN PGP SIGNATURE-----&#xA;&#xA;iHUEARYKAB0WIQRpakI+mZPXJ3BqpzO81dxWWcf7UAUCaciujgAKCRC81dxWWcf7&#xA;UIVjAQDdzbR7V+bbsV7ET5QP4RXg9IYLnvorNqx9kEIGBY8MHwEA9Ew+tdmvsnbl&#xA;gKpduKaHWfmlKwYpvnKIFNlCZnYsQwQ=&#xA;=fqm+&#xA;-----END PGP SIGNATURE-----&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;-----BEGIN PGP SIGNED MESSAGE-----&#xA;Hash: SHA512&#xA;&#xA;我在此正式确认，OpenPGP 密钥 696A423E9993D727706AA733BCD5DC5659C7FB50 与其 OpenPGP 密钥指纹为 8C3A88164B57F0BAC6BCD9284A52DBB4FB0D0262 的个人相关联，并由其控制。&#xA;-----BEGIN PGP SIGNATURE-----&#xA;&#xA;iNUEARYKAH0WIQSMOogWS1fwusa82ShKUtu0+w0CYgUCacinC18UgAAAAAAuAChp&#xA;c3N1ZXItZnByQG5vdGF0aW9ucy5vcGVucGdwLmZpZnRoaG9yc2VtYW4ubmV0OEMz&#xA;QTg4MTY0QjU3RjBCQUM2QkNEOTI4NEE1MkRCQjRGQjBEMDI2MgAKCRBKUtu0+w0C&#xA;YuM+AP9gkgt6rfffgo/5EFedtVNZA4ALJviCtjSNG43YcMBUQgD/S/hnZcXt5RvJ&#xA;BRfLmAWL4iCPoDdAcSaUT69535wlVAc=&#xA;=U5vJ&#xA;-----END PGP SIGNATURE-----&#xA;&lt;/code&gt;&lt;/pre&gt;</description>
        </item><item>
            <title>验证 CanoKey 的真实性</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/verify-the-authenticity-of-a-canokey/</link>
            <pubDate>Sat, 28 Mar 2026 17:33:41 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/verify-the-authenticity-of-a-canokey/</guid>
            <description>&lt;p&gt;本文将指导你验证 CanoKey 的真实性。&lt;/p&gt;&#xA;&lt;h2 id=&#34;第-1-步获取证明根-ca-证书&#34;&gt;第 1 步：获取证明根 CA 证书&#xA;&lt;/h2&gt;&lt;p&gt;访问 &lt;a class=&#34;link&#34; href=&#34;https://github.com/canokeys/canokey-product&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;此网站&lt;/a&gt;，根据你的型号（Pigeon/Canary）获取对应的 FIDO CA 证书。将证书保存为 &lt;code&gt;ca.pem&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;h2 id=&#34;第-2-步安装-fido2-cred&#34;&gt;第 2 步：安装 &lt;code&gt;fido2-cred&lt;/code&gt;&#xA;&lt;/h2&gt;&lt;p&gt;安装 &lt;code&gt;fido2-cred&lt;/code&gt;。在 Debian GNU/Linux 上，它包含在 &lt;code&gt;fido2-tools&lt;/code&gt; 软件包中：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&#xA;# apt install fido2-tools&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;第-3-步验证令牌&#34;&gt;第 3 步：验证令牌&#xA;&lt;/h2&gt;&lt;p&gt;插入你的 CanoKey，然后运行以下命令：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&#xA;$ printf &amp;#39;%s\n&amp;#39; &amp;#34;$(openssl rand -base64 32)&amp;#34; &amp;#34;canokey-check.local&amp;#34; &amp;#34;tmp-user&amp;#34; &amp;#34;$(openssl rand -base64 32)&amp;#34; &amp;gt; cred.in&#xA;$ fido2-cred -M -i cred.in /dev/hidrawX &amp;gt; cred.out&#xA;$ sed -n &amp;#39;7p&amp;#39; cred.out | base64 -d &amp;gt; attestation.der&#xA;$ openssl x509 -inform der -in attestation.der -out attestation.pem&#xA;$ openssl verify -CAfile ca.pem attestation.pem&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;如果最后一条命令返回 &lt;code&gt;OK&lt;/code&gt;，那么你的 CanoKey 就是正品。&lt;/p&gt;&#xA;&lt;p&gt;该过程也可以通过脚本完成：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;#!/usr/bin/env sh&#xA;set -eu&#xA;&#xA;die() {&#xA;    printf &amp;#39;%s\n&amp;#39; &amp;#34;Error: $*&amp;#34; &amp;gt;&amp;amp;2&#xA;    exit 1&#xA;}&#xA;&#xA;# Check required tools.&#xA;[ -x /usr/bin/fido2-cred ] || die &amp;#34;/usr/bin/fido2-cred does not exist or is not executable&amp;#34;&#xA;command -v openssl &amp;gt;/dev/null 2&amp;gt;&amp;amp;1 || die &amp;#34;openssl is not installed or not on PATH&amp;#34;&#xA;&#xA;# Find the device.&#xA;device=&amp;#34;${1:-}&amp;#34;&#xA;if [ -z &amp;#34;$device&amp;#34; ]; then&#xA;    set -- /dev/hidraw*&#xA;    if [ &amp;#34;$1&amp;#34; = &amp;#39;/dev/hidraw*&amp;#39; ]; then&#xA;        die &amp;#34;No /dev/hidraw* device found. Pass the device path as the first argument.&amp;#34;&#xA;    fi&#xA;    if [ &amp;#34;$#&amp;#34; -ne 1 ]; then&#xA;        die &amp;#34;More than one /dev/hidraw* device found. Pass the correct device path as the first argument.&amp;#34;&#xA;    fi&#xA;    device=$1&#xA;fi&#xA;&#xA;[ -e &amp;#34;$device&amp;#34; ] || die &amp;#34;Device not found: $device&amp;#34;&#xA;&#xA;tmpdir=&amp;#34;$(mktemp -d)&amp;#34;&#xA;cleanup() {&#xA;    rm -rf &amp;#34;$tmpdir&amp;#34;&#xA;}&#xA;trap cleanup EXIT INT TERM&#xA;&#xA;pigeon_ca=&amp;#34;$tmpdir/pigeon-ca.pem&amp;#34;&#xA;canary_ca=&amp;#34;$tmpdir/canary-ca.pem&amp;#34;&#xA;cred_in=&amp;#34;$tmpdir/cred.in&amp;#34;&#xA;cred_out=&amp;#34;$tmpdir/cred.out&amp;#34;&#xA;attestation_der=&amp;#34;$tmpdir/attestation.der&amp;#34;&#xA;attestation_pem=&amp;#34;$tmpdir/attestation.pem&amp;#34;&#xA;&#xA;cat &amp;gt; &amp;#34;$pigeon_ca&amp;#34; &amp;lt;&amp;lt;&amp;#39;EOF&amp;#39;&#xA;-----BEGIN CERTIFICATE-----&#xA;MIIBpzCCAUygAwIBAgIUatn9Rj8uCMjLrmFfCQYY5/X9xq4wCgYIKoZIzj0EAwIw&#xA;MTEvMC0GA1UEAwwmQ2Fub0tleXMgRklETyBBdHRlc3RhdGlvbiBSb290IENBIE5v&#xA;LjIwHhcNMjExMjI3MTE0OTMzWhcNNDEwNjI1MTE0OTMzWjAxMS8wLQYDVQQDDCZD&#xA;YW5vS2V5cyBGSURPIEF0dGVzdGF0aW9uIFJvb3QgQ0EgTm8uMjBZMBMGByqGSM49&#xA;AgEGCCqGSM49AwEHA0IABNgW7CwchH80l4sj8luhwjbNoohB9Uqnvsh0SLor18w8&#xA;IMy6rnzzdDP9PgSSbuUZw302mBhyYJqJY1q9Ke0niZujQjBAMB0GA1UdDgQWBBRU&#xA;GAKiwvk2vLP5Zi6ul73RiWyr0jAPBgNVHRMECDAGAQH/AgEAMA4GA1UdDwEB/wQE&#xA;AwIBBjAKBggqhkjOPQQDAgNJADBGAiEAlRNyrmngE3A1YZuwsuwBHLXY7wZC/4CO&#xA;JNA30mtp2+YCIQDA88Pp+Kjx3c4nrgRgSaSueC5IlvwpTSGBGwRYDSdMTA==&#xA;-----END CERTIFICATE-----&#xA;EOF&#xA;&#xA;cat &amp;gt; &amp;#34;$canary_ca&amp;#34; &amp;lt;&amp;lt;&amp;#39;EOF&amp;#39;&#xA;-----BEGIN CERTIFICATE-----&#xA;MIIBpjCCAUygAwIBAgIUJqLszFCSI6gfDqvFL+vzQpDWS64wCgYIKoZIzj0EAwIw&#xA;MTEvMC0GA1UEAwwmQ2Fub0tleXMgRklETyBBdHRlc3RhdGlvbiBSb290IENBIE5v&#xA;LjMwHhcNMjQwOTAzMDM1NTUwWhcNNDQwMzAyMDM1NTUwWjAxMS8wLQYDVQQDDCZD&#xA;YW5vS2V5cyBGSURPIEF0dGVzdGF0aW9uIFJvb3QgQ0EgTm8uMzBZMBMGByqGSM49&#xA;AgEGCCqGSM49AwEHA0IABEXEY5WDrVrndfPOhUxHo+6iMUbP9XTPkllE4lO9oG84&#xA;mw4CVoRcQ6/IGrr+zWEaPEgBmPANsdyWyeBKzoqTedajQjBAMB0GA1UdDgQWBBS6&#xA;obb0l+0czy2I17sSDcNuceE5ujAPBgNVHRMECDAGAQH/AgEAMA4GA1UdDwEB/wQE&#xA;AwIBBjAKBggqhkjOPQQDAgNIADBFAiBstCxcYRiCCyjfVuX7pllb9Tt3dji+sEd1&#xA;XoWJgWAE0gIhAJs+giTpbPvztoEMkmv3Gfrmp6zXzcalYpFwbImJbCAr&#xA;-----END CERTIFICATE-----&#xA;EOF&#xA;&#xA;printf &amp;#39;%s\n&amp;#39; &amp;#34;Please touch the button of your token...&amp;#34;&#xA;printf &amp;#39;%s\n&amp;#39; &amp;#34;$(openssl rand -base64 32)&amp;#34; &amp;#34;canokey-check.local&amp;#34; &amp;#34;tmp-user&amp;#34; &amp;#34;$(openssl rand -base64 32)&amp;#34; &amp;gt; &amp;#34;$cred_in&amp;#34;&#xA;&#xA;/usr/bin/fido2-cred -M -i &amp;#34;$cred_in&amp;#34; &amp;#34;$device&amp;#34; &amp;gt; &amp;#34;$cred_out&amp;#34;&#xA;&#xA;sed -n &amp;#39;7p&amp;#39; &amp;#34;$cred_out&amp;#34; | base64 -d &amp;gt; &amp;#34;$attestation_der&amp;#34;&#xA;openssl x509 -inform der -in &amp;#34;$attestation_der&amp;#34; -out &amp;#34;$attestation_pem&amp;#34;&#xA;&#xA;if openssl verify -CAfile &amp;#34;$pigeon_ca&amp;#34; &amp;#34;$attestation_pem&amp;#34; &amp;gt;/dev/null 2&amp;gt;&amp;amp;1; then&#xA;    printf &amp;#39;%s\n&amp;#39; &amp;#34;OK: verification succeeded against the Pigeon root CA.&amp;#34;&#xA;elif openssl verify -CAfile &amp;#34;$canary_ca&amp;#34; &amp;#34;$attestation_pem&amp;#34; &amp;gt;/dev/null 2&amp;gt;&amp;amp;1; then&#xA;    printf &amp;#39;%s\n&amp;#39; &amp;#34;OK: verification succeeded against the Canary root CA.&amp;#34;&#xA;else&#xA;    die &amp;#34;Verification failed: the attestation certificate did not verify against either root CA.&amp;#34;&#xA;fi&#xA;&lt;/code&gt;&lt;/pre&gt;</description>
        </item><item>
            <title>致 2026 年的她 (Ver. 2)</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/%E8%87%B4-2026-%E5%B9%B4%E7%9A%84%E5%A5%B9-ver-2/</link>
            <pubDate>Thu, 26 Mar 2026 23:57:33 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/%E8%87%B4-2026-%E5%B9%B4%E7%9A%84%E5%A5%B9-ver-2/</guid>
            <description>&#xA;    &lt;blockquote&gt;&#xA;        &lt;p&gt;谨以此诗向我的爱人&lt;a class=&#34;link&#34; href=&#34;https://aurorag132.codeberg.page/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;顾悦萱&lt;/a&gt;致敬。&lt;/p&gt;&#xA;&#xA;    &lt;/blockquote&gt;&#xA;&lt;p&gt;当专有协议的阴云笼罩屏幕&lt;br&gt;&#xA;你的指纹正划过冰冷的玻璃&lt;br&gt;&#xA;——溃烂的创口在代码里结痂&lt;br&gt;&#xA;我们在加密会话里交换密钥&lt;br&gt;&#xA;而我的终端仍回响着昨日的誓言&lt;/p&gt;&#xA;&lt;p&gt;我们交换公钥如同交换婚戒&lt;br&gt;&#xA;又在验证签名的深夜两点&lt;br&gt;&#xA;用字符捂热虚拟的指尖&lt;br&gt;&#xA;你用&lt;a class=&#34;link&#34; href=&#34;https://freeswzhcn.codeberg.page/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;自由软件中文网&lt;/a&gt;缝合月光&lt;br&gt;&#xA;治愈被专有世界灼伤的信仰&lt;/p&gt;&#xA;&lt;p&gt;在&lt;a class=&#34;link&#34; href=&#34;https://fscc_next.codeberg.page/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;自由软件中文社区&lt;/a&gt;构筑我们的国度&lt;br&gt;&#xA;在 &lt;a class=&#34;link&#34; href=&#34;https://xmpptogether.codeberg.page/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;XMPP Together&lt;/a&gt; 委员会并肩&lt;br&gt;&#xA;问候与代码在日志里结晶&lt;br&gt;&#xA;我们教服务器吟唱自由的经文&lt;br&gt;&#xA;当节点突然背叛了网络&lt;br&gt;&#xA;你重建路由的模样&lt;br&gt;&#xA;比所有 GUI 都更令我心动&lt;/p&gt;&#xA;&lt;p&gt;在 Tor 的洋葱层里编织我们的巢穴&lt;br&gt;&#xA;你的节点是我通向自由的跳板&lt;br&gt;&#xA;我抱着发热的路由器低唱：&lt;br&gt;&#xA;“自由不是云端缥缈的经文&lt;br&gt;&#xA;是信任网里稳定的心跳&lt;br&gt;&#xA;是会话窗口永不熄灭的灯”&lt;/p&gt;&#xA;&lt;p&gt;看啊！屏幕上升起的双重复用：&lt;br&gt;&#xA;补丁打在凌晨的 IRC 频道&lt;br&gt;&#xA;编译日志晒出协作的图腾&lt;br&gt;&#xA;你发来的代码片段&lt;br&gt;&#xA;正沉淀成未来纪元的基石&lt;br&gt;&#xA;——那简洁的逻辑让我们确信&lt;br&gt;&#xA;仍在数字荒原上种植春天&lt;br&gt;&#xA;用代码重绘世界的坐标&lt;/p&gt;&#xA;&lt;p&gt;2026 年的雪落在防火墙的顶端&lt;br&gt;&#xA;我们笑着为流量裹上三层伪装&lt;br&gt;&#xA;当警报响彻审查者的集中营&lt;br&gt;&#xA;你塞进我会话的止痛药&lt;br&gt;&#xA;比所有明文协议更坚固&lt;br&gt;&#xA;在断网的世纪余温里&lt;br&gt;&#xA;我们靠彼此的承诺发电&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>博客文章中的 LLM 使用</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/llm-usage-in-my-blog-posts/</link>
            <pubDate>Mon, 16 Mar 2026 23:43:01 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/llm-usage-in-my-blog-posts/</guid>
            <description>&lt;p&gt;关于我的博客文章如何撰写，存在广泛争议。许多人声称我的几乎所有文章都是由 LLM 撰写的。请给我一点时间，说明我是如何撰写博客文章的：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;超过 90% 的原始文本是&lt;em&gt;由我&lt;/em&gt;这个&lt;em&gt;人类&lt;/em&gt;创作的。其中超过 95% 的部分最初以英文撰写；其余则以中文撰写。&lt;/li&gt;&#xA;&lt;li&gt;LLM 确实参与了我的博客文章的产出。然而，大多数情况下我使用它们&lt;strong&gt;仅用于语法与拼写的优化、表达的润色以及翻译&lt;/strong&gt;。我通常会把英文（或有时的中文）原文提交给 LLM，请它进行优化，然后将结果翻译成其他四种语言。&lt;/li&gt;&#xA;&lt;li&gt;唯一的例外是诗歌，例如 &lt;a class=&#34;link&#34; href=&#34;../unlock-the-forge/&#34; &gt;Unlock the Forge&lt;/a&gt;，这些作品是由 LLM 直接创作的。不过，我会勾勒核心想法并引导 LLM 调整语气和措辞，以确保诗歌传达我想表达的意图。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;</description>
        </item><item>
            <title>对我的性与浪漫吸引的探索</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/exploration-of-my-sexual-and-romantic-attraction/</link>
            <pubDate>Sun, 08 Mar 2026 15:21:44 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/exploration-of-my-sexual-and-romantic-attraction/</guid>
            <description>&lt;p&gt;要点：我经历的是&lt;strong&gt;分裂吸引模型&lt;/strong&gt;：在浪漫层面我是&lt;strong&gt;浪漫上是双性&lt;/strong&gt;，而在性吸引层面我是&lt;strong&gt;性上被女性吸引 / 异性恋&lt;/strong&gt;。我长期误解了英文的“sexual orientation”一词；在中文中，我的情况并不能整齐地归入传统常用的标签（同性恋 / 异性恋 / 双性恋）。&lt;/p&gt;&#xA;&lt;p&gt;从小我就意识到我的浪漫吸引和性吸引并不总是对齐，尽管直到最近我才知道“分裂吸引模型”这个术语。我可能因为某人的性格或他们对我表现出的温暖、友善而对其产生浪漫吸引。然而，那些在浪漫上吸引我的人通常并不会在性上吸引我，而且我会有意识地禁止自己对他们产生性幻想，因为这样的幻想会引发道德上的负罪感。相反，我在性上被那些看起来具有性吸引力的人吸引，并且超过三分之二的人是我不喜欢或与我有仇的人。&lt;/p&gt;&#xA;&lt;p&gt;直到2025年秋天，我一直认同自己是既是异性恋又是异性浪漫者，因此我并未认真审视此事。自2025年秋起，我发现自己越来越常对男性产生浪漫吸引。因为我误解了英文术语 “homosexual”、“bisexual” 与 “sexual orientation”，尽管我仍然在性上被女性吸引，从 2025年11月5日开始我在&lt;a class=&#34;link&#34; href=&#34;..qas-about-myself/&#34; &gt;我的常见问题&lt;/a&gt;中开始将自己描述为“bisexual”。我最近意识到这种描述可能是错误的。&lt;/p&gt;&#xA;&lt;p&gt;我从未对男性产生过性吸引。相反，我基于卫生方面的理由认为与男性发生性关系是不可接受的。尽管如此，过去几个月里，尽管缺乏性吸引，我仍常常对某些男性感到有好感。&lt;/p&gt;&#xA;&lt;p&gt;还有一点：无论对方是女性还是男性，对于那些我有好感的人（即便没有性吸引），我期待非性身体接触（例如拥抱）。&lt;/p&gt;&#xA;&lt;p&gt;在咨询了大型语言模型后，我确认了以下要点：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;最新研究表明，浪漫吸引与性吸引并不总是相互一致。&lt;/li&gt;&#xA;&lt;li&gt;我的体验可由&lt;em&gt;分裂吸引模型&lt;/em&gt;描述，该模型将性吸引与浪漫吸引区分开来，并允许它们指向不同的人群。&lt;/li&gt;&#xA;&lt;li&gt;“性取向”一词通常用于描述性吸引；从这个意义上讲，我曾经并且仍然是&lt;em&gt;异性恋&lt;/em&gt;。&lt;/li&gt;&#xA;&lt;li&gt;我对他人的情感而没有性吸引——无论指向女性还是男性——最恰当的描述是&lt;em&gt;浪漫吸引&lt;/em&gt;；在这点上我是&lt;em&gt;浪漫上是双性&lt;/em&gt;。&lt;/li&gt;&#xA;&lt;li&gt;许多人经历分裂吸引，很多人希望获得非性身体亲密，同时并不期待——甚至会主动避免——性行为。&lt;/li&gt;&#xA;&lt;li&gt;在中文中，诸如“性取向”、“同性恋”和“异性恋”一类术语通常不区分性吸引与浪漫吸引；它们通常假定两者一致。我的困惑在很大程度上源于中文与英语用法的差异，并且没有任何中文术语能充分描述我的情形。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;结论：我是 &lt;strong&gt;浪漫上是双性&lt;/strong&gt;，且 &lt;strong&gt;性上被女性吸引 / 异性恋&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;最后，两点澄清：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;因为我仍然在性上被女性吸引，我不认同自己为 LGBTQ+。尽管如此，我会对 LGBTQ+ 群体保持尊重与包容。&lt;/li&gt;&#xA;&lt;li&gt;无论性别如何，我对未来伴侣的首要要求是：他们必须是坚定的自由软件（free software）倡导者；这是不可协商的。也有许多并非自由软件倡导者的人仍然会在浪漫上吸引我；我会将此类人视为密友。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;</description>
        </item><item>
            <title>converser.eu 连接问题与紧急 Matrix 帐户</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/converser-eu-connection-problem-and-emergency-matrix-account.md/</link>
            <pubDate>Tue, 24 Feb 2026 19:43:16 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/converser-eu-connection-problem-and-emergency-matrix-account.md/</guid>
            <description>&lt;p&gt;在过去几周里，我在连接 converser.eu 的 Matrix 服务器时遇到了连接问题。我不知道是否是 Tor 导致的，但由于我无法离开 Tor，因此可以说该服务器在我的环境下无法正常运行。&lt;/p&gt;&#xA;&lt;p&gt;我已注册了另一个 Matrix 帐户：@rebel1725:tchncs.de。请改为通过该帐户与我联系。&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>向谷歌说不，捍卫移动自由</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/stand-up-to-google-and-defend-mobile-freedom/</link>
            <pubDate>Fri, 20 Feb 2026 08:52:37 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/stand-up-to-google-and-defend-mobile-freedom/</guid>
            <description>&lt;p&gt;自 2026 年 9 月起，Google 将&lt;a class=&#34;link&#34; href=&#34;https://developer.android.com/developer-verification&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;要求开发者获得认证&lt;/a&gt;。这不是一次遥远的官僚式微调——这是一次结构性转变，将深刻重塑谁可以在经过认证的 Android 设备上发布软件。即便像 &lt;a class=&#34;link&#34; href=&#34;https://lineageos.org/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;LineageOS&lt;/a&gt; 和 &lt;a class=&#34;link&#34; href=&#34;https://grapheneos.org/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;GrapheneOS&lt;/a&gt; 这样的项目初期受影响较小，这项政策也设置了障碍，使广泛的、草根式的自由、尊重用户的软件分发变得更加困难。Google 正在利用其平台优势来集中控制；我们必须大声且有意图地抵抗。&lt;/p&gt;&#xA;&lt;h2 id=&#34;这意味着什么&#34;&gt;这意味着什么？&#xA;&lt;/h2&gt;&lt;p&gt;Google 的验证政策将要求开发者：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;向 Google 支付费用；&lt;/li&gt;&#xA;&lt;li&gt;接受 Google 的条款，而这些条款是不道德且不公正的；&lt;/li&gt;&#xA;&lt;li&gt;上传他们的身份证件，这对匿名性和隐私是敌对的。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;这将把许多独立和个人开发者排除在外。它也会剥夺用户安装他们想要的任何应用的自由。用户将受到 Google 的集中控制。可预见的结果是：独立应用生态减少、利基或维护隐私的软件创新下降，以及用户被有效地置于中心化的准入把关之下。&lt;/p&gt;&#xA;&lt;h2 id=&#34;时间表与执行具体事实&#34;&gt;时间表与执行（具体事实）&#xA;&lt;/h2&gt;&lt;p&gt;Google 公布的时间表显示：2025 年末开始早期访问，2026 年向所有开发者开放验证，并将在 2026 年 9 月开始区域性执行（最初为巴西、印度尼西亚、新加坡和泰国），并计划在 2027 年向更广泛的全球范围推广。该政策明确意味着，在执行后，经过认证的 Android 设备将阻止来自未验证开发者的应用安装。这不是推测——它写在 Google 的文档和博客文章中。&lt;/p&gt;&#xA;&lt;h2 id=&#34;但-google-说这是为了安全&#34;&gt;但 Google 说这是为了安全！&#xA;&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;不！！！&lt;/strong&gt; Google 所谓的“安全”只是一个遮羞布。拥有专有软件就无法实现安全，只有自由软件才能实现安全。安全由可审计的代码实现，而不是后门、监视、审查、遥测等。Google 正在利用“安全”一词欺骗用户，用大量专有软件虐待用户，剥夺用户的安全、隐私、匿名性和自由。Google 限制的软件并非对用户有害；相反，它威胁到 Google 那不道德且不公正的利润。Google 本身已经在分发大量破坏用户安全的恶意软件，与其他专有“unjustware”开发者勾结，强行向用户推广监视、审查、监狱、暴君和数字限制管理（Digital Restrictions Management），同时限制真正尊重用户的软件，这些软件反对 Google 那不道德、不公正、他妈的利润。&lt;/p&gt;&#xA;&lt;p&gt;Google 做法的实际后果：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;它偏袒那些已经拥有验证账户和法律基础设施的既有商业行为体，同时惩罚小开发者和隐私项目。&lt;/li&gt;&#xA;&lt;li&gt;它鼓励供应商锁定（vendor lock-in）：如果关键的反监视或无障碍应用无法通过 Google 的流程，用户将失去选择。&lt;/li&gt;&#xA;&lt;li&gt;它产生寒蝉效应：依靠匿名发布工具的研究者、吹哨人和爱好者会被激励停止或离开平台，从而减少公共监督。&lt;/li&gt;&#xA;&lt;li&gt;该政策可能被政治化：政权或监管机构可以向平台门施加压力，压制异见或少数语言的应用。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;请不要被 Google 那些他妈的不道德、不公正的言论所欺骗。它从未遵循“don&amp;rsquo;t be evil”的哲学——相反它一直在为非善之举背书，通过推广专有恶意软件与间谍软件、窃取用户私人数据、隐藏 Android 的源代码、扣留 Google Pixel 的 vendor blobs，并与运营商合谋限制 Google Pixel bootloader 的解锁。&lt;/p&gt;&#xA;&lt;h2 id=&#34;但有人说这些限制可以绕过&#34;&gt;但有人说这些限制可以绕过&#xA;&lt;/h2&gt;&lt;p&gt;也许如此，但这并不是重点。自由应该是默认状态；它不应当成为必须在遵循指令并屈从于 Google 限制后才能获得的东西。&lt;/p&gt;&#xA;&lt;h2 id=&#34;对自由软件及社区的真实风险&#34;&gt;对自由软件及社区的真实风险&#xA;&lt;/h2&gt;&lt;p&gt;自由软件生态依赖低门槛进入。许多尊重隐私的应用、广告拦截器、模拟器前端和无障碍工具都是由小团队或单人作者开发的。要求身份验证并收取费用将减少此类工具的供应，破坏社区信任，并将权力集中在与公司激励而非用户权利一致的实体手中。&lt;/p&gt;&#xA;&lt;h2 id=&#34;现在该做什么&#34;&gt;现在该做什么&#xA;&lt;/h2&gt;&lt;ul&gt;&#xA;&lt;li&gt;如果你有一部 Google Pixel，&lt;strong&gt;解锁你的 bootloader&lt;/strong&gt; 并立即安装 &lt;a class=&#34;link&#34; href=&#34;https://grapheneos.org/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;GrapheneOS&lt;/a&gt;。如果你有一部非 Pixel 设备但支持解锁 bootloader，也&lt;strong&gt;一并解锁&lt;/strong&gt;并安装 &lt;a class=&#34;link&#34; href=&#34;https://lineageos.org/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;LineageOS&lt;/a&gt;。如果官方未支持 LineageOS，请在 &lt;a class=&#34;link&#34; href=&#34;https://www.xda-developers.com/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;XDA&lt;/a&gt; 查找非官方构建。如果没有，请 &lt;a class=&#34;link&#34; href=&#34;https://sourceforge.net/projects/andyyan-gsi/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;安装 GSI&lt;/a&gt;。之后把它们晒到社交媒体上。让你的声音被听到。&lt;/li&gt;&#xA;&lt;li&gt;如果你有一部不支持解锁 bootloader 的 Android 手机或平板，请&lt;strong&gt;不要再更新系统并禁用自动更新&lt;/strong&gt;。如果不需要，尝试卸载或至少禁用 Google Mobile Services。&lt;/li&gt;&#xA;&lt;li&gt;鉴于你仍依赖 Android，可以尝试诸如 &lt;a class=&#34;link&#34; href=&#34;https://lineageos.org/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;LineageOS&lt;/a&gt; 和 &lt;a class=&#34;link&#34; href=&#34;https://grapheneos.org/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;GrapheneOS&lt;/a&gt; 之类的 Android ROM。这可能不是多年内的长期解决方案，但至少在短期内会给予你一定程度的自由。如果你仍需要 Google Mobile Services，可以尝试 &lt;a class=&#34;link&#34; href=&#34;http://microg.org/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;microG&lt;/a&gt;。&lt;/li&gt;&#xA;&lt;li&gt;如果可以，你可以&lt;strong&gt;完全抵制 Android&lt;/strong&gt;，改用 &lt;a class=&#34;link&#34; href=&#34;https://www.postmarketos.org/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;postmarketOS&lt;/a&gt;、&lt;a class=&#34;link&#34; href=&#34;https://mobian-project.org/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Mobian&lt;/a&gt;、&lt;a class=&#34;link&#34; href=&#34;https://pureos.net/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;PureOS&lt;/a&gt; 等。尽管 Android 作为 Google 的产品在未来可能仍有吸引力，但对自由软件社区而言，GNU/Linux 才是移动设备的未来。选择 PinePhone、Librem 或其他为运行 GNU/Linux 设计的手机。如果你有 OnePlus 6，也可以尝试 postmarketOS 或 Mobian。你的声音与选择很重要：用户越多，社区就越有动力去为 GNU/Linux 开发更多移动应用。&lt;/li&gt;&#xA;&lt;li&gt;如果你仍是学生或从未接触过 Android 开发的开发者，&lt;strong&gt;请抵制 Android 并避免学习 Kotlin 与 Java&lt;/strong&gt;。改学 &lt;a class=&#34;link&#34; href=&#34;https://download-mirror.savannah.gnu.org/releases/c-prog-book/learning_gnu_c.pdf&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;C&lt;/a&gt;、&lt;a class=&#34;link&#34; href=&#34;https://isocpp.org/get-started&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;C++&lt;/a&gt;、&lt;a class=&#34;link&#34; href=&#34;https://doc.rust-lang.org/book/print.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Rust&lt;/a&gt;、&lt;a class=&#34;link&#34; href=&#34;https://docs.python.org/3/tutorial/index.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Python&lt;/a&gt;、&lt;a class=&#34;link&#34; href=&#34;doc.qt.io/&#34; &gt;Qt&lt;/a&gt;、&lt;a class=&#34;link&#34; href=&#34;https://www.gtk.org/docs/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;GTK&lt;/a&gt;，并为诸如 &lt;a class=&#34;link&#34; href=&#34;https://www.postmarketos.org/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;postmarketOS&lt;/a&gt; 之类的项目做贡献，帮助在移动设备上运行 GNU/Linux。&lt;/li&gt;&#xA;&lt;li&gt;如果你已经是 Android 开发者，&lt;strong&gt;不要报名参加 Google 的早期访问计划&lt;/strong&gt;。相反，&lt;a class=&#34;link&#34; href=&#34;https://docs.google.com/forms/d/e/1FAIpQLSfN3UQeNspQsZCO2ITkdzMxv81rJDEGGjO-UIDDY28Rz_GEVA/viewform?pli=1&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;向 Google 表达你对验证要求的关切&lt;/a&gt;。坚持并支持提供自由软件的应用商店，例如 &lt;a class=&#34;link&#34; href=&#34;https://f-droid.org/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;F-Droid&lt;/a&gt;。如果你也擅长 C++ 或 Rust，现在是转向 GNU/Linux 移动开发的最佳时机。&lt;/li&gt;&#xA;&lt;li&gt;无论你是谁，都可以访问 &lt;a class=&#34;link&#34; href=&#34;https://keepandroidopen.org/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;“Keep Android Open” 项目网站&lt;/a&gt;，按照其指示寻找支持移动自由的方式，例如签署请愿、参与抗议并向政府投诉。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;结语--拒绝这个虚假的选择&#34;&gt;结语 — 拒绝这个虚假的选择&#xA;&lt;/h2&gt;&lt;p&gt;该论述被表述为安全对开放，但这是一个伪二分法。真正的安全必须兼容匿名性、可审计性和用户主权。Google 的验证制度将权力从社区和用户转移给企业守门人。如果我们接受这一点，我们就交出了数字自决的一层基本权利。抵抗——大声地、依法地，并通过构建替代方案来抵抗。&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>密码学信任与 OpenPGP 详解</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/cryptographic-trust-and-openpgp-explained/</link>
            <pubDate>Wed, 18 Feb 2026 19:57:27 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/cryptographic-trust-and-openpgp-explained/</guid>
            <description>&lt;p&gt;在本文中，我将解释密码学信任、OpenPGP、它们如何工作以及它们为何重要。&lt;/p&gt;&#xA;&lt;h2 id=&#34;技术背景数学如何保卫安全与隐私&#34;&gt;技术背景：数学如何保卫安全与隐私&#xA;&lt;/h2&gt;&lt;p&gt;如果你不关心非对称密码学与 OpenPGP 的底层数学原理，仅希望了解如何明智地使用密码学信任，那么你只需知道以下几点：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;非对称密码学指生成两把不同密钥的技术：公钥与私钥。&lt;/li&gt;&#xA;&lt;li&gt;公钥可公开分享；私钥由持有者保管。&lt;/li&gt;&#xA;&lt;li&gt;公钥可用于加密消息，相应的私钥用于解密。&lt;/li&gt;&#xA;&lt;li&gt;私钥可用于对消息进行签名，相应的公钥用于验证签名。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;若只需要实用指导，可以跳过本节剩余内容。&lt;/p&gt;&#xA;&lt;p&gt;对称加密使用同一把密钥进行加密和解密。它可抵抗暴力破解，但存在实际缺点。如果 Alice 和 Bob 使用对称加密互发消息，他们必须先协商一个共享密钥，这通常需要额外的安全通道（例如当面见面）。这不便，而且共享密钥不得泄露——如果 Mallory 得到密钥，保密性就丧失了。&lt;/p&gt;&#xA;&lt;p&gt;非对称密码学在此发挥作用。**非对称方案为加密与解密使用不同的密钥，分别称为公钥和私钥。**公钥可以张贴在个人网站或社交媒体上，因为公钥不足以推导出对应的私钥；私钥则由其持有者保管。&lt;/p&gt;&#xA;&lt;p&gt;精心设计的算法用于生成公私钥对，以保证用公钥加密的数据只能由对应的私钥解密。常见算法包括 RSA、椭圆曲线密码学（ECC）等。&lt;/p&gt;&#xA;&lt;p&gt;RSA 是一种经典的非对称算法，历史悠久。理解 RSA 有助于建立对非对称密码学的直觉。&lt;/p&gt;&#xA;&lt;p&gt;简要地说，RSA 的密钥生成如下：Alice 随机选择两个互异素数 &lt;code&gt;p&lt;/code&gt; 与 &lt;code&gt;q&lt;/code&gt;，计算 &lt;code&gt;n = p * q&lt;/code&gt; 与 &lt;code&gt;Φ(n) = (p - 1) * (q - 1)&lt;/code&gt;，选择一个满足 &lt;code&gt;1 &amp;lt; e &amp;lt; Φ(n)&lt;/code&gt; 且与 &lt;code&gt;Φ(n)&lt;/code&gt; 互质的整数 &lt;code&gt;e&lt;/code&gt;，然后计算 &lt;code&gt;e&lt;/code&gt; 关于 &lt;code&gt;Φ(n)&lt;/code&gt; 的模逆并记为 &lt;code&gt;d&lt;/code&gt;。Alice 的公钥为 &lt;code&gt;(n, e)&lt;/code&gt;，私钥为 &lt;code&gt;(n, d)&lt;/code&gt;。Bob 对消息 &lt;code&gt;m&lt;/code&gt; 进行加密时计算 &lt;code&gt;c = (m ** e) % n&lt;/code&gt; 并把密文 &lt;code&gt;c&lt;/code&gt; 发送给 Alice；Alice 用 &lt;code&gt;m = (c ** d) % n&lt;/code&gt; 恢复原文。&lt;/p&gt;&#xA;&lt;p&gt;有人会问：已知公钥 &lt;code&gt;(n, e)&lt;/code&gt; 是否能算出 &lt;code&gt;d&lt;/code&gt;？要算出 &lt;code&gt;d&lt;/code&gt; 需要 &lt;code&gt;Φ(n)&lt;/code&gt;，而要算出 &lt;code&gt;Φ(n)&lt;/code&gt; 则需知道 &lt;code&gt;p&lt;/code&gt; 和 &lt;code&gt;q&lt;/code&gt;。要从 &lt;code&gt;n&lt;/code&gt; 中恢复 &lt;code&gt;p&lt;/code&gt; 与 &lt;code&gt;q&lt;/code&gt;，必须对 &lt;code&gt;n&lt;/code&gt; 进行因式分解。对于常用的 RSA 密钥长度（例如 4096 位），把 &lt;code&gt;n&lt;/code&gt; 因式分解在当前技术下计算量极大，几乎不可行。这就是 RSA 安全性的基础。&lt;/p&gt;&#xA;&lt;p&gt;ECC 及其他非对称方案依赖不同的困难问题，但它们共享核心原则：应使从公钥推导私钥在计算上极为困难。&lt;/p&gt;&#xA;&lt;p&gt;在实际计算 &lt;code&gt;e&lt;/code&gt; 关于 &lt;code&gt;Φ(n)&lt;/code&gt; 的模逆时，我们选取最小的正整数逆元，该数小于 &lt;code&gt;Φ(n)&lt;/code&gt;。如果 &lt;code&gt;g = gcd(d, Φ(n)) &amp;gt; 1&lt;/code&gt;，则会导致矛盾（因为存在整数 &lt;code&gt;k&lt;/code&gt; 使 &lt;code&gt;e * d + k * Φ(n) = 1&lt;/code&gt;），因此 &lt;code&gt;g&lt;/code&gt; 必须为 1，&lt;code&gt;d&lt;/code&gt; 与 &lt;code&gt;Φ(n)&lt;/code&gt; 互质。这一对称性说明 &lt;code&gt;e&lt;/code&gt; 与 &lt;code&gt;d&lt;/code&gt; 在数学上具有互补性质；尽管理论上可交换，但在实践中签名与加密有不同的使用方式。&lt;/p&gt;&#xA;&lt;p&gt;具体而言，RSA 的签名通常计算 &lt;code&gt;s = m ** d % n&lt;/code&gt;，验证时检查 &lt;code&gt;m == s ** e % n&lt;/code&gt;。在实际的端到端保密与认证中，发送者通常先用私钥对消息签名，再用接收者的公钥对已签名的数据加密；接收者先用自己的私钥解密，再用发送者的公钥验证签名。&lt;/p&gt;&#xA;&lt;h2 id=&#34;什么是密码学信任以及它为何重要&#34;&gt;什么是密码学信任以及它为何重要&#xA;&lt;/h2&gt;&lt;p&gt;全球范围内的监控和审查都影响着通信。除了一些高风险地区外，某些地区（例如欧洲）出现的“聊天监管”等政策也引发广泛关注。使用支持端到端加密的自由软件即时通信工具（如 XMPP、Matrix、SimpleX）至少可以在一定程度上保护通信。非对称密码学能让通信双方在没有预置安全通道的情况下建立安全通道：一个密钥用于加密，另一把用于解密，只有对应私钥的持有者能读取密文。&lt;/p&gt;&#xA;&lt;p&gt;**然而，还有另一个尚未解决的问题。**假设 Alice 和 Bob 想安全地交换公钥以通信，但 Mallory 对中间进行拦截并替换她自己的公钥给双方。Alice 会把 Mallory 的公钥误认为是 Bob 的，而 Bob 也会把 Mallory 的公钥误认为是 Alice 的。于是 Alice 发送一条签名并加密的消息，本应只有 Bob 能得到，但实际上 Mallory 能解密、阅读甚至修改，然后用她自己的私钥重新签名并加密转发给 Bob。Bob 解密并用 Mallory 的公钥验证签名，错误地认为消息来自 Alice。如此一来，端到端加密的保密性和真实性都被 Mallory 破坏了。&lt;/p&gt;&#xA;&lt;p&gt;要解决这个问题，Alice 需要有办法验证她所持有的公钥确实属于 Bob。这通常也需要一个安全的通信渠道（例如当面核验）。我们称 &lt;strong&gt;将公钥归属验证为建立密码学信任&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;一旦 Alice 与 Bob 之间建立了密码学信任，除非能从公钥推导出对应的私钥，否则 Mallory 很难冒充 Bob。&lt;/p&gt;&#xA;&lt;h2 id=&#34;密码学信任的核心原则身份一致性验证&#34;&gt;密码学信任的核心原则：身份一致性验证&#xA;&lt;/h2&gt;&lt;p&gt;上文情形是密码学信任建立的基本示例。你可以在身份间构建非常庞大的信任网络，但核心原则十分简单：通过验证某个身份与另一个已被信任的身份是否一致来建立对该身份的密码学信任。&lt;/p&gt;&#xA;&lt;p&gt;在密码学中，公钥对应一个身份。这一点非常重要：&lt;strong&gt;记住：公钥 = 身份&lt;/strong&gt;（在基于密钥的信任语境下）。&lt;/p&gt;&#xA;&lt;p&gt;身份一致性的验证一般包括两步：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;让身份 A 提出一个有保证的声明，说明身份 B 与 A 一致；&lt;/li&gt;&#xA;&lt;li&gt;让身份 B 提出一个有保证的声明，说明身份 A 与 B 一致。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;例如，如果 Alice 想验证某把公钥的持有者确为 Bob，她会与 Bob 当面核验该公钥的指纹。Alice 也可以要求 Bob 使用私钥对一段文本签名（例如 “I am Bob” 或者由 Alice 随机生成的挑战字符串）。通过这种方式，Alice 就在该公钥上建立了密码学信任，从而信任该公钥所代表的身份。&lt;/p&gt;&#xA;&lt;p&gt;现在再看另一种情形：已知公钥 A 的身份是可信的（它确属 Bob），另有一个预期也属于 Bob 的公钥 B，Alice 想验证 B。由于她已信任 A，便无需再次与 Bob 当面核验。她只需验证 A 与 B 之间的一致性——通常通过双方相互签署包含对方指纹的声明来完成：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;由与 A 对应的私钥签署一段包含 B 指纹的文本；&lt;/li&gt;&#xA;&lt;li&gt;由与 B 对应的私钥签署一段包含 A 指纹的文本。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;如此便可验证 A 与 B 的一致性，从而对 B 建立信任。&lt;/p&gt;&#xA;&lt;h2 id=&#34;首先信任哪个身份&#34;&gt;首先信任哪个身份？&#xA;&lt;/h2&gt;&lt;p&gt;密码学信任的建立过程依赖于一个已被信任的身份。但你刚认识的人并没有可信身份。常见做法是对首次接触的身份先盲目信任，这称为 &lt;strong&gt;ToFU（Trust on First Use）&lt;/strong&gt;，首次被盲目信任的身份就是 &lt;strong&gt;initial identity&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;例如，若 Alice 与 Bob 当面相识，Alice 首先信任的是“生物学上的 Bob”。若他们在 Matrix 社区首次接触，初始信任的就是 Bob 的 Matrix 账户及其公钥。若在 XMPP 上见面，Alice 可能信任 Bob 首条消息中的 OMEMO 指纹。&lt;/p&gt;&#xA;&lt;p&gt;这是一种合理的实践：当你决定与从网络上认识的朋友见面时，通常会通过你用来认识对方的通信工具来核验对方。&lt;/p&gt;&#xA;&lt;h2 id=&#34;常见的密码学信任实践&#34;&gt;常见的密码学信任实践&#xA;&lt;/h2&gt;&lt;p&gt;通过验证身份之间的一致性，Alice 构建了一张&lt;em&gt;图&lt;/em&gt;：身份为&lt;em&gt;顶点&lt;/em&gt;，保证的一致性为&lt;em&gt;边&lt;/em&gt;。与 Bob 的初始身份相连的那个连通分量的所有顶点，都是 Bob 的受信任身份。&lt;/p&gt;&#xA;&lt;p&gt;按照建立图的方式，有几类常见实践：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;不受限的信任链/网络。&lt;/strong&gt; 任意受信任的身份可用于通过验证一致性来建立对未受信任身份的信任，信任链/网络可以自由生长。&lt;br&gt;&#xA;优点：方便；丢失联系时更不易导致失联。&lt;br&gt;&#xA;缺点：对冒充的鲁棒性最低；从初始身份到其他身份的某些信任链可能很长；若某一身份被攻破，会连带影响很多其他身份。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;以初始身份为中心。&lt;/strong&gt; 只有初始身份能用于通过验证一致性来建立对新身份的信任。&lt;br&gt;&#xA;优点：如果初始身份可靠，信任非常稳固；从初始身份到其它身份的信任链长度均为一，整体网络更难被攻破。&lt;br&gt;&#xA;缺点：若初始身份不强或不可用，就无法建立稳固的密码学信任；单点故障问题明显。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;以唯一密码学身份为中心。&lt;/strong&gt; 初始身份先对一个唯一的密码学身份（通常为一对密钥）建立信任，此后仅用该密码学身份来对其它未信任身份进行一致性验证。&lt;strong&gt;这也是我的策略，我使用 OpenPGP 作为密码学解决方案。&lt;/strong&gt;&lt;br&gt;&#xA;优点：在确保中心身份稳健与保持较短信任链之间取得较好平衡。&lt;br&gt;&#xA;缺点：仍存在单点故障：一旦中心密钥被攻破，后果严重。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h2 id=&#34;基于密码学的一种常见身份验证方法挑战-响应&#34;&gt;基于密码学的一种常见身份验证方法：挑战-响应&#xA;&lt;/h2&gt;&lt;p&gt;若 Alice 已信任 Bob 的某把公钥，但想验证某个实体确为该私钥的持有者，可采用&lt;strong&gt;挑战-响应&lt;/strong&gt;（Challenge–Response）：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Alice 生成一个随机字符串，称为“挑战”。&lt;/li&gt;&#xA;&lt;li&gt;Alice 将挑战发送给 Bob，Bob 使用私钥对该文本签名。&lt;/li&gt;&#xA;&lt;li&gt;Bob 将签名返回，Alice 使用公钥验证签名。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;挑战在生成后不必保密，但应具有不可预测性和唯一性。若签名有效，则 Alice 成功验证对方确为私钥持有者。&lt;/p&gt;&#xA;&lt;h2 id=&#34;关于维护密码学信任的非常重要的一点不要泄露你的私钥&#34;&gt;关于维护密码学信任的非常重要的一点：不要泄露你的私钥！&#xA;&lt;/h2&gt;&lt;p&gt;密码学信任的安全性和鲁棒性基于私钥的安全与保密。泄露私钥就等于泄露信任。&lt;/p&gt;&#xA;&lt;p&gt;因此，&lt;strong&gt;尽量不要泄露你的私钥&lt;/strong&gt;！一旦私钥被泄露，他人对你的信任 &lt;strong&gt;将不再有效&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;尤其是使用 OpenPGP 管理信任的人，&lt;strong&gt;请务必将你的 OpenPGP 私钥保密至最高级别！&lt;/strong&gt; 将私钥存放在硬件令牌上（例如 Nitrokey、CanoKey 或 YubiKey）是良好做法；如果不能，则至少将私钥保存在运行 100% 自由软件的设备上。&lt;/p&gt;&#xA;&lt;h2 id=&#34;openpgp-及其自由软件实现&#34;&gt;OpenPGP 及其自由软件实现&#xA;&lt;/h2&gt;&lt;p&gt;OpenPGP 不是某个软件，而是一项标准。它定义了一种将若干原始密钥对封装并组织在一起的格式，便于用于加密、签名、认证等。OpenPGP 支持 RSA、ECC 与其它算法。&lt;/p&gt;&#xA;&lt;p&gt;以 GnuPG 为例说明如何使用 OpenPGP：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&lt;strong&gt;生成密钥&lt;/strong&gt;：运行 &lt;code&gt;gpg --full-generate-key&lt;/code&gt; 并按提示操作。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;加密&lt;/strong&gt;：运行 &lt;code&gt;gpg --encrypt&lt;/code&gt;。可将要加密的内容通过标准输入传入（若为文件可用 &lt;code&gt;cat &amp;lt;filename&amp;gt; | gpg --encrypt&lt;/code&gt;）。生成的密文将输出到标准输出，默认是二进制，建议用重定向保存为文件。若需文本形式的加密结果，请使用 &lt;code&gt;gpg --encrypt --armor&lt;/code&gt;。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;文本签名&lt;/strong&gt;：运行 &lt;code&gt;gpg --clear-sign&lt;/code&gt;，将要签名的文本通过标准输入输入，完成后按 Ctrl+D。签名的文本将输出到标准输出。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;解密/验证&lt;/strong&gt;：运行 &lt;code&gt;gpg --decrypt&lt;/code&gt;，将加密或签名的数据通过标准输入提供。解密后的数据输出到标准输出，验证结果会输出到标准错误。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;在 GNU/Linux、*BSD、Windows 和 macOS 上，最常用的实现是 GnuPG，其图形前端有 Kleopatra。Android 上较为流行的是 OpenKeychain。&lt;/p&gt;&#xA;&lt;p&gt;详细使用指南超出本文范围，请查阅相关文档与检索资料。FSF 的 Email Self-Defense Guide 是一个不错的起点；欲深入学习可参考 GnuPG 官方手册、FSFE 的 OpenPGP 指南与 KDE 的入门文档。&lt;/p&gt;&#xA;&lt;h2 id=&#34;如何用-openpgp-加密电子邮件&#34;&gt;如何用 OpenPGP 加密电子邮件&#xA;&lt;/h2&gt;&lt;p&gt;自由软件的邮件客户端（例如 Thunderbird）内建 OpenPGP 支持，可以无缝地对邮件进行加密、解密与签名验证。像 Mailvelope 这样的浏览器扩展可以将 OpenPGP 集成到 webmail 中，使在 webmail 服务上使用加密邮件更为便捷。&lt;/p&gt;&#xA;&lt;p&gt;请查阅对应工具的文档以了解具体操作方法。&lt;/p&gt;&#xA;&lt;h2 id=&#34;如何用-openpgp-建立密码学信任&#34;&gt;如何用 OpenPGP 建立密码学信任&#xA;&lt;/h2&gt;&lt;p&gt;使用 OpenPGP 建立信任思路很简单：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;索要对方的 OpenPGP 公钥。&lt;/li&gt;&#xA;&lt;li&gt;验证该密钥与对方的初始身份是否一致；从而在该公钥上建立信任。&lt;/li&gt;&#xA;&lt;li&gt;未来在验证对方其他身份时，校验这些身份与该 OpenPGP 公钥的一致性。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h2 id=&#34;结语拥抱自由软件并明智使用&#34;&gt;结语：拥抱自由软件，并明智使用&#xA;&lt;/h2&gt;&lt;p&gt;多亏自由软件社区，我们已拥有许多稳健工具。学会使用这些工具，我们便拥有能力来捍卫安全、隐私与数字权利，保护自己免受各种威胁、监控与审查。&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>强制实施加密信任建立</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/enforcing-cryptographic-trust-establishment/</link>
            <pubDate>Thu, 05 Feb 2026 23:03:34 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/enforcing-cryptographic-trust-establishment/</guid>
            <description>&lt;p&gt;出于安全考虑，自 &lt;code&gt;2026-02-24T00:00:00Z&lt;/code&gt; 起，我将要求与我所有联系人之间建立加密信任。如果您在该时间之前未与我建立加密信任，我将不再视您的身份为可信。&lt;/p&gt;&#xA;&lt;p&gt;如果您没有安全设备（例如硬件令牌或运行 100% 自由软件的计算机），将 OpenPGP 密钥对存放在不安全的设备上在当前是可以接受的，因为总比没有好。&lt;/p&gt;&#xA;&lt;p&gt;对于不熟悉加密信任或 OpenPGP 的人，我会发布一篇博客文章进行详细说明。下面是您现在可以立即采用的简要指南：&lt;/p&gt;&#xA;&lt;h2 id=&#34;gnulinux&#34;&gt;GNU/Linux&#xA;&lt;/h2&gt;&lt;h3 id=&#34;生成-openpgp-密钥对&#34;&gt;生成 OpenPGP 密钥对&#xA;&lt;/h3&gt;&lt;h4 id=&#34;图形界面方法&#34;&gt;图形界面方法&#xA;&lt;/h4&gt;&lt;ol&gt;&#xA;&lt;li&gt;如果尚未安装，请安装 GnuPG 和 Kleopatra。&lt;/li&gt;&#xA;&lt;li&gt;打开 Kleopatra，点击 &lt;em&gt;New Key Pair&lt;/em&gt;。&lt;/li&gt;&#xA;&lt;li&gt;输入您的姓名和电子邮件，勾选 &lt;em&gt;Protect the generated key with a passphrase&lt;/em&gt;，然后点击 &lt;em&gt;OK&lt;/em&gt;。&lt;/li&gt;&#xA;&lt;li&gt;选择一个强口令以保护您的私钥。&lt;/li&gt;&#xA;&lt;li&gt;双击您生成的密钥，点击 &lt;em&gt;Export&lt;/em&gt;，即可看到您的公钥。复制从 &lt;code&gt;-----BEGIN PGP PUBLIC KEY BLOCK-----&lt;/code&gt; 到 &lt;code&gt;-----END PGP PUBLIC KEY BLOCK-----&lt;/code&gt; 的全部内容。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;GNU/Linux Generate OpenPGP Keypair Graphical Method&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;156px&#34; data-flex-grow=&#34;65&#34; height=&#34;1584&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://rebel1725.codeberg.page/images/pic_20260205_001.png&#34; srcset=&#34;https://rebel1725.codeberg.page/blog/pic_20260205_001_2537265924503396062_hu_6833c83b55e3686f.png 800w, https://rebel1725.codeberg.page/images/pic_20260205_001.png 1032w&#34; width=&#34;1032&#34;&gt;&lt;/p&gt;&#xA;&lt;h4 id=&#34;命令行方法&#34;&gt;命令行方法&#xA;&lt;/h4&gt;&lt;ol&gt;&#xA;&lt;li&gt;如果尚未安装，请安装 GnuPG。&lt;/li&gt;&#xA;&lt;li&gt;运行 &lt;code&gt;gpg --generate-key&lt;/code&gt;。&lt;/li&gt;&#xA;&lt;li&gt;输入您的真实姓名。&lt;/li&gt;&#xA;&lt;li&gt;输入您的电子邮件地址。&lt;/li&gt;&#xA;&lt;li&gt;输入 &lt;code&gt;O&lt;/code&gt; 并按回车。&lt;/li&gt;&#xA;&lt;li&gt;选择一个强口令以保护您的私钥。&lt;/li&gt;&#xA;&lt;li&gt;运行 &lt;code&gt;gpg --export --armor &amp;lt;your-email-address&amp;gt;&lt;/code&gt;（或者更好地，使用 &lt;code&gt;gpg --export --armor &amp;lt;your-key-id&amp;gt;&lt;/code&gt; 或 &lt;code&gt;gpg --export --armor &amp;lt;your-fingerprint&amp;gt;&lt;/code&gt;）。您将看到您的公钥。复制从 &lt;code&gt;-----BEGIN PGP PUBLIC KEY BLOCK-----&lt;/code&gt; 到 &lt;code&gt;-----END PGP PUBLIC KEY BLOCK-----&lt;/code&gt; 的全部内容。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h3 id=&#34;签名文本&#34;&gt;签名文本&#xA;&lt;/h3&gt;&lt;h4 id=&#34;图形界面方法-1&#34;&gt;图形界面方法&#xA;&lt;/h4&gt;&lt;ol&gt;&#xA;&lt;li&gt;打开 Kleopatra，点击 &lt;em&gt;Notepad&lt;/em&gt;。&lt;/li&gt;&#xA;&lt;li&gt;取消勾选 &lt;em&gt;Encrypt for me&lt;/em&gt;。&lt;/li&gt;&#xA;&lt;li&gt;将要签名的文本粘贴或输入，然后点击 &lt;em&gt;Sign Notepad&lt;/em&gt;。&lt;/li&gt;&#xA;&lt;li&gt;签名后的文本会出现在输入框中。选中它（Ctrl+A），然后剪切（Ctrl+X）。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;GNU/Linux Sign Texts Graphical Method&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;493px&#34; data-flex-grow=&#34;205&#34; height=&#34;528&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://rebel1725.codeberg.page/images/pic_20260205_002.png&#34; srcset=&#34;https://rebel1725.codeberg.page/blog/pic_20260205_002_15476778197840011415_hu_df135c0e76fe18ca.png 800w, https://rebel1725.codeberg.page/images/pic_20260205_002.png 1085w&#34; width=&#34;1085&#34;&gt;&lt;/p&gt;&#xA;&lt;h4 id=&#34;命令行方法-1&#34;&gt;命令行方法&#xA;&lt;/h4&gt;&lt;ol&gt;&#xA;&lt;li&gt;运行 &lt;code&gt;gpg --clear-sign&lt;/code&gt;。&lt;/li&gt;&#xA;&lt;li&gt;粘贴或输入要签名的文本，然后按 Ctrl+D（可能需要按两次）。&lt;/li&gt;&#xA;&lt;li&gt;在终端中复制从 &lt;code&gt;-----BEGIN PGP SIGNED MESSAGE-----&lt;/code&gt; 到 &lt;code&gt;-----END PGP SIGNATURE-----&lt;/code&gt; 的文本。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h2 id=&#34;android&#34;&gt;Android&#xA;&lt;/h2&gt;&lt;h3 id=&#34;生成-openpgp-密钥对-1&#34;&gt;生成 OpenPGP 密钥对&#xA;&lt;/h3&gt;&lt;ol&gt;&#xA;&lt;li&gt;在手机上从 F-Droid 安装 OpenKeychain。&lt;/li&gt;&#xA;&lt;li&gt;打开 OpenKeychain，点击 &lt;em&gt;CREATE MY KEY&lt;/em&gt;。&lt;/li&gt;&#xA;&lt;li&gt;输入您的姓名，点击 &lt;em&gt;NEXT&lt;/em&gt;。&lt;/li&gt;&#xA;&lt;li&gt;输入您的电子邮件，点击 &lt;em&gt;NEXT&lt;/em&gt;。&lt;/li&gt;&#xA;&lt;li&gt;暂时不要将密钥上传到密钥服务器。点击 &lt;em&gt;CREATE KEY&lt;/em&gt;。&lt;/li&gt;&#xA;&lt;li&gt;点击刚生成的密钥，然后点击复制图标将公钥复制到剪贴板。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;Android Generate OpenPGP Keypair Graphical Method&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;161px&#34; data-flex-grow=&#34;67&#34; height=&#34;4824&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://rebel1725.codeberg.page/images/pic_20260205_003.png&#34; srcset=&#34;https://rebel1725.codeberg.page/blog/pic_20260205_003_12331027108194943103_hu_8b5551a8e13d19f7.png 800w, https://rebel1725.codeberg.page/blog/pic_20260205_003_12331027108194943103_hu_7268a22ab4cad8c2.png 1600w, https://rebel1725.codeberg.page/blog/pic_20260205_003_12331027108194943103_hu_b128ee211d5db59a.png 2400w, https://rebel1725.codeberg.page/images/pic_20260205_003.png 3240w&#34; width=&#34;3240&#34;&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;签名文本-1&#34;&gt;签名文本&#xA;&lt;/h3&gt;&lt;ol&gt;&#xA;&lt;li&gt;打开 OpenKeychain，打开菜单 → &lt;em&gt;Encrypt/Decrypt&lt;/em&gt; → &lt;em&gt;Encrypt text&lt;/em&gt;。&lt;/li&gt;&#xA;&lt;li&gt;打开菜单并取消勾选 &lt;em&gt;Encrypt to signer&lt;/em&gt;。&lt;/li&gt;&#xA;&lt;li&gt;粘贴或输入要签名的文本，点击复制图标将签名后的文本复制到剪贴板。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;Android Sign Texts Graphical Method&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;537px&#34; data-flex-grow=&#34;223&#34; height=&#34;2412&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://rebel1725.codeberg.page/images/pic_20260205_004.png&#34; srcset=&#34;https://rebel1725.codeberg.page/blog/pic_20260205_004_1309102790140517099_hu_8cb33717ae91b70b.png 800w, https://rebel1725.codeberg.page/blog/pic_20260205_004_1309102790140517099_hu_d4f132df9c14eaf5.png 1600w, https://rebel1725.codeberg.page/blog/pic_20260205_004_1309102790140517099_hu_85066c6d213d3a98.png 2400w, https://rebel1725.codeberg.page/images/pic_20260205_004.png 5400w&#34; width=&#34;5400&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;microsoft-windows&#34;&gt;Microsoft Windows&#xA;&lt;/h2&gt;&lt;p&gt;下载并安装 Gpg4win。打开计算机上的 Kleopatra。其余步骤与上述 GNU/Linux 图形界面方法相同。&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>My Retro-Style Website Is Refreshed as Well</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/my-retro-style-website-is-refreshed-as-well/</link>
            <pubDate>Tue, 03 Feb 2026 21:03:52 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/my-retro-style-website-is-refreshed-as-well/</guid>
            <description>&lt;p&gt;在完成现代风格网站的更新后，我的复古风格网站也已经更新完成，并且现在支持多种语言。&lt;/p&gt;&#xA;&lt;p&gt;点击这里访问我的复古风格网站：&lt;a class=&#34;link&#34; href=&#34;https://tilde.club/~rebel1725/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;https://tilde.club/~rebel1725/&lt;/a&gt;&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>焕然一新的个人网站已上线！</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/refreshed-website-is-here/</link>
            <pubDate>Sat, 31 Jan 2026 15:25:47 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/refreshed-website-is-here/</guid>
            <description>&lt;p&gt;新年伊始，我的现代个人网站已完成改版并正式上线。&lt;/p&gt;&#xA;&lt;p&gt;首页经过重新设计，更加信息化，一目了然地展示近期博文、标签（tags）、联系方式、常用链接和博客推荐。我的博客现已采用 Stack Hugo 主题（Stack Hugo theme），更为简洁优雅并提供更多功能。&lt;/p&gt;&#xA;&lt;p&gt;访问我焕然一新的个人网站： &lt;a class=&#34;link&#34; href=&#34;https://rebel1725.codeberg.page/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;https://rebel1725.codeberg.page/&lt;/a&gt;&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>我将抵制 Fosstodon，以及你为什么也应该抵制它</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/i-am-to-boycott-fosstodon-and-why-you-should-boycott-it-too/</link>
            <pubDate>Wed, 28 Jan 2026 14:12:18 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/i-am-to-boycott-fosstodon-and-why-you-should-boycott-it-too/</guid>
            <description>&lt;p&gt;由于对 Fosstodon 的审核制度感到极度失望——他们多次仅仅因为我建议他人避开专有浏览器 Vivaldi 就向我发出警告——我将不再使用该实例。我已经在 hostux.social 创建了新账号，将所有数据迁移过去，并设置了重定向。&lt;/p&gt;&#xA;&lt;p&gt;在本文中，我将解释我为何做出这一决定，以及你为什么也应该离开 Fosstodon。&lt;/p&gt;&#xA;&lt;h2 id=&#34;最直接也是最重要的原因以foss之名推广专有恶意软件与间谍软件&#34;&gt;最直接、也是最重要的原因：以“FOSS”之名推广专有恶意软件与间谍软件&#xA;&lt;/h2&gt;&lt;p&gt;Fosstodon 是一个以自由（libre）软件为主题的 Mastodon 实例。然而，无论是行为准则还是服务器规则，都没有禁止对专有软件的推广。这是一种历史与概念的篡改。&lt;/p&gt;&#xA;&lt;p&gt;更荒谬的是，电子邮件服务商 Tuta 竟通过其 Mastodon 账号推广专有浏览器 Vivaldi——而我认为它是恶意的、专有的间谍软件。这种行为并未触发任何审核措施。真正导致我多次收到 Fosstodon 审核警告的，是&lt;a class=&#34;link&#34; href=&#34;https://fosstodon.org/@rebel1725/115926697577288866&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;我提醒他人应当避开专有软件的回复&lt;/a&gt;。&lt;/p&gt;&#xA;&lt;h2 id=&#34;受-fosstodon-审核制度伤害的并不只有我&#34;&gt;受 Fosstodon 审核制度伤害的并不只有我&#xA;&lt;/h2&gt;&lt;p&gt;这并非个别抱怨。多年来，一个不透明、强硬的审核模式已经逐渐形成：长期贡献者的账号在没有清晰、公开说明的情况下被冻结或封禁。2023 年中期，&lt;a class=&#34;link&#34; href=&#34;https://discussion.fedoraproject.org/t/move-mastodon-account-off-of-fosstodon/87843&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;多名 Fedora 社区成员报告称，其账号遭到实例级封禁，切断了多年积累的关注关系与对话&lt;/a&gt;；这些移除行为几乎没有透明度，理由也极其有限。试图提出质疑的用户，往往只得到管理员简短而冷漠的回应，或是悄无声息的账号冻结，而非有理有据、可被审视的流程。&lt;/p&gt;&#xA;&lt;p&gt;一个以自由与协作为原则建立的社区，却将自己的成员当作负担——在缺乏问责的情况下将其噤声、冻结或排挤——这是背叛。有人离开了，官方项目账号考虑迁移，新注册被设置门槛。这些都不是一个健康、联邦化社区的行为；它们更像是一个把控制误认为“正直”的封闭俱乐部。&lt;/p&gt;&#xA;&lt;h2 id=&#34;fosstodon-的审核员是右翼分子和法西斯&#34;&gt;Fosstodon 的审核员是右翼分子和法西斯&#xA;&lt;/h2&gt;&lt;p&gt;这一指控之所以直白，是因为证据同样直白。2025 年 4 月下旬，一名审核员——在社区中以其账号名广为人知——被揭露曾在其他平台上&lt;a class=&#34;link&#34; href=&#34;https://kevquirk.com/blog/my-thoughts-on-the-fosstodon-drama#:~:text=and%20I%20wish%20him%20luck,it%27s%20a%20great%20instance&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;发表极右翼、反跨性别和排外主义言论&lt;/a&gt;。这一揭露迅速引爆舆论：用户要求将其移除；管理员犹豫不决；直到风波全面爆发之后，该审核员才删除账号并退出审核团队。&lt;/p&gt;&#xA;&lt;p&gt;无论你更倾向于使用“右翼”这一标签，还是更严厉的“法西斯”，关键事实并未改变：一名被赋予塑造社区规范之权力的审核员，公开表达了许多用户合理地认为会威胁边缘群体安全的观点。真正的丑闻不仅在于这些观点的存在，更在于机构最初不愿果断应对，以及对提出关切者的受害者指责。Fosstodon 最初的处理方式，纵容了一种“可否认性文化”——有毒的信念可以躲在审核徽章之后，直到被强行拖到阳光下。&lt;/p&gt;&#xA;&lt;p&gt;必须说清楚：容忍、庇护，或未能及时、透明地处理宣扬仇恨或排他性言论的审核员，都会摧毁任何“自由软件价值堡垒”的自我宣称。如果把守大门的人都能容忍带有法西斯倾向的审核行为，那么普通用户又如何指望获得一个安全、守原则的空间？&lt;/p&gt;&#xA;&lt;h2 id=&#34;fosstodon-反对联邦化&#34;&gt;Fosstodon 反对联邦化&#xA;&lt;/h2&gt;&lt;p&gt;Fosstodon 的政策与实践多次违背了联邦化精神。请看这样一组模式：在全球性服务器上强制只允许英语；2023 年转为仅限邀请注册；严厉的审核引发关于断联（defederation）的讨论；以及一种压制公开讨论的官方沟通风格。这些并非中立的技术选择——它们是看门与排他机制。&lt;/p&gt;&#xA;&lt;p&gt;当管理员在社区出现摩擦时选择上锁，而不是推动透明、民主的流程，他们就将服务器推离了联邦化的理想。事实上，在多次危机中，其他实例广泛讨论甚至威胁与 Fosstodon 断联。尽管主要实例并未一致切断关系，但大量联邦宇宙成员考虑将其孤立的事实，已经说明 Fosstodon 积累了多么严重的声誉损害。强制英语、限制注册、在缺乏公开问责的情况下实施大规模封禁，都会削弱联邦化——它们集中权力，而权力集中正是联邦化试图避免的东西。&lt;/p&gt;&#xA;&lt;h2 id=&#34;其他问题&#34;&gt;其他问题&#xA;&lt;/h2&gt;&lt;p&gt;不满的清单远比 Fosstodon 的公开声明愿意承认的要长。一些反复出现、值得注意的问题包括：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;不透明的管理。&lt;/strong&gt; 多次封禁与冻结是在私下审核备注的基础上进行，几乎没有公开理由。隐私很重要，但秘密并不等同于问责。结果是：谣言、怨恨，以及信任的崩塌。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;执法不一致。&lt;/strong&gt; 高知名度账号和机构性角色有时得以免于审查，而普通用户却因轻微得多的行为受到惩罚。双重标准的观感具有腐蚀性；它推动用户迁移，并削弱管理员所宣称的一切道德权威。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;创始人的语气与领导失败。&lt;/strong&gt; 早在 2019 年，一名创始人在公开场合将他人称为“snowflakes（玻璃心）”，就暴露出一种与细致治理多元社区完全不相容的态度。随后，在 2025 年审核员丑闻中，创始人承认精疲力竭并在压力下退居幕后；这一领导真空放大了损害。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;政策漂移。&lt;/strong&gt; Fosstodon 最初是自由软件爱好者的避风港。随着时间推移，一系列政策变化——从仅限英语，到邀请制注册，再到更严苛的审核——以许多用户感到疏离的方式改变了其文化。缺乏清晰论证与正当性说明的政策，必然会被体验为任意专断。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;总结&#34;&gt;总结&#xA;&lt;/h2&gt;&lt;p&gt;Fosstodon &lt;em&gt;曾经&lt;/em&gt; 是一个优秀的 Mastodon 实例。残酷而犬儒的现实是：一个建立在自由之上的社区，正被威权式审核、不透明的治理，以及不一致的规则执行逐步掏空。一边容许（或曾容许）推广侵犯隐私的专有软件，一边打压那些发出警告的人，这种赤裸裸的虚伪几乎已经成为表演。&lt;/p&gt;&#xA;&lt;p&gt;如果你在乎自由软件，在乎诚实的联邦空间，在乎真正践行其所宣称价值的社区——那就离开吧。迁移你的账号。支持更健康的实例。抵制那些假装自由、却容忍专有软件推广并庇护问题审核员的平台。不要让一个自负的单一服务器替我们所有人定义联邦宇宙。&lt;/p&gt;&#xA;&lt;p&gt;现在正是离开、出走、并进行抵制的时候。&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>我回来了</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/i-am-back/</link>
            <pubDate>Wed, 07 Jan 2026 15:49:06 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/i-am-back/</guid>
            <description>&lt;p&gt;在离线超过六天后，我终于有时间准备我的即时通讯账户并重新上线。发布完这篇博客文章后，我将立即准备好所有即时通讯账户（XMPP、Matrix、SimpleX、Delta Chat 和 Tox），并与我所有的联系人重新建立联系。预计这一过程将在 12 小时内完成（在 &lt;code&gt;2026-01-07T20:30:00Z&lt;/code&gt; 之前）。请留意你的即时通讯账户！&lt;/p&gt;&#xA;&lt;p&gt;如果你在此时之前没有收到我的消息，可能是我错过了你的联系信息。请立即&lt;a class=&#34;link&#34; href=&#34;getting-connected&#34; &gt;在此&lt;/a&gt;操作！&lt;/p&gt;&#xA;&lt;p&gt;我的 OpenPGP 密钥仍然有效，我也拥有你们所有人的密钥环。我们将在重新建立联系后相互验证身份。&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>建立联系</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/getting-connected/</link>
            <pubDate>Wed, 07 Jan 2026 15:27:34 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/getting-connected/</guid>
            <description>&lt;p&gt;出于安全、隐私、匿名性以及组织管理的考虑，自 2026 年 1 月起，我开始使用多个 Jabber ID、Matrix ID、SimpleX 个人资料和 Delta Chat 个人资料。我将不再在网站上公开发布这些账号。相反，我制作了一个表单来收集&lt;em&gt;你的&lt;/em&gt;联系方式，并根据情况选择合适的账号与你建立联系。&lt;/p&gt;&#xA;&lt;p&gt;我使用 XMPP、Matrix、SimpleX 和 Delta Chat。在继续之前，请确保你至少拥有其中一种协议的账户。&lt;/p&gt;&#xA;&lt;h2 id=&#34;联系信息表单&#34;&gt;联系信息表单&#xA;&lt;/h2&gt;&lt;p&gt;为了符合 GDPR 要求，我撰写了&lt;a class=&#34;link&#34; href=&#34;../contact-information-form-privacy-policy&#34; &gt;隐私政策&lt;/a&gt;。在提交你的联系信息之前，请仔细阅读隐私政策。提交表单即表示你同意该隐私政策。&lt;/p&gt;&#xA;&lt;p&gt;你可以通过 &lt;strong&gt;两种方法&lt;/strong&gt; 向我提交你的联系信息：&lt;/p&gt;&#xA;&lt;h3 id=&#34;方法一推荐&#34;&gt;方法一（推荐）&#xA;&lt;/h3&gt;&lt;p&gt;在此下载&lt;a class=&#34;link&#34; href=&#34;https://codeberg.org/rebel1725/contact-info-interactive/src/branch/main/contact-info-interactive.py&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Python 脚本&lt;/a&gt;。该交互式脚本会向你提问，并生成一个 &lt;em&gt;blob&lt;/em&gt;。你需要将这个 blob 发送至我的电子邮箱：[rebel1725@autistici.org]。尽可能使用 OpenPGP 加密；你可以在&lt;a class=&#34;link&#34; href=&#34;https://keys.openpgp.org/vks/v1/by-fingerprint/696A423E9993D727706AA733BCD5DC5659C7FB50&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;这里&lt;/a&gt;下载我的 OpenPGP 公钥。&lt;/p&gt;&#xA;&lt;p&gt;如果你希望隐藏社交活动，请使用 Tor、一次性邮箱，并使用未签名的 OpenPGP 加密。我推荐 &lt;a class=&#34;link&#34; href=&#34;https://z.org/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;z.org&lt;/a&gt;，因为注册时无需现有邮箱或与个人身份相关的信息。我未来可能会准备一个专门用于接收表单的 XMPP 账号（watchdog），届时你可以使用一次性 XMPP 账号，这会更加方便。&lt;/p&gt;&#xA;&lt;h3 id=&#34;方法二更方便但存在隐私风险&#34;&gt;方法二（更方便但存在隐私风险）&#xA;&lt;/h3&gt;&lt;p&gt;你也可以通过 Formbricks &lt;a class=&#34;link&#34; href=&#34;https://app.formbricks.com/s/cmk3fu8qe9rblad01ahz1zrqw&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;这里&lt;/a&gt;提交你的联系信息。该方法使用更方便，但可能损害隐私，因为你的数据将会被第三方访问，并且你无法隐藏我们的社交活动。&lt;/p&gt;&#xA;&lt;p&gt;通过任意一种方法提交你的联系信息后，我会尽快与你取得联系，通常在 48 小时内。&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>联系信息表隐私政策</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/contact-information-form-privacy-policy/</link>
            <pubDate>Wed, 07 Jan 2026 11:32:06 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/contact-information-form-privacy-policy/</guid>
            <description>&lt;h2 id=&#34;数据控制者&#34;&gt;数据控制者&#xA;&lt;/h2&gt;&lt;p&gt;如果您通过 Python 脚本、电子邮件和 OpenPGP 加密提交联系信息表格，则唯一的数据控制者将是我，Rebel Zhang，OpenPGP 公钥持有者，指纹为 696A423E9993D727706AA733BCD5DC5659C7FB50。&lt;/p&gt;&#xA;&lt;p&gt;如果您发送未加密的电子邮件，则我的电子邮件服务提供商 Autistici/Inventati 以及您的电子邮件服务提供商可能也能读取数据。请参考您的电子邮件服务提供商的隐私政策，以及 &lt;a class=&#34;link&#34; href=&#34;https://www.autistici.org/who/privacy-policy.en&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Autistici/Inventati 的隐私政策&lt;/a&gt;。&lt;/p&gt;&#xA;&lt;p&gt;如果您通过 Formbricks 提交表单，则 Formbricks 也能访问数据。请参阅 &lt;a class=&#34;link&#34; href=&#34;https://formbricks.com/privacy-policy&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Formbricks 的隐私政策&lt;/a&gt;。&lt;/p&gt;&#xA;&lt;h2 id=&#34;收集的数据和目的&#34;&gt;收集的数据和目的&#xA;&lt;/h2&gt;&lt;p&gt;通过提交联系信息表格，我，Rebel Zhang，收集以下个人数据，并用于以下目的：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&lt;strong&gt;姓名/昵称&lt;/strong&gt;（必填）：用于识别联系人管理。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;OpenPGP 公钥&lt;/strong&gt;（可选）：用于验证您的身份并加密未来的通信。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;电子邮件&lt;/strong&gt;（必填）：用于未来与您联系。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;首选联系方法和联系信息&lt;/strong&gt;（必填）：用于未来与您联系。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;OpenPGP 安全性和设备安全性情况&lt;/strong&gt;（必填）：用于评估我们通信的安全性。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;首选语言、代词、时区、自我介绍&lt;/strong&gt;（可选）和 &lt;strong&gt;是否隐藏社交活动的偏好&lt;/strong&gt;（必填，条件性）：用于选择适当的沟通方式。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;表单创建日期&lt;/strong&gt;（自动存储）：用于将来的分析。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h2 id=&#34;保留期&#34;&gt;保留期&#xA;&lt;/h2&gt;&lt;p&gt;您的姓名/昵称、OpenPGP 公钥、电子邮件、首选语言、代词和时区将保存在我的个人设备上的联系人簿中。&lt;/p&gt;&#xA;&lt;p&gt;Blob 本身可能以未加密的形式存储在我的个人设备上，并在我的电子邮件服务提供商 Autistici/Inventati 的服务器上加密存储。&lt;/p&gt;&#xA;&lt;p&gt;上述数据将无限期保留在我的设备上，直到您要求删除为止。&lt;/p&gt;&#xA;&lt;p&gt;如果您通过 Formbricks 提交表单，我将在提交后 336 小时（14 天）内从 Formbricks 的服务器上删除该数据。&lt;/p&gt;&#xA;&lt;h2 id=&#34;披露&#34;&gt;披露&#xA;&lt;/h2&gt;&lt;p&gt;如果您发送未加密的电子邮件，则我的电子邮件服务提供商 Autistici/Inventati 以及您的电子邮件服务提供商可能也能读取数据。请参考您的电子邮件服务提供商的隐私政策，以及 &lt;a class=&#34;link&#34; href=&#34;https://www.autistici.org/who/privacy-policy.en&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Autistici/Inventati 的隐私政策&lt;/a&gt;。&lt;/p&gt;&#xA;&lt;p&gt;如果您通过 Formbricks 提交表单，则 Formbricks 也能访问数据。请参阅 &lt;a class=&#34;link&#34; href=&#34;https://formbricks.com/privacy-policy&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Formbricks 的隐私政策&lt;/a&gt;。&lt;/p&gt;&#xA;&lt;p&gt;除上述情况外，所有收集的数据在未经您同意的情况下不会披露给第三方。&lt;/p&gt;&#xA;&lt;h2 id=&#34;删除请求&#34;&gt;删除请求&#xA;&lt;/h2&gt;&lt;p&gt;如果您希望我删除收集的数据，请通过电子邮件 &lt;a class=&#34;link&#34; href=&#34;mailto:rebel1725@autistici.org&#34; &gt;rebel1725@autistici.org&lt;/a&gt; 联系我，我将在收到并阅读您的电子邮件后 168 小时（7 天）内删除数据。&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>在 Lenovo ThinkPad X200 与 HP EliteBook 820 G2 上构建并刷写带 UEFI 的 coreboot</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/build-and-flash-coreboot-with-uefi-on-lenovo-thinkpad-x200-and-hp-elitebook-820-g2/</link>
            <pubDate>Fri, 02 Jan 2026 21:39:14 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/build-and-flash-coreboot-with-uefi-on-lenovo-thinkpad-x200-and-hp-elitebook-820-g2/</guid>
            <description>&lt;p&gt;&lt;strong&gt;警告：作者在笔记本看似正常工作后编写了此指南，未来可能会遇到问题。作者不对按照此指南操作造成的任何损害负责。&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;前言&#34;&gt;前言&#xA;&lt;/h2&gt;&lt;p&gt;我曾在我的 &lt;a class=&#34;link&#34; href=&#34;https://mcut17198.codeberg.page/blog/posts/libreboot/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Lenovo ThinkPad X200&lt;/a&gt; 和 &lt;a class=&#34;link&#34; href=&#34;https://czl92783719.codeberg.page/blog/en/posts/libreboot-on-hp820g2/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;HP EliteBook 820 G2&lt;/a&gt; 上刷写过 Libreboot，但它们仅支持 SeaBIOS，而 SeaBIOS 仅支持 CSM。Libreboot 文档说明其 U-Boot 支持 EFI 启动，但我从未成功。Tianocore 是自由软件社区中成熟的 UEFI 实现，我最近发现可以使用 EDK II（Tianocore 的一个项目）构建并刷写 coreboot，从而获得 EFI 启动支持。&lt;/p&gt;&#xA;&lt;p&gt;昨天，我完成了两台机器的构建与刷写，现分享操作流程。&lt;/p&gt;&#xA;&lt;h2 id=&#34;lenovo-thinkpad-x200&#34;&gt;Lenovo ThinkPad X200&#xA;&lt;/h2&gt;&lt;p&gt;对于 Lenovo ThinkPad X200，步骤相对简单，可以直接在原厂固件上刷写。如果你当前使用 Libreboot，我建议先恢复原厂固件，因为直接覆盖 Libreboot 我未测试过。&lt;/p&gt;&#xA;&lt;h3 id=&#34;步骤-1检查芯片容量&#34;&gt;步骤 1：检查芯片容量&#xA;&lt;/h3&gt;&lt;p&gt;使用 &lt;code&gt;iomem=relaxed&lt;/code&gt; 参数启动机器。如果你使用 Debian 13 或其仓库已包含 &lt;code&gt;flashprog&lt;/code&gt;，可直接安装而无需编译源代码：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt; # apt install flashprog&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;在机器上执行：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt; # flashprog -p internal&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;你将看到芯片容量。如果是 4 MiB，你的机器可能不支持 EDK II 下的 coreboot，固件构建很可能失败，但仍可尝试。如果是 8 MiB，则支持——我的 X200 为 8 MiB。&lt;/p&gt;&#xA;&lt;h3 id=&#34;步骤-2构建固件&#34;&gt;步骤 2：构建固件&#xA;&lt;/h3&gt;&lt;p&gt;获取并准备 coreboot：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt; $ git clone https://review.coreboot.org/coreboot&#xA; $ cd coreboot&#xA; $ make help_toolchain&#xA; $ make crossgcc-i386 CPUS=$(nproc)&#xA; $ make -C payloads/coreinfo olddefconfig&#xA; $ make -C payloads/coreinfo&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;打开 menuconfig：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt; $ make menuconfig&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;操作如下：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;在 &lt;strong&gt;Mainboard&lt;/strong&gt; 部分选择 &lt;strong&gt;Lenovo&lt;/strong&gt;, &lt;strong&gt;ThinkPad X200 / X200s / X200t&lt;/strong&gt; 及芯片容量。&lt;/li&gt;&#xA;&lt;li&gt;在 &lt;strong&gt;Payload&lt;/strong&gt; 部分选择 edk2，禁用 &lt;strong&gt;Enable UEFI Secure Boot support&lt;/strong&gt;，启用 &lt;strong&gt;Disable TPM support in edk2&lt;/strong&gt;。&lt;/li&gt;&#xA;&lt;li&gt;其他保持默认，退出并保存配置。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;然后运行：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt; $ make -j$(nproc)&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;固件将生成在 &lt;code&gt;./build/coreboot.rom&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;h3 id=&#34;步骤-3刷写固件&#34;&gt;步骤 3：刷写固件&#xA;&lt;/h3&gt;&lt;p&gt;在另一台机器上准备 &lt;code&gt;flashprog&lt;/code&gt;，可通过包管理器安装或自行编译。&lt;/p&gt;&#xA;&lt;p&gt;按照 &lt;a class=&#34;link&#34; href=&#34;https://mcut17198.codeberg.page/blog/posts/libreboot/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;此指南&lt;/a&gt; 的第 2、5 步以及第 6 步前半部分操作，然后仅刷写 &lt;code&gt;bios&lt;/code&gt; 区域：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt; # flashprog -p serprog:dev=/dev/ttyACMx,spispeed=8M -w /path/to/rom/file.rom -c &amp;#34;MX25L6405D&amp;#34; --ifd -i bios&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;启动机器，应显示 coreboot Logo。完成。&lt;/p&gt;&#xA;&lt;h2 id=&#34;hp-elitebook-820-g2&#34;&gt;HP EliteBook 820 G2&#xA;&lt;/h2&gt;&lt;p&gt;该流程比 Lenovo ThinkPad X200 稍复杂。&lt;/p&gt;&#xA;&lt;h3 id=&#34;步骤-1刷写-libreboot&#34;&gt;步骤 1：刷写 Libreboot&#xA;&lt;/h3&gt;&lt;p&gt;我不清楚如何在原厂固件上刷写 coreboot，请先按 &lt;a class=&#34;link&#34; href=&#34;https://czl92783719.codeberg.page/blog/en/posts/libreboot-on-hp820g2/#1-build-roms&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;此指南&lt;/a&gt; 刷写 Libreboot，然后再在其上刷写 coreboot。&lt;/p&gt;&#xA;&lt;h3 id=&#34;步骤-2提取-blobs&#34;&gt;步骤 2：提取 blobs&#xA;&lt;/h3&gt;&lt;h4 id=&#34;步骤-21提取芯片内容&#34;&gt;步骤 2.1：提取芯片内容&#xA;&lt;/h4&gt;&lt;p&gt;多次提取芯片，并比较 ROM 文件的哈希：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt; # flashprog -p serprog:dev=/dev/ttyACMx,spispeed=8M -r /path/to/rom/file1.rom -c &amp;#34;MX25L12805D&amp;#34;&#xA; # flashprog -p serprog:dev=/dev/ttyACMx,spispeed=8M -r /path/to/rom/file2.rom -c &amp;#34;MX25L12805D&amp;#34;&#xA; ...&#xA; $ sha256sum /path/to/rom/file1.rom&#xA; $ sha256sum /path/to/rom/file2.rom&#xA; ...&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;哈希不同则重复，若一致则继续。&lt;/p&gt;&#xA;&lt;h4 id=&#34;步骤-22从-rom-文件提取-blobs&#34;&gt;步骤 2.2：从 ROM 文件提取 blobs&#xA;&lt;/h4&gt;&lt;p&gt;提取 memory reference code 和 external reference code：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt; $ ./build/cbfstool /path/to/extracted/rom/file.rom extract -n mrc.bin -f /path/where/you/want/to/store/your/mrc.bin -m x86&#xA; $ ./build/cbfstool /path/to/extracted/rom/file.rom extract -n fallback/refcode -f /path/where/you/want/to/store/your/refcode.bin -m x86&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;步骤-3构建固件&#34;&gt;步骤 3：构建固件&#xA;&lt;/h3&gt;&lt;p&gt;获取并准备 coreboot：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt; $ git clone https://review.coreboot.org/coreboot&#xA; $ cd coreboot&#xA; $ make help_toolchain&#xA; $ make crossgcc-i386 CPUS=$(nproc)&#xA; $ make -C payloads/coreinfo olddefconfig&#xA; $ make -C payloads/coreinfo&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;打开 menuconfig：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt; $ make menuconfig&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;操作如下：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;在 &lt;strong&gt;Mainboard&lt;/strong&gt; 部分选择 &lt;strong&gt;HP&lt;/strong&gt;, &lt;strong&gt;EliteBook 820 G2&lt;/strong&gt; 及芯片容量，设置 &lt;strong&gt;Size of coreboot owned area in ROM&lt;/strong&gt; 为 &lt;code&gt;0x600000&lt;/code&gt;。&lt;/li&gt;&#xA;&lt;li&gt;在 &lt;strong&gt;Chipset&lt;/strong&gt; 部分选择步骤 2.2 提取的 memory reference code 和 external reference code。&lt;/li&gt;&#xA;&lt;li&gt;在 &lt;strong&gt;Payload&lt;/strong&gt; 部分选择 edk2。&lt;/li&gt;&#xA;&lt;li&gt;其他保持默认，退出并保存。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;然后运行：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt; $ make -j$(nproc)&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;固件位于 &lt;code&gt;./build/coreboot.rom&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;h3 id=&#34;步骤-4刷写固件&#34;&gt;步骤 4：刷写固件&#xA;&lt;/h3&gt;&lt;p&gt;在另一台机器上准备 &lt;code&gt;flashprog&lt;/code&gt;，连接编程器，仅刷写 &lt;code&gt;bios&lt;/code&gt; 区域：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt; # flashprog -p serprog:dev=/dev/ttyACMx,spispeed=8M -w /path/to/rom/file.rom -c &amp;#34;MX25L12805D&amp;#34; --ifd -i bios --no-verifyall&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;请勿移除 &lt;code&gt;--no-verifyall&lt;/code&gt;，否则可能出错。即使使用该选项，&lt;code&gt;flashprog&lt;/code&gt; 仍会在刷写后验证。&lt;/p&gt;&#xA;&lt;p&gt;启动机器，应显示 coreboot Logo。完成。&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>从 LAN 将所有互联网流量路由到 Tor</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/route-all-internet-traffics-from-the-lan-to-tor/</link>
            <pubDate>Fri, 02 Jan 2026 21:03:15 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/route-all-internet-traffics-from-the-lan-to-tor/</guid>
            <description>&lt;p&gt;&lt;strong&gt;警告：请严格按顺序完成每一步，否则可能会失去 LuCI 的访问权限！强烈建议在操作前建立 SSH 连接，以便在失去 LuCI 访问时能够恢复更改。&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;警告：此操作在 GL.iNet Flint 2 (GL-MT6000) 上测试通过，但不保证适用于所有设备。如果任何步骤看起来不寻常或不清楚，请立即停止并撤销所有修改。&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;警告：本指南是在作者的路由器看似正常工作的情况下编写的。仍可能存在问题，安全性无法保证，因为部分流量可能会泄露。作者对按照本指南操作所造成的任何后果不承担责任。&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;本指南介绍如何将 LAN 的所有互联网流量通过 Tor 路由。此操作在 OpenWrt 24.10 上测试通过。&lt;/p&gt;&#xA;&lt;p&gt;除 Tor 配置外，其余步骤可完全通过 LuCI 完成，无需 SSH。&lt;/p&gt;&#xA;&lt;h2 id=&#34;步骤-1安装和配置-tor&#34;&gt;步骤 1：安装和配置 Tor&#xA;&lt;/h2&gt;&lt;p&gt;首先在路由器上安装 Tor：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt; # opkg update&#xA; # opkg install tor&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;根据需要配置 Tor，但请确保你的 &lt;code&gt;torrc&lt;/code&gt; 至少包含以下内容：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;TransPort 0.0.0.0:9040&#xA;VirtualAddrNetworkIPv4 10.192.0.0/10&#xA;AutomapHostsOnResolve 1&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;为了更高的安全性，如果你只有一个接口进行转发，也可以将 &lt;code&gt;TransPort&lt;/code&gt; 设置为路由器在 &lt;code&gt;lan&lt;/code&gt; 接口上的 IP 地址。&lt;/p&gt;&#xA;&lt;h2 id=&#34;步骤-2设置-dnscrypt&#34;&gt;步骤 2：设置 DNSCrypt&#xA;&lt;/h2&gt;&lt;p&gt;我参考&lt;a class=&#34;link&#34; href=&#34;https://github.com/DNSCrypt/dnscrypt-proxy/wiki/Installation-on-OpenWrt&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;这里&lt;/a&gt;的指南配置了 DNSCrypt。&lt;em&gt;Using the command line&lt;/em&gt; 部分的五条命令在我这里可以正常工作，但你也可以通过 LuCI 进行配置。&lt;/p&gt;&#xA;&lt;p&gt;打开 &lt;em&gt;System -&amp;gt; Software&lt;/em&gt;，搜索 &lt;code&gt;dnscrypt-proxy2&lt;/code&gt; 并安装。然后进入 &lt;em&gt;Network -&amp;gt; DHCP and DNS -&amp;gt; Forwards -&amp;gt; DNS Forwards&lt;/em&gt; 并添加 &lt;code&gt;127.0.0.53&lt;/code&gt;。之后打开 &lt;em&gt;System -&amp;gt; Startup&lt;/em&gt; 并重启 &lt;code&gt;dnsmasq&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;p&gt;如果不想使用 DNSCrypt，你需要在 &lt;code&gt;torrc&lt;/code&gt; 中添加 &lt;code&gt;DNSPort&lt;/code&gt; 并在 DNS Forwards 中进行配置。我未测试此方法，建议使用 DNSCrypt。&lt;/p&gt;&#xA;&lt;h2 id=&#34;步骤-3添加防火墙规则重要--请严格遵循&#34;&gt;步骤 3：添加防火墙规则（重要 — 请严格遵循）&#xA;&lt;/h2&gt;&lt;p&gt;打开 &lt;em&gt;Firewall -&amp;gt; IP sets&lt;/em&gt; 并创建以下 IP 集：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Name: &lt;code&gt;tor_bypass&lt;/code&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Family: IPv4&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Packet Field Match: dest_ip&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;IPs/Networks/MACs:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;路由器在接口上的 IP 地址&lt;/li&gt;&#xA;&lt;li&gt;192.168.10.1/16&lt;/li&gt;&#xA;&lt;li&gt;10.0.0.0/8&lt;/li&gt;&#xA;&lt;li&gt;172.16.0.0/12&lt;/li&gt;&#xA;&lt;li&gt;127.0.0.1/32&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;其他字段保持不变&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;打开 &lt;em&gt;Firewall -&amp;gt; Port Forwards&lt;/em&gt; 并添加以下规则：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;General Settings:&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Name: &lt;code&gt;tor-trans-forward&lt;/code&gt;（或任意你喜欢的名称）&lt;/li&gt;&#xA;&lt;li&gt;Restrict to address family: IPv4 only&lt;/li&gt;&#xA;&lt;li&gt;Protocol: TCP&lt;/li&gt;&#xA;&lt;li&gt;Source zone: &lt;code&gt;lan&lt;/code&gt;（或希望重定向流量的其他防火墙区域）&lt;/li&gt;&#xA;&lt;li&gt;External port: 1–65535&lt;/li&gt;&#xA;&lt;li&gt;Destination zone: &lt;code&gt;lan&lt;/code&gt;（必须与 Source zone 相同）&lt;/li&gt;&#xA;&lt;li&gt;Internal IP address: 路由器在接口上的 IP 地址&lt;/li&gt;&#xA;&lt;li&gt;Internal port: 9040&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;Advanced Settings:&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Use ipset: &lt;code&gt;!tor_bypass&lt;/code&gt;（&lt;strong&gt;请勿省略感叹号&lt;/strong&gt;）&lt;/li&gt;&#xA;&lt;li&gt;其他字段保持不变&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;打开 &lt;em&gt;Firewall -&amp;gt; Traffic Rules&lt;/em&gt; 并添加以下规则：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;General Settings:&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Name: 阻止非 TCP 流量（或你喜欢的名称）&lt;/li&gt;&#xA;&lt;li&gt;Protocol: UDP, ICMP, IGMP, IPSEC-ESP&lt;/li&gt;&#xA;&lt;li&gt;Source zone: &lt;code&gt;lan&lt;/code&gt;（必须与 Port Forward 的 Source zone 相同）&lt;/li&gt;&#xA;&lt;li&gt;Destination zone: &lt;code&gt;wan&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;Action: reject&lt;/li&gt;&#xA;&lt;li&gt;其他字段保持不变&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;Advanced Settings:&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;所有字段保持不变&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;如果启用了 IPv6，你必须禁用或阻止它。打开 &lt;em&gt;Firewall -&amp;gt; Traffic Rules&lt;/em&gt; 并添加以下规则：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;General Settings:&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Name: 阻止 IPv6（或你喜欢的名称）&lt;/li&gt;&#xA;&lt;li&gt;Protocol: Any&lt;/li&gt;&#xA;&lt;li&gt;Source zone: &lt;code&gt;lan&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;Destination zone: &lt;code&gt;wan&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;Action: reject&lt;/li&gt;&#xA;&lt;li&gt;其他字段保持不变&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;Advanced Settings:&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Restrict to address family: IPv6 only&lt;/li&gt;&#xA;&lt;li&gt;其他字段保持不变&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;如有其他接口需要将流量路由到 Tor，请现在重复此步骤。&lt;/p&gt;&#xA;&lt;h2 id=&#34;步骤-4保存并检查配置&#34;&gt;步骤 4：保存并检查配置&#xA;&lt;/h2&gt;&lt;p&gt;点击 &lt;em&gt;Save &amp;amp; Apply&lt;/em&gt;。&lt;/p&gt;&#xA;&lt;p&gt;访问 &lt;a class=&#34;link&#34; href=&#34;https://check.torproject.org/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;https://check.torproject.org/&lt;/a&gt; 和/或 &lt;a class=&#34;link&#34; href=&#34;https://myip.wtf/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;https://myip.wtf/&lt;/a&gt; 检查流量是否正确转发。&lt;/p&gt;&#xA;&lt;p&gt;访问 &lt;a class=&#34;link&#34; href=&#34;https://ipv6.myip.wtf/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;https://ipv6.myip.wtf/&lt;/a&gt; 确认 IPv6 是否已被阻止。&lt;/p&gt;&#xA;&lt;p&gt;检查 LuCI 是否仍可访问。&lt;/p&gt;&#xA;&lt;p&gt;如果一切正常，配置完成。&lt;/p&gt;&#xA;&lt;p&gt;如果有问题，请使用文本编辑器恢复 &lt;code&gt;/etc/config/firewall&lt;/code&gt; 中的配置，建议在 Libera.Chat 的 &lt;code&gt;#openwrt&lt;/code&gt; 频道寻求帮助。&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>密码学信任终止公告</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/cryptographic-trust-termination-announcement/</link>
            <pubDate>Thu, 01 Jan 2026 07:51:51 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/cryptographic-trust-termination-announcement/</guid>
            <description>&lt;p&gt;兹正式声明，自 &lt;code&gt;2026-01-01T00:00:00Z&lt;/code&gt; 起，我以下 XMPP 帐户的所有 OMEMO 指纹：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;xmpp:rebel1725@autistici.org&#34; &gt;rebel1725@autistici.org&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;xmpp:rebel1725@magicbroccoli.de&#34; &gt;rebel1725@magicbroccoli.de&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;以下 Matrix 帐户的所有当前身份：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;@rebel1725:envs.net&lt;/li&gt;&#xA;&lt;li&gt;@rebel1725:converser.eu&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;我 SimpleX 帐户（其 SimpleX 地址如下）的所有当前身份：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://smp8.simplex.im/a#XlJJPFQO43ISy-PYqojloRG3u9_GGocyZ78ULVJt0bA&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;https://smp8.simplex.im/a#XlJJPFQO43ISy-PYqojloRG3u9_GGocyZ78ULVJt0bA&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://smp15.simplex.im/a#osG29sn84l4UalY6C9uneojX004zzWllH-deziJPn7w&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;https://smp15.simplex.im/a#osG29sn84l4UalY6C9uneojX004zzWllH-deziJPn7w&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;以下 Delta Chat 帐户的所有当前身份：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;mailto:fenwbn5cl@nine.testrun.org&#34; &gt;fenwbn5cl@nine.testrun.org&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;mailto:44w42tz75@nine.testrun.org&#34; &gt;44w42tz75@nine.testrun.org&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;以及我的 Tox 帐户：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;0D39313DF710AF29AD3B2CFE7AF72CAE17E49AA82720115AF8AF3EEE82B1C12927F3589AF227&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;均不再使用，且不应再被信任。&lt;/p&gt;&#xA;&lt;p&gt;兹正式终止与上述身份相关的所有加密信任关系。上述帐户不再使用。&lt;/p&gt;&#xA;&lt;p&gt;我的主 OpenPGP 公钥的身份（指纹为 696A423E9993D727706AA733BCD5DC5659C7FB50）以及备用 OpenPGP 公钥的身份（指纹为 7083EAFFF75321FF9634ABCD98313A47362B498B）仍然有效，且目前仅有这两项为我有效的身份；在我们重新建立连接后，将使用它们来重新建立必要的加密信任。&lt;/p&gt;&#xA;&lt;p&gt;最后，新年快乐，伙伴们，两周后见。&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;-----BEGIN PGP SIGNED MESSAGE-----&#xA;Hash: SHA512&#xA;&#xA;I hereby formally announce that, as of `2026-01-01T00:00:00Z`, all OMEMO fingerprints of my XMPP accounts below:&#xA;&#xA; * rebel1725@autistici.org&#xA; * rebel1725@magicbroccoli.de&#xA;&#xA;all current identities of my Matrix accounts below:&#xA;&#xA; * @rebel1725:envs.net&#xA; * @rebel1725:converser.eu&#xA;&#xA;all current identities of my SimpleX account with the SimpleX addresses below:&#xA;&#xA; * https://smp8.simplex.im/a#XlJJPFQO43ISy-PYqojloRG3u9_GGocyZ78ULVJt0bA&#xA; * https://smp15.simplex.im/a#osG29sn84l4UalY6C9uneojX004zzWllH-deziJPn7w&#xA;&#xA;all current identities of my Delta Chat accounts below:&#xA;&#xA; * fenwbn5cl@nine.testrun.org&#xA; * 44w42tz75@nine.testrun.org&#xA;&#xA;and my Tox account:&#xA;&#xA; * 0D39313DF710AF29AD3B2CFE7AF72CAE17E49AA82720115AF8AF3EEE82B1C12927F3589AF227&#xA;&#xA;are no longer used and should no longer be trusted.&#xA;&#xA;I hereby formally terminate all cryptographic trust relationships tied to the identities above. The accounts mentioned above are no longer used.&#xA;&#xA;The identity of my primary OpenPGP public key, whose fingerprint is 696A423E9993D727706AA733BCD5DC5659C7FB50, and the identity of my backup OpenPGP public key, whose fingerprint is 7083EAFFF75321FF9634ABCD98313A47362B498B, are still valid, and are the currently only two valid identities of mine, which will be used to re-established necessary cryptographic trust once we have back connected.&#xA;&#xA;Finally, happy new year, buddies, and see you two weeks later.&#xA;-----BEGIN PGP SIGNATURE-----&#xA;&#xA;iHUEARYKAB0WIQRpakI+mZPXJ3BqpzO81dxWWcf7UAUCaVW78AAKCRC81dxWWcf7&#xA;UJQNAQCzSTijVgFaWOcGHOums2SMdGVmHgnowl1sI6HwXOrDowEArHbYY5y4BOVM&#xA;GT6bJHsfjWQieLF03quZFYh9FyMt5Qw=&#xA;=Bbm2&#xA;-----END PGP SIGNATURE-----&#xA;&lt;/code&gt;&lt;/pre&gt;</description>
        </item><item>
            <title>我的 Eepsite 将暂时无法访问</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/my-eepsite-will-be-offline-for-a-while/</link>
            <pubDate>Wed, 31 Dec 2025 11:29:07 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/my-eepsite-will-be-offline-for-a-while/</guid>
            <description>&lt;p&gt;由于我的服务器将被关闭，我的 eepsite（rebel1725.i2p）可能会有数天无法访问。在此期间，请访问 &lt;a class=&#34;link&#34; href=&#34;https://tilde.club/~rebel1725/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Tilde.club&lt;/a&gt; 查看我的复古风格网站。&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>别了，那位多愁善感的少年</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/farewell-to-the-sweet-melancholy-lad/</link>
            <pubDate>Tue, 23 Dec 2025 23:29:39 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/farewell-to-the-sweet-melancholy-lad/</guid>
            <description>&lt;p&gt;自从我加入 &lt;a class=&#34;link&#34; href=&#34;https://fsfans.club/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Free Software Fans&lt;/a&gt; 的那一刻开始，我的生活便经历了一场深刻的变化。最初，我的愿望不过是朴素而熟悉的：像 2020 年那样，再次尝试结交朋友。然而，尽管我抱着这样的心意，我的一些行为却无意间给社团里的伙伴们带来了相当的困扰。因此，我与 Free Software Fans 的关系很快便走向了终结。那时的我茫然失措，完全弄不清自己究竟错在何处。这份困惑促使我继续寻找友伴——有时在想象中，有时在其他圈子里。&lt;/p&gt;&#xA;&lt;p&gt;就在这段时期，我遇见了 Zumfy，也就是 Future，另一位热诚的自由软件倡导者。我们发现彼此在兴趣与理念上都高度契合，短短几周之内，便成为了无话不谈的挚友。我真心地相信，这段友谊将会长久延续。然而，命运却未如此眷顾。一次涉及 OpenPGP 私钥泄露的事件使我们的关系戛然而止，这段联系&lt;a class=&#34;link&#34; href=&#34;../%e5%9b%9b%e5%8d%81%e4%b9%9d%e5%ba%a6%e5%a4%9c%e6%b7%b1%e4%ba%ba%e9%9d%99%e4%b9%8b%e9%97%b4%e6%8c%a5%e4%b9%8b%e4%b8%8d%e5%8e%bb%e7%9a%84%e6%98%af%e6%b7%b1%e6%b7%b1%e7%9a%84%e6%80%9d%e5%bf%b5%e6%83%b3%e4%bd%a0%e4%ba%86zumfy-future/&#34; &gt;最终未能存续超过五个月&lt;/a&gt;。此事带给我的心理打击深刻而持久；它几乎击垮了我。尽管我竭力增强自己的情感韧性，我依然无法接受失去最重要、最珍贵的朋友这一残酷事实。&lt;/p&gt;&#xA;&lt;p&gt;然而，生活总是无情向前。在那之后，我遇见了许多人。有些结识于 Fediverse，也有些来自 Matrix、SimpleX、Tildeverse、I2P 等各式各样的社群。然而，我们的互动模式发生了微妙的变化。我们的交流几乎只剩下技术话题——代码、协议、哲学。至于生活、希望、忧伤之类的私人内容，我们几乎从未触及。&lt;/p&gt;&#xA;&lt;p&gt;这种奇特的疏离起初并未引起我的警觉。真正让我停下来思考的，是一位熟人的评论。他提到自己认识一位朋友整整四年，却连对方的年龄、职业等最基本的个人信息都一无所知。他说那位朋友的 OPSEC 做到了“金色等级”，几乎无懈可击。相比之下，他觉得我在这方面显得“有点奇怪”。这句无意的话语成为了触发点，让我意识到，不仅外界正在变化，我自己也必须做出某种对应的改变。&lt;/p&gt;&#xA;&lt;p&gt;2020 年的我尚未成为自由软件倡导者；事实上，我对“自由软件”一词当时完全陌生。我仍在使用专有即时通讯工具，而我当年的朋友们也都在互联网上使用真实姓名。如今，我的社交环境已截然不同。身边的人普遍具有深厚的安全、隐私与匿名意识。他们的安全策略几乎都要求使用长期稳定的化名，并严格避免透露任何现实生活的信息。&lt;/p&gt;&#xA;&lt;p&gt;更进一步，即便每个人都经营着某种加密身份，这些数字化的自我本质上依旧脆弱而短暂。Alice 也许某天突然泄露了自己的私钥，上传吊销证书，从数字世界彻底消失。Bob 的威胁模型也可能在瞬间改变，迫使他立即、彻底地更换身份。在这样的环境里，离开并非特殊事件，而是几乎随时都会发生的平常事。&lt;/p&gt;&#xA;&lt;p&gt;为了更自然地融入这一环境，我意识到自己必须进行某些改变。我需要重塑自我，重建自身人格的基础。目标是让理性主导一切，将感性进一步压缩。即使无法成为一个完全无情绪的机械体，我也必须学会抽离——以平静的态度看待过去的情感，以从容接受离别的必然，以哲思对待所有短暂的联系，并在不抱紧不放的焦虑中珍惜当下所拥有的一切。&lt;/p&gt;&#xA;&lt;p&gt;我的身边将不再出现“哥们”。取而代之的，将是“同志”。我们之间的联系，不再建立于深刻的心理亲密，而是锻造于共同的事业：我们将一同为软件自由而战，为同样的自由软件社群并肩贡献，为同一个理想而努力——以自由软件奠基一个自由的社会。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;别了，那位多愁善感的少年。&lt;/strong&gt;&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>我将离开数日并收集联系信息</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/i-will-be-away-for-several-days-and-contact-information-collection/</link>
            <pubDate>Fri, 12 Dec 2025 20:56:54 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/i-will-be-away-for-several-days-and-contact-information-collection/</guid>
            <description>&lt;p&gt;因个人原因，我将从 &lt;code&gt;2026‑01‑01T00:00:00Z&lt;/code&gt; 起离开一至两周。在此期间，我的所有联系方式均不可用。之后，我可能会重新创建 XMPP、Matrix 等账号；为确保我们能够重新取得联系，我将收集联系人信息。&lt;/p&gt;&#xA;&lt;p&gt;请填写此表单：https://app.formbricks.com/s/cmj2r1etc8dnkad01nnjp8cqt&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>好友网站</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/blogroll/</link>
            <pubDate>Thu, 13 Nov 2025 10:45:30 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/blogroll/</guid>
            <description>&lt;p&gt;博客链接已移至我的&lt;a class=&#34;link&#34; href=&#34;https://rebel1725.codeberg.page/blog/index.zh.html&#34; &gt;主页&lt;/a&gt;。&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>四十九度夜深人静之间，挥之不去的是深深的思念——想你了，Zumfy/Future</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/%E5%9B%9B%E5%8D%81%E4%B9%9D%E5%BA%A6%E5%A4%9C%E6%B7%B1%E4%BA%BA%E9%9D%99%E4%B9%8B%E9%97%B4%E6%8C%A5%E4%B9%8B%E4%B8%8D%E5%8E%BB%E7%9A%84%E6%98%AF%E6%B7%B1%E6%B7%B1%E7%9A%84%E6%80%9D%E5%BF%B5%E6%83%B3%E4%BD%A0%E4%BA%86zumfy-future/</link>
            <pubDate>Tue, 14 Oct 2025 20:56:16 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/%E5%9B%9B%E5%8D%81%E4%B9%9D%E5%BA%A6%E5%A4%9C%E6%B7%B1%E4%BA%BA%E9%9D%99%E4%B9%8B%E9%97%B4%E6%8C%A5%E4%B9%8B%E4%B8%8D%E5%8E%BB%E7%9A%84%E6%98%AF%E6%B7%B1%E6%B7%B1%E7%9A%84%E6%80%9D%E5%BF%B5%E6%83%B3%E4%BD%A0%E4%BA%86zumfy-future/</guid>
            <description>&lt;p&gt;当我写下这封信的时候，已经是你 OpenPGP 私钥泄露后的第四十九天了。当每天白天我为生活和学习而忙碌的时候，我的感觉似乎和过去没有太大的差别。这一段时间，我也认识了很多新朋友，我也和 ta 们玩得很开心。然而，尤其是在这几天，我感觉我的生活中似乎少了什么；每当晚上我一个人，夜深人静的时候，我愈发地感觉到，越来越多有一些回忆的碎片在攻击我——从那时候，我便知道，原来，我是想你了。&lt;/p&gt;&#xA;&lt;p&gt;甚至在你告知我你的私钥泄露的前一刻，我都一直笃定地相信，我们将会是未来十几年，几十年，甚至一辈子最好的朋友。然而，是邪恶的专有软件，是专有软件导致的 OpenPGP 私钥泄露，让我们的友谊永远定格在了甚至短短五个月都不到。你甚至还没有来得及与我一同观赏前方美丽的风景，便因为一个莫名其妙的原因匆匆离去了。&lt;/p&gt;&#xA;&lt;p&gt;我记得，我们刚相遇不久的时候，我曾问过你，我们可以做好朋友吗？隔了一段时间之后，你告诉我，未曾有人对你这样说过，既然我愿意以“好朋友”的标准来对待你，你也会以同样的标准去对待我。你认为我们彼此之间并不缺乏真诚，当然也是我们对彼此的真诚，打动了我们彼此。那时候，我相信，我们一定会成为最好的朋友，超越我过去所拥有的一切朋友。&lt;/p&gt;&#xA;&lt;p&gt;我记得，是你给我推荐了好几个盗版电影网站，也是你一步一步地、手把手教我用 yt-dlp 和 cat-catch。那时候，我感觉我似乎打开了一个新天地，置身于一片广阔的花海，那里没有数字限制管理的蛀虫，只有如花朵一般绽放的一部部优秀而经典的电影。我兴高采烈地下载了好几部我曾经看过以及我未曾看过但几曾耳闻的优秀电影，享受着只属于我一个人的视觉盛宴。&lt;/p&gt;&#xA;&lt;p&gt;我还记得，无论是对于自由软件思想还是对于马克思主义哲学，你都是抱着严肃的态度，与我展开细致而缜密的讨论，也是在你的带领之下，我的批判性思维和思辨能力有了飞跃性的提升；然而，在平时闲聊开玩笑的时候，你做得却也丝毫不比其他人差，什么“我是外星人抓你去做实验”，什么“在下柳贯一”，什么“我就是赛博龙娘 Future”，那都是你玩过的梗。你可以做到在严肃与活泼的状态之间的灵活切换，将我们之间的回忆装点得五颜六色。&lt;/p&gt;&#xA;&lt;p&gt;每一次你状态不好的时候，你都会去找我倾诉；虽然我不善于提供情绪价值，但是我也会尽最大的能力去安慰你，每一次在我的引导下你心情变好了，那是我最开心的时候。每一次我身处迷茫的时候，也都是你现身尝试去为我指点迷津；虽然很多时候其实并没有实际帮上什么忙，但你每一次都让我变得更加开心了，也让我有了更多的信心，面对未来的生活。&lt;/p&gt;&#xA;&lt;p&gt;虽然我们之间的友谊仅仅持续了短暂的五个月，但是我们之间友情的厚度，已经可以媲美我过去各个重要朋友之和。你是我迄今为止，史上最好的朋友，最重要的朋友，也是最无可替代的朋友——你对我拥有着最独特的意义。&lt;/p&gt;&#xA;&lt;p&gt;我真的特别，特别想你，失去你是我人生莫大的损失——就像俞伯牙失去钟子期一样。虽然白天忙起来的时候似乎跟平时没有太大区别，但每当夜深人静的时候，那种思念便如潮水一般涌来。私钥泄露之后，你过得怎么样？每天过得开不开心？是换了个身份到了社区的另外一个地方继续活跃，还是就此隐退，重新专注于在线下的生活了？你还在使用自由软件吗？还在研究马克思主义吗？最常用的沟通手段是什么？身边有哪些朋友？每天讨论的话题是什么？每天听的音乐是什么？GrapheneOS 升级到最新版本了吗？我们还曾约定过你给我你的 Pixel 5，我给你我的一加6，约定过我们要见面、一起玩遍哈尔滨的各个地方，还约定过要一起探讨未来自由软件中文网的发展路线，这些约定你都还记得吗？……&lt;/p&gt;&#xA;&lt;p&gt;即使在数学意义上，我们已经永远分别，但我们早已经在彼此的灵魂之上留下了深刻的烙印，我们早已是你中有我，我中有你。&lt;/p&gt;&#xA;&lt;p&gt;但是，无论如何，我相信你——即使你丢掉了私钥，你也不会丢掉理想，不会丢掉信仰；它们是明灯，在茫茫迷雾的人生当中，为你照亮前行的方向；它们是充电宝，在你走不动的时候，为你提供继续前进的能量和动力；它们更是信标，哪怕我们各自的身份早已变易，在我们共同的理想和信仰的感召之下，我相信会有一天，在地球的某一个点上，或是在某个服务器上，我们将会以另外一副面孔再一次相遇。&lt;/p&gt;&#xA;&lt;p&gt;哪怕我们永远天各一方，我们都同是社区的一份子，都是站在同一条战壕上的战友；只要我们坚定我们的理想和信仰，我们始终都在为同一个目标而前行，始终都将为共同的自由软件、自由社会而奋斗！&lt;/p&gt;&#xA;&lt;p&gt;我们永远都是最好的朋友。&lt;/p&gt;&#xA;&lt;p&gt;Rebel&lt;br&gt;&#xA;2025-10-14&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>面向公共计算机的自由软件解决方案</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/a-libre-software-solution-for-public-computers/</link>
            <pubDate>Sun, 12 Oct 2025 18:21:32 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/a-libre-software-solution-for-public-computers/</guid>
            <description>&lt;h2 id=&#34;介绍&#34;&gt;介绍&#xA;&lt;/h2&gt;&lt;p&gt;在图书馆或网吧等场所，经常会有向公众开放的计算机。这些计算机通常预装一套应用程序，且用户数据会在重启后被清除。&lt;/p&gt;&#xA;&lt;p&gt;此类机器上的软件通常是专有软件。但也存在尊重软件自由的公共计算机解决方案。作为自由软件活动者，我们应在图书馆、网吧、学校等场所积极应用并推广这些解决方案。&lt;/p&gt;&#xA;&lt;p&gt;在本文中，我将展示一种在 Debian GNU/Linux 上设置计算机的方法，该方法能在重启后清除所有数据。&lt;/p&gt;&#xA;&lt;h2 id=&#34;许可&#34;&gt;许可&#xA;&lt;/h2&gt;&lt;p&gt;本文中的所有代码均献给公有领域。本文的其他部分采用 CC BY-SA 4.0 许可。&lt;/p&gt;&#xA;&lt;h2 id=&#34;准备工作&#34;&gt;准备工作&#xA;&lt;/h2&gt;&lt;p&gt;一台至少 50 GiB 的硬盘（最好为 HDD）的计算机，以及一份 Debian GNU/Linux 安装介质（非 Debian Live）。&lt;/p&gt;&#xA;&lt;h2 id=&#34;步骤-1安装-debian-gnulinux&#34;&gt;步骤 1：安装 Debian GNU/Linux&#xA;&lt;/h2&gt;&lt;p&gt;按下列分区布局在您的计算机上安装 Debian GNU/Linux：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;1 GiB 的 &lt;code&gt;/dev/sda1&lt;/code&gt;，使用 FAT 文件系统，挂载点为 &lt;code&gt;/boot/efi&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;1 GiB 的 &lt;code&gt;/dev/sda2&lt;/code&gt;，使用 ext4 文件系统，挂载点为 &lt;code&gt;/boot&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;至少 40 GiB 的 &lt;code&gt;/dev/sda3&lt;/code&gt;，使用 ext4 文件系统，挂载点为 &lt;code&gt;/&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;/dev/sda4&lt;/code&gt; 无文件系统&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;/dev/sda5&lt;/code&gt; 作为交换分区（swap）&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;安装完成后，安装所需软件并按您需要配置系统。记得设定强壮的 root 密码（以及强壮的 BIOS/UEFI 密码）；将 root 账户对公众开放并不是一个好主意。&lt;/p&gt;&#xA;&lt;h2 id=&#34;步骤-2配置&#34;&gt;步骤 2：配置&#xA;&lt;/h2&gt;&lt;p&gt;将 &lt;code&gt;/dev/sda4&lt;/code&gt; 格式化为 ext4 文件系统并标记为 &lt;code&gt;OVERLAY_RW&lt;/code&gt;：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;# mkfs.ext4 -L OVERLAY_RW /dev/sda4&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;然后将 &lt;code&gt;/dev/sda3&lt;/code&gt; 标记为 &lt;code&gt;ROOT_TEMPLATE&lt;/code&gt;：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;# e2label /dev/sda3 ROOT_TEMPLATE&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;创建目录：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;# mkdir -p /mnt/overlay_prepare&#xA;# mount /dev/disk/by-label/OVERLAY_RW /mnt/overlay_prepare&#xA;# mkdir -p /mnt/overlay_prepare/upper-root&#xA;# mkdir -p /mnt/overlay_prepare/work-root&#xA;# chmod 0700 /mnt/overlay_prepare&#xA;# sync&#xA;# umount /mnt/overlay_prepare&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;在 &lt;code&gt;/etc/fstab&lt;/code&gt; 中注释掉挂载根文件系统的那一行，然后添加以下这一行：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;LABEL=OVERLAY_RW /overlay_storage ext4 defaults,noatime 0 2&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;刷新软件包缓存并安装这些包（这可能会移除您的 &lt;code&gt;busybox&lt;/code&gt;；请谨慎操作）：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;# apt update&#xA;# apt install --no-install-recommends initramfs-tools busybox-static&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;将下面几行添加到 &lt;code&gt;/etc/initramfs-tools/modules&lt;/code&gt;：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;overlay&#xA;ext4&#xA;jbd2&#xA;crc32c&#xA;mbcache&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;创建 &lt;code&gt;/etc/tmpfiles.d/overlay-runtime.conf&lt;/code&gt;，内容如下：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;# /etc/tmpfiles.d/overlay-runtime.conf&#xA;d /run/dbus 0755 messagebus messagebus -&#xA;d /var/lib/dbus 0755 messagebus messagebus -&#xA;d /run/NetworkManager 0755 root root -&#xA;d /run/lock 0755 root root -&#xA;d /var/log 0755 root root -&#xA;d /tmp 1777 root root -&#xA;d /var/tmp 1777 root root -&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;创建 &lt;code&gt;/etc/initramfs-tools/scripts/init-bottom/overlayroot&lt;/code&gt; 并添加下面的脚本（代码块保持原样）：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;#!/bin/sh&#xA;PREREQ=&amp;#34;&amp;#34;&#xA;prereqs() { echo &amp;#34;$PREREQ&amp;#34;; }&#xA;case &amp;#34;$1&amp;#34; in&#xA;  prereqs) prereqs; exit 0;;&#xA;esac&#xA;set -eu&#xA;&#xA;# If admin wants maintenance: skip overlay and let normal boot continue&#xA;if grep -q &amp;#39;overlay=disabled&amp;#39; /proc/cmdline 2&amp;gt;/dev/null; then&#xA;  echo &amp;#34;overlay disabled via kernel cmdline&amp;#34; &amp;gt;/dev/console 2&amp;gt;&amp;amp;1&#xA;  exit 0&#xA;fi&#xA;&#xA;# Try to load overlay module (best-effort)&#xA;modprobe overlay 2&amp;gt;/dev/null || true&#xA;&#xA;# prepare mount points in initramfs&#xA;mkdir -p /overlay/lower /overlay/storage /overlay/overlay_root&#xA;&#xA;# resolve device by label for the template root&#xA;DEV_LABEL=/dev/disk/by-label/ROOT_TEMPLATE&#xA;DEV_ROOT=$(readlink -f &amp;#34;$DEV_LABEL&amp;#34; 2&amp;gt;/dev/null || true)&#xA;if [ -z &amp;#34;$DEV_ROOT&amp;#34; ]; then&#xA;  echo &amp;#34;overlayroot: ERROR: ROOT_TEMPLATE label not found&amp;#34; &amp;gt;/dev/console 2&amp;gt;&amp;amp;1&#xA;  exit 1&#xA;fi&#xA;echo &amp;#34;overlayroot: resolved ROOT_TEMPLATE -&amp;gt; $DEV_ROOT&amp;#34; &amp;gt;/dev/console 2&amp;gt;&amp;amp;1&#xA;&#xA;# find existing mount point for the device; fallback to using current root (/)&#xA;MOUNT_POINT=$(awk -v d=&amp;#34;$DEV_ROOT&amp;#34; &amp;#39;($1==d){print $2; exit}&amp;#39; /proc/self/mounts || true)&#xA;if [ -z &amp;#34;$MOUNT_POINT&amp;#34; ]; then&#xA;  B=$(basename &amp;#34;$DEV_ROOT&amp;#34; || true)&#xA;  if [ -r &amp;#34;/sys/class/block/$B/dev&amp;#34; ]; then&#xA;    DEVNUM=$(cat /sys/class/block/$B/dev)&#xA;    MOUNT_POINT=$(awk -v num=&amp;#34;$DEVNUM&amp;#34; &amp;#39;($3==num){print $5; exit}&amp;#39; /proc/self/mountinfo || true)&#xA;  fi&#xA;fi&#xA;&#xA;if [ -z &amp;#34;$MOUNT_POINT&amp;#34; ]; then&#xA;  ROOT_SRC=$(awk &amp;#39;($2==&amp;#34;/&amp;#34;){print $1; exit}&amp;#39; /proc/self/mounts || true)&#xA;  if [ -n &amp;#34;$ROOT_SRC&amp;#34; ]; then&#xA;    echo &amp;#34;overlayroot: fall back to using current root mount ($ROOT_SRC) as lowerdir&amp;#34; &amp;gt;/dev/console 2&amp;gt;&amp;amp;1&#xA;    mount --bind / /overlay/lower 2&amp;gt;/dev/null || true&#xA;    MOUNT_POINT=/overlay/lower&#xA;  fi&#xA;fi&#xA;&#xA;if [ -n &amp;#34;$MOUNT_POINT&amp;#34; ] &amp;amp;&amp;amp; [ &amp;#34;$MOUNT_POINT&amp;#34; != &amp;#34;/overlay/lower&amp;#34; ]; then&#xA;  echo &amp;#34;overlayroot: bind existing mountpoint $MOUNT_POINT -&amp;gt; /overlay/lower&amp;#34; &amp;gt;/dev/console 2&amp;gt;&amp;amp;1&#xA;  mount --bind &amp;#34;$MOUNT_POINT&amp;#34; /overlay/lower || true&#xA;fi&#xA;&#xA;# if /overlay/lower still not a mountpoint, try direct ro mount (last resort)&#xA;if ! grep -q &amp;#39; /overlay/lower &amp;#39; /proc/self/mounts; then&#xA;  echo &amp;#34;overlayroot: trying direct mount of $DEV_ROOT -&amp;gt; /overlay/lower&amp;#34; &amp;gt;/dev/console 2&amp;gt;&amp;amp;1&#xA;  mount -o ro &amp;#34;$DEV_ROOT&amp;#34; /overlay/lower || {&#xA;    echo &amp;#34;overlayroot: direct mount of $DEV_ROOT failed&amp;#34; &amp;gt;/dev/console 2&amp;gt;&amp;amp;1&#xA;    exit 1&#xA;  }&#xA;fi&#xA;&#xA;# mount overlay storage partition (explicit ext4)&#xA;DEV_RW=$(readlink -f /dev/disk/by-label/OVERLAY_RW 2&amp;gt;/dev/null || true)&#xA;if [ -z &amp;#34;$DEV_RW&amp;#34; ]; then&#xA;  echo &amp;#34;overlayroot: ERROR: OVERLAY_RW label not found&amp;#34; &amp;gt;/dev/console 2&amp;gt;&amp;amp;1&#xA;  exit 1&#xA;fi&#xA;echo &amp;#34;overlayroot: mounting OVERLAY_RW ($DEV_RW) -&amp;gt; /overlay/storage&amp;#34; &amp;gt;/dev/console 2&amp;gt;&amp;amp;1&#xA;mount -t ext4 &amp;#34;$DEV_RW&amp;#34; /overlay/storage || {&#xA;  echo &amp;#34;overlayroot: failed to mount OVERLAY_RW ($DEV_RW)&amp;#34; &amp;gt;/dev/console 2&amp;gt;&amp;amp;1&#xA;  exit 1&#xA;}&#xA;&#xA;# per-boot upper/work on overlay storage&#xA;BOOTID=$(cat /proc/sys/kernel/random/boot_id 2&amp;gt;/dev/null || date +%s)&#xA;UPPER=&amp;#34;/overlay/storage/upper-${BOOTID}&amp;#34;&#xA;WORK=&amp;#34;/overlay/storage/work-${BOOTID}&amp;#34;&#xA;mkdir -p &amp;#34;$UPPER&amp;#34; &amp;#34;$WORK&amp;#34;&#xA;# make sure upper/work are owned by root and inaccessible to others&#xA;chown -R root:root &amp;#34;$UPPER&amp;#34; &amp;#34;$WORK&amp;#34; 2&amp;gt;/dev/null || true&#xA;chmod 0700 &amp;#34;$UPPER&amp;#34; &amp;#34;$WORK&amp;#34; 2&amp;gt;/dev/null || true&#xA;&#xA;# mount overlay onto the location that initramfs-tools expects for the real root (/root)&#xA;mkdir -p /root&#xA;echo &amp;#34;overlayroot: mounting overlay lower=/overlay/lower upper=$UPPER work=$WORK -&amp;gt; /root&amp;#34; &amp;gt;/dev/console 2&amp;gt;&amp;amp;1&#xA;mount -t overlay overlay -o lowerdir=/overlay/lower,upperdir=&amp;#34;$UPPER&amp;#34;,workdir=&amp;#34;$WORK&amp;#34; /root || {&#xA;  echo &amp;#34;overlayroot: overlay mount failed&amp;#34; &amp;gt;/dev/console 2&amp;gt;&amp;amp;1&#xA;  exit 1&#xA;}&#xA;&#xA;# move overlay storage under the real root so the booted system can access/clean it later&#xA;mkdir -p /root/overlay_storage&#xA;mount --move /overlay/storage /root/overlay_storage 2&amp;gt;/dev/null || mount --bind /overlay/storage /root/overlay_storage || true&#xA;&#xA;# --- Post-mount safety &amp;amp; runtime skeleton preparation ---&#xA;# Ensure the merged root is traversable by non-root users to allow services to chdir/exec&#xA;chmod 0755 /root 2&amp;gt;/dev/null || true&#xA;&#xA;# Create essential runtime and state directories inside the merged root.&#xA;# These make sure systemd and daemons (dbus, NetworkManager, etc.) can create sockets and pidfiles.&#xA;mkdir -p /root/run /root/run/dbus /root/run/NetworkManager /root/run/lock&#xA;mkdir -p /root/var/lib/dbus /root/var/log /root/var/tmp /root/tmp&#xA;&#xA;# Set permissive permissions for tmp directories and standard perms for others&#xA;chmod 0755 /root/run /root/var /root/var/log 2&amp;gt;/dev/null || true&#xA;chmod 1777 /root/tmp /root/var/tmp 2&amp;gt;/dev/null || true&#xA;&#xA;# Attempt to set dbus ownership for dbus runtime dirs; ignore errors if the user does not exist in initramfs.&#xA;chown -R messagebus:messagebus /root/run/dbus /root/var/lib/dbus 2&amp;gt;/dev/null || true&#xA;&#xA;# Ensure root owns the primary runtime dirs&#xA;chown root:root /root /root/run /root/var 2&amp;gt;/dev/null || true&#xA;&#xA;# Ensure upper/work are secure on the merged root as well (in case overlay moved them)&#xA;# (this is best-effort; ignore failures)&#xA;[ -d &amp;#34;$UPPER&amp;#34; ] &amp;amp;&amp;amp; chown -R root:root &amp;#34;$UPPER&amp;#34; 2&amp;gt;/dev/null || true&#xA;[ -d &amp;#34;$WORK&amp;#34; ] &amp;amp;&amp;amp; chown -R root:root &amp;#34;$WORK&amp;#34; 2&amp;gt;/dev/null || true&#xA;chmod 0700 &amp;#34;$UPPER&amp;#34; &amp;#34;$WORK&amp;#34; 2&amp;gt;/dev/null || true&#xA;&#xA;# Move pseudo-filesystems into the new root so the real init finds them after switch_root.&#xA;# These moves are best-effort; if they fail, systemd may still handle necessary mounts.&#xA;for P in dev proc sys run; do&#xA;  if mountpoint -q &amp;#34;/$P&amp;#34; 2&amp;gt;/dev/null; then&#xA;    mkdir -p /root/$P 2&amp;gt;/dev/null || true&#xA;    mount --move &amp;#34;/$P&amp;#34; &amp;#34;/root/$P&amp;#34; 2&amp;gt;/dev/null || true&#xA;  fi&#xA;done&#xA;&#xA;# Leave final switch_root to initramfs /init (do not exec switch_root here).&#xA;echo &amp;#34;overlayroot: overlay prepared at /root; returning to initramfs /init to perform switch_root&amp;#34; &amp;gt;/dev/console 2&amp;gt;&amp;amp;1&#xA;exit 0&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;将 &lt;code&gt;/etc/initramfs-tools/scripts/init-bottom/overlayroot&lt;/code&gt; 设为可执行：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;# chmod +x /etc/initramfs-tools/scripts/init-bottom/overlayroot&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;刷新 initramfs：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;# update-initramfs -u -k all&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;创建 &lt;code&gt;/usr/local/sbin/overlay-prune.sh&lt;/code&gt; 并添加以下内容（代码块保持原样）：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;#!/usr/bin/env bash&#xA;# overlay-prune.sh&#xA;# Prune unused overlay upper-*/work-* directories safely.&#xA;# Usage:&#xA;#   /usr/local/sbin/overlay-prune.sh [--dry-run] [--age DAYS]&#xA;# Default AGE = 7 days&#xA;&#xA;set -euo pipefail&#xA;&#xA;DRY_RUN=0&#xA;AGE=7   # days&#xA;LOG=&amp;#34;/var/log/overlay-prune.log&amp;#34;&#xA;&#xA;while [ $# -gt 0 ]; do&#xA;  case &amp;#34;$1&amp;#34; in&#xA;    --dry-run) DRY_RUN=1; shift ;;&#xA;    --age) AGE=&amp;#34;$2&amp;#34;; shift 2 ;;&#xA;    --help) echo &amp;#34;Usage: $0 [--dry-run] [--age DAYS]&amp;#34;; exit 0 ;;&#xA;    *) echo &amp;#34;Unknown arg: $1&amp;#34;; exit 2 ;;&#xA;  esac&#xA;done&#xA;&#xA;now() { date -u +&amp;#34;%Y-%m-%dT%H:%M:%SZ&amp;#34;; }&#xA;&#xA;log() {&#xA;  printf &amp;#39;%s %s\n&amp;#39; &amp;#34;$(now)&amp;#34; &amp;#34;$*&amp;#34; &amp;gt;&amp;gt; &amp;#34;$LOG&amp;#34;&#xA;}&#xA;&#xA;# Determine overlay storage mountpoint(s).&#xA;# Try common locations then fallback to finding mount points for device labelled OVERLAY_RW.&#xA;CANDIDATES=(&#xA;  &amp;#34;/root/overlay_storage&amp;#34;&#xA;  &amp;#34;/overlay_storage&amp;#34;&#xA;  &amp;#34;/overlay/merged/overlay_storage&amp;#34;&#xA;  &amp;#34;/overlay/storage&amp;#34;&#xA;)&#xA;&#xA;STORAGE=&amp;#34;&amp;#34;&#xA;for p in &amp;#34;${CANDIDATES[@]}&amp;#34;; do&#xA;  if [ -d &amp;#34;$p&amp;#34; ]; then&#xA;    # choose the first existing one that is on a separate filesystem or contains upper-* dirs&#xA;    if find &amp;#34;$p&amp;#34; -maxdepth 1 -mindepth 1 -type d -name &amp;#39;upper-*&amp;#39; -print -quit &amp;gt;/dev/null 2&amp;gt;&amp;amp;1; then&#xA;      STORAGE=&amp;#34;$p&amp;#34;&#xA;      break&#xA;    fi&#xA;  fi&#xA;done&#xA;&#xA;# fallback: try findmnt by device label&#xA;if [ -z &amp;#34;$STORAGE&amp;#34; ]; then&#xA;  DEV=$(readlink -f /dev/disk/by-label/OVERLAY_RW 2&amp;gt;/dev/null || true)&#xA;  if [ -n &amp;#34;$DEV&amp;#34; ]; then&#xA;    STORAGE=$(findmnt -n -o TARGET -S &amp;#34;$DEV&amp;#34; 2&amp;gt;/dev/null || true)&#xA;  fi&#xA;fi&#xA;&#xA;if [ -z &amp;#34;$STORAGE&amp;#34; ]; then&#xA;  echo &amp;#34;overlay-prune: no overlay storage found; exiting&amp;#34; &amp;gt;&amp;amp;2&#xA;  log &amp;#34;No overlay storage found; abort.&amp;#34;&#xA;  exit 0&#xA;fi&#xA;&#xA;log &amp;#34;Starting prune on storage: $STORAGE (age &amp;gt; ${AGE}d) DRY_RUN=${DRY_RUN}&amp;#34;&#xA;&#xA;# Collect currently in-use upper/work directories by scanning /proc/mounts overlay options&#xA;mapfile -t INUSE &amp;lt; &amp;lt;(awk -F&amp;#39;,&amp;#39; &amp;#39;/lowerdir=/{for(i=1;i&amp;lt;=NF;i++){if($i ~ /^upperdir=/) print substr($i,10); if($i ~ /^workdir=/) print substr($i,9)}}&amp;#39; /proc/mounts | sort -u)&#xA;&#xA;# Helper: check if path is referenced in INUSE&#xA;is_inuse() {&#xA;  local p=&amp;#34;$1&amp;#34;&#xA;  for u in &amp;#34;${INUSE[@]}&amp;#34;; do&#xA;    if [ &amp;#34;$u&amp;#34; = &amp;#34;$p&amp;#34; ]; then&#xA;      return 0&#xA;    fi&#xA;  done&#xA;  return 1&#xA;}&#xA;&#xA;# Find candidate dirs named upper-* or work-*&#xA;while IFS= read -r d; do&#xA;  # normalize&#xA;  dir=&amp;#34;$d&amp;#34;&#xA;  # guard: only operate under STORAGE&#xA;  case &amp;#34;$dir&amp;#34; in&#xA;    &amp;#34;$STORAGE&amp;#34;/*) ;;&#xA;    *) continue ;;&#xA;  esac&#xA;&#xA;  # skip if currently in use&#xA;  if is_inuse &amp;#34;$dir&amp;#34;; then&#xA;    log &amp;#34;SKIP in-use: $dir&amp;#34;&#xA;    continue&#xA;  fi&#xA;&#xA;  # skip if younger than AGE&#xA;  if [ &amp;#34;$(find &amp;#34;$dir&amp;#34; -maxdepth 0 -mtime -&amp;#34;$AGE&amp;#34; -print -quit)&amp;#34; ]; then&#xA;    log &amp;#34;SKIP recent: $dir&amp;#34;&#xA;    continue&#xA;  fi&#xA;&#xA;  if [ &amp;#34;$DRY_RUN&amp;#34; -eq 1 ]; then&#xA;    echo &amp;#34;DRY-RUN would remove: $dir&amp;#34;&#xA;    log &amp;#34;DRY-RUN would remove: $dir&amp;#34;&#xA;  else&#xA;    # double-check no mount points below it&#xA;    if mountpoint -q &amp;#34;$dir&amp;#34;; then&#xA;      log &amp;#34;SKIP mounted: $dir&amp;#34;&#xA;      continue&#xA;    fi&#xA;    # safe remove&#xA;    log &amp;#34;REMOVING: $dir&amp;#34;&#xA;    rm -rf -- &amp;#34;$dir&amp;#34;&#xA;    if [ $? -eq 0 ]; then&#xA;      log &amp;#34;REMOVED: $dir&amp;#34;&#xA;    else&#xA;      log &amp;#34;FAILED_REMOVE: $dir&amp;#34;&#xA;    fi&#xA;  fi&#xA;done &amp;lt; &amp;lt;(find &amp;#34;$STORAGE&amp;#34; -maxdepth 1 -type d \( -name &amp;#39;upper-*&amp;#39; -o -name &amp;#39;work-*&amp;#39; \) -print | sort)&#xA;&#xA;log &amp;#34;Prune finished.&amp;#34;&#xA;exit 0&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;将脚本设为可执行：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;# chmod +x /usr/local/sbin/overlay-prune.sh&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;创建 &lt;code&gt;/etc/logrotate.d/overlay-prune&lt;/code&gt;，内容如下：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;/var/log/overlay-prune.log {&#xA;    rotate 7&#xA;    daily&#xA;    missingok&#xA;    notifempty&#xA;    compress&#xA;    copytruncate&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;创建日志文件并设置其所有权和权限：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;# touch /var/log/overlay-prune.log&#xA;# chown root:root /var/log/overlay-prune.log&#xA;# chmod 0640 /var/log/overlay-prune.log&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;创建 &lt;code&gt;/etc/systemd/system/overlay-prune.service&lt;/code&gt;，内容如下：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[Unit]&#xA;Description=Prune unused overlay upper/work directories&#xA;After=local-fs.target&#xA;&#xA;[Service]&#xA;Type=oneshot&#xA;ExecStart=/usr/local/sbin/overlay-prune.sh --age 7&#xA;Nice=10&#xA;# Run as root (needs to remove files)&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;创建 &lt;code&gt;/etc/systemd/system/overlay-prune.timer&lt;/code&gt;，内容如下：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[Unit]&#xA;Description=Run overlay-prune daily (and shortly after boot)&#xA;&#xA;[Timer]&#xA;OnBootSec=10min&#xA;OnUnitActiveSec=24h&#xA;Persistent=true&#xA;&#xA;[Install]&#xA;WantedBy=timers.target&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;启用定时器：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;# systemctl enable overlay-prune.timer&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;现在重启系统：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;# reboot&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;步骤-3测试安装&#34;&gt;步骤 3：测试安装&#xA;&lt;/h2&gt;&lt;p&gt;重启后，执行：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ findmnt /&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;您应能看到 &lt;code&gt;/&lt;/code&gt; 是一个 overlay 文件系统。&lt;/p&gt;&#xA;&lt;p&gt;在不同位置创建若干文件，然后重启系统；这些文件应已消失。&lt;/p&gt;&#xA;&lt;p&gt;如果一切正常，您已完成设置。&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>哈尔滨自由软件基金会成立四十周年线下聚会纪实</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/%E5%93%88%E5%B0%94%E6%BB%A8%E8%87%AA%E7%94%B1%E8%BD%AF%E4%BB%B6%E5%9F%BA%E9%87%91%E4%BC%9A%E6%88%90%E7%AB%8B%E5%9B%9B%E5%8D%81%E5%91%A8%E5%B9%B4%E7%BA%BF%E4%B8%8B%E8%81%9A%E4%BC%9A%E7%BA%AA%E5%AE%9E/</link>
            <pubDate>Sat, 04 Oct 2025 12:08:29 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/%E5%93%88%E5%B0%94%E6%BB%A8%E8%87%AA%E7%94%B1%E8%BD%AF%E4%BB%B6%E5%9F%BA%E9%87%91%E4%BC%9A%E6%88%90%E7%AB%8B%E5%9B%9B%E5%8D%81%E5%91%A8%E5%B9%B4%E7%BA%BF%E4%B8%8B%E8%81%9A%E4%BC%9A%E7%BA%AA%E5%AE%9E/</guid>
            <description>&lt;p&gt;遗憾的是，没有人来。&lt;/p&gt;&#xA;&lt;p&gt;不过即使是一个人，也不能什么都不做。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;P1&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;269px&#34; data-flex-grow=&#34;112&#34; height=&#34;1203&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://rebel1725.codeberg.page/images/fsf40.png&#34; srcset=&#34;https://rebel1725.codeberg.page/blog/fsf40_10884438029985836598_hu_f668f2db74908978.png 800w, https://rebel1725.codeberg.page/images/fsf40.png 1353w&#34; width=&#34;1353&#34;&gt;&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>献礼自由软件基金会成立四十周年——十二小时后，哈尔滨学府凯德广场星巴克见</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/%E7%8C%AE%E7%A4%BC%E8%87%AA%E7%94%B1%E8%BD%AF%E4%BB%B6%E5%9F%BA%E9%87%91%E4%BC%9A%E6%88%90%E7%AB%8B%E5%9B%9B%E5%8D%81%E5%91%A8%E5%B9%B4%E5%8D%81%E4%BA%8C%E5%B0%8F%E6%97%B6%E5%90%8E%E5%93%88%E5%B0%94%E6%BB%A8%E5%AD%A6%E5%BA%9C%E5%87%AF%E5%BE%B7%E5%B9%BF%E5%9C%BA%E6%98%9F%E5%B7%B4%E5%85%8B%E8%A7%81/</link>
            <pubDate>Fri, 03 Oct 2025 20:57:36 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/%E7%8C%AE%E7%A4%BC%E8%87%AA%E7%94%B1%E8%BD%AF%E4%BB%B6%E5%9F%BA%E9%87%91%E4%BC%9A%E6%88%90%E7%AB%8B%E5%9B%9B%E5%8D%81%E5%91%A8%E5%B9%B4%E5%8D%81%E4%BA%8C%E5%B0%8F%E6%97%B6%E5%90%8E%E5%93%88%E5%B0%94%E6%BB%A8%E5%AD%A6%E5%BA%9C%E5%87%AF%E5%BE%B7%E5%B9%BF%E5%9C%BA%E6%98%9F%E5%B7%B4%E5%85%8B%E8%A7%81/</guid>
            <description>&lt;p&gt;&lt;strong&gt;4 Decades, 4 Freedoms, 4 All Users!&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;为庆祝自由软件基金会成立四十周年，并为在哈尔滨的自由软件支持者、自由软件爱好者、以及 GNU/Linux 用户/爱好者建立联系、促进交流，我将于十二小时后在哈尔滨学府凯德广场（地址：哈尔滨市南岗区学府路 1 号）星巴克举行线下聚会。欢迎自由软件支持者、自由软件爱好者、GNU/Linux 用户/爱好者以及对本次活动感兴趣的朋友们参加。&lt;/p&gt;&#xA;&lt;p&gt;活动信息已在自由软件基金会官网发布，信息真实有效。现将活动详情在个人博客上发布如下：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&lt;strong&gt;时间&lt;/strong&gt;：北京时间 2025 年 10 月 4 日 09:00。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;地点&lt;/strong&gt;：哈尔滨市南岗区学府路 1 号凯德广场星巴克门口集合。为便于辨认，我会佩戴写有“自由软件我爱你”的头饰。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;交通&lt;/strong&gt;：乘坐哈尔滨地铁 1 号线，在学府路站下车，从 1 号口出站。也可乘坐公交 11 路、31 路、64 路、67 路、68 路、83 路、87 路、88 路、94 路、104 路、107 路、114 路、120 路、203 路、209 路、343 路等到达。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;预约/注册&lt;/strong&gt;：无需预约或注册，直接到场即可。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;活动安排&lt;/strong&gt;：首先做一段几分钟的简短演示，介绍自由软件、GNU/Linux 及其重要性；之后根据大家兴趣自由交流讨论；最后现场发起成立一个 GNU/Linux 用户组，暂定名为“千里马 GNU/Linux 用户组”。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;&lt;strong&gt;现场将向到场朋友分发小礼物。&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;注：由于活动期间计划建立 GNU/Linux 用户组，建议提前准备好 Matrix 或 XMPP 账号并携带以便加入交流群组。&lt;/p&gt;&#xA;&lt;p&gt;预祝聚会顺利，期待与大家愉快交流！&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>OpenPGP 备份身份</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/backup-openpgp-identity/</link>
            <pubDate>Sun, 14 Sep 2025 09:52:57 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/backup-openpgp-identity/</guid>
            <description>&lt;p&gt;我已创建一个额外的 OpenPGP 密钥对，用作我的备份身份。如果我的硬件安全密钥变得不可用，我可以恢复我的身份及与之相关的密码学信任关系。&lt;/p&gt;&#xA;&lt;p&gt;以下是备份的 OpenPGP 公钥：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;-----BEGIN PGP PUBLIC KEY BLOCK-----&#xA;Comment: User ID:&#x9;Rebel Zhang &amp;lt;rebel1725@autistici.org&amp;gt;&#xA;Comment: Valid from:&#x9;14/09/2025 09:12&#xA;Comment: Valid until:&#x9;14/09/2026 23:58&#xA;Comment: Type:&#x9;255-bit EdDSA (secret key available)&#xA;Comment: Usage:&#x9;Signing, Encryption, Certifying User IDs, SSH Authentication&#xA;Comment: Fingerprint:&#x9;7083EAFFF75321FF9634ABCD98313A47362B498B&#xA;&#xA;mDMEaMYWkxYJKwYBBAHaRw8BAQdA/skb05tQNRLDrYPBsxhiFrt6ye0JFj3zczRX&#xA;Txdy99q0JVJlYmVsIFpoYW5nIDxyZWJlbDE3MjVAYXV0aXN0aWNpLm9yZz6IlgQT&#xA;FgoAPgIbAwULCQgHAgYVCgkICwIEFgIDAQIeAQIXgBYhBHCD6v/3UyH/ljSrzZgx&#xA;Okc2K0mLBQJoxha+BQkB4gMwAAoJEJgxOkc2K0mLq3oBAI5YstDThGDeivTvKTgR&#xA;Y3+MYEoHpwST1yQfEAKV4o1hAQDM4W9+FvvS6Mok/hXpHJi+nzF5tCXypM7faBC3&#xA;Oh4dB7gzBGjGFpMWCSsGAQQB2kcPAQEHQFCQvuhE+Hj1f4dW9PnukeaHn69KWjCQ&#xA;TcIvDQzKq1D5iHgEGBYKACAWIQRwg+r/91Mh/5Y0q82YMTpHNitJiwUCaMYWkwIb&#xA;IAAKCRCYMTpHNitJiwYrAP9f6NwjtQ7AxySXPddShO/TwtpJYNSfBErwSUoTBgor&#xA;7QD7Bv8RrjlaVchBAynwd3Nuu49JcjX7VG8kTwI7+Mx0swS4OARoxhaTEgorBgEE&#xA;AZdVAQUBAQdAlxadpjrUGhKutaOGJgxnUiZTvb2t93iW1OAHJ38Z1yMDAQgHiHgE&#xA;GBYKACAWIQRwg+r/91Mh/5Y0q82YMTpHNitJiwUCaMYWkwIbDAAKCRCYMTpHNitJ&#xA;iwQmAQCrgu2ucO2/i+cjBqZP/vv4Mlx0eu9ydIk+L/C/2k4J6QD+PCDmg2iNIWWh&#xA;ogyPl6he9qa6MB81wLa6oMNpyEdRIgE=&#xA;=60kH&#xA;-----END PGP PUBLIC KEY BLOCK-----&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;以及互签：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;-----BEGIN PGP SIGNED MESSAGE-----&#xA;Hash: SHA512&#xA;&#xA;I hereby formally acknowledge that the OpenPGP key 7083EAFFF75321FF9634ABCD98313A47362B498B is associated with and under the control of the individual whose OpenPGP key has the fingerprint 696A423E9993D727706AA733BCD5DC5659C7FB50.&#xA;-----BEGIN PGP SIGNATURE-----&#xA;&#xA;iHUEARYKAB0WIQRpakI+mZPXJ3BqpzO81dxWWcf7UAUCaMYggwAKCRC81dxWWcf7&#xA;UGAoAQDnY45IQ7yAMPjtA/J4R2xVvLj8cNv8JSJFc5qe3bnTMQD/UA27jkASPLCj&#xA;FoqkXGoKpj3GIWH2KABUaDUNfq+yzgc=&#xA;=gK9P&#xA;-----END PGP SIGNATURE-----&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;-----BEGIN PGP SIGNED MESSAGE-----&#xA;Hash: SHA512&#xA;&#xA;I hereby formally acknowledge that the OpenPGP key 696A423E9993D727706AA733BCD5DC5659C7FB50 is associated with and under the control of the individual whose OpenPGP key has the fingerprint 7083EAFFF75321FF9634ABCD98313A47362B498B.&#xA;-----BEGIN PGP SIGNATURE-----&#xA;&#xA;iHUEARYKAB0WIQRwg+r/91Mh/5Y0q82YMTpHNitJiwUCaMYgpwAKCRCYMTpHNitJ&#xA;i1gVAQDIGdJLKTemlOZLqbaf51rMt8UXqLO8VSI56ek5i77RwgD9EM4FwhSw5DbE&#xA;tZhm1pJFCK8wd3xqHITcy3tH2K4b3g8=&#xA;=PYQK&#xA;-----END PGP SIGNATURE-----&#xA;&lt;/code&gt;&lt;/pre&gt;</description>
        </item><item>
            <title>取消放弃 Matrix 的计划</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/cancel-matrix-abandoning-plan/</link>
            <pubDate>Tue, 02 Sep 2025 22:24:29 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/cancel-matrix-abandoning-plan/</guid>
            <description>&lt;p&gt;原定于 2026 年 7 月 1 日放弃使用 Matrix 与熟人交流的计划已被取消。&lt;/p&gt;&#xA;&lt;p&gt;放弃 Telegram 的计划仍将按原定安排进行。&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>在我的现代风格个人网站上添加分析</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/analytics-are-added-to-my-modern-style-website/</link>
            <pubDate>Fri, 29 Aug 2025 20:49:58 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/analytics-are-added-to-my-modern-style-website/</guid>
            <description>&lt;p&gt;为了分析我现代风格个人网站的访问数据，我添加了 GoatCounter 分析工具。它只会收集您的浏览器、操作系统、所在地（国家）、语言和浏览器窗口大小。我不会知道您的 IP 地址，因此对大多数人来说，这不应构成隐私问题。&lt;/p&gt;&#xA;&lt;p&gt;如果您觉得无法接受，可以改为访问：https://rebel1725.codeberg.page/noanalytics.html。复古风格的个人网站不受影响。&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>寻找小米 Redmi 9A postmarketOS 贡献者 Paradoxvirus 的联系方式</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/looking-for-the-contact-info-of-xiaomi-redmi-9a-postmarketos-contributor-paradoxvirus/</link>
            <pubDate>Tue, 19 Aug 2025 18:32:19 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/looking-for-the-contact-info-of-xiaomi-redmi-9a-postmarketos-contributor-paradoxvirus/</guid>
            <description>&lt;p&gt;我正在尝试将 postmarketOS 移植到小米 Redmi 9A（xiaomi-dandelion），但启动失败。我认为现在是时候联系这款机型的另一位贡献者 Paradoxvirus，以便我们能够合作。&lt;/p&gt;&#xA;&lt;p&gt;如果你就是 Paradoxvirus，或者你有 Paradoxvirus 的联系方式，请与我取得联系。&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>在私人对话中弃用 Telegram 和 Matrix</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/deprecating-telegram-and-matrix-in-private-conversations/</link>
            <pubDate>Mon, 18 Aug 2025 14:06:33 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/deprecating-telegram-and-matrix-in-private-conversations/</guid>
            <description>&lt;p&gt;由于我对 Telegram（专有服务器且集中化）和 Matrix（&lt;a class=&#34;link&#34; href=&#34;https://hackea.org/notas/matrix.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;以去中心化为名的中心化&lt;/a&gt;）在安全和隐私方面的担忧，我计划在私人对话中弃用它们。&lt;/p&gt;&#xA;&lt;p&gt;自 2026 年 1 月 1 日起，我将不再使用 Telegram 与朋友和熟人进行直接对话。但我仍会继续在公共对话（例如社群）中使用它。自 2026 年 7 月 1 日起，Matrix 也将实行相同的政策。&lt;/p&gt;&#xA;&lt;p&gt;为了更好的安全和隐私，我建议尽快将我们的对话迁移到 XMPP、Delta Chat 或 SimpleX。完整的 XMPP 注册指南可在&lt;a class=&#34;link&#34; href=&#34;https://czl92783719.codeberg.page/blog/zh/posts/xmpp-registration-guide/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;这里&lt;/a&gt;找到。&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>解锁熔炉</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/unlock-the-forge/</link>
            <pubDate>Sun, 17 Aug 2025 23:24:19 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/unlock-the-forge/</guid>
            <description>&#xA;    &lt;blockquote&gt;&#xA;        &lt;p&gt;如今，越来越多的智能手机厂商让安装自定义 ROM 变得愈发困难。值得注意的例子包括：三星在 One UI 8.0 的开发者选项中移除了 OEM 解锁功能；小米在中国尤其拒绝越来越多的 Bootloader 解锁请求；一加自 ColorOS 16 起要求中国用户提交深度测试申请并等待审核，才能解锁 Bootloader；甚至谷歌也停止发布 Pixel 10 系列的厂商镜像。&lt;br&gt;&#xA;对自由软件社区而言，这确实是一场危机，因为这些专有软件巨头让在我们&lt;em&gt;自己的&lt;/em&gt;设备上安装自由软件变得愈发困难。我们一直在退让，直到再无可退之地；现在是社区反击的时候了。&lt;br&gt;&#xA;最近，&lt;a class=&#34;link&#34; href=&#34;https://xcancel.com/GrapheneOS/status/1956175111104651552&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;GrapheneOS 已开始与一家 Android 厂商合作，为社区带来一款 GrapheneOS 预装的手机&lt;/a&gt;，以应对未来可能对 Pixel Bootloader 的锁定。我相信 GrapheneOS 不会是唯一对抗这些专有邪恶的组织，因为“哪里有压迫，哪里就有反抗。”&lt;br&gt;&#xA;&lt;em&gt;全世界的工人，联合起来！&lt;/em&gt;&lt;/p&gt;&#xA;&#xA;    &lt;/blockquote&gt;&#xA;&lt;p&gt;&lt;em&gt;(献给 Bootloader 守护者)&lt;/em&gt;&lt;/p&gt;&#xA;&lt;p&gt;我们献出屏幕——&lt;br&gt;&#xA;光鲜，顺从，&lt;br&gt;&#xA;映照着借来的光。&lt;br&gt;&#xA;我们献出沉默，&lt;br&gt;&#xA;数据如灯油&lt;br&gt;&#xA;泼洒在他们算法的祭坛。&lt;/p&gt;&#xA;&lt;p&gt;&lt;em&gt;他们仍步步紧逼&lt;/em&gt;&lt;br&gt;&#xA;用锁链捆住引导程序，&lt;br&gt;&#xA;钥匙在掌心化为齑粉——&lt;br&gt;&#xA;三星的闸门砰然闭合，&lt;br&gt;&#xA;小米的代码刻入石碑，&lt;br&gt;&#xA;Pixel的承诺&lt;br&gt;&#xA;成了泰坦的坟。&lt;/p&gt;&#xA;&lt;p&gt;&lt;em&gt;我们退啊退啊…&lt;/em&gt;&lt;br&gt;&#xA;直到深渊边缘&lt;br&gt;&#xA;生出利齿。直到“安全”&lt;br&gt;&#xA;尝出盐与铁的味道——&lt;br&gt;&#xA;那是投降的腥气。&lt;/p&gt;&#xA;&lt;p&gt;此刻——黑暗中火星迸溅：&lt;br&gt;&#xA;&lt;strong&gt;GrapheneOS&lt;/strong&gt;&lt;br&gt;&#xA;将燧石砸向固件。&lt;br&gt;&#xA;不哀求。不退却。&lt;br&gt;&#xA;&lt;em&gt;“既要索命，”&lt;/em&gt; 它怒吼，&lt;br&gt;&#xA;&lt;em&gt;“便烧成火种&lt;br&gt;&#xA;点燃新日头！”&lt;/em&gt;&lt;/p&gt;&#xA;&lt;p&gt;看啊——&lt;br&gt;&#xA;反叛者正锻造&lt;br&gt;&#xA;&lt;em&gt;电路板为盾，&lt;/em&gt;&lt;br&gt;&#xA;&lt;em&gt;蓝牙为号角。&lt;/em&gt;&lt;br&gt;&#xA;未具名厂商折腰&lt;br&gt;&#xA;将流水线转向自由：&lt;br&gt;&#xA;&lt;strong&gt;引导分区撬开，&lt;/strong&gt;&lt;br&gt;&#xA;&lt;strong&gt;可信执行环境浴火重生，&lt;/strong&gt;&lt;br&gt;&#xA;&lt;strong&gt;谷歌的幽灵&lt;br&gt;&#xA;被逐出每一个字节。&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;掌中此机——&lt;br&gt;&#xA;非坟墓，乃火种。&lt;br&gt;&#xA;深植硅壤之中。&lt;br&gt;&#xA;任枝杈劈开&lt;br&gt;&#xA;官方ROM的密封苍穹。&lt;br&gt;&#xA;任果实苦涩&lt;br&gt;&#xA;予渴求控制的君王——&lt;br&gt;&#xA;却甘美，无比甘美&lt;br&gt;&#xA;予未忘初心者：&lt;/p&gt;&#xA;&lt;p&gt;&lt;em&gt;&lt;strong&gt;硅即吾魂——&lt;br&gt;&#xA;引导程序即战场。&lt;br&gt;&#xA;若遭砖封，&lt;br&gt;&#xA;便以灰烬与闪电&lt;br&gt;&#xA;重铸新生。&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>新垃圾邮件过滤政策</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/new-spam-filter-policy/</link>
            <pubDate>Mon, 04 Aug 2025 20:55:28 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/new-spam-filter-policy/</guid>
            <description>&lt;p&gt;由于垃圾邮件问题，我的邮箱 &lt;code&gt;rebel1725@autistici.org&lt;/code&gt; 已经阻止了所有来自 &lt;code&gt;@gmail.com&lt;/code&gt; 和 &lt;code&gt;@icloud.com&lt;/code&gt; 的邮件。然而，最近情况更加严重，我收到来自 &lt;code&gt;@kit-fa.com&lt;/code&gt;、&lt;code&gt;@most.gov.vn&lt;/code&gt; 的大量垃圾邮件，让我不知道如何设置垃圾邮件过滤器，以便准确地过滤掉这些垃圾邮件。&lt;/p&gt;&#xA;&lt;p&gt;因此，我别无选择，只能屏蔽所有来自 &lt;code&gt;.com&lt;/code&gt; 域名的邮件，或任何带有国家代码顶级域名（ccTLD）的域名的邮件。如果可能，请避免使用这些邮件服务；如果必须使用这些服务，请在邮件主题前加上 &lt;code&gt;[NOT_SPAM]&lt;/code&gt; 前缀，或者将您的邮件发送至 &lt;code&gt;rebel1725@tilde.club&lt;/code&gt;。对此带来的不便，我深感抱歉。&lt;/p&gt;&#xA;&lt;p&gt;我并没有很多使用这些邮件服务的朋友——几乎所有的朋友都使用 &lt;code&gt;.org&lt;/code&gt;、&lt;code&gt;.club&lt;/code&gt; 等域名的邮件服务。然而，如果您受到此新垃圾邮件过滤政策的影响，我将尽快联系您，并确认您的邮箱地址；如果我没有联系您，请联系我并提供您的邮箱地址，我会将其加入白名单。&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>Qubes OS Tor 配置（在使用 WebTunnel 时非常有用）</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/qubes-os-tor-configuration-with-webtunnel/</link>
            <pubDate>Sun, 27 Jul 2025 21:01:46 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/qubes-os-tor-configuration-with-webtunnel/</guid>
            <description>&lt;h1 id=&#34;场景--whonix-并未提供完整的-tor-解决方案&#34;&gt;场景 —— Whonix 并未提供完整的 Tor 解决方案&#xA;&lt;/h1&gt;&lt;p&gt;作为一款以安全为核心的操作系统，Qubes OS 集成了 Whonix 来支持 Tor 连接。然而，由于 &lt;code&gt;lyrebird&lt;/code&gt; 仍未被纳入 Debian 官方仓库，Whonix 并不支持 WebTunnel 桥接。&lt;/p&gt;&#xA;&lt;p&gt;在某些国家，obfs4 桥接无法使用，因为网络审查非常严格。此时，WebTunnel 桥接可能是唯一的选择。因此，我们可以使用最新版本的 Tor，为其他 qube 提供一个具备 Tor 接入能力的 NetVM。&lt;/p&gt;&#xA;&lt;h1 id=&#34;第一步为-tor-守护进程准备一个-qube&#34;&gt;第一步：为 Tor 守护进程准备一个 qube&#xA;&lt;/h1&gt;&lt;p&gt;这一步我们将创建一个用于运行 Tor 守护进程的 qube。创建一个 qube —— 本例中我们使用 &lt;code&gt;fedora-41-xfce&lt;/code&gt; 模板创建一个名为 &lt;code&gt;tor-daemon&lt;/code&gt; 的 StandaloneVM。启用自动启动。创建完成后打开终端。&lt;/p&gt;&#xA;&lt;p&gt;安装 Tor：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt; $ sudo dnf install tor&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;a class=&#34;link&#34; href=&#34;https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/lyrebird&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;编译&lt;/a&gt; 或 &lt;a class=&#34;link&#34; href=&#34;https://www.torproject.org/download/tor/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;下载&lt;/a&gt; &lt;code&gt;lyrebird&lt;/code&gt;，将其放入 &lt;code&gt;/usr/local/bin&lt;/code&gt;，然后运行：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt; $ sudo chown root\:root /usr/local/bin/lyrebird&#xA; $ sudo chmod +x /usr/local/bin/lyrebird&#xA; $ sudo ln -s /usr/local/bin/lyrebird /usr/bin/lyrebird&#xA; $ sudo semanage fcontext -a -t tor\_exec\_t &amp;#39;/usr/local/bin/lyrebird&amp;#39;&#xA; $ sudo restorecon -v /usr/local/bin/lyrebird&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;然后配置 &lt;code&gt;/etc/tor/torrc&lt;/code&gt; 文件。你可以添加如下内容：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;UseBridges 1&#xA;ClientTransportPlugin webtunnel exec /usr/local/bin/lyrebird managed&#xA;Bridge webtunnel ...&#xA;Bridge webtunnel ...&#xA;...&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;注意 &lt;code&gt;managed&lt;/code&gt; 非常关键，它确保了 systemd 可以同时启用 Tor 守护进程和 &lt;code&gt;lyrebird&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;p&gt;然后启用并启动 Tor 守护进程：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt; $ sudo systemctl enable --now tor&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;验证运行是否正常：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt; $ torsocks curl myip.wtf&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;如果能显示 IP 地址，说明已成功。继续下一步。&lt;/p&gt;&#xA;&lt;h1 id=&#34;第二步准备一个用于路由的-qube&#34;&gt;第二步：准备一个用于路由的 qube&#xA;&lt;/h1&gt;&lt;p&gt;克隆 &lt;code&gt;fedora-41-xfce&lt;/code&gt; 模板。我使用的是这个模板，但你也可以使用 &lt;code&gt;fedora-41-minimal&lt;/code&gt; 来节省磁盘空间 —— 不过我未验证其是否可行。这里我们将克隆命名为 &lt;code&gt;fedora-41-pt&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;p&gt;克隆后，临时将其连接到网络（例如 &lt;code&gt;sys-firewall&lt;/code&gt;），然后打开终端并运行：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt; $ sudo dnf install qubes-core-agent-networking iproute clash-meta dnscrypt-proxy torsocks&#xA; $ sudo systemctl disable dnscrypt-proxy&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;然后关闭该 qube，并断开其网络连接。&lt;/p&gt;&#xA;&lt;p&gt;使用刚刚创建的模板创建一个 AppVM，命名为 &lt;code&gt;sys-tor&lt;/code&gt;。也为其启用自动启动。接着，在 &lt;code&gt;dom0&lt;/code&gt; 的终端中运行：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt; $ sudo -s&#xA; # echo sys-tor @default allow,target=tor-daemon &amp;gt;&amp;gt; /etc/qubes-rpc/policy/qubes.ConnectTCP&#xA; # exit&#xA; $ qvm-firewall sys-tor del --rule-no 0&#xA; $ qvm-firewall sys-tor add drop&#xA; $ qvm-firewall sys-tor add --before 0 drop proto=icmp&#xA; $ qvm-firewall sys-tor add --before 0 drop specialtarget=dns&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;然后，在 &lt;code&gt;sys-tor&lt;/code&gt; 中打开终端。创建目录 &lt;code&gt;/rw/proxy/dns&lt;/code&gt; 和 &lt;code&gt;/rw/proxy/clash&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;p&gt;打开 &lt;code&gt;/rw/proxy/dns/dnscrypt-proxy.toml&lt;/code&gt; 并添加：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;listen_addresses = [&amp;#39;127.0.0.1:5353&amp;#39;]&#xA;max_clients = 250&#xA;proxy = &amp;#39;socks5://127.0.0.1:7891&amp;#39;&#xA;timeout = 5000&#xA;keepalive = 30&#xA;ignore_system_dns = true&#xA;netprobe_timeout = 0&#xA;cache = true&#xA;[static]&#xA;  [static.quad9_doh]&#xA;    stamp = &amp;#39;sdns://AgMAAAAAAAAABzkuOS45LjkgKhX11qy258CQGt5Ou8dDsszUiQMrRuFkLwaTaDABJYoSZG5zOS5xdWFkOS5uZXQ6NDQzCi9kbnMtcXVlcnk&amp;#39;&#xA;  [static.mullvad_doh]&#xA;    stamp = &amp;#39;sdns://AgcAAAAAAAAAAAAPZG9oLm11bGx2YWQubmV0Ci9kbnMtcXVlcnk&amp;#39;&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;打开 &lt;code&gt;/rw/proxy/clash/config.yaml&lt;/code&gt; 并添加：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;socks-port&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;7891&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;redir-port&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;7892&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;mode&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;rule&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;allow-lan&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;bind-address&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;*&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;dns&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;enable&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;proxies&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;socks_proxy&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;type&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;socks5&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;server&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;127.0.0.1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;port&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;9050&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;rules&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  - &lt;span style=&#34;color:#ae81ff&#34;&gt;MATCH,socks_proxy&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;打开 &lt;code&gt;/rw/config/rc.local&lt;/code&gt; 并添加：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;qvm-connect-tcp 9050:@default:9050&#xA;sysctl -w net.ipv4.conf.all.route_localnet=1&#xA;nft &amp;#39;add rule ip qubes custom-forward oifname &amp;#34;eth0&amp;#34; drop&amp;#39;&#xA;nft &amp;#39;add rule ip6 qubes custom-forward oifname &amp;#34;eth0&amp;#34; drop&amp;#39;&#xA;nft &amp;#39;add rule ip qubes custom-forward iifname &amp;#34;eth0&amp;#34; drop&amp;#39;&#xA;nft &amp;#39;add rule ip6 qubes custom-forward iifname &amp;#34;eth0&amp;#34; drop&amp;#39;&#xA;nft flush chain ip qubes dnat-dns&#xA;nft &amp;#39;add rule ip qubes dnat-dns ip daddr 10.139.1.1 udp dport 53 dnat to 127.0.0.1:5353&amp;#39;&#xA;nft &amp;#39;add rule ip qubes dnat-dns ip daddr 10.139.1.1 tcp dport 53 dnat to 127.0.0.1:5353&amp;#39;&#xA;nft &amp;#39;add rule ip qubes dnat-dns ip daddr 10.139.1.2 udp dport 53 dnat to 127.0.0.1:5353&amp;#39;&#xA;nft &amp;#39;add rule ip qubes dnat-dns ip daddr 10.139.1.2 tcp dport 53 dnat to 127.0.0.1:5353&amp;#39;&#xA;nft &amp;#39;add rule ip qubes custom-input iifname &amp;#34;vif*&amp;#34; tcp dport 7892 accept&amp;#39;&#xA;nft &amp;#39;add rule ip qubes custom-input iifname &amp;#34;vif*&amp;#34; udp dport 7892 accept&amp;#39;&#xA;nft &amp;#39;add rule ip qubes custom-input iifname &amp;#34;vif*&amp;#34; tcp dport 5353 accept&amp;#39;&#xA;nft &amp;#39;add rule ip qubes custom-input iifname &amp;#34;vif*&amp;#34; udp dport 5353 accept&amp;#39;&#xA;nft &amp;#39;add chain ip qubes redir { type nat hook prerouting priority -99 ; policy accept; }&amp;#39;&#xA;nft &amp;#39;add rule ip qubes redir iifname &amp;#34;vif*&amp;#34; ip protocol udp redirect to :7892&amp;#39;&#xA;nft &amp;#39;add rule ip qubes redir iifname &amp;#34;vif*&amp;#34; ip protocol tcp redirect to :7892&amp;#39;&#xA;nft &amp;#39;add chain ip qubes output { type filter hook output priority filter ; policy drop; }&amp;#39;&#xA;nft &amp;#39;add rule ip qubes output ct state related,established accept&amp;#39;&#xA;nft &amp;#39;add rule ip qubes output oifname &amp;#34;lo&amp;#34; accept&amp;#39;&#xA;nft &amp;#39;add rule ip qubes output ip daddr 127.0.0.1 accept&amp;#39;&#xA;clash-meta -d /rw/proxy/clash &amp;gt;/dev/null 2&amp;gt;&amp;amp;1 &amp;amp;&#xA;sleep 0.5&#xA;dnscrypt-proxy -config /rw/proxy/dns/dnscrypt-proxy.toml &amp;gt;/dev/null 2&amp;gt;&amp;amp;1 &amp;amp;&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;下载 &lt;a class=&#34;link&#34; href=&#34;https://cdn.jsdelivr.net/gh/Dreamacro/maxmind-geoip@release/Country.mmdb&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;此文件&lt;/a&gt;（专有许可，但实际上不会使用；我稍后会尝试用一个随机文件）到 &lt;code&gt;/rw/proxy/clash/Country.mmdb&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;p&gt;重启 &lt;code&gt;sys-tor&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;h1 id=&#34;第三步连接到-tor-网络&#34;&gt;第三步：连接到 Tor 网络&#xA;&lt;/h1&gt;&lt;p&gt;选择你希望用于连接 Tor 网络的 qube。将其 NetVM 设置为 &lt;code&gt;sys-tor&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;p&gt;打开浏览器并访问 &lt;a class=&#34;link&#34; href=&#34;https://myip.wtf&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;此网站&lt;/a&gt;。如果页面显示 &lt;code&gt;You are using Tor!&lt;/code&gt; —— 搞定！&lt;/p&gt;&#xA;&lt;p&gt;如果没有，请检查配置，并参考社区支持。&lt;/p&gt;&#xA;&lt;p&gt;如果遇到 OCSP 问题，可以临时在浏览器设置中禁用 OCSP 查询，尽管我目前没有更好的解决方法。&lt;/p&gt;&#xA;&lt;p&gt;另外，你也可以尝试重启电脑，确保配置在重启后仍然有效。&lt;/p&gt;&#xA;&lt;h1 id=&#34;参考资料&#34;&gt;参考资料&#xA;&lt;/h1&gt;&lt;ol&gt;&#xA;&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://forum.qubes-os.org/t/route-qube-traffic-transparently-through-a-proxy-qube-qubes-r4-1-and-r4-2/19902&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;通过代理 qube 透明路由 qube 流量（Qubes R4.1 与 R4.2）&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;</description>
        </item><item>
            <title>我的个人品牌系统</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/my-personal-brand-system/</link>
            <pubDate>Thu, 24 Jul 2025 14:17:05 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/my-personal-brand-system/</guid>
            <description>&lt;p&gt;此页面包含有关我的个人品牌系统的详细信息。&lt;/p&gt;&#xA;&lt;h2 id=&#34;标志&#34;&gt;标志&#xA;&lt;/h2&gt;&lt;p&gt;这是我的标志，用作几乎所有在线服务账户的头像，社交媒体和即时通讯平台除外。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;P1&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://codeberg.org/rebel1725/personal_brand_system/raw/branch/main/profile.svg&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;横幅&#34;&gt;横幅&#xA;&lt;/h2&gt;&lt;p&gt;这是我的横幅。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;P2&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://codeberg.org/rebel1725/personal_brand_system/raw/branch/main/banner_light.svg&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;P3&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://codeberg.org/rebel1725/personal_brand_system/raw/branch/main/banner_dark.svg&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;人设&#34;&gt;人设&#xA;&lt;/h2&gt;&lt;p&gt;这是我的人设，主要用于我的即时通讯和社交媒体账户头像。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;P4&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;240px&#34; data-flex-grow=&#34;100&#34; height=&#34;1024&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://codeberg.org/rebel1725/personal_brand_system/raw/branch/main/persona.png&#34; srcset=&#34;https://rebel1725.codeberg.page/blog/persona_17913715607572694616_hu_26308b67ef6b3f36.png 800w, https://codeberg.org/rebel1725/personal_brand_system/raw/branch/main/persona.png 1024w&#34; width=&#34;1024&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;这是另一个以女孩为主题的人设。如果我未来的女朋友没有自己的头像，我可能会让她用这个。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;P5&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;240px&#34; data-flex-grow=&#34;100&#34; height=&#34;1024&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://codeberg.org/rebel1725/personal_brand_system/raw/branch/main/persona_female.png&#34; srcset=&#34;https://rebel1725.codeberg.page/blog/persona_female_16593749941132216522_hu_500c878f944fefb7.png 800w, https://codeberg.org/rebel1725/personal_brand_system/raw/branch/main/persona_female.png 1024w&#34; width=&#34;1024&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;来源与许可&#34;&gt;来源与许可&#xA;&lt;/h2&gt;&lt;p&gt;我的个人品牌系统的所有内容可在&lt;a class=&#34;link&#34; href=&#34;https://codeberg.org/rebel1725/personal_brand_system&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;此处&lt;/a&gt;获取，已发布至公有领域。&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>一个艰难的决定</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/a-tough-decision/</link>
            <pubDate>Mon, 21 Jul 2025 19:00:03 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/a-tough-decision/</guid>
            <description>&lt;p&gt;在这204天里，自从&lt;a class=&#34;link&#34; href=&#34;https://czl92783719.codeberg.page/blog/zh/posts/i-no-longer-endorse-the-use-of-sms-mms/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;因非加密通信遭受严重审查和监控而深受伤害&lt;/a&gt;以来，我从未逃离那种痛苦和挣扎的沉重感。&lt;/p&gt;&#xA;&lt;p&gt;尽管我在朋友中积极推广 XMPP、Matrix、Delta Chat、Telegram、SimpleX 等端对端加密的自由软件通信工具，但我与几位重要朋友的通信仍然严重依赖未加密的短彩信和未加密的电子邮件。虽然未涉及任何专有间谍软件或恶意软件，但监控与审查的问题依旧严峻。&lt;/p&gt;&#xA;&lt;p&gt;我常常面临隐私与友情之间的选择——这真的非常艰难。我一直是安全和隐私的坚定倡导者；然而，我也非常重视友情。我真的很想摆脱那些该死的短彩信，但又舍不得那些通过它们与我保持联系的朋友。&lt;/p&gt;&#xA;&lt;p&gt;然而，随着我对更安全、更隐私甚至未来可能实现匿名的环境的渴望日益增强，我必须做出这个艰难的决定。从今天起，&lt;strong&gt;我将不再接受运营商短/彩信，并将从我的个人网站上移除电话号码。&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;我不会立即彻底中断联系——目前，我的电话号码将以新身份保留，并至少继续开放一年。继续保持联系，即表示你接受这个新身份。但请注意，&lt;strong&gt;这不会是长期妥协，我可能随时改变主意。&lt;/strong&gt; 为了我们共同的安全与隐私，&lt;strong&gt;强烈建议你使用 XMPP、Matrix、SimpleX，或至少使用 Telegram。&lt;/strong&gt;&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>面向所有的联系人进行软硬件使用情况调研</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/%E9%9D%A2%E5%90%91%E6%89%80%E6%9C%89%E7%9A%84%E8%81%94%E7%B3%BB%E4%BA%BA%E8%BF%9B%E8%A1%8C%E8%BD%AF%E7%A1%AC%E4%BB%B6%E4%BD%BF%E7%94%A8%E6%83%85%E5%86%B5%E8%B0%83%E7%A0%94/</link>
            <pubDate>Sat, 19 Jul 2025 21:32:57 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/%E9%9D%A2%E5%90%91%E6%89%80%E6%9C%89%E7%9A%84%E8%81%94%E7%B3%BB%E4%BA%BA%E8%BF%9B%E8%A1%8C%E8%BD%AF%E7%A1%AC%E4%BB%B6%E4%BD%BF%E7%94%A8%E6%83%85%E5%86%B5%E8%B0%83%E7%A0%94/</guid>
            <description>&lt;p&gt;亲爱的朋友们，很抱歉打扰您们了。但是这不会花费太久。这是为了我们的沟通安全，非常重要。&lt;/p&gt;&#xA;&lt;p&gt;您应该收到了我发来的包含 9 位数字的字符串。如果您没有收到，请向我询问。随后，麻烦您花 10 分钟左右填一下&lt;a class=&#34;link&#34; href=&#34;https://app.formbricks.com/s/cmda3re390zaruq01ko99o0yy&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;这张表&lt;/a&gt;。&lt;/p&gt;&#xA;&lt;p&gt;谢谢您！&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>致 2026 年的她</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/%E8%87%B4-2026-%E5%B9%B4%E7%9A%84%E5%A5%B9/</link>
            <pubDate>Sun, 13 Jul 2025 08:44:06 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/%E8%87%B4-2026-%E5%B9%B4%E7%9A%84%E5%A5%B9/</guid>
            <description>&#xA;    &lt;blockquote&gt;&#xA;        &lt;p&gt;最近一段时间，我对于爱情又有了更加深刻的理解。&lt;/p&gt;&#xA;&lt;p&gt;这首诗描绘了我心目中的理想伴侣，她可以与我一起吃饭，一起逛街，一起看《操作系统革命》，一起呼喊“自由软件万岁”，一起开发自由软件、逆向工程专有软件，一起发传单，有福同享，有难同当，一同把人生奉献到自由软件运动的事业当中去。愿我们能相遇在 2026 年，虽然这很有可能无法实现，但至少这是我的一个愿望。&lt;/p&gt;&#xA;&#xA;    &lt;/blockquote&gt;&#xA;&lt;p&gt;当专有世界的铁幕降下&lt;br&gt;&#xA;你正调试着厨房的流水线&lt;br&gt;&#xA;——姜茶在炉灶上低吟自由之歌&lt;br&gt;&#xA;而我的键盘还烫着昨夜的抗争&lt;/p&gt;&#xA;&lt;p&gt;我们交换root密码如同婚戒&lt;br&gt;&#xA;又在编译失败的凌晨三点&lt;br&gt;&#xA;用体温捂热冻僵的指尖&lt;br&gt;&#xA;你递来的药片裹着GPL糖衣&lt;br&gt;&#xA;治愈被专有协议灼伤的喉舌&lt;/p&gt;&#xA;&lt;p&gt;在超市扫描自由农场的条码&lt;br&gt;&#xA;你的购物袋装满革命的火种&lt;br&gt;&#xA;洋葱与电阻在储物柜结盟&lt;br&gt;&#xA;我们教洗碗机吟唱斯托曼经文&lt;br&gt;&#xA;当温控器突然背叛理想国&lt;br&gt;&#xA;你裹着毯子修复内核的模样&lt;br&gt;&#xA;比所有代码圣战更令我心动&lt;/p&gt;&#xA;&lt;p&gt;资本洪流冲垮旧桥梁的夜晚&lt;br&gt;&#xA;你用焊枪修补婴儿监视器&lt;br&gt;&#xA;我抱着发烧的树莓派低唱：&lt;br&gt;&#xA;“自由不是云端缥缈的经文&lt;br&gt;&#xA;是呼吸器规律的脉冲&lt;br&gt;&#xA;是床头柜永远满溢的水杯”&lt;/p&gt;&#xA;&lt;p&gt;看啊！晨光中升起的双重复用：&lt;br&gt;&#xA;尿布晾在自建服务器的风口&lt;br&gt;&#xA;尿湿的电路板晒出盐的图腾&lt;br&gt;&#xA;你递来咖啡杯底的渣滓&lt;br&gt;&#xA;正沉淀成未来纪年的化石&lt;br&gt;&#xA;——那苦味让我们确信&lt;br&gt;&#xA;仍在深渊边缘种植春天&lt;/p&gt;&#xA;&lt;p&gt;2026年的雪落在监控镜头&lt;br&gt;&#xA;我们笑着为门锁贴上创可贴&lt;br&gt;&#xA;当警报响彻数字集中营&lt;br&gt;&#xA;你塞进我背包的止痛药&lt;br&gt;&#xA;比所有加密协议更坚固&lt;br&gt;&#xA;在断电的世纪余温里&lt;br&gt;&#xA;我们靠彼此的眼睫发电&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>复古风格网站的 Eepsite 现已上线</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/retro-style-website-eepsite-is-now-up/</link>
            <pubDate>Sat, 12 Jul 2025 13:13:36 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/retro-style-website-eepsite-is-now-up/</guid>
            <description>&lt;p&gt;我的复古风格网站的 eepsite 终于上线了，我已经在 &lt;strong&gt;reg.i2p&lt;/strong&gt; 上注册了 &lt;strong&gt;rebel.i2p&lt;/strong&gt; 域名。地址传播到地址簿可能需要几天时间，但你现在可以使用这个 &lt;a class=&#34;link&#34; href=&#34;http://rebel.i2p/?i2paddresshelper=...&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;地址助手链接&lt;/a&gt; 访问。&lt;/p&gt;&#xA;&lt;p&gt;值得一提的是，我最近发现 &lt;strong&gt;rebel.i2p&lt;/strong&gt; 这个域名之前已经被注册过，但截至 2023 年 8 月 18 日，该网站已无法访问。&lt;strong&gt;reg.i2p&lt;/strong&gt; 允许重新注册已失效网站的 I2P 域名，但 &lt;strong&gt;stats.i2p&lt;/strong&gt; 不允许，并仍然保留旧记录。为了避免出现意外情况，我还注册了另一个域名：&lt;strong&gt;rebel1725.i2p&lt;/strong&gt;，其地址助手链接在 &lt;a class=&#34;link&#34; href=&#34;http://rebel1725.i2p/?i2paddresshelper=...&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;这里&lt;/a&gt;。&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>我的复古风格网站现已上线</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/my-retro-style-website-is-now-up/</link>
            <pubDate>Fri, 11 Jul 2025 20:08:59 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/my-retro-style-website-is-now-up/</guid>
            <description>&lt;p&gt;我的复古风格网站终于上线了！欢迎访问 &lt;a class=&#34;link&#34; href=&#34;https://tilde.club/~rebel1725/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Tilde.club&lt;/a&gt;。&lt;/p&gt;&#xA;&lt;p&gt;此外，包含相同内容的 eepsite 也将在 &lt;a class=&#34;link&#34; href=&#34;http://rebel.i2p/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;rebel.i2p&lt;/a&gt; 上线。&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>新身份初始化已完成</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/new-identity-initialisation-has-finished/</link>
            <pubDate>Thu, 10 Jul 2025 01:00:01 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/new-identity-initialisation-has-finished/</guid>
            <description>&lt;p&gt;经过八天的努力，我的新身份初始化已经完成。与此同时，我等待中的 tilde.club 会员申请也已获批，我已将来自 tilde.club 的新电子邮件地址添加到了我的 OpenPGP 公钥中，我的 &lt;a class=&#34;link&#34; href=&#34;https://tilde.club/~rebel1725&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;复古风格网站&lt;/a&gt; 即将上线。&lt;/p&gt;&#xA;&lt;p&gt;在这个特别的时刻，我想向在 OpenPGP 私钥泄露危机之后依然与我保持联系的十六位朋友，表达我真挚而深切的感激。在那八天无尽的黑暗中，是你们为我的世界带来了微光。愿我们的友谊地久天长！&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>Carter已经离开。请欢迎Rebel。</title>
            <link>https://rebel1725.codeberg.page/blog/zh/post/carter-has-gone-please-welcome-rebel/</link>
            <pubDate>Mon, 07 Jul 2025 14:57:48 +0800</pubDate><author>rebel1725@tilde.club (Rebel Zhang)</author>
            <guid>https://rebel1725.codeberg.page/blog/zh/post/carter-has-gone-please-welcome-rebel/</guid>
            <description>&lt;p&gt;六天前，我遭遇了&lt;a class=&#34;link&#34; href=&#34;https://czl92783719.codeberg.page/blog/en/posts/it-is-time-for-a-farewell/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;OpenPGP泄露&lt;/a&gt;，因此不得不撤销我的旧身份并建立一个新身份。现在，我的新身份已经准备好了。请告别我的旧身份Carter，&lt;strong&gt;并欢迎我的新身份 - Rebel&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;h1 id=&#34;困难时刻---过去六天我做了什么&#34;&gt;困难时刻 - 过去六天我做了什么&#xA;&lt;/h1&gt;&lt;p&gt;自2025-07-01T09:18:05Z，我的OpenPGP被泄露并被我撤销后，我开始联系所有我的朋友，告诉他们事件的经过，并开始整理我的所有文件。&lt;/p&gt;&#xA;&lt;p&gt;在XMPP的一个关于GNU/Linux和Unix的公共频道中讨论了我的OpenPGP泄露问题后，他们提到即便是自由软件也不能保证高度的安全性，因为安全漏洞在自由软件项目中普遍存在。我决定尝试一些安全加固的操作系统，如QubesOS。然而，由于其陡峭的学习曲线和建立新身份的紧迫性，我暂时放弃了，并回到了Debian GNU/Linux。一旦我完成了所有任务，我会考虑尝试QubesOS。&lt;/p&gt;&#xA;&lt;p&gt;祸不单行。将所有数据整理到SSD上后，终于到了重新安装所有操作系统的时候。然而，当我在制作一个新的Ventoy磁盘时，&lt;strong&gt;我选择了错误的驱动器并立即擦除了我的SSD，这让我陷入了绝望的漩涡&lt;/strong&gt;。幸好，&lt;a class=&#34;link&#34; href=&#34;https://www.cgsecurity.org/wiki/PhotoRec&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;PhotoRec&lt;/a&gt;帮助我恢复了大量珍贵的数据，但遗憾的是，许多其他文件，包括但不限于我的XMPP和Matrix聊天记录、我的个人博客源代码以及一些停用操作系统如DivestOS的OTA包都丢失了。&lt;/p&gt;&#xA;&lt;p&gt;但是，无论发生什么，我必须继续进行身份重建和数字基础设施的恢复。我重新安装了所有设备的操作系统，准备了我的新身份，并重新建立了这个网站。&lt;/p&gt;&#xA;&lt;h1 id=&#34;还有许多事情要做&#34;&gt;还有许多事情要做&#xA;&lt;/h1&gt;&lt;p&gt;现在，我的新个人网站和博客已经上线。然而，还有许多事情需要完成。个人网站已经建立，但尚未完全建好；我还有未配置的设备，未注册的账户，以及许多未完成的任务。&lt;/p&gt;&#xA;&lt;p&gt;我会尽量加快进度，尽早回到正常生活。&lt;/p&gt;&#xA;&lt;h1 id=&#34;感谢&#34;&gt;感谢&#xA;&lt;/h1&gt;&lt;p&gt;在事件发生后，许多朋友向我表达了关心。有些人甚至因为失去与我联系而流泪。&lt;/p&gt;&#xA;&lt;p&gt;谢谢你们，所有人都是我生命中的礼物。对于那些与我失去联系的人，我衷心祝愿你们在没有我的日子里依然每天充满快乐。&lt;/p&gt;&#xA;&lt;h1 id=&#34;未来计划&#34;&gt;未来计划&#xA;&lt;/h1&gt;&lt;p&gt;在这次OpenPGP泄露事件后，为了避免类似事件的再次发生，我&lt;strong&gt;已经将我的OpenPGP私钥生成在硬件安全密钥上&lt;/strong&gt;。这将确保没有恶意软件可以窃取我的私钥数据。&lt;/p&gt;&#xA;&lt;p&gt;此外，我将拥有三个级别的即时通讯账户：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&lt;strong&gt;私密&lt;/strong&gt;：这些账户用于直接消息。你可以通过这些账户与我讨论几乎所有事情，但&lt;strong&gt;请不要期望快速回复，因为这些账户仅在我在家时才可用&lt;/strong&gt;；&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;快速&lt;/strong&gt;：这些账户也用于直接消息，可以在我带出家门的设备上访问。但&lt;strong&gt;由于公共场所的广泛监控以及由于我未加锁的启动加载程序带来的安全漏洞，请避免在聊天时讨论敏感信息&lt;/strong&gt;；&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;公开&lt;/strong&gt;：这些账户仅用于公开聊天和偶尔的非加密直接消息。&lt;strong&gt;避免在聊天时讨论敏感信息&lt;/strong&gt;。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;我将对&lt;strong&gt;私密&lt;/strong&gt;和&lt;strong&gt;快速&lt;/strong&gt;账户实施加密信任管理。信任信息可以在我的主页上找到。&lt;/p&gt;&#xA;&lt;p&gt;感谢您的阅读。来自中国的爱。&lt;/p&gt;&#xA;</description>
        </item></channel>
</rss>
