详解C语言内核字符串拷贝与比较

作者:lyshark 时间:2023-11-02 15:22:30 

在上一篇文章《驱动开发:内核字符串转换方法》中简单介绍了内核是如何使用字符串以及字符串之间的转换方法,本章将继续探索字符串的拷贝与比较,与应用层不同内核字符串拷贝与比较也需要使用内核专用的API函数,字符串的拷贝往往伴随有内核内存分配,我们将首先简单介绍内核如何分配堆空间,然后再以此为契机简介字符串的拷贝与比较。

首先内核中的堆栈分配可以使用ExAllocatePool()这个内核函数实现,此外还可以使用ExAllocatePoolWithTag()函数,两者的区别是,第一个函数可以直接分配内存,第二个函数在分配时需要指定一个标签,此外内核属性常用的有两种NonPagedPool用于分配非分页内存,而PagePool则用于分配分页内存,在开发中推荐使用非分页内存,因为分页内存数量有限。

内存分配使用ExAllocatePool函数,内存拷贝可使用RtlCopyMemory函数,需要注意该函数其实是对Memcpy函数的包装。

#include <ntifs.h>

VOID UnDriver(PDRIVER_OBJECT driver)
{
DbgPrint("驱动已卸载 \n");
}

// PowerBy: LyShark
NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
UNICODE_STRING uncode_buffer = { 0 };

DbgPrint("hello lyshark \n");

wchar_t * wchar_string = L"hello lyshark";

// 设置最大长度
uncode_buffer.MaximumLength = 1024;

// 分配内存空间
uncode_buffer.Buffer = (PWSTR)ExAllocatePool(PagedPool, 1024);

// 设置字符长度 因为是宽字符,所以是字符长度的 2 倍
uncode_buffer.Length = wcslen(wchar_string) * 2;

// 保证缓冲区足够大,否则程序终止
ASSERT(uncode_buffer.MaximumLength >= uncode_buffer.Length);

// 将 wchar_string 中的字符串拷贝到 uncode_buffer.Buffer
RtlCopyMemory(uncode_buffer.Buffer, wchar_string, uncode_buffer.Length);

// 设置字符串长度 并输出
uncode_buffer.Length = wcslen(wchar_string) * 2;
DbgPrint("输出字符串: %wZ \n", uncode_buffer);

// 释放堆空间
ExFreePool(uncode_buffer.Buffer);
uncode_buffer.Buffer = NULL;
uncode_buffer.Length = uncode_buffer.MaximumLength = 0;

DbgPrint("驱动已加载 \n");
Driver->DriverUnload = UnDriver;
return STATUS_SUCCESS;
}

代码输出效果:

详解C语言内核字符串拷贝与比较

实现空间分配

字符串结构UNICODE_STRING可以定义数组,空间的分配也可以循环进行,例如我们分配十个字符串结构,并输出结构内的参数。

#include <ntifs.h>

VOID UnDriver(PDRIVER_OBJECT driver)
{
DbgPrint("驱动已卸载 \n");
}

// PowerBy: LyShark
NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
UNICODE_STRING uncode_buffer[10] = { 0 };
wchar_t * wchar_string = L"hello lyshark";

DbgPrint("hello lyshark \n");

int size = sizeof(uncode_buffer) / sizeof(uncode_buffer[0]);
DbgPrint("数组长度: %d \n", size);

for (int x = 0; x < size; x++)
{
// 分配空间
uncode_buffer[x].Buffer = (PWSTR)ExAllocatePool(PagedPool, 1024);

// 设置长度
uncode_buffer[x].MaximumLength = 1024;
uncode_buffer[x].Length = wcslen(wchar_string) * sizeof(WCHAR);
ASSERT(uncode_buffer[x].MaximumLength >= uncode_buffer[x].Length);

// 拷贝字符串并输出
RtlCopyMemory(uncode_buffer[x].Buffer, wchar_string, uncode_buffer[x].Length);
uncode_buffer[x].Length = wcslen(wchar_string) * sizeof(WCHAR);
DbgPrint("循环: %d 输出字符串: %wZ \n", x, uncode_buffer[x]);

// 释放内存
ExFreePool(uncode_buffer[x].Buffer);
uncode_buffer[x].Buffer = NULL;
uncode_buffer[x].Length = uncode_buffer[x].MaximumLength = 0;
}

DbgPrint("驱动加载成功 \n");
Driver->DriverUnload = UnDriver;
return STATUS_SUCCESS;
}

代码输出效果:

详解C语言内核字符串拷贝与比较

实现字符串拷贝

此处可以直接使用RtlCopyMemory函数直接对内存操作,也可以调用内核提供的RtlCopyUnicodeString函数来实现,具体代码如下。

#include <ntifs.h>

VOID UnDriver(PDRIVER_OBJECT driver)
{
DbgPrint("驱动已卸载 \n");
}

// PowerBy: LyShark
NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
DbgPrint("hello lyshark \n");

UNICODE_STRING uncode_buffer_source = { 0 };
UNICODE_STRING uncode_buffer_target = { 0 };

// 该函数可用于初始化字符串
RtlInitUnicodeString(&uncode_buffer_source, L"hello lyshark");

// 初始化target字符串,分配空间
uncode_buffer_target.Buffer = (PWSTR)ExAllocatePool(PagedPool, 1024);
uncode_buffer_target.MaximumLength = 1024;

// 将source中的内容拷贝到target中
RtlCopyUnicodeString(&uncode_buffer_target, &uncode_buffer_source);

// 输出结果
DbgPrint("source = %wZ \n", &uncode_buffer_source);
DbgPrint("target = %wZ \n", &uncode_buffer_target);

// 释放空间 source 无需销毁
// 如果强制释放掉source则会导致系统蓝屏,因为source是在栈上的
RtlFreeUnicodeString(&uncode_buffer_target);

DbgPrint("驱动加载成功 \n");

Driver->DriverUnload = UnDriver;
return STATUS_SUCCESS;
}

代码输出效果:

详解C语言内核字符串拷贝与比较

实现字符串比较

如果需要比较两个UNICODE_STRING字符串结构体是否相等,那么可以使用RtlEqualUnicodeString这个内核函数实现,该函数第三个参数是返回值类型,如果是TRUE则默认返回真,否则返回假,具体代码如下。

#include <ntifs.h>

VOID UnDriver(PDRIVER_OBJECT driver)
{
DbgPrint("驱动已卸载 \n");
}

// PowerBy: LyShark
NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
DbgPrint("hello lyshark \n");

UNICODE_STRING uncode_buffer_source = { 0 };
UNICODE_STRING uncode_buffer_target = { 0 };

// 该函数可用于初始化字符串
RtlInitUnicodeString(&uncode_buffer_source, L"hello lyshark");
RtlInitUnicodeString(&uncode_buffer_target, L"hello lyshark");

// 比较字符串是否相等
if (RtlEqualUnicodeString(&uncode_buffer_source, &uncode_buffer_target, TRUE))
{
DbgPrint("字符串相等 \n");
}
else
{
DbgPrint("字符串不相等 \n");
}

DbgPrint("驱动加载成功 \n");

Driver->DriverUnload = UnDriver;
return STATUS_SUCCESS;
}

代码输出效果:

详解C语言内核字符串拷贝与比较

有时在字符串比较时需要统一字符串格式,例如全部变大写以后在做比较等,此时可以使用RtlUpcaseUnicodeString函数将小写字符串为大写,然后在做比较,代码如下。

#include <ntifs.h>

VOID UnDriver(PDRIVER_OBJECT driver)
{
DbgPrint("驱动已卸载 \n");
}

// PowerBy: LyShark
NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
DbgPrint("hello lyshark \n");

UNICODE_STRING uncode_buffer_source = { 0 };
UNICODE_STRING uncode_buffer_target = { 0 };

// 该函数可用于初始化字符串
RtlInitUnicodeString(&uncode_buffer_source, L"hello lyshark");
RtlInitUnicodeString(&uncode_buffer_target, L"HELLO LYSHARK");

// 字符串小写变大写
RtlUpcaseUnicodeString(&uncode_buffer_target, &uncode_buffer_source, TRUE);
DbgPrint("小写输出: %wZ \n", &uncode_buffer_source);
DbgPrint("变大写输出: %wZ \n", &uncode_buffer_target);

// 销毁字符串
RtlFreeUnicodeString(&uncode_buffer_target);

DbgPrint("驱动加载成功 \n");

Driver->DriverUnload = UnDriver;
return STATUS_SUCCESS;
}

代码输出效果:

详解C语言内核字符串拷贝与比较

来源:https://www.cnblogs.com/LyShark/p/16740467.html

标签:C语言,内核,字符串,拷贝,比较
0
投稿

猜你喜欢

  • Android使用Gridview单行横向滚动显示

    2021-07-28 17:40:43
  • 史上最全的java随机数生成算法分享

    2023-10-17 15:22:33
  • C#中public变量不能被unity面板识别的解决方案

    2022-03-26 18:17:18
  • android 通过向viewpage中添加listview来完成滑动效果(类似于qq滑动界面)

    2023-07-27 19:59:38
  • Springboot通过谷歌Kaptcha 组件生成图形验证码功能

    2021-07-24 23:42:47
  • java swing实现QQ账号密码输入框

    2023-01-13 06:26:52
  • JVM类运行机制实现原理解析

    2023-11-01 18:26:20
  • c#实现一个超实用的证件照换底色小工具(附源码)

    2023-05-20 08:32:17
  • Android RecyclerView实现下拉刷新和上拉加载更多

    2022-03-16 09:02:40
  • 事务在c#中的使用

    2021-11-27 23:30:29
  • Java看完秒懂版熔断和降级的关系

    2023-11-06 01:12:13
  • java实现学生成绩档案管理系统

    2023-06-29 22:48:43
  • C#泛型与非泛型性能比较的实例

    2022-01-31 17:26:51
  • Java split函数拆分后变成null问题解决方案

    2022-05-24 17:00:36
  • Java continue break制作简单聊天室程序

    2022-12-20 01:23:01
  • Java SpringCache+Redis缓存数据详解

    2023-11-29 01:01:05
  • Android 中 退出多个activity的经典方法

    2023-02-09 04:38:59
  • 详解Java线程-守护线程与用户线程

    2023-11-25 00:17:29
  • 完美解决Android App启动页有白屏闪过的问题

    2021-11-18 02:12:31
  • 详解Java中的ReentrantLock锁

    2023-07-18 10:00:45
  • asp之家 软件编程 m.aspxhome.com