//======================================获取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;
}
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课