Advanced Award BIOS v4.51 PG Hacking

This tutorial is intended for people who already done some award bios modification before, and already knows the core component of award bios. In case you haven't done it or haven't know anything yet, you can read somewhere else. I've made tutorial called Preliminary Bios Modification Guide and Award BIOS structure. As the title said, what I'm going to explain here only apply exactly to Award Bios version 4.51PG. However, the principle of this modification can be applied to other bioses as well, provided that you have enough knowledge in assembly language and using disassembler. As usual, I didn't held any responsibility in the damage that may occur if you apply the steps explained here, proceed at your own risk, you have been warned. I'd like to thank to Petr Soucek for his inspiring tutorial, Gigabyte ga586hx bios modification. I'm indebted to him for opening my eyes about what could possibly be done to the award bios file. Thanks Petr :-).

Hacking Steps Summary

OK, let's get down to the business. I'm using Iwill VD133 (the slot 1 version) mainboard as my testbed. This mainboard uses award bios version 4.51PG dated 28 July 2000. In this article I'll explain how to do "bios code injection", i.e. injecting our patch into original.tmp (system bios) file. The area in original.tmp that we are going to inject with code is somewhere around memory test area code which is part of the POST (Power On Self Test). This area is right above the area which handles hdd initialization as described by Petr in his article. We will need these software tools:

Now we are armed with the right tools. What we need to do next are summarised below :

Details on how these are accomplished will be explained in the next sections, so read on :-).

Hacking Steps in Detail

WARNING: The explanations in this section remain valid, however, there is stability issue with this approach in my testbed. Read more about this issue here. In conjuction with the issue, I strongly recommend you to read this section first before proceeding, since it contains fundamental tricks that are used throughout this article.

1. Extracting original.tmp

This step is very easy if you have the right tool. I accomplish this step by using award bios editor v1.0 program which is created by Mike Tedder a.k.a bpoint. Credit goes to him for providing us with this excellent tool :-). But be warned that it may still have some issue when used with award bios version 6.0PG.

I just do some clicking on the related menus to do this. Here how it's done: select the system bios item in the tree on the left then open up action menu then select Extract File menu and proceed at your will. Be sure to place builtins.dll in the same directory as awdbedit.exe. We need this since upon starting, awdbedit scans the directory in which it's located for plugin. builtins.dll is the main plugin which provided the capability to recognize core (and some extended) award bios components, such as original.tmp, the epa file, etc. Note that the awdbedit that I'm using already been compiled several times and undergone some cosmetic patches, since the version from sourceforge site uses "annoying size" fonts which displays horrible in my small CRT monitor. Below is the screenshot of award bios editor that I'm using:

2. Disassembling original.tmp

This step is tricky. It depends a lot in your skill and experience in using assembly language and disassembler, however I'm going to share some tricks that I gained during my journey through patching my bios.

Open up the extracted original.tmp from previous step in your hexeditor, then examine it. Here's a snapshot from Hexworkshop that I'm using:

Address  Hexadecimal values                                Ascii representation 

00000000 4273 4704 00E0 00F0 0060 0040 0000 0000 1130 2A30 BsG......`.@.....0*0 

00000014 4330 5C30 080B 0C02 4465 7465 6374 696E 6720 4944 C0\0....Detecting ID 

00000028 4520 5072 696D 6172 7920 4D61 7374 6572 2020 2E2E E Primary Master  .. 

0000003C 2E20 5B50 7265 7373 2006 4634 0820 746F 2073 6B69 . [Press .F4. to ski 

00000050 705D 2000 0813 1320 2020 2020 2020 2020 2020 2020 p] ....              

00000064 2020 2020 2013 1200 536B 6970 2000 4E6F 6E65 2000      ...Skip .None . 

00000078 1327 5072 696D 6172 7920 536C 6176 6520 2020 0C16 .'Primary Slave   .. 

0000008C 2000 1327 5365 636F 6E64 6172 7920 4D61 7374 6572  ..'Secondary Master 

000000A0 0C16 2000 1327 5365 636F 6E64 6172 7920 536C 6176 .. ..'Secondary Slav 

000000B4 6520 0C16 2000 080B 466F 756E 6420 4344 524F 4D20 e .. ...Found CDROM  

000000C8 3A20 0008 0B46 6F75 6E64 2041 5441 5049 2044 6576 : ...Found ATAPI Dev 

000000DC 6963 6520 3A20 001E 060F A866 B8FF FFFF FF66 8986 ice : .....f.....f.. 

000000F0 E901 6689 8604 0266 33C0 6689 86D7 01C6 86D6 0130 ..f....f3.f........0 

00000104 8886 F301 6689 8600 0288 86FF 0188 865A 0168 00F0 ....f..........Z.h.. 

00000118 0FA9 B840 008E D8B8 0100 8EC0 8D06 59EC 26A3 F000 ...@..........Y.&... 

0000012C 8026 B600 FBBE 942F E847 6B0A C074 0580 0EB6 0004 .&...../.Gk..t...... 

00000140 C606 7500 0080 A6E1 01F0 C606 B500 008A 4612 C0E8 ..u.............F... 

00000154 040A C074 3C3C 0F75 3480 7E19 2F75 2E80 BE82 0006 ...t<<.u4.~./u...... 

00000168 7305 C686 8200 06BB C276 66C1 EE10 808E E101 01E8 s........vf......... 

0000017C 4D08 7207 F686 E401 0174 0A80 4E12 F0C6 4619 2FEB M.r......t..N...F./. 

00000190 04FE 0675 008A 4612 240F 7503 EB43 903C 0F75 2C80 ...u..F.$.u..C.<.u,. 

000001A4 7E1A 2F75 26BB 8A77 8D36 7800 66C1 E610 808E E101 ~./u&..w.6x.f....... 

000001B8 02E8 0F08 7207 F686 E401 0274 0A80 4E12 0FC6 461A ....r......t..N...F. 

000001CC 2FEB 128A 0E75 00D0 E1B0 01D2 E008 06B5 00FE 0675 /....u.............u 

000001E0 0080 7E67 0074 3A80 7E67 2F75 22BB 5278 8D36 8E00 ..~g.t:.~g/u".Rx.6.. 

000001F4 66C1 E610 808E E101 04E8 CB07 7207 F686 E401 0474 f...........r......t 

00000208 06C6 4667 2FEB 128A 0E75 00D0 E1B0 02D2 E008 06B5 ..Fg/....u.......... 

0000021C 00FE 0675 0080 7E70 0074 3A80 7E70 2F75 22BB 1A79 ...u..~p.t:.~p/u"..y 

00000230 8D36 A400 66C1 E610 808E E101 08E8 8B07 7207 F686 .6..f...........r... 

00000244 E401 0874 06C6 4670 2FEB 128A 0E75 00D0 E1B0 03D2 ...t..Fp/....u...... 

00000258 E008 06B5 00FE 0675 0060 33D2 8AC2 2403 0FB6 F081 .......u.`3...$..... 

0000026C C6E9 01F6 C202 750B F686 D601 1074 1CB4 10EB 09F6 ......u......t...... 

00000280 86D6 0120 7411 B420 803A FF74 0A80 3A02 7605 C602 ... t.. .:.t..:.v... 

00000294 020A F480 FA03 7404 FEC2 EBC4 8A86 D601 24CF 0AC6 ......t.........$... 

000002A8 8886 D601 61E8 FF0D FFB6 E901 FFB6 EB01 FFB6 D701 ....a............... 

000002BC FFB6 D901 8B86 0802 8D36 15F0 E863 6DE8 4511 B800 .........6...cm.E...

To successfully disassemble this file we need some common sense and intelligent guesses. I used this guide :

Based on the guide above, we disassemble original.tmp using ndisasmw.exe. Since I was bored enough to type such a massive command in the command line, we are going to use a windows batch file as follows :

@echo off

ndisasmw.exe -b16 -k 0,0xE3 -k 0x106A,0x3F -k 0x2E76,0xA -k 0x2F2F,0x16 -k 0x328D,0x2B -k 0x43E0,0x360

-k 0x5D5D,0x52 -k 0x7063,0x33 sys_part.bin >> sys_part.txt

Address   Binary Code       Mnemonic 

00000000  skipping 0xE3 bytes 

000000E3  1E                push ds 

000000E4  06                push es 

000000E5  0FA8              push gs 

000000E7  66B8FFFFFFFF      mov eax,0xffffffff 

000000ED  668986E901        mov [bp+0x1e9],eax 

000000F2  6689860402        mov [bp+0x204],eax 

000000F7  6633C0            xor eax,eax 

000000FA  668986D701        mov [bp+0x1d7],eax 

000000FF  C686D60130        mov byte [bp+0x1d6],0x30 

00000104  8886F301          mov [bp+0x1f3],al 

00000108  6689860002        mov [bp+0x200],eax 

0000010D  8886FF01          mov [bp+0x1ff],al 

00000111  88865A01          mov [bp+0x15a],al 

00000115  6800F0            push word 0xf000 

00000118  0FA9              pop gs ........ 

00000D73  E85A03            call 0x10d0 

00000D76  268B05            mov ax,[es:di] 

00000D79  3DFFFF            cmp ax,0xffff 

00000D7C  0F84C702          jz near 0x1047 

00000D80  8904              mov [si],ax 

00000D82  268B4502          mov ax,[es:di+0x2] 

00000D86  268A7506          mov dh,[es:di+0x6] 

00000D8A  268A550C          mov dl,[es:di+0xc] 

00000D8E  26F6450180        test byte [es:di+0x1],0x80 

00000D93  7549              jnz 0xdde

00000D95  26F6456302        test byte [es:di+0x63],0x2 

00000D9A  7442              jz 0xdde 

00000D9C  2666837D7800      cmp dword [es:di+0x78],byte +0x0 

00000DA2  743A              jz 0xdde 

00000DA4  2666837D78FF      cmp dword [es:di+0x78],byte -0x1 

00000DAA  7432              jz 0xdde 

00000DAC  26817D7A0050      cmp word [es:di+0x7a],0x5000 

00000DB2  772A              ja 0xdde 

00000DB4  26817D7AF003      cmp word [es:di+0x7a],0x3f0 

00000DBA  7202              jc 0xdbe 

00000DBC  B2FF              mov dl,0xff 

00000DBE  52                push dx 

00000DBF  8AC6              mov al,dh 

00000DC1  F6E2              mul dl 

00000DC3  660FB7C8          movzx ecx,ax 

00000DC7  26668B4578        mov eax,[es:di+0x78] 

00000DCC  6633D2            xor edx,edx 

00000DCF  66F7F1            div ecx 

00000DD2  663D00000100      cmp eax,0x10000 

00000DD8  7203              jc 0xddd 

00000DDA  B8FFFF            mov ax,0xffff 

00000DDD  5A                pop dx 

00000DDE  894402            mov [si+0x2],ax 

00000DE1  887404            mov [si+0x4],dh 

00000DE4  885410            mov [si+0x10],dl 

00000DE7  268A455E          mov al,[es:di+0x5e] 

00000DEB  BA4000            mov dx,0x40 

00000DEE  8EDA              mov ds,dx 

00000DF0  5A                pop dx ........

3. Building and Injecting Code into original.tmp

Here's our plan :

Now we have the plan, but before proceeding further we have to take care some cautions. Note that sys_patch.asm are assembled using masm615 with LINK version 5.60.339. We have to take some protective measure to protect ourself against bad code as follows:

Then we proceed to search for the code to replace. Petr Soucek in his article points out about the hdd initialization routine, we are going to place our code just above that code. The disassembly result of my bios around that code as follows:

Address   Binary Code       Mnemonic 

...... 

00000D76  268B05            mov ax,[es:di] 

00000D79  3DFFFF            cmp ax,0xffff -- this is where we're going to place the call to our code  

00000D7C  0F84C702          jz near 0x1047 

00000D80  8904              mov [si],ax 

00000D82  268B4502          mov ax,[es:di+0x2] 

00000D86  268A7506          mov dh,[es:di+0x6] 

00000D8A  268A550C          mov dl,[es:di+0xc] 

00000D8E  26F6450180        test byte [es:di+0x1],0x80 

00000D93  7549              jnz 0xdde 

00000D95  26F6456302        test byte [es:di+0x63],0x2 

00000D9A  7442              jz 0xdde 

00000D9C  2666837D7800      cmp dword [es:di+0x78],byte +0x0 

00000DA2  743A              jz 0xdde 

00000DA4  2666837D78FF      cmp dword [es:di+0x78],byte -0x1 

00000DAA  7432              jz 0xdde 

00000DAC  26817D7A0050      cmp word [es:di+0x7a],0x5000 

00000DB2  772A              ja 0xdde 

00000DB4  26817D7AF003      cmp word [es:di+0x7a],0x3f0 

00000DBA  7202              jc 0xdbe 

00000DBC  B2FF              mov dl,0xff 

00000DBE  52                push dx 

00000DBF  8AC6              mov al,dh 

00000DC1  F6E2              mul dl 

00000DC3  660FB7C8          movzx ecx,ax 

00000DC7  26668B4578        mov eax,[es:di+0x78] 

00000DCC  6633D2            xor edx,edx 

00000DCF  66F7F1            div ecx 

00000DD2  663D00000100      cmp eax,0x10000 

00000DD8  7203              jc 0xddd 

00000DDA  B8FFFF            mov ax,0xffff 

00000DDD  5A                pop dx ........

Then proceed to look where we can place our injected code. In my case, I found the suitable area beginning at EFF0h. The following is the hex dump of my original.tmp around that area :

Address  Hexadecimal values                                Ascii representation 

........ 

0000EFC4 68CF EF68 8854 EA88 6100 E0C3 C300 0000 0000 0000 h..h.T..a........... 

0000EFD8 0000 0000 0000 0000 C300 0000 0000 0000 0000 0000 .................... 

0000EFEC 0000 0000 FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF ....................

0000F000 FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF ....................

0000F014 FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF ....................

0000F028 FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF ....................

0000F03C FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF ....................

0000F050 FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF ....................

0000F064 FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF ....................

0000F078 FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF ....................

0000F08C FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF ....................

0000F0A0 FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF ....................

........

As you can see, these are just padding bytes. The FFh bytes continues until FFFFh address. So, I'll just place my code beginning at EFF0h.

Now we proceed to build our injected code. Here's the listing of my code :

; ------------------- sys_patch.asm ---------------------------------------------------

.486p

CSEG    SEGMENT PARA PUBLIC USE16 'CODE'

       ASSUME CS:CSEG

       ORG 0

; equates, have been tested and works fine

       in_port    equ 0cf8h

       out_port   equ 0cfch

       ioq_mask   equ 00000080h

       ioq_reg    equ 80000050h

       bank_mask  equ 20000844h

       bank_reg   equ 80000068h

       tlb_mask   equ 00000008h

       tlb_reg    equ 8000006ch

       dram_mask  equ 00020202h

       dram_reg   equ 80000064h

INIT    PROC    NEAR

; save all register that will be affected by our code

       push eax

       push ebx

       push edx

       pushfd

; patch the ioq reg

       mov eax,ioq_reg

       mov ebx,ioq_mask

       call PATCH_PCI

; patch the DRAM controller, i.e. the interleaving part

       mov eax,dram_reg

       mov ebx,dram_mask

       call PATCH_PCI

; patch bank active page ctl reg

       mov eax,bank_reg

       mov ebx,bank_mask

       call PATCH_PCI

; Activate Fast TLB lookup

       mov eax,tlb_reg

       mov ebx,tlb_mask

       call PATCH_PCI

; restore register contents and call the replaced instruction prior to return

       popfd

       pop edx

       pop ebx

       pop eax 

       cmp ax,0ffffh 

; This is the instruction that we replace in the POST code

          ret    

; return and proceed to the next initialization code

          INIT    ENDP          PATCH_PCI PROC NEAR         

; The register address is passed via EAX register         

; The mask value is passed via EBX register

         mov dx,0cf8h 

; fetch the input port addr of PCI cfg space

         out dx,eax

         mov dx,0cfch

          in  eax,dx

         or  eax,ebx  

; mask the regs value (activate certain bits)

         out dx,eax

         ret          

; return to initialization code above PATCH_PCI

       ENDP  

CSEG    ENDS

                     END               

; -------------------------- END OF sys_patch.asm -------------------------------------------

There are some things that we have to note here. First, every branching instruction is a near branching instruction which uses relative address. Second, we are telling the assembler to emit 16 bits code. Third,we preserve all the register status during our injected code execution, I've been bitten by forgetting to preserve dx register during my code injection experiment, I learn a lot from it :-). The resulting binary from the code above as follows:

Address  Hexadecimal values                                Ascii representation 

00000000 6650 6653 6652 669C 66B8 5000 0080 66BB 8000 0000 fPfSfRf.f.P...f..... 

00000014 E839 0066 B864 0000 8066 BB02 0202 00E8 2A00 66B8 .9.f.d...f......*.f. 

00000028 6800 0080 66BB 4408 0020 E81B 0066 B86C 0000 8066 h...f.D.. ...f.l...f 

0000003C BB08 0000 00E8 0C00 669D 665A 665B 6658 83F8 FFC3 ........f.fZf[fX....

00000050 BAF8 0C66 EFBA FC0C 66ED 660B C366 EFC3           ...f....f.f..f..

The disassembly of this binary using " ndisasmw.exe -b16 sys_patch.com > sys_patch.txt " as follows:

Address   Binary Code       Mnemonic 

00000000  6650              push eax 

00000002  6653              push ebx 

00000004  6652              push edx 

00000006  669C              pushfd 

00000008  66B850000080      mov eax,0x80000050 

0000000E  66BB80000000      mov ebx,0x80 

00000014  E83900            call 0x50 

00000017  66B864000080      mov eax,0x80000064 

0000001D  66BB02020200      mov ebx,0x20202 

00000023  E82A00            call 0x50 

00000026  66B868000080      mov eax,0x80000068 

0000002C  66BB44080020      mov ebx,0x20000844 

00000032  E81B00            call 0x50 

00000035  66B86C000080      mov eax,0x8000006c 

0000003B  66BB08000000      mov ebx,0x8 

00000041  E80C00            call 0x50 

00000044  669D              popfd 

00000046  665A              pop edx 

00000048  665B              pop ebx 

0000004A  6658              pop eax 

0000004C  83F8FF            cmp ax,byte -0x1  --- This isn't what expected :-( 

0000004F  C3                ret 

00000050  BAF80C            mov dx,0xcf8 

00000053  66EF              out dx,eax 

00000055  BAFC0C            mov dx,0xcfc 

00000058  66ED              in eax,dx 

0000005A  660BC3            or eax,ebx 

0000005D  66EF              out dx,eax 

0000005F  C3                ret

Looking at the resulting binary and its disassembly result, we know that we need to replace the code that is not supposed to be like that by using hex editor. But we have to ensure that the amount of bytes we are replacing is the same with the assembled version, if not, then all the branching instruction will be screwed up :-(. Fortunately we have 3 bytes to be replaced with also 3 bytes instruction, so this shouldn't be a problem. Now, we replace the 83 F8 FF bytes with 3D FF FF bytes which is the "correct instruction" based on what our previous bios code does. The resulting hex dump and disassembly as follows :

Hexdump:

Address  Hexadecimal values                                Ascii representation 

00000000 6650 6653 6652 669C 66B8 5000 0080 66BB 8000 0000 fPfSfRf.f.P...f..... 

00000014 E839 0066 B864 0000 8066 BB02 0202 00E8 2A00 66B8 .9.f.d...f......*.f. 

00000028 6800 0080 66BB 4408 0020 E81B 0066 B86C 0000 8066 h...f.D.. ...f.l...f 

0000003C BB08 0000 00E8 0C00 669D 665A 665B 6658 3DFF FFC3 ........f.fZf[fX=...

00000050 BAF8 0C66 EFBA FC0C 66ED 660B C366 EFC3           ...f....f.f..f..

Disassembly:

Address   Binary Code       Mnemonic 

00000000  6650              push eax 

00000002  6653              push ebx 

00000004  6652              push edx 

00000006  669C              pushfd 

00000008  66B850000080      mov eax,0x80000050 

0000000E  66BB80000000      mov ebx,0x80 

00000014  E83900            call 0x50 

00000017  66B864000080      mov eax,0x80000064 

0000001D  66BB02020200      mov ebx,0x20202 

00000023  E82A00            call 0x50 

00000026  66B868000080      mov eax,0x80000068 

0000002C  66BB44080020      mov ebx,0x20000844 

00000032  E81B00            call 0x50 

00000035  66B86C000080      mov eax,0x8000006c 

0000003B  66BB08000000      mov ebx,0x8 

00000041  E80C00            call 0x50 

00000044  669D              popfd 

00000046  665A              pop edx 

00000048  665B              pop ebx 

0000004A  6658              pop eax 

0000004C  3DFFFF            cmp ax,0xffff    --- This is what we expected :-)  

0000004F  C3                ret 

00000050  BAF80C            mov dx,0xcf8 

00000053  66EF              out dx,eax 

00000055  BAFC0C            mov dx,0xcfc 

00000058  66ED              in eax,dx 

0000005A  660BC3            or eax,ebx 

0000005D  66EF              out dx,eax 

0000005F  C3                ret

Then we proceed to inject our code into the area that we mentioned above. It's very easy, just paste our binary into that area using a hex editor. But before that, be sure to remove the same amount of FFh bytes in that area as the size of our binary, in my case, this is 60h bytes. Here's the resulting hex dump :

Address  Hexadecimal values                                Ascii representation 

........ 

0000EFB0 00B4 20B0 10E8 00DF B002 E81A E466 5B07 1FF8 C30E .. ..........f[..... 

0000EFC4 68CF EF68 8854 EA88 6100 E0C3 C300 0000 0000 0000 h..h.T..a........... 

0000EFD8 0000 0000 0000 0000 C300 0000 0000 0000 0000 0000 .................... 

0000EFEC 0000 0000 6650 6653 6652 669C 66B8 5000 0080 66BB ....fPfSfRf.f.P...f.

0000F000 8000 0000 E839 0066 B864 0000 8066 BB02 0202 00E8 .....9.f.d...f......

0000F014 2A00 66B8 6800 0080 66BB 4408 0020 E81B 0066 B86C *.f.h...f.D.. ...f.l

0000F028 0000 8066 BB08 0000 00E8 0C00 669D 665A 665B 6658 ...f........f.fZf[fX

0000F03C 3DFF FFC3 BAF8 0C66 EFBA FC0C 66ED 660B C366 EFC3 =......f....f.f..f..

0000F050 FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF ....................

0000F064 FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF ....................

........

Now, as our last step in this section is replacing the original code with a call into our injected code.

First, we have to calculate the intrasegment distance as follows :

distance = EFF0h - D7Ch

distance = E274h

Second, we make the binary for the call instruction. That would be: E8 74 E2 , the distance value is reversed, since intel x86 uses little endian scheme. Note that call instruction distance is calculated relative to the next instruction after the call instruction itself, that's why we are using D7Ch above, not D79h, keep this in mind.

Third, replace the code in address D79h with our code, i.e. E8 74 E2 using our hex editor. The resulting disassembly after replacing that code will be :

Address   Binary Code       Mnemonic 

........ 

00000D73  E85A03            call 0x10d0 

00000D76  268B05            mov ax,[es:di] 

00000D79  E874E2            call 0xeff0  

00000D7C  0F84C702          jz near 0x1047 

00000D80  8904              mov [si],ax 

00000D82  268B4502          mov ax,[es:di+0x2] 

00000D86  268A7506          mov dh,[es:di+0x6] 

00000D8A  268A550C          mov dl,[es:di+0xc] 

00000D8E  26F6450180        test byte [es:di+0x1],0x80 

00000D93  7549              jnz 0xdde ........

Well, now we have done what we want to original.tmp, this completed our steps in this section.

4. Replacing the Old original.tmp

For me, this is just a trivial task. I just open up award bios editor and then select the system bios item in the left, then choose replace file from menu to replace the original.tmp with my modified version of original.tmp. Eventhough this step seems to be very easy, there is a catch however. Read the next section for explanation in this issue.

5. Finishing Touches

Award bios editor seems still have some issue with award bios v4.51PG checksum. In my case, if I use different name than original.tmp as the name for the modified original.tmp file, award bios editor didn't complain,so does modbin and cbrom. But in fact, there are still wrong checksum in the resulting bios file (after its orignal.tmp replaced with the modified one). This is what I experienced : after successfully flashing the bios into my mainboard, the board boot, but it complains about wrong bios checksum and only booted into the award boot block bios. This issue can be fixed by opening and modifying our modded bios in modbin, and after that saving our changes into the corresponding bios file. I accomplish this by changing the bios name string and then saving my changes into the bios file using modbin v4.50.80C. After flashing the bios into my motherboard everything works as expected. Beside what I've said, I strongly recommend you to try running cbrom and modbin in your resulting modified bios file to ensure that it is a valid bios file before flashing it into your mainboard.

A More Radical original.tmp Hacking

WARNING : The explanations in this section remain valid, however there is stability issue with this approach in my testbed. Read more about it here.

The modification that we are going to do in this part is similar to what described above, in Hacking Steps in Detail. The difference is in the part of the original bios code (original.tmp) that we are going to replace with a call into our code. This hack also will incorporate some complexities of the call instruction itself. I will only highlights the differences here, I'm not going to repeat what I've explained above.

We proceed through the steps mentioned above until we arrive at Disassembling original.tmp. In this step, the code spot where we are going to place our call into the injected routine is around 2A0h. I'm not so sure what this area of code doing, but one thing for sure, this is still part of the POST code area. Below is the disassembly of this part in my bios :


Address   Binary Code       Mnemonic 

........ 

000002AC  61                popa 

000002AD  E8FF0D            call 0x10af  

000002B0  FFB6E901          push word [bp+0x1e9] 

000002B4  FFB6EB01          push word [bp+0x1eb] 

000002B8  FFB6D701          push word [bp+0x1d7] 

000002BC  FFB6D901          push word [bp+0x1d9] 

000002C0  8B860802          mov ax,[bp+0x208] 

000002C4  8D3615F0          lea si,[0xf015] 

000002C8  E8636D            call 0x702e  

00002CB  E84511            call 0x1413  

000002CE  B800ED            mov ax,0xed00 

000002D1  26A3C801          mov [es:0x1c8],ax 

000002D5  26C706CA0100F0    mov word [es:0x1ca],0xf000 

000002DC  B824ED            mov ax,0xed24 

000002DF  26A3CC01          mov [es:0x1cc],ax 

000002E3  26C706CE0100F0    mov word [es:0x1ce],0xf000 

000002EA  E8FC0F            call 0x12e9   -- insert a call to our code here  

000002ED  C606C60000        mov byte [0xc6],0x0 

000002F2  F686E4010F        test byte [bp+0x1e4],0xf 

000002F7  7441              jz 0x33a 

000002F9  8A86E401          mov al,[bp+0x1e4] 

000002FD  32E4              xor ah,ah 

000002FF  8A0EEA00          mov cl,[0xea] 

00000303  8AE9              mov ch,cl 

00000305  80E103            and cl,0x3 ........

The majority of the code that we are going to inject is still the same. Only one different, we are substituting the cmp ax,0ffffh code with a call instruction like what is highlighted in the disassembly result above, but we need some trick to achieve that. The listing as follows :

; ------------------- sys_patch.asm ---------------------------------------------------

.486p

CSEG    SEGMENT PARA PUBLIC USE16 'CODE'

       ASSUME CS:CSEG

       ORG 0

; equates, have been tested and works fine

       in_port   equ 0cf8h

       out_port  equ 0cfch

       ioq_mask  equ 00000080h

       ioq_reg   equ 80000050h

       bank_mask equ 20000844h

       bank_reg  equ 80000068h

       tlb_mask  equ 00000008h

       tlb_reg   equ 8000006ch

       dram_mask equ 00020202h

       dram_reg  equ 80000064h

INIT    PROC    NEAR

; save all register that will be affected by our code

       push eax

       push ebx

       push edx

       pushfd

; patch the ioq reg

       mov eax,ioq_reg

       mov ebx,ioq_mask

       call PATCH_PCI

; patch the DRAM controller, i.e. the interleaving part

       mov eax,dram_reg

       mov ebx,dram_mask

       call PATCH_PCI

; patch bank active page ctl reg

       mov eax,bank_reg

       mov ebx,bank_mask

       call PATCH_PCI

; Activate Fast TLB lookup

       mov eax,tlb_reg

       mov ebx,tlb_mask

       call PATCH_PCI

; restore register contents and call the replaced instruction prior to return

       popfd

       pop edx

       pop ebx

       pop eax

 call PATCH_PCI ; !!!WARNING!!!Replace the target of this call with the default from the real bios

          ret            ; return to instruction after the code that we replace in system bios

INIT    ENDP


PATCH_PCI PROC NEAR

; The register address is passed via EAX register         

; The mask value is passed via EBX register

         mov     dx,0cf8h  ; fetch the input port addr of PCI cfg space

         out     dx,eax

         mov     dx,0cfch

          in      eax,dx

         or      eax,ebx   ; mask the regs value (activate certain bits)

         out     dx,eax

         ret                ; return to initialization code above

PATCH_PCI       ENDP

  CSEG    ENDS

                     END               

; -------------------------- END OF sys_patch.asm -------------------------------------------

as you can see from the code highlighted above, we are placing a "dummy call" there so that the assembler can assemble our code. If we don't do so, it will complain and say that we are calling non-existent routine. We are going to replace the target of that call instruction manually by using hex editor. The resulting binary and its disassembly as follows :

Hex dump :

Address  Hexadecimal values                                Ascii representation

00000000 6650 6653 6652 669C 66B8 5000 0080 66BB 8000 0000 fPfSfRf.f.P...f..... 

00000014 E839 0066 B864 0000 8066 BB02 0202 00E8 2A00 66B8 .9.f.d...f......*.f. 

00000028 6800 0080 66BB 4408 0020 E81B 0066 B86C 0000 8066 h...f.D.. ...f.l...f 

0000003C BB08 0000 00E8 0C00 669D 665A 665B 6658 E801 00C3 ........f.fZf[fX....

00000050 BAF8 0C66 EFBA FC0C 66ED 660B C366 EFC3           ...f....f.f..f..

Disassembly result :

Address   Binary Code       Mnemonic 

00000000  6650              push eax 

00000002  6653              push ebx 

00000004  6652              push edx 

00000006  669C              pushfd 

00000008  66B850000080      mov eax,0x80000050 

0000000E  66BB80000000      mov ebx,0x80 

00000014  E83900            call 0x50 

00000017  66B864000080      mov eax,0x80000064 

0000001D  66BB02020200      mov ebx,0x20202 

00000023  E82A00            call 0x50 

00000026  66B868000080      mov eax,0x80000068 

0000002C  66BB44080020      mov ebx,0x20000844 

00000032  E81B00            call 0x50 

00000035  66B86C000080      mov eax,0x8000006c 

0000003B  66BB08000000      mov ebx,0x8 

00000041  E80C00            call 0x50 

00000044  669D              popfd 

00000046  665A              pop edx 

00000048  665B              pop ebx 

0000004A  6658              pop eax 

0000004C  E80100            call 0x50 --- this is where we need to patch manually 

0000004F  C3                ret 

00000050  BAF80C            mov dx,0xcf8 

00000053  66EF              out dx,eax 

00000055  BAFC0C            mov dx,0xcfc 

00000058  66ED              in eax,dx 

0000005A  660BC3            or eax,ebx 

0000005D  66EF              out dx,eax 

0000005F  C3                ret

Now, we only need to insert our code into EFF0h and then do some "address fixups". This is tricky step . I accomplish it as follows :

Address  Hexadecimal values                                Ascii representation 

........ 

0000EFD8 0000 0000 0000 0000 C300 0000 0000 0000 0000 0000 .................... 

0000EFEC 0000 0000 6650 6653 6652 669C 66B8 5000 0080 66BB ....fPfSfRf.f.P...f. 

0000F000 8000 0000 E839 0066 B864 0000 8066 BB02 0202 00E8 .....9.f.d...f...... 

0000F014 2A00 66B8 6800 0080 66BB 4408 0020 E81B 0066 B86C *.f.h...f.D.. ...f.l 

0000F028 0000 8066 BB08 0000 00E8 0C00 669D 665A 665B 6658 ...f........f.fZf[fX 

0000F03C E801 00C3 BAF8 0C66 EFBA FC0C 66ED 660B C366 EFC3 .......f....f.f..f..

0000F050 FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF ....................

........

             

                          

Address  Hexadecimal values                                Ascii representation 

........ 

000002D0 ED26 A3C8 0126 C706 CA01 00F0 B824 ED26 A3CC 0126 .&...&.......$.&...& 

000002E4 C706 CE01 00F0 E803 EDC6 06C6 0000 F686 E401 0F74 ...................t

000002F8 418A 86E4 0132 E48A 0EEA 008A E980 E103 F6C5 0474 A....2.............t

0000030C 133A CC74 15F6 C530 740A C0ED 0480 E503 3AEC 7406 .:.t...0t.......:.t.

........

0000EFD8 0000 0000 0000 0000 C300 0000 0000 0000 0000 0000 ....................

0000EFEC 0000 0000 6650 6653 6652 669C 66B8 5000 0080 66BB ....fPfSfRf.f.P...f.

0000F000 8000 0000 E839 0066 B864 0000 8066 BB02 0202 00E8 .....9.f.d...f......

0000F014 2A00 66B8 6800 0080 66BB 4408 0020 E81B 0066 B86C *.f.h...f.D.. ...f.l

0000F028 0000 8066 BB08 0000 00E8 0C00 669D 665A 665B 6658 ...f........f.fZf[fX

0000F03C E8AA 22C3 BAF8 0C66 EFBA FC0C 66ED 660B C366 EFC3 .."....f....f.f..f..

0000F050 0000 0000 FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF ....................

........

              

The next steps proceed exactly the same as what described above in Hacking Steps in Detail. After applying those steps, we are done and ready to flash the modified bios.

My Latest Modification and Possible Downside of Previous Methods

My recent experiment with various "code insertion point" in the original.tmp of my computer's bios reveals that previous modifications that I explained sometimes will result in a freezing system during boot. The possibility of this freezing event is around 10 percent in my system. I haven't found any exact explanation on this, but I think this might be related to instruction timing issue or something else that I haven't know yet. Due to this reason, I'm looking for a better method to achieve my goal. I came across the idea of completely replacing an "unneeded" code in my mainboard bios with my own code. I found that the "EPA procedure" is the most suitable for the time being. This procedure is only responsible for displaying EPA logo in award bios. Hence, if we replace it, the only effect is no EPA logo displayed ( if you choose not to rewrite this functionality in the modified bios code, like me). It's located between 1F0Ch and 2009h in my bios's first 64 KByte code (E000h segment), it may be a bit different in your bios. It can be found easily by searching for byte sequence : 808EE10110F6461430h , this byte sequence is the first two instruction of the "EPA procedure". You also can found this procedure by searching for the "AWBM" string (not including the quote).

Note that I have to switch to an older version bios for my mainboard to accomplish this, since my mainboard's latest bios incorporated a different method which doesn't execute the "legacy EPA procedure" at all . I know this, since I've replaced the legacy code that happens to be still included in that bios's original.tmp, but nothing happen, so I conclude it must be in different part of the bios and might be in different bios component. This method displayed full size customized image during boot, not only full sized logo but also customized POST indicators on top of the full sized image. Due to this, the target bios that I'm using is an older one, dated 24th February 2000 and uses the "legacy EPA procedure". Things like this have to be taken into account in case your bios also structured like my latest mainboard bios, i.e. using a "customized EPA procedure" which is not located in the "legacy EPA procedure code spot".

The steps that we'll use here is similar to the steps in Hacking Steps in Detail, except that we are not only replacing one line of code but the entire procedure and also we are not placing any "injected code" in the last 4 KByte of the first 64 Kbyte of the bios code (original.tmp).

Now, the details. The hex dump around that procedure in my bios as follows :

Address  Hexadecimal values                      Ascii representation 

00001F00 C706 1A04 1E00 1E00 9DF8 C390 808E E101 ................

00001F10 10F6 4614 3074 01C3 061E 60BE 0060 BF00 ..F.0t....`..`..

00001F20 3AB9 0030 E85A 4EC6 86ED 0155 B812 00CD :..0.ZN....U....

00001F30 10FC B800 008E C0BF 0070 B820 07B9 D007 .........p. ....

00001F40 F3AB BE0C 0AE8 B64C 0AC0 7416 BF04 00E8 .......L..t.....

00001F50 774E B800 408E D866 813E 0000 4157 424D wN..@..f.>..AWBM

00001F60 7422 C686 ED01 00BF 0C00 E85C 4EB8 0040 t".........\N..@

00001F70 8ED8 6681 3E00 0041 5742 4D0F 856B 00C6 ..f.>..AWBM..k..

00001F80 86ED 01AA B801 12B3 36CD 1033 D280 BEED ........6..3....

00001F90 01AA 7503 BA10 0033 C980 BEED 01AA 7503 ..u....3......u.

00001FA0 B9E0 01E8 2F01 80BE ED01 AA74 1403 0E04 ..../......t....

00001FB0 0081 F980 0272 EC03 1606 0081 FAD0 0172 .....r.........r

00001FC0 D6E8 9F00 B800 12B3 36CD 1080 BEED 01AA ........6.......

00001FD0 7418 C686 ED01 AABE 8942 E823 0F74 03BE t........B.#.t..

00001FE0 C442 E846 02C6 86ED 0155 80A6 E101 EFBE .B.F.....U......

00001FF0 003A BF00 60B9 0030 E886 4DB8 0000 8ED8 .:..`..0..M.....

00002000 C606 9004 0061 1F07 C380 BEED 0155 7452 .....a.......UtR

The disassembly of the above EPA display procedure as follows :

Address   Binary Code       Mnemonic 

........ 

00001F0C  EPA Procedure :  

00001F0C  808EE10110        or byte [bp+0x1e1],0x10 

00001F11  F6461430          test byte [bp+0x14],0x30 

00001F15  7401              jz 0x1f18 

00001F17  C3                ret 

00001F18  06                push es 

00001F19  1E                push ds 

00001F1A  60                pusha 

00001F1B  BE0060            mov si,0x6000 

00001F1E  BF003A            mov di,0x3a00 

00001F21  B90030            mov cx,0x3000 

00001F24  E85A4E            call 0x6d81 

00001F27  C686ED0155        mov byte [bp+0x1ed],0x55 

00001F2C  B81200            mov ax,0x12 

00001F2F  CD10              int 0x10 

00001F31  FC                cld 

00001F32  B80000            mov ax,0x0 

00001F35  8EC0              mov es,ax 

00001F37  BF0070            mov di,0x7000 

00001F3A  B82007            mov ax,0x720 

00001F3D  B9D007            mov cx,0x7d0 

00001F40  F3AB              rep stosw 

00001F42  BE0C0A            mov si,0xa0c 

00001F45  E8B64C            call 0x6bfe 

00001F48  0AC0              or al,al 

00001F4A  7416              jz 0x1f62 

00001F4C  BF0400            mov di,0x4 

00001F4F  E8774E            call 0x6dc9 

00001F52  B80040            mov ax,0x4000 

00001F55  8ED8              mov ds,ax 

00001F57  66813E0000415742  cmp dword [0x0],0x4d425741 --> cmp dword [0x0],"AWBM"           -4D 

00001F60  7422              jz 0x1f84 

00001F62  C686ED0100        mov byte [bp+0x1ed],0x0 

00001F67  BF0C00            mov di,0xc 

00001F6A  E85C4E            call 0x6dc9 

00001F6D  B80040            mov ax,0x4000 

00001F70  8ED8              mov ds,ax 

00001F72  66813E0000415742  cmp dword [0x0],0x4d425741  --> cmp dword [0x0],"AWBM"           -4D 

00001F7B  0F856B00          jnz near 0x1fea 

00001F7F  C686ED01AA        mov byte [bp+0x1ed],0xaa 

00001F84  B80112            mov ax,0x1201 

00001F87  B336              mov bl,0x36 

00001F89  CD10              int 0x10 

00001F8B  33D2              xor dx,dx 

00001F8D  80BEED01AA        cmp byte [bp+0x1ed],0xaa 

00001F92  7503              jnz 0x1f97 

00001F94  BA1000            mov dx,0x10 

00001F97  33C9              xor cx,cx 

00001F99  80BEED01AA        cmp byte [bp+0x1ed],0xaa 

00001F9E  7503              jnz 0x1fa3 

00001FA0  B9E001            mov cx,0x1e0 

00001FA3  E82F01            call 0x20d5 

00001FA6  80BEED01AA        cmp byte [bp+0x1ed],0xaa 

00001FAB  7414              jz 0x1fc1 

00001FAD  030E0400          add cx,[0x4] 

00001FB1  81F98002          cmp cx,0x280 

00001FB5  72EC              jc 0x1fa3 

00001FB7  03160600          add dx,[0x6] 

00001FBB  81FAD001          cmp dx,0x1d0 

00001FBF  72D6              jc 0x1f97 

00001FC1  E89F00            call 0x2063 

00001FC4  B80012            mov ax,0x1200 

00001FC7  B336              mov bl,0x36 

00001FC9  CD10              int 0x10 

00001FCB  80BEED01AA        cmp byte [bp+0x1ed],0xaa 

00001FD0  7418              jz 0x1fea 

00001FD2  C686ED01AA        mov byte [bp+0x1ed],0xaa 

00001FD7  BE8942            mov si,0x4289 

00001FDA  E8230F            call 0x2f00 

00001FDD  7403              jz 0x1fe2 

00001FDF  BEC442            mov si,0x42c4 

00001FE2  E84602            call 0x222b 

00001FE5  C686ED0155        mov byte [bp+0x1ed],0x55 

00001FEA  80A6E101EF        and byte [bp+0x1e1],0xef 

00001FEF  BE003A            mov si,0x3a00 

00001FF2  BF0060            mov di,0x6000 

00001FF5  B90030            mov cx,0x3000 

00001FF8  E8864D            call 0x6d81 

00001FFB  B80000            mov ax,0x0 

00001FFE  8ED8              mov ds,ax 

00002000  C606900400        mov byte [0x490],0x0 

00002005  61                popa 

00002006  1F                pop ds 

00002007  07                pop es 

00002008  C3                ret 

00002008  End of EPA Procedure ........

The listing of my code as follows :

; ------------------- patch.asm ---------------------------------------------------

.486p

; Macro definition

PATCH_PCI  macro  reg_addr,mask

      

   mov eax,reg_addr ; fetch the address of the regs to be patched

   mov dx,in_port   ; fetch the input port addr of PCI cfg space

   out dx,eax

   mov dx,out_port

   in  eax,dx

   or  eax,mask     ; mask the regs value (activate certn. bits)

   out dx,eax

          endm

CSEG  SEGMENT PARA PUBLIC USE16 'CODE'

     ASSUME CS:CSEG

     ORG 0

    ; ORG 100h ; only for testing in dos

; equates, have been tested & works

       in_port    equ 0cf8h

       out_port   equ 0cfch

       ioq_mask   equ 00000080h

       ioq_reg    equ 80000050h

       bank_mask  equ 20000844h

       bank_reg   equ 80000068h

       tlb_mask   equ 00000008h

       tlb_reg    equ 8000006ch

       dram_mask  equ 00020202h

       dram_reg   equ 80000064h

INIT  PROC  NEAR

; save current state

   pushfd

   pushad

; disable interrupt during execution of our routine

   cli

; patch everything as needed

   PATCH_PCI ioq_reg, ioq_mask   ; patch the ioq reg

   PATCH_PCI dram_reg, dram_mask ; patch the DRAM controller

                                 ; i.e. the interleaving part

   PATCH_PCI bank_reg, bank_mask ; patch bank active page ctl reg

   PATCH_PCI tlb_reg, tlb_mask   ; activate Fast TLB lookup

; set video mode

   sti         ; enable interrupt for our video mode setup routine below

   mov ax,12h  ; set video mode to 640x480 pixel, 16 color

   int 10h

      

; restore last state prior to our routine

   popad

   popfd  ; implicitly restores the Interrupt flag state

; return to main bios routine (original.tmp)

   retn                         

INIT  ENDP

      

   db 8Fh dup (90h) ; fill the remaining "code space" with nop instruction

      

CSEG  ENDS     

     END              

; -------------------------- END OF patch.asm -------------------------------------------

The resulting binary of the above code as follows :

Address  Hexadecimal values                                Ascii representation 00000000 669C 6660 FA66 B850 0000 80BA F80C 66EF f.f`.f.P......f. 00000010 BAFC 0C66 ED66 0D80 0000 0066 EF66 B864 ...f.f.....f.f.d 00000020 0000 80BA F80C 66EF BAFC 0C66 ED66 0D02 ......f....f.f.. 00000030 0202 0066 EF66 B868 0000 80BA F80C 66EF ...f.f.h......f. 00000040 BAFC 0C66 ED66 0D44 0800 2066 EF66 B86C ...f.f.D.. f.f.l 00000050 0000 80BA F80C 66EF BAFC 0C66 ED66 83C8 ......f....f.f.. 00000060 0866 EFFB B812 00CD 1066 6166 9DC3 9090 .f.......faf.... 00000070 9090 9090 9090 9090 9090 9090 9090 9090 ................ 00000080 9090 9090 9090 9090 9090 9090 9090 9090 ................ 00000090 9090 9090 9090 9090 9090 9090 9090 9090 ................ 000000A0 9090 9090 9090 9090 9090 9090 9090 9090 ................ 000000B0 9090 9090 9090 9090 9090 9090 9090 9090 ................ 000000C0 9090 9090 9090 9090 9090 9090 9090 9090 ................ 000000D0 9090 9090 9090 9090 9090 9090 9090 9090 ................ 000000E0 9090 9090 9090 9090 9090 9090 9090 9090 ................ 000000F0 9090 9090 9090 9090 9090 9090 90        .............

The disassembly of the code around that area after manual modification using a hex editor as follows :

Address   Binary Code       Mnemonic 

........ 

00001F0C  New EPA procedure :  

00001F0C  669C              pushfd 

00001F0E  6660              pushad 

00001F10  FA                cli 

00001F11  66B850000080      mov eax,0x80000050 

00001F17  BAF80C            mov dx,0xcf8 

00001F1A  66EF              out dx,eax 

00001F1C  BAFC0C            mov dx,0xcfc 

00001F1F  66ED              in eax,dx 

00001F21  660D80000000      or eax,0x80 

00001F27  66EF              out dx,eax 

00001F29  66B864000080      mov eax,0x80000064 

00001F2F  BAF80C            mov dx,0xcf8 

00001F32  66EF              out dx,eax 

00001F34  BAFC0C            mov dx,0xcfc 

00001F37  66ED              in eax,dx 

00001F39  660D02020200      or eax,0x20202 

00001F3F  66EF              out dx,eax 

00001F41  66B868000080      mov eax,0x80000068 

00001F47  BAF80C            mov dx,0xcf8 

00001F4A  66EF              out dx,eax 

00001F4C  BAFC0C            mov dx,0xcfc 

00001F4F  66ED              in eax,dx 

00001F51  660D44080020      or eax,0x20000844 

00001F57  66EF              out dx,eax 

00001F59  66B86C000080      mov eax,0x8000006c 

00001F5F  BAF80C            mov dx,0xcf8 

00001F62  66EF              out dx,eax 

00001F64  BAFC0C            mov dx,0xcfc 

00001F67  66ED              in eax,dx 

00001F69  6683C808          or eax,byte +0x8 

00001F6D  66EF              out dx,eax 

00001F6F  FB                sti 

00001F70  B81200            mov ax,0x12 

00001F73  CD10              int 0x10 

00001F75  6661              popad 

00001F77  669D              popfd 

00001F79  C3                ret 

00001F7A  90                nop 

........ 

00002008  90                nop 

00002008  End of New EPA procedure  

........

The rest is just exactly the same as the previous modification explained in Hacking Steps in Detail and in the A More Radical original.tmp Hacking. That's it and we're done :-).

-- Update --

Finally I managed to mod my mainboard's latest bios that uses "custom EPA procedure" as mentioned above. In that bios binary, I found a custom BIOS component that responsible for the "custom EPA procedure", however it still contain the "legacy EPA procedure" in it's original.tmp. Below is output from unmodified version of that BIOS :

CBROM V2.08 (C)Award Software 2000 All Rights Reserved.

             ********  vd30728.bin BIOS component ********

No. Item-Name         Original-Size   Compressed-Size Original-File-Name

================================================================================

 0. System BIOS       20000h(128.00K) 15532h(85.30K)  original.tmp

 1. XGROUP CODE       057C0h(21.94K)  03AADh(14.67K)  awardext.rom

 2. CPU micro code    0A000h(40.00K)  05D03h(23.25K)  CPUCODE.BIN

 3. ACPI table        021A6h(8.41K)   00E21h(3.53K)   ACPITBL.BIN

 4. EPA LOGO          02D3Ch(11.31K)  00382h(0.88K)   iwillbmp.bmp

 5. NNOPROM           00FECh(3.98K)   00A5Fh(2.59K)   nnoprom.bin

 6. VRS ROM           02280h(8.62K)   014BBh(5.18K)   anti_vir.bin

 7. ROS ROM           14380h(80.88K)  0F670h(61.61K)  E:\2A6LGI3C\AAA\ROSUPD.BIN

 Total compress code space  = 35532h(213.30K)

 Total compressed code size = 3140Fh(197.01K)

 Remain compress code space = 04123h(16.28K)

                         ** Micro Code Information **

Update ID  CPUID  |  Update ID  CPUID  |  Update ID  CPUID  |  Update ID  CPUID

------------------+--------------------+---------------------+-------------------

PPGA   11   0681|  PPGA   10   0683|  PPGA   08   0686|  PPGA   03   0665

SLOT1  13   0630|  SLOT1  20   0632|  SLOT1  34   0633|  SLOT1  35   0634

SLOT1  40   0651|  SLOT1  2A   0652|  SLOT1  10   0653|  SLOT1  0A   0660

SLOT1  03   0671|  SLOT1  10   0672|  SLOT1  0E   0673|  SLOT1  14   0680

SLOT1  0D   0681|  SLOT1  0C   0683|  SLOT1  07   0686|

As you can see, there's a component called ROS ROM. I found that this component responsible for the custom EPA procedure. Extracting this bios component can be done by excuting :

cbrom208 vd30728.bin /ROS Extract

I don't have enough time disassembling and dissecting this component, hence I only extract it and looking at it's binary contents using hexeditor. A quick read over this binary confirm my suspicion. Then I just release this component from that bios and then "patch" the "legacy EPA procedure" in its original.tmp. Releasing this component is achieved by invoking :

cbrom208 vd30728.bin /ROS Release

To ensure that my goal to patch my BIOS will be achieved, I decided to flash the mainboard bios that has no more ROS ROM and see what happens. As predicted, the bios "fallback" to executing "legacy EPA procedure". However, we have 2 jobs to accomplish. First, to replace the EPA procedure and second, to ensure that the old "custom EPA procedure" is not called anymore, since if it's called, there's possibility our "modified EPA procedure" will not be called, you'll see the reason very soon. The "legacy EPA procedure" in my bios located between 1F1Ch and 200Bh. The disassembly as follows :

Address   Binary Code       Mnemonic 

........ 

00001F1C   --- EPA Procedure ---  

00001F1C  808EE10110        or byte [bp+0x1e1],0x10 

00001F21  F6461430          test byte [bp+0x14],0x30 

00001F25  7401              jz 0x1f28 

00001F27  C3                ret 

00001F28  06                push es 

00001F29  1E                push ds 

00001F2A  60                pusha 

00001F2B  BE0060            mov si,0x6000 

00001F2E  BF003A            mov di,0x3a00 

00001F31  B90030            mov cx,0x3000 

00001F34  E8CA4E            call 0x6e01 

00001F37  C686ED0155        mov byte [bp+0x1ed],0x55 

00001F3C  B81200            mov ax,0x12 

00001F3F  CD10              int 0x10 

00001F41  FC                cld 

00001F42  B80000            mov ax,0x0 

00001F45  8EC0              mov es,ax 

00001F47  BF0070            mov di,0x7000 

00001F4A  B82007            mov ax,0x720 

00001F4D  B9D007            mov cx,0x7d0 

00001F50  F3AB              rep stosw 

00001F52  BE0C0A            mov si,0xa0c 

00001F55  E8264D            call 0x6c7e 

00001F58  0AC0              or al,al 

00001F5A  7416              jz 0x1f72 

00001F5C  BF0400            mov di,0x4 

00001F5F  E8E74E            call 0x6e49 

00001F62  B80040            mov ax,0x4000 

00001F65  8ED8              mov ds,ax 

00001F67  66813E0000415742  cmp dword [0x0],0x4d425741  -- cmp dword [0x0],"AWBM"          -4D 

00001F70  7422              jz 0x1f94 

00001F72  C686ED0100        mov byte [bp+0x1ed],0x0 

00001F77  BF0C00            mov di,0xc 

00001F7A  E8CC4E            call 0x6e49 

00001F7D  B80040            mov ax,0x4000 

00001F80  8ED8              mov ds,ax 

00001F82  66813E0000415742  cmp dword [0x0],0x4d425741  -- cmp dword [0x0],"AWBM"          -4D 

00001F8B  0F855D00          jnz near 0x1fec 

00001F8F  C686ED01AA        mov byte [bp+0x1ed],0xaa 

00001F94  B80112            mov ax,0x1201 

00001F97  B336              mov bl,0x36 

00001F99  CD10              int 0x10 

00001F9B  33D2              xor dx,dx 

00001F9D  80BEED01AA        cmp byte [bp+0x1ed],0xaa 

00001FA2  7503              jnz 0x1fa7 

00001FA4  BA1000            mov dx,0x10 

00001FA7  33C9              xor cx,cx 

00001FA9  80BEED01AA        cmp byte [bp+0x1ed],0xaa 

00001FAE  7503              jnz 0x1fb3 

00001FB0  B9E001            mov cx,0x1e0 

00001FB3  E81A01            call 0x20d0 

00001FB6  80BEED01AA        cmp byte [bp+0x1ed],0xaa 

00001FBB  7414              jz 0x1fd1 

00001FBD  030E0400          add cx,[0x4] 

00001FC1  81F98002          cmp cx,0x280 

00001FC5  72EC              jc 0x1fb3 

00001FC7  03160600          add dx,[0x6] 

00001FCB  81FAD001          cmp dx,0x1d0 

00001FCF  72D6              jc 0x1fa7 

00001FD1  E89100            call 0x2065 

00001FD4  B80012            mov ax,0x1200 

00001FD7  B336              mov bl,0x36 

00001FD9  CD10              int 0x10 

00001FDB  80BEED01AA        cmp byte [bp+0x1ed],0xaa 

00001FE0  740A              jz 0x1fec 

00001FE2  C686ED01AA        mov byte [bp+0x1ed],0xaa 

00001FE7  C686ED0155        mov byte [bp+0x1ed],0x55 

00001FEC  80A6E101EF        and byte [bp+0x1e1],0xef 

00001FF1  BE003A            mov si,0x3a00 

00001FF4  BF0060            mov di,0x6000 

00001FF7  B90030            mov cx,0x3000 

00001FFA  E8044E            call 0x6e01 

00001FFD  B80000            mov ax,0x0 

00002000  8ED8              mov ds,ax 

00002002  C606900400        mov byte [0x490],0x0 

00002007  61                popa 

00002008  1F                pop ds 

00002009  07                pop es 

0000200A  C3                ret 

0000200A  -- End of EPA Procedure -- ........

I replace this "legacy EPA procedure" with my code. The listing of the code as follows :

; ------------------- patch.asm ---------------------------------------------------

.486p

; Macro definition

PATCH_PCI  macro  reg_addr,mask

      

   mov eax,reg_addr ; fetch the address of the regs to be patched

   mov dx,in_port   ; fetch the input port addr of PCI cfg space

   out dx,eax

   mov dx,out_port

   in  eax,dx

   or  eax,mask     ; mask the regs value (activate certn. bits)

   out dx,eax

          endm

CSEG  SEGMENT PARA PUBLIC USE16 'CODE'

     ASSUME CS:CSEG

     ORG 0

    

; equates, have been tested & works

   in_port    equ 0cf8h

   out_port   equ 0cfch

   ioq_mask   equ 00000080h

   ioq_reg    equ 80000050h

   bank_mask  equ 20000844h

   bank_reg   equ 80000068h

   tlb_mask   equ 00000008h

   tlb_reg    equ 8000006ch

   dram_mask  equ 00020202h

   dram_reg   equ 80000064h

INIT  PROC  NEAR

; save current state

   pushfd

   pushad

; disable interrupt during execution of our routine

   cli

; patch everything as needed

   PATCH_PCI ioq_reg, ioq_mask   ; patch the ioq reg

   PATCH_PCI dram_reg, dram_mask ; patch the DRAM controller

                                 ; i.e. the interleaving part

   PATCH_PCI bank_reg, bank_mask ; patch bank active page ctl reg

   PATCH_PCI tlb_reg, tlb_mask   ; activate Fast TLB lookup

; set video mode

   sti  ; enable interrupt for our video mode setup routine below

  

   ; set video mode to 640x480 pixel, 16 color and clear video buffer (assumed to be VGA Bios)

   mov ax,12h 

   int 10h

; restore last state prior to our routine

   popad

   popfd  ; implicitly restores the Interrupt flag state

; return to main bios routine (original.tmp)

   retn                         

INIT  ENDP

      

   ORG 0EFh ; zero fill the remaining "code space"

      

CSEG  ENDS     

     END              

; -------------------------- END OF patch.asm -------------------------------------------

to assemble this code I use the following command :

ml /AT patch.asm /Fe patch.bin /link /TINY

I use hexeditor to replace the "legacy EPA procedure" in my mainboard's original.tmp with the assembled code. Now, to ensure the old "custom EPA procedure" won't be called, we look for a call to the epa procedure in the disassembly of the first 64 KB original.tmp code (segment E000h). I found it at address 1E56h in my mainboard's latest bios. The disassembly as follows :

Address   Binary Code       Mnemonic 

........ 

00001E3B  6800E0            push word 0xe000 

00001E3E  684C1E            push word 0x1e4c 

00001E41  6831EC            push word 0xec31 

00001E44  68864F            push word 0x4f86 

00001E47  EA30EC00F0        jmp 0xf000:0xec30 

00001E4C  B800F0            mov ax,0xf000 

00001E4F  8ED8              mov ds,ax 

00001E51  E88C11            call 0x2fe0  -- this is the call to "custom EPA procedure"

00001E54  7303              jnc 0x1e59  --  this jump instruction have to be eliminated

00001E56  E8C300            call 0x1f1c  --  this is the call to "legacy EPA procedure" 

00001E59  E8AF01            call 0x200b 

00001E5C  BA0018            mov dx,0x1800 ........

I came across the above commented code after comparing my mainboard's latest bios (which has "custom EPA procedure") and its older bios which has no "custom EPA procedure". The disassembly of the bios without "custom EPA procedure" as follows :

Address   Binary Code       Mnemonic 

........ 

00001E37  6800E0            push word 0xe000 

00001E3A  68481E            push word 0x1e48 

00001E3D  6831EC            push word 0xec31 

00001E40  68F54E            push word 0x4ef5 

00001E43  EA30EC00F0        jmp 0xf000:0xec30 

00001E48  B800F0            mov ax,0xf000 

00001E4B  8ED8              mov ds,ax 

00001E4D  E8BC00            call 0x1f0c -- this is call to "legacy EPA procedure" 

00001E50  E8B601            call 0x2009 

00001E53  BA0018            mov dx,0x1800 ........

so, to achieve our second goal, just replace the unneeded instruction with a nop (90h) instruction by using hexeditor. The disassembly of the patched code as follows :

Address   Binary Code       Mnemonic 

........ 

00001E3B  6800E0            push word 0xe000 

00001E3E  684C1E            push word 0x1e4c 

00001E41  6831EC            push word 0xec31 

00001E44  68864F            push word 0x4f86 

00001E47  EA30EC00F0        jmp 0xf000:0xec30 

00001E4C  B800F0            mov ax,0xf000 

00001E4F  8ED8              mov ds,ax 

00001E51  90                nop

00001E52  90                nop

00001E53  90                nop

00001E54  90                nop

00001E55  90                nop

00001E56  E8C300            call 0x1f1c - call to "legacy EPA procedure" (now our modded EPA procedure) 

00001E59  E8AF01            call 0x200b 

00001E5C  BA0018            mov dx,0x1800 ........

The rest is just exactly the same as the previous modification explained in Hacking Steps in Detail and in the A More Radical original.tmp Hacking. I suspect that every mainboard with a custom EPA procedure might conform to the structure that I explained here, i.e. having a "custom EPA procedure" and a "legacy EPA procedure". Due to this reason we could possibly mod any Award BIOS by using the method I explained here, it's your job to confirm this :-).

WARNING: After reading the last method described above, we might be tempted to replace the "custom EPA procedure" with call to our own "injected" procedure somewhere in the first 64 KByte (E000h segment) and left the "legacy EPA Procedure" to handle the "EPA display procedure". However, further experiment in my system reveals that the so called "legacy EPA procedure" above (which is in my mainboard's latest bios) is an incomplete "EPA procedure". I've try it and found that even the "legacy EPA procedure" is "partially embedded" in the "custom EPA procedure", hence the result is complete lock up during boot. We have to take this into account when doing this kind of modification. The conclusion is: if you want to mod a custom EPA procedure, you have to completely replace it to be safe or trace it thoroughly before modifying it, if you just want to modify it without completely replacing it. I prefer to replace them all with my own code and "save some clockcycle" by not doing the eyecandy that appear ugly to me :-) since VGA card related routine tend to be slow.

Closing Note

Some of the reader might ask, why I only replace the "exactly 3 bytes of code" instruction with a call into my code in the first two modification method above? The reason is plain and clear, to minimize the effect of the code that we inserted into the bios. I can mess up with 4 bytes instruction and place a nop instruction ( 90h ) after the call into my code (which occupy 3 bytes), but I refuse to do so, since I've been experiencing a lockup with that approach in my machine. Logically, it shouldn't happen, but this is a peculiarity that needs more investigation.

If you want a bulletproof original.tmp hacking method, then I suggest the last method. If it's not possible at all in your bios, you can stick to the basic principle, i.e. look for "cosmetic procedure" and replace it with your own code. This is the safest method that I can suggest. If you are an experienced hacker, then you might find a better method. What I write here is only a humble solution to my problem. I'm not an experienced hacker in "direct hardware programming", I'm a newbie in this field :-(.

My main reason "screwing up" with original.tmp is the "isa option rom trick", that I previously employed sometimes not working with my "LAN card in disguise" (which is actually a SCSI controller) if the isa option rom is assembled by using assembler other than masm 6.11 and masm 6.15. The code that masm emit is somehow weird, I can't decode it, it seems to be undocumented opcode :-(. You can read about my "LAN card in disguise" stuff here.

That's all, I hope this would be useful for you. I have no testbed yet available for award version 6.0PG bioses :-(. However, I've just began dissecting and disassembling them. If you have found something wrong in this article or have developed new bios hacking trick based on what I explain here, please let me know.

copyright © Darmawan M S a.k.a Pinczakko