I created a small windows service to capture some events, including the system shutdown. Every time I turn off the computer, the service event is not called. But when I restart the computer the event works normally.
I already tried to use: SERVICE_ACCEPT_PRESHUTDOWN + SERVICE_CONTROL_PRESHUTDOWN and was not successful.
How could I catch the computer shutdown event?
Ps: After compiling I register the service with the following command: sc.exe create "ZSimpleService" binPath = "C:\path\ZSimpleService.exe"
Edit 1: I'm using windows 10
Code:
SERVICE_STATUS g_ServiceStatus = { 0 };
SERVICE_STATUS_HANDLE g_StatusHandle = NULL;
HANDLE g_ServiceStopEvent = INVALID_HANDLE_VALUE;
VOID WINAPI ServiceMain(DWORD argc, LPTSTR *argv);
DWORD WINAPI ServiceWorkerThread(LPVOID lpParam);
DWORD WINAPI CtrlHandlerEx(DWORD CtrlCode, DWORD eventType, LPVOID eventData, LPVOID context);
#define SERVICE_NAME _T("ZSimpleService")
VOID WINAPI ServiceMain(DWORD argc, LPTSTR *argv) {
g_StatusHandle = RegisterServiceCtrlHandlerEx(SERVICE_NAME, CtrlHandlerEx,
NULL);
if (g_StatusHandle == NULL) {
goto EXIT;
}
// Tell the service controller we are starting
ZeroMemory( & g_ServiceStatus, sizeof(g_ServiceStatus));
g_ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP
| SERVICE_ACCEPT_POWEREVENT | SERVICE_ACCEPT_SESSIONCHANGE
| SERVICE_ACCEPT_SHUTDOWN;
g_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwServiceSpecificExitCode = 0;
g_ServiceStatus.dwCheckPoint = 0;
if (SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE) {
//...
}
g_ServiceStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (g_ServiceStopEvent == NULL) {
//...
goto EXIT;
}
g_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwCheckPoint = 0;
if (SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE) {
//...
}
HANDLE hThread = CreateThread(NULL, 0, ServiceWorkerThread, NULL, 0, NULL);
WaitForSingleObject(hThread, INFINITE);
CloseHandle(g_ServiceStopEvent);
g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwCheckPoint = 3;
if (SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE) {
}
EXIT: return;
}
void suspending() {
FILE *file = fopen("C:\\test\\suspending.txt", "w+");
if (file)
fprintf(file, "...");
}
void logoff() {
FILE *file = fopen("C:\\test\\logoff.txt", "w+");
if (file)
fprintf(file, "...");
}
void lock_session() {
FILE *file = fopen("C:\\test\\lock_session.txt", "w+");
if (file)
fprintf(file, "...");
}
void poweroff() {
FILE *file = fopen("C:\\test\\poweroff.txt", "w+");
if (file)
fprintf(file, "...");
}
DWORD WINAPI CtrlHandlerEx(DWORD CtrlCode, DWORD eventType, LPVOID eventData,
LPVOID context) {
switch (CtrlCode) {
case SERVICE_CONTROL_STOP: {
g_ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwCheckPoint = 0;
g_ServiceStatus.dwWaitHint = 0;
if (SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE) {
//...
}
SetEvent(g_ServiceStopEvent);
return NO_ERROR;
}
case SERVICE_CONTROL_POWEREVENT: {
if (eventType == PBT_APMQUERYSUSPEND) {
//Computer is suspending
suspending();
}
return NO_ERROR;
}
case SERVICE_CONTROL_SESSIONCHANGE: {
switch (eventType) {
case WTS_SESSION_LOGOFF:
//User is logging off
logoff();
break;
case WTS_SESSION_LOCK:
//User locks the session
lock_session();
break;
}
return NO_ERROR;
}
case SERVICE_CONTROL_SHUTDOWN: {
//Computer is shutting down
poweroff();
return NO_ERROR;
}
default:
return ERROR_CALL_NOT_IMPLEMENTED;
}
}
DWORD WINAPI ServiceWorkerThread(LPVOID lpParam) {
while (WaitForSingleObject(g_ServiceStopEvent, 0) != WAIT_OBJECT_0) {
//many cool code....
Sleep(3000);
}
return 0;
}
DWORD RunService() {
SERVICE_TABLE_ENTRY serviceTable[] = { { SERVICE_NAME, ServiceMain },
{ 0, 0 } };
if (StartServiceCtrlDispatcher(serviceTable)) {
return 0;
} else {
DWORD erro = GetLastError();
//handler erro...
return 1;
}
}
int _tmain(int argc, TCHAR *argv[]) {
RunService();
return 0;
}
When the fast startup option enabled, click start menu -> shutdown will put the machine into sleep mode/hibernation instead of shutdown. But restart menu isn't affected. (And shuting down from command line isn't affected too as we already found.)
So you can disable fast startup to solve this issue.
Related
I'm creating service for Windows 10. I've followed this tutorial. https://www.codeproject.com/Articles/499465/Simple-Windows-Service-in-Cplusplus
But when I've added my code to this example, something happened and I can't stop service from Services list. I can stop it only from task manager. But if I comment my code, service stopping properly.
I would be grateful for any advice. Code listed below.
#include <Windows.h>
#include <tchar.h>
#include <string>
#include <fstream>
SERVICE_STATUS g_ServiceStatus = { 0 };
SERVICE_STATUS_HANDLE g_StatusHandle = NULL;
HANDLE g_ServiceStopEvent = INVALID_HANDLE_VALUE;
std::wofstream output(L"C:\\Users\\0x0\\source\\Service\\output.txt");
VOID WINAPI ServiceMain(DWORD argc, LPTSTR *argv);
VOID WINAPI ServiceCtrlHandler(DWORD);
DWORD WINAPI ServiceWorkerThread(LPVOID lpParam);
#define SERVICE_NAME _T("TestService")
DWORD WINAPI ServiceWorkerThread(LPVOID lpParam)
{
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
auto dwFlags = FILE_ATTRIBUTE_NORMAL;
STARTUPINFOW si;
GetStartupInfoW(&si);
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
ZeroMemory(&pi, sizeof(pi));
HANDLE service_pipe = CreateNamedPipe(TEXT("\\\\.\\pipe\\ServicePipe"),
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
128,
16 * 1024,
16 * 1024,
0,
nullptr);
if (service_pipe == INVALID_HANDLE_VALUE)
{
return 1;
}
TCHAR inbox_buffer[1024];
DWORD read, write;
while (1)
{
if (WaitForSingleObject(g_ServiceStopEvent, 0) != WAIT_OBJECT_0)
{
//If I comment this 'if block', service stopping properly. But I don't see any errors in this part of code.
if (ConnectNamedPipe(service_pipe, nullptr))
{
if (ReadFile(service_pipe, inbox_buffer, 1024 * sizeof(TCHAR), &read, nullptr))
{
std::wstring args = inbox_buffer;
std::wstring command = L"\"C:\\Program Files (x86)\\Unility\\utility.exe\" " + args;
if (!CreateProcessW(NULL, (LPWSTR)command.c_str(), NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi))
{
output << "CreateProcessW Error = " << GetLastError() << std::endl;
}
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
bool success = false;
do
{
success = WriteFile(service_pipe, L"executed", sizeof(L"executed"), &write, nullptr);
} while (!success);
}
DisconnectNamedPipe(service_pipe);
}
}
else
{
output << "WaitForSingleObject(g_ServiceStopEvent, 0)" << std::endl;
break;
}
}
output << "CloseHandle(service_pipe)_1" << std::endl;
CloseHandle(service_pipe);
output << "CloseHandle(service_pipe)_2" << std::endl;
return ERROR_SUCCESS;
}
VOID WINAPI ServiceCtrlHandler(DWORD CtrlCode)
{
switch (CtrlCode)
{
case SERVICE_CONTROL_STOP:
if (g_ServiceStatus.dwCurrentState != SERVICE_RUNNING)
break;
g_ServiceStatus.dwControlsAccepted = 0;
g_ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwCheckPoint = 4;
if (SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE)
{
output << "TestService: ServiceCtrlHandler: SetServiceStatus returned error" << std::endl;
}
SetEvent(g_ServiceStopEvent);
output << "SetEvent(g_ServiceStopEvent)_1" << std::endl;
break;
default:
break;
}
output << "SetEvent(g_ServiceStopEvent)_2" << std::endl;
}
VOID WINAPI ServiceMain(DWORD argc, LPTSTR *argv)
{
DWORD Status = E_FAIL;
g_StatusHandle = RegisterServiceCtrlHandler(SERVICE_NAME, ServiceCtrlHandler);
if (g_StatusHandle == NULL)
{
return;
}
ZeroMemory(&g_ServiceStatus, sizeof(g_ServiceStatus));
g_ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
g_ServiceStatus.dwControlsAccepted = 0;
g_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwServiceSpecificExitCode = 0;
g_ServiceStatus.dwCheckPoint = 0;
if (SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE)
{
output << "TestService: ServiceMain: SetServiceStatus returned error" << std::endl;
}
g_ServiceStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (g_ServiceStopEvent == NULL)
{
g_ServiceStatus.dwControlsAccepted = 0;
g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
g_ServiceStatus.dwWin32ExitCode = GetLastError();
g_ServiceStatus.dwCheckPoint = 1;
if (SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE)
{
output << "TestService: ServiceMain: SetServiceStatus returned error" << std::endl;
}
return;
}
g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
g_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwCheckPoint = 0;
if (SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE)
{
output << "TestService: ServiceMain: SetServiceStatus returned error" << std::endl;
}
HANDLE hThread = CreateThread(NULL, 0, ServiceWorkerThread, NULL, 0, NULL);
WaitForSingleObject(hThread, INFINITE);
output << "CloseHandle(g_ServiceStopEvent)_1" << std::endl;
CloseHandle(g_ServiceStopEvent);
output << "CloseHandle(g_ServiceStopEvent)_2" << std::endl;
g_ServiceStatus.dwControlsAccepted = 0;
g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwCheckPoint = 3;
if (SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE)
{
output << "TestService: ServiceMain: SetServiceStatus returned error" << std::endl;
}
return;
}
int _tmain(int argc, TCHAR *argv[])
{
SERVICE_TABLE_ENTRY ServiceTable[] =
{
{(LPWSTR)"TestService", (LPSERVICE_MAIN_FUNCTION)ServiceMain},
{NULL, NULL}
};
if (StartServiceCtrlDispatcher(ServiceTable) == FALSE)
{
return GetLastError();
}
return 0;
}
Dirty way, but it's working. I've created function which handles all job related to pipes. I've runned this function in new thread. When the service receives a stop signal, I send a stop message to the pipe and it stops the loop.
#include <Windows.h>
#include <tchar.h>
#include <string>
#include <thread>
#include <fstream>
SERVICE_STATUS g_ServiceStatus = { 0 };
SERVICE_STATUS_HANDLE g_StatusHandle = NULL;
HANDLE g_ServiceStopEvent = INVALID_HANDLE_VALUE;
VOID WINAPI ServiceMain(DWORD argc, LPTSTR *argv);
VOID WINAPI ServiceCtrlHandler(DWORD);
DWORD WINAPI ServiceWorkerThread(LPVOID lpParam);
#define SERVICE_NAME _T("TestService")
void pipe_server_function() {
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
auto dwFlags = FILE_ATTRIBUTE_NORMAL;
STARTUPINFOW si;
GetStartupInfoW(&si);
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
ZeroMemory(&pi, sizeof(pi));
HANDLE service_pipe = CreateNamedPipe(TEXT("\\\\.\\pipe\\ServicePipe"),
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
128,
16 * 1024,
16 * 1024,
0,
nullptr);
if (service_pipe == INVALID_HANDLE_VALUE)
{
return;
}
TCHAR inbox_buffer[1024];
std::fill(inbox_buffer, inbox_buffer + 1024, '\0');
DWORD read, write;
while (true)
{
if (ConnectNamedPipe(service_pipe, nullptr))
{
if (ReadFile(service_pipe, inbox_buffer, 1024 * sizeof(TCHAR), &read, nullptr))
{
std::wstring args = inbox_buffer;
if (args.find("stop_signal") != std::wstring::npos)
{
DisconnectNamedPipe(service_pipe);
break;
}
std::wstring command = L"\"C:\\Program Files (x86)\\Unility\\utility.exe\" " + args;
if (!CreateProcessW(NULL, (LPWSTR)command.c_str(), NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi))
{
//CreateProcessW failed. You should log this!
}
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
bool success = false;
do
{
success = WriteFile(service_pipe, L"executed", sizeof(L"executed"), &write, nullptr);
} while (!success);
}
DisconnectNamedPipe(service_pipe);
std::fill(inbox_buffer, inbox_buffer + 1024, '\0');
}
}
CloseHandle(service_pipe);
}
DWORD WINAPI ServiceWorkerThread(LPVOID lpParam)
{
if (WaitForSingleObject(g_ServiceStopEvent, 0) != WAIT_OBJECT_0) {
Sleep(1000);
}
service::handle gsprint_pipe = CreateFile(TEXT("\\\\.\\pipe\\ServicePipe"),
GENERIC_READ | GENERIC_WRITE,
0,
nullptr,
OPEN_EXISTING,
0,
nullptr);
bool succeess = false;
DWORD read;
do
{
succeess = WriteFile(gsprint_pipe, L"stop_signal", sizeof(L"stop_signal"), &read, nullptr);
} while (!succeess);
return ERROR_SUCCESS;
}
VOID WINAPI ServiceCtrlHandler(DWORD CtrlCode)
{
switch (CtrlCode)
{
case SERVICE_CONTROL_STOP:
if (g_ServiceStatus.dwCurrentState != SERVICE_RUNNING)
break;
g_ServiceStatus.dwControlsAccepted = 0;
g_ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwCheckPoint = 4;
if (SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE)
{
//SetServiceStatus failed. You should log this!
}
SetEvent(g_ServiceStopEvent);
break;
default:
break;
}
}
VOID WINAPI ServiceMain(DWORD argc, LPTSTR *argv)
{
DWORD Status = E_FAIL;
g_StatusHandle = RegisterServiceCtrlHandler(SERVICE_NAME, ServiceCtrlHandler);
if (g_StatusHandle == NULL)
{
return;
}
ZeroMemory(&g_ServiceStatus, sizeof(g_ServiceStatus));
g_ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
g_ServiceStatus.dwControlsAccepted = 0;
g_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwServiceSpecificExitCode = 0;
g_ServiceStatus.dwCheckPoint = 0;
if (SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE)
{
//SetServiceStatus failed. You should log this!
}
g_ServiceStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (g_ServiceStopEvent == NULL)
{
g_ServiceStatus.dwControlsAccepted = 0;
g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
g_ServiceStatus.dwWin32ExitCode = GetLastError();
g_ServiceStatus.dwCheckPoint = 1;
if (SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE)
{
//SetServiceStatus failed. You should log this!
}
return;
}
g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
g_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwCheckPoint = 0;
if (SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE)
{
//SetServiceStatus failed. You should log this!
}
std::thread pipe_server(pipe_server_function);
HANDLE hThread = CreateThread(NULL, 0, ServiceWorkerThread, NULL, 0, NULL);
WaitForSingleObject(hThread, INFINITE);
pipe_server.join();
CloseHandle(g_ServiceStopEvent);
g_ServiceStatus.dwControlsAccepted = 0;
g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwCheckPoint = 3;
if (SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE)
{
//SetServiceStatus failed. You should log this!
}
return;
}
int _tmain(int argc, TCHAR *argv[])
{
SERVICE_TABLE_ENTRY ServiceTable[] =
{
{(LPWSTR)"TestService", (LPSERVICE_MAIN_FUNCTION)ServiceMain},
{NULL, NULL}
};
if (StartServiceCtrlDispatcher(ServiceTable) == FALSE)
{
return GetLastError();
}
return 0;
}
I'm trying to inject my DLL into a 64-bit process that I just created. I initially create it suspended so that I can apply WinAPI patch trampolines in that process (from my injected DLL.) But if I understand it correctly, I cannot inject my DLL into a suspended process.
So I came up with the following code, following the guy's suggestions, but it doesn't go far. The VirtualProtectEx fails and I get an error code ERROR_INVALID_ADDRESS. I marked it in the source below.
Any idea where am I messing up?
PROCESS_INFORMATION pi = {0};
STARTUPINFO si = {0};
si.cb = sizeof(si);
WCHAR buffer[MAX_PATH];
::StringCchCopy(buffer, _countof(buffer), L"injected-process.exe");
if(CreateProcessW(0, buffer, 0, 0, 0, CREATE_SUSPENDED, 0, 0, &si, &pi))
{
inject_dll_into_suspended_x64_proc(pi.hProcess, pi.hThread, "injected-process.exe");
//... continue on
}
and then the code to prep process for injection:
bool inject_dll_into_suspended_x64_proc(HANDLE hProc, HANDLE hMainThread, const char* pstrProcFileName)
{
bool bRes = false;
int nOSError = NO_ERROR;
DWORD dwEntryOffset = 0;
LOADED_IMAGE li = { 0 };
if (::MapAndLoad(pstrProcFileName, NULL, &li, FALSE, TRUE))
{
dwEntryOffset = li.FileHeader->OptionalHeader.AddressOfEntryPoint;
::UnMapAndLoad(&li);
}
if(dwEntryOffset)
{
// 90 nop
// EB FE jmp self
static BYTE inject_asm_x64[] = {
0x90,
0xEB, 0xFE,
};
BYTE buffBackup[sizeof(inject_asm_x64)] = { 0 };
//Get process base addr
BYTE* pBaseAddr = (BYTE*)::VirtualAllocEx(hProc, NULL, sizeof(buffBackup), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (pBaseAddr)
{
BYTE* pAddr = pBaseAddr + dwEntryOffset;
DWORD dwOldProtect = 0;
if (::VirtualProtectEx(hProc, pAddr, sizeof(buffBackup), PAGE_EXECUTE_READWRITE, &dwOldProtect)) //** FAILS: With error code: 487, or ERROR_INVALID_ADDRESS
{
__try
{
//Backup what we have there now
size_t szcbRead = 0;
if (::ReadProcessMemory(hProc, pAddr, buffBackup, sizeof(buffBackup), &szcbRead) &&
szcbRead == sizeof(buffBackup))
{
//Now write our code into entry point
size_t dwcbSzWrtn = 0;
if (WriteProcessMemory(hProc, pAddr, inject_asm_x64, sizeof(inject_asm_x64), &dwcbSzWrtn) &&
dwcbSzWrtn == sizeof(inject_asm_x64))
{
bool bIntermediateSuccess = false;
bool bThreadIsSuspended = true;
//Resume thread
if (ResumeThread(hMainThread) == 1)
{
bThreadIsSuspended = false;
CONTEXT context;
bool bReached = false;
//Wait for it to reach our JMP self opcode
for(;; ::Sleep(1))
{
if(!::GetThreadContext(hMainThread, &context))
{
//Failed
nOSError = ::GetLastError();
break;
}
if(context.Rip == (DWORD64)(pAddr + 1)) //First is nop, so skip it
{
//Got it
bReached = true;
break;
}
}
if(bReached)
{
//Do our DLL injection now
if(inject_dll_here(hProc))
{
//Injected OK
bIntermediateSuccess = true;
}
else
nOSError = ::GetLastError();
//Suspend main thread
if(::SuspendThread(hMainThread) == 0)
{
//Thread is again suspended
bThreadIsSuspended = true;
}
else
{
//Failed
nOSError = ::GetLastError();
bIntermediateSuccess = false;
}
}
}
else
nOSError = ::GetLastError();
if(bThreadIsSuspended)
{
//Revert process memory back
if (WriteProcessMemory(hProc, pAddr, buffBackup, sizeof(buffBackup), &dwcbSzWrtn) &&
dwcbSzWrtn == sizeof(buffBackup))
{
//Now restore the main thread
if (ResumeThread(hMainThread) == 1)
{
//Done
bRes = bIntermediateSuccess;
}
else
nOSError = ::GetLastError();
}
else
nOSError = ::GetLastError();
}
}
else
nOSError = ::GetLastError();
}
else
nOSError = ::GetLastError();
}
__finally
{
//Reset protection flags
::VirtualProtectEx(hProc, pAddr, sizeof(buffBackup), dwOldProtect, NULL);
}
}
else
nOSError = ::GetLastError();
//Free mem
::VirtualFreeEx(hProc, pBaseAddr, 0, MEM_RELEASE);
}
else
nOSError = ::GetLastError();
}
else
nOSError = ::GetLastError();
return bRes;
}
I made a service using a tutorial. How can I make it actually do something? Here's the code:
#include <windows.h>
SERVICE_STATUS serviceStatus = { 0 };
SERVICE_STATUS_HANDLE statusHandle;
HANDLE serviceStopEvent = INVALID_HANDLE_VALUE;
void WINAPI ServiceMain(DWORD argc, LPTSTR *argv);
void WINAPI ServiceCtrlHandler(DWORD);
DWORD WINAPI ServiceWorkerThread(LPVOID lParam);
#define SERVICE_NAME "Cool Service"
int main(int argc, char **argv)
{
SERVICE_TABLE_ENTRY serviceTable[] =
{
{SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION)ServiceMain},
{NULL, NULL}
};
if (!StartServiceCtrlDispatcher(serviceTable))
return GetLastError();
return 0;
}
void WINAPI ServiceMain(DWORD argc, LPTSTR *argv)
{
DWORD status = E_FAIL;
statusHandle = RegisterServiceCtrlHandler(SERVICE_NAME, ServiceCtrlHandler);
if (statusHandle == NULL)
goto EXIT;
ZeroMemory(&serviceStatus, sizeof(serviceStatus));
serviceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
serviceStatus.dwControlsAccepted = 0;
serviceStatus.dwCurrentState = SERVICE_START_PENDING;
serviceStatus.dwWin32ExitCode = 0;
serviceStatus.dwServiceSpecificExitCode = 0;
serviceStatus.dwCheckPoint = 0;
if (!SetServiceStatus(statusHandle, &serviceStatus))
OutputDebugString("Cool Service: Service Main: SetServiceStatus returned error!");
serviceStopEvent = CreateEvent(NULL, true, false, NULL);
if (serviceStopEvent == NULL)
{
serviceStatus.dwControlsAccepted = 0;
serviceStatus.dwCurrentState = SERVICE_STOPPED;
serviceStatus.dwWin32ExitCode = GetLastError();
serviceStatus.dwCheckPoint = 1;
if (!SetServiceStatus(statusHandle, &serviceStatus))
OutputDebugString("Cool Service: Service Main: SetServiceStatus returned error!");
goto EXIT;
}
serviceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
serviceStatus.dwCurrentState = SERVICE_RUNNING;
serviceStatus.dwWin32ExitCode = 0;
serviceStatus.dwCheckPoint = 0;
if (!SetServiceStatus(statusHandle, &serviceStatus))
OutputDebugString("Cool Service: Service Main: SetServiceStatus returned error!");
HANDLE thread = CreateThread(NULL, 0, ServiceWorkerThread, NULL, 0, NULL);
WaitForSingleObject(thread, INFINITE);
CloseHandle(serviceStopEvent);
serviceStatus.dwControlsAccepted = 0;
serviceStatus.dwCurrentState = SERVICE_STOPPED;
serviceStatus.dwWin32ExitCode = 0;
serviceStatus.dwCheckPoint = 3;
if (!SetServiceStatus(statusHandle, &serviceStatus))
OutputDebugString("Cool Service: Service Main: SetServiceStatus returned error!");
EXIT:
return;
}
void WINAPI ServiceCtrlHandler(DWORD ctrlCode)
{
switch (ctrlCode)
{
case SERVICE_CONTROL_STOP:
{
if (serviceStatus.dwCurrentState != SERVICE_RUNNING)
break;
serviceStatus.dwControlsAccepted = 0;
serviceStatus.dwCurrentState = SERVICE_STOP_PENDING;
serviceStatus.dwWin32ExitCode = 0;
serviceStatus.dwCheckPoint = 4;
if (!SetServiceStatus(statusHandle, &serviceStatus))
OutputDebugString("Cool Service: Service Handler: SetServiceStatus returned error!");
SetEvent(serviceStopEvent);
break;
}
default: break;
}
}
void Function()
{
Beep(7000, 1000);
}
DWORD WINAPI ServiceWorkerThread(LPVOID lParam)
{
while (WaitForSingleObject(serviceStopEvent, 0) != WAIT_OBJECT_0)
{
Function();
Sleep(3000);
}
return ERROR_SUCCESS;
}
The service does nothing after I install and start it in "services.msc", it should beep, right? Or my thinking is off the way here. Thanks for help :)
I have to read some Registry Value as soon as the program starts. The Code does works correctly and gives the Registry Value I seek, if the code is compiled and run from Command prompt. But If I create the service and attach the exe to the service using following code:
sc create someservice start=auto binpath= "PATH to EXE of Code"
and run the service I don't get the desired value. I have attached the complete code. I have logged the result of each step also.
#include <Windows.h>
#include <iostream>
#include <string>
SERVICE_STATUS ServiceStatus;
SERVICE_STATUS_HANDLE hStatus;
int WriteToLog(const char *);
std::string GetLPInstalledPath();
std::string GetLPInstalledPath()
{
HKEY hKey;
char buf[255];
DWORD dwType;
DWORD dwBufSize = sizeof(buf);
std::string ss="";
const char* subkey = "Software\\\\Logpoint\\\\InstalledPath";
WriteToLog(" Inside GetLPInstalledPath") ;
if( RegOpenKey(HKEY_CURRENT_USER,subkey,&hKey) == ERROR_SUCCESS)
{
WriteToLog("Opened the Registry Key");
dwType = REG_SZ;
if( RegQueryValueEx(hKey,"path",0, &dwType, (BYTE*)buf, &dwBufSize) == ERROR_SUCCESS)
{
ss = buf;
WriteToLog(ss.c_str());
}
else
{
WriteToLog(" Cound not find the value");
}
RegCloseKey(hKey);
}
else
{
WriteToLog(" Cannot Open the Installed Registry Path");
}
return ss;
}
int WriteToLog(const char* str)
{
//const char *logfile = "D:\\ubuntu_share\\lpa\\lpa_c\\build_win\\src\\lpa\\sample.txt";
FILE* log;
log = fopen("C:\\lpa\\sample.txt", "a+");
if (log == NULL)
return -1;
fprintf(log, "%s\n", str);
fclose(log);
return 0;
}
int Run()
{
WriteToLog("Run");
WriteToLog("entering infinite loop of main thread ");
while(1);
WriteToLog("end of main thread ");
return 0;
}
void ControlHandler(DWORD request)
{
//LOG4CPLUS_INFO(root, "ControlHandler: Entry";
switch(request)
{
case SERVICE_CONTROL_STOP:
//WriteToLog("Monitoring stopped.");
WriteToLog( "ControlHandler: SERVICE_CONTROL_STOP Request");
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
if(SetServiceStatus (hStatus, &ServiceStatus)==FALSE)
{
WriteToLog("ServiceCtrlHandler: SetServiceStatus returned error");
}
return;
case SERVICE_CONTROL_SHUTDOWN:
// WriteToLog("Monitoring shutdown.");
WriteToLog("ControlHandler: SERVICE_CONTROL_SHUTDOWN Request");
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
if(SetServiceStatus (hStatus, &ServiceStatus) == FALSE)
{
WriteToLog("ServiceCtrlHandler: SetServiceStatus returned error");
}
return;
case SERVICE_CONTROL_INTERROGATE:
return;
default:
WriteToLog("ServiceCtrlHandler");
break;
}
// Report current status
SetServiceStatus (hStatus, &ServiceStatus);
WriteToLog("ServiceCtrlHandler: Exit");
return;
}
void ServiceMain(int argc, char** argv)
{
//WriteToLog("at ServiceMain");
WriteToLog("ServiceMain");
int error;
ServiceStatus.dwServiceType = SERVICE_WIN32;
ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwServiceSpecificExitCode = 0;
ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwWaitHint = 0;
hStatus = RegisterServiceCtrlHandler(
"MemoryStatus",
(LPHANDLER_FUNCTION)ControlHandler);
if (hStatus == NULL)
{
// Registering Control Handler failed
WriteToLog("ServiceMain: RegisterServiceCtrlHandler returned error");
return;
}
// We report the running status to SCM.
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
if(SetServiceStatus (hStatus, &ServiceStatus)==FALSE)
{
WriteToLog("ServiceMain: SetServiceStatus returned error");
}
WriteToLog("ServiceMain: Performing Service Start Operations");
Run();
WriteToLog("ServiceMain: Performing Cleanup Operations");
ServiceStatus.dwControlsAccepted = 0;
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwCheckPoint = 3;
if (SetServiceStatus (hStatus, &ServiceStatus) == FALSE)
{
WriteToLog("ServiceMain: SetServiceStatus returned error");
}
WriteToLog("ServiceMain: Exit");
return;
}
int StartLpaService()
{
SERVICE_TABLE_ENTRY ServiceTable[2];
ServiceTable[0].lpServiceName = "MemoryStatus";
ServiceTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain;
ServiceTable[1].lpServiceName = NULL;
ServiceTable[1].lpServiceProc = NULL;
// Start the control dispatcher thread for our service
if(StartServiceCtrlDispatcher(ServiceTable) == FALSE)
{
WriteToLog("StartLpaService: StartServiceCtrlDispatcher returned error");
return GetLastError ();
}
WriteToLog("Main: Exit");
return 0;
}
int main(int argc, char **argv)
{
std::string pa = GetLPInstalledPath();
#ifdef SERVICE_DEBUG
WriteToLog("SERVICE_DEBUG");
Sleep(15000);
#endif
StartLpaService();
return 0;
}
The problem I am facing is that if the service of the program is started, no Registry value is written, but running directly from command prompt is giving the value. How do I solve this Issue?
You are looking in HKCU, the registry hive for the current user. So the most plausible explanation for what you describe is simply that the service is running under a different user. That is the service runs under a user account other than the interactive user.
I'm writing a win32 form application and drawing it with Direct2D. I have a few cross threaded functions to do animations on it and I'm doing web requests with WinHTTP. The issue is, when I use any WinHttp functions (even just opening an HINTERNET session), it will cause the thread not to terminate properly. After I run the 'login' process once, the program cannot exit calmly. I've posted the relevant code below:
//the login process
void __cdecl processloginasync(void* arg)
{
//getting text from textboxes, etc.
if(usernamestr.find(L'#') != wstring::npos && usernamestr.find(L".") != wstring::npos) {
swapdrawmode(1);
_beginthread(loadwheel,NULL,arg);
void* result = NULL;
unsigned sz = 0;
int rescode = web_request(L"appurl.mywebsite.com/func.php",ss.str().c_str(),result,sz);
//other code to handle the reply...
swapdrawmode(0);
}
else {
error_str = L"Invalid email address.";
err = TRUE;
}
if(err == TRUE) {
textopacity = 0;
animatemode = 0;
_beginthread(animatetext,NULL,arg);
}
//I realize I haven't called 'free' on result, I'll fix that.
}
//the web_request function
int web_request (const wchar_t* server, const wchar_t* object, void*& dest, unsigned& size)
{
vector<void*> retval;
vector<unsigned> szs;
HINTERNET hSess = NULL, hConn = NULL, hReq = NULL;
int res = 0;
DWORD dwDownloaded = 0;
DWORD dwSize = 0;
DWORD retcode = NULL;
short err = FALSE;
const wchar_t* accepted_types[] = {
L"image/*",
L"text/*",
NULL
};
hSess = WinHttpOpen(L"smartCARS2 Web/1.1",WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
if(hSess)
hConn = WinHttpConnect(hSess,server,INTERNET_DEFAULT_HTTP_PORT, NULL);
else {
err = TRUE;
retcode = HTTP_OPEN_FAILED;
}
if(hConn)
hReq = WinHttpOpenRequest(hConn, NULL, object, NULL, WINHTTP_NO_REFERER,accepted_types,NULL);
else {
err = TRUE;
retcode = HTTP_CONN_FAILED;
}
if(hReq)
res = WinHttpSendRequest(hReq, WINHTTP_NO_ADDITIONAL_HEADERS, NULL, WINHTTP_NO_REQUEST_DATA, NULL, NULL, NULL);
else {
err = TRUE;
retcode = HTTP_OPENREQ_FAILED;
}
if(res)
res = WinHttpReceiveResponse(hReq, NULL);
else {
err = TRUE;
retcode = HTTP_SEND_REQ_FAILED;
}
DWORD tsize = 0;
if(res) {
do {
dwSize = 0;
if(!WinHttpQueryDataAvailable(hReq, &dwSize)) {
retcode = HTTP_COULD_NOT_QUERY_SIZE;
err = TRUE;
break;
}
if(!dwSize)
break;
tsize += dwSize;
void* rets = malloc(dwSize + 1);
if(!rets) {
break;
}
if(!WinHttpReadData(hReq, (void*)rets, dwSize, &dwDownloaded)) {
retcode = HTTP_COULD_NOT_READ_DATA;
err = TRUE;
break;
}
if(!dwDownloaded) {
retcode = HTTP_COULD_NOT_DOWNLOAD;
err = TRUE;
break;
}
szs.push_back(dwSize);
retval.push_back(rets);
} while(dwSize > 0);
}
size = tsize;
unsigned int sz = retval.size();
dest = malloc(tsize);
tsize = 0;
for(unsigned i = 0; i < sz; i++) {
memcpy((BYTE*)dest + tsize,retval[i],szs[i]);
free(retval[i]);
tsize += szs[i];
}
if(hSess)
WinHttpCloseHandle(hSess);
if(hConn)
WinHttpCloseHandle(hConn);
if(hReq)
WinHttpCloseHandle(hReq);
if(err == TRUE)
return retcode;
return 0;
}
As far as I know, as soon as the main thread terminates, the others are not waited for. So the problem is probably in your main thread. You just need to attach a debugger if not already being debugged (Debug | Attach to process in VS) to a zombie process and press "Break all", then use "Threads" and "Call stack" windows to figure what's happening.