朱雅琼 发表于 2010-8-27 11:07:18

如何检测进程是否被挂起

本帖最后由 朱雅琼 于 2010-8-27 13:39 编辑

RT...请大大指教?

3mile 发表于 2010-8-28 17:02:17

不懂帮顶。希望有人能帮你解决。

xsjtxy 发表于 2010-8-28 17:49:29

我怎么看不懂啊。哪个来解释一下LZ说的什么。

朱雅琼 发表于 2010-8-28 22:27:30

http://www.autoitx.com/forum.php?mod=viewthread&tid=7374&highlight=%BD%F8%B3%CC%B9%D2%C6%F0

看这个帖,如果进程被这个函数挂起,如何检测出来..进程已经被挂起,也就是已经被暂停..!~

pusofalse 发表于 2010-8-29 14:34:56

“如果”已经改成“如何”了啊,因为你的错字,即便第一天就看见你的帖子,但还是不会回复你。
既然已经改过来了,那就告诉你:

挂起一个进程,实际是挂起了这个进程的主线程。

NtQuerySystemInformation(ntdll.dll)的5号功能可以枚举系统中所有的进程和线程,调用这个函数之后,会取得一个SYSTEM_PROCESS_INFORMATION结构,这个结构的长度是不定的。

SYSTEM_PROCESS_INFORMATION结构:ULONG                   NextEntryOffset;
ULONG                   NumberOfThreads;
LARGE_INTEGER         Reserved;
LARGE_INTEGER         CreateTime;
LARGE_INTEGER         UserTime;
LARGE_INTEGER         KernelTime;
UNICODE_STRING          ImageName;
KPRIORITY               BasePriority;
HANDLE                  ProcessId;
HANDLE                  InheritedFromProcessId;
ULONG                   HandleCount;
ULONG                   Reserved2;
ULONG                   PrivatePageCount;
VM_COUNTERS             VirtualMemoryCounters;
IO_COUNTERS             IoCounters;
SYSTEM_THREAD         Threads;这个结构实际是个单向链表,第一个成员NextEntryOffset表示下一个进程信息的偏移,从NextEntryOffset开始到IoCounters,这段结构的长度是确定的(184字节),记录着进程的多种信息,比如ImageName表示进程的映像名称,ProcessId表示进程的PID,InheritedFromProcessId是父进程的ID,CreateTime是进程的创建时间等等。
Threads是进程的线程信息,实际是个数组,数组的元素数量是不确定的,因为每个进程的线程数量都是不确定的,SYSTEM_THREAD的结构:LARGE_INTEGER         KernelTime;
LARGE_INTEGER         UserTime;
LARGE_INTEGER         CreateTime;
ULONG                   WaitTime;
PVOID                   StartAddress;
CLIENT_ID               ClientId;
KPRIORITY               Priority;
LONG                  BasePriority;
ULONG                   ContextSwitchCount;
ULONG                   State;
KWAIT_REASON            WaitReason;
这一段记录着线程的各种信息,StartAddress是线程的起始地址,ClientId是进程ID与线程ID,Priority线程优先级。其中的State和WaitReason分别表示线程的状态和等待原因,只要读取这两个信息就能判断出进程是否处于挂起状态,当两个的值都为5时,表示线程正处于挂起状态。

紧跟IoCounters其后的第一个SYSTEM_THREAD表示进程的第一个线程(即主线程),然后接着第一个SYSTEM_THREAD之后还是一个SYSTEM_THREAD,表示进程的第2个线程,依此。在其后到底要紧跟几个SYSTEM_THREAD,取决于SYSTEM_PROCESS_INFORMATION的第2个成员NumberOfThreads(线程数量)。

1、调用NtQuerySystemInformation的5号功能获取系统中的所有进程,取得SYSTEM_PROCESS_INFORMATION结构指针。
2、通过指针枚举所有进程,判断ProcessId是否是目标进程,不是则当前指针加NextEntryoffset,使指针指向下一进程信息,继续枚举。如是,读取第一个SYSTEM_THREAD(主线程)中的State和WaitReason,如果值都是5,说明进程处于挂起状态。
3、判断NextEntryOffset是否为0,为0则停止枚举。

以上。

PS:如果你想做伸手党,肯定会被无视。当然,如果事先自己独立思考过 又是另外一回事。

xsjtxy 发表于 2010-8-29 19:03:52

那个功能太强了。配合做杀毒软件

朱雅琼 发表于 2010-8-29 23:14:40

大大..这么深奥的东西..我真的写不出来的..

weiym 发表于 2010-8-30 08:32:29

简单点可以用API SendMessageTimeout, 如果消息响应超时,说明进程挂起了

leon460 发表于 2010-9-16 22:44:35

学习啊,太厉害了,,看都看不懂,何况要写了?

menfan1 发表于 2010-9-18 14:12:57

呵呵,学习一下。。

pusofalse 发表于 2010-9-18 22:29:17

好吧,我承认我5#的回复实在是多余了,楼主觉得呢?

#include <Thread.au3>

$iProcessId = ProcessExists("Notepad.exe")
If ($iProcessId = 0) Then Exit

$aThread = _RTEnumerateThreads($iProcessId)
If ($aThread = 5) And ($aThread = 5) Then
        MsgBox(48, "", "Process " & $iProcessId & " is suspended.")
Else
        MsgBox(48, "", "Process " & $iProcessId & " is not suspended.")
EndIf

_RTEnumerateThreads 原型:
Func _RTEnumerateThreads($iProcessId = 0)
        Local $pBuffer, $iOffset, $pThreads, $pBuffer1, $aResult = []

        If (@NumParams) Then
                If $iProcessId = -1 Then $iProcessId = @AutoItPid
                $iProcessId = ProcessExists($iProcessId)
                If Not $iProcessId Then Return SetError(2, 0, $aResult)
        EndIf

        _RTQuerySystemInformation(5, 0, 0)
        If (@Extended = 0) Then Return SetError(@error, 0, $aResult)

        $pBuffer = _RTHeapAlloc(@Extended)
        If _RTQuerySystemInformation(5, $pBuffer, @Extended) = False Then
                Return SetError(@error, _RTHeapFree($pBuffer), $aResult)
        EndIf
        $pBuffer1 = $pBuffer

        If @NumParams Then
                While 1
                        $iOffset = _RTReadBytes($pBuffer)

                        If _RTReadBytes($pBuffer + 68) <> $iProcessId Then
                                If ($iOffset) Then
                                        $pBuffer += $iOffset
                                        ContinueLoop
                                Else
                                        ExitLoop
                                EndIf
                        EndIf

                        $aResult = _RTReadBytes($pBuffer + 4)
                        $pThreads = $pBuffer + 184

                        Redim $aResult[$aResult + 1]

                        For $i = 1 To $aResult
                                $aResult[$i] = _RTReadBytes($pThreads + ($i - 1) * 64 + 36); ThreadId
                                $aResult[$i] = $iProcessId        ; ProcessId
                                $aResult[$i] = _RTReadBytes($pThreads + ($i - 1) * 64 + 40); Priority
                                $aResult[$i] = _RTReadBytes($pThreads + ($i - 1) * 64 + 44); BPriority
                                $aResult[$i] = _RTReadBytes($pThreads + ($i - 1) * 64 + 28, "ptr")
                                $aResult[$i] = _RTReadBytes($pThreads + ($i - 1) * 64 + 48); CSwitch
                                $aResult[$i] = _RTReadBytes($pThreads + ($i - 1) * 64 + 52); State
                                $aResult[$i] = _RTReadBytes($pThreads + ($i - 1) * 64 + 56); Reason
                        Next
                        ExitLoop
                WEnd
        Else
                Local $iPrevIndex = 1
                While 1
                        $iOffset = _RTReadBytes($pBuffer)

                        $aResult += _RTReadBytes($pBuffer + 4)
                        $pThreads = $pBuffer + 184

                        Redim $aResult[$aResult + 1]

                        For $i = $iPrevIndex To $aResult
                                $aResult[$i] = _RTReadBytes($pThreads + ($i - $iPrevIndex) * 64 + 36)
                                $aResult[$i] = _RTReadBytes($pThreads + ($i - $iPrevIndex) * 64 + 32)
                                $aResult[$i] = _RTReadBytes($pThreads + ($i - $iPrevIndex) * 64 + 40)
                                $aResult[$i] = _RTReadBytes($pThreads + ($i - $iPrevIndex) * 64 + 44)
                                $aResult[$i] = _RTReadBytes($pThreads + ($i - $iPrevIndex) * 64 + 28, "ptr")
                                $aResult[$i] = _RTReadBytes($pThreads + ($i - $iPrevIndex) * 64 + 48)
                                $aResult[$i] = _RTReadBytes($pThreads + ($i - $iPrevIndex) * 64 + 52)
                                $aResult[$i] = _RTReadBytes($pThreads + ($i - $iPrevIndex) * 64 + 56)
                        Next
                        If ($iOffset = 0) Then ExitLoop

                        $pBuffer += $iOffset
                        $iPrevIndex = $aResult + 1
                WEnd

        EndIf
        Return SetError(0, _RTHeapFree($pBuffer1), $aResult)
EndFunc        ;==>_RTEnumerateThreads

4216730 发表于 2010-9-19 01:30:19

回复 11# pusofalse


    没有5楼的说明就更加看不懂11楼的原理了
NtQuerySystemInformation(ntdll.dll)的5号功能就这么强大,也勉强看明白了
能不能再像5楼那样介绍下其它的功能呢
页: [1]
查看完整版本: 如何检测进程是否被挂起