SSDT-フックとMDL



Ssdt Hook Mdl



最初に理解することは、SSDTHOOKは別の関数を記述し、SSDTテーブルのアドレスを置き換えることです。
SystemServiceTable

SystemServiceTable



システムサービステーブルにアクセスするにはどうすればよいですか?

SSDTのフルネームは、システムサービス記述子テーブル、システムサービス記述子テーブルです。

以下はグローバル変数です
kd> dd KeServiceDescriptorTable(SSDT)



このエクスポートされたステートメントはすぐに使用できます

kd> dd KeServiceDescriptorTableShadow(SSDTシャドウ)

この未輸出は他の方法で見つける必要があります



1 2 3 4 5 6 7 8 9 
kd> dd KeServiceDescriptorTable 83fac9c0 83ec0d9c 00000000 00000191 83ec13e4 83fac9d0 00000000 00000000 00000000 00000000 83fac9e0 83f1f6af 00000000 025355a9 000000bb 83fac9f0 00000011 00000100 5385d2ba d717548f 83faca00 83ec0d9c 00000000 00000191 83ec13e4 83faca10 956d6000 00000000 00000339 956d702c 83faca20 00000000 00000000 83faca24 00000340 83faca30 00000340 865fab00 00000007 00000000 

ここで、83ec0d9cは関数アドレス、00000191は関数の数、83ec13e4は関数パラメーターの数、単位は1バイトです。 4で割ると、関数アドレステーブル上の対応する関数の数になります。最初の関数は最初の数値です。

以下は機能アドレス表です

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 
kd> dd 83ec0d9c 83ec0d9c 840bcc28 83f0340d 8404cb68 83e6788a 83ec0dac 840be4ff 83f403fa 8412eb05 8412eb4e 83ec0dbc 840413bd 84148368 841495c1 84037b95 83ec0dcc 840c8b35 84121963 84074a56 840446cc 83ec0ddc 83fda928 84113898 8402b14e 8406da62 83ec0dec 840b9df1 8401b238 840b91fe 84038c0c 83ec0dfc 840ca5bc 8403b28f 840ca39c 840c2afc 83ec0e0c 8404d0f0 8410e657 840bfec9 840ca7ee According to this definition a structure //The following is the structure of the system service table typedef struct _KSYSTEM_SERVICE_TABLE { PULONG ServiceTableBase // Base address of service function address table PULONG ServiceCounterTableBase ULONG NumberOfService // Number of service functions PULONG ParamTableBase // Base address of service function parameter table } KSYSTEM_SERVICE_TABLE, *PKSYSTEM_SERVICE_TABLE 

以下は機能パラメータ番号表を4で割ったものが実数です

1 2 3 4 5 6 7 8 9 10 
kd> db 83ec13e4 83ec13e4 18 20 2c 2c 40 2c 40 44-0c 08 08 18 18 08 04 04 . ,,@,@D........ 83ec13f4 0c 0c 10 18 24 0c 2c 0c-18 10 0c 0c 0c 0c 0c 0c ....$.,......... 83ec1404 08 0c 18 18 14 18 0c 20-10 08 08 08 0c 08 0c 0c ....... ........ 83ec1414 08 04 04 0c 08 08 08 08-0c 04 04 20 08 10 0c 20 ........... ... 83ec1424 14 0c 2c 10 0c 0c 1c 10-20 20 10 38 10 14 10 20 ..,..... .8... 83ec1434 24 24 28 1c 1c 14 10 20-2c 10 34 28 18 2c 14 28 $$(.... ,.4(.,.( 83ec1444 08 0c 08 04 04 04 04 04-0c 04 08 28 00 04 04 1c ...........(.... 83ec1454 18 00 08 08 18 0c 14 18-08 18 0c 08 08 0c 04 00 ................ 

関数テーブルのアドレスを取得する方法

1 2 3 4 5 6 7 8 9 10 11 
 //This is the SSDT structure, that is, the system service description table, which contains multiple system service tables typedef struct _KSERVICE_TABLE_DESCRIPTOR { KSYSTEM_SERVICE_TABLE ntoskrnl // Service function of ntoskrnl.exe KSYSTEM_SERVICE_TABLE win32k //Service function of win32k.sys (kernel support of GDI32.dll/User32.dll) KSYSTEM_SERVICE_TABLE notUsed1 KSYSTEM_SERVICE_TABLE notUsed2 }KSERVICE_TABLE_DESCRIPTOR, *PKSERVICE_TABLE_DESCRIPTOR 

// ntoskrnlによってエクスポートされたSSDTをエクスポートします(10-10-12)
外部PKSERVICE_TABLE_DESCRIPTORKeServiceDescriptorTable

//これはエクスポートされます。カーネルファイルに移動する必要があるため、名前をブラインドにすることはできません

次のコードは、印刷および表示できるSSDTテーブルアドレスを表示するためのコードです。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 
#include #include typedef struct _KSYSTEM_SERVICE_TABLE { PULONG ServiceTableBase // Base address of service function address table PULONG ServiceCounterTableBase ULONG NumberOfService // Number of service functions PULONG ParamTableBase // Base address of service function parameter table } KSYSTEM_SERVICE_TABLE, *PKSYSTEM_SERVICE_TABLE typedef struct _KSERVICE_TABLE_DESCRIPTOR { KSYSTEM_SERVICE_TABLE ntoskrnl // Service function of ntoskrnl.exe KSYSTEM_SERVICE_TABLE win32k //Service function of win32k.sys (kernel support of GDI32.dll/User32.dll) KSYSTEM_SERVICE_TABLE notUsed1 KSYSTEM_SERVICE_TABLE notUsed2 }KSERVICE_TABLE_DESCRIPTOR, *PKSERVICE_TABLE_DESCRIPTOR //Export SSDT exported by ntoskrnl extern PKSERVICE_TABLE_DESCRIPTOR KeServiceDescriptorTable//This is exported, to find it in the kernel file, so the name can not be blind VOID DriverUnload(PDRIVER_OBJECT pDriver) { UNREFERENCED_PARAMETER(pDriver) KdPrint(('My Dirver is unloading...')) } NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pPath) { UNREFERENCED_PARAMETER(pPath) KdPrint(('->%x 
', KeServiceDescriptorTable)) pDriver->DriverUnload = DriverUnload return STATUS_SUCCESS } 

ページテーブルのベースアドレスでページ属性を変更する

SSDTが配置されている物理ページは読み取り専用です。変更する場合は、最初にページ属性を変更して書き込み可能にする必要があります。

1.最初の方法は、私たちが学んだ知識を使用して、ページテーブルのベースアドレスを直接変更することです。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 
if(RCR4 & 0x00000020) //The description is 2-9-9-12 paging KdPrint(('2-9-9-12Page %p
',RCR4)) KdPrint(('PTE1 %p
',*(DWORD*)(0xC0000000 + ((HookFunAddr >> 9) & 0x007FFFF8)))) *(DWORD64*)(0xC0000000 + ((HookFunAddr >> 9) & 0x007FFFF8)) else //The description is 10-10-12 paging KdPrint(('10-10-12Page break
')) KdPrint(('PTE1 %p
',*(DWORD*)(0xC0000000 + ((HookFunAddr >> 10) & 0x003FFFFC)))) *(DWORD*)(0xC0000000 + ((HookFunAddr >> 10) & 0x003FFFFC)) 

CR0レジスタを変更する(WP位置を0に変更)

CR0

CR0レジスタ

たとえば、SSDTHOOKNtOpenProcessが必要な場合は、最初にIDAを介してkernelBaseのOpenProcessを見つける必要があります。一連の検査の後、最終的にntdllにZWOpenProcessが見つかりました。 NtOpenProcessが表示される場所

1 2 3 4 
.text:77F05D88 mov eax, 0BEh NtOpenProcess .text:77F05D8D mov edx, 7FFE0300h .text:77F05D92 call dword ptr [edx] .text:77F05D94 retn 10h 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 
kd> dd KeServiceDescriptorTable 83f789c0 83e8cd9c 00000000 00000191 83e8d3e4 83f789d0 00000000 00000000 00000000 00000000 83f789e0 83eeb6af 00000000 025355a9 000000bb 83f789f0 00000011 00000100 5385d2ba d717548f 83f78a00 83e8cd9c 00000000 00000191 83e8d3e4 83f78a10 95d46000 00000000 00000339 95d4702c 83f78a20 00000000 00000000 83f78a24 00000340 83f78a30 00000340 865fab00 00000007 00000000 kd> dd 83e8cd9c+4*BE 83e8d094 840219dc 84073fff 84061b37 83f8d0c7 83e8d0a4 84079674 83ff50c6 84096977 8405db6f 83e8d0b4 8406dd87 840882e4 84061c4e 84119e0f 83e8d0c4 841026f1 84103989 83ff3506 84050970 83e8d0d4 841022a2 84101fc2 8410235a 8410207a 83e8d0e4 8400693f 83fd5f60 83ff0a51 841040e4 83e8d0f4 841041aa 84052403 840a35a7 840679a1 83e8d104 84114a3e 84114e83 83ed2d34 84086b8c kd> u 840219dc nt!NtOpenProcess: 840219dc 8bff mov edi,edi 840219de 55 push ebp 840219df 8bec mov ebp,esp 840219e1 51 push ecx 840219e2 51 push ecx 840219e3 64a124010000 mov eax,dword ptr fs:[00000124h] 840219e9 8a803a010000 mov al,byte ptr [eax+13Ah] 840219ef 8b4d14 mov ecx,dword ptr [ebp+14h] 

MDLを介したページ属性の変更について説明しましょう。
はメモリ記述子リスト、または略してMDLです。 MDLとは何ですか?文字通り、メモリ記述子のリストを理解することは難しくありません。 MDLには、メモリ領域の開始、所有者プロシージャ、バイト数、マークなどが含まれています。OK、最初にMDLポインタを定義する必要があります。

1 2 
 PMDL MDLSystemCall 

MDLポインターを定義した後、MAPPEDシリーズのパラメーターを使用してメモリーを書き込み可能にし、MDLをメモリーにロックしてから、MmMap操作用のPVOIDポインターを定義する必要があります。

1 
PVOID *MappedSCT 
1 2 3 4 5 6 7 
MDLSystemCall = MmCreateMdl( NULL, //Memory descriptor list KeServiceDescriptorTable.ServiceTableBase,// Memory address KeServiceDescriptorTable.NumberOfServices*4)//Memory length if(!MDLSystemCall) return STATUS_UNSUCCESSFUL 

作成されたMDL、ページ配列を埋めます

1 2 3 
MmBuildMdlForNonPagedPool(MDLSystemCall)//Create the MDL description of the memory page MDLSystemCall->MdlFlags = MDLSystemCall->MdlFlags | MDL_MAPPED_TO_SYSTEM_VA //Set MDL flag to be writable MappedSCT = MmMapLockedPages(MDLSystemCall, KernelMode) 

次に、ここにフックするなど、独自の操作を行います

次に、MDLをリリースするための別のコードがあります

1 2 3 4 5 
if(MDSystemCall) { MmUnmapLockedPages(MappedSCT, MDSystemCall) IoFreeMdl(MDSystemCall) } 

以下はSSDTフックコードです

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 
#include #include //1. Find the function address table of the system service table //Define a global variable to store the previous NtOpenProcess address ULONG uOldNtOpenProcess //With the address, a function NtOpenProcess pointer is needed to call the original NtOpenProcess //Define functions for repairing and restoring page attributes PMDL MDSystemCall PVOID *MappedSCT typedef NTSTATUS(*NTOPENPROCESS)( __out PHANDLE ProcessHandle, __in ACCESS_MASK DesiredAccess, __in POBJECT_ATTRIBUTES ObjectAttributes, __in_opt PCLIENT_ID ClientId ) typedef struct _KSYSTEM_SERVICE_TABLE { PULONG ServiceTableBase // Base address of service function address table PULONG ServiceCounterTableBase ULONG NumberOfService // Number of service functions PULONG ParamTableBase // Base address of service function parameter table } KSYSTEM_SERVICE_TABLE, *PKSYSTEM_SERVICE_TABLE typedef struct _KSERVICE_TABLE_DESCRIPTOR { KSYSTEM_SERVICE_TABLE ntoskrnl // Service function of ntoskrnl.exe KSYSTEM_SERVICE_TABLE win32k //Service function of win32k.sys (kernel support of GDI32.dll/User32.dll) KSYSTEM_SERVICE_TABLE notUsed1 KSYSTEM_SERVICE_TABLE notUsed2 }KSERVICE_TABLE_DESCRIPTOR, *PKSERVICE_TABLE_DESCRIPTOR //Export SSDT exported by ntoskrnl extern PKSERVICE_TABLE_DESCRIPTOR KeServiceDescriptorTable//This is exported, to find it in the kernel file, so the name can not be blind //Prepare the function for replacement NTSTATUS NTAPI MyNtOpenProcess(__out PHANDLE ProcessHandle, __in ACCESS_MASK DesiredAccess, __in POBJECT_ATTRIBUTES ObjectAttributes, __in_opt PCLIENT_ID ClientId ) { NTSTATUS Status Status = STATUS_SUCCESS //Fill in your business here. . . Various filters, modify the return structure, etc. KdPrint(('MyNtOpenProcess %x %x %x %x 
', ProcessHandle, DesiredAccess, ObjectAttributes, ClientId)) //Fill here is to open the original function, because this function also needs to realize the original function, otherwise it will be messy, unless you implement it in your own business return ((NTOPENPROCESS)uOldNtOpenProcess)(ProcessHandle, DesiredAccess, ObjectAttributes, ClientId) } void PageProtectOff() { //MDSystemCall = MmCreateMdl(NULL, KeServiceDescriptorTable->ntoskrnl.ServiceTableBase, KeServiceDescriptorTable->ntoskrnl.NumberOfService * 4) //if (!MDSystemCall) // //return STATUS_UNSUCCESSFUL // return //MmBuildMdlForNonPagedPool(MDSystemCall) //MDSystemCall->MdlFlags = MDSystemCall->MdlFlags | MDL_MAPPED_TO_SYSTEM_VA //MappedSCT = MmMapLockedPages(MDSystemCall, KernelMode) __asm ​​{//Disable memory protection push eax mov eax, cr0 and eax, ~0x10000 mov cr0, eax pop eax } } void PageProtectOn() { ////Unlock and release MDL //if (MDSystemCall) //{ // MmUnmapLockedPages(MappedSCT, MDSystemCall) // IoFreeMdl(MDSystemCall) //} __asm ​​{//Restore memory protection push eax mov eax, cr0 or eax, 0x10000 mov cr0, eax pop eax } } //3. Modify the function address, prepare a function to modify the function address void HookNtOpenProcess() { NTSTATUS Status Status = STATUS_SUCCESS PageProtectOff() uOldNtOpenProcess = KeServiceDescriptorTable->ntoskrnl.ServiceTableBase[0xBE] KeServiceDescriptorTable->ntoskrnl.ServiceTableBase[0xBE] = (ULONG)MyNtOpenProcess PageProtectOn() } //4. Restore void UnHookNtOpenProcess() { PageProtectOff() KeServiceDescriptorTable->ntoskrnl.ServiceTableBase[0xBE] = (ULONG)uOldNtOpenProcess PageProtectOn() } VOID DriverUnload(PDRIVER_OBJECT pDriver) { UNREFERENCED_PARAMETER(pDriver) UnHookNtOpenProcess() KdPrint(('My Dirver is unloading...')) } NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pPath) { UNREFERENCED_PARAMETER(pPath) KdPrint(('->%x 
', KeServiceDescriptorTable->ntoskrnl.ServiceTableBase[0xBE]))//Get function address table HookNtOpenProcess() pDriver->DriverUnload = DriverUnload return STATUS_SUCCESS } 

次に、PChuntを使用して、HOOKの前後のこの関数アドレスの変更を監視できます。

これはフックの前です 画像

画像

これはフックの後です