1. 程式人生 > >【舊文章搬運】ZwQuerySystemInformation列舉進執行緒資訊

【舊文章搬運】ZwQuerySystemInformation列舉進執行緒資訊

原文發表於百度空間,2008-10-15
==========================================================================

很古老的東西了,寫一寫,權當練手吧.
本來以為沒什麼難度,很科普很傻瓜的東西,但是寫的時候還是遇到一些問題,程序資訊正確,得到的執行緒資訊總是不正確,後來分析了一下,發現這個ntdll sdk中定義的程序資訊結構和執行緒資訊結構都有點問題,可能它是來自《Win2000 Native API》一書,不適用於Windows XP。後來參考WRK修正了一下。執行緒資訊結構也有問題,和WRK中的一樣,但是結果仍然不正確,簡單分析了一下,得出結構大小應為0x40,最終還是修正了一下,才有正確結果。
最終確定的程序結構如下:

typedef struct _SYSTEM_PROCESSES {
ULONG NextEntryDelta;
ULONG ThreadCount;
LARGE_INTEGER Reserved1[3];
LARGE_INTEGER CreateTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER KernelTime;
UNICODE_STRING ProcessName;
KPRIORITY BasePriority;
ULONG ProcessId;
ULONG InheritedFromProcessId;
ULONG HandleCount;
ULONG SessionId;
ULONG_PTR PageDirectoryBase;
VM_COUNTERS VmCounters;
ULONG PrivatePageCount;
// add by achillis IO_COUNTERS IoCounters; SYSTEM_THREADS Threads[1]; } SYSTEM_PROCESSES, *PSYSTEM_PROCESSES;

 

執行緒資訊結構如下:

typedef struct _SYSTEM_THREADS{
    LARGE_INTEGER KernelTime;
    LARGE_INTEGER UserTime;
    LARGE_INTEGER CreateTime;
    ULONG WaitTime;
    PVOID StartAddress;
    CLIENT_ID ClientId;
    KPRIORITY Priority;
    LONG BasePriority;
    ULONG ContextSwitches;
    ULONG ThreadState;
    ULONG WaitReason;
    ULONG Reversed;
//add by achillis } SYSTEM_THREAD_INFORMATION,*PSYSTEM_THREADS;

 

紅色部分是我增加的,也不知道到底對不對,但是目前為止在我的XP SP2上可以得到正確結果。
列舉程序和執行緒資訊的程式碼如下:

int ShowProcess(void)
{
NTSTATUS status;
DWORD retlen,truelen;
char *buf=NULL,*p=NULL;
ANSI_STRING ansiStr;
int cnt=0;
PSYSTEM_PROCESSES pSysProcess;
PSYSTEM_THREADS pSysThread;
status=ZwQuerySystemInformation(SystemProcessInformation,NULL,0,&retlen);
truelen=retlen;
status=ZwAllocateVirtualMemory(NtCurrentProcess(),(PVOID*)&buf,0,&retlen,MEM_COMMIT,PAGE_READWRITE);
printf("Size of SYSTEM_THREAD:%d\n",sizeof(SYSTEM_THREADS));
p=buf;
status=ZwQuerySystemInformation(SystemProcessInformation,buf,truelen,&retlen);
do
{
   cnt++;
   pSysProcess=(PSYSTEM_PROCESSES)buf;
   RtlUnicodeStringToAnsiString(&ansiStr,&pSysProcess->ProcessName,TRUE);
   printf("Name:%s\n",ansiStr.Buffer);
   RtlFreeAnsiString(&ansiStr);
   printf("ThreadCnt:%d\t",pSysProcess->ThreadCount);
   printf("Priority:%d\t",pSysProcess->BasePriority);
   printf("PID:%4d\t",pSysProcess->ProcessId);
   printf("PPID:%d\n",pSysProcess->InheritedFromProcessId);
   printf("HandleCnt:%d\n",pSysProcess->HandleCount);
   //在每一項SYSTEM_PROCESS結構的最後是一個接一個的SYSTEM_THREAD結構
   //輸出每個執行緒的資訊
   if (pSysProcess->ThreadCount&&pSysProcess->ProcessId)
   {
    DWORD i=0;
    pSysThread=pSysProcess->Threads;
    for (;i<pSysProcess->ThreadCount;i++)
    {
     printf("Thread[%d] StartAddr:0x%08x\t",i+1,pSysThread->StartAddress);
     printf("TID:%d\t",pSysThread->ClientId.UniqueThread);
     printf("SwitchCnt:%d\n",pSysThread->ContextSwitchCount);
     pSysThread++;
    }
   }
   //若NextEntryDelta為0,則表明已結束
   if (pSysProcess->NextEntryDelta==0)
   {
    break;
   }
   buf=buf+pSysProcess->NextEntryDelta;
   printf("===============================================================\n");
}while (1);
printf("Total:%d\n",cnt);
status=ZwFreeVirtualMemory(NtCurrentProcess(),(PVOID*)&p,&truelen,MEM_RELEASE);
return 0;
}

 

寫到這兒又想起了經典的Hook ZwQuerySystemInfoamation隱藏程序,其實SYSTEM_PROCESS結構中的NextEntryDelta作為指向下一個結構的偏移量,其作用類似於指標,使整體構成了一個單鏈表,要隱藏就是從連結串列中刪除一個元素而已,簡單的資料結構知識,呵呵~