参考网站为:
http://blog.youkuaiyun.com/woshisadshiwo/article/details/6853564
http://blog.youkuaiyun.com/woshinia/article/details/7850295
http://blog.youkuaiyun.com/xieqidong/article/details/2936771
1. com相关
使用atl的com 选择服务器类型的,工程为vs2008 ,com service相关命令 demoname.exe /Service , net start demoname,net stop demoname,demoname.exe /UnRegServer
在class CNoUacComModule : public CAtlServiceModuleT< CNoUacComModule, IDS_SERVICENAME >下面添加下列代码
//修改服务的进程安全设置
HRESULT InitializeSecurity() throw()
{
// TODO : 调用 CoInitializeSecurity 并为服务提供适当的
// 安全设置
// 建议 - PKT 级别的身份验证、
// RPC_C_IMP_LEVEL_IDENTIFY 的模拟级别
// 以及适当的非 NULL 安全说明符。
return CoInitializeSecurity( NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_NONE,
RPC_C_IMP_LEVEL_IDENTIFY, NULL, EOAC_NONE, NULL );
//return S_OK;
}
//修改服务的描述
HRESULT RegisterAppId(bool bService = false)
{
OutputDebugStringA("============= RegisterAppId ============================================== \n");
HRESULT hr = S_OK;
BOOL res = __super::RegisterAppId(bService);
if (bService)
{
if (IsInstalled())
{
OutputDebugString(m_szServiceName);
SC_HANDLE hSCM = ::OpenSCManagerW(NULL, NULL, SERVICE_CHANGE_CONFIG);
SC_HANDLE hService = NULL;
if (hSCM == NULL)
hr = AtlHresultFromLastError();
else
{
hService = ::OpenService(hSCM, m_szServiceName, SERVICE_CHANGE_CONFIG);
if (hService != NULL)
{
::ChangeServiceConfig(hService, SERVICE_NO_CHANGE,
SERVICE_AUTO_START,//修改服务为 自动启动
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
m_szServiceName); // 通过修改资源IDS_SERVICENAME 修改服务的显示名字
SERVICE_DESCRIPTION Description;
TCHAR szDescription[1024];
ZeroMemory(szDescription, 1024);
ZeroMemory(&Description, sizeof(SERVICE_DESCRIPTION));
lstrcpy(szDescription, _T("示例服务,by nanjun@ligsoft.com"));
Description.lpDescription = szDescription;
::ChangeServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION, &Description);
::CloseServiceHandle(hService);
}
else
hr = AtlHresultFromLastError();
::CloseServiceHandle(hSCM);
}
}
}
return hr;
}
HRESULT PreMessageLoop(int nShowCmd) throw()
{
HRESULT hr = __super::PreMessageLoop(nShowCmd);
// 微软的BUG
if (hr == S_FALSE)
hr = S_OK;
if (SUCCEEDED(hr))
{
// Add any custom code to initialize your service
// 这个状态一定要修改,否则会出现1053错误,
// 这个错误我花了很多时间才搞定
SetServiceStatus(SERVICE_RUNNING);
}
return hr;
}
HRESULT PostMessageLoop() throw()
{
HRESULT hr = __super::PostMessageLoop();
if (SUCCEEDED(hr))
{
// Add any custom code to uninitialize your service
}
return hr;
}
void OnStop() throw()
{
__super::OnStop();
SetServiceStatus(SERVICE_STOPPED);
}
void OnPause() throw()
{
__super::OnPause();
SetServiceStatus(SERVICE_PAUSED);
}
void OnContinue() throw()
{
__super::OnContinue();
SetServiceStatus(SERVICE_RUNNING);
}
接下来切换到类属性 选择添加类(CAuthorityControl) 选择atl简单对象,添加好了之后 ,
在对应的IAuthorityControl添加函数(一定要在IAuthorityControl不要在CAuthorityControl),这样就可以供给调用方去调用了。
修改reg文件 例如:AuthorityControl.rgs
原来的为:
HKCR
{
NoUacCom.AuthorityControl.1 = s 'AuthorityControl Class'
{
CLSID = s '{9E723EF4-5251-42D4-BF8B-E2D4C9613B9A}'
}
NoUacCom.AuthorityControl = s 'AuthorityControl Class'
{
CLSID = s '{9E723EF4-5251-42D4-BF8B-E2D4C9613B9A}'
CurVer = s 'NoUacCom.AuthorityControl.1'
}
NoRemove CLSID
{
ForceRemove {9E723EF4-5251-42D4-BF8B-E2D4C9613B9A} = s 'AuthorityControl Class'
{
ProgID = s 'NoUacCom.AuthorityControl.1'
VersionIndependentProgID = s 'NoUacCom.AuthorityControl'
ForceRemove 'Programmable'
LocalServer32 = s '%MODULE%'
'TypeLib' = s '{072E3124-EA52-4903-AF11-B080578F1197}'
}
}
}
修改为:
HKCR
{
NoUacCom.AuthorityControl.1 = s 'NoUacCom'
{
CLSID = s '{9E723EF4-5251-42D4-BF8B-E2D4C9613B9A}'
}
NoUacCom.AuthorityControl = s 'NoUacCom'
{
CLSID = s '{9E723EF4-5251-42D4-BF8B-E2D4C9613B9A}'
CurVer = s 'NoUacCom.AuthorityControl.1'
}
NoRemove CLSID
{
ForceRemove {9E723EF4-5251-42D4-BF8B-E2D4C9613B9A} = s 'NoUacCom' //这个一定要和应用程序的名称一致
{
ProgID = s 'NoUacCom.AuthorityControl.1'
VersionIndependentProgID = s 'NoUacCom.AuthorityControl'
ForceRemove 'Programmable'
LocalServer32 = s '%MODULE%'
val AppID = s '%APPID%' //第一要用appid
'TypeLib' = s '{072E3124-EA52-4903-AF11-B080578F1197}'
}
}
}
HKCR 修改为上面的就可以不用启动服务了net start "service name" 只需要安装服务demoname.exe /Service 即可。
2.躲过uac
躲过uac需要服务的帮助,也就是需要上面的com service 下面是实现代码
STDMETHODIMP CAuthorityControl::LaunchAppIntoDifferentSession(BSTR filePath, LONG* ret)
{
///在服务中用管理员权限创建一个可弹出UI的进程 (这个是可以弹出窗口的) 并且可以绕过uac
HANDLE hToken = NULL;
HANDLE hTokenDup = NULL;
BOOL bSuccess = TRUE;
do
{
if(OpenProcessToken(GetCurrentProcess(),TOKEN_ALL_ACCESS,&hToken))
{
if(DuplicateTokenEx(hToken, TOKEN_ALL_ACCESS,NULL, SecurityIdentification, TokenPrimary, &hTokenDup))
{
DWORD dwSessionId = WTSGetActiveConsoleSessionId();
if(!SetTokenInformation(hTokenDup,TokenSessionId,&dwSessionId,sizeof(DWORD)))
{
printf("SetTokenInformation error !error code:%d\n",GetLastError());
bSuccess = FALSE;
break;
}
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si,sizeof(STARTUPINFO));
ZeroMemory(&pi,sizeof(PROCESS_INFORMATION));
si.cb = sizeof(STARTUPINFO);
si.lpDesktop = _T("WinSta0\\Default");
si.wShowWindow = SW_SHOW;
si.dwFlags = STARTF_USESHOWWINDOW /*|STARTF_USESTDHANDLES*/;
LPVOID pEnv = NULL;
DWORD dwCreationFlag = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT;
if(!CreateEnvironmentBlock(&pEnv,hTokenDup,FALSE))
{
printf("CreateEnvironmentBlock error !error code:%d\n",GetLastError());
bSuccess = FALSE;
break;
}
LPCWSTR szfilePath = static_cast<LPCWSTR>(filePath);
if(!CreateProcessAsUser(hTokenDup,szfilePath,NULL,NULL,NULL,FALSE,dwCreationFlag,pEnv,NULL,&si,&pi))
{
printf("CreateProcessAsUser error !error code:%d\n",GetLastError());
bSuccess = FALSE;
break;
}
if(pEnv)
{
DestroyEnvironmentBlock(pEnv);
}
}
else
{
printf("DuplicateTokenEx error !error code:%d\n",GetLastError());
bSuccess = FALSE;
break;
}
}
else
{
printf("cannot get administror!error code:%d\n",GetLastError());
bSuccess = FALSE;
break;
}
}while(0);
if(hTokenDup != NULL && hTokenDup != INVALID_HANDLE_VALUE)
CloseHandle(hTokenDup);
if(hToken != NULL && hToken != INVALID_HANDLE_VALUE)
CloseHandle(hToken);
if (bSuccess)
{
*ret = 0;
}
else
{
*ret = 1;
}
}
还有一种方式也可以躲过uac 但是不能弹出ui
PROCESS_INFORMATION pi;
STARTUPINFO si;
BOOL bResult = FALSE;
DWORD dwSessionId,winlogonPid;
HANDLE hUserToken,hUserTokenDup,hPToken,hProcess;
DWORD dwCreationFlags;
dwSessionId = WTSGetActiveConsoleSessionId();
//////////////////////////////////////////
//查找winlogon进程
////////////////////////////////////////
PROCESSENTRY32 procEntry;
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnap == INVALID_HANDLE_VALUE)
{
return 1 ;
}
procEntry.dwSize = sizeof(PROCESSENTRY32);
if (!Process32First(hSnap, &procEntry))
{
return 1 ;
}
do
{
if (_stricmp(procEntry.szExeFile, "winlogon.exe") == 0)
{
//找到winlogon进程
//确定它运行在控制台会话中
DWORD winlogonSessId = 0;
if (ProcessIdToSessionId(procEntry.th32ProcessID, &winlogonSessId)
&& winlogonSessId == dwSessionId)
{
winlogonPid = procEntry.th32ProcessID;
break;
}
}
} while (Process32Next(hSnap, &procEntry));
////////////////////////////////////////////////////////////////////////
WTSQueryUserToken(dwSessionId,&hUserToken);
dwCreationFlags = NORMAL_PRIORITY_CLASS|CREATE_NEW_CONSOLE;
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb= sizeof(STARTUPINFO);
si.lpDesktop = "winsta0//default";
ZeroMemory(&pi, sizeof(pi));
TOKEN_PRIVILEGES tp;
LUID luid;
hProcess = OpenProcess(MAXIMUM_ALLOWED,FALSE,winlogonPid);
if(!::OpenProcessToken(hProcess,TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY
|TOKEN_DUPLICATE|TOKEN_ASSIGN_PRIMARY|TOKEN_ADJUST_SESSIONID
|TOKEN_READ|TOKEN_WRITE,&hPToken))
{
int abcd = GetLastError();
printf("Process token open Error: %u/n",GetLastError());
}
if (!LookupPrivilegeValue(NULL,SE_DEBUG_NAME,&luid))
{
printf("Lookup Privilege value Error: %u/n",GetLastError());
}
tp.PrivilegeCount =1;
tp.Privileges[0].Luid =luid;
tp.Privileges[0].Attributes =SE_PRIVILEGE_ENABLED;
DuplicateTokenEx(hPToken,MAXIMUM_ALLOWED,NULL,
SecurityIdentification,TokenPrimary,&hUserTokenDup);
int dup = GetLastError();
//调整令牌权限
SetTokenInformation(hUserTokenDup,
TokenSessionId,(void*)dwSessionId,sizeof(DWORD));
if (!AdjustTokenPrivileges(hUserTokenDup,FALSE,&tp,sizeof(TOKEN_PRIVILEGES),
(PTOKEN_PRIVILEGES)NULL,NULL))
{
int abc =GetLastError();
printf("Adjust Privilege value Error: %u/n",GetLastError());
}
if (GetLastError()== ERROR_NOT_ALL_ASSIGNED)
{
printf("Token does not have the provilege/n");
}
LPVOID pEnv =NULL;
if(CreateEnvironmentBlock(&pEnv,hUserTokenDup,TRUE))
{
dwCreationFlags|=CREATE_UNICODE_ENVIRONMENT;
}
else
pEnv=NULL;
//在用户登录的会话中启动进程
bResult = CreateProcessAsUser(
hUserTokenDup, //用户的访问令牌
_T("C://SessionLauncher//a.exe"), //要执行的文件
NULL, //命令行
NULL, //进程指针SECURITY_ATTRIBUTES
NULL, //线程指针SECURITY_ATTRIBUTES
FALSE, //句柄不可继承
dwCreationFlags, //创建标志
pEnv, //指向新环境块的指针
NULL, //当前目录名
&si, //指向STARTUPINFO结构的指针
&pi //新进程的相关信息
);
int iResultOfCreateProcessAsUser = GetLastError();//此处结果应为0
//关闭所有句柄
CloseHandle(hProcess);
CloseHandle(hUserToken);
CloseHandle(hUserTokenDup);
CloseHandle(hPToken);
return 0;
}
3.测试我们的com
在测试程序里面添加引用或者是把 上面的com工程中的生成文件copy到 测试工程中
#include "..\NoUacCom\NoUacCom_i.h"
#include "..\NoUacCom\NoUacCom_i.c"
IAuthorityControl * pIAuthorit=NULL; // 我们定义的接口
// 初始化
HRESULT hr = CoInitialize(NULL);
if(FAILED(hr))
{
printf("Coinitialize failed! hr=0x%x", hr);
system("pause");
return 0;
}
// 创建COM对象
hr = CoCreateInstance(CLSID_AuthorityControl, NULL, CLSCTX_ALL,
IID_IAuthorityControl, (void **)&pIAuthorit);
if(FAILED(hr))
{
printf("create com failed! hr=0x%x", hr);
CoUninitialize();
system("pause");
return 0;
}
BSTR bstr = NULL;
bstr = SysAllocString ( runExePath.c_str() );
if ( NULL == bstr )
{
printf("SysAllocString out of memory error \r\n");
}
else
{
hr = pIAuthorit->LaunchAppIntoDifferentSession(bstr,&ret);
SysFreeString (bstr);
if(FAILED(hr))
{
printf("pIAuthorit->testFun() failed! hr=0x%x", hr);
pIAuthorit->Release();
CoUninitialize();
system("pause");
return 0;
}
}
4.下面说一下怎么测试 服务
第一种就是输出到日志文件中。
第二种就是先安装了服务,打了断点 在vs2008的 调试菜单选择 附加到进程,选择到你的进程(显示所有进程)这样就可以直接调试了 需要debug版本编译的服务