(******************************************************************************
* 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.
Windows 2K不用驱动进入ring0(实现部分)
最新推荐文章于 2011-04-29 16:06:00 发布