Cross Your Ts and Dot Your Filenames
Jason Geffner (JasonGeffner) <jasongefmicrosoftcom> Thursday, March 27 2008 02:55.00 CDT


I was developing some automation code recently and found that a process that I was injecting code into was crashing. At first I thought it was an error in my injected code, but when I looked at the crash-dump, I was amazed to see that the issue was in MFC42.DLL:



MOV EBX,104
PUSH EBX
LEA EAX,DWORD PTR SS:[EBP+szBuffer]
PUSH EAX
PUSH DWORD PTR DS:[ESI+6C]
CALL DWORD PTR DS:[<&KERNEL32.GetModuleFileNameA>
LEA EAX,DWORD PTR SS:[EBP+szBuffer]
PUSH 2E
PUSH EAX
CALL DWORD PTR DS:[<&msvcrt._mbsrchr>]
POP ECX
POP ECX
MOV DWORD PTR SS:[EBP-80],EAX
MOV BYTE PTR DS:[EAX],0     <-- Crash!


The code above is from MFC42.DLL, version 6.2.4131.0 from Windows XP SP2. It effectively does the following:



GetModuleFileName(NULL, szBuffer, MAX_PATH);
*(_mbsrchr(szBuffer, .)) = 0;


The function _mbsrchr(...) returns NULL if the character searched for is not found. This means that if there is no . in the current processs filename (which was the case for the file I was testing) then the highlighted line above will try to write the byte 0x00 to address 0x00000000, which will cause a crash.


I figured that this was some obscure function from MFC42.DLL that most applications dont make use of, however, after a little digging it turns out that this code is in CWinApp::SetCurrentHandles(), which is called by AfxWinInit(...). From http://msdn2.microsoft.com/en-us/library/w04bs753(vs.80).aspx:



"[AfxWinInit] is called by the MFC-supplied WinMain function, as part of the CWinApp initialization of a GUI-based application, to initialize MFC."


In other words, almost every MFC GUI program executes the code snippet above!


AAs surprised as I was by this, I figured that surely this had been fixed for Vista. Believe it or not, the same issue exists! Below is the code from MFC42.DLL version 6.6.8063.0 from Windows Vista Gold:



PUSH 104
LEA EDX,DWORD PTR SS:[EBP+szBuffer]
MOV [EDI+0C],ECX
MOV EAX,DWORD PTR DS:[ESI+6C]
PUSH EDX
PUSH EAX
CALL DWORD PTR DS:[<&KERNEL32.GetModuleFileNameA>
TEST EAX,EAX
JZ LOC_722F1484
CMP EAX,104
JZ LOC_722F1484
LEA ECX,[EBP+szBuffer]
PUSH 2E
PUSH ECX
CALL __mbsrchr
MOV EBX,EAX
ADD ESP,8
TEST EBX,EBX
MOV [EBP+VAR_310],EBX
JZ LOC_7230DB7D
...







__mbsrchr:
MOV EDI,EDI
PUSH EBP
MOV EBP,ESP
POP EBP
JMP DWORD PTR DS:[<&msvcrt._mbsrchr>]






LOC_7230DB7D:
...
JMP DWORD PTR DS:[<&msvcrt.CxxThrowException>]


While the code above checks for the lack of a . in the filename, it still throws an exception and causes a crash if theres no ..


The good news is that it doesnt seem easy to accidentally execute an executable file without a . in the filename in Vista:



C:>copy c:windows
otepad.exe notepad_exe
1 file(s) copied.

C:>notepad_exe
notepad_exe is not recognized as an internal or external command, operable program or batch file.

C:>start notepad_exe
[This opens the "Open With" dialog box in Explorer instead of executing the file.]


However, it is still possible to run non-dotted-files via API functions like CreateProcess(...) to cause the crash described above.



Comments
Posted: Wednesday, December 31 1969 18:00.00 CST