获得进程映像文件 (中)

来源:互联网 发布:修改为21端口 编辑:程序博客网 时间:2024/04/30 13:13

NTSTATUS
PsReferenceProcessFilePointer (
    IN PEPROCESS Process,
    OUT PVOID *OutFileObject
    )

/*++

Routine Description:

    This routine returns a referenced pointer to the FilePointer of Process.  
    This is a rundown protected wrapper around MmGetFileObjectForSection.

Arguments:

    Process - Supplies the process to query.

    OutFileObject - Returns the file object backing the requested section if
                    success is returned.

Return Value:

    NTSTATUS.
   
Environment:

    Kernel mode, PASSIVE_LEVEL.

--*/

{
    PFILE_OBJECT FileObject;

    PAGED_CODE();
   
    if (!ExAcquireRundownProtection (&Process->RundownProtect)) {
        return STATUS_UNSUCCESSFUL;
    }

    if (Process->SectionObject == NULL) {
        ExReleaseRundownProtection (&Process->RundownProtect);
        return STATUS_UNSUCCESSFUL;
    }

    FileObject = MmGetFileObjectForSection ((PVOID)Process->SectionObject);

    *OutFileObject = FileObject;

    ObReferenceObject (FileObject);

    ExReleaseRundownProtection (&Process->RundownProtect);

    return STATUS_SUCCESS;
}


NTSTATUS
SeInitializeProcessAuditName (
    __in __typefix(PFILE_OBJECT) PVOID FileObject,
    __in BOOLEAN bIgnoreAuditPolicy,
    __deref_out POBJECT_NAME_INFORMATION *pAuditName
    )

/*++

Routine Description:

    This routine initializes the executable name for auditing purposes.  It allocates memory for the
    image file name.  This memory is pointed to by pAuditName.  

Arguments:

    FileObject - Supplies a pointer to a file object for the image being
                 executed.
                 
    bIgnoreAuditPolicy - boolean that indicates that the call should proceed without
        regard to the system's auditing policy.         

    pAuditName - Supplies a pointer to a pointer for the object name information.

Return value:

    NTSTATUS.

Environment:

    KeAttached to the target process so not all system services are available.

--*/

{
    NTSTATUS Status;
    OBJECT_NAME_INFORMATION TempNameInfo;
    ULONG ObjectNameInformationLength;
    POBJECT_NAME_INFORMATION pInternalAuditName;
    PFILE_OBJECT FilePointer;

    PAGED_CODE();

    ASSERT (pAuditName != NULL);
    *pAuditName = NULL;

    //
    // Check if the caller would like to get the process name, even if auditing does not
    // require it.
    //

    if (FALSE == bIgnoreAuditPolicy) {
        //
        // At the time of process creation, this routine should only proceed when Object Access or
        // Detailed Tracking auditing is enabled.  In all other cases, the process name is acquired
        // when it is requested.
        //

        if (!SepAdtAuditThisEventWithContext( AuditCategoryObjectAccess, TRUE, FALSE, NULL ) &&
            !SepAdtAuditThisEventWithContext( AuditCategoryDetailedTracking, TRUE, FALSE, NULL )) {

            return STATUS_SUCCESS;
        }
    }

    FilePointer = (PFILE_OBJECT) FileObject;

    //
    // Compute full path for imagefile.
    // This first call to ObQueryNameString is guaranteed to fail.
    // The ObjectNameInformationLength contains only a
    // UNICODE_STRING, so if this call succeeded it would indicate
    // an imagefile name of length 0.  That is bad, so all return
    // values except STATUS_BUFFER_OVERFLOW (from NTFS) and
    // STATUS_BUFFER_TOO_SMALL (from DFS).  This call gives
    // me the buffer size that I need to store the image name.
    //

    pInternalAuditName = &TempNameInfo;
    ObjectNameInformationLength = sizeof(OBJECT_NAME_INFORMATION);

    Status = ObQueryNameString (FilePointer,
                                pInternalAuditName,
                                ObjectNameInformationLength,
                                &ObjectNameInformationLength);

    if ((Status == STATUS_BUFFER_OVERFLOW) ||
        (Status == STATUS_BUFFER_TOO_SMALL)) {
   
        //
        // Sanity check ObQueryNameString.  Different filesystems
        // may be buggy, so make sure that the return length makes
        // sense (that it has room for a non-NULL Buffer in the
        // UNICODE_STRING).
        //
   
        if (ObjectNameInformationLength > sizeof(OBJECT_NAME_INFORMATION)) {
            pInternalAuditName = ExAllocatePoolWithTag (NonPagedPool,
                                                        ObjectNameInformationLength,
                                                        'aPeS');

            if (pInternalAuditName != NULL) {
                Status = ObQueryNameString (FilePointer,
                                            pInternalAuditName,
                                            ObjectNameInformationLength,
                                            &ObjectNameInformationLength);
            
                if (!NT_SUCCESS(Status)) {
               
#if DBG
                    DbgPrint("/n** ObqueryNameString failed with 0x%x./n", Status);
#endif //DBG

                    //
                    // If the second call to ObQueryNameString did not succeed, then
                    // something is very wrong.  Set the image name to NULL string.
                    //                                          
                    // Free the memory that the first call to ObQueryNameString requested,
                    // and allocate enough space to store an empty UNICODE_STRING.
                    //

                    ExFreePool (pInternalAuditName);
                    ObjectNameInformationLength = sizeof(OBJECT_NAME_INFORMATION);
                    pInternalAuditName = ExAllocatePoolWithTag (NonPagedPool,
                                                                ObjectNameInformationLength,
                                                                'aPeS');
               
                    if (pInternalAuditName != NULL) {
                        RtlZeroMemory(pInternalAuditName, ObjectNameInformationLength);
                    
                        //
                        // Status = STATUS_SUCCESS to allow the process creation to continue.
                        //

                        Status = STATUS_SUCCESS;
                    } else {
                        Status = STATUS_NO_MEMORY;
                    }
                }
            } else {
                Status = STATUS_NO_MEMORY;
            }
        } else {
        
            //
            // If this happens, then ObQueryNameString is broken for the FS on which
            // it was called.
            //

#if DBG
            DbgPrint("/n** ObqueryNameString failed with 0x%x./n", Status);
#endif //DBG

            ObjectNameInformationLength = sizeof(OBJECT_NAME_INFORMATION);
            pInternalAuditName = ExAllocatePoolWithTag (NonPagedPool,
                                                        ObjectNameInformationLength,
                                                        'aPeS');

            if (pInternalAuditName != NULL) {
                RtlZeroMemory(pInternalAuditName, ObjectNameInformationLength);
            
                //
                // Status = STATUS_SUCCESS to allow the process creation to continue.
                //

                Status = STATUS_SUCCESS;
            } else {
                Status = STATUS_NO_MEMORY;
            }
        }
    } else {

        //
        // If ObQueryNameString returns some other error code, we cannot
        // be certain of which action to take, or whether it has properly
        // set the ReturnLength.  For example, ObQueryNameString has slightly
        // different semantics under DFS than NTFS.  Additionally, 3rd
        // party file systems may also behave unpredictably.  For these reasons,
        // in the case of an unexpected error code from ObQueryNameString
        // we set AuditName to zero length unicode string and allow process
        // creation to continue.
        //
   
#if DBG
        DbgPrint("/n** ObqueryNameString failed with 0x%x./n", Status);
#endif //DBG

        ObjectNameInformationLength = sizeof(OBJECT_NAME_INFORMATION);
        pInternalAuditName = ExAllocatePoolWithTag(NonPagedPool, ObjectNameInformationLength, 'aPeS');

        if (pInternalAuditName != NULL) {
            RtlZeroMemory(pInternalAuditName, ObjectNameInformationLength);

            //
            // Status = STATUS_SUCCESS to allow the process creation to continue.
            //

            Status = STATUS_SUCCESS;
        } else {
            Status = STATUS_NO_MEMORY;
        }
    }

    *pAuditName = pInternalAuditName;

    return Status;
}
NTSTATUS
SeLocateProcessImageName(
    __in PEPROCESS Process,
    __deref_out PUNICODE_STRING *pImageFileName
    )

/*++

Routine Description
   
    This routine returns the ImageFileName information from the process, if available.  This is a "lazy evaluation" wrapper
    around SeInitializeProcessAuditName.  If the image file name information has already been computed, then this call simply
    allocates and returns a UNICODE_STRING with this information.  Otherwise, the function determines the name, stores the name in the
    EPROCESS structure, and then allocates and returns a UNICODE_STRING.  Caller must free the memory returned in pImageFileName.
   
Arguments

    Process - process for which to acquire the name
   
    pImageFileName - output parameter to return name to caller
   
Return Value

    NTSTATUS.
   
--*/

{
    NTSTATUS                 Status            = STATUS_SUCCESS;
    PVOID                    FilePointer       = NULL;
    PVOID                    PreviousValue     = NULL;
    POBJECT_NAME_INFORMATION pProcessImageName = NULL;
    PUNICODE_STRING          pTempUS           = NULL;
    ULONG                    NameLength        = 0;

    PAGED_CODE();

    *pImageFileName = NULL;
   
    if (NULL == Process->SeAuditProcessCreationInfo.ImageFileName) {

        //
        // The name has not been predetermined.  We must determine the process name.   First, reference the
        // PFILE_OBJECT and lookup the name.  Then again check the process image name pointer against NULL.  
        // Finally, set the name.
        //

        Status = PsReferenceProcessFilePointer( Process, &FilePointer );
        
        if (NT_SUCCESS(Status)) {

            //
            // Get the process name information.  
            //

            Status = SeInitializeProcessAuditName(
                          FilePointer,
                          TRUE, // skip audit policy
                          &pProcessImageName // to be allocated in nonpaged pool
                          );

            if (NT_SUCCESS(Status)) {

                //
                // Only use the pProcessImageName if the field in the process is currently NULL.
                //

                PreviousValue = InterlockedCompareExchangePointer(
                                    (PVOID *) &Process->SeAuditProcessCreationInfo.ImageFileName,
                                    (PVOID) pProcessImageName,
                                    (PVOID) NULL
                                    );
               
                if (NULL != PreviousValue) {
                    ExFreePool(pProcessImageName); // free what we caused to be allocated.
                }
            }
            ObDereferenceObject( FilePointer );
        }
    }
   
   
    if (NT_SUCCESS(Status)) {
        
        //
        // Allocate space for a buffer to contain the name for returning to the caller.
        //

        NameLength = sizeof(UNICODE_STRING) + Process->SeAuditProcessCreationInfo.ImageFileName->Name.MaximumLength;
        pTempUS = ExAllocatePoolWithTag( NonPagedPool, NameLength, 'aPeS' );

        if (NULL != pTempUS) {

            RtlCopyMemory(
                pTempUS,
                &Process->SeAuditProcessCreationInfo.ImageFileName->Name,
                NameLength
                );

            pTempUS->Buffer = (PWSTR)(((PUCHAR) pTempUS) + sizeof(UNICODE_STRING));
            *pImageFileName = pTempUS;

        } else {
            
            Status = STATUS_NO_MEMORY;
        }
    }

    return Status;
}