實現關閉進程函數,殺掉pchunter
前段時間包同學到一家公司去面試,面試官問他如果不用TerminateProcess如何實現關閉進程,作為一個快要畢業的人來說對這個問題很敏感,畢竟也要面對這關. 現在問題擺在面前,如何解決這個問題,想了想最好的方法就是直接看操作系統怎麼實現 TerminateProcess 的自己實現個就好了,在一定程度上就可以阻止別人通過hook技術來攔截. 這段代碼很早就寫好了,但是帖子什麼的一直沒什麼時間寫(薛老師今天講的殼還沒有脫),寫完這篇帖子去脫殼了
另外: 本人小菜,大神們輕點噴
開始吧!下面截圖的代碼都是win2000的代碼,在看源碼的同時有時候需要用ida打開win7的ntoskrnl.exe對比著看,所幸的是雖然經過很多版本更迭,但是這塊的基本原理沒啥變化,所以就盡量不貼ida反彙編的圖了(可讀性差)
NtTerminateProcess的函數實現,其中最關鍵的 如圖:
這個函數主要乾的事情就是遍歷進程的線程,然後對每個線程執行PspTerminateThreadByPointer
再分析下 PspTerminateThreadByPointer 函數的實現
這個函數是分兩種情況的:
情況一,是線程自己關閉自己:直接執行PspExitThread
PspExitThread這個函數太龐雜簡單說下它的作用:
1. 執行了一大堆清理代碼,主要清理當前線程Ethread的資源
2. 從調度鏈表和等待鏈表中去掉它
3. 如果是進程的最後一個線程,直接清理進程空間
4. 執行KiSwapThread切換到一個新線程去
情況二,關閉掉別的線程:在對方線線程中插入一個內核apc,這個內核apc最後會調用PspExitThread函數
PspTerminateThreadByPointer 和NtTerminateProcess分析總結:
1. 所謂殺死進程,其實只要把每個線程殺死就好了,最後一個線程會負責收屍的
2. 線程不能被殺死,只能自殺.所以如果想殺掉線程最好讓它自己執行自殺代碼,內核apc(後面會簡單講下內核apc,沒法深入再講就錯題了)是個不錯的選擇
內核Apc執行的時機(講的不對請指正哈):
1. 中斷和異常返回,下面是ReatOs的代碼(貼代碼為證,避免別人說我瞎嗶嗶O(∩_∩)O哈哈~)
2. 高irql轉到第irql,這塊直接看win732逆向的代碼:KfLowerIrql
主要關注: HalpCheckForSoftwareInterrrupt
執行apc的地方就是KiDeliverApc
3. 線程切換的時候,還是直接貼win2000的代碼
原理講完了,現在直接貼效果圖了:
殺掉之前,寫好進程id:
執行完殺掉的代碼:
另外直接附上代碼:
Entry.c
#include <KrTypeDef.h>#include <ntddk.h>//需要殺死的進程id#define PCHUNTER_ID 3232VOID 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地址出錯
")); return STATUS_SUCCESS; } g_fpPspExitThreadAddr = (fpTypePspExitThread)GetPspExitThread(uPspTerminateThreadByPointerAddr); if (NULL == g_fpPspExitThreadAddr) { KdPrint(("查找PspExitThread地址出錯
")); return STATUS_SUCCESS; } // PEPROCESS pProcess = LookupProcess((HANDLE)PCHUNTER_ID); if (NULL == pProcess) { KdPrint((("沒有在PsCidTable中找到進程,尼瑪不會隱藏了吧
"))); } else { KillProcess(pProcess); } return STATUS_SUCCESS;}VOID DriverUnload(PDRIVER_OBJECT pDriver){ KdPrint(("驅動退出
"));}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 0xe8ULONG 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,就是假設在殺線程的同時創建線程怎麼辦?
最後謝謝大家!
更多乾貨文章,關注看雪學院公眾號 ikanxue
本文由看雪論壇 又出bug了 原創 轉載請註明來自看雪社區
推薦閱讀:
TAG:編程技術 |