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 //后面提供一个集中下载的位置...