获取当前用户的sid

!macro _GSID_Func_CALL
    System::Call "user32::FindWindow(i0,tProgram Manager)p.r1"
    System::Call user32::GetWindowThreadProcessId(pr1,*i.r2)i.r3
    System::Call Kernel32::OpenProcess(i0x0400,i0,ir2)i.r4
    System::Call Advapi32::OpenProcessToken(pr4,i0x0008,*i.r5)i.r9
    System::Call Advapi32::GetTokenInformation(pr5,i1,*i.r0,i0,*i.r7)i.r8
    System::Alloc $7
    Pop $0
    System::Call Advapi32::GetTokenInformation(pr5,i1,ir0,ir7,*i.r7)i.r8
    System::Call *$0(i.R0)
    System::Call Advapi32::LookupAccountSid(i0,iR0,t.R6,*i260,t.R7,*i260,*i .r2)
    System::Free $0
    System::Call *(&t${NSIS_MAX_STRLEN})i.R3
    System::Call advapi32::LookupAccountName(t,tR6,iR3,*i${NSIS_MAX_STRLEN},t,*i${NSIS_MAX_STRLEN},*i)
    System::Call advapi32::ConvertSidToStringSid(iR3,*t.R4)
    ; StrCpy $0 $R4
    System::Free $R3
    System::Free $R4
    Push $R4
!macroend

获取当前用户的sid,python实现


import ctypes
import ctypes.wintypes

# 加载必要的 Windows API 函数
user32 = ctypes.WinDLL('user32', use_last_error=True)
kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)
advapi32 = ctypes.WinDLL('advapi32', use_last_error=True)

# 定义一些常量
PROCESS_QUERY_INFORMATION = 0x0400
TOKEN_QUERY = 0x0008
NSIS_MAX_STRLEN = 1024

# 函数声明
FindWindow = user32.FindWindowW
FindWindow.restype = ctypes.wintypes.HWND
FindWindow.argtypes = [ctypes.wintypes.LPCWSTR, ctypes.wintypes.LPCWSTR]

GetWindowThreadProcessId = user32.GetWindowThreadProcessId
GetWindowThreadProcessId.restype = ctypes.wintypes.DWORD
GetWindowThreadProcessId.argtypes = [ctypes.wintypes.HWND, ctypes.POINTER(ctypes.wintypes.DWORD)]

OpenProcess = kernel32.OpenProcess
OpenProcess.restype = ctypes.wintypes.HANDLE
OpenProcess.argtypes = [ctypes.wintypes.DWORD, ctypes.wintypes.BOOL, ctypes.wintypes.DWORD]

OpenProcessToken = advapi32.OpenProcessToken
OpenProcessToken.restype = ctypes.wintypes.BOOL
OpenProcessToken.argtypes = [ctypes.wintypes.HANDLE, ctypes.wintypes.DWORD, ctypes.POINTER(ctypes.wintypes.HANDLE)]

GetTokenInformation = advapi32.GetTokenInformation
GetTokenInformation.restype = ctypes.wintypes.BOOL
GetTokenInformation.argtypes = [ctypes.wintypes.HANDLE, ctypes.wintypes.DWORD, ctypes.wintypes.LPVOID, ctypes.wintypes.DWORD, ctypes.POINTER(ctypes.wintypes.DWORD)]

LookupAccountSidW = advapi32.LookupAccountSidW
LookupAccountSidW.restype = ctypes.wintypes.BOOL
LookupAccountSidW.argtypes = [ctypes.wintypes.LPWSTR, ctypes.wintypes.LPVOID, ctypes.wintypes.LPWSTR, ctypes.POINTER(ctypes.wintypes.DWORD), ctypes.wintypes.LPWSTR, ctypes.POINTER(ctypes.wintypes.DWORD), ctypes.POINTER(ctypes.wintypes.DWORD)]

ConvertSidToStringSidW = advapi32.ConvertSidToStringSidW
ConvertSidToStringSidW.restype = ctypes.wintypes.BOOL
ConvertSidToStringSidW.argtypes = [ctypes.wintypes.LPVOID, ctypes.POINTER(ctypes.wintypes.LPWSTR)]

LocalFree = kernel32.LocalFree
LocalFree.restype = ctypes.wintypes.HANDLE
LocalFree.argtypes = [ctypes.wintypes.HANDLE]

def get_sid_from_process():
    # 找到 "Program Manager" 窗口
    hwnd = FindWindow(None, "Program Manager")
    if not hwnd:
        raise ctypes.WinError(ctypes.get_last_error())
  
    # 获取窗口的进程ID
    process_id = ctypes.wintypes.DWORD()
    thread_id = GetWindowThreadProcessId(hwnd, ctypes.byref(process_id))
  
    if not thread_id:
        raise ctypes.WinError(ctypes.get_last_error())
  
    # 打开进程
    process_handle = OpenProcess(PROCESS_QUERY_INFORMATION, False, process_id)
    if not process_handle:
        raise ctypes.WinError(ctypes.get_last_error())
  
    # 打开进程令牌
    token_handle = ctypes.wintypes.HANDLE()
    if not OpenProcessToken(process_handle, TOKEN_QUERY, ctypes.byref(token_handle)):
        raise ctypes.WinError(ctypes.get_last_error())
  
    # 获取令牌信息所需的缓冲区大小
    token_info_size = ctypes.wintypes.DWORD()
    GetTokenInformation(token_handle, 1, None, 0, ctypes.byref(token_info_size))
  
    # 分配缓冲区并获取令牌信息
    token_info = ctypes.create_string_buffer(token_info_size.value)
    if not GetTokenInformation(token_handle, 1, token_info, token_info_size.value, ctypes.byref(token_info_size)):
        raise ctypes.WinError(ctypes.get_last_error())
  
    # 获取 SID
    sid = ctypes.cast(token_info, ctypes.POINTER(ctypes.wintypes.LPVOID)).contents
    name_size = ctypes.wintypes.DWORD(NSIS_MAX_STRLEN)
    domain_size = ctypes.wintypes.DWORD(NSIS_MAX_STRLEN)
    sid_name_use = ctypes.wintypes.DWORD()
  
    name = ctypes.create_unicode_buffer(name_size.value)
    domain = ctypes.create_unicode_buffer(domain_size.value)
  
    if not LookupAccountSidW(None, sid, name, ctypes.byref(name_size), domain, ctypes.byref(domain_size), ctypes.byref(sid_name_use)):
        raise ctypes.WinError(ctypes.get_last_error())
  
    # 将 SID 转换为字符串
    sid_string = ctypes.wintypes.LPWSTR()
    if not ConvertSidToStringSidW(sid, ctypes.byref(sid_string)):
        raise ctypes.WinError(ctypes.get_last_error())
  
    # 打印 SID 字符串
    result = sid_string.value
    LocalFree(sid_string)
  
    return result

if __name__ == "__main__":
    sid = get_sid_from_process()
    print(f"当前用户的 SID: {sid}")


解释:
FindWindow:查找名为 "Program Manager" 的窗口,它通常是桌面进程。
GetWindowThreadProcessId:获取该窗口的线程和进程 ID。
OpenProcess:使用进程 ID 打开进程。
OpenProcessToken:获取该进程的访问令牌。
GetTokenInformation:获取访问令牌的用户信息,这里需要两次调用,第一次用于获取所需缓冲区大小,第二次用于实际获取数据。
LookupAccountSidW:查找与 SID 关联的账户名称和域名。
ConvertSidToStringSidW:将 SID 转换为字符串形式。
LocalFree:释放分配的内存。
这个 Python 实现与原始的 NSIS 脚本执行的步骤基本相同,能够获取当前登录用户的 SID,即使在管理员权限下运行也能正确地获取用户信息。

Rust 获取当前用户SID

use std::os::windows::ffi::OsStrExt;
use std::{ffi::OsStr, time};
use std::{ptr, thread};
use widestring::WideCStr;
use winapi::{
    ctypes::c_void,
    shared::{minwindef::DWORD, sddl::ConvertSidToStringSidW, winerror::ERROR_INSUFFICIENT_BUFFER},
    um::{
        errhandlingapi::GetLastError,
        handleapi::{CloseHandle, INVALID_HANDLE_VALUE},
        processthreadsapi::{OpenProcess, OpenProcessToken},
        securitybaseapi::GetTokenInformation,
        winbase::LocalFree,
        winnt::{HANDLE, TOKEN_QUERY, TOKEN_USER},
        winuser::{FindWindowW, GetWindowThreadProcessId},
    },
};

fn get_sid_from_process() -> Result<String, std::io::Error> {
    unsafe {
        // 查找 "Program Manager" 窗口
        let window_title: Vec<u16> = OsStr::new("Program Manager")
            .encode_wide()
            .chain(Some(0)) // 添加 null 终止符
            .collect();
        let hwnd = FindWindowW(ptr::null(), window_title.as_ptr());
        if hwnd.is_null() {
            return Err(std::io::Error::last_os_error());
        }

        // 获取进程 ID
        let mut process_id: DWORD = 0;
        let thread_id = GetWindowThreadProcessId(hwnd, &mut process_id);
        if thread_id == 0 {
            return Err(std::io::Error::last_os_error());
        }

        // 打开进程句柄
        let process_handle =
            OpenProcess(winapi::um::winnt::PROCESS_QUERY_INFORMATION, 0, process_id);
        if process_handle == INVALID_HANDLE_VALUE {
            return Err(std::io::Error::last_os_error());
        }

        // 打开进程令牌
        let mut token_handle: HANDLE = ptr::null_mut();
        if OpenProcessToken(process_handle, TOKEN_QUERY, &mut token_handle) == 0 {
            CloseHandle(process_handle);
            return Err(std::io::Error::last_os_error());
        }

        // 获取令牌信息大小
        let mut token_info_size: DWORD = 0;
        let status = GetTokenInformation(
            token_handle,
            winapi::um::winnt::TokenUser,
            ptr::null_mut(),
            0,
            &mut token_info_size,
        );

        // 检查是否为缓冲区不足错误
        if status != 0 || GetLastError() != ERROR_INSUFFICIENT_BUFFER {
            CloseHandle(token_handle);
            CloseHandle(process_handle);
            return Err(std::io::Error::last_os_error());
        }

        // 分配缓冲区并获取令牌信息
        let mut buffer = vec![0u8; token_info_size as usize];
        if GetTokenInformation(
            token_handle,
            winapi::um::winnt::TokenUser,
            buffer.as_mut_ptr() as *mut _,
            token_info_size,
            &mut token_info_size,
        ) == 0
        {
            CloseHandle(token_handle);
            CloseHandle(process_handle);
            return Err(std::io::Error::last_os_error());
        }

        // 提取 SID
        let token_user = &*(buffer.as_ptr() as *const TOKEN_USER);
        let sid = token_user.User.Sid;

        // 转换 SID 到字符串
        let mut sid_string_ptr: *mut u16 = ptr::null_mut();
        if ConvertSidToStringSidW(sid as *mut _, &mut sid_string_ptr) == 0 {
            CloseHandle(token_handle);
            CloseHandle(process_handle);
            return Err(std::io::Error::last_os_error());
        }

        // 转换字符串并释放内存
        let sid_cstr = WideCStr::from_ptr_str(sid_string_ptr);
        let sid_str = sid_cstr.to_string_lossy().to_owned();
        LocalFree(sid_string_ptr as *mut c_void);

        // 清理资源
        CloseHandle(token_handle);
        CloseHandle(process_handle);

        Ok(sid_str)
    }
}

fn main() {
    match get_sid_from_process() {
        Ok(sid) => println!("当前用户的 SID: {}", sid),
        Err(e) => eprintln!("错误: {}", e),
    }

    // let ten_millis = time::Duration::from_millis(10000);
    // let now = time::Instant::now();

    // thread::sleep(ten_millis);
}