hook PsCreateSystemThread
很多RootKit在ring0下利用PsCreateSystemThread来创建系统线程做某些WS的事情,我们平时不利用ARK工具的话,是很难发现这些线程,在某些情况下,需要anti一些特定的rootkit,这里给出一个简单的示例:
.h:
.c:
.h:
#pragma once
#include < ntddk.h >
typedef long LONG;
typedef unsigned char BOOL, * PBOOL;
typedef unsigned char BYTE, * PBYTE;
typedef unsigned long DWORD, * PDWORD;
typedef unsigned short WORD, * PWORD;
typedef void * HMODULE;
typedef long NTSTATUS, * PNTSTATUS;
typedef unsigned long DWORD;
typedef DWORD * PDWORD;
typedef unsigned long ULONG;
typedef unsigned long ULONG_PTR;
typedef ULONG * PULONG;
typedef unsigned short WORD;
typedef unsigned char BYTE;
typedef unsigned char UCHAR;
typedef unsigned short USHORT;
typedef void * PVOID;
typedef BYTE BOOLEAN;
#define SEC_IMAGE 0x01000000
NTSTATUS
PsLookupProcessByProcessId(
IN HANDLE ProcessId,
OUT PEPROCESS * Process
);
#include < ntddk.h >
typedef long LONG;
typedef unsigned char BOOL, * PBOOL;
typedef unsigned char BYTE, * PBYTE;
typedef unsigned long DWORD, * PDWORD;
typedef unsigned short WORD, * PWORD;
typedef void * HMODULE;
typedef long NTSTATUS, * PNTSTATUS;
typedef unsigned long DWORD;
typedef DWORD * PDWORD;
typedef unsigned long ULONG;
typedef unsigned long ULONG_PTR;
typedef ULONG * PULONG;
typedef unsigned short WORD;
typedef unsigned char BYTE;
typedef unsigned char UCHAR;
typedef unsigned short USHORT;
typedef void * PVOID;
typedef BYTE BOOLEAN;
#define SEC_IMAGE 0x01000000
NTSTATUS
PsLookupProcessByProcessId(
IN HANDLE ProcessId,
OUT PEPROCESS * Process
);
.c:
#include
"
HookPsThread.h
"
/**/ /******************************************************************************
Hook PsCreateSystemThread
out adress
******************************************************************************/
// =============================================================================
// Version Define
// =============================================================================
#define EPROCESS_SIZE 1
#define PEB_OFFSET 2
#define FILE_NAME_OFFSET 3
#define PROCESS_LINK_OFFSET 4
#define PROCESS_ID_OFFSET 5
#define EXIT_TIME_OFFSET 6
// =============================================================================
// Logic Define
// =============================================================================
ULONG PsCreateSystemThreadAddr = 0 ;
char PsCreateSystemThreadData[ 5 ] = {0} ;
DWORD ProcessNameOffset;
// -----------------------------------------------------------------------------
// GetPlantformDependentInfo
// -----------------------------------------------------------------------------
DWORD GetPlantformDependentInfo( DWORD dwFlag )
{
DWORD current_build;
DWORD ans = 0;
PsGetVersion(NULL, NULL, ¤t_build, NULL);
switch ( dwFlag )
{
case EPROCESS_SIZE:
if (current_build == 2195) ans = 0 ; // 2000,当前不支持2000,下同
if (current_build == 2600) ans = 0x25C; // xp
if (current_build == 3790) ans = 0x270; // 2003
break;
case PEB_OFFSET:
if (current_build == 2195) ans = 0;
if (current_build == 2600) ans = 0x1b0;
if (current_build == 3790) ans = 0x1a0;
break;
case FILE_NAME_OFFSET:
if (current_build == 2195) ans = 0;
if (current_build == 2600) ans = 0x174;
if (current_build == 3790) ans = 0x164;
break;
case PROCESS_LINK_OFFSET:
if (current_build == 2195) ans = 0;
if (current_build == 2600) ans = 0x088;
if (current_build == 3790) ans = 0x098;
break;
case PROCESS_ID_OFFSET:
if (current_build == 2195) ans = 0;
if (current_build == 2600) ans = 0x084;
if (current_build == 3790) ans = 0x094;
break;
case EXIT_TIME_OFFSET:
if (current_build == 2195) ans = 0;
if (current_build == 2600) ans = 0x078;
if (current_build == 3790) ans = 0x088;
break;
}
return ans;
}
// -----------------------------------------------------------------------------
// GetFunctionAddr
// -----------------------------------------------------------------------------
ULONG GetFunctionAddr( IN PCWSTR FunctionName)
{
UNICODE_STRING UniCodeFunctionName;
RtlInitUnicodeString( &UniCodeFunctionName, FunctionName );
return (ULONG)MmGetSystemRoutineAddress( &UniCodeFunctionName );
}
// -----------------------------------------------------------------------------
// _PsCreateSystemThread
// -----------------------------------------------------------------------------
NTSTATUS _PsCreateSystemThread(IN PKSTART_ROUTINE StartRoutine)
{
ULONG RAddr = (ULONG)StartRoutine; //Routine Address
//Get Process Info
LPTSTR CurProc;
PEPROCESS EProcess;
PsLookupProcessByProcessId(PsGetCurrentProcessId(), &EProcess);
CurProc =(LPTSTR)EProcess;
CurProc =CurProc+ProcessNameOffset;
if (strncmp((char*)CurProc,"System",6) != 0)
{
DbgPrint("Current Process : %s, StartRoutine : %X\n", (char *)CurProc, StartRoutine);
}
return 0;
}
// -----------------------------------------------------------------------------
// MyPsCreateSystemThread
// -----------------------------------------------------------------------------
__declspec (naked) void MyPsCreateSystemThread()
{
_asm
{
pushad
push [esp+20h+18h]
call _PsCreateSystemThread
popad
mov edi,edi
push ebp
mov ebp,esp
jmp PsCreateSystemThreadAddr
}
}
// -----------------------------------------------------------------------------
// Install Hook
// -----------------------------------------------------------------------------
VOID InHook()
{
PsCreateSystemThreadAddr = GetFunctionAddr(L"PsCreateSystemThread");
__asm
{
push eax
mov eax, CR0
and eax, 0FFFEFFFFh
mov CR0, eax
pop eax
}
//Save asmCode
memcpy(PsCreateSystemThreadData, (PVOID)PsCreateSystemThreadAddr, 5);
(ULONG)PsCreateSystemThreadAddr += 5;
//Inline PsCreateSystemThread
__asm
{
mov esi, PsCreateSystemThreadAddr
sub esi, 5
mov byte ptr[esi], 0xE9
lea eax, [MyPsCreateSystemThread]
sub eax, esi
sub eax, 5
mov dword ptr [esi+1],eax
}
__asm
{
push eax
mov eax, CR0
or eax, NOT 0FFFEFFFFh
mov CR0, eax
pop eax
}
DbgPrint("Hooked OK.\n");
return;
}
// -----------------------------------------------------------------------------
// Uninstall Hook
// -----------------------------------------------------------------------------
VOID UnHook()
{
__asm
{
push eax
mov eax, CR0
and eax, 0FFFEFFFFh
mov CR0, eax
pop eax
}
(ULONG)PsCreateSystemThreadAddr -= 5;
memcpy((PVOID)PsCreateSystemThreadAddr, PsCreateSystemThreadData, 5);
__asm
{
push eax
mov eax, CR0
or eax, NOT 0FFFEFFFFh
mov CR0, eax
pop eax
}
DbgPrint("UnHook OK.\n");
return;
}
// -----------------------------------------------------------------------------
// Driver UnLoad
// -----------------------------------------------------------------------------
void OnUnload(PDRIVER_OBJECT pDriverObj)
{
UnHook();
DbgPrint("UnLoading Driver");
}
// -----------------------------------------------------------------------------
// Driver LoadEntry
// -----------------------------------------------------------------------------
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObj, PUNICODE_STRING pRegistryString)
{
pDriverObj->DriverUnload = OnUnload;
DbgPrint("Loading Driver");
ProcessNameOffset = GetPlantformDependentInfo(FILE_NAME_OFFSET);
InHook();
return STATUS_SUCCESS;
}
/**/ /******************************************************************************
Hook PsCreateSystemThread
out adress
******************************************************************************/
// =============================================================================
// Version Define
// =============================================================================
#define EPROCESS_SIZE 1
#define PEB_OFFSET 2
#define FILE_NAME_OFFSET 3
#define PROCESS_LINK_OFFSET 4
#define PROCESS_ID_OFFSET 5
#define EXIT_TIME_OFFSET 6
// =============================================================================
// Logic Define
// =============================================================================
ULONG PsCreateSystemThreadAddr = 0 ;
char PsCreateSystemThreadData[ 5 ] = {0} ;
DWORD ProcessNameOffset;
// -----------------------------------------------------------------------------
// GetPlantformDependentInfo
// -----------------------------------------------------------------------------
DWORD GetPlantformDependentInfo( DWORD dwFlag )
{
DWORD current_build;
DWORD ans = 0;
PsGetVersion(NULL, NULL, ¤t_build, NULL);
switch ( dwFlag )
{
case EPROCESS_SIZE:
if (current_build == 2195) ans = 0 ; // 2000,当前不支持2000,下同
if (current_build == 2600) ans = 0x25C; // xp
if (current_build == 3790) ans = 0x270; // 2003
break;
case PEB_OFFSET:
if (current_build == 2195) ans = 0;
if (current_build == 2600) ans = 0x1b0;
if (current_build == 3790) ans = 0x1a0;
break;
case FILE_NAME_OFFSET:
if (current_build == 2195) ans = 0;
if (current_build == 2600) ans = 0x174;
if (current_build == 3790) ans = 0x164;
break;
case PROCESS_LINK_OFFSET:
if (current_build == 2195) ans = 0;
if (current_build == 2600) ans = 0x088;
if (current_build == 3790) ans = 0x098;
break;
case PROCESS_ID_OFFSET:
if (current_build == 2195) ans = 0;
if (current_build == 2600) ans = 0x084;
if (current_build == 3790) ans = 0x094;
break;
case EXIT_TIME_OFFSET:
if (current_build == 2195) ans = 0;
if (current_build == 2600) ans = 0x078;
if (current_build == 3790) ans = 0x088;
break;
}
return ans;
}
// -----------------------------------------------------------------------------
// GetFunctionAddr
// -----------------------------------------------------------------------------
ULONG GetFunctionAddr( IN PCWSTR FunctionName)
{
UNICODE_STRING UniCodeFunctionName;
RtlInitUnicodeString( &UniCodeFunctionName, FunctionName );
return (ULONG)MmGetSystemRoutineAddress( &UniCodeFunctionName );
}
// -----------------------------------------------------------------------------
// _PsCreateSystemThread
// -----------------------------------------------------------------------------
NTSTATUS _PsCreateSystemThread(IN PKSTART_ROUTINE StartRoutine)
{
ULONG RAddr = (ULONG)StartRoutine; //Routine Address
//Get Process Info
LPTSTR CurProc;
PEPROCESS EProcess;
PsLookupProcessByProcessId(PsGetCurrentProcessId(), &EProcess);
CurProc =(LPTSTR)EProcess;
CurProc =CurProc+ProcessNameOffset;
if (strncmp((char*)CurProc,"System",6) != 0)
{
DbgPrint("Current Process : %s, StartRoutine : %X\n", (char *)CurProc, StartRoutine);
}
return 0;
}
// -----------------------------------------------------------------------------
// MyPsCreateSystemThread
// -----------------------------------------------------------------------------
__declspec (naked) void MyPsCreateSystemThread()
{
_asm
{
pushad
push [esp+20h+18h]
call _PsCreateSystemThread
popad
mov edi,edi
push ebp
mov ebp,esp
jmp PsCreateSystemThreadAddr
}
}
// -----------------------------------------------------------------------------
// Install Hook
// -----------------------------------------------------------------------------
VOID InHook()
{
PsCreateSystemThreadAddr = GetFunctionAddr(L"PsCreateSystemThread");
__asm
{
push eax
mov eax, CR0
and eax, 0FFFEFFFFh
mov CR0, eax
pop eax
}
//Save asmCode
memcpy(PsCreateSystemThreadData, (PVOID)PsCreateSystemThreadAddr, 5);
(ULONG)PsCreateSystemThreadAddr += 5;
//Inline PsCreateSystemThread
__asm
{
mov esi, PsCreateSystemThreadAddr
sub esi, 5
mov byte ptr[esi], 0xE9
lea eax, [MyPsCreateSystemThread]
sub eax, esi
sub eax, 5
mov dword ptr [esi+1],eax
}
__asm
{
push eax
mov eax, CR0
or eax, NOT 0FFFEFFFFh
mov CR0, eax
pop eax
}
DbgPrint("Hooked OK.\n");
return;
}
// -----------------------------------------------------------------------------
// Uninstall Hook
// -----------------------------------------------------------------------------
VOID UnHook()
{
__asm
{
push eax
mov eax, CR0
and eax, 0FFFEFFFFh
mov CR0, eax
pop eax
}
(ULONG)PsCreateSystemThreadAddr -= 5;
memcpy((PVOID)PsCreateSystemThreadAddr, PsCreateSystemThreadData, 5);
__asm
{
push eax
mov eax, CR0
or eax, NOT 0FFFEFFFFh
mov CR0, eax
pop eax
}
DbgPrint("UnHook OK.\n");
return;
}
// -----------------------------------------------------------------------------
// Driver UnLoad
// -----------------------------------------------------------------------------
void OnUnload(PDRIVER_OBJECT pDriverObj)
{
UnHook();
DbgPrint("UnLoading Driver");
}
// -----------------------------------------------------------------------------
// Driver LoadEntry
// -----------------------------------------------------------------------------
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObj, PUNICODE_STRING pRegistryString)
{
pDriverObj->DriverUnload = OnUnload;
DbgPrint("Loading Driver");
ProcessNameOffset = GetPlantformDependentInfo(FILE_NAME_OFFSET);
InHook();
return STATUS_SUCCESS;
}