网上很多文章都有关于SSDT的完整的实现,但是没有关于Shadow SSDT的完整实现,目前最好的文章是《shadow ssdt学习笔记 by zhuwg》,我这里的程序也很多参考了他的文章,在这里谢谢了。我这里给出一个hook shadow ssdt的完整实现的驱动和3层的代码。
这里主要是hook 了NtUserFindWindowEx,NtUserBuildHwndList,NtUserQueryWindow,NtUserGetForegroundWindow,NtUserWindowFromPoint来防止其他应用程序通过FindWindow,EnumWindow,WindowFromPoint,GetForegroundWindow这些函数来枚举我们的窗口,不过这个程序对于GetWindowText这个东西无法防护,如果有朋友在驱动层实现了对该函数的保护,是否能一起交流呢。
关于hook的流程,看了上面zhuwg的文章,大家应该很好的了解了。下面的代码也很简单。大家随便看看吧,通信方面,随便使用了METHOD_NEITHER方法,这个方法不好,有问题,不过懒得改了,懂驱动的应该很容易改为BUFFERED模式吧。
在这里谢谢给了很多帮助的各位牛人,特别是NetRoc,很细心的帮我测试。。
代码:
#include <ntddk.h> #include <windef.h> #include <stdio.h> #include <string.h> #include "HookShadowSSDT.h" VOID UnloadDriver(IN PDRIVER_OBJECT DriverObject); NTSTATUS HideProcess_Create(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); NTSTATUS HideProcess_Close(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); NTSTATUS HideProcess_IoControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); PVOID GetInfoTable(ULONG ATableType); HANDLE GetCsrPid(); VOID InitCallNumber(); NTSTATUS PsLookupProcessByProcessId(IN ULONG ulProcId, OUT PEPROCESS * pEProcess); ///////////////声明Native API/////////////////////////////////////// typedef NTSTATUS (*NTUSERFINDWINDOWEX)( IN HWND hwndParent, IN HWND hwndChild, IN PUNICODE_STRING pstrClassName OPTIONAL, IN PUNICODE_STRING pstrWindowName OPTIONAL, IN DWORD dwType); typedef NTSTATUS (*NTUSERBUILDHWNDLIST)( IN HDESK hdesk, IN HWND hwndNext, IN ULONG fEnumChildren, IN DWORD idThread, IN UINT cHwndMax, OUT HWND *phwndFirst, OUT ULONG *pcHwndNeeded); typedef UINT_PTR (*NTUSERQUERYWINDOW)( IN ULONG WindowHandle, IN ULONG TypeInformation); typedef ULONG (*NTUSERGETFOREGROUNDWINDOW)(VOID); typedef HWND (*NTUSERWINDOWFROMPOINT)(LONG, LONG); NTSTATUS ZwQuerySystemInformation( IN ULONG SystemInformationClass, IN PVOID SystemInformation, IN ULONG SystemInformationLength, OUT PULONG ReturnLength); NTSTATUS ZwDuplicateObject( IN HANDLE SourceProcessHandle, IN PHANDLE SourceHandle, IN HANDLE TargetProcessHandle, OUT PHANDLE TargetHandle, IN ACCESS_MASK DesiredAccess OPTIONAL, IN BOOLEAN InheritHandle, IN ULONG Options ); NTSTATUS ZwQueryObject( IN HANDLE ObjectHandle, IN ULONG ObjectInformationClass, OUT PVOID ObjectInformation, IN ULONG ObjectInformationLength, OUT PULONG ReturnLength OPTIONAL); NTSTATUS PsLookupProcessByProcessId( IN ULONG ulProcId, OUT PEPROCESS * pEProcess); NTSTATUS KeAttachProcess(PEPROCESS pPeb); NTSTATUS KeDetachProcess(); NTSTATUS MyNtUserFindWindowEx( IN HWND hwndParent, IN HWND hwndChild, IN PUNICODE_STRING pstrClassName OPTIONAL, IN PUNICODE_STRING pstrWindowName OPTIONAL, IN DWORD dwType); NTSTATUS MyNtUserBuildHwndList( IN HDESK hdesk, IN HWND hwndNext, IN ULONG fEnumChildren, IN DWORD idThread, IN UINT cHwndMax, OUT HWND *phwndFirst, OUT ULONG* pcHwndNeeded); UINT_PTR MyNtUserQueryWindow( IN ULONG WindowHandle, IN ULONG TypeInformation); ULONG MyNtUserGetForegroundWindow(VOID); HWND MyNtUserWindowFromPoint(LONG x, LONG y); __declspec(dllimport) _stdcall KeAddSystemServiceTable(PVOID, PVOID, PVOID, PVOID, PVOID); ////////////////////定义所用到的全局变量/////////////// __declspec(dllimport) ServiceDescriptorTableEntry KeServiceDescriptorTable; unsigned long OldCr0; UNICODE_STRING DeviceNameString; UNICODE_STRING LinkDeviceNameString; NTUSERFINDWINDOWEX g_OriginalNtUserFindWindowEx; NTUSERBUILDHWNDLIST g_OriginalNtUserBuildHwndList; NTUSERQUERYWINDOW g_OriginalNtUserQueryWindow; NTUSERGETFOREGROUNDWINDOW g_OriginalNtUserGetForegroundWindow; NTUSERWINDOWFROMPOINT g_OriginalNtUserWindowFromPoint; PEPROCESS crsEProc; CCHAR outBuf[1024]; //输入缓冲区大小 HANDLE ProcessIdToProtect = (HANDLE)0; //保护的句柄 ULONG NtUserFindWindowEx_callnumber = 0; //NtUserFindWindowEx的服号 ULONG NtUserGetForegroundWindow_callnumber = 0; ULONG NtUserQueryWindow_callnumber = 0; ULONG NtUserBuildHwndList_callnumber = 0; ULONG NtUserWindowFromPoint_callnumber = 0; ULONG LastForegroundWindow; unsigned int getAddressOfShadowTable() { unsigned int i; unsigned char *p; unsigned int dwordatbyte; p = (unsigned char*) KeAddSystemServiceTable; for(i = 0; i < 4096; i++, p++) { __try { dwordatbyte = *(unsigned int*)p; } __except(EXCEPTION_EXECUTE_HANDLER) { return 0; } if(MmIsAddressValid((PVOID)dwordatbyte)) { if(memcmp((PVOID)dwordatbyte, &KeServiceDescriptorTable, 16) == 0) { if((PVOID)dwordatbyte == &KeServiceDescriptorTable) { continue; } return dwordatbyte; } } } return 0; } ULONG getShadowTable() { KeServiceDescriptorTableShadow = (PServiceDescriptorTableEntry) getAddressOfShadowTable(); if(KeServiceDescriptorTableShadow == NULL) { DbgPrint("hooker.sys: Couldnt find shadowtable!"); return FALSE; } else { DbgPrint("hooker.sys: Shadowtable has been found!"); DbgPrint("hooker.sys: Shadowtable entries: %d", KeServiceDescriptorTableShadow[1].NumberOfServices); return TRUE; } } //根据操作系统来确定具体函数的服务号 VOID InitCallNumber() { ULONG majorVersion, minorVersion; PsGetVersion( &majorVersion, &minorVersion, NULL, NULL ); if ( majorVersion == 5 && minorVersion == 2 ) { DbgPrint("comint32: Running on Windows 2003"); NtUserFindWindowEx_callnumber = 0x179; NtUserGetForegroundWindow_callnumber = 0x193; NtUserBuildHwndList_callnumber = 0x137; NtUserQueryWindow_callnumber = 0x1E1; NtUserWindowFromPoint_callnumber = 0x24C; } else if ( majorVersion == 5 && minorVersion == 1 ) { DbgPrint("comint32: Running on Windows XP"); NtUserFindWindowEx_callnumber = 0x17A; NtUserGetForegroundWindow_callnumber = 0x194; NtUserBuildHwndList_callnumber = 0x138; NtUserQueryWindow_callnumber = 0x1E3; NtUserWindowFromPoint_callnumber = 0x250; } else if ( majorVersion == 5 && minorVersion == 0 ) { DbgPrint("comint32: Running on Windows 2000"); NtUserFindWindowEx_callnumber = 0x170; NtUserGetForegroundWindow_callnumber = 0x189; NtUserBuildHwndList_callnumber = 0x12E; NtUserQueryWindow_callnumber = 0x1D2; NtUserWindowFromPoint_callnumber = 0x238; } } PVOID GetInfoTable(ULONG ATableType) { ULONG mSize = 0x4000; PVOID mPtr = NULL; NTSTATUS St; do { mPtr = ExAllocatePool(PagedPool, mSize); memset(mPtr, 0, mSize); if (mPtr) { St = ZwQuerySystemInformation(ATableType, mPtr, mSize, NULL); } else return NULL; if (St == STATUS_INFO_LENGTH_MISMATCH) { ExFreePool(mPtr); mSize = mSize * 2; } } while (St == STATUS_INFO_LENGTH_MISMATCH); if (St == STATUS_SUCCESS) return mPtr; ExFreePool(mPtr); return NULL; } HANDLE GetCsrPid() { HANDLE Process, hObject; HANDLE CsrId = (HANDLE)0; OBJECT_ATTRIBUTES obj; CLIENT_ID cid; UCHAR Buff[0x100]; POBJECT_NAME_INFORMATION ObjName = (PVOID)&Buff; PSYSTEM_HANDLE_INFORMATION_EX Handles; ULONG r; Handles = GetInfoTable(SystemHandleInformation); if (!Handles) return CsrId; for (r = 0; r < Handles->NumberOfHandles; r++) { if (Handles->Information[r].ObjectTypeNumber == 21) //Port object { InitializeObjectAttributes(&obj, NULL, OBJ_KERNEL_HANDLE, NULL, NULL); cid.UniqueProcess = (HANDLE)Handles->Information[r].ProcessId; cid.UniqueThread = 0; if (NT_SUCCESS(NtOpenProcess(&Process, PROCESS_DUP_HANDLE, &obj, &cid))) { if (NT_SUCCESS(ZwDuplicateObject(Process, (HANDLE)Handles->Information[r].Handle,NtCurrentProcess(), &hObject, 0, 0, DUPLICATE_SAME_ACCESS))) { if (NT_SUCCESS(ZwQueryObject(hObject, ObjectNameInformation, ObjName, 0x100, NULL))) { if (ObjName->Name.Buffer && !wcsncmp(L"\\Windows\\ApiPort", ObjName->Name.Buffer, 20)) { CsrId = (HANDLE)Handles->Information[r].ProcessId; } } ZwClose(hObject); } ZwClose(Process); } } } ExFreePool(Handles); return CsrId; } BOOLEAN Sleep(ULONG MillionSecond) { NTSTATUS st; LARGE_INTEGER DelayTime; DelayTime = RtlConvertLongToLargeInteger(-10000*MillionSecond); st=KeDelayExecutionThread( KernelMode, FALSE, &DelayTime ); return (NT_SUCCESS(st)); } NTSTATUS DriverEntry (IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath) { NTSTATUS status; PDEVICE_OBJECT deviceObject; RtlInitUnicodeString( &DeviceNameString, HIDE_PROCESS_WIN32_DEV_NAME ); RtlInitUnicodeString( &LinkDeviceNameString,HIDE_PROCESS_DEV_NAME ); KdPrint(("DriverEntry Enter............................\n")); status = IoCreateDevice( DriverObject, 0, &DeviceNameString, FILE_DEVICE_DISK_FILE_SYSTEM, FILE_DEVICE_SECURE_OPEN, FALSE, & deviceObject ); if (!NT_SUCCESS( status )) { KdPrint(( "DriverEntry: Error creating control device object, status=%08x\n", status )); return status; } status = IoCreateSymbolicLink( (PUNICODE_STRING) &LinkDeviceNameString, (PUNICODE_STRING) &DeviceNameString ); if (!NT_SUCCESS(status)) { IoDeleteDevice(deviceObject); return status; } //获得shadow的地址 getShadowTable(); //根据不同的系统获得不同的函数服务号 InitCallNumber(); DriverObject->MajorFunction[IRP_MJ_CREATE] = HideProcess_Create; DriverObject->MajorFunction[IRP_MJ_CLOSE] = HideProcess_Close; DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = HideProcess_IoControl; DriverObject->DriverUnload=UnloadDriver; status = PsLookupProcessByProcessId((ULONG)GetCsrPid(), &crsEProc); if (!NT_SUCCESS( status )) { DbgPrint("PsLookupProcessByProcessId() error\n"); return status; } KeAttachProcess(crsEProc); __try { if ((KeServiceDescriptorTableShadow!=NULL) \ && (NtUserFindWindowEx_callnumber!=0) && (NtUserGetForegroundWindow_callnumber!=0) \ && (NtUserBuildHwndList_callnumber!=0) && (NtUserQueryWindow_callnumber!=0) \ && (NtUserWindowFromPoint_callnumber!=0)) { g_OriginalNtUserFindWindowEx = (NTUSERFINDWINDOWEX)KeServiceDescriptorTableShadow[1].ServiceTableBase[NtUserFindWindowEx_callnumber]; g_OriginalNtUserQueryWindow=(NTUSERQUERYWINDOW)KeServiceDescriptorTableShadow[1].ServiceTableBase[NtUserQueryWindow_callnumber]; g_OriginalNtUserBuildHwndList=(NTUSERBUILDHWNDLIST)KeServiceDescriptorTableShadow[1].ServiceTableBase[NtUserBuildHwndList_callnumber]; g_OriginalNtUserGetForegroundWindow=(NTUSERGETFOREGROUNDWINDOW)KeServiceDescriptorTableShadow[1].ServiceTableBase[NtUserGetForegroundWindow_callnumber]; g_OriginalNtUserWindowFromPoint = (NTUSERWINDOWFROMPOINT)KeServiceDescriptorTableShadow[1].ServiceTableBase[NtUserWindowFromPoint_callnumber]; } else KeServiceDescriptorTableShadow=NULL; _asm { CLI //dissable interrupt MOV EAX, CR0 //move CR0 register into EAX AND EAX, NOT 10000H //disable WP bit MOV CR0, EAX //write register back } if ((KeServiceDescriptorTableShadow!=NULL) && (NtUserFindWindowEx_callnumber!=0) && (NtUserGetForegroundWindow_callnumber!=0) && (NtUserBuildHwndList_callnumber!=0) && (NtUserQueryWindow_callnumber!=0)) { (NTUSERFINDWINDOWEX)(KeServiceDescriptorTableShadow[1].ServiceTableBase[NtUserFindWindowEx_callnumber]) = MyNtUserFindWindowEx; (NTUSERQUERYWINDOW)KeServiceDescriptorTableShadow[1].ServiceTableBase[NtUserQueryWindow_callnumber] = MyNtUserQueryWindow; (NTUSERBUILDHWNDLIST)KeServiceDescriptorTableShadow[1].ServiceTableBase[NtUserBuildHwndList_callnumber] = MyNtUserBuildHwndList; (NTUSERGETFOREGROUNDWINDOW)KeServiceDescriptorTableShadow[1].ServiceTableBase[NtUserGetForegroundWindow_callnumber] = MyNtUserGetForegroundWindow; (NTUSERWINDOWFROMPOINT)KeServiceDescriptorTableShadow[1].ServiceTableBase[NtUserWindowFromPoint_callnumber] = MyNtUserWindowFromPoint; } _asm { MOV EAX, CR0 //move CR0 register into EAX OR EAX, 10000H //enable WP bit MOV CR0, EAX //write register back STI //enable interrupt } } __finally { KeDetachProcess(); } return status ; } NTSTATUS HideProcess_Create(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { DbgPrint("HideProcess_Create\n"); Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); return Irp->IoStatus.Status; } NTSTATUS HideProcess_Close(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { DbgPrint("HideProcess_Close\n"); Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); return Irp->IoStatus.Status; } NTSTATUS HideProcess_IoControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { NTSTATUS status = STATUS_SUCCESS; ULONG controlCode; PIO_STACK_LOCATION irpStack; HANDLE hEvent; OBJECT_HANDLE_INFORMATION objHandleInfo; ULONG outputLength, inputLength; PVOID inputBuffer; DWORD dd; irpStack = IoGetCurrentIrpStackLocation(Irp); outputLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength; inputLength=irpStack->Parameters.DeviceIoControl.InputBufferLength; controlCode = irpStack->Parameters.DeviceIoControl.IoControlCode; DbgPrint("IN CONTROL\r\n"); switch(controlCode) { case IO_PROTECT: ProcessIdToProtect = (HANDLE)irpStack->Parameters.DeviceIoControl.Type3InputBuffer; DbgPrint("IO_PROTECT:%d", ProcessIdToProtect); break; default: break; } Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); return status; } VOID UnloadDriver(IN PDRIVER_OBJECT DriverObject) { UNICODE_STRING uniWin32NameString; UNICODE_STRING LinkNameString; PDEVICE_OBJECT deviceObject; NTSTATUS status; status = PsLookupProcessByProcessId((ULONG)GetCsrPid(), &crsEProc); if (!NT_SUCCESS( status )) { DbgPrint("PsLookupProcessByProcessId() error\n"); return ; } KeAttachProcess(crsEProc); //////////////////////UnHook ZwQuerySystemInformation///////////////////////////////////////////////// __try { _asm { CLI //dissable interrupt MOV EAX, CR0 //move CR0 register into EAX AND EAX, NOT 10000H //disable WP bit MOV CR0, EAX //write register back } if ((KeServiceDescriptorTableShadow!=NULL) && (NtUserFindWindowEx_callnumber!=0) && (NtUserGetForegroundWindow_callnumber!=0) && (NtUserBuildHwndList_callnumber!=0) && (NtUserQueryWindow_callnumber!=0)) { (NTUSERFINDWINDOWEX)(KeServiceDescriptorTableShadow[1].ServiceTableBase[NtUserFindWindowEx_callnumber]) = g_OriginalNtUserFindWindowEx; (NTUSERQUERYWINDOW)KeServiceDescriptorTableShadow[1].ServiceTableBase[NtUserQueryWindow_callnumber] = g_OriginalNtUserQueryWindow; (NTUSERBUILDHWNDLIST)KeServiceDescriptorTableShadow[1].ServiceTableBase[NtUserBuildHwndList_callnumber] = g_OriginalNtUserBuildHwndList; (NTUSERGETFOREGROUNDWINDOW)KeServiceDescriptorTableShadow[1].ServiceTableBase[NtUserGetForegroundWindow_callnumber] = g_OriginalNtUserGetForegroundWindow; (NTUSERWINDOWFROMPOINT)KeServiceDescriptorTableShadow[1].ServiceTableBase[NtUserWindowFromPoint_callnumber] = g_OriginalNtUserWindowFromPoint; } _asm { MOV EAX, CR0 //move CR0 register into EAX OR EAX, 10000H //enable WP bit MOV CR0, EAX //write register back STI //enable interrupt } } __finally { KeDetachProcess(); Sleep(50); } deviceObject= DriverObject->DeviceObject; IoDeleteSymbolicLink(&LinkDeviceNameString); ASSERT(!deviceObject->AttachedDevice); if ( deviceObject != NULL ) { IoDeleteDevice( deviceObject ); } } NTSTATUS MyNtUserFindWindowEx( IN HWND hwndParent, IN HWND hwndChild, IN PUNICODE_STRING pstrClassName OPTIONAL, IN PUNICODE_STRING pstrWindowName OPTIONAL, IN DWORD dwType) { ULONG result; result = g_OriginalNtUserFindWindowEx(hwndParent, hwndChild, pstrClassName, pstrWindowName, dwType); if (PsGetCurrentProcessId()!=ProcessIdToProtect) { ULONG ProcessID; ProcessID = g_OriginalNtUserQueryWindow(result, 0); DbgPrint("ProcessID:%d", ProcessID); if (ProcessID==(ULONG)ProcessIdToProtect) return 0; } return result; } NTSTATUS MyNtUserBuildHwndList(IN HDESK hdesk, IN HWND hwndNext, IN ULONG fEnumChildren, IN DWORD idThread, IN UINT cHwndMax, OUT HWND *phwndFirst, OUT ULONG* pcHwndNeeded) { NTSTATUS result; if (PsGetCurrentProcessId()!=ProcessIdToProtect) { ULONG ProcessID; if (fEnumChildren==1) { ProcessID = g_OriginalNtUserQueryWindow((ULONG)hwndNext, 0); if (ProcessID==(ULONG)ProcessIdToProtect) return STATUS_UNSUCCESSFUL; } result = g_OriginalNtUserBuildHwndList(hdesk,hwndNext,fEnumChildren,idThread,cHwndMax,phwndFirst,pcHwndNeeded); if (result==STATUS_SUCCESS) { ULONG i=0; ULONG j; while (i<*pcHwndNeeded) { ProcessID=g_OriginalNtUserQueryWindow((ULONG)phwndFirst[i],0); if (ProcessID==(ULONG)ProcessIdToProtect) { for (j=i; j<(*pcHwndNeeded)-1; j++) phwndFirst[j]=phwndFirst[j+1]; phwndFirst[*pcHwndNeeded-1]=0; (*pcHwndNeeded)--; continue; } i++; } } return result; } return g_OriginalNtUserBuildHwndList(hdesk,hwndNext,fEnumChildren,idThread,cHwndMax,phwndFirst,pcHwndNeeded); } ULONG MyNtUserGetForegroundWindow(VOID) { ULONG result; result= g_OriginalNtUserGetForegroundWindow(); if (PsGetCurrentProcessId()!=ProcessIdToProtect) { ULONG ProcessID; ProcessID=g_OriginalNtUserQueryWindow(result, 0); if (ProcessID == (ULONG)ProcessIdToProtect) result=LastForegroundWindow; else LastForegroundWindow=result; } return result; } UINT_PTR MyNtUserQueryWindow(IN ULONG WindowHandle,IN ULONG TypeInformation) { ULONG WindowHandleProcessID; if (PsGetCurrentProcessId()!=ProcessIdToProtect) { WindowHandleProcessID = g_OriginalNtUserQueryWindow(WindowHandle,0); if (WindowHandleProcessID==(ULONG)ProcessIdToProtect) return 0; } return g_OriginalNtUserQueryWindow(WindowHandle,TypeInformation); } HWND MyNtUserWindowFromPoint(LONG x, LONG y) { return 0; }