Holy cow, I wrote a book!
A customer wanted to know how they could improve the security of USB thumb drives in their organization. Specifically, they wanted to block access to removable media devices (primarily USB thumb drives), but provide a list of exceptions for specific thumb drives. Fortunately, there's a whitepaper that covers exactly this topic and explains how to set up your policies to accomplish this.
Step-By-Step Guide to Controlling Device Installation Using Group Policy
The verb phrase touch base is in general business jargon use, but it's quite popular at Microsoft.
To touch base with someone is to contact someone in a lightweight and mostly-informal sort of way. In other words, it takes the form of a piece of email or a brief office visit rather than a formal meeting with an agenda.
Bob, can you touch base with the Nosebleed team to verify that this design change won't affect them?
Bob is expected to contact a representative from the Nosebleed team, either by sending email, or by telephone, or by stopping by their office for a quick chat. If Bob sets up a one-hour meeting with a dozen engineers from both sides, then he's blowing the issue out of proportion.
Ry Jones wants to know what other podcasts I subscribe to.
Remember, I wrote this back in 2011.
Here's what I listen to. Note that I am not averse to fast-forwarding over parts that don't interest me, such as when they discuss a movie that I simply don't care about.
The syntax for specifying that requests to import a function from your DLL should be forwarded to another DLL is
; A.DEF EXPORTS Dial = B.Call
This says that if somebody tries to call Dial() from A.DLL, they are really calling Call() in B.DLL. This forwarding is done in the loader. Normally, when a client links to the function A!Dial, the loader says, "Okay, let me get the address of the Dial function in A.DLL and store it into the __imp__Dial variable." It's the logical equivalent of
Dial()
A.DLL
Call()
B.DLL
A!Dial
Dial
__imp__Dial
client::__imp__Dial = GetProcAddress(hinstA, "Dial");
When you use a forwarder, the loader sees the forwarder entry and says, "Whoa, I'm not actually supposed to get the function from A.DLL at all! I'm supposed to get the function Call from B.DLL!" So it loads B.DLL and gets the function Call from it.
Call
hinstB = LoadLibrary("B.DLL"); client::__imp__Dial = GetProcAddress(B, "Call");
(Of course, the loader doesn't actually do it this way, but this is a good way of thinking about it.)
But what if the function Call was exported by ordinal? How do you tell the linker, "Please create a forwarder entry for Dial that forwards to function 42 in B.DLL?"
I didn't know, but I was able to guess.
Back in the days of 16-bit Windows, there were two ways to obtain the address of a function exported by ordinal. The first way is the way most people are familiar with:
FARPROC fp = GetProcAddress(hinst, MAKEINTRESOURCE(42));
The second way uses an alternate formulation, passing the desired ordinal as a string prefixed with the number-sign:
FARPROC fp = GetProcAddress(hinst, "#42");
You can hide a number inside a string by using MAKEINTRESOURCE, and you can hide a string inside a number by using the '#' character.
MAKEINTRESOURCE
Given that the number sign has been used in the past to hide a number inside a string, I figured it was worth a shot to see if the loader carried this convention forward. (No pun intended.)
; A.DEF EXPORTS Dial = B.#1
Hey, check it out. It works.
Sometimes a little knowledge of history actually helps you solve problems in the present day.
This time, I'm not going to set up a story. I'm just going to go straight to the punch line.
A customer overrode the new operator in order to add additional instrumentation. Something like this:
new
struct EXTRASTUFF { DWORD Awesome1; DWORD Awesome2; }; // error checking elided for expository purposes void *operator new(size_t n) { EXTRASTUFF *extra = (EXTRASTUFF)malloc(sizeof(EXTRASTUFF) + n); extra->Awesome1 = get_awesome_1(); extra->Awesome2 = get_awesome_2(); return ((BYTE *)extra) + sizeof(EXTRASTUFF); } // use your imagination to implement // operators new[], delete, and delete[]
This worked out okay on 32-bit systems because in 32-bit Windows, MEMORY_ALLOCATION_ALIGNMENT is 8, and sizeof(EXTRASTUFF) is also 8. If you start with a value that is a multiple of 8, then add 8 to it, the result is still a multiple of 8, so the pointer returned by the custom operator new remains properly aligned.
MEMORY_ALLOCATION_ALIGNMENT
sizeof(EXTRASTUFF)
operator new
But on 64-bit systems, things went awry. On 64-bit systems, MEMORY_ALLOCATION_ALIGNMENT is 16, As a result, the custom operator new handed out guaranteed-misaligned memory.
The misalignment went undetected for a long time, but the sleeping bug finally woke up when somebody allocated a structure that contained an SLIST_ENTRY. As we saw earlier, the SLIST_ENTRY really does need to be aligned according to the MEMORY_ALLOCATION_ALIGNMENT, especially on 64-bit systems, because 64-bit Windows takes advantage of the extra "guaranteed to be zero" bits that 16-byte alignment gives you. If your SLIST_ENTRY is not 16-byte aligned, then those "guaranteed to be zero" bits are not actually zero, and then the algorithm breaks down.
SLIST_ENTRY
Result: Memory corruption and eventually a crash.
Keytips are those little pop-up keyboard accelerator thingies that appear on the Ribbon when you tap the Alt key:
46 00 0C 20 46 00 0C 20 ----- ----- ----- ----- F ????? F ?????
The question marks are U+200C, formally known as ZERO WIDTH NON-JOINER. Michael Kaplan discussed the character (and its evil twin the ZERO WIDTH JOINER) some time ago.
The ZERO WIDTH NON-JOINER (or ZWNJ to his friends) is a hint to the font engine that the characters on opposite sides of the ZWNJ should not be combined into a ligature. In English, the ZWNJ would prevent two consecutive lowercase "f"s from being converted into a "ff" ligature. Ligatures are fading from use in contemporary printing, probably due to the rise of computers. Back in the old days, you saw all sorts of neat ligatures, like "st".
Breaking up the ligature is important when presenting keyboard accelerators. Imagine if the keyboard accelerator for a key sequence was "A" followed by "E". If this were displayed as "Æ", users would waste their time looking for an "Æ" key on their keyboard. Although English doesn't have many ligatures any more, many other languages still employ them heavily. (You may have noticed that the keytip was a bit overzealous with the ZWNJ, putting one at the end of the string even though there was nothing for the second F to be unjoined from!)
So if you encounter one of these ZWNJ characters, don't be afraid. He's just there to break things up. And as Michael notes, ZWNJ and ZWJ "are supposed to be ignored in things like the Unicode Collation Algortihm."
Update: An official fix for this issue has been released to Windows Update, although I must say that I think my patch has more style than the official one. You do not need to patch your binary. Just keep your copy of Windows 8 up to date and you'll be fine.
For the five remaining Microsoft Money holdouts (meekly raises hand), here's a patch for a crashing bug during import of account transactions or when changing a payee of a downloaded transaction in Microsoft Money Sunset Deluxe. Patch the mnyob99.dll file as follows:
Note that this patch is completely unsupported. If it makes your computer explode or transfers all your money to an account in the Cayman Islands, well, too bad for you.
If you are not one of the five remaining customers of Microsoft Money, this is a little exercise in application compatibility debugging. Why application compatibility debugging? Because the problem seems to be more prevalent on Windows 8 machines.
Note that I used no special knowledge about Microsoft Money. All this debugging was performed with information you also have access to. It's not like I have access to the Microsoft Money source code. And I did this debugging entirely on my own. It was not part of any official customer support case or anything like that. I was just debugging a crash that I kept hitting.
The crash occurs in the function utlsrf08!DwStringLengthA:
utlsrf08!DwStringLengthA
utlsrf08!DwStringLengthA: push ebp mov ebp,esp mov eax,dword ptr [ebp+8] lea edx,[eax+1] again: mov cl,byte ptr [eax] inc eax test cl,cl jne again sub eax,edx pop ebp ret 4
The proximate cause is that the string pointer in eax is garbage. If you unwind the stack one step, you'll see that the pointer came from here:
eax
lea eax,[ebp-20Ch] push eax call dword ptr [__imp__GetCurrentProcessId] push eax push offset "Global\TRIE@%d!%s" lea eax,[ebp-108h] push 104h push eax call mnyob99!DwStringFormatA add esp,14h lea eax,[ebp-2E4h] push eax push 5Ch push dword ptr [ebp-2E4h] ; invalid pointer call mnyob99!DwStringLengthA sub eax,7 push eax lea eax,[ebp-101h] push eax jmp l2 l1: mov eax,dword ptr [ebp-2E4h] mov byte ptr [eax],5Fh lea eax,[ebp-2E4h] push eax push 5Ch push dword ptr [ebp-2E4h] call mnyob99!DwStringLengthA push eax push dword ptr [ebp-2E4h] l2: call mnyob99!FStringFindCharacterA cmp dword ptr [ebp-2E4h],edi jne l1
I was lucky in that all the function calls here were to imported functions, so I could extract the names from the imported function table. For example, the call to DwStringFormatA was originally
DwStringFormatA
call mnyob99!CBillContextMenu::SetHwndNotifyOnGoto+0x1e56a (243fc3cc)
But the target address is an import stub:
jmp dword ptr [mnyob99+0x1ec0 (24001ec0)]
And then I can walk the import table to see that this was the import table entry for utlsrf08!DwStringFormatA. From the function name, it's evident that this is some sort of sprintf-like function. (If you disassemble it, you'll see that it's basically a wrapper around vsnprintf.)
utlsrf08!DwStringFormatA
sprintf
vsnprintf
Reverse-compiling this code, we get
char name[...]; char buffer[MAX_PATH]; char *backslash; ... DwStringFormatA(buffer, MAX_PATH, "Global\\TRIE@%d!%s", GetCurrentProcessId(), name); // Change all backslashes (except for the first one) to underscores if (FStringFindCharacterA(buffer + 7, DwStringLengthA(backslash) - 7, '\\',&backslash)) { do { *backslash = '_'; // Change backslash to underscore } while (FStringFindCharacterA(backslash, DwStringLengthA(backslash), '\\',&backslash)); }
(Remember, all variable names are made-up since I don't have source code access. I'm just working from the disassembly.)
At this point, you can see the bug: It's an uninitialized variable at the first call to StringFindCharacterA. Whether we crash or survive is a matter of luck. If the uninitialized variable happens to be a pointer to readable data, then the DwStringLengthA will eventually find the null terminator, and since in practice the string does not contain any extra backslashes, the call to FStringFindCharacterA fails, and nobody gets hurt.
StringFindCharacterA
DwStringLengthA
FStringFindCharacterA
But it looks like their luck ran out, and now the uninitialized variable contains something that is not a valid pointer.
The if test should have been
if
if (FStringFindCharacterA(buffer + 7, DwStringLengthA(buffer) - 7, '\\',&backslash))
This means changing the
push dword ptr [ebp-2E4h]
to
lea eax,[ebp-101h] push eax
Unfortunately, the patch is one byte larger than the existing code, so we will need to get a little clever in order to get it to fit.
One trick is to rewrite the test as
if (FStringFindCharacterA(buffer + 7, DwStringLengthA(buffer + 7), '\\',&backslash))
That lets us rewrite the assembly code as
lea eax,[ebp-2E4h] push eax push 5Ch lea eax,[ebp-101h] ; \ was "push dword ptr [ebp-2E4h]" push eax ; / call mnyob99!DwStringLengthA ; unchanged but code moved down one byte nop ; \ was "sub eax,7" (3-byte instruction) nop ; / push eax lea eax,[ebp-101h] push eax
The new instructions (lea and push) are one byte larger than the original push, but we got rid of the three-byte sub eax, 7, so it's a net savings of two bytes, which therefore fits.
lea
push
sub eax, 7
However, I'm going to crank the nerd level up another notch and try to come up with a patch that involves modifying as few bytes as possible. In other words, I'm going for style points.
To do this, I'm going to take advantage of the fact that the string length is the return value of DwStringFormatA, so that lets me eliminate the call to DwStringLengthA altogether. However, this means that I have to be careful not to damage the value in eax before I get there.
DwStringFormatA
lea ecx,[ebp-2E4h] ; was "lea eax,[ebp-2E4h]" push ecx ; was "push eax" push 5Ch nop ; \ nop ; | nop ; | nop ; | was "push dword ptr [ebp-2E4h]" nop ; | nop ; / nop ; \ nop ; | nop ; | was "call mnyob99!DwStringLengthA" nop ; | nop ; / sub eax,7 push eax lea eax,[ebp-101h] push eax
Patching the lea eax, ... to be lea ecx, ... can be done with a single byte, and the push eax is a single-byte instruction as well, so the first two patches can be done with one byte each. That leaves me with 11 bytes that need to be nop'd out.
lea eax, ...
lea ecx, ...
push eax
The naïve way of nopping out eleven bytes is simply to patch in 11 nop instructions, but you can do better by taking advantage of the bytes that are already there.
nop
ffb51cfdffff push dword ptr [ebp-2E4h] 85b51cfdffff test dword ptr [ebp-2E4h],esi e8770a0000 call mnyob99!DwStringLengthA b9770a0000 mov ecx,0A77h
By patching a single byte in each of the two instructions, I can turn them into effective nops by making them do nothing interesting. The first one tests the uninitialized variable against some garbage bits, and the second one loads a unused register with a constant. (Since the ecx register is going to be trashed by the call to FStringFindCharacterA, we are free to modify it all we want prior to the call. No code could have relied on it anyway.)
ecx
That second patch is a variation of one I called out some time ago, except that instead of patching out the call with a mov eax, immed32, we're using a mov ecx, immed32, because the value in the eax register is still important.
mov eax, immed32
mov ecx, immed32
Here's the final result:
lea ecx,[ebp-2E4h] ; was "lea eax,[ebp-2E4h]" push ecx ; was "push eax" push 5Ch test dword ptr [ebp-2E4h],esi ; was "push dword ptr [ebp-2E4h]" mov ecx,0a77h ; was "call mnyob99!DwStringLengthA" sub eax,7 push eax lea eax,[ebp-101h] push eax
Bonus chatter: When I shared this patch with my friends, I mentioned that this patch made me feel like my retired colleague Jeff, who had a reputation for accomplishing astonishing programming tasks in his spare time. You would pop into his office asking for some help, and he'd fire up some program you'd never seen before.
"What's that?" you'd ask.
"Oh, it's a debugger I wrote," he'd calmly reply.
Or you'd point him to a program and apologize, "Sorry, I only compiled it for x86. There isn't an Alpha version."
"That's okay, I'll run it in my emulator," he'd say, matter-of-factly.
(And retiring from Microsoft hasn't slowed him down. Here's an IBM PC Model 5150 emulator written in JavaScript.)
Specifically, I said, "I feel like Jeff, who does this sort of thing before his morning coffee."
Jeff corrected me. "If this was something I used to do before coffee, that probably meant I was up all night. Persistence >= talent."
But, I mean, c'mon. Frequentists vs Bayesians? Worst. Action. Movie. Ever.
Anonymous asks a metric buttload of questions, which means that I feel compelled to answer all or none. And given the choice, I decided to answer none.
Okay, I will answer one and ignore the rest.
Why are taskbar live previews lost when you use Fast User Switching?
When you switch away from a user via Fast User Switching, the Desktop Window Manager for that session is turned off. After all, since that session no longer has access to the screen, there's no point running all this code and consuming all this memory for something nobody can see.
When the Desktop Window Manager restarts upon reactivation of a session, it can recovery nearly all of the information it needs: It can enumerate all the windows and obtain their positions and styles. For each visible window, it can send a WM_PAINT message to ask it to paint its contents afresh. But if the window is minimized, the Desktop Window Manager has no way to get at the application's non-minimized pixels, because the application will respond to the WM_PAINT message by saying, "My client area is 0×0. I will therefore paint nothing!"
WM_PAINT
This is one of those tradeoffs that you have to make when engineering software. The benefit of shutting down the Desktop Window Manager when it is not being used exceeds the cost of losing thumbnails for minimized applications. Until the application is restored (and can therefore be sent a WM_PAINT message to get it to paint its client area at its restored size), the Desktop Window Manager merely shows a placeholder bitmap.
GetDC
ReleaseDC
The same restriction also applies to printer DCs. Printer DCs must be created and destroyed on the same thread. The printing team imposed this additional rule in order to make it easier for printer driver vendors to author their drivers. (Printer driver developers have a habit of calling CoInitialize in their implementation of CreateDC and CoUninitialize in their implementation of DeleteDC.)
CoInitialize
CreateDC
CoUninitialize
DeleteDC
Given that printer drivers are a third-party extension point, it's probably in your best interest to treat printer DCs as having hard thread affinity, since who knows what the printer driver is going to do if you try to access it from multiple threads. In other words, the thread that creates the printer DC should be the only thread which prints to it, and should also be the thread which destroys the printer DC when printing is complete.
That's not saying that all your printing has to be done from one thread. If you want, you can create multiple printer DCs, each on different threads. Just make sure to use each printer DC only on the thread that created it. Your printer driver will thank you.