實現關閉進程函數,殺掉pchunter

實現關閉進程函數,殺掉pchunter

前段時間包同學到一家公司去面試,面試官問他如果不用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

#include

//需要殺死的進程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

#include

#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

最後謝謝大家!

更多幹貨文章,關注看雪學院公眾號 ikanxue


分享到:


相關文章: