进程提权小结
一直在使用的进程提权,今天在这里做个简单的小结。
进程提权需要使用到一组Windows API有:
1.OpenProcessToken
2.LookupPrivilegeValue
3.AdjustTokenPrivileges
值得注意的是,使用这组函数提升权限的前提是进程具备该权限,只是访问令牌中没有启用该权限。如果进程的访问令牌中本身就没有关联该权限,那么AdjustTokenPrivileges函数调用将会返回ERROR_NOT_ALL_ASSIGNED(值为1300L)的错误码。
0x01 OpenProcessToken
BOOL WINAPI OpenProcessToken( __in HANDLE ProcessHandle, //进程句柄(当前进程为GetCurrentProcess()为参数) __in DWORD DesiredAccess, //访问令牌特权 __out PHANDLE TokenHandle //返回的参数,就是AdjustTokenPrivileges的第一个参数 );
注意第二个参数令牌的权限,这个权限是要有修改权限的特权(TOKEN_ADJUST_PRIVILEGES),意思就是要把程序的权限修改得更高。所有权限可以写TOKEN_ALL_ACCESS ,去查看一个令牌特权可以用TOKEN_QUERY
HANDLE ProcessHandle = GetCurrentProcess(); HANDLE TokenHandle = NULL; if (!OpenProcessToken(ProcessHandle, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &TokenHandle)) { return FALSE; }
0x02 TOKEN_PRIVILEGES结构
typedef struct _TOKEN_PRIVILEGES { DWORD PrivilegeCount; //要修改的特权数目 LUID_AND_ATTRIBUTES Privileges[ANYSIZE_ARRAY]; //特权数组 }TOKEN_PRIVILEGES;
LUID_AND_ATTRIBUTES 结构体:
typedef struct _LUID_AND_ATTRIBUTES { LUID Luid; //一个标志,不同的Luid代表着各种不同的特权类型 DWORD Attributes; //要这个特权干嘛,如启用这个特权(SE_PRIVILEGE_ENABLED) } LUID_AND_ATTRIBUTES;
0x03 LookupPrivilegeValue
BOOL WINAPI LookupPrivilegeValue( __in_opt LPCTSTR lpSystemName, //系统的名字,如果为NULL,就是本地名字(这里就填NULL) __in LPCTSTR lpName, //特权的名字 __out PLUID lpLuid //通过指针返回一个LUID类型的Luid的标识,这个值就就可以填入刚才的结构体里了。 );
0x04 AdjustTokenPrivilege
BOOL WINAPI AdjustTokenPrivileges( __in HANDLE TokenHandle, //OpenProcessToken第三个指针参数传出的句柄值 __in BOOL DisableAllPrivileges, //是否禁用所有所有的特权(这里填false) __in_opt PTOKEN_PRIVILEGES NewState, //新的TOKEN_PRIVILEGES的特权结构体指针 __in DWORD BufferLength, //上面结构体的字节长度(sizeof) __out_opt PTOKEN_PRIVILEGES PreviousState, //接受原先的特权的结构体 __out_opt PDWORD ReturnLength //结构体的字节长度的指针 );
进程提权中后两个参数不用管。
MSDN叙述:
如果第五个参数不是NULL,在OpenProcessToken加特权时除了需要指定TOKEN_ADJUST_PRIVILEGES还必须指定TOKEN_QUERY
如果第五个参数是NULL,你不接受原先的结构体(第六个当然也是NULL), 就不用再指定附加的TOKEN_QUERY的特权了。
还要注意:
就算这个函数返回为真,还要调用GetLastError()来检验是否完全成功。如果GetLastError()==ERROR_SUCCESS就代表修改非常成功 ,这个非常重要!!
源代码:
BOOL EnableSeDebugPrivilege(IN const CHAR* PriviledgeName, BOOL IsEnable); if (EnableSeDebugPrivilege("DebugPrivilege", TRUE) == FALSE) { } BOOL EnableSeDebugPrivilege(IN const CHAR* PriviledgeName, BOOL IsEnable) { // 打开权限令牌 HANDLE ProcessHandle = GetCurrentProcess(); HANDLE TokenHandle = NULL; TOKEN_PRIVILEGES TokenPrivileges = { 0 }; if (!OpenProcessToken(ProcessHandle, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &TokenHandle)) { return FALSE; } LUID v1; if (!LookupPrivilegeValue(NULL, PriviledgeName, &v1)) // 通过权限名称查找uID { CloseHandle(TokenHandle); TokenHandle = NULL; return FALSE; } TokenPrivileges.PrivilegeCount = 1; // 要提升的权限个数 TokenPrivileges.Privileges[0].Attributes = IsEnable == TRUE ? SE_PRIVILEGE_ENABLED : 0; // 动态数组,数组大小根据Count的数目 TokenPrivileges.Privileges[0].Luid = v1; if (!AdjustTokenPrivileges(TokenHandle, FALSE, &TokenPrivileges, sizeof(TOKEN_PRIVILEGES), NULL, NULL)) { CloseHandle(TokenHandle); TokenHandle = NULL; return FALSE; } CloseHandle(TokenHandle); TokenHandle = NULL; return TRUE; }