How do I get the current users SID in Windows 10/11? (ntapi)

i can't seem to make a function that gets the current users SID, only using the ntapi crate (nt functions only), and im hoping to have something functional. May someone please help me get this? thank you.

also, this function hasn't been implemented using just the winapi crate yet, maybe that will be a good start, and to go from there

What have you tried, and how does it fail? Can you show us the code of your best attempt so far, since we can iterate on that to help you fix it and understand why it didn't work.

i haven't really drafted anything in c++ or rust, but heres a stack overflow question to give a general idea, c# - How can I get the SID of the current Windows account? - Stack Overflow

as for nt functions the i believe NtQueryInformationToken, NtOpenThreadToken, NtOpenProcessToken may be in use, in conclusion, i need the users SID represented as a rust string

This is what i have so far

pub fn get_sid() {
    unsafe {
        let mut h_token: *mut c_void = null_mut();
        if OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &mut h_token) == 0 {
            panic!();
        }

        let user_token: *mut c_void = null_mut();
        let mut return_length: DWORD = 0;

        if GetTokenInformation(h_token, TokenUser, user_token, 1024, &mut return_length) == 0 {}
    }
}

I'm curious: do you have a non-suspicious reason to want to use the undocumented internal ntapi rather than the public API? 90% of the time FrobleWidget() is just forwarding to NtFrobleWidget() anyway.

Only time I've seen people wanting to use that is because there's some special ability not exposed in the public API or to avoid (presumably bad) virus scanners.

Hopefully this will get you on your way...

Cargo.toml

[package]
name = "cusid"
version = "0.1.0"
edition = "2021"

[dependencies]
grob = "0.1.3"

[target.'cfg(windows)'.dependencies.windows]
version = "0.48"
features = [
    "Win32_Foundation",
    "Win32_Security",
    "Win32_System_Threading",
]

main.rs

use grob::{RvIsError, winapi_small_binary};
use windows::Win32::Foundation::HANDLE;
use windows::Win32::Security::{GetTokenInformation, SID, TokenUser, TOKEN_QUERY, TOKEN_USER};
use windows::Win32::System::Threading::{GetCurrentProcess, OpenProcessToken};

fn main() -> Result<(), Box<dyn std::error::Error>> {

    let h = unsafe { GetCurrentProcess() };
    println!("h = {:?}", h);

    let mut h_token: HANDLE = Default::default();
    let rv = unsafe { OpenProcessToken(h, TOKEN_QUERY, &mut h_token) };
    println!("rv = {:?}", rv);
    println!("h_token = {:?}", h_token);

    let _gti = winapi_small_binary(
        |argument| {
            let rv = unsafe {
                GetTokenInformation(
                    h_token,
                    TokenUser,
                    Some(argument.pointer()),
                    *argument.size(),
                argument.size(),
                )
            };
            RvIsError::new(rv)
        },
        |frozen_buffer| {
            if let Some(fbp) = frozen_buffer.pointer() {
                let tup = fbp as *const TOKEN_USER;
                let attributes = unsafe{(*tup).User.Attributes};
                println!("attributes = {}", attributes);
                let psid = unsafe{(*tup).User.Sid.0} as *const SID;
                println!("psid = {:?}", psid);

                let revision = unsafe{(*psid).Revision};
                println!("revision = {:?}", revision);

                let identifier_authority = unsafe{(*psid).IdentifierAuthority};
                println!("identifier_authority = {:?}", identifier_authority);

                let sub_authority_count = unsafe{(*psid).SubAuthorityCount};
                println!("sub_authority_count = {:?}", sub_authority_count);
                let mut sub_authority = unsafe{(*psid).SubAuthority.as_ptr()};
                for _ in 0..sub_authority_count {
                    println!("sub_authority = {:?}", unsafe{*sub_authority});
                    sub_authority = unsafe{sub_authority.add(1)};
                }
            }
            // The SID could be converted to a string then returned from this closure making it
            // available to the rest of the program.
            Ok(())
        },
    )?;
    Ok(())
}

1 Like

A better version...

Cargo.toml

[package]
name = "cusid"
version = "0.1.0"
edition = "2021"

[dependencies]
grob = "0.1.3"

[target.'cfg(windows)'.dependencies.windows]
version = "0.48"
features = [
    "Win32_Foundation",
    "Win32_Globalization",
    "Win32_Security",
    "Win32_Security_Authorization",
    "Win32_System_Memory",
    "Win32_System_Threading",
]

main.rs

use std::ffi::OsString;
use std::os::windows::ffi::OsStringExt;
use std::slice::from_raw_parts;

use grob::{RvIsError, winapi_small_binary};
use windows::core::{PCWSTR, PWSTR};
use windows::Win32::Foundation::{FALSE, HANDLE, HLOCAL, PSID};
use windows::Win32::Globalization::lstrlenW;
use windows::Win32::Security::{GetTokenInformation, TokenUser, TOKEN_QUERY, TOKEN_USER};
use windows::Win32::Security::Authorization::ConvertSidToStringSidW;
use windows::Win32::System::Memory::LocalFree;
use windows::Win32::System::Threading::{GetCurrentProcess, OpenProcessToken};

struct LocalHeapString {
    inner: PWSTR,
}

impl LocalHeapString {
    fn as_mut_ptr(&mut self) -> &mut PWSTR {
        &mut self.inner
    }
}

impl Default for LocalHeapString {
    fn default() -> Self {
        Self {
            inner: PWSTR::null(),
        }
    }
}

impl Drop for LocalHeapString {
    fn drop(&mut self) {
        if self.inner != PWSTR::null() {
            let free_me: HLOCAL = HLOCAL(self.inner.0 as isize);
            self.inner = PWSTR::null();
            let _ = unsafe { LocalFree(free_me) };
        }
    }
}

impl From<LocalHeapString> for String {
    fn from(value: LocalHeapString) -> Self {
        let as_constant_wide_string: PCWSTR = PCWSTR(value.inner.0);
        let s = unsafe { lstrlenW(as_constant_wide_string) };
        let v = unsafe { from_raw_parts(as_constant_wide_string.0, s as usize) };
        let as_os_string = OsString::from_wide(v);
        let as_rust_string = as_os_string.to_string_lossy();
        as_rust_string.into_owned()
    }
}

fn convert_sid_to_string(value: PSID) -> Result<String, std::io::Error> {
    let mut lhs = LocalHeapString::default();
    if unsafe { ConvertSidToStringSidW(value, lhs.as_mut_ptr()) } == FALSE {
        return Err(std::io::Error::last_os_error());
    }
    Ok(lhs.into())
}

fn get_user_sid_from_token(token: HANDLE) -> Result<String, std::io::Error> {
    winapi_small_binary(
        |argument| {
            let rv = unsafe {
                GetTokenInformation(
                    token,
                    TokenUser,
                    Some(argument.pointer()),
                    *argument.size(),
                argument.size(),
                )
            };
            RvIsError::new(rv)
        },
        |frozen_buffer| {
            if let Some(fbp) = frozen_buffer.pointer() {
                let tup = fbp as *const TOKEN_USER;
                convert_sid_to_string( unsafe {*tup}.User.Sid)
            } else {
                Err(std::io::Error::new(
                    std::io::ErrorKind::Other,
                    "something went terribly wrong"))
            }
        }
    )
}

fn main() -> Result<(), Box<dyn std::error::Error>> {

    let h = unsafe { GetCurrentProcess() };
    // GetCurrentProcess cannot fail

    let mut h_token: HANDLE = Default::default();
    if unsafe { OpenProcessToken(h, TOKEN_QUERY, &mut h_token) } == FALSE {
        return Err(std::io::Error::last_os_error().into());
    }

    let sid = get_user_sid_from_token(h_token)?;
    println!("sid = {}", sid);

    Ok(())
}

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.