Source: http://www.chinaitlab.com/ Hidden technology is very extensive in computer system security, especially in cyber attacks, when an attacker successfully invaded a system, effectively hiding an attacker's documents, processes and its loading The module is particularly important. This article will discuss the advanced hidden technology of files, processes, and modules in Linux systems. These technologies have been widely applied to various back door or safety testing procedures, and some are just starting, still in the discussion stage, the application is very less. 1. Hidden technology 1.1. The interrupt control and system calls underline The Intel x86 series microcomputer support 256 interrupts, in order to make the processor easily identify each interrupt source, the number of interrupts from 0 ~ 256, ie, give an interrupt type code n, Intel call it as an interrupt vector. Linux implements system calls with an interrupt vector (128 or 0x80), all system calls enter the kernel through the unique portal system_call, when the user dynamic process performs an int 0x80 assembly instruction, the CPU switches to the kernel state, and starts Execute the system_call function, the system_call function re-acquires the address of the corresponding system call by the system call table sys_call_table. The address of all system call functions is stored in the system call table sys_call_table, and each address can be indexed with the system call number, such as the SYS_CALL_TABLE [NR_FORK] index, is the address of the system calls SYS_FORK (). Linux uses an interrupt descriptor (8 bytes) to represent each interrupt related information, its format is as follows: Offset 31 .....16 Some flags, type codes, and reserved bit segment selector offset 15 ....0 The interrupt descriptor is placed in a continuous address space, which is called an interrupt descriptor table (IDT), and its start address is placed in the Interrupt Descriptor Table Register (IDTR), and its format is as follows: 32 base Address value boundaries in which each structure can be represented as follows: By the above instructions can be drawn by the IDTR register to find the system_call function address: found the interrupt descriptor table according to the IDTR register, the 0x80 item of the interrupt descriptor table is The address of the system_call function, this address will be applied in later discussion. 1.2.Linux's LKM (Mounting Kernel Module) technology provides a module mechanism in order to maintain a smaller volume and can easily perform a functional extension. The module is part of the kernel, but is not compiled into the kernel, which is compiled into a target file, and is being dynamically inserted into the kernel as needed during operation or from the kernel. Since the module is running as part of the Linux kernel after insertion, the module programming is actually the kernel programming, so some resources exported by the kernel can be used in the module, such as the previous kernel export system call table for Linux2.4.18 ( The address of the sys_call_table, which can directly modify the inlet of the system call according to the address, thereby changing the system call. In the module programming, there must be initialization functions and clear functions. In general, these two functions are default to init_module (), and clearup_module (), starting from the 2.3.13 core version, the user can rename, initialize the two functions The function is called when the module is inserted into the system, and some functions and symbols can be made, and the clerution function is called when the module is removed, and some recovery work is usually done in this function.
1.3.3.Linux Memory Image / DEV / KMEM is a character device that is a computer main memory image, which can be tested even modify the system. When the kernel does not export the SYS_CALL_TABLE address or does not allow the module to modify the system to call the system. Thus, the purpose of hiding files, processes, or modules. 1.4.Proc File System Proc File System is a virtual file system that implements the interface of the file system for outputting the system operation. It provides an interface in the form of a file system, providing communication between the operating system itself and the application process, enables the application to be safe and convenient to obtain internal data information of the system's current health care, and can modify certain systems. Configuration information. Since PROC is implemented in an interface system interface, it can be accessed like accessing a normal file, but it only exists in memory. 2. Technical Analysis 2.1 Hidden file Linux system System calls used to query file information are sys_getdents, which can be observed by string, such as the Strace LS lists the system calls used by the command LS, which can be found by LS Sys_GETEDENTS to perform operation. When the information of the file or directory is queried, the Linux system performs the corresponding query operation with SYS_GETEDENTS and passes the obtained information to the user space run, so if the system call is modified, remove the result and some specific files Related information, then all programs that use the system call will see the file, thereby achieving hidden purposes. First introduce the original system call, its prototype is: int SYS_GETDENTS (unsigned int FD, Struct Dirent * DIRP, Unsigned INT Count) where fd is a file descriptor pointing to the directory file, which is read according to the directory file pointed to by the FD. Corresponding to the DIRENT structure, in DIRP, where count is the amount of data returned in DIRP, the function returns the value of the number of bytes that fill to DIRP when correct. The figure below is the modified system calls the Hacked_getDents execution process. The HACKED_GETDENTS function in the figure actually invokes the original system call, then removes file information related to a specific file name from the obtained Dream structure, so that the application will not see the existence of the file from the system call back. It should be noted that some newers are queried by Sys_GETDENTS64, but their implementation principles are basically the same as sys_getdents, so they can still be modified in these versions to modify the system call, hidden files. . 2.2 Hidden Modules Analyze how to modify system calls to hide files for specific names, in actual processing, often use modules to achieve the purpose of modifying system calls, but when inserting a module, if you do not take any hidden measures, very It is easy to be discovered by the other party, once the other party discovers and uninstalls the plugged module, all files that use the module to be hidden, so you should continue to analyze how to hide the specific name. The system call used to query module information in Linux is SYS_QUERY_MODULE, so you can achieve the purpose of hidden specific modules by modifying the system call.
First explain the original system call, the prototype of the system call is: int SYS_QUERY_MODULE (const char * name, int which, void * buf, size_t bufsize, size_t * reset) If the parameter Name is not empty, the specific module is accessed, otherwise Access is the kernel module, the parameter which description query type, when WHICH = QM_Modules returns all currently inserted module names, stored into the number of modules in RET, buffsize is the size of the BUF buffer. You can only process the situation of WHICH = QM_Modules during the module hidden process. The modified system call work procedure is as follows: 1) Call the original system call, return error code; 2) If WHICH is not equal to QM_Modules, no processing is required, directly returns. 3) Processing from the start position of the BUF, if there is a specific name, then the name will be overwritten forward. 4) Repeat 3) until all the names are finished, return it correctly. 2.3 Hiding Process In LINUX, there is no system call for directly querying process information. It is similar to the PS to query the process information to be implemented by querying the PROC file system. It has already introduced the PROC file system in the background knowledge, due to its application file The system's interface is implemented, so it is also possible to hide the file in the PROC file system with the method of hidden files, and only the judgment of the PROC file system is required to be added to the above Hacked_getdents. Since PROC is a special file system, only in memory, there is no actual device, so the Linux kernel is assigned to it a particular primary device number 0 and a specific secondary device number 1, in addition to this Since there is no corresponding I node in the abstament, the system is also assigned to it a special node proc_root_ino (value 1), and the No. 1 index node on the device is reserved. Through the above analysis, it is possible to determine whether a file belongs to the PROC file system: 1) Get the INODE structure Dinode; 2) IF (Dinode-> i_ino == proc_root_ino &&! Major (Dinode-> i_DEV) & Minor (Dinode-> i _DEV) == 1) {This file belongs to the PROC file system} to give a pseudo code hidden specific process to hidden specific processes indicating: Hacket_getdents (Unsigned Int FD, Struct Dirent * DIRP, Unsigned int COUNT ) {Call the original system call; obtain the node corresponding to the FD; if (this file is a PROC file system && This file name needs to hide) {Remove file related information from DIRP}} 2.4 Modifying the system Call now has resolved How to modify the system call to achieve hidden purposes, then how do you use the modified system call to replace the original? This issue is often the most critical in practical applications, and how this will be discussed below in different situations. (1) When the system exports SYS_CALL_TABLE, and supports dynamic insertion modules: This kernel configuration is very common before the Linux core 2.4.18.
In this case, modify the system call is very easy, just modify the corresponding SYS_CALL_TABLE entry to point to new system calls. The following is the corresponding code: int orig_getdents (unsigned int fd, struct dirent * dirp, unsigned int count) int init_module (void) / * Initialization module * / {orig_getdents = sys_call_table [SYS_getdents]; // save the original system call orig_query_module = sys_call_table [SYS_query_module] sys_call_table [SYS_getdents] = hacked_getdents; // set up a new system call sys_call_table [SYS_query_module] = hacked_query_module; return 0; // return 0 on success} void cleanup_module (void) / * unloading module * / {sys_call_table [SYS_getdents ] = ORIG_GETDENTS; // Restore the original system call SYS_CALL_TABLE [SYS_QUERY_MODULE] = Orig_Query_Module;} (2) In the case where the system does not export sys_call_table: Linux kernels After 2.4.18, the SYS_CALL_TABLE symbol is no longer exported for security, so that it is impossible Get the address of the system call table directly, then other methods must be found to get this address. In the background knowledge, it is mentioned that / dev / kmem is an image of the system's main memory, which can be used to find the address of the SYS_CALL_TABLE and modify it to use new system calls. So how do you find the address of SYS_CALL_TABLE in the system image? Let's take a look at how system_call's source code is to achieve system calls (code /ARCH/i386/kernel/entry.s): entry (system_call) Pushl% EAX # Save Orig_Eax Save_all get_current (% EBX) CMPL $ NR_syscalls),% eax jae badsys testb $ 0x02, tsk_ptrace (% ebx) # PT_TRACESYS jne tracesys call * SYMBOL_NAME (sys_call_table) (,% eax, 4) movl% eax, EAX (% esp) # save the return value ENTRY (ret_from_sys_call This source code first saves the value of the corresponding register, then determines whether the system call number (in the EAX register) is legal, then process the setting of the debug, after all of these, use Call * Symbol_name (sys_call_table) (,% EAX, 4) to transfer the corresponding system call for processing, and Symbol_Name (sys_call_table) is the address of SYS_CALL_TABLE. As can be seen from the above analysis, after the SYSTEM_CALL function is found, you can determine the location of the SYS_CALL_TABLE using the character matching, because the machine command code of Call Something (,% Eax, 4) is 0xFF 0x14 0x85. So, match this instruction code.
As for how to determine the address of System_Call already introduced in the background knowledge, the corresponding pseudo code is given: struct {// Various field meaning can refer to the background knowledge about the IDTR register Unsigned short limit; unsigned int base;} __ attribute __ (PACKED) IDTR; Struct {// Each field meaning can refer to the introduction of the interrupt descriptor in the background knowledge, unsigned short sel; unsigned short, flags; unsigned short off2;} __ attribute __ ((packed) IDT) IDT INT KMEM; / * The following function is used to read the SZ byte to the memory m from the offset from the Kemem. * / Void ReadkMem (Void * m, unsigned off, int SZ) {... ...} / * The following function is used to read the count bytes from the SRC * / void WeitekMem (Void * src, void * dest, unsigned int count) {..........} Unsigned Sct; // Store the SYS_CALL_TABLE address char buff [100]; // is used to store the top 100 bytes of the System_Call function. Char * p; if ((kmem = open ("/ dev / kmem", o_rdonly) <0) Return 1; ASM ("SIDT% 0": = M "(IDTR)); // Read IDTR register The value is readkmem (& IDT, IDTR.BASE 8 * 0X80, SIZEOF (IDT)) // in the IDTR structure // = (idt.off2 << 16) | IDT.OFF1; / / Get the address of the System_Call function. ReadkMem (BUFF, SYS_CALL_OFF, 100) // Read 100 bytes of the system_call function to BUFF P = (CHAR *) MEMMEM (BUFF, 100, "XFFX14x85", 3); // Get the address of the Call statement corresponding to the machine code SCT = (unsigned *) // Gets the address of sys_call_table. At this point, SYS_CALL_TABLE can be obtained in memory, so that the corresponding system call corresponding to the corresponding system call can be found according to the system call number, the new system adjustment can be used, and the specific practices are as follows: ReadkMem (& Orig_getdents, Sct SYS_getdents * 4,4) // save the original system call readkmem (& orig_query_module, sct SYS_query_module * 4,4); writekmem (hacked_getdents, sct SYS_getdents * 4,4); // set up a new system call writekmem (hacket_query_module, SCT SYS_QUERY_MODULE * 4, 4); 2.5 Other related techniques have completely solved the hidden related technical issues, in practical applications, the startup module or process can be added to the corresponding start-up directory, suppose Your Linux runs 3, then you can add it in the directory RC3.D (this directory often exists in the /etc/rc.d or / etc.), Then change the name of the script to hidden names.