• 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
    ", NeededSize);
    
    			//使用5号功能来获取系统的进程和线程的信息
    			status = ZwQuerySystemInformation(
    				SystemProcessesAndThreadsInformation, //SystemProcessesAndThreadsInformation = 5 
    				pBuffer,
    				NeededSize, 
    				NULL);
    			//假设调用成功
    			if (NT_SUCCESS(status)) 
    			{
    				DbgPrint("ZwQuerySystemInformation() success
    ");
    
    				//指针类型转换
    				pInfo = (PSYSTEM_PROCESSES)pBuffer;
    
    				while (TRUE)
    				{
    					//PID=0,系统的
    					if (pInfo->ProcessId == 0)
    					{
    						DbgPrint("PID %5d System Idle Process
    ", pInfo->ProcessId);
    					}
    					else
    					{	//打印进程的PID和进程的名称
    						DbgPrint("PID %5d %ws
    ", 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
    ", 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
    ", pModuleList->smi[i].Base, pModuleList->smi[i].Size, pModuleList->smi[i].ImageName);
    				}
    			}
    		}
    
    	}
    	__except(EXCEPTION_EXECUTE_HANDLER)
    	{
    		//打印异常的代码
    		DbgPrint("%08x
    ", 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--注冊表创建成功!
    ");
    
    				break;
    			}
    		case REG_EXPAND_SZ:
    			{
    				ZwSetValueKey(
    					hRegister,
    					&Unicode_ValueName, //键值的名称
    					0,
    					Reg_Type,           //键值的类型
    					Value,              //键值的值
    					wcslen(Value)*2
    					);
    				DbgPrint("REG_EXPAND_SZ--注冊表创建成功!
    ");
    
    				break;
    			}
    		case REG_DWORD:
    			{
    				ulValue_DWORD = sizeof(REG_DWORD);
    				ZwSetValueKey(
    					hRegister,
    					&Unicode_ValueName,   //键值的名称
    					0,
    					Reg_Type,             //键值的类型
    					&Value,
    					sizeof(ulValue_DWORD) //键值的值
    					);
    				DbgPrint("REG_DWORD--注冊表创建成功!
    ");
    
    				break;
    			}
    		}
    
    		//关闭句柄
    		ZwClose(hRegister);
    	}
    
    	return bRetOK;
    }
    
    //******************************************************************************************************************************
    
    //驱动卸载例程函数
    VOID DriverUnload(IN PDRIVER_OBJECT DriverObject)
    {
    	DbgPrint("卸载完毕!
    ");
    }
    
    //驱动入口函数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讲课资料整理和学习



  • 相关阅读:
    和大家一起了解Windows Server 2016 License许可证授权方式
    centos的cockpit安装使用
    Nscan-20150223
    JexBoss-20170328
    InsightScan-20150320
    Clusterd-20151119
    BBScan-20200419
    Astra-20190405
    为什么计算机计算时间要从1970年开始
    Appium环境搭建
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/5368484.html
Copyright © 2020-2023  润新知