Windows资源监视器软件的原理

微软给我们提供了一些很好的程序,比如资源监视器,可以从这个软件里获取分析windows的自身的一些性能数据,比如CPU、内存、磁盘数据、文件读写、进程线程等,他具体怎么实现呢,今天这天文章就带你去获取其真实的原理。

1.分析

打开windows任务栏管理器,在其性能选项里,可以看到性能监控的一些机器性能图表

这个只是一些概要数据,如果要看详细的内容,可以点击左下角的“打开资源监视器”,会自己开启一个进程perfmon.exe的进程,这个进程界面会显示详细的资源信息

我们可以看到每个进程打开了什么文件、读写了什么磁盘数据、以及访问了什么网络的IP都有详细的信息,这个进程既没有文件过滤驱动也没有网络驱动他是如何实现去获取这些详细的信息呢,下面我们来具体分析下。

打开这个软件所在的目录,可以看到一些对应的perfmon.exe 、perfnet.dll、perfDisk.dll、perfos.dll、perfpro.dll进程和模块

用IDA打开perfmon.exe看看其进程一些函数

也只是一些UI相关的函数,说明核心功能并不在这里exe里 ,在继续换一个,用IDA打开perdisk.dll这个模块

模块里有一些比较明显的函数CollectDiskObjectData、CollectPDiskObjectData、CollectLDiskObjectData等函数,选择一个函数用windbg调试器去下断点

当第一放过运行时,调试器立马就停了下来,看堆栈区域

大概是这样的

# RetAddr           : Args to Child                                                           : Call Site
00 00007ffc`2d132060 : ffffffff`feced300 00000000`00000010 00000000`00000014 00000000`00000000 : perfdisk!CollectDiskObjectData
01 00007ffc`2d1316b5 : 00000000`00007f88 00000000`00000000 00000000`00000000 00000000`00000000 : ADVAPI32!QueryExtensibleData+0x540
02 00007ffc`29a92a99 : 0000021e`67749c66 00000000`000602ff 000000fc`368ff728 00007ffc`ffffffff : ADVAPI32!PerfRegQueryValue+0x325
03 00007ffc`29a9204d : ffffffff`80000004 000000fc`368ff7a4 0000021e`6b4904f0 000000fc`368ff820 : KERNELBASE!MapPredefinedHandleInternal+0x8e9
04 00007ffc`25f063ec : ffffffff`80000004 0000021e`6b490490 0000021e`00008000 000000fc`368ff7a4 : KERNELBASE!RegQueryValueExW+0xed
05 00007ffc`25f056ad : 0000021e`6b490490 0000021e`6ad74c10 00000000`00008000 00000000`00000000 : pdh!GetSystemPerfData+0x9c
06 00007ffc`25f054c9 : 01d2e6b6`135f9140 000000fc`368ff8b8 00000000`00000000 01d2e673`053c5140 : pdh!GetQueryPerfData+0xcd
07 00007ffc`01548566 : 00000000`00000000 00000000`00000003 00000000`00000000 00000000`000002b0 : pdh!PdhCollectQueryData+0x59
08 00007ffc`2ad58364 : 0000021e`6adc1b00 00000000`00000000 00000000`00000000 00000000`00000000 : wdc!WdcTraceControl::QueryThread+0x1a6
09 00007ffc`2d2370d1 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : KERNEL32!BaseThreadInitThunk+0x14
0a 00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!RtlUserThreadStart+0x21

堆栈看该函数被调用是从wdc!WdcTraceControl::QueryThread这个函数过来的,看样子是一个单独的数据线程,是wdc.dll这个模块里的函数,继续用IDA打开wdc这个模块。

查看WdcTraceControl::QueryThread这个函数实现,确实调用了一些监控实例的Query方法,这里我们可以确认wc.dll这个模块是核心功能所在的模块,现在可以分析下是怎么开启这个线程的,开启前做了哪些工作。

发现只有一处调用,就是WdcTraceControl::Start函数调用了这个函数开启线程

继续往上翻阅WdcTraceControl::Start函数实现

有一个WdcTraceControl::TraceStart 函数,进入该函数

发现该函数调用OpenTrace、StartTrace、EnableTraceEx、processTrace这些函数,从EnableTraceEx的参数ThreadPoolGuid、PsProvGuid、DiskProvGuid、FileProvGuid、NetProvGuid可以判断这些函数就是核心功能,查看微软的CSDN终于发现了秘密,原来这些函数是 微软事件诊断函数(ETW),其中OpenTrace的里的有一个参数是事件的回掉接收函数,我们看到的WdcTraceControl::CallbackEvent这个函数就是,下个断点,确实断了下来

就是WdcTraceControl::TraceThread线程中的ProcessTrace函数处理获取了内核日志数据然后调用了设置的回调函数WdcTraceControl::CallbackEvent去处理,为了进一步验证,翻阅该回调函数的实现

可以知道里面处理了各种过来的数据包括网络、磁盘、cpu、内存、线程、进程日志信息,去写个demo实例验证我们的结果。

2.代码demo

#include "stdafx.h"
#define INITGUID  //Include this #define to use SystemTraceControlGuid in Evntrace.h.
#include <Windows.h>
#include <wmistr.h>
#include <evntrace.h>
#include <evntcons.h>
#include <strsafe.h>
#pragma comment(lib,"Advapi32.lib")
#define LOGFILE_PATH    L"kernellogfile.etl"
#define ETL_FILE        L"G:\\OpenSource\\GitHub\\WindowsSDK7-Samples\\winbase\\Eventing\\EtwConsumer\\Output\\16.pdf.etl"
#define __REAL_TIME_MODE
/* 不同类型的GUID,从MSDN手册中找,固定的 */
DEFINE_GUID ( /* 3d6fa8d0-fe05-11d0-9dda-00c04fd7ba7c */
ProcessGuid,
0x3d6fa8d0,
0xfe05,
0x11d0,
0x9d, 0xda, 0x00, 0xc0, 0x4f, 0xd7, 0xba, 0x7c
);
ULONG WINAPI BufferCallback( __in PEVENT_TRACE_LOGFILE LogFile )
{
printf( "BufferCallback!\n" );
return TRUE;
}
/* 可以调用SetTraceCallback 设置单独事件GUID的回调函数,即使如此,EventCallback仍然会收到所有的事件 */
VOID WINAPI EventRecordCallback( __in PEVENT_RECORD Event )
{
if ( IsEqualGUID( Event->EventHeader.ProviderId, ProcessGuid ) )
{
/* 需要解析数据格式 */
printf( "EventRecordCallback  ProcessGuid!\n" );
}
printf( "EventRecordCallback!\n" );
}
VOID WINAPI EventCallback( PEVENT_TRACE pEvent )
{
printf( "EventCallback!\n" );
}
VOID EventConsumer()
{
TRACEHANDLE hTrace = NULL;
EVENT_TRACE_LOGFILE traceFile;
#ifdef __REAL_TIME_MODE
traceFile.LogFileName = NULL;
traceFile.LoggerName  = KERNEL_LOGGER_NAME;
traceFile.ProcessTraceMode = PROCESS_TRACE_MODE_REAL_TIME | PROCESS_TRACE_MODE_EVENT_RECORD;
#else
traceFile.LogFileName = ETL_FILE;
traceFile.LoggerName = NULL;
traceFile.ProcessTraceMode = PROCESS_TRACE_MODE_EVENT_RECORD;
#endif
traceFile.BufferCallback        = BufferCallback;
traceFile.EventCallback         = EventCallback;
if ( traceFile.ProcessTraceMode & PROCESS_TRACE_MODE_EVENT_RECORD )
traceFile.EventRecordCallback   = EventRecordCallback;
traceFile.Context = NULL;
hTrace = OpenTrace( &traceFile );
if ( hTrace == (TRACEHANDLE)INVALID_HANDLE_VALUE || hTrace == 0x0 )
return ;
ULONG status = ProcessTrace( &hTrace, 1, NULL, NULL );
}
void EventController(void)
{
ULONG status = ERROR_SUCCESS;
TRACEHANDLE SessionHandle = 0;
EVENT_TRACE_PROPERTIES* pSessionProperties = NULL;
ULONG BufferSize = 0;
BufferSize = sizeof(EVENT_TRACE_PROPERTIES) + sizeof(KERNEL_LOGGER_NAME) + sizeof(LOGFILE_PATH) ;
pSessionProperties = (EVENT_TRACE_PROPERTIES*) malloc(BufferSize);    
if (NULL == pSessionProperties)
{
wprintf(L"Unable to allocate %d bytes for properties structure.\n", BufferSize);
goto cleanup;
}
ZeroMemory(pSessionProperties, BufferSize);
pSessionProperties->Wnode.BufferSize    = BufferSize;
pSessionProperties->Wnode.Flags         = WNODE_FLAG_TRACED_GUID;
pSessionProperties->Wnode.ClientContext = 1; //QPC clock resolution
pSessionProperties->Wnode.Guid          = SystemTraceControlGuid; 
pSessionProperties->EnableFlags         = EVENT_TRACE_FLAG_PROCESS;                 // 关注事件
#ifdef __REAL_TIME_MODE
pSessionProperties->LogFileMode         = EVENT_TRACE_REAL_TIME_MODE;               // EVENT_TRACE_USE_PAGED_MEMORY 该标识在win7上会导致失败
#else
pSessionProperties->LogFileMode         = EVENT_TRACE_FILE_MODE_CIRCULAR;
#endif
pSessionProperties->MaximumFileSize     = 5;  // 5 MB
pSessionProperties->LoggerNameOffset    = sizeof(EVENT_TRACE_PROPERTIES);
pSessionProperties->LogFileNameOffset   = sizeof(EVENT_TRACE_PROPERTIES) + sizeof(KERNEL_LOGGER_NAME); 
#ifndef __REAL_TIME_MODE            // 也可在RealTime模式下开启,但是没必要RealTime都记录到文件
StringCbCopy((LPWSTR)((char*)pSessionProperties + pSessionProperties->LogFileNameOffset), sizeof(LOGFILE_PATH), LOGFILE_PATH);
#endif
status = StartTrace((PTRACEHANDLE)&SessionHandle, KERNEL_LOGGER_NAME, pSessionProperties);
if (ERROR_SUCCESS != status)
{
if (ERROR_ALREADY_EXISTS == status)
wprintf(L"The NT Kernel Logger session is already in use.\n");
else
wprintf(L"EnableTrace() failed with %lu\n", status);
goto cleanup;
}
EventConsumer();
wprintf(L"Press any key to end trace session ");
getchar();
cleanup:
if (SessionHandle)
{
status = ControlTrace(SessionHandle, KERNEL_LOGGER_NAME, pSessionProperties, EVENT_TRACE_CONTROL_STOP);
if (ERROR_SUCCESS != status)
wprintf(L"ControlTrace(stop) failed with %lu\n", status);
}
else
{
/* 开启会话后,若不关闭,即使进程退出,依然会保持开启状态,单独关闭可使用如下方式 */
status = ControlTrace(NULL, KERNEL_LOGGER_NAME, pSessionProperties, EVENT_TRACE_CONTROL_STOP);
if (ERROR_SUCCESS != status)
wprintf(L"ControlTrace(stop) failed with %lu\n", status);
}
if (pSessionProperties)
free(pSessionProperties);
}
int _tmain(int argc, _TCHAR* argv[])
{
EventController();
//EventConsumer();
while (true)
{
Sleep(300000);
}
return 0;
}

运行后,当有数据来时就会进入我们设置的回调函数

此处我们大概知道了该软件的实现原理,剩下具体的对数据的内容的解析不再继续赘述,读者可以自行去研究,从这篇文章里我们知道了微软提供了一套内核事件诊断的函数方便我们去分析系统一些的性能,我们不光可以用这些函数去分析诊断系统,我们可以充分利用这些函数去实现一些我们想要的功能,大家可以自行去发挥。

转自:https://bbs.pediy.com/thread-218627.htm

原文地址:https://www.cnblogs.com/yilang/p/12148078.html

时间: 2024-08-29 09:48:12

Windows资源监视器软件的原理的相关文章

Windows文件监视器 1.0 绿色版

软件名称:软件名称: Windows文件监视器 软件语言: 简体中文 授权方式: 免费软件 运行环境: Win7 / Vista / Win2003 / WinXP / Win2008 软件大小: 176 KB 图片预览: 软件简介: 本程序可以对指定的某个盘符或某个目录进行监视,监视的内容包括任何文件及子文件夹的新建.删除.重命令.大小修改等等,并显示监视的结果 软件下载地址:电信下载 联通下载

【转】基于RSA算法实现软件注册码原理初讨

1 前言 目前,商用软件和共享软件绝大部份都是采用注册码授权的方式来保证软件本身不被盗用,以保证自身的利益.尽管很多常用的许多软件系统的某些版本已经被别人破解,但对于软件特殊行业而言,注册码授权的方式还是一种保护软件系统本身的一种有效的手段. 通常而言,注册码授权方式有以下几种方式: u  安装序列号方式:这是最为常用的方式,Mircosoft提供的产品(例如:Windows系列产品.Office系列产品等等)都是采用这种方式.通过一种复杂的算法生成安装序列号,在安装过程中,安装程序对用户输入的

Windows 性能监视器的基本指标(CPU,内存,硬盘参数)

转载:http://kms.lenovots.com/kb/article.php?id=7045 Windows 性能监视器的基本指标(CPU,内存,硬盘参数) 作为一个系统工程师来说,要看懂监控的数据至关重要,关系着优化和分析出现的问题,因此,今天给出Windows 性能监视器的一些基本指标(CPU,内存,硬盘参数),希望对大家将来优化和分析问题提供帮忙. Windows -Processor 指标名称 指标描述 指标范围 指标单位 CPU利用率(% Processor Time) % Pr

时序图与状态图(Rose) - Windows XP经典软件系列

最近开始了自己高级数据结构之旅,在这次旅行中,我将持续把一些高级的数据结构从理论到编码都过一遍,同时通过博客形式分享出来,希望大家指出不足之处! 二叉排序树是一种动态排序的数据结构,支持插入.删除.查找等操作,且平均时间复杂度为O(log(N)),但是普通二叉排序树不能保证树退化为一颗分支的情况,此时最坏情况下的时间复杂度为O(N).此时,平衡二叉树的产生了.平衡二叉树是一种动态调整平衡的数据结构,但理想的平衡二叉树很难,于是人们使用AVL.红黑树.Treap.伸展树等来替代平衡二叉树,这些数据

类图(Rose) - Windows XP经典软件系列

最近开始了自己高级数据结构之旅,在这次旅行中,我将持续把一些高级的数据结构从理论到编码都过一遍,同时通过博客形式分享出来,希望大家指出不足之处! 二叉排序树是一种动态排序的数据结构,支持插入.删除.查找等操作,且平均时间复杂度为O(log(N)),但是普通二叉排序树不能保证树退化为一颗分支的情况,此时最坏情况下的时间复杂度为O(N).此时,平衡二叉树的产生了.平衡二叉树是一种动态调整平衡的数据结构,但理想的平衡二叉树很难,于是人们使用AVL.红黑树.Treap.伸展树等来替代平衡二叉树,这些数据

Windows的条形码软件开发工具包Barcode Reader Toolkit for Windows介绍

Softek Barcode Reader Toolkit是一款支持Windows的软件开发工具包(SDK),使您的应用程序可以从图像中提取条形码信息.API(应用程序接口)可用在.net, java, com, ocx 和 windows dll工具包中.标准版支持一维和二维条形码.通过条形码的位置可分离文件. 具体功能: 通常,这款SDK用在扫描包含条形码文件的应用程序中.调用工具包中的功能,可提取图像中的条形码值,然后将这个值定义为数据库类中的关键词.需要从数码相机中检测图像条形码控件的应

Atitit Atitit.软件兼容性原理----------API兼容 Qa7

1. 兼容性的重要性与反面教材1 2. 提升兼容性的原则2 2.1. What 与how 分离2 2.2. 老人老办法,新人新办法,只新增,少修改,莫删除3 2.3. 计划赶不上变化,永远api修改也不可能整齐划一,反而带来不兼容的风险3 3. 把握API的生命周期andAPI分级3 4. 对兼容性保持友好的api设计方法3 4.1. 细粒度的方法3 4.2. Ioc容器动态配置3 4.3. 把你的method()视为全局global的,确保每一个方法都不重名尽可能..不要幻想有模块命名空间等,

解决windows server 2003在center中克隆提示无法找到windows资源

问题: 在center中克隆windows server2003的时候我们会遇到下面的问题,提示未在服务器上找到windows自定义资源 产生原因: 这是由于系统本身的原因,windows server 2008 以后的版本默认都把sysprep集成在了内核中,所以克隆的时候可以直接调用该程序,而windows server2003以前的版本默认没有该程序,所以在克隆的时候会提示没有在服务器上找到windows资源,其实就是没有找到sysprep这个程序. 解决办法: 我们手动把windows

文件操作 - Windows资源文件的读取

=============== Windows资源文件的读取 =============== Windows资源操作函数 12 LoadAccelerators 加载快捷键资源 14 LoadBitmap 加载位图资源 16 LoadCursor 加载光标资源 18 LoadIcon 加载图标资源 20 LoadMenu 加载菜单资源 22 LoadString 加载字符串资源 Windows资源操作函数 29 FindResource 从指定模块中加载指定名称.类型的资源 31 SizeofR