From a52a46c9c19930402f734bcd26ccd806b23ba74c Mon Sep 17 00:00:00 2001 From: Jason Hood Date: Sat, 24 Nov 2012 23:41:29 +1000 Subject: [PATCH] New method to obtain 32-bit LoadLibraryW from 64-bit code, eliminating the need for ANSI-LLW.exe. Set the code page so ansicon.exe can display some strings properly. Expand wildcards for -t. VC6 can now compile the 32-bit version; use it for the release binaries. Improvements to the VC makefile. Describe the sequences in a bit more detail. --- ANSI-LLW.c | 22 -------- ANSI.c | 20 +++++--- ansicon.c | 133 ++++++++++++++++++++++++++++++++++++++++++++---- ansicon.h | 4 ++ injdll32.c | 137 ++++++++++++++++++++++++++++++++++++++------------ makefile | 14 +++--- makefile.vc | 49 ++++++++++++------ readme.txt | 25 ++++++--- sequences.txt | 118 +++++++++++++++++++++++++++++++++++++++++++ util.c | 2 +- version.h | 10 ++-- wow64.h | 2 +- 12 files changed, 431 insertions(+), 105 deletions(-) delete mode 100644 ANSI-LLW.c create mode 100644 sequences.txt diff --git a/ANSI-LLW.c b/ANSI-LLW.c deleted file mode 100644 index 28991f0..0000000 --- a/ANSI-LLW.c +++ /dev/null @@ -1,22 +0,0 @@ -/* - ANSI-LLW.c - Output the 32-bit address of LoadLibraryW. - - Jason Hood, 13 November, 2010 (LLA version 5 September, 2010). - - 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 -#include - -int main( void ) -{ - return (DWORD)GetProcAddress( GetModuleHandle( "kernel32.dll" ), - "LoadLibraryW" ); -} diff --git a/ANSI.c b/ANSI.c index 3907252..9673d55 100644 --- a/ANSI.c +++ b/ANSI.c @@ -91,18 +91,23 @@ v1.53, 12 June, 2012: fixed Update_GRM when running multiple processes (e.g. "cl /MP"). + + v1.60, 22 to 24 November, 2012: + alternative method to obtain LLW for 64->32 injection; + support for VC6 (remove section pragma, rename isdigit to is_digit). */ #include "ansicon.h" #include "version.h" #include -#define isdigit(c) ('0' <= (c) && (c) <= '9') +#define is_digit(c) ('0' <= (c) && (c) <= '9') #ifdef __GNUC__ -#define SHARED __attribute__((shared, section(".share"))) +#define SHARED __attribute__((shared, section(".shared"))) #else -#pragma section(".shared", read,write,shared) +#pragma data_seg(".shared", "read,write,shared") +#pragma data_seg() #define SHARED __declspec(allocate(".shared")) #endif @@ -228,6 +233,9 @@ SHARED DWORD s_flag; #define GRM_INIT 1 #define GRM_EXIT 2 +#ifdef _WIN64 +SHARED DWORD LLW32; +#endif // Wait for the child process to finish, then update our GRM to the child's. @@ -846,7 +854,7 @@ ParseAndPrintString( HANDLE hDev, } else if (state == 3) { - if (isdigit( *s )) + if (is_digit( *s )) { es_argc = 0; es_argv[0] = *s - '0'; @@ -873,7 +881,7 @@ ParseAndPrintString( HANDLE hDev, } else if (state == 4) { - if (isdigit( *s )) + if (is_digit( *s )) { es_argv[es_argc] = 10 * es_argv[es_argc] + (*s - '0'); } @@ -1775,7 +1783,7 @@ void OriginalAttr( void ) // and terminated. //----------------------------------------------------------------------------- -__declspec(dllexport) // to stop MinGW exporting everything +__declspec(dllexport) // just to stop MinGW exporting everything BOOL WINAPI DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved ) { BOOL bResult = TRUE; diff --git a/ansicon.c b/ansicon.c index 2b87abe..51bb144 100644 --- a/ansicon.c +++ b/ansicon.c @@ -64,15 +64,21 @@ v1.52, 10 April, 2012: fixed running "cmd" if "ComSpec" is not defined; pass process & thread identifiers on the command line (for x86->x64). + + v1.60, 22 & 24 November, 2012: + set the code page to convert strings correctly; + expand wildcards for -t; + write the date if appending to the log. */ -#define PDATE L"12 June, 2012" +#define PDATE L"24 November, 2012" #include "ansicon.h" #include "version.h" #include #include #include +#include #ifdef __MINGW32__ int _CRT_glob = 0; @@ -96,6 +102,7 @@ void display( LPCTSTR, BOOL ); void print_error( LPCTSTR, ... ); LPTSTR skip_spaces( LPTSTR ); void get_arg( LPTSTR, LPTSTR*, LPTSTR* ); +void get_file( LPTSTR, LPTSTR*, LPTSTR* ); void process_autorun( TCHAR ); @@ -103,6 +110,12 @@ 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. +#ifdef _WIN64 +DWORD LLW32; +#endif + + // Find the name of the DLL and inject it. BOOL Inject( LPPROCESS_INFORMATION ppi, BOOL* gui, LPCTSTR app ) { @@ -199,6 +212,10 @@ int main( void ) 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 ); + #ifdef _WIN64 if (*arg == '-' && arg[1] == 'P') { @@ -212,8 +229,8 @@ int main( void ) } #endif - if (log_level && !(log_level & 8)) - DEBUGSTR( 1, NULL ); // create a new file + 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 @@ -235,8 +252,7 @@ int main( void ) case 'l': SetEnvironmentVariable( L"ANSICON_LOG", arg + 2 ); log_level = _wtoi( arg + 2 ); - if (!(log_level & 8)) // unless told otherwise - DEBUGSTR( 1, NULL ); // create a new file + DEBUGSTR( 1, NULL ); // create a session break; case 'i': @@ -285,7 +301,7 @@ int main( void ) a = -a; a = ((a >> 4) & 15) | ((a & 15) << 4); } - SetConsoleTextAttribute( hConOut, a ); + SetConsoleTextAttribute( hConOut, (WORD)a ); SetEnvironmentVariable( L"ANSICON_DEF", NULL ); break; } @@ -316,14 +332,14 @@ arg_out: { if (*cmd == '\0') { - cmd = _wgetenv( L"ComSpec" ); - if (cmd == NULL) + if (GetEnvironmentVariable( L"ComSpec", arg, MAX_PATH )) + cmd = arg; + else { // CreateProcessW writes to the string, so can't simply point to "cmd". static TCHAR cmdstr[] = L"cmd"; cmd = cmdstr; } - arg = cmd; } ZeroMemory( &si, sizeof(si) ); @@ -369,7 +385,7 @@ arg_out: else // (*arg == 't' || *arg == 'T') { BOOL title = (*arg == 'T'); - get_arg( arg, &argv, &cmd ); + get_file( arg, &argv, &cmd ); if (*arg == '\0') wcscpy( arg, L"-" ); do @@ -382,7 +398,7 @@ arg_out: } else display( arg, title ); - get_arg( arg, &argv, &cmd ); + get_file( arg, &argv, &cmd ); } while (*arg); } @@ -650,6 +666,101 @@ void get_arg( LPTSTR arg, LPTSTR* argv, LPTSTR* cmd ) } +int glob_sort( const void* a, const void* b ) +{ + return lstrcmpi( *(LPCTSTR*)a, *(LPCTSTR*)b ); +} + + +// As get_arg, but expand wildcards. +void get_file( LPTSTR arg, LPTSTR* argv, LPTSTR* cmd ) +{ + HANDLE fh, in; + WIN32_FIND_DATA fd; + LPTSTR path; + int size; + char buf[1024]; + static LPTSTR name; + static LPTSTR* glob; + static int globbed; + + if (globbed != 0) + { + if (glob[globbed] == NULL) + { + free( glob ); + globbed = 0; + } + else + { + wcscpy( name, glob[globbed++] ); + return; + } + } + + get_arg( arg, argv, cmd ); + if (wcspbrk( arg, L"*?" ) != NULL) + { + fh = FindFirstFile( arg, &fd ); + if (fh != INVALID_HANDLE_VALUE) + { + size = 0; + do + { + if (! (fd.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY | + FILE_ATTRIBUTE_HIDDEN))) + { + ++globbed; + size += (int)wcslen( fd.cFileName ) + 1; + } + } while (FindNextFile( fh, &fd )); + FindClose( fh ); + + if (globbed != 0) + { + for (path = name = arg; *path != '\0'; ++path) + if (*path == '\\' || *path == '/') + name = path + 1; + glob = malloc( (globbed + 1) * sizeof(LPTSTR) + TSIZE(size) ); + path = (LPTSTR)(glob + globbed + 1); + globbed = 0; + fh = FindFirstFile( arg, &fd ); + do + { + if (! (fd.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY | + FILE_ATTRIBUTE_HIDDEN))) + { + // Ignore apparent binary files. + wcscpy( name, fd.cFileName ); + in = CreateFile( arg, GENERIC_READ, + FILE_SHARE_READ|FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, 0, NULL ); + if (in != INVALID_HANDLE_VALUE) + { + ReadFile( in, buf, sizeof(buf), (LPVOID)&size, NULL ); + CloseHandle( in ); + if (memchr( buf, 0, size ) != NULL) + continue; + } + size = (int)wcslen( fd.cFileName ) + 1; + memcpy( path, fd.cFileName, TSIZE(size) ); + glob[globbed++] = path; + path += size; + } + } while (FindNextFile( fh, &fd )); + FindClose( fh ); + glob[globbed] = NULL; + + qsort( glob, globbed, sizeof(LPTSTR), glob_sort ); + + wcscpy( name, glob[0] ); + globbed = 1; + } + } + } +} + + void help( void ) { _putws( diff --git a/ansicon.h b/ansicon.h index 8819186..4e07db5 100644 --- a/ansicon.h +++ b/ansicon.h @@ -12,7 +12,11 @@ #endif #define WIN32_LEAN_AND_MEAN +#ifdef _WIN64 +#define _WIN32_WINNT 0x0600 // MinGW-w64 wants this defined for Wow64 stuff +#else #define _WIN32_WINNT 0x0500 // MinGW wants this defined for OpenThread +#endif #include #include #include diff --git a/injdll32.c b/injdll32.c index 25ed7ae..c62b10b 100644 --- a/injdll32.c +++ b/injdll32.c @@ -18,11 +18,12 @@ #include "ansicon.h" #ifdef _WIN64 -#if defined(__MINGW64__) || (defined(_MSC_VER) && _MSC_VER <= 1400) +#ifndef WOW64_CONTEXT_ALL #include "wow64.h" TWow64GetThreadContext Wow64GetThreadContext; TWow64SetThreadContext Wow64SetThreadContext; +#define IMPORT_WOW64 #endif #define CONTEXT WOW64_CONTEXT @@ -30,12 +31,99 @@ TWow64SetThreadContext Wow64SetThreadContext; #define CONTEXT_CONTROL WOW64_CONTEXT_CONTROL #define GetThreadContext Wow64GetThreadContext #define SetThreadContext Wow64SetThreadContext + +#define MakeVA( cast, offset ) (cast)((DWORD_PTR)base + (DWORD)(offset)) + +extern DWORD LLW32; +LPVOID base; + +int export_cmp( const void* a, const void* b ) +{ + return strcmp( (LPCSTR)a, MakeVA( LPCSTR, *(const PDWORD)b ) ); +} + + +/* + Get the address of the 32-bit LoadLibraryW function from 64-bit code. This + was originally done via executing a helper program (ANSI-LLW.exe), but for + some reason, virus scanners really didn't like it (even when I rewrote it in + assembly so it was 1024 bytes and literally two instructions, virustotal + still had three scanners complaining). Now I do it the "hard" way - load the + 32-bit kernel32.dll directly and search the exports. Even worse, it seems + Wow64 loads kernel32.dll at a different base address each boot (at least, I + hope it only changes each boot). Fortunately, loading the DLL as an image in + 64-bit code seems to use the 32-bit address. +*/ +BOOL get_LLW32( void ) +{ + HMODULE kernel32; + TCHAR buf[MAX_PATH]; + UINT len; + PIMAGE_DOS_HEADER pDosHeader; + PIMAGE_NT_HEADERS32 pNTHeader; + PIMAGE_EXPORT_DIRECTORY pExportDir; + PDWORD fun_table, name_table; + PWORD ord_table; + PDWORD pLLW; + + len = GetSystemWow64Directory( buf, MAX_PATH ); + wcscpy( buf + len, L"\\kernel32.dll" ); + // MinGW-w64 has a typo, calling it LINRARY. + kernel32 = LoadLibraryEx( buf, NULL, 0x20/*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. + base = (LPVOID)((DWORD_PTR)kernel32 & 0xFFFF0000); + + // Tests to make sure we're looking at a module image (the 'MZ' header) + pDosHeader = (PIMAGE_DOS_HEADER)base; + if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) + { + DEBUGSTR( 1, L"Image has no DOS header!" ); + return FALSE; + } + + // The MZ header has a pointer to the PE header + pNTHeader = MakeVA( PIMAGE_NT_HEADERS32, pDosHeader->e_lfanew ); + + // One more test to make sure we're looking at a "PE" image + if (pNTHeader->Signature != IMAGE_NT_SIGNATURE) + { + DEBUGSTR( 1, L"Image has no NT header!" ); + return FALSE; + } + + // We now have a valid pointer to the module's PE header. + // Get a pointer to its exports section. + 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!" ); + return FALSE; + } + LLW32 = MakeVA( DWORD, fun_table[ord_table[pLLW - name_table]] ); + + FreeLibrary( kernel32 ); + return TRUE; +} +#else +DWORD LLW32; #endif -DWORD LLW; - - void InjectDLL32( LPPROCESS_INFORMATION ppi, LPCTSTR dll ) { CONTEXT context; @@ -54,12 +142,21 @@ void InjectDLL32( LPPROCESS_INFORMATION ppi, LPCTSTR dll ) if (len > TSIZE(MAX_PATH)) return; - if (LLW == 0) + if (LLW32 == 0) { - HMODULE hKernel = GetModuleHandleA( "kernel32.dll" ); #ifdef _WIN64 -#ifdef __MINGW64__ + if (!get_LLW32()) + return; +#else + LLW32 = (DWORD)GetProcAddress( GetModuleHandleA( "kernel32.dll" ), + "LoadLibraryW" ); +#endif + } +#ifdef IMPORT_WOW64 + if (Wow64GetThreadContext == 0) + { #define GETPROC( proc ) proc = (T##proc)GetProcAddress( hKernel, #proc ) + HMODULE hKernel = GetModuleHandleA( "kernel32.dll" ); GETPROC( Wow64GetThreadContext ); GETPROC( Wow64SetThreadContext ); // Assume if one is defined, so is the other. @@ -68,30 +165,8 @@ void InjectDLL32( LPPROCESS_INFORMATION ppi, LPCTSTR dll ) DEBUGSTR( 1, L"Failed to get pointer to Wow64GetThreadContext.\n" ); return; } -#endif - - STARTUPINFO si; - PROCESS_INFORMATION pi; - ZeroMemory( &si, sizeof(si) ); - si.cb = sizeof(si); - // ...ANSI32.dll\0 - CopyMemory( code, dll, len - TSIZE(7) ); - // ...ANSI-LLW.exe\0 - CopyMemory( code + len - TSIZE(7), L"-LLW.exe", TSIZE(9) ); - if (!CreateProcess( (LPCTSTR)code, NULL, NULL, NULL, FALSE, 0, NULL, NULL, - &si, &pi )) - { - DEBUGSTR( 1, L"Failed to execute \"%s\".\n", (LPCTSTR)code ); - return; - } - WaitForSingleObject( pi.hProcess, INFINITE ); - GetExitCodeProcess( pi.hProcess, &LLW ); - CloseHandle( pi.hProcess ); - CloseHandle( pi.hThread ); -#else - LLW = (DWORD)GetProcAddress( hKernel, "LoadLibraryW" ); -#endif } +#endif CopyMemory( code + CODESIZE, dll, len ); len += CODESIZE; @@ -111,7 +186,7 @@ void InjectDLL32( LPPROCESS_INFORMATION ppi, LPCTSTR dll ) *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.pL++ = LLW32 - (mem32 + (DWORD)(ip.pB+4 - code)); *ip.pB++ = 0x61; // popa *ip.pB++ = 0x9d; // popf *ip.pB++ = 0xc3; // ret diff --git a/makefile b/makefile index 0007bee..b12f961 100644 --- a/makefile +++ b/makefile @@ -10,6 +10,9 @@ # # 13 December, 2011: # use CMD for file operations, not programs from fileutils. +# +# 23 November, 2012: +# set the base address of the DLLs to AC0000[00] (AnsiCon). CC = gcc CFLAGS = -O2 -Wall @@ -33,7 +36,7 @@ all: ansicon32 ansicon64 ansicon32: x86 x86/ansicon.exe x86/ANSI32.dll -ansicon64: x64 x64/ansicon.exe x64/ANSI64.dll x64/ANSI32.dll x64/ANSI-LLW.exe +ansicon64: x64 x64/ansicon.exe x64/ANSI64.dll x64/ANSI32.dll x86: cmd /c "mkdir x86" @@ -42,7 +45,7 @@ x86/ansicon.exe: x86/ansicon.o $(X86OBJS) x86/ansiconv.o $(CC) -m32 $+ -s -o $@ x86/ANSI32.dll: x86/ANSI.o $(X86OBJS) x86/ansiv.o - $(CC) -m32 $+ -s -o $@ -mdll -Wl,-shared + $(CC) -m32 $+ -s -o $@ -mdll -Wl,-shared,--image-base,0xAC0000 x64: cmd /c "mkdir x64" @@ -51,13 +54,10 @@ x64/ansicon.exe: x64/ansicon.o $(X64OBJS) x64/ansiconv.o $(CC) -m64 $+ -s -o $@ x64/ANSI64.dll: x64/ANSI.o $(X64OBJS) x64/ansiv.o - $(CC) -m64 $+ -s -o $@ -mdll -Wl,-shared + $(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 - $(CC) -m32 $+ -s -o $@ -mdll -Wl,-shared - -x64/ANSI-LLW.exe: ANSI-LLW.c - $(CC) -m32 $(CFLAGS) $< -s -o $@ + $(CC) -m32 $+ -s -o $@ -mdll -Wl,-shared,--image-base,0xAC0000 x86/ansicon.o: version.h x86/ANSI.o: version.h diff --git a/makefile.vc b/makefile.vc index da71872..77a8328 100644 --- a/makefile.vc +++ b/makefile.vc @@ -7,12 +7,22 @@ # 64-bit version still requires the 32-bit ANSI32.dll, so both environments # are required and you should build the 32-bit version before the 64-bit. +# 22 & 23 November, 2012: +# determine if the PSDK is used automatically; +# use AC0000[00] (AnsiCon) as the base address; +# twiddle stuff around to support VC6 (with 2003 PSDK) for the 32-bit version; +# determine BITS automatically. + #BITS = 32 #BITS = 64 !IFNDEF BITS +!IF "$(CPU)" == "AMD64" || "$(PLATFORM)" == "x64" +BITS = 64 +!ELSE BITS = 32 !ENDIF +!ENDIF !IF $(BITS) == 32 DIR = x86 @@ -24,12 +34,23 @@ DIR = x64 !ENDIF !ENDIF -CC = cl -CFLAGS = /nologo /W3 /Ox /GF /D_CRT_SECURE_NO_WARNINGS -LIBS = advapi32.lib user32.lib - # This is required for the 2003 Platform SDK, but not for Visual Studio 2010. -#LIBS64 = bufferoverflowu.lib +!IF "$(_NMAKE_VER)" == "7.00.8882" +LIBS64 = bufferoverflowu.lib +# The 2003 Toolkit doesn't have MSVCRT.LIB (but VC98 does). +!IF $(BITS) == 32 && !DEFINED(SHARE) && !DEFINED(MSVCDIR) +SHARE = +!ENDIF +!ENDIF + +# Link with MSVCRT.LIB by default. +!IFNDEF SHARE +SHARE = /MD +!ENDIF + +CC = cl +CFLAGS = /nologo /W3 /Ox /GF $(SHARE) /D_CRT_SECURE_NO_WARNINGS +LIBS = advapi32.lib user32.lib X86OBJS = x86\proctype.obj x86\injdll32.obj x86\util.obj X64OBJS = x64\proctype.obj x64\injdll64.obj x64\injdll32.obj x64\util.obj @@ -44,31 +65,28 @@ all: ansicon$(BITS) ansicon32: x86 x86\ansicon.exe x86\ANSI32.dll x64\ANSI32.dll -ansicon64: x64 x64\ansicon.exe x64\ANSI64.dll x64\ANSI-LLW.exe +ansicon64: x64 x64\ansicon.exe x64\ANSI64.dll x86: mkdir x86 x86\ansicon.exe: x86\ansicon.obj $(X86OBJS) x86\ansicon.res - $(CC) /nologo /Fe$@ $** $(LIBS) + $(CC) /nologo $(SHARE) /Fe$@ $** $(LIBS) /link /filealign:512 x86\ANSI32.dll: x86\ANSI.obj $(X86OBJS) x86\ansi.res - $(CC) /nologo /LD /Fe$@ $** $(LIBS) + $(CC) /nologo $(SHARE) /LD /Fe$@ $** $(LIBS) /link /base:0xAC0000 /section:.shared,s /filealign:512 x64: mkdir x64 x64\ansicon.exe: x64\ansicon.obj $(X64OBJS) x64\ansicon.res - $(CC) /nologo /Fe$@ $** $(LIBS) $(LIBS64) + $(CC) /nologo $(SHARE) /Fe$@ $** $(LIBS) $(LIBS64) x64\ANSI64.dll: x64\ANSI.obj $(X64OBJS) x64\ansi.res - $(CC) /nologo /LD /Fe$@ $** $(LIBS) $(LIBS64) + $(CC) /nologo $(SHARE) /LD /Fe$@ $** $(LIBS) $(LIBS64) /link /base:0xAC000000 /section:.shared,s x64\ANSI32.dll: x64\ANSI32.obj x64\proctype32.obj x86\injdll32.obj x86\util.obj x86\ansi.res - $(CC) /nologo /LD /Fe$@ $** $(LIBS) - -x64\ANSI-LLW.exe: ANSI-LLW.c - $(CC) $(CFLAGS) /Fe$@ /Fo$*.obj $? $(LIBS64) + $(CC) /nologo $(SHARE) /LD /Fe$@ $** $(LIBS) /link /base:0xAC0000 /section:.shared,s /filealign:512 ansicon.c: ansicon.h version.h ansicon.rc: version.h @@ -86,3 +104,6 @@ x64\proctype32.obj: proctype.c clean: -del $(DIR)\*.obj $(DIR)\*.res $(DIR)\*.lib $(DIR)\*.exp +!IF $(BITS) == 32 + -del x64\ansi32.obj x64\proctype32.obj +!ENDIF diff --git a/readme.txt b/readme.txt index 78f00eb..9cdc8d4 100644 --- a/readme.txt +++ b/readme.txt @@ -3,7 +3,7 @@ Copyright 2005-2012 Jason Hood - Version 1.53. Freeware + Version 1.60. Freeware =========== @@ -18,7 +18,8 @@ Requirements ============ - Windows 2000 Professional and later (it won't work with NT or 9X). + 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). ============ @@ -39,7 +40,7 @@ --------- Delete ANSI.dll, it has been replaced with ANSI32.dll. - Delete ANSI-LLA.dll, it has been replaced with ANSI-LLW.dll. + Delete ANSI-LLA.exe/ANSI-LLW.exe, they are no longer needed. Uninstall a pre-1.50 version and reinstall with this version. @@ -182,7 +183,8 @@ decimal number (optional, in most cases defaulting to 1); BEL, SO and SI are ASCII 7, 14 and 15. Regarding SGR: bold will set the foreground intensity; underline and blink will set the background intensity; - conceal uses background as foreground. + conceal uses background as foreground. See `sequences.txt' for a more + complete description. I make a distinction between "\e[m" and "\e[0;...m". Both will restore the original foreground/background colors (and so "0" should be the @@ -274,6 +276,13 @@ Legend: + added, - bug-fixed, * changed. + 1.60 - 24 November, 2012: + * new method to get the 32-bit LoadLibraryW address from 64-bit code. + This removes the need for ANSI-LLW.exe, which caused lots of virus + warnings, for some reason. + - set the code page to display some file names properly; + + expand wildcards for -t (ignoring directories and hidden/binary files). + 1.53 - 12 June, 2012: - fix for multiple simultaneous process creation (e.g. "cl /MP ..."). @@ -432,8 +441,10 @@ I would like to be informed if it is placed on a CD-ROM (other than an archive compilation; permission is granted, I'd just like to know). Modified versions may be distributed, provided it is indicated as such - in the version text and a source diff is included. + in the version text and a source diff is made available. In particular, + the supplied binaries are freely redistributable, but the x64 binaries + must also include COPYING.MinGW-w64-runtime.txt. - ========================== - Jason Hood, 12 June, 2012. + ============================== + Jason Hood, 24 November, 2012. diff --git a/sequences.txt b/sequences.txt new file mode 100644 index 0000000..f994445 --- /dev/null +++ b/sequences.txt @@ -0,0 +1,118 @@ + + ANSICON + Version 1.60 + +This is a complete list of the ANSI escape sequences recognised by ANSICON, +roughly ordered by function. The initial escape character is assumed. + + +[m restore default color (and intensity) +[0m as above +[...m set attributes (any of these numbers, separated by semicolons): + 0 all attributes off + 1 bold (foreground is intense) + 4 underline (background is intense) + 5 blink (background is intense) + 7 reverse video + 8 concealed (foreground becomes background) + 22 bold off (foreground is not intense) + 24 underline off (background is not intense) + 25 blink off (background is not intense) + 27 normal video + 28 concealed off + 30 foreground black + 31 foreground red + 32 foreground green + 33 foreground yellow + 34 foreground blue + 35 foreground magenta + 36 foreground cyan + 37 foreground white + 39 default foreground (using current intensity) + 40 background black + 41 background red + 42 background green + 43 background yellow + 44 background blue + 45 background magenta + 46 background cyan + 47 background white + 49 default background (using current intensity) + +[J erase from cursor to the end of display +[0J as above +[1J erase from the start of diplay to cursor (inclusive) +[2J erase display and move cursor to the top-left + +[K erase from cursor to the end of line +[0K as above +[1K erase from the start of line to cursor (inclusive) +[2K erase line + +[X erase one character +[#X erase # characters + +[L insert one blank line +[#L insert # blank lines + +[M delete one line +[#M delete # lines + +[P delete one character +[#P delete # characters + +[@ insert one blank character +[#@ insert # blank characters + +[A move cursor up one line +[#A move cursor up # lines +[B move cursor down one line +[#B move cursor down # lines +[C move cursor right one character +[#C move cursor right # characters +[D move cursor left one character +[#D move cursor left # characters + +[k move cursor up one line +[#k move cursor up # lines +[e move cursor down one line +[#e move cursor down # lines +[a move cursor right one character +[#a move cursor right # characters +[j move cursor left one character +[#j move cursor left # characters + +[E move cursor down one line and to first column +[#E move cursor down # lines and to first column +[F move cursor up one line and to first column +[#F move cursor up # lines and to first column + +[G move cursor to first column +[#G move cursor to column # + +[` move cursor to first column +[#` move cursor to column # + +[d move cursor to first line +[#d move cursor to line # + +[H move cursor to top-left +[#H move cursor to line # and first column +[#;#H move cursor to line #, column # + +[f move cursor to top-left +[#f move cursor to line # and first column +[#;#f move cursor to line #, column # + +[s save cursor position +[u move cursor to saved position + +[?25h show cursor +[?25l hide cursor + +[5n sends "\e[0n" to console input (where \e is escape) +[6n sends "\e[#;#R" (line & column) to console input +[21t sends "\e]lTitle\e\" (the console's window title) to console input +]0;TitleST + sets the console title to "Title"; ST (string terminator) is either + character 7 (BEL) or escape and backslash diff --git a/util.c b/util.c index 461b7b6..a5ec64a 100644 --- a/util.c +++ b/util.c @@ -55,7 +55,7 @@ void DEBUGSTR( int level, LPTSTR szFormat, ... ) } if (szFormat == NULL) { - file = fopen( tempfile, "wt" ); + file = fopen( tempfile, (log_level & 8) ? "at" : "wt" ); if (file != NULL) { SYSTEMTIME now; diff --git a/version.h b/version.h index ff76004..189162c 100644 --- a/version.h +++ b/version.h @@ -2,8 +2,8 @@ version.h - Version defines. */ -#define PVERS L"1.53" // wide string -#define PVERSA "1.53" // ANSI string (windres 2.16.91 didn't like L) -#define PVERE L"153" // wide environment string -#define PVEREA "153" // ANSI environment string -#define PVERB 1,5,3,0 // binary (resource) +#define PVERS L"1.60" // wide string +#define PVERSA "1.60" // ANSI string (windres 2.16.91 didn't like L) +#define PVERE L"160" // wide environment string +#define PVEREA "160" // ANSI environment string +#define PVERB 1,6,0,0 // binary (resource) diff --git a/wow64.h b/wow64.h index 33e0444..ab71a64 100644 --- a/wow64.h +++ b/wow64.h @@ -1,7 +1,7 @@ /* wow64.h - Definitions for Wow64. - Mingw64/TDM does not include these Wow64 definitions. + The 2003 Platform SDK does not include these Wow64 definitions. */ #ifndef WOW64_H