我在c ++中设计了一个窗口服务(S1),它可以远程启动或停止服务。 当我将此作为一个进程运行时,此服务正常工作。 但是当我将其添加到服务管理器并在本地系统帐户下运行时,它无法工作,在这种情况下,OpenSCManager返回0(访问被拒绝)。
int main(int argc, char* argv[])
{
//this is sample code not complete service code//
char *premote_server= "192.168.122.100";
ImpersonateUser();
//access service control manager
SC_HANDLE hSCM = ::OpenSCManager(premote_server,
SERVICES_ACTIVE_DATABASE,
SC_MANAGER_ALL_ACCESS);
DWORD dwError = GetLastError(); //dwError is 5 which is Acess is denied.
if (hSCM == 0)
{
printf("ERROR: UNABLE TO OPEN SERVICE MANAGER\n");
PrintError(GetLastError());
return;
}
StopSvc(hSCM, 'servicename');
::CloseServiceHandle(hSCM);
delete[] pName;
return 0;
}
void ImpersonateUser()
{
//prepare to access remote system
DWORD id = GetCurrentProcessId();
HANDLE hp = OpenProcess(PROCESS_ALL_ACCESS, FALSE, id);
HANDLE t;
BOOL b = OpenProcessToken( hp,
TOKEN_QUERY | TOKEN_DUPLICATE ,
&t);
if(!ImpersonateLoggedOnUser(t))
{
PrintError(GetLastError());
return;
}
CloseHandle(hp); //close handle
CloseHandle(t);
}
void StopSvc(SC_HANDLE hSCM,, char *szSvcName)
{
SC_HANDLE hService = ::OpenService(hSCM,
szSvcName,
SERVICE_STOP);
if (hService == NULL)
{
printf("ERROR: COULDN'T OPEN SERVICE\n");
return;
}
SERVICE_STATUS status;
if(!::ControlService(hService,
SERVICE_CONTROL_STOP,
&status))
printf("ERROR: COULDN'T STOP SERVICE\n");
::CloseServiceHandle(hService);
QuerySvc(szNetworkName, szSvcName);
}
注意: 1.我对本地系统和远程系统拥有管理员权限。 2.由于其他功能,我无法更改服务登录属性。 3.我正在使用Visual Studio 2015进行开发。
答案 0 :(得分:1)
我拥有远程系统的管理员权限
但远程系统如何知道这一点?您需要以某种方式首先使用用户名/密码连接到远程计算机上的\IPC$
资源。这可以通过NetUseAdd
.try代码完成,例如:
#include <Lm.h>
ULONG RemoteTest(PCWSTR lpMachineName, PCWSTR username, PCWSTR password, PCWSTR lpServiceName)
{
USE_INFO_2 ui = {
0, 0, (PWSTR)password, 0, USE_IPC, 0, MAXDWORD, (PWSTR)username
};
ui.ui2_remote = (PWSTR)alloca((wcslen(lpMachineName) + 8) *sizeof(WCHAR));
swprintf(ui.ui2_remote, L"\\\\%s\\IPC$", lpMachineName);
ULONG ParmError, err;
if (!(err = NetUseAdd(0, 2, (PBYTE)&ui, &ParmError)))
{
BOOL fOk = FALSE;
if (SC_HANDLE hSCM = OpenSCManager(lpMachineName, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS))
{
if (SC_HANDLE hService = OpenService(hSCM, lpServiceName, SERVICE_START|SERVICE_STOP|SERVICE_INTERROGATE|SERVICE_QUERY_STATUS ))
{
SERVICE_STATUS ss;
fOk = QueryServiceStatus(hService, &ss);
//StartService(hService, 0, 0);
//ControlService(hService, SERVICE_CONTROL_STOP, &ss);
CloseServiceHandle(hService);
}
CloseServiceHandle(hSCM);
}
if (!fOk)
{
err = GetLastError();
}
NetUseDel(0, ui.ui2_remote, USE_LOTS_OF_FORCE);
}
return err;
}
// RemoteTest(L"192.168.122.100", L"Administrator", L"***", L"***");
关于你的void ImpersonateUser()
- 起初它毫无意义(模仿当前进程令牌的线程),不需要打开当前进程句柄,但可以使用常量伪句柄GetCurrentProcess
或NtCurrentProcess()
宏。而这一切都没有任何影响。对于prepare to access remote system
- 您需要NetUseAdd
来电
答案 1 :(得分:0)
如果您在域环境中,则可以按照this answer.中的说明更改目标计算机上的服务权限。简短版本是权限需要明确授予访问权限以启动和停止向用户提供服务有问题的帐户。
在这种情况下,您需要授予对源计算机的域帐户的访问权限。计算机域帐户采用COMPUTERNAME$
形式。