Debugging Services Using WinDbg

Hello paranoids

 Recently i have been spending some time going over some samples suspected to be related to Emissary Panda group. The initial lead was this Linkedin post. Then, later, one one of my colleagues @0xcpu mentioned this Tweet

 TLDR; executable drops dll, loads it and calls export that creates Windows service to run itself. The dll drops and deploys a filter driver. Both the dll and the initial executable were protected by VMProtect in virtualised mode.

 While i was able to get to unpacked ServiceMain by loading the malicious dll within Rundll, i was not sure if the malware depended on service-related features to work properly so i decided to deploy the dll as a service. I remembered that a good friend @Qutluch from FireEye adventures wrote the following blog post.

 VMProtect as most packers has a couple of techniques to detect the existence of an attached debugger and for the trick i wanted to use to skip VMProtect hanky panky i wanted to avoid having debuggers attached. Using cdb as a debugging server was a no-no. I wanted to use WinDbg and so this blog post builds mostly on top of the blog post above.

The Procedure

I will explain the procedure briefly and emphasize the changes.

  • Copy svchost.exe to malsvchost.exe under System32.
  • Deploy the service using the same script as mentioned on the blog (transcribed below in case the blog goes down):
@echo off
set BINPATH="C:\Users\user\Desktop\sample.dll"

sc create %SERVICENAME% binPath= "%SYSTEMROOT%\system32\malsvchost.exe -k %SERVICENAME%" type= share start= demand
reg add "HKLM\System\CurrentControlSet\Services\%SERVICENAME%\Parameters" /v ServiceDLL /t REG_EXPAND_SZ /d %BINPATH% /f
reg add "HKLM\Software\Microsoft\Windows NT\CurrentVersion\SvcHost" /v %SERVICENAME% /t REG_MULTI_SZ /d "%SERVICENAME%\0" /f
reg add "HKLM\SYSTEM\CurrentControlSet\Control" /v ServicesPipeTimeout /t REG_DWORD /d 86400000 /f


  • On GFlags, provide the path for your WinDbg executable. Experience tells me you should go for the x64 version to avoid pain if the malware is x86 but plays with x64 from time to time (e.g. spawns a x64 process, uses Heaven’s Gate to run x64 code). The image name should be malsvchost.exe.
  • Run the bat file from a command prompt with admin privs. Run Services.msc and verify that your service is there. Make it interactive (my service has a different name since it is the name used by the original dropper):


 The reason for the above configuration will become clear if you try to start the service without the option set. WinDbg will not show up and quick Google search will point you in this direction. Consider rebooting the system to make sure everything persists and the services start with the new definition of timeout.

 Even with this, the whole process of debugging a service using WinDbg is esoteric to say the least. Let us now start the service:

Process Hacker: Windbg spawning malsvchost.exe
sc start hang

Graphically, WinDbg is nowhere to be found. Ctrl+C and redo the same and now you get the same as above but with the following alert:

 On the old-school window, you will set a break on load for your dll. In my case, i called the dll ep.dll and not sample.dll:

Old-school debugger Window: setting break on load and running.
Old-school debugger Window: setting break on load and running.

 And as you can see, the service start command ran and returned:

Command Prompt: Service Started Successfully
Command Prompt: Service Started Successfully

 You should also find the TLS/Entrypoint offsets within the loaded image using:

  • lm: check base of loaded module
  • IDA: with module loaded at the same base address as the one displayed by lm, look for the relevant entrypoint (i.e. first routine(s) to be executed)

  Then, set a breakpoint on those and let the (old-school) debugger run. Once you are at the entrypoint, you can then perform the commands below. The reason for the above steps is: when the exception for the loaded module is triggered, if you attach another debugger you will notice that while the original debugger shows the loaded module, the other does not. This may be because there is an interruption (not to be confused with CPU interrupts) at the time when the dll is being mapped in memory (stops at NtMapViewOfSection). While the first debugger seems aware of this, the second is not and that may be a problem if you forget to take note of the base address of the loaded module you wish to debug.  If you forget to do this and switch debugger before reaching the TLS/entrypoint is no big deal. You  can still use !address and try to find where your module is mapped (don’t recommend).

 Note: When you try to set the BPs and run to the entrypoint(s), it is possible that nothing will happen. Check the state of the threads. If they have suspended counters above zero, you will need to use:

  • ~*: check thread indexes (e.g. 0,1,2…)
  • ~[THREAD_INDEX]m: decrement the suspend counters by one

 Then, you can let the debugger run.

 I have no idea what is this 90’s-looking Window for and i will not waste time trying to figure it out. I need to go back to my 21st century desktop. We now need to transition between debuggers and this is a point you may find useful in the future if you realise that you started with a x86 debugger and out of a sudden you have x64 code in the process. You will also have trouble with x86/x64 if your x86 debugger is debugging a malicious binary that decides to spawn a x64 process and you want to attach to the child (CreateProcess will return an error and the process will not be created).

 Once you are on the debugee entrypoint/TLS, the procedure is:

  • Run the command .abandon. As opposed to .detach, .abandon will not let the application run
  • Spawn a new WinDbg instance and attach to to the process malsvchost.exe. For this, you will need the command (attempting to attach using the GUI will not work per my experience):

    [WINDBG_PATH] -pe -p [PID]
  • Optional: Do not kill the old debugger process. When i did this, later, if i needed to detach the new debugger from the malsvchost process, the process would disappear (i.e. exited? got killed? who knows?)

You are now inside the service and you can proceed to debug.

Final Thoughts

  While i avoid writing tutorials on basic topics like this, it is my understanding this is essential for an upcoming post. Here i wanted to show you how you can debug a service using Windbg without using CDB as the middleman. The reason for this becomes clear once you read the upcoming post i previously mentioned since the presence of a debugger may be enough to prevent you from analyzing a sample using protected using advanced packers like VMProtect.

Stay safe 😉

One thought on “Debugging Services Using WinDbg

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s