为了确保用户应用程序能够顺利调用Windows内核功能,我们需要采取一种类似于Linux shell的方式来执行相应的指令。最初,我计划利用Microsoft提供的内核AVL树,并结合C++类来优化搜索操作的时间复杂度至O(log n)。然而,无论我如何尝试编写代码或查阅相关资料,最终都遭遇了系统蓝屏的困境,这让我无计可施。
在对比链表(时间复杂度为O(n))和哈希表(unordered_map,时间复杂度为O(1))的性能时,我发现当数据量低于10000条时,链表的速度最多仅比哈希表慢2到3倍。鉴于此,我决定改用链表来实现这一功能。尽管链表相对简单,但它无法接受C++类作为参数传递,这又一次导致了系统的蓝屏问题。
面对这一挑战,我不得不采取更为直接的方法,即使用if语句来判断和处理数据。虽然这种方法在速度上绝对优于链表,但它也不可避免地导致了代码结构的复杂化,形成了所谓的“史山代码”。在这里,我必须承认自己的能力有限,并请求您的理解和宽恕。
command.h
#pragma once
#include <ntifs.h>
#include "Logging.h"
#include "data.h"
#include "file.h"
extern UNICODE_STRING *commands;
extern ULONG commandCount;
NTSTATUS InitializeCommands();
VOID UninitializeCommands();
//可以根据自己的需求添加指令
//必须遵循NTSTATUS command_命令名字(UNICODE_STRING* args, ULONG length);
//否则您就要重构代码了
NTSTATUS command_help(UNICODE_STRING* args, ULONG length);
NTSTATUS command_echo(UNICODE_STRING* args, ULONG length);
NTSTATUS execute(UNICODE_STRING command, UNICODE_STRING* args, ULONG length);
command.cpp
#include "command.h"
UNICODE_STRING *commands;
ULONG commandCount;
NTSTATUS InitializeCommands()
{
NTSTATUS status = STATUS_SUCCESS;
commandCount = 2;
commands = (UNICODE_STRING*)ExAllocatePool2(POOL_FLAG_NON_PAGED, sizeof(UNICODE_STRING) * commandCount, 'CMD');
if (commands == NULL) {
WriteLog("[LyKernelService] Failed to allocate memory for commands, status = 0x%x\n", status);
return STATUS_NO_MEMORY;
}
RtlInitUnicodeString(&commands[0], L"help");
RtlInitUnicodeString(&commands[1], L"echo");
}
VOID UninitializeCommands()
{
ExFreePoolWithTag(commands, 'CMD');
}
NTSTATUS command_help(UNICODE_STRING* args, ULONG length)
{
NTSTATUS status = STATUS_SUCCESS;
status = CleanResult();
if (!NT_SUCCESS(status)) {
WriteLog("[LyKernelService] Failed to clean result, status = 0x%x\n", status);
return status;
}
for (ULONG i = 0; i < commandCount; i++) {
WriteLog("[LyKernelService] %wZ\n", &commands[i]);
WriteResult("%wZ\n", &commands[i]);
}
setResponseData("file(result)\n");
return status;
}
NTSTATUS command_echo(UNICODE_STRING* args, ULONG length)
{
for (ULONG i = 0; i < length; i++) {
WriteLog("[LyKernelService] %wZ\n", &args[i]);
}
setResponseData("ok!\n");
return STATUS_SUCCESS;
}
NTSTATUS execute(UNICODE_STRING command, UNICODE_STRING* args, ULONG length)
{
if (RtlEqualUnicodeString(&command, &commands[0], TRUE)) {
command_help(args, length);
} else if (RtlEqualUnicodeString(&command, &commands[1], TRUE)) {
command_echo(args, length);
}
else {
WriteLog("[LyKernelService] Invalid command.");
return STATUS_INVALID_PARAMETER;
}
}
一定要注意,关于setResponseData和WriteResult的区别,前者速度快但是只能写入1024字节的数据(超级小),而后者适合大量数据写入(不用担心会覆盖,这个方法属于追加数据)