<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>iolaSay</title><description>影言 · 个人博客</description><link>https://678234.xyz/</link><follow_challenge><feedId>59899165476559872</feedId><userId>59826467493052416</userId></follow_challenge><item><title>我分析了 11 万局王者对局，发现一些有趣的事情</title><link>https://678234.xyz/2026/07/28/WZRY-Analysis-2/</link><guid isPermaLink="true">https://678234.xyz/2026/07/28/WZRY-Analysis-2/</guid><pubDate>Tue, 28 Jul 2026 14:30:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;声明：本文只记录个人设备和本人账号上的分析过程，包含 AI 辅助创作，可能会带来一定的不适感，谨慎阅读。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;2019 年，我写过《&lt;a href=&quot;https://678234.xyz/2019/04/11/WZRY-Analysis/&quot;&gt;抓取、分析王者荣耀高分段战绩&lt;/a&gt;》和《&lt;a href=&quot;https://678234.xyz/2019/06/14/WZRY-Analysis-1/&quot;&gt;王者荣耀数据分析 1&lt;/a&gt;》。那次靠王者营地跑了两个月，拿到 6.5 万局和 34.6 万名玩家。&lt;/p&gt;
&lt;p&gt;七年后，我把数据入口换到了游戏客户端。上一篇《&lt;a href=&quot;https://678234.xyz/2026/07/26/WZRY-Protocol-Hook/&quot;&gt;从抓包到改字段&lt;/a&gt;》里，我在游戏进程中拦截收发消息，把对局结算和玩家档案读成 JSON，再让客户端查询玩家近期战绩。&lt;/p&gt;
&lt;p&gt;每次查询最多返回最近 50 局，每局还能带出九名同局玩家。陌生玩家会进入待查队列，查询沿着同局关系继续展开。&lt;/p&gt;
&lt;p&gt;截至 2026 年 7 月 29 日，库里共有 600,987 名玩家、118,781 局对局和 1,176,669 条参战记录，其中 6,521 名玩家有档案，共留下 6,553 份档案快照。对局覆盖一千多个大区。&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/collection-overview-8c2643f1d3dd-768w.webp 768w, https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/collection-overview-8c2643f1d3dd-1536w.webp 1536w&quot; sizes=&quot;(max-width: 800px) 100vw, 760px&quot;&gt;&lt;img src=&quot;https://678234.xyz/upload/images/2026-07-28-WZRY-Analysis-2/collection-overview.png&quot; alt=&quot;当前采集概览，包含玩家、档案、对局和参战记录数量&quot; decoding=&quot;async&quot; width=&quot;2844&quot; height=&quot;1600&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;先说几条最值得看的结果。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;游戏的真实响应里确实有官方 AI 标记。它们带正常 uid、大区、昵称和段位，外观上足以伪装成真人。&lt;/li&gt;
&lt;li&gt;排位中有 1,842 局出现一整队五名伪人，它们的胜率只有 4.45%。有一名玩家在 48 局里遇到 23 次这种对手，拿走 22 胜。&lt;/li&gt;
&lt;li&gt;完整五排比五个散人平均早 1 分 32 秒结束。&lt;/li&gt;
&lt;li&gt;游戏响应还带有普通界面看不到的 MMR 和 ELO。它们与累计星数的相关系数接近 1，渠道、手机系统和大区之间也能看到清楚的差异。&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;声明：本文只分析个人设备和个人账号可以查询到的数据，不发布采集代码。查询从高星玩家附近开始，样本无法当作全服统计。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;先来个劲爆的。&lt;/p&gt;
&lt;h2 id=&quot;游戏里确实有伪人&quot;&gt;游戏里确实有伪人&lt;/h2&gt;
&lt;p&gt;《王者荣耀》玩家很早就在怀疑，排位会安排人机伪装成真人。过去的讨论常靠昵称、头像、英雄选择和走位猜测，很难确认。&lt;/p&gt;
&lt;p&gt;这次我从客户端收到的真实响应里读到了 &lt;code&gt;bIsAI&lt;/code&gt;。部分参战者的 &lt;code&gt;world&lt;/code&gt; 大于 0，有正常 uid、大区、昵称和段位，&lt;code&gt;bIsAI&lt;/code&gt; 却带着非零值。本文把这类身份叫作「伪人」；&lt;code&gt;world=0&lt;/code&gt; 或对局带 &lt;code&gt;bPkAI&lt;/code&gt; 的记录归为简单人机。&lt;/p&gt;
&lt;p&gt;当前库里有 17,857 条伪人参战记录，涉及 17,674 个 &lt;code&gt;(uid, world)&lt;/code&gt; 身份。除 &lt;code&gt;bIsAI&lt;/code&gt; 外，英雄熟练度也能把两组记录清楚分开：17,851 条伪人记录为非零，普通玩家记录全部为 0。&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/ai-proficiency-b12c6f15ef09-768w.webp 768w, https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/ai-proficiency-b12c6f15ef09-1536w.webp 1536w&quot; sizes=&quot;(max-width: 800px) 100vw, 760px&quot;&gt;&lt;img src=&quot;https://678234.xyz/upload/images/2026-07-28-WZRY-Analysis-2/ai-proficiency.png&quot; alt=&quot;普通玩家和伪人的英雄熟练度对照&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; fetchpriority=&quot;low&quot; width=&quot;2396&quot; height=&quot;470&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h3 id=&quot;排位巅峰赛和匹配都有&quot;&gt;排位、巅峰赛和匹配都有&lt;/h3&gt;
&lt;p&gt;十人记录完整时，三个主要模式的统计如下：&lt;/p&gt;









































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;模式&lt;/th&gt;&lt;th align=&quot;right&quot;&gt;完整对局&lt;/th&gt;&lt;th align=&quot;right&quot;&gt;有伪人的对局&lt;/th&gt;&lt;th align=&quot;right&quot;&gt;出现率&lt;/th&gt;&lt;th align=&quot;right&quot;&gt;每边一个&lt;/th&gt;&lt;th align=&quot;right&quot;&gt;一方五个&lt;/th&gt;&lt;th align=&quot;right&quot;&gt;五人伪人队胜率&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;排位&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;74,715&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;4,693&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;6.28%&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;2,830&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;1,842&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;4.45%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;巅峰赛&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;33,193&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;524&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;1.58%&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;521&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;3&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;0%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;匹配&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;4,815&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;254&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;5.28%&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;180&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;71&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;0%&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/ai-mode-summary-fca56bb11b05-768w.webp 768w, https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/ai-mode-summary-fca56bb11b05-1536w.webp 1536w&quot; sizes=&quot;(max-width: 800px) 100vw, 760px&quot;&gt;&lt;img src=&quot;https://678234.xyz/upload/images/2026-07-28-WZRY-Analysis-2/ai-mode-summary.png&quot; alt=&quot;排位、巅峰赛和匹配里的伪人对局数量、比例与胜率&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; fetchpriority=&quot;low&quot; width=&quot;2396&quot; height=&quot;610&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;巅峰赛里也有 524 局，出现率 1.58%。其中 521 局是双方各一个伪人，另有 3 局是一方完整五人伪人队，三局全输。&lt;/p&gt;
&lt;p&gt;排位里的两种主要安排是双方各一个，以及一方出现完整五人队。细分到每局双方人数，&lt;code&gt;1+1&lt;/code&gt; 有 2,830 局，&lt;code&gt;0+5&lt;/code&gt; 有 1,535 局，&lt;code&gt;1+5&lt;/code&gt; 有 292 局，&lt;code&gt;2+2&lt;/code&gt; 有 21 局。&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/ranked-ai-placement-1db2619713f5-768w.webp 768w, https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/ranked-ai-placement-1db2619713f5-1536w.webp 1536w&quot; sizes=&quot;(max-width: 800px) 100vw, 760px&quot;&gt;&lt;img src=&quot;https://678234.xyz/upload/images/2026-07-28-WZRY-Analysis-2/ranked-ai-placement.png&quot; alt=&quot;排位伪人出现率的五颗星分档，以及双方各有几个伪人&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; fetchpriority=&quot;low&quot; width=&quot;2396&quot; height=&quot;858&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;伪人出现率随分段快速下降。按每局真人的平均累计星数每五颗一档，低分档最高达到约 50% 至 71%；王者门口约 13%，110 至 114 累计星为 5.17%，135 至 149 累计星降到约 0.9% 至 1.03%。&lt;/p&gt;
&lt;h3 id=&quot;五人伪人队胜率只有-445&quot;&gt;五人伪人队胜率只有 4.45%&lt;/h3&gt;
&lt;p&gt;排位里一方完整五人伪人的 1,842 局，伪人队只赢 82 局，胜率 4.45%，对手一侧胜率 95.55%。其中 1,535 局的对手是纯真人，292 局带一个伪人，11 局带两个，1 局带三个，3 局带四个。&lt;/p&gt;
&lt;p&gt;伪人队赢下的 82 局里，71 局对手是纯真人，11 局对手带一个伪人。五个伪人都打不过的纯真人队有 71 支，福利局送到脸上还能输，这次很难怪匹配。&lt;/p&gt;
&lt;p&gt;再看真人对手上一条已采集记录。完整五人伪人队的对面共有 7,067 名不同玩家，其中 1,077 人能找到更早的记录，上一条记录的败率为 79.44%。&lt;/p&gt;
&lt;p&gt;按开局月份和累计星数每五颗一档寻找普通排位对照后，留下 1,065 名可比玩家：&lt;/p&gt;

























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;上一条已采集记录&lt;/th&gt;&lt;th align=&quot;right&quot;&gt;五人伪人局对手&lt;/th&gt;&lt;th align=&quot;right&quot;&gt;同月同分段普通排位&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;败率&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;79.44%&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;34.98%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;平均评分&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;7.718&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;8.494&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;平均 KDA&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;3.055&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;5.383&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/ai-opponent-previous-0012f80f6aa9-768w.webp 768w, https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/ai-opponent-previous-0012f80f6aa9-1536w.webp 1536w&quot; sizes=&quot;(max-width: 800px) 100vw, 760px&quot;&gt;&lt;img src=&quot;https://678234.xyz/upload/images/2026-07-28-WZRY-Analysis-2/ai-opponent-previous.png&quot; alt=&quot;五人伪人队胜负，以及真人对手上一条记录与普通排位对照&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; fetchpriority=&quot;low&quot; width=&quot;2396&quot; height=&quot;1010&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;把窗口拉到十条已采集排位，离目标局越近，输局越集中。最近三条整体胜率为 38.52%，最近十条为 51.56%。&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/ai-opponent-history-6af37243ca34-768w.webp 768w, https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/ai-opponent-history-6af37243ca34-1536w.webp 1536w&quot; sizes=&quot;(max-width: 800px) 100vw, 760px&quot;&gt;&lt;img src=&quot;https://678234.xyz/upload/images/2026-07-28-WZRY-Analysis-2/ai-opponent-history.png&quot; alt=&quot;遇到完整五人伪人队前十条已采集排位的胜率变化&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; fetchpriority=&quot;low&quot; width=&quot;2396&quot; height=&quot;1748&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;战绩接口最多返回最近 50 局，两条已采集记录之间仍可能夹着遗漏对局。近期输局与五人伪人局经常一起出现。&lt;/p&gt;
&lt;h3 id=&quot;有人-48-局遇到-23-次五人伪人队&quot;&gt;有人 48 局遇到 23 次五人伪人队&lt;/h3&gt;
&lt;p&gt;玩家「我是给※」的档案排位胜率为 51.0%。我采到他的 48 局 PVP，对面有完整五人伪人队的共有 23 局，他赢了 22 局；另有 5 局带部分伪人，赢了 4 局；剩余 20 局纯真人对局只赢 11 局。48 局合计 37 胜，胜率 77.1%。&lt;/p&gt;
&lt;p&gt;主播&lt;a href=&quot;https://space.bilibili.com/268941858/&quot;&gt;磊哥&lt;/a&gt;分享过一套利用匹配机制的经验：在游戏里梦游，待在塔下挂机清线，尽量少击杀、少拿高评分和 MVP。他把这叫「避免沾染因果」。相关视频包括&lt;a href=&quot;https://www.bilibili.com/video/BV1nBjhz1ErC/&quot;&gt;《高阶鸡爪流教学，随便沾染因果也不涨评分》&lt;/a&gt;和&lt;a href=&quot;https://www.bilibili.com/video/BV18cF7z1EKT/&quot;&gt;《谁暴露了自己的实力，谁就会变成牢玩家》&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/ai-playstyle-case-ebc53d42589b-768w.webp 768w, https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/ai-playstyle-case-ebc53d42589b-1536w.webp 1536w&quot; sizes=&quot;(max-width: 800px) 100vw, 760px&quot;&gt;&lt;img src=&quot;https://678234.xyz/upload/images/2026-07-28-WZRY-Analysis-2/ai-playstyle-case.png&quot; alt=&quot;高采集胜率玩家的伪人对手构成，以及低评分和零击杀的全库对照&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; fetchpriority=&quot;low&quot; width=&quot;2396&quot; height=&quot;3090&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;这 23 场带来 22 胜，占他全部 37 个胜场的 59.5%。全库按上一局胜负分层后，五人伪人局与普通排位的低评分、零击杀比例接近；上一条记录告负与五人伪人局同时出现得更频繁。&lt;/p&gt;
&lt;h3 id=&quot;同一身份键同时以真人和伪人出现&quot;&gt;同一身份键同时以真人和伪人出现&lt;/h3&gt;
&lt;p&gt;17,674 个带 AI 标记的身份里，198 个也出现过普通玩家记录，87 个只以伪人身份重复出现。&lt;/p&gt;
&lt;p&gt;30 个身份留下 32 条「普通昵称、伪人昵称、恢复普通昵称」记录，跨度都在 15 天内；其中 9 个身份的伪人记录还与普通玩家对局发生时间重叠。相同的 &lt;code&gt;(uid, world)&lt;/code&gt; 可以使用两个名字，同时参加两场正在进行的对局。&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/ai-identity-reuse-9156f3e67441-768w.webp 768w, https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/ai-identity-reuse-9156f3e67441-1536w.webp 1536w&quot; sizes=&quot;(max-width: 800px) 100vw, 760px&quot;&gt;&lt;img src=&quot;https://678234.xyz/upload/images/2026-07-28-WZRY-Analysis-2/ai-identity-reuse.png&quot; alt=&quot;伪人身份复用、昵称恢复和对局时间重叠记录&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; fetchpriority=&quot;low&quot; width=&quot;2396&quot; height=&quot;692&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;这里甚至能查到一部分伪人开放的历史战绩。这种现象很容易让人怀疑真人账号被拿去填充；目前只能确认身份键复用和 9 组时间重叠，uid 生成机制仍未知。&lt;/p&gt;
&lt;h3 id=&quot;五人伪人局在同段位下仍然结束得很快&quot;&gt;五人伪人局在同段位下仍然结束得很快&lt;/h3&gt;
&lt;p&gt;我之前直接拿三类排位的总体分布做比较，这里混入了段位构成的影响：高星局的伪人出现率低，而高星局本来就打得更短。8 月 4 日，我用扩充后的样本重算了一次。每局先取真人的平均累计星数，按五颗星分档；纯真人分桶至少有 20 局才进入对照，再按两类伪人局各自的星数构成给真人样本加权。&lt;/p&gt;
































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;排位类型&lt;/th&gt;&lt;th align=&quot;right&quot;&gt;进入同星对照&lt;/th&gt;&lt;th align=&quot;right&quot;&gt;本组平均&lt;/th&gt;&lt;th align=&quot;right&quot;&gt;对照平均&lt;/th&gt;&lt;th align=&quot;right&quot;&gt;本组中位数&lt;/th&gt;&lt;th align=&quot;right&quot;&gt;对照中位数&lt;/th&gt;&lt;th align=&quot;right&quot;&gt;10 分钟内（本组 / 对照）&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;一方五个伪人&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;4,761 / 4,807&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;12:44&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;15:46&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;12:05&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;15:16&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;14.95% / 4.58%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;每边一个伪人&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;3,391 / 3,422&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;16:21&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;16:08&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;15:51&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;15:42&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;2.86% / 3.83%&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/ai-duration-distribution-d222c0a50fa6-768w.webp 768w, https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/ai-duration-distribution-d222c0a50fa6-1536w.webp 1536w&quot; sizes=&quot;(max-width: 800px) 100vw, 760px&quot;&gt;&lt;img src=&quot;https://678234.xyz/upload/images/2026-07-28-WZRY-Analysis-2/ai-duration-distribution.png&quot; alt=&quot;完整五人伪人队与同星分段纯真人排位的一分钟时长分布&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; fetchpriority=&quot;low&quot; width=&quot;2396&quot; height=&quot;1190&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;完整五人队的平均时长仍然短 3:02，95% 区间为短 2:56 至 3:08；中位数短 3:11。校正段位构成后，差距还比总体对照更大。每边一个伪人的平均时长只多 13 秒，中位数多 9 秒，10 分钟内占比还略低于同星真人局。这组的时长分布基本贴着同星真人基线，短局特征集中在完整五人伪人队。&lt;/p&gt;
&lt;p&gt;一天内没有固定的伪人时段。按场次数看，完整五人队在 22 点占比最高，为 8.96%；双方各一个在 21 点最高，为 9.75%。按该小时全部排位计算，19 点的两类出现率最高，分别为 3.36% 和 5.72%。&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/ai-hourly-distribution-3c0479ffdace-768w.webp 768w, https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/ai-hourly-distribution-3c0479ffdace-1536w.webp 1536w&quot; sizes=&quot;(max-width: 800px) 100vw, 760px&quot;&gt;&lt;img src=&quot;https://678234.xyz/upload/images/2026-07-28-WZRY-Analysis-2/ai-hourly-distribution.png&quot; alt=&quot;两类伪人局在 24 小时内的场次占比分布及出现率峰值&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; fetchpriority=&quot;low&quot; width=&quot;2396&quot; height=&quot;1030&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;自然日走势里，完整五人队在 7 月 26 日最多，共 270 局；双方各一个在 7 月 25 日最多，共 368 局。出现率峰值都在 7 月 20 日，分别为 4.07% 和 9.65%。&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/ai-daily-distribution-f2d9f436e172-768w.webp 768w, https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/ai-daily-distribution-f2d9f436e172-1536w.webp 1536w&quot; sizes=&quot;(max-width: 800px) 100vw, 760px&quot;&gt;&lt;img src=&quot;https://678234.xyz/upload/images/2026-07-28-WZRY-Analysis-2/ai-daily-distribution.png&quot; alt=&quot;两类伪人局按自然日统计的场次数和出现率&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; fetchpriority=&quot;low&quot; width=&quot;2396&quot; height=&quot;1122&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;自然日曲线受每日样本分段变化影响，目前看不出固定周期。&lt;/p&gt;
&lt;h3 id=&quot;单个伪人有一半去打野&quot;&gt;单个伪人有一半去打野&lt;/h3&gt;
&lt;p&gt;双方各一个伪人的记录中，49.43% 出现在打野位；对抗路占 27.42%，游走 13.59%，发育路 7.47%，中路只有 2.08%。同批普通玩家的五路分布都接近两成。&lt;/p&gt;
&lt;p&gt;完整五人伪人队的 1,842 支队伍中，1,840 支五路齐全，所有队伍都选择了五个不同英雄。1,842 套阵容里有 1,828 套互不重复。&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/ai-role-distribution-23a99d0c4b76-768w.webp 768w, https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/ai-role-distribution-23a99d0c4b76-1536w.webp 1536w&quot; sizes=&quot;(max-width: 800px) 100vw, 760px&quot;&gt;&lt;img src=&quot;https://678234.xyz/upload/images/2026-07-28-WZRY-Analysis-2/ai-role-distribution.png&quot; alt=&quot;双方各一个伪人和完整五人伪人队的分路分布&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; fetchpriority=&quot;low&quot; width=&quot;2396&quot; height=&quot;974&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;单个伪人的英雄选择很集中，前十名合计占 43.96%，普通真人只有 19.60%。打野前三是铠、典韦和宫本武藏；对抗路的项羽占 15.01%，普通真人只有 4.10%。&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/ai-hero-pair-preferences-23fa1447e170-768w.webp 768w, https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/ai-hero-pair-preferences-23fa1447e170-1536w.webp 1536w&quot; sizes=&quot;(max-width: 800px) 100vw, 760px&quot;&gt;&lt;img src=&quot;https://678234.xyz/upload/images/2026-07-28-WZRY-Analysis-2/ai-hero-pair-preferences.png&quot; alt=&quot;双方各一个伪人时，各分路前十英雄和真人基线&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; fetchpriority=&quot;low&quot; width=&quot;2396&quot; height=&quot;2702&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;完整五人伪人队用过 99 名英雄，前十合计占 27.46%。对抗路最常见吕布，中路安琪拉，发育路马可波罗，打野铠，游走刘禅。马可波罗在这组发育路里占 16.58%，同分路普通真人只有 4.92%。&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/ai-hero-full-preferences-acbfaee13795-768w.webp 768w, https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/ai-hero-full-preferences-acbfaee13795-1536w.webp 1536w&quot; sizes=&quot;(max-width: 800px) 100vw, 760px&quot;&gt;&lt;img src=&quot;https://678234.xyz/upload/images/2026-07-28-WZRY-Analysis-2/ai-hero-full-preferences.png&quot; alt=&quot;完整五人伪人队各分路前十英雄和真人基线&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; fetchpriority=&quot;low&quot; width=&quot;2396&quot; height=&quot;2702&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;说完最抓眼的伪人，再回到这 11 万局本身。&lt;/p&gt;
&lt;h2 id=&quot;再看这-11-万局&quot;&gt;再看这 11 万局&lt;/h2&gt;
&lt;p&gt;页面里的段位统一换算成累计星数，从青铜开始累加每一小段所需星数，王者门口是 92 星，之后继续加王者星数。&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/rank-distribution-f5d0b1db9952-768w.webp 768w, https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/rank-distribution-f5d0b1db9952-1536w.webp 1536w&quot; sizes=&quot;(max-width: 800px) 100vw, 760px&quot;&gt;&lt;img src=&quot;https://678234.xyz/upload/images/2026-07-28-WZRY-Analysis-2/rank-distribution.png&quot; alt=&quot;玩家累计星数分布，以及各段位和王者星级辅助线&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; fetchpriority=&quot;low&quot; width=&quot;2396&quot; height=&quot;872&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;这张分布图主要说明采样范围。查询从高星玩家开始，队列也优先寻找相近星数，所以高星玩家很多。7 月 20 日的样本平均累计星数为 134.09，中位数 129；到 7 月 29 日，均值升到 171.09，中位数 190。后文的段位和英雄数字只描述这批偏高星样本。&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/star-trend-f6f810ddee10-768w.webp 768w, https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/star-trend-f6f810ddee10-1536w.webp 1536w&quot; sizes=&quot;(max-width: 800px) 100vw, 760px&quot;&gt;&lt;img src=&quot;https://678234.xyz/upload/images/2026-07-28-WZRY-Analysis-2/star-trend.png&quot; alt=&quot;每天采到的玩家平均与中位累计星数&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; fetchpriority=&quot;low&quot; width=&quot;1588&quot; height=&quot;838&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;先收紧到 70,022 局完整真人排位：双方各有五条记录、十人都是正常大区、整局没有简单人机或伪人，时长至少五分钟。&lt;/p&gt;
&lt;p&gt;这些对局平均打 14:56，中位数 14:17。13 分钟档最多，共 8,770 局；不到 10 分钟的占 6.05%，20 分钟以上占 11.00%。&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/match-duration-distribution-2da0691fe6c5-768w.webp 768w, https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/match-duration-distribution-2da0691fe6c5-1536w.webp 1536w&quot; sizes=&quot;(max-width: 800px) 100vw, 760px&quot;&gt;&lt;img src=&quot;https://678234.xyz/upload/images/2026-07-28-WZRY-Analysis-2/match-duration-distribution.png&quot; alt=&quot;七万局完整真人排位按一分钟统计的时长分布&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; fetchpriority=&quot;low&quot; width=&quot;1588&quot; height=&quot;592&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h3 id=&quot;分段越高对局整体越短&quot;&gt;分段越高，对局整体越短&lt;/h3&gt;
&lt;p&gt;8 月 4 日，我用扩充后的样本补算了一次分段与时长。这里只看完整真人 5v5、时长至少五分钟的对局：排位按每局十人的当局累计星数取平均，每五颗一档；巅峰赛用结算分数和本局增减还原十人的开局前积分，再取平均，每 50 分一档。统计单位是对局，每局只记一次。&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/rank-duration-trend-dc81dd9ffd95-768w.webp 768w, https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/rank-duration-trend-dc81dd9ffd95-1536w.webp 1536w&quot; sizes=&quot;(max-width: 800px) 100vw, 760px&quot;&gt;&lt;img src=&quot;https://678234.xyz/upload/images/2026-07-28-WZRY-Analysis-2/rank-duration-trend.png&quot; alt=&quot;完整真人排位按每局十人平均累计星数分桶的对局时长趋势&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; fetchpriority=&quot;low&quot; width=&quot;2396&quot; height=&quot;1146&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;排位共有 93,782 局，46 个分桶中有 38 个达到每档 100 局的门槛。45 至 49 累计星的平均时长为 16:34，220 至 224 星为 14:07，稳定分桶的最大差距是 2 分 27 秒。把 38 个稳定分桶做简单线性拟合，每增加五颗星，平均时长约缩短 3.7 秒。曲线中段有一段回升：160 至 164 星为 14:11，195 至 199 星升到 14:54，随后再次下降。&lt;/p&gt;
&lt;p&gt;巅峰赛共有 77,781 局，25 个分桶中有 19 个达到门槛。1500 至 1549 分的平均时长为 15:16，2250 至 2299 分为 13:22，相差 1 分 54 秒；线性趋势约为每增加 50 分缩短 5.8 秒。2300 分以上又回到 13:36 至 13:37。两个模式的整体方向一致，局部都能看到反复。当前数据无法区分操作水平、阵容选择、投降和采样路径各自带来的影响。&lt;/p&gt;
&lt;p&gt;开局时间集中在晚间。22 点有 9,520 局，21 点有 9,379 局；早上 6 点和 7 点最低，分别为 1,352 和 1,354 局。凌晨 4 至 6 点的样本平均累计星数为 174.9 至 178.9，19 至 22 点落在 136.6 至 138.8。采样范围里，凌晨还在玩的玩家平均星数明显更高。&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/hourly-activity-trend-e271ef287064-768w.webp 768w, https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/hourly-activity-trend-e271ef287064-1536w.webp 1536w&quot; sizes=&quot;(max-width: 800px) 100vw, 760px&quot;&gt;&lt;img src=&quot;https://678234.xyz/upload/images/2026-07-28-WZRY-Analysis-2/hourly-activity-trend.png&quot; alt=&quot;全部已采对局在 24 小时内的开局数量和平均累计星数&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; fetchpriority=&quot;low&quot; width=&quot;2396&quot; height=&quot;650&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;这 70,022 局里，胜方平均死亡 2.94 次，败方为 4.77 次。基础战斗数据里，胜负最明显的区别就是少死。&lt;/p&gt;
&lt;p&gt;下面的英雄榜切回全部已采模式。瑶有 23,739 次出场，百里守约 23,671 次，后羿 23,266 次。只看至少出场 800 次的英雄，胜率前三是盾山 56.63%、雅典娜 56.00% 和沈梦溪 55.97%；末三位是明世隐 45.39%、吕布 46.56% 和露娜 46.65%。&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/hero-appearance-winrate-1b6846e5a9e1-768w.webp 768w, https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/hero-appearance-winrate-1b6846e5a9e1-1536w.webp 1536w&quot; sizes=&quot;(max-width: 800px) 100vw, 760px&quot;&gt;&lt;img src=&quot;https://678234.xyz/upload/images/2026-07-28-WZRY-Analysis-2/hero-appearance-winrate.png&quot; alt=&quot;英雄出场次数、胜率、平均评分和榜单&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; fetchpriority=&quot;low&quot; width=&quot;2428&quot; height=&quot;1128&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;这些英雄胜率只是当前高星采样路径下的快照。它适合观察这批对局，拿去当全服英雄强度表会失真。&lt;/p&gt;
&lt;h3 id=&quot;越高端的局瑶的胜率越高&quot;&gt;越高端的局，瑶的胜率越高&lt;/h3&gt;
&lt;p&gt;把瑶单独拿出来，排位和巅峰赛的完整真人 5v5 共有 20,464 场，综合胜率 51.85%；排位胜率 52.4%，巅峰赛胜率 47.1%。再按瑶玩家本人当局结算的累计星数每五颗分一档，195 星以前的胜率大多在 50% 附近，195 星以后进入明显的上升段。230 星以上超过 70%，最后一档接近 90%。每档至少有 20 场才进入曲线。&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/hero-yao-winrate-by-stars-ed451fb3bee2-768w.webp 768w, https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/hero-yao-winrate-by-stars-ed451fb3bee2-1536w.webp 1536w&quot; sizes=&quot;(max-width: 800px) 100vw, 760px&quot;&gt;&lt;img src=&quot;https://678234.xyz/upload/images/2026-07-28-WZRY-Analysis-2/hero-yao-winrate-by-stars.png&quot; alt=&quot;瑶在完整真人 5v5 中按本人当局累计星数每五颗分档的胜率变化&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; fetchpriority=&quot;low&quot; width=&quot;2972&quot; height=&quot;1354&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;为什么呢好难猜啊🤪……（高分段还在玩瑶的很可能是为了国标请演员的富婆，在 B 站搜索「富婆瑶妹」等关键词了解）&lt;/p&gt;
&lt;p&gt;再把 7 月 1 日至 8 月 3 日的完整真人排位按胜负拆开，200 星以上的瑶胜局结束得更快：&lt;/p&gt;
































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;瑶玩家累计星数&lt;/th&gt;&lt;th align=&quot;right&quot;&gt;对局&lt;/th&gt;&lt;th align=&quot;right&quot;&gt;胜 / 负&lt;/th&gt;&lt;th align=&quot;right&quot;&gt;胜率&lt;/th&gt;&lt;th align=&quot;right&quot;&gt;胜局平均时长&lt;/th&gt;&lt;th align=&quot;right&quot;&gt;败局平均时长&lt;/th&gt;&lt;th align=&quot;right&quot;&gt;胜局比败局短&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;200 至 224 星&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;3,736&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;2,127 / 1,609&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;56.93%&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;13:58&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;14:41&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;0:44&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;225 至 249 星&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;421&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;300 / 121&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;71.26%&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;13:24&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;14:59&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;1:35&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;高星段同时出现了胜率上升和胜局缩短。到了 225 至 249 星，平均差距已经超过一分半，除了请演员无法解释。&lt;/p&gt;
&lt;h3 id=&quot;朵莉亚也有同样的演员问题&quot;&gt;朵莉亚也有同样的演员问题&lt;/h3&gt;
&lt;p&gt;朵莉亚的曲线也在高星段突然上扬。排位完整真人 5v5 中，175 至 199 星的胜率为 46.51%，200 至 224 星为 49.94%，225 至 249 星升到 65.66%，最后一段共有 265 场。按连续星数拟合，每增加十颗星，胜率约增加 1.48 个百分点，BH 校正后的 &lt;code&gt;q = 0.0196&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/hero-doria-winrate-by-stars-61ed7f251d49-768w.webp 768w, https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/hero-doria-winrate-by-stars-61ed7f251d49-1520w.webp 1520w&quot; sizes=&quot;(max-width: 800px) 100vw, 760px&quot;&gt;&lt;img src=&quot;https://678234.xyz/upload/images/2026-07-28-WZRY-Analysis-2/hero-doria-winrate-by-stars.png&quot; alt=&quot;朵莉亚在完整真人排位中按本人当局累计星数每五颗分档的胜率变化&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; fetchpriority=&quot;low&quot; width=&quot;1520&quot; height=&quot;597&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h3 id=&quot;六七分钟结束的瑶和朵莉亚胜局&quot;&gt;六七分钟结束的瑶和朵莉亚胜局&lt;/h3&gt;
&lt;p&gt;继续筛选 7 月 1 日至 8 月 3 日的完整真人排位，只保留瑶或朵莉亚获胜、时长在 6:00 至 7:59 的对局（六分概念神，资本发力了）：&lt;/p&gt;



































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;英雄&lt;/th&gt;&lt;th align=&quot;right&quot;&gt;6:00 至 6:59&lt;/th&gt;&lt;th align=&quot;right&quot;&gt;7:00 至 7:59&lt;/th&gt;&lt;th align=&quot;right&quot;&gt;合计&lt;/th&gt;&lt;th align=&quot;right&quot;&gt;使用者 ≥175 星&lt;/th&gt;&lt;th align=&quot;right&quot;&gt;使用者 ≥200 星&lt;/th&gt;&lt;th align=&quot;right&quot;&gt;十人平均 ≥175 星&lt;/th&gt;&lt;th align=&quot;right&quot;&gt;十人平均 ≥200 星&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;瑶&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;110&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;113&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;223&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;142&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;70&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;89&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;22&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;朵莉亚&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;87&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;75&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;162&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;98&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;36&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;86&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;24&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;两名英雄没有在同一胜方一起出现，因此 385 次英雄胜场对应 385 局。按使用者本人 ≥175 星计算，短胜局占瑶该分段全部胜局的 2.12%，朵莉亚为 1.79%；按十人平均 ≥175 星计算，比例分别为 1.43% 和 1.60%。十人平均达到 200 星后仍有 46 场。&lt;/p&gt;
&lt;h3 id=&quot;露娜的高分段胜率也在涨&quot;&gt;露娜的高分段胜率也在涨&lt;/h3&gt;
&lt;p&gt;露娜在巅峰赛里的趋势也很明显。这里把分桶放大到每 100 分一档：2000 至 2099 分的胜率为 50.97%，2100 至 2199 分为 49.69%，2200 至 2299 分升到 53.19%，2300 至 2399 分达到 59.88%。最后一档有 334 场。按连续积分拟合，每增加 100 分，胜率约增加 3.44 个百分点，BH 校正后的 &lt;code&gt;q = 0.0454&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/hero-luna-winrate-by-master-score-7d60716d258b-768w.webp 768w, https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/hero-luna-winrate-by-master-score-7d60716d258b-1520w.webp 1520w&quot; sizes=&quot;(max-width: 800px) 100vw, 760px&quot;&gt;&lt;img src=&quot;https://678234.xyz/upload/images/2026-07-28-WZRY-Analysis-2/hero-luna-winrate-by-master-score.png&quot; alt=&quot;露娜在完整真人巅峰赛中按本人当局巅峰积分每 100 分分档的胜率变化&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; fetchpriority=&quot;low&quot; width=&quot;1520&quot; height=&quot;597&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;这条曲线大概来自玩家熟练度。露娜对操作和进场时机的要求很高，高分段还敢选露娜的一般都是绝活哥了。把对局时长按同样分段拆开后，露娜没有出现瑶和朵莉亚那种高分段异常缩短的区间，2300 至 2399 分的平均时长回到 14:00。&lt;/p&gt;
&lt;h3 id=&quot;正式服里有人用上了五个未公布英雄&quot;&gt;正式服里有人用上了五个未公布英雄&lt;/h3&gt;
&lt;p&gt;英雄出场榜里还出现了五个官方尚未公布、当前只显示 ID 的英雄：&lt;code&gt;#547&lt;/code&gt;、&lt;code&gt;#631&lt;/code&gt;、&lt;code&gt;#640&lt;/code&gt;、&lt;code&gt;#646&lt;/code&gt; 和 &lt;code&gt;#635&lt;/code&gt;。它们分别出场 3、7、14、16 和 19 次，合计 59 次，涉及 56 个玩家身份和 50 局对局。&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/unannounced-hero-appearances-9a63f28d953f-768w.webp 768w, https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/unannounced-hero-appearances-9a63f28d953f-1536w.webp 1536w&quot; sizes=&quot;(max-width: 800px) 100vw, 760px&quot;&gt;&lt;img src=&quot;https://678234.xyz/upload/images/2026-07-28-WZRY-Analysis-2/unannounced-hero-appearances.png&quot; alt=&quot;正式服中五个未公布英雄的出场、胜率、KDA 和评分&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; fetchpriority=&quot;low&quot; width=&quot;1710&quot; height=&quot;1116&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;这些记录来自 &lt;code&gt;1xxx&lt;/code&gt; 至 &lt;code&gt;4xxx&lt;/code&gt; 的正式大区。使用者自身都没有 AI 标记，59 次出场中还有 28 次发生在整局没有 AI 标记的对局里。正式服确实已经有人玩到了这五个英雄，客户端目前还没有显示它们的名字。&lt;/p&gt;
&lt;h2 id=&quot;先看一些榜单&quot;&gt;先看一些榜单&lt;/h2&gt;
&lt;p&gt;6,521 名有档案的玩家里，2,626 人玩了九年以上，3,288 人打过一万场，207 人超过三万场。总场次最高的玩家打了 58,959 场。&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/player-age-distribution-9f779be42ec4-768w.webp 768w, https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/player-age-distribution-9f779be42ec4-1536w.webp 1536w&quot; sizes=&quot;(max-width: 800px) 100vw, 760px&quot;&gt;&lt;img src=&quot;https://678234.xyz/upload/images/2026-07-28-WZRY-Analysis-2/player-age-distribution.png&quot; alt=&quot;账号年限分布，以及各年限玩家的平均累计场次&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; fetchpriority=&quot;low&quot; width=&quot;2396&quot; height=&quot;670&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;单局榜单只看排位、时长至少五分钟、目标玩家为真人的记录。&lt;/p&gt;







































































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;纪录&lt;/th&gt;&lt;th&gt;玩家与英雄&lt;/th&gt;&lt;th align=&quot;right&quot;&gt;数值&lt;/th&gt;&lt;th&gt;结果&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;对英雄伤害&lt;/td&gt;&lt;td&gt;明日寻飞鸟ν / 甄姬&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;795,681&lt;/td&gt;&lt;td&gt;29:36，胜&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;承伤&lt;/td&gt;&lt;td&gt;卡纳德·白星 / 海诺&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;618,878&lt;/td&gt;&lt;td&gt;26:53，负&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;治疗&lt;/td&gt;&lt;td&gt;瞅你咋地8855 / 程咬金&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;519,015&lt;/td&gt;&lt;td&gt;25:13，负&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;控制&lt;/td&gt;&lt;td&gt;众生苦我独鲜 / 墨子&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;197.5 秒&lt;/td&gt;&lt;td&gt;29:14，负&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;击杀&lt;/td&gt;&lt;td&gt;✿҉͜恋戰᭄ / 鲁班七号&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;31&lt;/td&gt;&lt;td&gt;25:13，胜&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;助攻&lt;/td&gt;&lt;td&gt;渣渣o瑶 / 元流之子（辅助）&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;49&lt;/td&gt;&lt;td&gt;30:25，胜&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;经济&lt;/td&gt;&lt;td&gt;春眠不橘晓 / 诸葛亮&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;31,601&lt;/td&gt;&lt;td&gt;35:14，负&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;死亡&lt;/td&gt;&lt;td&gt;゛小趴菜・ / 兰陵王&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;18&lt;/td&gt;&lt;td&gt;26:42，负&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;推塔&lt;/td&gt;&lt;td&gt;杨砚辞、凝冬 / 后羿&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;9 座&lt;/td&gt;&lt;td&gt;12:58，胜&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;补兵&lt;/td&gt;&lt;td&gt;落幕$忧伤 / 姜子牙&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;148&lt;/td&gt;&lt;td&gt;31:39，胜&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/ranked-single-match-boards-db240e988577-768w.webp 768w, https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/ranked-single-match-boards-db240e988577-1536w.webp 1536w&quot; sizes=&quot;(max-width: 800px) 100vw, 760px&quot;&gt;&lt;img src=&quot;https://678234.xyz/upload/images/2026-07-28-WZRY-Analysis-2/ranked-single-match-boards.png&quot; alt=&quot;排位单局伤害与承伤前十榜单，包含玩家、英雄、KDA 和结果&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; fetchpriority=&quot;low&quot; width=&quot;2428&quot; height=&quot;980&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;31 杀那局只打了 25:13。伤害榜第一的甄姬在 29:36 里打出 795,681 英雄伤害；控制榜第一的墨子让对手累计失去操作 197.5 秒。推塔纪录只用了 12:58，经济纪录打到 31,601 仍然输了。&lt;/p&gt;
&lt;h2 id=&quot;五排段位平台和分区&quot;&gt;五排、段位、平台和分区&lt;/h2&gt;
&lt;p&gt;结算记录带有每名玩家排队时的组队人数和组队编号，可以直接识别完整五排、混编队和五个散人。&lt;/p&gt;
&lt;p&gt;完整五排每个人头平均带 2.03 个助攻，混编队是 1.88，五个散人是 1.77。五排全队平均击杀 17.14，五个散人是 22.61；平均死亡分别为 17.06 和 22.45。&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/squad-coordination-d97ec0649906-768w.webp 768w, https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/squad-coordination-d97ec0649906-1520w.webp 1520w&quot; sizes=&quot;(max-width: 800px) 100vw, 760px&quot;&gt;&lt;img src=&quot;https://678234.xyz/upload/images/2026-07-28-WZRY-Analysis-2/squad-coordination.png&quot; alt=&quot;完整五排、混编和五个散人的击杀、助攻与参与度&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; fetchpriority=&quot;low&quot; width=&quot;1520&quot; height=&quot;554&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;时长差异更大。&lt;/p&gt;





































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;对局构成&lt;/th&gt;&lt;th align=&quot;right&quot;&gt;对局数&lt;/th&gt;&lt;th align=&quot;right&quot;&gt;平均时长&lt;/th&gt;&lt;th align=&quot;right&quot;&gt;中位数&lt;/th&gt;&lt;th align=&quot;right&quot;&gt;12 分钟内&lt;/th&gt;&lt;th align=&quot;right&quot;&gt;20 分钟以上&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;完整五排&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;12,358&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;14:14&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;13:35&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;29.74%&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;8.93%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;混编&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;43,331&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;14:51&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;14:14&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;21.92%&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;10.36%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;五个散人&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;14,333&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;15:46&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;15:13&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;13.40%&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;14.71%&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/squad-duration-d5472db2a022-768w.webp 768w, https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/squad-duration-d5472db2a022-1536w.webp 1536w&quot; sizes=&quot;(max-width: 800px) 100vw, 760px&quot;&gt;&lt;img src=&quot;https://678234.xyz/upload/images/2026-07-28-WZRY-Analysis-2/squad-duration.png&quot; alt=&quot;完整五排、混编和五个散人按一分钟统计的时长分布&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; fetchpriority=&quot;low&quot; width=&quot;2396&quot; height=&quot;650&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;完整五排的平均时长比五个散人短 1 分 32 秒，中位数短 1 分 38 秒。12 分钟内结束的比例高了一倍多，人头数还少约四分之一。&lt;/p&gt;
&lt;h3 id=&quot;哪些英雄在五排里变化最大&quot;&gt;哪些英雄在五排里变化最大&lt;/h3&gt;
&lt;p&gt;旧文章曾拿鬼谷子做过一次五排和单排的卡方检验，当时五排样本只有 499 局，结果无法支持「鬼谷子更依赖配合」。&lt;/p&gt;
&lt;p&gt;这次只比较完整五排和五个散人，并按开局月份、队伍平均累计星数每五颗一档分层。两组分别有 24,716 和 28,666 支队伍，106 名英雄达到两组各 200 场的门槛，再对全部英雄做 BH 多重检验校正。&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/squad-hero-difference-66b01e2681eb-768w.webp 768w, https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/squad-hero-difference-66b01e2681eb-1536w.webp 1536w&quot; sizes=&quot;(max-width: 800px) 100vw, 760px&quot;&gt;&lt;img src=&quot;https://678234.xyz/upload/images/2026-07-28-WZRY-Analysis-2/squad-hero-difference.png&quot; alt=&quot;完整五排与五个散人的英雄胜率差异、置信区间和校正结果&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; fetchpriority=&quot;low&quot; width=&quot;2396&quot; height=&quot;1734&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;校正后有 10 名英雄达到显著水平。公孙离的五排胜率高 22.42 个百分点，戈娅高 20.07 个百分点，沈梦溪高 18.06 个百分点，瑶高 7.67 个百分点。另一端，黄忠低 19.75 个百分点，程咬金低 20.86 个百分点。&lt;/p&gt;
&lt;p&gt;鬼谷子的五排复核仍然没有显著差异：五排 138 胜 / 317 场，五个散人 95 胜 / 174 场；分层差异为 -4.49 个百分点，95% 置信区间跨过 0，&lt;code&gt;p = 0.644&lt;/code&gt;。当前达到显著水平的 10 名英雄已经列在图中。&lt;/p&gt;
&lt;h3 id=&quot;累计星数与死亡kda&quot;&gt;累计星数与死亡、KDA&lt;/h3&gt;
&lt;p&gt;把排位按累计星数每五颗一档后，死亡和 KDA 都有波动。&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/rank-combat-trend-404ea69ddff6-768w.webp 768w, https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/rank-combat-trend-404ea69ddff6-1520w.webp 1520w&quot; sizes=&quot;(max-width: 800px) 100vw, 760px&quot;&gt;&lt;img src=&quot;https://678234.xyz/upload/images/2026-07-28-WZRY-Analysis-2/rank-combat-trend.png&quot; alt=&quot;排位累计星数与平均死亡、KDA 的变化趋势&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; fetchpriority=&quot;low&quot; width=&quot;1520&quot; height=&quot;590&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;再把玩家分成三组，并按实际对局时长归一到每 10 分钟：累计星数不高于 108 的玩家死亡 2.76 次，109 至 127 星是 2.42 次，128 星以上是 2.52 次；三组击杀加助攻分别为 7.61、7.44 和 7.42。中间一组死亡最低，最高一组回升到 2.52 次。图里画的是每五颗星一档的每局平均死亡和平均 KDA，两种口径的趋势都有波动。&lt;/p&gt;
&lt;h3 id=&quot;苹果样本段位更高微信区对局更久&quot;&gt;苹果样本段位更高，微信区对局更久&lt;/h3&gt;
&lt;p&gt;区服号段可以分成手Q安卓、手Q苹果、微信安卓和微信苹果。档案响应里还有 MMR 和 ELO，这两个数字不会显示在普通玩家界面。&lt;/p&gt;








































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;渠道与系统&lt;/th&gt;&lt;th align=&quot;right&quot;&gt;玩家&lt;/th&gt;&lt;th align=&quot;right&quot;&gt;平均累计星数&lt;/th&gt;&lt;th align=&quot;right&quot;&gt;ELO&lt;/th&gt;&lt;th align=&quot;right&quot;&gt;排位胜率&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;手Q安卓&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;2,170&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;175.9&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;3,339&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;55.06%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;手Q苹果&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;745&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;195.3&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;3,547&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;57.08%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;微信安卓&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;2,229&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;153.1&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;3,103&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;54.10%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;微信苹果&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;1,347&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;176.5&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;3,350&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;54.89%&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/channel-platform-comparison-c03719e2c498-768w.webp 768w, https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/channel-platform-comparison-c03719e2c498-1536w.webp 1536w&quot; sizes=&quot;(max-width: 800px) 100vw, 760px&quot;&gt;&lt;img src=&quot;https://678234.xyz/upload/images/2026-07-28-WZRY-Analysis-2/channel-platform-comparison.png&quot; alt=&quot;手Q和微信在安卓、苹果上的玩家数量、星数、ELO 与胜率&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; fetchpriority=&quot;low&quot; width=&quot;2396&quot; height=&quot;672&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;同一渠道里，苹果样本的平均累计星数和 ELO 都更高。手Q苹果比手Q安卓高 19.4 个累计星数和 208 ELO；微信苹果比微信安卓高 23.4 个累计星数和 247 ELO。&lt;/p&gt;
&lt;p&gt;对局时长还有另一条稳定趋势：手Q安卓平均 14:21，手Q苹果 14:17，微信安卓 14:53，微信苹果 14:47。同一手机系统下，微信样本都比手Q多打约半分钟。&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/zone-duration-416428140531-768w.webp 768w, https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/zone-duration-416428140531-1520w.webp 1520w&quot; sizes=&quot;(max-width: 800px) 100vw, 760px&quot;&gt;&lt;img src=&quot;https://678234.xyz/upload/images/2026-07-28-WZRY-Analysis-2/zone-duration.png&quot; alt=&quot;按四个渠道号段排列的各大区平均对局时长&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; fetchpriority=&quot;low&quot; width=&quot;1520&quot; height=&quot;810&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;「微信区玩家年纪更大，所以动作慢」可以当作一个有趣猜想。当前能确认的只有渠道时长差异，档案里没有年龄字段。&lt;/p&gt;
&lt;h3 id=&quot;mmrelo-与累计星数几乎同步&quot;&gt;MMR、ELO 与累计星数几乎同步&lt;/h3&gt;
&lt;p&gt;相关性矩阵把玩家档案、实战数据、每场被赞和 MVP 比例放到了一张图里。&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/correlation-matrix-eae6402f3ad1-768w.webp 768w, https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/correlation-matrix-eae6402f3ad1-1536w.webp 1536w&quot; sizes=&quot;(max-width: 800px) 100vw, 760px&quot;&gt;&lt;img src=&quot;https://678234.xyz/upload/images/2026-07-28-WZRY-Analysis-2/correlation-matrix.png&quot; alt=&quot;玩家档案、实战胜率、场均被赞和 MVP 率的 Pearson 相关性矩阵&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; fetchpriority=&quot;low&quot; width=&quot;2752&quot; height=&quot;2012&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;累计星数、MMR 和 ELO 的相关系数为 0.991 至 0.997。累计 MVP 与总场次的相关系数达到 0.86，累计指标明显受场次影响。横向比较玩家时，场均被赞和 MVP 率更有参考价值；它们与排位胜率的相关系数分别为 0.47 和 0.40。&lt;/p&gt;
&lt;h2 id=&quot;隐藏战绩后还能继续找&quot;&gt;隐藏战绩后还能继续找&lt;/h2&gt;
&lt;p&gt;指定玩家关闭战绩以后，他仍可能出现在同局其他人的公开历史中。继续查询这些同局玩家，还能找到更多相关对局。这个方法在顶尖对局尤其有效，因为高分段玩家会反复遇到。&lt;/p&gt;
&lt;p&gt;查询结果也能直接生成开黑关系图。严格口径只连接同一阵营、组队人数大于 1、组队编号相同的玩家。当前图谱有 172,103 个玩家节点和 239,372 条开黑关系。下面这个例子向外展开两层，一屏里有 53 人和 143 条关系，中心玩家直接连着 15 名开黑伙伴。&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/strict-party-graph-4246f23ef17f-768w.webp 768w, https://678234.xyz/optimized/upload/images/2026-07-28-WZRY-Analysis-2/strict-party-graph-4246f23ef17f-1536w.webp 1536w&quot; sizes=&quot;(max-width: 800px) 100vw, 760px&quot;&gt;&lt;img src=&quot;https://678234.xyz/upload/images/2026-07-28-WZRY-Analysis-2/strict-party-graph.png&quot; alt=&quot;从一名玩家向外展开两层的严格开黑关系图&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; fetchpriority=&quot;low&quot; width=&quot;2954&quot; height=&quot;1698&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;战绩还保留每局当时的昵称，所以能看到玩家改名。&lt;/p&gt;
&lt;h2 id=&quot;最后&quot;&gt;最后&lt;/h2&gt;
&lt;p&gt;这 11 万局串起了几件平时很难放在一起看的事：英雄和玩家的极端纪录、五排与散人的节奏差异、不同平台和大区的表现、界面里看不到的 MMR 与 ELO，还有伪人在排位和巅峰赛里的分布。&lt;/p&gt;
&lt;p&gt;七年前那篇文章主要依赖王者营地公开的战绩。这一次，客户端响应里的组队结构、隐藏分和 AI 标记也进了同一套分析。样本沿高星玩家向外扩散，结论都限定在这 11 万局里；至少下次再聊五排、区服差异、隐藏分和伪人，手里已经有图和数字可以对照。&lt;/p&gt;</content:encoded><category>折腾</category><category>王者荣耀</category><category>数据分析</category><category>逆向</category><category>IL2CPP</category></item><item><title>王者荣耀消息协议的一些研究</title><link>https://678234.xyz/2026/07/26/WZRY-Protocol-Hook/</link><guid isPermaLink="true">https://678234.xyz/2026/07/26/WZRY-Protocol-Hook/</guid><pubDate>Sun, 26 Jul 2026 15:40:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;声明：本文只记录个人设备和本人账号上的分析过程，包含 AI 辅助创作，可能会带来一定的不适感，谨慎阅读。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;起因很简单。登录页列着一千多个大区，我想确认这些名字来自实时响应还是本地缓存，再改一个看看。区服流量很快就抓到了，后面的工作主要花在进程内改写和协议对象解析上。&lt;/p&gt;
&lt;p&gt;设备是一台 root 真机，HyperOS 3 / Android 16 / arm64，装了 KernelSU 和 Zygisk Next。游戏版本是国服 11.4.1.1，SO 构建日期为 2026-06-14。文中的函数地址都是这个版本的 RVA，具体数值记录在项目文档中。&lt;/p&gt;
&lt;h2 id=&quot;现在能做什么&quot;&gt;现在能做什么&lt;/h2&gt;
&lt;p&gt;游戏进程里常驻一个 Zygisk 原生模块，分别拦截收包和发包。消息对象会通过 IL2CPP 反射转成 JSON，发送到主机上的工作台。规则在网页中配置，可以按字段路径改写消息，也可以构造一条本地消息交给客户端处理。&lt;/p&gt;
&lt;p&gt;先看两个已经在屏幕上确认的例子。第一个是区服名，只改手Q1区：&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://678234.xyz/optimized/upload/images/2026-07-26-WZRY-Protocol-Hook/zone-renamed-58882cffc5dd-768w.webp 768w, https://678234.xyz/optimized/upload/images/2026-07-26-WZRY-Protocol-Hook/zone-renamed-58882cffc5dd-1536w.webp 1536w&quot; sizes=&quot;(max-width: 800px) 100vw, 760px&quot;&gt;&lt;img src=&quot;https://678234.xyz/upload/images/2026-07-26-WZRY-Protocol-Hook/zone-renamed.png&quot; alt=&quot;选择服务器界面，手Q1区的名字被替换&quot; decoding=&quot;async&quot; width=&quot;2510&quot; height=&quot;1156&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;第二个是大厅左上角的昵称。游戏内改名入口最多填写 6 个中文字，下面这张图显示了 8 个，后面的内容被控件截断：&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://678234.xyz/optimized/upload/images/2026-07-26-WZRY-Protocol-Hook/nickname-long-c44573002b6e-768w.webp 768w, https://678234.xyz/optimized/upload/images/2026-07-26-WZRY-Protocol-Hook/nickname-long-c44573002b6e-1536w.webp 1536w&quot; sizes=&quot;(max-width: 800px) 100vw, 760px&quot;&gt;&lt;img src=&quot;https://678234.xyz/upload/images/2026-07-26-WZRY-Protocol-Hook/nickname-long.png&quot; alt=&quot;大厅左上角昵称显示为「任意长度改写验证」，后半截被控件宽度截断&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; fetchpriority=&quot;low&quot; width=&quot;2510&quot; height=&quot;1156&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;规则只有一行，把登录响应 &lt;code&gt;SCID_CMD_GAMELOGINRSP&lt;/code&gt; 里的 &lt;code&gt;szName&lt;/code&gt; 换掉。实际塞进去的是 26 个中文字、78 字节，而 TDR schema 给这个字段的定长是 64 字节：&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;I WzryZg: [route] r msgid=1003 szName : System.Byte[] OK -&gt; 新 Byte[78](任意长)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里修改的是 &lt;code&gt;unpack&lt;/code&gt; 完成后的对象，发生在游戏逻辑读取之前。客户端改名界面的 6 字限制没有参与，收包对象也接受了超过 schema 定长的数组。&lt;/p&gt;
&lt;h2 id=&quot;区服表是明文改写放到进程内&quot;&gt;区服表是明文，改写放到进程内&lt;/h2&gt;
&lt;p&gt;tcpdump 直接抓到了明文区服流量，区服名和 &lt;code&gt;LogicWorldID&lt;/code&gt; 都在响应里。帧结构也很简单：&lt;code&gt;55 00 00 00&lt;/code&gt; 后面是一个字节的长度，再跟 UTF-8 名字。&lt;/p&gt;
&lt;p&gt;顺着这份明文把整张表解了出来，1075 条，每条是 &lt;code&gt;&amp;#x3C;平台&gt;&amp;#x3C;编号&gt;区&amp;#x3C;诗意名&gt;&lt;/code&gt; 加上 &lt;code&gt;LogicWorldID&lt;/code&gt; 和一组 relay 地址。手Q 601 条、微信 458 条，剩下十来条是抢先服、测试服、提审服这类。诗意名基本取自英雄和皮肤词，落雪白狼、鲜血枭雄、电玩小子、长城防线都在里面。&lt;/p&gt;
&lt;p&gt;游戏界面当时最多显示到手Q547区（落雪白狼，&lt;code&gt;LogicWorldID&lt;/code&gt; 1557），ilink 响应已经包含手Q600区（戍鼓铭心，1610）。548 到 600 区的名字已经下发，界面只显示开服部分。编号和 ID 大致遵循手QN区对应 1000+N、微信N区对应 3010+N，中间有跳号；547 区对应 1557，1547 已被其他节点占用。&lt;/p&gt;
&lt;p&gt;确认响应内容后，还需要找到合适的改写位置。我依次检查了 libc 收发函数、eBPF 和透明中继。&lt;/p&gt;
&lt;p&gt;我先用 Frida 挂 &lt;code&gt;recv&lt;/code&gt;、&lt;code&gt;read&lt;/code&gt; 和 &lt;code&gt;recvfrom&lt;/code&gt;。同一次 60 秒启动中，tcpdump 看到了两千多次区服相关字段，libc hook 的计数为零。诊断日志正常，确认这段流量使用了编号 207 的裸 &lt;code&gt;recvfrom&lt;/code&gt; 系统调用。&lt;/p&gt;
&lt;p&gt;eBPF 可以稳定看到完整流量，我也记录了 ilink flow 的特征。本次使用的探针只做观测，没有继续实现内核侧改写。&lt;/p&gt;
&lt;p&gt;透明中继需要实现拆帧、TDR 解析、字段修改和重新组包，还要处理心跳与重传。这个工作量超出了区服名验证的需要。&lt;/p&gt;
&lt;p&gt;我改在游戏进程内处理已经解包的对象。后续消息是否加密、走哪种传输协议，都由游戏原有网络层处理。&lt;/p&gt;
&lt;h2 id=&quot;frida-attach-会触发游戏崩溃&quot;&gt;Frida attach 会触发游戏崩溃&lt;/h2&gt;
&lt;p&gt;Frida 便于快速验证，但 attach 主进程后游戏会崩溃，注入的 gum 运行时无法继续运行。&lt;/p&gt;
&lt;p&gt;我又把 gadget 放进 Zygisk 模块加载。主进程仍会退出，能存活的子进程没有目标协议对象。继续处理 Frida 特征需要覆盖多处检测点，这次没有沿用这条方案。&lt;/p&gt;
&lt;p&gt;我改用纯 Zygisk 原生模块随 zygote 进入游戏进程。模块可以常驻，inline hook 需要自行实现。&lt;/p&gt;
&lt;h2 id=&quot;shadowhook-无法在代码段附近分配跳板&quot;&gt;ShadowHook 无法在代码段附近分配跳板&lt;/h2&gt;
&lt;p&gt;我先试了 ShadowHook。它使用四字节相对跳转，需要在目标函数 ±128MB 内放置一小段跳板代码。&lt;code&gt;libil2cpp.so&lt;/code&gt; 有 217MB，代码段占 155MB；扫描整个代码段只找到一处 12 字节零填充，附近也没有可用映射。&lt;/p&gt;
&lt;p&gt;安装时报错 &lt;code&gt;errno=40&lt;/code&gt;。源码里使用目标地址减 128MB 作为 mmap hint，这个地址落在库自身映射中，内核返回的地址超出了相对跳转范围。&lt;code&gt;MAP_FIXED&lt;/code&gt; 也找不到稳定空闲区间；ASLR 生成的布局每次不同，有一次出现 9MB 间隙，重启后便消失了。&lt;/p&gt;
&lt;p&gt;我改用 16 字节绝对跳转：目标函数开头写入 &lt;code&gt;LDR X17,#8; BR X17; .quad proxy&lt;/code&gt;，原指令搬到另一块可执行内存，末尾再跳回目标函数加 16 的位置。And64InlineHook 也使用这种做法。被搬走的指令必须位置无关；当前目标函数以 &lt;code&gt;sub sp&lt;/code&gt; 或 &lt;code&gt;stp&lt;/code&gt; 开头，&lt;code&gt;adrp&lt;/code&gt; 都在前 16 字节之外。&lt;/p&gt;
&lt;p&gt;区服名相关函数只在登录期调用，可以在 gcloud 载入后、组网前一次性安装 16 字节跳转。&lt;/p&gt;
&lt;p&gt;收发函数从启动起就被网络线程高频调用。16 字节写入不具备原子性，安装过程中执行到目标地址会读到新旧混合的指令，崩溃时间也不固定。&lt;/p&gt;
&lt;p&gt;高频函数改用断点 hook。安装时原子写入一条 &lt;code&gt;BRK #0&lt;/code&gt;（&lt;code&gt;0xD4200000&lt;/code&gt;），SIGTRAP 处理函数在信号上下文中把 PC 改到 proxy。frida-gum 的 exceptor 也采用类似方式。安装过程无需暂停线程，每次命中会增加一次异常处理；首指令为 &lt;code&gt;adrp&lt;/code&gt; 的函数仍需先完成重定位。&lt;/p&gt;
&lt;p&gt;托管内存盲读统一使用 &lt;code&gt;process_vm_readv&lt;/code&gt;，非法地址返回 EFAULT；写入前先用 &lt;code&gt;safe_read&lt;/code&gt; 检查目标地址。实测读取速度约为 pipe 探测的四十倍。托管指针的顶字节还带有 TBI tag，解析前需要移除；日志中指针顶部的 &lt;code&gt;0xb4&lt;/code&gt; 帮助确认了这个问题。&lt;/p&gt;
&lt;h2 id=&quot;在运行时导出-il2cpp-符号&quot;&gt;在运行时导出 IL2CPP 符号&lt;/h2&gt;
&lt;p&gt;在 IL2CPP 层安装 hook，需要先确定函数地址。这个版本的 &lt;code&gt;CodeRegistration&lt;/code&gt; 和 &lt;code&gt;MetadataRegistration&lt;/code&gt; 都是零，Il2CppDumper 的 auto 和 manual 模式均失败。几年前的游戏版本还能通过明文 metadata 和两个注册地址静态导出符号，这个方法已经无法使用。&lt;/p&gt;
&lt;p&gt;IL2CPP 使用 AOT：C# 先转成 C++，再编译为 ARM64 机器码。&lt;code&gt;libil2cpp.so&lt;/code&gt; 中没有统一的解释执行入口，每个 C# 方法对应一个原生函数。运行时 metadata 仍保留方法指针，函数逻辑则需要在 IDA 中查看反汇编。&lt;/p&gt;
&lt;p&gt;模块可以从运行时 domain 枚举 assembly 和 class，再导出命名空间、父类、方法名、RVA、字段偏移与类型。结果包含 63,034 个类、412,674 个方法，共 69.8MB 文本，执行时间不到一秒。字段偏移来自当前进程中的实际布局。&lt;/p&gt;
&lt;h2 id=&quot;收包拦截-handlemsg发包拦截-pack&quot;&gt;收包拦截 HandleMsg，发包拦截 pack&lt;/h2&gt;
&lt;p&gt;拿到符号表后，我按消息覆盖范围选择 hook 点。&lt;/p&gt;
&lt;p&gt;区服名最初挂在服务器 URL 构造函数上。每个区服节点调用一次，一次登录触发一千两百多次，名字位于参数节点下层的托管字符串中。这个位置只能处理区服列表。&lt;/p&gt;
&lt;p&gt;协议封装层有出站序列化的 &lt;code&gt;CSPkg.pack&lt;/code&gt; 和入站反序列化的 &lt;code&gt;unpack&lt;/code&gt;。从这里可以拿到 &lt;code&gt;CSPkg&lt;/code&gt; 对象：&lt;code&gt;+0x10&lt;/code&gt; 是消息头，头里 &lt;code&gt;+0xc&lt;/code&gt; 是路由键 &lt;code&gt;dwMsgID&lt;/code&gt;，&lt;code&gt;+0x18&lt;/code&gt; 是消息体，消息体的 &lt;code&gt;+0x10&lt;/code&gt; 是实际消息对象。&lt;/p&gt;
&lt;p&gt;大厅阶段还有部分消息不经过 &lt;code&gt;unpack&lt;/code&gt;。继续查看调用关系后，收包分发入口确定为 &lt;code&gt;NetworkModule.HandleMsg&lt;/code&gt;，参数布局与 &lt;code&gt;CSPkg&lt;/code&gt; 一致，msgid 也能对应。最终收包拦截 &lt;code&gt;HandleMsg&lt;/code&gt;，发包拦截 &lt;code&gt;pack&lt;/code&gt;。登录重试阶段反复出现的 1014、1191 和 1193，分别对应重新登录通知、游戏服重定向通知和错误码通知，也与游戏日志中的方法名一致。&lt;/p&gt;
&lt;h2 id=&quot;从等长字节替换改成字段路径&quot;&gt;从等长字节替换改成字段路径&lt;/h2&gt;
&lt;p&gt;最早的实现会在消息体中搜索字节串，再原地替换成等长内容。「王者独尊」和「总裁牛逼」在 UTF-8 与 UTF-16LE 下长度相同，所以区服名验证能够成功。&lt;/p&gt;
&lt;p&gt;这种方式无法修改长度，也无法直接确认目标字段。&lt;/p&gt;
&lt;p&gt;我用反射 API 把消息对象递归写成 JSON：&lt;code&gt;il2cpp_object_get_class&lt;/code&gt; 获取类，&lt;code&gt;il2cpp_class_get_parent&lt;/code&gt; 遍历父类，再按 &lt;code&gt;il2cpp_type_get_name&lt;/code&gt; 选择读取方式。实例字段需要通过 flags 排除 static；第一版没有过滤，输出里混入了 &lt;code&gt;BASEVERSION&lt;/code&gt; 和 &lt;code&gt;CLASS_ID&lt;/code&gt; 等类常量。单条记录如下：&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;&quot;dir&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;r&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;&quot;msgid&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1193&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;&quot;cmd&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;SCID_NTF_ERRCODE&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;SCPKG_NTF_ERRCODE&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;&quot;body&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;&quot;stResultInfo&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:{&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;&quot;iResultId&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;11014&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;&quot;stArgList&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:{&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;&quot;iNum&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;&quot;astArgs&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:{&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;&quot;classId&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;148&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; &quot;jarrCount&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}},&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;&quot;m_classID&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;150&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;&quot;m_classID&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;3338&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;字段名和嵌套结构导出后，规则可以直接使用 &lt;code&gt;stResultInfo.iResultId&lt;/code&gt; 这样的路径。消息写入 JSONL 文件；logcat 会截断长行，消息量大时也会丢行，不适合保存几 KB 的消息。缓冲区写满时会补齐右括号并添加截断标记，保证每行仍可解析。&lt;/p&gt;
&lt;p&gt;收包在 &lt;code&gt;unpack&lt;/code&gt; 之后修改，对象会直接交给游戏逻辑；发包在 &lt;code&gt;pack&lt;/code&gt; 之前修改，TDR 会重新计算长度前缀。对象层可以替换数组指针，收包侧已验证可以扩展长度，发包侧仍受 schema 定长约束。&lt;/p&gt;
&lt;p&gt;8,868 个协议类中没有 &lt;code&gt;System.String&lt;/code&gt; 字段，文本使用 &lt;code&gt;System.Byte[]&lt;/code&gt;，共 1,155 处。文本改写需要用 &lt;code&gt;il2cpp_array_new&lt;/code&gt; 创建新数组。&lt;/p&gt;
&lt;h2 id=&quot;昵称空白来自-8-字节偏移&quot;&gt;昵称空白来自 8 字节偏移&lt;/h2&gt;
&lt;p&gt;账号最初所在的区服达到注册上限，登录阶段只能收到 1014、1191 和 1193 三条通知，其中没有文本字段。换到可以进入大厅的区服后，收包消息从 3 种增至 282 种，其中 21 个字段是文本 &lt;code&gt;Byte[]&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;挑中的是 &lt;code&gt;SCID_CMD_GAMELOGINRSP&lt;/code&gt;（1003）的 &lt;code&gt;szName&lt;/code&gt;，TDR schema 里定长 64 字节，原值「饿了狂吃三碗」18 字节，大厅左上角直接显示它。&lt;/p&gt;
&lt;p&gt;第一条规则我就写了个 78 字节的名字，故意超过 schema 的 64。logcat 里 &lt;code&gt;新 Byte[78](任意长)&lt;/code&gt; 打出来了，切到大厅一看，昵称位置是空的：&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://678234.xyz/optimized/upload/images/2026-07-26-WZRY-Protocol-Hook/nickname-blank-3f1f713ef2cd-768w.webp 768w, https://678234.xyz/optimized/upload/images/2026-07-26-WZRY-Protocol-Hook/nickname-blank-3f1f713ef2cd-1536w.webp 1536w&quot; sizes=&quot;(max-width: 800px) 100vw, 760px&quot;&gt;&lt;img src=&quot;https://678234.xyz/upload/images/2026-07-26-WZRY-Protocol-Hook/nickname-blank.png&quot; alt=&quot;大厅左上角昵称位置空白，只剩等级&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; fetchpriority=&quot;low&quot; width=&quot;2510&quot; height=&quot;1156&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;我先怀疑 78 字节超过限制，于是换成 15 字节短名字，界面仍然空白。问题出在数组写入方式。&lt;/p&gt;
&lt;p&gt;于是在改写之前，先把原数组从对象首地址起的 48 字节打出来：&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;+0x00  e08cdd496f0000b4                  klass&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;+0x08  0000000000000000                  monitor&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;+0x10  4000000000000000                  max_length = 0x40 = 64&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;+0x18  e9a5bf e4ba86 e78b82 e59083 ...   数据 = 饿了狂吃三碗&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;标准 &lt;code&gt;Il2CppArray&lt;/code&gt; 布局通常为 &lt;code&gt;+0x10&lt;/code&gt; bounds、&lt;code&gt;+0x18&lt;/code&gt; max_length、&lt;code&gt;+0x20&lt;/code&gt; 数据。当前 SO 的长度位于 &lt;code&gt;+0x10&lt;/code&gt;，数据从 &lt;code&gt;+0x18&lt;/code&gt; 开始，整体相差 8 字节。旧代码读取时漏掉开头，写入时在数据前留下 8 个零，游戏将其识别为空串。&lt;/p&gt;
&lt;p&gt;把偏移改成数据 &lt;code&gt;+0x18&lt;/code&gt;、长度 &lt;code&gt;+0x10&lt;/code&gt;，短名字立刻就出来了：&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://678234.xyz/optimized/upload/images/2026-07-26-WZRY-Protocol-Hook/nickname-ok-054fef87d875-768w.webp 768w, https://678234.xyz/optimized/upload/images/2026-07-26-WZRY-Protocol-Hook/nickname-ok-054fef87d875-1536w.webp 1536w&quot; sizes=&quot;(max-width: 800px) 100vw, 760px&quot;&gt;&lt;img src=&quot;https://678234.xyz/upload/images/2026-07-26-WZRY-Protocol-Hook/nickname-ok.png&quot; alt=&quot;大厅左上角昵称显示为「改写成功了」&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; fetchpriority=&quot;low&quot; width=&quot;2510&quot; height=&quot;1156&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;再使用 78 字节规则后，界面显示「任意长度改写验证」，后续内容被控件截断。本次收包对象成功读取并渲染了 78 字节数组，客户端改名界面的输入限制没有参与这条处理路径。&lt;/p&gt;
&lt;p&gt;发包时换入 99 字节数组，对象可以正常创建，pack 仍按 schema 中的 N 读取 &lt;code&gt;char szXxx[N]&lt;/code&gt;，超出部分不会发送。长度扩展目前只在收包侧验证成功。&lt;/p&gt;
&lt;h2 id=&quot;协议表使用相邻版本的数据&quot;&gt;协议表使用相邻版本的数据&lt;/h2&gt;
&lt;p&gt;拿到 msgid 还差一张表，得知道 1193 是什么、body 里都有哪些字段。&lt;/p&gt;
&lt;p&gt;相邻小版本的协议项目已经整理了 4,015 条命令 ID 映射，以及按 C# 类还原的 proto 和 TDR 定义。我抽查心跳、登录、匹配、商城和聊天消息，编号、类名与命名空间都能对应当前运行时 dump，便直接用作路由表。RVA 仍按当前版本重新定位。&lt;/p&gt;
&lt;p&gt;当前 dump 中筛出了 7,836 个协议消息类，并将字段名、类型和偏移导出为 JSON。相同协议名会同时出现在 &lt;code&gt;CSProtocol.*&lt;/code&gt; 和 &lt;code&gt;CSProtocolWrapper.*&lt;/code&gt; 中，前者是运行时引用类型，后者是 ValueType 镜像，字段偏移不同。索引最初使用短名，Wrapper 覆盖了运行时类型；改用全名并单独生成运行时索引后，字段偏移恢复正常。&lt;/p&gt;
&lt;h2 id=&quot;在-curl_easy_perform-读取最终-url&quot;&gt;在 curl_easy_perform 读取最终 URL&lt;/h2&gt;
&lt;p&gt;游戏还有一批 HTTP 请求，我也记录了它们的 URL。第一版按符号拦截 &lt;code&gt;libcrosCurl.so&lt;/code&gt; 导出的 &lt;code&gt;cros_curl_easy_setopt&lt;/code&gt;，只收到四次调用，option 都是 99（&lt;code&gt;CURLOPT_NOSIGNAL&lt;/code&gt;），没有出现 &lt;code&gt;CURLOPT_URL&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;静态反汇编显示，导出层会转到库内的非导出变参 setopt，再进入 &lt;code&gt;Curl_vsetopt&lt;/code&gt;。跳转表使用标准 curl option 编号，&lt;code&gt;CURLOPT_URL&lt;/code&gt; 为 10002。我按地址拦截库内 setopt，触发次数与导出层一致，收到的仍然只有 &lt;code&gt;CURLOPT_NOSIGNAL&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;libPluginCrosCurl.so&lt;/code&gt; 是一个 18KB 的 GCloud 插件，导出 &lt;code&gt;CurlFuncQueryService::QueryCurlFuncs&lt;/code&gt;。调用方通过函数指针表调用 curl，符号 hook 无法拦截设置 URL 的位置。&lt;/p&gt;
&lt;p&gt;我在两个库的 &lt;code&gt;curl_easy_perform&lt;/code&gt; 入口调用 &lt;code&gt;getinfo(handle, CURLINFO_EFFECTIVE_URL)&lt;/code&gt;，再将结果写入 JSONL。这样可以记录 MSDK、FaaS 的完整请求 URL，以及构造服务器地址时使用的 Tdir 字符串，并通过 &lt;code&gt;via&lt;/code&gt; 区分来源。&lt;/p&gt;
&lt;h2 id=&quot;消息工作台和远端规则&quot;&gt;消息工作台和远端规则&lt;/h2&gt;
&lt;p&gt;规则最初写在设备的 &lt;code&gt;wzry.cfg&lt;/code&gt; 中。每次修改都要编辑文件、推送并等待热重载；查看消息结构还要先读取 JSONL。大厅能收到 282 种消息，继续用配置文件操作很慢。&lt;/p&gt;
&lt;p&gt;我把消息查看和规则配置放到主机。设备上报收发消息，前端提供实时列表、历史记录和全文搜索，也可以直接创建规则。设备端只保留引导配置。&lt;/p&gt;
&lt;p&gt;传输使用局域网常驻 TCP，每帧由四字节大端长度和 JSON 组成。连接开启 &lt;code&gt;TCP_NODELAY&lt;/code&gt;；实测 Nagle 会增加约 40ms 决策延迟。收发直接调用 syscall，防止数据再次进入 libc hook 的 &lt;code&gt;scan()&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;局域网常驻连接的 300 次往返全部成功：P50 2.5ms、P99 5.0ms、最大 18.1ms。登录峰值达到每秒 264 条消息；全部同步决策时，网络线程单秒累计等待约 700ms。大厅空闲阶段约为每秒 5 条消息，累计等待 13ms。&lt;/p&gt;
&lt;p&gt;服务端会下发一份关注集。名单内的 msgid 使用同步决策，名单外直接放行并异步上报。单次超时或连续失败时，设备放行消息并熔断十秒，随后重新探测连接。&lt;/p&gt;
&lt;p&gt;服务端使用 Node 22 和内置的 &lt;code&gt;node:sqlite&lt;/code&gt;，启用 FTS5。TypeScript 由 Node 直接运行，一个进程提供 TCP 决策、HTTP 控制接口和前端静态文件。前端使用 Vite、React 与 react-router。&lt;/p&gt;
&lt;p&gt;界面现在是这样：&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://678234.xyz/optimized/upload/images/2026-07-26-WZRY-Protocol-Hook/workbench-af6add10b5b6-768w.webp 768w, https://678234.xyz/optimized/upload/images/2026-07-26-WZRY-Protocol-Hook/workbench-af6add10b5b6-1536w.webp 1536w&quot; sizes=&quot;(max-width: 800px) 100vw, 760px&quot;&gt;&lt;img src=&quot;https://678234.xyz/upload/images/2026-07-26-WZRY-Protocol-Hook/workbench.png&quot; alt=&quot;工作台实时页：左侧消息流按 npc 过滤，右侧是消息详情和 body 的 JSON 树&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; fetchpriority=&quot;low&quot; width=&quot;2000&quot; height=&quot;465&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;左侧消息流支持按方向、msgid 和名称过滤，也可以暂停。右侧显示消息头、运行时类名和 body 的 JSON 树。图中搜索 &lt;code&gt;npc&lt;/code&gt; 后找到了 &lt;code&gt;CSID_ADD_NPC_REQ&lt;/code&gt;（2015）。点击树中的字段可以创建改写规则，路径和当前值会自动填入。&lt;/p&gt;
&lt;p&gt;规则支持三种处置：&lt;code&gt;allow&lt;/code&gt; 原样放行、&lt;code&gt;patch&lt;/code&gt; 按字段路径修改、&lt;code&gt;drop&lt;/code&gt; 在发包侧丢弃。&lt;/p&gt;
&lt;h2 id=&quot;验证昵称金币和钻石&quot;&gt;验证昵称、金币和钻石&lt;/h2&gt;
&lt;p&gt;昵称规则用于验证远端下发。&lt;code&gt;synctimeout&lt;/code&gt; 最初按 30 字节空包的 P99 设为 5ms，真实事件 JSON 约 5KB，设备在收到决策前已经超时。放宽到 50ms 后，日志记录为 &lt;code&gt;决策回话 8323us&lt;/code&gt;。JSON 字符串值本身带引号，重复包装后昵称会显示为 &lt;code&gt;&quot;远端下发的名字&quot;&lt;/code&gt;，解析时需要去掉外层引号。&lt;/p&gt;
&lt;p&gt;货币数据位于登录响应。&lt;code&gt;SCPKG_CMD_GAMELOGINRSP&lt;/code&gt; 中有 &lt;code&gt;stCoinList.CoinCnt&lt;/code&gt;，类型为 &lt;code&gt;UInt32[]&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;完整登录后，&lt;code&gt;stCoinList.CoinCnt[1] = 6222&lt;/code&gt; 与界面金币一致，下标 6 的值 190 与钻石一致。&lt;code&gt;COM_COIN_TYPE&lt;/code&gt; 只能提供候选，这两个下标来自界面交叉确认。前端会保存人工确认的数组下标含义。&lt;/p&gt;
&lt;p&gt;原来的 JSON walker 遇到数值数组只记录长度，赋值也只支持 &lt;code&gt;Byte[]&lt;/code&gt;。这里增加了数组元素展开和 &lt;code&gt;name[idx]&lt;/code&gt; 路径语法。&lt;/p&gt;
&lt;p&gt;规则在页面上填两行就行：&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://678234.xyz/optimized/upload/images/2026-07-26-WZRY-Protocol-Hook/rule-editor-1c21ee9b9fba-768w.webp 768w, https://678234.xyz/optimized/upload/images/2026-07-26-WZRY-Protocol-Hook/rule-editor-1c21ee9b9fba-1536w.webp 1536w&quot; sizes=&quot;(max-width: 800px) 100vw, 760px&quot;&gt;&lt;img src=&quot;https://678234.xyz/upload/images/2026-07-26-WZRY-Protocol-Hook/rule-editor.png&quot; alt=&quot;规则编辑弹窗：收包、msgid 1003、patch 两条字段路径&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; fetchpriority=&quot;low&quot; width=&quot;2000&quot; height=&quot;1137&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;保存，重登，大厅顶上的数字就变了：&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://678234.xyz/optimized/upload/images/2026-07-26-WZRY-Protocol-Hook/coins-3c08ef13729c-768w.webp 768w, https://678234.xyz/optimized/upload/images/2026-07-26-WZRY-Protocol-Hook/coins-3c08ef13729c-1418w.webp 1418w&quot; sizes=&quot;(max-width: 800px) 100vw, 760px&quot;&gt;&lt;img src=&quot;https://678234.xyz/upload/images/2026-07-26-WZRY-Protocol-Hook/coins.png&quot; alt=&quot;大厅顶部显示金币 8888万、钻石 66666&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; fetchpriority=&quot;low&quot; width=&quot;1418&quot; height=&quot;536&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;点券不在 &lt;code&gt;CoinCnt&lt;/code&gt; 里，它有自己的消息 &lt;code&gt;SCPKG_CMD_ACNTCOUPONS&lt;/code&gt;（1161/1162），字段是 &lt;code&gt;llCouponsCnt&lt;/code&gt;，后来也验过了，同样能改。&lt;/p&gt;
&lt;p&gt;这些修改只影响 &lt;code&gt;unpack&lt;/code&gt; 后的客户端对象。服务器账户数据没有变化，购买请求仍会按服务器状态校验。&lt;/p&gt;
&lt;h2 id=&quot;协议按-msgid-分发消息&quot;&gt;协议按 msgid 分发消息&lt;/h2&gt;
&lt;p&gt;前端显示往返耗时，需要先配对请求和响应。&lt;code&gt;RegisterMsgHandler(msgid, delegate)&lt;/code&gt; 只按 msgid 建立索引，&lt;code&gt;HandleMsg&lt;/code&gt; 也根据包头 msgid 找到委托。分发过程中没有通用请求上下文、逐请求回调或关联令牌。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;CSPkgHead.dwSvrPkgSeq&lt;/code&gt; 是服务器包序号，客户端发包会回显最近收到的值，同一个序号可能连续出现在多条发包中；服务器主动通知的值为 0，属于 ack 语义。四千个消息类里只有 6 个带 &lt;code&gt;dwClientReqID&lt;/code&gt;。SCID 有 2,435 个，CSID 有 1,580 个，许多服务器通知没有对应请求。&lt;/p&gt;
&lt;p&gt;前端使用命名规则和时间窗口配对，&lt;code&gt;CSID_X_REQ&lt;/code&gt; 对应 &lt;code&gt;SCID_X_RSP&lt;/code&gt;。1,580 个 CSID 中有 1,280 个能按名称找到响应，耗时列会明确标记为推测值。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;HandleMsg&lt;/code&gt; 按 msgid 选择处理委托。构造 CSPkg 后交给这个入口，就能复用游戏已有的消息处理函数。&lt;/p&gt;
&lt;h2 id=&quot;构造-cspkg-并交给-handlemsg&quot;&gt;构造 CSPkg 并交给 HandleMsg&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;CSPkg&lt;/code&gt;、&lt;code&gt;CSPkgHead&lt;/code&gt; 和 &lt;code&gt;CSPkgBody&lt;/code&gt; 会经过真实收包路径，可以在 hook 中缓存对应的 class。&lt;code&gt;dataObject&lt;/code&gt; 的协议类需要按名称查找，模块会在 112 个程序集里调用 &lt;code&gt;il2cpp_class_from_name&lt;/code&gt;。&lt;code&gt;object_new&lt;/code&gt; 分配内存后，还要通过 &lt;code&gt;il2cpp_runtime_object_init&lt;/code&gt; 执行 TDR 生成的 &lt;code&gt;.ctor&lt;/code&gt;，创建子结构和定长数组。&lt;/p&gt;
&lt;p&gt;托管 API 需要在已经 attach domain 的线程上调用。在轮询线程直接调用会导致进程退出。远端命令会先进入队列，下一次 &lt;code&gt;HandleMsg&lt;/code&gt; 触发时再由游戏网络线程执行。队列在当前消息分发前清空，以保持到账通知先于 &lt;code&gt;_RSP&lt;/code&gt; 的实际顺序。&lt;/p&gt;
&lt;p&gt;注入 &lt;code&gt;1162 SCPKG_CMD_ACNTCOUPONS&lt;/code&gt; 并将 &lt;code&gt;llCouponsCnt&lt;/code&gt; 设为 777777 后，大厅顶栏显示 777777 点券。注入 &lt;code&gt;1823 SCPKG_HEROSKIN_ADD&lt;/code&gt; 后，商城中对应皮肤的按钮从「购买」变为「已拥有」。&lt;/p&gt;
&lt;h2 id=&quot;让客户端显示到账需要三类消息&quot;&gt;让客户端显示到账需要三类消息&lt;/h2&gt;
&lt;p&gt;我记录了一次购买小乔的完整时间线，一条请求对应七条服务端消息：&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;s 1817 CSID_BUYHERO_REQ                  dwBillNo=... bBuyType=2 dwHeroID=106&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;r 1010 SCID_ACNT_INFO_UPD                货币扣除&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;r 1504 CSID_TASKUPD_NTF                  任务进度&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;r 48601 SCID_COLLECT_VALUE_TOTAL_INFO_NTF&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;r 4403 SCID_ACHIEVEMENT_DONE_DATA_CHG_NTF&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;r 1810 SCID_HERO_INFO_UPD          ←     英雄到账，排在 _RSP 前面&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;r 1818 SCID_BUYHERO_RSP                  iResultId=0 dwHeroID=106 dwCoinCost=5888&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;r 51457 SCID_BUY_REGRET_INFO_NTF         反悔期信息&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;1810 SCID_HERO_INFO_UPD&lt;/code&gt; 在购买响应 &lt;code&gt;1818&lt;/code&gt; 之前到达。另一次皮肤购买因货币不足而失败，服务端只返回 &lt;code&gt;1820&lt;/code&gt;，&lt;code&gt;iResultId=13&lt;/code&gt;，&lt;code&gt;wCoinType&lt;/code&gt; 和 &lt;code&gt;dwCoinCost&lt;/code&gt; 都是 0。&lt;/p&gt;
&lt;p&gt;只把 &lt;code&gt;_RSP&lt;/code&gt; 结果码改为 0 时，客户端没有收到到账通知，也没有显示购买成功弹窗。&lt;/p&gt;
&lt;p&gt;注入到账通知后，客户端自动发送穿戴请求，服务端继续返回：&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;s 8566 CSID_CMD_SKIN_SUIT_REQ         客户端自动发的穿戴请求&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;r 8569 SCID_CMD_WEAR_SKIN_SUIT_RSP    iResultId=122009&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;r 8567 SCID_CMD_SKIN_SUIT_RSP         iResultId=0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;122009&lt;/code&gt; 对应下面的未拥有提示。此时商城按钮已经显示「已拥有」，穿戴请求仍被服务端拒绝：&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://678234.xyz/optimized/upload/images/2026-07-26-WZRY-Protocol-Hook/skin-owned-a7bb0e2aee76-768w.webp 768w, https://678234.xyz/optimized/upload/images/2026-07-26-WZRY-Protocol-Hook/skin-owned-a7bb0e2aee76-900w.webp 900w&quot; sizes=&quot;(max-width: 800px) 100vw, 760px&quot;&gt;&lt;img src=&quot;https://678234.xyz/upload/images/2026-07-26-WZRY-Protocol-Hook/skin-owned.png&quot; alt=&quot;商城里皮肤按钮显示已拥有，上方提示由于您尚未拥有翡翠华章皮肤，无法自动穿戴&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; fetchpriority=&quot;low&quot; width=&quot;900&quot; height=&quot;414&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;这次皮肤流程需要三处处理：模块注入 &lt;code&gt;1823&lt;/code&gt; 到账通知，规则将 &lt;code&gt;1820&lt;/code&gt; 的购买响应改为成功，再将 &lt;code&gt;8569&lt;/code&gt; 的穿戴校验结果改为成功。三条都只改变客户端当前会话中的显示和后续处理。&lt;/p&gt;
&lt;p&gt;购买请求只提供 &lt;code&gt;dwResID&lt;/code&gt;，到账通知使用 &lt;code&gt;dwHeroID&lt;/code&gt; 和 &lt;code&gt;bSkinID&lt;/code&gt;。换算关系为 &lt;code&gt;dwHeroID = dwResID / 100&lt;/code&gt;、&lt;code&gt;bSkinID = dwResID % 100&lt;/code&gt;；&lt;code&gt;18801&lt;/code&gt; 对应英雄 188 的 1 号皮肤。&lt;/p&gt;
&lt;h2 id=&quot;英雄拥有列表在登录时下发&quot;&gt;英雄拥有列表在登录时下发&lt;/h2&gt;
&lt;p&gt;注入英雄到账通知后，客户端显示了购买成功弹窗，商城列表仍显示未拥有。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;1886 SCID_ACNTHEROINFO_PARTTWO_NTY&lt;/code&gt; 在登录时下发英雄拥有列表，结构为 &lt;code&gt;dwHeroNum&lt;/code&gt; 加一个 200 槽位数组，我的账号当时 &lt;code&gt;dwHeroNum=12&lt;/code&gt;。&lt;code&gt;1810 SCID_HERO_INFO_UPD&lt;/code&gt; 只更新已有条目；列表中缺少目标英雄时，商城读取不到对应记录。&lt;/p&gt;
&lt;p&gt;处理方式是在 &lt;code&gt;1886&lt;/code&gt; 中增加 &lt;code&gt;dwHeroNum&lt;/code&gt;，并向空槽位写入英雄号。普通字段改写遇到空元素时停止，构造消息时则按元素类型创建对象。&lt;/p&gt;
&lt;h2 id=&quot;用模块处理计算和跨消息状态&quot;&gt;用模块处理计算和跨消息状态&lt;/h2&gt;
&lt;p&gt;规则适合把指定字段改成固定值。购买流程还需要根据 &lt;code&gt;dwResID&lt;/code&gt; 计算英雄号和皮肤号、记录已经处理的物品，并主动推送新消息。&lt;/p&gt;
&lt;p&gt;本地主机服务增加了模块脚本。脚本运行在 &lt;code&gt;node:vm&lt;/code&gt; 中，上下文只提供 &lt;code&gt;msg&lt;/code&gt;、&lt;code&gt;body&lt;/code&gt;、&lt;code&gt;get&lt;/code&gt;、&lt;code&gt;push&lt;/code&gt;、&lt;code&gt;patch&lt;/code&gt;、&lt;code&gt;store&lt;/code&gt;、&lt;code&gt;grants&lt;/code&gt; 和 &lt;code&gt;log&lt;/code&gt;。&lt;code&gt;on&lt;/code&gt; 声明触发条件，&lt;code&gt;handle&lt;/code&gt; 执行处理。皮肤模块的主体如下：&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;on &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { dir: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;s&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, msgid: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1819&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;handle&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;ctx&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; resid&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ctx.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;dwResID&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  ctx.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;push&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({ msgid: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1823&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, type: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;SCPKG_HEROSKIN_ADD&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, patch: [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    { path: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;dwHeroID&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, value: &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Math.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;floor&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(resid &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 100&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)) },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    { path: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;bSkinID&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,  value: &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(resid &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 100&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  ]});&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;ctx.store&lt;/code&gt; 保存模块自己的 KV 状态，&lt;code&gt;ctx.grants&lt;/code&gt; 按类型记录物品号。前端存储页可以查看和编辑这两类数据，也可以手工添加发放记录。&lt;/p&gt;
&lt;p&gt;固定字段改写继续使用规则；涉及计算、状态或消息推送时使用模块。&lt;/p&gt;
&lt;p&gt;模块命中次数最初 upsert 到 &lt;code&gt;modules&lt;/code&gt; 表。仓库模块命中后会产生一条 &lt;code&gt;code&lt;/code&gt; 为空的同名记录，数据库记录优先加载，导致文件模块失效。命中计数随后移到独立表中。&lt;/p&gt;
&lt;h2 id=&quot;当前范围&quot;&gt;当前范围&lt;/h2&gt;
&lt;p&gt;目前验证的是客户端消息改写和本地消息注入。金币、点券、英雄与皮肤状态都只改变当前客户端中的对象；切换场景或重新登录后，真实响应会覆盖这些状态，服务器账户数据保持原值。&lt;/p&gt;
&lt;p&gt;完整服务端还需要实现持久状态、业务逻辑和校验。文中的 IL2CPP RVA 只适用于 11.4.1.1 与 2026-06-14 构建，游戏更新后需要重新定位。&lt;/p&gt;</content:encoded><category>折腾</category><category>王者荣耀</category><category>王者荣耀私服</category><category>Android</category><category>逆向</category><category>IL2CPP</category><category>Zygisk</category></item><item><title>Codex Control Chrome MCP：把 Chrome 控制能力借给其他 Agent</title><link>https://678234.xyz/2026/06/26/Codex-Control-Chrome-MCP/</link><guid isPermaLink="true">https://678234.xyz/2026/06/26/Codex-Control-Chrome-MCP/</guid><pubDate>Fri, 26 Jun 2026 15:20:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;声明：本文包含 AI 辅助创作。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;最近扒了扒 Codex App 控制 Chrome 的办法。它通过 Codex Chrome Extension 接管用户平时使用的 Chrome Profile，登录态、Cookie、打开的标签页和已安装扩展都在。常见的浏览器自动化方案会新开一个干净的 Profile，有些还要求开启 &lt;code&gt;--remote-debugging-port&lt;/code&gt;。碰到需要登录的网站，重新收拾环境很麻烦。&lt;/p&gt;
&lt;p&gt;这套能力目前主要给 Codex App 使用。我想把通信链路抽出来包成 MCP，交给其他 Agent 工具。&lt;/p&gt;
&lt;p&gt;项目地址：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/iola1999/codex-control-chrome-mcp&quot;&gt;https://github.com/iola1999/codex-control-chrome-mcp&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;起因&quot;&gt;起因&lt;/h2&gt;
&lt;p&gt;我之前用 Chrome DevTools MCP 时，浏览器环境通常和日常 Chrome Profile 分开。隔离环境适合自动化测试。通用 Agent 经常卡在登录和环境配置上。&lt;/p&gt;
&lt;p&gt;典型问题包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;新 Profile 要重新登录网站；&lt;/li&gt;
&lt;li&gt;平时依赖的浏览器扩展需要再装一遍；&lt;/li&gt;
&lt;li&gt;当前打开的标签页接不过来；&lt;/li&gt;
&lt;li&gt;有些网站会对新设备或新登录态多做一次校验。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Codex Chrome Extension 直接运行在用户日常的 Chrome Profile 里，可以复用真实登录态和扩展。&lt;/p&gt;
&lt;h2 id=&quot;通信链路&quot;&gt;通信链路&lt;/h2&gt;
&lt;p&gt;扒完发现，链路走的是 Chrome Extension + Native Messaging。外部 CDP remote debugging port 没有参与。&lt;/p&gt;
&lt;p&gt;大致结构如下：&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Codex Chrome Extension&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  -&gt; chrome.runtime.connectNative(&quot;com.openai.codexextension&quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  -&gt; native messaging host&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  -&gt; chrome.debugger.attach / chrome.debugger.sendCommand&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  -&gt; CDP&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;扩展运行在日常 Chrome Profile 中，通过 Native Messaging host 和本地进程通信，再调用 &lt;code&gt;chrome.debugger&lt;/code&gt; 发送 CDP 命令。这样一来，现成的登录态和扩展都能直接用。&lt;/p&gt;
&lt;h2 id=&quot;做了什么&quot;&gt;做了什么&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;codex-control-chrome-mcp&lt;/code&gt; 在这条链路外包了一层 MCP：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;注册 &lt;code&gt;com.openai.codexextension&lt;/code&gt; 对应的 Native Messaging host；&lt;/li&gt;
&lt;li&gt;保存并代理 Codex 原有的 extension-host，让 Codex App 继续使用同一个入口；&lt;/li&gt;
&lt;li&gt;在本地开一个 bridge socket，供 MCP server 发送 JSON-RPC；&lt;/li&gt;
&lt;li&gt;MCP server 提供标签页、导航、CDP、截图和事件读取等工具；&lt;/li&gt;
&lt;li&gt;仓库内附带一份 skill，约束 Agent 调用工具的顺序。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;名字沿用了 Codex 官方 skill 里的 &lt;code&gt;control-chrome&lt;/code&gt;，后缀说明它是 MCP server。&lt;/p&gt;
&lt;h2 id=&quot;怎么用&quot;&gt;怎么用&lt;/h2&gt;
&lt;p&gt;前置条件是先装好 Codex Chrome Extension：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://chromewebstore.google.com/detail/hehggadaopoacecdllhhajmbjkdcmajg&quot;&gt;https://chromewebstore.google.com/detail/hehggadaopoacecdllhhajmbjkdcmajg&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;随后按仓库 README 安装 native host，再给支持 MCP 的 Agent 工具添加一份 stdio 配置。&lt;/p&gt;
&lt;p&gt;如果 Agent 支持 skill，也可以引用仓库里的 skill：&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;skills/codex-control-chrome-mcp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这份 skill 主要管调用顺序：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;先检查 MCP bridge 和扩展连接状态；&lt;/li&gt;
&lt;li&gt;复用已有页面时，先列出用户标签页，再 claim 对应 tab；&lt;/li&gt;
&lt;li&gt;做 CDP 之前先 attach；&lt;/li&gt;
&lt;li&gt;监听 Network/Runtime/Page 事件时，先 enable 对应 domain；&lt;/li&gt;
&lt;li&gt;结束前 finalize tabs，明确哪些标签页需要保留。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;步骤本身很短。模型自己猜时会搞错顺序、臆造 tab id，偶尔还会漏读事件。单独放一份 skill 能省下不少纠错时间。&lt;/p&gt;
&lt;h2 id=&quot;现在的状态&quot;&gt;现在的状态&lt;/h2&gt;
&lt;p&gt;目前版本已经能读取、claim、新建和导航标签页，也能发送原始 CDP 命令、读取网络与页面事件、截屏。包发在 npm 上，可以用 npx 启动；仓库里也带着配套 skill。&lt;/p&gt;
&lt;p&gt;我还在研究 Codex 自己的 &lt;code&gt;browser-client&lt;/code&gt;。眼下先把 tab 和 CDP 这些底层能力做稳，高层封装以后再说。&lt;/p&gt;
&lt;h2 id=&quot;适用场景&quot;&gt;适用场景&lt;/h2&gt;
&lt;p&gt;我主要拿它处理已经登录的网站和当前打开的页面。任务要调用浏览器扩展，或者需要通过 CDP 查网络、控制台、性能与 DOM 时，也不用再维护另一套 Profile。&lt;/p&gt;
&lt;p&gt;限制也很具体：项目依赖 Codex Chrome Extension 和 Native Messaging host 注册。同一时间，&lt;code&gt;com.openai.codexextension&lt;/code&gt; 只有一个 manifest 生效。项目会代理原有的 extension-host，让 Codex App 和 MCP 共用这个入口。&lt;/p&gt;
&lt;p&gt;浏览器自动化跑在哪个 Profile 里，很影响实际体验。日常 Agent 接手现成页面时，登录态和扩展都对得上，少了许多重复配置。这个项目把 Codex Chrome Extension 已有的控制链路接到 MCP 上，代码不算多，我自己用着挺省事。&lt;/p&gt;
&lt;p&gt;本文仅记录个人设备和个人环境下的技术调研与实现。浏览器 Profile 中可能包含敏感数据，请只在自己拥有并明确授权的场景中使用。&lt;/p&gt;</content:encoded><category>折腾</category><category>Codex</category><category>MCP</category><category>Chrome</category><category>AI</category></item><item><title>再谈如何愉快地使用钉钉</title><link>https://678234.xyz/2026/06/18/DingTalk-macOS-NoRead/</link><guid isPermaLink="true">https://678234.xyz/2026/06/18/DingTalk-macOS-NoRead/</guid><pubDate>Thu, 18 Jun 2026 12:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;声明：本文包含 AI 辅助创作。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;折腾仅因个人兴趣，记录分享仅为研究学习交流，请勿用于违法用途。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;起因&quot;&gt;起因&lt;/h2&gt;
&lt;p&gt;接着 &lt;a href=&quot;https://678234.xyz/2023/05/27/How-to-use-DingTalk-happily/&quot;&gt;如何愉快地使用钉钉&lt;/a&gt; 那篇往下写。上次写到「如何不让别人看自己的已读状态」时，我只放了几个参考链接。这次把 macOS 客户端上的做法补全。&lt;/p&gt;
&lt;p&gt;最近刷屏的《置身钉内》里有段话：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;钉钉的基因，从诞生的第一天起，就是永远站在「发信人」立场……为什么卡片里的消息一定要算已读，为什么系统要主动把事推到用户面前，很多答案，都可以回到这个原点。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;发消息时，我也喜欢看到「已读」。轮到自己收消息，这两个字有时就像一只盯着人的眼睛。我从客户端这一侧下手，给自己留一点「装没看见」的余地。碰到难回答的问题，至少还能先不说话。&lt;/p&gt;
&lt;h2 id=&quot;原理&quot;&gt;原理&lt;/h2&gt;
&lt;p&gt;钉钉的已读状态由客户端主动上报。点开会话后，客户端会发送消息状态 RPC，服务器更新状态，再把结果同步给其他设备和消息发送方。&lt;/p&gt;
&lt;p&gt;下面只讲运行时注入。通过启动脚本拉起的进程会加载 hook，从 Dock 或 Applications 启动时照常上报已读。&lt;/p&gt;
&lt;h2 id=&quot;调用链&quot;&gt;调用链&lt;/h2&gt;
&lt;p&gt;当前版本点开会话时会发送两类状态请求：&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;/r/IDLMessageStatus/updateToViewV2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;/r/IDLMessageStatus/updateToReadV2&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;顺序通常是先 View，再 Read。调用链如下：&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;用户点开会话&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  -&gt; 业务层生成消息状态 Request&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  -&gt; wukong::lwp::UserAgent::sendRequest&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  -&gt; GaeaMac LWP RPC&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  -&gt; /r/IDLMessageStatus/updateToViewV2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  -&gt; /r/IDLMessageStatus/updateToReadV2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  -&gt; 服务器更新消息状态&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这些请求走钉钉自己的 LWP RPC，最后都会进 GaeaMac。&lt;/p&gt;
&lt;p&gt;主程序从 &lt;code&gt;GaeaMac.framework&lt;/code&gt; 动态导入下面这个函数：&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;wukong::lwp::UserAgent::sendRequest(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    std::shared_ptr&amp;#x3C;wukong::lwp::Request&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    std::shared_ptr&amp;#x3C;wukong::lwp::RequestContext&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;用 fishhook 替换主程序的导入指针，就能在请求进入 GaeaMac 前读取 &lt;code&gt;requestLine&lt;/code&gt;。遇到 Read/View 状态路径时直接返回，其余 RPC 仍交给原函数发送。&lt;/p&gt;
&lt;p&gt;hook 只改当前进程里的动态导入指针，不会碰代码页和安装包内容。进程退出后，这次修改也就没了。&lt;/p&gt;
&lt;h2 id=&quot;文件结构&quot;&gt;文件结构&lt;/h2&gt;
&lt;p&gt;先准备这四个文件：&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;dingtalk-read/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;├── fishhook.c&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;├── fishhook.h&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;├── noread_hook.mm&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;└── launch_noread.sh&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;fishhook.c&lt;/code&gt; 和 &lt;code&gt;fishhook.h&lt;/code&gt; 取自 &lt;a href=&quot;https://github.com/facebook/fishhook&quot;&gt;facebook/fishhook&lt;/a&gt;，项目目录里已经放好了。&lt;/p&gt;
&lt;h2 id=&quot;hook-源码&quot;&gt;Hook 源码&lt;/h2&gt;
&lt;p&gt;新建 &lt;code&gt;noread_hook.mm&lt;/code&gt;：&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;objective-c&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// noread_hook.mm&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// Hook DingTalk&apos;s Wukong LWP request layer through its imported symbol.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;#include&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;fishhook.h&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;#include&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &amp;#x3C;dlfcn.h&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;#include&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &amp;#x3C;stdarg.h&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;#include&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &amp;#x3C;stdio.h&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;#include&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &amp;#x3C;stdlib.h&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;#include&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &amp;#x3C;atomic&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;#include&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &amp;#x3C;memory&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;#include&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &amp;#x3C;mutex&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;#include&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &amp;#x3C;string&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;#include&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &amp;#x3C;utility&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;namespace gaea::lwp {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;class Request;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;namespace wukong::lwp {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;class UserAgent;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;class Request;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;class RequestContext;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;namespace {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;constexpr &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; char&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;kSendRequestSymbol&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;    &quot;_ZN6wukong3lwp9UserAgent11sendRequestENSt3__110shared_ptrINS0_7RequestEEENS3_INS0_14RequestContextEEE&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;constexpr &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; char&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;kRequestLineSymbol&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;    &quot;_ZNK4gaea3lwp7Request11requestLineEv&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;constexpr &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; char&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;kReadV1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;/r/IDLMessageStatus/updateToRead&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;constexpr &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; char&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;kReadV2&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;/r/IDLMessageStatus/updateToReadV2&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;constexpr &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; char&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;kViewV1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;/r/IDLMessageStatus/updateToView&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;constexpr &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; char&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;kViewV2&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;/r/IDLMessageStatus/updateToViewV2&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;constexpr &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; char&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;kViewByEntrance&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;    &quot;/r/IDLMessageStatus/updateToViewByEntranceCid&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;using SendRequestFn &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    wukong::lwp::UserAgent &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    std::shared_ptr&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;wukong::lwp::Request&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    std::shared_ptr&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;wukong::lwp::RequestContext&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;using RequestLineFn &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; const&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; std::string &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; gaea::lwp::Request &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;SendRequestFn gOriginalSendRequest &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; nullptr;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;RequestLineFn gRequestLine &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; nullptr;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;std::mutex gLogMutex;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;std::atomic&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;unsigned&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; long&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; gSeenCount{&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;std::atomic&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;unsigned&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; long&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; gBlockedCount{&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;bool&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; gBlockMode &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; false&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; char&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;logPath&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; char&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;path &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; getenv&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;NOREAD_LOG&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; path &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt; path&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; path &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;/tmp/dingtalk-noread.log&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; logLine&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; char&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;format, ...) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    std::lock_guard&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;std::mutex&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; lock&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(gLogMutex);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    FILE &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;file &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; fopen&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;logPath&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(), &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;a&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;file) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    va_list args;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    va_start&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(args, format);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    vfprintf&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(file, format, args);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    va_end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(args);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    fflush&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(file);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    fclose&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(file);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;bool&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; isMessageStatusUpdate&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; std::string &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;requestLine) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; requestLine &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; kReadV1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; requestLine &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; kReadV2&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; ||&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;           requestLine &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; kViewV1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; requestLine &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; kViewV2&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; ||&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;           requestLine &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; kViewByEntrance&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; hookedSendRequest&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    wukong::lwp::UserAgent &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    std::shared_ptr&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;wukong::lwp::Request&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; request,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    std::shared_ptr&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;wukong::lwp::RequestContext&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; context) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; char&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;requestLineText &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;(unavailable)&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    bool&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; shouldBlock &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; false&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (request &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; gRequestLine) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        // wukong::lwp::Request derives from gaea::lwp::Request. The base&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        // subobject is at offset zero in the current GaeaMac build.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        const&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; auto &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;gaeaRequest &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            reinterpret_cast&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;const&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; gaea::lwp::Request &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(request.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;());&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        const&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; std::string &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;requestLine &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; gRequestLine&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(gaeaRequest);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        requestLineText &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; requestLine.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;c_str&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        shouldBlock &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; isMessageStatusUpdate&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(requestLine);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (requestLine.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;find&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;/r/IDLMessageStatus/&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;!=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; std::string::npos) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            const&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; unsigned&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; long&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; seen &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; ++&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;gSeenCount;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;            logLine&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;[NoRead] SEEN #&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;%lu&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; %s\n&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, seen, requestLineText);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (gBlockMode &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; shouldBlock) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        const&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; unsigned&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; long&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; blocked &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; ++&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;gBlockedCount;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;        logLine&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;[NoRead] BLOCKED #&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;%lu&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; %s\n&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, blocked, requestLineText);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (gOriginalSendRequest) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;        gOriginalSendRequest&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;std::move&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(request), &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;std::move&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(context));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}  &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// namespace&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;__attribute__&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;((constructor)) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; initializeNoReadHook&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; char&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;mode &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; getenv&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;NOREAD_MODE&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    gBlockMode &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; mode &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; std::string&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(mode) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;block&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    gRequestLine &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; reinterpret_cast&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;RequestLineFn&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;        dlsym&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(RTLD_DEFAULT, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;kRequestLineSymbol&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    struct&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; rebinding binding &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        kSendRequestSymbol&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        reinterpret_cast&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;void&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; *&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(hookedSendRequest),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        reinterpret_cast&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;void&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; **&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;gOriginalSendRequest),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; result &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; rebind_symbols&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;binding, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    logLine&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;        &quot;[NoRead] loaded mode=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;%s&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; rebind=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;%d&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; original=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;%p&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; requestLine=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;%p\n&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        gBlockMode &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;block&quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;observe&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        result,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        reinterpret_cast&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;void&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; *&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(gOriginalSendRequest),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        reinterpret_cast&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;void&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; *&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(gRequestLine));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这段代码有两个运行模式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;observe&lt;/code&gt;：记录消息状态 RPC，再调用原函数发送。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;block&lt;/code&gt;：记录并丢弃 Read/View 状态 RPC，其余请求照常发送。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;启动脚本&quot;&gt;启动脚本&lt;/h2&gt;
&lt;p&gt;新建 &lt;code&gt;launch_noread.sh&lt;/code&gt;：&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;#!/bin/bash&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -euo&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; pipefail&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;SCRIPT_DIR&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;$(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;$(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;dirname&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;$0&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;)&quot; &amp;#x26;&amp;#x26; &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;pwd&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;)&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;APP&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;/Applications/DingTalk.app&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;BIN&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$APP&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;/Contents/MacOS/DingTalk&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;DYLIB&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$SCRIPT_DIR&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;/dingtalk_noread.dylib&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;SOURCE&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$SCRIPT_DIR&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;/noread_hook.mm&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;FISHHOOK_C&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$SCRIPT_DIR&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;/fishhook.c&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;FISHHOOK_H&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$SCRIPT_DIR&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;/fishhook.h&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;ENTITLEMENTS&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$SCRIPT_DIR&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;/.entitlements.plist&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;LOG&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$SCRIPT_DIR&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;/noread.log&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;MODE&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;${1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;block&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [ &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$MODE&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; !=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;observe&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ] &amp;#x26;&amp;#x26; [ &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$MODE&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; !=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;block&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ]; &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;Usage: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;$0&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; [observe|block]&quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &gt;&amp;#x26;2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    exit&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; file &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$BIN&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$SOURCE&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$FISHHOOK_C&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$FISHHOOK_H&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [ &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -e&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$file&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ]; &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        echo&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;Missing: &lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$file&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &gt;&amp;#x26;2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        exit&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;done&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;command&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -v&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; clang&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &gt;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;/dev/null&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;command&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -v&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; clang++&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &gt;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;/dev/null&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;command&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -v&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; codesign&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &gt;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;/dev/null&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;NEED_BUILD&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [ &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$DYLIB&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ]; &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    NEED_BUILD&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;elif&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [ &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$SOURCE&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -nt&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$DYLIB&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;||&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;     [ &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$FISHHOOK_C&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -nt&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$DYLIB&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;||&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;     [ &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$FISHHOOK_H&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -nt&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$DYLIB&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ]; &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    NEED_BUILD&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [ &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$NEED_BUILD&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;1&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ]; &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    BUILD_DIR&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;mktemp&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -d&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    trap&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;rm -rf &quot;$BUILD_DIR&quot;&apos;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; EXIT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    clang&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -c&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -arch&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; arm64&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -O2&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -Wall&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -Wextra&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        -o&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$BUILD_DIR&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;/fishhook.o&quot;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$FISHHOOK_C&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    clang++&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -dynamiclib&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -arch&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; arm64&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -std=c++17&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        -framework&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; Foundation&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        -O2&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -Wall&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -Wextra&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -Wno-deprecated-declarations&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        -o&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$DYLIB&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$SOURCE&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$BUILD_DIR&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;/fishhook.o&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    rm&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -rf&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$BUILD_DIR&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    trap&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; EXIT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;codesign&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; --force&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; --sign&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$DYLIB&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &gt;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; 2&gt;&amp;#x26;1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# 钉钉更新后官方签名会恢复 disable-library-validation。启动脚本读取当前&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# entitlements，只翻转这一项，然后按 hardened runtime 方式重签 App 主层。&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;CURRENT_ENTITLEMENTS&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;mktemp&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;codesign&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -d&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; --entitlements&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; :-&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$BIN&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    &gt;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$CURRENT_ENTITLEMENTS&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; 2&gt;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;LIBRARY_VALIDATION&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    grep&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -oE&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;com\.apple\.security\.cs\.disable-library-validation&amp;#x3C;/key&gt;&amp;#x3C;(true|false)/&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;        &quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$CURRENT_ENTITLEMENTS&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    grep&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -oE&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;(true|false)/&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    tr&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -d&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;/&apos;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;rm&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$CURRENT_ENTITLEMENTS&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [ &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$LIBRARY_VALIDATION&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; !=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;true&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ]; &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    codesign&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -d&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; --entitlements&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; :-&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$APP&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        &gt;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$ENTITLEMENTS&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; 2&gt;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;/dev/null&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    python3&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$ENTITLEMENTS&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &amp;#x3C;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;PY&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;import plistlib&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;import sys&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;path = sys.argv[1]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;with open(path, &apos;rb&apos;) as source:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;    entitlements = plistlib.load(source)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;entitlements[&apos;com.apple.security.cs.disable-library-validation&apos;] = True&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;with open(path, &apos;wb&apos;) as target:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;    plistlib.dump(entitlements, target)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;PY&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    codesign&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; --force&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; --sign&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; --options&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; runtime&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        --entitlements&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$ENTITLEMENTS&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;        &quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$APP&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &gt;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$LOG&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;[launch_noread] starting @ $(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;+%F %T&apos;)&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;[launch_noread] app   = &lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$APP&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;[launch_noread] dylib = &lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$DYLIB&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    echo&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;[launch_noread] mode  = &lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$MODE&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$LOG&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    cd&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$APP&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;/Contents/MacOS&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    exec&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; env&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;        NOREAD_MODE=&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$MODE&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;        NOREAD_LOG=&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$LOG&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;        DYLD_INSERT_LIBRARIES=&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$DYLIB&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;        &quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$BIN&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$LOG&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; 2&gt;&amp;#x26;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; &amp;#x26;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;PID&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;$!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;[launch_noread] pid=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$PID&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$LOG&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;DingTalk started: pid=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$PID&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;, mode=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$MODE&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;Log: &lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$LOG&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;脚本会处理这些事：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;根据源码时间自动编译 &lt;code&gt;dingtalk_noread.dylib&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;给 dylib 做 ad-hoc 签名。&lt;/li&gt;
&lt;li&gt;应用更新后自动恢复注入所需的 entitlement。&lt;/li&gt;
&lt;li&gt;通过 &lt;code&gt;DYLD_INSERT_LIBRARIES&lt;/code&gt; 启动并写入独立日志。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;脚本实际执行的重签命令是：&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;codesign&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; --force&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; --sign&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; --options&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; runtime&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    --entitlements&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; .entitlements.plist&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;    /Applications/DingTalk.app&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;它会保留 hardened runtime，内嵌 framework 仍使用官方签名。&lt;/p&gt;
&lt;h2 id=&quot;使用方式&quot;&gt;使用方式&lt;/h2&gt;
&lt;p&gt;给脚本添加执行权限：&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;chmod&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; +x&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; launch_noread.sh&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;启动拦截模式：&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;./launch_noread.sh&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看请求但保留原生行为：&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;./launch_noread.sh&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; observe&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;实时查看日志：&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;tail&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; noread.log&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;日志判读&quot;&gt;日志判读&lt;/h2&gt;
&lt;p&gt;注入成功后，日志开头会出现：&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[NoRead] loaded mode=block rebind=0 original=0x11f1fe158 requestLine=0x11f1bb374&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;再点开一个会话，会看到：&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[NoRead] SEEN #1 /r/IDLMessageStatus/updateToViewV2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[NoRead] BLOCKED #1 /r/IDLMessageStatus/updateToViewV2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[NoRead] SEEN #2 /r/IDLMessageStatus/updateToReadV2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[NoRead] BLOCKED #2 /r/IDLMessageStatus/updateToReadV2&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;rebind=0&lt;/code&gt; 表示 fishhook 注册成功。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;original&lt;/code&gt; 有地址表示已拿到原始发送函数。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;requestLine&lt;/code&gt; 有地址表示可以读取 LWP 请求路径。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;BLOCKED&lt;/code&gt; 表示请求在进入 GaeaMac 之前已经被丢弃。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;验证&quot;&gt;验证&lt;/h2&gt;
&lt;p&gt;先记下启动时间，再在客户端点开一个新的未读会话。&lt;code&gt;noread.log&lt;/code&gt; 里应该出现 Read/View 的 &lt;code&gt;BLOCKED&lt;/code&gt; 记录。&lt;/p&gt;
&lt;p&gt;接着从当前进程打开的文件中找到原生 &lt;code&gt;gaea.log&lt;/code&gt;：&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;PID&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;pgrep&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;/Applications/.+\.app/Contents/MacOS/DingTalk&apos;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; head&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;LOG&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;lsof&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$PID&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; awk&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;/gaea\.log/{print $9}&apos;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; tail&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$LOG&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;再查注入启动后的发送记录：&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;grep&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -E&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;send request request_line=/r/IDLMessageStatus/updateTo(Read|View)&apos;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$LOG&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; tail&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -20&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果注入日志有 &lt;code&gt;BLOCKED&lt;/code&gt;，原生 RPC 日志还停在启动前的最后一条，请求就已经被截在 &lt;code&gt;wukong::lwp::UserAgent::sendRequest&lt;/code&gt; 这一层。&lt;/p&gt;
&lt;p&gt;也可以拿同账号的另一台设备对照。电脑端点开新的未读会话后，另一台设备应继续显示未读。&lt;/p&gt;
&lt;h2 id=&quot;普通启动&quot;&gt;普通启动&lt;/h2&gt;
&lt;p&gt;退出注入进程，再从 Applications 或 Dock 启动钉钉，已读功能就会恢复。&lt;/p&gt;
&lt;p&gt;命令行方式：&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;open&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; /Applications/DingTalk.app&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;版本更新&quot;&gt;版本更新&lt;/h2&gt;
&lt;p&gt;客户端更新后仍然运行这个启动脚本。它会重新读取 entitlements、编译 dylib，再启动注入进程。&lt;/p&gt;
&lt;p&gt;如果新版本改了 GaeaMac 的 C++ 符号，启动日志里的 &lt;code&gt;original&lt;/code&gt; 或 &lt;code&gt;requestLine&lt;/code&gt; 会变成空地址。遇到这种情况，用 &lt;code&gt;nm&lt;/code&gt; 重新确认两个导出符号：&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;APP&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;/Applications/DingTalk.app&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;BIN&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$APP&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;/Contents/MacOS/DingTalk&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;GAEA&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$APP&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;/Contents/Frameworks/GaeaMac.framework/Versions/A/GaeaMac&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;nm&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -arch&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; arm64&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -m&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$BIN&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; 2&gt;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; c++filt&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    grep&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;wukong::lwp::UserAgent::sendRequest&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;nm&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -arch&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; arm64&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$GAEA&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; 2&gt;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;/dev/null&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    grep&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;__ZNK4gaea3lwp7Request11requestLineEv&apos;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;使用边界&quot;&gt;使用边界&lt;/h2&gt;
&lt;p&gt;本文记录的是个人设备、个人账号和官方安装的 macOS 客户端。文中的逆向、调试与 Hook 只应用于自己拥有或明确获准测试的环境，请勿改动他人数据，也不要拿它规避正常的工作协作。&lt;/p&gt;
&lt;p&gt;-END-&lt;/p&gt;</content:encoded><category>折腾</category><category>钉钉</category><category>macOS</category><category>Objective-C++</category><category>Hook</category></item><item><title>王者荣耀 GM 调试面板入口验证记录</title><link>https://678234.xyz/2026/06/14/WZRY-GM-Panel/</link><guid isPermaLink="true">https://678234.xyz/2026/06/14/WZRY-GM-Panel/</guid><pubDate>Sun, 14 Jun 2026 12:55:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;声明：本文只记录个人设备和本地安装包上的分析结果，初稿由 AI 生成。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;结论&quot;&gt;结论&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;2026-06-17 更新：训练营中已能通过 &lt;code&gt;CheatCommandBattleEntry._GMDesignDebugCommand&lt;/code&gt; 唤起「策划属性调试」面板。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;测试对象是王者荣耀 Android 版 &lt;code&gt;11.3.1.1&lt;/code&gt;。目前确认了两条调试入口：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;外层 &lt;code&gt;CheatCode&lt;/code&gt; 配置面板，通过隐藏触摸暗码触发，还要 patch 设备登记检查。&lt;/li&gt;
&lt;li&gt;对局内的「策划属性调试」面板，需要先处理 TP 检测，再调用 &lt;code&gt;_GMDesignDebugCommand&lt;/code&gt;。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;在选服页 patch &lt;code&gt;libtprt&lt;/code&gt; 的线程创建函数后，进入对局没有再产生 crash 或 tombstone。旧截图里的 &lt;code&gt;GM指令&lt;/code&gt;、&lt;code&gt;DldGMPanel&lt;/code&gt; 和 &lt;code&gt;OpenGM&lt;/code&gt; 资源也还在，内容与体验服字节级一致；大厅中的直接入口暂时没找到。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;一外层-cheatcode-面板&quot;&gt;一、外层 CheatCode 面板&lt;/h2&gt;
&lt;h3 id=&quot;触发方式&quot;&gt;触发方式&lt;/h3&gt;
&lt;p&gt;触发点在启动阶段的开场视频/启动 Dialog 上，通过屏幕四角和中心区域的隐藏触摸暗码触发：&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;左上 -&gt; 右上 -&gt; 右上 -&gt; 右下 -&gt; 左下 -&gt; 中心&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;暗码由 Java 层的触摸事件处理器识别。命中后内部开关置为 true，随后进入 Unity 层的 GM/Cheat 显示逻辑。&lt;/p&gt;
&lt;h3 id=&quot;设备登记拦截&quot;&gt;设备登记拦截&lt;/h3&gt;
&lt;p&gt;暗码命中后，原始流程会先进入设备登记检查并显示弹窗：&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://678234.xyz/optimized/upload/images/2026-06-14-WZRY-GM-Panel/device-unregistered-ca9eff10329f-768w.webp 768w, https://678234.xyz/optimized/upload/images/2026-06-14-WZRY-GM-Panel/device-unregistered-ca9eff10329f-1536w.webp 1536w&quot; sizes=&quot;(max-width: 800px) 100vw, 760px&quot;&gt;&lt;img src=&quot;https://678234.xyz/upload/images/2026-06-14-WZRY-GM-Panel/device-unregistered.png&quot; alt=&quot;设备未登记弹窗&quot; decoding=&quot;async&quot; width=&quot;2510&quot; height=&quot;1156&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;设备未登记&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;请使用下列ID登记设备&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;否则未来会无法登录&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;点击确定复制&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;弹窗背后是 IL2CPP 侧的异步状态机。它会向服务端发 HTTP 请求，检查当前设备是否在白名单中。&lt;/p&gt;
&lt;h3 id=&quot;运行时-patch&quot;&gt;运行时 Patch&lt;/h3&gt;
&lt;p&gt;设备登记状态机里有一个条件分支。进程启动后、输入暗码前，用 root 权限修改当前进程内存，把这个分支 &lt;code&gt;nop&lt;/code&gt; 掉，流程就会走成功侧的清理路径并打开 CheatCode 面板。保留原指令时，流程会显示“设备未登记”弹窗。&lt;/p&gt;
&lt;p&gt;运行时 patch 只对当前 PID 生效。应用重启后，要给新 PID 再写一次。&lt;/p&gt;
&lt;h3 id=&quot;验证日志&quot;&gt;验证日志&lt;/h3&gt;
&lt;p&gt;暗码命中时，日志会打印 0~4 的区域序列，&lt;code&gt;m_bOpenCheat&lt;/code&gt; 和 &lt;code&gt;java IsShowCheatWindow&lt;/code&gt; 也会变成 &lt;code&gt;true&lt;/code&gt;。patch 前后的 PID 一致，可以确认内存修改与暗码触发发生在同一进程。&lt;/p&gt;
&lt;h3 id=&quot;cheatcode-面板&quot;&gt;CheatCode 面板&lt;/h3&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://678234.xyz/optimized/upload/images/2026-06-14-WZRY-GM-Panel/cheatcode-panel-9f1264ccdd7b-768w.webp 768w, https://678234.xyz/optimized/upload/images/2026-06-14-WZRY-GM-Panel/cheatcode-panel-9f1264ccdd7b-1536w.webp 1536w&quot; sizes=&quot;(max-width: 800px) 100vw, 760px&quot;&gt;&lt;img src=&quot;https://678234.xyz/upload/images/2026-06-14-WZRY-GM-Panel/cheatcode-panel.png&quot; alt=&quot;CheatCode 面板&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; fetchpriority=&quot;low&quot; width=&quot;2510&quot; height=&quot;1156&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;该面板偏配置/环境调试，可见项目包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;TVersion&lt;/code&gt; / &lt;code&gt;废弃 Tdir(mtcls)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;清空缓存&lt;/code&gt; / &lt;code&gt;清空Prefs&lt;/code&gt; / &lt;code&gt;清空Http缓存&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;离线云控配置&lt;/code&gt; / &lt;code&gt;显示缓存目录&lt;/code&gt; / &lt;code&gt;显示出错文件&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CachePatchSwitch&lt;/code&gt; / &lt;code&gt;QtsLibVerboseLog&lt;/code&gt; / &lt;code&gt;关闭所有SDK&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;启用网络诊断工具&lt;/code&gt; / &lt;code&gt;启用网络加速&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pandora测试环境&lt;/code&gt; / &lt;code&gt;强制使用Limited声音&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;禁用FormPreload&lt;/code&gt; / &lt;code&gt;Wwise不hookQts&lt;/code&gt; / &lt;code&gt;启用AudioService&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;方法暴露&quot;&gt;方法暴露&lt;/h3&gt;
&lt;p&gt;Java 层负责识别触摸暗码并切换显示开关。Unity/IL2CPP 层能找到 &lt;code&gt;IsEnableGM()&lt;/code&gt;、&lt;code&gt;OpenCheatForm()&lt;/code&gt; 等 Cheat 方法，面板也由这一层真正打开。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;二策划属性调试面板&quot;&gt;二、策划属性调试面板&lt;/h2&gt;
&lt;p&gt;旧截图里的 &lt;code&gt;GM指令&lt;/code&gt; / &lt;code&gt;GM 命令列表&lt;/code&gt; 界面走另一条分支。解析 metadata 后，&lt;code&gt;CheatCommandBattleEntry&lt;/code&gt; 类一共能找到 23 个方法，&lt;code&gt;_GMDesignDebugCommand&lt;/code&gt; 会打开对局内调试面板。这个方法要在对局或训练营中调用；大厅没有注册回调，拿到返回对象也不会渲染 UI。&lt;/p&gt;
&lt;p&gt;对局中使用动态调试工具会触发腾讯 TerSafe 检测，所以调用面板前还得先处理 TP。&lt;/p&gt;
&lt;h3 id=&quot;唤起方式&quot;&gt;唤起方式&lt;/h3&gt;
&lt;p&gt;一开始我用短时 Frida 调用确认了面板存在，随后两次遇到封号。&lt;code&gt;frida-agent.so&lt;/code&gt; 注入后会留在进程里，&lt;code&gt;frida-server&lt;/code&gt; 还要监听端口，这些都是 TP 的检测目标。实际链路是 TP 发现异常、进程崩溃、tombstone 上报，最后由服务器标记账号。&lt;/p&gt;
&lt;p&gt;后来换成了 9KB 的原生探针。它通过 ptrace 注入游戏进程，在 constructor 中调用 IL2CPP 的 &lt;code&gt;runtime_invoke&lt;/code&gt;，面板唤起后立刻退出。全程没有常驻后台进程和监听端口，内存里也不会长期留着 agent。&lt;/p&gt;



































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;Frida 方案&lt;/th&gt;&lt;th&gt;原生探针&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;注入物&lt;/td&gt;&lt;td&gt;frida-agent.so (~8MB)&lt;/td&gt;&lt;td&gt;自定义 .so (9KB)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;后台进程&lt;/td&gt;&lt;td&gt;frida-server 常驻&lt;/td&gt;&lt;td&gt;无&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;网络端口&lt;/td&gt;&lt;td&gt;27042&lt;/td&gt;&lt;td&gt;无&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;内存驻留&lt;/td&gt;&lt;td&gt;长期&lt;/td&gt;&lt;td&gt;constructor 执行完即退出&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;封号风险&lt;/td&gt;&lt;td&gt;高（已确认两次）&lt;/td&gt;&lt;td&gt;仍待验证&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h3 id=&quot;面板截图&quot;&gt;面板截图&lt;/h3&gt;
&lt;p&gt;训练营：&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://678234.xyz/optimized/upload/images/2026-06-14-WZRY-GM-Panel/design-attribute-debug-f72703634186-768w.webp 768w, https://678234.xyz/optimized/upload/images/2026-06-14-WZRY-GM-Panel/design-attribute-debug-f72703634186-1536w.webp 1536w&quot; sizes=&quot;(max-width: 800px) 100vw, 760px&quot;&gt;&lt;img src=&quot;https://678234.xyz/upload/images/2026-06-14-WZRY-GM-Panel/design-attribute-debug.png&quot; alt=&quot;策划属性调试面板-训练营&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; fetchpriority=&quot;low&quot; width=&quot;2510&quot; height=&quot;1156&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;离线单机模式：&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://678234.xyz/optimized/upload/images/2026-06-14-WZRY-GM-Panel/offline-design-debug-b97ee43cfe44-768w.webp 768w, https://678234.xyz/optimized/upload/images/2026-06-14-WZRY-GM-Panel/offline-design-debug-b97ee43cfe44-1536w.webp 1536w&quot; sizes=&quot;(max-width: 800px) 100vw, 760px&quot;&gt;&lt;img src=&quot;https://678234.xyz/upload/images/2026-06-14-WZRY-GM-Panel/offline-design-debug.png&quot; alt=&quot;策划属性调试面板-离线&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; fetchpriority=&quot;low&quot; width=&quot;2510&quot; height=&quot;1156&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;面板标题是「策划属性调试」，下面排着大量分类按钮，内容以对局属性和数值调试为主。UI 用独立 Canvas 渲染，遇到非标准分辨率时会缩得很小。Canvas 的 &lt;code&gt;set_scaleFactor&lt;/code&gt; 方法已经找到，适配还没做。&lt;/p&gt;
&lt;h3 id=&quot;方法列表&quot;&gt;方法列表&lt;/h3&gt;
&lt;p&gt;metadata 中的 &lt;code&gt;CheatCommandBattleEntry&lt;/code&gt; 一共有 23 个方法。下面这些已经逐个测过：&lt;/p&gt;



























































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;方法&lt;/th&gt;&lt;th&gt;argc&lt;/th&gt;&lt;th&gt;大厅&lt;/th&gt;&lt;th&gt;训练营&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;_GMDesignDebugCommand&lt;/code&gt;&lt;/td&gt;&lt;td&gt;0&lt;/td&gt;&lt;td&gt;返回对象，无 UI&lt;/td&gt;&lt;td&gt;&lt;strong&gt;弹出「策划属性调试」面板&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;_GMBluePrintFrameCommand&lt;/code&gt;&lt;/td&gt;&lt;td&gt;5&lt;/td&gt;&lt;td&gt;未测&lt;/td&gt;&lt;td&gt;蓝图调试面板（待测试）&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;SendCommand&lt;/code&gt;&lt;/td&gt;&lt;td&gt;7&lt;/td&gt;&lt;td&gt;未测&lt;/td&gt;&lt;td&gt;发送调试命令（待测试）&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;StartHighlightAutoToolFunc&lt;/code&gt;&lt;/td&gt;&lt;td&gt;0&lt;/td&gt;&lt;td&gt;&lt;strong&gt;异常&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;返回正常&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;IsPVECoop&lt;/code&gt;&lt;/td&gt;&lt;td&gt;0&lt;/td&gt;&lt;td&gt;true&lt;/td&gt;&lt;td&gt;true&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;SetKillNotifyText&lt;/code&gt;&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;正常执行&lt;/td&gt;&lt;td&gt;未测&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;RemoveAll&lt;/code&gt;&lt;/td&gt;&lt;td&gt;0&lt;/td&gt;&lt;td&gt;void&lt;/td&gt;&lt;td&gt;void&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;ResetSkinIds&lt;/code&gt;&lt;/td&gt;&lt;td&gt;0&lt;/td&gt;&lt;td&gt;未测&lt;/td&gt;&lt;td&gt;void&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h3 id=&quot;资源痕迹旧-gm-命令列表&quot;&gt;资源痕迹：旧 GM 命令列表&lt;/h3&gt;
&lt;p&gt;旧截图中包含 &lt;code&gt;GM指令&lt;/code&gt;、&lt;code&gt;DldGMPanel&lt;/code&gt;、&lt;code&gt;OpenGM&lt;/code&gt; 等字符串。对应的资源块 &lt;code&gt;5165_0.db&lt;/code&gt; 在当前版本中依然存在，内容与体验服字节级一致。当前版本里还能找到 GM/Cheat 系统、命令注册和命令历史等资源。&lt;/p&gt;
&lt;p&gt;我还没在大厅里直接打开这组资源。它可能依赖 UGC/Pandora app exposure 或特定对局上下文，从资源关系看是第三条面板分支。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;三脚本与后续&quot;&gt;三、脚本与后续&lt;/h2&gt;
&lt;h3 id=&quot;脚本&quot;&gt;脚本&lt;/h3&gt;
&lt;p&gt;分析时写的脚本都放在 &lt;code&gt;tools/runtime/&lt;/code&gt;：&lt;/p&gt;





































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;脚本&lt;/th&gt;&lt;th&gt;用途&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;open_sgame_cheatcode_panel_root.sh&lt;/code&gt;&lt;/td&gt;&lt;td&gt;启动阶段 patch + 暗码触发 CheatCode 面板&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;sgame_tp_race_patch.sh&lt;/code&gt;&lt;/td&gt;&lt;td&gt;ptrace 安全 patch libtprt，阻止 TP 检测线程启动&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;sgame_frida_cheatbattle_invoke.py&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Frida 短时调用 CheatCommandBattleEntry 方法&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;sgame_ptrace_memrw.cpp&lt;/code&gt;&lt;/td&gt;&lt;td&gt;ptrace 安全内存读写（编译为 ARM64 设备二进制）&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;sgame_metadata_index.py&lt;/code&gt;&lt;/td&gt;&lt;td&gt;global-metadata.dat 解析，方法/类型/token 索引&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;sgame_qtsvfs_gm_blocks.py&lt;/code&gt;&lt;/td&gt;&lt;td&gt;QtsVFS 资源块解析&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;sgame_qtsvfs_compare_blocks.py&lt;/code&gt;&lt;/td&gt;&lt;td&gt;正式服/体验服资源块字节级对比&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;设备侧工具路径：&lt;code&gt;/data/adb/.sgame_diag/&lt;/code&gt;。&lt;/p&gt;</content:encoded><category>折腾</category><category>王者荣耀</category><category>Android</category><category>逆向</category><category>调试</category><category>cheatcode</category></item><item><title>最近 Vibe Coding 的玩具们</title><link>https://678234.xyz/2026/05/18/Vibe-Coding-Toys/</link><guid isPermaLink="true">https://678234.xyz/2026/05/18/Vibe-Coding-Toys/</guid><pubDate>Mon, 18 May 2026 12:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;声明：本文包含 AI 辅助创作。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;刚水完一篇 &lt;a href=&quot;https://678234.xyz/2026/05/18/UURC-Web/&quot;&gt;UURC-Web&lt;/a&gt; 的逆向记录，回头盘了盘今年的业余项目，我才发现自己几乎没手写过代码。&lt;/p&gt;
&lt;p&gt;我的做法很固定：需求和现象由我讲，AI 负责查资料、改代码和跑排查；我盯结果，拿实机验收，跑偏了就让它重来。上班写业务代码也渐渐变成这个状态，业余项目更放飞。现在主要靠嘴干活，像个随时返工的监工。&lt;/p&gt;
&lt;p&gt;下面这些，就是最近下班后靠 Vibe 搓出来的玩具。&lt;/p&gt;
&lt;h2 id=&quot;1-uurc-web在公司浏览器里远程控制&quot;&gt;1. UURC-Web：在公司浏览器里远程控制&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/iola1999/uurc-web&quot;&gt;UURC-Web&lt;/a&gt; 是最近最合我心意的一个。公司电脑不让装远控，我就试着在浏览器里复刻 UU 远程。&lt;/p&gt;
&lt;p&gt;这活儿以前能让我掉一地头发：Android APK 要拆，native 层的 &lt;code&gt;libstreamer.so&lt;/code&gt; 要看，那套改过的 WebRTC 协议也得逐项对齐。&lt;/p&gt;
&lt;p&gt;给 AI 接上 IDA Pro MCP 后，它能直接进 so 库里翻 Protobuf 封包、找加密 Key。真正难查的一次卡死发生在开源以后：画面放着一直正常，接管鼠标几秒后就停。每次 &lt;code&gt;pointermove&lt;/code&gt; 都会触发三次左右的整棵组件树重渲染，100ms 一次的控制心跳被主线程拖慢；data channel 碰上背压时，旧代码还会把心跳彻底停掉。&lt;/p&gt;
&lt;p&gt;调试事件改用环形缓冲，输入处理从大 controller 里拆开，鼠标移动也合并到每个动画帧只发一次，这才把停推问题压住。Windows 键鼠随后又单独折腾了一轮：桌面端直接收 JSON 和归一化坐标，键盘用 VK 键码；网络稍慢时，远端会把 press 到 release 之间的延迟当成长按，&lt;code&gt;whoami&lt;/code&gt; 能打成 &lt;code&gt;whoooooami&lt;/code&gt;。现在普通键会在 &lt;code&gt;keydown&lt;/code&gt; 时立即发出一组 press + release，修饰键留到 &lt;code&gt;keyup&lt;/code&gt; 再释放。&lt;/p&gt;
&lt;p&gt;控制页现在会自动连设备，连续重连失败后改走 UU Relay，伙伴远程协助也能处理设备验证码和对端确认。音频和双向剪贴板也接上了。控制通道里的 &lt;code&gt;cursor shape&lt;/code&gt; 会跟着输入框、窗口边缘等状态变化，自定义 PNG 光标还保留热点和缩放。我大部分时间都在描述现象、抓日志和检查实机，AI 负责顺着线索改代码。&lt;/p&gt;
&lt;h2 id=&quot;2-smalldesktopdisplay桌上的像素乐园&quot;&gt;2. SmallDesktopDisplay：桌上的像素乐园&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/iola1999/SmallDesktopDisplay&quot;&gt;SmallDesktopDisplay&lt;/a&gt; 是个基于 ESP8266（ESP-12E）的桌面迷你显示器。以前玩单片机，总要写 C++、调 SPI 驱动，再盯着那点内存抠像素。&lt;/p&gt;
&lt;p&gt;这次我让 AI 按远程渲染架构来做。ESP8266 固件只管选择链路、上传按钮事件，再把收到的 RGB565 矩形帧刷到 TFT 屏幕。UI、页面状态和动画都在 &lt;code&gt;remote-render&lt;/code&gt; 服务里跑，由 Node.js、React、Yoga 和 Skia 生成 240x240 的画面。&lt;/p&gt;
&lt;p&gt;逻辑都在后端，加功能基本等于写前端。现在首页是时钟加萧山天气，公历旁边会显示农历、节气和节日；主题、字体、亮度可以在屏幕上调，也能从 Web 控制台看预览。之前塞进去的贪吃蛇、吃豆人和打砖块已经撤掉，数字雨背景在实机上也显得太乱，后来整个删了。少画这层背景以后，稳态传输量大约减半，全屏重同步从 28KB 降到了 9KB。&lt;/p&gt;
&lt;p&gt;屏幕接上实机后，预览图里好看的颜色到了 ST7789 上会发灰，Noto 天气图标也比文字高出 5～10px。我把实机现象继续丢给 AI，它给设备输出加上饱和度和暗部 gamma 补偿，又用真实字体逐像素量墨迹边界，把图标偏差压到 2px 左右。&lt;/p&gt;
&lt;p&gt;传输链路也重做了一遍。设备接上 USB 时，会在开机后的 1.5 秒内探测宿主机，连上就走 921600 波特率的串口推送，没探测到便继续用 WiFi。OrbStack 透不过 USB 串口，我这台 Mac 上的渲染服务也搬成了 launchd 常驻进程。相邻的差分色块会合并，CRC32 换成查表计算，TFT 的 SPI 时钟也从 27MHz 提到了 40MHz。现在时钟跳秒通常只传一个 747B 的矩形；最新一次实机记录里，全屏帧是 8.9KB，总耗时 128ms。&lt;/p&gt;
&lt;p&gt;串口第一次跑到真机上时冒出几个很怪的问题。我把日志丢给 AI，它查到健康检查拿旧的 &lt;code&gt;millis()&lt;/code&gt; 做减法，时间戳下溢成了约 42 亿，设备每两秒就误发一次探测；从 WiFi 切串口时，WiFi 反初始化又会阻塞，第一帧直接挤爆 4KB 的 RX 缓冲。它随后改成消费完帧再取新时间，先关 WiFi 再回复握手；宿主机收到设备重启的 &lt;code&gt;HELLO&lt;/code&gt; 也会立刻回应。&lt;/p&gt;
&lt;h2 id=&quot;3-x-tui在终端里摸鱼&quot;&gt;3. x-tui：在终端里摸鱼&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/iola1999/x-tui&quot;&gt;x-tui&lt;/a&gt; 是个 X（Twitter）终端客户端。官方网页用着太重，我便让 AI 做了一个跑在 Alt-buffer 里的全屏 TUI。&lt;/p&gt;
&lt;p&gt;技术栈很缝合：fork 了一份 &lt;code&gt;@anthropic/ink&lt;/code&gt;，再用 React 19 和 Bun 跑在终端里。操作方式照着 Vim 来，&lt;code&gt;j/k/gg/G&lt;/code&gt; 移动，&lt;code&gt;l/t/b&lt;/code&gt; 点赞、转推、收藏，&lt;code&gt;/&lt;/code&gt; 搜索。详情页退回列表时，SWR 缓存会保留内容和焦点位置。&lt;/p&gt;
&lt;p&gt;推文配图也能直接显示。iTerm2、Kitty 和 Ghostty 走各自的图片协议，其他终端退回半方块（Halfblock）字符画。我没细抠控制序列和光标跟踪，只提了句“想在终端里像 Vim 一样刷推，还要能发图”，代码就一批批冒出来了。&lt;/p&gt;
&lt;h2 id=&quot;4-anchordesk强迫症的资料库助手&quot;&gt;4. AnchorDesk：强迫症的资料库助手&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/iola1999/AnchorDesk&quot;&gt;AnchorDesk&lt;/a&gt; 看起来更像个正经产品原型，给个人和小团队整理工作资料用。&lt;/p&gt;
&lt;p&gt;它会解析 PDF、Docx、TXT 和 Markdown，切块后放进检索库。回答必须带引用，缺资料时再去网上查公开信息。&lt;/p&gt;
&lt;p&gt;BullMQ 任务调度和 Drizzle ORM 的 Schema 升级都是 Vibe 出来的，长报告的大纲生成与分章导出也一样。我的主要贡献，可能是 README 里那句“本项目采用 MIT 协议”。hh&lt;/p&gt;
&lt;h2 id=&quot;5-lapse-box旧手机的最后一点尊严&quot;&gt;5. Lapse-box：旧手机的最后一点尊严&lt;/h2&gt;
&lt;p&gt;这个还没开源，专门拿家里吃灰的 Android 旧手机拍延时。&lt;/p&gt;
&lt;p&gt;后台做的事还挺多。手机会连续扫描焦点，并测试不同 ISO 下的曝光和底噪；后端自动拉取原图、降噪，再用 FFmpeg 把几千张照片压成带时间戳的 4K 视频。&lt;/p&gt;
&lt;p&gt;旧手机固定在窗台上，每天盯着日出日落。我坐在电脑前，让 AI 帮忙修 Bug，等着看自动生成的延时预览。&lt;/p&gt;
&lt;p&gt;这几个月，我开始把时间花在拆问题上。API 的小坑交给 AI 处理，我去琢磨贪吃蛇的路径、远控延迟和系统的数据流。它写出的代码照样会犯蠢，有时修一个 Bug 又添两个，所以检查结果和及时叫停依旧少不了。&lt;/p&gt;
&lt;p&gt;顺便，这篇博客也是我 Vibe 出来的。摸鱼快乐！&lt;/p&gt;
&lt;p&gt;-END-&lt;/p&gt;</content:encoded><category>折腾</category><category>Vibe Coding</category><category>AI</category><category>玩具</category><category>效率</category></item><item><title>UURC-Web：如何愉快地从公司电脑连回家</title><link>https://678234.xyz/2026/05/18/UURC-Web/</link><guid isPermaLink="true">https://678234.xyz/2026/05/18/UURC-Web/</guid><pubDate>Mon, 18 May 2026 02:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;声明：本文包含 AI 辅助创作。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;折腾仅因个人兴趣，记录分享仅为研究学习交流，请勿用于违法用途。&lt;/p&gt;
&lt;p&gt;2026-07-19 更新：补上开源后两个月的排查记录，内容来自仓库里的实际提交和测试。&lt;/p&gt;
&lt;p&gt;2026-07-26 更新：加上我部署的公共实例地址，以及自部署的说明。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;很久没写这种长篇考古记录了。最近又开了个坑：&lt;a href=&quot;https://github.com/iola1999/uurc-web&quot;&gt;UURC-Web&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;公司电脑不让装第三方远控软件，可我偶尔还得连回家里那台 Mac。客户端装不了，那就试试浏览器。&lt;/p&gt;
&lt;p&gt;我给 AI 提了个需求：把网易 UU 远程（UURemote）接进网页。接下来几天，我主要在准备环境、描述现象和验收结果。&lt;/p&gt;
&lt;h2 id=&quot;为什么要折腾这玩意&quot;&gt;为什么要折腾这玩意？&lt;/h2&gt;
&lt;p&gt;UU 远程在 macOS 上延迟低，画质也不错。它没有网页版主控端，我便给 AI 接上 IDA Pro MCP，让它从官方客户端里找线索。&lt;/p&gt;
&lt;p&gt;目标很朴素：网页能登录、看屏幕，键盘鼠标也能用。中转服务放到 Cloudflare 的免费额度里，直连控制照常工作。&lt;/p&gt;
&lt;h2 id=&quot;考古现场&quot;&gt;考古现场&lt;/h2&gt;
&lt;h3 id=&quot;第一阶段拆解-android-apk&quot;&gt;第一阶段：拆解 Android APK&lt;/h3&gt;
&lt;p&gt;第一步是看官方客户端怎么做。Android 版 &lt;code&gt;com.netease.uuremote&lt;/code&gt; 交给 AI 后，它先跑了一次 &lt;code&gt;apktool d&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;业务逻辑基本都在 Java/Kotlin 层，走普通的 HTTPS 请求，也就是网易的 &lt;code&gt;nrd&lt;/code&gt; API。音视频流、信令（Signaling）和 WebRTC 协商都塞在 native 库 &lt;code&gt;libstreamer.so&lt;/code&gt; 里。&lt;/p&gt;
&lt;p&gt;硬骨头也在这里。AI 通过 IDA Pro MCP 顺着 native 符号往下翻，找到了 &lt;code&gt;socket.io&lt;/code&gt;、&lt;code&gt;SDP&lt;/code&gt;、&lt;code&gt;ICE&lt;/code&gt; 和 &lt;code&gt;DTLS/SRTP&lt;/code&gt;，最后理出三层：业务 API、Socket.io 信令、WebRTC 数据通道。&lt;/p&gt;
&lt;h3 id=&quot;第二阶段照着原生客户端的-webrtc-布局协商&quot;&gt;第二阶段：照着原生客户端的 WebRTC 布局协商&lt;/h3&gt;
&lt;p&gt;原生客户端会在 native 层创建 5 路 &lt;code&gt;video&lt;/code&gt; 收流和 1 路 &lt;code&gt;audio&lt;/code&gt;。浏览器端要照着这套 WebRTC 布局协商，费了不少劲。&lt;/p&gt;
&lt;p&gt;UU 的信令在 WebRTC 交换外又包了一层 &lt;code&gt;SOAC&lt;/code&gt;（Signaling Offer/Answer/Candidate），还会用 Gzip 压缩 SDP。受控端只认官方格式，AI 便照着原生客户端构造 Protobuf 风格的 Envelope 和二进制 payload。&lt;/p&gt;
&lt;h2 id=&quot;踩过的坑&quot;&gt;踩过的坑&lt;/h2&gt;
&lt;h3 id=&quot;鼠标一动画面就停&quot;&gt;鼠标一动，画面就停&lt;/h3&gt;
&lt;p&gt;刚开源时碰到过一个很邪门的问题：只看画面可以一直跑，接管鼠标后几秒就冻住，断开重连才能恢复。WebRTC stats 里显示的是 &lt;code&gt;transport_stalled&lt;/code&gt;，RTP 收包已经停了，受控端压根没再推流。&lt;/p&gt;
&lt;p&gt;问题出在输入热路径。每次 &lt;code&gt;pointermove&lt;/code&gt; 都会触发大约三次整棵组件树重渲染，还要深拷贝完整的会话状态。鼠标以 60～120Hz 移动时，主线程忙着跑 React，100ms 一次的控制心跳和 &lt;code&gt;EchoRequest&lt;/code&gt; 回复开始延迟。&lt;code&gt;channel.send&lt;/code&gt; 偶尔遇到背压，还会把心跳永久停掉。受控端超时后把主控判成离线，视频也随之停了。&lt;/p&gt;
&lt;p&gt;这部分修复由 AI 完成：调试事件放进环形缓冲，data channel 状态只在真正变化时推给 React，输入处理也从大 controller 中拆了出去。我负责反复移动和点击，把仍会卡住或丢落点的情况继续丢回去。后来它又把连续的鼠标移动合并到每个动画帧只发一次；点击发生前先补发当前位置，合并后也不会丢掉最后一个落点。&lt;/p&gt;
&lt;p&gt;卡顿诊断也跟着细分了。&lt;code&gt;transport_stalled&lt;/code&gt; 表示 RTP 已停，&lt;code&gt;decode_stalled&lt;/code&gt; 表示包还在进、解码帧数却没动。后者连续出现两次时会触发自动恢复，控制台同时记录 RTP 增量、ICE candidate pair 和信令状态，下一次再卡就有东西可查了。&lt;/p&gt;
&lt;h3 id=&quot;windows-画面正常键鼠全死&quot;&gt;Windows 画面正常，键鼠全死&lt;/h3&gt;
&lt;p&gt;Windows 端最初只能看到画面，鼠标和键盘完全没反应，console 里也没有报错。我把 Windows 受控端和官方 Android 主控端连好，再让 AI 重翻 &lt;code&gt;libinputmanager.so&lt;/code&gt;，对照控制通道抓包。它发现桌面端输入直接发送 JSON；Android 和 MuMu 会在外面包一层 &lt;code&gt;send_to_rom&lt;/code&gt; protobuf。当时的代码把 Windows 送进了移动端路径，被控端收到后直接丢弃。&lt;/p&gt;
&lt;p&gt;鼠标坐标和键码也各有一层转换。Windows 与 macOS 都收 &lt;code&gt;[0, 1]&lt;/code&gt; 范围的绝对坐标，代码当时发的是像素；键盘则要把 Android KeyCode 映射成 Windows VK，并带上官方报文里的 &lt;code&gt;interrept: true&lt;/code&gt;。把路由、坐标和键码补齐后，Windows 的键鼠终于开始工作。&lt;/p&gt;
&lt;p&gt;紧接着又出现了 &lt;code&gt;whoami&lt;/code&gt; 打成 &lt;code&gt;whoooooami&lt;/code&gt;。网络延迟拉长了 &lt;code&gt;kbd_press&lt;/code&gt; 到 &lt;code&gt;kbd_release&lt;/code&gt; 的间隔，UU 的 Windows 服务端把中间这段时间当成长按。最终处理是让 Ctrl、Alt、Shift、Meta 保持到 &lt;code&gt;keyup&lt;/code&gt; 再释放；普通按键在每次 &lt;code&gt;keydown&lt;/code&gt; 时立即发一组 press + release，长按重复交给浏览器自己的 repeat 事件。中文直接用远端输入法，复制粘贴走文本通道。&lt;/p&gt;
&lt;h3 id=&quot;右键alttab-和触控板&quot;&gt;右键、Alt+Tab 和触控板&lt;/h3&gt;
&lt;p&gt;输入能走通以后，还有些很碎、用起来又很烦的问题。浏览器右键菜单会吞掉 &lt;code&gt;pointerup&lt;/code&gt;，远端便一直以为右键还按着；Alt+Tab、切应用和切标签页也可能让系统吃掉 &lt;code&gt;keyup&lt;/code&gt;。现在 stage 失焦、window blur 或页面隐藏时都会调用 &lt;code&gt;releaseAllInputs&lt;/code&gt;，把记录中的按键和鼠标按钮全部抬起。&lt;/p&gt;
&lt;p&gt;滚轮也绕了一圈。React 的 &lt;code&gt;onWheel&lt;/code&gt; 是 passive listener，&lt;code&gt;preventDefault&lt;/code&gt; 拦不住页面跟着滚，所以控制区改用了原生的 non-passive listener。桌面端还要把 DOM 的内容滚动方向换成 UU 使用的原生滚轮方向，并统一 pixel、line、page 三种 delta。触控板的横轴噪声会先过滤，最终增益降到 0.5，不会轻轻一划就滚出去半页。&lt;/p&gt;
&lt;p&gt;多路视频时，早期代码用 &lt;code&gt;querySelector(&quot;video&quot;)&lt;/code&gt; 取到了第一路隐藏画面，鼠标坐标会按错误分辨率换算。现在只认正在显示的 video，并用同一套几何计算处理 &lt;code&gt;contain&lt;/code&gt; 留黑边和 &lt;code&gt;cover&lt;/code&gt; 裁切。最近接上的远端光标也复用了这套坐标，光标形状、热点和缩放能和画面对上。&lt;/p&gt;
&lt;h2 id=&quot;最近补上的功能&quot;&gt;最近补上的功能&lt;/h2&gt;
&lt;p&gt;连接流程现在会自动完成。进入控制页后，页面会加入设备并建立连接，control channel 打开后直接进入「控制中」，焦点也会落到画面上。设备若被自己上一个网页会话占着，会根据 participant 的 &lt;code&gt;clientId&lt;/code&gt; 自动接管；占用者是其他人时，页面仍会等你明确确认。自动路径连续重连失败两次后，下一次会强制走 UU Relay。&lt;/p&gt;
&lt;p&gt;伙伴远程协助也接进来了。登录后填对方的设备 ID 即可发起，前端会先查询受控端要求的验证方式：有设备验证码就带码加入，需要对方确认时留在等待状态，两种方式同时开启的设备也能走完。加入结果会返回目标平台，Windows、macOS 等输入协议由页面自己选择。&lt;/p&gt;
&lt;p&gt;界面上的改动比较杂。画面源会标出分辨率和「无信号」，切到空视频轨时直接显示「该画面暂无内容」，黑屏的原因一眼就能看到；命令栏平时停在画面上方，进入全屏后才变成可拖动浮层；「仅查看 / 控制中」可以随时暂停输入，连接和画面状态也换成了能看懂的中文。&lt;/p&gt;
&lt;p&gt;声音走独立播放器，工具栏可以静音和调音量，浏览器拦住自动播放时按钮会提示手动恢复。&lt;/p&gt;
&lt;p&gt;光标对操作感的影响比我预想中大。移到输入框、窗口边缘和链接上时，形状变化会直接告诉我远端当前能做什么。控制通道里的 &lt;code&gt;cursor shape&lt;/code&gt; 会被解析成本地光标，文本、等待、移动、缩放、手型等状态都能跟着远端走；远端发来的自定义 PNG 也会保留热点和缩放。鼠标操作优先使用浏览器原生光标，触摸设备或浏览器不支持图片光标时，页面会显示一层跟随指针的光标。它与输入坐标共用画面几何计算，切换视频源、画面留黑边或被裁切时，光标和实际点击位置也能对上。&lt;/p&gt;
&lt;p&gt;剪贴板两个方向都通。本机粘贴通过文本通道发到远端，受控端回传的 &lt;code&gt;RomMsg_Text&lt;/code&gt; 写进浏览器剪贴板，浏览器拒绝写入时内容会留在面板里，可以手动取用。&lt;/p&gt;
&lt;h2 id=&quot;现在的样子&quot;&gt;现在的样子&lt;/h2&gt;
&lt;p&gt;到 7 月，我已经会实际拿 &lt;a href=&quot;https://github.com/iola1999/uurc-web&quot;&gt;UURC-Web&lt;/a&gt; 干活了。短信验证码登录、账号凭证导入导出、设备状态和控制占用都能在网页里处理，Windows、macOS、Android 和 MuMu 也各自走对了输入路径。&lt;/p&gt;
&lt;p&gt;部署有两种方式：Docker 直接拉起，或者放到 Cloudflare Worker + Durable Objects，后者刚好能吃到免费额度，细节写在下一节。&lt;/p&gt;
&lt;h2 id=&quot;在线体验&quot;&gt;在线体验&lt;/h2&gt;
&lt;p&gt;公共实例：&lt;a href=&quot;https://uurc.678234.xyz&quot;&gt;https://uurc.678234.xyz&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这个入口适合看界面、走一遍基本流程。UU Remote Web 要处理短信登录、账号凭证和带鉴权的 UU API 请求，日常使用建议自己部署，验证码、账号登录和凭证导入这几步只在自己控制或者完全信任的实例上做。&lt;/p&gt;
&lt;p&gt;自部署里比较省事的是 Cloudflare Worker + Durable Object。Worker 负责页面、UU API 转发和信令网关，远控的画面、声音和输入仍然由浏览器通过 WebRTC 协商。自动路径会优先尝试局域网或者 P2P 直连，条件不满足时才走 UU 中转，部署到 Cloudflare 上不会关掉直连能力。&lt;/p&gt;
&lt;h2 id=&quot;后记&quot;&gt;后记&lt;/h2&gt;
&lt;p&gt;这个项目里最花时间的是把 native 层的调用链、协议字段和网页端实现对起来，&lt;code&gt;libstreamer.so&lt;/code&gt; 那几万行伪代码靠我自己读会非常慢。AI 做这部分效率比我高，我负责把现象说清楚、判断它查得有没有跑偏，再拿设备验证。这个分工在这个项目上是成立的。&lt;/p&gt;
&lt;p&gt;项目代码已经开源，有类似需求、或者想看看这套远控协议怎么跑，可以直接去仓库翻代码。&lt;/p&gt;
&lt;h2 id=&quot;使用边界&quot;&gt;使用边界&lt;/h2&gt;
&lt;p&gt;本文记录的是个人账号和自有设备上的研究过程。文中的逆向、抓包、调试与远控验证只应在自己拥有或明确授权的设备上进行，请勿连接或控制他人设备，也不要用这些方法规避平台或组织的管理要求。&lt;/p&gt;
&lt;p&gt;-END-&lt;/p&gt;</content:encoded><category>折腾</category><category>远控</category><category>逆向</category><category>WebRTC</category><category>Cloudflare</category></item><item><title>如何愉快地使用钉钉</title><link>https://678234.xyz/2023/05/27/How-to-use-DingTalk-happily/</link><guid isPermaLink="true">https://678234.xyz/2023/05/27/How-to-use-DingTalk-happily/</guid><pubDate>Sat, 27 May 2023 11:00:00 GMT</pubDate><content:encoded>&lt;p&gt;忙太久没冒泡了，水一篇工作相关的吧。&lt;/p&gt;
&lt;p&gt;标题有点科幻，不过最近确实解了钉钉上困扰我的两个问题：思考的间隙无意识点开钉钉看一眼，以及因为好奇谁没读我在群里发的消息而点击已读状态翻一翻。&lt;/p&gt;
&lt;p&gt;靠掰正习惯、调整心态来解决它们难度有点高，最近找了些技术流的解法效果不错，记录一下万一能帮到谁呢~&lt;/p&gt;
&lt;h2 id=&quot;如何避免无消息时看钉钉&quot;&gt;如何避免无消息时看钉钉&lt;/h2&gt;
&lt;p&gt;这个很好解决，以下几种一起用：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;不要设置弹出钉钉窗口的快捷键；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;将钉钉的小图标收起来，Windows 上托盘区自带了，macOS 上可以用 &lt;a href=&quot;https://github.com/dwarvesf/hidden&quot;&gt;Hidden Bar&lt;/a&gt; 这个软件；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Windows 能直接关掉钉钉窗口让它离开任务栏，而 macOS 上想隐藏 Dock 上的钉钉图标麻烦了些，查了些方案成本都有点高（比如得关 SIP 或者要借助些付费软件），对比下来还是 &lt;code&gt;sudo lsappinfo setinfo -app 钉钉 ApplicationType=UIElement&lt;/code&gt; 这样一行命令搞定最为方便，虽然有些副作用（影响不大就不写了），也可以临时 set 回 &lt;code&gt;Foreground&lt;/code&gt; 恢复；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[可选] 直接退出钉钉，隔久一点时间再打开看下或者单纯靠手机的通知被找。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;如何不去看别人的已读状态&quot;&gt;如何不去看别人的已读状态&lt;/h2&gt;
&lt;p&gt;这个就略技术流了，其实前面也水过几篇「调戏」钉钉的文档，例如 &lt;a href=&quot;https://678234.xyz/2021/01/21/DingTalk-mod/&quot;&gt;调戏钉钉 PC 客户端&lt;/a&gt;、 &lt;a href=&quot;https://678234.xyz/2021/09/15/DingTalk-Mod-Hook-CEF-Call/&quot;&gt;调戏钉钉 PC 客户端之 Hook CEF 函数调用&lt;/a&gt;，针对该问题的解决方案是通过修改前端代码隐藏会话窗口内的「x 人未读」的 DOM 节点，看不到自然也不会想去点击了。&lt;/p&gt;
&lt;p&gt;Windows 上需要参考前文找一下 webContents 压缩包密码，而 macOS 上的钉钉干脆直接没压缩 webContents &lt;del&gt;任人摆布&lt;/del&gt;（飞书：？）。&lt;/p&gt;
&lt;p&gt;要修改的文件是 &lt;code&gt;webContents/assets/chatbox-index.[hash].js&lt;/code&gt;（跟撤回的一样），文件中搜一下 &lt;code&gt;msg-unread-indicator&lt;/code&gt; 可以看到几处 createElement，不用管具体都是啥场景，都将第三个参数改成空字符串即可。&lt;/p&gt;
&lt;p&gt;不便拿公司电脑截图，本文就不附图了，效果完美到就跟钉钉没有已读回执这种 👻 东西一样。&lt;/p&gt;
&lt;h2 id=&quot;如何不让别人看自己的已读状态&quot;&gt;如何不让别人看自己的已读状态&lt;/h2&gt;
&lt;p&gt;这个是突然想起来的，但不在本文范围内，也不是很礼貌就不写了，感兴趣请参考 &lt;a href=&quot;https://www.freebuf.com/sectool/258385.html&quot;&gt;https://www.freebuf.com/sectool/258385.html&lt;/a&gt; 或 &lt;a href=&quot;https://blog.csdn.net/frozleaf/article/details/111569433%E3%80%82&quot;&gt;https://blog.csdn.net/frozleaf/article/details/111569433。&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;套话&quot;&gt;套话&lt;/h2&gt;
&lt;p&gt;折腾仅因个人兴趣，记录分享仅为研究学习交流，请勿用于违法用途。&lt;/p&gt;</content:encoded><category>折腾</category></item><item><title>在浏览器端计算 ssimulacra2</title><link>https://678234.xyz/2023/01/08/Calc-Ssimulacra2-in-FE/</link><guid isPermaLink="true">https://678234.xyz/2023/01/08/Calc-Ssimulacra2-in-FE/</guid><pubDate>Sun, 08 Jan 2023 11:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;受限于数据安全规定，暂不能贴出本文的完整版。当前已经有了 &lt;a href=&quot;https://github.com/plwljobue77256/nrs-binding-ssimulacra2&quot;&gt;napi 版本的 ssimulacra2&lt;/a&gt; 实现，可以用在 Node.js 服务端。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;关于图像处理&quot;&gt;关于图像处理&lt;/h2&gt;
&lt;p&gt;关于图片处理前后的质量差异，有多种评价指标: PSNR SSIM SSIMULACRA SSIMULACRA2&lt;/p&gt;
&lt;h2 id=&quot;计算-ssimulacra2&quot;&gt;计算 SSIMULACRA2&lt;/h2&gt;
&lt;h3 id=&quot;c&quot;&gt;C++&lt;/h3&gt;
&lt;p&gt;原版实现，官方仓库 &lt;a href=&quot;https://github.com/cloudinary/ssimulacra2&quot;&gt;https://github.com/cloudinary/ssimulacra2&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;编译困难，可执行环境有限。&lt;/p&gt;
&lt;h3 id=&quot;rust&quot;&gt;Rust&lt;/h3&gt;
&lt;p&gt;编译简单，支持多种可执行环境 &lt;a href=&quot;https://github.com/rust-av/ssimulacra2&quot;&gt;https://github.com/rust-av/ssimulacra2&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;纯-js-实现&quot;&gt;纯 JS 实现&lt;/h3&gt;
&lt;p&gt;性能问题、精度&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/iola1999/ssimulacra2-js&quot;&gt;https://github.com/iola1999/ssimulacra2-js&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;wasm&quot;&gt;Wasm&lt;/h3&gt;
&lt;p&gt;两种思路：虚拟文件系统、零拷贝 rgb 数组&lt;/p&gt;
&lt;h2 id=&quot;实现-wasm-方案&quot;&gt;实现 Wasm 方案&lt;/h2&gt;
&lt;p&gt;安装 rust 等等等等&lt;/p&gt;
&lt;h2 id=&quot;可用库&quot;&gt;可用库&lt;/h2&gt;
&lt;p&gt;npm 包 &lt;a href=&quot;https://github.com/iola1999/calc-s2-rust&quot;&gt;https://github.com/iola1999/calc-s2-rust&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;demo 演示 &lt;a href=&quot;https://calc-s2-vitefe.vercel.app/&quot;&gt;https://calc-s2-vitefe.vercel.app/&lt;/a&gt;&lt;/p&gt;</content:encoded><category>折腾</category></item><item><title>Web3.0 捞钱入门</title><link>https://678234.xyz/2022/04/09/Make-money-with-smart-contract/</link><guid isPermaLink="true">https://678234.xyz/2022/04/09/Make-money-with-smart-contract/</guid><pubDate>Sat, 09 Apr 2022 08:00:00 GMT</pubDate><content:encoded>&lt;p&gt;先看示例 &lt;a href=&quot;https://web3-fe.vercel.app/&quot;&gt;https://web3-fe.vercel.app/&lt;/a&gt; ，接下来分享如何实现它，看完你也有机会去捞钱。&lt;/p&gt;
&lt;h2 id=&quot;0x0-基础概念&quot;&gt;0x0 基础概念&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;这部分内容有官方更专业的表述： &lt;a href=&quot;https://ethereum.org/zh/developers/docs/intro-to-ethereum/&quot;&gt;https://ethereum.org/zh/developers/docs/intro-to-ethereum/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;以太坊网络&quot;&gt;以太坊网络&lt;/h3&gt;
&lt;p&gt;以太坊是一条区块链，最好的描述是将其描述为一个公共数据库，它由网络中的许多计算机更新和共享。&lt;/p&gt;
&lt;p&gt;“区块”指的是数据和状态是按顺序批量或”区块”存储的。 如果你向别人发送 ETH，需要将交易数据添加到一个区块中才算成功。&lt;/p&gt;
&lt;p&gt;“链”指的是每个区块加密引用其父块。 换句话说，区块被链接在一起。 在不改变所有后续区块的情况下，区块内数据是无法改变，但改变后续区块需要整个网络的共识。&lt;/p&gt;
&lt;h3 id=&quot;eth&quot;&gt;ETH&lt;/h3&gt;
&lt;p&gt;以太币 (ETH) 是以太坊上的的原生加密货币。 它存在目的是为了允许算力市场的存在。 这种市场为参与者提供了一种经济激励，以验证并执行交易请求，为网络提供计算资源。这也是大家对挖矿、加密数字货币的传统印象。&lt;/p&gt;
&lt;p&gt;当前，1 ETH 价格约 3200 USD ，大约 20400 CNY。&lt;/p&gt;
&lt;p&gt;比 ETH 更小的单位是 wei（致敬密码学的先驱戴伟（Wei Dai）），1 ETH = 10^9 Gwei = 10^18 wei。&lt;/p&gt;
&lt;h3 id=&quot;交易&quot;&gt;交易&lt;/h3&gt;
&lt;p&gt;在以太坊网络中，有一台规范化计算机（称为以太坊虚拟机，或 EVM），其状态得到以太坊网络中所有人的一致同意。 每个参与以太坊网络的人（每个以太坊节点）都会保存一份这台计算机的状态。 此外，任何参与者都可以广播请求这台计算机进行任意计算。 每当广播这样的请求网络时，网络上的其他参与者就会验证、确认并进行（“执行”）计算。 这个命令会导致 EVM 的状态变化，并且在整个网络中传播。&lt;/p&gt;
&lt;p&gt;计算请求被称为交易请求；所有交易的记录以及 EVM 的当前状态都存储在区块链中，而区块链又由所有节点存储并达成一致。&lt;/p&gt;
&lt;p&gt;以下为一些交易示例：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ETH 转账 &lt;a href=&quot;https://etherscan.io/tx/0x0aee0c2060a15a172701abbd17bde9c1ca7f11210a90002336aeb5d59d9454fe&quot;&gt;https://etherscan.io/tx/0x0aee0c2060a15a172701abbd17bde9c1ca7f11210a90002336aeb5d59d9454fe&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;发布智能合约代码（目标账户地址是 0） &lt;a href=&quot;https://etherscan.io/tx/0x8f7858f98c58d61c2648788f06affe505fde3b29cb35bd6256477eb5212a7203&quot;&gt;https://etherscan.io/tx/0x8f7858f98c58d61c2648788f06affe505fde3b29cb35bd6256477eb5212a7203&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;执行智能合约代码&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;智能合约&quot;&gt;智能合约&lt;/h3&gt;
&lt;p&gt;应用程序开发者将程序（可重复使用的代码片段）上传到 EVM 存储中，然后用户通过不同的参数请求执行这些代码片段。 我们将这些上传至网络并由网络执行的程序称为智能合约（类似后端服务），它不可被篡改。&lt;/p&gt;
&lt;p&gt;简单来说，你可以把智能合约想象成一种自动售货机：通过特定参数调用脚本后，如果满足某些特定条件，就会执行一些操作或计算。 例如，如果调用者将以太币发送给特定的接收者，通过简单的卖方智能合约就可以创建和分配数字资产所有权。&lt;/p&gt;
&lt;p&gt;任何开发者都可以创建智能合约并在网络上公开，并使用区块链作为其数据层，向网络支付费用。 然后，任何用户都可以调用智能合约来执行其代码，并再次向网络支付费用。&lt;/p&gt;
&lt;h3 id=&quot;帐户&quot;&gt;帐户&lt;/h3&gt;
&lt;p&gt;存储以太币之处。 用户可以初始化帐户，将以太币存入帐户，并将以太币转给其他用户。 帐户和帐户余额储存在 EVM 中的一个大表格中，是 EVM 总体状态的一部分。&lt;/p&gt;
&lt;p&gt;以太坊有两种帐户类型：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;外部持有 — 私钥的所有者控制&lt;/li&gt;
&lt;li&gt;合约 — 一种由代码控制，部署在网络上的智能合约。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;它们都能接收、持有和发送 ETH，与已部署的智能合约进行交互。&lt;/p&gt;
&lt;h3 id=&quot;钱包&quot;&gt;钱包&lt;/h3&gt;
&lt;p&gt;帐户和钱包不同。 账户是用户拥有的以太坊账户的密钥和地址对。 钱包是一个界面或者说应用程序，可以与以太坊账户交互。&lt;/p&gt;
&lt;p&gt;支持 ETH 的钱包非常多：&lt;a href=&quot;https://ethereum.org/zh/wallets/find-wallet/&quot;&gt;https://ethereum.org/zh/wallets/find-wallet/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;为了与 Web3.0 交互，可以考虑如 Chrome 浏览器插件：MetaMask 这样的钱包。&lt;/p&gt;
&lt;h3 id=&quot;gas&quot;&gt;Gas&lt;/h3&gt;
&lt;p&gt;以太坊允许开发者创建 去中心化应用 (dApp)，它们共享算力池。 这个共享池是有限的，因此以太坊需要一种机制来确定谁可以使用它。 否则，某个 dApp 可能会意外或恶意地消耗所有网络资源，从而导致其他应用程序无法访问算力池。&lt;/p&gt;
&lt;p&gt;ETH 加密货币支持以太坊算力的定价机制。 当用户想要完成一笔交易时，他们必须支付以太币，使他们的交易被区块链识别。 「交易」要是按照智能合约的规定一步一步执行命令，每执行一个命令都会产生一定的消耗，这个消耗以 Gas 作为单位，不同命令消耗的 Gas 数量也不相同。例如，加减计算的费用是 3 gas，计算 SHA-3 的费用是 30 gas，输出日志的费用是 8 gas / byte，写入存储的费用高达 20000 gas / 32 bytes。总的来说，消耗 CPU 比消耗存储便宜，简单计算比复杂计算便宜，读取比写入便宜。「查询」则不需要。&lt;/p&gt;
&lt;p&gt;这些使用成本被称为 gas 费用，gas 费用的多少取决于执行交易所需的算力和全网当时的算力需求。以太坊上的每一笔交易都包含一个值域，指定了要从发送者地址发送到接收者地址的 ETH 转移数量（以 wei ，10^-18 ETH，为单位）。当接收者地址是智能合约时，当智能合约执行其代码时，这些转移的以太币可用于支付 gas 费用。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;撰文时以太坊的 Gas Limit (即 Gas 限制) 是 1500 万 Gas，这是&lt;strong&gt;单个以太坊区块&lt;/strong&gt;中可以使用多少 Gas 数量的上限(也即是说，单个以太坊区块中包含的所有交易的 Gas 量加起来不能超过 1500 万)。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Gas 价格以 Gwei 标明，假设 gas 的价格是 20 Gwei（这个比例称为基本费用，最终会被燃烧销毁），当前一次交易基础费用 21000 gas，则需要支付交易费用 21000 * 20 = 420,000 Gwei = 0.00042 ETH（约 1.34 USD， 约 8.5 CNY）。&lt;/p&gt;
&lt;p&gt;Gas 一般用于描述交易费用，wei 则一般用于 ETH 金额单位。&lt;/p&gt;
&lt;p&gt;为了使交易更快地被确认，还可以在每 gas 对应的基本 Gwei 费用之外添加额外的小费（优先费），由矿工获得，大多数钱包会自动设置该值。&lt;/p&gt;
&lt;p&gt;还可以为交易设置最高费用，它与实际收费之间的差额将会退还给交易发起者。&lt;/p&gt;
&lt;h3 id=&quot;web3&quot;&gt;Web3&lt;/h3&gt;
&lt;p&gt;Web2 指的是我们如今众所周知的互联网版本。 一个在互联网公司掌控下提供服务来交换个人数据的互联网。 就以太坊而言，Web3 指的是在区块链上运行的去中心化应用。 任何用户都可以参与以太坊上的这些应用，个人数据却不会被出卖。&lt;/p&gt;
&lt;p&gt;Web3 就是一个去中心化的互联网，旨在打造出一个全新的合约系统，并颠覆个人和机构达成协议的方式。可以基于“无须信任的交互系统”在“各方之间实现创新的交互模式”。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;一些优点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;网络上的任何人都有使用服务的权限 — — 换言之，不需要许可。&lt;/li&gt;
&lt;li&gt;没有人可以屏蔽您或拒绝您访问该服务。&lt;/li&gt;
&lt;li&gt;付款是通过本地令牌即 ether (ETH) 构建的。&lt;/li&gt;
&lt;li&gt;以太坊是图灵完备的，这意味着你可以有很多程序部署在上面。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;局限性：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;交易进展较慢&lt;/li&gt;
&lt;li&gt;开发、使用学习门槛高，可访问性稍差&lt;/li&gt;
&lt;li&gt;成本较高，因此很多成功的 dApp 仅将其代码的一小部分放入区块链&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;是不是已经会了？有没有迫不及待地想了解如何捞钱，Let’s start！&lt;/p&gt;
&lt;h2 id=&quot;0x1-编写与部署智能合约&quot;&gt;0x1 编写与部署智能合约&lt;/h2&gt;
&lt;h3 id=&quot;了解测试网络&quot;&gt;了解测试网络&lt;/h3&gt;
&lt;p&gt;MetaMask 钱包中切换到 Ropsten 测试网络&lt;/p&gt;
&lt;p&gt;【图片待补充】&lt;/p&gt;
&lt;p&gt;可以在这里获取测试所需的 ETH 资产 &lt;a href=&quot;https://faucet.egorfine.com/&quot;&gt;https://faucet.egorfine.com/&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;测试网浏览器 &lt;a href=&quot;https://ropsten.etherscan.io/&quot;&gt;https://ropsten.etherscan.io/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;编写合约&quot;&gt;编写合约&lt;/h3&gt;
&lt;p&gt;HardHat 是一个 Ethereum 本地开发套件，用于智能合约的开发测试部署。&lt;/p&gt;
&lt;p&gt;使用 &lt;code&gt;npx hardhat init&lt;/code&gt;初始化项目。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;contracts&lt;/code&gt;sol 是 eth 合约后缀名，VSCode 插件：solidity。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;contract&lt;/code&gt;关键字声明合约。&lt;code&gt;view&lt;/code&gt;关键字是指该函数不更改 EVM 状态，也就不需要消耗 Gas**。**&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;//SPDX-License-Identifier: Unlicense&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;pragma solidity &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;^&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0.8&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;hardhat/console.sol&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;contract Counter {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    uint256 count;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    constructor&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        count &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    function&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; increment&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        count &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    function&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; getCount&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; view&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; returns&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;uint256&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; count;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;部署执行合约&quot;&gt;部署、执行合约&lt;/h3&gt;
&lt;p&gt;在 &lt;code&gt;hardhat.config.js&lt;/code&gt;文件中添加一个 &lt;code&gt;network&lt;/code&gt; 条目。 这里我们使用 Ropsten 测试网络。&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;@nomiclabs/hardhat-waffle&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// usePlugin(&quot;@nomiclabs/hardhat-waffle&quot;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// Go to https://infura.io/ and create a new project&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// Replace this with your Infura project ID&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; INFURA_PROJECT_ID&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;xxxxx&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// Replace this private key with your Ropsten account private key&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// To export your private key from Metamask, open Metamask and&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// go to Account Details &gt; Export Private Key&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// Be aware of NEVER putting real Ether into testing accounts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; ROPSTEN_PRIVATE_KEY&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;xxxxx&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// You need to export an object to set up your config&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// Go to https://hardhat.org/config/ to learn more&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/**&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt; * &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;@type&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt; import(&apos;hardhat/config&apos;).HardhatUserConfig&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt; */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;exports&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  solidity: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;0.8.4&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  networks: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    ropsten: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      url: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;`https://ropsten.infura.io/v3/${&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;INFURA_PROJECT_ID&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;}`&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      accounts: [&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;`0x${&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;ROPSTEN_PRIVATE_KEY&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;}`&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;infura 是一个网关，代理与以太坊交互。
周五（2022.4.22）晚间服务中断了一会儿
【图片待补充】&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;部署、执行合约的写法：&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; hre&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; require&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;hardhat&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; main&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; async&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; () &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Counter&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; hre.ethers.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getContractFactory&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Counter&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; counter&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Counter.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;deploy&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; counter.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;deployed&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  console.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;`deplyed at ${&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;counter&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;address&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;}`&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  let&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; count;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  count &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; counter.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getCount&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  console.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;`count(0) is ${&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;count&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;}`&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; counter.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;increment&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  count &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; counter.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getCount&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  console.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;`count(1) is ${&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;count&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;}`&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; incrementTx&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; counter.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;increment&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  // 等待确认&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; incrementTx.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;wait&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  count &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; counter.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getCount&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  console.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;`count(2) is ${&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;count&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;}`&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  .&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;then&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; process.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;exit&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  .&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;catch&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    console.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(error);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    process.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;exit&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  });&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;使用&lt;code&gt;npx hardhat run --network ropsten scripts/run.js&lt;/code&gt;来运行合约。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;$ npx hardhat run —network ropsten scripts/run.js
Compiled 1 Solidity file successfully
deplyed at 0x4a37bDf634b6D56b0A84Ec60939E11F0f16c0B44
count(0) is 0
count(1) is 0
count(2) is 2&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;可以在 &lt;code&gt;artifacts&lt;/code&gt;目录查看合约编译产物。反编译合约：&lt;a href=&quot;https://ropsten.etherscan.io/bytecode-decompiler?a=0x4a37bdf634b6d56b0a84ec60939e11f0f16c0b44&quot;&gt;https://ropsten.etherscan.io/bytecode-decompiler?a=0x4a37bdf634b6d56b0a84ec60939e11f0f16c0b44&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;每次重新部署都会产生新的合约地址，所以合约一经部署后是不能更新的，即使是被发现了 Bug。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;不过，也可以实现一种“可升级”的智能合约来实现迭代。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;可以看到 count(1) 还是旧的值，说明交易在被矿工确认过之前还不是真正“生效”的。&lt;/p&gt;
&lt;p&gt;合约交易执行完成后会返回一个 Transaction 对象，获取 count(2) 之前等待了这个交易确认（耗时可能要许久），获取的才是更新后的值。&lt;/p&gt;
&lt;p&gt;如需直接执行指定地址的合约，参考代码如下：&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; contractAddress&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;0x4a37bDf634b6D56b0A84Ec60939E11F0f16c0B44&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; counter&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; hre.ethers.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getContractAt&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Counter&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, contractAddress);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; count;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;count &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; counter.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getCount&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;console.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;`count(0) is ${&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;count&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;}`&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;检查-eth-支出&quot;&gt;检查 ETH 支出&lt;/h3&gt;
&lt;p&gt;在测试网浏览器上查看自己的钱包地址的 ETH 记录：&lt;a href=&quot;https://ropsten.etherscan.io/address/0x02f71c43977dfe2399a23ba4272493819fbf86b5&quot;&gt;https://ropsten.etherscan.io/address/0x02f71c43977dfe2399a23ba4272493819fbf86b5&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;【图片待补充】&lt;/p&gt;
&lt;p&gt;可以看到合约部署 + 合约调用及其 ETH 花费。&lt;/p&gt;
&lt;h3 id=&quot;在线编辑器&quot;&gt;在线编辑器&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;http://remix.ethereum.org/&quot;&gt;http://remix.ethereum.org/&lt;/a&gt; 这里可以在线编译、部署、调试调用合约，也十分方便。&lt;/p&gt;
&lt;h3 id=&quot;本地网络测试&quot;&gt;本地网络测试&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;因为公开测试网络的存在，开发调试已经很方便了，可以忽略本章节。本地网络在交易确认速度上很有优势。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;通过 &lt;code&gt;npx hardhat node&lt;/code&gt;可以启动一个本机节点，同时会提供一些测试钱包地址和私钥。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;$ npx hardhat node
Started HTTP and WebSocket JSON-RPC server at &lt;a href=&quot;http://127.0.0.1:8545/&quot;&gt;http://127.0.0.1:8545/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Accounts…&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Metamask 添加本地网络时，需要修改一下链 ID。&lt;/p&gt;
&lt;p&gt;【图片待补充】&lt;/p&gt;
&lt;p&gt;使用&lt;code&gt;npx hardhat run scripts/run.js --network localhost&lt;/code&gt;在本地网络运行合约&lt;/p&gt;
&lt;p&gt;节点这边日志看到成功部署：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Contract deployment: Counter
Contract address: 0x5fbdb2315678afecb367f032d93f642f64180aa3
Transaction: 0xdbd2def227498425ab0ebff63e56ba2b99a36101c7c1492c5dfb8365fbc345a3
From: 0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266
Value: 0 ETH
Gas used: 135941 of 135941
Block #1: 0x500048e068c01c318a005f663c3210ebf72ec33335477435cdb98ff8fe62551f&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;deplyed at 0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0
count(1) is 0
count(2) is 1
count(3) is 2&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;0x2-再来写写-web30-前端交互&quot;&gt;0x2 再来写写 Web3.0 前端交互&lt;/h2&gt;
&lt;p&gt;回到我们熟悉的领域了，不过你需要先了解一下…&lt;/p&gt;
&lt;h3 id=&quot;前端是如何跟链上智能合约通信的&quot;&gt;前端是如何跟链上智能合约通信的？&lt;/h3&gt;
&lt;p&gt;答案是使用浏览器插件。一般的 Web3.0 操作体验都是使用钱包登陆，钱包插件会在 &lt;code&gt;window&lt;/code&gt; 上挂载 &lt;code&gt;web3&lt;/code&gt;、&lt;code&gt;ethereum&lt;/code&gt;。前端代码通过钱包插件与网关交互，网关再进行链上数据查询或更新。&lt;/p&gt;
&lt;p&gt;那鲸探是怎么回事呢，抢 NTF 时为何没见过要折腾钱包？其原因是鲸探后端服务来替用户持有了链上账户，购买 NFT 后直接内部跟区块链交互了，门槛低了很多，但也少了开放性。（个人理解）&lt;/p&gt;
&lt;p&gt;这里我们继续使用 MetaMask 钱包，使用 npm 包 &lt;code&gt;ethers&lt;/code&gt; 来处理与钱包的连接工作。&lt;/p&gt;
&lt;h3 id=&quot;主要流程&quot;&gt;主要流程&lt;/h3&gt;
&lt;p&gt;先创建个前端项目 &lt;code&gt;npx create-react-app web3-fe --template typescript&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;与钱包交互的几个核心的方法如下：&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; checkIfWalletConnected&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; async&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; () &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  try&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;ethereum&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; window;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;ethereum) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      console.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;`please install metamask`&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;      return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; accounts&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ethereum.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;request&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      method: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;eth_accounts&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (accounts.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;length&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; !==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;      const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; account&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; accounts[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      console.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;`found account with address`&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, account);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;      setAccount&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(account);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      console.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;`no auth account found`&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;catch&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (err) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    console.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(err);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; connectWallet&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; async&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; () &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  try&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;ethereum&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; window;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;ethereum) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      console.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;`please install metamask`&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;      return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; accounts&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ethereum.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;request&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      method: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;eth_requestAccounts&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    console.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(accounts[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    setAccount&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(accounts[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;catch&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (err) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    console.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(err);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { ethers } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;ethers&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; abi &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;./utils/Counter.json&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; contractAddress&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;0x4a37bDf634b6D56b0A84Ec60939E11F0f16c0B44&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; contractABI&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; abi.abi;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; getCount&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; async&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; () &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  try&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;ethereum&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; window;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; provider&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ethers.providers.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Web3Provider&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(ethereum);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; signer&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; provider.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getSigner&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; CounterContract&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ethers.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Contract&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      contractAddress,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      contractABI,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      signer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; counts&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; CounterContract.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getCount&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    setCount&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(counts.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;toNumber&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;());&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;catch&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (err) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    console.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(err);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; increment&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; async&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; () &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  try&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;ethereum&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; window;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; provider&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ethers.providers.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Web3Provider&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(ethereum);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; signer&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; provider.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getSigner&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; CounterContract&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ethers.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Contract&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      contractAddress,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      contractABI,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      signer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; tx&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; CounterContract.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;increment&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; tx.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;wait&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    await&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; getCount&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;catch&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (err) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    console.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;err&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(err);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;UI 部分自行发挥，最终效果见演示。&lt;/p&gt;
&lt;p&gt;在请求交易时，浏览器钱包插件会弹出确认提示框：&lt;/p&gt;
&lt;p&gt;【图片待补充】【图片待补充】&lt;/p&gt;
&lt;p&gt;【图片待补充】&lt;/p&gt;
&lt;p&gt;完整前端代码供参考：&lt;a href=&quot;https://github.com/iola1999/web3-fe&quot;&gt;https://github.com/iola1999/web3-fe&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;0x3-不忘初心&quot;&gt;0x3 不忘初心&lt;/h2&gt;
&lt;p&gt;掌握了以上知识，如何捞钱？常见的捞钱方式有以下几种：&lt;/p&gt;
&lt;h3 id=&quot;发行-ntf&quot;&gt;发行 NTF&lt;/h3&gt;
&lt;p&gt;像素头像、盲盒、转&lt;del&gt;赠&lt;/del&gt;售一应俱全 &lt;a href=&quot;https://www.bilibili.com/video/BV1S341177sQ&quot;&gt;https://www.bilibili.com/video/BV1S341177sQ&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;发行数字货币&quot;&gt;发行数字货币&lt;/h3&gt;
&lt;p&gt;基于以太坊发行子货币 &lt;a href=&quot;https://solidity-cn.readthedocs.io/zh/develop/introduction-to-smart-contracts.html#subcurrency&quot;&gt;https://solidity-cn.readthedocs.io/zh/develop/introduction-to-smart-contracts.html#subcurrency&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;无门槛割韭菜，一键发行空气币 &lt;a href=&quot;https://mp.weixin.qq.com/s/JRQgpJfhIMVV8erSK3Dfcw&quot;&gt;https://mp.weixin.qq.com/s/JRQgpJfhIMVV8erSK3Dfcw&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;区块链彩票&quot;&gt;区块链彩票&lt;/h3&gt;
&lt;p&gt;基于开源智能合约的彩票，投注、开奖流程链上可查，可信度高。&lt;/p&gt;
&lt;p&gt;今天我们来重点演示一下这种方式如何捞钱，来这里体验：&lt;a href=&quot;https://web3-fe.vercel.app/lottery&quot;&gt;https://web3-fe.vercel.app/lottery&lt;/a&gt; 。&lt;/p&gt;
&lt;p&gt;放心，智能合约、前端源码已开源在：&lt;a href=&quot;https://github.com/iola1999/web3-fe&quot;&gt;https://github.com/iola1999/web3-fe&lt;/a&gt; ，非常之公平公正公开（比某彩高到不知哪里去了）。&lt;/p&gt;
&lt;p&gt;【图片待补充】&lt;/p&gt;
&lt;p&gt;【先演示一下钱包、连接、交易流程。】&lt;/p&gt;
&lt;p&gt;可以在这里领取测试网的 ETH：&lt;a href=&quot;https://faucet.egorfine.com/&quot;&gt;https://faucet.egorfine.com/&lt;/a&gt; ，也可以直接找我给你转账一些。&lt;/p&gt;
&lt;p&gt;中奖者将获得奖池里一半的 ETH，当然在测试链上这并没有什么价值。但是：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;最后祝您 — 财富自由。&lt;/strong&gt;&lt;/p&gt;</content:encoded><category>折腾</category></item></channel></rss>