内核里的其他常用

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. linux内核编程_内核线程kthread_run

    linux内核编程_内核线程kthread_run 1. 简述: 2. 使用示例: 3. 详述: 1. 简述: 头文件: include/linux/kthread.h 数据类型: struct ta ...

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

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

  3. 国嵌linux内核编程,linux内核--那些年看国嵌视频学习

    1.linux系统构成 由用户空间和内核空间构成.其中用户空间由应用程序和C库:内核空间由系统调用接口.kernel.架构代码.硬件设备平台 为什么linux系统会被划分为用户空间和内核空间?处于安全 ...

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

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

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

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

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

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

  7. Windows内核编程(三)-内核驱动运行与调试

    内核驱动运行与调试 驱动的运行 驱动的运行通过服务来实现. 微软规定,驱动文件必须经过微软的数字签名后,才可以运行在64位系统上,如果把没有经过签名的驱动直接放在64位操作系统中运行,结果是驱动加载失 ...

  8. linux内核编程,实现内核之间的调用

    Linux 内核模块编写三个模块文件mainmod.c,lenmod.c,summod.c,在mainmod模块调用summod模块对数组进行求和运算,调用lenmod模块求数组中元素 1 先看自己的 ...

  9. Windows驱动开发学习笔记(二)—— 驱动调试内核编程基础

    Windows驱动开发学习笔记(二)-- 驱动调试&内核编程基础 基础知识 驱动调试 PDB(Program Debug Database) WinDbg 加载 PDB 实验:调试 .sys ...

最新文章

  1. 【蓝桥java】递归基础之输出连续数字
  2. linux解压tar到目录,在Linux系统中将tar文件解压到不同的目录中的教程
  3. 牛客网【每日一题】4月24日 子序列
  4. Andriod Studio两种签名机制V1和V2的区别
  5. MongoDB数据库操作---mongoose操作
  6. Android 系统(191)---ODM 开发用户常见需求文档(九)
  7. Ubuntu安装Chrome的方法
  8. 基准对象object中的基础类型----元组 (五)
  9. lua collectgarbage
  10. Python可视化:python画图颜色设置
  11. 计算机网络实验一VLAN间路由
  12. 移动硬盘提示数据错误循环冗余检查要怎么办啊
  13. 滴滴裁员2000人启示:牛逼的人,都有铁饭碗
  14. 【已解决】Python安装TensorFlow报错“Consider adding this directory to PATH or, if you prefer to suppress this
  15. 苹果4s怎么越狱教程_苹果手机越狱状态简单APP多开教程
  16. mac 下安装 tomcat7
  17. 使用STM32F4标准外设库实现网线热插拔- 分析STM3240G-EVAL官方工程
  18. 十进制小数转化为二进制小数
  19. 银行家算法——C++实现 [ 开源代码 + 详细解析 ]
  20. 机器人砂型铸造_启东精密砂型铸造

热门文章

  1. DHCP服务器功能浅析
  2. 菜鸟玩基金(四)——注意事项
  3. Qt QDialog将窗体变为顶层窗体(activateWindow(); 和 raise() )
  4. 【异常-举例6:finally】
  5. Atitit.js模块化 atiImport 的新特性javascript import
  6. 产品经理提升修炼的方法
  7. 赴美工作常识(Part 4 - 面试)
  8. 实现状态面板的显示与隐藏
  9. Oracle数据库----函数
  10. Python 非空即真、列表生成式、三元表达式 day3