So far, we have covered various types of kernel rootkit infections in memory, but I think that this chapter begs a section dedicated to explaining how kernel drivers can be infected by attackers, and how to go about detecting these infections.
LKMs are ELF objects. To be more specific, they are ET_REL files (object files). Since they are effectively just relocatable code, the ways to infect them, such as hijacking functions, are more limited. Fortunately, there are some kernel-specific mechanisms that take place during the load time of the ELF kernel object, the process of relocating functions within the LKM, that makes infecting them quite easy. The entire method and reasons for it working are described in this wonderful phrack paper at http://phrack.org/issues/68/11.html, but the general idea is simple:
init_module() to have the same offset/value as the evil replacement function.This is the method used most ubiquitously by attackers on modern Linux systems (2.6 to 3.x kernels). There is another method that has not been specifically described anywhere else, and I will share it briefly.
LKM files are relocatable code, as previously mentioned, and are therefore quite easy to add code to since the parasite can be written in C and then compiled as relocatable before linking. After linking the new parasite code, which presumably contains a new function (or several functions), the attacker can simply hijack any function within the LKM using function trampolines, as described early in this chapter. So, the attacker replaces the first several bytes of the target function with a jump to the new function. The new function then memcpy's the original bytes to the old function before invoking it, and memcpy's the trampoline back in place for the next time the hook is to be called.
The solution to this problem should seem obvious based on the two simple detection methods just described. For the symbol hijacking method, you can simply look for two symbols that have the same value. In the example shown in the Phrack article, the init_module() function was hijacked, but the technique should apply to any function that the attacker wants to hijack. This is because the kernel handles relocations for each one (although I have not tested this theory):
$ objdump -t infected.lkm 00000040 g F .text 0000001b evil ... 00000040 g F .text 0000001b init_module
Notice in the preceding symbol output that init_module and evil have the same relative address. This—right here—is an infected LKM as demonstrated in Phrack 68 #11. Detecting functions hijacked with trampolines is also quite simple and was already described in section 9.6.3, where we discussed detecting trampolines in the kernel. Simply apply the same analysis to the functions in a LKM file, which can be disassembled with tools such as objdump.