/* MS Windows WMF Vulnerability HotFix by Ilfak Guilfanov ------------------------------------------------------ PLEASE READ THE FOLLOWING CAREFULLY! This is a temporary fix to correct the MS Windows Metafile file vulnerability: http://www.hexblog.com/2005/12/wmf_vuln.html It has been tested on Windows 2000, Windows XP 32bit/64bit, Windows Server 2003. Please use it at your own risk and switch to the official patch from Microsoft as soon as it is be available. The installer injects this DLL to processes in the system using the following registry key: HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Windows\AppInit_DLLs All processes using to user32.dll will be affected by this fix. The DLL patches the Escape() function in gdi32.dll and makes SETABORT escape sequence invalid. I do not know if there are any bad consequences of this (anything printer related?) THIS FIX IS PROVIDED 'AS IS' WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF FITNESS FOR A PURPOSE, OR THE WARRANTY OF NON-INFRINGEMENT. IN NO EVENT SHALL ILFAK GUILFANOV BE LIABLE TO YOU OR ANY THIRD PARTIES FOR ANY SPECIAL, PUNITIVE, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING, WITHOUT LIMITATION, THOSE RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT HE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES, AND ON ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OF THIS SOFTWARE. */ #include #define qnumber(x) (sizeof(x)/sizeof(x[0])) // 77 is a wildcard and matches any byte const BYTE WILD = 0x77; const BYTE MODRM_RR = 0x78; static const BYTE hotlink1[] = { 0x8B, MODRM_RR, // mov Rx, Rx 0x55, // push ebp 0x8B, 0xEC, // mov ebp, esp }; static const BYTE hotlink2[] = { 0x55, // push ebp 0x8B, 0xEC, // mov ebp, esp 0x83, 0xEC, WILD // sub esp, 18h }; struct hotlink_t { const BYTE *bytes; size_t size; }; static const hotlink_t hotlinks[] = { { hotlink1, sizeof(hotlink1) }, { hotlink2, sizeof(hotlink2) }, }; extern "C" const char str[] = "Copyright 2006 by Ilfak Guilfanov, ig@hexblog.com\0" "http://www.hexblog.com"; static const char gdi32_dll_name[] = "gdi32.dll"; static HINSTANCE gdi32 = NULL; static BYTE *ptr = NULL; static void *after_thunk; static int hotlink_idx; static int spdelta; static bool already_installed = false; //-------------------------------------------------------------------------- static int __stdcall thunk(HDC, int func,int param1, void *restparams, DWORD) { if ( func != 9 ) // SetAbort { __asm { sub esp, spdelta jmp dword ptr after_thunk // handle everything except SetAbort } } return 0; // fail } //-------------------------------------------------------------------------- static bool update_hotlink5(const BYTE *what) { DWORD old_protection, dummy; if ( VirtualProtect(ptr, 5, PAGE_EXECUTE_READWRITE, &old_protection) ) { ptr[0] = what[0]; ptr[1] = what[1]; ptr[2] = what[2]; ptr[3] = what[3]; ptr[4] = what[4]; VirtualProtect(ptr, 5, old_protection, &dummy); return true; } else { ptr = NULL; return false; } } //-------------------------------------------------------------------------- // returns number of matched hotlink or -1 static int find_hotlink(void) { for ( size_t i=0; i < qnumber(hotlinks); i++ ) { const BYTE *b = hotlinks[i].bytes; size_t s = hotlinks[i].size; size_t j; for ( j=0; j < s; j++ ) { switch ( b[j] ) { case WILD: continue; case MODRM_RR: // modrm byte of mov rx, rx instruction { BYTE mr = ptr[j]; if ( (mr & 0xC0) != 0xC0 ) // register pair? break; int r1 = mr & 7; int r2 = (mr>>3) & 7; if ( r1 != r2 ) // registers the same? break; } continue; default: if ( b[j] != ptr[j] ) break; continue; } break; } if ( j == s ) { spdelta = i ? ptr[5] : 0; return i; } } return -1; } //-------------------------------------------------------------------------- // check if the hotfix has already been installed static void check_for_running_hotfix(void) { if ( ptr[0] == 0xE9 ) { DWORD displ = *(DWORD*)(ptr+1); ptr = ptr + 5 + displ; if ( !IsBadReadPtr(ptr, 8) && memcmp(thunk, ptr, 8) == 0 ) { displ = char(ptr[8]); ptr = ptr + 9 + displ; static const BYTE xor_ret14[] = { 0x33, 0xC0, // xor eax, eax 0x5D, // pop ebp 0xC2, 0x14, 0x00 // retn 14h }; if ( !IsBadReadPtr(ptr, sizeof(xor_ret14)) && memcmp(ptr, xor_ret14, sizeof(xor_ret14)) == 0 ) { already_installed = true; } } } } //-------------------------------------------------------------------------- // returns number of matched hotlink or -1 static int find_gdi32_hotlink(void) { OSVERSIONINFO OSVersionInfo; OSVersionInfo.dwOSVersionInfoSize = sizeof(OSVersionInfo); if ( GetVersionEx(&OSVersionInfo) == NULL || OSVersionInfo.dwMajorVersion < 5 ) // at least win2000 { return -1; } gdi32 = LoadLibrary(gdi32_dll_name); ptr = (BYTE *)GetProcAddress(gdi32, "Escape"); if ( ptr == NULL ) { FAIL: FreeLibrary(gdi32); gdi32 = NULL; ptr = NULL; return -1; } int idx = find_hotlink(); if ( idx == -1 ) { check_for_running_hotfix(); goto FAIL; } return idx; } //-------------------------------------------------------------------------- // 2 - already installed // 1 - incompatible system // 0 - all ok extern "C" int __declspec(dllexport) get_wmffix_code(void) { if ( already_installed ) return 2; return ptr == NULL ? 1 : 0; } //-------------------------------------------------------------------------- int __stdcall DllMain(HINSTANCE hinst, unsigned long reason, void*) { switch ( reason ) { case DLL_PROCESS_ATTACH: DisableThreadLibraryCalls(hinst); hotlink_idx = find_gdi32_hotlink(); if ( hotlink_idx != -1 ) { DWORD displ = (BYTE *)thunk - (ptr+5); BYTE jump[5]; jump[0] = 0xE9; jump[1] = BYTE(displ >> 0); jump[2] = BYTE(displ >> 8); jump[3] = BYTE(displ >> 16); jump[4] = BYTE(displ >> 24); if ( update_hotlink5(jump) ) after_thunk = ptr + hotlinks[hotlink_idx].size; } break; case DLL_PROCESS_DETACH: if ( ptr != NULL ) update_hotlink5(hotlinks[hotlink_idx].bytes); FreeLibrary(gdi32); break; } return 1; }