Didier Stevens

Monday 4 May 2020

Quickpost: Empty ZIP File

Filed under: Quickpost — Didier Stevens @ 0:00

As a reminder to myself, here is the hexdump of an empty ZIP file: 50 4B 05 06 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

And here is the cut-bytes.py command to generate an empty ZIP file:

C:\Demo>cut-bytes.py -a : #e#’PK’+0x0506+repeat(0x12,0x00)
00000000: 50 4B 05 06 00 00 00 00 00 00 00 00 00 00 00 00 PK…………..
00000010: 00 00 00 00 00 00 ……

Quickpost info

Sunday 26 April 2020

Quickpost: My SpiderMonkey’s Cheat Sheet

Filed under: My Software,Quickpost — Didier Stevens @ 8:27

I have a modified version of SpiderMonkey, Mozilla’s (old) JavaScript parser, that helps me with JavaScript analysis.

Details here.

js.exe -e “document.output(‘x’);” sample.js
zipdump.py -s 1 -d sample.js.zip | js.exe -e “document.output(‘a’);” –
zipdump.py -s 1 -d sample.js.zip | js.exe -e “document.output(‘d’);” –
zipdump.py -s 1 -d sample.js.zip | js.exe -e “document.output(‘X’);” –
zipdump.py -s 1 -d sample.js.zip | js.exe -e “document.output(‘A’);” –
zipdump.py -s 1 -d sample.js.zip | js.exe -e “document.output(‘D’);” –
zipdump.py -s 1 -d sample.js.zip | js.exe -e “document.output(‘f’);” –
zipdump.py -s 1 -d sample.js.zip | js.exe –

Saturday 28 March 2020

Quickpost: Windows Domain Controllers Have No Local Accounts

Filed under: Quickpost — Didier Stevens @ 0:00

Windows domain controllers have no local accounts. I think I learned this back when I made my “Practice ntds.dit File Overview” series of blog posts.

Today I had to search for a Microsoft document covering this: Built-in and Account Domains.

Quickpost info

Monday 23 March 2020

Quickpost: User-Agent: Microsoft Office Excel 2014

Filed under: Networking,Quickpost — Didier Stevens @ 14:25

To start: there is no version 2014 of Microsoft Office.

That’s why I was intrigued when I saw User Agent String “Microsoft Office Excel 2014” appearing in Wireshark when I did some tests with Excel’s data importing features.

With Excel 2019, when I get data from a CSV file and provide an URL (in stead of a local filename) like this:

Excel will issue several OPTIONS and HEAD requests, with different User Agent Strings:

And finally, a GET request to download the file:

Xavier Mertens has mentioned User Agent String “Microsoft Office Excel 2014” in another context: “Microsoft Apps Diverted from Their Main Use“.

Quickpost info

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:


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;


BOOL WINAPI DllMain(HMODULE hModule, DWORD dwReason, LPVOID lpReserved)
	switch (dwReason)
    return TRUE;

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

	SetServiceStatus(g_serviceStatusHandle, &g_serviceStatus);

	return NO_ERROR;

	while (TRUE)
		if (g_serviceStatus.dwCurrentState == SERVICE_RUNNING)
			OutputDebugString(L"Working ...");

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);
	for (dwIter=0; dwIter<dwArgc; dwIter++)

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

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

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

	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");

	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
Use at your own risk

  2019/04/03: start


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

« Previous PageNext Page »

Blog at WordPress.com.