Статьи по меткам ‘WinAPI’

Сайт PInvoke.NET

Ноябрь 21st, 2010

При работе над одним проектом на C# у меня возникала необходимость использования большого количества WinAPI-функций. Как Вы знаете, импортировать в C# функции из динамически загружаемых библиотек DLL можно, используя технологию P/Invoke. При этом нужно прописать все импорты функций и необходимых структур данных.

На это занятие может уйти некоторое время, которое можно было бы потратить на что-то более полезное :)

На сайте PInvoke.NET собрана огромная коллекция импортов WinAPI-функций и структур данных. Интересующую функцию, структуру или перечисление Вы можете найти воспользовавшись поиском в левой части сайта.

Приведу пример прототипа WinAPI-функции из MSDN и PInvoke.NET:

1
BOOL WINAPI Beep(DWORD dwFreq, DWORD dwDuration);
Прототип функции Beep() из MSDN
1
2
3
[DllImport("kernel32.dll", SetLastError=true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool Beep(uint dwFreq, uint dwDuration);
Прототип функции Beep() из pinvoke.net

А вот например структура SYSTEM_INFO:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
typedef struct _SYSTEM_INFO {
  union {
    DWORD  dwOemId;
    struct {
      WORD wProcessorArchitecture;
      WORD wReserved;
    } ;
  } ;
  DWORD     dwPageSize;
  LPVOID    lpMinimumApplicationAddress;
  LPVOID    lpMaximumApplicationAddress;
  DWORD_PTR dwActiveProcessorMask;
  DWORD     dwNumberOfProcessors;
  DWORD     dwProcessorType;
  DWORD     dwAllocationGranularity;
  WORD      wProcessorLevel;
  WORD      wProcessorRevision;
} SYSTEM_INFO;
Структура SYSTEM_INFO из MSDN
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[StructLayout(LayoutKind.Sequential)]
public struct SYSTEM_INFO
{
    public ushort processorArchitecture;
    ushort reserved;
    public uint pageSize;
    public IntPtr minimumApplicationAddress;
    public IntPtr maximumApplicationAddress;
    public IntPtr activeProcessorMask;
    public uint numberOfProcessors;
    public uint processorType;
    public uint allocationGranularity;
    public ushort processorLevel;
    public ushort processorRevision;
}
Структура SYSTEM_INFO из pinvoke.net
Вывод

Ресурс PInvoke.NET может здорово сэкономить время при разработке программ на C# под платформу Windows.

Получение любых привилегий для процесса на C#

Май 15th, 2010

Иногда для выполнения каких-либо операций приложению требуется получить различные привилегии. Например для того, чтобы посмотреть используемые модули системного процесса, наше приложение должно обладать привилегией отладчика.

Чтобы изменить привилегии процесса, нужно воспользоваться тремя WinAPI-функциями:

  1. Прежде всего, необходимо открыть токен доступа процесса функцией OpenProcessToken() из библиотеки advapi32.dll .
  2. С помощью функции LookupPrivilegeValue(), подготовить структуру TOKEN_PRIVILEGES, в которой разместить информацию о требуемом уровне привилегий.
  3. Обратиться к функции AdjustTokenPrivileges() непосредственно для изменения привилегии процесса.

Кстати, чтобы успешно получить привилегии отладчика, нужно иметь администраторские права.

Ниже приведен код на C#, обеспечивающий получение заданных привилегий(метод SetPrivilege()). В нем также определены строковые константы привилегий:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
public class PrivilegeManager
{
    [DllImport("advapi32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool OpenProcessToken(IntPtr ProcessHandle,
        UInt32 DesiredAccess, out IntPtr TokenHandle);

    private static uint STANDARD_RIGHTS_REQUIRED = 0x000F0000;
    private static uint STANDARD_RIGHTS_READ = 0x00020000;
    private static uint TOKEN_ASSIGN_PRIMARY = 0x0001;
    private static uint TOKEN_DUPLICATE = 0x0002;
    private static uint TOKEN_IMPERSONATE = 0x0004;
    private static uint TOKEN_QUERY = 0x0008;
    private static uint TOKEN_QUERY_SOURCE = 0x0010;
    private static uint TOKEN_ADJUST_PRIVILEGES = 0x0020;
    private static uint TOKEN_ADJUST_GROUPS = 0x0040;
    private static uint TOKEN_ADJUST_DEFAULT = 0x0080;
    private static uint TOKEN_ADJUST_SESSIONID = 0x0100;
    private static uint TOKEN_READ = (STANDARD_RIGHTS_READ | TOKEN_QUERY);
    private static uint TOKEN_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | TOKEN_ASSIGN_PRIMARY |
        TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_QUERY_SOURCE |
        TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT |
        TOKEN_ADJUST_SESSIONID);

    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern IntPtr GetCurrentProcess();

    [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool LookupPrivilegeValue(string lpSystemName, string lpName,
        out LUID lpLuid);

    #region Privelege constants
         
        public const string SE_ASSIGNPRIMARYTOKEN_NAME = "SeAssignPrimaryTokenPrivilege";
        public const string SE_AUDIT_NAME = "SeAuditPrivilege";
        public const string SE_BACKUP_NAME = "SeBackupPrivilege";
        public const string SE_CHANGE_NOTIFY_NAME = "SeChangeNotifyPrivilege";
        public const string SE_CREATE_GLOBAL_NAME = "SeCreateGlobalPrivilege";
        public const string SE_CREATE_PAGEFILE_NAME = "SeCreatePagefilePrivilege";
        public const string SE_CREATE_PERMANENT_NAME = "SeCreatePermanentPrivilege";
        public const string SE_CREATE_SYMBOLIC_LINK_NAME = "SeCreateSymbolicLinkPrivilege";
        public const string SE_CREATE_TOKEN_NAME = "SeCreateTokenPrivilege";
        public const string SE_DEBUG_NAME = "SeDebugPrivilege";
        public const string SE_ENABLE_DELEGATION_NAME = "SeEnableDelegationPrivilege";
        public const string SE_IMPERSONATE_NAME = "SeImpersonatePrivilege";
        public const string SE_INC_BASE_PRIORITY_NAME = "SeIncreaseBasePriorityPrivilege";
        public const string SE_INCREASE_QUOTA_NAME = "SeIncreaseQuotaPrivilege";
        public const string SE_INC_WORKING_SET_NAME = "SeIncreaseWorkingSetPrivilege";
        public const string SE_LOAD_DRIVER_NAME = "SeLoadDriverPrivilege";
        public const string SE_LOCK_MEMORY_NAME = "SeLockMemoryPrivilege";
        public const string SE_MACHINE_ACCOUNT_NAME = "SeMachineAccountPrivilege";
        public const string SE_MANAGE_VOLUME_NAME = "SeManageVolumePrivilege";
        public const string SE_PROF_SINGLE_PROCESS_NAME = "SeProfileSingleProcessPrivilege";
        public const string SE_RELABEL_NAME = "SeRelabelPrivilege";
        public const string SE_REMOTE_SHUTDOWN_NAME = "SeRemoteShutdownPrivilege";
        public const string SE_RESTORE_NAME = "SeRestorePrivilege";
        public const string SE_SECURITY_NAME = "SeSecurityPrivilege";
        public const string SE_SHUTDOWN_NAME = "SeShutdownPrivilege";
        public const string SE_SYNC_AGENT_NAME = "SeSyncAgentPrivilege";
        public const string SE_SYSTEM_ENVIRONMENT_NAME = "SeSystemEnvironmentPrivilege";
        public const string SE_SYSTEM_PROFILE_NAME = "SeSystemProfilePrivilege";
        public const string SE_SYSTEMTIME_NAME = "SeSystemtimePrivilege";
        public const string SE_TAKE_OWNERSHIP_NAME = "SeTakeOwnershipPrivilege";
        public const string SE_TCB_NAME = "SeTcbPrivilege";
        public const string SE_TIME_ZONE_NAME = "SeTimeZonePrivilege";
        public const string SE_TRUSTED_CREDMAN_ACCESS_NAME = "SeTrustedCredManAccessPrivilege";
        public const string SE_UNDOCK_NAME = "SeUndockPrivilege";
        public const string SE_UNSOLICITED_INPUT_NAME = "SeUnsolicitedInputPrivilege";
    #endregion

    [StructLayout(LayoutKind.Sequential)]
    public struct LUID
    {
        public UInt32 LowPart;
        public Int32 HighPart;
    }

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern bool CloseHandle(IntPtr hHandle);

    public const UInt32 SE_PRIVILEGE_ENABLED_BY_DEFAULT = 0x00000001;
    public const UInt32 SE_PRIVILEGE_ENABLED = 0x00000002;
    public const UInt32 SE_PRIVILEGE_REMOVED = 0x00000004;
    public const UInt32 SE_PRIVILEGE_USED_FOR_ACCESS = 0x80000000;

    [StructLayout(LayoutKind.Sequential)]
    public struct TOKEN_PRIVILEGES
    {
        public UInt32 PrivilegeCount;
        public LUID Luid;
        public UInt32 Attributes;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct LUID_AND_ATTRIBUTES
    {
        public LUID Luid;
        public UInt32 Attributes;
    }

    [DllImport("advapi32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool AdjustTokenPrivileges(IntPtr TokenHandle,
       [MarshalAs(UnmanagedType.Bool)]bool DisableAllPrivileges,
       ref TOKEN_PRIVILEGES NewState,
       UInt32 Zero,
       IntPtr Null1,
       IntPtr Null2);

    /// <summary>
    /// Меняет привилегию
    /// </summary>
    /// <param name="PID">ID процесса</param>
    /// <param name="privelege">Привилегия</param>
    public static void SetPrivilege(IntPtr PID, string privilege)
    {
        IntPtr hToken;
        LUID luidSEDebugNameValue;
        TOKEN_PRIVILEGES tkpPrivileges;

        if (!OpenProcessToken(PID, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, out hToken))
        {
            throw new Exception("Произошла ошибка при выполнении OpenProcessToken(). Код ошибки "
                + Marshal.GetLastWin32Error());
        }

        if (!LookupPrivilegeValue(null, privilege, out luidSEDebugNameValue))
        {
            CloseHandle(hToken);
            throw new Exception("Произошла ошибка при выполнении LookupPrivilegeValue(). Код ошибки "
                + Marshal.GetLastWin32Error());
        }

        tkpPrivileges.PrivilegeCount = 1;
        tkpPrivileges.Luid = luidSEDebugNameValue;
        tkpPrivileges.Attributes = SE_PRIVILEGE_ENABLED;

        if (!AdjustTokenPrivileges(hToken, false, ref tkpPrivileges, 0, IntPtr.Zero, IntPtr.Zero))
        {
            throw new Exception("Произошла ошибка при выполнении LookupPrivilegeValue(). Код ошибки :"
                + Marshal.GetLastWin32Error());
        }
        CloseHandle(hToken);
    }
}

Статический метод SetPrivilege() принимает два параметра: первый – PID(Process ID), идентификатор процесса, а второй – строковое название привилегии. Во второй параметр удобно передавать одну из констант, которые также есть в классе PrivilegeManager.

Возможно Вам понадобится узнать PID Вашего процесса. Нет ничего проще! Воспользуйтесь функцией GetCurrentProcess().

См. также Константы привилегий в Windows.

Копирование материалов сайта допускается только с разрешения администрации сайта.