[C#] User/System 권한으로 레지스트리(Registry) 값 읽어오기

업데이트:

Registry 값 읽어오기

C++ 포스팅 내용과 비교

시스템 권한으로 레지스트리를 읽어오는 방법에대하여 아래 링크에 c++을 이용한 포스팅으로 소개했었다.

  • https://hwanine.github.io/c++/Registry-c++/

이번엔 C#에서 레지스트리를 읽어오는 방식에 대하여 다뤄보겠다.


User 권한 방식

아래 코드를 통해 레지스트리 값을 읽고 저장할 수 있다.
Microsoft.Win32 네임스페이스를 사용한다.

using Microsoft.Win32;

// 레지스트리 추출
var readRegKey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey("{RegistryPath}"); // 레지스트리 경로 입력
var value = readRegKey?.GetValue("{Value}")?.ToString(); // 가져올 값 입력

// 레지스트리 저장
var saveRegKey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey("{RegistryPath}", true); // 레지스트리 경로 입력
if (!Microsoft.Win32.Registry.CurrentUser.GetSubKeyNames().Select(x => x.Equals(saveRegKey)).Any())
{
    Microsoft.Win32.Registry.CurrentUser.CreateSubKey(saveRegKey);
}
saveRegKey?.SetValue("{key}", "{value}"); // 저장할 키와 값 입력

위의 방법으로 레지스트리 값을 읽고 쓸 수 있다. 물론 다른 자료형으로 읽는 방법도 가능하다.


문제점

근데 이 방법으로 사용하면 마찬가지로 시스템 권한일 경우 레지스트리를 읽어오지못한다. 즉, C#으로 윈도우 서비스 개발을 할 경우, 서비스 권한을 유저 권한으로 변경해주지 않으면 System 계정으로 레지스트리에 접근을하여 정상적으로 읽어오지 못한다.


System 권한 방식

아래 코드는 윈도우 서비스에 Local System 계정으로 등록되어있어도 정상적으로 레지스트리를 읽어올 수 있다.

방식은 C++ 방식과 같다.

  1. 실행된 프로세스 PID를 찾는다.
  2. 프로세스 ID로 실행자 SID를 찾는다.
  3. 실행자 SID로 레지스트리를 조회한다.
// 탐색기 프로세스를 찾아 PID를 찾는다.
foreach (Process process in Process.GetProcesses()) // 프로세스 목록들 모두에 대해
{
    var processName = process.ProcessName;
    if (processName.Equals("explorer")) // 프로세스 이름이 발견되면
    {
        var dd = process.MachineName;
        sid = GetProcessInfoByPID(process.Id, out user);
    }
}

public static string GetProcessInfoByPID(int PID, out string User)
{
    User = String.Empty;
    var OwnerSID = String.Empty;
    string processname = String.Empty;
    try
    {
        ObjectQuery sq = new ObjectQuery
            ("Select * from Win32_Process Where ProcessID = '" + PID + "'");
        ManagementObjectSearcher searcher = new ManagementObjectSearcher(sq);
        var searcherGet = searcher.Get();
        if (searcherGet.Count == 0)
            return OwnerSID;
        foreach (ManagementObject oReturn in searcherGet)
        {
            string[] o = new String[2];
            //시스템 계정 추출
            oReturn.InvokeMethod("GetOwner", (object[])o);
            User = o[0];
            
            if (User == null)
                User = String.Empty;
            //시스템 SID 추출
            string[] sid = new String[1];
            oReturn.InvokeMethod("GetOwnerSid", (object[])sid);
            OwnerSID = sid[0];
            return OwnerSID;
        }
    }
    catch
    {
        return OwnerSID;
    }
    return OwnerSID;
}

이제 시스템 계정의 SID까지 추출이 완료되었다. 이 SID로 레지스트리를 추출할 수 있다.

// 레지스트리 추출
var readPath = sid + "{RegistryPath}"; // 레지스트리 경로 입력
var ReadRegkey = Microsoft.Win32.Registry.Users.OpenSubKey(readPath);
return ReadRegkey?.GetValue("{Value}").ToString();

// 레지스트리 저장
var savePath = sid + "{RegistryPath}"; // 레지스트리 경로 입력
var saveRegKey = Microsoft.Win32.Users.OpenSubKey(savePath, true); // 레지스트리 경로 입력
if (!Microsoft.Win32.Users.GetSubKeyNames().Select(x => x.Equals(saveRegKey)).Any())
{
    Microsoft.Win32.Users.CreateSubKey(saveRegKey);
}
saveRegKey?.SetValue("{key}", "{value}"); // 저장할 키와 값 입력

해당 샘플코드를 커스터마이징하여 사용하면 C#서비스 프로젝트에서 레지스트리 값을 조작할 경우나 다른 특별한 경우 프로세스가 시스템 계정이어도 정상적으로 현재 유저 계정의 레지스트리를 읽어올 수 있다.


태그: ,

카테고리:

업데이트:

댓글남기기