<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>SunBK201&#39;s Blog</title>
    <link>http://blog.sunbk201.site/</link>
    <description>Recent content on SunBK201&#39;s Blog feedId:80934128438220800+userId:41428277522420736</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>zh-cn</language>
    <lastBuildDate>Sun, 03 Dec 2023 03:37:08 +0800</lastBuildDate><atom:link href="http://blog.sunbk201.site/feed.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>校园网防检测: UA3F - 新一代 UA 修改方法</title>
      <link>http://blog.sunbk201.site/posts/ua3f/</link>
      <pubDate>Sun, 03 Dec 2023 03:37:08 +0800</pubDate>
      
      <guid>http://blog.sunbk201.site/posts/ua3f/</guid>
      <description>&lt;h1 id=&#34;太长不看写于-202511&#34;&gt;太长不看（写于 2025.11）&lt;/h1&gt;
&lt;p&gt;修改 User-Agent 字段：使用 &lt;a href=&#34;https://github.com/SunBK201/UA3F&#34;&gt;UA3F&lt;/a&gt;，默认配置开箱即用，ipk 安装即可。&lt;/p&gt;
&lt;p&gt;UA3F 的使用教程见：&lt;a href=&#34;https://sunbk201public.notion.site/UA3F-2a21f32cbb4b80669e04ec1f053d0333&#34;&gt;猴子也能看懂的 UA3F 使用教程&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&#34;前言&#34;&gt;前言&lt;/h1&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;为了能够绕过校园网的接入设备数量的限制，有众多同仁对校园网的共享检测机制进行研究，我也在 &lt;a href=&#34;https://blog.sunbk201.site/crack-campus-network&#34;&gt;关于某大学校园网共享上网检测机制的研究与解决方案&lt;/a&gt; 一文中归纳总结出校园网的共享检测常见方法：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;TTL 字段的检测&lt;/li&gt;
&lt;li&gt;HTTP User-Agent 头部检测&lt;/li&gt;
&lt;li&gt;DPI 检测技术&lt;/li&gt;
&lt;li&gt;IPv4 Identification 字段&lt;/li&gt;
&lt;li&gt;时钟偏移的检测技术&lt;/li&gt;
&lt;li&gt;Flash Cookie 检测&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;其中上述的一部分方法随着历史原因与技术的迭代已经被废弃：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Flash Cookie 检测: 随着 HTML5 与 WebGL 等技术的出现，Flash 已经于 2020 年退出历史舞台&lt;/li&gt;
&lt;li&gt;IPv4 Identification 字段: 经过验证 iPhone、Mac 等移动设备的 Identification 会保持为 0&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;而剩下的时钟偏移的检测实际落地应用场景有待考证，DPI 检测技术由于会对网络设备造成过高的负载压力，因此部分高校可能不会开启此功能。&lt;/p&gt;
&lt;p&gt;对于 TTL 字段的检测，目前已有成熟有效的方法能够绕过检测，即利用 netfilter/iptables 对 TTL 进行修改即可。
那么目前防检测方案唯一有待优化的就是剩下来的 HTTP User-Agent 头部检测，而 User-Agent 头部检测也是目前各大高校最常用的防共享检测方案之一。
在之前的工作中，有同仁提出了 XMURP-UA，一个用于修改 User-Agent 的内核模块，但是存在性能以及无法处理 80 端口以外的流量等问题；为了弥补 XMURP-UA 的端口覆盖不全的问题，UA2F 被提出，其最大的贡献在于借助 libnetfilter_queue 将 TCP Flow 进行 HTTP 解析并将 UA 修改，该方法能够处理任意端口流量。&lt;/p&gt;
&lt;p&gt;但是经过长期的实践，UA2F 存在以下问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;由于依赖于 netfilter/libnetfilter_queue 的外部动态库，因此实际构建与部署较为复杂，需要涉及对 OpenWrt 的交叉编译，对用户存在门槛。&lt;/li&gt;
&lt;li&gt;UA2F 依赖于 netfilter/iptables 进行流重定向，因此与 Clash 等代理工具存在冲突问题，因此对于依赖于 Clash 等代理工具的用户，不得不采用二级路由的形式已实现 Clash 与 UA2F 的共存。&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;ua3f-新一代-ua-修改方法&#34;&gt;UA3F: 新一代 UA 修改方法&lt;/h1&gt;
&lt;p&gt;为了解决上述 UA2F 存在的问题，我提出一种全新的 HTTP User-Agent 修改方法: &lt;a href=&#34;https://github.com/SunBK201/UA3F&#34;&gt;UA3F&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://sunbk201.oss-cn-beijing.aliyuncs.com/img/ua3f&#34; alt=&#34;UA3F&#34;&gt;&lt;/p&gt;
&lt;p&gt;由上图所示，UA3F 依赖于 Clash 等基于规则的代理工具，UA3F 本身最为一个 SOCKS5 代理对本机提供服务，借助 Clash，UA3F 能够捕获入站全部流量，由 Clash 向 UA3F 转发的全部潜在的 HTTP 流量，这里值得注意的是，UA3F 可以接受任何基于 TCP 协议的流量，但是只关注于 HTTP，UA3F 会尝试解析 TCP 流并判断当前连接是否承载 HTTP 流量，如果判定非 HTTP 连接，则直接转发，如果判定为 HTTP 连接，则进行 HTTP 流量解析并定位修改 User-Agent 头部。&lt;/p&gt;
&lt;p&gt;通过上述方式，UA3F 可以做到：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;与 Clash 共存&lt;/li&gt;
&lt;li&gt;借助 Clash 的流量重定向，UA3F 可以截获到全部 HTTP 流量&lt;/li&gt;
&lt;li&gt;UA3F 对外作为一个定制的 SOCKS5 代理，与 Clash 部署到同一路由器设备，相当于将远程的代理服务器转移到本地，由本地进行流量转发处理，因此 UA3F 依赖 Clash 但并不需要外部远程代理服务器进行加密代理转发。&lt;/li&gt;
&lt;li&gt;自定义 UA 内容&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;ua3f-使用&#34;&gt;UA3F 使用&lt;/h1&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 无参数执行，默认监听端口为 1080，默认 UA 修改为 FFF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;./ua3f
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 可以修改监听端口与自定义 UA&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 以下通过下面参数可以让 UA3F 监听端口为 8080，UA 修改为 HELLO&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;./ua3f -p &lt;span style=&#34;color:#ae81ff&#34;&gt;8080&lt;/span&gt; -f HELLO
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;UA3F 作为一个 SOCK5 服务，Clash 可以十分方便进行配接入，下面提供一个 Clash 的配置用于接入：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;proxies&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ua3f&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;type&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;socks5&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;server&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;127.0.0.1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;port&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;1080&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;url&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;http://connectivitycheck.platform.hicloud.com/generate_204&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;rules&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  - &lt;span style=&#34;color:#ae81ff&#34;&gt;PROCESS-NAME,ua3f,DIRECT&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  - &lt;span style=&#34;color:#ae81ff&#34;&gt;MATCH,ua3f&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里值得注意的是，请确保 &lt;code&gt;PROCESS-NAME,ua3f,DIRECT&lt;/code&gt; 置于规则列表的最顶部。
对于部分用户有代理加密需求的用户，可以在上述 2 条规则之间加入自定义的加密代理规则，例如:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;rules&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  - &lt;span style=&#34;color:#ae81ff&#34;&gt;PROCESS-NAME,ua3f,DIRECT&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  - &lt;span style=&#34;color:#ae81ff&#34;&gt;DOMAIN-SUFFIX,google.com,Proxy&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  - &lt;span style=&#34;color:#ae81ff&#34;&gt;MATCH,ua3f&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;通过与加密代理的配合，可以实现：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;直连网络流量通过 UA3F 进行处理转发&lt;/li&gt;
&lt;li&gt;加密代理网络流量通过 Clash 连接外部代理服务器进行代理转发&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;结束&#34;&gt;结束&lt;/h1&gt;
&lt;p&gt;校园网防共享检测的需求对我来说已经消失，但是观察到目前现有方法的限制与问题，我进行了 UA3F 的初步实现，目前已经开源: &lt;a href=&#34;https://github.com/SunBK201/UA3F&#34;&gt;https://github.com/SunBK201/UA3F&lt;/a&gt;，UA3F 的实现处于初级阶段，可能存在一些问题，因此欢迎各位同学进行反馈与指正。&lt;/p&gt;
&lt;p&gt;欢迎加入讨论组进行讨论交流：&lt;a href=&#34;https://t.me/crack_campus_network&#34;&gt;Telegram&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>命令行界面设计指南</title>
      <link>http://blog.sunbk201.site/posts/cli-guidelines-zh/</link>
      <pubDate>Sun, 15 Jan 2023 00:28:23 +0800</pubDate>
      
      <guid>http://blog.sunbk201.site/posts/cli-guidelines-zh/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://sunbk201.github.io/cli-guidelines-zh/&#34;&gt;https://sunbk201.github.io/cli-guidelines-zh/&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>About</title>
      <link>http://blog.sunbk201.site/about/</link>
      <pubDate>Sun, 01 Jan 2023 00:00:00 +0000</pubDate>
      
      <guid>http://blog.sunbk201.site/about/</guid>
      <description>&lt;p&gt;hi guys!&lt;/p&gt;
&lt;p&gt;Contact Me: &lt;a href=&#34;mailto:me@sunbk201.com&#34;&gt;me@sunbk201.com&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Twitter &lt;a href=&#34;https://twitter.com/SunBK201&#34;&gt;@SunBK201&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;GitHub &lt;a href=&#34;https://github.com/SunBK201&#34;&gt;@SunBK201&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;RSS &lt;a href=&#34;https://blog.sunbk201.site/feed.xml&#34;&gt;@SunBK201&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>正则表达式高阶使用：负向零宽度断言</title>
      <link>http://blog.sunbk201.site/posts/regex-lookaround/</link>
      <pubDate>Fri, 31 Dec 2021 00:00:00 +0000</pubDate>
      
      <guid>http://blog.sunbk201.site/posts/regex-lookaround/</guid>
      <description>&lt;p&gt;当我在写 Surge 的规则配置文件时，我发现我需要通过正则表达式使用 policy-regex-filter 进行过滤，具体的需求是：排除包含指定字符串的节点，过滤获得没有包含指定字符串的节点。&lt;/p&gt;
&lt;p&gt;这是个难题，平时使用正则表达式主要是“匹配”的思想，这次要使用“否定排除”的思想。&lt;/p&gt;
&lt;p&gt;零宽度断言 (zero-width-assertions) 解决了这个问题。 我们这里讨论的是否定的断言。 零宽度断言所匹配到的内容并不会保存到结果中去。&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;^((?!hede).)*$
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;上面的正则表达式是用来匹配排除包含 &lt;code&gt;hede&lt;/code&gt; 的结果。&lt;/p&gt;
&lt;p&gt;一个字符串包含 n 个字符的 list，在每个字符的前后都包涵一个空的字符串，因此含有 n 个字符的 list 拥有 n+1 个空字符串。 我们来看下这个字符串 &lt;code&gt;&amp;quot;ABhedeCD&amp;quot;&lt;/code&gt; :&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;    ┌──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┐
S = │e1│ A │e2│ B │e3│ h │e4│ e │e5│ d │e6│ e │e7│ C │e8│ D │e9│
    └──┴───┴──┴───┴──┴───┴──┴───┴──┴───┴──┴───┴──┴───┴──┴───┴──┘
index    0      1      2      3      4      5      6      7
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;其中，e 们都是空字符串，表达式 &lt;code&gt;(?!hede)&lt;/code&gt;. 会检查每个的 e 的后面有没有 &lt;code&gt;“hede”&lt;/code&gt; 子字符串，如果没有，&lt;code&gt;.&lt;/code&gt; 会匹配任意一个字符（除了换行符），这种行为称为“零宽度断言”，因为他们没有消耗任何字符，仅仅只是在断言或证实某些东西。 因此，在上面的例子中，对于每个空字符串都会被验证其之后有无 &lt;code&gt;“hede”&lt;/code&gt;，之后再与 . 匹配。 表达式 &lt;code&gt;(?!hede)&lt;/code&gt;. 只会进行一次上面的验证，因此，我们将其成组重复多次：&lt;code&gt;((?!hede).)*&lt;/code&gt;。 最后，我们锚定首尾：&lt;code&gt;^((?!hede).)*$&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;quot;ABhedeCD&amp;quot;&lt;/code&gt; 最终会在 &lt;code&gt;e3&lt;/code&gt; 处失败，因为 &lt;code&gt;e3&lt;/code&gt; 之后存在字符串 &lt;code&gt;“hede”&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;我们再将其拓展一下，可以匹配排除包含多个指定字符串的节点：&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;^((?!(本站|流量|过期|下架|用户群|官网|精简)).)*$
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;准确来说，上面使用的属于「正向否定查找」，常规用法是：&lt;code&gt;x(?=y)&lt;/code&gt;，含义是仅仅当 &lt;code&gt;x&lt;/code&gt; 后面不跟着 &lt;code&gt;y&lt;/code&gt; 时匹配 &lt;code&gt;x&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;例如，仅仅当这个数字后面没有跟小数点的时候，&lt;code&gt;\d+(?!\.)&lt;/code&gt; 匹配一个数字。正则表达式 &lt;code&gt;\d+(?!\.)&lt;/code&gt; 匹配 &lt;code&gt;141&lt;/code&gt; 而不是 &lt;code&gt;3.141&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;但 &lt;code&gt;(?!hede).&lt;/code&gt; 的这种用法属实少见，其思想是将其匹配字符之前的部分看作是一个字符串（空字符串）（&lt;code&gt;[空字符串](?!hede).&lt;/code&gt;），而检查是这个空字符串的后面是否匹配 &lt;code&gt;(?!hede)&lt;/code&gt;。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>多线程简介：走进并发世界</title>
      <link>http://blog.sunbk201.site/posts/gentle-introduction-multithreading/</link>
      <pubDate>Thu, 26 Aug 2021 00:00:00 +0000</pubDate>
      
      <guid>http://blog.sunbk201.site/posts/gentle-introduction-multithreading/</guid>
      <description>&lt;p&gt;现代计算机有能力在同一时间进行多种操作。在硬件进步和愈发智能的操作系统的支持下，这一特性能够使我们的程序运行得更快，无论是在执行速度还是响应速度方面。&lt;/p&gt;
&lt;p&gt;利用多线程的优势编写软件是非常有趣的，但是也非常困难：它需要你了解你的计算机的内部。多线程是操作系统提供的一种充满魔力的工具，在这一篇我们将尝试掀开多线程的面纱，让我们开始吧！&lt;/p&gt;
&lt;h1 id=&#34;进程和线程命名&#34;&gt;进程和线程：命名&lt;/h1&gt;
&lt;p&gt;现代操作系统可以同时运行多个程序。这就是为什么你可以在你的浏览器（一个程序）中阅读这篇文章，同时在你的媒体播放器（另一个程序）中听音乐。每个程序被称为一个正在执行的进程。操作系统可以利用许多软件技巧，使一个进程与其他进程一起运行，或者充分利用底层硬件的优势。无论哪种方式，最后的结果都是你感觉到所有程序都在同时运行。&lt;/p&gt;
&lt;p&gt;在操作系统中运行进程并不是同时执行几个操作的唯一方法。每个进程能够在其内部同时运行子任务，称为线程。你可以把线程看作是进程本身的一个片段。每个进程在启动时至少会触发一个线程，这被称为主线程。然后，根据程序或程序员的需要，可以启动或终止其他线程。多线程是指在一个进程中运行多个线程。&lt;/p&gt;
&lt;p&gt;例如，你的媒体播放器很可能运行多个线程：一个用于渲染界面–这通常是主线程，另一个用于播放音乐，等等。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://sunbk201.oss-cn-beijing.aliyuncs.com/img/20210826172202.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;h1 id=&#34;进程与线程的不同&#34;&gt;进程与线程的不同&lt;/h1&gt;
&lt;p&gt;每个进程都有操作系统分配的自己的一大块内存。默认情况下，该内存不能与其他进程共享：你的浏览器不能访问分配给媒体播放器的内存，反之亦然。如果你运行同一个进程的两个实例，也就是说，如果你启动浏览器两次，也会发生同样的事情。操作系统将每个实例视为一个新的进程，分配给它自己独立的内存部分。因此，默认情况下，两个或更多的进程没有办法共享数据，除非他们执行高级技巧 – &lt;a href=&#34;https://en.wikipedia.org/wiki/Inter-process_communication&#34;&gt;进程间通信（IPC）&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;与进程不同，线程共享操作系统分配给其父进程的同一块内存：媒体播放器主界面的数据可以很容易地被音频引擎访问，反之亦然。因此，两个线程之间的对话更容易。除此之外，线程通常比进程更轻量：它们占用资源更少，创建速度更快，这就是为什么它们也被称为轻量级进程。&lt;/p&gt;
&lt;p&gt;线程是一种使你的程序同时执行多个操作的方便方法。如果没有线程，你将不得不为每个任务编写一个程序，将它们作为进程运行，并通过操作系统使它们同步。这将更加困难（ IPC 很麻烦）和缓慢（进程比线程更重）。&lt;/p&gt;
&lt;h1 id=&#34;绿色线程纤维&#34;&gt;绿色线程：纤维&lt;/h1&gt;
&lt;p&gt;到目前为止，所提到的线程是操作系统的事情：一个想要启动一个新线程的进程必须与操作系统对话。不过，并不是每一个平台都原生支持线程。绿色线程，也被称为纤维，是一种模拟，使多线程程序能够在不原生支持线程的环境中工作。例如，在底层操作系统没有原生线程支持的情况下，虚拟机可以实现绿色线程。&lt;/p&gt;
&lt;p&gt;绿色线程的创建和管理速度较快，因为它们完全绕过了操作系统，但也有缺点。关于这点我们之后再讲。&lt;/p&gt;
&lt;p&gt;“绿色线程”这个名字是指 Sun Microsystem 的 Green Team，他们在 90 年代设计了最初的 Java 线程库。如今，Java 不再使用绿色线程：他们早在 2000 年就转向了本地线程。其他一些编程语言 – Go、Haskell 或 Rust 等等–都实现了绿色线程的类似产物，而不是本地线程。&lt;/p&gt;
&lt;h1 id=&#34;线程的用途&#34;&gt;线程的用途&lt;/h1&gt;
&lt;p&gt;为什么一个进程要采用多线程？正如我之前提到的，并行做事会大大加快事情的进展。假设你要在你的电影编辑器中渲染一部电影。编辑器可以很聪明地将渲染操作分散到多个线程中，每个线程处理电影的一个部分。因此，如果用一个线程处理，比如说，需要一个小时，用两个线程则需要 30 分钟；用四个线程则需要 15 分钟，以此类推。&lt;/p&gt;
&lt;p&gt;真的就这么简单吗？ 有三个要点需要考虑：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;并非每个程序都需要多线程。因为如果你的应用程序执行顺序操作或经常等待用户进行 IO，多线程可能不是那么有益；&lt;/li&gt;
&lt;li&gt;你不能把更多的线程扔给一个应用程序来使它运行得更快：每个子任务都必须经过深思熟虑和精心设计，以执行并行操作。&lt;/li&gt;
&lt;li&gt;并不能 100% 保证线程会真正并行地执行它们的操作，也就是在同一时间会发生什么：这很大程度上取决于底层硬件。 最后一个是至关重要的：如果你的电脑不支持同时进行多项操作，操作系统就必须伪造这些操作。我们将在一分钟内看到如何做。现在，让我们把并发看作是有任务同时运行的感觉，而真正的并行则是任务在同一时间运行。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&#34;https://sunbk201.oss-cn-beijing.aliyuncs.com/img/20210826182809.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;h1 id=&#34;是什么让并发和并行成为可能&#34;&gt;是什么让并发和并行成为可能&lt;/h1&gt;
&lt;p&gt;计算机中的中央处理单元（CPU）负责运行程序的工作。它由几个部分组成，其中最主要的是所谓的核心：这是实际进行计算的地方。一个核心一次只能运行一个操作。&lt;/p&gt;
&lt;p&gt;这当然是一个主要的缺点。由于这个原因，操作系统已经开发了先进的技术，使用户能够同时运行多个进程（或线程），特别是在图形环境中，甚至在单核机器上。最重要的一项技术叫做抢占式多任务，抢占式多任务是指中断一个任务，切换到另一个任务，然后在稍后的时间恢复第一个任务的能力。&lt;/p&gt;
&lt;p&gt;因此，如果你的 CPU 只有一个核心，操作系统的部分工作就是将这个单一核心的计算能力分散到多个进程或线程中，这些线程在一个循环中一个接一个地执行。这种操作给你一种错觉，即有一个以上的程序在并行运行，或者一个程序同时做多件事情（如果是多线程）。并发性得到了满足，但真正的并行性–同时运行进程的能力–仍然缺失。&lt;/p&gt;
&lt;p&gt;今天，现代的CPU通常有一个以上的内核，其中每个内核一次执行一个独立的操作。这意味着，有了两个或更多的核心，真正的并行是可能的。例如，我的 Intel Core i7 有 8 个核心：它可以同时运行 8 个不同的进程或线程。&lt;/p&gt;
&lt;h1 id=&#34;单核上的运行多线程应用有意义吗&#34;&gt;单核上的运行多线程应用：有意义吗？&lt;/h1&gt;
&lt;p&gt;在单核机器上，真正的并行化是不可能实现的。尽管如此，如果你的应用程序能够从中受益，那么编写一个多线程程序仍然是有意义的。当一个进程采用多个线程时，即使其中一个线程执行缓慢或阻塞的任务，抢占式多任务也能保持应用程序的运行。&lt;/p&gt;
&lt;p&gt;例如，你正在开发一个桌面应用程序，从一个非常慢的磁盘上读取一些数据。如果你编写的程序只有一个线程，那么整个应用程序就会冻结，直到磁盘操作完成：分配给唯一线程的 CPU 功率在等待磁盘唤醒时被浪费了。当然，除了这个进程之外，操作系统还在运行许多其他进程，但你的具体应用程序不会有任何进展。&lt;/p&gt;
&lt;p&gt;让我们以多线程的方式来重新思考你的应用程序。线程 A 负责磁盘访问，而线程 B 负责主界面。如果线程 A 因为设备速度慢而被卡住等待，线程 B 仍然可以运行主界面，保持你的程序的响应速度。这是可能的，因为有两个线程，操作系统可以在它们之间切换 CPU 资源，而不会卡在较慢的那一个。&lt;/p&gt;
&lt;h1 id=&#34;越多线程越多问题&#34;&gt;越多线程，越多问题&lt;/h1&gt;
&lt;p&gt;正如我们所知，线程共享其父进程的同一块内存。这使得两个或多个线程在同一个应用程序中交换数据变得非常容易。例如：一个电影编辑器可能持有很大一部分共享内存，其中包含视频时间线。这样的共享内存被几个工作线程读取，这些线程被指定用于将电影渲染到文件中。他们都只需要一个到该内存区域的句柄（例如一个指针），以便从其中读取并将渲染的帧输出到磁盘。&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;h1 id=&#34;线程安全的概念&#34;&gt;线程安全的概念&lt;/h1&gt;
&lt;p&gt;如果一段代码能够正常工作，即没有数据竞争或竞态条件，即使许多线程同时执行它，也可以说它是线程安全的。你可能已经注意到，一些编程库声明自己是线程安全的：如果你正在编写一个多线程程序，你要确保任何其他的第三方函数可以在不同的线程中使用而不会引发并发问题。&lt;/p&gt;
&lt;h1 id=&#34;数据竞争的根源&#34;&gt;数据竞争的根源&lt;/h1&gt;
&lt;p&gt;我们知道，一个 CPU 核心一次只能执行一条机器指令。这样的指令被说成是原子性的，因为它是不可分割的：它不能被分解成更小的操作。希腊语中的「atom」（ἄτομος；atomos）的意思是不可切割。&lt;/p&gt;
&lt;p&gt;不可分割的属性使得原子操作在本质上是线程安全的。当一个线程对共享数据执行原子写操作时，没有其他线程可以读取半成品的修改。相反，当一个线程对共享数据进行原子读取时，它读取的是整个数值，因为它出现在一个时间点上。线程没有办法从原子操作中溜走，因此不可能发生数据竞争。&lt;/p&gt;
&lt;p&gt;坏消息是，绝大多数的操作都是非原子性的。即使是像 &lt;code&gt;x = 1&lt;/code&gt; 这样的琐碎赋值，在某些硬件上也可能是由多个原子机器指令组成的，使得赋值本身作为一个整体是非原子的。因此，如果一个线程读取 &lt;code&gt;x&lt;/code&gt;，而另一个线程执行赋值，就会触发数据竞争。&lt;/p&gt;
&lt;h1 id=&#34;竞态条件&#34;&gt;竞态条件&lt;/h1&gt;
&lt;p&gt;抢占式多任务让操作系统完全控制线程管理：它可以根据高级调度算法启动、停止和暂停线程。作为一个程序员，你无法控制执行的时间或顺序。事实上，像这样的简单代码是无法保证的：&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;writer_thread.start()
reader_thread.start()
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;将以这个特定的顺序启动两个线程。多次运行这个程序，你会注意到它在每次运行中的表现是不同的：有时写程序的线程先启动，有时则是读程序的。如果你的程序需要写程序总是在读程序之前运行，你肯定会遇到一个竞态条件。&lt;/p&gt;
&lt;p&gt;这种行为被称为非决定性的：每次的结果都会改变，你无法预测它。调试受竞态条件影响的程序是非常烦人的，因为你不可能总是以可控的方式重现这个问题。&lt;/p&gt;
&lt;h1 id=&#34;教会线程们如何相处并发控制&#34;&gt;教会线程们如何相处：并发控制&lt;/h1&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;不可变的数据：共享数据被标记为不可变的，没有什么可以改变它：线程只允许从它那里读取，消除了根本原因。我们知道线程可以安全地从同一内存位置读取，只要他们不修改它。这就是&lt;a href=&#34;https://en.wikipedia.org/wiki/Functional_programming&#34;&gt;函数式编程&lt;/a&gt;背后的主要理念。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is a version from &lt;a href=&#34;https://www.internalpointers.com/&#34;&gt;Internal Pointers&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>1500 字节是如何成为互联网的 MTU 的？</title>
      <link>http://blog.sunbk201.site/posts/why-is-ethernet-mtu-1500/</link>
      <pubDate>Thu, 15 Jul 2021 00:00:00 +0000</pubDate>
      
      <guid>http://blog.sunbk201.site/posts/why-is-ethernet-mtu-1500/</guid>
      <description>&lt;p&gt;以太网无处不在，数以万计的硬件供应商都在讨论和实现它。然而，几乎每个以太网链路都都有一个共同的数字，那就是 MTU：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ip l
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1: lo: &amp;lt;LOOPBACK,UP,LOWER_UP&amp;gt; mtu &lt;span style=&#34;color:#ae81ff&#34;&gt;65536&lt;/span&gt; state UNKNOWN
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2: enp5s0: &amp;lt;BROADCAST,MULTICAST,UP,LOWER_UP&amp;gt; mtu &lt;span style=&#34;color:#ae81ff&#34;&gt;1500&lt;/span&gt; state UP 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src=&#34;https://sunbk201.oss-cn-beijing.aliyuncs.com/img/20210715135605.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;MTU（最大传输单元）规定了一个数据包可以有多大。一般来说，当你在自己的局域网上与其他设备通信时，MTU 大约为 1500 字节，互联网也几乎普遍采用 1500 字节。然而，这并不意味着这些链路层技术不能传输更大的数据包。&lt;/p&gt;
&lt;p&gt;例如，802.11（WiFi）的 MTU 为 2304 字节，或者如果你的网络使用 &lt;a href=&#34;https://en.wikipedia.org/wiki/Fiber_Distributed_Data_Interface&#34;&gt;FDDI&lt;/a&gt;，那么你的 MTU 约为 4352 字节。以太网本身有一个 “巨型帧 “的概念，MTU 可以设置为 9000 字节（在支持的网卡、交换机和路由器上）。&lt;/p&gt;
&lt;p&gt;然而，这些设定在互联网上几乎无关大局。由于互联网的骨干网现在大多是由以太网链路组成的，因此事实上数据包的最大尺寸现在被非正式地设定为 1500 字节，以避免数据包在链路上被分片。&lt;/p&gt;
&lt;p&gt;从表面上看，1500 是一个奇怪的数字，我们通常期望计算中的许多常数都是基于数学常量的，比如 2 的幂。&lt;/p&gt;
&lt;p&gt;那么，1500 是怎么来的，为什么我们还在使用它？&lt;/p&gt;
&lt;h1 id=&#34;神奇的数字&#34;&gt;神奇的数字&lt;/h1&gt;
&lt;p&gt;以太网的第一次重大突破是以 10BASE-2（廉价网）和 10BASE-5（稠密网）的形式出现的，这些数字大致表明一个网段可以跨越多少百米。&lt;/p&gt;
&lt;p&gt;由于当时有许多竞争性协议，而且存在硬件限制，以太网原作者在一封电子邮件中指出，数据包缓冲区的内存要求在神奇的 1500 数字上有一些作用。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;回过头来看，一个较长的最大值可能会更好，但如果它在早期增加了网卡的成本，可能会阻止以太网的广泛接受。&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;然而，这并不是故事的全部。1980年发表的 &lt;a href=&#34;https://blog.benjojo.co.uk/asset/4Up5QvCjAa&#34;&gt;Ethernet: Distributed Packet Switching for Local Computer Networks&lt;/a&gt; 一文是对网络上较大数据包的效率成本分析的早期说明。这在当时对以太网特别重要，因为以太网网络将在所有系统之间共享相同的同轴电缆，或者以太网集线器，一次只允许一个数据包在以太网段的所有成员之间传输。&lt;/p&gt;
&lt;p&gt;我们必须选择一个数字，使得数据在这些共享（有时是繁忙的）网段上的传输延迟不会太高，但这也意味着数据包头的开销不会太大。(见上面链接的论文第 15-16 页的一些表格)&lt;/p&gt;
&lt;p&gt;看来，当时的工程师们最多只挑选了 1500 字节，或大约 12000 比特作为最佳&amp;quot;安全&amp;quot;值。&lt;/p&gt;
&lt;p&gt;从那时起，各种其他的传输系统陆续出现，但其中最低的MTU值仍然是以太网的 1500 字节。大于网络上的最低 MTU 将导致 IP 分片，或者需要进行路径 MTU 检测。这两种情况都有各自的问题。即使是大型操作系统供应商有时也会将默认 &lt;a href=&#34;https://archive.nanog.org/mailinglist/mailarchives/old_archive/1998-02/msg00064.html&#34;&gt;MTU&lt;/a&gt; 降到更低。&lt;/p&gt;
&lt;h1 id=&#34;效率问题&#34;&gt;效率问题&lt;/h1&gt;
&lt;p&gt;所以现在我们知道，互联网的 MTU 上限为1500，主要是由于传统的延迟数字和硬件限制，这对互联网的效率有多大影响？&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://sunbk201.oss-cn-beijing.aliyuncs.com/img/20210715141919.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;如果我们看一下一个主要的互联网流量交换点（AMS-IX）的数据，我们会发现，至少有20%经过交换点的数据包是最大尺寸的。我们还可以看到局域网的总流量：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://sunbk201.oss-cn-beijing.aliyuncs.com/img/20210715142133.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;如果你把这两张图结合起来，你得到的结果大致上是这样的。这是对每个数据包大小区间的流量的估计。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://sunbk201.oss-cn-beijing.aliyuncs.com/img/20210715142242.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;或者，如果我们只看所有这些以太网序言和报头引起的流量，我们会得到同样的图表，但有不同的尺度。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://sunbk201.oss-cn-beijing.aliyuncs.com/img/20210715142400.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;这表明大量的带宽被花在最大的数据包类的包头上。由于峰值流量显示最大的数据包桶的开销约为 246GBit/s，我们可以假设，如果我们在有条件的情况下都采用了巨型帧，那么这个开销将只有约 41GBit/s。&lt;/p&gt;
&lt;p&gt;但我认为在这一点上，宽广的互联网上已经有人这样做过。虽然一些&lt;a href=&#34;https://web.archive.org/web/20200108213905/https://he.net/ip_transit.html&#34;&gt;互联网通信公司以 9000MTU 运营&lt;/a&gt;，但绝大多数并非如此，而且一次又一次地&lt;a href=&#34;https://en.wikipedia.org/wiki/IPv6_deployment&#34;&gt;证明&lt;/a&gt;，共同改变互联网的想法是非常困难的。&lt;/p&gt;
&lt;p&gt;This is a version from &lt;a href=&#34;https://blog.benjojo.co.uk/&#34;&gt;benjojo&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>关于 SSD，每一位开发者都应该知道的一些知识</title>
      <link>http://blog.sunbk201.site/posts/ssd-should-know/</link>
      <pubDate>Wed, 23 Jun 2021 00:00:00 +0000</pubDate>
      
      <guid>http://blog.sunbk201.site/posts/ssd-should-know/</guid>
      <description>&lt;p&gt;基于闪存的 Solid-State Drives (SSDs) 固态硬盘 已经在很大程度上取代了磁盘，成为标准的存储介质。从程序员的角度来看，固态硬盘和磁盘看起来非常相似：两者都是持久性的，通过文件系统和系统调用实现基于页面（如 4KB）的访问，并且具有大容量。&lt;/p&gt;
&lt;p&gt;然而，也有一些重要的区别，如果想达到最佳的 SSD 性能，这些区别就变得很重要。周所周知，SSD 更加复杂，如果只是简单地认为它们是快速的磁盘，那么它们的性能表现会显得相当难以理解。这篇文章的目的是让大家了解为什么 SSD 会有这样的性能表现，这有助于构建能够充分利用它们的软件。请注意，我讨论的是 NAND 闪存，而不是英特尔 Optane 内存，后者具有不同的特性）。&lt;/p&gt;
&lt;h1 id=&#34;驱动器drives不是磁盘disks&#34;&gt;驱动器（Drives）不是磁盘（Disks）&lt;/h1&gt;
&lt;p&gt;固态硬盘经常被称为磁盘，但这是一种误导，因为它们在半导体上存储数据，而不是在机械磁盘上。要从一个随机块中读取或写入，磁盘必须机械地将其磁头移动到正确的位置，这需要 10ms 的时间。相比之下，从固态硬盘中进行随机读取，需要大约 100us–快 100 倍。这种低读取延迟就是为什么系统从固态硬盘启动要比从磁盘启动快得多的原因。&lt;/p&gt;
&lt;h1 id=&#34;并行性&#34;&gt;并行性&lt;/h1&gt;
&lt;p&gt;磁盘和固态硬盘的另一个重要区别是，磁盘有一个磁头，只在顺序访问时表现良好。相比之下，固态硬盘由几十个甚至几百个闪存芯片（“并行单元”）组成，可以同时访问。&lt;/p&gt;
&lt;p&gt;固态硬盘透明地将较大的文件以页为单位在闪存芯片上存储，而硬件预取器则确保顺序扫描能够利用所有可用的闪存芯片。然而，在闪存层面上，顺序读取和随机读取之间没有太大的区别。事实上，对于大多数固态硬盘来说，随机读取页面也有可能实现利用几乎全部的带宽。要做到这一点，必须同时安排数百个随机 IO 请求，以保持所有闪存芯片的工作。这可以通过启动大量线程或使用异步 IO 接口（如 libaio 或 io_uring）来实现。&lt;/p&gt;
&lt;h1 id=&#34;写入&#34;&gt;写入&lt;/h1&gt;
&lt;p&gt;写入时，事情变得更加有趣，例如，如果我们测试下写入延迟，我们可以测量到低至10us的结果–比读快 10 倍。然而，延迟看起来如此之低，是因为固态硬盘在易失性 RAM 上进行了写入缓存。NAND 闪存的实际写入延迟约为 1ms - 比读取慢 10 倍。在消费级固态硬盘上，这可以通过在写完后发出 sync/flush 来衡量，以确保数据在闪存上的持久性。在大多数数据中心/服务器固态硬盘上，写延迟无法直接测量：sync/flush 将立即完成，因为即使在断电的情况下备用电池依旧可以保证写缓存的持久性。&lt;/p&gt;
&lt;p&gt;为了在相对较高的写入延迟下实现高的写入带宽，写使用了与读相同的技巧：他们同时访问多个闪存芯片。因为写缓存可以异步写入页面，所以甚至没有必要同时安排那么多的写入来获得良好的写入性能。然而，写入的延迟不可能总是被完全掩盖：例如，由于写入占用闪存芯片的时间是读的10倍，写入会导致对同一闪存芯片的读取有明显的尾部延迟。&lt;/p&gt;
&lt;h1 id=&#34;out-of-place-写入&#34;&gt;Out-Of-Place 写入&lt;/h1&gt;
&lt;p&gt;我们对 SSD 的理解忽略了一个重要的事实：NAND 闪存的页面不能被覆盖。页的写入只能在事先已被擦除的块内按顺序进行。这些擦除块的大小为多 MB，由数百个页面组成。在一个新的固态硬盘上，所有的块都已被擦除，人们可以直接开始写入新的数据。&lt;/p&gt;
&lt;p&gt;然而，更新页面就不那么容易了。如果只是为了就地覆盖一个页面而擦除整个区块，那就太浪费了。因此，固态硬盘通过将新版本的页面写到一个新的位置来执行页面更新。这意味着逻辑和物理页面地址是解耦的。存储在 SSD 上的映射表将逻辑（软件）地址转换为物理（闪存）位置。这个组件也被称为 Flash Translation Layer（FTL）。&lt;/p&gt;
&lt;p&gt;例如，让我们假设我们有一个 SSD，有 3 个擦除块，每个有 4 个页面。对 P1, P2, P0, P3, P5, P1 页的一连串写入可能会导致以下物理 SSD 状态：&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th style=&#34;text-align: center&#34;&gt;&lt;/th&gt;
          &lt;th style=&#34;text-align: center&#34;&gt;&lt;/th&gt;
          &lt;th style=&#34;text-align: center&#34;&gt;&lt;/th&gt;
          &lt;th style=&#34;text-align: center&#34;&gt;&lt;/th&gt;
          &lt;th&gt;&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;Block 0&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;P1 (old)&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;P2&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;P0&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;P3&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;Block 1&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;P5&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;P1&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;→&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;Block 2&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;这时，我们已经没有空闲的擦除块了（尽管从逻辑上来说，应该还有空间）。在写入另一个页面之前，SSD 首先要擦除一个块。在这个例子中，对于垃圾回收器来说，最好是擦除第 0 块，因为只有其中的一个页面还在使用。在擦除第0块后，我们为 3 个写页腾出了空间：&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th style=&#34;text-align: center&#34;&gt;&lt;/th&gt;
          &lt;th style=&#34;text-align: center&#34;&gt;&lt;/th&gt;
          &lt;th style=&#34;text-align: center&#34;&gt;&lt;/th&gt;
          &lt;th style=&#34;text-align: center&#34;&gt;&lt;/th&gt;
          &lt;th&gt;&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;Block 0&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;P1 (old)&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;P2 (old)&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;P0&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;P3 (old)&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;Block 1&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;P5&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;P1 (old)&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;P3&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;P4&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;Block 2&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;P7&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;P1&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;P6&lt;/td&gt;
          &lt;td style=&#34;text-align: center&#34;&gt;P2&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;h1 id=&#34;写入放大与超额配置&#34;&gt;写入放大与超额配置&lt;/h1&gt;
&lt;p&gt;为了垃圾回收 block 0，我们不得不物理地移动 P0 页，尽管在逻辑上该页没有发生什么。换句话说，对于闪存 SSD 来说，物理（闪存）写入的数量通常高于逻辑（软件）写入的数量。两者之间的比例被称为写入放大（WA）。在我们的例子中，为了给 0 区块的 3 个新页面腾出空间，我们不得不移动 1 个页面。因此，我们有 4 个物理写，3 个逻辑写，也就是说，写放大率为 1.33。&lt;/p&gt;
&lt;p&gt;高写入放大率会降低性能，并减少闪存的使用寿命。写入放大率有多大，取决于访问模式和固态硬盘的满度。大的连续写入有低的写入放大率，而随机写入是最糟糕的情况。&lt;/p&gt;
&lt;p&gt;让我们假设我们的 SSD 被填充到 50%，我们进行随机写入。在稳定状态下，无论我们在哪里擦除一个区块，该区块的大约一半的页面仍然在使用，并且平均要被复制。因此，50% 的填充系数的写入放大率是 2。一般来说，填充系数 f 的最坏情况下的写入放大率是 1/(1-f)。&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&gt;&lt;/th&gt;
          &lt;th&gt;&lt;/th&gt;
          &lt;th&gt;&lt;/th&gt;
          &lt;th&gt;&lt;/th&gt;
          &lt;th&gt;&lt;/th&gt;
          &lt;th&gt;&lt;/th&gt;
          &lt;th&gt;&lt;/th&gt;
          &lt;th&gt;&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;f&lt;/td&gt;
          &lt;td&gt;0.1&lt;/td&gt;
          &lt;td&gt;0.2&lt;/td&gt;
          &lt;td&gt;0.3&lt;/td&gt;
          &lt;td&gt;0.4&lt;/td&gt;
          &lt;td&gt;0.5&lt;/td&gt;
          &lt;td&gt;0.6&lt;/td&gt;
          &lt;td&gt;0.7&lt;/td&gt;
          &lt;td&gt;0.8&lt;/td&gt;
          &lt;td&gt;0.9&lt;/td&gt;
          &lt;td&gt;0.95&lt;/td&gt;
          &lt;td&gt;0.99&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;WA&lt;/td&gt;
          &lt;td&gt;1.11&lt;/td&gt;
          &lt;td&gt;1.25&lt;/td&gt;
          &lt;td&gt;1.43&lt;/td&gt;
          &lt;td&gt;1.67&lt;/td&gt;
          &lt;td&gt;2.00&lt;/td&gt;
          &lt;td&gt;2.50&lt;/td&gt;
          &lt;td&gt;3.33&lt;/td&gt;
          &lt;td&gt;5&lt;/td&gt;
          &lt;td&gt;10&lt;/td&gt;
          &lt;td&gt;20&lt;/td&gt;
          &lt;td&gt;100&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;因为在填充系数接近 1 的情况下，写入放大率会变得不合理地高，大多数固态硬盘都有隐藏的备用容量。这种超额配置通常为总容量的 10-20%。当然，通过创建一个空的分区并永远不向其写入，也很容易增加更多的超额配置。&lt;/p&gt;
&lt;h1 id=&#34;总结&#34;&gt;总结&lt;/h1&gt;
&lt;p&gt;目前，固态硬盘已经变得相当便宜，而且它们具有非常高的性能。例如，三星 PM1733 服务器固态硬盘每 TB 价格约为 200 EUR ，并承诺提供接近 7GB/s 的读取和 4GB/s 的写入带宽。实际上，要实现如此高的性能，需要了解 SSD 的工作原理，这篇文章就是描述了闪存 SSD 最重要的底层机制。&lt;/p&gt;
&lt;p&gt;我尽量让这篇文章简短，要想了解更多，&lt;a href=&#34;https://codecapsule.com/2014/02/12/coding-for-ssds-part-1-introduction-and-table-of-contents/&#34;&gt;这篇教程&lt;/a&gt; 是一个不错的起点。最后，由于 SSD 已经变得如此之快，操作系统的 I/O 堆栈往往成为性能瓶颈。Linux 的实验结果可以在这篇的  &lt;a href=&#34;http://cidrdb.org/cidr2020/papers/p16-haas-cidr20.pdf&#34;&gt;CIDR 2020论文&lt;/a&gt; 中找到。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>关于 iOS SSID 格式字符串 BUG 的快速分析</title>
      <link>http://blog.sunbk201.site/posts/quick-analysis-wifid/</link>
      <pubDate>Mon, 21 Jun 2021 00:00:00 +0000</pubDate>
      
      <guid>http://blog.sunbk201.site/posts/quick-analysis-wifid/</guid>
      <description>&lt;p&gt;数天前，Twitter 上的&lt;a href=&#34;https://twitter.com/vm_call/status/1405937492642123782&#34;&gt;一条推文&lt;/a&gt;爆出了一个iOS Wi-Fi 的 BUG：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;@vm_call: After joining my personal WiFi with the SSID “%p%s%s%s%s%n”, my iPhone permanently disabled it’s WiFi functionality. Neither rebooting nor changing SSID fixes it :~)&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&#34;https://sunbk201.oss-cn-beijing.aliyuncs.com/img/20210621105740.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;看起来这是一个格式化字符串的错误，现在这种 BUG 已经很少见了。我用相同的 SSID 设置了一个热点，用我的测试设备尝试加入，wifid 很快就崩掉了。&lt;/p&gt;
&lt;p&gt;以下是崩溃日志 &lt;code&gt;wifid-2021-06-20-xxxxxx.ips&lt;/code&gt;:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Thread 2 name:  Dispatch queue: com.apple.wifid.managerQueue
Thread 2 Crashed:
0   libsystem_platform.dylib      	0x00000001ebcb9724 _platform_strlen + 4
1   CoreFoundation                	0x00000001a381d84c __CFStringAppendFormatCore + 8812
2   CoreFoundation                	0x00000001a381efa8 _CFStringCreateWithFormatAndArgumentsReturningMetadata + 160
3   WiFiPolicy                    	0x00000001d0895f8c -[WFLogger WFLog:message:] + 192
4   ???                           	0x000000010692c00c 0 + 4405248012
5   wifid                         	0x0000000100f58a74 0x100e40000 + 1149556
6   wifid                         	0x0000000100f58c74 0x100e40000 + 1150068
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;所以这真的是格式化字符串错误！&lt;/p&gt;
&lt;p&gt;反编译 dyld_shared_cache 中的这个函数 &lt;code&gt;-[WFLogger WFLog:message:]&lt;/code&gt;，有 2 处对 &lt;code&gt;CFStringCreateWithFormatAndArguments&lt;/code&gt; 的引用:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;v7 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;j__CFStringCreateWithCString_107&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;0LL&lt;/span&gt;, a4, &lt;span style=&#34;color:#ae81ff&#34;&gt;0x8000100u&lt;/span&gt;); &lt;span style=&#34;color:#75715e&#34;&gt;// the format string
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; ( v7 &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; (v7 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;j__CFStringCreateWithCString_107&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;0LL&lt;/span&gt;, a4, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;)) &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0LL&lt;/span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; ( self&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;_destination &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    v8 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;j__CFStringCreateWithFormatAndArguments_26&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;0LL&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0LL&lt;/span&gt;, v7, v21);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    v18[&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;] &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;__int64&lt;/span&gt;)v8;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; ( self&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;_destination &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (&lt;span style=&#34;color:#f92672&#34;&gt;!&lt;/span&gt;self&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;_wflRunningOnWatchClassDevice &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; self&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;_wflEnableDualLoggingOnWatchClassDevice) )
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;(_QWORD &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;)&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;v16.tm_sec &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0LL&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;(_QWORD &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;)&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;v16.tm_hour &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;v16;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;(_QWORD &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;)&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;v16.tm_mon &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0x2020000000LL&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;(_QWORD &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;)&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;v16.tm_wday &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0LL&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  v10 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;j__CFStringCreateWithFormatAndArguments_26&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;0LL&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0LL&lt;/span&gt;, v7, v21); &lt;span style=&#34;color:#75715e&#34;&gt;// &amp;lt;-- here
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;用 lldb debug 这个 issue 很麻烦了，因为这个 method 太常见了。因此，使用 frida frida-trace -U wifid -m &amp;lsquo;-[WFLogger WFLog:message:]&amp;rsquo;, 然后使用以下通知脚本：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;onEnter&lt;/span&gt;(log, args, state) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; msg &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; args[&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;].&lt;span style=&#34;color:#a6e22e&#34;&gt;readUtf8String&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;(&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;`&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;[WFLogger WFLog:&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;{args[&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;]} message:&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;{msg}]&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;`&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (msg.&lt;span style=&#34;color:#a6e22e&#34;&gt;indexOf&lt;/span&gt;(&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;p&lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;s&lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;s&lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;s&lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;s&lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;n&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; (let i &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;; i &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;; i&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;(args[i], JSON.&lt;span style=&#34;color:#a6e22e&#34;&gt;stringify&lt;/span&gt;(Process.&lt;span style=&#34;color:#a6e22e&#34;&gt;findRangeByAddress&lt;/span&gt;(args[i])));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;(&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;called from:&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;\&lt;/span&gt;n&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      Thread.&lt;span style=&#34;color:#a6e22e&#34;&gt;backtrace&lt;/span&gt;(this.context, Backtracer.ACCURATE)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      .&lt;span style=&#34;color:#a6e22e&#34;&gt;map&lt;/span&gt;(DebugSymbol.fromAddress).&lt;span style=&#34;color:#a6e22e&#34;&gt;join&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;\n&amp;#39;&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;\n&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这是在崩溃之前的日志：&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;17863 ms -[WFLogger WFLog:0x3 message:Dequeuing command type: “%@” pending commands: %ld]

17863 ms -[WFLogger WFLog:0x3 message:{ASSOC+} Attempting Apple80211AssociateAsync to %p%s%s%s%s%n]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;根据 backtrace，这就是根本原因：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;v27 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;sub_1000A25D4&lt;/span&gt;(v21);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;v28 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;objc_msgSend&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;OBJC_CLASS___NSString,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;stringWithFormat:&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;CFSTR&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Attempting Apple80211AssociateAsync to %@&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        v27);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;v29 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;objc_msgSend&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;OBJC_CLASS___NSString, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;stringWithFormat:&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;CFSTR&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{ %@+} %@&amp;#34;&lt;/span&gt;), &lt;span style=&#34;color:#a6e22e&#34;&gt;CFSTR&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ASSOC&amp;#34;&lt;/span&gt;), v28);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;v30 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;objc_autoreleasePoolPush&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;v31 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;)qword_100251888;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; ( qword_100251888 )
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    v32 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;objc_msgSend&lt;/span&gt;(v29, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;UTF8String&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;objc_msgSend&lt;/span&gt;(v31, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;WFLog:message:&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;3LL&lt;/span&gt;, v32);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;objc_autoreleasePoolPop&lt;/span&gt;(v30);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;它将 SSID concat 到一个格式字符串，并将其传递给 &lt;code&gt;WFLog:message:&lt;/code&gt; 方法，目的地是 3，所以是 &lt;code&gt;CFStringCreateWithFormatAndArguments&lt;/code&gt; 的第二个 xref 引发了拒绝服务。&lt;/p&gt;
&lt;p&gt;对于可利用性，目前还没有问题，其余的参数也不像是可以控制的。因此，我不认为这个 bug 是可利用的。毕竟，要触发这个 bug，你需要连接到该 WiFi，其中的 &lt;code&gt;SSID&lt;/code&gt; 对受害者是可见的。钓鱼 Wi-Fi 或许更有效。&lt;/p&gt;
&lt;p&gt;This is a version from &lt;a href=&#34;https://blog.chichou.me/&#34;&gt;Schou&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>main 通常是个函数，那么什么时候不是呢？</title>
      <link>http://blog.sunbk201.site/posts/when-is-main-not-a-function/</link>
      <pubDate>Fri, 18 Jun 2021 00:00:00 +0000</pubDate>
      
      <guid>http://blog.sunbk201.site/posts/when-is-main-not-a-function/</guid>
      <description>&lt;p&gt;这始于我的同伴，尽管他已经知道如何编程，但却被迫参加我大学的计算机科学入门课程。我们跟他开玩笑说，他需要做一个可以运行的程序，但是评分的老师不能搞明白它是如何运行的。所以要求就是制作一个满足作业要求的程序，同时又要混淆视听，让评分人认为它不应该能运行起来。考虑到这一点，我开始回想起之前见过的C语言技巧库，其中有一点特别突出。我将通过这个技巧完成这个特殊的程序，这个技巧的想法来自一篇博客 &lt;a href=&#34;http://mainisusuallyafunction.blogspot.com/&#34;&gt;main is usually a function&lt;/a&gt;，这让我想到什么时候 main 不是一个函数？&lt;/p&gt;
&lt;p&gt;（你可以&lt;code&gt;下载&lt;/code&gt;我在这里写的代码，注意我是在 64-bit Linux 进行编写的，因此你如果在其它平台运行，你或许需要进行调整。）&lt;/p&gt;
&lt;p&gt;我解决问题的过程通常和大多数程序员做的事情一样。第 1 步：在谷歌上搜索有关问题。第 2 步：点击第一页上每个看起来相关的链接。如果没有解决，尝试不同的查询，然后重复。值得庆幸的是，这个问题的&lt;a href=&#34;http://stackoverflow.com/a/2252429/745719&#34;&gt;答案&lt;/a&gt;出现在 Stackoverflow 首次搜索中。在 1984 年，一个奇怪的程序赢得了 IOCCC，其中 main 被声明为 &lt;code&gt;short main[] = {...}&lt;/code&gt;，不知何故，这个程序成功做了一些事情，并打印到屏幕上！这是一个很好的例子。不幸的是，它是为一个完全不同的架构和编译器编写的，所以我真的没有简单的方法来找出它做了什么，但从它只是一堆数字的事实来看，我可以推测，那里的数字只是一些短函数的编译二进制，链接器在寻找主函数时只是把它扔到它的位置。&lt;/p&gt;
&lt;p&gt;有了我们的假设，即程序的代码只是以数组形式表示的主函数的编译汇编，让我们看看是否可以通过制作一个小程序来复制这一现象，看看我们是否可以做到这一点。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;char&lt;/span&gt; main[] &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Hello world!&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ gcc -Wall main_char.c -o first
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;main_char.c:1:6: warning: ‘main’ is usually a &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;-Wmain&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  char main&lt;span style=&#34;color:#f92672&#34;&gt;[]&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Hello world!&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      ^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ./first
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Segmentation fault
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;好了，它成功了… 因此我们的下一个目标是它能真正打印一些东西到屏幕上。回想一下我有限的 ASM 经验，我记得有不同的 section 决定了不同东西的去处。与我们最相关的两个section是.text section 和 .datasection。.text 包含所有可执行的代码，它是只读的，而 .data 包含可读和可写的代码，但它是不可执行的。在我们的例子中，我们只能填入 main 函数的代码，所以任何被放在 .data section 的东西都是不可行的。我们需要找到一种方法，在 main 函数内获得字符串 “Hello world!” 并引用它。&lt;/p&gt;
&lt;p&gt;我开始研究如何用尽可能少的代码来打印东西。由于我知道目标系统将是64位Linux，我发现我可以调用系统的写入调用，它将会输出到屏幕上。现在回过头来看这段代码，我认为我不需要为此使用汇编，但同时，我真的很高兴我能够学到一些东西。开始写内联 GCC ASM 是最难的部分，但一旦我掌握了它，一切就开始变得容易了。&lt;/p&gt;
&lt;p&gt;不过，开始并不容易。事实证明，我通过谷歌能找到的大部分ASM知识都是以下内容：非常老旧，英特尔的语法，而且是 32 位系统。记住在我们的方案中，我们需要文件在 64 位系统上用 gcc 编译，不需要对编译器标志进行任何特殊的修改，所以这意味着没有特殊的编译标志，也不能包括任何自定义的链接步骤，我们要使用 GCC 内联 AT&amp;amp;T 语法。我的大部分时间都花在了寻找有关64位系统的现代汇编的信息上了！我想这是一个很好的例子。也许是我的 Google-fu 有所欠缺 :) 这一部分几乎都是试验和错误。我的目标只是用 gcc inline ASM 的 write syscall 向屏幕打印 “Hello world!&amp;quot;，为什么这么难呢？对于想学习如何做这个的人，我推荐以下网站： Linux syscall list, Intro to Inline ASM, Differences between Intel and AT&amp;amp;T Syntax.&lt;/p&gt;
&lt;p&gt;最终，我的 ASM 代码完成了，而且看起来它可以工作！记住，我的目标是制作一个 main，它是一个打印 Hello World 的 ASM 数组。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;__asm__&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// print Hello World
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;movl $1, %eax;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;/* 1 is the syscall number for write on 64-bit */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;movl $1, %ebx;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;/* 1 is stdout and is the first argument */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;movl $message, %esi;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;/* load the address of string into the second argument*/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;movl $13, %edx;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;/* third argument is the length of the string to print*/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;syscall;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// call exit (so it doesn&amp;#39;t try to run the string Hello World)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// maybe I could have just used ret instead?
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;movl $60,%eax;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;xorl %ebx,%ebx; &lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;syscall;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// Store the Hello World inside the main function
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;message: .ascii &lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;Hello World!&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\\&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;n&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    );
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ gcc -Wall asm_main.c -o second
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;asm_main.c:1:6: warning: &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; type of ‘main’ is not ‘int’ &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;-Wmain&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  void main&lt;span style=&#34;color:#f92672&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      ^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ./second
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Hello World!
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;YES! 它打印出来了! 现在让我们看看编译后的十六进制代码，它应该与我们写的 ASM 代码一一对应起来。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(gdb) disass main
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Dump of assembler code &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; function main:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;0x00000000004004ed&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;:&lt;/span&gt;     push   &lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;rbp             ; Compiler inserted
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;0x00000000004004ee&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;:&lt;/span&gt;     mov    &lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;rsp,&lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;rbp
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;0x00000000004004f1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;:&lt;/span&gt;     mov    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0x1&lt;/span&gt;,&lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;eax        ; It&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;s our code&lt;span style=&#34;color:#f92672&#34;&gt;!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;0x00000000004004f6&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;9&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;:&lt;/span&gt;     mov    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0x1&lt;/span&gt;,&lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;ebx
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;0x00000000004004fb&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;14&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;:&lt;/span&gt;    mov    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0x400510&lt;/span&gt;,&lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;esi
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;0x0000000000400500&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;19&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;:&lt;/span&gt;    mov    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0xd&lt;/span&gt;,&lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;edx
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;0x0000000000400505&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;24&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;:&lt;/span&gt;    syscall
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;0x0000000000400507&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;26&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;:&lt;/span&gt;    mov    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0x3c&lt;/span&gt;,&lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;eax
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;0x000000000040050c&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;31&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;:&lt;/span&gt;    xor    &lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;ebx,&lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;ebx
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;0x000000000040050e&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;33&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;:&lt;/span&gt;    syscall
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;0x0000000000400510&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;35&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;:&lt;/span&gt;    rex.W                   ; String hello world
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;0x0000000000400511&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;36&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;:&lt;/span&gt;    gs                      ; it&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;s garbled since
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;0x0000000000400512&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;37&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;:&lt;/span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;insb&lt;/span&gt;   (&lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;dx),&lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;es:(&lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;rdi) ; it&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;s not real ASM
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;0x0000000000400513&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;38&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;:&lt;/span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;insb&lt;/span&gt;   (&lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;dx),&lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;es:(&lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;rdi) ; so it couldn&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;t be
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;0x0000000000400514&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;39&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;:&lt;/span&gt;    outsl  &lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;ds:(&lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;rsi),(&lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;dx) ; disassembled
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;0x0000000000400515&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;40&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;:&lt;/span&gt;    and    &lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;dl,&lt;span style=&#34;color:#ae81ff&#34;&gt;0x6f&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;rdi)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;0x0000000000400518&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;43&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;:&lt;/span&gt;    jb     &lt;span style=&#34;color:#ae81ff&#34;&gt;0x400586&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;0x000000000040051a&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;45&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;:&lt;/span&gt;    and    &lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;ecx,&lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;fs:(&lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;rdx)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;0x000000000040051d&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;48&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;:&lt;/span&gt;    pop    &lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;rbp             ; Compiler&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;inserted
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;0x000000000040051e&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;49&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;:&lt;/span&gt;    retq
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;End of assembler dump.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这看起来是个有戏的 main，现在让我们去抓取它的十六进制内容，并将其作为字符串 dump 出去，看看是否能正常工作。我的方法是加载 gdb，像这样在 main 处打印 hex。上次我们拆解 main 的时候，看到它有 49 个字节长，所以可以用 dump 命令把十六进制保存到文件中。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# example of how to print the hex
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;(gdb) x&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;49&lt;/span&gt;xb main
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0x4004ed&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;main&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;:&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0x55&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0x48&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0x89&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0xe5&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0xb8&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0x01&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0x00&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0x00&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0x4004f5&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;main&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;8&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;:&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;0x00&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0xbb&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0x01&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0x00&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0x00&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0x00&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0xbe&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0x10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0x4004fd&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;main&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;16&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;:&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0x05&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0x40&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0x00&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0xba&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0x0d&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0x00&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0x00&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0x00&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0x400505&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;main&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;24&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;:&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0x0f&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0x05&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0xb8&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0x3c&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0x00&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0x00&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0x00&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0x31&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0x40050d&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;main&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;32&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;:&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0xdb&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0x0f&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0x05&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0x48&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0x65&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0x6c&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0x6c&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0x6f&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0x400515&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;main&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;40&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;:&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0x20&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0x57&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0x6f&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0x72&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0x6c&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0x64&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0x21&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0x0a&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0x40051d&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;main&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;48&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;:&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0x5d&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# example of how to save it to a file
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;(gdb) dump memory hex.out main main&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;49&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;现在我们有了 hex dump，我们可以用我知道的最简单的方法将它们全部转换成整数，那就是使用 python。在Python 2.6 和 2.7中，你可以用下面的方法将其转换为方便我们使用的 int 数组。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-py&#34; data-lang=&#34;py&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; array
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; hex_string &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;554889E5B801000000BB01000000BE10054000BA0D0000000F05B83C00000031DB0F0548656C6C6F20576F726C64210A5D&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;decode(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;hex&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; array&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;array(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;B&amp;#39;&lt;/span&gt;, hex_string)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;array(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;B&amp;#39;&lt;/span&gt;, [&lt;span style=&#34;color:#ae81ff&#34;&gt;85&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;72&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;137&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;229&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;184&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;187&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;190&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;16&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;64&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;186&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;13&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;15&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;184&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;60&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;49&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;219&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;15&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;72&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;101&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;108&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;108&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;111&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;32&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;87&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;111&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;114&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;108&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;33&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;93&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我想如果我的 bash foo 和 unix 知识更丰富的话，我可以找到一个更简单的方法来做这件事，但在谷歌上搜索 “编译后的函数的十六进制转储 “这样的东西，会得到几个关于如何用各种语言打印十六进制的问题。不管怎么说，我们现在有了一个逗号分隔的函数数组，所以让我们把它放到一个新的文件中。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;char&lt;/span&gt; main[] &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;85&lt;/span&gt;,                 &lt;span style=&#34;color:#75715e&#34;&gt;// push   %rbp
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;72&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;137&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;229&lt;/span&gt;,       &lt;span style=&#34;color:#75715e&#34;&gt;// mov    %rsp,%rbp
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;184&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;,    &lt;span style=&#34;color:#75715e&#34;&gt;// mov    $0x1,%eax
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;187&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;,    &lt;span style=&#34;color:#75715e&#34;&gt;// mov    $0x1,%ebx
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;190&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;16&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;64&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;,  &lt;span style=&#34;color:#75715e&#34;&gt;// mov    $0x400510,%esi
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;186&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;13&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;,   &lt;span style=&#34;color:#75715e&#34;&gt;// mov    $0xd,%edx
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;15&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;,              &lt;span style=&#34;color:#75715e&#34;&gt;// syscall
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;184&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;60&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;,   &lt;span style=&#34;color:#75715e&#34;&gt;// mov    $0x3c,%eax
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;49&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;219&lt;/span&gt;,            &lt;span style=&#34;color:#75715e&#34;&gt;// xor    %ebx,%ebx
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;15&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;,              &lt;span style=&#34;color:#75715e&#34;&gt;// syscall
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// Hello world!\n
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;72&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;101&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;108&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;108&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;111&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;32&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;87&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;111&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;114&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;108&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;33&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;,             &lt;span style=&#34;color:#75715e&#34;&gt;// pop    %rbp
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;93&lt;/span&gt;                  &lt;span style=&#34;color:#75715e&#34;&gt;// retq
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ gcc -Wall compiled_array_main.c -o third
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;compiled_array_main.c:1:6: warning: ‘main’ is usually a &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;-Wmain&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  char main&lt;span style=&#34;color:#f92672&#34;&gt;[]&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      ^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ./third
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Segmentation fault
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Segfault！我做错了什么？是时候再次启动 gdb，看看错误是什么了。由于 main 不再是一个函数，我们不能简单地使用 break main 来在那里设置断点。相反，我们可以使用 break _start 在调用 libc runtime startup 的方法上获得一个断点（该函数调用 main），我们可以看到我们传递给 __libc_start_main 的地址。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt; gdb .&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;third&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(gdb) &lt;span style=&#34;color:#66d9ef&#34;&gt;break&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;_start&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(gdb) &lt;span style=&#34;color:#a6e22e&#34;&gt;run&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(gdb) layout &lt;span style=&#34;color:#66d9ef&#34;&gt;asm&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; B&lt;span style=&#34;color:#f92672&#34;&gt;+&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;│&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0x400400&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;_start&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;                       xor    &lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;ebp,&lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;ebp                                                                       &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;│&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;│&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0x400402&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;_start&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;                     mov    &lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;rdx,&lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;r9                                                                        &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;│&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;│&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0x400405&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;_start&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;                     pop    &lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;rsi                                                                            &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;│&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;│&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0x400406&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;_start&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;6&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;                     mov    &lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;rsp,&lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;rdx                                                                       &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;│&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;│&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0x400409&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;_start&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;9&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;                     and    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0xfffffffffffffff0&lt;/span&gt;,&lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;rsp                                                        &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;│&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;│&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0x40040d&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;_start&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;13&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;                    push   &lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;rax                                                                            &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;│&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;│&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0x40040e&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;_start&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;14&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;                    push   &lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;rsp                                                                            &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;│&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;│&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0x40040f&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;_start&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;15&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;                    mov    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0x400560&lt;/span&gt;,&lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;r8                                                                   &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;│&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;│&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0x400416&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;_start&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;22&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;                    mov    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0x4004f0&lt;/span&gt;,&lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;rcx                                                                  &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;│&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;│&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0x40041d&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;_start&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;29&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;                    mov    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0x601060&lt;/span&gt;,&lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;rdi                                                                  &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;│&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;│&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0x400424&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;_start&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;36&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;                    callq  &lt;span style=&#34;color:#ae81ff&#34;&gt;0x4003e0&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;__libc_start_main&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;@&lt;/span&gt;plt&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;                                                &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;│&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;通过测试，我发现在 %rdi 上 push 的值是 main 的位置，但这次似乎有些不对劲。等一下，它把 main 放在了 .data 部分! 早些时候我提到了 .text 是只读可执行代码的位置，而 .data 是不可执行的读写值的位置！这就是问题所在，这段代码试图运行被标记为不可执行的内存，这是导致 segfault 的原因。我怎么能让编译器相信我的 &amp;ldquo;main&amp;rdquo; 属于 .text 呢！？好吧，我的搜索结果是空的，我确信这就是道路的尽头。是时候收工了，game over。&lt;/p&gt;
&lt;p&gt;但那晚没有找到解决方案我就无法入睡。我继续搜索，再搜索，直到我在一个 stackoverflow 的帖子上找到一个非常明显和简单的解决方案，可惜我已经找不到网址了。我所要做的就是把 main 函数声明 为const 把它改成 &lt;code&gt;const char main[] = {&lt;/code&gt; 从而让它进入正确的 section，所以让我们再试着编译。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ gcc -Wall const_array_main.c -o fourth
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;const_array_main.c:1:12: warning: ‘main’ is usually a &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;-Wmain&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  const char main&lt;span style=&#34;color:#f92672&#34;&gt;[]&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            ^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ./fourth
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;SL&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;.....&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;emmmm, 它现在在做什么! 是时候再次使用 gdb，看看发生了什么。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gdb .&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;fourth&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(gdb) &lt;span style=&#34;color:#66d9ef&#34;&gt;break&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;_start&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(gdb) &lt;span style=&#34;color:#a6e22e&#34;&gt;run&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(gdb) layout &lt;span style=&#34;color:#66d9ef&#34;&gt;asm&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;所以看一下代码，我们可以看到 main 的地址在 ASM 的 _start 指令中，在我的机器上看起来是这样的 &lt;code&gt;mov $0x4005a0,%rdi&lt;/code&gt; 我们可以用这个在 main 上设置一个断点，通过做 &lt;code&gt;break *0x4005a0&lt;/code&gt;，然后用 c 继续执行。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(gdb) &lt;span style=&#34;color:#66d9ef&#34;&gt;break&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0x4005a0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(gdb) &lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(gdb) x&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;49&lt;/span&gt;i &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;pc     &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;pc is the current executing instruction
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0x4005a4&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;main&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;:&lt;/span&gt;   mov    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0x1&lt;/span&gt;,&lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;eax
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0x4005a9&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;main&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;9&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;:&lt;/span&gt;   mov    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0x1&lt;/span&gt;,&lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;ebx
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0x4005ae&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;main&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;14&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;:&lt;/span&gt;  mov    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0x400510&lt;/span&gt;,&lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;esi
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0x4005b3&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;main&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;19&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;:&lt;/span&gt;  mov    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0xd&lt;/span&gt;,&lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;edx
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0x4005b8&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;main&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;24&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;:&lt;/span&gt;  syscall
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我剪掉了一些不重要的汇编。如果你没有注意到出错的地方，push 到 print 的地址 (0x400510) 并不是我们存储字符串 &lt;code&gt;&amp;quot;Hello world!\n &amp;quot;&lt;/code&gt; 的地址(0x4005c3)！它实际上仍然指向原始编译的可执行文件中的计算位置，而不是使用相对寻址来打印它。这意味着我们需要修改汇编代码，以便加载相对于当前地址的字符串的地址。就目前而言，在 32 位代码中完成这个任务相当困难，但幸运的是我们使用的是 64 位ASM，所以我们可以使用 lea 指令来轻松完成。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;__asm__&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// print Hello World
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;movl $1, %eax;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;/* 1 is the syscall number for write */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;movl $1, %ebx;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;/* 1 is stdout and is the first argument */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// &amp;#34;movl $message, %esi;\n&amp;#34; /* load the address of string into the second argument*/
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// instead use this to load the address of the string
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// as 16 bytes from the current instruction
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;leal 16(%eip), %esi;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;movl $13, %edx;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;/* third argument is the length of the string to print*/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;syscall;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// call exit (so it doesn&amp;#39;t try to run the string Hello World
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// maybe I could have just used ret instead
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;movl $60,%eax;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;xorl %ebx,%ebx; &lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;syscall;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// Store the Hello World inside the main function
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;message: .ascii &lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;Hello World!&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\\&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;n&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    );
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ gcc -Wall relative_str_asm.c -o fifth
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;relative_str_asm.c:1:6: warning: &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; type of ‘main’ is not ‘int’ &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;-Wmain&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  void main&lt;span style=&#34;color:#f92672&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      ^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ./fifth
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Hello World!
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;现在我们可以使用前面讨论过的技术，将十六进制的值提取成一个整数数组。但是这一次，我想通过使用整整 4 个字节的 ints 来使它变得更有伪装性和技巧性。我们可以通过在 gdb 中把信息作为一个 int 打印出来，而不是把十六进制转储到一个文件中，然后再复制粘贴到程序中。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gdb .&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;fifth&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(gdb) x&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;13&lt;/span&gt;dw main
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0x4004ed&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;main&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;:&lt;/span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;443987883&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;440&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;113408&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1922629632&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0x4004fd&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;main&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;16&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;:&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;4149&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;899584&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;84869120&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;15544&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0x40050d&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;main&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;32&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;:&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;266023168&lt;/span&gt;   &lt;span style=&#34;color:#ae81ff&#34;&gt;1818576901&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;1461743468&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;1684828783&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0x40051d&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;main&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;48&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;:&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1017312735&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我选择了数字 13，因为 main 的长度为 49 字节，为了安全起见，49/4 取整为 13。由于我们提前退出了这个函数，所以应该不会有什么影响。现在剩下的就是把这个复制粘贴到我们的 compiled_array_main.c 中并运行它。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; main[] &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;443987883&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;440&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;113408&lt;/span&gt;, &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1922629632&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;4149&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;899584&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;84869120&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;15544&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;266023168&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;1818576901&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;1461743468&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;1684828783&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1017312735&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ gcc -Wall final_array.c -o sixth
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;final_array.c:1:11: warning: ‘main’ is usually a &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;-Wmain&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  const int main&lt;span style=&#34;color:#f92672&#34;&gt;[]&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            ^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ./sixth
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Hello World!
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;自始至终，我们都忽略了关于 warning: ‘main’ is usually a function 的警告信息 :)&lt;/p&gt;
&lt;p&gt;我猜，当我的朋友交出这样的作业时，会因为糟糕的编码风格而扣分，然而并不会说别的&amp;hellip;&amp;hellip;&lt;/p&gt;
&lt;p&gt;This is a version from &lt;a href=&#34;http://jroweboy.github.io/about/&#34;&gt;James Rowe&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>String Hashing 如何工作？</title>
      <link>http://blog.sunbk201.site/posts/string-hashing/</link>
      <pubDate>Tue, 15 Jun 2021 00:00:00 +0000</pubDate>
      
      <guid>http://blog.sunbk201.site/posts/string-hashing/</guid>
      <description>&lt;p&gt;&lt;img src=&#34;https://sunbk201.oss-cn-beijing.aliyuncs.com/img/20210614002954.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;字符串哈希是一种将字符串转换为哈希数字的技术。我们为什么需要这样做？有时我们需要比较超长字符串，此时我们可以比较生成的哈希，而不是比较字符串，从而提升效率。&lt;/p&gt;
&lt;p&gt;假设你需要比较下面的两个字符串：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;A&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;imagine that this is a string of 200 characters&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;imagine that this is a string of 200 characterz&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;假设两个字符串都有 200 个字符。一个暴力的方法是依次比较每个字符，看它们是否匹配。像下面这样：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;A&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;imagine that this is a string of 200 characters&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;imagine that this is a string of 200 characterz&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;equal&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;A&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;A&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;length&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;){
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;A&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;] &lt;span style=&#34;color:#f92672&#34;&gt;!==&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;]) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;console&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;equal&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;A&lt;/span&gt;,&lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;对于超长字符串来说，这并不是最佳选择，因为它的性能是 O(min(A, B))。&lt;/p&gt;
&lt;p&gt;当然，我们可以通过添加一个比较 A 大小和 B 大小的条件来使其成为 O(n)。像下面这样：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;equal&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;A&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;A&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;lenght&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!==&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;length&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;A&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;length&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;){
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;A&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;] &lt;span style=&#34;color:#f92672&#34;&gt;!==&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;]) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;正如我所说，最坏的情况是 O(n)，但在实际生产环境中，我们需要比较一个真正的超长字符串。&lt;/p&gt;
&lt;p&gt;字符串哈希可以将我们的字符串转换成一个整数，这将作为一个哈希数字。因此，我们比较两个哈希值 &lt;code&gt;hash(A)==hash(B)&lt;/code&gt; ，性能会是 O(1)。这是我们比较两个字符串的最佳选择。&lt;/p&gt;
&lt;h1 id=&#34;string-hash-公式&#34;&gt;String Hash 公式&lt;/h1&gt;
&lt;p&gt;&lt;img src=&#34;https://sunbk201.oss-cn-beijing.aliyuncs.com/img/20210617170827.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;我们规定 p 和 m 是素数，s[0], s[1], s[2]… 是每个字符的值，在这里是字符编码。&lt;/p&gt;
&lt;p&gt;p: 素数，大致等于所使用的不同字符的数量。例如，如果我们要计算一个只包括英文小写字母的单词的哈希值，31 会是个不错的数字。然而，如果我们还会使用大写字母的话，那么 53 是一个合适的选择。&lt;/p&gt;
&lt;p&gt;m: 这个数字越大，两个随机字符串出现碰撞的概率就越小。这个变量也应该是素数。&lt;/p&gt;
&lt;p&gt;10 ^ 9 + 9 是个常用的选择。&lt;/p&gt;
&lt;p&gt;比如我们使用下面一组：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;31&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1e9&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;9&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;word&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;apple&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我们想要得到 apple 的哈希，因此我们使用 String Hash 公式：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://sunbk201.oss-cn-beijing.aliyuncs.com/img/20210617170855.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;进一步：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://sunbk201.oss-cn-beijing.aliyuncs.com/img/20210617171007.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;字符编码为：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;a&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;97&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;p&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;112&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;p&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;112&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;l&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;108&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;e&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;101&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在公式中进行替换：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://sunbk201.oss-cn-beijing.aliyuncs.com/img/20210617171156.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;然后我们化简得到公式：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://sunbk201.oss-cn-beijing.aliyuncs.com/img/20210617171227.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;最终：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://sunbk201.oss-cn-beijing.aliyuncs.com/img/20210617171249.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;我们最终得到 apple 的哈希为 96604250。&lt;/p&gt;
&lt;p&gt;以下是 JavaScript 的实现：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;hash&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;word&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;31&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1e9&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;9&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;hash_value&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;word&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;length&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;letter&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;word&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;charCode&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;letter&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;charCodeAt&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#a6e22e&#34;&gt;hash_value&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;hash_value&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;charCode&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; Math.&lt;span style=&#34;color:#a6e22e&#34;&gt;pow&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;hash_value&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;console&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;hash&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;apple&amp;#34;&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is a version from &lt;a href=&#34;https://jorgechavez.dev/&#34;&gt;Jorge Chávez&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>什么是 /dev/null：介绍一下比特桶 (Bit Bucket)</title>
      <link>http://blog.sunbk201.site/posts/dev-null-bit-bucket/</link>
      <pubDate>Mon, 14 Jun 2021 00:00:00 +0000</pubDate>
      
      <guid>http://blog.sunbk201.site/posts/dev-null-bit-bucket/</guid>
      <description>&lt;p&gt;如果你之前曾经使用过 Linux，你很有可能遇到过比特桶 (Bit Bucket)，通常写为 &lt;code&gt;/dev/null&lt;/code&gt;。了解这个特殊的文件是如何工作的以及它的重要性，有利于使之成为我们极有用的工具。我们将讨论什么是 &lt;code&gt;/dev/null&lt;/code&gt;，如何使用它，以及为什么它为什么叫做比特桶。我们还将探讨一些例子，说明它在通常情况下是如何使用的。&lt;/p&gt;
&lt;h1 id=&#34;为什么叫-比特桶&#34;&gt;为什么叫 “比特桶”？&lt;/h1&gt;
&lt;p&gt;早期的计算机使用打孔卡来存储数据和编程代码。当机器打完孔后，未使用的材料会掉进一个桶里。随着时间的推移，比特桶成为一个通用术语，指的是一个丢弃无用比特的地方。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;/dev/null&lt;/code&gt; 的其他名字是 black hole、null route、punch bucket、null device，或者只是 null。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://sunbk201.oss-cn-beijing.aliyuncs.com/img/1280px-Univac_bit_bucket.JPG&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;h1 id=&#34;devnull-文件&#34;&gt;/dev/null 文件&lt;/h1&gt;
&lt;p&gt;&lt;code&gt;/dev/null&lt;/code&gt; 文件是一个在启动时产生的伪设备文件。它没有大小（0字节），在磁盘上占用 0 个块，对所有用户都有读/写权限。下面的截图显示，该文件和上次系统重启的日期和时间相同。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://sunbk201.oss-cn-beijing.aliyuncs.com/img/20210613201532.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;这是一个被称为字符设备文件的特殊文件。这允许该文件像一个设备（空设备）一样运作，它没有缓冲，可以接受数据流。当你访问一个设备文件时，你是在与一个驱动程序进行通信。在 &lt;code&gt;/dev/null&lt;/code&gt; 的情况中，它就像一个带有驱动程序的有具体用途的伪设备。它会丢弃你写给它的任何东西，并且只在读取时返回一个 EOF 字符。发送 EOF 或多或少意味着让进程意识到不会有更多的输入被发送（End of File）。&lt;/p&gt;
&lt;h1 id=&#34;devnull-文件的使用&#34;&gt;/dev/null 文件的使用&lt;/h1&gt;
&lt;h2 id=&#34;使用-devnull-抑制输出&#34;&gt;使用 /dev/null 抑制输出&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;/dev/null&lt;/code&gt; 文件最常被用来抑制输出。在下面的例子中，我们使用 &lt;code&gt;&amp;gt;&lt;/code&gt; 重定向操作符，将 &lt;a href=&#34;https://www.putorius.net/linux-stat-command.html&#34;&gt;stat 命令&lt;/a&gt; 的输出发送到比特桶中。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;stat /etc/passwd &amp;gt; /dev/null
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这样做有效地抑制了输出的命令（标准输出）。&lt;/p&gt;
&lt;p&gt;我们可以使用 &lt;code&gt;/dev/null&lt;/code&gt;，通过重定向标准错误（STDERR）来抑制错误输出，如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;stat /etc/passwdss 2&amp;gt; /dev/null
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我们把文件名改为 passwdss，但它并不存在。这通常会显示一个 “No such file or directory “的错误。不过，由于我们将 STDERR（标准错误）输出重定向到 &lt;code&gt;/dev/null&lt;/code&gt;，所以这个错误被丢弃了。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://sunbk201.oss-cn-beijing.aliyuncs.com/img/ani-diag1-min.gif&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;注意: 要了解更多关于重定向和标准数据流（STDIN、STDOUT、STDERR）的知识，请阅读 &lt;a href=&#34;https://www.putorius.net/linux-io-file-descriptors-and-redirection.html&#34;&gt;Linux I/O, Standard Streams, and Redirection&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;注意: 发送到 &lt;code&gt;/dev/null&lt;/code&gt; 的数据会被立即丢弃，无法恢复。&lt;/p&gt;
&lt;h2 id=&#34;使用-devnull-来输入-eofend-of-file&#34;&gt;使用 /dev/null 来输入 EOF（End of File）&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;/dev/null&lt;/code&gt; 的另一个常见用途是提供一个空白或空的输入，除了EOF字符外什么都没有。你可能并不清楚为什么需要这样一个函数。然而，有很多工具需要一个EOF字符才能进行。例如，mailx 工具将允许你从命令行中输入一个电子邮件。它会一直等待输入，直到它收到一个EOF字符，这个字符是通过点击 CTRL + D 来发送的。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://sunbk201.oss-cn-beijing.aliyuncs.com/img/ani-diag-mail-fast-min.gif&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;注意：EOT（传输结束）和 EOF（文件结束）有技术上的差异，归结为编码问题，不在本教程的范围内。&lt;/p&gt;
&lt;p&gt;如果我们想发送一封空白的电子邮件，我们将不得不进入交互式模式，并点击 CTRL + D，没有输入。如果是在脚本或其他无人看管的情况下使用，这将是不切实际的。作为一种变通方法，我们可以将 &lt;code&gt;/dev/null&lt;/code&gt; 重定向到 mailx 命令中，让它为我们做这件事。&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;mailx -s &amp;#34;Just Another Email&amp;#34; user@putorius.net &amp;lt; /dev/null
Null message body; hope that&amp;#39;s ok
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;使用-devnull-来清空一个文件&#34;&gt;使用 /dev/null 来清空一个文件&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;/dev/null&lt;/code&gt; 文件的另一个常见用途是清空文件的内容。如果你使用 &lt;code&gt;&amp;gt;&lt;/code&gt; 重定向操作符将 &lt;code&gt;/dev/null&lt;/code&gt; 重定向到一个文件中，它将有效地删除该文件的内容。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sunbk201@BKALIEN:~$ ls -l scp.log
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;-rw-r--r-- &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; sunbk201 sunbk201 &lt;span style=&#34;color:#ae81ff&#34;&gt;13&lt;/span&gt; Jun &lt;span style=&#34;color:#ae81ff&#34;&gt;13&lt;/span&gt; 20:48 scp.log
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sunbk201@BKALIEN:~$ cat /dev/null &amp;gt; scp.log
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sunbk201@BKALIEN:~$ ls -l scp.log
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;-rw-r--r-- &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; sunbk201 sunbk201 &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; Jun &lt;span style=&#34;color:#ae81ff&#34;&gt;13&lt;/span&gt; 20:48 scp.log
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sunbk201@BKALIEN:~$ cat scp.log
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;另一个选择是使用 &lt;code&gt;cp&lt;/code&gt; 命令将 &lt;code&gt;/dev/null&lt;/code&gt; 复制到该文件上，像这样：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sunbk201@BKALIEN:~$ ls -l scp.log
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;-rw-r--r-- &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; sunbk201 sunbk201 &lt;span style=&#34;color:#ae81ff&#34;&gt;13&lt;/span&gt; Jun &lt;span style=&#34;color:#ae81ff&#34;&gt;13&lt;/span&gt; 20:49 scp.log
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sunbk201@BKALIEN:~$ cp /dev/null scp.log
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sunbk201@BKALIEN:~$ ls -l scp.log
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;-rw-r--r-- &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; sunbk201 sunbk201 &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; Jun &lt;span style=&#34;color:#ae81ff&#34;&gt;13&lt;/span&gt; 20:50 scp.log
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;总结&#34;&gt;总结&lt;/h1&gt;
&lt;p&gt;比特桶（/dev/null）对于系统管理员、开发工程师和几乎所有使用命令行的人来说都是一个重要而有用的工具。在这篇文章中，我们讨论了 &lt;code&gt;/dev/null&lt;/code&gt; 的一些最常见的用途，一旦你知道它的作用，你可能会发现越来越多的使用方法。&lt;/p&gt;
&lt;p&gt;Resource and Links:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://linux.die.net/man/4/null&#34;&gt;Null Man Page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.putorius.net/linux-io-file-descriptors-and-redirection.html&#34;&gt;Linux I/O, Standard Streams, and Redirection&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Bit_bucket&#34;&gt;Bit Bucket – WikiPedia&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Null_device&#34;&gt;Null Device – WikPedia&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is a version from &lt;a href=&#34;https://www.putorius.net/&#34;&gt;putorius&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>3 Tribes of Programming - 3 大编程阵营</title>
      <link>http://blog.sunbk201.site/posts/3-tribes-of-programming/</link>
      <pubDate>Sun, 06 Jun 2021 00:00:00 +0000</pubDate>
      
      <guid>http://blog.sunbk201.site/posts/3-tribes-of-programming/</guid>
      <description>&lt;p&gt;有一个老笑话，计算机科学其实是一个谎言，因为它不怎么跟计算机相关，也不是真正的科学。&lt;/p&gt;
&lt;p&gt;有趣的笑话，每个人都笑了, 然后有人说 “但是它还是跟计算机有些相关性的，不是吗？”。&lt;/p&gt;
&lt;p&gt;在外面，有争论是这样的：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“ I’ll happily renounce “programmer” in favor of “applied mathematician” or something, whatever it takes to avoid C. - &lt;a href=&#34;https://t.co/DsIEo5x4uI&#34;&gt;https://t.co/DsIEo5x4uI&lt;/a&gt; / Twitter
有些人认为，我们计算机中的整个现代堆栈（内核、操作系统、浏览器、虚拟机）是用C + ASM 编写的。所以你应该了解 C 和 ASM。&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;这真的很重要吗？问题的关键在于：一个程序，指令序列与逻辑思想的表达，两者谁更重要？&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://sunbk201.oss-cn-beijing.aliyuncs.com/img/C9-K_xsVwAAJfqY.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;也可能两者都不是，而程序只是我们为其他人制作的东西。如果没有阅读它的读者，任何一条信息都是无意义的。如果不参考它们所处的外部世界，程序是否也毫无意义？&lt;/p&gt;
&lt;p&gt;一个朋友曾经向我吹嘘，他可以用Ada证明大多数程序是正确的，而且完全没有错误。我问他能不能证明这个函数是正确的。&lt;/p&gt;
&lt;p&gt;fn sub(a, b) { return a + b }&lt;/p&gt;
&lt;p&gt;他说：“当然，这太简单了”。于是我问他他的测试工具如何发现函数有错误的名字，他笑着慌了手脚。&lt;/p&gt;
&lt;h1 id=&#34;三大编程阵营&#34;&gt;三大编程阵营&lt;/h1&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;你是一个创造者。你创造事物为人们所用。
我们在这些理想的基础上自我选择进入同侪的社区。我们使用编码语言来向我们的同侪表达这些理想。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我认为每个群体都有自己的准则，和自己的子版块。他们有自己的编程语言、英雄与反派。&lt;/p&gt;
&lt;h2 id=&#34;编程即数学的应用&#34;&gt;编程即数学的应用&lt;/h2&gt;
&lt;p&gt;第一个阵营认为，编程从根本上说是一种思想的表达 - 一种我们可以用生命来馈赠的数学诗歌。在冯·诺依曼机器上执行它们只是一个实现细节。&lt;/p&gt;
&lt;p&gt;带着这种心态，下面这些细节就很重要：&lt;/p&gt;
&lt;p&gt;源代码：源代码应该读起来像诗歌一样 - 稠密又浓重，只需要很少的几行代码来表达一个想法。一旦理解，简练的程序看起来就像是对你的程序的美丽而明显的描述。 源代码的精炼比执行的简单或快速更重要。高级语言比低级语言更优秀，因为高级语言能让你更清楚地表达你的意图。
执行：程序如何被计算机执行只是编译器的一个执行细节，代码的简单比执行的快速更重要。
正确性：如果准确的实现了规范，那么程序将会是正确的。我们可以使用Ada来证明程序的正确性。
UI：代码如何与人进行互动与他程序的实现是两码事，漂亮的代码比漂亮的用户界面更重要。
举例: &lt;a href=&#34;https://www.youtube.com/watch?v=f84n5oFoZBc&#34;&gt;Rich Hickey&lt;/a&gt;, &lt;a href=&#34;https://vimeo.com/36579366&#34;&gt;Brett Victor&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这类程序员可能是最不常见的，这可能是因为这种人很难找到工作。在 stackoverflow 统计的的所有语言中，Haskell 在的周末使用率最高。&lt;/p&gt;
&lt;p&gt;现代编程语言的大部分（可以说是全部）的进步都源自于这个阵营的努力。如果你用 React 做了一个网站，你应该知道，不变性模型和把你的观点表达为从数据到 DOM 的纯函数模型来自函数式编程。实际上，大多数现代语言的功能都是由那些把编程当作思想的人发明的。几年（或几十年）之后，这些功能被复制到更流行的语言中，并被当作新的想法。&lt;/p&gt;
&lt;p&gt;我有一个朋友，他花了几个月的时间喜欢上了 J，他最终用 J 写了一个小游戏，他把他的代码描述成这个完美无瑕的水晶。后来他想把它做成多人游戏 - 但要做到这一点，他就必须处理迟延问题。而这将需要分割一些美丽的内部流程。他无法忍受这一点，所以他完全放弃了这个项目。&lt;/p&gt;
&lt;p&gt;这个故事很有趣，但我有点嫉妒我的朋友。我打赌他学到了很多东西，而且玩得很开心。这样的经历使我们变得更加优秀。&lt;/p&gt;
&lt;p&gt;去年年底我参加了一个 Haskell 的短期课程，我向主讲老师提出了挑战。我告诉他：“这的确不错，但我打赌我仍然可以用我的实用语言比你更快地做出有用的软件”。他说不可能 - 使用 haskell，他相信他可以实现任何我可以实现的东西，而且更快、更好，代码更少。我们没有验证这个说法 - 但我仍然想知道 - 他是对的吗？&lt;/p&gt;
&lt;p&gt;最喜欢的语言：Haskell, Lisp, ML (Ocaml, etc), Closure, ADA&lt;/p&gt;
&lt;p&gt;居所：FP meetups, &lt;a href=&#34;http://lambda-the-ultimate.org/&#34;&gt;Lambda the ultimate&lt;/a&gt;, Strange Loop, &lt;a href=&#34;https://www.data61.csiro.au/&#34;&gt;Research&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://steve-yegge.blogspot.com.au/2010/12/haskell-researchers-announce-discovery.html&#34;&gt;Steve Yegge making fun of this tribe&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;编程即硬件-hack&#34;&gt;编程即硬件 Hack&lt;/h2&gt;
&lt;p&gt;第二个阵营认为，编程从根本上是与计算机的硬件联系在一起的。没有计算机就无法运行任何程序，因此要进行有效地编程，我们必须时刻牢记计算机 - 硬件和软件。&lt;/p&gt;
&lt;p&gt;优雅和美丽不仅来自于简单的代码库，而且来自于该代码库以一种优雅和有效的方式驱动硬件。&lt;/p&gt;
&lt;p&gt;因此，优雅之处在于：&lt;/p&gt;
&lt;p&gt;源代码：代码应该是简洁的，但是简介的代码不如干净利落的执行来的重要。低级语言通常优于高级语言，因为你可以更明确地知道计算机在执行你的代码时在做些什么（因此，你有更多的空间来进行优化）。
执行：计算机如何执行你的代码是最重要的。不考虑执行的编程只是在为缓慢的性能添砖加瓦。
正确性：如果一个程序在正常参数下以你期望的方式运行，那么它就是正确的。执行的优雅性比正确性更重要。如果一个理论上的问题由于机器的工作方式而无法在实践中发生，那么它就不是一个真正的错误。一个程序必须有快速的执行速度才能被认为是正确的。
UI：代码如何与人互动是与它的实现应该分开考虑。让硬件的限制来指导用户体验是可以的。
举例： Poul-Henning Kamp, Michael Steil, The 8-Bit guy&lt;/p&gt;
&lt;p&gt;这里的关键是要考虑到计算机和你的运行程序的整体性。按照此方阵营的说法，编写好软件的最佳（唯一）方法是全面考虑它将如何运行，以及我们的程序将如何与其他硬件和软件互动。做好这一点，就能达到硬件的共鸣，一切都像上好油的时钟一样运行。这种快乐就像驾驶一辆你能听到和理解的手波车一样。&lt;/p&gt;
&lt;p&gt;任何混淆计算机如何执行你的程序的行为对执行方来说都是危险的 - 因为它增加了更多需要考虑的变量。因此，这个阵营的人经常嘲笑垃圾回收器，或者 JS 性能基准测试结果的大闹改变了我们编写代码的方式。C 语言编译器中的未定义行为是一个持续争论的焦点。&lt;/p&gt;
&lt;p&gt;在现代应用开发中，我们的计算机速度已经足够快了，这种思维已经不那么重要。几十年前，你需要对计算机的工作原理有深刻的理解才能编写软件。但现在基本上你使用的任何语言都足够快了，所以为什么要费心学习 C 语言呢？我认识的大多数网络开发者都不懂 C 语言，也没有兴趣去学习指针或手动内存管理。&lt;/p&gt;
&lt;p&gt;但是这类工作在很多领域仍然有很大的价值。游戏开发社区仍然用 C++ 编写大部分代码（尽管unity正在慢慢改变这种状况）。安全工程师需要一个系统的理解来寻找漏洞。嵌入式系统工程师不能浪费周期和内存，一旦后端系统变得足够大，性能又开始重要起来。&lt;/p&gt;
&lt;p&gt;而且，即使它不实用，但被迫思考机器的问题也是非常有趣的! 例如，PICO-8 施加了专横的 “硬件 “限制，迫使你在设计游戏的时候变得聪明起来。&lt;/p&gt;
&lt;p&gt;在这个社区中，我们的计算机几乎所有的性能改进都归功于此，超出了客户的要求。没有人像那些整天考虑硬件的人那样关心性能。但是，如果你把你的电脑当成一台机器，还有什么比无意义的工作更让你感到丑陋的呢？&lt;/p&gt;
&lt;p&gt;我真的很好奇 Rust 是否会在这个社区中大火。Rust 本质上是一种由上述第一阵营的语言书呆子设计的语言，为那些关心运行时效率的人服务。他们会接受它吗？未来的游戏引擎会被移植到 Rust 上吗？&lt;/p&gt;
&lt;p&gt;与第一个阵营的冲突：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;可变性 （内存从根本上说是可变的 / 但它使我们的程序更难理解）&lt;/li&gt;
&lt;li&gt;GC （它使你的程序变得缓慢而笨拙 / 但错误较少！）&lt;/li&gt;
&lt;li&gt;抽象（你使你的程序更难 / 更容易推理）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;最喜欢的语言：C, C++, Assembly&lt;/p&gt;
&lt;p&gt;居所：Hackerspaces, Game dev shops, database companies, CCC, Defcon.&lt;/p&gt;
&lt;p&gt;Brett Victor &lt;a href=&#34;https://vimeo.com/71278954&#34;&gt;making fun of this tribe&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;编程即创造的工具&#34;&gt;编程即创造的工具&lt;/h2&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;正确性：Bugs 的坏处只与它们的影响成正比。程序应该按照用户期望的方式运行。&lt;/li&gt;
&lt;li&gt;UI：UI 比其他任何东西都要重要。程序的其他部分都是为用户界面而存在的。
我认为大多数专业的软件工程师都在这个阵营里 - 这很合理，因为这是写软件最容易赚钱的地方。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;根据我的经验，这个阵营的人在社区方面更出色。他们似乎更积极，更鼓励新成员，并愿意提供帮助。 我想这是因为你可以通过简单的观察自己来判断你在其他两个阵营中是否做得很好。如果你为其他人制作软件，满足感来自于让你周围的人感到快乐。&lt;/p&gt;
&lt;p&gt;我不禁觉得这个地方有点儿没有灵魂。走到极端，这种世界观并不重视工程本身的美。尽管你可能会对其他团体提出相反的批评 - 他们不重视他们的软件如何影响世界。&lt;/p&gt;
&lt;p&gt;在这个阵营和我谈到的其他两个阵营之间存在着很多冲突。而且这可能会变得有点刻薄。 我知道很多做产品的人对他们缺乏传统数据结构和算法的知识感到自责。他们觉得被 “真正的” 程序员批判，因为他们不能实现晦涩的算法和二进制框架协议。 在这个阵营的人看来，反正其他人已经实现了所有这些东西。所以，谁在乎呢？&lt;/p&gt;
&lt;p&gt;这还算公平，但它也是事实，很多问题是由前端工程师缺乏技术能力造成的。这主要是自我纠正 - 如果你的程序太慢，你知道它并可以修复它。 但是安全工程是真正的危险。如果你不知道如何保护你编写的软件不受黑客攻击，那么它可能就很危险。 而且，即使你被黑了，你也可能不知道这是个问题。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;@jdan Well, then you’re not a very good programmer. Sorry but that’s how it is.&amp;rdquo; ~ Jonathan Blow (@Jonathan_Blow) June 12, 2015&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;就上面的言论而言，Jonathan Blow（著名的独立游戏开发者）说，如果你不能逆转二叉树，你就不是一个好的开发者，即使你每天都在写有用的软件。&lt;/p&gt;
&lt;p&gt;他说的对吗？这取决于 “好的开发者” 是什么意思，而这又取决于你关心的是哪个阵营。 我认为 Blow 是&lt;a href=&#34;https://www.youtube.com/watch?v=gWv_vUgbmug&#34;&gt;在第二阵营&lt;/a&gt;，评判标准是你知道多少。 @jdan在第三阵营，所以他的评判标准是他做了什么。Jonathan Blow 当然会写出有用的软件，但他的上一个游戏（The Witness）花了这么长时间，原因之一是他自己写的引擎，而不是使用现成的东西。当&lt;a href=&#34;http://the-witness.net/news/2011/06/how-to-program-independent-games/comment-page-2/#comment-3655&#34;&gt;被问及这个问题时&lt;/a&gt;：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“ 我对Unity不是很了解。然而，很明显，如果不重写大部分Unity（或添加很多没有的东西，拒绝使用Unity提供的大部分东西），就无法在Unity中构建 The Witness。而我们反正已经有了一个简单的图形引擎。因此，在建立我们自己的系统时，我们可以确保它们确实是游戏所需要的最好的东西。 ”&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;我怀疑他对第一部分的看法是错误的。但我自己主要是在第二阵营，所以我理解无论如何要写自己的引擎这种想法。我可能也会做同样的事情。&lt;/p&gt;
&lt;p&gt;最喜欢的语言：无论做什么都完成了工作。JS, Ruby, Python, Swift, C#.&lt;/p&gt;
&lt;p&gt;居所：Twitter, SydJS, StackOverflow, 你附近的公司!&lt;/p&gt;
&lt;p&gt;Gary Bernhardt &lt;a href=&#34;https://www.destroyallsoftware.com/talks/the-birth-and-death-of-javascript&#34;&gt;making fun of this camp&lt;/a&gt;.&lt;/p&gt;
&lt;h1 id=&#34;一场安静的战争&#34;&gt;一场安静的战争&lt;/h1&gt;
&lt;p&gt;我认为我们社区中的很多冲突和分歧都可以用这些术语来表达。并且还有很多程序员之间的误解。&lt;/p&gt;
&lt;p&gt;例如，当一个整数溢出时，你的编程语言应该怎么做？如果你认为编程就像数学诗一样，首先它应该给你一个数学上正确的结果。&lt;/p&gt;
&lt;p&gt;Haskell (第一阵营):&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;λ: 23^23
20880467999847912034355032910567 :: Num a =&amp;gt; a
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Vs C (第二阵营):&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;printf(&amp;#34;%llu\n&amp;#34;, 1 &amp;lt;&amp;lt; 100); // overflows. Prints 0.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;而如果你只是想发布一个产品，你就不必须在乎了。在javascript中（第三阵营），根本就没有整数类型。JS只用浮点数来表示一切。如果它们溢出了，那就倒霉了。&lt;/p&gt;
&lt;p&gt;Rust 试图在前两个阵营中各占一席之地 - 成为一门由编程语言书呆子创造的语言，但却能编译出高效的代码。不出所料，这个问题在 Rust 社区引起了长时间的争论。最后的解决方案是这样的：默认情况下，溢出导致的异常在调试模式下被抛出，但在生产模式下安静地工作。&lt;/p&gt;
&lt;p&gt;Rob Pike（ Go 的作者）对他的语言想要吸引哪个阵营感到困惑。他在 Go 发布几年后写了这篇文章。&lt;/p&gt;
&lt;p&gt;“ 几周前有人问我，“你在推出 Go 时遇到的最大惊喜是什么？” 我立刻就知道了答案。尽管我们期望 C++ 程序员将 Go 视为一种替代方案，但大多数Go程序员来自 Python 和Ruby 等语言。很少有来自 C++ 的人。 ”&lt;/p&gt;
&lt;p&gt;为什么？好吧，C++ 程序员在很大程度上属于上述第二阵营。他们想知道他们的代码将如何运行。但是 Go 有一个垃圾收集器和一个快速编译器。真的，Go 关心的是如何摆脱你的束缚，让你可以直接做东西。它是为最后一个阵营的人设计的语言，他们想制造产品。那些关心这个问题的人目前使用什么语言呢？Python、Ruby 和 Javascript。所以 Go 的目标当然是他们。&lt;/p&gt;
&lt;h1 id=&#34;闭幕&#34;&gt;闭幕&lt;/h1&gt;
&lt;p&gt;下一次，当你看到关于 Javascript 是我们行业的毒瘤还是福音的争论时，或者当你看到像我这样的人对现代应用程序是垃圾感到愤怒时，请问你自己是为哪个阵营说话。 他们是在拥护美丽的代码吗？性能和 “深刻理解”？还是他们只想完成工作和发布产品？&lt;/p&gt;
&lt;p&gt;归根结底，代码就是代码。即使我们有不同的理由来写软件，我们所写的东西（通常）是兼容的。即使不是这样（Haskell）- 也总是有很多我们可以学习和窃取的想法。&lt;/p&gt;
&lt;p&gt;毕竟，我们都欠对方很多。没有语言书呆子，我们仍然在写汇编。没有系统程序员，我们就不会有操作系统，而 haskell 和 javascript 也会慢得不能再慢。如果没有产品工程师，其他人就会被迫写 CSS。相信我，没有人愿意这样。&lt;/p&gt;
&lt;p&gt;格雷斯-霍珀海军少将（Rear Admiral Grace Hopper）成功地将机器理解和产品思维联系起来，并在此过程中发明了一种与机器无关的计算机语言的概念。如果不能同时考虑到计算机能做什么和我们希望计算机做什么，这就不可能实现。&lt;/p&gt;
&lt;p&gt;但我个人认为，我们应该渴望成为 &lt;a href=&#34;https://www.youtube.com/watch?v=YyIQKBzIuBY&#34;&gt;Alan Kay&lt;/a&gt; 那样的人，同时做到这三点。他和他的团队经常跨越多个阵营的界限。举个例子，他从观察儿童学习 Squeak 和 Logo 中发明了面向对象的编程。他认为有一些方法可以让吃到蛋糕 - 使用现代技术来设计更简单的系统，使其更快、更优雅、对人类更有用。如果你还没有这样做，你应该看看他的每一次演讲。慢慢地看吧。&lt;/p&gt;
&lt;p&gt;这当然是我的目标。希望我在70岁以后还能让人们大吃一惊。&lt;/p&gt;
&lt;p&gt;This is a version from &lt;a href=&#34;https://josephg.com/&#34;&gt;josephg&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Why OO Sucks - 为什么面向对象糟透了？</title>
      <link>http://blog.sunbk201.site/posts/why-oo-sucks/</link>
      <pubDate>Thu, 03 Jun 2021 00:00:00 +0000</pubDate>
      
      <guid>http://blog.sunbk201.site/posts/why-oo-sucks/</guid>
      <description>&lt;p&gt;当我第一次接触到 OOP（面向对象编程） 思想的时候，我是持怀疑态度的，但我不知道是因为什么，只是感觉这是”错误“的。OOP 推出后变得非常流行（我稍后会解释为什么），现在批评 OOP 就好比在亵渎神明。OOness（面向对象性） 成为任何一种受欢迎语言必须拥有的东西。&lt;/p&gt;
&lt;p&gt;说到这里，我想起了在巴黎举行的第 7 届 IEEE Logic 编程大会上，法国 IBM 时任老板的主旨演讲。 IBM prolog 已经添加了很多 OO 扩展，当被问及为什么他回答：&lt;/p&gt;
&lt;p&gt;“我们的客户想要 OO prolog，所以我们制作了 OO prolog”&lt;/p&gt;
&lt;h1 id=&#34;why-oo-sucks---为什么面向对象糟透了&#34;&gt;Why OO Sucks - 为什么面向对象糟透了&lt;/h1&gt;
&lt;p&gt;我对 OOP （面向对象编程）的主要反对意见要追溯到其中涉及的基本思想，我将概述其中的一些思想以及我对它们的反对意见。&lt;/p&gt;
&lt;h2 id=&#34;反对-1---数据结构和函数不应绑定在一起&#34;&gt;反对 1 - 数据结构和函数不应绑定在一起&lt;/h2&gt;
&lt;p&gt;对象以不可分割的单位将函数和数据结构绑定在一起。 我认为这是一个基本错误，因为函数和数据结构属于完全不同的世界。 为什么？&lt;/p&gt;
&lt;p&gt;函数是功能的执行，是做什么，它们有输入和输出。输入和输出是数据结构，这些数据结构被函数改变。函数是由命令式序列构建的：“先做这个再做那个…”， 要理解函数，你必须理解事情完成的顺序（在惰性 FPL 和逻辑语言中，这个限制是放松的）。&lt;/p&gt;
&lt;p&gt;数据结构就只是数据结构，他们什么都不做。它们本质上是声明。 “理解”数据结构比“理解”函数容易得多。&lt;/p&gt;
&lt;p&gt;函数被理解为将输入转换为输出的黑盒。如果我理解了输入和输出，那么我就理解了函数。但这并不意味着我可以编写该函数。&lt;/p&gt;
&lt;p&gt;函数通常是通过观察它们是计算系统中的事物来“理解”的，该系统的工作是将类型 T1 的数据结构转换为类型 T2 的数据结构。&lt;/p&gt;
&lt;p&gt;函数和数据结构是完全不同类型的事物，因此将它们锁在同一个笼子里从根本上是错误的。&lt;/p&gt;
&lt;h2 id=&#34;反对-2---一切都必须是对象&#34;&gt;反对 2 - 一切都必须是对象&lt;/h2&gt;
&lt;p&gt;想想 “time”。在面向对象语言中，“time” 必须是一个对象。但是在非 OO 语言中，“time” 只是数据类型的一个实例。例如，在 Erlang 中有很多不同种类的时间，这些可以使用类型声明清晰明确地指定，如下所示：&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;-deftype day() = 1..31.
-deftype month() = 1..12.
-deftype year() = int().
-deftype hour() = 1..24.
-deftype minute() = 1..60.
-deftype second() = 1..60.
-deftype abstime() = {abstime, year(), month(), day(), hour(), min(), sec()}.
-deftype hms() = {hms, hour(), min(), sec()}.
...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;请注意，这些定义不属于任何特定对象。它们无处不在，表示时间的数据结构可以被系统中的任何函数操作。&lt;/p&gt;
&lt;p&gt;没有关联的方法。&lt;/p&gt;
&lt;h2 id=&#34;反对-3---在-oopl面向对象编程语言中数据类型定义是分散在各处的&#34;&gt;反对 3 - 在 OOPL（面向对象编程语言）中，数据类型定义是分散在各处的&lt;/h2&gt;
&lt;p&gt;在 OOPL 中，数据类型定义属于对象。所以我无法在一个地方找到所有的数据类型定义。在 Erlang 或 C 中，我可以在单个包含文件或数据字典中定义所有数据类型。在 OOPL 中我不能这么做：数据类型定义散布在各处。&lt;/p&gt;
&lt;p&gt;让我举一个例子。假设我想定义一个无处不在的数据结构，在 OOPL 中会带来麻烦。&lt;/p&gt;
&lt;p&gt;正如 lisp 程序员早就知道的那样，拥有少量普遍存在的数据类型和大量用于处理它们的小函数比拥有大量数据类型和少量起作用的函数要好。&lt;/p&gt;
&lt;p&gt;无处不在的数据结构类似于链表、数组或哈希表，或者更高级的对象，如时间、日期或文件名。&lt;/p&gt;
&lt;p&gt;在 OOPL 中，我必须选择一些基础对象，我将在其中定义普遍存在的数据结构，所有其他想要使用该数据结构的对象都必须继承该对象。 假设现在我想创建一些“时间”对象，它属于哪里以及在哪个对象中……&lt;/p&gt;
&lt;h2 id=&#34;反对-4---对象有私有状态&#34;&gt;反对 4 - 对象有私有状态&lt;/h2&gt;
&lt;p&gt;状态是万恶之源。特别是应该避免有副作用的函数。&lt;/p&gt;
&lt;p&gt;虽然编程语言中的状态是不可取的，但在现实世界中状态比比皆是。我对我的银行账户状态非常关心，当我从银行存款或取款时，我希望我的银行账户状态能够正确更新。&lt;/p&gt;
&lt;p&gt;鉴于现实世界中存在状态，编程语言应该提供哪些工具来处理状态？&lt;/p&gt;
&lt;p&gt;OOPL说： “对程序员隐藏状态”。状态只有通过访问函数才能隐藏和可见。
传统的编程语言（C、Pascal）说： 状态变量的可见性是由语言的作用域规则控制的。
纯声明式语言说： 没有状态。
系统的全局状态被带入到所有函数中并又从所有函数中带出来，诸如 monad（用于 FPL）和 DCG（逻辑语言）之类的机制用于向程序员隐藏状态， 因此他们可以好像“状态无关紧要”的进行编程，但在必要时可以完全访问系统状态。&lt;/p&gt;
&lt;p&gt;OOPL 的 “对程序员隐藏状态” 是最糟糕的选择。他们没有暴露状态并试图找到减少状态干扰的方法，而是将其隐藏起来。&lt;/p&gt;
&lt;h1 id=&#34;为什么-oo-很受欢迎&#34;&gt;为什么 OO 很受欢迎？&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;原因 1 - 它被认为很容易学习。&lt;/li&gt;
&lt;li&gt;原因 2 - 它被认为使代码重用更容易。&lt;/li&gt;
&lt;li&gt;原因 3 - 它被炒作了。&lt;/li&gt;
&lt;li&gt;原因 4 - 它创造了一个新的软件产业。
我看不到原因 1 和 2 的证据。原因 3 和 4 似乎是技术背后的驱动力。如果一种语言技术如此糟糕以至于它创造了一个新的行业来解决它自己制造的问题，那么对于从中获利的人来说，这一定是个好主意。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这才是 OOP 背后的真正驱动力。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Shadowsocks-libev 部署教程</title>
      <link>http://blog.sunbk201.site/posts/shadowsocks-libev-deploy/</link>
      <pubDate>Wed, 02 Jun 2021 00:00:00 +0000</pubDate>
      
      <guid>http://blog.sunbk201.site/posts/shadowsocks-libev-deploy/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://sunbk201public.notion.site/sunbk201public/Shadowsocks-libev-f78f777f132b4caea67b38736cc3d662&#34;&gt;https://sunbk201public.notion.site/sunbk201public/Shadowsocks-libev-f78f777f132b4caea67b38736cc3d662&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>ShellClash 加密防检测教程</title>
      <link>http://blog.sunbk201.site/posts/shellclash-deploy/</link>
      <pubDate>Wed, 02 Jun 2021 00:00:00 +0000</pubDate>
      
      <guid>http://blog.sunbk201.site/posts/shellclash-deploy/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://sunbk201public.notion.site/sunbk201public/ShellClash-d199f43309e44ab4b4d4ece01dbac3bb&#34;&gt;https://sunbk201public.notion.site/sunbk201public/ShellClash-d199f43309e44ab4b4d4ece01dbac3bb&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>OpenWrt 编译与防检测部署教程</title>
      <link>http://blog.sunbk201.site/posts/openwrt-compile/</link>
      <pubDate>Tue, 01 Jun 2021 00:00:00 +0000</pubDate>
      
      <guid>http://blog.sunbk201.site/posts/openwrt-compile/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://sunbk201public.notion.site/sunbk201public/OpenWrt-f59ae1a76741486092c27bc24dbadc59&#34;&gt;https://sunbk201public.notion.site/sunbk201public/OpenWrt-f59ae1a76741486092c27bc24dbadc59&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>全新方案-懒人福音-无需手动编译修改UA-校园网防检测</title>
      <link>http://blog.sunbk201.site/posts/change-ua-by-proxy/</link>
      <pubDate>Sun, 30 May 2021 00:00:00 +0000</pubDate>
      
      <guid>http://blog.sunbk201.site/posts/change-ua-by-proxy/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://blog.sunbk201.site/posts/ua3f/&#34;&gt;校园网防检测: UA3F - 新一代 UA 修改方法&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://blog.sunbk201.site/crack-campus-network&#34;&gt;关于某大学校园网共享上网检测机制的研究与解决方案&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://blog.sunbk201.site/posts/openwrt-compile&#34;&gt;OpenWrt 编译与防检测部署教程&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;阅读过上面两篇文章的同学可以发现，手动编译OpenWrt是一件很痛苦的事。 显然对于一些动手能力不强的同学来说，通过 UA2F 修改UA是比较困难的。而且，UA2F从设计层面上也存在一些问题，例如无法处理网卡分包等情况。&lt;/p&gt;
&lt;p&gt;因此，我们需要一种更加简单的方案，既能无需编译OpenWrt，又能更好的满足我们的需求。&lt;/p&gt;
&lt;p&gt;之前我曾经提到过我们可以通过加密流量来实现防检测，但我当时并没有采取这个策略，因为进行全局加密网络流畅度影响太大， 而进行部分加密目前市面上还没有很好的解决方案（之前是这么认为），目前大多数加密软件都是基于规则的加密，但支持的多为针对域名的加密。&lt;/p&gt;
&lt;p&gt;然而我们的需求是针对http应用层的加密，这类加密方案目前支持的不多。&lt;/p&gt;
&lt;p&gt;经过我深入了解，Clash 中 DstPort 是我们最理想的规则选项，我们可以指定代理目标端口为http的80端口从而实现http应用层的加密。&lt;/p&gt;
&lt;p&gt;此外，除了针对http的加密外，我们还可以通过支持Mitm的网络调试工具对http中UA进行重写以达到修改UA的目的。&lt;/p&gt;
&lt;p&gt;基于上面的分析，我总结了以下方案：&lt;/p&gt;
&lt;h1 id=&#34;windows-用户&#34;&gt;Windows 用户&lt;/h1&gt;
&lt;p&gt;使用 Clash，添加规则：&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;- DST-PORT,80,proxy
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;加入以上规则即可实现针对 80 端口的加密&lt;/p&gt;
&lt;h1 id=&#34;andorid-用户&#34;&gt;Andorid 用户&lt;/h1&gt;
&lt;p&gt;使用 Clash，添加规则：&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;- DST-PORT,80,proxy
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;加入以上规则即可实现针对80 端口的加密&lt;/p&gt;
&lt;h1 id=&#34;ios--mac-用户&#34;&gt;iOS &amp;amp; Mac 用户&lt;/h1&gt;
&lt;p&gt;使用 Quantumult X/Surge 等支持重写的工具，添加重写规则：&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;# Quantumult X
^http:// url request-header (\r\n)User-[A|a]gent:.+(\r\n) request-header $1User-Agent: F$2
&lt;/code&gt;&lt;/pre&gt;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;# Surge
^http:// header-replace User-Agent F
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;加入以上规则即可实现针对 UA 的重写&lt;/p&gt;
&lt;h1 id=&#34;openwrt-配置&#34;&gt;OpenWrt 配置&lt;/h1&gt;
&lt;p&gt;使用 OpenClash，添加规则：&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;- DST-PORT,80,proxy
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;如果在 OpenWrt 加入这条配置，那么就无需进行其他终端的配置了。&lt;/p&gt;
&lt;h1 id=&#34;其他&#34;&gt;其他&lt;/h1&gt;
&lt;p&gt;对于 TTL 和 NTP 方面，我们无需进行手动编译，常见的 OpenWrt 固件都能够默认支持。 对于 IPID，我认为无需关注，基于 IPID 的检测我认为是不现实且很少见的。&lt;/p&gt;
&lt;p&gt;如果有疑问可以加讨论组：&lt;a href=&#34;https://t.me/crack_campus_network&#34;&gt;Telegram&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>关于某大学校园网共享上网检测机制的研究与解决方案</title>
      <link>http://blog.sunbk201.site/posts/crack-campus-network/</link>
      <pubDate>Sat, 13 Mar 2021 00:00:00 +0000</pubDate>
      
      <guid>http://blog.sunbk201.site/posts/crack-campus-network/</guid>
      <description>&lt;h1 id=&#34;太长不看写于-202511&#34;&gt;太长不看（写于 2025.11）&lt;/h1&gt;
&lt;p&gt;校园网共享检测有 4 种方式，检测力和难度依次加大：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;针对 IP 数据包的 TTL 字段的检测&lt;/li&gt;
&lt;li&gt;针对 HTTP User-Agent 字段的检测&lt;/li&gt;
&lt;li&gt;针对 TCP 时间戳计算时钟偏移的检测&lt;/li&gt;
&lt;li&gt;针对部分应用特征的 DPI 检测（例如微信）&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;⚠️注意：你的校园网不一定 4 种方式都会开启。&lt;/p&gt;
&lt;p&gt;下面是针对这 4 种检测方式的解决方案总结：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;修改 TTL 字段：在路由器防火墙添加。使用 &lt;a href=&#34;https://github.com/SunBK201/UA3F&#34;&gt;UA3F&lt;/a&gt; 默认配置开箱即用，ipk 安装即可。&lt;/li&gt;
&lt;li&gt;修改 User-Agent 字段：使用 &lt;a href=&#34;https://github.com/SunBK201/UA3F&#34;&gt;UA3F&lt;/a&gt;，默认配置开箱即用，ipk 安装即可。&lt;/li&gt;
&lt;li&gt;清除 TCP 时间戳选项：使用 &lt;a href=&#34;https://github.com/SunBK201/UA3F&#34;&gt;UA3F&lt;/a&gt; 的清除 TCP 时间戳选项功能即可。&lt;/li&gt;
&lt;li&gt;加密流量：使用科学代理加密（例如 Clash、Surge 等），将部分特征流量进行加密。&lt;a href=&#34;https://github.com/SunBK201/UA3F#clash-%E5%8F%82%E8%80%83%E9%85%8D%E7%BD%AE&#34;&gt;UA3F&lt;/a&gt; 提供了 Clash 参考配置。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;UA3F 的使用教程见：&lt;a href=&#34;https://sunbk201public.notion.site/UA3F-2a21f32cbb4b80669e04ec1f053d0333&#34;&gt;猴子也能看懂的 UA3F 使用教程&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;⚠️关于 IPID 的检测：现代网络设备 IPID 已经不再递增，因此不再需要修改 IPID。&lt;/p&gt;
&lt;h1 id=&#34;前言&#34;&gt;前言&lt;/h1&gt;
&lt;p&gt;关于本校的校园网，相信大家都知道是禁止单一账号下多设备同时访问互联网的，具体表现为 1 个账号只能同时让 1 台有线设备和 1 台无线设备接入互联网，这给我们一些拥有多设备的同学带来了很大的不便，因此不少同学想到了使用家用路由器的方式来解决这个为问题，然而校园网会进行共享上网检测，一旦发现一个 IP 下有多个不同设备的流量，就会封禁账号 2-8 小时不等，害的同学们怨声载道。&lt;/p&gt;
&lt;p&gt;然而奇怪的是本校内竟无应对此检测的方案，俗话说得好，道高一尺魔高一丈，肯定是有办法解决这个问题的。 因此本人出于学术兴趣，针对本校校园网共享上网检测机制进行了研究分析，并针对该机制提出了一些解决方案。&lt;/p&gt;
&lt;h1 id=&#34;对于本校校园网网络环境的说明&#34;&gt;对于本校校园网网络环境的说明&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;校园网网络硬件设备：锐捷三层交换机（目前已知）&lt;/li&gt;
&lt;li&gt;校园网认证系统：Drcom Web Portal 认证&lt;/li&gt;
&lt;li&gt;校园网网络防火墙安全方案：深信服&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;为什么本校要禁止多设备共享上网&#34;&gt;为什么本校要禁止多设备共享上网？&lt;/h1&gt;
&lt;p&gt;对于家用的上网资费，平均一年就要数百甚至上千元人民币，而校园网的资费一般都很低，如果一个宿舍只用一个账号一个路由器就可以实现全员上网的话，那 ISP 肯定要亏死，因此肯定会封禁像路由器这种设备的。&lt;/p&gt;
&lt;h1 id=&#34;本校校园网共享上网检测机制的研究&#34;&gt;本校校园网共享上网检测机制的研究&lt;/h1&gt;
&lt;p&gt;目前已知的（可能）存在的有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;基于 IPv4 数据包包头内的 TTL 字段的检测&lt;/li&gt;
&lt;li&gt;基于 HTTP 数据包请求头内的 User-Agent 字段的检测&lt;/li&gt;
&lt;li&gt;DPI (Deep Packet Inspection) 深度包检测技术&lt;/li&gt;
&lt;li&gt;基于 IPv4 数据包包头内的 Identification 字段的检测&lt;/li&gt;
&lt;li&gt;基于网络协议栈时钟偏移的检测技术&lt;/li&gt;
&lt;li&gt;Flash Cookie 检测技术&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;下面我会对这些技术的实现原理作出进一步说明。&lt;/p&gt;
&lt;h2 id=&#34;基于-ipv4-数据包包头内的-ttl-字段的检测&#34;&gt;基于 IPv4 数据包包头内的 TTL 字段的检测&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;存活时间（Time To Live，TTL），指一个数据包在经过一个路由器时，可传递的最长距离（跃点数）。 每当数据包经过一个路由器时，其存活次数就会被减一。当其存活次数为0时，路由器便会取消该数据包转发，IP网络的话，会向原数据包的发出者发送一个ICMP TTL数据包以告知跃点数超限。其设计目的是防止数据包因不正确的路由表等原因造成的无限循环而无法送达及耗尽网络资源。&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;这是一个比较有效且合理的检测技术，IPv4数据包下存在 TTL（Time To Live）这一字段，数据包每经过一个路由器（即经过一个网段），该TTL值就会减一。&lt;/p&gt;
&lt;p&gt;不同的操作系统的默认 TTL 值是不同的，Windows 是 128， macOS/iOS、Linux 是 64。&lt;/p&gt;
&lt;p&gt;因此如果我们自己接入路由器到校园网，我们的通过路由器的数据包会变为 127 或 63，一旦校园网抓包检测到这种数据包TTL不是128或64，就会判定为用户接入了路由器。&lt;/p&gt;
&lt;h2 id=&#34;基于-http-数据包请求头内的-user-agent-字段的检测&#34;&gt;基于 HTTP 数据包请求头内的 User-Agent 字段的检测&lt;/h2&gt;
&lt;p&gt;HTTP 数据包请求头存在一个叫做 User-Agent 的字段，该字段通常能够标识出操作系统类型，例如：&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.72 Safari/537.36 Edg/89.0.774.45
Mozilla/5.0 (iPad; U; CPU OS 3_2_1 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Mobile/7B405
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;校园网会通过多次抓包检测此字段，若发现同时出现例如Windows NT 10.0 iPad 的字段，则判定存在多设备上网。&lt;/p&gt;
&lt;h2 id=&#34;dpi-deep-packet-inspection-深度包检测技术&#34;&gt;DPI (Deep Packet Inspection) 深度包检测技术&lt;/h2&gt;
&lt;p&gt;这个检测方案比较先进，检测系统会抓包分析应用层的流量，根据不同应用程序的数据包的特征值来判断出是否存在多设备上网。&lt;/p&gt;
&lt;p&gt;具体可参考：&lt;a href=&#34;https://patents.google.com/patent/CN106411644A/zh&#34;&gt;基于 DPI 技术的网络共享设备检测方法及系统&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;此种方式已确认在锐捷相关设备上应用，当由于此项功能极耗费性能，因此有些学校可能不会开启此项功能。&lt;/p&gt;
&lt;h2 id=&#34;基于-ipv4-数据包包头内的-identification-字段的检测&#34;&gt;基于 IPv4 数据包包头内的 Identification 字段的检测&lt;/h2&gt;
&lt;p&gt;IP 报文首部存在一个叫做 Identification 的字段，此字段用来唯一标识一个 IP 报文，在实际的应用中通常把它当做一个计数器，一台主机依次发送的IP数据包内的 Identification 字段会对应的依次递增，同一时间段内，而不同设备的 Identification 字段的递增区间一般是不同的，因此校园网可以根据一段时间内递增区间的不同判断出是否存在多设备共享上网。
具体可以参考此专利：&lt;a href=&#34;https://patents.google.com/patent/CN104836700A/zh&#34;&gt;基于 IPID 和概率统计模型的 NAT 主机个数检测方法&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;不过经过我的抓包分析，Windows 的 TCP/IP 协议栈对 Identification 字段的实现是递增，而 iOS 的实现是保持全 0，因此校园网是否使用了该检测机制有待商榷。&lt;/p&gt;
&lt;h2 id=&#34;基于网络协议栈时钟偏移的检测技术&#34;&gt;基于网络协议栈时钟偏移的检测技术&lt;/h2&gt;
&lt;p&gt;不同主机物理时钟偏移不同，网络协议栈时钟与物理时钟存在对应关系，不同主机发送报文频率与时钟存在统计对应关系，通过特定的频谱分析算法，发现不同的网络时钟偏移来确定不同主机。&lt;/p&gt;
&lt;p&gt;具体可以参考此专利：&lt;a href=&#34;https://patents.google.com/patent/CN111970173A/zh&#34;&gt;一种基于时钟偏移的加密流量共享检测方法与装置&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;此种方式具有一定的实验性，因此我不认为此种方式投入了商用。&lt;/p&gt;
&lt;h2 id=&#34;flash-cookie-检测技术&#34;&gt;Flash Cookie 检测技术&lt;/h2&gt;
&lt;p&gt;该技术已经用不到了，Flash 都凉了&amp;hellip; 不过还是提一下。
Flash Cookie 会记录用户在访问 Flash 网页的时候保留的信息，只要当用户打开浏览器去上网，那么就能被 AC 记录到 Flash Cookie 的特征值，由于 Flash Cookie 不容易被清除，而且具有针对每个用户具有唯一，并且支持跨浏览器，所以被用于做防共享检测。&lt;/p&gt;
&lt;p&gt;具体参考：&lt;a href=&#34;https://bbs.sangfor.com.cn/plugin.php?id=sangfor_databases:index&amp;amp;mod=viewdatabase&amp;amp;tid=6273&#34;&gt;深信服防共享测试指导书&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&#34;防共享上网检测的解决方案&#34;&gt;防共享上网检测的解决方案&lt;/h1&gt;
&lt;p&gt;对于校园网重重的检测，我们似乎已经不可能从终端级提出一个完美的解决方案，因此，下面的解决方案都是基于网关级的。简单来说，我们需要在路由器上动手脚。&lt;/p&gt;
&lt;p&gt;路由器固件我们选择 OpenWrt，这是一个开源的路由器系统，允许我们自定义其系统内核以及添加自定义插件。&lt;/p&gt;
&lt;h2 id=&#34;针对基于-ipv4-数据包包头内的-ttl-字段的检测的解决方案&#34;&gt;针对基于 IPv4 数据包包头内的 TTL 字段的检测的解决方案&lt;/h2&gt;
&lt;p&gt;应对思路很简单：修改 TTL 为固定值。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 在 OpenWrt 上安装必要的软件包&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;opkg update &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; opkg install iptables-mod-ipopt kmod-ipt-ipopt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 加入以下防火墙规则&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;iptables -t mangle -A POSTROUTING -j TTL --ttl-set &lt;span style=&#34;color:#ae81ff&#34;&gt;64&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;针对基于-http-数据包请求头内的-user-agent-字段的检测的解决方案&#34;&gt;针对基于 HTTP 数据包请求头内的 User-Agent 字段的检测的解决方案&lt;/h2&gt;
&lt;p&gt;应对思路：统一所有终端的 User-Agent 这一点实现起来有点困难，目前有四种解决方案。&lt;/p&gt;
&lt;h3 id=&#34;方案一通过-privoxy-修改-user-agent此方案不再建议使用&#34;&gt;&lt;del&gt;方案一：通过 Privoxy 修改 User-Agent&lt;/del&gt;（此方案不再建议使用）&lt;/h3&gt;
&lt;p&gt;&lt;del&gt;这个方案存在一个很大的缺点就是性能太差，会极大的拖慢我们的带宽，但也是最简单的方案。&lt;/del&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 安装 Privoxy 软件包&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;opkg update
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;opkg install privoxy luci-app-privoxy luci-i18n-privoxy-zh-cn
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;del&gt;进入 Privoxy 管理页面设置，进入文件与目录，Action Files 中只保留 match-all.action，Filter Files 与 Trust Files 留空；进入访问控制，Listen Address 填写 0.0.0.0:8118，Permit Address 填写 192.168.0.0/16，勾选 Enable Action File Editor；进入杂项，勾选 Accept Intercepted Requests；进入日志，取消全部选项；点击保存并应用；进入 OpenWRT 防火墙设置，在自定义设置中填入以下内容：&lt;/del&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 将局域网内的 HTTP 请求转发到 Privoxy 代理服务器上&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;iptables -t nat -N http_ua_drop
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;iptables -t nat -I PREROUTING -p tcp --dport &lt;span style=&#34;color:#ae81ff&#34;&gt;80&lt;/span&gt; -j http_ua_drop
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;iptables -t nat -A http_ua_drop -m mark --mark 1/1 -j RETURN
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;iptables -t nat -A http_ua_drop -d 0.0.0.0/8 -j RETURN
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;iptables -t nat -A http_ua_drop -d 127.0.0.0/8 -j RETURN
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;iptables -t nat -A http_ua_drop -d 192.168.0.0/16 -j RETURN
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;iptables -t nat -A http_ua_drop -p tcp -j REDIRECT --to-port &lt;span style=&#34;color:#ae81ff&#34;&gt;8118&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;del&gt;打开 &lt;code&gt;http://config.privoxy.org/edit-actions-list?f=0&lt;/code&gt;；点击 Edit，在 Action 那一列中，hide-user-agent 改选为 Enable - 在右侧 User Agent string to send 框中填写 &lt;code&gt;Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36&lt;/code&gt;，其它全部选择为 No Change；点击 Submit。&lt;/del&gt;&lt;/p&gt;
&lt;h3 id=&#34;方案二使用-xmurp-ua-修改-ua&#34;&gt;方案二：使用 XMURP-UA 修改 UA&lt;/h3&gt;
&lt;p&gt;这个方案需要手动交叉编译 OpenWrt，有能力的同学可以尝试。&lt;/p&gt;
&lt;p&gt;优点：这是个内核模块，因此性能不错&lt;/p&gt;
&lt;p&gt;缺点：因为是内核模块，因此稳定性欠佳，此外这个模块只能修改 80 端口的数据包，因此有些非 80 端口的数据包是修改不了的。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git clone https://github.com/CHN-beta/xmurp-ua.git package/xmurp-ua
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;make menuconfig
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 在 Kernel module -&amp;gt; Other modules 里勾选 kmod-xmurp-ua（按 y）。保存退出。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 正常编译镜像，镜像中就会包含插件了。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果要单独编译此模块，需运行：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;make package/xmurp-ua/compile V&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;sc
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd /tmp
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pkg install 改成对应的xmurp-ua文件名.ipk
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 安装压缩内存插件&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;opkg update
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;opkg install zram-swap
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 检测这两个插件是否均已安装成功&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;opkg list-installed | grep zram-swap
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;opkg list-installed | grep xmurp-ua
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 重启路由器&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;reboot
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;方案三使用-ua2f-修改-ua&#34;&gt;方案三：使用 UA2F 修改 UA&lt;/h3&gt;
&lt;p&gt;UA2F 可以修改所有端口的数据包，而且性能不错，不过依旧需要编译。 具体参见：&lt;a href=&#34;https://github.com/Zxilly/UA2F&#34;&gt;Zxilly/UA2F&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;验证方式：&lt;a href=&#34;http://ua.233996.xyz/&#34;&gt;UA 检测-HTTP&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;方案四ua3f&#34;&gt;方案四：UA3F&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;https://blog.sunbk201.site/posts/ua3f/&#34;&gt;校园网防检测: UA3F - 新一代 UA 修改方法&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/SunBK201/UA3F&#34;&gt;UA3F Github&lt;/a&gt;&lt;/p&gt;
&lt;table&gt;
  &lt;tr&gt;
    &lt;td&gt;&lt;img src=&#34;https://sunbk201.oss-cn-beijing.aliyuncs.com/img/ua3f-luci&#34; alt=&#34;Left Image&#34;&gt;&lt;/td&gt;
    &lt;td&gt;&lt;img src=&#34;https://sunbk201.oss-cn-beijing.aliyuncs.com/img/ua3f-statistics&#34; alt=&#34;Right Image&#34;&gt;&lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;&lt;img src=&#34;https://sunbk201.oss-cn-beijing.aliyuncs.com/img/ua3f&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;h3 id=&#34;方案五使用代理客户端中的重写功能对-http-header-进行修改&#34;&gt;方案五：使用代理客户端中的重写功能对 http-header 进行修改&lt;/h3&gt;
&lt;p&gt;这应该是最容易操作的方法，也可能是有效的方法。&lt;/p&gt;
&lt;p&gt;以 Quantumult X 为例，只需在重写规则里面加入一条：&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;http:// url request-header (\r\n)User-[A|a]gent:.+(\r\n) request-header $1User-Agent: $2
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;iOS 客户端 Quantumult X、Shadowrocket、Surge 等都支持重写功能。&lt;/p&gt;
&lt;p&gt;Android 的客户端可以使用 surfboard（或许现在不支持了）。&lt;/p&gt;
&lt;p&gt;macOS 可以使用 Surge。&lt;/p&gt;
&lt;p&gt;Clash 用户要失望了，Clash 不支持 URL 重写，不过可以使用 Clash 走规则匹配，把 HTTP 流量全都加密。&lt;/p&gt;
&lt;p&gt;如果不想在自己的客户端上长时间开启代理，可以在 OpenWrt 中使用 OpenClash/ShellClash 进行网关级修改。&lt;/p&gt;
&lt;h2 id=&#34;针对基于-ipv4-数据包包头内的-identification-字段的检测的解决方案&#34;&gt;针对基于 IPv4 数据包包头内的 Identification 字段的检测的解决方案&lt;/h2&gt;
&lt;p&gt;应对思路：修改所有数据包的 ID 字段为递增。&lt;/p&gt;
&lt;p&gt;我们使用 &lt;a href=&#34;https://github.com/CHN-beta/rkp-ipid&#34;&gt;rkp-ipid&lt;/a&gt; 这一内核模块进行修改。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git clone https://github.com/CHN-beta/rkp-ipid.git package/rkp-ipid
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;make package/rkp-ipid/compile V&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;sc
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;# 设置所有发出的数据包的 IPID 为递增
iptables -t mangle -N IPID_MOD
iptables -t mangle -A FORWARD -j IPID_MOD
iptables -t mangle -A OUTPUT -j IPID_MOD
iptables -t mangle -A IPID_MOD -d 0.0.0.0/8 -j RETURN
iptables -t mangle -A IPID_MOD -d 127.0.0.0/8 -j RETURN
# iptables -t mangle -A IPID_MOD -d 10.0.0.0/8 -j RETURN
iptables -t mangle -A IPID_MOD -d 172.16.0.0/12 -j RETURN
iptables -t mangle -A IPID_MOD -d 192.168.0.0/16 -j RETURN
iptables -t mangle -A IPID_MOD -d 255.0.0.0/8 -j RETURN
iptables -t mangle -A IPID_MOD -j MARK --set-xmark 0x10/0x10
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;针对基于网络协议栈时钟偏移的检测技术的解决方案&#34;&gt;针对基于网络协议栈时钟偏移的检测技术的解决方案&lt;/h2&gt;
&lt;p&gt;应对思路：在局域网中建立 NTP 服务器统一时间戳&lt;/p&gt;
&lt;p&gt;进入 OpenWrt 系统设置, 勾选 Enable NTP client（启用 NTP 客户端）和 Provide NTP server（作为 NTP 服务器提供服务）&lt;/p&gt;
&lt;p&gt;NTP server candidates（候选 NTP 服务器）四个框框分别填写:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;ntp1.aliyun.com, time1.cloud.tencent.com, stdtime.gov.hk, pool.ntp.org
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;进入 OpenWrt 防火墙设置，在 自定义设置 中填入以下内容:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;# 防时钟偏移检测
iptables -t nat -N ntp_force_local
iptables -t nat -I PREROUTING -p udp --dport 123 -j ntp_force_local
iptables -t nat -A ntp_force_local -d 0.0.0.0/8 -j RETURN
iptables -t nat -A ntp_force_local -d 127.0.0.0/8 -j RETURN
iptables -t nat -A ntp_force_local -d 192.168.0.0/16 -j RETURN
iptables -t nat -A ntp_force_local -s 192.168.0.0/16 -j DNAT --to-destination 192.168.1.1
# 最后的 192.168.1.1 需要修改为路由器网关地址
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;确认效果：在 Windows 电脑上，打开控制面板，在右上角查看方式处选择小图标，然后点击“日期和时间”。点击 Internet 时间 -&amp;gt; 更改设置，点几次“立即更新”，直到提示“时钟在 xxx 与 xxx 同步成功”。这时，暂时地拔掉墙上接口与路由器之间的网线（断开了外网的连接），再点一次“立即更新”，应该仍然提示成功，这说明 NTP 请求已经被劫持到了路由器自身而不是外网。然后把网线插回。&lt;/p&gt;
&lt;h2 id=&#34;针对-flash-cookie-检测技术的解决方案&#34;&gt;针对 Flash Cookie 检测技术的解决方案&lt;/h2&gt;
&lt;p&gt;应对思路：iptables 拒绝 AC 进行 Flash 检测&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;# iptables 拒绝 AC 进行 Flash 检测
iptables -I FORWARD -p tcp --sport 80 --tcp-flags ACK ACK -m string --algo bm --string &amp;#34; src=\&amp;#34;http://1.1.1.&amp;#34; -j DROP
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;针对-dpi-deep-packet-inspection-深度包检测技术的解决方案&#34;&gt;针对 DPI (Deep Packet Inspection) 深度包检测技术的解决方案&lt;/h2&gt;
&lt;p&gt;应对思路：加密数据包。&lt;/p&gt;
&lt;p&gt;我们无法通过修改数据包来防止 DPI 检测，因此加密是最好的手段。&lt;/p&gt;
&lt;h1 id=&#34;最后&#34;&gt;最后&lt;/h1&gt;
&lt;p&gt;对于认为修改 UA IPID 太过麻烦的同学，可以直接对自己的流量进行全加密，前提是你的有充足的解密代理服务器&lt;/p&gt;
&lt;p&gt;下面我给出最终全部的配置脚本：&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;# @SunBK201 - https://blog.sunbk201.site
iptables -t nat -A PREROUTING -p udp --dport 53 -j REDIRECT --to-ports 53
iptables -t nat -A PREROUTING -p tcp --dport 53 -j REDIRECT --to-ports 53

# 通过 rkp-ipid 设置 IPID
iptables -t mangle -N IPID_MOD
iptables -t mangle -A FORWARD -j IPID_MOD
iptables -t mangle -A OUTPUT -j IPID_MOD
iptables -t mangle -A IPID_MOD -d 0.0.0.0/8 -j RETURN
iptables -t mangle -A IPID_MOD -d 127.0.0.0/8 -j RETURN
# 由于本校局域网是A类网，所以我将这一条注释掉了，具体要不要注释结合你所在的校园网
# iptables -t mangle -A IPID_MOD -d 10.0.0.0/8 -j RETURN
iptables -t mangle -A IPID_MOD -d 172.16.0.0/12 -j RETURN
iptables -t mangle -A IPID_MOD -d 192.168.0.0/16 -j RETURN
iptables -t mangle -A IPID_MOD -d 255.0.0.0/8 -j RETURN
iptables -t mangle -A IPID_MOD -j MARK --set-xmark 0x10/0x10

# ua2f 改UA
iptables -t mangle -N ua2f
# 由于本校局域网是A类网，所以我将这一条注释掉了，具体要不要注释结合你所在的校园网
# iptables -t mangle -A ua2f -d 10.0.0.0/8 -j RETURN
iptables -t mangle -A ua2f -d 127.0.0.0/8 -j RETURN
iptables -t mangle -A ua2f -d 192.168.0.0/16 -j RETURN # 不处理流向保留地址的包
iptables -t mangle -A ua2f -p tcp --dport 443 -j RETURN # 不处理 https
iptables -t mangle -A ua2f -p tcp --dport 22 -j RETURN # 不处理 SSH 
iptables -t mangle -A ua2f -p tcp --dport 80 -j CONNMARK --set-mark 44
iptables -t mangle -A ua2f -m connmark --mark 43 -j RETURN # 不处理标记为非 http 的流 (实验性)
iptables -t mangle -A ua2f -m set --set nohttp dst,dst -j RETURN
iptables -t mangle -A ua2f -j NFQUEUE --queue-num 10010
  
iptables -t mangle -A FORWARD -p tcp -m conntrack --ctdir ORIGINAL -j ua2f
iptables -t mangle -A FORWARD -p tcp -m conntrack --ctdir REPLY


# 防时钟偏移检测
iptables -t nat -N ntp_force_local
iptables -t nat -I PREROUTING -p udp --dport 123 -j ntp_force_local
iptables -t nat -A ntp_force_local -d 0.0.0.0/8 -j RETURN
iptables -t nat -A ntp_force_local -d 127.0.0.0/8 -j RETURN
iptables -t nat -A ntp_force_local -d 192.168.0.0/16 -j RETURN
iptables -t nat -A ntp_force_local -s 192.168.0.0/16 -j DNAT --to-destination 192.168.1.1

# 通过 iptables 修改 TTL 值
iptables -t mangle -A POSTROUTING -j TTL --ttl-set 64

# iptables 拒绝 AC 进行 Flash 检测
iptables -I FORWARD -p tcp --sport 80 --tcp-flags ACK ACK -m string --algo bm --string &amp;#34; src=\&amp;#34;http://1.1.1.&amp;#34; -j DROP  
&lt;/code&gt;&lt;/pre&gt;&lt;h1 id=&#34;对于防检测方案的可用性分析验证&#34;&gt;对于防检测方案的可用性分析验证&lt;/h1&gt;
&lt;p&gt;为检测方案的可用性，我进行了抓包分析。&lt;/p&gt;
&lt;p&gt;实验环境为：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;一台路由器（模拟校园网提供接入互联网服务）（192.168.5.1）&lt;/li&gt;
&lt;li&gt;一台抓包服务器(192.168.5.219)(模拟检测系统)，提供web访问服务，以供客户机访问。&lt;/li&gt;
&lt;li&gt;一台路由器（模拟我们自己接入校园网的路由器）（192.168.5.190）&lt;/li&gt;
&lt;li&gt;两台客户机：一台Win10（192.168.1.10）一台iOS（192.168.1.20）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;两台客户机同时访问抓包服务器(192.168.5.219)进行抓包分析。&lt;/p&gt;
&lt;h2 id=&#34;部署防检测方案前&#34;&gt;部署防检测方案前&lt;/h2&gt;
&lt;p&gt;TTL: 127 / 63&lt;/p&gt;
&lt;p&gt;IPID: 64764-64779 / 0-0&lt;/p&gt;
&lt;p&gt;UA: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.72 Safari/537.36 Edg/89.0.774.45&lt;/p&gt;
&lt;p&gt;Mozilla/5.0 (iPad; U; CPU OS 3_2_1 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Mobile/7B405&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://sunbk201.oss-cn-beijing.aliyuncs.com/img/20210614011914.png&#34; alt=&#34;&#34;&gt;
&lt;img src=&#34;https://sunbk201.oss-cn-beijing.aliyuncs.com/img/20210614012122.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;部署防检测方案后&#34;&gt;部署防检测方案后&lt;/h2&gt;
&lt;p&gt;TTL: 64 / 64&lt;/p&gt;
&lt;p&gt;IPID: 2319-2504&lt;/p&gt;
&lt;p&gt;UA: FFFFFFFFFFFFFFFFFFFFFFFFFFFF&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://sunbk201.oss-cn-beijing.aliyuncs.com/img/20210614011948.png&#34; alt=&#34;&#34;&gt;
&lt;img src=&#34;https://sunbk201.oss-cn-beijing.aliyuncs.com/img/20210614012220.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;最终结论防共享检测有效&#34;&gt;最终结论：防共享检测有效！&lt;/h2&gt;
&lt;h1 id=&#34;实际使用&#34;&gt;实际使用&lt;/h1&gt;
&lt;p&gt;我已经使用此方案一周之久，这一周内没有过发生一次封禁，可以肯定，此解决方案实际使用是有效的！&lt;/p&gt;
&lt;h1 id=&#34;写在最后&#34;&gt;写在最后&lt;/h1&gt;
&lt;p&gt;我在写这篇文章的时候已经大三了，其实早在我大一的时候就有过一段时间来试图解决这个问题，但是当时能力还不够，无法拿出完整的解决方案，现在能力够了，但是也快毕业了，说实话现在再使用这些防检测方案已经有些晚了，不过，我相信这些解决方案可以对我们以后一些大一大二的同学有所帮助，我所做的一些工作也是值得的。&lt;/p&gt;
&lt;p&gt;具体操作见：&lt;a href=&#34;https://www.notion.so/OpenWrt-f59ae1a76741486092c27bc24dbadc59&#34;&gt;OpenWrt 编译与防检测部署教程&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;如果大家有疑问可以加讨论组： &lt;a href=&#34;https://t.me/crack_campus_network&#34;&gt;Telegram&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;最后，感谢开发 OpenWrt 防检测模块的作者们 &lt;a href=&#34;https://github.com/Zxilly&#34;&gt;Zxilly&lt;/a&gt;、 &lt;a href=&#34;https://github.com/CHN-beta&#34;&gt;CHN-beta&lt;/a&gt; ，是有了他们的无私奉献，才使我能够整理出这么一份解决方案。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>hello, world</title>
      <link>http://blog.sunbk201.site/posts/hello-world/</link>
      <pubDate>Sun, 01 Mar 2020 00:00:00 +0000</pubDate>
      
      <guid>http://blog.sunbk201.site/posts/hello-world/</guid>
      <description>&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;hello, world&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    
  </channel>
</rss>