Improvements

This commit is contained in:
Jason Hood 2010-12-12 21:58:35 +10:00
parent a3a594001b
commit b9d2207742
10 changed files with 261 additions and 115 deletions

139
ANSI.c
View File

@ -57,26 +57,18 @@
v1.31, 13 & 19 November, 2010:
fix multibyte conversion problems.
v1.32, 4 December, 2010:
test for lpNumberOfCharsWritten/lpNumberOfBytesWritten being NULL.
v1.32, 4 & 12 December, 2010:
test for lpNumberOfCharsWritten/lpNumberOfBytesWritten being NULL;
recognise DSR and xterm window title;
ignore sequences starting with \e[? & \e[>.
*/
#ifndef UNICODE
# define UNICODE
#endif
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include "ansicon.h"
#include <tlhelp32.h>
#include "injdll.h"
#include "debugstr.h"
#define lenof(array) (sizeof(array)/sizeof(*(array)))
#define isdigit(c) ('0' <= (c) && (c) <= '9')
// ========== Global variables and constants
// Macro for adding pointers/DWORDs together without C arithmetic interfering
@ -107,14 +99,18 @@ HMODULE hKernel; // Kernel32 module handle
HINSTANCE hDllInstance; // Dll instance handle
HANDLE hConOut; // handle to CONOUT$
#define ESC '\x1B' // ESCape character
#define ESC '\x1B' // ESCape character
#define BEL '\x07'
#define MAX_ARG 16 // max number of args in an escape sequence
int state; // automata state
//TCHAR prefix; // escape sequence prefix ( '[' or '(' );
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;
// color constants
@ -384,6 +380,30 @@ void PushBuffer( TCHAR c )
}
}
//-----------------------------------------------------------------------------
// 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 );
for (; *seq; ++seq)
{
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.uChar.UnicodeChar = *seq;
in.Event.KeyEvent.dwControlKeyState = 0;
WriteConsoleInput( hStdIn, &in, 1, &out );
}
}
// ========== Print functions
//-----------------------------------------------------------------------------
@ -410,7 +430,11 @@ void InterpretEscSeq( void )
SMALL_RECT Rect;
CHAR_INFO CharInfo;
//if (prefix == '[')
// Just ignore \e[? & \e[> sequences.
if (prefix2 != 0)
return;
if (prefix == '[')
{
GetConsoleScreenBufferInfo( hConOut, &Info );
switch (suffix)
@ -707,13 +731,49 @@ void InterpretEscSeq( void )
SetConsoleCursorPosition( hConOut, SavePos );
return;
case 'n': // ESC[#n Device status report
if (es_argc != 1) return; // ESC[n == ESC[0n -> ignored
if (es_argv[0] == 5)
SendSequence( L"\x1b[0n" ); // "OK"
else if (es_argv[0] == 6)
{
TCHAR buf[32];
wsprintf( buf, L"\x1b[%d;%dR", Info.dwCursorPosition.Y + 1,
Info.dwCursorPosition.X + 1 );
SendSequence( buf );
}
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 == ']')
{
if (es_argc == 1 && es_argv[0] == 0) // ESC]0;titleST
{
DEBUGSTR( L"SetConsoleTitle = %d", SetConsoleTitle( Pt_arg ) );
}
}
}
//-----------------------------------------------------------------------------
// ParseAndPrintString(hDev, lpBuffer, nNumberOfBytesToWrite)
// Parses the string lpBuffer, interprets the escapes sequences and prints the
@ -748,11 +808,14 @@ ParseAndPrintString( HANDLE hDev,
else if (state == 2)
{
if (*s == ESC) ; // \e\e...\e == \e
else if ((*s == '[')) // || (*s == '('))
else if ((*s == '[') || (*s == ']')) // || (*s == '('))
{
FlushBuffer();
//prefix = *s;
prefix = *s;
prefix2 = 0;
state = 3;
Pt_len = 0;
*Pt_arg = '\0';
}
else state = 1;
}
@ -771,6 +834,10 @@ ParseAndPrintString( HANDLE hDev,
es_argv[1] = 0;
state = 4;
}
else if (*s == '?' || *s == '>')
{
prefix2 = *s;
}
else
{
es_argc = 0;
@ -788,7 +855,9 @@ ParseAndPrintString( HANDLE hDev,
else if (*s == ';')
{
if (es_argc < MAX_ARG-1) es_argc++;
es_argv[es_argc] = 0;
es_argv[es_argc] = 0;
if (prefix == ']')
state = 5;
}
else
{
@ -798,6 +867,23 @@ ParseAndPrintString( HANDLE hDev,
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;
}
}
FlushBuffer();
if (lpNumberOfBytesWritten != NULL)
@ -834,11 +920,6 @@ void Inject( LPPROCESS_INFORMATION pinfo, LPPROCESS_INFORMATION lpi,
InjectDLL32( pinfo, dll );
#endif
}
else
{
DEBUGSTR( L" Unsupported process type" );
}
if (lpi)
memcpy( lpi, pinfo, sizeof(PROCESS_INFORMATION) );
@ -1194,14 +1275,10 @@ BOOL WINAPI DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved )
HMODULE api;
PHookFn hook;
#if (MYDEBUG > 1)
_snprintf( tempfile, MAX_PATH, "%s\\ansicon.log", getenv( "TEMP" ) );
#endif
if (dwReason == DLL_PROCESS_ATTACH)
{
#if (MYDEBUG > 1)
DeleteFileA( tempfile );
DEBUGSTR( NULL );
#endif
hDllInstance = hInstance; // save Dll instance handle

View File

@ -43,30 +43,19 @@
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 December, 2010:
make -p more robust.
v1.32, 4 & 12 December, 2010:
make -p more robust;
inject into GUI processes again.
*/
#define PVERS L"1.32"
#define PDATE L"4 December, 2010"
#define PDATE L"12 December, 2010"
#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>
#include "ansicon.h"
#include <shellapi.h>
#include <tlhelp32.h>
#include <ctype.h>
#include <io.h>
#include "injdll.h"
#include "debugstr.h"
#define lenof(array) (sizeof(array)/sizeof(*(array)))
#ifdef __MINGW32__
int _CRT_glob = 0;

46
ansicon.h Normal file
View File

@ -0,0 +1,46 @@
/*
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)))
BOOL ProcessType( LPPROCESS_INFORMATION );
void InjectDLL32( LPPROCESS_INFORMATION, LPCTSTR );
void InjectDLL64( LPPROCESS_INFORMATION, LPCTSTR );
// ========== Auxiliary debug function
//#define MYDEBUG 1 // use OutputDebugString
#define MYDEBUG 2 // use %temp%\ansicon.log
#ifndef MYDEBUG
# define MYDEBUG 0 // no debugging
#endif
#if (MYDEBUG > 0)
void DEBUGSTR( LPTSTR szFormat, ... );
#else
# if defined(_MSC_VER) && _MSC_VER <= 1400
void DEBUGSTR() { }
# else
# define DEBUGSTR(...)
# endif
#endif
#endif

View File

@ -2,24 +2,31 @@
debugstr.c - Auxiliary debug functionality.
*/
#ifndef UNICODE
# define UNICODE
#include "ansicon.h"
#if (MYDEBUG > 1)
char tempfile[MAX_PATH];
#endif
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <ImageHlp.h>
#include "debugstr.h"
#define lenof(array) (sizeof(array)/sizeof(*(array)))
#if (MYDEBUG > 0)
void DEBUGSTR( LPTSTR szFormat, ... ) // sort of OutputDebugStringf
{
TCHAR szBuffer[1024], szEscape[1024];
va_list pArgList;
#if (MYDEBUG > 1)
if (*tempfile == '\0')
_snprintf( tempfile, MAX_PATH, "%s\\ansicon.log", getenv( "TEMP" ) );
#endif
if (szFormat == NULL)
{
#if (MYDEBUG > 1)
DeleteFileA( tempfile );
#endif
return;
}
va_start( pArgList, szFormat );
_vsnwprintf( szBuffer, lenof(szBuffer), szFormat, pArgList );
va_end( pArgList );
@ -33,33 +40,34 @@ void DEBUGSTR( LPTSTR szFormat, ... ) // sort of OutputDebugStringf
{
if (*szFormat < 32)
{
*pos++ = '\\';
switch (*szFormat)
{
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 += wprintf( pos, L"%.*o",
(szFormat[1] >= '0' && szFormat[1] <= '7') ? 3 : 1,
*szFormat );
}
*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')
;
else
*pos++ = '\\';
*pos++ = '"';
if (first)
first = FALSE;
else if (szFormat[1] == '\0')
;
else
*pos++ = '\\';
*pos++ = '"';
}
else
{
*pos++ = *szFormat;
*pos++ = *szFormat;
}
}
*pos = '\0';

View File

@ -15,7 +15,7 @@
I've decided to simply keep the memory.
*/
#include "injdll.h"
#include "ansicon.h"
#ifdef _WIN64
#if defined(__MINGW64__) || (defined(_MSC_VER) && _MSC_VER <= 1400)
@ -65,7 +65,10 @@ void InjectDLL32( LPPROCESS_INFORMATION ppi, LPCTSTR dll )
GETPROC( Wow64SetThreadContext );
// Assume if one is defined, so is the other.
if (Wow64GetThreadContext == 0)
{
DEBUGSTR( "Failed to get pointer to Wow64GetThreadContext.\n" );
return;
}
#endif
STARTUPINFO si;
@ -78,7 +81,10 @@ void InjectDLL32( LPPROCESS_INFORMATION ppi, LPCTSTR dll )
CopyMemory( code + len - 7*sizeof(TCHAR), L"-LLW.exe", 9*sizeof(TCHAR) );
if (!CreateProcess( (LPCTSTR)code, NULL, NULL, NULL, FALSE, 0, NULL, NULL,
&si, &pi ))
{
DEBUGSTR( "Failed to execute \"%s\".\n", (LPCTSTR)code );
return;
}
WaitForSingleObject( pi.hProcess, INFINITE );
GetExitCodeProcess( pi.hProcess, &LLW );
CloseHandle( pi.hProcess );

View File

@ -15,7 +15,7 @@
I've decided to simply keep the memory.
*/
#include "injdll.h"
#include "ansicon.h"
void InjectDLL64( LPPROCESS_INFORMATION ppi, LPCTSTR dll )
{

View File

@ -11,6 +11,9 @@
CC = gcc
CFLAGS = -O2 -Wall
X86OBJS = x86/proctype.o x86/injdll32.o x86/debugstr.o
X64OBJS = x64/proctype.o x64/injdll64.o x64/injdll32.o x64/debugstr.o
x86/%.o: %.c
$(CC) -m32 -c $(CFLAGS) $(CPPFLAGS) $< -o $@
@ -32,19 +35,19 @@ ansicon64: x64 x64/ansicon.exe x64/ANSI64.dll x64/ANSI32.dll x64/ANSI-LLW.exe
x86:
mkdir x86
x86/ansicon.exe: x86/ansicon.o x86/debugstr.o x86/proctype.o x86/injdll32.o x86/ansiconv.o
x86/ansicon.exe: x86/ansicon.o $(X86OBJS) x86/ansiconv.o
$(CC) -m32 $+ -s -o $@
x86/ANSI32.dll: x86/ANSI.o x86/debugstr.o x86/proctype.o x86/injdll32.o x86/ansiv.o
x86/ANSI32.dll: x86/ANSI.o $(X86OBJS) x86/ansiv.o
$(CC) -m32 $+ -s -o $@ -mdll -Wl,-shared
x64:
mkdir x64
x64/ansicon.exe: x64/ansicon.o x64/debugstr.o x64/proctype.o x64/injdll64.o x64/injdll32.o x64/ansiconv.o
x64/ansicon.exe: x64/ansicon.o $(X64OBJS) x64/ansiconv.o
$(CC) -m64 $+ -s -o $@
x64/ANSI64.dll: x64/ANSI.o x64/debugstr.o x64/proctype.o x64/injdll64.o x64/injdll32.o x64/ansiv.o
x64/ANSI64.dll: x64/ANSI.o $(X64OBJS) x64/ansiv.o
$(CC) -m64 $+ -s -o $@ -mdll -Wl,-shared
x64/ANSI32.dll: x86/ANSI32.dll
@ -58,6 +61,13 @@ x86/ansiv.o: ansi.rc
x64/ansiconv.o: ansicon.rc
x64/ansiv.o: ansi.rc
ansicon.c: ansicon.h
ANSI.c: ansicon.h
debugstr.c: ansicon.h
injdll32.c: ansicon.h
injdll64.c: ansicon.h
proctype.c: ansicon.h
clean:
-rm x86/*.o
-rm x64/*.o

View File

@ -28,6 +28,9 @@ CC = cl
CFLAGS = /nologo /W3 /Ox /GF /D_CRT_SECURE_NO_WARNINGS
LIBS = advapi32.lib shell32.lib user32.lib
X86OBJS = x86\proctype.obj x86\injdll32.obj x86\debugstr.obj
X64OBJS = x64\proctype.obj x64\injdll64.obj x64\injdll32.obj x64\debugstr.obj
{}.c{$(DIR)}.obj:
$(CC) /c $(CFLAGS) /Fo$@ $<
@ -43,10 +46,10 @@ ansicon64: x64 x64\ansicon.exe x64\ANSI64.dll x64\ANSI32.dll x64\ANSI-LLW.exe
x86:
mkdir x86
x86\ansicon.exe: x86\ansicon.obj x86\proctype.obj x86\injdll32.obj x86\ansicon.res
x86\ansicon.exe: x86\ansicon.obj $(X86OBJS) x86\ansicon.res
$(CC) /nologo /Fe$@ $** $(LIBS)
x86\ANSI32.dll: x86\ANSI.obj x86\proctype.obj x86\injdll32.obj x86\ansi.res
x86\ANSI32.dll: x86\ANSI.obj $(X86OBJS) x86\ansi.res
!IF $(BITS) == 32
$(CC) /nologo /LD /Fe$@ $** $(LIBS)
!ENDIF
@ -54,10 +57,10 @@ x86\ANSI32.dll: x86\ANSI.obj x86\proctype.obj x86\injdll32.obj x86\ansi.res
x64:
mkdir x64
x64\ansicon.exe: x64\ansicon.obj x64\proctype.obj x64\injdll64.obj x64\injdll32.obj x64\ansicon.res
x64\ansicon.exe: x64\ansicon.obj $(X64OBJS) x64\ansicon.res
$(CC) /nologo /Fe$@ $** $(LIBS) bufferoverflowu.lib
x64\ANSI64.dll: x64\ANSI.obj x64\proctype.obj x64\injdll64.obj x64\injdll32.obj x64\ansi.res
x64\ANSI64.dll: x64\ANSI.obj $(X64OBJS) x64\ansi.res
$(CC) /nologo /LD /Fe$@ $** $(LIBS) bufferoverflowu.lib
x64\ANSI32.dll: x86\ANSI32.dll
@ -66,5 +69,12 @@ x64\ANSI32.dll: x86\ANSI32.dll
x64\ANSI-LLW.exe: ANSI-LLW.c
$(CC) $(CFLAGS) /Fe$@ /Fo$*.obj $? bufferoverflowu.lib
ansicon.c: ansicon.h
ANSI.c: ansicon.h
debugstr.c: ansicon.h
injdll32.c: ansicon.h
injdll64.c: ansicon.h
proctype.c: ansicon.h
clean:
-del $(DIR)\*.obj $(DIR)\*.res
-del $(DIR)\*.obj $(DIR)\*.res $(DIR)\*.lib $(DIR)\*.exp

View File

@ -2,15 +2,13 @@
Test for a valid process.
*/
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include "ansicon.h"
int ProcessType( LPPROCESS_INFORMATION pinfo )
{
MEMORY_BASIC_INFORMATION minfo;
char* ptr = 0;
int type = 0;
while (VirtualQueryEx( pinfo->hProcess, ptr, &minfo, sizeof(minfo) ))
{
@ -28,37 +26,31 @@ int ProcessType( LPPROCESS_INFORMATION pinfo )
{
if (nt_header.Signature == IMAGE_NT_SIGNATURE)
{
if (nt_header.OptionalHeader.Subsystem ==
IMAGE_SUBSYSTEM_WINDOWS_CUI)
if (nt_header.OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI ||
nt_header.OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI)
{
if (nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_I386)
{
type = 32;
return 32;
#ifdef _WIN64
}
else if (nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64)
{
type = 64;
if (nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64)
return 64;
#endif
}
else
{
//DEBUGSTR( L" Ignoring unsupported machine (%x)",
// nt_header.FileHeader.Machine );
}
DEBUGSTR( L" Ignoring unsupported machine (0x%X)",
nt_header.FileHeader.Machine );
}
else
{
//DEBUGSTR( L" Ignoring non-console subsystem (%u)",
// nt_header.OptionalHeader.Subsystem );
DEBUGSTR( L" Ignoring non-Windows subsystem (%u)",
nt_header.OptionalHeader.Subsystem );
}
break;
}
}
return 0;
}
}
ptr += minfo.RegionSize;
}
return type;
DEBUGSTR( L" Ignoring non-Windows process" );
return 0;
}

View File

@ -114,6 +114,9 @@
\e[#@ ICH: Insert CHaracter
\e[#P DCH: Delete CHaracter
\e[#;#;#m SGM: Set Graphics Mode
\e[#n DSR: Device Status Report
\e[21t Report (xterm) window's title
\e]0;titleBEL Set (xterm) window's title (and icon)
`\e' represents the escape character (ASCII 27); `#' represents a
decimal number (optional, in most cases defaulting to 1). Regarding
@ -144,9 +147,11 @@
Legend: + added, - bug-fixed, * changed.
1.32 - 4 December, 2010:
1.32 - 12 December, 2010:
- fixed crash due to NULL lpNumberOfBytesWritten/lpNumberOfCharsWritten;
- -p will test the parent process for validity.
- -p will test the parent process for validity;
* hook into GUI processes;
+ recognise DSR and xterm window title sequences.
1.31 - 19 November, 2010:
- fixed multibyte support (no extra junk with UTF-8 files);
@ -238,6 +243,8 @@
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.
=======
Contact
@ -245,6 +252,7 @@
mailto:jadoxa@yahoo.com.au
http://ansicon.adoxa.cjb.net/
https://github.com/adoxa/ansicon
Jason Hood
11 Buckle Street
@ -264,5 +272,5 @@
in the version text and a source diff is included.
=============================
Jason Hood, 4 December, 2010.
==============================
Jason Hood, 12 December, 2010.