如何用Rust调用CreateSymbolicLink创建注册表符号链接?
在Rust中创建注册表符号链接
要在Rust中实现类似NtApiDotNet的注册表符号链接创建功能,你需要直接调用Windows Native API的NtCreateKey函数(或其用户态别名ZwCreateKey)——因为标准Win32注册表API不直接支持创建符号链接。以下是具体实现步骤和代码示例:
依赖准备
先在Cargo.toml中添加必要的依赖:
[dependencies] ntapi = "0.4" winapi = { version = "0.3", features = ["winbase", "winnt", "handleapi"] } widestring = "1.0"
实现代码
use ntapi::ntkeapi::NtCreateKey; use std::ptr; use winapi::{ shared::ntdef::{OBJECT_ATTRIBUTES, NTSTATUS, UNICODE_STRING, STATUS_SUCCESS}, um::winnt::{KEY_CREATE_LINK, KEY_READ, OBJECT_NAME_INFORMATION}, }; use widestring::U16CString; fn enable_privilege() -> bool { // 创建符号链接需要启用SE_CREATE_SYMBOLIC_LINK_PRIVILEGE权限 use winapi::{ um::{ handleapi::CloseHandle, securitybaseapi::AdjustTokenPrivileges, winbase::{OpenProcessToken, LookupPrivilegeValueW}, winnt::{HANDLE, TOKEN_ADJUST_PRIVILEGES, TOKEN_QUERY, LUID_AND_ATTRIBUTES, SE_PRIVILEGE_ENABLED}, }, }; let mut token: HANDLE = ptr::null_mut(); if unsafe { OpenProcessToken(winapi::um::processthreadsapi::GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &mut token) } == 0 { return false; } let mut luid = winapi::shared::ntdef::LUID { LowPart: 0, HighPart: 0 }; let privilege_name = U16CString::from_str("SeCreateSymbolicLinkPrivilege").unwrap(); if unsafe { LookupPrivilegeValueW(ptr::null(), privilege_name.as_ptr(), &mut luid) } == 0 { unsafe { CloseHandle(token) }; return false; } let mut privs = LUID_AND_ATTRIBUTES { Luid: luid, Attributes: SE_PRIVILEGE_ENABLED }; let mut prev_state = winapi::um::winnt::PRIVILEGE_SET { PrivilegeCount: 1, Control: 0, Privilege: [privs; 1] }; let mut prev_state_len = 0; let success = unsafe { AdjustTokenPrivileges( token, 0, &mut prev_state, std::mem::size_of::<winapi::um::winnt::PRIVILEGE_SET>() as u32, ptr::null_mut(), &mut prev_state_len, ) } != 0; unsafe { CloseHandle(token) }; success } fn create_registry_symlink(link_path: &str, target_path: &str) -> Result<(), NTSTATUS> { // 将路径转换为Native API要求的Unicode字符串 let link_name = U16CString::from_str(link_path).map_err(|_| ntapi::ntstatus::STATUS_UNSUCCESSFUL)?; let target_name = U16CString::from_str(target_path).map_err(|_| ntapi::ntstatus::STATUS_UNSUCCESSFUL)?; // 构造OBJECT_ATTRIBUTES结构体,描述要创建的符号链接路径 let mut obj_attr = OBJECT_ATTRIBUTES { Length: std::mem::size_of::<OBJECT_ATTRIBUTES>() as u32, RootDirectory: ptr::null_mut(), ObjectName: &mut UNICODE_STRING { Length: (link_name.len() * 2) as u16, MaximumLength: (link_name.len() * 2 + 2) as u16, Buffer: link_name.as_ptr(), }, Attributes: 0, SecurityDescriptor: ptr::null_mut(), SecurityQualityOfService: ptr::null_mut(), }; // 设置符号链接的目标路径 let mut symlink_target = OBJECT_NAME_INFORMATION { Name: UNICODE_STRING { Length: (target_name.len() * 2) as u16, MaximumLength: (target_name.len() * 2 + 2) as u16, Buffer: target_name.as_ptr(), }, }; let mut key_handle: winapi::shared::ntdef::HANDLE = ptr::null_mut(); let status = unsafe { NtCreateKey( &mut key_handle, KEY_READ, &mut obj_attr, 0, ptr::null_mut(), KEY_CREATE_LINK, &mut symlink_target as *mut _ as *mut _, ) }; if status != STATUS_SUCCESS { return Err(status); } unsafe { winapi::um::handleapi::CloseHandle(key_handle) }; Ok(()) } fn main() { // 先启用创建符号链接所需的权限 if !enable_privilege() { eprintln!("Failed to enable SeCreateSymbolicLinkPrivilege"); return; } // 示例:创建HKLM\SOFTWARE\MyLink指向HKLM\SOFTWARE\MyTarget // 注意:Native API中注册表路径需用\Registry\Machine这类原生格式,而非HKLM别名 match create_registry_symlink(r"\Registry\Machine\SOFTWARE\MyLink", r"\Registry\Machine\SOFTWARE\MyTarget") { Ok(_) => println!("Registry symbolic link created successfully"), Err(status) => eprintln!("Failed to create symlink, NTSTATUS: 0x{:X}", status), } }
关键说明
- 权限要求:创建注册表符号链接必须启用
SeCreateSymbolicLinkPrivilege,普通用户默认无此权限,需以管理员身份运行程序。 - 路径格式:Native API接受的注册表路径是
\Registry\Machine、\Registry\User这类原生格式,不能直接用Win32的HKLM、HKCU别名。 NtCreateKey参数:必须指定KEY_CREATE_LINK标志,并将符号链接目标路径通过OBJECT_NAME_INFORMATION结构体传入。
内容的提问来源于stack exchange,提问作者cantfetzthis
相关产品推荐
相关产品推荐

