本帖最后由 ANY.LNK 于 2024-11-7 01:59 编辑
此分析作者分为四部分发送,可在https://n4r1b.com/posts/查看原文目录
WdFilter是MDAV的主要内核组件,作为“FSFilter Anti-Virus”加载顺序组的minifilter,它链接到文件系统堆栈(一个相当高的高度),在一些回调前后处理I/O操作。不仅如此,该驱动同样应用了其他技术以获取系统中正在发生事件信息,本文将进行更深入的分析。
初始化
作者分析时的WdFilter版本为4.18.1910.4(SHA256:52D2A7A085896AC8A4FF92201FC87587EDF86B930825840974C6BC09BFB27E5B),如今,WdFilter已经进行了多次更新,但一些基本的结构、原理和运行方式不会改变太多
我们先从DriverEntry开始。正如WdBoot那样第一步首先检查是否处于安全模式下并启动WPP跟踪。随后,主结构MpData分配。在我分析的这个版本中MpData为0xCC0字节,并分配在一块非分页池中的标签为MPfd的区域。分配完成后,代码将继续调用MpInitializeGlobals以初始化MpData中的一些结构(PagedLookasideLists, EResources, Timer among others)此函数同样负责计算掩码以确认操作系统版本,如下图所示
MpVerifyWindowsVersion接收主系统版本,内部版本,ServicePack以及构建数等,最后调用RtlVerifyVersionInfo验证系统版本是否更高。
在此函数内的一些函数指针将被获取,特别是MpGetSystemRoutines中的一些。这个函数会使用MmGetSystemRoutineAddress并保存返回的地址入MpData,在此处系统版本掩码OsVersionMask投入使用,因为一些指针只能在特定的系统版本中获取,例如FltRequestFileInfoOnCreateCompletion只能在Windows 10 17726及更高版本获得。
回到初始化函数,还有一件它要做的事是创建如下SID:
·MpServiceSID
·NriServiceSID
·TrustedInstallerSID
随后MpData初始化完成,虽然仍然存在大量等待被其他函数填充的组件。你可以在下面看到庞大的结构仍然有很多区域的缺失
- typedef struct _MP_DATA
- {
- SHORT Magic; // Set to 0xDA00
- SHORT StructSize; // Sizeof 0xCC0
- PDRIVER_OBJECT pDriverObject;
- PFLT_FILTER MpFilter;
- NTSTATUS (__fastcall *pPsSetCreateProcessNotifyRoutineEx)(PCREATE_PROCESS_NOTIFY_ROUTINE_EX, BOOLEAN);
- NTSTATUS (__fastcall *pPsSetCreateProcessNotifyRoutineEx2)(PSCREATEPROCESSNOTIFYTYPE, PVOID, BOOLEAN);
- NTSTATUS (__fastcall *pPsSetCreateThreadNotifyRoutineEx)(PSCREATETHREADNOTIFYTYPE, PVOID);
- NTSTATUS (__fastcall *pObRegisterCallbacks)(POB_CALLBACK_REGISTRATION, PVOID *);
- void (__fastcall *pObUnRegisterCallbacks)(PVOID);
- NTSTATUS (__fastcall *pFltRegisterForDataScan)(const PFLT_INSTANCE);
- NTSTATUS (__fastcall *pFltCreateSectionForDataScan)(PFLT_INSTANCE Instance, PFILE_OBJECT FileObject, PFLT_CONTEXT SectionContext, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PLARGE_INTEGER MaximumSize, ULONG SectionPageProtection, ULONG AllocationAttributes, ULONG Flags, PHANDLE SectionHandle, PVOID *SectionObject, PLARGE_INTEGER SectionFileSize);
- NTSTATUS (__fastcall *pFltCloseSectionForDataScan)(PFLT_CONTEXT);
- NTSTATUS (__fastcall *pFltRequestFileInfoOnCreateCompletion)(PFLT_FILTER, PFLT_CALLBACK_DATA, ULONG);
- PVOID (__fastcall *pFltRetrieveFileInfoOnCreateCompletion)(PFLT_FILTER Filter, PFLT_CALLBACK_DATA Data, ULONG InfoClass, PULONG Size);
- NTSTATUS (__fastcall *pFsRtlQueryCachedVdl)(PFILE_OBJECT FileObject, PLONGLONG Vdl);
- PVOID pIoBoostThreadIo;
- PVOID pKeSetActualBasePriorityThread;
- PVOID pSeGetCachedSigningLevel;
- PIO_FOEXT_SILO_PARAMETERS (__fastcall *pIoGetSiloParameters)(const PFILE_OBJECT);
- BYTE field_90;
- BYTE PanicModeFlag;
- BYTE field_92;
- BYTE field_93;
- INT ScannedFilesCount;
- INT field_98;
- INT field_9C;
- PEPROCESS MsMpEngProcess;
- HANDLE MsMpEngProcessId;
- INT ConnectionPortCookieSet;
- PFLT_PORT FltProtectionControlPort;
- PFLT_PORT ProtectionControlPortServerCookie;
- PFLT_PORT FltProtectionPort;
- PFLT_PORT ProtectionPortServerCookie;
- PFLT_PORT FltProtectionVeryLowIoPort;
- PFLT_PORT ProtectionVeryLowIoServerCookie;
- PFLT_PORT FltProtectionRemoteIoPort;
- PFLT_PORT ProtectionRemoteIoServerCookie;
- PFLT_PORT FltProtectionAsyncPort;
- PFLT_PORT ProtectionAsyncServerCookie;
- INT SomeScanFileFlag;
- INT SendSyncNotificationFlag;
- KSEMAPHORE ScanFileSemaphore1;
- KSEMAPHORE ScanFileSempahore2;
- KSEMAPHORE SendingSyncSemaphore;
- PVOID pBootSectorCache;
- LIST_ENTRY FltInstanceCtxList;
- LIST_ENTRY FltStreamCtxList;
- PCWSTR RegistryParametersPath;
- BYTE DriverVerifiedFlag;
- BYTE field_1A1;
- BYTE field_1A2;
- BYTE field_1A3;
- INT VerifyDriverLevelValue;
- INT64 ResetTimer;
- INT FileScanConsecutiveTimeoutsCount;
- INT field_1B4;
- KDPC WdFilterDPC;
- KTIMER WdFilterTimer;
- ERESOURCE MpDataResource;
- INT64 AsyncNotificationCount;
- INT OsVersionMask;
- INT MonitorFlags;
- INT64 field_2B0;
- INT64 field_2B8;
- PAGED_LOOKASIDE_LIST CompletionContextLookaside;
- NPAGED_LOOKASIDE_LIST WriteContextLookaside;
- NPAGED_LOOKASIDE_LIST field_3C0;
- PAGED_LOOKASIDE_LIST InstanceContextLookaside;
- PAGED_LOOKASIDE_LIST FltInputMessagesLookaside;
- PAGED_LOOKASIDE_LIST FltOutputMessagesLookaside;
- ULONG MpFilterEcpSize;
- INT64 field_5C8;
- INT64 field_5D0;
- INT64 field_5D8;
- INT64 field_5E0;
- INT64 field_5E8;
- INT64 field_5F0;
- INT64 field_5F8;
- NPAGED_LOOKASIDE_LIST ExtraCreateParamsLookaside;
- PVOID ObRegistrationHandle;
- PSID MpServiceSID;
- PSID NriServiceSID;
- PSID TrustedInstallerSID;
- INT MaxLocalScanTimeout;
- INT MaxNetworkScanTimeout;
- INT field_6A8;
- INT UnsetObAndRegCallback;
- BYTE RawVolumeWriteFlag;
- BYTE MpOrWdFlag;
- BYTE field_6B2;
- BYTE field_6B3;
- INT field_6B4;
- PVOID PowerSettingCbHandle;
- BYTE LowPowerEpochOn;
- BYTE field_6C1;
- BYTE field_6C2;
- BYTE field_6C3;
- int field_6C4;
- INT64 MachineUptime;
- MP_CSRSS_HOOK_DATA *pCsrssHookData;
- PCALLBACK_OBJECT pProcessNotificationCallback;
- PCALLBACK_OBJECT pNriNotificationCallback;
- INT64 NriNotificationCallbackHandle;
- INT64 field_6F0;
- INT64 field_6F8;
- LIST_ENTRY field_700;
- FAST_MUTEX MpDataFastMutex;
- INT64 field_748;
- INT64 field_750;
- INT64 field_758;
- INT64 field_760;
- INT64 field_768;
- INT64 field_770;
- INT64 field_778;
- PAGED_LOOKASIDE_LIST PagedLookasideMPbc;
- INT field_800;
- INT field_804;
- INT64 field_808;
- INT64 field_810;
- INT64 field_818;
- INT64 field_820;
- INT64 field_828;
- INT64 field_830;
- INT64 field_838;
- INT64 field_840;
- INT64 field_848;
- INT64 field_850;
- INT64 field_858;
- INT64 field_860;
- INT CsvFileStateCacheType;
- INT FileStateCachePolicy;
- INT64 field_870;
- INT field_878;
- INT field_87C;
- INT CounterFileSystemTypeCSVFS;
- INT field_884;
- INT field_888;
- INT RefsFileStateCacheType;
- INT FileStateCachePolicy1;
- INT64 field_898;
- INT field_8A0;
- INT field_8A4;
- INT CounterFileSystemTypeREFS;
- INT field_8AC;
- INT field_8B0;
- INT64 FltSendMessageTimeStamp;
- INT FltSendMessageCount;
- INT field_8C4;
- INT SomethingWithSettingProcessInfo;
- INT FltSendMessageError;
- INT FltSendMessageErrorCode;
- INT FltSendMessageStatusTimeout;
- INT FltSendMessageReplyBufferMismatch;
- INT AllowFilterManualDetach;
- LIST_ENTRY BootScanCtxList;
- ERESOURCE ExResource1;
- ERESOURCE ExResource2;
- INT field_9C0;
- INT field_9C4;
- PUNICODE_STRING SystemRootPath;
- INT field_9D0;
- INT field_9D4;
- BYTE OpenWithoutReadNotificationFlag;
- RTL_GENERIC_TABLE RtlGenericTable;
- FAST_MUTEX WdFilterGenericTableMutex;
- MP_SYNC_NOTIFICATIONS_STATUS SyncNotifications[8];
- INT SyncNotificationRecvCount[8];
- INT SyncNotificationsCount[8];
- INT SyncNotificationsStatus[8];
- INT SyncNotificationsIoTimeoutCount[8];
- INT SyncNotificationsRecvErrorCount[8];
- INT MonitorNotificationFlag;
- INT field_B84;
- INT64 SyncMonitorNotificationTimeout;
- INT64 RandNumber;
- BYTE MpEaString[256];
- INT AsyncDirectoryNotificationFlag;
- BYTE DataLossPreventionFlag;
- BYTE field_C9D;
- BYTE field_C9E;
- BYTE field_C9F;
- INT64 field_CA0;
- INT64 field_CA8;
- INT64 field_CB0;
- INT64 field_CB8;
- } MP_DATA, *PMP_DATA;
复制代码
下一步是设定驱动的参数或配置,这将再MpLoadRegistryParameters中完成。此函数会通过遍历被我命名为MP_CONFIG_PARAMS的组设置一个RTL_REGISTRY_QUERY_TABLE
- typedef struct _MP_CONFIG_PARAMS
- {
- PCWSTR Name;
- PMP_CONFIG *pMpConfig;
- INT64 DefaultData;
- } MP_CONFIG_PARAMS, *PMP_CONFIG_PARAMS
复制代码
可以看出,这个结构的第二个组件是结构MP_CONFIG的内部指针。该地址将在QueryTable被设置为EntryContext。最终函数会以注册表HKLM\System\CurrentControlSet\Services\WdFilter\Parameters调用RtlQueryRegistryValuesEx。此调用后,将检查EntryContext返回的值是否符合某些条件,若不符合将重设回默认值。MP_CONFIG有如下定义:
MpConfig结构被填充后,部分默认值将被复制入MpSetDefaultConfigs中的MpData中,接着函数MpSetBufferLimits将为用于同用户层MsMpEng.exe通信的输入输出消息设置不同的限制
我将把这部分通信的详细过程留到另一篇文章中。——作者
MpData初始化的最后一件事是初始化线程提速的相关内容——由函数MpInitializeBoostManager完成。现在还不是很相关,但我们能在其他文章中看到相关的内容。
从现在起,代码将开始初始化各种结构,每种又有不同的功能。我会介绍所有的组件,但在此我们先关注其中的一部分。首个函数是MpInitializeProcessTable,如其名,该函数将初始化持续跟踪系统进程情况的结构。为达成此目的,它将分配0x800大小的含一个LIST_ENTRY组的池——每个列表的入口点都是0x10大小,所以我们在此组内共有0x80个入口——这个LIST_ENTRY实际上是一个指向我命名为ProcessCtx结构的切换指针,其中包含观测进程的信息。进程表的定义类似于下图
此后,DriverEntry将调用MpInitBootSectorCache以分配0x64、标志为MPgb的池并保存一个再MpData->pBootSectorCache中的指针。——我们将在另一篇文章中详细讲解引导扇区检测。
之后,基于保存在MpConfig.MaxCopyCacheSize中的值,另一个池将被分配,这次指向此池的指针将被保存在全局变量MpCopyCacheData中。——MaxCopyCacheSize的值不能高于0x200,为了分配池该值左移6次,因此最大值是0x8000。当此完成后,下一步是初始化如下的结构和回调:
·进程排除项回调,在MpInitializeProcessExclusions中以0x78大小、标志MPps初始化,保存在全局MpProcessExclusion中。
·电源设置回调,在MpPowerStatusInitialize中完成,接收MpData->PowerSettingCbHandle的地址作为参数,该函数使用PoRegisterPowerSettingCallback在电源设置GUID_LOW_POWER_EPOCH上设立回调。注册成功后,句柄将保存在参数中——我们将在文章结尾看到实际的回调函数。
·事务NTFS结构,将在MpTxfInitialize中以0x140大小、MPtd标志初始化,保存为全局名称MpTxfData。
·同异步结构共存的异步工作线程在MpAsyncInitialize中初始化,此结构主要保留两个列表的排队等待被异步工作线程发送的消息。此线程同样在此结构中被初始化,且函数MpAsyncpWorkerThread被设置为它的启动例程。
·注册表数据结构,在MpRegInitialize中初始化,大小0x500、标志MPrd。这是另一个大而重要的结构,主要用于注册表回调。下一篇文章中我们将详细讲述此回调。
·文档规则结构,在MpInitializeDocOpenRules中初始化,大小0x100,标志MPdo,保存在全局MpBmDocOpenRules——一会儿后我们可以深入看到更多关于这个有趣的结构
·文档卫士(受控文件夹访问)结构,在MpFgInitialize中初始化,只能在Windows 10 16000或更晚的操作系统上运行,大小0x240、标志MPFg,保存于全局MpFolderGuard。此结构保留指向RTL_AVL_TABLE表和RTL_AVL_TABLE的指针,主要用于允许或撤销对文件/文件夹的访问。
·最后,驱动信息结构,在MpInitializeDriverInfo中初始化,同ELAM驱动紧密联系(绑定),主要用于回调在\Callback\WdEbNotificationCallback注册的函数。当我们看到此函数时,便可以将先前WdBoot的内容同WdFilter处理这些数据的内容联系到一起。
于此,我们已拥有大量已分配的池和初始化的结构:
DriverEntry中的下一步是初始化MpInitializeFltMgr中的minifilter,以及MpCreateCommPorts中的通信端口。
前者将基于配置和OsVersionMask为FLT_REGISTRATION结构选择一个特定的OperationRegistration,并通过FilterRegistration注册minifilter FltRegisterFilter。
后者首先设置使用MpServiceID的安全描述器,此安全描述器将在ObjectAttributes作为FltCreateCommunicationPort的参数使用。
创立4个不同的端口:
·MicrosoftMalwareProtectionControlPort(这是唯一注册MessageNotifyCallback的端口)
·MicrosoftMalwareProtectionPort
·MicrosoftMalwareProtectionVeryLowIoPort
·MicrosoftMalwareProtectionRemoteIoPort
从这一点来看,DriverEntry将为如下事件注册回调:
·进程创建
·映像加载
·线程创建
·映像验证
·对象操作(进程类型和桌面对象类型)
·注册表操作
(本文本部分集中在前两条上)
设置映像验证回调后,驱动将开始FltStartFiltering过滤。驱动初始化将在后二回调注册完毕后完成。当然,如果任意步骤失败,驱动将清空所有。
MpSetProcessNotifyRoutine
我们首个研究的回调注册是进程创建,此回调注册在MpSetProcessNotifyRoutine中。此函数首先检查PsSetCreateProcessNotifyRoutineEx2是否可用(Windows 10 14980 OsVersionMask & 0x80),若可用则会使用此函数注册回调;若不可用它将检查PsSetCreateProcessNotifyRoutineEx,如果这个也不可用,它将采用PsSetCreateProcessNotifyRoutine。当其中任何之一的回调注册后,代码将继续创立两个回调对象(\Callback\WdProcessNotificationCallback和\Callback\WdNriNotificationCallback)。在那之后,代码同样会注册回调函数MpNriNotificationCallback
MpCreateProcessNotifyRoutineEx - MpCreateProcessNotifyRoutine
此节我将讲解为进程创建而注册的的回调例程作用。正如节标题所述,可以有两个例程,前者由..Ex2和..Ex注册,后者由PsSetCreateProcessNotifyRoutine注册。
..Ex和..Ex2的区别是后者允许提供一个PSCREATEPROCESSNOTIFYTYPE虽然尽管此值可以仅设置为PsCreateProcessNotifySubsystems。或许将来会增加更多的值,例如仅从WSL子系统获取通知。另一方面,此二者和PsSetCreateProcessNotifyRoutine的不同在于后者例程原型为CREATE_PROCESS_NOTIFY_ROUTINE,而前二者为CREATE_PROCESS_NOTIFY_ROUTINE_EX
所有的函数都很像,并共享很多代码。只有一小部分不同,最主要的区别在于:
·MpCreateProcessNotifyRoutineEx可以使用PS_CREATE_NOTIFY_INFO,例如标志FileOpenNameAvailable被设置时则无需获取进程句柄即可获取ImageFileName;
·MpCreateProcessNotifyRoutineEx可以通过将CreationStatus设置为错误进而拒绝进程创建;
·MpCreateProcessNotifyRoutineEx拥有调用MpAddBootProcessEntry添加进程到进程启动列表的能力
进入实际代码,正如我前文所述,若我们没有FileOpenNameAvailable的标志或PS_CREATE_NOTIFY_INFO,代码将继续通过ZwOpenProcess获取进程句柄并调用MpGetProcessNameByHandle,此函数将继续调用ZwQueryInformationProcess获取ProcessImageFileName作为ProcessInformationClass。一旦回调获取ImageFileName它将继续获取规范化名称,为实现此目标,它将调用MpGetImageNormalizedName函数。此函数主要调用FltGetFileNameInformationUnsafe,名称选项为FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT。最终,回调例程将以调用主函数MpHandleProcessNotification作为结尾。
MpHandleProcessNotification:
此函数拥有两个清晰的代码路径,由Create标志定义。有进程创建的情况下,第一个,也是过滤器最重要的步骤之一,是创建ProcessContext结构。在MpCreateProcessContext中完成。
该函数主要从Lookaside MpProcessTable->ProcessCtxLookaside中分配内存,用于保留进程的上下文——大小0xC0,标志MPpX——内存分配完成后,它将填充进程上下文结构组件,如下:
一旦进程上下文(从现在起称之为ProcessCtx)被检索或创建,函数将继续检查是否应为此进程添加文档规则。此功能在MpSetProcessDocOpenRule中完成且涉及2个结构:其一用于保存所有文档规则的列表,其二则为每条规则保存列表。
代码的功能基本上就是遍历每个条目,对比ImageFileName和DocProcessName,若匹配其中任意的规则,MP_DOC_RULE结构指针将保存在ProcessCtx->pDocRule。
下一步是检查已创建上下文的进程是否为csrss.exe——MpSetProcessPreScanHook——若是,则指向CsrssPreScanHook的指针将被保存在ProcessCtx.pCsrssPreScanHook且标志MpData->pCsrssHookData->HookSetFlag将设立。只会在csrss.exe的进程上下文如此。
在通知进程创建前的最后一步是检查进程是否满足某些例外条件并依此设置ProcessCtx.ProcessFlags。用于执行此目的的有3个函数:
·MpSetProcessExempt
·MpSetProcessHardening
·MpSetProcessHardeningExclusion
第一个函数将遍历以下结构的单个列表条目——我明白,这有大量结构。
它将检查ImageFileName的FinalComponent是否小于等于列表中的任意一条。若匹配则通过应用0x1的OR设置ProcessFlags。驱动程序可以基于用户层的MsMpEng.exe添加进程或路径到MP_PROCESS_EXCLUDED列表。
我们可以在此看到使用此标准排除的进程列表:
此情况下有个特殊情况:若进程为MsMpEng.exe,进程标志将被OR设为0x9
第二个检查首先检查FinalComponent是否匹配MpCmdRun.exe或MsMpEng.exe。此情况下它将检查进程访问权限是否匹配先前创建的MpServiceSID。若没有进程名匹配,它将检查NisSrv.exe和NriServiceSID。若任意情况匹配成功,进程标志将被OR设为0x10。
另一种可能的情况是如果我们正在运行MpFilter而非WdFilter,则进程名称将同msseces.exe进行比较。若成功匹配,进程标志将被OR设为0x80
最后的检查首先创建(如果需要的话)一个加固排除进程列表条目。此列表条目的值被硬编码在WdFilter的结构之一,一个标志指示了它应用于哪些系统,最终掩码将被应用在进程标签上。
这些值将被填充在如下结构中
一旦结构填充完毕,就会使用非常标准的检查流程:代码比较名称,若匹配,就应用ProcessHardeningExcludedFlag到ProcessCtx.ProcessFlags。下图展示了我系统中在MP_PROCESS_HARDENING_EXCLUDED中的进程列表。
关于进程排除的最后一个细节:刚刚两个结构的引用保存在另一个结构中——是的,因为已经没有足够的结构了……但,还有一个
所有这一切后,“默认”结构上下文准备完成。是时候通知回调\Callback\WdProcessNotificationCallback了。参数1包含如下结构:
通知完回调就只需一步就可以结束进程通知回调了,这一步就是向监听端口ProtectionPortServerCookie的用户层进程发送通知了。
在介绍前,我先解释下未设置进程创建标志(即进程正在退出)的情况。此时将通过进程ID获取进程上下文,填充MP_PROCESS_CB_NOTIFY结构并通知回调。此后调用MpSendProcessMessage创建并发送信息。
最后的细节是对MpCopyCacheProcessTerminate的调用将遍历MP_COPY_CACHE_ENTRY组
MpSendProcessMessage
此函数,和很多本文中出现的其他函数,都用于处理创建包含特定数据的信息,并发送给MsMpEng.exe。可以同步发送,也可以异步发送(使用上述工作线程——消息的创建会不同)。尽管有时使用异步方法,但稍后会同步发送该消息。
在此函数中,两种信息都会使用异步创建,但如果参数CreateFlag被设置为0x1,则消息将同步发送(FltSendMessage),若为0x0,消息会进入等待序列,稍后由工作线程处理。
我尽量简化解释,所有异步消息将由函数MpAsyncCreateNotification创建。此函数接收2个参数,第一个是一个外参,返回分配缓冲区内的一个移位指针,此指针作为消息发送;第二个是要分配的大小。
调用后,我们将得到一个需要用特定数据填充的缓冲区。这次也一样,缓冲区被移位8字节到我命名为AsyncMessageData的结构中:
我们可以看到,此结构包含一个联合体,每种不同类型消息的特定数据都从此开始。此处我们重点关注ProcessNotify相关数据。
此结构不包含ImageFileName和CommandLine,若存在任何其一或其二,字符串将位于数据后,组件OffsetToImageFileName、OffsetToCommandLine将包含每个字符串的相对偏移量(从内部结构开始的相对值)
结构体内的结构AuxPidCreationTime只是包含以ULONG存储的PID和以ULONG64存储的创建时间。若有人知道已经定义了的包含这些数据的结构,请告知,我会修改。
一旦消息发送,在使用FltSendMessage的情况下,函数将继续检查调用状态并据此填充部分MpData区域
·FltSendMessageCount
·FltSendMessageError(失败的情况下)
·FltSendMessageStatusTimeout(状态为STATUS_TIMEOUT)
若一切正常,代码将检查ReplyBuffer(首字节应为0x5D,第二字节应为0x60,为回应消息的大小),此中回应缓冲区可包含是否允许创建进程的判断结果(字节0x48)
结束前操作的最后一步是设置进程信息(主要使用从ReplyBuffer接收的信息)。此后它将测试进程标志ProcessFlags & 0x20 || ProcessFlags & 0x18用于添加进程到信任或非信任列表,分别在在MpSetTrustedProcess或MpSetUntrustedProcess中完成。但这篇文章已经够长了,所以就留到下一部分去吧。
MpPowerStatusCallback
在结束前,我会讲一点之前提到的在初始化时注册的电源设置回调例程。
由于我对电源管理的知识匮乏,没有此GUID的信息,唯一找到同微软、低功耗阶段有关的是文档中的PEP_LOW_POWER_EPOCH,但文档中也没说明,只说用于一个已经废弃的通知。将此函数放在这里只是希望如果有知道这个函数功能的人可以联系到我。
总结
文档的第一部分就到这里了,抱歉写了这么长且有些混乱的文章。我真的想写的简洁明了,但驱动程序涉及很多很复杂的事情。但请耐心看完所有的文章,这会很有意义!我希望我们在结尾能把这所有的一切串起来。后续还有许多文章,在下一篇中,我们将继续讨论映像加载和线程创建回调,希望大家喜欢!
若有任何错误疏漏,请随时联系!
附加
这个小windbg脚本可以让我们从系统中所有进程上下文打印任意想要获取的数据。只需WdFilter的符号并随意调整!list命令即可。
- r @$t0 = poi(poi(WdFilter!MpProcessTable)+180); // MpProcessTable->ProcessCtxArray 的指针
- .for (r $t1 = 0; @$t1 != 0x80; r $t1 = @$t1+1) // 组大小 size 0x80
- {
- r @$t2 = @$t0+10*@$t1; // 移动指针到下一个 LIST_ENTRY
- .if ( @$t2 == poi(@$t2) ) { // 检查我们的指针值是否与 Blink 一致
- .continue
- }
- .else { // 走一遍 LIST_ENTRY 并打印
- // 想从 ProcessCtx 获取的组件
- // ProcessCtx.ProcessId 和 ProcessCtx.ProcessCmdLine
- !list -t nt!_LIST_ENTRY.Flink -x "dd @$extret+10 L1; dS /c100 poi(@$extret+20)" -a "L1" poi(@$t2)
- }
- }
复制代码
运行上述脚本,将得到
|