typedef struct _SYSTEM_SERVICE_TABLE { PVOID ServiceTableBase; //这个指向系统服务函数地址表 PULONG ServiceCounterTableBase; ULONG NumberOfService; //服务函数的个数,NumberOfService*4 就是整个地址表的大小 ULONG ParamTableBase; }SYSTEM_SERVICE_TABLE,*PSYSTEM_SERVICE_TABLE; typedef struct _SERVICE_DESCRIPTOR_TABLE { SYSTEM_SERVICE_TABLE ntoskrnel; //ntoskrnl.exe的服务函数 SYSTEM_SERVICE_TABLE win32k; //win32k.sys的服务函数,(gdi.dll/user.dll的内核支持) SYSTEM_SERVICE_TABLE NotUsed1; SYSTEM_SERVICE_TABLE NotUsed2; }SYSTEM_DESCRIPTOR_TABLE,*PSYSTEM_DESCRIPTOR_TABLE; |
nt!RtlpBreakWithStatusInstruction: 80527fc8 cc int 3 kd> dd KeServiceDescriptorTable 80553380 805021fc 00000000 0000011c 80502670 80553390 00000000 00000000 00000000 00000000 805533a0 00000000 00000000 00000000 00000000 805533b0 00000000 00000000 00000000 00000000 805533c0 00002710 bf80c227 00000000 00000000 805533d0 f9e6da80 f963a9e0 816850f0 806e0f40 805533e0 00000000 00000000 00000000 00000000 805533f0 97c5ac40 01c7abf5 00000000 00000000 |
kd> dd 805021fc 805021fc 80599746 805e6914 805ea15a 805e6946 8050220c 805ea194 805e697c 805ea1d8 805ea21c 8050221c 8060b880 8060c5d2 805e1cac 805e1904 8050222c 805ca928 805ca8d8 8060bea6 805ab334 8050223c 8060b4be 8059dbbc 805a5786 805cc406 8050224c 804ffed0 8060c5c4 8056be64 805353f2 8050225c 80604b90 805b19c0 805ea694 80619a56 8050226c 805eeb86 80599e34 80619caa 805996e6 |
kd> u 80599746 nt!NtAcceptConnectPort: 80599746 689c000000 push 9Ch 8059974b 6820a14d80 push offset nt!_real+0x128 (804da120) 80599750 e8abebf9ff call nt!_SEH_prolog (80538300) 80599755 64a124010000 mov eax,dword ptr fs:[00000124h] 8059975b 8a8040010000 mov al,byte ptr [eax+140h] 80599761 884590 mov byte ptr [ebp-70h],al 80599764 84c0 test al,al 80599766 0f84b9010000 je nt!NtAcceptConnectPort+0x1df (80599925) |
kd> u 805e6914 nt!NtAccessCheck: 805e6914 8bff mov edi,edi 805e6916 55 push ebp 805e6917 8bec mov ebp,esp 805e6919 33c0 xor eax,eax 805e691b 50 push eax 805e691c ff7524 push dword ptr [ebp+24h] 805e691f ff7520 push dword ptr [ebp+20h] 805e6922 ff751c push dword ptr [ebp+1Ch] |
/* 演示HOOK系统服务调用表中的NtOpenProcess函数,保护需要保护的进程被,防止被杀掉 */ #include<ntddk.h> /* KeServiceDescriptorTable仅有ntoskrnel一项,没有包含win32k,而且后面的两个字段都没有使用,所 以为了简便直接把SystemServiceDescriptorTable定义成SYSTEM_SERVICE_TABLE,免得访问多个结构体的 字段,麻烦。这里明白就行了。 */ typedef struct _SystemServiceDescriptorTable { PVOID ServiceTableBase; PULONG ServiceCounterTableBase; ULONG NumberOfService; ULONG ParamTableBase; }SystemServiceDescriptorTable,*PSystemServiceDescriptorTable; // KeServiceDescriptorTable为ntoskrnl.exe导出 extern PSystemServiceDescriptorTable KeServiceDescriptorTable; // 定义一下NtOpenProcess的原型,下面如果用汇编调用就不用定义了,但是我想尽量不用汇编 typedef NTSTATUS (__stdcall *NTOPENPROCESS)( OUT PHANDLE ProcessHandle, IN ACCESS_MASK AccessMask, IN POBJECT_ATTRIBUTES ObjectAttributes, IN PCLIENT_ID ClientId ); NTOPENPROCESS RealNtOpenProcess; // 定义函数原型 VOID Hook(); VOID Unhook(); VOID OnUnload(IN PDRIVER_OBJECT DriverObject); // 真实的函数地址,我们会在自定义的函数中调用 ULONG RealServiceAddress; // 需要被驱动保护的进程ID HANDLE MyPID; // 自定义的NtOpenProcess函数 NTSTATUS __stdcall MyNtOpenProcess( OUT PHANDLE ProcessHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, IN PCLIENT_ID ClientId ) { NTSTATUS rc; ULONG PID; //DbgPrint( "NtOpenProcess() called.\n" ); rc = (NTSTATUS)(NTOPENPROCESS)RealNtOpenProcess( ProcessHandle, DesiredAccess, ObjectAttributes, ClientId ); if( (ClientId != NULL) ) { PID = (ULONG)ClientId->UniqueProcess; //DbgPrint( "%d was opened,Handle is %d.\n", PID, (ULONG)ProcessHandle ); // 如果进程PID是1520,直接返回权限不足,并将句柄设置为空 if( PID == 1520 ) { DbgPrint( "Some want to open pid 1520!\n" ); ProcessHandle = NULL; rc = STATUS_ACCESS_DENIED; } } return rc; } // 驱动入口 NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath ) { DriverObject->DriverUnload = OnUnload; Hook(); return STATUS_SUCCESS; } // 驱动卸载 VOID OnUnload(IN PDRIVER_OBJECT DriverObject) { Unhook( ); } // 此处修改SSDT中的NtOpenProcess服务地址 VOID Hook() { ULONG Address; // 0x7A为Winxp+SP2下NtOpenProcess服务ID号 // Adress是个地址A,这个地址的数据还是一个地址B,这个地址B就是NtOpenProcess的地址了 // (ULONG)KeServiceDescriptorTable->ServiceTableBase就是温家堡的第一个房间 // Address是第7A个房间。 Address = (ULONG)KeServiceDescriptorTable->ServiceTableBase + 0x7A * 4; // 取得地址A的值,也就是NtOpenProcess服务的地址了,保存原来NtOpenProcess的地址以后恢 复用 RealServiceAddress = *(ULONG*)Address; RealNtOpenProcess = (NTOPENPROCESS)RealServiceAddress; DbgPrint( "Address of Real NtOpenProcess: 0x%08X\n", RealServiceAddress ); DbgPrint(" Address of MyNtOpenProcess: 0x%08X\n", MyNtOpenProcess ); // 去掉内存保护 __asm { cli mov eax, cr0 and eax, not 10000h mov cr0, eax } // 修改SSDT中NtOpenProcess服务的地址 *((ULONG*)Address) = (ULONG)MyNtOpenProcess; // 恢复内存保护 __asm { mov eax, cr0 or eax, 10000h mov cr0, eax sti } } ////////////////////////////////////////////////////// VOID Unhook() { ULONG Address; Address = (ULONG)KeServiceDescriptorTable->ServiceTableBase + 0x7A * 4; __asm { cli mov eax, cr0 and eax, not 10000h mov cr0, eax } // 还原SSDT *((ULONG*)Address) = (ULONG)RealServiceAddress; __asm { mov eax, cr0 or eax, 10000h mov cr0, eax sti } DbgPrint("Unhook"); } |