Many changes, bad programmer!
Just copying the history from the source: recognize the standard handle defines in WriteFile; minor speed improvement by caching GetConsoleMode; keep track of three handles (ostensibly stdout, stderr and a file); test a DOS header exists before writing to e_oemid; more flexible/robust handling of data directories; files writing to the console will always succeed; log: use API file functions and a custom printf; add a blank line between processes; set function name for MyWriteConsoleA; scan imports from "kernel32" (without extension); added dynamic environment variable CLICOLOR; removed _hwrite (it's the same address as _lwrite); join multibyte characters split across separate writes; remove wcstok, avoiding potential interference with the host; similarly, use a private heap instead of malloc.
This commit is contained in:
parent
2f18f10719
commit
40f59c543c
25
ansicon.c
25
ansicon.c
@ -87,7 +87,7 @@
|
|||||||
add error codes to some message.
|
add error codes to some message.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define PDATE L"26 February, 2014"
|
#define PDATE L"24 December, 2015"
|
||||||
|
|
||||||
#include "ansicon.h"
|
#include "ansicon.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
@ -169,6 +169,7 @@ int my_fputws( const wchar_t* s, FILE* f )
|
|||||||
#define _putws( s ) my_fputws( s L"\n", stdout )
|
#define _putws( s ) my_fputws( s L"\n", stdout )
|
||||||
|
|
||||||
|
|
||||||
|
HANDLE hHeap;
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
LPTSTR DllNameType;
|
LPTSTR DllNameType;
|
||||||
#endif
|
#endif
|
||||||
@ -183,7 +184,7 @@ BOOL Inject( LPPROCESS_INFORMATION ppi, BOOL* gui, LPCTSTR app )
|
|||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
if (app != NULL)
|
if (app != NULL)
|
||||||
#endif
|
#endif
|
||||||
DEBUGSTR( 1, L"%s (%lu)", app, ppi->dwProcessId );
|
DEBUGSTR( 1, "%S (%u)", app, ppi->dwProcessId );
|
||||||
type = ProcessType( ppi, &base, gui );
|
type = ProcessType( ppi, &base, gui );
|
||||||
if (type <= 0)
|
if (type <= 0)
|
||||||
{
|
{
|
||||||
@ -230,7 +231,7 @@ void RemoteLoad( LPPROCESS_INFORMATION ppi, LPCTSTR app )
|
|||||||
int type;
|
int type;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
DEBUGSTR( 1, L"%s (%lu)", app, ppi->dwProcessId );
|
DEBUGSTR( 1, "%S (%u)", app, ppi->dwProcessId );
|
||||||
|
|
||||||
// Find the base address of kernel32.dll.
|
// Find the base address of kernel32.dll.
|
||||||
ticks = GetTickCount();
|
ticks = GetTickCount();
|
||||||
@ -242,7 +243,7 @@ void RemoteLoad( LPPROCESS_INFORMATION ppi, LPCTSTR app )
|
|||||||
#ifndef _WIN64
|
#ifndef _WIN64
|
||||||
if (err == ERROR_PARTIAL_COPY)
|
if (err == ERROR_PARTIAL_COPY)
|
||||||
{
|
{
|
||||||
DEBUGSTR( 1, L" Ignoring 64-bit process (use x64\\ansicon)" );
|
DEBUGSTR( 1, " Ignoring 64-bit process (use x64\\ansicon)" );
|
||||||
fputws( L"ANSICON: parent is 64-bit (use x64\\ansicon).\n", stderr );
|
fputws( L"ANSICON: parent is 64-bit (use x64\\ansicon).\n", stderr );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -251,10 +252,10 @@ void RemoteLoad( LPPROCESS_INFORMATION ppi, LPCTSTR app )
|
|||||||
// two seconds to avoid a potentially infinite loop.
|
// two seconds to avoid a potentially infinite loop.
|
||||||
if (err == ERROR_BAD_LENGTH && GetTickCount() - ticks < 2000)
|
if (err == ERROR_BAD_LENGTH && GetTickCount() - ticks < 2000)
|
||||||
{
|
{
|
||||||
Sleep( 0 );
|
Sleep( 1 );
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
DEBUGSTR( 1, L" Unable to create snapshot (%lu)", err );
|
DEBUGSTR( 1, " Unable to create snapshot (%u)", err );
|
||||||
no_go:
|
no_go:
|
||||||
fputws( L"ANSICON: unable to inject into parent.\n", stderr );
|
fputws( L"ANSICON: unable to inject into parent.\n", stderr );
|
||||||
return;
|
return;
|
||||||
@ -272,7 +273,7 @@ void RemoteLoad( LPPROCESS_INFORMATION ppi, LPCTSTR app )
|
|||||||
CloseHandle( hSnap );
|
CloseHandle( hSnap );
|
||||||
if (LLW == NULL)
|
if (LLW == NULL)
|
||||||
{
|
{
|
||||||
DEBUGSTR( 1, L" Unable to locate kernel32.dll (%lu)", GetLastError() );
|
DEBUGSTR( 1, " Unable to locate kernel32.dll" );
|
||||||
goto no_go;
|
goto no_go;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -292,7 +293,7 @@ void RemoteLoad( LPPROCESS_INFORMATION ppi, LPCTSTR app )
|
|||||||
mem = VirtualAllocEx( ppi->hProcess, NULL, len, MEM_COMMIT, PAGE_READWRITE );
|
mem = VirtualAllocEx( ppi->hProcess, NULL, len, MEM_COMMIT, PAGE_READWRITE );
|
||||||
if (mem == NULL)
|
if (mem == NULL)
|
||||||
{
|
{
|
||||||
DEBUGSTR( 1, L" Unable to allocate virtual memory (%lu)", GetLastError() );
|
DEBUGSTR(1, " Failed to allocate virtual memory (%u)", GetLastError());
|
||||||
goto no_go;
|
goto no_go;
|
||||||
}
|
}
|
||||||
WriteProcMem( mem, DllName, TSIZE(len + 11) );
|
WriteProcMem( mem, DllName, TSIZE(len + 11) );
|
||||||
@ -357,6 +358,8 @@ int main( void )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hHeap = HeapCreate( 0, 0, 65 * 1024 );
|
||||||
|
|
||||||
prog = get_program_name( NULL );
|
prog = get_program_name( NULL );
|
||||||
*buf = '\0';
|
*buf = '\0';
|
||||||
GetEnvironmentVariable( L"ANSICON_LOG", buf, lenof(buf) );
|
GetEnvironmentVariable( L"ANSICON_LOG", buf, lenof(buf) );
|
||||||
@ -369,7 +372,7 @@ int main( void )
|
|||||||
pi.hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, pi.dwProcessId );
|
pi.hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, pi.dwProcessId );
|
||||||
if (pi.hProcess == NULL)
|
if (pi.hProcess == NULL)
|
||||||
{
|
{
|
||||||
DEBUGSTR( 1, L" Unable to open process %lu (%lu)",
|
DEBUGSTR( 1, " Unable to open process %u (%u)",
|
||||||
pi.dwProcessId, GetLastError() );
|
pi.dwProcessId, GetLastError() );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -738,7 +741,7 @@ BOOL GetParentProcessInfo( LPPROCESS_INFORMATION ppi, LPTSTR name )
|
|||||||
hSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
|
hSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
|
||||||
if (hSnap == INVALID_HANDLE_VALUE)
|
if (hSnap == INVALID_HANDLE_VALUE)
|
||||||
{
|
{
|
||||||
DEBUGSTR( 1, L"Failed to create snapshot (%lu)", GetLastError() );
|
DEBUGSTR( 1, "Failed to create snapshot (%u)", GetLastError() );
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -747,7 +750,7 @@ BOOL GetParentProcessInfo( LPPROCESS_INFORMATION ppi, LPTSTR name )
|
|||||||
CloseHandle( hSnap );
|
CloseHandle( hSnap );
|
||||||
if (!fOk)
|
if (!fOk)
|
||||||
{
|
{
|
||||||
DEBUGSTR( 1, L"Failed to locate parent" );
|
DEBUGSTR( 1, "Failed to locate parent" );
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
// Macro for adding pointers/DWORDs together without C arithmetic interfering
|
// Macro for adding pointers/DWORDs together without C arithmetic interfering
|
||||||
#define MakeVA( cast, offset ) (cast)((DWORD_PTR)pDosHeader + (DWORD)(offset))
|
#define MakeVA( cast, offset ) (cast)((DWORD_PTR)pDosHeader + (DWORD)(offset))
|
||||||
|
|
||||||
|
#define DATADIRS OptionalHeader.NumberOfRvaAndSizes
|
||||||
#define EXPORTDIR OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]
|
#define EXPORTDIR OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]
|
||||||
#define IMPORTDIR OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
|
#define IMPORTDIR OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
|
||||||
#define BOUNDDIR OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT]
|
#define BOUNDDIR OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT]
|
||||||
@ -61,6 +62,7 @@ DWORD GetProcRVA( LPCTSTR, LPCSTR, int );
|
|||||||
DWORD GetProcRVA( LPCTSTR, LPCSTR );
|
DWORD GetProcRVA( LPCTSTR, LPCSTR );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
extern HANDLE hHeap;
|
||||||
|
|
||||||
extern TCHAR prog_path[MAX_PATH];
|
extern TCHAR prog_path[MAX_PATH];
|
||||||
extern LPTSTR prog;
|
extern LPTSTR prog;
|
||||||
@ -74,6 +76,6 @@ extern char* ansi_bits;
|
|||||||
void set_ansi_dll( void );
|
void set_ansi_dll( void );
|
||||||
|
|
||||||
extern int log_level;
|
extern int log_level;
|
||||||
void DEBUGSTR( int level, LPTSTR szFormat, ... );
|
void DEBUGSTR( int level, LPCSTR szFormat, ... );
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
106
injdll.c
106
injdll.c
@ -38,11 +38,35 @@ static PVOID FindMem( HANDLE hProcess, PBYTE base, DWORD len )
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Count the imports directly (including the terminator), since the size of the
|
||||||
|
// import directory is not necessarily correct (Windows doesn't use it at all).
|
||||||
|
static DWORD sizeof_imports( LPPROCESS_INFORMATION ppi,
|
||||||
|
PBYTE pBase, DWORD rImports )
|
||||||
|
{
|
||||||
|
IMAGE_IMPORT_DESCRIPTOR import;
|
||||||
|
PIMAGE_IMPORT_DESCRIPTOR pImports;
|
||||||
|
DWORD cnt;
|
||||||
|
|
||||||
|
if (rImports == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
pImports = (PIMAGE_IMPORT_DESCRIPTOR)(pBase + rImports);
|
||||||
|
cnt = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
++cnt;
|
||||||
|
ReadProcVar( pImports++, &import );
|
||||||
|
} while (import.Name != 0);
|
||||||
|
|
||||||
|
return cnt * sizeof(import);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void InjectDLL( LPPROCESS_INFORMATION ppi, PBYTE pBase )
|
void InjectDLL( LPPROCESS_INFORMATION ppi, PBYTE pBase )
|
||||||
{
|
{
|
||||||
DWORD rva;
|
DWORD rva;
|
||||||
PVOID pMem;
|
PVOID pMem;
|
||||||
DWORD len;
|
DWORD len, import_size;
|
||||||
DWORD pr;
|
DWORD pr;
|
||||||
IMAGE_DOS_HEADER DosHeader;
|
IMAGE_DOS_HEADER DosHeader;
|
||||||
IMAGE_NT_HEADERS NTHeader, *pNTHeader;
|
IMAGE_NT_HEADERS NTHeader, *pNTHeader;
|
||||||
@ -59,18 +83,19 @@ void InjectDLL( LPPROCESS_INFORMATION ppi, PBYTE pBase )
|
|||||||
pNTHeader = (PIMAGE_NT_HEADERS)(pBase + DosHeader.e_lfanew);
|
pNTHeader = (PIMAGE_NT_HEADERS)(pBase + DosHeader.e_lfanew);
|
||||||
ReadProcVar( pNTHeader, &NTHeader );
|
ReadProcVar( pNTHeader, &NTHeader );
|
||||||
|
|
||||||
len = 4 * PTRSZ + ansi_len + sizeof(*pImports) + NTHeader.IMPORTDIR.Size;
|
import_size = sizeof_imports( ppi, pBase, NTHeader.IMPORTDIR.VirtualAddress );
|
||||||
pImports = malloc( len );
|
len = 2 * PTRSZ + ansi_len + sizeof(*pImports) + import_size;
|
||||||
|
pImports = HeapAlloc( hHeap, 0, len );
|
||||||
if (pImports == NULL)
|
if (pImports == NULL)
|
||||||
{
|
{
|
||||||
DEBUGSTR( 1, L" Failed to allocate memory." );
|
DEBUGSTR( 1, " Failed to allocate memory" );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
pMem = FindMem( ppi->hProcess, pBase, len );
|
pMem = FindMem( ppi->hProcess, pBase, len );
|
||||||
if (pMem == NULL)
|
if (pMem == NULL)
|
||||||
{
|
{
|
||||||
DEBUGSTR( 1, L" Failed to allocate virtual memory." );
|
DEBUGSTR( 1, " Failed to allocate virtual memory (%u)", GetLastError() );
|
||||||
free( pImports );
|
HeapFree( hHeap, 0, pImports );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
rva = (DWORD)((PBYTE)pMem - pBase);
|
rva = (DWORD)((PBYTE)pMem - pBase);
|
||||||
@ -78,37 +103,39 @@ void InjectDLL( LPPROCESS_INFORMATION ppi, PBYTE pBase )
|
|||||||
ip.pL = (PLONG_PTR)pImports;
|
ip.pL = (PLONG_PTR)pImports;
|
||||||
*ip.pL++ = IMAGE_ORDINAL_FLAG + 1;
|
*ip.pL++ = IMAGE_ORDINAL_FLAG + 1;
|
||||||
*ip.pL++ = 0;
|
*ip.pL++ = 0;
|
||||||
*ip.pL++ = IMAGE_ORDINAL_FLAG + 1;
|
|
||||||
*ip.pL++ = 0;
|
|
||||||
memcpy( ip.pB, ansi_dll, ansi_len );
|
memcpy( ip.pB, ansi_dll, ansi_len );
|
||||||
ip.pB += ansi_len;
|
ip.pB += ansi_len;
|
||||||
ip.pI->OriginalFirstThunk = rva + 2 * PTRSZ;
|
ip.pI->OriginalFirstThunk = 0;
|
||||||
ip.pI->TimeDateStamp = 0;
|
ip.pI->TimeDateStamp = 0;
|
||||||
ip.pI->ForwarderChain = 0;
|
ip.pI->ForwarderChain = 0;
|
||||||
ip.pI->Name = rva + 4 * PTRSZ;
|
ip.pI->Name = rva + 2 * PTRSZ;
|
||||||
ip.pI->FirstThunk = rva;
|
ip.pI->FirstThunk = rva;
|
||||||
ReadProcMem( pBase + NTHeader.IMPORTDIR.VirtualAddress,
|
ReadProcMem( pBase+NTHeader.IMPORTDIR.VirtualAddress, ip.pI+1, import_size );
|
||||||
ip.pI + 1, NTHeader.IMPORTDIR.Size );
|
|
||||||
WriteProcMem( pMem, pImports, len );
|
WriteProcMem( pMem, pImports, len );
|
||||||
free( pImports );
|
HeapFree( hHeap, 0, pImports );
|
||||||
|
|
||||||
// If there's no IAT, copy the original IDT (to allow writable ".idata").
|
// If there's no IAT, copy the original IDT (to allow writable ".idata").
|
||||||
if (NTHeader.IATDIR.VirtualAddress == 0)
|
if (NTHeader.DATADIRS > IMAGE_DIRECTORY_ENTRY_IAT &&
|
||||||
|
NTHeader.IATDIR.VirtualAddress == 0)
|
||||||
NTHeader.IATDIR = NTHeader.IMPORTDIR;
|
NTHeader.IATDIR = NTHeader.IMPORTDIR;
|
||||||
|
|
||||||
NTHeader.IMPORTDIR.VirtualAddress = rva + 4 * PTRSZ + ansi_len;
|
NTHeader.IMPORTDIR.VirtualAddress = rva + 2 * PTRSZ + ansi_len;
|
||||||
NTHeader.IMPORTDIR.Size += sizeof(*pImports);
|
//NTHeader.IMPORTDIR.Size += sizeof(*pImports);
|
||||||
|
|
||||||
// Remove bound imports, so the updated import table is used.
|
// Remove bound imports, so the updated import table is used.
|
||||||
|
if (NTHeader.DATADIRS > IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT)
|
||||||
|
{
|
||||||
NTHeader.BOUNDDIR.VirtualAddress = 0;
|
NTHeader.BOUNDDIR.VirtualAddress = 0;
|
||||||
NTHeader.BOUNDDIR.Size = 0;
|
//NTHeader.BOUNDDIR.Size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
VirtProtVar( pNTHeader, PAGE_READWRITE );
|
VirtProtVar( pNTHeader, PAGE_READWRITE );
|
||||||
WriteProcVar( pNTHeader, &NTHeader );
|
WriteProcVar( pNTHeader, &NTHeader );
|
||||||
VirtProtVar( pNTHeader, pr );
|
VirtProtVar( pNTHeader, pr );
|
||||||
|
|
||||||
// Remove the IL-only flag on a managed process.
|
// Remove the IL-only flag on a managed process.
|
||||||
if (NTHeader.COMDIR.VirtualAddress != 0 && NTHeader.COMDIR.Size != 0)
|
if (NTHeader.DATADIRS > IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR &&
|
||||||
|
NTHeader.COMDIR.VirtualAddress != 0)
|
||||||
{
|
{
|
||||||
pComHeader = (PIMAGE_COR20_HEADER)(pBase + NTHeader.COMDIR.VirtualAddress);
|
pComHeader = (PIMAGE_COR20_HEADER)(pBase + NTHeader.COMDIR.VirtualAddress);
|
||||||
ReadProcVar( pComHeader, &ComHeader );
|
ReadProcVar( pComHeader, &ComHeader );
|
||||||
@ -128,7 +155,7 @@ void InjectDLL32( LPPROCESS_INFORMATION ppi, PBYTE pBase )
|
|||||||
{
|
{
|
||||||
DWORD rva;
|
DWORD rva;
|
||||||
PVOID pMem;
|
PVOID pMem;
|
||||||
DWORD len;
|
DWORD len, import_size;
|
||||||
DWORD pr;
|
DWORD pr;
|
||||||
IMAGE_DOS_HEADER DosHeader;
|
IMAGE_DOS_HEADER DosHeader;
|
||||||
IMAGE_NT_HEADERS32 NTHeader, *pNTHeader;
|
IMAGE_NT_HEADERS32 NTHeader, *pNTHeader;
|
||||||
@ -145,18 +172,19 @@ void InjectDLL32( LPPROCESS_INFORMATION ppi, PBYTE pBase )
|
|||||||
pNTHeader = (PIMAGE_NT_HEADERS32)(pBase + DosHeader.e_lfanew);
|
pNTHeader = (PIMAGE_NT_HEADERS32)(pBase + DosHeader.e_lfanew);
|
||||||
ReadProcVar( pNTHeader, &NTHeader );
|
ReadProcVar( pNTHeader, &NTHeader );
|
||||||
|
|
||||||
len = 16 + ansi_len + sizeof(*pImports) + NTHeader.IMPORTDIR.Size;
|
import_size = sizeof_imports( ppi, pBase, NTHeader.IMPORTDIR.VirtualAddress );
|
||||||
pImports = malloc( len );
|
len = 8 + ansi_len + sizeof(*pImports) + import_size;
|
||||||
|
pImports = HeapAlloc( hHeap, 0, len );
|
||||||
if (pImports == NULL)
|
if (pImports == NULL)
|
||||||
{
|
{
|
||||||
DEBUGSTR( 1, L" Failed to allocate memory." );
|
DEBUGSTR( 1, " Failed to allocate memory" );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
pMem = FindMem( ppi->hProcess, pBase, len );
|
pMem = FindMem( ppi->hProcess, pBase, len );
|
||||||
if (pMem == NULL)
|
if (pMem == NULL)
|
||||||
{
|
{
|
||||||
DEBUGSTR( 1, L" Failed to allocate virtual memory." );
|
DEBUGSTR( 1, " Failed to allocate virtual memory" );
|
||||||
free( pImports );
|
HeapFree( hHeap, 0, pImports );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
rva = (DWORD)((PBYTE)pMem - pBase);
|
rva = (DWORD)((PBYTE)pMem - pBase);
|
||||||
@ -164,31 +192,33 @@ void InjectDLL32( LPPROCESS_INFORMATION ppi, PBYTE pBase )
|
|||||||
ip.pL = (PLONG)pImports;
|
ip.pL = (PLONG)pImports;
|
||||||
*ip.pL++ = IMAGE_ORDINAL_FLAG32 + 1;
|
*ip.pL++ = IMAGE_ORDINAL_FLAG32 + 1;
|
||||||
*ip.pL++ = 0;
|
*ip.pL++ = 0;
|
||||||
*ip.pL++ = IMAGE_ORDINAL_FLAG32 + 1;
|
|
||||||
*ip.pL++ = 0;
|
|
||||||
memcpy( ip.pB, ansi_dll, ansi_len );
|
memcpy( ip.pB, ansi_dll, ansi_len );
|
||||||
ip.pB += ansi_len;
|
ip.pB += ansi_len;
|
||||||
ip.pI->OriginalFirstThunk = rva + 8;
|
ip.pI->OriginalFirstThunk = 0;
|
||||||
ip.pI->TimeDateStamp = 0;
|
ip.pI->TimeDateStamp = 0;
|
||||||
ip.pI->ForwarderChain = 0;
|
ip.pI->ForwarderChain = 0;
|
||||||
ip.pI->Name = rva + 16;
|
ip.pI->Name = rva + 8;
|
||||||
ip.pI->FirstThunk = rva;
|
ip.pI->FirstThunk = rva;
|
||||||
ReadProcMem( pBase + NTHeader.IMPORTDIR.VirtualAddress,
|
ReadProcMem( pBase+NTHeader.IMPORTDIR.VirtualAddress, ip.pI+1, import_size );
|
||||||
ip.pI + 1, NTHeader.IMPORTDIR.Size );
|
|
||||||
WriteProcMem( pMem, pImports, len );
|
WriteProcMem( pMem, pImports, len );
|
||||||
free( pImports );
|
HeapFree( hHeap, 0, pImports );
|
||||||
|
|
||||||
if (NTHeader.IATDIR.VirtualAddress == 0)
|
if (NTHeader.DATADIRS > IMAGE_DIRECTORY_ENTRY_IAT &&
|
||||||
|
NTHeader.IATDIR.VirtualAddress == 0)
|
||||||
NTHeader.IATDIR = NTHeader.IMPORTDIR;
|
NTHeader.IATDIR = NTHeader.IMPORTDIR;
|
||||||
NTHeader.IMPORTDIR.VirtualAddress = rva + 16 + ansi_len;
|
NTHeader.IMPORTDIR.VirtualAddress = rva + 8 + ansi_len;
|
||||||
NTHeader.IMPORTDIR.Size += sizeof(*pImports);
|
//NTHeader.IMPORTDIR.Size += sizeof(*pImports);
|
||||||
|
if (NTHeader.DATADIRS > IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT)
|
||||||
|
{
|
||||||
NTHeader.BOUNDDIR.VirtualAddress = 0;
|
NTHeader.BOUNDDIR.VirtualAddress = 0;
|
||||||
NTHeader.BOUNDDIR.Size = 0;
|
//NTHeader.BOUNDDIR.Size = 0;
|
||||||
|
}
|
||||||
VirtProtVar( pNTHeader, PAGE_READWRITE );
|
VirtProtVar( pNTHeader, PAGE_READWRITE );
|
||||||
WriteProcVar( pNTHeader, &NTHeader );
|
WriteProcVar( pNTHeader, &NTHeader );
|
||||||
VirtProtVar( pNTHeader, pr );
|
VirtProtVar( pNTHeader, pr );
|
||||||
|
|
||||||
if (NTHeader.COMDIR.VirtualAddress != 0 && NTHeader.COMDIR.Size != 0)
|
if (NTHeader.DATADIRS > IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR &&
|
||||||
|
NTHeader.COMDIR.VirtualAddress != 0)
|
||||||
{
|
{
|
||||||
pComHeader = (PIMAGE_COR20_HEADER)(pBase + NTHeader.COMDIR.VirtualAddress);
|
pComHeader = (PIMAGE_COR20_HEADER)(pBase + NTHeader.COMDIR.VirtualAddress);
|
||||||
ReadProcVar( pComHeader, &ComHeader );
|
ReadProcVar( pComHeader, &ComHeader );
|
||||||
@ -233,7 +263,7 @@ static PBYTE get_ntdll( LPPROCESS_INFORMATION ppi )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUGSTR( 1, L" Failed to find ntdll.dll!" );
|
DEBUGSTR( 1, " Failed to find ntdll.dll!" );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -266,7 +296,7 @@ void InjectDLL64( LPPROCESS_INFORMATION ppi )
|
|||||||
PAGE_EXECUTE_READ );
|
PAGE_EXECUTE_READ );
|
||||||
if (pMem == NULL)
|
if (pMem == NULL)
|
||||||
{
|
{
|
||||||
DEBUGSTR( 1, L" Failed to allocate virtual memory (%lu)", GetLastError() );
|
DEBUGSTR(1, " Failed to allocate virtual memory (%u)", GetLastError());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,10 +43,10 @@ DWORD GetProcRVA( LPCTSTR module, LPCSTR func )
|
|||||||
if (hMod == NULL)
|
if (hMod == NULL)
|
||||||
{
|
{
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
DEBUGSTR( 1, L"Unable to load %d-bit %s (%lu)!",
|
DEBUGSTR( 1, "Unable to load %u-bit %S (%u)!",
|
||||||
bits, module, GetLastError() );
|
bits, module, GetLastError() );
|
||||||
#else
|
#else
|
||||||
DEBUGSTR( 1, L"Unable to load %s (%lu)!", module, GetLastError() );
|
DEBUGSTR( 1, "Unable to load %S (%u)!", module, GetLastError() );
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -70,9 +70,9 @@ DWORD GetProcRVA( LPCTSTR module, LPCSTR func )
|
|||||||
if (pFunc == NULL)
|
if (pFunc == NULL)
|
||||||
{
|
{
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
DEBUGSTR( 1, L"Could not find %d-bit %s!", bits, func );
|
DEBUGSTR( 1, "Could not find %u-bit %s!", bits, func );
|
||||||
#else
|
#else
|
||||||
DEBUGSTR( 1, L"Could not find %s!", func );
|
DEBUGSTR( 1, "Could not find %s!", func );
|
||||||
#endif
|
#endif
|
||||||
rva = 0;
|
rva = 0;
|
||||||
}
|
}
|
||||||
|
42
proctype.c
42
proctype.c
@ -76,8 +76,8 @@ int ProcessType( LPPROCESS_INFORMATION ppi, PBYTE* pBase, BOOL* gui )
|
|||||||
if (nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_I386)
|
if (nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_I386)
|
||||||
{
|
{
|
||||||
PIMAGE_NT_HEADERS32 pNTHeader = (PIMAGE_NT_HEADERS32)&nt_header;
|
PIMAGE_NT_HEADERS32 pNTHeader = (PIMAGE_NT_HEADERS32)&nt_header;
|
||||||
if (pNTHeader->COMDIR.VirtualAddress != 0 &&
|
if (pNTHeader->DATADIRS > IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR &&
|
||||||
pNTHeader->COMDIR.Size != 0)
|
pNTHeader->COMDIR.VirtualAddress != 0)
|
||||||
{
|
{
|
||||||
IMAGE_COR20_HEADER ComHeader, *pComHeader;
|
IMAGE_COR20_HEADER ComHeader, *pComHeader;
|
||||||
pComHeader = (PIMAGE_COR20_HEADER)((PBYTE)minfo.BaseAddress
|
pComHeader = (PIMAGE_COR20_HEADER)((PBYTE)minfo.BaseAddress
|
||||||
@ -87,56 +87,50 @@ int ProcessType( LPPROCESS_INFORMATION ppi, PBYTE* pBase, BOOL* gui )
|
|||||||
!(ComHeader.Flags & COMIMAGE_FLAGS_32BITREQUIRED))
|
!(ComHeader.Flags & COMIMAGE_FLAGS_32BITREQUIRED))
|
||||||
{
|
{
|
||||||
#if defined(_WIN64) || !defined(W32ON64) // W32ON64 will log due to -P
|
#if defined(_WIN64) || !defined(W32ON64) // W32ON64 will log due to -P
|
||||||
DEBUGSTR( 1, L" AnyCPU %s (base = %.8X)",
|
DEBUGSTR( 1, " AnyCPU %s (base = %q)",
|
||||||
(*gui) ? L"GUI" : L"console",
|
(*gui) ? "GUI" : "console", minfo.BaseAddress );
|
||||||
PtrToUint( minfo.BaseAddress ) );
|
|
||||||
#endif
|
#endif
|
||||||
#if defined(_WIN64) || defined(W32ON64)
|
#if defined(_WIN64) || defined(W32ON64)
|
||||||
return 48;
|
return 48;
|
||||||
#else
|
#else
|
||||||
if (ProcessIs64( ppi->hProcess ))
|
if (ProcessIs64( ppi->hProcess ))
|
||||||
{
|
{
|
||||||
DEBUGSTR( 1, L" Unsupported (use x64\\ansicon)" );
|
DEBUGSTR( 1, " Unsupported (use x64\\ansicon)" );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return 32;
|
return 32;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DEBUGSTR( 1, L" 32-bit %s (base = %.8X)",
|
DEBUGSTR( 1, " 32-bit %s (base = %q)",
|
||||||
(*gui) ? L"GUI" : L"console",
|
(*gui) ? "GUI" : "console", minfo.BaseAddress );
|
||||||
PtrToUint( minfo.BaseAddress ) );
|
|
||||||
return 32;
|
return 32;
|
||||||
}
|
}
|
||||||
if (nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64)
|
if (nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64)
|
||||||
{
|
{
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
DEBUGSTR( 1, L" 64-bit %s (base = %.8X_%.8X)",
|
DEBUGSTR( 1, " 64-bit %s (base = %p)",
|
||||||
(*gui) ? L"GUI" : L"console",
|
(*gui) ? "GUI" : "console", minfo.BaseAddress );
|
||||||
(DWORD)((DWORD_PTR)minfo.BaseAddress >> 32),
|
|
||||||
PtrToUint( minfo.BaseAddress ) );
|
|
||||||
return 64;
|
return 64;
|
||||||
#elif defined(W32ON64)
|
#elif defined(W32ON64)
|
||||||
// Console will log due to -P, but GUI may be ignored (if not,
|
// Console will log due to -P, but GUI may be ignored (if not,
|
||||||
// this'll show up twice).
|
// this'll show up twice).
|
||||||
if (*gui)
|
if (*gui)
|
||||||
DEBUGSTR( 1, L" 64-bit GUI (base = 00000000_%.8X)",
|
DEBUGSTR( 1, " 64-bit GUI (base = %P)", minfo.BaseAddress );
|
||||||
PtrToUint( minfo.BaseAddress ) );
|
|
||||||
return 64;
|
return 64;
|
||||||
#else
|
#else
|
||||||
DEBUGSTR( 1, L" 64-bit %s (base = 00000000_%.8X)",
|
DEBUGSTR( 1, " 64-bit %s (base = %P)",
|
||||||
(*gui) ? L"GUI" : L"console",
|
(*gui) ? "GUI" : "console", minfo.BaseAddress );
|
||||||
PtrToUint( minfo.BaseAddress ) );
|
DEBUGSTR( 1, " Unsupported (use x64\\ansicon)" );
|
||||||
DEBUGSTR( 1, L" Unsupported (use x64\\ansicon)" );
|
|
||||||
return 0;
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
DEBUGSTR( 1, L" Ignoring unsupported machine (0x%X)",
|
DEBUGSTR( 1, " Ignoring unsupported machine (0x%X)",
|
||||||
nt_header.FileHeader.Machine );
|
nt_header.FileHeader.Machine );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DEBUGSTR( 1, L" Ignoring unsupported subsystem (%u)",
|
DEBUGSTR( 1, " Ignoring unsupported subsystem (%u)",
|
||||||
nt_header.OptionalHeader.Subsystem );
|
nt_header.OptionalHeader.Subsystem );
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@ -147,16 +141,16 @@ int ProcessType( LPPROCESS_INFORMATION ppi, PBYTE* pBase, BOOL* gui )
|
|||||||
if (((DWORD)ptr >> 12) + ((DWORD)minfo.RegionSize >> 12) >= 0x100000)
|
if (((DWORD)ptr >> 12) + ((DWORD)minfo.RegionSize >> 12) >= 0x100000)
|
||||||
{
|
{
|
||||||
#ifdef W32ON64
|
#ifdef W32ON64
|
||||||
DEBUGSTR( 1, L" Pointer overflow: assuming 64-bit" );
|
DEBUGSTR( 1, " Pointer overflow: assuming 64-bit" );
|
||||||
return 64;
|
return 64;
|
||||||
#else
|
#else
|
||||||
DEBUGSTR( 1, L" Ignoring apparent 64-bit process (use x64\\ansicon)" );
|
DEBUGSTR( 1, " Ignoring apparent 64-bit process (use x64\\ansicon)" );
|
||||||
return 0;
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUGSTR( 1, L" Ignoring non-Windows process" );
|
DEBUGSTR( 1, " Ignoring non-Windows process" );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
58
readme.md
58
readme.md
@ -5,8 +5,8 @@ provides much the same functionality as `ANSI.SYS` does for MS-DOS.
|
|||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
* 32-bit: Windows 2000 Professional or later (it won't work with NT or 9X).
|
* 32-bit: Windows 2000 Professional and later (it won't work with NT or 9X).
|
||||||
* 64-bit: Vista or later (it won't work with XP64).
|
* 64-bit: AMD64 (it won't work with IA64).
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
@ -111,15 +111,17 @@ Using `ansicon` after install will always start with the default attributes,
|
|||||||
restoring the originals on exit; all other programs will use the current
|
restoring the originals on exit; all other programs will use the current
|
||||||
attributes. The shift state is always reset for a new process.
|
attributes. The shift state is always reset for a new process.
|
||||||
|
|
||||||
The Windows API `WriteFile` and `WriteConsoleA` functions will set the number of
|
My version of `WriteConsoleA` will always set the number of characters written,
|
||||||
characters written, not the number of bytes. When using a multibyte character
|
not the number of bytes. This means writing a double-byte character as two
|
||||||
set, this results in a smaller number (since multiple bytes are used to
|
bytes will set 0 the first write (nothing was written) and 1 the second (when
|
||||||
represent a single character). Some programs recognise this as a reduced write
|
the character was actually written); Windows normally sets 1 for both writes.
|
||||||
and will inadvertently repeat previous characters. If you discover such a
|
Similarly, writing the individual bytes of a multibyte character will set 0 for
|
||||||
program, use the `ANSICON_API` environment variable to record it and override
|
all but the last byte, then 1 on the last; Windows normally sets 1 for each
|
||||||
the API, returning the original byte count. Ruby (prior to 1.9.3) is an example
|
byte, writing the undefined character. However, my `WriteFile` (and
|
||||||
of such a program, so use `set ANSICON_API=ruby` to avoid the repitition. The
|
`_lwrite`/`_hwrite`) will always set what was received; Windows, using a
|
||||||
full syntax is:
|
multibyte character set (but not DBCS), would set the characters. You can have
|
||||||
|
`WriteConsoleA` return the original byte count by using the `ANSICON_API`
|
||||||
|
environment variable:
|
||||||
|
|
||||||
ANSICON_API=[!]program;program;program...
|
ANSICON_API=[!]program;program;program...
|
||||||
|
|
||||||
@ -127,14 +129,16 @@ 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
|
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
|
the program is in the list. The variable can be made permanent by going to
|
||||||
_System Properties_, selecting the _Advanced_ tab (with Vista onwards, this can
|
_System Properties_, selecting the _Advanced_ tab (with Vista onwards, this can
|
||||||
be done by running _"SystemPropertiesAdvanced"_) and clicking _Environment
|
be done by running `SystemPropertiesAdvanced`) and clicking _Environment
|
||||||
Variables_.
|
Variables_.
|
||||||
|
|
||||||
|
|
||||||
## Limitations
|
## Limitations
|
||||||
|
|
||||||
- The entire console buffer is used, not just the visible window.
|
- Line sequences use the window; column sequences use the buffer.
|
||||||
- There's a conflict with NVIDIA's drivers, requiring the setting of the
|
- An application using multiple screen buffers will not have separate
|
||||||
|
attributes in each buffer.
|
||||||
|
- There may be a conflict with NVIDIA's drivers, requiring the setting of the
|
||||||
Environment Variable:
|
Environment Variable:
|
||||||
|
|
||||||
ANSICON_EXC=nvd3d9wrap.dll;nvd3d9wrapx.dll
|
ANSICON_EXC=nvd3d9wrap.dll;nvd3d9wrapx.dll
|
||||||
@ -146,19 +150,26 @@ Variables_.
|
|||||||
|
|
||||||
The following escape sequences are recognised.
|
The following escape sequences are recognised.
|
||||||
|
|
||||||
\e]0;titleBEL Set (xterm) window's title (and icon)
|
\e]0;titleBEL xterm: Set window's title (and icon, ignored)
|
||||||
\e[21t Report (xterm) window's title
|
\e]2;titleBEL xterm: Set window's title
|
||||||
\e[s Save Cursor
|
\e[21t xterm: Report window's title
|
||||||
\e[u Restore Cursor
|
\e[s ANSI.SYS: Save Cursor Position
|
||||||
|
\e[u ANSI.SYS: Restore Cursor Position
|
||||||
|
\e[#Z CBT Cursor Backward Tabulation
|
||||||
\e[#G CHA Cursor Character Absolute
|
\e[#G CHA Cursor Character Absolute
|
||||||
|
\e[#I CHT Cursor Forward Tabulation
|
||||||
\e[#E CNL Cursor Next Line
|
\e[#E CNL Cursor Next Line
|
||||||
\e[#F CPL Cursor Preceding Line
|
\e[#F CPL Cursor Preceding Line
|
||||||
|
\e[3h CRM Control Representation Mode (display controls)
|
||||||
|
\e[3l CRM Control Representation Mode (perform controls)
|
||||||
\e[#D CUB Cursor Left
|
\e[#D CUB Cursor Left
|
||||||
\e[#B CUD Cursor Down
|
\e[#B CUD Cursor Down
|
||||||
\e[#C CUF Cursor Right
|
\e[#C CUF Cursor Right
|
||||||
\e[#;#H CUP Cursor Position
|
\e[#;#H CUP Cursor Position
|
||||||
\e[#A CUU Cursor Up
|
\e[#A CUU Cursor Up
|
||||||
\e[#P DCH Delete Character
|
\e[#P DCH Delete Character
|
||||||
|
\e[?7h DECAWM DEC Autowrap Mode (autowrap)
|
||||||
|
\e[?7l DECAWM DEC Autowrap Mode (no autowrap)
|
||||||
\e[?25h DECTCEM DEC Text Cursor Enable Mode (show cursor)
|
\e[?25h DECTCEM DEC Text Cursor Enable Mode (show cursor)
|
||||||
\e[?25l DECTCEM DEC Text Cursor Enable Mode (hide cursor)
|
\e[?25l DECTCEM DEC Text Cursor Enable Mode (hide cursor)
|
||||||
\e[#M DL Delete Line
|
\e[#M DL Delete Line
|
||||||
@ -174,6 +185,7 @@ The following escape sequences are recognised.
|
|||||||
\e[#L IL Insert Line
|
\e[#L IL Insert Line
|
||||||
SI LS0 Locking-shift Zero (see below)
|
SI LS0 Locking-shift Zero (see below)
|
||||||
SO LS1 Locking-shift One
|
SO LS1 Locking-shift One
|
||||||
|
\e[#b REP Repeat
|
||||||
\e[#;#;#m SGR Select Graphic Rendition
|
\e[#;#;#m SGR Select Graphic Rendition
|
||||||
\e[#d VPA Line Position Absolute
|
\e[#d VPA Line Position Absolute
|
||||||
\e[#k VPB Line Position Backward
|
\e[#k VPB Line Position Backward
|
||||||
@ -193,6 +205,12 @@ the latter will explicitly reset them. The environment variable `ANSICON_DEF`
|
|||||||
can be used to change the default colors (same value as `-m`; setting the
|
can be used to change the default colors (same value as `-m`; setting the
|
||||||
variable does not change the current colors).
|
variable does not change the current colors).
|
||||||
|
|
||||||
|
The first time a program clears the screen (`\e[2J`) will actually scroll in a
|
||||||
|
new window (assuming the buffer is bigger than the window, of course).
|
||||||
|
Subsequent clears will then blank the window. However, if the window has
|
||||||
|
scrolled, or the cursor is on the last line of the buffer, it will again scroll
|
||||||
|
in a new window.
|
||||||
|
|
||||||
|
|
||||||
### Ignored Sequences
|
### Ignored Sequences
|
||||||
|
|
||||||
@ -214,7 +232,7 @@ http://vt100.net/docs/vt220-rm/table2-4.html.
|
|||||||
|
|
||||||
Char Unicode Code Point & Name
|
Char Unicode Code Point & Name
|
||||||
---- -------------------------
|
---- -------------------------
|
||||||
_ U+0020 Space (blank)
|
_ U+00A0 No-Break Space (blank)
|
||||||
` U+2666 Black Diamond Suit
|
` U+2666 Black Diamond Suit
|
||||||
a U+2592 Medium Shade
|
a U+2592 Medium Shade
|
||||||
b U+2409 Symbol For Horizontal Tabulation
|
b U+2409 Symbol For Horizontal Tabulation
|
||||||
@ -299,4 +317,4 @@ In particular, the supplied binaries are freely redistributable.
|
|||||||
A formal license (zlib) is available in `LICENSE.txt`.
|
A formal license (zlib) is available in `LICENSE.txt`.
|
||||||
|
|
||||||
---
|
---
|
||||||
Copyright 2005-2014 Jason Hood
|
Copyright 2005-2015 Jason Hood
|
||||||
|
53
readme.txt
53
readme.txt
@ -1,9 +1,9 @@
|
|||||||
|
|
||||||
ANSICON
|
ANSICON
|
||||||
|
|
||||||
Copyright 2005-2014 Jason Hood
|
Copyright 2005-2015 Jason Hood
|
||||||
|
|
||||||
Version 1.71. Freeware
|
Version 1.72. Freeware
|
||||||
|
|
||||||
|
|
||||||
Description
|
Description
|
||||||
@ -110,9 +110,10 @@ Usage
|
|||||||
The variable is updated whenever a program reads it directly (i.e. as an
|
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
|
individual request, not as part of the entire environment block). For
|
||||||
example, 'set an' will not update it, but 'echo %ansicon%' will. Also
|
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
|
created are ANSICON_VER, which contains the version without the point (1.50
|
||||||
becomes "150"). This variable does not exist as part of the environment
|
becomes "150"), and CLICOLOR (see http://bixense.com/clicolors/), which
|
||||||
block ('set an' will not show it).
|
contains "1". These variables do not exist as part of the environment
|
||||||
|
block (e.g. 'set an' will not show ANSICON_VER).
|
||||||
|
|
||||||
If installed, GUI programs will not be hooked. Either start the program
|
If installed, GUI programs will not be hooked. Either start the program
|
||||||
directly with 'ansicon', or add it to the ANSICON_GUI variable (see
|
directly with 'ansicon', or add it to the ANSICON_GUI variable (see
|
||||||
@ -122,15 +123,17 @@ Usage
|
|||||||
utes, restoring the originals on exit; all other programs will use the cur-
|
utes, restoring the originals on exit; all other programs will use the cur-
|
||||||
rent attributes. The shift state is always reset for a new process.
|
rent attributes. The shift state is always reset for a new process.
|
||||||
|
|
||||||
The Windows API WriteFile and WriteConsoleA functions will set the number
|
My version of WriteConsoleA will always set the number of characters writt-
|
||||||
of characters written, not the number of bytes. When using a multibyte
|
en, not the number of bytes. This means writing a double-byte character as
|
||||||
character set, this results in a smaller number (since multiple bytes are
|
two bytes will set 0 the first write (nothing was written) and 1 the second
|
||||||
used to represent a single character). Some programs recognise this as a
|
(when the character was actually written); Windows normally sets 1 for both
|
||||||
reduced write and will inadvertently repeat previous characters. If you
|
writes. Similarly, writing the individual bytes of a multibyte character
|
||||||
discover such a program, use the ANSICON_API environment variable to record
|
will set 0 for all but the last byte, then 1 on the last; Windows normally
|
||||||
it and override the API, returning the original byte count. Ruby (prior to
|
sets 1 for each byte, writing the undefined character. However, my
|
||||||
1.9.3) is an example of such a program, so use 'set ANSICON_API=ruby' to
|
WriteFile (and _lwrite/_hwrite) will always set what was received; Windows,
|
||||||
avoid the repitition. The full syntax is:
|
using a multibyte character set (but not DBCS), would set the characters.
|
||||||
|
You can have WriteConsoleA return the original byte count by using the
|
||||||
|
ANSICON_API environment variable:
|
||||||
|
|
||||||
ANSICON_API=[!]program;program;program...
|
ANSICON_API=[!]program;program;program...
|
||||||
|
|
||||||
@ -277,7 +280,7 @@ Limitations
|
|||||||
Line sequences use the window; column sequences use the buffer.
|
Line sequences use the window; column sequences use the buffer.
|
||||||
Tabs are fixed at eight columns.
|
Tabs are fixed at eight columns.
|
||||||
|
|
||||||
There's a conflict with NVIDIA's drivers, requiring the setting of the
|
There may be a conflict with NVIDIA's drivers, requiring the setting of the
|
||||||
Environment Variable:
|
Environment Variable:
|
||||||
|
|
||||||
ANSICON_EXC=nvd3d9wrap.dll;nvd3d9wrapx.dll
|
ANSICON_EXC=nvd3d9wrap.dll;nvd3d9wrapx.dll
|
||||||
@ -291,8 +294,24 @@ Version History
|
|||||||
|
|
||||||
Legend: + added, - bug-fixed, * changed.
|
Legend: + added, - bug-fixed, * changed.
|
||||||
|
|
||||||
|
1.72 - 24 December, 2015:
|
||||||
|
- handle STD_OUTPUT_HANDLE & STD_ERROR_HANDLE in WriteFile;
|
||||||
|
- better handling of unusual PE files;
|
||||||
|
* cache GetConsoleMode for an improvement in speed;
|
||||||
|
* files writing to the console always succeed (should mostly remove the
|
||||||
|
need for ANSICON_API);
|
||||||
|
* log: add a blank line between processes;
|
||||||
|
remove the separate line for WriteFile & _lwrite;
|
||||||
|
write byte strings as-is, wide strings using the current code page;
|
||||||
|
use caret notation for control characters, with hexadecimal "^xNN"
|
||||||
|
and "^uNNNN" for characters not in the code page (custom printf);
|
||||||
|
* join multibyte characters split across separate writes;
|
||||||
|
* remove wcstok, avoiding potential interference with the host program;
|
||||||
|
* similarly, remove malloc & friends, using a private heap;
|
||||||
|
+ add CLICOLOR dynamic environment variable.
|
||||||
|
|
||||||
1.71 - 23 October, 2015:
|
1.71 - 23 October, 2015:
|
||||||
+ add _CRT_NON_CONFORMING_WCSTOK define
|
+ add _CRT_NON_CONFORMING_WCSTOK define for VS2015.
|
||||||
|
|
||||||
1.70 - 26 February, 2014:
|
1.70 - 26 February, 2014:
|
||||||
- don't hook again if using LoadLibrary or LoadLibraryEx;
|
- don't hook again if using LoadLibrary or LoadLibraryEx;
|
||||||
@ -501,4 +520,4 @@ Distribution
|
|||||||
|
|
||||||
|
|
||||||
==============================
|
==============================
|
||||||
Jason Hood, 26 February, 2014.
|
Jason Hood, 24 December, 2015.
|
||||||
|
357
util.c
357
util.c
@ -74,99 +74,316 @@ void set_ansi_dll( void )
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DEBUGSTR( int level, LPTSTR szFormat, ... )
|
static LPSTR buf;
|
||||||
{
|
static DWORD buf_len;
|
||||||
static char tempfile[MAX_PATH];
|
static BOOL quote, alt;
|
||||||
static DWORD pid;
|
|
||||||
|
|
||||||
TCHAR szBuffer[1024], szEscape[1024];
|
static DWORD str_format( DWORD pos, BOOL wide, DWORD_PTR str, DWORD len )
|
||||||
va_list pArgList;
|
{
|
||||||
HANDLE mutex;
|
static UINT cp;
|
||||||
DWORD wait;
|
static DWORD flags;
|
||||||
FILE* file;
|
static BOOL def, *pDef, start_trail;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
LPSTR a;
|
||||||
|
LPWSTR w;
|
||||||
|
} src;
|
||||||
|
int ch;
|
||||||
|
BOOL trail;
|
||||||
|
|
||||||
if ((log_level & 3) < level && !(level & 4 & log_level))
|
src.a = (LPSTR)str;
|
||||||
return;
|
if (len == 0 && str != 0)
|
||||||
|
len = (DWORD)(wide ? wcslen( src.w ) : strlen( src.a ));
|
||||||
|
|
||||||
if (*tempfile == '\0')
|
if (pos + len * 6 + 8 >= buf_len)
|
||||||
{
|
{
|
||||||
_snprintf( tempfile, MAX_PATH, "%s\\ansicon.log", getenv( "TEMP" ) );
|
LPVOID tmp = HeapReAlloc( hHeap, 0, buf, buf_len + len * 6 + 8 );
|
||||||
pid = GetCurrentProcessId();
|
if (tmp == NULL)
|
||||||
}
|
return 0;
|
||||||
if (szFormat == NULL)
|
buf = tmp;
|
||||||
{
|
buf_len = (DWORD)HeapSize( hHeap, 0, buf );
|
||||||
// Explicitly use 't', as _fmode might be binary.
|
|
||||||
file = fopen( tempfile, (log_level & 8) ? "at" : "wt" );
|
|
||||||
if (file != NULL)
|
|
||||||
{
|
|
||||||
SYSTEMTIME now;
|
|
||||||
GetLocalTime( &now );
|
|
||||||
fseek( file, 0, SEEK_END );
|
|
||||||
if (ftell( file ) != 0)
|
|
||||||
putc( '\n', file );
|
|
||||||
fprintf( file, "ANSICON (" BITSA "-bit) 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 );
|
if (len == 0)
|
||||||
_vsnwprintf( szBuffer, lenof(szBuffer), szFormat, pArgList );
|
{
|
||||||
va_end( pArgList );
|
if (str == 0)
|
||||||
|
pos += wsprintfA( buf + pos, "<null>" );
|
||||||
|
else if (quote)
|
||||||
|
{
|
||||||
|
buf[pos++] = '"';
|
||||||
|
buf[pos++] = '"';
|
||||||
|
}
|
||||||
|
else if (alt)
|
||||||
|
pos += wsprintfA( buf + pos, "<empty>" );
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
szFormat = szBuffer;
|
if (cp != GetConsoleOutputCP())
|
||||||
if (*szFormat == '\33')
|
|
||||||
{
|
{
|
||||||
BOOL first = TRUE;
|
cp = GetConsoleOutputCP();
|
||||||
LPTSTR pos = szEscape;
|
if (wide)
|
||||||
while (*++szFormat != '\0' && pos < szEscape + lenof(szEscape) - 4)
|
|
||||||
{
|
{
|
||||||
if (*szFormat < 32)
|
wchar_t und = L'\xFFFF';
|
||||||
|
flags = WC_NO_BEST_FIT_CHARS;
|
||||||
|
pDef = &def;
|
||||||
|
// Some code pages don't support the default character.
|
||||||
|
if (!WideCharToMultiByte( cp, flags, &und, 1, buf + pos, 12, NULL, pDef ))
|
||||||
{
|
{
|
||||||
*pos++ = '\\';
|
flags = 0;
|
||||||
switch (*szFormat)
|
pDef = NULL;
|
||||||
|
def = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (quote)
|
||||||
|
buf[pos++] = '"';
|
||||||
|
|
||||||
|
trail = FALSE;
|
||||||
|
while (len-- != 0)
|
||||||
{
|
{
|
||||||
case '\a': *pos++ = 'a'; break;
|
if (wide)
|
||||||
case '\b': *pos++ = 'b'; break;
|
ch = *src.w++;
|
||||||
case '\t': *pos++ = 't'; break;
|
else
|
||||||
case '\r': *pos++ = 'r'; break;
|
ch = (BYTE)*src.a++;
|
||||||
case '\n': *pos++ = 'n'; break;
|
|
||||||
case 27 : *pos++ = 'e'; break;
|
if (ch < 32 || (quote && start_trail))
|
||||||
|
{
|
||||||
|
start_trail = FALSE;
|
||||||
|
if (quote)
|
||||||
|
{
|
||||||
|
buf[pos++] = '\\';
|
||||||
|
switch (ch)
|
||||||
|
{
|
||||||
|
case '\0': buf[pos++] = '0'; break;
|
||||||
|
case '\a': buf[pos++] = 'a'; break;
|
||||||
|
case '\b': buf[pos++] = 'b'; break;
|
||||||
|
case '\t': buf[pos++] = 't'; break;
|
||||||
|
case '\n': buf[pos++] = 'n'; break;
|
||||||
|
case '\v': buf[pos++] = 'v'; break;
|
||||||
|
case '\f': buf[pos++] = 'f'; break;
|
||||||
|
case '\r': buf[pos++] = 'r'; break;
|
||||||
|
case 27 : buf[pos++] = 'e'; break;
|
||||||
default:
|
default:
|
||||||
pos += _snwprintf( pos, 32, L"%.*o",
|
pos += wsprintfA( buf + pos, "x%.2X", ch );
|
||||||
(szFormat[1] >= '0' && szFormat[1] <= '7') ? 3 : 1,
|
|
||||||
*szFormat );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (*szFormat == '"')
|
buf[pos++] = '^';
|
||||||
|
buf[pos++] = ch + '@';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (quote && ch == '"')
|
||||||
{
|
{
|
||||||
if (first)
|
buf[pos++] = '\\';
|
||||||
first = FALSE;
|
buf[pos++] = ch;
|
||||||
else if (szFormat[1] != '\0')
|
|
||||||
*pos++ = '\\';
|
|
||||||
}
|
}
|
||||||
*pos++ = *szFormat;
|
else if (!wide)
|
||||||
|
{
|
||||||
|
if (quote && (cp == 932 || cp == 936 || cp == 949 || cp == 950))
|
||||||
|
{
|
||||||
|
if (trail)
|
||||||
|
trail = FALSE;
|
||||||
|
else if (IsDBCSLeadByteEx( cp, (char)ch ))
|
||||||
|
{
|
||||||
|
if (len == 0)
|
||||||
|
start_trail = TRUE;
|
||||||
|
else
|
||||||
|
trail = TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*pos = '\0';
|
if (quote && start_trail)
|
||||||
szFormat = szEscape;
|
pos += wsprintfA( buf + pos, "\\x%.2X", ch );
|
||||||
|
else
|
||||||
|
buf[pos++] = ch;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int mb = WideCharToMultiByte( cp, flags, src.w - 1, 1, buf + pos, 12,
|
||||||
|
NULL, pDef );
|
||||||
|
if (def)
|
||||||
|
mb = wsprintfA( buf + pos, ch < 0x100 ? "%cx%.2X" : "%cu%.4X",
|
||||||
|
(quote) ? '\\' : '^', ch );
|
||||||
|
pos += mb;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex = CreateMutex( NULL, FALSE, L"ANSICON_debug_file" );
|
if (quote)
|
||||||
wait = WaitForSingleObject( mutex, 500 );
|
buf[pos++] = '"';
|
||||||
file = fopen( tempfile, "at" );
|
|
||||||
if (file != NULL)
|
return pos;
|
||||||
{
|
|
||||||
fwprintf( file, L"%s (%lu): %s\n", prog, pid, szFormat );
|
|
||||||
fclose( file );
|
|
||||||
}
|
}
|
||||||
if (wait == WAIT_OBJECT_0)
|
|
||||||
|
void DEBUGSTR( int level, LPCSTR szFormat, ... )
|
||||||
|
{
|
||||||
|
static int prefix_len;
|
||||||
|
static HANDLE mutex;
|
||||||
|
static DWORD size;
|
||||||
|
|
||||||
|
WCHAR temp[MAX_PATH];
|
||||||
|
HANDLE file;
|
||||||
|
va_list pArgList;
|
||||||
|
DWORD len, slen, written;
|
||||||
|
DWORD_PTR num;
|
||||||
|
|
||||||
|
if ((log_level & 3) < level && !(level & 4 & log_level))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (mutex == NULL)
|
||||||
|
{
|
||||||
|
mutex = CreateMutex( NULL, FALSE, L"ANSICON_debug_file" );
|
||||||
|
if (mutex == NULL)
|
||||||
|
{
|
||||||
|
file = INVALID_HANDLE_VALUE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
buf = HeapAlloc( hHeap, 0, 2048 );
|
||||||
|
buf_len = (DWORD)HeapSize( hHeap, 0, buf );
|
||||||
|
prefix_len = wsprintfA( buf, "%S (%lu): ", prog, GetCurrentProcessId() );
|
||||||
|
}
|
||||||
|
if (WaitForSingleObject( mutex, 500 ) == WAIT_TIMEOUT)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ExpandEnvironmentStrings( L"%TEMP%\\ansicon.log", temp, lenof(temp) );
|
||||||
|
file = CreateFile( temp, GENERIC_WRITE, FILE_SHARE_READ, NULL,
|
||||||
|
(szFormat != NULL || (log_level & 8)) ? OPEN_ALWAYS
|
||||||
|
: CREATE_ALWAYS,
|
||||||
|
0, NULL );
|
||||||
|
if (file == INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
ReleaseMutex( mutex );
|
ReleaseMutex( mutex );
|
||||||
CloseHandle( mutex );
|
CloseHandle( mutex );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = SetFilePointer( file, 0, NULL, FILE_END );
|
||||||
|
if (len == 0 || szFormat == NULL)
|
||||||
|
{
|
||||||
|
char buf[128];
|
||||||
|
SYSTEMTIME now;
|
||||||
|
|
||||||
|
size = 0;
|
||||||
|
|
||||||
|
if (len != 0)
|
||||||
|
{
|
||||||
|
memset( buf + 2, '=', 72 );
|
||||||
|
buf[0] = buf[74] = buf[76] = '\r';
|
||||||
|
buf[1] = buf[75] = buf[77] = '\n';
|
||||||
|
WriteFile( file, buf, 78, &written, NULL );
|
||||||
|
}
|
||||||
|
|
||||||
|
GetLocalTime( &now );
|
||||||
|
len = wsprintfA( buf, "ANSICON (" BITSA "-bit) v" PVERSA " log (%d)"
|
||||||
|
" started %d-%.2d-%.2d %d:%.2d:%.2d\r\n",
|
||||||
|
log_level,
|
||||||
|
now.wYear, now.wMonth, now.wDay,
|
||||||
|
now.wHour, now.wMinute, now.wSecond );
|
||||||
|
WriteFile( file, buf, len, &written, NULL );
|
||||||
|
if (szFormat == NULL)
|
||||||
|
{
|
||||||
|
CloseHandle( file );
|
||||||
|
ReleaseMutex( mutex );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (len != size)
|
||||||
|
WriteFile( file, "\r\n", 2, &written, NULL );
|
||||||
|
|
||||||
|
va_start( pArgList, szFormat );
|
||||||
|
|
||||||
|
// Customized printf, mainly to handle wide-character strings the way I want.
|
||||||
|
// It only supports:
|
||||||
|
// %u unsigned 32-bit decimal
|
||||||
|
// %X unsigned 32-bit upper case hexadecimal
|
||||||
|
// %p native pointer
|
||||||
|
// %q native pointer, display as 32 bits
|
||||||
|
// %P 32-bit pointer, display as 64 bits
|
||||||
|
// %s null-terminated byte characters
|
||||||
|
// %S null-terminated wide characters
|
||||||
|
//
|
||||||
|
// s & S may be prefixed with (in this order):
|
||||||
|
// " quote the string, using C-style escapes and <null> for NULL
|
||||||
|
// # use <null> for NULL and <empty> for ""
|
||||||
|
// < length of the string is the previous %u
|
||||||
|
// * length of the string is the parameter before the string
|
||||||
|
//
|
||||||
|
// Wide strings are converted according to the current code page; if a
|
||||||
|
// character could not be translated, hex is used.
|
||||||
|
//
|
||||||
|
// C-style escapes are the standard backslash sequences, plus '\e' for ESC,
|
||||||
|
// with '\x' used for two hex digits and '\u' for four. Otherwise, caret
|
||||||
|
// notation is used to represent controls, with '^x'/'^u' for hex.
|
||||||
|
|
||||||
|
num = 0;
|
||||||
|
len = prefix_len;
|
||||||
|
while (*szFormat != '\0')
|
||||||
|
{
|
||||||
|
if (*szFormat != '%')
|
||||||
|
buf[len++] = *szFormat++;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
quote = alt = FALSE;
|
||||||
|
++szFormat;
|
||||||
|
if (*szFormat == '"')
|
||||||
|
{
|
||||||
|
quote = TRUE;
|
||||||
|
++szFormat;
|
||||||
|
}
|
||||||
|
if (*szFormat == '#')
|
||||||
|
{
|
||||||
|
alt = TRUE;
|
||||||
|
++szFormat;
|
||||||
|
}
|
||||||
|
slen = 0;
|
||||||
|
if (*szFormat == '<')
|
||||||
|
{
|
||||||
|
slen = (DWORD)num;
|
||||||
|
++szFormat;
|
||||||
|
}
|
||||||
|
if (*szFormat == '*')
|
||||||
|
{
|
||||||
|
slen = va_arg( pArgList, DWORD );
|
||||||
|
++szFormat;
|
||||||
|
}
|
||||||
|
num = va_arg( pArgList, DWORD_PTR );
|
||||||
|
switch (*szFormat++)
|
||||||
|
{
|
||||||
|
case 'u': len += wsprintfA( buf + len, "%u", (DWORD)num ); break;
|
||||||
|
case 'X': len += wsprintfA( buf + len, "%X", (DWORD)num ); break;
|
||||||
|
case 'p':
|
||||||
|
#ifdef _WIN64
|
||||||
|
len += wsprintfA( buf + len, "%.8X_%.8X",
|
||||||
|
(DWORD)(num >> 32), (DWORD)num );
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
case 'q': len += wsprintfA( buf + len, "%.8X", (DWORD)num ); break;
|
||||||
|
case 'P': len += wsprintfA( buf + len, "00000000_%.8X", (DWORD)num ); break;
|
||||||
|
case 's': len = str_format( len, FALSE, num, slen ); break;
|
||||||
|
case 'S': len = str_format( len, TRUE, num, slen ); break;
|
||||||
|
default:
|
||||||
|
buf[len++] = '%';
|
||||||
|
if (szFormat[-1] == '\0')
|
||||||
|
--szFormat;
|
||||||
|
else
|
||||||
|
buf[len++] = szFormat[-1];
|
||||||
|
}
|
||||||
|
if (len >= buf_len - 20)
|
||||||
|
{
|
||||||
|
LPVOID tmp = HeapReAlloc( hHeap, 0, buf, buf_len + 128 );
|
||||||
|
if (tmp == NULL)
|
||||||
|
break;
|
||||||
|
buf = tmp;
|
||||||
|
buf_len = (DWORD)HeapSize( hHeap, 0, buf );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buf[len++] = '\r';
|
||||||
|
buf[len++] = '\n';
|
||||||
|
|
||||||
|
WriteFile( file, buf, len, &written, NULL );
|
||||||
|
|
||||||
|
size = GetFileSize( file, NULL );
|
||||||
|
CloseHandle( file );
|
||||||
|
ReleaseMutex( mutex );
|
||||||
}
|
}
|
||||||
|
10
version.h
10
version.h
@ -2,11 +2,11 @@
|
|||||||
version.h - Version defines.
|
version.h - Version defines.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define PVERS L"1.71" // wide string
|
#define PVERS L"1.72" // wide string
|
||||||
#define PVERSA "1.71" // ANSI string (windres 2.16.91 didn't like L)
|
#define PVERSA "1.72" // ANSI string (windres 2.16.91 didn't like L)
|
||||||
#define PVERE L"171" // wide environment string
|
#define PVERE L"172" // wide environment string
|
||||||
#define PVEREA "171" // ANSI environment string
|
#define PVEREA "172" // ANSI environment string
|
||||||
#define PVERB 1,7,1,0 // binary (resource)
|
#define PVERB 1,7,2,0 // binary (resource)
|
||||||
|
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
# define BITS L"64"
|
# define BITS L"64"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user