Question

I am attempting to inject a dll into an existing process using the LoadLibrary and CreateRemoteThread approach. All of my code is working beautifully except for the fact that DllMain is not being called for some reason.

I've wracked my brains and done as much internet research as I can but none of the suggestions have helped.

When I statically load the dll into a sample project it works beautifully.

When I dynamically load the dll into a sample project using LoadLibrary, it works beautifully.

The only time that DllMain is not called is when I'm trying to inject it into a process using the LoadLibrary and CreateRemoteThread approach. I'm at my wits end!

I have verified that the dll is loaded into the notepad.exe process from the injector because the SimpleDLL.dll file is locked and cannot be deleted or overwritten until I close notepad.exe.

Fyi, my ide is Microsoft Visual Studio 2010 Ultimate.

// SimpleDLL.h
#pragma once

#include "Stdafx.h"

#ifdef COMPILE_MYLIBRARY
  #define MYLIBRARY_EXPORT __declspec(dllexport)
#else
  #define MYLIBRARY_EXPORT __declspec(dllimport)
#endif

.

//SimpleDLL.cpp
#include "Stdafx.h"
#include "SimpleDll.h"

extern "C" int __stdcall DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved ) {

    printf("SimpleDll: DllMain called.\n");

    switch( fdwReason )
    {
        case DLL_PROCESS_ATTACH:
            printf("SimpleDll: DLL_PROCESS_ATTACH.\n");
            break;
        case DLL_PROCESS_DETACH:
            printf("SimpleDll: DLL_PROCESS_DETACH.\n");
            break;
        case DLL_THREAD_ATTACH:
            printf("SimpleDll: DLL_THREAD_ATTACH.\n");
            break;
        case DLL_THREAD_DETACH:
            printf("SimpleDll: DLL_THREAD_DETACH.\n");
            break;
    }

    return TRUE;
};

SimpleDLLCaller.cpp - This runs correctly and prints out the messages from DllMain. This is a project I built to verify that the dll is constructed correctly. From the output that I can see, it appears to be operating correctly when loaded in this way.

// SimpleDLLCaller.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

int _tmain(int argc, _TCHAR* argv[])
{
    LoadLibraryA( "C:\\SimpleDll.dll" );

    _getch(); 

    return 0;
}

Output from SimpleDllCaller:

SimpleDll: DllMain called.
SimpleDll: DLL_PROCESS_ATTACH.

Simple Injector.cpp - This is a separate project from SimpleDLLCaller and compiles/runs successfully without warnings (as long as notepad.exe is already running) but no messages from DllMain are displayed.

// Simple Injector.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#include <windows.h> 
#include <tlhelp32.h> 
#include <shlwapi.h> 
#include <conio.h> 
#include <stdio.h> 

#define WIN32_LEAN_AND_MEAN 
#define CREATE_THREAD_ACCESS (PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ) 

BOOL Inject(DWORD pID, const char * dll_name ) 
{ 
    HANDLE targetProcess, createdThread; 
    //HMODULE hLib; 
    char buf[50] = {0}; 
    LPVOID myRemoteString, LoadLibAddy;

    if( ! pID ) 
    {
        return FALSE;
    }

    targetProcess = OpenProcess( CREATE_THREAD_ACCESS, FALSE, pID );
    if( ! targetProcess ) 
    { 
        sprintf_s(buf, "OpenProcess() failed: %d", GetLastError()); 
        MessageBox(NULL, buf, "Loader", MB_OK); 
        printf(buf); 
        return false; 
    }

    LoadLibAddy = (LPVOID)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
    if( ! LoadLibAddy )
    {
        printf( "ERROR: Problems with GetProcAddress.  Error code: %d\n", GetLastError() );
        return false;
    }

    // Allocate space in the process for the dll 
    myRemoteString = (LPVOID)VirtualAllocEx( targetProcess, NULL, strlen(dll_name), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
    if( ! myRemoteString )
    {
        printf( "ERROR: Problems with VirtualAllocEx.  Error code: %d\n", GetLastError() );
        return false;
    }

    // Write the string name of the dll in the memory allocated 
    if( ! WriteProcessMemory( targetProcess, (LPVOID)myRemoteString, dll_name, strlen(dll_name), NULL) )
    {
        printf( "ERROR: Problems with WriteProcessMemory.  Error code: %d\n", GetLastError() );
        return false;
    }

    // Load the dll
    createdThread = CreateRemoteThread( targetProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibAddy, (LPVOID)myRemoteString, NULL, NULL);
    if( ! createdThread )
    {
        printf( "ERROR: Problems with CreateRemoteThread.  Error code: %d\n", GetLastError() );
        return false;
    }

    WaitForSingleObject(createdThread, INFINITE);

    // Free the memory that is not being using anymore. 
    if( myRemoteString != NULL ) VirtualFreeEx( targetProcess, myRemoteString, 0, MEM_RELEASE );
    if( createdThread != NULL ) CloseHandle( createdThread );
    if( targetProcess != NULL ) CloseHandle( targetProcess );

    //VirtualFreeEx(hProcess , (LPVOID)Memory , 0, MEM_RELEASE); 

    return true; 
} 

DWORD GetTargetThreadIDFromProcName(const char *ProcName) 
{ 
   PROCESSENTRY32 pe; 
   HANDLE thSnapShot; 
   BOOL retval, ProcFound = false; 

   thSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 
   if(thSnapShot == INVALID_HANDLE_VALUE) 
   { 
      //MessageBox(NULL, "Error: Unable <strong class="highlight">to</strong> create toolhelp snapshot!", "2MLoader", MB_OK); 
      printf("Error: Unable to create toolhelp snapshot!"); 
      return false; 
   } 

   pe.dwSize = sizeof(PROCESSENTRY32); 

   retval = Process32First(thSnapShot, &pe); 
   while(retval) 
   { 
      if( !strcmp(pe.szExeFile, ProcName) ) 
      { 
         return pe.th32ProcessID; 
      } 
      retval = Process32Next(thSnapShot, &pe); 
   } 
   return 0; 
}

int _tmain(int argc, _TCHAR* argv[])
{
   // Retrieve process ID 
   DWORD pID = GetTargetThreadIDFromProcName("notepad.exe"); 
    if( !pID )
    {
        printf( "ERROR: Could not find any process for notepad.exe.\n");
        _getch();
        return 0;
    }

    // Get the dll's full path name 
    char buf[MAX_PATH] = {0}; 
    // GetFullPathName("..\\SimpleDLL.dll", MAX_PATH, buf, NULL); 
    sprintf_s(buf, "C:\\SimpleDLL.dll");

    printf( "Dll path = %s\n", buf );

    // Inject our main dll 
    if(!Inject(pID, buf)) 
    {
        printf("Dll not loaded."); 
    }
    else
    {
        printf("Dll loaded."); 
    }

    _getch();
    return 0; 
}

Output from Simple Injector:

Dll path = C:\SimpleDLL.dll
Dll loaded.

Please tell me what I'm doing wrong here. Any feedback is welcome.

Was it helpful?

Solution

Your DLL may be correctly Loaded. Don't expect your printf to do do anything. If you want a proof, write your message in a text file, or use MessageBox, or use Process Explorer.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top