代码:
//======================================获取pspcidtable地址CODE1======================= //利用PsLookupXX函数搜索特征码0x35ff和0xe8获取 ULONG GetAddrFromProcessId() { UNICODE_STRING pslookup; PUCHAR addr; //单字节指针 PUCHAR p; //单字节指针 ULONG q; //四字节 RtlInitUnicodeString(&pslookup,L"PsLookupProcessByProcessId"); addr=(PUCHAR)MmGetSystemRoutineAddress(&pslookup); KdPrint(("[PsLookupProcessByProcessId] addr:0x%x\n",addr)); for(p=addr;p<addr+PAGE_SIZE;p++) { if((*(PUSHORT)p==0x35ff)&&(*(p+6)==0xe8)) { q=*(PULONG)(p+2); KdPrint(("[GetAddrFromProcessId] pspcidtable:0x%x\n",q)); return q; break; } } return 0; } //======================================获取pspcidtable地址CODE2======================= //利用KPCR取得 ULONG GetAddrFromKpcr() { ULONG pspcidtable; //#define kpcr 0xffdff000 //kpcr+0x37 是KdVersionBlock //KdVersionBlock+0x80是pspcidtable指针 pspcidtable=*((PULONG)((*(PULONG)(kpcr+0x34)) + (ULONG)(0x80))); KdPrint(("[GetAddrFromKpcr] pspcidtable:0x%x\n",pspcidtable)); return pspcidtable; } //====================================获取pspciatable地址CODE3========================= //KdEnableDebugger->KdInitSystem->KdDebuggerDataBlock->KDDEBUGGER_DATA32->PspCidTable //====================================================================================== //====================================遍历pspcidtable CODE1========================= //利用导出的ExEnumHandleTable(ntoskrnl.exe导出函数),可以直接操作,不需要根据GMM自己定位地址 //================================================================================ //====================================自己遍历pspcidtable表========================= //=============通过当前进程获取进程对象指针(PsGetCurrentProcess函数获取object指针转换成object_header里面记录对象类型)=============== typedef struct _OBJECT_HEADER { union { struct { LONG PointerCount; LONG HandleCount; }; LIST_ENTRY Entry; }; POBJECT_TYPE Type; UCHAR NameInfoOffset; UCHAR HandleInfoOffset; UCHAR QuotaInfoOffset; UCHAR Flags; union { //POBJECT_CREATE_INFORMATION ObjectCreateInfo; PVOID QuotaBlockCharged; }; PSECURITY_DESCRIPTOR SecurityDescriptor; QUAD Body; } OBJECT_HEADER, *POBJECT_HEADER; ULONG GetProcessType() { ULONG type; ULONG objecttoeprocess; objecttoeprocess=(ULONG)PsGetCurrentProcess(); //object转换成object_header完全可以object-0x18 objecttoeprocess=(ULONG)OBJECT_TO_OBJECT_HEADER(objecttoeprocess); type=*(PULONG)(objecttoeprocess+TYPE); KdPrint(("[GetProcessType] type:0x%x\n",type)); return type; } //===================================采用单链表记录进程Eprocess地址================================================ void RecordProcess(ULONG address) //address { PROCESSINFO *r; if(head==NULL) { head=(PROCESSINFO *)ExAllocatePoolWithTag(NonPagedPool,sizeof(PROCESSINFO),MEM_TAG);//分配头指针 if(head==NULL) { KdPrint(("[RecoardProcess] Aloocate error\n")); } //分配内存,用完必须释放,否则内存泄漏 head->addr=0x0; } if(head->addr==0x0) { head->addr=address; KdPrint(("[RecordProcess] head->addr:0x%x",head->addr)); p=head; } else { r=(PROCESSINFO *)ExAllocatePoolWithTag(NonPagedPool,sizeof(PROCESSINFO),MEM_TAG); if(r==NULL) { KdPrint(("[RecoardProcess] Aloocate error\n")); } p->next=r; p=r; r->addr=address; KdPrint(("[RecoardProcess] r->addr:0x%x\n",r->addr)); r->next=NULL; } } //==================================根据PID找对象指针===================================================== void GetPointerToObject(ULONG table,ULONG pid)//函数返回的object即指向EPROCESS的指针 { ULONG object,objectheader; ULONG NextFreeTableEntry; ULONG processtype,type; ULONG flags; processtype=GetProcessType();//调用函数获取进程类型 if(MmIsAddressValid((PULONG)(table+pid*2))) { if(MmIsAddressValid((PULONG)(table+ pid*2 +NEXTFREETABLEENTRY))) { NextFreeTableEntry=*(PULONG)(table + pid*2 + NEXTFREETABLEENTRY); if(NextFreeTableEntry==0)//正常的handle_table_entry中NextFreeTableEntry为0 { object=*(PULONG)(table+pid*2); object=((object | 0x80000000)& 0xfffffff8);//转换为对象指针 KdPrint(("[GetPointerToObject] object:0x%x\n",object)); //函数要记录的进程ERROCESS地址 objectheader=(ULONG)OBJECT_TO_OBJECT_HEADER(object);//获取对象头指针 KdPrint(("[GetPointerToObject] objectheader:0x%x\n",objectheader)); if(MmIsAddressValid((PULONG)(objectheader+TYPE))) { type=*(PULONG)(objectheader+TYPE); if(type==processtype)//表明是进程对象 { flags=*(PULONG)(object+FLAGS);//EPROCESS中Flags偏移量,指明了进程的死活 //KdPrint(("[GetPointerToObject]) flags:0x%x\n",flags) if((flags&0xc)!=0xc)//死进程的flags最后一位为C { RecordProcess(object); num=num+1; //进程数量 } } } } } } } //==================================遍历pspcidtable列举进程信息============================================ void ListProcess() { ULONG pspcidtable; ULONG tablecode; ULONG table1,table2,table3,table4,table5; //2层表正常情况下足够存放进程了,所以3层表就不考虑 ULONG cid; ULONG NextHandleNeedingPool; pspcidtable=GetAddrFromKpcr(); //取pspcidtable地址 KdPrint(("[ListProcess]pspcidtable:0x%x\n",pspcidtable)); if(MmIsAddressValid((PULONG)pspcidtable))//地址是否有效 { tablecode=*(PULONG)(*(PULONG)pspcidtable);//取tablecode地址 NextHandleNeedingPool=*(PULONG)(*(PULONG)pspcidtable+0x038);//NextHandleNeedingPool值 KdPrint(("[ListProcess] tablecode:0x%x\n",tablecode)); KdPrint(("[ListProcess] NextHandleNeedingPool:0x%0x\n",NextHandleNeedingPool)); //PID最大值 if((tablecode & 0x00000003)==0)//1层表存放的就是handle_table的基址 { table1=tablecode; KdPrint(("[ListProcess] table1:0x%0x\n",table1)); table2=0; } else if((tablecode & 0x00000003)==1)//2层表,一级表存放的是指向2级表的指针 { tablecode=tablecode&0xfffffffe; //低二位清零 table1=*(PULONG)tablecode; //1个表存放0x800=2048大的PID,不够大 table2=*(PULONG)(tablecode+4);//2个表存放0x1000=4096大的PID,不够大 table3=*(PULONG)(tablecode+8);//3个表存放0x1800=6144大的PID,不够大 table4=*(PULONG)(tablecode+12);//4个表可以存放0x2000=8192大的PID,还不够大啊 table5=*(PULONG)(tablecode+16);//5个表可以存放0x2800=10240的的PID,足够了吧 KdPrint(("[ListProcess] table1:0x%x\n",table1)); KdPrint(("[ListProcess] table2:0x%x\n",table2)); KdPrint(("[ListProcess] table3:0x%x\n",table3)); KdPrint(("[ListProcess] table4:0x%x\n",table4)); KdPrint(("[ListProcess] table5:0x%x\n",table5)); } //遍历 for(cid=0;cid<NextHandleNeedingPool;cid=cid+4)//要加4 { if((table1!=0)&&(cid<=0x800))//在第一个表中 { GetPointerToObject(table1,cid); } if((table2!=0)&&(0x800<cid && cid<=0x1000))//在第二个表中 { cid=(ULONG)(cid-0x800); //KdPrint(("[ListProcess] cid 0x%x\n",cid)); GetPointerToObject(table2,cid); cid=(ULONG)(cid+0x800); //KdPrint(("[ListProcess] cid 0x%x\n",cid)); } if((table3!=0)&&(0x1000<cid && cid<=0x1800))//在第三个表中 { cid=(ULONG)(cid-0x1000); GetPointerToObject(table3,cid); cid=(ULONG)(cid+0x1000); } if((table4!=0)&&(0x1800<cid && cid<=0x2000))//在第四个表中 { cid=(ULONG)(cid-0x1800); GetPointerToObject(table4,cid); cid=(ULONG)(cid+0x1800); } if((table5!=0)&&(0x2000<cid && cid<=0x2800))//在第五个表中 { cid=(ULONG)(cid-0x2000); GetPointerToObject(table5,cid); cid=(ULONG)(cid+0x2000); } } } } // //取进程全路径==================================================================== //原理Eprocess->sectionobject(0x138)->Segment(0x014)->ControlAera(0x000)->FilePointer(0x024)->(FileObject->FileName,FileObject->DeviceObject) void GetProcessPath(ULONG eprocess,CHAR ProcessPath[256]) { ULONG object; PFILE_OBJECT FilePointer; UNICODE_STRING path; //路径 UNICODE_STRING name; //盘符 ANSI_STRING string; path.Length=0; path.MaximumLength=256; path.Buffer=(PWCHAR)ExAllocatePoolWithTag(NonPagedPool,256,MEM_TAG); //必须释放 if(MmIsAddressValid((PULONG)(eprocess+0x138)))//Eprocess->sectionobject(0x138) { object=(*(PULONG)(eprocess+0x138)); KdPrint(("[GetProcessFileName] sectionobject :0x%x\n",object)); if(MmIsAddressValid((PULONG)((ULONG)object+0x014))) { object=*(PULONG)((ULONG)object+0x014); KdPrint(("[GetProcessFileName] Segment :0x%x\n",object)); if(MmIsAddressValid((PULONG)((ULONG)object+0x0))) { object=*(PULONG)((ULONG_PTR)object+0x0); KdPrint(("[GetProcessFileName] ControlAera :0x%x\n",object)); if(MmIsAddressValid((PULONG)((ULONG)object+0x024))) { object=*(PULONG)((ULONG)object+0x024); KdPrint(("[GetProcessFileName] FilePointer :0x%x\n",object)); } else return ; } else return ; } else return ; } else return ; FilePointer=(PFILE_OBJECT)object; //KdPrint(("[GetProcessFileName] FilePointer :%wZ\n",&FilePointer->FileName)); ObReferenceObjectByPointer((PVOID)FilePointer,0,NULL,KernelMode);//引用计数+1,操作对象 RtlVolumeDeviceToDosName(FilePointer->DeviceObject,&name); //获取盘符名 //KdPrint(("[GetProcessFileName] FilePointer :%wZ\n",&name)); RtlCopyUnicodeString(&path,&name);//盘符连接 RtlAppendUnicodeStringToString(&path,&FilePointer->FileName);//路径连接 //KdPrint(("[GetProcessFileName] FilePointer :%wZ\n",&path)); ObDereferenceObject(FilePointer); //关闭对象引用 //需要转换成ANSI_STRING,然后在转换成char输出给ring3 RtlUnicodeStringToAnsiString(&string,&path,TRUE); //释放内存 if(string.Length >= 256 ) //保证以\0结尾 { memcpy(ProcessPath, string.Buffer, 256); *(ProcessPath + 255) = 0; } else { memcpy(ProcessPath, string.Buffer, string.Length); ProcessPath[string.Length] = 0; } ExFreePool(path.Buffer); //释放 RtlFreeAnsiString(&string);//释放 } //====================================进程信息========================================================== void GetProcessInformation()//获取进程名,PID,路径 { ListProcess(); //调用函数 KdPrint(("[DispatchIoctl] num:%d\n",num));//打印出进程数量 for(p=head;MmIsAddressValid(p);p=p->next) //写实现功能,获取进程PID,进程名,图标、全路径 { //KdPrint(("===============================================\n")); KdPrint(("[GetProcessInformation] EPROCESS:0x%x\n",p->addr)); //EPROCESS获取进程名 //XP下0x084偏移存放的进程PID //XP下0x174偏移存放的进程ProcessName p->pid=*(int *)(p->addr+CID); KdPrint(("[GetProcessInformation] PID:%d\n",p->pid)); //进程PID KdPrint(("===============================================\n")); memcpy(p->name,(PUCHAR)(p->addr+NAME),16); KdPrint(("[GetProcessInformation] ProcessName:%s\n",p->name)); //进程名 //获取全路径 GetProcessPath(p->addr,p->Path); KdPrint(("[GetProcessInformation] ProcessPath:%s\n",p->Path)); //进程全路径 } } //==================================释放链表函数========================================================= void FreeList() { //释放链表,释放内存 PROCESSINFO *q; p=head; q=p->next; while(q!=NULL) { KdPrint(("[DispathIoctl] p->addr:0x%x\n",p->addr)); ExFreePool(p); p=q; q=p->next; n=n+1; } KdPrint(("[DispathIoctl] p->addr:0x%x\n",p->addr)); ExFreePool(p); head=NULL; //不知道ExFreePool释放后head竟然不为NULL.p和head都是全局变量 n=n+1; KdPrint(("[DispatchIoctl] n:%d\n",n));//打印出释放进程数量 n=0; }