Bios Hacking
Version 1.3 July, 2004
If you have a motherboard with
unknown resistors before sensor chips, and you need correct computation
formula, this document is for you.
What you need
=============
1) to know assembly
2) Interactive disassembler (IDA)
3) Bios from that motherboard
4) Bios unpacker
1) yeah learn it first :)
2) You can get freeware version from simtelnet mirrors
ftp://ftp.simtel.net/pub/simtelnet/msdos/disasm/ida37fw.zip
Read some primers herehttp://fravia.anticrack.de/howtouse.htm
3) Get the bios and create the installation disk. Extract the bios
file, it will be biggest file round 300KB
4) bios unpacker, the bios image is compressed similar as Linux
(bzImage) you will need some utilities to decompress it back
For most common BIOSes you can get them from here:
http://www-user.tu-cottbus.de/~kannegv/programm/index_e.htm
Or here:
http://biosgfx.euro.ru/
http://biosgfx.euro.ru/download/
awardeco.arj 44668 Sun Dec 21 13:04:00 MET 2003
For example this one for AWARD modular bios.
What next
=========
Uncompress the bios image.
You will get like:
AWARDECO * V.K. * 2000.10.07..2003.12.21
Position packed C target type unpacked filename
-------- -------- ----- --------- --------------- -- --------------------
000C0000 0001021D -lh5- 5000:0000 System BIOS -> 00020000 original.tmp
000D0246 000037B2 -lh5- 4001:0000 CPU micro code -> 00004826 cpucode.exe
000D3A20 00003FEB -lh5- 6000:0000 -> 00007CD0 AWARDEXT.ROM
000D7A34 00003096 -lh5- A800:0000 -> 00004D3A FILE1.ROM
000DAAF0 0000078F -lh5- A000:0000 -> 00000F90 AWARDEYT.ROM
000DB2A8 00000279 -lh5- 4002:0000 EPA pattern -> 00000642 awardepa.epa
000DB54A 00000D01 -lh5- 4003:0000 ACPI table -> 000026DB ACPITBL.BIN
000DC273 00001293 -lh5- 4007:0000 Virus ROM -> 00001F65 cav_shdw.bin
000DD52F 00008C10 -lh5- 4011:0000 LOGO1 ROM -> 0000E000 ba4019m1.lom
000F2000 00001000 Deco F200:0000 => 00001000 r00F2000.dec
000FE000 00002000 Boot FE00:0000 => 00002000 r00FE000.dec
It will create the files with binary code of bios.
For phoenix bios, HW monitoring was found in "T" type module
PHOEDECO * V.K. * 1998.04.02..2003.11.02
dpl126.iwl
Position packed C unpacked type target filename
-------- -------- -- -------- ------------ -------- -- ------------
...
000E2EA5 00002D5D 05 00006710 T 00000000 -> r00E2EA5.DEC
...
For AMI BIOS I found HW monitoring code in "Setup Client" (type 4).
Now for each file use ndiasm (from NASM package) to create quickly
a assembly dump.
like this way. 16 bit code with autosync
nasm -b 16 -a original.tmp > original.asm
Sensor monitoring code will be most likely in "T" module for Phoenix
and in 128KB Award bios file (second half)
After that first you need is to know at least the IO address of the
chip if you are trying to find superIO ISA device. If you try to find
SMBus
device, you need find SMBUs adapter base address. Suppose now you, are
trying to figure out chip that is on ISA bus. Now try to grep for base
address value.
ruik@kiur:/var/lib/dosemu/freedos/aw/pc87366/asm$ grep 0xecd0 *
original.asm:00011013 BAD0EC mov dx,0xecd0
original.asm:00011025 BAD0EC mov dx,0xecd0
original.asm:0001EC6D 7761 ja 0xecd0
Looks good, it loads base address to register DX which is often used in
out dx,al (or in dx,al) instruction.
Please note sometimes is particular port address used. If the base is
0x600, voltages are for example at 0x620 and you know that bank switch
register is +9, it may happen that there will be 0x629.
ruik@kiur:/usr/lib/freedos/illwill/roms/sensors$ grep -A 3 0x629 *.asm
00001849 BA2906 mov dx,0x629
0000184C B001 mov al,0x1
0000184E EE out dx,al
0000184F E6ED out 0xed,al
Now if you know that the IO operations are performed in this module it
is time to start IDA. This disassembler will help you to find all
callers of the code that communicates with the chip.
Award bios image usually is 128KB long. Use dd command to split it to
two 64KB parts. Open IDA, open file p1.rom place it at E0000, load
another part p2.rom and place it at f0000. Now let work the
autoanalysis and
yourself. Try to discover as much code round the address of 1013 in
second segment as possible. Press keys c and u (c as mark as code, u
unmark) You can use n key to rename functions. After all you should get
something like that:
seg001:1012 inportplusbase proc near ; CODE XREF: readval+4
seg001:1012 ; readval+10.p readval+1A
seg001:1012 push dx
seg001:1013 mov dx, 0ECD0h
seg001:1016 jmp short loc_1000_1035
Now look at the datasheet to find how to communicate with the chip. Use
code XREF to see where is this code used.
seg001:0C93 mov cl, 9
seg001:0C95 mov al, 1
seg001:0C97 call outportplusbase
seg001:0C9A call readval
seg001:0C9D jmp computeexit
This reads the in1 but there is no reference to code. There is usually
a jumptable. Quite near this code. This function is very promising it
is used when doing voltage conversions:
seg001:0C52 push bx
seg001:0C53 push cx
seg001:0C54 push dx
seg001:0C55 call tablehash
seg001:0C58 mov ax, cs:[bx+0Ah]
seg001:0C5C or ax, ax
seg001:0C5E jz loc_1000_C7A
seg001:0C60 call ax
seg001:0C62 cbw ; expand 8 bit in AL to AX
seg001:0C63 mov cl, 10h
seg001:0C65 mul cl ; ;result in AX
seg001:0C67 mov cx, cs:[bx] ; use first constants
seg001:0C6A imul cx ; result in DX:AX
seg001:0C6C mov cx, cs:[bx+2] ; load div constant
seg001:0C70 idiv cx ; DX will be reminder
seg001:0C72 add ax, cs:[bx+4] ; add third constant to AX
seg001:0C76
seg001:0C76 loc_1000_C76: ; CODE XREF:
seg001:0C7D.j
seg001:0C76 pop dx
First a offset to some table is computed in tablehash. In table are
"pointers to function" (call ax) to read desired "in". Rest values in a
table are + * and / constants. Like this
seg001:0BCB sometable2 dw 1 ; imul
seg001:0BCD dw 1 ; idiv
seg001:0BCF dw 0 ; add
seg001:0BD1 dw 640h ; ???
seg001:0BD3 dw 73Ah ; ???
seg001:0BD5 in2 dw 0CA0h ; caller
The function that chooses right elements from a table:
seg001:0C41 tablehash proc near ; CODE XREF:
seg001:0C55
seg001:0C41 xor bx, bx
seg001:0C43 cmp ch, 6
seg001:0C46 jnb loc_1000_C4D ; jump if CH is equal or bigger
seg001:0C48 mov bl, ch
seg001:0C4A imul bx, 0Eh ; CH*0E
seg001:0C4D
seg001:0C4D loc_1000_C4D: ; CODE XREF:tablehash+5.j
seg001:0C4D add bx, 0BCBh ; add table start
seg001:0C51 retn
seg001:0C51 tablehash endp
As you can see the table begins at seg001:0BCB,
if it contains some code, use u to uncover it again, because its not
code but your dreamed table :) Rest is easy, follow the code from
readval, to see if there is some manipulation with it. (In computexit
is) Than use the constants from table in sensors.conf and you are done.
(hopefully) If there are thermistors you could also find the translate
table for them.
This code reads values from chip registers
seg001:0E95 mov cl, 9
seg001:0E97 mov al, 2
seg001:0E99 jmp short loc_1000_E9B
seg001:0E9B
seg001:0E9B loc_1000_E9B: ; CODE XREF:
seg001:0E8D
seg001:0E9B ; seg001:0E93.j
seg001:0E9B add al, 0Bh
seg001:0E9D call outportplusbase
seg001:0EA0 call readval
seg001:0EA3 call xlatsmth
seg001:0EA6 retn
Last function is interresting
seg001:0EC3 xlatsmth proc near ; CODE XREF:
seg001:0EA3
seg001:0EC3 mov si, 0EDEh
seg001:0EC6
seg001:0EC6 loc_1000_EC6: ; CODE XREF:xlatsmth+F.j
seg001:0EC6 cmp al, cs:[si]
seg001:0EC9 jnb loc_1000_ED4
seg001:0ECB add si, 2
seg001:0ECE cmp si, 0FBAh
seg001:0ED2 jb loc_1000_EC6
seg001:0ED4
seg001:0ED4 loc_1000_ED4: ; CODE XREF:xlatsmth+6.j
seg001:0ED4 xor ah, ah
seg001:0ED6 inc si
seg001:0ED7
seg001:0ED7 loc_1000_ED7:
seg001:0ED7 mov al, cs:[si]
seg001:0EDA cbw
seg001:0EDB
seg001:0EDB loc_1000_EDB:
seg001:0EDB shl ax, 1
seg001:0EDD retn
seg001:0EDD xlatsmth endp
It will use a table, located at 0xEDE.
Its format is in this case: val readed from chip, temp (1 byte) next
val readed from chip, other temp etc (1 byte)
seg001:0EDE somexlat db 0E4h ; ä
seg001:0EDF db 0F6h ; ö
seg001:0EE0 db 0E2h ; â
seg001:0EE1 db 0F7h ; ÷
seg001:0EE2 db 0E0h ; à
seg001:0EE3 db 0F8h ; ø
seg001:0EE4 db 0DEh ; Þ
seg001:0EE5 db 0F9h ; ù
etc
If you read E4 from register, temp is F6 which is -10C. You can draw
this in OpenOffice for example and dig a function for it then.
Final remarks
==============
If you are lucky, you can get this in one evening.
Sometimes IO ports aren't stored as here as immediate value but in
memory like this:
mov dx,cs:[something]
So you must check this type too. It may happen, that base address is
loaded to some other register. Use regular expressions to reduce your
search space. If it is smbus device you must find code in bios that
sends command data to SMBUS (it will be lot of it and not so easy to
find sensor related code)
Often despite base is for example 0x290, try to search for 0x295
(important address).
Good Luck.
Rudolf Marek
EOF
