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,104PUSH EBXLEA EAX,DWORD PTR SS:[EBP+szBuffer]PUSH EAXPUSH DWORD PTR DS:[ESI+6C]CALL DWORD PTR DS:[<&KERNEL32.GetModuleFileNameA>LEA EAX,DWORD PTR SS:[EBP+szBuffer]PUSH 2EPUSH EAXCALL DWORD PTR DS:[<&msvcrt._mbsrchr>]POP ECXPOP ECXMOV DWORD PTR SS:[EBP-80],EAXMOV 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 104LEA EDX,DWORD PTR SS:[EBP+szBuffer]MOV [EDI+0C],ECXMOV EAX,DWORD PTR DS:[ESI+6C]PUSH EDXPUSH EAXCALL DWORD PTR DS:[<&KERNEL32.GetModuleFileNameA>TEST EAX,EAXJZ LOC_722F1484CMP EAX,104JZ LOC_722F1484LEA ECX,[EBP+szBuffer]PUSH 2EPUSH ECXCALL __mbsrchrMOV EBX,EAXADD ESP,8TEST EBX,EBXMOV [EBP+VAR_310],EBXJZ LOC_7230DB7D... __mbsrchr:MOV EDI,EDIPUSH EBPMOV EBP,ESPPOP EBPJMP DWORD PTR DS:[<&msvcrt._mbsrchr>] LOC_7230DB7D:...JMP DWORD PTR DS:[<&msvcrt.CxxThrowException>]
PUSH 104LEA EDX,DWORD PTR SS:[EBP+szBuffer]MOV [EDI+0C],ECXMOV EAX,DWORD PTR DS:[ESI+6C]PUSH EDXPUSH EAXCALL DWORD PTR DS:[<&KERNEL32.GetModuleFileNameA>TEST EAX,EAXJZ LOC_722F1484CMP EAX,104JZ LOC_722F1484LEA ECX,[EBP+szBuffer]PUSH 2EPUSH ECXCALL __mbsrchrMOV EBX,EAXADD ESP,8TEST EBX,EBXMOV [EBP+VAR_310],EBXJZ LOC_7230DB7D...
__mbsrchr:MOV EDI,EDIPUSH EBPMOV EBP,ESPPOP EBPJMP 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_exe1 file(s) copied.C:>notepad_exenotepad_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.
There are 31,328 total registered users.
[+] expand