《隱形兵器 III：代碼的宿命》| Autonomous Vulnerability Discovery, Memory Safety & Adversarial Self-Play | IDRI

# 《隱形兵器》

## 紅隊三部曲・下篇：代碼的宿命

### ——當機器學會尋找漏洞，人類留下的錯誤開始反過來尋找人類

---

# 01｜05:42

凌晨 05:42。

紅隊基地。

整座機房沒有一盞燈是為了照亮人。

冷白色的指示燈一排排閃爍。

GPU node 的風扇維持在高轉速。

液冷系統持續吞吐熱量。

空氣裡有一種很奇怪的味道。

金屬。

灰塵。

塑膠。

還有電子設備長時間滿載後，那種近乎沒有溫度的焦躁。

---

林祈安站在玻璃牆前。

她看著牆另一邊的機櫃。

「全部上線？」

程遠回答：

「全部。」

「Fuzzer？」

「上線。」

「Symbolic engine？」

「上線。」

「Crash triage？」

「上線。」

「Model-based scheduler？」

「已經開始跑。」

---

Richard坐在後面。

沒有說話。

---

周野把最後一個 terminal 關掉。

「現在這東西。」

他說。

「已經不是工具了。」

林祈安回頭。

「那是什麼？」

周野看著機房。

> 「是一個不會累的工程師。」

---

Richard終於笑了。

「不。」

他說。

> **「工程師至少知道什麼時候該回家。」**

---

# 02｜Self-Play

第二代攻防平台正式啟動。

它不再依賴人類一次次提出假設。

而是讓兩組模型互相產生問題。

---

```text id="9d8j4v"
Attack Policy
     ↓
Candidate State
     ↓
Simulation
     ↓
Observation
     ↓
Defensive Response
     ↓
Reward / Penalty
     ↓
Policy Update
     ↺
```

---

紅隊不再單純問：

> 「哪裡有漏洞？」

而是：

> 「在目前防禦策略下，哪一類狀態最值得探索？」

藍隊也不再單純問：

> 「怎麼修？」

而是：

> 「哪一種修補會迫使攻擊策略改變？」

---

這已經不是傳統的：

`Red vs Blue`

而是：

**Policy vs Policy。**

---

林祈安看著第一輪結果。

「開始收斂。」

Richard問：

「太快？」

「有點。」

「為什麼？」

她指向螢幕。

「雙方策略開始互相適應。」

---

周野淡淡說：

「兩個人下棋。」

林祈安搖頭。

「不是。」

「兩個模型。」

---

Richard補了一句：

> 「兩個不知道自己為什麼下棋的模型。」

---

# 03｜速度

第一輪：

`17.4 ms`

第二輪：

`9.8 ms`

第三輪：

`3.2 ms`

然後：

`1.1 ms`

---

程遠看著 dashboard。

「還能快。」

Richard問：

「為什麼要快？」

「因為越快，探索空間越大。」

「然後？」

「找到更多 candidate。」

「然後？」

程遠停住。

Richard看著他。

> 「最後得到更多你不知道自己為什麼相信的東西。」

---

程遠沒有回答。

---

林祈安卻在另一邊看著數據。

她知道Richard擔心什麼。

速度會讓模型產生一個危險幻覺：

**只要計算量足夠大，就能消除未知。**

---

但她也知道。

這個幻覺很難阻止。

因為數字真的很好看。

---

# 04｜Blue Side

顧青禾也看到同樣的變化。

ASTER-X 的 telemetry pipeline 開始出現前所未有的壓力。

不是流量突然暴增。

而是：

**行為變化速度。**

---

過去。

攻擊者可能一天調整一次策略。

現在：

幾秒。

甚至更短。

---

模型剛適應一個 behavior。

下一輪 behavior 已經變了。

---

工程師問：

「我們提高 retraining frequency？」

顧青禾搖頭。

「不要。」

「為什麼？」

> 「如果我們讓模型跟著每一次變化跑。」

> 「它會開始學習噪音。」

---

她看著那條快速震盪的曲線。

---

「我們現在遇到的問題不是 drift。」

「是 velocity。」

---

# 05｜Velocity

她把兩個詞寫在白板上。

```text id="3q6x5k"
Drift
```

下面：

```text id="x4c9s1"
Velocity
```

---

「Drift 是方向。」

她說。

「Velocity 是變化速度。」

「當速度高到超過 observation window。」

她停了一下。

> **「你甚至還沒看懂上一個狀態，下一個狀態已經死了。」**

---

這是第三篇真正的戰場。

---

不是：

**誰比較準。**

而是：

**誰能在更短時間裡完成一次完整的 observe → decide → act → adapt。**

---

# 06｜Fuzzing Engine

紅隊的漏洞研究引擎開始工作。

它沒有一個漂亮的名字。

只有：

`FUSE`

Fuzzing and Unified Search Engine。

---

它可以從：

* program state
* execution trace
* crash signature
* memory state
* input grammar
* historical vulnerability pattern

建立候選搜尋空間。

---

然後反覆探索。

---

第一次。

沒有結果。

第二次。

沒有結果。

第一萬次。

沒有結果。

第一億次。

---

`Interesting State Detected`

---

程遠站起來。

「找到了？」

周野走過來。

「還不知道。」

---

他看著 crash report。

不是典型 crash。

沒有立即的 segmentation fault。

只有：

**state inconsistency。**

---

周野的表情第一次變了。

---

# 07｜Rust

周野的代號：

`Rust`

這個名字其實不是因為他喜歡 Rust 語言。

而是因為他曾經說：

> 「所有系統最後都會生鏽。」

---

他看著 execution trace。

一次。

兩次。

十次。

---

「不是一般 memory corruption。」

林祈安問：

「那是什麼？」

「生命週期問題。」

「Memory lifetime？」

「嗯。」

---

他把幾個 state 疊在一起。

```text id="5q6p3e"
Allocate
   ↓
Use
   ↓
Release
   ↓
Unexpected Reference
```

---

林祈安看著它。

「UAF？」

周野沒有立即回答。

---

他又跑了一次。

---

同樣的 state。

同樣的錯誤。

---

他才說：

> 「可能。」

---

Richard站在後面。

「可能就夠了。」

周野回頭。

「不。」

「為什麼？」

> 「因為 memory safety 不能靠直覺。」

---

Richard點頭。

「很好。」

---

# 08｜Three Years Ago

另一條時間線。

三年前。

凌晨 02:43。

那個年輕工程師還坐在電腦前。

---

他正在修一個完全不同的問題。

Pipeline。

不是 security。

不是 exploit。

甚至不是 production incident。

只是：

**某個舊元件的相容性。**

---

他看到一個 cleanup path。

知道它很醜。

知道它不理想。

但 deadline 在後面。

---

他寫了一個 workaround。

註解：

`temporary`

---

然後 commit。

---

`Approved.`

---

沒有人知道。

這個 commit 從此活了三年。

---

# 09｜現在

周野重新看著那個 crash state。

「這東西很老。」

Richard問：

「多久？」

「不知道。」

「估。」

「三年以上。」

---

房間安靜。

---

林祈安看向Richard。

她忽然想起第二篇。

`legacy-ingest`

`temporary workaround`

---

「就是它？」

Richard沒有回答。

---

周野卻說：

「不是同一個 bug。」

他停了一下。

> 「但可能是同一種人留下的東西。」

---

# 10｜人類的漏洞

林祈安皺眉。

「什麼意思？」

周野回答：

> 「不是 coding error。」

> 「是 decision error。」

---

他指著那段歷史。

「當時的人知道這裡不漂亮。」

「但風險不夠高。」

「所以 postponed。」

---

Richard接著說：

「然後下一個人看到。」

「以為前一個人已經處理。」

周野點頭。

「再下一個人。」

「看到 test 都是綠的。」

---

最後：

**沒有人真的擁有它。**

---

Richard說：

> 「這就是 legacy 最危險的地方。」

> 「它沒有主人。」

---

# 11｜藍隊的模型也找到了

顧青禾收到同一份 anomaly。

但她看到的是另一種證據。

---

Memory telemetry。

Process behavior。

Crash frequency。

Restart pattern。

Runtime mitigation state。

---

模型給出：

`Risk: High`

但：

`Exploitability: Uncertain`

---

顧青禾沒有直接下結論。

她問：

「原始 crash state？」

工程師把資料送過來。

---

她看了很久。

「隔離。」

---

工程師問：

「要 patch？」

「先。」

「然後？」

「建立獨立 reproduction environment。」

---

她沒有追擊。

沒有封鎖所有相關服務。

也沒有立刻重建整個模型。

---

她只做一件事：

**把未知從 production 裡拿出去。**

---

# 12｜紅隊的誘惑

紅隊看著 candidate。

程遠說：

「可以深入。」

Richard問：

「為什麼？」

「因為它可能是突破點。」

周野說：

「可能。」

---

林祈安卻突然問：

「如果它是真的呢？」

所有人看她。

「如果這個漏洞不是模型生成的。」

「而是真的存在。」

「那我們現在找到的不是 candidate。」

她停了一下。

> **「是現實。」**

---

Richard看著她。

「繼續。」

---

# 13｜The Machine

自動化搜尋引擎開始加速。

---

`10⁶`

`10⁷`

`10⁸`

---

候選 state 不斷被淘汰。

---

`Noise`

`Duplicate`

`Non-reproducible`

`Low relevance`

---

最後只剩少數。

---

其中一個：

`Persistent State Anomaly`

---

周野看了十秒。

「這個。」

林祈安問：

「確認？」

「還沒有。」

「那為什麼？」

周野回答：

> 「因為它很像一個人寫出來的 bug。」

---

Richard看向他。

「這是什麼標準？」

周野笑了一下。

> 「經驗。」

---

# 14｜Nash

雙方模型開始高速迭代。

紅隊：

`Attack Policy A`

藍隊：

`Defense Policy B`

紅隊：

`A'`

藍隊：

`B'`

---

每次更新。

收益差距縮小。

---

*`ΔU → 0`*

---

林祈安看著曲線。

「開始收斂。」

Richard問：

「到哪？」

「接近 equilibrium。」

---

周野問：

「Nash？」

「近似。」

---

Richard沉默。

---

如果兩個模型都能預測對方。

如果兩邊都可以快速適應。

如果每一次策略變更，都被對方立即修正。

---

最後：

**沒有人能取得穩定優勢。**

---

這就是模型世界裡的和平。

---

不是因為大家理解彼此。

而是：

**每一個動作都已經被對方預期。**

---

# 15｜The Human Move

Richard突然問：

「它們知道這個嗎？」

林祈安看向他。

「什麼？」

「平衡。」

「知道。」

「那如果我們不按照平衡走？」

她愣了一下。

---

Richard說：

> 「AI 只會對它認為可能的行為做最佳化。」

「所以？」

> **「真正的異常，不一定是最好的策略。」**

---

林祈安慢慢理解。

如果模型學會：

`optimal attack`

它也可能忽略：

**stupid attack。**

---

人類最擅長的東西之一。

就是做一件看起來完全不合理的事情。

---

# 16｜那個舊漏洞

周野重新跑歷史 binary analysis。

不是尋找新漏洞。

而是：

**確認舊漏洞。**

---

結果出來。

三年前的版本。

某個 lifecycle path。

某個 reference。

某個 cleanup sequence。

---

不是漂亮的 zero-day。

不是全新發現。

不是 AI 自主生成的神蹟。

---

只是：

**一個三年前留下來的 memory safety 問題。**

---

周野把結果傳給Richard。

只有一句：

> 「是真的。」

---

Richard看著那行字。

沒有笑。

---

# 17｜The Free

他走到白板。

寫下：

```text id="c2v8pf"
Object
   ↓
Reference
   ↓
Release
   ↓
Reference remains
```

然後把最後一行圈起來。

---

林祈安問：

「這就是最後一擊？」

Richard搖頭。

「不是。」

「那是什麼？」

> 「這是提醒。」

---

她不明白。

Richard說：

> 「我們一直以為最後一擊要由 AI 找到。」

> 「其實三年前就有人把它留下了。」

---

房間安靜。

---

# 18｜顧青禾知道了

藍隊收到 patch validation。

修補後：

memory state 穩定。

runtime telemetry 正常。

---

但顧青禾沒有立即關掉 anomaly。

她問：

「誰寫的？」

工程師回答：

「三年前的元件團隊。」

「現在呢？」

「團隊已經解散。」

---

顧青禾閉上眼睛。

---

又是：

**沒有主人。**

---

她突然明白。

第一篇的 `emergence`。

第二篇的 `provenance`。

第三篇的 `legacy`。

原來一直是同一個問題。

---

不是漏洞。

而是：

**責任的時間跨度。**

---

# 19｜最後的對話

紅隊。

林祈安問：

「如果 AI 可以找到所有漏洞。」

「我們還需要人嗎？」

Richard沒有立即回答。

---

他走到窗前。

城市已經開始亮。

早餐店開門。

公車開始行駛。

一個送貨員把箱子搬下車。

沒有人知道。

幾百公里外。

兩套機器剛剛完成了一場數十億次狀態探索。

---

Richard說：

> 「需要。」

「為什麼？」

> 「因為 AI 找得到漏洞。」

「然後？」

> 「但它不知道哪一個漏洞，是人類應該負責的。」

---

林祈安沉默。

---

Richard繼續：

> 「你可以讓模型理解 code。」

> 「可以讓它理解 exploitability。」

> 「甚至可以讓它理解對手。」

---

他轉身。

> **「但你很難讓它理解，為什麼三年前那個人會選擇先回家。」**

---

# 20｜顧青禾

顧青禾站在同一片晨光裡。

她手上拿著修補完成的報告。

最後一欄：

`Root Cause`

不是：

`Memory Error`

不是：

`Unsafe Reference`

---

她要求工程師重新寫。

最後報告變成：

> **「未被持續擁有的工程決策，經過時間累積後形成安全風險。」**

---

她簽名。

---

然後把報告歸檔。

檔名：

`legacy_decision_001`

---

這一次。

她沒有把它分類成：

`Incident`

而是：

**Institutional Memory。**

---

# 21｜Equilibrium

紅隊模型停止。

藍隊模型停止。

---

雙方的策略曲線最後重疊。

---

*`ΔU ≈ 0`*

---

林祈安看著螢幕。

「Nash equilibrium。」

周野說：

「看起來。」

Richard卻搖頭。

「不是。」

---

兩人看向他。

---

他指著另一條線。

---

`Human Decision`

---

那條線從頭到尾都沒有收斂。

---

Richard說：

> **「因為人不是模型。」**

---

# 22｜最後一個 Bug

故事回到三年前。

那個年輕工程師終於完成工作。

凌晨 03:12。

他關掉 terminal。

看著最後一個 commit。

---

`temporary workaround`

---

他猶豫了一下。

想改掉。

但手機響了。

家人問：

「你什麼時候回來？」

他看了一眼時間。

03:13。

---

他說：

「現在。」

---

然後關機。

---

那段 code 留了下來。

---

不是因為他笨。

不是因為他不負責。

甚至不是因為公司不重視安全。

---

只是因為：

**那天晚上，他也是一個人。**

---

# 23｜The Last State

多年後。

沒有人知道他的名字。

沒有人記得那個 commit。

沒有人會在 incident report 裡寫：

> 「因為某個工程師凌晨三點想回家。」

---

但所有模型。

所有 fuzzers。

所有 detection engine。

所有 threat intelligence。

所有 automated defense。

最後都在處理：

**那個選擇留下來的結果。**

---

這就是代碼的宿命。

---

Code 不會記得作者。

Binary 不會理解 deadline。

Memory 不知道誰加班。

CPU 不知道誰想回家。

---

它們只會：

**執行。**

---

# 24｜黎明

早上 06:18。

紅隊基地。

Richard關掉最後一台螢幕。

林祈安問：

「結束了？」

Richard看著窗外。

「這一輪。」

「下一輪呢？」

他笑了一下。

---

「下一輪永遠會有。」

---

周野背起包。

「所以我們到底贏了沒有？」

Richard想了一下。

> 「如果你需要一個勝負。」

「嗯。」

> 「那我們沒贏。」

「藍隊呢？」

「他們也沒有。」

---

程遠問：

「那我們做了什麼？」

Richard走出門。

只留下最後一句：

> **「我們只是證明，世界沒有被算完。」**

---

# 《代碼的宿命》・完

# 《隱形兵器》紅隊三部曲・完

---

# Story Background｜終局背景

三部曲最初的戰場是：

**Network。**

然後進入：

**Model。**

最後抵達：

**Code。**

但真正的戰場，其實一路都沒有改變。

一直都是：

**Trust。**

---

三篇可以濃縮成：

```text id="t5n7xe"
第一篇
「我能不能讓你看不到我？」
        ↓
第二篇
「我能不能讓你相信錯誤的答案？」
        ↓
第三篇
「即使你看穿一切，
你能不能理解三年前為什麼有人留下這個 Bug？」
```

這才是整套三部曲真正的閉環。

---

# Technical Architecture｜終局技術架構

第三篇不再單純依賴某個 exploit。

整體架構是：

```text id="j4r8kt"
Historical Software
       ↓
Static / Dynamic Analysis
       ↓
Fuzzing
       ↓
State Exploration
       ↓
Crash / Anomaly Triage
       ↓
Exploitability Assessment
       ↓
Defensive Simulation
       ↓
Policy Adaptation
       ↺
```

攻防雙方則進入：

```text id="9u6s3c"
Red Policy
    ↕
Simulation
    ↕
Blue Policy
    ↕
Simulation
    ↺
```

最終：

*`ΔU ≈ 0`*

也就是雙方策略收益差距逐漸收斂。

但故事故意留下最後一條沒有收斂的變數：

```text id="s4x0qz"
Human Context
```

因為：

**人類不是 stationary policy。**

人會改變目標。

改變優先級。

改變價值。

改變心情。

甚至在凌晨三點決定：

> 「今天先回家。」

這些東西沒有辦法漂亮地塞進 reward function。

---

# Technical Concepts｜本篇核心技術

本篇涉及：

* Automated Fuzzing
* Coverage-Guided Exploration
* State-Space Search
* Symbolic Execution
* Crash Triage
* Memory Safety
* Use-After-Free
* Object Lifetime
* Reference Lifetime
* Runtime Mitigation
* Dynamic Analysis
* Static Analysis
* Exploitability Assessment
* Reinforcement Learning
* Self-Play
* Policy Optimization
* Reward Shaping
* Adversarial Adaptation
* Nash Equilibrium
* Model Convergence
* Automated Patch Validation
* Legacy Software Risk
* Technical Debt
* Security Debt
* Provenance
* Institutional Memory

其中最重要的一個不是 UAF。

是：

**Exploitability ≠ Existence。**

某個 memory safety issue 存在，不代表它一定能形成可靠攻擊。

反過來：

某個模型認為「沒有 exploit」，也不代表漏洞不存在。

因此紅隊與藍隊都必須區分：

```text id="g7r3hm"
Bug
 ↓
Reachability
 ↓
State Control
 ↓
Impact
 ↓
Exploitability
```

這比「找到一個 crash 就宣布 zero-day」嚴謹得多。

後者通常只是把 fuzzing report 穿上軍裝。

---

# Character Arc｜人物終局

## Richard

第一篇：

**經驗 > 自動化**

第二篇：

**理解模型**

第三篇：

**接受模型永遠無法完整理解人。**

他最後沒有成為「最強紅隊」。

反而成為一個更成熟的人：

> **知道什麼可以做，與什麼值得做，是兩個不同問題。**

---

## 林祈安

她的弧線最完整。

第一篇：

> 模型可以理解世界。

第二篇：

> 模型可能誤解世界。

第三篇：

> **模型可以探索世界，但不能替人決定世界的意義。**

她最後沒有放棄 AI。

恰恰相反。

她變得更相信 AI。

只是：

**不再崇拜 AI。**

---

## 周野

他從頭到尾都相信：

**machine state 才是真實。**

最後卻發現：

machine state 的上游，

是：

```text
Requirement
↓
Design
↓
Decision
↓
Code
↓
Binary
↓
Memory
```

所以他最後真正理解：

> **最低階的漏洞，有時候是最高階決策留下的影子。**

---

## 顧青禾

她是三部曲裡最接近「成熟」的人。

她沒有擊敗紅隊。

也沒有讓模型完美。

她只是始終拒絕把：

**Unknown**

偽裝成：

**Known。**

這讓她在第三篇保住了系統。

---

## 程遠

他的變化最微妙。

第一篇：

> 「只要 automation 能做，就不需要人。」

第二篇：

> 「模型可以替我們做判斷。」

第三篇：

他第一次問：

> 「如果機器比我們更快，我們還有什麼用？」

Richard沒有回答。

因為這個問題沒有標準答案。

---

# Final Foreshadowing｜最後留下的東西

故事結束。

但世界沒有結束。

在最後一頁。

一台紅隊分析節點重新啟動。

---

沒有攻擊任務。

沒有 C2。

沒有 exploit。

只有一個新的 repository。

名稱：

`legacy-review`

---

第一個 commit：

`human_context_required`

---

另一座城市。

顧青禾的藍隊也建立了一個新的模型。

名字：

`ASTER-Ω`

第一個 rule：

> **Never collapse uncertainty without provenance.**

---

林祈安看到這條 rule。

她笑了一下。

然後回覆：

> 「Good rule。」

---

幾秒後。

顧青禾收到回覆。

她看著那個帳號。

沒有名字。

只有：

`Morrow`

---

她沒有封鎖。

也沒有回報。

只回了一句：

> 「I know。」

---

# Leo's Note｜終章後記

這套三部曲寫到最後，我反而不太想談 0-Day。

因為 0-Day 很浪漫。

尤其對沒有真的維護過大型系統的人。

一講：

**自動化漏洞挖掘。**

**Symbolic Execution。**

**AI Exploit Synthesis。**

**Microsecond Decision Loop。**

整個畫面馬上有了。

GPU 在燒。

風扇在叫。

螢幕滿是紅色。

彷彿下一秒就能把 Pentagon 螢幕炸黑。

很電影。

也很爽。

但真正做工程的人知道。

系統最常死的地方，通常沒有那麼華麗。

可能是一個：

`TODO`

一個：

`temporary`

一個：

`legacy`

一個：

「明天再改。」

甚至只是：

> 「這次先這樣。」

---

這些東西不會出現在 AI 的 reward function 裡。

但它們會出現在 codebase 裡。

然後活三年。

五年。

十年。

最後某一天。

一個模型花幾十億次計算。

才發現：

**原來人類早就把門打開了。**

---

這就是我想留下的最後一句話。

不是：

> AI 會取代駭客。

也不是：

> AI 會取代防守者。

甚至不是：

> AI 會超越人類。

這些都太廉價。

真正值得害怕的是：

> **當機器開始比人類更快地發現錯誤，而人類卻比機器更慢地承認「這個錯誤為什麼會存在」。**

因為那一刻。

問題已經不在技術。

而在我們。

---

四十五歲以後，我對 Bug 的態度也變了。

年輕時看到 bug：

**修掉。**

當主管後看到 bug：

**評估風險。**

再老一點：

**先問誰會因此受傷。**

現在？

我大概會先看 commit history。

然後泡一杯咖啡。

如果發現最後是：

`temporary workaround`

我通常會笑。

不是因為好笑。

是因為我知道。

**這個故事還沒完。**

代碼不會記得我們。

但它會忠實地繼承我們所有沒有處理完的決定。

這大概就是：

# **代碼的宿命。**
