网上找到好多Ring3层运行Ring0级的资料,可惜都是Asm,C/C++的代码,有一个用Delphi编写VXD的例子,还只能在Delphi3上编译。经过多方参考,终于搞定。让各位大虾见笑了。此段代码只能在95/98中运行,其实原理和CIH的开头获取特权级部分一样。小弟很菜,不足之处请各位大虾指教。谢谢。 button1 : 直接执行Int 03h,在IDE环境中会产生单步调试的中断,独立运行会发生异常,是为了证明button2执行的代码正确性而设置的。 
button2 : 实际获取Ring 0 级的代码,使用了内嵌汇编。 
button3 : 停止button2中的发声 unit main; interface uses 
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, 
  StdCtrls; type 
  TForm1 = class(TForm) 
    Button1: TButton; 
    Button2: TButton; 
    Button3: TButton; 
    procedure Button1Click(Sender: TObject); 
    procedure Button2Click(Sender: TObject); 
    procedure Button3Click(Sender: TObject); 
  private 
    { Private declarations } 
  public 
    { Public declarations } 
  end; var 
  Form1: TForm1; 
 var  IDT : array [0..5] of byte; // 保存中断描述符表 
      lpOldGate : dword;          // 存放旧向量 
implementation {$R *.DFM} procedure aa; stdcall; 
const ExceptionUsed = $03;        // 中断号。 
begin 
   asm 
     sidt IDT                   //  读入中断描述符表 
     mov ebx, dword ptr [IDT+2]   
     add ebx, 8*ExceptionUsed 
     cli 
     mov dx, word ptr [ebx+6] 
     shl edx, 16d 
     mov dx, word ptr [ebx] 
     mov [lpOldGate], edx 
     mov eax, offset @@Ring0Code    // 修改向量,指向Ring0级代码段 
     mov word ptr [ebx], ax 
     shr eax, 16d 
     mov word ptr [ebx+6], ax 
     int ExceptionUsed             // 发生中断 
     mov ebx, dword ptr [IDT+2] 
     add ebx, 8*ExceptionUsed 
     mov edx, [lpOldGate] 
     mov word ptr [ebx], dx 
     shr edx, 16d 
     mov word ptr [ebx+6], dx      // 恢复被改了的向量 
     ret     @@Ring0Code:   // Ring0级代码段   
      mov eax,cr0  // 此句在Ring3级会发生异常错误 
      mov dx, $61  // 以下语句是为了证明执行了此段代码,让PCSpeak发声 
      mov al, $ff 
      out dx, al 
      mov dx, $43 
      mov al, $b6 
      out dx, al 
      mov dx, $42 
      mov al, $f0 
      out dx, al 
      mov dx, $42 
      mov al, $0 
      out dx, al 
      iretd         // 中断返回 
   end; 
end; procedure TForm1.Button1Click(Sender: TObject); 
begin 
    aa;      
end; procedure TForm1.Button2Click(Sender: TObject); 
begin 
    asm 
       int 03h           //  
    end; 
end; procedure TForm1.Button3Click(Sender: TObject); 
var bvalue : byte; 
   value : word; 
begin //  停止PCSpeak发声 
  asm 
     mov dx, $61 
     in al, dx 
     mov bValue, al 
  end ; 
  value := bValue and $fc; 
  bValue := Trunc(Value and 255); 
  asm 
    mov dx, $61 
   mov al, bValue 
   out dx, al 
  end; 
end; end. 

解决方案 »

  1.   

    找到一篇相关文章,也是用ASM众 所 周 知, 在Windows95/98 的Win32 on Intel x86 体 系 中 利 用 了 处 理 器 的 三 环 保 护 模 型 中 的 零 环(Ring0, 最 高 权 限 级 别) 和 三 环(Ring3, 最 低 权 限 级 别)。 一 般 应 用 程 序 都 运 行 在Ring3 下, 受 到 严 格 的" 保 护", 只 能 规  
    矩 地 使 用Win32API。 如 果 我 们 想 进 行 一 些 系 统 级 的 操 作, 例 如 在 嵌 入 汇 编 中 使 用 诸 如"Mov EAX,CR0", 或 像 在DOS 下 那 样 调 用 一 些 必 不 可 少 的 系 统 服 务( 如BIOS,DPMI 服 务) 而 用"Int xx", 都 会 导 致" 非 法 操 作"。 但  
    这 种 能 力 有 时 是 必 不 可 少 的, 一 到 这 种 时 候Microsoft 就 " 建 议 编 写 一 个VxD"。VxD 大 家 早 有 所 闻 了, 在VxD 里, 不 但 可 以 执 行CPU 的 所 有 指 令, 而 且 可 以 调 用VMM( 虚 拟 机 管 理 器) 和 其 他VxD 提 供 的 上 千 个 系 统 级 服  
    务。 获 得 这 一 能 力 的 最 本 质 原 因 在 于 它 运 行 在Ring0, 与 系 统 内 核 同 一 级 别。 但 是 它 体 系 的 复 杂 性、 开 发 工 具 的 不 易 获 得、 帮 助 文 档 的 不 完 备, 使Microsoft 排 除 了 一 大 批 程 序 员 和 竞 争 对 手。 而 将  
    在Windows2000(Windows98 也 开 始 支 持) 中 取 代VxD 的WDM 对Win95 程 序 员 也 是 个 噩 梦, 它 需 要 了 解Windows NT 核 心 驱 动 模 型。  
     
    ----有 没 有 简 单 一 些 的 办 法 呢 ? 我 们 可 以 令 一 个 普 通Win32 应 用 程 序 运 行 在Ring0 下, 从 而 获 得VxD 的 能 力 吗 ? 答 案 是 肯 定 的。 下 面 我 们 就 简 述 一 下 这 一 技 巧, 有 关Intel x86 保 护 模 式 的 基 础 知 识 请 大 家 看 有  
    关 书 籍。  
     
    ----首 先 此 技 巧 基 于 以 下 理 论 根 据:  
     
    ----一、SIDT 指 令( 将 中 断 描 述 符 表 寄 存 器 IDTR - -64 位 宽,16 ~47Bit 存 有 中 断 描 述 符 表IDT 基 地 址 - - 的 内 容 存 入 指 定 地 址 单 元) 不 是 特 权 指 令, 就 是 说 我 们 可 以 在Ring3 下 执 行 该 指 令, 获 得IDT 的 基 地 址,  
    从 而 修 改IDT, 增 加 一 个 中 断 门 安 置 我 们 的 中 断 服 务, 一 旦Ring3 程 序 中 产 生 此 中 断,VMM 就 会 调 用 此 中 断 服 务 程 序, 而 此 中 断 服 务 程 序 就 运 行 在Ring0 下 了。 这 一 点 与 在DOS 下 非 常 相 似。  
     
    ----二、Windows95 Win32 应 用 程 序 运 行 一 个 映 射 到 全 部4G 内 存 的 段 中, 选 择 子 为0137h,Ring0 中 的VxD 运 行 在 另 一 个 映 射 到 全 部4G 内 存 的 段 中, 选 择 子028h, 这 两 个 段 除 了 选 择 子 决 定 的 访 问 权 限 不 同 外, 没 什 么 不  
    同, 各 自 段 中 相 同 的 偏 移 量 对 应 了 相 同 的 线 性 地 址。 所 以 我 们 放 在Win32 应 用 程 序 中 的 中 断 服 务 程 序 可 以 以Ring3 的 段 偏 移 量 被Ring0 中 的VMM 寻 址。  
     
    ----下 面 我 们 以 具 体 例 子 进 一 步 说 明, 程 序 中 有 详 细 注 释。  
     
    ----这 是 一 个Win32 Console Program( 控 制 台 应 用 程 序), 虽 然 运 行 中 看 起 来 很 像DOS 筐 中 运 行 的 实 模 式DOS 程 序, 但 它 是 货 真 价 实 的 运 行 在Ring3 下 的Win32 程 序。 用Visual C + + 5.0 AppWizard 创 建 一 个Win32 Console Program  
    项 目, 添 加 以 下.CPP 文 件, 编 译 即 可。  
     
     #include 
     #include 
     #include 
     #include  
      // 若 无DDK 带 下 划 线 的 可 略 去, 
      这 些 语 句 演 示 了 调 用VMM/VXD 服 务 
    DWORDLONG IDTR,SavedGate; 
    WORD OurGate[4]={0,0x0028,0xee00,0x0000}; 
    // 中 断 门 描 述 符 格 式 如 下: 
     
     
     
    DWORD _eax,_ecx,_cr0; 
    WORD vmmver; 
    HVM sysvm; 
     
    void nothing() 

          //Used to test call in Ring0 
          sysvm=Get_Sys_VM_Handle(); 

     
    void __declspec( naked ) Ring0Proc(void) 
      // 中 断 例 程, 运 行 在Ring0 

          _asm{ 
                mov   _eax,eax    // 
                mov   _ecx,ecx    // 
                mov   eax, CR0     
       // 测 试Ring3 中 不 能 执 行 的 特 权 指 令 
                mov   _cr0,eax    // 
          } 
                VMMCall(Get_VMM_Version);  
      // 调 用VMM 服 务 
          _asm{ 
                mov vmmver,ax 
          } 
          nothing();   
      // 测 试 在 运 行 于Ring0 的  
        中 断 例 程 中 调 用 子 
          _asm  iretd    
      // 中 断 返 回, 与 在 实 模 式  
        编 程 无 本 质 区 别 

    void main() // 主 程 序 

          _asm{ 
          mov   eax, offset Ring0Proc 
          mov   [OurGate], ax  // 将 中 断 函 数 的 地 址 
          shr   eax, 16   // 填 入 新 造 的 中 断 门 
          mov   [OurGate +6], ax // 描 述 符 
     
          sidt  fword ptr IDTR     
      // 将 中 断 描 述 符 表 寄 存 器(IDTR) 
         的 内 容 取 出 
          mov   ebx, dword ptr [IDTR +2] 
      // 取 出 中 断 描 述 符 表(IDT) 基 地 址 
          add   ebx, 8 *9   
       // 计 算Int 9 的 描 述 符 应 放 置 的 地 址 选 用 
        Int9 是 因 为 它 在Win32 保 护 模 式 下 未 占 用 
     
          mov      edi, offset SavedGate 
          mov      esi, ebx 
          movsd   // 保 存 原 来 的Int 9 描 述 符 到 
          movsd  //SavedGate 以 便 恢 复 
     
          mov      edi, ebx 
          mov      esi, offset OurGate 
          movsd  // 替 换 原 来 的 中 断 门 描 述 符 
          movsd  // 以 安 装 中 断 服 务 例 程 
     
          mov   eax,0x6200  
       // 用 以 测 试 放 在EAX 中 的 数 据 
         能 否 正 确 传 到Ring0 中 断 
          mov   ecx,0  
       // 用 以 测 试 放 在ECX 中 的 数 据  
         能 否 正 确 传 到Ring0 中 断 
          mov   ecx,0  
       // 用 以 测 试 放 在ECX 中 的 数 据  
         能 否 正 确 传 到Ring0 中 断 
                   // 因 为 很 多VxD 服 务 都 用 
                     此 二 寄 存 器 传 递 参 数 
          int  9h   
         // 人 为 触 发 中 断, 平 时 会 出 现 
           保 护 错 误 蓝 屏 或 非 法 操 
                 // 作 对 话 框, 现 在 安 装 了 
                 // 中 断 服 务 例 程 后, 就 会 通 过 
                 //VMM 在Ring0 调 用 中 断 服 务 例 程 
                    - -Ring0Proc 
     
          mov    edi, ebx 
          mov    esi, offset SavedGate 
          movsd // 恢 复 原 来 的 中 断 门 描 述 符 
          movsd 
          } 
          cout<<"CR0="<<_cr0< 
     运 行 结 果: 
     
     
     
    ----此 方 法 的 好 处 一 是 回 避 了 奇 特 的VxD  
    文 件 格 式, 不 用 使 用 汇 编 语 言 编 程, 二 是 应 用 程 序 不 用 带 一 个 单  
    独 的VxD 文 件, 干 净 利 索。 
    ----值 得 一 提 的 是, 许 多 文 章 描 述 著 名 的 
    CIH 病 毒 都 说 其 利 用 了VxD 技 术, 是 说 它 带 一 个 单 独 的VxD 文 件  
    吗 ? 显 然 不 可 能, 实 际 上CIH 病 毒 使 用 的 就 是 以 上 技 巧, 进 入Ring0  
    后 调 用VMM 服 务 分 配 一 块 内 存, 把 自 身 拷 贝 进 去, 然 后 用IFS VxD 的 
    IFSMgr_InstallFileSystemApiHook 服 务 安 装 文 件 系 统 监 视 以 感 染 其 他 文  
    件, 只 不 过CIH 病 毒 安 装 的 是Int 3 中 断, 这 跟 在DOS 下 没 什 么 两 样。  
    我 们 也 可 以 对 此 了 解 以 更 好 地 防 范CIH 病 毒。 
    ----最 后 还 要 指 出 其 缺 陷, 这 个 技 巧 仅 能 用  
    在Windows95/97/98 下, 在Windows NT 下 行 不 通。 不 过 听 说CIH 病 毒 的 作 者  
    已 经 开 发 了NT 版 的CIH 病 毒, 说 明NT 中 也 有 类 似 的" 后 门"。