성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] 아쉽게도, 커뮤니티는 아니고 개인 블로그입니다. ^^
[정성태] 질문이 잘 이해가 안 됩니다. 우선, 해당 소스코드에서 ILis...
[양승조
] var대신 dinamic으로 선언해서 해결은 했습니다. 맞는 해...
[양승조
] 또 막혔습니다. ㅠㅠ var list = props[i].Ge...
[양승조
] 아. 감사합니다. 어제는 안됐던것 같은데....정신을 차려야겠네...
[정성태] "props[i].GetValue(props[i])" 코드에서 ...
[정성태] 저렇게 조각 코드 말고, 실제로 재현이 되는 예제 프로젝트를 압...
[정성태] Modules 창(Ctrl+Shift+U)을 띄워서, 해당 Op...
[정성태] 만드실 수 있습니다. 단지, Unity 엔진 내의 스크립트와 W...
[공진영] 안녕하세요 좋은글 감사합니다. 현재 제가 wpf로 관제 모...
글쓰기
제목
이름
암호
전자우편
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# - 프로세스의 모든 핸들을 열람</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# - (핸들을 이용하여) 모든 열린 파일을 열람 ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/1338'>http://www.sysnet.pe.kr/2/0/1338</a> C# - 닷넷에서 프로세스가 열고 있는 파일 목록을 구하는 방법 ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/10833'>http://www.sysnet.pe.kr/2/0/10833</a> </pre> <br /> 위의 코드에서 걸리는 점이 있다면, 포인터에 대해 직접 offset 값을 취해 정보를 얻는다는 것입니다. 그런데 최근에 다음의 글을 읽게 되었는데,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Reversing Windows Internals (Part 1) - Digging Into Handles, Callbacks & ObjectTypes ; <a target='tab' href='https://rayanfam.com/topics/reversing-windows-internals-part1/'>https://rayanfam.com/topics/reversing-windows-internals-part1/</a> </pre> <br /> 저 글에서 소개한 소스 코드를 보면 정식적인 구조체를 이용해 해결하고 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > SinaKarvandi/Process-Magics ; <a target='tab' href='https://github.com/SinaKarvandi/Process-Magics'>https://github.com/SinaKarvandi/Process-Magics</a> Process-Magics/EnumAllHandles/EnumAllHandles/ ; <a target='tab' href='https://github.com/SinaKarvandi/Process-Magics/tree/master/EnumAllHandles/EnumAllHandles'>https://github.com/SinaKarvandi/Process-Magics/tree/master/EnumAllHandles/EnumAllHandles</a> </pre> <br /> 이참에, 찾아 보니 그런대로 이미 구조체들이 공식 문서화된 것들이 있습니다. ^^<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > NtQueryObject function (winternl.h) ; <a target='tab' href='https://learn.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntqueryobject'>https://learn.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntqueryobject</a> PUBLIC_OBJECT_TYPE_INFORMATION structure (ntifs.h) ; <a target='tab' href='https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/ns-ntifs-__public_object_type_information'>https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/ns-ntifs-__public_object_type_information</a> typedef struct _PUBLIC_OBJECT_BASIC_INFORMATION { ULONG Attributes; ACCESS_MASK GrantedAccess; ULONG HandleCount; ULONG PointerCount; ULONG Reserved[10]; // reserved for internal use } PUBLIC_OBJECT_BASIC_INFORMATION, *PPUBLIC_OBJECT_BASIC_INFORMATION; PUBLIC_OBJECT_TYPE_INFORMATION structure (ntifs.h) ; <a target='tab' href='https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/ns-ntifs-__public_object_type_information'>https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/ns-ntifs-__public_object_type_information</a> typedef struct __PUBLIC_OBJECT_TYPE_INFORMATION { UNICODE_STRING TypeName; ULONG Reserved [22]; // reserved for internal use } PUBLIC_OBJECT_TYPE_INFORMATION, *PPUBLIC_OBJECT_TYPE_INFORMATION; ObQueryNameString function - ntifs.h (include FltKernel.h, Ntifs.h) ; <a target='tab' href='https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-obquerynamestring'>https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-obquerynamestring</a> typedef struct _OBJECT_NAME_INFORMATION { UNICODE_STRING Name; } OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION; </pre> <br /> 한 가지 아쉬운 점은, NtQuerySystemInformation 함수를 통해 모든 핸들 정보를 구하는 SystemHandleInformation 관련 구조체는 (사실상 documented에 가깝지만 ^^;) 여전히 undocumented 상태라는 점입니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> 그런데, 이 코드를 실행해 보면 dropbox가 설치된 컴퓨터에서 다음의 코드를 실행 시 hang 현상이 발생합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // GetHandleName 함수 while (NtQueryObject(*DUP_HANDLE, ObjectNameInformation, OBJECT_NAME, GuessSize, &RequiredSize) == STATUS_INFO_LENGTH_MISMATCH) </pre> <br /> 문제가 되는 핸들을 알아내 Process Explorer에서 살펴보면 항상 다음의 Handle에서 멈추는 것을 확인할 수 있는데,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Type: File Name: \Device\NamedPipe\DropboxDataPipe </pre> <br /> 이 외에도 몇몇 Handle에서 멈춤 현상이 동일하게 발생합니다. 그때마다 "DropboxDataPipe"와 동일한 것은 해당 핸들의 "속성" 창으로 보안 정보를 보려고 했을 때,<br /> <br /> <img alt='handle_enum_1.png' src='/SysWebRes/bbs/handle_enum_1.png' /><br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > The requested security information is either unavailable or can't be displayed. </pre> <br /> 위와 같이 조회가 안 되지만, 저렇게 보안 정보가 안 보이는 것이라고 해도 모든 핸들의 정보가 NtQueryObject에서 hang 현상이 발생하지는 않습니다. 예를 들어, "\Device\CNG"가 예외인 경우였습니다.<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;' > MPC-HC causes a freeze ; <a target='tab' href='https://github.com/erengy/taiga/issues/270'>https://github.com/erengy/taiga/issues/270</a> </pre> <br /> 이런 글이 나오고 그런 현상을 예외로 걸러내기 위해 다음과 같은 조건을 포함하고 있습니다.<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://github.com/tamentis/psutil/blob/master/psutil/arch/mswindows/process_handles.c'>https://github.com/tamentis/psutil/blob/master/psutil/arch/mswindows/process_handles.c</a> // Skip access codes that can cause NtDuplicateObject() or NtQueryObject() // to hang if (<span style='color: blue; font-weight: bold'>handle.GrantedAccess == 0x00100000 || handle.GrantedAccess == 0x00120189 || handle.GrantedAccess == 0x0012019f || handle.GrantedAccess == 0x001a019f || handle.GrantedAccess == 0x0012008D</span>) continue; // 또는, // <a target='tab' href='https://github.com/erengy/anisthesia/blob/master/src/win/open_files.cpp'>https://github.com/erengy/anisthesia/blob/master/src/win/open_files.cpp</a> if (!(access_mask & FILE_READ_DATA)) return false; // We further assume that media players do not have any kind of write access // to video files: if (<span style='color: blue; font-weight: bold'>(access_mask & FILE_APPEND_DATA) || (access_mask & FILE_WRITE_EA) || (access_mask & FILE_WRITE_ATTRIBUTES)</span>) { return false; } </pre> <br /> 문제는, 저게 요행히 맞을 수는 있어도 GrantedAccess/access_mask 값이 hang 현상과 직접적인 연관은 없다는 점입니다. 게다가 hang이 발생했던 "\Device\NamedPipe\DropboxDataPipe"의 경우 제 시스템에서는 GrantedAccess 값이 0x120089였고, 그와 동일한 GrantedAccess 값을 가지고 있던 다른 Handle(예, "\Device\DeviceApi")에 대해서는 NtQueryObject 조회가 정상적으로 실행되었습니다.<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;' > C# (CSharp) SYSTEM_HANDLE_INFORMATION Examples ; <a target='tab' href='https://csharp.hotexamples.com/examples/-/SYSTEM_HANDLE_INFORMATION/-/php-system_handle_information-class-examples.html'>https://csharp.hotexamples.com/examples/-/SYSTEM_HANDLE_INFORMATION/-/php-system_handle_information-class-examples.html</a> </pre> <br /> 이렇게도 비교하는데,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > //skip special NamedPipe handle (this may cause hang up with NtQueryObject function) if (targetHandleInfo.AccessMask.ToInt64() == 0x0012019F) { return String.Empty; } </pre> <br /> 그나마 주석에서 얻은 한 가지 힌트라면 "특별한 NamedPipe"라고 가정을 하지만 그렇다고 해서 크게 도움이 되지는 않습니다. 왜냐하면 AccessMark == 0x0012019F를 가진 핸들 중에서 그것이 "File"인지, "특별한 NamedPipe"인지 구별할 수 있는 방법이 없기 때문입니다.<br /> <br /> 반면, "<a target='tab' href='https://learn.microsoft.com/en-us/sysinternals/downloads/process-explorer'>Process Explorer</a>"는 hang 현상 없이 정확히 해당 정보를 가져오는 걸로 봐서 아마도 Kernel driver 영역에서나 가능하지 않을까 예상해 봅니다. (혹시 User 모드에서 해당 방법을 아시는 분은 덧글 부탁드립니다. ^^)<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;' > C# - (핸들을 이용하여) 모든 열린 파일을 열람 ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/1338'>http://www.sysnet.pe.kr/2/0/1338</a> </pre> <br /> 코드에서는 이를 회피하기 위해 별도의 스레드에 작업을 맡긴 후 EventWaitHandle.WaitOne(timeout)을 호출하는 방식으로 해결하고 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > private static bool GetFileNameFromHandle(IntPtr handle, out string fileName, int wait) { using (FileNameFromHandleState f = new FileNameFromHandleState(handle)) { ThreadPool.QueueUserWorkItem(new WaitCallback(GetFileNameFromHandle), f); if (f.WaitOne(wait)) { fileName = f.FileName; return f.RetValue; } else { fileName = string.Empty; return false; } } } </pre> <br /> 심지어 ProcessHacker 소스 코드에서도,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > processhacker/phlib/hndlinfo.c ; <a target='tab' href='https://github.com/processhacker/processhacker/blob/master/phlib/hndlinfo.c'>https://github.com/processhacker/processhacker/blob/master/phlib/hndlinfo.c</a> </pre> <br /> PhpGetObjectName에 보면, PhCallNtQueryObjectWithTimeout과 NtQueryObject를 섞어 쓰고 있습니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> 이렇게 해서 소스 코드를 "<a target='tab' href='http://www.sysnet.pe.kr/2/0/1338'>C# - (핸들을 이용하여) 모든 열린 파일을 열람</a>" 글에서 사용했던 것에 비해 좀 더 개선을 했습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > DotNetSamples/WinForms/EnumHandles/ ; <a target='tab' href='https://github.com/stjeong/DotNetSamples/tree/master/WinForms/EnumHandles'>https://github.com/stjeong/DotNetSamples/tree/master/WinForms/EnumHandles</a> </pre> <br /> 그래서 새롭게 변경한 소스 코드를 활용하면 다음과 같은 식으로 원하는 프로세스의 핸들을 열람할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > using (WindowsHandleInfo whi = new WindowsHandleInfo()) { for (int i = 0; i < whi.HandleCount; i++) { SYSTEM_HANDLE_ENTRY she = whi[i]; if (she.OwnerPid != processId) { continue; } string objName = she.GetName(out string handleTypeName); Console.WriteLine($"{handleTypeName}: {objName}"); } } </pre> <br /> 다음 화면은 Process Explorer의 출력 결과(왼쪽)와 첨부한 예제 프로젝트의 실행 결과를 보여줍니다.<br /> <br /> <img onclick='toggle_img(this)' class='imgView' alt='handle_enum_2.png' src='/SysWebRes/bbs/handle_enum_2.png' /><br /> <br /> 속도는 Process Explorer보다 느리지만, 상황에 따라 쓸만할 것입니다. ^^<br /> <br /> <hr style='width: 50%' /><br /> <br /> 당연한 이야기겠지만, GetFileNameFromHandle에서 hang 현상을 피하기 위해 ThreadPool.QueueUserWorkItem을 사용함으로써 만약 저 기능을 계속해서 호출하면 "hang 현상에 걸린 스레드"가 지속적으로 누적될 수 있습니다. 다음은 Visual Studio의 디버그 모드로 해당 스레드들이 누적되어 있는 것을 보여줍니다.<br /> <br /> <img onclick='toggle_img(this)' class='imgView' alt='handle_enum_3.png' src='/SysWebRes/bbs/handle_enum_3.png' /><br /> </p><br /> <br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
1959
(왼쪽의 숫자를 입력해야 합니다.)