From 1b3511ac1f297b12fa3ba738abc52b5b34a1cc18 Mon Sep 17 00:00:00 2001 From: Jason Hood Date: Wed, 22 Dec 2010 18:47:45 +1000 Subject: [PATCH] Fixed x64 and MinGW32 crashes. --- ANSI-LLW.c | 8 +++++++- ANSI.c | 4 ++-- ansicon.c | 20 ++++++++++++++++---- ansicon.h | 2 +- injdll32.c | 4 ++-- proctype.c | 24 +++++++++++++++++------- readme.txt | 9 ++++++--- 7 files changed, 51 insertions(+), 20 deletions(-) diff --git a/ANSI-LLW.c b/ANSI-LLW.c index ed048b0..28991f0 100644 --- a/ANSI-LLW.c +++ b/ANSI-LLW.c @@ -5,6 +5,11 @@ I don't know of a method to retrieve the 32-bit address of a function in 64-bit code, so this is a simple workaround. + + 18 December, 2010: Initially I used GetProcAddress, but then I thought that + was silly, why don't I just return LoadLibraryW directly? That worked fine + for TDM64 and VC, but MinGW32 would return the address of the jump to the + function, not the function itself. Not so silly after all. */ #define WIN32_LEAN_AND_MEAN @@ -12,5 +17,6 @@ int main( void ) { - return (DWORD)LoadLibraryW; + return (DWORD)GetProcAddress( GetModuleHandle( "kernel32.dll" ), + "LoadLibraryW" ); } diff --git a/ANSI.c b/ANSI.c index bb64c99..5840975 100644 --- a/ANSI.c +++ b/ANSI.c @@ -57,7 +57,7 @@ v1.31, 13 & 19 November, 2010: fix multibyte conversion problems. - v1.32, 4, 12 & 16 December, 2010: + v1.32, 4 to 22 December, 2010: test for lpNumberOfCharsWritten/lpNumberOfBytesWritten being NULL; recognise DSR and xterm window title; ignore sequences starting with \e[? & \e[>; @@ -908,7 +908,7 @@ void Inject( LPPROCESS_INFORMATION pinfo, LPPROCESS_INFORMATION lpi, #ifdef _WIN64 DWORD len = GetModuleFileName( GetModuleHandleA( "ANSI64.dll" ), dll, lenof(dll) ); - if (type == 32 || type == -32) + if (type == 32) { dll[len-6] = '3'; dll[len-5] = '2'; diff --git a/ansicon.c b/ansicon.c index 7d4ac1e..3deaadc 100644 --- a/ansicon.c +++ b/ansicon.c @@ -43,14 +43,14 @@ VC compatibility (2008 Express for 32-bit, PSDK 2003 R2 for 64-bit); explicitly use wide characters (stick with TCHAR, but not ). - v1.32, 4, 12 & 16 December, 2010: + v1.32, 4 to 22 December, 2010: make -p more robust; inject into GUI processes; -i implies -p. */ #define PVERS L"1.32" -#define PDATE L"17 December, 2010" +#define PDATE L"22 December, 2010" #include "ansicon.h" #include @@ -95,6 +95,10 @@ BOOL Inject( LPPROCESS_INFORMATION ppi ) WCHAR dll[MAX_PATH]; int type; +#if (MYDEBUG > 0) + if (GetModuleFileNameEx( ppi->hProcess, NULL, dll, lenof(dll) )) + DEBUGSTR( L"%s", dll ); +#endif type = ProcessType( ppi ); if (type == 0) return FALSE; @@ -103,7 +107,6 @@ BOOL Inject( LPPROCESS_INFORMATION ppi ) while (dll[len-1] != '\\') --len; #ifdef _WIN64 - type = abs( type ); wsprintf( dll + len, L"ANSI%d.dll", type ); if (type == 32) InjectDLL32( ppi, dll ); @@ -303,7 +306,15 @@ int main( void ) CoInitialize( NULL ); do { - Sleep( 10 ); + // When I first tried doing this, it took a little while to + // succeed. Testing again shows it works immediately - perhaps the + // CoInitialize introduces enough of a delay. Still, play it safe + // and keep trying. And if you're wondering why I do it at all, + // ProcessType may detect GUI, even for a console process. That's + // fine after injection (including -p), but not here. We *need* to + // suspend our own execution whilst running the child, otherwise + // bad things happen (besides which, I want to restore the original + // attributes when the child exits). if (GetModuleFileNameEx( pi.hProcess, NULL, name, lenof(name) )) { DWORD_PTR info; @@ -315,6 +326,7 @@ int main( void ) info ); break; } + Sleep( 10 ); } while (GetExitCodeProcess( pi.hProcess, &rc ) && rc == STILL_ACTIVE); CoUninitialize(); diff --git a/ansicon.h b/ansicon.h index 2d04920..608d062 100644 --- a/ansicon.h +++ b/ansicon.h @@ -28,7 +28,7 @@ void InjectDLL64( LPPROCESS_INFORMATION, LPCTSTR ); // ========== Auxiliary debug function #ifndef MYDEBUG -# define MYDEBUG 2 // 0 - no debugging +# define MYDEBUG 0 // 0 - no debugging // 1 - use OutputDebugString // 2 - use %temp%\ansicon.log #endif diff --git a/injdll32.c b/injdll32.c index 7f7888d..08d2a16 100644 --- a/injdll32.c +++ b/injdll32.c @@ -57,9 +57,9 @@ void InjectDLL32( LPPROCESS_INFORMATION ppi, LPCTSTR dll ) if (LLW == 0) { + HMODULE hKernel = GetModuleHandleA( "kernel32.dll" ); #ifdef _WIN64 #ifdef __MINGW64__ - HMODULE hKernel = GetModuleHandleA( "kernel32.dll" ); #define GETPROC( proc ) proc = (T##proc)GetProcAddress( hKernel, #proc ) GETPROC( Wow64GetThreadContext ); GETPROC( Wow64SetThreadContext ); @@ -90,7 +90,7 @@ void InjectDLL32( LPPROCESS_INFORMATION ppi, LPCTSTR dll ) CloseHandle( pi.hProcess ); CloseHandle( pi.hThread ); #else - LLW = (DWORD)LoadLibrary; + LLW = (DWORD)GetProcAddress( hKernel, "LoadLibraryW" ); #endif } diff --git a/proctype.c b/proctype.c index 7ffd653..457b75b 100644 --- a/proctype.c +++ b/proctype.c @@ -1,5 +1,13 @@ /* - Test for a valid process. + Test for a valid process. This may sometimes detect GUI, even for a console + process. I think this is due to a DLL being loaded in the address space + before the main image. Ideally I could just use the base address directly, + but that doesn't seem easy to do for another process - there doesn't seem to + be a GetModuleHandle for another process. The CreateRemoteThread trick won't + work with 64-bit (exit code is DWORD) and setting it up to make it work + hardly seems worth it. There's GetModuleInformation, but passing in NULL just + returns a base of NULL, so that's no help. Since 64/32 is sufficient, let + ansicon.exe handle the difference between console/GUI. */ #include "ansicon.h" @@ -14,10 +22,10 @@ int ProcessType( LPPROCESS_INFORMATION pinfo ) { IMAGE_DOS_HEADER dos_header; SIZE_T read; - if (ReadProcessMemory( pinfo->hProcess, minfo.AllocationBase, + if (minfo.BaseAddress == minfo.AllocationBase && + ReadProcessMemory( pinfo->hProcess, minfo.AllocationBase, &dos_header, sizeof(dos_header), &read )) { - DEBUGSTR( L" Base = %p", minfo.AllocationBase ); if (dos_header.e_magic == IMAGE_DOS_SIGNATURE) { IMAGE_NT_HEADERS nt_header; @@ -33,14 +41,16 @@ int ProcessType( LPPROCESS_INFORMATION pinfo ) { if (nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_I386) { - DEBUGSTR( L" 32-bit %s", (gui) ? L"GUI" : L"console" ); - return (gui) ? -32 : 32; + DEBUGSTR( L" %p: 32-bit %s", + minfo.AllocationBase, (gui) ? L"GUI" : L"console" ); + return 32; } #ifdef _WIN64 if (nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64) { - DEBUGSTR( L" 64-bit %s", (gui) ? L"GUI" : L"console" ); - return (gui) ? -64 : 64; + DEBUGSTR( L" %p: 64-bit %s", + minfo.AllocationBase, (gui) ? L"GUI" : L"console" ); + return 64; } #endif DEBUGSTR( L" Ignoring unsupported machine (0x%X)", diff --git a/readme.txt b/readme.txt index fc39541..237785b 100644 --- a/readme.txt +++ b/readme.txt @@ -140,6 +140,8 @@ The 64-bit version can inject into a 32-bit process, but the 32-bit version will not inject into a 64-bit process. + Building rubyinstaller on Win7 crashes (XP is fine). + =============== Version History @@ -147,11 +149,12 @@ Legend: + added, - bug-fixed, * changed. - 1.32 - 16 December, 2010: + 1.32 - 22 December, 2010: - fixed crash due to NULL lpNumberOfBytesWritten/lpNumberOfCharsWritten; - -p will test the parent process for validity; * hook into GUI processes; - + recognise DSR and xterm window title sequences. + + recognise DSR and xterm window title sequences; + - fixed MinGW32 binaries (LLW was wrong). 1.31 - 19 November, 2010: - fixed multibyte support (no extra junk with UTF-8 files); @@ -273,4 +276,4 @@ ============================== - Jason Hood, 16 December, 2010. + Jason Hood, 22 December, 2010.