【旧文章搬运】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
",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
",ansiStr.Buffer);
   RtlFreeAnsiString(&ansiStr);
   printf("ThreadCnt:%d	",pSysProcess->ThreadCount);
   printf("Priority:%d	",pSysProcess->BasePriority);
   printf("PID:%4d	",pSysProcess->ProcessId);
   printf("PPID:%d
",pSysProcess->InheritedFromProcessId);
   printf("HandleCnt:%d
",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	",i+1,pSysThread->StartAddress);
     printf("TID:%d	",pSysThread->ClientId.UniqueThread);
     printf("SwitchCnt:%d
",pSysThread->ContextSwitchCount);
     pSysThread++;
    }
   }
   //若NextEntryDelta为0,则表明已结束
   if (pSysProcess->NextEntryDelta==0)
   {
    break;
   }
   buf=buf+pSysProcess->NextEntryDelta;
   printf("===============================================================
");
}while (1);
printf("Total:%d
",cnt);
status=ZwFreeVirtualMemory(NtCurrentProcess(),(PVOID*)&p,&truelen,MEM_RELEASE);
return 0;
}

写到这儿又想起了经典的Hook ZwQuerySystemInfoamation隐藏进程,其实SYSTEM_PROCESS结构中的NextEntryDelta作为指向下一个结构的偏移量,其作用类似于指针,使整体构成了一个单链表,要隐藏就是从链表中删除一个元素而已,简单的数据结构知识,呵呵~

原文地址:https://www.cnblogs.com/achillis/p/10180184.html