☰
HackBrowserData 主密钥检索机制深度解析:基于 RFC-006 的 macOS / Windows / Linux 三平台 Chromium 密钥获取架构
2026/10/4 4:33:22 网站建设 项目流程
  • 网络安全
  • 应用安全
  • 密码学
  • CLI

【免费下载链接】HackBrowserData

Extract and decrypt browser data, supporting multiple data types, runnable on various operating systems (macOS, Windows, Linux).

项目地址:https://gitcode.com/gh_mirrors/ha/HackBrowserData
点击查看免费下载

本指南以 rfcs/006-key-retrieval-mechanisms.md(RFC-006)为骨架,结合 HackBrowserData 仓库中masterkey、browser、crypto等包的源码实现,系统讲解 Chromium 系浏览器主密钥(Master Key)在 macOS、Windows、Linux 三个平台上的存储方式与检索策略。读完本文,你将掌握Retriever接口与ChainRetriever链式语义、按密文版本前缀分层的MasterKeys(V10/V11/V20)机制、macOS 的三种取钥手段(含 CVE-2025-24204 内存转储)、Windows 的 DPAPI 与 App-Bound Encryption(ABE)双轨方案,以及 Linux 上"peanuts"硬编码密钥与 D-Bus Secret Service 的搭配,并理解 Safari 为何独立于这套体系。

1. 概述:Chromium 主密钥的三种平台存储形态

Chromium 系浏览器(Chrome、Edge、Brave、Opera、Vivaldi 等)并不会直接用明文保存密码、Cookie、信用卡等敏感数据,而是先派生出一个主密钥(master key),再用它加密落盘。主密钥本身按平台存放在不同的"保险柜"中,RFC-006 给出了权威对照表:

平台存储位置密钥类型
macOSmacOS Keychain(钥匙串)密码字符串 → PBKDF2 → AES-128
WindowsLocal StateJSON(DPAPI 加密)原始 AES-256 密钥
LinuxGNOME Keyring / KDE Wallet(经 D-Bus)密码字符串 → PBKDF2 → AES-128

要点是:每个平台可能存在多种取钥途径,例如 macOS 既能靠 root 权限的内存转储拿密码,也能用登录密码直接解锁钥匙串,还能退化为调用security命令。HackBrowserData 用Retriever接口与ChainRetriever链式模式把这些策略抽象成"按优先级逐个尝试、先成功者胜出"的管线。

关于 Chromium 密文本身的加密细节(AES-CBC/GCM、密文版本前缀等),属于 RFC-003 的范畴;Firefox 通过key4.db自管密钥,见 RFC-005。

2. Retriever 抽象:Hints、接口与链式取钥

2.1 Hints:显式传参而非位置参数

接口的入参是一个Hints结构体,目的是让调用方的意图显式化,而不是靠一堆位置参数拼凑。源码定义见 masterkey/retriever.go:

type Hints struct { KeychainLabel string // macOS Keychain account / Linux D-Bus Secret Service item label (e.g. "Chrome", "Chrome Safe Storage") WindowsABEKey string // Windows ABE browser key used by ABERetriever to locate the elevation-service COM interface (e.g. "chrome", "edge"). "" → ABE not applicable; ABERetriever returns (nil, nil) silently. LocalStatePath string // path to Local State JSON. Only used on Windows (DPAPI + ABE both read it). }

每个 retriever 只读取与自己平台相关的字段,其余字段一律忽略。调用方从BrowserConfig填充Hints:KeychainLabel直接拷贝配置值;WindowsABEKey则在cfg.WindowsABE为 true 时置为cfg.Key。这一组装逻辑实现在 browser/chromium/chromium.go 的buildHints中(V10 的 DPAPI 与 V20 的 ABE 都依赖它)。

2.2 Retriever 接口与返回值语义

// Retriever obtains a Chromium master key from one platform source (DPAPI, Keychain, D-Bus, …). type Retriever interface { RetrieveKey(hints Hints) ([]byte, error) }

返回值就是拿来即用的解密密钥:Windows 上是 32 字节原始 AES-256 密钥,macOS/Linux 上则是经 PBKDF2 派生后的 16 字节 AES-128 密钥。也就是说,"取钥"这一层已经把 PBKDF2 派生完成了,下游拿到[]byte即可直接喂给解密器。

2.3 ChainRetriever:先成功者胜出

type ChainRetriever struct { retrievers []Retriever } func (c *ChainRetriever) RetrieveKey(hints Hints) ([]byte, error) { var errs []error for _, r := range c.retrievers { key, err := r.RetrieveKey(hints) if err == nil && len(key) > 0 { return key, nil } if err != nil { log.Debugf("retriever %T failed: %v", r, err) errs = append(errs, fmt.Errorf("%T: %w", r, err)) } } return nil, fmt.Errorf("all retrievers failed: %w", errors.Join(errs...)) }

语义有三个关键点(对应 masterkey/retriever.go):

  • 先成功者胜出:只要某个 retriever 返回err == nil且密钥非空,立即返回,后续 retriever 不再执行;
  • 静默降级:单个 retriever 失败只打Debugf日志,不中断链路;
  • 全失败合并错误:所有 retriever 都失败时,用errors.Join把每个 retriever 的错误合并成一个整体错误返回,方便诊断是哪个环节出了问题。

2.4 MasterKeys / Retrievers:按密文版本分层,而不是单链

RFC-006 的关键设计是:不能只有一个"获胜密钥",因为一个 profile 里可能混有多种密文版本(Windows 的 v10+v20、Linux 的 v10+v11)。因此masterkey包提供了按密文版本前缀分层的容器,见 masterkey/masterkeys.go:

// MasterKeys holds one key per cipher tier; a profile can mix tiers (Win v10+v20, Linux v10+v11), // so each is populated independently. A nil tier = that cipher version can't be decrypted. type MasterKeys struct { V10 []byte `json:"v10,omitempty"` V11 []byte `json:"v11,omitempty"` V20 []byte `json:"v20,omitempty"` } // Retrievers is the per-tier retriever configuration; unused slots are nil. type Retrievers struct { V10 Retriever V11 Retriever V20 Retriever } // NewMasterKeys fetches each non-nil tier and joins per-tier errors. func NewMasterKeys(r Retrievers, hints Hints) (MasterKeys, error) { // ...对每个非 nil 的 tier 独立调用 RetrieveKey,错误用 errors.Join 合并 }

NewMasterKeys会独立评估每一个非 nil 的 tier,某个 tier 失败不影响其他 tier 成功;返回的错误是各 tier 错误的errors.Join。日志级别由调用方决定——browser/chromium.(Browser).masterKeys()(browser/chromium/chromium.go)目前把各 tier 的错误统一以Warnf输出,理由是对于一个短生命周期 CLI(默认输出即可见所有 warn 行)而言,"部分失败"与"全部失败"的区分价值不高。

2.5 缓存与注入:每个进程只建一次检索链

检索链在整个进程内只创建一次:browser包按平台分别实现的newCredentialInjector(见 browser/browser_darwin.go、browser/browser_linux.go、browser/browser_windows.go)负责把masterkey.DefaultRetrievers()的产物注入到每一个 Chromium 浏览器、每一个 profile 上,并通过能力接口分派(详见第 8 节)。macOS 的 retriever 内部还用了sync.Once(源码见 masterkey/retriever_darwin.go 的GcoredumpRetriever与KeychainPasswordRetriever),因此多 profile 的浏览器只会触发一次钥匙串弹窗或内存转储。

3. macOS 密钥获取:三种策略与一条链

Chromium 在 macOS 上把加密密码存放在用户登录钥匙串(login keychain)中,账号名与浏览器相关(如"Chrome"、"Brave"、"Microsoft Edge")。

3.1 三种检索策略

① GcoredumpRetriever —— 利用 CVE-2025-24204 漏洞(需 root)

原理:利用gcore二进制持有的com.apple.system-task-ports.read权限绕过 TCC 保护,直接读取securityd(系统安全守护进程)的内存,从中提取钥匙串密钥。整体流程(实现见 masterkey/gcoredump_darwin.go,构建标签为darwin && keychain_gcore):

  1. 通过sysctl(kern.proc.all)定位securityd的 PID;
  2. 用gcore转储该进程内存;
  3. 用vmmap解析堆区域,在MALLOC_SMALL区域中扫描 24 字节的密钥模式;
  4. 拿每个候选密钥尝试解锁login.keychain-db。

该策略的显著特征是失败时返回(nil, nil)静默放行——因为"需要 root"是常态而非异常,不值得报警告淹没真正的错误(与 ABERetriever 的设计哲学一致)。

② KeychainPasswordRetriever —— 直接解锁钥匙串(无需 root、非交互)

使用用户的 macOS 登录密码(来自--keychain-pw参数)直接解锁login.keychain-db。底层依赖项目作者自研的keychainbreaker库——一个纯 Go 实现的 macOS Keychain 文件解析与解密器。实现见 masterkey/retriever_darwin.go 的loadKeychainRecords:keychainbreaker.Open()打开钥匙串文件,Unlock(keychainbreaker.WithPassword(password))解锁,再枚举GenericPasswords()记录。

③ SecurityCmdRetriever —— 调用security命令(最后手段)

执行security find-generic-password -wa <label>获取密码。这会触发 macOS 密码对话框,属于交互式操作,所以被放在链路最后。实现上有三个工程细节(masterkey/retriever_darwin.go):

  • 使用exec.CommandContext包裹,设置30 秒超时(securityCmdTimeout),防止用户挂起对话框导致进程卡死;
  • 按存储名(label)做结果缓存(sync.Mutex+map[string]securityResult),每个浏览器的密钥只弹一次框;
  • 对"用户拒绝授权或输错密码"的模糊错误(security以非零退出但 stderr 为空)做了可读化处理,而不是抛出晦涩的exit status 128 ()。

3.2 链式顺序

macOS 只有 V10 这一层,由DefaultRetrievers(keychainPassword)组装(masterkey/retriever_darwin.go):链的首元素永远是GcoredumpRetriever;仅当密码非空时才插入KeychainPasswordRetriever;最后固定追加SecurityCmdRetriever。顺序如下:

优先级策略前置条件是否交互
1Gcoredump(CVE-2025-24204)Root否
2钥匙串密码--keychain-pw参数否
3security命令行无是(弹窗)

3.3 PBKDF2 派生参数

无论走哪条路,最终得到的都是原始密码字符串,必须经 PBKDF2 派生为 AES-128 密钥。参数在 masterkey/retriever_darwin.go 的darwinParams中硬编码,与 Chromium 上游os_crypt_mac.mm一致:

参数值说明
盐值(Salt)"saltysalt"Chromium 上游 os_crypt_mac.mm 中定义的固定盐
迭代次数1003刻意压低,保证解密性能
密钥长度16 字节(AES-128)
哈希算法HMAC-SHA1

派生由 masterkey/params.go 的pbkdf2Params.deriveKey统一封装(底层调crypto.PBKDF2Key)。

3.4 Keychain 标签映射

每个浏览器在钥匙串里用一段短账号字符串标识自己的条目,通常是浏览器基础名("Chrome"、"Brave"、"Arc"),Edge 是"Microsoft Edge"。变体浏览器共享标签而非各自定义:Chrome Beta 别名到"Chrome",Opera GX 别名到"Opera"。权威映射表位于platformBrowsers()各条目的KeychainLabel字段,见 browser/browser_darwin.go(例如 Chrome 的KeychainLabel: "Chrome"、Edge 的KeychainLabel: "Microsoft Edge")。

4. Windows 密钥获取:DPAPI 与 App-Bound 双轨

4.1 先决认知:Windows 上有两把主密钥

Chromium 在 Windows 的Local StateJSON 里可能存两把主密钥:

  • v10 旧版密钥(os_crypt.encrypted_key,DPAPI 包裹);
  • v20 App-Bound Encryption 密钥(os_crypt.app_bound_encrypted_key,IElevator 包裹,Chrome 127+ 引入)。

两者可以在同一个 profile 中共存:Chrome 127+ 对新 Cookie用 v20 加密,但升级前已有的密码和旧 Cookie 仍留在 v10 上。因此取钥层必须独立获取两把密钥,而不是用 ChainRetriever 串起来(详见 4.4 与 issue #578)。

4.2 DPAPI 背景

Windows Data Protection API(DPAPI)是Crypt32.dll提供的内置对称加密服务,以当前登录用户的 Windows 凭据(由其登录密码派生)作为根密钥材料。应用只需调用CryptProtectData加密、CryptUnprotectData解密,无需自行管理密钥。三个关键特性:

  • 用户作用域:一个 Windows 用户加密的数据,另一个用户即使在同一台机器上也解不开;
  • 机器绑定:加密的 blob 无法在其他机器上解密(除非使用漫游凭据);
  • 无密码提示:只要调用进程运行在正确的用户会话下,解密对进程是透明的。

4.3 检索流程

Local State → os_crypt.encrypted_key (base64 字符串) | "DPAPI" 前缀 | DPAPI 加密的 AES 密钥 | |--------------|-----------------------| | 5B (ASCII) | 剩余字节 | → 去掉前缀 → CryptUnprotectData (Crypt32.dll) → 32 字节 AES-256 主密钥

实现层面,DPAPIRetriever(masterkey/retriever_windows.go)的步骤是:读取Local State→ 用gjson取os_crypt.encrypted_key→ base64 解码 →校验"DPAPI"前缀(前缀不符或长度过短都会报错,防止拿到损坏数据)→ 调用crypto.DecryptDPAPI解开剩余字节。运行时通过syscall.NewLazyDLL加载Crypt32.dll,以DATA_BLOB结构传入密文,Windows 内部用用户凭据派生解密密钥并返回明文主密钥。

4.4 无需 PBKDF2

与 macOS/Linux 不同,DPAPI直接给出最终的 AES-256 密钥:没有中间密码、没有派生步骤。该密钥原样用于 AES-256-GCM 解密(算法细节见 RFC-003)。

4.5 双 Tier 检索器(V10 + V20)

Windows 的masterkey.Retrievers结构体填两个槽,二者独立运行、互不干扰,而不是"先成功者胜出"的链:

槽位检索器数据来源字段机制
V10DPAPIRetrieveros_crypt.encrypted_keyCryptUnprotectData(Crypt32.dll)
V20ABERetrieveros_crypt.app_bound_encrypted_keyIElevator 反射注入(见 RFC-010)

V11 在 Windows 上保持 nil(Chromium 在 Windows 不产生 v11 前缀)。装配发生在browser/browser_windows.go的newCredentialInjector中:masterkey.DefaultRetrievers()返回Retrievers{V10: &DPAPIRetriever{}, V20: &ABERetriever{}},再通过Browser.SetRetrievers(r)注入。提取时masterkey.NewMasterKeys独立跑每个槽——一个 tier 失败不影响另一个 tier 成功,因为从 pre-127 升级而来的混合 tier profile 需要"部分成功"才有价值。

为什么不用 ChainRetriever?ChainRetriever是"先成功者胜出"语义:一旦 ABE 返回密钥,DPAPI 就永远不被调用。这对正交的两个 tier是错误的语义——这正是 issue #578 的根因:升级后的 profile 其 v10 加密密码因只取到 v20 密钥而静默解密失败。NewMasterKeys独立评估各 tier 并返回errors.Join合并的逐 tier 错误。

非 ABE 的 Chromium 分支(Opera、Vivaldi、Yandex、360、QQ、Sogou)在platformBrowsers()中不设WindowsABE(默认 false)。调用方因此把Hints.WindowsABEKey留空,ABERetriever对空值直接返回(nil, nil)(masterkey/abe_windows.go 第 31-34 行),NewMasterKeys将其视为"不适用"——对这些分支尝试 ABE 是无操作(no-op)而非失败,它们的 V10 DPAPI 密钥照常工作。

5. Linux 密钥获取:peanuts 与 D-Bus 双槽

5.1 双 Tier 检索器(V10 + V11)

Linux 的Retrievers结构体填两个槽,一一对应 Chromium 在本平台可能产生的两个密文前缀:

槽位前缀检索器机制Chromium 对应物
V10v10PosixRetrieverPBKDF2("peanuts")kV10Key(对应上游PosixKeyProvider)
V11v11DBusRetrieverPBKDF2(D-Bus Secret Service 密码)kV11Key(对应上游FreedesktopSecretKeyProvider)

V20 在 Linux 上保持 nil(App-Bound Encryption 仅限 Windows)。v12(Chromium 的SecretPortalKeyProvider,Flatpak / xdg-desktop-portal 方案)是独立的一层,尚未实现——decryptValue的CipherV12分支会抛出可操作的"已知缺口"错误(见 browser/chromium/decrypt.go 与 crypto/version.go)。

DBusRetriever(masterkey/retriever_linux.go)查询 D-Bus Secret Service API(由gnome-keyring-daemon或kwalletd提供):连接dbus.SessionBus()→keyring.GetSecretService→OpenSession→ 遍历所有 collections 与 items,查找标签与浏览器存储名匹配的条目 → 取回密钥并派生。它填 V11 槽,因为Chromium 只有在钥匙串访问成功时才会发出 v11 前缀。

PosixRetriever使用硬编码密码"peanuts",派生出的固定 16 字节 AES-128 密钥即 kV10Key。它填 V10 槽,因为 Chromium 对用此密钥加密的数据发出 v10 前缀。该检索器永远确定性成功——即使没有任何钥匙串守护进程。

5.2 为什么是两个槽而不是一条链

一个 profile 完全可以同时携带 v10 与 v11 密文——只要主机在"有钥匙串的桌面会话"与"无钥匙串的 headless 会话"之间切换过(例如一台先跑 headless shell、后进完整桌面的笔记本)。旧实现ChainRetriever{DBus, Fallback}是"先成功者胜出":只要 D-Bus 成功,peanuts 就永远不被调用,导致 v10 密文无法解密。现在的拆分正是对 Windows V10/V20 修复(4.5 节)与 issue #578 根因逻辑的镜像:不同密文前缀对应不同密钥来源,取钥层必须独立产出两把密钥,而不是挑"一个获胜密钥"。

5.3 PBKDF2 派生参数(远弱于 macOS)

两种策略产出的都是密码字符串,经 PBKDF2 派生。参数在 masterkey/retriever_linux.go 的linuxParams中定义,与 Chromium 上游os_crypt_linux.cc一致:

参数值说明
盐值(Salt)"saltysalt"与 macOS 相同的固定盐
迭代次数1与 macOS 的 1003 形成鲜明对比
密钥长度16 字节(AES-128)
哈希算法HMAC-SHA1

迭代次数为 1意味着 PBKDF2 退化成"带密钥的 HMAC",完全没有密钥拉伸(key-stretching)效果。再叠加广为人知的回退密码"peanuts",Linux 上不依赖钥匙串的 Chromium 加密几乎可以被任意破解——这是 RFC-006 明确指出的安全事实,也是取证工具能够工作的基础。

5.4 Keychain 标签映射

Linux 的 D-Bus 标签遵循"<name> Safe Storage"惯例,但多数浏览器别名到一个小集合上,真正的独立标签只有三个:"Chrome Safe Storage"、"Chromium Safe Storage"、"Brave Safe Storage",其余浏览器全部映射到三者之一。权威映射在 browser/browser_linux.go 的platformBrowsers()中,例如:

  • Chrome / Chrome Beta / Vivaldi →"Chrome Safe Storage";
  • Chromium / Edge / Opera →"Chromium Safe Storage";
  • Brave →"Brave Safe Storage"。

6. 平台汇总

平台检索器(填充的槽位)PBKDF2密钥尺寸
macOSV10 = 链(Gcoredump → KeychainPassword* → SecurityCmd)1003 次迭代AES-128
WindowsV10 = DPAPIRetriever;V20 = ABERetriever(Chrome 127+)无AES-256
LinuxV10 = PosixRetriever("peanuts" kV10Key);V11 = DBusRetriever(钥匙串 kV11Key)1 次迭代AES-128

* 仅当解析出非空密码时包含——要么来自--keychain-pw参数,要么来自交互式 TTY 提示。

7. Safari 凭据提取:刻意独立于 Retriever 体系

Safari不是Retriever接口的使用者。它有自己的凭据提取路径browser/safari/extract_password.go,直接使用 keychainbreaker 库列出login.keychain-db中的InternetPassword记录(browser/safari/extract_password.go 的getInternetPasswords:keychainbreaker.Open()→ 若有密码则TryUnlock→ 枚举 InternetPassword 记录)。这是刻意的架构选择,而非疏漏。

7.1 为什么 Safari 不共享 Chromium 链

维度Chromium 链Safari 直接访问
输出16 字节 AES-128 密钥InternetPassword记录列表
用途解密 Login Data 数据库记录本身就是凭据
消费者数量10+ 个 Chromium 变体1(仅 Safari)
失败模式硬失败(无密钥 → 无法解密)软失败(降级为仅元数据)
缓存收益高(多 profile、多浏览器)无(单浏览器、单次调用)

把 Safari 硬塞进Retriever接口需要返回与[]byte不同的类型,与接口"主密钥抽象"的既定用途矛盾;为单一消费者再造一条平行的 "InternetPassword 链" 则属于过度设计——它没有任何值得链式串联的回退策略。

注意"失败模式"一行:Chromium必须拿到主密钥否则提取整体失败,所以需要不断升级的策略链;Safari 可以优雅降级——即使钥匙串无法解锁,仅导出元数据(URL 和用户名,无明文密码)仍有价值,所以"试一次 keychainbreaker,失败就告警"足够。

7.2 通用规则

每个浏览器包拥有自己的凭据获取策略。masterkey存在的意义仅限于在 Chromium 变体家族间共享检索逻辑。新增浏览器实现应效仿 Safari 与 Firefox——自己掌控凭据代码。

该规则在仓库中已经生效的证据:

  • Firefox(browser/firefox/firefox.go)不 importmasterkey或keychainbreaker,从key4.db经内部 NSS PBE 派生密钥,见 RFC-005;
  • Safari直接用 keychainbreaker 取InternetPassword记录;
  • Chromium 变体全部走masterkey,因为它们共享同一条链并受益于共享的sync.Once缓存。

未来贡献者若要新增一个从 Keychain 读凭据的 macOS 浏览器,应把访问逻辑写进该浏览器的包,而不是扩展masterkey;只有新浏览器是契合现有主密钥链的 Chromium 变体时,才值得扩展masterkey。

7.3--keychain-pw密码的去向:两个刻意不统一的能力接口

macOS 登录密码在启动时由 browser/browser_darwin.go 的resolveKeychainPassword解析一次,然后通过按平台实现的闭包newCredentialInjector分发给两个消费者。该闭包捕获检索链和原始密码,按每个 Browser 恰好满足的能力接口分发:

消费者能力接口定义位置载荷
Chromium 浏览器KeyManagerbrowser/browser.gomasterkey.Retrievers结构体(V10/V11/V20 槽;未用 tier 为 nil)
SafariKeychainPasswordReceiverbrowser/browser.go原始string

两个接口刻意不统一:它们承载的抽象不同——一个交给浏览器预先组装好的检索链,另一个交给浏览器一个凭据令牌去解锁自己的访问路径。强行统一会造出一个泄漏抽象的、无真实共享语义的多态接口。

工程细节:resolveKeychainPassword在构建检索链之前还会先用 keychainbreaker 做一次提前TryUnlock校验,于是错误的密码会在启动时就以告警形式暴露,而不是拖到提取中途才失败。为此付出的"打开钥匙串两次"(一次校验、一次在KeychainPasswordRetriever内)的小成本,换来了明显更好的用户体验。此外该函数遵循严格的降级逻辑:无--keychain-pw且 stdin 非 TTY 时直接返回空字符串,受钥匙串保护的数据将以元数据形式导出。

8. 从密钥到明文:解密链路的版本分派

拿到MasterKeys之后,解密由 browser/chromium/decrypt.go 的decryptValue完成,它按密文版本前缀分派到对应 tier(版本识别见 crypto/version.go 的DetectVersion):

  • v10→masterKeys.V10。这里有一个跨平台精巧设计:v10 密文的算法由密钥长度决定——32 字节密钥走 AES-GCM(Windows),16 字节密钥走 AES-CBC(macOS/Linux)。按密钥长度分派让"跨主机解密"(例如在 macOS 上解密 Windows 导出的密钥)与操作系统无关;
  • v11→masterKeys.V11,Linux 专用 AES-CBC,算法与 Linux v10 相同但密钥来自钥匙串(kV11Key)而非 peanuts(kV10Key),因此两个 tier 需要不同密钥;
  • v20→masterKeys.V20,跨平台 AES-GCM(Chrome 127+ ABE),线格式与 Windows v10 相同;
  • v12→ 明确报"未实现"错误(Chromium SecretPortal / Flatpak 的已知缺口),而不是模糊的"不支持";
  • 缺失 tier 密钥会以密文级解密错误呈现,提取层将其当作空明文处理而非致命错误(browser/chromium/decrypt.go 注释明确说明)。

从取钥到解密的完整调用链是:DiscoverBrowsersWithKeys→newCredentialInjector(注入Retrievers)→Browser.Extract→b.masterKeys()(sync.Once缓存,内部走ExportKeys→masterkey.NewMasterKeys)→decryptValue。buildHints还会把Local State拷贝进临时目录(Windows DPAPI/ABE 从一个进程拥有的路径读取),见 browser/chromium/chromium.go。

9. 实战:主密钥的跨主机导出与离线解密

主密钥检索能力不止服务于本机提取,还能支撑跨主机解密:在来源主机上导出主密钥(dumpkeys),在分析主机上离线解密拷贝过来的数据,甚至可解出分析主机无法安装引擎的浏览器(如在 macOS 上解密 Sogou/QQ 浏览器数据)。这得益于MasterKeys的 JSON 可序列化结构(masterkey/dump.go 中Dump/Vault类型,每个Vault携带Keys MasterKeys)。标准工作流(详见 README.md 的 Cross-host decryption 一节):

# 来源主机:导出主密钥 + 打包解密所需的文件 hack-browser-data dumpkeys -o keys.json hack-browser-data archive -o browser-data.zip # 拷贝到分析主机后离线解密 hack-browser-data restore --keys keys.json --data-zip browser-data.zip

keys.json包含明文主密钥,须按秘密对待(dumpkeys -o以0600权限落盘)。macOS 场景下,dumpkeys同样接受--keychain-pw参数来免交互解锁钥匙串:

标志简写默认说明
--browser-ball目标浏览器(all|chrome|edge|...)
--output-ostdout输出文件(0600权限);省略则输出到 stdout 便于 SSH 管道
--keychain-pwmacOS 钥匙串密码

restore不依赖分析主机的本地浏览器表,可恢复的浏览器恰好是keys.json中的 vaults;数据可经--data-zip(archive产物)或--data-dir(手工拷贝的 User Data 目录)提供。这是第 2.4 节"按 tier 独立取钥"设计在跨主机场景下的直接红利——一个 profile 若同时含 v10 与 v20 密文,两把密钥都会被完整导出并逐层解密。

10. 小结与延伸阅读

RFC-006 描绘的取钥架构可以概括为三句话:按平台找对保险柜(Keychain / DPAPI / D-Bus),按密文版本分对槽(V10/V11/V20),按失败成本排好队(链式 vs 独立分层)。ChainRetriever只用于 macOS 上"同层不同手段"的递进;Windows 与 Linux 的"不同层不同来源"则用MasterKeys的多槽结构独立求值——这个区分是 issue #578 用教训换来的正确语义。Safari 与 Firefox 则证明:当消费者形态与 Chromium 差异过大时,自管凭据代码反而是更清晰的选择。

关键实现与文档索引:

  • 检索抽象与链式实现:masterkey/retriever.go、分层容器 masterkey/masterkeys.go
  • macOS 检索器与 PBKDF2 参数:masterkey/retriever_darwin.go、CVE-2025-24204 转储 masterkey/gcoredump_darwin.go
  • Windows DPAPI / ABE 检索器:masterkey/retriever_windows.go、masterkey/abe_windows.go
  • Linux D-Bus / peanuts 检索器与参数:masterkey/retriever_linux.go
  • 注入与平台浏览器表:browser/browser.go、browser/browser_darwin.go、browser/browser_linux.go、browser/browser_windows.go
  • 版本分派解密:browser/chromium/decrypt.go、crypto/version.go
  • Safari 独立路径:browser/safari/extract_password.go
  • 跨主机导出格式:masterkey/dump.go,CLI 用法见 README.md

外部参考资料(RFC-006 原文标注,此处仅作文字说明):Chromium 上游os_crypt_mac.mm/os_crypt_win.cc/os_crypt_linux.cc中的盐值与密钥派生常量;CVE-2025-24204 的公开 PoC 与 Apple 安全公告;微软文档中CryptUnprotectData的 DPAPI 说明。相关 RFC:RFC-003(Chromium 加密机制)、RFC-005(Firefox NSS 加密与密钥派生)、RFC-010(Chrome ABE 集成)。

  • 网络安全
  • 应用安全
  • 密码学
  • CLI

【免费下载链接】HackBrowserData

Extract and decrypt browser data, supporting multiple data types, runnable on various operating systems (macOS, Windows, Linux).

项目地址:https://gitcode.com/gh_mirrors/ha/HackBrowserData
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询