<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <author>
    <name>dumpbuss</name>
  </author>
  <generator uri="https://hexo.io/">Hexo</generator>
  <id>https://unkn0wn.cc/</id>
  <link href="https://unkn0wn.cc/" rel="alternate"/>
  <link href="https://unkn0wn.cc/atom.xml" rel="self"/>
  <rights>All rights reserved 2026, dumpbuss</rights>
  <subtitle>empty</subtitle>
  <title>unkn0wn</title>
  <updated>2026-11-01T23:02:45.863Z</updated>
  <entry>
    <author>
      <name>dumpbuss</name>
    </author>
    <content>
      <![CDATA[<p>由于笔者是一个<a href="https://m.qidian.com/ask/qpepevxtupe">活在过去的人</a>, 近日在使用发布于 2025 年的 <a href="https://t.me/s/qq_updatelog?q=38711">QQ 9.9.21-38711</a> 安装 LiteLoaderQQNT 1.4.1 时出现了登录后约 <a href="https://www.bilibili.com/video/BV1YdxVzkEe3/">0.08 分</a>钟后自动退出登录并跳回登录页面的问题。在进行一些分析和 logging 并与 <a href="https://claude.ai/">Claude</a> <a href="https://platform.claude.com/docs/en/models/opus-5-5/overview">Opus 5.5</a> xhigh (<a href="https://claude.ai/upgrade?recommendedPlan=max&amp;src=plan_intent">Max Plan</a>) 进行简单<a href="https://www.anthropic.com/legal/aup">交流</a>后花费<a href="https://zh.wikipedia.org/zh-cn/GUNDAM%E7%B3%BB%E5%88%97">高达</a>少于 <a href="https://ja.hinative.com/questions/6830605">8 分</a>钟的时间修复了此问题, 且为了记录将解决方案分享到此文章。</p><h2 id="简要分析"><a class="markdownIt-Anchor" href="#简要分析"></a> 简要分析</h2><h3 id="appquit-的调用-stack-trace"><a class="markdownIt-Anchor" href="#appquit-的调用-stack-trace"></a> app.quit 的调用 stack trace</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">2026-11-01T18:47:12.902Z [pid 27124 +8819ms] !!! app.quit []  </span><br><span class="line">        at S (C:\Program Files\Tencent\QQNT\versions\9.9.21-38711\resources\app\application.asar\17.background.js:1:1368379)</span><br><span class="line">        at BrowserWindow.&lt;anonymous&gt; (C:\Program Files\Tencent\QQNT\versions\9.9.21-38711\resources\app\application.asar\17.background.js:1:1371148)</span><br><span class="line">        at BrowserWindow.emit (node:events:530:35)</span><br></pre></td></tr></table></figure><p>通过日志记录调用栈不难发现，<code>17.background.js</code> 多次调用了 <code>app.quit</code> <code>app.relaunch</code> 等方法，基本确定是这个 JS 手动触发退出而非 LiteLoader 本体报错崩溃。</p><p>进一步对其进行插入脚本分析:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">2026-11-01T19:36:38.480Z [pid 23024 +6761ms]   [region 1367811] hash.update([&quot;QQ:unsafe check&quot;]) -&gt; [Hash] &#123;&#125; </span><br><span class="line">          at i (C:\Program Files\Tencent\QQNT\versions\9.9.21-38711\resources\app\application.asar\17.background.js:1:1367811)</span><br><span class="line">          at v (C:\Program Files\Tencent\QQNT\versions\9.9.21-38711\resources\app\application.asar\17.background.js:1:1368181)</span><br><span class="line">          at C:\Program Files\Tencent\QQNT\versions\9.9.21-38711\resources\app\application.asar\17.background.js:1:1371849</span><br><span class="line">          at D.bindWinEvents (C:\Program Files\Tencent\QQNT\versions\9.9.21-38711\resources\app\application.asar\17.background.js:1:1372175)</span><br><span class="line">          at new D (C:\Program Files\Tencent\QQNT\versions\9.9.21-38711\resources\app\application.asar\17.background.js:1:1374307)</span><br><span class="line">          at new D (C:\Program Files\Tencent\QQNT\versions\9.9.21-38711\resources\app\application.asar\553.background.js:1:51140)</span><br><span class="line">          at Object.getWindow (C:\Program Files\Tencent\QQNT\versions\9.9.21-38711\resources\app\application.asar\17.background.js:1:1263845)</span><br></pre></td></tr></table></figure><p>可见 <code>QQ:unsafe check</code> 字样，且对 QQ 进程进行快照里也包含此字样，确定为此版本 QQ 的防篡改，且 LiteLoader 群内的替换 <code>dbghelp.dll</code> 与 <code>QQ.exe</code> 均没有解决此版本 QQ 上的此问题（有可能是不进行向下兼容故没有处理）。</p><h3 id="读取-globalthisliteloader"><a class="markdownIt-Anchor" href="#读取-globalthisliteloader"></a> 读取 globalThis.LiteLoader</h3><p>同样方式查出疑似 QQ 对 LiteLoader 的读取:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">2026-11-01T19:11:16.209Z [pid 18368 +39750ms] LiteLoader getter denied Error</span><br><span class="line">    at get (...LiteLoaderQQNT\src\main\api.js:49:111)</span><br><span class="line">    at C:\Program Files\Tencent\QQNT\versions\9.9.21-38711\resources\app\application.asar\17.background.js:1:1371985</span><br><span class="line">    at D.bindWinEvents (C:\Program Files\Tencent\QQNT\versions\9.9.21-38711\resources\app\application.asar\17.background.js:1:1372175)</span><br><span class="line">    at new D (C:\Program Files\Tencent\QQNT\versions\9.9.21-38711\resources\app\application.asar\17.background.js:1:1374307)</span><br></pre></td></tr></table></figure><p>对比 1.3.1 和 1.4.1 的代码后发现，<code>globalThis.LiteLoader</code> 在1.4.0+ 是一个 getter:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">Object.defineProperty(globalThis, &quot;LiteLoader&quot;, &#123;</span><br><span class="line">    get() &#123;</span><br><span class="line">        const stack = new Error().stack.split(&quot;\n&quot;)[2];</span><br><span class="line">        const allowed = [LiteLoader.path.root, LiteLoader.path.profile];</span><br><span class="line">        return allowed.some((item) =&gt; stack.includes(item)) ? LiteLoader : null;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>如果调用者不在白名单内，1.4.x 会返回 <code>null</code>，而 1.3.1 调用返回的为 <code>undefined</code> 。</p><h3 id="读取-_getpreloadpaths0"><a class="markdownIt-Anchor" href="#读取-_getpreloadpaths0"></a> 读取 _getPreloadPaths[0]</h3><p>对 1.3.x 和 1.4.x 的代码 diff 后发现另一处差异:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"># <span class="number">1.4</span><span class="number">.1</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">proxyPreload</span>(<span class="params">func</span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (func?.<span class="property">name</span> == <span class="string">&quot;_getPreloadPaths&quot;</span>) <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Proxy</span>(func, &#123;</span><br><span class="line">        <span class="title function_">apply</span>(<span class="params">target, thisArg, argArray</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> [</span><br><span class="line">                path.<span class="title function_">join</span>(<span class="title class_">LiteLoader</span>.<span class="property">path</span>.<span class="property">root</span>, <span class="string">&quot;./src/preload/api.js&quot;</span>),</span><br><span class="line">                path.<span class="title function_">join</span>(<span class="title class_">LiteLoader</span>.<span class="property">path</span>.<span class="property">root</span>, <span class="string">&quot;./src/preload/module.js&quot;</span>),</span><br><span class="line">                ...<span class="title class_">Reflect</span>.<span class="title function_">apply</span>(target, thisArg, argArray)</span><br><span class="line">            ];</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;);</span><br></pre></td></tr></table></figure><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"># <span class="number">1.3</span><span class="number">.0</span></span><br><span class="line">    <span class="variable language_">window</span>.<span class="property">webContents</span>.<span class="property">_getPreloadPaths</span> = <span class="keyword">new</span> <span class="title class_">Proxy</span>(<span class="variable language_">window</span>.<span class="property">webContents</span>.<span class="property">_getPreloadPaths</span>, &#123;</span><br><span class="line">        <span class="title function_">apply</span>(<span class="params">target, thisArg, argArray</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> [</span><br><span class="line">                ...<span class="title class_">Reflect</span>.<span class="title function_">apply</span>(target, thisArg, argArray),</span><br><span class="line">                path.<span class="title function_">join</span>(<span class="title class_">LiteLoader</span>.<span class="property">path</span>.<span class="property">root</span>, <span class="string">&quot;src/preload.js&quot;</span>)</span><br><span class="line">            ];</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;);</span><br></pre></td></tr></table></figure><p>1.4.1 的 preload path 里，LiteLoader 的 preload 在 QQ 前面，而 1.3.0 的则在 QQ 后面。</p><p>胁迫 Claude 对此进行分析后得出:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">D.bindWinEvents           17.background.js:1:1372175</span><br><span class="line">  └ 检查函数（匿名，SFI 539499）</span><br><span class="line">      ├ 1371785  e.webContents._getPreloadPaths()</span><br><span class="line">      ├ 1371763  p.resolve(&lt;上一步结果&gt;[0])</span><br><span class="line">      ├ 1371815  .startsWith(&quot;C:\Program Files\Tencent\QQNT\versions\9.9.21-38711\resources\app\application.asar\&quot;)</span><br></pre></td></tr></table></figure><p>QQ 会判断 <code>_getPreloadPaths()[0]</code> 是否位于其本体的 <code>application.asar</code> 下，如果不是依旧会触发风控。</p><h2 id="解决方案"><a class="markdownIt-Anchor" href="#解决方案"></a> 解决方案</h2><h3 id="修改-srcmainapijs"><a class="markdownIt-Anchor" href="#修改-srcmainapijs"></a> 修改 src/main/api.js</h3><p>45 行附近:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="title class_">Object</span>.<span class="title function_">defineProperty</span>(globalThis, <span class="string">&quot;LiteLoader&quot;</span>, &#123;</span><br><span class="line">    <span class="title function_">get</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">const</span> stack = <span class="keyword">new</span> <span class="title class_">Error</span>().<span class="property">stack</span>.<span class="title function_">split</span>(<span class="string">&quot;\n&quot;</span>)[<span class="number">2</span>];</span><br><span class="line">        <span class="keyword">const</span> allowed = [<span class="title class_">LiteLoader</span>.<span class="property">path</span>.<span class="property">root</span>, <span class="title class_">LiteLoader</span>.<span class="property">path</span>.<span class="property">profile</span>];</span><br><span class="line">        <span class="keyword">return</span> allowed.<span class="title function_">some</span>(<span class="function">(<span class="params">item</span>) =&gt;</span> stack.<span class="title function_">includes</span>(item)) ? <span class="title class_">LiteLoader</span> : <span class="literal">undefined</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><h3 id="修改-srcmainhookjs"><a class="markdownIt-Anchor" href="#修改-srcmainhookjs"></a> 修改 src/main/hook.js</h3><p>20 行附近 :</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">proxyPreload</span>(<span class="params">func</span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (func?.<span class="property">name</span> == <span class="string">&quot;_getPreloadPaths&quot;</span>) <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Proxy</span>(func, &#123;</span><br><span class="line">        <span class="title function_">apply</span>(<span class="params">target, thisArg, argArray</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> [</span><br><span class="line">                ...<span class="title class_">Reflect</span>.<span class="title function_">apply</span>(target, thisArg, argArray),</span><br><span class="line">                path.<span class="title function_">join</span>(<span class="title class_">LiteLoader</span>.<span class="property">path</span>.<span class="property">root</span>, <span class="string">&quot;./src/preload/api.js&quot;</span>),</span><br><span class="line">                path.<span class="title function_">join</span>(<span class="title class_">LiteLoader</span>.<span class="property">path</span>.<span class="property">root</span>, <span class="string">&quot;./src/preload/module.js&quot;</span>)</span><br><span class="line">            ];</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;);</span><br></pre></td></tr></table></figure><p>修改后进行测试，再无重启现象。插件加载正常。</p>]]>
    </content>
    <id>https://unkn0wn.cc/2026/11/02/liteloader-fix/</id>
    <link href="https://unkn0wn.cc/2026/11/02/liteloader-fix/"/>
    <published>2026-11-02T05:00:18.000Z</published>
    <summary>
      <![CDATA[<p>由于笔者是一个<a href="https://m.qidian.com/ask/qpepevxtupe">活在过去的人</a>, 近日在使用发布于 2025 年的 <a href="https://t.me/s/qq_updatelog?q=38711">QQ 9.9.2]]>
    </summary>
    <title>修复 LiteLoaderQQNT 1.4.x 在旧版 QQ 3xxxx 的登录闪退</title>
    <updated>2026-11-01T23:02:45.863Z</updated>
  </entry>
</feed>
