仿98(DOS7.1)的F$.EXE(>512M模式运行),P_QUEST的P$.EXE 本文基于486DX2,主板,可带primary(启动)/secondary控制IDE器2,中断14/15,每个IDE,可带master(启动,电缆中)/slave(缆端)(跳线ds插/空)2通道,每通道,可带1台硬盘驱动器,每驱动器,可带1块NORMAL,LBA,LARGE模式的IDE硬盘. DOS,98对硬盘,先按IDE,后按m/s,依次编号,不编闲置通道.例如,有3块盘,块1,2在pri_m/s上,块3在sec_cs上,此3块,编为80h~82h. 开机盘的IDE及通道,由BIOS的BOOT SEQ指定. (1) DOS/98的读写F16/32格式的位置X的Y个连续扇区的BIOS中断13h参数: ah的2/3指明读/写,al的低6位指明Y,es:bx指向内存buf首,cl的低6位指明X的扇号sector,最小1,ch,左拼cl第6,7位,齐指X的柱面号cylinder,最小0,dh指明磁头号head,最小0,dl指明软硬盘编号. IDE原有的NORMAL,BIOS限定柱面数1024,磁头数16,扇区数63,每扇512字节,相乘=容量528MB.用作cmos_chs(cylinder:head:sector)立体寻扇. LBA,仅磁头数异达255,容量8.4GB LARGE,柱面数>1024,磁头数16,控制器做柱面数/2,磁头数*2,以适13h.容量2048*16*63*512=1G 周边设定:Block模式加速,PIO(并行I/O接口)模式,影响rate (2) 针对LBA的扩展13h线性64位lba寻扇: chs转时,lba=c*sectors_per_cylinder+h*sectors_per_track+(s-1) 其中,sectors_per_cylinder为每柱面扇数,sectors_per_track为每磁道扇数,因s从1编号,要减1. 互转,见"(7) 文"的chs2lba,lba2chs. 利用extblk块: extblk db 16 ;块的字节数(含此字节) db 0 sec_tot dw 1 指明Y个扇区 buf_off dw 0 ;内存buf偏移 buf_seg dw 0 ;buf段值 lbal dw 0 ;lba低双字低字 lbah dw 0 ;lba低双字高字 dd 0 ;lba高双字 读/写时,ah=42h/43h,多ds:si指向extblk 扩展i13的BIOS支持性(柱数<1024,先用chs),及导出硬盘柱数,头数,每道扇数,算法见"(7) 文"的h_geo (3) 硬盘分区: 每硬盘,最多划为DOS主分区,DOS扩展分区,非DOS分区之1的4区,述于16字节/区的64字节分区表(dpt): bootON db 0 80H/0,是活跃/不活跃. db ? 分区启动chs的头号 dw ? 低6位:扇区,低第6,7位与高字节,'齐指'柱面号 volume db 0 分区标识值 db ? 结束chs dw ? Front dd 0 此分区之前(称隐藏)扇区数.INT_25H_dx=1,是在其后读逻辑首扇 In dd 0 此分区所含扇区数 MBR(F$制的1扇盘主引导记录,软盘0:0:1,硬盘DOS分区的首扇,即INT_25H_扇号dx=1),转cpu给Format.com制的驻有OS的活跃主分区引导记录(OBR). 主分区的保留区(引导扇区PBS囿其内,软盘仅藏1区)之后,常是2份FAT,再后,是根目录. PBS片断: 0~2:JMP引导程序 3~0AH:厂,sys_ver (BPB首)0BH~0CH:每扇bytes 0DH:每簇扇数 0EH~0FH:保留区扇数 10H:FAT份数 11H~12H:F16根目录32字节项的数目,F32:0. 13H~14H:软盘,32M内硬盘:分区总扇数 15H:介质,软盘:F0H,硬盘:F8H 16H~17H:软盘,32M内硬盘:每FAT占用扇 18H~19H:每道扇数 1AH~1BH:磁头数 1CH~1FH:此分区之前隐藏扇数 20H~23H:32M外硬盘:分区总扇数 24H~27H:32M外硬盘:每FAT占用扇 40H:磁盘BIOS,1st硬盘:80H,软盘:0 47H~51H:vol 52H~59H:file_sys 软盘6.22的io.sys,最先分得簇,如目录项0基第13字,指向1e,此12BIT的项值,是1f0002,指明01f->020->...->fff链. 分区标识值: 闲置:0 DOS主分区:1,4,6,0bh,0ch,0eh DOS扩展分区:5,0fh 非DOS分区:其它 笔者用P,对硬盘划分4个DOS主分区,再prw,读此盘(0:0:0)到文件0,用debug,改分区vol值为2,用prw,回写0到(0:0:0),P的分区info页,显vol对应XENIX. 释意,见"(7) 文"的FAT 若vol<20H,则高4位,1/0表示隐藏/非隐藏,后缀X,用于扩展i13接口. 各硬盘,均含0:0:1(chs)的1扇MBR,其偏移1be字节,连续存4个分区表. 各硬盘,最多1个DOS扩展分区,其内,能划分称为逻辑分区的数个DOS主分区,非DOS分区. 逻辑分区串成链.例如,vol=5的扩展分区E,先含1个DOS主分区D,后含1个非DOS分区N,则E的Front域值F,是E内的各逻辑分区位置基址,F指明扇区S1,而S1的偏移1be字节,是D的分区表,偏移1ce字节,其vol=0fh,表示DOS扩展分区,其Front域值,加上基址F,指明扇区S2,而S2的偏移1be字节,是N的分区表,偏移1ce字节,其vol=链尾0. (4) 仿F$及P$,列出分区逻辑盘符: 盘符,C:~Z:列出.用F$,P$,能建数个逻辑分区 分区超过Z:符时,F$照列,P$不赋盘符,prw赋^符 活跃分区数>1时,引导错,但F$及prw照列,P$显错 F$,P$,依vol域,查以下3步,每步,查80h至83h: (1) 查DOS主分区 若是,则查bootON是否80H,若是,此分区就占1个逻辑盘符,若无活跃主分区,表项在MBR首现的主分区,就占1个逻辑盘符. 例如,3硬盘,80h的第1,3分区是主分区,但第3分区活跃,则第3分区占盘符C:.而81h,只含DOS扩展分区,其上,含1个DOS主分区及1个非DOS分区;82h的第2,4分区是不活跃主分区,则最先在MBR中出现的第2分区,占盘符D: (2) 查DOS扩展分区 按逻辑分区在链上次序,查它是否DOS主分区,若是,就占盘符,81h的DOS扩展分区上的DOS主分区,占盘符E: (3) 查未占过盘符的DOS主分区及非DOS分区 按MBR中,分区表项出现的先后次序,查分区是否DOS主分区,若是,且它未占过盘符,就占盘符.80h的第1分区,占盘符F:,82h的第4分区,占盘符G: F$,P$,prw,不给非DOS分区赋盘符,仅显In值. (5) 例: 笔者486,在pri_ds上,装ST32140A驱动器(2012M),在sec_ds上,装QUANTUM(514M). (5.1) 80h上,现有vol=6的DOS活跃主分区(FAT16B,1299M),vol=6的主分区(F16B,39.4M),vol=17h的非DOS分区(HiddenNTFS,574.9M),vol=5的扩展分区,其托4个逻辑分区,按链上次序是: vol=0bh的DOS主分区(F32,35.4M),vol=83h的非DOS分区(LINUX_Ext2,19.7M),vol=1的DOS主分区(Unfmt,3.9M),vol=6的主分区(41.3M) (5.2) 81h上,现有vol=82h的非DOS分区(L_Swap,3M),vol=11h的非DOS分区(Unfmt,3M),vol=6的活跃主分区(472.5M),vol=0fh的扩展分区,其托4个逻辑分区,按链上次序: vol=82h的非DOS分区(L_Swap,10.8M),vol=1的主分区(F12,8.8M),vol=7的非DOS分区(N,9,8M),vol=1的主分区(U,7.8M). 从98软盘启动,F$,P$,列出这些分区的盘符及容: C:1299M D;472.5M E:35.4M F:3.9M G:41.3M J:39.4M H:8.8M I:7.8M (6) prw功能 命令行是prw.exe [foo1] 初见: b(pb),p(arti),r(ead sec to foo/stdout),w(rite foo to sec),v(xd w) 命令键b,p,r,w,v: (6.1) b,显subBPB (6.2) p,显分区盘编号,逻辑盘符,BootON值,vol值,Front值,In值,例如 80,C:,Boot:80,FAT:06,Front:0000003f,In:00101661 (6.3) r,读软硬盘内容到新建foo,或stdout (6.4) wv,写已存foo到软硬盘.v多依VxD,胜v86禁13h写.算法,见"(8) 论V86下,直寻硬盘扇区,只能靠VxD" rwv,用旧FCB式,读源F16,F32,写F16.逐扇有结果I/O,直至出错或事成. 欲读80h的MBR到文件b:d,先发: prw b:d 再答r,界面: drv(00~01,80~83)80 0~cyl(0029) 0~hd(1f) 1~sec(3f) 0~lba(00014abf) c(hs),l(ba)l 0~lba(00014abf)00000000 0~cyl(0000) 0~hd(00) 1~sec(01) 0~lba(00000000) 1~total(ffff)0001 事成/中止,d长度512/0. v86时,改向buf文符到F32的文件g,可发prw c:u>g (7) 文 NIBSZ=8 ;8个hex数 nibasc macro local nq add al,48 cmp al,10+48 jb nq add al,97-48-10 nq: endm alasc macro mov ah,al and al,15 nibasc xchg ah,al rept 4 shr al,1 高nibble endm nibasc stosw endm axasc macro push ax mov al,ah 转ah alasc pop ax 转al alasc endm d segment buf db 511 dup(0) 放MRB.全囿V86页(4k),buf长1023,囿DMA_64k buf511 db 0 老buf尾 info_sz dw 26 ;min sz of info buf 新buf flags dw 0 ;flags cylinders0 dw 0 ;number of cylinders on disk cylinders1 dw 0 heads00 db 0 ;number of heads on disk heads01 db 0 heads1 dw 0 s1track00 db 0 ;number of sectors per track s1track01 db 0 s1track1 dw 0 sectors dq 0 ;number of sectors on requested disk sector_sz dw 0 ;number of bytes per sector db 511-26 dup(0) ;新buf FAT db 13,10,'0~0eh:' db 13,10,'?OS,F12/Unfmt,,,F16/U_,EXtend,F16B,NTFS,,,,F32,F32_13X,,F16' db 13,10,'11,14,16,17,1b:(Hidden)' db 13,10,'F12/U_,F16,F16B,N,F32$' .view db '0000,cx=' viewcx db '13EX,dx=' viewdx db 'tend' CR db 13,10,36 extblk db 16,0 分区表16字节用 sec_tot dw 1 buf_off dw buf ;buf偏移 buf_seg dw SEG buf lbal dw 0 ;lba低双字低字 lbah dw 0 ;lba低双字高字 dd 0 ;lba高双字 cmd_p db 'b(pb),p(arti),r(ead sec to foo/stdout),w(rite foo to sec),v(xd w)$';rwv用 logi_p db 13,10,'logi_drv(A:=01)$' subBPB db 13,10,'SV_sec:' SV_sec db 0,'000,FATs:' 向foo读 FATs db '00,sec_per_FAT:' sec1FAT db '0000$' drv_p db 13,10,'drv(00~01,80~83)$' ;扩展i13用 mod_p db 13,10,'c(hs),l(ba)$' ;dosext,nondos用 db 13,10 from80 db '8?,' logidrv db 'C:,Boot:' Boot db '?0,FAT:' volume db '06,Front:' Front_h dw ?,? 又做总扇数 Front_l db '0000,In:' In_h dw 0,? 又做当前扇号 In_l db '0000$' cyl_p db 13,10,'0~cyl(' cyl_p1 db '????)$' hd_p db 13,10,'0~hd(' hd_p1 db '??)$' sec_p db 13,10,'1~sec(' sec_p1 db '??)$' lba_p db 13,10,'0~lba(' lbah_p1 db '????' lbal_p1 db '????)$' total_p db 13,10,'1~total(ffff)$' scr_p db '^C,f(ast),n(ext)$' primk db 1,4,6,11,12,14 主分区标识 primksz=$-primk extmk db 5,15 扩展分区标识 extmksz=$-extmk stk1 dw NIBSZ/4 dup(0) ;INnib栈 db 32 rowasc db (2+1)*16 dup(32),36 kbd db NIBSZ+1 ;键盘buf kbd1 db 67 parti用 kbd2 db NIBSZ+1 dup(0) fcbdrv db 0 fcbnam db 8 dup(32) fcbext db 3 dup(32) fcbblk dw 0 fcbrsz dw 512 fcbsz db 4 dup (4) 已占分区表号,4硬盘*1字节,parti用 fcbdat dw 0 fcbdos1 db 10 dup(0) fcbrno db 0 entry label dword ;fcbrand entrydi dw 0 entryes dw 0 media_h db 0 ;头数 media_c dw 0 ;柱数 s1cyl dw 0 ;扇数/柱 s1track db 0 ;扇数/道 drv db 0 ;输入 hd db 0 cyl dw 0 sec db 0 hextbl db '0123456789abcdef' d ends c segment assume cs:c,ds:d,es:d @ proc far push ds ;为exe返回 xor ax,ax 压cd20的psp:0 push ax mov ax,d mov es,ax cmp byte ptr ds:[5dh],32 缺foo je @0 inc es:SV_sec mov cx,1+8+3 mov si,5ch sh复制盘符+大写8.3名到5ch lea di,fcbdrv rep movsb es:di=ds:si的盘符+8.3 @0: mov ds,ax mov ah,9 lea dx,cmd_p ;问命令 int 21h mov ah,1 int 21h cmp al,'b' je b jmp p b: mov kbd,2 + 1 lea dx,logi_p 问逻辑盘 Call INnib mov ax,440dh mov cx,860h 传统及扩展13,共享BPB前12字节 lea dx,buf int 21h mov ax,word ptr buf[7+3] lea di,SV_sec axasc mov al,buf[7+5] lea di,FATs alasc mov ax,word ptr buf[7+11] or ax,ax jnz bo mov ax,word ptr buf[7+25] bo: lea di,sec1FAT axasc mov ah,9 lea dx,subBPB int 21h ret p: cmp al,'p' jne r mov ah,9 lea dx,FAT int 21h lea bx,buf mov dx,80h 扩展i13,可兼容传统 Call dospri mov mod_p,dl mov dl,80h Call dosext mov lbal,0 mov lbah,0 mov dl,80h Call nondos ret r: mov cmd_p,al cmp al,'r' je rwv cmp al,'w' je rwv cmp al,'v' je v ret v: mov ax,1684h ;func mov bx,3180h ;接口ID int 2fh mov ax,es ;es:di=V86口cs:ip or ax,di jnz v1 ret es,di全0,失败 v1: mov entrydi,di mov entryes,es push ds pop es rwv: mov kbd,2 + 1 lea dx,drv_p 问磁盘 Call INnib mov drv,bl mov dl,bl 驱动器 test bl,80h jne rwv1 xor dh,dh 头 Call f_geo jmp rwv2 rwv1: Call h_geo rwv2: test media_h,255 jne rwv3 ret rwv3: mul s1cyl sub ax,1 ;lba始于0,可写CF sbb dx,0 mov lbal,ax mov lbah,dx Call lba2chs Call rng mov ah,9 ;问寻扇 lea dx,mod_p int 21h mov ah,1 int 21h cmp al,'c' je rwv4 mov kbd,8 + 1 lea dx,lba_p call INnib ;问lbah,lbal mov lbal,bx mov ax,stk1 mov lbah,ax Call lba2chs jmp rwv5 rwv4:mov kbd,4 + 1 lea dx,cyl_p ;问柱面号 Call INnib mov cyl,bx mov kbd,2 + 1 lea dx,hd_p ;问头号 Call INnib mov hd,bl mov kbd,2 + 1 lea dx,sec_p ;问扇号 Call INnib mov sec,bl Call chs2lba rwv5:Call rng ;显出立体,线性值 mov kbd,4 + 1 lea dx,total_p ;问总计 Call INnib mov Front_h,bx lea dx,fcbdrv ;指向fcb mov ah,15 ;open for w,v cmp cmd_p,'r' jne rw1 test SV_sec,1 向foo读 jz rw2 mov ah,16h ;create or trunc for r,软盘启动,拒存取F32盘 rw1: int 21h 改fcbdrv为3=C or al,al al为0,成功 jnz rw7 mov fcbrsz,512 重置 rw2: mov ax,600h al=clr mov bx,700h bl=page xor cx,cx mov dx,184fh 25*80 int 10h cursor grow 0,24 mov ah,1ah ;DTA lea dx,buf mov bx,dx ;I/O数据区 int 21h rw3: test Front_h,65535 jz rw6 cmp cmd_p,'r' jne rw4 mov ax,201h mov dl,drv Call rw1by1 je rw6 Call scr test SV_sec,1 ;向foo读 jz rw5 mov ah,15h ;强制write lea dx,fcbdrv int 21h jmp rw5 rw4: mov ah,14h ;read lea dx,fcbdrv int 21h Call scr mov ax,301h mov dl,drv Call rw1by1 je rw8 ;出错,关闭 rw5: add lbal,1 adc lbah,0 inc In_h dec Front_h jmp rw3 rw6: test SV_sec,1 向foo读 jnz rw8 rw7: ret rw8: mov ah,16 ;close lea dx,fcbdrv int 21h ret @ endp dospri proc ;统计硬盘数,查DOS主分区 dospri0:cmp dl,80h+4 je dospri7 mov ax,201h ;测硬盘 mov cx,1 int 13h jc dospri7 mov bp,4*16 xor si,si ;分区表,占4*16字节 dospri1:cmp si,4*16 je dospri4 mov al,buf[1beh+si+4] 取vol mov cx,primksz 是主分区? lea di,primk repne scasb jne dospri3 test byte ptr buf[1beh+si],80h ;取BootON jnz dospri2 cmp bp,4*16 jnz dospri3 dospri2:mov bp,si ;暂选首现主分区 jnz dospri5 dospri3:Add si,16 jmp dospri1 dospri4:cmp bp,4*16 je dospri6 dospri5:mov si,dx sub si,80h mov ax,bp div extblk mov fcbsz[si],al 标占分区表项号 mov al,kbd1 mov logidrv,al inc kbd1 Call Show dospri6:inc dl ;读下块硬盘 jmp dospri0 dospri7:ret dospri endp pri_non proc mov logidrv,32 mov cx,primksz lea di,primk repne scasb jne non ;不赋非DOS分区盘符 mov logidrv,94 ^符 mov al,kbd1 cmp al,'Z' ja non mov logidrv,al inc kbd1 non: Call Show ret pri_non endp dosext proc 查DOS扩展分区 dosext0:cmp dl,mod_p je dosext4 mov ax,201h mov cx,1 int 13h xor bp,bp dosext1:cmp bp,4*16 je dosext3 mov al,buf[1beh+bp+4] mov cx,extmksz 是扩展分区? lea di,extmk repne scasb jne dosext2 push bx push dx Call h_geo pop dx pop bx mov ax,word ptr buf[1beh+bp+8] ;Front low mov entrydi,ax 基址 mov lbal,ax mov ax,word ptr buf[1beh+bp+10] ;Front high mov entryes,ax mov lbah,ax xor bp,bp ;为show Call chain jmp dosext3 dosext2:Add bp,16 jmp dosext1 dosext3:inc dl jmp dosext0 dosext4:ret dosext endp h_geo proc mov ah,41h mov bx,55aah ;测BIOS支持i13_X int 13h jc h_geoo cmp bx,0aa55h 再核 jne h_geoo test cx,1 ;支持41~44,47~48第1子集? jz h_geoo mov ah,48h 取尺寸 lea si,info_sz int 13h mov al,heads00 ;头数 or al,al jz h_geoo 无效info包 mov media_h,al inc drv_p 启扩展 mov ah,s1track00 ;每道扇数 mov s1track,ah mul ah mov s1cyl,ax 每柱面扇数 mov ax,cylinders0 ;柱面数 mov media_c,ax ret h_geoo: mov ah,8 取尺寸 int 13h jc h_geoq inc dh mov al,dh mov media_h,al ;头数 mov s1track,cl and s1track,63 每道扇数 mul s1track mov s1cyl,ax ;每柱面扇数 xchg ch,cl rol ch,1 rol ch,1 and ch,3 mov ax,cx inc ax mov media_c,ax ;柱面数 h_geoq: ret h_geo endp chain proc ;处理链 chain0: mov ax,201h Call rw1by1 mov al,buf[1beh+4] call pri_non test buf[1beh+16+4],255 ;0,5,15之1 je chain1 mov ax,word ptr buf[1beh+16+8] add ax,entrydi ;加基址entrydi mov lbal,ax mov ax,word ptr buf[1beh+16+10] adc ax,entryes ;加基址entryes mov lbah,ax jmp chain0 chain1: ret chain endp nondos proc 查未占过盘符的DOS主分区及非DOS分区 nondos0:cmp dl,mod_p je nondos4 mov ax,201h mov cx,1 int 13h mov bp,dx sub bp,80h mov al,fcbsz[bp] 取已占分区表号 mul extblk mov fcbdat,ax xor bp,bp nondos1:cmp bp,4*16 je nondos3 cmp bp,fcbdat je nondos2 ;已占 mov al,buf[1beh+bp+4] test al,255 不理闲置分区 jz nondos2 mov cx,extmksz ;略扩展分区 lea di,extmk repne scasb jz nondos2 call pri_non nondos2:Add bp,16 jmp nondos1 nondos3:inc dl jmp nondos0 nondos4:ret nondos endp show proc ;分区信息 push dx and dl,3 盘号80~83 add dl,48 mov from80[1],dl mov Boot,48 多数为0 test buf[1beh+bp],80h jz show0 mov Boot,56 show0: mov al,buf[1beh+bp+4] ;显vol lea di,volume alasc mov ax,word ptr buf[1beh+bp+8] ;取Front low add ax,lbal ;为chain而加 pushf lea di,Front_l axasc mov ax,word ptr buf[1beh+bp+10] ;Front high popf adc ax,lbah ;为chain而加 lea di,Front_h axasc mov ax,word ptr buf[1beh+bp+12] ;取In low lea di,In_l axasc mov ax,word ptr buf[1beh+bp+14] ;In high lea di,In_h axasc mov ah,9 lea dx,from80 sub dx,2 int 21h pop dx ret Show endp rw1by1 proc 读/写1扇 test drv_p,1 13=传统 jnz rw1by11 xor al,al 不校验写 or ah,40h lea si,extblk ;扩展块 jmp rw1by12 rw1by11:push ax push dx call lba2chs pop dx pop ax call cxdh mov word ptr viewcx,cx mov word ptr viewdx,dx rw1by12:cmp cmd_p,'v' je rw1by13 int 13h ret 遗c rw1by13:Call [entry] cmp bp,4096 VxD按(8.3)返bp值 jae rw1by14 push bx add bx,bp ;使bx,bx+511在4k内 mov buf_off,bx 扩展i13 push cx push si lea si,buf511 ;原buf尾 mov di,si add di,bp ;新buf尾 std ;从后向前移1扇 mov cx,256 rep movsw cld pop si pop cx Call [entry] pop bx mov buf_off,bx 扩展i13 cmp bp,4096 rw1by14:je rw1by15 cmp bp,1010h jne rw1by16 xor ah,ah Call [entry] 释它页 rw1by15:cmp al,al 置zr rw1by16:ret rw1by1 endp f_geo proc lea bx,buf ;缓区 mov cx,1 ;0:0:1(chs)引导扇 f_geo0: mov ax,201h ;读1扇 int 13h ;读11起的bios参数块 jc f_geo0 ;换盘 mov al,[bx+26] ;偏移26:头数 mov media_h,al mov ah,[bx+24] ;偏移24:每道扇数 mov s1track,ah mul ah mov s1cyl,ax ;每柱面扇数 mov ax,[bx+19] ;偏移19:总扇数 xor dx,dx ;高字 div s1cyl mov media_c,ax ;柱面数 ret f_geo endp rng proc mov ax,cyl ;当前柱面 lea di,cyl_p1 axasc mov al,hd ;当前头 lea di,hd_p1 alasc mov al,sec ;当前扇号 lea di,sec_p1 alasc mov ax,lbah ;当前lba高字 lea di,lbah_p1 axasc mov ax,lbal ;当前lba低字 lea di,lbal_p1 axasc mov ah,9 lea dx,cyl_p int 21h lea dx,hd_p int 21h lea dx,sec_p int 21h lea dx,lba_p int 21h ret rng endp scr proc mov cx,16 字符数/row xor si,si scr0: push bx mov ah,2 xor bh,bh pg xor dx,dx dh=row int 10h pop bx lea dx,.view test si,256 jz scr1 jmp scr3 scr1: mov di,dx mov ax,In_h 现扇号 axasc test drv_p,1 jnz scr2 jmp scr3 scr2: lea di,viewcx mov ax,word ptr [di] axasc lea di,viewdx mov ax,word ptr [di] axasc scr3: mov ah,9 int 21h scr4: mov ax,si lea di,stk1 axasc lea bp,rowasc scr5: mov al,[bx+si] mov di,si and di,15 mov FAT[di],46 cmp al,32 jb scr6 mov FAT[di],al scr6: mov di,bp alasc Add bp,2+2-1 inc si test si,15 jne scr5 mov ah,9 行的hex lea dx,stk1 int 21h push bx mov ah,64 行的asc及汉字 mov bx,1 lea dx,FAT int 21h pop bx mov ah,9 lea dx,CR int 21h test si,255 je scr7 jmp scr4 scr7: cmp scr_p,'f' je scr8 mov ah,9 lea dx,scr_p int 21h mov ah,1 ;按1键 int 21h cmp al,'f' jne scr8 mov scr_p,al scr8: test si,511 je scr9 jmp scr0 scr9: ret scr endp cxdh proc mov dh,hd ;头号 mov cx,cyl ;柱面号 xchg cl,ch ror cl,1 ror cl,1 and cl,not 63 or cl,sec ;低6位扇号 ret cxdh endp lba2chs proc mov ax,lbal mov dx,lbah div s1cyl ;柱面号 mov cyl,ax mov ax,dx div s1track mov hd,al ;头号 inc ah mov sec,ah ;扇号 ret lba2chs endp chs2lba proc mov ax,cyl ;柱面号 mul s1cyl mov lbal,ax mov lbah,dx mov al,s1track ;每道扇数 mul hd Add lbal,ax adc lbah,0 mov al,sec ;此处,低6位扇号 dec al cbw Add lbal,ax adc lbah,0 ret chs2lba endp INnib proc ;kbd限长nib入kbd2.转后入stk1,低字还入bx INnib0: mov ah,9 int 21h push dx inc ah ;回车才收 lea dx,kbd int 21h pop dx mov al,kbd dec al cmp al,kbd1 ;实长 jnz INnib0 xor bp,bp lea si,kbd2 INnib1: lodsb mov cx,16 lea di,hextbl repne scasb jnz INnib0 dec kbd1 inc cx ;转'[0-9a-f]'为0~15 sub cx,16 neg cx rept 4 shl bx,1 ;bx接收nibble,左入0 endm or bl,cl test kbd1,3 ;已收4个nibble jnz INnib1 mov stk1[bp],bx add bp,TYPE stk1 test kbd1,NIBSZ*2-1 jnz INnib1 ret INnib endp c ends end @ (8) 论V86下,直寻硬盘扇区,只能靠VxD VToolsD建的C级VxD,有读/写DOS分区的R0_ReadAbsoluteDisk/R0_Write...函数. 例如,响应自32位C的W32_DEVICEIOCONTROL事件时,用格式R0_Read...(2,1,0,buf,&w),读相对DOS分区的逻辑扇号是1的分区引导扇区PBS.这时,当前虚拟机hVM,是系统(证于Test_Sys_VM_Handle测事件实参IOCTLPARAMS.dioc_hvm).VxD不改hVM身份. 又如,响应自16位ASM程序的V86_API_Entry入口调用时,同上,读PBS,这时,hVM是DOS(证于Test_...测入口实参VMHANDLE). 均读PBS含"MSWIN4...". 但VxD,也能在V86下,用Exec_Int(0x13),法如13h,直寻硬盘,如PBS之前MBR. 笔者c.cpp+a.exe,直读MBR连续5扇.需cfg.sys,隐dev=EMM386 (8.1) 用QuickVxD,建C++级VxD,设备名=C,设备ID=0x3180,选动态装 选API页Standard App Entry Points框Real/V86 Mode.体,见(8.3). 选OnSysDynamicDevice的Init及Exit.体中: 选发SHELL_SYSMODAL_Message(Get_Cur_VM_Handle(),MB_SYSTEMMODAL,"m","cap") 必发return(true) (8.2) 写a.asm,汇编时,/DNPAGE=5,指明5扇.读变写,需debug下,改r2w3处的2为3. VxD查客户这5扇缓区,囿V86空间1页(4K字节)的整体性,未全囿,bp返回<4k的修正量. IF2 IF NPAGE LT 1 or NPAGE GT 8 %OUT 0 .ERR ENDIF ENDIF d segment buf db NPAGE*512*2-1 dup(9);留足修区 entry dd 0 d ends c segment assume cs:c,ds:d @: mov bp,d mov ds,bp mov ax,1684h 功能号 mov bx,3180h 接口ID int 2fh mov ax,es es/di=API_Entry入口段/偏移 or ax,di jz @3 ;es及di全为零,失败 mov word ptr [entry],di mov word ptr [entry+2],es mov ax,ds 设exec_int参数 mov es,ax lea bx,buf es:bx,指向缓区首 r2w3: mov ah,2 读80h硬盘MBR处NPAGE扇 mov al,NPAGE mov cx,1 0:0:1(chs) mov dx,128 std VxD出兰屏,写修 call [entry] cmp bp,4096 VxD按(8.3)返bp值 jae @2 add bx,bp 修缓区首址 test ah,1 查读/写 jz @1 此例ah=2,读盘 lea si,buf 写入时,从后向前,移NPAGE*256字 add si,NPAGE*512-1 si指向原缓区尾 mov di, si add di,bp di指向新缓区尾 mov cx, NPAGE*256 rep movsw ds:si所指cx字,移到es:di mov cx,1 @1: call [entry] cmp bp,4096 @2: je @3 cmp bp,1010h jne @3 xor ah,ah ;释它页 call [entry] @3: xor ax,ax mov es,ax mov ax,[bx+1beh] 成功/失败,72h矢量=分区表首字/9 mov es:[1c8h],ax mov ah,4ch int 21h c ends end @ (8.3) ...V86_API_Entry(VMHANDLE hVM, CLIENT_STRUCT* pRegs)体 DWORD h,t; CLIENT_STRUCT s; if(pRegs->CBRS.Client_AH){//2读3写 h=(DWORD)Map_Flat(CLIENT_ES,CLIENT_BX);//h=客户缓区首es:bx的32位线性址 t=h+pRegs->CBRS.Client_AL*512-1;//t=尾的线性址 if((h>>12)!=(t>>12)){ pRegs->CWRS.Client_BP=(4096-(h&4095));//首尾未囿同页,bp返客户增bx量 return; } if((h>>12)<0x110)//缓区能被V86寻,bp返4096 pRegs->CWRS.Client_BP=4096; else if(LinMapIntoV86(h>>12,hVM,0x10,1,0,&t)){ //缓区所在页,成功映入V86第0x10页,bp返0x1010 pRegs->CWRS.Client_BP=0x1010; h=(16<<12)+(h&4095);//由t及偏移,得缓区V86址h }else{//无页等,bp返0x1110 pRegs->CWRS.Client_BP=0x1110; return; } Save_Client_State(&s);//存reg Begin_Nest_V86_Exec();//当前虚拟机,能寻V86 pRegs->CRS.Client_ES=(h>>4);//es=址h的段值 pRegs->CRS.Client_EBX=(h&15);//bx=址h的偏移 Exec_Int(0x13); End_Nest_Exec();//复原 Restore_Client_State(&s); if(pRegs->CWRS.Client_Flags&1024){//方向,控兰屏 sprintf((char*)s.CBRS.Client_res30,"%x",pRegs->CWRS.Client_BP); SHELL_SYSMODAL_Message(hVM,MB_SYSTEMMODAL,(char*)s.CBRS.Client_res30,"bp"); } }else//知bp返0x1010时,客户释它页 MapIntoV86(GetNulPageHandle(),hVM,16,1,0,0); (8.4) 装VxD法 静态: 放C.VXD于c:/windows/system,在c:/windows/system.ini的386Enh,写device=C.VxD,再reboot 动态4法: 用VxD_Loader,选C.VXD 用DriverMonitor,先打开C.VXD,再Start 放C.VXD于c:/windows/system/iosubsys,再reboot 用笔者DOS窗口a的exe #include #define pre "////.//" main(int ac,char *av[]){ char *vxd; HANDLE h; if (ac==1) printf("vxd_load ?.vxd/n"); else{ vxd=malloc(strlen(pre)+strlen(av[1])); sprintf(vxd,"%s%s",pre,av[1]); h=CreateFile(vxd,0,0,0,0,FILE_FLAG_DELETE_ON_CLOSE,0); if(h!=INVALID_HANDLE_VALUE){ printf("To unload,hit Enter"); getch(); CloseHandle(h); } } } 装C.VXD,事毕,敲回车到窗a,卸此VXD  
|