This article introduces some general hook ideas:
At the system kernel level, many information about MS is not disclosed, including the number of function parameters and the type of each parameter. In the system kernel, a large number of registers are accessed, while many register values are provided by upper-layer callers. If the value changes, the system becomes unstable. Unexpected consequences may occur. In addition, sometimes you do not know the parameters of the function to be hooked, so you cannot change its stack at will. If you are not careful, it may lead to a blue screen. Therefore, the best principle of Hook is that when calling the original function in the hook function, all register values, the values in the stack are the same as the information before the hook. In this way, the error will not occur in the original function. Generally, our own hook functions are written in the C file. For example, the target function kireadythread of the hook.
Generally, you can implement one by yourself:
Mykireadythread (...)
{
......
Call kireadythread
......
}
However, a stack frame will appear in the Code Compiled using the C compiler:
Push EBP
MoV EBP, ESP
This is contrary to our original intention of not changing the number of registers. Therefore, we can use assembly to implement mykireadythread.
_ FUNC @ 0 proc
Pushad; Save General registers
Call _ cfunc @ 0; here is some processing before entering the original function.
Popad; General Register recovery
Push eax
MoV eax, [esp + 4]; get the return address of the system when calling the target function.
MoV DS: _ orgret, eax; stored in a temporary variable
Pop eax
MoV [esp], retaddr; change the return address of the target function to the return address of its own code space so that it can take over the processing after returning it
JMP _ orgdestfunction; jump to the original target function
Retaddr:
Pushad; Save the register after the original function is processed
Call _ hookdestfunction @ 0; reprocess
Popad; reply register
Jmp ds: _ orgret; jump to the next command for the system to call the target function.
_ FUNC @ 0 endp
When we want to intercept the target API, we only need to modify the machine with the first five bytes of the original function into a JMP _ FUNC.
Save the original 5 bytes. When you jump into the original function, restore the five bytes.
Hook kireadythread:
Kireadythread is called during Thread Scheduling preemption. Its prototype is
Void fastcall kireadythread (in prkthread thread)
When you enter kireadythread, ECx points to thread.
Therefore, you can hook kireadythread and then use the process information of ECx that is worth but the former thread.
Kireadythreadis not exported by ntosknrl.exe, so it is hard-coded. In 2000sp4, the address is 0x8043141f.
Specific implementation:
////////////////////////////////
// 1.cpp
////////////////////////////////
# Ifdef _ cplusplus
Extern "C "{
# Endif
# Include "ntddk. H"
# Include "string. H"
# Include "ntifs. H"
# Include "stdio. H"
# Define file_device_event 0x8000
# Define ioctl_passbuf/
Ctl_code (file_device_event, 0x802, method_buffered, file_any_access)
Void driverunload (in pdriver_object pdriverobject );
Ntstatus DriverEntry (in pdriver_object driverobject, in punicode_string registrypath );
Void cfunc ();
Void hookdestfunction ();
Ntstatus deviceiocontroldispatch (in pdevice_object deviceobject,
In pirp );
Extern void func ();
Void resumedestfunction ();
Const wchar DevLink [] = l "//?? // Myevent ";
Const wchar devname [] = l "// device // myevent ";
Unicode_string devnameunicd;
Unicode_string devlinkunicd;
Ulong orgdestfunction = (ulong) 0x8043141f; // kireadythread
Char jmpmycode [] = {0xe9, 0x00,0x00,0x00,0x00 };
Char orgcode [5];
Char outbuf [128] [16];
Int COUNT = 0;
Ulong orgcr0;
# Ifdef _ cplusplus
}
# Endif
Void disablewriteprotect (Pulong poldattr)
{
Ulong uattr;
_ ASM
{
Push eax;
MoV eax, Cr0;
MoV uattr, eax;
And eax, 0 fffeffffh; // 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;
};
}
Ntstatus DriverEntry (in pdriver_object pdriverobject, in punicode_string registrypath)
{
Ntstatus status;
Pdevice_object pdevice;
Dbuplint ("DriverEntry called! /N ");
Rtlinitunicodestring (& devnameunicd, devname );
Rtlinitunicodestring (& devlinkunicd, DevLink );
Status = iocreatedevice (pdriverobject,
0,
& Devnameunicd,
File_device_unknown,
0,
True,
& Pdevice );
If (! Nt_success (Status ))
{
Dbuplint ("can not create device./N "));
Return status;
}
Status = iocreatesymboliclink (& devlinkunicd, & devnameunicd );
If (! Nt_success (Status ))
{
Dbuplint ("cannot create link./N "));
Return status;
}
Pdriverobject-> driverunload = driverunload;
Pdriverobject-> majorfunction [irp_mj_create] =
Pdriverobject-> majorfunction [irp_mj_close] =
Pdriverobject-> majorfunction [irp_mj_device_control] = deviceiocontroldispatch;
Pdriverobject-> driverunload = driverunload;
* (Ulong *) (jmpmycode + 1) = (ulong) func-(ulong) orgdestfunction-5;
Memcpy (orgcode, (char *) orgdestfunction, 5 );
Hookdestfunction ();
Return STATUS_SUCCESS;
}
Void driverunload (in pdriver_object pdriverobject)
{
Ntstatus status;
Resumedestfunction ();
If (pdriverobject-> deviceobject! = NULL)
{
Status = iodeletesymboliclink (& devlinkunicd );
If (! Nt_success (Status ))
{
Dbuplint ("iodeletesymboliclink () failed/N "));
}
Iodeletedevice (pdriverobject-> deviceobject );
}
}
Void displayname (pkthread thread)
{
Pkprocess process = thread-> apcstate. process;
Peprocess = (peprocess) process;
Dbuplint ("imagefilename = % s/n", peprocess-> imagefilename );
Sprintf (outbuf [count ++], "% s", peprocess-> imagefilename );
}
Void cfunc (void)
{
Ulong pkheader = 0;
_ ASM
{
MoV pkheader, ECx // ECx register is the prkthread parameter in kireadythread
}
Resumedestfunction ();
If (pkheader! = 0 & count <128)
{
Displayname (pkthread) pkheader );
}
}
Void hookdestfunction ()
{
Disablewriteprotect (& orgcr0 );
Memcpy (char *) orgdestfunction, jmpmycode, 5 );
Enablewriteprotect (or1_0 );
}
Void resumedestfunction ()
{
Disablewriteprotect (& orgcr0 );
Memcpy (char *) orgdestfunction, orgcode, 5 );
Enablewriteprotect (or1_0 );
}
Ntstatus deviceiocontroldispatch (
In pdevice_object deviceobject,
In pirp
)
{
Pio_stack_location irpstack;
Ntstatus status;
Pvoid inputbuffer;
Ulong inputlength;
Pvoid outputbuffer;
Ulong outputlength;
Object_handle_information objhandleinfo;
Status = STATUS_SUCCESS;
// Retrieve the ioctl Request Code
Irpstack = iogetcurrentirpstacklocation (pirp );
Switch (irpstack-> majorfunction)
{
Case irp_mj_create:
Dbuplint ("Call irp_mj_create/N ");
Break;
Case irp_mj_close:
Dbuplint ("Call irp_mj_close/N ");
Break;
Case irp_mj_device_control:
Dbuplint ("irp_mj_device_control/N ");
Inputlength = irpstack-> parameters. deviceiocontrol. inputbufferlength;
Outputlength = irpstack-> parameters. deviceiocontrol. outputbufferlength;
Switch (irpstack-> parameters. deviceiocontrol. iocontrolcode)
{
Case ioctl_passbuf:
{
Rtlcopymemory (pirp-> userbuffer, outbuf, 20*16 );
Memset (outbuf, 0,128*16 );
Count = 0;
Break;
}
Default:
Break;
}
Default:
Dbuplint ("Call irp_mj_unknown/N ");
Break;
}
Pirp-> iostatus. Status = status;
Pirp-> iostatus. Information = 0;
Iocompleterequest (pirp, io_no_increment );
Return status;
}
////////////////////////////////
// 1.asm
////////////////////////////////
. 386
. Model small
. Data
_ Orgret dd 0
. Code
Public _ FUNC @ 0
Extrn _ cfunc @ 0: near
Extrn _ hookdestfunction @ 0: near
Extrn _ orgdestfunction: DWORD
_ FUNC @ 0 proc
Pushad
Call _ cfunc @ 0
Popad
Push eax
MoV eax, [esp + 4]
MoV DS: _ orgret, eax
Pop eax
MoV [esp], retaddr
JMP _ orgdestfunction
Retaddr:
Pushad
Call _ hookdestfunction @ 0
Popad
Jmp ds: _ orgret
_ FUNC @ 0 endp
End
//////////////////////////////////////// //
// App. cpp
//////////////////////////////////////// //
# Include <windows. h>
# Include <stdio. h>
# Define file_device_event 0x8000
# Define ctl_code (devicetype, function, method, access )(/
(Devicetype) <16) | (ACCESS) <14) | (function) <2) | (method )/
)
# Define file_any_access 0
# Define method_buffered 0
# Define file_device_unknown 0x00000022
# Define ioctl_passbuf/
Ctl_code (file_device_event, 0x802, method_buffered, file_any_access)
Int main ()
{
Handle hdevice;
Bool status;
Ulong dwreturn;
Char outbuf [129] [16];
Hdevice = NULL;
M_hcommevent = NULL;
Hdevice = createfile ("//. // myevent ",
Generic_read | generic_write,
File_pai_read | file_pai_write,
Null,
Open_existing,
File_attribute_normal,
Null );
If (hdevice = invalid_handle_value)
{
Printf ("createfile wrong/N ");
Getchar ();
Return 0;
}
While (1)
{
Memset (outbuf, 0,129*16 );
Status = deviceiocontrol (hdevice,
Ioctl_passbuf,
Null,
0,
& Outbuf,
128*16,
& Dwreturn, null );
If (! Status)
{
Printf ("Io wrong + % d/N", getlasterror ());
Getchar ();
Return 0;
}
Int C = 0;
While (* (char *) (& outbuf) + C * 16 ))
{
// Skip csrss.exe and process information, because a large amount of information is generated.
If (strcmp (char *) (& outbuf) + C * 16, "app.exe ")&&/
Strcmp (char *) (& outbuf) + C * 16, "csrss.exe "))
Printf ("% s/n", (char *) (& outbuf) + C * 16 );
C ++;
}
Sleep (1 );
}
}
Test results:
......
Ttplayer.exe
System
Ttplayer.exe
Vrvmon.exe
Ttplayer.exe
System
System
EXPLORER. EXE
EXPLORER. EXE
EXPLORER. EXE
......
Testing, compiling environment 2000 SP4 2000 DDK
The hidden Process Code of the thread is not written. However, basically, the implementation is similar. You only need to compare the returned information with the information obtained by ring3 to find out the abnormal process.