I'm currently on the journey where I am learning more about Linux internals. This series of posts are meant to document my learning. As always, this allows me to fallback to my own materials when I need to refresh my memory. This first post is ... well .. Hello World :-)
While this first program is not a rootkit, it is meant to help me understand the basics of the Linux Kernel Modules (LKM). Without further ado, let's get going.
Key points:
1. Kernel Modules must have at least two functions. These are the initialization function and the cleanup function. The "__init" functions is what gets called when "insmod" command is executed. The cleanup function "__exit" is what gets executed when "rmmod" command is executed.
2. Every kernel module needs to include "linux/module.h" and "linux/init.h"
3. Need to include "linux/kernel.h" to use for example "printk()"
4. "printk()" is a logging mechanism for the kernel. Basically to give information, warnings, etc.
5. In practice when using the "printk", don't use the number representations. Instead use the macro such as KERN_INFO.
6. Kernel modules are compiled differently from user space apps
7. ".ko" files have a ".modinfo" section which contains additional information.
8. LKMs are loaded at runtime
9. LKMs are not loaded into user space and are thus essentially part of the kernel.
10. Initialization functions should always be declared as static as they are not meant to be visible outside the specific file.
10. Initialization functions should always be declared as static as they are not meant to be visible outside the specific file.
11. "module_init" is mandatory. It specifies where the initialization function is found.
12. The cleanup function "module_exit" unregisters interfaces and return resources to the system before the module is removed.
13. If the module does not define a cleanup function, the kernel does not allow it to be unloaded.
Let's now get going with the code for the kernel mode:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | kali@securitynik:~/rootkits/HelloWorld$ touch helloWorld.c kali@securitynik:~/rootkits/HelloWorld$ vi helloWorld.c kali@securitynik:~/rootkits/HelloWorld$ cat helloWorld.c /* * This is my first crack at writing a Linux Kernel Module (LKM) * Author: Nik Alleyne * Blog: www.securitynik.com * File: helloWorld.c */ // Let the system know we are part of the kernel // #define __KERNEL__ // Let the system know we are not a permanent part of the kernel // #define MODULE // init.h needed for entry and exit macros #include <linux/init.h> // Remember every module needs module linux/module.h #include <linux/module.h> // kernel.h is needed for printk() in this example #include <linux/kernel.h> // Specify the license information. License choice impacts the way the kernel treats your module. MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Nik Alleyne - www.securitynik.com"); MODULE_DESCRIPTION("My First Linux Kernel Module (LKM)"); MODULE_VERSION("0.1a"); // Setup the initialization module. Basically what the LKM does at startup static int __init hello_init(void) { printk(KERN_INFO "[*] ENTERING!! Welcome to SecurityNik LKM World! \n"); // Always return 0 to show success. // If a non-zero value is returned it more than likely means an error occurred while loading return 0; } // Setup the cleanup module. Basically what the LKM does upon exit static void __exit hello_exit(void) { printk(KERN_INFO "[*] LEAVING!! I've had enough of this. I'm leaving. See ya ...\n"); } // Now tell the system which module to load upon initialization module_init(hello_init); // Which module to call upon exit module_exit(hello_exit); /* * References: * https://elixir.bootlin.com/linux/latest/source/include/linux/module.h * https://elixir.bootlin.com/linux/latest/source/include/linux/kernel.h * https://elixir.bootlin.com/linux/latest/source/include/linux/printk.h * https://elixir.bootlin.com/linux/latest/source/include/linux/tty.h * */ |
To compile this code, we need a "Makefile". Below is my "Makefile"
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | # # This is the Makefile for my Linux Kernel Module (LKM) # Author: Nik Alleyne # Blog: www.securitynik.com # File: Makefile # # The following line is the only one which is truly required. # the file should match the name of the C file obj-m += helloWorld.o # # --directory (or the more used -C) - switches to the kernel directory before performing any make tasks # `uname --kernel-release` returns the current kernel version. Basically we are building against the current kernel. # M=$(PWD) - Tells the make command where the actual project file exists. This value represents the absolute path # modules - This is the default target. It is the same as if no target was specified # clean - Removes all generated files in the module directory only # # all: make --directory=/lib/modules/$(shell uname --kernel-release)/build/ M=$(PWD) modules clean: make --directory=/lib/modules/$(shell uname --kernel-release)/build/ M=$(PWD) clean # # Reference # http://www.tldp.org/LDP/lkmpg/2.6/html/x181.html # https://www.kernel.org/doc/Documentation/kbuild/modules.txt # |
Now that we have those two files, let's "make all".
1 2 3 4 5 6 7 8 9 | kali@securitynik:~/rootkits/HelloWorld$ make all make --directory=/lib/modules/5.5.0-kali2-amd64/build/ M=/home/kali/rootkits/HelloWorld modules make[1]: Entering directory '/usr/src/linux-headers-5.5.0-kali2-amd64' CC [M] /home/kali/rootkits/HelloWorld/helloWorld.o Building modules, stage 2. MODPOST 1 modules CC [M] /home/kali/rootkits/HelloWorld/helloWorld.mod.o LD [M] /home/kali/rootkits/HelloWorld/helloWorld.ko make[1]: Leaving directory '/usr/src/linux-headers-5.5.0-kali2-amd64' |
Looks like the "make" was successful. Let's confirm.
1 2 3 | kali@securitynik:~/rootkits/HelloWorld$ ls helloWorld.c helloWorld.mod helloWorld.mod.o Makefile Module.symvers helloWorld.ko helloWorld.mod.c helloWorld.o modules.order |
Most important file above for us is the "helloWorld.ko". Let's get some information on the module before installing.
1 2 3 4 5 6 7 8 9 10 11 | kali@securitynik:~/rootkits/HelloWorld$ sudo modinfo helloWorld.ko filename: /home/kali/rootkits/HelloWorld/helloWorld.ko version: 0.1a description: My First Linux Kernel Module (LKM) author: Nik Alleyne - www.securitynik.com license: GPL v2 srcversion: 8B4C656BD1E37221F0FBC7C depends: retpoline: Y name: helloWorld vermagic: 5.5.0-kali2-amd64 SMP mod_unload modversions |
Looks good! Let's perform a "dmesg --clear" before installing the module:
1 | kali@securitynik:~/rootkits/HelloWorld$ sudo dmesg --clear |
Let's now install our first LKM
1 | kali@securitynik:~/rootkits/HelloWorld$ sudo insmod helloWorld.ko |
Let's now confirm the module was properly installed by looking at our "dmesg" by using "dmesg --ctime".
1 2 | kali@securitynik:~/rootkits/HelloWorld$ sudo dmesg --ctime [Sat Jul 4 13:47:07 2020] [*] ENTERING!! Welcome to SecurityNik LKM World! |
Looks like it the module might have been installed properly. Let's look at the "/var/log/messages" file to get a different view of this message:
1 2 | kali@securitynik:~/rootkits/HelloWorld$ sudo tail --lines 1 /var/log/messages Jul 4 13:46:32 securitynik kernel: [86342.320847] [*] ENTERING!! Welcome to SecurityNik LKM World! |
Let's now finally confirm our module is installed by executing "lsmod"
1 2 3 4 | kali@securitynik:~/rootkits/HelloWorld$ lsmod Module Size Used by helloWorld 16384 0 .... |
Nice! Let's now uninstall the module via "sudo rmmod helloWorld".
1 | kali@securitynik:~/rootkits/HelloWorld$ sudo rmmod helloWorld |
Let's look at our "dmesg" again to see if the exit note was written.
1 2 3 | kali@securitynik:~/rootkits/HelloWorld$ sudo dmesg --ctime [Sat Jul 4 13:47:07 2020] [*] ENTERING!! Welcome to SecurityNik LKM World! [Sat Jul 4 13:51:52 2020] [*] LEAVING!! I've had enough of this. I'm leaving. See ya ... |
Looks good. Believe I have achieved my objectives in this post.
Let's execute "make clean" to remove the previously created files
1 2 3 4 5 | kali@securitynik:~/rootkits/HelloWorld$ make clean make --directory=/lib/modules/5.5.0-kali2-amd64/build/ M=/home/kali/rootkits/HelloWorld clean make[1]: Entering directory '/usr/src/linux-headers-5.5.0-kali2-amd64' CLEAN /home/kali/rootkits/HelloWorld/Module.symvers make[1]: Leaving directory '/usr/src/linux-headers-5.5.0-kali2-amd64' |
Let's now confirm only our original files exists.
1 2 | kali@securitynik:~/rootkits/HelloWorld$ ls helloWorld.c Makefile |
Nice! That's it for this post. See you in the next where I learn a bit more and go a bit deeper.
References:
Can you recommend books and resources to sharpen my skills on systems programming and kernel programming with C?
ReplyDelete