原文发表于百度空间,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作为指向下一个结构的偏移量,其作用类似于指针,使整体构成了一个单链表,要隐藏就是从链表中删除一个元素而已,简单的数据结构知识,呵呵~