首发于freebuf :  http://www.freebuf.com/column/137615.html

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;
}

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

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

Windows资源监视器软件的原理相关推荐

  1. 如何打开Windows7和Windows server 2008 R2的资源监视器

    Windows资源监视器是一个MMC管理单元,它楚一个可以帮助用户分析系统性能的工具.通过它可以实时监控计箅机系统资源的使用情况,可以随时了解当前计算机的运行情况.如哪些应用使汁算机变得缓慢,哪些操作 ...

  2. Windows Mobile手机软件安装卸载方法

    Windows Mobile手机软件安装卸载方法 智能手机功能强大,最重要的一方面就是它们可以反复的安装软件游戏以及主题等.以下罗列了智能手机上常见的几种格式软件的安装以及卸载方法. 软件.游戏的安装 ...

  3. Atitit.软件兼容性原理与实践 v3 q326.docx

    Atitit.软件兼容性原理与实践 v3 q326.docx 1. 架构兼容性1 2. Api兼容性1 2.1. 新api  vs  修改旧的api1 3. Web方面的兼容性(js,html)1 3 ...

  4. windows 系统监视器_使用Windows 7中的可靠性监视器对计算机问题进行故障排除

    windows 系统监视器 Windows Vista introduced us to the Reliability and Performance Monitor utility to help ...

  5. java实现资源监视器_实现Java监视的12个步骤程序存在缺陷

    java实现资源监视器 Java监视的当前状态最大的问题是什么? 生产中的错误很像喝醉的短信. 您只有在事情已经发生之后才意识到出了点问题. 发短信日志通常比应用程序错误日志更有趣,但是--两者可能同 ...

  6. (转)Windows 性能监视器工具-perfmon

    Windows 性能监视器工具 如果需要在一台计算机上监视多个 Report Server 实例,可以同时或单独监视这些实例.选择要包括的实例是计数器添加过程的一部分.有关使用 Windows 附带的 ...

  7. [转]Windows 性能监视器工具-perfmon

    2019独角兽企业重金招聘Python工程师标准>>> Windows 性能监视器工具 如果需要在一台计算机上监视多个 Report Server 实例,可以同时或单独监视这些实例. ...

  8. Windows常用必备软件整理,太全了,值得收藏

    目录 1.Office系列 2.杀毒软件 3.视频播放和视频处理 4.音乐播放 5.压缩解压 6.输入法 7.PDF阅读软件 8.文件加密 9.网盘 10.社交聊天 11.日常办公软件 ‍12.图片/ ...

  9. Python使用psutil的电脑资源监控软件

    前言 心血来潮想写一个电脑资源使用情况的监控程序 环境 windows10 python3.6.4 方法 安装psutil模块.打开cmd pip install psutil psutil模块使用方 ...

最新文章

  1. C语言:十六进制(HEX)和浮点类型(float、double)转换
  2. String常用方法总结
  3. 并发的发展历史-线程的出现
  4. 计算机毕业设计答辩慌?软工本科 Java EE 毕设项目答辩问题、答案汇总指南奉上
  5. MYSQL 10038 服务启动不起来
  6. Music 环形界面的算法记录
  7. python动态属性_Python进阶之@property动态属性的实现
  8. Python build-in数据类型之字符串str (一)
  9. ESP32利用百度智能云实现图像识别 文字识别
  10. (C语言实现)栈求表达式的值(实数范围内)
  11. 百度地图批量精度和维度Java,关于百度地图API批量转换成坐标的方法
  12. 图形学---中点画线法---opengl中实现
  13. the mid-autumn festival
  14. oracle 手工创建数据库
  15. c语言中if( k1)的含义,C语言:我的按键程序K1键按下没有反应,其他两个都有反应...
  16. 三步掩模行业调研报告 - 市场现状分析与发展前景预测
  17. [译] 用于 iOS 的 ML Kit 教程:识别图像中的文字
  18. 【数据分析】使用numpy实现多项式的求导以及可视化
  19. 如何让提高网站访问速度
  20. 计算机办公软件应用实训,计算机专业职业教育实训系列教材:Office 2007办公软件实训教程...

热门文章

  1. 夏普打印机卡纸后出现 错误代码h5-01的清除方法
  2. 公共关系礼仪实务章节测试题——公共关系概述(三)
  3. matlab中单独存图_[转载]matlab中保存图片的方法
  4. laravel 服务容器,容器概念
  5. 智慧路灯地方标准:“江苏省城市照明智慧灯杆建设指南”发布实施
  6. ESP32的蓝牙架构你真的了解吗?来,蓝牙博主给你安排~
  7. kmalloc使用不当导致内存分配失败问题
  8. 策划经验分享——常用软件篇
  9. fluke福禄克8000|8508A|8808A|8845A|8846A数字万用表软件NS-Multimeter
  10. python2 python3 通信_基于Python的串口通信(2)