Always find the base address of kernel32.dll.
This commit is contained in:
parent
b2c8a9ec12
commit
bccf933c0a
18
ANSI.c
18
ANSI.c
@ -111,9 +111,10 @@
|
|||||||
v.166, 20 & 21 September, 2013:
|
v.166, 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.67, 25 January, 2014:
|
v1.67, 25 to 27 January, 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;
|
||||||
|
always find the base address of kernel32.dll.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ansicon.h"
|
#include "ansicon.h"
|
||||||
@ -252,8 +253,9 @@ SHARED DWORD s_flag;
|
|||||||
#define GRM_INIT 1
|
#define GRM_INIT 1
|
||||||
#define GRM_EXIT 2
|
#define GRM_EXIT 2
|
||||||
|
|
||||||
|
SHARED DWORD LLW32r;
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
SHARED DWORD LLW32;
|
SHARED DWORD LLW64r;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@ -1842,6 +1844,16 @@ BOOL WINAPI DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved )
|
|||||||
hDllInstance = hInstance; // save Dll instance handle
|
hDllInstance = hInstance; // save Dll instance handle
|
||||||
DEBUGSTR( 1, L"hDllInstance = %p", hDllInstance );
|
DEBUGSTR( 1, L"hDllInstance = %p", hDllInstance );
|
||||||
|
|
||||||
|
if (LLW32r == 0)
|
||||||
|
{
|
||||||
|
if (!get_LLW32r())
|
||||||
|
return FALSE;
|
||||||
|
#ifdef _WIN64
|
||||||
|
if (!get_LLW64r())
|
||||||
|
return FALSE;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
// Get the entry points to the original functions.
|
// Get the entry points to the original functions.
|
||||||
hKernel = GetModuleHandleA( APIKernel );
|
hKernel = GetModuleHandleA( APIKernel );
|
||||||
for (hook = Hooks; hook->name; ++hook)
|
for (hook = Hooks; hook->name; ++hook)
|
||||||
|
30
ansicon.c
30
ansicon.c
@ -78,7 +78,7 @@
|
|||||||
don't write the reset sequence if output is redirected.
|
don't write the reset sequence if output is redirected.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define PDATE L"25 January, 2014"
|
#define PDATE L"27 January, 2014"
|
||||||
|
|
||||||
#include "ansicon.h"
|
#include "ansicon.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
@ -111,10 +111,11 @@ BOOL GetParentProcessInfo( LPPROCESS_INFORMATION ppi, LPTSTR );
|
|||||||
|
|
||||||
|
|
||||||
// The DLL shares this variable, so injection requires it here.
|
// The DLL shares this variable, so injection requires it here.
|
||||||
|
DWORD LLW32r;
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
DWORD LLW32;
|
DWORD LLW64r;
|
||||||
extern LPVOID base;
|
|
||||||
#endif
|
#endif
|
||||||
|
extern LPVOID kernel32_base;
|
||||||
|
|
||||||
|
|
||||||
// Find the name of the DLL and inject it.
|
// Find the name of the DLL and inject it.
|
||||||
@ -137,11 +138,18 @@ BOOL Inject( LPPROCESS_INFORMATION ppi, BOOL* gui, LPCTSTR app )
|
|||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
wsprintf( dll + len, L"ANSI%d.dll", type );
|
wsprintf( dll + len, L"ANSI%d.dll", type );
|
||||||
if (type == 32)
|
if (type == 32)
|
||||||
|
{
|
||||||
|
get_LLW32r();
|
||||||
InjectDLL32( ppi, dll );
|
InjectDLL32( ppi, dll );
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
get_LLW64r();
|
||||||
InjectDLL64( ppi, dll );
|
InjectDLL64( ppi, dll );
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
wcscpy( dll + len, L"ANSI32.dll" );
|
wcscpy( dll + len, L"ANSI32.dll" );
|
||||||
|
get_LLW32r();
|
||||||
InjectDLL32( ppi, dll );
|
InjectDLL32( ppi, dll );
|
||||||
#endif
|
#endif
|
||||||
return TRUE;
|
return TRUE;
|
||||||
@ -275,19 +283,15 @@ int main( void )
|
|||||||
DEBUGSTR( 1, L"Already installed" );
|
DEBUGSTR( 1, L"Already installed" );
|
||||||
}
|
}
|
||||||
else if (GetParentProcessInfo( &pi, arg ))
|
else if (GetParentProcessInfo( &pi, arg ))
|
||||||
{
|
|
||||||
pi.hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pi.dwProcessId);
|
|
||||||
pi.hThread = OpenThread( THREAD_ALL_ACCESS, FALSE, pi.dwThreadId );
|
|
||||||
SuspendThread( pi.hThread );
|
|
||||||
#ifdef _WIN64
|
|
||||||
// Find the base address of kernel32.dll if the 64-bit version is
|
|
||||||
// injecting into a 32-bit parent.
|
|
||||||
if (IsWow64Process( pi.hProcess, &gui ) && gui)
|
|
||||||
{
|
{
|
||||||
HANDLE hSnap;
|
HANDLE hSnap;
|
||||||
MODULEENTRY32 me;
|
MODULEENTRY32 me;
|
||||||
BOOL fOk;
|
BOOL fOk;
|
||||||
|
|
||||||
|
pi.hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pi.dwProcessId);
|
||||||
|
pi.hThread = OpenThread( THREAD_ALL_ACCESS, FALSE, pi.dwThreadId );
|
||||||
|
SuspendThread( pi.hThread );
|
||||||
|
// Find the base address of kernel32.dll.
|
||||||
hSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE |
|
hSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE |
|
||||||
TH32CS_SNAPMODULE32,
|
TH32CS_SNAPMODULE32,
|
||||||
pi.dwProcessId );
|
pi.dwProcessId );
|
||||||
@ -299,14 +303,12 @@ int main( void )
|
|||||||
{
|
{
|
||||||
if (_wcsicmp( me.szModule, L"kernel32.dll" ) == 0)
|
if (_wcsicmp( me.szModule, L"kernel32.dll" ) == 0)
|
||||||
{
|
{
|
||||||
base = me.modBaseAddr;
|
kernel32_base = me.modBaseAddr;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CloseHandle( hSnap );
|
CloseHandle( hSnap );
|
||||||
}
|
}
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (!Inject( &pi, &gui, arg ))
|
if (!Inject( &pi, &gui, arg ))
|
||||||
rc = 1;
|
rc = 1;
|
||||||
ResumeThread( pi.hThread );
|
ResumeThread( pi.hThread );
|
||||||
|
@ -47,6 +47,8 @@ typedef struct
|
|||||||
int ProcessType( LPPROCESS_INFORMATION, BOOL* );
|
int ProcessType( LPPROCESS_INFORMATION, BOOL* );
|
||||||
void InjectDLL32( LPPROCESS_INFORMATION, LPCTSTR );
|
void InjectDLL32( LPPROCESS_INFORMATION, LPCTSTR );
|
||||||
void InjectDLL64( LPPROCESS_INFORMATION, LPCTSTR );
|
void InjectDLL64( LPPROCESS_INFORMATION, LPCTSTR );
|
||||||
|
BOOL get_LLW32r( void );
|
||||||
|
BOOL get_LLW64r( void );
|
||||||
|
|
||||||
extern TCHAR prog_path[MAX_PATH];
|
extern TCHAR prog_path[MAX_PATH];
|
||||||
extern LPTSTR prog;
|
extern LPTSTR prog;
|
||||||
|
110
injdll32.c
110
injdll32.c
@ -31,13 +31,14 @@ TWow64SetThreadContext Wow64SetThreadContext;
|
|||||||
#define CONTEXT_CONTROL WOW64_CONTEXT_CONTROL
|
#define CONTEXT_CONTROL WOW64_CONTEXT_CONTROL
|
||||||
#define GetThreadContext Wow64GetThreadContext
|
#define GetThreadContext Wow64GetThreadContext
|
||||||
#define SetThreadContext Wow64SetThreadContext
|
#define SetThreadContext Wow64SetThreadContext
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern DWORD LLW32r;
|
||||||
|
LPVOID kernel32_base;
|
||||||
|
PIMAGE_DOS_HEADER pDosHeader;
|
||||||
|
|
||||||
#define MakeVA( cast, offset ) (cast)((DWORD_PTR)pDosHeader + (DWORD)(offset))
|
#define MakeVA( cast, offset ) (cast)((DWORD_PTR)pDosHeader + (DWORD)(offset))
|
||||||
|
|
||||||
extern DWORD LLW32;
|
|
||||||
LPVOID base;
|
|
||||||
static PIMAGE_DOS_HEADER pDosHeader;
|
|
||||||
|
|
||||||
int export_cmp( const void* a, const void* b )
|
int export_cmp( const void* a, const void* b )
|
||||||
{
|
{
|
||||||
return strcmp( (LPCSTR)a, MakeVA( LPCSTR, *(const PDWORD)b ) );
|
return strcmp( (LPCSTR)a, MakeVA( LPCSTR, *(const PDWORD)b ) );
|
||||||
@ -45,12 +46,9 @@ int export_cmp( const void* a, const void* b )
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Get the relative address of the 32-bit LoadLibraryW function from 64-bit code.
|
Get the relative address of LoadLibraryW direct from kernel32.dll.
|
||||||
This was originally done via executing a helper program (ANSI-LLW.exe), but I
|
|
||||||
never liked doing that, so now I do it the "hard" way - load the 32-bit
|
|
||||||
kernel32.dll directly and search the exports.
|
|
||||||
*/
|
*/
|
||||||
BOOL get_LLW32( void )
|
BOOL get_LLW32r( void )
|
||||||
{
|
{
|
||||||
HMODULE kernel32;
|
HMODULE kernel32;
|
||||||
TCHAR buf[MAX_PATH];
|
TCHAR buf[MAX_PATH];
|
||||||
@ -61,7 +59,11 @@ BOOL get_LLW32( void )
|
|||||||
PWORD ord_table;
|
PWORD ord_table;
|
||||||
PDWORD pLLW;
|
PDWORD pLLW;
|
||||||
|
|
||||||
|
#ifdef _WIN64
|
||||||
len = GetSystemWow64Directory( buf, MAX_PATH );
|
len = GetSystemWow64Directory( buf, MAX_PATH );
|
||||||
|
#else
|
||||||
|
len = GetSystemDirectory( buf, MAX_PATH );
|
||||||
|
#endif
|
||||||
wcscpy( buf + len, L"\\kernel32.dll" );
|
wcscpy( buf + len, L"\\kernel32.dll" );
|
||||||
kernel32 = LoadLibraryEx( buf, NULL, LOAD_LIBRARY_AS_IMAGE_RESOURCE );
|
kernel32 = LoadLibraryEx( buf, NULL, LOAD_LIBRARY_AS_IMAGE_RESOURCE );
|
||||||
if (kernel32 == NULL)
|
if (kernel32 == NULL)
|
||||||
@ -89,24 +91,24 @@ BOOL get_LLW32( void )
|
|||||||
FreeLibrary( kernel32 );
|
FreeLibrary( kernel32 );
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
LLW32 = fun_table[ord_table[pLLW - name_table]];
|
LLW32r = fun_table[ord_table[pLLW - name_table]];
|
||||||
|
|
||||||
FreeLibrary( kernel32 );
|
FreeLibrary( kernel32 );
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
DWORD LLW32;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
void InjectDLL32( LPPROCESS_INFORMATION ppi, LPCTSTR dll )
|
void InjectDLL32( LPPROCESS_INFORMATION ppi, LPCTSTR dll )
|
||||||
{
|
{
|
||||||
CONTEXT context;
|
CONTEXT context;
|
||||||
DWORD ep;
|
DWORD ep;
|
||||||
DWORD len;
|
BOOL eip;
|
||||||
LPVOID mem;
|
LPVOID mem;
|
||||||
DWORD mem32;
|
DWORD mem32;
|
||||||
DWORD pr;
|
DWORD pr;
|
||||||
|
DWORD LLW;
|
||||||
|
|
||||||
|
DWORD len;
|
||||||
#define CODESIZE 20
|
#define CODESIZE 20
|
||||||
BYTE code[CODESIZE+TSIZE(MAX_PATH)];
|
BYTE code[CODESIZE+TSIZE(MAX_PATH)];
|
||||||
union
|
union
|
||||||
@ -114,9 +116,23 @@ void InjectDLL32( LPPROCESS_INFORMATION ppi, LPCTSTR dll )
|
|||||||
PBYTE pB;
|
PBYTE pB;
|
||||||
PDWORD pL;
|
PDWORD pL;
|
||||||
} ip;
|
} ip;
|
||||||
#ifdef _WIN64
|
|
||||||
BOOL entry = FALSE;
|
struct unicode_string
|
||||||
#endif
|
{
|
||||||
|
USHORT Length;
|
||||||
|
USHORT MaximumLength;
|
||||||
|
DWORD Buffer;
|
||||||
|
};
|
||||||
|
struct ldr_module // incomplete definition
|
||||||
|
{
|
||||||
|
DWORD next, prev;
|
||||||
|
DWORD baseAddress;
|
||||||
|
DWORD entryPoint;
|
||||||
|
DWORD sizeOfImage;
|
||||||
|
struct unicode_string fullDllName;
|
||||||
|
struct unicode_string baseDllName;
|
||||||
|
} ldr;
|
||||||
|
WCHAR basename[MAX_PATH];
|
||||||
|
|
||||||
#ifdef IMPORT_WOW64
|
#ifdef IMPORT_WOW64
|
||||||
if (Wow64GetThreadContext == 0)
|
if (Wow64GetThreadContext == 0)
|
||||||
@ -137,7 +153,6 @@ void InjectDLL32( LPPROCESS_INFORMATION ppi, LPCTSTR dll )
|
|||||||
len = TSIZE(lstrlen( dll ) + 1);
|
len = TSIZE(lstrlen( dll ) + 1);
|
||||||
if (len > TSIZE(MAX_PATH))
|
if (len > TSIZE(MAX_PATH))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
CopyMemory( code + CODESIZE, dll, len );
|
CopyMemory( code + CODESIZE, dll, len );
|
||||||
len += CODESIZE;
|
len += CODESIZE;
|
||||||
|
|
||||||
@ -149,36 +164,15 @@ void InjectDLL32( LPPROCESS_INFORMATION ppi, LPCTSTR dll )
|
|||||||
|
|
||||||
ip.pB = code;
|
ip.pB = code;
|
||||||
|
|
||||||
|
// Determine the base address of kernel32.dll. If injecting into the parent
|
||||||
|
// process, the base has already been determined. Otherwise, use the PEB to
|
||||||
|
// walk the loaded modules.
|
||||||
|
if (kernel32_base != 0)
|
||||||
|
{
|
||||||
ep = context.Eip;
|
ep = context.Eip;
|
||||||
if (LLW32 == 0)
|
eip = TRUE;
|
||||||
{
|
}
|
||||||
#ifndef _WIN64
|
else
|
||||||
LLW32 = (DWORD)GetProcAddress( GetModuleHandle( L"kernel32.dll" ),
|
|
||||||
"LoadLibraryW" );
|
|
||||||
#else
|
|
||||||
struct unicode_string
|
|
||||||
{
|
|
||||||
USHORT Length;
|
|
||||||
USHORT MaximumLength;
|
|
||||||
DWORD Buffer;
|
|
||||||
};
|
|
||||||
struct ldr_module // incomplete definition
|
|
||||||
{
|
|
||||||
DWORD next, prev;
|
|
||||||
DWORD baseAddress;
|
|
||||||
DWORD entryPoint;
|
|
||||||
DWORD sizeOfImage;
|
|
||||||
struct unicode_string fullDllName;
|
|
||||||
struct unicode_string baseDllName;
|
|
||||||
} ldr;
|
|
||||||
WCHAR basename[MAX_PATH];
|
|
||||||
|
|
||||||
if (!get_LLW32())
|
|
||||||
return;
|
|
||||||
// Determine the base address of the 32-bit kernel32.dll. If injecting
|
|
||||||
// into the parent process, base has already been determined. Otherwise,
|
|
||||||
// use the PEB to walk the loaded modules.
|
|
||||||
if (base == 0)
|
|
||||||
{
|
{
|
||||||
// When a process is created suspended, EAX has the entry point and EBX
|
// When a process is created suspended, EAX has the entry point and EBX
|
||||||
// points to the PEB.
|
// points to the PEB.
|
||||||
@ -188,11 +182,12 @@ void InjectDLL32( LPPROCESS_INFORMATION ppi, LPCTSTR dll )
|
|||||||
DEBUGSTR( 1, L"Failed to read Ldr from PEB." );
|
DEBUGSTR( 1, L"Failed to read Ldr from PEB." );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
ep = context.Eax;
|
||||||
|
eip = FALSE;
|
||||||
// In case we're a bit slow (which seems to be unlikely), set up an
|
// In case we're a bit slow (which seems to be unlikely), set up an
|
||||||
// infinite loop as the entry point.
|
// infinite loop as the entry point.
|
||||||
WriteProcessMemory( ppi->hProcess, mem, "\xEB\xFE", 2, NULL );
|
WriteProcessMemory( ppi->hProcess, mem, "\xEB\xFE", 2, NULL );
|
||||||
FlushInstructionCache( ppi->hProcess, mem, 2 );
|
FlushInstructionCache( ppi->hProcess, mem, 2 );
|
||||||
ep = context.Eax;
|
|
||||||
context.Eax = mem32;
|
context.Eax = mem32;
|
||||||
SetThreadContext( ppi->hThread, &context );
|
SetThreadContext( ppi->hThread, &context );
|
||||||
VirtualProtectEx( ppi->hProcess, mem, len, PAGE_EXECUTE, &pr );
|
VirtualProtectEx( ppi->hProcess, mem, len, PAGE_EXECUTE, &pr );
|
||||||
@ -220,7 +215,7 @@ void InjectDLL32( LPPROCESS_INFORMATION ppi, LPCTSTR dll )
|
|||||||
basename, ldr.baseDllName.MaximumLength, NULL );
|
basename, ldr.baseDllName.MaximumLength, NULL );
|
||||||
if (_wcsicmp( basename, L"kernel32.dll" ) == 0)
|
if (_wcsicmp( basename, L"kernel32.dll" ) == 0)
|
||||||
{
|
{
|
||||||
LLW32 += ldr.baseAddress;
|
kernel32_base = UIntToPtr( ldr.baseAddress );
|
||||||
goto gotit;
|
goto gotit;
|
||||||
}
|
}
|
||||||
} while (ldr.next != *ip.pL + 0x1c);
|
} while (ldr.next != *ip.pL + 0x1c);
|
||||||
@ -228,12 +223,9 @@ void InjectDLL32( LPPROCESS_INFORMATION ppi, LPCTSTR dll )
|
|||||||
gotit:
|
gotit:
|
||||||
SuspendThread( ppi->hThread );
|
SuspendThread( ppi->hThread );
|
||||||
VirtualProtectEx( ppi->hProcess, mem, len, pr, &pr );
|
VirtualProtectEx( ppi->hProcess, mem, len, pr, &pr );
|
||||||
entry = TRUE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
LLW32 += PtrToUint( base );
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
LLW = PtrToUint( kernel32_base ) + LLW32r;
|
||||||
|
kernel32_base = 0;
|
||||||
|
|
||||||
*ip.pB++ = 0x68; // push ep
|
*ip.pB++ = 0x68; // push ep
|
||||||
*ip.pL++ = ep;
|
*ip.pL++ = ep;
|
||||||
@ -242,7 +234,7 @@ void InjectDLL32( LPPROCESS_INFORMATION ppi, LPCTSTR dll )
|
|||||||
*ip.pB++ = 0x68; // push L"path\to\ANSI32.dll"
|
*ip.pB++ = 0x68; // push L"path\to\ANSI32.dll"
|
||||||
*ip.pL++ = mem32 + CODESIZE;
|
*ip.pL++ = mem32 + CODESIZE;
|
||||||
*ip.pB++ = 0xe8; // call LoadLibraryW
|
*ip.pB++ = 0xe8; // call LoadLibraryW
|
||||||
*ip.pL++ = LLW32 - (mem32 + (DWORD)(ip.pB+4 - code));
|
*ip.pL++ = LLW - (mem32 + (DWORD)(ip.pB+4 - code));
|
||||||
*ip.pB++ = 0x61; // popa
|
*ip.pB++ = 0x61; // popa
|
||||||
*ip.pB++ = 0x9d; // popf
|
*ip.pB++ = 0x9d; // popf
|
||||||
*ip.pB++ = 0xc3; // ret
|
*ip.pB++ = 0xc3; // ret
|
||||||
@ -250,10 +242,10 @@ void InjectDLL32( LPPROCESS_INFORMATION ppi, LPCTSTR dll )
|
|||||||
WriteProcessMemory( ppi->hProcess, mem, code, len, NULL );
|
WriteProcessMemory( ppi->hProcess, mem, code, len, NULL );
|
||||||
FlushInstructionCache( ppi->hProcess, mem, len );
|
FlushInstructionCache( ppi->hProcess, mem, len );
|
||||||
VirtualProtectEx( ppi->hProcess, mem, len, PAGE_EXECUTE, &pr );
|
VirtualProtectEx( ppi->hProcess, mem, len, PAGE_EXECUTE, &pr );
|
||||||
#ifdef _WIN64
|
|
||||||
if (entry)
|
if (eip)
|
||||||
return;
|
{
|
||||||
#endif
|
|
||||||
context.Eip = mem32;
|
context.Eip = mem32;
|
||||||
SetThreadContext( ppi->hThread, &context );
|
SetThreadContext( ppi->hThread, &context );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
157
injdll64.c
157
injdll64.c
@ -17,17 +17,97 @@
|
|||||||
|
|
||||||
#include "ansicon.h"
|
#include "ansicon.h"
|
||||||
|
|
||||||
|
extern DWORD LLW64r;
|
||||||
|
extern LPVOID kernel32_base;
|
||||||
|
extern PIMAGE_DOS_HEADER pDosHeader;
|
||||||
|
|
||||||
|
#define MakeVA( cast, offset ) (cast)((DWORD_PTR)pDosHeader + (DWORD)(offset))
|
||||||
|
|
||||||
|
extern int export_cmp( const void* a, const void* b );
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Get the relative address of LoadLibraryW direct from kernel32.dll.
|
||||||
|
*/
|
||||||
|
BOOL 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;
|
||||||
|
|
||||||
|
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 FALSE;
|
||||||
|
}
|
||||||
|
// 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->OptionalHeader.
|
||||||
|
DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].
|
||||||
|
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 LoadLibraryW!" );
|
||||||
|
FreeLibrary( kernel32 );
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
LLW64r = fun_table[ord_table[pLLW - name_table]];
|
||||||
|
|
||||||
|
FreeLibrary( kernel32 );
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void InjectDLL64( LPPROCESS_INFORMATION ppi, LPCTSTR dll )
|
void InjectDLL64( LPPROCESS_INFORMATION ppi, LPCTSTR dll )
|
||||||
{
|
{
|
||||||
CONTEXT context;
|
CONTEXT context;
|
||||||
DWORD len;
|
DWORD64 ep;
|
||||||
|
BOOL rip;
|
||||||
LPVOID mem;
|
LPVOID mem;
|
||||||
|
DWORD pr;
|
||||||
DWORD64 LLW;
|
DWORD64 LLW;
|
||||||
|
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
PBYTE pB;
|
PBYTE pB;
|
||||||
PDWORD64 pL;
|
PDWORD64 pL;
|
||||||
} ip;
|
} ip;
|
||||||
|
|
||||||
|
struct unicode_string
|
||||||
|
{
|
||||||
|
USHORT Length;
|
||||||
|
USHORT MaximumLength;
|
||||||
|
DWORD64 Buffer;
|
||||||
|
};
|
||||||
|
struct ldr_module // incomplete definition
|
||||||
|
{
|
||||||
|
DWORD64 next, prev;
|
||||||
|
DWORD64 baseAddress;
|
||||||
|
DWORD64 entryPoint;
|
||||||
|
DWORD64 sizeOfImage;
|
||||||
|
struct unicode_string fullDllName;
|
||||||
|
struct unicode_string baseDllName;
|
||||||
|
} ldr;
|
||||||
|
WCHAR basename[MAX_PATH];
|
||||||
|
|
||||||
|
DWORD len;
|
||||||
#define CODESIZE 92
|
#define CODESIZE 92
|
||||||
static BYTE code[CODESIZE+TSIZE(MAX_PATH)] = {
|
static BYTE code[CODESIZE+TSIZE(MAX_PATH)] = {
|
||||||
0,0,0,0,0,0,0,0, // original rip
|
0,0,0,0,0,0,0,0, // original rip
|
||||||
@ -78,19 +158,86 @@ void InjectDLL64( LPPROCESS_INFORMATION ppi, LPCTSTR dll )
|
|||||||
CopyMemory( code + CODESIZE, dll, len );
|
CopyMemory( code + CODESIZE, dll, len );
|
||||||
len += CODESIZE;
|
len += CODESIZE;
|
||||||
|
|
||||||
context.ContextFlags = CONTEXT_CONTROL;
|
context.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
|
||||||
GetThreadContext( ppi->hThread, &context );
|
GetThreadContext( ppi->hThread, &context );
|
||||||
mem = VirtualAllocEx( ppi->hProcess, NULL, len, MEM_COMMIT,
|
mem = VirtualAllocEx( ppi->hProcess, NULL, len, MEM_COMMIT,
|
||||||
PAGE_EXECUTE_READWRITE );
|
PAGE_READWRITE );
|
||||||
LLW = (DWORD64)LoadLibraryW;
|
|
||||||
|
|
||||||
ip.pB = code;
|
ip.pB = code;
|
||||||
|
|
||||||
*ip.pL++ = context.Rip;
|
// Determine the base address of kernel32.dll. If injecting into the parent
|
||||||
|
// process, the base has already been determined. Otherwise, use the PEB to
|
||||||
|
// walk the loaded modules.
|
||||||
|
if (kernel32_base != 0)
|
||||||
|
{
|
||||||
|
ep = context.Rip;
|
||||||
|
rip = TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// When a process is created suspended, RCX has the entry point and RDX
|
||||||
|
// points to the PEB.
|
||||||
|
if (!ReadProcessMemory( ppi->hProcess, (LPVOID)(context.Rdx + 0x18),
|
||||||
|
ip.pL, 8, NULL ))
|
||||||
|
{
|
||||||
|
DEBUGSTR( 1, L"Failed to read Ldr from PEB." );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ep = context.Rcx;
|
||||||
|
rip = FALSE;
|
||||||
|
// In case we're a bit slow (which seems to be unlikely), set up an
|
||||||
|
// infinite loop as the entry point.
|
||||||
|
WriteProcessMemory( ppi->hProcess, (PBYTE)mem + 16, "\xEB\xFE", 2, NULL );
|
||||||
|
FlushInstructionCache( ppi->hProcess, (PBYTE)mem + 16, 2 );
|
||||||
|
context.Rcx = (DWORD64)mem + 16;
|
||||||
|
SetThreadContext( ppi->hThread, &context );
|
||||||
|
VirtualProtectEx( ppi->hProcess, mem, len, PAGE_EXECUTE, &pr );
|
||||||
|
// Now resume the thread, as the PEB hasn't even been created yet.
|
||||||
|
ResumeThread( ppi->hThread );
|
||||||
|
while (*ip.pL == 0)
|
||||||
|
{
|
||||||
|
Sleep( 0 );
|
||||||
|
ReadProcessMemory( ppi->hProcess, (LPVOID)(context.Rdx + 0x18),
|
||||||
|
ip.pL, 8, NULL );
|
||||||
|
}
|
||||||
|
// Read PEB_LDR_DATA.InInitializationOrderModuleList.Flink.
|
||||||
|
ReadProcessMemory( ppi->hProcess, (LPVOID)(*ip.pL + 0x30),
|
||||||
|
&ip.pL[1], 8, NULL );
|
||||||
|
// Sometimes we're so quick ntdll.dll is the only one present, so keep
|
||||||
|
// looping until kernel32.dll shows up.
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
ldr.next = ip.pL[1];
|
||||||
|
do
|
||||||
|
{
|
||||||
|
ReadProcessMemory( ppi->hProcess, (LPVOID)ldr.next,
|
||||||
|
&ldr, sizeof(ldr), NULL );
|
||||||
|
ReadProcessMemory( ppi->hProcess, (LPVOID)ldr.baseDllName.Buffer,
|
||||||
|
basename, ldr.baseDllName.MaximumLength, NULL );
|
||||||
|
if (_wcsicmp( basename, L"kernel32.dll" ) == 0)
|
||||||
|
{
|
||||||
|
kernel32_base = (LPVOID)ldr.baseAddress;
|
||||||
|
goto gotit;
|
||||||
|
}
|
||||||
|
} while (ldr.next != *ip.pL + 0x30);
|
||||||
|
}
|
||||||
|
gotit:
|
||||||
|
SuspendThread( ppi->hThread );
|
||||||
|
VirtualProtectEx( ppi->hProcess, mem, len, pr, &pr );
|
||||||
|
}
|
||||||
|
LLW = (DWORD64)kernel32_base + LLW64r;
|
||||||
|
kernel32_base = 0;
|
||||||
|
|
||||||
|
*ip.pL++ = ep;
|
||||||
*ip.pL++ = LLW;
|
*ip.pL++ = LLW;
|
||||||
|
|
||||||
WriteProcessMemory( ppi->hProcess, mem, code, len, NULL );
|
WriteProcessMemory( ppi->hProcess, mem, code, len, NULL );
|
||||||
FlushInstructionCache( ppi->hProcess, mem, len );
|
FlushInstructionCache( ppi->hProcess, mem, len );
|
||||||
|
VirtualProtectEx( ppi->hProcess, mem, len, PAGE_EXECUTE, &pr );
|
||||||
|
|
||||||
|
if (rip)
|
||||||
|
{
|
||||||
context.Rip = (DWORD64)mem + 16;
|
context.Rip = (DWORD64)mem + 16;
|
||||||
SetThreadContext( ppi->hThread, &context );
|
SetThreadContext( ppi->hThread, &context );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user