Inject by adding to the Import Directory Table.
-p uses CreateRemoteThread, determining kernel32.dll & LLW dynamically. Loading via LoadLibrary will remember the current attributes, restoring them on unload. Tweaked log output (remove quotes around CreateProcess command line; add an underscore to 64-bit addresses). ansicon.exe will really output (to the console) strings as Unicode. Fixed ansicon.exe, if installed, restoring the default attributes, not current. ansicon.exe will start with ANSICON_DEF (if defined and -m not used).
This commit is contained in:
parent
bccf933c0a
commit
dc7569dc26
101
ANSI.c
101
ANSI.c
@ -108,13 +108,15 @@
|
|||||||
v1.65, 28 August, 2013:
|
v1.65, 28 August, 2013:
|
||||||
fix \e[K (was using window, not buffer).
|
fix \e[K (was using window, not buffer).
|
||||||
|
|
||||||
v.166, 20 & 21 September, 2013:
|
v1.66, 20 & 21 September, 2013:
|
||||||
fix 32-bit process trying to detect 64-bit process.
|
fix 32-bit process trying to detect 64-bit process.
|
||||||
|
|
||||||
v1.67, 25 to 27 January, 2014:
|
v1.70, 25 January to 4 February, 2014:
|
||||||
don't hook ourself from LoadLibrary or LoadLibraryEx;
|
don't hook ourself from LoadLibrary or LoadLibraryEx;
|
||||||
update the LoadLibraryEx flags that should not cause hooking;
|
update the LoadLibraryEx flags that should not cause hooking;
|
||||||
always find the base address of kernel32.dll.
|
inject by manipulating the import directory table;
|
||||||
|
restore original attribute on detach (for LoadLibrary/FreeLibrary usage);
|
||||||
|
log: remove the quotes around the CreateProcess command line string.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ansicon.h"
|
#include "ansicon.h"
|
||||||
@ -135,6 +137,7 @@
|
|||||||
// ========== Global variables and constants
|
// ========== Global variables and constants
|
||||||
|
|
||||||
HANDLE hConOut; // handle to CONOUT$
|
HANDLE hConOut; // handle to CONOUT$
|
||||||
|
WORD orgattr; // original attribute
|
||||||
|
|
||||||
#define ESC '\x1B' // ESCape character
|
#define ESC '\x1B' // ESCape character
|
||||||
#define BEL '\x07'
|
#define BEL '\x07'
|
||||||
@ -253,11 +256,6 @@ SHARED DWORD s_flag;
|
|||||||
#define GRM_INIT 1
|
#define GRM_INIT 1
|
||||||
#define GRM_EXIT 2
|
#define GRM_EXIT 2
|
||||||
|
|
||||||
SHARED DWORD LLW32r;
|
|
||||||
#ifdef _WIN64
|
|
||||||
SHARED DWORD LLW64r;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
// Wait for the child process to finish, then update our GRM to the child's.
|
// Wait for the child process to finish, then update our GRM to the child's.
|
||||||
DWORD WINAPI UpdateGRM( LPVOID child_pi )
|
DWORD WINAPI UpdateGRM( LPVOID child_pi )
|
||||||
@ -470,6 +468,7 @@ void InterpretEscSeq( void )
|
|||||||
case 7: grm.rvideo = 1; break;
|
case 7: grm.rvideo = 1; break;
|
||||||
case 8: grm.concealed = 1; break;
|
case 8: grm.concealed = 1; break;
|
||||||
case 21: // oops, this actually turns on double underline
|
case 21: // oops, this actually turns on double underline
|
||||||
|
// but xterm turns off bold too, so that's alright
|
||||||
case 22: grm.bold = 0; break;
|
case 22: grm.bold = 0; break;
|
||||||
case 25:
|
case 25:
|
||||||
case 24: grm.underline = 0; break;
|
case 24: grm.underline = 0; break;
|
||||||
@ -1049,9 +1048,7 @@ BOOL HookAPIOneMod(
|
|||||||
// We now have a valid pointer to the module's PE header.
|
// We now have a valid pointer to the module's PE header.
|
||||||
// Get a pointer to its imports section.
|
// Get a pointer to its imports section.
|
||||||
pImportDesc = MakeVA( PIMAGE_IMPORT_DESCRIPTOR,
|
pImportDesc = MakeVA( PIMAGE_IMPORT_DESCRIPTOR,
|
||||||
pNTHeader->OptionalHeader.
|
pNTHeader->IMPORTDIR.VirtualAddress );
|
||||||
DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].
|
|
||||||
VirtualAddress );
|
|
||||||
|
|
||||||
// Bail out if the RVA of the imports section is 0 (it doesn't exist)
|
// Bail out if the RVA of the imports section is 0 (it doesn't exist)
|
||||||
if (pImportDesc == (PIMAGE_IMPORT_DESCRIPTOR)pDosHeader)
|
if (pImportDesc == (PIMAGE_IMPORT_DESCRIPTOR)pDosHeader)
|
||||||
@ -1113,35 +1110,18 @@ BOOL HookAPIOneMod(
|
|||||||
}
|
}
|
||||||
if (patch)
|
if (patch)
|
||||||
{
|
{
|
||||||
DWORD flOldProtect, flNewProtect, flDummy;
|
DWORD pr;
|
||||||
MEMORY_BASIC_INFORMATION mbi;
|
|
||||||
|
|
||||||
DEBUGSTR( 3, L" %S", hook->name );
|
DEBUGSTR( 3, L" %S", hook->name );
|
||||||
// Get the current protection attributes.
|
// Change the access protection on the region of committed pages in
|
||||||
VirtualQuery( &pThunk->u1.Function, &mbi, sizeof(mbi) );
|
// the virtual address space of the current process.
|
||||||
// Take the access protection flags.
|
VirtualProtect( &pThunk->u1.Function, PTRSZ, PAGE_READWRITE, &pr );
|
||||||
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.
|
// Overwrite the original address with the address of the new function.
|
||||||
if (!WriteProcessMemory( GetCurrentProcess(),
|
pThunk->u1.Function = (DWORD_PTR)patch;
|
||||||
&pThunk->u1.Function,
|
|
||||||
&patch, sizeof(patch), NULL ))
|
|
||||||
{
|
|
||||||
DEBUGSTR( 1, L"Could not patch!" );
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Put the page attributes back the way they were.
|
// Put the page attributes back the way they were.
|
||||||
VirtualProtect( &pThunk->u1.Function, sizeof(PVOID),
|
VirtualProtect( &pThunk->u1.Function, PTRSZ, pr, &pr );
|
||||||
flOldProtect, &flDummy );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pThunk++; // Advance to next imported function address
|
pThunk++; // Advance to next imported function address
|
||||||
@ -1212,10 +1192,11 @@ void Inject( DWORD dwCreationFlags, LPPROCESS_INFORMATION lpi,
|
|||||||
BOOL wide, LPCVOID lpApp, LPCVOID lpCmd )
|
BOOL wide, LPCVOID lpApp, LPCVOID lpCmd )
|
||||||
{
|
{
|
||||||
int type;
|
int type;
|
||||||
|
PBYTE base;
|
||||||
BOOL gui;
|
BOOL gui;
|
||||||
|
|
||||||
type = ProcessType( child_pi, &gui );
|
type = ProcessType( child_pi, &base, &gui );
|
||||||
if (gui)
|
if (gui && type > 0)
|
||||||
{
|
{
|
||||||
TCHAR app[MAX_PATH];
|
TCHAR app[MAX_PATH];
|
||||||
LPTSTR name;
|
LPTSTR name;
|
||||||
@ -1273,20 +1254,20 @@ void Inject( DWORD dwCreationFlags, LPPROCESS_INFORMATION lpi,
|
|||||||
type = 0;
|
type = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (type != 0)
|
if (type > 0)
|
||||||
{
|
{
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
if (type == 32)
|
if (type == 32)
|
||||||
{
|
{
|
||||||
hDllNameType[0] = '3';
|
ansi_bits[0] = '3';
|
||||||
hDllNameType[1] = '2';
|
ansi_bits[1] = '2';
|
||||||
InjectDLL32( child_pi, hDllName );
|
InjectDLL32( child_pi, base );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
hDllNameType[0] = '6';
|
ansi_bits[0] = '6';
|
||||||
hDllNameType[1] = '4';
|
ansi_bits[1] = '4';
|
||||||
InjectDLL64( child_pi, hDllName );
|
InjectDLL( child_pi, base );
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
#ifdef W32ON64
|
#ifdef W32ON64
|
||||||
@ -1313,7 +1294,7 @@ void Inject( DWORD dwCreationFlags, LPPROCESS_INFORMATION lpi,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
InjectDLL32( child_pi, hDllName );
|
InjectDLL( child_pi, base );
|
||||||
#endif
|
#endif
|
||||||
if (!gui && !(dwCreationFlags & (CREATE_NEW_CONSOLE | DETACHED_PROCESS)))
|
if (!gui && !(dwCreationFlags & (CREATE_NEW_CONSOLE | DETACHED_PROCESS)))
|
||||||
{
|
{
|
||||||
@ -1370,7 +1351,7 @@ BOOL WINAPI MyCreateProcessA( LPCSTR lpApplicationName,
|
|||||||
&child_pi ))
|
&child_pi ))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
DEBUGSTR( 1, L"CreateProcessA: (%lu) \"%S\", \"%S\"",
|
DEBUGSTR( 1, L"CreateProcessA: (%lu) \"%S\", %S",
|
||||||
child_pi.dwProcessId,
|
child_pi.dwProcessId,
|
||||||
(lpApplicationName == NULL) ? "" : lpApplicationName,
|
(lpApplicationName == NULL) ? "" : lpApplicationName,
|
||||||
(lpCommandLine == NULL) ? "" : lpCommandLine );
|
(lpCommandLine == NULL) ? "" : lpCommandLine );
|
||||||
@ -1406,7 +1387,7 @@ BOOL WINAPI MyCreateProcessW( LPCWSTR lpApplicationName,
|
|||||||
&child_pi ))
|
&child_pi ))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
DEBUGSTR( 1, L"CreateProcessW: (%lu) \"%s\", \"%s\"",
|
DEBUGSTR( 1, L"CreateProcessW: (%lu) \"%s\", %s",
|
||||||
child_pi.dwProcessId,
|
child_pi.dwProcessId,
|
||||||
(lpApplicationName == NULL) ? L"" : lpApplicationName,
|
(lpApplicationName == NULL) ? L"" : lpApplicationName,
|
||||||
(lpCommandLine == NULL) ? L"" : lpCommandLine );
|
(lpCommandLine == NULL) ? L"" : lpCommandLine );
|
||||||
@ -1609,7 +1590,6 @@ WINAPI MyWriteConsoleA( HANDLE hCon, LPCVOID lpBuffer,
|
|||||||
|
|
||||||
return WriteConsoleA( hCon, lpBuffer, nNumberOfCharsToWrite,
|
return WriteConsoleA( hCon, lpBuffer, nNumberOfCharsToWrite,
|
||||||
lpNumberOfCharsWritten, lpReserved );
|
lpNumberOfCharsWritten, lpReserved );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL
|
BOOL
|
||||||
@ -1774,6 +1754,7 @@ void OriginalAttr( void )
|
|||||||
NULL, OPEN_EXISTING, 0, 0 );
|
NULL, OPEN_EXISTING, 0, 0 );
|
||||||
if (!GetConsoleScreenBufferInfo( hConOut, &csbi ))
|
if (!GetConsoleScreenBufferInfo( hConOut, &csbi ))
|
||||||
csbi.wAttributes = 7;
|
csbi.wAttributes = 7;
|
||||||
|
orgattr = csbi.wAttributes;
|
||||||
CloseHandle( hConOut );
|
CloseHandle( hConOut );
|
||||||
|
|
||||||
if (s_flag == GRM_INIT && s_pid == GetCurrentProcessId())
|
if (s_flag == GRM_INIT && s_pid == GetCurrentProcessId())
|
||||||
@ -1823,7 +1804,8 @@ void OriginalAttr( void )
|
|||||||
// and terminated.
|
// and terminated.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
__declspec(dllexport) // just to stop MinGW exporting everything
|
// Need to export something for static loading to work, this is as good as any.
|
||||||
|
__declspec(dllexport)
|
||||||
BOOL WINAPI DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved )
|
BOOL WINAPI DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved )
|
||||||
{
|
{
|
||||||
BOOL bResult = TRUE;
|
BOOL bResult = TRUE;
|
||||||
@ -1840,19 +1822,19 @@ BOOL WINAPI DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved )
|
|||||||
hDllNameType = hDllName - 6 +
|
hDllNameType = hDllName - 6 +
|
||||||
#endif
|
#endif
|
||||||
GetModuleFileName( hInstance, hDllName, lenof(hDllName) );
|
GetModuleFileName( hInstance, hDllName, lenof(hDllName) );
|
||||||
|
#ifdef _WIN64
|
||||||
|
ansi_bits = (LPSTR)hDllNameType;
|
||||||
|
#endif
|
||||||
|
set_ansi_dll( hDllName );
|
||||||
|
|
||||||
hDllInstance = hInstance; // save Dll instance handle
|
hDllInstance = hInstance; // save Dll instance handle
|
||||||
DEBUGSTR( 1, L"hDllInstance = %p", hDllInstance );
|
|
||||||
|
|
||||||
if (LLW32r == 0)
|
|
||||||
{
|
|
||||||
if (!get_LLW32r())
|
|
||||||
return FALSE;
|
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
if (!get_LLW64r())
|
DEBUGSTR( 1, L"hDllInstance = %.8X_%.8X",
|
||||||
return FALSE;
|
(DWORD)((DWORD_PTR)hDllInstance >> 32),
|
||||||
|
PtrToUint( hDllInstance ) );
|
||||||
|
#else
|
||||||
|
DEBUGSTR( 1, L"hDllInstance = %p", hDllInstance );
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
|
|
||||||
// Get the entry points to the original functions.
|
// Get the entry points to the original functions.
|
||||||
hKernel = GetModuleHandleA( APIKernel );
|
hKernel = GetModuleHandleA( APIKernel );
|
||||||
@ -1869,6 +1851,11 @@ BOOL WINAPI DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved )
|
|||||||
{
|
{
|
||||||
DEBUGSTR( 1, L"Unloading" );
|
DEBUGSTR( 1, L"Unloading" );
|
||||||
HookAPIAllMod( Hooks, TRUE );
|
HookAPIAllMod( Hooks, TRUE );
|
||||||
|
hConOut = CreateFile( L"CONOUT$", GENERIC_READ | GENERIC_WRITE,
|
||||||
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||||
|
NULL, OPEN_EXISTING, 0, 0 );
|
||||||
|
SetConsoleTextAttribute( hConOut, orgattr );
|
||||||
|
CloseHandle( hConOut );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
Copyright (C) 2005-2013 Jason Hood
|
Copyright (C) 2005-2014 Jason Hood
|
||||||
|
|
||||||
This software is provided 'as-is', without any express or implied
|
This software is provided 'as-is', without any express or implied
|
||||||
warranty. In no event will the author be held liable for any damages
|
warranty. In no event will the author be held liable for any damages
|
||||||
|
115
LLW.c
Normal file
115
LLW.c
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
/*
|
||||||
|
Locate the relative address of LoadLibraryW in kernel32.dll. This is needed
|
||||||
|
to get the 32-bit address from 64-bit code, and it eliminates the possibility
|
||||||
|
of it already being hooked.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ansicon.h"
|
||||||
|
|
||||||
|
static PIMAGE_DOS_HEADER pDosHeader;
|
||||||
|
|
||||||
|
#define MakeVA( cast, offset ) (cast)((DWORD_PTR)pDosHeader + (DWORD)(offset))
|
||||||
|
|
||||||
|
|
||||||
|
static int export_cmp( const void* a, const void* b )
|
||||||
|
{
|
||||||
|
return strcmp( (LPCSTR)a, MakeVA( LPCSTR, *(const PDWORD)b ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DWORD get_LLW32r( void )
|
||||||
|
{
|
||||||
|
HMODULE kernel32;
|
||||||
|
TCHAR buf[MAX_PATH];
|
||||||
|
UINT len;
|
||||||
|
PIMAGE_NT_HEADERS32 pNTHeader;
|
||||||
|
PIMAGE_EXPORT_DIRECTORY pExportDir;
|
||||||
|
PDWORD fun_table, name_table;
|
||||||
|
PWORD ord_table;
|
||||||
|
PDWORD pLLW;
|
||||||
|
DWORD LLWr;
|
||||||
|
|
||||||
|
#ifdef _WIN64
|
||||||
|
len = GetSystemWow64Directory( buf, MAX_PATH );
|
||||||
|
#else
|
||||||
|
len = GetSystemDirectory( buf, MAX_PATH );
|
||||||
|
#endif
|
||||||
|
wcscpy( buf + len, L"\\kernel32.dll" );
|
||||||
|
kernel32 = LoadLibraryEx( buf, NULL, LOAD_LIBRARY_AS_IMAGE_RESOURCE );
|
||||||
|
if (kernel32 == NULL)
|
||||||
|
{
|
||||||
|
DEBUGSTR( 1, L"Unable to load 32-bit kernel32.dll!" );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// The handle uses low bits as flags, so strip 'em off.
|
||||||
|
pDosHeader = (PIMAGE_DOS_HEADER)((DWORD_PTR)kernel32 & ~0xFFFF);
|
||||||
|
pNTHeader = MakeVA( PIMAGE_NT_HEADERS32, pDosHeader->e_lfanew );
|
||||||
|
pExportDir = MakeVA( PIMAGE_EXPORT_DIRECTORY,
|
||||||
|
pNTHeader->EXPORTDIR.VirtualAddress );
|
||||||
|
|
||||||
|
fun_table = MakeVA( PDWORD, pExportDir->AddressOfFunctions );
|
||||||
|
name_table = MakeVA( PDWORD, pExportDir->AddressOfNames );
|
||||||
|
ord_table = MakeVA( PWORD, pExportDir->AddressOfNameOrdinals );
|
||||||
|
|
||||||
|
pLLW = bsearch( "LoadLibraryW", name_table, pExportDir->NumberOfNames,
|
||||||
|
sizeof(DWORD), export_cmp );
|
||||||
|
if (pLLW == NULL)
|
||||||
|
{
|
||||||
|
DEBUGSTR( 1, L"Could not find 32-bit LoadLibraryW!" );
|
||||||
|
LLWr = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LLWr = fun_table[ord_table[pLLW - name_table]];
|
||||||
|
}
|
||||||
|
FreeLibrary( kernel32 );
|
||||||
|
return LLWr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef _WIN64
|
||||||
|
DWORD64 get_LLW64r( void )
|
||||||
|
{
|
||||||
|
HMODULE kernel32;
|
||||||
|
TCHAR buf[MAX_PATH];
|
||||||
|
UINT len;
|
||||||
|
PIMAGE_NT_HEADERS pNTHeader;
|
||||||
|
PIMAGE_EXPORT_DIRECTORY pExportDir;
|
||||||
|
PDWORD fun_table, name_table;
|
||||||
|
PWORD ord_table;
|
||||||
|
PDWORD pLLW;
|
||||||
|
DWORD64 LLWr;
|
||||||
|
|
||||||
|
len = GetSystemDirectory( buf, MAX_PATH );
|
||||||
|
wcscpy( buf + len, L"\\kernel32.dll" );
|
||||||
|
kernel32 = LoadLibraryEx( buf, NULL, LOAD_LIBRARY_AS_IMAGE_RESOURCE );
|
||||||
|
if (kernel32 == NULL)
|
||||||
|
{
|
||||||
|
DEBUGSTR( 1, L"Unable to load 64-bit kernel32.dll!" );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// The handle uses low bits as flags, so strip 'em off.
|
||||||
|
pDosHeader = (PIMAGE_DOS_HEADER)((DWORD_PTR)kernel32 & ~0xFFFF);
|
||||||
|
pNTHeader = MakeVA( PIMAGE_NT_HEADERS, pDosHeader->e_lfanew );
|
||||||
|
pExportDir = MakeVA( PIMAGE_EXPORT_DIRECTORY,
|
||||||
|
pNTHeader->EXPORTDIR.VirtualAddress );
|
||||||
|
|
||||||
|
fun_table = MakeVA( PDWORD, pExportDir->AddressOfFunctions );
|
||||||
|
name_table = MakeVA( PDWORD, pExportDir->AddressOfNames );
|
||||||
|
ord_table = MakeVA( PWORD, pExportDir->AddressOfNameOrdinals );
|
||||||
|
|
||||||
|
pLLW = bsearch( "LoadLibraryW", name_table, pExportDir->NumberOfNames,
|
||||||
|
sizeof(DWORD), export_cmp );
|
||||||
|
if (pLLW == NULL)
|
||||||
|
{
|
||||||
|
DEBUGSTR( 1, L"Could not find 64-bit LoadLibraryW!" );
|
||||||
|
LLWr = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LLWr = fun_table[ord_table[pLLW - name_table]];
|
||||||
|
}
|
||||||
|
FreeLibrary( kernel32 );
|
||||||
|
return LLWr;
|
||||||
|
}
|
||||||
|
#endif
|
302
ansicon.c
302
ansicon.c
@ -76,17 +76,30 @@
|
|||||||
|
|
||||||
v1.63, 25 July, 2013:
|
v1.63, 25 July, 2013:
|
||||||
don't write the reset sequence if output is redirected.
|
don't write the reset sequence if output is redirected.
|
||||||
|
|
||||||
|
v1.70, 31 January to 3 February, 2014:
|
||||||
|
restore the original (current, not default) attributes if using ansicon.exe
|
||||||
|
when it's already installed;
|
||||||
|
use ANSICON_DEF if defined and -m not given;
|
||||||
|
-e and -t will not output anything if the DLL could not load;
|
||||||
|
use Unicode output (_O_U16TEXT, for compilers/systems that support it);
|
||||||
|
log: 64-bit addresses get an underscore between the 8-digit groups.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define PDATE L"27 January, 2014"
|
#define PDATE L"4 February, 2014"
|
||||||
|
|
||||||
#include "ansicon.h"
|
#include "ansicon.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
#include <tlhelp32.h>
|
#include <tlhelp32.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <fcntl.h>
|
||||||
#include <io.h>
|
#include <io.h>
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
|
|
||||||
|
#ifndef _O_U16TEXT
|
||||||
|
#define _O_U16TEXT 0x20000
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __MINGW32__
|
#ifdef __MINGW32__
|
||||||
int _CRT_glob = 0;
|
int _CRT_glob = 0;
|
||||||
#endif
|
#endif
|
||||||
@ -99,7 +112,7 @@ int _CRT_glob = 0;
|
|||||||
void help( void );
|
void help( void );
|
||||||
|
|
||||||
void display( LPCTSTR, BOOL );
|
void display( LPCTSTR, BOOL );
|
||||||
void print_error( LPCTSTR, ... );
|
void print_error( LPCTSTR );
|
||||||
LPTSTR skip_spaces( LPTSTR );
|
LPTSTR skip_spaces( LPTSTR );
|
||||||
void get_arg( LPTSTR, LPTSTR*, LPTSTR* );
|
void get_arg( LPTSTR, LPTSTR*, LPTSTR* );
|
||||||
void get_file( LPTSTR, LPTSTR*, LPTSTR* );
|
void get_file( LPTSTR, LPTSTR*, LPTSTR* );
|
||||||
@ -110,12 +123,49 @@ BOOL find_proc_id( HANDLE snap, DWORD id, LPPROCESSENTRY32 ppe );
|
|||||||
BOOL GetParentProcessInfo( LPPROCESS_INFORMATION ppi, LPTSTR );
|
BOOL GetParentProcessInfo( LPPROCESS_INFORMATION ppi, LPTSTR );
|
||||||
|
|
||||||
|
|
||||||
// The DLL shares this variable, so injection requires it here.
|
static HANDLE hConOut;
|
||||||
DWORD LLW32r;
|
static WORD wAttr;
|
||||||
#ifdef _WIN64
|
|
||||||
DWORD LLW64r;
|
void get_original_attr( void )
|
||||||
#endif
|
{
|
||||||
extern LPVOID kernel32_base;
|
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
||||||
|
|
||||||
|
hConOut = CreateFile( L"CONOUT$", GENERIC_READ | GENERIC_WRITE,
|
||||||
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||||
|
NULL, OPEN_EXISTING, 0, 0 );
|
||||||
|
GetConsoleScreenBufferInfo( hConOut, &csbi );
|
||||||
|
wAttr = csbi.wAttributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void set_original_attr( void )
|
||||||
|
{
|
||||||
|
SetConsoleTextAttribute( hConOut, wAttr );
|
||||||
|
CloseHandle( hConOut );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// The fputws function in MSVCRT.DLL (Windows 7 x64) is broken for Unicode
|
||||||
|
// output (it just writes the first character). VC6 & 7 don't support Unicode
|
||||||
|
// output at all (just converting to ANSI) and even when it is supported, it
|
||||||
|
// just writes single characters (as does _putws & fwprintf). So what the
|
||||||
|
// heck, DIY.
|
||||||
|
int my_fputws( const wchar_t* s, FILE* f )
|
||||||
|
{
|
||||||
|
if (_isatty( _fileno( f ) ))
|
||||||
|
{
|
||||||
|
DWORD written;
|
||||||
|
WriteConsole( hConOut, s, (DWORD)wcslen( s ), &written, NULL );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fputws( s, f );
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define fputws my_fputws
|
||||||
|
#define _putws( s ) my_fputws( s L"\n", stdout )
|
||||||
|
|
||||||
|
|
||||||
// Find the name of the DLL and inject it.
|
// Find the name of the DLL and inject it.
|
||||||
@ -124,11 +174,13 @@ BOOL Inject( LPPROCESS_INFORMATION ppi, BOOL* gui, LPCTSTR app )
|
|||||||
DWORD len;
|
DWORD len;
|
||||||
WCHAR dll[MAX_PATH];
|
WCHAR dll[MAX_PATH];
|
||||||
int type;
|
int type;
|
||||||
|
PBYTE base;
|
||||||
|
|
||||||
DEBUGSTR( 1, L"%s (%lu)", app, ppi->dwProcessId );
|
DEBUGSTR( 1, L"%s (%lu)", app, ppi->dwProcessId );
|
||||||
type = ProcessType( ppi, gui );
|
type = ProcessType( ppi, &base, gui );
|
||||||
if (type == 0)
|
if (type <= 0)
|
||||||
{
|
{
|
||||||
|
if (type == 0)
|
||||||
fwprintf( stderr, L"ANSICON: %s: unsupported process.\n", app );
|
fwprintf( stderr, L"ANSICON: %s: unsupported process.\n", app );
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
@ -137,41 +189,94 @@ BOOL Inject( LPPROCESS_INFORMATION ppi, BOOL* gui, LPCTSTR app )
|
|||||||
memcpy( dll, prog_path, TSIZE(len) );
|
memcpy( dll, prog_path, TSIZE(len) );
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
wsprintf( dll + len, L"ANSI%d.dll", type );
|
wsprintf( dll + len, L"ANSI%d.dll", type );
|
||||||
|
ansi_bits = (LPSTR)(dll + len + 4);
|
||||||
|
set_ansi_dll( dll );
|
||||||
if (type == 32)
|
if (type == 32)
|
||||||
{
|
InjectDLL32( ppi, base );
|
||||||
get_LLW32r();
|
|
||||||
InjectDLL32( ppi, dll );
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
InjectDLL( ppi, base );
|
||||||
get_LLW64r();
|
|
||||||
InjectDLL64( ppi, dll );
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
wcscpy( dll + len, L"ANSI32.dll" );
|
wcscpy( dll + len, L"ANSI32.dll" );
|
||||||
get_LLW32r();
|
set_ansi_dll( dll );
|
||||||
InjectDLL32( ppi, dll );
|
InjectDLL( ppi, base );
|
||||||
#endif
|
#endif
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static HANDLE hConOut;
|
// Use CreateRemoteThread to load our DLL in the target process.
|
||||||
static CONSOLE_SCREEN_BUFFER_INFO csbi;
|
void RemoteLoad( LPPROCESS_INFORMATION ppi )
|
||||||
|
|
||||||
void get_original_attr( void )
|
|
||||||
{
|
{
|
||||||
hConOut = CreateFile( L"CONOUT$", GENERIC_READ | GENERIC_WRITE,
|
HANDLE hSnap;
|
||||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
MODULEENTRY32 me;
|
||||||
NULL, OPEN_EXISTING, 0, 0 );
|
PBYTE LLW;
|
||||||
GetConsoleScreenBufferInfo( hConOut, &csbi );
|
BOOL fOk;
|
||||||
|
WCHAR dll[MAX_PATH];
|
||||||
|
DWORD len;
|
||||||
|
LPVOID mem;
|
||||||
|
HANDLE thread;
|
||||||
|
#ifdef _WIN64
|
||||||
|
BOOL WOW64;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Find the base address of kernel32.dll.
|
||||||
|
LLW = NULL;
|
||||||
|
hSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32,
|
||||||
|
ppi->dwProcessId );
|
||||||
|
if (hSnap != INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
me.dwSize = sizeof(MODULEENTRY32);
|
||||||
|
for (fOk = Module32First( hSnap, &me ); fOk;
|
||||||
|
fOk = Module32Next( hSnap, &me ))
|
||||||
|
{
|
||||||
|
if (_wcsicmp( me.szModule, L"kernel32.dll" ) == 0)
|
||||||
|
{
|
||||||
|
LLW = me.modBaseAddr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CloseHandle( hSnap );
|
||||||
|
}
|
||||||
|
#ifndef _WIN64
|
||||||
|
else if (GetLastError() == ERROR_PARTIAL_COPY)
|
||||||
|
{
|
||||||
|
fputws( L"ANSICON: parent is 64-bit (use x64\\ansicon).\n", stderr );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (LLW == NULL)
|
||||||
|
{
|
||||||
|
no_llw:
|
||||||
|
fputws( L"ANSICON: unable to inject into parent.\n", stderr );
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
len = (DWORD)(prog - prog_path);
|
||||||
void set_original_attr( void )
|
memcpy( dll, prog_path, TSIZE(len) );
|
||||||
|
#ifdef _WIN64
|
||||||
|
if (IsWow64Process( ppi->hProcess, &WOW64 ) && WOW64)
|
||||||
{
|
{
|
||||||
SetConsoleTextAttribute( hConOut, csbi.wAttributes );
|
wcscpy( dll + len, L"ANSI32.dll" );
|
||||||
CloseHandle( hConOut );
|
LLW += get_LLW32r();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
wcscpy( dll + len, L"ANSI64.dll" );
|
||||||
|
LLW += get_LLW64r();
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
wcscpy( dll + len, L"ANSI32.dll" );
|
||||||
|
LLW += get_LLW32r();
|
||||||
|
#endif
|
||||||
|
if (LLW == me.modBaseAddr)
|
||||||
|
goto no_llw;
|
||||||
|
mem = VirtualAllocEx( ppi->hProcess, NULL, len, MEM_COMMIT, PAGE_READWRITE );
|
||||||
|
WriteProcMem( mem, dll, TSIZE(len + 11) );
|
||||||
|
thread = CreateRemoteThread( ppi->hProcess, NULL, 4096,
|
||||||
|
(LPTHREAD_START_ROUTINE)LLW, mem, 0, NULL );
|
||||||
|
WaitForSingleObject( thread, INFINITE );
|
||||||
|
CloseHandle( thread );
|
||||||
|
VirtualFreeEx( ppi->hProcess, mem, 0, MEM_RELEASE );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -186,13 +291,25 @@ int main( void )
|
|||||||
STARTUPINFO si;
|
STARTUPINFO si;
|
||||||
PROCESS_INFORMATION pi;
|
PROCESS_INFORMATION pi;
|
||||||
LPTSTR argv, arg, cmd;
|
LPTSTR argv, arg, cmd;
|
||||||
TCHAR logstr[4];
|
TCHAR buf[4];
|
||||||
BOOL installed;
|
|
||||||
BOOL shell, run, gui;
|
BOOL shell, run, gui;
|
||||||
HMODULE ansi;
|
HMODULE ansi;
|
||||||
DWORD len;
|
DWORD len;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
|
// Convert wide strings using the current code page.
|
||||||
|
sprintf( (LPSTR)buf, ".%u", GetConsoleOutputCP() );
|
||||||
|
setlocale( LC_CTYPE, (LPSTR)buf );
|
||||||
|
|
||||||
|
// Switch console output to Unicode.
|
||||||
|
if (_isatty( 1 ))
|
||||||
|
_setmode( 1, _O_U16TEXT);
|
||||||
|
if (_isatty( 2 ))
|
||||||
|
_setmode( 2, _O_U16TEXT);
|
||||||
|
|
||||||
|
// Create a console handle and store the current attribute.
|
||||||
|
get_original_attr();
|
||||||
|
|
||||||
argv = GetCommandLine();
|
argv = GetCommandLine();
|
||||||
len = (DWORD)wcslen( argv ) + 1;
|
len = (DWORD)wcslen( argv ) + 1;
|
||||||
if (len < MAX_PATH)
|
if (len < MAX_PATH)
|
||||||
@ -217,13 +334,9 @@ int main( void )
|
|||||||
}
|
}
|
||||||
|
|
||||||
prog = get_program_name( NULL );
|
prog = get_program_name( NULL );
|
||||||
*logstr = '\0';
|
*buf = '\0';
|
||||||
GetEnvironmentVariable( L"ANSICON_LOG", logstr, lenof(logstr) );
|
GetEnvironmentVariable( L"ANSICON_LOG", buf, lenof(buf) );
|
||||||
log_level = _wtoi( logstr );
|
log_level = _wtoi( buf );
|
||||||
|
|
||||||
// Using "" for setlocale uses the system ANSI code page.
|
|
||||||
sprintf( (LPSTR)logstr, ".%u", GetConsoleOutputCP() );
|
|
||||||
setlocale( LC_CTYPE, (LPSTR)logstr );
|
|
||||||
|
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
if (*arg == '-' && arg[1] == 'P')
|
if (*arg == '-' && arg[1] == 'P')
|
||||||
@ -241,19 +354,7 @@ int main( void )
|
|||||||
if (log_level)
|
if (log_level)
|
||||||
DEBUGSTR( 1, NULL ); // start a new session
|
DEBUGSTR( 1, NULL ); // start a new session
|
||||||
|
|
||||||
installed = (GetEnvironmentVariable( L"ANSICON_VER", NULL, 0 ) != 0);
|
|
||||||
// If it's already installed, remove it. This serves two purposes: preserves
|
|
||||||
// the parent's GRM; and unconditionally injects into GUI, without having to
|
|
||||||
// worry about ANSICON_GUI.
|
|
||||||
if (installed)
|
|
||||||
{
|
|
||||||
if (_isatty( 1 ))
|
|
||||||
fputws( L"\33[m", stdout );
|
|
||||||
FreeLibrary( GetModuleHandle( ANSIDLL ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
shell = run = TRUE;
|
shell = run = TRUE;
|
||||||
get_original_attr();
|
|
||||||
|
|
||||||
while (*arg == '-')
|
while (*arg == '-')
|
||||||
{
|
{
|
||||||
@ -277,40 +378,12 @@ int main( void )
|
|||||||
|
|
||||||
case 'p':
|
case 'p':
|
||||||
shell = FALSE;
|
shell = FALSE;
|
||||||
// If it's already installed, there's no need to do anything.
|
if (GetParentProcessInfo( &pi, arg + 3 ))
|
||||||
if (installed)
|
|
||||||
{
|
{
|
||||||
DEBUGSTR( 1, L"Already installed" );
|
|
||||||
}
|
|
||||||
else if (GetParentProcessInfo( &pi, arg ))
|
|
||||||
{
|
|
||||||
HANDLE hSnap;
|
|
||||||
MODULEENTRY32 me;
|
|
||||||
BOOL fOk;
|
|
||||||
|
|
||||||
pi.hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pi.dwProcessId);
|
pi.hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pi.dwProcessId);
|
||||||
pi.hThread = OpenThread( THREAD_ALL_ACCESS, FALSE, pi.dwThreadId );
|
pi.hThread = OpenThread( THREAD_ALL_ACCESS, FALSE, pi.dwThreadId );
|
||||||
SuspendThread( pi.hThread );
|
SuspendThread( pi.hThread );
|
||||||
// Find the base address of kernel32.dll.
|
RemoteLoad( &pi );
|
||||||
hSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE |
|
|
||||||
TH32CS_SNAPMODULE32,
|
|
||||||
pi.dwProcessId );
|
|
||||||
if (hSnap != INVALID_HANDLE_VALUE)
|
|
||||||
{
|
|
||||||
me.dwSize = sizeof(MODULEENTRY32);
|
|
||||||
for (fOk = Module32First( hSnap, &me ); fOk;
|
|
||||||
fOk = Module32Next( hSnap, &me ))
|
|
||||||
{
|
|
||||||
if (_wcsicmp( me.szModule, L"kernel32.dll" ) == 0)
|
|
||||||
{
|
|
||||||
kernel32_base = me.modBaseAddr;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
CloseHandle( hSnap );
|
|
||||||
}
|
|
||||||
if (!Inject( &pi, &gui, arg ))
|
|
||||||
rc = 1;
|
|
||||||
ResumeThread( pi.hThread );
|
ResumeThread( pi.hThread );
|
||||||
CloseHandle( pi.hThread );
|
CloseHandle( pi.hThread );
|
||||||
CloseHandle( pi.hProcess );
|
CloseHandle( pi.hProcess );
|
||||||
@ -360,6 +433,15 @@ arg_out:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ensure the default attributes are the current attributes.
|
||||||
|
if (GetEnvironmentVariable( L"ANSICON_DEF", buf, lenof(buf) ) != 0)
|
||||||
|
{
|
||||||
|
int a = wcstol( buf, NULL, 16 );
|
||||||
|
if (a < 0)
|
||||||
|
a = ((-a >> 4) & 15) | ((-a & 15) << 4);
|
||||||
|
SetConsoleTextAttribute( hConOut, (WORD)a );
|
||||||
|
}
|
||||||
|
|
||||||
if (run)
|
if (run)
|
||||||
{
|
{
|
||||||
if (*cmd == '\0')
|
if (*cmd == '\0')
|
||||||
@ -392,7 +474,7 @@ arg_out:
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
print_error( arg, arg );
|
print_error( arg );
|
||||||
rc = 1;
|
rc = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -404,8 +486,7 @@ arg_out:
|
|||||||
print_error( ANSIDLL );
|
print_error( ANSIDLL );
|
||||||
rc = 1;
|
rc = 1;
|
||||||
}
|
}
|
||||||
|
else if (*arg == 'e' || *arg == 'E')
|
||||||
if (*arg == 'e' || *arg == 'E')
|
|
||||||
{
|
{
|
||||||
cmd += 2;
|
cmd += 2;
|
||||||
if (*cmd == ' ' || *cmd == '\t')
|
if (*cmd == ' ' || *cmd == '\t')
|
||||||
@ -433,14 +514,10 @@ arg_out:
|
|||||||
get_file( arg, &argv, &cmd );
|
get_file( arg, &argv, &cmd );
|
||||||
} while (*arg);
|
} while (*arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
FreeLibrary( ansi );
|
FreeLibrary( ansi );
|
||||||
}
|
}
|
||||||
|
|
||||||
if (run || *arg)
|
|
||||||
set_original_attr();
|
set_original_attr();
|
||||||
else
|
|
||||||
CloseHandle( hConOut );
|
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -495,30 +572,30 @@ void display( LPCTSTR name, BOOL title )
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void print_error( LPCTSTR name, ... )
|
void print_error( LPCTSTR name )
|
||||||
{
|
{
|
||||||
LPTSTR errmsg = NULL;
|
LPTSTR errmsg = NULL;
|
||||||
DWORD err = GetLastError();
|
DWORD err = GetLastError();
|
||||||
va_list arg;
|
|
||||||
|
|
||||||
|
fputws( L"ANSICON: ", stderr );
|
||||||
if (err == ERROR_BAD_EXE_FORMAT)
|
if (err == ERROR_BAD_EXE_FORMAT)
|
||||||
{
|
{
|
||||||
// This error requires an argument, which is a duplicate of name.
|
// This error requires an argument, which is name.
|
||||||
va_start( arg, name );
|
FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM |
|
||||||
FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
|
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||||
NULL, err, 0, (LPTSTR)(LPVOID)&errmsg, 0, &arg );
|
FORMAT_MESSAGE_ARGUMENT_ARRAY,
|
||||||
va_end( arg );
|
NULL, err, 0, (LPTSTR)(LPVOID)&errmsg, 0, (va_list*)&name );
|
||||||
fwprintf( stderr, L"ANSICON: %s", errmsg );
|
fputws( errmsg, stderr );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
|
if (FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM |
|
||||||
NULL, err, 0, (LPTSTR)(LPVOID)&errmsg, 0, NULL );
|
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||||
// Just in case there are other messages requiring args...
|
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||||
if (errmsg == NULL)
|
NULL, err, 0, (LPTSTR)(LPVOID)&errmsg, 0, NULL ))
|
||||||
fwprintf( stderr, L"ANSICON: %s: Error %lu.\n", name, err );
|
fwprintf( stderr, L"%s: %s", name, errmsg );
|
||||||
else
|
else
|
||||||
fwprintf( stderr, L"ANSICON: %s: %s", name, errmsg );
|
fwprintf( stderr, L"%s: Error %lu.\n", name, err );
|
||||||
}
|
}
|
||||||
LocalFree( errmsg );
|
LocalFree( errmsg );
|
||||||
}
|
}
|
||||||
@ -759,7 +836,7 @@ void get_file( LPTSTR arg, LPTSTR* argv, LPTSTR* cmd )
|
|||||||
for (path = name = arg; *path != '\0'; ++path)
|
for (path = name = arg; *path != '\0'; ++path)
|
||||||
if (*path == '\\' || *path == '/')
|
if (*path == '\\' || *path == '/')
|
||||||
name = path + 1;
|
name = path + 1;
|
||||||
glob = malloc( (globbed + 1) * sizeof(LPTSTR) + TSIZE(size) );
|
glob = malloc( (globbed + 1) * PTRSZ + TSIZE(size) );
|
||||||
path = (LPTSTR)(glob + globbed + 1);
|
path = (LPTSTR)(glob + globbed + 1);
|
||||||
globbed = 0;
|
globbed = 0;
|
||||||
fh = FindFirstFile( arg, &fd );
|
fh = FindFirstFile( arg, &fd );
|
||||||
@ -789,7 +866,7 @@ void get_file( LPTSTR arg, LPTSTR* argv, LPTSTR* cmd )
|
|||||||
FindClose( fh );
|
FindClose( fh );
|
||||||
glob[globbed] = NULL;
|
glob[globbed] = NULL;
|
||||||
|
|
||||||
qsort( glob, globbed, sizeof(LPTSTR), glob_sort );
|
qsort( glob, globbed, PTRSZ, glob_sort );
|
||||||
|
|
||||||
wcscpy( name, glob[0] );
|
wcscpy( name, glob[0] );
|
||||||
globbed = 1;
|
globbed = 1;
|
||||||
@ -799,6 +876,13 @@ void get_file( LPTSTR arg, LPTSTR* argv, LPTSTR* cmd )
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// VC macros don't like preprocessor statements mixed with strings.
|
||||||
|
#ifdef _WIN64
|
||||||
|
#define WINTYPE L"Windows"
|
||||||
|
#else
|
||||||
|
#define WINTYPE L"Win32"
|
||||||
|
#endif
|
||||||
|
|
||||||
void help( void )
|
void help( void )
|
||||||
{
|
{
|
||||||
_putws(
|
_putws(
|
||||||
@ -806,11 +890,7 @@ L"ANSICON by Jason Hood <jadoxa@yahoo.com.au>.\n"
|
|||||||
L"Version " PVERS L" (" PDATE L"). Freeware.\n"
|
L"Version " PVERS L" (" PDATE L"). Freeware.\n"
|
||||||
L"http://ansicon.adoxa.vze.com/\n"
|
L"http://ansicon.adoxa.vze.com/\n"
|
||||||
L"\n"
|
L"\n"
|
||||||
#ifdef _WIN64
|
L"Process ANSI escape sequences in " WINTYPE L" console programs.\n"
|
||||||
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"\n"
|
||||||
L"ansicon [-l<level>] [-i] [-I] [-u] [-U] [-m[<attr>]] [-p]\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" [-e|E string | -t|T [file(s)] | program [args]]\n"
|
||||||
|
33
ansicon.h
33
ansicon.h
@ -31,6 +31,22 @@
|
|||||||
#define LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE 0x20
|
#define LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE 0x20
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define EXPORTDIR OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]
|
||||||
|
#define IMPORTDIR OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
|
||||||
|
#define BOUNDDIR OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT]
|
||||||
|
#define IATDIR OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT]
|
||||||
|
#define COMDIR OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR]
|
||||||
|
|
||||||
|
|
||||||
|
// Reduce the verbosity of some functions (assuming variable names).
|
||||||
|
#define ReadProcVar(a, b) ReadProcMem( a, b, sizeof(*(b)) )
|
||||||
|
#define WriteProcVar(a, b) WriteProcMem( a, b, sizeof(*(b)) )
|
||||||
|
#define ReadProcMem(a, b, c) ReadProcessMemory( ppi->hProcess, a, b, c, NULL )
|
||||||
|
#define WriteProcMem(a, b, c) WriteProcessMemory( ppi->hProcess, a, b, c, NULL )
|
||||||
|
#define VirtProtVar(a, b) VirtualProtectEx( ppi->hProcess, a, sizeof(*(a)), b, &pr )
|
||||||
|
|
||||||
|
#define PTRSZ sizeof(PVOID)
|
||||||
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
@ -44,16 +60,23 @@ typedef struct
|
|||||||
} GRM, *PGRM; // Graphic Rendition Mode
|
} GRM, *PGRM; // Graphic Rendition Mode
|
||||||
|
|
||||||
|
|
||||||
int ProcessType( LPPROCESS_INFORMATION, BOOL* );
|
int ProcessType( LPPROCESS_INFORMATION, PBYTE*, BOOL* );
|
||||||
void InjectDLL32( LPPROCESS_INFORMATION, LPCTSTR );
|
|
||||||
void InjectDLL64( LPPROCESS_INFORMATION, LPCTSTR );
|
void InjectDLL( LPPROCESS_INFORMATION, PBYTE );
|
||||||
BOOL get_LLW32r( void );
|
void InjectDLL32( LPPROCESS_INFORMATION, PBYTE );
|
||||||
BOOL get_LLW64r( void );
|
|
||||||
|
DWORD get_LLW32r( void );
|
||||||
|
DWORD64 get_LLW64r( void );
|
||||||
|
|
||||||
extern TCHAR prog_path[MAX_PATH];
|
extern TCHAR prog_path[MAX_PATH];
|
||||||
extern LPTSTR prog;
|
extern LPTSTR prog;
|
||||||
LPTSTR get_program_name( LPTSTR );
|
LPTSTR get_program_name( LPTSTR );
|
||||||
|
|
||||||
|
extern char ansi_dll[MAX_PATH];
|
||||||
|
extern DWORD ansi_len;
|
||||||
|
extern char* ansi_bits;
|
||||||
|
void set_ansi_dll( LPTSTR );
|
||||||
|
|
||||||
extern int log_level;
|
extern int log_level;
|
||||||
void DEBUGSTR( int level, LPTSTR szFormat, ... );
|
void DEBUGSTR( int level, LPTSTR szFormat, ... );
|
||||||
|
|
||||||
|
202
injdll.c
Normal file
202
injdll.c
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
/*
|
||||||
|
Inject the DLL into the target process by modifying its import descriptor
|
||||||
|
table. The target process must have been created suspended.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ansicon.h"
|
||||||
|
|
||||||
|
|
||||||
|
// Search for a suitable free area after the main image. (32-bit code could
|
||||||
|
// really go anywhere, but let's keep it relatively local.)
|
||||||
|
PVOID FindMem( HANDLE hProcess, PBYTE base, DWORD len )
|
||||||
|
{
|
||||||
|
MEMORY_BASIC_INFORMATION minfo;
|
||||||
|
PBYTE ptr;
|
||||||
|
PVOID mem;
|
||||||
|
|
||||||
|
for (ptr = base;
|
||||||
|
VirtualQueryEx( hProcess, ptr, &minfo, sizeof(minfo) );
|
||||||
|
ptr += minfo.RegionSize)
|
||||||
|
{
|
||||||
|
if ((minfo.State & MEM_FREE) && minfo.RegionSize >= len)
|
||||||
|
{
|
||||||
|
#ifdef _WIN64
|
||||||
|
if ((PBYTE)minfo.BaseAddress - base > 0xFfFfFfFf - len)
|
||||||
|
return NULL;
|
||||||
|
#endif
|
||||||
|
mem = VirtualAllocEx( hProcess, (PVOID)
|
||||||
|
(((DWORD_PTR)minfo.BaseAddress + 0xFFFF) & ~0xFFFF),
|
||||||
|
len, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE );
|
||||||
|
if (mem != NULL)
|
||||||
|
return mem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void InjectDLL( LPPROCESS_INFORMATION ppi, PBYTE pBase )
|
||||||
|
{
|
||||||
|
DWORD rva;
|
||||||
|
PVOID pMem;
|
||||||
|
DWORD len;
|
||||||
|
DWORD pr;
|
||||||
|
IMAGE_DOS_HEADER DosHeader;
|
||||||
|
IMAGE_NT_HEADERS NTHeader, *pNTHeader;
|
||||||
|
PIMAGE_IMPORT_DESCRIPTOR pImports, pANSI_ImportDesc;
|
||||||
|
IMAGE_COR20_HEADER ComHeader, *pComHeader;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
PBYTE pB;
|
||||||
|
PLONG_PTR pL;
|
||||||
|
} ip;
|
||||||
|
|
||||||
|
ReadProcVar( pBase, &DosHeader );
|
||||||
|
pNTHeader = (PIMAGE_NT_HEADERS)(pBase + DosHeader.e_lfanew);
|
||||||
|
ReadProcVar( pNTHeader, &NTHeader );
|
||||||
|
|
||||||
|
len = 4 * PTRSZ + ansi_len
|
||||||
|
+ sizeof(*pANSI_ImportDesc) + NTHeader.IMPORTDIR.Size;
|
||||||
|
pImports = malloc( len );
|
||||||
|
if (pImports == NULL)
|
||||||
|
{
|
||||||
|
DEBUGSTR( 1, L" Failed to allocate memory." );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pMem = FindMem( ppi->hProcess, pBase, len );
|
||||||
|
if (pMem == NULL)
|
||||||
|
{
|
||||||
|
DEBUGSTR( 1, L" Failed to allocate virtual memory." );
|
||||||
|
free( pImports );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
rva = (DWORD)((PBYTE)pMem - pBase);
|
||||||
|
|
||||||
|
ip.pL = (PLONG_PTR)pImports;
|
||||||
|
*ip.pL++ = IMAGE_ORDINAL_FLAG + 1;
|
||||||
|
*ip.pL++ = 0;
|
||||||
|
*ip.pL++ = IMAGE_ORDINAL_FLAG + 1;
|
||||||
|
*ip.pL++ = 0;
|
||||||
|
memcpy( ip.pB, ansi_dll, ansi_len );
|
||||||
|
ip.pB += ansi_len;
|
||||||
|
pANSI_ImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)ip.pB;
|
||||||
|
pANSI_ImportDesc->OriginalFirstThunk = rva + 2 * PTRSZ;
|
||||||
|
pANSI_ImportDesc->TimeDateStamp = 0;
|
||||||
|
pANSI_ImportDesc->ForwarderChain = 0;
|
||||||
|
pANSI_ImportDesc->Name = rva + 4 * PTRSZ;
|
||||||
|
pANSI_ImportDesc->FirstThunk = rva;
|
||||||
|
ReadProcMem( pBase + NTHeader.IMPORTDIR.VirtualAddress,
|
||||||
|
pANSI_ImportDesc + 1, NTHeader.IMPORTDIR.Size );
|
||||||
|
WriteProcMem( pMem, pImports, len );
|
||||||
|
free( pImports );
|
||||||
|
|
||||||
|
NTHeader.IMPORTDIR.VirtualAddress = rva + 4 * PTRSZ + ansi_len;
|
||||||
|
NTHeader.IMPORTDIR.Size += sizeof(*pANSI_ImportDesc);
|
||||||
|
|
||||||
|
// If there's no IAT, copy the IDT.
|
||||||
|
if (NTHeader.IATDIR.VirtualAddress == 0)
|
||||||
|
NTHeader.IATDIR = NTHeader.IMPORTDIR;
|
||||||
|
|
||||||
|
// Remove bound imports, so the updated import table is used.
|
||||||
|
NTHeader.BOUNDDIR.VirtualAddress = 0;
|
||||||
|
NTHeader.BOUNDDIR.Size = 0;
|
||||||
|
|
||||||
|
VirtProtVar( pNTHeader, PAGE_READWRITE );
|
||||||
|
WriteProcVar( pNTHeader, &NTHeader );
|
||||||
|
VirtProtVar( pNTHeader, pr );
|
||||||
|
|
||||||
|
// Remove the IL-only flag on a managed process.
|
||||||
|
if (NTHeader.COMDIR.VirtualAddress != 0 && NTHeader.COMDIR.Size != 0)
|
||||||
|
{
|
||||||
|
pComHeader = (PIMAGE_COR20_HEADER)(pBase + NTHeader.COMDIR.VirtualAddress);
|
||||||
|
ReadProcVar( pComHeader, &ComHeader );
|
||||||
|
if (ComHeader.Flags & COMIMAGE_FLAGS_ILONLY)
|
||||||
|
{
|
||||||
|
ComHeader.Flags &= ~COMIMAGE_FLAGS_ILONLY;
|
||||||
|
VirtProtVar( pComHeader, PAGE_READWRITE );
|
||||||
|
WriteProcVar( pComHeader, &ComHeader );
|
||||||
|
VirtProtVar( pComHeader, pr );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef _WIN64
|
||||||
|
void InjectDLL32( LPPROCESS_INFORMATION ppi, PBYTE pBase )
|
||||||
|
{
|
||||||
|
DWORD rva;
|
||||||
|
PVOID pMem;
|
||||||
|
DWORD len;
|
||||||
|
DWORD pr;
|
||||||
|
IMAGE_DOS_HEADER DosHeader;
|
||||||
|
IMAGE_NT_HEADERS32 NTHeader, *pNTHeader;
|
||||||
|
PIMAGE_IMPORT_DESCRIPTOR pImports, pANSI_ImportDesc;
|
||||||
|
IMAGE_COR20_HEADER ComHeader, *pComHeader;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
PBYTE pB;
|
||||||
|
PLONG pL;
|
||||||
|
} ip;
|
||||||
|
|
||||||
|
ReadProcVar( pBase, &DosHeader );
|
||||||
|
pNTHeader = (PIMAGE_NT_HEADERS32)(pBase + DosHeader.e_lfanew);
|
||||||
|
ReadProcVar( pNTHeader, &NTHeader );
|
||||||
|
|
||||||
|
len = 16 + ansi_len + sizeof(*pANSI_ImportDesc) + NTHeader.IMPORTDIR.Size;
|
||||||
|
pImports = malloc( len );
|
||||||
|
if (pImports == NULL)
|
||||||
|
{
|
||||||
|
DEBUGSTR( 1, L" Failed to allocate memory." );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pMem = FindMem( ppi->hProcess, pBase, len );
|
||||||
|
if (pMem == NULL)
|
||||||
|
{
|
||||||
|
DEBUGSTR( 1, L" Failed to allocate virtual memory." );
|
||||||
|
free( pImports );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
rva = (DWORD)((PBYTE)pMem - pBase);
|
||||||
|
|
||||||
|
ip.pL = (PLONG)pImports;
|
||||||
|
*ip.pL++ = IMAGE_ORDINAL_FLAG32 + 1;
|
||||||
|
*ip.pL++ = 0;
|
||||||
|
*ip.pL++ = IMAGE_ORDINAL_FLAG32 + 1;
|
||||||
|
*ip.pL++ = 0;
|
||||||
|
memcpy( ip.pB, ansi_dll, ansi_len );
|
||||||
|
ip.pB += ansi_len;
|
||||||
|
pANSI_ImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)ip.pB;
|
||||||
|
pANSI_ImportDesc->OriginalFirstThunk = rva + 8;
|
||||||
|
pANSI_ImportDesc->TimeDateStamp = 0;
|
||||||
|
pANSI_ImportDesc->ForwarderChain = 0;
|
||||||
|
pANSI_ImportDesc->Name = rva + 16;
|
||||||
|
pANSI_ImportDesc->FirstThunk = rva;
|
||||||
|
ReadProcMem( pBase + NTHeader.IMPORTDIR.VirtualAddress,
|
||||||
|
pANSI_ImportDesc + 1, NTHeader.IMPORTDIR.Size );
|
||||||
|
WriteProcMem( pMem, pImports, len );
|
||||||
|
free( pImports );
|
||||||
|
|
||||||
|
NTHeader.IMPORTDIR.VirtualAddress = rva + 16 + ansi_len;
|
||||||
|
NTHeader.IMPORTDIR.Size += sizeof(*pANSI_ImportDesc);
|
||||||
|
if (NTHeader.IATDIR.VirtualAddress == 0)
|
||||||
|
NTHeader.IATDIR = NTHeader.IMPORTDIR;
|
||||||
|
NTHeader.BOUNDDIR.VirtualAddress = 0;
|
||||||
|
NTHeader.BOUNDDIR.Size = 0;
|
||||||
|
VirtProtVar( pNTHeader, PAGE_READWRITE );
|
||||||
|
WriteProcVar( pNTHeader, &NTHeader );
|
||||||
|
VirtProtVar( pNTHeader, pr );
|
||||||
|
|
||||||
|
if (NTHeader.COMDIR.VirtualAddress != 0 && NTHeader.COMDIR.Size != 0)
|
||||||
|
{
|
||||||
|
pComHeader = (PIMAGE_COR20_HEADER)(pBase + NTHeader.COMDIR.VirtualAddress);
|
||||||
|
ReadProcVar( pComHeader, &ComHeader );
|
||||||
|
if (ComHeader.Flags & COMIMAGE_FLAGS_ILONLY)
|
||||||
|
{
|
||||||
|
ComHeader.Flags &= ~COMIMAGE_FLAGS_ILONLY;
|
||||||
|
VirtProtVar( pComHeader, PAGE_READWRITE );
|
||||||
|
WriteProcVar( pComHeader, &ComHeader );
|
||||||
|
VirtProtVar( pComHeader, pr );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
251
injdll32.c
251
injdll32.c
@ -1,251 +0,0 @@
|
|||||||
/*
|
|
||||||
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
|
|
||||||
#ifndef WOW64_CONTEXT_ALL
|
|
||||||
#include "wow64.h"
|
|
||||||
|
|
||||||
TWow64GetThreadContext Wow64GetThreadContext;
|
|
||||||
TWow64SetThreadContext Wow64SetThreadContext;
|
|
||||||
#define IMPORT_WOW64
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define CONTEXT WOW64_CONTEXT
|
|
||||||
#undef CONTEXT_CONTROL
|
|
||||||
#define CONTEXT_CONTROL WOW64_CONTEXT_CONTROL
|
|
||||||
#define GetThreadContext Wow64GetThreadContext
|
|
||||||
#define SetThreadContext Wow64SetThreadContext
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern DWORD LLW32r;
|
|
||||||
LPVOID kernel32_base;
|
|
||||||
PIMAGE_DOS_HEADER pDosHeader;
|
|
||||||
|
|
||||||
#define MakeVA( cast, offset ) (cast)((DWORD_PTR)pDosHeader + (DWORD)(offset))
|
|
||||||
|
|
||||||
int export_cmp( const void* a, const void* b )
|
|
||||||
{
|
|
||||||
return strcmp( (LPCSTR)a, MakeVA( LPCSTR, *(const PDWORD)b ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
Get the relative address of LoadLibraryW direct from kernel32.dll.
|
|
||||||
*/
|
|
||||||
BOOL get_LLW32r( void )
|
|
||||||
{
|
|
||||||
HMODULE kernel32;
|
|
||||||
TCHAR buf[MAX_PATH];
|
|
||||||
UINT len;
|
|
||||||
PIMAGE_NT_HEADERS32 pNTHeader;
|
|
||||||
PIMAGE_EXPORT_DIRECTORY pExportDir;
|
|
||||||
PDWORD fun_table, name_table;
|
|
||||||
PWORD ord_table;
|
|
||||||
PDWORD pLLW;
|
|
||||||
|
|
||||||
#ifdef _WIN64
|
|
||||||
len = GetSystemWow64Directory( buf, MAX_PATH );
|
|
||||||
#else
|
|
||||||
len = GetSystemDirectory( buf, MAX_PATH );
|
|
||||||
#endif
|
|
||||||
wcscpy( buf + len, L"\\kernel32.dll" );
|
|
||||||
kernel32 = LoadLibraryEx( buf, NULL, LOAD_LIBRARY_AS_IMAGE_RESOURCE );
|
|
||||||
if (kernel32 == NULL)
|
|
||||||
{
|
|
||||||
DEBUGSTR( 1, L"Unable to load 32-bit kernel32.dll!" );
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
// The handle uses low bits as flags, so strip 'em off.
|
|
||||||
pDosHeader = (PIMAGE_DOS_HEADER)((DWORD_PTR)kernel32 & ~0xFFFF);
|
|
||||||
pNTHeader = MakeVA( PIMAGE_NT_HEADERS32, pDosHeader->e_lfanew );
|
|
||||||
pExportDir = MakeVA( PIMAGE_EXPORT_DIRECTORY,
|
|
||||||
pNTHeader->OptionalHeader.
|
|
||||||
DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].
|
|
||||||
VirtualAddress );
|
|
||||||
|
|
||||||
fun_table = MakeVA( PDWORD, pExportDir->AddressOfFunctions );
|
|
||||||
name_table = MakeVA( PDWORD, pExportDir->AddressOfNames );
|
|
||||||
ord_table = MakeVA( PWORD, pExportDir->AddressOfNameOrdinals );
|
|
||||||
|
|
||||||
pLLW = bsearch( "LoadLibraryW", name_table, pExportDir->NumberOfNames,
|
|
||||||
sizeof(DWORD), export_cmp );
|
|
||||||
if (pLLW == NULL)
|
|
||||||
{
|
|
||||||
DEBUGSTR( 1, L"Could not find LoadLibraryW!" );
|
|
||||||
FreeLibrary( kernel32 );
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
LLW32r = fun_table[ord_table[pLLW - name_table]];
|
|
||||||
|
|
||||||
FreeLibrary( kernel32 );
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void InjectDLL32( LPPROCESS_INFORMATION ppi, LPCTSTR dll )
|
|
||||||
{
|
|
||||||
CONTEXT context;
|
|
||||||
DWORD ep;
|
|
||||||
BOOL eip;
|
|
||||||
LPVOID mem;
|
|
||||||
DWORD mem32;
|
|
||||||
DWORD pr;
|
|
||||||
DWORD LLW;
|
|
||||||
|
|
||||||
DWORD len;
|
|
||||||
#define CODESIZE 20
|
|
||||||
BYTE code[CODESIZE+TSIZE(MAX_PATH)];
|
|
||||||
union
|
|
||||||
{
|
|
||||||
PBYTE pB;
|
|
||||||
PDWORD pL;
|
|
||||||
} ip;
|
|
||||||
|
|
||||||
struct unicode_string
|
|
||||||
{
|
|
||||||
USHORT Length;
|
|
||||||
USHORT MaximumLength;
|
|
||||||
DWORD Buffer;
|
|
||||||
};
|
|
||||||
struct ldr_module // incomplete definition
|
|
||||||
{
|
|
||||||
DWORD next, prev;
|
|
||||||
DWORD baseAddress;
|
|
||||||
DWORD entryPoint;
|
|
||||||
DWORD sizeOfImage;
|
|
||||||
struct unicode_string fullDllName;
|
|
||||||
struct unicode_string baseDllName;
|
|
||||||
} ldr;
|
|
||||||
WCHAR basename[MAX_PATH];
|
|
||||||
|
|
||||||
#ifdef IMPORT_WOW64
|
|
||||||
if (Wow64GetThreadContext == 0)
|
|
||||||
{
|
|
||||||
#define GETPROC( proc ) proc = (T##proc)GetProcAddress( hKernel, #proc )
|
|
||||||
HMODULE hKernel = GetModuleHandle( L"kernel32.dll" );
|
|
||||||
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." );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
len = TSIZE(lstrlen( dll ) + 1);
|
|
||||||
if (len > TSIZE(MAX_PATH))
|
|
||||||
return;
|
|
||||||
CopyMemory( code + CODESIZE, dll, len );
|
|
||||||
len += CODESIZE;
|
|
||||||
|
|
||||||
context.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
|
|
||||||
GetThreadContext( ppi->hThread, &context );
|
|
||||||
mem = VirtualAllocEx( ppi->hProcess, NULL, len, MEM_COMMIT,
|
|
||||||
PAGE_READWRITE );
|
|
||||||
mem32 = (DWORD)(DWORD_PTR)mem;
|
|
||||||
|
|
||||||
ip.pB = code;
|
|
||||||
|
|
||||||
// Determine the base address of kernel32.dll. If injecting into the parent
|
|
||||||
// process, the base has already been determined. Otherwise, use the PEB to
|
|
||||||
// walk the loaded modules.
|
|
||||||
if (kernel32_base != 0)
|
|
||||||
{
|
|
||||||
ep = context.Eip;
|
|
||||||
eip = TRUE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// When a process is created suspended, EAX has the entry point and EBX
|
|
||||||
// points to the PEB.
|
|
||||||
if (!ReadProcessMemory( ppi->hProcess, UIntToPtr( context.Ebx + 0x0C ),
|
|
||||||
ip.pL, 4, NULL ))
|
|
||||||
{
|
|
||||||
DEBUGSTR( 1, L"Failed to read Ldr from PEB." );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ep = context.Eax;
|
|
||||||
eip = FALSE;
|
|
||||||
// In case we're a bit slow (which seems to be unlikely), set up an
|
|
||||||
// infinite loop as the entry point.
|
|
||||||
WriteProcessMemory( ppi->hProcess, mem, "\xEB\xFE", 2, NULL );
|
|
||||||
FlushInstructionCache( ppi->hProcess, mem, 2 );
|
|
||||||
context.Eax = mem32;
|
|
||||||
SetThreadContext( ppi->hThread, &context );
|
|
||||||
VirtualProtectEx( ppi->hProcess, mem, len, PAGE_EXECUTE, &pr );
|
|
||||||
// Now resume the thread, as the PEB hasn't even been created yet.
|
|
||||||
ResumeThread( ppi->hThread );
|
|
||||||
while (*ip.pL == 0)
|
|
||||||
{
|
|
||||||
Sleep( 0 );
|
|
||||||
ReadProcessMemory( ppi->hProcess, UIntToPtr( context.Ebx + 0x0C ),
|
|
||||||
ip.pL, 4, NULL );
|
|
||||||
}
|
|
||||||
// Read PEB_LDR_DATA.InInitializationOrderModuleList.Flink.
|
|
||||||
ReadProcessMemory( ppi->hProcess, UIntToPtr( *ip.pL + 0x1c ),
|
|
||||||
&ip.pL[1], 4, NULL );
|
|
||||||
// Sometimes we're so quick ntdll.dll is the only one present, so keep
|
|
||||||
// looping until kernel32.dll shows up.
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
ldr.next = ip.pL[1];
|
|
||||||
do
|
|
||||||
{
|
|
||||||
ReadProcessMemory( ppi->hProcess, UIntToPtr( ldr.next ),
|
|
||||||
&ldr, sizeof(ldr), NULL );
|
|
||||||
ReadProcessMemory( ppi->hProcess, UIntToPtr( ldr.baseDllName.Buffer ),
|
|
||||||
basename, ldr.baseDllName.MaximumLength, NULL );
|
|
||||||
if (_wcsicmp( basename, L"kernel32.dll" ) == 0)
|
|
||||||
{
|
|
||||||
kernel32_base = UIntToPtr( ldr.baseAddress );
|
|
||||||
goto gotit;
|
|
||||||
}
|
|
||||||
} while (ldr.next != *ip.pL + 0x1c);
|
|
||||||
}
|
|
||||||
gotit:
|
|
||||||
SuspendThread( ppi->hThread );
|
|
||||||
VirtualProtectEx( ppi->hProcess, mem, len, pr, &pr );
|
|
||||||
}
|
|
||||||
LLW = PtrToUint( kernel32_base ) + LLW32r;
|
|
||||||
kernel32_base = 0;
|
|
||||||
|
|
||||||
*ip.pB++ = 0x68; // push ep
|
|
||||||
*ip.pL++ = ep;
|
|
||||||
*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 );
|
|
||||||
VirtualProtectEx( ppi->hProcess, mem, len, PAGE_EXECUTE, &pr );
|
|
||||||
|
|
||||||
if (eip)
|
|
||||||
{
|
|
||||||
context.Eip = mem32;
|
|
||||||
SetThreadContext( ppi->hThread, &context );
|
|
||||||
}
|
|
||||||
}
|
|
243
injdll64.c
243
injdll64.c
@ -1,243 +0,0 @@
|
|||||||
/*
|
|
||||||
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"
|
|
||||||
|
|
||||||
extern DWORD LLW64r;
|
|
||||||
extern LPVOID kernel32_base;
|
|
||||||
extern PIMAGE_DOS_HEADER pDosHeader;
|
|
||||||
|
|
||||||
#define MakeVA( cast, offset ) (cast)((DWORD_PTR)pDosHeader + (DWORD)(offset))
|
|
||||||
|
|
||||||
extern int export_cmp( const void* a, const void* b );
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
Get the relative address of LoadLibraryW direct from kernel32.dll.
|
|
||||||
*/
|
|
||||||
BOOL get_LLW64r( void )
|
|
||||||
{
|
|
||||||
HMODULE kernel32;
|
|
||||||
TCHAR buf[MAX_PATH];
|
|
||||||
UINT len;
|
|
||||||
PIMAGE_NT_HEADERS pNTHeader;
|
|
||||||
PIMAGE_EXPORT_DIRECTORY pExportDir;
|
|
||||||
PDWORD fun_table, name_table;
|
|
||||||
PWORD ord_table;
|
|
||||||
PDWORD pLLW;
|
|
||||||
|
|
||||||
len = GetSystemDirectory( buf, MAX_PATH );
|
|
||||||
wcscpy( buf + len, L"\\kernel32.dll" );
|
|
||||||
kernel32 = LoadLibraryEx( buf, NULL, LOAD_LIBRARY_AS_IMAGE_RESOURCE );
|
|
||||||
if (kernel32 == NULL)
|
|
||||||
{
|
|
||||||
DEBUGSTR( 1, L"Unable to load 64-bit kernel32.dll!" );
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
// The handle uses low bits as flags, so strip 'em off.
|
|
||||||
pDosHeader = (PIMAGE_DOS_HEADER)((DWORD_PTR)kernel32 & ~0xFFFF);
|
|
||||||
pNTHeader = MakeVA( PIMAGE_NT_HEADERS, pDosHeader->e_lfanew );
|
|
||||||
pExportDir = MakeVA( PIMAGE_EXPORT_DIRECTORY,
|
|
||||||
pNTHeader->OptionalHeader.
|
|
||||||
DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].
|
|
||||||
VirtualAddress );
|
|
||||||
|
|
||||||
fun_table = MakeVA( PDWORD, pExportDir->AddressOfFunctions );
|
|
||||||
name_table = MakeVA( PDWORD, pExportDir->AddressOfNames );
|
|
||||||
ord_table = MakeVA( PWORD, pExportDir->AddressOfNameOrdinals );
|
|
||||||
|
|
||||||
pLLW = bsearch( "LoadLibraryW", name_table, pExportDir->NumberOfNames,
|
|
||||||
sizeof(DWORD), export_cmp );
|
|
||||||
if (pLLW == NULL)
|
|
||||||
{
|
|
||||||
DEBUGSTR( 1, L"Could not find LoadLibraryW!" );
|
|
||||||
FreeLibrary( kernel32 );
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
LLW64r = fun_table[ord_table[pLLW - name_table]];
|
|
||||||
|
|
||||||
FreeLibrary( kernel32 );
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void InjectDLL64( LPPROCESS_INFORMATION ppi, LPCTSTR dll )
|
|
||||||
{
|
|
||||||
CONTEXT context;
|
|
||||||
DWORD64 ep;
|
|
||||||
BOOL rip;
|
|
||||||
LPVOID mem;
|
|
||||||
DWORD pr;
|
|
||||||
DWORD64 LLW;
|
|
||||||
|
|
||||||
union
|
|
||||||
{
|
|
||||||
PBYTE pB;
|
|
||||||
PDWORD64 pL;
|
|
||||||
} ip;
|
|
||||||
|
|
||||||
struct unicode_string
|
|
||||||
{
|
|
||||||
USHORT Length;
|
|
||||||
USHORT MaximumLength;
|
|
||||||
DWORD64 Buffer;
|
|
||||||
};
|
|
||||||
struct ldr_module // incomplete definition
|
|
||||||
{
|
|
||||||
DWORD64 next, prev;
|
|
||||||
DWORD64 baseAddress;
|
|
||||||
DWORD64 entryPoint;
|
|
||||||
DWORD64 sizeOfImage;
|
|
||||||
struct unicode_string fullDllName;
|
|
||||||
struct unicode_string baseDllName;
|
|
||||||
} ldr;
|
|
||||||
WCHAR basename[MAX_PATH];
|
|
||||||
|
|
||||||
DWORD len;
|
|
||||||
#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 | CONTEXT_INTEGER;
|
|
||||||
GetThreadContext( ppi->hThread, &context );
|
|
||||||
mem = VirtualAllocEx( ppi->hProcess, NULL, len, MEM_COMMIT,
|
|
||||||
PAGE_READWRITE );
|
|
||||||
|
|
||||||
ip.pB = code;
|
|
||||||
|
|
||||||
// Determine the base address of kernel32.dll. If injecting into the parent
|
|
||||||
// process, the base has already been determined. Otherwise, use the PEB to
|
|
||||||
// walk the loaded modules.
|
|
||||||
if (kernel32_base != 0)
|
|
||||||
{
|
|
||||||
ep = context.Rip;
|
|
||||||
rip = TRUE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// When a process is created suspended, RCX has the entry point and RDX
|
|
||||||
// points to the PEB.
|
|
||||||
if (!ReadProcessMemory( ppi->hProcess, (LPVOID)(context.Rdx + 0x18),
|
|
||||||
ip.pL, 8, NULL ))
|
|
||||||
{
|
|
||||||
DEBUGSTR( 1, L"Failed to read Ldr from PEB." );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ep = context.Rcx;
|
|
||||||
rip = FALSE;
|
|
||||||
// In case we're a bit slow (which seems to be unlikely), set up an
|
|
||||||
// infinite loop as the entry point.
|
|
||||||
WriteProcessMemory( ppi->hProcess, (PBYTE)mem + 16, "\xEB\xFE", 2, NULL );
|
|
||||||
FlushInstructionCache( ppi->hProcess, (PBYTE)mem + 16, 2 );
|
|
||||||
context.Rcx = (DWORD64)mem + 16;
|
|
||||||
SetThreadContext( ppi->hThread, &context );
|
|
||||||
VirtualProtectEx( ppi->hProcess, mem, len, PAGE_EXECUTE, &pr );
|
|
||||||
// Now resume the thread, as the PEB hasn't even been created yet.
|
|
||||||
ResumeThread( ppi->hThread );
|
|
||||||
while (*ip.pL == 0)
|
|
||||||
{
|
|
||||||
Sleep( 0 );
|
|
||||||
ReadProcessMemory( ppi->hProcess, (LPVOID)(context.Rdx + 0x18),
|
|
||||||
ip.pL, 8, NULL );
|
|
||||||
}
|
|
||||||
// Read PEB_LDR_DATA.InInitializationOrderModuleList.Flink.
|
|
||||||
ReadProcessMemory( ppi->hProcess, (LPVOID)(*ip.pL + 0x30),
|
|
||||||
&ip.pL[1], 8, NULL );
|
|
||||||
// Sometimes we're so quick ntdll.dll is the only one present, so keep
|
|
||||||
// looping until kernel32.dll shows up.
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
ldr.next = ip.pL[1];
|
|
||||||
do
|
|
||||||
{
|
|
||||||
ReadProcessMemory( ppi->hProcess, (LPVOID)ldr.next,
|
|
||||||
&ldr, sizeof(ldr), NULL );
|
|
||||||
ReadProcessMemory( ppi->hProcess, (LPVOID)ldr.baseDllName.Buffer,
|
|
||||||
basename, ldr.baseDllName.MaximumLength, NULL );
|
|
||||||
if (_wcsicmp( basename, L"kernel32.dll" ) == 0)
|
|
||||||
{
|
|
||||||
kernel32_base = (LPVOID)ldr.baseAddress;
|
|
||||||
goto gotit;
|
|
||||||
}
|
|
||||||
} while (ldr.next != *ip.pL + 0x30);
|
|
||||||
}
|
|
||||||
gotit:
|
|
||||||
SuspendThread( ppi->hThread );
|
|
||||||
VirtualProtectEx( ppi->hProcess, mem, len, pr, &pr );
|
|
||||||
}
|
|
||||||
LLW = (DWORD64)kernel32_base + LLW64r;
|
|
||||||
kernel32_base = 0;
|
|
||||||
|
|
||||||
*ip.pL++ = ep;
|
|
||||||
*ip.pL++ = LLW;
|
|
||||||
|
|
||||||
WriteProcessMemory( ppi->hProcess, mem, code, len, NULL );
|
|
||||||
FlushInstructionCache( ppi->hProcess, mem, len );
|
|
||||||
VirtualProtectEx( ppi->hProcess, mem, len, PAGE_EXECUTE, &pr );
|
|
||||||
|
|
||||||
if (rip)
|
|
||||||
{
|
|
||||||
context.Rip = (DWORD64)mem + 16;
|
|
||||||
SetThreadContext( ppi->hThread, &context );
|
|
||||||
}
|
|
||||||
}
|
|
26
makefile.gcc
26
makefile.gcc
@ -16,13 +16,16 @@
|
|||||||
#
|
#
|
||||||
# Tested with:
|
# Tested with:
|
||||||
# * MinGW/gcc 4.7.2;
|
# * MinGW/gcc 4.7.2;
|
||||||
# * tdm-gcc-4.7.1-2;
|
# * tdm-gcc-4.8.1-3;
|
||||||
# * tdm64-gcc-4.7.1-3;
|
# * tdm64-gcc-4.8.1-3;
|
||||||
# * MinGW-builds x64-4.8.1-release-posix-seh-rev1.
|
# * MinGW-builds x64-4.8.1-release-posix-seh-rev1.
|
||||||
|
|
||||||
CC = gcc
|
CC = gcc
|
||||||
CFLAGS = -O2 -Wall
|
CFLAGS = -O2 -Wall
|
||||||
|
|
||||||
|
# Identify ansicon.exe using "ANSI" as a version number.
|
||||||
|
IVER = -Wl,--major-image-version,20033,--minor-image-version,18771
|
||||||
|
|
||||||
#ARCH = 32
|
#ARCH = 32
|
||||||
#ARCH = 64
|
#ARCH = 64
|
||||||
#ARCH = multi
|
#ARCH = multi
|
||||||
@ -41,8 +44,8 @@ endif
|
|||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
X86OBJS = x86/proctype.o x86/injdll32.o x86/util.o
|
X86OBJS = x86/proctype.o x86/injdll.o x86/util.o
|
||||||
X64OBJS = x64/proctype.o x64/injdll64.o x64/injdll32.o x64/util.o
|
X64OBJS = x64/proctype.o x64/injdll.o x64/util.o
|
||||||
|
|
||||||
# Determine the appropriate separator to run multiple commands - ";" for sh.exe
|
# Determine the appropriate separator to run multiple commands - ";" for sh.exe
|
||||||
# and "&" for CMD.EXE. $(SHELL) is initially defined to "sh.exe" - if it
|
# and "&" for CMD.EXE. $(SHELL) is initially defined to "sh.exe" - if it
|
||||||
@ -67,7 +70,7 @@ x86/%v.o: %.rc version.h
|
|||||||
$(RCmsg)windres -U _WIN64 -F pe-i386 $< $@
|
$(RCmsg)windres -U _WIN64 -F pe-i386 $< $@
|
||||||
|
|
||||||
x64/%.o: %.c ansicon.h
|
x64/%.o: %.c ansicon.h
|
||||||
$(CCmsg)$(CC) -m64 -c $(CFLAGS) $< -o $@
|
$(CCmsg)$(CC) -m64 -g -c $(CFLAGS) $< -o $@
|
||||||
|
|
||||||
x64/%v.o: %.rc version.h
|
x64/%v.o: %.rc version.h
|
||||||
$(RCmsg)windres -F pe-x86-64 $< $@
|
$(RCmsg)windres -F pe-x86-64 $< $@
|
||||||
@ -89,8 +92,8 @@ ansicon64: x64 x64/ansicon.exe x64/ANSI64.dll
|
|||||||
x86:
|
x86:
|
||||||
cmd /c "mkdir x86"
|
cmd /c "mkdir x86"
|
||||||
|
|
||||||
x86/ansicon.exe: x86/ansicon.o $(X86OBJS) x86/ansiconv.o
|
x86/ansicon.exe: x86/ansicon.o $(X86OBJS) x86/LLW.o x86/ansiconv.o
|
||||||
$(LDmsg)$(CC) -m32 $+ -s -o $@
|
$(LDmsg)$(CC) -m32 $+ -s -o $@ $(IVER)
|
||||||
|
|
||||||
x86/ANSI32.dll: x86/ANSI.o $(X86OBJS) x86/ansiv.o
|
x86/ANSI32.dll: x86/ANSI.o $(X86OBJS) x86/ansiv.o
|
||||||
$(LDmsg)$(CC) -m32 $+ -s -o $@ -mdll -Wl,-shared,--image-base,0xAC0000
|
$(LDmsg)$(CC) -m32 $+ -s -o $@ -mdll -Wl,-shared,--image-base,0xAC0000
|
||||||
@ -98,14 +101,15 @@ x86/ANSI32.dll: x86/ANSI.o $(X86OBJS) x86/ansiv.o
|
|||||||
x64:
|
x64:
|
||||||
cmd /c "mkdir x64"
|
cmd /c "mkdir x64"
|
||||||
|
|
||||||
x64/ansicon.exe: x64/ansicon.o $(X64OBJS) x64/ansiconv.o
|
x64/ansicon.exe: x64/ansicon.o $(X64OBJS) x64/LLW.o x64/ansiconv.o
|
||||||
$(LDmsg)$(CC) -m64 $+ -s -o $@
|
$(LDmsg)$(CC) -m64 $+ -s -o $@ $(IVER)
|
||||||
|
|
||||||
x64/ANSI64.dll: x64/ANSI.o $(X64OBJS) x64/ansiv.o
|
x64/ANSI64.dll: x64/ANSI.o $(X64OBJS) x64/ansiv.o
|
||||||
$(LDmsg)$(CC) -m64 $+ -s -o $@ -mdll -Wl,-shared,--image-base,0xAC000000
|
$(LDmsg)$(CC) -m64 $+ -s -o $@ -mdll -Wl,-shared,--image-base,0xAC000000
|
||||||
|
|
||||||
x64/ANSI32.dll: x64/ANSI32.o x64/proctype32.o x86/injdll32.o x86/util.o x86/ansiv.o
|
x64/ANSI32.dll: x64/ANSI32.o x64/proctype32.o x86/injdll.o x86/util.o x86/ansiv.o
|
||||||
$(LDmsg)$(CC) -m32 $+ -s -o $@ -mdll -Wl,-shared,--image-base,0xAC0000
|
$(LDmsg)$(CC) -m32 $+ -s -o $@ -mdll \
|
||||||
|
-Wl,-shared,--image-base,0xAC0000,--large-address-aware
|
||||||
|
|
||||||
x86/ansicon.o: version.h
|
x86/ansicon.o: version.h
|
||||||
x86/ANSI.o: version.h
|
x86/ANSI.o: version.h
|
||||||
|
31
makefile.vc
31
makefile.vc
@ -62,8 +62,11 @@ MT = mt.exe
|
|||||||
CFLAGS = /nologo /W3 /O2 $(SHARE) /D_CRT_SECURE_NO_WARNINGS
|
CFLAGS = /nologo /W3 /O2 $(SHARE) /D_CRT_SECURE_NO_WARNINGS
|
||||||
LIBS = advapi32.lib user32.lib $(LIBS64)
|
LIBS = advapi32.lib user32.lib $(LIBS64)
|
||||||
|
|
||||||
X86OBJS = x86\proctype.obj x86\injdll32.obj x86\util.obj
|
# Identify ansicon.exe using "ANSI" as a version number.
|
||||||
X64OBJS = x64\proctype.obj x64\injdll64.obj x64\injdll32.obj x64\util.obj
|
LINK = /link /version:20033.18771
|
||||||
|
|
||||||
|
X86OBJS = x86\proctype.obj x86\injdll.obj x86\util.obj
|
||||||
|
X64OBJS = x64\proctype.obj x64\injdll.obj x64\util.obj
|
||||||
|
|
||||||
!IF !DEFINED(V)
|
!IF !DEFINED(V)
|
||||||
V = 0
|
V = 0
|
||||||
@ -90,15 +93,16 @@ ansicon64: x64 x64\ansicon.exe x64\ANSI64.dll
|
|||||||
x86:
|
x86:
|
||||||
mkdir x86
|
mkdir x86
|
||||||
|
|
||||||
x86\ansicon.exe: x86\ansicon.obj $(X86OBJS) x86\ansicon.res
|
x86\ansicon.exe: x86\ansicon.obj $(X86OBJS) x86\LLW.obj x86\ansicon.res
|
||||||
$(LDmsg)$(CC) /nologo $(SHARE) /Fe$@ $** $(LIBS) /link /filealign:512
|
$(LDmsg)$(CC) /nologo $(SHARE) /Fe$@ $** $(LIBS) $(LINK) /filealign:512
|
||||||
!IF "$(_NMAKE_VER)" == "9.00.30729.01"
|
!IF "$(_NMAKE_VER)" == "9.00.30729.01"
|
||||||
$(MTmsg)$(MT) /nologo -manifest $@.manifest -outputresource:$@;1
|
$(MTmsg)$(MT) /nologo -manifest $@.manifest -outputresource:$@;1
|
||||||
@del $@.manifest
|
@del $@.manifest
|
||||||
!ENDIF
|
!ENDIF
|
||||||
|
|
||||||
x86\ANSI32.dll: x86\ANSI.obj $(X86OBJS) x86\ansi.res
|
x86\ANSI32.dll: x86\ANSI.obj $(X86OBJS) x86\ansi.res
|
||||||
$(LDmsg)$(CC) /nologo $(SHARE) /LD /Fe$@ $** $(LIBS) /link /base:0xAC0000 /section:.shared,s /filealign:512
|
$(LDmsg)$(CC) /nologo $(SHARE) /LD /Fe$@ $** $(LIBS) /link \
|
||||||
|
/base:0xAC0000 /section:.shared,s /filealign:512
|
||||||
!IF "$(_NMAKE_VER)" == "9.00.30729.01"
|
!IF "$(_NMAKE_VER)" == "9.00.30729.01"
|
||||||
$(MTmsg)$(MT) /nologo -manifest $@.manifest -outputresource:$@;2
|
$(MTmsg)$(MT) /nologo -manifest $@.manifest -outputresource:$@;2
|
||||||
@del $@.manifest
|
@del $@.manifest
|
||||||
@ -107,14 +111,16 @@ x86\ANSI32.dll: x86\ANSI.obj $(X86OBJS) x86\ansi.res
|
|||||||
x64:
|
x64:
|
||||||
mkdir x64
|
mkdir x64
|
||||||
|
|
||||||
x64\ansicon.exe: x64\ansicon.obj $(X64OBJS) x64\ansicon.res
|
x64\ansicon.exe: x64\ansicon.obj $(X64OBJS) x64\LLW.obj x64\ansicon.res
|
||||||
$(LDmsg)$(CC) /nologo $(SHARE) /Fe$@ $** $(LIBS)
|
$(LDmsg)$(CC) /nologo $(SHARE) /Fe$@ $** $(LIBS) $(LINK)
|
||||||
|
|
||||||
x64\ANSI64.dll: x64\ANSI.obj $(X64OBJS) x64\ansi.res
|
x64\ANSI64.dll: x64\ANSI.obj $(X64OBJS) x64\ansi.res
|
||||||
$(LDmsg)$(CC) /nologo $(SHARE) /LD /Fe$@ $** $(LIBS) /link /base:0xAC000000 /section:.shared,s
|
$(LDmsg)$(CC) /nologo $(SHARE) /LD /Fe$@ $** $(LIBS) /link \
|
||||||
|
/base:0xAC000000 /section:.shared,s
|
||||||
|
|
||||||
x64\ANSI32.dll: x64\ANSI32.obj x64\proctype32.obj x86\injdll32.obj x86\util.obj x86\ansi.res
|
x64\ANSI32.dll: x64\ANSI32.obj x64\proctype32.obj x86\injdll.obj x86\util.obj x86\ansi.res
|
||||||
$(LDmsg)$(CC) /nologo $(SHARE) /LD /Fe$@ $** $(LIBS) /link /base:0xAC0000 /section:.shared,s /filealign:512
|
$(LDmsg)$(CC) /nologo $(SHARE) /LD /Fe$@ $** $(LIBS) /link \
|
||||||
|
/base:0xAC0000 /section:.shared,s /filealign:512 /largeaddressaware
|
||||||
!IF "$(_NMAKE_VER)" == "9.00.30729.01"
|
!IF "$(_NMAKE_VER)" == "9.00.30729.01"
|
||||||
$(MTmsg)$(MT) /nologo -manifest $@.manifest -outputresource:$@;2
|
$(MTmsg)$(MT) /nologo -manifest $@.manifest -outputresource:$@;2
|
||||||
@del $@.manifest
|
@del $@.manifest
|
||||||
@ -125,12 +131,13 @@ ansicon.rc: version.h
|
|||||||
ANSI.c: ansicon.h version.h
|
ANSI.c: ansicon.h version.h
|
||||||
ANSI.rc: version.h
|
ANSI.rc: version.h
|
||||||
util.c: ansicon.h version.h
|
util.c: ansicon.h version.h
|
||||||
injdll32.c: ansicon.h
|
injdll.c: ansicon.h
|
||||||
injdll64.c: ansicon.h
|
|
||||||
proctype.c: ansicon.h
|
proctype.c: ansicon.h
|
||||||
|
LLW.c: ansicon.h
|
||||||
|
|
||||||
x64\ANSI32.obj: ANSI.c
|
x64\ANSI32.obj: ANSI.c
|
||||||
$(CCmsg)$(CC) /DW32ON64 /c $(CFLAGS) /Fo$@ $?
|
$(CCmsg)$(CC) /DW32ON64 /c $(CFLAGS) /Fo$@ $?
|
||||||
|
|
||||||
x64\proctype32.obj: proctype.c
|
x64\proctype32.obj: proctype.c
|
||||||
$(CCmsg)$(CC) /DW32ON64 /c $(CFLAGS) /Fo$@ $?
|
$(CCmsg)$(CC) /DW32ON64 /c $(CFLAGS) /Fo$@ $?
|
||||||
|
|
||||||
|
99
proctype.c
99
proctype.c
@ -1,76 +1,76 @@
|
|||||||
/*
|
/*
|
||||||
Test for a valid process. This may sometimes detect GUI, even for a console
|
Test for a valid process (i386 for x86; that or AMD64 for x64). We can get
|
||||||
process. I think this is due to a DLL being loaded in the address space
|
that info from the image header, which means getting the process's base
|
||||||
before the main image. Ideally I could just use the base address directly,
|
address (which we need anyway, to modify the imports). The simplest way to
|
||||||
but that doesn't seem easy to do for another process - there doesn't seem to
|
do that is to enumerate the pages, looking for an executable image.
|
||||||
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"
|
#include "ansicon.h"
|
||||||
|
|
||||||
|
|
||||||
int ProcessType( LPPROCESS_INFORMATION pinfo, BOOL* gui )
|
int ProcessType( LPPROCESS_INFORMATION ppi, PBYTE* pBase, BOOL* gui )
|
||||||
{
|
{
|
||||||
char* ptr;
|
PBYTE ptr;
|
||||||
MEMORY_BASIC_INFORMATION minfo;
|
MEMORY_BASIC_INFORMATION minfo;
|
||||||
IMAGE_DOS_HEADER dos_header;
|
IMAGE_DOS_HEADER dos_header;
|
||||||
IMAGE_NT_HEADERS nt_header;
|
IMAGE_NT_HEADERS nt_header;
|
||||||
SIZE_T read;
|
|
||||||
|
|
||||||
|
*pBase = NULL;
|
||||||
*gui = FALSE;
|
*gui = FALSE;
|
||||||
|
|
||||||
for (ptr = NULL;
|
for (ptr = NULL;
|
||||||
VirtualQueryEx( pinfo->hProcess, ptr, &minfo, sizeof(minfo) );
|
VirtualQueryEx( ppi->hProcess, ptr, &minfo, sizeof(minfo) );
|
||||||
ptr += minfo.RegionSize)
|
ptr += minfo.RegionSize)
|
||||||
{
|
{
|
||||||
if (minfo.BaseAddress == minfo.AllocationBase &&
|
if (minfo.BaseAddress == minfo.AllocationBase
|
||||||
ReadProcessMemory( pinfo->hProcess, minfo.AllocationBase,
|
&& ReadProcVar( minfo.BaseAddress, &dos_header )
|
||||||
&dos_header, sizeof(dos_header), &read ))
|
&& dos_header.e_magic == IMAGE_DOS_SIGNATURE
|
||||||
|
&& ReadProcVar( (PBYTE)minfo.BaseAddress + dos_header.e_lfanew,
|
||||||
|
&nt_header )
|
||||||
|
&& nt_header.Signature == IMAGE_NT_SIGNATURE
|
||||||
|
&& !(nt_header.FileHeader.Characteristics & IMAGE_FILE_DLL))
|
||||||
{
|
{
|
||||||
if (dos_header.e_magic == IMAGE_DOS_SIGNATURE)
|
// Don't load into ansicon.exe, it wants to do that itself.
|
||||||
{
|
if (nt_header.OptionalHeader.MajorImageVersion == 20033 &&
|
||||||
if (ReadProcessMemory( pinfo->hProcess, (char*)minfo.AllocationBase +
|
nt_header.OptionalHeader.MinorImageVersion == 18771)
|
||||||
dos_header.e_lfanew, &nt_header,
|
return -1;
|
||||||
sizeof(nt_header), &read ))
|
|
||||||
{
|
*pBase = minfo.BaseAddress;
|
||||||
if (nt_header.Signature == IMAGE_NT_SIGNATURE &&
|
if (nt_header.OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI)
|
||||||
(nt_header.FileHeader.Characteristics &
|
*gui = TRUE;
|
||||||
(IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DLL))
|
if (*gui ||
|
||||||
== IMAGE_FILE_EXECUTABLE_IMAGE)
|
nt_header.OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI)
|
||||||
{
|
|
||||||
*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)
|
if (nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_I386)
|
||||||
{
|
{
|
||||||
// Microsoft ignores precision on %p.
|
|
||||||
DEBUGSTR( 1, L" 32-bit %s (base = %.8X)",
|
DEBUGSTR( 1, L" 32-bit %s (base = %.8X)",
|
||||||
(*gui) ? L"GUI" : L"console",
|
(*gui) ? L"GUI" : L"console",
|
||||||
(DWORD)(DWORD_PTR)minfo.AllocationBase );
|
PtrToUint( minfo.BaseAddress ) );
|
||||||
return 32;
|
return 32;
|
||||||
}
|
}
|
||||||
|
if (nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64)
|
||||||
|
{
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
if (nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64)
|
DEBUGSTR( 1, L" 64-bit %s (base = %.8X_%.8X)",
|
||||||
{
|
(*gui) ? L"GUI" : L"console",
|
||||||
DEBUGSTR( 1, L" 64-bit %s (base = %p)",
|
(DWORD)((DWORD_PTR)minfo.BaseAddress >> 32),
|
||||||
(*gui) ? L"GUI" : L"console", minfo.AllocationBase );
|
PtrToUint( minfo.BaseAddress ) );
|
||||||
return 64;
|
return 64;
|
||||||
}
|
|
||||||
#elif defined(W32ON64)
|
#elif defined(W32ON64)
|
||||||
if (nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64)
|
// Console will log due to -P, but GUI may be ignored (if not,
|
||||||
{
|
// this'll show up twice).
|
||||||
DEBUGSTR( 1, L" 64-bit %s",
|
if (*gui)
|
||||||
(*gui) ? L"GUI" : L"console" );
|
DEBUGSTR( 1, L" 64-bit GUI (base = 00000000_%.8X)",
|
||||||
|
PtrToUint( minfo.BaseAddress ) );
|
||||||
return 64;
|
return 64;
|
||||||
}
|
#else
|
||||||
|
DEBUGSTR( 1, L" 64-bit %s (base = 00000000_%.8X)",
|
||||||
|
(*gui) ? L"GUI" : L"console",
|
||||||
|
PtrToUint( minfo.BaseAddress ) );
|
||||||
|
DEBUGSTR( 1, L" Unsupported (use x64\\ansicon)" );
|
||||||
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
DEBUGSTR( 1, L" Ignoring unsupported machine (0x%X)",
|
DEBUGSTR( 1, L" Ignoring unsupported machine (0x%X)",
|
||||||
nt_header.FileHeader.Machine );
|
nt_header.FileHeader.Machine );
|
||||||
}
|
}
|
||||||
@ -81,19 +81,16 @@ int ProcessType( LPPROCESS_INFORMATION pinfo, BOOL* gui )
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#ifndef _WIN64
|
#ifndef _WIN64
|
||||||
// If a 32-bit process loads a 64-bit one, we may miss the base
|
// If a 32-bit process loads a 64-bit one, we may miss the base
|
||||||
// address. If the pointer overflows, assume 64-bit.
|
// address. If the pointer overflows, assume 64-bit.
|
||||||
if (((DWORD)ptr >> 12) + ((DWORD)minfo.RegionSize >> 12) > 0x80000)
|
if (((DWORD)ptr >> 12) + ((DWORD)minfo.RegionSize >> 12) >= 0x100000)
|
||||||
{
|
{
|
||||||
#ifdef W32ON64
|
#ifdef W32ON64
|
||||||
DEBUGSTR( 1, L" Pointer overflow: assuming 64-bit console" );
|
DEBUGSTR( 1, L" Pointer overflow: assuming 64-bit" );
|
||||||
return 64;
|
return 64;
|
||||||
#else
|
#else
|
||||||
DEBUGSTR( 1, L" Ignoring apparent 64-bit process" );
|
DEBUGSTR( 1, L" Ignoring apparent 64-bit process (use x64\\ansicon)" );
|
||||||
return 0;
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
38
readme.txt
38
readme.txt
@ -1,9 +1,9 @@
|
|||||||
|
|
||||||
ANSICON
|
ANSICON
|
||||||
|
|
||||||
Copyright 2005-2013 Jason Hood
|
Copyright 2005-2014 Jason Hood
|
||||||
|
|
||||||
Version 1.66. Freeware
|
Version 1.70. Freeware
|
||||||
|
|
||||||
|
|
||||||
Description
|
Description
|
||||||
@ -17,7 +17,7 @@ Requirements
|
|||||||
============
|
============
|
||||||
|
|
||||||
32-bit: Windows 2000 Professional and later (it won't work with NT or 9X).
|
32-bit: Windows 2000 Professional and later (it won't work with NT or 9X).
|
||||||
64-bit: Vista and later (it won't work with XP64).
|
64-bit: AMD64 (IA64 could work with a little modification).
|
||||||
|
|
||||||
|
|
||||||
Installation
|
Installation
|
||||||
@ -93,10 +93,10 @@ Usage
|
|||||||
16 Log all imported modules (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
|
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
|
ANSICON_LOG (to the number) instead. The variable is only read once when a
|
||||||
started; changing it won't affect running processes. If you identify a
|
process is started; changing it won't affect running processes. If you
|
||||||
module that causes problems, add it to the ANSICON_EXC environment variable
|
identify a module that causes problems, add it to the ANSICON_EXC environ-
|
||||||
(see ANSICON_API below, but the extension is required).
|
ment variable (see ANSICON_API below, but the extension is required).
|
||||||
|
|
||||||
E.g.: 'ansicon -l5' will start a new command processor, logging every pro-
|
E.g.: 'ansicon -l5' will start a new command processor, logging every pro-
|
||||||
cess it starts along with their output.
|
cess it starts along with their output.
|
||||||
@ -264,12 +264,26 @@ Limitations
|
|||||||
|
|
||||||
ANSICON_EXC=nvd3d9wrap.dll;nvd3d9wrapx.dll
|
ANSICON_EXC=nvd3d9wrap.dll;nvd3d9wrapx.dll
|
||||||
|
|
||||||
|
An application using multiple screen buffers will not have separate
|
||||||
|
attributes in each buffer.
|
||||||
|
|
||||||
|
|
||||||
Version History
|
Version History
|
||||||
===============
|
===============
|
||||||
|
|
||||||
Legend: + added, - bug-fixed, * changed.
|
Legend: + added, - bug-fixed, * changed.
|
||||||
|
|
||||||
|
1.70 - 4 February, 2014:
|
||||||
|
- don't hook again if using LoadLibrary or LoadLibraryEx;
|
||||||
|
- update the LoadLibraryEx flags that shouldn't hook;
|
||||||
|
- restore original attributes on detach (for LoadLibrary/FreeLibrary usage);
|
||||||
|
- ansicon.exe will start with ANSICON_DEF (if defined and -m not used);
|
||||||
|
- an installed ansicon.exe will restore current (not default) attributes;
|
||||||
|
* inject into a created process by modifying the import descriptor table
|
||||||
|
(use CreateRemoteThread for -p);
|
||||||
|
* log: remove the quotes around the CreateProcess command line;
|
||||||
|
add an underscore in 64-bit addresses to distinguish 8-digit groups.
|
||||||
|
|
||||||
1.66 - 20 September, 2013:
|
1.66 - 20 September, 2013:
|
||||||
- fix 32-bit process trying to detect 64-bit process.
|
- fix 32-bit process trying to detect 64-bit process.
|
||||||
|
|
||||||
@ -442,12 +456,6 @@ Contact
|
|||||||
http://ansicon.adoxa.vze.com/
|
http://ansicon.adoxa.vze.com/
|
||||||
https://github.com/adoxa/ansicon
|
https://github.com/adoxa/ansicon
|
||||||
|
|
||||||
Jason Hood
|
|
||||||
11 Buckle Street
|
|
||||||
North Rockhampton
|
|
||||||
Qld 4701
|
|
||||||
Australia
|
|
||||||
|
|
||||||
|
|
||||||
Distribution
|
Distribution
|
||||||
============
|
============
|
||||||
@ -461,5 +469,5 @@ Distribution
|
|||||||
in LICENSE.txt.
|
in LICENSE.txt.
|
||||||
|
|
||||||
|
|
||||||
===============================
|
=============================
|
||||||
Jason Hood, 20 September, 2013.
|
Jason Hood, 4 February, 2014.
|
||||||
|
50
util.c
50
util.c
@ -8,9 +8,14 @@
|
|||||||
|
|
||||||
TCHAR prog_path[MAX_PATH];
|
TCHAR prog_path[MAX_PATH];
|
||||||
LPTSTR prog;
|
LPTSTR prog;
|
||||||
|
|
||||||
int log_level;
|
int log_level;
|
||||||
char tempfile[MAX_PATH];
|
|
||||||
DWORD pid;
|
char ansi_dll[MAX_PATH];
|
||||||
|
DWORD ansi_len;
|
||||||
|
#ifdef _WIN64
|
||||||
|
char* ansi_bits;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// Get just the name of the program: "C:\path\program.exe" -> "program".
|
// Get just the name of the program: "C:\path\program.exe" -> "program".
|
||||||
@ -37,8 +42,46 @@ LPTSTR get_program_name( LPTSTR program )
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Get the ANSI path of the DLL for the import. If it can't be converted,
|
||||||
|
// just use the name and hope it's on the PATH. Returns the length of the
|
||||||
|
// path/name, including padding to make it dword-aligned. The 64-bit version
|
||||||
|
// expects ansi_bits to point to the size within dll on entry.
|
||||||
|
void set_ansi_dll( LPTSTR dll )
|
||||||
|
{
|
||||||
|
BOOL bad;
|
||||||
|
|
||||||
|
ansi_len = WideCharToMultiByte( CP_ACP, WC_NO_BEST_FIT_CHARS, dll, -1,
|
||||||
|
NULL, 0, NULL, &bad );
|
||||||
|
if (bad || ansi_len > MAX_PATH)
|
||||||
|
{
|
||||||
|
ansi_len = 12;
|
||||||
|
memcpy( ansi_dll, "ANSI32.dll\0", 12 );
|
||||||
|
#ifdef _WIN64
|
||||||
|
if (*ansi_bits == '6')
|
||||||
|
{
|
||||||
|
ansi_dll[4] = '6';
|
||||||
|
ansi_dll[5] = '4';
|
||||||
|
}
|
||||||
|
ansi_bits = ansi_dll + 4;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WideCharToMultiByte( CP_ACP, WC_NO_BEST_FIT_CHARS, dll, -1,
|
||||||
|
ansi_dll, MAX_PATH, NULL, NULL );
|
||||||
|
#ifdef _WIN64
|
||||||
|
ansi_bits = ansi_dll + ansi_len - 7;
|
||||||
|
#endif
|
||||||
|
ansi_len = (ansi_len + 3) & ~3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void DEBUGSTR( int level, LPTSTR szFormat, ... )
|
void DEBUGSTR( int level, LPTSTR szFormat, ... )
|
||||||
{
|
{
|
||||||
|
static char tempfile[MAX_PATH];
|
||||||
|
static DWORD pid;
|
||||||
|
|
||||||
TCHAR szBuffer[1024], szEscape[1024];
|
TCHAR szBuffer[1024], szEscape[1024];
|
||||||
va_list pArgList;
|
va_list pArgList;
|
||||||
HANDLE mutex;
|
HANDLE mutex;
|
||||||
@ -55,6 +98,7 @@ void DEBUGSTR( int level, LPTSTR szFormat, ... )
|
|||||||
}
|
}
|
||||||
if (szFormat == NULL)
|
if (szFormat == NULL)
|
||||||
{
|
{
|
||||||
|
// Explicitly use 't', as _fmode might be binary.
|
||||||
file = fopen( tempfile, (log_level & 8) ? "at" : "wt" );
|
file = fopen( tempfile, (log_level & 8) ? "at" : "wt" );
|
||||||
if (file != NULL)
|
if (file != NULL)
|
||||||
{
|
{
|
||||||
@ -116,7 +160,7 @@ void DEBUGSTR( int level, LPTSTR szFormat, ... )
|
|||||||
|
|
||||||
mutex = CreateMutex( NULL, FALSE, L"ANSICON_debug_file" );
|
mutex = CreateMutex( NULL, FALSE, L"ANSICON_debug_file" );
|
||||||
wait = WaitForSingleObject( mutex, 500 );
|
wait = WaitForSingleObject( mutex, 500 );
|
||||||
file = fopen( tempfile, "at" ); // _fmode might be binary
|
file = fopen( tempfile, "at" );
|
||||||
if (file != NULL)
|
if (file != NULL)
|
||||||
{
|
{
|
||||||
fwprintf( file, L"%s (%lu): %s\n", prog, pid, szFormat );
|
fwprintf( file, L"%s (%lu): %s\n", prog, pid, szFormat );
|
||||||
|
10
version.h
10
version.h
@ -2,11 +2,11 @@
|
|||||||
version.h - Version defines.
|
version.h - Version defines.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define PVERS L"1.67" // wide string
|
#define PVERS L"1.70" // wide string
|
||||||
#define PVERSA "1.67" // ANSI string (windres 2.16.91 didn't like L)
|
#define PVERSA "1.70" // ANSI string (windres 2.16.91 didn't like L)
|
||||||
#define PVERE L"167" // wide environment string
|
#define PVERE L"170" // wide environment string
|
||||||
#define PVEREA "167" // ANSI environment string
|
#define PVEREA "170" // ANSI environment string
|
||||||
#define PVERB 1,6,7,0 // binary (resource)
|
#define PVERB 1,7,0,0 // binary (resource)
|
||||||
|
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
# define BITS L"64"
|
# define BITS L"64"
|
||||||
|
88
wow64.h
88
wow64.h
@ -1,88 +0,0 @@
|
|||||||
/*
|
|
||||||
wow64.h - Definitions for Wow64.
|
|
||||||
|
|
||||||
The 2003 Platform SDK 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
|
|
Loading…
x
Reference in New Issue
Block a user