· 9 years ago · Dec 06, 2016, 01:16 AM
1#include <linux/module.h> // For kernel modules
2#include <linux/kernel.h> // For printk's (KERN_WARNING, KERN_EMERG, KERN_INFO, etc.)
3#include <linux/init.h> // For __init and __exit macros (for kernel)
4#include <linux/unistd.h> // sys_call_table __NR_* system call function indices
5#include <linux/fs.h> // filp_open
6#include <linux/slab.h> // kmalloc
7#include <asm/paravirt.h> // write_cr0
8#include <asm/uaccess.h> // get_fs, set_fs
9#include "hooks.h"
10
11#include <linux/cred.h>
12
13//WRITE #INCLUDES
14#include <linux/syscalls.h>
15#include <linux/file.h>
16#include <linux/fcntl.h>
17
18
19#include <linux/delay.h> // for msleep()
20#include <linux/kthread.h> // for threads
21#include <linux/sched.h> // for task_struct
22
23#include <linux/time.h>
24#include <linux/proc_fs.h>
25#include <linux/seq_file.h>
26
27//Constants used to in hacking sys_call_table
28#define PROC_V "/proc/version"
29#define BOOT_PATH "/boot/System.map-"
30#define MAX_VERSION_LEN 256
31
32
33
34//Global Variables
35char* buffer[300]; //What we want to print
36int n = 1; //While Loop flag
37unsigned long *syscall_table = NULL; //for hacking syscall table
38int maxsize = 10; //Buffer size flag
39int nextmax = 10; //Buffer size flag increaser
40
41//Function Declarations
42 //Threads
43 void thread_startup(void);
44 void thread_cleanup(void);
45 static struct task_struct *thread1;
46 //Write
47 static void write_file(char*, char*);
48 //Hooking
49 void hack(void);
50 void unhack(void);
51 asmlinkage int (*original_execve)(unsigned int, const char __user *, size_t);
52 //Time
53 char *getTime(int);
54 char *toString(int);
55
56
57//Function info: Find The address of the sys_call_table()
58static int find_sys_call_table (char *kern_ver)
59{
60 char system_map_entry[MAX_VERSION_LEN];
61 int i = 0;
62
63 char *filename; //will hold "/boot/System.map-<version>"
64
65
66
67 //Length of the System.map filename
68 //(We include the " + 1" for the null termination char)
69 size_t filename_length = strlen(kern_ver) + strlen(BOOT_PATH) + 1;
70
71 struct file *f = NULL; //pointer to /boot/System.map-<version> file
72
73
74 //Allow kernel space references rather than just user-space
75 mm_segment_t oldfs;
76 oldfs = get_fs();
77 set_fs (KERNEL_DS);
78
79 printk(KERN_EMERG "Kernel version: %s\n", kern_ver);
80
81 //Dynamically allocate filename
82 filename = kmalloc(filename_length, GFP_KERNEL);
83 if (filename == NULL)
84 {
85 printk(KERN_EMERG "kmalloc failed on System.map-<version> filename allocation");
86 return -1;
87 }
88
89 memset(filename, 0, filename_length); //Error proof by clearing clean
90
91 strncpy(filename, BOOT_PATH, strlen(BOOT_PATH)); //Add BOOT_PATH
92 strncat(filename, kern_ver, strlen(kern_ver)); //add kernel version
93
94 //Open the System.map file
95 f = filp_open(filename, O_RDONLY, 0);
96 if (IS_ERR(f) || (f == NULL))
97 {
98 printk(KERN_EMERG "Error opening System.map-<version> file: %s\n", filename);
99 return -1;
100 }
101
102 memset(system_map_entry, 0, MAX_VERSION_LEN); //Fill string with 0s to avoid errors
103
104 //Read the file until:
105 // A: we fully fill up buffer
106 // B: we read a full line from the file
107 while (vfs_read(f, system_map_entry + i, 1, &f->f_pos) == 1) //WHAT!
108 {
109 //if we max out or if we hit an new line...
110 if ( system_map_entry[i] == '\n' || i == MAX_VERSION_LEN )
111 {
112 // Reset the "column" / "character" counter for the row
113 i = 0;
114
115 //if we finally find sys_call_table......
116 if (strstr(system_map_entry, "sys_call_table") != NULL)
117 {
118 char *sys_string;
119 char *system_map_entry_ptr = system_map_entry;
120 sys_string = kmalloc(MAX_VERSION_LEN, GFP_KERNEL);
121 if (sys_string == NULL)
122 {
123 filp_close(f, 0); //close file
124 set_fs(oldfs); // return old fs
125 kfree(filename); // free memory to avoid memory leaks
126 return -1;
127 }
128 memset(sys_string, 0, MAX_VERSION_LEN); //clear up sys_string
129 strncpy(sys_string, strsep(&system_map_entry_ptr, " "), MAX_VERSION_LEN); //Copy system_map_entry(only address) into sys_string
130 kstrtoul(sys_string, 16, &syscall_table); //turn hex address into unsigned long address and write into global syscall_table
131 printk(KERN_EMERG "syscall_table retrieved\n");
132 kfree(sys_string);
133 break;
134 }
135 memset(system_map_entry, 0, MAX_VERSION_LEN); //Set back to all zeros to avoid bugs
136 continue;
137 }
138 i++; //next byte
139 }
140
141 filp_close(f, 0); //close file
142 set_fs(oldfs); //return of oldfs
143 kfree(filename); //free memory to avoid leaks
144 return 0;
145}
146
147
148
149
150static void write_file(char *filename, char *data)
151{
152 struct file *file; //file we will use
153 loff_t pos = 0; //WHAT
154 int fd;
155
156 //Allow for kerenl space refrence, not just userspace
157 mm_segment_t oldfs;
158 oldfs = get_fs();
159 set_fs(get_ds());
160
161 //open file
162 //(filename, open for writing only | create if not exists, owner can read/write, others can just read)
163 file = filp_open(filename, O_WRONLY|O_CREAT, 0644);
164
165
166 if (file)
167 {
168 //(filename, data we want to write, length of data, position of where to write)
169 vfs_write(file, data, strlen(data), &pos);
170 fput(file);
171 }
172
173 filp_close(file, NULL); //Close file
174 set_fs(oldfs); //return to normal userspace only refrence
175}
176
177
178
179asmlinkage int new_execve (const char *filename, char *const argvu[], char *const envp[])
180{
181
182 //store data where the sbin/ file string should be
183 char sbin[5];
184 memcpy( sbin, &filename[5], 4);
185 sbin[4] = '\0';
186
187 //if the process is infact in sbin, it is a user application
188 if ( strcmp(sbin, "sbin") == 0 ){
189 int f_len;
190 f_len = strlen(filename);
191
192 int p_len = f_len-10;
193 char pname[p_len];
194
195 memcpy(pname, &filename[10], p_len); //only copy executable name ie, application name
196 pname[p_len] = '\0';
197
198 //Error check, a few common proccess that are also in sbin
199 if( (strcmp(pname, "grep") != 0) &&
200 (strcmp(pname, "asep") != 0) &&
201 (strcmp(pname, "make") != 0) &&
202 (strcmp(pname, "as") != 0) &&
203 (strcmp(pname, "uuid") != 0) &&
204 (strcmp(pname, "locate") != 0) &&
205 (strcmp(pname, "gnome-terminal") != 0) &&
206 (strcmp(pname, "dpk") != 0) )
207 {
208 printk(KERN_INFO "filename: %s\n", filename);
209 //append to global buffer
210 strcat(buffer, pname);
211 strcat(buffer, "\t");
212
213
214 //Produce Time
215 unsigned long get_time;
216 int sec, hr, min, tmp1,tmp2, tmp3;
217 struct timeval tv;
218 struct tm tv2;
219
220 do_gettimeofday(&tv);
221 get_time = tv.tv_sec;
222 sec = get_time % 60;
223 tmp1 = get_time / 60;
224 min = tmp1 % 60;
225 tmp2 = tmp1 / 60;
226 hr = (tmp2 % 24) - 4 - 1;
227 tmp3 = tv2.tm_year;
228 //set to our time zone
229
230
231 printk("hr: %d\n", hr);
232
233 char *smin[2];
234 char *shr[2];
235 strcpy(smin, getTime(min));
236 strcpy(shr, getTime(hr) );
237
238 strcat(buffer, shr);
239 strcat(buffer, ":");
240 strcat(buffer, smin);
241 strcat(buffer, "\n");
242
243
244 printk(KERN_EMERG "execve() hooked %s:[%s] U:[%u]\n", sbin, pname, get_current_user()->uid);
245
246 }
247 }
248
249 //return the original execve so it can preform normal function
250 return original_execve(filename, argvu, envp);
251}
252
253
254
255char *getTime(int number)
256{
257 printk(KERN_INFO "in getTime [Just in]\n");
258
259 int n = number;
260 int t = 0;
261
262 static char numString[2];
263
264 char ones[1];
265 char tens[1];
266 if (number > 10)
267 {
268 printk(KERN_INFO "number > 10\n");
269 while(n > 10)
270 {
271 n = n - 10;
272 t++;
273 }
274
275 strcpy(ones, toString(n));
276 strcpy(tens, toString(t));
277
278 }
279 else if (number == 10)
280 {
281 printk(KERN_INFO "number == 10\n");
282 strcpy(ones, "1");
283 strcpy(tens, "0");
284 }
285
286 else //(number < 10)
287 {
288 printk(KERN_INFO "number < 10\n");
289 strcpy(ones, toString(number));
290 strcpy(tens, "0");
291 }
292
293 strcat(numString, tens);
294 strcat(numString, ones);
295 numString[2] = '\0';
296
297 printk(KERN_INFO "FULL: %s\n", numString);
298
299 return numString;
300
301}
302
303char *toString(int num)
304{
305 static char str[1];
306 printk(KERN_INFO "in toString [Just in]\n");
307
308 if(num == 0){ strcpy(str, "0");}
309 else if(num == 1){ strcpy(str, "1");}
310 else if(num == 2){ strcpy(str, "2");}
311 else if(num == 3){ strcpy(str, "3");}
312 else if(num == 4){ strcpy(str, "4");}
313 else if(num == 5){ strcpy(str, "5");}
314 else if(num == 6){ strcpy(str, "6");}
315 else if(num == 7){ strcpy(str, "7");}
316 else if(num == 8){ strcpy(str, "8");}
317 else if(num == 9){ strcpy(str, "9");}
318
319 printk(KERN_INFO "in toString AFTER num:%d str:%s\n", num, str);
320 return str;
321}
322
323
324void hack(void)
325{
326 //hack syscalltable to writable
327 write_cr0 (read_cr0 () & (~ 0x10000)); //here we change the 16th CR0 address to Writ-able from Unwrite-able (bitmask logic)
328 //write in our new_execve() function
329 original_execve = (void *)syscall_table[__NR_execve]; // save original execve()
330 syscall_table[__NR_execve] = &new_execve; //put in the new one, redefining the system call number
331
332 //unhack syscalltable to not-writable
333 write_cr0 (read_cr0 () | 0x10000); //change it back to unwrite-able
334
335 printk(KERN_EMERG "[+] onload: sys_call_table hooked\n");
336}
337
338
339
340int thread_fn(void) {
341 printk(KERN_INFO "In thread\n");
342
343 while (n == 1)
344 {
345 //to avoid an over intense inifit loop we sleep every 30 seconds
346 msleep(30000);
347 printk(KERN_INFO "While Hit bufsize[%d] \n", strlen(buffer));
348
349 //print when buffer reaches set size
350 if (strlen(buffer) >= maxsize){
351 printk(KERN_INFO "In thread (if statment)");
352 write_file("/tmp/test.txt", buffer); //write
353 maxsize += nextmax; //increase buffer size for printing
354 }
355 if ( strlen(buffer) > 265 ){
356 buffer[0] = '/0';
357 }
358 }
359
360 return 0;
361}
362
363
364
365
366static int __init onload(void)
367{
368 thread_startup();
369
370 char *kv[16];
371 strcpy(kv, "4.4.0-31-generic");
372
373 printk(KERN_WARNING "Hello world!\n");
374 find_sys_call_table(kv);
375
376 //if (we actually got sys_call_table address)
377 if (syscall_table != NULL)
378 {
379 hack();
380
381 }
382 else
383 {
384 printk(KERN_EMERG "[-] onload: syscall_table is NULL\n");
385 }
386
387
388 return 0;
389}
390
391void unhack(void)
392{
393 write_cr0 (read_cr0 () & (~ 0x10000)); //here we change the 16th CR0 address to Writ-able from Unwrite-able (bitmaks logic)
394 syscall_table[__NR_execve] = original_execve; //redefine system call number back to the original defention of execve()
395 write_cr0 (read_cr0 () | 0x10000); //back to Unwrite-able
396 printk(KERN_EMERG "[+] onunload: sys_call_table unhooked\n");
397}
398
399void thread_startup(void){
400
401 char our_thread[15]="whileloopThread"; // Name the thread
402 printk(KERN_INFO "in thread_startup\n");
403 thread1 = kthread_create(thread_fn,NULL,our_thread); //form kernel thread (no need to transfer any data through)
404 if(thread1)
405 {
406 printk(KERN_INFO "in thread_startup (if)\n");
407 wake_up_process(thread1); //launch kernel thread
408 }
409
410}
411
412void thread_cleanup(void) {
413 n = 0; //end while loop of kernel thread
414 int ret;
415 ret = kthread_stop(thread1); //kill kernel thread
416 if(!ret)
417 printk(KERN_INFO "Thread stopped\n");
418}
419
420
421static void __exit onunload(void)
422{
423 thread_cleanup();
424
425 //if (we actually did any hacking in the first place)
426 if (syscall_table != NULL)
427 {
428 unhack();
429 }
430 else
431 {
432 printk(KERN_EMERG "[-] onunload: syscall_table is NULL\n");
433 }
434
435 printk(KERN_INFO "Goodbye world!\n");
436}
437
438module_init(onload);
439module_exit(onunload);