23

I know there are various questions and books on this but I can't seem to get my C++ DLL injected into any processes.

The code to inject the DLL:

#include <iostream>
#include "windows.h"

bool Inject(DWORD pId, char *dllName);

using namespace std;

int main()
{
    Inject(600, "C:\\d.dll");
    return 0;
}

bool Inject(DWORD pId, char *dllName)
{
    HANDLE h = OpenProcess(PROCESS_ALL_ACCESS, false, pId);
    if(h)
    {
        LPVOID LoadLibAddr = (LPVOID)GetProcAddress(GetModuleHandleA("kernel32.dll"), "LoadLibraryA");
        LPVOID dereercomp = VirtualAllocEx(h, NULL, strlen(dllName), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
        WriteProcessMemory(h, dereercomp, dllName, strlen(dllName), NULL);
        HANDLE asdc = CreateRemoteThread(h, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibAddr, dereercomp, 0, NULL);
        WaitForSingleObject(asdc, INFINITE);
        VirtualFreeEx(h, dereercomp, strlen(dllName), MEM_RELEASE);
        CloseHandle(asdc);
        CloseHandle(h);
        return true;
    }
    return false;
}

and the DLL I am trying to inject:

#include <windows.h>
#include <stdio.h>

BOOL APIENTRY DllMain (HINSTANCE hInst     /* Library instance handle. */ ,
                       DWORD reason        /* Reason this function is being called. */ ,
                       LPVOID reserved     /* Not used. */ )
{
switch (reason)
    {
      case DLL_PROCESS_ATTACH:
           MessageBox (0, "From DLL\n", "Process Attach", MB_ICONINFORMATION);
        break;

      case DLL_PROCESS_DETACH:
           MessageBox (0, "From DLL\n", "Process Detach", MB_ICONINFORMATION);
        break;

      case DLL_THREAD_ATTACH:
           MessageBox (0, "From DLL\n", "Thread Attach", MB_ICONINFORMATION);
        break;

      case DLL_THREAD_DETACH:
           MessageBox (0, "From DLL\n", "Thread Detach", MB_ICONINFORMATION);
        break;
    }

    return TRUE;
}

I don't know enough C++ to know where this is going wrong. I have run Process Explorer on the process I am trying to inject to (process run as admin aswell) but it isn't being injected. When I run it, nothing happens, any ideas?

Bali C
  • 30,582
  • 35
  • 123
  • 152
  • 2
    have you checked that you permissions (debug permissions) to open the process? – Jimmy Jun 07 '12 at 10:58
  • @Jimmy How would I check this? – Bali C Jun 07 '12 at 11:35
  • you can check out http://msdn.microsoft.com/en-us/library/aa291232(v=VS.71).aspx or alternatively run process as admin – Jimmy Jun 07 '12 at 12:21
  • @Jimmy Thanks for the suggestion but I tried running as admin but to no avail. – Bali C Jun 07 '12 at 12:32
  • 3
    Your code is devoid of any error checking, other than OpenProcess. So sure you don't know why it doesn't work. – Hans Passant Jun 07 '12 at 12:56
  • @HansPassant TBH I copied and pasted this code, but it is meant to work well, which is why I can't understand why it won't work for me. – Bali C Jun 07 '12 at 13:02
  • @BaliC, copy and paste, meant to work well, that *does sound convincing*, so maybe there are mischievous goblins at work in your computer to defeat your program? – Lumi Jun 07 '12 at 13:23
  • @BaliC : see my answer, I think it's related to UAC – rkosegi Jun 07 '12 at 14:38
  • 2
    Do `OutputDebugString` instead of `MessageBox`, and check it with DebugView. You might be reaching your `MessageBox`, but you just cannot see it properly being called from `DllMain`. – Roman R. Jun 11 '12 at 14:03

5 Answers5

26

Don't do MessageBox from DllMain. Why? See:

Your message box might just deadlock before showing up there. To ensure you reach the code line of interest, use OutputDebugString instead. As you indicated you are familiar with Process Explorer, you might notice created thread there (you can obtain its identifier in your launcher by providing last argument in your CreateRemoteThread) and its locked state with execution inside kernel libraries.

This is where you need to put OutputDebugString:

BOOL APIENTRY DllMain(HMODULE hModule, DWORD nReason, VOID* pvReserved)
{
    pvReserved;
    TCHAR pszMessage[1024] = { 0 };
    _stprintf_s(pszMessage, _T("GetCurrentProcessId() %d, hModule 0x%p, nReason %d\r\n"), GetCurrentProcessId(), hModule, nReason);
    OutputDebugString(pszMessage);
    /*switch(nReason)
    {
    case DLL_PROCESS_ATTACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }*/
    return TRUE;
}

Another thing to make sure is that you are loading DLL of correct bitness. Win32 DLL into Win32 process, or x64 DLL into x64 process.

UPDATE. I am putting this up from comment: here is the source code for the Visual Studio 2010 project that does the thing: SVN or Trac.

  • You put process identifier into source code
  • The executable creates remote thread and loads library
  • The library starts from DllMain and generates debug output
  • DebugView shows you the output
  • ProcessExplorer shows you the thread created, and you also have its identifier printed
Community
  • 1
  • 1
Roman R.
  • 68,205
  • 6
  • 94
  • 158
  • Thanks for the links, should I create a function and call the function from DllMain then? – Bali C Jun 11 '12 at 14:13
  • The compiler isn't recognising `_stprintf_s` and `_T`. Am I missing a header? Docs say `stdio.h` but I have that added. Thanks – Bali C Jun 11 '12 at 14:26
  • Thanks, but still no joy. I was compiling in CodeBlocks, tried in VS but still nothing happening. No errors that I can see, just no message box. – Bali C Jun 12 '12 at 14:24
  • I tried the code yesterday and it worked for me, you can grab full source here http://www.alax.info/svn/public/trunk/Utilities/InjectLibrary/ I don't understand what kind of error you are getting. You will see no message box for the reasons mentioned in answer above - you cannot get it in `DllMain`. – Roman R. Jun 12 '12 at 14:35
7

The problem you're likely running into is that the address of LoadLibraryA() in your application might not be the same in the target process, due to ASLR - a technology designed specifically to thwart the activity you're attempting. Modern versions of Windows (Vista+) have this enabled by default for system DLLs

In order to do what you want, you'll need to implement a proper ThreadProc in your application that loads your DLL, allocate some executable memory (PAGE_EXECUTE) memory in your target process, copy it there, and use this address as your thread start point.

Bukes
  • 3,668
  • 1
  • 18
  • 20
  • Thanks, I didn't know about ASLR. Is there any links where I can find the code that will do this? – Bali C Jun 11 '12 at 14:32
  • Seems like randomization only occurs at startup, right? http://stackoverflow.com/questions/8568901/would-aslr-cause-friction-for-the-address-with-dll-injection – Motomotes Mar 24 '14 at 21:41
  • This logic is implemented in the loader, which means that any time a DLL is mapped into the address space of an application by the loader. This includes DLLs pulled in by linking via import libraries (startup), or by DLLs loaded via LoadLibrary()/LoadLibraryEx(). – Bukes Mar 24 '14 at 23:16
  • ASLR is only during startup, after that as long as both process have the same bit architecture (e.g. x64, x86) they will both have the same address for system libraries and their functions since kernel32.dll has to be loaded at the same address in every process. – Edward Severinsen Sep 14 '19 at 04:14
  • 1
    I'd also like to add that ASLR is for preventing remote code execution, "remote" as in a remote computer. That way a hacker exploiting a buffer overflow or the like won't know where to point EIP to execute specific functions to make remote connections or other malicious things. It's not meant to hinder other processes on the same computer. It would be pretty easily worked around if that were the case. – Edward Severinsen Sep 14 '19 at 04:23
5

Admin account does not need to implicitly own SE_DEBUG privilege. If you run under Vista/Win7, make sure that UAC is disabled. Use this code to enable it before you try to open process memory:

BOOL EnableDebugPrivilege()
{
    HANDLE hToken;
    LUID luid;
    TOKEN_PRIVILEGES tkp;

    if(!OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken ))
    {
        return FALSE;
    }

    if(!LookupPrivilegeValue( NULL, SE_DEBUG_NAME, &luid ))
    {
        return FALSE;
    }

    tkp.PrivilegeCount = 1;
    tkp.Privileges[0].Luid = luid;
    tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

    if(!AdjustTokenPrivileges( hToken, false, &tkp, sizeof( tkp ), NULL, NULL ))
    {
        return FALSE;
    }

    if(!CloseHandle( hToken ))
    {
        return FALSE;
    }

    return TRUE;
}
rkosegi
  • 14,165
  • 5
  • 50
  • 83
3

I would start with someone else's working example and go from there. The example projects, tutorials, and explanations on CodeProject are really solid.

Here is one on Hooking and DLLs.

And another. And a google search for you.

For certain kinds of hooks, there are permission limitations that you have to overcome, or you have to accept the fact that you can't hook every process.

Setting the UI-Access to true, and having your executable in C:/Program Files/, and having your dll digitally signed helps to access some of the secure windows in Windows. Here is an article that discusses some of these things.

Hope that helps.

phyatt
  • 18,472
  • 5
  • 61
  • 80
0

SetWindowsHookEx can also inject your DLL into another process.

Chris O
  • 5,017
  • 3
  • 35
  • 42