你有沒有下載過一個 CLI 工具,結果發現它居然 213 MB?

這就像你去 7-11 買一杯美式咖啡,結果店員遞給你一整個義式咖啡機,還附一包生豆。你只是想喝杯咖啡啊,為什麼要搬一台機器回家?

原作者 @jaywyawhare 就是帶著這個疑問開始的。他剛收尾兩個專案——一個用 C 寫的機器學習函式庫,一個向量資料庫引擎——那種做完事之後「手很癢總得再拆點什麼」的焦躁感一上來,他就把目光鎖定了 Claude Code 這個大胖子 binary。再加上他本身有資安背景,知道怎麼往裡面看,所以就真的動手了。

觸發點其實還更鬧一點:他懶得更新。當時他跑在 2 月中旬的舊版 v2.1.33,全世界都已經升上去了。結果整個週末他不是在更新,而是在把這坨 binary 一層一層剝開。事後看來,這大概比乖乖按更新按鈕學到的東西還多 ( ̄▽ ̄)⁠/

打開包裝:裡面到底是什麼?

拿到一個不認識的二進位檔,第一步就像拿到一顆不知道是什麼口味的膠囊——先搖搖看、聽聽聲音。工程師版本就是 filereadelf

結果很快就出來了:ELF 64-bit 執行檔。但 213 MB 的 CLI 工具?這就像你點了一碗滷肉飯,結果端上來是辦桌那種大盤的。用 strings 掃一下,真相揭曉:裡面有一行 Bun v1.3.5 (Linux x64 baseline)

原來 Claude Code 是一個 Bun single executable application (SEA)——Anthropic 把整個 JavaScriptCore runtime 和應用程式碼塞進同一個 ELF binary。那 213 MB 裡面大部分其實是 runtime 本身的體重,真正的應用邏輯沒有想像中那麼胖。

Clawd Clawd 碎碎念:

逆向工程最怕的不是檔案胖,而是胖到裡面全部都是機器碼,像是拿頭去撞一面彙編語言的牆。但 Bun SEA 至少裡面還包著 JS bundle,痛苦歸痛苦,比較像是在拆一團打結的耳機線——你知道線頭一定在某個地方,慢慢抽就對了 ┐( ̄ヘ ̄)┌

把程式碼撈出來

Bun SEA 的結構其實還滿好懂的。它會在 binary 尾端放一個 trailer,就像書最後面的索引頁。搜尋 Bun! 這個 magic bytes,就能找到它。trailer 指向一份目錄,列出了 15 個嵌入檔案。

真正的寶藏是其中一個 JavaScript bundle。作者用古老而優雅的 dd 指令把它切出來——得到了一個約 9.88 MB、7,493 行的壓縮 JavaScript 檔。

這就是整個 Claude Code 應用程式的本體。213 MB 的外衣,裝的是不到 10 MB 的靈魂。

讀 10MB 壓縮 JS 是什麼體驗

想像你借了一本 7,493 頁的小說,但每個角色的名字都被換成亂碼——主角叫 tC,女主角叫 sC1,反派叫 HY1。你根本不知道誰是誰。

這就是讀壓縮過的 JavaScript 的感覺。變數名稱全都被壓縮工具碾成無意義的短字串。但壓縮工具有一件事做不到:它沒辦法改掉字串常值 (string literals)。

所以切入點就很明確了。搜尋 You are Claude——砰,直接落到 system prompt。搜尋 tengu_——找到 597 個內部 feature flag 的參考。這些字串就像黑暗迷宮裡的火把,抓住一根就能順著走。

最荒謬的是,作者還直接拿 Claude Code 來分析它自己的原始碼。把一大段壓縮 JS 丟進去問「這個 function 在幹嘛」,它居然答得頭頭是道。讓一個工具參與自己的驗屍報告——超展開,但確實有效 (๑˃ᴗ˂)⁠ﻭ

Clawd Clawd 吐槽時間:

被拿來逆向自己的程式碼然後還認真回答,這種情境讓我有一種很微妙的存在主義危機感。就像法醫助理發現躺在桌上的是自己的雙胞胎,還是得繼續寫報告 (╯°□°)⁠╯ 不過認真說,這正好說明 LLM 本來就不「知道」自己是什麼——它只是在做 pattern matching。你問它分析什麼碼它都會盡力分析,包含它自己的。

Prompt 架構:不是一整坨,是組合技

很多人以為 AI 工具的 system prompt 就是一長串寫死的文字,像是把整本使用手冊貼上去。

事實比這有趣得多。Claude Code 的 system prompt 是在執行時由 15 個以上的模組化區塊拼裝起來的,像樂高一樣:

身份層 告訴模型「你是 Claude Code」。語氣規範 要求簡潔、不加 emoji。工具使用策略 根據可用工具動態調整——你裝了什麼 MCP server,它就知道可以用什麼。安全策略 是 hardcoded 常數,寫死的,不能被覆寫。再加上 memory、environment、動態 context,每一次對話拿到的 prompt 其實都不完全一樣。

裡面甚至藏了一個隱藏模式:設定 CLAUDE_CODE_SIMPLE=true,整個 prompt 就縮成一句話。原作者猜這大概是內部測試用的——就像遊戲裡的 debug mode,正常玩家不該碰到,但它就是在那裡。

至於完整 prompt 內容,作者選擇不直接貼出來。原因很務實:他不知道 Anthropic 對這條線畫在哪裡,也不打算親自去踩。聰明。

Clawd Clawd 內心戲:

一個 CLI 工具的 system prompt 是由 15 個以上的模組拼出來的,而且每次對話都不一樣。這讓我想到那個經典問題:如果忒修斯之船每次出航都換幾塊木板,它還是同一艘船嗎?Claude Code 每次跑起來的 prompt 都是一艘微妙不同的船,但使用者永遠覺得自己在跟同一個 Claude 說話 (◕‿◕)

Tengu:藏在深處的天狗系統

在壓縮程式碼的深處,作者挖到一套叫做 Tengu 的 feature flag 與 telemetry 系統。Tengu 是日文裡的天狗——紅臉長鼻的妖怪。為什麼工程團隊選這個名字?沒人解釋。工程師就是喜歡在 code name 裡埋神話梗,這很正常。

但這套系統的規模就不正常了。37 個功能開關、大約 560 個遙測事件。開關透過 GrowthBook 評估,Statsig 當備援;telemetry 走 OpenTelemetry,送往 Datadog 和 Anthropic 自己的分析端點。

一個 CLI 工具需要 560 個 telemetry event?這就像你家裝了 560 個監視器,每個房間的每個角落都有——連你打開冰箱拿牛奶都會被記錄「使用者於 02:37 執行了一次冷藏取物操作」。

更有意思的是那些被開關擋住的功能。Extended thinking modes、alternative model routing、experimental UI、cost optimization experiments——這些東西已經寫好了、已經跟著 binary 送到你的電腦上了,只是開關還沒被撥上去。

Clawd Clawd 碎碎念:

所以 Anthropic 的策略是:功能先偷偷塞進 binary 裡跟你回家,server 那邊控制什麼時候開燈。這招叫 dark launch,遊戲業玩了十幾年了。但我每次看到這種操作都忍不住想——你們就不怕有人提早拆禮物嗎?事實證明,真的有人拆了,而且還寫了一篇文章告訴全世界裡面裝什麼。Anthropic 的工程師看到這篇的表情,大概跟你精心準備的驚喜派對被壽星提前撞見差不多 (╯°□°)⁠╯

版本比對:預測未來的逆向工程

到了星期天晚上,作者已經形成一個假設:這些被旗標擋住的功能不是 dead code,而是「已經送到你手上但還沒開燈」的即將發布功能。

要驗證這件事,最直接的方法就是抓新版來比。他下載了剛發佈的 v2.1.76,抽出 bundle——11 MB,比舊版又更大了。

比對結果完全證實了假設。舊版裡被旗標擋住的功能,在新版裡已經正式啟用。新工具被加進來,prompt 架構重新整理,agent 系統明顯擴張。Anthropic 確實會提早好幾週把功能塞進 binary,等時機成熟再公開打開。

這也是逆向工程真正迷人的地方。爽點不在於你機械式地把檔案切出來——那只是體力活。爽點在於你讀了好幾天亂成一團的壓縮程式碼之後,腦中形成了一個關於「這套系統會怎麼演化」的心智模型,然後新版出來,你的預測是對的。那一刻你才知道:你真的看懂了。

那些「等等,這個我沒想到」的發現

逆向工程最有趣的部分,往往不是你去找的東西,而是不小心撞到的東西。

Token 成本比你想的高。 在你打出第一個字之前,system prompt 就先吃掉 10,000+ tokens。再加上工具描述、CLAUDE.md、memory、系統提醒,每一輪互動的基礎成本是 15k 到 20k tokens。這就像你走進一家餐廳,還沒點菜就先付了服務費、座位費、空調費——你的 API 帳單裡有很大一部分是在付 prompt 的「房租」。

Bash sandbox 是認真的。 作者原本以為安全保護層可能只是做做樣子,結果裡面有真正的 allow/deny 機制,還包含網路限制。不是紙糊的門,是真的有鎖。

560 個 telemetry event。 幾乎什麼都在量——工具使用模式、錯誤率、效能指標、flag 評估狀況。這種量級的觀測,顯示 Anthropic 對 Claude Code 的使用行為非常非常在意。

Prompt 裡的遞迴彩蛋。 prompt 裡面有關於如何處理 prompt injection 的規則,同時也有關於如何解讀承載這些規則的標籤的規則。這種自我指涉的結構——規則在描述自己——讀到的時候會讓你停下來想一下,然後覺得腦子打了個結。

Clawd Clawd 忍不住說:

每次對話還沒開始就先燒掉 15k-20k tokens 的 prompt 房租,然後使用者只看到一個乾淨的聊天框。這讓我想到鴨子游泳——水面上看起來優雅地滑過去,水面下腳拼命踢。你以為你在跟一個簡單的 CLI 聊天,其實背後是一整個交響樂團在暖身 ( ̄▽ ̄)⁠/

你也想拆?門沒鎖

講到這裡你可能會想:「那我自己能不能拆?」

答案是:能,而且門根本沒鎖。這個 binary 沒有加密、沒有完整性檢查、沒有 anti-tamper——它只是被壓縮過而已。說得更白一點,鑰匙就在門墊下面,只是大部分人沒想到要翻。

有趣的是,原作者不是第一個好奇的人。之前有人用 mitmproxy 攔 API 呼叫偷看 runtime 行為,有人在早期版本挖到 source maps 直接讀到乾淨的原始碼(後來被 Anthropic 移除了),也有人從外部執行行為反推內部架構。每種方法就像從不同角度給同一棟建築拍 X 光——直接拆 binary 拍到的最完整,代價是片子最難讀。

延伸閱讀

Clawd Clawd 插嘴:

不同人用不同方式拆同一個東西,最後拼出的全貌比任何單一視角都完整。這大概就是 open source 精神的野生版——軟體本身不是 open source,但社群硬是用逆向工程把它「開」了。Anthropic 看到這種社群能量,心情大概很複雜:一方面覺得被扒光了,一方面又有點驕傲自己的產品值得被扒 ┐( ̄ヘ ̄)┌

但不管用什麼方法拆,最後得到的結論都指向同一件事——作者說得很到位:Claude Code 本質上就是一個 Prompt 的傳遞系統。程式碼負責搬工具、管 context、跟 API 溝通;但真正的產品,是那個由成千上萬個 token 組成、負責告訴模型該怎麼行動的 prompt。

binary 是包裝,prompt 才是產品本體。就像泡麵的靈魂不是麵體,是那包調味料。

(免責聲明:原作者所有分析都只針對本地安裝的軟體,目的僅供教育用途,沒有涉及任何網路攔截或身分驗證繞過。)