1. PID를 알고 있을 때 작업관리자에서 프로세스 종료시 종료되지 않는 드라이버.
//3. SDT Hooking
#include <ntddk.h>
// 함수 이름(주소)를 가지고 SDT 서비스 번호를 얻어내는 매크로
#define SERIVCE_ID( f ) *(ULONG*)( (char*)f + 1 )
// SDT Table의 각항목을 구성하는 구조체
#pragma pack(1) // 1 Byte 단위로 align(정렬)하라는 지시어
typedef struct ServiceDescriptorEntry
{
unsigned int* ServiceTableBase; // 함수 주소
unsigned int* ServiceCounterTableBase;
unsigned int NumberOfServices;
unsigned char* ParamTableBase;
} ServiceDescriptorTableEntry_t;
#pragma pack()
// ntoskrnl.exe 에서는 SDT Table을 export 하고 있다.
__declspec(dllimport) ServiceDescriptorTableEntry_t
KeServiceDescriptorTable;
// ntoskrnl.exe 가 가진 ZwTerminateProcess를 import 한다.
// Hooking 에 대상이 되는 함수를 import
__declspec(dllimport)
NTSTATUS __stdcall ZwTerminateProcess( HANDLE handle, NTSTATUS ExitCode);
// 원래 함수의 주소를 보관하고 있어야 한다.
typedef NTSTATUS (__stdcall *FUNC)(HANDLE, NTSTATUS );
FUNC old; // 원래 함수의 주소를 담아둘 변수.
// 새로운 함수
NTSTATUS __stdcall foo( HANDLE handle, NTSTATUS ExitCode )
{
DbgPrint("TerminateProcess is Called : %x", handle );
if ( handle != (HANDLE)0 && handle != (HANDLE)-1 ) // 자기 스스로 죽는 ExitProcess 일 경우 제외
{
PVOID pEprocess = 0; // 계산기의 EPROcESS의 주소를 담을 변수
OBJECT_HANDLE_INFORMATION obj_handle; // 핸들의 관한 정보(상속여부등)를 얻어 올 변수
// User Level 에서 사용하던 핸들을 가지고 커널메모리에 있는 구조체의 주소를 직접 얻는다.
// 이때 참조 개수가 증가한다.
NTSTATUS status = ObReferenceObjectByHandle(
handle,
GENERIC_ALL,
NULL,
KernelMode,
&pEprocess,
&obj_handle );
if( pEprocess != 0 )
{
// ObjectTable에 등록된 주소(물리주소)의 0x84에(xp,2003) PID값이 저장되어 있다.
int id = *((int*)((char*)pEprocess + 0x84));
if( id == 2648 ) // PID 값을 조사
{
DbgPrint("no kill");
return STATUS_SUCCESS;
}
// 구조체를 다 사용했으므로 참조개수를 줄인다.
ObDereferenceObject( pEprocess );
}
}
// 기존의 함수로 다시 보낸다.
return old( handle, ExitCode );
}
// 실제 SDT 훅을 하는 함수.
void InstallSDTHook()
{
// 함수의 서비스 번호를 구한다.
int id = SERIVCE_ID(ZwTerminateProcess);
DbgPrint("ZwTerminateProcess service ID : %d", id );
// 원래 함수의 주소를 보관해 둔다.
old = (FUNC)KeServiceDescriptorTable.ServiceTableBase[ id ];
__asm { CLI } // interrupt 중지 - 다른 스레드가 실행흐름을 중지시키지 못하게 한다.(커널모드만 가능)
// SDT Table을 수정(Hooking) 한다.
KeServiceDescriptorTable.ServiceTableBase[ id ] = (unsigned int)foo;
__asm { STI } // interrupt 다시 시작 - 다른 스레드로의 전환(Context Switch) 를 가능하게 한다.
}
void UninstallSDTHook()
{
int id = SERIVCE_ID(ZwTerminateProcess);
__asm { CLI } // interrup 중지
// SDT 를 다시 원래대로 변경해 놓는다.
KeServiceDescriptorTable.ServiceTableBase[ id ] = (unsigned int)old;
__asm { STI }
}
VOID DriverUnload( PDRIVER_OBJECT pDrvObj )
{
UninstallSDTHook();
DbgPrint( "Driver Unload" );
}
NTSTATUS DriverEntry( PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath )
{
DbgPrint("DriverEntry");
pDrvObj->DriverUnload = DriverUnload;
InstallSDTHook();
return STATUS_SUCCESS;
}
#include <ntddk.h>
// 함수 이름(주소)를 가지고 SDT 서비스 번호를 얻어내는 매크로
#define SERIVCE_ID( f ) *(ULONG*)( (char*)f + 1 )
// SDT Table의 각항목을 구성하는 구조체
#pragma pack(1) // 1 Byte 단위로 align(정렬)하라는 지시어
typedef struct ServiceDescriptorEntry
{
unsigned int* ServiceTableBase; // 함수 주소
unsigned int* ServiceCounterTableBase;
unsigned int NumberOfServices;
unsigned char* ParamTableBase;
} ServiceDescriptorTableEntry_t;
#pragma pack()
// ntoskrnl.exe 에서는 SDT Table을 export 하고 있다.
__declspec(dllimport) ServiceDescriptorTableEntry_t
KeServiceDescriptorTable;
// ntoskrnl.exe 가 가진 ZwTerminateProcess를 import 한다.
// Hooking 에 대상이 되는 함수를 import
__declspec(dllimport)
NTSTATUS __stdcall ZwTerminateProcess( HANDLE handle, NTSTATUS ExitCode);
// 원래 함수의 주소를 보관하고 있어야 한다.
typedef NTSTATUS (__stdcall *FUNC)(HANDLE, NTSTATUS );
FUNC old; // 원래 함수의 주소를 담아둘 변수.
// 새로운 함수
NTSTATUS __stdcall foo( HANDLE handle, NTSTATUS ExitCode )
{
DbgPrint("TerminateProcess is Called : %x", handle );
if ( handle != (HANDLE)0 && handle != (HANDLE)-1 ) // 자기 스스로 죽는 ExitProcess 일 경우 제외
{
PVOID pEprocess = 0; // 계산기의 EPROcESS의 주소를 담을 변수
OBJECT_HANDLE_INFORMATION obj_handle; // 핸들의 관한 정보(상속여부등)를 얻어 올 변수
// User Level 에서 사용하던 핸들을 가지고 커널메모리에 있는 구조체의 주소를 직접 얻는다.
// 이때 참조 개수가 증가한다.
NTSTATUS status = ObReferenceObjectByHandle(
handle,
GENERIC_ALL,
NULL,
KernelMode,
&pEprocess,
&obj_handle );
if( pEprocess != 0 )
{
// ObjectTable에 등록된 주소(물리주소)의 0x84에(xp,2003) PID값이 저장되어 있다.
int id = *((int*)((char*)pEprocess + 0x84));
if( id == 2648 ) // PID 값을 조사
{
DbgPrint("no kill");
return STATUS_SUCCESS;
}
// 구조체를 다 사용했으므로 참조개수를 줄인다.
ObDereferenceObject( pEprocess );
}
}
// 기존의 함수로 다시 보낸다.
return old( handle, ExitCode );
}
// 실제 SDT 훅을 하는 함수.
void InstallSDTHook()
{
// 함수의 서비스 번호를 구한다.
int id = SERIVCE_ID(ZwTerminateProcess);
DbgPrint("ZwTerminateProcess service ID : %d", id );
// 원래 함수의 주소를 보관해 둔다.
old = (FUNC)KeServiceDescriptorTable.ServiceTableBase[ id ];
__asm { CLI } // interrupt 중지 - 다른 스레드가 실행흐름을 중지시키지 못하게 한다.(커널모드만 가능)
// SDT Table을 수정(Hooking) 한다.
KeServiceDescriptorTable.ServiceTableBase[ id ] = (unsigned int)foo;
__asm { STI } // interrupt 다시 시작 - 다른 스레드로의 전환(Context Switch) 를 가능하게 한다.
}
void UninstallSDTHook()
{
int id = SERIVCE_ID(ZwTerminateProcess);
__asm { CLI } // interrup 중지
// SDT 를 다시 원래대로 변경해 놓는다.
KeServiceDescriptorTable.ServiceTableBase[ id ] = (unsigned int)old;
__asm { STI }
}
VOID DriverUnload( PDRIVER_OBJECT pDrvObj )
{
UninstallSDTHook();
DbgPrint( "Driver Unload" );
}
NTSTATUS DriverEntry( PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath )
{
DbgPrint("DriverEntry");
pDrvObj->DriverUnload = DriverUnload;
InstallSDTHook();
return STATUS_SUCCESS;
}
Tag | WDM