64位内核开发第十四讲,MiniFilter文件过滤框架以及安装方式
MiniFilter文件过滤第一讲 文件过滤框架以及安装方式
一丶MiniFilter 文件过滤框架
1.1 简介
MiniFilter是微软为我们开发的一个新的驱动,称为过滤管理器.(Filter Manager或者 fltmgr).这个驱动主要作用就是如果有文件操作可以通知我们.
MiniFilter的优点和不足如下:
优点:
1.增加开发速度
2.不用关心IRP处理工作,这些交给 Filter Manager处理即可.
不足:
MiniFilter开发的时候虽然简单了但是隐藏了很多细节.比如设备对象等等.如果使用以前的方式进行开发 那么就如同 C语言内嵌汇编 对兼容性不好 也失去了MiniFilter的意义.
1.2 MiniFilter框架
框架如下:
在IO管理器中我们的 MiniFilter会去进行注册. 如上图所示. 有 A B C三个.
而MiniFilter中最重要的是 高度值(Altitude) 不光有高度值还有分组.
比如A的分组就在 FSFilter Activity Monitor
B在 FSFilter Anti-Virus
也就是反病毒层级. 高度越高越会被先执行.假设你拦截了文件访问你可以不发送给下一层. 这样 B C 就接受不到了. 所以这个高度值需要我们找微软申请.(但是不申请好像也能用.只要不影响即可)
高度值 是从 20000 ~ 429999
的.而高度值又有分组. 所以高度值不能乱写.一般就是每个分组有个高度值范围.
查询地址如下: 微筛选器驱动程序的加载顺序组和高度 - Windows drivers | Microsoft Docs
二丶MiniFilter 编程框架
2.1 简介
对应到程序来说 MiniFilter是很简单的. 只需要三个内核API就可以使用MiniFilter了.
而API中所需要的参数就是结构体. 所以我们搞清楚结构体中的参数就可以了. 其实就是往结构体里面填写东西即可.
内核API如下:
NTSTATUS
FltRegisterFilter(
IN PDRIVER_OBJECT Driver,
IN CONST FLT_REGISTRATION *Registration,
OUT PFLT_FILTER *RetFilter
);
NTSTATUS
FltStartFiltering(
IN PFLT_FILTER Filter);
VOID
FltUnregisterFilter(
IN PFLT_FILTER Filter
);
API就三个. 分为 注册 启动 卸载
其中启动和卸载都是一个参数.就是Filter句柄.此句柄是从FltRegisterFilter
第三个参数传出的. 所以主要学习的就是第一个.
此函数有三个参数
-
参数1 Driver 在DDK驱动中的 DriverEntry中的驱动对象.
-
参数2 一个结构体 此结构体就是我们要了解的结构体.下面说.
-
参数3 传出的句柄. 文件管理器的句柄. 注册成功后会传出句柄 给 启动 和卸载函数使用.
2.2 FLT_REGISTRATION 结构体
在我们的注册函数中有次结构体. 此结构体如下:
typedef struct _FLT_REGISTRATION {
USHORT Size; @1 指向自身的大小sizeof(FLT_REGISTRATION).
USHORT Version; 版本 必须设置为FLT_REGISTRATION_VERSION
FLT_REGISTRATION_FLAGS Flags; 标志 @1
CONST FLT_CONTEXT_REGISTRATION *ContextRegistration; 上下文@2
CONST FLT_OPERATION_REGISTRATION *OperationRegistration;
PFLT_FILTER_UNLOAD_CALLBACK FilterUnloadCallback;
PFLT_INSTANCE_SETUP_CALLBACK InstanceSetupCallback;
PFLT_INSTANCE_QUERY_TEARDOWN_CALLBACK InstanceQueryTeardownCallback;
PFLT_INSTANCE_TEARDOWN_CALLBACK InstanceTeardownStartCallback;
PFLT_INSTANCE_TEARDOWN_CALLBACK InstanceTeardownCompleteCallback;
PFLT_GENERATE_FILE_NAME GenerateFileNameCallback;
PFLT_NORMALIZE_NAME_COMPONENT NormalizeNameComponentCallback;
PFLT_NORMALIZE_CONTEXT_CLEANUP NormalizeContextCleanupCallback;
#if FLT_MGR_LONGHORN
PFLT_TRANSACTION_NOTIFICATION_CALLBACK TransactionNotificationCallback;
PFLT_NORMALIZE_NAME_COMPONENT_EX NormalizeNameComponentExCallback;
#endif // FLT_MGR_LONGHORN
} FLT_REGISTRATION, *PFLT_REGISTRATION;
含义如下:
成员 | 含义 | 说明 | 是否重点 ⚪了解 √号 重点 ×极少或不使用 |
---|---|---|---|
Size | 大小 | 指向自身的大小 sizeof(FLT_REGISTRATION) | ⚪ |
Version | 版本 | 必须设置为 FLT_REGISTRATION_VERSION | ⚪ |
Flags | 标志 | 两种设置,设置为NULL或者 FLTFL_REGISTRATION_DO_NOT_SUPPORT_SERVICE_STOP 设置为STOP的时候 MinniFilter停止服务的时候不会进行卸载不管你的卸载函数是否设置 | ⚪ |
ContextRegistration | 上下文 | 注册处理上下文的函数 如果注册了则结构体数组的最后一项必须设置为 FLT_CONTEXT_END | ⚪ |
OperationRegistration | 回调函数集 | 重点中的重点,主要学习的就是这个域怎么设置. 是一个结构体数组可以设置我们感兴趣的回调. 最后一项设置为 IRP_MJ_OPERATION_END | √ |
FilterUnloadCallback | 卸载函数 | 卸载MiniFilter回调.如果flags = xx_STOP 那么不管你是否设置都不会卸载 | √ |
InstanceSetupCallback | 卷实例加载回调 | 当一个卷加载的时候MiniFilter会为其生成一个实例并且绑定,比如移动硬盘接入的时候就会生成一个实例. 可以设置为NULL. | ⚪ |
InstanceQueryTeardownCallback | 控制实例销毁函数 | 这个实例只会在手工解除绑定的时候会来. | ⚪ |
InstanceTeardownStartCallback | 实例销毁函数 | 当调用的时候代表已经解除绑定,可以设置为NULL | ⚪ |
InstanceTeardownCompleteCallback | 实例解绑定完成函数 | 当确定时调用解除绑定后的完成函数,可以设置为NULL. | ⚪ |
GenerateFileNameCallback | 文件名字回调 | 生成文件名可以设置回调,可以设置为NULL. | ⚪ |
NormalizeNameComponentCallback | 查询WDK | ⚪× | |
NormalizeContextCleanupCallback | 查询WDK | ⚪× | |
TransactionNotificationCallback | 查询WDK | ⚪× | |
NormalizeNameComponentExCallback | 查询WDK | ⚪× |
其实本质就是学习 回调函数集
他是一个对象数组.我们看下它的结构吧.
typedef struct _FLT_OPERATION_REGISTRATION {
UCHAR MajorFunction;
FLT_OPERATION_REGISTRATION_FLAGS Flags;
PFLT_PRE_OPERATION_CALLBACK PreOperation;
PFLT_POST_OPERATION_CALLBACK PostOperation;
PVOID Reserved1;
} FLT_OPERATION_REGISTRATION, *PFLT_OPERATION_REGISTRATION;
-
参数1 指明的你想监控的IRP操作
-
参数2 是个标志
-
参数3 是你执行的监控回调 pre代表的意思是先前回调. 比如文件创建 还未创建之前调用你
-
参数4 监控后回调. 文件创建完会调用的回调
-
参数五 保留参数 给NULL即可.
IRP可以监控很多 这个查询WDK文档即可.
这里说一下 标志
标志如下:
标志 | 含义 |
---|---|
FLTFL_OPERATION_REGISTRATION_SKIP_CACHED_IO | 使用此标志代表了不对缓存的IO处理进行 pre和post函数操作 适用于快速IO 因为所有快速IO已经缓存 |
FLTFL_OPERATION_REGISTRATION_SKIP_PAGING_IO | 指定不应该为分页操作的IO进行回调操作.对于不是基于IRP的io操作都会跳过.不会调用我们的函数 |
看着比较蒙对吧. 那我说一下. 其实在我们写一个文件的时候并不是直接写入到磁盘中.
而是先写到缓存中的. 缓存在写到内存中的.
调用链大概如下:
APP->IO->FSD->Cache->MM->IO->FSD->DISk 第一种
APP->IO->FSD->DISk 第二种
第一种就是先写到缓存中,当满足1024个字节的时候再由MM发起IO请求.然后在通知文件系统最好写道磁盘中.
第二种就是直接通过IO到文件系统,然后写入到磁盘中.
如果频繁读写是影响效率的.所以对于第一种不是IRP发起的请求我们都可以忽略掉.
所以这两个标志的意思就是差不多这个意思.
2.3 pre回调 和post回调
pre回调函数原型如下:
typedef FLT_PREOP_CALLBACK_STATUS
(*PFLT_PRE_OPERATION_CALLBACK) (
__inout PFLT_CALLBACK_DATA Data,
__in PCFLT_RELATED_OBJECTS FltObjects,
__deref_out_opt PVOID *CompletionContext
);
post回调函数如下:
typedef FLT_POSTOP_CALLBACK_STATUS
(FLTAPI *PFLT_POST_OPERATION_CALLBACK) (
__inout PFLT_CALLBACK_DATA Data,
__in PCFLT_RELATED_OBJECTS FltObjects,
__in_opt PVOID CompletionContext,
__in FLT_POST_OPERATION_FLAGS Flags
);
2.3.1 pre返回值和post返回值
首先说一下返回值
pre返回值如下
返回值 | 含义 | 是否是重点 |
---|---|---|
FLT_PREOP_SUCCESS_WITH_CALLBACK | 完成回调的调用并且callbackData往下发,post中可以使用CallbackData | √ |
FLT_PREOP_SUCCESS_NO_CALLBACK | 完成回调,不带参数往下发. | √ |
FLT_PREOP_PENDING | 挂起 | |
FLT_PREOP_DISALLOW_FASTIO | 禁用Fastio | |
FLT_PREOP_COMPLETE | 完成回调,不会往下发 | √ |
FLT_PREOP_SYNCHRONIZE | 同步 |
其实主要就是三个常用的就是 FLT_PREOP_SUCCESS_WITH_CALLBACK
和 FLT_PREOP_COMPLETE
POST回调
返回值 | 含义 | 是否常用 |
---|---|---|
FLT_POSTOP_FINISHED_PROCESSING | 完成,筛选器管理器将继续完成 I/O 操作的处理。 | √ |
FLT_POSTOP_MORE_PROCESSING_REQUIRED | 微筛选器驱动程序已停止 I/O 操作的完成处理,但它不会将操作的控制权返回给筛选器管理器。 | √ |
FLT_POSTOP_DISALLOW_FSFILTER_IO | 微筛选器驱动程序不允许快速 QueryOpen 操作,并强制该操作沿慢速路径向下。这样做会导致 I/O 管理器通过执行文件的打开/查询/关闭来为请求提供服务。微筛选器驱动程序应仅返回 QueryOpen 的此状态。 |
2.3.2 PFLT_CALLBACK_DATA 数据获取
此参数是参数1 是很重要的参数. 其结构如下
typedef struct _FLT_CALLBACK_DATA {
FLT_CALLBACK_DATA_FLAGS Flags;
PETHREAD CONST Thread;
PFLT_IO_PARAMETER_BLOCK CONST Iopb;
IO_STATUS_BLOCK IoStatus;
struct _FLT_TAG_DATA_BUFFER *TagData;
union {
struct {
LIST_ENTRY QueueLinks;
PVOID QueueContext[2];
};
PVOID FilterContext[4];
};
KPROCESSOR_MODE RequestorMode;
} FLT_CALLBACK_DATA, *PFLT_CALLBACK_DATA;
其中记录了线程. 标志 iopb 以及 IoStatus
线程可以判断是否是哪个进程的
PFLT_CALLBACK_DATA Data;
PEPROCESS processObject =
Data->Thread ? IoThreadToProcess(Data->Thread) : PsGetCurrentProcess();
其中Iopb域则记录了我们之前从IRP堆栈中要获取的Buffer值.
Data->Iopb->Parameters.Create.SecurityContext->DesiredAccess
PVOID pQueryBuffer =
Data->Iopb->Parameters.DirectoryControl.QueryDirectory.DirectoryBuffer;
ULONG uQueryBufferSize =
Data->Iopb->Parameters.DirectoryControl.QueryDirectory.Length
PMDL pReadMdl = Data->Iopb->Parameters.Read. MdlAddress;
PVOID pReadBuffer = Data->Iopb->Parameters.Read. ReadBuffer;
ULONG uReadLength = Data->Iopb->Parameters.Read.Length;
IoStatus则记录了读写操作的长度值
还可以判断Data是什么操作. 也有宏.
FLT_IS_IRP_OPERATION
FLT_IS_FASTIO_OPERATION
FLT_IS_FS_FILTER_OPERATION
例子
if (FLT_IS_FASTIO_OPERATION(DATA))
{
status = STATUS_FLT_DISALLOW_FAST_IO;
Data->IoStatus.Status = status;
Data->IoStatus.information = 0;
return FLT_PREOP_DISALLOW_FASTIO;
}
2.3.3 对象的获取 FltObjects
它也是一个结构,记录了所有的你可以使用到的对象.
typedef struct _FLT_RELATED_OBJECTS {
USHORT CONST Size;
USHORT CONST TransactionContext;
PFLT_FILTER CONST Filter;
PFLT_VOLUME CONST Volume;
PFLT_INSTANCE CONST Instance;
PFILE_OBJECT CONST FileObject;
PKTRANSACTION CONST Transaction;
} FLT_RELATED_OBJECTS, *PFLT_RELATED_OBJECTS;
typedef CONST struct _FLT_RELATED_OBJECTS *PCFLT_RELATED_OBJECTS;
常用的就是如下:
FltObjects->Volume,
FltObjects->Instance,
FltObjects->FileObject,
FltObjects->FileObject->DeviceObject
2.3.4 例子学习
在WDK7600的Src目录下 有MiniFilter框架. 可以学习一下. 而如果使用VS高版本则需要自己选择模板进行生成.
例子目录: x:\WinDDK\7600.16385.1\src\filesys\miniFilter
-
nullFilter
一个基本的框架,没有过滤的用处.可以看看怎么写的.
-
passThrough
一个完整的框架 所以过滤已经设置,但是并不使用.以它学习是最好的.
-
scanner
一个拦截框架可以看看例子.
三丶MiniFilter的使用
MiniFilter需要进行安装方式有两种 inf安装方式和动态加载方式.
3.1 Inf安装方式 以passThrough 此例子的Inf讲解
inf了解即可.使用的时候拷贝一个inf即可.里面东西换成自己的就行
Inf如下:
;;;
;;; PassThrough
;;;
;;;
;;; Copyright (c) 1999 - 2001, Microsoft Corporation
;;;
[Version]
Signature = "$Windows NT$"
Class = "ActivityMonitor" ;指明了驱动的分组,必须指定.
ClassGuid = {b86dff51-a31e-4bac-b3cf-e8cfe75c9fc2} ;GUID 每个分组都有固定的GUID
Provider = %Msft% ;变量值 从STRING节中可以看到驱动提供者的名称
DriverVer = 06/16/2007,1.0.0.1 ;版本号
CatalogFile = passthrough.cat ;inf对应的cat 文件 可以不需要
[DestinationDirs]
DefaultDestDir = 12 ;告诉我们驱动拷贝到哪里 13代表拷贝到%windir%
MiniFilter.DriverFiles = 12 ;%windir%\system32\drivers
;;
;; Default install sections
;;
[DefaultInstall]
OptionDesc = %ServiceDescription%
CopyFiles = MiniFilter.DriverFiles
[DefaultInstall.Services]
AddService = %ServiceName%,,MiniFilter.Service
;;
;; Default uninstall sections
;;
[DefaultUninstall]
DelFiles = MiniFilter.DriverFiles
[DefaultUninstall.Services]
DelService = %ServiceName%,0x200 ;Ensure service is stopped before deleting
;
; Services Section
;
[MiniFilter.Service] ;服务的一些信息
DisplayName = %ServiceName%
Description = %ServiceDescription%
ServiceBinary = %12%\%DriverName%.sys ;%windir%\system32\drivers\
Dependencies = "FltMgr" ;服务的依赖
ServiceType = 2 ;SERVICE_FILE_SYSTEM_DRIVER
StartType = 3 ;SERVICE_DEMAND_START
ErrorControl = 1 ;SERVICE_ERROR_NORMAL
LoadOrderGroup = "FSFilter Activity Monitor" ;文件过滤分组
AddReg = MiniFilter.AddRegistry ;文件过滤注册表需要添加的高度值等信息
;
; Registry Modifications
;
[MiniFilter.AddRegistry]
HKR,,"DebugFlags",0x00010001 ,0x0
HKR,"Instances","DefaultInstance",0x00000000,%DefaultInstance%
HKR,"Instances\"%Instance1.Name%,"Altitude",0x00000000,%Instance1.Altitude%
HKR,"Instances\"%Instance1.Name%,"Flags",0x00010001,%Instance1.Flags%
;
; Copy Files
;
[MiniFilter.DriverFiles]
%DriverName%.sys
[SourceDisksFiles]
passthrough.sys = 1,,
[SourceDisksNames]
1 = %DiskId1%,,,
;;
;; String Section
;;
[Strings]
Msft = "Microsoft Corporation"
ServiceDescription = "PassThrough Mini-Filter Driver"
ServiceName = "PassThrough"
DriverName = "PassThrough"
DiskId1 = "PassThrough Device Installation Disk"
;Instances specific information.
DefaultInstance = "PassThrough Instance"
Instance1.Name = "PassThrough Instance"
Instance1.Altitude = "370030"
Instance1.Flags = 0x0 ; Allow all attachments
其实INF文件本质就是跟我们正常的DDK安装服务的方式一样.只不过他是在注册表中多加两个一个注册表键和实例.
INF安装后首先会拷贝驱动到 C:\\windows\\System32\driver
然后往注册表下面注册信息.
如下:
所以 如果我们动态加载驱动的时候需要多建立两个键 分别是 instances xxxinstance
然后添加高度值.
在动态加载的时候 我们的依赖驱动要修改为 FltMgr
分组要写为 FSFilter Activity Monitor
伪代码可使用的部分例子
创建驱动服务如下:
//创建驱动所对应的服务
hService = CreateService( hServiceMgr,
lpszDriverName, // 驱动程序的在注册表中的名字
lpszDriverName, // 注册表驱动程序的DisplayName 值
SERVICE_ALL_ACCESS, // 加载驱动程序的访问权限
SERVICE_FILE_SYSTEM_DRIVER, // 表示加载的服务是文件系统驱动程序
SERVICE_DEMAND_START, // 注册表驱动程序的Start 值 01234 五个选项 0 由系统核心进行加载 1 io子系统加载 2自动启动 3 手动启动 4禁止启动
SERVICE_ERROR_IGNORE, // 注册表驱动程序的ErrorControl 值
szDriverImagePath, // 注册表驱动程序的ImagePath 值
"FSFilter Activity Monitor",// 注册表驱动程序的Group 值 如果是文件过滤驱动动态加载则需要指定这个分组
NULL,
"FltMgr", // 注册表驱动程序的DependOnService 值 文件过滤驱动需要依赖FltMgr 需要在这里执行
NULL,
NULL);
其它比如启动服务 停止服务都是一样的.和DDK一样的.
安装文件过滤驱动的时候还需要我们为其在注册表中创建两个键.并且还需要设置高度值.
代码如下:
strcpy(szTempStr,"SYSTEM\\CurrentControlSet\\Services\\");
strcat(szTempStr,lpszDriverName);
strcat(szTempStr,"\\Instances");
if(RegCreateKeyEx(HKEY_LOCAL_MACHINE,szTempStr,0,"",REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS,NULL,&hKey,(LPDWORD)&dwData)!=ERROR_SUCCESS)
{
return FALSE;
}
// 注册表驱动程序的DefaultInstance 值
strcpy(szTempStr,lpszDriverName);
strcat(szTempStr," Instance");
if(RegSetValueEx(hKey,"DefaultInstance",0,REG_SZ,(CONST BYTE*)szTempStr,(DWORD)strlen(szTempStr))!=ERROR_SUCCESS)
{
return FALSE;
}
RegFlushKey(hKey);//刷新注册表
RegCloseKey(hKey);
//-------------------------------------------------------------------------------------------------------
// SYSTEM\\CurrentControlSet\\Services\\DriverName\\Instances\\DriverName Instance子健下的键值项
//-------------------------------------------------------------------------------------------------------
strcpy(szTempStr,"SYSTEM\\CurrentControlSet\\Services\\");
strcat(szTempStr,lpszDriverName);
strcat(szTempStr,"\\Instances\\");
strcat(szTempStr,lpszDriverName);
strcat(szTempStr," Instance");
if(RegCreateKeyEx(HKEY_LOCAL_MACHINE,szTempStr,0,"",REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS,NULL,&hKey,(LPDWORD)&dwData)!=ERROR_SUCCESS)
{
return FALSE;
}
// 注册表驱动程序的Altitude 值
strcpy(szTempStr,lpszAltitude);
if(RegSetValueEx(hKey,"Altitude",0,REG_SZ,(CONST BYTE*)szTempStr,(DWORD)strlen(szTempStr))!=ERROR_SUCCESS)
{
return FALSE;
}
// 注册表驱动程序的Flags 值
dwData=0x0;
if(RegSetValueEx(hKey,"Flags",0,REG_DWORD,(CONST BYTE*)&dwData,sizeof(DWORD))!=ERROR_SUCCESS)
{
return FALSE;
}
RegFlushKey(hKey);//刷新注册表
RegCloseKey(hKey);
3.2 使用驱动
inf安装完 只不过是注册了一个项到注册表.拷贝了驱动到系统目录.
我们可以使用两种方式启动
net start PassThrough
fltmc load PassThrough
两种方式都可以.
inf也可以通过 函数 SetupCopyOEMInfA
来进行加载. 当然我们一般都是右键点击进行安装.
如果是动态加载的方式,那么我们就按照动态加载的方式启动即可.
3.3 内核下预先准备MiniFilter的注册
其实跟3.1一样,3.1是应用层创建的注册表项. 而如果想保持应用层不变的情况下,那么就需要内核驱动在自己被加载的时候,自己注册为MiniFilter
也就是自己操作注册表即可.
下面提供例子.
/Call BOOLEAN result = PrepMiniFilter(my_driver_reg_path,L"324213");
NTSTATUS PrepMiniFilter(IN PUNICODE_STRING reg_path, IN PWSTR altiude) {
BOOLEAN result = FALSE;
NTSTATUS status = STATUS_UNSUCCESSFUL;
PWSTR driver_name = NULL;
WCHAR key_path[MAX_PATH] = {0};
WCHAR default_instance_value_data[MAX_PATH] = {0};
if (reg_path == NULL) return result;
if (reg_path->Buffer == NULL) return result;
if (reg_path->Length <= 0) return result;
if (altiude == NULL) return result;
if (altiude[0] == L'\0') return result;
do {
driver_name = wcsrchr(reg_path->Buffer, L'\\');
if (!MmIsAddressValid(driver_name)) break;
RtlZeroMemory(key_path, MAX_PATH * sizeof(WCHAR));
// swprintf(key_path, L"%ws\\Instances", driver_name);
status = RtlStringCbPrintfW(key_path, sizeof(key_path), L"%ws\\Instances",
driver_name);
if (!NT_SUCCESS(status)) break;
status = RtlCreateRegistryKey(RTL_REGISTRY_SERVICES, key_path);
if (!NT_SUCCESS(status)) break;
// swprintf(Data, L"%ws Instance", &driver_name[1]);
status = RtlStringCbPrintfW(default_instance_value_data,
sizeof(default_instance_value_data),
L"%ws Instance", &driver_name[1]);
if (!NT_SUCCESS(status)) break;
status = RtlWriteRegistryValue(
RTL_REGISTRY_SERVICES, key_path, L"DefaultInstance", REG_SZ,
default_instance_value_data,
(ULONG)(wcslen(default_instance_value_data) * sizeof(WCHAR) + 2));
if (!NT_SUCCESS(status)) break;
RtlZeroMemory(key_path, MAX_PATH * sizeof(WCHAR));
// swprintf(key_path, L"%ws\\Instances%ws Instance", driver_name,
// driver_name);
status = RtlStringCbPrintfW(key_path, sizeof(key_path),
L"%ws\\Instances%ws Instance", driver_name,
driver_name);
if (!NT_SUCCESS(status)) break;
status = RtlCreateRegistryKey(RTL_REGISTRY_SERVICES, key_path);
if (!NT_SUCCESS(status)) break;
status = RtlCreateRegistryKey(RTL_REGISTRY_SERVICES, key_path);
if (!NT_SUCCESS(status)) break;
status = RtlWriteRegistryValue(
RTL_REGISTRY_SERVICES, key_path, L"Altitude", REG_SZ, altiude,
(ULONG)(wcslen(altiude) * sizeof(WCHAR) + 2));
if (!NT_SUCCESS(status)) break;
ULONG dwData = 0;
status = RtlWriteRegistryValue(RTL_REGISTRY_SERVICES, key_path, L"Flags",
REG_DWORD, &dwData, 4);
if (!NT_SUCCESS(status)) break;
result = TRUE;
} while (FALSE);
return result;
}
使用的时候查看注释即可. 一般DriverEntry的第二个成员就是 reg_path, 第一个参数传入reg_path,第二个参数传入你想创建的 Altitude
值即可.
坚持两字,简单,轻便,但是真正的执行起来确实需要很长很长时间.当你把坚持两字当做你要走的路,那么你总会成功. 想学习,有问题请加群.群号:725864912(收费)群名称: 逆向学习小分队 群里有大量学习资源. 以及定期直播答疑.有一个良好的学习氛围. 涉及到外挂反外挂病毒 司法取证加解密 驱动过保护 VT 等技术,期待你的进入。
详情请点击链接查看置顶博客 https://www.cnblogs.com/iBinary/p/7572603.html
本文来自博客园,作者:iBinary,未经允许禁止转载 转载前可联系本人.对于爬虫人员来说如果发现保留起诉权力.https://www.cnblogs.com/iBinary/p/15809124.html
欢迎大家关注我的微信公众号.不定期的更新文章.更新技术. 关注公众号后请大家养成 不白嫖的习惯.欢迎大家赞赏. 也希望在看完公众号文章之后 不忘 点击 收藏 转发 以及点击在看功能. QQ群: