无忧启动论坛

 找回密码
 注册
搜索
系统gho:最纯净好用系统下载站投放广告、加入VIP会员,请联系 微信:wuyouceo
123
返回列表 发新帖
楼主: 窄口牛
打印 上一主题 下一主题

grub4dos虚拟个内存盘(用高位),进win98还能用上它?(已有结论,无法实现)

  [复制链接]
61#
发表于 2023-10-12 07:01:32 | 只看该作者
看到有人继续关注,本帖就稍稍深入一步,谈谈 win98 下访问 --top 内存盘的技术可行性。纯粹是空谈,不再实干。因为空谈容易,实干难。

我们知道,著名的 CIH 病毒的作者就是一个高手。他能够在 Win98 之下获取 CPU 最高权限( ring 0 权限),从而不受任何约束地执行自己的代码。这个获取 ring 0 权限的代码,我估计现在还能够从网上找到。除此之外,网上还能找到另外一个牛人,名叫 Z0MBiE,他有个主页:

https://z0mbie.dreamhosters.com/

里面有很多代码和文章。有人把他的代码和文章收集起来,保存在这里:

https://github.com/lwerdna/z0mbie.host.sk

他能用多种方法从 win98 获取 ring0 权限。

我们利用这个技术,就可以让 grub.exe 从 win98 下运行,进入实模式,然后再执行 grub4dos 的其他命令。

如果说在 win98 之下运行 grub.exe 的意义不大的话,那么,下面这个应该算是有实在意义的:获取 ring 0 权限后,磁盘仿真代码能够顺利读取(或写入)4G 以上的高位内存,这样,--top 的问题就解决了。

点评

good!!没用过  发表于 2023-10-14 13:06
回复

使用道具 举报

62#
 楼主| 发表于 2023-10-12 08:40:39 来自手机 | 只看该作者
dayeye 发表于 2023-10-11 22:45
ACER 4750G,10G内存,实机安装win98。map --mem --top 的2375M的fd盘可以格式化完成使用。格式化时间很长, ...

大内存补丁后就能了。系统内认到3.5g,实际可能会用的就2g。

点评

good  发表于 2023-10-14 13:06
回复

使用道具 举报

63#
发表于 2023-10-14 08:24:39 | 只看该作者
本帖最后由 不点 于 2023-10-14 12:30 编辑

理解、分析一下 Z0MBiE 的从 VM86 模式获取 ring0 权限的代码。文件名是 V86_2_R0.ASM。

以下是源代码,并附上我的注解。

;  V86 -> RING0 (从 VM86 模式进入 ring0)

; this program should be executed under Win95/98
; developed under win98

程序应在 Win95/98 下运行;是在 Win98 下开发的。

; 1. start in V86, exec int3
; 2. go to PROT16/RING3 using DPMI, exec int3
; 3. go to PROT32/RING0 using DPMI/IDT hack, exec int3
; 4. back to DOS

第一步,从 VM86 模式启动,执行 int3 指令
第二步,用 DPMI 进入 16 位保护模式,ring3,执行 int3 指令
第三步,用 DPMI 并对 IDT 进行 hack,进入32位保护模式,ring0,执行 int3 指令
第四步,返回 DOS

这些 int3 指令,不起实质性作用,只是为了调试的时候,能够在此处中断。

;                                           (c) Z0MBiE/29A -- March 22, 1999

                        model   tiny      (tiny 的意思就是要生成 .com 程序)
                        p386
                        locals  __
                        jumps
                        codeseg

                        org     100h
start:

                        mov     ax, 1600h       ; windows running?
                        int     2fh
                        cmp     al, 4           ; win95/98 ?
                        jne     __exit        若不是 win9x,退出

                        int 3                   ; V86

                        lea     sp, endofstack  ; set own stack
                                                         设置自己的堆栈

                        mov     ah, 4ah         ; resize our memory block
                        mov     bx, memory      调整内存块大小
                        int     21h

以上代码不是实质性的,仅仅是减少本程序对内存的过多占用,因为 .com 程序默认占用 64K,有点多。

                        mov     ax, 1687h       ; DPMI - installation check
                        int     2fh        检查是否存在 DPMI
                        or      ax, ax
                        jnz     __exit        若不存在 DPMI,退出
                        ; ES:DI = DPMI mode-switch entry point
                        ; SI=memory(in par.) needed for DPMI private data

                        push    es              ; init DPMI initproc
                        push    di
                        pop     dpmicall    保存DPMI模式切换子程序入口

                        mov     ah, 48h         ; allocate memory
                        mov     bx, si          ; for DPMI private data
                        int     21h        为 DPMI 所需私有数据分配内存
                        jc      __exit
                        mov     es, ax        保存分配到的内存段值到ES

这额外的私有数据,有点讨厌。.com 程序运行在 DOS 下,当然可以调用 DOS 来分配内存。
然而我们假如只是在 int13 的 handler 里面运行,此时还能调用 DOS 来分配内存吗?
这是个疑问。就算能调用,将来在 int13 handler 结束时,还得记住要释放内存。
所以,安全起见,我们应该设法避免调用 DOS API 来分配内存。

                        xor     ax, ax  ; flags: bit0=0 -> 16-bit program
                        call    dpmicall    调用模式切换子程序
                        jc      __exit
                        ; now in protected mode (16-bit, ring3)

此时已进入 16 位保护模式,ring3 权限。

                        int 3                   ; PROT16/R3

                        sidt    idtr            ; read IDTR (读 “中断描述符表” 寄存器)

只有进入保护模式之后,DPMI 才会为保护模式代码生成 IDT。
这可能就是为什么需要进入保护模式的原因。

                        mov     ax, 6           ; save (get&push) ES.base
                        mov     bx, es        获取ES段的基地址
                        int     31h
                        push    cx        将 ES 基地址保存在堆栈上
                        push    dx

                        mov     ax, 7           ; set ES.base
                        mov     bx, es        设置 ES 段的基地址......
                        push    idtr_base  ; CX:DX=newnase=IDTR.base (此处 newnase 是打字错误,应为 newbase)
                        pop     dx              ......为中断描述符表的基地址
                        pop     cx
                        int     31h

把 ES 指向中断描述符表,目的就是要修改中断描述符表。
ring3 程序可以修改中断描述符表,并进入 ring0,这应该属于 DPMI 的一个漏洞。

; by default ES points to PSP and ES.limit is 0FFh,
; so we can increase it a little w/o problems

DPMI 在默认时设置 ES 指向 PSP,段限是 0FFh(其实就是通常所说的 100h)。
所以我们可以把段限增大一点,没问题。

段限其实准备增大到中断描述符表的长度,也就是 2K。

; DPMI host is big madafucka, it dont allows you to set selectorlimit >= 2GB

去它大爷的,DPMI 服务端真该死,它不允许你设置段限为 2GB 或更多。

那就设置段限为 2K 吧,反正也够用了。

                        mov     ax, 8           ; set ES.limit
                        mov     bx, es
                        mov     cx, 0           ; CX:DX=newlimit=maxIDTlimit
                        mov     dx, 256*8-1      (这就是 2K)
                        int     31h

                        mov     ax, 0006h       ; get CS.base into CX:DX
                        mov     bx, cs
                        int     31h        获取 CS 基地址

                        add     dx, offset __ring0 ;calc lin. addr of __ring0
                        adc     cx, 0           ; [BUGFIX] was: dx
                        push    cx
                        push    dx
                        pop     ebp        __ring0 的线性地址放在 ebp 中

                        xchg    bp, es:[0]              ; INT00 <--> __ring0
                        rol     ebp, 16
                        xchg    bp, es:[6]   
修改中断描述符表的int 00表项,使其指向 __ring0
                        xor     dx, dx
                        xor     cx, cx        除以零,故意制造故障或异常
                        div     cx     ;  call INT 00

除以零以后,会跳到 __ring0 处,执行 32 位保护模式的 ring0 代码(异常处理代码)。

异常处理结束后,回到这里继续运行。由于异常处理用 iret 结束,所以,

此时已经回到 16 位保护模式,ring3 权限了。

                        xchg    bp, es:[6]              ; INT00 <--> __ring0
                        rol     ebp, 16
                        xchg    bp, es:[0]  恢复中断描述符表原来的int00指针

                        mov     ax, 7           ; restore(pop&set) ES.base
                        mov     bx, es        恢复 ES 原来的基地址
                        pop     dx
                        pop     cx
                        int     31h

ES 段限不必恢复,大一点没关系。

__exit:                 mov     ax, 4c00h       ; exit
                        int     21h

在 DPMI 的保护模式下,可以直接执行 int21h/4C00h,退出DOS。
我们在 int13 handler 里面,当然不可以这么做。

在 int13 handler 里面,此时我们必须做一个额外的工作。
我们需要从 16 位保护模式切换到 VM86 模式,
这是因为 int13 handler 本来就运行在 VM86 模式。
如果继续保持 16 位保护模式的话,
在 int13 handler 的处理全部完成、准备最后执行 iret 返回到调用者的时候,就完蛋了。

我们可以通过调用 int31h/AX=301h 来切换到 VM86 模式。这个调用的名称是:
Call Real Mode Procedure With Far Return Frame。参见

; DOS PROTECTED MODE INTERFACE(DPMI) SPECIFICATION Version 1.0
; March 12, 1991
; Application Program Interface (API) for Protected Mode DOS Applications
; © Copyright The DPMI Committee, 1989-1991.
; All rights reserved.

; http://www.sudleyplace.com/dpmione/dpmispec1.0.pdf

调用之后,我们不要用 RETF 指令返回到保护模式。因为我们的目的只是进入 VM86 模式而已。

既然访问高位内存的工作已经完成,
此刻我们需要跳转到(或返回到) int13 handler 的某个合适的地方,这样就平滑过渡到了原来的流程,继续运行。

__ring0:                int 3                   ; PROT32/R0

                        inc     cx   ; inc ecx (!)
这条指令让 CX 不再是 0,保证 “除以零” 这个故障不会反复发生,而只发生一次。
这是因为,新型 CPU 把 “除以零” 作为故障,而故障的处理程序在 iret 结束后,
会再次跳到(返回到)出现故障的这条指令,重复执行一次。
也就是说,如果此时 CX 仍然是零,那么,故障将再次触发,
这样,就会无限循环,死机。

我们的 ring0 代码,应该插入这里。

此刻处于 32 位保护模式,ring0 权限。

我们的 ring0 代码需要进入 long 模式,
访问 4G 以上高位内存中的扇区数据,
然后再回到 32 位保护模式。

                        iret

这条 iret 会返回到先前的 16 位保护模式(ring3)代码中。

; ---------------------------------------------------------------------------

dpmicall                dd      ?

idtr                    label   fword
idtr_limit              dw      ?
idtr_base               dd      ?

                        even
                        db      1024 dup (?)
endofstack:

memory                  equ     ($-start+256+15)/16

                        end     start


点评

good!!!  发表于 2023-10-14 13:07
回复

使用道具 举报

64#
发表于 2023-10-14 12:58:03 | 只看该作者
谢谢分享
回复

使用道具 举报

65#
发表于 2023-10-14 14:30:03 | 只看该作者
前面的帖子,是说可以参考 Z0MBiE 的代码,利用 DPMI 的漏洞获取 ring0 权限从而进入 long 模式,实现高位内存的访问。

如果不利用漏洞,而是想办法给 Win9x 的 VMM(虚拟机管理器,或虚拟机监控器)打补丁,让它能够访问高位内存,那就更好。当然了,这就相当于写一个 VxD 驱动程序了,甚至比写 VxD 还要难,因为我们无法获得 VMM 的源代码,只能靠反汇编。为 VMM 打补丁就是给它增加一个 int 功能调用,类似于 int15h/87h,但能够访问 4G 以上的高位内存。然后让 grub4dos 的 int13 handler 调用它即可。

能够运行 win98 的硬件,已经消失殆尽了。所以,以上提到的这些代码和方法,也都没什么实际价值。它仅有的价值,大概也只是作为教学的材料,用来练习 intel cpu 的汇编指令。一个有漏洞的 Win98,也不可能成为人们普遍采纳的、主流的操作系统。就是说,在未来,整个 Win98 系统,主要的用途,大概也只是作为一个 intel CPU 指令集的实验教材。前面提到的这些方法,如果你通过学习,能够成功实现,那么,你对于 intel 指令集的学习(就好比说,这是一道闯关题),就算是过关了。
回复

使用道具 举报

66#
发表于 2024-2-26 21:10:27 | 只看该作者
谢谢分享
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|Archiver|捐助支持|无忧启动 ( 闽ICP备05002490号-1 )

闽公网安备 35020302032614号

GMT+8, 2024-11-2 05:34

Powered by Discuz! X3.3

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表