Resolve the IDT extension mechanism of Windows2000

Source: Internet
Author: User
Resolve the IDT extension mechanism of Windows2000

Release date:
Abstract:

Abstract: http://www.xfocus.net/articles/200309/618.html

Created:
Article attributes: original
Article submitted: Brief (brief_at_safechina.net)

Resolve the IDT extension mechanism of Windows2000

Author: Brief
E-mail: Brief@fz5fz.org
Homepage: http://www.fz5fz.org & http://www.safechina.net
Date: 08-05-2003

Preface

Today, let's talk about the extension of the interrupt mechanism in Windows 2000. First of all, I declare that the technology mentioned in this article is not what I found, but what I learned when I learned the Windows kernel, the goal is to provide some practical materials to my friends who have just entered the underlying WINDOWS learning level, as well as record their learning process. If you are a Windows Kernel expert, hope you have time to give us some advice. If you are also a beginner, welcome to our fz5fz website for discussion! Well, let's go straight to the question. If you don't know much about interruptions, it will be an exciting journey.

1> introduction to windows trap mechanism

Trap is an indispensable system mechanism in windows. When an exception occurs in the system (hardware or software interrupt), the processor captures this action and transfers the control of the system to a fixed processing program, perform corresponding operations. Before the processor starts to process an interruption or exception, it must save some processor environment parameters to the stack for system restoration. The system is implemented through a method called trap frame, which saves the environment data of all threads in the system to the kernel stack, after the execution is completed, the execution points in the system control process are restored through the stack's out-of-stack mechanism. The traps in the kernel are divided into interruptions and exceptions. An interruption is an asynchronous event that occurs immediately in the system and has nothing to do with the processor status of the current system. At the same time, interruptions in the system can be divided into shielded interruptions and unshielded interruptions. An exception is a synchronization event. Exceptions can be reproduced in specific circumstances, but interruptions cannot. Interruptions can be divided into hardware interruptions and software interruptions. Obviously, hardware interruptions are related to hardware, such as some operations performed by the I/O device, processing on the processor clock or hardware port. Software interruption is introduced by the interrupt command int XX, which is usually the code that the application enters the operating system after execution in user mode. At this time, the system provides users with a variety of system services. For example, in Windows NT/2000, the system service call is implemented through the software interrupt int 0x2e (System Service interrupt, although Microsoft uses a "quick system call interface" in Windows XP/2003 to provide system services for users, a large number of interrupted services still exist in the system.

2> interrupt handling and related processes

Here we will discuss the data structure related to specific processors, so there will be some porting issues. This article is only for Intel's x86 family processor, the program included in this article only supports normal execution on the intel X86 processor. What is IDT? IDT (Interrupt Descriptor Table) is called the Interrupt Descriptor Table. It is an array that can hold 8192 units. Each member in the array is a 8-byte segment descriptor called a "Gate. In IDT, there are three types of doors: interrrupt gate, trap gate, and task gate, but they are mainly interrupt and trap doors. There is only a slight difference between the two. We only care about the interrupt gate in IDT. If you are interested in this aspect, for more information, see intel architecture software developer's manual and Volume 3. At the same time, there is an Interrupt Descriptor Table register (idtr) in the system, which contains the base address of the system Interrupt Descriptor Table and the limitation information of IDT, which is closely related to a compilation command sidt. In the following sections, we will see that it is the basis and key for us to implement extension of various Interrupt Descriptor tables! Note that, after the paging, segmentation, and virtual storage mechanisms are introduced in windows, this scheduling mechanism exists to transfer the code and data to the memory, transfers unnecessary data to external storage (secondary storage, such as hard disks ). If we find that the data we need is not in the memory when executing some code, a "page disconnection" will be triggered ", in this case, the system will search for the interrupted ISR (interrupt service routine, interrupt service routine) in IDT and execute the corresponding incoming call. You can imagine what the results will be if our Interrupt Descriptor Table is called out to external storage? At that time, the system will not be able to locate the "Page-missing interrupt" service routine, so far the system will crash!

In the Interrupt Descriptor Table, we mentioned an interesting register idtr. Of course, we are more concerned with the data that is more direct to us: code segment selector in IDT ), the offset of the interrupted code and the permission level (descriptor privilege level) parameter of the Interrupt Descriptor. Next, let's look at the execution process of the interrupt command. We should know that the application runs in the user mode (Ring 3), while the Interrupt Descriptor Table exists in the kernel mode (RING 0) in the system address space. After a software interruption occurs, that is, after an application calls a software interruption instruction, the processor first retrieves the input interrupt number parameter in the IDT, find the entry unit of the response and check the permission level parameters of the interrupt gate to check whether application calls under Ring 3 are allowed, in this way, the operating system reserves the right to control the call of software interruptions. However, hardware interruptions and exceptions do not focus on permission information. If the current privilge level (CPL) value is greater than the required permission (descriptor privilege level ), that is, when the permissions are insufficient, a general protection fault (general protection fault) is triggered. Otherwise, the processor switches from the user stack to the kernel stack. Now it is time to save the thread environment. The processor will press the stack pointer (SS: ESP) and Standard interrupt frame (eflags and Cs: EIP) in user mode into the stack. Then the processor enters our interrupt service routine, executes the relevant code processing, and then returns to the called application through the assembly instruction iretd. When the iretd command is executed, the system restores the data stored in the stack's thread environment from the stack. After the system recovers the environment before the command is executed, it then executes the subsequent code of the application.

3> interrupt-related data structure

First, we will introduce the data structure of a key Assembly command sidt mentioned above. After executing the command sidt, the system will save the base address and limit (6 bytes in total) of the Interrupt Descriptor Table to the variable pointer pointed to in the command, this is the entry port for IDT operations.

Typedef struct _ idtr
{
// Define the limit of the Interrupt Descriptor Table. The length is two bytes;
Short idtlimit;
// Define the base address of the interrupt description server table, which consists of four bytes;
Unsigned int idtbase;
} Idtr, * pidtr;

After obtaining the IDT entry, we will retrieve the IDT unit corresponding to the interrupt number that we need to process in the Interrupt Descriptor Table. The unit contains a lot of data structures that we need to pay attention, among them, we are most concerned with the code snippet selector, the offset of interrupted code execution, and the privilege level. Well, Let's define it first. In the next article, we will discuss in detail their specific applications.

Typedef struct _ idtentry
{
// The Last 16 bits of the offset of the interrupted code execution;
Unsigned short offsetlow;
// Selector, that is, register;
Unsigned short selector;
// Reserved Bit, always zero;
Unsigned char reserved;
// Type of the door in IDT: including the interrupt door, trap door, and task door;
Unsigned char type: 4;
// Segment identification space;
Unsigned char segmentflag: 1;
// Permission level of the interrupt door. 0 indicates the kernel level, and 3 indicates the user level;
Unsigned char DPL: 2;
// Presents the flag space;
Unsigned char present: 1;
// The 16-bit high offset of the interrupted Execution Code;
Unsigned short offsethigh;
} Idtentry, * pidtentry;

4> Create a software interrupt hook

As a common Windows programmer, you may need to be familiar with the basic functions of the system and be familiar with general program development. However, for a Windows kernel-level analysis developer, an in-depth understanding of the underlying system is necessary and important. Hook creates an excellent opportunity for us to understand the internal operating mechanism of the system. At the same time, writing a system-related monitoring program can automatically record and analyze internal system operations. Of course, we cannot be limited to understanding the system. We are more eager to modify and expand the system, change the original operating features of the system, and inject the functional components we need, making the system more suitable for ourselves is what we most want to see. Previously we talked about the hooks used to create system service calls to intercept system service calls. Similarly, in Windows2000, system services are interrupted through System Service (System Service interrupt, int 0x2e) by intercepting software interruptions, You can monitor and modify system service calls. Here we mainly discuss how to create hooks for software interruptions. However, hardware interruptions and exceptions are no exception. We can also apply the methods mentioned in this article to hardware interruptions and exceptions. For example, we can also write a kernel-level keyboard Recorder by intercepting the interrupt call of the keyboard driver. It can directly perform operations on each key-and-release operation, and the effect is very obvious, however, some functions related to hardware interrupt hooks provided by Microsoft also need to be used.

5> How to Create a software interrupt hook?

In fact, the process of creating a software interrupt hook should be obvious. Next we will briefly introduce the process of creating a hook, and then explain it with the actual code. First, we use the Assembly command sidt (sidt: store Interrupt Descriptor Table register; LIDT: Load Interrupt Descriptor Table register) to obtain the IDT base address idtbase, then we search for the hookintid In the Interrupt Descriptor Table, which should be an integer between 0 and 8192, although the latest intel processor claims to support Interrupt Descriptor units, however, due to some restrictions, only the first 256 interrupt descriptions can be handled. After finding the interrupt description that we need to hook, save the original interrupt Execution Code offset (32 bits) to a global variable oldisr, for use during interrupt processing or IDT recovery. In this way, the offset of the Execution Code corresponding to the interrupt number in the new IDT points to our own processing code. In our processing code newisr, note that some thread environments should be saved first. After processing the additional execution program we added (Monitor, monitoring registry-related 16 system service calls, recover the site and execute the program code that points to the interrupt door. In this way, we don't know what extra operations we have done on the broken door. It's just like what we did before! If we only process the code we added and do not continue to execute the previous program code corresponding to the interrupt gate, the system will be chaotic or even crash! When we uninstalled our software interrupt hook, we performed a reverse operation. Obtain the base address of the IDT, and then assign the offset of the old Execution Code address saved in the global variable to the Offset Unit (offsetlow/offsethigh) corresponding to the interrupt number ). The process is about to be discussed. The related program is T-hookint. Let's look at the code!

Void
Hookint (void)
{
// Save the data structure of the IDT entry's base address and restriction information;
Idtr;
// Record the pointer of the IDT array and use it to find the interrupt door corresponding to the hook interrupt number;
Pidtentry idtentry;

// Assemble the command sidt to obtain the IDT entry information;
_ ASM sidt idtr;

// Assign the IDT base address value;
Idtentry = (pidtentry) idtr. idtbase;

// Save the offset of the Execution Code pointed to by the interrupt gate corresponding to the interrupt number hookintid for execution of Interrupt Processing or restoration;
Oldisr = (unsigned INT) idtentry [hookintid]. offsethigh <16) | (idtentry [hookintid]. offsetlow );

// Guanzhong disconnection
_ ASM CLI
// Update the base 16 bits of the Execution Code offset;
Idtentry [hookintid]. offsetlow = (unsigned short) newisr;
// Update the 16-bit high Execution Code offset;
Idtentry [hookintid]. offsethigh = (unsigned short) (unsigned INT) newisr> 16 );
// Interrupt
_ Asm sti;
}

Void
Unhookint (void)
{
Idtr;
Pidtentry idtentry;

_ ASM sidt idtr;
Idtentry = (pidtentry) idtr. idtbase;

_ ASM CLI
// The Restoration interrupt number hookintid corresponds to the last 16 bits of the offset of the Code executed by the interrupt gate;
Idtentry [hookintid]. offsetlow = (unsigned short) oldisr;
// The restore interrupt number hookintid corresponds to the 16-bit high offset of the Code executed by the interrupt gate;
Idtentry [hookintid]. offsethigh = (unsigned short) (unsigned INT) oldisr> 16 );
_ Asm sti;

}

Void
_ Fastcall
Monitor ()
{
......
// Because the interrupt number we handle is 0x2e,
// Corresponds to System Service interrupt ),
// Identify system service calls by obtaining the values in the eax register;
_ ASM mov dwserviceid, eax;

// Execute the kernel function to obtain the ID number of the current process;
Dwprocessid = (unsigned INT) psgetcurrentprocessid ();

// Upgrade the current IRQL to prevent interruption;
Keraiseirql (high_level, & oldirql );

Switch (dwserviceid)
{
// If the eax value is 0x23,
// Calls the zwcreatekey system service corresponding to Windows2000;
Case 0x23:
Dbuplint ("processid: % d zwcreatekey/N", dwprocessid );
Break;
......
Default:
Break;
}

// Restore the original IRQL;
Kelowerirql (oldirql );
}

6> functions and principles of software interruptions added

By adding software interruptions, we can extend the functions of the system and change many operations of the system. We have introduced how to add new system service calls to the system to expand the system. By adding new software interruptions, you can also add system service calls, in addition, we can execute arbitrary ring 0 code in the newly added interrupt handler, which is so gratifying!

In fact, in IDT, 256 interrupt gate units are not fully utilized, and there are still some streams left to interrupt the door for future extension and use, we can add some mechanisms for these unused interrupt doors for our use. In fact, there are many similarities between the process of adding a software interrupt and the process of adding a software interrupt hook we described in detail. So I will not introduce it in detail here. Similarly, first obtain the IDT base address, then find the interrupt gate descriptor corresponding to the interrupt number that we will add in the Interrupt Descriptor Table, and then assign values to the relevant parameters, make it a real software interrupt door. In this case, we can use the interrupt command int XX in the application to call our own service program in the interrupt door.

7> implementation process of software interruption

The related program for the T-ADDIG (add interrupt gate), let's look at the code ha ~

Ntstatus
Installig ()
{
......

// Determine whether the interrupt we want to add is occupied;
If (idtentry [addintid]. offsetlow! = 0
| Idtentry [addintid]. offsethigh! = 0)
{
Return status_unsuccessful;
}

// Copy the original interrupt gate description;
Rtlcopymemory (& oldidtentry, & idtentry [addintid], sizeof (oldidtentry ));

// Guanzhong disconnection
_ ASM CLI

// Update the base 16 bits of the Execution Code offset;
Idtentry [addintid]. offsetlow = (unsigned short) interruptserviceroutine;
// Specifies the segment selector of the target code segment. The value of CS is 8;
Idtentry [addintid]. selector = 8;
// Reserved Bit, always zero;
Idtentry [addintid]. Reserved = 0;
// Door type. 0xe indicates that the door is interrupted;
Idtentry [addintid]. type = 0xe;
// Segmentflag sets the 0 code segment;
Idtentry [addintid]. segmentflag = 0;
// The descriptor permission level is 3, which allows the user mode program to call this interrupt;
Idtentry [addintid]. DPL = 3;
// Set the flag;
Idtentry [addintid]. Present = 1;
// Update the 16-bit high Execution Code offset;
Idtentry [addintid]. offsethigh = (unsigned short) (unsigned INT) interruptserviceroutine> 16 );

// Interrupt
_ ASM STI

Return STATUS_SUCCESS;
}

Void
Removeig ()
{
......
_ ASM CLI
// Restore the modified interrupt gate descriptor;
Rtlcopymemory (& idtentry [addintid], & oldidtentry, sizeof (oldidtentry ));
_ ASM STI
}

Extern
Void
_ Cdecl
Interruptserviceroutine (void)
{
Unsigned int command;
// Obtain the value in the eax register and accept the command parameters passed in from user mode;
_ ASM mov command, eax;
// Run the kernel code to obtain the OS version number;
Dbuplint ("ntbuildnumber = % d/N", (unsigned short) ntbuildnumber );
// Returns an interrupted message;
_ ASM iretd;
}

Postscript

Here, we just introduced some basic methods for extending IDT. Of course, there are still many more in-depth ones, which are worth exploring. For example, we can extend t-hookint, not only to monitor system service calls related to system registry operations, but to change the internal mechanism of Windows XP/2003, therefore, it is not so realistic to intercept system service calls through hook int 0x2e. Of course, there is also an IDT-based kernel-level backdoor that can be provided to any user by adding new software interruptions, such as system-level command. In short, the journey to explore the mysteries of the Windows kernel is not over yet, maybe it can only be considered a start.

Appendix:

As there are many Source Code related to this article, I will not post it here. You are welcome to download it from our homepage. Thank you ~

About us:

Fz5fz is mainly engaged in the study and research of network/system security, in-depth analysis and discussion of programming technology, persistence in originality, and pursuit of sharing.
Fz5fz home: http://www.fz5fz.org

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.