|
얼덜 님이 쓰신 글 :
: 안녕하세요 프로세스를 서스펜드 하다가
:
: 의문점이 생겨서 질문드립니다.
:
: 예전에는 프로세스랑 쓰레드 둘다 스냅샷을 찍어서 pid 동일한거 찾은다음
:
: 쓰레드를 SuspendThread 시켰는데 이 방식이 불안정(?) 하다는 말을 들어서
:
: NtSuspendProcess 함수를 써서 서스펜드 시키게 됬습니다
:
: 문제는 기존 함수였던 SuspendThread / ResumeThread 함수들은 리턴값으로 서스펜드 카운트를 반환해서
:
: 몇번 서스펜드 명령이 있었는지를 보고 그만큼 Resume 을줬었는데
:
: NtSuspendProcess 함수는 그런걸 반환안하더라구요 그냥 반환값 무조건 0;
:
: 그래서인지 서스펜드를 여러번 시켜서 서스펜드 카운트는 쌓였는데 Resume 은 한번만 줘서
:
: 프로그램이 정상작동을 하지 않는등의 문제가 생깁니다.
:
: NtSuspendProcess 함수로 서스펜드 카운트를 받는 방법이 있을까요?
:
: 그리고 NtSuspendProcess 랑 SuspendThread 랑 무슨 차이가 있나요?
:
답변:
NtSuspendProcess()는 리턴값으로 NT_STATUS 를 사용하므로... 성공하면 0 값을 리턴하게 됩니다.
커널 내부 자료구조에서 카운트를 유지하고 있어서 NtSuspendProcess()를 여러번 호출했다면 프로세스를 Resume 시키기
위해선 NtSuspendProcess()를 호출한 횟수 만큼 NtResumeProcess()를 호출해줘야 합니다.
그에 반해서...
NtResumeProcess()는 여러번 호출해도 상관 없습니다. NtSuspendProcess()를 호출한 수 만큼 NtResumeProcess()를
호출하면 프로세스가 Resume 상태가 되고, 그 후에 또 다시 NtResumeProcess()를 호출해도 카운트 되는 것은 없다는 거죠.
카운트 값은 커널 내부 자료구조에서 갖고 있으므로...
위 두개의 API를 이용해서 처리할 경우.. 타겟 프로세스 상태가 Suspend상태인지 아닌지를 알아내서 Suspend 가 풀릴 때 까지
NtResumeProcess()를 계속 호출하는 구조로 로직을 구성해야 합니다.
타겟 프로세스의 Resume/Suspended 상태는 NtQuerySystemInformation()를 이용해서 알아 낼 수 있습니다.
어떤 프로세스의 SYSTEM_THREAD 라는 자료구조의 WaitReason 필드 값이 '5'이면 Suspended 상태 입니다.
SuspendThread()를 이용하는 것 보다 NtSuspendProcess()을 이용하는 게 유리한 것은...
하나의 프로세스는 여러개의 쓰레드를 가질 수 있고, 각기의 쓰레드를 개별적으로 Resume/Suspended 처리를 하게 되면
쓰레드 간의 종속관계로 인해서 문제가 발생할 수도 있기 때문 입니다. 잘못하면 데드락 상황이 발생할 수도 있고요.
NtQuerySystemInformation(), NtSuspendProcess(), NtResumeProcess() 등의 함수는 Undocumented API 이지만...
XP 이후부터 현재의 Windows 10 에 이르기 까지 계속 사용되고 있습니다. 커널 변경에 따라서 함수의 내부 Implementation이
바뀔 수는 있어도... Win32 레이어가 존재하는 한... 이 API들이 사라질 가능성은 ... 전혀 없다고 봐도 무방 하지요.
시스템 유틸리티 프로그램을 만들 때... 상당히 자주 사용되는 API이기도 합니다.(MS에서도 자신들이 만든 프로그램에서 자주
사용하기도 합니다.) Undocumented API라고 해서 꺼릴 필요는 없다는 겁니다.
|