實現關閉程式函式,殺掉pchunter

Editor發表於2018-04-04
前段時間包同學到一家公司去面試,面試官問他如果不用TerminateProcess如何實現關閉程式,作為一個快要畢業的人來說對這個問題很敏感,畢竟也要面對這關.
現在問題擺在面前,如何解決這個問題,想了想最好的方法就是直接看作業系統怎麼實現 TerminateProcess 的自己實現個就好了,在一定程度上就可以阻止別人通過hook技術來攔截.
    
這段程式碼很早就寫好了,但是帖子什麼的一直沒什麼時間寫(薛老師今天講的殼還沒有脫),寫完這篇帖子去脫殼了
    
另外: 本人小菜,大神們輕點噴

    
開始吧!下面截圖的程式碼都是win2000的程式碼,在看原始碼的同時有時候需要用ida開啟win7的ntoskrnl.exe對比著看,所幸的是雖然經過很多版本更迭,但是這塊的基本原理沒啥變化,所以就儘量不貼ida反彙編的圖了(可讀性差)

    NtTerminateProcess的函式實現,其中最關鍵的 如圖:


    實現關閉程式函式,殺掉pchunter

   實現關閉程式函式,殺掉pchunter


  這個函式主要乾的事情就是遍歷程式的執行緒,然後對每個執行緒執行PspTerminateThreadByPointer


    再分析下 PspTerminateThreadByPointer 函式的實現

     這個函式是分兩種情況的:

     情況一,是執行緒自己關閉自己:直接執行PspExitThread


        實現關閉程式函式,殺掉pchunter

        PspExitThread這個函式太龐雜簡單說下它的作用:

        1. 執行了一大堆清理程式碼,主要清理當前執行緒Ethread的資源

        2. 從排程連結串列和等待連結串列中去掉它

        3. 如果是程式的最後一個執行緒,直接清理程式空間

        4. 執行KiSwapThread切換到一個新執行緒去


          實現關閉程式函式,殺掉pchunter


    情況二,關閉掉別的執行緒:在對方線執行緒中插入一個核心apc,這個核心apc最後會呼叫PspExitThread函式


         實現關閉程式函式,殺掉pchunter

         實現關閉程式函式,殺掉pchunter


       PspTerminateThreadByPointer 和NtTerminateProcess分析總結:

       1. 所謂殺死程式,其實只要把每個執行緒殺死就好了,最後一個執行緒會負責收屍的

       2. 執行緒不能被殺死,只能自殺.所以如果想殺掉執行緒最好讓它自己執行自殺程式碼,核心apc(後面會簡單講下核心apc,沒法深入再講就錯題了)是個不錯的選擇


      核心Apc執行的時機(講的不對請指正哈):

     1. 中斷和異常返回,下面是ReatOs的程式碼(貼程式碼為證,避免別人說我瞎嗶嗶O(∩_∩)O哈哈~)

        實現關閉程式函式,殺掉pchunter

    2. 高irql轉到第irql,這塊直接看win732逆向的程式碼:KfLowerIrql

        實現關閉程式函式,殺掉pchunter

         主要關注: HalpCheckForSoftwareInterrrupt

          實現關閉程式函式,殺掉pchunter

          執行apc的地方就是KiDeliverApc

          實現關閉程式函式,殺掉pchunter

      3. 執行緒切換的時候,還是直接貼win2000的程式碼

         實現關閉程式函式,殺掉pchunter

        實現關閉程式函式,殺掉pchunter



        原理講完了,現在直接貼效果圖了:

        殺掉之前,寫好程式id:

         實現關閉程式函式,殺掉pchunter


    執行完殺掉的程式碼:

  實現關閉程式函式,殺掉pchunter


另外直接附上程式碼:

 Entry.c


#include <KrTypeDef.h>

#include <ntddk.h>

//需要殺死的程式id

#define PCHUNTER_ID   3232

VOID DriverUnload(PDRIVER_OBJECT pDriver);

PEPROCESS LookupProcess(HANDLE hPid);

PETHREAD LookupThread(HANDLE hTid);

VOID KillProcess(PEPROCESS pEProcess);

ULONG GetPspTerminateThreadByPointer();

ULONG GetPspExitThread(ULONG PspTerminateThreadByPointer);

VOID SelfTerminateThread(

    KAPC *Apc,

    PKNORMAL_ROUTINE *NormalRoutine,

    PVOID *NormalContext,

    PVOID *SystemArgument1,

    PVOID *SystemArgument2);

fpTypePspExitThread g_fpPspExitThreadAddr = NULL;

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pPath)

{

    DbgBreakPoint();

    pDriver->DriverUnload = DriverUnload;

    //提前把函式查詢出來

    ULONG uPspTerminateThreadByPointerAddr =  GetPspTerminateThreadByPointer();

    if (0 == uPspTerminateThreadByPointerAddr)

    {

        KdPrint(("查詢PspTerminateThreadByPointerAddr地址出錯\n"));

        return STATUS_SUCCESS;

    }

    g_fpPspExitThreadAddr = (fpTypePspExitThread)GetPspExitThread(uPspTerminateThreadByPointerAddr);

    if (NULL == g_fpPspExitThreadAddr)

    {

        KdPrint(("查詢PspExitThread地址出錯\n"));

        return STATUS_SUCCESS;

    }

    //

    PEPROCESS pProcess = LookupProcess((HANDLE)PCHUNTER_ID);

    if (NULL == pProcess)

    {

        KdPrint((("沒有在PsCidTable中找到程式,尼瑪不會隱藏了吧\n")));

    }

    else

    {

        KillProcess(pProcess);

    }

    return STATUS_SUCCESS;

}

VOID DriverUnload(PDRIVER_OBJECT pDriver)

{

    KdPrint(("驅動退出\n"));

}

PEPROCESS LookupProcess(HANDLE hPid)

{

    PEPROCESS pEProcess = NULL;

    if (NT_SUCCESS(PsLookupProcessByProcessId(hPid, &pEProcess)))

        return pEProcess;

    return NULL;

}

VOID KillProcess(PEPROCESS pEProcess)

{

    PEPROCESS pEProc = NULL;

    PETHREAD  pEThrd = NULL;

    ULONG i = 0;

    for (i = 4; i < 0x25600; i += 4)

    {

        pEThrd = LookupThread((HANDLE)i);

        if (!pEThrd)  continue;

        pEProc = IoThreadToProcess(pEThrd);

        if (pEProc == pEProcess)

        {

            PKAPC pApc = NULL;

            pApc = (PKAPC)ExAllocatePool(NonPagedPool, sizeof(KAPC));

            if (NULL == pApc) return;

            //插入核心apc

            KeInitializeApc(pApc, (PKTHREAD)pEThrd, OriginalApcEnvironment, (PKKERNEL_ROUTINE)&SelfTerminateThread, NULL, NULL, 0, NULL);

            KeInsertQueueApc(pApc, NULL, 0, 2);

        }

        ObDereferenceObject(pEThrd);

    }

}

PETHREAD LookupThread(HANDLE hTid)

{

    PETHREAD pEThread = NULL;

    if (NT_SUCCESS(PsLookupThreadByThreadId(hTid, &pEThread)))

        return pEThread;

    return NULL;

}

VOID SelfTerminateThread(

    KAPC *Apc, 

    PKNORMAL_ROUTINE *NormalRoutine, 

    PVOID *NormalContext, 

    PVOID *SystemArgument1, 

    PVOID *SystemArgument2)

{

    ExFreePool(Apc);

    g_fpPspExitThreadAddr(STATUS_SUCCESS);

}

ULONG GetPspTerminateThreadByPointer()

{

    UNICODE_STRING funcName;

    RtlInitUnicodeString(&funcName, L"PsTerminateSystemThread");

    ULONG step = 0;

    ULONG targetFunAddr = 0;

    ULONG baseFunAddr = (ULONG)MmGetSystemRoutineAddress(&funcName);

    for (step = baseFunAddr; step < (baseFunAddr + 1024); step++)

    {

        //searching for 0x50,0xe8

        if (((*(PUCHAR)(UCHAR*)(step - 1)) == 0x50) && ((*(PUCHAR)(UCHAR*)(step)) == 0xe8))

        {

            ULONG offset = *(PULONG)(step + 1);

            targetFunAddr = step + 5 + offset;

            break;

        }

    }

    return targetFunAddr;

} //PspExitThread stamp code:0x0c 0xe8

ULONG GetPspExitThread(ULONG PspTerminateThreadByPointer)

{

    ULONG step = 0;

    ULONG targetFunAddr = 0;

    ULONG baseFunc = PspTerminateThreadByPointer;

    for (step = baseFunc; step < (baseFunc + 1024); step++)

    {

        //searching for 0x0c,0xe8

        if (((*(PUCHAR)(UCHAR*)(step - 1)) == 0x0c) && ((*(PUCHAR)(UCHAR*)(step)) == 0xe8))

        {

            ULONG m_offset = *(PULONG)(step + 1);

            targetFunAddr = step + 5 + m_offset;

            break;

        }

    }

    return targetFunAddr;



 KrTypeDef.h


#pragma  once

#include <ntifs.h>

#include <ntddk.h>

#pragma warning(disable:4189 4100)

typedef enum _KAPC_ENVIRONMENT

{

    OriginalApcEnvironment,

    AttachedApcEnvironment,

    CurrentApcEnvironment,

    InsertApcEnvironment

} KAPC_ENVIRONMENT;

typedef VOID (*PKNORMAL_ROUTINE) (

    IN PVOID NormalContext,

    IN PVOID SystemArgument1,

    IN PVOID SystemArgument2

    );

typedef VOID(*PKKERNEL_ROUTINE) (

    IN struct _KAPC *Apc,

    IN OUT PKNORMAL_ROUTINE *NormalRoutine,

    IN OUT PVOID *NormalContext,

    IN OUT PVOID *SystemArgument1,

    IN OUT PVOID *SystemArgument2

    );

typedef VOID(*PKRUNDOWN_ROUTINE) (

    IN struct _KAPC *Apc

    );

VOID NTAPI KeInitializeApc(__in PKAPC   Apc,

    __in PKTHREAD     Thread,

    __in KAPC_ENVIRONMENT     TargetEnvironment,

    __in PKKERNEL_ROUTINE     KernelRoutine,

    __in_opt PKRUNDOWN_ROUTINE    RundownRoutine,

    __in PKNORMAL_ROUTINE     NormalRoutine,

    __in KPROCESSOR_MODE  Mode,

    __in PVOID    Context

    );

BOOLEAN  NTAPI KeInsertQueueApc(IN PKAPC Apc,

    IN PVOID SystemArgument1,

    IN PVOID SystemArgument2,

    IN KPRIORITY PriorityBoost);

typedef VOID(NTAPI *fpTypePspExitThread)(

    IN NTSTATUS ExitStatus

    );

#define OFFSET(type, f) ((SIZE_T) \

    ((char *)&((type *)0)->f - (char *)(type *)0))



ps:程式碼有處bug,就是假設在殺執行緒的同時建立執行緒怎麼辦?

實現關閉程式函式,殺掉pchunter

最後謝謝大家!

相關文章