tags:

views:

325

answers:

4

Hello, I am working on a project that can start a program on the winlogon desktop. The program works perfectly while debugging but when I start it outside the ide it fails strangly with the infamous c0000005 error. The weirdest thing though is it doesn't seem to occur on any particular line. Here is the code:

#include "stdafx.h"
#include <windows.h>
#include "BinRes.h"
#include <string>
#include <iostream>

int main(int argc, char* argv[])
{
    if(argc != 2)
    {
     return 0;
    }

std::string a;
a.append(BinRes::getAppLocation());
a.append("\\wls.exe");
BinRes::ExtractBinResource("EXE",102,"wls.exe");
Sleep(500);
SC_HANDLE schsm;
schsm = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
SC_HANDLE schs;
schs = CreateService(schsm,"WLS","WLS",SERVICE_ALL_ACCESS,SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS,SERVICE_DEMAND_START,NULL,a.c_str(),0,0,0,0,0);
char* cd = argv[1];
LPCSTR* arg = (LPCSTR*)&cd;
StartService(schs,1,arg);
HANDLE endevent;
endevent = OpenEvent(EVENT_ALL_ACCESS,TRUE,"ENDWLS");
WaitForSingleObject(endevent,INFINITE);
SERVICE_STATUS ss;
QueryServiceStatus(schs,&ss);
if(ss.dwCurrentState != SERVICE_STOPPED)
{
    LPSERVICE_STATUS xyz = (LPSERVICE_STATUS)malloc(sizeof(LPSERVICE_STATUS));
    ControlService(schs,SERVICE_CONTROL_STOP,xyz);
}
DeleteService(schs);
//error occurs right here
DeleteFile(a.c_str());
return 0;
}

The error always occurs after DeleteService and before the next line but I'm sure it isn't DeleteService because the service is deleted. I tried commenting out DeleteService and DeleteFile but it still crashes. I'm sure I've made some bonehead mistake and am just going blind. Thanks in advance for the help!

+6  A: 

Hi. I think the problem lies within the

LPSERVICE_STATUS xyz = (LPSERVICE_STATUS)malloc(sizeof(LPSERVICE_STATUS));
ControlService(schs,SERVICE_CONTROL_STOP,xyz);

part. The last argument xyz to ControlService is used by that API to return status information about the service. You are actually passing a pointer to a pointer sized memory region here, which is too small to hold all the values, which ControlService would like to fill in. IMHO you get bitten at run-time, because executing the ControlService call will override random memory directly after the space for the pointer allocated by malloc.

Try

SERVICE_STATUS xyz;
memset(&xyz, 0, sizeof(xyz));
ControlService(schs, SERVICE_CONTROL_STOP, &xyz);

instead. There is no need to allocate the structure dynamically here. According to the documentation, the ControlService will only use it to return status information; it won't be stored somewhere within Windows internal data structures.

More about the content of the structure can be in the MS documentation. No idea, why it might work during debugging. Maybe, the malloc linked against for debugging behaves slightly differently in comparison to the production version malloc?

Dirk
That seems like it would be correct but DeleteService is still called.
Yup. There is no need for the falsely overwritten memory to cause the crash immediately. It might be, that the crash happens on the next call to free (which might, for example, happen during the call to c_str() or virtually anywhere. You cannot really tell with this kind of errors.
Dirk
+4  A: 

In the windows API types starting with LP are pointers, so LPSERVICE_STATUS is a pointer to a SERVICE_STATUS. Therefore sizeof(LPSERVICE_STATUS) returns the size of a pointer, not the size of a SERVICE_STATUS, and this malloc doesn't allocate enough memory:

LPSERVICE_STATUS xyz = (LPSERVICE_STATUS)malloc(sizeof(LPSERVICE_STATUS));
ControlService(schs,SERVICE_CONTROL_STOP,xyz);

The correct size would be sizeof(SERVICE_STATUS). Also you don't really seem to need to allocate the memory dynamically, a pointer to a local variable should work as well:

SERVICE_STATUS xyz;
ControlService(schs,SERVICE_CONTROL_STOP,&xyz);
sth
A: 

Thanks you guys, I got it working!

A: 

The reason why it usually would NOT fail is the last part of:

"The service control manager fills in the structure only when ControlService returns one of the following error codes: NO_ERROR, ERROR_INVALID_SERVICE_CONTROL, ERROR_SERVICE_CANNOT_ACCEPT_CTRL, or ERROR_SERVICE_NOT_ACTIVE. Otherwise, the structure is not filled in."

from http://msdn.microsoft.com/en-us/library/ms682108%28VS.85%29.aspx

So it would only ever use the pointer when something fails... :)

Rahn