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

Rust中使用CryptUnprotectData解密数据出现STATUS_HEAP_CORRUPTION错误

问题描述

我正在开发一个Rust函数,接收&[u8]类型数据,调用WinAPI的CryptUnprotectData完成解密,函数定义如下:

fn decrypt(data: &[u8]) -> Result<Vec<u8>, String> {}

解密逻辑已实现,但释放CryptUnprotectData返回的缓冲区时触发堆损坏错误:

error: process didn't exit successfully: `target\debug\main.exe` (exit code: 0xc0000374, STATUS_HEAP_CORRUPTION)

完整函数代码:

use winapi::{
    um::{
        winbase,
        dpapi,
        wincrypt
    },
    shared::minwindef
};
use std::ptr;

fn decrypt(keydpapi: &[u8]) -> Result<Vec<u8>, String> {
    let mut data_in = wincrypt::DATA_BLOB {
        cbData: keydpapi.len() as minwindef::DWORD,
        pbData: keydpapi.as_ptr() as *mut minwindef::BYTE,
    };
    let mut data_out = wincrypt::DATA_BLOB {
        cbData: 0,
        pbData: ptr::null_mut()
    };
    let result = unsafe {
        dpapi::CryptUnprotectData(
            &mut data_in,
            ptr::null_mut(),
            ptr::null_mut(),
            ptr::null_mut(),
            ptr::null_mut(),
            0,
            &mut data_out
        )
    };
    if result == 0 {
        return Err("CryptUnprotectData failed".to_string())
    };
    if data_out.pbData.is_null() {
        return Err("CryptUnprotectData returned a null pointer".to_string());
    }
    
    let decrypted_data = unsafe {
        Vec::from_raw_parts(data_out.pbData, data_out.cbData as usize, data_out.cbData as usize)
    };
    unsafe {
        winbase::LocalFree(data_out.pbData as minwindef::HLOCAL); // 错误触发位置
    };
    Ok(decrypted_data)
}
问题原因与修复方案

核心问题

  1. 双重释放:调用Vec::from_raw_parts后,Rust的Vec会接管data_out.pbData指向的内存所有权,当Vec被销毁时会自动释放该内存。但手动调用LocalFree再次释放同一块内存,直接导致堆损坏。
  2. 分配器不匹配:CryptUnprotectData返回的内存通过WinAPI的LocalAlloc分配,而Vec::from_raw_parts默认使用Rust全局分配器释放内存,两者分配/释放逻辑不兼容,即使不手动释放也可能引发后续内存错误。

修复方案(推荐)

放弃直接接管WinAPI内存,改为拷贝数据到Rust管理的Vec中,再手动释放原缓冲区:

// 替换原代码中decrypted_data到LocalFree的部分
let decrypted_data = unsafe {
    // 将WinAPI返回的内存转为不可变切片,再拷贝到Rust Vec中
    std::slice::from_raw_parts(data_out.pbData, data_out.cbData as usize).to_vec()
};
// 手动释放WinAPI分配的原内存
unsafe {
    winbase::LocalFree(data_out.pbData as minwindef::HLOCAL);
}
Ok(decrypted_data)

该方案优势:

  • 彻底避免双重释放问题
  • 确保内存由对应分配器管理,无兼容性风险
  • 实现简单,无需额外依赖

额外优化建议

  • 调用CryptUnprotectData失败时,可调用winapi::um::errhandlingapi::GetLastError()获取具体错误码,替换通用错误信息,便于排查问题。
  • 确保导入std::ptr,否则ptr::null_mut()会编译报错。

内容的提问来源于stack exchange,提问作者anonymous

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 01:30:02