Windows 2K不用驱动进入ring0(实现部分)

来源:互联网 发布:桌面软件 webui 编辑:程序博客网 时间:2024/05/17 08:10

(******************************************************************************
*   CopyRight (c) By 姚佩云 2004
*   All Right Reserved
*   Email : i_rock_1001@163.com www.jynx.com.cn
*   Date    :
*       New Develop   : 2004-x-x
*       Modified      : 2004-03-24
*   Description :
*       这是一个从ring3层不用驱动直接进入ring0层的例子,参考的网上资料
*   Export  :
*       ReadWritePhyMem : ring3下读写物理内存
*       ExecRing0Proc   : ring3下执行ring0级别的函数
*   Thanks  :
*       alphax(多喝了三五杯) http://expert.csdn.net/Expert/topic/2718/2718748.xml?temp=8.550662E-02
*       tt.t                 http://www.delphibbs.com/delphibbs/dispq.asp?lid=2470866
*   首发大富翁(www.delphibbs.com)blog,转载请保留
******************************************************************************)
unit Ring0;

interface
uses
    Windows,SysUtils,Aclapi,Accctrl,NtDll{这是ntdll.dll的函数声明};
type

    _GDTENTRYR = packed record
        Limit    : WORD ;
        BaseLow  : WORD ;
        BaseHigh : WORD ;
    end;
    TGDTENTRYR = _GDTENTRYR;
    PGDTENTRYR = ^TGDTENTRYR;

    _CALLGATE_DESCRIPTOR = packed record
        Offset_0_15                : WORD;
        Selector                   : WORD ;
        ParamCount_SomeBits        : Byte ;  // ParamCount:4 SomeBits:4
        Type_AppSystem_Dpl_Present : Byte ;  // Type:4 AppSystem:1 Dpl:2 Present:1
        Offset_16_31               : WORD ;
    end;
    TCALLGATE_DESCRIPTOR = _CALLGATE_DESCRIPTOR;
    PCALLGATE_DESCRIPTOR = ^TCALLGATE_DESCRIPTOR;
const
    ObjectPhysicalMemoryDeviceName = '/Device/Physicalmemory';



function ReadWritePhyMem(Address: DWORD; Length: DWORD; Buffer: PChar;ReadOrNot: Boolean = True): Boolean;
function ExecRing0Proc( Entry,seglen : ULONG):Boolean;

implementation

function SetPhysicalMemorySectionCanBeWrited(hSection: THandle): Boolean;
var
  pDacl: PACL;
  pNewDacl: PACL;
  pSD: PPSECURITY_DESCRIPTOR;
  dwRes: Cardinal;
  ea: EXPLICIT_ACCESS_A;
  label CleanUp;
begin
  Result:=False;

  pDacl:=Nil;
  pNewDacl:=Nil;
  pSD:=Nil;

  dwres:=GetSecurityInfo(hSection,SE_KERNEL_OBJECT,DACL_SECURITY_INFORMATION,nil,
    nil,@pDacl,nil,pSD);
  try
    if dwres<>ERROR_SUCCESS then
      Exit;

    FillChar(ea,SizeOf(EXPLICIT_ACCESS),0);
    ea.grfAccessPermissions:=SECTION_MAP_WRITE;
    ea.grfAccessMode:=GRANT_ACCESS;
    ea.grfInheritance:=NO_INHERITANCE;
    ea.Trustee.TrusteeForm:=TRUSTEE_IS_NAME;
    ea.Trustee.TrusteeType:=TRUSTEE_IS_USER;
    ea.Trustee.ptstrName:='CURRENT_USER';
    SetEntriesInAcl(1,@ea,Nil,pNewDacl);

    dwRes:=SetSecurityInfo(hSection,SE_KERNEL_OBJECT,DACL_SECURITY_INFORMATION,
      Nil,Nil,pNewDacl,Nil);
    if dwRes=ERROR_SUCCESS then
      Exit;

    Result:=True;
  finally
    if pSD<>Nil then
      LocalFree(Cardinal(pSD^));
    if pNewDacl<>Nil then
      LocalFree(Cardinal(pSD^));
  end;
end;

function GetPhysicalAddress(vAddress:ULONG):LARGE_INTEGER;

begin

   if (vAddress < $80000000) or (vAddress >= $A0000000) then
      Result.QuadPart  :=  vAddress and $FFFF000
   else
      Result.QuadPart  :=  vAddress and $1FFFF000;

end;

function OpenPhysicalMemory(ReadOrNot: Boolean): THandle;
var
  Status: NTSTATUS;
  PhysMem: THandle;
  PhysMemString: UNICODE_STRING;
  Attributes: TNtObjectAttributes;
  SectionAttrib: Integer;
begin
  Result:=0;
  RtlInitUnicodeString(@PhysMemString,ObjectPhysicalMemoryDeviceName);
  InitializeObjectAttributes(@Attributes,
            @PhysMemString,
            OBJ_CASE_INSENSITIVE or OBJ_KERNEL_HANDLE,
            0,
            Nil);

  if ReadOrNot then
    SectionAttrib:=SECTION_MAP_READ
  else
    SectionAttrib:=SECTION_MAP_READ or SECTION_MAP_WRITE;
  Status:=ZwOpenSection(@PhysMem,SectionAttrib,@Attributes);
  if not ReadOrNot then
  begin
    if Status=STATUS_ACCESS_DENIED then
    begin
      Status:=ZwOpenSection(@PhysMem,READ_CONTROL or WRITE_DAC,@Attributes);
      SetPhysicalMemorySectionCanBeWrited(PhysMem);
      ZwClose(PhysMem);
      Status:=ZwOpenSection(@PhysMem,SectionAttrib,@Attributes);
    end;
  end;
  if not NT_SUCCESS(Status) then
    Exit;

  Result:=PhysMem;
end;

function MapPhysicalMemory(ReadOrNot: Boolean; PhysicalMemory: THandle;
  Address: DWORD; Length: DWORD; var VirtualAddress: pointer): Boolean;
var
  Access: Cardinal;
  Status: NTSTATUS;
  Base:LARGE_INTEGER;

    SystemInfo: TSystemInfo;
    Offset,Granularity: ULONG;
begin
  Result := FALSE;


    GetSystemInfo(SystemInfo);
    Granularity := SystemInfo.dwAllocationGranularity;
    Offset := Address mod Granularity;
    Length := Length + Offset;


  if ReadOrNot then
    Access:=PAGE_READONLY
  else
    Access:=PAGE_READWRITE;
  VirtualAddress :=nil;
  Base:=GetPhysicalAddress(Address-Offset);
  status := NtMapViewOfSection(PhysicalMemory,
        THandle(-1),
        VirtualAddress,
        0,
        Length,
        Base,
        Length,
        ViewShare,
        0,
        Access);

  if not NT_SUCCESS(Status) then
    Exit;
  VirtualAddress:=Pointer(DWORD(VirtualAddress)+Offset);
  //Inc(DWORD(VirtualAddress),Address Mod $1000);
  Result:=True;
end;

procedure UnMapPhysicalMemory(Address: Pointer);
begin
  NtUnmapViewOfSection(THandle(-1), Address);
end;


function ReadWritePhyMem(Address: DWORD; Length: DWORD; Buffer: PChar;
  ReadOrNot: Boolean = True): Boolean;
var
  PhysMem: THandle;
  vAddress: Pointer;
begin
  Result:=False;

  PhysMem:=OpenPhysicalMemory(ReadOrNot);
  if PhysMem=0 then
    Exit;

  if not MapPhysicalMemory(ReadOrNot,PhysMem,Address,Length,vAddress) then
    Exit;

  try
    if ReadOrNot then
      Move(vAddress^,Buffer^,Length)
    else
      Move(Buffer^,vAddress^,Length);

    Result:=True;
  except
    on E: Exception do

      MessageBox(0,PChar('缓冲区长度不足或内存跨段。'#13+
        '每个内存段为 4KB 的整数倍,每次读写不能跨越多个不同的内存段。'),
        '错误',MB_ICONERROR+MB_OK+MB_SYSTEMMODAL);

  end;

  UnMapPhysicalMemory(vAddress);
  ZwClose(PhysMem);
end;


function InstallCallgate(Section:THandle; FunProc:ULONG):ULONG;
var
    gdt : TGDTENTRYR;
begin
    asm sgdt gdt end;
end;

function ExecRing0Proc( Entry,seglen : ULONG):Boolean;
var
    gdt : TGDTENTRYR;
    cg  : PCALLGATE_DESCRIPTOR;

    PhysMem: THandle;
    ReadOrNot: Boolean ;
    Address : ULONG;
    vAddress: Pointer;

    bType : Byte;

    _farcall:array [0..2]of word;

begin

    ReadOrNot := FALSE;
    asm sgdt gdt end;

    PhysMem:=OpenPhysicalMemory(ReadOrNot);
    if PhysMem=0 then
        Exit;

    Address := (gdt.BaseHigh shl 16) or gdt.BaseLow;

    if not MapPhysicalMemory(ReadOrNot,PhysMem,Address,gdt.Limit+1,vAddress) then
        Exit;

    cg := PCALLGATE_DESCRIPTOR(ULONG(vAddress)+(gdt.Limit and $FFF8));
    while ( ULONG(cg) > ULONG(vAddress)) do
    begin

        bType := cg.Type_AppSystem_Dpl_Present ;
        bType := bType shr 4; //btmp := cg.type
        if( bType = 0) then
        begin
            cg.offset_0_15 := LOWORD(Entry);
            cg.selector := 8;
            cg.ParamCount_SomeBits := 0;
            {
            cg->type = 0xC;             // 386 call gate
            cg->app_system = 0;      // A system descriptor
            cg->dpl = 3;             // Ring 3 code can call
            cg->present = 1;
            }
            //cg.Type_AppSystem_Dpl_Present :=$C7;
            cg.Type_AppSystem_Dpl_Present :=$EC;

            cg.Offset_16_31 := HIWORD(Entry);
            break;
        end;
        Dec(cg);
    end;

    _farcall[2]:=(ULONG(cg)-ULONG(vAddress)) or 3;  //Ring 3 callgate;

    if(not VirtualLock(pointer(Entry),seglen)) then
        exit;

    SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_TIME_CRITICAL);

    Sleep(0);

    asm
        lea eax, _farcall
        DB 0FFH, 018H           //call fword ptr [eax]
    end;

    SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_NORMAL);

    VirtualUnlock(pointer(Entry),seglen);

    //Clear callgate
    PPointer(cg)^ := nil;
    Inc(cg);
    PPointer(cg)^ := nil;
    cg.Offset_0_15 :=0;
    cg.Selector :=0;
    cg.ParamCount_SomeBits :=0;
    cg.Type_AppSystem_Dpl_Present :=0;
    cg.Offset_16_31 :=0;

    UnMapPhysicalMemory(vAddress);
    ZwClose(PhysMem);

    Result := TRUE;
end;

end.