首页
社区
课程
招聘
[原创]NtOpenProcess读源码+少量注释
发表于: 2009-6-11 22:39 9178

[原创]NtOpenProcess读源码+少量注释

2009-6-11 22:39
9178

//当我们用远程线程注入DLL到另一个进程空间中时,我们就会经常用到OpenProcess()函数。现在假设我们的进程调用OpenProcess()根据要打开的另一个进程Id号,它是怎么得到那一个进程句柄的。然后根据 这个句柄操作那个进程的。OpenProcess里面会调用 NtOpenProcess()系统调用,其它的很多细节没有分析,我只分析了如何得到句柄。看代码如下(都是操作系统的代码,我只是分析一下,因为技术有限)
NTSTATUS
NtOpenProcess (
    OUT PHANDLE ProcessHandle,
    IN ACCESS_MASK DesiredAccess,
    IN POBJECT_ATTRIBUTES ObjectAttributes,
    IN PCLIENT_ID ClientId OPTIONAL
    )
{   HANDLE Handle;
    KPROCESSOR_MODE PreviousMode;
    NTSTATUS Status;
    PEPROCESS Process;
    PETHREAD Thread;
    CLIENT_ID CapturedCid;
    BOOLEAN ObjectNamePresent;
    BOOLEAN ClientIdPresent;
    ACCESS_STATE AccessState;
    AUX_ACCESS_DATA AuxData;
    BOOLEAN DebugPrivilege;
    PAGED_CODE();
    //
    // Make sure that only one of either ClientId or ObjectName is
    // present.
    //
    PreviousMode = KeGetPreviousMode();
    if (PreviousMode != KernelMode) {//如果这个调用是从OpenProcess引起的就进来,就要检查看内核函数看能不能访问用户空间的地址
        //
        // Since we need to look at the ObjectName field, probe
        // ObjectAttributes and capture object name present indicator.
        //
        try {
            ProbeForWriteHandle(ProcessHandle);
            ProbeForRead(ObjectAttributes,
                         sizeof(OBJECT_ATTRIBUTES),
                         sizeof(ULONG));
            ObjectNamePresent = (BOOLEAN)ARGUMENT_PRESENT(ObjectAttributes->ObjectName);
            if (ARGUMENT_PRESENT(ClientId)) {
                ProbeForRead(ClientId, sizeof(CLIENT_ID), sizeof(ULONG));
                CapturedCid = *ClientId;
                ClientIdPresent = TRUE;
                }
            else {
                ClientIdPresent = FALSE;
                }
            }
        except(EXCEPTION_EXECUTE_HANDLER) {
            return GetExceptionCode();
            }
        }
    else {
                //如果直接从内核下调用的,直接访问就是了
        ObjectNamePresent = (BOOLEAN)ARGUMENT_PRESENT(ObjectAttributes->ObjectName);
        if (ARGUMENT_PRESENT(ClientId)) {
            CapturedCid = *ClientId;
            ClientIdPresent = TRUE;
            }
        else {
            ClientIdPresent = FALSE;
            }
        }
    if ( ObjectNamePresent && ClientIdPresent ) {
        return STATUS_INVALID_PARAMETER_MIX;//如果进程对象名和进程ID号都存在的话,返回参数错误
        }
    //
    // Create an AccessState here, because the caller may have
    // DebugPrivilege, which requires us to make special adjustments
    // to his desired access mask.  We do this by modifying the
    // internal fields in the AccessState to achieve the effect
    // we desire.
    //
    Status = SeCreateAccessState(
                 &AccessState,
                 &AuxData,
                 DesiredAccess,
                 &PsProcessType->TypeInfo.GenericMapping
                 );
    if ( !NT_SUCCESS(Status) ) {
        return Status;
    }
    //
    // Check here to see if the caller has SeDebugPrivilege.  If
    // he does, we will allow him any access he wants to the process.
    // We do this by clearing the DesiredAccess in the AccessState
    // and recording what we want him to have in the PreviouslyGrantedAccess
    // field.
    //
    // Note that this routine performs auditing as appropriate.
    //
    if (NtGlobalFlag & ***_IGNORE_DEBUG_PRIV) {
        DebugPrivilege = TRUE;
    } else
    DebugPrivilege =  SeSinglePrivilegeCheck(
                          SeDebugPrivilege,
                          PreviousMode
                          );
    if (DebugPrivilege) {
    //如果这个进程有SeDebugPrivilege权限就会进入这里进一步设置
        if ( AccessState.RemainingDesiredAccess & MAXIMUM_ALLOWED ) {
            AccessState.PreviouslyGrantedAccess |= PROCESS_ALL_ACCESS;
        } else {
            AccessState.PreviouslyGrantedAccess |= ( AccessState.RemainingDesiredAccess );
        }
        AccessState.RemainingDesiredAccess = 0;//清除这个权限,意味着给了这个进程对要操作的进程对象的所有权限
    }
    if ( ObjectNamePresent ) {
        //
        // Open handle to the process object with the specified desired access,
        // set process handle value, and return service completion status.
        //
        Status = ObOpenObjectByName(
                    ObjectAttributes,
                    PsProcessType,
                    PreviousMode,
                    &AccessState,
                    0,
                    NULL,
                    &Handle
                    ); 这里应该也会在本进程的句柄表中加入一项,并返回这个HANDLE_TABLE_ENTRY数组的下标(进程句柄),这个HANDLE_TABLE_ENTRY结构里的object指向被打开的那个进程对象头的地址        SeDeleteAccessState( &AccessState );
        if ( NT_SUCCESS(Status) ) {
            try {
                *ProcessHandle = Handle;
                }
            except(EXCEPTION_EXECUTE_HANDLER) {
                return Status;
                }
            }
        return Status;
        }
    if ( ClientIdPresent ) {
        Thread = NULL;
        if (CapturedCid.UniqueThread) {
            Status = PsLookupProcessThreadByCid(
                        &CapturedCid,
                        &Process,
                        &Thread
                        );
            if ( !NT_SUCCESS(Status) ) {
                SeDeleteAccessState( &AccessState );
                return Status;
                }
            }
        else {
                        //注意这里的进程ID其实是PspCidTable句柄表中数组的下标(它是全局的,整个系统才一个这样的表)线程ID也是一样的
            Status = PsLookupProcessByProcessId(
                        CapturedCid.UniqueProcess,
                        &Process
                        );//根据进程ID从PspCidTable表中得到进程对象(注意这里是对象体不是对象头)的地址
            if ( !NT_SUCCESS(Status) ) {
                SeDeleteAccessState( &AccessState );
                return Status;
                }
            }
        //
        // OpenObjectByAddress
        //
        Status = ObOpenObjectByPointer(
                    Process,
                    ObjectAttributes->Attributes,
                    &AccessState,
                    0,
                    PsProcessType,
                    PreviousMode,
                    &Handle
                    );//这里应该也会在本进程的句柄表中加入一项,并返回这个HANDLE_TABLE_ENTRY数组的下标(进程句柄),这个HANDLE_TABLE_ENTRY结构里的object指向被打开的那个进程对象头的地址。    SeDeleteAccessState( &AccessState );
        if ( Thread ) {
            ObDereferenceObject(Thread);
            }
        ObDereferenceObject(Process);
        if ( NT_SUCCESS(Status) ) {
            try {
                *ProcessHandle = Handle;
                }
            except(EXCEPTION_EXECUTE_HANDLER) {
                return Status;
                }
            }
        return Status;
        }
    return STATUS_INVALID_PARAMETER_MIX;
}

NTSTATUS
ObOpenObjectByPointer(
    IN PVOID Object,
    IN ULONG HandleAttributes,
    IN PACCESS_STATE PassedAccessState OPTIONAL,
    IN ACCESS_MASK DesiredAccess,
    IN POBJECT_TYPE ObjectType OPTIONAL,
    IN KPROCESSOR_MODE AccessMode,
    OUT PHANDLE Handle
    )
{   
    NTSTATUS Status;
    HANDLE NewHandle;
    POBJECT_HEADER ObjectHeader;
    ACCESS_STATE LocalAccessState;
    PACCESS_STATE AccessState = NULL;
    AUX_ACCESS_DATA AuxData;
    PAGED_CODE();
    ObpValidateIrql( "ObOpenObjectByPointer" );
    Status = ObReferenceObjectByPointer( Object,
                                         0,
                                         ObjectType,
                                         AccessMode
                                       );//这个函数会增加这个对象的引用计数,防止对象管理器删除这个对象,如下ObjectHeader->PointerCount += 1;
    if (NT_SUCCESS( Status )) {
        ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object );
        if (!ARGUMENT_PRESENT( PassedAccessState )) {
            Status = SeCreateAccessState( &LocalAccessState,
                                               &AuxData,
                                               DesiredAccess,
                                               &ObjectHeader->Type->TypeInfo.GenericMapping
                                          );
            if (!NT_SUCCESS( Status )) {
                ObDereferenceObject( Object );
                return(Status);
            }
            AccessState = &LocalAccessState;
        } else {
            AccessState = PassedAccessState;
        }
        if (ObjectHeader->Type->TypeInfo.InvalidAttributes & HandleAttributes) {
                    if (AccessState == &LocalAccessState) {
                SeDeleteAccessState( AccessState );
            }
            ObDereferenceObject( Object );
            return( STATUS_INVALID_PARAMETER );
        }
        Status = ObpCreateHandle( ObOpenHandle,
                                  Object,
                                  ObjectType,
                                  AccessState,
                                  0,
                                  HandleAttributes,
                                  FALSE,
                                  AccessMode,
                                  (PVOID *)NULL,
                                  &NewHandle
                                );
        if (!NT_SUCCESS( Status )) {
            ObDereferenceObject( Object );
            }
        }
    if (NT_SUCCESS( Status )) {
        *Handle = NewHandle;
        }
    else {
        *Handle = NULL;
        }
    if (AccessState == &LocalAccessState) {
        SeDeleteAccessState( AccessState );
    }
    return( Status );
}
NTSTATUS
ObpCreateHandle(
    IN OB_OPEN_REASON OpenReason,
    IN PVOID Object,
    IN POBJECT_TYPE ExpectedObjectType OPTIONAL,
    IN PACCESS_STATE AccessState,
    IN ULONG ObjectPointerBias OPTIONAL,
    IN ULONG Attributes,
    IN BOOLEAN DirectoryLocked,
    IN KPROCESSOR_MODE AccessMode,
    OUT PVOID *ReferencedNewObject OPTIONAL,
    OUT PHANDLE Handle
    )
{
    NTSTATUS Status;
    POBJECT_HEADER ObjectHeader;
    POBJECT_TYPE ObjectType;
    PVOID ObjectTable;
    OBJECT_TABLE_ENTRY ObjectTableEntry;
    HANDLE NewHandle;
    ACCESS_MASK DesiredAccess;
    ACCESS_MASK GrantedAccess;
    ULONG BiasCount;
    PAGED_CODE();
    ObpValidateIrql( "ObpCreateHandle" );
    DesiredAccess = AccessState->RemainingDesiredAccess |
                    AccessState->PreviouslyGrantedAccess;
    ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object );
    ObjectType = ObjectHeader->Type;
    if (ARGUMENT_PRESENT( ExpectedObjectType ) &&
        ObjectType != ExpectedObjectType
       ) {
        if (DirectoryLocked) {
            ObpLeaveRootDirectoryMutex();
            }
        return( STATUS_OBJECT_TYPE_MISMATCH );
        }
    ObjectTableEntry.ObjectHeader = ObjectHeader;//初始化handle_table_entry结构,它用来插入到句柄表中的一项
       //#define ObpGetObjectTable() (PsGetCurrentProcess()->ObjectTable)
        ObjectTable = ObpGetObjectTable();//得到当前进程的句柄表(也就是调用OpenProcess的进程)
    //
    // ObpIncrementHandleCount will perform access checking on the
    // object being opened as appropriate.
    //
    Status = ObpIncrementHandleCount( OpenReason,
                                      PsGetCurrentProcess(),
                                      Object,
                                      ObjectType,
                                      AccessState,
                                      AccessMode,
                                      Attributes
                                    );
    if (AccessState->GenerateOnClose) {
        Attributes |= OBJ_AUDIT_OBJECT_CLOSE;
    }
    ObjectTableEntry.Attributes |= (Attributes & OBJ_HANDLE_ATTRIBUTES);
    DesiredAccess = AccessState->RemainingDesiredAccess |
                    AccessState->PreviouslyGrantedAccess;
    GrantedAccess = DesiredAccess &
                   (ObjectType->TypeInfo.ValidAccessMask |
                    ACCESS_SYSTEM_SECURITY );
    if (DirectoryLocked) {
        ObpLeaveRootDirectoryMutex();
        }
    if (!NT_SUCCESS( Status )) {
        return( Status );
        }
    if (ARGUMENT_PRESENT( ObjectPointerBias )) {
        BiasCount = ObjectPointerBias;
        while (BiasCount--) {
            ObpIncrPointerCount( ObjectHeader );
            }
        }
#if i386 && !FPO
    if (NtGlobalFlag & ***_KERNEL_STACK_TRACE_DB) {
        ObjectTableEntry.GrantedAccessIndex = ObpComputeGrantedAccessIndex( GrantedAccess );
        ObjectTableEntry.CreatorBackTraceIndex = RtlLogStackBackTrace();
        }
    else
#endif // i386 && !FPO
    ObjectTableEntry.GrantedAccess = GrantedAccess;//初始化这个句柄的权限
    NewHandle = ExCreateHandle( ObjectTable, (PHANDLE_ENTRY)&ObjectTableEntry );//它会在本进程的句柄表中加入一项ObjectTableEntry,然后返回这个新的句柄(HANDLE_TABLE_ENTRY数组的下标)这里就是在调用OpenProcess()的进程的句柄表中加入了一项得到了句柄。以后根据这个句柄就能调用很多函数了,比如WriteProcessMemory()需要以进程句柄作为参数的函数。
    if (NewHandle == NULL) {
        if (ARGUMENT_PRESENT( ObjectPointerBias )) {
            BiasCount = ObjectPointerBias;
            while (BiasCount--) {
                ObpDecrPointerCount( ObjectHeader );
                }
            }
        ObpDecrementHandleCount( PsGetCurrentProcess(),
                                 ObjectHeader,
                                 ObjectType,
                                 GrantedAccess
                               );
        return( STATUS_INSUFFICIENT_RESOURCES );
        }
    *Handle = MAKE_OBJECT_HANDLE( NewHandle );
    //
    // If requested, generate audit messages to indicate that a new handle
    // has been allocated.
    //
    // This is the final security operation in the creation/opening of the
    // object.
    //
    if ( AccessState->GenerateAudit ) {
        SeAuditHandleCreation(
            AccessState,
            *Handle
            );
        }
    if (OpenReason == ObCreateHandle) {
        PAUX_ACCESS_DATA AuxData = AccessState->AuxData;
        if ( ( AuxData->PrivilegesUsed != NULL) && (AuxData->PrivilegesUsed->PrivilegeCount > 0) ) {
            SePrivilegeObjectAuditAlarm(
                *Handle,
                &AccessState->SubjectSecurityContext,
                GrantedAccess,
                AuxData->PrivilegesUsed,
                TRUE,
                KeGetPreviousMode()
                );
        }
    }
    if (ARGUMENT_PRESENT( ObjectPointerBias ) &&
        ARGUMENT_PRESENT( ReferencedNewObject )
       ) {
        *ReferencedNewObject = Object;
        }
    return( STATUS_SUCCESS );
}


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 7
支持
分享
最新回复 (7)
雪    币: 205
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
在内核中取个进程句柄怎么这么难 ,有无线程的代码??
2009-6-11 23:17
0
雪    币: 252
活跃值: (13)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
3
无线程的代码么意思?
2009-6-12 00:52
0
雪    币: 221
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
题目改成: 读源码+少量注释
2009-6-12 08:57
0
雪    币: 635
活跃值: (101)
能力值: ( LV12,RANK:420 )
在线值:
发帖
回帖
粉丝
5
同上,标题应改为:读代码+代码注释翻译
2009-6-12 13:43
0
雪    币: 205
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
有没有现成的代码?!
这几天在写一个远程视频传输和控制的应用程序,由一个驱动在内核中配合支持。已实现由应用程序给驱动传入一个进程名,驱动就将这个进程隐藏起来。
但却卡在由进程名或进程id去除进程的DEP(也有资料称NX写保护)上,在内核中怎么都得不到进程的句柄?!!! 请高手出马啊。
2009-6-13 21:14
0
雪    币: 635
活跃值: (101)
能力值: ( LV12,RANK:420 )
在线值:
发帖
回帖
粉丝
7
pslookupprocessbyprocessid->obopenobjectbypointer

写木马就写木马,还:远程视频传输和控制的应用程序,现在的人啊~一点都不厚道
2009-6-13 21:21
0
雪    币: 129
活跃值: (31)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
哈哈,晕死,我以为怎么个分析呢,源来是代码 ++ 少量解析....
2009-6-14 08:49
0
游客
登录 | 注册 方可回帖
返回
//