内核里的其他常用

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. CISCN-2018-Quals-note-service2

    CISCN-2018-Quals-note-service2 总结 做完这道题,收获如下: 1)汇编语句jmp short s,最后编译出来的机器码为\xEB\x??,问号代表pc寄存器会往前或往后跳 ...

  2. 04-Spring自定义标签解析

    自定义标签的解析 这一篇主要说明自定义标签的解析流程,除了 bean.alias.import.beans之外的标签,都属于自定义标签的范围,自定义标签的解析需要命名空间配合, 获取对应的命名空间 根 ...

  3. 【codeforces - 1307G】Cow and Exercise

    目录 description solution accepted code details description 给定 n 点 m 边简单有向图,有边权. q 次询问,每次给出 xi.可以增加某些边 ...

  4. Typora的一些快捷键

      语法格式 快捷键 标题 # + 空格 = 一级标题, ## + 空格 =二级标题, 以此类推 shift + 数字1 =一级标题 ,shift + 数字2 =二级标题 , 以此类推 有序列表 1 ...

  5. 周期串(JAVA语言)

    package 第三章习题; /*  * 如果一个字符可以由某个长度为k的字符串重复多次得到,则称该串以k为周期.  * 例如:abcabcabcabc 以3为周期(注意:它也以6和12为周期)  * ...

  6. 如何提高Web应用系统的性能?

    随着互联网信息技术的发展,人们逐渐开始习惯在网络上交友.购物.学习.娱乐.工作,甚至是找工作.因此市场对网站的响应速度也提出了新的要求,提高Web应用系统的性能成为急需解决的关键问题.本文将会给出一些 ...

  7. 剑指 Offer 03. 数组中重复的数字

    剑指 Offer 03. 数组中重复的数字 找出数组中重复的数字. 在一个长度为 n 的数组 nums 里的所有数字都在 0-n-1 的范围内.数组中某些数字是重复的,但不知道有几个数字重复了,也不知 ...

  8. java例题_06 最大公约数&最小公倍数

    1 /*6 [程序 6 求最大公约数及最小公倍数] 2 题目:输入两个正整数 m 和 n,求其最大公约数和最小公倍数. 3 程序分析:利用辗除法. 4 */ 5 6 /*分析 7 * ======== ...

  9. BST(二叉搜索树)的基本操作

    BST(二叉搜索树) 首先,我们定义树的数据结构如下: public class TreeNode { int val; TreeNode left; TreeNode right; public T ...

  10. 「HTML+CSS」--自定义加载动画【010】

    前言 Hello!小伙伴! 首先非常感谢您阅读海轰的文章,倘若文中有错误的地方,欢迎您指出- 哈哈 自我介绍一下 昵称:海轰 标签:程序猿一只|C++选手|学生 简介:因C语言结识编程,随后转入计算机 ...