How to Reboot Programmatically? - c++

How can I reboot in c++? Is there any provision in WinSDK? What kind of rights should my program(process) have to do so?

There is the ExitWindowsEx Function that can do this. You need to pass the EWX_REBOOT (0x00000002) flag to restart the system.
Important note here (quote from MSDN):
The ExitWindowsEx function returns as soon as it has initiated the shutdown process. The shutdown or logoff then proceeds asynchronously. The function is designed to stop all processes in the caller's logon session. Therefore, if you are not the interactive user, the function can succeed without actually shutting down the computer. If you are not the interactive user, use the InitiateSystemShutdown or InitiateSystemShutdownEx function.
You can choose between the appropriate function depending on your situation.

Before calling the ExitWindowsEx function you need to enable the SE_SHUTDOWN_NAME privilege:
OpenProcessToken(GetCurrentProcess (),TOKEN_ADJUST_PRIVILEGES,...)
LookupPrivilegeValue
AdjustTokenPrivileges
CloseHandle

I presume you have a very good case for wanting to reboot a PC that may be running lots of other applications.
It sounds like you are looking for InitiateShutdown(), passing SHUTDOWN_RESTART in dwShutdownFlags.

#Anders solution would look, Not sure if this is fully functional as I wrote this a while ago and have not run it in a while. Documentation below.
https://learn.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-adjusttokenprivileges
https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-lookupprivilegevaluea
https://learn.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-initiatesystemshutdowna
void shutSystemOff(const bool &shutReboot = true)
{
// Create all required variables
int vRet = 0;
bool adjustRet;
HANDLE hToken = NULL;
LUID luid;
TOKEN_PRIVILEGES tp;
// Get LUID for current boot for current process.
OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken);
LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &luid);
// Modify and Adjust token privileges for current process.
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
adjustRet = AdjustTokenPrivileges(hToken, false, &tp, sizeof(tp), NULL, 0);
// Check if token privileges were set.
if (adjustRet)
{
// Initiates system shutdown ( Local system, Shutdown Message, Dwell time, Prompt user, Reboot )
InitiateSystemShutdownA(NULL, NULL, 0, true, shutReboot);
}
}

Related

Windows 7 Shutdown Issue / ExitWindowsEx/AdjustTokenPrivileges

Hello to all stackoverflow great minds!! I need some explanation and suggestion on how to determine what have cause this problem. I hope nobody would be harass and will judge directly. If there are not clear here please be kind to reply.
I have an application that i am investigating right now. The application will shutdown the Windows if a power-off message was posted from one of its child processes.
Scenario:
When i start the application and post a power-off message nothing happens to windows only the application was exited. The second time I start the application then post again a power off message the windows shutdown or reboot depending on the condition i had send.
HANDLE hToken;
TOKEN_PRIVILEGES tp;
OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);
LookupPrivilegeValue(NULL,
SE_SHUTDOWN_NAME, &(tp.Privileges[0].Luid));
tp.PrivilegeCount = 1;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL);
if ( iApplicationProblemOccured == 1 ){
ExitWindowsEx(EWX_FORCE | EWX_SHUTDOWN | EWX_POWEROFF, 0L);
} else {
if(wShutdownType != 1) {
ExitWindowsEx(EWX_FORCE | EWX_REBOOT, 0L);
} else {
ExitWindowsEx(EWX_FORCE | EWX_SHUTDOWN | EWX_POWEROFF, 0L);
}
}
AdjustTokenPrivileges(hToken, TRUE, &tp, sizeof(tp), NULL, NULL);
ExitProcess(0);
The problem is why the execution of the ExitWindowsEx from the first power off does not works?
I have checked the tokenpriveleges from the first poweroff but it was enabled.
I have also change the dwReason to planned in the ExitWindowsEx but nothing happens.
From what i read in
https://msdn.microsoft.com/en-us/library/windows/desktop/aa376868(v=vs.85).aspx
if the return of ExitWindowsEx is 0, it does not necessarily determines that the execution of windows shutdown will be successful because the function will only initiate the shutdown process.
I am thinking that there is something process/services that blocks stops the windows shutdown process from the first power off..
Is there a way to debug the windows shutdown process after my application send the shutdown request?
I am hoping someone can help me with this issue!!
Thanks a lot..

Trying to run user-mode process from a local service with medium integrity level

My goal is to run my user GUI process in a logged on user session from my local service. I roughly do the following:
//Pseudo-code, with error checks omitted
HANDLE hToken;
WTSQueryUserToken(dwUserSessionID, &hToken);
HANDLE hToken2;
DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, NULL, SecurityIdentification, TokenPrimary, &hToken2);
//Need to adjust UIAccess for the needs of the user process
DWORD dwUIAccess = 1;
SetTokenInformation(hToken2, TokenUIAccess, &dwUIAccess, sizeof(dwUIAccess));
ImpersonateLoggedOnUser(hToken2);
CreateProcessAsUser(hToken2, strUserExeFilePath, ...);
RevertToSelf();
CloseHandle(hToken2);
CloseHandle(hToken);
This works and the user process starts just fine, but there's one issue with its integrity level. When this code runs right after the service is installed (when the user session has been long logged on) the user process it creates has SECURITY_MANDATORY_MEDIUM_RID, which is the level I would expect.
But if the code above is run right after an interactive Windows user logs on to the workstation, the user process starts up but it has the SECURITY_MANDATORY_HIGH_RID integrity level. (I am testing it on Windows 7.)
So I thought to add the following code to adjust the integrity level:
PSID pSidIL = NULL;
//INFO on SID: https://support.microsoft.com/en-us/kb/243330?wa=wsignin1.0
ConvertStringSidToSid(L"S-1-16-8192", &pSidIL);
TOKEN_MANDATORY_LABEL tml = {0};
tml.Label.Attributes = SE_GROUP_INTEGRITY;
tml.Label.Sid = pSidIL;
SetTokenInformation(hToken2, TokenIntegrityLevel, &tml, sizeof(TOKEN_MANDATORY_LABEL) + ::GetSidLengthRequired(1));
LocalFree(pSidIL);
but it made no difference, and the user process still ran with high integrity level after a user logon.
Any idea what am I doing wrong here?

OpenProcessToken fails with ERROR_ACCESS_DENIED from a local system service

Let me explain my situation first. The issue I describe below comes from an end-user's machine, and all I have to work with is just a copy of the Windows Event Log. I cannot access the machine itself to run any debugging tests.
Now the issue. I have a service application that I create as such:
SC_HANDLE hScService = CreateService(hScManager,
L"MyServiceID",
L"My Service Name",
SERVICE_ALL_ACCESS,
SERVICE_WIN32_OWN_PROCESS,
SERVICE_AUTO_START,
SERVICE_ERROR_NORMAL,
SrvcPath,
NULL, NULL, NULL, NULL, _T(""));
The service process later has its SE_DEBUG_NAME privilege set using the AdjustTokenPrivileges API.
Later on I have a method that enumerates running processes and later gets processes LUIDs, using a code as such:
//'pProcIDs' = list of process IDs obtained from EnumProcesses()
for(UINT i = 0; i < nNumProc; i++)
{
DWORD dwProcID = pProcIDs[i];
//Skip obvious system processes
if(dwProcID != 0 &&
dwProcID != 4)
{
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwProcID);
if(hProcess)
{
HANDLE hTokenHandle;
if(::OpenProcessToken(hProcess, TOKEN_QUERY, &hTokenHandle))
{
TOKEN_STATISTICS ts;
DWORD dwcbSz = 0;
if(::GetTokenInformation(hTokenHandle, TokenStatistics, &ts, sizeof(ts), &dwcbSz))
{
//And so on...
}
else
{
//Handle error here
}
::CloseHandle(hTokenHandle);
}
else
{
//***Here's where I get my error in question***
}
::CloseHandle(hProcess);
}
else
{
//Handle error here
}
}
}
When I run the code above on my own development computers, it runs just fine. Note that those computers run "stock" copies of the OS without any AVP or other third-party software installed.
The event log copy I received from a customer running Windows 7 Professional machine (that is a member of an Active Directory domain) has 3 processes that return ERROR_ACCESS_DENIED when I call OpenProcessToken on them from the code above. Their PIDs are just regular values, such as 1824, 2760, 5024 (that obviously change after a reboot.)
Does anyone have any idea why it happens? Do I need to set additional privileges for my service?
PS. From the event log I can tell that the workstation in question has some Symantec Antivirus product installed, judging by this line:
New virus definition file loaded. Version: 140217066.
Symantec antivirus software (as well as that of many other security software vendors) may attempt to prevent tampering with their processes by un-authorized actors. Acquiring the process token for one of their processes just might qualify.
That said, you can quickly verify that the PIDs in question are in fact part of the Symantec package by examining the path to executable images that back the processes. If they are part of the Symantec AV software package, you'll need to look in to configuring it to trust your application, or disable it while you run this code (not recommended), or simply ignore errors of this type.

WinAPI: OpenProcess() returns error 5 with SeDebugPrivilege enabled for host process

I've got a routine where I process-walk to obtain the HANDLE of each process as I 'walk' down the list (which works fine), but my issue lies when I do:
HANDLE h = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pe32.th32ProcessID) where PROCESS_ALL_ACCESS is the access token, handle inheritance is set to FALSE, and pe32 is a PROCESSENTRY32
GetLastError() returns error code 5, and all the handles that are made are addresses which do not correspond to any appropriate process in Spy++32/64 (I've tried building the application under both platform targets, but as you'd expect, the result is the same).
The code for setting SeDebugPrivilege for the host process which I'm using is:
BOOL EnableDebugPrivilege(BOOL bEnable)
{
HANDLE hToken = nullptr;
LUID luid;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) return FALSE;
if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid)) return FALSE;
TOKEN_PRIVILEGES tokenPriv;
tokenPriv.PrivilegeCount = 1;
tokenPriv.Privileges[0].Luid = luid;
tokenPriv.Privileges[0].Attributes = bEnable ? SE_PRIVILEGE_ENABLED : 0;
if (!AdjustTokenPrivileges(hToken, FALSE, &tokenPriv, sizeof(TOKEN_PRIVILEGES), NULL, NULL)) return FALSE;
return TRUE;
}
Some questions that would be helpful to you:
I'm running Windows 7 x64 Professional.
Yes, devenv.exe is started with "Run as Administrator" privileges, which means that the debugger and the application itself are started under the same affinity.
I have tried toggling UAC or running the application with UAC off altogether. Still error code 5.
I just attempted doing it with PROCESS_QUERY_LIMITED_INFORMATION and I receive error code 6, or ERROR_INVALID_HANDLE. Also attempted with PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, result is error 5 again.
SeDebugPrivilege is enabled, verified with SysInternals' Process Explorer. Additionally, all processes that spawn from devenv/whatever the debugger is called inherit SeDebugPrivilege so...this is weird.
Thank you all very much for your time, I'm reaching wits end with this issue :S
Are you sure you are not passing 0 as a process ID value? The system idle process with ID 0 is included in the snapshot under the name [System Process], but you can't open a handle for it as the documentation for OpenProcess specifically says it'll fail. Well it says a bit more:
If the specified process is the System Process (0x00000000), the
function fails and the last error code is ERROR_INVALID_PARAMETER. If
the specified process is the Idle process or one of the CSRSS
processes, this function fails and the last error code is
ERROR_ACCESS_DENIED because their access restrictions prevent
user-level code from opening them.
Well, it's not completely true as I was able to open handle to CSRSS (of course, it doesn't actually have the requested rights). But it may fail for some protected processes (audiodg), so you shouldn't not do this. Instead, check the name of the process if it's the one you want.

How to turn off pc via windows API?

I never programmed a winapi so i have a little problem here .
I need turn off my pc from my application .
I found this example link text then i found this example how to change privileges link text
But i have problem how to get that parameter HANDLE hToken // access token handle
I think i need to make it in the next order to get the parameter
OpenProcessToken LookupPrivilegeValue AdjustTokenPrivileges
but there are a lot parameters that i have no idea what to do with them .
maybe you have jere some example how i get that HANDLE hToken parameter to make that work .
By the way I already saw the following post link text
Thanks a lot all you .
// ==========================================================================
// system shutdown
// nSDType: 0 - Shutdown the system
// 1 - Shutdown the system and turn off the power (if supported)
// 2 - Shutdown the system and then restart the system
void SystemShutdown(UINT nSDType)
{
HANDLE hToken;
TOKEN_PRIVILEGES tkp ;
::OpenProcessToken(::GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, &hToken);
::LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid);
tkp.PrivilegeCount = 1 ; // set 1 privilege
tkp.Privileges[0].Attributes= SE_PRIVILEGE_ENABLED;
// get the shutdown privilege for this process
::AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0);
switch (nSDType)
{
case 0: ::ExitWindowsEx(EWX_SHUTDOWN|EWX_FORCE, 0); break;
case 1: ::ExitWindowsEx(EWX_POWEROFF|EWX_FORCE, 0); break;
case 2: ::ExitWindowsEx(EWX_REBOOT |EWX_FORCE, 0); break;
}
}
You could use ShellExecute() to call shutdown.exe
This is a bit much for the comments on Daniel's answer, so I'll put it here.
It looks like your main issue at this point is that your process isn't running with the priveleges required to perform a system shutdown.
The docs for ExitWindowsEx contain this line:
To shut down or restart the system,
the calling process must use the
AdjustTokenPrivileges function to
enable the SE_SHUTDOWN_NAME privilege.
For more information, see Running with
Special Privileges.
They also have some example code. In a pinch, you can just copy that.
http://msdn.microsoft.com/en-us/library/aa376868(VS.85).aspx
Try
ExitWindowsEx(EWX_POWEROFF, 0);
#include<iostream>
using namespace std;
int main(){
system("shutdown -s -f -t 0");
}
Some working code for InitiateSystemShutdownEx:
// Get the process token
HANDLE hToken;
OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
&hToken);
// Build a token privilege request object for shutdown
TOKEN_PRIVILEGES tk;
tk.PrivilegeCount = 1;
tk.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
LookupPrivilegeValue(NULL, TEXT("SeShutdownPrivilege"), &tk.Privileges[0].Luid);
// Adjust privileges
AdjustTokenPrivileges(hToken, FALSE, &tk, 0, NULL, 0);
// Go ahead and shut down
InitiateSystemShutdownEx(NULL, NULL, 0, FALSE, FALSE, 0);
So far as I can tell, the advantage to this over the ExitWindowsEx solution is that the calling process does not need to belong to the active user.