성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] VT sequences to "CONOUT$" vs. STD_O...
[정성태] NetCoreDbg is a managed code debugg...
[정성태] Evaluating tail call elimination in...
[정성태] What’s new in System.Text.Json in ....
[정성태] What's new in .NET 9: Cryptography ...
[정성태] 아... 제시해 주신 "https://akrzemi1.wordp...
[정성태] 다시 질문을 정리할 필요가 있을 것 같습니다. 제가 본문에...
[이승준] 완전히 잘못 짚었습니다. 댓글 지우고 싶네요. 검색을 해보...
[정성태] 우선 답글 감사합니다. ^^ 그런데, 사실 저 예제는 (g...
[이승준] 수정이 안되어서... byteArray는 BYTE* 타입입니다...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <h1 style='font-family: Malgun Gothic, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>C# - ETW 관련 Win32 API 사용 예제 코드 (2) NT Kernel Logger</h1> <p> 지난 글에 이어,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > C# - ETW 관련 Win32 API 사용 예제 코드 (1) ; <a target='tab' href='https://www.sysnet.pe.kr/2/0/12292'>https://www.sysnet.pe.kr/2/0/12292</a> </pre> <br /> 이번에는 ETW Consumer를 Win32 API를 이용해 작성해 보겠습니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> 우선 세션을 먼저 생성해야 하는데 이를 위해 StartTrace API를 사용할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > string sessionName = NativeMethods.KERNEL_LOGGER_NAME; // KERNEL_LOGGER_NAME == "NT Kernel Logger" EventTraceProperties prop = new EventTraceProperties(true, sessionName, NativeMethods.SystemTraceControlGuid); // SystemTraceControlGuid == 9e814aad-3204-11d2-9a82-006008a86939 <span style='color: blue; font-weight: bold'>result = NativeMethods.<a target='tab' href='https://learn.microsoft.com/en-us/windows/win32/api/evntrace/nf-evntrace-starttracea'>StartTrace</a>(out sessionHandle, sessionName, ref prop);</span> </pre> <br /> 위의 코드는 (<a target='tab' href='https://www.sysnet.pe.kr/2/0/10909'>xperf -providers 출력 결과</a>의) ETW Provider 중 "Windows Kernel Trace" (9e814aad-3204-11d2-9a82-006008a86939)를 사용하는 코드로 예를 든 것입니다. 주의할 것은, SystemTraceControlGuid의 경우 반드시 세션 이름을 "NT Kernel Logger"로 해야 한다는 건데, 이런 사실은 다음의 글을 통해 알게 되었습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > THE WORST API EVER MADE ; <a target='tab' href='https://caseymuratori.com/blog_0025'>https://caseymuratori.com/blog_0025</a> Configuring and Starting the NT Kernel Logger Session ; <a target='tab' href='https://learn.microsoft.com/en-us/windows/win32/etw/configuring-and-starting-the-nt-kernel-logger-session'>https://learn.microsoft.com/en-us/windows/win32/etw/configuring-and-starting-the-nt-kernel-logger-session</a> </pre> <br /> (제목에서 볼 수 있는 것처럼, 저 개인적으로도 ETW 관련 API의 이름이나 사용법이 체계적이지 않음을 100% 공감합니다. ^^;)<br /> <br /> 저렇게 세션을 생성했으면, (이전에 StartTrace라는 이름의 API를 호출했음에도) "Trace"를 "시작"하기 위해 OpenTrace API를 호출해야 합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > EventTraceLogfile logFile = new EventTraceLogfile(); logFile.LoggerName = sessionName; <span style='color: blue; font-weight: bold'>logFile.EventRecordCallback = EventRecordCallback;</span> logFile.ProcessTraceMode = NativeMethods.PROCESS_TRACE_MODE_EVENT_RECORD | NativeMethods.PROCESS_TRACE_MODE_REAL_TIME | NativeMethods.PROCESS_TRACE_MODE_RAW_TIMESTAMP; <span style='color: blue; font-weight: bold'>traceHandle = NativeMethods.<a target='tab' href='https://learn.microsoft.com/en-us/windows/win32/api/evntrace/nf-evntrace-opentracew'>OpenTrace</a>(ref logFile);</span> static private void EventRecordCallback([In] ref EventRecord eventRecord) { Console.WriteLine(DateTime.Now + ": " + eventRecord.EventHeader.ProcessId); } </pre> <br /> 위의 코드는 이벤트가 발생했을 시 콜백을 실행하라고 등록하는데 원한다면 파일로도 지정할 수 있습니다. 하지만, 이렇게 등록했다고 해서 trace로 인한 콜백이 호출되는 것은 아닙니다. 콜백이 호출되려면 이후 <a target='tab' href='https://learn.microsoft.com/en-us/windows/win32/api/evntrace/nf-evntrace-processtrace'>ProcessTrace API</a>를 호출해야 하는데, 이 함수는 호출 스레드를 블록시키기 때문에 보통 새로운 스레드를 생성해 호출하는 식으로 구현합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > new Thread((ThreadStart)( () => { ProcessTrace(traceHandle); })).Start(); Console.WriteLine("Press ENTER key to exit..."); Console.ReadLine(); public static int ProcessTrace(ulong traceHandle) { ulong[] handles = { traceHandle }; <span style='color: blue; font-weight: bold'>int result = NativeMethods.ProcessTrace(handles, (uint)handles.Length, IntPtr.Zero, IntPtr.Zero);</span> return result; } </pre> <br /> 마지막으로, ProcessTrace의 blocking 상태를 해제하려면 CloseTrace를 호출하고,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > NativeMethods.<a target='tab' href='https://learn.microsoft.com/en-us/windows/win32/api/evntrace/nf-evntrace-closetrace'>CloseTrace</a>(traceHandle); </pre> <br /> 세션까지 완전히 종료하려면 ControlTrace 호출로 마무리를 합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // <a target='tab' href='https://www.sysnet.pe.kr/2/0/12292#control_trace'>https://www.sysnet.pe.kr/2/0/12292#control_trace</a> EtwInterop.CloseActiveSession(sessionName); </pre> <br /> <hr style='width: 50%' /><br /> <br /> "Windows Kernel Trace"의 경우, 기본적인 사용법은 위와 같은 순서로 구현할 수 있지만 한 가지 설명해야 할 것이 더 있습니다. 이에 대해서는 EVENT_TRACE_PROPERTIES 구조체 문서를 확인해야 하는데,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > EVENT_TRACE_PROPERTIES structure ; <a target='tab' href='https://learn.microsoft.com/en-us/windows/win32/api/evntrace/ns-evntrace-event_trace_properties'>https://learn.microsoft.com/en-us/windows/win32/api/evntrace/ns-evntrace-event_trace_properties</a> </pre> <br /> 위의 글에 보면, "system logger" 유형인 경우 "EnableFlags"에 설정할 수 있는 값들을 설명하고 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // // Enable flags for Kernel Events // #define EVENT_TRACE_FLAG_PROCESS 0x00000001 // process start & end #define EVENT_TRACE_FLAG_THREAD 0x00000002 // thread start & end #define EVENT_TRACE_FLAG_IMAGE_LOAD 0x00000004 // image load #define EVENT_TRACE_FLAG_DISK_IO 0x00000100 // physical disk IO #define EVENT_TRACE_FLAG_DISK_FILE_IO 0x00000200 // requires disk IO #define EVENT_TRACE_FLAG_MEMORY_PAGE_FAULTS 0x00001000 // all page faults #define EVENT_TRACE_FLAG_MEMORY_HARD_FAULTS 0x00002000 // hard faults only #define EVENT_TRACE_FLAG_NETWORK_TCPIP 0x00010000 // tcpip send & receive #define EVENT_TRACE_FLAG_REGISTRY 0x00020000 // registry calls #define EVENT_TRACE_FLAG_DBGPRINT 0x00040000 // DbgPrint(ex) Calls // // Enable flags for Kernel Events on Vista and above // #define EVENT_TRACE_FLAG_PROCESS_COUNTERS 0x00000008 // process perf counters #define EVENT_TRACE_FLAG_CSWITCH 0x00000010 // context switches #define EVENT_TRACE_FLAG_DPC 0x00000020 // deferred procedure calls #define EVENT_TRACE_FLAG_INTERRUPT 0x00000040 // interrupts #define EVENT_TRACE_FLAG_SYSTEMCALL 0x00000080 // system calls #define EVENT_TRACE_FLAG_DISK_IO_INIT 0x00000400 // physical disk IO initiation #define EVENT_TRACE_FLAG_ALPC 0x00100000 // ALPC traces #define EVENT_TRACE_FLAG_SPLIT_IO 0x00200000 // split io traces (VolumeManager) #define EVENT_TRACE_FLAG_DRIVER 0x00800000 // driver delays #define EVENT_TRACE_FLAG_PROFILE 0x01000000 // sample based profiling #define EVENT_TRACE_FLAG_FILE_IO 0x02000000 // file IO #define EVENT_TRACE_FLAG_FILE_IO_INIT 0x04000000 // file IO initiation // // Enable flags for Kernel Events on Win7 and above // #define EVENT_TRACE_FLAG_DISPATCHER 0x00000800 // scheduler (ReadyThread) #define EVENT_TRACE_FLAG_VIRTUAL_ALLOC 0x00004000 // VM operations // // Enable flags for Kernel Events on Win8 and above // #define EVENT_TRACE_FLAG_VAMAP 0x00008000 // map/unmap (excluding images) #define EVENT_TRACE_FLAG_NO_SYSCONFIG 0x10000000 // Do not do sys config rundown // // Enable flags for Kernel Events on Threshold and above // #define EVENT_TRACE_FLAG_JOB 0x00080000 // job start & end #define EVENT_TRACE_FLAG_DEBUG_EVENTS 0x00400000 // debugger events (break/continue/...) </pre> <br /> 예를 들어, 이 중에서 EVENT_TRACE_FLAG_PROCESS 플래그는 프로세스의 생성/종료에 대한 이벤트를 받을 수 있게 합니다. 따라서, 다음과 같이 설정해 주면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > EventTraceProperties prop = new EventTraceProperties(true, sessionName, NativeMethods.SystemTraceControlGuid); <span style='color: blue; font-weight: bold'>prop.SetFlags(NativeMethods.EVENT_TRACE_FLAG_PROCESS);</span> result = NativeMethods.StartTrace(out sessionHandle, sessionName, ref prop); </pre> <br /> 이후 (EXE) 프로세스 생성/종료마다 이벤트 콜백 함수가 실행됩니다.<br /> <br /> (<a target='tab' href='https://www.sysnet.pe.kr/bbs/DownloadAttachment.aspx?fid=1623&boardid=331301885'>첨부 파일은 이 글의 예제 코드를 포함</a>합니다.)<br /> <br /> <hr style='width: 50%' /><br /> <br /> 참고로 아래의 문서에도 나오지만,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Controlling Event Tracing Sessions ; <a target='tab' href='https://learn.microsoft.com/en-us/windows/win32/etw/controlling-event-tracing-sessions'>https://learn.microsoft.com/en-us/windows/win32/etw/controlling-event-tracing-sessions</a> </pre> <br /> ETW 세션을 다루는 방식이 여러 가지이므로 자신이 사용하려는 Provider에 따라 저 문서를 보고 어느 유형에 속하는지 선택해 코딩을 해야 합니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> 이 글에서 EVENT_TRACE_FLAG_PROCESS를 설정한 "Windows Kernel Trace" 동작은 지난 글에서 설명한,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > C# - 특정 EXE 프로세스를 종료시킨 EXE를 찾아내는 방법 ; <a target='tab' href='https://www.sysnet.pe.kr/2/0/11172'>https://www.sysnet.pe.kr/2/0/11172</a> </pre> <br /> "Microsoft-Windows-Kernel-Audit-API-Calls" ETW provider를 통해서도 유사하게 구현할 수 있습니다. 이에 대해서는 다음번 글에서 살펴보겠습니다.<br /> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
1533
(왼쪽의 숫자를 입력해야 합니다.)