gpt4 book ai didi

c - Windows 内核驱动程序 : How to determine if thread terminated?

转载 作者:可可西里 更新时间:2023-11-01 09:32:24 29 4
gpt4 key购买 nike

我有一个线程用于某些操作,它需要保持事件状态,直到标志另有说明为止。

我用 PsCreateSystemThread创建线程,然后使用 ObReferenceObjectByHandle获取 ETHREAD在使用 KeWaitForSingleObject 卸载驱动程序之前等待线程终止的对象引用.

The function that creates the thread and retrieves a reference to it:


ntStatus = PsCreateSystemThread(
&hThread,
(ACCESS_MASK)0, NULL,
(HANDLE)0, NULL,
ThreadRoutine,
(PVOID)pThreadData
);
if (!NT_SUCCESS(ntStatus))
{
return ntStatus;
}

ntStatus = ObReferenceObjectByHandle(
hThread,
THREAD_ALL_ACCESS,
NULL,
KernelMode,
(PVOID*)&ptThreadObject,
NULL
);
if (!NT_SUCCESS(ntStatus))
{
bStopThread = TRUE;
ptThreadObject = NULL;
return ntStatus;
}

The thread routine:


LARGE_INTEGER liSleepTime;
while (FALSE == bThread)
{
liSleepTime.QuadPart = 1000 * RELATIVE_MILLISECOND;
KeDelayExecutionThread(KernelMode, FALSE, (&liSleepTime));

ExAcquireFastMutex(&fmMutex);
//DO SOMTHING
ExReleaseFastMutex(&fmMutex);
}

PsTerminateSystemThread(STATUS_SUCCESS);

The unload driver function:


if (NULL != ptThreadObject)
{
bStopThread = TRUE;

KeWaitForSingleObject(
(PVOID)ptThreadObject,
Executive,
KernelMode,
FALSE,
(&liTimeOut));
ObDereferenceObject((PVOID)ptThreadObject);
ptThreadObject= NULL;
}

我需要这个线程一直运行。

有没有办法检查线程是否提前终止? (如果它是由 PsTerminateSystemThread 完成的,我可以添加一个“ bool 值”并在调用 PsTerminateSystemThread 终止线程之前设置它)。

One more question:



我在它的例程开始时终止了线程,并在调用 ObReferenceObjectByHandle 之前等待了 20 秒并且它没有失败。
ntStatus = PsCreateSystemThread(
&hThread,
(ACCESS_MASK)0, NULL,
(HANDLE)0, NULL,
ThreadRoutine,
(PVOID)pThreadData
);
if (!NT_SUCCESS(ntStatus))
{
return ntStatus;
}
// The ThreadRoutine calling PsTerminateSystemThread first and terminate.

liSleepTime.QuadPart = 20000 * RELATIVE_MILLISECOND;
KeDelayExecutionThread(KernelMode, FALSE, (&liSleepTime));

ntStatus = ObReferenceObjectByHandle(
hThread,
THREAD_ALL_ACCESS,
NULL,
KernelMode,
(PVOID*)&ptThreadObject,
NULL
);
if (!NT_SUCCESS(ntStatus))
{
bStopThread = TRUE;
ptThreadObject = NULL;
return ntStatus;
}

为什么 ObReferenceObjectByHandle 成功而不失败? - 线程早已不复存在。

谢谢。

最佳答案

Why does ObReferenceObjectByHandle succeed and not fail? -The thread is long gone.



但为什么它必须失败? ObReferenceObjectByHandle 只需 return 返回指向对象主体的相应指针。 ETHREAD在你的情况下。对象的状态 - 在这里不发挥任何作用。终止线程与否绝对无关。直到您拥有指向线程主体结构的句柄或引用指针 ( ETHREAD ) - 该对象将不会被释放。所以,如果 hThread是有效的句柄 - ObReferenceObjectByHandle必须成功。

How to determine if thread terminated?



非常简单 - 只需等待它说通过 KeWaitForSingleObject ,你已经完成了。因为线程对象本身是一种调度程序对象,当线程终止时,它设置为信号状态和 KeWaitForSingleObject返回。
if (ptThreadObject)
{
bStopThread = TRUE;

KeWaitForSingleObject(
ptThreadObject,
Executive,
KernelMode,
FALSE,
0);
ObDereferenceObject(ptThreadObject);
}

注意 - 您必须将 Timeout 设置为 0 以无限期地等待直到线程终止(调度程序对象设置为信号状态)。你也不需要 Actor ptThreadObjectPVOID - 它已经是指针。 (PVOID)ptThreadObject不是错误,而是多余和不必要的代码。

Is there a way to check if the thread is terminated prematurely?



操作系统,我不明白你在 下的意思过早 .检查线程是否终止,我们可以通过等待它。但过早地只能在您的代码上下文中有意义。假设您可以通过 PsTerminateSystemThread 设置不同的线程退出状态然后(在线程终止后)通过 PsGetThreadExitStatus 获得此存在状态.如果线程仍在运行 PsGetThreadExitStatus返回 STATUS_PENDING .这个例程也可以部分用于检查线程状态 - 如果它返回任何不同于 STATUS_PENDING 的状态- 线程终止。但如果它返回 STATUS_PENDING - 不清楚 - 或线程仍在运行,或线程存在通过 PsTerminateSystemThread(STATUS_PENDING) .当然使用 STATUS_PENDING因为存在状态是个坏主意,永远不要使用。在这种情况下,您可以使用 PsGetThreadExitStatus 确定线程状态(运行/终止)也是,不过这个套路不等。但您的驱动程序逻辑需要 等待 当线程终止时,只有在此之后我们才能卸载驱动程序。所以只有 KeWaitForSingleObject (或其他等待功能)是正确的解决方案。如果线程可以以不同的方式存在 - 在调用中使用不同的退出状态 PsTerminateSystemThread并通过 PsGetThreadExitStatus 取回线程终止后(所以在 KeWaitForSingleObject 之后)

但是请拨打 PsTerminateSystemThread是可选的 - 您可以简单地从 ThreadRoutine 返回- 在这种情况下,系统自己拨打 PsTerminateSystemThread(STATUS_SUCCESS); - 所以在你的代码中调用 PsTerminateSystemThread(STATUS_SUCCESS);还有多余的和不必要的代码。您需要拨打 PsTerminateSystemThread仅当您希望退货状态与 STATUS_SUCCESS 不同时和 检查 线程终止后返回状态。请注意,Windows 本身不会解释和使用线程退出状态。它只是将它存储在 ETHREAD目的。如果您不查询和使用此状态 - 它的退出状态无关紧要。

还有 liSleepTime.QuadPart = 1000 * RELATIVE_MILLISECOND;如果您使用 ,您可以从循环中退出 - 在循环之前设置常数 暂停。

如果在 asm 代码中使用特殊的线程入口点,我们也不能在驱动程序卸载中等待线程终止。显然,在线程运行之前,不得卸载驱动程序。对于这个存在 2 解决方案 - 一个是在驱动程序卸载例程中等待,所有驱动程序线程终止。但是存在和另一个 - 在我们创建线程时添加对驱动程序对象的引用,并在线程退出时取消引用驱动程序对象。

所以定义全局变量:
PDRIVER_OBJECT gDriverObject;

DriverEntry初始化它: gDriverObject = DriverObject;
并以下一种方式启动线程:
ObfReferenceObject(gDriverObject);

NTSTATUS status = PsCreateSystemThread(
&hThread,
0, NULL,
0, NULL,
ThreadRoutine,
pThreadData
);
if (!NT_SUCCESS(status))
{
ObfDereferenceObject(gDriverObject);
}

并且在线程退出时需要调用 ObfDereferenceObject(gDriverObject); .但在 ObfDereferenceObject(gDriverObject); 之后我们已经无法返回驱动程序代码 - 它可以已经卸载。所以这个调用不能从 c/c++ 代码中完成。在用户模式存在 FreeLibraryAndExitThread ,但在内核模式下没有这个 api 的模拟。唯一的解决方案——在 asm 代码中实现线程入口点——这个入口调用 c/c++ 线程例程,最后 jmp (但不是 拨打 )到 ObfDereferenceObject .

将您的 c/c++ proc 定义为
void NTAPI _ThreadRoutine(PVOID pv)
{
// not call PsTerminateSystemThread here !!
}

x64 和 c 的代码( ml64 /c /Cp $(InputFileName) -> $(InputName).obj )
extern _ThreadRoutine : PROC
extern gDriverObject : QWORD
extern __imp_ObfDereferenceObject : QWORD

_TEXT segment 'CODE'

ThreadRoutine proc
sub rsp,28h
call _ThreadRoutine
add rsp,28h
mov rcx,gDriverObject
jmp __imp_ObfDereferenceObject
ThreadRoutine endp

_TEXT ENDS

end

x86 和 c 的代码( ml /c /Cp $(InputFileName) -> $(InputName).obj )
.686

extern _gDriverObject:DWORD
extern __imp_@ObfDereferenceObject@4:DWORD
extern __ThreadRoutine : PROC

_TEXT SEGMENT

_ThreadRoutine proc
mov eax,[esp]
xchg eax,[esp+4]
mov [esp],eax
call __ThreadRoutine
mov ecx,_gDriverObject
jmp __imp_@ObfDereferenceObject@4
_ThreadRoutine endp

_TEXT ENDS
END

有了这个你可以 不等退出工作线程 - 只需向他发出终止信号( bStopThread = TRUE; )并从驱动程序卸载返回。

关于c - Windows 内核驱动程序 : How to determine if thread terminated?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48953855/

29 4 0
文章推荐: java - MongoDB 和 Morphia - 传统 id(长)而不是 ObjectId
文章推荐: java - 将网站的
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com