windows内核Api的学习
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
整理好的代码和文档的下载地址:http://download.csdn.net/detail/qq1084283172/8862791
參考资料:
AGP讲课资料整理和学习
windows内核Api的学习的更多相关文章
- windows内核对象管理学习笔记
目前正在阅读毛老师的<windows内核情景分析>一书对象管理章节,作此笔记. Win内核中是使用对象概念来描述管理内核中使用到的数据结构.此对象(Object)均是由对象头(Object ...
- ERROR: Symbol file could not be found 寒江孤钓<<windows 内核安全编程>> 学习笔记
手动下载了Symbols,设置好了Symbols File Path,串口连接上了以后,出现ERROR: Symbol file could not be found, 并且会一直不停的出现windb ...
- 发生系统错误 1275.此驱动程序被阻止加载 寒江孤钓<<windows 内核安全编程>> 学习笔记
安装书中第一章成功安装first服务之后,在cmd窗口使用命令行 "net start first" 时, 出现 "发生系统错误 1275.此驱动程序被阻止加载" ...
- 无法编译出.sys文件 寒江孤钓<<windows 内核安全编程>> 学习笔记
系统环境:win7 编译环境:Windows Win7 IA-64 Checked Build Environment 按照书中所说的步骤,出现如下问题 后来直接使用光盘源码,编译成功,于是对照源文件 ...
- Debuggee not connected 寒江孤钓<<windows 内核安全编程>> 学习笔记
双机联调出现的问题 真机系统win7 虚拟机系统xp 安装书中的配置一步一步走,发现最后启动系统后,windbg一直显示 Opened \\.\pipe\com_1Waiting to reconne ...
- 指定的服务已标记为删除 寒江孤钓<<windows 内核安全编程>> 学习笔记
运行cmd:"sc delete first" 删除我们的服务之后, 再次创建这个服务的时候出现 "指定的服务已标记为删除"的错误, 原因是我们删除服务之前没有 ...
- 删除自定义服务 寒江孤钓<<windows 内核安全编程>> 学习笔记
书中第一章 成功启动first服务之后, 发现书中并没有介绍删除服务的方式, SRVINSTW工具中的移除服务功能,也无法找到我们要删除的服务, 于是,搜素了下,发现解决方法如下: 在cmd中输入 & ...
- 学习windows内核书籍推荐 ----------转自http://tieshow.iteye.com/blog/1565926
虽然,多年java,正在java,看样子还得继续java.(IT小城,还是整java随意点)应用程序 运行于操作系统之上, 晓操作系统,方更晓应用程序. 主看windows,因为可玩性高,闭源才 ...
- Windows录音API学习笔记(转)
源:Windows录音API学习笔记 Windows录音API学习笔记 结构体和函数信息 结构体 WAVEINCAPS 该结构描述了一个波形音频输入设备的能力. typedef struct { W ...
随机推荐
- for、for..in、forEach、$.each等循环性能测试
var num = 10000000,arr = []; for(i=0;i<num;i++){ arr[i] = i+2; } //1) 使用 for 循环 function test1() ...
- Redis在windows下安装过程(转载)
转载自(http://www.cnblogs.com/M-LittleBird/p/5902850.html) 一.下载windows版本的Redis 官网以及没有下载地址,只能在github上下载, ...
- Android 后台线程,timertask实现定期更新时间
简述:这是一类定时功能的原型,用来在后台线程中运行一些定时的服务,比如定时修改时间 知识点: 1. Android多线程的消息通信(handler) 2. Java中时间的获取,以及String的格式 ...
- exim CVE-2017-16943 uaf漏洞分析
前言 本文由 本人 首发于 先知安全技术社区: https://xianzhi.aliyun.com/forum/user/5274 这是最近爆出来的 exim 的一个 uaf 漏洞,可以进行远程代码 ...
- redis介绍(2)简单安装
我分两种方式讲解 window 下载地址:https://github.com/MSOpenTech/redis/releases. Redis 支持 32 位和 64 位.这个需要根据你系统平台的实 ...
- requirejs中Shims使用说明
RequireJS中如果使用AMD规范,在使用的过程中没有太多的问题,如果加载非AMD规范的JS文件,就需要使用Require中的shim. require.config({ paths:{ jque ...
- 7 Recursive AutoEncoder结构递归自编码器(tensorflow)不能调用GPU进行计算的问题(非机器配置,而是网络结构的问题)
一.源代码下载 代码最初来源于Github:https://github.com/vijayvee/Recursive-neural-networks-TensorFlow,代码介绍如下:“This ...
- 【AOP】spring 的AOP编程报错:[Xlint:invalidAbsoluteTypeName]error
AOP来发过程中,报错如下: warning no match for this type name: net.shopxx.wx.institution.controller [Xlint:inva ...
- ORACLE数据泵还原(IMPDP命令)
Oracle数据库还原IMPDP命令是相对于EXPDP命令的,方向是反向的.即对于数据库备份进行还原操作.一.知晓IMPDP命令 C:\>impdp -help Import: Release ...
- 从一个简单的 JPA 示例开始
本文主要讲述 Spring Data JPA,但是为了不至于给 JPA 和 Spring 的初学者造成较大的学习曲线,我们首先从 JPA 开始,简单介绍一个 JPA 示例:接着重构该示例,并引入 Sp ...