windows内核api就是ntoskrnl.exe导出的函数。我们能够跟调用应用层的api一样,调用内核api。
只是内核api须要注意的是。假设函数导出了。而且函数文档化(也就是能够直接在msdn上搜索到)。ExFreePool函数导出。而且文档化,那么我们能够直接调用。导出了未文档化,那么我们就要声明。什么叫文档化和未文档化呢?大家来看一个函数:
UCHAR *PsGetProcessImageFileName(IN PEPROCESS Process);
文档化:就是如果函数导出了,而且在msdn上能够搜索到。
就是文档化我们调用文档化的函数就是直接调用。
未文档化:就是如果函数已经导出了。可是在msdn上没有搜到。就是未文档化函数我们要调用它,就得自己手动声明。
内核编程就跟应用层一样,都是api的调用。都是Hook,都是反Hook,一样的编程思维。它们本质的差别仅仅是在于一个先后顺序。比方看图-什么叫本质的差别:顺序掉
从ring3到SSDT层主体实现函数的调用顺序:
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讲课资料整理和学习