Introduction
From theory, the request to kernel driver from user space application is handled in the user application thread. Cool, so there should be SID associated... To get SID in user space application is about two lines, but how to do we do it in kernel? Is it possible? Yep it is, and here comes code snippet, which can save you a substantial quantum of reading...
Using the code
The first function GetCurrentThreadSid obtains SID in binary form into newly allocated pooled memory (free it with call
to ExFreePoolWithTag). GetCurrentThreadUnicodeStringSid converts binary SID into UTF16 textual form. GetCurrentThreadStringSid converts UTF16 to ANSII.
#include <ntddk.h>
#include <ntifs.h>
NTSTATUS GetCurrentThreadSid(OUT PISID *pSid);
NTSTATUS GetCurrentThreadStringSid(OUT UCHAR **pStringSid, ULONG *pSidLen);
NTSTATUS GetCurrentThreadUnicodeStringSid(OUT PUNICODE_STRING pStringSid);
#pragma alloc_text("PAGED_CODE", GetCurrentThreadSid)
#pragma alloc_text("PAGED_CODE", GetCurrentThreadStringSid)
#pragma alloc_text("PAGED_CODE", GetCurrentThreadUnicodeStringSid)
NTSTATUS GetCurrentThreadSid(OUT PISID *pSid)
{
NTSTATUS ret=STATUS_UNSUCCESSFUL;
PTOKEN_USER user=NULL;
ULONG nTokenInfo=0;
HANDLE hToken=NULL;
ULONG nSidLen=0;
PAGED_CODE()
if(!pSid)
return STATUS_INVALID_PARAMETER;
ret=ZwOpenThreadTokenEx( ZwCurrentThread(), GENERIC_READ, TRUE, OBJ_KERNEL_HANDLE , &hToken);
if(ret!=STATUS_SUCCESS)
{
ret=ZwOpenProcessTokenEx(ZwCurrentProcess() ,GENERIC_READ, OBJ_KERNEL_HANDLE , &hToken);
if(!hToken)
goto cleanup;
}
ret=ZwQueryInformationToken(hToken,TokenUser ,NULL, 0, &nTokenInfo);
if(ret!=STATUS_BUFFER_TOO_SMALL)
goto cleanup;
user=(PTOKEN_USER)ExAllocatePoolWithTag(PagedPool, nTokenInfo, 'N000');
if(!user)
{
ret=STATUS_NO_MEMORY;
goto cleanup;
}
ret=ZwQueryInformationToken(hToken,TokenUser ,user, nTokenInfo, &nTokenInfo);
if(ret!=STATUS_SUCCESS)
goto cleanup;
if(!RtlValidSid(user->User.Sid))
{
ret=STATUS_UNSUCCESSFUL;
goto cleanup;
}
nSidLen=RtlLengthSid(user->User.Sid);
*pSid=(PISID)ExAllocatePoolWithTag(PagedPool, nSidLen, 'N000');
if(!*pSid)
{
ret=STATUS_NO_MEMORY;
goto cleanup;
}
RtlCopyMemory(*pSid,user->User.Sid,nSidLen);
if(!RtlValidSid(*pSid))
{
ExFreePoolWithTag(*pSid, 'N000');
*pSid=NULL;
ret=STATUS_UNSUCCESSFUL;
goto cleanup;
}
ret=STATUS_SUCCESS;
cleanup:
if(user)
ExFreePoolWithTag(user, 'N000');
if(hToken)
ZwClose(hToken);
return ret;
}
NTSTATUS GetCurrentThreadUnicodeStringSid(OUT PUNICODE_STRING pStringSid)
{
NTSTATUS ret=STATUS_UNSUCCESSFUL;
PISID pSid=NULL;
PAGED_CODE()
if(!pStringSid)
return STATUS_INVALID_PARAMETER;
ret=GetCurrentThreadSid(&pSid);
if(ret!=STATUS_SUCCESS)
return ret;
ret=RtlConvertSidToUnicodeString(pStringSid,pSid,TRUE);
ExFreePoolWithTag(pSid, 'N000');
return ret;
}
NTSTATUS GetCurrentThreadStringSid(OUT UCHAR **pStringSid, OUT ULONG *pSidLen)
{
NTSTATUS ret=STATUS_UNSUCCESSFUL;
UNICODE_STRING StringSid={0};
ULONG i;
ULONG charlen=0;
PAGED_CODE()
if(!pStringSid || !pSidLen)
return STATUS_INVALID_PARAMETER;
ret=GetCurrentThreadUnicodeStringSid(&StringSid);
if(ret!=STATUS_SUCCESS)
return ret;
charlen=StringSid.Length/sizeof(WCHAR);
*pStringSid=ExAllocatePoolWithTag(PagedPool, charlen+1,'N000');
if(!*pStringSid)
{
ret=STATUS_NO_MEMORY;
goto cleanup;
}
for(i=0;i<charlen;i++)
{
(*pStringSid)[i]=(UCHAR)StringSid.Buffer[i];
}
(*pStringSid)[charlen]=0;
*pSidLen=charlen;
ret=STATUS_SUCCESS;
cleanup:
RtlFreeUnicodeString(&StringSid);
return ret;
}History
Fixed hToken closing and string length in conversion from UTF16 to ANSI. Added zipped source codes.