我正在开发一个
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
错误,我将不胜感激。
谢谢!
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
};
此代码有两处不正确。
Vec::from_raw_parts()
取得所提供的分配指针的所有权;也就是说,它负责释放分配。如果您在创建 Vec
后释放分配,这将是双重释放。
的所有权被有效地转移到ptr
,然后它可以随意释放、重新分配或更改指针指向的内存内容。确保调用此函数后没有其他任何东西使用该指针。Vec<T>
分配必须由 Rust 全局分配器分配:
必须使用全局分配器进行分配,例如viaptr
功能。alloc::alloc
每当您使用
unsafe
功能时,您必须阅读安全要求并遵守所有要求。
而不是
Vec::from_raw_parts
,您应该使用 std::slice::from_raw_parts
构造一个非拥有的切片引用,然后在该切片上调用
to_vec()
将数据 copy 到新的 Vec
中。然后,您可以LocalFree
系统创建的分配。
如果您不想复制数据,则必须返回拥有 Windows 分配的类型 - 而不是 Rust
Vec
。我不熟悉 Windows 绑定,所以也许这样的类型已经存在,但如果不存在,则编写自己的类型 - 一个包含指针的结构,并实现 Deref
特征以提供数据访问和 Drop
当不再需要时释放特征。