summaryrefslogtreecommitdiff
path: root/ansicon
diff options
context:
space:
mode:
Diffstat (limited to 'ansicon')
-rwxr-xr-xansicon/.gitignore3
-rwxr-xr-xansicon/ANSI-LLW.c22
-rwxr-xr-xansicon/ANSI.c1825
-rwxr-xr-xansicon/COPYING.MinGW-w64-runtime.txt240
-rwxr-xr-xansicon/G1.bat18
-rwxr-xr-xansicon/G1.txtbin0 -> 404 bytes
-rwxr-xr-xansicon/ansi.rc42
-rwxr-xr-xansicon/ansicon.c686
-rwxr-xr-xansicon/ansicon.h47
-rwxr-xr-xansicon/ansicon.rc36
-rwxr-xr-xansicon/injdll32.c123
-rwxr-xr-xansicon/injdll64.c96
-rwxr-xr-xansicon/makefile82
-rwxr-xr-xansicon/makefile.vc88
-rwxr-xr-xansicon/proctype.c105
-rwxr-xr-xansicon/readme.txt439
-rwxr-xr-xansicon/util.c128
-rwxr-xr-xansicon/version.h9
-rwxr-xr-xansicon/wow64.h88
19 files changed, 4077 insertions, 0 deletions
diff --git a/ansicon/.gitignore b/ansicon/.gitignore
new file mode 100755
index 0000000..a45c74f
--- /dev/null
+++ b/ansicon/.gitignore
@@ -0,0 +1,3 @@
+*.zip
+/x86
+/x64
diff --git a/ansicon/ANSI-LLW.c b/ansicon/ANSI-LLW.c
new file mode 100755
index 0000000..28991f0
--- /dev/null
+++ b/ansicon/ANSI-LLW.c
@@ -0,0 +1,22 @@
+/*
+ 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 <windows.h>
+
+int main( void )
+{
+ return (DWORD)GetProcAddress( GetModuleHandle( "kernel32.dll" ),
+ "LoadLibraryW" );
+}
diff --git a/ansicon/ANSI.c b/ansicon/ANSI.c
new file mode 100755
index 0000000..3907252
--- /dev/null
+++ b/ansicon/ANSI.c
@@ -0,0 +1,1825 @@
+/*
+ ANSI.c - ANSI escape sequence console driver.
+
+ Jason Hood, 21 & 22 October, 2005.
+
+ Derived from ANSI.xs by Jean-Louis Morel, from his Perl package
+ Win32::Console::ANSI. I removed the codepage conversion ("\e(") and added
+ WriteConsole hooking.
+
+ v1.01, 11 & 12 March, 2006:
+ disable when console has disabled processed output;
+ \e[5m (blink) is the same as \e[4m (underline);
+ do not conceal control characters (0 to 31);
+ \e[m will restore original color.
+
+ v1.10, 22 February, 2009:
+ fix MyWriteConsoleW for strings longer than the buffer;
+ initialise attributes to current;
+ hook into child processes.
+
+ v1.11, 28 February, 2009:
+ fix hooking into child processes (only do console executables).
+
+ v1.12, 9 March, 2009:
+ really fix hooking (I didn't realise MinGW didn't generate relocations).
+
+ v1.13, 21 & 27 March, 2009:
+ alternate injection method, to work with DEP;
+ use Unicode and the current output code page (not OEMCP).
+
+ v1.14, 3 April, 2009:
+ fix test for empty import section.
+
+ v1.15, 17 May, 2009:
+ properly update lpNumberOfCharsWritten in MyWriteConsoleA.
+
+ v1.20, 26 & 29 May, 17 to 21 June, 2009:
+ create an ANSICON environment variable;
+ hook GetEnvironmentVariable to create ANSICON dynamically;
+ use another injection method.
+
+ v1.22, 5 October, 2009:
+ hook LoadLibrary to intercept the newly loaded functions.
+
+ v1.23, 11 November, 2009:
+ unload gracefully;
+ conceal characters by making foreground same as background;
+ reverse the bold/underline attributes, too.
+
+ v1.25, 15, 20 & 21 July, 2010:
+ hook LoadLibraryEx (now cscript works);
+ Win7 support.
+
+ v1.30, 3 August to 7 September, 2010:
+ x64 support.
+
+ v1.31, 13 & 19 November, 2010:
+ fix multibyte conversion problems.
+
+ v1.32, 4 to 22 December, 2010:
+ test for lpNumberOfCharsWritten/lpNumberOfBytesWritten being NULL;
+ recognise DSR and xterm window title;
+ ignore sequences starting with \e[? & \e[>;
+ close the handles opened by CreateProcess.
+
+ v1.40, 25 & 26 February, 1 March, 2011:
+ hook GetProcAddress, addresses issues with .NET (work with PowerShell);
+ implement SO & SI to use the DEC Special Graphics Character Set (enables
+ line drawing via ASCII); ignore \e(X & \e)X (where X is any character);
+ add \e[?25h & \e[?25l to show/hide the cursor (DECTCEM).
+
+ v1.50, 7 to 14 December, 2011:
+ added dynamic environment variable ANSICON_VER to return version;
+ read ANSICON_EXC environment variable to exclude selected modules;
+ read ANSICON_GUI environment variable to hook selected GUI programs;
+ read ANSICON_DEF environment variable to set the default GR;
+ transfer current GR to child, read it on exit.
+
+ v1.51, 15 January, 5, 22 & 24 February, 2012:
+ added log mask 16 to log all the imported modules of imported modules;
+ ignore the version within the core API DLL names;
+ fix 32-bit process trying to identify 64-bit process;
+ hook _lwrite & _hwrite.
+
+ v1.52, 10 April, 1 & 2 June, 2012:
+ use ansicon.exe to enable 32-bit to inject into 64-bit;
+ implement \e[39m & \e[49m (only setting color, nothing else);
+ added the character/line equivalents (keaj`) of the cursor movement
+ sequences (ABCDG), as well as vertical absolute (d) and erase characters
+ (X).
+
+ v1.53, 12 June, 2012:
+ fixed Update_GRM when running multiple processes (e.g. "cl /MP").
+*/
+
+#include "ansicon.h"
+#include "version.h"
+#include <tlhelp32.h>
+
+#define isdigit(c) ('0' <= (c) && (c) <= '9')
+
+#ifdef __GNUC__
+#define SHARED __attribute__((shared, section(".share")))
+#else
+#pragma section(".shared", read,write,shared)
+#define SHARED __declspec(allocate(".shared"))
+#endif
+
+
+// ========== Global variables and constants
+
+HANDLE hConOut; // handle to CONOUT$
+
+#define ESC '\x1B' // ESCape character
+#define BEL '\x07'
+#define SO '\x0E' // Shift Out
+#define SI '\x0F' // Shift In
+
+#define MAX_ARG 16 // max number of args in an escape sequence
+int state; // automata state
+TCHAR prefix; // escape sequence prefix ( '[', ']' or '(' );
+TCHAR prefix2; // secondary prefix ( '?' or '>' );
+TCHAR suffix; // escape sequence suffix
+int es_argc; // escape sequence args count
+int es_argv[MAX_ARG]; // escape sequence args
+TCHAR Pt_arg[MAX_PATH*2]; // text parameter for Operating System Command
+int Pt_len;
+BOOL shifted;
+
+
+// DEC Special Graphics Character Set from
+// http://vt100.net/docs/vt220-rm/table2-4.html
+// Some of these may not look right, depending on the font and code page (in
+// particular, the Control Pictures probably won't work at all).
+const WCHAR G1[] =
+{
+ ' ', // _ - blank
+ L'\x2666', // ` - Black Diamond Suit
+ L'\x2592', // a - Medium Shade
+ L'\x2409', // b - HT
+ L'\x240c', // c - FF
+ L'\x240d', // d - CR
+ L'\x240a', // e - LF
+ L'\x00b0', // f - Degree Sign
+ L'\x00b1', // g - Plus-Minus Sign
+ L'\x2424', // h - NL
+ L'\x240b', // i - VT
+ L'\x2518', // j - Box Drawings Light Up And Left
+ L'\x2510', // k - Box Drawings Light Down And Left
+ L'\x250c', // l - Box Drawings Light Down And Right
+ L'\x2514', // m - Box Drawings Light Up And Right
+ L'\x253c', // n - Box Drawings Light Vertical And Horizontal
+ L'\x00af', // o - SCAN 1 - Macron
+ L'\x25ac', // p - SCAN 3 - Black Rectangle
+ L'\x2500', // q - SCAN 5 - Box Drawings Light Horizontal
+ L'_', // r - SCAN 7 - Low Line
+ L'_', // s - SCAN 9 - Low Line
+ L'\x251c', // t - Box Drawings Light Vertical And Right
+ L'\x2524', // u - Box Drawings Light Vertical And Left
+ L'\x2534', // v - Box Drawings Light Up And Horizontal
+ L'\x252c', // w - Box Drawings Light Down And Horizontal
+ L'\x2502', // x - Box Drawings Light Vertical
+ L'\x2264', // y - Less-Than Or Equal To
+ L'\x2265', // z - Greater-Than Or Equal To
+ L'\x03c0', // { - Greek Small Letter Pi
+ L'\x2260', // | - Not Equal To
+ L'\x00a3', // } - Pound Sign
+ L'\x00b7', // ~ - Middle Dot
+};
+
+#define FIRST_G1 '_'
+#define LAST_G1 '~'
+
+
+// color constants
+
+#define FOREGROUND_BLACK 0
+#define FOREGROUND_WHITE FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE
+
+#define BACKGROUND_BLACK 0
+#define BACKGROUND_WHITE BACKGROUND_RED|BACKGROUND_GREEN|BACKGROUND_BLUE
+
+const BYTE foregroundcolor[8] =
+{
+ FOREGROUND_BLACK, // black foreground
+ FOREGROUND_RED, // red foreground
+ FOREGROUND_GREEN, // green foreground
+ FOREGROUND_RED | FOREGROUND_GREEN, // yellow foreground
+ FOREGROUND_BLUE, // blue foreground
+ FOREGROUND_BLUE | FOREGROUND_RED, // magenta foreground
+ FOREGROUND_BLUE | FOREGROUND_GREEN, // cyan foreground
+ FOREGROUND_WHITE // white foreground
+};
+
+const BYTE backgroundcolor[8] =
+{
+ BACKGROUND_BLACK, // black background
+ BACKGROUND_RED, // red background
+ BACKGROUND_GREEN, // green background
+ BACKGROUND_RED | BACKGROUND_GREEN, // yellow background
+ BACKGROUND_BLUE, // blue background
+ BACKGROUND_BLUE | BACKGROUND_RED, // magenta background
+ BACKGROUND_BLUE | BACKGROUND_GREEN, // cyan background
+ BACKGROUND_WHITE, // white background
+};
+
+const BYTE attr2ansi[8] = // map console attribute to ANSI number
+{
+ 0, // black
+ 4, // blue
+ 2, // green
+ 6, // cyan
+ 1, // red
+ 5, // magenta
+ 3, // yellow
+ 7 // white
+};
+
+GRM grm;
+
+// saved cursor position
+COORD SavePos;
+
+// Variables to enable copying attributes between processes.
+SHARED DWORD s_pid;
+SHARED GRM s_grm;
+SHARED DWORD s_flag;
+#define GRM_INIT 1
+#define GRM_EXIT 2
+
+
+
+// Wait for the child process to finish, then update our GRM to the child's.
+DWORD WINAPI UpdateGRM( LPVOID child_pi )
+{
+ DWORD pid = ((LPPROCESS_INFORMATION)child_pi)->dwProcessId;
+ HANDLE proc = ((LPPROCESS_INFORMATION)child_pi)->hProcess;
+ free( child_pi );
+
+ WaitForSingleObject( proc, INFINITE );
+ CloseHandle( proc );
+
+ if (s_flag == GRM_EXIT && s_pid == pid)
+ {
+ s_flag = 0;
+ grm = s_grm;
+ }
+
+ return 0;
+}
+
+
+// Search an environment variable for a string.
+BOOL search_env( LPCTSTR var, LPCTSTR val )
+{
+ static LPTSTR env;
+ static DWORD env_len;
+ DWORD len;
+ BOOL not;
+
+ len = GetEnvironmentVariable( var, env, env_len );
+ if (len == 0)
+ return FALSE;
+
+ if (len > env_len)
+ {
+ LPTSTR tmp = realloc( env, TSIZE(len) );
+ if (tmp == NULL)
+ return FALSE;
+ env = tmp;
+ env_len = len;
+ GetEnvironmentVariable( var, env, env_len );
+ }
+
+ not = (*env == '!');
+ if (not && env[1] == '\0')
+ return TRUE;
+
+ for (var = wcstok( env + not, L";" ); var; var = wcstok( NULL, L";" ))
+ if (_wcsicmp( val, var ) == 0)
+ return !not;
+
+ return not;
+}
+
+
+// ========== Print Buffer functions
+
+#define BUFFER_SIZE 2048
+
+int nCharInBuffer;
+WCHAR ChBuffer[BUFFER_SIZE];
+
+//-----------------------------------------------------------------------------
+// FlushBuffer()
+// Writes the buffer to the console and empties it.
+//-----------------------------------------------------------------------------
+
+void FlushBuffer( void )
+{
+ DWORD nWritten;
+ if (nCharInBuffer <= 0) return;
+ WriteConsole( hConOut, ChBuffer, nCharInBuffer, &nWritten, NULL );
+ nCharInBuffer = 0;
+}
+
+//-----------------------------------------------------------------------------
+// PushBuffer( WCHAR c )
+// Adds a character in the buffer.
+//-----------------------------------------------------------------------------
+
+void PushBuffer( WCHAR c )
+{
+ if (shifted && c >= FIRST_G1 && c <= LAST_G1)
+ c = G1[c-FIRST_G1];
+ ChBuffer[nCharInBuffer] = c;
+ if (++nCharInBuffer == BUFFER_SIZE)
+ FlushBuffer();
+}
+
+//-----------------------------------------------------------------------------
+// SendSequence( LPTSTR seq )
+// Send the string to the input buffer.
+//-----------------------------------------------------------------------------
+
+void SendSequence( LPTSTR seq )
+{
+ DWORD out;
+ INPUT_RECORD in;
+ HANDLE hStdIn = GetStdHandle( STD_INPUT_HANDLE );
+
+ in.EventType = KEY_EVENT;
+ in.Event.KeyEvent.bKeyDown = TRUE;
+ in.Event.KeyEvent.wRepeatCount = 1;
+ in.Event.KeyEvent.wVirtualKeyCode = 0;
+ in.Event.KeyEvent.wVirtualScanCode = 0;
+ in.Event.KeyEvent.dwControlKeyState = 0;
+ for (; *seq; ++seq)
+ {
+ in.Event.KeyEvent.uChar.UnicodeChar = *seq;
+ WriteConsoleInput( hStdIn, &in, 1, &out );
+ }
+}
+
+// ========== Print functions
+
+//-----------------------------------------------------------------------------
+// InterpretEscSeq()
+// Interprets the last escape sequence scanned by ParseAndPrintString
+// prefix escape sequence prefix
+// es_argc escape sequence args count
+// es_argv[] escape sequence args array
+// suffix escape sequence suffix
+//
+// for instance, with \e[33;45;1m we have
+// prefix = '[',
+// es_argc = 3, es_argv[0] = 33, es_argv[1] = 45, es_argv[2] = 1
+// suffix = 'm'
+//-----------------------------------------------------------------------------
+
+void InterpretEscSeq( void )
+{
+ int i;
+ WORD attribut;
+ CONSOLE_SCREEN_BUFFER_INFO Info;
+ CONSOLE_CURSOR_INFO CursInfo;
+ DWORD len, NumberOfCharsWritten;
+ COORD Pos;
+ SMALL_RECT Rect;
+ CHAR_INFO CharInfo;
+
+ if (prefix == '[')
+ {
+ if (prefix2 == '?' && (suffix == 'h' || suffix == 'l'))
+ {
+ if (es_argc == 1 && es_argv[0] == 25)
+ {
+ GetConsoleCursorInfo( hConOut, &CursInfo );
+ CursInfo.bVisible = (suffix == 'h');
+ SetConsoleCursorInfo( hConOut, &CursInfo );
+ return;
+ }
+ }
+ // Ignore any other \e[? or \e[> sequences.
+ if (prefix2 != 0)
+ return;
+
+ GetConsoleScreenBufferInfo( hConOut, &Info );
+ switch (suffix)
+ {
+ case 'm':
+ if (es_argc == 0) es_argv[es_argc++] = 0;
+ for (i = 0; i < es_argc; i++)
+ {
+ if (30 <= es_argv[i] && es_argv[i] <= 37)
+ grm.foreground = es_argv[i] - 30;
+ else if (40 <= es_argv[i] && es_argv[i] <= 47)
+ grm.background = es_argv[i] - 40;
+ else switch (es_argv[i])
+ {
+ case 0:
+ case 39:
+ case 49:
+ {
+ TCHAR def[4];
+ int a;
+ *def = '7'; def[1] = '\0';
+ GetEnvironmentVariable( L"ANSICON_DEF", def, lenof(def) );
+ a = wcstol( def, NULL, 16 );
+ grm.reverse = FALSE;
+ if (a < 0)
+ {
+ grm.reverse = TRUE;
+ a = -a;
+ }
+ if (es_argv[i] != 49)
+ grm.foreground = attr2ansi[a & 7];
+ if (es_argv[i] != 39)
+ grm.background = attr2ansi[(a >> 4) & 7];
+ if (es_argv[i] == 0)
+ {
+ if (es_argc == 1)
+ {
+ grm.bold = a & FOREGROUND_INTENSITY;
+ grm.underline = a & BACKGROUND_INTENSITY;
+ }
+ else
+ {
+ grm.bold = 0;
+ grm.underline = 0;
+ }
+ grm.rvideo = 0;
+ grm.concealed = 0;
+ }
+ }
+ break;
+
+ case 1: grm.bold = FOREGROUND_INTENSITY; break;
+ case 5: // blink
+ case 4: grm.underline = BACKGROUND_INTENSITY; break;
+ case 7: grm.rvideo = 1; break;
+ case 8: grm.concealed = 1; break;
+ case 21: // oops, this actually turns on double underline
+ case 22: grm.bold = 0; break;
+ case 25:
+ case 24: grm.underline = 0; break;
+ case 27: grm.rvideo = 0; break;
+ case 28: grm.concealed = 0; break;
+ }
+ }
+ if (grm.concealed)
+ {
+ if (grm.rvideo)
+ {
+ attribut = foregroundcolor[grm.foreground]
+ | backgroundcolor[grm.foreground];
+ if (grm.bold)
+ attribut |= FOREGROUND_INTENSITY | BACKGROUND_INTENSITY;
+ }
+ else
+ {
+ attribut = foregroundcolor[grm.background]
+ | backgroundcolor[grm.background];
+ if (grm.underline)
+ attribut |= FOREGROUND_INTENSITY | BACKGROUND_INTENSITY;
+ }
+ }
+ else if (grm.rvideo)
+ {
+ attribut = foregroundcolor[grm.background]
+ | backgroundcolor[grm.foreground];
+ if (grm.bold)
+ attribut |= BACKGROUND_INTENSITY;
+ if (grm.underline)
+ attribut |= FOREGROUND_INTENSITY;
+ }
+ else
+ attribut = foregroundcolor[grm.foreground] | grm.bold
+ | backgroundcolor[grm.background] | grm.underline;
+ if (grm.reverse)
+ attribut = ((attribut >> 4) & 15) | ((attribut & 15) << 4);
+ SetConsoleTextAttribute( hConOut, attribut );
+ return;
+
+ case 'J':
+ if (es_argc == 0) es_argv[es_argc++] = 0; // ESC[J == ESC[0J
+ if (es_argc != 1) return;
+ switch (es_argv[0])
+ {
+ case 0: // ESC[0J erase from cursor to end of display
+ len = (Info.dwSize.Y - Info.dwCursorPosition.Y - 1) * Info.dwSize.X
+ + Info.dwSize.X - Info.dwCursorPosition.X - 1;
+ FillConsoleOutputCharacter( hConOut, ' ', len,
+ Info.dwCursorPosition,
+ &NumberOfCharsWritten );
+ FillConsoleOutputAttribute( hConOut, Info.wAttributes, len,
+ Info.dwCursorPosition,
+ &NumberOfCharsWritten );
+ return;
+
+ case 1: // ESC[1J erase from start to cursor.
+ Pos.X = 0;
+ Pos.Y = 0;
+ len = Info.dwCursorPosition.Y * Info.dwSize.X
+ + Info.dwCursorPosition.X + 1;
+ FillConsoleOutputCharacter( hConOut, ' ', len, Pos,
+ &NumberOfCharsWritten );
+ FillConsoleOutputAttribute( hConOut, Info.wAttributes, len, Pos,
+ &NumberOfCharsWritten );
+ return;
+
+ case 2: // ESC[2J Clear screen and home cursor
+ Pos.X = 0;
+ Pos.Y = 0;
+ len = Info.dwSize.X * Info.dwSize.Y;
+ FillConsoleOutputCharacter( hConOut, ' ', len, Pos,
+ &NumberOfCharsWritten );
+ FillConsoleOutputAttribute( hConOut, Info.wAttributes, len, Pos,
+ &NumberOfCharsWritten );
+ SetConsoleCursorPosition( hConOut, Pos );
+ return;
+
+ default:
+ return;
+ }
+
+ case 'K':
+ if (es_argc == 0) es_argv[es_argc++] = 0; // ESC[K == ESC[0K
+ if (es_argc != 1) return;
+ switch (es_argv[0])
+ {
+ case 0: // ESC[0K Clear to end of line
+ len = Info.srWindow.Right - Info.dwCursorPosition.X + 1;
+ FillConsoleOutputCharacter( hConOut, ' ', len,
+ Info.dwCursorPosition,
+ &NumberOfCharsWritten );
+ FillConsoleOutputAttribute( hConOut, Info.wAttributes, len,
+ Info.dwCursorPosition,
+ &NumberOfCharsWritten );
+ return;
+
+ case 1: // ESC[1K Clear from start of line to cursor
+ Pos.X = 0;
+ Pos.Y = Info.dwCursorPosition.Y;
+ FillConsoleOutputCharacter( hConOut, ' ',
+ Info.dwCursorPosition.X + 1, Pos,
+ &NumberOfCharsWritten );
+ FillConsoleOutputAttribute( hConOut, Info.wAttributes,
+ Info.dwCursorPosition.X + 1, Pos,
+ &NumberOfCharsWritten );
+ return;
+
+ case 2: // ESC[2K Clear whole line.
+ Pos.X = 0;
+ Pos.Y = Info.dwCursorPosition.Y;
+ FillConsoleOutputCharacter( hConOut, ' ', Info.dwSize.X, Pos,
+ &NumberOfCharsWritten );
+ FillConsoleOutputAttribute( hConOut, Info.wAttributes,
+ Info.dwSize.X, Pos,
+ &NumberOfCharsWritten );
+ return;
+
+ default:
+ return;
+ }
+
+ case 'X': // ESC[#X Erase # characters.
+ if (es_argc == 0) es_argv[es_argc++] = 1; // ESC[X == ESC[1X
+ if (es_argc != 1) return;
+ FillConsoleOutputCharacter( hConOut, ' ', es_argv[0],
+ Info.dwCursorPosition,
+ &NumberOfCharsWritten );
+ FillConsoleOutputAttribute( hConOut, Info.wAttributes, es_argv[0],
+ Info.dwCursorPosition,
+ &NumberOfCharsWritten );
+ return;
+
+ case 'L': // ESC[#L Insert # blank lines.
+ if (es_argc == 0) es_argv[es_argc++] = 1; // ESC[L == ESC[1L
+ if (es_argc != 1) return;
+ Rect.Left = 0;
+ Rect.Top = Info.dwCursorPosition.Y;
+ Rect.Right = Info.dwSize.X - 1;
+ Rect.Bottom = Info.dwSize.Y - 1;
+ Pos.X = 0;
+ Pos.Y = Info.dwCursorPosition.Y + es_argv[0];
+ CharInfo.Char.UnicodeChar = ' ';
+ CharInfo.Attributes = Info.wAttributes;
+ ScrollConsoleScreenBuffer( hConOut, &Rect, NULL, Pos, &CharInfo );
+ return;
+
+ case 'M': // ESC[#M Delete # lines.
+ if (es_argc == 0) es_argv[es_argc++] = 1; // ESC[M == ESC[1M
+ if (es_argc != 1) return;
+ if (es_argv[0] > Info.dwSize.Y - Info.dwCursorPosition.Y)
+ es_argv[0] = Info.dwSize.Y - Info.dwCursorPosition.Y;
+ Rect.Left = 0;
+ Rect.Top = Info.dwCursorPosition.Y + es_argv[0];
+ Rect.Right = Info.dwSize.X - 1;
+ Rect.Bottom = Info.dwSize.Y - 1;
+ Pos.X = 0;
+ Pos.Y = Info.dwCursorPosition.Y;
+ CharInfo.Char.UnicodeChar = ' ';
+ CharInfo.Attributes = Info.wAttributes;
+ ScrollConsoleScreenBuffer( hConOut, &Rect, NULL, Pos, &CharInfo );
+ return;
+
+ case 'P': // ESC[#P Delete # characters.
+ if (es_argc == 0) es_argv[es_argc++] = 1; // ESC[P == ESC[1P
+ if (es_argc != 1) return;
+ if (Info.dwCursorPosition.X + es_argv[0] > Info.dwSize.X - 1)
+ es_argv[0] = Info.dwSize.X - Info.dwCursorPosition.X;
+ Rect.Left = Info.dwCursorPosition.X + es_argv[0];
+ Rect.Top = Info.dwCursorPosition.Y;
+ Rect.Right = Info.dwSize.X - 1;
+ Rect.Bottom = Info.dwCursorPosition.Y;
+ CharInfo.Char.UnicodeChar = ' ';
+ CharInfo.Attributes = Info.wAttributes;
+ ScrollConsoleScreenBuffer( hConOut, &Rect, NULL, Info.dwCursorPosition,
+ &CharInfo );
+ return;
+
+ case '@': // ESC[#@ Insert # blank characters.
+ if (es_argc == 0) es_argv[es_argc++] = 1; // ESC[@ == ESC[1@
+ if (es_argc != 1) return;
+ if (Info.dwCursorPosition.X + es_argv[0] > Info.dwSize.X - 1)
+ es_argv[0] = Info.dwSize.X - Info.dwCursorPosition.X;
+ Rect.Left = Info.dwCursorPosition.X;
+ Rect.Top = Info.dwCursorPosition.Y;
+ Rect.Right = Info.dwSize.X - 1 - es_argv[0];
+ Rect.Bottom = Info.dwCursorPosition.Y;
+ Pos.X = Info.dwCursorPosition.X + es_argv[0];
+ Pos.Y = Info.dwCursorPosition.Y;
+ CharInfo.Char.UnicodeChar = ' ';
+ CharInfo.Attributes = Info.wAttributes;
+ ScrollConsoleScreenBuffer( hConOut, &Rect, NULL, Pos, &CharInfo );
+ return;
+
+ case 'k': // ESC[#k
+ case 'A': // ESC[#A Moves cursor up # lines
+ if (es_argc == 0) es_argv[es_argc++] = 1; // ESC[A == ESC[1A
+ if (es_argc != 1) return;
+ Pos.Y = Info.dwCursorPosition.Y - es_argv[0];
+ if (Pos.Y < 0) Pos.Y = 0;
+ Pos.X = Info.dwCursorPosition.X;
+ SetConsoleCursorPosition( hConOut, Pos );
+ return;
+
+ case 'e': // ESC[#e
+ case 'B': // ESC[#B Moves cursor down # lines
+ if (es_argc == 0) es_argv[es_argc++] = 1; // ESC[B == ESC[1B
+ if (es_argc != 1) return;
+ Pos.Y = Info.dwCursorPosition.Y + es_argv[0];
+ if (Pos.Y >= Info.dwSize.Y) Pos.Y = Info.dwSize.Y - 1;
+ Pos.X = Info.dwCursorPosition.X;
+ SetConsoleCursorPosition( hConOut, Pos );
+ return;
+
+ case 'a': // ESC[#a
+ case 'C': // ESC[#C Moves cursor forward # spaces
+ if (es_argc == 0) es_argv[es_argc++] = 1; // ESC[C == ESC[1C
+ if (es_argc != 1) return;
+ Pos.X = Info.dwCursorPosition.X + es_argv[0];
+ if (Pos.X >= Info.dwSize.X) Pos.X = Info.dwSize.X - 1;
+ Pos.Y = Info.dwCursorPosition.Y;
+ SetConsoleCursorPosition( hConOut, Pos );
+ return;
+
+ case 'j': // ESC[#j
+ case 'D': // ESC[#D Moves cursor back # spaces
+ if (es_argc == 0) es_argv[es_argc++] = 1; // ESC[D == ESC[1D
+ if (es_argc != 1) return;
+ Pos.X = Info.dwCursorPosition.X - es_argv[0];
+ if (Pos.X < 0) Pos.X = 0;
+ Pos.Y = Info.dwCursorPosition.Y;
+ SetConsoleCursorPosition( hConOut, Pos );
+ return;
+
+ case 'E': // ESC[#E Moves cursor down # lines, column 1.
+ if (es_argc == 0) es_argv[es_argc++] = 1; // ESC[E == ESC[1E
+ if (es_argc != 1) return;
+ Pos.Y = Info.dwCursorPosition.Y + es_argv[0];
+ if (Pos.Y >= Info.dwSize.Y) Pos.Y = Info.dwSize.Y - 1;
+ Pos.X = 0;
+ SetConsoleCursorPosition( hConOut, Pos );
+ return;
+
+ case 'F': // ESC[#F Moves cursor up # lines, column 1.
+ if (es_argc == 0) es_argv[es_argc++] = 1; // ESC[F == ESC[1F
+ if (es_argc != 1) return;
+ Pos.Y = Info.dwCursorPosition.Y - es_argv[0];
+ if (Pos.Y < 0) Pos.Y = 0;
+ Pos.X = 0;
+ SetConsoleCursorPosition( hConOut, Pos );
+ return;
+
+ case '`': // ESC[#`
+ case 'G': // ESC[#G Moves cursor column # in current row.
+ if (es_argc == 0) es_argv[es_argc++] = 1; // ESC[G == ESC[1G
+ if (es_argc != 1) return;
+ Pos.X = es_argv[0] - 1;
+ if (Pos.X >= Info.dwSize.X) Pos.X = Info.dwSize.X - 1;
+ if (Pos.X < 0) Pos.X = 0;
+ Pos.Y = Info.dwCursorPosition.Y;
+ SetConsoleCursorPosition( hConOut, Pos );
+ return;
+
+ case 'd': // ESC[#d Moves cursor row #, current column.
+ if (es_argc == 0) es_argv[es_argc++] = 1; // ESC[d == ESC[1d
+ if (es_argc != 1) return;
+ Pos.Y = es_argv[0] - 1;
+ if (Pos.Y < 0) Pos.Y = 0;
+ if (Pos.Y >= Info.dwSize.Y) Pos.Y = Info.dwSize.Y - 1;
+ SetConsoleCursorPosition( hConOut, Pos );
+ return;
+
+ case 'f': // ESC[#;#f
+ case 'H': // ESC[#;#H Moves cursor to line #, column #
+ if (es_argc == 0)
+ es_argv[es_argc++] = 1; // ESC[H == ESC[1;1H
+ if (es_argc == 1)
+ es_argv[es_argc++] = 1; // ESC[#H == ESC[#;1H
+ if (es_argc > 2) return;
+ Pos.X = es_argv[1] - 1;
+ if (Pos.X < 0) Pos.X = 0;
+ if (Pos.X >= Info.dwSize.X) Pos.X = Info.dwSize.X - 1;
+ Pos.Y = es_argv[0] - 1;
+ if (Pos.Y < 0) Pos.Y = 0;
+ if (Pos.Y >= Info.dwSize.Y) Pos.Y = Info.dwSize.Y - 1;
+ SetConsoleCursorPosition( hConOut, Pos );
+ return;
+
+ case 's': // ESC[s Saves cursor position for recall later
+ if (es_argc != 0) return;
+ SavePos = Info.dwCursorPosition;
+ return;
+
+ case 'u': // ESC[u Return to saved cursor position
+ if (es_argc != 0) return;
+ SetConsoleCursorPosition( hConOut, SavePos );
+ return;
+
+ case 'n': // ESC[#n Device status report
+ if (es_argc != 1) return; // ESC[n == ESC[0n -> ignored
+ switch (es_argv[0])
+ {
+ case 5: // ESC[5n Report status
+ SendSequence( L"\33[0n" ); // "OK"
+ return;
+
+ case 6: // ESC[6n Report cursor position
+ {
+ TCHAR buf[32];
+ wsprintf( buf, L"\33[%d;%dR", Info.dwCursorPosition.Y + 1,
+ Info.dwCursorPosition.X + 1 );
+ SendSequence( buf );
+ }
+ return;
+
+ default:
+ return;
+ }
+
+ case 't': // ESC[#t Window manipulation
+ if (es_argc != 1) return;
+ if (es_argv[0] == 21) // ESC[21t Report xterm window's title
+ {
+ TCHAR buf[MAX_PATH*2];
+ DWORD len = GetConsoleTitle( buf+3, lenof(buf)-3-2 );
+ // Too bad if it's too big or fails.
+ buf[0] = ESC;
+ buf[1] = ']';
+ buf[2] = 'l';
+ buf[3+len] = ESC;
+ buf[3+len+1] = '\\';
+ buf[3+len+2] = '\0';
+ SendSequence( buf );
+ }
+ return;
+
+ default:
+ return;
+ }
+ }
+ else // (prefix == ']')
+ {
+ // Ignore any \e]? or \e]> sequences.
+ if (prefix2 != 0)
+ return;
+
+ if (es_argc == 1 && es_argv[0] == 0) // ESC]0;titleST
+ {
+ SetConsoleTitle( Pt_arg );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// ParseAndPrintString(hDev, lpBuffer, nNumberOfBytesToWrite)
+// Parses the string lpBuffer, interprets the escapes sequences and prints the
+// characters in the device hDev (console).
+// The lexer is a three states automata.
+// If the number of arguments es_argc > MAX_ARG, only the MAX_ARG-1 firsts and
+// the last arguments are processed (no es_argv[] overflow).
+//-----------------------------------------------------------------------------
+
+BOOL
+ParseAndPrintString( HANDLE hDev,
+ LPCVOID lpBuffer,
+ DWORD nNumberOfBytesToWrite,
+ LPDWORD lpNumberOfBytesWritten
+ )
+{
+ DWORD i;
+ LPCTSTR s;
+
+ if (hDev != hConOut) // reinit if device has changed
+ {
+ hConOut = hDev;
+ state = 1;
+ shifted = FALSE;
+ }
+ for (i = nNumberOfBytesToWrite, s = (LPCTSTR)lpBuffer; i > 0; i--, s++)
+ {
+ if (state == 1)
+ {
+ if (*s == ESC) state = 2;
+ else if (*s == SO) shifted = TRUE;
+ else if (*s == SI) shifted = FALSE;
+ else PushBuffer( *s );
+ }
+ else if (state == 2)
+ {
+ if (*s == ESC) ; // \e\e...\e == \e
+ else if ((*s == '[') || (*s == ']'))
+ {
+ FlushBuffer();
+ prefix = *s;
+ prefix2 = 0;
+ state = 3;
+ Pt_len = 0;
+ *Pt_arg = '\0';
+ }
+ else if (*s == ')' || *s == '(') state = 6;
+ else state = 1;
+ }
+ else if (state == 3)
+ {
+ if (isdigit( *s ))
+ {
+ es_argc = 0;
+ es_argv[0] = *s - '0';
+ state = 4;
+ }
+ else if (*s == ';')
+ {
+ es_argc = 1;
+ es_argv[0] = 0;
+ es_argv[1] = 0;
+ state = 4;
+ }
+ else if (*s == '?' || *s == '>')
+ {
+ prefix2 = *s;
+ }
+ else
+ {
+ es_argc = 0;
+ suffix = *s;
+ InterpretEscSeq();
+ state = 1;
+ }
+ }
+ else if (state == 4)
+ {
+ if (isdigit( *s ))
+ {
+ es_argv[es_argc] = 10 * es_argv[es_argc] + (*s - '0');
+ }
+ else if (*s == ';')
+ {
+ if (es_argc < MAX_ARG-1) es_argc++;
+ es_argv[es_argc] = 0;
+ if (prefix == ']')
+ state = 5;
+ }
+ else
+ {
+ es_argc++;
+ suffix = *s;
+ InterpretEscSeq();
+ state = 1;
+ }
+ }
+ else if (state == 5)
+ {
+ if (*s == BEL)
+ {
+ Pt_arg[Pt_len] = '\0';
+ InterpretEscSeq();
+ state = 1;
+ }
+ else if (*s == '\\' && Pt_len > 0 && Pt_arg[Pt_len-1] == ESC)
+ {
+ Pt_arg[--Pt_len] = '\0';
+ InterpretEscSeq();
+ state = 1;
+ }
+ else if (Pt_len < lenof(Pt_arg)-1)
+ Pt_arg[Pt_len++] = *s;
+ }
+ else if (state == 6)
+ {
+ // Ignore it (ESC ) 0 is implicit; nothing else is supported).
+ state = 1;
+ }
+ }
+ FlushBuffer();
+ if (lpNumberOfBytesWritten != NULL)
+ *lpNumberOfBytesWritten = nNumberOfBytesToWrite - i;
+ return (i == 0);
+}
+
+
+// ========== Hooking API functions
+//
+// References about API hooking (and dll injection):
+// - Matt Pietrek ~ Windows 95 System Programming Secrets.
+// - Jeffrey Richter ~ Programming Applications for Microsoft Windows 4th ed.
+
+// Macro for adding pointers/DWORDs together without C arithmetic interfering
+#define MakeVA( cast, offset ) (cast)((DWORD_PTR)(pDosHeader)+(DWORD)(offset))
+
+
+const char APIKernel[] = "kernel32.dll";
+const char APIConsole[] = "API-MS-Win-Core-Console-";
+const char APIProcessThreads[] = "API-MS-Win-Core-ProcessThreads-";
+const char APIProcessEnvironment[] = "API-MS-Win-Core-ProcessEnvironment-";
+const char APILibraryLoader[] = "API-MS-Win-Core-LibraryLoader-";
+const char APIFile[] = "API-MS-Win-Core-File-";
+
+typedef struct
+{
+ PCSTR name;
+ DWORD len;
+ HMODULE base;
+} API_DATA, *PAPI_DATA;
+
+API_DATA APIs[] =
+{
+ { APIConsole, sizeof(APIConsole) - 1, NULL },
+ { APIProcessThreads, sizeof(APIProcessThreads) - 1, NULL },
+ { APIProcessEnvironment, sizeof(APIProcessEnvironment) - 1, NULL },
+ { APILibraryLoader, sizeof(APILibraryLoader) - 1, NULL },
+ { APIFile, sizeof(APIFile) - 1, NULL },
+ { NULL, 0, NULL }
+};
+
+
+HMODULE hKernel; // Kernel32 module handle
+HINSTANCE hDllInstance; // Dll instance handle
+TCHAR hDllName[MAX_PATH]; // Dll file name
+#if defined(_WIN64) || defined(W32ON64)
+LPTSTR hDllNameType; // pointer to process type within above
+#endif
+
+typedef struct
+{
+ PCSTR lib;
+ PSTR name;
+ PROC newfunc;
+ PROC oldfunc;
+ PROC apifunc;
+} HookFn, *PHookFn;
+
+HookFn Hooks[];
+
+const WCHAR zIgnoring[] = L"Ignoring";
+const WCHAR zHooking[] = L"Hooking";
+const WCHAR zUnhooking[] = L"Unhooking";
+
+
+//-----------------------------------------------------------------------------
+// HookAPIOneMod
+// Substitute a new function in the Import Address Table (IAT) of the
+// specified module.
+// Return FALSE on error and TRUE on success.
+//-----------------------------------------------------------------------------
+
+BOOL HookAPIOneMod(
+ HMODULE hFromModule, // Handle of the module to intercept calls from
+ PHookFn Hooks, // Functions to replace
+ BOOL restore // Restore the original functions
+ )
+{
+ PIMAGE_DOS_HEADER pDosHeader;
+ PIMAGE_NT_HEADERS pNTHeader;
+ PIMAGE_IMPORT_DESCRIPTOR pImportDesc;
+ PIMAGE_THUNK_DATA pThunk;
+ PHookFn hook;
+
+ // Tests to make sure we're looking at a module image (the 'MZ' header)
+ pDosHeader = (PIMAGE_DOS_HEADER)hFromModule;
+ 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_HEADERS, 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 imports section.
+ pImportDesc = MakeVA( PIMAGE_IMPORT_DESCRIPTOR,
+ pNTHeader->OptionalHeader.
+ DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].
+ VirtualAddress );
+
+ // Bail out if the RVA of the imports section is 0 (it doesn't exist)
+ if (pImportDesc == (PIMAGE_IMPORT_DESCRIPTOR)pDosHeader)
+ return TRUE;
+
+ // Iterate through the array of imported module descriptors, looking
+ // for the module whose name matches the pszFunctionModule parameter.
+ for (; pImportDesc->Name; pImportDesc++)
+ {
+ BOOL kernel = TRUE;
+ PSTR pszModName = MakeVA( PSTR, pImportDesc->Name );
+ if (_stricmp( pszModName, APIKernel ) != 0)
+ {
+ PAPI_DATA lib;
+ for (lib = APIs; lib->name; ++lib)
+ {
+ if (_strnicmp( pszModName, lib->name, lib->len ) == 0)
+ {
+ if (lib->base == NULL)
+ {
+ lib->base = GetModuleHandleA( pszModName );
+ for (hook = Hooks; hook->name; ++hook)
+ if (hook->lib == lib->name)
+ hook->apifunc = GetProcAddress( lib->base, hook->name );
+ }
+ break;
+ }
+ }
+ if (lib->name == NULL)
+ {
+ if (log_level & 16)
+ DEBUGSTR( 2, L" %s %S", zIgnoring, pszModName );
+ continue;
+ }
+ kernel = FALSE;
+ }
+ if (log_level & 16)
+ DEBUGSTR( 2, L" Scanning %S", pszModName );
+
+ // Get a pointer to the found module's import address table (IAT).
+ pThunk = MakeVA( PIMAGE_THUNK_DATA, pImportDesc->FirstThunk );
+
+ // Blast through the table of import addresses, looking for the ones
+ // that match the original addresses.
+ while (pThunk->u1.Function)
+ {
+ for (hook = Hooks; hook->name; ++hook)
+ {
+ PROC patch = 0;
+ if (restore)
+ {
+ if ((PROC)pThunk->u1.Function == hook->newfunc)
+ patch = (kernel) ? hook->oldfunc : hook->apifunc;
+ }
+ else if ((PROC)pThunk->u1.Function == hook->oldfunc ||
+ (PROC)pThunk->u1.Function == hook->apifunc)
+ {
+ patch = hook->newfunc;
+ }
+ if (patch)
+ {
+ DWORD flOldProtect, flNewProtect, flDummy;
+ MEMORY_BASIC_INFORMATION mbi;
+
+ 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 );
+
+ // 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;
+ }
+
+ // Put the page attributes back the way they were.
+ VirtualProtect( &pThunk->u1.Function, sizeof(PVOID),
+ flOldProtect, &flDummy );
+ }
+ }
+ pThunk++; // Advance to next imported function address
+ }
+ }
+
+ return TRUE; // Function not found
+}
+
+//-----------------------------------------------------------------------------
+// HookAPIAllMod
+// Substitute a new function in the Import Address Table (IAT) of all
+// the modules in the current process.
+// Return FALSE on error and TRUE on success.
+//-----------------------------------------------------------------------------
+
+BOOL HookAPIAllMod( PHookFn Hooks, BOOL restore )
+{
+ HANDLE hModuleSnap;
+ MODULEENTRY32 me;
+ BOOL fOk;
+
+ // Take a snapshot of all modules in the current process.
+ hModuleSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE,
+ GetCurrentProcessId() );
+
+ if (hModuleSnap == INVALID_HANDLE_VALUE)
+ {
+ DEBUGSTR( 1, L"Failed to create snapshot!" );
+ return FALSE;
+ }
+
+ // Fill the size of the structure before using it.
+ me.dwSize = sizeof(MODULEENTRY32);
+
+ // Walk the module list of the modules.
+ for (fOk = Module32First( hModuleSnap, &me ); fOk;
+ fOk = Module32Next( hModuleSnap, &me ))
+ {
+ // We don't hook functions in our own module.
+ if (me.hModule != hDllInstance && me.hModule != hKernel)
+ {
+ if (search_env( L"ANSICON_EXC", me.szModule ))
+ {
+ DEBUGSTR( 2, L"%s %s", zIgnoring, me.szModule );
+ continue;
+ }
+ DEBUGSTR( 2, L"%s %s", (restore) ? zUnhooking : zHooking, me.szModule );
+ // Hook this function in this module.
+ if (!HookAPIOneMod( me.hModule, Hooks, restore ))
+ {
+ CloseHandle( hModuleSnap );
+ return FALSE;
+ }
+ }
+ }
+ CloseHandle( hModuleSnap );
+ DEBUGSTR( 2, L"%s completed", (restore) ? zUnhooking : zHooking );
+ return TRUE;
+}
+
+
+// ========== Child process injection
+
+// Inject code into the target process to load our DLL.
+void Inject( DWORD dwCreationFlags, LPPROCESS_INFORMATION lpi,
+ LPPROCESS_INFORMATION child_pi,
+ BOOL wide, LPCVOID lpApp, LPCVOID lpCmd )
+{
+ int type;
+ BOOL gui;
+
+ type = ProcessType( child_pi, &gui );
+ if (gui)
+ {
+ TCHAR app[MAX_PATH];
+ LPTSTR name;
+ LPCTSTR term = L" \t";
+
+ app[MAX_PATH-1] = '\0';
+ if (lpApp == NULL)
+ {
+ // Extract the program from the command line. I would use
+ // GetModuleFileNameEx, but it doesn't work when a process is created
+ // suspended and setting up a delay until it does work sometimes
+ // prevents the process running at all. GetProcessImageFileName works,
+ // but it's not supported in 2K.
+ if (wide)
+ {
+ LPCTSTR pos;
+ for (pos = lpCmd; *pos == ' ' || *pos == '\t'; ++pos) ;
+ if (*pos == '"')
+ {
+ term = L"\"";
+ ++pos;
+ }
+ wcsncpy( app, pos, MAX_PATH-1 );
+ }
+ else
+ {
+ LPCSTR pos;
+ for (pos = lpCmd; *pos == ' ' || *pos == '\t'; ++pos) ;
+ if (*pos == '"')
+ {
+ term = L"\"";
+ ++pos;
+ }
+ MultiByteToWideChar( CP_ACP, 0, pos, -1, app, MAX_PATH );
+ }
+ // CreateProcess only works with surrounding quotes ('"a name"' works, but
+ // 'a" "name' fails), so that's all I'll test, too. However, it also
+ // tests for a file at each separator ('a name' tries "a.exe" before
+ // "a name.exe") which I won't do.
+ name = wcspbrk( app, term );
+ if (name)
+ *name = '\0';
+ }
+ else
+ {
+ if (wide)
+ wcsncpy( app, lpApp, MAX_PATH-1 );
+ else
+ MultiByteToWideChar( CP_ACP, 0, lpApp, -1, app, MAX_PATH );
+ }
+ name = get_program_name( app );
+ if (!search_env( L"ANSICON_GUI", name ))
+ {
+ DEBUGSTR( 1, L" %s", zIgnoring );
+ type = 0;
+ }
+ }
+ if (type != 0)
+ {
+#ifdef _WIN64
+ if (type == 32)
+ {
+ hDllNameType[0] = '3';
+ hDllNameType[1] = '2';
+ InjectDLL32( child_pi, hDllName );
+ }
+ else
+ {
+ hDllNameType[0] = '6';
+ hDllNameType[1] = '4';
+ InjectDLL64( child_pi, hDllName );
+ }
+#else
+#ifdef W32ON64
+ if (type == 64)
+ {
+ TCHAR args[64];
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+ wcscpy( hDllNameType, L"CON.exe" );
+ wsprintf( args, L"ansicon -P%lu:%lu",
+ child_pi->dwProcessId, child_pi->dwThreadId );
+ ZeroMemory( &si, sizeof(si) );
+ si.cb = sizeof(si);
+ if (CreateProcess( hDllName, args, NULL, NULL, FALSE, 0, NULL, NULL,
+ &si, &pi ))
+ {
+ WaitForSingleObject( pi.hProcess, INFINITE );
+ CloseHandle( pi.hProcess );
+ CloseHandle( pi.hThread );
+ }
+ else
+ DEBUGSTR( 1, L"Could not execute \"%s\"", hDllName );
+ wcscpy( hDllNameType, L"32.dll" );
+ }
+ else
+#endif
+ InjectDLL32( child_pi, hDllName );
+#endif
+ if (!gui && !(dwCreationFlags & (CREATE_NEW_CONSOLE | DETACHED_PROCESS)))
+ {
+ LPPROCESS_INFORMATION cpi;
+ s_pid = child_pi->dwProcessId;
+ s_grm = grm;
+ s_flag = GRM_INIT;
+ cpi = malloc( sizeof(*cpi) );
+ cpi->dwProcessId = child_pi->dwProcessId;
+ DuplicateHandle( GetCurrentProcess(), child_pi->hProcess,
+ GetCurrentProcess(), &cpi->hProcess, 0, FALSE,
+ DUPLICATE_SAME_ACCESS );
+ CloseHandle( CreateThread( NULL, 4096, UpdateGRM, cpi, 0, NULL ) );
+ }
+ }
+
+ if (!(dwCreationFlags & CREATE_SUSPENDED))
+ ResumeThread( child_pi->hThread );
+
+ if (lpi)
+ {
+ memcpy( lpi, child_pi, sizeof(PROCESS_INFORMATION) );
+ }
+ else
+ {
+ CloseHandle( child_pi->hThread );
+ CloseHandle( child_pi->hProcess );
+ }
+}
+
+
+BOOL WINAPI MyCreateProcessA( LPCSTR lpApplicationName,
+ LPSTR lpCommandLine,
+ LPSECURITY_ATTRIBUTES lpThreadAttributes,
+ LPSECURITY_ATTRIBUTES lpProcessAttributes,
+ BOOL bInheritHandles,
+ DWORD dwCreationFlags,
+ LPVOID lpEnvironment,
+ LPCSTR lpCurrentDirectory,
+ LPSTARTUPINFOA lpStartupInfo,
+ LPPROCESS_INFORMATION lpProcessInformation )
+{
+ PROCESS_INFORMATION child_pi;
+
+ if (!CreateProcessA( lpApplicationName,
+ lpCommandLine,
+ lpThreadAttributes,
+ lpProcessAttributes,
+ bInheritHandles,
+ dwCreationFlags | CREATE_SUSPENDED,
+ lpEnvironment,
+ lpCurrentDirectory,
+ lpStartupInfo,
+ &child_pi ))
+ return FALSE;
+
+ DEBUGSTR( 1, L"CreateProcessA: (%lu) \"%S\", \"%S\"",
+ child_pi.dwProcessId,
+ (lpApplicationName == NULL) ? "" : lpApplicationName,
+ (lpCommandLine == NULL) ? "" : lpCommandLine );
+ Inject( dwCreationFlags, lpProcessInformation, &child_pi,
+ FALSE, lpApplicationName, lpCommandLine );
+
+ return TRUE;
+}
+
+
+BOOL WINAPI MyCreateProcessW( LPCWSTR lpApplicationName,
+ LPWSTR lpCommandLine,
+ LPSECURITY_ATTRIBUTES lpThreadAttributes,
+ LPSECURITY_ATTRIBUTES lpProcessAttributes,
+ BOOL bInheritHandles,
+ DWORD dwCreationFlags,
+ LPVOID lpEnvironment,
+ LPCWSTR lpCurrentDirectory,
+ LPSTARTUPINFOW lpStartupInfo,
+ LPPROCESS_INFORMATION lpProcessInformation )
+{
+ PROCESS_INFORMATION child_pi;
+
+ if (!CreateProcessW( lpApplicationName,
+ lpCommandLine,
+ lpThreadAttributes,
+ lpProcessAttributes,
+ bInheritHandles,
+ dwCreationFlags | CREATE_SUSPENDED,
+ lpEnvironment,
+ lpCurrentDirectory,
+ lpStartupInfo,
+ &child_pi ))
+ return FALSE;
+
+ DEBUGSTR( 1, L"CreateProcessW: (%lu) \"%s\", \"%s\"",
+ child_pi.dwProcessId,
+ (lpApplicationName == NULL) ? L"" : lpApplicationName,
+ (lpCommandLine == NULL) ? L"" : lpCommandLine );
+ Inject( dwCreationFlags, lpProcessInformation, &child_pi,
+ TRUE, lpApplicationName, lpCommandLine );
+
+ return TRUE;
+}
+
+
+FARPROC WINAPI MyGetProcAddress( HMODULE hModule, LPCSTR lpProcName )
+{
+ PHookFn hook;
+ FARPROC proc;
+
+ proc = GetProcAddress( hModule, lpProcName );
+
+ if (proc)
+ {
+ if (hModule == hKernel)
+ {
+ // Ignore LoadLibrary so other hooks continue to work (our version
+ // might end up at a different address).
+ if (proc == Hooks[0].oldfunc || proc == Hooks[1].oldfunc)
+ {
+ DEBUGSTR( 3, L"GetProcAddress: %S (ignoring)", lpProcName );
+ return proc;
+ }
+ for (hook = Hooks + 2; hook->name; ++hook)
+ {
+ if (proc == hook->oldfunc)
+ {
+ DEBUGSTR( 3, L"GetProcAddress: %S", lpProcName );
+ return hook->newfunc;
+ }
+ }
+ }
+ else
+ {
+ PAPI_DATA api;
+ for (api = APIs; api->name; ++api)
+ {
+ if (hModule == api->base)
+ {
+ if (proc == Hooks[0].apifunc || proc == Hooks[1].apifunc)
+ {
+ DEBUGSTR( 3, L"GetProcAddress: %S (ignoring)", lpProcName );
+ return proc;
+ }
+ for (hook = Hooks + 2; hook->name; ++hook)
+ {
+ if (proc == hook->apifunc)
+ {
+ DEBUGSTR( 3, L"GetProcAddress: %S", lpProcName );
+ return hook->newfunc;
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ return proc;
+}
+
+
+void HookLibrary( HMODULE hMod, LPCVOID lpFileName, BOOL wide, LPCSTR funcName )
+{
+ LPCWSTR name;
+ WCHAR wname[MAX_PATH];
+
+ if (hMod && hMod != hKernel)
+ {
+ if (!wide)
+ {
+ MultiByteToWideChar( AreFileApisANSI() ? CP_ACP : CP_OEMCP, 0,
+ lpFileName, -1, wname, MAX_PATH );
+ lpFileName = wname;
+ }
+ name = wcsrchr( lpFileName, '\\' );
+ if (name == NULL)
+ name = lpFileName;
+ else
+ ++name;
+ if (search_env( L"ANSICON_EXC", name ))
+ DEBUGSTR( 2, L"%s %s (%S)", zIgnoring, lpFileName, funcName );
+ else
+ {
+ DEBUGSTR( 2, L"%s %s (%S)", zHooking, lpFileName, funcName );
+ HookAPIOneMod( hMod, Hooks, FALSE );
+ }
+ }
+}
+
+
+HMODULE WINAPI MyLoadLibraryA( LPCSTR lpFileName )
+{
+ HMODULE hMod = LoadLibraryA( lpFileName );
+ HookLibrary( hMod, lpFileName, FALSE, "LoadLibraryA" );
+ return hMod;
+}
+
+
+HMODULE WINAPI MyLoadLibraryW( LPCWSTR lpFileName )
+{
+ HMODULE hMod = LoadLibraryW( lpFileName );
+ HookLibrary( hMod, lpFileName, TRUE, "LoadLibraryW" );
+ return hMod;
+}
+
+
+HMODULE WINAPI MyLoadLibraryExA( LPCSTR lpFileName, HANDLE hFile,
+ DWORD dwFlags )
+{
+ HMODULE hMod = LoadLibraryExA( lpFileName, hFile, dwFlags );
+ if (!(dwFlags & LOAD_LIBRARY_AS_DATAFILE))
+ HookLibrary( hMod, lpFileName, FALSE, "LoadLibraryExA" );
+ return hMod;
+}
+
+
+HMODULE WINAPI MyLoadLibraryExW( LPCWSTR lpFileName, HANDLE hFile,
+ DWORD dwFlags )
+{
+ HMODULE hMod = LoadLibraryExW( lpFileName, hFile, dwFlags );
+ if (!(dwFlags & LOAD_LIBRARY_AS_DATAFILE))
+ HookLibrary( hMod, lpFileName, TRUE, "LoadLibraryExW" );
+ return hMod;
+}
+
+
+//-----------------------------------------------------------------------------
+// MyWrite...
+// It is the new function that must replace the original Write... function.
+// This function have exactly the same signature as the original one.
+//-----------------------------------------------------------------------------
+
+BOOL
+WINAPI MyWriteConsoleA( HANDLE hCon, LPCVOID lpBuffer,
+ DWORD nNumberOfCharsToWrite,
+ LPDWORD lpNumberOfCharsWritten, LPVOID lpReserved )
+{
+ DWORD Mode;
+ LPWSTR buf;
+ DWORD len;
+ BOOL rc = TRUE;
+
+ // if we write in a console buffer with processed output
+ if (GetConsoleMode( hCon, &Mode ) && (Mode & ENABLE_PROCESSED_OUTPUT))
+ {
+ UINT cp = GetConsoleOutputCP();
+ DEBUGSTR( 4, L"\33WriteConsoleA: %lu \"%.*S\"",
+ nNumberOfCharsToWrite, nNumberOfCharsToWrite, lpBuffer );
+ len = MultiByteToWideChar( cp, 0, lpBuffer, nNumberOfCharsToWrite, NULL,0 );
+ buf = malloc( TSIZE(len) );
+ if (buf == NULL)
+ {
+ if (lpNumberOfCharsWritten != NULL)
+ *lpNumberOfCharsWritten = 0;
+ return (nNumberOfCharsToWrite == 0);
+ }
+ MultiByteToWideChar( cp, 0, lpBuffer, nNumberOfCharsToWrite, buf, len );
+ rc = ParseAndPrintString( hCon, buf, len, lpNumberOfCharsWritten );
+ free( buf );
+ if (rc && lpNumberOfCharsWritten != NULL &&
+ *lpNumberOfCharsWritten != nNumberOfCharsToWrite)
+ {
+ // Converting a multibyte character to Unicode results in a different
+ // "character" count. This causes some programs to think not everything
+ // was written, so the difference is sent again. Fudge the (presumably)
+ // correct count.
+ if (search_env( L"ANSICON_API", prog ))
+ *lpNumberOfCharsWritten = nNumberOfCharsToWrite;
+ }
+ return rc;
+ }
+
+ return WriteConsoleA( hCon, lpBuffer, nNumberOfCharsToWrite,
+ lpNumberOfCharsWritten, lpReserved );
+
+}
+
+BOOL
+WINAPI MyWriteConsoleW( HANDLE hCon, LPCVOID lpBuffer,
+ DWORD nNumberOfCharsToWrite,
+ LPDWORD lpNumberOfCharsWritten, LPVOID lpReserved )
+{
+ DWORD Mode;
+ if (GetConsoleMode( hCon, &Mode ) && (Mode & ENABLE_PROCESSED_OUTPUT))
+ {
+ DEBUGSTR( 4, L"\33WriteConsoleW: %lu \"%.*s\"",
+ nNumberOfCharsToWrite, nNumberOfCharsToWrite, lpBuffer );
+ return ParseAndPrintString( hCon, lpBuffer,
+ nNumberOfCharsToWrite,
+ lpNumberOfCharsWritten );
+ }
+
+ return WriteConsoleW( hCon, lpBuffer, nNumberOfCharsToWrite,
+ lpNumberOfCharsWritten, lpReserved );
+}
+
+BOOL
+WINAPI MyWriteFile( HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
+ LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped )
+{
+ DWORD Mode;
+ if (GetConsoleMode( hFile, &Mode ) && (Mode & ENABLE_PROCESSED_OUTPUT))
+ {
+ DEBUGSTR( 4, L"WriteFile->" );
+ return MyWriteConsoleA( hFile, lpBuffer,
+ nNumberOfBytesToWrite,
+ lpNumberOfBytesWritten,
+ lpOverlapped );
+ }
+
+ // here, WriteFile is the old function (this module is not hooked)
+ return WriteFile( hFile, lpBuffer, nNumberOfBytesToWrite,
+ lpNumberOfBytesWritten, lpOverlapped );
+}
+
+
+#define HHFILE (HANDLE)(DWORD_PTR)
+
+UINT
+WINAPI My_lwrite( HFILE hFile, LPCSTR lpBuffer, UINT uBytes )
+{
+ DWORD Mode, written;
+ if (GetConsoleMode( HHFILE hFile, &Mode ) && (Mode & ENABLE_PROCESSED_OUTPUT))
+ {
+ DEBUGSTR( 4, L"_lwrite->" );
+ MyWriteConsoleA( HHFILE hFile, lpBuffer, uBytes, &written, NULL );
+ return written;
+ }
+
+ return _lwrite( hFile, lpBuffer, uBytes );
+}
+
+long
+WINAPI My_hwrite( HFILE hFile, LPCSTR lpBuffer, long lBytes )
+{
+ DWORD Mode, written;
+ if (GetConsoleMode( HHFILE hFile, &Mode ) && (Mode & ENABLE_PROCESSED_OUTPUT))
+ {
+ DEBUGSTR( 4, L"_hwrite->" );
+ MyWriteConsoleA( HHFILE hFile, lpBuffer, lBytes, &written, NULL );
+ return written;
+ }
+
+ return _hwrite( hFile, lpBuffer, lBytes );
+}
+
+
+// ========== Environment variable
+
+void set_ansicon( PCONSOLE_SCREEN_BUFFER_INFO pcsbi )
+{
+ CONSOLE_SCREEN_BUFFER_INFO csbi;
+ TCHAR buf[64];
+
+ if (pcsbi == NULL)
+ {
+ HANDLE hConOut;
+ hConOut = CreateFile( L"CONOUT$", GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, OPEN_EXISTING, 0, 0 );
+ GetConsoleScreenBufferInfo( hConOut, &csbi );
+ CloseHandle( hConOut );
+ pcsbi = &csbi;
+ }
+
+ wsprintf( buf, L"%dx%d (%dx%d)",
+ pcsbi->dwSize.X, pcsbi->dwSize.Y,
+ pcsbi->srWindow.Right - pcsbi->srWindow.Left + 1,
+ pcsbi->srWindow.Bottom - pcsbi->srWindow.Top + 1 );
+ SetEnvironmentVariable( L"ANSICON", buf );
+}
+
+DWORD
+WINAPI MyGetEnvironmentVariableA( LPCSTR lpName, LPSTR lpBuffer, DWORD nSize )
+{
+ if (lstrcmpiA( lpName, "ANSICON_VER" ) == 0)
+ {
+ if (nSize < sizeof(PVEREA))
+ return sizeof(PVEREA);
+ memcpy( lpBuffer, PVEREA, sizeof(PVEREA) );
+ return sizeof(PVEREA) - 1;
+ }
+
+ if (lstrcmpiA( lpName, "ANSICON" ) == 0)
+ set_ansicon( NULL );
+
+ return GetEnvironmentVariableA( lpName, lpBuffer, nSize );
+}
+
+DWORD
+WINAPI MyGetEnvironmentVariableW( LPCWSTR lpName, LPWSTR lpBuffer, DWORD nSize )
+{
+ if (lstrcmpi( lpName, L"ANSICON_VER" ) == 0)
+ {
+ if (nSize < lenof(PVERE))
+ return lenof(PVERE);
+ memcpy( lpBuffer, PVERE, sizeof(PVERE) );
+ return lenof(PVERE) - 1;
+ }
+
+ if (lstrcmpi( lpName, L"ANSICON" ) == 0)
+ set_ansicon( NULL );
+
+ return GetEnvironmentVariableW( lpName, lpBuffer, nSize );
+}
+
+
+// ========== Initialisation
+
+HookFn Hooks[] = {
+ // These two are expected first!
+ { APILibraryLoader, "LoadLibraryA", (PROC)MyLoadLibraryA, NULL, NULL },
+ { APILibraryLoader, "LoadLibraryW", (PROC)MyLoadLibraryW, NULL, NULL },
+ { APIProcessThreads, "CreateProcessA", (PROC)MyCreateProcessA, NULL, NULL },
+ { APIProcessThreads, "CreateProcessW", (PROC)MyCreateProcessW, NULL, NULL },
+ { APIProcessEnvironment, "GetEnvironmentVariableA", (PROC)MyGetEnvironmentVariableA, NULL, NULL },
+ { APIProcessEnvironment, "GetEnvironmentVariableW", (PROC)MyGetEnvironmentVariableW, NULL, NULL },
+ { APILibraryLoader, "GetProcAddress", (PROC)MyGetProcAddress, NULL, NULL },
+ { APILibraryLoader, "LoadLibraryExA", (PROC)MyLoadLibraryExA, NULL, NULL },
+ { APILibraryLoader, "LoadLibraryExW", (PROC)MyLoadLibraryExW, NULL, NULL },
+ { APIConsole, "WriteConsoleA", (PROC)MyWriteConsoleA, NULL, NULL },
+ { APIConsole, "WriteConsoleW", (PROC)MyWriteConsoleW, NULL, NULL },
+ { APIFile, "WriteFile", (PROC)MyWriteFile, NULL, NULL },
+ { APIKernel, "_lwrite", (PROC)My_lwrite, NULL, NULL },
+ { APIKernel, "_hwrite", (PROC)My_hwrite, NULL, NULL },
+ { NULL, NULL, NULL, NULL, NULL }
+};
+
+//-----------------------------------------------------------------------------
+// OriginalAttr()
+// Determine the original attributes for use by \e[m.
+//-----------------------------------------------------------------------------
+void OriginalAttr( void )
+{
+ HANDLE hConOut;
+ CONSOLE_SCREEN_BUFFER_INFO csbi;
+
+ hConOut = CreateFile( L"CONOUT$", GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, OPEN_EXISTING, 0, 0 );
+ if (!GetConsoleScreenBufferInfo( hConOut, &csbi ))
+ csbi.wAttributes = 7;
+ CloseHandle( hConOut );
+
+ if (s_flag == GRM_INIT && s_pid == GetCurrentProcessId())
+ {
+ s_flag = 0;
+ grm = s_grm;
+ }
+ else
+ {
+ if (GetEnvironmentVariable( L"ANSICON_REVERSE", NULL, 0 ))
+ {
+ SetEnvironmentVariable( L"ANSICON_REVERSE", NULL );
+ grm.reverse = TRUE;
+ grm.foreground = attr2ansi[(csbi.wAttributes >> 4) & 7];
+ grm.background = attr2ansi[csbi.wAttributes & 7];
+ grm.bold = (csbi.wAttributes & BACKGROUND_INTENSITY) >> 4;
+ grm.underline = (csbi.wAttributes & FOREGROUND_INTENSITY) << 4;
+ }
+ else
+ {
+ grm.foreground = attr2ansi[csbi.wAttributes & 7];
+ grm.background = attr2ansi[(csbi.wAttributes >> 4) & 7];
+ grm.bold = csbi.wAttributes & FOREGROUND_INTENSITY;
+ grm.underline = csbi.wAttributes & BACKGROUND_INTENSITY;
+ }
+ }
+ if (!GetEnvironmentVariable( L"ANSICON_DEF", NULL, 0 ))
+ {
+ TCHAR def[4];
+ LPTSTR a = def;
+ if (grm.reverse)
+ {
+ *a++ = '-';
+ csbi.wAttributes = ((csbi.wAttributes >> 4) & 15)
+ | ((csbi.wAttributes & 15) << 4);
+ }
+ wsprintf( a, L"%X", csbi.wAttributes & 255 );
+ SetEnvironmentVariable( L"ANSICON_DEF", def );
+ }
+ set_ansicon( &csbi );
+}
+
+
+//-----------------------------------------------------------------------------
+// DllMain()
+// Function called by the system when processes and threads are initialized
+// and terminated.
+//-----------------------------------------------------------------------------
+
+__declspec(dllexport) // to stop MinGW exporting everything
+BOOL WINAPI DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved )
+{
+ BOOL bResult = TRUE;
+ PHookFn hook;
+ TCHAR logstr[4];
+
+ if (dwReason == DLL_PROCESS_ATTACH)
+ {
+ *logstr = '\0';
+ GetEnvironmentVariable( L"ANSICON_LOG", logstr, lenof(logstr) );
+ log_level = _wtoi( logstr );
+ prog = get_program_name( NULL );
+#if defined(_WIN64) || defined(W32ON64)
+ hDllNameType = hDllName - 6 +
+#endif
+ GetModuleFileName( hInstance, hDllName, lenof(hDllName) );
+
+ hDllInstance = hInstance; // save Dll instance handle
+ DEBUGSTR( 1, L"hDllInstance = %p", hDllInstance );
+
+ // Get the entry points to the original functions.
+ hKernel = GetModuleHandleA( APIKernel );
+ for (hook = Hooks; hook->name; ++hook)
+ hook->oldfunc = GetProcAddress( hKernel, hook->name );
+
+ bResult = HookAPIAllMod( Hooks, FALSE );
+ OriginalAttr();
+ DisableThreadLibraryCalls( hInstance );
+ }
+ else if (dwReason == DLL_PROCESS_DETACH)
+ {
+ if (lpReserved == NULL)
+ {
+ DEBUGSTR( 1, L"Unloading" );
+ HookAPIAllMod( Hooks, TRUE );
+ }
+ else
+ {
+ DEBUGSTR( 1, L"Terminating" );
+ s_pid = GetCurrentProcessId();
+ s_grm = grm;
+ s_flag = GRM_EXIT;
+ }
+ }
+
+ return bResult;
+}
diff --git a/ansicon/COPYING.MinGW-w64-runtime.txt b/ansicon/COPYING.MinGW-w64-runtime.txt
new file mode 100755
index 0000000..3d11e87
--- /dev/null
+++ b/ansicon/COPYING.MinGW-w64-runtime.txt
@@ -0,0 +1,240 @@
+MinGW-w64 runtime licensing
+***************************
+
+This program or library was built using MinGW-w64 and statically
+linked against the MinGW-w64 runtime. Some parts of the runtime
+are under licenses which require that the copyright and license
+notices are included when distributing the code in binary form.
+These notices are listed below.
+
+
+========================
+Overall copyright notice
+========================
+
+Copyright (c) 2009, 2010 by the mingw-w64 project
+
+This license has been certified as open source. It has also been designated
+as GPL compatible by the Free Software Foundation (FSF).
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions in source code must retain the accompanying copyright
+ notice, this list of conditions, and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the accompanying
+ copyright notice, this list of conditions, and the following disclaimer
+ in the documentation and/or other materials provided with the
+ distribution.
+ 3. Names of the copyright holders must not be used to endorse or promote
+ products derived from this software without prior written permission
+ from the copyright holders.
+ 4. The right to distribute this software or to use it for any purpose does
+ not give you the right to use Servicemarks (sm) or Trademarks (tm) of
+ the copyright holders. Use of them is covered by separate agreement
+ with the copyright holders.
+ 5. If any files are modified, you must cause the modified files to carry
+ prominent notices stating that you changed the files and the date of
+ any change.
+
+Disclaimer
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESSED
+OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+========================================
+getopt, getopt_long, and getop_long_only
+========================================
+
+Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+Sponsored in part by the Defense Advanced Research Projects
+Agency (DARPA) and Air Force Research Laboratory, Air Force
+Materiel Command, USAF, under agreement number F39502-99-1-0512.
+
+ * * * * * * *
+
+Copyright (c) 2000 The NetBSD Foundation, Inc.
+All rights reserved.
+
+This code is derived from software contributed to The NetBSD Foundation
+by Dieter Baron and Thomas Klausner.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+
+===============================================================
+gdtoa: Converting between IEEE floating point numbers and ASCII
+===============================================================
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1997, 1998, 1999, 2000, 2001 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+
+ * * * * * * *
+
+The author of this software is David M. Gay.
+
+Copyright (C) 2005 by David M. Gay
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that the copyright notice and this permission notice and warranty
+disclaimer appear in supporting documentation, and that the name of
+the author or any of his current or former employers not be used in
+advertising or publicity pertaining to distribution of the software
+without specific, written prior permission.
+
+THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+NO EVENT SHALL THE AUTHOR OR ANY OF HIS CURRENT OR FORMER EMPLOYERS BE
+LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
+DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+ * * * * * * *
+
+The author of this software is David M. Gay.
+
+Copyright (C) 2004 by David M. Gay.
+All Rights Reserved
+Based on material in the rest of /netlib/fp/gdota.tar.gz,
+which is copyright (C) 1998, 2000 by Lucent Technologies.
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+
+
+=========================
+Parts of the math library
+=========================
+
+Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+
+Developed at SunSoft, a Sun Microsystems, Inc. business.
+Permission to use, copy, modify, and distribute this
+software is freely granted, provided that this notice
+is preserved.
+
+ * * * * * * *
+
+Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+
+Developed at SunPro, a Sun Microsystems, Inc. business.
+Permission to use, copy, modify, and distribute this
+software is freely granted, provided that this notice
+is preserved.
+
+ * * * * * * *
+
+FIXME: Cephes math lib
+Copyright (C) 1984-1998 Stephen L. Moshier
+
+It sounds vague, but as to be found at
+<http://lists.debian.org/debian-legal/2004/12/msg00295.html>, it gives an
+impression that the author could be willing to give an explicit
+permission to distribute those files e.g. under a BSD style license. So
+probably there is no problem here, although it could be good to get a
+permission from the author and then add a license into the Cephes files
+in MinGW runtime. At least on follow-up it is marked that debian sees the
+version a-like BSD one. As MinGW.org (where those cephes parts are coming
+from) distributes them now over 6 years, it should be fine.
+
+===================================
+Headers and IDLs imported from Wine
+===================================
+
+Some header and IDL files were imported from the Wine project. These files
+are prominent maked in source. Their copyright belongs to contributors and
+they are distributed under LGPL license.
+
+Disclaimer
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
diff --git a/ansicon/G1.bat b/ansicon/G1.bat
new file mode 100755
index 0000000..37a6bb8
--- /dev/null
+++ b/ansicon/G1.bat
@@ -0,0 +1,18 @@
+@echo off & setlocal
+
+::Extract the current code page. Hopefully this method will work with other
+::languages. CHCP outputs: "Active code page: #". Take the last five
+::characters (the longest code) and delete up to and including the space.
+for /f "delims=" %%j in ('chcp') do set CP=%%j
+set CP=%CP:~-5%
+set CP=%CP:* =%
+
+x86\ansicon -e The DEC Special Graphics Character Set according to code page %CP%:^
+
+^
+
+ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { ^| } ~^
+
+^
+
+ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { ^| } ~
diff --git a/ansicon/G1.txt b/ansicon/G1.txt
new file mode 100755
index 0000000..a007b91
--- /dev/null
+++ b/ansicon/G1.txt
Binary files differ
diff --git a/ansicon/ansi.rc b/ansicon/ansi.rc
new file mode 100755
index 0000000..16a4585
--- /dev/null
+++ b/ansicon/ansi.rc
@@ -0,0 +1,42 @@
+/*
+ ansi.rc - Version resource for ANSI{32,64}.dll.
+
+ Jason Hood, 11 November, 2009.
+*/
+
+#include <winver.h>
+#include "version.h"
+
+#ifdef _WIN64
+# define BITS "64"
+#else
+# define BITS "32"
+#endif
+
+1 VERSIONINFO
+FILEVERSION PVERB
+PRODUCTVERSION PVERB
+FILEOS VOS_NT
+FILETYPE VFT_DLL
+{
+ BLOCK "StringFileInfo"
+ {
+ BLOCK "040904B0"
+ {
+ VALUE "Comments", "http://ansicon.adoxa.cjb.net/"
+ VALUE "CompanyName", "Jason Hood"
+ VALUE "FileDescription", "ANSI Console"
+ VALUE "FileVersion", PVERSA
+ VALUE "InternalName", "ANSI" BITS
+ VALUE "LegalCopyright", "Freeware"
+ VALUE "OriginalFilename", "ANSI" BITS ".dll"
+ VALUE "ProductName", "ANSICON"
+ VALUE "ProductVersion", PVERSA
+ }
+ }
+
+ BLOCK "VarFileInfo"
+ {
+ VALUE "Translation", 0x0409, 0x04B0
+ }
+}
diff --git a/ansicon/ansicon.c b/ansicon/ansicon.c
new file mode 100755
index 0000000..2b87abe
--- /dev/null
+++ b/ansicon/ansicon.c
@@ -0,0 +1,686 @@
+/*
+ ANSICON.c - ANSI escape sequence console driver.
+
+ Jason Hood, 21 to 23 October, 2005.
+
+ Original injection code was derived from Console Manager by Sergey Oblomov
+ (hoopoepg). Use of FlushInstructionCache came from www.catch22.net.
+ Additional information came from "Process-wide API spying - an ultimate hack",
+ Anton Bassov's article in "The Code Project" (use of OpenThread).
+
+ v1.01, 11 & 12 March, 2006:
+ -m option to set "monochrome" (grey on black);
+ restore original color on exit.
+
+ v1.10, 22 February, 2009:
+ ignore Ctrl+C/Ctrl+Break.
+
+ v1.13, 21 & 27 March, 2009:
+ alternate injection method, to work with DEP;
+ use Unicode.
+
+ v1.20, 17 to 21 June, 2009:
+ use a combination of the two injection methods;
+ test if ANSICON is already installed;
+ added -e (and -E) option to echo the command line (without newline);
+ added -t (and -T) option to type (display) files (with file name).
+
+ v1.21, 23 September, 2009:
+ added -i (and -u) to add (remove) ANSICON to AutoRun.
+
+ v1.24, 6 & 7 January, 2010:
+ no arguments to -t, or using "-" for the name, will read from stdin;
+ fix -t and -e when ANSICON was already loaded.
+
+ v1.25, 22 July, 2010:
+ added -IU for HKLM.
+
+ v1.30, 3 August to 7 September, 2010:
+ x64 support.
+
+ v1.31, 13 & 15 November, 2010:
+ use LLW to fix potential Unicode path problems;
+ VC compatibility (2008 Express for 32-bit, PSDK 2003 R2 for 64-bit);
+ explicitly use wide characters (stick with TCHAR, but not <tchar.h>).
+
+ v1.32, 4 to 22 December, 2010:
+ make -p more robust;
+ inject into GUI processes;
+ -i implies -p.
+
+ v1.50, 7 to 14 December, 2011:
+ -u does not imply -p;
+ add the PID to the debugging output;
+ use ANSICON_VER to test if already installed;
+ always place first in AutoRun;
+ logging is always available, controlled by ANSICON_LOG environment variable;
+ only restore the original color after program/echo/type;
+ return program's exit code.
+
+ 7 January, 2012:
+ fixed installing into a piped CMD.EXE;
+ added a log message indicating all imports have been processed.
+
+ v1.52, 10 April, 2012:
+ fixed running "cmd" if "ComSpec" is not defined;
+ pass process & thread identifiers on the command line (for x86->x64).
+*/
+
+#define PDATE L"12 June, 2012"
+
+#include "ansicon.h"
+#include "version.h"
+#include <tlhelp32.h>
+#include <ctype.h>
+#include <io.h>
+
+#ifdef __MINGW32__
+int _CRT_glob = 0;
+#endif
+
+
+#ifdef _WIN64
+# define BITS L"64"
+#else
+# define BITS L"32"
+#endif
+
+
+#define CMDKEY L"Software\\Microsoft\\Command Processor"
+#define AUTORUN L"AutoRun"
+
+
+void help( void );
+
+void display( LPCTSTR, BOOL );
+void print_error( LPCTSTR, ... );
+LPTSTR skip_spaces( LPTSTR );
+void get_arg( LPTSTR, LPTSTR*, LPTSTR* );
+
+void process_autorun( TCHAR );
+
+BOOL find_proc_id( HANDLE snap, DWORD id, LPPROCESSENTRY32 ppe );
+BOOL GetParentProcessInfo( LPPROCESS_INFORMATION ppi, LPTSTR );
+
+
+// Find the name of the DLL and inject it.
+BOOL Inject( LPPROCESS_INFORMATION ppi, BOOL* gui, LPCTSTR app )
+{
+ DWORD len;
+ WCHAR dll[MAX_PATH];
+ int type;
+
+ DEBUGSTR( 1, L"%s (%lu)", app, ppi->dwProcessId );
+ type = ProcessType( ppi, gui );
+ if (type == 0)
+ {
+ fwprintf( stderr, L"ANSICON: %s: unsupported process.\n", app );
+ return FALSE;
+ }
+
+ len = (DWORD)(prog - prog_path);
+ memcpy( dll, prog_path, TSIZE(len) );
+#ifdef _WIN64
+ wsprintf( dll + len, L"ANSI%d.dll", type );
+ if (type == 32)
+ InjectDLL32( ppi, dll );
+ else
+ InjectDLL64( ppi, dll );
+#else
+ wcscpy( dll + len, L"ANSI32.dll" );
+ InjectDLL32( ppi, dll );
+#endif
+ return TRUE;
+}
+
+
+static HANDLE hConOut;
+static CONSOLE_SCREEN_BUFFER_INFO csbi;
+
+void get_original_attr( void )
+{
+ hConOut = CreateFile( L"CONOUT$", GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, OPEN_EXISTING, 0, 0 );
+ GetConsoleScreenBufferInfo( hConOut, &csbi );
+}
+
+
+void set_original_attr( void )
+{
+ SetConsoleTextAttribute( hConOut, csbi.wAttributes );
+ CloseHandle( hConOut );
+}
+
+
+DWORD CtrlHandler( DWORD event )
+{
+ return (event == CTRL_C_EVENT || event == CTRL_BREAK_EVENT);
+}
+
+
+int main( void )
+{
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+ LPTSTR argv, arg, cmd;
+ TCHAR logstr[4];
+ BOOL installed;
+ BOOL shell, run, gui;
+ HMODULE ansi;
+ DWORD len;
+ int rc = 0;
+
+ argv = GetCommandLine();
+ len = (DWORD)wcslen( argv ) + 1;
+ if (len < MAX_PATH)
+ len = MAX_PATH;
+ arg = malloc( TSIZE(len) );
+ get_arg( arg, &argv, &cmd ); // skip the program name
+ get_arg( arg, &argv, &cmd );
+
+ if (*arg)
+ {
+ if (wcscmp( arg, L"/?" ) == 0 ||
+ wcscmp( arg, L"--help" ) == 0)
+ {
+ help();
+ return rc;
+ }
+ if (wcscmp( arg, L"--version" ) == 0)
+ {
+ _putws( L"ANSICON (" BITS L"-bit) version " PVERS L" (" PDATE L")." );
+ return rc;
+ }
+ }
+
+ prog = get_program_name( NULL );
+ *logstr = '\0';
+ GetEnvironmentVariable( L"ANSICON_LOG", logstr, lenof(logstr) );
+ log_level = _wtoi( logstr );
+
+#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.hThread = OpenThread( THREAD_ALL_ACCESS, FALSE, pi.dwThreadId );
+ Inject( &pi, &gui, arg );
+ CloseHandle( pi.hThread );
+ CloseHandle( pi.hProcess );
+ return 0;
+ }
+#endif
+
+ if (log_level && !(log_level & 8))
+ DEBUGSTR( 1, NULL ); // create a new file
+
+ 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)
+ {
+ fputws( L"\33[m", stdout );
+ FreeLibrary( GetModuleHandle( L"ANSI" BITS L".dll" ) );
+ }
+
+ shell = run = TRUE;
+ get_original_attr();
+
+ while (*arg == '-')
+ {
+ switch (arg[1])
+ {
+ 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
+ break;
+
+ case 'i':
+ case 'I':
+ case 'u':
+ case 'U':
+ shell = FALSE;
+ process_autorun( arg[1] );
+ if (arg[1] == 'u' || arg[1] == 'U')
+ break;
+ // else fall through
+
+ case 'p':
+ shell = FALSE;
+ // If it's already installed, there's no need to do anything.
+ if (installed)
+ {
+ DEBUGSTR( 1, L"Already installed" );
+ }
+ else if (GetParentProcessInfo( &pi, arg ))
+ {
+ pi.hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pi.dwProcessId);
+ pi.hThread = OpenThread( THREAD_ALL_ACCESS, FALSE, pi.dwThreadId );
+ SuspendThread( pi.hThread );
+ if (!Inject( &pi, &gui, arg ))
+ rc = 1;
+ ResumeThread( pi.hThread );
+ CloseHandle( pi.hThread );
+ CloseHandle( pi.hProcess );
+ }
+ else
+ {
+ fputws( L"ANSICON: could not obtain the parent process.\n", stderr );
+ rc = 1;
+ }
+ break;
+
+ case 'm':
+ {
+ int a = wcstol( arg + 2, NULL, 16 );
+ if (a == 0)
+ a = (arg[2] == '-') ? -7 : 7;
+ if (a < 0)
+ {
+ SetEnvironmentVariable( L"ANSICON_REVERSE", L"1" );
+ a = -a;
+ a = ((a >> 4) & 15) | ((a & 15) << 4);
+ }
+ SetConsoleTextAttribute( hConOut, a );
+ SetEnvironmentVariable( L"ANSICON_DEF", NULL );
+ break;
+ }
+
+ case 'e':
+ case 'E':
+ case 't':
+ case 'T':
+ run = FALSE;
+ ++arg;
+ goto arg_out;
+ }
+ get_arg( arg, &argv, &cmd );
+ }
+arg_out:
+ if (run && *cmd == '\0')
+ {
+ if (!shell)
+ run = FALSE;
+ else if (!_isatty( 0 ))
+ {
+ *arg = 't';
+ run = FALSE;
+ }
+ }
+
+ if (run)
+ {
+ if (*cmd == '\0')
+ {
+ cmd = _wgetenv( L"ComSpec" );
+ if (cmd == NULL)
+ {
+ // 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) );
+ si.cb = sizeof(si);
+ if (CreateProcess( NULL, cmd, NULL, NULL, TRUE, CREATE_SUSPENDED,
+ NULL, NULL, &si, &pi ))
+ {
+ Inject( &pi, &gui, arg );
+ ResumeThread( pi.hThread );
+ if (!gui)
+ {
+ SetConsoleCtrlHandler( (PHANDLER_ROUTINE)CtrlHandler, TRUE );
+ WaitForSingleObject( pi.hProcess, INFINITE );
+ GetExitCodeProcess( pi.hProcess, (LPDWORD)(LPVOID)&rc );
+ }
+ CloseHandle( pi.hProcess );
+ CloseHandle( pi.hThread );
+ }
+ else
+ {
+ print_error( arg, arg );
+ rc = 1;
+ }
+ }
+ else if (*arg)
+ {
+ ansi = LoadLibrary( L"ANSI" BITS L".dll" );
+ if (ansi == NULL)
+ {
+ print_error( L"ANSI" BITS L".dll" );
+ rc = 1;
+ }
+
+ if (*arg == 'e' || *arg == 'E')
+ {
+ cmd += 2;
+ if (*cmd == ' ' || *cmd == '\t')
+ ++cmd;
+ fputws( cmd, stdout );
+ if (*arg == 'e')
+ putwchar( '\n' );
+ }
+ else // (*arg == 't' || *arg == 'T')
+ {
+ BOOL title = (*arg == 'T');
+ get_arg( arg, &argv, &cmd );
+ if (*arg == '\0')
+ wcscpy( arg, L"-" );
+ do
+ {
+ if (title)
+ {
+ wprintf( L"==> %s <==\n", arg );
+ display( arg, title );
+ putwchar( '\n' );
+ }
+ else
+ display( arg, title );
+ get_arg( arg, &argv, &cmd );
+ } while (*arg);
+ }
+
+ FreeLibrary( ansi );
+ }
+
+ if (run || *arg)
+ set_original_attr();
+ else
+ CloseHandle( hConOut );
+
+ return rc;
+}
+
+
+// Display a file.
+void display( LPCTSTR name, BOOL title )
+{
+ HANDLE in, out;
+ BOOL pipe;
+ char buf[8192];
+ DWORD len;
+
+ if (*name == '-' && name[1] == '\0')
+ {
+ pipe = TRUE;
+ in = GetStdHandle( STD_INPUT_HANDLE );
+ }
+ else
+ {
+ pipe = FALSE;
+ in = CreateFile( name, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, OPEN_EXISTING, 0, NULL );
+ if (in == INVALID_HANDLE_VALUE)
+ {
+ print_error( name );
+ return;
+ }
+ }
+ if (title)
+ {
+ putwchar( '\n' );
+ // Need to flush, otherwise it's written *after* STD_OUTPUT_HANDLE should
+ // it be redirected.
+ fflush( stdout );
+ }
+ out = GetStdHandle( STD_OUTPUT_HANDLE );
+ for (;;)
+ {
+ if (!ReadFile( in, buf, sizeof(buf), &len, NULL ))
+ {
+ if (GetLastError() != ERROR_BROKEN_PIPE)
+ print_error( name );
+ break;
+ }
+ if (len == 0)
+ break;
+ WriteFile( out, buf, len, &len, NULL );
+ }
+ if (!pipe)
+ CloseHandle( in );
+}
+
+
+void print_error( LPCTSTR name, ... )
+{
+ LPTSTR errmsg = NULL;
+ DWORD err = GetLastError();
+ va_list arg;
+
+ 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 );
+ }
+ 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 );
+ else
+ fwprintf( stderr, L"ANSICON: %s: %s", name, errmsg );
+ }
+ LocalFree( errmsg );
+}
+
+
+// Add or remove ANSICON to AutoRun.
+void process_autorun( TCHAR cmd )
+{
+ HKEY cmdkey;
+ TCHAR ansicon[MAX_PATH+80];
+ TCHAR logstr[80];
+ LPTSTR autorun, ansirun;
+ DWORD len, type, exist;
+ BOOL inst;
+
+ if (log_level)
+ _snwprintf( logstr, lenof(logstr), L"set ANSICON_LOG=%d&", log_level );
+ else
+ *logstr = '\0';
+ len = TSIZE(_snwprintf( ansicon, lenof(ansicon),
+ L"(if %%ANSICON_VER%%==^%%ANSICON_VER^%% %s\"%s\" -p)",
+ logstr, prog_path ) + 1);
+
+ inst = (towlower( cmd ) == 'i');
+ RegCreateKeyEx( (iswlower( cmd )) ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE,
+ CMDKEY, 0, NULL,
+ REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
+ &cmdkey, &exist );
+ exist = 0;
+ RegQueryValueEx( cmdkey, AUTORUN, NULL, NULL, NULL, &exist );
+ if (exist == 0)
+ {
+ if (inst)
+ RegSetValueEx( cmdkey, AUTORUN, 0, REG_SZ, (PBYTE)ansicon, len );
+ }
+ else
+ {
+ // Let's assume there's sufficient memory.
+ autorun = malloc( exist + len );
+ RegQueryValueEx( cmdkey, AUTORUN, NULL, &type, (PBYTE)autorun, &exist );
+ // Remove the existing command, if present.
+ ansirun = wcsstr( autorun, L"(if %ANSICON_VER%" );
+ if (ansirun != NULL)
+ {
+ LPTSTR tmp = wcschr( ansirun, '"' ); // opening quote
+ tmp = wcschr( tmp + 1, '"' ); // closing quote
+ tmp = wcschr( tmp + 1, ')' ); // closing bracket
+ if (*++tmp == '&')
+ ++tmp;
+ if (*tmp == '&')
+ ++tmp;
+ if (*tmp == '\0')
+ {
+ if (ansirun > autorun && ansirun[-1] == '&')
+ --ansirun;
+ if (ansirun > autorun && ansirun[-1] == '&')
+ --ansirun;
+ }
+ wcscpy( ansirun, tmp );
+ exist = TSIZE((DWORD)wcslen( autorun ) + 1);
+ }
+ if (inst)
+ {
+ if (exist == sizeof(TCHAR))
+ RegSetValueEx( cmdkey, AUTORUN, 0, REG_SZ, (PBYTE)ansicon, len );
+ else
+ {
+ memmove( (PBYTE)autorun + len, autorun, exist );
+ memcpy( autorun, ansicon, len );
+ ((PBYTE)autorun)[len-sizeof(TCHAR)] = '&';
+ RegSetValueEx( cmdkey, AUTORUN, 0, type, (PBYTE)autorun, exist+len );
+ }
+ }
+ else
+ {
+ if (exist == sizeof(TCHAR))
+ RegDeleteValue( cmdkey, AUTORUN );
+ else
+ RegSetValueEx( cmdkey, AUTORUN, 0, type, (PBYTE)autorun, exist );
+ }
+ free( autorun );
+ }
+ RegCloseKey( cmdkey );
+}
+
+
+// Search each process in the snapshot for id.
+BOOL find_proc_id( HANDLE snap, DWORD id, LPPROCESSENTRY32 ppe )
+{
+ BOOL fOk;
+
+ ppe->dwSize = sizeof(PROCESSENTRY32);
+ for (fOk = Process32First( snap, ppe ); fOk; fOk = Process32Next( snap, ppe ))
+ if (ppe->th32ProcessID == id)
+ break;
+
+ return fOk;
+}
+
+
+// Obtain the process and thread identifiers of the parent process.
+BOOL GetParentProcessInfo( LPPROCESS_INFORMATION ppi, LPTSTR name )
+{
+ HANDLE hSnap;
+ PROCESSENTRY32 pe;
+ THREADENTRY32 te;
+ BOOL fOk;
+
+ hSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS|TH32CS_SNAPTHREAD, 0 );
+
+ if (hSnap == INVALID_HANDLE_VALUE)
+ return FALSE;
+
+ find_proc_id( hSnap, GetCurrentProcessId(), &pe );
+ if (!find_proc_id( hSnap, pe.th32ParentProcessID, &pe ))
+ {
+ CloseHandle( hSnap );
+ return FALSE;
+ }
+
+ te.dwSize = sizeof(te);
+ for (fOk = Thread32First( hSnap, &te ); fOk; fOk = Thread32Next( hSnap, &te ))
+ if (te.th32OwnerProcessID == pe.th32ProcessID)
+ break;
+
+ CloseHandle( hSnap );
+
+ ppi->dwProcessId = pe.th32ProcessID;
+ ppi->dwThreadId = te.th32ThreadID;
+ wcscpy( name, pe.szExeFile );
+
+ return fOk;
+}
+
+
+// Return the first non-space character from arg.
+LPTSTR skip_spaces( LPTSTR arg )
+{
+ while (*arg == ' ' || *arg == '\t')
+ ++arg;
+
+ return arg;
+}
+
+
+// Retrieve an argument from the command line. cmd gets the existing argv; argv
+// is ready for the next argument.
+void get_arg( LPTSTR arg, LPTSTR* argv, LPTSTR* cmd )
+{
+ LPTSTR line;
+
+ line = *cmd = skip_spaces( *argv );
+ while (*line != '\0')
+ {
+ if (*line == ' ' || *line == '\t')
+ {
+ ++line;
+ break;
+ }
+ if (*line == '"')
+ {
+ while (*++line != '\0')
+ {
+ if (*line == '"')
+ {
+ ++line;
+ break;
+ }
+ *arg++ = *line;
+ }
+ }
+ else
+ *arg++ = *line++;
+ }
+ *arg = '\0';
+ *argv = line;
+}
+
+
+void help( void )
+{
+ _putws(
+L"ANSICON by Jason Hood <jadoxa@yahoo.com.au>.\n"
+L"Version " PVERS L" (" PDATE L"). Freeware.\n"
+L"http://ansicon.adoxa.cjb.net/\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"\n"
+L"ansicon [-l<level>] [-i] [-I] [-u] [-U] [-m[<attr>]] [-p]\n"
+L" [-e|E string | -t|T [file(s)] | program [args]]\n"
+L"\n"
+L" -l\t\tset the logging level (1=process, 2=module, 3=function,\n"
+L" \t\t +4=output, +8=append) for program (-p is unaffected)\n"
+L" -i\t\tinstall - add ANSICON to the AutoRun entry (also implies -p)\n"
+L" -u\t\tuninstall - remove ANSICON from the AutoRun entry\n"
+L" -I -U\t\tuse local machine instead of current user\n"
+L" -m\t\tuse grey on black (\"monochrome\") or <attr> as default color\n"
+L" -p\t\thook into the parent process\n"
+L" -e\t\techo string\n"
+L" -E\t\techo string, don't append newline\n"
+L" -t\t\tdisplay files (\"-\" for stdin), combined as a single stream\n"
+L" -T\t\tdisplay files, name first, blank line before and after\n"
+L" program\trun the specified program\n"
+L" nothing\trun a new command processor, or display stdin if redirected\n"
+L"\n"
+L"<attr> is one or two hexadecimal digits; please use \"COLOR /?\" for details.\n"
+L"It may start with '-' to reverse foreground and background (but not for -p)."
+ );
+}
diff --git a/ansicon/ansicon.h b/ansicon/ansicon.h
new file mode 100755
index 0000000..8819186
--- /dev/null
+++ b/ansicon/ansicon.h
@@ -0,0 +1,47 @@
+/*
+ ansicon.h - Header file for common definitions.
+
+ Jason Hood, 12 December, 2010 (originally injdll.h, 20 June, 2009).
+*/
+
+#ifndef ANSICON_H
+#define ANSICON_H
+
+#ifndef UNICODE
+# define UNICODE
+#endif
+
+#define WIN32_LEAN_AND_MEAN
+#define _WIN32_WINNT 0x0500 // MinGW wants this defined for OpenThread
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define lenof(array) (sizeof(array)/sizeof(*(array)))
+#define TSIZE(size) ((size) * sizeof(TCHAR))
+
+
+typedef struct
+{
+ BYTE foreground; // ANSI base color (0 to 7; add 30)
+ BYTE background; // ANSI base color (0 to 7; add 40)
+ BYTE bold; // console FOREGROUND_INTENSITY bit
+ BYTE underline; // console BACKGROUND_INTENSITY bit
+ BYTE rvideo; // swap foreground/bold & background/underline
+ BYTE concealed; // set foreground/bold to background/underline
+ BYTE reverse; // swap console foreground & background attributes
+} GRM, *PGRM; // Graphic Rendition Mode
+
+
+int ProcessType( LPPROCESS_INFORMATION, BOOL* );
+void InjectDLL32( LPPROCESS_INFORMATION, LPCTSTR );
+void InjectDLL64( LPPROCESS_INFORMATION, LPCTSTR );
+
+extern TCHAR prog_path[MAX_PATH];
+extern LPTSTR prog;
+LPTSTR get_program_name( LPTSTR );
+
+extern int log_level;
+void DEBUGSTR( int level, LPTSTR szFormat, ... );
+
+#endif
diff --git a/ansicon/ansicon.rc b/ansicon/ansicon.rc
new file mode 100755
index 0000000..09b03c1
--- /dev/null
+++ b/ansicon/ansicon.rc
@@ -0,0 +1,36 @@
+/*
+ ansicon.rc - Version resource for ansicon.exe.
+
+ Jason Hood, 11 November, 2009.
+*/
+
+#include <winver.h>
+#include "version.h"
+
+1 VERSIONINFO
+FILEVERSION PVERB
+PRODUCTVERSION PVERB
+FILEOS VOS_NT
+FILETYPE VFT_APP
+{
+ BLOCK "StringFileInfo"
+ {
+ BLOCK "040904B0"
+ {
+ VALUE "Comments", "http://ansicon.adoxa.cjb.net/"
+ VALUE "CompanyName", "Jason Hood"
+ VALUE "FileDescription", "ANSI Console"
+ VALUE "FileVersion", PVERSA
+ VALUE "InternalName", "ansicon"
+ VALUE "LegalCopyright", "Freeware"
+ VALUE "OriginalFilename", "ansicon.exe"
+ VALUE "ProductName", "ANSICON"
+ VALUE "ProductVersion", PVERSA
+ }
+ }
+
+ BLOCK "VarFileInfo"
+ {
+ VALUE "Translation", 0x0409, 0x04B0
+ }
+}
diff --git a/ansicon/injdll32.c b/ansicon/injdll32.c
new file mode 100755
index 0000000..25ed7ae
--- /dev/null
+++ b/ansicon/injdll32.c
@@ -0,0 +1,123 @@
+/*
+ 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
+#if defined(__MINGW64__) || (defined(_MSC_VER) && _MSC_VER <= 1400)
+#include "wow64.h"
+
+TWow64GetThreadContext Wow64GetThreadContext;
+TWow64SetThreadContext Wow64SetThreadContext;
+#endif
+
+#define CONTEXT WOW64_CONTEXT
+#undef CONTEXT_CONTROL
+#define CONTEXT_CONTROL WOW64_CONTEXT_CONTROL
+#define GetThreadContext Wow64GetThreadContext
+#define SetThreadContext Wow64SetThreadContext
+#endif
+
+
+DWORD LLW;
+
+
+void InjectDLL32( LPPROCESS_INFORMATION ppi, LPCTSTR dll )
+{
+ CONTEXT context;
+ DWORD len;
+ LPVOID mem;
+ DWORD mem32;
+ #define CODESIZE 20
+ BYTE code[CODESIZE+TSIZE(MAX_PATH)];
+ union
+ {
+ PBYTE pB;
+ PDWORD pL;
+ } ip;
+
+ len = TSIZE(lstrlen( dll ) + 1);
+ if (len > TSIZE(MAX_PATH))
+ return;
+
+ if (LLW == 0)
+ {
+ HMODULE hKernel = GetModuleHandleA( "kernel32.dll" );
+#ifdef _WIN64
+#ifdef __MINGW64__
+ #define GETPROC( proc ) proc = (T##proc)GetProcAddress( hKernel, #proc )
+ 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.\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
+ }
+
+ CopyMemory( code + CODESIZE, dll, len );
+ len += CODESIZE;
+
+ context.ContextFlags = CONTEXT_CONTROL;
+ GetThreadContext( ppi->hThread, &context );
+ mem = VirtualAllocEx( ppi->hProcess, NULL, len, MEM_COMMIT,
+ PAGE_EXECUTE_READWRITE );
+ mem32 = (DWORD)(DWORD_PTR)mem;
+
+ ip.pB = code;
+
+ *ip.pB++ = 0x68; // push eip
+ *ip.pL++ = context.Eip;
+ *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 );
+ context.Eip = mem32;
+ SetThreadContext( ppi->hThread, &context );
+}
diff --git a/ansicon/injdll64.c b/ansicon/injdll64.c
new file mode 100755
index 0000000..c46bd46
--- /dev/null
+++ b/ansicon/injdll64.c
@@ -0,0 +1,96 @@
+/*
+ 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"
+
+void InjectDLL64( LPPROCESS_INFORMATION ppi, LPCTSTR dll )
+{
+ CONTEXT context;
+ DWORD len;
+ LPVOID mem;
+ DWORD64 LLW;
+ union
+ {
+ PBYTE pB;
+ PDWORD64 pL;
+ } ip;
+ #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;
+ GetThreadContext( ppi->hThread, &context );
+ mem = VirtualAllocEx( ppi->hProcess, NULL, len, MEM_COMMIT,
+ PAGE_EXECUTE_READWRITE );
+ LLW = (DWORD64)LoadLibraryW;
+
+ ip.pB = code;
+
+ *ip.pL++ = context.Rip;
+ *ip.pL++ = LLW;
+
+ WriteProcessMemory( ppi->hProcess, mem, code, len, NULL );
+ FlushInstructionCache( ppi->hProcess, mem, len );
+ context.Rip = (DWORD64)mem + 16;
+ SetThreadContext( ppi->hThread, &context );
+}
diff --git a/ansicon/makefile b/ansicon/makefile
new file mode 100755
index 0000000..0007bee
--- /dev/null
+++ b/ansicon/makefile
@@ -0,0 +1,82 @@
+# Makefile for ANSICON.
+# Jason Hood, 11 March, 2006. Updated 20 June, 2009.
+
+# I've used TDM64 (gcc 4.6.1), building the 32-bit version in the x86 directory
+# and the 64-bit version in the x64 directory. MinGW32 (gcc 3.4.5) will also
+# build the 32-bit version.
+
+# 19 November, 2010:
+# explicitly use 64-bit flags, in case the compiler isn't.
+#
+# 13 December, 2011:
+# use CMD for file operations, not programs from fileutils.
+
+CC = gcc
+CFLAGS = -O2 -Wall
+
+X86OBJS = x86/proctype.o x86/injdll32.o x86/util.o
+X64OBJS = x64/proctype.o x64/injdll64.o x64/injdll32.o x64/util.o
+
+x86/%.o: %.c ansicon.h
+ $(CC) -m32 -c $(CFLAGS) $< -o $@
+
+x86/%v.o: %.rc version.h
+ windres -U _WIN64 -F pe-i386 $< $@
+
+x64/%.o: %.c ansicon.h
+ $(CC) -m64 -c $(CFLAGS) $< -o $@
+
+x64/%v.o: %.rc version.h
+ windres -F pe-x86-64 $< $@
+
+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
+
+x86:
+ cmd /c "mkdir x86"
+
+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
+
+x64:
+ cmd /c "mkdir x64"
+
+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
+
+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 $@
+
+x86/ansicon.o: version.h
+x86/ANSI.o: version.h
+x64/ansicon.o: version.h
+x64/ANSI.o: version.h
+x86/util.o: version.h
+x64/util.o: version.h
+x86/ansiconv.o: ansicon.rc
+x86/ansiv.o: ansi.rc
+x64/ansiconv.o: ansicon.rc
+x64/ansiv.o: ansi.rc
+
+x64/ANSI32.o: ANSI.c
+ $(CC) -m32 -DW32ON64 $(CFLAGS) $< -c -o $@
+x64/proctype32.o: proctype.c
+ $(CC) -m32 -DW32ON64 $(CFLAGS) $< -c -o $@
+
+# Need two commands, because if the directory doesn't exist, it won't delete
+# anything at all.
+clean:
+ -cmd /c "del x86\*.o 2>nul"
+ -cmd /c "del x64\*.o 2>nul"
diff --git a/ansicon/makefile.vc b/ansicon/makefile.vc
new file mode 100755
index 0000000..da71872
--- /dev/null
+++ b/ansicon/makefile.vc
@@ -0,0 +1,88 @@
+# VC makefile for ANSICON.
+# Jason Hood, 15 November, 2010.
+
+# I've used Visual C++ 2008 Express for the 32-bit version and the 2003 R2
+# Platform SDK for the 64-bit version. Since these are entirely separate
+# environments, define BITS to decide which should be built. Note that the
+# 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.
+
+#BITS = 32
+#BITS = 64
+
+!IFNDEF BITS
+BITS = 32
+!ENDIF
+
+!IF $(BITS) == 32
+DIR = x86
+!ELSE
+!IF $(BITS) == 64
+DIR = x64
+!ELSE
+!ERROR BITS should be defined to 32 or 64.
+!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
+
+X86OBJS = x86\proctype.obj x86\injdll32.obj x86\util.obj
+X64OBJS = x64\proctype.obj x64\injdll64.obj x64\injdll32.obj x64\util.obj
+
+{}.c{$(DIR)}.obj:
+ $(CC) /c $(CFLAGS) /Fo$@ $<
+
+{}.rc{$(DIR)}.res:
+ rc /fo$@ $<
+
+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
+
+x86:
+ mkdir x86
+
+x86\ansicon.exe: x86\ansicon.obj $(X86OBJS) x86\ansicon.res
+ $(CC) /nologo /Fe$@ $** $(LIBS)
+
+x86\ANSI32.dll: x86\ANSI.obj $(X86OBJS) x86\ansi.res
+ $(CC) /nologo /LD /Fe$@ $** $(LIBS)
+
+x64:
+ mkdir x64
+
+x64\ansicon.exe: x64\ansicon.obj $(X64OBJS) x64\ansicon.res
+ $(CC) /nologo /Fe$@ $** $(LIBS) $(LIBS64)
+
+x64\ANSI64.dll: x64\ANSI.obj $(X64OBJS) x64\ansi.res
+ $(CC) /nologo /LD /Fe$@ $** $(LIBS) $(LIBS64)
+
+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)
+
+ansicon.c: ansicon.h version.h
+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
+proctype.c: ansicon.h
+
+x64\ANSI32.obj: ANSI.c
+ $(CC) /DW32ON64 /c $(CFLAGS) /Fo$@ $?
+x64\proctype32.obj: proctype.c
+ $(CC) /DW32ON64 /c $(CFLAGS) /Fo$@ $?
+
+clean:
+ -del $(DIR)\*.obj $(DIR)\*.res $(DIR)\*.lib $(DIR)\*.exp
diff --git a/ansicon/proctype.c b/ansicon/proctype.c
new file mode 100755
index 0000000..27399cd
--- /dev/null
+++ b/ansicon/proctype.c
@@ -0,0 +1,105 @@
+/*
+ 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.
+*/
+
+#include "ansicon.h"
+
+
+int ProcessType( LPPROCESS_INFORMATION pinfo, BOOL* gui )
+{
+ char* ptr;
+ MEMORY_BASIC_INFORMATION minfo;
+ IMAGE_DOS_HEADER dos_header;
+ IMAGE_NT_HEADERS nt_header;
+ SIZE_T read;
+
+ *gui = FALSE;
+ for (ptr = NULL;
+ VirtualQueryEx( pinfo->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 (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)
+ {
+ 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 );
+ return 32;
+ }
+#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 );
+ 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" );
+ return 64;
+ }
+#endif
+ DEBUGSTR( 1, L" Ignoring unsupported machine (0x%X)",
+ nt_header.FileHeader.Machine );
+ }
+ else
+ {
+ DEBUGSTR( 1, L" Ignoring unsupported subsystem (%u)",
+ nt_header.OptionalHeader.Subsystem );
+ }
+ return 0;
+ }
+ }
+ }
+ }
+#ifdef _WIN32
+ // If a 32-bit process manages to load a 64-bit one, we may miss the base
+ // address. If the pointer overflows, assume 64-bit and abort.
+ if (ptr > ptr + minfo.RegionSize)
+ {
+#ifdef W32ON64
+ DEBUGSTR( 1, L" Pointer overflow: assuming 64-bit console" );
+ return 64;
+#else
+ DEBUGSTR( 1, L" Ignoring apparent 64-bit process" );
+ return 0;
+#endif
+ }
+#endif
+ }
+
+ DEBUGSTR( 1, L" Ignoring non-Windows process" );
+ return 0;
+}
diff --git a/ansicon/readme.txt b/ansicon/readme.txt
new file mode 100755
index 0000000..78f00eb
--- /dev/null
+++ b/ansicon/readme.txt
@@ -0,0 +1,439 @@
+
+ ANSICON
+
+ Copyright 2005-2012 Jason Hood
+
+ Version 1.53. Freeware
+
+
+ ===========
+ Description
+ ===========
+
+ ANSICON provides ANSI escape sequences for Windows console programs. It
+ provides much the same functionality as `ANSI.SYS' does for MS-DOS.
+
+
+ ============
+ Requirements
+ ============
+
+ Windows 2000 Professional and later (it won't work with NT or 9X).
+
+
+ ============
+ Installation
+ ============
+
+ Add x86 (if your OS is 32-bit) or x64 (if 64-bit) to your PATH, or copy
+ the relevant files to a directory already on the PATH. Alternatively,
+ use option `-i' (or `-I') to install it permanently, by adding an entry
+ to CMD.EXE's AutoRun registry value (current user or local machine,
+ respectively). Uninstall simply involves closing any programs that are
+ currently using it, running with `-u' (and/or `-U') to remove the Auto-
+ Run entry/ies, then removing the directory from PATH or deleting the
+ files. No other changes are made.
+
+ ---------
+ Upgrading
+ ---------
+
+ Delete ANSI.dll, it has been replaced with ANSI32.dll.
+ Delete ANSI-LLA.dll, it has been replaced with ANSI-LLW.dll.
+ Uninstall a pre-1.50 version and reinstall with this version.
+
+
+ =====
+ Usage
+ =====
+
+ Options (case sensitive):
+
+ -l Log to %temp%\ansicon.log.
+
+ -p Enable the parent process (i.e. the command shell used to
+ run ANSICON) to recognise escapes.
+
+ -m Set the current (and default) attribute to grey on black
+ ("monochrome"), or the attribute following the `m' (please
+ use `COLOR /?' for attribute values).
+
+ -e Echo the command line - a space or tab after the `e' is
+ ignored, the remainder is displayed verbatim.
+
+ -E As above, but no newline is added.
+
+ -t Display ("type") each file (or standard input if none or the
+ name is "-") as though they are a single file.
+
+ -T Display "==> FILE NAME <==", a blank line (or an error
+ message), the file and another blank line.
+
+ Running ANSICON with no arguments will start a new instance of the com-
+ mand processor (the program defined by the `ComSpec' environment var-
+ iable, typically `CMD.EXE'), or display standard input if it is redir-
+ ected. Any argument will be treated as a program and its arguments.
+
+ Eg: `ansicon -m30 -t file.ans' will display `file.ans' using black on
+ cyan as the default color.
+
+ The attribute may start with "-" to permanently reverse the foreground
+ and background colors (but not when using `-p'). Eg: `ansicon -m-f0 -t
+ file.log' will use reversed black on white as the default (i.e. white on
+ black, with foreground sequences changing the background).
+
+ If you experience trouble with certain programs, the log may help in
+ finding the cause; it can be found at "%TEMP%\ansicon.log". A number
+ should follow the `l':
+
+ 0 No logging
+ 1 Log process start and end
+ 2 Above, plus log modules used by the process
+ 3 Above, plus log functions that are hooked
+ 4 Log console output (add to any of the above)
+ 8 Append to the existing file (add to any of the above)
+ 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 (one known is "nvd3d9wrap.dll") add it to
+ the ANSICON_EXC environment variable (see ANSICON_API below, but the
+ extension is required).
+
+ Once installed, the ANSICON environment variable will be created. This
+ variable is of the form "WxH (wxh)", where W & H are the width and
+ height of the buffer and w & h are the width and height of the window.
+ The variable is updated whenever a program reads it directly (i.e. as
+ an individual request, not as part of the entire environment block).
+ For example, "set an" will not update it, but "echo %ansicon%" will.
+ Also created is ANSICON_VER, which contains the version without the
+ point (1.50 becomes "150"). This variable does not exist as part of the
+ environment block ("set an" will not show it).
+
+ If installed, GUI programs will not be hooked. Either start the program
+ directly with `ansicon', or add it to the ANSICON_GUI variable (see
+ ANSICON_API below).
+
+ Using `ansicon' after install will always start with the default attrib-
+ utes, restoring the originals on exit; all other programs will use the
+ current attributes. The shift state is always reset for a new process.
+
+ The Windows API WriteFile and WriteConsoleA functions will set the num-
+ ber of characters written, not the number of bytes. When using a multi-
+ byte character set, this results in a smaller number (since multiple
+ bytes are used to represent a single character). Some programs recog-
+ nise this as a reduced write and will inadvertently repeat previous
+ characters. If you discover such a program, use the ANSICON_API envir-
+ onment variable to record it and override the API, returning the origin-
+ al byte count. Ruby is an example of such a program (at least, up till
+ 1.9.2p0), so use "set ANSICON_API=ruby" to avoid the repitition. The
+ full syntax of the variable is:
+
+ ANSICON_API=[!]program;program;program...
+
+ PROGRAM is the name of the program, with no path and extension. The
+ leading exclamation inverts the usage, meaning the API will always be
+ overridden, unless the program is in the list. The variable can be made
+ permanent by going to System Properties, selecting the Advanced tab and
+ clicking Environment Variables (using XP; Vista/7 may be different).
+
+
+ ====================
+ Sequences Recognised
+ ====================
+
+ The following escape sequences are recognised.
+
+ \e]0;titleBEL Set (xterm) window's title (and icon)
+ \e[21t Report (xterm) window's title
+ \e[s Save Cursor
+ \e[u Restore Cursor
+ \e[#G CHA Cursor Character Absolute
+ \e[#E CNL Cursor Next Line
+ \e[#F CPL Cursor Preceding Line
+ \e[#D CUB Cursor Left
+ \e[#B CUD Cursor Down
+ \e[#C CUF Cursor Right
+ \e[#;#H CUP Cursor Position
+ \e[#A CUU Cursor Up
+ \e[#P DCH Delete Character
+ \e[?25h DECTCEM DEC Text Cursor Enable Mode (show cursor)
+ \e[?25l DECTCEM DEC Text Cursor Enable Mode (hide cursor)
+ \e[#M DL Delete Line
+ \e[#n DSR Device Status Report
+ \e[#X ECH Erase Character
+ \e[#J ED Erase In Page
+ \e[#K EL Erase In Line
+ \e[#` HPA Character Position Absolute
+ \e[#j HPB Character Position Backward
+ \e[#a HPR Character Position Forward
+ \e[#;#f HVP Character And Line Position
+ \e[#@ ICH Insert Character
+ \e[#L IL Insert Line
+ SI LS0 Locking-shift Zero (see below)
+ SO LS1 Locking-shift One
+ \e[#;#;#m SGR Select Graphic Rendition
+ \e[#d VPA Line Position Absolute
+ \e[#k VPB Line Position Backward
+ \e[#e VPR Line Position Forward
+
+ `\e' represents the escape character (ASCII 27); `#' represents a
+ 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.
+
+ 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
+ first parameter); the former will also restore the original bold and
+ underline attributes, whilst the latter will explicitly reset them. The
+ environment variable ANSICON_DEF can be used to change the default col-
+ ors (same value as `-m'; setting the variable does not change the cur-
+ rent colors).
+
+
+ =================
+ Sequences Ignored
+ =================
+
+ The following escape sequences are explicitly ignored.
+
+ \e(? Designate G0 character set (`?' is anything).
+ \e)? Designate G1 character set (`?' is anything).
+ \e[?... Private sequence
+ \e[>... Private sequence
+
+ The G0 character set is always ASCII; the G1 character set is always
+ the DEC Special Graphics Character Set.
+
+
+ ==================================
+ DEC Special Graphics Character Set
+ ==================================
+
+ This is my interpretation of the set, as shown by
+ http://vt100.net/docs/vt220-rm/table2-4.html.
+
+
+ Char Unicode Code Point & Name
+ ---- -------------------------
+ _ U+0020 Space (blank)
+ ` U+2666 Black Diamond Suit
+ a U+2592 Medium Shade
+ b U+2409 Symbol For Horizontal Tabulation
+ c U+240C Symbol For Form Feed
+ d U+240D Symbol For Carriage Return
+ e U+240A Symbol For Line Feed
+ f U+00B0 Degree Sign
+ g U+00B1 Plus-Minus Sign
+ h U+2424 Symbol For Newline
+ i U+240B Symbol For Vertical Tabulation
+ j U+2518 Box Drawings Light Up And Left
+ k U+2510 Box Drawings Light Down And Left
+ l U+250C Box Drawings Light Down And Right
+ m U+2514 Box Drawings Light Up And Right
+ n U+253C Box Drawings Light Vertical And Horizontal
+ o U+00AF Macron (SCAN 1)
+ p U+25AC Black Rectangle (SCAN 3)
+ q U+2500 Box Drawings Light Horizontal (SCAN 5)
+ r U+005F Low Line (SCAN 7)
+ s U+005F Low Line (SCAN 9)
+ t U+251C Box Drawings Light Vertical And Right
+ u U+2524 Box Drawings Light Vertical And Left
+ v U+2534 Box Drawings Light Up And Horizontal
+ w U+252C Box Drawings Light Down And Horizontal
+ x U+2502 Box Drawings Light Vertical
+ y U+2264 Less-Than Or Equal To
+ z U+2265 Greater-Than Or Equal To
+ { U+03C0 Greek Small Letter Pi
+ | U+2260 Not Equal To
+ } U+00A3 Pound Sign
+ ~ U+00B7 Middle Dot
+
+
+ G1.txt is a Unicode file to view the glyphs "externally". G1.bat is a
+ batch file (using `x86\ansicon') to show the glyphs in the console. The
+ characters will appear as they should using Lucida (other than the Sym-
+ bols), but code page will influence them when using a raster font (but
+ of particular interest, 437 and 850 both show the Box Drawings).
+
+
+ ===========
+ Limitations
+ ===========
+
+ The entire console buffer is used, not just the visible window.
+
+ Building rubyinstaller on Win7 crashes (XP is fine).
+
+
+ ===============
+ Version History
+ ===============
+
+ Legend: + added, - bug-fixed, * changed.
+
+ 1.53 - 12 June, 2012:
+ - fix for multiple simultaneous process creation (e.g. "cl /MP ...").
+
+ 1.52 - 2 June, 2012:
+ + 32-bit processes can inject into 64-bit processes;
+ + implemented \e[39m & \e[49m (set default foreground/background color);
+ + added \e[#X, \e[#`, \e[#a, \e[#d, \e[#e, \[e#j and \e[#k;
+ * changed sequence descriptions to those in ECMA-48, ordered by acronym.
+
+ 1.51 - 24 February, 2012:
+ - fixed installing into a piped/redirected CMD.EXE;
+ - fixed 32-bit process trying to identify a 64-bit process;
+ - ignore version within core API DLL names (now Win8 works);
+ + hook _lwrite & _hwrite (now Silverfrost FTN95 v6.20 works).
+
+ 1.50 - 14 December, 2011:
+ - -u does not imply -p;
+ - return the program's exit code;
+ - -p by itself will not restore original color;
+ - output error messages to stderr;
+ * logging is always available, with various levels; include the pid;
+ * don't automatically hook GUI programs, use `ansicon' or ANSICON_GUI;
+ * always place first in AutoRun; don't run if already installed;
+ + global reverse video capability;
+ + added ANSICON_VER to provide version/install test;
+ + added ANSICON_EXC to exclude selected modules;
+ + added ANSICON_DEF to explicitly set the default SGM.
+
+ 1.40 - 1 March, 2011:
+ - hook GetProcAddress (now PowerShell works);
+ + add SO/SI, using the DEC Special Graphics Character Set for G1;
+ + add DECTCEM to show/hide the cursor.
+
+ 1.32 - 22 December, 2010:
+ - fixed crash due to NULL lpNumberOfBytesWritten/lpNumberOfCharsWritten;
+ - -p will test the parent process for validity;
+ * hook into GUI processes;
+ + recognise DSR and xterm window title sequences;
+ - fixed MinGW32 binaries (LLW was wrong).
+
+ 1.31 - 19 November, 2010:
+ - fixed multibyte support (no extra junk with UTF-8 files);
+ * provide workaround for API byte/character differences;
+ * fixed potential problem if install path uses Unicode.
+
+ 1.30 - 7 September, 2010:
+ + x64 version.
+
+ 1.25 - 22 July, 2010:
+ - hook LoadLibraryEx (now CScript works);
+ - fixed -i when AutoRun existed, but was empty;
+ + support for Windows 7;
+ + -I (and -U) use HKEY_LOCAL_MACHINE.
+
+ 1.24 - 7 January, 2010:
+ - fix -t and -e when ANSICON was already running;
+ + read standard input if redirected with no arguments, if -t has no
+ files, or if the name is "-" (which also serves as a workaround for
+ programs that don't get hooked, such as CScript).
+
+ 1.23 - 11 November, 2009:
+ - restore hooked functions when unloading;
+ - reverse the "bold" and "underline" settings;
+ * conceal characters by making foreground color same as background.
+
+ 1.22 - 5 October, 2009:
+ - hook LoadLibrary to inject into applications started via association.
+
+ 1.21 - 23 September, 2009:
+ + -i (and -u) option to add (remove) entry to AutoRun value.
+
+ 1.20 - 21 June, 2009:
+ * use another injection method;
+ + create ANSICON environment variable;
+ + -e (and -E) option to echo the command line (without newline);
+ + -t (and -T) option to type (display) files (with file name).
+
+ 1.15 - 17 May, 2009:
+ - fix output corruption for long (over 8192 characters) ANSI strings.
+
+ 1.14 - 3 April, 2009:
+ - fix the test for an empty import section (eg. XCOPY now works).
+
+ 1.13 - 21 & 27 March, 2009:
+ * use a new injection method (to work with DEP);
+ * use Unicode.
+
+ 1.12 - 9 March, 2009:
+ - fix processing child programs (generate a relocatable DLL).
+
+ 1.11 - 28 February, 2009:
+ - fix processing child programs (only use for console executables).
+
+ 1.10 - 22 February, 2009:
+ - fix output corruption (buffer overflow in MyConsoleWriteW);
+ - recognise current screen attributes as current ANSI atrributes;
+ - ignore Ctrl+C and Ctrl+Break;
+ + process child programs.
+
+ 1.01 - 12 March, 2006:
+ * \e[m will restore original color, not set grey on black;
+ + -m option to set default (and initial) color;
+ - restore original color on exit;
+ - disable escape processing when console has disabled processed output;
+ + \e[5m (blink) is the same as \e[4m (underline);
+ - do not conceal control characters (0 to 31).
+
+ 1.00 - 23 October, 2005:
+ + initial release.
+
+
+ ===============
+ Acknowledgments
+ ===============
+
+ Jean-Louis Morel, for his Perl package Win32::Console::ANSI. It
+ provided the basis of `ANSI.dll'.
+
+ Sergey Oblomov (hoopoepg), for Console Manager. It provided the basis
+ of `ansicon.exe'.
+
+ Anton Bassov's article "Process-wide API spying - an ultimate hack" in
+ "The Code Project".
+
+ Richard Quadling - his persistence in finding bugs has made ANSICON
+ what it is today.
+
+ Dmitry Menshikov, Marko Bozikovic and Philippe Villiers, for their
+ assistance in making the 64-bit version a reality.
+
+ Luis Lavena and the Ruby people for additional improvements.
+
+ Leigh Hebblethwaite for documentation tweaks.
+
+
+ =======
+ Contact
+ =======
+
+ mailto:jadoxa@yahoo.com.au
+ http://ansicon.adoxa.cjb.net/
+ https://github.com/adoxa/ansicon
+
+ Jason Hood
+ 11 Buckle Street
+ North Rockhampton
+ Qld 4701
+ Australia
+
+
+ ============
+ Distribution
+ ============
+
+ The original zipfile can be freely distributed, by any means. However,
+ 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.
+
+
+ ==========================
+ Jason Hood, 12 June, 2012.
diff --git a/ansicon/util.c b/ansicon/util.c
new file mode 100755
index 0000000..461b7b6
--- /dev/null
+++ b/ansicon/util.c
@@ -0,0 +1,128 @@
+/*
+ util.c - Utility functions.
+*/
+
+#include "ansicon.h"
+#include "version.h"
+
+
+TCHAR prog_path[MAX_PATH];
+LPTSTR prog;
+int log_level;
+char tempfile[MAX_PATH];
+DWORD pid;
+
+
+// Get just the name of the program: "C:\path\program.exe" -> "program".
+// Returns a pointer within program; it is modified to remove the extension.
+LPTSTR get_program_name( LPTSTR program )
+{
+ LPTSTR name, ext;
+
+ if (program == NULL)
+ {
+ GetModuleFileName( NULL, prog_path, lenof(prog_path) );
+ program = prog_path;
+ }
+ name = wcsrchr( program, '\\' );
+ if (name != NULL)
+ ++name;
+ else
+ name = program;
+ ext = wcsrchr( name, '.' );
+ if (ext != NULL && ext != name)
+ *ext = '\0';
+
+ return name;
+}
+
+
+void DEBUGSTR( int level, LPTSTR szFormat, ... )
+{
+ TCHAR szBuffer[1024], szEscape[1024];
+ va_list pArgList;
+ HANDLE mutex;
+ DWORD wait;
+ FILE* file;
+
+ if ((log_level & 3) < level && !(level & 4 & log_level))
+ return;
+
+ if (*tempfile == '\0')
+ {
+ _snprintf( tempfile, MAX_PATH, "%s\\ansicon.log", getenv( "TEMP" ) );
+ pid = GetCurrentProcessId();
+ }
+ if (szFormat == NULL)
+ {
+ file = fopen( tempfile, "wt" );
+ if (file != NULL)
+ {
+ SYSTEMTIME now;
+ GetLocalTime( &now );
+ fprintf( file, "ANSICON v" PVERSA " log (%d) started "
+ "%d-%.2d-%.2d %d:%.2d:%.2d\n",
+ log_level,
+ now.wYear, now.wMonth, now.wDay,
+ now.wHour, now.wMinute, now.wSecond );
+ fclose( file );
+ }
+ return;
+ }
+
+ va_start( pArgList, szFormat );
+ _vsnwprintf( szBuffer, lenof(szBuffer), szFormat, pArgList );
+ va_end( pArgList );
+
+ szFormat = szBuffer;
+ if (*szFormat == '\33')
+ {
+ BOOL first = TRUE;
+ LPTSTR pos = szEscape;
+ while (*++szFormat != '\0' && pos < szEscape + lenof(szEscape) - 4)
+ {
+ if (*szFormat < 32)
+ {
+ *pos++ = '\\';
+ switch (*szFormat)
+ {
+ case '\a': *pos++ = 'a'; break;
+ case '\b': *pos++ = 'b'; break;
+ case '\t': *pos++ = 't'; break;
+ case '\r': *pos++ = 'r'; break;
+ case '\n': *pos++ = 'n'; break;
+ case 27 : *pos++ = 'e'; break;
+ default:
+ pos += _snwprintf( pos, 32, L"%.*o",
+ (szFormat[1] >= '0' && szFormat[1] <= '7') ? 3 : 1,
+ *szFormat );
+ }
+ }
+ else
+ {
+ if (*szFormat == '"')
+ {
+ if (first)
+ first = FALSE;
+ else if (szFormat[1] != '\0')
+ *pos++ = '\\';
+ }
+ *pos++ = *szFormat;
+ }
+ }
+ *pos = '\0';
+ szFormat = szEscape;
+ }
+
+ mutex = CreateMutex( NULL, FALSE, L"ANSICON_debug_file" );
+ wait = WaitForSingleObject( mutex, 500 );
+ file = fopen( tempfile, "at" ); // _fmode might be binary
+ if (file != NULL)
+ {
+ fwprintf( file, L"%s (%lu): %s\n", prog, pid, szFormat );
+ fclose( file );
+ }
+ if (wait == WAIT_OBJECT_0)
+ ReleaseMutex( mutex );
+ CloseHandle( mutex );
+}
diff --git a/ansicon/version.h b/ansicon/version.h
new file mode 100755
index 0000000..ff76004
--- /dev/null
+++ b/ansicon/version.h
@@ -0,0 +1,9 @@
+/*
+ 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)
diff --git a/ansicon/wow64.h b/ansicon/wow64.h
new file mode 100755
index 0000000..33e0444
--- /dev/null
+++ b/ansicon/wow64.h
@@ -0,0 +1,88 @@
+/*
+ wow64.h - Definitions for Wow64.
+
+ Mingw64/TDM 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