You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 19:35:30