详解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;
}
代码输出效果:
实现空间分配
字符串结构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;
}
代码输出效果:
实现字符串拷贝
此处可以直接使用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;
}
代码输出效果:
实现字符串比较
如果需要比较两个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;
}
代码输出效果:
有时在字符串比较时需要统一字符串格式,例如全部变大写以后在做比较等,此时可以使用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;
}
代码输出效果:
来源:https://www.cnblogs.com/LyShark/p/16740467.html


猜你喜欢
- 本文实例讲述了Android编程实现二级下拉菜单及快速搜索的方法。分享给大家供大家参考,具体如下:一、我们要做什么?上面有个搜索框,下面是一
- GC的前世与今生虽然本文是以.NET作为目标来讲述GC,但是GC的概念并非才诞生不久。早在1958年,由鼎鼎大名的图林奖得主John McC
- 效果如下:直接上代码,留着以后用,代码目录结构如下:其中BaseFragment.java是另外5个Fragment的基类,代码如下:pac
- 本文实例为大家分享了Android实现随手指移动小球的具体代码,供大家参考,具体内容如下这个随手指移动小球,首先要使用paint画笔在can
- 问题描述:输入一个链表的头结点,从尾巴到头反过来打印出每个结点的值。首先定义链表结点public class ListNode { &nbs
- 一、效果图本控件已上传Github,欢迎Star和Fork,项目地址:CircleWaterWaveView二、设计思路观察效果图,可以看出
- springboot和vue结合的方案网络上的主要有以下两种:1. 【不推荐】在html中直接使用script标签引入vue和一些常用的组件
- 本文实例展示了WinForm实现为ComboBox绑定数据源并提供下拉提示功能,这是一个非常有实用价值的功能,具体实现方法如下:主要功能代码
- 在res目录下建一个drawable文件夹,注意文件夹名字一定要是drawable,否则在xml模板中你是找不到shape的下图就通过一个x
- 算法思想快速排序是C.R.A.Hoare于1962年提出的一种划分交换排序。它采用了一种分治的策略,通常称其为分治法(Divide-and-
- 静态库和动态库的区别1、静态库的扩展名一般为".a"或者".lib";动态库的扩展名一般为"
- 本文为大家分享了C#多线程之线程控制,供大家参考,具体内容如下方案一:调用线程控制方法.启动:Thread.Start();停止:Threa
- 自动登录,是为了帮助用户多次使用这个网页时,不用再次输入用户名和密码就可以登录。自动登录是指用户将用户的登录信息,人,保存到本地的文件中Co
- SpringBoot打jar包遇到的xml文件丢失在pom.xml的build标签中添加如下内容指定资源路径<resources>
- 导入生成器需要的依赖坐标:<dependency> <groupId>com.baomidou</
- String对象是不可变的:意思就是无论是对String的新增或修改,出现一个全新的String内容时,都意味着诞生了一个新的对象。但是如果
- MyBatis-PlusMyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改
- 题目:求1+2!+3!+...+20!的和程序分析:此程序只是把累加变成了累乘。程序设计:public class Ex21 {  
- 数据库结构如下strategy中有外键member_id(关联member表)外键strategy_category(关联category表
- 本文实例讲述了Android编程防止进程被第三方软件杀死的方法。分享给大家供大家参考,具体如下:项目测试的时候发现,按home键回到桌面,再