Author:bujin888
Recently many of driver's tutorial wrote with delphi on forum, Want to show my study results, share for everyone.
code:
unit Driver;
interface
uses
nt_status,ntoskrnl,ntutils;
const
DeviceName = '\Device\360safeBoxA';
DosDeviceName = '\DosDevices\360safeBoxA';
IOCTL_HOOK_START = $0022E000;
IOCTL_HOOK_STOP = $0022E004;
IOCTL_PROTECT_PROCESS = $0022E200;
IOCTL_PROTECT_HWND = $0022E201;
IOCTL_PROTECT_OTHER = $0022E204;
var
DosDevName: TUnicodeString;
TempSafeId:Handle=0;
TempSafehandle:Handle=0;
function _DriverEntry(pDriverObject: PDriverObject; RegistryPath: PUnicodeString) : NTSTATUS; stdcall;
implementation
uses hooking;
function hookCreate(ADeviceObject: PDeviceObject; AIrp: PIrp): NTSTATUS; stdcall;
begin
Result := STATUS_SUCCESS;
AIrp^.IoStatus.Status := Result;
IoCompleteRequest(AIrp, IO_NO_INCREMENT);
end;
function hookClose(ADeviceObject: PDeviceObject; AIrp: PIrp): NTSTATUS; stdcall;
begin
Result := STATUS_SUCCESS;
AIrp^.IoStatus.Status := Result;
IoCompleteRequest(AIrp, IO_NO_INCREMENT);
end;
function hookDeviceControl(ADeviceObject: PDeviceObject; AIrp:PIrp): NTSTATUS; stdcall;
var
LStack: PIO_STACK_LOCATION;
pIOBuffer: Pointer;
LBufInLen, LBufOutLen,
LCode, LRet,OutByteCount: ULONG;
begin
LStack := IoGetCurrentIrpStackLocation(AIrp);
Result := STATUS_SUCCESS;
AIrp^.IoStatus.Information := 0;
LCode := LStack^.Parameters.DeviceIoControl.IoControlCode;
pIOBuffer := AIrp^.AssociatedIrp.SystemBuffer;
LBufInLen := LStack^.Parameters.DeviceIoControl.InputBufferLength;
LBufOutLen := LStack^.Parameters.DeviceIoControl.OutputBufferLength;
OutByteCount:=0;
case LCode of
IOCTL_HOOK_START: begin
LRet := HookingHook;
OutByteCount:=4;
LONG(pIOBuffer^):=LRet;
end;
IOCTL_HOOK_STOP: begin
LRet := HookingUnhook;
OutByteCount:=4;
LONG(pIOBuffer^):=LRet;
end;
IOCTL_PROTECT_PROCESS: begin
TempSafeId:=Handle(pIOBuffer^);
SetSafeId(TempSafeId);
OutByteCount:=4;
LONG(pIOBuffer^):=Integer(True);
end;
IOCTL_PROTECT_HWND:begin
TempSafehandle:=Handle(pIOBuffer^);
SetSafehandle(TempSafehandle);
OutByteCount:=4;
LONG(pIOBuffer^):=Integer(True);
end;
IOCTL_PROTECT_OTHER: begin
DoPub;
OutByteCount:=4;
LONG(pIOBuffer^):=Integer(True);
end;
else
Result := STATUS_INVALID_DEVICE_REQUEST;
AIrp^.IoStatus.Information := 0;
end;
AIrp^.IoStatus.Status := Result;
AIrp^.IoStatus.Information := OutByteCount;
IoCompleteRequest(AIrp, IO_NO_INCREMENT);
end;
procedure DriverUnload(pDriverObject: PDriverObject); stdcall;
begin
HookingUnhook;
IoDeleteSymbolicLink(@DosDevName);
IoDeleteDevice(pDriverObject^.DeviceObject);
end;
function _DriverEntry(pDriverObject: PDriverObject; RegistryPath: PUnicodeString) : NTSTATUS; stdcall;
var
LDevName: TUnicodeString;
LDevObj: PDeviceObject;
begin
RtlInitUnicodeString(LDevName, DeviceName);
RtlInitUnicodeString(DosDevName, DosDeviceName);
Result := IoCreateDevice(pDriverObject,0, @LDevName,
FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, LDevObj);
if NT_SUCCESS(Result) then
begin
pDriverObject^.MajorFunction[IRP_MJ_CREATE] := @hookCreate;
pDriverObject^.MajorFunction[IRP_MJ_CLOSE] := @hookClose;
pDriverObject^.MajorFunction[IRP_MJ_DEVICE_CONTROL] := @hookDeviceControl;
pDriverObject^.DriverUnload := @DriverUnload;
Result := IoCreateSymbolicLink(@DosDevName, @LDevName);
if not NT_SUCCESS(Result) then
begin
IoDeleteDevice(pDriverObject^.DeviceObject);
end;
end;
end;
end.
interface
uses
nt_status,ntoskrnl,ntutils;
const
DeviceName = '\Device\360safeBoxA';
DosDeviceName = '\DosDevices\360safeBoxA';
IOCTL_HOOK_START = $0022E000;
IOCTL_HOOK_STOP = $0022E004;
IOCTL_PROTECT_PROCESS = $0022E200;
IOCTL_PROTECT_HWND = $0022E201;
IOCTL_PROTECT_OTHER = $0022E204;
var
DosDevName: TUnicodeString;
TempSafeId:Handle=0;
TempSafehandle:Handle=0;
function _DriverEntry(pDriverObject: PDriverObject; RegistryPath: PUnicodeString) : NTSTATUS; stdcall;
implementation
uses hooking;
function hookCreate(ADeviceObject: PDeviceObject; AIrp: PIrp): NTSTATUS; stdcall;
begin
Result := STATUS_SUCCESS;
AIrp^.IoStatus.Status := Result;
IoCompleteRequest(AIrp, IO_NO_INCREMENT);
end;
function hookClose(ADeviceObject: PDeviceObject; AIrp: PIrp): NTSTATUS; stdcall;
begin
Result := STATUS_SUCCESS;
AIrp^.IoStatus.Status := Result;
IoCompleteRequest(AIrp, IO_NO_INCREMENT);
end;
function hookDeviceControl(ADeviceObject: PDeviceObject; AIrp:PIrp): NTSTATUS; stdcall;
var
LStack: PIO_STACK_LOCATION;
pIOBuffer: Pointer;
LBufInLen, LBufOutLen,
LCode, LRet,OutByteCount: ULONG;
begin
LStack := IoGetCurrentIrpStackLocation(AIrp);
Result := STATUS_SUCCESS;
AIrp^.IoStatus.Information := 0;
LCode := LStack^.Parameters.DeviceIoControl.IoControlCode;
pIOBuffer := AIrp^.AssociatedIrp.SystemBuffer;
LBufInLen := LStack^.Parameters.DeviceIoControl.InputBufferLength;
LBufOutLen := LStack^.Parameters.DeviceIoControl.OutputBufferLength;
OutByteCount:=0;
case LCode of
IOCTL_HOOK_START: begin
LRet := HookingHook;
OutByteCount:=4;
LONG(pIOBuffer^):=LRet;
end;
IOCTL_HOOK_STOP: begin
LRet := HookingUnhook;
OutByteCount:=4;
LONG(pIOBuffer^):=LRet;
end;
IOCTL_PROTECT_PROCESS: begin
TempSafeId:=Handle(pIOBuffer^);
SetSafeId(TempSafeId);
OutByteCount:=4;
LONG(pIOBuffer^):=Integer(True);
end;
IOCTL_PROTECT_HWND:begin
TempSafehandle:=Handle(pIOBuffer^);
SetSafehandle(TempSafehandle);
OutByteCount:=4;
LONG(pIOBuffer^):=Integer(True);
end;
IOCTL_PROTECT_OTHER: begin
DoPub;
OutByteCount:=4;
LONG(pIOBuffer^):=Integer(True);
end;
else
Result := STATUS_INVALID_DEVICE_REQUEST;
AIrp^.IoStatus.Information := 0;
end;
AIrp^.IoStatus.Status := Result;
AIrp^.IoStatus.Information := OutByteCount;
IoCompleteRequest(AIrp, IO_NO_INCREMENT);
end;
procedure DriverUnload(pDriverObject: PDriverObject); stdcall;
begin
HookingUnhook;
IoDeleteSymbolicLink(@DosDevName);
IoDeleteDevice(pDriverObject^.DeviceObject);
end;
function _DriverEntry(pDriverObject: PDriverObject; RegistryPath: PUnicodeString) : NTSTATUS; stdcall;
var
LDevName: TUnicodeString;
LDevObj: PDeviceObject;
begin
RtlInitUnicodeString(LDevName, DeviceName);
RtlInitUnicodeString(DosDevName, DosDeviceName);
Result := IoCreateDevice(pDriverObject,0, @LDevName,
FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, LDevObj);
if NT_SUCCESS(Result) then
begin
pDriverObject^.MajorFunction[IRP_MJ_CREATE] := @hookCreate;
pDriverObject^.MajorFunction[IRP_MJ_CLOSE] := @hookClose;
pDriverObject^.MajorFunction[IRP_MJ_DEVICE_CONTROL] := @hookDeviceControl;
pDriverObject^.DriverUnload := @DriverUnload;
Result := IoCreateSymbolicLink(@DosDevName, @LDevName);
if not NT_SUCCESS(Result) then
begin
IoDeleteDevice(pDriverObject^.DeviceObject);
end;
end;
end;
end.
Code:
unit hooking;
interface
uses
nt_status,ntoskrnl,ntutils,ssdthook;
type
TZwOpenProcess = function(ProcessHandle:PHandle; DesiredAccess:TAccessMask;
ObjectAttributes:PObjectAttributes;
ClientId:PClientId):NTSTATUS; stdcall;
TNtUserFindWindowEx= Function (hwndParent,hwndChild:Handle;
pstrClassName,pstrWindowName:PUnicodeString;
dwType:LONG):NTSTATUS;stdcall;
var
HookActive: Boolean=False;
OldZwOpenProcess:LONG=0;
OldNtUserFindWindowEx:LONG=0;
SafeId:Handle=0;
SafeHandle:Handle=0;
procedure SetSafeId(value:Handle);
procedure SetSafeHandle(value:Handle);
function HookingHook: Integer; stdcall;
function HookingUnhook: Integer; stdcall;
procedure DoPub;
implementation
procedure SetSafeId(value:Handle);
begin
SafeId:=value;
end;
procedure SetSafeHandle(value:Handle);
begin
SafeHandle:=value;
end;
function ZwOpenProcessAddr:Pointer;
begin
Result:=GetImportFunAddr(@ZwOpenProcess);
end;
function NewNtUserFindWindowEx(hwndParent,hwndChild:Handle;pstrClassName,pstrWindowName:PUnicodeString;dwType:LONG):NTSTATUS;stdcall;
begin
Result:=TNtUserFindWindowEx(pointer(OldNtUserFindWindowEx))(hwndParent,hwndChild,pstrClassName,pstrWindowName,dwType);
if Result=SafeHandle then Result:=0;
end;
function NewZwOpenProcess(ProcessHandle:PHandle; DesiredAccess:TAccessMask; ObjectAttributes:PObjectAttributes; ClientId:PClientId):NTSTATUS; stdcall;
var
Temp:Handle;
begin
Temp:=ProcessHandle^;
if Temp=SafeId then
Result:=0
else
Result:=TZwOpenProcess(pointer(OldZwOpenProcess))(ProcessHandle,DesiredAccess,ObjectAttributes, ClientId);
end;
function HookingHook: Integer; stdcall;
var
uCr0cpu:dword;
begin
if HookActive then
begin
Result:=Integer(False);
Exit;
end;
//关闭写保护
asm
cli
push eax
mov eax, cr0
mov [uCr0cpu], eax
and eax, not 000010000h
mov cr0, eax
pop eax
end;
OldZwOpenProcess:=InterlockedExchange(SystemServiceName(ZwOpenProcessAddr),LONG(@NewZwOpenProcess));
OldNtUserFindWindowEx:=InterlockedExchange(ShadowSystemServiceOrd($17a),LONG(@NewNtUserFindWindowEx));
// 打开写保护
asm
push eax
mov eax, [uCr0cpu]
mov cr0, eax
pop eax
sti
end;
HookActive := True;
Result := Integer(True);
end;
function HookingUnhook: Integer; stdcall;
var
uCr0cpu:dword;
begin
if not HookActive then
begin
Result:=Integer(False);
Exit;
end;
//关闭写保护
asm
cli
push eax
mov eax, cr0
mov [uCr0cpu], eax
and eax, not 000010000h
mov cr0, eax
pop eax
end;
InterlockedExchange(SystemServiceName(ZwOpenProcessAddr),OldZwOpenProcess);
InterlockedExchange(ShadowSystemServiceOrd($17a),OldNtUserFindWindowEx);
// 打开写保护
asm
push eax
mov eax, [uCr0cpu]
mov cr0, eax
pop eax
sti
end;
HookActive := False;
Result := Integer(True);
end;
procedure DoPub;
begin
DbgPrint('%08x',ShadowSystemServiceOrd(0));
DbgPrint('%08x',ShadowSystemServiceOrd(0)^);
end;
end.
For prevent some people do wrong with it, Only paste main functions
interface
uses
nt_status,ntoskrnl,ntutils,ssdthook;
type
TZwOpenProcess = function(ProcessHandle:PHandle; DesiredAccess:TAccessMask;
ObjectAttributes:PObjectAttributes;
ClientId:PClientId):NTSTATUS; stdcall;
TNtUserFindWindowEx= Function (hwndParent,hwndChild:Handle;
pstrClassName,pstrWindowName:PUnicodeString;
dwType:LONG):NTSTATUS;stdcall;
var
HookActive: Boolean=False;
OldZwOpenProcess:LONG=0;
OldNtUserFindWindowEx:LONG=0;
SafeId:Handle=0;
SafeHandle:Handle=0;
procedure SetSafeId(value:Handle);
procedure SetSafeHandle(value:Handle);
function HookingHook: Integer; stdcall;
function HookingUnhook: Integer; stdcall;
procedure DoPub;
implementation
procedure SetSafeId(value:Handle);
begin
SafeId:=value;
end;
procedure SetSafeHandle(value:Handle);
begin
SafeHandle:=value;
end;
function ZwOpenProcessAddr:Pointer;
begin
Result:=GetImportFunAddr(@ZwOpenProcess);
end;
function NewNtUserFindWindowEx(hwndParent,hwndChild:Handle;pstrClassName,pstrWindowName:PUnicodeString;dwType:LONG):NTSTATUS;stdcall;
begin
Result:=TNtUserFindWindowEx(pointer(OldNtUserFindWindowEx))(hwndParent,hwndChild,pstrClassName,pstrWindowName,dwType);
if Result=SafeHandle then Result:=0;
end;
function NewZwOpenProcess(ProcessHandle:PHandle; DesiredAccess:TAccessMask; ObjectAttributes:PObjectAttributes; ClientId:PClientId):NTSTATUS; stdcall;
var
Temp:Handle;
begin
Temp:=ProcessHandle^;
if Temp=SafeId then
Result:=0
else
Result:=TZwOpenProcess(pointer(OldZwOpenProcess))(ProcessHandle,DesiredAccess,ObjectAttributes, ClientId);
end;
function HookingHook: Integer; stdcall;
var
uCr0cpu:dword;
begin
if HookActive then
begin
Result:=Integer(False);
Exit;
end;
//关闭写保护
asm
cli
push eax
mov eax, cr0
mov [uCr0cpu], eax
and eax, not 000010000h
mov cr0, eax
pop eax
end;
OldZwOpenProcess:=InterlockedExchange(SystemServiceName(ZwOpenProcessAddr),LONG(@NewZwOpenProcess));
OldNtUserFindWindowEx:=InterlockedExchange(ShadowSystemServiceOrd($17a),LONG(@NewNtUserFindWindowEx));
// 打开写保护
asm
push eax
mov eax, [uCr0cpu]
mov cr0, eax
pop eax
sti
end;
HookActive := True;
Result := Integer(True);
end;
function HookingUnhook: Integer; stdcall;
var
uCr0cpu:dword;
begin
if not HookActive then
begin
Result:=Integer(False);
Exit;
end;
//关闭写保护
asm
cli
push eax
mov eax, cr0
mov [uCr0cpu], eax
and eax, not 000010000h
mov cr0, eax
pop eax
end;
InterlockedExchange(SystemServiceName(ZwOpenProcessAddr),OldZwOpenProcess);
InterlockedExchange(ShadowSystemServiceOrd($17a),OldNtUserFindWindowEx);
// 打开写保护
asm
push eax
mov eax, [uCr0cpu]
mov cr0, eax
pop eax
sti
end;
HookActive := False;
Result := Integer(True);
end;
procedure DoPub;
begin
DbgPrint('%08x',ShadowSystemServiceOrd(0));
DbgPrint('%08x',ShadowSystemServiceOrd(0)^);
end;
end.
For prevent some people do wrong with it, Only paste main functions
code:
// Get a address offunction from export table
function GetImportFunAddr(lpImportAddr: Pointer): Pointer; stdcall;
begin
Result := PPointer(PPointer(Cardinal(lpImportAddr) + 2)^)^;
end;
// KeServiceDescriptorTable+ ofsset with function's name calculate
function SystemServiceName(AFunc: Pointer): PLONG; stdcall;
var
lpKeServiceDescriptorTable: PServiceDescriptorEntry;
begin
lpKeServiceDescriptorTable := GetImportFunAddr(@KeServiceDescriptorTable);
Result := PLONG(Cardinal(lpKeServiceDescriptorTable^.ServiceTableBase) + (SizeOf(ULONG) * PULONG(ULONG(AFunc) + 1)^));
end;
// KeServiceDescriptorTable+ offset of sequence number's name calculate
function SystemServiceOrd(iOrd: ULONG): PLONG; stdcall;
var
lpKeServiceDescriptorTable: PServiceDescriptorEntry;
begin
lpKeServiceDescriptorTable := GetImportFunAddr(@KeServiceDescriptorTable);
Result := PLONG(PLONG(Cardinal(lpKeServiceDescriptorTable^.ServiceTableBase) + (SizeOf(ULONG) * iOrd)));
end;
function FindShadowTable:Pointer; //XP Vesion
var
lpKeServiceDescriptorTable:ULONG;
begin
lpKeServiceDescriptorTable := ULONG(GetImportFunAddr(@KeServiceDescriptorTable));
Result:=Pointer(lpKeServiceDescriptorTable-$40);
end;
function FindShadowTable2:Pointer;
var
cPtr, pOpcode:ULONG;
I:ULONG;
begin
Result:=nil;
cPtr:=ULONG(GetImportFunAddr(@KeAddSystemServiceTable));
I:=cPtr;
While (I<(cPtr+$1000)) Do
begin
if MmIsAddressValid(Pointer(I)) then
begin
if word(pointer(I)^)=$888d then
begin
Result:=PPointer(I+2)^;
break
end;
end;
I:=I+1;
end;
end;
//Offset of sequence number's name
function ShadowSystemServiceOrd(iOrd: ULONG): PLONG; stdcall;
var
lpKeServiceDescriptorTable:PShadowSrvDescriptorEntry;
begin
lpKeServiceDescriptorTable :=FindShadowTable2;
Result := PLONG(Cardinal(lpKeServiceDescriptorTable^.win32kTable.ServiceTableBase) + (SizeOf(ULONG) * iOrd));
end;
function GetImportFunAddr(lpImportAddr: Pointer): Pointer; stdcall;
begin
Result := PPointer(PPointer(Cardinal(lpImportAddr) + 2)^)^;
end;
// KeServiceDescriptorTable+ ofsset with function's name calculate
function SystemServiceName(AFunc: Pointer): PLONG; stdcall;
var
lpKeServiceDescriptorTable: PServiceDescriptorEntry;
begin
lpKeServiceDescriptorTable := GetImportFunAddr(@KeServiceDescriptorTable);
Result := PLONG(Cardinal(lpKeServiceDescriptorTable^.ServiceTableBase) + (SizeOf(ULONG) * PULONG(ULONG(AFunc) + 1)^));
end;
// KeServiceDescriptorTable+ offset of sequence number's name calculate
function SystemServiceOrd(iOrd: ULONG): PLONG; stdcall;
var
lpKeServiceDescriptorTable: PServiceDescriptorEntry;
begin
lpKeServiceDescriptorTable := GetImportFunAddr(@KeServiceDescriptorTable);
Result := PLONG(PLONG(Cardinal(lpKeServiceDescriptorTable^.ServiceTableBase) + (SizeOf(ULONG) * iOrd)));
end;
function FindShadowTable:Pointer; //XP Vesion
var
lpKeServiceDescriptorTable:ULONG;
begin
lpKeServiceDescriptorTable := ULONG(GetImportFunAddr(@KeServiceDescriptorTable));
Result:=Pointer(lpKeServiceDescriptorTable-$40);
end;
function FindShadowTable2:Pointer;
var
cPtr, pOpcode:ULONG;
I:ULONG;
begin
Result:=nil;
cPtr:=ULONG(GetImportFunAddr(@KeAddSystemServiceTable));
I:=cPtr;
While (I<(cPtr+$1000)) Do
begin
if MmIsAddressValid(Pointer(I)) then
begin
if word(pointer(I)^)=$888d then
begin
Result:=PPointer(I+2)^;
break
end;
end;
I:=I+1;
end;
end;
//Offset of sequence number's name
function ShadowSystemServiceOrd(iOrd: ULONG): PLONG; stdcall;
var
lpKeServiceDescriptorTable:PShadowSrvDescriptorEntry;
begin
lpKeServiceDescriptorTable :=FindShadowTable2;
Result := PLONG(Cardinal(lpKeServiceDescriptorTable^.win32kTable.ServiceTableBase) + (SizeOf(ULONG) * iOrd));
end;
can u give the code of SSDT shadow hooking
ReplyDelete