• [驱动开发] 驱动隐藏 driveEntry返回失败


    常见隐藏驱动的方式:

    • 驱动模块断链
    • 调用MiProcessLoadEntry删除驱动对象(据说不会触发PG)
    • 清理MmUnloadDriver List 和 PiDDBCacheTable两处
    • driveEntry返回失败
    • 驱动模块加载后立即卸载

    今天介绍一种driveEntry返回失败隐藏驱动的方法 —— DriverEntry返回失败


    原理

    windows会根据DriverEntry的返回值判断驱动是否加载成功。如果返回成功,会在注册表详细记录,并将sys文件复制到System32/drivers目录下;如果失败,会回收执行代码时分配的栈空间,但此时代码已经执行。


    实现

    driverEntry执行的时候操作系统分配的栈内存,执行完毕会被回收,数据和代码都不会留下,只能额外在堆空间分配一块内存,把需要继续执行的代码和数据(本实验是回调函数)都留在堆上,本例中,回调函数需要打印。但call函数后面的操作数都是相对偏移,不是绝对地址。回调函数被复制到堆上,自身位置改变,打印函数的偏移肯定也变了,这里需要重定位,怎么办?

    先自定义一个函数指针,指向打印函数,但地址随便用个Magic Number糊弄; 等回调函数的代码拷贝到堆上后,再调用MmGetSystemRoutineAddress得到打印函数的地址,再写回函数指针;

    我个人的理解是写成类似 shellcode 的风格,也就是 “无地址相关”。

    完整代码如下(其实不多,也就100行左右):

    #include <fltKernel.h>
    
    typedef ULONG (__cdecl * DbgPrintType)(
        _In_z_ _Printf_format_string_ PCSTR Format,
        ...
    );
    
    #define DBG_PTR_TAG_MAGICNO 0xbabababababababa
    
    void MyLoadImageNotifyRoutine(
        PUNICODE_STRING FullImageName,
        HANDLE ProcessId,
        PIMAGE_INFO ImageInfo
    )
    {
        ProcessId = ProcessId;
        DbgPrintType MyDbgPrint = (DbgPrintType)DBG_PTR_TAG_MAGICNO;
        if (FullImageName != NULL && ImageInfo != NULL)
        {
            if ((ULONG_PTR)ImageInfo->ImageBase > (ULONG_PTR)0xf000000000000000)
            {
                MyDbgPrint("MyLoadImageNotifyRoutine: loading a kernel module: %wZ.\r\n",
                    FullImageName);
            }
        }
    }
    
    void DriverUnload(PDRIVER_OBJECT DriverObject)
    {
        DriverObject = DriverObject;
        KdPrint(("Hello, unloaded.\r\n"));
        PsRemoveLoadImageNotifyRoutine(MyLoadImageNotifyRoutine);
    }
    
    #define FUNC_LEN 0x100
    
    NTSTATUS
    DriverEntry(
        _In_ PDRIVER_OBJECT  DriverObject,
        _In_ PUNICODE_STRING RegistryPath
    )
    {
        NTSTATUS status = STATUS_SUCCESS;
        UNICODE_STRING dbgprint_str = RTL_CONSTANT_STRING(L"DbgPrint");
        //分配堆空间,后续把自己的回调函数(这部分代码还要执行)
        PVOID my_func_body = ExAllocatePoolWithTag(NonPagedPool, FUNC_LEN, 'Disp');
        DbgPrintType dbgprint_ptr = NULL;
        PUCHAR func_body_ptr = NULL;
        int i;
    
        // 防止警告。
        DriverObject = DriverObject;
        RegistryPath = RegistryPath;
        DbgBreakPoint();
    
        do {
            if (my_func_body == NULL)
            {
                status = STATUS_INSUFFICIENT_RESOURCES;
                break;
            }
    
            // 动态获取DbgPrint函数的地址。
            dbgprint_ptr = (DbgPrintType)MmGetSystemRoutineAddress(&dbgprint_str);
            if (dbgprint_ptr == NULL)
            {
                status = STATUS_UNSUCCESSFUL;
                break;
            }
            // 拷贝函数体。
            memcpy(my_func_body, (PVOID)MyLoadImageNotifyRoutine, FUNC_LEN);
    
            // 替换函数体中的立即数0xbabababababababa,使之变成DbgPrint函数的地址
            for (i = 0; i < FUNC_LEN; ++i)
            {
                func_body_ptr = (PUCHAR)my_func_body + i;
                if (*(ULONG_PTR*)func_body_ptr == (ULONG_PTR)DBG_PTR_TAG_MAGICNO)
                {
                    *(ULONG_PTR*)func_body_ptr = (ULONG_PTR)dbgprint_ptr;
                    break;
                }
            }
            if (i == FUNC_LEN)
            {
                status = STATUS_UNSUCCESSFUL;
                break;
            }
    
            // 将分配的堆函数注册成回调函数。
            status = PsSetLoadImageNotifyRoutine((PLOAD_IMAGE_NOTIFY_ROUTINE)my_func_body);
        } while (0);
        
        if (status != STATUS_SUCCESS && my_func_body != NULL)
        {
            ExFreePool(my_func_body);
        }
    
        // 返回失败,确保驱动"不加载"。
        status = STATUS_UNSUCCESSFUL;
        return status;
    

    效果如下:

    (1)反正在PCHUNTER的驱动模块页面是找不到了

    (2)加载驱动时看到的提示,给人感觉好像失败了:

    在这里插入图片描述

    但其实驱动的代码已经运行了,这里能正常检测和打印被加载的模块:

    在这里插入图片描述

    (3)内核模块还是能看到,但没有路径,不好找模块在哪,给分析增加难度:
    (但实际上开一个文件监控还是能找到驱动在哪)
    在这里插入图片描述

  • 相关阅读:
    6.VUE事件处理
    springmvc在使用@ModelAttribute注解获取Request和Response会产生线程并发不安全问题
    IDEAhttp://lookdiv.com/index/index/indexcodeindex.html
    不四舍五入保留...4(round(273.86015,4,1);)
    spring security中@PreAuthorize、@PostAuthorize、@PreFilter和@PostFilter四者的区别
    @RepeatSubmit spring boot 防止重复提交
    权限设计的杂谈
    vue设置全局样式变量 less
    坐标轴刻度取值算法-基于魔数数组-源于echarts的y轴刻度计算需求
    less使用
  • 原文地址:https://www.cnblogs.com/csnd/p/15613316.html
Copyright © 2020-2023  润新知