windows內核代碼之進程操作


[toc]

一丶簡介

整理一下windows內核中.常用的代碼.這里只整理下進程的相關代碼.

二丶 windows內核之遍歷進程

內核中記錄進程的結構體是EPROCESS結構.所以只需要遍歷這個結構即可.標准方法可以使用ZwQuerySystemInformation函數.使用SystemProcessInformation功能號. 另外也有很多種枚舉進程的方法比如找到EPROCESS結構進行枚舉的.(CPU結構體 KPCR)等等.不過兼容性都是不太好.另一種方法是枚舉句柄表 PspCidTable里面有記錄EPROCESS 也能檢查出斷鏈等隱藏的進程.不過缺點就是. PspCidTable並不是一個公開的變量.要活的它的地址的話.你就需要使用硬編碼或者符號了.但是大家知道使用硬編碼那么就不會跟着系統走了.如果想要通用那么就最好不要使用. 這里看到網上有更簡單的方法.
只用使用幾個公開API即可.

  • PsLookUpProcessByProcessId 根據進程Pid返回進程的EPROCESS

  • ObDereferenceObject 返回的EPROCESS會被引用一次,進行解引用.

另外還需要幾個API可以獲得進程的名字 進程的父PID等等

  • PsGetProcessImageFileName(IN PEPROCESS proc)
  • PsGetProcessInheritedFromUniqueProcessId(IN PEPROCESS proc)

遍歷多大,根據進程PID排列.步進為4, 總工是 2^31 -1即可.

具體代碼如下:

#include <ntifs.h>

NTKERNELAPI UCHAR* PsGetProcessImageFileName(IN PEPROCESS Process); //未公開的進行導出即可
NTKERNELAPI HANDLE PsGetProcessInheritedFromUniqueProcessId(IN PEPROCESS Process);//未公開進行導出

void DriverUnLoad(PDRIVER_OBJECT pDriverObj)
{
	KdPrint(("驅動卸載成功"));
}
/*
1.枚舉所有進程.  2^31方
*/
PEPROCESS GetEprocessByPid(HANDLE pid)
{
	//根據PID 返回PEPROCESS
	PEPROCESS pEpro = NULL;
	NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
	ntStatus = PsLookupProcessByProcessId(pid, &pEpro);
	if (NT_SUCCESS(ntStatus))
	{
		return pEpro;
	}
	return NULL;
}
void IteratorProcess()
{
	PEPROCESS pCurrentEprocess = NULL;
	for (int i = 0; i < 2147483648; i += 4)
	{
		pCurrentEprocess = GetEprocessByPid((HANDLE)i);
		if (pCurrentEprocess != NULL)
		{
			DbgPrint("進程名字為: %s 進程PID = %d 進程的父Pid = %d\r\n", 
				PsGetProcessImageFileName(pCurrentEprocess),
				PsGetProcessId(pCurrentEprocess),
				PsGetProcessInheritedFromUniqueProcessId(pCurrentEprocess));
			ObDereferenceObject(pCurrentEprocess); //解引用
		}
	}
}

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObj, PUNICODE_STRING pRegPath)
{
	ULONG iCount = 0;
	NTSTATUS ntStatus;
	pDriverObj->DriverUnload = DriverUnLoad;
	IteratorProcess();  //遍歷進程

	return STATUS_SUCCESS;
}


結果

三丶Windows內核之暫停與恢復進程

在Ring3我們想暫停與恢復進程一般都是使用NativeApi.動態獲取等等.
在內核中一樣也有.在VISTA之后,便有導出了.

  • ** NTKERNELAPI NTSTATUS PsSuspendProcess(PEPROCESS Proc) **
  • ** NTKERNELAPI NTSTATUS PsResumeProcess(PEPROCESS Proc) ;**

未掛起前

加載驅動進行掛起

#include <ntifs.h>

NTKERNELAPI NTSTATUS PsSuspendProcess(PEPROCESS proc);	//暫停進程
NTKERNELAPI NTSTATUS PsResumeProcess(PEPROCESS proc);	//恢復進程
void DriverUnLoad(PDRIVER_OBJECT pDriverObj)
{
	KdPrint(("驅動卸載成功"));
}
/*
1.枚舉所有進程.  2^31方
*/
PEPROCESS GetEprocessByPid(HANDLE pid)
{
	//根據PID 返回PEPROCESS
	PEPROCESS pEpro = NULL;
	NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
	ntStatus = PsLookupProcessByProcessId(pid, &pEpro);
	if (NT_SUCCESS(ntStatus))
	{
		return pEpro;
	}
	return NULL;
}

void TestSusPendProcess(ULONG pid)
{
	PEPROCESS pCurrentEprocess = NULL;
	pCurrentEprocess = GetEprocessByPid((HANDLE)pid);
	if (pCurrentEprocess != NULL)
	{
		PsSuspendProcess(pCurrentEprocess);
		DbgPrint("掛起進程成功\r\n");
		ObDereferenceObject(pCurrentEprocess);
	}

}

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObj, PUNICODE_STRING pRegPath)
{
	ULONG iCount = 0;
	NTSTATUS ntStatus;
	pDriverObj->DriverUnload = DriverUnLoad;
	//IteratorProcess();  //遍歷進程
	TestSusPendProcess(2728); //掛起進程,傳入指定PID
	return STATUS_SUCCESS;
}

恢復進程代碼同上.不一一舉例.

四丶結束進程

4.1 標准方法結束

標准方法結束 就是采用ZwOpenProcess 打開進程獲取句柄.然后使用內核函數 ZwTerminateProcess結束. 最后ZwClose關閉句柄.
非標准結束就是Attach進程.然后內存清零來結束這個進程.如果能Attach上.那么就可以用來強殺進程.當然Attach可以. 自己修改頁表.(PDE PTE)等.修改指定內存也是一樣的.

代碼如下

void ZwKillProcess(ULONG pid)
{
	HANDLE ProcessHandle = NULL;
	OBJECT_ATTRIBUTES obj;
	CLIENT_ID cid = { 0 };
	NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
	InitializeObjectAttributes(&obj,NULL,OBJ_KERNEL_HANDLE|OBJ_CASE_INSENSITIVE,NULL,NULL);
	cid.UniqueProcess = (HANDLE)pid;
	cid.UniqueThread = 0;
	ntStatus =  ZwOpenProcess(&ProcessHandle, GENERIC_ALL, &obj, &cid);
	if (NT_SUCCESS(ntStatus))
	{
		ZwTerminateProcess(ProcessHandle, 0);
		ZwClose(ProcessHandle);
	}
	ZwClose(ProcessHandle);
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObj, PUNICODE_STRING pRegPath)
{
	ULONG iCount = 0;
	NTSTATUS ntStatus;
	pDriverObj->DriverUnload = DriverUnLoad;
	//IteratorProcess();  //遍歷進程
	ZwKillProcess(2728); //掛起進程,傳入指定PID
	return STATUS_SUCCESS;
}

4.2非標准方法結束進程

非標准的方式就是Attach進進程進行內存清零.這里提供了兩種方法.原理是一樣

KeAttachProcess方法 與 KeStackAttachProcess方法. 其中第一種屬於舊方法了.根據MSDN所說API已經升級為了KeStackAttachProcess

代碼如下




#include <ntifs.h>

NTKERNELAPI UCHAR* PsGetProcessImageFileName(IN PEPROCESS Process); //未公開的進行導出即可


NTKERNELAPI VOID NTAPI KeAttachProcess(PEPROCESS Process);
NTKERNELAPI VOID NTAPI KeDetachProcess();

void DriverUnLoad(PDRIVER_OBJECT pDriverObj)
{
	KdPrint(("驅動卸載成功"));
}
/*
1.枚舉所有進程.  2^31方
*/
PEPROCESS GetEprocessByPid(HANDLE pid)
{
	//根據PID 返回PEPROCESS
	PEPROCESS pEpro = NULL;
	NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
	ntStatus = PsLookupProcessByProcessId(pid, &pEpro);
	if (NT_SUCCESS(ntStatus))
	{
		return pEpro;
	}
	return NULL;
}



//新方法
void MemKillProcess(HANDLE pid)
{
	PEPROCESS proc = NULL;
	NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
	PKAPC_STATE pApcState = NULL;


	PsLookupProcessByProcessId((HANDLE)pid,&proc);
	if (proc == 0)
	{
		
		return;
	}
	
	//KeAttachProcess(proc);
	//KeDetachProcess()  等都已經過時.所以使用新的
	pApcState = (PKAPC_STATE)ExAllocatePoolWithTag(NonPagedPool, sizeof(PKAPC_STATE), '1111');
	if (NULL == pApcState)
	{
		ObDereferenceObject(proc);
		return;
	}
	__try{
		KeStackAttachProcess(proc, pApcState);
		//KeAttachProcess(proc);
		for (int i = 0x10000; i < 0x20000000; i += PAGE_SIZE)
		{
			__try
			{
				memset((PVOID)i, 0, PAGE_SIZE);
			}
			__except (1)
			{
				;		//內部處理異常
			}
		}
		KeUnstackDetachProcess(pApcState);
		//KeDetachProcess();
		ObDereferenceObject(proc);
		return;
	}
	__except (1)
	{
		DbgPrint("強殺出錯\r\n");
		KeUnstackDetachProcess(pApcState);
		ObDereferenceObject(proc);
	}


	return;
}
HANDLE GetPidByProcessName(char *ProcessName)
{
	PEPROCESS pCurrentEprocess = NULL;
	HANDLE pid = 0;
	DbgPrint("尋找名為%s的PID\r\n", ProcessName);
	for (int i = 0; i < 2147483647; i += 4)
	{
		pCurrentEprocess = GetEprocessByPid((HANDLE)i);
		if (pCurrentEprocess != NULL)
		{
			/*DbgPrint("進程名字為: %s 進程PID = %d 進程的父Pid = %d\r\n",
				PsGetProcessImageFileName(pCurrentEprocess),
				PsGetProcessId(pCurrentEprocess),
				PsGetProcessInheritedFromUniqueProcessId(pCurrentEprocess));*/
			pid = PsGetProcessId(pCurrentEprocess);
			if (strstr(PsGetProcessImageFileName(pCurrentEprocess), ProcessName) != NULL)
			{
				ObDereferenceObject(pCurrentEprocess); //解引用
				DbgPrint("找到了\r\n");
				return pid;
			}
			ObDereferenceObject(pCurrentEprocess); //解引用
		}
	}
	DbgPrint("未找到\r\n");
	return (HANDLE)-1;
}
//舊方法
void OldMemKillProcess(HANDLE pid)
{
	SIZE_T i = 0;
	//依附進程
	PEPROCESS proc = 0;
	PsLookupProcessByProcessId(pid, &proc);
	if (NULL == proc)
	{
		return;
	}
	KeAttachProcess((PEPROCESS)proc); //這里改為指定進程的 EPROCESS
	for (i = 0x10000; i < 0x20000000; i += PAGE_SIZE)
	{
		__try
		{
			memset((PVOID)i, 0, PAGE_SIZE); //把進程內存全部置零
		}
		_except(1)
		{
			;
		}
	}
	//退出依附進程
	KeDetachProcess();
	ObDereferenceObject(proc);
}

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObj, PUNICODE_STRING pRegPath)
{
	ULONG iCount = 0;
	NTSTATUS ntStatus;
	pDriverObj->DriverUnload = DriverUnLoad;

	MemKillProcess(GetPidByProcessName("calc.exe")); //新方法
	OldMemKillProcess(GetPidByProcessName("calc.exe"));//舊方法
	return STATUS_SUCCESS;
}

兩種方法在win7 64上面都可以.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM