Thread: DLL Ejection

  1. #1
    Registered User Ktulu's Avatar
    Join Date
    Oct 2006
    Posts
    107

    Question DLL Ejection

    Does anyone know how to eject a DLL from a process?

    Here is my Injection code:
    Code:
    BOOL InjectDLL ( HANDLE HanProcess, CONST CHAR * ChaDLL )
    {
    
        CHAR ChaDLLFilePath [ ( MAX_PATH + 16 ) ] = { 0 };
    
        strcpy ( ChaDLLFilePath, ChaDLL );
    
        HMODULE ModKernel32 = GetModuleHandle ( "Kernel32.dll" );
    
        if ( ModKernel32 != NULL )
        {
    
            LPVOID ProcessBaseAdress = VirtualAllocEx ( HanProcess, NULL, sizeof ( ChaDLLFilePath ), MEM_COMMIT, PAGE_READWRITE );
    
            if ( ProcessBaseAdress != NULL )
            {
    
                if ( WriteProcessMemory ( HanProcess, ProcessBaseAdress, ( VOID * ) ChaDLLFilePath, sizeof ( ChaDLLFilePath ), NULL ) )
                {
    
                    HANDLE HanDLLThread = CreateRemoteThread ( HanProcess, NULL, 0, LPTHREAD_START_ROUTINE ( GetProcAddress ( ModKernel32, "LoadLibraryA" ) ), ProcessBaseAdress, 0, NULL );
    
                    if ( HanDLLThread != NULL )
                    {
    
                        if ( WaitForSingleObject ( HanDLLThread, INFINITE ) != WAIT_FAILED )
                        {
    
                            CloseHandle ( HanDLLThread );
    
                            VirtualFreeEx ( HanProcess, ProcessBaseAdress, 0, MEM_RELEASE );
    
                            CloseHandle ( HanProcess );
    
                            return TRUE;
                        }
    
                        CloseHandle ( HanDLLThread );
    
                        VirtualFreeEx ( HanProcess, ProcessBaseAdress, 0, MEM_RELEASE );
                    }
    
                    else
                    {
    
                        VirtualFreeEx ( HanProcess, ProcessBaseAdress, 0, MEM_RELEASE );
                    }
                }
    
                else
                {
    
                    VirtualFreeEx ( HanProcess, ProcessBaseAdress, 0, MEM_RELEASE );
                }
            }
        }
    
        CloseHandle ( HanProcess );
    
        return FALSE;
    }
    I think I may have to do something with like this:
    GetProcAddress ( ModKernel32, "FreeLibraryA" )
    instead of this:
    GetProcAddress ( ModKernel32, "LoadLibraryA" )

    Recording to this:
    The FreeLibrary function decrements the reference count of the loaded dynamic-link library (DLL) module. When the reference count reaches zero, the module is unmapped from the address space of the calling process and the handle is no longer valid. This function supersedes the FreeModule function.
    This parameter is reserved

  2. #2
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    If you can get the HMODULE of the DLL you loaded, you can use exactly the same trick you're already using. Just put this HMODULE instead of ProcessBaseAddress.

    But I find your trick very suspect already. What guarantee do you have that the HMODULE of kernel32.dll is the same in the other process as in yours?

    On the other hand, it seems to match what Jeffrey Richter does, so that's probably fine. Just note that even he says only that in his experience, the handle is always the same.

    The very same book, by the way, also contains an eject library call. It does indeed work like I said. It uses the Toolhelp32 library to create a snapshot of all modules and just searches for the one that has the same szModule and szExePath as the library you injected.
    Last edited by CornedBee; 11-11-2006 at 06:12 PM.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  3. #3
    Registered User
    Join Date
    Nov 2006
    Location
    Pakistan
    Posts
    3
    Use GetProcAddress(ModKernel32, "FreeLibrary") . ModKernel32 is always the same for every process because Windows always loads ntdll.dll, kernel32.dll, and user32.dll at the same address in every process. Use GetExitCodeThread() to receive the return value from the LoadLibraryA() remote call, and use it as the input to FreeLibrary later on.

  4. #4
    Registered User Ktulu's Avatar
    Join Date
    Oct 2006
    Posts
    107
    Here is with what I came up with, it doesn't work (ofcourse ), I tried alot of variations, all didn't work, I just can't figure it out, please help me out here:

    Code:
    BOOL EjectDLL ( HANDLE HanProcess, DWORD WorProcessId, CONST CHAR * ChaDLL )
    {
    
        CHAR ChaDLLFilePath [ ( MAX_PATH + 16 ) ] = { 0 };
    
        strcpy ( ChaDLLFilePath, ChaDLL );
    
        HMODULE ModDLLHandle = NULL;
    
        BYTE * BytDLLBaseAdress = 0;
    
        MODULEENTRY32 MOEModuleInformation = { 0 };
    
        MOEModuleInformation.dwSize = sizeof ( MODULEENTRY32 );
    
        HANDLE HanModuleSnapshot = CreateToolhelp32Snapshot ( TH32CS_SNAPMODULE, WorProcessId );
    
        Module32First ( HanModuleSnapshot, & MOEModuleInformation );
    
        do
        {
    
            if ( ! strcmp ( MOEModuleInformation.szExePath, ChaDLLFilePath ) )
            {
    
                ModDLLHandle = MOEModuleInformation.hModule;
    
                BytDLLBaseAdress = MOEModuleInformation.modBaseAddr;
            }
        }
    
        while ( Module32Next ( HanModuleSnapshot, & MOEModuleInformation ) );
    
        CloseHandle ( HanModuleSnapshot );
    
        if ( ModDLLHandle != NULL )
        {
    
            if ( BytDLLBaseAdress != 0 )
            {
    
                if ( WriteProcessMemory ( HanProcess, BytDLLBaseAdress, ( VOID * ) ChaDLLFilePath, sizeof ( ChaDLLFilePath ), NULL ) )
                {
    
                    if ( VirtualFreeEx ( HanProcess, BytDLLBaseAdress, 0, MEM_RELEASE ) )
                    {
    
                        CloseHandle ( HanProcess );
    
                        return TRUE;
                    }
                }
            }
        }
    
        CloseHandle ( HanProcess );
    
        return FALSE;
    }
    This parameter is reserved

  5. #5
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    You're not even calling CreateRemoteThread. And you need to write the module handle into the memory, not the DLL path.

    What cefarix suggested is a bad idea, btw. A thread procedure's return value is a 32-bit value. In 64-bit Windows, handles are 64 bits wide.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  6. #6
    Registered User Ktulu's Avatar
    Join Date
    Oct 2006
    Posts
    107
    Ok, I got it like this now but it doesn't work either, can you see why?

    Code:
    BOOL EjectDLL ( HANDLE HanProcess, DWORD WorProcessId, CONST CHAR * ChaDLL )
    {
    
        CHAR ChaDLLFilePath [ ( MAX_PATH + 16 ) ] = { 0 };
    
        strcpy ( ChaDLLFilePath, ChaDLL );
    
        HMODULE ModDLLHandle = NULL;
    
        BYTE * BytDLLBaseAdress = 0;
    
        MODULEENTRY32 MOEModuleInformation = { 0 };
    
        MOEModuleInformation.dwSize = sizeof ( MODULEENTRY32 );
    
        HANDLE HanModuleSnapshot = CreateToolhelp32Snapshot ( TH32CS_SNAPMODULE, WorProcessId );
    
        Module32First ( HanModuleSnapshot, & MOEModuleInformation );
    
        do
        {
    
            if ( ! strcmp ( MOEModuleInformation.szExePath, ChaDLLFilePath ) )
            {
    
                ModDLLHandle = MOEModuleInformation.hModule;
    
                BytDLLBaseAdress = MOEModuleInformation.modBaseAddr;
            }
        }
    
        while ( Module32Next ( HanModuleSnapshot, & MOEModuleInformation ) );
    
        CloseHandle ( HanModuleSnapshot );
    
        HMODULE ModKernel32 = GetModuleHandle ( "Kernel32.dll" );
    
        if ( ModKernel32 != NULL )
        {
    
            if ( ModDLLHandle != NULL &&
                 BytDLLBaseAdress != 0 )
            {
    
                if ( WriteProcessMemory ( HanProcess, BytDLLBaseAdress, ( VOID * ) ModDLLHandle, sizeof ( ModDLLHandle ), NULL ) )
                {
    
                   HANDLE HanDLLThread = CreateRemoteThread ( HanProcess, NULL, 0, LPTHREAD_START_ROUTINE ( GetProcAddress ( ModKernel32, "FreeLibrary" ) ), BytDLLBaseAdress, 0, NULL );
    
                    if ( HanDLLThread != NULL )
                    {
    
                        if ( WaitForSingleObject ( HanDLLThread, INFINITE ) != WAIT_FAILED )
                        {
    
                            CloseHandle ( HanDLLThread );
    
                            VirtualFreeEx ( HanProcess, BytDLLBaseAdress, 0, MEM_RELEASE );
    
                            CloseHandle ( HanProcess );
    
                            return TRUE;
                        }
    
                        CloseHandle ( HanDLLThread );
                    }
                }
            }
        }
    
        CloseHandle ( HanProcess );
    
        return FALSE;
    }
    This parameter is reserved

  7. #7
    Registered User Tonto's Avatar
    Join Date
    Jun 2005
    Location
    New York
    Posts
    1,465
    Code:
    WriteProcessMemory ( HanProcess, BytDLLBaseAdress, ( VOID * ) ModDLLHandle, sizeof ( ModDLLHandle ), NULL )
    I can't tell, is that smart? To just write the module handle at the base address of that loaded dll?

    Code:
    VirtualFreeEx ( HanProcess, BytDLLBaseAdress, 0, MEM_RELEASE );
    Why do you free memory at the base address of where the dll was loaded?

  8. #8
    Madly in anger with you
    Join Date
    Nov 2005
    Posts
    211
    not its not smart.

    you are doing it the hard way in the last 2 posts of code.

    after calling WaitForSingleObject with the remote thread handle, call GetExitCodeThread with it. this will retrieve LoadLibrary/DllMain's return value, which will be the base address (HMODULE) of your mapped DLL. given this value, you can unmap the injected DLL via FreeLibrary:

    Code:
    HanDLLThread = CreateRemoteThread(HanProcess, NULL, 0, (LPTHREAD_START_ROUTINE)GetProcAddress(ModKernel32, "FreeLibrary"), (void *)dwExitCode, 0, NULL);
    where dwExitCode is the value you retrieved with GetExitCodeThread.
    Last edited by Bleech; 11-12-2006 at 06:23 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

  9. #9
    Registered User Ktulu's Avatar
    Join Date
    Oct 2006
    Posts
    107
    Yes, but in this way you are only able to eject a DLL which you have injected earlier because you have the handle of the main thread of the injected DLL. But if I want to eject a DLL which I didn't inject in the first place I can't get the exit code because I don't have the main thread of that DLL, only the process were it is mapped in and the file path of the DLL, how to eject a DLL by only knowing the process where it is mapped in and the file path of that DLL?
    This parameter is reserved

  10. #10
    Registered User Ktulu's Avatar
    Join Date
    Oct 2006
    Posts
    107
    Allright, nevermind :P.

    As Tonto said, using WriteProcessMemory and VirtualFreeEx is not usefull when ejecting a DLL,
    so I removed those functions and I changed, according to sl34k, a parameter in the CreateRemoteThread function and it worked .

    Here is the DLL Ejection function:
    Code:
    BOOL EjectDLL ( HANDLE HanProcess, DWORD WorProcessId, CONST CHAR * ChaDLL )
    {
    
        CHAR ChaDLLFilePath [ ( MAX_PATH + 16 ) ] = { 0 };
    
        strcpy ( ChaDLLFilePath, ChaDLL );
    
        HMODULE ModDLLHandle = NULL;
    
        BYTE * BytDLLBaseAdress = 0;
    
        MODULEENTRY32 MOEModuleInformation = { 0 };
    
        MOEModuleInformation.dwSize = sizeof ( MODULEENTRY32 );
    
        HANDLE HanModuleSnapshot = CreateToolhelp32Snapshot ( TH32CS_SNAPMODULE, WorProcessId );
    
        Module32First ( HanModuleSnapshot, & MOEModuleInformation );
    
        do
        {
    
            if ( ! strcmp ( MOEModuleInformation.szExePath, ChaDLLFilePath ) )
            {
    
                ModDLLHandle = MOEModuleInformation.hModule;
    
                BytDLLBaseAdress = MOEModuleInformation.modBaseAddr;
            }
        }
    
        while ( Module32Next ( HanModuleSnapshot, & MOEModuleInformation ) );
    
        CloseHandle ( HanModuleSnapshot );
    
        HMODULE ModKernel32 = GetModuleHandle ( "Kernel32.dll" );
    
        if ( ModKernel32 != NULL )
        {
    
            if ( ModDLLHandle != NULL &&
                 BytDLLBaseAdress != 0 )
            {
    
                HANDLE HanDLLThread = CreateRemoteThread ( HanProcess, NULL, 0, LPTHREAD_START_ROUTINE ( GetProcAddress ( ModKernel32, "FreeLibrary" ) ), ( VOID * ) BytDLLBaseAdress, 0, NULL );
    
                if ( HanDLLThread != NULL )
                {
    
                    if ( WaitForSingleObject ( HanDLLThread, INFINITE ) != WAIT_FAILED )
                    {
    
                        CloseHandle ( HanDLLThread );
    
                        CloseHandle ( HanProcess );
    
                        return TRUE;
                    }
    
                    CloseHandle ( HanDLLThread );
                }
            }
        }
    
        CloseHandle ( HanProcess );
    
        return FALSE;
    }
    This parameter is reserved

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. non-MFC DLL with MFC app question.
    By Kempelen in forum Windows Programming
    Replies: 10
    Last Post: 08-20-2008, 07:11 AM
  2. dll communicating between each other
    By cloudy in forum C++ Programming
    Replies: 5
    Last Post: 06-17-2005, 02:20 AM
  3. DLL and std::string woes!
    By Magos in forum C++ Programming
    Replies: 7
    Last Post: 09-08-2004, 12:34 PM
  4. Using class with DLL
    By greg2 in forum C++ Programming
    Replies: 2
    Last Post: 09-12-2003, 05:24 AM
  5. .lib vs .h vs .dll
    By Shadow12345 in forum C++ Programming
    Replies: 13
    Last Post: 01-01-2003, 05:29 AM