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.
This commit is contained in:
Jason Hood 2018-04-30 11:06:18 +10:00
parent 2cb2af78c8
commit 852db64d91
6 changed files with 90 additions and 58 deletions

41
ANSI.c
View File

@ -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 <mmsystem.h>
#include <mmsystem.h>
#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,7 +1772,7 @@ void InterpretEscSeq( void )
case 6: // ESC[6n Report cursor position
{
TCHAR buf[32];
wsprintf( buf, L"\33[%d;%d%sR",
_snwprintf( buf, lenof(buf), L"\33[%d;%d%sR",
CUR.Y - top + 1, CUR.X + 1,
(suffix2 == '+') ? L"+" : L"" );
SendSequence( buf );
@ -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,7 +3706,7 @@ void set_ansicon( PCONSOLE_SCREEN_BUFFER_INFO pcsbi )
pcsbi = &csbi;
}
wsprintf( buf, L"%dx%d (%dx%d)",
_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 );
@ -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
{

View File

@ -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 ))

View File

@ -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"

View File

@ -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;

View File

@ -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.

30
util.c
View File

@ -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, "<null>" );
{
memcpy( buf + pos, "<null>", 6 );
pos += 6;
}
else if (quote)
{
buf[pos++] = '"';
buf[pos++] = '"';
}
else if (alt)
pos += wsprintfA( buf + pos, "<empty>" );
{
memcpy( buf + pos, "<empty>", 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,7 +209,7 @@ 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",
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,7 +280,7 @@ void DEBUGSTR( int level, LPCSTR szFormat, ... )
}
GetLocalTime( &now );
len = wsprintfA( buf, "ANSICON (" BITSA "-bit) v" PVERSA " log (%d)"
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,
@ -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",
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: