实现内核级 HOOK 对于拦截、分析、跟踪系统内核起着致关重要的作用。实现的方法不同意味着应用侧重点的不同。如想要拦截 NATIVE API 那么可能常用的就是 HOOK SERVICE TABLE 的方法。如果要分析一些系统调用,那么可能想到用 HOOK INT 2E 中断来实现。如果想要拦截或跟踪其他内核 DRIVER 的调用,那么就要用到HOOK PE 的方法来实现。这里我们更注重的是实现,原理方面已有不少高手在网上发表过文章。大家可以结合起来读。下面以我写的几个实例程序来讲解一下各种方法的实现。错误之处还望各位指正。

1、HOOK SERVICE TABLE 方法: 
   这种方法对于拦截 NATIVE API 来说用的比较多。原理就是通过替换系统导 
出的一个 SERVICE TABLE 中相应的 NATIVE API 的地址来达到拦截的目的。 
因为此方法较为简单,网上也有不少资料来介绍。所以这里就不给出实例程序了。SERVICE TABLE 的结构如下:

typedef struct ServiceDescriptorEntry { 
    unsigned int *ServiceTableBase; 
    unsigned int *ServiceCounterTableBase;  
    unsigned int NumberOfServices; 
    unsigned char *ParamTableBase; 
} ServiceDescriptorTableEntry_t, *PServiceDescriptorTableEntry_t;

2、HOOK INT 2E 方法: 
   这种方法对于跟踪、分析系统调用来说用的比较多。原理是通过替换 IDT 
表中的 INT 2E 中断,使之指向我们自己的中断服务处理例程来实现的。掌握 
此方法需要你对保护模式有一定的基础。下面的程序演示了这一过程。

/***************************************************************** 
文件名        : WssHookInt2e.c 
描述          : 系统调用跟踪 
作者          : sinister 
最后修改日期  : 2002-11-02 
*****************************************************************/

#include "ntddk.h" 
#include "string.h"

#define DWORD unsigned __int32 
#define WORD unsigned __int16 
#define BYTE unsigned __int8 
#define BOOL __int32

#define LOWORD(l)           ((WORD)(l)) 
#define HIWORD(l)           ((WORD)(((DWORD)(l) >> 16) & 0xFFFF)) 
#define LOBYTE(w)           ((BYTE)(w)) 
#define HIBYTE(w)           ((BYTE)(((WORD)(w) >> 8) & 0xFF))

#define MAKELONG(a, b) ((LONG) (((WORD) (a)) | ((DWORD) ((WORD) (b))) << 16))

#define SYSTEMCALL 0x2e 
#define SYSNAME "System" 
#define PROCESSNAMELEN 16

#pragma pack(1)

//定义 IDTR  
typedef struct tagIDTR { 
        WORD IDTLimit; 
        WORD LowIDTbase; 
        WORD HiIDTbase; 
}IDTR, *PIDTR;

//定义 IDT  
typedef struct tagIDTENTRY{ 
    WORD OffsetLow; 
    WORD selector; 
    BYTE unused_lo; 
    unsigned char unused_hi:5; 
    unsigned char DPL:2; 
    unsigned char P:1; 
    WORD OffsetHigh; 
} IDTENTRY, *PIDTENTRY;

#pragma pack()

DWORD    OldInt2eService; 
ULONG    ProcessNameOffset; 
TCHAR   ProcessName[PROCESSNAMELEN];

static NTSTATUS  MydrvDispatch (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); 
VOID DriverUnload (IN PDRIVER_OBJECT pDriverObject); 
ULONG GetProcessNameOffset(); 
VOID GetProcessName( PCHAR Name ); 
VOID InstallNewInt2e(); 
VOID UninstallNewInt2e();

VOID __fastcall NativeApiCall() 

    KIRQL OldIrql; 
     
    DWORD ServiceID; 
    DWORD ProcessId;

__asm mov ServiceID,eax;

ProcessId = (DWORD)PsGetCurrentProcessId(); 
    GetProcessName(ProcessName);

KeRaiseIrql(HIGH_LEVEL, &OldIrql); // 提升当前的 IRQL 级别防止被中断

switch ( ServiceID ) 
    { 
            case 0x20: 
                 DbgPrint("NEWINT2E: ProcessName: %s; ProcessID: %d; Native Api: NtCreateFile() \n",ProcessName,ProcessId); 
                 break;

case 0x2b: 
                 DbgPrint("NEWINT2E: ProcessName: %s; ProcessID: %d; Native Api: NtCreateSection() \n",ProcessName,ProcessId);                  
                 break;

case 0x30: 
                 DbgPrint("NEWINT2E: ProcessName: %s; ProcessID: %d; Native Api: NtCreateToken() \n",ProcessName,ProcessId);                  
                 break; 
                  
    }

KeLowerIrql(OldIrql); //恢复原始 IRQL

}

__declspec(naked) NewInt2eService() 

    __asm{ 
        pushad 
        pushfd 
        push fs 
        mov bx,0x30 
        mov fs,bx 
        push ds 
        push es

sti 
        call NativeApiCall; // 调用记录函数 
        cli

pop es 
        pop ds 
        pop fs 
        popfd 
        popad

jmp    OldInt2eService;  //跳到原始 INT 2E 继续工作 
    } 
}

VOID InstallNewInt2e() 
{

IDTR         idtr; 
    PIDTENTRY    OIdt; 
    PIDTENTRY    NIdt;

//得到 IDTR 中得段界限与基地址 
    __asm {  
        sidt idtr; 
    }

//得到IDT基地址 
    OIdt = (PIDTENTRY)MAKELONG(idtr.LowIDTbase,idtr.HiIDTbase);

//保存原来的 INT 2E 服务例程 
    OldInt2eService = MAKELONG(OIdt[SYSTEMCALL].OffsetLow,OIdt[SYSTEMCALL].OffsetHigh); 
     
    NIdt = &(OIdt[SYSTEMCALL]);

__asm { 
        cli 
        lea eax,NewInt2eService;  //得到新的 INT 2E 服务例程偏移 
        mov ebx, NIdt; 
        mov [ebx],ax;   //INT 2E 服务例程低 16 位 
        shr eax,16      //INT 2E 服务例程高 16 位 
        mov [ebx+6],ax; 
        lidt idtr  //装入新的 IDT 
        sti 
    }

}

VOID UninstallNewInt2e() 

    IDTR         idtr; 
    PIDTENTRY    OIdt; 
    PIDTENTRY    NIdt;

__asm { 
        sidt idtr; 
    }

OIdt = (PIDTENTRY)MAKELONG(idtr.LowIDTbase,idtr.HiIDTbase);

NIdt = &(OIdt[SYSTEMCALL]);

_asm { 
        cli 
        lea eax,OldInt2eService; 
        mov ebx, NIdt; 
        mov [ebx],ax; 
        shr eax,16 
        mov [ebx+6],ax; 
        lidt idtr 
        sti 
    }

}

// 驱动入口 
NTSTATUS  DriverEntry( IN PDRIVER_OBJECT DriverObject,  IN PUNICODE_STRING RegistryPath )  

     
    UNICODE_STRING  nameString, linkString; 
    PDEVICE_OBJECT  deviceObject; 
    NTSTATUS        status; 
    HANDLE          hHandle; 
    int                i;

//卸载驱动 
    DriverObject->DriverUnload = DriverUnload;

//建立设备 
    RtlInitUnicodeString( &nameString, L"\\Device\\WssHookInt2e" ); 
     
    status = IoCreateDevice( DriverObject, 
                             0, 
                             &nameString, 
                             FILE_DEVICE_UNKNOWN, 
                             0, 
                             TRUE, 
                             &deviceObject 
                           );

if (!NT_SUCCESS( status )) 
        return status;

RtlInitUnicodeString( &linkString, L"\\DosDevices\\WssHookInt2e" );

status = IoCreateSymbolicLink (&linkString, &nameString);

if (!NT_SUCCESS( status )) 
    { 
        IoDeleteDevice (DriverObject->DeviceObject); 
        return status; 
    }

for ( i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)    {

DriverObject->MajorFunction[i] = MydrvDispatch; 
    }

DriverObject->DriverUnload = DriverUnload;

ProcessNameOffset = GetProcessNameOffset(); 
    InstallNewInt2e();

return STATUS_SUCCESS;  
}

//处理设备对象操作

static NTSTATUS MydrvDispatch (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) 
{  
    Irp->IoStatus.Status = STATUS_SUCCESS; 
    Irp->IoStatus.Information = 0L; 
    IoCompleteRequest( Irp, 0 ); 
    return Irp->IoStatus.Status; 
     
}

VOID DriverUnload (IN PDRIVER_OBJECT    pDriverObject) 

    UNICODE_STRING  nameString;

UninstallNewInt2e(); 
    RtlInitUnicodeString( &nameString, L"\\DosDevices\\WssHookInt2e" );     
    IoDeleteSymbolicLink(&nameString); 
    IoDeleteDevice(pDriverObject->DeviceObject);

return; 
}

ULONG GetProcessNameOffset() 

        PEPROCESS curproc; 
        int i; 
         
        curproc = PsGetCurrentProcess();

// 
        // Scan for 12KB, hopping the KPEB never grows that big! 
        // 
        for( i = 0; i < 3*PAGE_SIZE; i++ ) {

if( !strncmp( SYSNAME, (PCHAR) curproc + i, strlen(SYSNAME) )) {

return i; 
            } 
        }

// 
        // Name not found - oh, well 
        // 
        return 0; 
}

VOID GetProcessName( PCHAR Name ) 
{

PEPROCESS curproc; 
        char *nameptr; 
        ULONG i;

if( ProcessNameOffset ) {

curproc = PsGetCurrentProcess(); 
            nameptr = (PCHAR) curproc + ProcessNameOffset; 
            strncpy( Name, nameptr, 16 );

} else {

strcpy( Name, "???"); 
        } 
}

3、 HOOK PE 方法 
    这种方法对于拦截、分析其他内核驱动的函数调用来说用的比较多。原理 
是根据替换 PE 格式导出表中的相应函数来实现的。此方法中需要用到一些小 
技巧。如内核模式并没有直接提供类似应用层的 GetModuleHandl()、GetProcAddress() 等函数来获得模块的地址。那么我们就需要自己来编写,这 
里用到了一个未公开的函数与结构。ZwQuerySystemInformation 与 SYSTEM_MODULE_INFORMATION 来实现得到模块的基地址。这样我们就可以根据 
PE 格式来枚举导出表中的函数来替换了。但这又引出了一个问题,那就是从 
WINDOWS 2000 后内核数据的页属性都是只读的,不能更改。内核模式也没有 
提供类似应用层的 VirtualProtectEx() 等函数来修改页面属性。那么也需要 
我们自己来编写。因为我们是在内核模式所以我们可以通过修改 cr0 寄存器的 
的写保护位来达到我们的目的。这样我们所期望的拦截内核模式函数的功能便 
得以实现。此方法需要你对 PE 格式有一定的基础。下面的程序演示了这一过程。

/***************************************************************** 
文件名        : WssHookPE.c 
描述          : 拦截内核函数 
作者          : sinister 
最后修改日期  : 2002-11-02 
*****************************************************************/

#include "ntddk.h" 
#include "windef.h"

typedef enum _SYSTEM_INFORMATION_CLASS { 
    SystemBasicInformation, 
    SystemProcessorInformation, 
    SystemPerformanceInformation, 
    SystemTimeOfDayInformation, 
    SystemNotImplemented1, 
    SystemProcessesAndThreadsInformation, 
    SystemCallCounts, 
    SystemConfigurationInformation, 
    SystemProcessorTimes, 
    SystemGlobalFlag, 
    SystemNotImplemented2, 
    SystemModuleInformation, 
    SystemLockInformation, 
    SystemNotImplemented3, 
    SystemNotImplemented4, 
    SystemNotImplemented5, 
    SystemHandleInformation, 
    SystemObjectInformation, 
    SystemPagefileInformation, 
    SystemInstructionEmulationCounts, 
    SystemInvalidInfoClass1, 
    SystemCacheInformation, 
    SystemPoolTagInformation, 
    SystemProcessorStatistics, 
    SystemDpcInformation, 
    SystemNotImplemented6, 
    SystemLoadImage, 
    SystemUnloadImage, 
    SystemTimeAdjustment, 
    SystemNotImplemented7, 
    SystemNotImplemented8, 
    SystemNotImplemented9, 
    SystemCrashDumpInformation, 
    SystemExceptionInformation, 
    SystemCrashDumpStateInformation, 
    SystemKernelDebuggerInformation, 
    SystemContextSwitchInformation, 
    SystemRegistryQuotaInformation, 
    SystemLoadAndCallImage, 
    SystemPrioritySeparation, 
    SystemNotImplemented10, 
    SystemNotImplemented11, 
    SystemInvalidInfoClass2, 
    SystemInvalidInfoClass3, 
    SystemTimeZoneInformation, 
    SystemLookasideInformation, 
    SystemSetTimeSlipEvent, 
    SystemCreateSession, 
    SystemDeleteSession, 
    SystemInvalidInfoClass4, 
    SystemRangeStartInformation, 
    SystemVerifierInformation, 
    SystemAddVerifier, 
    SystemSessionProcessesInformation 
} SYSTEM_INFORMATION_CLASS;

typedef struct tagSYSTEM_MODULE_INFORMATION { 
    ULONG Reserved[2]; 
    PVOID Base; 
    ULONG Size; 
    ULONG Flags; 
    USHORT Index; 
    USHORT Unknown; 
    USHORT LoadCount; 
    USHORT ModuleNameOffset; 
    CHAR ImageName[256]; 
} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;

#define IMAGE_DOS_SIGNATURE        0x5A4D      // MZ 
#define IMAGE_NT_SIGNATURE      0x50450000  // PE00 
#define IMAGE_NT_SIGNATURE1        0x00004550    // 00EP

typedef struct _IMAGE_DOS_HEADER {      // DOS .EXE header 
    WORD   e_magic;                     // Magic number 
    WORD   e_cblp;                      // Bytes on last page of file 
    WORD   e_cp;                        // Pages in file 
    WORD   e_crlc;                      // Relocations 
    WORD   e_cparhdr;                   // Size of header in paragraphs 
    WORD   e_minalloc;                  // Minimum extra paragraphs needed 
    WORD   e_maxalloc;                  // Maximum extra paragraphs needed 
    WORD   e_ss;                        // Initial (relative) SS value 
    WORD   e_sp;                        // Initial SP value 
    WORD   e_csum;                      // Checksum 
    WORD   e_ip;                        // Initial IP value 
    WORD   e_cs;                        // Initial (relative) CS value 
    WORD   e_lfarlc;                    // File address of relocation table 
    WORD   e_ovno;                      // Overlay number 
    WORD   e_res[4];                    // Reserved words 
    WORD   e_oemid;                     // OEM identifier (for e_oeminfo) 
    WORD   e_oeminfo;                   // OEM information; e_oemid specific 
    WORD   e_res2[10];                  // Reserved words 
    LONG   e_lfanew;                    // File address of new exe header 
  } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

typedef struct _IMAGE_FILE_HEADER { 
    WORD    Machine; 
    WORD    NumberOfSections; 
    DWORD   TimeDateStamp; 
    DWORD   PointerToSymbolTable; 
    DWORD   NumberOfSymbols; 
    WORD    SizeOfOptionalHeader; 
    WORD    Characteristics; 
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;

typedef struct _IMAGE_DATA_DIRECTORY { 
    DWORD   VirtualAddress; 
    DWORD   Size; 
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;

#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES    16

// 
// Optional header format. 
//

typedef struct _IMAGE_OPTIONAL_HEADER { 
    // 
    // Standard fields. 
    //

WORD    Magic; 
    BYTE    MajorLinkerVersion; 
    BYTE    MinorLinkerVersion; 
    DWORD   SizeOfCode; 
    DWORD   SizeOfInitializedData; 
    DWORD   SizeOfUninitializedData; 
    DWORD   AddressOfEntryPoint; 
    DWORD   BaseOfCode; 
    DWORD   BaseOfData;

// 
    // NT additional fields. 
    //

DWORD   ImageBase; 
    DWORD   SectionAlignment; 
    DWORD   FileAlignment; 
    WORD    MajorOperatingSystemVersion; 
    WORD    MinorOperatingSystemVersion; 
    WORD    MajorImageVersion; 
    WORD    MinorImageVersion; 
    WORD    MajorSubsystemVersion; 
    WORD    MinorSubsystemVersion; 
    DWORD   Win32VersionValue; 
    DWORD   SizeOfImage; 
    DWORD   SizeOfHeaders; 
    DWORD   CheckSum; 
    WORD    Subsystem; 
    WORD    DllCharacteristics; 
    DWORD   SizeOfStackReserve; 
    DWORD   SizeOfStackCommit; 
    DWORD   SizeOfHeapReserve; 
    DWORD   SizeOfHeapCommit; 
    DWORD   LoaderFlags; 
    DWORD   NumberOfRvaAndSizes; 
    IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; 
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;

typedef struct _IMAGE_NT_HEADERS { 
    DWORD Signature; 
    IMAGE_FILE_HEADER FileHeader; 
    IMAGE_OPTIONAL_HEADER32 OptionalHeader; 
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

typedef IMAGE_NT_HEADERS32                  IMAGE_NT_HEADERS; 
typedef PIMAGE_NT_HEADERS32                 PIMAGE_NT_HEADERS;

// 
// Section header format. 
//

#define IMAGE_SIZEOF_SHORT_NAME              8

typedef struct _IMAGE_SECTION_HEADER { 
    BYTE    Name[IMAGE_SIZEOF_SHORT_NAME]; 
    union { 
            DWORD   PhysicalAddress; 
            DWORD   VirtualSize; 
    } Misc; 
    DWORD   VirtualAddress; 
    DWORD   SizeOfRawData; 
    DWORD   PointerToRawData; 
    DWORD   PointerToRelocations; 
    DWORD   PointerToLinenumbers; 
    WORD    NumberOfRelocations; 
    WORD    NumberOfLinenumbers; 
    DWORD   Characteristics; 
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;

#define IMAGE_SIZEOF_SECTION_HEADER          40 
// 
// Export Format 
//

typedef struct _IMAGE_EXPORT_DIRECTORY { 
    DWORD   Characteristics; 
    DWORD   TimeDateStamp; 
    WORD    MajorVersion; 
    WORD    MinorVersion; 
    DWORD   Name; 
    DWORD   Base; 
    DWORD   NumberOfFunctions; 
    DWORD   NumberOfNames; 
    DWORD   AddressOfFunctions;     // RVA from base of image 
    DWORD   AddressOfNames;         // RVA from base of image 
    DWORD   AddressOfNameOrdinals;  // RVA from base of image 
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;

#define BASEADDRLEN 10

NTSYSAPI 
NTSTATUS 
NTAPI 
ZwQuerySystemInformation( 
    IN SYSTEM_INFORMATION_CLASS SystemInformationClass, 
    IN OUT PVOID SystemInformation, 
    IN ULONG SystemInformationLength, 
    OUT PULONG ReturnLength OPTIONAL 
    );

typedef NTSTATUS (* ZWCREATEFILE)( 
  OUT PHANDLE FileHandle, 
  IN ACCESS_MASK DesiredAccess, 
  IN POBJECT_ATTRIBUTES ObjectAttributes, 
  OUT PIO_STATUS_BLOCK IoStatusBlock, 
  IN PLARGE_INTEGER AllocationSize  OPTIONAL, 
  IN ULONG FileAttributes, 
  IN ULONG ShareAccess, 
  IN ULONG CreateDisposition, 
  IN ULONG CreateOptions, 
  IN PVOID EaBuffer  OPTIONAL, 
  IN ULONG EaLength 
  );

ZWCREATEFILE    OldZwCreateFile;

static NTSTATUS  MydrvDispatch (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); 
VOID DriverUnload (IN PDRIVER_OBJECT pDriverObject); 
VOID DisableWriteProtect( PULONG pOldAttr); 
VOID EnableWriteProtect( ULONG ulOldAttr ); 
FARPROC HookFunction(    PCHAR pModuleBase, PCHAR pHookName, FARPROC pHookFunc );

NTSTATUS   
HookNtCreateFile( 
  OUT PHANDLE FileHandle, 
  IN ACCESS_MASK DesiredAccess, 
  IN POBJECT_ATTRIBUTES ObjectAttributes, 
  OUT PIO_STATUS_BLOCK IoStatusBlock, 
  IN PLARGE_INTEGER AllocationSize  OPTIONAL, 
  IN ULONG FileAttributes, 
  IN ULONG ShareAccess, 
  IN ULONG CreateDisposition, 
  IN ULONG CreateOptions, 
  IN PVOID EaBuffer  OPTIONAL, 
  IN ULONG EaLength 
  );

PCHAR MyGetModuleBaseAddress( PCHAR pModuleName )  

    PSYSTEM_MODULE_INFORMATION    pSysModule;

ULONG            uReturn; 
    ULONG            uCount; 
    PCHAR            pBuffer = NULL; 
    PCHAR            pName    = NULL; 
    NTSTATUS        status; 
    UINT            ui;

CHAR            szBuffer[BASEADDRLEN]; 
    PCHAR            pBaseAddress; 
     
    status = ZwQuerySystemInformation( SystemModuleInformation, szBuffer, BASEADDRLEN, &uReturn );

pBuffer = ( PCHAR )ExAllocatePool( NonPagedPool, uReturn );

if ( pBuffer ) 
    { 
        status = ZwQuerySystemInformation( SystemModuleInformation, pBuffer, uReturn, &uReturn );

if( status == STATUS_SUCCESS ) 
        { 
            uCount = ( ULONG )*( ( ULONG * )pBuffer ); 
            pSysModule = ( PSYSTEM_MODULE_INFORMATION )( pBuffer + sizeof( ULONG ) );

for ( ui = 0; ui < uCount; ui++ ) 
            { 
                pName = MyStrchr( pSysModule->ImageName, ‘\\’ );

if ( !pName )  
                { 
                    pName = pSysModule->ImageName; 
                }

else { 
                    pName++; 
                }

if( !_stricmp( pName, pModuleName ) ) 
                { 
                    pBaseAddress = ( PCHAR )pSysModule->Base; 
                    ExFreePool( pBuffer ); 
                    return pBaseAddress; 
                }

pSysModule ++; 
            } 
        }

ExFreePool( pBuffer ); 
    }

return NULL; 
}

FARPROC HookFunction( PCHAR pModuleBase, PCHAR HookFunName, FARPROC HookFun ) 

    PIMAGE_DOS_HEADER         pDosHdr; 
    PIMAGE_NT_HEADERS         pNtHdr; 
    PIMAGE_SECTION_HEADER     pSecHdr; 
    PIMAGE_EXPORT_DIRECTORY  pExtDir;

UINT                    ui,uj; 
    PCHAR                    FunName; 
    DWORD                    *dwAddrName; 
    DWORD                    *dwAddrFun; 
    FARPROC                    pOldFun; 
    ULONG                    uAttrib;

pDosHdr = ( PIMAGE_DOS_HEADER )pModuleBase;

if ( IMAGE_DOS_SIGNATURE == pDosHdr->e_magic ) 
    { 
        pNtHdr = ( PIMAGE_NT_HEADERS )( pModuleBase + pDosHdr->e_lfanew );

if( IMAGE_NT_SIGNATURE  == pNtHdr->Signature ||    IMAGE_NT_SIGNATURE1 == pNtHdr->Signature ) 
        { 
            pSecHdr = ( PIMAGE_SECTION_HEADER )( pModuleBase + pDosHdr->e_lfanew + sizeof( IMAGE_NT_HEADERS ) );

for ( ui = 0; ui < (UINT)pNtHdr->FileHeader.NumberOfSections; ui++ ) 
            { 
                if ( !strcmp( pSecHdr->Name, ".edata" ) ) 
                {                 
                    pExtDir = ( PIMAGE_EXPORT_DIRECTORY )( pModuleBase + pSecHdr->VirtualAddress ); 
                    dwAddrName = ( PDWORD )(pModuleBase + pExtDir->AddressOfNames ); 
                    dwAddrFun = ( PDWORD )(pModuleBase + pExtDir->AddressOfFunctions );

for ( uj = 0; uj < (UINT)pExtDir->NumberOfFunctions; uj++ ) 
                    { 
                        FunName = pModuleBase + *dwAddrName;

if( !strcmp( FunName, HookFunName ) ) 
                        { 
                            DbgPrint(" HOOK  %s()\n",FunName); 
                            DisableWriteProtect( &uAttrib ); 
                            pOldFun = ( FARPROC )( pModuleBase + *dwAddrFun ); 
                            *dwAddrFun = ( PCHAR )HookFun - pModuleBase; 
                            EnableWriteProtect( uAttrib ); 
                            return pOldFun; 
                        }

dwAddrName ++; 
                      dwAddrFun ++; 
                    } 
                }

pSecHdr++; 
            } 
        } 
    }

return NULL; 
}

// 驱动入口 
NTSTATUS  DriverEntry( IN PDRIVER_OBJECT DriverObject,  IN PUNICODE_STRING RegistryPath )  

     
    UNICODE_STRING  nameString, linkString; 
    PDEVICE_OBJECT  deviceObject; 
    NTSTATUS        status; 
    HANDLE          hHandle; 
    PCHAR            pModuleAddress; 
    int                i;

//卸载驱动 
    DriverObject->DriverUnload = DriverUnload;

//建立设备 
    RtlInitUnicodeString( &nameString, L"\\Device\\WssHookPE" ); 
     
    status = IoCreateDevice( DriverObject, 
                             0, 
                             &nameString, 
                             FILE_DEVICE_UNKNOWN, 
                             0, 
                             TRUE, 
                             &deviceObject 
                           );

if (!NT_SUCCESS( status )) 
        return status;

RtlInitUnicodeString( &linkString, L"\\DosDevices\\WssHookPE" );

status = IoCreateSymbolicLink (&linkString, &nameString);

if (!NT_SUCCESS( status )) 
    { 
        IoDeleteDevice (DriverObject->DeviceObject); 
        return status; 
    }     
     
    pModuleAddress = MyGetModuleBaseAddress("ntoskrnl.exe"); 
    if ( pModuleAddress == NULL) 
    { 
        DbgPrint(" MyGetModuleBaseAddress()\n"); 
        return 0; 
    }

OldZwCreateFile = (ZWCREATEFILE)HookFunction( pModuleAddress, "ZwCreateFile",(ZWCREATEFILE)HookNtCreateFile); 
    if ( OldZwCreateFile == NULL) 
    { 
        DbgPrint(" HOOK FAILED\n"); 
        return 0; 
    }

DbgPrint("HOOK SUCCEED\n");

for ( i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)    {

DriverObject->MajorFunction[i] = MydrvDispatch; 
    }

DriverObject->DriverUnload = DriverUnload; 
      
  return STATUS_SUCCESS;  
}

//处理设备对象操作

static NTSTATUS MydrvDispatch (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) 
{  
    Irp->IoStatus.Status = STATUS_SUCCESS; 
    Irp->IoStatus.Information = 0L; 
    IoCompleteRequest( Irp, 0 ); 
    return Irp->IoStatus.Status; 
     
}

VOID DriverUnload (IN PDRIVER_OBJECT    pDriverObject) 

    UNICODE_STRING  nameString; 
    PCHAR            pModuleAddress;

pModuleAddress = MyGetModuleBaseAddress("ntoskrnl.exe"); 
    if ( pModuleAddress == NULL) 
    { 
        DbgPrint("MyGetModuleBaseAddress()\n"); 
        return ; 
    }

OldZwCreateFile = (ZWCREATEFILE)HookFunction( pModuleAddress, "ZwCreateFile",(ZWCREATEFILE)OldZwCreateFile); 
    if ( OldZwCreateFile == NULL) 
    { 
        DbgPrint(" UNHOOK FAILED!\n"); 
        return ; 
    }

DbgPrint("UNHOOK SUCCEED\n");

RtlInitUnicodeString( &nameString, L"\\DosDevices\\WssHookPE" );     
    IoDeleteSymbolicLink(&nameString); 
    IoDeleteDevice(pDriverObject->DeviceObject);

return; 
}

NTSTATUS   
HookNtCreateFile( 
  OUT PHANDLE FileHandle, 
  IN ACCESS_MASK DesiredAccess, 
  IN POBJECT_ATTRIBUTES ObjectAttributes, 
  OUT PIO_STATUS_BLOCK IoStatusBlock, 
  IN PLARGE_INTEGER AllocationSize  OPTIONAL, 
  IN ULONG FileAttributes, 
  IN ULONG ShareAccess, 
  IN ULONG CreateDisposition, 
  IN ULONG CreateOptions, 
  IN PVOID EaBuffer  OPTIONAL, 
  IN ULONG EaLength 
  ) 

    NTSTATUS    status;

DbgPrint("Hook ZwCreateFile()\n");

status = ((ZWCREATEFILE)(OldZwCreateFile))( 
               FileHandle, 
               DesiredAccess, 
               ObjectAttributes, 
               IoStatusBlock, 
               AllocationSize, 
               FileAttributes, 
               ShareAccess, 
               CreateDisposition, 
               CreateOptions, 
               EaBuffer, 
               EaLength 
              );

return status; 
}

VOID DisableWriteProtect( PULONG pOldAttr) 
{

ULONG uAttr;

_asm 
    { 
          push eax; 
          mov  eax, cr0; 
          mov  uAttr, eax; 
          and  eax, 0FFFEFFFFh; // CR0 16 BIT = 0 
          mov  cr0, eax; 
          pop  eax; 
    };

*pOldAttr = uAttr; //保存原有的 CRO 属性

}

VOID EnableWriteProtect( ULONG uOldAttr ) 
{

_asm 
  { 
       push eax; 
       mov  eax, uOldAttr; //恢复原有 CR0 属性 
       mov  cr0, eax; 
       pop  eax; 
  };

}

http://www.cnblogs.com/lzjsky/archive/2010/11/19/1881568.html

内核级HOOK的几种实现与应用的更多相关文章

  1. SSDT Hook实现内核级的进程保护

    目录 SSDT Hook效果图 SSDT简介 SSDT结构 SSDT HOOK原理 Hook前准备 如何获得SSDT中函数的地址呢 SSDT Hook流程 SSDT Hook实现进程保护 Ring3与 ...

  2. Windows平台内核级文件访问

    1.背景     在windows平台下,应用程序通常使用API函数来进行文件访问,创建,打开,读写文件.从kernel32的CreateFile/ReadFile/WriteFile函数,到本地系统 ...

  3. Windows2003 内核级进程隐藏、侦测技术

    论文关键字: 内核 拦截 活动进程链表 系统服务派遣表 线程调度链 驱动程序简介    论文摘要:信息对抗是目前计算机发展的一个重要的方向,为了更好的防御,必须去深入的了解敌人进攻的招式.信息对抗促使 ...

  4. 【原创】内核ShellCode注入的一种方法

    标 题: [原创]内核ShellCode注入的一种方法 作 者: organic 时 间: 2013-05-04,04:34:08 链 接: http://bbs.pediy.com/showthre ...

  5. 多线程 用户级线程和内核级线程 from C++多核高级编程

    转 http://book.51cto.com/art/201006/206946.htm 6.1.1 用户级线程和内核级线程 2010-06-21 20:37 齐宁/董泽惠 译 清华大学出版社 字号 ...

  6. Linux用户级线程和内核级线程区别

    1.内核级线程: (1)线程的创建.撤销和切换等,都需要内核直接实现,即内核了解每一个作为可调度实体的线程.(2)这些线程可以在全系统内进行资源的竞争.(3)内核空间内为每一个内核支持线程设置了一个线 ...

  7. 内核级线程(KLT)和用户级线程(ULT)

    内核级线程(KLT)和用户级线程(ULT) tags: KLT ULT 内核级线程 用户级线程 引言:本文涉及到操作系统的内核模式和用户模式,如果不太懂的话,可以参看我的这篇文章内核模式和用户模式,其 ...

  8. {Python之线程} 一 背景知识 二 线程与进程的关系 三 线程的特点 四 线程的实际应用场景 五 内存中的线程 六 用户级线程和内核级线程(了解) 七 python与线程 八 Threading模块 九 锁 十 信号量 十一 事件Event 十二 条件Condition(了解) 十三 定时器

    Python之线程 线程 本节目录 一 背景知识 二 线程与进程的关系 三 线程的特点 四 线程的实际应用场景 五 内存中的线程 六 用户级线程和内核级线程(了解) 七 python与线程 八 Thr ...

  9. 从0开始:Windows内核利用的另一种方式

    https://www.anquanke.com/post/id/91063 从0开始:Windows内核利用的另一种方式 阅读量    9168 |   稿费 200   分享到: 发布时间:201 ...

随机推荐

  1. C++中数字与字符串之间的转换,别人的,

    C++中数字与字符串之间的转换   1.字符串数字之间的转换 (1)string --> char *   string str("OK");   char * p = st ...

  2. file_get_contents()的另一种使用方法

    今天在网上看到一篇挺不错的文章,拿过来保存学习一下.本文源地址为:http://www.kuitao8.com/20140727/2867.shtml $data = file_get_content ...

  3. java中数组与List相互转换的方法

    1.List转换成为数组.(这里的List是实体是ArrayList) 调用ArrayList的toArray方法. toArray public <T> T[] toArray(T[] ...

  4. jquery easyUI DataGrid 初始化的时候就显示可排序的字段

    在使用easy ui的列表中,想要标记可以排序的字段,使用户一看页面就知道哪些是可以点击排序的. 给可排序的字段添加 图标在列名后面.不可排序的字段还和原来一样. 步骤: 你需要一个图标 , 你需要给 ...

  5. JDK常见问题 环境变量配置

    "javac不是内部命令或外部命令" Windows7 安装"jdk-6u26-windows-x64.exe"后,常提示"javac不是内部命令或外 ...

  6. DelphiXE7如何调用Java Class,JAR等文件?

    源文地址:http://jingyan.baidu.com/article/e4d08ffdb61b040fd3f60d44.html 第一步,我们先在互联网上把java2pas这个工具下载下来. 下 ...

  7. STL跨DLL使用

    今天在写一个函数,需要将map作为一个引用参数传入函数体内部进行赋值,结果编译通过,执行时总是崩溃,在网上找到了一些作者写的blog,详细解释了这种情况发生的原因,特转载在这里,便于自己今后查询. 原 ...

  8. 调magento自定义模板发邮件

    1. 设置邮件模板 <global> <template> <email> <custom_email_template1 module="Samp ...

  9. js中调用mangeto的js翻译

    第一步: <script type="text/javascript"> Translator.add('英文','<?php echo this->__( ...

  10. Haffman编码(haffman树)

    Haffman编码 时间限制:1000 ms  |  内存限制:65535 KB 难度:3   描述 哈弗曼编码大家一定很熟悉吧(不熟悉也没关系,自己查去...).现在给你一串字符以及它们所对应的权值 ...