Service and application in single EXE? Update
10
May
Posted by: Christian Wimmer in: Common
Creating a binary file that consists of a service and a normal application can be done very simple without using the service manager. Just check for SYSTEM account. It is very unlikely that your app is run as SYSTEM (only RunAsSys does ).
-
uses …, JwsclToken;
-
begin
-
if JwIsSystem then
-
begin
-
try
-
Application.Initialize;
-
Application.CreateForm(TMyService, MyService);
-
Application.Run;
-
end
-
else
-
begin
-
end;
-
end;
Update
Mark Robinson suggested (in a comment) to check for a “service.exe” parent process. Since I did not find a solution within seconds, I decided to show how it works. Quite in handy came a CodeProject article about finding a parent process. The code is also available through download. Use it on your own risk.
-
function GetParentProcess(out ProcessEntry32 : TProcessEntry32W; const ProcessID : DWORD = 0) : DWORD; overload;
-
-
function InternalGetParentProcess(
-
const Condition : Boolean;
-
out ProcessEntry32 : TProcessEntry32W; const ProcessID : DWORD = 0) : DWORD;
-
var
-
hSnap : THandle;
-
ProcEntry : TProcessEntry32W;
-
currentID : DWORD;
-
Continue : Boolean;
-
-
begin
-
hSnap := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
-
result := INVALID_HANDLE_VALUE;
-
-
ZeroMemory(@ProcessEntry32, sizeof(ProcessEntry32));
-
-
try
-
ProcEntry.dwSize := sizeof(ProcEntry);
-
Continue := Process32FirstW(hSnap, ProcEntry);
-
-
if (ProcessID = DWORD(-1)) or (ProcessID = 0) then
-
CurrentID := GetCurrentProcessId
-
else
-
CurrentID := ProcessID;
-
-
result := INVALID_HANDLE_VALUE;
-
-
while (continue) do
-
begin
-
if CurrentID = ProcEntry.th32ProcessID then
-
begin
-
result := ProcEntry.th32ParentProcessID;
-
-
if not Condition then
-
begin
-
InternalGetParentProcess(true, ProcessEntry32, result);
-
end
-
else
-
ProcessEntry32 := ProcEntry;
-
end;
-
-
continue := Process32NextW(hSnap,ProcEntry) and (result = INVALID_HANDLE_VALUE);
-
end;
-
finally
-
CloseHandle(hSnap);
-
end;
-
end;
-
-
begin
-
result := InternalGetParentProcess(false, ProcessEntry32, ProcessID);
-
end;
-
-
function GetParentProcess(const ProcessID : DWORD = 0) : DWORD; overload;
-
var ProcessEntry32 : TProcessEntry32W;
-
begin
-
result := GetParentProcess(ProcessEntry32, ProcessID);
-
end;
-
-
function GetParentProcess(out ExeName : WideString; const ProcessID : DWORD = 0) : DWORD; overload;
-
var ProcessEntry32 : TProcessEntry32W;
-
begin
-
result := GetParentProcess(ProcessEntry32, ProcessID);
-
if result <> INVALID_HANDLE_VALUE then
-
ExeName := ProcessEntry32.szExeFile
-
else
-
ExeName := ”;
-
end;
-
-
var P : DWORD;
-
Name : WideString;
-
begin
-
P :=GetParentProcess(Name);
-
writeln(P,‘ ‘,Name);
-
readln;
-
end.
There are three versions of GetParentProcess, so you can get more information than usual necessary.
The reason why the first version has an internal function is that we need to iterate the process list twice to get the parent’s process name.
Finally all you have to do is to check for its name “services.exe”.
-
if CompareText(Name,’services.exe’) then
However there can be a bad coincidence and another process who started your app is named like that. In this case we should just check for the full path.
-
function RetrieveModuleFileName(const PID : DWORD) : WideString;
-
var
-
FileName : Array[0..MAX_PATH] of Widechar;
-
hP : THandle;
-
begin
-
hP := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, false, PID);
-
if hP = 0 then
-
RaiseLastOSError;
-
-
try
-
if GetModuleFileNameExW(hP,0,FileName, sizeof(FileName)) = 0 then
-
RaiseLastOSError;
-
result := FileName;
-
finally
-
CloseHandle(hP);
-
end;
-
end;
Now we can be sure that it is the correct process.
-
function GetSystem32Path : WideString;
-
var Path : Array[0..MAX_PATH] of Widechar;
-
begin
-
Result := ”;
-
if SUCCEEDED(SHGetFolderPathW(0,CSIDL_SYSTEM,0,SHGFP_TYPE_DEFAULT, @Path)) then
-
result := IncludeTrailingBackslash(Path); //Oopps, may convert unicode to ansicode
-
end;
-
-
var PID : DWORD;
-
begin
-
PID := GetParentProcess(Name);
-
-
Path := RetrieveModuleFileName(P);
-
SysPath := GetSystem32Path+’services.exe’;
-
if CompareText(SysPath, Path) = 0 then
-
//OK
-
else
-
//not a service
-
end.
We are not at the end. I should mention that your service application can also be in a service pool hosted by the parent process “svchost.exe”. In such a case of course, we have to check for “svchost.exe” instead of “services.exe”
convert this post to pdf.
11 Responses
Guus Creuwels
09|May|2008 1Good tip, however this will probably not work if the service app will run with a specific account specified (for example when network access is required).
Oliver
09|May|2008 2Hi, if you mean CIFS/SMB, then you are most certainly right. But services have never been restricted using the network in any sense.
Lars Bargmann
10|May|2008 3No, services are not restricted from the network, but running them under sys-account will most likely tick off your AD-people, if your service needs write-access to something…
Where I work (Rather big IT-infrastructure) every service that needs to do anything on the network-drives, will be running under a service-account that is being maintained in the AD…
Remko
10|May|2008 4AFAIK services running under the Local System account are denied access to the network (this was new in windows 2003). If you do need your service to access the network you should use the Network Service account in which case you need to give the computer account (computername followed by a $) permissions on the remote system (only possible in domain environments). If you need access to a remote share (CIFS/SMB) which does not permit anonymous access or access to the computer account you should use a (domain) user account.
If you do use a user account make sure it’s not a domain admin, change the password at regular intervals etc. etc.
Oliver
10|May|2008 5Lars, that’s exactly how it should be done. Normally you would expect this to be done by installers, too, but too many people seem to think that running as SYSTEM is the only way. Especially outbound services should be run with as limited rights as possible.
Remko, this is only valid for CIFS/SMB connections and wasn’t new with Windows 2003, although it may be even stricter there than it was previously. I know for sure that you can relax the policies in order to allows this, but this is a horrible horrible style. And for changing the password, it’s good to have a service which stores this in the secret stash (for example IIS allows you to configure this behavior, by saying that IIS can manage its own user accounts).
Christian Wimmer
10|May|2008 6So what is the right way to determine whether my process is running as a service or not? I suspect it includes the service control manager - and a connection to it. Actually I don’t have time to find it out, so maybe some wise guys can show it? thx
Mark Robinson
10|May|2008 7Find out what the parent process is, it will always be “services.exe” if the app is running as a service.
Christian Wimmer
10|May|2008 8Thank you. I updated the post with your information.
Mark Robinson
11|May|2008 9Cheers. Forgot about svchost.exe too, but glad I could help!
Remko
12|May|2008 10@Oliver: I meant the Local Service account (sorry for the typo) which was introduced in win2003 (http://msdn.microsoft.com/en-us/library/ms684188(VS.85).aspx). The account has considerably less permissions than the System account.
Oliver
12|May|2008 11Oh, sorry. That makes sense, of course.
Leave a reply
Search
Paypal donation (EUR)
Categories
Most Viewed
Archives
Tags
ACL callback COM Conversion CreateProcess DACL Delphi dialog DidYouKnow DLL documentation Download elevation factory file Handle header HowTo interface JWA JWSCL Kernel Microsoft KillProcess Laptop mail mailinglist manifest permission Privilege Process ProcessExplorer RunEl Russinovich Service Setup Sid TerminateProcess Theme Thread Token UAC user Vista Window WindowsRecent Posts
Recent Comments
Blogroll
Pages
Meta
A design creation of Design Disease
Copyright © 2007 - JEDI Windows API - is proudly powered by WordPress
InSense 1.0 Theme by Design Disease brought to you by HostGator Web Hosting.