首页 > 系统相关 >windows内核Api的学习

windows内核Api的学习

时间:2022-10-11 21:32:46浏览次数:60  
标签:DbgPrint ULONG windows Api 键值 内核 注册表 pBuffer NULL

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\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







标签:DbgPrint,ULONG,windows,Api,键值,内核,注册表,pBuffer,NULL
From: https://blog.51cto.com/csnd/5748083

相关文章