837 views
首页 > 技术心得 > 有关线程的一些函数

有关线程的一些函数

2009年7月22日

1. 根据线程ID找出其所在的模块名
2. 获取线程当前状态, 是挂起还是终止, 没有直接的 API. 这段代码比较实用


1. 根据线程ID找出其所在的模块名

#define   WIN32_LEAN_AND_MEAN
#define   _WIN32_WINNT   0x400
#include   <stdio.h>
#include   <tchar.h>
#include   <locale.h>
#include   <windows.h>  

#include <psapi.h>
#pragma comment(lib, "psapi.lib")

#include   <Tlhelp32.h>  

//
//   Thread   Information   Classes
//  

typedef   enum   _THREADINFOCLASS   {
        ThreadBasicInformation,
        ThreadTimes,
        ThreadPriority,
        ThreadBasePriority,
        ThreadAffinityMask,
        ThreadImpersonationToken,
        ThreadDescriptorTableEntry,
        ThreadEnableAlignmentFaultFixup,
        ThreadEventPair_Reusable,
        ThreadQuerySetWin32StartAddress,
        ThreadZeroTlsCell,
        ThreadPerformanceCount,
        ThreadAmILastThread,
        ThreadIdealProcessor,
        ThreadPriorityBoost,
        ThreadSetTlsArrayAddress,
        ThreadIsIoPending,
        ThreadHideFromDebugger,
        ThreadBreakOnTermination,
        MaxThreadInfoClass
}   THREADINFOCLASS;  

typedef struct _CLIENT_ID {
    HANDLE   UniqueProcess;
    HANDLE   UniqueThread;
} CLIENT_ID;
typedef   CLIENT_ID   *PCLIENT_ID;  

typedef   struct   _THREAD_BASIC_INFORMATION   {   //   Information   Class   0
    LONG        ExitStatus;
    PVOID       TebBaseAddress;
    CLIENT_ID   ClientId;
    LONG        AffinityMask;
    LONG        Priority;
    LONG        BasePriority;
}   THREAD_BASIC_INFORMATION,   *PTHREAD_BASIC_INFORMATION;  

typedef LONG (__stdcall * PFN_ZwQueryInformationThread)(
                                                       IN   HANDLE   ThreadHandle,
                                                       IN   THREADINFOCLASS   ThreadInformationClass,
                                                       OUT   PVOID   ThreadInformation,
                                                       IN   ULONG   ThreadInformationLength,
                                                       OUT   PULONG   ReturnLength   OPTIONAL
                                                       );
typedef LONG (__stdcall * PFN_RtlNtStatusToDosError)(IN ULONG status);
typedef DWORD (__stdcall * PFN_RtlGetLastWin32Error)();

EXTERN_C PFN_ZwQueryInformationThread pfn_ZwQueryInformationThread = NULL;
EXTERN_C PFN_RtlNtStatusToDosError  pfn_RtlNtStatusToDosError = NULL;
EXTERN_C PFN_RtlGetLastWin32Error  pfn_RtlGetLastWin32Error = NULL;

BOOL ShowThreadInfo (DWORD tid)
{
    THREAD_BASIC_INFORMATION tbi = { 0 };
    PVOID   startaddr = NULL;
    LONG    status = 0;
    HANDLE  hThread=NULL, process=NULL;
    TCHAR   modname   [0x100] = { 0 };
    BOOL bResult = FALSE;

    do
    {
        hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, tid);
        if (hThread == NULL) {
            SetLastError(pfn_RtlGetLastWin32Error());
            break;
        }

        status   =   pfn_ZwQueryInformationThread   (hThread,
            ThreadQuerySetWin32StartAddress,
            &startaddr,
            sizeof   (startaddr),
            NULL);
        if (status < 0) {
            SetLastError(pfn_RtlNtStatusToDosError(status));
            break;
        };  

        _tprintf(TEXT("Thread %08x  start address is %p\n"), tid, startaddr);  

        status = pfn_ZwQueryInformationThread(hThread,
            ThreadBasicInformation,
            &tbi,
            sizeof   (tbi),
            NULL);  

        if (status < 0)
        {
            SetLastError(pfn_RtlNtStatusToDosError(status));
            break;
        };  

        _tprintf   (TEXT   ("Thread %08x 's process ID is %08x\n"),
            tid,
            (DWORD)tbi.ClientId.UniqueProcess);  

        process   =   OpenProcess   (PROCESS_ALL_ACCESS,
            FALSE,
            (DWORD)tbi.ClientId.UniqueProcess);  

        if (process == NULL) {
            SetLastError(pfn_RtlGetLastWin32Error());
            break;
        };  

        GetModuleFileNameEx(process, NULL, modname, 0x100);
        _tprintf(TEXT("Thread %08x Located in Process Image %s\n"), tid, modname);

        GetMappedFileName(process, startaddr, modname, 0x100);
        _tprintf(TEXT("Thread %08x Located in module \"%s\"\n"), tid, modname);

        bResult = TRUE;
    } while (FALSE);

    if (process) {
        CloseHandle(process);
    }
    if (hThread) {
        CloseHandle(hThread);
    }

    return   TRUE;
};  

int   main   (void)
{
    HINSTANCE hNTDLL = NULL;
    HANDLE h = NULL;
    THREADENTRY32 te = { sizeof(te) };  

    setlocale(LC_ALL, ".ACP");
    hNTDLL = GetModuleHandle(TEXT("ntdll"));
    pfn_ZwQueryInformationThread = (PFN_ZwQueryInformationThread)
        GetProcAddress(hNTDLL, "ZwQueryInformationThread");
    pfn_RtlNtStatusToDosError = (PFN_RtlNtStatusToDosError)
        GetProcAddress(hNTDLL, "RtlNtStatusToDosError");
    pfn_RtlGetLastWin32Error = (PFN_RtlGetLastWin32Error)
        GetProcAddress(hNTDLL, "RtlGetLastWin32Error");

    h   =   CreateToolhelp32Snapshot   (TH32CS_SNAPTHREAD,   0);
    te.dwSize   =   sizeof   (te);
    if(Thread32First(h, &te))
    {
        do
        {
            if   (ShowThreadInfo   (te.th32ThreadID))
            {
            }
            else
            {
                _tprintf(TEXT("Can't get thread %08x information, Error code is %d\r\n"),
                    te.th32ThreadID,   GetLastError());
            };
        }   while   (Thread32Next   (h,   &te));
    };
    CloseHandle   (h);
}

2. 获取线程当前状态, 是挂起还是终止, 没有直接的 API. 这段代码比较实用

#include <stdio.h>
#include <windows.h>
#include <winbase.h>
#include <ntsecapi.h>

#define UNICODE
#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
#define STATUS_SUCCESS              ((NTSTATUS) 0x00000000)
#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS) 0xC0000004)
#define SystemProcessesAndThreadsInformation    5
#define NTAPI    __stdcall

typedef enum _THREAD_STATE
{
    StateInitialized,
    StateReady,
    StateRunning,
    StateStandby,
    StateTerminated,
    StateWait,
    StateTransition,
    StateUnknown
}THREAD_STATE;

typedef enum _KWAIT_REASON
{
    Executive,
    FreePage,
    PageIn,
    PoolAllocation,
    DelayExecution,
    Suspended,
    UserRequest,
    WrExecutive,
    WrFreePage,
    WrPageIn,
    WrPoolAllocation,
    WrDelayExecution,
    WrSuspended,
    WrUserRequest,
    WrEventPair,
    WrQueue,
    WrLpcReceive,
    WrLpcReply,
    WrVirtualMemory,
    WrPageOut,
    WrRendezvous,
    Spare2,
    Spare3,
    Spare4,
    Spare5,
    Spare6,
    WrKernel,
    MaximumWaitReason
}KWAIT_REASON;

typedef NTSTATUS (WINAPI *PNTRAISE)(NTSTATUS,
                                    ULONG,
                                    ULONG,
                                    PULONG,
                                    UINT,
                                    PULONG);   

typedef LONG NTSTATUS;
typedef LONG    KPRIORITY;

typedef struct _CLIENT_ID {
    DWORD        UniqueProcess;
    DWORD        UniqueThread;
} CLIENT_ID, * PCLIENT_ID;

typedef struct _VM_COUNTERS {
    SIZE_T        PeakVirtualSize;
    SIZE_T        VirtualSize;
    ULONG        PageFaultCount;
    SIZE_T        PeakWorkingSetSize;
    SIZE_T        WorkingSetSize;
    SIZE_T        QuotaPeakPagedPoolUsage;
    SIZE_T        QuotaPagedPoolUsage;
    SIZE_T        QuotaPeakNonPagedPoolUsage;
    SIZE_T        QuotaNonPagedPoolUsage;
    SIZE_T        PagefileUsage;
    SIZE_T        PeakPagefileUsage;
} VM_COUNTERS;

typedef struct _SYSTEM_THREAD_INFORMATION {
    LARGE_INTEGER   KernelTime;
    LARGE_INTEGER   UserTime;
    LARGE_INTEGER   CreateTime;
    ULONG            WaitTime;
    PVOID            StartAddress;
    CLIENT_ID        ClientId;
    KPRIORITY        Priority;
    KPRIORITY        BasePriority;
    ULONG            ContextSwitchCount;
    LONG            State;
    LONG            WaitReason;
} SYSTEM_THREAD_INFORMATION, * PSYSTEM_THREAD_INFORMATION;

typedef struct _SYSTEM_PROCESS_INFORMATION {
    ULONG            NextEntryDelta;
    ULONG            ThreadCount;
    ULONG            Reserved1[6];
    LARGE_INTEGER   CreateTime;
    LARGE_INTEGER   UserTime;
    LARGE_INTEGER   KernelTime;
    UNICODE_STRING ProcessName;
    KPRIORITY        BasePriority;
    ULONG            ProcessId;
    ULONG            InheritedFromProcessId;
    ULONG            HandleCount;
    ULONG            Reserved2[2];
    VM_COUNTERS        VmCounters;
    IO_COUNTERS        IoCounters;
    SYSTEM_THREAD_INFORMATION Threads[5];
} SYSTEM_PROCESS_INFORMATION, * PSYSTEM_PROCESS_INFORMATION;

typedef DWORD (WINAPI* PQUERYSYSTEM)(UINT, PVOID, DWORD,PDWORD);

/************************************************************************/
/* 函数说明:
   参数:dwThreadID 代表线程ID ,这里主要是验证线程的ID
             szProcessName,表示线程所在的进程名

返回值:
       true: 表示线程被挂起
       false: 表示线程正常。

*/
/************************************************************************/

BOOL IsThreadSuspend(DWORD dwThreadID,wchar_t *szProcessName)
{
    ULONG cbBuffer = 0x5000;

    BOOL bRet = FALSE;

    LPVOID pBuffer = NULL;
    NTSTATUS Status;

    DWORD b=0;

    PQUERYSYSTEM NtQuerySystemInformation;
    PSYSTEM_PROCESS_INFORMATION pInfo ;

    NtQuerySystemInformation = (PQUERYSYSTEM) GetProcAddress(
        LoadLibrary( "ntdll.dll" ),
        "NtQuerySystemInformation" );

    do
    {
        pBuffer = malloc(cbBuffer);
        if (pBuffer == NULL)
        {
            break;
        }

        Status = NtQuerySystemInformation(
            SystemProcessesAndThreadsInformation,
            pBuffer, cbBuffer, NULL);

        if (Status == STATUS_INFO_LENGTH_MISMATCH)
        {
            free(pBuffer);
            cbBuffer *= 2;
        }
        else if (!NT_SUCCESS(Status))
        {
            free(pBuffer);
        }

    }   while (Status == STATUS_INFO_LENGTH_MISMATCH);

    pInfo = (PSYSTEM_PROCESS_INFORMATION)pBuffer;

    for (;;)
    {

        if (pInfo->NextEntryDelta == 0)
            break;
        if(pInfo->ProcessName.Buffer!=NULL &&
            !_wcsicmp(pInfo->ProcessName.Buffer,szProcessName))
        {

            for(b=0;b<pInfo->ThreadCount ;b++)
            {
                if(pInfo->Threads[b].ClientId.UniqueThread == dwThreadID ) //找到线程
                {

                    if(pInfo->Threads[b].State == StateWait && pInfo->Threads[b].WaitReason == Suspended) //线程被挂起
                    {
                        bRet = TRUE;
                        break;
                    }
                }
            }
            break;

        }
        pInfo = (PSYSTEM_PROCESS_INFORMATION)(((PUCHAR)pInfo) +    pInfo->NextEntryDelta);
    }

    free(pBuffer);
    return bRet;
}   

/**************************************************************/
/*判断线程是否被终止 , 如果终止返回FALSE,如果还活着返回TRUE
/**************************************************************/

BOOL IsThreadAlive(DWORD dwThreadID)
{
    BOOL bRet = FALSE;
    DWORD ExitCode = 0;

    HANDLE hThread = OpenThread(THREAD_QUERY_INFORMATION,FALSE,dwThreadID);
    if(hThread != NULL)
    {
        if(GetExitCodeThread(hThread,&ExitCode))
        {
            if( ExitCode == STILL_ACTIVE)
                bRet = TRUE;
        }

        CloseHandle(hThread);
    }

    return bRet;
}

int _tmain(int argc, _TCHAR* argv[])
{
    BOOL bRET =IsThreadSuspend(2320,L"EXPLORER.EXE");
    if(bRET)
    {
        printf(" 2320线程被挂起了!");
    }
    return 0;
}

技术心得

  1. 目前还没有任何评论.
  1. 目前还没有任何 trackbacks 和 pingbacks.