Skip to content

Commit 33ba31a

Browse files
committed
Remove dependence on the CRT; import DLL; fixes
Windows 10's MSVCRT will only work if the Win32 version in the header is 0 or 10. Some PE's use it for something else, so when the DLL is injected the process fails. Provide custom routines for the C functions used, so the DLL only depends on KERNEL32. With the DLL independent of the CRT that would mean the exe would either also need to be independent, or the source files would need to be built twice (or just remove a linker warning). Another option is to export the functions from the DLL and have the exe import them, which turned out to simplify things quite nicely. A process that has a really long command line would not log properly, so double the heap to accommodate it. If ANSICON_DEF could not be parsed the default attribute would be zero (black on black). Use 7 or -7 instead.
1 parent f8509c9 commit 33ba31a

9 files changed

+579
-312
lines changed

ANSI.c

+148-116
Large diffs are not rendered by default.

ansicon.c

+33-117
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,12 @@
8989
v1.80, 28 October & 30 November, 2017:
9090
write newline with _putws, not putwchar (fixes redirecting to CON);
9191
use -pu to unload from the parent.
92+
93+
v1.84, 7 May, 2018:
94+
import the DLL.
9295
*/
9396

94-
#define PDATE L"4 May, 2018"
97+
#define PDATE L"7 May, 2018"
9598

9699
#include "ansicon.h"
97100
#include "version.h"
@@ -128,25 +131,6 @@ BOOL GetParentProcessInfo( LPPROCESS_INFORMATION ppi, LPTSTR );
128131

129132

130133
static HANDLE hConOut;
131-
static WORD wAttr;
132-
133-
void get_original_attr( void )
134-
{
135-
CONSOLE_SCREEN_BUFFER_INFO csbi;
136-
137-
hConOut = CreateFile( L"CONOUT$", GENERIC_READ | GENERIC_WRITE,
138-
FILE_SHARE_READ | FILE_SHARE_WRITE,
139-
NULL, OPEN_EXISTING, 0, 0 );
140-
GetConsoleScreenBufferInfo( hConOut, &csbi );
141-
wAttr = csbi.wAttributes;
142-
}
143-
144-
145-
void set_original_attr( void )
146-
{
147-
SetConsoleTextAttribute( hConOut, wAttr );
148-
CloseHandle( hConOut );
149-
}
150134

151135

152136
// The fputws function in MSVCRT.DLL (Windows 7 x64) is broken for Unicode
@@ -172,53 +156,6 @@ int my_fputws( const wchar_t* s, FILE* f )
172156
#define _putws( s ) my_fputws( s L"\n", stdout )
173157

174158

175-
HANDLE hHeap;
176-
#if defined(_WIN64)
177-
LPTSTR DllNameType;
178-
#endif
179-
180-
// Find the name of the DLL and inject it.
181-
BOOL Inject( LPPROCESS_INFORMATION ppi, BOOL* gui, LPCTSTR app )
182-
{
183-
DWORD len;
184-
int type;
185-
PBYTE base;
186-
187-
#ifdef _WIN64
188-
if (app != NULL)
189-
#endif
190-
DEBUGSTR( 1, "%S (%u)", app, ppi->dwProcessId );
191-
type = ProcessType( ppi, &base, gui );
192-
if (type <= 0)
193-
{
194-
if (type == 0)
195-
fwprintf( stderr, L"ANSICON: %s: unsupported process.\n", app );
196-
return FALSE;
197-
}
198-
199-
len = (DWORD)(prog - prog_path);
200-
memcpy( DllName, prog_path, TSIZE(len) );
201-
#ifdef _WIN64
202-
_snwprintf( DllName + len, MAX_PATH-1 - len,
203-
L"ANSI%d.dll", (type == 48) ? 64 : type );
204-
DllNameType = DllName + len + 4;
205-
set_ansi_dll();
206-
if (type == 64)
207-
InjectDLL( ppi, base );
208-
else if (type == 32)
209-
InjectDLL32( ppi, base );
210-
else // (type == 48)
211-
RemoteLoad64( ppi );
212-
#else
213-
wcscpy( DllName + len, L"ANSI32.dll" );
214-
set_ansi_dll();
215-
InjectDLL( ppi, base );
216-
#endif
217-
218-
return TRUE;
219-
}
220-
221-
222159
// Use CreateRemoteThread to (un)load our DLL in the target process.
223160
void RemoteLoad( LPPROCESS_INFORMATION ppi, LPCTSTR app, BOOL unload )
224161
{
@@ -227,7 +164,6 @@ void RemoteLoad( LPPROCESS_INFORMATION ppi, LPCTSTR app, BOOL unload )
227164
PBYTE proc;
228165
DWORD rva;
229166
BOOL fOk;
230-
DWORD len;
231167
LPVOID param;
232168
HANDLE thread;
233169
DWORD ticks;
@@ -236,7 +172,7 @@ void RemoteLoad( LPPROCESS_INFORMATION ppi, LPCTSTR app, BOOL unload )
236172
int type;
237173
#endif
238174

239-
DEBUGSTR( 1, "%S (%u)", app, ppi->dwProcessId );
175+
DEBUGSTR( 1, "Parent = %S (%u)", app, ppi->dwProcessId );
240176

241177
// Find the base address of kernel32.dll.
242178
ticks = GetTickCount();
@@ -266,29 +202,35 @@ void RemoteLoad( LPPROCESS_INFORMATION ppi, LPCTSTR app, BOOL unload )
266202
return;
267203
}
268204
proc = param = NULL;
269-
len = (DWORD)(prog - prog_path);
270-
memcpy( DllName, prog_path, TSIZE(len) );
271205
#ifdef _WIN64
272-
type = (IsWow64Process( ppi->hProcess, &WOW64 ) && WOW64) ? 32 : 64;
273-
_snwprintf( DllName + len, MAX_PATH-1 - len, L"ANSI%d.dll", type );
206+
type = 64;
207+
if (IsWow64Process( ppi->hProcess, &WOW64 ) && WOW64)
208+
{
209+
type = 32;
210+
*(PDWORD)DllNameType = 0x320033/*L'23'*/;
211+
}
274212
#endif
275213
me.dwSize = sizeof(MODULEENTRY32);
276214
for (fOk = Module32First( hSnap, &me ); fOk; fOk = Module32Next( hSnap, &me ))
277215
{
278216
if (_wcsicmp( me.szModule, L"kernel32.dll" ) == 0)
279217
{
280218
proc = me.modBaseAddr;
281-
if (!unload)
219+
if (!unload || param)
282220
break;
283221
}
284222
else if (unload)
285223
{
286224
#ifdef _WIN64
287-
if (_wcsicmp( me.szModule, DllName + len ) == 0)
225+
if (_wcsicmp( me.szModule, DllNameType - 4 ) == 0)
288226
#else
289227
if (_wcsicmp( me.szModule, L"ANSI32.dll" ) == 0)
290228
#endif
229+
{
291230
param = me.modBaseAddr;
231+
if (proc)
232+
break;
233+
}
292234
}
293235
}
294236
CloseHandle( hSnap );
@@ -307,7 +249,6 @@ void RemoteLoad( LPPROCESS_INFORMATION ppi, LPCTSTR app, BOOL unload )
307249
rva = GetProcRVA( L"kernel32.dll", (unload) ? "FreeLibrary"
308250
: "LoadLibraryW", type );
309251
#else
310-
wcscpy( DllName + len, L"ANSI32.dll" );
311252
rva = GetProcRVA( L"kernel32.dll", unload ? "FreeLibrary" : "LoadLibraryW" );
312253
#endif
313254
if (rva == 0)
@@ -316,13 +257,14 @@ void RemoteLoad( LPPROCESS_INFORMATION ppi, LPCTSTR app, BOOL unload )
316257

317258
if (!unload)
318259
{
260+
DWORD len = TSIZE((DWORD)wcslen( DllName ) + 1);
319261
param = VirtualAllocEx(ppi->hProcess, NULL, len, MEM_COMMIT,PAGE_READWRITE);
320262
if (param == NULL)
321263
{
322264
DEBUGSTR(1, " Failed to allocate virtual memory (%u)", GetLastError());
323265
goto no_go;
324266
}
325-
WriteProcMem( param, DllName, TSIZE(len + 11) );
267+
WriteProcMem( param, DllName, len );
326268
}
327269
thread = CreateRemoteThread( ppi->hProcess, NULL, 4096,
328270
(LPTHREAD_START_ROUTINE)proc, param, 0, NULL );
@@ -346,7 +288,6 @@ int main( void )
346288
LPTSTR argv, arg, cmd;
347289
TCHAR buf[4];
348290
BOOL shell, run, gui;
349-
HMODULE ansi;
350291
DWORD len;
351292
int rc = 0;
352293

@@ -361,7 +302,9 @@ int main( void )
361302
_setmode( 2, _O_U16TEXT);
362303

363304
// Create a console handle and store the current attributes.
364-
get_original_attr();
305+
hConOut = CreateFile( L"CONOUT$", GENERIC_READ | GENERIC_WRITE,
306+
FILE_SHARE_READ | FILE_SHARE_WRITE,
307+
NULL, OPEN_EXISTING, 0, 0 );
365308

366309
argv = GetCommandLine();
367310
len = (DWORD)wcslen( argv ) + 1;
@@ -386,9 +329,6 @@ int main( void )
386329
}
387330
}
388331

389-
hHeap = HeapCreate( 0, 0, 65 * 1024 );
390-
391-
prog = get_program_name( NULL );
392332
*buf = '\0';
393333
GetEnvironmentVariable( L"ANSICON_LOG", buf, lenof(buf) );
394334
log_level = _wtoi( buf );
@@ -405,7 +345,12 @@ int main( void )
405345
}
406346
else
407347
{
408-
Inject( &pi, &gui, NULL );
348+
PBYTE base;
349+
DEBUGSTR( 1, "64-bit process (%u) started by 32-bit", pi.dwProcessId );
350+
if (ProcessType( &pi, &base, NULL ) == 48)
351+
RemoteLoad64( &pi );
352+
else
353+
InjectDLL( &pi, base );
409354
CloseHandle( pi.hProcess );
410355
}
411356
return 0;
@@ -456,20 +401,8 @@ int main( void )
456401
}
457402

458403
case 'm':
459-
{
460-
int a = wcstol( arg + 2, NULL, 16 );
461-
if (a == 0)
462-
a = (arg[2] == '-') ? -7 : 7;
463-
if (a < 0)
464-
{
465-
SetEnvironmentVariable( L"ANSICON_REVERSE", L"1" );
466-
a = -a;
467-
a = ((a >> 4) & 15) | ((a & 15) << 4);
468-
}
469-
SetConsoleTextAttribute( hConOut, (WORD)a );
470-
SetEnvironmentVariable( L"ANSICON_DEF", NULL );
404+
SetEnvironmentVariable( L"ANSICON_DEF", arg[2] ? arg + 2 : L"7" );
471405
break;
472-
}
473406

474407
case 'e':
475408
case 'E':
@@ -494,13 +427,7 @@ int main( void )
494427
}
495428

496429
// Ensure the default attributes are the current attributes.
497-
if (GetEnvironmentVariable( L"ANSICON_DEF", buf, lenof(buf) ) != 0)
498-
{
499-
int a = wcstol( buf, NULL, 16 );
500-
if (a < 0)
501-
a = ((-a >> 4) & 15) | ((-a & 15) << 4);
502-
SetConsoleTextAttribute( hConOut, (WORD)a );
503-
}
430+
WriteConsole( hConOut, L"\33[m", 3, &len, NULL );
504431

505432
if (run)
506433
{
@@ -518,11 +445,9 @@ int main( void )
518445

519446
ZeroMemory( &si, sizeof(si) );
520447
si.cb = sizeof(si);
521-
if (CreateProcess( NULL, cmd, NULL, NULL, TRUE, CREATE_SUSPENDED,
522-
NULL, NULL, &si, &pi ))
448+
if (CreateProcess( NULL, cmd, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi ))
523449
{
524-
Inject( &pi, &gui, arg );
525-
ResumeThread( pi.hThread );
450+
ProcessType( &pi, NULL, &gui );
526451
if (!gui)
527452
{
528453
SetConsoleCtrlHandler( (PHANDLER_ROUTINE)CtrlHandler, TRUE );
@@ -540,13 +465,7 @@ int main( void )
540465
}
541466
else if (*arg)
542467
{
543-
ansi = LoadLibrary( ANSIDLL );
544-
if (ansi == NULL)
545-
{
546-
print_error( ANSIDLL );
547-
rc = 1;
548-
}
549-
else if (*arg == 'e' || *arg == 'E')
468+
if (*arg == 'e' || *arg == 'E')
550469
{
551470
cmd += 2;
552471
if (*cmd == ' ' || *cmd == '\t')
@@ -574,11 +493,8 @@ int main( void )
574493
get_file( arg, &argv, &cmd );
575494
} while (*arg);
576495
}
577-
FreeLibrary( ansi );
578496
}
579497

580-
set_original_attr();
581-
582498
return rc;
583499
}
584500

ansicon.h

+37-9
Original file line numberDiff line numberDiff line change
@@ -83,34 +83,62 @@ typedef struct IMAGE_COR20_HEADER
8383
#define VirtProtVar(a, b) VirtualProtectEx( ppi->hProcess, a, sizeof(*(a)), b, &pr )
8484

8585

86-
int ProcessType( LPPROCESS_INFORMATION, PBYTE*, BOOL* );
86+
#ifdef PDATE // i.e. from ansicon.c
87+
#define EXTERN __declspec(dllimport) extern
88+
#else
89+
#define EXTERN __declspec(dllexport) extern
90+
#endif
91+
92+
EXTERN int ProcessType( LPPROCESS_INFORMATION, PBYTE*, BOOL* );
8793
BOOL Wow64Process( HANDLE );
8894

95+
#ifdef _WIN64
96+
EXTERN
97+
#endif
8998
void InjectDLL( LPPROCESS_INFORMATION, PBYTE );
9099
void RemoteLoad32( LPPROCESS_INFORMATION );
91100
#ifdef _WIN64
92101
void InjectDLL32( LPPROCESS_INFORMATION, PBYTE );
93-
void RemoteLoad64( LPPROCESS_INFORMATION );
94-
DWORD GetProcRVA( LPCTSTR, LPCSTR, int );
102+
EXTERN void RemoteLoad64( LPPROCESS_INFORMATION );
103+
EXTERN DWORD GetProcRVA( LPCTSTR, LPCSTR, int );
95104
#else
96-
DWORD GetProcRVA( LPCTSTR, LPCSTR );
105+
EXTERN DWORD GetProcRVA( LPCTSTR, LPCSTR );
97106
#endif
98107

99108
extern HANDLE hHeap;
100109

101-
extern TCHAR prog_path[MAX_PATH];
110+
EXTERN TCHAR prog_path[MAX_PATH];
102111
extern LPTSTR prog;
103112
LPTSTR get_program_name( LPTSTR );
104113

105-
extern TCHAR DllName[MAX_PATH];
106-
extern LPTSTR DllNameType;
114+
EXTERN TCHAR DllName[MAX_PATH];
115+
EXTERN LPTSTR DllNameType;
107116
extern char ansi_dll[MAX_PATH];
108117
extern DWORD ansi_len;
109118
extern char* ansi_bits;
110119
void set_ansi_dll( void );
111120
DWORD get_os_version( void );
112121

113-
extern int log_level;
114-
void DEBUGSTR( int level, LPCSTR szFormat, ... );
122+
EXTERN int log_level;
123+
EXTERN void DEBUGSTR( int level, LPCSTR szFormat, ... );
124+
125+
// Replacements for C runtime functions.
126+
#undef RtlFillMemory
127+
#undef RtlMoveMemory
128+
#undef RtlZeroMemory
129+
void WINAPI RtlFillMemory( PVOID, SIZE_T, BYTE );
130+
void WINAPI RtlMoveMemory( PVOID, const VOID*, SIZE_T );
131+
void WINAPI RtlZeroMemory( PVOID, SIZE_T );
132+
133+
#define arrcpy( dst, src ) RtlMoveMemory( dst, src, sizeof(dst) )
134+
135+
unsigned long ac_wcstoul( const wchar_t*, wchar_t**, int );
136+
int ac_wtoi( const wchar_t* );
137+
long ac_wcstol( const wchar_t*, wchar_t**, int );
138+
wchar_t* ac_wcspbrk( const wchar_t*, const wchar_t* );
139+
wchar_t* ac_wcsrchr( const wchar_t*, wchar_t );
140+
int ac_strnicmp( const char*, const char*, size_t );
141+
int ac_sprintf( char*, const char*, ... );
142+
int ac_wprintf( wchar_t*, const char*, ... );
115143

116144
#endif

0 commit comments

Comments
 (0)