C++解密Chrome已保存密码出现ERROR_INVALID_PARAMETER错误87如何解决
错误原因及修复方案
导致错误码87(无效参数)的核心问题有2处:
- 解密输入的长度参数非法:你将加密数据的实际长度手动+1后传给
CryptUnprotectData,该接口要求输入长度与加密数据的实际字节数完全一致,额外增加的长度会被判定为无效参数。 - 加密数据读取方式错误:
password_value是SQLite的BLOB二进制字段,使用sqlite3_column_text读取会自动截断非ASCII字符,导致传给解密接口的输入数据本身不完整。
其他需要修正的潜在问题:
- 解密后输出的内存需要主动调用
LocalFree释放,否则会造成内存泄漏 - 直接在
out.pbData[out.cbData]位置写入0属于越界操作,会破坏堆内存结构 - SQL查询中不需要单独计算
length(password_value),可以直接通过sqlite3_column_bytes获取BLOB字段的实际长度
修正后完整代码
#include <windows.h> #include <sqlite3.h> #include <iostream> #include <string> #pragma comment(lib, "crypt32") std::string uncryptData(BYTE* password, int size) { DATA_BLOB in; DATA_BLOB out; in.pbData = password; in.cbData = size; // 修正:使用原始长度,不额外+1 if (CryptUnprotectData(&in, NULL, NULL, NULL, NULL, 0, &out)) { // 修正:复制解密内容到std::string管理内存,避免越界和泄漏 std::string result(reinterpret_cast<char*>(out.pbData), out.cbData); LocalFree(out.pbData); // 释放系统分配的内存 return result; } else { std::cout << "error: " << GetLastError() << "\n"; } return "Error"; } void printPassword(sqlite3_stmt* stmt) { std::string url = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0)); std::string login = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1)); if (!login.empty()) { // 修正:用sqlite3_column_blob读二进制,sqlite3_column_bytes拿长度 BYTE* pwdBlob = reinterpret_cast<BYTE*>(sqlite3_column_blob(stmt, 2)); int pwdLen = sqlite3_column_bytes(stmt, 2); std::string password = uncryptData(pwdBlob, pwdLen); std::cout << url << ":" << login << ":" << password << "\n"; } } void findPasswordTable(sqlite3* db) { int i = 0; sqlite3_stmt* stmt; std::cout << "Database open\n"; // 修正:去掉length(password_value)查询项,直接取password_value的长度 const char* query = "SELECT origin_url, username_value, password_value FROM logins"; if (sqlite3_prepare_v2(db, query, -1, &stmt, 0) == SQLITE_OK) { while (sqlite3_step(stmt) == SQLITE_ROW) { printPassword(stmt); i++; } } else { std::cout << "Error compiling query\n"; } sqlite3_finalize(stmt); sqlite3_close(db); } int main() { sqlite3* db; std::string dbPath = "C:/Users/*user*/Desktop/New folder/Login Data"; if (sqlite3_open(dbPath.c_str(), &db) == SQLITE_OK) { findPasswordTable(db); } else { std::cout << "Error opening database"; } return 0; }
补充说明
如果是Chrome 80及以上版本,保存的密码会先用AES-256-GCM加密,密钥用CryptUnprotectData加密后存在Local State文件中,需要先解密拿到AES密钥再解密password_value字段,上述代码仅适用于Chrome 80以下版本的密码解密。
内容的提问来源于stack exchange,提问作者aralph48
相关产品推荐
相关产品推荐

