Didier Stevens

Tuesday 29 October 2019

Quickpost: Running a Service DLL

Filed under: Quickpost — Didier Stevens @ 0:00

To install and run a service DLL compiled with MinGW on Kali, I execute following commands from a BAT file with an elevated command prompt:

copy SvcHostDemo.dll %SystemRoot%\System32\SvcHostDemo.dll
sc create SvcHostDemo binPath= ^%%SystemRoot^%%"\system32\svchost.exe -k mygroup" type= share start= demand
reg add HKLM\SYSTEM\CurrentControlSet\services\SvcHostDemo\Parameters /v ServiceDll /t REG_EXPAND_SZ /d ^%%SystemRoot^%%\System32\SvcHostDemo.dll /f
reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Svchost" /v mygroup /t REG_MULTI_SZ /d SvcHostDemo /f

Line 1 copies the DLL to system32.

Line 2 creates a service with name SvcHostDemo, that will start svchost.exe with service host group “mygroup”. The service can run in a shared svchost process, and it needs to be started manually.

Line 3 creates the registry entry ServiceDll referring to SvcHostDemo.dll.

Line 4 creates the service host group “mygroup” under the key for svchost. This service host group contains the service SvcHostDemo.

These commands create the following registry entries:

On a 64-bit Windows system, system32\svchost.exe is a 64-bit application and thus the service DLL needs to be a 64-bit DLL.

On a 32-bit Windows system, system32\svchost.exe is a 32-bit application and thus the service DLL needs to be a 32-bit DLL.

 

To start the service from the command line, the following command can be issued from an elevated command prompt: sc start SvcHostDemo.

Since service SvcHostDemo is the only service of service host group mygroup, starting the service causes a svchost.exe process to be created and the DLL is loaded inside this new process.

To pause the service: sc pause SvcHostDemo.

To resume the service: sc continue SvcHostDemo.

To stop the service: sc stop SvcHostDemo.

And since service SvcHostDemo is the only service of service host group mygroup, stopping the service causes the svchost.exe process to be terminated.

 

The many debug messages generated by this demo service can be viewed with DebugView. Run dbgview.exe elevated and enable “Capture Global Win32”, otherwise debug messages from a service (running under the local system account) will no be captured and displayed.

This service can also run inside an existing service host group, like netsvcs. To achieve this, line 2 of the commands above needs to use service host group netsvcs in stead of mygroup. And line 4 is not needed, but the existing multistring netsvcs under key Svchost needs to be updated to include SvcHostDemo. This change requires a reboot of the Windows machine to become effective.

With these changes, starting the service results in loading of the DLL in the existing svchost.exe process for the netsvcs service host group.

Stopping the service does not result in termination of the svchost.exe process, as it is hosting many other Microsoft Windows services.

To unload the DLL from the svchost.exe process when the service is stopped, set registry value ServiceDllUnloadOnStop under Parameters to 1.

reg add HKLM\SYSTEM\CurrentControlSet\services\SvcHostDemo\Parameters /v ServiceDllUnloadOnStop /t REG_DWORD /d 1 /f

 

If the name of the service function is not ServiceMain, but another name like RunThisService for example, then registry value ServiceMain under Parameters can be set to RunThisService.

reg add HKLM\SYSTEM\CurrentControlSet\services\SvcHostDemo\Parameters /v ServiceMain /t REG_SZ /d RunThisService /f

 

I used Windows 7 to demo this, as shared services on Windows 10 behave differently. Starting with Windows 10 version 1703, a service host refactoring took place and on machines with more than 3.5 GB of RAM each service DLL has its own svchost process, regardless of service host groups. This resulted in a change in the ImagePath registry entries. On Windows 10 machines version 1703 and later, almost all ImagePath entries for “svchost.exe -k servicegroup” have an extra option “-p”, like this: “svchost.exe -k servicegroup -p”. One of the very few svchost services not having this -p option, is the BTAGService service.

I still need to figure out what this option -p means exactly.


Quickpost info


Monday 28 October 2019

Quickpost: Compiling Service DLLs with MinGW on Kali

Filed under: Quickpost — Didier Stevens @ 7:36

Compiling a service DLL (a Windows DLL implementing a service to be executed inside a shared svchost.exe process) with MinGW on Kali, is almost the same as compiling a DLL.

A service DLL implements a service and must export a ServiceMain function. To prevent name mangling of the exported function, the ServiceMain definition needs to be ‘extern “C”‘:

extern “C” VOID WINAPI ServiceMain(DWORD dwArgc, LPCWSTR* lpszArgv)

And we need a DEF file:

LIBRARY SvcHostDemo
EXPORTS
	ServiceMain

This DEF file can be passed as argument to the MinGW compiler.

To create a 32-bit DLL:

i686-w64-mingw32-gcc -shared -municode -o SvcHostDemo.dll SvcHostDemo.def SvcHostDemo.cpp

To create a 64-bit DLL:

x86_64-w64-mingw32-gcc -shared -municode -o SvcHostDemo.dll SvcHostDemo.def SvcHostDemo.cpp

Option -municode is needed because I use TCHARs and want to compile a UNICODE executable.

Here is the code of my service template:


#define _UNICODE

#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <strsafe.h>

SERVICE_STATUS_HANDLE g_serviceStatusHandle = nullptr;
HANDLE g_hSvcStopEvent = NULL;

SERVICE_STATUS g_serviceStatus = {SERVICE_WIN32_SHARE_PROCESS, SERVICE_START_PENDING, SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_PAUSE_CONTINUE};

BOOL WINAPI DllMain(HMODULE hModule, DWORD dwReason, LPVOID lpReserved)
{
	OutputDebugString(L"DllMain");
	switch (dwReason)
    {
	    case DLL_PROCESS_ATTACH:
					OutputDebugString(L"DLL_PROCESS_ATTACH");
	        break;
	    case DLL_THREAD_ATTACH:
					OutputDebugString(L"DLL_THREAD_ATTACH");
	        break;
	    case DLL_THREAD_DETACH:
					OutputDebugString(L"DLL_THREAD_DETACH");
	        break;
	    case DLL_PROCESS_DETACH:
					OutputDebugString(L"DLL_PROCESS_DETACH");
	        break;
    }
    return TRUE;
}

DWORD WINAPI HandlerEx(DWORD dwControl, DWORD dwEventType, LPVOID lpEventData, LPVOID lpContext)
{
	switch (dwControl)
	{
		case SERVICE_CONTROL_STOP:
			OutputDebugString(L"HandlerEx SERVICE_CONTROL_STOP");
			g_serviceStatus.dwCurrentState = SERVICE_STOPPED;
			SetEvent(g_hSvcStopEvent);
			break;
		case SERVICE_CONTROL_SHUTDOWN:
			OutputDebugString(L"HandlerEx SERVICE_CONTROL_SHUTDOWN");
			g_serviceStatus.dwCurrentState = SERVICE_STOPPED;
			SetEvent(g_hSvcStopEvent);
			break;
		case SERVICE_CONTROL_PAUSE:
			OutputDebugString(L"HandlerEx SERVICE_CONTROL_PAUSE");
			g_serviceStatus.dwCurrentState = SERVICE_PAUSED;
			break;
		case SERVICE_CONTROL_CONTINUE:
			OutputDebugString(L"HandlerEx SERVICE_CONTROL_CONTINUE");
			g_serviceStatus.dwCurrentState = SERVICE_RUNNING;
			break;
		case SERVICE_CONTROL_INTERROGATE:
			OutputDebugString(L"HandlerEx SERVICE_CONTROL_INTERROGATE");
			break;
		default:
			OutputDebugString(L"HandlerEx default");
			break;
	}

	SetServiceStatus(g_serviceStatusHandle, &g_serviceStatus);

	return NO_ERROR;
}

DWORD WINAPI Worker(LPVOID lpParam)
{
	while (TRUE)
	{
		if (g_serviceStatus.dwCurrentState == SERVICE_RUNNING)
			OutputDebugString(L"Working ...");
		Sleep(1000);
	}
}

extern "C" VOID WINAPI ServiceMain(DWORD dwArgc, LPCWSTR* lpszArgv)
{
	TCHAR szOutput[256];
	DWORD dwIter;

	OutputDebugString(L"Begin ServiceMain");
	StringCchPrintf(szOutput, 256, L"dwArgc = %d", dwArgc);
	OutputDebugString(szOutput);
	for (dwIter=0; dwIter<dwArgc; dwIter++)
		OutputDebugString(lpszArgv[dwIter]);

	if (dwArgc > 0)
		g_serviceStatusHandle = RegisterServiceCtrlHandlerExW(lpszArgv[0], HandlerEx, nullptr);
	else
		g_serviceStatusHandle = RegisterServiceCtrlHandlerExW(L"SvcHostDemo", HandlerEx, nullptr);
	if (!g_serviceStatusHandle)
	{
		OutputDebugString(L"Error 1 ServiceMain");
		return;
	}

	g_hSvcStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

	if (g_hSvcStopEvent == NULL)
	{
		OutputDebugString(L"Error 2 ServiceMain");
		return;
	}

	g_serviceStatus.dwCurrentState = SERVICE_RUNNING;

	SetServiceStatus(g_serviceStatusHandle, &g_serviceStatus);

	OutputDebugString(L"Starting Worker ServiceMain");

	if (NULL == CreateThread(NULL, 0, Worker, NULL, 0, NULL))
	{
		OutputDebugString(L"Error 3 ServiceMain");
		return;
	}

	OutputDebugString(L"Waiting ServiceMain");

	WaitForSingleObject(g_hSvcStopEvent, INFINITE);

	OutputDebugString(L"End ServiceMain");
}

Quickpost info


Monday 21 October 2019

Quickpost: ExifTool, OLE Files and FlashPix Files

Filed under: Forensics,maldoc,Malware,Quickpost — Didier Stevens @ 0:00

ExifTool can misidentify VBA macro files as FlashPix files.

The binary file format of Office documents (.doc, .xls) uses the Compound File Binary Format, what I like to refer as OLE files. These files can be analyzed with my tool oledump.py.

Starting with Office 2007, the default file format (.docx, .docm, .xlsx, …) is Office Open XML: OOXML. It’s in essence a ZIP container with XML files inside. However, VBA macros inside OOXML files (.docm, .xlsm) are not stored as XML files, they are still stored inside an OLE file: the ZIP container contains a file with name vbaProject.bin. That is an OLE file containing the VBA macros.

This can be observed with my zipdump.py tool:

oledump.py can look inside the ZIP container to analyze the embedded vbaProject.bin file:

And of course, it can handle an OLE file directly:

When ExifTool is given a vbaProject.bin file for analysis, it will misidentify it as a picture file: a FlashPix file.

That’s because when ExifTool doesn’t have enough metadata or an identifying extension to identify an OLE file, it will fall back to FlashPix file detection. That’s because FlashPix files are also based on the OLE file format, and AFAIK ExifTool started out as an image tool:

That is why on VirusTotal, vbaProject.bin files from OOXML files with macros, will be misidentified as FlashPix files:

When the extension of a vbaProject.bin file is changed to .doc, ExifTool will misidentify it as a Word document:

ExifTool is not designed to identify VBA macro files (vbaProject.bin). These files are not Office documents, neither pictures. But since they are also OLE files, ExifTool tries to guess what they are, based on the extension, and if that doesn’t help, it falls back to the FlashPix file format (based on OLE).

There’s no “bug” to fix, you just need to be aware of this particular behavior of ExifTool: it is a tool to extract information from media formats, when it analyses an OLE file and doesn’t have enough metadata/proper file extension, it will fall back to FlashPix identification.

 


Quickpost info


Tuesday 30 July 2019

Quickpost: tcp-honeypot.py & Browser Tests

Filed under: My Software,Networking,Quickpost — Didier Stevens @ 0:00

tcp-honeypot.py is a Python program that allows you to define listeners using dictionaries: they listen on a given TCP port and process connections according to their configuration.

It started as a simple TCP honeypot, but now I use it too if I need a small network server.

For my quickpost “Quickpost: Browsers & Content-Disposition“, I needed a simple web server that would serve a page that I could fully control (headers & body).

I did this with tcp-honeypot. Dictionary dListeners (used by tcp-honeypot) defines the listeners: the keys are the TCP port numbers to listen on, and the values are dictionaries with configuration entries.

As I wanted to serve 3 different pages, I resorted to listen on 3 different ports (8080, 8081, 8082), each would serve a different page. Each dictionary for these listeners contains one entry with key THP_REPLY. Because each listener is very simple it listens for a connection and reads incoming data, discards it, and then sends its reply (regardless of input).

Here is the code to do this (file content-disposition-test.py):

#!/usr/bin/env python

__description__ = 'TCP honeypot configuration for Content-Disposition tests'
__author__ = 'Didier Stevens'
__version__ = '0.0.1'
__date__ = '2019/04/03'

"""
Source code put in public domain by Didier Stevens, no Copyright
https://DidierStevens.com
Use at your own risk

History:
  2019/04/03: start

Todo:
"""

dListeners = {
    8080:    {THP_REPLY: TW_CRLF(['HTTP/1.1 200 OK', 'Content-Disposition: inline', '', 'Line 1', 'Line 2', 'Line 3'])},
    8081:    {THP_REPLY: TW_CRLF(['HTTP/1.1 200 OK', 'Content-Disposition: attachment', '', 'Line 1', 'Line 2', 'Line 3'])},
    8082:    {THP_REPLY: TW_CRLF(['HTTP/1.1 200 OK', 'Content-Disposition: attachment; filename="test.js"', '', 'Line 1', 'Line 2', 'Line 3'])},
}

THP_REPLY configures a listener to read incoming data when a TCP connection is established, then send a reply (the value of dictionary entry THP_ENTRY) and then close the connection. This value is a string: the HTTP message (start-line, headers and body) to be send to the browser. In stead of defining one long string with start-line, headers and body, separated with carriage return & newline (CR NL), I use convenience function TW_CRNL. When you call convenience function TW_CRNL (Terminate With CR NL) with a list of strings, it terminates each string with CR NL (\r\n) and concatenates all strings into one string, that is returned by the function.

To start the server with this configuration, I just have to run tcp-honeypot.py with content-disposition-test.py as argument.

There are other methods to do this, for example using a single port. I’ll describe these methods in an upcoming blog post.


Quickpost info


Wednesday 3 July 2019

Quickpost: nslookup Types

Filed under: Networking,Quickpost — Didier Stevens @ 0:00

A reminder to myself, how to set a nslookup type via the command-line:

The label of the root domain is an empty string, hence a FQDN with root domain ends with a dot (.), like google.com. :


Quickpost info


Tuesday 11 June 2019

Quickpost: C Random Functions in Other Languages

Filed under: Quickpost — Didier Stevens @ 0:00

Some time ago, I had to implement a particular C-runtime random number generator in Python. That’s not difficult to do, you just need a variable that maintains the state (seed) of the random number generator, and then you use a simple algebraic expression: a linear congruential generator.

What’s more difficult to figure out, is knowing which multiplier (a) and increment (c) you need to reproduce the particular C-runtime random number generator.

Fortunately, I discovered that Wikipedia has a table with a and c values for many C compilers and other languages: parameters in common use.


Quickpost info


Sunday 19 May 2019

Quickpost: Retrieving an SSL Certificate with nmap

Filed under: Encryption,Networking,Quickpost — Didier Stevens @ 8:28

One of my first quickposts, more than 10 years ago, was an howto: using openssl to retrieve the certificate of a web site.

Since then, nmap has a scripting engine, and there is a script to check a certificate with nmap: ssl-cert.nse.

You just have to scan the site and port for which you want to check the certificate, like this: nmap -p 443 –script ssl-cert didierstevens.com

If you want the certificate too, increase verbosity with option -v:

Checking a certificate will not work if you scan a port that is not known to provide SSL/TLS:

In that case, you have to use service discovery (-sV):

 


Quickpost info


Thursday 4 April 2019

Quickpost: Browsers & Content-Disposition

Filed under: Quickpost — Didier Stevens @ 0:00

A quick check confirmed that response header Content-Disposition can direct browsers to display or save a file.

I used my tcp-honeypot.py to serve 3 HTTP responses:

HTTP/1.1 200 OK
Content-Disposition: inline

Line 1
Line 2
Line 3

 

HTTP/1.1 200 OK
Content-Disposition: attachment

Line 1
Line 2
Line 3

 

HTTP/1.1 200 OK
Content-Disposition: attachment; filename=”test.js”

Line 1
Line 2
Line 3

 

Only the Content-Disposition response header changes between these 3 responses.

With Content-Disposition response header “inline”, Internet Explorer displays the content inside the browser window:

With Content-Disposition response header “attachment”, Internet Explorer proposes to save the content to disk using a generated filename:

With Content-Disposition response header “attachment; filename=”test.js””, Internet Explorer proposes to open or save the content to disk using the provided filename test.js:

When option Open is selected, file test.js will be opened with the Windows scripting host (after warnings are clicked away).

The behavior of Edge is quite similar:

Google Chrome saves the file to disk without prompting the user (attachment):

And Firefox prompts the user (attachment):

Tests were conducted on a fully patched Windows 10 1809 machine, with default configurations for Internet Explorer and Edge.

The latest versions of Chrome and Firefox were installed with default configurations.


Quickpost info


Saturday 23 March 2019

Quickpost: PDF Tools Download Feature

Filed under: My Software,PDF,Quickpost — Didier Stevens @ 9:34

When I’m asked to perform a quick check of an online PDF document, that I expect to be benign, I will just point my PDF tools to the online document. When you provide an URL argument to pdf-parser, it will download the document and perform the analysis (without writing it to disk).


Quickpost info


 

Monday 3 December 2018

Quickpost: Developing for ESP32 with the Arduino IDE

Filed under: Hardware,Quickpost,WiFi — Didier Stevens @ 0:00

I have a couple of ESP32’s that can also be programmed with the Arduino IDE, provided the necessary board manager is installed:

After starting the IDE

I open the preferences:

And add the board manager URL for the ESP32 (https://dl.espressif.com/dl/package_esp32_index.json):

And via the Tools menu I launch the Boards Manager:

And install the ESP32 board manager:

And then I can select the right board (ESP32 Dev Module):

Then I can connect my ESP32 board to my Windows machine, and it will complain about missing drivers:

I install the CP210x drivers:

Then I can select the right port in the Tools menu:

And now everything is ready to program my ESP32. I will start with the WiFiScan example:

Which can then be compiled and uploaded to the ESP32 board:

Once it is uploaded and running, I can connect to the ESP32 board via the serial monitor:

 

 

Next Page »

Blog at WordPress.com.