Is there a way to debug completely a windows service with Delphi?
It's actually quite easy. Just use the standard DEBUG compiler directive to start the service as a console application instead of a service.
program MyServiceApp;
{$ifdef DEBUG}
{$APPTYPE CONSOLE}
{$endif}
uses
System.SysUtils,
[..]
begin
{$ifdef DEBUG}
try
// In debug mode the server acts as a console application.
WriteLn('MyServiceApp DEBUG mode. Press enter to exit.');
// Create the TService descendant manually.
ServerContainer1 := TServerContainer.Create(nil);
// Simulate service start.
ServerContainer1.ServiceStart(ServerContainer1, MyDummyBoolean);
// Keep the console box running (ServerContainer1 code runs in the background)
ReadLn;
// On exit, destroy the service object.
FreeAndNil(ServerContainer1);
except
on E: Exception do
begin
Writeln(E.ClassName, ': ', E.Message);
WriteLn('Press enter to exit.');
ReadLn;
end;
end;
{$else}
// Run as a true windows service (release).
if not Application.DelayInitialize or Application.Installing then
Application.Initialize;
Application.CreateForm(TServerContainer, ServerContainer1);
Application.Run;
{$endif}
end.
You can use unitDebugService.pas from Colin Wilson's NT Low Level Utilities (page is gone, available in the wayback machine)
and then in the DPR:
begin
if (paramCount > 0) and (SameText(ParamStr(1), '-DEBUG')) then
begin
FreeAndNil (Application);
Application := TDebugServiceApplication.Create(nil);
end;
//... the rest of the normal DPR code
end.
This way you can run from within Delphi with debugging (by setting the project Debugger Parameters), use the EXE as a service, or run from the commandline with the -DEBUG switch, and .
Use Run -> Attach to process. This way you can debug a service without doing any changes to its code. The only tricky part maybe debugging the service start code, because attaching may require some time, and the start must happen in 30s (although you can tweak Windows to allow a longer time). You can use a delay (sleep...) to allow you to attach in time, or if you just need to see what happens you can use OutputDebugString() to print to the debug output (use Delphi Event View to see it).
Yes, there is:
Debugging services: an easy way
Do you create services with Delphi?
Then maybe you are also annoyed at the
time consuming way of starting,
restarting, killing and attaching to
the service process application every
time. Well, there is remedy.
You don’t need to do this. Instead run
Delphi as a SYSTEM application and do
some minor adaptions to the service
code.
I've tried this, but only appears the cpu window with assembly codes.
Then you only should solve this problem.
Basically, to debug a Win2 service, there are few ways:
Use "Attach to process" command to attach debugger to already running service. You may insert startup delays to have time to attach debugger, if you need to attach at the very beginning. However, you would also have to tweak the system to increase service timeouts.
Use "Image File Execution Options" registry key to force-run Delphi's debugger at service startup. The same considerations about system timeouts apply.
Temporary convert service into usual application and run it under debugger normally. You may re-launch IDE under different user account to gain more priviledges for the "service".
If you for some reason has only CPU view of your service after starting debugging - this means that Delphi's debugger can't find debug information for your service. That is a different problem and you should search solution for it.
Usually, you need to do:
Make sure that output folder for your service application is set to folder from which it will be loaded by the system. I.e. if your service is located in C:\Windows\System32 - then set output folder to C:\Windows\System32. Do not copy .exe file elsewhere from your output folder. For 64 systems you may try alias (sysnative/SysWOW64) or real name. I think it's best to set output path to project's folder and re-register service to be loaded from project folder.
(Optional) Set output path for DCU into the same folder as .exe file.
Delete all of your DCU files.
Make sure to enable debug options on "Compiler" page in project options.
(Optional) Additionally you may also include TD32/RSM/MAP options on "Linker" page.
Make sure there is no IDE expert/extension, which may modify .exe file, debug information or file modification date for these files.
Make sure there is no old files (DCU/exe) in other locations.
Make a full rebuild (Project/Build all).
Run your service.
Yes there is.
In your dpr:
Application.CreateForm(TMyService, MyService);
_ServiceInDebugMode := SysUtils.FindCmdLineSwitch('DEBUG', True);
if _ServiceInDebugMode then
DebugService(MyService)
else
SvcMgr.Application.Run;
DebugService is a procedure that creates a debug form, a service control thread and kicks off everything by calling Forms.Application.Run.
You can compare the service control thread with the Windows' SCM (Service Control Manager), the debug form with an application that talks to the SCM (such as the services.msc) to start and stop services. The service should also have its own thread (service thread) to respond to control codes coming in from the SCM or our service control thread and one or many more separate threads to do its actual work. You want separate threads for the actual work (instead of coding it in the event handlers of your TService descendant) to ensure that the thread in which the TService itself runs is always free to respond to control codes from the SCM and you can still stop and start the service even when per chance a/the worker thread is frozen.
This approach allows you to debug the service app code as well, but involves a fair amount of code and placing a couple of hooks into windows api functions to work properly. Too much to show here at short notice. Maybe I'll write it up in an article some day.
In the mean time, if you don't want to code it all yourself you have two options. Either go with a library such as SVCOM or the one mentioned by Mick which do it all for you, or when in debug mode by-pass the service code all together and "simply" start your service as a "normal" forms application. You will have to disentangle the real functionality of your service from your TService descendant's code/event handlers, but that is something I'd recommend anyway for the reasons mentioned above.
Related
We're having a very strange behaviour that I'm unable to identify a root cause for. We use TFS (2017.U2) to compile our legacy system, and are trying to update our build farm from 2008R2 up to 2016. The build system uses PowerShell (v5) to cycle through a list of VBP projects and run a VBS script to compile the projects.
First a bit of basics. UAC is totally disabled (in the registry, not just the slider control), VB6.EXE is also set to XP SP3 compatability, and also to run as the administrator.
Unfortunately, while we can see VB6.EXE start in task manager - it just hangs. Zero activity. Running the same compile interactively works just fine with the same user. This led me to theorize it was an environment problem, however process explorer shows me a valid user environment on the VB6.EXE process.
I don't believe this is due to VB6 throwing an error, as (at least in previous versions of Windows Server) when a background process opens a UI element, the OS indicates to the foreground that the background wants to break in. We dont see that.
We've stubbed this back to a bare minimum code example which I call "test.ps1":
$vb6="C:\Program Files (x86)\Microsoft Visual Studio\VB98\vb6.exe"
Set-Location D:\Builds\27\s\path\prjdir
start-process $vb6 -ArgumentList "/make /out errors.txt project.vbp" -wait
We've been using "start-process" to trigger the VB6 compiles because direct invokation via PowerShell doesn't ingest the parameters properly (they're actually built out of strings passed into the master script in the full blown process... this is the simplified version).
When run interactively (.\test.ps1) this functions properly. The project compiled and I get an errors.txt file written.
When started as a process (start-process .\test.ps1) this again functions properly.
When triggered via a TFS "PowerShell Script" task, this fails to complete the VB6 step - the VB6.EXE can be seen in the Task viewer with the appropriate arguments, and no CPU or IO is associated with the task. No errors.txt file is written. No new DLL is created.
I was able to dummy this down even further and remove TFS from the stack by running the test script from another machine. I ran a remote invokation of the script, and duplicated the result using this command:
PS C:\Users\svc_build> Invoke-Command –ComputerName TestBuild02 –ScriptBlock {powershell C:\Users\svc_build\desktop\test.ps1 }
Again, no errors.txt, and no new DLL. VB6.EXE starts up and just sits there. Process monitor doesnt provide any help in diagnosing what might be the issue.
This now smells of a security door being shut on me - even though the same domain user is running the same job, the difference is that this is a background process... and something is preventing a background process of executing in the same context as a foreground process.
Assuming this assumption is correct, can someone point me at the reason a remotely triggered (background) session isn't able to run VB6.EXE? (and of course, a work around for the situation would be appreciated :) )
If this is not a security issue - can someone identify the real culprit, and the solution to getting VB6 running as a background process, like we're used to seeing it run on W2K8R2?
I'm a bit late to the party, but this sounds like a very similar scenario to what I've just encountered.
Windows 10 v2004
UAC disabled
Compiling by running VB6.exe via a PowerShell script.
Using Bamboo as the build server, running as a Managed Service Account.
When running the build on the server via Bamboo, it hangs. When logging into the build server and running the build manually, it succeeded.
After cutting down the code I was able to reproduce a minimal failing case. The hang was caused by code in a UserControl's UserControl_Initialize method that was manipulating UI controls, but only when that UserControl was placed on a Form in the same project.
During compilation, the compiler will create an instance of the Form (why, I don't know), which in turn creates an instance of the UserControl, which in turn runs the UserControl_Initialize method. I can only assume that running the code at that point resulted in an error of some sort, and that resulted in the compiler hanging.
The same error can be caused by the UserControl_Resize event. That case is reasonably easy to fix by checking if Ambient.UserMode is true before trying to resize the child controls.
Private Sub UserControl_Resize()
If UserControl.Ambient.UserMode Then
' Position the child controls
End If
End Sub
Fixing the UserControl_Initialize methods required the code in those methods to be run at a different point (for example, when the UserControl is given the data to display, we now run the code that was previously in UserControl_Initialize).
Also worth noting is the compatibility settings for VB6.exe that we had to use. Using "Windows XP SP3" compatibility mode resulted in VB6.exe hanging immediately. We had to set it to not use any compatibility mode, but we did have to set Run this program as an adminisrtator, and had that applying for all users.
I am trying to understand what Image File Executions Options can do and what it's normally used for. I know it is used for debugging purposes but how do I know its used for malicious purposes? Is this registry key used with every executable? If not, is it suspicious?
For example what does \Image File Execution Options\DevOverrideEnable do?
PS: I have looked a these sources already:
https://gooroo.io/GoorooTHINK/Article/17352/Image-File-Execution-Options-Good-Evil-Fun/28441
https://blog.malwarebytes.com/101/2015/12/an-introduction-to-image-file-execution-options/
Normally debuggers can run a process or attach to existing process to debug it and it's enough for normal projects but in some projects like services debugger can't start the service because of Windows service architecture. in this scenario we should attach debugger to running service process but if we want to debug some codes in startup of service we can't do it by this method because debugger attached to process after the startup codes executed.
In scenarios like this we can use Image File Executions Options (IFEO) by configuring to launch debugger when process start, when specified process start Windows launch process inside specified debugger and let developer to debug the process from beginning of born !
The problem of this option is Microsoft Windows do not (and cannot ;) check the specified debugger is really a debugge.
On the other hand malware authors use this option as a trick to start they malicious process when some process run, for example they can run a injector every time "explorer.exe" process run and inject some malicious code to it.
Finally IFEO is not malicious option by it self but maybe! and there is not simple way to know it's malicious or not. if you want to be sure it's malicious or not the debugger should be analyze and check manually for malicious activity.
If you are not computer skilled person the easiest way for you is to find the IFEO registry keys and find debugger's path from theme and upload debugger file to online scanner website like VirusTotal and hope they tell the truth :))
We are trying to troubleshoot a nasty problem on a production server where the server will start misbehaving after running for awhile.
Diagnostics have led us to believe there may be a bug in a DLL that is used by one of the processes running on this server that is resulting in a global atom leak. The assumed vector is a process that is calling RegisterClass without a corresponding UnregisterClass (and the class name is using a random number as part of the name, so it's a different class name each time the process starts).
This article provided some information: https://blogs.msdn.microsoft.com/ntdebugging/2012/01/31/identifying-global-atom-table-leaks/
But we are reluctant to attempt kernel mode debugging on a production server, so we have tried installing windbg and using the !gatom command to list atoms for a given session.
I use windbg to attach to a process in one of the sessions (these processes are running as Windows Services if that matters), then invoke the !gatom command. The returned atom list doesn't have any window classes in it.
Then I read this: https://blogs.msdn.microsoft.com/oldnewthing/20150429-00/?p=44984
and it sounds like there is a separate atom table for windows classes. And no way to query it. I was hoping that we'd be able to actually see how many windows class atoms have been registered, and see if that list gets bigger over time, indicating a leak.
The documentation on !gatom is sparse, and I'm hoping I can get some expert confirmation or recommendations on how to proceed.
Does anyone have any ideas on how we can get at the list of registered Windows classes on a production server?
More detail about what happens when the server starts to misbehave:
We run many instances (>50) of the same application as separately registered services running from isolated executables and DLLs - so each of those 50 instances has their own private executables and DLLs.
During their normal run, the processes unload and reload a DLL (about every hour). There is a windows class used that's part of a "session handle" used by the DLL (the session handle is part of the registered windows class name), and that session handle is unique each time the DLL is loaded. So every hour, there is an additional Window class registration, made by a DLL (our service stays running).
After some period of time, the system will get into a state where further attempts to load the DLL in question fail. This may happen for one of the services, then gradually over time, other services will start to have the same problem.
When this happens, restarting the service does not fix the problem. The only way that we've found to get things running properly again is to reboot the server.
We are monitoring memory commit load, and we are well within the virtual memory of the server. We are even within the physical memory size.
I just did a code review the vendor of the DLL, and it looks like they are not actually calling RegisterClass from the DLL itself (they only make one RegisterClass call from the DLL, and it's a static string - not a different class name for each session). The DLL launches an EXE, and that EXE is the one that registers the session specific class name. Their EXE does call UnregisterClass (and even if it didn't, the EXE is terminated when we unload their DLL, so it seems that this may not be what is going on).
I am now out of bullets on this one. The behavior seems like some sort of resource leak or pool exhaustion. The next time this happens, I will try connecting to the failing process with windbg and see what the application atom pool looks like - but I'm not hopeful that is going to shed any light.
Update: The excellent AtomTableMonitor tool has narrowed the problem to rogue RegisterWindowMessage. I'm going to ask a more specific question focused on this exact issue: Diagnosing RegisterWindowsMessage leak
You may try using this standalone global atom monitor
The application appears to have capabilities to monitor atoms in services
that run in a different session
btw if you have narrowed it to RegisterWindowMessage
then spy++ can log the Registered messages system wide along with thread and process
spy++ (i am using it from vs2015 community)
ctrl+m select all windows in system
in the messages tab clear all and select registered
and start logging
you can also save the log (it is plain text in-spite of strange extension )
powershell -c "gc spy++.sxl -Tail 3"
<000152> 001F01A4 P message:0xC1B2 [Registered:"nsAppShell:EventID"] wParam:00000000 lParam:06EDFCE0 time:4:2
7:49.584 point:(408, 221)
<000153> 001F01A4 P message:0xC1B2 [Registered:"nsAppShell:EventID"] wParam:00000000 lParam:06EDFCE0 time:4:2
7:49.600 point:(408, 221)
<000154> 001F01A4 P message:0xC1B2 [Registered:"nsAppShell:EventID"] wParam:00000000 lParam:06EDFCE0 time:4:2
7:49.600 point:(408, 221)
I have a Windows Service and I would like to see what it's doing when it starts up. Normally to accomplish something like that, I'd hard-code a Thread.Sleep for like 10 seconds to give me enough time to attach the debugger. This is effective, but annoying, as I need to re-compile once to put the pause in and again when I (hopefully remember to) take the pause out. I know I could alternatively hard-code a break command in, but that also requires me to re-compile my solution.
I know I can also separate my service's logic into a separate project that can be run in Visual Studio, which I can use most of the time, but sometimes I want to see exactly what my service is doing when it's running as a service.
Is there a way that I can get my debugger attached to my service so that I can see the things it's doing on startup, without hard-coding and re-compiling anything?
There is a registry key which gives you a chance to attach a debugger to the process as soon as it is created.
Save the following snippet as a *.reg file and import to your registry:
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\services.exe]
"Debugger"="c:\\Program Files\\Debugging Tool For Windows\\windbg.exe"
remember to change 'services.exe' to the actual services executable file name.
You can also use the gflag tool to facilitate the work. For detailed information please check KB 824344: How to debug Windows services
Take a look at Attach to a process on the Tools menu in Visual Studio. You can put a break point in your code and then start the process and debug the service. You may have to put a thread.sleep() to give you enough time to react.
You have to start the service than attach to the process in Visual Studio. The thread.sleep() will give you the time to perform the attaching without blowing by your start up code.
Here is Microsoft's advice on how to accomplish this: http://msdn.microsoft.com/en-us/library/7a50syb3%28VS.80%29.aspx
I have a console application (written in VB6 ) which is behaving strangely on my machine. I kick it off from the command line and what should be a two minute job drops straight back to the prompt - if I run this on another machine the executable will sit and wait until the job finishes before returning control back to the prompt. If I check process explorer I can see that the executable is running as a background process and other than this strange background-ness is running as expected.
Any thoughts on why this could be happening? (Running on 32-bit Windows XP Pro SP3.)
It's totally unclear whether this is an application you wrote and have the source code for. If that's the case, you need to get in and start debugging. At the least, use OutputDebugString to send information about what's going on to any number of potential viewers. Taking that a step further, consider rewiring the app using the Console module I wrote, along with vbAdvance to recompile. This combination will allow you the full power of the VB6 IDE to debug within. No more guessing about what's going on.
Then again, if it's not your app, I'm not sure what VB6 has to do with it and wish you the best of luck trying to figure out what's up.
It sounds to me as though the app isn't being recognised as a console app on one of your machines. Console apps weren't officially supported in VB6, although there are some well-known hacks for creating them (particularly the free add-in vbAdvance). Possibly your console app is a bit unreliable? If Windows thinks your app is a GUI rather than a console app, it won't wait for it to finish.
As a pragmatic workaround: try launching with start /wait rather than just using the exename. That forces the command prompt to wait for the program to finish, whether it's a GUI app or a console app.
Sounds like an error is occurring that is being 'swallowed' by the application. Do you have the source code?
Errors in VB6 apps are often due to some COM component not installed and/or registered.
Download SysInternals Process Monitor and this will show up accesses to ProgIDs that fail (uninstalled/unregistered COM components).
Check out: Process Monitor - Hands-On Labs and Examples.
Have you checked permissions? Is the application accessing any network based resources?