2010-11-08 15:31:01 +10:00
|
|
|
/*
|
|
|
|
Inject code into the target process to load our DLL. The target thread
|
|
|
|
should be suspended on entry; it remains suspended on exit.
|
|
|
|
|
|
|
|
Initially I used the "stack" method of injection. However, this fails
|
|
|
|
when DEP is active, since that doesn't allow code to execute in the stack.
|
|
|
|
To overcome this I used the "CreateRemoteThread" method. However, this
|
|
|
|
would fail with Wselect, a program to assist batch files. Wselect runs,
|
|
|
|
but it has no output. As it turns out, removing the suspended flag would
|
|
|
|
make Wselect work, but it caused problems with everything else. So now I
|
|
|
|
allocate a section of memory and change the context to run from there. At
|
|
|
|
first I had an event to signal when the library was loaded, then the memory
|
|
|
|
was released. However, that wouldn't work with -p and CMD.EXE (4NT v8
|
|
|
|
worked fine). Since it's possible the DLL might start a process suspended,
|
|
|
|
I've decided to simply keep the memory.
|
|
|
|
*/
|
|
|
|
|
2010-12-12 21:58:35 +10:00
|
|
|
#include "ansicon.h"
|
2010-11-08 15:31:01 +10:00
|
|
|
|
|
|
|
#ifdef _WIN64
|
2010-11-15 21:51:38 +10:00
|
|
|
#if defined(__MINGW64__) || (defined(_MSC_VER) && _MSC_VER <= 1400)
|
2010-11-08 15:31:01 +10:00
|
|
|
#include "wow64.h"
|
|
|
|
|
|
|
|
TWow64GetThreadContext Wow64GetThreadContext;
|
|
|
|
TWow64SetThreadContext Wow64SetThreadContext;
|
2010-11-15 21:51:38 +10:00
|
|
|
#endif
|
2010-11-08 15:31:01 +10:00
|
|
|
|
|
|
|
#define CONTEXT WOW64_CONTEXT
|
|
|
|
#undef CONTEXT_CONTROL
|
|
|
|
#define CONTEXT_CONTROL WOW64_CONTEXT_CONTROL
|
|
|
|
#define GetThreadContext Wow64GetThreadContext
|
|
|
|
#define SetThreadContext Wow64SetThreadContext
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2010-11-13 14:49:27 +10:00
|
|
|
DWORD LLW;
|
2010-11-08 15:31:01 +10:00
|
|
|
|
|
|
|
|
2010-11-15 21:51:38 +10:00
|
|
|
void InjectDLL32( LPPROCESS_INFORMATION ppi, LPCTSTR dll )
|
2010-11-08 15:31:01 +10:00
|
|
|
{
|
|
|
|
CONTEXT context;
|
|
|
|
DWORD len;
|
|
|
|
LPVOID mem;
|
|
|
|
DWORD mem32;
|
|
|
|
#define CODESIZE 20
|
2010-11-15 21:51:38 +10:00
|
|
|
BYTE code[CODESIZE+MAX_PATH*sizeof(TCHAR)];
|
|
|
|
union
|
|
|
|
{
|
|
|
|
PBYTE pB;
|
|
|
|
PDWORD pL;
|
|
|
|
} ip;
|
2010-11-08 15:31:01 +10:00
|
|
|
|
2010-11-15 21:51:38 +10:00
|
|
|
len = lstrlen( dll ) + 1;
|
2010-11-08 15:31:01 +10:00
|
|
|
if (len > MAX_PATH)
|
|
|
|
return;
|
2010-11-15 21:51:38 +10:00
|
|
|
len *= sizeof(TCHAR);
|
2010-11-08 15:31:01 +10:00
|
|
|
|
2010-11-13 14:49:27 +10:00
|
|
|
if (LLW == 0)
|
2010-11-08 15:31:01 +10:00
|
|
|
{
|
|
|
|
#ifdef _WIN64
|
2010-11-15 21:51:38 +10:00
|
|
|
#ifdef __MINGW64__
|
2010-12-04 15:19:36 +10:00
|
|
|
HMODULE hKernel = GetModuleHandleA( "kernel32.dll" );
|
2010-11-08 15:31:01 +10:00
|
|
|
#define GETPROC( proc ) proc = (T##proc)GetProcAddress( hKernel, #proc )
|
|
|
|
GETPROC( Wow64GetThreadContext );
|
|
|
|
GETPROC( Wow64SetThreadContext );
|
|
|
|
// Assume if one is defined, so is the other.
|
|
|
|
if (Wow64GetThreadContext == 0)
|
2010-12-12 21:58:35 +10:00
|
|
|
{
|
2010-12-16 16:00:56 +10:00
|
|
|
DEBUGSTR( L"Failed to get pointer to Wow64GetThreadContext.\n" );
|
2010-11-08 15:31:01 +10:00
|
|
|
return;
|
2010-12-12 21:58:35 +10:00
|
|
|
}
|
2010-11-15 21:51:38 +10:00
|
|
|
#endif
|
2010-11-08 15:31:01 +10:00
|
|
|
|
2010-11-15 21:51:38 +10:00
|
|
|
STARTUPINFO si;
|
2010-11-08 15:31:01 +10:00
|
|
|
PROCESS_INFORMATION pi;
|
|
|
|
ZeroMemory( &si, sizeof(si) );
|
|
|
|
si.cb = sizeof(si);
|
2010-11-13 14:49:27 +10:00
|
|
|
// ...ANSI32.dll\0
|
2010-11-15 21:51:38 +10:00
|
|
|
CopyMemory( code, dll, len - 7*sizeof(TCHAR) );
|
2010-11-13 21:54:02 +10:00
|
|
|
// ...ANSI-LLW.exe\0
|
2010-11-15 21:51:38 +10:00
|
|
|
CopyMemory( code + len - 7*sizeof(TCHAR), L"-LLW.exe", 9*sizeof(TCHAR) );
|
|
|
|
if (!CreateProcess( (LPCTSTR)code, NULL, NULL, NULL, FALSE, 0, NULL, NULL,
|
|
|
|
&si, &pi ))
|
2010-12-12 21:58:35 +10:00
|
|
|
{
|
2010-12-16 16:00:56 +10:00
|
|
|
DEBUGSTR( L"Failed to execute \"%s\".\n", (LPCTSTR)code );
|
2010-11-08 15:31:01 +10:00
|
|
|
return;
|
2010-12-12 21:58:35 +10:00
|
|
|
}
|
2010-11-08 15:31:01 +10:00
|
|
|
WaitForSingleObject( pi.hProcess, INFINITE );
|
2010-11-13 14:49:27 +10:00
|
|
|
GetExitCodeProcess( pi.hProcess, &LLW );
|
2010-11-08 15:31:01 +10:00
|
|
|
CloseHandle( pi.hProcess );
|
|
|
|
CloseHandle( pi.hThread );
|
|
|
|
#else
|
2010-11-15 21:51:38 +10:00
|
|
|
LLW = (DWORD)LoadLibrary;
|
2010-11-08 15:31:01 +10:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
CopyMemory( code + CODESIZE, dll, len );
|
|
|
|
len += CODESIZE;
|
|
|
|
|
|
|
|
context.ContextFlags = CONTEXT_CONTROL;
|
|
|
|
GetThreadContext( ppi->hThread, &context );
|
|
|
|
mem = VirtualAllocEx( ppi->hProcess, NULL, len, MEM_COMMIT,
|
|
|
|
PAGE_EXECUTE_READWRITE );
|
|
|
|
mem32 = (DWORD)(DWORD_PTR)mem;
|
|
|
|
|
|
|
|
ip.pB = code;
|
|
|
|
|
|
|
|
*ip.pB++ = 0x68; // push eip
|
|
|
|
*ip.pL++ = context.Eip;
|
|
|
|
*ip.pB++ = 0x9c; // pushf
|
|
|
|
*ip.pB++ = 0x60; // pusha
|
2010-11-13 14:49:27 +10:00
|
|
|
*ip.pB++ = 0x68; // push L"path\to\ANSI32.dll"
|
2010-11-08 15:31:01 +10:00
|
|
|
*ip.pL++ = mem32 + CODESIZE;
|
2010-11-13 14:49:27 +10:00
|
|
|
*ip.pB++ = 0xe8; // call LoadLibraryW
|
2010-11-15 21:51:38 +10:00
|
|
|
*ip.pL++ = LLW - (mem32 + (DWORD)(ip.pB+4 - code));
|
2010-11-08 15:31:01 +10:00
|
|
|
*ip.pB++ = 0x61; // popa
|
|
|
|
*ip.pB++ = 0x9d; // popf
|
|
|
|
*ip.pB++ = 0xc3; // ret
|
|
|
|
|
|
|
|
WriteProcessMemory( ppi->hProcess, mem, code, len, NULL );
|
|
|
|
FlushInstructionCache( ppi->hProcess, mem, len );
|
|
|
|
context.Eip = mem32;
|
|
|
|
SetThreadContext( ppi->hThread, &context );
|
|
|
|
}
|