Delphi 能不能从Ring 3进入Ring 0?
有例子吗?
多谢.

解决方案 »

  1.   

    我发现了一篇发表在1999.11.29 b13版的
    《令win32应用程序跳入系统层》东南大学 卢威 [email protected]
    是用vc++嵌汇编做的,
    很接近了,可试试BCB或DELPHI进入Ring0
    东南大学卢威1999.12发表在<<计算机世界>>报上的一篇
    <<WIN32跳入系统0层>>,原采用VC++编程,现改成C++Builder
    供诸位参考,DELPHI类似; 
    void Ring0Proc()  // 在Ring0中执行你自已的代码
    {
        // .......
        asm mov eax,CR0;  // 试验一下Ring3不能执行的特权指令
        // .......
    }
    // =====================================================
    void  __declspec(naked) NewInt() //新中断
    {
          Ring0Proc();
          asm  iretd;
    }
    #define  IntNo  9
    DWORDLONG  IDTR,SavedGate;
    WORD OurGate[4]={0,0x0028,0xee00,0x0000};
    void  GotoRing0()
    {
          asm
            {
                mov  eax,offset NewInt;
                mov  [OurGate],ax;
                shr  eax,16;
                mov  [OurGate+6],ax;
                sidt fword ptr IDTR;
                mov  ebx,dword ptr [IDTR+2];
                add  ebx,IntNo*8;
                mov  edi,offset SavedGate;
                mov  esi,ebx;
                movsd;
                movsd;
                mov  edi,ebx;
                mov  esi,offset OurGate;
                movsd;
                movsd;
                int  IntNo;
                mov  edi,ebx;  // 开始恢复原中断门
                mov  esi,offset SavedGate;
                movsd;
                movsd;
            }
    }
    // ===================================================void __fastcall TForm1::Button1Click(TObject *Sender)
    {
        GotoRing0();
    }
    ***********************************************编译是通过了,你自己调试一下吧。
    lea    esi, MyInt; 一句语法应该有逻辑错误,要在Debug中仔细看一下。procedure MyInt;
    asm
      // 这里面的内容可要你自己写哦。
    end;const HookExceptionNumber = 3;procedure GetRing0;
    asm
    // 连续压入8个字节作为缓冲区
    push    eax
    push    eax;// 取得idt偏移,共6字节,含段选择子2字节,偏移4字节。
    sidt    [esp-02h]; // Get IDT Base Address// 弹出4字节偏移
    pop    ebx;// 每个中断门8字节,所以偏移是HookExceptionNumber*08h
    // 另外的4字节是定位到中心,因为中断门的4字节偏移分开放在8字节的0、1、6、7中。
    // 0、1存放偏移低16位,6、7存放高16位。2,3是段选择子。4、5是门属性。
    add    ebx, HookExceptionNumber*08h + 04h;// 关中断,准备修改idt。
    cli// 取得中断门的4、5、6、7字节,其中6、7字节在ebp高16位
    mov    ebp, [ebx]; // Get Exception Base// 取得中断门的0、1字节到bp(实际上是ebp的低16位)。
    mov    bp, [ebx-04h]; // Entry Point
    // 这样就合成了完整的32位偏移。// 取得自己中断函数入口地址,放入esi中。
    lea    esi, MyInt;  // 压入堆栈
    push    esi// 填充入口低16位到中断门0、1字节。
    mov    [ebx-04h], si;// 将高16位移动到低16位。
    shr    esi, 16; // Modify Exception// 填充入口高16位到中断门6、7字节。
    mov    [ebx+02h], si; // Entry Point Address// idt修改完毕。// 调整堆栈
    pop    esi// 此时堆栈比初始状态多压8字节。估计是在引发的中断中处理。
    // ebp的初始中断入口估计也是在自己的中断函数中用于恢复现场。// 后面的就是引发软中断,取得ring0权力。
    // 不过说句老实话。CIH的创意是不错,不过CIH的汇编的水平其实很一般。int    HookExceptionNumber; // GenerateException// ReadyRestoreSE:
    stiend;
    ----------------------------------
    const IntNo=9;var
    IDTR,SavedGate:int64;
    OurGate:array[0..3] of word=(0,$0028,$ee00,$0000);procedure Ring0Proc;  // 在Ring0中执行你自已的代码
    begin
        // .......
        asm
        mov eax,CR0;  // 试验一下Ring3不能执行的特权指令
        end;
    end;
    // =====================================================
    procedure   NewInt(); //新中断
    begin
          Ring0Proc();
          asm
          iretd;
          end;
    end;procedure  GotoRing0;
    begin
          asm
                mov  eax,offset NewInt;
                mov  word ptr[OurGate],ax;
                shr  eax,16;
                mov  word ptr[OurGate+6],ax;
                sidt fword ptr IDTR;//在Delphi中应该改成:lea ebx, idtr;     sidt [ebx]
                mov  ebx,dword ptr [IDTR+2];
                add  ebx,IntNo*8;
                mov  edi,offset SavedGate;
                mov  esi,ebx;
                movsd;
                movsd;
                mov  edi,ebx;
                mov  esi,offset OurGate;
                movsd;
                movsd;
                int  IntNo;
                mov  edi,ebx;  // 开始恢复原中断门
                mov  esi,offset SavedGate;
                movsd;
                movsd;
            end;
    end;
    // ===================================================procedure TForm1.Button1Click(Sender: TObject);
    begin
     gotoring0;
    end;
    ********************************
    const IntNo=3;//var
    //IDTR,SavedGate:int64;procedure Ring0Proc;  // 在Ring0中执行你自已的代码
    begin
        // .......
    //    showmessage('kfsdj;fk');
        asm
        mov eax,CR0;  // 试验一下Ring3不能执行的特权指令
        end;
    end;
    // =====================================================
    procedure   NewInt(); //新中断
    begin
          Ring0Proc();
          asm
          iretd;
          end;
    end;procedure  GotoRing0;
    begin
          asm
                mov  edi,offset buf;
                sidt [edi];    //Get IDT-->buf;
                mov ebx,[edi+2]   //求中断门基址
                add ebx,IntNo*8;
                mov esi,ebx;
                push edi;
                push esi;
                movsd;
                movsd;
                cli;
                mov eax,offset newint;
                mov [ebx],ax;
                shr eax,16;
                mov [ebx+6],ax;
                mov ax,0ee00h;
                mov [ebx+4],ax;
                int intno;
                pop edi
                pop esi;
                movsd;
                movsd;
                sti;
            end;
    end;
      

  2.   

    在WIN9X下用SIDT指令获取IDT基地址,修改IDT,增加一中断服务,使其指向应用程序.也可调用VXD间接得到RING0.WINNT/2000下,直接读写物理内存,或将程序虚拟线性地址转换为物理地址.因为NT下只有驱动和内核运行在RING0,所以只有通过驱动来读写端口.
      

  3.   

    楼主看了这本书就知道了,专门将了这个问题。
    飞思科技的《WINDOWS 核心编程》
      

  4.   

    如果DELPHI对DDK支持好,就完全可以,我也正在学习!
      

  5.   

    可以,我实现了
    http://www.delphibbs.com/keylife/iblog_show.asp?xid=6679
    http://www.delphibbs.com/keylife/iblog_show.asp?xid=6680
    http://www.delphibbs.com/keylife/iblog_show.asp?xid=6681
      

  6.   

    嗯上面的方法挺好的
    与我写的很接近啦只是Xp/2003下通过ZwSystemDebugControl还能支持访问虚拟地址在8000000H上的空间
    而我实现FarCall使用的是另外的方法:内存Patch技术,比你的略为复杂点,但效果是一样的还有一个问题,VM上无法运行这个程序的,因为VM下,系统的GDT不在4MB区域,基本上都是FFC07000h的,且就算用别的工具访问到了,读出来的都是无效的0,看来是VM的奇怪“问题”,我就解决不了了http://lysoft.7u7.net
      

  7.   

    代码只能在 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.
      

  8.   

    谢谢各位老大.To:ypyRock(Rock)
    我看过了你的例子,很佩服!!!!!procedure TForm1.Button2Click(Sender: TObject); 
    出错的问题也找到原因了,是没有保护现场.把ExecRing0Proc的定义改为下面这样就可以了.
    function ExecRing0Proc( Entry,seglen : ULONG):Boolean; stdcall;我想在问一下老大,我怎么在rang0下用API啊?就是平常这样用吗?多谢.
      

  9.   

    不是代码被覆盖了,还是保护现场的问题.procedure TForm1.Button2Click(Sender: TObject);
    var
        s:string;
        i:integer;
    begin
      self.Memo1.Lines.Add ( 'aa');
      ZeroMemory(@R0Data, SizeOf(R0Data));
      VirtualLock(@R0Data, SizeOf(R0Data));
        ExecRing0Proc0(ULONG(@Ring0Func),$100);
      VirtualUnlock(@R0Data, SizeOf(R0Data));
      //&iquest;&Eacute;&Auml;&Uuml;&Ecirc;&Ccedil;&para;&Ntilde;&Otilde;&raquo;±&raquo;&AElig;&AElig;&raquo;&micro;&Aacute;&Euml;&pound;&not;&Otilde;&acirc;&Agrave;&iuml;&micro;÷&Oacute;&Atilde;&frac34;&Iacute;&sup3;&ouml;&acute;í&pound;&not;&cedil;&szlig;&Ecirc;&Ouml;°&iuml;&iquest;&acute;&iquest;&acute;
      i:= R0Data.mrc0;
      s:=IntToHex(i, 8);
      caption := s;
      self.Memo1.Lines.Add ( 'aa');
      Memo1.Lines.Add ('CR2        = $'+ IntToHex(R0Data.mrc2, 8));
      Memo1.Lines.Add ('CR3        = $'+ IntToHex(R0Data.mrc3, 8));end;function ExecRing0Proc0( Entry,seglen : dword):Boolean;
    asm
      push ebx
      push seglen
      push Entry
      call ExecRing0Proc
      pop ebx
    end;这样就可以了.
      

  10.   

    呵呵,我早就自己搞定了R3->R0的实现:)R0下不能使用普通的API的,可能都未必有问题,但建议都不要这样做只能使用Zw的API或NtOSkrnl.exe中的APIR0下出错将会导致系统Reboot的,所以R0下不要做太多的东西http://lysoft.7u7.net
      

  11.   

    to  ly_liuyang(Liu Yang) 
      Zw的API或NtOSkrnl.exe中的API 能不能给个例子?
      多谢.
      

  12.   

    NTDDK的API都是Zw开头的VA->PA的实现:procedure Ring0Func; stdcall;
    begin
      asm
        pushad
        pushf
        cli    mov esi, MemoryAddress.VirtualAddress
        push esi
        call _MmGetPhysicalAddress
        mov MemoryAddress.PhysicalAddress.LowPart, eax  // save low part of LARGE_INTEGER
        mov MemoryAddress.PhysicalAddress.HighPart, edx       // save high part of LARGE_INTEGER    popf
        popad
        retf
      end;
    end;procedure MmGetPhysicalAddress;
    var hNTDll: THandle;
    begin
      _MmGetPhysicalAddress := 0;
      hNTDll := LoadLibrary('ntoskrnl.exe');
      if hNTDll <> 0 then
         begin
           _MmGetPhysicalAddress := NTOSBaseAddr + Cardinal(GetProcAddress(hNTDll, 'MmGetPhysicalAddress')) - hNTDll;
           FreeLibrary(hNTDll);
    //       ShowMessage(Format('Virtual address of MmGetPhysicalAddress in Kernel Mode  : %s', [IntToHex(_MmGetPhysicalAddress, 8)]));
         end;
      if _MmGetPhysicalAddress > 0 then ExecRing0Proc(@Ring0Func, 32);
    end;呵呵,NT OS Kernel的东西哦你不是有什么特殊的需求,最好不要随便用Ring0,作为技术研究还可以,真要做事情,还是老实用SYS的WDM驱动才是正路,Delphi不适合做这些事情的,选择VC吧,真的要Delphi就需要借助WinDriver这样的驱动开发包http://lysoft.7u7.net
      

  13.   

    多谢。
    我是想把验证的代码放在Ring0运行,如果通过了,就在Ring0修改code区。
    我不知道能不能实现。
      

  14.   

    关于LYSoft版本可见
    http://community.csdn.net/Expert/topic/3570/3570742.xml?temp=.5977899完整的见
    http://blog.csdn.net/ly_liuyang/archive/2004/11/20/189013.aspx只是数值计算是可以的,但你要注意Ring0的代码是占用100%CPU的,不要过于复杂
    另外这个方法是由条件限制的:不能在VM或VPC上使用,必须是管理员帐户登陆,系统允许调试权限http://lysoft.7u7.net
      

  15.   

    只能在98中运行,NT都不可以
    CIH的做法就是这样的,这样的东西省省吧