I'm attempting to write a DLL Injector in C# using the CreateRemoteThread / LoadLibrary technique. I got to the point last night where the function runs without erroring (until I put in another exception) but doesn't actually inject the module (leading me to believe that LoadLibrary is not actually executed). My machine at home where I was running it is Win 7 Ultimate RC 7100 x64.
I got to work this morning and the code ran, and injected the DLL, without a hitch (work machine is XP SP3 32bit). This reinforces my belief that the problem is something to do with changes between XP and Vista/7 and/or differences in Dll injection between x64/x86.
So far the examples I've seen on injecting in x64 seem pretty similar in terms of what they are doing. I had a look at Cypher's loader program, and the most notable difference in that (other than it being C++) is the CustomGetProcAddress rewrite that parses PE image format to find LoadLibraryW address. As the reasoning behind this is due to Vista potentially stuffing things up, I was wondering if that is likely the problem.
I've attached the relevant code. At home on Win 7 x64 it gets to the "Code executed properly, but unable to get an appropriate module handle, possible Win32Exception" line. Marshal.GetLastWin32Error() returns 0 at this point ("The operation completed successfully" - But this probably just indicates that GetExitCodeThread doesn't cause an error - I'll be testing what possible Win32 errors are returned from the call to CreateRemoteThread once I get home this arvo)
Code:
private IntPtr InjectLibraryInternal(string libFullPath)
{
uint sizeUni = (uint)Encoding.Unicode.GetByteCount(libFullPath);
// Get Handle to Kernel32.dll and pointer to LoadLibraryW
IntPtr hKernel32 = Imports.GetModuleHandle("Kernel32");
if (hKernel32 == IntPtr.Zero)
throw new Win32Exception(Marshal.GetLastWin32Error());
IntPtr hLoadLib = Imports.GetProcAddress(hKernel32, "LoadLibraryW");
if (hLoadLib == IntPtr.Zero)
throw new Win32Exception(Marshal.GetLastWin32Error());
// allocate memory to the local process for libFullPath
IntPtr pLibPath = Imports.VirtualAllocEx(_process.Handle, IntPtr.Zero, sizeUni, AllocationType.Commit, MemoryProtection.ReadWrite);
if (pLibPath == IntPtr.Zero)
throw new Win32Exception(Marshal.GetLastWin32Error());
// write libFullPath to pLibPath
int bytesWritten;
if (!Imports.WriteProcessMemory(_process.Handle, pLibPath, Marshal.StringToHGlobalUni(libFullPath), sizeUni, out bytesWritten) || bytesWritten != (int)sizeUni)
throw new Win32Exception(Marshal.GetLastWin32Error());
// load dll via call to LoadLibrary using CreateRemoteThread
IntPtr hThread = Imports.CreateRemoteThread(_process.Handle, IntPtr.Zero, 0, hLoadLib, pLibPath, 0, IntPtr.Zero);
if (hThread == IntPtr.Zero)
throw new Win32Exception(Marshal.GetLastWin32Error());
if (Imports.WaitForSingleObject(hThread, uint.MaxValue) != 0)
throw new Win32Exception(Marshal.GetLastWin32Error());
// get address of loaded module
IntPtr hLibModule;// = IntPtr.Zero;
if (!Imports.GetExitCodeThread(hThread, out hLibModule))
throw new Win32Exception(Marshal.GetLastWin32Error());
if (hLibModule == IntPtr.Zero)
throw new Exception("Code executed properly, but unable to get an appropriate module handle, possible Win32Exception", new Win32Exception(Marshal.GetLastWin32Error()));
// clean up
if (!Imports.CloseHandle(hThread))
throw new Win32Exception(Marshal.GetLastWin32Error());
if (!Imports.VirtualFreeEx(_process.Handle, pLibPath, 0, AllocationType.Release))
throw new Win32Exception(Marshal.GetLastWin32Error());
return hLibModule;
}
Edit: Fixed, Platform Target: Any CPU needed to be x86 for the dll that was being injected/process it was being injected into. Thanks Cypher, now to fix resource leaks.