첨부 실행 코드는 나눔고딕코딩 폰트를 사용합니다.
728x90
반응형
728x170
using System;
using System.Runtime.InteropServices;

/// <summary>
/// 종료 플래그 종류
/// </summary>
public enum ExitFlagType
{
    /// <summary>
    /// 로그오프
    /// </summary>
    LogOff = 0,

    /// <summary>
    /// 셧다운
    /// </summary>
    Shutdown = 1,

    /// <summary>
    /// 리부팅
    /// </summary>
    Reboot = 2,

    /// <summary>
    /// 강제 여부
    /// </summary>
    Force = 4,

    /// <summary>
    /// 전원 끄기
    /// </summary>
    PowerOff = 8,

    /// <summary>
    /// 보류시 강제 여부
    /// </summary>
    ForceIfHung = 16
}


/// <summary>
/// 사유 종류
/// </summary>
public enum ReasonType : uint
{
    /// <summary>
    /// 애플리케이션 이슈
    /// </summary>
    ApplicationIssue = 0x00040000,

    /// <summary>
    /// 하드웨어 이슈
    /// </summary>
    HardwareIssue = 0x00010000,

    /// <summary>
    /// 소프트웨어 이슈
    /// </summary>
    SoftwareIssue = 0x00030000,

    /// <summary>
    /// 계획 셧다운
    /// </summary>
    PlannedShutdown = 0x80000000
}


/// <summary>
/// 토큰 특권
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct TokenPrivileges
{
    /// <summary>
    /// 특권 수
    /// </summary>
    public int PrivilegeCount;

    /// <summary>
    /// LUID
    /// </summary>
    public long LUID;

    /// <summary>
    /// 어트리뷰트
    /// </summary>
    public int Attributes;
}


#region 확장 윈도우 종료하기 - ExitWindowsEx(flagType, reasonType)

/// <summary>
/// 확장 윈도우 종료하기
/// </summary>
/// <param name="flagType">플래그 종류</param>
/// <param name="reasonType">사유 종류</param>
/// <returns>처리 결과</returns>
[DllImport("user32.dll", SetLastError = true)]
private static extern int ExitWindowsEx(uint flagType, uint reasonType);

#endregion

#region 현재 프로세스 구하기 - GetCurrentProcess();

/// <summary>
/// 현재 프로세스 구하기
/// </summary>
/// <returns>현재 프로세스 핸들</returns>
[DllImport("kernel32.dll")]
private static extern IntPtr GetCurrentProcess();

#endregion

#region 프로세스 토큰 열기 - OpenProcessToken(processHandle, desiredAccess, tokenHandle)

/// <summary>
/// 프로세스 토큰 열기
/// </summary>
/// <param name="processHandle">프로세스 핸들</param>
/// <param name="desiredAccess">희망 액세스</param>
/// <param name="tokenHandle">토큰 핸들</param>
/// <returns>처리 결과</returns>
[DllImport("advapi32.dll", SetLastError = true)]
private static extern int OpenProcessToken(IntPtr processHandle, int desiredAccess, ref IntPtr tokenHandle);

#endregion

#region 특권 값 조사하기 - LookupPrivilegeValue(systemName, name, uid)

/// <summary>
/// 특권 값 조사하기
/// </summary>
/// <param name="systemName">시스템명</param>
/// <param name="name">명칭</param>
/// <param name="uid">UID</param>
/// <returns>처리 결과</returns>
[DllImport("advapi32.dll", SetLastError = true)]
private static extern int LookupPrivilegeValue(string systemName, string name, ref long uid);

#endregion

#region 토큰 특권 조정하기 - AdjustTokenPrivileges(tokenHandle, disableAllPrivileges, newState, bufferLength, previousState, length)

/// <summary>
/// 토큰 특권 조정하기
/// </summary>
/// <param name="tokenHandle">토큰 핸들</param>
/// <param name="disableAllPrivileges">모든 특권 비활성화 여부</param>
/// <param name="newState">새로운 상태</param>
/// <param name="bufferLength">버퍼 길이</param>
/// <param name="previousState">이전 상태</param>
/// <param name="length">길이</param>
/// <returns>처리 결과</returns>
[DllImport("advapi32.dll", SetLastError = true)]
private static extern int AdjustTokenPrivileges(IntPtr tokenHandle, bool disableAllPrivileges, ref TokenPrivileges newState, int bufferLength, IntPtr previousState, IntPtr length);

#endregion


#region 특권 올리기 - ElevatePrivileges()

/// <summary>
/// 특권 올리기
/// </summary>
private void ElevatePrivileges()
{
    IntPtr currentProcessHandle = GetCurrentProcess();
    IntPtr tokenHandle          = IntPtr.Zero;

    int result = OpenProcessToken(currentProcessHandle, AdjustPrivileges | TokenQuery, ref tokenHandle);

    if(result == 0)
    {
        throw new Win32Exception(Marshal.GetLastWin32Error());
    }

    TokenPrivileges tokenPrivileges;

    tokenPrivileges.PrivilegeCount = 1;
    tokenPrivileges.LUID           = 0;
    tokenPrivileges.Attributes     = PrivilegeEnabled;

    result = LookupPrivilegeValue(null, ShutdownPrivilege, ref tokenPrivileges.LUID);

    if(result == 0)
    {
        throw new Win32Exception(Marshal.GetLastWin32Error());
    }

    result = AdjustTokenPrivileges(tokenHandle, false, ref tokenPrivileges, 0, IntPtr.Zero, IntPtr.Zero);

    if(result == 0)
    {
        throw new Win32Exception(Marshal.GetLastWin32Error());
    }
}

#endregion


#region 윈도우즈 셧다운 하기 - ShutdownWindows(force)

/// <summary>
/// 윈도우즈 셧다운 하기
/// </summary>
/// <param name="force">강제 여부</param>
public void ShutdownWindows(bool force)
{
    ElevatePrivileges();

    int result = 0;

    if(force)
    {
        result = ExitWindowsEx
        (
            (uint)(ExitFlagType.Shutdown | ExitFlagType.PowerOff | ExitFlagType.Force),
            (uint)(ReasonType.HardwareIssue | ReasonType.PlannedShutdown)
        );
    }
    else
    {
        result = ExitWindowsEx
        (
            (uint)(ExitFlagType.Shutdown | ExitFlagType.PowerOff),
            (uint)(ReasonType.HardwareIssue | ReasonType.PlannedShutdown)
        );

        if(result == 0)
        {
            throw new Win32Exception(Marshal.GetLastWin32Error());
        }
    }
}

#endregion
728x90
반응형
그리드형(광고전용)
Posted by icodebroker

댓글을 달아 주세요