Exclude entire programs; better hooking of dynamically-loaded libraries.

ANSICON_EXC can now be used to exclude an entire program (including children).
This is achieved by simply not specifying an extension: ANSICON_EXC=program.exe
will just ignore program.exe (its DLLs will still be hooked, as will its child-
ren), but ANSICON_EXC=program will not hook program at all (which also means
its children will not be hooked).

The various LoadLibrary hooks would only hook the DLL that was specified - any
DLLs it loaded would be missed.  That has now been rectified.  Similarly, a DLL
that is injected via CreateRemoteThread, using LoadLibraryA or LoadLibraryW as
its ThreadProc, will now be hooked.
This commit is contained in:
Jason Hood 2014-02-10 16:33:42 +10:00
parent 6da33b2af0
commit bd696b55c8
4 changed files with 186 additions and 132 deletions

312
ANSI.c
View File

@ -111,7 +111,7 @@
v1.66, 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.70, 25 January to 8 February, 2014: v1.70, 25 January to 10 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;
inject by manipulating the import directory table; for 64-bit AnyCPU use inject by manipulating the import directory table; for 64-bit AnyCPU use
@ -119,7 +119,11 @@
restore original attributes on detach (for LoadLibrary/FreeLibrary usage); restore original attributes on detach (for LoadLibrary/FreeLibrary usage);
log: remove the quotes around the CreateProcess command line string and log: remove the quotes around the CreateProcess command line string and
distinguish NULL and "" args; distinguish NULL and "" args;
attributes (and saved position) are local to each console window. attributes (and saved position) are local to each console window;
exclude entire programs, by not using an extension in ANSICON_EXC;
hook modules injected via CreateRemoteThread+LoadLibrary;
hook all modules loaded due to LoadLibrary, not just the specified;
don't hook a module that's already hooked us.
*/ */
#include "ansicon.h" #include "ansicon.h"
@ -1066,6 +1070,7 @@ typedef struct
PROC newfunc; PROC newfunc;
PROC oldfunc; PROC oldfunc;
PROC apifunc; PROC apifunc;
PULONG_PTR myimport;
} HookFn, *PHookFn; } HookFn, *PHookFn;
HookFn Hooks[]; HookFn Hooks[];
@ -1085,7 +1090,8 @@ const WCHAR zUnhooking[] = L"Unhooking";
BOOL HookAPIOneMod( BOOL HookAPIOneMod(
HMODULE hFromModule, // Handle of the module to intercept calls from HMODULE hFromModule, // Handle of the module to intercept calls from
PHookFn Hooks, // Functions to replace PHookFn Hooks, // Functions to replace
BOOL restore // Restore the original functions BOOL restore, // Restore the original functions
LPCTSTR sp // Logging indentation
) )
{ {
PIMAGE_DOS_HEADER pDosHeader; PIMAGE_DOS_HEADER pDosHeader;
@ -1093,6 +1099,15 @@ BOOL HookAPIOneMod(
PIMAGE_IMPORT_DESCRIPTOR pImportDesc; PIMAGE_IMPORT_DESCRIPTOR pImportDesc;
PIMAGE_THUNK_DATA pThunk; PIMAGE_THUNK_DATA pThunk;
PHookFn hook; PHookFn hook;
BOOL self;
if (hFromModule == NULL)
{
self = TRUE;
hFromModule = hDllInstance;
}
else
self = FALSE;
// Tests to make sure we're looking at a module image (the 'MZ' header) // Tests to make sure we're looking at a module image (the 'MZ' header)
pDosHeader = (PIMAGE_DOS_HEADER)hFromModule; pDosHeader = (PIMAGE_DOS_HEADER)hFromModule;
@ -1147,13 +1162,13 @@ BOOL HookAPIOneMod(
if (lib->name == NULL) if (lib->name == NULL)
{ {
if (log_level & 16) if (log_level & 16)
DEBUGSTR( 2, L" %s %S", zIgnoring, pszModName ); DEBUGSTR( 2, L" %s%s %S", sp, zIgnoring, pszModName );
continue; continue;
} }
kernel = FALSE; kernel = FALSE;
} }
if (log_level & 16) if (log_level & 16)
DEBUGSTR( 2, L" Scanning %S", pszModName ); DEBUGSTR( 2, L" %sScanning %S", sp, pszModName );
// Get a pointer to the found module's import address table (IAT). // Get a pointer to the found module's import address table (IAT).
pThunk = MakeVA( PIMAGE_THUNK_DATA, pImportDesc->FirstThunk ); pThunk = MakeVA( PIMAGE_THUNK_DATA, pImportDesc->FirstThunk );
@ -1173,13 +1188,23 @@ BOOL HookAPIOneMod(
else if ((PROC)pThunk->u1.Function == hook->oldfunc || else if ((PROC)pThunk->u1.Function == hook->oldfunc ||
(PROC)pThunk->u1.Function == hook->apifunc) (PROC)pThunk->u1.Function == hook->apifunc)
{ {
patch = hook->newfunc; if (self)
hook->myimport = &pThunk->u1.Function;
else
{
// Don't hook if our import already points to the module being
// hooked (i.e. it's already hooked us).
MEMORY_BASIC_INFORMATION minfo;
VirtualQuery( (LPVOID)*hook->myimport, &minfo, sizeof(minfo) );
if (minfo.AllocationBase != hFromModule)
patch = hook->newfunc;
}
} }
if (patch) if (patch)
{ {
DWORD pr; DWORD pr;
DEBUGSTR( 3, L" %S", hook->name ); DEBUGSTR( 3, L" %s%S", sp, hook->name );
// Change the access protection on the region of committed pages in // Change the access protection on the region of committed pages in
// the virtual address space of the current process. // the virtual address space of the current process.
VirtualProtect( &pThunk->u1.Function, PTRSZ, PAGE_READWRITE, &pr ); VirtualProtect( &pThunk->u1.Function, PTRSZ, PAGE_READWRITE, &pr );
@ -1205,11 +1230,13 @@ BOOL HookAPIOneMod(
// Return FALSE on error and TRUE on success. // Return FALSE on error and TRUE on success.
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
BOOL HookAPIAllMod( PHookFn Hooks, BOOL restore ) BOOL HookAPIAllMod( PHookFn Hooks, BOOL restore, BOOL indent )
{ {
HANDLE hModuleSnap; HANDLE hModuleSnap;
MODULEENTRY32 me; MODULEENTRY32 me;
BOOL fOk; BOOL fOk;
LPCTSTR op, sp;
DWORD pr;
// Take a snapshot of all modules in the current process. // Take a snapshot of all modules in the current process.
hModuleSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, hModuleSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE,
@ -1221,6 +1248,9 @@ BOOL HookAPIAllMod( PHookFn Hooks, BOOL restore )
return FALSE; return FALSE;
} }
op = (restore) ? zUnhooking : zHooking;
sp = (indent) ? L" " : L"";
// Fill the size of the structure before using it. // Fill the size of the structure before using it.
me.dwSize = sizeof(MODULEENTRY32); me.dwSize = sizeof(MODULEENTRY32);
@ -1229,84 +1259,110 @@ BOOL HookAPIAllMod( PHookFn Hooks, BOOL restore )
fOk = Module32Next( hModuleSnap, &me )) fOk = Module32Next( hModuleSnap, &me ))
{ {
// We don't hook functions in our own module. // We don't hook functions in our own module.
if (me.hModule != hDllInstance && me.hModule != hKernel) if (me.hModule == hDllInstance || me.hModule == hKernel)
continue;
// Don't scan what we've already scanned.
if (*(PDWORD)((PBYTE)me.hModule + 36) == 'ISNA') // e_oemid, e_oeminfo
continue;
VirtualProtect( (PBYTE)me.hModule + 36, 4, PAGE_READWRITE, &pr );
*(PDWORD)((PBYTE)me.hModule + 36) = 'ISNA';
VirtualProtect( (PBYTE)me.hModule + 36, 4, pr, &pr );
if (search_env( L"ANSICON_EXC", me.szModule ))
{ {
if (search_env( L"ANSICON_EXC", me.szModule )) DEBUGSTR( 2, L"%s%s %s", sp, zIgnoring, me.szModule );
{ continue;
DEBUGSTR( 2, L"%s %s", zIgnoring, me.szModule ); }
continue;
} // Hook the functions in this module.
DEBUGSTR( 2, L"%s %s", (restore) ? zUnhooking : zHooking, me.szModule ); DEBUGSTR( 2, L"%s%s %s", sp, op, me.szModule );
// Hook this function in this module. if (!HookAPIOneMod( me.hModule, Hooks, restore, sp ))
if (!HookAPIOneMod( me.hModule, Hooks, restore )) {
{ CloseHandle( hModuleSnap );
CloseHandle( hModuleSnap ); return FALSE;
return FALSE;
}
} }
} }
CloseHandle( hModuleSnap ); CloseHandle( hModuleSnap );
DEBUGSTR( 2, L"%s completed", (restore) ? zUnhooking : zHooking ); DEBUGSTR( 2, L"%s%s completed", sp, op );
return TRUE; return TRUE;
} }
// ========== Child process injection // ========== Child process injection
static LPTSTR get_program( LPTSTR app, BOOL wide, LPCVOID lpApp, LPCVOID lpCmd ) #define MAX_DEV_PATH (32+MAX_PATH) // device form instead of drive letter
static LPTSTR get_program( LPTSTR app, HANDLE hProcess,
BOOL wide, LPCVOID lpApp, LPCVOID lpCmd )
{ {
app[MAX_PATH-1] = '\0'; app[MAX_DEV_PATH-1] = '\0';
if (lpApp == NULL) if (lpApp == NULL)
{ {
// Extract the program from the command line. I would use typedef DWORD (WINAPI *PGPIFNW)( HANDLE, LPTSTR, DWORD );
// GetModuleFileNameEx, but it doesn't work when a process is created static PGPIFNW GetProcessImageFileName;
// suspended and setting up a delay until it does work sometimes
// prevents the process running at all. GetProcessImageFileName works,
// but it's not supported in 2K.
LPTSTR name;
LPCTSTR term = L" \t";
if (wide) if (GetProcessImageFileName == NULL)
{ {
LPCTSTR pos; // Use Ex to avoid potential recursion with other hooks.
for (pos = lpCmd; *pos == ' ' || *pos == '\t'; ++pos) ; HMODULE psapi = LoadLibraryEx( L"psapi.dll", NULL, 0 );
if (*pos == '"') if (psapi != NULL)
{ {
term = L"\""; GetProcessImageFileName = (PGPIFNW)GetProcAddress( psapi,
++pos; "GetProcessImageFileNameW" );
} }
wcsncpy( app, pos, MAX_PATH-1 ); if (GetProcessImageFileName == NULL)
GetProcessImageFileName = INVALID_HANDLE_VALUE;
} }
else if (GetProcessImageFileName == INVALID_HANDLE_VALUE ||
GetProcessImageFileName( hProcess, app, MAX_DEV_PATH ) == 0)
{ {
LPCSTR pos; LPTSTR name;
for (pos = lpCmd; *pos == ' ' || *pos == '\t'; ++pos) ; LPCTSTR term = L" \t";
if (*pos == '"')
if (wide)
{ {
term = L"\""; LPCTSTR pos;
++pos; for (pos = lpCmd; *pos == ' ' || *pos == '\t'; ++pos) ;
if (*pos == '"')
{
term = L"\"";
++pos;
}
wcsncpy( app, pos, MAX_DEV_PATH-1 );
} }
MultiByteToWideChar( CP_ACP, 0, pos, -1, app, MAX_PATH-1 ); else
{
LPCSTR pos;
for (pos = lpCmd; *pos == ' ' || *pos == '\t'; ++pos) ;
if (*pos == '"')
{
term = L"\"";
++pos;
}
MultiByteToWideChar( CP_ACP, 0, pos, -1, app, MAX_DEV_PATH-1 );
}
// CreateProcess only works with surrounding quotes ('"a name"' works,
// but 'a" "name' fails), so that's all I'll test, too. However, it also
// tests for a file at each separator ('a name' tries "a.exe" before
// "a name.exe") which I won't do.
name = wcspbrk( app, term );
if (name)
*name = '\0';
} }
// CreateProcess only works with surrounding quotes ('"a name"' works, but
// 'a" "name' fails), so that's all I'll test, too. However, it also
// tests for a file at each separator ('a name' tries "a.exe" before
// "a name.exe") which I won't do.
name = wcspbrk( app, term );
if (name)
*name = '\0';
} }
else else
{ {
if (wide) if (wide)
wcsncpy( app, lpApp, MAX_PATH-1 ); wcsncpy( app, lpApp, MAX_DEV_PATH-1 );
else else
MultiByteToWideChar( CP_ACP, 0, lpApp, -1, app, MAX_PATH-1 ); MultiByteToWideChar( CP_ACP, 0, lpApp, -1, app, MAX_DEV_PATH-1 );
} }
return get_program_name( app ); return get_program_name( app );
} }
// Inject code into the target process to load our DLL. // Inject code into the target process to load our DLL.
void Inject( DWORD dwCreationFlags, LPPROCESS_INFORMATION lpi, void Inject( DWORD dwCreationFlags, LPPROCESS_INFORMATION lpi,
LPPROCESS_INFORMATION child_pi, LPPROCESS_INFORMATION child_pi,
@ -1315,23 +1371,26 @@ void Inject( DWORD dwCreationFlags, LPPROCESS_INFORMATION lpi,
int type; int type;
PBYTE base; PBYTE base;
BOOL gui; BOOL gui;
WCHAR app[MAX_PATH]; WCHAR app[MAX_DEV_PATH];
LPTSTR name = NULL; LPTSTR name;
if (log_level) name = get_program( app, child_pi->hProcess, wide, lpApp, lpCmd );
DEBUGSTR( 1, L"%s (%lu)", name, child_pi->dwProcessId );
if (search_env( L"ANSICON_EXC", name ))
{ {
name = get_program( app, wide, lpApp, lpCmd ); DEBUGSTR( 1, L" Excluded" );
DEBUGSTR( 1, L"%s (%lu)", name, child_pi->dwProcessId ); type = 0;
} }
type = ProcessType( child_pi, &base, &gui ); else
if (gui && type > 0)
{ {
if (name == NULL) type = ProcessType( child_pi, &base, &gui );
name = get_program( app, wide, lpApp, lpCmd ); if (gui && type > 0)
if (!search_env( L"ANSICON_GUI", name ))
{ {
DEBUGSTR( 1, L" %s", zIgnoring ); if (!search_env( L"ANSICON_GUI", name ))
type = 0; {
DEBUGSTR( 1, L" %s", zIgnoring );
type = 0;
}
} }
} }
if (type > 0) if (type > 0)
@ -1540,39 +1599,11 @@ FARPROC WINAPI MyGetProcAddress( HMODULE hModule, LPCSTR lpProcName )
} }
void HookLibrary( HMODULE hMod, LPCVOID lpFileName, BOOL wide, LPCSTR funcName )
{
LPCWSTR name;
WCHAR wname[MAX_PATH];
if (hMod && hMod != hKernel && hMod != hDllInstance)
{
if (!wide)
{
MultiByteToWideChar( AreFileApisANSI() ? CP_ACP : CP_OEMCP, 0,
lpFileName, -1, wname, MAX_PATH );
lpFileName = wname;
}
name = wcsrchr( lpFileName, '\\' );
if (name == NULL)
name = lpFileName;
else
++name;
if (search_env( L"ANSICON_EXC", name ))
DEBUGSTR( 2, L"%s %s (%S)", zIgnoring, lpFileName, funcName );
else
{
DEBUGSTR( 2, L"%s %s (%S)", zHooking, lpFileName, funcName );
HookAPIOneMod( hMod, Hooks, FALSE );
}
}
}
HMODULE WINAPI MyLoadLibraryA( LPCSTR lpFileName ) HMODULE WINAPI MyLoadLibraryA( LPCSTR lpFileName )
{ {
HMODULE hMod = LoadLibraryA( lpFileName ); HMODULE hMod = LoadLibraryA( lpFileName );
HookLibrary( hMod, lpFileName, FALSE, "LoadLibraryA" ); DEBUGSTR( 2, L"LoadLibraryA %S", lpFileName );
HookAPIAllMod( Hooks, FALSE, TRUE );
return hMod; return hMod;
} }
@ -1580,7 +1611,8 @@ HMODULE WINAPI MyLoadLibraryA( LPCSTR lpFileName )
HMODULE WINAPI MyLoadLibraryW( LPCWSTR lpFileName ) HMODULE WINAPI MyLoadLibraryW( LPCWSTR lpFileName )
{ {
HMODULE hMod = LoadLibraryW( lpFileName ); HMODULE hMod = LoadLibraryW( lpFileName );
HookLibrary( hMod, lpFileName, TRUE, "LoadLibraryW" ); DEBUGSTR( 2, L"LoadLibraryW %s", lpFileName );
HookAPIAllMod( Hooks, FALSE, TRUE );
return hMod; return hMod;
} }
@ -1592,7 +1624,10 @@ HMODULE WINAPI MyLoadLibraryExA( LPCSTR lpFileName, HANDLE hFile,
if (!(dwFlags & (LOAD_LIBRARY_AS_DATAFILE | if (!(dwFlags & (LOAD_LIBRARY_AS_DATAFILE |
LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE | LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE |
LOAD_LIBRARY_AS_IMAGE_RESOURCE))) LOAD_LIBRARY_AS_IMAGE_RESOURCE)))
HookLibrary( hMod, lpFileName, FALSE, "LoadLibraryExA" ); {
DEBUGSTR( 2, L"LoadLibraryExA %S", lpFileName );
HookAPIAllMod( Hooks, FALSE, TRUE );
}
return hMod; return hMod;
} }
@ -1604,7 +1639,10 @@ HMODULE WINAPI MyLoadLibraryExW( LPCWSTR lpFileName, HANDLE hFile,
if (!(dwFlags & (LOAD_LIBRARY_AS_DATAFILE | if (!(dwFlags & (LOAD_LIBRARY_AS_DATAFILE |
LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE | LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE |
LOAD_LIBRARY_AS_IMAGE_RESOURCE))) LOAD_LIBRARY_AS_IMAGE_RESOURCE)))
HookLibrary( hMod, lpFileName, TRUE, "LoadLibraryExW" ); {
DEBUGSTR( 2, L"LoadLibraryExW %s", lpFileName );
HookAPIAllMod( Hooks, FALSE, TRUE );
}
return hMod; return hMod;
} }
@ -1808,21 +1846,21 @@ WINAPI MyGetEnvironmentVariableW( LPCWSTR lpName, LPWSTR lpBuffer, DWORD nSize )
HookFn Hooks[] = { HookFn Hooks[] = {
// These two are expected first! // These two are expected first!
{ APILibraryLoader, "LoadLibraryA", (PROC)MyLoadLibraryA, NULL, NULL }, { APILibraryLoader, "LoadLibraryA", (PROC)MyLoadLibraryA, NULL, NULL, NULL },
{ APILibraryLoader, "LoadLibraryW", (PROC)MyLoadLibraryW, NULL, NULL }, { APILibraryLoader, "LoadLibraryW", (PROC)MyLoadLibraryW, NULL, NULL, NULL },
{ APIProcessThreads, "CreateProcessA", (PROC)MyCreateProcessA, NULL, NULL }, { APIProcessThreads, "CreateProcessA", (PROC)MyCreateProcessA, NULL, NULL, NULL },
{ APIProcessThreads, "CreateProcessW", (PROC)MyCreateProcessW, NULL, NULL }, { APIProcessThreads, "CreateProcessW", (PROC)MyCreateProcessW, NULL, NULL, NULL },
{ APIProcessEnvironment, "GetEnvironmentVariableA", (PROC)MyGetEnvironmentVariableA, NULL, NULL }, { APIProcessEnvironment, "GetEnvironmentVariableA", (PROC)MyGetEnvironmentVariableA, NULL, NULL, NULL },
{ APIProcessEnvironment, "GetEnvironmentVariableW", (PROC)MyGetEnvironmentVariableW, NULL, NULL }, { APIProcessEnvironment, "GetEnvironmentVariableW", (PROC)MyGetEnvironmentVariableW, NULL, NULL, NULL },
{ APILibraryLoader, "GetProcAddress", (PROC)MyGetProcAddress, NULL, NULL }, { APILibraryLoader, "GetProcAddress", (PROC)MyGetProcAddress, NULL, NULL, NULL },
{ APILibraryLoader, "LoadLibraryExA", (PROC)MyLoadLibraryExA, NULL, NULL }, { APILibraryLoader, "LoadLibraryExA", (PROC)MyLoadLibraryExA, NULL, NULL, NULL },
{ APILibraryLoader, "LoadLibraryExW", (PROC)MyLoadLibraryExW, NULL, NULL }, { APILibraryLoader, "LoadLibraryExW", (PROC)MyLoadLibraryExW, NULL, NULL, NULL },
{ APIConsole, "WriteConsoleA", (PROC)MyWriteConsoleA, NULL, NULL }, { APIConsole, "WriteConsoleA", (PROC)MyWriteConsoleA, NULL, NULL, NULL },
{ APIConsole, "WriteConsoleW", (PROC)MyWriteConsoleW, NULL, NULL }, { APIConsole, "WriteConsoleW", (PROC)MyWriteConsoleW, NULL, NULL, NULL },
{ APIFile, "WriteFile", (PROC)MyWriteFile, NULL, NULL }, { APIFile, "WriteFile", (PROC)MyWriteFile, NULL, NULL, NULL },
{ APIKernel, "_lwrite", (PROC)My_lwrite, NULL, NULL }, { APIKernel, "_lwrite", (PROC)My_lwrite, NULL, NULL, NULL },
{ APIKernel, "_hwrite", (PROC)My_hwrite, NULL, NULL }, { APIKernel, "_hwrite", (PROC)My_hwrite, NULL, NULL, NULL },
{ NULL, NULL, NULL, NULL, NULL } { NULL, NULL, NULL, NULL, NULL, NULL }
}; };
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -1844,21 +1882,16 @@ void OriginalAttr( PVOID lpReserved )
// If we were loaded dynamically, remember the current attributes to restore // If we were loaded dynamically, remember the current attributes to restore
// upon unloading. However, if we're the 64-bit DLL, but the image is 32- // upon unloading. However, if we're the 64-bit DLL, but the image is 32-
// bit, then the dynamic load was due to injecting into AnyCPU. // bit, then the dynamic load was due to injecting into AnyCPU.
while (lpReserved == NULL) // breakable if if (lpReserved == NULL)
{ {
#ifdef _WIN64 #ifdef _WIN64
if (*DllNameType == '6') PIMAGE_DOS_HEADER pDosHeader;
{ PIMAGE_NT_HEADERS pNTHeader;
PIMAGE_DOS_HEADER pDosHeader; pDosHeader = (PIMAGE_DOS_HEADER)GetModuleHandle( NULL );
PIMAGE_NT_HEADERS pNTHeader; pNTHeader = MakeVA( PIMAGE_NT_HEADERS, pDosHeader->e_lfanew );
pDosHeader = (PIMAGE_DOS_HEADER)GetModuleHandle( NULL ); if (pNTHeader->FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64)
pNTHeader = MakeVA( PIMAGE_NT_HEADERS, pDosHeader->e_lfanew );
if (pNTHeader->FileHeader.Machine == IMAGE_FILE_MACHINE_I386)
break;
}
#endif #endif
orgattr = csbi.wAttributes; orgattr = csbi.wAttributes;
break;
} }
get_state(); get_state();
@ -1878,6 +1911,8 @@ BOOL WINAPI DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved )
BOOL bResult = TRUE; BOOL bResult = TRUE;
PHookFn hook; PHookFn hook;
TCHAR logstr[4]; TCHAR logstr[4];
typedef LONG (WINAPI *PNTQIT)( HANDLE, int, PVOID, ULONG, PULONG );
static PNTQIT NtQueryInformationThread;
if (dwReason == DLL_PROCESS_ATTACH) if (dwReason == DLL_PROCESS_ATTACH)
{ {
@ -1905,16 +1940,23 @@ BOOL WINAPI DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved )
for (hook = Hooks; hook->name; ++hook) for (hook = Hooks; hook->name; ++hook)
hook->oldfunc = GetProcAddress( hKernel, hook->name ); hook->oldfunc = GetProcAddress( hKernel, hook->name );
bResult = HookAPIAllMod( Hooks, FALSE ); // Get my import addresses, to detect if anyone's hooked me.
HookAPIOneMod( NULL, Hooks, FALSE, L"" );
bResult = HookAPIAllMod( Hooks, FALSE, FALSE );
OriginalAttr( lpReserved ); OriginalAttr( lpReserved );
DisableThreadLibraryCalls( hInstance );
NtQueryInformationThread = (PNTQIT)GetProcAddress(
GetModuleHandle( L"ntdll.dll" ), "NtQueryInformationThread" );
if (NtQueryInformationThread == NULL)
DisableThreadLibraryCalls( hInstance );
} }
else if (dwReason == DLL_PROCESS_DETACH) else if (dwReason == DLL_PROCESS_DETACH)
{ {
if (lpReserved == NULL) if (lpReserved == NULL)
{ {
DEBUGSTR( 1, L"Unloading" ); DEBUGSTR( 1, L"Unloading" );
HookAPIAllMod( Hooks, TRUE ); HookAPIAllMod( Hooks, TRUE, FALSE );
} }
else else
{ {
@ -1931,6 +1973,18 @@ BOOL WINAPI DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved )
CloseHandle( pState ); CloseHandle( pState );
CloseHandle( hMap ); CloseHandle( hMap );
} }
else if (dwReason == DLL_THREAD_DETACH)
{
PVOID start;
if (NtQueryInformationThread( GetCurrentThread(),
9 /* ThreadQuerySetWin32StartAddress */,
&start, sizeof(start), NULL ) == 0
&& (start == Hooks[0].oldfunc || start == Hooks[1].oldfunc
|| start == Hooks[0].apifunc || start == Hooks[1].apifunc))
{
DEBUGSTR( 2, L"Injection detected" );
HookAPIAllMod( Hooks, FALSE, TRUE );
}
}
return bResult; return bResult;
} }

View File

@ -87,7 +87,7 @@
add error codes to some message. add error codes to some message.
*/ */
#define PDATE L"8 February, 2014" #define PDATE L"10 February, 2014"
#include "ansicon.h" #include "ansicon.h"
#include "version.h" #include "version.h"

View File

@ -21,7 +21,7 @@
# * 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 -Wno-multichar
# Identify ansicon.exe using "ANSI" as a version number. # Identify ansicon.exe using "ANSI" as a version number.
IVER = -Wl,--major-image-version,20033,--minor-image-version,18771 IVER = -Wl,--major-image-version,20033,--minor-image-version,18771

View File

@ -23,7 +23,7 @@
#BITS = 64 #BITS = 64
!IFNDEF BITS !IFNDEF BITS
!IF "$(CPU)" == "AMD64" || "$(PLATFORM)" == "x64" !IF "$(CPU)" == "AMD64" || "$(PLATFORM)" == "x64" || "$(PLATFORM)" == "X64"
BITS = 64 BITS = 64
!ELSE !ELSE
BITS = 32 BITS = 32