/************************************************** *************
I just have a question about some DLL injecting code that I got from the article here:
http://www.codeproject.com/threads/winspy.asp
in the example LibSpy program, there is an InjectDLL function. here it is:
Code:
//-----------------------------------------------
// InjectDll
// Notice: Loads "LibSpy.dll" into the remote process
// (via CreateRemoteThread & LoadLibrary)
//
// Return value: 1 - success;
// 0 - failure;
//
int InjectDll( HANDLE hProcess )
{
HANDLE hThread;
char szLibPath [_MAX_PATH];
void* pLibRemote = 0; // the address (in the remote process) where
// szLibPath will be copied to;
DWORD hLibModule = 0; // base adress of loaded module (==HMODULE);
HMODULE hKernel32 = ::GetModuleHandle("Kernel32");
// Get full path of "LibSpy.dll"
if( !GetModuleFileName( hInst,szLibPath,_MAX_PATH) )
return false;
strcpy( strstr(szLibPath,".exe"),".dll" );
// 1. Allocate memory in the remote process for szLibPath
// 2. Write szLibPath to the allocated memory
pLibRemote = ::VirtualAllocEx( hProcess, NULL, sizeof(szLibPath), MEM_COMMIT, PAGE_READWRITE );
if( pLibRemote == NULL )
return false;
::WriteProcessMemory(hProcess, pLibRemote, (void*)szLibPath,sizeof(szLibPath),NULL);
// Load "LibSpy.dll" into the remote process
// (via CreateRemoteThread & LoadLibrary)
hThread = ::CreateRemoteThread( hProcess, NULL, 0,
(LPTHREAD_START_ROUTINE) ::GetProcAddress(hKernel32,"LoadLibraryA"),
pLibRemote, 0, NULL );
if( hThread == NULL )
goto JUMP;
::WaitForSingleObject( hThread, INFINITE );
// Get handle of loaded module
::GetExitCodeThread( hThread, &hLibModule );
::CloseHandle( hThread );
JUMP:
::VirtualFreeEx( hProcess, pLibRemote, sizeof(szLibPath), MEM_RELEASE );
if( hLibModule == NULL )
return false;
// Unload "LibSpy.dll" from the remote process
// (via CreateRemoteThread & FreeLibrary)
hThread = ::CreateRemoteThread( hProcess,
NULL, 0,
(LPTHREAD_START_ROUTINE) ::GetProcAddress(hKernel32,"FreeLibrary"),
(void*)hLibModule,
0, NULL );
if( hThread == NULL ) // failed to unload
return false;
::WaitForSingleObject( hThread, INFINITE );
::GetExitCodeThread( hThread, &hLibModule );
::CloseHandle( hThread );
// return value of remote FreeLibrary (=nonzero on success)
return hLibModule;
}
I understand all of the code but how he handles CreateRemoteThread returning NULL. take a good look at it. he handles it by unloading the DLL, which is logical, but look at his code.
he jumps over GetExitCodeThread and then tests the value of hLibModule against NULL in the goto label. hLibModule is declared as a DWORD at the beginning of the function and initialized to 0. by jumping over GetExitCodeThread, hLibModule will remain 0, the if test will return FALSE, thus the DLL will never be unloaded, when in reality it should be (since CreateRemoteThread returned NULL). also I don't quite understand how I am supposed to get the remote thread's exit code to be able to unload the DLL, when the remote thread hasn't been created . I can either create the remote thread successfully (and be able to obtain its exit code), or not create the remote thread successfully (and not be able to obtain its exit code).
could anyone please tell me how they think that code is supposed to work?
I also noticed he lacks a call to VirtualFreeEx after the remote thread has been created to free the library. I am guessing this is unnecessary since FreeLibrary will have already unmapped the DLL and freed the memory?
any input here is greatly appreciated.
thank you in advance!
************************************************** *************/
EDIT: erm, I understand the above code better now. I was thinking that the creation of the remote thread was failing because LoadLibrary was returning ERROR_ALREADY_EXISTS, thus the jump to unload the library. now I see that the call to CreateRemoteThread failing has nothing to do with the loading of the library (other than the fact that if the thread creation fails, the library will not be loaded). so now my question is:
if CreateRemoteThread is called and returns NULL, and then I call GetLastError to retrieve the last error code, and I get ERROR_ALREADY_EXISTS what do you think has happened?