Windows资源监视器软件的原理
微軟給我們提供了一些很好的程序,比如資源監(jiān)視器,可以從這個(gè)軟件里獲取分析windows的自身的一些性能數(shù)據(jù),比如CPU、內(nèi)存、磁盤(pán)數(shù)據(jù)、文件讀寫(xiě)、進(jìn)程線程等,他具體怎么實(shí)現(xiàn)呢,今天這天文章就帶你去獲取其真實(shí)的原理。
1.分析
打開(kāi)windows任務(wù)欄管理器,在其性能選項(xiàng)里,可以看到性能監(jiān)控的一些機(jī)器性能圖表
這個(gè)只是一些概要數(shù)據(jù),如果要看詳細(xì)的內(nèi)容,可以點(diǎn)擊左下角的“打開(kāi)資源監(jiān)視器”,會(huì)自己開(kāi)啟一個(gè)進(jìn)程perfmon.exe的進(jìn)程,這個(gè)進(jìn)程界面會(huì)顯示詳細(xì)的資源信息
我們可以看到每個(gè)進(jìn)程打開(kāi)了什么文件、讀寫(xiě)了什么磁盤(pán)數(shù)據(jù)、以及訪問(wèn)了什么網(wǎng)絡(luò)的IP都有詳細(xì)的信息,這個(gè)進(jìn)程既沒(méi)有文件過(guò)濾驅(qū)動(dòng)也沒(méi)有網(wǎng)絡(luò)驅(qū)動(dòng)他是如何實(shí)現(xiàn)去獲取這些詳細(xì)的信息呢,下面我們來(lái)具體分析下。
打開(kāi)這個(gè)軟件所在的目錄,可以看到一些對(duì)應(yīng)的perfmon.exe 、perfnet.dll、perfDisk.dll、perfos.dll、perfpro.dll進(jìn)程和模塊
用IDA打開(kāi)perfmon.exe看看其進(jìn)程一些函數(shù)
也只是一些UI相關(guān)的函數(shù),說(shuō)明核心功能并不在這里exe里 ,在繼續(xù)換一個(gè),用IDA打開(kāi)perdisk.dll這個(gè)模塊
模塊里有一些比較明顯的函數(shù)CollectDiskObjectData、CollectPDiskObjectData、CollectLDiskObjectData等函數(shù),選擇一個(gè)函數(shù)用windbg調(diào)試器去下斷點(diǎn)
當(dāng)?shù)谝环胚^(guò)運(yùn)行時(shí),調(diào)試器立馬就停了下來(lái),看堆棧區(qū)域
大概是這樣的
#RetAddr:ArgstoChild:CallSite 0000007ffc`2d132060:ffffffff`feced30000000000`0000001000000000`0000001400000000`00000000:perfdisk!CollectDiskObjectData 0100007ffc`2d1316b5:00000000`00007f8800000000`0000000000000000`0000000000000000`00000000:ADVAPI32!QueryExtensibleData+0x540 0200007ffc`29a92a99:0000021e`67749c6600000000`000602ff000000fc`368ff72800007ffc`ffffffff:ADVAPI32!PerfRegQueryValue+0x325 0300007ffc`29a9204d:ffffffff`80000004000000fc`368ff7a40000021e`6b4904f0000000fc`368ff820:KERNELBASE!MapPredefinedHandleInternal+0x8e9 0400007ffc`25f063ec:ffffffff`800000040000021e`6b4904900000021e`00008000000000fc`368ff7a4:KERNELBASE!RegQueryValueExW+0xed 0500007ffc`25f056ad:0000021e`6b4904900000021e`6ad74c1000000000`0000800000000000`00000000:pdh!GetSystemPerfData+0x9c 0600007ffc`25f054c9:01d2e6b6`135f9140000000fc`368ff8b800000000`0000000001d2e673`053c5140:pdh!GetQueryPerfData+0xcd 0700007ffc`01548566:00000000`0000000000000000`0000000300000000`0000000000000000`000002b0:pdh!PdhCollectQueryData+0x59 0800007ffc`2ad58364:0000021e`6adc1b0000000000`0000000000000000`0000000000000000`00000000:wdc!WdcTraceControl::QueryThread+0x1a6 0900007ffc`2d2370d1:00000000`0000000000000000`0000000000000000`0000000000000000`00000000:KERNEL32!BaseThreadInitThunk+0x14 0a00000000`00000000:00000000`0000000000000000`0000000000000000`0000000000000000`00000000:ntdll!RtlUserThreadStart+0x21
堆棧看該函數(shù)被調(diào)用是從wdc!WdcTraceControl::QueryThread這個(gè)函數(shù)過(guò)來(lái)的,看樣子是一個(gè)單獨(dú)的數(shù)據(jù)線程,是wdc.dll這個(gè)模塊里的函數(shù),繼續(xù)用IDA打開(kāi)wdc這個(gè)模塊。
查看WdcTraceControl::QueryThread這個(gè)函數(shù)實(shí)現(xiàn),確實(shí)調(diào)用了一些監(jiān)控實(shí)例的Query方法,這里我們可以確認(rèn)wc.dll這個(gè)模塊是核心功能所在的模塊,現(xiàn)在可以分析下是怎么開(kāi)啟這個(gè)線程的,開(kāi)啟前做了哪些工作。
發(fā)現(xiàn)只有一處調(diào)用,就是WdcTraceControl::Start函數(shù)調(diào)用了這個(gè)函數(shù)開(kāi)啟線程
繼續(xù)往上翻閱WdcTraceControl::Start函數(shù)實(shí)現(xiàn)
有一個(gè)WdcTraceControl::TraceStart函數(shù),進(jìn)入該函數(shù)
發(fā)現(xiàn)該函數(shù)調(diào)用OpenTrace、StartTrace、EnableTraceEx、processTrace這些函數(shù),從EnableTraceEx的參數(shù)ThreadPoolGuid、PsProvGuid、DiskProvGuid、FileProvGuid、NetProvGuid可以判斷這些函數(shù)就是核心功能,查看微軟的CSDN終于發(fā)現(xiàn)了秘密,原來(lái)這些函數(shù)是微軟事件診斷函數(shù)(ETW),其中OpenTrace的里的有一個(gè)參數(shù)是事件的回掉接收函數(shù),我們看到的WdcTraceControl::CallbackEvent這個(gè)函數(shù)就是,下個(gè)斷點(diǎn),確實(shí)斷了下來(lái)
就是WdcTraceControl::TraceThread線程中的ProcessTrace函數(shù)處理獲取了內(nèi)核日志數(shù)據(jù)然后調(diào)用了設(shè)置的回調(diào)函數(shù)WdcTraceControl::CallbackEvent去處理,為了進(jìn)一步驗(yàn)證,翻閱該回調(diào)函數(shù)的實(shí)現(xiàn)
可以知道里面處理了各種過(guò)來(lái)的數(shù)據(jù)包括網(wǎng)絡(luò)、磁盤(pán)、cpu、內(nèi)存、線程、進(jìn)程日志信息,去寫(xiě)個(gè)demo實(shí)例驗(yàn)證我們的結(jié)果。
2.代碼demo
#include"stdafx.h"
#defineINITGUID//Includethis#definetouseSystemTraceControlGuidinEvntrace.h.
#include<Windows.h>
#include<wmistr.h>
#include<evntrace.h>
#include<evntcons.h>
#include<strsafe.h>
#pragmacomment(lib,"Advapi32.lib")
#defineLOGFILE_PATHL"kernellogfile.etl"
#defineETL_FILEL"G:\OpenSource\GitHub\WindowsSDK7-Samples\winbase\Eventing\EtwConsumer\Output\16.pdf.etl"
#define__REAL_TIME_MODE
/*不同類型的GUID,從MSDN手冊(cè)中找,固定的*/
DEFINE_GUID(/*3d6fa8d0-fe05-11d0-9dda-00c04fd7ba7c*/
ProcessGuid,
0x3d6fa8d0,
0xfe05,
0x11d0,
0x9d,0xda,0x00,0xc0,0x4f,0xd7,0xba,0x7c
);
ULONGWINAPIBufferCallback(__inPEVENT_TRACE_LOGFILELogFile)
{
printf("BufferCallback!
");
returnTRUE;
}
/*可以調(diào)用SetTraceCallback設(shè)置單獨(dú)事件GUID的回調(diào)函數(shù),即使如此,EventCallback仍然會(huì)收到所有的事件*/
VOIDWINAPIEventRecordCallback(__inPEVENT_RECORDEvent)
{
if(IsEqualGUID(Event->EventHeader.ProviderId,ProcessGuid))
{
/*需要解析數(shù)據(jù)格式*/
printf("EventRecordCallbackProcessGuid!
");
}
printf("EventRecordCallback!
");
}
VOIDWINAPIEventCallback(PEVENT_TRACEpEvent)
{
printf("EventCallback!
");
}
VOIDEventConsumer()
{
TRACEHANDLEhTrace=NULL;
EVENT_TRACE_LOGFILEtraceFile;
#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;
ULONGstatus=ProcessTrace(&hTrace,1,NULL,NULL);
}
voidEventController(void)
{
ULONGstatus=ERROR_SUCCESS;
TRACEHANDLESessionHandle=0;
EVENT_TRACE_PROPERTIES*pSessionProperties=NULL;
ULONGBufferSize=0;
BufferSize=sizeof(EVENT_TRACE_PROPERTIES)+sizeof(KERNEL_LOGGER_NAME)+sizeof(LOGFILE_PATH);
pSessionProperties=(EVENT_TRACE_PROPERTIES*)malloc(BufferSize);
if(NULL==pSessionProperties)
{
wprintf(L"Unabletoallocate%dbytesforpropertiesstructure.
",BufferSize);
gotocleanup;
}
ZeroMemory(pSessionProperties,BufferSize);
pSessionProperties->Wnode.BufferSize=BufferSize;
pSessionProperties->Wnode.Flags=WNODE_FLAG_TRACED_GUID;
pSessionProperties->Wnode.ClientContext=1;//QPCclockresolution
pSessionProperties->Wnode.Guid=SystemTraceControlGuid;
pSessionProperties->EnableFlags=EVENT_TRACE_FLAG_PROCESS;//關(guān)注事件
#ifdef__REAL_TIME_MODE
pSessionProperties->LogFileMode=EVENT_TRACE_REAL_TIME_MODE;//EVENT_TRACE_USE_PAGED_MEMORY該標(biāo)識(shí)在win7上會(huì)導(dǎo)致失敗
#else
pSessionProperties->LogFileMode=EVENT_TRACE_FILE_MODE_CIRCULAR;
#endif
pSessionProperties->MaximumFileSize=5;//5MB
pSessionProperties->LoggerNameOffset=sizeof(EVENT_TRACE_PROPERTIES);
pSessionProperties->LogFileNameOffset=sizeof(EVENT_TRACE_PROPERTIES)+sizeof(KERNEL_LOGGER_NAME);
#ifndef__REAL_TIME_MODE//也可在RealTime模式下開(kāi)啟,但是沒(méi)必要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"TheNTKernelLoggersessionisalreadyinuse.
");
else
wprintf(L"EnableTrace()failedwith%lu
",status);
gotocleanup;
}
EventConsumer();
wprintf(L"Pressanykeytoendtracesession");
getchar();
cleanup:
if(SessionHandle)
{
status=ControlTrace(SessionHandle,KERNEL_LOGGER_NAME,pSessionProperties,EVENT_TRACE_CONTROL_STOP);
if(ERROR_SUCCESS!=status)
wprintf(L"ControlTrace(stop)failedwith%lu
",status);
}
else
{
/*開(kāi)啟會(huì)話后,若不關(guān)閉,即使進(jìn)程退出,依然會(huì)保持開(kāi)啟狀態(tài),單獨(dú)關(guān)閉可使用如下方式*/
status=ControlTrace(NULL,KERNEL_LOGGER_NAME,pSessionProperties,EVENT_TRACE_CONTROL_STOP);
if(ERROR_SUCCESS!=status)
wprintf(L"ControlTrace(stop)failedwith%lu
",status);
}
if(pSessionProperties)
free(pSessionProperties);
}
int_tmain(intargc,_TCHAR*argv[])
{
EventController();
//EventConsumer();
while(true)
{
Sleep(300000);
}
return0;
}
運(yùn)行后,當(dāng)有數(shù)據(jù)來(lái)時(shí)就會(huì)進(jìn)入我們?cè)O(shè)置的回調(diào)函數(shù)
此處我們大概知道了該軟件的實(shí)現(xiàn)原理,剩下具體的對(duì)數(shù)據(jù)的內(nèi)容的解析不再繼續(xù)贅述,讀者可以自行去研究,從這篇文章里我們知道了微軟提供了一套內(nèi)核事件診斷的函數(shù)方便我們?nèi)シ治鱿到y(tǒng)一些的性能,我們不光可以用這些函數(shù)去分析診斷系統(tǒng),我們可以充分利用這些函數(shù)去實(shí)現(xiàn)一些我們想要的功能,大家可以自行去發(fā)揮。
轉(zhuǎn)自:https://bbs.pediy.com/thread-218627.htm
總結(jié)
以上是生活随笔為你收集整理的Windows资源监视器软件的原理的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 如何理性看待中国留学生对广岛原爆的评价?
- 下一篇: BPE特性