Хук ZwTerminateProcess в драйвере x64 (без SSDT)

Я нашел и прочитал этот вопрос, но не нашел ответа альтернатива перехвата SSDT в системах x64

Я хочу защитить свое приложение от завершения другими программами. В 32-битной версии Windows я использовал SSDT hooking для подключения ZwTerminateProcess или ZwOpenProcess. Я должен обновить свою программу для использования в 64-битной версии Windows. И, к сожалению, в 64-битных окнах мы не можем использовать хук SSDT (Поскольку Patch Guard (KPP)), обратите внимание, что в этом случае я не хочу обходить PG и должен использовать только перехват в режиме ядра. Например, я не хочу, чтобы моя программа начинала завершаться (даже) следующим кодом:

NTSTATUS drvTerminateProcess( ULONG ulProcessID )
{
    NTSTATUS          ntStatus = STATUS_SUCCESS;
    HANDLE            hProcess;
    OBJECT_ATTRIBUTES ObjectAttributes;
    CLIENT_ID         ClientId;

    DbgPrint( "drvTerminateProcess( %u )", ulProcessID );

    InitializeObjectAttributes( &ObjectAttributes, NULL, OBJ_INHERIT, NULL, NULL ); 

    ClientId.UniqueProcess = (HANDLE)ulProcessID;
    ClientId.UniqueThread  = NULL;

    __try
    {
        ntStatus = ZwOpenProcess( &hProcess, PROCESS_ALL_ACCESS, &ObjectAttributes, &ClientId );
        if( NT_SUCCESS(ntStatus) )
        {
            ntStatus = ZwTerminateProcess( hProcess, 0 );
            if( !NT_SUCCESS(ntStatus) )
                DbgPrint( "ZwTerminateProcess failed with status : %08X\n", ntStatus );

            ZwClose( hProcess );
        }
        else
            DbgPrint( "ZwOpenProcess failed with status : %08X\n", ntStatus );
    }
    __except( EXCEPTION_EXECUTE_HANDLER )
    {
        ntStatus = STATUS_UNSUCCESSFUL;
        DbgPrint( "Exception caught in drvTerminateProcess()" );
    }

    return ntStatus;
}

Для выполнения этой работы я использовал следующую функцию (NewZwOpenProcess) и заменил ее оригинальной ZwOpenProcess в SSDT, но в x64 windows я не знаю, что мне делать :( :

NTSTATUS NewZwOpenProcess(
        OUT PHANDLE ProcessHandle,
        IN ACCESS_MASK DesiredAccess,
        IN POBJECT_ATTRIBUTES ObjectAttributes,
        IN PCLIENT_ID ClientId OPTIONAL)
{
        HANDLE ProcessId;

    __try 
    {
            ProcessId = ClientId->UniqueProcess;
    }
    __except(EXCEPTION_EXECUTE_HANDLER)
    {
       return STATUS_INVALID_PARAMETER;
    }
   
   if (ProcessId == (HANDLE)11) //Check if the PID matches our protected process PID (My programm)
    {
     return STATUS_ACCESS_DENIED; 
    }
  else 
    return OldZwOpenProcess(ProcessHandle, DesiredAccess,ObjectAttributes, ClientId);
}

Есть идеи ??

(Извините, если мой английский плохой)


person Behrooz    schedule 12.12.2013    source источник
comment
И именно поэтому нам нравится Patch Guard.   -  person Hans Passant    schedule 12.12.2013
comment
@HansPassant :), Да, мы любим PG, но я разрабатываю программное обеспечение для обеспечения безопасности, и для меня важно защитить свои программы.   -  person Behrooz    schedule 12.12.2013
comment
Microsoft разработала PG, так что вам больше не нужны такие глупые хаки.   -  person Hans Passant    schedule 12.12.2013
comment
@HansPassant Да, вы правы, но PG предотвращает только руткиты и вредоносные программы режима ядра, а не для защиты пользователей.   -  person Behrooz    schedule 13.12.2013


Ответы (4)


Я нашел свой ответ, я использую обратные вызовы режима ядра.

#include <ntddk.h>
#include <common.h>

// coded by Behrooz

VOID UnloadRoutine(IN PDRIVER_OBJECT DriverObject)
{

    FreeProcFilter();
    DbgPrintEx( DPFLTR_IHVDRIVER_ID,  DPFLTR_INFO_LEVEL,"Unloaded\n");
}

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,  IN PUNICODE_STRING RegistryPath)
{

    NTSTATUS status = RegisterCallbackFunction();
  if(!NT_SUCCESS(status))
  {
     DbgPrintEx( DPFLTR_IHVDRIVER_ID,  DPFLTR_ERROR_LEVEL,"Faild to RegisterCallbackFunction .status : 0x%X \n",status);
  }
    DriverObject->DriverUnload = UnloadRoutine;

    DbgPrintEx( DPFLTR_IHVDRIVER_ID,  DPFLTR_INFO_LEVEL,"Driver Loaded\n");

    return STATUS_SUCCESS;

}
//
// PRE OPERATION
//
OB_PREOP_CALLBACK_STATUS ObjectPreCallback(
  IN  PVOID RegistrationContext,
  IN  POB_PRE_OPERATION_INFORMATION OperationInformation
)
{
    LPSTR ProcName;
    // OB_PRE_OPERATION_INFORMATION OpInfo;



UNREFERENCED_PARAMETER(RegistrationContext);


ProcName=GetProcessNameFromPid(PsGetProcessId((PEPROCESS)OperationInformation->Object));

if( !_stricmp(ProcName,"calc.exe") )
{
    if (OperationInformation->Operation == OB_OPERATION_HANDLE_CREATE)
     {
       if ((OperationInformation->Parameters->CreateHandleInformation.OriginalDesiredAccess & PROCESS_TERMINATE) == PROCESS_TERMINATE)
         {
           OperationInformation->Parameters->CreateHandleInformation.DesiredAccess &= ~PROCESS_TERMINATE;
         }
       if ((OperationInformation->Parameters->CreateHandleInformation.OriginalDesiredAccess & PROCESS_VM_OPERATION) == PROCESS_VM_OPERATION)
        {
          OperationInformation->Parameters->CreateHandleInformation.DesiredAccess &= ~PROCESS_VM_OPERATION;
        }
       if ((OperationInformation->Parameters->CreateHandleInformation.OriginalDesiredAccess & ~PROCESS_VM_READ) == PROCESS_VM_READ)
        {
         OperationInformation->Parameters->CreateHandleInformation.DesiredAccess &= ~PROCESS_VM_READ;
        }
      if ((OperationInformation->Parameters->CreateHandleInformation.OriginalDesiredAccess & PROCESS_VM_WRITE) == PROCESS_VM_WRITE)
        {
         OperationInformation->Parameters->CreateHandleInformation.DesiredAccess &= ~PROCESS_VM_WRITE;
        }
     }
}
    DbgPrintEx( DPFLTR_IHVDRIVER_ID,  DPFLTR_INFO_LEVEL,"ObjectPreCallback ----> Process Name [%s] \n", ProcName);
   return OB_PREOP_SUCCESS;
}
//
//POST OPERATION
//

VOID ObjectPostCallback(
  IN  PVOID RegistrationContext,
  IN  POB_POST_OPERATION_INFORMATION OperationInformation
)
{
   DbgPrintEx( DPFLTR_IHVDRIVER_ID,  DPFLTR_INFO_LEVEL,"PostProcCreateRoutine. \n");
}
//
// REGISTE CALLBACK FUNCTION
//

NTSTATUS RegisterCallbackFunction()
{
    NTSTATUS ntStatus = STATUS_SUCCESS;
    UNICODE_STRING Altitude;
    USHORT filterVersion = ObGetFilterVersion();
    USHORT registrationCount = 1;
    OB_OPERATION_REGISTRATION RegisterOperation;
    OB_CALLBACK_REGISTRATION RegisterCallBack;
    REG_CONTEXT RegistrationContext;
    memset(&RegisterOperation, 0, sizeof(OB_OPERATION_REGISTRATION));
    memset(&RegisterCallBack, 0, sizeof(OB_CALLBACK_REGISTRATION));
    memset(&RegistrationContext, 0, sizeof(REG_CONTEXT));
    RegistrationContext.ulIndex = 1;
    RegistrationContext.Version = 120;
    if (filterVersion == OB_FLT_REGISTRATION_VERSION) {
        DbgPrintEx( DPFLTR_IHVDRIVER_ID,  DPFLTR_INFO_LEVEL,"Filter Version is correct.\n");

        RegisterOperation.ObjectType = PsProcessType;
        RegisterOperation.Operations = OB_OPERATION_HANDLE_CREATE;
        RegisterOperation.PreOperation = ObjectPreCallback;
        RegisterOperation.PostOperation = ObjectPostCallback;
        RegisterCallBack.Version = OB_FLT_REGISTRATION_VERSION;
        RegisterCallBack.OperationRegistrationCount = registrationCount;
        RtlInitUnicodeString(&Altitude, L"XXXXXXX");
        RegisterCallBack.Altitude = Altitude;
        RegisterCallBack.RegistrationContext = &RegistrationContext;
        RegisterCallBack.OperationRegistration = &RegisterOperation;
        DbgPrintEx( DPFLTR_IHVDRIVER_ID,  DPFLTR_INFO_LEVEL,"Register Callback Function Entry.\n");


        ntStatus = ObRegisterCallbacks(&RegisterCallBack, &_CallBacks_Handle);
        if (ntStatus == STATUS_SUCCESS) {
        DbgPrintEx( DPFLTR_IHVDRIVER_ID,  DPFLTR_INFO_LEVEL,"Register Callback Function Successful.\n");
        }
        else {
            if (ntStatus == STATUS_FLT_INSTANCE_ALTITUDE_COLLISION) {
                DbgPrintEx( DPFLTR_IHVDRIVER_ID,  DPFLTR_ERROR_LEVEL,"Status Filter Instance Altitude Collision.\n");
            }
            if (ntStatus == STATUS_INVALID_PARAMETER) {
               DbgPrintEx( DPFLTR_IHVDRIVER_ID,  DPFLTR_ERROR_LEVEL,"Status Invalid Parameter.\n");
            }
            if (ntStatus == STATUS_ACCESS_DENIED) {
                DbgPrintEx( DPFLTR_IHVDRIVER_ID,  DPFLTR_ERROR_LEVEL,"The callback routines do not reside in a signed kernel binary image.\n");
            }
            if (ntStatus == STATUS_INSUFFICIENT_RESOURCES) {
               DbgPrintEx( DPFLTR_IHVDRIVER_ID,  DPFLTR_ERROR_LEVEL,"Status Allocate Memory Failed.\n");
            }
              DbgPrintEx( DPFLTR_IHVDRIVER_ID,  DPFLTR_ERROR_LEVEL,"Register Callback Function Failed with 0x%08x\n",ntStatus);
        }
    }
    else {
               DbgPrintEx( DPFLTR_IHVDRIVER_ID,  DPFLTR_ERROR_LEVEL,"Filter Version is not supported.\n");
    }
    return ntStatus;
}
//
// FREE PROC FILTER
//

NTSTATUS FreeProcFilter()
{
    // if the callbacks are active - remove them
    if (NULL != _CallBacks_Handle)
    {
        ObUnRegisterCallbacks(_CallBacks_Handle);
        _CallBacks_Handle=NULL;
    }
    return STATUS_SUCCESS;
}


LPSTR GetProcessNameFromPid(HANDLE pid)
{
    PEPROCESS Process;
    if (PsLookupProcessByProcessId(pid, & Process) == STATUS_INVALID_PARAMETER)
    {
        return "pid???";
    }
    return (LPSTR)PsGetProcessImageFileName(Process);

}

общий.h

#include <ntddk.h>

// coded by Behrooz

//-----------------------------------------------
//  Defines
//-----------------------------------------------

//Process Security and Access Rights
#define PROCESS_CREATE_THREAD  (0x0002)
#define PROCESS_CREATE_PROCESS (0x0080)
#define PROCESS_TERMINATE      (0x0001)
#define PROCESS_VM_WRITE       (0x0020)
#define PROCESS_VM_READ        (0x0010)
#define PROCESS_VM_OPERATION   (0x0008)
#define PROCESS_SUSPEND_RESUME (0x0800)


#define MAXIMUM_FILENAME_LENGTH 256
//-----------------------------------------------
// callback
//-----------------------------------------------

PVOID _CallBacks_Handle = NULL;

typedef struct _OB_REG_CONTEXT {
    __in USHORT Version;
    __in UNICODE_STRING Altitude;
    __in USHORT ulIndex;
    OB_OPERATION_REGISTRATION *OperationRegistration;
} REG_CONTEXT, *PREG_CONTEXT;


//-----------------------------------------------
// PID2ProcName
//-----------------------------------------------
extern UCHAR *PsGetProcessImageFileName(IN PEPROCESS Process);

extern   NTSTATUS PsLookupProcessByProcessId(
     HANDLE ProcessId,
    PEPROCESS *Process
);
typedef PCHAR (*GET_PROCESS_IMAGE_NAME) (PEPROCESS Process);
GET_PROCESS_IMAGE_NAME gGetProcessImageFileName;

LPSTR GetProcessNameFromPid(HANDLE pid);



//-----------------------------------------------
//  Forward Declaration
//-----------------------------------------------
NTSTATUS DriverEntry(
    IN PDRIVER_OBJECT DriverObject, 
    IN PUNICODE_STRING RegistryPath
    );

VOID UnloadDriver(
    IN PDRIVER_OBJECT DriverObject
    );

OB_PREOP_CALLBACK_STATUS ObjectPreCallback(
  IN  PVOID RegistrationContext,
  IN  POB_PRE_OPERATION_INFORMATION OperationInformation
  );

VOID ObjectPostCallback(
  IN  PVOID RegistrationContext,
  IN  POB_POST_OPERATION_INFORMATION OperationInformation
  );

NTSTATUS RegisterCallbackFunction() ;
NTSTATUS FreeProcFilter();

Результат моего теста: введите здесь описание изображения

person Behrooz    schedule 20.12.2013
comment
Спасибо, что поделились, скажите, какую версию WDK вы используете? - person navossoc; 21.06.2014
comment
@navossoc Добро пожаловать, WINDDK версии 7600.16385.1 - person Behrooz; 22.06.2014
comment
Я пробовал этот код, но ObRegisterCallbacks возвращает STATUS_ACCESS_DENIED, хотя я подписал свой драйвер. Помоги мне, пожалуйста, - person Akhil V Suku; 03.03.2016
comment
@Behrooz, ваше решение также работает в 32-битной Windows? - person ; 09.12.2016
comment
@Behrooz, можете ли вы поделиться файлом .inf, который вы использовали? - person meraydin; 20.02.2021

Спасибо за ваш код, и я успешно тестирую его на win10 x64. Кстати, я обнаружил, что ObRegisterCallbacks возвращает STATUS_ACCESS_DENIED, хотя я подписал свой драйвер. Поэтому я спрашиваю многих людей, а затем нахожу решение для этого. Добавьте этот текст в свой «исходный» файл: LINKER_FLAGS=/integritycheck

затем вы можете восстановить и отказаться от своего драйвера. Он был найден на bbs.pediy.com.

person ruin1990    schedule 22.04.2016

Кто-то может сделать «ObUnregisterCallbacks» и даже зарегистрировать свой собственный, чтобы вы не могли его обнаружить.

person Hansa Ribe    schedule 24.02.2016
comment
И ваш собственный код может проверить, присутствует ли обратный вызов. Это то, что делают большинство приличных AV или AC, они пытаются снова зарегистрировать обратный вызов, и если действие завершается успешно, это означает, что обратный вызов был удален, так что наказывайте! - person Tayab; 16.06.2021

Похоже, файл .inf не нужен. просто SC CREATE ServiceName type= kernel binPath= pathtoyourfile.

person meraydin    schedule 25.02.2021