트러블슈팅/Windbg, Debugging

[ProcMon] ProcessMonitor 노하우, 내가 사용하는 어플리케이션에서 디버깅 위치 잡아서 Procmon에 인젝션하기

TheShield 2023. 2. 5. 21:31
반응형

개발을 하다보면 다음의 상황이 벌어지곤 한다.

 

1. 파일을 열거나 레지스트리를 여는 등 시스템 call이 들어가는 부분에 문제가 생겨서

파일 여는 부분이 실패하거나 레지스트리 쓰기가 실패하거나, 네트워크가 차단되는 등

 

'의심 가는 부분'이 분명히 있는데, 이걸 찾으려고 procmon을 이용한다.

 

2. 쭉쭉쭉쭉 리스트가 나오는데, 문제는

과연 내 프로그램 상에서 [어디에서] 막혔는지 찾으려면

 

저 procmon의 로그에서 나의 프로그램의 디버깅 위치가 나와야 한다.

 

[대부분은] 대충 시간을 맞춰보거나

access denied 등을 찾아본다. 얼추 맞는 걸 찾아본다.

 

여기에 또 한가지의 노하우가 있는데,

A라는 정상 흐름과 B라는 비정상 흐름이 있다면

똑같이 실행시켜본 후 diff를 떠보면 procmon의 로그 파일 끼리 diff해서

어떤 api에서 문제가 생기는지 찾을 수 있다. 

 

A: OPEN FILE OPEN FILE OPEN FILE

B: OPEN FILE OPEN FILE FAIL, OPEN FILE

 

이러면 딱 나오지 않는가?

 

다시 본문으로 돌아가서, 

 

과연 내 프로그램의 [어디에서] 시스템 콜이 막혔을 까 찾는 걸

과연 시간의 흐름에만 맡겨야 하는가?

 

예를 들어 10:45 경에 문제가 생기고 내 프로그램의 전용 로그에서 찾아서

PROCMON과 맞춰보는 건 약간 뭔가 대충스럽지 않은가?

 

이럴 때 예전에 Windows SysInternals의 책과 Procmon의 도움말에서 본 내용 중에

도움이 되는 내용이 있다.

 

바로 내 응용 혹은 커널에서 (로우~ 하이 레벨까지 모두 접근 가능하다)

직접 procmon에 콜해서 시작과 끝을 호출하는 것이다.

이걸 procmon에선 인젝션이라 표현했는데

 

다음과 같은 것이다. 

 

내 프로그램 상에서 문제가 생길만한 지점 start ()

 

procmon의 로그들

....

.....

....

 

내 프로그램 상에서 문제가 생길만한 지점 end()

 

이렇게 지정하면 ,

 

최소한 어디에서 문제가 생기고

어떤 시스템 call 들의 일련의 문제가 생기는지 알 수 있지 않을까?

 

방법은 다음과 같다.

1. process monitor help에서 제공하는 다음의 코드를 

필요시마다 (start, end)에 콜해준다.

 

Injecting Application Debug Messages
If you are an application developer, it might be useful to include your own debug output in Process Monitor's event stream so that you can better correlate application operations with other events. Process Monitor allows unprivileged applications to inject wide-character strings of up to 2048 characters in length. The code sample below shows how to open the Process Monitor debugging interface and write messages to the event stream. The strings do not need to be null-terminated, though the one in the example is. The code sample below demonstrates how to generate Process Monitor debug output. John Robbins has also made helper classes you can use in your native or managed application to easily add support, which you can download here.

Note that you must show Profiling events, which are filtered by the default filter configuration, to see these events.

#include <windows.h>
#include <tchar.h>
#include <stdio.h>

#define FILE_DEVICE_PROCMON_LOG 0x00009535
#define IOCTL_EXTERNAL_LOG_DEBUGOUT (ULONG) CTL_CODE( FILE_DEVICE_PROCMON_LOG, 0x81, METHOD_BUFFERED, FILE_WRITE_ACCESS )

int main()
{

HANDLE hDevice = CreateFile( L"\\\\.\\Global\\ProcmonDebugLogger", GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );

if ( hDevice != INVALID_HANDLE_VALUE ) {

WCHAR text[] = L"Debug out";

DWORD textlen = (wcslen(text)+1) *sizeof(WCHAR);
DWORD nb = 0;

BOOL ok = DeviceIoControl( hDevice, IOCTL_EXTERNAL_LOG_DEBUGOUT, text, textlen, NULL, 0, &nb, NULL );

if ( ok ) {

printf( "wrote debug output message\n" );

} else {

printf( "error 0x%x\n", GetLastError() );

}

CloseHandle( hDevice );

} else {

printf( "error %d opening Process Monitor\n", GetLastError() );

}

return 0;

}

 

 

2.

맨 오른 쪽의 profile을 켜준다. (포함해준다.)

 

3. 그리고 전체 로그에서 위에 명시한대로,

내 응용 프로그램에서 호출한 [로그]의 내용의 사이에서 호출된

procmon의 system call 들을 살펴본다. 

 

 

이걸 예전에 알았으면 시간 맞춰본다고 찾고

 duration 찾아보고 이런 시간 낭비를 안했을 것이다.

 

이걸 어떻게 찾았냐고?

심심해서 sysinternals의 모든 도움말을 다 읽어보다 찾게 되었다.

 

모든 기본은 [도움말]에 있다.

 

 

반응형