2013年11月15日星期五

在驱动中获取进程的用户名及SID

/*
文件名:GetSecurityUserInfo.C

功能:获取当前操作注册表的进程的用户.

SOURCE文件内容如下:
TARGETNAME=test

TARGETTYPE=DRIVER

TARGETLIBS=$(DDK_LIB_PATH)\ksecdd.lib 

SOURCES=GetSecurityUserInfo.C 

TARGETPATH=obj

made by correy
made at 2013.11.15
email:kouleguan at hotmail dot com
homepage:http://correy.webs.com
不足之处,敬请指出.
*/

#include <ntifs.h>

LARGE_INTEGER  Cookie;

NTSTATUS print_current_user()
    /*
    打印当前操作的当前进程的用户名等.
    */
{
    NTSTATUS status = 0;
    PACCESS_TOKEN pat = 0;    
    UNICODE_STRING  SidString = {0};
    PTOKEN_STATISTICS pts;
    PSecurityUserData  PUserInformation;

    pat = PsReferencePrimaryToken(PsGetCurrentProcess());    

    status = SeQueryInformationToken(pat, TokenStatistics,(PVOID *) & pts);
    if( !NT_SUCCESS( status ) )
    {
        PsDereferencePrimaryToken(pat);
        return status;
    }

    //还有一种情况也会发生如下情况,就是在Windows server 2008 X64上,具体的有待检查和添加.
    if (pts->AuthenticationId.HighPart == 0 && pts->AuthenticationId.LowPart == 999)//为何是这两个数,不得而知.
    {
        //获取到了系统帐户,就是system,本地系统帐户.
        //打印的消息一般如下:
        //UserName :KOUDAQIANG-2008$
        //LogonServer :
        //LogonDomainName :WORKGROUP
        //SID :S-1-5-18

        KdPrint(("UserName:system\n"));

        PsDereferencePrimaryToken(pat);
        return status;
    }

    //可以考虑把下面的代码写成工作线程.

    //下面的函数需要连接Ksecdd.lib,如:TARGETLIBS=$(DDK_LIB_PATH)\ksecdd.lib
    status = GetSecurityUserInfo(&pts->AuthenticationId, 0, &PUserInformation);
    if( !NT_SUCCESS( status ) )
    {
        return status;
    }

    //status = RtlConvertSidToUnicodeString(&SidString, PUserInformation->pSid,TRUE);
    //if( !NT_SUCCESS( status ) )//成功.#define STATUS_INVALID_SID               ((NTSTATUS)0xC0000078L)   -1073741704
    //{
    //    return status;
    //}        

    KdPrint(("UserName:%wZ\n",&PUserInformation->UserName));
    //KdPrint(("LogonServer :%wZ\n",&PUserInformation->LogonServer));
    //KdPrint(("LogonDomainName :%wZ\n",&PUserInformation->LogonDomainName));
    //KdPrint(("SID :%wZ\n",&SidString));

    //RtlFreeUnicodeString(&SidString); 
    LsaFreeReturnBuffer(PUserInformation);

    PsDereferencePrimaryToken(pat);

    return status;
}

EX_CALLBACK_FUNCTION RegistryCallback;
NTSTATUS RegistryCallback(__in PVOID  CallbackContext, __in_opt PVOID  Argument1, __in_opt PVOID  Argument2)
{
    print_current_user();

    return STATUS_SUCCESS;
}

DRIVER_UNLOAD Unload;
VOID Unload(__in PDRIVER_OBJECT DriverObject)
{   
    CmUnRegisterCallback(Cookie);
}

#pragma INITCODE
DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry(__in struct _DRIVER_OBJECT * DriverObject, __in PUNICODE_STRING RegistryPath)
{
    KdBreakPoint();

    DriverObject->DriverUnload = Unload; 

    return CmRegisterCallback(RegistryCallback, NULL, &Cookie);
} 

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/*
文件名:RtlFormatCurrentUserKeyPath.C

功能:获取当前操作注册表的进程的用户的SID.

made by correy
made at 2014.06.14
homepage:http://correy.webs.com
不足之处,敬请指出.
*/

#include <ntifs.h>
#include <windef.h>

//#pragma comment (lib,"ksecdd.lib")

LARGE_INTEGER  Cookie;


//http://msdn.microsoft.com/en-us/library/ff899322(v=vs.85).aspx 
//Initializes the supplied buffer with a string representation of the SID for the current user.
//extern NTSTATUS /*WINAPI*/ RtlFormatCurrentUserKeyPath(/*_Out_*/  UNICODE_STRING CurrentUserKeyPath);  //此函数在XP就已经导出,但直接引用会出现链接错误。
typedef NTSTATUS (WINAPI * RtlFormatCurrentUserKeyPath)(/*_Out_*/  UNICODE_STRING * CurrentUserKeyPath); //那咱就动态获取吧!
//CurrentUserKeyPath [out]
//String that represents the current user's root key in the Registry. Caller must call RtlFreeUnicodeString to free the buffer when done with it.
/*
注意:微软的官方的链接里面是错误的。
开始我还以为这是我第一个发现参数传递结构,而不是指针的。
*/

RtlFormatCurrentUserKeyPath g_p_RtlFormatCurrentUserKeyPath;


PVOID ExpAllocateStringRoutine (IN SIZE_T NumberOfBytes)
{
    return ExAllocatePoolWithTag (PagedPool,NumberOfBytes,'grtS');
}
//上下的定义摘自:\wrk\WindowsResearchKernel-WRK\WRK-v1.2\base\ntos\ex\pool.c
#ifdef ALLOC_DATA_PRAGMA
#pragma const_seg("PAGECONST")
#endif
const PRTL_ALLOCATE_STRING_ROUTINE RtlAllocateStringRoutine = ExpAllocateStringRoutine;
const PRTL_FREE_STRING_ROUTINE RtlFreeStringRoutine = (PRTL_FREE_STRING_ROUTINE)ExFreePool;
#ifdef ALLOC_DATA_PRAGMA
#pragma const_seg()
#endif


// Maximum size of TOKEN_USER information.
#define SIZE_OF_TOKEN_INFORMATION                   \
    sizeof( TOKEN_USER )                            \
    + sizeof( SID )                                 \
    + sizeof( ULONG ) * SID_MAX_SUB_AUTHORITIES
//这个函数及上面的定义摘自WRK-v1.2/base/ntos/rtl/regutil.c,但是有修改,可以在驱动中使用或者利用。
NTSTATUS RtlFormatCurrentUserKeyPath0(OUT PUNICODE_STRING CurrentUserKeyPath)
/*++
Routine Description:
    Initialize the supplied buffer with a string representation of the current user's SID.
    这个函数还是有必要说明几点:
    1.要获取当前用户的SID,首先的不是判断SID而是当前用户,再获取SID这很容易。
      一台计算机同时登陆几个不同的用户是正常的。
      通常一个普通的用户一个会话,包括远程登录的。
      所以另一个捷径是判断会话,这有公开/导出的函数。如某个进程或者线程属于哪个会话。
    2.此函数有发掘利用的价值,看你怎么用了。
    3.此函数获取的不是当前登录用户的SID,而是当前的操作的进程的用户的SID,如系统帐户,网络帐户,服务帐户等。

Arguments:
    CurrentUserKeyPath - Returns a string that represents the current user's root key in the Registry.  
    Caller must call RtlFreeUnicodeString to free the buffer when done with it.

Return Value:
    NTSTATUS - Returns STATUS_SUCCESS if the user string was succesfully initialized.
--*/
{
    HANDLE TokenHandle = 0;
    UCHAR TokenInformation[ SIZE_OF_TOKEN_INFORMATION ];
    ULONG ReturnLength;
    ULONG SidStringLength = 0 ;//添加初始化为0.
    UNICODE_STRING SidString ;
    NTSTATUS Status;

    // Inside the kernel we can tell rapidly if we are impersonating.
    Status = STATUS_NO_TOKEN;
    if (PsIsThreadTerminating (PsGetCurrentThread ())) {//原来是PS_IS_THREAD_IMPERSONATING。
        Status = ZwOpenThreadTokenEx (NtCurrentThread(), TOKEN_READ, TRUE, OBJ_KERNEL_HANDLE, &TokenHandle);
        if ( !NT_SUCCESS( Status ) && ( Status != STATUS_NO_TOKEN ) ) {
            return Status;
        }
    }

    if ( !NT_SUCCESS( Status ) ) {
        Status = ZwOpenProcessTokenEx (NtCurrentProcess(), TOKEN_READ, OBJ_KERNEL_HANDLE, &TokenHandle);
        if ( !NT_SUCCESS( Status )) {
            return Status;
        }
    }

    Status = ZwQueryInformationToken( TokenHandle, TokenUser, TokenInformation, sizeof( TokenInformation ), &ReturnLength);
    ZwClose( TokenHandle );
    if ( !NT_SUCCESS( Status )) {
        return Status;
    }

    //Status = RtlLengthSidAsUnicodeString(((PTOKEN_USER)TokenInformation)->User.Sid, &SidStringLength);
    //if ( !NT_SUCCESS( Status ) ) {
    //    return Status ;
    //}
    //因为RtlLengthSidAsUnicodeString在XP上没有导出,所以用下面的两个函数替换。
    if (!RtlValidSid(((PTOKEN_USER)TokenInformation)->User.Sid)) {
        return Status ;
    }
    SidStringLength = RtlLengthSid(((PTOKEN_USER)TokenInformation)->User.Sid);
    if (!SidStringLength) {
        return Status ;
    }

    CurrentUserKeyPath->Length = 0;
    CurrentUserKeyPath->MaximumLength = (USHORT)(SidStringLength + sizeof( L"\\REGISTRY\\USER\\" ) + sizeof( UNICODE_NULL ));
    CurrentUserKeyPath->Buffer = (RtlAllocateStringRoutine)( CurrentUserKeyPath->MaximumLength );
    if (CurrentUserKeyPath->Buffer == NULL) {
        return STATUS_NO_MEMORY;
    }
        
    RtlAppendUnicodeToString( CurrentUserKeyPath, L"\\REGISTRY\\USER\\" );// Copy "\REGISTRY\USER" to the current user string.

    SidString.MaximumLength = CurrentUserKeyPath->MaximumLength;//(USHORT)SidStringLength ;这里有修改 原数乘以2应该也可以的,不然RtlConvertSidToUnicodeString失败。
    SidString.Length = 0 ;
    SidString.Buffer = CurrentUserKeyPath->Buffer + (CurrentUserKeyPath->Length / sizeof(WCHAR) );

    Status = RtlConvertSidToUnicodeString( &SidString, ((PTOKEN_USER)TokenInformation)->User.Sid, FALSE);
    if ( !NT_SUCCESS( Status )) {//#define STATUS_BUFFER_OVERFLOW           ((NTSTATUS)0x80000005L)
        RtlFreeUnicodeString( CurrentUserKeyPath );
    } else {
        CurrentUserKeyPath->Length += SidString.Length ;
    }

    return Status;
}


NTSTATUS print_current_user()
    /*
    打印当前操作的当前进程的用户名等.
    */
{
    NTSTATUS status = 0;
    UNICODE_STRING CurrentUserKeyPath = {0};

    status = g_p_RtlFormatCurrentUserKeyPath(&CurrentUserKeyPath);
    if( !NT_SUCCESS( status ) )
    {
        return status;
    }
    KdPrint(("CurrentUserKeyPath:%wZ\n",&CurrentUserKeyPath));//"\REGISTRY\USER\S-1-5-18"
    RtlFreeUnicodeString(&CurrentUserKeyPath);


    status = RtlFormatCurrentUserKeyPath0(&CurrentUserKeyPath);
    if( !NT_SUCCESS( status ) )
    {
        return status;
    }
    KdPrint(("CurrentUserKeyPath:%wZ\n",&CurrentUserKeyPath));//"\REGISTRY\USER\S-1-5-18"
    RtlFreeUnicodeString(&CurrentUserKeyPath);

    return status;
}

EX_CALLBACK_FUNCTION RegistryCallback;
NTSTATUS RegistryCallback(__in PVOID  CallbackContext, __in_opt PVOID  Argument1, __in_opt PVOID  Argument2)
{
    print_current_user();
    return STATUS_SUCCESS;
}

DRIVER_UNLOAD Unload;
VOID Unload(__in PDRIVER_OBJECT DriverObject)
{   
    CmUnRegisterCallback(Cookie);
}

#pragma INITCODE
DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry(__in struct _DRIVER_OBJECT * DriverObject, __in PUNICODE_STRING RegistryPath)
{
    UNICODE_STRING us_RtlFormatCurrentUserKeyPath;

    KdBreakPoint();

    DriverObject->DriverUnload = Unload; 

    RtlInitUnicodeString( &us_RtlFormatCurrentUserKeyPath, L"RtlFormatCurrentUserKeyPath" );
    g_p_RtlFormatCurrentUserKeyPath = MmGetSystemRoutineAddress(&us_RtlFormatCurrentUserKeyPath);
    if (g_p_RtlFormatCurrentUserKeyPath == NULL)
    {
        return STATUS_UNSUCCESSFUL;
    }

    return CmRegisterCallback(RegistryCallback, NULL, &Cookie);
} 

没有评论:

发表评论