From 852db64d916da83c808f06f4e7401c6a5fcc1a78 Mon Sep 17 00:00:00 2001 From: Jason Hood Date: Mon, 30 Apr 2018 11:06:18 +1000 Subject: [PATCH] Dynamically load WINMM, remove USER32 Prevent loading more libraries than necessary, so load WINMM the first time the bell is used and use the CRT printf functions to avoid loading USER32 at all. I was also going to remove MSVCRT, but that turned out to be more trouble than it's worth. However, a side-effect that I kept is replacing bsearch with a dedicated search routine. --- ANSI.c | 51 +++++++++++++++++++++++++++++++++++---------------- ansicon.c | 7 ++++--- makefile.vc | 5 +++-- procrva.c | 34 +++++++++++++++++++--------------- readme.txt | 9 +++++---- util.c | 42 ++++++++++++++++++++++++------------------ 6 files changed, 90 insertions(+), 58 deletions(-) diff --git a/ANSI.c b/ANSI.c index 5c7a0c6..18f66c8 100644 --- a/ANSI.c +++ b/ANSI.c @@ -197,17 +197,24 @@ v1.83, 16 February, 2018: create the flush thread on first use. - v1.84-wip, 17 February, 2018: - close the flush handles on detach. + v1.84-wip, 17 February, 26 to 30 April, 2018: + close the flush handles on detach; + dynamically load WINMM.DLL; + use sprintf/_snprintf/_snwprintf instead of wsprintf, avoiding USER32.DLL; + replace bsearch (in procrva.c) with specific code. */ #include "ansicon.h" #include "version.h" -#include +#include #ifndef SND_SENTRY #define SND_SENTRY 0x80000 #endif +#undef PlaySound +typedef BOOL (WINAPI *FnPlaySound)( LPCWSTR, HMODULE, DWORD ); +FnPlaySound PlaySound; +HMODULE winmm; #define is_digit(c) ('0' <= (c) && (c) <= '9') @@ -483,7 +490,7 @@ void get_state( void ) valid_state = TRUE; - wsprintf( buf, L"ANSICON_State_%X", PtrToUint( hwnd ) ); + _snwprintf( buf, lenof(buf), L"ANSICON_State_%X", PtrToUint( hwnd ) ); hMap = CreateFileMapping( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(STATE), buf ); init = (GetLastError() != ERROR_ALREADY_EXISTS); @@ -552,7 +559,7 @@ void get_state( void ) *a++ = '-'; ATTR = ((ATTR >> 4) & 15) | ((ATTR & 15) << 4); } - wsprintf( a, L"%X", ATTR & 255 ); + _snwprintf( a, 3, L"%X", ATTR & 255 ); SetEnvironmentVariable( L"ANSICON_DEF", def ); } set_ansicon( &Info ); @@ -1018,9 +1025,9 @@ void send_palette_sequence( COLORREF c ) g = GetGValue( c ); b = GetBValue( c ); if ((c & 0x0F0F0F) == ((c >> 4) & 0x0F0F0F)) - wsprintf( buf, L"#%X%X%X", r & 0xF, g & 0xF, b & 0xF ); + _snwprintf( buf, lenof(buf), L"#%X%X%X", r & 0xF, g & 0xF, b & 0xF ); else - wsprintf( buf, L"#%02X%02X%02X", r, g, b ); + _snwprintf( buf, lenof(buf), L"#%02X%02X%02X", r, g, b ); SendSequence( buf ); } @@ -1765,9 +1772,9 @@ void InterpretEscSeq( void ) case 6: // ESC[6n Report cursor position { TCHAR buf[32]; - wsprintf( buf, L"\33[%d;%d%sR", - CUR.Y - top + 1, CUR.X + 1, - (suffix2 == '+') ? L"+" : L"" ); + _snwprintf( buf, lenof(buf), L"\33[%d;%d%sR", + CUR.Y - top + 1, CUR.X + 1, + (suffix2 == '+') ? L"+" : L"" ); SendSequence( buf ); } return; @@ -2236,7 +2243,17 @@ ParseAndPrintString( HANDLE hDev, else if (pState->crm) PushBuffer( (WCHAR)c ); else if (c == BEL) { - if (hBell == NULL) + if (PlaySound == NULL) + { + winmm = LoadLibraryEx( L"winmm.dll", NULL, 0 ); + if (winmm != NULL) + PlaySound = (FnPlaySound)GetProcAddress( winmm, "PlaySoundW" ); + if (PlaySound == NULL) + PlaySound = INVALID_HANDLE_VALUE; + } + if (PlaySound == INVALID_HANDLE_VALUE) + PushBuffer( (WCHAR)c ); + else if (hBell == NULL) hBell = CreateThread( NULL, 4096, BellThread, NULL, 0, NULL ); } else if (c == SO) shifted = TRUE; @@ -2975,7 +2992,7 @@ void Inject( DWORD dwCreationFlags, LPPROCESS_INFORMATION lpi, STARTUPINFO si; PROCESS_INFORMATION pi; wcscpy( DllNameType, L"CON.exe" ); - wsprintf( args, L"ansicon -P%ld", child_pi->dwProcessId ); + _snwprintf( args, lenof(args), L"ansicon -P%lu", child_pi->dwProcessId ); ZeroMemory( &si, sizeof(si) ); si.cb = sizeof(si); if (CreateProcess( DllName, args, NULL, NULL, FALSE, 0, NULL, NULL, @@ -3689,10 +3706,10 @@ void set_ansicon( PCONSOLE_SCREEN_BUFFER_INFO pcsbi ) pcsbi = &csbi; } - wsprintf( buf, L"%dx%d (%dx%d)", - pcsbi->dwSize.X, pcsbi->dwSize.Y, - pcsbi->srWindow.Right - pcsbi->srWindow.Left + 1, - pcsbi->srWindow.Bottom - pcsbi->srWindow.Top + 1 ); + _snwprintf( buf, lenof(buf), L"%dx%d (%dx%d)", + pcsbi->dwSize.X, pcsbi->dwSize.Y, + pcsbi->srWindow.Right - pcsbi->srWindow.Left + 1, + pcsbi->srWindow.Bottom - pcsbi->srWindow.Top + 1 ); SetEnvironmentVariable( L"ANSICON", buf ); } @@ -3920,6 +3937,8 @@ BOOL WINAPI DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved ) { DEBUGSTR( 1, "Unloading" ); HookAPIAllMod( Hooks, TRUE, FALSE ); + if (winmm != NULL) + FreeLibrary( winmm ); } else { diff --git a/ansicon.c b/ansicon.c index 8511d9f..4ea679c 100644 --- a/ansicon.c +++ b/ansicon.c @@ -91,7 +91,7 @@ use -pu to unload from the parent. */ -#define PDATE L"17 February, 2018" +#define PDATE L"30 April, 2018" #include "ansicon.h" #include "version.h" @@ -199,7 +199,8 @@ BOOL Inject( LPPROCESS_INFORMATION ppi, BOOL* gui, LPCTSTR app ) len = (DWORD)(prog - prog_path); memcpy( DllName, prog_path, TSIZE(len) ); #ifdef _WIN64 - wsprintf( DllName + len, L"ANSI%d.dll", (type == 48) ? 64 : type ); + _snwprintf( DllName + len, MAX_PATH-1 - len, + L"ANSI%d.dll", (type == 48) ? 64 : type ); DllNameType = DllName + len + 4; set_ansi_dll(); if (type == 64) @@ -269,7 +270,7 @@ void RemoteLoad( LPPROCESS_INFORMATION ppi, LPCTSTR app, BOOL unload ) memcpy( DllName, prog_path, TSIZE(len) ); #ifdef _WIN64 type = (IsWow64Process( ppi->hProcess, &WOW64 ) && WOW64) ? 32 : 64; - wsprintf( DllName + len, L"ANSI%d.dll", type ); + _snwprintf( DllName + len, MAX_PATH-1 - len, L"ANSI%d.dll", type ); #endif me.dwSize = sizeof(MODULEENTRY32); for (fOk = Module32First( hSnap, &me ); fOk; fOk = Module32Next( hSnap, &me )) diff --git a/makefile.vc b/makefile.vc index dbd3f40..1e0b09a 100644 --- a/makefile.vc +++ b/makefile.vc @@ -60,13 +60,14 @@ SHARE = /MD MT = mt.exe CFLAGS = /nologo /W3 /O2 $(SHARE) /D_CRT_SECURE_NO_WARNINGS -LIBS = advapi32.lib user32.lib winmm.lib $(LIBS64) +LIBS = advapi32.lib $(LIBS64) # Identify ansicon.exe using "ANSI" as a version number. LINK = /link /version:20033.18771 X86OBJS = x86\injdll.obj x86\proctype.obj x86\util.obj X64OBJS = x64\injdll.obj x64\proctype.obj x64\util.obj x64\procrva.obj +X6432OBJS = x86\injdll.obj x64\proctype32.obj x86\util.obj !IF !DEFINED(V) V = 0 @@ -118,7 +119,7 @@ x64\ANSI64.dll: x64\ANSI.obj $(X64OBJS) x64\ansi.res $(LDmsg)$(CC) /nologo $(SHARE) /LD /Fe$@ $** $(LIBS) /link \ /base:0xAC000000 -x64\ANSI32.dll: x64\ANSI32.obj x64\proctype32.obj x86\injdll.obj x86\util.obj x86\ansi.res +x64\ANSI32.dll: x64\ANSI32.obj $(X6432OBJS) x86\ansi.res $(LDmsg)$(CC) /nologo $(SHARE) /LD /Fe$@ $** $(LIBS) /link \ /base:0xAC0000 /filealign:512 /largeaddressaware !IF "$(_NMAKE_VER)" == "9.00.30729.01" diff --git a/procrva.c b/procrva.c index 3204bcc..fa73917 100644 --- a/procrva.c +++ b/procrva.c @@ -9,12 +9,6 @@ static PIMAGE_DOS_HEADER pDosHeader; -static int export_cmp( const void* a, const void* b ) -{ - return strcmp( (LPCSTR)a, MakeVA( LPCSTR, *(const PDWORD)b ) ); -} - - #ifdef _WIN64 DWORD GetProcRVA( LPCTSTR module, LPCSTR func, int bits ) #else @@ -28,8 +22,8 @@ DWORD GetProcRVA( LPCTSTR module, LPCSTR func ) PIMAGE_EXPORT_DIRECTORY pExportDir; PDWORD fun_table, name_table; PWORD ord_table; - PDWORD pFunc; DWORD rva; + int lo, mid, hi, cmp; #ifdef _WIN64 if (bits == 32) @@ -65,20 +59,30 @@ DWORD GetProcRVA( LPCTSTR module, LPCSTR func ) name_table = MakeVA( PDWORD, pExportDir->AddressOfNames ); ord_table = MakeVA( PWORD, pExportDir->AddressOfNameOrdinals ); - pFunc = bsearch( func, name_table, pExportDir->NumberOfNames, - sizeof(DWORD), export_cmp ); - if (pFunc == NULL) + rva = 0; + lo = 0; + hi = pExportDir->NumberOfNames - 1; + while (lo <= hi) + { + mid = (lo + hi) / 2; + cmp = strcmp( func, MakeVA( LPCSTR, name_table[mid] ) ); + if (cmp == 0) + { + rva = fun_table[ord_table[mid]]; + break; + } + if (cmp < 0) + hi = mid - 1; + else + lo = mid + 1; + } + if (rva == 0) { #ifdef _WIN64 DEBUGSTR( 1, "Could not find %u-bit %s!", bits, func ); #else DEBUGSTR( 1, "Could not find %s!", func ); #endif - rva = 0; - } - else - { - rva = fun_table[ord_table[pFunc - name_table]]; } FreeLibrary( hMod ); return rva; diff --git a/readme.txt b/readme.txt index a2a5e04..af536d8 100644 --- a/readme.txt +++ b/readme.txt @@ -339,8 +339,9 @@ Version History Legend: + added, - bug-fixed, * changed. - 1.84-wip - 17 February, 2018: - - close the flush handles on detach. + 1.84-wip - 30 April, 2018: + - close the flush handles on detach; + * remove dependency on USER32, dynamically load WINMM. 1.83 - 16 February, 2018: - create the flush thread on first use. @@ -615,5 +616,5 @@ Distribution in LICENSE.txt. -============================== -Jason Hood, 17 February, 2018. +=========================== +Jason Hood, 30 April, 2018. diff --git a/util.c b/util.c index 9d4ed8b..069d471 100644 --- a/util.c +++ b/util.c @@ -107,14 +107,20 @@ static DWORD str_format( DWORD pos, BOOL wide, DWORD_PTR str, DWORD len ) if (len == 0) { if (str == 0) - pos += wsprintfA( buf + pos, "" ); + { + memcpy( buf + pos, "", 6 ); + pos += 6; + } else if (quote) { buf[pos++] = '"'; buf[pos++] = '"'; } else if (alt) - pos += wsprintfA( buf + pos, "" ); + { + memcpy( buf + pos, "", 7 ); + pos += 7; + } return pos; } @@ -165,7 +171,7 @@ static DWORD str_format( DWORD pos, BOOL wide, DWORD_PTR str, DWORD len ) case '\r': buf[pos++] = 'r'; break; case 27 : buf[pos++] = 'e'; break; default: - pos += wsprintfA( buf + pos, "x%.2X", ch ); + pos += sprintf( buf + pos, "x%.2X", ch ); } } else @@ -194,7 +200,7 @@ static DWORD str_format( DWORD pos, BOOL wide, DWORD_PTR str, DWORD len ) } } if (quote && start_trail) - pos += wsprintfA( buf + pos, "\\x%.2X", ch ); + pos += sprintf( buf + pos, "\\x%.2X", ch ); else buf[pos++] = ch; } @@ -203,8 +209,8 @@ static DWORD str_format( DWORD pos, BOOL wide, DWORD_PTR str, DWORD len ) int mb = WideCharToMultiByte( cp, flags, src.w - 1, 1, buf + pos, 12, NULL, pDef ); if (def) - mb = wsprintfA( buf + pos, ch < 0x100 ? "%cx%.2X" : "%cu%.4X", - (quote) ? '\\' : '^', ch ); + mb = sprintf( buf + pos, ch < 0x100 ? "%cx%.2X" : "%cu%.4X", + (quote) ? '\\' : '^', ch ); pos += mb; } } @@ -240,7 +246,7 @@ void DEBUGSTR( int level, LPCSTR szFormat, ... ) } buf = HeapAlloc( hHeap, 0, 2048 ); buf_len = (DWORD)HeapSize( hHeap, 0, buf ); - prefix_len = wsprintfA( buf, "%S (%lu): ", prog, GetCurrentProcessId() ); + prefix_len = sprintf( buf, "%S (%lu): ", prog, GetCurrentProcessId() ); } if (WaitForSingleObject( mutex, 500 ) == WAIT_TIMEOUT) return; @@ -274,11 +280,11 @@ void DEBUGSTR( int level, LPCSTR szFormat, ... ) } GetLocalTime( &now ); - len = wsprintfA( buf, "ANSICON (" BITSA "-bit) v" PVERSA " log (%d)" - " started %d-%.2d-%.2d %d:%.2d:%.2d\r\n", - log_level, - now.wYear, now.wMonth, now.wDay, - now.wHour, now.wMinute, now.wSecond ); + len = sprintf( buf, "ANSICON (" BITSA "-bit) v" PVERSA " log (%d)" + " started %d-%.2d-%.2d %d:%.2d:%.2d\r\n", + log_level, + now.wYear, now.wMonth, now.wDay, + now.wHour, now.wMinute, now.wSecond ); WriteFile( file, buf, len, &written, NULL ); if (szFormat == NULL) { @@ -349,16 +355,16 @@ void DEBUGSTR( int level, LPCSTR szFormat, ... ) num = va_arg( pArgList, DWORD_PTR ); switch (*szFormat++) { - case 'u': len += wsprintfA( buf + len, "%u", (DWORD)num ); break; - case 'X': len += wsprintfA( buf + len, "%X", (DWORD)num ); break; + case 'u': len += sprintf( buf + len, "%u", (DWORD)num ); break; + case 'X': len += sprintf( buf + len, "%X", (DWORD)num ); break; case 'p': #ifdef _WIN64 - len += wsprintfA( buf + len, "%.8X_%.8X", - (DWORD)(num >> 32), (DWORD)num ); + len += sprintf( buf + len, "%.8X_%.8X", + (DWORD)(num >> 32), (DWORD)num ); break; #endif - case 'q': len += wsprintfA( buf + len, "%.8X", (DWORD)num ); break; - case 'P': len += wsprintfA( buf + len, "00000000_%.8X", (DWORD)num ); break; + case 'q': len += sprintf( buf + len, "%.8X", (DWORD)num ); break; + case 'P': len += sprintf( buf + len, "00000000_%.8X", (DWORD)num ); break; case 's': len = str_format( len, FALSE, num, slen ); break; case 'S': len = str_format( len, TRUE, num, slen ); break; default: