<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet href="/scripts/pretty-feed-v3.xsl" type="text/xsl"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:h="http://www.w3.org/TR/html4/"><channel><title>Cris.Q</title><description>无问西东</description><link>https://crisq.top</link><item><title>DevEco Studio 移植笔记</title><link>https://crisq.top/blog/deveco_linux_porting_notes</link><guid isPermaLink="true">https://crisq.top/blog/deveco_linux_porting_notes</guid><description>逆向工程最有用的一集</description><pubDate>Fri, 30 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;前几个月买了个华为的平板，一直想趁机搞搞鸿蒙开发，但苦于 DevEco 不支持 Linux，遂开始考虑是否可能进行移植。&lt;/p&gt;
&lt;h1&gt;准备工作&lt;/h1&gt;
&lt;h2&gt;获取 DevEco Studio 的 Windows版&lt;/h2&gt;
&lt;p&gt;我们这里从华为官方下载Windows版本的安装包（本文撰写时可下载的版本是&lt;a href=&quot;https://developer.huawei.com/consumer/cn/download/&quot;&gt;DevEco Studio 6.0.2 Release&lt;/a&gt;），通过wine安装即可。安装配置全部保持默认，则DevEco的程序本体应该在&lt;code&gt;~/.wine/drive_c/Program Files/Huawei/DevEco Studio&lt;/code&gt;下，我们进入该目录。&lt;/p&gt;
&lt;h2&gt;获取 IDEA&lt;/h2&gt;
&lt;p&gt;由于目前的 DevEco Studio 是基于IDEA修改制作而成的，所以我们需要一份IDEA的Linux版作为参考，我下载的版本是&lt;a href=&quot;https://www.jetbrains.com/idea/download/download-thanks.html?platform=linux&quot;&gt;2025.3.2&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;进行解压和整理后我们的目录格式如下：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;.  
├── DevEco Studio  
│   ├── bin  
│   ├── ......
│   └── tools  
└── idea-IU-253.30387.90  
	├── bin  
	├── ......
	└── plugins
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;移植环境&lt;/h1&gt;
&lt;h2&gt;移植JBR&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;JBR ( Jetbrains Runtime )&lt;/strong&gt; 是由 JetBrains 制作的 JDK 改版，我们下载 IDEA 时就已经包含在内。直接复制替换DevEco Studio中的jbr目录即可。&lt;/p&gt;
&lt;p&gt;当然，IDEA 和 DevEco 使用的 JBR 版本不一定相同，如果你希望 JBR 版本完全匹配，可以通过wine打印一下DevEco的jbr版本，再到&lt;a href=&quot;https://github.com/JetBrains/JetBrainsRuntime/releases&quot;&gt;Github&lt;/a&gt;上进行下载。&lt;/p&gt;
&lt;h2&gt;移植Node&lt;/h2&gt;
&lt;p&gt;华为的构建工具要么是用nodejs写的要么使用python写的，查看tools/node，发现NodeJS版本是&lt;a href=&quot;https://nodejs.org/dist/v18.20.1/node-v18.20.1-linux-x64.tar.xz&quot;&gt;v18.20.1 LTS&lt;/a&gt;，于是在官网下载该版本，解压，替换原目录。（这里为了和Windows版本的目录结构保持一致，我将node/bin子目录下的文件全部软链接到了node目录）&lt;/p&gt;
&lt;p&gt;此时&lt;code&gt;tools&lt;/code&gt;目录下应该有node文件夹。&lt;/p&gt;
&lt;h2&gt;替换libs&lt;/h2&gt;
&lt;p&gt;进入&lt;code&gt;lib&lt;/code&gt;目录，复制 IDEA 样本中的&lt;code&gt;native, pty4j, jna&lt;/code&gt;三个目录并替换DevEco中的目录&lt;/p&gt;
&lt;h2&gt;替换OpenHarmony SDK&lt;/h2&gt;
&lt;p&gt;这里用下载好的OpenHarmony SDK替换&lt;code&gt;sdk/default/openharmony&lt;/code&gt;即可。（至于如何下载，可以直接使用DevEco提供的下载工具，你可以先跳过本步，做完其他步骤，之后应该能在Linux上打开它并下载SDK了）&lt;/p&gt;
&lt;h1&gt;逆向官方启动器&lt;/h1&gt;
&lt;p&gt;由于华子大概率是直接搬的官方启动器，这里我直接用 ida 逆了 bin/idea。最有用的函数应该是&lt;code&gt;xplat_launcheer::main_lib&lt;/code&gt;。~~在GPT的帮助下得出的~~ 结论如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;启动器使用~~世界上最好的语言~~ Rust 编写&lt;/li&gt;
&lt;li&gt;启动器加载时会向当前目录的上层递归读取&lt;code&gt;product-info.json&lt;/code&gt;文件，最大深度为5&lt;/li&gt;
&lt;li&gt;启动器会加载properties文件，具体加载的是&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;因此，我们通过编写&lt;code&gt;product-info.json&lt;/code&gt;和&lt;code&gt;devecostudio.vmoption&lt;/code&gt;，即可完成最后的移植工作。&lt;/p&gt;
&lt;h1&gt;编写相关配置文件&lt;/h1&gt;
&lt;p&gt;这部分就不多赘述，给出可以抄作业的VMOption &amp;#x26; product-info &amp;#x26; idea properties:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;// product-info.json
{  
&quot;name&quot;: &quot;DevEco Studio&quot;,  
&quot;version&quot;: &quot;6.0.2.640&quot;,  
&quot;versionSuffix&quot;: &quot;&quot;,  
&quot;buildNumber&quot;: &quot;243.24978.46.36.602640&quot;,  
&quot;productCode&quot;: &quot;DS&quot;,  
&quot;envVarBaseName&quot;: &quot;DEVECOSTUDIO&quot;,  
&quot;dataDirectoryName&quot;: &quot;DevEcoStudio6.0&quot;,  
&quot;svgIconPath&quot;: &quot;bin/devecostudio.svg&quot;,  
&quot;productVendor&quot;: &quot;Huawei&quot;,  
&quot;launch&quot;: [  
{  
&quot;os&quot;: &quot;Linux&quot;,  
&quot;arch&quot;: &quot;amd64&quot;,  
&quot;launcherPath&quot;: &quot;bin/devecostudio&quot;,  
&quot;javaExecutablePath&quot;: &quot;jbr/bin/java&quot;,  
&quot;vmOptionsFilePath&quot;: &quot;bin/devecostudio64-lin.vmoptions&quot;,  
&quot;startupWmClass&quot;: &quot;deveco-studio&quot;,  
&quot;bootClassPathJarNames&quot;: [  
&quot;platform-loader.jar&quot;,  
&quot;util-8.jar&quot;,  
&quot;util.jar&quot;,  
&quot;util_rt.jar&quot;,  
&quot;opentelemetry.jar&quot;,  
&quot;app.jar&quot;,  
&quot;stats.jar&quot;,  
&quot;jps-model.jar&quot;,  
&quot;external-system-rt.jar&quot;,  
&quot;rd.jar&quot;,  
&quot;bouncy-castle.jar&quot;,  
&quot;protobuf.jar&quot;,  
&quot;forms_rt.jar&quot;,  
&quot;lib.jar&quot;,  
&quot;externalProcess-rt.jar&quot;,  
&quot;groovy.jar&quot;,  
&quot;annotations.jar&quot;,  
&quot;hwlib.jar&quot;,  
&quot;idea_rt.jar&quot;,  
&quot;kotlinx-coroutines-slf4j-1.8.0-intellij.jar&quot;,  
&quot;nio-fs.jar&quot;,  
&quot;trove.jar&quot;  
],  
&quot;additionalJvmArguments&quot;: [  
&quot;-Djava.system.class.loader=com.intellij.util.lang.PathClassLoader&quot;,  
&quot;-Didea.vendor.name=Huawei&quot;,  
&quot;-Didea.paths.selector=DevEcoStudio6.0&quot;,  
&quot;-Djna.boot.library.path=$IDE_HOME/lib/jna/amd64&quot;,  
&quot;-Dpty4j.preferred.native.folder=$IDE_HOME/lib/pty4j&quot;,  
&quot;-Djna.nosys=true&quot;,  
&quot;-Djna.noclasspath=true&quot;,  
&quot;-Dintellij.platform.runtime.repository.path=$IDE_HOME/modules/module-descriptors.jar&quot;,  
&quot;-Didea.platform.prefix=DevEcoStudio&quot;,  
&quot;-Dsplash=true&quot;,  
&quot;-Daether.connector.resumeDownloads=false&quot;,  
&quot;-Dcompose.swing.render.on.graphics=true&quot;,  
&quot;--add-opens=java.base/java.io=ALL-UNNAMED&quot;,  
&quot;--add-opens=java.base/java.lang=ALL-UNNAMED&quot;,  
&quot;--add-opens=java.base/java.lang.ref=ALL-UNNAMED&quot;,  
&quot;--add-opens=java.base/java.lang.reflect=ALL-UNNAMED&quot;,  
&quot;--add-opens=java.base/java.net=ALL-UNNAMED&quot;,  
&quot;--add-opens=java.base/java.nio=ALL-UNNAMED&quot;,  
&quot;--add-opens=java.base/java.nio.charset=ALL-UNNAMED&quot;,  
&quot;--add-opens=java.base/java.text=ALL-UNNAMED&quot;,  
&quot;--add-opens=java.base/java.time=ALL-UNNAMED&quot;,  
&quot;--add-opens=java.base/java.util=ALL-UNNAMED&quot;,  
&quot;--add-opens=java.base/java.util.concurrent=ALL-UNNAMED&quot;,  
&quot;--add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED&quot;,  
&quot;--add-opens=java.base/java.util.concurrent.locks=ALL-UNNAMED&quot;,  
&quot;--add-opens=java.base/jdk.internal.vm=ALL-UNNAMED&quot;,  
&quot;--add-opens=java.base/sun.net.dns=ALL-UNNAMED&quot;,  
&quot;--add-opens=java.base/sun.nio.ch=ALL-UNNAMED&quot;,  
&quot;--add-opens=java.base/sun.nio.fs=ALL-UNNAMED&quot;,  
&quot;--add-opens=java.base/sun.security.ssl=ALL-UNNAMED&quot;,  
&quot;--add-opens=java.base/sun.security.util=ALL-UNNAMED&quot;,  
&quot;--add-opens=java.desktop/com.sun.java.swing=ALL-UNNAMED&quot;,  
&quot;--add-opens=java.desktop/com.sun.java.swing.plaf.gtk=ALL-UNNAMED&quot;,  
&quot;--add-opens=java.desktop/java.awt=ALL-UNNAMED&quot;,  
&quot;--add-opens=java.desktop/java.awt.dnd.peer=ALL-UNNAMED&quot;,  
&quot;--add-opens=java.desktop/java.awt.event=ALL-UNNAMED&quot;,  
&quot;--add-opens=java.desktop/java.awt.font=ALL-UNNAMED&quot;,  
&quot;--add-opens=java.desktop/java.awt.image=ALL-UNNAMED&quot;,  
&quot;--add-opens=java.desktop/java.awt.peer=ALL-UNNAMED&quot;,  
&quot;--add-opens=java.desktop/javax.swing=ALL-UNNAMED&quot;,  
&quot;--add-opens=java.desktop/javax.swing.plaf.basic=ALL-UNNAMED&quot;,  
&quot;--add-opens=java.desktop/javax.swing.text=ALL-UNNAMED&quot;,  
&quot;--add-opens=java.desktop/javax.swing.text.html=ALL-UNNAMED&quot;,  
&quot;--add-opens=java.desktop/javax.swing.text.html.parser=ALL-UNNAMED&quot;,  
&quot;--add-opens=java.desktop/sun.awt=ALL-UNNAMED&quot;,  
&quot;--add-opens=java.desktop/sun.awt.X11=ALL-UNNAMED&quot;,  
&quot;--add-opens=java.desktop/sun.awt.datatransfer=ALL-UNNAMED&quot;,  
&quot;--add-opens=java.desktop/sun.awt.image=ALL-UNNAMED&quot;,  
&quot;--add-opens=java.desktop/sun.font=ALL-UNNAMED&quot;,  
&quot;--add-opens=java.desktop/sun.java2d=ALL-UNNAMED&quot;,  
&quot;--add-opens=java.desktop/sun.swing=ALL-UNNAMED&quot;,  
&quot;--add-opens=java.management/sun.management=ALL-UNNAMED&quot;,  
&quot;--add-opens=jdk.attach/sun.tools.attach=ALL-UNNAMED&quot;,  
&quot;--add-opens=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED&quot;,  
&quot;--add-opens=jdk.internal.jvmstat/sun.jvmstat.monitor=ALL-UNNAMED&quot;,  
&quot;--add-opens=jdk.jdi/com.sun.tools.jdi=ALL-UNNAMED&quot;  
],  
&quot;mainClass&quot;: &quot;com.intellij.idea.Main&quot;  
}  
],  
&quot;bundledPlugins&quot;: [],  
&quot;modules&quot;: [],  
&quot;fileExtensions&quot;: [],  
&quot;layout&quot;: []  
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# devecostudio64-lin.vmoptions
-Xms256m  
-Xmx2048m  
-XX:ReservedCodeCacheSize=512m  
-XX:CICompilerCount=2  
-XX:+HeapDumpOnOutOfMemoryError  
-XX:-OmitStackTraceInFastThrow  
-XX:+IgnoreUnrecognizedVMOptions  
-XX:+UnlockDiagnosticVMOptions  
-XX:TieredOldPercentage=100000  
-ea  
-Dfile.encoding=UTF-8  
-Dsun.java2d.metal=true  
-Dawt.lock.fair=true  
-Dsun.io.useCanonCaches=false  
-Djdk.nio.maxCachedBufferSize=2097152  
-Djava.util.zip.use.nio.for.zip.file.access=true  
-Djava.nio.file.spi.DefaultFileSystemProvider=com.intellij.platform.core.nio.fs.MultiRoutingFileSystemProvider  
-Djdk.attach.allowAttachSelf=true  
-Dsun.tools.attach.tmp.only=true  
-Djdk.http.auth.tunneling.disabledSchemes=&quot;&quot;  
-Djdk.module.illegalAccess.silent=true  
-Djbr.catch.SIGABRT=true  
-Dkotlinx.coroutines.debug=off  
-Djava.security.manager=com.intellij.platform.core.nio.fs.CoreBootstrapSecurityManager
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-properties&quot;&gt;# idea.properties

# ---------------------------------------------------------------------  
# DevEco Studio - Linux
# Based on IntelliJ Platform 243.x  
# ---------------------------------------------------------------------  
  
# Use ${idea.home.path} macro to specify location relative to IDE installation home.  
# Use ${xxx} where xxx is any Java property (including defined in previous lines of this file)  
# to refer to its value.  
  
# ---------------------------------------------------------------------  
# Paths (use defaults unless you really need to override)  
# ---------------------------------------------------------------------  
# idea.config.path=${user.home}/.DevEcoStudio/config  
# idea.system.path=${user.home}/.DevEcoStudio/system  
# idea.plugins.path=${idea.config.path}/plugins  
# idea.log.path=${idea.system.path}/log  
  
# ---------------------------------------------------------------------  
# File size limits  
# ---------------------------------------------------------------------  
idea.max.intellisense.filesize=2500  
idea.max.content.load.filesize=20000  
  
# ---------------------------------------------------------------------  
# Console &amp;#x26; process behavior  
# ---------------------------------------------------------------------  
idea.cycle.buffer.size=4096  
idea.no.launcher=false  
idea.dynamic.classpath=false  
  
# ---------------------------------------------------------------------  
# UI / Window manager behavior  
# ---------------------------------------------------------------------  
idea.popup.weight=heavy  
  
# ---------------------------------------------------------------------  
# Graphics &amp;#x26; rendering (Linux-safe)  
# ---------------------------------------------------------------------  
sun.java2d.d3d=false  
sun.java2d.pmoffscreen=false  
swing.bufferPerWindow=true  
sun.java2d.uiScale.enabled=false  
javax.swing.rebaseCssSizeMap=true  
  
# ---------------------------------------------------------------------  
# Accessibility &amp;#x26; stability (JBR)  
# ---------------------------------------------------------------------  
javax.swing.JTree.excludeAccessibleChildrenFromClosedNodes=true  
sun.awt.mac.a11y.tableAccessibleRowCountThreshold=1000  
sun.lwawt.macosx.LWCToolkit.invokeAndWait.disposeOnEDTFree=true  
  
# ---------------------------------------------------------------------  
# Smooth scrolling (disabled by default, stable choice)  
# ---------------------------------------------------------------------  
# idea.true.smooth.scrolling=true  
  
# ---------------------------------------------------------------------  
# DevEco specific: plugin compatibility baseline  
# IMPORTANT: keeps DevEco plugins from behaving like pure IDEA plugins  
# ---------------------------------------------------------------------  
idea.plugins.compatible.build=IC-243.24978.46  
  
# ---------------------------------------------------------------------  
# HarmonyOS / DevEco toolchain (keep even if commented)  
# ---------------------------------------------------------------------  
# ide.harmonyos.sdk.location=/path/hosdk/  
# ide.ohpm.location=/path/ohpm  
# ide.hvigor.location=/path/hvigor  
# ide.node.location=/path/node  
# ide.emulator.location=/path/emulator  
  
# ---------------------------------------------------------------------  
# ArkTS / Node related limits (optional)  
# ---------------------------------------------------------------------  
# arkts.server.max.intellisense.filesize=10240  
# arkts.server.max.old.space.size=8192  
  
# ---------------------------------------------------------------------  
# Error handling  
# ---------------------------------------------------------------------  
idea.fatal.error.notification=disabled
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里值得注意的一个 fun fact 是：如果你使用&lt;code&gt;sun.java2d.uiScale=true&lt;/code&gt;开启 IDEA 推荐的 Scale by OS，华为奇怪的插件加载机制会搞砸一切！所以这里设置为false，我们就完成了全部的移植工作。&lt;/p&gt;
&lt;h1&gt;处理签名问题&lt;/h1&gt;
&lt;p&gt;此时的DevEco看起来已经可以正常开发了，但在签名时会遇到奇怪的问题：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;2026-02-05 22:20:54,000 [ 490226]   WARN - #com.huawei.deveco.projectmgmt.hos.s  
ignature.sign.utils.AutoGenerateKeyCSRUtil - No available JDK is found.  
2026-02-05 22:21:00,716 [ 496942]   WARN - #com.huawei.deveco.projectmgmt.hos.s  
ignature.sign.utils.AutoGenerateKeyCSRUtil - No available JDK is found.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我们使用 Recaf 逆向该组件。（如果有做Java逆向的朋友，真心推荐Recaf，目前用过的最好用的Java反编译/字节码修改工具，绝对的神器级别）。组件位置是&lt;code&gt;plugins/harmony/lib/hos-project-mgmt-6.0.2.640.jar&lt;/code&gt;，相关代码是：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;String toolPath = homePath + TOOL_PATH;              // /jbr/bin
if (SystemInfo.isMac || SystemInfo.isLinux) {
    toolPath = homePath + MAC_TOOL_PATH;             // /jbr/Contents/Home/bin
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;也就是说 Linux 被直接和 Mac 划到一起去了，组件找寻 &lt;code&gt;jbr/Contents/Home/bin/keytool&lt;/code&gt;，二实际路径是&lt;code&gt;jbr/bin/keytool&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;因此我们“伪装路径”，具体方法不做赘述。&lt;/p&gt;
&lt;h1&gt;移植“模拟器”&lt;/h1&gt;
&lt;p&gt;由于鸿蒙的模拟器不开源，我们显然无法强行兼容之，所以这里采用 &lt;a href=&quot;https://docs.oniroproject.org/device-development/developer-boards/emulator&quot;&gt;Oniro Emulator&lt;/a&gt;。按照其要求安装配置即可。&lt;/p&gt;
&lt;h1&gt;效果&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1.BVJgEfOA.webp&amp;#x26;w=2880&amp;#x26;h=1800&amp;#x26;f=webp&quot; alt=&quot;CodeGenie 可用性展示&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F2.Bgm4qRFa.webp&amp;#x26;w=2880&amp;#x26;h=1800&amp;#x26;f=webp&quot; alt=&quot;实机运行可用性展示&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F3.DTUoAM4D.webp&amp;#x26;w=2880&amp;#x26;h=1796&amp;#x26;f=webp&quot; alt=&quot;模拟器运行可用性展示&quot;&gt;&lt;/p&gt;</content:encoded><h:img src="/_astro/cover.82zTM2KP.webp"/><enclosure url="/_astro/cover.82zTM2KP.webp"/></item><item><title>诗歌里的秋季</title><link>https://crisq.top/blog/fall_in_fall</link><guid isPermaLink="true">https://crisq.top/blog/fall_in_fall</guid><description>高一时候创新作文大赛的参赛作文</description><pubDate>Mon, 26 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;正文&lt;/h1&gt;
&lt;p&gt;秋天从没写过一场秋天。&lt;/p&gt;
&lt;p&gt;金丝细框眼镜斜架在鼻梁上，一蓬乱发张扬地束在头顶，消瘦的身躯拖举着高昂的下颌。正如青春期善于卖弄感情的少年们一样，他也喜欢写诗。&lt;/p&gt;
&lt;p&gt;当然，充足的荷尔蒙让他热衷于追求极致的，热烈的，甚至偏激的情感。在他的诗里，每每能看到作者为各种各样的伤春悲秋死来活去。披肝沥胆凿出雕梁画栋的惊人之语———于是，各种各样古意盎然的意向便在他的诗作中排着队出现：诸如无边的旷野，或是漫天的晨星，不胜枚举。&lt;/p&gt;
&lt;p&gt;沉浸于如此波澜壮阔的脑内世界，他对于那些寻常的事物便也就提不起多大兴趣了。比如十月软绵绵的小雨，或树上打着旋的几片枯叶，他自不屑去提起它们。&lt;/p&gt;
&lt;p&gt;于是乎，秋天的笔从未垂青过秋天，也是理所当然的了。&lt;/p&gt;
&lt;p&gt;十一月的寒风催促着街边的每一棵树，梧桐拿叶裹紧了自己，对四周渐渐冷清的空气避之不及。来往的学生们也渐添上了厚实的棉衣，抱着双臂，手拢在袖中，只是行色匆匆地赶路。远山悄然间从翠绿冷却了深青与墨蓝，勾勒开几道温柔的弧线。秋天一面静静走着，一面幻想着自己脑中那些我们称之为“中二病”的画面。他随意找了条长椅，歪倒下去，环视着四周，思考如何打发午饭后这一小段休闲的时光。&lt;/p&gt;
&lt;p&gt;四周尽是些司空见惯的无趣场景。他把头向右倾着，眼神漫无目的的游荡。&lt;/p&gt;
&lt;p&gt;“你有试过把梧桐叶遮在眼睛上吗？蛮有趣的哦。”&lt;/p&gt;
&lt;p&gt;似乎是谁曾对他说过这句话吧，他心中暗自嘲笑这人的幼稚。一片梧桐叶动了动，几只蚂蚁吃力地钻出，抬着食物挪向自己的领地。快要入冬了啊，结束这个一如既往无趣的秋天。一阵微冷的风让他眯了眯眼，他想抬头看看天，正巧一片硕大的梧桐叶被风吹落，在他的脸颊上磕了一下，又向地面飘去。他皱了皱眉，忽然想起那幼稚的建议，叹了口气，以一种精致的吊儿郎当的态度，弯腰把树叶捡了起来，盖在了眼睛上。那叶极薄，阳光从金黄色的缝隙中渗进了些许米白与橙红，给他的世界上了层滤镜。&lt;/p&gt;
&lt;p&gt;他闭上一只眼，直起身子，看向那个灰色的秋季世界。&lt;/p&gt;
&lt;p&gt;一切都变得不同了。&lt;/p&gt;
&lt;p&gt;深黑的树皮变成了棕红色，闪着古铜般的暗金光泽，天空变得青橙交织，像橘黄与水蓝叠加上色的釉彩，风总是能晕开一层浅浅的紫色，像镜头的眩光一般，令人目眩神迷。他的眼睛因惊讶而睁大了些，他前倾着头，屏住呼吸。眼前异变的日常让他惊奇，日常呵，究竟是加上了多彩的滤镜，还是卸去了平凡的伪装呢？&lt;/p&gt;
&lt;p&gt;他看见飞鸟在天幕间留下一道浅浅的尾迹，向着南方徐徐行进，水塘上一片枯叶如小舟一般划开波浪，激起一圈淡淡的涟漪。路边人们勾肩搭背地聊着天，聊着面包与理想，平凡与伟大。&lt;/p&gt;
&lt;p&gt;他看见店员嘴角浅浅的笑，少年少女怯生生比出的爱心。他看见了一切他从未放在心上的悸动，一种不同于以往的复杂感觉，既不伟大，也不震撼，却令人难以忽视，难以忘怀。&lt;/p&gt;
&lt;p&gt;透过一片树叶，他才看见了秋。&lt;/p&gt;
&lt;p&gt;他抄起随身的本子，将那片叶子夹在第一页，又匆忙翻开新的一页。他要写诗，虽然不知是什么他自己也说不清道不明的复杂情感在驱动着他，但他要写诗。不，他写不出来，没有青领书生红衣公子来帮他了。&lt;/p&gt;
&lt;p&gt;“一剪秋叶酌冷香”划掉，太艳俗；“清秋十里华灯上”划掉，卖弄风雅；“秋风吹落满庭芳”划掉。莫名其妙，周围没有满庭，也没有芳。他分明地感到，自己正在完成一项不能逃避的工作，他正努力从那个困在暴雨、飞雪和各种华丽意向中的自我中挣脱出来。他写下一个又一个曾经屡试不爽的古风词汇，努力把它们拼装成唬人的句子，然后一遍遍涂掉，划掉，撕掉......&lt;/p&gt;
&lt;p&gt;他又翻过了新的一页。&lt;/p&gt;
&lt;p&gt;不过，这一次他没有急于再次开始之前的唯美古风拼字游戏，而是一笔一画地将每个他看见的景物记录下来，他的笔尖行得极慢，兴许还带着些虔诚的意味。他托着腮，扶了扶歪着的眼镜，他又想起了那片梧桐叶，想象着把他抵在眼眶上的感觉。渐渐的，他感到内心里有什么东西被秋风吹冷了，整个人变得清爽起来。那些空洞的话语和为赋新词的呻吟都在离他远去————奇怪的是，他并不想挽留它们，甚至都懒得向他们挥一挥手。&lt;/p&gt;
&lt;p&gt;他只是又翻开了新的一页。&lt;/p&gt;
&lt;p&gt;......&lt;/p&gt;
&lt;p&gt;“秋天，你可算回来了，午自习马上就开始了————哟，写的什么？又是飞雪连天射白鹿什么的吗？”&lt;/p&gt;
&lt;p&gt;“不是啦，写的是秋天。”&lt;/p&gt;
&lt;p&gt;他神秘地一笑，一路小跑穿过走廊，跃下几级台阶，向着友人挥一挥手。一路秋色里，他在场。&lt;/p&gt;
&lt;h1&gt;碎碎念&lt;/h1&gt;
&lt;p&gt;有一说一本来没准备发出来的，但翻旧手机的笔记册时翻到了这篇，看完感觉青春又回来了一点，遂还是发出来纪念一下我逝去的少年气吧哎哎哎~&lt;/p&gt;
&lt;p&gt;GPT老师一开始大骂这篇文章（雾，好在后来稍微留了点口德，好险没给我骂破防。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2Fgpt.CXH_t75N.png&amp;#x26;w=1317&amp;#x26;h=1202&amp;#x26;f=webp&quot; alt=&quot;GPT老师还是收住了没骂太大声&quot;&gt;&lt;/p&gt;
&lt;p&gt;整体能看出来是很明显的高中生文笔，那时的小朋友还对于世界有着纯粹而理想主义的认识，喜欢从自己的生命体验出发，却发现出发不了一点，于是停留在“我”的视角绕圈圈。还有生硬的情感切换，不过考虑到高一的笔者实在是太清澈了，也可以理解hh（其实现在也很清澈很愚蠢就是了&lt;/p&gt;
&lt;p&gt;一路秋色里，希望大家也都在场。&lt;/p&gt;</content:encoded><h:img src="/_astro/cover.BltQSGco.webp"/><enclosure url="/_astro/cover.BltQSGco.webp"/></item><item><title>一份莫名其妙的C语言速查表</title><link>https://crisq.top/blog/c_cheatsheet</link><guid isPermaLink="true">https://crisq.top/blog/c_cheatsheet</guid><description>看看期末给孩子逼成啥样了都...</description><pubDate>Fri, 16 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import { Aside } from &apos;astro-pure/user&apos;&lt;/p&gt;
&lt;h1&gt;输入读取&lt;/h1&gt;
&lt;h2&gt;读取整行字符串（包括空格）&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;char line[200];
fgets(line, sizeof(line), stdin);
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;连续读多行直到 EOF&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;char s[200];
while (fgets(s, sizeof(s), stdin)) { 
	// 处理每一行 
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;处理单行多元素输入&lt;/h2&gt;
&lt;p&gt;用 &lt;code&gt;strtok&lt;/code&gt; 分割：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;char s[200]; 
fgets(s, sizeof(s), stdin); char *p = strtok(s, &quot;,&quot;);
while (p != NULL) {
	int x = atoi(p); 
	// 用 x 
	p = strtok(NULL, &quot;,&quot;); // 从原位置继续往后切
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;用空格分开时将 &lt;code&gt;strtok&lt;/code&gt; 的分隔符设置成空格即可。&lt;/p&gt;
&lt;p&gt;对于存入数组的情况：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;char line[200];
int arr[50], cnt = 0;
fgets(line, sizeof(line), stdin);
char *p = strtok(line, &quot; &quot;);
while (p != NULL) {
	arr[cnt++] = atoi(p);
	p = strtok(NULL, &quot; &quot;);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;连续读取未知数量数字直到换行&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;int x;
while (scanf(&quot;%d&quot;, &amp;#x26;x) == 1) { 
	// 用 x 
	if (getchar() == &apos;\n&apos;) 
		break; 
		// 换行就停 
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;读取带空格的单词，直到遇到换行&lt;/h2&gt;
&lt;p&gt;示例输入：&lt;br&gt;
&lt;code&gt;apple banana orange&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;char s[100]; 
while (scanf(&quot;%s&quot;, s) == 1) { 
	// 处理 s 
	if (getchar() == &apos;\n&apos;) 
		break; 
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;字符串 → 数组 → 排序&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;char line[200];
int arr[100], cnt = 0;

// 读取整行
if (fgets(line, sizeof(line), stdin) == NULL) return 0;

// strtok 分割（空格分隔）
char *p = strtok(line, &quot; \n&quot;); // 顺便把 &apos;\n&apos; 也当分隔符
while (p != NULL) {
    arr[cnt++] = atoi(p);
    p = strtok(NULL, &quot; \n&quot;);
}

// 排序
qsort(arr, cnt, sizeof(int), cmp);
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;字符串处理&lt;/h1&gt;
&lt;p&gt;记得要引入 &lt;code&gt;string.h&lt;/code&gt; 才能使用下列方法&lt;/p&gt;
&lt;h2&gt;长度/比较&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;#include &amp;#x3C;string.h&gt;
size_t len = strlen(s); 
int r = strcmp(a, b); // &amp;#x3C;0, =0, &gt;0
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;子串检索&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;char* p = strchr(s, &apos;x&apos;);   // 第一次出现 &apos;x&apos; 的位置
char* q = strstr(s, &quot;abc&quot;); // 第一次出现子串 &quot;abc&quot;的位置
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;分割字符串&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;#include &amp;#x3C;string.h&gt; 
char line[200]; 
fgets(line, sizeof(line), stdin); 
for(char* p = strtok(line, &quot; ,\n&quot;); p; p = strtok(NULL, &quot; ,\n&quot;))
{ 
	// p 是每个 token
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里 for 循环中的 &lt;code&gt;p&lt;/code&gt; 等价于 &lt;code&gt;p!=NULL&lt;/code&gt;，后面传入 NULL 表示从上一次 &lt;code&gt;strtok&lt;/code&gt; 停下的位置继续往后切。&lt;/p&gt;
&lt;h1&gt;类型处理&lt;/h1&gt;
&lt;p&gt;记得要引入 &lt;code&gt;ctype.h&lt;/code&gt; 才能使用下列方法&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;isdigit&lt;/code&gt;：是否是数字字符 &lt;code&gt;&apos;0&apos;..&apos;9&apos;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;isalnum&lt;/code&gt;：是否是字母或数字（混合判断）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;isspace&lt;/code&gt;：是否是空白字符（空格、换行、Tab 等）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;islower&lt;/code&gt; / &lt;code&gt;isupper&lt;/code&gt;：是否是小写 / 大写字母&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tolower&lt;/code&gt; / &lt;code&gt;toupper&lt;/code&gt;：大小写转换&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这几个因为用法太显而易见了就不给示例了。&lt;/p&gt;
&lt;h1&gt;妙妙工具&lt;/h1&gt;
&lt;h2&gt;Qsort&lt;/h2&gt;
&lt;p&gt;记得引入 &lt;code&gt;stdlib.h&lt;/code&gt;。基本用法形如：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;qsort(base, n, size, cmp);
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;base&lt;/code&gt;：数组首地址（比如 &lt;code&gt;arr&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;n&lt;/code&gt;：元素个数&lt;/li&gt;
&lt;li&gt;&lt;code&gt;size&lt;/code&gt;：每个元素的字节数（通常 &lt;code&gt;sizeof(arr[0])&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cmp&lt;/code&gt;：比较函数指针（你自己写，决定升序/降序/按什么字段排）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;使用示例：&lt;/p&gt;
&lt;h3&gt;给 int 数组升序排序&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;#include &amp;#x3C;stdio.h&gt;
#include &amp;#x3C;stdlib.h&gt;
int cmp_int_asc(const void *a, const void *b) {
	int x = *(const int*)a;
	int y = *(const int*)b;
	return (x &gt; y) - (x &amp;#x3C; y); // 避免 x-y 溢出 
}

int main() {
	int arr[] = {10, 3, 25, -7, 8};
	int n = sizeof(arr) / sizeof(arr[0]);
	qsort(arr, n, sizeof(arr[0]), cmp_int_asc);
	
	for (int i = 0; i &amp;#x3C; n; i++)
		printf(&quot;%d &quot;, arr[i]);
	return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;cmp&lt;/code&gt; 返回值的规则
比较函数 &lt;code&gt;cmp(a,b)&lt;/code&gt; 必须满足：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;返回 &lt;strong&gt;&amp;#x3C; 0&lt;/strong&gt;：表示 &lt;code&gt;a&lt;/code&gt; 应该排在 &lt;code&gt;b&lt;/code&gt; 前面&lt;/li&gt;
&lt;li&gt;返回 &lt;strong&gt;0&lt;/strong&gt;：表示相等&lt;/li&gt;
&lt;li&gt;返回 &lt;strong&gt;&gt; 0&lt;/strong&gt;：表示 &lt;code&gt;a&lt;/code&gt; 应该排在 &lt;code&gt;b&lt;/code&gt; 后面&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;排结构体&lt;/h3&gt;
&lt;p&gt;假设要按 &lt;code&gt;score&lt;/code&gt; 升序排，score 相同按 &lt;code&gt;id&lt;/code&gt; 升序：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;typedef struct {
	int id;
	int score;
} Node;

int cmp_node(const void *a, const void *b) {
	const Node *x = (const Node*)a;
	const Node *y = (const Node*)b;
	if (x-&gt;score != y-&gt;score)
		return (x-&gt;score &gt; y-&gt;score) - (x-&gt;score &amp;#x3C; y-&gt;score);
	return (x-&gt;id &gt; y-&gt;id) - (x-&gt;id &amp;#x3C; y-&gt;id);
}

int main() {
	qsort(nodes, n, sizeof(nodes[0]), cmp_node);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Printf 格串&lt;/h2&gt;
&lt;h3&gt;补零（或者补别的什么）&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;printf(&quot;%05d\n&quot;, 42);   // 00042
printf(&quot;%02d:%02d\n&quot;, 3, 7); // 03:07
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;精度（保留位数）&lt;/h3&gt;
&lt;h4&gt;浮点：控制小数位数（四舍五入）&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;printf(&quot;%.2f\n&quot;, 3.14159); // 3.14 
printf(&quot;%.0f\n&quot;, 3.9);     // 4
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;字符串：最大输出长度&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;printf(&quot;%.3s\n&quot;, &quot;abcdef&quot;); // abc
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;动态宽度/精度&lt;/h4&gt;
&lt;p&gt;宽度由参数给：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;int w = 8; 
printf(&quot;^%0*d^\n&quot;, w, 123); // &quot;^00000123^&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;内存操作&lt;/h1&gt;
&lt;h2&gt;&lt;code&gt;malloc&lt;/code&gt;：申请一块未初始化的内存&lt;/h2&gt;
&lt;p&gt;特点：申请到的内容是垃圾值，要手动初始化。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;int n = 10;
int *a = (int*)malloc(n * sizeof(int)); // 申请10个int  
if (a == NULL) {     
	// 内存不足
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;&lt;code&gt;calloc&lt;/code&gt;：申请 + 自动清零&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;int n = 10;
int *a = (int*)calloc(n, sizeof(int)); // 10个int，全部为0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;（这俩都是用完要 &lt;code&gt;free()&lt;/code&gt; 的，你最好别忘了）&lt;/p&gt;
&lt;h2&gt;Memset&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;int a[100]; memset(a, 0, sizeof(a));
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Memcpy&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;int a[5] = {1,2,3,4,5};
int b[5];
memcpy(b, a, sizeof(a));
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;文化常识（确信）&lt;/h1&gt;
&lt;h2&gt;ASCII 相关&lt;/h2&gt;
&lt;p&gt;计数排序必需品：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;大写字母范围是 &lt;strong&gt;65 ~ 90&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;小写字母范围是 &lt;strong&gt;97 ~ 122&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&apos;0&apos;&lt;/code&gt; = &lt;strong&gt;48&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&apos;9&apos;&lt;/code&gt; = &lt;strong&gt;57&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;标准 ASCII 可打印字符是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;32 ~ 126&lt;/strong&gt;（共 95 个）&lt;/li&gt;
&lt;li&gt;其中 &lt;strong&gt;32 是空格 &lt;code&gt;&apos; &apos;&lt;/code&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;位运算&lt;/h2&gt;
&lt;p&gt;| &lt;code&gt;&amp;#x26;&lt;/code&gt;  | 按位与操作，按二进制位进行&quot;与&quot;运算  | &lt;code&gt;(A &amp;#x26; B)&lt;/code&gt; 将得到 &lt;code&gt;12&lt;/code&gt; 即为 0000 1100  |
| ---- | ------------------- | -------------------------------- |
| &lt;code&gt;\|&lt;/code&gt; | 按位或运算符，按二进制位进行&quot;或&quot;运算 | &lt;code&gt;(A \| B)&lt;/code&gt; 将得到 &lt;code&gt;61&lt;/code&gt; 即为 0011 1101 |
| &lt;code&gt;^&lt;/code&gt;  | 异或运算符，按二进制位进行&quot;异或&quot;运算 | &lt;code&gt;(A ^ B)&lt;/code&gt; 将得到 &lt;code&gt;49&lt;/code&gt; 即为 0011 0001  |
| &lt;code&gt;~&lt;/code&gt;  | 取反运算符，按二进制位进行&quot;取反&quot;运算 | &lt;code&gt;(~A)&lt;/code&gt; 将得到 &lt;code&gt;-61&lt;/code&gt; 即为 1100 0011    |
| &lt;code&gt;&amp;#x3C;&amp;#x3C;&lt;/code&gt; | 二进制左移运算符            | &lt;code&gt;A &amp;#x3C;&amp;#x3C; 2&lt;/code&gt; 将得到 &lt;code&gt;240&lt;/code&gt; 即为 1111 0000  |
| &lt;code&gt;&gt;&gt;&lt;/code&gt; | 二进制右移运算符            | &lt;code&gt;A &gt;&gt; 2&lt;/code&gt; 将得到 &lt;code&gt;15&lt;/code&gt; 即为 0000 1111   |&lt;/p&gt;
&lt;h2&gt;Break &amp;#x26; continue&lt;/h2&gt;
&lt;p&gt;Break 跳出整个循环体，continue 步出单次循环&lt;/p&gt;
&lt;h2&gt;数组指针 &amp;#x26; 指针数组&lt;/h2&gt;
&lt;h3&gt;指针数组&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;int *p[3];
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;含义：&lt;code&gt;p&lt;/code&gt; 是一个长度为 3 的数组，&lt;code&gt;p[i]&lt;/code&gt; 是 &lt;code&gt;int*&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;char *s[3] = {&quot;aa&quot;, &quot;bb&quot;, &quot;cc&quot;};
printf(&quot;%s\n&quot;, s[1]); // bb
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;数组指针&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;int (*p)[3];
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;int a[2][3] = {{1,2,3},{4,5,6}};
int (*p)[3] = a;      // 指向第0行
printf(&quot;%d\n&quot;, p[1][2]); // 6
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;二维数组&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;int a[2][3] = {
    {1, 2, 3},
    {4, 5, 6}
};
// a 是一个2个元素的数组，每个元素是一个3个元素的数组
// 也就是：int[3] t[2]; 本质上 [3] 和 int 配对
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;行指针 &amp;#x26; 列指针&lt;/h2&gt;
&lt;h3&gt;行指针&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;行指针 = 指向“一整行”的指针&lt;/strong&gt;&lt;br&gt;
也就是：指向 &lt;code&gt;int[列数]&lt;/code&gt; 这种数组的指针。&lt;/p&gt;
&lt;p&gt;如果有 4 列：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;int (*row)[4];
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;row&lt;/code&gt; 指向第 0 行&lt;/li&gt;
&lt;li&gt;&lt;code&gt;row + 1&lt;/code&gt; 指向第 1 行（因为它知道“一行有 4 个 int”）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;row[i][j]&lt;/code&gt; 可以直接当二维数组用&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;列指针（其实就是普通的元素指针）&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;int *p = &amp;#x26;a[0][0];
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;此时 &lt;code&gt;p + n&lt;/code&gt; 指向的元素是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;第几行：&lt;code&gt;row = n / C&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;第几列：&lt;code&gt;col = n % C&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;结构体&lt;/h2&gt;
&lt;p&gt;结构体的声明（反正我直接用 typedef 了）&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;typedef struct {
	int x;
	int y;
} Point; // 相当于将一个匿名结构体绑定给 Point 了

Point p = {0, 0};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;允许函数以结构体为返回值，此时发生拷贝。&lt;/p&gt;
&lt;h2&gt;判断傻逼类型注释的技巧&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;从右向左螺旋读，遇到括号时被“挡住”。&lt;/strong&gt; 例如对于这个愚蠢至极的数组指针定义：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;int (*p)[3];
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这次括号把 &lt;code&gt;*p&lt;/code&gt; 绑定在一起了：&lt;/p&gt;
&lt;p&gt;从 &lt;code&gt;p&lt;/code&gt; 开始读：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;(*p)&lt;/code&gt;：说明 &lt;strong&gt;p 是指针&lt;/strong&gt;（因为要先解引用）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(*p)[3]&lt;/code&gt;：解引用后得到的东西是数组（长度 3）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所以它是&lt;strong&gt;数组指针&lt;/strong&gt;：&lt;code&gt;p&lt;/code&gt; 是指针，指向“3 个 int 的数组”&lt;/p&gt;</content:encoded><h:img src="/_astro/cover.pwaCtYU7.webp"/><enclosure url="/_astro/cover.pwaCtYU7.webp"/></item><item><title>让我们告别2025</title><link>https://crisq.top/blog/2025</link><guid isPermaLink="true">https://crisq.top/blog/2025</guid><description>2025年终总结</description><pubDate>Mon, 29 Dec 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;很难相信我度过了一个怎样的2025，上半年和下半年割裂得像是两年压缩进了一年——六月前还满脑子学习，喜欢在周末带着作业听着喜欢的播客泡在咖啡馆里，九月后却又背着电脑疲于奔命在劳累与焦虑中。不过客观来说，我的2025过得还是挺充实的。&lt;/p&gt;
&lt;p&gt;讲真，我真的觉得我的高三挺美好的，说这句话并不意味着孩子被优绩主义PUA傻了，我怀念的是那些从夹缝中挤出的 do something fun 的时间和那些有一搭没一搭地日常玩笑着的友人。&lt;/p&gt;
&lt;p&gt;我在&lt;a href=&quot;https://crisq.top/blog/2024#%E4%B9%B0%E4%BA%86%E4%B8%80%E5%9D%97%E6%99%BA%E8%83%BD%E8%A1%A8&quot;&gt;2024年终总结&lt;/a&gt;里写过这样一段话：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Spotify的免费版14天会掉登录，在手机上还好说（进行一些科学处理），手表上可着实有点难受了，于是每两周不得不抽出一天来回家重新登录Spotify（这方面内容先按下不表），不过激活之后Spotify的体验堪称优秀，我喜欢的播客和音乐直接受藏到音乐库就可以随时收听了。Spotify Wear最近的一次更新还加入了搜索功能，这下好了，抛掉手机吧少年（笑）。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;真的满足了吗？完全没有，我想念我的小宇宙，想念我的订阅列表和第一时间同步的更新，也想念评论区的互动。那么怎么办呢？既然没有一个Wear专属的小宇宙，就自己做一个吧！抱着这样的想法，从寒假开始动工，到三月最后一次commit，一个播客App逐渐成型。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2Fpic4.aomyM8yc.webp&amp;#x26;w=1424&amp;#x26;h=1235&amp;#x26;f=webp&quot; alt=&quot;用Penpot画的宣传图&quot;&gt;&lt;/p&gt;
&lt;p&gt;取&lt;strong&gt;Casmos&lt;/strong&gt;这个名字的原因也很简单——对应播客的&lt;strong&gt;Cast&lt;/strong&gt;融合对应小宇宙英文名的&lt;strong&gt;Cosmos&lt;/strong&gt;。开发Cosmos的这段时间真是我那几个月最快乐的时候，每当一个新的API接口点亮一个亲手搭建的组件或界面，那种喜悦和成就感都是无以复加的，我想起了几年前熬夜写星火的投稿器和AppimageToDeb工具的时候，熬大夜而满心欢喜，又或是前年筹备班会展示情景剧时通了一个星期宵的热情，人最幸福的不就是干自己喜欢的事吗。现在想来，其实有点项目当时的我。&lt;/p&gt;
&lt;p&gt;当然，播客之外，高三的备考生活总还是紧张劳累的，不过我的成绩倒没有那么令人紧张，所以我的心态整体还是不错的。每个周末把卷子夹成一摞，带到书店去，伴着一杯咖啡和几集播客不紧不慢的写完，全身心沉浸在推理和死思索中，其实还蛮惬意的哦。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2Fpic2.pHTaImu7.webp&amp;#x26;w=1440&amp;#x26;h=1679&amp;#x26;f=webp&quot; alt=&quot;人类早期驯服作业珍贵记录&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2Fpic3.W33dDqwX.webp&amp;#x26;w=1440&amp;#x26;h=1058&amp;#x26;f=webp&quot; alt=&quot;珍贵在哪&quot;&gt;&lt;/p&gt;
&lt;p&gt;回忆起来，陪伴着我度过高三的是两件事，一个是每天晚自习放学后偷偷溜到乒乓球台跟朋友们打球，另一个是每周六早上都可以早起去校门口搞杯瑞幸，收获一天的幸福感。两件小小的事，现在想来也算是我的精神寄托了吧。&lt;/p&gt;
&lt;p&gt;说实话，我很爱我的老师们，他们都是很好的老师，教导有方，也不会说散布很保守很古老的“万般皆下品”之类的价值观，而是很尊重我们的喜好和兴趣。我记得我的生物老师默许我两年不写生物作业，我还经常跑到她办公室要零食；语文老师也喜欢跟我分享各种有趣的文章，并愿意接受我拿各种社论，诗歌和小说当作周末作业交上去（真的可以的）；物理老师有点唯读书论，但日常生活中也很体贴人，经常跟我们道歉（把我们没做对题的问题很真诚地怪罪到自己身上）；数学老师是个有数学情怀的人，我印象很深的他的一句话是“这个不考，但我觉得如果这种思维都不学的话你们的数学算是白学了”，经常分享一些数学史的小趣闻，也会鼓励同学们深入研究某个问题后整理成论文投稿。每当想起他们，我就会惧怕自己考不好，辜负了他们的宽容和用心，越这样想越焦虑，越焦虑越控制不住往坏处假设。&lt;strong&gt;焦虑是最好的咖啡因。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;而我的高考，大概就是被这样的焦虑毁掉的吧。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;第一天进考场时下着大雨，我不想找借口说大雨毁了我的大学梦之类的，但就是没发挥好，看到作文的一刻脑子是晕的——不再是多元思辨，而是一篇没有明显概念冲突点的歌功颂德。就像让一个惯用戏剧冲突塑造主线的编剧写一篇合家欢，他自然不自觉地开始歪曲起了题意，试图从中提炼出那么一些对立的观点进行思辨。结局是悲惨的，他的语文只考进了很低的&lt;strong&gt;110&lt;/strong&gt;档位，远低于他的预期。&lt;/p&gt;
&lt;p&gt;中午我没有睡着，也没心思复习数学，带着满眸的死灰踏进数学考场，却出乎意料考得还不错，最后几分钟在漫无目的地瞎看中看出了解析几何的隐藏条件，顺利拿分，最终考了&lt;strong&gt;138&lt;/strong&gt;。唯一的小遗憾可能就是最后一题第三问看到时间不多而慌乱，导致没仔细做。不过比起我的平均水平，这次的数学无疑考得扬眉吐气的。&lt;/p&gt;
&lt;p&gt;随后的物理英语化学像是走马灯一样闪过，我完全不记得自己考了什么，考得如何，但分数是一样的低，物理我记不得多少分了，但应该也就&lt;strong&gt;60&lt;/strong&gt;或&lt;strong&gt;70&lt;/strong&gt;左右吧，化学也只有&lt;strong&gt;80&lt;/strong&gt;多，最令我痛心的是生物，考了我有史以来最差的分数：连90都没有，卡在了&lt;strong&gt;89&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;也许是预感到了什么，我考生物前一天的晚上哭着跟我的生物老师说我对不起她，她安慰我让我早点睡，我更睡不着了，一直哭。现在想来，也许那是一个自我指涉的预言。&lt;/p&gt;
&lt;p&gt;高考那几天一直在下雨，我记得&lt;/p&gt;
&lt;p&gt;不过，过去的总归是过去了，（毫无意外地）没有考上自己心中的南京大学，，最后还是选择了家门口的武汉大学，却发现这的校园真的很美，也不失为一个意外的收获。至少在这件事上，算是上天最好的安排了。&lt;/p&gt;
&lt;p&gt;如果你看过我的&lt;a href=&quot;crisq.top/blog/jiang_nan&quot;&gt;南京游记&lt;/a&gt;，你应该记得我对这座城市的热爱。现在回忆起来，其实南京和杭州都是美好的回忆，去灵隐寺的那天大雨倾盆，灰黄的寺墙在雨中褪色，虽无钟声，却让人心静。&lt;/p&gt;
&lt;p&gt;然而在灵隐寺求的高分似乎没那么灵验😭。算了，自己没救谁也救不了，就不大书哀怨了。&lt;/p&gt;
&lt;p&gt;旅行生活结束后很是清闲了一阵子，突然想减肥就去办了健身房的月卡，每天晚上去撸会铁，跑跑步，感觉也没啥效果hh，倒是力气似乎是大了一些的。暑假还尝试着自己做了葡萄柠檬茶，效果非常之堪忧（悲叹）。每天晚上实在不知道干啥了就会去散步，从家门口出发，选一个方向一直走啊走啊走，有一次走了六七公里后越来越偏，快走到郊区了😂。&lt;/p&gt;
&lt;p&gt;心想着这样闲不行啊，这样子闲肯定绝对显然是不行的啊，就去找了个助教的活干着。每天帮忙改改作业，收收本子管管午休，和一帮本来根本叫不上名字的学生逐渐熟络起来，也习惯了每天早起，在地铁上掐准麦当劳开业的时间点一份早餐外卖，坐在位子上美美享用。同事们人很好，如果有人的活特别多或者当天出了特殊情况，大家都会主动帮忙。记得有一次忙里偷闲晚上跟一个同事出去捞了一顿巨贵无比的烤肉（于是自那以后我就成了烤肉的忠实拥趸，每个月都要吃一两次hh）。&lt;/p&gt;
&lt;p&gt;七月下旬时，一切尘埃落定：信息安全。也好，那就开始新的一段旅程吧，我开始捡起尘封的CTF工具，不过不再是小学时候喜爱的Web安全（妈的你那个时候的水平怎么好意思说喜爱的，太不要脸了），受&lt;a href=&quot;https://space.bilibili.com/3546576408546044&quot;&gt;Happy Hacking&lt;/a&gt;的影响，这次选了逆向工程方向，然后就体会到了什么叫坐牢，真的是极致的坐牢。汇编语言？不会哦；可执行文件格式？不会哦；加密算法？不会哦；不会哦不会哦全都不会哦！那就学呗，CSAPP启动（事实上四分之一都没读完，笑死我了）。&lt;/p&gt;
&lt;p&gt;而九月份后，成为大学生的cris老师精神状态，可真是颇为美丽呢（大雾），每天在图书馆敲代码敲到晚上满脸疲惫地吊着一张死人脸晃荡着回宿舍，中途去711买点夜宵续命——这就是我每天的日常。&lt;/p&gt;
&lt;p&gt;保研的焦虑，竞赛的焦虑，人生选择的焦虑，因为什么都想要反而什么都得不到，甚至让自己的学业受到了影响。之前我不理解为什么大学生上完课还得下去再听一遍，现在我理解了。每天心思都是乱的，不是在思考各种杂七杂八的任务就是在纠结于一些无关紧要的事情，再加上一周几次课和不定时交的作业，很难说“落实”二字到底有没有分量。我时常感觉喘不过气来，便只能扫车，启动，去把校园逛上个一整圈。从信息学部沿着自强大道一路向上，拐出梅园，来到行政楼的青顶下，穿过老斋舍拔起的翘角飞檐，又在樱园北路拐个弯儿扑向湖滨的水汽氤氲。我向来对武大的“最美校园”之称是心服口服的，校园的景色足矣治愈我，给与我继续生活的动力。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2Fpic1.CzXuFBRP.webp&amp;#x26;w=1966&amp;#x26;h=1474&amp;#x26;f=webp&quot; alt=&quot;樱园北路&quot;&gt;&lt;/p&gt;
&lt;p&gt;十月份时趁着国庆假期又去了趟南京，十一月则是在校运会时溜走，跑长沙玩了两天，偷偷旅行还是很刺激的哈哈！到了十二月的岁末寒冬，则是每天往返教学楼都冻得够呛，而且似乎有点醒不过来了，翘了好几节早八😭，我忏悔。&lt;/p&gt;
&lt;p&gt;期末考试临近，也是忙里偷闲中敲下了这段文字。不想再做什么升华或渲染，我很喜欢我的2025，虽然有痛苦，有繁忙，有（非常大的）不尽如人意和遗憾，但总归只要向前走就有收获，因为可能性是生命本身的礼物。这是我回首一年的感受，也希望你能有同样的感触。&lt;/p&gt;
&lt;p&gt;最后，祝愿看到这里的大家平安喜乐。&lt;/p&gt;</content:encoded><h:img src="/_astro/pic1.CzXuFBRP.webp"/><enclosure url="/_astro/pic1.CzXuFBRP.webp"/></item><item><title>BITs2CTF-2025 RE方向题解</title><link>https://crisq.top/blog/bits2ctf_2025_newbies</link><guid isPermaLink="true">https://crisq.top/blog/bits2ctf_2025_newbies</guid><description>笑死，上了封神榜</description><pubDate>Sat, 22 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;帮着同学打了一下北理的第一届新生赛，题目都十分有趣，收获满满。有一道是&lt;code&gt;LLVM pass&lt;/code&gt;是容器题，就没打。&lt;/p&gt;
&lt;p&gt;（当然，邪恶的代打行为被主办方正义制裁了，不过也是罪有应得啦）&lt;/p&gt;
&lt;h2&gt;大战WebAssembly&lt;/h2&gt;
&lt;p&gt;给了一个 WebAssembly 的 check.wasm，外加一个 JavaScript 脚本逐字符验证
flag：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;  if (check(i, flag[i].charCodeAt(), enc[i]) != 1)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;逆向WebAssembly模块可知有check，f和g三个函数，总结下来一次check大概执行以下逻辑：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;  flag[i] = enc[i] XOR ((2*i + 1) XOR 8)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;写出解密脚本即可：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;  const enc = [
  75, 66, 89, 124, 51, 64, 81, 65, 98, 76, 46, 46, 32, 76, 113, 39, 71,
  24, 12, 112,
  120, 19, 80, 0, 79, 8, 98, 10, 68, 80, 86, 4, 124, 126, 43, 58, 112,
  114, 60, 24,
  61, 104, 59, 108, 101, 100, 102, 51, 54, 92, 5, 92, 62, 91, 81, 87, 65,
  79, 77,
  78, 65, 29, 67, 40, 189, 229, 233, 208, 233, 178, 176, 216, 206, 175,
  168, 242,
  236,
  ];
  
  let flag = [];
  
  for (let i = 0; i &amp;#x3C; enc.length; i++) {
  const v = enc[i] ^ ((2 * i + 1) ^ 8);
  flag.push(String.fromCharCode(v));
  }
  
  console.log(&quot;FLAG =&gt;&quot;, flag.join(&quot;&quot;));
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;什么？你问我怎么逆 WebAssembly 文件？IDA 9.2 直接打开就行啊，有 Loader
的。&lt;/p&gt;
&lt;p&gt;答案：&lt;code&gt;BITs2CTF{W311_d0n3!_Y0u&apos;v3_5ucc355fu11y_d3f3473d_7h3_84084010n6_4nd_h15_W45m}&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;真假奶龙&lt;/h2&gt;
&lt;p&gt;使用 Lua Decompiler 反编译Bytecode得：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-lua&quot;&gt;  -- filename: @./main.lua
  -- version: lua54
  -- line: [0, 0] id: 0
  local function r0_0(r0_1)
  -- line: [1, 20] id: 1
  if type(r0_1) ~= &quot;string&quot; then
  return &quot;请输入文本&quot;
  end
  r0_1 = string.reverse(r0_1)
  local r1_1 = {}
  for r5_1 = 1, #r0_1, 1 do
  local r6_1 = string.byte(r0_1, r5_1)
  if r6_1 &gt;= 48 and r6_1 &amp;#x3C;= 57 then
  table.insert(r1_1, (r6_1 + -48 + 2) % 9 + 48)
  elseif r5_1 ~= 1 then
  table.insert(r1_1, r6_1 + r1_1[r5_1 + -1])
  else
  table.insert(r1_1, r6_1)
  end
  end
  return r1_1
  end
  local r1_0 = {
  125,
  158,
  51,
  84,
  54,
  171,
  51,
  146,
  56,
  134,
  50,
  51,
  51,
  54,
  132,
  227,
  54,
  149,
  53,
  167,
  54,
  149,
  270,
  51,
  51,
  54,
  53,
  167,
  262,
  379,
  50,
  171,
  266,
  48,
  54,
  158,
  48,
  143,
  51,
  164,
  50,
  54,
  51,
  139,
  234,
  50,
  48,
  143,
  243,
  53,
  171,
  50,
  164,
  276,
  371,
  53,
  171,
  210,
  327,
  50,
  139,
  234,
  267,
  53,
  163,
  50,
  150,
  245,
  51,
  51,
  53,
  140,
  263,
  333,
  417,
  484,
  52,
  167,
  251,
  324,
  390
  }
  print(&quot;==========================&quot;)
  print(&quot; | 奶龙与小七之真假奶龙 | &quot;)
  print(&quot;==========================&quot;)
  print(&quot;你：我是奶龙！&quot;)
  print(&quot;假奶龙：我才是奶龙！&quot;)
  print(&quot;你：我会喷火，你会吗？&quot;)
  print(&quot;假奶龙：我也会！&quot;)
  print(&quot;小七：你们别争了，真正的奶龙会念出只有我能听懂的神奇咒语！&quot;)
  print(&quot;请输入你的咒语：&quot;)
  local r3_0 = r0_0(io.read())
  for r8_0 in pairs(r3_0) do
  local r9_0 = r3_0[r8_0]
  local r10_0 = r1_0[r8_0]
  if r9_0 ~= r10_0 then
  print(&quot;小七没有听懂你的咒语，你没有证明自己是真的奶龙！&quot;)
  os.exit(1)
  end
  end
  -- close: r4_0
  print(&quot;恭喜你说出了正确的咒语，你是真的奶龙！&quot;)
  os.exit(1)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;加密逻辑是典型的替换密码：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;整体反转输入&lt;/li&gt;
&lt;li&gt;从左到右扫描反转后的字符串：
&lt;ul&gt;
&lt;li&gt;如果是数字：用 (d+2) mod 9 的方式映射到另一个数字&lt;/li&gt;
&lt;li&gt;如果是非数字 &amp;#x26; 是第一个字符：直接用 ASCII 值&lt;/li&gt;
&lt;li&gt;如果是非数字 &amp;#x26; 不是第一个字符：把当前 ASCII 和前一个输出值相加&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;写出解密脚本：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;  r1_0 = [
  125,158,51,84,54,171,51,146,56,134,50,51,51,54,132,227,
  54,149,53,167,54,149,270,51,51,54,53,167,262,379,50,171,
  266,48,54,158,48,143,51,164,50,54,51,139,234,50,48,143,
  243,53,171,50,164,276,371,53,171,210,327,50,139,234,267,
  53,163,50,150,245,51,51,53,140,263,333,417,484,52,167,
  251,324,390
  ]
  
  # 逆向数字分支：(c - 48 + 2) % 9 + 48
  digit_map = {}
  for d in range(48, 58): # &apos;0&apos;..&apos;9&apos;
  enc = (d - 48 + 2) % 9 + 48
  digit_map.setdefault(enc, []).append(d)
  
  def reverse_enc(out):
  &quot;&quot;&quot;
  反推得到反转后的字符串（byte 数组）
  &quot;&quot;&quot;
  s_rev = [None] * len(out)
  
  # i = 0，对应 Lua 的 i = 1
  s_rev[0] = out[0] # 必须是非数字，直接就是 ASCII！
  
  for i in range(1, len(out)):
  val = out[i]
  
  # 分支 1：尝试非数字分支：val = c + out[i-1]
  c = val - out[i-1]
  if 32 &amp;#x3C;= c &amp;#x3C;= 126 and not (48 &amp;#x3C;= c &amp;#x3C;= 57): # 可显示 &amp;#x26; 非数字
  s_rev[i] = c
  continue
  
  # 分支 2：尝试数字分支
  if val in digit_map:
  # 如果能对应到某些数字，那就是数字字符
  # 多个可能时一般只有一个可打印
  for d in digit_map[val]:
  s_rev[i] = d
  break
  continue
  
  raise ValueError(&quot;无法反推第 {} 项&quot;.format(i))
  
  return s_rev
  
  s_rev = reverse_enc(r1_0)
  
  # 把 byte 数组拼成字符串，并反转回来
  s = &apos;&apos;.join(chr(c) for c in s_rev[::-1])
  print(&quot;解出的咒语：&quot;)
  print(s)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;答案：&lt;code&gt;BITs2CTF{W311_d0n3!_Y0u&apos;v3_pr0v3d_70_X140q1_7h47_y0u_r3411y_4r3_4_N4110N6_1u4!1!}&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;ChaCha20&lt;/h2&gt;
&lt;p&gt;简单到令人困惑的Python逆向，pycdc跑一遍就出来了&lt;/p&gt;
&lt;p&gt;源代码：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;  # Source Generated with Decompyle++
  # File: chacha20.pyc (Python 3.10)
  
  from cryptography.hazmat.primitives.ciphers import Cipher, algorithms
  from cryptography.hazmat.backends import default_backend
  from Crypto.Util.number import long_to_bytes, bytes_to_long
  from secret import flag
  import time
  import random
  import os
  
  def chacha20_encrypt(plaintext = None, key = None, nonce = None):
  cipher = Cipher(algorithms.ChaCha20(key, nonce), None,
  default_backend(), **(&apos;mode&apos;, &apos;backend&apos;))
  encryptor = cipher.encryptor()
  ciphertext = encryptor.update(plaintext)
  return ciphertext
  
  if __name__ == &apos;__main__&apos;:
  k1 = bytes_to_long(os.urandom(32))
  n1 = bytes_to_long(os.urandom(16))
  print(f&apos;&apos;&apos;k1={k1}&apos;&apos;&apos;)
  print(f&apos;&apos;&apos;n1={n1}&apos;&apos;&apos;)
  random.seed(int(time.time()) % 100)
  k2 = random.getrandbits(128)
  n2 = random.getrandbits(64)
  key = long_to_bytes(k1 ^ k2)
  nonce = long_to_bytes(n1 ^ n2)
  encrypted_data = chacha20_encrypt(flag, key, nonce)
  print(f&apos;&apos;&apos;加密后: {encrypted_data.hex()}&apos;&apos;&apos;)
  return None
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;解密脚本：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;  from cryptography.hazmat.primitives.ciphers import Cipher, algorithms
  from cryptography.hazmat.backends import default_backend
  from Crypto.Util.number import long_to_bytes
  import random
  
  # ================== 已知数据（从 result.txt 里抄过来的） ==================
  k1 =
  89156737880809474145449532029493055444849328922741582677584755390029529653680
  n1 = 20979402206073728478533457085044507592
  ct_hex =
  &quot;a8c123f27ed9d34a6040a98f0b9d5e22930ca34bd3195e27a1e73725aba2f3eff888&quot;
  
  ciphertext = bytes.fromhex(ct_hex)
  
  def chacha20_xor(data, key, nonce):
  &quot;&quot;&quot;和原脚本一样，用 ChaCha20 做加解密（同一个操作）&quot;&quot;&quot;
  cipher = Cipher(algorithms.ChaCha20(key, nonce), None, default_backend())
  encryptor = cipher.encryptor()
  return encryptor.update(data)
  
  for seed in range(100):
  random.seed(seed)
  k2 = random.getrandbits(128)
  n2 = random.getrandbits(64)
  
  key = long_to_bytes(k1 ^ k2)
  nonce = long_to_bytes(n1 ^ n2)
  
  # 理论上 key 应该 32 字节，nonce 应该 16 字节，这里简单做个保护
  if len(key) != 32 or len(nonce) != 16:
  continue
  
  try:
  pt = chacha20_xor(ciphertext, key, nonce)
  except Exception as e:
  # 不符合要求长度等情况直接跳过
  continue
  
  # 简单筛一下：只要能 decode，且包含 CTF 常见格式就输出
  try:
  s = pt.decode(&quot;utf-8&quot;)
  except UnicodeDecodeError:
  continue
  
  if &quot;CTF{&quot; in s or &quot;BITs2CTF{&quot; in s:
  print(f&quot;[+] seed = {seed}&quot;)
  print(f&quot;[+] plaintext = {s}&quot;)
  break
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;答案：&lt;code&gt;BITs2CTF{pyc_reverse_is_important}&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;EasyMaze&lt;/h2&gt;
&lt;p&gt;一眼的迷宫题。&lt;/p&gt;
&lt;p&gt;查看代码发现没有做任何混淆，逻辑清晰易懂，代码可读性高，夸赞一下。&lt;/p&gt;
&lt;p&gt;在 &lt;code&gt;Maze::Maze&lt;/code&gt; 找到迷宫数据，排除反调试后的假数据，发现&lt;code&gt;Maze&lt;/code&gt;类中除了前后左右外还有上下两个方向移动的函数，于是猜测应该是把三维迷宫逐层展开成一个二维迷宫（所以看起来是6*36的奇怪比例）。&lt;/p&gt;
&lt;p&gt;相关代码截取发给AI后写出了美观的求解页面（非必须，个人喜好）&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2Fimage5.B8ylekb9.png&amp;#x26;w=1265&amp;#x26;h=653&amp;#x26;f=webp&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;答案：&lt;code&gt;BITs2CTF{QHGIIVVWRKECAEWNVUTQPHEEEGQ}&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;Gore&lt;/h2&gt;
&lt;p&gt;Go语言逆向。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2Fimage7.BplqR_1r.png&amp;#x26;w=670&amp;#x26;h=226&amp;#x26;f=webp&quot; alt=&quot;&quot;&gt;
这里是伪随机，但是Go版本未知，随机数生成逻辑可能和文档记录的不同。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2Fimage8.CkLN0UFs.png&amp;#x26;w=1208&amp;#x26;h=168&amp;#x26;f=webp&quot; alt=&quot;&quot;&gt;
查看 &lt;code&gt;main_keyexpand&lt;/code&gt; 和 &lt;code&gt;main_crypt&lt;/code&gt; 发现加密逻辑是&lt;strong&gt;环状XOR&lt;/strong&gt;，但&lt;code&gt;ran[]&lt;/code&gt;序列不方便完全静态复现。于是动调之：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;  pwndbg&gt; info args
  box = 0xc0001abea0
  data = 0xc0001abed0
  ran = 0xc0001abeb8
  length = 56
  
  pwndbg&gt; x/gx (0xc0001abeb8)
  0xc0001abeb8: 0x000000c0001bc1c0
  
  pwndbg&gt; x/56gx (0xc0001bc1c0)
  0xc0001bc1c0: 0x0000000000000017 0x0000000000000068
  0xc0001bc1d0: 0x0000000000000084 0x0000000000000017
  0xc0001bc1e0: 0x0000000000000008 0x000000000000008f
  0xc0001bc1f0: 0x00000000000000a6 0x00000000000000f2
  0xc0001bc200: 0x00000000000000ea 0x000000000000002f
  0xc0001bc210: 0x0000000000000053 0x00000000000000b1
  0xc0001bc220: 0x00000000000000d3 0x00000000000000b6
  0xc0001bc230: 0x00000000000000e2 0x000000000000005b
  0xc0001bc240: 0x000000000000005c 0x000000000000009c
  0xc0001bc250: 0x0000000000000058 0x0000000000000064
  0xc0001bc260: 0x00000000000000f8 0x00000000000000a8
  0xc0001bc270: 0x0000000000000022 0x00000000000000e2
  0xc0001bc280: 0x0000000000000094 0x0000000000000005
  0xc0001bc290: 0x0000000000000057 0x0000000000000069
  0xc0001bc2a0: 0x0000000000000048 0x00000000000000fe
  0xc0001bc2b0: 0x0000000000000020 0x0000000000000032
  0xc0001bc2c0: 0x0000000000000078 0x00000000000000c1
  0xc0001bc2d0: 0x0000000000000022 0x0000000000000053
  0xc0001bc2e0: 0x00000000000000c9 0x0000000000000030
  0xc0001bc2f0: 0x0000000000000047 0x00000000000000ac
  0xc0001bc300: 0x000000000000001b 0x000000000000008f
  0xc0001bc310: 0x000000000000003d 0x000000000000009f
  0xc0001bc320: 0x0000000000000072 0x00000000000000df
  0xc0001bc330: 0x00000000000000cd 0x0000000000000034
  0xc0001bc340: 0x00000000000000ae 0x00000000000000fe
  0xc0001bc350: 0x0000000000000032 0x00000000000000f9
  0xc0001bc360: 0x00000000000000fc 0x000000000000005a
  0xc0001bc370: 0x000000000000004e 0x0000000000000036
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;写出解密脚本：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;  target = [
  0xBE, 0x67, 0xF3, 0x76, 0xE1, 0x5C, 0xA0, 0x79,
  0x1F, 0x42, 0xA7, 0x02, 0xE6, 0x99, 0x8D, 0xE3,
  0xCE, 0x10, 0x30, 0x36, 0xF6, 0x1C, 0x1B, 0xA1,
  0x4D, 0x25, 0x45, 0x43, 0xEE, 0x35, 0xFC, 0xB1,
  0x87, 0xB3, 0xBB, 0x5D, 0x26, 0x1E, 0xE7, 0x08,
  0x50, 0xFC, 0x4E, 0xA4, 0x7E, 0x45, 0xE6, 0xFC,
  0xC9, 0x18, 0x38, 0x10, 0xA6, 0x4B, 0x7F, 0xD5,
  ]
  
  ran = [
  0x17, 0x68, 0x84, 0x17, 0x08, 0x8f, 0xa6, 0xf2,
  0xea, 0x2f, 0x53, 0xb1, 0xd3, 0xb6, 0xe2, 0x5b,
  0x5c, 0x9c, 0x58, 0x64, 0xf8, 0xa8, 0x22, 0xe2,
  0x94, 0x05, 0x57, 0x69, 0x48, 0xfe, 0x20, 0x32,
  0x78, 0xc1, 0x22, 0x53, 0xc9, 0x30, 0x47, 0xac,
  0x1b, 0x8f, 0x3d, 0x9f, 0x72, 0xdf, 0xcd, 0x34,
  0xae, 0xfe, 0x32, 0xf9, 0xfc, 0x5a, 0x4e, 0x36,
  ]
  
  def keyexpand(k):
  length = len(k)
  box = list(range(256))
  i = 0
  j = 0
  while i &amp;#x3C; 256:
  v = box[i]
  j_idx = (k[i % length] + v + j) % 256
  box[i] = box[j_idx] ^ v
  box[j_idx] ^= box[i]
  box[i] ^= box[j_idx]
  i += 1
  j = j_idx
  return box
  
  def crypt(box0, data, ran):
  length = len(data)
  box = box0[:] # copy
  i = 0
  j = 0
  t = 0
  while t &amp;#x3C; length:
  v7 = i - (((i + 1) &amp;#x26; ~0xff))
  idx_i = v7 + 1
  
  v10 = box[idx_i]
  j_idx = (v10 + j) % 256
  
  box[idx_i] = box[j_idx] ^ v10
  box[j_idx] ^= box[idx_i]
  box[idx_i] ^= box[j_idx]
  
  v16 = box[idx_i]
  v17 = v7 + j_idx + 1
  
  idx_ran = v17 % length
  idx_s = ran[idx_ran] ^ ((box[j_idx] + v16) % 256)
  
  data[t] ^= box[idx_s]
  
  t += 1
  i = idx_i
  j = j_idx
  return data
  
  def invert_ring_xor(q):
  L = len(q)
  xor_0_to_Lm2 = 0
  for i in range(L-1):
  xor_0_to_Lm2 ^= q[i]
  p0 = q[L-1] ^ xor_0_to_Lm2 ^ q[0]
  p = [0]*L
  p[0] = p0
  acc = 0
  for k in range(1, L):
  acc ^= q[k-1]
  p[k] = acc ^ p0
  return p
  
  def main():
  key_str = &quot;BITs2CTF{}&quot;
  k = [ord(c) for c in key_str]
  box0 = keyexpand(k)
  
  data = target.copy()
  q = crypt(box0, data, ran.copy())
  
  p = invert_ring_xor(q)
  
  mid_bytes = []
  for idx in range(28):
  lo = chr(p[2*idx])
  hi = chr(p[2*idx+1])
  mid_bytes.append(int(hi+lo, 16))
  
  middle = bytes(mid_bytes).decode()
  flag = &quot;BITs2CTF{&quot; + middle + &quot;}&quot;
  print(flag)
  
  if __name__ == &quot;__main__&quot;:
  main()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;答案：&lt;code&gt;BITs2CTF{G0r3_15_h@Aa4%&amp;#x26;rD_7O_5oLv3?!}&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;Math&lt;/h2&gt;
&lt;p&gt;fun1到fun4都是纯数学运算，可以化简成Z3求解器友好的形式。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;  from z3 import *
  
  # 6 个 32-bit 无符号变量
  A, b, c, d, e, f = BitVecs(&apos;A b c d e f&apos;, 32)
  
  s = Solver()
  
  # 范围约束：100000 &amp;#x3C; x &amp;#x3C; 1000000
  lo = BitVecVal(100000, 32)
  hi = BitVecVal(1000000, 32)
  for v in (A, b, c, d, e, f):
  s.add(UGT(v, lo)) # v &gt; 100000
  s.add(ULT(v, hi)) # v &amp;#x3C; 1000000
  
  # 1) (A + b) % 951081 == 597141
  mod = BitVecVal(951081, 32)
  s.add(URem(A + b, mod) == BitVecVal(597141, 32))
  
  # 2) A - b + 2c == 1644082
  s.add(A - b + (c &amp;#x3C;&amp;#x3C; 1) == BitVecVal(1644082, 32))
  
  # 3) 4f XOR d == 1161537
  s.add(((f &amp;#x3C;&amp;#x3C; 2) ^ d) == BitVecVal(1161537, 32))
  
  # 4) 5(d - e) == 343890
  s.add((BitVecVal(5, 32) * (d - e)) == BitVecVal(343890, 32))
  
  # 5) A + f == 1136538
  s.add(A + f == BitVecVal(1136538, 32))
  
  # 6) 2d + e == 1952901
  s.add((d &amp;#x3C;&amp;#x3C; 1) + e == BitVecVal(1952901, 32))
  
  print(s.check())
  m = s.model()
  
  A_val = m[A].as_long()
  b_val = m[b].as_long()
  c_val = m[c].as_long()
  d_val = m[d].as_long()
  e_val = m[e].as_long()
  f_val = m[f].as_long()
  
  print(&quot;A =&quot;, A_val)
  print(&quot;b =&quot;, b_val)
  print(&quot;c =&quot;, c_val)
  print(&quot;d =&quot;, d_val)
  print(&quot;e =&quot;, e_val)
  print(&quot;f =&quot;, f_val)
  
  flag =
  f&quot;BITs2CTF{{{A_val:x}{b_val:x}{c_val:x}{d_val:x}{e_val:x}{f_val:x}}}&quot;
  print(&quot;Flag:&quot;, flag)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;答案：&lt;code&gt;BITs2CTF{a5b51d446ddffa7a486593bbb6fc49}&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;这题本来想用Angr做符号执行，玩一把花活儿，结果Angr似乎跑进死循环了，可能还是学艺不精不太会用，sad😢😢。&lt;/p&gt;
&lt;h2&gt;Rustre&lt;/h2&gt;
&lt;p&gt;Rust是一种很严谨的语言，所以当你尝试反编译rustre::main的时候你就会看到编译器摁造出来的依托垃圾。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2Fimage11.CUxKSrI6.png&amp;#x26;w=744&amp;#x26;h=942&amp;#x26;f=webp&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;各种边界检查丑的不要不要的，无法看出实际情况。于是让AI对代码进行简化（也就是说：写出一个等效Rust项目，这一步巨难无比，我花了一个下午才折腾出等效的可用代码）：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;  ❯ cat src/main.rs
  use std::io::{self};
  
  // 对应 IDA 中的 rustre::square
  // 在 Debug 编译下，Rust 会自动插入溢出检查 (is_mul_ok)
  fn square(n: u32) -&gt; u32 {
  n * n
  }
  
  // 对应 IDA 中的 keychange
  fn keychange(key: &amp;#x26;mut [u8]) {
  // 还原去重逻辑
  // 遍历 1..4，比较 key[i] 和 key[i-1]
  for i in 1..4 {
  if key[i] == key[i - 1] {
  key[i] = 50; // ASCII &apos;2&apos;
  }
  }
  
  // 还原 XOR 链逻辑
  // 遍历 0..3
  for i in 0..3 {
  key[i] ^= key[i + 1];
  }
  }
  
  // 对应 IDA 中的 enc
  // 这里包含了一个关键的逻辑陷阱，导致只加密了前 12 字节
  fn enc(data: &amp;#x26;mut [u8], key: &amp;#x26;[u8]) {
  let len = data.len();
  // 陷阱还原：原作者可能想写 len / 4，但写成了 len / 8 (也就是 &gt;&gt; 3)
  // 导致 limit = 28 / 8 = 3
  let limit = len &gt;&gt; 3;
  
  for i in 0..limit {
  // 每次处理 4 字节
  for j in 0..4 {
  let data_idx = i * 4 + j;
  // 密钥轮转逻辑: (Block + Offset) % 4
  let key_idx = (i + j) % 4;
  
  data[data_idx] ^= key[key_idx];
  }
  }
  }
  
  fn main() {
  // 1. 读取输入
  // 对应 std::io::stdio::Stdin::read_line
  let mut input_str = String::new();
  io::stdin()
  .read_line(&amp;#x26;mut input_str)
  .expect(&quot;Failed to read line&quot;);
  
  // 对应 core::str::trim
  let input = input_str.trim();
  
  // 对应 &quot;Wrong length!&quot; 检查
  if input.len() != 28 {
  println!(&quot;Wrong length!&quot;);
  return;
  }
  
  let mut data = input.as_bytes().to_vec();
  
  // 2. 准备密钥
  let mut key_str = String::from(&quot;reee&quot;);
  // SAFETY: &quot;reee&quot; is valid utf8, unsafe implies direct byte
  manipulation in some contexts,
  // but standard into_bytes is safe. kept simple here.
  let mut key = key_str.into_bytes();
  
  keychange(&amp;#x26;mut key);
  
  // 3. 执行加密 (含 Trap)
  enc(&amp;#x26;mut data, &amp;#x26;key);
  
  // 4. 位重组 (Shuffle)
  // 对应那一长串的 index 操作。
  // 使用 chunks(7) 会导致编译器对定长循环进行展开 (Loop Unrolling)
  let mut shuffled_data = vec![0u8; 28];
  
  for (chunk_idx, chunk) in data.chunks(7).enumerate() {
  let base_idx = chunk_idx * 7;
  
  // 模拟 7x7 位变换
  for (s_byte_idx, &amp;#x26;byte) in chunk.iter().enumerate() {
  // 假设只处理 ASCII 的低 7 位
  for b in 0..7 {
  // 取出第 b 位
  if (byte &gt;&gt; b) &amp;#x26; 1 == 1 {
  // 还原公式: dst = (6 - b - s) % 7
  // 使用 rem_euclid 确保负数取模结果为正，符合数学定义
  let d_byte_idx = (6 - (b as i32) - (s_byte_idx as i32)).rem_euclid(7)
  as usize;
  
  shuffled_data[base_idx + d_byte_idx] |= 1 &amp;#x3C;&amp;#x3C; b;
  }
  }
  }
  }
  
  // 5. 字节映射与比较
  // 对应 IDA 中的 rustre::main::{{closure}}
  // 以及最终的 cmp 逻辑
  let target = [
  139, 161, 68, 233, 197, 35, 129, 79, 171, 76, 167, 6, 37, 135, 207,
  236, 143, 169, 41, 205,
  8, 197, 109, 109, 205, 228, 140, 128,
  ];
  
  // Map: ((x ^ 25) &gt;&gt; 3) | ((x ^ 25) &amp;#x3C;&amp;#x3C; 5)
  // 这在 Rust 中就是 rotate_right(3)
  let final_data: Vec&amp;#x3C;u8&gt; = shuffled_data
  .iter()
  .map(|&amp;#x26;x| {
  let val = x ^ (square(5) as u8);
  val.rotate_right(3)
  })
  .collect();
  
  // 6. 结果判定
  if final_data == target {
  println!(&quot;You are right!&quot;);
  } else {
  println!(&quot;You are wrong!&quot;);
  }
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;那还说什么，直接vibe it~&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;  #!/usr/bin/env python3
  # -*- coding: utf-8 -*-
  
  # 题目中 main 里给的 target 数组
  TARGET = [
  139, 161, 68, 233, 197, 35, 129, 79,
  171, 76, 167, 6, 37, 135, 207, 236,
  143, 169, 41, 205, 8, 197, 109, 109,
  205, 228, 140, 128,
  ]
  
  def keychange_from_reee():
  &quot;&quot;&quot;
  还原 Rust 里的 keychange(&quot;reee&quot;)
  初始: &quot;reee&quot; -&gt; [114, 101, 101, 101]
  &quot;&quot;&quot;
  key = [ord(c) for c in &quot;reee&quot;]
  
  # 去重逻辑
  for i in range(1, 4):
  if key[i] == key[i - 1]:
  key[i] = 50 # &apos;2&apos;
  
  # XOR 链
  for i in range(3):
  key[i] ^= key[i + 1]
  
  return key # [23, 87, 87, 101]
  
  
  def inverse_map(target):
  &quot;&quot;&quot;
  逆向这一段：
  val = x ^ 25
  out = val.rotate_right(3)
  
  对应逆过程：
  val = rotate_left(x, 3)
  src = val ^ 25
  &quot;&quot;&quot;
  res = []
  for x in target:
  # 8-bit rotate_left(3)
  val = ((x &amp;#x3C;&amp;#x3C; 3) &amp;#x26; 0xFF) | (x &gt;&gt; 5)
  res.append(val ^ 25)
  return res # 得到 shuffled_data
  
  
  def inverse_shuffle(shuffled):
  &quot;&quot;&quot;
  逆向 7x7 位重组：
  
  正向：
  for each chunk of 7 bytes:
  for s in 0..6:
  for b in 0..6:
  if src[s] 第 b 位为 1:
  d = (6 - b - s) mod 7
  dst[d] 的第 b 位 |= 1
  
  逆向：
  已知 dst[d] 第 b 位为 1，则：
  s = (6 - b - d) mod 7
  src[s] 的第 b 位 |= 1
  &quot;&quot;&quot;
  n = len(shuffled)
  out = [0] * n
  assert n % 7 == 0
  
  num_chunks = n // 7
  for chunk_idx in range(num_chunks):
  base = chunk_idx * 7
  for d in range(7):
  byte = shuffled[base + d]
  for b in range(7): # 只处理低 7 位
  if (byte &gt;&gt; b) &amp;#x26; 1:
  s = (6 - b - d) % 7
  out[base + s] |= (1 &amp;#x3C;&amp;#x3C; b)
  return out # 即 enc 之后的 data
  
  
  def inverse_enc(data_after_enc, key):
  &quot;&quot;&quot;
  逆向 enc：
  
  正向：
  limit = len &gt;&gt; 3 = 3 (因为 len=28)
  i=0..2, j=0..3:
  idx = i*4 + j
  data[idx] ^= key[(i+j) % 4]
  
  XOR 自反，所以逆向做同样的 XOR 即可还原。
  &quot;&quot;&quot;
  data = list(data_after_enc)
  for i in range(3):
  for j in range(4):
  idx = i * 4 + j
  kidx = (i + j) % 4
  data[idx] ^= key[kidx]
  return data
  
  
  def main():
  # 1. 逆最后一步 map，得到 shuffled_data
  shuffled = inverse_map(TARGET)
  
  # 2. 逆 7x7 位重组，得到 enc 之后但 shuffle 之前的 data
  data_after_enc = inverse_shuffle(shuffled)
  
  # 3. 还原 key
  key = keychange_from_reee()
  
  # 4. 逆 enc，得到原始输入（flag 字节）
  plain_bytes = inverse_enc(data_after_enc, key)
  
  # 5. 转成字符串
  flag = &apos;&apos;.join(chr(b) for b in plain_bytes)
  print(&quot;Recovered flag:&quot;, flag)
  
  
  if __name__ == &quot;__main__&quot;:
  main()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;答案：&lt;code&gt;BITs2CTF{D1fficuLt_Ru57R3~~}&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;这个题目还是很有难度的，1kpts名副其实。传统的长代码审计也很克制 AI
。我使用Gemini3分步处理，非常完美的解决了这道题目，令人感叹长上下文就是爽啊~&lt;/p&gt;
&lt;p&gt;另外值得提一嘴的就是AI的使用。这些日子大量使用AI辅助做题，发现了一个小技巧：&lt;strong&gt;我们把AI的解题步骤分为提供信息和思路推进，则思路推进一定要分步处理，信息提供一定要一步给完&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;如何理解这句话呢？例如有&lt;code&gt;fun1()&lt;/code&gt;、&lt;code&gt;fun2()&lt;/code&gt;两个函数，经过了3个不同的加密步骤得到密文。&lt;/p&gt;
&lt;p&gt;则，你的第一条prompt应该是：&lt;code&gt;fun1()&lt;/code&gt;的完整代码+&lt;code&gt;fun2()&lt;/code&gt;的完整代码+调度器（让AI知道是3轮加密），2️而不应该是：第一条prompt给&lt;code&gt;fun1()&lt;/code&gt;的代码，AI提示你给出&lt;code&gt;fun2()&lt;/code&gt;的，你再给。&lt;/p&gt;
&lt;p&gt;一次给足信息的效果几乎总是远远强于分步给出信息的会话，fun fact to share.&lt;/p&gt;
&lt;h2&gt;感想&lt;/h2&gt;
&lt;p&gt;最近很不顺心，打N1打的有点破防，结果看到&lt;a href=&quot;https://astralprisma.github.io/2025/11/02/about_flowers_2/&quot;&gt;这篇博客&lt;/a&gt;，震惊地发现：设计这道卡住我一周的难题的，位列N1官网的师傅，竟然才大二（或大三）。一瞬间被差距打击地体无完肤了，迫切地想做题做题做题。&lt;/p&gt;
&lt;p&gt;这种心态健康吗？也不见得多健康，熬夜，眼睛痛，头晕，上课打不起精神，作业欠一堆，还有那些自己处于体验生活目的加入的学生社团和组织的任务......算了，你没有义务成为天才，还是过好自己的生活吧。&lt;/p&gt;
&lt;p&gt;You only live once.&lt;/p&gt;</content:encoded><h:img src="/_astro/cover.GdN2kgg6.webp"/><enclosure url="/_astro/cover.GdN2kgg6.webp"/></item><item><title>流量时代正在断送媒体的良知：锐评新京报报道南京大学帝王蟹事件</title><link>https://crisq.top/blog/aritxs_view_of_the_nju_defamation</link><guid isPermaLink="true">https://crisq.top/blog/aritxs_view_of_the_nju_defamation</guid><description>转自Aritx，和我自己的一点看法</description><pubDate>Tue, 04 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;以下内容转自我的好友&lt;a href=&quot;https://www.aritxonly.top/posts/251104-media-thoughts-about-nju/&quot;&gt;AritxOnly-音唯&lt;/a&gt;，作为 WHU 的学子，互联网上的口诛笔伐这些日子真是受够了。我对南大很有感情，便就借着他的这篇文章抒发下自己的悲愤吧。&lt;/p&gt;
&lt;hr&gt;
&lt;blockquote&gt;
&lt;p&gt;“媒体面前，事实似乎不再重要了。”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这几个月我越来越不信任新闻，因为事实往往不是它们让你看到的那样。&lt;/p&gt;
&lt;p&gt;昨天去九食堂，和女朋友盘算着叫几个人一起尝尝没尝过的帝王蟹，今天就被骂上热搜了。&lt;/p&gt;
&lt;h2&gt;从数码圈乱象起手&lt;/h2&gt;
&lt;p&gt;我关注的圈子，是无良媒体扎堆的数码圈。&lt;/p&gt;
&lt;p&gt;“比一元硬币还薄”的断章取义、“小字营销”的带节奏、“年轻人的最后一台车”的情绪包装——这些我都看在眼里。但我没有发声。&lt;/p&gt;
&lt;p&gt;我不是小米的“死忠粉”，只是一个喜欢产品、能分辨是非的普通人。用着华为手表、拿着OPPO手机、背着苹果电脑，也装着米家生态。可当我看到那么多人被带偏，被煽动去骂、去信时，我才真正意识到：媒体对公众的影响力有多么恐怖。&lt;/p&gt;
&lt;h2&gt;锐评本次事件&lt;/h2&gt;
&lt;p&gt;南大学生十人八人，分享一只帝王蟹又何罪之有呢？&lt;/p&gt;
&lt;p&gt;你们说我们不务学习，尽显奢靡之风——而我告诉你午夜的生命科学楼、计算机楼、电子楼等院楼灯火通明，不止研究生和博士生，还有本科生和教职老师。他们用尽心力，只为了给国家给社会创造更多的价值。&lt;/p&gt;
&lt;p&gt;你们说我们没有积蓄，尽花父母钱财——而我告诉你南京的大学生家教的数量已经超出你们的想象。我的同学们，不是通过家教兼职赚钱，就是通过实习积攒工作经历，亦或是投资理财理财。我们的有能力拼一桌人均150的帝王蟹。&lt;/p&gt;
&lt;p&gt;你们会拿南大前校训“嚼得菜根，做得大事”上纲上线，而我告诉你，奢俭由人，南大学子绝不会因为享用过一餐帝王蟹，就真认为自己是“帝王”了。&lt;/p&gt;
&lt;h2&gt;一点冷静的分析&lt;/h2&gt;
&lt;p&gt;情绪发泄之外，不妨跳出这件事情本身，来看看媒体是如何误导群众，而群众又是如何制造出庞大的互联网声量的。&lt;/p&gt;
&lt;p&gt;媒体首先给事件贴上标签，用情绪代替事实，用“高校奢靡”“学生浪费”这样的话术触发公众的愤怒。随后，社交平台的算法捕捉到这种情绪，放大矛盾，推送给更多还没了解真相的用户。于是，一场舆论的狂欢开始了。谁还在乎真相？只要骂，就能被看见。&lt;/p&gt;
&lt;p&gt;在这样的环境里， &lt;strong&gt;一个人的认知，决定了他能看到的东西&lt;/strong&gt; 。&lt;/p&gt;
&lt;p&gt;那些骂南大“奢靡”的人，或许只是看到了自己生活的投射——他们身边确实充斥着攀比、虚荣和浮躁，于是理所当然地认为所有学校都一样。当他们看到一所大学的食堂敢卖帝王蟹，他们不会想到是尝试改革、是多样化供餐，而会本能地嘲讽：“这不就是洗脚城吗？”&lt;/p&gt;
&lt;p&gt;他们眼里的“奢靡之风”，正是他们熟悉的世界；他们嘲笑的“校园堕落”，也许只是南大走在前面的尝试。他们酸的，不是帝王蟹的价格，而是自己学校里没有这样的改变。&lt;/p&gt;
&lt;p&gt;就好像真正的“花粉”也会批驳华为旗舰机系统更新不及时、价格虚高等等不足，而手上拿着低端机的网友却对这些真金白银支持华为的人们口诛笔伐。网络上从来不缺精神股东，网络只是他们的情绪宣泄口。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;这就是流量时代最可悲的地方：人们不再追问“事实是什么”，而是急着寻找能让自己情绪有出口的东西。媒体知道这一点，于是不断制造“可以骂”的新闻。群众在骂声中获得快感，而真相被埋在最不值钱的地方。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;是啊， &lt;strong&gt;真相已随那一串串的字符流，消失在了大数据的海洋里&lt;/strong&gt; 。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;最后发一段我在 QQ 空间写下的评论吧：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;最近互联网上似乎形成了一种新的猎巫范式：大家似乎已经发现了一种通过找各种清奇的角度，片面陈述甚至伪造事实来诋毁高校的固定套路——当然，很有效，很爽，很能恶心人。
从“入学小心被留学生强奸”的浙江大学，“努力培养和NGO勾结的汉奸”的武汉大学，到“奢靡之风成性”的南京大学，下一个是谁呢？
我不想说什么诸如“不分青红皂白选择一竿子打死的人都是上不起985的红眼loser”这种无谓的诛心之论，只是祝愿各位在被裹挟着的舆论彰显出的所谓“民意的铁拳”砸到自己身上的时候，也能有诋毁别人学校时那样的镇定与愉悦。&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded><h:img src="/_astro/cover.BTs6bDjZ.webp"/><enclosure url="/_astro/cover.BTs6bDjZ.webp"/></item><item><title>WHUCTF-2025 RE方向全题解</title><link>https://crisq.top/blog/whuctf_2025_newbies_wp</link><guid isPermaLink="true">https://crisq.top/blog/whuctf_2025_newbies_wp</guid><description>最近正好打完了WHUCTF的新生赛，写一篇题解记录一下。</description><pubDate>Sun, 26 Oct 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;WHUCTF-2025 RE方向全题解&lt;/h1&gt;
&lt;h2&gt;签到&lt;/h2&gt;
&lt;p&gt;打开发现是弗吉尼亚密码，直接解密即可。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;WHUCTF{welcome_to_reverse-kep}.exe&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;ezbase&lt;/h2&gt;
&lt;p&gt;发现密文 &lt;code&gt;d2h1Y3RmezZac2U2NF8xc192ZXJ5XzNac3ktZWtlfQ==&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;猜测base64，发现表都没换&lt;/p&gt;
&lt;p&gt;坏了，想简单了，换表了，难度还是太高了（&lt;/p&gt;
&lt;p&gt;&lt;code&gt;aBCDEFGHIJKLMNOPQRSTUVWXYZAbcdefghijklmnoqprstuvwxyz0123456789+/&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;得：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;whuctf{6@se64_1s_very_3@sy-eke}.exe&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;太空逃亡&lt;/h2&gt;
&lt;p&gt;主函数是一个巨简单的验证函数，关键的加密逻辑在&lt;code&gt;sub_4015F8&lt;/code&gt;。检验得其把用户输入当作一串方向键 W/A/S/D（分别对应上、左、下、右），在一个 16×16 的网格（线性数组 byte_4A3020）上沿直线滑动：每次沿某方向一直前进直到遇到一个非 0的格（障碍/节点）；不能越界、不能连续输入相同方向，目标是最终抵达数组中值为 &apos;!&apos;（33）的格子。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;迷宫地图 (0=路径, !=终点, 其他=障碍):
. . . . # . . . . . . . # # # #
. . . # # . . . # # . . . . . .
. . . . . . . . # # . # # . . .
. . . # . # # . # # . # # . . .
. . . # . # # . # # . # . . . .
. . # # . # # . . . . # . . . .
. . . . . # # . . . . # . . . .
# . . . . . . . . . . . . . . .
. . . . . . . . . . . . # . . .
. . . . . . # # # . . . # . . .
. . . . . . . # # # . . . . # #
. . . # . # . # . # . . . . # .
. . . . . . . . . . . . . . # #
# # # # . # . # . # . . . . # .
. # . # . # . # . # . . . . # .
. # . # . # . # . # ! . . . # #
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;值得注意的是！这是一个冰面迷宫，左右移会直接移到可移动区域的边缘。&lt;/p&gt;
&lt;p&gt;写出解密脚本即可：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;import hashlib
from collections import deque


def parse_maze_data():
    &quot;&quot;&quot;解析IDA风格的迷宫数据&quot;&quot;&quot;
    # 解析重复计数语法
    def parse_dup(part):
        part = part.strip()
        if &apos;dup(&apos; in part:
            count_str, value_str = part.split(&apos;dup(&apos;)
            count_str = count_str.strip()
            value_str = value_str.strip(&apos;)&apos;)

            # 处理十六进制计数 (如0Eh, 1Bh等)
            if count_str.endswith(&apos;h&apos;):
                count = int(count_str[:-1], 16)
            else:
                count = int(count_str)

            # 处理十六进制值
            if value_str.endswith(&apos;h&apos;):
                value = int(value_str[:-1], 16)
            else:
                value = int(value_str)

            return [value] * count
        else:
            # 处理普通值
            if part.endswith(&apos;h&apos;):
                return [int(part[:-1], 16)]
            else:
                return [int(part)]

    # 原始数据
    raw_data = [
        &quot;4 dup(0), 23h, 7 dup(0), 4 dup(23h), 3 dup(0), 2 dup(23h)&quot;,
        &quot;3 dup(0), 2 dup(4Fh), 0Eh dup(0), 2 dup(4Fh), 0, 2 dup(50h)&quot;,
        &quot;6 dup(0), 4Ch, 0, 2 dup(4Fh), 0, 2 dup(4Fh), 0, 2 dup(50h)&quot;,
        &quot;6 dup(0), 4Ch, 0, 2 dup(4Fh), 0, 2 dup(4Fh), 0, 50h&quot;,
        &quot;6 dup(0), 2 dup(4Ch), 0, 2 dup(4Fh), 4 dup(0), 50h&quot;,
        &quot;9 dup(0), 2 dup(4Fh), 4 dup(0), 50h, 4 dup(0), 23h&quot;,
        &quot;1Bh dup(0), 23h, 9 dup(0), 3 dup(4Dh), 3 dup(0), 23h&quot;,
        &quot;0Ah dup(0), 3 dup(4Dh), 4 dup(0), 2 dup(45h), 3 dup(0)&quot;,
        &quot;30h, 0, 4Dh, 0, 4Dh, 0, 4Dh, 4 dup(0), 45h, 0Fh dup(0)&quot;,
        &quot;2 dup(45h), 3 dup(54h), 49h, 0, 4Dh, 0, 4Dh, 0, 4Dh&quot;,
        &quot;4 dup(0), 45h, 2 dup(0), 54h, 0, 49h, 0, 4Dh, 0, 4Dh&quot;,
        &quot;0, 4Dh, 4 dup(0), 45h, 2 dup(0), 54h, 0, 49h, 0, 4Dh&quot;,
        &quot;0, 4Dh, 0, 4Dh, 21h, 3 dup(0), 2 dup(45h)&quot;
    ]

    maze = []
    for line in raw_data:
        parts = line.split(&apos;,&apos;)
        for part in parts:
            part = part.strip()
            if part:
                maze.extend(parse_dup(part))

    return maze


def solve_maze(maze, start, end):
    &quot;&quot;&quot;使用BFS算法求解迷宫最短路径&quot;&quot;&quot;
    rows, cols = 16, 16
    directions = [(0, 1, &apos;D&apos;), (1, 0, &apos;S&apos;), (0, -1, &apos;A&apos;), (-1, 0, &apos;W&apos;)]

    # 将一维数组转换为二维网格
    grid = [[maze[i * cols + j] for j in range(cols)] for i in range(rows)]

    # BFS初始化
    queue = deque([(start, [])])
    visited = set([start])

    while queue:
        (x, y), path = queue.popleft()

        # 到达终点
        if (x, y) == end:
            return path

        # 探索四个方向
        for dx, dy, direction in directions:
            nx, ny = x + dx, y + dy

            # 检查边界和可通行性
            if 0 &amp;#x3C;= nx &amp;#x3C; rows and 0 &amp;#x3C;= ny &amp;#x3C; cols:
                if (nx, ny) not in visited and (grid[nx][ny] == 0 or grid[nx][ny] == 0x21):
                    visited.add((nx, ny))
                    queue.append(((nx, ny), path + [direction]))

    return None  # 无解


def visualize_maze(maze):
    &quot;&quot;&quot;可视化迷宫&quot;&quot;&quot;
    rows, cols = 16, 16
    grid = [[maze[i * cols + j] for j in range(cols)] for i in range(rows)]

    print(&quot;迷宫地图 (0=路径, !=终点, 其他=障碍):&quot;)
    for i in range(rows):
        for j in range(cols):
            if grid[i][j] == 0:
                print(&apos;.&apos;, end=&apos; &apos;)
            elif grid[i][j] == 0x21:
                print(&apos;!&apos;, end=&apos; &apos;)
            else:
                print(&apos;#&apos;, end=&apos; &apos;)
        print()


def main():
    # 解析迷宫数据
    print(&quot;正在解析迷宫数据...&quot;)
    maze = parse_maze_data()

    # 检查迷宫大小
    print(f&quot;迷宫大小: {len(maze)} 字节&quot;)

    # 可视化迷宫
    visualize_maze(maze)

    # 设置起点和终点
    start = (0, 0)
    end = (15, 15)  # 终点在右下角

    print(f&quot;\n起点: {start}&quot;)
    print(f&quot;终点: {end}&quot;)

    # 求解迷宫
    print(&quot;\n正在求解迷宫...&quot;)
    path = solve_maze(maze, start, end)

    if path:
        path_str = &apos;&apos;.join(path)
        print(f&quot;找到路径! 长度: {len(path)}&quot;)
        print(f&quot;WASD序列: {path_str}&quot;)

        # 计算MD5
        md5_hash = hashlib.md5(path_str.encode()).hexdigest()
        print(f&quot;MD5哈希: {md5_hash}&quot;)

        # 构造flag
        flag = f&quot;WHUCTF{{{md5_hash}}}&quot;
        print(f&quot;\nFLAG: {flag}&quot;)
    else:
        print(&quot;未找到路径!&quot;)


if __name__ == &quot;__main__&quot;:
    main()
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Try to find me&lt;/h2&gt;
&lt;p&gt;打开IDA一片茫然，啥都找不到。于是Shift + F12查字符串发现了：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;strcpy((char *)(v0 + 40), &quot;Software\\flag&quot;);
strcpy((char *)(v0 + 84), &quot;flag&quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;找到了程序逻辑的尾巴：
&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2FREADME_20251026213501173.j6u9X6vV.png&amp;#x26;w=1726&amp;#x26;h=462&amp;#x26;f=webp&quot; alt=&quot;&quot;&gt;
这里会把解密后的目标字符串写入注册表的&lt;code&gt;HKEY_CURRENT_USER\Software\flag&lt;/code&gt;，然后残忍地删掉。
&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2FREADME_20251026213803043.CBjeNtkW.png&amp;#x26;w=1794&amp;#x26;h=792&amp;#x26;f=webp&quot; alt=&quot;&quot;&gt;
不行，不能让它删掉（悲）
&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2FREADME_20251026213903570.CgfPlcr0.png&amp;#x26;w=1080&amp;#x26;h=1210&amp;#x26;f=webp&quot; alt=&quot;&quot;&gt;
于是我们patch掉这两个&lt;code&gt;RegDeleteKey&lt;/code&gt;的调用，再次运行程序。
&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2FREADME_20251026214334459.DWAJb-ag.png&amp;#x26;w=1138&amp;#x26;h=650&amp;#x26;f=webp&quot; alt=&quot;&quot;&gt;
注：本题的加密是曾经书记出的困难题，所以别想着静调了~&lt;/p&gt;
&lt;h2&gt;What can you find&lt;/h2&gt;
&lt;p&gt;这题可以当作一道misc去做：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;&gt; binwalk -e ./what_can_you_find.3dsx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;得一张png，打开有：
&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2Fimage.DUzchUWg.png&amp;#x26;w=400&amp;#x26;h=240&amp;#x26;f=webp&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;这其实是非预期，下面介绍一种比较简洁的预期解法。&lt;/p&gt;
&lt;p&gt;首先，我们了解到3DSX是ELF的变体，因此有映射区段并反编译的可能。通过查找Github已有的开源库我们发现了 &lt;a href=&quot;https://github.com/0xEBFE/3DSX-IDA-PRO-Loader&quot;&gt;这个项目&lt;/a&gt;，这里作者其实已经对IDA 7以上的版本做了适配，我进行了少量修改使它符合IDA 9的标准，但不修改也没大问题，可以直接用。放入&lt;code&gt;~/.idapro/loaders&lt;/code&gt;即可：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2Findex_20251027114541451.DgnPh9Gj.png&amp;#x26;w=2880&amp;#x26;h=1800&amp;#x26;f=webp&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;现在，我们就可以像处理一个正常的ELF可执行文件那样去处理它了。先查找字符串可以发现如上的逆天言论，跳转找到主函数：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2Findex_20251027114651772.CKaBKyGm.png&amp;#x26;w=2880&amp;#x26;h=1800&amp;#x26;f=webp&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;这里是一个输入密码并显示图片的简单程序，因此我们要从中提取出图片文件。此处像上面非预期一样binwalk即可。&lt;/p&gt;
&lt;h2&gt;好多文件&lt;/h2&gt;
&lt;p&gt;好多文件！！！&lt;/p&gt;
&lt;p&gt;但是没关系，观察Plugins发现，83和84单独分离出了自己的dll，猜测83和84是节目效果。&lt;/p&gt;
&lt;p&gt;打开后发现是盘子（小）小故事，笑死了。&lt;/p&gt;
&lt;p&gt;打开exe文件，太乱了，拖一下列表发现主要函数：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;// Hidden C++ exception states: #wind=2
HBRUSH __fastcall WndProc(HWND hWnd, UINT msg, HDC wParam, LPARAM lParam)
{

    ...something_else...

      if ( (unsigned __int16)wParam == 2 )
      {
        GetWindowTextW(hEdit, buf, 32);
        score = j__wtoi(buf);
        if ( (unsigned int)score &amp;#x3C;= 0x64 )
        {
          std::wstring::wstring(&amp;#x26;dllName);
          if ( score &gt; 60 )
          {
            if ( score &gt; 82 )
            {
              if ( score == 83 )
              {
                std::wstring::operator=(&amp;#x26;dllName, L&quot;Plugin_83.dll&quot;);
              }
              else if ( score == 84 )
              {
                std::wstring::operator=(&amp;#x26;dllName, L&quot;Plugin_84.dll&quot;);
              }
              else
              {
                std::wstring::operator=(&amp;#x26;dllName, L&quot;Plugin_85_100.dll&quot;);
              }
            }
            else
            {
              std::wstring::operator=(&amp;#x26;dllName, L&quot;Plugin_61_82.dll&quot;);
            }
          }
          else
          {
            std::wstring::operator=(&amp;#x26;dllName, L&quot;Plugin_0_60.dll&quot;);
          }
          v8 = std::wstring::c_str(&amp;#x26;dllName);
          hMod = LoadLibraryW(v8);
          if ( hMod )
          {
            RunPlugin = (void (__fastcall *)(HWND__ *, int))GetProcAddress(hMod, &quot;RunPlugin&quot;);
            if ( RunPlugin )
            {
              RunPlugin_1 = (std::wstring *)RunPlugin;
              RunPlugin(hWnd, score);
            }
            else
            {
              MessageBoxW(hWnd, &amp;#x26;lpText_, &amp;#x26;lpCaption_, 0x10u);
            }
            FreeLibrary(hMod);
            std::wstring::~wstring(&amp;#x26;dllName);
          }
          else
          {
            RunPlugin_1 = std::operator+&amp;#x3C;wchar_t&gt;(&amp;#x26;result, &amp;#x26;Left, &amp;#x26;dllName);
            _Left = RunPlugin_1;
            std::operator+&amp;#x3C;wchar_t&gt;(&amp;#x26;v19, RunPlugin_1, Right);
            std::wstring::~wstring(&amp;#x26;result);
  ...something_else...
  return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我们发现了调用dll的关键函数：&lt;code&gt;RunPlugin&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;分别打开几个Plugin的该函数，发现不同的惊喜：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2FREADME_20251026220030342.Bv6ZWK8P.png&amp;#x26;w=972&amp;#x26;h=534&amp;#x26;f=webp&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;直接猜XOR，最后结果肯定是&lt;code&gt;whuctf{&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2FREADME_20251026220152409.Dt_aIglI.png&amp;#x26;w=1660&amp;#x26;h=476&amp;#x26;f=webp&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;不用说了，基础的换表base64，Cyberchef直接梭。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2FREADME_20251026220342220.BmaWq_bU.png&amp;#x26;w=986&amp;#x26;h=1006&amp;#x26;f=webp&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;你这是典型的RC4逻辑，RC4思维，RC4素质。&lt;/p&gt;
&lt;p&gt;分别解密后拼出完整flag：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;whuctf{I_w1ll_give_y0u_an_extr@_po1nt}&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;hajimi_player&lt;/h2&gt;
&lt;p&gt;使用FindCrypt发现了一些AES相关的东西：
&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2FREADME_20251025220535815.BUjpLLGp.png&amp;#x26;w=1238&amp;#x26;h=412&amp;#x26;f=webp&quot; alt=&quot;&quot;&gt;
&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2FREADME_20251025220644781.BDfYr_QZ.png&amp;#x26;w=1984&amp;#x26;h=970&amp;#x26;f=webp&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;询问AI有：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;函数 1：&lt;code&gt;sub_140012E50&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;作用：实现 AES-128 的密钥扩展 (Key Expansion)。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;概要说明：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;输入：16 字节主密钥（&lt;code&gt;a1&lt;/code&gt;）。&lt;/li&gt;
&lt;li&gt;输出：176 字节扩展密钥（&lt;code&gt;a2&lt;/code&gt;），即 11 轮 × 16 字节的轮密钥。&lt;/li&gt;
&lt;li&gt;内部逻辑：
&lt;ul&gt;
&lt;li&gt;拷贝前 16 字节为初始轮密钥。&lt;/li&gt;
&lt;li&gt;每 16 字节为一轮，执行：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;RotWord&lt;/code&gt;（循环左移 1 字节）；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SubWord&lt;/code&gt;（用 Rijndael S-box 替换每个字节）；&lt;/li&gt;
&lt;li&gt;首字节 XOR 上 Rcon（轮常数），并更新 Rcon；&lt;/li&gt;
&lt;li&gt;按 AES 规则生成新的 16 字节轮密钥。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;使用的表：&lt;code&gt;RijnDael_AES_LONG_14001DBE0&lt;/code&gt;（AES S-box）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;👉 &lt;strong&gt;简单说&lt;/strong&gt;：它把一个 16 字节的 AES 密钥展开成所有轮用的 176 字节密钥数据。&lt;/p&gt;
&lt;p&gt;函数 2：&lt;code&gt;sub_140013D70&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;作用：执行 AES 的 SubBytes 步骤（S-box 替换）。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;概要说明：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;输入：指向 16 字节数据块的指针（&lt;code&gt;a1&lt;/code&gt;）。&lt;/li&gt;
&lt;li&gt;对每个字节执行：&lt;code&gt;byte = SBOX[byte]&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;直接在原缓冲区中替换（就地操作），返回 16。&lt;/li&gt;
&lt;li&gt;同样使用表 &lt;code&gt;RijnDael_AES_LONG_14001DBE0&lt;/code&gt;（Rijndael S-box）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;👉 &lt;strong&gt;简单说&lt;/strong&gt;：它把 16 字节“状态矩阵”中的每个字节都通过 AES S-box 映射，属于 AES 加密的一个核心变换步骤。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;查找引用，发现了函数&lt;code&gt;sub_140012CA0&lt;/code&gt;：
&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2FREADME_20251025221220430.DZh1bljx.png&amp;#x26;w=1388&amp;#x26;h=1048&amp;#x26;f=webp&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;分析得出这是单块AES的加密实现，用GPT的话说就是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;这是单块 AES-128 加密的驱动函数——把 16 字节明文用 16 字节密钥加密成 16 字节密文（相当于 ECB 的单块操作）。流程就是标准 AES：初始轮密钥异或 → 9 个主轮（SubBytes→ShiftRows→MixColumns→AddRoundKey）→ 最后一轮（SubBytes→ShiftRows→AddRoundKey，不含 MixColumns）。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;顺着该函数的线索，观察行移位和列混淆和轮密钥加的相关函数：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;sub_140013A30：ShiftRows&lt;/li&gt;
&lt;li&gt;sub_140013390：MixColumns&lt;/li&gt;
&lt;li&gt;sub_140012C00：AddRoundKey（state XOR round key）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;发现全是标准实现。（想到了书记骂盘子的“都多少年了还看不出来AES”）&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2FREADME_20251025221839218.DuZXmGBR.png&amp;#x26;w=598&amp;#x26;h=500&amp;#x26;f=webp&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;全部更名后，想起了被PolyEncrypt支配的恐惧。&lt;/p&gt;
&lt;p&gt;根据该函数的引用，跳转到了&lt;code&gt;sub_140011990&lt;/code&gt;，这是一个登录对话框，输入用户名和密码。&lt;/p&gt;
&lt;p&gt;然而，我们发现了奇怪的函数！&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2FREADME_20251025222633178.CqDGl20X.png&amp;#x26;w=1570&amp;#x26;h=1030&amp;#x26;f=webp&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;根据函数签名，它长得很像加密函数，但又不是我们之前分析的AES_EncryptBlock。导航进去并尝试分析之。发现是一个类TEA实现。这里Trunk和跳转比较多就不贴出完整流程了，给一个重命名表，可自行检验：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;sub_140013E00 = TEA_EncryptBlock128_ECB
sub_140013EA0 = TEA_Encrypt64
sub_140011447 = TEA_Trunk_Wrapper
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;至此登录部分分析完毕，给出用户名和密码的解密脚本（解密需要的静态数据就不贴出了，很容易找到）。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;WHUCTF2025_新生赛/RE/hajimi_player via 🐍
❯ cat dec.py
# Requires: pip install pycryptodome
from Crypto.Cipher import AES
import struct

# Constants from .rdata
C1 = bytes.fromhex(
    &quot;F2 C1 8F 6E 89 18 46 70 DE E6 76 95 E7 BC 17 CB&quot;.replace(&quot; &quot;, &quot;&quot;))
C2 = bytes.fromhex(
    &quot;4D D5 DF FB 1A CA 76 E6 1E 22 5F 3E 57 58 F3 EB&quot;.replace(&quot; &quot;, &quot;&quot;))

# TEA key words (little-endian 32-bit words as in the binary)
k0 = 0x00000001
k1 = 0x00000002
k2 = 0x00000003
k3 = 0x00000004
KEY_WORDS = (k0, k1, k2, k3)

# TEA parameters observed in the binary
DELTA = 0x0D33B470  # custom delta from disassembly
ROUNDS = 32


def le_bytes_to_u32_pair(b8):
    &quot;&quot;&quot;Little-endian: first 4 bytes -&gt; v0 (low dword), next 4 -&gt; v1&quot;&quot;&quot;
    v0 = struct.unpack(&quot;&amp;#x3C;I&quot;, b8[0:4])[0]
    v1 = struct.unpack(&quot;&amp;#x3C;I&quot;, b8[4:8])[0]
    return v0, v1


def u32_pair_to_le_bytes(v0, v1):
    return struct.pack(&quot;&amp;#x3C;I&quot;, v0) + struct.pack(&quot;&amp;#x3C;I&quot;, v1)


def tea_decrypt_block64(v0, v1, k):
    &quot;&quot;&quot;Decrypt single 64-bit block that was encrypted with the variant seen in binary.&quot;&quot;&quot;
    k0, k1, k2, k3 = k
    mask32 = 0xFFFFFFFF
    # initial sum = delta * rounds mod 2^32
    sum_ = (DELTA * ROUNDS) &amp;#x26; mask32
    # run rounds in reverse
    for _ in range(ROUNDS):
        # reverse of:
        # v5 += (k3 + (v4&gt;&gt;5)) ^ (sum + v4) ^ (k2 + (v4&amp;#x3C;&amp;#x3C;4));
        # v4 += (k1 + (v5&gt;&gt;5)) ^ (sum + v5) ^ (k0 + (v5&amp;#x3C;&amp;#x3C;4));
        v1 = (v1 - (((k3 + ((v0 &gt;&gt; 5) &amp;#x26; mask32)) ^ ((sum_ + v0) &amp;#x26; mask32)
              ^ ((k2 + ((v0 &amp;#x3C;&amp;#x3C; 4) &amp;#x26; mask32)) &amp;#x26; mask32)) &amp;#x26; mask32)) &amp;#x26; mask32
        v0 = (v0 - (((k1 + ((v1 &gt;&gt; 5) &amp;#x26; mask32)) ^ ((sum_ + v1) &amp;#x26; mask32)
              ^ ((k0 + ((v1 &amp;#x3C;&amp;#x3C; 4) &amp;#x26; mask32)) &amp;#x26; mask32)) &amp;#x26; mask32)) &amp;#x26; mask32
        sum_ = (sum_ - DELTA) &amp;#x26; mask32
    return v0, v1


def tea_decrypt_128_ecb(cipher16, k):
    &quot;&quot;&quot;Decrypt 16-byte block that was encrypted as two TEA-64 encryptions (ECB on two halves).&quot;&quot;&quot;
    assert len(cipher16) == 16
    out = bytearray(16)
    for i in range(2):
        blk = cipher16[i*8:(i+1)*8]
        v0, v1 = le_bytes_to_u32_pair(blk)
        pv0, pv1 = tea_decrypt_block64(v0, v1, k)
        out[i*8:(i+1)*8] = u32_pair_to_le_bytes(pv0, pv1)
    return bytes(out)


def aes128_decrypt_block(cipher16, key16):
    assert len(cipher16) == 16 and len(key16) == 16
    cipher = AES.new(key16, AES.MODE_ECB)
    return cipher.decrypt(cipher16)


# Step 1: decrypt username block (TEA variant)
plain_user_block = tea_decrypt_128_ecb(C1, KEY_WORDS)
print(&quot;Username block (hex):&quot;, plain_user_block.hex())

# remove trailing zero padding to get ASCII username (zero-padded)
username = plain_user_block.rstrip(b&quot;\x00&quot;).decode(&apos;latin1&apos;, errors=&apos;replace&apos;)
print(&quot;Username:&quot;, repr(username))

# Step 2: decrypt password block using AES-128 with username-block as key
# The code uses the username block (16 bytes) as AES key directly.
plain_pass_block = aes128_decrypt_block(C2, plain_user_block)
print(&quot;Password block (hex):&quot;, plain_pass_block.hex())
password = plain_pass_block.rstrip(b&quot;\x00&quot;).decode(&apos;latin1&apos;, errors=&apos;replace&apos;)
print(&quot;Password:&quot;, repr(password))

WHUCTF2025_新生赛/RE/hajimi_player via 🐍
❯ python dec.py
Username block (hex): 68616a696d696e616d656c75646f6f6f
Username: &apos;hajiminameludooo&apos;
Password block (hex): 6d616e626f2331623265266562686a34
Password: &apos;manbo#1b2e&amp;#x26;ebhj4&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;获得用户名和密码。&lt;/p&gt;
&lt;p&gt;接下来根据窗口逻辑，顺着指针&lt;code&gt;dwNewLong_&lt;/code&gt;捋到函数&lt;code&gt;sub_140012480&lt;/code&gt;，发现是一个文件解密器的实现。GPT大人如是说：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;快速结论（一句话）
sub_140012480 是 Hajimi Player 的窗口过程：用户点击 “select your hajimi file” 会把路径放到全局 FileName；点击 “play” 会读取 GetWindowLongPtr(hWnd, GWLP_USERDATA)（也就是登录时存的 Destination —— username+password 拼接字符串），把它作为“密钥/密钥材料”传给 sub_14001110E（初始化/派生解密上下文），然后调用 sub_140011451 把读到的文件数据用该上下文进行解密/处理，最后把解密后数据指向全局 ::Block/::Size 以供播放。也就是说 Player 在播放前会对选中文件进行解密，解密密钥由窗口的 user-data（登录时的 username+password）来派生/生成。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;啊伟大的GPT大人！&lt;/p&gt;
&lt;p&gt;解密文件部分主要涉及的是&lt;code&gt;sub_14001110E&lt;/code&gt;和&lt;code&gt;sub_140011451&lt;/code&gt;，分析得知：&lt;/p&gt;
&lt;p&gt;...能得知什么，就一破RC4罢了。&lt;/p&gt;
&lt;p&gt;解密之：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# RC4 decrypt for Hajimi Player files
key = (b&quot;hajiminameludooo&quot; + b&quot;manbo#1b2e&amp;#x26;ebhj4&quot;)  # username + password

def rc4_ksa(key: bytes):
    S = list(range(256))
    j = 0
    for i in range(256):
        j = (j + S[i] + key[i % len(key)]) &amp;#x26; 0xFF
        S[i], S[j] = S[j], S[i]
    return S, 0, 0  # S, i, j

def rc4_prga(S, i, j):
    i = (i + 1) &amp;#x26; 0xFF
    j = (j + S[i]) &amp;#x26; 0xFF
    S[i], S[j] = S[j], S[i]
    K = S[(S[i] + S[j]) &amp;#x26; 0xFF]
    return K, S, i, j

def rc4_crypt(data: bytes, key: bytes) -&gt; bytes:
    S, i, j = rc4_ksa(key)
    out = bytearray(len(data))
    for n, b in enumerate(data):
        k, S, i, j = rc4_prga(S, i, j)
        out[n] = b ^ k
    return bytes(out)

inp = &quot;video.hajimi&quot;   # 改成你的文件名
outp = &quot;output.bin&quot;

with open(inp, &quot;rb&quot;) as f:
    enc = f.read()

dec = rc4_crypt(enc, key)

with open(outp, &quot;wb&quot;) as f:
    f.write(dec)

# 粗略看看是否像明文
head = dec[:64]
print(&quot;Decrypted head (hex):&quot;, head.hex())
try:
    print(&quot;ASCII head:&quot;, head.decode(&quot;latin1&quot;))
except:
    pass
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;通过file命令查阅生成的基密文件后发现是个MP4，遂直接mpv播放之。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2FREADME_20251025230119858.Cx2KKG81.png&amp;#x26;w=2880&amp;#x26;h=1800&amp;#x26;f=webp&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;WHUCTF{h@jimin@meLud0_axiga@xiii}&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;byd气笑了。&lt;/p&gt;
&lt;h2&gt;Baby_HeavenGate&lt;/h2&gt;
&lt;p&gt;众所周知，Heaven&apos;s Gate是一种在32位程序环境下执行64位代码的混淆技术。
&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2FREADME_20251026220840806.Dnbj68GK.png&amp;#x26;w=1048&amp;#x26;h=656&amp;#x26;f=webp&quot; alt=&quot;&quot;&gt;
于是，当我们看到这个JUMPOUT时，我们就知道要切到反汇编界面进行查看了。
&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2FREADME_20251026222545342.DteT61yp.png&amp;#x26;w=1358&amp;#x26;h=154&amp;#x26;f=webp&quot; alt=&quot;&quot;&gt;
&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2FREADME_20251026222604147.YCA364Wx.png&amp;#x26;w=1136&amp;#x26;h=788&amp;#x26;f=webp&quot; alt=&quot;&quot;&gt;
这里出现了牢门经典的&lt;code&gt;call $+5&lt;/code&gt;、&lt;code&gt;retf&lt;/code&gt;等汇编指令。&lt;/p&gt;
&lt;p&gt;进门发现一个简单的异或：
&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2FREADME_20251026222656335.C1KDmrQm.png&amp;#x26;w=1254&amp;#x26;h=256&amp;#x26;f=webp&quot; alt=&quot;&quot;&gt;
继续往下分析，又发现了经典牢门：
&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2FREADME_20251026220950460.BNYmScRq.png&amp;#x26;w=1596&amp;#x26;h=370&amp;#x26;f=webp&quot; alt=&quot;&quot;&gt;
&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F%E6%97%A0%E6%A0%87%E9%A2%98.CbG0QRba.png&amp;#x26;w=1684&amp;#x26;h=962&amp;#x26;f=webp&quot; alt=&quot;&quot;&gt;
分析可得，这里会把用户输入送入&lt;code&gt;sub_402000&lt;/code&gt;函数中。
当然，如果你实现没有执行某一步骤，你看到的可能不是正经的sub_402000，而是一些奇怪的东西。
&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2FREADME_20251026222013694.DreyXfKC.png&amp;#x26;w=1622&amp;#x26;h=742&amp;#x26;f=webp&quot; alt=&quot;&quot;&gt;
其实这里出题人已经通过区段名给了我们提示：这里是Heaven&apos;s Gate跳转到的64位代码处。我们通过IDA的Edit-&gt; Segments -&gt; Edit Segment将x64区段改为64位：
&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2FREADME_20251026222357102.0SlA7gbw.png&amp;#x26;w=1622&amp;#x26;h=742&amp;#x26;f=webp&quot; alt=&quot;&quot;&gt;
&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2FREADME_20251026222405556.CnA8wmDU.png&amp;#x26;w=1782&amp;#x26;h=958&amp;#x26;f=webp&quot; alt=&quot;&quot;&gt;
核心的异或解密逻辑就搞定了。&lt;/p&gt;
&lt;p&gt;因此，写出解密脚本如下：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# 加密数据
encrypted = [
    0x09, 0x2e, 0x27, 0x36, 0x39, 0x01, 0x65, 0x35, 0x71, 0x05,
    0x28, 0x20, 0x1d, 0x28, 0x23, 0x32, 0x34, 0x1d, 0x24, 0x61,
    0x27, 0x73, 0x05, 0x34, 0x36, 0x26, 0x12
]

# &quot;Heaven&apos;s Gate&quot; 密钥 (13个字符)
key = b&quot;Heaven&apos;s Gate&quot;

# 第一步：逆向第二步XOR（使用&quot;Heaven&apos;s Gate&quot;作为轮转密钥）


def get_key_char(index):
    return key[index % len(key)]

# 第二步：逆向XOR_Encrypt


def decrypt_xor_encrypt(encrypted_byte):
    for original in range(256):
        if encrypted_byte == (original + 39 - 2 * (original &amp;#x26; 0x27)) &amp;#x26; 0xFF:
            return original
    return None


# 完整解密
decrypted_step1 = [encrypted[i] ^ get_key_char(i) for i in range(27)]
decrypted_step2 = [decrypt_xor_encrypt(b) for b in decrypted_step1]

flag = &apos;&apos;.join(chr(b) for b in decrypted_step2)
print(&quot;解密结果:&quot;, flag)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;解密结果: &lt;code&gt;flag{Heavens_Gate_mastered}&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;天才侦探&lt;/h2&gt;
&lt;p&gt;打开发现奇怪的&lt;code&gt;setjmp&lt;/code&gt;函数：
&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2FREADME_20251026225644015._Bx453g-.png&amp;#x26;w=528&amp;#x26;h=172&amp;#x26;f=webp&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;带着对它的疑惑，先看看别处的逻辑🤔&lt;/p&gt;
&lt;p&gt;很轻松地，我们可以看出XOR和XXTEA_Encrypt加密的线索。&lt;/p&gt;
&lt;p&gt;然而，XXTEA_Encrypt中部出现了疑似花指令的诡异跳转。切到汇编：
&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2FREADME_20251026230556014.sW8LzyxM.png&amp;#x26;w=676&amp;#x26;h=270&amp;#x26;f=webp&quot; alt=&quot;&quot;&gt;
&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2FREADME_20251026230733133.DyIVSuen.png&amp;#x26;w=1874&amp;#x26;h=464&amp;#x26;f=webp&quot; alt=&quot;&quot;&gt;
经典的跳转到+1位置，在中间藏一个恶心人的幽灵call。NOP掉即可。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;__int64 __fastcall XXTEA_Encrypt(char *Buf1, int n10, char *Can_y0u_catch_me)
{
    ...something...
  if ( n10 &amp;#x3C;= 1 )
  {
    if ( n10 &amp;#x3C; -1 )
    {
      v20 = -n10;
      v10 = 52 / -n10 + 6;
      v14 = 1131796 * v10;
      v19 = *(_DWORD *)Buf1;
      do
      {
        v8 = (v14 &gt;&gt; 2) &amp;#x26; 3;
        for ( i = v20 - 1; i; --i )
        {
          v16 = *(_DWORD *)&amp;#x26;Buf1[4 * (i - 1)];
          v5 = &amp;#x26;Buf1[4 * i];
          *(_DWORD *)v5 -= ((v19 ^ v14) + (v16 ^ *(_DWORD *)&amp;#x26;Can_y0u_catch_me[4 * (v8 ^ i &amp;#x26; 3)]))
                         ^ (((4 * v19) ^ (v16 &gt;&gt; 5)) + ((v19 &gt;&gt; 3) ^ (16 * v16)));
          v19 = *(_DWORD *)v5;
        }
        v17 = *(_DWORD *)&amp;#x26;Buf1[4 * v20 - 4];
        *(_DWORD *)Buf1 -= (((4 * v19) ^ (v17 &gt;&gt; 5)) + ((v19 &gt;&gt; 3) ^ (16 * v17)))
                         ^ ((v19 ^ v14) + (v17 ^ *(_DWORD *)&amp;#x26;Can_y0u_catch_me[4 * v8]));
        v19 = *(_DWORD *)Buf1;
        v14 -= 1131796;
        --v10;
      }
      while ( v10 );
    }
  }
  else
  {
    v9 = 52 / n10 + 6;
    v13 = 0;
    v15 = *(_DWORD *)&amp;#x26;Buf1[4 * n10 - 4];
    do
    {
      v13 += 0x114514;
      v7 = (v13 &gt;&gt; 2) &amp;#x26; 3;
      for ( j = 0; j &amp;#x3C; n10 - 1; ++j )
      {
        v18 = *(_DWORD *)&amp;#x26;Buf1[4 * j + 4];
        v3 = &amp;#x26;Buf1[4 * j];
        *(_DWORD *)v3 += ((v18 ^ v13) + (v15 ^ *(_DWORD *)&amp;#x26;Can_y0u_catch_me[4 * (v7 ^ j &amp;#x26; 3)]))
                       ^ (((4 * v18) ^ (v15 &gt;&gt; 5)) + ((v18 &gt;&gt; 3) ^ (16 * v15)));
        v15 = *(_DWORD *)v3;
      }
      v4 = &amp;#x26;Buf1[4 * n10 - 4];
      *(_DWORD *)v4 += ((*(_DWORD *)Buf1 ^ v13) + (v15 ^ *(_DWORD *)&amp;#x26;Can_y0u_catch_me[4 * (v7 ^ j &amp;#x26; 3)]))
                     ^ (((4 * *(_DWORD *)Buf1) ^ (v15 &gt;&gt; 5)) + ((*(_DWORD *)Buf1 &gt;&gt; 3) ^ (16 * v15)));
      v15 = *(_DWORD *)v4;
      --v9;
    }
    while ( v9 );
  }
  return 0xFFFFFFFF / 0;                        // 这里会触发除0异常，抛出浮点数异常然后触发longjmp
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然而，在XXTEA加密的末尾，我们发现了奇怪的除0行为！
&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2FREADME_20251026230005029.B_6e65tG.png&amp;#x26;w=592&amp;#x26;h=206&amp;#x26;f=webp&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;这里非常不对劲，除0会引发报错。猜测这里的报错是有意为之，我们找到错误处理函数&lt;code&gt;Function&lt;/code&gt;：
&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2FREADME_20251026230059449.qmlzDflD.png&amp;#x26;w=748&amp;#x26;h=256&amp;#x26;f=webp&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;一个永真跳转，先执行sub_4015F0，再执行longjmp_w。到这里我们明白了上面的setjmp究竟起何作用：一开始Buf是0，执行XXTEA加密，然后XXTEA加密末尾通过除零触发Function，修改Buf为1并跳到setjmp处，使程序进入XOR_Encrypt的分支。&lt;/p&gt;
&lt;p&gt;于是，问题就在于：sub_4015F0()做了什么。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2FREADME_20251026230313331.DAYFNeuW.png&amp;#x26;w=998&amp;#x26;h=566&amp;#x26;f=webp&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;分析各种跳转发现，这里又是一个异或。&lt;/p&gt;
&lt;p&gt;于是理清了所有加密步骤，写出解密脚本：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;import struct

# 密文数据 (从 Cipher)
cipher_bytes = bytes([
    0x8A, 0xFF, 0x4B, 0x28, 0xF8, 0x79, 0x53, 0xA8,
    0xFA, 0xE0, 0x9B, 0x21, 0x9D, 0xAB, 0x79, 0x01,
    0xCD, 0xD7, 0x49, 0xA5, 0x7A, 0x05, 0x0B, 0x94,
    0xF5, 0xD8, 0xBA, 0xD9, 0x4B, 0x26, 0x3E, 0x0C,
    0x8F, 0x91, 0x70, 0x41, 0x05, 0xE9, 0x40, 0xD7
])

# sub_4015F0 中使用的 cipher 数组 (从 unk_49F020 提取，按 DWORD 存储)
unk_49F020 = [
    0x0000003E, 0x00000034, 0x000000BE, 0x000000D6,
    0x00000000, 0x0000008F, 0x000000C8, 0x00000006,
    0x00000008, 0x000000E2, 0x000000F9, 0x00000005,
    0x000000FD, 0x000000E0, 0x0000003A, 0x000000D0,
    0x0000000A, 0x000000C2, 0x000000D7, 0x000000D4,
    0x0000000C, 0x0000001E, 0x00000047, 0x0000004D,
    0x0000009D, 0x00000020, 0x000000F9, 0x00000095,
    0x0000009F, 0x0000000F, 0x000000E8, 0x00000075,
    0x000000CA, 0x000000F6, 0x00000096, 0x00000096,
    0x0000007B, 0x00000028, 0x0000001B, 0x000000D1
]

# XXTEA 密钥
xxtea_key = b&quot;Can_y0u_catch_me&quot;

# XOR 密钥
xor_key = b&quot;Siesta&quot;


def xxtea_decrypt(v, k):
    &quot;&quot;&quot;XXTEA 解密算法&quot;&quot;&quot;
    def MX(sum, y, z, p, e, k):
        return ((z &gt;&gt; 5 ^ y &amp;#x3C;&amp;#x3C; 2) + (y &gt;&gt; 3 ^ z &amp;#x3C;&amp;#x3C; 4)) ^ ((sum ^ y) + (k[p &amp;#x26; 3 ^ e] ^ z))

    n = len(v)
    rounds = 6 + 52 // n
    sum = (rounds * 0x114514) &amp;#x26; 0xFFFFFFFF
    y = v[0]

    while rounds &gt; 0:
        e = (sum &gt;&gt; 2) &amp;#x26; 3
        for p in range(n - 1, 0, -1):
            z = v[p - 1]
            v[p] = (v[p] - MX(sum, y, z, p, e, k)) &amp;#x26; 0xFFFFFFFF
            y = v[p]
        z = v[n - 1]
        v[0] = (v[0] - MX(sum, y, z, 0, e, k)) &amp;#x26; 0xFFFFFFFF
        y = v[0]
        sum = (sum - 0x114514) &amp;#x26; 0xFFFFFFFF
        rounds -= 1

    return v


def decrypt():
    # 步骤1: 逆 XOR_Encrypt (与 &quot;Siesta&quot; 异或)
    data = bytearray(cipher_bytes)
    for i in range(40):
        data[i] ^= xor_key[i % len(xor_key)]

    print(&quot;Step 1 - 逆 XOR_Encrypt:&quot;)
    print(&apos; &apos;.join(f&apos;{b:02x}&apos; for b in data))

    # 步骤2: 逆 sub_4015F0 ((data ^ cipher[i]) - 1)
    for i in range(40):
        # 原加密: Input[i] = (Input[i] + 1) ^ cipher[i]
        # 逆运算: Input[i] = (data[i] ^ cipher[i]) - 1
        data[i] = ((data[i] ^ (unk_49F020[i] &amp;#x26; 0xFF)) - 1) &amp;#x26; 0xFF

    print(&quot;\nStep 2 - 逆 sub_4015F0:&quot;)
    print(&apos; &apos;.join(f&apos;{b:02x}&apos; for b in data))

    # 步骤3: XXTEA 解密
    # 将字节数组转换为 32 位整数数组（小端序）
    v = list(struct.unpack(&apos;&amp;#x3C;10I&apos;, bytes(data)))

    # 将密钥转换为 32 位整数数组
    k = list(struct.unpack(&apos;&amp;#x3C;4I&apos;, xxtea_key[:16]))

    # 执行 XXTEA 解密
    decrypted = xxtea_decrypt(v, k)

    # 转换回字节
    result = struct.pack(&apos;&amp;#x3C;10I&apos;, *decrypted)

    print(&quot;\nStep 3 - XXTEA 解密:&quot;)
    print(&apos; &apos;.join(f&apos;{b:02x}&apos; for b in result))

    # 尝试解析为字符串
    try:
        flag = result.decode(&apos;ascii&apos;, errors=&apos;ignore&apos;)
        print(f&quot;\n解密结果: {flag}&quot;)
        return flag
    except:
        print(&quot;\n解密结果 (hex):&quot;, result.hex())
        return result


if __name__ == &quot;__main__&quot;:
    print(&quot;=&quot; * 60)
    print(&quot;开始解密...&quot;)
    print(&quot;=&quot; * 60)
    print()

    result = decrypt()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;解密结果: &lt;code&gt;WHUCTF{U_ar3_as_pr0f3ssional_as_siesta!}&lt;/code&gt;&lt;/p&gt;
&lt;h1&gt;感想&lt;/h1&gt;
&lt;p&gt;本次迎新赛拿到了个总榜第二。当然还是感谢学长们不杀之恩。&lt;/p&gt;
&lt;p&gt;第一天下午去了Deepin的WHLUG，没写题，第二天运动会+百团大战+游园会，算是玩爽了，也没怎么写题，我忏悔喵。&lt;/p&gt;
&lt;p&gt;最后，逆向工程这个方向，从迎新赛打到moe，从NewStar打到ILoveCTF，甚至在强网杯还干出来一题。再回头看看迎新赛，虽不能说轻舟已过万重山，至少也翻过了一两重吧。&lt;/p&gt;</content:encoded><h:img src="/_astro/cover.DqTfBCzW.png"/><enclosure url="/_astro/cover.DqTfBCzW.png"/></item><item><title>中气爱讲座记录</title><link>https://crisq.top/blog/geoscience_cafe_251017</link><guid isPermaLink="true">https://crisq.top/blog/geoscience_cafe_251017</guid><description>晚上听的一场由WHU-GeoScienceCafe举办的分享会</description><pubDate>Fri, 17 Oct 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;气象科普最前线&lt;/h1&gt;
&lt;h2&gt;结缘科普与科普的历程&lt;/h2&gt;
&lt;p&gt;中气爱连续存在了 14~15 年（刚上初中时就创立了）。&lt;/p&gt;
&lt;p&gt;关心天气：一路南下，今年的秋好像跟往年不太一样。整个天永远是阴沉的，雨很大。（？为何呢）&lt;/p&gt;
&lt;p&gt;来自广东潮汕，自小学二年级就开始关注气象。潮汕作为沿海地区，每年夏天有各种台风侵袭。&quot;珍珠&quot;侵袭当晚，台风裹挟的雨像针一样非常吓人------大自然并不温和。&lt;/p&gt;
&lt;p&gt;学生时代痴迷台风，不止喜欢表面，还会关注机理------台风为何发生？台风如何行动？台风为何可以预测？......&lt;/p&gt;
&lt;p&gt;结缘台风论坛，中气爱的&quot;发源地&quot;。创作了大量优质的气象科普内容。开始阅读大气科学的大学教材。午休时捧着《天气学原理与方法》。==看不懂也要看。（这一点想起了小学时热爱黑客文化的我）==&lt;/p&gt;
&lt;p&gt;正值 2011 年微博出现，&quot;中气爱&quot;开始正式更新，早期的&quot;140 字&quot;科普训练------至今共创作微博 42760 则。（这一点和当今的短视频&quot;感觉&quot;是一脉相承的）&lt;/p&gt;
&lt;p&gt;2015 开办微信公众号，几天一次的&quot;天气沙盘推演&quot;（意图塑造战场般紧张刺激的氛围）==造就了中气爱的独特文风==，至今已创作文章 1992 篇。&lt;/p&gt;
&lt;p&gt;2022 年正式开始视频创作，从图文到视频的&quot;惊险一跃&quot;。&lt;/p&gt;
&lt;p&gt;2022 年并非规划出来，从 2020 就开始思考尝试------第一个视频只有 3 分钟，收获了 3000 的播放量。紧接着创作第二条，只有 700~800 人看。突然有一天（2022 台风活跃）播放量上去了。==（厚积薄发）==&lt;/p&gt;
&lt;p&gt;在探索中形成合适的风格，而非尝试事先规划。&lt;/p&gt;
&lt;p&gt;从而造就了如今的中气爱------全网 1500 万粉丝，团队运营了内容账号矩阵（中气爱、中气爱怎么说、科普航、中气爱科技新知...）&lt;/p&gt;
&lt;h2&gt;科普心得&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;中气爱的内生动力：对天气现象的天然、强烈、持久的兴趣。（科普也存在&quot;外部性&quot;&lt;a href=&quot;%E5%A4%96%E9%83%A8%E6%80%A7%E6%98%AF%E6%8C%87%E4%B8%80%E4%B8%AA%E7%BB%8F%E6%B5%8E%E4%B8%BB%E4%BD%93%E7%9A%84%E8%A1%8C%E4%B8%BA%E5%AF%B9%E5%85%B6%E4%BB%96%E4%BA%BA%E4%BA%A7%E7%94%9F%E4%BA%86%E5%BD%B1%E5%93%8D%EF%BC%8C%E4%BD%86%E5%B9%B6%E4%B8%8D%E4%B8%BA%E6%AD%A4%E6%89%BF%E6%8B%85%E7%9B%B8%E5%BA%94%E7%9A%84%E6%88%90%E6%9C%AC%E6%88%96%E8%8E%B7%E5%BE%97%E7%9B%B8%E5%BA%94%E6%94%B6%E7%9B%8A&quot;&gt;^1&lt;/a&gt;）虽然兴趣方向不同，但会有&quot;让更多人知道&quot;的共同乐趣。&lt;/li&gt;
&lt;li&gt;因热爱而探索，自发创作，业务训练，技术研发...... 从线上到线下，实地追击台风。（从纯粹的热爱转变到主动的实践）&lt;/li&gt;
&lt;li&gt;干一行爱一行（当你想持之以恒的创作，没有受众的支持很难坚持）&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;科普语言的选择&lt;/h3&gt;
&lt;p&gt;学术语言，业务语言，网络语言------三者有联系，更有区别。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;台风&quot;格美&quot;打转，如何解读？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;学术：多专业名词，侧重客观描述，复杂且难以理解
业务：详细描述，中心不明确，注意力容易跑偏。&lt;/p&gt;
&lt;p&gt;探索网络语言------观众最希望听什么？
==不感兴趣&quot;为什么&quot;，但关心&quot;怎么样, 有何影响&quot;&lt;a href=&quot;%E5%B0%A4%E5%85%B6%E6%98%AF%22%E5%AF%B9%E6%88%91%E7%9A%84%E7%94%9F%E6%B4%BB%E6%9C%89%E4%BD%95%E5%BD%B1%E5%93%8D%22&quot;&gt;^2&lt;/a&gt;。例如：&quot;对此&lt;strong&gt;不少朋友感到困惑，甚至害怕&lt;/strong&gt;。&lt;strong&gt;有人说&lt;/strong&gt;格美要掉头去日本韩国了，不会再登陆我国了；&lt;strong&gt;还有人说&lt;/strong&gt;格美要绕开台湾，直接一手登陆福建了。这两种说法&lt;strong&gt;都不正确&lt;/strong&gt;，由于 xxx 山脉存在，扰乱台风环流，xxx，&lt;strong&gt;这是正常的&lt;/strong&gt;。&quot;。&lt;/p&gt;
&lt;p&gt;做科普时尽量避免急切地讲&quot;为什么&quot;，要先抛出一个不那么&quot;科普&quot;的问题，让受众驻足停留个几秒钟，再不经意穿插科普知识点。（用故事的糖衣包裹枯燥无味的科学知识）&lt;/p&gt;
&lt;h3&gt;在坚持&quot;科&quot;的同时，尽可能&quot;普&quot;&lt;/h3&gt;
&lt;p&gt;三个例子
&quot;热带扰动&quot;：专业性，晦涩性，学术性，专注&quot;机理&quot;。替换成&quot;台风胚胎&quot;后，让观众理解：热带扰动是台风的前身，是其前置条件，专注&quot;联系&quot;。（而且是与受众感兴趣的元素有联系）&lt;/p&gt;
&lt;p&gt;&quot;台风外围下沉气流&quot;：受众关心&quot;台风来之前为何如此热？&quot;，于是替换成&quot;空调外机&quot;：台风中心在制冷，能量往外抛就是&quot;空调外机&quot;------诙谐，但尽可能捕捉气象背后的科学原理。&lt;/p&gt;
&lt;p&gt;&quot;各种东西&quot;：不列举长串名词，而是以诙谐的用法概称之，一方面直观强调严重性，一方面可以引起对&quot;各种东西&quot;好奇的观众对气象知识的兴趣。&lt;/p&gt;
&lt;p&gt;（重要的不是比喻这一手法，而是往什么方向比喻）&lt;/p&gt;
&lt;h3&gt;在长期科普中形成科普直觉&lt;/h3&gt;
&lt;p&gt;对&lt;strong&gt;大众关注&lt;/strong&gt;的热点，痛点问题的&lt;strong&gt;捕捉能力和阐释能力&lt;/strong&gt;。迅速确定选题，分析呈现模式（故事片的手法，呈现大量实况）。同时要关注&lt;strong&gt;发布时间&lt;/strong&gt;：高温稍稍降低，此时人们关切是否还会高温，于是及时推出，回应关切。&lt;/p&gt;
&lt;h3&gt;科普和科研紧密融合&lt;/h3&gt;
&lt;p&gt;科普成果成为了科研论文的素材。科研向公众号向公众提供专业前沿科普内容。&lt;/p&gt;
&lt;p&gt;AI 出现后，其完全不依赖任何物理公式，而是一个纯涌现的过程的特性很值得分析。趁此社会热点，抓住时机科普（甚至训练了自己的 AI 气象预测模型坤舆并对其原理进行科普）。==当把这方面内容讲给他人听，反而更有利于科研灵感的产生，加深对科研内容的理解==。科普与科研并不矛盾。&lt;/p&gt;
&lt;h2&gt;成就感是科普的常见驱动力&lt;/h2&gt;
&lt;p&gt;&quot;有时候学霸的讲解比老师更靠谱&quot;------&lt;strong&gt;将知识给别人讲懂，是一种成就感。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;随着科普，另一个很重要的意义涌现------以郑州 7.20 暴雨为例，团队微博小编及时关注，发了很多微博。但后来发生的事情远超预料。
&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2Fcanva.PjUeA3Vq.jpg&amp;#x26;w=1137&amp;#x26;h=523&amp;#x26;f=webp&quot; alt=&quot;特大暴雨纪实&quot;&gt;&lt;/p&gt;
&lt;p&gt;当天的郑州雨量直接破了纪录。团队意识到这样的降雨量肯定伴有意外事件发生，于是积极提醒，一天发了五十条微博提醒大家关注和警惕。事件结束后，观众纷纷发来感谢------&lt;strong&gt;让更多的人了解科学，是一种责任感。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;单对单地讲气象不一定会让人感兴趣，但正如&lt;strong&gt;大数定律&lt;/strong&gt;所说：跟大量受众传播时，一定会有不少人会从科普中意识到自己对气象的热爱，从而对社会产生益处。&lt;/p&gt;
&lt;h2&gt;气候变暖面前，我们能做什么&lt;/h2&gt;
&lt;p&gt;低碳环保肯定正确，但每天提只会让人枯燥。中气爱的角度是：气候变化是一个事实，让所有人意识到气候变暖离我们并不远。&lt;/p&gt;
&lt;p&gt;每天绑架别人说&quot;你不能开车，要公共交通，你不能开空调......&quot;并不现实，但一方面可以通过长久地科普让人们潜意识中加深对气候变化的印象，一方面介绍大气科学前沿的研究者，让人们知道这些知识非常重要，从而帮助公众建立对于大气科学的兴趣，培养接力者。&lt;/p&gt;
&lt;p&gt;中气爱的口号之一：让大气科学广为人知。&lt;/p&gt;
&lt;h2&gt;提问时间&lt;/h2&gt;
&lt;h3&gt;如何平衡科普、科研与生活的关系&lt;/h3&gt;
&lt;p&gt;其实这是一个很难的问题，大家都会觉得时间不够用。要更多地利用碎片时间。整块的时间拿来做正事（连续的时间才能做更好的科研），零碎的时间用于科普（科研前画个半小时关注一下气候变化过程，创作微博之类）。注重劳逸结合，好好生活。&lt;/p&gt;
&lt;h3&gt;如何在专业课学经济时还能保持对气象的高水平认知&lt;/h3&gt;
&lt;p&gt;中气爱不做预测，只是把气象台的预测用一种通俗易懂的方式说出来。&lt;/p&gt;
&lt;p&gt;对于气象知识的积累是从初中开始持之以恒的，每天花个半小时，积少成多，能维持对气象的认知。归根结底还是如何协调安排自己的时间。明确主业，利用零碎时间维持大气方向知识量。&lt;/p&gt;
&lt;h3&gt;遇到负面反馈的观众，如何看待和应对&lt;/h3&gt;
&lt;p&gt;相信绝大多数观众发心是善意的，&quot;如果...... 的话，会更好&quot;。欣然接受，视为一种鞭策。&lt;/p&gt;</content:encoded><h:img src="/_astro/cover.7I99uFrn.webp"/><enclosure url="/_astro/cover.7I99uFrn.webp"/></item><item><title>使用 Typst 渲染数学公式</title><link>https://crisq.top/blog/test_typst</link><guid isPermaLink="true">https://crisq.top/blog/test_typst</guid><description>测试使用 Typst 渲染数学公式</description><pubDate>Wed, 15 Oct 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;原理&lt;/h2&gt;
&lt;p&gt;尝试使用 &lt;a href=&quot;https://github.com/Myriad-Dreamin/astro-typst&quot;&gt;astro-typst&lt;/a&gt; 渲染数学公式。&lt;/p&gt;
&lt;p&gt;笑死，完全用不了，样式也是乱的，目录也是乱的，渲染也是乱的。&lt;/p&gt;
&lt;p&gt;于是使用 rehype-typst，并大量定制主题样式，有了现在这个勉强可以接受的渲染方案。这样今后我 Obsidian 上的数学笔记就能同步过来了。&lt;/p&gt;
&lt;p&gt;参考了博主 &lt;a href=&quot;https://hanwen.io/zh/posts/use_typst_for_math_in_blog/&quot;&gt;huawen&lt;/a&gt; 的方案，在此致谢。&lt;/p&gt;
&lt;p&gt;如果只需要渲染 Typst Math，装个rehype-typst后直接写就行了。但我遇到了三个问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;明暗页面总有一个会吃掉Typst的文字&lt;/li&gt;
&lt;li&gt;内联公式总是会自己换行。&lt;/li&gt;
&lt;li&gt;TOC识别元素时会将渲染出的svg里的标题元素渲染成目录项&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;经过和 AI 的~~对骂~~探讨，得出了修改方法&lt;/p&gt;
&lt;h3&gt;解决方案与修改内容&lt;/h3&gt;
&lt;h4&gt;1. 创建自定义Rehype插件：&lt;code&gt;rehype-filter-svg-headings.ts&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;问题&lt;/strong&gt;：TOC会识别Typst生成的SVG内部的&lt;code&gt;h5:div&lt;/code&gt;元素作为标题&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解决方案&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;创建了&lt;code&gt;src/plugins/rehype-filter-svg-headings.ts&lt;/code&gt;插件&lt;/li&gt;
&lt;li&gt;检测并过滤SVG内部的命名空间标题元素（&lt;code&gt;h5:div&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;在构建时自动移除这些内部标题，防止它们出现在目录中&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;关键代码&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;// 检测SVG内部的标题元素
const isHeading =
  node.tagName &amp;#x26;&amp;#x26;
  (/^h[1-6]$/.test(node.tagName) || // 标准HTML标题
    node.tagName.includes(&apos;h5:&apos;) || // 命名空间标题如 h5:div
    classNameStr.includes(&apos;tsel&apos;)) // Typst选择元素
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;2. 优化CSS样式：&lt;code&gt;src/assets/styles/app.css&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;问题1&lt;/strong&gt;：内联公式总是换行显示&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解决方案&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;为段落内的Typst SVG添加内联显示样式&lt;/li&gt;
&lt;li&gt;优化垂直对齐和大小缩放&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;/* 行内公式样式 */
p .typst-doc,
p svg.typst-doc {
  display: inline !important;
  vertical-align: -0.3em !important;
  margin: 0 0.1em !important;
  max-height: 1.4em !important;
  transform: scale(1.15) !important;
  transform-origin: 0 0.5em !important;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;问题2&lt;/strong&gt;：块级公式大小异常&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解决方案&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;确保块级公式不受行内样式影响&lt;/li&gt;
&lt;li&gt;保持块级公式的原始大小&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;/* 块级公式 - 不受样式影响 */
.typst-doc {
  display: block;
  max-width: 100%;
  height: auto;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;问题3&lt;/strong&gt;：主题切换时Typst公式显示异常&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解决方案&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;添加JavaScript控制的深色模式支持&lt;/li&gt;
&lt;li&gt;使用CSS滤镜实现颜色反转&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;/* JavaScript控制的深色模式 */
html.dark svg.typst-doc {
  filter: invert(100%) sepia(0%) saturate(367%) hue-rotate(19deg) brightness(105%) contrast(101%) !important;
}

/* 浅色模式重置滤镜 */
html:not(.dark) svg.typst-doc {
  filter: none !important;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;3. 配置Astro插件&lt;/h4&gt;
&lt;p&gt;在&lt;code&gt;astro.config.ts&lt;/code&gt;中配置了自定义插件：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;// 添加自定义rehype插件
rehypePlugins: [
  // ... 其他插件
  rehypeFilterSvgHeadings
]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;最终效果&lt;/h3&gt;
&lt;p&gt;经过这些修改，现在Typst数学公式能够：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;✅ 行内公式正确显示在行内，不换行&lt;/li&gt;
&lt;li&gt;✅ 块级公式保持原始大小和块级显示&lt;/li&gt;
&lt;li&gt;✅ TOC只显示真正的文章标题，不包含数学公式字符&lt;/li&gt;
&lt;li&gt;✅ 在深色/浅色主题切换时正确显示&lt;/li&gt;
&lt;li&gt;✅ 支持复杂的数学表达式和矩阵&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;大部分代码使用 Cline + DeepSeek V3.2 完成，感谢Vibe Coding救我等不会前端的小白于水火。&lt;/p&gt;
&lt;h2&gt;简单公式示例&lt;/h2&gt;
&lt;p&gt;这是一个行内公式示例: $f(x) = x^2$ 看起来不错的。&lt;/p&gt;
&lt;p&gt;而这里就可以接下一行了&lt;/p&gt;
&lt;p&gt;这里是再下一行&lt;/p&gt;
&lt;p&gt;$$
because sum_(i=1)^(16)f(i) = 5 \ therefore cases(x^2 + 2x + 1 = 6, x - 5 =7)
$$&lt;/p&gt;
&lt;p&gt;行间公式也能正常显示&lt;/p&gt;
&lt;h2&gt;矩阵与向量&lt;/h2&gt;
&lt;p&gt;$$
mat(1+lambda,1,1, 0; 1,1+lambda,1,3; 1,1,1+lambda,lambda) -&gt; mat(1,1+lambda,1,3; 0,-lambda,lambda,lambda-3; 0,0,-lambda(lambda+3),(lambda+3)(1-lambda); delim: &quot;(&quot;)
$$&lt;/p&gt;
&lt;h2&gt;渲染一段完整的数学笔记&lt;/h2&gt;
&lt;p&gt;证明：&lt;/p&gt;
&lt;p&gt;(1).&lt;/p&gt;
&lt;p&gt;$$
&quot;要证：&quot; forall epsilon &gt; 0, exists delta &gt; 0, forall 0 &amp;#x3C; |x - 1| &amp;#x3C; delta , |2x -2|&amp;#x3C;epsilon
\ &quot;取：&quot; delta = epsilon/4 , &quot;则 &quot; 0&amp;#x3C; |x-1| &amp;#x3C; epsilon/4 -&gt; |2x - 2| = 2 |x-1| &amp;#x3C; epsilon/2 &amp;#x3C; epsilon \ thick \ therefore lim_(x-&gt;1) (2x-1)=1
$$&lt;/p&gt;
&lt;p&gt;(2).&lt;/p&gt;
&lt;p&gt;$$
&quot;要证：&quot; forall epsilon &gt; 0, exists delta &gt; 0, forall 0 &amp;#x3C; |x-1| &amp;#x3C; delta, |(x+1) - 2 | &amp;#x3C; epsilon \ thick \ therefore &quot;取 &quot; delta = epsilon/2 , &quot;则：&quot; |(x^2-1)/(x-1) -2| = |x+1-2| = |x-1|&amp;#x3C; delta  = epsilon/2 &amp;#x3C; epsilon \ thick \ therefore lim_(x-&gt;1) (x^2-1)/(x-1) = 2
$$&lt;/p&gt;
&lt;p&gt;(3).&lt;/p&gt;
&lt;p&gt;$$
&quot;要证：&quot; forall epsilon &gt; 0, exists delta &gt; 0, forall 0&amp;#x3C;|x-2|&amp;#x3C;delta, |x^2 - 4| &amp;#x3C; epsilon \ therefore &quot;取&quot; delta_1 = 1, &quot;则 &quot; |x+2| |x-2| &amp;#x3C; 5 |x-2| &amp;#x3C;epsilon -&gt; delta_2 &amp;#x3C; 1/5 \ therefore delta = min{1, epsilon/5} \ thick \ &quot;此时 &quot; |x^2 - 4| &amp;#x3C; 5 &amp;#x3C; epsilon &quot;或&quot; |x^2-4| &amp;#x3C; 5* epsilon/5 &amp;#x3C; epsilon \ thick \ therefore lim_(x-&gt;2) x^2 = 4
$$&lt;/p&gt;</content:encoded><h:img src="/_astro/cover.B92TOfCL.webp"/><enclosure url="/_astro/cover.B92TOfCL.webp"/></item><item><title>记一杯花茶的逆向工程</title><link>https://crisq.top/blog/another_flower_tea_wp</link><guid isPermaLink="true">https://crisq.top/blog/another_flower_tea_wp</guid><description>WHUCTF 2025 迎新练习的（伪）压轴题</description><pubDate>Mon, 25 Aug 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;（本文是新手 re 同学的学习笔记，所以可能比较啰唆，见谅~）&lt;/p&gt;
&lt;h1&gt;审题&lt;/h1&gt;
&lt;p&gt;审题可知，flower 代表花指令，tea 代表加密算法是 TEA 或者某种 TEA 的衍生算法。&lt;/p&gt;
&lt;h2&gt;分析加密算法&lt;/h2&gt;
&lt;p&gt;首先导航到 Strings 发现一个很明显的 base 64 编码数据 &lt;code&gt;bTRwbGUxc3hubg==&lt;/code&gt;，解密后发现 ~~主席是男娘~~ 得到了 &lt;code&gt;m4ple1sxnn&lt;/code&gt;，猜想应该是密钥。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2Fimg1.D5_Ryefb.png&amp;#x26;w=1266&amp;#x26;h=252&amp;#x26;f=webp&quot; alt=&quot;查看字符串&quot;&gt;&lt;/p&gt;
&lt;p&gt;再使用 FindCrypt 插件查看是否有明显的常见加密算法迹象：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2Fimg2.CBM5IwHy.png&amp;#x26;w=1162&amp;#x26;h=246&amp;#x26;f=webp&quot; alt=&quot;查看可能的加密&quot;&gt;&lt;/p&gt;
&lt;p&gt;没有看到有用信息，重新根据 Strings 中保留的字符串，定位到跳转点。整理后代码如下（其中包含对我的一些疑问点的注释，感谢 GPT 5 的解答）：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;__int64 sub_140001A79()
{
  _QWORD v1[2]; // 实际扮演的是 结构体 而不是单纯数组。
                // v1[0] 保存了地址值（这里是 &amp;#x26;unk_1400C82E0）。
                // v1[1] 保存了长度值（15）。
                // sub_1400AB3F0 接收到的第二个参数本质上就是“指向一块数据的指针 + 这块数据的长度”。
  _BYTE input[32]; // [rsp+30h] [rbp-70h] BYREF
  _BYTE key[32]; // [rsp+50h] [rbp-50h] BYREF
  _BYTE cipher[30]; // [rsp+70h] [rbp-30h] BYREF
  char v5; // [rsp+8Eh] [rbp-12h] BYREF
  char v6; // [rsp+8Fh] [rbp-11h] BYREF
  char *v7; // [rsp+90h] [rbp-10h]
  char *v8; // [rsp+98h] [rbp-8h]
  sub_14000DC40();
  v8 = &amp;#x26;v5;
  v1[0] = &amp;#x26;unk_1400C82E0;
  v1[1] = 15;
  sub_1400AB3F0(cipher, v1, &amp;#x26;v5);
  sub_1400A1160(&amp;#x26;v5);
  v7 = &amp;#x26;v6;
  base64_decode(key, &quot;bTRwbGUxc3hubg==&quot;, &amp;#x26;v6); // 这里明显是base64处理函数，外部做解码即可。
  sub_1400A10A0(&amp;#x26;v6);
  printf(&amp;#x26;unk_1400C6BC0, &quot;plz input your flag: &quot;); // 这里应该是单纯打印字符串的函数
  // 但是读取输入为何要顺带读一个&quot;全局变量？&quot;
  // 绝大多数 C 程序在调用 `printf` 的时候，编译器最终会把它翻译成 `fprintf(stdout, &quot;msg&quot;)`。
  // `stdout` 在 Windows CRT 里就是一个全局变量，编译时常常会被放在 `.data` 里，反编译看上去就是 `&amp;#x26;unk_1400C6BC0`。
  get_input(input);// 显然，获取输入
  trim_input(&amp;#x26;unk_1400C6860, input); // 这里读取一个全局变量并对input做处理
  // 可能的处理方式：1. 标准化字符串，删除空格和特殊字符之类。 2. 对字符串和读入的全局变量做变换，使之以某种方式&quot;混合&quot;或者&quot;发生作用关系&quot;。这里我们就认为是普通的处理输入。
  if ( (unsigned __int8)xxtea_encrypt(input, cipher, key) )// 同时出现密文，密钥和输入，显然是加密比较函数了
    printf(&amp;#x26;unk_1400C6BC0, &quot;Right!let_us_have_a_cup_of_tea!!!\n&quot;);
  else
    printf(&amp;#x26;unk_1400C6BC0, &quot;oh_no_no_no!!!\n&quot;);
  sub_1400AFEB0(input);
  sub_1400AFEB0(key);
  sub_1400AB510(cipher);
  // 对那几个栈上对象做收尾工作：释放可能的堆内存、把长度归零等。
  return 0;
  // 标准返回函数
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;于是我们清理 &lt;code&gt;sub_1400018CA&lt;/code&gt; (在上述清理过的代码中为 xxtea_encrypt )代码：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;__int64 __fastcall xxtea_encrypt(__int64 input, __int64 cipher, __int64 key)
{
  size_t n16; // rbx
  const void *v4; // rax
  size_t Size; // rsi
  const void *v6; // rbx
  void *v7; // rax
  __int64 v8; // rbx
  __int64 v9; // rax
  _BYTE v11[32]; // [rsp+20h] [rbp-70h] BYREF
  _QWORD v12[2]; // [rsp+40h] [rbp-50h] BYREF
  _BYTE v13[43]; // [rsp+50h] [rbp-40h] BYREF
  char v14; // [rsp+7Bh] [rbp-15h] BYREF
  int v15; // [rsp+7Ch] [rbp-14h] BYREF
  char *v16; // [rsp+80h] [rbp-10h]
  unsigned __int64 v17; // [rsp+88h] [rbp-8h]
  sub_140001450(v13, key);

  // 下面是处理 key 的函数
  v12[0] = 0;
  v12[1] = 0;
  if ( (unsigned __int64)sub_14002F0A0(v13) &gt; 0x10 )
    n16 = 16;
  else
    n16 = sub_14002F0A0(v13);
  v4 = (const void *)sub_1400AD570(v13);
  memcpy(v12, v4, n16);
  // 将10位的小暖男（确信）密钥扩展成16位，空缺处补0
  // eg: maple1sxnn -&gt; maple1sxnn000000

  v17 = (unsigned __int64)(sub_14002F0A0(input) + 3) &gt;&gt; 2; // XXTEA 所需的&quot;按4字节对齐后的词数&quot;

  v16 = &amp;#x26;v14;
  v15 = 0;
  sub_1400AB490(v11, v17, &amp;#x26;v15, &amp;#x26;v14);
  sub_1400A1160(&amp;#x26;v14);
  Size = sub_14002F0A0(input);
  v6 = (const void *)sub_14002EEB0(input);
  v7 = (void *)sub_1400AB3C0(v11);
  memcpy(v7, v6, Size);
  // 准备工作，实现一些拷贝，缓冲之类的操作

  v8 = sub_14002D4C0(v11);          // 当前数据长度（字节数）
  v9 = sub_1400AB3C0(v11);          // 数据指针
  xxtea_encrypt(v9, v8, v12);       // XXTEA 加密的核心函数
  // 这里把 buf[0..len-1] 按小端 32-bit 词视图、长度 n = (len+3)&gt;&gt;2，用 key（四个 32-bit 子键）做循环加密。
  LODWORD(v8) = sub_1400BF530(v11, cipher);
  sub_1400AB510(v11);
  sub_1400AFEB0(v13);
  return (unsigned int)v8;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可知：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;使用 &lt;code&gt;m4ple1sxnn&lt;/code&gt; 作为密钥材料（16 字节，因此填 0）&lt;/li&gt;
&lt;li&gt;对用户输入的flag进行加密（通过&lt;code&gt;sub_1400016DC&lt;/code&gt;函数）&lt;/li&gt;
&lt;li&gt;将加密结果与预存的数据进行比较&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;花指令处理&lt;/h2&gt;
&lt;p&gt;于是定位到 &lt;code&gt;sub_1400016DC&lt;/code&gt; 函数，发现是一个跳转。显然这里 JUMPOUT 出的地址才是真正的实现函数。但是由于它没有被 IDA 识别为函数，我们只能强行看汇编了。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;void __fastcall encrypt_impl(__int64 a1, unsigned __int64 a2)
{
  if ( a2 &gt; 1 &amp;#x26;&amp;#x26; 0x34 / (unsigned int)a2 != -6 )
    JUMPOUT(0x140001744LL);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(AI 注释： &lt;strong&gt;你不一定要把 JUMPOUT 目标当“新函数”看。&lt;/strong&gt; JUMPOUT 往往只是&lt;strong&gt;跳到一个代码块&lt;/strong&gt;（可能在同一函数里，或落在别的函数的中间/尾块），反编译器因此&lt;strong&gt;不把它认作函数入口&lt;/strong&gt;。先把它当作“落点基本块”去读即可；若你确认那儿才是一个独立入口，再手动建函数。 )&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-asm&quot;&gt;; 噪音 / 误解码（建议当作 db）
; xor     eax, [rcx+4514F845h]
; adc     [rax], eax
; xor eax, [rcx+4514F845h] 带巨大的位移，对未定义的 RCX 取内存；adc [rax], eax 会对 EAX 指向的地址写内存，若 EAX 未设定几乎必崩——它们既不保存现场也不建立栈框，和后续“规整的逻辑”断层。
; loc_14000174B  ← 以这里作为代码起点更合理
mov     eax, [rbp+var_8]      ; eax = sum !!!注意，这里是读取sum的地方!！初始的Sum就是我们需要的Delta
shr     eax, 2
and     eax, 3                ; eax = (sum &gt;&gt; 2) &amp;#x26; 3  → e ∈ {0,1,2,3}
mov     [rbp+var_18], eax     ; e
mov     [rbp+var_C], 0        ; i = 0
jmp     loc_140001806         ; 进入主循环
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果我们将上面两条花指令 NOP 掉，其实可以看见部分 XXTEA 的实现（Delta 累加部分被更多花指令隐藏掉了）：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;void __fastcall encrypt_impl(_DWORD *a1, unsigned __int64 a2, __int64 a3)
{
  unsigned int *v3; // rax
  unsigned int *v4; // rax
  unsigned int v6; // [rsp+4h] [rbp-1Ch]
  unsigned int v7; // [rsp+10h] [rbp-10h]
  unsigned int i; // [rsp+14h] [rbp-Ch]
  unsigned int v9; // [rsp+1Ch] [rbp-4h]
  if ( a2 &gt; 1 )
  {
    v9 = a1[(unsigned int)(a2 - 1)];
    v7 = 0x34 / (unsigned int)a2 + 6;
    while ( v7-- )
    {
      for ( i = 0; i &amp;#x3C; (int)a2 - 1; ++i )
      {
        v6 = a1[i + 1];
        v3 = &amp;#x26;a1[i];
        *v3 += (v6 + (v9 ^ *(_DWORD *)(4LL * (i &amp;#x26; 3) + a3))) ^ (((4 * v6) ^ (v9 &gt;&gt; 5)) + ((v6 &gt;&gt; 3) ^ (16 * v9)));
        v9 = *v3;
      }
      v4 = &amp;#x26;a1[(unsigned int)(a2 - 1)];
      *v4 += (*a1 + (v9 ^ *(_DWORD *)(4LL * (i &amp;#x26; 3) + a3))) ^ (((4 * *a1) ^ (v9 &gt;&gt; 5)) + ((*a1 &gt;&gt; 3) ^ (16 * v9)));
      v9 = *v4;
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;进入主循环（太长了不贴），可以发现是一个标准的&quot;判断是主循环还是尾循环，并执行符合 XXTEA 规则的轮加密&quot;的函数。自此我们确定了该函数是 XXTEA 加密。（这一步需要有密码学基础，至少得熟悉常见的对称加密的代码实现，可以选择问AI）下一步就是找 Delta 了。&lt;/p&gt;
&lt;p&gt;然而，上面 FindCrypt 的结果已经指出：TEA 类算法中经典的 Delta 值（0x9E3779B9）并没有出现在我们的程序中（表现为检测不出 TEA 类算法），于是我们猜测该程序有自定义的 Delta 值。结合上述内容可知 Delta 被花指令隐藏，该部分处理比较困难，于是考虑通过动态调试获取之（由于笔者使用 Linux 环境，这里使用 winedbg + gdb，选用x64dbg 等亦可）：&lt;/p&gt;
&lt;h2&gt;动态调试&lt;/h2&gt;
&lt;p&gt;首先，我们需要解决一个问题：去哪找？&lt;/p&gt;
&lt;p&gt;根据上述内容，注意到：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-asm&quot;&gt;mov     eax, [rbp+var_8]      ; eax = sum !!!注意，这里是读取sum的地方!！初始的Sum就是我们需要的Delta
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里就是我们需要的函数，它的地址在 IDA 中可以发现是 &lt;code&gt;0x14000174b&lt;/code&gt;，于是启动 gdb 并下断：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;pwndbg&gt;  winedbg --gdb another_flower_tea.exe
(Some Output)
pwndbg&gt;  b *0x14000174b # 下断点
pwndbg&gt;  c # continue，表示执行程序到断点
# 等待程序停在断点处，中间可能需要按照源程序要求执行输入操作，随便输入些东西即可
pwndbg&gt;  set $sum_addr = $rbp - 8 # 源程序显示采用的是负偏移，所以我们先提前算出负偏移的 offset
pwndbg&gt; x/wx $sum_addr
0x21fd68:	0x00114514
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;好了！我们拿到了初始的 Delta——0x00114514，一个非常符合网安学长精神状态的数。于是根据标准的 XXTEA 加密过程，可以开始写解密脚本了。&lt;/p&gt;
&lt;p&gt;写出解密脚本如下（可以求助 AI 或翻阅 Github 现成实现并修改 Delta 值）：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;#include &amp;#x3C;stdint.h&gt;
#include &amp;#x3C;stdio.h&gt;
#include &amp;#x3C;string.h&gt;
#define DELTA 0x00114514
void xxtea_decrypt(uint32_t *v, uint32_t len, uint32_t *k) {
  uint32_t n = len - 1;
  uint32_t z = v[n], y = v[0], sum = 0, e;
  uint32_t p, q;
  q = 6 + 52 / (n + 1);
  sum = q * DELTA; // 初始sum值
  while (sum != 0) {
    e = (sum &gt;&gt; 2) &amp;#x26; 3;
    for (p = n; p &gt; 0; p--) {
      z = v[p - 1];
      y = v[p] -= (((z &gt;&gt; 5) ^ (y &amp;#x3C;&amp;#x3C; 2)) + ((y &gt;&gt; 3) ^ (z &amp;#x3C;&amp;#x3C; 4))) ^
                  ((sum ^ y) + (k[(p &amp;#x26; 3) ^ e] ^ z));
    }
    z = v[n];
    y = v[0] -= (((z &gt;&gt; 5) ^ (y &amp;#x3C;&amp;#x3C; 2)) + ((y &gt;&gt; 3) ^ (z &amp;#x3C;&amp;#x3C; 4))) ^
                ((sum ^ y) + (k[(p &amp;#x26; 3) ^ e] ^ z));
    sum -= DELTA;
  }
}
// 将密钥扩展为4个uint32_t，不足部分填0
void key_setup(const char *key_str, uint32_t *key) {
  memset(key, 0, 16); // 先清零
  memcpy(key, key_str, strlen(key_str) &amp;#x3C; 16 ? strlen(key_str) : 16);
}
int main() {
  // 加密数据（60字节，15个uint32_t）
  uint8_t enc_data[] = {
      0x92, 0x37, 0x53, 0x0B, 0x48, 0x37, 0x0A, 0x7D, 0x08, 0xF6, 0x91, 0x5F,
      0xA2, 0x4B, 0x3C, 0xAD, 0x06, 0xFB, 0x6C, 0x8B, 0xF3, 0x51, 0x74, 0x6D,
      0xF3, 0x8F, 0x6F, 0x58, 0x20, 0x75, 0xFE, 0x81, 0xE0, 0x46, 0x0A, 0x88,
      0x0E, 0x80, 0x04, 0xBD, 0xBE, 0xCB, 0x4B, 0x74, 0xC4, 0x58, 0x12, 0x30,
      0x91, 0x29, 0x4D, 0x12, 0x1E, 0xCE, 0x38, 0x01, 0xD5, 0xF3, 0x0D, 0x23};
  uint32_t data[15];
  memcpy(data, enc_data, sizeof(data));
  // 密钥
  const char *key_str = &quot;m4ple1sxnn&quot;;
  uint32_t key[4];
  key_setup(key_str, key);
  // 解密
  xxtea_decrypt(data, 15, key);
  // 以字符串形式输出（可读明文）
  printf(&quot;\n解密结果 (string):\n&quot;);
  char *str = (char *)data;
  for (int i = 0; i &amp;#x3C; 60; i++) {
    if (str[i] &gt;= 32 &amp;#x26;&amp;#x26; str[i] &amp;#x3C;= 126) {
      putchar(str[i]);
    } else if (str[i] == 0) {
      putchar(&apos;\\&apos;);
      putchar(&apos;0&apos;);
    } else {
      printf(&quot;\\x%02X&quot;, (unsigned char)str[i]);
    }
  }
  putchar(&apos;\n&apos;);
  return 0;
}
&lt;/code&gt;&lt;/pre&gt;</content:encoded><h:img src="/_astro/cover.4JqW3jMj.webp"/><enclosure url="/_astro/cover.4JqW3jMj.webp"/></item><item><title>江南漫溯 | 南京篇</title><link>https://crisq.top/blog/jiang_nan</link><guid isPermaLink="true">https://crisq.top/blog/jiang_nan</guid><description>高考后去了一趟南京，顺带去杭州逛了逛</description><pubDate>Thu, 26 Jun 2025 14:26:00 GMT</pubDate><content:encoded>&lt;p&gt;import { Aside } from &apos;astro-pure/user&apos;
import { Masonry } from &apos;astro-masonry&apos;
import { Image } from &quot;astro:assets&quot;
import BilibiliVideoCard from &quot;../../../components/Bilibili/BilibiliVideoCard.astro&quot;&lt;/p&gt;
&lt;p&gt;在我的音乐人圈子里有位好友，在南京大学念书，因而我很早便对南京心生向往，想去亲自看看秦淮风物，但却懒癌发作，迟迟不愿计划出发，恰巧一天下午准备看看南京博物院是否还有预约位，抱着试试看的心态随手约了20号上午的票，竟然成功了。于是蛰伏已久的旅行热情突然被唤起，匆匆整顿行装，17号便迫不及待地出发，扑向江南的怀抱。&lt;/p&gt;
&lt;h1&gt;🚶‍♂️ Day 1 | 匆匆出行，却也有路上风景&lt;/h1&gt;
&lt;p&gt;说是Day1其实没那么严谨，上午去优衣库买了两件换洗的衣服，下午就赶慌赶忙前往火车站。人生中第一次独自离家如此之远，兴奋是难免的。然而，上了火车后才体会到极致的无聊，索性便听着播客，靠在桌板上一觉睡到到站。&lt;/p&gt;
&lt;p&gt;旅途虽然奔波，多少留下了些光影的痕迹。我曾在很小的时候去过一次南京，留下的最深印象就是那里的地铁有地上段，果然，在窗外从深黑变为淡紫时，世界便在我眼前徐徐晕开。天幕似乎在流动，与如缕的云搅拌在一起，渐变成温暖的粉色。伴着逐渐褪成剪影的房屋和草木，明暗交织，颇令人心醉。&lt;/p&gt;
&lt;p&gt;我特别喜欢蓝调时刻的南京，所有地方都透着娴静又唯美的气质。图二还颇有点动漫中电车窗外日落的感觉了，甚至可以想象窗外人们结束一天的忙碌谈笑漫步的场景，他们会去哪儿呢？也许是一家藏在深巷间的精酿酒馆，也许是公园里能看见萤火虫的长椅，也许就是自己安安稳稳，遮风避雨的家。烟火气漫卷开，涂抹了我对这座古老城市印象的底色。&lt;/p&gt;
&lt;p&gt;安顿完行李，准备随便出门转转，没想到，一转就给转迷路了🤣，眼看着林立的高楼大厦逐渐变成陌生的小街小巷和各类狭小逼仄的门面，初来乍到的小年轻还是有点畏手畏脚，转着转着索性放开了，到哪儿不是逛吃逛吃，找了家看着顺眼的小店整了点甜品（&lt;strong&gt;你永远可以相信南京的甜品铺子！是真的多，又多又好！！&lt;/strong&gt;），芒果酱是现做的，冰沙软乎乎，看起来像木鱼花，吃起来感觉很轻盈，还蛮好吃~
&amp;#x3C;Masonry
breakpointCols={{ default: 3, 1024: 2, 640: 1 }}
class=&quot;flex gap-4 px-4&quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751033022621.CzRvKeb0.webp&amp;#x26;w=1408&amp;#x26;h=2111&amp;#x26;f=webp&quot; alt=&quot;武汉站&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751033006267.B0olH4h4.webp&amp;#x26;w=1536&amp;#x26;h=1344&amp;#x26;f=webp&quot; alt=&quot;蓝调时刻，南京地铁的窗外&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751033008739.CRv3FcjF.webp&amp;#x26;w=1536&amp;#x26;h=1344&amp;#x26;f=webp&quot; alt=&quot;自认为拍得很美的站台&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751033020945.CMp0FCEz.webp&amp;#x26;w=1536&amp;#x26;h=1344&amp;#x26;f=webp&quot; alt=&quot;繁华的新街口夜景&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751033026776.B0tH7YOt.webp&amp;#x26;w=1152&amp;#x26;h=1728&amp;#x26;f=webp&quot; alt=&quot;一家真的很好吃的小店&quot;&gt;
&lt;/p&gt;
&lt;h1&gt;⛰️ Day 2 | 登高，会禅，看老蒋&lt;/h1&gt;
&lt;h2&gt;李记清真馆为什么是神&lt;/h2&gt;
&lt;p&gt;带着前几天在B站上狂刷南京旅行指南的自信，次日清晨直奔李记清真馆，准备试试他家芳名远传的牛肉锅贴。我认为他家牛肉锅贴最神奇的是外皮，松脆酥软，却不易碎，入口仿佛肉松般细腻，带着甜味的肉汁涌入口中，回味悠长。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751040561158.AO7Nc0vK.webp&amp;#x26;w=1536&amp;#x26;h=1344&amp;#x26;f=webp&quot; alt=&quot;真的！信我！李记就是神&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;哦对了，记得避雷旁边的望吉利，他家的所有饮料真的都好难喝😡。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;爬山，见佛，瞰南京&lt;/h2&gt;
&lt;p&gt;吃饱喝足，立马准备赶往牛首山！&lt;/p&gt;
&lt;p&gt;当然，行程不出意外地出意外了。网约车司机在离景点还有一公里多的荒郊野岭把我直接放下车了，我居然也稀里糊涂答应了（可能觉得是不是走几步就能找到景区了，也没看定位，麻了，大家千万不要学我），于是体验了一把原生态山水后和农民婶婶打听到了最近的公路的方位，又叫了另一辆网约车才算到目的地（人生地不熟的，要用走估计得走好久......）&lt;/p&gt;
&lt;p&gt;好在，总算还是到了。在门口买了杯星巴克，喝完就开始爬山。好家伙，给我爬了个半死，网上明明说有电梯，结果要抵达电梯先要爬个将近四千步，还都是爬升上坡，顶着六月份的大太阳，可谓折磨。嘛，安慰安慰自己，这是佛祖给孩子的考验，嗯，一定是。&lt;/p&gt;
&lt;p&gt;山脚是一处小湖，有很多鱼，颇有种“皆若空游无所依”的飘逸感，山顶则是佛顶宫和佛顶塔，按照攻略，先走进了佛顶宫。混着檀香的空调冷风吹来，解散暑气，确乎颇有种飘飘欲仙的感觉。穹顶很震撼，是那种说不出门道，照片也展示不出来的震撼。佛祖巨像卧在莲台中央，缓缓旋转，推荐各位亲自去看一看（如果爬得了山的话）。下到地宫的千佛殿，拍几张佛造像，虽然说偶像崇拜不是佛学本意吧，但当成纯粹的文化艺术作品来欣赏，未尝不是一场视觉盛宴。&lt;/p&gt;
&lt;p&gt;&amp;#x3C;Masonry
breakpointCols={{ default: 3, 1024: 2, 640: 1 }}
class=&quot;flex gap-4 px-4&quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751033022055.ZgrBQ6Xs.webp&amp;#x26;w=1536&amp;#x26;h=1344&amp;#x26;f=webp&quot; alt=&quot;佛顶宫-游鱼&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751040677497.CxMwf9p1.webp&amp;#x26;w=1306&amp;#x26;h=1142&amp;#x26;f=webp&quot; alt=&quot;佛顶宫穹顶&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751033013229.B73J95V2.webp&amp;#x26;w=1536&amp;#x26;h=1344&amp;#x26;f=webp&quot; alt=&quot;卧佛&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751033010624.DUx--DK7.webp&amp;#x26;w=1306&amp;#x26;h=1142&amp;#x26;f=webp&quot; alt=&quot;千佛殿-上层视角&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751033019512.DKog64Hc.webp&amp;#x26;w=1306&amp;#x26;h=1142&amp;#x26;f=webp&quot; alt=&quot;千佛殿-特写&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751033012359.DQClgeKX.webp&amp;#x26;w=1536&amp;#x26;h=1344&amp;#x26;f=webp&quot; alt=&quot;佛顶宫-外部1&quot;&gt;
&lt;/p&gt;
&lt;p&gt;逛完了佛顶宫，也就顺带去佛顶塔拍了几张。佛顶塔也好难爬，泪目了，尤其是到了第六层还是七层之后只能爬阁楼，楼梯更加陡峭逼仄，实在是太难为人了，下行时，不得不猫着身子斜着脚走路，委委屈屈。好在登高望远，迎着山顶吹来的风，拍下了南京城的天际线，还是很壮丽的。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751033006536.DjSzXW9V.webp&amp;#x26;w=1536&amp;#x26;h=1344&amp;#x26;f=webp&quot; alt=&quot;当然，任何壮丽在我糟糕的摄影技术面前将荡然无存&quot;&gt;&lt;/p&gt;
&lt;h2&gt;没能看到老蒋是我最大的遗憾&lt;/h2&gt;
&lt;p&gt;中午回酒店稍事休息（其实是懒癌发作躺床上玩手机玩到快三点）后前往总统府找老蒋（www），一进门就是一个近代史相关资料展，也算是大概了解了一下民国发生了什么大事www。给我留下的比较好印象的一点是这个展览没有一味聚焦在宏大叙事上，没有只介绍谁和谁打了，谁把谁暗杀了，谁即了谁的位，而是专门留了很大一块区域介绍民国的文化交融（如天主教嬷嬷给渔民传教）和生活风貌（如职工体操大会的老照片、健康宝宝评选、女子运动会等），感觉对民国的认识一下子立体起来了。虽然仍然是浮光掠影，但至少也摆脱了“才子佳人上海滩”或者“人民水深火热”、“黑暗统治”之类片面的刻板印象，看到了有生气有血肉的人的生活。总体上是一个很值得推荐的展，像我这种对民国历史几乎一窍不通的人也能有所收获。&lt;/p&gt;
&lt;p&gt;顺着人流行进时，还发现一个侧院有太平天国主题的展，也顺带看了看。嚯呀，洪老师的龙椅看着好~~土豪般的俗气~~ 符合人设😅。&lt;/p&gt;
&lt;p&gt;然而，最大的遗憾是子超楼由于装修而暂停开放，心心念念想看的老蒋办公室也没看成。&lt;/p&gt;
&lt;p&gt;&amp;#x3C;Masonry
breakpointCols={{ default: 2, 640: 1 }}
class=&quot;flex gap-4 px-4&quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751033016677.orUH4ydq.webp&amp;#x26;w=1152&amp;#x26;h=1728&amp;#x26;f=webp&quot; alt=&quot;新青年&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2FIMG20250618152949.uiDHUOyR.webp&amp;#x26;w=1536&amp;#x26;h=1344&amp;#x26;f=webp&quot; alt=&quot;回望近代百年风云&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751033014491.ClZh64gy.webp&amp;#x26;w=1877&amp;#x26;h=1642&amp;#x26;f=webp&quot; alt=&quot;真的好俗气&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2FIMG20250618164412.DP3bu0S2.webp&amp;#x26;w=1656&amp;#x26;h=2484&amp;#x26;f=webp&quot; alt=&quot;牢蒋&quot;&gt;
&lt;/p&gt;
&lt;p&gt;最后放一张孙先生的名言结束总统府一章吧。
&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751040677051.ChIQuFXn.webp&amp;#x26;w=979&amp;#x26;h=1469&amp;#x26;f=webp&quot; alt=&quot;同志仍需努力&quot;&gt;&lt;/p&gt;
&lt;h2&gt;夜闯夫子庙，仗“证”走金陵&lt;/h2&gt;
&lt;p&gt;众所周知，当谈起夫子庙的时候，无论是不是南京人，一定会往死里骂。但没办法，想看秦淮夜景，大概率也只能去夫子庙。于是，抱着&lt;strong&gt;不在夫子庙买哪怕一块钱的小吃&lt;/strong&gt;的坚定意志，“奄奄黄昏后，寂寂人定初”，我来到了这里.
然而，直到前往江南贡院前，我对这一片的印象都是：糟糕，十分糟糕。且不说各式光怪陆离的宰人店面和穿着形制混乱粗糙劣质的所谓杂糅汉服摆拍的游人，单是核心卖点“秦淮”，也被五颜六色的灯带蹂躏得媚俗不堪，完全无法带入“烟笼寒水月笼沙”的静谧诗意中，只看到因追逐客流量和成交量而粉碎着洒落一地的金陵幻梦。所以，即使为了看秦淮夜景，我的评价仍然是&lt;strong&gt;别去夫子庙，它会毁了你心中的江南。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;当然，旁边的江南贡院（中国科举博物馆）还是要夸一夸的！&lt;/p&gt;
&lt;p&gt;首先是因为它的全，几乎将清楚了科举制度的发源演进，科举的流程步骤，科举的试题内容及验身、答卷、审卷、改卷全流程的各种复杂防作弊措施。甚至还列了很多份真实的科举答卷（有一说一，排比句这种东西古人也很爱用，看来应试作文小技巧是古今通用的，但流俗也是真的流俗~）。&lt;/p&gt;
&lt;p&gt;其次，高考生免票。好那不用多说了，我会成为忠实的自来水并把它夸上天的。&lt;/p&gt;
&lt;p&gt;&amp;#x3C;Masonry
breakpointCols={{ default: 3, 1024: 2, 640: 1 }}
class=&quot;flex gap-4 px-4&quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751033026454.CqeDtdB5.webp&amp;#x26;w=1306&amp;#x26;h=1142&amp;#x26;f=webp&quot; alt=&quot;书院历史博物馆&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751033009710.CcX3-hyK.webp&amp;#x26;w=1536&amp;#x26;h=1344&amp;#x26;f=webp&quot; alt=&quot;秦淮夜景&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751081648154.CwogCvD_.webp&amp;#x26;w=1306&amp;#x26;h=1142&amp;#x26;f=webp&quot; alt=&quot;所谓秦淮夜景&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751033010990.DJZO3HyD.webp&amp;#x26;w=1152&amp;#x26;h=1728&amp;#x26;f=webp&quot; alt=&quot;我爱江南贡院（并不&quot;&gt;
&lt;/p&gt;
&lt;h1&gt;🏛️ Day 3 | 孝陵观景，中山怀人，门东圆梦&lt;/h1&gt;
&lt;h2&gt;克里斯摸黑闯孝陵&lt;/h2&gt;
&lt;p&gt;由于明孝陵早晨六点半前免票的政策，五点就摸黑起来准备闯孝陵了！&lt;/p&gt;
&lt;p&gt;网传“南京最美六百米”的神道其实就我而言并没有什么感觉，只觉得走了就是走了，可能雨天去会更漂亮吧。&lt;/p&gt;
&lt;p&gt;走到尽头就是方城明楼，由于明孝陵至今未被掘，能看的也只有地上建筑，到此便可返程了。临走时去了一趟长生鹿苑，令人很难受的是，长生鹿苑八点半才正式营业，也就是说我得等个一小时左右才能去摸鹿，此刻正是蚊子疯狂肆虐的时节，我的腿上已经显出一些红色的抓痕了，于是一狠心和我的小鹿们挥手告别，赶紧遛掉。&lt;/p&gt;
&lt;p&gt;&amp;#x3C;Masonry
breakpointCols={{ default: 3, 1024: 2, 640: 1 }}
sortByHeight={true}
class=&quot;flex gap-4 px-4&quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751033023171.DvRZd-ug.webp&amp;#x26;w=1306&amp;#x26;h=1142&amp;#x26;f=webp&quot; alt=&quot;大石兽&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751033024134.CmHZDZXT.webp&amp;#x26;w=1306&amp;#x26;h=1142&amp;#x26;f=webp&quot; alt=&quot;石士兵&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751033017002.Zaa4cNXa.webp&amp;#x26;w=1306&amp;#x26;h=1142&amp;#x26;f=webp&quot; alt=&quot;神道&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751033016433.DVXTS1CV.webp&amp;#x26;w=1152&amp;#x26;h=1728&amp;#x26;f=webp&quot; alt=&quot;哈利·波特剧照质感&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751033018985.CSxnjoo7.webp&amp;#x26;w=1536&amp;#x26;h=1344&amp;#x26;f=webp&quot; alt=&quot;方城明楼&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751033015525.DH-kL8mu.webp&amp;#x26;w=1306&amp;#x26;h=1142&amp;#x26;f=webp&quot; alt=&quot;长生鹿苑&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751033015896.BrZ50BCM.webp&amp;#x26;w=1877&amp;#x26;h=1642&amp;#x26;f=webp&quot; alt=&quot;小白鹿！&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751033013493.DaAHXup9.webp&amp;#x26;w=1536&amp;#x26;h=1344&amp;#x26;f=webp&quot; alt=&quot;鸭鸭&quot;&gt;
&lt;/p&gt;
&lt;p&gt;快看我拍的小白鹿！好可爱！！门口的水塘里还有鸭子（还是鹅🪿？）反正也很可爱就是了~&lt;/p&gt;
&lt;h2&gt;奋登山谒陵瞻国父&lt;/h2&gt;
&lt;p&gt;从明孝陵到钟山景区观光车站点，很是走了一段，中途看见了一个有趣的标牌：&lt;/p&gt;
&lt;p&gt;在中山陵狠狠爬了好多级台阶😭，我跟同学说我能一分钟内爬上去，结果上是上去了，心率飙到160了。谒陵结束出来时我又贪玩想滑台阶旁的斜坡，结果因为正好下着小雨，脚底打滑摔倒在地，万幸屁股比后脑勺先着地，目前幸存😊.&lt;/p&gt;
&lt;p&gt;当你不知道午饭吃什么的时候怎么办？那就无脑南京大牌档吧！至少不难吃~
&amp;#x3C;Masonry
breakpointCols={{ default: 3, 1024: 2, 640: 1 }}
class=&quot;flex gap-4 px-4&quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751033024484.zMf9BNa9.webp&amp;#x26;w=1306&amp;#x26;h=1142&amp;#x26;f=webp&quot; alt=&quot;真的好好玩&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751033015166.DrP6Tb_Z.webp&amp;#x26;w=979&amp;#x26;h=1469&amp;#x26;f=webp&quot; alt=&quot;中山陵&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751033026148.DngYhsTb.webp&amp;#x26;w=1536&amp;#x26;h=1344&amp;#x26;f=webp&quot; alt=&quot;南京大牌档&quot;&gt;
&lt;/p&gt;
&lt;p&gt;下午实在不知道干嘛了，想去先锋书店又不想动，想去红山动物园又不想动，想去鸡鸣寺又不想动，于是就继续躺酒店里躺了一下午。（胡适之啊胡适之你怎能如此堕落！！！）&lt;/p&gt;
&lt;h2&gt;老门东？颜值巅峰！&lt;/h2&gt;
&lt;p&gt;快傍晚时，按照原定行程，来到老门东，看看南京除了秦淮风月之外的另一种夜景。&lt;/p&gt;
&lt;p&gt;烟雨浸透的南京才是最美的南京。人群熙熙攘攘，却没有夫子庙那般摩肩接踵惹人厌烦。正是日落月升之时，天幕一片澄澈的靛蓝，如刚漂洗过，与徽派的青瓦白墙相映成趣。间或穿插着点点红灯笼，为潇潇洒洒的青蓝色调注入一抹明艳的撞色。青石板路沟壑间流淌着潺潺的雨水，薄雾模糊了霓虹灯闪烁的光。颇有些“金吾不禁夜，玉漏莫相催”的气派。&lt;/p&gt;
&lt;p&gt;&amp;#x3C;Masonry
breakpointCols={{ default: 3, 1024: 2, 640: 1 }}
class=&quot;flex gap-4 px-4&quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751033025754.CH017_jW.webp&amp;#x26;w=1306&amp;#x26;h=1142&amp;#x26;f=webp&quot; alt=&quot;老门东1&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751033023604.Bj-fMd39.webp&amp;#x26;w=1536&amp;#x26;h=1344&amp;#x26;f=webp&quot; alt=&quot;老门东2&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751033020166.ByxYii0n.webp&amp;#x26;w=1536&amp;#x26;h=1344&amp;#x26;f=webp&quot; alt=&quot;老门东3&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751033019900.GWBKLMMr.webp&amp;#x26;w=1536&amp;#x26;h=1344&amp;#x26;f=webp&quot; alt=&quot;老门东4&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751033012869.sE_rP_Ya.webp&amp;#x26;w=1306&amp;#x26;h=1142&amp;#x26;f=webp&quot; alt=&quot;老门东5&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751033010283.CbbrQv5P.webp&amp;#x26;w=1306&amp;#x26;h=1142&amp;#x26;f=webp&quot; alt=&quot;老门东6&quot;&gt;
&lt;/p&gt;
&lt;p&gt;至于吃嘛，老门东基本上也就是和夫子庙坐一桌的，但门东水铺还不错哦，值得打卡。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751033018460.Dt1GRlz8.webp&amp;#x26;w=2208&amp;#x26;h=1932&amp;#x26;f=webp&quot; alt=&quot;门东水铺&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;我早就说过，你永远可以相信南京的甜品铺子吧，嘿嘿&lt;/p&gt;
&lt;p&gt;---Cris.Q&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;Day 4 | 晃晃悠悠南博，心心念念南大&lt;/h1&gt;
&lt;p&gt;终于，到了20号，可以去我此行的真正目的地——南京博物院了。&lt;/p&gt;
&lt;p&gt;我跟你们讲，南博的票真的很难约的！（虽然我一下就约上了，但是看网上似乎不好约欸~）&lt;/p&gt;
&lt;p&gt;当然，还有集印章环节，真的得做足功课（小红书上有很多攻略，但我不用小红书hhh所以只能硬着头皮瞎转悠）。&lt;/p&gt;
&lt;p&gt;&amp;#x3C;Masonry
breakpointCols={{ default: 2, 640: 1 }}
class=&quot;flex gap-4 px-4&quot;
sortByHeight={true}&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2Ffailed_example.BXJxdL7a.webp&amp;#x26;w=771&amp;#x26;h=2699&amp;#x26;f=webp&quot; alt=&quot;某失败案例现身说法&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751033012076.BTH1-dvr.webp&amp;#x26;w=1152&amp;#x26;h=1728&amp;#x26;f=webp&quot; alt=&quot;集印章啦！&quot;&gt;
&lt;/p&gt;
&lt;p&gt;在深陷民国馆泥潭前，好好欣赏了一遍艺术馆，老师们的作品真的都好棒。&lt;/p&gt;
&lt;p&gt;&amp;#x3C;Masonry
breakpointCols={{ default: 3, 1024: 2, 640: 1 }}
class=&quot;flex gap-4 px-4&quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751033011828.D-ykf9RW.webp&amp;#x26;w=1152&amp;#x26;h=1728&amp;#x26;f=webp&quot; alt=&quot;太白&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751033007377.DFFs8bNc.webp&amp;#x26;w=1656&amp;#x26;h=2484&amp;#x26;f=webp&quot; alt=&quot;泥人造像&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751033007120.gIb1t05S.webp&amp;#x26;w=1152&amp;#x26;h=1728&amp;#x26;f=webp&quot; alt=&quot;吴健雄奶奶，伟大的物理学家&quot;&gt;
&lt;/p&gt;
&lt;p&gt;而把宝贵的一个半小时浪费在民国馆后，只能特种兵行程了，匆匆看完了历史馆和特展馆，拍了一些很有意思的文物。（唐宋真的是一座艺术高峰，太多文物都漂亮而有个性了，相比起来明清感觉太四平八稳了一些，没唐朝那么“飘”）&lt;/p&gt;
&lt;p&gt;&amp;#x3C;Masonry
breakpointCols={{ default: 3, 1024: 2, 640: 1 }}
class=&quot;flex gap-4 px-4&quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751033011546.BVHqdnOD.webp&amp;#x26;w=1536&amp;#x26;h=1344&amp;#x26;f=webp&quot; alt=&quot;可爱的小...这是啥？&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751033008167.BUfeDyQ8.webp&amp;#x26;w=1536&amp;#x26;h=1344&amp;#x26;f=webp&quot; alt=&quot;牙齿很好的石狮子&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751033008996.DvjdRMAA.webp&amp;#x26;w=1306&amp;#x26;h=1142&amp;#x26;f=webp&quot; alt=&quot;颜色鲜艳的龙头&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751033009415.DZhFSvZm.webp&amp;#x26;w=1152&amp;#x26;h=1728&amp;#x26;f=webp&quot; alt=&quot;质地细腻的叶脉纹瓶子&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751033025484.BD8VhY-q.webp&amp;#x26;w=1536&amp;#x26;h=1344&amp;#x26;f=webp&quot; alt=&quot;坐在大象背上&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751033024794.aiwLOABo.webp&amp;#x26;w=1152&amp;#x26;h=1728&amp;#x26;f=webp&quot; alt=&quot;清新的青莲&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751033020463.DAr5QyXT.webp&amp;#x26;w=1656&amp;#x26;h=2484&amp;#x26;f=webp&quot; alt=&quot;鱼，嘴好大&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751033019278.Dzk3BavN.webp&amp;#x26;w=1536&amp;#x26;h=1344&amp;#x26;f=webp&quot; alt=&quot;很有艺术感的铜锁&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751033018187.D0jfCQj0.webp&amp;#x26;w=1152&amp;#x26;h=1728&amp;#x26;f=webp&quot; alt=&quot;唐三彩马，很帅&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751033017924.CpcurkWM.webp&amp;#x26;w=1536&amp;#x26;h=1344&amp;#x26;f=webp&quot; alt=&quot;特展馆憨态可掬的没人知道是什么&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751092313706.CqLgvmBb.webp&amp;#x26;w=1408&amp;#x26;h=2111&amp;#x26;f=webp&quot; alt=&quot;我红温了！&quot;&gt;
&lt;/p&gt;
&lt;h2&gt;明知分差悬殊，仍是梦中情校&lt;/h2&gt;
&lt;p&gt;前文也提到过了，由于我朋友在南大上学，我对南大还是很心生向往的。于是，通过一些&lt;strong&gt;比较特殊&lt;/strong&gt;的手段，我走进了南大的校门。&lt;/p&gt;
&lt;p&gt;鼓楼校区并不大，但是建筑错综复杂，很容易迷路，再加上当时离我赶车前去杭州只有不到两个小时，我便只能一边慌张一遍匆匆浏览南大的风貌。&lt;/p&gt;
&lt;p&gt;&amp;#x3C;Masonry
breakpointCols={{ default: 3, 1024: 2, 640: 1 }}
class=&quot;flex gap-4 px-4&quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751033027039.BwhE7W3E.webp&amp;#x26;w=1306&amp;#x26;h=1142&amp;#x26;f=webp&quot; alt=&quot;南京大学1&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751033021216.jWhy34E9.webp&amp;#x26;w=1306&amp;#x26;h=1142&amp;#x26;f=webp&quot; alt=&quot;南京大学2&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751033014078.Cm3_gxmM.webp&amp;#x26;w=1306&amp;#x26;h=1142&amp;#x26;f=webp&quot; alt=&quot;南京大学3&quot;&gt;
&lt;/p&gt;
&lt;p&gt;虽然已经尽力赶时间了，但是千算万算，忘记了南京那时正值晚高峰，堵车啊朋友们！！！！&lt;/p&gt;
&lt;p&gt;于是，改签失败，被迫选了绕远路的换乘方案，好在最后还是平安抵达了杭州西。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2F1751033009982.BTvKm7XJ.webp&amp;#x26;w=1306&amp;#x26;h=1142&amp;#x26;f=webp&quot; alt=&quot;前往杭州&quot;&gt;&lt;/p&gt;
&lt;p&gt;总结我这几天的南京之行，确实过于走马观花了。行程安排也不合理。即使如此，我仍然感到充实和满足，学到了很多象牙塔里无法接触的处事法则。&lt;/p&gt;
&lt;p&gt;不过，如果有机会，我还会再回来，作为一个精神南京人，我还会选择一个风和日丽的日子，再次扑进这座六朝古都宽容、坚实而温柔的怀抱。&lt;/p&gt;
&lt;p&gt;至于杭州嘛，这篇游记实在给我写得累死了，等有时间再写杭州篇吧。&lt;/p&gt;
&lt;p&gt;感谢看到这里哦👋&lt;/p&gt;</content:encoded><h:img src="/_astro/cover.BeT3IvI0.webp"/><enclosure url="/_astro/cover.BeT3IvI0.webp"/></item><item><title>我的2024</title><link>https://crisq.top/blog/2024</link><guid isPermaLink="true">https://crisq.top/blog/2024</guid><description>2024年终总结</description><pubDate>Sun, 26 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;有点难以置信的是，整个2024，我几乎没有发布一篇博文......说实话有点难过，有点悲哀，但这也是没办法的嘛，毕竟高三了。今年其实没什么好说的，大部分时间在无穷无尽的作业，满溢出来的压抑氛围和一杯一杯灌下去的咖啡中度过，剩下的少量时间用来忙点自己的兴趣。前者在博客里发再多牢骚都是扯淡，还是写写后者吧。&lt;/p&gt;
&lt;h2&gt;买了一块智能表！&lt;/h2&gt;
&lt;p&gt;首先，今年令我最高兴的事情大概就是我有了一块智能表：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2Foppowatch.CCe_y3k9.webp&amp;#x26;w=3072&amp;#x26;h=4096&amp;#x26;f=webp&quot; alt=&quot;我的OPPO Watch 4 Pro&quot; title=&quot;我的OPPO Watch 4 Pro&quot;&gt;&lt;/p&gt;
&lt;p&gt;这块手表是OPPO Watch 4 Pro，我大概在11月购入，给了我剩下两个月极大的幸福感（因为我终于可以又网易云音乐和Spotify听歌听播客了！泪目。&lt;/p&gt;
&lt;p&gt;在没有这块表前，我用一个老旧的mp3播放器听歌，由于我住校，每周回家都得先下好自己收藏的播客，然后带到学校去听。然而大部分播客又恰好不是周末更新，每次只能听旧的，可实在是太难受了......举一个最直观的例子，有了这块表后，我终于可以准点听到每周三晚上更新的《半拿铁》了，两位主播的声音想起来那一刻感觉疲惫感都一扫而空了。Spotify的免费版14天会掉登录，在手机上还好说（进行一些科学处理），手表上可着实有点难受了，于是每两周不得不抽出一天来回家重新登录Spotify（这方面内容先按下不表），不过激活之后Spotify的体验堪称优秀，我喜欢的播客和音乐直接受藏到音乐库就可以随时收听了。Spotify Wear最近的一次更新还加入了搜索功能，这下好了，抛掉手机吧少年（笑）。&lt;/p&gt;
&lt;p&gt;另一个老大难的问题——记住每天作业有什么，有了手表上滴答清单的帮助，变成了每天下晚自习后对着手表想念咒一样自言自语”xxx写到xxx，xxx写完第xxx面“（其实是语音输入），彻底解放大脑嘿嘿~&lt;/p&gt;
&lt;p&gt;OPPO Watch还有欧路词典App，可以方便的查词，在英语课上别人都在查字典时瞬间把问题抢答的感觉，啧啧从来没有如此强大过~ &lt;strong&gt;然而，必须强调的一点是，我是设置了校园模式的，每天7:30到5:15都不能使用第三方App（白名单内除外，我的白名单只有滴答清单和欧路词典）。所以不要说我是坏孩子哦，我可是乖乖的~&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;18岁了 🍰！&lt;/h2&gt;
&lt;p&gt;成年啦！！！好感慨。&lt;/p&gt;
&lt;p&gt;成年前的最后一个周末回家时，父母给了我个”惊喜“——提前给我准备了”生日宴会“，然而我当天正好甲流，全都泡汤了~&lt;/p&gt;
&lt;p&gt;不过生日当天倒是在学校好好high了一把。中午的时候跑到校门口的蛋糕店买了整整十个蛋糕（ -200 ￥ ），提着到我膝盖那么大的袋子，走得那叫一个志得意满。收到了班主任的祝福（还请我吃了肯德基），给我开心坏了哈哈。朋友们也送了不少礼物，甚至有个哥们把自己斥巨资积攒的原神周边打包了一大盒送我（本人称之为“年轻时犯下的错误”），这下我这个不玩原神的反而被迫成了班上原神浓度最高的了🤣。另一个朋友同样斥巨资请我喝了杯星巴克，那叫一个感动，嘴角抑制不住地流下了泪水。&lt;/p&gt;
&lt;p&gt;18之后好多事可以干了，我记得我准点等到生日当天的00:00，打开我的表测了一次心电图（该功能仅年满十八周岁用户可用），看着窦性心律那个一跳一跳的图，心里还挺美。&lt;/p&gt;
&lt;h2&gt;我将建立健！康！的生活习惯（也许&lt;/h2&gt;
&lt;p&gt;12月初我立下雄心壮志要更改以前混乱不堪的作息习惯，从“12:30~6:30”改为“11：30~5:30”&lt;/p&gt;
&lt;p&gt;成功了吗？？没有。晚上始终睡不着，闭着眼睛感觉有困意，但不多。翻来覆去总感觉膈应，眼皮子闭上了又觉得想要睁开，那叫一个难受。躺到最后都躺出完美主义了，非要找到一个两手两脚都不觉得膈应的姿势才能罢休，一折腾下来又12:30了。早上即使早起也...不如不起，纯粹糟践自己。&lt;/p&gt;
&lt;p&gt;再一个就是早饭，本来我是不吃早饭的，但是又觉得还是随便吃点什么有助于不犯困，于是就买了点方便粥，结果第二天便利店就不卖方便粥了，抗拒之下只好拿起方便面（我讨厌方便面纯粹是因为它的调味吃起来泛酸而且不容易消退，搞得人很难受），果然还是不能接受呢~&lt;/p&gt;
&lt;p&gt;到底要不要“调整作息”，不知道，再看吧。&lt;/p&gt;
&lt;h2&gt;OneThing好文明&lt;/h2&gt;
&lt;p&gt;高三居然有元旦晚会，这是咱没想到的——既然要办，没办法，技术支持是肯定跑不了咱的。&lt;/p&gt;
&lt;p&gt;同学们发来歌曲要“降人声”，出于算力考虑，没有胆敢上自己这台只有集成显卡的小笔记本，去&lt;a href=&quot;https://onethingai.com/&quot;&gt;OneThingAI&lt;/a&gt;家租了台4090的服务器捣鼓了三小时多（ -7.64 ￥），用的是&lt;a href=&quot;https://github.com/SUC-DriverOld/MSST-WebUI&quot;&gt;MSST WebUI&lt;/a&gt;。提取人声后便是漫长的处理（这部分自然是操持上咱最爱的Reaper），不过这次倒是尝试了用LSP Studio出的Plugin Suite来做混音，效果极佳，太爱开源插件了！&lt;/p&gt;
&lt;p&gt;后来又来了各种奇奇怪怪的要求，什么把三首歌混一起，这首的副歌结束时直接无缝接下一首歌的副歌之类（......也都给实现了！&lt;/p&gt;
&lt;p&gt;当然，事后请几顿饭几杯星巴克是少不了的~&lt;/p&gt;
&lt;p&gt;import Audio from &apos;../../../components/Audio.astro&apos;&lt;/p&gt;
&lt;h2&gt;碰了Flutter和Jetpack，放弃了&lt;/h2&gt;
&lt;p&gt;有了表自然想着开发点手表上的应用。不得不吐槽OPPO官方的开发文档几乎就跟没有一样。一开始技术选型是Kotlin + Jetpack Compose，粗略地写了写后发现Compose这设计是真的优雅，直到我放了个LazyColumn上去，才发现这种设计方法带来的重组让LazyColumn默认状态下在手表上“一滑就卡”。上网搜了不少解决方案都没法解决，遂弃之。当然，并没有说Compose不好，只是我实在没有时间研究怎么让它跑在非WearOS设备上（我相信Wear Compose肯定已经优化得很好了，奈何用不了~）。&lt;/p&gt;
&lt;p&gt;所以，目光投向了Flutter + Rust这个我关注已久的方案上。不得不承认，&lt;a href=&quot;rinf.cunarist.com/&quot;&gt;Rinf&lt;/a&gt;是一个救人于水火的库，好用，推荐！唯一令人诟病的是Flutter这糟糕的语法，和Compose比起来确实太古朴了，颇有一种“声明式，但是不优雅”之感。由于时间不太够，也就没深究下去。2025等高考完可能会再捡起来玩玩。&lt;/p&gt;
&lt;h2&gt;今年最讨厌的词&lt;/h2&gt;
&lt;p&gt;就是挂在班主任嘴边的“按部就班”&lt;/p&gt;
&lt;p&gt;我甚至写了个段子，把班主任常说的词总结成了一句话，文段如下：&lt;/p&gt;
&lt;p&gt;这篇很规范很典型的文章告诉我们一定要按部就班的颗粒归仓。&lt;/p&gt;
&lt;p&gt;如果有碰巧和我同班的朋友看到这句话估计就...嘛，会心一笑了~&lt;/p&gt;
&lt;p&gt;好了，就写这么多吧。枯燥的一年也没什么可总结的，希望明年会更好。&lt;/p&gt;
&lt;p&gt;祝大家新春快乐呀~&lt;/p&gt;</content:encoded><h:img src="/_astro/cover.CsljT1W8.webp"/><enclosure url="/_astro/cover.CsljT1W8.webp"/></item><item><title>琴师</title><link>https://crisq.top/blog/guqin</link><guid isPermaLink="true">https://crisq.top/blog/guqin</guid><description>一篇写了有一段时间的小说</description><pubDate>Sun, 25 Aug 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;一&lt;/h2&gt;
&lt;p&gt;    初唐是个繁荣而动荡的矛盾时代，更别提最近还传着武后称帝的流言。&lt;/p&gt;
&lt;p&gt;    但龚羽没有感知到外界的纷扰，他只是每日坐在桌前画着图，在后院的桐木林中挑挑拣拣，间或做些刨锯活计谋生。在远离都城的小山上，苍翠掩映中，落着几幢古朴的宅子。那是龚家时代驻守的祖宅。&lt;/p&gt;
&lt;p&gt;    陇西龚氏，世代琴师出身，秦汉时期也曾显赫一时。凡其所制之琴，纹如润玉，弦比月辉，浑然天成。达官显贵为了求得龚氏瑶琴一把，无不竞相争抢，相传还闹出过人命官司，一度从郡守告到廷尉，惹得大人攥着卷宗左右为难。至于那晚照下拔起的未央宫中，花梨木架端御琴上醒目的龚字刻印，也无疑堪比一张不容质疑的金字招牌。家道中落后，父辈世代惦记着重振家业，做过许多尝试。然而，好琴须得良木，浑腔方出金鸣。苦于没有上好的桐木，数代人奔走四方，辛苦搜寻，从剑南和黔中带回了许多树种，回到陇西栽下，日夜呵护，仅留其品色俱佳者。如今他的祖宅后院中，就葱郁着他的不知多少代先祖汗水浇灌的成果。&lt;/p&gt;
&lt;p&gt;    陇西临近西域，自太宗朝始，往来的胡商把大量形制新颖的乐器带入中原。龚羽经常和这帮人打交道，因得以聆听品玩这些还未在唐朝流传开的异域之声。他知道，龚家数十代人坚守的梦想不能只通过一遍遍重复前人走过的老路实现，从他的父辈开始，两代人靠着人脉，寻了许多胡琴和琵琶，将其巧思融入古琴的设计中。稿纸像雪片般堆满半间房，龚羽知道，不需要再画了。他把成稿与父亲的棺椁葬在一处，孤身守着老宅。桐木饱汲风露，但少一天就是少一天，龚家等了四百年了，这事容不得性急。他想象着成琴在手里摩梭时的触感。他知道不能固守在陇西，他的目光看向太极宫所在的方向。&lt;/p&gt;
&lt;p&gt;    那座城在汉朝叫长安，随后的王权更替中改了不少次名，如今又叫回了长安。一如龚家忍辱负重的蛰伏，也该再度扬名了。&lt;/p&gt;
&lt;p&gt;    龚羽，由宫及羽，五音俱全；桐木，自汉至唐，经年始成。&lt;/p&gt;
&lt;h2&gt;二&lt;/h2&gt;
&lt;p&gt;    初阳匆匆穿过泛黄的琴谱，又顺着干硬的床板爬上后窗，掠过交错的树叶与层叠的枝条，将一缕缕辉光送至古铜色的树干上，为其鎏上一层内敛的暗金。龚羽比对一遍纪年簿上所载，第四百个春秋已然度过，他准备着手砍它了。&lt;/p&gt;
&lt;p&gt;    三更即起，昏昏灯下，颤颤笔端，早已烂熟于心的的琴稿转眼浮现，又附每个部件的精密结构与共鸣腔体的形态草案，甚至随绘了纹样与装饰的示例，一鸟一凤，一草一木皆循章法。他把琴体画得很大，上刻一个张扬的龚字，四周云纹绕带，双凰振羽，字形若龙行虎步，筋骨毕现。虽在纸上，但纸又怎承得下？他需得把这琴从笔墨中解救出来。于是斫、磨、涤、烤、染、拭，精益而求精；挑、抹、拨、合、点、闷，凡音必中律。春去秋来，龚羽本就银灰夹杂的头发已然全白，那五六捆桐木版也从与门奇高降至堪堪及腰，奇形怪状的半成品反而越堆越高。看着被自己挥霍的，旁逸而斜出的条条框框，他双手背后，笑得像一个天真的艺术家。又伏下身继续做琴，斧凿纷飞间，他下意识抬手擦汗，只触到自己干硬的布满皱纹的额头，大概是汗水已被吹散了。&lt;/p&gt;
&lt;p&gt;    铮然一声轻响，风月齐动，山林呼应，金铁交鸣。琴成。&lt;/p&gt;
&lt;p&gt;    向县里申请下过所文书后，他带上全部的家当，择好日子前去长安。临行前，他又去了一趟后院。被伐倒的树冠上年轮已看不分明，只剩短短一截桩，其侧刻着长短不一的十六条线。他摸着那些刻线，浅浅笑着，然后摇了摇头，从斑驳的回忆中抽身出来，像握笔一样握着刻刀，同他的十六代祖辈一般，斜斜刻下。&lt;/p&gt;
&lt;p&gt;    十七条线。&lt;/p&gt;
&lt;h2&gt;三&lt;/h2&gt;
&lt;p&gt;    数月的脚程，他终于站到了紧闭的长安城门下。&lt;/p&gt;
&lt;p&gt;    好不容易等到开远门前凝滞着的长队开始挪动，后面的胡商不耐烦地搡他一下：“磨磨蹭蹭，怕不是越度的！”。一阵浓烈而刺鼻的汗味惹他惊得不知所措，亦使他感到颇有些恍惚。他下意识把背着的琴换到胸前护住。琴还完好，他松了一口气。&lt;/p&gt;
&lt;p&gt;    京城自是与他世代隐居的小村别若云泥，林立的各坊险些使他迷路——绕居德、群贤，穿西市，走怀远、丰乐。朱雀大街突然扑进他逼仄的视野。此刻街上正人流如织，一片鼎沸的嚣嚣，他眺望远方，却连正对面的荐福寺都看不见。他不由地怯了。自幼不是与青灯做伴，就是枕琴谱而眠的他，所能耐的极闹便是夏虫的鼓噪，又怎见过这般烈火烹油的盛景。&lt;/p&gt;
&lt;p&gt;    整齐的鼓声开始响起，盖住了一切杂音——午时已到，市鼓三百下，贵公子们也该出门了。他需得加紧赶往东市——沿路走，沿路打听，他早就知道东市是上层人物出入的豪富场所。至于自己，休说绫罗锦缎，就连穿上一套体面的圆领袍靴都是奢望。注视着贴在自己身上的灰白麻布短打，他把琴抱得更紧了。&lt;/p&gt;
&lt;p&gt;    安仁、长兴两坊，他几乎是全速跑过去的。待他在东市前停住脚步，市门早已大开，扑面而来的便是商贩叫卖的声浪。他犹豫地后退一步，但琴却没有后退，于是他便又很快迈了回去。低着头，从商铺和摊贩的缝隙中小心翼翼地经过，找到一片还算空旷的地界。微微颔首，他把包着琴的裹布解开。&lt;/p&gt;
&lt;p&gt;    那只粗砺的手攀上弦，他拍了拍他的友人，像在为他饯行。而后，他将手虚虚勾起，搭在弦上。&lt;/p&gt;
&lt;p&gt;    铮！&lt;/p&gt;
&lt;p&gt;    时光突然湍急了起来，人们都不约而同回过头，被这未尝听过的音色震住。说是瑶琴之音，却能奏得干净利落，一拨一按间当断即断，清脆若黄鹂啼露；说是胡琴之音，却又音色雅正，婉转流泻，轻轻一扫便余音不绝。人们激动起来，狂热地拥向他，叫嚷着不同的话语，他几乎要耳鸣。&lt;/p&gt;
&lt;p&gt;    他费力推开人群，与另一只拨开人群的手相遇。那是一位穿着青衣的带玉公子。&lt;/p&gt;
&lt;p&gt;    龚羽有些不知所措，想要开口询问是否有意购琴，却又觉得不能失礼，只能嗫嚅着整理他那身毫无必要整理的短褂：“这位公子，可有购琴之意？”。&lt;/p&gt;
&lt;p&gt;    那人直勾勾盯着琴，眼神中闪烁着难以压抑的兴奋。他的手紧紧攥着袖子，在沉默中思考着什么。不久后，他似突然想到了什么，松开了紧攥的手，转过身对着簇拥的人群，朗声说道：“某陈子昂，蜀中人士，善音律，久苦无良桐以奏，成美琴之名，今幸得逢佳琴于斯，莫非天意？诸君，何不明日偕往宣阳里，子昂愿与诸位共赏妙音，听琴品茗岂不快哉？”&lt;/p&gt;
&lt;p&gt;    温和大方的笑容出现在他脸上，如果龚羽没有察觉到他抿紧的嘴唇。&lt;/p&gt;
&lt;p&gt;    “琴师， 休说此琴何值， 子昂愿倾某所有， 但求成全。”&lt;/p&gt;
&lt;p&gt;    他似乎在对他说话，但却没有看着他。周围喧起震天的喝彩声，但却也没有人看着他。&lt;/p&gt;
&lt;p&gt;    他的头被震得发昏，只站在远处，痴痴地笑着。&lt;/p&gt;
&lt;h2&gt;四&lt;/h2&gt;
&lt;p&gt;    宣阳坊就在东市旁边，几步路便可赶去。&lt;/p&gt;
&lt;p&gt;    隆隆的鼓声再次伴着山间的半朵夕阳响起，他户籍不在长安，坊正自然不会放他进坊，在长安又无亲眷朋友，只能奔着寺院去了。他想起朱雀大街旁的荐福寺，心下决定到寺中投宿一晚。街鼓八百下，足够他慢慢走过去。&lt;/p&gt;
&lt;p&gt;    各坊的门在他身后重重关上，行人以肉眼可见的速度迅速减少。天色黑得很快，暗青的夜空逐渐在一片橙红中晕开，金色的晚霞漂浮在云间，打着旋向天边的远山绵延，一点点暗淡下去。&lt;/p&gt;
&lt;p&gt;    禅房内的灯火算不上明亮。他注视着跳动的火苗，一言不发。&lt;/p&gt;
&lt;p&gt;    夜半的风涛中，他曾想起自己的父亲，父亲的父亲。他想起自己幼时在桐木下与父亲玩笑，抚摸着树冠上的刻痕，嫌弃它们刻得太乱，父亲的面容却突然严肃起来，毫不犹豫对他一顿训斥。那是他第一次意识到这些老树在父亲眼里的地位。他又想起父亲弹琴时无意中跟他讲到过的伯牙绝弦的故事。&lt;/p&gt;
&lt;p&gt;    “岂不愚乎？市之即好呀，何必摔呢？”&lt;/p&gt;
&lt;p&gt;    “倘少一子期， 又何有伯牙之名乎？ 没了子期的伯牙， 没了子期的琴， 卑如尘土而已。 ”&lt;/p&gt;
&lt;p&gt;    但求成全啊......&lt;/p&gt;
&lt;p&gt;    那一袭青衣又浮现在他眼前，他的嘴角情不自禁挂起了笑。他似乎看到老屋后一圈圈的年轮流淌下来，流过山川河流，流进钟鼎府上、朱门堂中。龚氏的名声享誉四方，龚家的子弟再一次穿上绫罗绸缎，环翠佩锦，出入在庙堂之高。夜风打着寺院内的芭蕉，他似乎听到琴声从四面八方涌来，铮然齐响......&lt;/p&gt;
&lt;p&gt;    和衣而卧，一夜未眠。&lt;/p&gt;
&lt;h2&gt;五&lt;/h2&gt;
&lt;p&gt;    第一声报晓鼓还是如期响起来了。&lt;/p&gt;
&lt;p&gt;    南北向的每条大街上，鼓楼迅速响应起来，鼓声由内而外依次传开。城内的一百几十所寺庙逐个撞响晨钟，交相辉映。这座沉睡的古都在绵长的钟声里迎来了第一缕阳光。寺门，坊门，市门齐齐打开。定格的长安城里，时间再次流动了起来。&lt;/p&gt;
&lt;p&gt;    龚羽揉了揉红肿的眼，他睡不着，他太盼望着亲眼见证自己的琴被弹响了。&lt;/p&gt;
&lt;p&gt;    从荐福寺所在的开化坊走到陈子昂所在的宣阳坊，也就一两柱香的功夫，但他却唯恐误时，寺门未开便守在门口，还遭了守夜的沙弥几句呵斥。&lt;/p&gt;
&lt;p&gt;    待他气喘吁吁来到宣阳坊时，酒席已经摆开了，各色人等穿梭于杯盏之间，觥筹交错，谈笑风生。陈子昂穿着水色的圆领袍，衣裾在风中摆动，他昂着头，站在正中央的圆台上，自信而捎带狂狷地笑着。龚羽被他感染，也不由地挂起了浅浅的笑。很快各式华贵的轿子款款而来，“武攸宜！”人群之中掀起不小的骚动。宫羽从没听过那个名字。&lt;/p&gt;
&lt;p&gt;    “诸君！今日云集宣阳里，是子昂之幸。特设好酒菜相宴，诸位莫言且尽杯盏！”言之激动处，他将酒狠狠泼在了地上，仰天而笑。&lt;/p&gt;
&lt;p&gt;    琴被抬上来了。龚羽屏住了呼吸。&lt;/p&gt;
&lt;p&gt;    “某，陈子昂，字伯玉。梓州射洪人士......”陈子昂的声音忽然变得严肃起来。不知为何，龚羽觉得气氛有些不对了起来。&lt;/p&gt;
&lt;p&gt;    “某有文百轴，以为才情卓然，针砭时弊。”他举起一卷写满小字的卷轴，展示给前排的众人看， 又回身捧出数卷文稿， 分发给前排的人们，陈子昂的手不住颤抖着， 紧紧抿起了嘴。“琴呢？妙音又在何处？”后排有好事者嚷起来，旋即被同伴推搡着制止。然而，陈子昂转过了头。他胜券在握的表情突然绷紧了起来。&lt;/p&gt;
&lt;p&gt;    “琴？ 某驰走京毂，如碌碌尘土， 竟无人知我！何也？ 若无此琴，子昂之心， 恐历一世而终不得成全啊！”陈子昂的语气竟带上些许愤怒的尖音，面色激动得发红， 令围观者颇有些悚然起来， 龚羽想到了自家曾经显赫的名声， 觉得心酸起来。但他还是耐心听了下去。“文章经世，声名通达，此子昂毕生之理想！大道如青天，余何独不能出？盛世此朗朗，余何独寂尘土！”琴上覆盖的绢布忽然被掀了起来。&lt;/p&gt;
&lt;p&gt;    烈日照在了陈子昂的面庞上，他的眼睛隐没在阴影中。&lt;/p&gt;
&lt;p&gt;    喧哗逐渐平息了下来，人们屏住呼吸。路过的风也跟着屏住呼吸，按住了柳条的摆动，枝头的夏虫也察觉到了气氛的凝重，当即也屏了息，四下陷入了一片寂静。人们都等待着陈子昂接下来的话。龚羽想走上前去，他已经觉察到事情的不妙，但人群拥成一团，似乎每个人都在阻挠着他。他张开嘴，想喊些什么，却只听到自己沉重的喘息声。&lt;/p&gt;
&lt;p&gt;    陈子昂举起了琴，轻轻抚了抚它光洁的琴身，又把手搭上了弦，作出试音的动作。他的眼睛自始至终没有看向琴师。也许他根本没察觉到他的到来。他突然开口了。&lt;/p&gt;
&lt;p&gt;    “琴， 难道比文章， 更能济世救民吗？”&lt;/p&gt;
&lt;p&gt;    “此乐， 不过贱工之役，岂宜留心？ ”&lt;/p&gt;
&lt;p&gt;    他举起琴，直勾勾盯着它，却毫不犹豫。他手臂上肌肉鼓起，青筋暴现。&lt;/p&gt;
&lt;p&gt;    他把琴重重砸在了地上。&lt;/p&gt;
&lt;p&gt;    轰的一声，所有弦被同时砸响，龚羽听到琴声嘶力竭的哀鸣。&lt;/p&gt;
&lt;p&gt;    流泻而下的云纹被从中间劈断， 裂痕似一道劫雷，斩下琴上凤凰的头颅，撕开龙虎的爪牙，继续蔓延，直至贯穿琴上的龚字刻印。烟尘飞扬起来，旋在四分五裂的琴周围， 只呜呜的啸着。&lt;/p&gt;
&lt;p&gt;    他眼前倏地一黑，坊间林立的楼宇缓慢倒塌，而那圈从老树上流淌下的年轮也在他脚下骤然绷断。他失去了立足点，双腿发软跌坐在地上。他的眼睛睁得滚圆，把眼角扯得生疼。但他没有办法流泪。&lt;/p&gt;
&lt;p&gt;    他的耳边，回荡起了那句但求成全。&lt;/p&gt;
&lt;h2&gt;补&lt;/h2&gt;
&lt;p&gt;本文成于 2024 年 5~6 月左右，当时是在阅读题上看见马伯庸《长安的荔枝》选段，突然来的灵感。遍在一节晚自习草草挥笔。感谢我的语文老师刘老师愿意耐着性子看完，真诚分享感受，也感谢我的另一位恩师姚老师一针见血的指点，每每直指要害，条分缕析，让我拍案叫绝。&lt;/p&gt;
&lt;p&gt;成文后本来是准备见诸报端的，想投《青年文摘》又怯懦犹疑，最终在对被拒稿的恐惧中按下了取消键；后又辗转投了诸如《沙地》之类的几家纯文学杂志，也渺无音信。大抵是学艺不精，或是缘法未到吧。索性也就整理整理，直接发在博客上，供读者一笑，也不失为一桩美事。&lt;/p&gt;
&lt;p&gt;25 年 6 月，高考失利，整理博客时删掉了除年终总结之外的所有文章，本文也于那次大清洗中罹难，同年八月意欲前往苏州游展，忽然想起这篇拙作，也就再次动笔，稍事打磨，尽量尊重原文，瑕疵之处若无伤大雅，也一并也予以保留。才疏学浅，不敢称什么作品，也就是权当留个纪念，当作我青葱岁月的一段刻印，便知足也。&lt;/p&gt;</content:encoded><h:img src="/_astro/cover.Y2BA83cE.webp"/><enclosure url="/_astro/cover.Y2BA83cE.webp"/></item><item><title>也许我们还缺一个年终总结</title><link>https://crisq.top/blog/2023</link><guid isPermaLink="true">https://crisq.top/blog/2023</guid><description>2023年终总结</description><pubDate>Sun, 21 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;转眼间又是一年匆匆过去，今天是一月 21 日，元旦已经远去。也许如果不逼着自己写点什么，我的 2023 就会如一阵烟雾消散在我的回忆里吧。于是，2022 的年终总结似乎还余温犹存，2023 的年终总结就已经不得不动笔了。&lt;/p&gt;
&lt;p&gt;今年的时间主要还是在学校里度过。四月份的时候帮着我们班开展了一次“广受好评”的班会，甚至在全校多次“公演”。还记得我为此几乎熬了一周的通宵，每天都怀着忐忑而兴奋的心情期待着第二天的排练和新的 mindstorm。虽然很累，但却因为是自己喜欢的事情而倍感充实。&lt;/p&gt;
&lt;p&gt;说起来，在学校的日子里倒是经常往语文办公室跑，却不是为了学习，而是去帮忙剪视频——班主任的教学比赛视频，同学的校园安全宣传视频，艺术节的班级节目混音小 set......来来回回反而成了办公室的常客，跟许多老师都混熟了。时不时还能找班主任要点小零食走（2333....&lt;/p&gt;
&lt;p&gt;今年的写作兴致也还算高，在作文本上留下了不少有意思的随笔，晚自习还偷偷摸鱼写了篇文言小品。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2Farticle.DAYHp74a.webp&amp;#x26;w=1400&amp;#x26;h=1231&amp;#x26;f=webp&quot; alt=&quot;拙劣模仿一下蒲松龄&quot;&gt;&lt;/p&gt;
&lt;p&gt;我曾经在 About 页面里说过，我是一个开发者，也是一个音乐制作人，我想今年的我更多偏向后一重身份。今年的 Gitlab 活跃度几乎没有，一方面是因为学业突然变得紧张，一方面在于认识了不少音乐人朋友，和他们的交流与合作让我的重心逐渐偏向了这块。&lt;/p&gt;
&lt;p&gt;大概是今年四五月份吧，我认识了 AritxOnly 同学（现在是一位南京大学的学生），他当时是一名高三学生，也是一位 Bass Music 爱好者。他带我探索了 Sound Design 的广阔世界，教会了我很多，也与我合作了几首作品。感谢他的陪伴，让我受益良多。虽然我仍不能算作一个成熟的制作人，水平也十分拙劣，但至少我感觉到自己的思绪有了一个倾诉的途径，有了一个表达的窗口。&lt;/p&gt;
&lt;p&gt;本来我们有一首合作单曲，准备在元旦那天准时发行，但是因为一些原因，可能会在一月下旬发布，年终总结里没写完的话，就交给音乐去诉说吧。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://crisq.top/_image?href=%2F_astro%2Falbum.B3ZUyT4r.webp&amp;#x26;w=700&amp;#x26;h=700&amp;#x26;f=webp&quot; alt=&quot;album&quot;&gt;&lt;/p&gt;</content:encoded><h:img src="/_astro/cover.DatVo22b.webp"/><enclosure url="/_astro/cover.DatVo22b.webp"/></item><item><title>年末随笔</title><link>https://crisq.top/blog/2022</link><guid isPermaLink="true">https://crisq.top/blog/2022</guid><description>2022年终总结</description><pubDate>Sun, 25 Dec 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;今年于我而言是很难忘的一年，写个流水账追忆一下。&lt;/p&gt;
&lt;p&gt;上半年我度过了我的初三。那是一段很累但很快乐的时光。初三的晚自习有三个多小时，我们就偷偷下位互相讨论题目，大部分时候会争得面红耳赤，然后带着怨气比做题速度。那时班上还喜欢提前写作业，各科作业都有。我个人更偏好写数学，曾经和当时的同桌比拼，一晚上写了十多面平面几何。你愿意说卷那就是卷吧，不过大概只是喜欢做题时的思考，品出了一些乐趣而已。&lt;/p&gt;
&lt;p&gt;我最享受的一段时间，就是每次吃完午饭后，我独自漫步在校园，看着走廊上慵懒靠着的同学们，午后的暖阳给他们的发梢和眼角镀一层金边，也染白了教学楼不再笔直的轮廓线。我的初中校园不大，在我们班门口的走廊往外看便能看到校门口。傍晚十分，我就会靠在走廊的栏杆上，看着短短一段路上形形色色的人们，当然，有时也会被“青春”的气息狠狠刺痛，暗骂一句烧死那对狗男女。&lt;/p&gt;
&lt;p&gt;中考那几天阴雨连绵，为了方便往返考场，我在考场附近的酒店暂住。那时我独住在一间房，特别喜欢戴上耳机，静静看着窗外的灯火和江面。每当看到江面上闪烁的光影和路边车流构成的灯河，就莫名对生活又产生了憧憬。大概是烟火气又飘进了心中吧，现在想来，那几天真是充满了诗意。&lt;/p&gt;
&lt;p&gt;后来的那个暑假，是陪着一位“特殊的友人”走过的。我们一起去了北京，在故宫和天坛留下一段足迹，也涌入前门大街和太古里的人海。那也算是我第一次脱离父母，独自远行。在连续几个月网课的当下，这着实是一段弥足珍贵的回忆。&lt;/p&gt;
&lt;p&gt;九月如期而至，高中生活莽莽撞撞地到来。在措手不及中又迎来网课的变故，期中考的取消，分科的纠结。下半年的日子一下子不好过了起来。索性，在线下教学的那些日子里，花园似的校园，同学间的互动和友谊，还有每天在办公室门口“踩点”的经历，或多或少总算还是给予了我些慰藉。&lt;/p&gt;
&lt;p&gt;不过，高中伊始，一切似乎都还充满不确定性。我似乎正陷入自我怀疑的摇摆中，不敢贸然踏出一步。哦，还有。十二月天寒地冻，我顺带还被新冠蹂躏了一波，真的很难受，希望别再得了。&lt;/p&gt;
&lt;p&gt;在彷徨，焦虑和虚无感中，我提起笔，四处寻找欢乐，充实和幸福感。&lt;/p&gt;
&lt;p&gt;送别2022,希望新年更好。&lt;/p&gt;</content:encoded><h:img src="/_astro/cover.BlckGtvN.webp"/><enclosure url="/_astro/cover.BlckGtvN.webp"/></item></channel></rss>