Archive for the ‘Programming’ Category

The system call dispatcher on x86

Wednesday, August 23rd, 2006

The system call dispatcher on x86 NT has undergone several revisions over the years.

Until recently, the primary method used to make system calls was the int 2e instruction (software interrupt, vector 0x2e). This is a fairly quick way to enter CPL 0 (kernel mode), and it is backwards compatible with all 32-bit capable x86 processors.

With Windows XP, the mainstream mechanism used to do system calls changed; From this point forward, the operating system selects a more optimized kernel transition mechanism based on your processor type. Pentium II and later processors will instead use the sysenter instruction, which is a more efficient mechanism of switching to CPL 0 (kernel mode), as it dispenses with some needless (in this case) overhead of usual interrupt dispatching.

How is this switch accomplished? Well, starting with Windows XP, the system service call stubs do not hardcode a particular instruction (say, int 2e) anymore. Instead, they indirect through a field in the KUSER_SHARED_DATA block (“SystemCall”). The meaning of this field changed in Windows XP SP2 and Windows Server 2003 SP1; in prior versions, the SystemCall field held the actual code used to make the system call (and was filled in at runtime with the proper values). In XP SP2 and Srv03 SP1, in the interests of reducing system attack surface, the KUSER_SHARED_DATA region was marked non-executable, and SystemCall becomes a pointer to a stub residing in NTDLL (with the pointer value being adjusted at runtime based on the processor type, to refer to an appropriate system call stub).

What this means for you today is that on modern systems, you can expect to see a sequence like so for system calls:

0:001> u ntdll!NtClose
ntdll!ZwClose:
7c821138 b81b000000       mov     eax,0x1b
7c82113d ba0003fe7f       mov     edx,0x7ffe0300
7c821142 ff12             call    dword ptr [edx]
7c821144 c20400           ret     0x4
7c821147 90               nop

0x7ffe0300 is +0x300 bytes into KUSER_SHARED_DATA. Looking at the structure definition, we can see that this is “SystemCall”:

0:001> dt ntdll!_KUSER_SHARED_DATA
   +0x000 TickCountLowDeprecated : Uint4B
   +0x004 TickCountMultiplier : Uint4B
   +0x008 InterruptTime    : _KSYSTEM_TIME
   [...]
   +0x300 SystemCall       : Uint4B
   +0x304 SystemCallReturn : Uint4B
   +0x308 SystemCallPad    : [3] Uint8B
   [...]

Since my system is Srv03 SP1, SystemCall is a pointer to a stub in NTDLL.

0:001> u poi(0x7ffe0300)
ntdll!KiFastSystemCall:
7c82ed50 8bd4             mov     edx,esp
7c82ed52 0f34             sysenter
ntdll!KiFastSystemCallRet:
7c82ed54 c3               ret

On my system, the system call dispatcher is using sysenter. You can look at the old int 2e dispatcher if you wish, as it is still supported for compatibility with older processors:

0:001> u ntdll!KiIntsystemCall
ntdll!KiIntSystemCall:
7c82ed60 8d542408         lea     edx,[esp+0x8]
7c82ed64 cd2e             int     2e
7c82ed66 c3               ret

The actual calling convention used by the system call dispatcher is thus:

  • eax contains the system call ordinal.
  • edx points to either the argument array of the system call on the stack (for int 2e), or the return address plus argument array (for sysenter).

For most of the time, though, you’ll probably not be dealing directly with the system call dispatching mechanism itself. If you are, however, now you know how it works.

Beware of the sign bit

Tuesday, August 22nd, 2006

Signedness can trip you up in unexpected ways.

One example of this is the fairly innocuous islower function in the C standard library. This function takes an int and returns a value indicating to you whether it represents a lowercase or uppercase character.

The prototype for this function is:

int islower(
   int c 
);

Unfortunately, due to how C works, this code is likely to introduce subtle bugs depending on the input you give it. For instance, if you have a char array and iterate through it checking if each character is lowercase, you might naively write a program like so:

char ch[] = "...";
for (int = 0; ch[i]; i++)
{
 if (islower(ch[i]))
 {
   ...
 }
}

This code has a nasty bug in it, though, in that if your compiler defaults to char as an 8-bit signed value (most every mainstream compiler on mainstream platforms does nowadays), and if you are given a character value that has more than 7 significant bits (say, 150), you will go off into undefined-behavior-land because the compiler will sign extend ch[i] to a negative int value of -150 instead of an int value of 150. Depending on the implementation of islower, this could have various different (bad) effects; for the Microsoft C implementation, islower indexes into an array based on the given argument, so you’ll underrun an array and get garbage results back.

“Find all references” in VS 8

Monday, August 21st, 2006

There is a cool new feature in Visual Studio 8’s editor UI that is pretty useful if you are trying to determine the scope of a particular change or crossreference a variable or function to determine where it is used: “find all references”.

You can activate this by right clicking a symbol in the source code editor and selecting “find all references”.  A window will open near the build output that lists all source references to the symbol in the current solution (read: workspace).  This is also pretty useful in debugging, if you want to determine where a particular variable might be modified in a particular way.  For example, I used this recently to pull up a list of all locations that might set a particular class pointer to null when debugging a null pointer dereference bug.

Another good use for this is if you are working in unfamiliar code and want to get a feel for the scope of a change you make.  Of course, this utility has some limitations (it only searches within the current workspace), but it can be very handy to quickly gauge how impactful a change might be.

You might be using unhandled exception filters without even knowing it.

Friday, August 18th, 2006

In a previous posting, I discussed some of the pitfalls of unhandled exception filters (and how they can become a security problem for your application). I mentioned some guidelines you can use to help work around these problems and minimize the risk, but, as I alluded to earlier, the problem is actually worse than it might appear on the surface.

The real gotcha about unhandled exception filters is that you have probably used them before in programs or DLLs and not even known that you were using them, which makes it very hard to not use them in dangerous situations. How can this be, you might ask? Well, it turns out that the Microsoft C runtime library uses an unhandled exception filter to catch unhandled C++ exceptions and call the terminate handler registered by set_terminate.

This unhandled exception filter is setup by the internal CRT functions _cinit (via _initterm_e). If you have the CRT source handy, this lives in crt0dat.c. The call looks like:

/*
* do initializations
*/
initret = _initterm_e( __xi_a, __xi_z );

Here, “__xi_a” and “__xi_z” define the bounds of an array of function pointers to initializers called during the CRT’s initialization. There is a pointer to a function (_CxxSetUnhandledExceptionFilter) that sets up the unhandled exception filter for C++ exceptions in this array. Unfortunately, source code for the function used to setup _CxxUnhandledExceptionFilter is not present, but you can find it by looking at the CRT in a disassembler.

push    offset CxxUnhandledExceptionFilter
call    SetUnhandledExceptionFilter
mov     lpTopLevelExceptionFilter, eax
xor     eax, eax
retn

This is pretty standard; it is just saving away the old exception filter and registering its new exception filter. The unhandled exception filter itself checks for a C++ exception – if found, it calls terminate, otherwise it tries to verify that the previous exception filter points to executable code, and if so, it will call it.

push    esi
mov     esi, [esp+arg_0]
mov     eax, [esi]
cmp     dword ptr [eax], 0E06D7363h
jnz     short not_cpp_except
cmp     dword ptr [eax+10h], 3
jnz     short not_cpp_except
mov     eax, [eax+14h]
cmp     eax, 19930520h
jz      short is_cpp_except
cmp     eax, 19930521h
jnz     short not_cpp_except 

is_cpp_except:
call    terminate

not_cpp_except:
mov     eax, lpTopLevelExceptionFilter
test    eax, eax
jz      short old_filter_unloaded
push    eax             ; lpfn
call    _ValidateExecute
test    eax, eax
pop     ecx
jz      short old_filter_unloaded
push    esi
call    lpTopLevelExceptionFilter
jmp     short done

old_filter_unloaded:
xor     eax, eax

done:
pop     esi
retn    4

The problem with the latter validation is there is no way to tell if the code is part of a legitimate DLL, or part of the heap or some other allocation that has moved over where a DLL had previously been unloaded, which is where the security risk is introduced.

So, we have established that the CRT potentially does bad things by installing an unhandled exception filter – so what? Well, if you link to the DLL version of the CRT, you are probably fine. The CRT DLL is unlikely to be unloaded during the process lifetime and will only be initialized once.

The kicker is if you linked to the static (non-DLL) version of the CRT. This is where things start to get dicey. The dangerous combination here is that each image linked to the static version of the CRT will have its own copy of _cinit, and its own copy of _CxxSetUnhandledExceptionFilter, its own copy of _CxxUnhandledExceptionFilter, and soforth. What this boils down to is that every image linked to the static version of the Microsoft C runtime installs an unhandled exception filter. So, if you have a DLL (say one that hosts an ActiveX object) which links to the static CRT (which is pretty attractive, as for plugin type DLLs you don’t want to have to write a separate installer to ensure that end users have that cumbersome msvcr80.dll), then you’re in trouble. Since this is an especially common scenario (plugin DLL linking to the static CRT), you have probably ended up using an unhandled exception filter without knowing it (and probably without realizing the implications of doing so) – simply by making an ActiveX control usable by Internet Explorer, for example. This really turns into a worst case scenario when it comes to DLLs that host ActiveX objects. These are DLLs that are going to be frequently loaded and unloaded, are controllable by untrusted script, and are very likely to link to the static CRT to get out of the headache of having to manage installation of the DLL CRT version. If you put all of these things together and throw in any kind of crash bug, you’ve got a recipie for remote code execution. What is even worse is that this isn’t just quick-fixable with a patch to the CRT, as the vulnerable CRT version is compiled into your binaries and not in its own hotfixable standalone DLL.

So, in order to be truly safe from the dangers of unhandled exception filters, you also need to rid your programs of the static CRT. Yes, it does make setup more of a pain, but the DLL CRT is superior in many ways (not to mention that it doesn’t suffer from this security problem!).

Win32 calling conventions: __cdecl in assembler

Thursday, August 17th, 2006

Continuing on the series about Win32 calling conventions, the next topic of discussion is how the various calling conventions look from an assembler level.

This is useful to know for a variety of reasons; if you are reverse engineering (or debugging) something, one of the first steps is figuring out the calling convention for a function you are working with, so that you know how to find the arguments for it, how it deals with the stack, and soforth.

For this post, I’ll concentrate primarily on __cdecl.  Future posts will cover the other major calling conventions.

As I have previously described, __cdecl is an entirely stack based calling convention, in which arguments are cleaned off the stack by the caller.  Given this, you can expect to see all of the arguments for a function placed onto the stack before a function call is main.  If you are using CL, then this is almost always done by using the “push” instruction to place arguments on the stack.

Consider the following simple example function:

__declspec(noinline)
int __cdecl CdeclFunction1(int a, int b, int c)
{
 return (a + b) * c;
}

First, we’ll take a look at what calls to a __cdecl function look like. For example, if we look at a call to the function described above like so:

CdeclFunction1(1, 2, 3);

… we’ll see something like this:

; 119  : 	int v = CdeclFunction1(1, 2, 3);

  00000	6a 03		 push	 3
  00002	6a 02		 push	 2
  00004	6a 01		 push	 1
  00006	e8 00 00 00 00	 call	 CdeclFunction1
  0000b	83 c4 0c	 add	 esp, 12

There are basically three different things going on here.

  1. Setting up arguments for the target function. This is what the three different “push” instructions do. Note that the arguments are pushed in reverse order – you’ll always see them in reverse order if they are placed on the stack via push.
  2. Making the actual function call itself. After all the arguments are in place, the “call” instruction is used to transfer execution to the target. Remember that on x86, the call instruction implicitly pushes the return address on the stack. After the function call returns, the return value of the function is stored in the eax (or edx:eax) registers, typically.
  3. Cleaning arguments off the stack after the function returns. This is the purpose of the “add esp, 0xc” instruction following the “call” instruction. Since the target function does not adjust the stack to remove arguments after the call, this is up to the calller. Sometimes, you may see multiple __cdecl function calls be made in rapid succession, with the compiler only cleaning arguments from the stack after all of the function calls have been made (turning many different “add esp” instructions into just one “add esp” instruction).

It is also worth looking at the implementation of the function to see what it does with the arguments passed in and how it sets up a return value. The assembler for CdeclFunction1 is as so:

CdeclFunction1 proc near

a= dword ptr  4
b= dword ptr  8
c= dword ptr  0Ch

mov     eax, [esp+8]    ; eax = b
mov     ecx, [esp+4]    ; ecx = a
add     eax, ecx        ; eax = eax + ecx
imul    eax, [esp+0Ch]  ; eax = eax * c
retn                    ; (return value = eax)
CdeclFunction1 endp

This function is fairly straightforward. Since __cdecl is stack based for argument passing, all of the parameters are on the stack. Recall that the “call” instruction pushes the return address onto the stack, so the stack will begin with the return value at [esp+0] and have the first argument at [esp+4]. A graphical view of the stack layout (relative to “esp”) of this function is thus:

+00000000  r              db 4 dup(?)      ; (Return address)
+00000004 a               dd ?
+00000008 b               dd ?
+0000000C c               dd ?

In this case, there is no frame pointer in use, so the function accesses all of the arguments directly relative to “esp”. The steps taken are:

  1. The function fills eax with the value of the second argument (b), located at [esp+8] according to our stack layout.
  2. Next, the function loads ecx with the value of the first argument (a), which is located at [esp+4].
  3. Next, the function adds to eax the value of the first argument (a), now stored in the ecx register.
  4. Finally, the function multiplies eax by the value of the third argument (c), located at [esp+c].
  5. After finishing with all of the computations needed to implement the function, it simply returns with a “retn” instruction. Since the caller cleans the stack, the “retn” intruction (with a stack adjustment) is not used here; __cdecl functions never use “retn <displacement>“, only “retn”. Additionally, because the result of the “mul” instruction happened to be stored in the eax register here, no extra instructions are needed to set up the return value, as it is already stored in the return value register (eax) at the end of the function.

Most __cdecl function calls are very similar to the one discussed above, although there will typically be much more code to the actual function and the function call (if there are many arguments), and the compiler may play some optimization tricks (such as deferring cleaning the stack across several function calls). The basic things to look for with a __cdecl function are:

  • All arguments are on the stack.
  • The return instruction is “retn” and not “retn <displacement>“, even when there are a non-zero number of arguments.
  • Shortly after the function call returns, the caller cleans the stack of arguments pushed. This may be deferred later, depending on how the compiler assembled the caller.

Note that if you have been paying attention, given the above criteria, you’ve probably noticed that a __cdecl function with zero arguments will look identical to an __stdcall function with zero arguments. If you don’t have symbols or decorated function names, there is no way to tell the two apart when there are no arguments, as the semantics are the same in that special case.

That’s all for a basic overview of __cdecl from an assembler perspective. Next time: more on the other calling conventions at an assembly level.

Beware of custom unhandled exception filters in DLLs

Wednesday, August 16th, 2006

Previously, I had discussed some techniques for debugging unhandled exception filters.  There are some more gotchas relating to unhandled exception filters than just debugging them, though.

The problem with unhandled exception filters is that they are broken by design.  The API (SetUnhandledExceptionFilter) used to install them allows you to build a chain of unhandled exception filters as multiple images within a process install their own filter.  While this may seem fine in practice, it actually turns out to be a serious flaw.  The problem is that there is no support for removing these unhandled exception filters out of order.  If you do so, you often end up with a previous unhandled exception filter pointer used by some DLL that points to a now-unloaded DLL, because some DLL with an unhandled exception filter was unloaded, but the unhandled exception filter registered after it still has a pointer to the previous filter in the now unloaded DLL.

This turns out to (at best) cause your custom crash handling logic to appear to randomly fail to operate, and at worst, introduce serious security holes in your program.  You can read more about the security hole this introduces in the paper on Uninformed.org, but the basic idea is that if unhandled exception filters are unregistered out of order, you have a “dangling” function pointer that points to no-mans-land.  If an attacker can fill your process address space with shell code and then cause an exception (perhaps an otherwise “harmless” null pointer dereference that would cause your program to crash), he or she can take control of your process and run arbitrary code.

Unfortunately, there isn’t a good way to fix this from an application perspective.  I would recommend just not ever calling the previous unhandled exception filter, as there is no way to know whether it points to the real code that registered it or malicious code that someone allocated all over your process address space (called “heap spraying” in exploitation terminology).

You still have to deal with the fact that someone else might later install an unhandled exception filter ahead of yours, though, and then cause the unhandled exception filter chain to be broken upstream of you.  There is no real good solution for this; you might investigate patching SetUnhandledExceptionFilter or UnhandledExceptionFilter to always call you, but you can imagine what would happen if two functions try to do this at the same time.

So, the moral of the story is as follows:

  1. Don’t trust unhandled exception filters, as the model is brittle and easily breaks in processes that load and unload DLLs frequently.
  2. If you must register an unhandled exception filter, do it in a DLL that is never unloaded (or even the main .exe) to prevent the unhandled exception filter from being used as an attack vector.
  3. Don’t try to call the previous unhandled exception filter pointer that you get back from SetUnhandledExceptionFilter, as this introduces a security risk.
  4. Don’t install an unhandled exception filter from within a plugin type DLL that is loaded in a third party application, and especially don’t install an unhandled exception filter in a plugin type DLL that gets unloaded on the fly.

Unfortunately, it turns out to be even harder than this to not get burned by unhandled exception filter chaining.  More on that in a future posting.

Why you shouldn’t touch things in DllMain

Wednesday, August 2nd, 2006

One topic that comes up on the Microsoft newsgroups every once and awhile is whether it is really that bad to be doing complicated things in DllMain.

The answer I almost always give is yes, you should always stay away from that.

This is a particularly insidious topic, as many people do things in DllMain anyway, despite MSDN’s warnings to the contrary, see that it seems to work on their computer, and ship it in their product / program / whatever.  Unfortunately, this often ends up with hard to debug problems that only fail on a particular customer computer – the kind that you really don’t want to get stuck debugging remotely.  The reason for this is that many of the things that can go wrong in DllMain are environment specific.  This is because depending on whether a particular DLL that you are calling inside of DllMain when you break the rules is loaded your DLL was loaded or not will often make the difference.

If you dynamically load a DLL in DllMain and it has not already been loaded yet, you will get back a valid HMODULE, but in reality the initializer function for the new DLL will not be called until after your DllMain returns.  However, if the DLL had already been loaded by something else and your LoadLibrary call just incremented a reference count, then DllMain has already been called for the DLL.  Where this gets ugly is if you call a function that relies on some state setup by DllMain, but on your development/test boxes, the DLL in question had already been loaded for some reason.  If on a customer computer, you end up being the first to load the DLL, you’ll have mysterious corruption and/or crashes resulting from this which never repro in the lab for you.

So, stay away from complicated things in DllMain.  There are other reasons too, but this is the big one for current OS releases (of course, Vista and future versions may add other things that can go wrong if you break the rules).

If you are interested, Michael Grier has an excellent series on this topic to help you understand just what can go wrong in DllMain.

Don’t forget to turn off your debug prints when you ship your product

Tuesday, August 1st, 2006

One thing that really annoys me when I am debugging a problem is when people ship their products with debug prints on in the release versions.

This just sucks, it really does.  It’s hard to pay attention to debug prints for things that matter if half of the third party software on your computer is compiled with debug prints enabled.  One example of a particularly annoying offender of this is the HGFS (host-guest filesystem) network filesystem provider shipped by VMware.  Now, I love VMware, but it’s really, really annoying that every single VM in existance with VMware Tools installed has built in debug print spam from every process that touches the network provider stack.

So, change those DbgPrint calls to KdPrint if you are working on a driver, and if you’re in user mode, make sure that OutputDebugString calls aren’t compiled in if you are in release mode.  Alternatively, leave them there but make sure that they are off by default unless you set a special configuration or registry parameter.

Fun with Logitech MX900 Bluetooth receivers

Thursday, July 6th, 2006

For some time now, I have been partial to cordless mice; they’re much less of a hastle to use than “conventional” mice, especially if you use a laptop primarily.  Several months ago, I decided to upgrade from a Logitech MX700 cordless optical mouse to an MX900 Bluetooth optical mouse, so that with my new Bluetooth-enabled laptop, I would not need to bring the bulky charger/base station it to plug into my computer at work every day.

As it would happen, the MX900 base station has a Bluetooth receiver that you can use (in conjunction with the WIDCOMM – now Broadcom – Bluetooth stack) to connect to other Bluetooth devices out there.  At the time when I first got the mouse, I didn’t really see this as all that useful, as my laptop already had an integrated Bluetooth receiver that was supposed by the Microsoft Bluetooth stack included with Windows XP SP2.  Recently, however, I got a second Bluetooth enabled device – a new cell phone – and decided that I might as well see what I could do with getting one of my other computers at my apartment talking to it.

 Now, a bit of background about the MX900 base station.  It’s actually a pretty neat thing – during boot (and even in normal operating system use, if you don’t have the right software installed), the MX900 will act as if it were a standard HID USB mouse even though it is actually connected through Bluetooth – “HID emulation mode”, as I call it.  This is a cool feature because it allows you to use your standard USB mouse drivers with the MX900 without having to go install all of Logitech’s drivers and the like before the mouse will work.  Additionally, if your BIOS supports USB input devices (most modern ones do), you can use the MX900 there even though it functions over Bluetooth.

As a result of the handy HID emulation mode feature of the MX900, I can already use it as a mouse on my other, non-Bluetooth computers as if it were a plain USB mouse, with the operating system none the wiser.  Therein is the rub, however; in order for me to be able to connect the MX900 base station to non-keyboard/mouse devices, I need to be able to convince Windows that it is actually a full fludged Bluetooth receiver and not just a USB mouse.  Normally, Logitech’s SetPoint software installs a program that runs when you log in to Windows and magically turns the MX900 base station into Bluetooth HCI mode, that is, native Bluetooth receiver mode – assuming you had installed the WIDCOMM bluetooth stack, that is.

 So, I set out to install SetPoint on my test computer.  Unfortunately, this didn’t really work out as planned.  The computer I had available to work with was running Windows Server 2003 and it seems that the SetPoint installer for the version I needed wasn’t exactly well tested on Windows Server 2003.  The installer would tend to blow up with heap corruption right away, making it impossible to do anything.  I then tried running the installer under the Windows XP SP2 compatibility layer (right click the .exe, there is a compatibility option in the propsheet if you an administrator).  This got me a bit further, but the Logitech installer inevitibly crashed.

Looking around a bit, there was actually a more recent version of SetPoint available (Logitech supports 2.22 with the MX900, the latesting being 2.60 which is designed for Logitech’s Bluetooth keyboard and mouse suite).  I figured that it was worth a try to install 2.60 and see if that worked.  Sure enough, the installer actually didn’t crash this time, but unfortunately, it would not accept that I had a Bluetooth device that was compatible with it; I got stuck at a dialog that instructed me to connect my Logitech Bluetooth device and hit OK, or skip the installation of the Bluetooth support and install “just plain” SetPoint.  Well, that sucks – the whole point of this excercise was to get Bluetooth working on the test computer, not Logitech’s middleware.

Poking around in my temp directory, I noticed that while the installer was running, one of the temporary directories it created seemed to have a second installer for the WIDCOMM Bluetooth stack (WIDCOMM – now Broadcom - does not make their software directly available for download to end users, and instead requires them to get it bundled with hardware from an equipment manufacturer).  A-ha – maybe there was light at the end of the tunnel, after all.  While the Logitech installer was waiting for me to hit Next in one of the wizard steps, I manually launched the WIDCOMM installer from the temp directory that the Logitech installer had created.  The installer actually worked fine, except that it too complained that it could not detect an active Bluetooth device (fortunately, though, it allowed me the option of continuing the install anyway).

After the WIDCOMM installer finished, I canceled out of the Logitech install and went to see if I could convince the WIDCOMM stack that I really did have a Bluetooth device.  After not getting anywhere on my own, I turned to Google, where I found a number of people complaining about the same problem (about not being able to turn their MX900 receivers to native HCI mode), but no quick solution for Windows.  I did, however, find something for Linux – a program called “hid2hci” that knew how to turn an MX900 Bluetooth receiver to a HCI mode.  Fortunately, source code was included, so it was easy enough to see what it was doing.  Unfortunately, I don’t really have a whole lot of experience with USB, on Windows or other platforms, and what I needed to do was port hid2hci to Windows.

The linux program is fairly simple.  Even with my limited knowledge of USB, what it was doing appeared to be straightforward enough.  The program sends three vendor-specific HID output reports (a HID report is the basic way to either report information from a device to the computer or change a setting on the device for HID devices) to the MX900 receiver.  After receiving the special three HID reports, the MX900 changes its PnP ID and appears to the operating system as a different piece of hardware, an HCI Bluetooth receiver.

 So, I got started working on a Windows version of hid2hci.  The first step was to crack open the Windows DDK documentation (you can download the DDK with the free KMDF 1.1 ISO distribution) and start looking around for ways to talk to USB devices.  It turns out that there is already a rather full featured API to do this, from both user mode and kernel mode.  Because all I really needed to do here was to send three custom commands to the MX900, I picked the user mode HID API to start with.

The user mode HID APIs live in hid.dll and come in two flavors: HID Parser routines (prefixed HidP_), and HID Device/Driver routines (prefixed HidD_).  The former provide a high level interface for formatting, preparing, and parsing the actual USB HID reports, while the latter deal with actually sending and receiving USB HID reports.  The API is a bit cumbersome, but it turns out to not be too hard to use.  The basic idea is:

  1. Open a handle to the HID device that you want to talk to with CreateFile.
  2. Call HidD_GetPreparsedData to load the preparsed data for the collection.  This basically retrieves all sorts of information about the HID device ahead of time in one blob that is later used by the HID Parser routines to ensure that you are matching the report formats used by the device.
  3. Call HidD_GetAttributes and HidD_GetCaps to make sure that the device is the one you meant to connect to and supports the HID usages that you are going to use.  Here, I wanted to verify that the vendor specific usage page 0xFF00, usage 0x0001 is present (as this is where I wanted to send the magic 3 reports to turn the receiver to HCI mode).
  4. Build the HID report.  I originally attempted to do this using the high level HID Parser APIs, but I couldn’t get it to work right – the HID Parser APIs kept complaining that the usage I requested didn’t exist.  I assume that this is because Logitech never bothered to completely describe the format of the HID reports for this vendor specific usage, resulting in the high level parser becoming unhappy if you asked it to format a report for that usage.  As a result, I just built the report manually by just writing the raw data into the report buffer and prepending the HID report ID (0x10) to the report data.
  5. Send the completed report to the device.  There are two ways to do this – WriteFile and HidD_SetOutputReport.  I attempted to use WriteFile first, but it always failed with ERROR_ACCESS_DENIED.  Not being an expert on HID devices, I tried the other documented routine (HidD_SetOutputReport) send the report, which worked fine.  HidD_SetOutputReport internally just sends a special IOCTL to the driver for the device you open, so the code paths are in fact different.

Steps 4 and 5 will basically need to be repeated for each of the three HID reports that we need to send to the Bluetooth receiver.

 There are a couple of other things that you need to do in order to get this to work that I glossed over.  In particular, you need to actually find the device that you want to open with CreateFile.  The best way to do this is by using the SetupDi family of APIs to enumerate all HID devices.  We can then verify that each device has the expected vendor ID, product ID, and HID usages before we try to send it the magical commands to convert the device to native HCI mode.

After putting all of these steps together, I had something that appeared to do what the Linux hid2hci program did.  Sure enough, when I ran my prototype hid2hci port on my test box, a new device appeared in Device Manager, which was detected by the WIDCOMM Bluetooth stack as a Cambridge Silicon Radio Bluetooth Receiver.  Success!

The device itself stays in native HCI mode until it is reset (i.e. rebooting the computer or unplugging the receiver itself), so the HCI conversion program needs to either periodically scan for devices to switch to HCI mode, or register for a device change notification in order to enable full Bluetooth functionality if you reboot or disconnect the Bluetooth receiver.

The source code for my Logitech HID-to-HCI convertor program is available for download if you are interested in it.  You will need Windows DDK installed in order to build it.  Alternatively, you can download the binary if you just want the program and don’t want to install the development environment to build it.  It takes two command line arguments: the hexadecimal vendor ID and hexadecimal product ID of the device that it should switch from HID emulation mode to native HCI mode.  You can find these under Device Manager if you are using Windows XP SP2 or Windows Server 2003 SP1 by going to your device’s property sheet and going to the details tab, then selecting the Hardware Ids listbox item.  The device you want is probably going to be named “USB Composite Device”.  If you are using an MX900, then you can use 046d for the vendor ID and c705 for the product ID.  There is no harm in running the program repeatedly after it has already switched your device(s) to HCI mode.