内核里的其他常用

1.遍历链表。内核里有很多数据结构,但它们并不是孤立的,内核使用双向链表把它们像糖

葫芦一样给串了起来。所以遍历双向链表能获得很多重要的内核数据。举个简单的例子,驱

动对象 DriverObject 就是使用双向链表给串起来的,遍历这个链表就可以枚举内核里所有的驱动。示例代码如下

//传入驱动自身的 DriverObject
VOID EnumDriver(PDRIVER_OBJECT pDriverObject)
{
PKLDR_DATA_TABLE_ENTRY entry = (PKLDR_DATA_TABLE_ENTRY)pDriverObject->DriverSection;
PKLDR_DATA_TABLE_ENTRY firstentry;
ULONG64 pDrvBase = 0;
KIRQL OldIrql;
firstentry = entry;
//当发现又找到自己时跳出循环,否则成了死循环。
while ((PKLDR_DATA_TABLE_ENTRY)entry->InLoadOrderLinks.Flink != firstentry)
{
DbgPrint("BASE=%p\tPATH=%wZ", entry->DllBase, entry->FullDllName);
entry = (PKLDR_DATA_TABLE_ENTRY)entry->InLoadOrderLinks.Flink;
}
}

2.等待。这个等于 RING3 的 Sleep 函数了。

#define DELAY_ONE_MICROSECOND (-10)
#define DELAY_ONE_MILLISECOND (DELAY_ONE_MICROSECOND*1000)
VOID MySleep(LONG msec)
{
LARGE_INTEGER my_interval;
my_interval.QuadPart = DELAY_ONE_MILLISECOND;
my_interval.QuadPart *= msec;
KeDelayExecutionThread(KernelMode, 0, &my_interval);
}

3.同步。这个可以理解成是“条件等待”。常用的是 KeWaitForSingleObject、KeInitializeEvent、

KeSetEvent 这几个函数。为了方便讲解,这个的示例代码与“内核线程”放在一起。先把这

几个函数的原型贴出来。

NTSTATUS KeWaitForSingleObject
(
_In_ PVOID Object,
_In_ KWAIT_REASON WaitReason,
_In_ KPROCESSOR_MODE WaitMode,
_In_ BOOLEAN Alertable,
_In_opt_ PLARGE_INTEGER Timeout
);
VOID KeInitializeEvent
(
_Out_ PRKEVENT Event,
_In_ EVENT_TYPE Type,
_In_ BOOLEAN State
);
LONG KeSetEvent
(
_Inout_ PRKEVENT Event,
_In_ KPRIORITY Increment,
_In_ BOOLEAN Wait
);

4.获得系统版本号。内核编程难免使用硬编码,以及使用一些高版本系统才出现的函数。为

了使得驱动能在低版本的系统上正常运行,就需要根据不同系统做不同处理了。

VOID GetVersion()
{
ULONG NtBuildNumber;
RTL_OSVERSIONINFOW osi;
osi.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOW);
RtlFillMemory(&osi, sizeof(RTL_OSVERSIONINFOW), 0);
RtlGetVersion(&osi);
NtBuildNumber = osi.dwBuildNumber;
DbgPrint("NtBuildNumber: %ld\n", NtBuildNumber);
return NtBuildNumber;
}

5.获得系统时间。在内核里获得系统时间的是标准时间(GMT+0),转换成本地时间还需要进

行转换。此功能在发布测试版软件的时候特别有用,限制人们只能在指定时间之前使用。

VOID MyGetCurrentTime()
{
LARGE_INTEGER CurrentTime;
LARGE_INTEGER LocalTime;
TIME_FIELDS TimeFiled;
// 这里得到的其实是格林威治时间
KeQuerySystemTime(&CurrentTime);
// 转换成本地时间
ExSystemTimeToLocalTime(&CurrentTime, &LocalTime);
// 把时间转换为容易理解的形式
RtlTimeToTimeFields(&LocalTime, &TimeFiled);
DbgPrint("[TimeTest] NowTime : %4d-%2d-%2d %2d:%2d:%2d",
TimeFiled.Year, TimeFiled.Month, TimeFiled.Day,
TimeFiled.Hour, TimeFiled.Minute, TimeFiled.Second);
}

6.内核线程。内核线程就是名义上属于 SYSTEM 进程的线程。比如说你要做坏事,却让 SYSTEM

进程背黑锅,是一件很爽的事情。内核线程还有几个特点:1. PreviousMode 是 KernelMode,

可以直接调用 Nt 开头的内核函数(Nt 开头的内核函数会检查 PreviousMode,如果

PreviousMode 不是 KernelMode,就会拒绝服务。有些人喜欢直接修改 ETHREAD 里的这个值,

但我个人觉得这么改不妥当)。2.内核线程不会自己结束,必须调用 PsTerminateSystemThread

才能被动结束。以下是例子, 同时演示了 等待 、同步和内核线程的使用。

KEVENT kEvent; //事件
//线程函数
VOID MyThreadFunc(IN PVOID context)
{
PUNICODE_STRING str = (PUNICODE_STRING)context;
DbgPrint("Kernel thread running: %wZ\n", str);
DbgPrint("Wait 3s!\n");
MySleep(3000);
DbgPrint("Kernel thread exit!\n");
KeSetEvent(&kEvent, 0, TRUE);
PsTerminateSystemThread(STATUS_SUCCESS);
}
//创建线程的函数
VOID CreateThreadTest()
{
HANDLE hThread;
UNICODE_STRING ustrTest = RTL_CONSTANT_STRING(L"This is a string for test!");
NTSTATUS status;
// 初始化事件
KeInitializeEvent(&kEvent, SynchronizationEvent, FALSE);
status = PsCreateSystemThread(&hThread, 0, NULL, NULL, NULL, MyThreadFunc,
(PVOID)&ustrTest);
if (!NT_SUCCESS(status))
{
DbgPrint("PsCreateSystemThread failed!");
return;
}
ZwClose(hThread);
// 等待事件
KeWaitForSingleObject(&kEvent, Executive, KernelMode, FALSE, NULL);
DbgPrint("CreateThreadTest OVER!\n");
}

7.强制重启计算机。在内核里直接使用 OUT 指令就能强制重启计算机而不可能被任何钩子

拦截。此代码可以用在反调试里。

VOID ForceReboot()
{
typedef void(__fastcall *FCRB)(void);
/*
mov al, 0FEh
out 64h, al
ret
*/
FCRB fcrb = NULL;
UCHAR shellcode[6] = "\xB0\xFE\xE6\x64\xC3";
fcrb = ExAllocatePool(NonPagedPool, 5);
memcpy(fcrb, shellcode, 5);
fcrb();
}

8.强制关闭计算机。在内核里直接使用 OUT 指令就能强制关闭计算机而不可能被任何钩子

拦截。此代码可以用在反调试里。

VOID ForceShutdown()
{
typedef void(__fastcall *FCRB)(void);
/*
mov ax,2001h
mov dx,1004h
out dx,ax
ret
*/
FCRB fcrb = NULL;
UCHAR shellcode[12] = "\x66\xB8\x01\x20\x66\xBA\x04\x10\x66\xEF\xC3";
fcrb = ExAllocatePool(NonPagedPool, 11);
memcpy(fcrb, shellcode, 11);
fcrb();
}

Win64 驱动内核编程-8.内核里的其他常用的更多相关文章

  1. Win64 驱动内核编程-3.内核里使用内存

    内核里使用内存 内存使用,无非就是申请.复制.设置.释放.在 C 语言里,它们对应的函数是:malloc.memcpy.memset.free:在内核编程里,他们分别对应 ExAllocatePool ...

  2. Win64 驱动内核编程-7.内核里操作进程

    在内核里操作进程 在内核里操作进程,相信是很多对 WINDOWS 内核编程感兴趣的朋友第一个学习的知识点.但在这里,我要让大家失望了,在内核里操作进程没什么特别的,就标准方法而言,还是调用那几个和进程 ...

  3. Win64 驱动内核编程-5.内核里操作文件

    内核里操作文件 RING0 操作文件和 RING3 操作文件在流程上没什么大的区别,也是"获得文件句柄->读/写/删/改->关闭文件句柄"的模式.当然了,只能用内核 A ...

  4. Win64 驱动内核编程-6.内核里操作注册表

    内核里操作注册表 RING0 操作注册表和 RING3 的区别也不大,同样是"获得句柄->执行操作->关闭句柄"的模式,同样也只能使用内核 API 不能使用 WIN32 ...

  5. Win64 驱动内核编程-4.内核里操作字符串

    内核里操作字符串 字符串本质上就是一段内存,之所以和内存使用分开讲,是因为内核里的字符串太有花 样了,细数下来竟然有 4 种字符串!这四种字符串,分别是:CHAR*.WCHAR*.ANSI_STRIN ...

  6. WIN64内核编程-的基础知识

    WIN64内核编程基础班(作者:胡文亮)   https://www.dbgpro.com/x64driver 我们先从一份"简历"说起: 姓名:X86或80x86 性别:? 出生 ...

  7. Win64 驱动内核编程-2.基本框架(安装.通讯.HelloWorld)

    驱动安装,通讯,Hello World 开发驱动的简单流程是这样,开发驱动安装程序,开发驱动程序,然后安装程序(或者其他程序)通过通讯给驱动传命令,驱动接到之后进行解析并且执行,然后把执行结果返回. ...

  8. Win64 驱动内核编程-18.SSDT

    SSDT 学习资料:http://blog.csdn.net/zfdyq0/article/details/26515019 学习资料:WIN64内核编程基础 胡文亮 SSDT(系统服务描述表),刚开 ...

  9. Win64 驱动内核编程-22.SHADOW SSDT HOOK(宋孖健)

    SHADOW SSDT HOOK HOOK 和 UNHOOK SHADOW SSDT 跟之前的 HOOK/UNHOOK SSDT 类似,区别是查找SSSDT的特征码,以及根据索引计算函数地址的公式,还 ...

随机推荐

  1. 元数据管理—动态表单设计器在crudapi系统中完整实现

    表单设计 在前面文章中,我们通过一系列案例介绍了表单设计的一些基本功能,表单设计起到非常重要作用,也是crudapi核心,所以本文会详细介绍表单设计中一些其它功能. 概要 表单字段column属性 列 ...

  2. mysql-canal-rabbitmq 安装部署教程

    原文 1.1. 开启 MySQL 的 binlog 日志 修改 my.cnf 或 my.ini(windows), 添加配置项: # binlog 日志存放路径 log-bin=D:\env\mysq ...

  3. Java线程安全问题

    线程安全问题是一个老生常谈的问题,那么多线程环境下究竟有那些问题呢?这么说吧,问题的形式多种多样的,归根结底的说是共享资源问题,无非可见性与有序性问题. 1. 可见性 可见性是对于内存中的共享资源来说 ...

  4. java 动态规划解决最大连续子数列和

    很多动态规划算法非常像数学中的递推.我们如果能找到一个合适的递推公式,就能很容易的解决问题.我们用dp[n]表示以第n个数结尾的最大连续子序列的和,这里第n个数必须在子序列中.于是存在以下递推公式: ...

  5. linux中的gtk 编程的页面切换

    在我们使用gtk这个工具时,有时想在同一个窗口中,根据选择来显示不同的操作菜单,这篇博文主要是解决此类问题 //创建窗口 GtkWidget *CreateMenuMain() { GtkWidget ...

  6. Visual Studio添加引用的方式

  7. MySQL在线DDL工具 gh-ost

    一.简介 gh-ost基于 golang 语言,是 github 开源的一个 DDL 工具,是 GitHub's Online Schema Transmogrifier/Transfigurator ...

  8. frida hook_RegisterNatives--使用frida打印so中动态注册的函数

    原文地址:https://github.com/lasting-yang/frida_hook_libartfrida -U --no-pause -f package_name -l hook_Re ...

  9. 11、Spring教程之声明式事务

    1.回顾事务 事务在项目开发过程非常重要,涉及到数据的一致性的问题,不容马虎! 事务管理是企业级应用程序开发中必备技术,用来确保数据的完整性和一致性. 事务就是把一系列的动作当成一个独立的工作单元,这 ...

  10. 【Azure 应用程序见解】 Application Insights 对App Service的支持问题

    问题描述 Web App 发布后, Application Insights 收集不到数据了 问题分析 在应用服务(App Service)中收集应用的监控数据(如Request,Exception, ...