精华区 [关闭][返回]

当前位置:网易精华区>>讨论区精华>>编程开发>>C/C++>>文件系统与注册表>>windows9x下绝对读写硬盘扇区的例程(转载

主题:windows9x下绝对读写硬盘扇区的例程(转载
发信人: black()
整理人: wenbobo(2002-12-27 15:48:51), 站内信件
近日在水木清华看到如下文章,给愿意分析VXD的参考:

发信人: Shuanshuan (阿涮), 信区: Programming       
标  题: windows9x下绝对读写硬盘扇区的例程
发信站: BBS 水木清华站 (Sat Aug 21 17:32:04 1999)

由于win9x下由win32程序对硬盘的写操作被屏蔽,所以绝对硬盘的读写的思路在于
设法转入16位程序,因此有两种方法可以达到这种目的:使用THUNK机制调用16位DLL
或用VxD转到16位方式,我觉得用THUNK太麻烦,其实VxD挺好编的,而且用起来也方便,
当时也是出于学习目的,编了这么一个VxD,还是挺好用的,我看精华区对这个问题的讨
论好像没有什么结果,就把它贴出来,算是班门弄斧吧!
我是用DDK编的,主要是因为我当时是出于学习.

//这是程序的主要部分,其中有一些宏定义,从字面上就能知道是干什么的,我就不罗嗦
//了
DWORD _stdcall CVXD_W32_DeviceIOControl(LPDIOC lpDIOCParms,
                                        CLIENT_STRUCT *pRegs)
{
        DWORD dwRetVal = 0,retu;
        DWORD *i;
        PVMMCB  hVM;
        DIOC_REGISTERS  *lpReg,*lpOutReg;
        CLIENT_STRUCT saveregs;
        DWORD PageNum;
        WORD PageOff;
        DWORD Address;
        DWORD V86PageNum,MyPage;
        WORD seg,offset;
        
        hVM=Get_Cur_VM_Handle();
        i=(DWORD *)(lpDIOCParms->lpvOutBuffer);
        lpReg=(DIOC_REGISTERS *)(lpDIOCParms->lpvInBuffer);
        lpOutReg=(DIOC_REGISTERS *)(lpDIOCParms->lpvOutBuffer);
        switch(lpDIOCParms->dwIoControlCode)
        {
                  .
                  .
                  .
        case 2:
                if(lpDIOCParms->cbInBuffer!=sizeof(DIOC_REGISTERS))
                        return dwRetVal=-1;

                //保存当前虚拟机的寄存器状态
                _asm push edi
                _asm lea edi,saveregs 
                VMMCall(Save_Client_State);
                _asm pop edi

                //输入的参数,具体怎么用看INT13的说明吧
                _ClientEAX=lpReg->reg_EAX;
                _ClientEDX=lpReg->reg_EDX;
                _ClientECX=lpReg->reg_ECX;
                _ClientEFlags=lpReg->reg_Flags;

/* 以下这一段是编写这个VxD时要考虑的主要问题:把缓冲区的地址映射入虚拟86的地址
区,Win32中用的都是线性地址,先根据它求出页面号,再把缓冲区所在的页映射到虚拟86区
中去,下面程序中有一个Bug,它没有考虑到缓冲区所占页面大于一页时的情形,事实上,缓
冲区可能处在叶面的边界上,而且它的大小可能超过一页,这些都要根据上面参数中给出
的缓冲区大小计算,当时我嫌麻烦,随便应付了一下.用的时候要把这段代码改一下 
*/
                PageNum=(lpReg->reg_EBX)>>12;
                PageOff=(lpReg->reg_EBX)&0xfff;
                _asm{
                        push 0
                        push 1
                        push 10
                        push hVM
                        push PageNum
                }
                VMMCall(_LinMapIntoV86);
                _asm add esp,14h
                _asm mov retu,eax
                _asm mov MyPage,edx   //返回的页面号在edx寄存器中
                if(retu==0) return 3;//这是我自己胡乱选的错误码,你可以自己定成
                                     //其它值 
                Address=(MyPage<<12)+PageOff;//计算新的线性地址
seg=LOWORD(Address>>4);          //把线性地址转化成传统的段:偏
                offset=LOWORD(Address-(seg<<4)); //移量的形式
_ClientAltES=seg;//这里一定不能弄错了,在Win32 Ring3程序中用的
//是_ClientES,而虚拟86方式下用的段寄存器则在
//_ClientAltES中,所以要用它
_ClientBX=offset;

//xixi,好戏开始了
VMMCall(Begin_Nest_V86_Exec);//这一句使得系统转入虚拟86方式
_asm mov eax,13h
VMMCall(Exec_Int);//发出int 13h中断调用
//保存返回值
if(lpDIOCParms->cbOutBuffer==sizeof(DIOC_REGISTERS))
                {
                        lpOutReg->reg_Flags=_ClientEFlags;
                        lpOutReg->reg_EAX=_ClientEAX;
                        lpOutReg->reg_EBX=_ClientEBX;
                        lpOutReg->reg_ECX=_ClientECX;
                        lpOutReg->reg_EDX=_ClientEDX;
                }
                End_Nest_Exec();//退出虚拟86方式
                
                //轻轻地我走了,正如我轻轻地来,我挥一挥衣袖,不带走一片云彩
                _asm push esi
                _asm lea esi,saveregs
                VMMCall(Restore_Client_State);
                _asm pop esi                           
                //这一段取消原来的映射
                VMMCall(_GetNulPageHandle);
                _asm mov PageNum,eax
                _asm{
                        push 0
                        push 0
                        push 1
                        push 10
                        push hVM
                        push PageNum
                }
                VMMCall(_MapIntoV86);
                _asm add esp,18h                         
                
                //OK
                return dwRetVal=0;
        }
        return dwRetVal;
}

--
6m※ 修改:·Shuanshuan 於 Aug 21 17:34:10 修改本文·[FROM:  162.105.23.174]m
m5m※ 来源:·BBS 水木清华站 bbs.net.tsinghua.edu.cn·[FROM: 162.105.23.174]m

--
-------------------------------------------------------------------------------
黑夜给了我黑色的眼睛,我用它寻找光明
Email : [email protected]

※ 来源:.网易 BBS bbs.netease.com.[FROM: 202.103.173.119]

[关闭][返回]