Skip to content

Instantly share code, notes, and snippets.

@Little-Ki
Last active October 23, 2020 15:05
Show Gist options
  • Save Little-Ki/c7ba4ef573281c472f0d1575853509a8 to your computer and use it in GitHub Desktop.
Save Little-Ki/c7ba4ef573281c472f0d1575853509a8 to your computer and use it in GitHub Desktop.
[Code] [Kernel] SSDT proxy class
/* SSDT proxy class */
/*
#pragma pack(1)
struct SYSTEM_SERVICE_TABLE {
// This pointer points to an array of int
// In 32 bits mode, this array saves <function's address>.
// In 64 bits mode, this array saves <(function's address - table's address) << 4>.
// So we calculate the function's address by this way:
// In 32 bits mode : function's address = [table's address + 4 * index]
// In 64 bits mode : function's address = [table's address + 4 * index] >> 4 + table's address
PVOID ServiceTableBase;
PVOID ServiceCounterTableBase;
#if defined(_X86_)
ULONG NumberOfServices;
#elif defined(_AMD64_)
ULONG64 NumberOfServices;
#endif
PVOID ParamTableBase;
}
#pragma pack()
*/
class SSDT_proxy {
public:
SSDT_proxy();
ULONG64 getFunction( ULONG index );
private:
PSYSTEM_SERVICE_TABLE pTable = nullptr;
ULONG64 getTableX64();
ULONG64 searchTableX64( ULONG64 begin, ULONG64 end );
}
SSDT_proxy::SSDT_proxy()
{
pTable = (PSYSTEM_SERVICE_TABLE) getTableX64();
}
/*
In 32 bits mode, we just use:
__decltype(dllimport) ServiceDescriptorTableEntry_t KeServiceDescriptorTable
to get the address of table.
But in 64 bits mode, this symbol does not exported, but function KiSystemCall64 references KeServiceDescriptorTable, so we can use AOB scan to find its address.
Disassembly code looks like:
// Win7 x64
nt!KiSystemServiceRepeat:
fffff800`03e8d772 4c8d15c7202300 lea r10,[nt!KeServiceDescriptorTable (fffff800`040bf840)]
fffff800`03e8d779 4c8d1d00212300 lea r11,[nt!KeServiceDescriptorTableShadow (fffff800`040bf880)]
… …
// Win8.1 x64
nt!KiSystemServiceRepeat:
fffff800`11b6c752 4c8d1567531f00 lea r10,[nt!KeServiceDescriptorTable (fffff800`11d61ac0)]
fffff800`11b6c759 4c8d1da0531f00 lea r11,[nt!KeServiceDescriptorTableShadow (fffff800`11d61b00)]
… …
Just search { 0x4C, 0x8D, 0x15 } then we can get the address of KeServiceDescriptorTable
/*
ULONG64 SSDT_proxy::getTableX64()
{
ULONG64 beginAddr = (ULONG64) __readmsr( 0xc0000082 );
ULONG64 endAddr = beginAddr + 0x500;
ULONGLONG pServiceTable = 0;
pServiceTable = searchTableX64( beginAddr, endAddr );
if ( pServiceTable )
return(pServiceTable);
ULONGLONG serviceUser = 0;
ULONGLONG templong = 0xffffffffffffffff;
for ( PUCHAR i = (PUCHAR) beginAddr; i < (PUCHAR) endAddr + 0xff; i++ )
{
if ( MmIsAddressValid( i ) && MmIsAddressValid( i + 5 ) )
{
if ( *(PUCHAR) i == 0xe9 && *(PUCHAR) (i + 5) == 0xc3 )
{
memcpy( &templong, (PUCHAR) (i + 1), 4 );
serviceUser = (ULONG64) (templong + 5 + i);
endAddr = serviceUser + 0x500;
pServiceTable = searchTableX64( serviceUser, endAddr );
return(pServiceTable);
}
}
}
return 0 ;
}
ULONG64 SSDT_proxy::searchTableX64( ULONG64 begin, ULONG64 end )
{
if ( MmIsAddressValid( (PVOID64) begin ) == FALSE )
return 0;
if ( MmIsAddressValid( (PVOID64) end ) == FALSE )
return 0;
PUCHAR i = (PUCHAR) begin;
ULONG64 rel = 0;
for ( i = begin; i < (PUCHAR) end; i++ )
{
if ( MmIsAddressValid( i ) && MmIsAddressValid( i + 1 ) && MmIsAddressValid( i + 2 ) )
{
if ( *(i) == 0x4c && *(i + 1) == 0x8d && *(i + 2) == 0x15 )
{
memcpy( &rel, i + 3, 4 );
return (ULONG64) rel + (ULONG64) i + 7;
}
}
}
return 0;
}
/*
Get function's address by function's index.
To get the function's index, just parse ntdll.dll pe struct.
The function's index is same between SSDT table and dll export table.
*/
ULONG64 SSDT_proxy::getFunction( ULONG index )
{
LONG dwtmp = 0;
ULONG64 addr = 0;
PULONG pTableBase = NULL;
if ( pTable != NULL )
{
pTableBase = (PULONG) pTable->ServiceTableBase;
dwtmp = pTableBase[index];
dwtmp = dwtmp >> 4;
addr = ( (LONG64) dwtmp + (ULONG64) pTableBase); /* &0xFFFFFFF0; */
}
return addr;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment