我尝试使用以下代码使用InitiateShutdown API重新启动远程计算机,但它失败并显示RPC_S_SERVER_UNAVAILABLE
或1722
错误代码:
//Process is running as administrator
//Select a remote machine to reboot:
//INFO: Tried it with and w/o two opening slashes.
LPCTSTR pServerName = L"192.168.42.105";
//Or use 127.0.0.1 if you don't have access to another machine on your network.
//This will attempt to reboot your local machine.
//In that case make sure to call shutdown /a /m \\127.0.0.1 to cancel it.
if(AdjustPrivilege(NULL, L"SeShutdownPrivilege", TRUE) &&
AdjustPrivilege(pServerName, L"SeRemoteShutdownPrivilege", TRUE))
{
int nErrorCode = ::InitiateShutdown(pServerName, NULL, 30,
SHUTDOWN_INSTALL_UPDATES | SHUTDOWN_RESTART, 0);
//Receive nErrorCode == 1722, or RPC_S_SERVER_UNAVAILABLE
}
BOOL AdjustPrivilege(LPCTSTR pStrMachine, LPCTSTR pPrivilegeName, BOOL bEnable)
{
HANDLE hToken;
TOKEN_PRIVILEGES tkp;
BOOL bRes = FALSE;
if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
return FALSE;
if(LookupPrivilegeValue(pStrMachine, pPrivilegeName, &tkp.Privileges[0].Luid))
{
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Attributes = bEnable ? SE_PRIVILEGE_ENABLED : SE_PRIVILEGE_REMOVED;
bRes = AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0);
int nOSError = GetLastError();
if(bRes)
{
if(nOSError != ERROR_SUCCESS)
bRes = FALSE;
}
}
CloseHandle(hToken);
return bRes;
}
因此,要准备运行此代码,请在this
计算机上执行以下操作,Windows 7 Pro
(就像我对Microsoft的shutdown工具所做的那样):
D1
计算机上的登录用户192.168.42.105
(this answer):NET USE \\192.168.42.105\IPC$ 1234 /USER:D1
然后在具有192.168.42.105
(每answer here with most upvotes)的远程计算机或Windows 7 Pro
上执行以下操作:
控制面板,网络和共享中心,更改高级共享设置 "私人"启用"启用文件和打印机共享"
设置以下键:
HKEY_LOCAL_MACHINE \ SOFTWARE \微软\的Windows \ CurrentVersion \政策\系统
LocalAccountTokenFilterPolicy = DWORD:1
运行secpol.msc,然后转到本地安全策略,安全设置,本地策略,用户权限分配。添加"每个人" to"强制从远程系统关闭"。 (记得在你完成测试后删除它!)
请注意,以下shutdown
命令似乎可以正常重启远程计算机:
shutdown /r /m \\192.168.42.105 /t 30
我的代码缺少什么?
修改
行。我承认我只是对InitiateShutdown
似乎没有"想要"使用远程服务器连接,而InitiateSystemShutdownEx
或InitiateSystemShutdown
完全没有问题。 (不幸的是后两者没有dwShutdownFlags
参数,我需要将SHUTDOWN_INSTALL_UPDATES
标志传递给它,这导致了我的持久性......)
在这一点上,除了WinDbg的副本之外,我没有别的方法可以找到它......我还在试图深入研究它,但到目前为止,这是我发现的......
(A)事实证明InitiateSystemShutdownEx
内部使用完全不同的RPC调用。没有太多细节,它使用以下参数启动与RpcStringBindingComposeW的RPC绑定:
ObjUuid = NULL
ProtSeq = ncacn_np
NetworkAddr = \\192.168.42.105
EndPoint = \\PIPE\\InitShutdown
Options = NULL
或以下绑定字符串:
ncacn_np:\\\\192.168.42.105[\\PIPE\\InitShutdown]
(B)另一方面,InitiateShutdown
使用以下绑定参数:
ObjUuid = 765294ba-60bc-48b8-92e9-89fd77769d91
ProtSeq = ncacn_ip_tcp
NetworkAddr = 192.168.42.105
EndPoint = NULL
Options = NULL
它后来转换为以下绑定字符串:
ncacn_np:\\\\192.168.42.105[\\PIPE\\lsarpc]
它用于获取传递给WsdrInitiateShutdown的RPC句柄(似乎有own specification):
如您所见,InitiateShutdown
调用在技术上被视为Unknown RPC service
(对于UUID {765294ba-60bc-48b8-92e9-89fd77769d91}
),后来在服务器和客户端之间进行了大量的凭据检查:
老实说,我不确定我是否想要使用低级调试器:)
在这个阶段,我会说我不太熟悉地方安全局"接口(或\PIPE\lsarpc
命名管道配置。)因此,如果有人知道服务器端缺少什么配置以允许此RPC调用通过,我将不胜感激,如果你可以发布你的服务吗?