pspcidtable

来源:互联网 发布:旧版淘宝下载 编辑:程序博客网 时间:2024/05/18 01:45

第8个男人" 的code里面就做的很好,找到PspCidTable后自己搜索所有的进程对象就行了:

//----------------------------------------------------------------------
VOID
IsValidProcess ()
/*++

Author : 第8个男人
Leaner : sudami [xiao_rui_119@163.com]
Time : 08/02/15

参数 : NULL

返回 : NULL


功能 :
给出PspCidTable的地址,结合_EXHANDLE、HANDLE_TABLE、HANDLE_TABLE_ENTRY
搜索到每个进程对象,纪录之.
前提条件: 假设暂且PspCidTable没有被抹掉

--*/

{
ULONG PspCidTable;
ULONG TableCode;
ULONG table1,table2;
ULONG object,objectheader;
ULONG NextFreeTableEntry;
ULONG processtype,type;
ULONG flags;
ULONG i;

PspCidTable = GetCidAddr(); // 搜索PsLookupProcessByProcessId函中的特征串即可
processtype = GetProcessType();

if (PspCidTable == 0) {
return ;
} else { //TableCode的低2位决定句柄表的级数

TableCode = *(PULONG) ( *(PULONG) PspCidTable );

if ( (TableCode & 3) == 0 ) { // 0级
table1 = TableCode;
table2 = 0;
} else if ( (TableCode & 3 ) == 1 ) { // 1级
TableCode = TableCode & 0xfffffffc;
table1 = *(PULONG)TableCode;
table2 = *(PULONG)( TableCode + 4 );
}

// 对cid从0x0到0x4e1c进行遍历
for (i = 0; i < 0x4e1c; i++) {
if (i <= 0x800) { // 第一张表中
if (MmIsAddressValid( (PULONG)(table1 + i*2) )) {

// HANDLE_TABLE_ENTRY地址 + PID * 2 ---> 对象的地址
object = *(PULONG)( table1 + i*2 );
if (MmIsAddressValid( (PULONG)(table1 + i*2 + NEXTFREETABLEENTRY) )) {

// 验证HANDLE_TABLE_ENTRY的合法性,这在ExEnumHandleTable函数的代码中也有
// 正常的_HANDLE_TABLE_ENTRY中NextFreeTableEntry应该为0
NextFreeTableEntry = *(PULONG)(table1 + i*2 + NEXTFREETABLEENTRY);
if (NextFreeTableEntry == 0) {
// 去掉低3位掩码标志
object = ((object | 0x80000000) & 0xfffffff8); // 转换为对象(体)指针
objectheader = (ULONG) /
OBJECT_TO_OBJECT_HEADER(object); // 获取对象(头)指针

if (MmIsAddressValid( (PULONG)(objectheader + TYPE) )) {
type = *(PULONG)(objectheader + TYPE);
if (type == processtype) { // 是否为进程对象

flags = *(PULONG)( (ULONG)object + /
GetPlantformDependentInfo(OFFSET_EPROCESS_FLAGS) );
if ((flags&0xc) != 0xc)
RecordInfo( object ); //flags显示进程没有退出
}
}
}
}
}
} else { // 第2张表

if (table2 != 0) {
// 步骤同上,只是object的获取为: HANDLE_TABLE_ENTRY地址 + (PID- 0x800)*2
if (MmIsAddressValid( (PULONG)(table2 + (i - 0x800)*2) )) {
object = *(PULONG)(table2 + (i - 0x800)*2);
if (MmIsAddressValid((PULONG)((table2+(i-0x800)*2)+NEXTFREETABLEENTRY))) {
NextFreeTableEntry=*(PULONG)((table2+(i-0x800)*2)+NEXTFREETABLEENTRY);
if (NextFreeTableEntry==0x0) {
object = ((object | 0x80000000) & 0xfffffff8);
objectheader = (ULONG) OBJECT_TO_OBJECT_HEADER(object);
if (MmIsAddressValid( (PULONG)(objectheader + TYPE) )) {
type = *(PULONG)(objectheader + TYPE);

if(type == processtype) {
flags = *(PULONG) ((ULONG)object + /
GetPlantformDependentInfo(OFFSET_EPROCESS_FLAGS));
if ((flags&0xc) != 0xc)
RecordInfo(object);
}
}
}
}
}
}
}
}
}
}
对以上这段代码,有点疑问?
句柄表是个三层表,一级表(基本表)可以存放0x200(512-1)个句柄,最大PID是0x800,当PID大于0x800时就要用2层表,2级表存放的是指向一级表的指针。一层表只有一个,指向许多个基本表。可以windbg验证。而上面代码只是table1,table2仅仅表明只有2个1级表,这完全不对吧。就一我系统为例,就存在3个1级表。而自己遍历PID仅仅考虑pid>0x800和pid<0x8002种情况,但是当PID>0x800是在第二个1级表,当pid>0x1000在第三个一级表,当pid>0x1800在第四个1级表。。。一次类推,所以上面代码好像不对啊。
根据理解,系统用2层表已经够存放进程句柄了,2级表存放指向一级表的指针,一级表存放的是表的基址。
下面是我根据理解写的代码:

//======================================获取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地址================================================
//记录进程信息的结构体

typedef struct _PROCESSINFO
{
ULONG addr; //进程对象指针,指向EPROCESS
ULONG pid; //进程PID
UCHAR name[20]; //进程名
UCHAR ProcessPath[256];//进程全路径
ULONG flag; //进程隐藏标志,1表示隐藏,否则为0
struct _PROCESSINFO *next; //单向链表指针,指向下一个进程
}PROCESSINFO,*PPROCESSINFO;
PROCESSINFO *head,*p;//定义头指针


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/n",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+(ULONG)0x038);


        KdPrint(("[ListProcess] tablecode:0x%x/n",tablecode));
KdPrint(("[ListProcess] NextHandleNeedingPool:0x%0x/n",NextHandleNeedingPool));


       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((cid<=0x800) && (table1!=0))//在第一个表中
{
GetPointerToObject(table1,cid);
}
else if((cid<=0x1000) && (table2!=0))//在第二个表中
{
cid=cid-0x800;
GetPointerToObject(table2,cid);
}
else if((cid<=0x1800) && (table3!=0))//在第三个表中
{
cid=cid-0x1000;
GetPointerToObject(table3,cid);

}
else if((cid<=0x2000) && (table4!=0))//在第四个表中
{
cid=cid-0x1800;
GetPointerToObject(table4,cid);
}
else if((cid<=0x2800) && (table5!=0))//在第五个表中
{
cid=cid-0x2000;
GetPointerToObject(table5,cid);
}
}

}

}

原创粉丝点击