windows UAC
UAC简介
UAC(User Account Control,用户帐户控制)是微软为提高系统安全而在Windows Vista中引入的新技术。
关闭UAC可以进行如下操作:
1、开始——运行,或者WIN+R键打开运行对话框,输入Gpedit.msc打开“组策略”。
2、依次定位:“计算机配置”——“Windows设置”——“安全设置”——“安全选项”。
3、在“安全选项”中找到“用户帐户控制: 管理审批模式下管理员的提升提示行为”选项,双击它。在弹出的窗口,点击右侧的向下箭头,修改为“不提示,直接提升”后确定”,就不会再弹出提示框了!
windows进程权限的检查:
//pElevationType:当前的权限类型:
typedef enum {
TokenElevationTypeDefault = 1,
TokenElevationTypeFull,
TokenElevationTypeLimited
} TOKEN_ELEVATION_TYPE , *PTOKEN_ELEVATION_TYPE;
TokenElevationTypeDefault:进程以缺省的用户身份运行,或者没有使用UAC功能,
简单来说,就是用户没有启动UAC功能,那么程序使用的令牌,一定不是Filter Token。
TokenElevationTypeFull:进程的权限已经被提升,进程令牌没有使用filter令牌
TokenElevationTypeLimited:进程使用的令牌是Filter令牌。
此时通过GetTokenInformation函数,并使用TokenLinkedToken标志,来获取原令牌。
windows权限提升代码
//pIsAdmin:是否是管理员。
#include<Windows.h>
#include<tchar.h>
#include<Shlobj.h>
//可以把这个函数当Windows API来用。这个函数返回BOOL,当函数返回TRUE的时候,函数成功,当函数返回FALSE的话
//函数失败。
/*
TOKEN_ELEVATION_TYPE* pElevationType:令牌提升类型。
BOOL* pIsAdmin :是否是管理员。保存结果
这个函数,确定了,运行当前程序的帐号,是否为管理员帐号,以及当前进程的令牌,是那种令牌。甚至你还可以确定,当前
的这个操作系统是否启动了UAC功能。
*/
BOOL GetProcessElevation(TOKEN_ELEVATION_TYPE* pElevationType, BOOL* pIsAdmin)
{
HANDLE hToken = NULL;
DWORD dwSize;
// 获得当前进程的令牌句柄。
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
return(FALSE);
BOOL bResult = FALSE;
// 看看这个令牌的权限提升类型是哪一种:
/*
TokenElevationTypeDefault:进程以缺省的用户身份运行,或者没有使用UAC功能,简单来说,就是用户没有启动UAC功能,那么程序使用的令牌,一定不是Filter Token。
TokenElevationTypeFull:进程的权限已经被提升,进程令牌没有使用filter令牌
TokenElevationTypeLimited:进程使用的令牌是Filter令牌。此时通过GetTokenInformation函数,并使用TokenLinkedToken标志,来获取原令牌。
*/
if (GetTokenInformation(hToken, TokenElevationType,
pElevationType, sizeof(TOKEN_ELEVATION_TYPE), &dwSize))
{
// 创建一个管理员SID
BYTE adminSID[SECURITY_MAX_SID_SIZE];
dwSize = sizeof(adminSID);
CreateWellKnownSid(WinBuiltinAdministratorsSid, NULL, &adminSID,
&dwSize);
if (*pElevationType == TokenElevationTypeLimited)
{
//通过Filter Token来获得原始的Token
HANDLE hUnfilteredToken = NULL;
//TokenLinkedToken标志,表示要获得Filter Token的原始Token。
GetTokenInformation(hToken, TokenLinkedToken, (VOID*)
&hUnfilteredToken, sizeof(HANDLE), &dwSize);
// 检查原始Token中,管理员账户adminSID是否被激活,如果被激活,那么说明启动这个
//程序的帐号是管理员帐号,否则不是。
if (CheckTokenMembership(hUnfilteredToken, &adminSID, pIsAdmin))
//这个CheckTokenMembership函数,结果被保存在pIsAdmin参数中,而这个函数的返回值
//只是表示,这个函数是否成功。
{
bResult = TRUE;
}
// 不要忘了关闭原始令牌。
CloseHandle(hUnfilteredToken);
}
else //如果是原始令牌,只要IsUsrAndmin就可以确定,启动当前程序的帐号是否是管理员帐号。
{
*pIsAdmin = IsUserAnAdmin();
bResult = TRUE;
}
}
// 不要忘了关闭进程令牌。
CloseHandle(hToken);
return(bResult);
}
int _tmain()
{
TOKEN_ELEVATION_TYPE Type;
BOOL IsAdmin;
BOOL re=GetProcessElevation(&Type, &IsAdmin);
if(re)
{
_tprintf(L"%d,Type");
if(IsAdmin)
_tprintf(L"on Admin running!\n");
else
_tprintf(L"on normal acount running!\n");
}
_gettchar();
return 0;
}
权限提升总结
- 先通过GetTokenInformation函数来确定,当前程序的令牌是否为Filter Token。
- 如果是,那么通过GetTokenInformation函数,来获得Filter Token的原始令牌。
- 在获得原始令牌后,通过CheckTokenMembership函数,确认在原始令牌中,有管理员的帐号,如果有,那么说明启动当前程序的账户是管理员帐号,否则就不是。
CheckTokenMembership确认一个SID是否在一个Token中可用。 - 如果不是Filter Token,那么直接使用IsUserAnAdmin函数,来确定启动当前程序的帐号,是否为管理员帐号。
提升进程权限的方法
#include<Windows.h>
#include<tchar.h>
//这个函数,将进程权限提升成具有调试权限的进程,这个权限应该是进程
//所能具有的最大权限。
//这个函数成功的前提,必须是,启动这个进程的帐号必须是管理员帐号。
//当fEnable=TRUE的时候,授予当前进程调试权限
//当fEnable=FALSE的时候,取消当前进程调试权限。
//当函数返回TRUE时,说明权限调整成功,否则失败。
BOOL EnableDebugPrivilege(BOOL fEnable)
{
//调试权限可以让该进程能够读取其他进程的信息。
BOOL fOk = FALSE; // Assume function fails
HANDLE hToken;
// 获取当前进程的令牌!
//这个函数第一个参数是当前进程句柄,第二个参数是:进程对获得的令牌,有那些操作
//权限。
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES,
&hToken)) {
//开始激活当前令牌的调试权限。
TOKEN_PRIVILEGES tp;//结构体,表示令牌权限
/*
typedef struct _TOKEN_PRIVILEGES {
DWORD PrivilegeCount;
//这个结构体,有几个权限,也就是第二个成员变量Privaileges数组,有几个元素。
LUID_AND_ATTRIBUTES Privileges[ANYSIZE_ARRAY];
} TOKEN_PRIVILEGES, *PTOKEN_PRIVILEGES;
typedef struct _LUID_AND_ATTRIBUTES {
LUID Luid;//本地唯一标识符。不可能重复的一个数组。这个东西和GUID是一个东西
DWORD Attributes;//权限属性。
} LUID_AND_ATTRIBUTES, *PLUID_AND_ATTRIBUTES;
*/
tp.PrivilegeCount = 1;//此时我们值启动调试权限,所以是1
//下面一个函数,查找调试权限的LUID,如果第一个参数是NULL,表示获取本地
//的某个权限的LUID
LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid);
//上面的LookupPrivilegeValue函数,获取本地系统的调试权限的LUID。
//下面一句话,在tp.Privileges[0].Attributes属性中,设置是开启这个权限,还是
//关闭这个权限。
tp.Privileges[0].Attributes = fEnable ? SE_PRIVILEGE_ENABLED : 0;
//当Attributes=SE_PRIVILEGE_ENABLE时,激活权限
//当Attributes=0时,关闭权限。
AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL);
//AdjustTokenPrivileges激活或者关闭tp中给定的权限。
fOk = (GetLastError() == ERROR_SUCCESS);//确实激活是否成功。
CloseHandle(hToken);
}
return(fOk);
}
//int _tmain() //能够看到启动的黑框
int _tWinMain(HINSTANCE,HINSTANCE,TCHAR*,int) //如果使用_tWinMain函数,用户看不到启动的黑框
{
if(EnableDebugPrivilege(TRUE))
{
_tprintf(L"Enable Debug privilege is ok!\n");
}
else
{
_tprintf(L"Enable Debug privilege is Failure!\n");
}
EnableDebugPrivilege(FALSE);
//////////////////////////////////////////////
//以管理员身份启动某一个程序
SHELLEXECUTEINFO ShExecInfo = {0};
ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
ShExecInfo.hwnd = NULL;
ShExecInfo.lpVerb = L"runas"; //这个参数设置,就是让ShellExecuteEx函数
//启动的进程,不要使用过滤令牌。
ShExecInfo.lpFile = L"cmd"; //这个就是你要启动的程序的绝对路径
ShExecInfo.lpParameters = L"";
ShExecInfo.lpDirectory = NULL;
ShExecInfo.nShow = SW_SHOW; //如果这个参数不设置,那么你看不见被启动程序的
//窗口。
ShExecInfo.hInstApp = NULL;
ShellExecuteEx(&ShExecInfo);
_fgettchar();
return 0;
}
代码运行结果