# 文件沒寫的 CLI 設定怎麼挖:用 strings + grep 從 binary 反查 hidden config(含實戰案例)
工程師日常踩坑:明明 UI 裡看到一個 toggle,但官方文件就是沒寫對應的 settings.json key 名稱。最近用這招從 Claude Code binary 挖出兩個 hidden key,分享一個 5 步驟通用方法論。
TL;DR
問題:CLI 工具 UI 裡有 toggle,但對應的 JSON / YAML key 文件沒寫,無法寫進設定檔自動化。
方法:
# Step 1: 找 binary 真實位置
which <cli-tool>
# Step 2: 跟著 symlink 走
readlink -f $(which <cli-tool>)
# Step 3: 抓所有可疑 key
strings <real-binary> | grep -E "^[a-zA-Z]*[Kk]eyword[a-zA-Z]*$" | sort -u
# Step 4: 確認 UI label 對應
strings <real-binary> | grep -B1 -A1 "<keyName>"
# Step 5: 寫進設定檔驗證
為什麼有效:CLI 工具大多用 string literal 存 config key,strings 會把這些 ASCII 字串全部撈出來。UI label 跟 storage key 通常字面距離很近,grep 上下文兩行就能比對。
目錄
- 為什麼 hidden settings 是常態
- 實戰案例:Claude Code 兩個 hidden key
- 完整 5 步驟方法論
- 進階技巧:縮小搜尋範圍
- 這招對哪些 CLI 工具有效
- 這招的限制
- 比 strings 更深入的工具
- 踩坑紀錄
- FAQ
- 延伸資源
為什麼 hidden settings 是常態
軟體迭代過程中,設定通常經歷三個階段:
剩下的 10% 是什麼?
- 新加的 toggle(doc lag 1-2 release)
- internal feature(給 power user,沒打算正式 publicize)
- 過渡期 key(會被改名但還沒改)
實戰案例:Claude Code 兩個 hidden key
起點:UI 看到 toggle
Claude Code 的 /config 互動選單裡有兩個對日常很有用的 toggle:
- Enable Remote Control for all sessions(每個新 session 自動開 RC,不用每次打
/rc) - Push when Claude decides(任務完成推播到手機)
~/.claude/settings.json 一勞永逸。
卡點:官方文件查無此 key
官方 Settings 文件只寫了反向 key:
disableRemoteControl: true # 這個會擋掉 RC
但反向的 enable / push 對應 key 沒寫。Google 搜「claude code settings.json remote control enable」全部都是 UI 互動教學,沒人寫過 JSON key。
用 strings 5 分鐘搞定
# 1. 找 binary
which claude
# /Users/yanchen/.local/bin/claude
# 2. 跟 symlink
readlink -f /Users/yanchen/.local/bin/claude
# /Users/yanchen/.local/share/claude-code/cli.js(或對應路徑)
# 3. 抓所有 remoteControl 開頭結尾的字串
strings $(readlink -f /Users/yanchen/.local/bin/claude) | \
grep -E "^[a-zA-Z]*[Rr]emote[Cc]ontrol[a-zA-Z]*$" | sort -u
輸出:
applyRemoteControlToAppState
autoAddRemoteControlDaemonWorker
disableRemoteControl
enableRemoteControl ← 看起來像
getRemoteControlAtStartup ← 也像
hasUsedRemoteControl
isRemoteControl
isRemoteControlHardDisabled
isRemoteControlInternalEventsEnabled
remoteControl
remoteControlAtStartup ← 最可疑
remoteControlSessionNamePrefix
remoteControlSpawnMode
remoteControlUpsellSeenCount
幾個候選都是 camelCase。最像 settings key 的:remoteControlAtStartup(有 getRemoteControlAtStartup getter,明顯是讀 config 的)。
確認 UI label 對應
strings $(readlink -f $(which claude)) | grep -B1 -A1 "remoteControlAtStartup"
輸出(節錄):
Claude in Chrome enabled by default
remoteControlAtStartup
Enable Remote Control for all sessions ← 賓果!UI label 就在下一行
--
default
remoteControlAtStartup
true ← 預設值也在
確認:remoteControlAtStartup 就是「Enable Remote Control for all sessions」對應 storage key。
寫進設定檔
// ~/.claude/settings.json
{
"remoteControlAtStartup": true,
"agentPushNotifEnabled": true // 用同樣手法挖出來
}
開新 terminal claude 一下→不用打 /rc 就直接 active。驗證成功,總共花 5 分鐘。
完整 5 步驟方法論
把上面流程抽象成可重複用的 SOP:
Step 1:定位 binary
# 找執行檔
which <cli-name>
# 跟 symlink(很多 CLI 是 symlink 到實際 JS / binary)
readlink -f $(which <cli-name>)
# 確認是 ELF binary 還是 script
file $(readlink -f $(which <cli-name>))
如果 file 顯示 ELF 或 Mach-O → 直接 strings 走起。
如果是 script(bash / Node.js / Python)→ 找它呼叫的真正 binary 或 bundle file。
Step 2:列舉可疑字串
strings <binary> | grep -E "^[a-zA-Z]*<keyword>[a-zA-Z]*$" | sort -u
是 UI 上 toggle 的關鍵字(小寫一個字就好)。例如:
- 找「Auto Save」相關 →
keyword=save或auto - 找「Telemetry」相關 →
keyword=telemetry - 找「Theme」相關 →
keyword=theme
^[a-zA-Z]*[a-zA-Z]*$ 會匹配純 camelCase / PascalCase identifier,過濾掉句子跟 path。
Step 3:篩選候選
可疑 key 通常符合:
- ✅ camelCase(
remoteControlAtStartup) - ✅ 跟 toggle 動作有 1:1 對應的命名(
enableXxx/xxxEnabled/disableXxx) - ❌ 開頭有
is/has/can/should(這些通常是 runtime flag,不是 config) - ❌ 結尾是
Mode/Type/Kind(這些是 enum 不是 boolean toggle)
Step 4:上下文確認
strings <binary> | grep -B1 -A1 "<candidateKey>"
看:
- 上下行有沒有 UI label(中文 / 英文都可能)
- 有沒有出現
default、true、false這種預設值字眼 - 有沒有對應的 getter / setter 名字(
getXxx、setXxx)
Step 5:實際驗證
寫進設定檔,重啟 process(CLI 通常是開新 session),確認行為改變。
如果沒效:
進階技巧:縮小搜尋範圍
技巧 1:看 UI label 字串反查 key
如果你只記得 UI label(例如「Enable Telemetry」),先搜 label:
strings <binary> | grep -i "enable telemetry" -B2
# 通常前 1-2 行就是對應的 storage key
技巧 2:看 default 值聚集處
很多 binary 把 default config 一起序列化在某段:
strings <binary> | grep -B5 "DEFAULT_SETTINGS\|defaultSettings\|DEFAULTS"
可能一次看到所有 hidden key 跟 default value。
技巧 3:JSON schema 字串
有些 CLI 內嵌 JSON schema 做 validation:
strings <binary> | grep -E '"(type|properties|enum)":' | head -50
看 schema 直接知道每個 key 的型別跟可選值。
技巧 4:跨平台對照
Windows / macOS / Linux 三個 binary 互相比對,重複出現的 key 是可信度高的真實 config:
diff <(strings claude-mac | grep -E "^[a-zA-Z]+$" | sort -u) \
<(strings claude-linux | grep -E "^[a-zA-Z]+$" | sort -u)
這招對哪些 CLI 工具有效
從我自己驗證過的列表:
| 工具 | 有效程度 | 備註 |
|---|---|---|
| Claude Code | ★★★★★ | Node.js bundle,幾乎所有 config key 都明碼 |
GitHub CLI (gh) | ★★★★ | Go binary,key 在 strings 裡可見 |
| Docker Desktop | ★★★ | Electron,部分 key 在 main process binary |
| VS Code | ★★★★★ | Electron + JSON schema 完整內嵌 |
| kubectl | ★★★ | Go binary,flag 解析在 strings 可見但 config 結構複雜 |
| AWS CLI | ★★ | Python,key 多在 .py 檔案而非 binary |
| Terraform | ★★★ | Go binary,provider 特定 config 要看 plugin |
cat 就好)。
這招的限制
限制 1:obfuscated / minified binary
JS bundle 跑過 minifier 之後,identifier 可能被改成 a、b、c。strings 會撈到一堆無意義的單字。
對策:找 source map(.js.map 檔案),或用 Webpack analyzer 反推。
限制 2:encrypted strings
少數 binary 把 config key 用簡單編碼或加密存(防有人挖)。strings 撈不到原始字串。
對策:上 Ghidra / radare2 動態 trace,看 runtime 解密後的 string。但這對日常需求是過度工程。
限制 3:runtime 動態組字串
const key = "remote" + "ControlAtStartup";
這種 case strings 看不到完整 key(只看到 fragment)。
對策:grep 看 fragment 上下文,通常前後一行就有提示。或者上 source map / 看 release note。
限制 4:找到 key 但不是 user-facing
有些 key 是 internal only,寫進去 process 直接 ignore 或 throw error。
對策:寫進去之後驗證實際行為改變,不要只看 JSON parse 過了就以為成功。
比 strings 更深入的工具
strings 是入門級。要走更深可以看:
| 工具 | 用途 | 學習成本 |
|---|---|---|
nm | 列 symbol(function / global var 名字) | ★ |
otool (macOS) / objdump | dump section、看 metadata | ★★ |
radare2 / r2 | 互動式反組譯框架 | ★★★★ |
| Ghidra | NSA 開源 GUI 反組譯 + 反編譯 | ★★★★ |
ltrace / strace | 追 library / system call | ★★★ |
如果你對更全面的 reverse engineering 感興趣,reversingBits 這個 cheatsheet repo 整理得很完整。
踩坑紀錄
坑 1:grep 漏掉混合大小寫的 key
# 我一開始這樣寫
strings binary | grep "remoteControl"
# 但實際 key 是 RemoteControl(PascalCase)
# 結果漏掉了
修正:用 grep -i 或 regex [Rr]emote[Cc]ontrol。
坑 2:symlink 跟錯
which claude 可能回 /usr/local/bin/claude,但實際 binary 在 ~/.npm/global/... 之類。
修正:一定要 readlink -f 跟到底。
坑 3:以為找到 key 寫進去就有效
挖到 enableRemoteControl: true 寫進設定檔結果沒效。實際 key 是 remoteControlAtStartup。前者是 internal flag,runtime 設定的,寫進 config 會被忽略。
修正:永遠驗證實際行為,不要靠名字猜功能。Step 5 的「實際驗證」步驟跳不得。
坑 4:bundle 內嵌很多假 key
Node.js bundle 把 dependency 的 string literal 也都打包進去。grep 一下會看到一堆其他 lib 的 key 名字。
修正:縮小 grep 範圍(用更具體的 keyword),或交叉比對 source map。
FAQ
Q:這算逆向工程嗎?合法嗎?
strings binary 是 read-only 操作,沒繞過任何技術保護,沒散布任何 derived work。各國法律對「閱讀 binary 內字串」幾乎都不視為侵權。但散布 reverse-engineered tool 或 bypass就是另一回事,那是法律問題不是技術問題。
Q:找到的 key 改 release 會壞嗎?
會。Hidden key 沒寫進文件,等於 maintainer 沒承諾向後相容。version bump 之後可能改名 / 移除。但通常 deprecation 會留一段時間(看 release note)。把這類 hack 當「便利但會過時」的工具,不要寫進關鍵自動化流程。
Q:JS bundle 太大 strings 跑很久?
試 rg --binary 取代 grep,或 ripgrep 配合 --text flag。也可以先 head -c 10M 取 prefix 縮小範圍。
Q:怎麼知道 key 的型別(boolean / string / number)?
grep 上下文看 default 值的格式:true/false = boolean,"xxx" = string,數字 = integer。寫進設定檔型別寫錯通常會 silent ignore 或警告。
Q:找不到時下一步是什麼?
--debug / verbose mode 印出 config dump延伸資源
- strings(1) man page — 官方
- reversingBits cheatsheet — RE 工具大全
- radare2 — 開源反組譯框架
- Ghidra — NSA 開源反組譯 GUI
- The Geek Stuff: RE tools in Linux — 入門教學