+++ /dev/null
-/*
- 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" );
-}
-/*
- 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;
-}
+/*\r
+ ANSI.c - ANSI escape sequence console driver.\r
+\r
+ Jason Hood, 21 & 22 October, 2005.\r
+\r
+ Derived from ANSI.xs by Jean-Louis Morel, from his Perl package\r
+ Win32::Console::ANSI. I removed the codepage conversion ("\e(") and added\r
+ WriteConsole hooking.\r
+\r
+ v1.01, 11 & 12 March, 2006:\r
+ disable when console has disabled processed output;\r
+ \e[5m (blink) is the same as \e[4m (underline);\r
+ do not conceal control characters (0 to 31);\r
+ \e[m will restore original color.\r
+\r
+ v1.10, 22 February, 2009:\r
+ fix MyWriteConsoleW for strings longer than the buffer;\r
+ initialise attributes to current;\r
+ hook into child processes.\r
+\r
+ v1.11, 28 February, 2009:\r
+ fix hooking into child processes (only do console executables).\r
+\r
+ v1.12, 9 March, 2009:\r
+ really fix hooking (I didn't realise MinGW didn't generate relocations).\r
+\r
+ v1.13, 21 & 27 March, 2009:\r
+ alternate injection method, to work with DEP;\r
+ use Unicode and the current output code page (not OEMCP).\r
+\r
+ v1.14, 3 April, 2009:\r
+ fix test for empty import section.\r
+\r
+ v1.15, 17 May, 2009:\r
+ properly update lpNumberOfCharsWritten in MyWriteConsoleA.\r
+\r
+ v1.20, 26 & 29 May, 17 to 21 June, 2009:\r
+ create an ANSICON environment variable;\r
+ hook GetEnvironmentVariable to create ANSICON dynamically;\r
+ use another injection method.\r
+\r
+ v1.22, 5 October, 2009:\r
+ hook LoadLibrary to intercept the newly loaded functions.\r
+\r
+ v1.23, 11 November, 2009:\r
+ unload gracefully;\r
+ conceal characters by making foreground same as background;\r
+ reverse the bold/underline attributes, too.\r
+\r
+ v1.25, 15, 20 & 21 July, 2010:\r
+ hook LoadLibraryEx (now cscript works);\r
+ Win7 support.\r
+\r
+ v1.30, 3 August to 7 September, 2010:\r
+ x64 support.\r
+\r
+ v1.31, 13 & 19 November, 2010:\r
+ fix multibyte conversion problems.\r
+\r
+ v1.32, 4 to 22 December, 2010:\r
+ test for lpNumberOfCharsWritten/lpNumberOfBytesWritten being NULL;\r
+ recognise DSR and xterm window title;\r
+ ignore sequences starting with \e[? & \e[>;\r
+ close the handles opened by CreateProcess.\r
+\r
+ v1.40, 25 & 26 February, 1 March, 2011:\r
+ hook GetProcAddress, addresses issues with .NET (work with PowerShell);\r
+ implement SO & SI to use the DEC Special Graphics Character Set (enables\r
+ line drawing via ASCII); ignore \e(X & \e)X (where X is any character);\r
+ add \e[?25h & \e[?25l to show/hide the cursor (DECTCEM).\r
+\r
+ v1.50, 7 to 14 December, 2011:\r
+ added dynamic environment variable ANSICON_VER to return version;\r
+ read ANSICON_EXC environment variable to exclude selected modules;\r
+ read ANSICON_GUI environment variable to hook selected GUI programs;\r
+ read ANSICON_DEF environment variable to set the default GR;\r
+ transfer current GR to child, read it on exit.\r
+\r
+ v1.51, 15 January, 5, 22 & 24 February, 2012:\r
+ added log mask 16 to log all the imported modules of imported modules;\r
+ ignore the version within the core API DLL names;\r
+ fix 32-bit process trying to identify 64-bit process;\r
+ hook _lwrite & _hwrite.\r
+\r
+ v1.52, 10 April, 1 & 2 June, 2012:\r
+ use ansicon.exe to enable 32-bit to inject into 64-bit;\r
+ implement \e[39m & \e[49m (only setting color, nothing else);\r
+ added the character/line equivalents (keaj`) of the cursor movement\r
+ sequences (ABCDG), as well as vertical absolute (d) and erase characters\r
+ (X).\r
+\r
+ v1.53, 12 June, 2012:\r
+ fixed Update_GRM when running multiple processes (e.g. "cl /MP").\r
+\r
+ v1.60, 22 to 24 November, 2012:\r
+ alternative method to obtain LLW for 64->32 injection;\r
+ support for VC6 (remove section pragma, rename isdigit to is_digit).\r
+\r
+ v1.61, 14 February, 2013:\r
+ go back to using ANSI-LLW.exe for 64->32 injection.\r
+\r
+ v1.62, 17 & 18 July, 2013:\r
+ another method to obtain LLW for 64->32 injection.\r
+\r
+ v1.64, 2 August, 2013:\r
+ better method of determining a console handle (see IsConsoleHandle).\r
+\r
+ v1.65, 28 August, 2013:\r
+ fix \e[K (was using window, not buffer).\r
+*/\r
+\r
+#include "ansicon.h"\r
+#include "version.h"\r
+#include <tlhelp32.h>\r
+\r
+#define is_digit(c) ('0' <= (c) && (c) <= '9')\r
+\r
+#ifdef __GNUC__\r
+#define SHARED __attribute__((shared, section(".shared")))\r
+#else\r
+#pragma data_seg(".shared", "read,write,shared")\r
+#pragma data_seg()\r
+#define SHARED __declspec(allocate(".shared"))\r
+#endif\r
+\r
+\r
+// ========== Global variables and constants\r
+\r
+HANDLE hConOut; // handle to CONOUT$\r
+\r
+#define ESC '\x1B' // ESCape character\r
+#define BEL '\x07'\r
+#define SO '\x0E' // Shift Out\r
+#define SI '\x0F' // Shift In\r
+\r
+#define MAX_ARG 16 // max number of args in an escape sequence\r
+int state; // automata state\r
+TCHAR prefix; // escape sequence prefix ( '[', ']' or '(' );\r
+TCHAR prefix2; // secondary prefix ( '?' or '>' );\r
+TCHAR suffix; // escape sequence suffix\r
+int es_argc; // escape sequence args count\r
+int es_argv[MAX_ARG]; // escape sequence args\r
+TCHAR Pt_arg[MAX_PATH*2]; // text parameter for Operating System Command\r
+int Pt_len;\r
+BOOL shifted;\r
+\r
+\r
+// DEC Special Graphics Character Set from\r
+// http://vt100.net/docs/vt220-rm/table2-4.html\r
+// Some of these may not look right, depending on the font and code page (in\r
+// particular, the Control Pictures probably won't work at all).\r
+const WCHAR G1[] =\r
+{\r
+ ' ', // _ - blank\r
+ L'\x2666', // ` - Black Diamond Suit\r
+ L'\x2592', // a - Medium Shade\r
+ L'\x2409', // b - HT\r
+ L'\x240c', // c - FF\r
+ L'\x240d', // d - CR\r
+ L'\x240a', // e - LF\r
+ L'\x00b0', // f - Degree Sign\r
+ L'\x00b1', // g - Plus-Minus Sign\r
+ L'\x2424', // h - NL\r
+ L'\x240b', // i - VT\r
+ L'\x2518', // j - Box Drawings Light Up And Left\r
+ L'\x2510', // k - Box Drawings Light Down And Left\r
+ L'\x250c', // l - Box Drawings Light Down And Right\r
+ L'\x2514', // m - Box Drawings Light Up And Right\r
+ L'\x253c', // n - Box Drawings Light Vertical And Horizontal\r
+ L'\x00af', // o - SCAN 1 - Macron\r
+ L'\x25ac', // p - SCAN 3 - Black Rectangle\r
+ L'\x2500', // q - SCAN 5 - Box Drawings Light Horizontal\r
+ L'_', // r - SCAN 7 - Low Line\r
+ L'_', // s - SCAN 9 - Low Line\r
+ L'\x251c', // t - Box Drawings Light Vertical And Right\r
+ L'\x2524', // u - Box Drawings Light Vertical And Left\r
+ L'\x2534', // v - Box Drawings Light Up And Horizontal\r
+ L'\x252c', // w - Box Drawings Light Down And Horizontal\r
+ L'\x2502', // x - Box Drawings Light Vertical\r
+ L'\x2264', // y - Less-Than Or Equal To\r
+ L'\x2265', // z - Greater-Than Or Equal To\r
+ L'\x03c0', // { - Greek Small Letter Pi\r
+ L'\x2260', // | - Not Equal To\r
+ L'\x00a3', // } - Pound Sign\r
+ L'\x00b7', // ~ - Middle Dot\r
+};\r
+\r
+#define FIRST_G1 '_'\r
+#define LAST_G1 '~'\r
+\r
+\r
+// color constants\r
+\r
+#define FOREGROUND_BLACK 0\r
+#define FOREGROUND_WHITE FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE\r
+\r
+#define BACKGROUND_BLACK 0\r
+#define BACKGROUND_WHITE BACKGROUND_RED|BACKGROUND_GREEN|BACKGROUND_BLUE\r
+\r
+const BYTE foregroundcolor[8] =\r
+{\r
+ FOREGROUND_BLACK, // black foreground\r
+ FOREGROUND_RED, // red foreground\r
+ FOREGROUND_GREEN, // green foreground\r
+ FOREGROUND_RED | FOREGROUND_GREEN, // yellow foreground\r
+ FOREGROUND_BLUE, // blue foreground\r
+ FOREGROUND_BLUE | FOREGROUND_RED, // magenta foreground\r
+ FOREGROUND_BLUE | FOREGROUND_GREEN, // cyan foreground\r
+ FOREGROUND_WHITE // white foreground\r
+};\r
+\r
+const BYTE backgroundcolor[8] =\r
+{\r
+ BACKGROUND_BLACK, // black background\r
+ BACKGROUND_RED, // red background\r
+ BACKGROUND_GREEN, // green background\r
+ BACKGROUND_RED | BACKGROUND_GREEN, // yellow background\r
+ BACKGROUND_BLUE, // blue background\r
+ BACKGROUND_BLUE | BACKGROUND_RED, // magenta background\r
+ BACKGROUND_BLUE | BACKGROUND_GREEN, // cyan background\r
+ BACKGROUND_WHITE, // white background\r
+};\r
+\r
+const BYTE attr2ansi[8] = // map console attribute to ANSI number\r
+{\r
+ 0, // black\r
+ 4, // blue\r
+ 2, // green\r
+ 6, // cyan\r
+ 1, // red\r
+ 5, // magenta\r
+ 3, // yellow\r
+ 7 // white\r
+};\r
+\r
+GRM grm;\r
+\r
+// saved cursor position\r
+COORD SavePos;\r
+\r
+// Variables to enable copying attributes between processes.\r
+SHARED DWORD s_pid;\r
+SHARED GRM s_grm;\r
+SHARED DWORD s_flag;\r
+#define GRM_INIT 1\r
+#define GRM_EXIT 2\r
+\r
+#ifdef _WIN64\r
+SHARED DWORD LLW32;\r
+#endif\r
+\r
+\r
+// Wait for the child process to finish, then update our GRM to the child's.\r
+DWORD WINAPI UpdateGRM( LPVOID child_pi )\r
+{\r
+ DWORD pid = ((LPPROCESS_INFORMATION)child_pi)->dwProcessId;\r
+ HANDLE proc = ((LPPROCESS_INFORMATION)child_pi)->hProcess;\r
+ free( child_pi );\r
+\r
+ WaitForSingleObject( proc, INFINITE );\r
+ CloseHandle( proc );\r
+\r
+ if (s_flag == GRM_EXIT && s_pid == pid)\r
+ {\r
+ s_flag = 0;\r
+ grm = s_grm;\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+\r
+// Search an environment variable for a string.\r
+BOOL search_env( LPCTSTR var, LPCTSTR val )\r
+{\r
+ static LPTSTR env;\r
+ static DWORD env_len;\r
+ DWORD len;\r
+ BOOL not;\r
+\r
+ len = GetEnvironmentVariable( var, env, env_len );\r
+ if (len == 0)\r
+ return FALSE;\r
+\r
+ if (len > env_len)\r
+ {\r
+ LPTSTR tmp = realloc( env, TSIZE(len) );\r
+ if (tmp == NULL)\r
+ return FALSE;\r
+ env = tmp;\r
+ env_len = len;\r
+ GetEnvironmentVariable( var, env, env_len );\r
+ }\r
+\r
+ not = (*env == '!');\r
+ if (not && env[1] == '\0')\r
+ return TRUE;\r
+\r
+ for (var = wcstok( env + not, L";" ); var; var = wcstok( NULL, L";" ))\r
+ if (_wcsicmp( val, var ) == 0)\r
+ return !not;\r
+\r
+ return not;\r
+}\r
+\r
+\r
+// ========== Print Buffer functions\r
+\r
+#define BUFFER_SIZE 2048\r
+\r
+int nCharInBuffer;\r
+WCHAR ChBuffer[BUFFER_SIZE];\r
+\r
+//-----------------------------------------------------------------------------\r
+// FlushBuffer()\r
+// Writes the buffer to the console and empties it.\r
+//-----------------------------------------------------------------------------\r
+\r
+void FlushBuffer( void )\r
+{\r
+ DWORD nWritten;\r
+ if (nCharInBuffer <= 0) return;\r
+ WriteConsole( hConOut, ChBuffer, nCharInBuffer, &nWritten, NULL );\r
+ nCharInBuffer = 0;\r
+}\r
+\r
+//-----------------------------------------------------------------------------\r
+// PushBuffer( WCHAR c )\r
+// Adds a character in the buffer.\r
+//-----------------------------------------------------------------------------\r
+\r
+void PushBuffer( WCHAR c )\r
+{\r
+ if (shifted && c >= FIRST_G1 && c <= LAST_G1)\r
+ c = G1[c-FIRST_G1];\r
+ ChBuffer[nCharInBuffer] = c;\r
+ if (++nCharInBuffer == BUFFER_SIZE)\r
+ FlushBuffer();\r
+}\r
+\r
+//-----------------------------------------------------------------------------\r
+// SendSequence( LPTSTR seq )\r
+// Send the string to the input buffer.\r
+//-----------------------------------------------------------------------------\r
+\r
+void SendSequence( LPTSTR seq )\r
+{\r
+ DWORD out;\r
+ INPUT_RECORD in;\r
+ HANDLE hStdIn = GetStdHandle( STD_INPUT_HANDLE );\r
+\r
+ in.EventType = KEY_EVENT;\r
+ in.Event.KeyEvent.bKeyDown = TRUE;\r
+ in.Event.KeyEvent.wRepeatCount = 1;\r
+ in.Event.KeyEvent.wVirtualKeyCode = 0;\r
+ in.Event.KeyEvent.wVirtualScanCode = 0;\r
+ in.Event.KeyEvent.dwControlKeyState = 0;\r
+ for (; *seq; ++seq)\r
+ {\r
+ in.Event.KeyEvent.uChar.UnicodeChar = *seq;\r
+ WriteConsoleInput( hStdIn, &in, 1, &out );\r
+ }\r
+}\r
+\r
+// ========== Print functions\r
+\r
+//-----------------------------------------------------------------------------\r
+// InterpretEscSeq()\r
+// Interprets the last escape sequence scanned by ParseAndPrintString\r
+// prefix escape sequence prefix\r
+// es_argc escape sequence args count\r
+// es_argv[] escape sequence args array\r
+// suffix escape sequence suffix\r
+//\r
+// for instance, with \e[33;45;1m we have\r
+// prefix = '[',\r
+// es_argc = 3, es_argv[0] = 33, es_argv[1] = 45, es_argv[2] = 1\r
+// suffix = 'm'\r
+//-----------------------------------------------------------------------------\r
+\r
+void InterpretEscSeq( void )\r
+{\r
+ int i;\r
+ WORD attribut;\r
+ CONSOLE_SCREEN_BUFFER_INFO Info;\r
+ CONSOLE_CURSOR_INFO CursInfo;\r
+ DWORD len, NumberOfCharsWritten;\r
+ COORD Pos;\r
+ SMALL_RECT Rect;\r
+ CHAR_INFO CharInfo;\r
+\r
+ if (prefix == '[')\r
+ {\r
+ if (prefix2 == '?' && (suffix == 'h' || suffix == 'l'))\r
+ {\r
+ if (es_argc == 1 && es_argv[0] == 25)\r
+ {\r
+ GetConsoleCursorInfo( hConOut, &CursInfo );\r
+ CursInfo.bVisible = (suffix == 'h');\r
+ SetConsoleCursorInfo( hConOut, &CursInfo );\r
+ return;\r
+ }\r
+ }\r
+ // Ignore any other \e[? or \e[> sequences.\r
+ if (prefix2 != 0)\r
+ return;\r
+\r
+ GetConsoleScreenBufferInfo( hConOut, &Info );\r
+ switch (suffix)\r
+ {\r
+ case 'm':\r
+ if (es_argc == 0) es_argv[es_argc++] = 0;\r
+ for (i = 0; i < es_argc; i++)\r
+ {\r
+ if (30 <= es_argv[i] && es_argv[i] <= 37)\r
+ grm.foreground = es_argv[i] - 30;\r
+ else if (40 <= es_argv[i] && es_argv[i] <= 47)\r
+ grm.background = es_argv[i] - 40;\r
+ else switch (es_argv[i])\r
+ {\r
+ case 0:\r
+ case 39:\r
+ case 49:\r
+ {\r
+ TCHAR def[4];\r
+ int a;\r
+ *def = '7'; def[1] = '\0';\r
+ GetEnvironmentVariable( L"ANSICON_DEF", def, lenof(def) );\r
+ a = wcstol( def, NULL, 16 );\r
+ grm.reverse = FALSE;\r
+ if (a < 0)\r
+ {\r
+ grm.reverse = TRUE;\r
+ a = -a;\r
+ }\r
+ if (es_argv[i] != 49)\r
+ grm.foreground = attr2ansi[a & 7];\r
+ if (es_argv[i] != 39)\r
+ grm.background = attr2ansi[(a >> 4) & 7];\r
+ if (es_argv[i] == 0)\r
+ {\r
+ if (es_argc == 1)\r
+ {\r
+ grm.bold = a & FOREGROUND_INTENSITY;\r
+ grm.underline = a & BACKGROUND_INTENSITY;\r
+ }\r
+ else\r
+ {\r
+ grm.bold = 0;\r
+ grm.underline = 0;\r
+ }\r
+ grm.rvideo = 0;\r
+ grm.concealed = 0;\r
+ }\r
+ }\r
+ break;\r
+\r
+ case 1: grm.bold = FOREGROUND_INTENSITY; break;\r
+ case 5: // blink\r
+ case 4: grm.underline = BACKGROUND_INTENSITY; break;\r
+ case 7: grm.rvideo = 1; break;\r
+ case 8: grm.concealed = 1; break;\r
+ case 21: // oops, this actually turns on double underline\r
+ case 22: grm.bold = 0; break;\r
+ case 25:\r
+ case 24: grm.underline = 0; break;\r
+ case 27: grm.rvideo = 0; break;\r
+ case 28: grm.concealed = 0; break;\r
+ }\r
+ }\r
+ if (grm.concealed)\r
+ {\r
+ if (grm.rvideo)\r
+ {\r
+ attribut = foregroundcolor[grm.foreground]\r
+ | backgroundcolor[grm.foreground];\r
+ if (grm.bold)\r
+ attribut |= FOREGROUND_INTENSITY | BACKGROUND_INTENSITY;\r
+ }\r
+ else\r
+ {\r
+ attribut = foregroundcolor[grm.background]\r
+ | backgroundcolor[grm.background];\r
+ if (grm.underline)\r
+ attribut |= FOREGROUND_INTENSITY | BACKGROUND_INTENSITY;\r
+ }\r
+ }\r
+ else if (grm.rvideo)\r
+ {\r
+ attribut = foregroundcolor[grm.background]\r
+ | backgroundcolor[grm.foreground];\r
+ if (grm.bold)\r
+ attribut |= BACKGROUND_INTENSITY;\r
+ if (grm.underline)\r
+ attribut |= FOREGROUND_INTENSITY;\r
+ }\r
+ else\r
+ attribut = foregroundcolor[grm.foreground] | grm.bold\r
+ | backgroundcolor[grm.background] | grm.underline;\r
+ if (grm.reverse)\r
+ attribut = ((attribut >> 4) & 15) | ((attribut & 15) << 4);\r
+ SetConsoleTextAttribute( hConOut, attribut );\r
+ return;\r
+\r
+ case 'J':\r
+ if (es_argc == 0) es_argv[es_argc++] = 0; // ESC[J == ESC[0J\r
+ if (es_argc != 1) return;\r
+ switch (es_argv[0])\r
+ {\r
+ case 0: // ESC[0J erase from cursor to end of display\r
+ len = (Info.dwSize.Y - Info.dwCursorPosition.Y - 1) * Info.dwSize.X\r
+ + Info.dwSize.X - Info.dwCursorPosition.X - 1;\r
+ FillConsoleOutputCharacter( hConOut, ' ', len,\r
+ Info.dwCursorPosition,\r
+ &NumberOfCharsWritten );\r
+ FillConsoleOutputAttribute( hConOut, Info.wAttributes, len,\r
+ Info.dwCursorPosition,\r
+ &NumberOfCharsWritten );\r
+ return;\r
+\r
+ case 1: // ESC[1J erase from start to cursor.\r
+ Pos.X = 0;\r
+ Pos.Y = 0;\r
+ len = Info.dwCursorPosition.Y * Info.dwSize.X\r
+ + Info.dwCursorPosition.X + 1;\r
+ FillConsoleOutputCharacter( hConOut, ' ', len, Pos,\r
+ &NumberOfCharsWritten );\r
+ FillConsoleOutputAttribute( hConOut, Info.wAttributes, len, Pos,\r
+ &NumberOfCharsWritten );\r
+ return;\r
+\r
+ case 2: // ESC[2J Clear screen and home cursor\r
+ Pos.X = 0;\r
+ Pos.Y = 0;\r
+ len = Info.dwSize.X * Info.dwSize.Y;\r
+ FillConsoleOutputCharacter( hConOut, ' ', len, Pos,\r
+ &NumberOfCharsWritten );\r
+ FillConsoleOutputAttribute( hConOut, Info.wAttributes, len, Pos,\r
+ &NumberOfCharsWritten );\r
+ SetConsoleCursorPosition( hConOut, Pos );\r
+ return;\r
+\r
+ default:\r
+ return;\r
+ }\r
+\r
+ case 'K':\r
+ if (es_argc == 0) es_argv[es_argc++] = 0; // ESC[K == ESC[0K\r
+ if (es_argc != 1) return;\r
+ switch (es_argv[0])\r
+ {\r
+ case 0: // ESC[0K Clear to end of line\r
+ len = Info.dwSize.X - Info.dwCursorPosition.X + 1;\r
+ FillConsoleOutputCharacter( hConOut, ' ', len,\r
+ Info.dwCursorPosition,\r
+ &NumberOfCharsWritten );\r
+ FillConsoleOutputAttribute( hConOut, Info.wAttributes, len,\r
+ Info.dwCursorPosition,\r
+ &NumberOfCharsWritten );\r
+ return;\r
+\r
+ case 1: // ESC[1K Clear from start of line to cursor\r
+ Pos.X = 0;\r
+ Pos.Y = Info.dwCursorPosition.Y;\r
+ FillConsoleOutputCharacter( hConOut, ' ',\r
+ Info.dwCursorPosition.X + 1, Pos,\r
+ &NumberOfCharsWritten );\r
+ FillConsoleOutputAttribute( hConOut, Info.wAttributes,\r
+ Info.dwCursorPosition.X + 1, Pos,\r
+ &NumberOfCharsWritten );\r
+ return;\r
+\r
+ case 2: // ESC[2K Clear whole line.\r
+ Pos.X = 0;\r
+ Pos.Y = Info.dwCursorPosition.Y;\r
+ FillConsoleOutputCharacter( hConOut, ' ', Info.dwSize.X, Pos,\r
+ &NumberOfCharsWritten );\r
+ FillConsoleOutputAttribute( hConOut, Info.wAttributes,\r
+ Info.dwSize.X, Pos,\r
+ &NumberOfCharsWritten );\r
+ return;\r
+\r
+ default:\r
+ return;\r
+ }\r
+\r
+ case 'X': // ESC[#X Erase # characters.\r
+ if (es_argc == 0) es_argv[es_argc++] = 1; // ESC[X == ESC[1X\r
+ if (es_argc != 1) return;\r
+ FillConsoleOutputCharacter( hConOut, ' ', es_argv[0],\r
+ Info.dwCursorPosition,\r
+ &NumberOfCharsWritten );\r
+ FillConsoleOutputAttribute( hConOut, Info.wAttributes, es_argv[0],\r
+ Info.dwCursorPosition,\r
+ &NumberOfCharsWritten );\r
+ return;\r
+\r
+ case 'L': // ESC[#L Insert # blank lines.\r
+ if (es_argc == 0) es_argv[es_argc++] = 1; // ESC[L == ESC[1L\r
+ if (es_argc != 1) return;\r
+ Rect.Left = 0;\r
+ Rect.Top = Info.dwCursorPosition.Y;\r
+ Rect.Right = Info.dwSize.X - 1;\r
+ Rect.Bottom = Info.dwSize.Y - 1;\r
+ Pos.X = 0;\r
+ Pos.Y = Info.dwCursorPosition.Y + es_argv[0];\r
+ CharInfo.Char.UnicodeChar = ' ';\r
+ CharInfo.Attributes = Info.wAttributes;\r
+ ScrollConsoleScreenBuffer( hConOut, &Rect, NULL, Pos, &CharInfo );\r
+ return;\r
+\r
+ case 'M': // ESC[#M Delete # lines.\r
+ if (es_argc == 0) es_argv[es_argc++] = 1; // ESC[M == ESC[1M\r
+ if (es_argc != 1) return;\r
+ if (es_argv[0] > Info.dwSize.Y - Info.dwCursorPosition.Y)\r
+ es_argv[0] = Info.dwSize.Y - Info.dwCursorPosition.Y;\r
+ Rect.Left = 0;\r
+ Rect.Top = Info.dwCursorPosition.Y + es_argv[0];\r
+ Rect.Right = Info.dwSize.X - 1;\r
+ Rect.Bottom = Info.dwSize.Y - 1;\r
+ Pos.X = 0;\r
+ Pos.Y = Info.dwCursorPosition.Y;\r
+ CharInfo.Char.UnicodeChar = ' ';\r
+ CharInfo.Attributes = Info.wAttributes;\r
+ ScrollConsoleScreenBuffer( hConOut, &Rect, NULL, Pos, &CharInfo );\r
+ return;\r
+\r
+ case 'P': // ESC[#P Delete # characters.\r
+ if (es_argc == 0) es_argv[es_argc++] = 1; // ESC[P == ESC[1P\r
+ if (es_argc != 1) return;\r
+ if (Info.dwCursorPosition.X + es_argv[0] > Info.dwSize.X - 1)\r
+ es_argv[0] = Info.dwSize.X - Info.dwCursorPosition.X;\r
+ Rect.Left = Info.dwCursorPosition.X + es_argv[0];\r
+ Rect.Top = Info.dwCursorPosition.Y;\r
+ Rect.Right = Info.dwSize.X - 1;\r
+ Rect.Bottom = Info.dwCursorPosition.Y;\r
+ CharInfo.Char.UnicodeChar = ' ';\r
+ CharInfo.Attributes = Info.wAttributes;\r
+ ScrollConsoleScreenBuffer( hConOut, &Rect, NULL, Info.dwCursorPosition,\r
+ &CharInfo );\r
+ return;\r
+\r
+ case '@': // ESC[#@ Insert # blank characters.\r
+ if (es_argc == 0) es_argv[es_argc++] = 1; // ESC[@ == ESC[1@\r
+ if (es_argc != 1) return;\r
+ if (Info.dwCursorPosition.X + es_argv[0] > Info.dwSize.X - 1)\r
+ es_argv[0] = Info.dwSize.X - Info.dwCursorPosition.X;\r
+ Rect.Left = Info.dwCursorPosition.X;\r
+ Rect.Top = Info.dwCursorPosition.Y;\r
+ Rect.Right = Info.dwSize.X - 1 - es_argv[0];\r
+ Rect.Bottom = Info.dwCursorPosition.Y;\r
+ Pos.X = Info.dwCursorPosition.X + es_argv[0];\r
+ Pos.Y = Info.dwCursorPosition.Y;\r
+ CharInfo.Char.UnicodeChar = ' ';\r
+ CharInfo.Attributes = Info.wAttributes;\r
+ ScrollConsoleScreenBuffer( hConOut, &Rect, NULL, Pos, &CharInfo );\r
+ return;\r
+\r
+ case 'k': // ESC[#k\r
+ case 'A': // ESC[#A Moves cursor up # lines\r
+ if (es_argc == 0) es_argv[es_argc++] = 1; // ESC[A == ESC[1A\r
+ if (es_argc != 1) return;\r
+ Pos.Y = Info.dwCursorPosition.Y - es_argv[0];\r
+ if (Pos.Y < 0) Pos.Y = 0;\r
+ Pos.X = Info.dwCursorPosition.X;\r
+ SetConsoleCursorPosition( hConOut, Pos );\r
+ return;\r
+\r
+ case 'e': // ESC[#e\r
+ case 'B': // ESC[#B Moves cursor down # lines\r
+ if (es_argc == 0) es_argv[es_argc++] = 1; // ESC[B == ESC[1B\r
+ if (es_argc != 1) return;\r
+ Pos.Y = Info.dwCursorPosition.Y + es_argv[0];\r
+ if (Pos.Y >= Info.dwSize.Y) Pos.Y = Info.dwSize.Y - 1;\r
+ Pos.X = Info.dwCursorPosition.X;\r
+ SetConsoleCursorPosition( hConOut, Pos );\r
+ return;\r
+\r
+ case 'a': // ESC[#a\r
+ case 'C': // ESC[#C Moves cursor forward # spaces\r
+ if (es_argc == 0) es_argv[es_argc++] = 1; // ESC[C == ESC[1C\r
+ if (es_argc != 1) return;\r
+ Pos.X = Info.dwCursorPosition.X + es_argv[0];\r
+ if (Pos.X >= Info.dwSize.X) Pos.X = Info.dwSize.X - 1;\r
+ Pos.Y = Info.dwCursorPosition.Y;\r
+ SetConsoleCursorPosition( hConOut, Pos );\r
+ return;\r
+\r
+ case 'j': // ESC[#j\r
+ case 'D': // ESC[#D Moves cursor back # spaces\r
+ if (es_argc == 0) es_argv[es_argc++] = 1; // ESC[D == ESC[1D\r
+ if (es_argc != 1) return;\r
+ Pos.X = Info.dwCursorPosition.X - es_argv[0];\r
+ if (Pos.X < 0) Pos.X = 0;\r
+ Pos.Y = Info.dwCursorPosition.Y;\r
+ SetConsoleCursorPosition( hConOut, Pos );\r
+ return;\r
+\r
+ case 'E': // ESC[#E Moves cursor down # lines, column 1.\r
+ if (es_argc == 0) es_argv[es_argc++] = 1; // ESC[E == ESC[1E\r
+ if (es_argc != 1) return;\r
+ Pos.Y = Info.dwCursorPosition.Y + es_argv[0];\r
+ if (Pos.Y >= Info.dwSize.Y) Pos.Y = Info.dwSize.Y - 1;\r
+ Pos.X = 0;\r
+ SetConsoleCursorPosition( hConOut, Pos );\r
+ return;\r
+\r
+ case 'F': // ESC[#F Moves cursor up # lines, column 1.\r
+ if (es_argc == 0) es_argv[es_argc++] = 1; // ESC[F == ESC[1F\r
+ if (es_argc != 1) return;\r
+ Pos.Y = Info.dwCursorPosition.Y - es_argv[0];\r
+ if (Pos.Y < 0) Pos.Y = 0;\r
+ Pos.X = 0;\r
+ SetConsoleCursorPosition( hConOut, Pos );\r
+ return;\r
+\r
+ case '`': // ESC[#`\r
+ case 'G': // ESC[#G Moves cursor column # in current row.\r
+ if (es_argc == 0) es_argv[es_argc++] = 1; // ESC[G == ESC[1G\r
+ if (es_argc != 1) return;\r
+ Pos.X = es_argv[0] - 1;\r
+ if (Pos.X >= Info.dwSize.X) Pos.X = Info.dwSize.X - 1;\r
+ if (Pos.X < 0) Pos.X = 0;\r
+ Pos.Y = Info.dwCursorPosition.Y;\r
+ SetConsoleCursorPosition( hConOut, Pos );\r
+ return;\r
+\r
+ case 'd': // ESC[#d Moves cursor row #, current column.\r
+ if (es_argc == 0) es_argv[es_argc++] = 1; // ESC[d == ESC[1d\r
+ if (es_argc != 1) return;\r
+ Pos.Y = es_argv[0] - 1;\r
+ if (Pos.Y < 0) Pos.Y = 0;\r
+ if (Pos.Y >= Info.dwSize.Y) Pos.Y = Info.dwSize.Y - 1;\r
+ SetConsoleCursorPosition( hConOut, Pos );\r
+ return;\r
+\r
+ case 'f': // ESC[#;#f\r
+ case 'H': // ESC[#;#H Moves cursor to line #, column #\r
+ if (es_argc == 0)\r
+ es_argv[es_argc++] = 1; // ESC[H == ESC[1;1H\r
+ if (es_argc == 1)\r
+ es_argv[es_argc++] = 1; // ESC[#H == ESC[#;1H\r
+ if (es_argc > 2) return;\r
+ Pos.X = es_argv[1] - 1;\r
+ if (Pos.X < 0) Pos.X = 0;\r
+ if (Pos.X >= Info.dwSize.X) Pos.X = Info.dwSize.X - 1;\r
+ Pos.Y = es_argv[0] - 1;\r
+ if (Pos.Y < 0) Pos.Y = 0;\r
+ if (Pos.Y >= Info.dwSize.Y) Pos.Y = Info.dwSize.Y - 1;\r
+ SetConsoleCursorPosition( hConOut, Pos );\r
+ return;\r
+\r
+ case 's': // ESC[s Saves cursor position for recall later\r
+ if (es_argc != 0) return;\r
+ SavePos = Info.dwCursorPosition;\r
+ return;\r
+\r
+ case 'u': // ESC[u Return to saved cursor position\r
+ if (es_argc != 0) return;\r
+ SetConsoleCursorPosition( hConOut, SavePos );\r
+ return;\r
+\r
+ case 'n': // ESC[#n Device status report\r
+ if (es_argc != 1) return; // ESC[n == ESC[0n -> ignored\r
+ switch (es_argv[0])\r
+ {\r
+ case 5: // ESC[5n Report status\r
+ SendSequence( L"\33[0n" ); // "OK"\r
+ return;\r
+\r
+ case 6: // ESC[6n Report cursor position\r
+ {\r
+ TCHAR buf[32];\r
+ wsprintf( buf, L"\33[%d;%dR", Info.dwCursorPosition.Y + 1,\r
+ Info.dwCursorPosition.X + 1 );\r
+ SendSequence( buf );\r
+ }\r
+ return;\r
+\r
+ default:\r
+ return;\r
+ }\r
+\r
+ case 't': // ESC[#t Window manipulation\r
+ if (es_argc != 1) return;\r
+ if (es_argv[0] == 21) // ESC[21t Report xterm window's title\r
+ {\r
+ TCHAR buf[MAX_PATH*2];\r
+ DWORD len = GetConsoleTitle( buf+3, lenof(buf)-3-2 );\r
+ // Too bad if it's too big or fails.\r
+ buf[0] = ESC;\r
+ buf[1] = ']';\r
+ buf[2] = 'l';\r
+ buf[3+len] = ESC;\r
+ buf[3+len+1] = '\\';\r
+ buf[3+len+2] = '\0';\r
+ SendSequence( buf );\r
+ }\r
+ return;\r
+\r
+ default:\r
+ return;\r
+ }\r
+ }\r
+ else // (prefix == ']')\r
+ {\r
+ // Ignore any \e]? or \e]> sequences.\r
+ if (prefix2 != 0)\r
+ return;\r
+\r
+ if (es_argc == 1 && es_argv[0] == 0) // ESC]0;titleST\r
+ {\r
+ SetConsoleTitle( Pt_arg );\r
+ }\r
+ }\r
+}\r
+\r
+//-----------------------------------------------------------------------------\r
+// ParseAndPrintString(hDev, lpBuffer, nNumberOfBytesToWrite)\r
+// Parses the string lpBuffer, interprets the escapes sequences and prints the\r
+// characters in the device hDev (console).\r
+// The lexer is a three states automata.\r
+// If the number of arguments es_argc > MAX_ARG, only the MAX_ARG-1 firsts and\r
+// the last arguments are processed (no es_argv[] overflow).\r
+//-----------------------------------------------------------------------------\r
+\r
+BOOL\r
+ParseAndPrintString( HANDLE hDev,\r
+ LPCVOID lpBuffer,\r
+ DWORD nNumberOfBytesToWrite,\r
+ LPDWORD lpNumberOfBytesWritten\r
+ )\r
+{\r
+ DWORD i;\r
+ LPCTSTR s;\r
+\r
+ if (hDev != hConOut) // reinit if device has changed\r
+ {\r
+ hConOut = hDev;\r
+ state = 1;\r
+ shifted = FALSE;\r
+ }\r
+ for (i = nNumberOfBytesToWrite, s = (LPCTSTR)lpBuffer; i > 0; i--, s++)\r
+ {\r
+ if (state == 1)\r
+ {\r
+ if (*s == ESC) state = 2;\r
+ else if (*s == SO) shifted = TRUE;\r
+ else if (*s == SI) shifted = FALSE;\r
+ else PushBuffer( *s );\r
+ }\r
+ else if (state == 2)\r
+ {\r
+ if (*s == ESC) ; // \e\e...\e == \e\r
+ else if ((*s == '[') || (*s == ']'))\r
+ {\r
+ FlushBuffer();\r
+ prefix = *s;\r
+ prefix2 = 0;\r
+ state = 3;\r
+ Pt_len = 0;\r
+ *Pt_arg = '\0';\r
+ }\r
+ else if (*s == ')' || *s == '(') state = 6;\r
+ else state = 1;\r
+ }\r
+ else if (state == 3)\r
+ {\r
+ if (is_digit( *s ))\r
+ {\r
+ es_argc = 0;\r
+ es_argv[0] = *s - '0';\r
+ state = 4;\r
+ }\r
+ else if (*s == ';')\r
+ {\r
+ es_argc = 1;\r
+ es_argv[0] = 0;\r
+ es_argv[1] = 0;\r
+ state = 4;\r
+ }\r
+ else if (*s == '?' || *s == '>')\r
+ {\r
+ prefix2 = *s;\r
+ }\r
+ else\r
+ {\r
+ es_argc = 0;\r
+ suffix = *s;\r
+ InterpretEscSeq();\r
+ state = 1;\r
+ }\r
+ }\r
+ else if (state == 4)\r
+ {\r
+ if (is_digit( *s ))\r
+ {\r
+ es_argv[es_argc] = 10 * es_argv[es_argc] + (*s - '0');\r
+ }\r
+ else if (*s == ';')\r
+ {\r
+ if (es_argc < MAX_ARG-1) es_argc++;\r
+ es_argv[es_argc] = 0;\r
+ if (prefix == ']')\r
+ state = 5;\r
+ }\r
+ else\r
+ {\r
+ es_argc++;\r
+ suffix = *s;\r
+ InterpretEscSeq();\r
+ state = 1;\r
+ }\r
+ }\r
+ else if (state == 5)\r
+ {\r
+ if (*s == BEL)\r
+ {\r
+ Pt_arg[Pt_len] = '\0';\r
+ InterpretEscSeq();\r
+ state = 1;\r
+ }\r
+ else if (*s == '\\' && Pt_len > 0 && Pt_arg[Pt_len-1] == ESC)\r
+ {\r
+ Pt_arg[--Pt_len] = '\0';\r
+ InterpretEscSeq();\r
+ state = 1;\r
+ }\r
+ else if (Pt_len < lenof(Pt_arg)-1)\r
+ Pt_arg[Pt_len++] = *s;\r
+ }\r
+ else if (state == 6)\r
+ {\r
+ // Ignore it (ESC ) 0 is implicit; nothing else is supported).\r
+ state = 1;\r
+ }\r
+ }\r
+ FlushBuffer();\r
+ if (lpNumberOfBytesWritten != NULL)\r
+ *lpNumberOfBytesWritten = nNumberOfBytesToWrite - i;\r
+ return (i == 0);\r
+}\r
+\r
+\r
+// ========== Hooking API functions\r
+//\r
+// References about API hooking (and dll injection):\r
+// - Matt Pietrek ~ Windows 95 System Programming Secrets.\r
+// - Jeffrey Richter ~ Programming Applications for Microsoft Windows 4th ed.\r
+\r
+// Macro for adding pointers/DWORDs together without C arithmetic interfering\r
+#define MakeVA( cast, offset ) (cast)((DWORD_PTR)(pDosHeader)+(DWORD)(offset))\r
+\r
+\r
+const char APIKernel[] = "kernel32.dll";\r
+const char APIConsole[] = "API-MS-Win-Core-Console-";\r
+const char APIProcessThreads[] = "API-MS-Win-Core-ProcessThreads-";\r
+const char APIProcessEnvironment[] = "API-MS-Win-Core-ProcessEnvironment-";\r
+const char APILibraryLoader[] = "API-MS-Win-Core-LibraryLoader-";\r
+const char APIFile[] = "API-MS-Win-Core-File-";\r
+\r
+typedef struct\r
+{\r
+ PCSTR name;\r
+ DWORD len;\r
+ HMODULE base;\r
+} API_DATA, *PAPI_DATA;\r
+\r
+API_DATA APIs[] =\r
+{\r
+ { APIConsole, sizeof(APIConsole) - 1, NULL },\r
+ { APIProcessThreads, sizeof(APIProcessThreads) - 1, NULL },\r
+ { APIProcessEnvironment, sizeof(APIProcessEnvironment) - 1, NULL },\r
+ { APILibraryLoader, sizeof(APILibraryLoader) - 1, NULL },\r
+ { APIFile, sizeof(APIFile) - 1, NULL },\r
+ { NULL, 0, NULL }\r
+};\r
+\r
+\r
+HMODULE hKernel; // Kernel32 module handle\r
+HINSTANCE hDllInstance; // Dll instance handle\r
+TCHAR hDllName[MAX_PATH]; // Dll file name\r
+#if defined(_WIN64) || defined(W32ON64)\r
+LPTSTR hDllNameType; // pointer to process type within above\r
+#endif\r
+\r
+typedef struct\r
+{\r
+ PCSTR lib;\r
+ PSTR name;\r
+ PROC newfunc;\r
+ PROC oldfunc;\r
+ PROC apifunc;\r
+} HookFn, *PHookFn;\r
+\r
+HookFn Hooks[];\r
+\r
+const WCHAR zIgnoring[] = L"Ignoring";\r
+const WCHAR zHooking[] = L"Hooking";\r
+const WCHAR zUnhooking[] = L"Unhooking";\r
+\r
+\r
+//-----------------------------------------------------------------------------\r
+// HookAPIOneMod\r
+// Substitute a new function in the Import Address Table (IAT) of the\r
+// specified module.\r
+// Return FALSE on error and TRUE on success.\r
+//-----------------------------------------------------------------------------\r
+\r
+BOOL HookAPIOneMod(\r
+ HMODULE hFromModule, // Handle of the module to intercept calls from\r
+ PHookFn Hooks, // Functions to replace\r
+ BOOL restore // Restore the original functions\r
+ )\r
+{\r
+ PIMAGE_DOS_HEADER pDosHeader;\r
+ PIMAGE_NT_HEADERS pNTHeader;\r
+ PIMAGE_IMPORT_DESCRIPTOR pImportDesc;\r
+ PIMAGE_THUNK_DATA pThunk;\r
+ PHookFn hook;\r
+\r
+ // Tests to make sure we're looking at a module image (the 'MZ' header)\r
+ pDosHeader = (PIMAGE_DOS_HEADER)hFromModule;\r
+ if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE)\r
+ {\r
+ DEBUGSTR( 1, L"Image has no DOS header!" );\r
+ return FALSE;\r
+ }\r
+\r
+ // The MZ header has a pointer to the PE header\r
+ pNTHeader = MakeVA( PIMAGE_NT_HEADERS, pDosHeader->e_lfanew );\r
+\r
+ // One more test to make sure we're looking at a "PE" image\r
+ if (pNTHeader->Signature != IMAGE_NT_SIGNATURE)\r
+ {\r
+ DEBUGSTR( 1, L"Image has no NT header!" );\r
+ return FALSE;\r
+ }\r
+\r
+ // We now have a valid pointer to the module's PE header.\r
+ // Get a pointer to its imports section.\r
+ pImportDesc = MakeVA( PIMAGE_IMPORT_DESCRIPTOR,\r
+ pNTHeader->OptionalHeader.\r
+ DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].\r
+ VirtualAddress );\r
+\r
+ // Bail out if the RVA of the imports section is 0 (it doesn't exist)\r
+ if (pImportDesc == (PIMAGE_IMPORT_DESCRIPTOR)pDosHeader)\r
+ return TRUE;\r
+\r
+ // Iterate through the array of imported module descriptors, looking\r
+ // for the module whose name matches the pszFunctionModule parameter.\r
+ for (; pImportDesc->Name; pImportDesc++)\r
+ {\r
+ BOOL kernel = TRUE;\r
+ PSTR pszModName = MakeVA( PSTR, pImportDesc->Name );\r
+ if (_stricmp( pszModName, APIKernel ) != 0)\r
+ {\r
+ PAPI_DATA lib;\r
+ for (lib = APIs; lib->name; ++lib)\r
+ {\r
+ if (_strnicmp( pszModName, lib->name, lib->len ) == 0)\r
+ {\r
+ if (lib->base == NULL)\r
+ {\r
+ lib->base = GetModuleHandleA( pszModName );\r
+ for (hook = Hooks; hook->name; ++hook)\r
+ if (hook->lib == lib->name)\r
+ hook->apifunc = GetProcAddress( lib->base, hook->name );\r
+ }\r
+ break;\r
+ }\r
+ }\r
+ if (lib->name == NULL)\r
+ {\r
+ if (log_level & 16)\r
+ DEBUGSTR( 2, L" %s %S", zIgnoring, pszModName );\r
+ continue;\r
+ }\r
+ kernel = FALSE;\r
+ }\r
+ if (log_level & 16)\r
+ DEBUGSTR( 2, L" Scanning %S", pszModName );\r
+\r
+ // Get a pointer to the found module's import address table (IAT).\r
+ pThunk = MakeVA( PIMAGE_THUNK_DATA, pImportDesc->FirstThunk );\r
+\r
+ // Blast through the table of import addresses, looking for the ones\r
+ // that match the original addresses.\r
+ while (pThunk->u1.Function)\r
+ {\r
+ for (hook = Hooks; hook->name; ++hook)\r
+ {\r
+ PROC patch = 0;\r
+ if (restore)\r
+ {\r
+ if ((PROC)pThunk->u1.Function == hook->newfunc)\r
+ patch = (kernel) ? hook->oldfunc : hook->apifunc;\r
+ }\r
+ else if ((PROC)pThunk->u1.Function == hook->oldfunc ||\r
+ (PROC)pThunk->u1.Function == hook->apifunc)\r
+ {\r
+ patch = hook->newfunc;\r
+ }\r
+ if (patch)\r
+ {\r
+ DWORD flOldProtect, flNewProtect, flDummy;\r
+ MEMORY_BASIC_INFORMATION mbi;\r
+\r
+ DEBUGSTR( 3, L" %S", hook->name );\r
+ // Get the current protection attributes.\r
+ VirtualQuery( &pThunk->u1.Function, &mbi, sizeof(mbi) );\r
+ // Take the access protection flags.\r
+ flNewProtect = mbi.Protect;\r
+ // Remove ReadOnly and ExecuteRead flags.\r
+ flNewProtect &= ~(PAGE_READONLY | PAGE_EXECUTE_READ);\r
+ // Add on ReadWrite flag\r
+ flNewProtect |= (PAGE_READWRITE);\r
+ // Change the access protection on the region of committed pages in the\r
+ // virtual address space of the current process.\r
+ VirtualProtect( &pThunk->u1.Function, sizeof(PVOID),\r
+ flNewProtect, &flOldProtect );\r
+\r
+ // Overwrite the original address with the address of the new function.\r
+ if (!WriteProcessMemory( GetCurrentProcess(),\r
+ &pThunk->u1.Function,\r
+ &patch, sizeof(patch), NULL ))\r
+ {\r
+ DEBUGSTR( 1, L"Could not patch!" );\r
+ return FALSE;\r
+ }\r
+\r
+ // Put the page attributes back the way they were.\r
+ VirtualProtect( &pThunk->u1.Function, sizeof(PVOID),\r
+ flOldProtect, &flDummy );\r
+ }\r
+ }\r
+ pThunk++; // Advance to next imported function address\r
+ }\r
+ }\r
+\r
+ return TRUE; // Function not found\r
+}\r
+\r
+//-----------------------------------------------------------------------------\r
+// HookAPIAllMod\r
+// Substitute a new function in the Import Address Table (IAT) of all\r
+// the modules in the current process.\r
+// Return FALSE on error and TRUE on success.\r
+//-----------------------------------------------------------------------------\r
+\r
+BOOL HookAPIAllMod( PHookFn Hooks, BOOL restore )\r
+{\r
+ HANDLE hModuleSnap;\r
+ MODULEENTRY32 me;\r
+ BOOL fOk;\r
+\r
+ // Take a snapshot of all modules in the current process.\r
+ hModuleSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE,\r
+ GetCurrentProcessId() );\r
+\r
+ if (hModuleSnap == INVALID_HANDLE_VALUE)\r
+ {\r
+ DEBUGSTR( 1, L"Failed to create snapshot!" );\r
+ return FALSE;\r
+ }\r
+\r
+ // Fill the size of the structure before using it.\r
+ me.dwSize = sizeof(MODULEENTRY32);\r
+\r
+ // Walk the module list of the modules.\r
+ for (fOk = Module32First( hModuleSnap, &me ); fOk;\r
+ fOk = Module32Next( hModuleSnap, &me ))\r
+ {\r
+ // We don't hook functions in our own module.\r
+ if (me.hModule != hDllInstance && me.hModule != hKernel)\r
+ {\r
+ if (search_env( L"ANSICON_EXC", me.szModule ))\r
+ {\r
+ DEBUGSTR( 2, L"%s %s", zIgnoring, me.szModule );\r
+ continue;\r
+ }\r
+ DEBUGSTR( 2, L"%s %s", (restore) ? zUnhooking : zHooking, me.szModule );\r
+ // Hook this function in this module.\r
+ if (!HookAPIOneMod( me.hModule, Hooks, restore ))\r
+ {\r
+ CloseHandle( hModuleSnap );\r
+ return FALSE;\r
+ }\r
+ }\r
+ }\r
+ CloseHandle( hModuleSnap );\r
+ DEBUGSTR( 2, L"%s completed", (restore) ? zUnhooking : zHooking );\r
+ return TRUE;\r
+}\r
+\r
+\r
+// ========== Child process injection\r
+\r
+// Inject code into the target process to load our DLL.\r
+void Inject( DWORD dwCreationFlags, LPPROCESS_INFORMATION lpi,\r
+ LPPROCESS_INFORMATION child_pi,\r
+ BOOL wide, LPCVOID lpApp, LPCVOID lpCmd )\r
+{\r
+ int type;\r
+ BOOL gui;\r
+\r
+ type = ProcessType( child_pi, &gui );\r
+ if (gui)\r
+ {\r
+ TCHAR app[MAX_PATH];\r
+ LPTSTR name;\r
+ LPCTSTR term = L" \t";\r
+\r
+ app[MAX_PATH-1] = '\0';\r
+ if (lpApp == NULL)\r
+ {\r
+ // Extract the program from the command line. I would use\r
+ // GetModuleFileNameEx, but it doesn't work when a process is created\r
+ // suspended and setting up a delay until it does work sometimes\r
+ // prevents the process running at all. GetProcessImageFileName works,\r
+ // but it's not supported in 2K.\r
+ if (wide)\r
+ {\r
+ LPCTSTR pos;\r
+ for (pos = lpCmd; *pos == ' ' || *pos == '\t'; ++pos) ;\r
+ if (*pos == '"')\r
+ {\r
+ term = L"\"";\r
+ ++pos;\r
+ }\r
+ wcsncpy( app, pos, MAX_PATH-1 );\r
+ }\r
+ else\r
+ {\r
+ LPCSTR pos;\r
+ for (pos = lpCmd; *pos == ' ' || *pos == '\t'; ++pos) ;\r
+ if (*pos == '"')\r
+ {\r
+ term = L"\"";\r
+ ++pos;\r
+ }\r
+ MultiByteToWideChar( CP_ACP, 0, pos, -1, app, MAX_PATH );\r
+ }\r
+ // CreateProcess only works with surrounding quotes ('"a name"' works, but\r
+ // 'a" "name' fails), so that's all I'll test, too. However, it also\r
+ // tests for a file at each separator ('a name' tries "a.exe" before\r
+ // "a name.exe") which I won't do.\r
+ name = wcspbrk( app, term );\r
+ if (name)\r
+ *name = '\0';\r
+ }\r
+ else\r
+ {\r
+ if (wide)\r
+ wcsncpy( app, lpApp, MAX_PATH-1 );\r
+ else\r
+ MultiByteToWideChar( CP_ACP, 0, lpApp, -1, app, MAX_PATH );\r
+ }\r
+ name = get_program_name( app );\r
+ if (!search_env( L"ANSICON_GUI", name ))\r
+ {\r
+ DEBUGSTR( 1, L" %s", zIgnoring );\r
+ type = 0;\r
+ }\r
+ }\r
+ if (type != 0)\r
+ {\r
+#ifdef _WIN64\r
+ if (type == 32)\r
+ {\r
+ hDllNameType[0] = '3';\r
+ hDllNameType[1] = '2';\r
+ InjectDLL32( child_pi, hDllName );\r
+ }\r
+ else\r
+ {\r
+ hDllNameType[0] = '6';\r
+ hDllNameType[1] = '4';\r
+ InjectDLL64( child_pi, hDllName );\r
+ }\r
+#else\r
+#ifdef W32ON64\r
+ if (type == 64)\r
+ {\r
+ TCHAR args[64];\r
+ STARTUPINFO si;\r
+ PROCESS_INFORMATION pi;\r
+ wcscpy( hDllNameType, L"CON.exe" );\r
+ wsprintf( args, L"ansicon -P%lu:%lu",\r
+ child_pi->dwProcessId, child_pi->dwThreadId );\r
+ ZeroMemory( &si, sizeof(si) );\r
+ si.cb = sizeof(si);\r
+ if (CreateProcess( hDllName, args, NULL, NULL, FALSE, 0, NULL, NULL,\r
+ &si, &pi ))\r
+ {\r
+ WaitForSingleObject( pi.hProcess, INFINITE );\r
+ CloseHandle( pi.hProcess );\r
+ CloseHandle( pi.hThread );\r
+ }\r
+ else\r
+ DEBUGSTR( 1, L"Could not execute \"%s\"", hDllName );\r
+ wcscpy( hDllNameType, L"32.dll" );\r
+ }\r
+ else\r
+#endif\r
+ InjectDLL32( child_pi, hDllName );\r
+#endif\r
+ if (!gui && !(dwCreationFlags & (CREATE_NEW_CONSOLE | DETACHED_PROCESS)))\r
+ {\r
+ LPPROCESS_INFORMATION cpi;\r
+ s_pid = child_pi->dwProcessId;\r
+ s_grm = grm;\r
+ s_flag = GRM_INIT;\r
+ cpi = malloc( sizeof(*cpi) );\r
+ cpi->dwProcessId = child_pi->dwProcessId;\r
+ DuplicateHandle( GetCurrentProcess(), child_pi->hProcess,\r
+ GetCurrentProcess(), &cpi->hProcess, 0, FALSE,\r
+ DUPLICATE_SAME_ACCESS );\r
+ CloseHandle( CreateThread( NULL, 4096, UpdateGRM, cpi, 0, NULL ) );\r
+ }\r
+ }\r
+\r
+ if (!(dwCreationFlags & CREATE_SUSPENDED))\r
+ ResumeThread( child_pi->hThread );\r
+\r
+ if (lpi)\r
+ {\r
+ memcpy( lpi, child_pi, sizeof(PROCESS_INFORMATION) );\r
+ }\r
+ else\r
+ {\r
+ CloseHandle( child_pi->hThread );\r
+ CloseHandle( child_pi->hProcess );\r
+ }\r
+}\r
+\r
+\r
+BOOL WINAPI MyCreateProcessA( LPCSTR lpApplicationName,\r
+ LPSTR lpCommandLine,\r
+ LPSECURITY_ATTRIBUTES lpThreadAttributes,\r
+ LPSECURITY_ATTRIBUTES lpProcessAttributes,\r
+ BOOL bInheritHandles,\r
+ DWORD dwCreationFlags,\r
+ LPVOID lpEnvironment,\r
+ LPCSTR lpCurrentDirectory,\r
+ LPSTARTUPINFOA lpStartupInfo,\r
+ LPPROCESS_INFORMATION lpProcessInformation )\r
+{\r
+ PROCESS_INFORMATION child_pi;\r
+\r
+ if (!CreateProcessA( lpApplicationName,\r
+ lpCommandLine,\r
+ lpThreadAttributes,\r
+ lpProcessAttributes,\r
+ bInheritHandles,\r
+ dwCreationFlags | CREATE_SUSPENDED,\r
+ lpEnvironment,\r
+ lpCurrentDirectory,\r
+ lpStartupInfo,\r
+ &child_pi ))\r
+ return FALSE;\r
+\r
+ DEBUGSTR( 1, L"CreateProcessA: (%lu) \"%S\", \"%S\"",\r
+ child_pi.dwProcessId,\r
+ (lpApplicationName == NULL) ? "" : lpApplicationName,\r
+ (lpCommandLine == NULL) ? "" : lpCommandLine );\r
+ Inject( dwCreationFlags, lpProcessInformation, &child_pi,\r
+ FALSE, lpApplicationName, lpCommandLine );\r
+\r
+ return TRUE;\r
+}\r
+\r
+\r
+BOOL WINAPI MyCreateProcessW( LPCWSTR lpApplicationName,\r
+ LPWSTR lpCommandLine,\r
+ LPSECURITY_ATTRIBUTES lpThreadAttributes,\r
+ LPSECURITY_ATTRIBUTES lpProcessAttributes,\r
+ BOOL bInheritHandles,\r
+ DWORD dwCreationFlags,\r
+ LPVOID lpEnvironment,\r
+ LPCWSTR lpCurrentDirectory,\r
+ LPSTARTUPINFOW lpStartupInfo,\r
+ LPPROCESS_INFORMATION lpProcessInformation )\r
+{\r
+ PROCESS_INFORMATION child_pi;\r
+\r
+ if (!CreateProcessW( lpApplicationName,\r
+ lpCommandLine,\r
+ lpThreadAttributes,\r
+ lpProcessAttributes,\r
+ bInheritHandles,\r
+ dwCreationFlags | CREATE_SUSPENDED,\r
+ lpEnvironment,\r
+ lpCurrentDirectory,\r
+ lpStartupInfo,\r
+ &child_pi ))\r
+ return FALSE;\r
+\r
+ DEBUGSTR( 1, L"CreateProcessW: (%lu) \"%s\", \"%s\"",\r
+ child_pi.dwProcessId,\r
+ (lpApplicationName == NULL) ? L"" : lpApplicationName,\r
+ (lpCommandLine == NULL) ? L"" : lpCommandLine );\r
+ Inject( dwCreationFlags, lpProcessInformation, &child_pi,\r
+ TRUE, lpApplicationName, lpCommandLine );\r
+\r
+ return TRUE;\r
+}\r
+\r
+\r
+FARPROC WINAPI MyGetProcAddress( HMODULE hModule, LPCSTR lpProcName )\r
+{\r
+ PHookFn hook;\r
+ FARPROC proc;\r
+\r
+ proc = GetProcAddress( hModule, lpProcName );\r
+\r
+ if (proc)\r
+ {\r
+ if (hModule == hKernel)\r
+ {\r
+ // Ignore LoadLibrary so other hooks continue to work (our version\r
+ // might end up at a different address).\r
+ if (proc == Hooks[0].oldfunc || proc == Hooks[1].oldfunc)\r
+ {\r
+ DEBUGSTR( 3, L"GetProcAddress: %S (ignoring)", lpProcName );\r
+ return proc;\r
+ }\r
+ for (hook = Hooks + 2; hook->name; ++hook)\r
+ {\r
+ if (proc == hook->oldfunc)\r
+ {\r
+ DEBUGSTR( 3, L"GetProcAddress: %S", lpProcName );\r
+ return hook->newfunc;\r
+ }\r
+ }\r
+ }\r
+ else\r
+ {\r
+ PAPI_DATA api;\r
+ for (api = APIs; api->name; ++api)\r
+ {\r
+ if (hModule == api->base)\r
+ {\r
+ if (proc == Hooks[0].apifunc || proc == Hooks[1].apifunc)\r
+ {\r
+ DEBUGSTR( 3, L"GetProcAddress: %S (ignoring)", lpProcName );\r
+ return proc;\r
+ }\r
+ for (hook = Hooks + 2; hook->name; ++hook)\r
+ {\r
+ if (proc == hook->apifunc)\r
+ {\r
+ DEBUGSTR( 3, L"GetProcAddress: %S", lpProcName );\r
+ return hook->newfunc;\r
+ }\r
+ }\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ return proc;\r
+}\r
+\r
+\r
+void HookLibrary( HMODULE hMod, LPCVOID lpFileName, BOOL wide, LPCSTR funcName )\r
+{\r
+ LPCWSTR name;\r
+ WCHAR wname[MAX_PATH];\r
+\r
+ if (hMod && hMod != hKernel)\r
+ {\r
+ if (!wide)\r
+ {\r
+ MultiByteToWideChar( AreFileApisANSI() ? CP_ACP : CP_OEMCP, 0,\r
+ lpFileName, -1, wname, MAX_PATH );\r
+ lpFileName = wname;\r
+ }\r
+ name = wcsrchr( lpFileName, '\\' );\r
+ if (name == NULL)\r
+ name = lpFileName;\r
+ else\r
+ ++name;\r
+ if (search_env( L"ANSICON_EXC", name ))\r
+ DEBUGSTR( 2, L"%s %s (%S)", zIgnoring, lpFileName, funcName );\r
+ else\r
+ {\r
+ DEBUGSTR( 2, L"%s %s (%S)", zHooking, lpFileName, funcName );\r
+ HookAPIOneMod( hMod, Hooks, FALSE );\r
+ }\r
+ }\r
+}\r
+\r
+\r
+HMODULE WINAPI MyLoadLibraryA( LPCSTR lpFileName )\r
+{\r
+ HMODULE hMod = LoadLibraryA( lpFileName );\r
+ HookLibrary( hMod, lpFileName, FALSE, "LoadLibraryA" );\r
+ return hMod;\r
+}\r
+\r
+\r
+HMODULE WINAPI MyLoadLibraryW( LPCWSTR lpFileName )\r
+{\r
+ HMODULE hMod = LoadLibraryW( lpFileName );\r
+ HookLibrary( hMod, lpFileName, TRUE, "LoadLibraryW" );\r
+ return hMod;\r
+}\r
+\r
+\r
+HMODULE WINAPI MyLoadLibraryExA( LPCSTR lpFileName, HANDLE hFile,\r
+ DWORD dwFlags )\r
+{\r
+ HMODULE hMod = LoadLibraryExA( lpFileName, hFile, dwFlags );\r
+ if (!(dwFlags & LOAD_LIBRARY_AS_DATAFILE))\r
+ HookLibrary( hMod, lpFileName, FALSE, "LoadLibraryExA" );\r
+ return hMod;\r
+}\r
+\r
+\r
+HMODULE WINAPI MyLoadLibraryExW( LPCWSTR lpFileName, HANDLE hFile,\r
+ DWORD dwFlags )\r
+{\r
+ HMODULE hMod = LoadLibraryExW( lpFileName, hFile, dwFlags );\r
+ if (!(dwFlags & LOAD_LIBRARY_AS_DATAFILE))\r
+ HookLibrary( hMod, lpFileName, TRUE, "LoadLibraryExW" );\r
+ return hMod;\r
+}\r
+\r
+\r
+//-----------------------------------------------------------------------------\r
+// IsConsoleHandle\r
+// Determine if the handle is writing to the console, with processed output.\r
+//-----------------------------------------------------------------------------\r
+BOOL IsConsoleHandle( HANDLE h )\r
+{\r
+ DWORD mode;\r
+\r
+ if (!GetConsoleMode( h, &mode ))\r
+ {\r
+ // This fails if the handle isn't opened for reading. Fortunately, it\r
+ // seems WriteConsole tests the handle before it tests the length.\r
+ return WriteConsole( h, NULL, 0, &mode, NULL );\r
+ }\r
+\r
+ return (mode & ENABLE_PROCESSED_OUTPUT);\r
+}\r
+\r
+\r
+//-----------------------------------------------------------------------------\r
+// MyWrite...\r
+// The new functions that must replace the original Write... functions. These\r
+// functions have exactly the same signature as the original ones. This\r
+// module is not hooked, so we can still call the original functions ourselves.\r
+//-----------------------------------------------------------------------------\r
+\r
+BOOL\r
+WINAPI MyWriteConsoleA( HANDLE hCon, LPCVOID lpBuffer,\r
+ DWORD nNumberOfCharsToWrite,\r
+ LPDWORD lpNumberOfCharsWritten, LPVOID lpReserved )\r
+{\r
+ LPWSTR buf;\r
+ DWORD len;\r
+ BOOL rc = TRUE;\r
+\r
+ if (IsConsoleHandle( hCon ))\r
+ {\r
+ UINT cp = GetConsoleOutputCP();\r
+ DEBUGSTR( 4, L"\33WriteConsoleA: %lu \"%.*S\"",\r
+ nNumberOfCharsToWrite, nNumberOfCharsToWrite, lpBuffer );\r
+ len = MultiByteToWideChar( cp, 0, lpBuffer, nNumberOfCharsToWrite, NULL,0 );\r
+ buf = malloc( TSIZE(len) );\r
+ if (buf == NULL)\r
+ {\r
+ if (lpNumberOfCharsWritten != NULL)\r
+ *lpNumberOfCharsWritten = 0;\r
+ return (nNumberOfCharsToWrite == 0);\r
+ }\r
+ MultiByteToWideChar( cp, 0, lpBuffer, nNumberOfCharsToWrite, buf, len );\r
+ rc = ParseAndPrintString( hCon, buf, len, lpNumberOfCharsWritten );\r
+ free( buf );\r
+ if (rc && lpNumberOfCharsWritten != NULL &&\r
+ *lpNumberOfCharsWritten != nNumberOfCharsToWrite)\r
+ {\r
+ // Converting a multibyte character to Unicode results in a different\r
+ // "character" count. This causes some programs to think not everything\r
+ // was written, so the difference is sent again. Fudge the (presumably)\r
+ // correct count.\r
+ if (search_env( L"ANSICON_API", prog ))\r
+ *lpNumberOfCharsWritten = nNumberOfCharsToWrite;\r
+ }\r
+ return rc;\r
+ }\r
+\r
+ return WriteConsoleA( hCon, lpBuffer, nNumberOfCharsToWrite,\r
+ lpNumberOfCharsWritten, lpReserved );\r
+\r
+}\r
+\r
+BOOL\r
+WINAPI MyWriteConsoleW( HANDLE hCon, LPCVOID lpBuffer,\r
+ DWORD nNumberOfCharsToWrite,\r
+ LPDWORD lpNumberOfCharsWritten, LPVOID lpReserved )\r
+{\r
+ if (IsConsoleHandle( hCon ))\r
+ {\r
+ DEBUGSTR( 4, L"\33WriteConsoleW: %lu \"%.*s\"",\r
+ nNumberOfCharsToWrite, nNumberOfCharsToWrite, lpBuffer );\r
+ return ParseAndPrintString( hCon, lpBuffer,\r
+ nNumberOfCharsToWrite,\r
+ lpNumberOfCharsWritten );\r
+ }\r
+\r
+ return WriteConsoleW( hCon, lpBuffer, nNumberOfCharsToWrite,\r
+ lpNumberOfCharsWritten, lpReserved );\r
+}\r
+\r
+BOOL\r
+WINAPI MyWriteFile( HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,\r
+ LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped )\r
+{\r
+ if (IsConsoleHandle( hFile ))\r
+ {\r
+ DEBUGSTR( 4, L"WriteFile->" );\r
+ return MyWriteConsoleA( hFile, lpBuffer,\r
+ nNumberOfBytesToWrite,\r
+ lpNumberOfBytesWritten,\r
+ lpOverlapped );\r
+ }\r
+\r
+ return WriteFile( hFile, lpBuffer, nNumberOfBytesToWrite,\r
+ lpNumberOfBytesWritten, lpOverlapped );\r
+}\r
+\r
+\r
+#define HHFILE (HANDLE)(DWORD_PTR)\r
+\r
+UINT\r
+WINAPI My_lwrite( HFILE hFile, LPCSTR lpBuffer, UINT uBytes )\r
+{\r
+ if (IsConsoleHandle( HHFILE hFile ))\r
+ {\r
+ DWORD written;\r
+ DEBUGSTR( 4, L"_lwrite->" );\r
+ MyWriteConsoleA( HHFILE hFile, lpBuffer, uBytes, &written, NULL );\r
+ return written;\r
+ }\r
+\r
+ return _lwrite( hFile, lpBuffer, uBytes );\r
+}\r
+\r
+long\r
+WINAPI My_hwrite( HFILE hFile, LPCSTR lpBuffer, long lBytes )\r
+{\r
+ if (IsConsoleHandle( HHFILE hFile ))\r
+ {\r
+ DWORD written;\r
+ DEBUGSTR( 4, L"_hwrite->" );\r
+ MyWriteConsoleA( HHFILE hFile, lpBuffer, lBytes, &written, NULL );\r
+ return written;\r
+ }\r
+\r
+ return _hwrite( hFile, lpBuffer, lBytes );\r
+}\r
+\r
+\r
+// ========== Environment variable\r
+\r
+void set_ansicon( PCONSOLE_SCREEN_BUFFER_INFO pcsbi )\r
+{\r
+ CONSOLE_SCREEN_BUFFER_INFO csbi;\r
+ TCHAR buf[64];\r
+\r
+ if (pcsbi == NULL)\r
+ {\r
+ HANDLE hConOut;\r
+ hConOut = CreateFile( L"CONOUT$", GENERIC_READ | GENERIC_WRITE,\r
+ FILE_SHARE_READ | FILE_SHARE_WRITE,\r
+ NULL, OPEN_EXISTING, 0, 0 );\r
+ GetConsoleScreenBufferInfo( hConOut, &csbi );\r
+ CloseHandle( hConOut );\r
+ pcsbi = &csbi;\r
+ }\r
+\r
+ wsprintf( buf, L"%dx%d (%dx%d)",\r
+ pcsbi->dwSize.X, pcsbi->dwSize.Y,\r
+ pcsbi->srWindow.Right - pcsbi->srWindow.Left + 1,\r
+ pcsbi->srWindow.Bottom - pcsbi->srWindow.Top + 1 );\r
+ SetEnvironmentVariable( L"ANSICON", buf );\r
+}\r
+\r
+DWORD\r
+WINAPI MyGetEnvironmentVariableA( LPCSTR lpName, LPSTR lpBuffer, DWORD nSize )\r
+{\r
+ if (lstrcmpiA( lpName, "ANSICON_VER" ) == 0)\r
+ {\r
+ if (nSize < sizeof(PVEREA))\r
+ return sizeof(PVEREA);\r
+ memcpy( lpBuffer, PVEREA, sizeof(PVEREA) );\r
+ return sizeof(PVEREA) - 1;\r
+ }\r
+\r
+ if (lstrcmpiA( lpName, "ANSICON" ) == 0)\r
+ set_ansicon( NULL );\r
+\r
+ return GetEnvironmentVariableA( lpName, lpBuffer, nSize );\r
+}\r
+\r
+DWORD\r
+WINAPI MyGetEnvironmentVariableW( LPCWSTR lpName, LPWSTR lpBuffer, DWORD nSize )\r
+{\r
+ if (lstrcmpi( lpName, L"ANSICON_VER" ) == 0)\r
+ {\r
+ if (nSize < lenof(PVERE))\r
+ return lenof(PVERE);\r
+ memcpy( lpBuffer, PVERE, sizeof(PVERE) );\r
+ return lenof(PVERE) - 1;\r
+ }\r
+\r
+ if (lstrcmpi( lpName, L"ANSICON" ) == 0)\r
+ set_ansicon( NULL );\r
+\r
+ return GetEnvironmentVariableW( lpName, lpBuffer, nSize );\r
+}\r
+\r
+\r
+// ========== Initialisation\r
+\r
+HookFn Hooks[] = {\r
+ // These two are expected first!\r
+ { APILibraryLoader, "LoadLibraryA", (PROC)MyLoadLibraryA, NULL, NULL },\r
+ { APILibraryLoader, "LoadLibraryW", (PROC)MyLoadLibraryW, NULL, NULL },\r
+ { APIProcessThreads, "CreateProcessA", (PROC)MyCreateProcessA, NULL, NULL },\r
+ { APIProcessThreads, "CreateProcessW", (PROC)MyCreateProcessW, NULL, NULL },\r
+ { APIProcessEnvironment, "GetEnvironmentVariableA", (PROC)MyGetEnvironmentVariableA, NULL, NULL },\r
+ { APIProcessEnvironment, "GetEnvironmentVariableW", (PROC)MyGetEnvironmentVariableW, NULL, NULL },\r
+ { APILibraryLoader, "GetProcAddress", (PROC)MyGetProcAddress, NULL, NULL },\r
+ { APILibraryLoader, "LoadLibraryExA", (PROC)MyLoadLibraryExA, NULL, NULL },\r
+ { APILibraryLoader, "LoadLibraryExW", (PROC)MyLoadLibraryExW, NULL, NULL },\r
+ { APIConsole, "WriteConsoleA", (PROC)MyWriteConsoleA, NULL, NULL },\r
+ { APIConsole, "WriteConsoleW", (PROC)MyWriteConsoleW, NULL, NULL },\r
+ { APIFile, "WriteFile", (PROC)MyWriteFile, NULL, NULL },\r
+ { APIKernel, "_lwrite", (PROC)My_lwrite, NULL, NULL },\r
+ { APIKernel, "_hwrite", (PROC)My_hwrite, NULL, NULL },\r
+ { NULL, NULL, NULL, NULL, NULL }\r
+};\r
+\r
+//-----------------------------------------------------------------------------\r
+// OriginalAttr()\r
+// Determine the original attributes for use by \e[m.\r
+//-----------------------------------------------------------------------------\r
+void OriginalAttr( void )\r
+{\r
+ HANDLE hConOut;\r
+ CONSOLE_SCREEN_BUFFER_INFO csbi;\r
+\r
+ hConOut = CreateFile( L"CONOUT$", GENERIC_READ | GENERIC_WRITE,\r
+ FILE_SHARE_READ | FILE_SHARE_WRITE,\r
+ NULL, OPEN_EXISTING, 0, 0 );\r
+ if (!GetConsoleScreenBufferInfo( hConOut, &csbi ))\r
+ csbi.wAttributes = 7;\r
+ CloseHandle( hConOut );\r
+\r
+ if (s_flag == GRM_INIT && s_pid == GetCurrentProcessId())\r
+ {\r
+ s_flag = 0;\r
+ grm = s_grm;\r
+ }\r
+ else\r
+ {\r
+ if (GetEnvironmentVariable( L"ANSICON_REVERSE", NULL, 0 ))\r
+ {\r
+ SetEnvironmentVariable( L"ANSICON_REVERSE", NULL );\r
+ grm.reverse = TRUE;\r
+ grm.foreground = attr2ansi[(csbi.wAttributes >> 4) & 7];\r
+ grm.background = attr2ansi[csbi.wAttributes & 7];\r
+ grm.bold = (csbi.wAttributes & BACKGROUND_INTENSITY) >> 4;\r
+ grm.underline = (csbi.wAttributes & FOREGROUND_INTENSITY) << 4;\r
+ }\r
+ else\r
+ {\r
+ grm.foreground = attr2ansi[csbi.wAttributes & 7];\r
+ grm.background = attr2ansi[(csbi.wAttributes >> 4) & 7];\r
+ grm.bold = csbi.wAttributes & FOREGROUND_INTENSITY;\r
+ grm.underline = csbi.wAttributes & BACKGROUND_INTENSITY;\r
+ }\r
+ }\r
+ if (!GetEnvironmentVariable( L"ANSICON_DEF", NULL, 0 ))\r
+ {\r
+ TCHAR def[4];\r
+ LPTSTR a = def;\r
+ if (grm.reverse)\r
+ {\r
+ *a++ = '-';\r
+ csbi.wAttributes = ((csbi.wAttributes >> 4) & 15)\r
+ | ((csbi.wAttributes & 15) << 4);\r
+ }\r
+ wsprintf( a, L"%X", csbi.wAttributes & 255 );\r
+ SetEnvironmentVariable( L"ANSICON_DEF", def );\r
+ }\r
+ set_ansicon( &csbi );\r
+}\r
+\r
+\r
+//-----------------------------------------------------------------------------\r
+// DllMain()\r
+// Function called by the system when processes and threads are initialized\r
+// and terminated.\r
+//-----------------------------------------------------------------------------\r
+\r
+__declspec(dllexport) // just to stop MinGW exporting everything\r
+BOOL WINAPI DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved )\r
+{\r
+ BOOL bResult = TRUE;\r
+ PHookFn hook;\r
+ TCHAR logstr[4];\r
+\r
+ if (dwReason == DLL_PROCESS_ATTACH)\r
+ {\r
+ *logstr = '\0';\r
+ GetEnvironmentVariable( L"ANSICON_LOG", logstr, lenof(logstr) );\r
+ log_level = _wtoi( logstr );\r
+ prog = get_program_name( NULL );\r
+#if defined(_WIN64) || defined(W32ON64)\r
+ hDllNameType = hDllName - 6 +\r
+#endif\r
+ GetModuleFileName( hInstance, hDllName, lenof(hDllName) );\r
+\r
+ hDllInstance = hInstance; // save Dll instance handle\r
+ DEBUGSTR( 1, L"hDllInstance = %p", hDllInstance );\r
+\r
+ // Get the entry points to the original functions.\r
+ hKernel = GetModuleHandleA( APIKernel );\r
+ for (hook = Hooks; hook->name; ++hook)\r
+ hook->oldfunc = GetProcAddress( hKernel, hook->name );\r
+\r
+ bResult = HookAPIAllMod( Hooks, FALSE );\r
+ OriginalAttr();\r
+ DisableThreadLibraryCalls( hInstance );\r
+ }\r
+ else if (dwReason == DLL_PROCESS_DETACH)\r
+ {\r
+ if (lpReserved == NULL)\r
+ {\r
+ DEBUGSTR( 1, L"Unloading" );\r
+ HookAPIAllMod( Hooks, TRUE );\r
+ }\r
+ else\r
+ {\r
+ DEBUGSTR( 1, L"Terminating" );\r
+ s_pid = GetCurrentProcessId();\r
+ s_grm = grm;\r
+ s_flag = GRM_EXIT;\r
+ }\r
+ }\r
+\r
+ return bResult;\r
+}\r
+++ /dev/null
-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.
-@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 { ^| } ~^
-
-^
-
-\ e _ ` 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 { ^| } ~\ f
+@echo off & setlocal\r
+\r
+::Extract the current code page. Hopefully this method will work with other\r
+::languages. CHCP outputs: "Active code page: #". Take the last five\r
+::characters (the longest code) and delete up to and including the space.\r
+for /f "delims=" %%j in ('chcp') do set CP=%%j\r
+set CP=%CP:~-5%\r
+set CP=%CP:* =%\r
+\r
+x86\ansicon -e The DEC Special Graphics Character Set according to code page %CP%:^\r
+\r
+^\r
+\r
+ _ ` 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 { ^| } ~^\r
+\r
+^\r
+\r
+\ e _ ` 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 { ^| } ~\ f\r
--- /dev/null
+Copyright (C) 2005-2013 Jason Hood\r
+\r
+This software is provided 'as-is', without any express or implied\r
+warranty. In no event will the author be held liable for any damages\r
+arising from the use of this software.\r
+\r
+Permission is granted to anyone to use this software for any purpose,\r
+including commercial applications, and to alter it and redistribute it\r
+freely, subject to the following restrictions:\r
+\r
+1. The origin of this software must not be misrepresented; you must not\r
+ claim that you wrote the original software. If you use this software\r
+ in a product, an acknowledgment in the product documentation would be\r
+ appreciated but is not required.\r
+2. Altered source versions must be plainly marked as such, and must not be\r
+ misrepresented as being the original software.\r
+3. This notice may not be removed or altered from any source distribution.\r
+\r
+Jason Hood\r
+jadoxa@yahoo.com.au\r
-/*
- 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
- }
-}
+/*\r
+ ansi.rc - Version resource for ANSI{32,64}.dll.\r
+\r
+ Jason Hood, 11 November, 2009.\r
+*/\r
+\r
+#include <winver.h>\r
+#include "version.h"\r
+\r
+VS_VERSION_INFO VERSIONINFO\r
+FILEVERSION PVERB\r
+PRODUCTVERSION PVERB\r
+FILEOS VOS_NT\r
+FILETYPE VFT_DLL\r
+{\r
+ BLOCK "StringFileInfo"\r
+ {\r
+ BLOCK "040904B0"\r
+ {\r
+ VALUE "Comments", "http://ansicon.adoxa.vze.com/"\r
+ VALUE "CompanyName", "Jason Hood"\r
+ VALUE "FileDescription", "ANSI Console"\r
+ VALUE "FileVersion", PVERSA\r
+ VALUE "InternalName", "ANSI" BITS\r
+ VALUE "LegalCopyright", "Freeware"\r
+ VALUE "OriginalFilename", ANSIDLL\r
+ VALUE "ProductName", "ANSICON"\r
+ VALUE "ProductVersion", PVERSA\r
+ }\r
+ }\r
+\r
+ BLOCK "VarFileInfo"\r
+ {\r
+ VALUE "Translation", 0x0409, 0x04B0\r
+ }\r
+}\r
-/*
- 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)."
- );
-}
+/*\r
+ ANSICON.c - ANSI escape sequence console driver.\r
+\r
+ Jason Hood, 21 to 23 October, 2005.\r
+\r
+ Original injection code was derived from Console Manager by Sergey Oblomov\r
+ (hoopoepg). Use of FlushInstructionCache came from www.catch22.net.\r
+ Additional information came from "Process-wide API spying - an ultimate hack",\r
+ Anton Bassov's article in "The Code Project" (use of OpenThread).\r
+\r
+ v1.01, 11 & 12 March, 2006:\r
+ -m option to set "monochrome" (grey on black);\r
+ restore original color on exit.\r
+\r
+ v1.10, 22 February, 2009:\r
+ ignore Ctrl+C/Ctrl+Break.\r
+\r
+ v1.13, 21 & 27 March, 2009:\r
+ alternate injection method, to work with DEP;\r
+ use Unicode.\r
+\r
+ v1.20, 17 to 21 June, 2009:\r
+ use a combination of the two injection methods;\r
+ test if ANSICON is already installed;\r
+ added -e (and -E) option to echo the command line (without newline);\r
+ added -t (and -T) option to type (display) files (with file name).\r
+\r
+ v1.21, 23 September, 2009:\r
+ added -i (and -u) to add (remove) ANSICON to AutoRun.\r
+\r
+ v1.24, 6 & 7 January, 2010:\r
+ no arguments to -t, or using "-" for the name, will read from stdin;\r
+ fix -t and -e when ANSICON was already loaded.\r
+\r
+ v1.25, 22 July, 2010:\r
+ added -IU for HKLM.\r
+\r
+ v1.30, 3 August to 7 September, 2010:\r
+ x64 support.\r
+\r
+ v1.31, 13 & 15 November, 2010:\r
+ use LLW to fix potential Unicode path problems;\r
+ VC compatibility (2008 Express for 32-bit, PSDK 2003 R2 for 64-bit);\r
+ explicitly use wide characters (stick with TCHAR, but not <tchar.h>).\r
+\r
+ v1.32, 4 to 22 December, 2010:\r
+ make -p more robust;\r
+ inject into GUI processes;\r
+ -i implies -p.\r
+\r
+ v1.50, 7 to 14 December, 2011:\r
+ -u does not imply -p;\r
+ add the PID to the debugging output;\r
+ use ANSICON_VER to test if already installed;\r
+ always place first in AutoRun;\r
+ logging is always available, controlled by ANSICON_LOG environment variable;\r
+ only restore the original color after program/echo/type;\r
+ return program's exit code.\r
+\r
+ 7 January, 2012:\r
+ fixed installing into a piped CMD.EXE;\r
+ added a log message indicating all imports have been processed.\r
+\r
+ v1.52, 10 April, 2012:\r
+ fixed running "cmd" if "ComSpec" is not defined;\r
+ pass process & thread identifiers on the command line (for x86->x64).\r
+\r
+ v1.60, 22 & 24 November, 2012:\r
+ set the code page to convert strings correctly;\r
+ expand wildcards for -t;\r
+ write the date if appending to the log.\r
+\r
+ v1.62, 18 July, 2013:\r
+ write the bits to the log;\r
+ test if creating the registry key fails (HKLM requires admin privileges).\r
+\r
+ v1.63, 25 July, 2013:\r
+ don't write the reset sequence if output is redirected.\r
+*/\r
+\r
+#define PDATE L"21 September, 2013"\r
+\r
+#include "ansicon.h"\r
+#include "version.h"\r
+#include <tlhelp32.h>\r
+#include <ctype.h>\r
+#include <io.h>\r
+#include <locale.h>\r
+\r
+#ifdef __MINGW32__\r
+int _CRT_glob = 0;\r
+#endif\r
+\r
+\r
+#define CMDKEY L"Software\\Microsoft\\Command Processor"\r
+#define AUTORUN L"AutoRun"\r
+\r
+\r
+void help( void );\r
+\r
+void display( LPCTSTR, BOOL );\r
+void print_error( LPCTSTR, ... );\r
+LPTSTR skip_spaces( LPTSTR );\r
+void get_arg( LPTSTR, LPTSTR*, LPTSTR* );\r
+void get_file( LPTSTR, LPTSTR*, LPTSTR* );\r
+\r
+void process_autorun( TCHAR );\r
+\r
+BOOL find_proc_id( HANDLE snap, DWORD id, LPPROCESSENTRY32 ppe );\r
+BOOL GetParentProcessInfo( LPPROCESS_INFORMATION ppi, LPTSTR );\r
+\r
+\r
+// The DLL shares this variable, so injection requires it here.\r
+#ifdef _WIN64\r
+DWORD LLW32;\r
+extern LPVOID base;\r
+#endif\r
+\r
+\r
+// Find the name of the DLL and inject it.\r
+BOOL Inject( LPPROCESS_INFORMATION ppi, BOOL* gui, LPCTSTR app )\r
+{\r
+ DWORD len;\r
+ WCHAR dll[MAX_PATH];\r
+ int type;\r
+\r
+ DEBUGSTR( 1, L"%s (%lu)", app, ppi->dwProcessId );\r
+ type = ProcessType( ppi, gui );\r
+ if (type == 0)\r
+ {\r
+ fwprintf( stderr, L"ANSICON: %s: unsupported process.\n", app );\r
+ return FALSE;\r
+ }\r
+\r
+ len = (DWORD)(prog - prog_path);\r
+ memcpy( dll, prog_path, TSIZE(len) );\r
+#ifdef _WIN64\r
+ wsprintf( dll + len, L"ANSI%d.dll", type );\r
+ if (type == 32)\r
+ InjectDLL32( ppi, dll );\r
+ else\r
+ InjectDLL64( ppi, dll );\r
+#else\r
+ wcscpy( dll + len, L"ANSI32.dll" );\r
+ InjectDLL32( ppi, dll );\r
+#endif\r
+ return TRUE;\r
+}\r
+\r
+\r
+static HANDLE hConOut;\r
+static CONSOLE_SCREEN_BUFFER_INFO csbi;\r
+\r
+void get_original_attr( void )\r
+{\r
+ hConOut = CreateFile( L"CONOUT$", GENERIC_READ | GENERIC_WRITE,\r
+ FILE_SHARE_READ | FILE_SHARE_WRITE,\r
+ NULL, OPEN_EXISTING, 0, 0 );\r
+ GetConsoleScreenBufferInfo( hConOut, &csbi );\r
+}\r
+\r
+\r
+void set_original_attr( void )\r
+{\r
+ SetConsoleTextAttribute( hConOut, csbi.wAttributes );\r
+ CloseHandle( hConOut );\r
+}\r
+\r
+\r
+DWORD CtrlHandler( DWORD event )\r
+{\r
+ return (event == CTRL_C_EVENT || event == CTRL_BREAK_EVENT);\r
+}\r
+\r
+\r
+int main( void )\r
+{\r
+ STARTUPINFO si;\r
+ PROCESS_INFORMATION pi;\r
+ LPTSTR argv, arg, cmd;\r
+ TCHAR logstr[4];\r
+ BOOL installed;\r
+ BOOL shell, run, gui;\r
+ HMODULE ansi;\r
+ DWORD len;\r
+ int rc = 0;\r
+\r
+ argv = GetCommandLine();\r
+ len = (DWORD)wcslen( argv ) + 1;\r
+ if (len < MAX_PATH)\r
+ len = MAX_PATH;\r
+ arg = malloc( TSIZE(len) );\r
+ get_arg( arg, &argv, &cmd ); // skip the program name\r
+ get_arg( arg, &argv, &cmd );\r
+\r
+ if (*arg)\r
+ {\r
+ if (wcscmp( arg, L"/?" ) == 0 ||\r
+ wcscmp( arg, L"--help" ) == 0)\r
+ {\r
+ help();\r
+ return rc;\r
+ }\r
+ if (wcscmp( arg, L"--version" ) == 0)\r
+ {\r
+ _putws( L"ANSICON (" BITS L"-bit) version " PVERS L" (" PDATE L")." );\r
+ return rc;\r
+ }\r
+ }\r
+\r
+ prog = get_program_name( NULL );\r
+ *logstr = '\0';\r
+ GetEnvironmentVariable( L"ANSICON_LOG", logstr, lenof(logstr) );\r
+ log_level = _wtoi( logstr );\r
+\r
+ // Using "" for setlocale uses the system ANSI code page.\r
+ sprintf( (LPSTR)logstr, ".%u", GetConsoleOutputCP() );\r
+ setlocale( LC_CTYPE, (LPSTR)logstr );\r
+\r
+#ifdef _WIN64\r
+ if (*arg == '-' && arg[1] == 'P')\r
+ {\r
+ swscanf( arg + 2, L"%u:%u", &pi.dwProcessId, &pi.dwThreadId );\r
+ pi.hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pi.dwProcessId);\r
+ pi.hThread = OpenThread( THREAD_ALL_ACCESS, FALSE, pi.dwThreadId );\r
+ Inject( &pi, &gui, arg );\r
+ CloseHandle( pi.hThread );\r
+ CloseHandle( pi.hProcess );\r
+ return 0;\r
+ }\r
+#endif\r
+\r
+ if (log_level)\r
+ DEBUGSTR( 1, NULL ); // start a new session\r
+\r
+ installed = (GetEnvironmentVariable( L"ANSICON_VER", NULL, 0 ) != 0);\r
+ // If it's already installed, remove it. This serves two purposes: preserves\r
+ // the parent's GRM; and unconditionally injects into GUI, without having to\r
+ // worry about ANSICON_GUI.\r
+ if (installed)\r
+ {\r
+ if (_isatty( 1 ))\r
+ fputws( L"\33[m", stdout );\r
+ FreeLibrary( GetModuleHandle( ANSIDLL ) );\r
+ }\r
+\r
+ shell = run = TRUE;\r
+ get_original_attr();\r
+\r
+ while (*arg == '-')\r
+ {\r
+ switch (arg[1])\r
+ {\r
+ case 'l':\r
+ SetEnvironmentVariable( L"ANSICON_LOG", arg + 2 );\r
+ log_level = _wtoi( arg + 2 );\r
+ DEBUGSTR( 1, NULL ); // create a session\r
+ break;\r
+\r
+ case 'i':\r
+ case 'I':\r
+ case 'u':\r
+ case 'U':\r
+ shell = FALSE;\r
+ process_autorun( arg[1] );\r
+ if (arg[1] == 'u' || arg[1] == 'U')\r
+ break;\r
+ // else fall through\r
+\r
+ case 'p':\r
+ shell = FALSE;\r
+ // If it's already installed, there's no need to do anything.\r
+ if (installed)\r
+ {\r
+ DEBUGSTR( 1, L"Already installed" );\r
+ }\r
+ else if (GetParentProcessInfo( &pi, arg ))\r
+ {\r
+ pi.hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pi.dwProcessId);\r
+ pi.hThread = OpenThread( THREAD_ALL_ACCESS, FALSE, pi.dwThreadId );\r
+ SuspendThread( pi.hThread );\r
+#ifdef _WIN64\r
+ // Find the base address of kernel32.dll if the 64-bit version is\r
+ // injecting into a 32-bit parent.\r
+ if (IsWow64Process( pi.hProcess, &gui ) && gui)\r
+ {\r
+ HANDLE hSnap;\r
+ MODULEENTRY32 me;\r
+ BOOL fOk;\r
+\r
+ hSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE |\r
+ TH32CS_SNAPMODULE32,\r
+ pi.dwProcessId );\r
+ if (hSnap != INVALID_HANDLE_VALUE)\r
+ {\r
+ me.dwSize = sizeof(MODULEENTRY32);\r
+ for (fOk = Module32First( hSnap, &me ); fOk;\r
+ fOk = Module32Next( hSnap, &me ))\r
+ {\r
+ if (_wcsicmp( me.szModule, L"kernel32.dll" ) == 0)\r
+ {\r
+ base = me.modBaseAddr;\r
+ break;\r
+ }\r
+ }\r
+ CloseHandle( hSnap );\r
+ }\r
+ }\r
+#endif\r
+ if (!Inject( &pi, &gui, arg ))\r
+ rc = 1;\r
+ ResumeThread( pi.hThread );\r
+ CloseHandle( pi.hThread );\r
+ CloseHandle( pi.hProcess );\r
+ }\r
+ else\r
+ {\r
+ fputws( L"ANSICON: could not obtain the parent process.\n", stderr );\r
+ rc = 1;\r
+ }\r
+ break;\r
+\r
+ case 'm':\r
+ {\r
+ int a = wcstol( arg + 2, NULL, 16 );\r
+ if (a == 0)\r
+ a = (arg[2] == '-') ? -7 : 7;\r
+ if (a < 0)\r
+ {\r
+ SetEnvironmentVariable( L"ANSICON_REVERSE", L"1" );\r
+ a = -a;\r
+ a = ((a >> 4) & 15) | ((a & 15) << 4);\r
+ }\r
+ SetConsoleTextAttribute( hConOut, (WORD)a );\r
+ SetEnvironmentVariable( L"ANSICON_DEF", NULL );\r
+ break;\r
+ }\r
+\r
+ case 'e':\r
+ case 'E':\r
+ case 't':\r
+ case 'T':\r
+ run = FALSE;\r
+ ++arg;\r
+ goto arg_out;\r
+ }\r
+ get_arg( arg, &argv, &cmd );\r
+ }\r
+arg_out:\r
+ if (run && *cmd == '\0')\r
+ {\r
+ if (!shell)\r
+ run = FALSE;\r
+ else if (!_isatty( 0 ))\r
+ {\r
+ *arg = 't';\r
+ run = FALSE;\r
+ }\r
+ }\r
+\r
+ if (run)\r
+ {\r
+ if (*cmd == '\0')\r
+ {\r
+ if (GetEnvironmentVariable( L"ComSpec", arg, MAX_PATH ))\r
+ cmd = arg;\r
+ else\r
+ {\r
+ // CreateProcessW writes to the string, so can't simply point to "cmd".\r
+ static TCHAR cmdstr[] = L"cmd";\r
+ cmd = cmdstr;\r
+ }\r
+ }\r
+\r
+ ZeroMemory( &si, sizeof(si) );\r
+ si.cb = sizeof(si);\r
+ if (CreateProcess( NULL, cmd, NULL, NULL, TRUE, CREATE_SUSPENDED,\r
+ NULL, NULL, &si, &pi ))\r
+ {\r
+ Inject( &pi, &gui, arg );\r
+ ResumeThread( pi.hThread );\r
+ if (!gui)\r
+ {\r
+ SetConsoleCtrlHandler( (PHANDLER_ROUTINE)CtrlHandler, TRUE );\r
+ WaitForSingleObject( pi.hProcess, INFINITE );\r
+ GetExitCodeProcess( pi.hProcess, (LPDWORD)(LPVOID)&rc );\r
+ }\r
+ CloseHandle( pi.hProcess );\r
+ CloseHandle( pi.hThread );\r
+ }\r
+ else\r
+ {\r
+ print_error( arg, arg );\r
+ rc = 1;\r
+ }\r
+ }\r
+ else if (*arg)\r
+ {\r
+ ansi = LoadLibrary( ANSIDLL );\r
+ if (ansi == NULL)\r
+ {\r
+ print_error( ANSIDLL );\r
+ rc = 1;\r
+ }\r
+\r
+ if (*arg == 'e' || *arg == 'E')\r
+ {\r
+ cmd += 2;\r
+ if (*cmd == ' ' || *cmd == '\t')\r
+ ++cmd;\r
+ fputws( cmd, stdout );\r
+ if (*arg == 'e')\r
+ putwchar( '\n' );\r
+ }\r
+ else // (*arg == 't' || *arg == 'T')\r
+ {\r
+ BOOL title = (*arg == 'T');\r
+ get_file( arg, &argv, &cmd );\r
+ if (*arg == '\0')\r
+ wcscpy( arg, L"-" );\r
+ do\r
+ {\r
+ if (title)\r
+ {\r
+ wprintf( L"==> %s <==\n", arg );\r
+ display( arg, title );\r
+ putwchar( '\n' );\r
+ }\r
+ else\r
+ display( arg, title );\r
+ get_file( arg, &argv, &cmd );\r
+ } while (*arg);\r
+ }\r
+\r
+ FreeLibrary( ansi );\r
+ }\r
+\r
+ if (run || *arg)\r
+ set_original_attr();\r
+ else\r
+ CloseHandle( hConOut );\r
+\r
+ return rc;\r
+}\r
+\r
+\r
+// Display a file.\r
+void display( LPCTSTR name, BOOL title )\r
+{\r
+ HANDLE in, out;\r
+ BOOL pipe;\r
+ char buf[8192];\r
+ DWORD len;\r
+\r
+ if (*name == '-' && name[1] == '\0')\r
+ {\r
+ pipe = TRUE;\r
+ in = GetStdHandle( STD_INPUT_HANDLE );\r
+ }\r
+ else\r
+ {\r
+ pipe = FALSE;\r
+ in = CreateFile( name, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,\r
+ NULL, OPEN_EXISTING, 0, NULL );\r
+ if (in == INVALID_HANDLE_VALUE)\r
+ {\r
+ print_error( name );\r
+ return;\r
+ }\r
+ }\r
+ if (title)\r
+ {\r
+ putwchar( '\n' );\r
+ // Need to flush, otherwise it's written *after* STD_OUTPUT_HANDLE should\r
+ // it be redirected.\r
+ fflush( stdout );\r
+ }\r
+ out = GetStdHandle( STD_OUTPUT_HANDLE );\r
+ for (;;)\r
+ {\r
+ if (!ReadFile( in, buf, sizeof(buf), &len, NULL ))\r
+ {\r
+ if (GetLastError() != ERROR_BROKEN_PIPE)\r
+ print_error( name );\r
+ break;\r
+ }\r
+ if (len == 0)\r
+ break;\r
+ WriteFile( out, buf, len, &len, NULL );\r
+ }\r
+ if (!pipe)\r
+ CloseHandle( in );\r
+}\r
+\r
+\r
+void print_error( LPCTSTR name, ... )\r
+{\r
+ LPTSTR errmsg = NULL;\r
+ DWORD err = GetLastError();\r
+ va_list arg;\r
+\r
+ if (err == ERROR_BAD_EXE_FORMAT)\r
+ {\r
+ // This error requires an argument, which is a duplicate of name.\r
+ va_start( arg, name );\r
+ FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,\r
+ NULL, err, 0, (LPTSTR)(LPVOID)&errmsg, 0, &arg );\r
+ va_end( arg );\r
+ fwprintf( stderr, L"ANSICON: %s", errmsg );\r
+ }\r
+ else\r
+ {\r
+ FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,\r
+ NULL, err, 0, (LPTSTR)(LPVOID)&errmsg, 0, NULL );\r
+ // Just in case there are other messages requiring args...\r
+ if (errmsg == NULL)\r
+ fwprintf( stderr, L"ANSICON: %s: Error %lu.\n", name, err );\r
+ else\r
+ fwprintf( stderr, L"ANSICON: %s: %s", name, errmsg );\r
+ }\r
+ LocalFree( errmsg );\r
+}\r
+\r
+\r
+// Add or remove ANSICON to AutoRun.\r
+void process_autorun( TCHAR cmd )\r
+{\r
+ HKEY cmdkey;\r
+ TCHAR ansicon[MAX_PATH+80];\r
+ TCHAR logstr[80];\r
+ LPTSTR autorun, ansirun;\r
+ DWORD len, type, exist;\r
+ BOOL inst;\r
+\r
+ if (log_level)\r
+ _snwprintf( logstr, lenof(logstr), L"set ANSICON_LOG=%d&", log_level );\r
+ else\r
+ *logstr = '\0';\r
+ len = TSIZE(_snwprintf( ansicon, lenof(ansicon),\r
+ L"(if %%ANSICON_VER%%==^%%ANSICON_VER^%% %s\"%s\" -p)",\r
+ logstr, prog_path ) + 1);\r
+\r
+ inst = (towlower( cmd ) == 'i');\r
+ if (RegCreateKeyEx( (iswlower(cmd)) ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE,\r
+ CMDKEY, 0, NULL,\r
+ REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,\r
+ &cmdkey, &exist ) != ERROR_SUCCESS)\r
+ {\r
+ fputws( L"ANSICON: could not update AutoRun", stderr );\r
+ if (iswupper( cmd ))\r
+ fwprintf( stderr, L" (perhaps use -%c, or run as admin)", towlower(cmd) );\r
+ fputws( L".\n", stderr );\r
+ }\r
+ exist = 0;\r
+ RegQueryValueEx( cmdkey, AUTORUN, NULL, NULL, NULL, &exist );\r
+ if (exist == 0)\r
+ {\r
+ if (inst)\r
+ RegSetValueEx( cmdkey, AUTORUN, 0, REG_SZ, (PBYTE)ansicon, len );\r
+ }\r
+ else\r
+ {\r
+ // Let's assume there's sufficient memory.\r
+ autorun = malloc( exist + len );\r
+ RegQueryValueEx( cmdkey, AUTORUN, NULL, &type, (PBYTE)autorun, &exist );\r
+ // Remove the existing command, if present.\r
+ ansirun = wcsstr( autorun, L"(if %ANSICON_VER%" );\r
+ if (ansirun != NULL)\r
+ {\r
+ LPTSTR tmp = wcschr( ansirun, '"' ); // opening quote\r
+ tmp = wcschr( tmp + 1, '"' ); // closing quote\r
+ tmp = wcschr( tmp + 1, ')' ); // closing bracket\r
+ if (*++tmp == '&')\r
+ ++tmp;\r
+ if (*tmp == '&')\r
+ ++tmp;\r
+ if (*tmp == '\0')\r
+ {\r
+ if (ansirun > autorun && ansirun[-1] == '&')\r
+ --ansirun;\r
+ if (ansirun > autorun && ansirun[-1] == '&')\r
+ --ansirun;\r
+ }\r
+ wcscpy( ansirun, tmp );\r
+ exist = TSIZE((DWORD)wcslen( autorun ) + 1);\r
+ }\r
+ if (inst)\r
+ {\r
+ if (exist == sizeof(TCHAR))\r
+ RegSetValueEx( cmdkey, AUTORUN, 0, REG_SZ, (PBYTE)ansicon, len );\r
+ else\r
+ {\r
+ memmove( (PBYTE)autorun + len, autorun, exist );\r
+ memcpy( autorun, ansicon, len );\r
+ ((PBYTE)autorun)[len-sizeof(TCHAR)] = '&';\r
+ RegSetValueEx( cmdkey, AUTORUN, 0, type, (PBYTE)autorun, exist+len );\r
+ }\r
+ }\r
+ else\r
+ {\r
+ if (exist == sizeof(TCHAR))\r
+ RegDeleteValue( cmdkey, AUTORUN );\r
+ else\r
+ RegSetValueEx( cmdkey, AUTORUN, 0, type, (PBYTE)autorun, exist );\r
+ }\r
+ free( autorun );\r
+ }\r
+ RegCloseKey( cmdkey );\r
+}\r
+\r
+\r
+// Search each process in the snapshot for id.\r
+BOOL find_proc_id( HANDLE snap, DWORD id, LPPROCESSENTRY32 ppe )\r
+{\r
+ BOOL fOk;\r
+\r
+ ppe->dwSize = sizeof(PROCESSENTRY32);\r
+ for (fOk = Process32First( snap, ppe ); fOk; fOk = Process32Next( snap, ppe ))\r
+ if (ppe->th32ProcessID == id)\r
+ break;\r
+\r
+ return fOk;\r
+}\r
+\r
+\r
+// Obtain the process and thread identifiers of the parent process.\r
+BOOL GetParentProcessInfo( LPPROCESS_INFORMATION ppi, LPTSTR name )\r
+{\r
+ HANDLE hSnap;\r
+ PROCESSENTRY32 pe;\r
+ THREADENTRY32 te;\r
+ BOOL fOk;\r
+\r
+ hSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS|TH32CS_SNAPTHREAD, 0 );\r
+\r
+ if (hSnap == INVALID_HANDLE_VALUE)\r
+ return FALSE;\r
+\r
+ find_proc_id( hSnap, GetCurrentProcessId(), &pe );\r
+ if (!find_proc_id( hSnap, pe.th32ParentProcessID, &pe ))\r
+ {\r
+ CloseHandle( hSnap );\r
+ return FALSE;\r
+ }\r
+\r
+ te.dwSize = sizeof(te);\r
+ for (fOk = Thread32First( hSnap, &te ); fOk; fOk = Thread32Next( hSnap, &te ))\r
+ if (te.th32OwnerProcessID == pe.th32ProcessID)\r
+ break;\r
+\r
+ CloseHandle( hSnap );\r
+\r
+ ppi->dwProcessId = pe.th32ProcessID;\r
+ ppi->dwThreadId = te.th32ThreadID;\r
+ wcscpy( name, pe.szExeFile );\r
+\r
+ return fOk;\r
+}\r
+\r
+\r
+// Return the first non-space character from arg.\r
+LPTSTR skip_spaces( LPTSTR arg )\r
+{\r
+ while (*arg == ' ' || *arg == '\t')\r
+ ++arg;\r
+\r
+ return arg;\r
+}\r
+\r
+\r
+// Retrieve an argument from the command line. cmd gets the existing argv; argv\r
+// is ready for the next argument.\r
+void get_arg( LPTSTR arg, LPTSTR* argv, LPTSTR* cmd )\r
+{\r
+ LPTSTR line;\r
+\r
+ line = *cmd = skip_spaces( *argv );\r
+ while (*line != '\0')\r
+ {\r
+ if (*line == ' ' || *line == '\t')\r
+ {\r
+ ++line;\r
+ break;\r
+ }\r
+ if (*line == '"')\r
+ {\r
+ while (*++line != '\0')\r
+ {\r
+ if (*line == '"')\r
+ {\r
+ ++line;\r
+ break;\r
+ }\r
+ *arg++ = *line;\r
+ }\r
+ }\r
+ else\r
+ *arg++ = *line++;\r
+ }\r
+ *arg = '\0';\r
+ *argv = line;\r
+}\r
+\r
+\r
+int glob_sort( const void* a, const void* b )\r
+{\r
+ return lstrcmpi( *(LPCTSTR*)a, *(LPCTSTR*)b );\r
+}\r
+\r
+\r
+// As get_arg, but expand wildcards.\r
+void get_file( LPTSTR arg, LPTSTR* argv, LPTSTR* cmd )\r
+{\r
+ HANDLE fh, in;\r
+ WIN32_FIND_DATA fd;\r
+ LPTSTR path;\r
+ int size;\r
+ char buf[1024];\r
+ static LPTSTR name;\r
+ static LPTSTR* glob;\r
+ static int globbed;\r
+\r
+ if (globbed != 0)\r
+ {\r
+ if (glob[globbed] == NULL)\r
+ {\r
+ free( glob );\r
+ globbed = 0;\r
+ }\r
+ else\r
+ {\r
+ wcscpy( name, glob[globbed++] );\r
+ return;\r
+ }\r
+ }\r
+\r
+ get_arg( arg, argv, cmd );\r
+ if (wcspbrk( arg, L"*?" ) != NULL)\r
+ {\r
+ fh = FindFirstFile( arg, &fd );\r
+ if (fh != INVALID_HANDLE_VALUE)\r
+ {\r
+ size = 0;\r
+ do\r
+ {\r
+ if (! (fd.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY |\r
+ FILE_ATTRIBUTE_HIDDEN)))\r
+ {\r
+ ++globbed;\r
+ size += (int)wcslen( fd.cFileName ) + 1;\r
+ }\r
+ } while (FindNextFile( fh, &fd ));\r
+ FindClose( fh );\r
+\r
+ if (globbed != 0)\r
+ {\r
+ for (path = name = arg; *path != '\0'; ++path)\r
+ if (*path == '\\' || *path == '/')\r
+ name = path + 1;\r
+ glob = malloc( (globbed + 1) * sizeof(LPTSTR) + TSIZE(size) );\r
+ path = (LPTSTR)(glob + globbed + 1);\r
+ globbed = 0;\r
+ fh = FindFirstFile( arg, &fd );\r
+ do\r
+ {\r
+ if (! (fd.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY |\r
+ FILE_ATTRIBUTE_HIDDEN)))\r
+ {\r
+ // Ignore apparent binary files.\r
+ wcscpy( name, fd.cFileName );\r
+ in = CreateFile( arg, GENERIC_READ,\r
+ FILE_SHARE_READ|FILE_SHARE_WRITE,\r
+ NULL, OPEN_EXISTING, 0, NULL );\r
+ if (in != INVALID_HANDLE_VALUE)\r
+ {\r
+ ReadFile( in, buf, sizeof(buf), (LPVOID)&size, NULL );\r
+ CloseHandle( in );\r
+ if (memchr( buf, 0, size ) != NULL)\r
+ continue;\r
+ }\r
+ size = (int)wcslen( fd.cFileName ) + 1;\r
+ memcpy( path, fd.cFileName, TSIZE(size) );\r
+ glob[globbed++] = path;\r
+ path += size;\r
+ }\r
+ } while (FindNextFile( fh, &fd ));\r
+ FindClose( fh );\r
+ glob[globbed] = NULL;\r
+\r
+ qsort( glob, globbed, sizeof(LPTSTR), glob_sort );\r
+\r
+ wcscpy( name, glob[0] );\r
+ globbed = 1;\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+\r
+void help( void )\r
+{\r
+ _putws(\r
+L"ANSICON by Jason Hood <jadoxa@yahoo.com.au>.\n"\r
+L"Version " PVERS L" (" PDATE L"). Freeware.\n"\r
+L"http://ansicon.adoxa.vze.com/\n"\r
+L"\n"\r
+#ifdef _WIN64\r
+L"Process ANSI escape sequences in Windows console programs.\n"\r
+#else\r
+L"Process ANSI escape sequences in Win32 console programs.\n"\r
+#endif\r
+L"\n"\r
+L"ansicon [-l<level>] [-i] [-I] [-u] [-U] [-m[<attr>]] [-p]\n"\r
+L" [-e|E string | -t|T [file(s)] | program [args]]\n"\r
+L"\n"\r
+L" -l\t\tset the logging level (1=process, 2=module, 3=function,\n"\r
+L" \t\t +4=output, +8=append) for program (-p is unaffected)\n"\r
+L" -i\t\tinstall - add ANSICON to the AutoRun entry (also implies -p)\n"\r
+L" -u\t\tuninstall - remove ANSICON from the AutoRun entry\n"\r
+L" -I -U\t\tuse local machine instead of current user\n"\r
+L" -m\t\tuse grey on black (\"monochrome\") or <attr> as default color\n"\r
+L" -p\t\thook into the parent process\n"\r
+L" -e\t\techo string\n"\r
+L" -E\t\techo string, don't append newline\n"\r
+L" -t\t\tdisplay files (\"-\" for stdin), combined as a single stream\n"\r
+L" -T\t\tdisplay files, name first, blank line before and after\n"\r
+L" program\trun the specified program\n"\r
+L" nothing\trun a new command processor, or display stdin if redirected\n"\r
+L"\n"\r
+L"<attr> is one or two hexadecimal digits; please use \"COLOR /?\" for details.\n"\r
+L"It may start with '-' to reverse foreground and background (but not for -p)."\r
+ );\r
+}\r
-/*
- 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
+/*\r
+ ansicon.h - Header file for common definitions.\r
+\r
+ Jason Hood, 12 December, 2010 (originally injdll.h, 20 June, 2009).\r
+*/\r
+\r
+#ifndef ANSICON_H\r
+#define ANSICON_H\r
+\r
+#ifndef UNICODE\r
+# define UNICODE\r
+#endif\r
+\r
+#define WIN32_LEAN_AND_MEAN\r
+#ifdef _WIN64\r
+#define _WIN32_WINNT 0x0600 // MinGW-w64 wants this defined for Wow64 stuff\r
+#else\r
+#define _WIN32_WINNT 0x0500 // MinGW wants this defined for OpenThread\r
+#endif\r
+#include <windows.h>\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+\r
+#define lenof(array) (sizeof(array)/sizeof(*(array)))\r
+#define TSIZE(size) ((size) * sizeof(TCHAR))\r
+\r
+\r
+typedef struct\r
+{\r
+ BYTE foreground; // ANSI base color (0 to 7; add 30)\r
+ BYTE background; // ANSI base color (0 to 7; add 40)\r
+ BYTE bold; // console FOREGROUND_INTENSITY bit\r
+ BYTE underline; // console BACKGROUND_INTENSITY bit\r
+ BYTE rvideo; // swap foreground/bold & background/underline\r
+ BYTE concealed; // set foreground/bold to background/underline\r
+ BYTE reverse; // swap console foreground & background attributes\r
+} GRM, *PGRM; // Graphic Rendition Mode\r
+\r
+\r
+int ProcessType( LPPROCESS_INFORMATION, BOOL* );\r
+void InjectDLL32( LPPROCESS_INFORMATION, LPCTSTR );\r
+void InjectDLL64( LPPROCESS_INFORMATION, LPCTSTR );\r
+\r
+extern TCHAR prog_path[MAX_PATH];\r
+extern LPTSTR prog;\r
+LPTSTR get_program_name( LPTSTR );\r
+\r
+extern int log_level;\r
+void DEBUGSTR( int level, LPTSTR szFormat, ... );\r
+\r
+#endif\r
-/*
- 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
- }
-}
+/*\r
+ ansicon.rc - Version resource for ansicon.exe.\r
+\r
+ Jason Hood, 11 November, 2009.\r
+*/\r
+\r
+#include <winver.h>\r
+#include "version.h"\r
+\r
+VS_VERSION_INFO VERSIONINFO\r
+FILEVERSION PVERB\r
+PRODUCTVERSION PVERB\r
+FILEOS VOS_NT\r
+FILETYPE VFT_APP\r
+{\r
+ BLOCK "StringFileInfo"\r
+ {\r
+ BLOCK "040904B0"\r
+ {\r
+ VALUE "Comments", "http://ansicon.adoxa.vze.com/"\r
+ VALUE "CompanyName", "Jason Hood"\r
+ VALUE "FileDescription", "ANSI Console"\r
+ VALUE "FileVersion", PVERSA\r
+ VALUE "InternalName", "ansicon"\r
+ VALUE "LegalCopyright", "Freeware"\r
+ VALUE "OriginalFilename", "ansicon.exe"\r
+ VALUE "ProductName", "ANSICON"\r
+ VALUE "ProductVersion", PVERSA\r
+ }\r
+ }\r
+\r
+ BLOCK "VarFileInfo"\r
+ {\r
+ VALUE "Translation", 0x0409, 0x04B0\r
+ }\r
+}\r
+\r
+// Add a manifest for the 32-bit version, to prevent registry redirection when\r
+// trying to use HKLM.\r
+#ifndef _WIN64\r
+1 24\r
+{\r
+"<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?>\\r
+<assembly xmlns=""urn:schemas-microsoft-com:asm.v1"" manifestVersion=""1.0"">\\r
+<trustInfo xmlns=""urn:schemas-microsoft-com:asm.v3"">\\r
+ <security>\\r
+ <requestedPrivileges>\\r
+ <requestedExecutionLevel level=""asInvoker"" uiAccess=""false"" />\\r
+ </requestedPrivileges>\\r
+ </security>\\r
+</trustInfo>\\r
+</assembly>"\r
+}\r
+#endif\r
-/*
- 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 );
-}
+/*\r
+ Inject code into the target process to load our DLL. The target thread\r
+ should be suspended on entry; it remains suspended on exit.\r
+\r
+ Initially I used the "stack" method of injection. However, this fails\r
+ when DEP is active, since that doesn't allow code to execute in the stack.\r
+ To overcome this I used the "CreateRemoteThread" method. However, this\r
+ would fail with Wselect, a program to assist batch files. Wselect runs,\r
+ but it has no output. As it turns out, removing the suspended flag would\r
+ make Wselect work, but it caused problems with everything else. So now I\r
+ allocate a section of memory and change the context to run from there. At\r
+ first I had an event to signal when the library was loaded, then the memory\r
+ was released. However, that wouldn't work with -p and CMD.EXE (4NT v8\r
+ worked fine). Since it's possible the DLL might start a process suspended,\r
+ I've decided to simply keep the memory.\r
+*/\r
+\r
+#include "ansicon.h"\r
+\r
+#ifdef _WIN64\r
+#ifndef WOW64_CONTEXT_ALL\r
+#include "wow64.h"\r
+\r
+TWow64GetThreadContext Wow64GetThreadContext;\r
+TWow64SetThreadContext Wow64SetThreadContext;\r
+#define IMPORT_WOW64\r
+#endif\r
+\r
+#define CONTEXT WOW64_CONTEXT\r
+#undef CONTEXT_CONTROL\r
+#define CONTEXT_CONTROL WOW64_CONTEXT_CONTROL\r
+#define GetThreadContext Wow64GetThreadContext\r
+#define SetThreadContext Wow64SetThreadContext\r
+\r
+#define MakeVA( cast, offset ) (cast)((DWORD_PTR)pDosHeader + (DWORD)(offset))\r
+\r
+extern DWORD LLW32;\r
+LPVOID base;\r
+static PIMAGE_DOS_HEADER pDosHeader;\r
+\r
+int export_cmp( const void* a, const void* b )\r
+{\r
+ return strcmp( (LPCSTR)a, MakeVA( LPCSTR, *(const PDWORD)b ) );\r
+}\r
+\r
+\r
+/*\r
+ Get the relative address of the 32-bit LoadLibraryW function from 64-bit code.\r
+ This was originally done via executing a helper program (ANSI-LLW.exe), but I\r
+ never liked doing that, so now I do it the "hard" way - load the 32-bit\r
+ kernel32.dll directly and search the exports.\r
+*/\r
+BOOL get_LLW32( void )\r
+{\r
+ HMODULE kernel32;\r
+ TCHAR buf[MAX_PATH];\r
+ UINT len;\r
+ PIMAGE_NT_HEADERS32 pNTHeader;\r
+ PIMAGE_EXPORT_DIRECTORY pExportDir;\r
+ PDWORD fun_table, name_table;\r
+ PWORD ord_table;\r
+ PDWORD pLLW;\r
+\r
+ len = GetSystemWow64Directory( buf, MAX_PATH );\r
+ wcscpy( buf + len, L"\\kernel32.dll" );\r
+ // MinGW-w64 had a typo, calling it LINRARY.\r
+ kernel32 = LoadLibraryEx( buf, NULL, 0x20/*LOAD_LIBRARY_AS_IMAGE_RESOURCE*/ );\r
+ if (kernel32 == NULL)\r
+ {\r
+ DEBUGSTR( 1, L"Unable to load 32-bit kernel32.dll!" );\r
+ return FALSE;\r
+ }\r
+ // The handle uses low bits as flags, so strip 'em off.\r
+ pDosHeader = (PIMAGE_DOS_HEADER)((DWORD_PTR)kernel32 & ~0xFFFF);\r
+ pNTHeader = MakeVA( PIMAGE_NT_HEADERS32, pDosHeader->e_lfanew );\r
+ pExportDir = MakeVA( PIMAGE_EXPORT_DIRECTORY,\r
+ pNTHeader->OptionalHeader.\r
+ DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].\r
+ VirtualAddress );\r
+\r
+ fun_table = MakeVA( PDWORD, pExportDir->AddressOfFunctions );\r
+ name_table = MakeVA( PDWORD, pExportDir->AddressOfNames );\r
+ ord_table = MakeVA( PWORD, pExportDir->AddressOfNameOrdinals );\r
+\r
+ pLLW = bsearch( "LoadLibraryW", name_table, pExportDir->NumberOfNames,\r
+ sizeof(DWORD), export_cmp );\r
+ if (pLLW == NULL)\r
+ {\r
+ DEBUGSTR( 1, L"Could not find LoadLibraryW!" );\r
+ FreeLibrary( kernel32 );\r
+ return FALSE;\r
+ }\r
+ LLW32 = fun_table[ord_table[pLLW - name_table]];\r
+\r
+ FreeLibrary( kernel32 );\r
+ return TRUE;\r
+}\r
+#else\r
+DWORD LLW32;\r
+#endif\r
+\r
+\r
+void InjectDLL32( LPPROCESS_INFORMATION ppi, LPCTSTR dll )\r
+{\r
+ CONTEXT context;\r
+ DWORD ep;\r
+ DWORD len;\r
+ LPVOID mem;\r
+ DWORD mem32;\r
+ DWORD pr;\r
+ #define CODESIZE 20\r
+ BYTE code[CODESIZE+TSIZE(MAX_PATH)];\r
+ union\r
+ {\r
+ PBYTE pB;\r
+ PDWORD pL;\r
+ } ip;\r
+#ifdef _WIN64\r
+ BOOL entry = FALSE;\r
+#endif\r
+\r
+#ifdef IMPORT_WOW64\r
+ if (Wow64GetThreadContext == 0)\r
+ {\r
+ #define GETPROC( proc ) proc = (T##proc)GetProcAddress( hKernel, #proc )\r
+ HMODULE hKernel = GetModuleHandle( L"kernel32.dll" );\r
+ GETPROC( Wow64GetThreadContext );\r
+ GETPROC( Wow64SetThreadContext );\r
+ // Assume if one is defined, so is the other.\r
+ if (Wow64GetThreadContext == 0)\r
+ {\r
+ DEBUGSTR( 1, L"Failed to get pointer to Wow64GetThreadContext." );\r
+ return;\r
+ }\r
+ }\r
+#endif\r
+\r
+ len = TSIZE(lstrlen( dll ) + 1);\r
+ if (len > TSIZE(MAX_PATH))\r
+ return;\r
+\r
+ CopyMemory( code + CODESIZE, dll, len );\r
+ len += CODESIZE;\r
+\r
+ context.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;\r
+ GetThreadContext( ppi->hThread, &context );\r
+ mem = VirtualAllocEx( ppi->hProcess, NULL, len, MEM_COMMIT,\r
+ PAGE_READWRITE );\r
+ mem32 = (DWORD)(DWORD_PTR)mem;\r
+\r
+ ip.pB = code;\r
+\r
+ ep = context.Eip;\r
+ if (LLW32 == 0)\r
+ {\r
+#ifndef _WIN64\r
+ LLW32 = (DWORD)GetProcAddress( GetModuleHandle( L"kernel32.dll" ),\r
+ "LoadLibraryW" );\r
+#else\r
+ struct unicode_string\r
+ {\r
+ USHORT Length;\r
+ USHORT MaximumLength;\r
+ DWORD Buffer;\r
+ };\r
+ struct ldr_module // incomplete definition\r
+ {\r
+ DWORD next, prev;\r
+ DWORD baseAddress;\r
+ DWORD entryPoint;\r
+ DWORD sizeOfImage;\r
+ struct unicode_string fullDllName;\r
+ struct unicode_string baseDllName;\r
+ } ldr;\r
+ WCHAR basename[MAX_PATH];\r
+\r
+ if (!get_LLW32())\r
+ return;\r
+ // Determine the base address of the 32-bit kernel32.dll. If injecting\r
+ // into the parent process, base has already been determined. Otherwise,\r
+ // use the PEB to walk the loaded modules.\r
+ if (base == 0)\r
+ {\r
+ // When a process is created suspended, EAX has the entry point and EBX\r
+ // points to the PEB.\r
+ if (!ReadProcessMemory( ppi->hProcess, UIntToPtr( context.Ebx + 0x0C ),\r
+ ip.pL, 4, NULL ))\r
+ {\r
+ DEBUGSTR( 1, L"Failed to read Ldr from PEB." );\r
+ return;\r
+ }\r
+ // In case we're a bit slow (which seems to be unlikely), set up an\r
+ // infinite loop as the entry point.\r
+ WriteProcessMemory( ppi->hProcess, mem, "\xEB\xFE", 2, NULL );\r
+ FlushInstructionCache( ppi->hProcess, mem, 2 );\r
+ ep = context.Eax;\r
+ context.Eax = mem32;\r
+ SetThreadContext( ppi->hThread, &context );\r
+ VirtualProtectEx( ppi->hProcess, mem, len, PAGE_EXECUTE, &pr );\r
+ // Now resume the thread, as the PEB hasn't even been created yet.\r
+ ResumeThread( ppi->hThread );\r
+ while (*ip.pL == 0)\r
+ {\r
+ Sleep( 0 );\r
+ ReadProcessMemory( ppi->hProcess, UIntToPtr( context.Ebx + 0x0C ),\r
+ ip.pL, 4, NULL );\r
+ }\r
+ // Read PEB_LDR_DATA.InInitializationOrderModuleList.Flink.\r
+ ReadProcessMemory( ppi->hProcess, UIntToPtr( *ip.pL + 0x1c ),\r
+ &ip.pL[1], 4, NULL );\r
+ // Sometimes we're so quick ntdll.dll is the only one present, so keep\r
+ // looping until kernel32.dll shows up.\r
+ for (;;)\r
+ {\r
+ ldr.next = ip.pL[1];\r
+ do\r
+ {\r
+ ReadProcessMemory( ppi->hProcess, UIntToPtr( ldr.next ),\r
+ &ldr, sizeof(ldr), NULL );\r
+ ReadProcessMemory( ppi->hProcess, UIntToPtr( ldr.baseDllName.Buffer ),\r
+ basename, ldr.baseDllName.MaximumLength, NULL );\r
+ if (_wcsicmp( basename, L"kernel32.dll" ) == 0)\r
+ {\r
+ LLW32 += ldr.baseAddress;\r
+ goto gotit;\r
+ }\r
+ } while (ldr.next != *ip.pL + 0x1c);\r
+ }\r
+ gotit:\r
+ SuspendThread( ppi->hThread );\r
+ VirtualProtectEx( ppi->hProcess, mem, len, pr, &pr );\r
+ entry = TRUE;\r
+ }\r
+ else\r
+ LLW32 += PtrToUint( base );\r
+#endif\r
+ }\r
+\r
+ *ip.pB++ = 0x68; // push ep\r
+ *ip.pL++ = ep;\r
+ *ip.pB++ = 0x9c; // pushf\r
+ *ip.pB++ = 0x60; // pusha\r
+ *ip.pB++ = 0x68; // push L"path\to\ANSI32.dll"\r
+ *ip.pL++ = mem32 + CODESIZE;\r
+ *ip.pB++ = 0xe8; // call LoadLibraryW\r
+ *ip.pL++ = LLW32 - (mem32 + (DWORD)(ip.pB+4 - code));\r
+ *ip.pB++ = 0x61; // popa\r
+ *ip.pB++ = 0x9d; // popf\r
+ *ip.pB++ = 0xc3; // ret\r
+\r
+ WriteProcessMemory( ppi->hProcess, mem, code, len, NULL );\r
+ FlushInstructionCache( ppi->hProcess, mem, len );\r
+ VirtualProtectEx( ppi->hProcess, mem, len, PAGE_EXECUTE, &pr );\r
+#ifdef _WIN64\r
+ if (entry)\r
+ return;\r
+#endif\r
+ context.Eip = mem32;\r
+ SetThreadContext( ppi->hThread, &context );\r
+}\r
-/*
- 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 );
-}
+/*\r
+ Inject code into the target process to load our DLL. The target thread\r
+ should be suspended on entry; it remains suspended on exit.\r
+\r
+ Initially I used the "stack" method of injection. However, this fails\r
+ when DEP is active, since that doesn't allow code to execute in the stack.\r
+ To overcome this I used the "CreateRemoteThread" method. However, this\r
+ would fail with Wselect, a program to assist batch files. Wselect runs,\r
+ but it has no output. As it turns out, removing the suspended flag would\r
+ make Wselect work, but it caused problems with everything else. So now I\r
+ allocate a section of memory and change the context to run from there. At\r
+ first I had an event to signal when the library was loaded, then the memory\r
+ was released. However, that wouldn't work with -p and CMD.EXE (4NT v8\r
+ worked fine). Since it's possible the DLL might start a process suspended,\r
+ I've decided to simply keep the memory.\r
+*/\r
+\r
+#include "ansicon.h"\r
+\r
+void InjectDLL64( LPPROCESS_INFORMATION ppi, LPCTSTR dll )\r
+{\r
+ CONTEXT context;\r
+ DWORD len;\r
+ LPVOID mem;\r
+ DWORD64 LLW;\r
+ union\r
+ {\r
+ PBYTE pB;\r
+ PDWORD64 pL;\r
+ } ip;\r
+ #define CODESIZE 92\r
+ static BYTE code[CODESIZE+TSIZE(MAX_PATH)] = {\r
+ 0,0,0,0,0,0,0,0, // original rip\r
+ 0,0,0,0,0,0,0,0, // LoadLibraryW\r
+ 0x9C, // pushfq\r
+ 0x50, // push rax\r
+ 0x51, // push rcx\r
+ 0x52, // push rdx\r
+ 0x53, // push rbx\r
+ 0x55, // push rbp\r
+ 0x56, // push rsi\r
+ 0x57, // push rdi\r
+ 0x41,0x50, // push r8\r
+ 0x41,0x51, // push r9\r
+ 0x41,0x52, // push r10\r
+ 0x41,0x53, // push r11\r
+ 0x41,0x54, // push r12\r
+ 0x41,0x55, // push r13\r
+ 0x41,0x56, // push r14\r
+ 0x41,0x57, // push r15\r
+ 0x48,0x83,0xEC,0x28, // sub rsp, 40\r
+ 0x48,0x8D,0x0D,41,0,0,0, // lea ecx, L"path\to\ANSI64.dll"\r
+ 0xFF,0x15,-49,-1,-1,-1, // call LoadLibraryW\r
+ 0x48,0x83,0xC4,0x28, // add rsp, 40\r
+ 0x41,0x5F, // pop r15\r
+ 0x41,0x5E, // pop r14\r
+ 0x41,0x5D, // pop r13\r
+ 0x41,0x5C, // pop r12\r
+ 0x41,0x5B, // pop r11\r
+ 0x41,0x5A, // pop r10\r
+ 0x41,0x59, // pop r9\r
+ 0x41,0x58, // pop r8\r
+ 0x5F, // pop rdi\r
+ 0x5E, // pop rsi\r
+ 0x5D, // pop rbp\r
+ 0x5B, // pop rbx\r
+ 0x5A, // pop rdx\r
+ 0x59, // pop rcx\r
+ 0x58, // pop rax\r
+ 0x9D, // popfq\r
+ 0xFF,0x25,-91,-1,-1,-1, // jmp original Rip\r
+ 0, // dword alignment for LLW, fwiw\r
+ };\r
+\r
+ len = TSIZE(lstrlen( dll ) + 1);\r
+ if (len > TSIZE(MAX_PATH))\r
+ return;\r
+ CopyMemory( code + CODESIZE, dll, len );\r
+ len += CODESIZE;\r
+\r
+ context.ContextFlags = CONTEXT_CONTROL;\r
+ GetThreadContext( ppi->hThread, &context );\r
+ mem = VirtualAllocEx( ppi->hProcess, NULL, len, MEM_COMMIT,\r
+ PAGE_EXECUTE_READWRITE );\r
+ LLW = (DWORD64)LoadLibraryW;\r
+\r
+ ip.pB = code;\r
+\r
+ *ip.pL++ = context.Rip;\r
+ *ip.pL++ = LLW;\r
+\r
+ WriteProcessMemory( ppi->hProcess, mem, code, len, NULL );\r
+ FlushInstructionCache( ppi->hProcess, mem, len );\r
+ context.Rip = (DWORD64)mem + 16;\r
+ SetThreadContext( ppi->hThread, &context );\r
+}\r
+++ /dev/null
-# 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"
--- /dev/null
+# MinGW/MinGW-w64 makefile for ANSICON.\r
+# Jason Hood, 11 March, 2006. Updated 20 June, 2009.\r
+#\r
+# 19 November, 2010:\r
+# explicitly use 64-bit flags, in case the compiler isn't.\r
+#\r
+# 13 December, 2011:\r
+# use CMD for file operations, not programs from fileutils.\r
+#\r
+# 23 November, 2012:\r
+# set the base address of the DLLs to AC0000[00] (AnsiCon).\r
+#\r
+# 17 & 18 July, 2013:\r
+# work with 32-bit only, 64-bit only or multilib compilers;\r
+# hide the commands (use V=1 to show them).\r
+#\r
+# Tested with:\r
+# * MinGW/gcc 4.7.2;\r
+# * tdm-gcc-4.7.1-2;\r
+# * tdm64-gcc-4.7.1-3;\r
+# * MinGW-builds x64-4.8.1-release-posix-seh-rev1.\r
+\r
+CC = gcc\r
+CFLAGS = -O2 -Wall\r
+\r
+#ARCH = 32\r
+#ARCH = 64\r
+#ARCH = multi\r
+\r
+ifndef ARCH\r
+# Use the machine to distinguish between MinGW and MinGW-w64.\r
+ifeq (,$(findstring 64,$(shell gcc -dumpmachine)))\r
+ARCH = 32\r
+else\r
+# It's 64-bit, if it's multi the lib name will be different.\r
+ifeq ($(shell gcc -m32 -print-libgcc-file-name),$(shell gcc -m64 -print-libgcc-file-name))\r
+ARCH = 64\r
+else\r
+ARCH = multi\r
+endif\r
+endif\r
+endif\r
+\r
+X86OBJS = x86/proctype.o x86/injdll32.o x86/util.o\r
+X64OBJS = x64/proctype.o x64/injdll64.o x64/injdll32.o x64/util.o\r
+\r
+V ?= 0\r
+ifeq ($(V),0)\r
+CCmsg = @echo $<;\r
+RCmsg = $(CCmsg)\r
+LDmsg = @echo $@;\r
+endif\r
+\r
+x86/%.o: %.c ansicon.h\r
+ $(CCmsg)$(CC) -m32 -c $(CFLAGS) $< -o $@\r
+\r
+x86/%v.o: %.rc version.h\r
+ $(RCmsg)windres -U _WIN64 -F pe-i386 $< $@\r
+\r
+x64/%.o: %.c ansicon.h\r
+ $(CCmsg) $(CC) -m64 -c $(CFLAGS) $< -o $@\r
+\r
+x64/%v.o: %.rc version.h\r
+ $(RCmsg)windres -F pe-x86-64 $< $@\r
+\r
+x64/%32.o: %.c\r
+ $(CCmsg)$(CC) -m32 -DW32ON64 $(CFLAGS) $< -c -o $@\r
+\r
+\r
+ifeq ($(ARCH),multi)\r
+all: ansicon32 ansicon64\r
+else\r
+all: ansicon$(ARCH)\r
+endif\r
+\r
+ansicon32: x86 x86/ansicon.exe x86/ANSI32.dll x64 x64/ANSI32.dll\r
+\r
+ansicon64: x64 x64/ansicon.exe x64/ANSI64.dll\r
+\r
+x86:\r
+ cmd /c "mkdir x86"\r
+\r
+x86/ansicon.exe: x86/ansicon.o $(X86OBJS) x86/ansiconv.o\r
+ $(LDmsg)$(CC) -m32 $+ -s -o $@\r
+\r
+x86/ANSI32.dll: x86/ANSI.o $(X86OBJS) x86/ansiv.o\r
+ $(LDmsg)$(CC) -m32 $+ -s -o $@ -mdll -Wl,-shared,--image-base,0xAC0000\r
+\r
+x64:\r
+ cmd /c "mkdir x64"\r
+\r
+x64/ansicon.exe: x64/ansicon.o $(X64OBJS) x64/ansiconv.o\r
+ $(LDmsg)$(CC) -m64 $+ -s -o $@\r
+\r
+x64/ANSI64.dll: x64/ANSI.o $(X64OBJS) x64/ansiv.o\r
+ $(LDmsg)$(CC) -m64 $+ -s -o $@ -mdll -Wl,-shared,--image-base,0xAC000000\r
+\r
+x64/ANSI32.dll: x64/ANSI32.o x64/proctype32.o x86/injdll32.o x86/util.o x86/ansiv.o\r
+ $(LDmsg)$(CC) -m32 $+ -s -o $@ -mdll -Wl,-shared,--image-base,0xAC0000\r
+\r
+x86/ansicon.o: version.h\r
+x86/ANSI.o: version.h\r
+x86/util.o: version.h\r
+x64/ansicon.o: version.h\r
+x64/ANSI.o: version.h\r
+x64/util.o: version.h\r
+\r
+# Need two commands, because if the directory doesn't exist, it won't delete\r
+# anything at all.\r
+clean:\r
+ -cmd /c "del x86\*.o 2>nul"\r
+ -cmd /c "del x64\*.o 2>nul"\r
-# 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
+# VC makefile for ANSICON.\r
+# Jason Hood, 15 November, 2010.\r
+#\r
+# Tested with:\r
+# * Visual Studio 6.0 (VC6);\r
+# * Visual C++ 2003 Toolkit (VC7);\r
+# * Platform SDK for Windows Server 2003 R2 (VC8 64-bit);\r
+# * Visual Studio 2008 Express SP1 (VC9);\r
+# * Visual Studio 2010 Professional (VC10).\r
+#\r
+# Note that the 64-bit version still requires a 32-bit compiler.\r
+#\r
+# 22 & 23 November, 2012:\r
+# determine if the PSDK is used automatically;\r
+# use AC0000[00] (AnsiCon) as the base address;\r
+# twiddle stuff around to support VC6 (with 2003 PSDK) for the 32-bit version;\r
+# determine BITS automatically.\r
+#\r
+# 18 July, 2013:\r
+# hide the commands (use V=1 to show them).\r
+\r
+#BITS = 32\r
+#BITS = 64\r
+\r
+!IFNDEF BITS\r
+!IF "$(CPU)" == "AMD64" || "$(PLATFORM)" == "x64"\r
+BITS = 64\r
+!ELSE\r
+BITS = 32\r
+!ENDIF\r
+!ENDIF\r
+\r
+!IF $(BITS) == 32\r
+DIR = x86\r
+!ELSE\r
+!IF $(BITS) == 64\r
+DIR = x64\r
+RFLAGS = /D_WIN64\r
+!ELSE\r
+!ERROR BITS should be defined to 32 or 64.\r
+!ENDIF\r
+!ENDIF\r
+\r
+# This is required for the 2003 Platform SDK, but not for Visual Studio 2010.\r
+!IF "$(_NMAKE_VER)" == "7.00.8882"\r
+!IF $(BITS) == 64\r
+LIBS64 = bufferoverflowu.lib\r
+# The 2003 Toolkit doesn't have MSVCRT.LIB, but VC98 does.\r
+!ELSEIF !DEFINED(SHARE) && !DEFINED(MSVCDIR)\r
+SHARE =\r
+!ENDIF\r
+!ENDIF\r
+\r
+# Link with MSVCRT.LIB by default.\r
+!IFNDEF SHARE\r
+SHARE = /MD\r
+!ENDIF\r
+\r
+# Manifest tool to embed the manifest required by 2008.\r
+MT = mt.exe\r
+\r
+CFLAGS = /nologo /W3 /O2 $(SHARE) /D_CRT_SECURE_NO_WARNINGS\r
+LIBS = advapi32.lib user32.lib $(LIBS64)\r
+\r
+X86OBJS = x86\proctype.obj x86\injdll32.obj x86\util.obj\r
+X64OBJS = x64\proctype.obj x64\injdll64.obj x64\injdll32.obj x64\util.obj\r
+\r
+!IF !DEFINED(V)\r
+V = 0\r
+!ENDIF\r
+!IF $(V) == 0\r
+CCmsg = @\r
+RCmsg = @echo $<&\r
+LDmsg = @echo $@&\r
+MTmsg = @echo Embedding manifest&\r
+!ENDIF\r
+\r
+{}.c{$(DIR)}.obj:\r
+ $(CCmsg)$(CC) /c $(CFLAGS) /Fo$@ $<\r
+\r
+{}.rc{$(DIR)}.res:\r
+ $(RCmsg)$(RC) $(RFLAGS) /fo$@ $<\r
+\r
+all: ansicon$(BITS)\r
+\r
+ansicon32: x86 x86\ansicon.exe x86\ANSI32.dll x64 x64\ANSI32.dll\r
+\r
+ansicon64: x64 x64\ansicon.exe x64\ANSI64.dll\r
+\r
+x86:\r
+ mkdir x86\r
+\r
+x86\ansicon.exe: x86\ansicon.obj $(X86OBJS) x86\ansicon.res\r
+ $(LDmsg)$(CC) /nologo $(SHARE) /Fe$@ $** $(LIBS) /link /filealign:512\r
+!IF "$(_NMAKE_VER)" == "9.00.30729.01"\r
+ $(MTmsg)$(MT) /nologo -manifest $@.manifest -outputresource:$@;1\r
+ @del $@.manifest\r
+!ENDIF\r
+\r
+x86\ANSI32.dll: x86\ANSI.obj $(X86OBJS) x86\ansi.res\r
+ $(LDmsg)$(CC) /nologo $(SHARE) /LD /Fe$@ $** $(LIBS) /link /base:0xAC0000 /section:.shared,s /filealign:512\r
+!IF "$(_NMAKE_VER)" == "9.00.30729.01"\r
+ $(MTmsg)$(MT) /nologo -manifest $@.manifest -outputresource:$@;2\r
+ @del $@.manifest\r
+!ENDIF\r
+\r
+x64:\r
+ mkdir x64\r
+\r
+x64\ansicon.exe: x64\ansicon.obj $(X64OBJS) x64\ansicon.res\r
+ $(LDmsg)$(CC) /nologo $(SHARE) /Fe$@ $** $(LIBS)\r
+\r
+x64\ANSI64.dll: x64\ANSI.obj $(X64OBJS) x64\ansi.res\r
+ $(LDmsg)$(CC) /nologo $(SHARE) /LD /Fe$@ $** $(LIBS) /link /base:0xAC000000 /section:.shared,s\r
+\r
+x64\ANSI32.dll: x64\ANSI32.obj x64\proctype32.obj x86\injdll32.obj x86\util.obj x86\ansi.res\r
+ $(LDmsg)$(CC) /nologo $(SHARE) /LD /Fe$@ $** $(LIBS) /link /base:0xAC0000 /section:.shared,s /filealign:512\r
+!IF "$(_NMAKE_VER)" == "9.00.30729.01"\r
+ $(MTmsg)$(MT) /nologo -manifest $@.manifest -outputresource:$@;2\r
+ @del $@.manifest\r
+!ENDIF\r
+\r
+ansicon.c: ansicon.h version.h\r
+ansicon.rc: version.h\r
+ANSI.c: ansicon.h version.h\r
+ANSI.rc: version.h\r
+util.c: ansicon.h version.h\r
+injdll32.c: ansicon.h\r
+injdll64.c: ansicon.h\r
+proctype.c: ansicon.h\r
+\r
+x64\ANSI32.obj: ANSI.c\r
+ $(CCmsg)$(CC) /DW32ON64 /c $(CFLAGS) /Fo$@ $?\r
+x64\proctype32.obj: proctype.c\r
+ $(CCmsg)$(CC) /DW32ON64 /c $(CFLAGS) /Fo$@ $?\r
+\r
+clean:\r
+ -del $(DIR)\*.obj $(DIR)\*.res $(DIR)\*.lib $(DIR)\*.exp\r
+!IF $(BITS) == 32\r
+ -del x64\ansi32.obj x64\proctype32.obj\r
+!ENDIF\r
-/*
- 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;
-}
+/*\r
+ Test for a valid process. This may sometimes detect GUI, even for a console\r
+ process. I think this is due to a DLL being loaded in the address space\r
+ before the main image. Ideally I could just use the base address directly,\r
+ but that doesn't seem easy to do for another process - there doesn't seem to\r
+ be a GetModuleHandle for another process. The CreateRemoteThread trick won't\r
+ work with 64-bit (exit code is DWORD) and setting it up to make it work\r
+ hardly seems worth it. There's GetModuleInformation, but passing in NULL just\r
+ returns a base of NULL, so that's no help. Since 64/32 is sufficient, let\r
+ ansicon.exe handle the difference between console/GUI.\r
+\r
+ Update: ignore images characterised as DLL.\r
+*/\r
+\r
+#include "ansicon.h"\r
+\r
+\r
+int ProcessType( LPPROCESS_INFORMATION pinfo, BOOL* gui )\r
+{\r
+ char* ptr;\r
+ MEMORY_BASIC_INFORMATION minfo;\r
+ IMAGE_DOS_HEADER dos_header;\r
+ IMAGE_NT_HEADERS nt_header;\r
+ SIZE_T read;\r
+\r
+ *gui = FALSE;\r
+ for (ptr = NULL;\r
+ VirtualQueryEx( pinfo->hProcess, ptr, &minfo, sizeof(minfo) );\r
+ ptr += minfo.RegionSize)\r
+ {\r
+ if (minfo.BaseAddress == minfo.AllocationBase &&\r
+ ReadProcessMemory( pinfo->hProcess, minfo.AllocationBase,\r
+ &dos_header, sizeof(dos_header), &read ))\r
+ {\r
+ if (dos_header.e_magic == IMAGE_DOS_SIGNATURE)\r
+ {\r
+ if (ReadProcessMemory( pinfo->hProcess, (char*)minfo.AllocationBase +\r
+ dos_header.e_lfanew, &nt_header,\r
+ sizeof(nt_header), &read ))\r
+ {\r
+ if (nt_header.Signature == IMAGE_NT_SIGNATURE &&\r
+ (nt_header.FileHeader.Characteristics &\r
+ (IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DLL))\r
+ == IMAGE_FILE_EXECUTABLE_IMAGE)\r
+ {\r
+ *gui = (nt_header.OptionalHeader.Subsystem\r
+ == IMAGE_SUBSYSTEM_WINDOWS_GUI);\r
+ if (nt_header.OptionalHeader.Subsystem ==\r
+ IMAGE_SUBSYSTEM_WINDOWS_CUI || *gui)\r
+ {\r
+ if (nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_I386)\r
+ {\r
+ // Microsoft ignores precision on %p.\r
+ DEBUGSTR( 1, L" 32-bit %s (base = %.8X)",\r
+ (*gui) ? L"GUI" : L"console",\r
+ (DWORD)(DWORD_PTR)minfo.AllocationBase );\r
+ return 32;\r
+ }\r
+#ifdef _WIN64\r
+ if (nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64)\r
+ {\r
+ DEBUGSTR( 1, L" 64-bit %s (base = %p)",\r
+ (*gui) ? L"GUI" : L"console", minfo.AllocationBase );\r
+ return 64;\r
+ }\r
+#elif defined(W32ON64)\r
+ if (nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64)\r
+ {\r
+ DEBUGSTR( 1, L" 64-bit %s",\r
+ (*gui) ? L"GUI" : L"console" );\r
+ return 64;\r
+ }\r
+#endif\r
+ DEBUGSTR( 1, L" Ignoring unsupported machine (0x%X)",\r
+ nt_header.FileHeader.Machine );\r
+ }\r
+ else\r
+ {\r
+ DEBUGSTR( 1, L" Ignoring unsupported subsystem (%u)",\r
+ nt_header.OptionalHeader.Subsystem );\r
+ }\r
+ return 0;\r
+ }\r
+ }\r
+ }\r
+ }\r
+#ifndef _WIN64\r
+ // If a 32-bit process loads a 64-bit one, we may miss the base\r
+ // address. If the pointer overflows, assume 64-bit.\r
+ if (((DWORD)ptr >> 12) + ((DWORD)minfo.RegionSize >> 12) > 0x80000)\r
+ {\r
+#ifdef W32ON64\r
+ DEBUGSTR( 1, L" Pointer overflow: assuming 64-bit console" );\r
+ return 64;\r
+#else\r
+ DEBUGSTR( 1, L" Ignoring apparent 64-bit process" );\r
+ return 0;\r
+#endif\r
+ }\r
+#endif\r
+ }\r
+\r
+ DEBUGSTR( 1, L" Ignoring non-Windows process" );\r
+ return 0;\r
+}\r
-
- 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.
+\r
+ ANSICON\r
+\r
+ Copyright 2005-2013 Jason Hood\r
+\r
+ Version 1.66. Freeware\r
+\r
+\r
+Description\r
+===========\r
+\r
+ ANSICON provides ANSI escape sequences for Windows console programs. It\r
+ provides much the same functionality as 'ANSI.SYS' does for MS-DOS.\r
+\r
+\r
+Requirements\r
+============\r
+\r
+ 32-bit: Windows 2000 Professional and later (it won't work with NT or 9X).\r
+ 64-bit: Vista and later (it won't work with XP64).\r
+\r
+\r
+Installation\r
+============\r
+\r
+ Add "x86" (if your OS is 32-bit) or "x64" (if 64-bit) to your PATH, or copy\r
+ the relevant files to a directory already on the PATH. Alternatively, use\r
+ option '-i' (or '-I', if permitted) to install it permanently, by adding an\r
+ entry to CMD.EXE's AutoRun registry value (current user or local machine,\r
+ respectively).\r
+\r
+ Uninstall simply involves closing any programs that are currently using it;\r
+ running with '-u' (and/or '-U') to remove it from AutoRun; removing the\r
+ directory from PATH; and deleting the files. No other changes are made\r
+ (although you may have also created environment variables).\r
+\r
+Upgrading\r
+---------\r
+\r
+ Delete ANSI.dll, it has been replaced with ANSI32.dll.\r
+ Delete ANSI-LLA.exe and ANSI-LLW.exe, they are no longer used.\r
+ Uninstall a pre-1.50 version and reinstall with this version.\r
+\r
+\r
+Usage\r
+=====\r
+\r
+ Options (case sensitive):\r
+\r
+ -l Log to "%TEMP%\ansicon.log".\r
+\r
+ -p Enable the parent process (i.e. the command shell used to run\r
+ ANSICON) to recognise escapes.\r
+\r
+ -m Set the current (and default) attribute to grey on black\r
+ ("monochrome"), or the attribute following the 'm' (please\r
+ use 'COLOR /?' for attribute values).\r
+\r
+ -e Echo the command line - a space or tab after the 'e' is\r
+ ignored, the remainder is displayed verbatim.\r
+\r
+ -E As above, but no newline is added.\r
+\r
+ -t Display ("type") each file (or standard input if none or the\r
+ name is "-") as though they are a single file.\r
+\r
+ -T Display "==> FILE NAME <==", a blank line (or an error\r
+ message), the file and another blank line.\r
+\r
+ Running ANSICON with no arguments will start a new instance of the command\r
+ processor (the program defined by the 'ComSpec' environment variable, typ-\r
+ ically 'CMD.EXE'), or display standard input if it is redirected. Any arg-\r
+ ument will be treated as a program and its arguments.\r
+ \r
+ E.g.: 'ansicon -m30 -t file.ans' will display "file.ans" using black on\r
+ cyan as the default color.\r
+\r
+ The attribute may start with '-' to permanently reverse the foreground and\r
+ background colors (but not when using '-p'). E.g.: 'ansicon -m-f0 -t\r
+ file.log' will use reversed black on white as the default (i.e. white on\r
+ black, with foreground sequences changing the background).\r
+\r
+ If you experience trouble with certain programs, the log may help in find-\r
+ ing the cause; it can be found at "%TEMP%\ansicon.log". A number should\r
+ follow the 'l':\r
+\r
+ 0 No logging\r
+ 1 Log process start and end\r
+ 2 Above, plus log modules used by the process\r
+ 3 Above, plus log functions that are hooked\r
+ 4 Log console output (add to any of the above)\r
+ 8 Append to the existing file (add to any of the above)\r
+ 16 Log all imported modules (add to any of the above)\r
+\r
+ The log option will not work with '-p'; set the environment variable\r
+ ANSICON_LOG instead. The variable is only read once when a new process is\r
+ started; changing it won't affect running processes. If you identify a\r
+ module that causes problems, add it to the ANSICON_EXC environment variable\r
+ (see ANSICON_API below, but the extension is required).\r
+\r
+ E.g.: 'ansicon -l5' will start a new command processor, logging every pro-\r
+ cess it starts along with their output.\r
+\r
+ Once installed, the ANSICON environment variable will be created. This\r
+ variable is of the form "WxH (wxh)", where 'W' & 'H' are the width and\r
+ height of the buffer and 'w' & 'h' are the width and height of the window.\r
+ The variable is updated whenever a program reads it directly (i.e. as an\r
+ individual request, not as part of the entire environment block). For\r
+ example, 'set an' will not update it, but 'echo %ansicon%' will. Also\r
+ created is ANSICON_VER, which contains the version without the point (1.50\r
+ becomes "150"). This variable does not exist as part of the environment\r
+ block ('set an' will not show it).\r
+\r
+ If installed, GUI programs will not be hooked. Either start the program\r
+ directly with 'ansicon', or add it to the ANSICON_GUI variable (see\r
+ ANSICON_API below).\r
+\r
+ Using 'ansicon' after install will always start with the default attrib-\r
+ utes, restoring the originals on exit; all other programs will use the cur-\r
+ rent attributes. The shift state is always reset for a new process.\r
+\r
+ The Windows API WriteFile and WriteConsoleA functions will set the number\r
+ of characters written, not the number of bytes. When using a multibyte\r
+ character set, this results in a smaller number (since multiple bytes are\r
+ used to represent a single character). Some programs recognise this as a\r
+ reduced write and will inadvertently repeat previous characters. If you\r
+ discover such a program, use the ANSICON_API environment variable to record\r
+ it and override the API, returning the original byte count. Ruby (prior to\r
+ 1.9.3) is an example of such a program, so use 'set ANSICON_API=ruby' to\r
+ avoid the repitition. The full syntax is:\r
+\r
+ ANSICON_API=[!]program;program;program...\r
+\r
+ PROGRAM is the name of the program, with no path and extension. The lead-\r
+ ing exclamation inverts the usage, meaning the API will always be over-\r
+ ridden, unless the program is in the list. The variable can be made perm-\r
+ anent by going to System Properties, selecting the Advanced tab (with Vista\r
+ onwards, this can be done by running "SystemPropertiesAdvanced") and click-\r
+ ing Environment Variables.\r
+\r
+\r
+Sequences Recognised\r
+====================\r
+\r
+ The following escape sequences are recognised.\r
+\r
+ \e]0;titleBEL Set (xterm) window's title (and icon)\r
+ \e[21t Report (xterm) window's title\r
+ \e[s Save Cursor\r
+ \e[u Restore Cursor\r
+ \e[#G CHA Cursor Character Absolute\r
+ \e[#E CNL Cursor Next Line\r
+ \e[#F CPL Cursor Preceding Line\r
+ \e[#D CUB Cursor Left\r
+ \e[#B CUD Cursor Down\r
+ \e[#C CUF Cursor Right\r
+ \e[#;#H CUP Cursor Position\r
+ \e[#A CUU Cursor Up\r
+ \e[#P DCH Delete Character\r
+ \e[?25h DECTCEM DEC Text Cursor Enable Mode (show cursor)\r
+ \e[?25l DECTCEM DEC Text Cursor Enable Mode (hide cursor)\r
+ \e[#M DL Delete Line\r
+ \e[#n DSR Device Status Report\r
+ \e[#X ECH Erase Character\r
+ \e[#J ED Erase In Page\r
+ \e[#K EL Erase In Line\r
+ \e[#` HPA Character Position Absolute\r
+ \e[#j HPB Character Position Backward\r
+ \e[#a HPR Character Position Forward\r
+ \e[#;#f HVP Character And Line Position\r
+ \e[#@ ICH Insert Character\r
+ \e[#L IL Insert Line\r
+ SI LS0 Locking-shift Zero (see below)\r
+ SO LS1 Locking-shift One\r
+ \e[#;#;#m SGR Select Graphic Rendition\r
+ \e[#d VPA Line Position Absolute\r
+ \e[#k VPB Line Position Backward\r
+ \e[#e VPR Line Position Forward\r
+\r
+ '\e' represents the escape character (ASCII 27); '#' represents a decimal\r
+ number (optional, in most cases defaulting to 1); BEL, SO and SI are ASCII\r
+ 7, 14 and 15. Regarding SGR: bold will set the foreground intensity; blink\r
+ and underline will set the background intensity; conceal uses background as\r
+ foreground. See "sequences.txt" for a more complete description.\r
+\r
+ I make a distinction between '\e[m' and '\e[0;...m'. Both will restore the\r
+ original foreground/background colors (and so '0' should be the first para-\r
+ meter); the former will also restore the original bold and underline attri-\r
+ butes, whilst the latter will explicitly reset them. The environment var-\r
+ iable ANSICON_DEF can be used to change the default colors (same value as\r
+ '-m'; setting the variable does not change the current colors).\r
+\r
+\r
+Sequences Ignored\r
+=================\r
+\r
+ The following escape sequences are explicitly ignored.\r
+\r
+ \e(? Designate G0 character set ('?' is any character).\r
+ \e)? Designate G1 character set ('?' is any character).\r
+ \e[?... Private sequence\r
+ \e[>... Private sequence\r
+\r
+ The G0 character set is always ASCII; the G1 character set is always the\r
+ DEC Special Graphics Character Set.\r
+\r
+\r
+DEC Special Graphics Character Set\r
+==================================\r
+\r
+ This is my interpretation of the set, as shown by\r
+ http://vt100.net/docs/vt220-rm/table2-4.html.\r
+\r
+\r
+ Char Unicode Code Point & Name\r
+ ---- -------------------------\r
+ _ U+0020 Space (blank)\r
+ ` U+2666 Black Diamond Suit\r
+ a U+2592 Medium Shade\r
+ b U+2409 Symbol For Horizontal Tabulation\r
+ c U+240C Symbol For Form Feed\r
+ d U+240D Symbol For Carriage Return\r
+ e U+240A Symbol For Line Feed\r
+ f U+00B0 Degree Sign\r
+ g U+00B1 Plus-Minus Sign\r
+ h U+2424 Symbol For Newline\r
+ i U+240B Symbol For Vertical Tabulation\r
+ j U+2518 Box Drawings Light Up And Left\r
+ k U+2510 Box Drawings Light Down And Left\r
+ l U+250C Box Drawings Light Down And Right\r
+ m U+2514 Box Drawings Light Up And Right\r
+ n U+253C Box Drawings Light Vertical And Horizontal\r
+ o U+00AF Macron (SCAN 1)\r
+ p U+25AC Black Rectangle (SCAN 3)\r
+ q U+2500 Box Drawings Light Horizontal (SCAN 5)\r
+ r U+005F Low Line (SCAN 7)\r
+ s U+005F Low Line (SCAN 9)\r
+ t U+251C Box Drawings Light Vertical And Right\r
+ u U+2524 Box Drawings Light Vertical And Left\r
+ v U+2534 Box Drawings Light Up And Horizontal\r
+ w U+252C Box Drawings Light Down And Horizontal\r
+ x U+2502 Box Drawings Light Vertical\r
+ y U+2264 Less-Than Or Equal To\r
+ z U+2265 Greater-Than Or Equal To\r
+ { U+03C0 Greek Small Letter Pi\r
+ | U+2260 Not Equal To\r
+ } U+00A3 Pound Sign\r
+ ~ U+00B7 Middle Dot\r
+\r
+ G1.txt is a Unicode file to view the glyphs "externally". G1.bat is a\r
+ batch file (using 'x86\ansicon') to show the glyphs in the console. The\r
+ characters will appear as they should using Lucida (other than the Sym-\r
+ bols), but code page will influence them when using a raster font (but of\r
+ particular interest, 437 and 850 both show the Box Drawings).\r
+\r
+\r
+Limitations\r
+===========\r
+\r
+ The entire console buffer is used, not just the visible window.\r
+\r
+ There's a conflict with NVIDIA's drivers, requiring the setting of the\r
+ Environment Variable:\r
+\r
+ ANSICON_EXC=nvd3d9wrap.dll;nvd3d9wrapx.dll\r
+\r
+\r
+Version History\r
+===============\r
+\r
+ Legend: + added, - bug-fixed, * changed.\r
+\r
+ 1.66 - 20 September, 2013:\r
+ - fix 32-bit process trying to detect 64-bit process.\r
+\r
+ 1.65 - 4 September, 2013:\r
+ - fix finding 32-bit LoadLibraryW address from 64-bit;\r
+ - fix \e[K (was using window, not buffer).\r
+\r
+ 1.64 - 2 August, 2013:\r
+ - improved detection of console output.\r
+\r
+ 1.63 - 25 July, 2013:\r
+ - don't write the reset sequence (when it's already installed) if output is\r
+ redirected.\r
+\r
+ 1.62 - 18 July, 2013:\r
+ - indicate if opening HKLM failed;\r
+ * removed ANSI-LLW.exe again, properly this time;\r
+ * add the architecture (32- or 64-bit) to the log.\r
+\r
+ 1.61 - 14 February, 2013:\r
+ * revert back to using ANSI-LLW.exe, as the new method was unreliable.\r
+\r
+ 1.60 - 24 November, 2012:\r
+ * new method to get the 32-bit LoadLibraryW address from 64-bit code.\r
+ This removes the need for ANSI-LLW.exe, which caused lots of virus\r
+ warnings, for some reason.\r
+ - set the code page to display some file names properly;\r
+ + expand wildcards for -t (ignoring directories and hidden/binary files).\r
+\r
+ 1.53 - 12 June, 2012:\r
+ - fix for multiple simultaneous process creation (e.g. "cl /MP ...").\r
+\r
+ 1.52 - 2 June, 2012:\r
+ + 32-bit processes can inject into 64-bit processes;\r
+ + implemented \e[39m & \e[49m (set default foreground/background color);\r
+ + added \e[#X, \e[#`, \e[#a, \e[#d, \e[#e, \[e#j and \e[#k;\r
+ * changed sequence descriptions to those in ECMA-48, ordered by acronym.\r
+\r
+ 1.51 - 24 February, 2012:\r
+ - fixed installing into a piped/redirected CMD.EXE;\r
+ - fixed 32-bit process trying to identify a 64-bit process;\r
+ - ignore version within core API DLL names (now Win8 works);\r
+ + hook _lwrite & _hwrite (now Silverfrost FTN95 v6.20 works).\r
+\r
+ 1.50 - 14 December, 2011:\r
+ - -u does not imply -p;\r
+ - return the program's exit code;\r
+ - -p by itself will not restore original color;\r
+ - output error messages to stderr;\r
+ * logging is always available, with various levels; include the pid;\r
+ * don't automatically hook GUI programs, use 'ansicon' or ANSICON_GUI;\r
+ * always place first in AutoRun; don't run if already installed;\r
+ + global reverse video capability;\r
+ + added ANSICON_VER to provide version/install test;\r
+ + added ANSICON_EXC to exclude selected modules;\r
+ + added ANSICON_DEF to explicitly set the default SGM.\r
+\r
+ 1.40 - 1 March, 2011:\r
+ - hook GetProcAddress (now PowerShell works);\r
+ + add SO/SI, using the DEC Special Graphics Character Set for G1;\r
+ + add DECTCEM to show/hide the cursor.\r
+\r
+ 1.32 - 22 December, 2010:\r
+ - fixed crash due to NULL lpNumberOfBytesWritten/lpNumberOfCharsWritten;\r
+ - -p will test the parent process for validity;\r
+ * hook into GUI processes;\r
+ + recognise DSR and xterm window title sequences;\r
+ - fixed MinGW32 binaries (LLW was wrong).\r
+\r
+ 1.31 - 19 November, 2010:\r
+ - fixed multibyte support (no extra junk with UTF-8 files);\r
+ * provide workaround for API byte/character differences;\r
+ * fixed potential problem if install path uses Unicode.\r
+\r
+ 1.30 - 7 September, 2010:\r
+ + x64 version.\r
+\r
+ 1.25 - 22 July, 2010:\r
+ - hook LoadLibraryEx (now CScript works);\r
+ - fixed -i when AutoRun existed, but was empty;\r
+ + support for Windows 7;\r
+ + -I (and -U) use HKEY_LOCAL_MACHINE.\r
+\r
+ 1.24 - 7 January, 2010:\r
+ - fix -t and -e when ANSICON was already running;\r
+ + read standard input if redirected with no arguments, if -t has no\r
+ files, or if the name is "-" (which also serves as a workaround for\r
+ programs that don't get hooked, such as CScript).\r
+\r
+ 1.23 - 11 November, 2009:\r
+ - restore hooked functions when unloading;\r
+ - reverse the "bold" and "underline" settings;\r
+ * conceal characters by making foreground color same as background.\r
+\r
+ 1.22 - 5 October, 2009:\r
+ - hook LoadLibrary to inject into applications started via association.\r
+\r
+ 1.21 - 23 September, 2009:\r
+ + -i (and -u) option to add (remove) entry to AutoRun value.\r
+\r
+ 1.20 - 21 June, 2009:\r
+ * use another injection method;\r
+ + create ANSICON environment variable;\r
+ + -e (and -E) option to echo the command line (without newline);\r
+ + -t (and -T) option to type (display) files (with file name).\r
+\r
+ 1.15 - 17 May, 2009:\r
+ - fix output corruption for long (over 8192 characters) ANSI strings.\r
+\r
+ 1.14 - 3 April, 2009:\r
+ - fix the test for an empty import section (eg. XCOPY now works).\r
+\r
+ 1.13 - 21 & 27 March, 2009:\r
+ * use a new injection method (to work with DEP);\r
+ * use Unicode.\r
+\r
+ 1.12 - 9 March, 2009:\r
+ - fix processing child programs (generate a relocatable DLL).\r
+\r
+ 1.11 - 28 February, 2009:\r
+ - fix processing child programs (only use for console executables).\r
+\r
+ 1.10 - 22 February, 2009:\r
+ - fix output corruption (buffer overflow in MyConsoleWriteW);\r
+ - recognise current screen attributes as current ANSI atrributes;\r
+ - ignore Ctrl+C and Ctrl+Break;\r
+ + process child programs.\r
+\r
+ 1.01 - 12 March, 2006:\r
+ * \e[m will restore original color, not set grey on black;\r
+ + -m option to set default (and initial) color;\r
+ - restore original color on exit;\r
+ - disable escape processing when console has disabled processed output;\r
+ + \e[5m (blink) is the same as \e[4m (underline);\r
+ - do not conceal control characters (0 to 31).\r
+\r
+ 1.00 - 23 October, 2005:\r
+ + initial release.\r
+\r
+\r
+Acknowledgments\r
+===============\r
+\r
+ Jean-Louis Morel, for his Perl package Win32::Console::ANSI. It provided\r
+ the basis of 'ANSI.dll'.\r
+\r
+ Sergey Oblomov (hoopoepg), for Console Manager. It provided the basis of\r
+ 'ansicon.exe'.\r
+\r
+ Anton Bassov's article "Process-wide API spying - an ultimate hack" in "The\r
+ Code Project".\r
+\r
+ Richard Quadling - his persistence in finding bugs has made ANSICON what it\r
+ is today.\r
+\r
+ Dmitry Menshikov, Marko Bozikovic and Philippe Villiers, for their assis-\r
+ tance in making the 64-bit version a reality.\r
+\r
+ Luis Lavena and the Ruby people for additional improvements.\r
+\r
+ Leigh Hebblethwaite for documentation tweaks.\r
+\r
+ Vincent Fatica for pointing out \e[K was not right.\r
+\r
+\r
+Contact\r
+=======\r
+\r
+ mailto:jadoxa@yahoo.com.au\r
+ http://ansicon.adoxa.vze.com/\r
+ https://github.com/adoxa/ansicon\r
+\r
+ Jason Hood\r
+ 11 Buckle Street\r
+ North Rockhampton\r
+ Qld 4701\r
+ Australia\r
+\r
+\r
+Distribution\r
+============\r
+\r
+ The original zipfile can be freely distributed, by any means. However, I\r
+ would like to be informed if it is placed on a CD-ROM (other than an arch-\r
+ ive compilation; permission is granted, I'd just like to know). Modified\r
+ versions may be distributed, provided it is indicated as such in the ver-\r
+ sion text and a source diff is made available. In particular, the supplied\r
+ binaries are freely redistributable. A formal license (zlib) is available\r
+ in LICENSE.txt.\r
+\r
+\r
+===============================\r
+Jason Hood, 20 September, 2013.\r
--- /dev/null
+\r
+ ANSICON\r
+ Version 1.60\r
+\r
+This is a complete list of the ANSI escape sequences recognised by ANSICON,\r
+roughly ordered by function. The initial escape character is assumed.\r
+\r
+\r
+[m restore default color (and intensity)\r
+[0m as above\r
+[...m set attributes (any of these numbers, separated by semicolons):\r
+ 0 all attributes off\r
+ 1 bold (foreground is intense)\r
+ 4 underline (background is intense)\r
+ 5 blink (background is intense)\r
+ 7 reverse video\r
+ 8 concealed (foreground becomes background)\r
+ 22 bold off (foreground is not intense)\r
+ 24 underline off (background is not intense)\r
+ 25 blink off (background is not intense)\r
+ 27 normal video\r
+ 28 concealed off\r
+ 30 foreground black\r
+ 31 foreground red\r
+ 32 foreground green\r
+ 33 foreground yellow\r
+ 34 foreground blue\r
+ 35 foreground magenta\r
+ 36 foreground cyan\r
+ 37 foreground white\r
+ 39 default foreground (using current intensity)\r
+ 40 background black\r
+ 41 background red\r
+ 42 background green\r
+ 43 background yellow\r
+ 44 background blue\r
+ 45 background magenta\r
+ 46 background cyan\r
+ 47 background white\r
+ 49 default background (using current intensity)\r
+\r
+[J erase from cursor to the end of display\r
+[0J as above\r
+[1J erase from the start of diplay to cursor (inclusive)\r
+[2J erase display and move cursor to the top-left\r
+\r
+[K erase from cursor to the end of line\r
+[0K as above\r
+[1K erase from the start of line to cursor (inclusive)\r
+[2K erase line\r
+\r
+[X erase one character\r
+[#X erase # characters\r
+\r
+[L insert one blank line\r
+[#L insert # blank lines\r
+\r
+[M delete one line\r
+[#M delete # lines\r
+\r
+[P delete one character\r
+[#P delete # characters\r
+\r
+[@ insert one blank character\r
+[#@ insert # blank characters\r
+\r
+[A move cursor up one line\r
+[#A move cursor up # lines\r
+[B move cursor down one line\r
+[#B move cursor down # lines\r
+[C move cursor right one character\r
+[#C move cursor right # characters\r
+[D move cursor left one character\r
+[#D move cursor left # characters\r
+\r
+[k move cursor up one line\r
+[#k move cursor up # lines\r
+[e move cursor down one line\r
+[#e move cursor down # lines\r
+[a move cursor right one character\r
+[#a move cursor right # characters\r
+[j move cursor left one character\r
+[#j move cursor left # characters\r
+\r
+[E move cursor down one line and to first column\r
+[#E move cursor down # lines and to first column\r
+[F move cursor up one line and to first column\r
+[#F move cursor up # lines and to first column\r
+\r
+[G move cursor to first column\r
+[#G move cursor to column #\r
+\r
+[` move cursor to first column\r
+[#` move cursor to column #\r
+\r
+[d move cursor to first line\r
+[#d move cursor to line #\r
+\r
+[H move cursor to top-left\r
+[#H move cursor to line # and first column\r
+[#;#H move cursor to line #, column #\r
+\r
+[f move cursor to top-left\r
+[#f move cursor to line # and first column\r
+[#;#f move cursor to line #, column #\r
+\r
+[s save cursor position\r
+[u move cursor to saved position\r
+\r
+[?25h show cursor\r
+[?25l hide cursor\r
+\r
+[5n sends "\e[0n" to console input (where \e is escape)\r
+[6n sends "\e[#;#R" (line & column) to console input\r
+[21t sends "\e]lTitle\e\" (the console's window title) to console input\r
+]0;TitleST\r
+ sets the console title to "Title"; ST (string terminator) is either\r
+ character 7 (BEL) or escape and backslash\r
-/*
- 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 );
-}
+/*\r
+ util.c - Utility functions.\r
+*/\r
+\r
+#include "ansicon.h"\r
+#include "version.h"\r
+\r
+\r
+TCHAR prog_path[MAX_PATH];\r
+LPTSTR prog;\r
+int log_level;\r
+char tempfile[MAX_PATH];\r
+DWORD pid;\r
+\r
+\r
+// Get just the name of the program: "C:\path\program.exe" -> "program".\r
+// Returns a pointer within program; it is modified to remove the extension.\r
+LPTSTR get_program_name( LPTSTR program )\r
+{\r
+ LPTSTR name, ext;\r
+\r
+ if (program == NULL)\r
+ {\r
+ GetModuleFileName( NULL, prog_path, lenof(prog_path) );\r
+ program = prog_path;\r
+ }\r
+ name = wcsrchr( program, '\\' );\r
+ if (name != NULL)\r
+ ++name;\r
+ else\r
+ name = program;\r
+ ext = wcsrchr( name, '.' );\r
+ if (ext != NULL && ext != name)\r
+ *ext = '\0';\r
+\r
+ return name;\r
+}\r
+\r
+\r
+void DEBUGSTR( int level, LPTSTR szFormat, ... )\r
+{\r
+ TCHAR szBuffer[1024], szEscape[1024];\r
+ va_list pArgList;\r
+ HANDLE mutex;\r
+ DWORD wait;\r
+ FILE* file;\r
+\r
+ if ((log_level & 3) < level && !(level & 4 & log_level))\r
+ return;\r
+\r
+ if (*tempfile == '\0')\r
+ {\r
+ _snprintf( tempfile, MAX_PATH, "%s\\ansicon.log", getenv( "TEMP" ) );\r
+ pid = GetCurrentProcessId();\r
+ }\r
+ if (szFormat == NULL)\r
+ {\r
+ file = fopen( tempfile, (log_level & 8) ? "at" : "wt" );\r
+ if (file != NULL)\r
+ {\r
+ SYSTEMTIME now;\r
+ GetLocalTime( &now );\r
+ fprintf( file, "ANSICON (" BITSA "-bit) v" PVERSA " log (%d) started "\r
+ "%d-%.2d-%.2d %d:%.2d:%.2d\n",\r
+ log_level,\r
+ now.wYear, now.wMonth, now.wDay,\r
+ now.wHour, now.wMinute, now.wSecond );\r
+ fclose( file );\r
+ }\r
+ return;\r
+ }\r
+\r
+ va_start( pArgList, szFormat );\r
+ _vsnwprintf( szBuffer, lenof(szBuffer), szFormat, pArgList );\r
+ va_end( pArgList );\r
+\r
+ szFormat = szBuffer;\r
+ if (*szFormat == '\33')\r
+ {\r
+ BOOL first = TRUE;\r
+ LPTSTR pos = szEscape;\r
+ while (*++szFormat != '\0' && pos < szEscape + lenof(szEscape) - 4)\r
+ {\r
+ if (*szFormat < 32)\r
+ {\r
+ *pos++ = '\\';\r
+ switch (*szFormat)\r
+ {\r
+ case '\a': *pos++ = 'a'; break;\r
+ case '\b': *pos++ = 'b'; break;\r
+ case '\t': *pos++ = 't'; break;\r
+ case '\r': *pos++ = 'r'; break;\r
+ case '\n': *pos++ = 'n'; break;\r
+ case 27 : *pos++ = 'e'; break;\r
+ default:\r
+ pos += _snwprintf( pos, 32, L"%.*o",\r
+ (szFormat[1] >= '0' && szFormat[1] <= '7') ? 3 : 1,\r
+ *szFormat );\r
+ }\r
+ }\r
+ else\r
+ {\r
+ if (*szFormat == '"')\r
+ {\r
+ if (first)\r
+ first = FALSE;\r
+ else if (szFormat[1] != '\0')\r
+ *pos++ = '\\';\r
+ }\r
+ *pos++ = *szFormat;\r
+ }\r
+ }\r
+ *pos = '\0';\r
+ szFormat = szEscape;\r
+ }\r
+\r
+ mutex = CreateMutex( NULL, FALSE, L"ANSICON_debug_file" );\r
+ wait = WaitForSingleObject( mutex, 500 );\r
+ file = fopen( tempfile, "at" ); // _fmode might be binary\r
+ if (file != NULL)\r
+ {\r
+ fwprintf( file, L"%s (%lu): %s\n", prog, pid, szFormat );\r
+ fclose( file );\r
+ }\r
+ if (wait == WAIT_OBJECT_0)\r
+ ReleaseMutex( mutex );\r
+ CloseHandle( mutex );\r
+}\r
-/*
- 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)
+/*\r
+ version.h - Version defines.\r
+*/\r
+\r
+#define PVERS L"1.66" // wide string\r
+#define PVERSA "1.66" // ANSI string (windres 2.16.91 didn't like L)\r
+#define PVERE L"166" // wide environment string\r
+#define PVEREA "166" // ANSI environment string\r
+#define PVERB 1,6,6,0 // binary (resource)\r
+\r
+#ifdef _WIN64\r
+# define BITS L"64"\r
+# define BITSA "64"\r
+#else\r
+# define BITS L"32"\r
+# define BITSA "32"\r
+#endif\r
+\r
+#define ANSIDLL L"ANSI" BITS L".dll"\r
-/*
- 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
+/*\r
+ wow64.h - Definitions for Wow64.\r
+\r
+ The 2003 Platform SDK does not include these Wow64 definitions.\r
+*/\r
+\r
+#ifndef WOW64_H\r
+#define WOW64_H\r
+\r
+#define WIN32_LEAN_AND_MEAN\r
+#include <windows.h>\r
+\r
+#define WOW64_CONTEXT_i386 0x00010000\r
+\r
+#define WOW64_CONTEXT_CONTROL (WOW64_CONTEXT_i386 | 0x00000001L)\r
+#define WOW64_CONTEXT_INTEGER (WOW64_CONTEXT_i386 | 0x00000002L)\r
+#define WOW64_CONTEXT_SEGMENTS (WOW64_CONTEXT_i386 | 0x00000004L)\r
+#define WOW64_CONTEXT_FLOATING_POINT (WOW64_CONTEXT_i386 | 0x00000008L)\r
+#define WOW64_CONTEXT_DEBUG_REGISTERS (WOW64_CONTEXT_i386 | 0x00000010L)\r
+#define WOW64_CONTEXT_EXTENDED_REGISTERS (WOW64_CONTEXT_i386 | 0x00000020L)\r
+\r
+#define WOW64_CONTEXT_FULL (WOW64_CONTEXT_CONTROL | WOW64_CONTEXT_INTEGER | WOW64_CONTEXT_SEGMENTS)\r
+\r
+#define WOW64_CONTEXT_ALL (WOW64_CONTEXT_CONTROL | WOW64_CONTEXT_INTEGER | WOW64_CONTEXT_SEGMENTS | \\r
+ WOW64_CONTEXT_FLOATING_POINT | WOW64_CONTEXT_DEBUG_REGISTERS | \\r
+ WOW64_CONTEXT_EXTENDED_REGISTERS)\r
+\r
+#define WOW64_SIZE_OF_80387_REGISTERS 80\r
+\r
+#define WOW64_MAXIMUM_SUPPORTED_EXTENSION 512\r
+\r
+typedef struct _WOW64_FLOATING_SAVE_AREA {\r
+ DWORD ControlWord;\r
+ DWORD StatusWord;\r
+ DWORD TagWord;\r
+ DWORD ErrorOffset;\r
+ DWORD ErrorSelector;\r
+ DWORD DataOffset;\r
+ DWORD DataSelector;\r
+ BYTE RegisterArea[WOW64_SIZE_OF_80387_REGISTERS];\r
+ DWORD Cr0NpxState;\r
+} WOW64_FLOATING_SAVE_AREA;\r
+\r
+typedef WOW64_FLOATING_SAVE_AREA *PWOW64_FLOATING_SAVE_AREA;\r
+\r
+typedef struct _WOW64_CONTEXT {\r
+\r
+ DWORD ContextFlags;\r
+\r
+ DWORD Dr0;\r
+ DWORD Dr1;\r
+ DWORD Dr2;\r
+ DWORD Dr3;\r
+ DWORD Dr6;\r
+ DWORD Dr7;\r
+\r
+ WOW64_FLOATING_SAVE_AREA FloatSave;\r
+\r
+ DWORD SegGs;\r
+ DWORD SegFs;\r
+ DWORD SegEs;\r
+ DWORD SegDs;\r
+\r
+ DWORD Edi;\r
+ DWORD Esi;\r
+ DWORD Ebx;\r
+ DWORD Edx;\r
+ DWORD Ecx;\r
+ DWORD Eax;\r
+\r
+ DWORD Ebp;\r
+ DWORD Eip;\r
+ DWORD SegCs;\r
+ DWORD EFlags;\r
+ DWORD Esp;\r
+ DWORD SegSs;\r
+\r
+ BYTE ExtendedRegisters[WOW64_MAXIMUM_SUPPORTED_EXTENSION];\r
+\r
+} WOW64_CONTEXT;\r
+\r
+typedef WOW64_CONTEXT *PWOW64_CONTEXT;\r
+\r
+\r
+typedef BOOL (WINAPI *TWow64GetThreadContext)( HANDLE hThread, PWOW64_CONTEXT lpContext );\r
+typedef BOOL (WINAPI *TWow64SetThreadContext)( HANDLE hThread, CONST WOW64_CONTEXT *lpContext );\r
+\r
+#endif\r
echo "Make sdb..."
make
- echo "Make ancicon..."
- cd "ansicon"
- if [ "${TARGET_OS}" = "windows-32" ]
- then
- make ansicon32
- else
- make ansicon32
- fi
- cd ..
+# echo "Make ancicon..."
+# cd "ansicon"
+# if [ "${TARGET_OS}" = "windows-32" ]
+# then
+# make ansicon32
+# else
+# make ansicon32
+# fi
+# cd ..
}
# install
[ "$1" = "clean" ] && clean
[ "$1" = "build" ] && build
[ "$1" = "install" ] && install
-exit 0
\ No newline at end of file
+exit 0