Vista/Win7中绕过UAC自启动

转载自:http://www.shily.net/topic/bypassing-uac-since-the-launch-on-vista-win7/#more-136


在开启了UAC的Vista/Win7/windows server 2008 等系统上,如果程序使用manifest进行了提权(requireAdministrator),程序在启动的时候系统会弹出一个全局的对话框,提示用户是否允许启动并并赋予管理员权限,点击确定后才能启动动程序。
但是如果是在程序自启动的情况下,就不一样了,UAC会直接拦截掉软件自启动,当然也不会弹那个全局对话框,难道需要管理员权限的软件就不能自启动了?
答案肯定是否定的,下面具体分析一下。
我们知道,不要管理员权限的程序是可以自启动的,manifest里面是像这样的:


<requestedPrivileges>;
<requestedExecutionLevel level="asInvoker" uiAccess="false" />;
</requestedPrivileges>


然而开机后我们是可以手动右键点击程序“以管理员身份运行”的,麻烦的就是需要手工点击一下,程序猿不就是喜欢自动化嘛,我们可以用程序来实现这个手动点击的过程。
大致过程和方法如下:
程序编译不使用manifest进行提权,然后使用注册表或者把快捷方式复制到启动目录等方法实现自启动,启动后的程序是没有管理员权限的,需要模拟用户以管理员权限启动的过程,可以使用ShellExecuteEx来实现,然后没有管理员权限的进程退出,以管理员权限启动的程序执行程序自身的其他逻辑。

实现代码如下:

const TCHAR *szUAC_EventNamt = _T("Global\\{AFC38980-3658-4694-34DC-6A0437995ACD}");//
//
// 注意:
//  *** 在有单实例要求的程序中,此函数必须在检测多进程之前调用,否则无法重启子进程! ***
//
//返回 TRUE 则继续运行
//  FALSE 则退出进程
//
BOOL ElevateOnUAC(void)
{
 BOOL bRet;
 TCHAR szSelfPath[MAX_PATH];
 TCHAR *lpszCommandLine;
 HANDLE hUAC_Event;
 DWORD dwLastErr;
 
 SHELLEXECUTEINFO sei = {0};
 SECURITY_ATTRIBUTES sa;
 sa.nLength = sizeof(sa);
 sa.bInheritHandle = TRUE;
 sa.lpSecurityDescriptor = NULL;
 
 ::SetLastError(ERROR_SUCCESS);
 hUAC_Event = ::CreateEvent(NULL, TRUE, FALSE, szUAC_EventNamt);//创建一个事件
 dwLastErr = ::GetLastError();
 
 if(hUAC_Event == NULL)//失败
 {
  _stprintf_s(szSelfPath, _countof(szSelfPath), _T("CreateEvent return NULL !  真失败...\r\nLastError = %d"), hUAC_Event, dwLastErr);
  ::MessageBox(NULL, szSelfPath, _T("Bug!"), MB_ICONERROR);
  return FALSE;//创建个事件都失败, 退出程序
 }
 
 if(ERROR_ALREADY_EXISTS != dwLastErr)//避免多次创建进程, 进入死循环
 {
  if(!IsUserAnAdmin() && IsEnableUAC())
  {
   ::GetModuleFileName(NULL, szSelfPath, MAX_PATH);
 
   //这里是为了把参数传给被提权的进程
   lpszCommandLine = ::GetCommandLine();// may be like ["c:\p f\a.exe" -a b /c] or [""]
   if(lpszCommandLine[0] == L'\"')
   {
    do
    {
     lpszCommandLine++;
    }while(lpszCommandLine[0] != L'\"');
    lpszCommandLine++;//pass the last quotes
 
    if(lpszCommandLine[0] == L' ')//如果有参数,那么这里会有个空格
    {
     lpszCommandLine++;
    }
   }
   else
   {
    while(lpszCommandLine[0] != L' ')// space
    {
     lpszCommandLine++;
    }
    lpszCommandLine++;//pass the last space
   }
 
   sei.cbSize = sizeof(SHELLEXECUTEINFO);
   sei.nShow = SW_SHOW;
   sei.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI;
   sei.lpFile = szSelfPath;
   sei.lpVerb = _T("runas");
   sei.lpParameters = lpszCommandLine;
   sei.lpDirectory  = NULL;
 
   bRet = ::ShellExecuteEx(&sei);
   if(bRet)
   {
    //::CloseHandle(sei.hProcess);
   }
   else
   {
    //启动失败, 可能是用户点击了取消, 设置事件让本程序退出
    ::SetEvent(hUAC_Event);
   }
   bRet = FALSE;//返回FALSE, 退出程序
  }
  else
   bRet = TRUE;//已经获得管理员权限 或者 没开启UAC 继续运行
 }
 else//已经存在这个事件, 表示是子进程
 {
  bRet = TRUE;//子进程执行这句
 }
 
 //如果是第一个进程, 这里要等待第二个进程执行这段代码后才会退出
 //第二进程会直接设置event为有信号
 if(bRet)
 {
  ::SetEvent(hUAC_Event);
 }
 
 if(sei.hProcess)
 {
  //等待两个事件中的任意一个, 第二个进程设置事件,或者由于异常退出进程
  //如果第二个进程既没有退出,也没设置事件,那就等待超时(30秒)
  HANDLE hEvent[2] = {sei.hProcess, hUAC_Event};
  ::WaitForMultipleObjects(_countof(hEvent), hEvent, FALSE, 1000*30);
  ::CloseHandle(sei.hProcess);
  sei.hProcess = NULL;
 }
 
 //关掉句柄
 //::WaitForSingleObject(hUAC_Event, INFINITE);
 ::CloseHandle(hUAC_Event);//获得权限的进程关闭句柄
 hUAC_Event = NULL;
 
 return bRet;
}
 
BOOL IsEnableUAC(void)
{
 BOOL bEnableUAC = FALSE;
 
 OSVERSIONINFO ovi = {0};
 ovi.dwOSVersionInfoSize = sizeof(ovi);
 if (::GetVersionEx(&ovi))
 {
  // window vista or windows server 2008 or later operating system
  if ( ovi.dwMajorVersion > 5 )
  {
   HKEY hKey = NULL;
   DWORD dwType = REG_DWORD;
   DWORD dwEnableLUA = 0;
   DWORD dwSize = sizeof(DWORD);
   LSTATUS lRet = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE,
    _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System\\"),
    0, KEY_READ, &hKey);
   if( ERROR_SUCCESS == lRet )
   {
    lRet = ::RegQueryValueEx(hKey, _T("EnableLUA"), NULL, &dwType, (BYTE*)&dwEnableLUA, &dwSize);
    ::RegCloseKey(hKey);
 
    if( ERROR_SUCCESS == lRet )
    {
     bEnableUAC = (dwEnableLUA) ? TRUE : FALSE;
    }
   }
  }
 }
 
 return bEnableUAC;
}


使用方法比较简单,只需要在程序的入口处调用ElevateOnUAC()函数就OK了,返回假就退出进程,返回真就继续执行。
我在这里用了一个Event来控制了一下,避免重复启动进程的错误,如果要使用这段代码,这个Event名字要自己改一下哦···

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值