Winflash/AwdFlash是Windows下和dos下的BIOS刷新工具。

在windows下,刷新BIOS需要读写物理内存或IO端口。
在NT平台下,读写物理内存或IO端口需要驱动来支持(也可以使用/dev/PhysicalMemory来完成,但是2003sp1...)
winflash使用驱动来实现物理内存/IO端口的读写,这一点很明显。

winflash/awdflash都是使用SMI Flash来进行BIOS刷新的。对winflash/awdflash反汇编,
都可以发现

mov     dx, ds:SMI_PORT
mov     al, 28h
out     dx, al          ; manufacture's diagnostic checkpoint


之类的字样.
(开始还以为这是调试用的端口.../感谢网友 的文章。)

废话就不说了,先看一下WinFlash的FlowChart吧:

直接将winflash拖到IDA中也可以,如果你能看得下去...

winflash是经过加壳的,用PE Scan检测一下,aspack 2.12
可直接脱壳,没有什么特殊的障碍...

在NT下,Winflash需要动态加载驱动,直接在代码中查找CreateService(),
然后在逐级找到calller,hehe,最后来到如下位置

snyped:004029A0 084                 mov     ecx, esi
snyped:004029A2 084                 call    check_OS_Version
snyped:004029A2
snyped:004029A7 084                 mov     ecx, esi
snyped:004029A9 084                 call    Start_SYS_Driver 
snyped:004029A9
snyped:004029AE 084                 test    al, al
snyped:004029B0 084                 jnz     short Check_Award_BIOS
snyped:004029B0
snyped:004029B2 084                 lea     ecx, [ebp+var_74]
snyped:004029B5 084                 mov     [ebp+var_4], 0FFFFFFFFh
snyped:004029BC 084                 call    CCommandLineInfo::~CCommandLineInfo(void)

有关MFC的东西不用管了,接着看下面
主要是调用驱动的功能来读取物理内存的F000:0000段的内容,
即SystemBIOS模块的内容(初始化后),从中获取BIOS/FlashROM的相关信息。

snyped:004029D4     Check_Award_BIOS:                       ; CODE XREF: CMainFrame_InitInstance+120j
snyped:004029D4 084                 mov     ecx, offset flash_info_struct
snyped:004029D9 084                 call    PhysicalMemoryRead      ;这里使用DeviceIoCtrl的222000h功能
                                                                    ;读取0xF0000-0xFFFFF的内存到用户态缓冲区
snyped:004029D9
snyped:004029DE 084                 mov     ecx, offset flash_info_struct
snyped:004029E3 084                 call    Get_Award_Modular_Sig   ;此函数从读取的0xF000段数据中获取BIOS信息
                                                                    ;
snyped:004029E3
snyped:004029E8 084                 test    al, al
snyped:004029EA 084                 jnz     short BIOS_is_Award
snyped:004029EA
snyped:004029EC 084                 push    offset s_XBiosAwardGb ; " 本机主板 BIOS 不是 Award 的!"
snyped:004029F1 088                 push    1               ; int
snyped:004029F3 08C                 push    0               ; int
snyped:004029F5 090                 mov     ecx, esi
snyped:004029F7 090                 call    ErrorDialog__1
snyped:004029F7
snyped:004029FC 084                 lea     ecx, [ebp+var_74]
snyped:004029FF 084                 mov     [ebp+var_4], 0FFFFFFFFh
snyped:00402A06 084                 call    CCommandLineInfo::~CCommandLineInfo(void)

在上面的代码中,最重要的函数就是0x004029E3 位置调用的函数

snyped:004011D0     Get_Award_Modular_Sig proc near         ; CODE XREF: CMainFrame_InitInstance+153p
snyped:004011D0                                             ; sub_4033A0+8p
snyped:004011D0 000                 push    esi
snyped:004011D1 004                 mov     esi, ecx
snyped:004011D3 004                 mov     ds:byte_44FB08, 0
snyped:004011DA 004                 mov     eax, [esi+4]
snyped:004011DD 004                 push    eax
snyped:004011DE 008                 call    check_Award_Modular_BIOS_Sig    ;当找到"Award Modular BIOS"字符串时,此函数返回1
snyped:004011DE
snyped:004011E3 004                 test    al, al
snyped:004011E5 004                 jnz     short loc_4011E9    ;AwdBIOS,在这里跳转
snyped:004011E5
snyped:004011E7 004                 pop     esi
snyped:004011E8 000                 retn
snyped:004011E8
snyped:004011E9     ; ---------------------------------------------------------------------------
snyped:004011E9
snyped:004011E9     loc_4011E9:                             ; CODE XREF: Get_Award_Modular_Sig+15j
snyped:004011E9 004                 mov     ecx, esi
snyped:004011EB 004                 call    GetSMI_Port     ;在Offset_"$@AWDFLASH"+0x2A位置获取SMI_PORT
snyped:004011EB
snyped:004011F0 004                 mov     ecx, esi等
snyped:004011F2 004                 call    GetFlashInfo    ;由"KAFLASH" 获取BIOS FlashROM信息,包括FlashROM 大小,Base Addr
snyped:004011F2
snyped:004011F7 004                 mov     ecx, esi
snyped:004011F9 004                 call    GetDecompressInfo   ;暂时这样认为,获取DecompressBlock的起始位置...(????)
snyped:004011F9
snyped:004011FE 004                 mov     al, 1
snyped:00401200 004                 pop     esi
snyped:00401201 000                 retn
snyped:00401201
snyped:00401201     Get_Award_Modular_Sig endp获取了BIOS和FlashROM的相关信息后,


下面是设置驱动的全局变量,SMI_PORT
其中IoCtlCode:
222004h-->设置驱动的全局变量,(in/out Buffer见下面)
222008h-->调用SMI_0x2E功能

snyped:00402A1E     BIOS_is_Award:                          ; CODE XREF: CMainFrame_InitInstance+15Aj
snyped:00402A1E 084                 cmp     ds:Window_Version, 2000h
snyped:00402A28 084                 jnz     short SMI_0x2E_Func_0
snyped:00402A28
snyped:00402A2A 084                 mov     ax, ds:SMI_PORT
snyped:00402A30 084                 lea     ecx, [ebp+BytesReturned]
snyped:00402A33 084                 mov     edi, ds:DeviceIoControl
snyped:00402A39 084                 push    0               ; lpOverlapped
snyped:00402A3B 088                 push    ecx             ; lpBytesReturned
snyped:00402A3C 08C                 push    0               ; nOutBufferSize
snyped:00402A3E 090                 push    0               ; lpOutBuffer
snyped:00402A40 094                 lea     edx, [ebp+SMI_Port]
snyped:00402A43 094                 mov     word ptr [ebp+SMI_Port], ax
snyped:00402A47 094                 mov     eax, ds:hDevice
snyped:00402A4C 094                 push    2               ; nInBufferSize
snyped:00402A4E 098                 push    edx             ; lpInBuffer
snyped:00402A4F 09C                 push    222004h ; <suspicious> ; dwIoControlCode
snyped:00402A54 0A0                 push    eax             ; hDevice
snyped:00402A55 0A4                 call    edi ; DeviceIoControl ; Set SMI Port!!!
snyped:00402A57 084                 lea     ecx, [ebp+BytesReturned]
snyped:00402A5A 084                 push    0               ; lpOverlapped
snyped:00402A5C 088                 push    ecx             ; lpBytesReturned
snyped:00402A5D 08C                 mov     ecx, ds:hDevice
snyped:00402A63 08C                 lea     edx, [ebp+OutBuffer]
snyped:00402A66 08C                 push    10h             ; nOutBufferSize
snyped:00402A68 090                 push    edx             ; lpOutBuffer
snyped:00402A69 094                 lea     eax, [ebp+OutBuffer]
snyped:00402A6C 094                 push    2               ; nInBufferSize
snyped:00402A6E 098                 push    eax             ; lpInBuffer
snyped:00402A6F 09C                 push    222008h ; <suspicious> ; dwIoControlCode
snyped:00402A74 0A0                 push    ecx             ; hDevice
snyped:00402A75 0A4                 mov     [ebp+OutBuffer], 0
snyped:00402A7C 0A4                 call    edi ; DeviceIoControl ; SMI_0x2E Func 00h
snyped:00402A7C                                             ; GetBiosInfo
snyped:00402A7E 084                 cmp     ds:Window_Version, 2000h
snyped:00402A88 084                 jz      short loc_402AA5 ; jmp here!!!
///MFC Init here...

基本上,WinFlash的基本init_FlowChart就出来了
下面转到到正题:

至于WinFlash怎样Program FlashROM,只需调试一下winflash.exe即可

说的太麻烦
大家有各自的调试手段
我使用的是IDA5来进行Ring3调试的(hehe),直接用ida5启动(unpacked)winflash.exe,然后
在刷新BIOS时将进程中断,即可由中断的代码位置来判断caller(call tree/path?)

基本上,刷新的代码部分如下,注视自己随便填写了,看得懂即可

//
//winflash代码里针对win98和NT做了不同的处理,这里只关心NT
//
snyped:0040209F     os_is_win2000:                          ; CODE XREF: SST_SectorProg+19j
snyped:0040209F 018                 mov     eax, [esp+18h+BytesReturned]
snyped:004020A3 018                 lea     ecx, [esp+18h+BytesReturned]
snyped:004020A7 018                 mov     ebx, ds:DeviceIoControl
snyped:004020AD 018                 push    0               ; lpOverlapped
snyped:004020AF 01C                 push    ecx             ; lpBytesReturned
snyped:004020B0 020                 push    0               ; nOutBufferSize
snyped:004020B2 024                 push    0               ; lpOutBuffer
snyped:004020B4 028                 lea     edx, [esp+28h+LocalBuffer] ; input buffer dd FFFC0000h
snyped:004020B4                                             ;
snyped:004020B8 028                 mov     [esp+28h+LocalBuffer], eax
snyped:004020BC 028                 mov     eax, ds:hDevice
snyped:004020C1 028                 push    4               ; nInBufferSize
snyped:004020C3 02C                 push    edx             ; lpInBuffer
snyped:004020C4 030                 push    222010h ; <suspicious> ; dwIoControlCode
snyped:004020C9 034                 push    eax             ; hDevice
snyped:004020CA 038                 call    ebx ; DeviceIoControl ; SetGlobal_Var
snyped:004020CC 018                 mov     edi, [esp+18h+Size_0x1000] ; edi==0x1000
snyped:004020D0 018                 test    edi, edi        ; EDI=FFFC0000h //很多注释都是调试的时候加上去的,应该很明显的....
snyped:004020D2 018                 jbe     short loc_4020FE
snyped:004020D2
snyped:004020D4 018                 add     edi, 0Fh        ; edi=0x100F
snyped:004020D7 018                 shr     edi, 4          ; edi=0x100
snyped:004020D7
snyped:004020DA
snyped:004020DA     loop_Byte_program:                      ; CODE XREF: SST_SectorProg+ACj
snyped:004020DA 018                 mov     eax, ds:hDevice
snyped:004020DF 018                 lea     ecx, [esp+18h+BytesReturned]
snyped:004020E3 018                 push    0               ; lpOverlapped
snyped:004020E5 01C                 push    ecx             ; lpBytesReturned
snyped:004020E6 020                 lea     edx, [esp+20h+OutBuffer]
snyped:004020EA 020                 push    4               ; nOutBufferSize
snyped:004020EC 024                 push    edx             ; lpOutBuffer
snyped:004020ED 028                 push    10h             ; nInBufferSize
snyped:004020EF 02C                 push    esi             ; lpInBuffer
snyped:004020F0 030                 push    22201Ch ; <suspicious> ; dwIoControlCode
snyped:004020F5 034                 push    eax             ; hDevice
snyped:004020F6 038                 call    ebx ; DeviceIoControl ; 处理16个字节,flash 16Bytes
snyped:004020F8 018                 add     esi, 10h        ; 移动到下16个字节
snyped:004020FB 018                 dec     edi             ; 总数减去16字节
snyped:004020FC 018                 jnz     short loop_Byte_program ; 循环处理
snyped:004020FC
snyped:004020FE
snyped:004020FE     loc_4020FE:                             ; CODE XREF: SST_SectorProg+23j
snyped:004020FE                                             ; SST_SectorProg+82j
snyped:004020FE 018                 pop     edi
snyped:004020FF 014                 pop     esi
snyped:00402100 010                 pop     ebp
snyped:00402101 00C                 mov     al, 1
snyped:00402103 00C                 pop     ebx
snyped:00402104 008                 add     esp, 8
snyped:00402107 000                 retn    0Ch
snyped:00402107
snyped:00402107     SST_SectorProg  endp
//SST是自己之前随便写的,还以为针对每种Flash有不同的flash方法函数...

在Flash之前,先使用SMI_0x29按4KB擦除ROM...

麻烦


看到这里你可能还是很糊涂,到底怎样Flash?
winflash.exe是请求winflash.sys来完成Flash的,直接静态反汇编winflash.sys即可(文件很简单,是个普通的driver/文件很小...)

至于各个寄存器的设置,反汇编的代码里看得很清楚了。
如果有疑问,可以使用softice调试一下:
做法是在winflash刷新的时候,ctrl+d,然后
addr winflash
mod winflash.sys找到winflash的加载基址
然后根据IDA反汇编的代码偏移计算出需要中断的代码位置,然后bpx即可.
(也可以直接单步跟踪,如果你很有耐心的话...)

这样,winfash的FlowChart基本上出来了
你也可以自己写一个Flash BIOS的程序(前提是awd/SMI Flash...)

不想说废话了
这里加一个自己部分注释的winflash.* 的IDB(适用于IDA5)地址.
link:   winflash_unpack.idb     http://xxxlink:   winflash_sys.idb        http://xxx //后面提供一个集中下载的位置...