diff --git a/inc/usersim/ps.h b/inc/usersim/ps.h index 8469042..3ce5133 100644 --- a/inc/usersim/ps.h +++ b/inc/usersim/ps.h @@ -104,4 +104,14 @@ void usersime_invoke_process_creation_notify_routine( _Inout_ PEPROCESS process, _In_ HANDLE process_id, _Inout_opt_ PPS_CREATE_NOTIFY_INFO create_info); +typedef PACCESS_TOKEN PEPROCESS_ACCESS_TOKEN; + +USERSIM_API +PACCESS_TOKEN +PsReferencePrimaryToken(_In_ PEPROCESS process); + +USERSIM_API +VOID +PsDereferencePrimaryToken(_In_ PACCESS_TOKEN token); + CXPLAT_EXTERN_C_END diff --git a/inc/usersim/se.h b/inc/usersim/se.h index 5a88506..064f229 100644 --- a/inc/usersim/se.h +++ b/inc/usersim/se.h @@ -5,6 +5,7 @@ #include "..\src\platform.h" #include "ke.h" +#include "rtl.h" CXPLAT_EXTERN_C_BEGIN @@ -180,6 +181,20 @@ USERSIM_API NTSTATUS SeQueryAuthenticationIdToken(_In_ PACCESS_TOKEN token, _Out_ PLUID authentication_id); +USERSIM_API +NTSTATUS +SeQueryInformationToken(_In_ PACCESS_TOKEN token, _In_ TOKEN_INFORMATION_CLASS token_information_class, _Out_ PVOID* token_information); + +USERSIM_API +NTSTATUS +SecLookupAccountSid( + _In_ PSID Sid, + _Inout_ PULONG NameSize, + _Out_opt_ PUNICODE_STRING Name, + _Inout_ PULONG DomainSize, + _Out_opt_ PUNICODE_STRING Domain, + _Out_ PSID_NAME_USE SidNameUse); + void usersim_initialize_se(); diff --git a/src/ps.cpp b/src/ps.cpp index bb636bd..576e993 100644 --- a/src/ps.cpp +++ b/src/ps.cpp @@ -212,4 +212,19 @@ usersime_invoke_process_creation_notify_routine( if (_usersim_process_creation_notify_routine != NULL) { _usersim_process_creation_notify_routine(process, process_id, create_info); } +} + +PACCESS_TOKEN +PsReferencePrimaryToken(_In_ PEPROCESS process) +{ + UNREFERENCED_PARAMETER(process); + // In user mode, return the current process token handle as a pseudo-token. + return (PACCESS_TOKEN)GetCurrentProcessToken(); +} + +VOID +PsDereferencePrimaryToken(_In_ PACCESS_TOKEN token) +{ + UNREFERENCED_PARAMETER(token); + // No-op in user mode; GetCurrentProcessToken() returns a pseudo-handle. } \ No newline at end of file diff --git a/src/se.cpp b/src/se.cpp index 9de85ba..8a637b8 100644 --- a/src/se.cpp +++ b/src/se.cpp @@ -250,3 +250,132 @@ SeQueryAuthenticationIdToken(_In_ PACCESS_TOKEN token, _Out_ PLUID authenticatio usersim_convert_sid_to_luid(((PTOKEN_OWNER)token_owner_buffer)->Owner, authentication_id); return STATUS_SUCCESS; } + +NTSTATUS +SeQueryInformationToken(_In_ PACCESS_TOKEN token, _In_ TOKEN_INFORMATION_CLASS token_information_class, _Out_ PVOID* token_information) +{ + *token_information = nullptr; + + if (cxplat_fault_injection_inject_fault()) { + return STATUS_UNSUCCESSFUL; + } + + HANDLE token_handle = (HANDLE)token; + DWORD needed = 0; + + // Get required buffer size. + (void)GetTokenInformation(token_handle, token_information_class, nullptr, 0, &needed); + DWORD error = GetLastError(); + if (error != ERROR_INSUFFICIENT_BUFFER || needed == 0) { + return win32_error_to_usersim_error(error); + } + + // Allocate buffer (caller frees with ExFreePool). + void* buffer = ExAllocatePoolUninitialized(NonPagedPoolNx, needed, USERSIM_TAG_TOKEN_ACCESS_INFORMATION); + if (buffer == nullptr) { + return STATUS_NO_MEMORY; + } + + if (!GetTokenInformation(token_handle, token_information_class, buffer, needed, &needed)) { + ExFreePool(buffer); + return win32_error_to_usersim_error(GetLastError()); + } + + *token_information = buffer; + return STATUS_SUCCESS; +} + +NTSTATUS +SecLookupAccountSid( + _In_ PSID Sid, + _Inout_ PULONG NameSize, + _Out_opt_ PUNICODE_STRING Name, + _Inout_ PULONG DomainSize, + _Out_opt_ PUNICODE_STRING Domain, + _Out_ PSID_NAME_USE SidNameUse) +{ + if (cxplat_fault_injection_inject_fault()) { + return STATUS_UNSUCCESSFUL; + } + + if (Sid == nullptr || NameSize == nullptr || DomainSize == nullptr || SidNameUse == nullptr) { + return STATUS_INVALID_PARAMETER; + } + + // Use LookupAccountSidW to resolve the SID in user mode. + DWORD name_chars = 0; + DWORD domain_chars = 0; + SID_NAME_USE name_use; + + // First call to get required buffer sizes (in characters including null terminator). + (void)LookupAccountSidW(nullptr, Sid, nullptr, &name_chars, nullptr, &domain_chars, &name_use); + DWORD error = GetLastError(); + if (error != ERROR_INSUFFICIENT_BUFFER) { + return win32_error_to_usersim_error(error); + } + + // If caller just wants sizes (Name and Domain are NULL), return sizes in bytes. + if (Name == nullptr && Domain == nullptr) { + // Return sizes as byte counts (without null terminator) to match kernel SecLookupAccountSid behavior. + *NameSize = (name_chars > 0) ? (ULONG)((name_chars - 1) * sizeof(WCHAR)) : 0; + *DomainSize = (domain_chars > 0) ? (ULONG)((domain_chars - 1) * sizeof(WCHAR)) : 0; + *SidNameUse = name_use; + return STATUS_BUFFER_TOO_SMALL; + } + + // Allocate temporary buffers for the LookupAccountSidW call. + WCHAR* name_buf = nullptr; + WCHAR* domain_buf = nullptr; + + if (name_chars > 0) { + name_buf = (WCHAR*)malloc(name_chars * sizeof(WCHAR)); + if (name_buf == nullptr) { + return STATUS_NO_MEMORY; + } + } + if (domain_chars > 0) { + domain_buf = (WCHAR*)malloc(domain_chars * sizeof(WCHAR)); + if (domain_buf == nullptr) { + free(name_buf); + return STATUS_NO_MEMORY; + } + } + + if (!LookupAccountSidW(nullptr, Sid, name_buf, &name_chars, domain_buf, &domain_chars, &name_use)) { + free(name_buf); + free(domain_buf); + return win32_error_to_usersim_error(GetLastError()); + } + + // Copy results into caller-provided UNICODE_STRING buffers. + // The kernel SecLookupAccountSid returns Length in bytes (without null terminator). + if (Name != nullptr && Name->Buffer != nullptr && name_chars > 0) { + USHORT byte_len = (USHORT)((name_chars) * sizeof(WCHAR)); + if (byte_len > Name->MaximumLength) { + byte_len = Name->MaximumLength; + } + memcpy(Name->Buffer, name_buf, byte_len); + Name->Length = byte_len; + *NameSize = byte_len; + } else { + *NameSize = 0; + } + + if (Domain != nullptr && Domain->Buffer != nullptr && domain_chars > 0) { + USHORT byte_len = (USHORT)((domain_chars) * sizeof(WCHAR)); + if (byte_len > Domain->MaximumLength) { + byte_len = Domain->MaximumLength; + } + memcpy(Domain->Buffer, domain_buf, byte_len); + Domain->Length = byte_len; + *DomainSize = byte_len; + } else { + *DomainSize = 0; + } + + *SidNameUse = name_use; + + free(name_buf); + free(domain_buf); + return STATUS_SUCCESS; +}