Detailed description of hook ssdt with source code

Source: Internet
Author: User
Tags define function superuser permission ssdt

Source code: hook ssdt source code

 

According to Microsoft, the Service Descriptor Table is an array composed of four structures, each of which is composed of four double-word items. Therefore, we can represent the service Descriptor Table:

Typedef struct servicedescriptortable

{

SDE servicedescriptor [4];

} SDT;

Each service descriptor is in the form of four dual characters. Its structure is as follows:

# Pragma pack (1)

Typedef struct servicedescriptorentry

{

Unsigned int * servicetablebase;

Unsigned int * servicecountertablebase; // used only in checked build

Unsigned int numberofservices;

Unsigned char * paramtablebase;

} SDE, * psde;

# Pragma pack ()

The data structure ssdt we are looking for is the call table referenced by the first domain (you can use the command dps nt in the debugger! Kiservicetable view)

 

I,DisableWPBit

It would be nice if we could simply replace the value with the ssdt, but the obstacle is that ssdt exists in the read-only memory. Therefore, in order to hook the routines referenced by ssdt, our general policy should look similar to the following format (expressed in pseudo code ):

Disablereadprotection ();

Modifyssdt ();

Enablereadprotection ();

Intel's documentation states: "If cr0.wp = 1, the access type is determined by the R/W flag of the page Directory and page table items. If cr0.wp = 0, the superuser permission allows read and write access ." Therefore, to damage write protection on ssdt, We need to temporarily clear the write protect (WP) Mark.

By assigning your own MDL to describe ssdt, we can disable read protection. MDL is associated with the physical memory page that stores ssdt content. The MDL element structure is defined in the WDM. h header file attached to the wdk:

Typedef struct _ MDL

{

Struct _ MDL * next;

Cshort size;

Cshort mdlflags;

Struct _ eprocess * process;

Pvoid mappedsystemva;

Pvoid startva;

Ulong bytecount;

Ulong byteoffset;

} MDL, * pmdl;

For this area of physical memory, once we add our own private description, we can use the bitwise OR and mdl_mapped_to_system_va macros to adjust the MDL permissions. Once again, we can implement it successfully because we have our own MDL object. Finally, we use the ing between the location of ssdt in the physical memory and MDL to formula.

Then, lock the MDL buffer we created in the linear space. In return, we get a new linear address, which also points to ssdt and can be modified.

In short, using MDL, we create a new writable buffer in the linear address space of the system, which is resolved to the physical memory that stores ssdt. As long as the two regions are resolved to the same physical memory area, it is no different. It is just a digital game, pure and simple. If you cannot write to a given area of linear memory, create your own region and write to it.

Wp_globals disablewp_mdl (unsigned int * ssdt, unsigned int nservices)

{

Wp_globals wpgbs;

Dbuplint ("[disablewp_mdl] ssdt = % \ n", ssdt );

Dbuplint ("[disablewp_mdl] nservices = % \ n", nservices );

 

Wpgbs. pmdl = mmcreatemdl (null, (pvoid) ssdt, (size_t) nservices * 4 );

If (wpgbs. pmdl = NULL)

{

Dbuplint ("[disablewp_mdl] % \ n", "Call to mmcreatemdl failed ");

Return (wpgbs );

}

 

Mmbuildmdlfornonpagedpool (wpgbs. pmdl );

Wpgbs. pmdl-> mdlflags = wpgbs. pmdl-> mdlflags | mdl_mapped_to_system_va;

Wpgbs. calltable = (unsigned char *) mmmaplockedpages (wpgbs. pmdl, kernelmode );

If (wpgbs. calltable = NULL)

{

Dbuplint ("[disablewp_mdl] % \ n", "Call to mmmaplockedpages failed ");

Return (wpgbs );

}

 

 

Return (wpgbs );

}

This routine returns a structure, which is just a wrapper pointing to the MDL and ssdt pointers.

Typedef struct _ wp_globals

{

Unsigned char * calltable;

Pmdl;

} Wp_globals;

We use the previous function to return this structure to access the writable ssdt version. In addition, when the MDL buffer is no longer needed, we can restore the original state of the transaction. To restore the system status, we use the following functions:

Void enablewp_mdl (pmdl mdlptr, unsigned char * calltable)

{

If (mdlptr! = NULL)

{

Mmunmaplockedpages (pvoid) calltable, mdlptr );

Iofreemdl (mdlptr );

}

}

 

II,HookSsdtItem

Once write protection is disabled, we can use the following routine to replace the new function address with ssdt.

Unsigned char * hookssdt (unsigned char * apicall, unsigned char * newaddr, unsigned int * calltable)

{

Plong target;

Unsigned int indexvalue;

 

Indexvalue = getssdtindex (apicall );

Target = (plong) & (calltable [indexvalue]);

Return (unsigned char *) interlockedexchange (target, (long) newaddr ));

}

This routine receives the address of the hook routine, the address of the existing routine, and the pointer to the ssdt, and returns the address of the existing routine (to restore ssdt after the task is completed ).

Given an NT * () function, where is its address in ssdt? We use u nt in the debugger! Run the ZW * command to view the assembly code and find that the assembly code at the beginning of the function is in this format: mov eax, xxxh. This XXX is the index number called by the system.

Unsigned int getssdtindex (unsigned char * address)

{

Unsigned char * addressofindex;

Unsigned int indexvalue;

 

Addressofindex = address + 1;

Indexvalue = * (Pulong) addressofindex );

Return (indexvalue );

}

Once the index value is available, it is easy to locate the address of the table item and replace it. However, please note that we must use interlockedexchange () to lock the access to this item so that we have exclusive access for the moment. Unlike the IDT or gdt processor-based structure, no matter how many processors are running, there is only one ssdt.

The same basic mechanism is used for decoupling system calls in ssdt. The only difference is that we do not return values to the call routine.

Void unhookssdt (unsigned char * apicall, unsigned char * oldaddr, unsigned int * calltable)

{

Plong target;

Unsigned int indexvalue;

 

Indexvalue = getssdtindex (apicall );

Target = (plong) & (calltable [indexvalue]);

Interlockedexchange (target, (long) oldaddr );

}

 

III,SsdtExample

Now that we have analyzed the various chords that make up this piece of music, let's play it and hear it. Hook zwterminateprocess system call.

Ntstatus DriverEntry (

In pdriver_object driverobject,

In punicode_string registrypath

)

{

Dbuplint ("load ssdt driver \ n ");

Driverobject-> driverunload = unload;

Wpglobals = disablewp_mdl (keservicedescriptortable. servicetablebase, keservicedescriptortable. numberofservices );

 

If (wpglobals. pmdl = NULL | wpglobals. calltable = NULL)

{

Return (status_unsuccessful );

}

 

Pmdl = wpglobals. pmdl;

Systemcalltable = (pvoid *) wpglobals. calltable;

 

Old_zwterminateprocess = (zwterminateprocessptr) hookssdt (unsigned char *) zwterminateprocess, (unsigned char *) newzwterminateprocess, (unsigned int *) systemcalltable );

 

Return STATUS_SUCCESS;

}

Keservicedescriptortableis the symbol exported by ntoskrnl.exe. To access it, we must add the _ declspec (dllimport) prefix to the declaration so that the compiler knows what we are doing. The exported kernel symbol provides an address in the memory. The data type definition (typedef struct servicedescriptorentry) We provide imposes a composite structure on the memory of this address. Using this common method, you can modify any variable exported by the operating system.

We save the returned values to three global variables (pmdl, systemcalltable, old_zwterminateprocess) to decouple system calls and re-enable write protection.

Void

Unload (

In pdriver_object driverobject

)

{

Dbuplint ("Unload ssdt driver \ n ");

 

Unhookssdt (unsigned char *) zwterminateprocess, (unsigned char *) old_zwterminateprocess, (unsigned int *) systemcalltable );

 

Enablewp_mdl (pmdl, (unsigned char *) systemcalltable );

}

Every time zwterminateprocess is called, the function we hook will be called. To store the addresses of existing system calls that implement this interface, define the following function pointer data types.

Typedef ntstatus (* zwterminateprocessptr )(

In handle processhandle optional,

In ntstatus exitstatus );

The only thing to do is implement hook routines. We trace the call by printing the output string and then call the original system call.

Ntstatus newzwterminateprocess (

In handle processhandle optional,

In ntstatus exitstatus)

{

Ntstatus;

Dbuplint ("newzwterminateprocess called \ n ");

Ntstatus = (zwterminateprocessptr) (old_zwterminateprocess) (processhandle, exitstatus );

 

If (! Nt_success (ntstatus ))

{

Dbuplint ("[newzwterminateprocess] % \ n", "Call to old_zwterminateprocess failed ");

}

Return STATUS_SUCCESS;

}

In this example, we create a standard operating program that hooks ssdt. No matter which routine we are blocking, the technical details of the hook and decoupling remain the same. From now on, whenever we want to track or filter system calls, we have to do only the following work:

 

  • Declare the original system call prototype (for exampleZwterminateprocess ())
  • Declare the corresponding function pointer data type (for exampleZwterminateprocessptr)
  • Define function pointers (for exampleOld_zwterminateprocess)
  • Implementation hook routine (for exampleNewzwterminateprocess ())

4. Load driver

We use instdrv to load the compiled driver dcsssdt. sys.

 

We use pchunter32 to check whether the hook is successful.

 

 

We can use dbgview to view debugging information.

 

No problem.

 

From http://www.dcscms.com/article/content.php? SEQ = 13

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.