如何用Rust构建可注册的Windows Credential Provider DLL?
实现Rust版Windows Credential Provider DLL的可行方案
一、核心前提:确保COM接口实现正确
你已完成ICredentialProvider的POC代码,需确认以下几点:
- 使用
windowscrate的#[implement(ICredentialProvider)]宏绑定接口,所有接口方法(如GetCredentialCount、GetCredentialAt等)均已正确实现 - 类继承自
IUnknown,且通过#[derive(Default)]或手动初始化实现默认构造逻辑 - 为你的Credential Provider生成唯一CLSID(可通过
uuidgen工具生成)
二、导出标准COM DLL函数
Windows Credential Provider依赖DLL导出4个核心COM函数:DllGetClassObject、DllCanUnloadNow、DllRegisterServer、DllUnregisterServer。以下是具体实现代码:
1. 实现类工厂(IClassFactory)
类工厂负责创建Credential Provider实例,需实现IClassFactory接口:
use windows::{ core::{HRESULT, GUID, IUnknown, PCWSTR}, Win32::{ System::Com::{IClassFactory, CLASS_E_CLASSNOTAVAILABLE, E_NOINTERFACE, S_OK}, System::Registry::{RegCloseKey, RegCreateKeyExW, RegDeleteKeyW, RegSetValueExW, HKEY_CLASSES_ROOT, HKEY_LOCAL_MACHINE, KEY_WRITE, REG_SZ}, }, }; use once_cell::sync::OnceCell; // 定义你的Credential Provider类 #[implement(ICredentialProvider)] struct MyCredentialProvider; // 全局类工厂实例(线程安全) static CLASS_FACTORY: OnceCell<IClassFactory> = OnceCell::new(); // 活跃对象计数(用于DllCanUnloadNow) static mut OBJECT_COUNT: u32 = 0; #[implement(IClassFactory)] struct MyClassFactory; impl IClassFactory_Impl for MyClassFactory { fn CreateInstance(&self, outer: Option<&IUnknown>, iid: &GUID, object: *mut *mut std::ffi::c_void) -> HRESULT { if outer.is_some() { return CLASS_E_CLASSNOTAVAILABLE; } let provider = MyCredentialProvider::default(); let unknown: IUnknown = provider.into(); unknown.QueryInterface(iid, object) } fn LockServer(&self, lock: bool) -> HRESULT { unsafe { if lock { OBJECT_COUNT += 1; } else { if OBJECT_COUNT > 0 { OBJECT_COUNT -= 1; } } } S_OK } }
2. 导出COM函数
添加#[no_mangle]和extern "system"标记导出函数:
#[no_mangle] extern "system" fn DllGetClassObject(rclsid: &GUID, riid: &GUID, ppv: *mut *mut std::ffi::c_void) -> HRESULT { // 替换成你的Credential Provider的CLSID const MY_CRED_PROV_CLSID: GUID = GUID::from_u128(0x12345678_1234_5678_1234_567812345678); if *rclsid != MY_CRED_PROV_CLSID { return CLASS_E_CLASSNOTAVAILABLE; } let factory = CLASS_FACTORY.get_or_init(|| MyClassFactory.into()); factory.QueryInterface(riid, ppv) } #[no_mangle] extern "system" fn DllCanUnloadNow() -> HRESULT { unsafe { if OBJECT_COUNT == 0 && CLASS_FACTORY.get().is_none() { S_OK } else { windows::Win32::System::Com::S_FALSE } } } #[no_mangle] extern "system" fn DllRegisterServer() -> HRESULT { const MY_CRED_PROV_CLSID: GUID = GUID::from_u128(0x12345678_1234_5678_1234_567812345678); let clsid_str = format!("{{{}}}", MY_CRED_PROV_CLSID); let clsid_wstr = PCWSTR::from_raw(clsid_str.encode_utf16().chain(Some(0)).collect::<Vec<_>>().as_ptr()); // 注册CLSID到HKEY_CLASSES_ROOT let mut hkey = std::ptr::null_mut(); let result = unsafe { RegCreateKeyExW( HKEY_CLASSES_ROOT, PCWSTR::from_raw(format!("CLSID\\{}", clsid_str).encode_utf16().chain(Some(0)).collect::<Vec<_>>().as_ptr()), 0, None, 0, KEY_WRITE, None, &mut hkey, None, ) }; if result != S_OK { return result; } // 设置InprocServer32指向当前DLL路径 let mut module_path = [0u16; 256]; unsafe { windows::Win32::System::LibraryLoader::GetModuleFileNameW(windows::Win32::Foundation::HMODULE(std::ptr::null_mut()), &mut module_path); RegSetValueExW( hkey, PCWSTR::from_raw("InprocServer32\0".as_ptr() as *const u16), 0, REG_SZ, module_path.as_ptr() as *const u8, (module_path.iter().position(|&c| c == 0).unwrap_or(0) * 2) as u32, ); RegCloseKey(hkey); } // 注册到Credential Providers目录 let mut cp_hkey = std::ptr::null_mut(); let cp_path = format!("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Authentication\\Credential Providers\\{}", clsid_str); let result = unsafe { RegCreateKeyExW( HKEY_LOCAL_MACHINE, PCWSTR::from_raw(cp_path.encode_utf16().chain(Some(0)).collect::<Vec<_>>().as_ptr()), 0, None, 0, KEY_WRITE, None, &mut cp_hkey, None, ) }; if result == S_OK { unsafe { RegCloseKey(cp_hkey) }; } S_OK } #[no_mangle] extern "system" fn DllUnregisterServer() -> HRESULT { const MY_CRED_PROV_CLSID: GUID = GUID::from_u128(0x12345678_1234_5678_1234_567812345678); let clsid_str = format!("{{{}}}", MY_CRED_PROV_CLSID); // 删除CLSID项 unsafe { RegDeleteKeyW( HKEY_CLASSES_ROOT, PCWSTR::from_raw(format!("CLSID\\{}", clsid_str).encode_utf16().chain(Some(0)).collect::<Vec<_>>().as_ptr()), ); // 删除Credential Providers项 RegDeleteKeyW( HKEY_LOCAL_MACHINE, PCWSTR::from_raw(format!("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Authentication\\Credential Providers\\{}", clsid_str).encode_utf16().chain(Some(0)).collect::<Vec<_>>().as_ptr()), ); } S_OK }
三、配置Cargo.toml
确保编译为DLL,并添加必要依赖:
[package] name = "my_cred_prov" version = "0.1.0" edition = "2021" [lib] crate-type = ["cdylib"] [dependencies] windows = { version = "0.52", features = ["Win32_System_Com", "Win32_System_Registry", "Win32_Foundation", "Win32_System_LibraryLoader"] } once_cell = "1.18"
四、编译与注册
- 编译DLL:执行
cargo build --release,生成的DLL在target/release目录下 - 注册DLL:以管理员身份运行
regsvr32.exe path/to/your/dll.dll - 测试:使用Windows SDK中的
CredProvTest.exe工具验证,或重启系统后查看登录界面是否加载你的Credential Provider
五、关键注意事项
- CLSID唯一性:必须为你的Credential Provider生成唯一GUID,避免与系统或其他第三方Provider冲突
- 线程模型:Credential Provider默认要求Apartment Threaded,类工厂的
LockServer需正确维护对象计数 - 接口方法实现:
ICredentialProvider的所有方法需严格遵循Windows SDK规范,尤其是返回值和参数处理 - 权限问题:注册DLL需要管理员权限,调试时可附加到
winlogon.exe进程
内容的提问来源于stack exchange,提问作者IHaxYou
相关产品推荐
相关产品推荐

