RAII wrappers over the Win32 access-token surface — OpenProcessToken,
DuplicateTokenEx, ImpersonateLoggedOnUser, SetThreadToken,
AdjustTokenPrivileges. The single hard invariant: dropping an
ImpersonationGuard calls RevertToSelf — always, including on unwind.
Hand-written impersonation code (Rubeus-style) forgets this on early returns;
here it is structurally impossible.
0.1.0-dev — pre-alpha, expect breaking changes before 0.1.0. Part of
the icedracon Rust offensive-AD ecosystem.
Handle-owning wrappers around the token API described in the
Access Tokens section of the Windows security model (see
processthreadsapi.h and the TOKEN_INFORMATION_CLASS enumeration).
Correctly reads ERROR_NOT_ALL_ASSIGNED from GetLastError on nominal
AdjustTokenPrivileges success — the one thing every hand-rolled
"enable SeDebugPrivilege" snippet on the internet gets wrong.
use windows_token::{Token, Privilege};
fn main() -> windows_token::Result<()> {
let tok = Token::open_current_process()?;
// Enable SeChangeNotifyPrivilege (normal users always hold this).
let _prev = tok.enable_privilege(Privilege::SeChangeNotify)?;
// Impersonation with guaranteed revert:
{
let _g = tok.impersonate_on_thread()?;
// ...do work under the impersonated identity...
} // <- RevertToSelf on drop, including on panic
println!("user = {}", tok.user_sid()?);
println!("il = {:?}", tok.integrity_level()?);
Ok(())
}- Working:
Token::open_current_process/Token::open_process(pid, access)aroundOpenProcessToken.Token::duplicate(ty, level)-> ownedDuplicateTokenExhandle.Token::enable_privilege(Privilege::…)viaLookupPrivilegeValueW+AdjustTokenPrivilegeswith correctERROR_NOT_ALL_ASSIGNEDhandling.Token::impersonate_on_thread()/set_on_current_thread()returning anImpersonationGuard(Drop = RevertToSelf).Token::user_sid()/integrity_level()viaGetTokenInformation(TokenUser | TokenIntegrityLevel).
- Stubbed / next milestone:
OpenThreadTokenis not yet wired (onlyOpenProcessToken).- No
LookupAccountSidW— SIDs render asS-1-...strings only. - No
CreateProcessAsUserW/ restricted-token helpers. - No integration tests against a real DC; only smoke tests on
GetCurrentProcess().
S-tier posture — narrow feature set on windows, no serde / log / async
runtime.
windows0.58 with onlyWin32_Security,Win32_System_Threading,Win32_Security_Authentication_Identity,Win32_Foundationenabled.windows-core0.58 forResult/Errorinterop.thiserror2 for error boilerplate.
windows-lsa— LSA ticket cache access; typical pattern isimpersonate_on_threadthen read the target LUID's cache.windows-sspi-shim— SSPI Negotiate ergonomics; the impersonated identity flows straight intoSspiClient::for_spn.windows-scm— local Service Control Manager wrapper, for the SYSTEM-side of the same workflows.
Together these enable "run adhammer as yourself" and impersonation-based lateral-movement tooling without dragging in Impacket or Rubeus.
MIT © 2026 zevs