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 have provided links to bios related website in the front page of this website and also I've made tutorial called Preliminary Bios Modification Guide and Mainboard Bios Components. 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 :-).
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:
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:

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.txtI dump the result into a text file to ease analyzing it.
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 ........In the upper part, you can see that I skipped some bytes that clearly shown as "readable ascii string" in my hexeditor. This string ends up with a terminating zero (00h), so I'm pretty sure of what I'm doing.
Here's our plan :
cmp ax,0ffffh ; the code in the original.tmp that I replaced.Masm615 doesn't emit 3DFFFFh binary for this code (which is the original code in the original.tmp file) . Hence, I have to replace that 3 bytes which Masm615 emits with the suitable code (3DFFFFh) using hexeditor. Things like this have to be taken into account when patching original.tmp.
relative_call_distance = addr_of_1st_injected_code - addr_after_call_instruction
For example, the near call instruction located at D79h and your injected code begins at EFF0h then the relative_call_distance will be :
relative_call_distance = EFF0h - D7Ch
relative_call_distance = E274h
... (main injected code here) .... the code that you replaced here ret
ml /AT sys_patch.asm /Fe sys_patch.bin /link /TINYNote: You don't need to pay attention to the linker warning, it has no effect to us since we are not building a real *.com file, we are targeting 16 bit pure binary code. The command above will end up buiding sys_patch.bin as the resulting binary file that we are going to use.
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.
; ------------------- 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 retLooking 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 :
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 retThen 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.
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.
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.
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 000002CB 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 retNow, 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 .................... ........Note that I've changed the last 8 bytes of FFh bytes with 00h bytes. This is just for fun :-). That's it, we've done with this third step.
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.......UtRThe 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 :-).
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 ExtractI 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 ReleaseTo 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 /TINYI 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 :-).
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 © 2004,2005,2006 Darmawan MS a.k.a Pinczakko