2019年1月19日星期六

没有对应驱动文件的系统线程

/*
早在2014.10.22都已经写过一个失败的隐藏系统线程的代码.
现在看来,当时失败在函数的处理上,里面有很多无效/非法的指令.

这几天突然看到:
https://github.com/tandasat/MemoryMon.git
https://github.com/Cr4sh/DrvHide-PoC.git
来个灵感的想法,写个测试,所以有了此文.

此驱动在procexp.exe是查不到的,因为驱动加载失败.
保留搜索内存的PE特征也应该搜索不到,因为驱动加载失败.
但是procexp.exe查看system的进程的线程信息能看到,但是你找不到对应的驱动,因为驱动加载失败.
假如驱动支持卸载,让驱动启动成功,卸载函数不做任何处理,我想驱动卸载后自己的那个系统线程还会继续运行.

最后说下:
这是个小玩意,
也许对你有用,
请勿用于非法用途,
小心MemoryMon监控出.
其实线程回调也能监控出,并进程识别和阻断(自己编写杀系统线程的代码)的.

编译环境:VS2017+WDK10
测试环境:Windows 10 x64

made by correy
made at 10:38 2019/1/19
https://correy.webs.com
*/

#include <ntifs.h>
#include <windef.h>
#include <intrin.h>

#define TAG 'tset' //test


PVOID gThreadObj;


/*
这里有众多的注意事项要说明:
1.函数内不准有异常处理的函数,特别是X64.
2.编译选项要关闭/JMC.否者会出现一些怪异的函数.
3.编译选项要关闭/guard:cf
4.此函数可考虑用汇编写.
5.此函数也可考虑用ShellCode写.
6.此函数不可访问本驱动的全局变量.
7.此函数不可直接调用系统的API,可获取地址,因为导入表在本驱动.
*/
#pragma region Context code that cannot reference any exports directly
#pragma optimize("", off)
#pragma check_stack(off)
#pragma runtime_checks("", off)


KSTART_ROUTINE MyThreadStart;
VOID MyThreadStart(__in PVOID  StartContext)
/*
此函数的功能在于的你的想象.
StartContext传入的内容,你想想吧!但这必须是你申请的内存,不可使本驱动的(局部或全局)变量.
*/
{
    //LARGE_INTEGER li;

    UNREFERENCED_PARAMETER(StartContext);

    __debugbreak();

    for (;;)
    {
        /*
        这里没有加退出条件。
        */

        __debugbreak();

        //li.QuadPart = -(10000 * 3 * 1000 * 60);
        //KeDelayExecutionThread(KernelMode, FALSE, &li);
    }

    //PsTerminateSystemThread(STATUS_SUCCESS);
}


VOID MyThreadEnd(VOID)
{
    NOTHING
}


#pragma runtime_checks("", restore)
#pragma check_stack()
#pragma optimize("", on)
#pragma endregion


DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry(__in struct _DRIVER_OBJECT  * DriverObject, __in PUNICODE_STRING  RegistryPath)
{
    NTSTATUS status = STATUS_SUCCESS;
    HANDLE                hThread = 0;
    OBJECT_ATTRIBUTES    oa;
    PVOID buffer = NULL;
    ULONG bufferLength = 0;

    UNREFERENCED_PARAMETER(RegistryPath);

    KdBreakPoint();

    bufferLength = (ULONG)((SIZE_T)MyThreadStart - (SIZE_T)MyThreadEnd);
    buffer = ExAllocatePoolWithTag(NonPagedPoolExecute, bufferLength, TAG);
    if (buffer == NULL) {
        return STATUS_INSUFFICIENT_RESOURCES;
    }
    RtlZeroMemory(buffer, bufferLength);

    RtlCopyMemory(buffer, (PVOID)MyThreadStart, bufferLength);
    /*
    此时检查buffer函数中有没非法的指令,有没调用非法的函数,调用的函数中有没非法的指令.
    可以与MyThreadStart函数做个对比.
    还可以对buffer下个断点.
    */

    InitializeObjectAttributes(&oa, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
    status = PsCreateSystemThread(&hThread, THREAD_ALL_ACCESS, &oa, NULL, NULL, (PKSTART_ROUTINE)buffer, NULL);
    if (!NT_SUCCESS(status))
    {
        KdPrint(("PsCreateSystemThread failed.\r\n"));
        return status;
    }

    ObReferenceObjectByHandle(hThread, THREAD_ALL_ACCESS, NULL, KernelMode, &gThreadObj, NULL);
    ZwClose(hThread);

    return STATUS_UNSUCCESSFUL;//不返回STATUS_CANCELLED也照样能运行那个线程的代码.
}

没有评论:

发表评论