Inject by adding to the Import Directory Table.
-p uses CreateRemoteThread, determining kernel32.dll & LLW dynamically. Loading via LoadLibrary will remember the current attributes, restoring them on unload. Tweaked log output (remove quotes around CreateProcess command line; add an underscore to 64-bit addresses). ansicon.exe will really output (to the console) strings as Unicode. Fixed ansicon.exe, if installed, restoring the default attributes, not current. ansicon.exe will start with ANSICON_DEF (if defined and -m not used).
This commit is contained in:
		
							parent
							
								
									bccf933c0a
								
							
						
					
					
						commit
						dc7569dc26
					
				
							
								
								
									
										101
									
								
								ANSI.c
									
									
									
									
									
								
							
							
						
						
									
										101
									
								
								ANSI.c
									
									
									
									
									
								
							| @ -108,13 +108,15 @@ | ||||
|   v1.65, 28 August, 2013: | ||||
|     fix \e[K (was using window, not buffer). | ||||
| 
 | ||||
|   v.166, 20 & 21 September, 2013: | ||||
|   v1.66, 20 & 21 September, 2013: | ||||
|     fix 32-bit process trying to detect 64-bit process. | ||||
| 
 | ||||
|   v1.67, 25 to 27 January, 2014: | ||||
|   v1.70, 25 January to 4 February, 2014: | ||||
|     don't hook ourself from LoadLibrary or LoadLibraryEx; | ||||
|     update the LoadLibraryEx flags that should not cause hooking; | ||||
|     always find the base address of kernel32.dll. | ||||
|     inject by manipulating the import directory table; | ||||
|     restore original attribute on detach (for LoadLibrary/FreeLibrary usage); | ||||
|     log: remove the quotes around the CreateProcess command line string. | ||||
| */ | ||||
| 
 | ||||
| #include "ansicon.h" | ||||
| @ -135,6 +137,7 @@ | ||||
| // ========== Global variables and constants
 | ||||
| 
 | ||||
| HANDLE	  hConOut;		// handle to CONOUT$
 | ||||
| WORD	  orgattr;		// original attribute
 | ||||
| 
 | ||||
| #define ESC	'\x1B'          // ESCape character
 | ||||
| #define BEL	'\x07' | ||||
| @ -253,11 +256,6 @@ SHARED DWORD s_flag; | ||||
| #define GRM_INIT 1 | ||||
| #define GRM_EXIT 2 | ||||
| 
 | ||||
| SHARED DWORD LLW32r; | ||||
| #ifdef _WIN64 | ||||
| SHARED DWORD LLW64r; | ||||
| #endif | ||||
| 
 | ||||
| 
 | ||||
| // Wait for the child process to finish, then update our GRM to the child's.
 | ||||
| DWORD WINAPI UpdateGRM( LPVOID child_pi ) | ||||
| @ -470,6 +468,7 @@ void InterpretEscSeq( void ) | ||||
| 	    case  7: grm.rvideo    = 1; break; | ||||
| 	    case  8: grm.concealed = 1; break; | ||||
| 	    case 21: // oops, this actually turns on double underline
 | ||||
| 		     // but xterm turns off bold too, so that's alright
 | ||||
| 	    case 22: grm.bold	   = 0; break; | ||||
| 	    case 25: | ||||
| 	    case 24: grm.underline = 0; break; | ||||
| @ -1049,9 +1048,7 @@ BOOL HookAPIOneMod( | ||||
|   // We now have a valid pointer to the module's PE header.
 | ||||
|   // Get a pointer to its imports section.
 | ||||
|   pImportDesc = MakeVA( PIMAGE_IMPORT_DESCRIPTOR, | ||||
| 			pNTHeader->OptionalHeader. | ||||
| 			 DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]. | ||||
| 			  VirtualAddress ); | ||||
| 			pNTHeader->IMPORTDIR.VirtualAddress ); | ||||
| 
 | ||||
|   // Bail out if the RVA of the imports section is 0 (it doesn't exist)
 | ||||
|   if (pImportDesc == (PIMAGE_IMPORT_DESCRIPTOR)pDosHeader) | ||||
| @ -1113,35 +1110,18 @@ BOOL HookAPIOneMod( | ||||
| 	} | ||||
| 	if (patch) | ||||
| 	{ | ||||
| 	  DWORD flOldProtect, flNewProtect, flDummy; | ||||
| 	  MEMORY_BASIC_INFORMATION mbi; | ||||
| 	  DWORD pr; | ||||
| 
 | ||||
| 	  DEBUGSTR( 3, L"  %S", hook->name ); | ||||
| 	  // Get the current protection attributes.
 | ||||
| 	  VirtualQuery( &pThunk->u1.Function, &mbi, sizeof(mbi) ); | ||||
| 	  // Take the access protection flags.
 | ||||
| 	  flNewProtect = mbi.Protect; | ||||
| 	  // Remove ReadOnly and ExecuteRead flags.
 | ||||
| 	  flNewProtect &= ~(PAGE_READONLY | PAGE_EXECUTE_READ); | ||||
| 	  // Add on ReadWrite flag
 | ||||
| 	  flNewProtect |= (PAGE_READWRITE); | ||||
| 	  // Change the access protection on the region of committed pages in the
 | ||||
| 	  // virtual address space of the current process.
 | ||||
| 	  VirtualProtect( &pThunk->u1.Function, sizeof(PVOID), | ||||
| 			  flNewProtect, &flOldProtect ); | ||||
| 	  // Change the access protection on the region of committed pages in
 | ||||
| 	  // the virtual address space of the current process.
 | ||||
| 	  VirtualProtect( &pThunk->u1.Function, PTRSZ, PAGE_READWRITE, &pr ); | ||||
| 
 | ||||
| 	  // Overwrite the original address with the address of the new function.
 | ||||
| 	  if (!WriteProcessMemory( GetCurrentProcess(), | ||||
| 				   &pThunk->u1.Function, | ||||
| 				   &patch, sizeof(patch), NULL )) | ||||
| 	  { | ||||
| 	    DEBUGSTR( 1, L"Could not patch!" ); | ||||
| 	    return FALSE; | ||||
| 	  } | ||||
| 	  pThunk->u1.Function = (DWORD_PTR)patch; | ||||
| 
 | ||||
| 	  // Put the page attributes back the way they were.
 | ||||
| 	  VirtualProtect( &pThunk->u1.Function, sizeof(PVOID), | ||||
| 			  flOldProtect, &flDummy ); | ||||
| 	  VirtualProtect( &pThunk->u1.Function, PTRSZ, pr, &pr ); | ||||
| 	} | ||||
|       } | ||||
|       pThunk++; // Advance to next imported function address
 | ||||
| @ -1212,10 +1192,11 @@ void Inject( DWORD dwCreationFlags, LPPROCESS_INFORMATION lpi, | ||||
| 	     BOOL wide, LPCVOID lpApp, LPCVOID lpCmd ) | ||||
| { | ||||
|   int	type; | ||||
|   PBYTE base; | ||||
|   BOOL	gui; | ||||
| 
 | ||||
|   type = ProcessType( child_pi, &gui ); | ||||
|   if (gui) | ||||
|   type = ProcessType( child_pi, &base, &gui ); | ||||
|   if (gui && type > 0) | ||||
|   { | ||||
|     TCHAR   app[MAX_PATH]; | ||||
|     LPTSTR  name; | ||||
| @ -1273,20 +1254,20 @@ void Inject( DWORD dwCreationFlags, LPPROCESS_INFORMATION lpi, | ||||
|       type = 0; | ||||
|     } | ||||
|   } | ||||
|   if (type != 0) | ||||
|   if (type > 0) | ||||
|   { | ||||
| #ifdef _WIN64 | ||||
|     if (type == 32) | ||||
|     { | ||||
|       hDllNameType[0] = '3'; | ||||
|       hDllNameType[1] = '2'; | ||||
|       InjectDLL32( child_pi, hDllName ); | ||||
|       ansi_bits[0] = '3'; | ||||
|       ansi_bits[1] = '2'; | ||||
|       InjectDLL32( child_pi, base ); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|       hDllNameType[0] = '6'; | ||||
|       hDllNameType[1] = '4'; | ||||
|       InjectDLL64( child_pi, hDllName ); | ||||
|       ansi_bits[0] = '6'; | ||||
|       ansi_bits[1] = '4'; | ||||
|       InjectDLL( child_pi, base ); | ||||
|     } | ||||
| #else | ||||
| #ifdef W32ON64 | ||||
| @ -1313,7 +1294,7 @@ void Inject( DWORD dwCreationFlags, LPPROCESS_INFORMATION lpi, | ||||
|     } | ||||
|     else | ||||
| #endif | ||||
|     InjectDLL32( child_pi, hDllName ); | ||||
|     InjectDLL( child_pi, base ); | ||||
| #endif | ||||
|     if (!gui && !(dwCreationFlags & (CREATE_NEW_CONSOLE | DETACHED_PROCESS))) | ||||
|     { | ||||
| @ -1370,7 +1351,7 @@ BOOL WINAPI MyCreateProcessA( LPCSTR lpApplicationName, | ||||
| 		       &child_pi )) | ||||
|     return FALSE; | ||||
| 
 | ||||
|   DEBUGSTR( 1, L"CreateProcessA: (%lu) \"%S\", \"%S\"", | ||||
|   DEBUGSTR( 1, L"CreateProcessA: (%lu) \"%S\", %S", | ||||
| 	    child_pi.dwProcessId, | ||||
| 	    (lpApplicationName == NULL) ? "" : lpApplicationName, | ||||
| 	    (lpCommandLine == NULL) ? "" : lpCommandLine ); | ||||
| @ -1406,7 +1387,7 @@ BOOL WINAPI MyCreateProcessW( LPCWSTR lpApplicationName, | ||||
| 		       &child_pi )) | ||||
|     return FALSE; | ||||
| 
 | ||||
|   DEBUGSTR( 1, L"CreateProcessW: (%lu) \"%s\", \"%s\"", | ||||
|   DEBUGSTR( 1, L"CreateProcessW: (%lu) \"%s\", %s", | ||||
| 	    child_pi.dwProcessId, | ||||
| 	    (lpApplicationName == NULL) ? L"" : lpApplicationName, | ||||
| 	    (lpCommandLine == NULL) ? L"" : lpCommandLine ); | ||||
| @ -1609,7 +1590,6 @@ WINAPI MyWriteConsoleA( HANDLE hCon, LPCVOID lpBuffer, | ||||
| 
 | ||||
|   return WriteConsoleA( hCon, lpBuffer, nNumberOfCharsToWrite, | ||||
| 			lpNumberOfCharsWritten, lpReserved ); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| BOOL | ||||
| @ -1774,6 +1754,7 @@ void OriginalAttr( void ) | ||||
| 				    NULL, OPEN_EXISTING, 0, 0 ); | ||||
|   if (!GetConsoleScreenBufferInfo( hConOut, &csbi )) | ||||
|     csbi.wAttributes = 7; | ||||
|   orgattr = csbi.wAttributes; | ||||
|   CloseHandle( hConOut ); | ||||
| 
 | ||||
|   if (s_flag == GRM_INIT && s_pid == GetCurrentProcessId()) | ||||
| @ -1823,7 +1804,8 @@ void OriginalAttr( void ) | ||||
| // and terminated.
 | ||||
| //-----------------------------------------------------------------------------
 | ||||
| 
 | ||||
| __declspec(dllexport) // just to stop MinGW exporting everything
 | ||||
| // Need to export something for static loading to work, this is as good as any.
 | ||||
| __declspec(dllexport) | ||||
| BOOL WINAPI DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved ) | ||||
| { | ||||
|   BOOL	  bResult = TRUE; | ||||
| @ -1840,19 +1822,19 @@ BOOL WINAPI DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved ) | ||||
|     hDllNameType = hDllName - 6 + | ||||
| #endif | ||||
|     GetModuleFileName( hInstance, hDllName, lenof(hDllName) ); | ||||
| #ifdef _WIN64 | ||||
|     ansi_bits = (LPSTR)hDllNameType; | ||||
| #endif | ||||
|     set_ansi_dll( hDllName ); | ||||
| 
 | ||||
|     hDllInstance = hInstance; // save Dll instance handle
 | ||||
|     DEBUGSTR( 1, L"hDllInstance = %p", hDllInstance ); | ||||
| 
 | ||||
|     if (LLW32r == 0) | ||||
|     { | ||||
|       if (!get_LLW32r()) | ||||
| 	return FALSE; | ||||
| #ifdef _WIN64 | ||||
|       if (!get_LLW64r()) | ||||
| 	return FALSE; | ||||
|     DEBUGSTR( 1, L"hDllInstance = %.8X_%.8X", | ||||
| 		 (DWORD)((DWORD_PTR)hDllInstance >> 32), | ||||
| 		 PtrToUint( hDllInstance ) ); | ||||
| #else | ||||
|     DEBUGSTR( 1, L"hDllInstance = %p", hDllInstance ); | ||||
| #endif | ||||
|     } | ||||
| 
 | ||||
|     // Get the entry points to the original functions.
 | ||||
|     hKernel = GetModuleHandleA( APIKernel ); | ||||
| @ -1869,6 +1851,11 @@ BOOL WINAPI DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved ) | ||||
|     { | ||||
|       DEBUGSTR( 1, L"Unloading" ); | ||||
|       HookAPIAllMod( Hooks, TRUE ); | ||||
|       hConOut = CreateFile( L"CONOUT$", GENERIC_READ | GENERIC_WRITE, | ||||
| 					FILE_SHARE_READ | FILE_SHARE_WRITE, | ||||
| 					NULL, OPEN_EXISTING, 0, 0 ); | ||||
|       SetConsoleTextAttribute( hConOut, orgattr ); | ||||
|       CloseHandle( hConOut ); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| Copyright (C) 2005-2013 Jason Hood | ||||
| Copyright (C) 2005-2014 Jason Hood | ||||
| 
 | ||||
| This software is provided 'as-is', without any express or implied | ||||
| warranty.  In no event will the author be held liable for any damages | ||||
|  | ||||
							
								
								
									
										115
									
								
								LLW.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										115
									
								
								LLW.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,115 @@ | ||||
| /*
 | ||||
|   Locate the relative address of LoadLibraryW in kernel32.dll.	This is needed | ||||
|   to get the 32-bit address from 64-bit code, and it eliminates the possibility | ||||
|   of it already being hooked. | ||||
| */ | ||||
| 
 | ||||
| #include "ansicon.h" | ||||
| 
 | ||||
| static PIMAGE_DOS_HEADER pDosHeader; | ||||
| 
 | ||||
| #define MakeVA( cast, offset ) (cast)((DWORD_PTR)pDosHeader + (DWORD)(offset)) | ||||
| 
 | ||||
| 
 | ||||
| static int export_cmp( const void* a, const void* b ) | ||||
| { | ||||
|   return strcmp( (LPCSTR)a, MakeVA( LPCSTR, *(const PDWORD)b ) ); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| DWORD get_LLW32r( void ) | ||||
| { | ||||
|   HMODULE kernel32; | ||||
|   TCHAR   buf[MAX_PATH]; | ||||
|   UINT	  len; | ||||
|   PIMAGE_NT_HEADERS32	  pNTHeader; | ||||
|   PIMAGE_EXPORT_DIRECTORY pExportDir; | ||||
|   PDWORD  fun_table, name_table; | ||||
|   PWORD   ord_table; | ||||
|   PDWORD  pLLW; | ||||
|   DWORD   LLWr; | ||||
| 
 | ||||
| #ifdef _WIN64 | ||||
|   len = GetSystemWow64Directory( buf, MAX_PATH ); | ||||
| #else | ||||
|   len = GetSystemDirectory( buf, MAX_PATH ); | ||||
| #endif | ||||
|   wcscpy( buf + len, L"\\kernel32.dll" ); | ||||
|   kernel32 = LoadLibraryEx( buf, NULL, LOAD_LIBRARY_AS_IMAGE_RESOURCE ); | ||||
|   if (kernel32 == NULL) | ||||
|   { | ||||
|     DEBUGSTR( 1, L"Unable to load 32-bit kernel32.dll!" ); | ||||
|     return 0; | ||||
|   } | ||||
|   // The handle uses low bits as flags, so strip 'em off.
 | ||||
|   pDosHeader = (PIMAGE_DOS_HEADER)((DWORD_PTR)kernel32 & ~0xFFFF); | ||||
|   pNTHeader  = MakeVA( PIMAGE_NT_HEADERS32, pDosHeader->e_lfanew ); | ||||
|   pExportDir = MakeVA( PIMAGE_EXPORT_DIRECTORY, | ||||
| 		       pNTHeader->EXPORTDIR.VirtualAddress ); | ||||
| 
 | ||||
|   fun_table  = MakeVA( PDWORD, pExportDir->AddressOfFunctions ); | ||||
|   name_table = MakeVA( PDWORD, pExportDir->AddressOfNames ); | ||||
|   ord_table  = MakeVA( PWORD,  pExportDir->AddressOfNameOrdinals ); | ||||
| 
 | ||||
|   pLLW = bsearch( "LoadLibraryW", name_table, pExportDir->NumberOfNames, | ||||
| 		  sizeof(DWORD), export_cmp ); | ||||
|   if (pLLW == NULL) | ||||
|   { | ||||
|     DEBUGSTR( 1, L"Could not find 32-bit LoadLibraryW!" ); | ||||
|     LLWr = 0; | ||||
|   } | ||||
|   else | ||||
|   { | ||||
|     LLWr = fun_table[ord_table[pLLW - name_table]]; | ||||
|   } | ||||
|   FreeLibrary( kernel32 ); | ||||
|   return LLWr; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| #ifdef _WIN64 | ||||
| DWORD64 get_LLW64r( void ) | ||||
| { | ||||
|   HMODULE kernel32; | ||||
|   TCHAR   buf[MAX_PATH]; | ||||
|   UINT	  len; | ||||
|   PIMAGE_NT_HEADERS	  pNTHeader; | ||||
|   PIMAGE_EXPORT_DIRECTORY pExportDir; | ||||
|   PDWORD  fun_table, name_table; | ||||
|   PWORD   ord_table; | ||||
|   PDWORD  pLLW; | ||||
|   DWORD64 LLWr; | ||||
| 
 | ||||
|   len = GetSystemDirectory( buf, MAX_PATH ); | ||||
|   wcscpy( buf + len, L"\\kernel32.dll" ); | ||||
|   kernel32 = LoadLibraryEx( buf, NULL, LOAD_LIBRARY_AS_IMAGE_RESOURCE ); | ||||
|   if (kernel32 == NULL) | ||||
|   { | ||||
|     DEBUGSTR( 1, L"Unable to load 64-bit kernel32.dll!" ); | ||||
|     return 0; | ||||
|   } | ||||
|   // The handle uses low bits as flags, so strip 'em off.
 | ||||
|   pDosHeader = (PIMAGE_DOS_HEADER)((DWORD_PTR)kernel32 & ~0xFFFF); | ||||
|   pNTHeader  = MakeVA( PIMAGE_NT_HEADERS, pDosHeader->e_lfanew ); | ||||
|   pExportDir = MakeVA( PIMAGE_EXPORT_DIRECTORY, | ||||
| 		       pNTHeader->EXPORTDIR.VirtualAddress ); | ||||
| 
 | ||||
|   fun_table  = MakeVA( PDWORD, pExportDir->AddressOfFunctions ); | ||||
|   name_table = MakeVA( PDWORD, pExportDir->AddressOfNames ); | ||||
|   ord_table  = MakeVA( PWORD,  pExportDir->AddressOfNameOrdinals ); | ||||
| 
 | ||||
|   pLLW = bsearch( "LoadLibraryW", name_table, pExportDir->NumberOfNames, | ||||
| 		  sizeof(DWORD), export_cmp ); | ||||
|   if (pLLW == NULL) | ||||
|   { | ||||
|     DEBUGSTR( 1, L"Could not find 64-bit LoadLibraryW!" ); | ||||
|     LLWr = 0; | ||||
|   } | ||||
|   else | ||||
|   { | ||||
|     LLWr = fun_table[ord_table[pLLW - name_table]]; | ||||
|   } | ||||
|   FreeLibrary( kernel32 ); | ||||
|   return LLWr; | ||||
| } | ||||
| #endif | ||||
							
								
								
									
										306
									
								
								ansicon.c
									
									
									
									
									
								
							
							
						
						
									
										306
									
								
								ansicon.c
									
									
									
									
									
								
							| @ -76,17 +76,30 @@ | ||||
| 
 | ||||
|   v1.63, 25 July, 2013: | ||||
|     don't write the reset sequence if output is redirected. | ||||
| 
 | ||||
|   v1.70, 31 January to 3 February, 2014: | ||||
|     restore the original (current, not default) attributes if using ansicon.exe | ||||
|      when it's already installed; | ||||
|     use ANSICON_DEF if defined and -m not given; | ||||
|     -e and -t will not output anything if the DLL could not load; | ||||
|     use Unicode output (_O_U16TEXT, for compilers/systems that support it); | ||||
|     log: 64-bit addresses get an underscore between the 8-digit groups. | ||||
| */ | ||||
| 
 | ||||
| #define PDATE L"27 January, 2014" | ||||
| #define PDATE L"4 February, 2014" | ||||
| 
 | ||||
| #include "ansicon.h" | ||||
| #include "version.h" | ||||
| #include <tlhelp32.h> | ||||
| #include <ctype.h> | ||||
| #include <fcntl.h> | ||||
| #include <io.h> | ||||
| #include <locale.h> | ||||
| 
 | ||||
| #ifndef _O_U16TEXT | ||||
| #define _O_U16TEXT 0x20000 | ||||
| #endif | ||||
| 
 | ||||
| #ifdef __MINGW32__ | ||||
| int _CRT_glob = 0; | ||||
| #endif | ||||
| @ -99,7 +112,7 @@ int _CRT_glob = 0; | ||||
| void   help( void ); | ||||
| 
 | ||||
| void   display( LPCTSTR, BOOL ); | ||||
| void   print_error( LPCTSTR, ... ); | ||||
| void   print_error( LPCTSTR ); | ||||
| LPTSTR skip_spaces( LPTSTR ); | ||||
| void   get_arg( LPTSTR, LPTSTR*, LPTSTR* ); | ||||
| void   get_file( LPTSTR, LPTSTR*, LPTSTR* ); | ||||
| @ -110,12 +123,49 @@ BOOL   find_proc_id( HANDLE snap, DWORD id, LPPROCESSENTRY32 ppe ); | ||||
| BOOL   GetParentProcessInfo( LPPROCESS_INFORMATION ppi, LPTSTR ); | ||||
| 
 | ||||
| 
 | ||||
| // The DLL shares this variable, so injection requires it here.
 | ||||
| DWORD  LLW32r; | ||||
| #ifdef _WIN64 | ||||
| DWORD  LLW64r; | ||||
| #endif | ||||
| extern LPVOID kernel32_base; | ||||
| static HANDLE hConOut; | ||||
| static WORD   wAttr; | ||||
| 
 | ||||
| void get_original_attr( void ) | ||||
| { | ||||
|   CONSOLE_SCREEN_BUFFER_INFO csbi; | ||||
| 
 | ||||
|   hConOut = CreateFile( L"CONOUT$", GENERIC_READ | GENERIC_WRITE, | ||||
| 				    FILE_SHARE_READ | FILE_SHARE_WRITE, | ||||
| 				    NULL, OPEN_EXISTING, 0, 0 ); | ||||
|   GetConsoleScreenBufferInfo( hConOut, &csbi ); | ||||
|   wAttr = csbi.wAttributes; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void set_original_attr( void ) | ||||
| { | ||||
|   SetConsoleTextAttribute( hConOut, wAttr ); | ||||
|   CloseHandle( hConOut ); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| // The fputws function in MSVCRT.DLL (Windows 7 x64) is broken for Unicode
 | ||||
| // output (it just writes the first character).  VC6 & 7 don't support Unicode
 | ||||
| // output at all (just converting to ANSI) and even when it is supported, it
 | ||||
| // just writes single characters (as does _putws & fwprintf).  So what the
 | ||||
| // heck, DIY.
 | ||||
| int my_fputws( const wchar_t* s, FILE* f ) | ||||
| { | ||||
|   if (_isatty( _fileno( f ) )) | ||||
|   { | ||||
|     DWORD written; | ||||
|     WriteConsole( hConOut, s, (DWORD)wcslen( s ), &written, NULL ); | ||||
|   } | ||||
|   else | ||||
|   { | ||||
|     fputws( s, f ); | ||||
|   } | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| #define fputws	    my_fputws | ||||
| #define _putws( s ) my_fputws( s L"\n", stdout ) | ||||
| 
 | ||||
| 
 | ||||
| // Find the name of the DLL and inject it.
 | ||||
| @ -124,11 +174,13 @@ BOOL Inject( LPPROCESS_INFORMATION ppi, BOOL* gui, LPCTSTR app ) | ||||
|   DWORD len; | ||||
|   WCHAR dll[MAX_PATH]; | ||||
|   int	type; | ||||
|   PBYTE base; | ||||
| 
 | ||||
|   DEBUGSTR( 1, L"%s (%lu)", app, ppi->dwProcessId ); | ||||
|   type = ProcessType( ppi, gui ); | ||||
|   if (type == 0) | ||||
|   type = ProcessType( ppi, &base, gui ); | ||||
|   if (type <= 0) | ||||
|   { | ||||
|     if (type == 0) | ||||
|       fwprintf( stderr, L"ANSICON: %s: unsupported process.\n", app ); | ||||
|     return FALSE; | ||||
|   } | ||||
| @ -137,41 +189,94 @@ BOOL Inject( LPPROCESS_INFORMATION ppi, BOOL* gui, LPCTSTR app ) | ||||
|   memcpy( dll, prog_path, TSIZE(len) ); | ||||
| #ifdef _WIN64 | ||||
|   wsprintf( dll + len, L"ANSI%d.dll", type ); | ||||
|   ansi_bits = (LPSTR)(dll + len + 4); | ||||
|   set_ansi_dll( dll ); | ||||
|   if (type == 32) | ||||
|   { | ||||
|     get_LLW32r(); | ||||
|     InjectDLL32( ppi, dll ); | ||||
|   } | ||||
|     InjectDLL32( ppi, base ); | ||||
|   else | ||||
|   { | ||||
|     get_LLW64r(); | ||||
|     InjectDLL64( ppi, dll ); | ||||
|   } | ||||
|     InjectDLL( ppi, base ); | ||||
| #else | ||||
|   wcscpy( dll + len, L"ANSI32.dll" ); | ||||
|   get_LLW32r(); | ||||
|   InjectDLL32( ppi, dll ); | ||||
|   set_ansi_dll( dll ); | ||||
|   InjectDLL( ppi, base ); | ||||
| #endif | ||||
|   return TRUE; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static HANDLE hConOut; | ||||
| static CONSOLE_SCREEN_BUFFER_INFO csbi; | ||||
| 
 | ||||
| void get_original_attr( void ) | ||||
| // Use CreateRemoteThread to load our DLL in the target process.
 | ||||
| void RemoteLoad( LPPROCESS_INFORMATION ppi ) | ||||
| { | ||||
|   hConOut = CreateFile( L"CONOUT$", GENERIC_READ | GENERIC_WRITE, | ||||
| 				    FILE_SHARE_READ | FILE_SHARE_WRITE, | ||||
| 				    NULL, OPEN_EXISTING, 0, 0 ); | ||||
|   GetConsoleScreenBufferInfo( hConOut, &csbi ); | ||||
| } | ||||
|   HANDLE hSnap; | ||||
|   MODULEENTRY32 me; | ||||
|   PBYTE  LLW; | ||||
|   BOOL	 fOk; | ||||
|   WCHAR  dll[MAX_PATH]; | ||||
|   DWORD  len; | ||||
|   LPVOID mem; | ||||
|   HANDLE thread; | ||||
| #ifdef _WIN64 | ||||
|   BOOL	 WOW64; | ||||
| #endif | ||||
| 
 | ||||
|   // Find the base address of kernel32.dll.
 | ||||
|   LLW = NULL; | ||||
|   hSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, | ||||
| 				    ppi->dwProcessId ); | ||||
|   if (hSnap != INVALID_HANDLE_VALUE) | ||||
|   { | ||||
|     me.dwSize = sizeof(MODULEENTRY32); | ||||
|     for (fOk = Module32First( hSnap, &me ); fOk; | ||||
| 	 fOk = Module32Next( hSnap, &me )) | ||||
|     { | ||||
|       if (_wcsicmp( me.szModule, L"kernel32.dll" ) == 0) | ||||
|       { | ||||
| 	LLW = me.modBaseAddr; | ||||
| 	break; | ||||
|       } | ||||
|     } | ||||
|     CloseHandle( hSnap ); | ||||
|   } | ||||
| #ifndef _WIN64 | ||||
|   else if (GetLastError() == ERROR_PARTIAL_COPY) | ||||
|   { | ||||
|     fputws( L"ANSICON: parent is 64-bit (use x64\\ansicon).\n", stderr ); | ||||
|     return; | ||||
|   } | ||||
| #endif | ||||
|   if (LLW == NULL) | ||||
|   { | ||||
|   no_llw: | ||||
|     fputws( L"ANSICON: unable to inject into parent.\n", stderr ); | ||||
|     return; | ||||
|   } | ||||
| 
 | ||||
| void set_original_attr( void ) | ||||
| { | ||||
|   SetConsoleTextAttribute( hConOut, csbi.wAttributes ); | ||||
|   CloseHandle( hConOut ); | ||||
|   len = (DWORD)(prog - prog_path); | ||||
|   memcpy( dll, prog_path, TSIZE(len) ); | ||||
| #ifdef _WIN64 | ||||
|   if (IsWow64Process( ppi->hProcess, &WOW64 ) && WOW64) | ||||
|   { | ||||
|     wcscpy( dll + len, L"ANSI32.dll" ); | ||||
|     LLW += get_LLW32r(); | ||||
|   } | ||||
|   else | ||||
|   { | ||||
|     wcscpy( dll + len, L"ANSI64.dll" ); | ||||
|     LLW += get_LLW64r(); | ||||
|   } | ||||
| #else | ||||
|   wcscpy( dll + len, L"ANSI32.dll" ); | ||||
|   LLW += get_LLW32r(); | ||||
| #endif | ||||
|   if (LLW == me.modBaseAddr) | ||||
|     goto no_llw; | ||||
|   mem = VirtualAllocEx( ppi->hProcess, NULL, len, MEM_COMMIT, PAGE_READWRITE ); | ||||
|   WriteProcMem( mem, dll, TSIZE(len + 11) ); | ||||
|   thread = CreateRemoteThread( ppi->hProcess, NULL, 4096, | ||||
| 			       (LPTHREAD_START_ROUTINE)LLW, mem, 0, NULL ); | ||||
|   WaitForSingleObject( thread, INFINITE ); | ||||
|   CloseHandle( thread ); | ||||
|   VirtualFreeEx( ppi->hProcess, mem, 0, MEM_RELEASE ); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| @ -186,13 +291,25 @@ int main( void ) | ||||
|   STARTUPINFO si; | ||||
|   PROCESS_INFORMATION pi; | ||||
|   LPTSTR  argv, arg, cmd; | ||||
|   TCHAR   logstr[4]; | ||||
|   BOOL	  installed; | ||||
|   TCHAR   buf[4]; | ||||
|   BOOL	  shell, run, gui; | ||||
|   HMODULE ansi; | ||||
|   DWORD   len; | ||||
|   int	  rc = 0; | ||||
| 
 | ||||
|   // Convert wide strings using the current code page.
 | ||||
|   sprintf( (LPSTR)buf, ".%u", GetConsoleOutputCP() ); | ||||
|   setlocale( LC_CTYPE, (LPSTR)buf ); | ||||
| 
 | ||||
|   // Switch console output to Unicode.
 | ||||
|   if (_isatty( 1 )) | ||||
|     _setmode( 1, _O_U16TEXT); | ||||
|   if (_isatty( 2 )) | ||||
|     _setmode( 2, _O_U16TEXT); | ||||
| 
 | ||||
|   // Create a console handle and store the current attribute.
 | ||||
|   get_original_attr(); | ||||
| 
 | ||||
|   argv = GetCommandLine(); | ||||
|   len = (DWORD)wcslen( argv ) + 1; | ||||
|   if (len < MAX_PATH) | ||||
| @ -217,19 +334,15 @@ int main( void ) | ||||
|   } | ||||
| 
 | ||||
|   prog = get_program_name( NULL ); | ||||
|   *logstr = '\0'; | ||||
|   GetEnvironmentVariable( L"ANSICON_LOG", logstr, lenof(logstr) ); | ||||
|   log_level = _wtoi( logstr ); | ||||
| 
 | ||||
|   // Using "" for setlocale uses the system ANSI code page.
 | ||||
|   sprintf( (LPSTR)logstr, ".%u", GetConsoleOutputCP() ); | ||||
|   setlocale( LC_CTYPE, (LPSTR)logstr ); | ||||
|   *buf = '\0'; | ||||
|   GetEnvironmentVariable( L"ANSICON_LOG", buf, lenof(buf) ); | ||||
|   log_level = _wtoi( buf ); | ||||
| 
 | ||||
| #ifdef _WIN64 | ||||
|   if (*arg == '-' && arg[1] == 'P') | ||||
|   { | ||||
|     swscanf( arg + 2, L"%u:%u", &pi.dwProcessId, &pi.dwThreadId ); | ||||
|     pi.hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pi.dwProcessId); | ||||
|     pi.hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, pi.dwProcessId ); | ||||
|     pi.hThread	= OpenThread(  THREAD_ALL_ACCESS,  FALSE, pi.dwThreadId ); | ||||
|     Inject( &pi, &gui, arg ); | ||||
|     CloseHandle( pi.hThread ); | ||||
| @ -241,19 +354,7 @@ int main( void ) | ||||
|   if (log_level) | ||||
|     DEBUGSTR( 1, NULL );	// start a new session
 | ||||
| 
 | ||||
|   installed = (GetEnvironmentVariable( L"ANSICON_VER", NULL, 0 ) != 0); | ||||
|   // If it's already installed, remove it.  This serves two purposes: preserves
 | ||||
|   // the parent's GRM; and unconditionally injects into GUI, without having to
 | ||||
|   // worry about ANSICON_GUI.
 | ||||
|   if (installed) | ||||
|   { | ||||
|     if (_isatty( 1 )) | ||||
|       fputws( L"\33[m", stdout ); | ||||
|     FreeLibrary( GetModuleHandle( ANSIDLL ) ); | ||||
|   } | ||||
| 
 | ||||
|   shell = run = TRUE; | ||||
|   get_original_attr(); | ||||
| 
 | ||||
|   while (*arg == '-') | ||||
|   { | ||||
| @ -277,40 +378,12 @@ int main( void ) | ||||
| 
 | ||||
|       case 'p': | ||||
| 	shell = FALSE; | ||||
| 	// If it's already installed, there's no need to do anything.
 | ||||
| 	if (installed) | ||||
| 	if (GetParentProcessInfo( &pi, arg + 3 )) | ||||
| 	{ | ||||
| 	  DEBUGSTR( 1, L"Already installed" ); | ||||
| 	} | ||||
| 	else if (GetParentProcessInfo( &pi, arg )) | ||||
| 	{ | ||||
| 	  HANDLE hSnap; | ||||
| 	  MODULEENTRY32 me; | ||||
| 	  BOOL fOk; | ||||
| 
 | ||||
| 	  pi.hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pi.dwProcessId); | ||||
| 	  pi.hThread  = OpenThread( THREAD_ALL_ACCESS,	FALSE, pi.dwThreadId ); | ||||
| 	  SuspendThread( pi.hThread ); | ||||
| 	  // Find the base address of kernel32.dll.
 | ||||
| 	  hSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE | | ||||
| 					    TH32CS_SNAPMODULE32, | ||||
| 					    pi.dwProcessId ); | ||||
| 	  if (hSnap != INVALID_HANDLE_VALUE) | ||||
| 	  { | ||||
| 	    me.dwSize = sizeof(MODULEENTRY32); | ||||
| 	    for (fOk = Module32First( hSnap, &me ); fOk; | ||||
| 		 fOk = Module32Next( hSnap, &me )) | ||||
| 	    { | ||||
| 	      if (_wcsicmp( me.szModule, L"kernel32.dll" ) == 0) | ||||
| 	      { | ||||
| 		kernel32_base = me.modBaseAddr; | ||||
| 		break; | ||||
| 	      } | ||||
| 	    } | ||||
| 	    CloseHandle( hSnap ); | ||||
| 	  } | ||||
| 	  if (!Inject( &pi, &gui, arg )) | ||||
| 	    rc = 1; | ||||
| 	  RemoteLoad( &pi ); | ||||
| 	  ResumeThread( pi.hThread ); | ||||
| 	  CloseHandle( pi.hThread ); | ||||
| 	  CloseHandle( pi.hProcess ); | ||||
| @ -360,6 +433,15 @@ arg_out: | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   // Ensure the default attributes are the current attributes.
 | ||||
|   if (GetEnvironmentVariable( L"ANSICON_DEF", buf, lenof(buf) ) != 0) | ||||
|   { | ||||
|     int a = wcstol( buf, NULL, 16 ); | ||||
|     if (a < 0) | ||||
|       a = ((-a >> 4) & 15) | ((-a & 15) << 4); | ||||
|     SetConsoleTextAttribute( hConOut, (WORD)a ); | ||||
|   } | ||||
| 
 | ||||
|   if (run) | ||||
|   { | ||||
|     if (*cmd == '\0') | ||||
| @ -392,7 +474,7 @@ arg_out: | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|       print_error( arg, arg ); | ||||
|       print_error( arg ); | ||||
|       rc = 1; | ||||
|     } | ||||
|   } | ||||
| @ -404,8 +486,7 @@ arg_out: | ||||
|       print_error( ANSIDLL ); | ||||
|       rc = 1; | ||||
|     } | ||||
| 
 | ||||
|     if (*arg == 'e' || *arg == 'E') | ||||
|     else if (*arg == 'e' || *arg == 'E') | ||||
|     { | ||||
|       cmd += 2; | ||||
|       if (*cmd == ' ' || *cmd == '\t') | ||||
| @ -433,14 +514,10 @@ arg_out: | ||||
| 	get_file( arg, &argv, &cmd ); | ||||
|       } while (*arg); | ||||
|     } | ||||
| 
 | ||||
|     FreeLibrary( ansi ); | ||||
|   } | ||||
| 
 | ||||
|   if (run || *arg) | ||||
|   set_original_attr(); | ||||
|   else | ||||
|     CloseHandle( hConOut ); | ||||
| 
 | ||||
|   return rc; | ||||
| } | ||||
| @ -495,30 +572,30 @@ void display( LPCTSTR name, BOOL title ) | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void print_error( LPCTSTR name, ... ) | ||||
| void print_error( LPCTSTR name ) | ||||
| { | ||||
|   LPTSTR errmsg = NULL; | ||||
|   DWORD  err = GetLastError(); | ||||
|   va_list arg; | ||||
| 
 | ||||
|   fputws( L"ANSICON: ", stderr ); | ||||
|   if (err == ERROR_BAD_EXE_FORMAT) | ||||
|   { | ||||
|     // This error requires an argument, which is a duplicate of name.
 | ||||
|     va_start( arg, name ); | ||||
|     FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, | ||||
| 		   NULL, err, 0, (LPTSTR)(LPVOID)&errmsg, 0, &arg ); | ||||
|     va_end( arg ); | ||||
|     fwprintf( stderr, L"ANSICON: %s", errmsg ); | ||||
|     // This error requires an argument, which is name.
 | ||||
|     FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | | ||||
| 		   FORMAT_MESSAGE_ALLOCATE_BUFFER | | ||||
| 		   FORMAT_MESSAGE_ARGUMENT_ARRAY, | ||||
| 		   NULL, err, 0, (LPTSTR)(LPVOID)&errmsg, 0, (va_list*)&name ); | ||||
|     fputws( errmsg, stderr ); | ||||
|   } | ||||
|   else | ||||
|   { | ||||
|     FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, | ||||
| 		   NULL, err, 0, (LPTSTR)(LPVOID)&errmsg, 0, NULL ); | ||||
|     // Just in case there are other messages requiring args...
 | ||||
|     if (errmsg == NULL) | ||||
|       fwprintf( stderr, L"ANSICON: %s: Error %lu.\n", name, err ); | ||||
|     if (FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | | ||||
| 		       FORMAT_MESSAGE_ALLOCATE_BUFFER | | ||||
| 		       FORMAT_MESSAGE_IGNORE_INSERTS, | ||||
| 		       NULL, err, 0, (LPTSTR)(LPVOID)&errmsg, 0, NULL )) | ||||
|       fwprintf( stderr, L"%s: %s", name, errmsg ); | ||||
|     else | ||||
|       fwprintf( stderr, L"ANSICON: %s: %s", name, errmsg ); | ||||
|       fwprintf( stderr, L"%s: Error %lu.\n", name, err ); | ||||
|   } | ||||
|   LocalFree( errmsg ); | ||||
| } | ||||
| @ -759,7 +836,7 @@ void get_file( LPTSTR arg, LPTSTR* argv, LPTSTR* cmd ) | ||||
| 	for (path = name = arg; *path != '\0'; ++path) | ||||
| 	  if (*path == '\\' || *path == '/') | ||||
| 	    name = path + 1; | ||||
| 	glob = malloc( (globbed + 1) * sizeof(LPTSTR) + TSIZE(size) ); | ||||
| 	glob = malloc( (globbed + 1) * PTRSZ + TSIZE(size) ); | ||||
| 	path = (LPTSTR)(glob + globbed + 1); | ||||
| 	globbed = 0; | ||||
| 	fh = FindFirstFile( arg, &fd ); | ||||
| @ -789,7 +866,7 @@ void get_file( LPTSTR arg, LPTSTR* argv, LPTSTR* cmd ) | ||||
| 	FindClose( fh ); | ||||
| 	glob[globbed] = NULL; | ||||
| 
 | ||||
| 	qsort( glob, globbed, sizeof(LPTSTR), glob_sort ); | ||||
| 	qsort( glob, globbed, PTRSZ, glob_sort ); | ||||
| 
 | ||||
| 	wcscpy( name, glob[0] ); | ||||
| 	globbed = 1; | ||||
| @ -799,6 +876,13 @@ void get_file( LPTSTR arg, LPTSTR* argv, LPTSTR* cmd ) | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| // VC macros don't like preprocessor statements mixed with strings.
 | ||||
| #ifdef _WIN64 | ||||
| #define WINTYPE L"Windows" | ||||
| #else | ||||
| #define WINTYPE L"Win32" | ||||
| #endif | ||||
| 
 | ||||
| void help( void ) | ||||
| { | ||||
|   _putws( | ||||
| @ -806,11 +890,7 @@ L"ANSICON by Jason Hood <jadoxa@yahoo.com.au>.\n" | ||||
| L"Version " PVERS L" (" PDATE L").  Freeware.\n" | ||||
| L"http://ansicon.adoxa.vze.com/\n" | ||||
| L"\n" | ||||
| #ifdef _WIN64 | ||||
| L"Process ANSI escape sequences in Windows console programs.\n" | ||||
| #else | ||||
| L"Process ANSI escape sequences in Win32 console programs.\n" | ||||
| #endif | ||||
| L"Process ANSI escape sequences in " WINTYPE L" console programs.\n" | ||||
| L"\n" | ||||
| L"ansicon [-l<level>] [-i] [-I] [-u] [-U] [-m[<attr>]] [-p]\n" | ||||
| L"        [-e|E string | -t|T [file(s)] | program [args]]\n" | ||||
|  | ||||
							
								
								
									
										33
									
								
								ansicon.h
									
									
									
									
									
								
							
							
						
						
									
										33
									
								
								ansicon.h
									
									
									
									
									
								
							| @ -31,6 +31,22 @@ | ||||
| #define LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE 0x20 | ||||
| #endif | ||||
| 
 | ||||
| #define EXPORTDIR OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT] | ||||
| #define IMPORTDIR OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT] | ||||
| #define BOUNDDIR  OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT] | ||||
| #define IATDIR	  OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT] | ||||
| #define COMDIR	  OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR] | ||||
| 
 | ||||
| 
 | ||||
| // Reduce the verbosity of some functions (assuming variable names).
 | ||||
| #define ReadProcVar(a, b)     ReadProcMem( a, b, sizeof(*(b)) ) | ||||
| #define WriteProcVar(a, b)    WriteProcMem( a, b, sizeof(*(b)) ) | ||||
| #define ReadProcMem(a, b, c)  ReadProcessMemory( ppi->hProcess, a, b, c, NULL ) | ||||
| #define WriteProcMem(a, b, c) WriteProcessMemory( ppi->hProcess, a, b, c, NULL ) | ||||
| #define VirtProtVar(a, b)     VirtualProtectEx( ppi->hProcess, a, sizeof(*(a)), b, &pr ) | ||||
| 
 | ||||
| #define PTRSZ sizeof(PVOID) | ||||
| 
 | ||||
| 
 | ||||
| typedef struct | ||||
| { | ||||
| @ -44,16 +60,23 @@ typedef struct | ||||
| } GRM, *PGRM;		// Graphic Rendition Mode
 | ||||
| 
 | ||||
| 
 | ||||
| int  ProcessType( LPPROCESS_INFORMATION, BOOL* ); | ||||
| void InjectDLL32( LPPROCESS_INFORMATION, LPCTSTR ); | ||||
| void InjectDLL64( LPPROCESS_INFORMATION, LPCTSTR ); | ||||
| BOOL get_LLW32r( void ); | ||||
| BOOL get_LLW64r( void ); | ||||
| int  ProcessType( LPPROCESS_INFORMATION, PBYTE*, BOOL* ); | ||||
| 
 | ||||
| void InjectDLL( LPPROCESS_INFORMATION, PBYTE ); | ||||
| void InjectDLL32( LPPROCESS_INFORMATION, PBYTE ); | ||||
| 
 | ||||
| DWORD	get_LLW32r( void ); | ||||
| DWORD64 get_LLW64r( void ); | ||||
| 
 | ||||
| extern TCHAR  prog_path[MAX_PATH]; | ||||
| extern LPTSTR prog; | ||||
| LPTSTR get_program_name( LPTSTR ); | ||||
| 
 | ||||
| extern char  ansi_dll[MAX_PATH]; | ||||
| extern DWORD ansi_len; | ||||
| extern char* ansi_bits; | ||||
| void   set_ansi_dll( LPTSTR ); | ||||
| 
 | ||||
| extern int log_level; | ||||
| void DEBUGSTR( int level, LPTSTR szFormat, ... ); | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										202
									
								
								injdll.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										202
									
								
								injdll.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,202 @@ | ||||
| /*
 | ||||
|   Inject the DLL into the target process by modifying its import descriptor | ||||
|   table.  The target process must have been created suspended. | ||||
| */ | ||||
| 
 | ||||
| #include "ansicon.h" | ||||
| 
 | ||||
| 
 | ||||
| // Search for a suitable free area after the main image.  (32-bit code could
 | ||||
| // really go anywhere, but let's keep it relatively local.)
 | ||||
| PVOID FindMem( HANDLE hProcess, PBYTE base, DWORD len ) | ||||
| { | ||||
|   MEMORY_BASIC_INFORMATION minfo; | ||||
|   PBYTE ptr; | ||||
|   PVOID mem; | ||||
| 
 | ||||
|   for (ptr = base; | ||||
|        VirtualQueryEx( hProcess, ptr, &minfo, sizeof(minfo) ); | ||||
|        ptr += minfo.RegionSize) | ||||
|   { | ||||
|     if ((minfo.State & MEM_FREE) && minfo.RegionSize >= len) | ||||
|     { | ||||
| #ifdef _WIN64 | ||||
|       if ((PBYTE)minfo.BaseAddress - base > 0xFfFfFfFf - len) | ||||
| 	return NULL; | ||||
| #endif | ||||
|       mem = VirtualAllocEx( hProcess, (PVOID) | ||||
| 			    (((DWORD_PTR)minfo.BaseAddress + 0xFFFF) & ~0xFFFF), | ||||
| 			    len, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE ); | ||||
|       if (mem != NULL) | ||||
| 	return mem; | ||||
|     } | ||||
|   } | ||||
|   return NULL; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void InjectDLL( LPPROCESS_INFORMATION ppi, PBYTE pBase ) | ||||
| { | ||||
|   DWORD rva; | ||||
|   PVOID pMem; | ||||
|   DWORD len; | ||||
|   DWORD pr; | ||||
|   IMAGE_DOS_HEADER	   DosHeader; | ||||
|   IMAGE_NT_HEADERS	   NTHeader, *pNTHeader; | ||||
|   PIMAGE_IMPORT_DESCRIPTOR pImports, pANSI_ImportDesc; | ||||
|   IMAGE_COR20_HEADER	   ComHeader, *pComHeader; | ||||
|   union | ||||
|   { | ||||
|     PBYTE     pB; | ||||
|     PLONG_PTR pL; | ||||
|   } ip; | ||||
| 
 | ||||
|   ReadProcVar( pBase, &DosHeader ); | ||||
|   pNTHeader = (PIMAGE_NT_HEADERS)(pBase + DosHeader.e_lfanew); | ||||
|   ReadProcVar( pNTHeader, &NTHeader ); | ||||
| 
 | ||||
|   len = 4 * PTRSZ + ansi_len | ||||
| 	+ sizeof(*pANSI_ImportDesc) + NTHeader.IMPORTDIR.Size; | ||||
|   pImports = malloc( len ); | ||||
|   if (pImports == NULL) | ||||
|   { | ||||
|     DEBUGSTR( 1, L"  Failed to allocate memory." ); | ||||
|     return; | ||||
|   } | ||||
|   pMem = FindMem( ppi->hProcess, pBase, len ); | ||||
|   if (pMem == NULL) | ||||
|   { | ||||
|     DEBUGSTR( 1, L"  Failed to allocate virtual memory." ); | ||||
|     free( pImports ); | ||||
|     return; | ||||
|   } | ||||
|   rva = (DWORD)((PBYTE)pMem - pBase); | ||||
| 
 | ||||
|   ip.pL = (PLONG_PTR)pImports; | ||||
|   *ip.pL++ = IMAGE_ORDINAL_FLAG + 1; | ||||
|   *ip.pL++ = 0; | ||||
|   *ip.pL++ = IMAGE_ORDINAL_FLAG + 1; | ||||
|   *ip.pL++ = 0; | ||||
|   memcpy( ip.pB, ansi_dll, ansi_len ); | ||||
|   ip.pB += ansi_len; | ||||
|   pANSI_ImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)ip.pB; | ||||
|   pANSI_ImportDesc->OriginalFirstThunk = rva + 2 * PTRSZ; | ||||
|   pANSI_ImportDesc->TimeDateStamp = 0; | ||||
|   pANSI_ImportDesc->ForwarderChain = 0; | ||||
|   pANSI_ImportDesc->Name = rva + 4 * PTRSZ; | ||||
|   pANSI_ImportDesc->FirstThunk = rva; | ||||
|   ReadProcMem( pBase + NTHeader.IMPORTDIR.VirtualAddress, | ||||
| 	       pANSI_ImportDesc + 1, NTHeader.IMPORTDIR.Size ); | ||||
|   WriteProcMem( pMem, pImports, len ); | ||||
|   free( pImports ); | ||||
| 
 | ||||
|   NTHeader.IMPORTDIR.VirtualAddress = rva + 4 * PTRSZ + ansi_len; | ||||
|   NTHeader.IMPORTDIR.Size += sizeof(*pANSI_ImportDesc); | ||||
| 
 | ||||
|   // If there's no IAT, copy the IDT.
 | ||||
|   if (NTHeader.IATDIR.VirtualAddress == 0) | ||||
|     NTHeader.IATDIR = NTHeader.IMPORTDIR; | ||||
| 
 | ||||
|   // Remove bound imports, so the updated import table is used.
 | ||||
|   NTHeader.BOUNDDIR.VirtualAddress = 0; | ||||
|   NTHeader.BOUNDDIR.Size = 0; | ||||
| 
 | ||||
|   VirtProtVar( pNTHeader, PAGE_READWRITE ); | ||||
|   WriteProcVar( pNTHeader, &NTHeader ); | ||||
|   VirtProtVar( pNTHeader, pr ); | ||||
| 
 | ||||
|   // Remove the IL-only flag on a managed process.
 | ||||
|   if (NTHeader.COMDIR.VirtualAddress != 0 && NTHeader.COMDIR.Size != 0) | ||||
|   { | ||||
|     pComHeader = (PIMAGE_COR20_HEADER)(pBase + NTHeader.COMDIR.VirtualAddress); | ||||
|     ReadProcVar( pComHeader, &ComHeader ); | ||||
|     if (ComHeader.Flags & COMIMAGE_FLAGS_ILONLY) | ||||
|     { | ||||
|       ComHeader.Flags &= ~COMIMAGE_FLAGS_ILONLY; | ||||
|       VirtProtVar( pComHeader, PAGE_READWRITE ); | ||||
|       WriteProcVar( pComHeader, &ComHeader ); | ||||
|       VirtProtVar( pComHeader, pr ); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| #ifdef _WIN64 | ||||
| void InjectDLL32( LPPROCESS_INFORMATION ppi, PBYTE pBase ) | ||||
| { | ||||
|   DWORD rva; | ||||
|   PVOID pMem; | ||||
|   DWORD len; | ||||
|   DWORD pr; | ||||
|   IMAGE_DOS_HEADER	   DosHeader; | ||||
|   IMAGE_NT_HEADERS32	   NTHeader, *pNTHeader; | ||||
|   PIMAGE_IMPORT_DESCRIPTOR pImports, pANSI_ImportDesc; | ||||
|   IMAGE_COR20_HEADER	   ComHeader, *pComHeader; | ||||
|   union | ||||
|   { | ||||
|     PBYTE pB; | ||||
|     PLONG pL; | ||||
|   } ip; | ||||
| 
 | ||||
|   ReadProcVar( pBase, &DosHeader ); | ||||
|   pNTHeader = (PIMAGE_NT_HEADERS32)(pBase + DosHeader.e_lfanew); | ||||
|   ReadProcVar( pNTHeader, &NTHeader ); | ||||
| 
 | ||||
|   len = 16 + ansi_len + sizeof(*pANSI_ImportDesc) + NTHeader.IMPORTDIR.Size; | ||||
|   pImports = malloc( len ); | ||||
|   if (pImports == NULL) | ||||
|   { | ||||
|     DEBUGSTR( 1, L"  Failed to allocate memory." ); | ||||
|     return; | ||||
|   } | ||||
|   pMem = FindMem( ppi->hProcess, pBase, len ); | ||||
|   if (pMem == NULL) | ||||
|   { | ||||
|     DEBUGSTR( 1, L"  Failed to allocate virtual memory." ); | ||||
|     free( pImports ); | ||||
|     return; | ||||
|   } | ||||
|   rva = (DWORD)((PBYTE)pMem - pBase); | ||||
| 
 | ||||
|   ip.pL = (PLONG)pImports; | ||||
|   *ip.pL++ = IMAGE_ORDINAL_FLAG32 + 1; | ||||
|   *ip.pL++ = 0; | ||||
|   *ip.pL++ = IMAGE_ORDINAL_FLAG32 + 1; | ||||
|   *ip.pL++ = 0; | ||||
|   memcpy( ip.pB, ansi_dll, ansi_len ); | ||||
|   ip.pB += ansi_len; | ||||
|   pANSI_ImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)ip.pB; | ||||
|   pANSI_ImportDesc->OriginalFirstThunk = rva + 8; | ||||
|   pANSI_ImportDesc->TimeDateStamp = 0; | ||||
|   pANSI_ImportDesc->ForwarderChain = 0; | ||||
|   pANSI_ImportDesc->Name = rva + 16; | ||||
|   pANSI_ImportDesc->FirstThunk = rva; | ||||
|   ReadProcMem( pBase + NTHeader.IMPORTDIR.VirtualAddress, | ||||
| 	       pANSI_ImportDesc + 1, NTHeader.IMPORTDIR.Size ); | ||||
|   WriteProcMem( pMem, pImports, len ); | ||||
|   free( pImports ); | ||||
| 
 | ||||
|   NTHeader.IMPORTDIR.VirtualAddress = rva + 16 + ansi_len; | ||||
|   NTHeader.IMPORTDIR.Size += sizeof(*pANSI_ImportDesc); | ||||
|   if (NTHeader.IATDIR.VirtualAddress == 0) | ||||
|     NTHeader.IATDIR = NTHeader.IMPORTDIR; | ||||
|   NTHeader.BOUNDDIR.VirtualAddress = 0; | ||||
|   NTHeader.BOUNDDIR.Size = 0; | ||||
|   VirtProtVar( pNTHeader, PAGE_READWRITE ); | ||||
|   WriteProcVar( pNTHeader, &NTHeader ); | ||||
|   VirtProtVar( pNTHeader, pr ); | ||||
| 
 | ||||
|   if (NTHeader.COMDIR.VirtualAddress != 0 && NTHeader.COMDIR.Size != 0) | ||||
|   { | ||||
|     pComHeader = (PIMAGE_COR20_HEADER)(pBase + NTHeader.COMDIR.VirtualAddress); | ||||
|     ReadProcVar( pComHeader, &ComHeader ); | ||||
|     if (ComHeader.Flags & COMIMAGE_FLAGS_ILONLY) | ||||
|     { | ||||
|       ComHeader.Flags &= ~COMIMAGE_FLAGS_ILONLY; | ||||
|       VirtProtVar( pComHeader, PAGE_READWRITE ); | ||||
|       WriteProcVar( pComHeader, &ComHeader ); | ||||
|       VirtProtVar( pComHeader, pr ); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| #endif | ||||
							
								
								
									
										251
									
								
								injdll32.c
									
									
									
									
									
								
							
							
						
						
									
										251
									
								
								injdll32.c
									
									
									
									
									
								
							| @ -1,251 +0,0 @@ | ||||
| /*
 | ||||
|   Inject code into the target process to load our DLL.	The target thread | ||||
|   should be suspended on entry; it remains suspended on exit. | ||||
| 
 | ||||
|   Initially I used the "stack" method of injection.  However, this fails | ||||
|   when DEP is active, since that doesn't allow code to execute in the stack. | ||||
|   To overcome this I used the "CreateRemoteThread" method.  However, this | ||||
|   would fail with Wselect, a program to assist batch files.  Wselect runs, | ||||
|   but it has no output.  As it turns out, removing the suspended flag would | ||||
|   make Wselect work, but it caused problems with everything else.  So now I | ||||
|   allocate a section of memory and change the context to run from there.  At | ||||
|   first I had an event to signal when the library was loaded, then the memory | ||||
|   was released.  However, that wouldn't work with -p and CMD.EXE (4NT v8 | ||||
|   worked fine).  Since it's possible the DLL might start a process suspended, | ||||
|   I've decided to simply keep the memory. | ||||
| */ | ||||
| 
 | ||||
| #include "ansicon.h" | ||||
| 
 | ||||
| #ifdef _WIN64 | ||||
| #ifndef WOW64_CONTEXT_ALL | ||||
| #include "wow64.h" | ||||
| 
 | ||||
| TWow64GetThreadContext Wow64GetThreadContext; | ||||
| TWow64SetThreadContext Wow64SetThreadContext; | ||||
| #define IMPORT_WOW64 | ||||
| #endif | ||||
| 
 | ||||
| #define CONTEXT 	 WOW64_CONTEXT | ||||
| #undef	CONTEXT_CONTROL | ||||
| #define CONTEXT_CONTROL  WOW64_CONTEXT_CONTROL | ||||
| #define GetThreadContext Wow64GetThreadContext | ||||
| #define SetThreadContext Wow64SetThreadContext | ||||
| #endif | ||||
| 
 | ||||
| extern DWORD LLW32r; | ||||
| LPVOID kernel32_base; | ||||
| PIMAGE_DOS_HEADER pDosHeader; | ||||
| 
 | ||||
| #define MakeVA( cast, offset ) (cast)((DWORD_PTR)pDosHeader + (DWORD)(offset)) | ||||
| 
 | ||||
| int export_cmp( const void* a, const void* b ) | ||||
| { | ||||
|   return strcmp( (LPCSTR)a, MakeVA( LPCSTR, *(const PDWORD)b ) ); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|   Get the relative address of LoadLibraryW direct from kernel32.dll. | ||||
| */ | ||||
| BOOL get_LLW32r( void ) | ||||
| { | ||||
|   HMODULE kernel32; | ||||
|   TCHAR   buf[MAX_PATH]; | ||||
|   UINT	  len; | ||||
|   PIMAGE_NT_HEADERS32	  pNTHeader; | ||||
|   PIMAGE_EXPORT_DIRECTORY pExportDir; | ||||
|   PDWORD  fun_table, name_table; | ||||
|   PWORD   ord_table; | ||||
|   PDWORD  pLLW; | ||||
| 
 | ||||
| #ifdef _WIN64 | ||||
|   len = GetSystemWow64Directory( buf, MAX_PATH ); | ||||
| #else | ||||
|   len = GetSystemDirectory( buf, MAX_PATH ); | ||||
| #endif | ||||
|   wcscpy( buf + len, L"\\kernel32.dll" ); | ||||
|   kernel32 = LoadLibraryEx( buf, NULL, LOAD_LIBRARY_AS_IMAGE_RESOURCE ); | ||||
|   if (kernel32 == NULL) | ||||
|   { | ||||
|     DEBUGSTR( 1, L"Unable to load 32-bit kernel32.dll!" ); | ||||
|     return FALSE; | ||||
|   } | ||||
|   // The handle uses low bits as flags, so strip 'em off.
 | ||||
|   pDosHeader = (PIMAGE_DOS_HEADER)((DWORD_PTR)kernel32 & ~0xFFFF); | ||||
|   pNTHeader  = MakeVA( PIMAGE_NT_HEADERS32, pDosHeader->e_lfanew ); | ||||
|   pExportDir = MakeVA( PIMAGE_EXPORT_DIRECTORY, | ||||
| 		       pNTHeader->OptionalHeader. | ||||
| 			DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]. | ||||
| 			 VirtualAddress ); | ||||
| 
 | ||||
|   fun_table  = MakeVA( PDWORD, pExportDir->AddressOfFunctions ); | ||||
|   name_table = MakeVA( PDWORD, pExportDir->AddressOfNames ); | ||||
|   ord_table  = MakeVA( PWORD,  pExportDir->AddressOfNameOrdinals ); | ||||
| 
 | ||||
|   pLLW = bsearch( "LoadLibraryW", name_table, pExportDir->NumberOfNames, | ||||
| 		  sizeof(DWORD), export_cmp ); | ||||
|   if (pLLW == NULL) | ||||
|   { | ||||
|     DEBUGSTR( 1, L"Could not find LoadLibraryW!" ); | ||||
|     FreeLibrary( kernel32 ); | ||||
|     return FALSE; | ||||
|   } | ||||
|   LLW32r = fun_table[ord_table[pLLW - name_table]]; | ||||
| 
 | ||||
|   FreeLibrary( kernel32 ); | ||||
|   return TRUE; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void InjectDLL32( LPPROCESS_INFORMATION ppi, LPCTSTR dll ) | ||||
| { | ||||
|   CONTEXT context; | ||||
|   DWORD   ep; | ||||
|   BOOL	  eip; | ||||
|   LPVOID  mem; | ||||
|   DWORD   mem32; | ||||
|   DWORD   pr; | ||||
|   DWORD   LLW; | ||||
| 
 | ||||
|   DWORD   len; | ||||
|   #define CODESIZE 20 | ||||
|   BYTE	  code[CODESIZE+TSIZE(MAX_PATH)]; | ||||
|   union | ||||
|   { | ||||
|     PBYTE  pB; | ||||
|     PDWORD pL; | ||||
|   } ip; | ||||
| 
 | ||||
|   struct unicode_string | ||||
|   { | ||||
|     USHORT Length; | ||||
|     USHORT MaximumLength; | ||||
|     DWORD  Buffer; | ||||
|   }; | ||||
|   struct ldr_module		// incomplete definition
 | ||||
|   { | ||||
|     DWORD next, prev; | ||||
|     DWORD baseAddress; | ||||
|     DWORD entryPoint; | ||||
|     DWORD sizeOfImage; | ||||
|     struct unicode_string fullDllName; | ||||
|     struct unicode_string baseDllName; | ||||
|   } ldr; | ||||
|   WCHAR basename[MAX_PATH]; | ||||
| 
 | ||||
| #ifdef IMPORT_WOW64 | ||||
|   if (Wow64GetThreadContext == 0) | ||||
|   { | ||||
|     #define GETPROC( proc ) proc = (T##proc)GetProcAddress( hKernel, #proc ) | ||||
|     HMODULE hKernel = GetModuleHandle( L"kernel32.dll" ); | ||||
|     GETPROC( Wow64GetThreadContext ); | ||||
|     GETPROC( Wow64SetThreadContext ); | ||||
|     // Assume if one is defined, so is the other.
 | ||||
|     if (Wow64GetThreadContext == 0) | ||||
|     { | ||||
|       DEBUGSTR( 1, L"Failed to get pointer to Wow64GetThreadContext." ); | ||||
|       return; | ||||
|     } | ||||
|   } | ||||
| #endif | ||||
| 
 | ||||
|   len = TSIZE(lstrlen( dll ) + 1); | ||||
|   if (len > TSIZE(MAX_PATH)) | ||||
|     return; | ||||
|   CopyMemory( code + CODESIZE, dll, len ); | ||||
|   len += CODESIZE; | ||||
| 
 | ||||
|   context.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER; | ||||
|   GetThreadContext( ppi->hThread, &context ); | ||||
|   mem = VirtualAllocEx( ppi->hProcess, NULL, len, MEM_COMMIT, | ||||
| 			PAGE_READWRITE ); | ||||
|   mem32 = (DWORD)(DWORD_PTR)mem; | ||||
| 
 | ||||
|   ip.pB = code; | ||||
| 
 | ||||
|   // Determine the base address of kernel32.dll.  If injecting into the parent
 | ||||
|   // process, the base has already been determined.  Otherwise, use the PEB to
 | ||||
|   // walk the loaded modules.
 | ||||
|   if (kernel32_base != 0) | ||||
|   { | ||||
|     ep = context.Eip; | ||||
|     eip = TRUE; | ||||
|   } | ||||
|   else | ||||
|   { | ||||
|     // When a process is created suspended, EAX has the entry point and EBX
 | ||||
|     // points to the PEB.
 | ||||
|     if (!ReadProcessMemory( ppi->hProcess, UIntToPtr( context.Ebx + 0x0C ), | ||||
| 			    ip.pL, 4, NULL )) | ||||
|     { | ||||
|       DEBUGSTR( 1, L"Failed to read Ldr from PEB." ); | ||||
|       return; | ||||
|     } | ||||
|     ep = context.Eax; | ||||
|     eip = FALSE; | ||||
|     // In case we're a bit slow (which seems to be unlikely), set up an
 | ||||
|     // infinite loop as the entry point.
 | ||||
|     WriteProcessMemory( ppi->hProcess, mem, "\xEB\xFE", 2, NULL ); | ||||
|     FlushInstructionCache( ppi->hProcess, mem, 2 ); | ||||
|     context.Eax = mem32; | ||||
|     SetThreadContext( ppi->hThread, &context ); | ||||
|     VirtualProtectEx( ppi->hProcess, mem, len, PAGE_EXECUTE, &pr ); | ||||
|     // Now resume the thread, as the PEB hasn't even been created yet.
 | ||||
|     ResumeThread( ppi->hThread ); | ||||
|     while (*ip.pL == 0) | ||||
|     { | ||||
|       Sleep( 0 ); | ||||
|       ReadProcessMemory( ppi->hProcess, UIntToPtr( context.Ebx + 0x0C ), | ||||
| 			 ip.pL, 4, NULL ); | ||||
|     } | ||||
|     // Read PEB_LDR_DATA.InInitializationOrderModuleList.Flink.
 | ||||
|     ReadProcessMemory( ppi->hProcess, UIntToPtr( *ip.pL + 0x1c ), | ||||
| 		       &ip.pL[1], 4, NULL ); | ||||
|     // Sometimes we're so quick ntdll.dll is the only one present, so keep
 | ||||
|     // looping until kernel32.dll shows up.
 | ||||
|     for (;;) | ||||
|     { | ||||
|       ldr.next = ip.pL[1]; | ||||
|       do | ||||
|       { | ||||
| 	ReadProcessMemory( ppi->hProcess, UIntToPtr( ldr.next ), | ||||
| 			   &ldr, sizeof(ldr), NULL ); | ||||
| 	ReadProcessMemory( ppi->hProcess, UIntToPtr( ldr.baseDllName.Buffer ), | ||||
| 			   basename, ldr.baseDllName.MaximumLength, NULL ); | ||||
| 	if (_wcsicmp( basename, L"kernel32.dll" ) == 0) | ||||
| 	{ | ||||
| 	  kernel32_base = UIntToPtr( ldr.baseAddress ); | ||||
| 	  goto gotit; | ||||
| 	} | ||||
|       } while (ldr.next != *ip.pL + 0x1c); | ||||
|     } | ||||
|   gotit: | ||||
|     SuspendThread( ppi->hThread ); | ||||
|     VirtualProtectEx( ppi->hProcess, mem, len, pr, &pr ); | ||||
|   } | ||||
|   LLW = PtrToUint( kernel32_base ) + LLW32r; | ||||
|   kernel32_base = 0; | ||||
| 
 | ||||
|   *ip.pB++ = 0x68;			// push  ep
 | ||||
|   *ip.pL++ = ep; | ||||
|   *ip.pB++ = 0x9c;			// pushf
 | ||||
|   *ip.pB++ = 0x60;			// pusha
 | ||||
|   *ip.pB++ = 0x68;			// push  L"path\to\ANSI32.dll"
 | ||||
|   *ip.pL++ = mem32 + CODESIZE; | ||||
|   *ip.pB++ = 0xe8;			// call  LoadLibraryW
 | ||||
|   *ip.pL++ = LLW - (mem32 + (DWORD)(ip.pB+4 - code)); | ||||
|   *ip.pB++ = 0x61;			// popa
 | ||||
|   *ip.pB++ = 0x9d;			// popf
 | ||||
|   *ip.pB++ = 0xc3;			// ret
 | ||||
| 
 | ||||
|   WriteProcessMemory( ppi->hProcess, mem, code, len, NULL ); | ||||
|   FlushInstructionCache( ppi->hProcess, mem, len ); | ||||
|   VirtualProtectEx( ppi->hProcess, mem, len, PAGE_EXECUTE, &pr ); | ||||
| 
 | ||||
|   if (eip) | ||||
|   { | ||||
|     context.Eip = mem32; | ||||
|     SetThreadContext( ppi->hThread, &context ); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										243
									
								
								injdll64.c
									
									
									
									
									
								
							
							
						
						
									
										243
									
								
								injdll64.c
									
									
									
									
									
								
							| @ -1,243 +0,0 @@ | ||||
| /*
 | ||||
|   Inject code into the target process to load our DLL.	The target thread | ||||
|   should be suspended on entry; it remains suspended on exit. | ||||
| 
 | ||||
|   Initially I used the "stack" method of injection.  However, this fails | ||||
|   when DEP is active, since that doesn't allow code to execute in the stack. | ||||
|   To overcome this I used the "CreateRemoteThread" method.  However, this | ||||
|   would fail with Wselect, a program to assist batch files.  Wselect runs, | ||||
|   but it has no output.  As it turns out, removing the suspended flag would | ||||
|   make Wselect work, but it caused problems with everything else.  So now I | ||||
|   allocate a section of memory and change the context to run from there.  At | ||||
|   first I had an event to signal when the library was loaded, then the memory | ||||
|   was released.  However, that wouldn't work with -p and CMD.EXE (4NT v8 | ||||
|   worked fine).  Since it's possible the DLL might start a process suspended, | ||||
|   I've decided to simply keep the memory. | ||||
| */ | ||||
| 
 | ||||
| #include "ansicon.h" | ||||
| 
 | ||||
| extern DWORD LLW64r; | ||||
| extern LPVOID kernel32_base; | ||||
| extern PIMAGE_DOS_HEADER pDosHeader; | ||||
| 
 | ||||
| #define MakeVA( cast, offset ) (cast)((DWORD_PTR)pDosHeader + (DWORD)(offset)) | ||||
| 
 | ||||
| extern int export_cmp( const void* a, const void* b ); | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|   Get the relative address of LoadLibraryW direct from kernel32.dll. | ||||
| */ | ||||
| BOOL get_LLW64r( void ) | ||||
| { | ||||
|   HMODULE kernel32; | ||||
|   TCHAR   buf[MAX_PATH]; | ||||
|   UINT	  len; | ||||
|   PIMAGE_NT_HEADERS	  pNTHeader; | ||||
|   PIMAGE_EXPORT_DIRECTORY pExportDir; | ||||
|   PDWORD  fun_table, name_table; | ||||
|   PWORD   ord_table; | ||||
|   PDWORD  pLLW; | ||||
| 
 | ||||
|   len = GetSystemDirectory( buf, MAX_PATH ); | ||||
|   wcscpy( buf + len, L"\\kernel32.dll" ); | ||||
|   kernel32 = LoadLibraryEx( buf, NULL, LOAD_LIBRARY_AS_IMAGE_RESOURCE ); | ||||
|   if (kernel32 == NULL) | ||||
|   { | ||||
|     DEBUGSTR( 1, L"Unable to load 64-bit kernel32.dll!" ); | ||||
|     return FALSE; | ||||
|   } | ||||
|   // The handle uses low bits as flags, so strip 'em off.
 | ||||
|   pDosHeader = (PIMAGE_DOS_HEADER)((DWORD_PTR)kernel32 & ~0xFFFF); | ||||
|   pNTHeader  = MakeVA( PIMAGE_NT_HEADERS, pDosHeader->e_lfanew ); | ||||
|   pExportDir = MakeVA( PIMAGE_EXPORT_DIRECTORY, | ||||
| 		       pNTHeader->OptionalHeader. | ||||
| 			DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]. | ||||
| 			 VirtualAddress ); | ||||
| 
 | ||||
|   fun_table  = MakeVA( PDWORD, pExportDir->AddressOfFunctions ); | ||||
|   name_table = MakeVA( PDWORD, pExportDir->AddressOfNames ); | ||||
|   ord_table  = MakeVA( PWORD,  pExportDir->AddressOfNameOrdinals ); | ||||
| 
 | ||||
|   pLLW = bsearch( "LoadLibraryW", name_table, pExportDir->NumberOfNames, | ||||
| 		  sizeof(DWORD), export_cmp ); | ||||
|   if (pLLW == NULL) | ||||
|   { | ||||
|     DEBUGSTR( 1, L"Could not find LoadLibraryW!" ); | ||||
|     FreeLibrary( kernel32 ); | ||||
|     return FALSE; | ||||
|   } | ||||
|   LLW64r = fun_table[ord_table[pLLW - name_table]]; | ||||
| 
 | ||||
|   FreeLibrary( kernel32 ); | ||||
|   return TRUE; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void InjectDLL64( LPPROCESS_INFORMATION ppi, LPCTSTR dll ) | ||||
| { | ||||
|   CONTEXT context; | ||||
|   DWORD64 ep; | ||||
|   BOOL	  rip; | ||||
|   LPVOID  mem; | ||||
|   DWORD   pr; | ||||
|   DWORD64 LLW; | ||||
| 
 | ||||
|   union | ||||
|   { | ||||
|     PBYTE    pB; | ||||
|     PDWORD64 pL; | ||||
|   } ip; | ||||
| 
 | ||||
|   struct unicode_string | ||||
|   { | ||||
|     USHORT  Length; | ||||
|     USHORT  MaximumLength; | ||||
|     DWORD64 Buffer; | ||||
|   }; | ||||
|   struct ldr_module		// incomplete definition
 | ||||
|   { | ||||
|     DWORD64 next, prev; | ||||
|     DWORD64 baseAddress; | ||||
|     DWORD64 entryPoint; | ||||
|     DWORD64 sizeOfImage; | ||||
|     struct unicode_string fullDllName; | ||||
|     struct unicode_string baseDllName; | ||||
|   } ldr; | ||||
|   WCHAR basename[MAX_PATH]; | ||||
| 
 | ||||
|   DWORD   len; | ||||
|   #define CODESIZE 92 | ||||
|   static BYTE code[CODESIZE+TSIZE(MAX_PATH)] = { | ||||
| 	0,0,0,0,0,0,0,0,	   // original rip
 | ||||
| 	0,0,0,0,0,0,0,0,	   // LoadLibraryW
 | ||||
| 	0x9C,			   // pushfq
 | ||||
| 	0x50,			   // push  rax
 | ||||
| 	0x51,			   // push  rcx
 | ||||
| 	0x52,			   // push  rdx
 | ||||
| 	0x53,			   // push  rbx
 | ||||
| 	0x55,			   // push  rbp
 | ||||
| 	0x56,			   // push  rsi
 | ||||
| 	0x57,			   // push  rdi
 | ||||
| 	0x41,0x50,		   // push  r8
 | ||||
| 	0x41,0x51,		   // push  r9
 | ||||
| 	0x41,0x52,		   // push  r10
 | ||||
| 	0x41,0x53,		   // push  r11
 | ||||
| 	0x41,0x54,		   // push  r12
 | ||||
| 	0x41,0x55,		   // push  r13
 | ||||
| 	0x41,0x56,		   // push  r14
 | ||||
| 	0x41,0x57,		   // push  r15
 | ||||
| 	0x48,0x83,0xEC,0x28,	   // sub   rsp, 40
 | ||||
| 	0x48,0x8D,0x0D,41,0,0,0,   // lea   ecx, L"path\to\ANSI64.dll"
 | ||||
| 	0xFF,0x15,-49,-1,-1,-1,    // call  LoadLibraryW
 | ||||
| 	0x48,0x83,0xC4,0x28,	   // add   rsp, 40
 | ||||
| 	0x41,0x5F,		   // pop   r15
 | ||||
| 	0x41,0x5E,		   // pop   r14
 | ||||
| 	0x41,0x5D,		   // pop   r13
 | ||||
| 	0x41,0x5C,		   // pop   r12
 | ||||
| 	0x41,0x5B,		   // pop   r11
 | ||||
| 	0x41,0x5A,		   // pop   r10
 | ||||
| 	0x41,0x59,		   // pop   r9
 | ||||
| 	0x41,0x58,		   // pop   r8
 | ||||
| 	0x5F,			   // pop   rdi
 | ||||
| 	0x5E,			   // pop   rsi
 | ||||
| 	0x5D,			   // pop   rbp
 | ||||
| 	0x5B,			   // pop   rbx
 | ||||
| 	0x5A,			   // pop   rdx
 | ||||
| 	0x59,			   // pop   rcx
 | ||||
| 	0x58,			   // pop   rax
 | ||||
| 	0x9D,			   // popfq
 | ||||
| 	0xFF,0x25,-91,-1,-1,-1,    // jmp   original Rip
 | ||||
| 	0,			   // dword alignment for LLW, fwiw
 | ||||
|   }; | ||||
| 
 | ||||
|   len = TSIZE(lstrlen( dll ) + 1); | ||||
|   if (len > TSIZE(MAX_PATH)) | ||||
|     return; | ||||
|   CopyMemory( code + CODESIZE, dll, len ); | ||||
|   len += CODESIZE; | ||||
| 
 | ||||
|   context.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER; | ||||
|   GetThreadContext( ppi->hThread, &context ); | ||||
|   mem = VirtualAllocEx( ppi->hProcess, NULL, len, MEM_COMMIT, | ||||
| 			PAGE_READWRITE ); | ||||
| 
 | ||||
|   ip.pB = code; | ||||
| 
 | ||||
|   // Determine the base address of kernel32.dll.  If injecting into the parent
 | ||||
|   // process, the base has already been determined.  Otherwise, use the PEB to
 | ||||
|   // walk the loaded modules.
 | ||||
|   if (kernel32_base != 0) | ||||
|   { | ||||
|     ep = context.Rip; | ||||
|     rip = TRUE; | ||||
|   } | ||||
|   else | ||||
|   { | ||||
|     // When a process is created suspended, RCX has the entry point and RDX
 | ||||
|     // points to the PEB.
 | ||||
|     if (!ReadProcessMemory( ppi->hProcess, (LPVOID)(context.Rdx + 0x18), | ||||
| 			    ip.pL, 8, NULL )) | ||||
|     { | ||||
|       DEBUGSTR( 1, L"Failed to read Ldr from PEB." ); | ||||
|       return; | ||||
|     } | ||||
|     ep = context.Rcx; | ||||
|     rip = FALSE; | ||||
|     // In case we're a bit slow (which seems to be unlikely), set up an
 | ||||
|     // infinite loop as the entry point.
 | ||||
|     WriteProcessMemory( ppi->hProcess, (PBYTE)mem + 16, "\xEB\xFE", 2, NULL ); | ||||
|     FlushInstructionCache( ppi->hProcess, (PBYTE)mem + 16, 2 ); | ||||
|     context.Rcx = (DWORD64)mem + 16; | ||||
|     SetThreadContext( ppi->hThread, &context ); | ||||
|     VirtualProtectEx( ppi->hProcess, mem, len, PAGE_EXECUTE, &pr ); | ||||
|     // Now resume the thread, as the PEB hasn't even been created yet.
 | ||||
|     ResumeThread( ppi->hThread ); | ||||
|     while (*ip.pL == 0) | ||||
|     { | ||||
|       Sleep( 0 ); | ||||
|       ReadProcessMemory( ppi->hProcess, (LPVOID)(context.Rdx + 0x18), | ||||
| 			 ip.pL, 8, NULL ); | ||||
|     } | ||||
|     // Read PEB_LDR_DATA.InInitializationOrderModuleList.Flink.
 | ||||
|     ReadProcessMemory( ppi->hProcess, (LPVOID)(*ip.pL + 0x30), | ||||
| 		       &ip.pL[1], 8, NULL ); | ||||
|     // Sometimes we're so quick ntdll.dll is the only one present, so keep
 | ||||
|     // looping until kernel32.dll shows up.
 | ||||
|     for (;;) | ||||
|     { | ||||
|       ldr.next = ip.pL[1]; | ||||
|       do | ||||
|       { | ||||
| 	ReadProcessMemory( ppi->hProcess, (LPVOID)ldr.next, | ||||
| 			   &ldr, sizeof(ldr), NULL ); | ||||
| 	ReadProcessMemory( ppi->hProcess, (LPVOID)ldr.baseDllName.Buffer, | ||||
| 			   basename, ldr.baseDllName.MaximumLength, NULL ); | ||||
| 	if (_wcsicmp( basename, L"kernel32.dll" ) == 0) | ||||
| 	{ | ||||
| 	  kernel32_base = (LPVOID)ldr.baseAddress; | ||||
| 	  goto gotit; | ||||
| 	} | ||||
|       } while (ldr.next != *ip.pL + 0x30); | ||||
|     } | ||||
|   gotit: | ||||
|     SuspendThread( ppi->hThread ); | ||||
|     VirtualProtectEx( ppi->hProcess, mem, len, pr, &pr ); | ||||
|   } | ||||
|   LLW = (DWORD64)kernel32_base + LLW64r; | ||||
|   kernel32_base = 0; | ||||
| 
 | ||||
|   *ip.pL++ = ep; | ||||
|   *ip.pL++ = LLW; | ||||
| 
 | ||||
|   WriteProcessMemory( ppi->hProcess, mem, code, len, NULL ); | ||||
|   FlushInstructionCache( ppi->hProcess, mem, len ); | ||||
|   VirtualProtectEx( ppi->hProcess, mem, len, PAGE_EXECUTE, &pr ); | ||||
| 
 | ||||
|   if (rip) | ||||
|   { | ||||
|     context.Rip = (DWORD64)mem + 16; | ||||
|     SetThreadContext( ppi->hThread, &context ); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										26
									
								
								makefile.gcc
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								makefile.gcc
									
									
									
									
									
								
							| @ -16,13 +16,16 @@ | ||||
| # | ||||
| # Tested with: | ||||
| # * MinGW/gcc 4.7.2; | ||||
| # * tdm-gcc-4.7.1-2; | ||||
| # * tdm64-gcc-4.7.1-3; | ||||
| # * tdm-gcc-4.8.1-3; | ||||
| # * tdm64-gcc-4.8.1-3; | ||||
| # * MinGW-builds x64-4.8.1-release-posix-seh-rev1. | ||||
| 
 | ||||
| CC = gcc | ||||
| CFLAGS = -O2 -Wall | ||||
| 
 | ||||
| # Identify ansicon.exe using "ANSI" as a version number. | ||||
| IVER = -Wl,--major-image-version,20033,--minor-image-version,18771 | ||||
| 
 | ||||
| #ARCH = 32 | ||||
| #ARCH = 64 | ||||
| #ARCH = multi | ||||
| @ -41,8 +44,8 @@ endif | ||||
| endif | ||||
| endif | ||||
| 
 | ||||
| X86OBJS = x86/proctype.o x86/injdll32.o x86/util.o | ||||
| X64OBJS = x64/proctype.o x64/injdll64.o x64/injdll32.o x64/util.o | ||||
| X86OBJS = x86/proctype.o x86/injdll.o x86/util.o | ||||
| X64OBJS = x64/proctype.o x64/injdll.o x64/util.o | ||||
| 
 | ||||
| # Determine the appropriate separator to run multiple commands - ";" for sh.exe | ||||
| # and "&" for CMD.EXE.  $(SHELL) is initially defined to "sh.exe" - if it | ||||
| @ -67,7 +70,7 @@ x86/%v.o: %.rc version.h | ||||
| 	$(RCmsg)windres -U _WIN64 -F pe-i386 $< $@ | ||||
| 
 | ||||
| x64/%.o: %.c ansicon.h | ||||
| 	$(CCmsg)$(CC) -m64 -c $(CFLAGS) $< -o $@ | ||||
| 	$(CCmsg)$(CC) -m64 -g -c $(CFLAGS) $< -o $@ | ||||
| 
 | ||||
| x64/%v.o: %.rc version.h | ||||
| 	$(RCmsg)windres -F pe-x86-64 $< $@ | ||||
| @ -89,8 +92,8 @@ ansicon64: x64 x64/ansicon.exe x64/ANSI64.dll | ||||
| x86: | ||||
| 	cmd /c "mkdir x86" | ||||
| 
 | ||||
| x86/ansicon.exe: x86/ansicon.o $(X86OBJS) x86/ansiconv.o | ||||
| 	$(LDmsg)$(CC) -m32 $+ -s -o $@ | ||||
| x86/ansicon.exe: x86/ansicon.o $(X86OBJS) x86/LLW.o x86/ansiconv.o | ||||
| 	$(LDmsg)$(CC) -m32 $+ -s -o $@ $(IVER) | ||||
| 
 | ||||
| x86/ANSI32.dll: x86/ANSI.o $(X86OBJS) x86/ansiv.o | ||||
| 	$(LDmsg)$(CC) -m32 $+ -s -o $@ -mdll -Wl,-shared,--image-base,0xAC0000 | ||||
| @ -98,14 +101,15 @@ x86/ANSI32.dll: x86/ANSI.o $(X86OBJS) x86/ansiv.o | ||||
| x64: | ||||
| 	cmd /c "mkdir x64" | ||||
| 
 | ||||
| x64/ansicon.exe: x64/ansicon.o $(X64OBJS) x64/ansiconv.o | ||||
| 	$(LDmsg)$(CC) -m64 $+ -s -o $@ | ||||
| x64/ansicon.exe: x64/ansicon.o $(X64OBJS) x64/LLW.o x64/ansiconv.o | ||||
| 	$(LDmsg)$(CC) -m64 $+ -s -o $@ $(IVER) | ||||
| 
 | ||||
| x64/ANSI64.dll: x64/ANSI.o $(X64OBJS) x64/ansiv.o | ||||
| 	$(LDmsg)$(CC) -m64 $+ -s -o $@ -mdll -Wl,-shared,--image-base,0xAC000000 | ||||
| 
 | ||||
| x64/ANSI32.dll: x64/ANSI32.o x64/proctype32.o x86/injdll32.o x86/util.o x86/ansiv.o | ||||
| 	$(LDmsg)$(CC) -m32 $+ -s -o $@ -mdll -Wl,-shared,--image-base,0xAC0000 | ||||
| x64/ANSI32.dll: x64/ANSI32.o x64/proctype32.o x86/injdll.o x86/util.o x86/ansiv.o | ||||
| 	$(LDmsg)$(CC) -m32 $+ -s -o $@ -mdll \ | ||||
| 		      -Wl,-shared,--image-base,0xAC0000,--large-address-aware | ||||
| 
 | ||||
| x86/ansicon.o:	version.h | ||||
| x86/ANSI.o:	version.h | ||||
|  | ||||
							
								
								
									
										31
									
								
								makefile.vc
									
									
									
									
									
								
							
							
						
						
									
										31
									
								
								makefile.vc
									
									
									
									
									
								
							| @ -62,8 +62,11 @@ MT = mt.exe | ||||
| CFLAGS = /nologo /W3 /O2 $(SHARE) /D_CRT_SECURE_NO_WARNINGS | ||||
| LIBS = advapi32.lib user32.lib $(LIBS64) | ||||
| 
 | ||||
| X86OBJS = x86\proctype.obj x86\injdll32.obj x86\util.obj | ||||
| X64OBJS = x64\proctype.obj x64\injdll64.obj x64\injdll32.obj x64\util.obj | ||||
| # Identify ansicon.exe using "ANSI" as a version number. | ||||
| LINK = /link /version:20033.18771 | ||||
| 
 | ||||
| X86OBJS = x86\proctype.obj x86\injdll.obj x86\util.obj | ||||
| X64OBJS = x64\proctype.obj x64\injdll.obj x64\util.obj | ||||
| 
 | ||||
| !IF !DEFINED(V) | ||||
| V = 0 | ||||
| @ -90,15 +93,16 @@ ansicon64: x64 x64\ansicon.exe x64\ANSI64.dll | ||||
| x86: | ||||
| 	mkdir x86 | ||||
| 
 | ||||
| x86\ansicon.exe: x86\ansicon.obj $(X86OBJS) x86\ansicon.res | ||||
| 	$(LDmsg)$(CC) /nologo $(SHARE) /Fe$@ $** $(LIBS) /link /filealign:512 | ||||
| x86\ansicon.exe: x86\ansicon.obj $(X86OBJS) x86\LLW.obj x86\ansicon.res | ||||
| 	$(LDmsg)$(CC) /nologo $(SHARE) /Fe$@ $** $(LIBS) $(LINK) /filealign:512 | ||||
| !IF "$(_NMAKE_VER)" == "9.00.30729.01" | ||||
| 	$(MTmsg)$(MT) /nologo -manifest $@.manifest -outputresource:$@;1 | ||||
| 	@del $@.manifest | ||||
| !ENDIF | ||||
| 
 | ||||
| x86\ANSI32.dll: x86\ANSI.obj $(X86OBJS) x86\ansi.res | ||||
| 	$(LDmsg)$(CC) /nologo $(SHARE) /LD /Fe$@ $** $(LIBS) /link /base:0xAC0000 /section:.shared,s /filealign:512 | ||||
| 	$(LDmsg)$(CC) /nologo $(SHARE) /LD /Fe$@ $** $(LIBS) /link \ | ||||
| 		      /base:0xAC0000 /section:.shared,s /filealign:512 | ||||
| !IF "$(_NMAKE_VER)" == "9.00.30729.01" | ||||
| 	$(MTmsg)$(MT) /nologo -manifest $@.manifest -outputresource:$@;2 | ||||
| 	@del $@.manifest | ||||
| @ -107,14 +111,16 @@ x86\ANSI32.dll: x86\ANSI.obj $(X86OBJS) x86\ansi.res | ||||
| x64: | ||||
| 	mkdir x64 | ||||
| 
 | ||||
| x64\ansicon.exe: x64\ansicon.obj $(X64OBJS) x64\ansicon.res | ||||
| 	$(LDmsg)$(CC) /nologo $(SHARE) /Fe$@ $** $(LIBS) | ||||
| x64\ansicon.exe: x64\ansicon.obj $(X64OBJS) x64\LLW.obj x64\ansicon.res | ||||
| 	$(LDmsg)$(CC) /nologo $(SHARE) /Fe$@ $** $(LIBS) $(LINK) | ||||
| 
 | ||||
| x64\ANSI64.dll: x64\ANSI.obj $(X64OBJS) x64\ansi.res | ||||
| 	$(LDmsg)$(CC) /nologo $(SHARE) /LD /Fe$@ $** $(LIBS) /link /base:0xAC000000 /section:.shared,s | ||||
| 	$(LDmsg)$(CC) /nologo $(SHARE) /LD /Fe$@ $** $(LIBS) /link \ | ||||
| 		      /base:0xAC000000 /section:.shared,s | ||||
| 
 | ||||
| x64\ANSI32.dll: x64\ANSI32.obj x64\proctype32.obj x86\injdll32.obj x86\util.obj x86\ansi.res | ||||
| 	$(LDmsg)$(CC) /nologo $(SHARE) /LD /Fe$@ $** $(LIBS) /link /base:0xAC0000 /section:.shared,s /filealign:512 | ||||
| x64\ANSI32.dll: x64\ANSI32.obj x64\proctype32.obj x86\injdll.obj x86\util.obj x86\ansi.res | ||||
| 	$(LDmsg)$(CC) /nologo $(SHARE) /LD /Fe$@ $** $(LIBS) /link \ | ||||
| 	    /base:0xAC0000 /section:.shared,s /filealign:512 /largeaddressaware | ||||
| !IF "$(_NMAKE_VER)" == "9.00.30729.01" | ||||
| 	$(MTmsg)$(MT) /nologo -manifest $@.manifest -outputresource:$@;2 | ||||
| 	@del $@.manifest | ||||
| @ -125,12 +131,13 @@ ansicon.rc: version.h | ||||
| ANSI.c:     ansicon.h version.h | ||||
| ANSI.rc:    version.h | ||||
| util.c:     ansicon.h version.h | ||||
| injdll32.c: ansicon.h | ||||
| injdll64.c: ansicon.h | ||||
| injdll.c:   ansicon.h | ||||
| proctype.c: ansicon.h | ||||
| LLW.c:	    ansicon.h | ||||
| 
 | ||||
| x64\ANSI32.obj: ANSI.c | ||||
| 	$(CCmsg)$(CC) /DW32ON64 /c $(CFLAGS) /Fo$@ $? | ||||
| 
 | ||||
| x64\proctype32.obj: proctype.c | ||||
| 	$(CCmsg)$(CC) /DW32ON64 /c $(CFLAGS) /Fo$@ $? | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										99
									
								
								proctype.c
									
									
									
									
									
								
							
							
						
						
									
										99
									
								
								proctype.c
									
									
									
									
									
								
							| @ -1,76 +1,76 @@ | ||||
| /*
 | ||||
|   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. | ||||
| 
 | ||||
|   Update: ignore images characterised as DLL. | ||||
|   Test for a valid process (i386 for x86; that or AMD64 for x64).  We can get | ||||
|   that info from the image header, which means getting the process's base | ||||
|   address (which we need anyway, to modify the imports).  The simplest way to | ||||
|   do that is to enumerate the pages, looking for an executable image. | ||||
| */ | ||||
| 
 | ||||
| #include "ansicon.h" | ||||
| 
 | ||||
| 
 | ||||
| int ProcessType( LPPROCESS_INFORMATION pinfo, BOOL* gui ) | ||||
| int ProcessType( LPPROCESS_INFORMATION ppi, PBYTE* pBase, BOOL* gui ) | ||||
| { | ||||
|   char* ptr; | ||||
|   PBYTE ptr; | ||||
|   MEMORY_BASIC_INFORMATION minfo; | ||||
|   IMAGE_DOS_HEADER dos_header; | ||||
|   IMAGE_NT_HEADERS nt_header; | ||||
|   SIZE_T read; | ||||
| 
 | ||||
|   *pBase = NULL; | ||||
|   *gui = FALSE; | ||||
| 
 | ||||
|   for (ptr = NULL; | ||||
|        VirtualQueryEx( pinfo->hProcess, ptr, &minfo, sizeof(minfo) ); | ||||
|        VirtualQueryEx( ppi->hProcess, ptr, &minfo, sizeof(minfo) ); | ||||
|        ptr += minfo.RegionSize) | ||||
|   { | ||||
|     if (minfo.BaseAddress == minfo.AllocationBase && | ||||
| 	ReadProcessMemory( pinfo->hProcess, minfo.AllocationBase, | ||||
| 			   &dos_header, sizeof(dos_header), &read )) | ||||
|     if (minfo.BaseAddress == minfo.AllocationBase | ||||
| 	&& ReadProcVar( minfo.BaseAddress, &dos_header ) | ||||
| 	&& dos_header.e_magic == IMAGE_DOS_SIGNATURE | ||||
| 	&& ReadProcVar( (PBYTE)minfo.BaseAddress + dos_header.e_lfanew, | ||||
| 			&nt_header ) | ||||
| 	&& nt_header.Signature == IMAGE_NT_SIGNATURE | ||||
| 	&& !(nt_header.FileHeader.Characteristics & IMAGE_FILE_DLL)) | ||||
|     { | ||||
|       if (dos_header.e_magic == IMAGE_DOS_SIGNATURE) | ||||
|       { | ||||
| 	if (ReadProcessMemory( pinfo->hProcess, (char*)minfo.AllocationBase + | ||||
| 			       dos_header.e_lfanew, &nt_header, | ||||
| 			       sizeof(nt_header), &read )) | ||||
| 	{ | ||||
| 	  if (nt_header.Signature == IMAGE_NT_SIGNATURE && | ||||
| 	      (nt_header.FileHeader.Characteristics & | ||||
| 			 (IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DLL)) | ||||
| 			 == IMAGE_FILE_EXECUTABLE_IMAGE) | ||||
| 	  { | ||||
| 	    *gui = (nt_header.OptionalHeader.Subsystem | ||||
| 			      == IMAGE_SUBSYSTEM_WINDOWS_GUI); | ||||
| 	    if (nt_header.OptionalHeader.Subsystem == | ||||
| 		IMAGE_SUBSYSTEM_WINDOWS_CUI || *gui) | ||||
|       // Don't load into ansicon.exe, it wants to do that itself.
 | ||||
|       if (nt_header.OptionalHeader.MajorImageVersion == 20033 && | ||||
| 	  nt_header.OptionalHeader.MinorImageVersion == 18771) | ||||
| 	return -1; | ||||
| 
 | ||||
|       *pBase = minfo.BaseAddress; | ||||
|       if (nt_header.OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI) | ||||
| 	*gui = TRUE; | ||||
|       if (*gui || | ||||
| 	  nt_header.OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI) | ||||
|       { | ||||
| 	if (nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_I386) | ||||
| 	{ | ||||
| 		// Microsoft ignores precision on %p.
 | ||||
| 	  DEBUGSTR( 1, L"  32-bit %s (base = %.8X)", | ||||
| 		    (*gui) ? L"GUI" : L"console", | ||||
| 			  (DWORD)(DWORD_PTR)minfo.AllocationBase ); | ||||
| 		    PtrToUint( minfo.BaseAddress ) ); | ||||
| 	  return 32; | ||||
| 	} | ||||
| 	if (nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64) | ||||
| 	{ | ||||
| #ifdef _WIN64 | ||||
| 	      if (nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64) | ||||
| 	      { | ||||
| 		DEBUGSTR( 1, L"  64-bit %s (base = %p)", | ||||
| 			  (*gui) ? L"GUI" : L"console", minfo.AllocationBase ); | ||||
| 	  DEBUGSTR( 1, L"  64-bit %s (base = %.8X_%.8X)", | ||||
| 		    (*gui) ? L"GUI" : L"console", | ||||
| 		    (DWORD)((DWORD_PTR)minfo.BaseAddress >> 32), | ||||
| 		    PtrToUint( minfo.BaseAddress ) ); | ||||
| 	  return 64; | ||||
| 	      } | ||||
| #elif defined(W32ON64) | ||||
| 	      if (nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64) | ||||
| 	      { | ||||
| 		DEBUGSTR( 1, L"  64-bit %s", | ||||
| 			  (*gui) ? L"GUI" : L"console" ); | ||||
| 	  // Console will log due to -P, but GUI may be ignored (if not,
 | ||||
| 	  // this'll show up twice).
 | ||||
| 	  if (*gui) | ||||
| 	    DEBUGSTR( 1, L"  64-bit GUI (base = 00000000_%.8X)", | ||||
| 		      PtrToUint( minfo.BaseAddress ) ); | ||||
| 	  return 64; | ||||
| 	      } | ||||
| #else | ||||
| 	  DEBUGSTR( 1, L"  64-bit %s (base = 00000000_%.8X)", | ||||
| 		    (*gui) ? L"GUI" : L"console", | ||||
| 		    PtrToUint( minfo.BaseAddress ) ); | ||||
| 	  DEBUGSTR( 1, L"  Unsupported (use x64\\ansicon)" ); | ||||
| 	  return 0; | ||||
| #endif | ||||
| 	} | ||||
| 	DEBUGSTR( 1, L"  Ignoring unsupported machine (0x%X)", | ||||
| 		  nt_header.FileHeader.Machine ); | ||||
|       } | ||||
| @ -81,19 +81,16 @@ int ProcessType( LPPROCESS_INFORMATION pinfo, BOOL* gui ) | ||||
|       } | ||||
|       return 0; | ||||
|     } | ||||
| 	} | ||||
|       } | ||||
|     } | ||||
| #ifndef _WIN64 | ||||
|     // If a 32-bit process loads a 64-bit one, we may miss the base
 | ||||
|     // address.  If the pointer overflows, assume 64-bit.
 | ||||
|     if (((DWORD)ptr >> 12) + ((DWORD)minfo.RegionSize >> 12) > 0x80000) | ||||
|     if (((DWORD)ptr >> 12) + ((DWORD)minfo.RegionSize >> 12) >= 0x100000) | ||||
|     { | ||||
| #ifdef W32ON64 | ||||
|       DEBUGSTR( 1, L"  Pointer overflow: assuming 64-bit console" ); | ||||
|       DEBUGSTR( 1, L"  Pointer overflow: assuming 64-bit" ); | ||||
|       return 64; | ||||
| #else | ||||
|       DEBUGSTR( 1, L"  Ignoring apparent 64-bit process" ); | ||||
|       DEBUGSTR( 1, L"  Ignoring apparent 64-bit process (use x64\\ansicon)" ); | ||||
|       return 0; | ||||
| #endif | ||||
|     } | ||||
|  | ||||
							
								
								
									
										38
									
								
								readme.txt
									
									
									
									
									
								
							
							
						
						
									
										38
									
								
								readme.txt
									
									
									
									
									
								
							| @ -1,9 +1,9 @@ | ||||
| 
 | ||||
| 				    ANSICON | ||||
| 
 | ||||
| 			 Copyright 2005-2013 Jason Hood | ||||
| 			 Copyright 2005-2014 Jason Hood | ||||
| 
 | ||||
| 			    Version 1.66.  Freeware | ||||
| 			    Version 1.70.  Freeware | ||||
| 
 | ||||
| 
 | ||||
| Description | ||||
| @ -17,7 +17,7 @@ Requirements | ||||
| ============ | ||||
| 
 | ||||
|     32-bit: Windows 2000 Professional and later (it won't work with NT or 9X). | ||||
|     64-bit: Vista and later (it won't work with XP64). | ||||
|     64-bit: AMD64 (IA64 could work with a little modification). | ||||
| 
 | ||||
| 
 | ||||
| Installation | ||||
| @ -93,10 +93,10 @@ Usage | ||||
|        16	Log all imported modules (add to any of the above) | ||||
| 
 | ||||
|     The log option will not work with '-p'; set the environment variable | ||||
|     ANSICON_LOG instead.  The variable is only read once when a new process is | ||||
|     started; changing it won't affect running processes.  If you identify a | ||||
|     module that causes problems, add it to the ANSICON_EXC environment variable | ||||
|     (see ANSICON_API below, but the extension is required). | ||||
|     ANSICON_LOG (to the number) instead.  The variable is only read once when a | ||||
|     process is started; changing it won't affect running processes.  If you | ||||
|     identify a module that causes problems, add it to the ANSICON_EXC environ- | ||||
|     ment variable (see ANSICON_API below, but the extension is required). | ||||
| 
 | ||||
|     E.g.: 'ansicon -l5' will start a new command processor, logging every pro- | ||||
|     cess it starts along with their output. | ||||
| @ -264,12 +264,26 @@ Limitations | ||||
| 
 | ||||
| 	ANSICON_EXC=nvd3d9wrap.dll;nvd3d9wrapx.dll | ||||
| 
 | ||||
|     An application using multiple screen buffers will not have separate | ||||
|     attributes in each buffer. | ||||
| 
 | ||||
| 
 | ||||
| Version History | ||||
| =============== | ||||
| 
 | ||||
|     Legend: + added, - bug-fixed, * changed. | ||||
| 
 | ||||
|     1.70 - 4 February, 2014: | ||||
|     - don't hook again if using LoadLibrary or LoadLibraryEx; | ||||
|     - update the LoadLibraryEx flags that shouldn't hook; | ||||
|     - restore original attributes on detach (for LoadLibrary/FreeLibrary usage); | ||||
|     - ansicon.exe will start with ANSICON_DEF (if defined and -m not used); | ||||
|     - an installed ansicon.exe will restore current (not default) attributes; | ||||
|     * inject into a created process by modifying the import descriptor table | ||||
|       (use CreateRemoteThread for -p); | ||||
|     * log: remove the quotes around the CreateProcess command line; | ||||
| 	   add an underscore in 64-bit addresses to distinguish 8-digit groups. | ||||
| 
 | ||||
|     1.66 - 20 September, 2013: | ||||
|     - fix 32-bit process trying to detect 64-bit process. | ||||
| 
 | ||||
| @ -442,12 +456,6 @@ Contact | ||||
|     http://ansicon.adoxa.vze.com/ | ||||
|     https://github.com/adoxa/ansicon | ||||
| 
 | ||||
|     Jason Hood | ||||
|     11 Buckle Street | ||||
|     North Rockhampton | ||||
|     Qld 4701 | ||||
|     Australia | ||||
| 
 | ||||
| 
 | ||||
| Distribution | ||||
| ============ | ||||
| @ -461,5 +469,5 @@ Distribution | ||||
|     in LICENSE.txt. | ||||
| 
 | ||||
| 
 | ||||
| =============================== | ||||
| Jason Hood, 20 September, 2013. | ||||
| ============================= | ||||
| Jason Hood, 4 February, 2014. | ||||
|  | ||||
							
								
								
									
										50
									
								
								util.c
									
									
									
									
									
								
							
							
						
						
									
										50
									
								
								util.c
									
									
									
									
									
								
							| @ -8,9 +8,14 @@ | ||||
| 
 | ||||
| TCHAR	prog_path[MAX_PATH]; | ||||
| LPTSTR	prog; | ||||
| 
 | ||||
| int	log_level; | ||||
| char	tempfile[MAX_PATH]; | ||||
| DWORD	pid; | ||||
| 
 | ||||
| char	ansi_dll[MAX_PATH]; | ||||
| DWORD	ansi_len; | ||||
| #ifdef _WIN64 | ||||
| char*	ansi_bits; | ||||
| #endif | ||||
| 
 | ||||
| 
 | ||||
| // Get just the name of the program: "C:\path\program.exe" -> "program".
 | ||||
| @ -37,8 +42,46 @@ LPTSTR get_program_name( LPTSTR program ) | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| // Get the ANSI path of the DLL for the import.  If it can't be converted,
 | ||||
| // just use the name and hope it's on the PATH.  Returns the length of the
 | ||||
| // path/name, including padding to make it dword-aligned.  The 64-bit version
 | ||||
| // expects ansi_bits to point to the size within dll on entry.
 | ||||
| void set_ansi_dll( LPTSTR dll ) | ||||
| { | ||||
|   BOOL bad; | ||||
| 
 | ||||
|   ansi_len = WideCharToMultiByte( CP_ACP, WC_NO_BEST_FIT_CHARS, dll, -1, | ||||
| 				  NULL, 0, NULL, &bad ); | ||||
|   if (bad || ansi_len > MAX_PATH) | ||||
|   { | ||||
|     ansi_len = 12; | ||||
|     memcpy( ansi_dll, "ANSI32.dll\0", 12 ); | ||||
| #ifdef _WIN64 | ||||
|     if (*ansi_bits == '6') | ||||
|     { | ||||
|       ansi_dll[4] = '6'; | ||||
|       ansi_dll[5] = '4'; | ||||
|     } | ||||
|     ansi_bits = ansi_dll + 4; | ||||
| #endif | ||||
|   } | ||||
|   else | ||||
|   { | ||||
|     WideCharToMultiByte( CP_ACP, WC_NO_BEST_FIT_CHARS, dll, -1, | ||||
| 			 ansi_dll, MAX_PATH, NULL, NULL ); | ||||
| #ifdef _WIN64 | ||||
|     ansi_bits = ansi_dll + ansi_len - 7; | ||||
| #endif | ||||
|     ansi_len = (ansi_len + 3) & ~3; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void DEBUGSTR( int level, LPTSTR szFormat, ... ) | ||||
| { | ||||
|   static char  tempfile[MAX_PATH]; | ||||
|   static DWORD pid; | ||||
| 
 | ||||
|   TCHAR   szBuffer[1024], szEscape[1024]; | ||||
|   va_list pArgList; | ||||
|   HANDLE  mutex; | ||||
| @ -55,6 +98,7 @@ void DEBUGSTR( int level, LPTSTR szFormat, ... ) | ||||
|   } | ||||
|   if (szFormat == NULL) | ||||
|   { | ||||
|     // Explicitly use 't', as _fmode might be binary.
 | ||||
|     file = fopen( tempfile, (log_level & 8) ? "at" : "wt" ); | ||||
|     if (file != NULL) | ||||
|     { | ||||
| @ -116,7 +160,7 @@ void DEBUGSTR( int level, LPTSTR szFormat, ... ) | ||||
| 
 | ||||
|   mutex = CreateMutex( NULL, FALSE, L"ANSICON_debug_file" ); | ||||
|   wait	= WaitForSingleObject( mutex, 500 ); | ||||
|   file	= fopen( tempfile, "at" ); // _fmode might be binary
 | ||||
|   file	= fopen( tempfile, "at" ); | ||||
|   if (file != NULL) | ||||
|   { | ||||
|     fwprintf( file, L"%s (%lu): %s\n", prog, pid, szFormat ); | ||||
|  | ||||
							
								
								
									
										10
									
								
								version.h
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								version.h
									
									
									
									
									
								
							| @ -2,11 +2,11 @@ | ||||
|   version.h - Version defines. | ||||
| */ | ||||
| 
 | ||||
| #define PVERS	L"1.67"         // wide string
 | ||||
| #define PVERSA	 "1.67"         // ANSI string (windres 2.16.91 didn't like L)
 | ||||
| #define PVERE	L"167"          // wide environment string
 | ||||
| #define PVEREA	 "167"          // ANSI environment string
 | ||||
| #define PVERB	1,6,7,0 	// binary (resource)
 | ||||
| #define PVERS	L"1.70"         // wide string
 | ||||
| #define PVERSA	 "1.70"         // ANSI string (windres 2.16.91 didn't like L)
 | ||||
| #define PVERE	L"170"          // wide environment string
 | ||||
| #define PVEREA	 "170"          // ANSI environment string
 | ||||
| #define PVERB	1,7,0,0 	// binary (resource)
 | ||||
| 
 | ||||
| #ifdef _WIN64 | ||||
| # define BITS L"64" | ||||
|  | ||||
							
								
								
									
										88
									
								
								wow64.h
									
									
									
									
									
								
							
							
						
						
									
										88
									
								
								wow64.h
									
									
									
									
									
								
							| @ -1,88 +0,0 @@ | ||||
| /*
 | ||||
|   wow64.h - Definitions for Wow64. | ||||
| 
 | ||||
|   The 2003 Platform SDK does not include these Wow64 definitions. | ||||
| */ | ||||
| 
 | ||||
| #ifndef WOW64_H | ||||
| #define WOW64_H | ||||
| 
 | ||||
| #define WIN32_LEAN_AND_MEAN | ||||
| #include <windows.h> | ||||
| 
 | ||||
| #define WOW64_CONTEXT_i386	0x00010000 | ||||
| 
 | ||||
| #define WOW64_CONTEXT_CONTROL		    (WOW64_CONTEXT_i386 | 0x00000001L) | ||||
| #define WOW64_CONTEXT_INTEGER		    (WOW64_CONTEXT_i386 | 0x00000002L) | ||||
| #define WOW64_CONTEXT_SEGMENTS		    (WOW64_CONTEXT_i386 | 0x00000004L) | ||||
| #define WOW64_CONTEXT_FLOATING_POINT	    (WOW64_CONTEXT_i386 | 0x00000008L) | ||||
| #define WOW64_CONTEXT_DEBUG_REGISTERS	    (WOW64_CONTEXT_i386 | 0x00000010L) | ||||
| #define WOW64_CONTEXT_EXTENDED_REGISTERS    (WOW64_CONTEXT_i386 | 0x00000020L) | ||||
| 
 | ||||
| #define WOW64_CONTEXT_FULL      (WOW64_CONTEXT_CONTROL | WOW64_CONTEXT_INTEGER | WOW64_CONTEXT_SEGMENTS) | ||||
| 
 | ||||
| #define WOW64_CONTEXT_ALL       (WOW64_CONTEXT_CONTROL | WOW64_CONTEXT_INTEGER | WOW64_CONTEXT_SEGMENTS | \ | ||||
|                                  WOW64_CONTEXT_FLOATING_POINT | WOW64_CONTEXT_DEBUG_REGISTERS | \ | ||||
|                                  WOW64_CONTEXT_EXTENDED_REGISTERS) | ||||
| 
 | ||||
| #define WOW64_SIZE_OF_80387_REGISTERS      80 | ||||
| 
 | ||||
| #define WOW64_MAXIMUM_SUPPORTED_EXTENSION     512 | ||||
| 
 | ||||
| typedef struct _WOW64_FLOATING_SAVE_AREA { | ||||
|     DWORD   ControlWord; | ||||
|     DWORD   StatusWord; | ||||
|     DWORD   TagWord; | ||||
|     DWORD   ErrorOffset; | ||||
|     DWORD   ErrorSelector; | ||||
|     DWORD   DataOffset; | ||||
|     DWORD   DataSelector; | ||||
|     BYTE    RegisterArea[WOW64_SIZE_OF_80387_REGISTERS]; | ||||
|     DWORD   Cr0NpxState; | ||||
| } WOW64_FLOATING_SAVE_AREA; | ||||
| 
 | ||||
| typedef WOW64_FLOATING_SAVE_AREA *PWOW64_FLOATING_SAVE_AREA; | ||||
| 
 | ||||
| typedef struct _WOW64_CONTEXT { | ||||
| 
 | ||||
|     DWORD ContextFlags; | ||||
| 
 | ||||
|     DWORD   Dr0; | ||||
|     DWORD   Dr1; | ||||
|     DWORD   Dr2; | ||||
|     DWORD   Dr3; | ||||
|     DWORD   Dr6; | ||||
|     DWORD   Dr7; | ||||
| 
 | ||||
|     WOW64_FLOATING_SAVE_AREA FloatSave; | ||||
| 
 | ||||
|     DWORD   SegGs; | ||||
|     DWORD   SegFs; | ||||
|     DWORD   SegEs; | ||||
|     DWORD   SegDs; | ||||
| 
 | ||||
|     DWORD   Edi; | ||||
|     DWORD   Esi; | ||||
|     DWORD   Ebx; | ||||
|     DWORD   Edx; | ||||
|     DWORD   Ecx; | ||||
|     DWORD   Eax; | ||||
| 
 | ||||
|     DWORD   Ebp; | ||||
|     DWORD   Eip; | ||||
|     DWORD   SegCs; | ||||
|     DWORD   EFlags; | ||||
|     DWORD   Esp; | ||||
|     DWORD   SegSs; | ||||
| 
 | ||||
|     BYTE    ExtendedRegisters[WOW64_MAXIMUM_SUPPORTED_EXTENSION]; | ||||
| 
 | ||||
| } WOW64_CONTEXT; | ||||
| 
 | ||||
| typedef WOW64_CONTEXT *PWOW64_CONTEXT; | ||||
| 
 | ||||
| 
 | ||||
| typedef BOOL (WINAPI *TWow64GetThreadContext)( HANDLE hThread, PWOW64_CONTEXT lpContext ); | ||||
| typedef BOOL (WINAPI *TWow64SetThreadContext)( HANDLE hThread, CONST WOW64_CONTEXT *lpContext ); | ||||
| 
 | ||||
| #endif | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Jason Hood
						Jason Hood