Work with 64-bit AnyCPU; copy original IDT to IAT; log improvements.
This commit is contained in:
parent
dc7569dc26
commit
db36552c42
134
ANSI.c
134
ANSI.c
@ -111,12 +111,14 @@
|
|||||||
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 4 February, 2014:
|
v1.70, 25 January to 7 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;
|
inject by manipulating the import directory table; for 64-bit AnyCPU use
|
||||||
|
ntdll's LdrLoadDll via CreateRemoteThread;
|
||||||
restore original attribute on detach (for LoadLibrary/FreeLibrary usage);
|
restore original attribute on detach (for LoadLibrary/FreeLibrary usage);
|
||||||
log: remove the quotes around the CreateProcess command line string.
|
log: remove the quotes around the CreateProcess command line string and
|
||||||
|
distinguish NULL and "" args.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ansicon.h"
|
#include "ansicon.h"
|
||||||
@ -956,10 +958,6 @@ ParseAndPrintString( HANDLE hDev,
|
|||||||
// - Matt Pietrek ~ Windows 95 System Programming Secrets.
|
// - Matt Pietrek ~ Windows 95 System Programming Secrets.
|
||||||
// - Jeffrey Richter ~ Programming Applications for Microsoft Windows 4th ed.
|
// - Jeffrey Richter ~ Programming Applications for Microsoft Windows 4th ed.
|
||||||
|
|
||||||
// Macro for adding pointers/DWORDs together without C arithmetic interfering
|
|
||||||
#define MakeVA( cast, offset ) (cast)((DWORD_PTR)(pDosHeader)+(DWORD)(offset))
|
|
||||||
|
|
||||||
|
|
||||||
const char APIKernel[] = "kernel32.dll";
|
const char APIKernel[] = "kernel32.dll";
|
||||||
const char APIConsole[] = "API-MS-Win-Core-Console-";
|
const char APIConsole[] = "API-MS-Win-Core-Console-";
|
||||||
const char APIProcessThreads[] = "API-MS-Win-Core-ProcessThreads-";
|
const char APIProcessThreads[] = "API-MS-Win-Core-ProcessThreads-";
|
||||||
@ -987,9 +985,8 @@ API_DATA APIs[] =
|
|||||||
|
|
||||||
HMODULE hKernel; // Kernel32 module handle
|
HMODULE hKernel; // Kernel32 module handle
|
||||||
HINSTANCE hDllInstance; // Dll instance handle
|
HINSTANCE hDllInstance; // Dll instance handle
|
||||||
TCHAR hDllName[MAX_PATH]; // Dll file name
|
|
||||||
#if defined(_WIN64) || defined(W32ON64)
|
#if defined(_WIN64) || defined(W32ON64)
|
||||||
LPTSTR hDllNameType; // pointer to process type within above
|
LPTSTR DllNameType; // pointer to process type within DllName
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
@ -1150,7 +1147,7 @@ BOOL HookAPIAllMod( PHookFn Hooks, BOOL restore )
|
|||||||
|
|
||||||
if (hModuleSnap == INVALID_HANDLE_VALUE)
|
if (hModuleSnap == INVALID_HANDLE_VALUE)
|
||||||
{
|
{
|
||||||
DEBUGSTR( 1, L"Failed to create snapshot!" );
|
DEBUGSTR( 1, L"Failed to create snapshot (%lu)!", GetLastError() );
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1186,23 +1183,10 @@ BOOL HookAPIAllMod( PHookFn Hooks, BOOL restore )
|
|||||||
|
|
||||||
// ========== Child process injection
|
// ========== Child process injection
|
||||||
|
|
||||||
// Inject code into the target process to load our DLL.
|
static LPTSTR get_program( LPTSTR app, BOOL wide, LPCVOID lpApp, LPCVOID lpCmd )
|
||||||
void Inject( DWORD dwCreationFlags, LPPROCESS_INFORMATION lpi,
|
|
||||||
LPPROCESS_INFORMATION child_pi,
|
|
||||||
BOOL wide, LPCVOID lpApp, LPCVOID lpCmd )
|
|
||||||
{
|
{
|
||||||
int type;
|
|
||||||
PBYTE base;
|
|
||||||
BOOL gui;
|
|
||||||
|
|
||||||
type = ProcessType( child_pi, &base, &gui );
|
|
||||||
if (gui && type > 0)
|
|
||||||
{
|
|
||||||
TCHAR app[MAX_PATH];
|
|
||||||
LPTSTR name;
|
|
||||||
LPCTSTR term = L" \t";
|
|
||||||
|
|
||||||
app[MAX_PATH-1] = '\0';
|
app[MAX_PATH-1] = '\0';
|
||||||
|
|
||||||
if (lpApp == NULL)
|
if (lpApp == NULL)
|
||||||
{
|
{
|
||||||
// Extract the program from the command line. I would use
|
// Extract the program from the command line. I would use
|
||||||
@ -1210,6 +1194,9 @@ void Inject( DWORD dwCreationFlags, LPPROCESS_INFORMATION lpi,
|
|||||||
// suspended and setting up a delay until it does work sometimes
|
// suspended and setting up a delay until it does work sometimes
|
||||||
// prevents the process running at all. GetProcessImageFileName works,
|
// prevents the process running at all. GetProcessImageFileName works,
|
||||||
// but it's not supported in 2K.
|
// but it's not supported in 2K.
|
||||||
|
LPTSTR name;
|
||||||
|
LPCTSTR term = L" \t";
|
||||||
|
|
||||||
if (wide)
|
if (wide)
|
||||||
{
|
{
|
||||||
LPCTSTR pos;
|
LPCTSTR pos;
|
||||||
@ -1230,7 +1217,7 @@ void Inject( DWORD dwCreationFlags, LPPROCESS_INFORMATION lpi,
|
|||||||
term = L"\"";
|
term = L"\"";
|
||||||
++pos;
|
++pos;
|
||||||
}
|
}
|
||||||
MultiByteToWideChar( CP_ACP, 0, pos, -1, app, MAX_PATH );
|
MultiByteToWideChar( CP_ACP, 0, pos, -1, app, MAX_PATH-1 );
|
||||||
}
|
}
|
||||||
// CreateProcess only works with surrounding quotes ('"a name"' works, but
|
// CreateProcess only works with surrounding quotes ('"a name"' works, but
|
||||||
// 'a" "name' fails), so that's all I'll test, too. However, it also
|
// 'a" "name' fails), so that's all I'll test, too. However, it also
|
||||||
@ -1245,9 +1232,32 @@ void Inject( DWORD dwCreationFlags, LPPROCESS_INFORMATION lpi,
|
|||||||
if (wide)
|
if (wide)
|
||||||
wcsncpy( app, lpApp, MAX_PATH-1 );
|
wcsncpy( app, lpApp, MAX_PATH-1 );
|
||||||
else
|
else
|
||||||
MultiByteToWideChar( CP_ACP, 0, lpApp, -1, app, MAX_PATH );
|
MultiByteToWideChar( CP_ACP, 0, lpApp, -1, app, MAX_PATH-1 );
|
||||||
}
|
}
|
||||||
name = get_program_name( app );
|
return get_program_name( app );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inject code into the target process to load our DLL.
|
||||||
|
void Inject( DWORD dwCreationFlags, LPPROCESS_INFORMATION lpi,
|
||||||
|
LPPROCESS_INFORMATION child_pi,
|
||||||
|
BOOL wide, LPCVOID lpApp, LPCVOID lpCmd )
|
||||||
|
{
|
||||||
|
int type;
|
||||||
|
PBYTE base;
|
||||||
|
BOOL gui;
|
||||||
|
WCHAR app[MAX_PATH];
|
||||||
|
LPTSTR name = NULL;
|
||||||
|
|
||||||
|
if (log_level)
|
||||||
|
{
|
||||||
|
name = get_program( app, wide, lpApp, lpCmd );
|
||||||
|
DEBUGSTR( 1, L"%s (%lu)", name, child_pi->dwProcessId );
|
||||||
|
}
|
||||||
|
type = ProcessType( child_pi, &base, &gui );
|
||||||
|
if (gui && type > 0)
|
||||||
|
{
|
||||||
|
if (name == NULL)
|
||||||
|
name = get_program( app, wide, lpApp, lpCmd );
|
||||||
if (!search_env( L"ANSICON_GUI", name ))
|
if (!search_env( L"ANSICON_GUI", name ))
|
||||||
{
|
{
|
||||||
DEBUGSTR( 1, L" %s", zIgnoring );
|
DEBUGSTR( 1, L" %s", zIgnoring );
|
||||||
@ -1257,31 +1267,34 @@ void Inject( DWORD dwCreationFlags, LPPROCESS_INFORMATION lpi,
|
|||||||
if (type > 0)
|
if (type > 0)
|
||||||
{
|
{
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
if (type == 32)
|
if (type == 64)
|
||||||
{
|
|
||||||
ansi_bits[0] = '3';
|
|
||||||
ansi_bits[1] = '2';
|
|
||||||
InjectDLL32( child_pi, base );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
ansi_bits[0] = '6';
|
ansi_bits[0] = '6';
|
||||||
ansi_bits[1] = '4';
|
ansi_bits[1] = '4';
|
||||||
InjectDLL( child_pi, base );
|
InjectDLL( child_pi, base );
|
||||||
}
|
}
|
||||||
|
else if (type == 32)
|
||||||
|
{
|
||||||
|
ansi_bits[0] = '3';
|
||||||
|
ansi_bits[1] = '2';
|
||||||
|
InjectDLL32( child_pi, base );
|
||||||
|
}
|
||||||
|
else // (type == 48)
|
||||||
|
{
|
||||||
|
InjectDLL64( child_pi );
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
#ifdef W32ON64
|
#ifdef W32ON64
|
||||||
if (type == 64)
|
if (type != 32)
|
||||||
{
|
{
|
||||||
TCHAR args[64];
|
TCHAR args[64];
|
||||||
STARTUPINFO si;
|
STARTUPINFO si;
|
||||||
PROCESS_INFORMATION pi;
|
PROCESS_INFORMATION pi;
|
||||||
wcscpy( hDllNameType, L"CON.exe" );
|
wcscpy( DllNameType, L"CON.exe" );
|
||||||
wsprintf( args, L"ansicon -P%lu:%lu",
|
wsprintf( args, L"ansicon -P%ld", child_pi->dwProcessId );
|
||||||
child_pi->dwProcessId, child_pi->dwThreadId );
|
|
||||||
ZeroMemory( &si, sizeof(si) );
|
ZeroMemory( &si, sizeof(si) );
|
||||||
si.cb = sizeof(si);
|
si.cb = sizeof(si);
|
||||||
if (CreateProcess( hDllName, args, NULL, NULL, FALSE, 0, NULL, NULL,
|
if (CreateProcess( DllName, args, NULL, NULL, FALSE, 0, NULL, NULL,
|
||||||
&si, &pi ))
|
&si, &pi ))
|
||||||
{
|
{
|
||||||
WaitForSingleObject( pi.hProcess, INFINITE );
|
WaitForSingleObject( pi.hProcess, INFINITE );
|
||||||
@ -1289,8 +1302,8 @@ void Inject( DWORD dwCreationFlags, LPPROCESS_INFORMATION lpi,
|
|||||||
CloseHandle( pi.hThread );
|
CloseHandle( pi.hThread );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
DEBUGSTR( 1, L"Could not execute \"%s\"", hDllName );
|
DEBUGSTR(1, L"Could not execute \"%s\" (%lu)", DllName, GetLastError());
|
||||||
wcscpy( hDllNameType, L"32.dll" );
|
wcscpy( DllNameType, L"32.dll" );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
@ -1339,6 +1352,13 @@ BOOL WINAPI MyCreateProcessA( LPCSTR lpApplicationName,
|
|||||||
{
|
{
|
||||||
PROCESS_INFORMATION child_pi;
|
PROCESS_INFORMATION child_pi;
|
||||||
|
|
||||||
|
DEBUGSTR( 1, L"CreateProcessA: %s%S%s, %S",
|
||||||
|
(lpApplicationName == NULL) ? L"" : L"\"",
|
||||||
|
(lpApplicationName == NULL) ? "<null>" : lpApplicationName,
|
||||||
|
(lpApplicationName == NULL) ? L"" : L"\"",
|
||||||
|
(lpCommandLine == NULL) ? "<null>" :
|
||||||
|
(*lpCommandLine == '\0') ? "<empty>" : lpCommandLine );
|
||||||
|
|
||||||
if (!CreateProcessA( lpApplicationName,
|
if (!CreateProcessA( lpApplicationName,
|
||||||
lpCommandLine,
|
lpCommandLine,
|
||||||
lpThreadAttributes,
|
lpThreadAttributes,
|
||||||
@ -1349,12 +1369,11 @@ BOOL WINAPI MyCreateProcessA( LPCSTR lpApplicationName,
|
|||||||
lpCurrentDirectory,
|
lpCurrentDirectory,
|
||||||
lpStartupInfo,
|
lpStartupInfo,
|
||||||
&child_pi ))
|
&child_pi ))
|
||||||
|
{
|
||||||
|
DEBUGSTR( 1, L" Failed (%lu)", GetLastError() );
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
DEBUGSTR( 1, L"CreateProcessA: (%lu) \"%S\", %S",
|
|
||||||
child_pi.dwProcessId,
|
|
||||||
(lpApplicationName == NULL) ? "" : lpApplicationName,
|
|
||||||
(lpCommandLine == NULL) ? "" : lpCommandLine );
|
|
||||||
Inject( dwCreationFlags, lpProcessInformation, &child_pi,
|
Inject( dwCreationFlags, lpProcessInformation, &child_pi,
|
||||||
FALSE, lpApplicationName, lpCommandLine );
|
FALSE, lpApplicationName, lpCommandLine );
|
||||||
|
|
||||||
@ -1375,6 +1394,13 @@ BOOL WINAPI MyCreateProcessW( LPCWSTR lpApplicationName,
|
|||||||
{
|
{
|
||||||
PROCESS_INFORMATION child_pi;
|
PROCESS_INFORMATION child_pi;
|
||||||
|
|
||||||
|
DEBUGSTR( 1, L"CreateProcessW: %s%s%s, %s",
|
||||||
|
(lpApplicationName == NULL) ? L"" : L"\"",
|
||||||
|
(lpApplicationName == NULL) ? L"<null>" : lpApplicationName,
|
||||||
|
(lpApplicationName == NULL) ? L"" : L"\"",
|
||||||
|
(lpCommandLine == NULL) ? L"<null>" :
|
||||||
|
(*lpCommandLine == '\0') ? L"<empty>" : lpCommandLine );
|
||||||
|
|
||||||
if (!CreateProcessW( lpApplicationName,
|
if (!CreateProcessW( lpApplicationName,
|
||||||
lpCommandLine,
|
lpCommandLine,
|
||||||
lpThreadAttributes,
|
lpThreadAttributes,
|
||||||
@ -1385,12 +1411,11 @@ BOOL WINAPI MyCreateProcessW( LPCWSTR lpApplicationName,
|
|||||||
lpCurrentDirectory,
|
lpCurrentDirectory,
|
||||||
lpStartupInfo,
|
lpStartupInfo,
|
||||||
&child_pi ))
|
&child_pi ))
|
||||||
|
{
|
||||||
|
DEBUGSTR( 1, L" Failed (%lu)", GetLastError() );
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
DEBUGSTR( 1, L"CreateProcessW: (%lu) \"%s\", %s",
|
|
||||||
child_pi.dwProcessId,
|
|
||||||
(lpApplicationName == NULL) ? L"" : lpApplicationName,
|
|
||||||
(lpCommandLine == NULL) ? L"" : lpCommandLine );
|
|
||||||
Inject( dwCreationFlags, lpProcessInformation, &child_pi,
|
Inject( dwCreationFlags, lpProcessInformation, &child_pi,
|
||||||
TRUE, lpApplicationName, lpCommandLine );
|
TRUE, lpApplicationName, lpCommandLine );
|
||||||
|
|
||||||
@ -1819,13 +1844,10 @@ BOOL WINAPI DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved )
|
|||||||
log_level = _wtoi( logstr );
|
log_level = _wtoi( logstr );
|
||||||
prog = get_program_name( NULL );
|
prog = get_program_name( NULL );
|
||||||
#if defined(_WIN64) || defined(W32ON64)
|
#if defined(_WIN64) || defined(W32ON64)
|
||||||
hDllNameType = hDllName - 6 +
|
DllNameType = DllName - 6 +
|
||||||
#endif
|
#endif
|
||||||
GetModuleFileName( hInstance, hDllName, lenof(hDllName) );
|
GetModuleFileName( hInstance, DllName, lenof(DllName) );
|
||||||
#ifdef _WIN64
|
set_ansi_dll();
|
||||||
ansi_bits = (LPSTR)hDllNameType;
|
|
||||||
#endif
|
|
||||||
set_ansi_dll( hDllName );
|
|
||||||
|
|
||||||
hDllInstance = hInstance; // save Dll instance handle
|
hDllInstance = hInstance; // save Dll instance handle
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
|
115
LLW.c
115
LLW.c
@ -1,115 +0,0 @@
|
|||||||
/*
|
|
||||||
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
|
|
167
ansicon.c
167
ansicon.c
@ -77,16 +77,17 @@
|
|||||||
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:
|
v1.70, 31 January to 7 February, 2014:
|
||||||
restore the original (current, not default) attributes if using ansicon.exe
|
restore the original (current, not default) attributes if using ansicon.exe
|
||||||
when it's already installed;
|
when it's already installed;
|
||||||
use ANSICON_DEF if defined and -m not given;
|
use ANSICON_DEF if defined and -m not given;
|
||||||
-e and -t will not output anything if the DLL could not load;
|
-e and -t will not output anything if the DLL could not load;
|
||||||
use Unicode output (_O_U16TEXT, for compilers/systems that support it);
|
use Unicode output (_O_U16TEXT, for compilers/systems that support it);
|
||||||
log: 64-bit addresses get an underscore between the 8-digit groups.
|
log: 64-bit addresses get an underscore between the 8-digit groups;
|
||||||
|
add error codes to some message.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define PDATE L"4 February, 2014"
|
#define PDATE L"7 February, 2014"
|
||||||
|
|
||||||
#include "ansicon.h"
|
#include "ansicon.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
@ -168,14 +169,20 @@ int my_fputws( const wchar_t* s, FILE* f )
|
|||||||
#define _putws( s ) my_fputws( s L"\n", stdout )
|
#define _putws( s ) my_fputws( s L"\n", stdout )
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(_WIN64)
|
||||||
|
LPTSTR DllNameType;
|
||||||
|
#endif
|
||||||
|
|
||||||
// Find the name of the DLL and inject it.
|
// Find the name of the DLL and inject it.
|
||||||
BOOL Inject( LPPROCESS_INFORMATION ppi, BOOL* gui, LPCTSTR app )
|
BOOL Inject( LPPROCESS_INFORMATION ppi, BOOL* gui, LPCTSTR app )
|
||||||
{
|
{
|
||||||
DWORD len;
|
DWORD len;
|
||||||
WCHAR dll[MAX_PATH];
|
|
||||||
int type;
|
int type;
|
||||||
PBYTE base;
|
PBYTE base;
|
||||||
|
|
||||||
|
#ifdef _WIN64
|
||||||
|
if (app != NULL)
|
||||||
|
#endif
|
||||||
DEBUGSTR( 1, L"%s (%lu)", app, ppi->dwProcessId );
|
DEBUGSTR( 1, L"%s (%lu)", app, ppi->dwProcessId );
|
||||||
type = ProcessType( ppi, &base, gui );
|
type = ProcessType( ppi, &base, gui );
|
||||||
if (type <= 0)
|
if (type <= 0)
|
||||||
@ -186,48 +193,75 @@ BOOL Inject( LPPROCESS_INFORMATION ppi, BOOL* gui, LPCTSTR app )
|
|||||||
}
|
}
|
||||||
|
|
||||||
len = (DWORD)(prog - prog_path);
|
len = (DWORD)(prog - prog_path);
|
||||||
memcpy( dll, prog_path, TSIZE(len) );
|
memcpy( DllName, prog_path, TSIZE(len) );
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
wsprintf( dll + len, L"ANSI%d.dll", type );
|
wsprintf( DllName + len, L"ANSI%d.dll", (type == 48) ? 64 : type );
|
||||||
ansi_bits = (LPSTR)(dll + len + 4);
|
DllNameType = DllName + len + 4;
|
||||||
set_ansi_dll( dll );
|
set_ansi_dll();
|
||||||
if (type == 32)
|
if (type == 64)
|
||||||
InjectDLL32( ppi, base );
|
|
||||||
else
|
|
||||||
InjectDLL( ppi, base );
|
InjectDLL( ppi, base );
|
||||||
|
else if (type == 32)
|
||||||
|
InjectDLL32( ppi, base );
|
||||||
|
else // (type == 48)
|
||||||
|
InjectDLL64( ppi );
|
||||||
#else
|
#else
|
||||||
wcscpy( dll + len, L"ANSI32.dll" );
|
wcscpy( DllName + len, L"ANSI32.dll" );
|
||||||
set_ansi_dll( dll );
|
set_ansi_dll();
|
||||||
InjectDLL( ppi, base );
|
InjectDLL( ppi, base );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Use CreateRemoteThread to load our DLL in the target process.
|
// Use CreateRemoteThread to load our DLL in the target process.
|
||||||
void RemoteLoad( LPPROCESS_INFORMATION ppi )
|
void RemoteLoad( LPPROCESS_INFORMATION ppi, LPCTSTR app )
|
||||||
{
|
{
|
||||||
HANDLE hSnap;
|
HANDLE hSnap;
|
||||||
MODULEENTRY32 me;
|
MODULEENTRY32 me;
|
||||||
PBYTE LLW;
|
PBYTE LLW;
|
||||||
BOOL fOk;
|
BOOL fOk;
|
||||||
WCHAR dll[MAX_PATH];
|
|
||||||
DWORD len;
|
DWORD len;
|
||||||
LPVOID mem;
|
LPVOID mem;
|
||||||
HANDLE thread;
|
HANDLE thread;
|
||||||
|
DWORD ticks;
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
BOOL WOW64;
|
BOOL WOW64;
|
||||||
|
int type;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
DEBUGSTR( 1, L"%s (%lu)", app, ppi->dwProcessId );
|
||||||
|
|
||||||
// Find the base address of kernel32.dll.
|
// Find the base address of kernel32.dll.
|
||||||
LLW = NULL;
|
ticks = GetTickCount();
|
||||||
hSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32,
|
while ((hSnap = CreateToolhelp32Snapshot(
|
||||||
ppi->dwProcessId );
|
TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, ppi->dwProcessId ))
|
||||||
if (hSnap != INVALID_HANDLE_VALUE)
|
== INVALID_HANDLE_VALUE)
|
||||||
{
|
{
|
||||||
|
DWORD err = GetLastError();
|
||||||
|
#ifndef _WIN64
|
||||||
|
if (err == ERROR_PARTIAL_COPY)
|
||||||
|
{
|
||||||
|
DEBUGSTR( 1, L" Ignoring 64-bit process (use x64\\ansicon)" );
|
||||||
|
fputws( L"ANSICON: parent is 64-bit (use x64\\ansicon).\n", stderr );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
// I really don't think this would happen, but if it does, give up after
|
||||||
|
// two seconds to avoid a potentially infinite loop.
|
||||||
|
if (err == ERROR_BAD_LENGTH && GetTickCount() - ticks < 2000)
|
||||||
|
{
|
||||||
|
Sleep( 0 );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
DEBUGSTR( 1, L" Unable to create snapshot (%lu)", err );
|
||||||
|
no_go:
|
||||||
|
fputws( L"ANSICON: unable to inject into parent.\n", stderr );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LLW = NULL;
|
||||||
me.dwSize = sizeof(MODULEENTRY32);
|
me.dwSize = sizeof(MODULEENTRY32);
|
||||||
for (fOk = Module32First( hSnap, &me ); fOk;
|
for (fOk = Module32First( hSnap, &me ); fOk; fOk = Module32Next( hSnap, &me ))
|
||||||
fOk = Module32Next( hSnap, &me ))
|
|
||||||
{
|
{
|
||||||
if (_wcsicmp( me.szModule, L"kernel32.dll" ) == 0)
|
if (_wcsicmp( me.szModule, L"kernel32.dll" ) == 0)
|
||||||
{
|
{
|
||||||
@ -236,42 +270,32 @@ void RemoteLoad( LPPROCESS_INFORMATION ppi )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
CloseHandle( hSnap );
|
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)
|
if (LLW == NULL)
|
||||||
{
|
{
|
||||||
no_llw:
|
DEBUGSTR( 1, L" Unable to locate kernel32.dll (%lu)", GetLastError() );
|
||||||
fputws( L"ANSICON: unable to inject into parent.\n", stderr );
|
goto no_go;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
len = (DWORD)(prog - prog_path);
|
len = (DWORD)(prog - prog_path);
|
||||||
memcpy( dll, prog_path, TSIZE(len) );
|
memcpy( DllName, prog_path, TSIZE(len) );
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
if (IsWow64Process( ppi->hProcess, &WOW64 ) && WOW64)
|
type = (IsWow64Process( ppi->hProcess, &WOW64 ) && WOW64) ? 32 : 64;
|
||||||
{
|
wsprintf( DllName + len, L"ANSI%d.dll", type );
|
||||||
wcscpy( dll + len, L"ANSI32.dll" );
|
LLW += GetProcRVA( L"kernel32.dll", "LoadLibraryW", type );
|
||||||
LLW += get_LLW32r();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
wcscpy( dll + len, L"ANSI64.dll" );
|
|
||||||
LLW += get_LLW64r();
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
wcscpy( dll + len, L"ANSI32.dll" );
|
wcscpy( DllName + len, L"ANSI32.dll" );
|
||||||
LLW += get_LLW32r();
|
LLW += GetProcRVA( L"kernel32.dll", "LoadLibraryW" );
|
||||||
#endif
|
#endif
|
||||||
if (LLW == me.modBaseAddr)
|
if (LLW == me.modBaseAddr)
|
||||||
goto no_llw;
|
goto no_go;
|
||||||
|
|
||||||
mem = VirtualAllocEx( ppi->hProcess, NULL, len, MEM_COMMIT, PAGE_READWRITE );
|
mem = VirtualAllocEx( ppi->hProcess, NULL, len, MEM_COMMIT, PAGE_READWRITE );
|
||||||
WriteProcMem( mem, dll, TSIZE(len + 11) );
|
if (mem == NULL)
|
||||||
|
{
|
||||||
|
DEBUGSTR( 1, L" Unable to allocate virtual memory (%lu)", GetLastError() );
|
||||||
|
goto no_go;
|
||||||
|
}
|
||||||
|
WriteProcMem( mem, DllName, TSIZE(len + 11) );
|
||||||
thread = CreateRemoteThread( ppi->hProcess, NULL, 4096,
|
thread = CreateRemoteThread( ppi->hProcess, NULL, 4096,
|
||||||
(LPTHREAD_START_ROUTINE)LLW, mem, 0, NULL );
|
(LPTHREAD_START_ROUTINE)LLW, mem, 0, NULL );
|
||||||
WaitForSingleObject( thread, INFINITE );
|
WaitForSingleObject( thread, INFINITE );
|
||||||
@ -341,12 +365,18 @@ int main( void )
|
|||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
if (*arg == '-' && arg[1] == 'P')
|
if (*arg == '-' && arg[1] == 'P')
|
||||||
{
|
{
|
||||||
swscanf( arg + 2, L"%u:%u", &pi.dwProcessId, &pi.dwThreadId );
|
pi.dwProcessId = _wtoi( arg + 2 );
|
||||||
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 );
|
if (pi.hProcess == NULL)
|
||||||
Inject( &pi, &gui, arg );
|
{
|
||||||
CloseHandle( pi.hThread );
|
DEBUGSTR( 1, L" Unable to open process %lu (%lu)",
|
||||||
|
pi.dwProcessId, GetLastError() );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Inject( &pi, &gui, NULL );
|
||||||
CloseHandle( pi.hProcess );
|
CloseHandle( pi.hProcess );
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -378,14 +408,10 @@ int main( void )
|
|||||||
|
|
||||||
case 'p':
|
case 'p':
|
||||||
shell = FALSE;
|
shell = FALSE;
|
||||||
if (GetParentProcessInfo( &pi, arg + 3 ))
|
if (GetParentProcessInfo( &pi, arg ))
|
||||||
{
|
{
|
||||||
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 );
|
RemoteLoad( &pi, arg );
|
||||||
SuspendThread( pi.hThread );
|
|
||||||
RemoteLoad( &pi );
|
|
||||||
ResumeThread( pi.hThread );
|
|
||||||
CloseHandle( pi.hThread );
|
|
||||||
CloseHandle( pi.hProcess );
|
CloseHandle( pi.hProcess );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -702,35 +728,30 @@ BOOL find_proc_id( HANDLE snap, DWORD id, LPPROCESSENTRY32 ppe )
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Obtain the process and thread identifiers of the parent process.
|
// Obtain the process identifier of the parent process.
|
||||||
BOOL GetParentProcessInfo( LPPROCESS_INFORMATION ppi, LPTSTR name )
|
BOOL GetParentProcessInfo( LPPROCESS_INFORMATION ppi, LPTSTR name )
|
||||||
{
|
{
|
||||||
HANDLE hSnap;
|
HANDLE hSnap;
|
||||||
PROCESSENTRY32 pe;
|
PROCESSENTRY32 pe;
|
||||||
THREADENTRY32 te;
|
|
||||||
BOOL fOk;
|
BOOL fOk;
|
||||||
|
|
||||||
hSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS|TH32CS_SNAPTHREAD, 0 );
|
hSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
|
||||||
|
|
||||||
if (hSnap == INVALID_HANDLE_VALUE)
|
if (hSnap == INVALID_HANDLE_VALUE)
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
find_proc_id( hSnap, GetCurrentProcessId(), &pe );
|
|
||||||
if (!find_proc_id( hSnap, pe.th32ParentProcessID, &pe ))
|
|
||||||
{
|
{
|
||||||
CloseHandle( hSnap );
|
DEBUGSTR( 1, L"Failed to create snapshot (%lu)", GetLastError() );
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
te.dwSize = sizeof(te);
|
fOk = (find_proc_id( hSnap, GetCurrentProcessId(), &pe ) &&
|
||||||
for (fOk = Thread32First( hSnap, &te ); fOk; fOk = Thread32Next( hSnap, &te ))
|
find_proc_id( hSnap, pe.th32ParentProcessID, &pe ));
|
||||||
if (te.th32OwnerProcessID == pe.th32ProcessID)
|
|
||||||
break;
|
|
||||||
|
|
||||||
CloseHandle( hSnap );
|
CloseHandle( hSnap );
|
||||||
|
if (!fOk)
|
||||||
|
{
|
||||||
|
DEBUGSTR( 1, L"Failed to locate parent" );
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
ppi->dwProcessId = pe.th32ProcessID;
|
ppi->dwProcessId = pe.th32ProcessID;
|
||||||
ppi->dwThreadId = te.th32ThreadID;
|
|
||||||
wcscpy( name, pe.szExeFile );
|
wcscpy( name, pe.szExeFile );
|
||||||
|
|
||||||
return fOk;
|
return fOk;
|
||||||
@ -897,7 +918,7 @@ L" [-e|E string | -t|T [file(s)] | program [args]]\n"
|
|||||||
L"\n"
|
L"\n"
|
||||||
L" -l\t\tset the logging level (1=process, 2=module, 3=function,\n"
|
L" -l\t\tset the logging level (1=process, 2=module, 3=function,\n"
|
||||||
L" \t\t +4=output, +8=append) for program (-p is unaffected)\n"
|
L" \t\t +4=output, +8=append) for program (-p is unaffected)\n"
|
||||||
L" -i\t\tinstall - add ANSICON to the AutoRun entry (also implies -p)\n"
|
L" -i\t\tinstall - add ANSICON to CMD's AutoRun entry (also implies -p)\n"
|
||||||
L" -u\t\tuninstall - remove ANSICON from the AutoRun entry\n"
|
L" -u\t\tuninstall - remove ANSICON from the AutoRun entry\n"
|
||||||
L" -I -U\t\tuse local machine instead of current user\n"
|
L" -I -U\t\tuse local machine instead of current user\n"
|
||||||
L" -m\t\tuse grey on black (\"monochrome\") or <attr> as default color\n"
|
L" -m\t\tuse grey on black (\"monochrome\") or <attr> as default color\n"
|
||||||
|
28
ansicon.h
28
ansicon.h
@ -15,15 +15,12 @@
|
|||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
#define _WIN32_WINNT 0x0600 // MinGW-w64 wants this defined for Wow64 stuff
|
#define _WIN32_WINNT 0x0600 // MinGW-w64 wants this defined for Wow64 stuff
|
||||||
#else
|
#else
|
||||||
#define _WIN32_WINNT 0x0500 // MinGW wants this defined for OpenThread
|
#define _WIN32_WINNT 0x0500
|
||||||
#endif
|
#endif
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#define lenof(array) (sizeof(array)/sizeof(*(array)))
|
|
||||||
#define TSIZE(size) ((size) * sizeof(TCHAR))
|
|
||||||
|
|
||||||
#ifndef LOAD_LIBRARY_AS_IMAGE_RESOURCE
|
#ifndef LOAD_LIBRARY_AS_IMAGE_RESOURCE
|
||||||
#define LOAD_LIBRARY_AS_IMAGE_RESOURCE 0x20
|
#define LOAD_LIBRARY_AS_IMAGE_RESOURCE 0x20
|
||||||
#endif
|
#endif
|
||||||
@ -31,13 +28,19 @@
|
|||||||
#define LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE 0x20
|
#define LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE 0x20
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define lenof(array) (sizeof(array)/sizeof(*(array)))
|
||||||
|
#define TSIZE(size) ((size) * sizeof(TCHAR))
|
||||||
|
#define PTRSZ sizeof(PVOID)
|
||||||
|
|
||||||
|
// Macro for adding pointers/DWORDs together without C arithmetic interfering
|
||||||
|
#define MakeVA( cast, offset ) (cast)((DWORD_PTR)pDosHeader + (DWORD)(offset))
|
||||||
|
|
||||||
#define EXPORTDIR OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]
|
#define EXPORTDIR OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]
|
||||||
#define IMPORTDIR OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
|
#define IMPORTDIR OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
|
||||||
#define BOUNDDIR OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT]
|
#define BOUNDDIR OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT]
|
||||||
#define IATDIR OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT]
|
#define IATDIR OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT]
|
||||||
#define COMDIR OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR]
|
#define COMDIR OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR]
|
||||||
|
|
||||||
|
|
||||||
// Reduce the verbosity of some functions (assuming variable names).
|
// Reduce the verbosity of some functions (assuming variable names).
|
||||||
#define ReadProcVar(a, b) ReadProcMem( a, b, sizeof(*(b)) )
|
#define ReadProcVar(a, b) ReadProcMem( a, b, sizeof(*(b)) )
|
||||||
#define WriteProcVar(a, b) WriteProcMem( a, b, sizeof(*(b)) )
|
#define WriteProcVar(a, b) WriteProcMem( a, b, sizeof(*(b)) )
|
||||||
@ -45,8 +48,6 @@
|
|||||||
#define WriteProcMem(a, b, c) WriteProcessMemory( 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 VirtProtVar(a, b) VirtualProtectEx( ppi->hProcess, a, sizeof(*(a)), b, &pr )
|
||||||
|
|
||||||
#define PTRSZ sizeof(PVOID)
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
@ -61,21 +62,28 @@ typedef struct
|
|||||||
|
|
||||||
|
|
||||||
int ProcessType( LPPROCESS_INFORMATION, PBYTE*, BOOL* );
|
int ProcessType( LPPROCESS_INFORMATION, PBYTE*, BOOL* );
|
||||||
|
BOOL Wow64Process( HANDLE );
|
||||||
|
|
||||||
void InjectDLL( LPPROCESS_INFORMATION, PBYTE );
|
void InjectDLL( LPPROCESS_INFORMATION, PBYTE );
|
||||||
|
#ifdef _WIN64
|
||||||
void InjectDLL32( LPPROCESS_INFORMATION, PBYTE );
|
void InjectDLL32( LPPROCESS_INFORMATION, PBYTE );
|
||||||
|
void InjectDLL64( LPPROCESS_INFORMATION );
|
||||||
|
DWORD GetProcRVA( LPCTSTR, LPCSTR, int );
|
||||||
|
#else
|
||||||
|
DWORD GetProcRVA( LPCTSTR, LPCSTR );
|
||||||
|
#endif
|
||||||
|
|
||||||
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 TCHAR DllName[MAX_PATH];
|
||||||
|
extern LPTSTR DllNameType;
|
||||||
extern char ansi_dll[MAX_PATH];
|
extern char ansi_dll[MAX_PATH];
|
||||||
extern DWORD ansi_len;
|
extern DWORD ansi_len;
|
||||||
extern char* ansi_bits;
|
extern char* ansi_bits;
|
||||||
void set_ansi_dll( LPTSTR );
|
void set_ansi_dll( void );
|
||||||
|
|
||||||
extern int log_level;
|
extern int log_level;
|
||||||
void DEBUGSTR( int level, LPTSTR szFormat, ... );
|
void DEBUGSTR( int level, LPTSTR szFormat, ... );
|
||||||
|
152
injdll.c
152
injdll.c
@ -1,14 +1,17 @@
|
|||||||
/*
|
/*
|
||||||
Inject the DLL into the target process by modifying its import descriptor
|
Inject the DLL into the target process by modifying its import descriptor
|
||||||
table. The target process must have been created suspended.
|
table. The target process must have been created suspended. However, for a
|
||||||
|
64-bit system with a .NET AnyCPU process, inject via LdrLoadDll in ntdll.dll
|
||||||
|
and CreateRemoteThread (since AnyCPU is stored as i386, but loads as AMD64,
|
||||||
|
preventing imports from working).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ansicon.h"
|
#include "ansicon.h"
|
||||||
|
|
||||||
|
|
||||||
// Search for a suitable free area after the main image. (32-bit code could
|
// Search for a suitable free area after the main image (32-bit code could
|
||||||
// really go anywhere, but let's keep it relatively local.)
|
// really go anywhere, but let's keep it relatively local.)
|
||||||
PVOID FindMem( HANDLE hProcess, PBYTE base, DWORD len )
|
static PVOID FindMem( HANDLE hProcess, PBYTE base, DWORD len )
|
||||||
{
|
{
|
||||||
MEMORY_BASIC_INFORMATION minfo;
|
MEMORY_BASIC_INFORMATION minfo;
|
||||||
PBYTE ptr;
|
PBYTE ptr;
|
||||||
@ -43,20 +46,20 @@ void InjectDLL( LPPROCESS_INFORMATION ppi, PBYTE pBase )
|
|||||||
DWORD pr;
|
DWORD pr;
|
||||||
IMAGE_DOS_HEADER DosHeader;
|
IMAGE_DOS_HEADER DosHeader;
|
||||||
IMAGE_NT_HEADERS NTHeader, *pNTHeader;
|
IMAGE_NT_HEADERS NTHeader, *pNTHeader;
|
||||||
PIMAGE_IMPORT_DESCRIPTOR pImports, pANSI_ImportDesc;
|
PIMAGE_IMPORT_DESCRIPTOR pImports;
|
||||||
IMAGE_COR20_HEADER ComHeader, *pComHeader;
|
IMAGE_COR20_HEADER ComHeader, *pComHeader;
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
PBYTE pB;
|
PBYTE pB;
|
||||||
PLONG_PTR pL;
|
PLONG_PTR pL;
|
||||||
|
PIMAGE_IMPORT_DESCRIPTOR pI;
|
||||||
} ip;
|
} ip;
|
||||||
|
|
||||||
ReadProcVar( pBase, &DosHeader );
|
ReadProcVar( pBase, &DosHeader );
|
||||||
pNTHeader = (PIMAGE_NT_HEADERS)(pBase + DosHeader.e_lfanew);
|
pNTHeader = (PIMAGE_NT_HEADERS)(pBase + DosHeader.e_lfanew);
|
||||||
ReadProcVar( pNTHeader, &NTHeader );
|
ReadProcVar( pNTHeader, &NTHeader );
|
||||||
|
|
||||||
len = 4 * PTRSZ + ansi_len
|
len = 4 * PTRSZ + ansi_len + sizeof(*pImports) + NTHeader.IMPORTDIR.Size;
|
||||||
+ sizeof(*pANSI_ImportDesc) + NTHeader.IMPORTDIR.Size;
|
|
||||||
pImports = malloc( len );
|
pImports = malloc( len );
|
||||||
if (pImports == NULL)
|
if (pImports == NULL)
|
||||||
{
|
{
|
||||||
@ -79,24 +82,23 @@ void InjectDLL( LPPROCESS_INFORMATION ppi, PBYTE pBase )
|
|||||||
*ip.pL++ = 0;
|
*ip.pL++ = 0;
|
||||||
memcpy( ip.pB, ansi_dll, ansi_len );
|
memcpy( ip.pB, ansi_dll, ansi_len );
|
||||||
ip.pB += ansi_len;
|
ip.pB += ansi_len;
|
||||||
pANSI_ImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)ip.pB;
|
ip.pI->OriginalFirstThunk = rva + 2 * PTRSZ;
|
||||||
pANSI_ImportDesc->OriginalFirstThunk = rva + 2 * PTRSZ;
|
ip.pI->TimeDateStamp = 0;
|
||||||
pANSI_ImportDesc->TimeDateStamp = 0;
|
ip.pI->ForwarderChain = 0;
|
||||||
pANSI_ImportDesc->ForwarderChain = 0;
|
ip.pI->Name = rva + 4 * PTRSZ;
|
||||||
pANSI_ImportDesc->Name = rva + 4 * PTRSZ;
|
ip.pI->FirstThunk = rva;
|
||||||
pANSI_ImportDesc->FirstThunk = rva;
|
|
||||||
ReadProcMem( pBase + NTHeader.IMPORTDIR.VirtualAddress,
|
ReadProcMem( pBase + NTHeader.IMPORTDIR.VirtualAddress,
|
||||||
pANSI_ImportDesc + 1, NTHeader.IMPORTDIR.Size );
|
ip.pI + 1, NTHeader.IMPORTDIR.Size );
|
||||||
WriteProcMem( pMem, pImports, len );
|
WriteProcMem( pMem, pImports, len );
|
||||||
free( pImports );
|
free( pImports );
|
||||||
|
|
||||||
NTHeader.IMPORTDIR.VirtualAddress = rva + 4 * PTRSZ + ansi_len;
|
// If there's no IAT, copy the original IDT (to allow writable ".idata").
|
||||||
NTHeader.IMPORTDIR.Size += sizeof(*pANSI_ImportDesc);
|
|
||||||
|
|
||||||
// If there's no IAT, copy the IDT.
|
|
||||||
if (NTHeader.IATDIR.VirtualAddress == 0)
|
if (NTHeader.IATDIR.VirtualAddress == 0)
|
||||||
NTHeader.IATDIR = NTHeader.IMPORTDIR;
|
NTHeader.IATDIR = NTHeader.IMPORTDIR;
|
||||||
|
|
||||||
|
NTHeader.IMPORTDIR.VirtualAddress = rva + 4 * PTRSZ + ansi_len;
|
||||||
|
NTHeader.IMPORTDIR.Size += sizeof(*pImports);
|
||||||
|
|
||||||
// Remove bound imports, so the updated import table is used.
|
// Remove bound imports, so the updated import table is used.
|
||||||
NTHeader.BOUNDDIR.VirtualAddress = 0;
|
NTHeader.BOUNDDIR.VirtualAddress = 0;
|
||||||
NTHeader.BOUNDDIR.Size = 0;
|
NTHeader.BOUNDDIR.Size = 0;
|
||||||
@ -130,19 +132,20 @@ void InjectDLL32( LPPROCESS_INFORMATION ppi, PBYTE pBase )
|
|||||||
DWORD pr;
|
DWORD pr;
|
||||||
IMAGE_DOS_HEADER DosHeader;
|
IMAGE_DOS_HEADER DosHeader;
|
||||||
IMAGE_NT_HEADERS32 NTHeader, *pNTHeader;
|
IMAGE_NT_HEADERS32 NTHeader, *pNTHeader;
|
||||||
PIMAGE_IMPORT_DESCRIPTOR pImports, pANSI_ImportDesc;
|
PIMAGE_IMPORT_DESCRIPTOR pImports;
|
||||||
IMAGE_COR20_HEADER ComHeader, *pComHeader;
|
IMAGE_COR20_HEADER ComHeader, *pComHeader;
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
PBYTE pB;
|
PBYTE pB;
|
||||||
PLONG pL;
|
PLONG pL;
|
||||||
|
PIMAGE_IMPORT_DESCRIPTOR pI;
|
||||||
} ip;
|
} ip;
|
||||||
|
|
||||||
ReadProcVar( pBase, &DosHeader );
|
ReadProcVar( pBase, &DosHeader );
|
||||||
pNTHeader = (PIMAGE_NT_HEADERS32)(pBase + DosHeader.e_lfanew);
|
pNTHeader = (PIMAGE_NT_HEADERS32)(pBase + DosHeader.e_lfanew);
|
||||||
ReadProcVar( pNTHeader, &NTHeader );
|
ReadProcVar( pNTHeader, &NTHeader );
|
||||||
|
|
||||||
len = 16 + ansi_len + sizeof(*pANSI_ImportDesc) + NTHeader.IMPORTDIR.Size;
|
len = 16 + ansi_len + sizeof(*pImports) + NTHeader.IMPORTDIR.Size;
|
||||||
pImports = malloc( len );
|
pImports = malloc( len );
|
||||||
if (pImports == NULL)
|
if (pImports == NULL)
|
||||||
{
|
{
|
||||||
@ -165,21 +168,20 @@ void InjectDLL32( LPPROCESS_INFORMATION ppi, PBYTE pBase )
|
|||||||
*ip.pL++ = 0;
|
*ip.pL++ = 0;
|
||||||
memcpy( ip.pB, ansi_dll, ansi_len );
|
memcpy( ip.pB, ansi_dll, ansi_len );
|
||||||
ip.pB += ansi_len;
|
ip.pB += ansi_len;
|
||||||
pANSI_ImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)ip.pB;
|
ip.pI->OriginalFirstThunk = rva + 8;
|
||||||
pANSI_ImportDesc->OriginalFirstThunk = rva + 8;
|
ip.pI->TimeDateStamp = 0;
|
||||||
pANSI_ImportDesc->TimeDateStamp = 0;
|
ip.pI->ForwarderChain = 0;
|
||||||
pANSI_ImportDesc->ForwarderChain = 0;
|
ip.pI->Name = rva + 16;
|
||||||
pANSI_ImportDesc->Name = rva + 16;
|
ip.pI->FirstThunk = rva;
|
||||||
pANSI_ImportDesc->FirstThunk = rva;
|
|
||||||
ReadProcMem( pBase + NTHeader.IMPORTDIR.VirtualAddress,
|
ReadProcMem( pBase + NTHeader.IMPORTDIR.VirtualAddress,
|
||||||
pANSI_ImportDesc + 1, NTHeader.IMPORTDIR.Size );
|
ip.pI + 1, NTHeader.IMPORTDIR.Size );
|
||||||
WriteProcMem( pMem, pImports, len );
|
WriteProcMem( pMem, pImports, len );
|
||||||
free( pImports );
|
free( pImports );
|
||||||
|
|
||||||
NTHeader.IMPORTDIR.VirtualAddress = rva + 16 + ansi_len;
|
|
||||||
NTHeader.IMPORTDIR.Size += sizeof(*pANSI_ImportDesc);
|
|
||||||
if (NTHeader.IATDIR.VirtualAddress == 0)
|
if (NTHeader.IATDIR.VirtualAddress == 0)
|
||||||
NTHeader.IATDIR = NTHeader.IMPORTDIR;
|
NTHeader.IATDIR = NTHeader.IMPORTDIR;
|
||||||
|
NTHeader.IMPORTDIR.VirtualAddress = rva + 16 + ansi_len;
|
||||||
|
NTHeader.IMPORTDIR.Size += sizeof(*pImports);
|
||||||
NTHeader.BOUNDDIR.VirtualAddress = 0;
|
NTHeader.BOUNDDIR.VirtualAddress = 0;
|
||||||
NTHeader.BOUNDDIR.Size = 0;
|
NTHeader.BOUNDDIR.Size = 0;
|
||||||
VirtProtVar( pNTHeader, PAGE_READWRITE );
|
VirtProtVar( pNTHeader, PAGE_READWRITE );
|
||||||
@ -199,4 +201,98 @@ void InjectDLL32( LPPROCESS_INFORMATION ppi, PBYTE pBase )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Locate the base address of 64-bit ntdll.dll. This is supposedly really at
|
||||||
|
the same address for every process, but let's find it anyway. A newly-
|
||||||
|
created suspended 64-bit process has two images in memory: the process itself
|
||||||
|
and ntdll.dll - the one that is a DLL must be ntdll.dll. (A 32-bit WOW64
|
||||||
|
process has three images - the process and both 64- & 32-bit ntdll.dll).
|
||||||
|
*/
|
||||||
|
static PBYTE get_ntdll( LPPROCESS_INFORMATION ppi )
|
||||||
|
{
|
||||||
|
PBYTE ptr;
|
||||||
|
MEMORY_BASIC_INFORMATION minfo;
|
||||||
|
IMAGE_DOS_HEADER dos_header;
|
||||||
|
IMAGE_NT_HEADERS nt_header;
|
||||||
|
|
||||||
|
for (ptr = NULL;
|
||||||
|
VirtualQueryEx( ppi->hProcess, ptr, &minfo, sizeof(minfo) );
|
||||||
|
ptr += minfo.RegionSize)
|
||||||
|
{
|
||||||
|
if (minfo.BaseAddress == minfo.AllocationBase
|
||||||
|
&& ReadProcVar( minfo.BaseAddress, &dos_header )
|
||||||
|
&& 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))
|
||||||
|
{
|
||||||
|
return minfo.BaseAddress;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUGSTR( 1, L" Failed to find ntdll.dll!" );
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void InjectDLL64( LPPROCESS_INFORMATION ppi )
|
||||||
|
{
|
||||||
|
PBYTE ntdll;
|
||||||
|
DWORD rLdrLoadDll;
|
||||||
|
PBYTE pMem;
|
||||||
|
DWORD len;
|
||||||
|
HANDLE thread;
|
||||||
|
BYTE code[64];
|
||||||
|
union
|
||||||
|
{
|
||||||
|
PBYTE pB;
|
||||||
|
PUSHORT pS;
|
||||||
|
PDWORD pD;
|
||||||
|
PBYTE* pL;
|
||||||
|
} ip;
|
||||||
|
|
||||||
|
ntdll = get_ntdll( ppi );
|
||||||
|
if (ntdll == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
rLdrLoadDll = GetProcRVA( L"ntdll.dll", "LdrLoadDll", 64 );
|
||||||
|
if (rLdrLoadDll == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
pMem = VirtualAllocEx( ppi->hProcess, NULL, 4096, MEM_COMMIT,
|
||||||
|
PAGE_EXECUTE_READ );
|
||||||
|
if (pMem == NULL)
|
||||||
|
{
|
||||||
|
DEBUGSTR( 1, L" Failed to allocate virtual memory (%lu)", GetLastError() );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = (DWORD)TSIZE(wcslen( DllName ) + 1);
|
||||||
|
ip.pB = code;
|
||||||
|
|
||||||
|
*ip.pL++ = ntdll + rLdrLoadDll; // address of LdrLoadDll
|
||||||
|
*ip.pD++ = 0x38ec8348; // sub rsp, 0x38
|
||||||
|
*ip.pD++ = 0x244c8d4c; // lea r9, [rsp+0x20]
|
||||||
|
*ip.pD++ = 0x058d4c20; // lea r8, L"path\to\ANSI64.dll"
|
||||||
|
*ip.pD++ = 16; // xor edx, edx
|
||||||
|
*ip.pD++ = 0xc933d233; // xor ecx, ecx
|
||||||
|
*ip.pS++ = 0x15ff; // call LdrLoadDll
|
||||||
|
*ip.pD++ = -34; // add rsp, 0x38
|
||||||
|
*ip.pD++ = 0x38c48348; // ret
|
||||||
|
*ip.pS++ = 0x00c3; // alignment for the name
|
||||||
|
*ip.pS++ = (USHORT)(len - TSIZE(1)); // UNICODE_STRING.Length
|
||||||
|
*ip.pS++ = (USHORT)len; // UNICODE_STRING.MaximumLength
|
||||||
|
*ip.pD++ = 0; // padding
|
||||||
|
*ip.pL++ = pMem + 56; // UNICODE_STRING.Buffer
|
||||||
|
WriteProcMem( pMem, code, ip.pB - code );
|
||||||
|
WriteProcMem( pMem + (ip.pB - code), DllName, len );
|
||||||
|
thread = CreateRemoteThread( ppi->hProcess, NULL, 4096,
|
||||||
|
(LPTHREAD_START_ROUTINE)(pMem + 8), NULL, 0, NULL );
|
||||||
|
WaitForSingleObject( thread, INFINITE );
|
||||||
|
CloseHandle( thread );
|
||||||
|
VirtualFreeEx( ppi->hProcess, pMem, 0, MEM_RELEASE );
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -44,8 +44,8 @@ endif
|
|||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
X86OBJS = x86/proctype.o x86/injdll.o x86/util.o
|
X86OBJS = x86/injdll.o x86/proctype.o x86/util.o
|
||||||
X64OBJS = x64/proctype.o x64/injdll.o x64/util.o
|
X64OBJS = x64/injdll.o x64/proctype.o x64/util.o x64/procrva.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
|
||||||
@ -92,7 +92,7 @@ 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/LLW.o x86/ansiconv.o
|
x86/ansicon.exe: x86/ansicon.o $(X86OBJS) x86/procrva.o x86/ansiconv.o
|
||||||
$(LDmsg)$(CC) -m32 $+ -s -o $@ $(IVER)
|
$(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
|
||||||
@ -101,7 +101,7 @@ 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/LLW.o x64/ansiconv.o
|
x64/ansicon.exe: x64/ansicon.o $(X64OBJS) x64/ansiconv.o
|
||||||
$(LDmsg)$(CC) -m64 $+ -s -o $@ $(IVER)
|
$(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
|
||||||
|
10
makefile.vc
10
makefile.vc
@ -65,8 +65,8 @@ LIBS = advapi32.lib user32.lib $(LIBS64)
|
|||||||
# Identify ansicon.exe using "ANSI" as a version number.
|
# Identify ansicon.exe using "ANSI" as a version number.
|
||||||
LINK = /link /version:20033.18771
|
LINK = /link /version:20033.18771
|
||||||
|
|
||||||
X86OBJS = x86\proctype.obj x86\injdll.obj x86\util.obj
|
X86OBJS = x86\injdll.obj x86\proctype.obj x86\util.obj
|
||||||
X64OBJS = x64\proctype.obj x64\injdll.obj x64\util.obj
|
X64OBJS = x64\injdll.obj x64\proctype.obj x64\util.obj x64\procrva.obj
|
||||||
|
|
||||||
!IF !DEFINED(V)
|
!IF !DEFINED(V)
|
||||||
V = 0
|
V = 0
|
||||||
@ -93,7 +93,7 @@ ansicon64: x64 x64\ansicon.exe x64\ANSI64.dll
|
|||||||
x86:
|
x86:
|
||||||
mkdir x86
|
mkdir x86
|
||||||
|
|
||||||
x86\ansicon.exe: x86\ansicon.obj $(X86OBJS) x86\LLW.obj x86\ansicon.res
|
x86\ansicon.exe: x86\ansicon.obj $(X86OBJS) x86\procrva.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
|
||||||
@ -111,7 +111,7 @@ x86\ANSI32.dll: x86\ANSI.obj $(X86OBJS) x86\ansi.res
|
|||||||
x64:
|
x64:
|
||||||
mkdir x64
|
mkdir x64
|
||||||
|
|
||||||
x64\ansicon.exe: x64\ansicon.obj $(X64OBJS) x64\LLW.obj x64\ansicon.res
|
x64\ansicon.exe: x64\ansicon.obj $(X64OBJS) x64\ansicon.res
|
||||||
$(LDmsg)$(CC) /nologo $(SHARE) /Fe$@ $** $(LIBS) $(LINK)
|
$(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
|
||||||
@ -133,7 +133,7 @@ ANSI.rc: version.h
|
|||||||
util.c: ansicon.h version.h
|
util.c: ansicon.h version.h
|
||||||
injdll.c: ansicon.h
|
injdll.c: ansicon.h
|
||||||
proctype.c: ansicon.h
|
proctype.c: ansicon.h
|
||||||
LLW.c: ansicon.h
|
procrva.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$@ $?
|
||||||
|
85
procrva.c
Normal file
85
procrva.c
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
Get the RVA of a function directly from a module. This allows 64-bit code to
|
||||||
|
work with 32-bit DLLs, and eliminates (or at least reduces) the possibility
|
||||||
|
of the function already being hooked.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ansicon.h"
|
||||||
|
|
||||||
|
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
|
||||||
|
DWORD GetProcRVA( LPCTSTR module, LPCSTR func )
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
HMODULE hMod;
|
||||||
|
TCHAR buf[MAX_PATH];
|
||||||
|
UINT len;
|
||||||
|
PIMAGE_NT_HEADERS pNTHeader;
|
||||||
|
PIMAGE_EXPORT_DIRECTORY pExportDir;
|
||||||
|
PDWORD fun_table, name_table;
|
||||||
|
PWORD ord_table;
|
||||||
|
PDWORD pFunc;
|
||||||
|
DWORD rva;
|
||||||
|
|
||||||
|
#ifdef _WIN64
|
||||||
|
if (bits == 32)
|
||||||
|
len = GetSystemWow64Directory( buf, MAX_PATH );
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
len = GetSystemDirectory( buf, MAX_PATH );
|
||||||
|
buf[len++] = '\\';
|
||||||
|
wcscpy( buf + len, module );
|
||||||
|
hMod = LoadLibraryEx( buf, NULL, LOAD_LIBRARY_AS_IMAGE_RESOURCE );
|
||||||
|
if (hMod == NULL)
|
||||||
|
{
|
||||||
|
#ifdef _WIN64
|
||||||
|
DEBUGSTR( 1, L"Unable to load %d-bit %s (%lu)!",
|
||||||
|
bits, module, GetLastError() );
|
||||||
|
#else
|
||||||
|
DEBUGSTR( 1, L"Unable to load %s (%lu)!", module, GetLastError() );
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// The handle uses low bits as flags, so strip 'em off.
|
||||||
|
pDosHeader = (PIMAGE_DOS_HEADER)((DWORD_PTR)hMod & ~0xFFFF);
|
||||||
|
pNTHeader = MakeVA( PIMAGE_NT_HEADERS, pDosHeader->e_lfanew );
|
||||||
|
#ifdef _WIN64
|
||||||
|
if (bits == 32)
|
||||||
|
pExportDir = MakeVA( PIMAGE_EXPORT_DIRECTORY,
|
||||||
|
((PIMAGE_NT_HEADERS32)pNTHeader)->EXPORTDIR.VirtualAddress );
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
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 );
|
||||||
|
|
||||||
|
pFunc = bsearch( func, name_table, pExportDir->NumberOfNames,
|
||||||
|
sizeof(DWORD), export_cmp );
|
||||||
|
if (pFunc == NULL)
|
||||||
|
{
|
||||||
|
#ifdef _WIN64
|
||||||
|
DEBUGSTR( 1, L"Could not find %d-bit %s!", bits, func );
|
||||||
|
#else
|
||||||
|
DEBUGSTR( 1, L"Could not find %s!", func );
|
||||||
|
#endif
|
||||||
|
rva = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rva = fun_table[ord_table[pFunc - name_table]];
|
||||||
|
}
|
||||||
|
FreeLibrary( hMod );
|
||||||
|
return rva;
|
||||||
|
}
|
62
proctype.c
62
proctype.c
@ -2,12 +2,44 @@
|
|||||||
Test for a valid process (i386 for x86; that or AMD64 for x64). We can get
|
Test for a valid process (i386 for x86; that or AMD64 for x64). We can get
|
||||||
that info from the image header, which means getting the process's base
|
that info from the image header, which means getting the process's base
|
||||||
address (which we need anyway, to modify the imports). The simplest way to
|
address (which we need anyway, to modify the imports). The simplest way to
|
||||||
do that is to enumerate the pages, looking for an executable image.
|
do that is to enumerate the pages, looking for an executable image. A .NET
|
||||||
|
AnyCPU process has a 32-bit structure, but will load as 64-bit when possible.
|
||||||
|
The 64-bit version (both DLLs) will say this is type 48 (halfway between 32 &
|
||||||
|
64); the 32-bit version will ignore it if run on a 64-bit OS.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ansicon.h"
|
#include "ansicon.h"
|
||||||
|
|
||||||
|
|
||||||
|
#if !defined(_WIN64) && !defined(W32ON64)
|
||||||
|
static BOOL ProcessIs64( HANDLE hProcess )
|
||||||
|
{
|
||||||
|
BOOL wow;
|
||||||
|
|
||||||
|
typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS)( HANDLE, PBOOL );
|
||||||
|
static LPFN_ISWOW64PROCESS fnIsWow64Process;
|
||||||
|
|
||||||
|
if (fnIsWow64Process == INVALID_HANDLE_VALUE)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (fnIsWow64Process == NULL)
|
||||||
|
{
|
||||||
|
fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(
|
||||||
|
GetModuleHandle( L"kernel32.dll" ), "IsWow64Process" );
|
||||||
|
if (fnIsWow64Process == NULL)
|
||||||
|
{
|
||||||
|
fnIsWow64Process = INVALID_HANDLE_VALUE;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If IsWow64Process fails, say it is 64, since injection probably wouldn't
|
||||||
|
// work, either.
|
||||||
|
return !(fnIsWow64Process( hProcess, &wow ) && wow);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
int ProcessType( LPPROCESS_INFORMATION ppi, PBYTE* pBase, BOOL* gui )
|
int ProcessType( LPPROCESS_INFORMATION ppi, PBYTE* pBase, BOOL* gui )
|
||||||
{
|
{
|
||||||
PBYTE ptr;
|
PBYTE ptr;
|
||||||
@ -43,6 +75,34 @@ int ProcessType( LPPROCESS_INFORMATION ppi, PBYTE* pBase, BOOL* gui )
|
|||||||
{
|
{
|
||||||
if (nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_I386)
|
if (nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_I386)
|
||||||
{
|
{
|
||||||
|
PIMAGE_NT_HEADERS32 pNTHeader = (PIMAGE_NT_HEADERS32)&nt_header;
|
||||||
|
if (pNTHeader->COMDIR.VirtualAddress != 0 &&
|
||||||
|
pNTHeader->COMDIR.Size != 0)
|
||||||
|
{
|
||||||
|
IMAGE_COR20_HEADER ComHeader, *pComHeader;
|
||||||
|
pComHeader = (PIMAGE_COR20_HEADER)((PBYTE)minfo.BaseAddress
|
||||||
|
+ pNTHeader->COMDIR.VirtualAddress);
|
||||||
|
ReadProcVar( pComHeader, &ComHeader );
|
||||||
|
if ((ComHeader.Flags & COMIMAGE_FLAGS_ILONLY) &&
|
||||||
|
!(ComHeader.Flags & COMIMAGE_FLAGS_32BITREQUIRED))
|
||||||
|
{
|
||||||
|
#if defined(_WIN64) || !defined(W32ON64) // W32ON64 will log due to -P
|
||||||
|
DEBUGSTR( 1, L" AnyCPU %s (base = %.8X)",
|
||||||
|
(*gui) ? L"GUI" : L"console",
|
||||||
|
PtrToUint( minfo.BaseAddress ) );
|
||||||
|
#endif
|
||||||
|
#if defined(_WIN64) || defined(W32ON64)
|
||||||
|
return 48;
|
||||||
|
#else
|
||||||
|
if (ProcessIs64( ppi->hProcess ))
|
||||||
|
{
|
||||||
|
DEBUGSTR( 1, L" Unsupported (use x64\\ansicon)" );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 32;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
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",
|
||||||
PtrToUint( minfo.BaseAddress ) );
|
PtrToUint( minfo.BaseAddress ) );
|
||||||
|
26
util.c
26
util.c
@ -11,6 +11,7 @@ LPTSTR prog;
|
|||||||
|
|
||||||
int log_level;
|
int log_level;
|
||||||
|
|
||||||
|
TCHAR DllName[MAX_PATH]; // Dll file name
|
||||||
char ansi_dll[MAX_PATH];
|
char ansi_dll[MAX_PATH];
|
||||||
DWORD ansi_len;
|
DWORD ansi_len;
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
@ -43,31 +44,27 @@ LPTSTR get_program_name( LPTSTR program )
|
|||||||
|
|
||||||
|
|
||||||
// Get the ANSI path of the DLL for the import. If it can't be converted,
|
// 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
|
// just use the name and hope it's on the PATH.
|
||||||
// path/name, including padding to make it dword-aligned. The 64-bit version
|
void set_ansi_dll( void )
|
||||||
// expects ansi_bits to point to the size within dll on entry.
|
|
||||||
void set_ansi_dll( LPTSTR dll )
|
|
||||||
{
|
{
|
||||||
BOOL bad;
|
BOOL bad;
|
||||||
|
|
||||||
ansi_len = WideCharToMultiByte( CP_ACP, WC_NO_BEST_FIT_CHARS, dll, -1,
|
ansi_len = WideCharToMultiByte( CP_ACP, WC_NO_BEST_FIT_CHARS, DllName, -1,
|
||||||
NULL, 0, NULL, &bad );
|
NULL, 0, NULL, &bad );
|
||||||
if (bad || ansi_len > MAX_PATH)
|
if (bad || ansi_len > MAX_PATH)
|
||||||
{
|
{
|
||||||
ansi_len = 12;
|
|
||||||
memcpy( ansi_dll, "ANSI32.dll\0", 12 );
|
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
if (*ansi_bits == '6')
|
|
||||||
{
|
|
||||||
ansi_dll[4] = '6';
|
|
||||||
ansi_dll[5] = '4';
|
|
||||||
}
|
|
||||||
ansi_bits = ansi_dll + 4;
|
ansi_bits = ansi_dll + 4;
|
||||||
|
if (*DllNameType == '6')
|
||||||
|
memcpy( ansi_dll, "ANSI64.dll\0", 12 );
|
||||||
|
else
|
||||||
#endif
|
#endif
|
||||||
|
memcpy( ansi_dll, "ANSI32.dll\0", 12 );
|
||||||
|
ansi_len = 12;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
WideCharToMultiByte( CP_ACP, WC_NO_BEST_FIT_CHARS, dll, -1,
|
WideCharToMultiByte( CP_ACP, WC_NO_BEST_FIT_CHARS, DllName, -1,
|
||||||
ansi_dll, MAX_PATH, NULL, NULL );
|
ansi_dll, MAX_PATH, NULL, NULL );
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
ansi_bits = ansi_dll + ansi_len - 7;
|
ansi_bits = ansi_dll + ansi_len - 7;
|
||||||
@ -104,6 +101,9 @@ void DEBUGSTR( int level, LPTSTR szFormat, ... )
|
|||||||
{
|
{
|
||||||
SYSTEMTIME now;
|
SYSTEMTIME now;
|
||||||
GetLocalTime( &now );
|
GetLocalTime( &now );
|
||||||
|
fseek( file, 0, SEEK_END );
|
||||||
|
if (ftell( file ) != 0)
|
||||||
|
putc( '\n', file );
|
||||||
fprintf( file, "ANSICON (" BITSA "-bit) v" PVERSA " log (%d) started "
|
fprintf( file, "ANSICON (" BITSA "-bit) v" PVERSA " log (%d) started "
|
||||||
"%d-%.2d-%.2d %d:%.2d:%.2d\n",
|
"%d-%.2d-%.2d %d:%.2d:%.2d\n",
|
||||||
log_level,
|
log_level,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user