성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] Working with Rust Libraries from C#...
[정성태] Detecting blocking calls using asyn...
[정성태] 아쉽게도, 커뮤니티는 아니고 개인 블로그입니다. ^^
[정성태] 질문이 잘 이해가 안 됩니다. 우선, 해당 소스코드에서 ILis...
[양승조
] var대신 dinamic으로 선언해서 해결은 했습니다. 맞는 해...
[양승조
] 또 막혔습니다. ㅠㅠ var list = props[i].Ge...
[양승조
] 아. 감사합니다. 어제는 안됐던것 같은데....정신을 차려야겠네...
[정성태] "props[i].GetValue(props[i])" 코드에서 ...
[정성태] 저렇게 조각 코드 말고, 실제로 재현이 되는 예제 프로젝트를 압...
[정성태] Modules 창(Ctrl+Shift+U)을 띄워서, 해당 Op...
글쓰기
제목
이름
암호
전자우편
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'>다른 프로세스에 환경 변수 설정하는 방법 - 두 번째 이야기</h1> <p> 지난 이야기에서 SYSTEM 권한으로 코드를 실행하는 방법을 설명했는데요.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Local SYSTEM 권한으로 코드를 실행하는 방법 ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/1436'>http://www.sysnet.pe.kr/2/0/1436</a> </pre> <br /> 사실 '관리자 권한'으로 실행하는 경우는 많아도 SYSTEM 권한으로 실행할 만한 코드는 거의 없습니다. 그나마 있다면... SYSTEM 권한으로 실행되는 NT 프로세스의 환경 변수의 값을 바꾸는 경우가 있는데요. 예전에도 이와 관련된 글이 있었습니다.<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='http://www.sysnet.pe.kr/2/0/1297'>http://www.sysnet.pe.kr/2/0/1297</a> </pre> <br /> COM+ 에 대행하기에는 너무 번거로운 선행 작업이 많아서 좀 불편한데요. 그래서, 이번에는 NT 서비스를 이용해 다시 한번 그 부분을 개선해 보기로 했습니다.<br /> <br /> 예제 프로그램의 목표는 모든 NT 서비스들의 부모 프로세스인 services.exe에 환경 변수를 설정하는 것입니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> services.exe에 대해 CreateRemoteThread를 사용하는 것은 같지만, 그 코드를 실행하는 것은 "<a target='tab' href='http://www.sysnet.pe.kr/2/0/1436'>Local SYSTEM 권한으로 코드를 실행하는 방법</a>"에서 설명했던 NT 서비스에서 할 것입니다.<br /> <br /> 문제는 servies.exe에 로드되는 DLL인데요. 아쉽게도 이것은 C# DLL로 만들 수 없습니다. 왜냐하면 C# 코드를 가진 DLL을 services.exe에 로드해서 실행시킬 수는 없기 때문입니다.<br /> <br /> 따라서 다음과 같이 2개의 프로젝트를 만들어야 합니다.<br /> <br /> <ul> <li>psexec2: C# EXE 프로젝트, 콘솔 프로그램이면서 스스로를 NT 서비스로 등록시켜 SYSTEM 권한으로 실행하는 코드를 함께 구현</li> <li>SetEnvDll: C++ DLL 프로젝트, services.exe 측에 Injection 되어 환경 변수를 설정하는 함수를 실행</li> </ul> <br /> SetEnvDll의 소스 코드는 다음과 같이 간단합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > #include <Windows.h> #pragma comment(lib, "kernel32.lib") BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: SetEnvironmentVariable(L"ALLTEST", L"TEST"); // Kernel32.dll return FALSE; case DLL_THREAD_ATTACH: return FALSE; case DLL_THREAD_DETACH: return TRUE; case DLL_PROCESS_DETACH: return TRUE; } return FALSE; } </pre> <br /> 빌드 방법도 다음의 글에 따라 해주시면 약 4K~5K 정도 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Visual C++ CRT(C Runtime DLL: msvcr...dll)에 대한 의존성 제거 ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/1437'>http://www.sysnet.pe.kr/2/0/1437</a> </pre> <br /> 그 다음은 위의 Win32 DLL을 Injection 시킬 세션 0에서 동작될 SYSTEM 권한의 프로세스가 필요한데요. 이는 psexec2 C# 프로젝트가 할 것입니다. psexec2 내의 코드는 다음의 글에서 설명한 것과 구조는 동일합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Local SYSTEM 권한으로 코드를 실행하는 방법 ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/1436'>http://www.sysnet.pe.kr/2/0/1436</a> </pre> <br /> 바뀌는 부분은 DoSystemRights 메소드에서 services.exe 프로세스에 Win32 DLL을 Injection 시켜야 하는데요. C++에서 이전에 했던 것처럼,<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='http://www.sysnet.pe.kr/2/0/1297'>http://www.sysnet.pe.kr/2/0/1297</a> </pre> <br /> 그대로 관련 Win32 API들을 C# P/Invoke를 사용해 DllImport로 변경해 주면 됩니다. 대충 다음과 같은 식으로 구성해 주면 되겠지요. ^^<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 void DoSystemRights() { Process thisProcess = Process.GetCurrentProcess(); // Win32 DLL을 services.exe 프로세스에 Injection 시킵니다. string folder = Path.GetDirectoryName(typeof(Program).Assembly.Location); string dllPath = Path.Combine(folder, "SetEnvDll.dll"); IntPtr NullPtr = IntPtr.Zero; Process[] processes = Process.GetProcessesByName("services"); foreach (Process process in processes) { IntPtr hProc = IntPtr.Zero; IntPtr pRemoteDll = IntPtr.Zero; IntPtr hKernel32 = IntPtr.Zero; IntPtr hThread = IntPtr.Zero; // 같은 이름의 실행 파일이 가능하므로, 최대한 범위를 좁힌다. if (process.SessionId == thisProcess.SessionId) { do { hProc = Win32API.OpenProcess(Win32API.ProcessAccessFlags.All, false, process.Id); if (hProc == IntPtr.Zero) { break; } byte[] contents = Encoding.ASCII.GetBytes(dllPath); pRemoteDll = Win32API.VirtualAllocEx(hProc, NullPtr, (uint)(contents.Length + 1), Win32API.AllocationType.Commit, Win32API.MemoryProtection.ReadWrite); if (pRemoteDll == IntPtr.Zero) { break; } UIntPtr written = UIntPtr.Zero; if (Win32API.WriteProcessMemory(hProc, pRemoteDll, contents, (uint)(contents.Length + 1), out written) == false) { break; } hKernel32 = Win32API.GetModuleHandle("kernel32.dll"); UIntPtr pfnLoadLibrary = Win32API.GetProcAddress(hKernel32, "LoadLibraryA"); if (pfnLoadLibrary == UIntPtr.Zero) { break; } hThread = Win32API.CreateRemoteThread(hProc, NullPtr, 0, pfnLoadLibrary, pRemoteDll, 0, NullPtr); if (hThread == IntPtr.Zero) { break; } Win32API.CloseHandle(hThread); } while (false); if (pRemoteDll != IntPtr.Zero) { Win32API.VirtualFreeEx(hProc, pRemoteDll, 0, Win32API.FreeType.Release); pRemoteDll = IntPtr.Zero; } if (hProc != IntPtr.Zero) { Win32API.CloseHandle(hProc); hProc = IntPtr.Zero; } } } } </pre> <br /> <a target='tab' href='http://www.sysnet.pe.kr/bbs/DownloadAttachment.aspx?fid=772&boardid=331301885'>첨부된 파일에 동작되는 예제 코드를 구성했으니 참고</a>하시고요. 기본 빌드 환경은 x64/Release로 되어 있고, Windows 8에서 테스트 해보았습니다.<br /> <br /> 빌드하고, /x64/Release/psexec2.exe를 실행하면 services.exe 프로세스에 "ALLTEST" 환경 변수의 값이 "TEST"로 새롭게 설정되는 것을 확인할 수 있습니다. (Process Explorer로 확인하시면 됩니다.)<br /> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
1187
(왼쪽의 숫자를 입력해야 합니다.)