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上面都可以.
windows内核代码之进程操作的更多相关文章
- windows 内核下获取进程路径
		
windows 内核下获取进程路径 思路:1):在EPROCESS结构中获取.此时要用到一个导出函数:PsGetProcessImageFileName,申明如下: NTSYSAPI UCHAR * ...
 - [5]windows内核情景分析---进程线程
		
本篇主要讲述进程的启动过程.线程的调度与切换.进程挂靠 进程的启动过程: BOOL CreateProcess ( LPCTSTR lpApplicationName, ...
 - 【旧文章搬运】Windows内核常见数据结构(进程相关)
		
原文发表于百度空间,2008-7-24========================================================================== 进程的相关结 ...
 - Windows内核之进程基本含义以及进程的创建
		
进程 1 进程的含义: 1.1 一个是操作系统用来管理进程的内核对象. 内核对象也是系统用来存放关于进程的统计信息的地方. 1.2 还有一个是地址空间,它包括全部可运行模块或DL L 模块的代 ...
 - Windows内核之进程的终止和子进程
		
1 进程终止的方法: <1>主线程的进入点函数返回(最好使用这种方法) <2>进程中的一个线程调用ExitProcesss函数(应该避免使用这样的方法). <3>还 ...
 - 《天书夜读:从汇编语言到windows内核编程》八 文件操作与注册表操作
		
1)Windows运用程序的文件与注册表操作进入R0层之后,都有对应的内核函数实现.在windows内核中,无论打开的是文件.注册表或者设备,都需要使用InitializeObjectAttribut ...
 - C++windows内核编程笔记day13 进程、线程与信号量
		
Windows进程 进程是一个容器,包括程序运行须要的代码.数据.资源等信息, windows进程的特点: 每一个进程都有自己的ID号 每一个进程都有自己的地址空间.进程之间无法訪问对方的地址空间. ...
 - 《Windows内核安全与驱动开发》 3.1 字符串操作
		
<Windows内核安全与驱动开发>阅读笔记 -- 索引目录 <Windows内核安全与驱动开发> 3.1 字符串操作 一.字符串的初始化 1. 判断下列代码为什么会蓝屏? U ...
 - Windows内核基础知识-8-监听进程、线程和模块
		
Windows内核基础知识-8-监听进程.线程和模块 Windows内核有一种强大的机制,可以在重大事件发送时得到通知,比如这里的进程.线程和模块加载通知. 本次采用链表+自动快速互斥体来实现内核的主 ...
 
随机推荐
- DevExpress之GridControl控件小知识
			
DevExpress之GridControl控件小知识 一.当代码中的DataTable中有建数据关系时,DevExpress 的 GridControl 会自动增加一个子视图 .列名也就是子表的字段 ...
 - Git 解决合并分支时的冲突
			
参考链接:https://www.liaoxuefeng.com/wiki/896043488029600/900004111093344 创建分支时,新分支的文件内容建立在原分支的基础上,我们称这时 ...
 - python基础05--深浅copy, set,bytes
			
1.1 深浅 copy 1. = 赋值操作, lis1=[1,2,3] list2 = list1 list1.append(4) 则list1,list2都变 赋值都指向同一个地址,改变一个 ...
 - Java自学-类和对象 传参
			
Java中的传参 变量有两种类型 基本类型 和类类型 参数也是变量,所以传参分为 基本类型传参 类类型传参 步骤 1 : 基本类型传参 基本类型传参 在方法内,无法修改方法外的基本类型参数 publi ...
 - IDEA新建一个Spring Boot项目
			
Maven构建项目模板 maven构建的是maven风格的纯净模板,要转变成spring boot项目需要自己添加依赖等配置. mvn archetype:generate: Maven插件原型是一个 ...
 - 5.Javascript闭包得实现原理和作用
			
闭包的实现原理和作用 1.闭包的概念:指有权访问另一个函数作用域中的变量的函数,一般情况就是在一个函数中包含另一个函数. 2.闭包的作用:访问函数内部变量.保持函数在环境中一直存在,不会被垃圾回收机制 ...
 - JS项目练习之求和(包含正则表达式验证)
			
最近在准备专升本,抽一点时间敷衍一下大家!!!嘿嘿嘿!!! 话不多说,上代码: <!DOCTYPE html> <html lang="zh-CN"> &l ...
 - javascript中的vavigator对象
			
appCodeName javaScript 1.0 介绍:与浏览器相关的内部代码名 appMinorVersion IE4及其后续的版本 介绍:辅版本号(通常应用于浏览器的补丁或服务包) appNa ...
 - C/ C++ 快速上手
			
C++ 快速上手 (一)https://www.cnblogs.com/cosmo89929/archive/2012/12/22/2828745.html C++ 快速上手 (二)https://w ...
 - 程序员式优雅表白,教你用python代码画爱心
			
还能用python代码画爱心?还有这种操作?这是什么原理? 不相信python代码可以画爱心?先来一张效果图来看看效果吧! 用python代码画爱心的思路是怎样的? 1.怎么画心形曲线 2.怎么填满心 ...