DirectShow Filter Graph Spy on Vista

I have been receiving comments that Filter Graph Spy tool does not work with Microsoft Vista operating system. I never had a moment to check until recently, and this time I realized that it really does not work. I am definitely aware of dramatic changes introduced with this operating system, and in particular UAC feature, virtualization and changes in security. No wonder this was the first guess that security was the cause, however the investigation showed there was a trail of issues underneath…

Investigation details deserve a separate post, while this one briefly outlines the issues and also accompany the repository update with a version compatible with Vista OS.

First of all, COM registration of the DLL (which definitely requires privilege elevation) succeeded on Vista. This means the registration procedure did not encounter any errors on the way, or poorly written code ignored the problem. It appeared that the source of the problem was CoTreatAsClass API, which failed to do the requested action, however returned status code indicating successful operation. This definitely looks like a bug and further comments on this particular behavior are expected to appear on Windows Applications Security MSDN forum, where I opened a topic on the matter.

With a COM TreatAs feature activated, the class’s behavior to instantiate instead of DirectShow’s CLSID_FilterGraph is restored, and in particular the DLL generates FilterGraphSpy.log log file on filter graph activity. Note that log file location is OS dependent (due to Vista’s permissions and file system virtualization):

  • pre-Vista OS: root of syste drive, typically C:\
  • starting Vista, administrator with elevated privileges: CSIDL_COMMON_APPDATA, typically C:\ProgramData (note this directory is hidden by deafult)
  • starting Vista, without elevated administrator privileges: CSIDL_LOCAL_APPDATA, typically C:\Users\$(UserName)\AppData\Local (note that AppData directory is hidden by deafult)

Still even with the log file generated and indicating activation of the spy, it was unable to connect to remote graph through the running object table (ROT). It appeared that the ROT entires are there where expected, it was OK to get an object from ROT and the problem came from QueryInterface code:

CComPtr<IUnknown> pFilterGraphUnknown;
ATLENSURE_SUCCEEDED(pRunningObjectTable->GetObject(pMoniker, &pFilterGraphUnknown));
CComQIPtr<IMyFilterGraph> pFilterGraph = pFilterGraphUnknown; // E_NOINTERFACE

The call reached the original object but COM subsystem was unable to marshal the interface through apartments to enable interprocess communication on it. The reason for this is absence of PSFactoryBuffer class (CLSID {92A3A302-DA7C-4A1F-BA7E-1802BB5D2D02}), which provides proxy/stub pairs for marshaling well known DirectShow interfaces in the Vista’s version of quartz.dll. As mentioned by Microsoft’s Mike Wasson, this class was moved from quartz.dll into Vista SDK’s proppage.dll, so in order to obtain connectivity to remote DirectShow graphs starting Vista, one needs to install this DLL with Windows SDK, or otherwise have it registered with the operating system.

Also note that DirectShow-enabled applications that have their filter graphs published on ROT will need an utility application such as GraphEdit started with the same permissions (elevated or not) in order to be able to access ROT entires.

To sum everything up, to install Alax.Info DirectShow Filter Graph Spy on Vista:

  • get the latest FilterGraphSpy.dll
  • regsvr32 FilterGraphSpy.dll on target system from administrative command prompt, with elevated privileges (note you should have a log file FilterGraphSpy.log generated in CSIDL_COMMON_APPDATA directory, with a few lines indicating registration success)
  • get Windows SDK and make $(WindowsSDK)\Bin\proppage.dll file registered on target system (also administrative regsvr32), note that it is necessary to restart DirectShow-enabled applications and GraphEdit after DLL registration to get graphs visible through ROT
  • mind the log file directories with FilterGraphSpy.log file

A partial Visual C++ .NET 2008 source code is available from SVN, release binary included.

DHCP Server: List of Issued Leases

Alax.Info DHCP Server was updated to provide user interface and show a list of issued DHCP leases, including:

  • hardware (MAC) address and IP address correspondence
  • latest date and time of DHCP lease issue
  • sortable list to be able to conveniently arrange entries and lookup items of interest

DHCP Lease List

Other changes include:

  • stores latest lease issue date and time in registry to be able to locate recently issued leases
  • indicates Windows service status through system tray icon (running or stopped)
  • minor fixes

Release information:

Hint on how to easily find your filter graph on running object table (ROT)

With a lot of DirectShow Filter Graphs published on Running Object Table, especially those automatically published by Filter Graph Spy utility, it might be a bit tricky to locate your graph of interest in the list.

Filter graphs are published with a textual moniker item name of predefined format, which is recognized by GraphEdit or GraphStudio, or similar utilities as an item corresponding to a filter graph. A template for such a string is “FilterGraph %08x pid %08x“, which obviously only contains raw pointer address and process identifier, which only help a bit in looking up for proper graph interactively. However, it is important how exactly applications are recognizing filter graph related names. For example, GraphStudio does it the following way:

rot->EnumRunning(&emon);
emon->Reset();
while (emon->Next(1, &moniker, &f) == NOERROR) {

    // is this a graph object ?
    LPOLESTR    displayname;
    moniker->GetDisplayName(bindctx, NULL, &displayname);

    CString        name(displayname);
    if (name.Find(_T("!FilterGraph")) == 0) {

The items that match are then listed in GUI with an original string, which means that it is possible to provide an informational suffix to be able to locate the graph in a more convenient way, e.g. with a process image name, not only identifier (“; process: …” was appended to the item name):

GraphStudio's ROT Items

GraphEdit is using another method and is more strict in selecting among available items. AFAIR earlier versions did not allow custom suffixes in item names, however the latest version still picks the items up from the global list. However, GraphEdit does not show graph’s original item name, so suffixes are merely useless with GraphEdit.

GraphEdit ROT Items

Filter Graph Spy utility was updated to automatically append process name suffix, which should be OK for both GrapEdit and GraphStudio. Still, the feature can be disabled through registry DWORD value named “Enable ROT Moniker Item Name Suffix” under HKEY_LOCAL_MACHINE\SOFTWARE\Alax.Info\Utilities. The value of zero, or missing, is the default behavior to enable suffixes. The value of 1 disables the feature, the value of 2 makes sure it is enabled.

static CConstIntegerRegistryValue g_nEnableRotMonikerItemNameSuffix(_T("Enable ROT Moniker Item Name Suffix")); // 0 Default, 1 Disable, 2 Enable
if(g_nEnableRotMonikerItemNameSuffix != 1)
{
    TCHAR pszPath[MAX_PATH] = { 0 };
    _W(GetModuleFileName(NULL, pszPath, DIM(pszPath)));
    CString sItemName = AtlFormatString(_T("%s; process: %s"), m_RunningFilterGraph.GetDefaultMonikerItemName(GetControllingUnknown()), FindFileName(pszPath));
    m_RunningFilterGraph.SetFilterGraph(GetControllingUnknown(), CStringW(sItemName));
} else
    m_RunningFilterGraph.SetFilterGraph(GetControllingUnknown())

A partial Visual C++ .NET 2008 source code is available from SVN, release binary included.

Video Decoder DMO and AM_SAMPLE_PREROLL

This does not seem to be documented anywhere, so it makes sense to mention. A video decoder, wrapped by DMO Wrapper Filter, will receive preroll media samples with AM_SAMPLE_PREROLL flag (alternatively available using IMediaSample::IsPreroll), but it won’t even forward these samples to the underlying DMO, instead they are just ignored.

MSDN says:

Preroll samples are processed but not displayed. They are located in the media stream before the displayable samples.

However this behavoir of DMO Wrapper Filter does not seem to be correct. A DMO might require (in my case, maybe there are other scenarios) to initialize its decoding context from a splice point and then be able to decode further samples. The way the wrapper is skipping samples it appears that DMO is not receiving splice point data and won’t be able to start decoding of non-preroll samples until it receives a non-preroll splice point media sample…

An easy tweak with PHPBB forums to avoid automated registration of spambot users

Spammers  finally reached PHPBB version 3 “Olympus” default CAPTCHA automated OCR task in their development schedule and recently started registering bot users passing the provided CAPTCHA confirmation code.

PHPBB3 CAPTCHA Sample

Luckily to them, PHPBB3 default CAPTCHA code is ridiculously easy to OCR, os basically this was rather expected. It does not however mean that there is no way to effectively stop automated registrations without spending too much time on forum engine update.

Automated registration spider sends HTTP POST with the code it OCR’red from the image and we can leave the same code querstion in place and just ask the interactive user to type some extra information into input field. For example, it is possible to instruct him/her to type an extra asterisk before the code, so that the following is expected to be typed in: *25K9RGS. This makes the only thing important: to put a proper not for the user so that he/she is aware that he needs this character to be also entered. PHP code update is relatively simple:

includes\ucp\ucp_register.php, near line 235:

<?php
////////////////////////////////
// NOTE: Checking extra asterisk in front of CAPCTCHA code to prevent from automated CAPTCHA readers
$confirm_code = $data['confirm_code'];
$confirm_code = (substr($confirm_code, 0, 1) == "*") ? substr($confirm_code, 1) : "";
if (strcasecmp($row['code'], $confirm_code) === 0)
// original:
//if (strcasecmp($row['code'], $data['confirm_code']) === 0)
////////////////////////////////
?>

then default style (e.g. subsilver2) HTML tempalte needs to have an extra character (9 instead of 8) space in the input field, styles\subsilver2\template\ucp_register.html, line 92:

<td class="row2"><input class="post" type="text" name="confirm_code" size="9" maxlength="9" /></td>

And finally the CONFIRM_CODE_EXPLAIN comment needs to be updated to instruct user to type the extra asterisk in language\en\common.php.