标 题: 【原创】ring0检测隐藏进程
作 者: 堕落天才
时 间: 2007-05-10,13:28
链 接: http://bbs.pediy.com/showthread.php?t=44243
//网上得到一篇好文章 Ring0下搜索内存枚举隐藏进程 ,但是拿里面的代码来使用的时候发现并没有太多效果
//于是修改之,终于实现了最初的目标
//由于直接搜索内存,跟系统调度没什么关系,所以能够枚举到各种方法隐藏的进程 包括断链、抹PspCidTable...
//甚至能枚举到已经"死掉"的进程,本程序通过进程的ExitTime来判断进程是不是已经结束
//除非能够把EProcess结构修改掉,但这个实现难度可能比较大,不知有没有哪位大侠试过(PID我修改过),欢迎讨论
//
//作者:堕落天才
//时间:2007年5月10日
//参考: uty Ring0下搜索内存枚举隐藏进程 http://www.cnxhacker.net/Article/show/3412.html
//下面代码在XP SP2测试通过
#include<ntddk.h>
///////////////////////////不同的windows版本下面的偏移值不同
#define EPROCESS_SIZE 0x25C //EPROCESS结构大小
#define PEB_OFFSET 0x1B0
#define FILE_NAME_OFFSET 0x174
#define PROCESS_LINK_OFFSET 0x088
#define PROCESS_ID_OFFSET 0x084
#define EXIT_TIME_OFFSET 0x078
#define OBJECT_HEADER_SIZE 0x018
#define OBJECT_TYPE_OFFSET 0x008
#define PDE_INVALID 2
#define PTE_INVALID 1
#define VALID 0
ULONG pebAddress; //PEB地址的前半部分
PEPROCESS pSystem; //system进程
ULONG pObjectTypeProcess; //进程对象类型
ULONG VALIDpage(ULONG addr) ; //该函数直接复制自 Ring0下搜索内存枚举隐藏进程
BOOLEAN IsaRealProcess(ULONG i); //该函数复制自 Ring0下搜索内存枚举隐藏进程
VOID WorkThread(IN PVOID pContext);
ULONG GetPebAddress(); //得到PEB地址前半部分
VOID EnumProcess(); //枚举进程
VOID ShowProcess(ULONG pEProcess); //显示结果
VOID OnUnload(IN PDRIVER_OBJECT DriverObject)
{
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath)
{
HANDLE hThread;
DriverObject -> DriverUnload = OnUnload;
pSystem = PsGetCurrentProcess();
pebAddress = GetPebAddress();
pObjectTypeProcess = *(PULONG)((ULONG)pSystem - OBJECT_HEADER_SIZE +OBJECT_TYPE_OFFSET);
PsCreateSystemThread(&hThread,
(ACCESS_MASK)0,
NULL,
(HANDLE)0,
NULL,
WorkThread,
NULL );
return STATUS_SUCCESS;
}
//////////////////////////////////////////////
VOID WorkThread(IN PVOID pContext)
{
EnumProcess();
PsTerminateSystemThread(STATUS_SUCCESS);
}
////////////////////////////////////////////////////////
ULONG GetPebAddress()
{
ULONG Address;
PEPROCESS pEProcess;
//由于system进程的peb总是零 我们只有到其他进程去找了
pEProcess = (PEPROCESS)((ULONG)((PLIST_ENTRY)((ULONG)pSystem + PROCESS_LINK_OFFSET))->Flink - PROCESS_LINK_OFFSET);
Address = *(PULONG)((ULONG)pEProcess + PEB_OFFSET);
return (Address & 0xFFFF0000);
}
///////////////////////////////////////////////////////
VOID EnumProcess()
{
ULONG uSystemAddress = (ULONG)pSystem;
ULONG i;
ULONG Address;
ULONG ret;
DbgPrint("-------------------------------------------");
DbgPrint("EProcess PID ImageFileName");
DbgPrint("---------------------------------");
for(i = 0x80000000; i < uSystemAddress; i += 4){//system进程的EPROCESS地址就是最大值了
ret = VALIDpage(i);
if (ret == VALID){
Address = *(PULONG)i;
if (( Address & 0xFFFF0000) == pebAddress){//每个进程的PEB地址都是在差不多的地方,地址前半部分是相同的
if(IsaRealProcess(i)){
ShowProcess(i - PEB_OFFSET);
i += EPROCESS_SIZE;
}
}
}else if(ret == PTE_INVALID){
i -=4;
i += 0x1000;//4k
}else{
i-=4;
i+= 0x400000;//4mb
}
}
ShowProcess(uSystemAddress);//system的PEB总是零 上面的方法是枚举不到的 不过我们用PsGetCurrentProcess就能得到了
DbgPrint("-------------------------------------------");
}
/////////////////////////////////////////////////////////
VOID ShowProcess(ULONG pEProcess)
{
PLARGE_INTEGER ExitTime;
ULONG PID;
PUCHAR pFileName;
ExitTime = (PLARGE_INTEGER)(pEProcess + EXIT_TIME_OFFSET);
if(ExitTime->QuadPart != 0) //已经结束的进程的ExitTime为非零
return ;
PID = *(PULONG)(pEProcess + PROCESS_ID_OFFSET);
pFileName = (PUCHAR)(pEProcess + FILE_NAME_OFFSET);
DbgPrint("0x%08X %04d %s",pEProcess,PID,pFileName);
}
/////////////////////////////////////////////////////////////
ULONG VALIDpage(ULONG addr)
{
ULONG pte;
ULONG pde;
pde = 0xc0300000 + (addr>>22)*4;
if((*(PULONG)pde & 0x1) != 0){
//large page
if((*(PULONG)pde & 0x80) != 0){
return VALID;
}
pte = 0xc0000000 + (addr>>12)*4;
if((*(PULONG)pte & 0x1) != 0){
return VALID;
}else{
return PTE_INVALID;
}
}
return PDE_INVALID;
}
////////////////////////////////////////////////////////////////
BOOLEAN IsaRealProcess(ULONG i)
{
NTSTATUS STATUS;
PUNICODE_STRING pUnicode;
UNICODE_STRING Process;
ULONG pObjectType;
ULONG ObjectTypeAddress;
if (VALIDpage(i- PEB_OFFSET) != VALID){
return FALSE;
}
ObjectTypeAddress = i - PEB_OFFSET - OBJECT_HEADER_SIZE + OBJECT_TYPE_OFFSET ;
if (VALIDpage(ObjectTypeAddress) == VALID){
pObjectType = *(PULONG)ObjectTypeAddress;
}else{
return FALSE;
}
if(pObjectTypeProcess == pObjectType){ //确定ObjectType是Process类型
return TRUE;
}
return FALSE;
}
////////////////////////////////////////////////////////////////////
作 者: 堕落天才
时 间: 2007-05-10,13:28
链 接: http://bbs.pediy.com/showthread.php?t=44243
//网上得到一篇好文章 Ring0下搜索内存枚举隐藏进程 ,但是拿里面的代码来使用的时候发现并没有太多效果
//于是修改之,终于实现了最初的目标
//由于直接搜索内存,跟系统调度没什么关系,所以能够枚举到各种方法隐藏的进程 包括断链、抹PspCidTable...
//甚至能枚举到已经"死掉"的进程,本程序通过进程的ExitTime来判断进程是不是已经结束
//除非能够把EProcess结构修改掉,但这个实现难度可能比较大,不知有没有哪位大侠试过(PID我修改过),欢迎讨论
//
//作者:堕落天才
//时间:2007年5月10日
//参考: uty Ring0下搜索内存枚举隐藏进程 http://www.cnxhacker.net/Article/show/3412.html
//下面代码在XP SP2测试通过
#include<ntddk.h>
///////////////////////////不同的windows版本下面的偏移值不同
#define EPROCESS_SIZE 0x25C //EPROCESS结构大小
#define PEB_OFFSET 0x1B0
#define FILE_NAME_OFFSET 0x174
#define PROCESS_LINK_OFFSET 0x088
#define PROCESS_ID_OFFSET 0x084
#define EXIT_TIME_OFFSET 0x078
#define OBJECT_HEADER_SIZE 0x018
#define OBJECT_TYPE_OFFSET 0x008
#define PDE_INVALID 2
#define PTE_INVALID 1
#define VALID 0
ULONG pebAddress; //PEB地址的前半部分
PEPROCESS pSystem; //system进程
ULONG pObjectTypeProcess; //进程对象类型
ULONG VALIDpage(ULONG addr) ; //该函数直接复制自 Ring0下搜索内存枚举隐藏进程
BOOLEAN IsaRealProcess(ULONG i); //该函数复制自 Ring0下搜索内存枚举隐藏进程
VOID WorkThread(IN PVOID pContext);
ULONG GetPebAddress(); //得到PEB地址前半部分
VOID EnumProcess(); //枚举进程
VOID ShowProcess(ULONG pEProcess); //显示结果
VOID OnUnload(IN PDRIVER_OBJECT DriverObject)
{
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath)
{
HANDLE hThread;
DriverObject -> DriverUnload = OnUnload;
pSystem = PsGetCurrentProcess();
pebAddress = GetPebAddress();
pObjectTypeProcess = *(PULONG)((ULONG)pSystem - OBJECT_HEADER_SIZE +OBJECT_TYPE_OFFSET);
PsCreateSystemThread(&hThread,
(ACCESS_MASK)0,
NULL,
(HANDLE)0,
NULL,
WorkThread,
NULL );
return STATUS_SUCCESS;
}
//////////////////////////////////////////////
VOID WorkThread(IN PVOID pContext)
{
EnumProcess();
PsTerminateSystemThread(STATUS_SUCCESS);
}
////////////////////////////////////////////////////////
ULONG GetPebAddress()
{
ULONG Address;
PEPROCESS pEProcess;
//由于system进程的peb总是零 我们只有到其他进程去找了
pEProcess = (PEPROCESS)((ULONG)((PLIST_ENTRY)((ULONG)pSystem + PROCESS_LINK_OFFSET))->Flink - PROCESS_LINK_OFFSET);
Address = *(PULONG)((ULONG)pEProcess + PEB_OFFSET);
return (Address & 0xFFFF0000);
}
///////////////////////////////////////////////////////
VOID EnumProcess()
{
ULONG uSystemAddress = (ULONG)pSystem;
ULONG i;
ULONG Address;
ULONG ret;
DbgPrint("-------------------------------------------");
DbgPrint("EProcess PID ImageFileName");
DbgPrint("---------------------------------");
for(i = 0x80000000; i < uSystemAddress; i += 4){//system进程的EPROCESS地址就是最大值了
ret = VALIDpage(i);
if (ret == VALID){
Address = *(PULONG)i;
if (( Address & 0xFFFF0000) == pebAddress){//每个进程的PEB地址都是在差不多的地方,地址前半部分是相同的
if(IsaRealProcess(i)){
ShowProcess(i - PEB_OFFSET);
i += EPROCESS_SIZE;
}
}
}else if(ret == PTE_INVALID){
i -=4;
i += 0x1000;//4k
}else{
i-=4;
i+= 0x400000;//4mb
}
}
ShowProcess(uSystemAddress);//system的PEB总是零 上面的方法是枚举不到的 不过我们用PsGetCurrentProcess就能得到了
DbgPrint("-------------------------------------------");
}
/////////////////////////////////////////////////////////
VOID ShowProcess(ULONG pEProcess)
{
PLARGE_INTEGER ExitTime;
ULONG PID;
PUCHAR pFileName;
ExitTime = (PLARGE_INTEGER)(pEProcess + EXIT_TIME_OFFSET);
if(ExitTime->QuadPart != 0) //已经结束的进程的ExitTime为非零
return ;
PID = *(PULONG)(pEProcess + PROCESS_ID_OFFSET);
pFileName = (PUCHAR)(pEProcess + FILE_NAME_OFFSET);
DbgPrint("0x%08X %04d %s",pEProcess,PID,pFileName);
}
/////////////////////////////////////////////////////////////
ULONG VALIDpage(ULONG addr)
{
ULONG pte;
ULONG pde;
pde = 0xc0300000 + (addr>>22)*4;
if((*(PULONG)pde & 0x1) != 0){
//large page
if((*(PULONG)pde & 0x80) != 0){
return VALID;
}
pte = 0xc0000000 + (addr>>12)*4;
if((*(PULONG)pte & 0x1) != 0){
return VALID;
}else{
return PTE_INVALID;
}
}
return PDE_INVALID;
}
////////////////////////////////////////////////////////////////
BOOLEAN IsaRealProcess(ULONG i)
{
NTSTATUS STATUS;
PUNICODE_STRING pUnicode;
UNICODE_STRING Process;
ULONG pObjectType;
ULONG ObjectTypeAddress;
if (VALIDpage(i- PEB_OFFSET) != VALID){
return FALSE;
}
ObjectTypeAddress = i - PEB_OFFSET - OBJECT_HEADER_SIZE + OBJECT_TYPE_OFFSET ;
if (VALIDpage(ObjectTypeAddress) == VALID){
pObjectType = *(PULONG)ObjectTypeAddress;
}else{
return FALSE;
}
if(pObjectTypeProcess == pObjectType){ //确定ObjectType是Process类型
return TRUE;
}
return FALSE;
}
////////////////////////////////////////////////////////////////////