Creation time: 2003-03-26
Article attribute: original
Article Source:
http://www.whitecell.org
Article submission:
Sinister (jias_at_21cn.com)
Several implementation and application of kernel level hook
Author: sinister
Email: SINISTER@whitecell.org
Homepage:
http://www.whitecell.org
Implementing the kernel level hook For interception, analysis, tracking system cores, the system is derived. The method of implementing is different means that the application side focus is different. If you want to intercept Native API, it is possible to use the Hook Service Table method. If you want to analyze some system calls, you might think of using the Hook Int 2E interrupt. If you want to intercept or track the call of other kernel Driver, you should use the Hook PE method to implement. Here we pay more attention to achieving, many masters have been published in the Internet. Everyone can combine it. The following is aware of several instance programs I have explained the implementation of various methods. In the wrong point, I also hope that you are correct.
1, Hook Service Table method:
This method is more useful for intercepting the Native API. The principle is through the replacement system guide
The address of the corresponding Native API in a Service Table is to achieve the purpose of interception.
Because this method is simple, there are many information on the Internet. So this will not give an example program. The structure of Service Table is as follows:
Typedef struct service {
Unsigned Int * ServiceTableBase;
Unsigned int * ServiceCountertableBase;
Unsigned int numberofservices;
Unsigned char * paramtablebase;
} ServicesDescriptAblentry_t, * pserviceDescriptableentRY_T;
2, Hook Int 2e method:
This approach is more useful for tracking, analyzing system calls. The principle is to replace IDT
The int 2e interrupt in the table is implemented to our own interrupt service processing routine. grasp
This method requires that you have a certain basis for the protection mode. The following program demonstrates this process.
/ ************************************************** *****************
File name: wsshookint2e.c
Description: System call tracking
Author: sinister
Last modified: 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))
#define HiWord ((Word) ((DWORD) >> 16) & 0xfff))
#define lobyte (w) ((byte) (w))
#define hibyte (w) ((Byte) ((Word) >> 8) & 0xFF))
#define Makelong (A, B) ((Word) ((Word)) | ((Word))) << 16)) # Define SystemCall 0x2e
#define sysname "system"
#define processnamelen 16
#pragma pack (1)
// Define IDTR
Typedef struct tagidtr {
Word IDtlimit;
Word lowidtbase;
Word HiIDTBase;
} IDTR, * PIDTR;
// Define 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 Oldint2EnTerevice;
Ulong processnameoffset;
Tchar processname [ProcessNamelen];
Static NTSTATUS MYDRVDISPATCH (in PDEvice_Object DeviceObject, in PIRP);
Void Driverunload (in PDRIVER_Object PDRIVEROBJECT);
Ulong getProcessNameOffset ();
Void getProcessName (Pchar Name);
Void InstallNewint2e ();
Void uninstallnewint2e ();
Void __fastcall nativeApical ()
{
KIRQL Oldirql;
DWORD serviceID;
DWORD processID;
__ASM MOV ServiceID, EAX;
PROCESSID = (DWORD) psgetcurrentprocessid ();
GetProcessName (ProcessName);
KeraiseiRQL (high_level, & oldirql); / / to enhance the current IRQL level to prevent interruption
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;
}
KLOWERIRQL (Oldirql); // Restore the original IRQL
}
__Declspec (naked) newint2ervice ()
{
__ASM {
Pushhad
Pushfd
Push fs
MOV BX, 0x30
MOV FS, BX
Push DS
Push ES
STI
Call nativeApical; // call record functions
CLI
POP ES
POP DS
POP FS
POPFD
Popad
JMP oldint2eervice; // Jump to the original INT 2E to continue working
}
}
Void InstallNewint2e ()
{
IDTR IDTR;
PidtenTry Oidt;
PidtenTry Nidt;
// Get the length of the segment and base address in IDTR
__ASM {
SIDT IDTR;
}
// Get the IDT base address
OIDT = (PIDTENTRY) makelong (idtr.lowidtbase); idtr.hiidtbase;
/ / Save the original INT 2E service routine
Oldint2erat = makelong (OIDT [SystemCall] .Offsetlow, Oidt [SystemCall] .offSethiGH);
NIDT = & (OIDT [SystemCall]);
__ASM {
CLI
LEA EAX, NewInt2EnTerevice; // Get a new INT 2E service routine offset
MOV EBX, NIDT;
MOV [EBX], AX; // int 2e service routine low 16 bits
SHR EAX, 16 // INT 2E service routine 16
MOV [EBX 6], AX;
LIDT IDTR / / Load new 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, Oldint2eervice;
MOV EBX, NIDT;
MOV [EBX], AX;
SHR EAX, 16
MOV [EBX 6], AX;
LIDT IDTR
STI
}
}
// Drive inlet
NTSTATUS DRIVERENTRY (in PDRIVER_OBJECT DriverObject, In Punicode_String RegistryPath)
{
Unicode_String NameString, Linkstring;
PDEvice_Object DeviceObject;
NTSTATUS STATUS;
Handle Hhandle;
INT I;
// Uninstall drive
DriverObject-> driverunload = driverunload;
// Establish a device
RTLinitunicodeString (& NameString, L "// device // wsshookint2e");
Status = IOCREATEVICE (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 DriverObject-> majorfunction [i] = mydrvdispatch; } DriverObject-> driverunload = driverunload; ProcessNameOffset = getProcessNameOffset (); InstallNewint2e (); Return status_success; } // Processing device object operation 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 big company trat! // 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 method This method is more useful for intercepting, analyzing other kernel-driven function calls. principle It is achieved according to the replacement of the corresponding function in the table exported in the PE format. Some small skill. If the kernel mode does not directly provide a function of getModuleHandl (), getProcAddress (), and getProcAddress () and other functions to get the address of the module. Then we need yourself to write, this An unprecedented function and structure are used. ZwQuerySystemInformation and System_Module_information are enabled to get the base address of the module. This way we can enumerate the function in the table according to the PE format. But this has taken a problem, that is The page properties of kernel data after Windows 2000 are read-only and cannot be changed. Nothing Provide a function of VirtualProtectex () such as an application layer to modify page properties. So Let's write it yourself. Because we are in kernel mode, we can modify the CR0 register The write protection bit is to achieve our goal. This way we expect to intercept the kernel mode function Implement. This method requires you to have a certain basis for the PE format. The following program demonstrates this process. / ************************************************** ***************** File name: wsshookpe.c Description: Intercepting kernel functions Author: sinister Last modified: 2002-11-02 *********************************************************** *************** / #include "ntddk.h" #include "windef.h" Typedef enum _system_information_class { SystembasicInformation, SystemProcessorInformation, SystemPerformanceInformation, SystemTimeOfDayInformation, SystemNotimplement1, SystemProcesSandthreadsinformation, SystemCallCounts, SystemConfigurationInformation, SystemProcessortimes, Systemglobalflag, Systemnotimplement2, SystemmoduleInformation, SystemlockInformation, Systemnotimplement3, Systemnotimplement 4, Systemnotimplement5, SystemHandleInformation, SystemObjectInformation, SystemPageFileinformation, SysteminstructionemulationCounts, SYSTEMITIONCOUNTS, SystemInvalidInfoclass1, Systemcacheinformation, SystemPoolTagInformation, SystemProcessorstatistics, SystemDPCINFORMATION, Systemnotimplement6, SystemLoadImage, SYSTEMLOADIMAGE, SYSTEMUNLOADIMAGE, SystemTimeAdjustment, Systemnotimplement7, Systemnotimplement8, Systemnotimplement9, SystemcrashDumpinformation, SystemExceptionInformation, SystemcrashdumpStateInformation, SystemkernelDebuggerinformation, SystemContextSwitchInformation, SystemRegistryQuotainFormation, SystemLoadAllImage, SystemPrioritySeparation, Systemnotimplement10, SystemNotimplement 11, SysteminvalidInfoclass2, SysteminvalidInfoclass3, SystemTIMEZONEInformation, SystemlooksideIndeinformation, SystemSetTimeSlipEvent, SystemCreateSession, SystemDeletession, SysteminvalidInfoclass4, SystemRangeStartInformation, SystemVerifierInformation, SystemAddVerifier, SystemSessionProcesSinformation } 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 POINTOSYMBOLTABLE; 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 SIZEOFINIALIZEDDATA; DWORD SIZEOFUNITIALIZEDDATA; DWord AddressofentryPoint; DWORD BASEOFCODE; DWORD BaseOfdata; // // NT Additional Fields. // DWORD ImageBase; DWord SectionAlignment; DWORD FileAlignment; Word MajoroPERATISYSTEMVERSION; 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_HEPERS32 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 POINTERTORELOCATION; 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 AddressOfnameRDINALS; // 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 phaldle filehandle, IN Access_mask desidaccess, In Pobject_Attributes Objectttributes, 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); Void Driverunload (in PDRIVER_Object PDRIVEROBJECT); Void disablewriteprotect (pulong paindattr); Void enableWriteProtect (Ulong Uloldattr); FarProc Hookfunction (Pchar Pmodulebase, Pchar PhookName, FarProc Phookfunc); NTSTATUS Hookntcreatefile Out phaldle filehandle, IN Access_mask desidaccess, In Pobject_Attributes Objectttributes, 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 = (pster sizeof (ulong)); For (ui = 0; 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 (Uttrib); Return PoldFun; } DWADDRNAME ; DWADDRFUN ; } } PsechDR ; } } } Return NULL; } // Drive inlet 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; // Uninstall drive DriverObject-> driverunload = driverunload; // Establish a device RTLinitunicodeString (& NameString, L "// device // wsshookpe"); Status = IOCREATEVICE (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 Suckceed / N"); For (i = 0; i DriverObject-> majorfunction [i] = mydrvdispatch; } DriverObject-> driverunload = driverunload; Return status_success; } // Processing device object operation 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 phaldle filehandle, IN Access_mask desidaccess, In Pobject_Attributes Objectttributes, 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) (FileHandle, DespedAccess, ObjectAttributes, Iostatusblock, Allocationsize, FileAttributes, ShareAccess, CreatedIndisposition, CREATEOPTIONS, Eabuffer, Ealength ); Return status; } Void DisableWriteProtect (Pulong Poldattr) { Ulong Uattr; _asm { Push Eax; MOV EAX, CR0; Mov Uattr, EAX; And Eax, 0FFFEFFFH; // CR0 16 bit = 0 MOV CR0, EAX; POP EAX; } * Poldattr = uattr; // Save the original CRO attribute } Void EnableWriteProtect (ulong uoldattr) { _asm { Push Eax; MOV EAX, uoldattr; // Restore the original CR0 attribute MOV CR0, EAX; POP EAX; } } about Us: WSS (WhiteCell Security Systems), a non-profit private technology organization, dedicated to various system safety techniques. Adhere to the traditional Hacker spirit, pursue the pureness of technology. WSS Home: http://www.whitecell.org/