提问人:anonymous 提问时间:9/27/2023 最后编辑:cafce25anonymous 更新时间:9/27/2023 访问量:84
在 Rust 中使用 CryptUnprotectData 解密数据会导致STATUS_HEAP_CORRUPTION错误
Decrypting Data with CryptUnprotectData in Rust Leads to STATUS_HEAP_CORRUPTION Error
问:
我正在开发一个函数,该函数接收并使用 .下面是有问题的函数: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
答:
4赞
Kevin Reid
9/27/2023
#1
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 全局分配器分配:
ptr
必须已使用全局分配器进行分配,例如alloc::alloc
函数。
每当您使用某项功能时,您都必须阅读安全要求并遵守所有这些要求。unsafe
您应该使用 std::slice::from_raw_parts
构造一个非拥有切片引用,而不是 ,然后调用该切片将数据复制到新的 .然后,您可以进行系统创建的分配。Vec::from_raw_parts
to_vec()
Vec
LocalFree
如果您不想复制数据,则必须返回拥有 Windows 分配的类型,而不是 Rust 。我不熟悉 Windows 绑定,所以也许这样的类型已经存在,但如果没有,那就编写你自己的 - 一个包含指针的结构,并实现 trait 以提供数据访问和 trait 以在不再需要它时解除分配。Vec
Deref
Drop
评论
0赞
anonymous
9/27/2023
更改为 std::slice::from_raw_parts(...)。to_vec()解决了它。这是一个很好的机会,可以更好地理解 Rust 的所有权原则。我喜欢为从 winapi 返回的内存视图创建可用变量的想法,Rust 允许您自定义 Deref 和 Drop 的行为真是太神奇了。谢谢!
评论
windows-sys
或windows
crate。任何一个都比积极维护要完整得多。winapi