windows内核Api的学习

windows内核api就是ntoskrnl.exe导出的函数。我们能够跟调用应用层的api一样,调用内核api

只是内核api须要注意的是。假设函数导出了。而且函数文档化(也就是能够直接在msdn上搜索到)。ExFreePool函数导出。而且文档化,那么我们能够直接调用。导出了未文档化,那么我们就要声明。什么叫文档化和未文档化呢?大家来看一个函数:

UCHAR *PsGetProcessImageFileName(IN PEPROCESS Process);

 

文档化:就是如果函数导出了,而且在msdn上能够搜索到。

就是文档化我们调用文档化的函数就是直接调用。

未文档化:就是如果函数已经导出了。可是在msdn上没有搜到。就是未文档化函数我们要调用它,就得自己手动声明。

 

内核编程就跟应用层一样,都是api的调用。都是Hook,都是Hook,一样的编程思维。它们本质的差别仅仅是在于一个先后顺序。比方看图-什么叫本质的差别:顺序掉

ring3SSDT层主体实现函数的调用顺序:

OpenProcesss-->ntdll!ZwOpenProcess-->ntos!ZwOpenProcess-->ntos!NtOpenProcess-->后面。假设你以内核层和应用的角度去理解,那么就是openprocess一直调用到NtOpenProcess还有后面。

 

演示样例代码:

KernelApiCode.c

#include <ntifs.h>
#include <ntimage.h>

//调用功能号
#define SystemModuleInformation 11
#define SystemProcessesAndThreadsInformation 5


// 系统进程信息结构体
typedef struct _SYSTEM_PROCESSES
{
	ULONG NextEntryDelta;
	ULONG ThreadCount;
	ULONG Reserved[6];
	LARGE_INTEGER CreateTime;
	LARGE_INTEGER UserTime;
	LARGE_INTEGER KernelTime;
	UNICODE_STRING ProcessName;        //进程的名称
	KPRIORITY BasePriority; 
	ULONG ProcessId;                   //进程的PID
	ULONG InheritedFromProcessId;
	ULONG HandleCount;
	ULONG Reserved2[2];
	VM_COUNTERS VmCounters;
	IO_COUNTERS IoCounters;
} _SYSTEM_PROCESSES, *PSYSTEM_PROCESSES;

// 系统模块信息结构体节点
typedef struct _SYSTEM_MODULE_INFORMATION  
{
	ULONG  Reserved[2];  
	ULONG  Base;            //模块的基址
	ULONG  Size;            //模块的大小    
	ULONG  Flags;        
	USHORT Index;       
	USHORT Unknown;     
	USHORT LoadCount;   
	USHORT ModuleNameOffset;
	CHAR   ImageName[256];  //模块的名称
} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;

//模块链结构
typedef struct _tagSysModuleList
{
	ULONG ulCount;
	SYSTEM_MODULE_INFORMATION smi[1];
} MODULES, *PMODULES;

//ZwQuerySystemInformation函数导出了,可是未文档化。所以要手动声明
NTSTATUS __stdcall ZwQuerySystemInformation(
	ULONG_PTR SystemInformationClass,  //调用功能号
	PVOID SystemInformation,           //信息结构体
	ULONG SystemInformationLength,     //信息结构体的字节长度
	PULONG ReturnLength                //返回的实际长度
	);

//在驱动层遍历进程
VOID EnumProcessList()
{
	//声明变量
	NTSTATUS status;
	ULONG NeededSize,i;
	PVOID pBuffer = NULL; //用来指向缓冲区
	PSYSTEM_PROCESSES pInfo = NULL; //指向SYSTEM_PROCESSES的指针

	__try
	{
		//获取存放系统的进程和线程信息的实际字节长度
		status = ZwQuerySystemInformation(
			SystemProcessesAndThreadsInformation,
			NULL,
			0,
			&NeededSize);
		if (status != STATUS_INFO_LENGTH_MISMATCH)
		{
			//长度不匹配 
			DbgPrint("!= STATUS_INFO_LENGTH_MISMATCH");

			return;
		}

		//依据获取的NeededSize申请非分页内存
		pBuffer = ExAllocatePool(NonPagedPool, NeededSize);
		if (pBuffer != NULL)
		{
			DbgPrint("NeededSize:%d\r\n", NeededSize);

			//使用5号功能来获取系统的进程和线程的信息
			status = ZwQuerySystemInformation(
				SystemProcessesAndThreadsInformation, //SystemProcessesAndThreadsInformation = 5 
				pBuffer,
				NeededSize, 
				NULL);
			//假设调用成功
			if (NT_SUCCESS(status)) 
			{
				DbgPrint("ZwQuerySystemInformation() success\r\n");

				//指针类型转换
				pInfo = (PSYSTEM_PROCESSES)pBuffer;

				while (TRUE)
				{
					//PID=0,系统的
					if (pInfo->ProcessId == 0)
					{
						DbgPrint("PID %5d System Idle Process\r\n", pInfo->ProcessId);
					}
					else
					{	//打印进程的PID和进程的名称
						DbgPrint("PID %5d %ws\r\n", pInfo->ProcessId, pInfo->ProcessName.Buffer);//这里是unicode
					}

					//假设没有下一个就结束
					if (pInfo->NextEntryDelta == 0)
					{
						break;
					}

					//遍历下一个
					pInfo = (PSYSTEM_PROCESSES)(((PUCHAR)pInfo) + pInfo->NextEntryDelta);
				}
			}
		}

	}
	//异常的处理 
	__except(EXCEPTION_EXECUTE_HANDLER)
	{
		//输出异常信息code
		DbgPrint("%08x\r\n", GetExceptionCode());
	}

	//释放申请的非分页内存资源
	if (pBuffer != NULL)
	{
		ExFreePool(pBuffer);
		pBuffer = NULL;
	}

}

//驱动层遍历系统模块
VOID GetKernelModuleInfo()
{
	//变量的声明
	NTSTATUS status;
	ULONG NeededSize, i;
	PVOID pBuffer = NULL; //用来指向缓冲区
	PMODULES pModuleList = NULL; //指向MODULES指针

	__try
	{
		//获取存放系统模块信息结构体的缓冲区的大小
		status = ZwQuerySystemInformation(
			SystemModuleInformation, 
			NULL,
			0,
			&NeededSize);
		if (status != STATUS_INFO_LENGTH_MISMATCH)
		{
			DbgPrint("!= STATUS_INFO_LENGTH_MISMATCH");

			return;
		}

		//依据NeededSize的大小,申请非分页内存的大小
		pBuffer = ExAllocatePool(NonPagedPool, NeededSize);
		if (pBuffer)
		{
			//调用功能号11来获取系统的模块的信息
			status=ZwQuerySystemInformation(
				SystemModuleInformation, //SystemModuleInformation = 11
				pBuffer,
				NeededSize,
				NULL);
			if (NT_SUCCESS(status))
			{
				//指针类型转换
				pModuleList = (PMODULES)pBuffer;

				//遍历系统的模块的信息
				for (i = 0; i< pModuleList->ulCount; i++)
				{
					//打印系统模块的基址、模块的大小、模块的名称
					DbgPrint("0x%08X:%d:%s\r\n", pModuleList->smi[i].Base, pModuleList->smi[i].Size, pModuleList->smi[i].ImageName);
				}
			}
		}

	}
	__except(EXCEPTION_EXECUTE_HANDLER)
	{
		//打印异常的代码
		DbgPrint("%08x\r\n", GetExceptionCode());
	}

	//释放申请的非分页内存资源
	if (pBuffer)
	{
		ExFreePool(pBuffer);
		pBuffer = NULL;
	}
		
}

/*
*创建注冊表
*SafeKey注冊表的路径
*Reg_Type注冊表的键值类型
*ValueName注冊表的键值的名称
*Value注冊表的键值的值
*/
BOOLEAN Safe_CreateValueKey(PWCHAR SafeKey, ULONG_PTR Reg_Type, PWCHAR ValueName, PWCHAR Value)
{
	//声明变量
	OBJECT_ATTRIBUTES objectAttributes;
	UNICODE_STRING RegUnicodeString, Unicode_ValueName;
	NTSTATUS ntStatus;
	HANDLE hRegister;
	ULONG_PTR ulValue_DWORD;
	ULONG_PTR ulResult = 0;
	BOOLEAN bRetOK = FALSE;

	//WCHAR字符串转UNICODE_STRING字符串
	RtlInitUnicodeString(&Unicode_ValueName, ValueName); //键值的名称
	RtlInitUnicodeString(&RegUnicodeString, SafeKey); //注冊表的路径

	//初始化objectAttributes
	InitializeObjectAttributes(
		&objectAttributes,
		&RegUnicodeString,   //注冊表的路径
		OBJ_CASE_INSENSITIVE, //对大写和小写敏感 
		NULL, 
		NULL 
		);

	//打开注冊表
	ntStatus = ZwCreateKey(
		&hRegister,     //返回注冊表的句柄
		KEY_ALL_ACCESS, //注冊表的权限
		&objectAttributes,
		0,
		NULL,
		REG_OPTION_NON_VOLATILE,
		&ulResult
		);

	if (NT_SUCCESS(ntStatus))
	{
		bRetOK = TRUE;

		//依据传入參数Reg_Type来实现各种功能
		//调用ZwSetValueKey函数来设置注冊表的
		switch (Reg_Type)
		{
		case REG_SZ:
			{
				ZwSetValueKey(
					hRegister,
					&Unicode_ValueName, //键值的名称
					0,
					Reg_Type,          //键值的类型
					Value,             //键值的值
					wcslen(Value)*2
					);
				DbgPrint("REG_SZ--注冊表创建成功!\n");

				break;
			}
		case REG_EXPAND_SZ:
			{
				ZwSetValueKey(
					hRegister,
					&Unicode_ValueName, //键值的名称
					0,
					Reg_Type,           //键值的类型
					Value,              //键值的值
					wcslen(Value)*2
					);
				DbgPrint("REG_EXPAND_SZ--注冊表创建成功!\n");

				break;
			}
		case REG_DWORD:
			{
				ulValue_DWORD = sizeof(REG_DWORD);
				ZwSetValueKey(
					hRegister,
					&Unicode_ValueName,   //键值的名称
					0,
					Reg_Type,             //键值的类型
					&Value,
					sizeof(ulValue_DWORD) //键值的值
					);
				DbgPrint("REG_DWORD--注冊表创建成功!\n");

				break;
			}
		}

		//关闭句柄
		ZwClose(hRegister);
	}

	return bRetOK;
}

//******************************************************************************************************************************

//驱动卸载例程函数
VOID DriverUnload(IN PDRIVER_OBJECT DriverObject)
{
	DbgPrint("卸载完毕!\n");
}

//驱动入口函数DriverEntry
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
	//设置驱动的卸载例程函数
	DriverObject->DriverUnload = DriverUnload;

	//遍历系统的进程
	EnumProcessList();

	//遍历系统的驱动模块
	GetKernelModuleInfo();
	
	//创建注冊表
	Safe_CreateValueKey(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services\\", REG_DWORD, L"Start", (PWCHAR)0x3);
	Safe_CreateValueKey(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services\\", REG_SZ, L"Start_String", L"Hi~ i am agp");

	return STATUS_SUCCESS;
}


makefile文件:

#
# DO NOT EDIT THIS FILE!!!  Edit .\sources. if you want to add a new source
# file to this component.  This file merely indirects to the real make file
# that is shared by all the driver components of the Windows NT DDK
#

!INCLUDE $(NTMAKEENV)\makefile.def

sources文件

TARGETNAME=KernelApiCode
TARGETPATH=obj
TARGETTYPE=DRIVER

# Additional defines for the C/C++ preprocessor
C_DEFINES=$(C_DEFINES)

SOURCES=KernelApiCode.c\
        drvversion.rc


整理好的代码和文档的下载地址:http://download.csdn.net/detail/qq1084283172/8862791


參考资料:

AGP讲课资料整理和学习



posted @ 2016-04-08 15:55  mengfanrong  阅读(1771)  评论(0编辑  收藏  举报