Lecture
A rootkit (English rootkit , that is, a “root set”) is a set of software (for example, executable files, scripts, configuration files) to provide:
The term Rootkit has historically come from the UNIX world, and this term is understood as a set of utilities or a special kernel module that an attacker installs on a hacked computer system immediately after obtaining the superuser's rights. This set, as a rule, includes various utilities for “tracing” traces of the invasion into the system, making invisible sniffers, scanners, keyloggers, and Trojans replacing the main UNIX utilities (in the case of a non-nuclear rootkit). Rootkit allows a hacker to gain a foothold in the hacked system and hide the traces of its activity by hiding files, processes, and the very presence of the rootkit in the system.
A rootkit can be installed into the system in various ways: download via an exploit, after receiving shell access (in such a case, a tool like wget or the original FTP client can be used to download the rootkit from a remote device), in the source code or software product resources.
There are various rootkit technologies, the most common: capturing call tables (IAT, IDT, SSDT, GDT), intercepting functions (for example, modifying the initial bytes), directly modifying system objects (DKOM), methods for using drivers.
The call table is an array in which each element stores the address of the corresponding procedure. Such tables exist in kernel mode (IDT, CPU MSRs, GDT, SSDT, IRP dispatch table), and in user mode (IAT).
Import Address Table (IAT) is the main table of user mode module calls. Most executable files have one or more built-in IATs containing addresses of library procedures imported from a DLL. [2]
On a multiprocessor machine, there are several instances of call tables (for example, IDT, GDT, MSR). Since each processor has its own system registers (in particular, GDTR - global descriptor table register (GDT), IDTR - interrupt table descriptor register (IDT) and IA32_SYSENTER_EIP - contains the virtual address of the input point in kernel mode (MSR)), it also has own system structures. [3]
When you change an entry in the call table, program execution is monitored and, if necessary, redirected to the required functions. An intercepted procedure can [4] :
The general idea of capturing is as follows:
If the interception function involves calling the original procedure, then blocking and monitoring are performed before the call, filtering the parameters after.
IAT is a table of calls placed in the file structure of the application. IAT stores the address of the procedures exported by a specific DLL. Each DLL with which the application locks at boot time has its own IAT. To capture the IAT, you must perform the following steps:
For IAT manipulation, access to the address space of the application to which the table belongs is required. One way is to inject a DLL. Among the methods for introducing a DLL into the address space of a process, you can specify [5]
The principle of operation is based on the fact that the first bytes of the intercepted functions are replaced by the interceptor code. It should be emphasized that when installing the interceptor, the code of the function being intercepted is not analyzed: the N first bytes change, not the first N machine commands. The consequence of this fact is [6] :
Algorithm of the rootkit:
Interceptor operation algorithm:
To intercept, it is sufficient to modify the five first bytes of the function, in which place the jmp operation is transferred, which transfers control to the rootkit interceptor.
It should be noted that the simplest systems are protected against attacks of this type and check the first byte of the called functions for the presence of the machine operation code jmp. As a countermeasure measure, rootkit developers use methods of “masking” the code recorded at the beginning of the interceptor function (using commands like PUSH / RET, placing several NOP operators or a garbage code like PUSH AX / POP AH, as well as elements of polymorphism).
The method of modifying the first byte of functions has a number of disadvantages, mainly due to the need to restore the machine code of the intercepted functions before calling them and re-intercepting them after the call. These operations reduce system performance and can cause disruptions in multi-threaded applications.
Windows NT operating systems use standard object models. The various components of the executing system define one or more types of objects. Each component exports, in kernel mode, a set of supported functions and properties, called a COM interface, for manipulating this type of object. No component can directly access another component object. Typical kernel mode objects are: [7]
This design provides flexibility and portability (portability), for example, future releases of the operating system may contain kernel components that define similar objects, but have a completely different internal structure. If such components export functions with preserved names and parameters, the change will have no effect. [eight]
Direct manipulation of kernel objects is a fairly powerful technology that is difficult to detect. However, there are a number of drawbacks, such as method instability, version dependence, implementation complexity due to the lack of a documented description of the structures and properties of objects. Despite these limitations, this method allows you to hide processes, device drivers, ports, increase the level of privileges of threads (hence, processes).
EPROCESS is a structure that serves as an internal representation of the process (process object). Windows uses a circular doubly linked list of EPROCESS structures to track the execution process. References linking EPROCESS objects are contained in the ActiveProcessLink field, whose structure is LIST_ENTRY [9] :
typedef struct _LIST_ENTRY {
struct _LIST_ENTRY * Flink; struct _LIST_ENTRY * Blink;
} LIST_ENTRY, * PLIST_ENTRY;
The simplest process hiding algorithm:
Excluding a process from the process list does not affect its execution. In Windows, code execution is planned at the thread level, the processes determine the context in which the threads are started. The process is hidden at the external level in tools that rely on the objects of EPROCESS processes, such as Task Manager. The kernel dispatcher uses a different accounting scheme that relies on other data structures (mainly the ETHREAD object). This method allows you to hide processes without losing functionality. [9]
Drivers. The Microsoft driver model supports a multi-layered architecture, so an I / O request (I / O request, data exchange between applications and drivers) can be serviced by a series of connected drivers, each of which performs its own task. The chain of drivers serving a physical device is called a stack. This modular approach allows new drivers to be included in the stack to increase functionality. In this case, only a separate part of the chain is changed or added. Also, some peripheral devices use the same controllers (and, accordingly, I / O buses). Modularity allows you to optimize the use of identical blocks of code, instead of writing a separate driver for each device.
The WDM model defines three types of drivers: a bus driver, functional drivers, and filter drivers. Filter drivers are usually located between other modules and capture IRPs passing through them. Before sending the IRP to the adjacent driver, the filter can view the contents or change it to affect the future behavior of the system. For example, when taking a disk image from a server that is critical to downtime, the driver filter can be used to modify the data stream in order to hide some files.
IRP packet (I / O request packet) is a Windows kernel data structure that provides data exchange between applications and the driver, as well as between the driver and the driver. When a request is received from an application, the I / O manager creates an appropriate IRP that localizes and sends to the top object in the driver stack. If the top driver was able to independently process the incoming IRP, it completes the request and returns the IRP to the I / O manager. Otherwise, the driver performs partial processing, localizes the underlying object in the stack and requests the I / O manager to transfer the IRP to the next driver.
When creating an IRP, the I / O manager reserves the memory area after the header. The allocated memory is used to write an array of IO_STACK_LOCATION structures allocated for each stack driver:
Memory size corresponds to the number of drivers in the stack. The array is numbered from 1, corresponding to the lower stack driver. The structure contains information about the driver control functions called by the I / O manager (MajorFunction and MinorFunction fields), parameters passed to the function (Parameters field, contents vary depending on the function), pointer to the driver object (DeviceObject), pointer to the completion function (CompletionRoutine field, this function is in the top level driver).
The driver management function, when it first receives the IRP, restores the parameters from the corresponding position in the I / O stack, making a call to IoGetCurrentIrpStackLocation (). Next, the prescribed actions are performed, after which, in the case of IRP forwarding to the lower stack driver, occurs:
There are two standard ways to set the stack position for the following driver: [10]
VOID IoSkipCurrentIrpStackLocation (IN PIRP Irp);
The function decrements the pointer to the IO_STACK_LOCATION array by one. Thus, when the IRP is sent, the pointer will be restored (automatically incremented by one), as a result, the same stack will be used. When using this method, there will be an unused area at the end of the stack.
VOID IoCopyCurrentIrpStackLocationToNext (IN PIRP Irp);
IRP transfer to the following driver is performed using the function: NTSTATUS IoCallDriver (IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp);
The first argument is a pointer to the underlying driver object. The method of obtaining such an address is determined by a specific control function; there is no standard method.
Each request must be completed either by the last driver in the stack (no further IRP forwarding is possible) or by one of the upstream.
The I / O manager initializes the completion process for a given IRP when any of the drivers that process the IRP calls the IoCompleteRoutine () termination function. When it is called, the I / O manager fills the portion of the I / O stack of the current driver with zeros, then calls the higher-level driver with the completion function set to this IRP. To determine how the lower level driver will process the request for a higher level driver function, only an I / O status block is available in the IRP.
Actually, the driver filter thus installed allows you to process not only incoming IRP packets (for example, block reading of a certain sector of the disk), but also manage the results of processing downstream drivers by initializing the completion function. [eleven]
Another way to implement rootkits is to modify the MBR and boot up to the operating system kernel, bootkits (for example, BackDoor.MaosBoot).
This type of malicious code in the Windows environment has been known since the early 1990s as stealth viruses.
In addition to itself, a rootkit, as a rule, can mask the presence in the system of any directories and files on the disk described in its configuration, keys in the registry. For this reason, “mounted” rootkit libraries have naturally appeared. Many rootkits install their drivers and services into the system (naturally, they are also “invisible”).
Rootkits can “pop up” not only attackers. It is a well-known case when Sony has built in the similarity of a rootkit into its licensed audio CDs. Rootkits are in essence the majority of software copy protection tools (and means of circumventing these protections — for example, emulators of CD and DVD drives). They differ from “illegal” only in that they are installed with the knowledge of the user [ source not specified 1635 days ] .
These are utilities or resident modules that detect the presence of rootkits in the system and (in varying degrees) remove them. There are many competing tools for this - both paid and free, but they all use similar principles of operation:
Finding discrepancies
Against MEP-rootkits. The same information is obtained in several ways using the API and "directly" and looking for discrepancies. In particular, import tables, the Native API table, the file system are usually scanned.
Comments
To leave a comment
Cryptanalysis, Types of Vulnerability and Information Protection
Terms: Cryptanalysis, Types of Vulnerability and Information Protection