Thread: question about DLL injecting code

  1. #1
    Madly in anger with you
    Join Date
    Nov 2005
    Posts
    211

    question about DLL injecting code

    /************************************************** *************
    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?
    Last edited by Bleech; 11-04-2006 at 06:12 PM.

    Intel Core 2 Quad Q6600 @ 2.40 GHz
    3072 MB PC2-5300 DDR2
    2 x 320 GB SATA (640 GB)
    NVIDIA GeForce 8400GS 256 MB PCI-E

  2. #2
    Reverse Engineer maxorator's Avatar
    Join Date
    Aug 2005
    Location
    Estonia
    Posts
    2,318
    Code:
    ::WaitForSingleObject( hThread, INFINITE );
    Why these two semicolons?
    "The Internet treats censorship as damage and routes around it." - John Gilmore

  3. #3
    erstwhile
    Join Date
    Jan 2002
    Posts
    2,227
    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?
    Probably because a previous thread hasn't been closed.
    Quote Originally Posted by msdn,CreateRemoteThread
    The thread object remains in the system until the thread has terminated and all handles to it are closed through a call to CloseHandle.
    See CreateRemoteThread.
    Quote Originally Posted by Maxorator
    Why these two semicolons?
    They're colons and together constitute the C++ scope resolution operator: they explicitly tell the compiler the following function has global scope and thereby avoids some possible naming conflicts. I suspect some msvc users don't use it for this, though - without the scope resolution operator for winapi functions you don't always get all the fancy function parameter 'intellisense'. Most mfc code I've seen is littered with it but then many mfc classes use the same names as winapi functions and therefore need it in order to resolve ambiguities.
    CProgramming FAQ
    Caution: this person may be a carrier of the misinformation virus.

  4. #4
    Reverse Engineer maxorator's Avatar
    Join Date
    Aug 2005
    Location
    Estonia
    Posts
    2,318
    I usually make very unique function and variable names, so I don't have such situations where I would need to put those semicolons before WinAPI calls.
    "The Internet treats censorship as damage and routes around it." - John Gilmore

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. DLL Calling Question
    By mercury529 in forum Windows Programming
    Replies: 11
    Last Post: 01-09-2007, 06:15 PM
  2. Formatting of code for DLL creation
    By NETnewbie in forum Windows Programming
    Replies: 3
    Last Post: 11-19-2006, 04:50 PM
  3. easy question about machine code
    By Jaguar in forum Tech Board
    Replies: 3
    Last Post: 10-07-2003, 09:11 AM
  4. .lib vs .h vs .dll
    By Shadow12345 in forum C++ Programming
    Replies: 13
    Last Post: 01-01-2003, 05:29 AM
  5. question regarding code found on this board
    By Unregistered in forum C Programming
    Replies: 3
    Last Post: 07-23-2002, 08:03 PM