很多RootKit在ring0下利用PsCreateSystemThread来创建系统线程做某些WS的事情,我们平时不利用ARK工具的话,是很难发现这些线程,在某些情况下,需要anti一些特定的rootkit,这里给出一个简单的示例:
.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
);
.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;
}