zoukankan      html  css  js  c++  java
  • 另类阻止驱动加载

    标 题: 【分享】【原创】另类阻止驱动加载
    作 者: czcqq
    时 间: 2010-05-04,22:27:47
    链 接: http://bbs.pediy.com/showthread.php?t=112338

    关于驱动的加载大概有几种方法
    1 在WINDOWS下动态加载
    2 在WINDOWS启动的时候加载
    3 感染系统文件


    对于 在WINDOWS启动的时候加载 和 感染系统文件 我们暂时不讨论,玩么只讨论动态加载


    一般的加载流程,是这样的:打开服务管理器->创建服务->启动服务->(系统加载驱动)
    这个过程系统最终会调用NtLoadDriver来加载驱动(也可以用Ntdll.dll里面的NtSetSystemInformation来加载)


    而NtLoadDriver 会向系统插入一个作业,然后等待另外一个系统线程来加载驱动,并等待驱动的加载完成(NtSetSystemInformation也是一样的),然后返回
    这样我们就可以HOOK NtLoadDriver和NtSetSystemInformation来阻止驱动加载,但是这个方法已经用烂了,这里我HOOK NtCreateSection来阻止驱动加载
    为什么HOOK NtCreateSection呢???
    因为在另外一个线程取得消息加载驱动的时候会调用NtCreateSection来映射驱动到内核内存空间


    (流程:大概是这样 IoCreateFile(打开驱动文件,将它的第二个参数设置为FILE_EXECUTE | SYNCHRONIZE) -> NtCreateSection(为驱动在内核内存空间创建一个节) ->NtMapViewOfSection(映射驱动到内核内存空间) -> 寻找驱动的DriverEntry,并调用 -> ZwClose(关闭文件句柄) ->然后通知NtLoadDriver(或者NtSetSystemInformation)驱动加载完成->NtLoadDriver(或者NtSetSystemInformation)返回用户层,并通知用户驱动加载完成)


    在驱动加载流程中,我们可以看到我们有很多机会劫持驱动的加载
    我们可以HOOK NtCreateSection 或者 NtMapViewOfSection 来阻止驱动加载
    这里我采用HOOK NtCreateSection的办法阻止驱动加载

    以下为代码



    #include <ntifs.h>

    //声明用到的头文件和结构 宏等
    #include "NtCreateSection.h"
    #if DBG
    #define DriversUnload(Address, p)                             
     Address->DriverUnload=p;
    #else
    #define DriversUnload(Address, p)                             
     Address->DriverUnload=NULL;
    #endif
    typedef int BOOL;
    typedef unsigned int        UINT;
    typedef unsigned long       DWORD;
    typedef unsigned short      WORD;
    typedef void *LPVOID;
    typedef unsigned char       BYTE;
    typedef DWORD          *PDWORD;
    typedef BYTE *PBYTE;
    typedef WORD            *PWORD;
    #define PAGE_NOACCESS          0x01     
    #define PAGE_READONLY          0x02     
    #define PAGE_READWRITE         0x04     
    #define PAGE_WRITECOPY         0x08     
    #define PAGE_EXECUTE           0x10     
    #define PAGE_EXECUTE_READ      0x20     
    #define PAGE_EXECUTE_READWRITE 0x40     
    #define PAGE_EXECUTE_WRITECOPY 0x80     
    #define PAGE_GUARD            0x100     
    #define PAGE_NOCACHE          0x200     
    #define PAGE_WRITECOMBINE     0x400     
    #define MEM_COMMIT           0x1000     
    #define MEM_RESERVE          0x2000     
    #define MEM_DECOMMIT         0x4000     
    #define MEM_RELEASE          0x8000     
    #define MEM_FREE            0x10000     
    #define MEM_PRIVATE         0x20000     
    #define MEM_MAPPED          0x40000     
    #define MEM_RESET           0x80000     
    #define MEM_TOP_DOWN       0x100000     
    #define MEM_4MB_PAGES    0x80000000     
    #define SEC_FILE           0x800000     
    #define SEC_IMAGE         0x1000000     
    #define SEC_VLM           0x2000000     
    #define SEC_RESERVE       0x4000000     
    #define SEC_COMMIT        0x8000000     
    #define SEC_NOCACHE      0x10000000     
    #define MEM_IMAGE         SEC_IMAGE  
    PVOID WriteAddress=NULL;
    PMDL pMdl=NULL; 
    //声明所需要的函数
    NTSYSAPI
    NTSTATUS
    NTAPI
    ZwYieldExecution(
    VOID
    );
    PVOID NTAPI GetJmpAddress(PVOID Fun,BOOL *Call_Code);
    NTSTATUS
    NTAPI
    CallBack_NtCreateSection (
        OUT PHANDLE SectionHandle,
        IN ACCESS_MASK DesiredAccess,
        IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
        IN PLARGE_INTEGER MaximumSize OPTIONAL,
        IN ULONG SectionPageProtection,
        IN ULONG AllocationAttributes,
        IN HANDLE FileHandle OPTIONAL
        );
    NTSTATUS
    NTAPI
    OldNtCreateSection (
        OUT PHANDLE SectionHandle,
        IN ACCESS_MASK DesiredAccess,
        IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
        IN PLARGE_INTEGER MaximumSize OPTIONAL,
        IN ULONG SectionPageProtection,
        IN ULONG AllocationAttributes,
        IN HANDLE FileHandle OPTIONAL
        );
    void makejmp(LPVOID Fun1,LPVOID Fun2,LPVOID jmp);
    #pragma alloc_text(PAGE,makejmp)
    #pragma alloc_text(PAGE,OldNtCreateSection)
    #pragma alloc_text(PAGE,CallBack_NtCreateSection)
    #pragma alloc_text(PAGE,GetJmpAddress)

    //所有声明结束


    //驱动入口

    NTSTATUS DriverEntry(
        IN PDRIVER_OBJECT  DriverObject,
        IN PUNICODE_STRING RegistryPath
      )
    {
      NTSTATUS Status = 0;
      PDEVICE_OBJECT pDeviceObject = NULL;
    //创建设备,这个就不讲解了,大家明白就好,我重点讲解HOOK过程
      Status = IoCreateDevice(
              DriverObject,
              0,
              NULL,
              FILE_DEVICE_UNKNOWN,
              0,
              FALSE,
              &pDeviceObject
              );

      if ( NT_SUCCESS(Status) ) {
        KIRQL oldIrql;
        PVOID HookAddress = NULL;

        BOOL Hook=0;
        PVOID JmpData=ExAllocatePool(NonPagedPool,5);//申请内存,用来保存内容为Jmp CallBack_NtCreateSection的代码
        DriversUnload(DriverObject,Unload);//设置DriverObject->DriverUnload = Unload;这个宏只有在调试版本的时候才会设置
    //DriverObject->DriverUnload = Unload;如果不是调试版本,就会设置DriverObject->DriverUnload = NULL;
        if(JmpData==NULL)
        {
          DbgPrint("HOOK NtCreateSection失败! 内存申请失败 ");
          return Status; 
        }
        memset(JmpData,0x90,5);//初始化JmpData内容为NOP
    //将NtCreateSection的头7个字节复制到OldNtCreateSection中来
          pMdl=IoCreateWriteMdlForAddress(OldNtCreateSection,&WriteAddress,7);
        if(pMdl==NULL)
        {
          DbgPrint("HOOK NtCreateSection失败! OldNtCreateSection 写入失败 ");
          ExFreePool(JmpData);
          JmpData=NULL;
                            WriteAddress=NULL;
                            pMdl=NULL;
          return Status;  
        }
        memcpy(WriteAddress,NtCreateSection,7);
        IoFreeMdlForAddress(WriteAddress,pMdl);
        WriteAddress=NULL;
    //将NtCreateSection的头5字节变成可写
        pMdl=IoCreateWriteMdlForAddress(NtCreateSection,&WriteAddress,7);
        if(pMdl==NULL)
        {
          DbgPrint("HOOK NtCreateSection失败! NtCreateSection 写入失败 ");
          ExFreePool(JmpData);
          JmpData=NULL;
                            WriteAddress=NULL;
                            pMdl=NULL;
          return Status; 
        }
    //检查是否已经被别人HOOK,如果已经被别人HOOK则我们退出HOOK,这里是可以改进的,但是我没有时间写,只能退出HOOK
        HookAddress=GetJmpAddress(NtCreateSection,&Hook);
        if(HookAddress!=NULL)
        {
          DbgPrint("HOOK NtCreateSection失败! 发现NtCreateSection已经被别人HOOK 所以本HOOK退出 ");
          ExFreePool(JmpData);
          JmpData=NULL;
          IoFreeMdlForAddress(WriteAddress,pMdl);
                            WriteAddress=NULL;
                            pMdl=NULL;
          return Status; 
        }
    //HOOK NtCreateSection
        if(NT_SUCCESS(ZwYieldExecution()))//先向系统申请CPU时间
        {
        _asm cli//关闭中断
        oldIrql = KeRaiseIrqlToDpcLevel();//提升到DPC级别
        memset(WriteAddress,0x90,7);//修改NtCreateSection的前7个字节为NOP指令
        makejmp(NtCreateSection,CallBack_NtCreateSection,JmpData);//取得 Jmp CallBack_NtCreateSection的代码,代码保存在JmpData中
        memcpy(WriteAddress,JmpData,5);//修改NtCreateSection前5个字节为 Jmp CallBack_NtCreateSection
        KeLowerIrql(oldIrql);//还原到原来的IRQL级别
        _asm sti//开中断

        }else
        {
          DbgPrint("申请CPU时间失败,HOOK退出 ");
        }
          ExFreePool(JmpData);
          JmpData=NULL;
          
      }

      return Status;
    }

    //我们的NtCreateSection过滤函数
    NTSTATUS
    NTAPI
    CallBack_NtCreateSection (
        OUT PHANDLE SectionHandle,
        IN ACCESS_MASK DesiredAccess,
        IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
        IN PLARGE_INTEGER MaximumSize OPTIONAL,
        IN ULONG SectionPageProtection,
        IN ULONG AllocationAttributes,
        IN HANDLE FileHandle OPTIONAL
        )
    {
      NTSTATUS Status = 0;
      Status = OldNtCreateSection(
          SectionHandle,
          DesiredAccess,
          ObjectAttributes ,
          MaximumSize ,
          SectionPageProtection,
          AllocationAttributes,
          FileHandle);
        if ( NT_SUCCESS(Status) )
      {
    //进行行为判断,如果是要加载驱动,我们就直接返回错误,并关闭句柄,如果不是就返回原来的结果
      if(((DWORD)PsGetCurrentProcessId()==(DWORD)4)|((DWORD)PsGetCurrentProcessId()==(DWORD)8)|((DWORD)PsGetCurrentProcessId()==(DWORD)0))
      {

        if((FlagOn(DesiredAccess,SECTION_MAP_EXECUTE))||(FlagOn(DesiredAccess,PAGE_EXECUTE_READ)))
        if((PAGE_EXECUTE==SectionPageProtection)|(AllocationAttributes==SEC_IMAGE))
        {
          ZwClose(*SectionHandle);
          *SectionHandle=NULL;
          return STATUS_ACCESS_DENIED;
        }
      }
      }
      return Status;
    }
    //用来跳转到原函数的一个裸函数
    __declspec(naked)NTSTATUS
    NTAPI
    OldNtCreateSection (
        OUT PHANDLE SectionHandle,
        IN ACCESS_MASK DesiredAccess,
        IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
        IN PLARGE_INTEGER MaximumSize OPTIONAL,
        IN ULONG SectionPageProtection,
        IN ULONG AllocationAttributes,
        IN HANDLE FileHandle OPTIONAL
        )
    {
      _asm
      {
        nop
          nop
          nop
          nop
          nop
          nop
          nop
          nop
          nop
          nop
          nop
          nop
          nop
          nop
          nop
          nop
          nop
          nop
          mov eax,NtCreateSection //将原函数地址送入eax
          add eax,7 //eax加7,用来跳过我们的HOOK
          push eax //将eax压入
          ret //跳回原函数
      }
    }

    //用来生成跳转代码的函数
       void makejmp(LPVOID Fun1,LPVOID Fun2,LPVOID jmp)
    {
      BYTE *data=(BYTE *)jmp;
        long dFun1=(long)Fun1;
      long dFun2=(long)Fun2;
      DWORD H;
      data[0]=0xe9;
      

      _asm
      {
      
          mov eax,dFun1
          mov edx,dFun2
          sub edx,eax
          sub edx,5
        mov H,edx
      }

      memcpy(&data[1],(void *)&H,4);

    }
    VOID Unload(
      IN PDRIVER_OBJECT DriverObject 
      )
    {
      KIRQL oldIrql;
      while(!NT_SUCCESS(ZwYieldExecution()))//取得CPU时间,如果取得失败,就一直获取,直到成功
      {
      }
      if(pMdl!=NULL)//检查我们是否已经进行过HOOK,//如果我们进行过HOOK 就还原
      {
      oldIrql = KeRaiseIrqlToDpcLevel();
      memcpy(WriteAddress,OldNtCreateSection,7);
      KeLowerIrql(oldIrql);
      IoFreeMdlForAddress(WriteAddress,pMdl);
      }
    IoDeleteDevice(DriverObject->DeviceObject);//删除设备

    pMdl=NULL;
    WriteAddress=NULL;
    }
    PVOID NTAPI GetJmpAddress(PVOID Fun,BOOL *Call_Code)
    {
        PVOID Return=NULL;
      BYTE *data=(BYTE *)Fun;
      DWORD Old=0;
      if(data[0]==0xe9)
      {
        *Call_Code=0;
      }else if (data[0]==0xe8)
      {
        *Call_Code=1;
      }else
      {
        *Call_Code=2;
        return NULL;
      }

      memcpy((void *)&Old,&data[1],4);
        _asm
      {
        mov eax,Old
        mov edx,Fun
        add eax,edx
        add eax,5
        mov Return,eax
      }
        return Return; 
    }



    这个驱动只支持单核心CPU 多核心CPU请自行修改(将所有CPU都提升到DPC级别 以后再进行HOOK)驱动加载流程是看了WIN2K的代码来讲的,WIN2K的代码很长,所以就简单的讲了一下*转载请注明来自看雪论坛@PEdiy.com  
    jpg改rar
  • 相关阅读:
    财务报表分析(张新民教授)-第五章 企业报表战略分析(1):资源配置战略(续)
    财务报表分析(张新民教授)-第五章 企业报表战略分析(1):资源配置战略
    财务报表分析(张新民教授)-第四章 企业经营活动与财务报表的关系
    以商品为生25:交易商品价差
    以商品为生22:页岩油与水力压裂的优缺点
    以商品为生17:石油价格历史——自1974年以来的高点和低点
    以商品为生15:商品交易中的Backwardation和Contango
    以商品为生14:大宗商品投资者的大豆交易指南
    以商品为生11:来自USDA的月度WASDE报告
    AJAX 跨域请求
  • 原文地址:https://www.cnblogs.com/kuangke/p/6259361.html
Copyright © 2011-2022 走看看