首页
社区
课程
招聘
[求助]ObOpenObjectByPointer后系统蓝屏的问题
发表于: 2009-12-3 19:07 19217

[求助]ObOpenObjectByPointer后系统蓝屏的问题

2009-12-3 19:07
19217
请各位大牛帮忙看看,
xp, sp2, PsSetCreateThreadNotifyRoutine回调中使用下面的函数打开thread句柄,传给ring3, ring3什么都不做。但是很快只要系统启动新线程就蓝屏。但是注释掉ObOpenObjectByPointer行就没问题,不明白。

HANDLE
GetThreadHandle(
        DWORD dwProcessId,
        DWORD dwThreadId)
{
        HANDLE hThread = NULL;
        PETHREAD pEThread = NULL;
        NTSTATUS status = STATUS_SUCCESS;
       
        status = GetProcessThread(dwProcessId, dwThreadId, &pEThread);
        if (NT_SUCCESS(status))
        {
                status = ObOpenObjectByPointer(pEThread, 0, 0, THREAD_ALL_ACCESS, *PsThreadType, KernelMode, &hThread);
                if (!NT_SUCCESS(status))
                {
                        hThread = NULL;
                }
        }
        return hThread;
}

THREAD 814f7020  Cid 0778.0448  Teb: 7ff9d000 Win32Thread: e1802a28 RUNNING on processor 0
Not impersonating
DeviceMap                 e1a0e8c0
Owning Process            0       Image:         <Unknown>
Attached Process          815a1c40       Image:         IEXPLORE.EXE
Wait Start TickCount      169226         Ticks: 0
Context Switch Count      581                 LargeStack
UserTime                  00:00:00.050
KernelTime                00:00:00.180
Win32 Start Address 0x7e624691
Start Address 0x7c810659
Stack Init f4ed6000 Current f4ed5ae8 Base f4ed6000 Limit f4ed0000 Call 0
Priority 10 BasePriority 8 PriorityDecrement 2 DecrementCount 16
ChildEBP RetAddr  Args to Child              
f4ed5a90 8056568c f4ed5b98 00000000 81582b10 nt!ObpValidateAccessMask+0xf (FPO: [1,0,0])
f4ed5b6c 8057d115 81582b10 f4ed5b98 001f03ff nt!ObInsertObject+0x1f4 (FPO: [6,49,4])
f4ed5cc4 8057d45c 0465d488 001f03ff 00000000 nt!PspCreateThread+0x618 (FPO: [Non-Fpo])
f4ed5d3c 804df7ec 0465d488 001f03ff 00000000 nt!NtCreateThread+0x118 (FPO: [Non-Fpo])
f4ed5d3c 7c92eb94 0465d488 001f03ff 00000000 nt!KiFastCallEntry+0xf8 (FPO: [0,0] TrapFrame @ f4ed5d64)
0465d3e0 7c92d7de 7c8104f5 0465d488 001f03ff ntdll!KiFastSystemCallRet (FPO: [0,0,0])
0465d4a4 7c9305c8 001d9f38 0465d4e4 00140000 ntdll!NtCreateThread+0xc (FPO: [8,0,0])
0465d838 7c810655 ffffffff 00000000 00000000 ntdll!RtlpFreeToHeapLookaside+0x22 (FPO: [2,0,4])
WARNING: Frame IP not in any known module. Following frames may be wrong.
0465d85c 300fffea 00000000 00000000 300fff7e 0x7c810655
0465d884 300c616c 30017d4a 05f24378 00000000 0x300fffea
0465d97c 00000000 0465da28 77fa62a5 0465dad8 0x300c616c

[培训]科锐逆向工程师培训第53期2025年7月8日开班!

收藏
免费 0
支持
分享
最新回复 (19)
雪    币: 38
活跃值: (591)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
2
楼主怎么在成功调用ObOpenObjectByPointer后再调用 ObDereferenceObject 呢?
2009-12-3 19:35
0
雪    币: 207
活跃值: (13)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
Access violation - code c0000005 (!!! second chance !!!)
nt!ObpValidateAccessMask+0xf:
805706ca f6410210        test    byte ptr [ecx+2],10h
ecx=00037438

GetProcessThread 枚举EProcess的链表自己实现的,没reference
ObOpenObjectByPointer 不用ObDereferenceObject吧

ObjectCreateInfo = ObjectHeader->ObjectCreateInfo;
。。。。。。
    AccessState->SecurityDescriptor = ObjectCreateInfo->SecurityDescriptor;

    //
    //  Check the desired access mask against the security descriptor
    //

    Status = ObpValidateAccessMask( AccessState );

看代码好像是
SecurityDescriptor 是个错误的指针

翻了半天wrk也没看出啥原因来,搞驱动没多久,很多东西不明白啊。

xp下,到底ThreadNotifyRoutine中怎么获取线程句柄呢?
2009-12-3 22:22
0
雪    币: 38
活跃值: (591)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
4
你内核下要句柄干什么?有ETHREAD就够了,如果是ring3下用的话,传回一个threadid就够了啊,最后调用
OpenThread不就得到线程句柄了。
2009-12-4 00:03
0
雪    币: 722
活跃值: (123)
能力值: ( LV12,RANK:300 )
在线值:
发帖
回帖
粉丝
5
楼主上面其实已经为找到症结开了一个头:

ObjectCreateInfo = ObjectHeader->ObjectCreateInfo;
。。。。。。
AccessState->SecurityDescriptor = ObjectCreateInfo->SecurityDescriptor;

//
// Check the desired access mask against the security descriptor
//

Status = ObpValidateAccessMask( AccessState );

这里出现了BSOD,说明此时ObjectHeader->ObjectCreateInfo不再是指向一个有效的OBJECT_CREATE_INFORMATION结构。
之所以会如此,就是因为楼主在CreateThreadNotifyRoutine中调用ObOpenObjectByPointer试图得到一个线程句柄。

PspCreateThread先调用ObCreateObject创建线程对象,然后再进行一些初始化工作之后,把线程对象插入进程EPROCESS的活动线程链里面。然后再经过一些操作,再调用CreateThreadNotifyRoutine,之后再调用ObInsertObject把线程对象加入进程的句柄表中。

也就是说,对CreateThreadNotifyRoutine的调用是在ObCreateObject之后而在ObInsertObject之前。而实际上,ObInsertObject默认其是在ObCreateObject之后第一个调用ObpCreateHandle将其加入句柄表的例程,试图在ObInsertObject被调用之前使用ObpCreateHandle获取相应对象句柄的操作都是不稳定的。

其实这个问题,早有文章出来,我就是Google到的。

我Google到的原文在c13K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4g2F1K9h3&6X3L8%4u0E0k6h3c8Q4x3X3g2G2M7X3N6Q4x3V1k6A6L8X3c8W2P5q4)9J5k6h3y4Y4K9g2)9K6c8Y4k6Q4x3@1b7I4i4K6t1$3j5g2)9K6c8o6g2Q4x3U0k6H3i4K6y4p5y4b7`.`.,该章讲述的是McAfee以前的版本的一个问题,即试图在ObCreateObject创建EPROCESS对象后在ObInsertObject前使用ObOpenObjectByPointer获取EPROCESS对象的句柄。这和楼主对ETHREAD对象的访问错误是一个道理(PspCreateProcess和PspCreateThread都涉及到先ObCreateObject再ObInsertObject的过程)。

以下是该文章中对问题的综述:
The critical phase of process execution that the summary refers to is the period between the time that the new process object instance is created by nt!ObCreateObject and the time the new process object is inserted into the process object type list by nt!ObInsertObject. The reason this phase is so critical is because it is not safe for things to attempt to obtain a handle to the process object, such as can be done by calling nt!ObOpenObjectByPointer. If an application were to attempt to obtain a handle to the process object before it had been inserted into the process object list by nt!ObInsertObject, critical creation state information that is stored in the process object's header would be overwritten with state information that is meant to be used after the process has passed the initial security validation phase that is handled by nt!ObInsertObject. In some cases, overwriting the creation state information prior to calling nt!ObInsertObject can lead to invalid pointer references when nt!ObInsertObject is eventually called, thus leading to an evil blue screen that some users are all too familiar with.


原因并不复杂,其实是ObOpenObjectByPointer抢在ObInsertObject之前调用了ObpCreateHandle,而ObpCreateHandle->ObpIncrementHandleCount->ObpChargeQuotaForObject将修改ObjectHeader的ObjectCreateInfo成员:
NTSTATUS
ObpChargeQuotaForObject (
IN POBJECT_HEADER ObjectHeader,
IN POBJECT_TYPE ObjectType,
OUT PBOOLEAN NewObject
)

/*++

Routine Description:

This routine charges quota against the current process for the new
object

Arguments:

ObjectHeader - Supplies a pointer to the new object being charged for

ObjectType - Supplies the type of the new object

NewObject - Returns true if the object is really new and false otherwise

Return Value:

An appropriate status value

--*/

{
POBJECT_HEADER_QUOTA_INFO QuotaInfo;
ULONG NonPagedPoolCharge;
ULONG PagedPoolCharge;

//
// Get a pointer to the quota block for this object
//

QuotaInfo = OBJECT_HEADER_TO_QUOTA_INFO( ObjectHeader );

*NewObject = FALSE;

//
// If the object is new then we have work to do otherwise
// we'll return with NewObject set to false
//

if (ObjectHeader->Flags & OB_FLAG_NEW_OBJECT) {

//
// Say the object now isn't new
//

ObjectHeader->Flags &= ~OB_FLAG_NEW_OBJECT;

//
// If there does exist a quota info structure for this
// object then calculate what our charge should be from
// the information stored in that structure
//

if (QuotaInfo != NULL) {

PagedPoolCharge = QuotaInfo->PagedPoolCharge +
QuotaInfo->SecurityDescriptorCharge;
NonPagedPoolCharge = QuotaInfo->NonPagedPoolCharge;

} else {

//
// There isn't any quota information so we're on our own
// Paged pool charge is the default for the object plus
// the security descriptor if present. Nonpaged pool charge
// is the default for the object.
//

PagedPoolCharge = ObjectType->TypeInfo.DefaultPagedPoolCharge;

if (ObjectHeader->SecurityDescriptor != NULL) {

ObjectHeader->Flags |= OB_FLAG_DEFAULT_SECURITY_QUOTA;
PagedPoolCharge += SE_DEFAULT_SECURITY_QUOTA;
}

NonPagedPoolCharge = ObjectType->TypeInfo.DefaultNonPagedPoolCharge;
}

//
// Now charge for the quota and make sure it succeeds
//

ObjectHeader->QuotaBlockCharged = (PVOID)PsChargeSharedPoolQuota( PsGetCurrentProcess(),
PagedPoolCharge,
NonPagedPoolCharge );

if (ObjectHeader->QuotaBlockCharged == NULL) {

return STATUS_QUOTA_EXCEEDED;
}

*NewObject = TRUE;
}


return STATUS_SUCCESS;
}
——引自wrk

也就是说,第一次调用ObpCreateHandle时,它将会把Object对象的OB_FLAG_NEW_OBJECT标志(uninformed的文章中称OB_FLAG_CREATE_INFO标志)去除,并将ObjectHeader的ObjectCreateInfo成员用另一个指向_EPROCESS_QUOTA_BLOCK结构的指针成员QuotaBlockCharged来代替(也就是说QuotaBlockCharged和ObjectCreateInfo是union)。
于是,当在CreateThreadNotifyRoutine中调用了ObOpenObjectByPointer(->ObpCreateHandle->ObpIncrementHandleCount->ObpChargeQuotaForObject)后,ObjectHeader->ObjectCreateInfo已经变成了ObjectHeader->QuotaBlockCharged,在此之后ObInsertObject再从中取SecurityDescriptor,自然是取到了不正确的数据,因此导致在ObpValidateAccessMask中读取无效的指针,导致Access Violation的BSOD。


更具体的内容,还是请楼主参阅uninformed的文章吧,里面说得非常清楚,与之对比起来,我都觉得我上面的解释纯属废话。
2009-12-4 02:09
2
雪    币: 7651
活跃值: (523)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
6
小聪的回答一向是准确、详细,膜拜~
2009-12-4 07:48
0
雪    币: 207
活跃值: (13)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
果然是大牛,这么快就发现了问题所在,回答也这么详细,非常感谢。
有些结构理解得还是很模糊,所以翻了wrk也不是能理解每行代码的意思。
看到ObpIncrementHandleCount就直接认为加1就完了,没想到还在下级,不过即便是我翻到ObpChargeQuotaForObject也不一定能发现问题,hoho。

to wtxpwh:
xp下,CreateThreadNotifyRoutine回调中都是没法在ring3下用openthread打开的。
原因是PsLookupThreadByThreadId调用会失败。
详细见1bdK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8X3S2A6i4K6u0W2j5X3q4A6k6s2g2Q4x3X3g2U0L8$3#2Q4x3V1k6*7P5Y4A6W2N6X3q4*7P5Y4A6Q4x3V1k6T1L8r3!0Y4i4K6u0r3K9i4c8W2L8g2)9J5c8X3k6S2z5e0N6T1k6U0p5$3x3$3x3H3j5K6u0V1y4e0W2X3x3X3c8W2x3K6u0W2k6W2)9J5k6h3S2@1L8h3H3`.

现在还是有一个问题,CreateThreadNotifyRoutine回调中如何得到线程的句柄呢?
2009-12-4 10:44
0
雪    币: 207
活跃值: (13)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
转一下eva的博客

在线程创建通知中无法使用PsLookupThreadByThreadId的原因2009-04-23 23:19关于PsLookupThreadByThreadId,MSDN里有这样一段描述:

A file system filter driver can enumerate active threads by calling PsLookupThreadByThreadId to convert a thread ID to an ETHREAD structure. The thread ID is available in the thread create routine. A file system filter driver can set a thread notification callback routine using PsSetCreateThreadNotifyRoutine. In the notification callback routine, the file system filter driver can use the passed in ThreadId parameter and call PsLookupThreadByThreadId to locate the ETHREAD structure.

听起来很不错,但实际却不行。这里微软犯了一个错误,从Win2000开始延续至今。

下面引用WRK的代码来说明错误的原因。

NTSTATUS
PsLookupThreadByThreadId(
    __in HANDLE ThreadId,
    __deref_out PETHREAD *Thread
    )
{

    PHANDLE_TABLE_ENTRY CidEntry;
    PETHREAD lThread;
    PETHREAD CurrentThread;
    NTSTATUS Status;

    PAGED_CODE();

    Status = STATUS_INVALID_PARAMETER;

    CurrentThread = PsGetCurrentThread ();
    KeEnterCriticalRegionThread (&CurrentThread->Tcb);

    CidEntry = ExMapHandleToPointer(PspCidTable, ThreadId);
    if (CidEntry != NULL) {
        lThread = (PETHREAD)CidEntry->Object;
        if (lThread->Tcb.Header.Type == ThreadObject && lThread->GrantedAccess) {

            if (ObReferenceObjectSafe(lThread)) {
                *Thread = lThread;
                Status = STATUS_SUCCESS;
            }
        }

        ExUnlockHandleTableEntry(PspCidTable, CidEntry);
    }

    KeLeaveCriticalRegionThread (&CurrentThread->Tcb);

    return Status;
}

通过跟踪PsLookupThreadByThreadId的调用过程发现,无法成功是因为lThread->GrantedAccess这个条件不满足。

再看PspCreateThread的代码。

NTSTATUS
PspCreateThread(
    OUT PHANDLE ThreadHandle,
    IN ACCESS_MASK DesiredAccess,
    IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
    IN HANDLE ProcessHandle,
    IN PEPROCESS ProcessPointer,
    OUT PCLIENT_ID ClientId OPTIONAL,
    IN PCONTEXT ThreadContext OPTIONAL,
    IN PINITIAL_TEB InitialTeb OPTIONAL,
    IN BOOLEAN CreateSuspended,
    IN PKSTART_ROUTINE StartRoutine OPTIONAL,
    IN PVOID StartContext
    )
{
    //
    // ...... 省略无关代码 ......
    //

    RtlZeroMemory (Thread, sizeof (ETHREAD));

    //
    // Initialize rundown protection for cross thread TEB refs etc.
    //
    ExInitializeRundownProtection (&Thread->RundownProtect);

    //
    // Assign this thread to the process so that from now on
    // we don't have to dereference in error paths.
    //
    Thread->ThreadsProcess = Process;

    Thread->Cid.UniqueProcess = Process->UniqueProcessId;

    CidEntry.Object = Thread;
    CidEntry.GrantedAccess = 0;
    Thread->Cid.UniqueThread = ExCreateHandle (PspCidTable, &CidEntry);

    if (Thread->Cid.UniqueThread == NULL) {
        ObDereferenceObject (Thread);
        return (STATUS_INSUFFICIENT_RESOURCES);
    }

    //
    // ...... 省略无关代码 ......
    //

    //
    // Notify registered callout routines of thread creation.
    //

    if (PspCreateThreadNotifyRoutineCount != 0) {
        ULONG i;
        PEX_CALLBACK_ROUTINE_BLOCK CallBack;
        PCREATE_THREAD_NOTIFY_ROUTINE Rtn;

        for (i = 0; i < PSP_MAX_CREATE_THREAD_NOTIFY; i++) {
            CallBack = ExReferenceCallBackBlock (&PspCreateThreadNotifyRoutine[i]);
            if (CallBack != NULL) {
                Rtn = (PCREATE_THREAD_NOTIFY_ROUTINE) ExGetCallBackBlockRoutine (CallBack);
                Rtn (Thread->Cid.UniqueProcess,
                     Thread->Cid.UniqueThread,
                     TRUE);
                ExDereferenceCallBackBlock (&PspCreateThreadNotifyRoutine[i],
                                            CallBack);
            }
        }
    }

    //
    // ...... 省略无关代码 ......
    //

    if ((Thread->CrossThreadFlags&PS_CROSS_THREAD_FLAGS_DEADTHREAD) == 0) {
        Status = ObGetObjectSecurity (Thread,
                                      &SecurityDescriptor,
                                      &MemoryAllocated);
        if (!NT_SUCCESS (Status)) {
            //
            // This trick us used so that Dbgk doesn't report
            // events for dead threads
            //
            PS_SET_BITS (&Thread->CrossThreadFlags,
                         PS_CROSS_THREAD_FLAGS_DEADTHREAD);

            if (CreateSuspended) {
                KeResumeThread(&Thread->Tcb);
            }
            KeReadyThread (&Thread->Tcb);
            ObDereferenceObject (Thread);
            ObCloseHandle (LocalThreadHandle, PreviousMode);
            return Status;
        }

        //
        // Compute the subject security context
        //

        SubjectContext.ProcessAuditId = Process;
        SubjectContext.PrimaryToken = PsReferencePrimaryToken(Process);
        SubjectContext.ClientToken = NULL;

        AccessCheck = SeAccessCheck (SecurityDescriptor,
                                     &SubjectContext,
                                     FALSE,
                                     MAXIMUM_ALLOWED,
                                     0,
                                     NULL,
                                     &PsThreadType->TypeInfo.GenericMapping,
                                     PreviousMode,
                                     &Thread->GrantedAccess,
                                     &accesst);

        PsDereferencePrimaryTokenEx (Process, SubjectContext.PrimaryToken);

        ObReleaseObjectSecurity (SecurityDescriptor,
                                 MemoryAllocated);

        if (!AccessCheck) {
            Thread->GrantedAccess = 0;
        }

        Thread->GrantedAccess |= (THREAD_TERMINATE | THREAD_SET_INFORMATION | THREAD_QUERY_INFORMATION);

    } else {
        Thread->GrantedAccess = THREAD_ALL_ACCESS;
    }

    KeReadyThread (&Thread->Tcb);
    ObDereferenceObject (Thread);

    return Status;
}

也就是说,Thread->GrantedAccess在线程创建通知之后才初始化,之前的值是0,所以前面说的条件无法满足。

从Win2000到Win2003,都存在这个问题。直到Vista,GrantedAccess的初始化才放到通知之前。

微软在更新文档的时候,显然忘记了测试旧的操作系统。

顺带一提,FsRtlCreateSectionForDataScan这个函数也存在一个问题。

函数原型如下;

NTSTATUS
FsRtlCreateSectionForDataScan(
    OUT PHANDLE SectionHandle,
    OUT PVOID *SectionObject,
    OUT PLARGE_INTEGER SectionFileSize OPTIONAL,
    IN PFILE_OBJECT FileObject,
    IN ACCESS_MASK DesiredAccess,
    IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
    IN PLARGE_INTEGER MaximumSize OPTIONAL,
    IN ULONG SectionPageProtection,
    IN ULONG AllocationAttributes,
    IN ULONG Flags
    );

问题在于ObjectAttributes参数居然依赖于PreviousMode。当PreviousMode==UserMode时,必须提供用户态地址。

要知道,FsRtlCreateSectionForDataScan并不是Nt/ZwXxx系统服务,而是内核专用的函数,常用于文件系统过滤驱动中,因此上下文是不确定的。这让使用者到哪里搞一个用户态地址的ObjectAttributes出来呢。临时分配就太慢了。而与此同时,SectionHandle,SectionFileSize等其他参数却总是内核地址。

对于既要处理用户态也要处理内核参数的函数,一般的做法是设一个ProbeMode参数,就像ObCreateObject那样。

出现问题的根本原因是,ObjectAttributes被直接传递给内部函数MmCreateSection。而MmCreateSection没有设计ProbeMode参数。

FsRtlCreateSectionForDataScan从2000sp4增量补丁包(Update Rollup)、XPsp2和2003sp1之后才出现,可以说是专为文件系统过滤驱动设计的。之前MmCreateSection的主要调用者只有NtCreateSection这个系统服务。所以MmCreateSection直接调用KeGetPreviousMode得到PreviousMode也没问题。不曾想后来FsRtlCreateSectionForDataScan第三者插足,导致了如今不和谐的状况。
2009-12-4 10:45
0
雪    币: 207
活跃值: (13)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
typedef struct _OBJECT_HEADER {
    LONG_PTR PointerCount;
    union {
        LONG_PTR HandleCount;
        PVOID NextToFree;
    };
    POBJECT_TYPE Type;
    UCHAR NameInfoOffset;
    UCHAR HandleInfoOffset;
    UCHAR QuotaInfoOffset;
    UCHAR Flags;

    union {
        POBJECT_CREATE_INFORMATION ObjectCreateInfo;
        PVOID QuotaBlockCharged;
    };

    PSECURITY_DESCRIPTOR SecurityDescriptor;
    QUAD Body;
} OBJECT_HEADER, *POBJECT_HEADER;

    union {
        POBJECT_CREATE_INFORMATION ObjectCreateInfo;
        PVOID QuotaBlockCharged;
    };
这unio太恶心了,不注意还真发现不了问题
2009-12-4 10:52
0
雪    币: 207
活跃值: (13)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
再问啊,xp下,CreateThreadNotifyRoutine回调中如何得到线程的句柄给ring3调用呢?
2009-12-4 10:54
0
雪    币: 722
活跃值: (123)
能力值: ( LV12,RANK:300 )
在线值:
发帖
回帖
粉丝
11
你为什么非要在CreateThreadNotifyRoutine中得到线程句柄不可呢?上面都已经告诉你了,在ObInsertObject之前是不能调用ObpCraeteHandle创建相应对程句柄的,没有这个,你哪来的句柄?自己写代码实现?
其次,无论在哪里,如果你的ObOpenObjectByPointer发自除system进程之外的进程,则如果采用OBJ_KERNEL_HANDLE,那么得到的句柄只能在Kernel Mode用,而不采用OBJ_KERNEL_HANDLE的话,也只能是该进程自己用,给不了其他进程Ring3部分用(除非其他进程再调用ZwDuplicateObject,而等到调用这个的话就根本不需要特意在CreateThreadNotifyRoutine取原始句柄)。
再次,如果你只是给那个进程自己用吧,那就更没必要了,CreateThread本来就会返回新线程句柄,不需要特意在CreateThreadNotifyRoutine取。
再假设,你是往目标进程注入远程线程吧,CreateRemoteThread同样会返回新线程句柄。

因此,我考虑了以上这么多情况,都看不到你非要在CreateThreadNotifyRoutine中取新线程句柄的绝对必要性何在。
2009-12-4 11:12
0
雪    币: 207
活跃值: (13)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
如果我在监控其他进程的线程创建,并modify context呢?
2009-12-4 12:34
0
雪    币: 207
活跃值: (13)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
恩,原理看是不能获得句柄了,只好试试看修改objectheader->flag了
不知道到objectheader各os版本是不是固定
2009-12-4 12:38
0
雪    币: 722
活跃值: (123)
能力值: ( LV12,RANK:300 )
在线值:
发帖
回帖
粉丝
14
问题不在于你想在Ring3做什么,而在于无论你做什么,都没有特别值得的理由必须在CreateThreadNotifyRoutine这个时机上获取句柄:
如果你想在CreateThreadNotifyRoutine这里把创建线程的操作阻塞下来,与其他进程通信,将句柄传给其他进程,那么它能立即使用这个句柄做安全的操作吗?不能,因为创建线程的操作还没有完成,还没有到Ring3程序能够按照正常途径调用API能够对它安全操作的地步。也就是说你不能在Ring0把它卡住之后让Ring3去改变它,也没有必要这么做,你完全可以让Ring3和Ring0通信(Ring3部分只是起GUI的作用)然后由Ring0完成实际的操作(比如你说的由Ring0在创建线程结束之前改变它的context)。
而如果你不是想在CreateThreadNotifyRoutine把它阻塞掉,而是仍然想让它继续跑,启动起来之后再由Ring3对它进行操作,那么你完全可以不在CreateThreadNotifyRoutine这个别扭的时机去取句柄,完全可以HOOK创建线程的过程,等ObInsertObject完了之后再取句柄。
如果你非要在线程执行起来那时刻immediately把它给挂起掉,以修改它最初的context,那么你也完全可以RING0 HOOK创建线程的函数,把参数中加上CREATE_SUSPEND,让系统自然地把它初始挂起,然后你再从容地获取句柄和操作,比你绞尽脑汁在CreateThreadNotifyRoutine里获取句柄要好多了。
2009-12-4 23:57
0
雪    币: 722
活跃值: (123)
能力值: ( LV12,RANK:300 )
在线值:
发帖
回帖
粉丝
15
越想越乱来了,我猜你本意要得到句柄给Ring3用,还非要用CreateThreadNotifyRoutine来实现,就是为了得到“规范”“有文档”“稳定”的效果,现在你为了实现这个目标,反而钻牛角尖去追求“未文档”“未公开”“不能保证稳定”的方法,这难道不是与你的本意背道而驰么?真是自己给自己找罪受。
2009-12-5 00:05
0
雪    币: 284
活跃值: (16)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
给自己找罪受的后果是,精通asm,精通逆向,将windows用asm写一个。这样既可解决楼主的问题~
obxxxx,obpxxxx系列函数很好很邪恶~
出现问题就调试吧~
偶的原则,ring3能解决的尽量在ring3吧。
思路也许有问题?貌似可以 GetThreadContext?
2009-12-5 09:11
0
雪    币: 722
活跃值: (123)
能力值: ( LV12,RANK:300 )
在线值:
发帖
回帖
粉丝
17
我觉得楼主的确是想用GetThreadContext,只不过传入的句柄他想在CreateTheadNotifyRoutine获取,这个我觉得实在是太别扭了,如果你要等到用GetThreadContext的时候,那在这个过程中有大把机会给你获取句柄,何必非要钻到死胡同里,还要硬挖出一条路……
2009-12-5 11:44
0
雪    币: 207
活跃值: (13)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
呵呵,昨天没上,后来没用了,干脆hook NtCreateThread了,传个CreateSusbend参数,ring3处理完再KeResumThread。
还是谢谢轩辕小聪耐心回复。

不过后来粗略试了下objectheader->flag &= ~OB_FLAG_NEW_OBJECT 后获取handle,还是出同样的错,不知道是不是我代码的问题,没继续试,改Hook ntcreatethread了
2009-12-6 13:10
0
雪    币: 12
活跃值: (905)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
考古
2022-8-23 17:52
0
雪    币: 3188
活跃值: (13681)
能力值: ( LV12,RANK:322 )
在线值:
发帖
回帖
粉丝
20

考古问题,轩辕小聪大佬的回答是正确的。

ObCreateObj和ExCreateHadnle已经在PsSetCreateThreadNotifyRoutine之前完成,并插入了到了ThreadListHead。理论上可以通过使用PsLookupThreadByThreadId拿到先拿到EThread,在调用ObOpenObjectByPointer拿到句柄。

2023-1-10 15:04
0
游客
登录 | 注册 方可回帖
返回