[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上面都可以.