感谢 GPT-5.6,完美修复了我的 TRAE数据库数据。
感谢这个帖子提供的逆向方案 在mac上进行了复刻
适用于断电或者不知道为什么突然会话全丢的情况。
核心报错:
database disk image is malformed、recover database failed
我把整个流程分享出来,大家遇到了可以直接发给 AI 作为 prompt 使用,也可以直接 clone 我的 github 仓库使用。
TRAE SQLCipher 数据库灾难恢复 SOP
文档版本:2.0
适用产品:TRAE CN / TRAE SOLO CN / TRAE WORK CN(及同族产品)
适用场景:断电、内核 panic、异常退出后,对话历史消失,日志出现:
database disk image is malformed
recover database failed
Backup database file not found
核心原则:
- 永远不要在原件上原地修复。
- 永远先备份、再工作副本、再验证、最后回写。
- 普通 SQLite 工具无法直接处理加密的
database.db。 - 密钥是每台机器独有的;通用“万能解密器”不现实。
- 目标是重建一个新的可用数据库,不是“修好旧文件”。
目录
- 总览流程图
- 故障机理
- 立即停止的危险操作
- 恢复前判断
- 通用阶段:备份与旁路抢救
- Windows 完整流程
- macOS 完整流程
- 通用阶段:解密、修复、重建、回写
- 成功标准与回滚
- 常见失败对照表
- 工具与依赖
- 安全与合规
1. 总览流程图
flowchart TD
A[发现对话消失 / 日志报 malformed] --> B[立即退出 TRAE]
B --> C[只读备份 database.db + WAL/SHM + 日志 + memory + state.vscdb]
C --> D[哈希校验备份 = 原件]
D --> E[旁路抢救: 日志 / memory / 草稿]
E --> F{平台?}
F -->|Windows| G[启动 TRAE 并内存扫描 ai_agent 相关进程]
F -->|macOS| H[确认 Debugging Restrictions=disabled]
H --> I[sudo 调试权限可用]
I --> J[只读扫描 AI 进程内存]
G --> K[HMAC-SHA512 验证候选密钥]
J --> K
K --> L{密钥验证通过?}
L -->|否| M[停止并保留备份 / 仅使用旁路恢复]
L -->|是| N[cipher_integrity_check]
N --> O[逐页解密为标准 SQLite 副本]
O --> P[修正头页数截断等断电痕迹]
P --> Q[sqlite3 .recover 重建 SQL]
Q --> R[导入新库 + integrity_check]
R --> S[sqlcipher_export 重新加密]
S --> T[退出 TRAE 并隔离正式目录旧库]
T --> U[安装恢复库并启动验证]
U --> V{历史会话可见?}
V -->|是| W[导出可读归档并结束]
V -->|否| X[回滚到隔离前快照]
密钥获取阶段单独展开:
flowchart LR
A[运行中的 TRAE AI 进程] --> B[读取进程内存]
B --> C[搜索 64 位十六进制候选]
C --> D[用 database.db 第 1 页盐值做 HMAC 校验]
D -->|匹配| E[保存 enc_key 到本机仅你可读文件]
D -->|不匹配| F[继续扫描 / 换进程]
2. 故障机理
2.1 为什么对话会“全没了”
TRAE 的 Agent 对话主库是 SQLCipher 4 加密的 SQLite:
| 项 | 值 |
|---|---|
| 算法 | AES-256-CBC |
| 页大小 | 4096 字节 |
| reserve | 80 字节 |
| 完整性 | HMAC-SHA512 |
| 文件头 | 不是 SQLite format 3,而是 16 字节随机盐 + 密文 |
断电或 panic 时常见两种损坏叠加:
- WAL 未合并 / 尾页未写完:头字段声明的页数大于物理文件页数。
- SQLite 逻辑结构损坏:
sqlite_master或某棵 B-tree 引用了不存在的页。
此时应用流程通常是:
加载密钥 → 打开加密库成功到 SQLCipher 层
→ 访问表结构/会话列表时触发 SQLite error 11
→ 尝试内置 recover
→ 找不到 Backup database file
→ 放弃,界面显示空历史
所以:
- 不是密钥丢了(很多情况下密钥仍能加载)。
- 不是对话被“删除了”(数据往往还在密文页里)。
- 是逻辑数据库无法完整打开,需要解密后重建。
2.2 为什么普通 SQLite 工具无效
直接对加密原件执行:
sqlite3 database.db 'PRAGMA integrity_check;'
sqlite3 database.db '.recover'
会得到:
file is not a database (26)
这是正常现象,不代表文件空了。
2.3 为什么不能“直接覆盖回去”
若只把损坏原件再拷回:
- TRAE 仍会报
malformed。 - 某些版本会重建一个很小的空库(数 MB),覆盖体验。
- 因此必须先 重建,再 回写。
3. 立即停止的危险操作
| 不要做 | 原因 |
|---|---|
| 卸载 / 重装 TRAE 后清数据 | 可能覆盖用户目录 |
| 清缓存、重置配置、重新登录 | 可能触发空库重建 |
删除 database.db-wal / database.db-shm 再“试试看” |
可能丢掉未合并事务 |
| 在正式目录创建新空会话 | 可能写入新库并污染状态 |
| 对加密原件跑 SQLite 修复工具 | 无意义且可能写坏副本 |
| 把密钥 / 管理员密码发到聊天 | 安全事故 |
| 把关 SIP 当作第一反应 | 有系统风险;仅在调试确实被拒时评估 |
4. 恢复前判断
满足以下条件时,完整数据库恢复价值高:
database.db体积大(数百 MB ~ 数 GB)。- 文件头不是
SQLite format 3。 - 日志是
database disk image is malformed,而不是单纯“找不到数据库”。 - 已有完整冷备份。
体积很小(例如 2MB 级别)的 database.db 往往是 应用重建后的空库,不是原始对话库。此时应去找备份、Time Machine、其它磁盘副本。
5. 通用阶段:备份与旁路抢救
Windows / macOS 在这一阶段逻辑相同,只是路径不同。
5.1 必须备份的对象
最少备份:
ModularData/ai-agent/database.db
ModularData/ai-agent/database.db-wal # 若存在
ModularData/ai-agent/database.db-shm # 若存在
User/globalStorage/state.vscdb
User/globalStorage/state.vscdb.backup # 若存在
logs/
.trae-cn/ 或等价用户数据目录(memory / attachments / argv.json 等)
建议额外备份:
User/globalStorage/storage.json
Local Storage/config.db
machineid
Preferences
5.2 哈希校验
备份完成后必须确认:
SHA256(原件) == SHA256(备份)
5.3 旁路抢救(不依赖密钥)
即使密钥暂时拿不到,也立刻提取:
| 来源 | 内容 |
|---|---|
| 渲染日志 | 用户消息、部分 Agent 回复、sessionId、工作区路径 |
.trae-cn/memory/session_memory_*.jsonl |
Agent 记忆摘要 |
state.vscdb 中 draft:session:*:code |
未发送/自动保存草稿 |
| 项目 Git 仓库 / 附件 | 实际代码与产物 |
这些可以独立导出 Markdown/JSON,作为保险。
6. Windows 完整流程
6.1 路径速查
常见路径(产品名可能不同):
%APPDATA%\Trae CN\ModularData\ai-agent\database.db
%APPDATA%\TRAE SOLO CN\ModularData\ai-agent\database.db
%USERPROFILE%\.trae-cn\
搜索:
Get-ChildItem $env:APPDATA -Recurse -Filter database.db -ErrorAction SilentlyContinue |
Where-Object { $_.FullName -match 'ModularData.*ai-agent' }
6.2 Windows 流程图
flowchart TD
A[退出 TRAE] --> B[复制 AppData 到安全备份目录]
B --> C[校验哈希]
C --> D[导出日志 / memory / state.vscdb]
D --> E[启动 TRAE 同一用户配置]
E --> F[定位加载 ai_agent.dll 的进程]
F --> G[内存扫描 64 位 hex 密钥候选]
G --> H[HMAC 验证 page 1]
H --> I[保存 verified key 到本机文件]
I --> J[进入通用解密与重建阶段]
6.3 Windows 密钥提取
6.3.1 条件
- 必须在 同一台电脑、同一用户、同一产品目录 下运行 TRAE。
- TRAE 需要至少加载过
ai_agent模块。 - 推荐管理员权限运行内存扫描工具。
6.3.2 推荐思路
参考社区与开源工具:
- 论坛:
https://forum.trae.cn/t/topic/18248 - 仓库:
https://github.com/Oh-My-Trae/trae-db-decrypt
核心步骤:
- 启动 TRAE。
- 找到加载
ai_agent.dll的进程 PID。 - 枚举可读内存区。
- 搜索:
x'<64 hex>'- 裸 64 位十六进制字符串
- 对每个候选用数据库第 1 页做 HMAC 验证。
- 仅保存验证通过的密钥。
6.3.3 验证密钥
需要 SQLCipher 4 CLI 或兼容库:
PRAGMA key = "x'你的64位十六进制密钥'";
PRAGMA cipher_version;
PRAGMA cipher_integrity_check;
期望:
cipher_version显示 SQLCipher 4.xcipher_integrity_check返回ok
注意:即使 cipher_integrity_check=ok,普通 SELECT 仍可能因逻辑损坏报 malformed。这不代表密钥错。
6.4 Windows 解密与恢复
拿到密钥后,进入 第 8 章通用阶段。工具链可用:
sqlcipher(推荐)- Python +
pycryptodome做逐页解密 - 官方
sqlite3做.recover
6.5 Windows 回写
- 退出 TRAE(任务管理器确认无残留)。
- 备份正式目录当前
database.db*到时间戳目录。 - 移走正式目录旧库,不要删除。
- 放入重新加密后的恢复库,命名为
database.db。 - 不要同时放入旧 WAL/SHM。
- 启动 TRAE,只检查历史会话。
7. macOS 完整流程
7.1 路径速查
常见路径:
~/Library/Application Support/TRAE SOLO CN/ModularData/ai-agent/database.db
~/Library/Application Support/Trae CN/ModularData/ai-agent/database.db
~/.trae-cn/
搜索:
find "$HOME/Library/Application Support" -path '*/ModularData/ai-agent/database.db' -print
应用包示例:
/Applications/TRAE SOLO CN.app
7.2 macOS 流程图
flowchart TD
A[退出 TRAE 并只读备份] --> B[旁路抢救日志/memory/草稿]
B --> C[csrutil status 检查 Debugging Restrictions]
C --> D{Debugging Restrictions = disabled?}
D -->|否| E[Recovery 模式关闭调试限制后重启]
D -->|是| F[系统设置允许开发者工具]
F --> G[终端验证: sudo lldb 可附加 sleep]
G --> H{附加成功?}
H -->|否| I[检查终端权限 / 是否需要完整退出并重开终端]
H -->|是| J[启动原版 TRAE 到 AI 进程存活]
J --> K[sudo 只读扫描 AI 进程内存]
K --> L[HMAC 验证并保存 key]
L --> M[进入通用解密与重建]
7.3 macOS 调试限制(关键)
macOS 默认会阻止外部进程读取其它进程内存。这与 TRAE 无关,是系统安全策略。
7.3.1 检查当前状态
csrutil status
本次成功恢复的环境示例(Custom Configuration):
System Integrity Protection status: unknown (Custom Configuration).
Configuration:
Apple Internal: disabled
Kext Signing: disabled
Filesystem Protections: disabled
Debugging Restrictions: disabled
DTrace Restrictions: enabled
NVRAM Protections: enabled
BaseSystem Verification: enabled
必须关注的一项:
Debugging Restrictions: disabled
| 状态 | 含义 |
|---|---|
Debugging Restrictions: enabled(默认) |
外部调试/读内存通常被拒 |
Debugging Restrictions: disabled |
允许 task_for_pid / lldb 类调试附加(仍建议用 sudo) |
说明:完整关闭 SIP 不是目标。核心是 Debugging Restrictions 必须为 disabled。
修改 SIP 配置需要进入 macOS Recovery,有系统风险,完成后应评估是否恢复加固。
7.3.2 如何进入 Recovery 修改(概要)
- 关机。
- Apple Silicon:长按电源进入启动选项 → Options → Continue。
Intel:开机时按住Command + R。 - 菜单栏 → 实用工具 → 终端。
- 根据需要配置 SIP。仅调试恢复期间可临时关闭 Debugging Restrictions。
- 重启后执行
csrutil status确认。
不推荐把“关 SIP”作为日常步骤。只有当:
- 开发者工具权限已开,
- 仍无法
lldb附加同用户进程, - 且你理解风险,
才考虑临时修改。
7.3.3 系统设置中的开发者工具
- 打开“系统设置” → “隐私与安全性” → “开发者工具”。
- 允许 Terminal / iTerm / 你实际用来调试的应用。
- 若在 Codex 桌面端内调试失败,不代表系统级
sudo lldb也失败;优先在真实终端验证。
7.3.4 先做无害附加测试
在终端:
sleep 300 &
pid=$!
sudo lldb -p "$pid" -o "process status" -o "detach" -b
kill "$pid"
成功时应看到类似:
Process xxxx stopped
...
Process xxxx detached
若仍报:
Not allowed to attach to process
则:
- 再查
csrutil status的Debugging Restrictions。 - 确认开发者工具权限。
- 完全退出并重开终端后再试。
- 不要继续扫描 TRAE。
7.4 macOS 密钥提取
7.4.1 定位 AI 进程
TRAE 启动后,AI 模块通常是带如下标记的 Helper:
vscode-crash-reporter-process-type=ai
查找:
pgrep -afil 'vscode-crash-reporter-process-type=ai|/Applications/TRAE SOLO CN.app'
优先扫描 AI 进程,不是 GPU/Network/Renderer 进程。
7.4.2 扫描策略
- 读取 AI 进程可读内存。
- 搜索 64 位十六进制字符串(可含
x'...'形式)。 - 用
database.db第 1 页做 HMAC-SHA512 验证。 - 只把验证通过的密钥写入
0600权限文件,例如:
./work/trae-sqlcipher-key.json
建议字段:
{
"enc_key": "<64 hex>",
"address": "0x...",
"source": "macOS Trae process memory; HMAC-SHA512 verified"
}
7.4.3 为什么 Codex 内置命令可能失败
即使你已在系统设置允许 Codex:
- Codex 的沙箱/辅助进程仍可能无法
task_for_pid。 - 应在用户本机终端用
sudo执行扫描脚本。 - 不要把 root 密码发给 AI 或写入文档。
7.4.4 关于 Keychain 弹窗
隔离克隆 / ad-hoc 重签名的测试包可能反复弹“获取机密信息”,因为:
- 签名变化导致 Keychain 项不匹配;
- AI 进程损坏后重启会重复请求。
推荐做法:
- 优先对 正式签名的原版 TRAE 进程 做只读内存扫描;
- 避免长时间运行会连环重启的测试克隆;
- 需要时用短窗口 + 自动退出。
7.5 macOS 解密与恢复
与 Windows 相同,进入 第 8 章。
macOS 可使用 Homebrew 的 sqlcipher:
brew install sqlcipher
sqlcipher -version
7.6 macOS 回写
- 退出 TRAE:
osascript -e 'tell application id "cn.trae.solo.app" to quit'
# 或按实际 bundle id 调整
- 确认无残留:
pgrep -afil '/Applications/TRAE SOLO CN.app'
- 备份正式目录当前库到桌面时间戳目录。
- 将正式目录旧
database.db*移到隔离区。 - 安装恢复后的加密库为
database.db。 - 校验 SHA-256。
- 启动:
open "/Applications/TRAE SOLO CN.app"
- 检查最新日志目录,确认没有
malformed。
8. 通用阶段:解密、修复、重建、回写
以下步骤在 工作副本 上进行。
输入是:加密原件备份 + 已验证密钥。
8.1 阶段流程图
flowchart TD
A[已验证 enc_key] --> B[PRAGMA cipher_integrity_check]
B --> C[逐页解密 -> decrypted.db]
C --> D[检查头页数 vs 物理页数]
D --> E[必要时修正头字段到 header-fixed.db]
E --> F[sqlite3 immutable .recover]
F --> G[导入 recovered-plain.db]
G --> H[integrity_check + 核心表计数]
H --> I[sqlcipher_export -> recovered-encrypted.db]
I --> J[再次验证加密库计数]
J --> K[回写正式目录]
8.2 用 SQLCipher 打开并检查
PRAGMA key = "x'YOUR_64_HEX_CHAR_KEY'";
PRAGMA cipher_version;
PRAGMA cipher_integrity_check;
解读:
| 结果 | 含义 |
|---|---|
cipher_integrity_check = ok |
加密页认证通过,逐页解密可行 |
SELECT 仍 malformed |
逻辑结构坏,需要 .recover |
file is not a database / 密钥错误 |
密钥不对或不是该库 |
8.3 逐页解密
SQLCipher 4 典型参数:
- AES-256-CBC
- page size = 4096
- reserve = 80
- page 1 前 16 字节是 salt,解密后替换为
SQLite format 3\0
伪代码:
from Crypto.Cipher import AES
PAGE = 4096
RESERVE = 80
SALT = 16
HEADER = b"SQLite format 3\x00"
def decrypt_page(key, page, n):
iv = page[PAGE - RESERVE : PAGE - RESERVE + 16]
cipher = AES.new(key, AES.MODE_CBC, iv)
if n == 1:
plain = cipher.decrypt(page[SALT:PAGE - RESERVE])
return HEADER + plain + b"\0" * RESERVE
plain = cipher.decrypt(page[:PAGE - RESERVE])
return plain + b"\0" * RESERVE
解密后:
file decrypted.db
# 应识别为 SQLite 3.x database
8.4 修正断电导致的页数截断
常见现象:
header database pages = 439955
physical file pages = 439949
SQLite 会拒绝打开。处理方式(仅对解密副本的克隆):
import os, struct
path = "decrypted-header-fixed.db"
page_size = 4096
pages = os.path.getsize(path) // page_size
with open(path, "r+b") as f:
f.seek(28)
f.write(struct.pack(">I", pages))
8.5 用 immutable 模式恢复
若头显示 WAL 读版本但没有 WAL 文件,使用:
sqlite3 'file:/ABS/PATH/decrypted-header-fixed.db?immutable=1' \
'PRAGMA quick_check;'
sqlite3 'file:/ABS/PATH/decrypted-header-fixed.db?immutable=1' \
'.recover --ignore-freelist' > recovered.sql
quick_check 可能仍报告某些 tree 引用了缺失页;这正是 .recover 要跳过的坏链。
8.6 导入新库并验证
sqlite3 recovered-plain.db < recovered.sql
sqlite3 -readonly recovered-plain.db 'PRAGMA integrity_check;'
核心表(不同版本可能略有差异):
SELECT 'chat_session', count(*) FROM chat_session
UNION ALL SELECT 'chat_message', count(*) FROM chat_message
UNION ALL SELECT 'chat_turn', count(*) FROM chat_turn
UNION ALL SELECT 'history_v2', count(*) FROM history_v2
UNION ALL SELECT 'agent_run', count(*) FROM agent_run;
本次成功案例数量级参考:
| 表 | 约数 |
|---|---|
| chat_session | 196 |
| chat_message | 1810 |
| chat_turn | 905 |
| history_v2 | 51822 |
| agent_run | 2099 |
8.7 重新加密
保留明文恢复库,另导出加密版:
-- 在 recovered-plain.db 上
ATTACH DATABASE 'recovered-encrypted.db' AS recovered KEY "x'YOUR_64_HEX_CHAR_KEY'";
SELECT sqlcipher_export('recovered');
DETACH DATABASE recovered;
验证加密版:
PRAGMA key = "x'YOUR_64_HEX_CHAR_KEY'";
PRAGMA cipher_integrity_check;
SELECT count(*) FROM chat_session;
SELECT count(*) FROM history_v2;
8.8 回写正式目录
- 退出 TRAE,确认无 AI 进程。
- 备份正式目录当前
database.db*到时间戳快照。 - 将正式目录旧文件移到隔离区(不要
rm)。 - 复制
recovered-encrypted.db为正式database.db。 - 不要带回旧 WAL/SHM。
- SHA-256 对比安装文件与恢复产物。
- 启动 TRAE,只验证旧会话列表与打开能力。
- 确认无
malformed后再正常使用。
9. 成功标准与回滚
9.1 成功标准
- TRAE 能启动。
- 最新日志无
database disk image is malformed。 - Agent 数据库初始化成功。
- 历史会话列表出现,旧会话可打开。
- 恢复库
integrity_check = ok且核心表计数合理。
9.2 回滚
若回写后更糟:
- 退出 TRAE。
- 移除刚安装的
database.db*。 - 从
LiveBeforeRestore-*或隔离区还原。 - 重新验证哈希。
永远保留:
加密原件备份
解密工作副本
recovered-plain.db
recovered-encrypted.db
旁路恢复 Markdown/JSON
10. 常见失败对照表
| 现象 | 可能原因 | 处理 |
|---|---|---|
file is not a database (26) |
对加密库用了普通 SQLite | 先取密钥并解密 |
malformed 但 cipher check ok |
逻辑结构损坏 | .recover 重建 |
.recover 秒失败 / 几乎无输出 |
未解密或页数截断未修 | 解密 + 修头页数 + immutable |
| 密钥扫描不到 | 扫错进程 / 调试被拒 / 应用未加载密钥 | 扫 AI 进程;检查 Debugging Restrictions |
| 连续 Keychain 弹窗 | ad-hoc 克隆反复重启 | 停克隆,改扫正式进程 |
| 回写后仍空历史 | 回写了空库 / 仍用旧 WAL | 确认恢复库体积与表计数;清旧 WAL/SHM |
| 体积从 GB 变成数 MB | 应用重建了空库 | 立即停止使用正式库,回退备份 |
11. 工具与依赖
11.1 通用
- SQLCipher 4 CLI
- SQLite 3 CLI(支持
.recover) - Python 3 +
pycryptodome(逐页解密) jq(处理 key json,可选)
11.2 Windows
- 管理员权限
- 内存扫描脚本(可参考
trae-db-decrypt) - PowerShell
11.3 macOS
- Xcode Command Line Tools /
lldb - Homebrew
sqlcipher - 终端
sudo csrutil status显示 Debugging Restrictions: disabled
12. 安全与合规
- 密钥、root 密码、Keychain 内容 不得 发到聊天、截图、工单。
- 扫描与恢复应离线进行,不上传
database.db。 - 恢复完成后评估是否恢复 SIP / Debugging Restrictions。
- 恢复库权限保持用户私有。
- 本 SOP 描述的是 本地灾难恢复,不是对第三方数据库的攻击方法。
附录 A. HMAC 验证逻辑(固定算法 / 动态密钥)
固定部分:
SQLCipher 4
AES-256-CBC
page_size = 4096
reserve = 80
HMAC = SHA-512
PBKDF2 rounds for mac_key = 2
动态部分:
raw_key : 32 字节,每机/配置独有
db_salt : database.db 前 16 字节
验证伪代码:
mac_salt = bytes(b ^ 0x3A for b in page1[:16])
mac_key = PBKDF2_HMAC_SHA512(raw_key, mac_salt, rounds=2, dklen=32)
digest = HMAC_SHA512(mac_key, page1[16:4032] + little_endian_u32(1))
assert digest == page1[4032:4096]
因此:
- 可以做 通用恢复工具;
- 不能做 无需本机密钥的通用解密器。
附录 B. 建议的工作目录结构
recovery-work/
backup/
database.db
database.db-wal
database.db-shm
logs/
state.vscdb
keys/
trae-sqlcipher-key.json # 0600
decrypt/
trae-database-decrypted.db
trae-database-decrypted-header-fixed.db
recover/
recovered.sql
recovered-plain.db
recovered-encrypted.db
exports/
sessions.md
messages.jsonl
notes/
hashes.txt
counts.txt
附录 C. 一页纸速查
- 退出 TRAE
- 备份 + 哈希
- 旁路抢救日志/草稿/记忆
- Windows:扫
ai_agent进程;macOS:确认Debugging Restrictions: disabled后sudo扫 AI 进程 - HMAC 验证密钥
- 解密副本
- 修页数截断
.recover→ 新库integrity_check+ 表计数- 重新加密
- 隔离旧库后回写
- 启动验证历史会话
永远不要对原件原地修复。
