Directory
- Ssdt hook
- Ssdt Introduction
- Ssdt Structure
- Ssdt hook Principle
- Prepare before hook
- How can I obtain the address of the function in ssdt?
- Ssdt hook Process
- Ssdt hook for Process Protection
- Communication between ring3 and ring0
- How to install, start, and stop the uninstall service
- References
- Source code attachment
- Copyright
Ssdt hook is used to load the driver and hook ntterminateprocess function successfully: when the specified process is protected and the process is ended using the "Task Manager", the "Access Denied" window is displayed, note: Our goal has been achieved: ssdt Introduction The full name of ssdt is system services Descriptor Table, System Service Descriptor Table.
This table associates ring3's Win32 API with ring0's kernel API.
Ssdt not only contains a large address index table, but also contains some useful information, such as the base address of the address index and the number of service functions.
By modifying the function address of this table, you can hook common Windows functions and APIs to filter and monitor system actions that you are concerned about.
Some hips, anti-virus software, system monitoring, and registry monitoring software often use this interface to implement their own monitoring modules.
The ssdt structure ssdt is the system service Descriptor Table. Its structure is as follows (see Chapter 2 of undocument Windows 2000 secretes ):
// Ksystem_service_table and counts // defines the ssdt structure typedef struct _ ksystem_service_table {Pulong servicetablebase; // The base address Pulong servicecountertablebase of ssdt (System Service dispatch table); // used for checked builds, contains the number of times each service in ssdt is called ulong numberofservice; // number of service functions, numberofservice * 4 is the size of the entire Address Table ulong paramtablebase; // sspt (System Service parameter table) base Address} ksystem_service_table, * pksystem_service_table; typedef struct _ partition {ksystem_service_table ntoskrnl; // ntoskrnl.exe service function ksystem_service_table win32k; // win32k. sys service functions (supported by gdi32.dll/user32.dll kernel) ksystem_service_table notused1; ksystem_service_table notused2;} kservice_table_descriptor, * pkservice_table_descriptor;
There are two System Service Identifier tables in the kernel, one is keservicedescriptortable(exported by ntoskrnl.exe) and the other is keserviedescriptortableshadow (not exported ). The difference between the two is that keservicedescriptortable only has one ntoskrnel, and keserviedescriptortableshadow contains ntoskrnel and win32k. Generally, the service address of native API is assigned by keservicedescriptortable, and the kernel API call service address of GDI. dll/user. dll is assigned by keserviedescriptortableshadow. It is also worth noting that win32k. sys is loaded only in the GUI thread. In general, it is not loaded. Therefore, if you want to hook the keserviedescriptortableshadow, it is generally triggered by a GUI program through iocontrolcode (I do not want to understand this at the beginning, after the blue screen crashes for n times, I cannot understand what is going on ). The ssdt hook principle has many types of kernel hooks. The following illustration shows that ssdt hook is only one of the hook technologies. This article describes how to use ssdt hook. The ssdt hook schematic diagram uses the kernel detective tool. We can find that the current address of ntterminateprocess changes before and after the ssdt hook, where, the current address after the change: 0xf885a110 is the address of the custom hook function (hookntterminateprocess. In this way, every time ntterminateprocess is executed, the function directed to by the "current address" will be executed. This is the principle of ssdt hook. In addition, reading the "fallen genius" of snow writes well. I directly reference the principle of ssdt hook, which is actually very simple. Let's take a look at what kind of keservicedescriptortable is.
lkd> dd KeServiceDescriptorTable 8055ab80 804e3d20 00000000 0000011c 804d9f48 8055ab90 00000000 00000000 00000000 00000000 8055aba0 00000000 00000000 00000000 00000000 8055abb0 00000000 00000000 00000000 00000000
As shown above, 80587691 805716ef 8057ab71 80581b5c is the address of the system service function. For example, when we call OpenProcess in ring3, the ID of the sysenter is 0x7a (XP SP2), and then the system checks the keservicedescriptortable. This is probably the case of keservicedescriptortable. ntoskrnel. servicetablebase (804e3d20) + 0x7a * 4 = 804e3f08, then 804e3f08-> 8057559e. This is where the OpenProcess system service function is located. Let's track it again:
lkd> u 8057559e nt!NtOpenProcess: 8057559e 68c4000000 push 0C4h 805755a3 6860b54e80 push offset nt!ObReferenceObjectByPointer+0x127 (804eb560) 805755a8 e8e5e4f6ff call nt!InterlockedPushEntrySList+0x79 (804e3a92) 805755ad 33f6 xor esi,esi
8057559e is the starting address of the ntopenprocess function.
Well, what if we change 8057559e to the address of our function? For example, if myntopenprocess is used, the system will directly call myntopenprocess instead of the original ntopenprocess. This is the principle of ssdt hook. In addition, for details about how to transfer the ring3 layer to the ring0 layer, refer to my post to help you better understand the ssdt Hook Technology: before ring3 is transferred to the ring0 tracking hook, we prepare to modify the ssdt table. First, this table must be writable, but it will be read-only in systems after XP, three methods to modify the memory protection mechanism (1) modify the registry recovery page protection: HKLM \ System \ CurrentControlSet \ Control \ Session manger \ Memory Management \ enforcewriteprotection = 0 remove page protection: HKLM \ System \ CurrentControlSet \ Control \ Session manger \ Memory Management \ disablepagingexecutive = 1 (2) Change the 1st-bit Windows Memory Allocation for the Cr0 register, which is paging management. There is a Cr0 register, such:
The 1st bits are called protection attribute spaces, which control the read or write attributes of pages. If it is 1, it can be read, written, or executed. If it is 0, it can only be read/executed. By default, ssdt and IDT page attributes are read-only and executable, but cannot be written. The Code is as follows:
// Set void disablewrite () {_ Try {_ ASM {mov eax, Cr0 or eax, 10000 h mov Cr0, eax STI} _ partition T (1) {dbuplint ("disablewrite execution failed! ") ;}}// Set to writable void enablewrite () {__ try {_ ASM {CLI mov eax, Cr0 and eax, not 10000 h // and eax, 0 fffeffffh mov Cr0, eax }}_ _ partition T (1) {dbuplint ("enablewrite execution failed! ");}}
(3) Use memory descriptor list (MDL)
For more information, see Google.
How can I obtain the address of the function in ssdt?
Two macros are used here:
① Obtain the index number of the specified service: syscall_index
② Obtain the current address of the specified service: syscall_function
The two macros are defined as follows:
// Obtain the index number of the service corresponding to zwservicefunction in ssdt Based on zwservicefunction # define syscall_index (servicefunction) (* (Pulong) (puchar) servicefunction + 1 )) // obtain the index number of the Service in ssdt Based on zwservicefunction, and then obtain the address of ntservicefunction # define syscall_function (servicefunction) keservicedescriptortable-> ntoskrnl. servicetablebase [syscall_index (servicefunction)]
Ssdt hook Process
In the driver's entry function (DriverEntry), The ssdt table before ssdt hook is backed up (saved in an array). During the backup, an index number corresponds to the current address, as shown in.
In this way, when the hook is removed, you can obtain the current address of the service name before the hook from the Global Array Based on the index number, so that the original address can be written back, this step is important.
When the user chooses to protect a process, an io_insert_protect_process control code is sent to the driver through deviceiocontrol. At this time, the driver generates an irp_mj_device_control, which is already in the driver
Irp_mj_device_control specifies a dispatch function: ssdthook_dispatchroutine_control. In this dispatch letter: we obtain the control code (whether to protect the process or cancel the protection process). If we want to protect a process, the PID of the process to be protected is passed to the driver through the 3rd parameters of deviceiocontrol. Then, read the PID from the buffer in the dispatch function ssdthook_dispatchroutine_control. To protect the process, add the PID of the process to an array, if you want to "unprotect processes", remove the process PID to be unprotected from the array.
After hook nttermianteprocess function, we will execute our custom function: hookntterminateprocess. In the hookntterminateprocess function, we will determine whether the current process is in the process array to be protected, if the PID exists in the array, an exception with insufficient permissions is returned. If the PID does not exist in the process protection array, the ntterminateprocess in the original ssdt is called directly to end the process.
With the above theoretical basis, ssdt hook implements process protection. Next we can talk about the specific implementation of ssdt hook to implement process protection. To implement process protection, you can hook nttermianteprocess or ntopenprocess. Here, I am Hook nttermianteprocess. As mentioned in the ssdt hook principles section, the essence of ssdt hook principles is: to customize a function (hookntterminateprocess) and direct the current address of the System Service nttermianteprocess to the address of our custom function. This step is executed in the driver entry function. When the driver is loaded, write the address of the custom function to the current address of the nttermianteprocess service in the ssdt table:
// Implement hook installation. It is mainly used to replace oldservicentstatus installhook (ulong oldservice, ulong newservice) {_ Try {ulong uoldattr = 0; enablewrite () in ssdt (); // remove page protection kdprint ("forged ntterminateprocess address: % x \ n", (INT) newservice); // keservicedescriptortable-> ntoskrnl. servicetablebase [syscall_index (oldservice)] = newservice; syscall_function (oldservice) = newservice; // disablewrite (); // restore page protection return status _ Success;} _ success T (1) {kdprint ("hook Installation failed! "));}}
Note that the page protection attribute of the memory needs to be removed before the hook, and the page protection attribute of the memory needs to be replied after the hook. The code for the hookntterminateprocess function is as follows:
//************************************// Function Name: hookntterminateprocess // Description: Custom ntopenprocess, used to implement the hook kernel API // Date: 2013/06/28 // parameter: processhandle: Process Handle exitstatus: // return value: // *********************************** ntstatus hookntterminateprocess (_ in_opt handle processhandle, __in ntstatus exitstatus) {ulong upid; ntstatus rtstatus; pchar pstrprocname; peprocess; ansi_string Str Procname; // obtain the fileobject corresponding to the process through the process handle. Because this is a process object, the eprocess object rtstatus = obreferenceobjectbyhandle (processhandle, file_read_data, null, kernelmode, (pvoid *) & peprocess, null); If (! Nt_success (rtstatus) {return rtstatus;} // Save the original ntterminateprocess address poldntterminateprocess = (ntterminateprocess) oldsysserviceaddr [syscall_index (zwterminateprocess)] In ssdt; // The process name and process ID can be obtained through this function, which is exported in the kernel (which can be seen in wrk) // But ntddk. H is not everywhere, so you need to declare it to use upid = (ulong) psgetprocessid (peprocess); pstrprocname = _ strupr (tchar *) psgetprocessimagefilename (peprocess )); // use Microsoft's undisclosed psgetprocessima Get the process name using the gefilename function // use the process name to initialize an ASCII string rtlinitansistring (& strprocname, pstrprocname); If (validateprocessneedprotect (upid )! =-1) {// ensure that the caller process can end (taskmgr.exe) if (upid! = (Ulong) psgetprocessid (psgetcurrentprocess () {// if the process is a protected process, return STATUS_ACCESS_DENIED if an exception with insufficient permissions is returned ;}} // for unprotected processes, you can directly call ntterminateprocess in the original ssdt to end the process rtstatus = poldntterminateprocess (processhandle, exitstatus); Return rtstatus ;}
For details about the communication between ring3 and ring0, see Chapter 7th of Zhang Fan's windows driver development technology: for details about how to install, start, stop, and uninstall the dispatch function, refer to my other blog post: NT driver loader (with source code) reference ssdt hook-Vs ring0 inline HOOK: http://bbs.pediy.com/showthread.php? T = 40832 process hiding and process protection (ssdt hook implementation): hidden
Ssdt hook implements kernel-level process protectionAll rights reserved. You are welcome to reprint it. However, please note: Reprinted from
Ssdt hook Structure