在 Rust 中使用 CryptUnprotectData 解密数据会导致 STATUS_HEAP_CORRUPTION 错误

问题描述 投票:0回答:1

我正在开发一个

Rust
函数,该函数接收
&[u8]
并使用
CryptUnprotectData
中的
WinAPI
对其进行解密。这是有问题的函数:

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

我已经成功实现了这个功能,并且使用

DPAPI
成功解密了数据。

但是,我在尝试释放传递给

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
};

fn decrypt(keydpapi: &[u8]) -> Result<Vec<u8>, String> {
    // https://learn.microsoft.com/en-us/windows/win32/api/dpapi/nf-dpapi-cryptunprotectdata
    // https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-localfree
    // https://docs.rs/winapi/latest/winapi/um/dpapi/index.html
    // https://docs.rs/winapi/latest/winapi/um/winbase/fn.LocalFree.html

    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); // error occured here
    };
    Ok(decrypted_data)
}

如果有任何见解或解决方案来解决此

STATUS_HEAP_CORRUPTION
错误,我将不胜感激。

谢谢!

winapi rust low-level dpapi
1个回答
0
投票
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); // error occured here
};

此代码有两处不正确。

  1. Vec::from_raw_parts()
    取得所提供的分配指针的所有权;也就是说,它负责释放分配。如果您在创建
    Vec
    后释放分配,这将是双重释放。

    ptr
    的所有权被有效地转移到
    Vec<T>
    ,然后它可以随意释放、重新分配或更改指针指向的内存内容。确保调用此函数后没有其他任何东西使用该指针。

  2. 分配必须由 Rust 全局分配器分配:

    • ptr
      必须使用全局分配器进行分配,例如via
      alloc::alloc
      功能。

每当您使用

unsafe
功能时,您必须阅读安全要求并遵守所有要求。

而不是

Vec::from_raw_parts
,您应该使用 std::slice::from_raw_parts
 构造一个非拥有的 
切片引用
,然后在该切片上调用
to_vec()
将数据 copy 到新的
Vec
中。然后,您可以
LocalFree
系统创建的分配。

如果您不想复制数据,则必须返回拥有 Windows 分配的类型 - 而不是 Rust

Vec
。我不熟悉 Windows 绑定,所以也许这样的类型已经存在,但如果不存在,则编写自己的类型 - 一个包含指针的结构,并实现
Deref
特征以提供数据访问和
Drop
当不再需要时释放特征。

© www.soinside.com 2019 - 2024. All rights reserved.