Windows Vista 이상의 환경에서 Service에서 interactive process 실행하기.

Windows Vista 이상의 환경에서 LocalSystem account context에서 돌아가는 Service에서 interactive process를 실행하는 방법에 대해 포스팅해보도록 하겠다.
이것 저것 많은 자료를 보면서 이해했다 ㅠㅠ

일단 Windows에서의 세션, 스테이션, 데스크탑에 대해서 이해해야한다.
위 링크를 일단 읽으면 세션, 스테이션, 데스크탑이 뭔지에 대해서 알 수 있다.

그리고 http://cappleblog.co.kr/m/post/241 이 것도 보면 좋을 것 같다.
access token에 대해서도 알아야한다.

그리고 위 링크에서 내가 오늘 포스팅하려는 내용에 대해 설명하고 있다.

좀 더 친절하게 정리해서 내가 써보려고한다.

1. 현재 로그인하고 있는 다른 유저와 상호작용하는 process를 실행하고 싶은 경우
  우선 로그인하는 있는 다른 유저가 로컬이라고 가정을 해보겠다. 서비스는 세션0에서 동작하고 있다. 그렇기 때문에 직접적으로 현재 로컬에서 로그인하고 있는 다른 유저의 세션에 접근할 수는 없다.
 그래서 일단 WTSGetActiveConsoleSessionId () 를 통해서 로컬에서 로그인되 '활성화' 되어 있는 유저의 세션id를 얻어야한다. 그리고 WTSQueryUserToken () 를 통해서 세션id에 해당하는 세션에 로그인되어있는 유저의 primary access token을 얻을 수 있다.
msdn을 보면 알겠지만 이 함수는 LocalSystem account context가 아니면 ERROR_ACCESS_DENIED가 발생한다. 
  그후에 위 함수에서 얻은 token과 함께 CreateProcessAsUser () 를 호출하면 token에 해당하는 session에 process를 실행시킬 수 있다. 근데 주의할 점이 이 CreateProcessAsUser 함수는 기본적으로 non-interactive windows station의 destop 안에서 process를 실행시킨다. 따라서 interactive한 process를 생성하기 위해서는 위 함수 호출시 인자가 되는 STARTUPINFO 구조체의 lpDesktop 멤버에 "winsta0\default"를 넣어줘야한다. 이것이 의미하는 바는 winsta0 스테이션에 default 데스크탑에 프로세스를 생성한다는 것이다. 이렇게 해야하는 이유는 오직 winsta0 스테이션만이 사용자와 상호작용할 수 있고, winsta0의 default 데스크탑이 사용자의 기본 데스크탑이기 때문이다. (첫번째 링크참고)
  만약 로컬이 아닌 RDP환경까지도 고려하기 위해서는 WTSEnumerateSessions () 를 이용해 세션들중 active상태인 세션을 찾아서 그 세션의 세션id로 WTSQueryUserToken ()을 호출하면 된다. 이 방법에 대한 실제코드는 github코드 를 참고하면 될 것 같다.
  그리고 프로세스중 explore.exe 를 이용해서 primary token을 얻는 방법도 있다. 사용자가 로그인하면 explore.exe 가 항상 켜지기 때문에 이를 이용하여 프로세스중 explore.exe의 process id를 얻어서 process id를 통해 process handle을 얻고 handle을 인자로 하여 OpenProcessToken () 을 호출함으로서 impersonation token을 얻을 수 있다. 그리고 DuplicateTokenEx () 을 통해서 impersonation token 을 primary token 으로 바꿀 수 있다.

2. 특정 유저의 권한으로 process를 실행하고 싶은 경우
  이 경우에는 특정 유저의 ID, PW 평문과 함께 LogonUser () 를 통해서 새로운 세션을 만들고 그 세션id와 연관된 primary access token을 얻을 수 있다. 그리고 이 토큰을 이용해 CreateProcessAsUser () 를 호출하면 token에 연관된 session에 process를 실행시킬 수 있다. 라는게 나의 생각이다. 실제로도 이를 이용한 코드가 잘 작동하기도 한다. (코드)
  근데 이 링크 에서 말하기(1.B)는 내가 말한 것 만큼 단순하지 않다. 음... 저 링크에 대해서 왜 굳히 저런식으로 해야하는지 사실 아직 잘 이해를 못했다.

그리고 시간상 아직 분석은 하지 못했지만 이 코드를 한번 봐도 괜찮을 것 같다.

  윈도우즈 시스템과 윈도우즈 프로그래밍에 대한 이해가 높지 않아서 이 기술에 대해 100% 이해는 하지 못했지만 나름대로 이해한 것을 한번 정리해보았다. 항상 그래왔듯이 이 내용들도 껌같이 쉬워지는 순간이 오기를 믿으며 일단 이 기술은 여기까지 마무리짓고 원래 내가 하던 것들을 해야겠다. 그리고 항상 느끼는 거지만 이해안가는 것도 계속 쳐다보다보면 이해가고 쉬워지는 것같다. 이제 자야지....ㅠㅠ

댓글