9

So i just read a little bit about how one would go about for injecting a dll into a running program on Wikipedia (the CreateRemoteThread idea). I followed the steps described and eventually got it working. The thing i found interesting though which took some time to figure out are the following: When creating my remote thread and sending in the function i would like to be run as the first/starting one i hit a snag, when it was run it failed to call the proper functions, they seemed to turn into rubbish when i looked at them in OllyDBG which in turn resulted in the program crashing down on me. The code i used then was something along these lines:

static DWORD __stdcall inject(LPVOID threadParam)
{
    MessageBoxA(NULL, "test", "test", NULL);
    LoadLibrary("my.dll");
    return 0;
}

And somewhere else:

CreateRemoteThreadEx(hProcess, NULL, 0, LPTHREAD_START_ROUTINE(fnPageBase), dbPageBase, 0, NULL, &threadId);

Where fnPageBase is the memory I've allocated in the to be injected process for my function and dbPageBase the memory I've allocated for a struct that is passed as the LPVOID threadParam.

Something like that, the problem was that both MessageBoxA and LoadLibrary didn't get a proper address it would seem, when i checked them in OllyDBG they always pointed to something that didn't exist. I googled around a little and found out that i should be using GetProcAddr to get a address to ie: LoadLibrary which i could later use by sending in some data via the LPVOID threadParam in my inject() call. So my question is: Why does it work when i use the GetProcAddr and not when I just try to use it "normally"? Do I get some specific address that's always mapped in for everyone in the same region in memory when using that?

Also, what happens to my strings in the inject() function? Are they moved to some other place during compile which makes them unavailable to the program i'm injecting since it's in a totally different place of the memory (i.e., it's not mapped to there?)? I worked that around by sending that along in a struct with the LPVOID threadParam aswell in a struct that i had copied over to memory available to the .exe I was injecting.

If you need more info on how I did the other parts please do tell and I'll update.

8

One thing you need to keep in mind is that code in your process and the code in the target process reside in different address spaces. So any address in your program is not necessary valid in the target process and vice versa.

This means the code that you inject cannot many any assumptions about addresses of functions or variables. Even your inject function's address is valid only in your process; to make it available in the target process you'd have to: 1) copy the code there; and 2) make sure any functions or memory addresses it refers to are valid in the new address space.

That's why the normal approach used with CreateRemoteThreadEx is to copy the DLL name to the target process and create the thread using the address of the LoadLibrary function:

// 1. Allocate memory in the remote process for szLibPath
pLibRemote = ::VirtualAllocEx( hProcess, NULL, sizeof(szLibPath),
                               MEM_COMMIT, PAGE_READWRITE );

// 2. Write szLibPath to the allocated memory
::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 );

(snippet from Code Project)

You can see that pLibRemote (with the address of the DLL name in the target process) is passed as the parameter to the thread routine. So the result of this is equivalent to:

LoadLibraryA(pLibRemote);

executed in the target process.

Strictly speaking, this is not guaranteed to work because the address of LoadLibraryA in your process is not necessarily the same as LoadLibraryA in the other process. However, in practice it does work because system DLLs like kernel32 (where LoadLibraryA resides) are mapped to the same address in all processes, so LoadLibraryA also has the same address in both processes.

  • So theoretically we could go wrong and not get a proper address even when using GetProcAddr? Also, why wouldn't &LoadLibraryA give a good address aswell if they're all mapped into the same region? Should this be posted somewhere else as a separate question or is it okay to ask here? – lfxgroove Sep 15 '13 at 8:46
  • &LoadLibraryA may return a pointer to the import stub in your process and not the final address in kernel32.dll. – Igor Skochinsky Sep 15 '13 at 12:30
  • I thought that nowadays with process space randomization you cannot even count on kernel32 being mapped at the same address... does it still work in win7/8 too? – Lorenzo Dematté Sep 16 '13 at 13:18
  • @LorenzoDematté: AFAIK load address of kernel32 is randomized on each boot but it remains constant afterwards. – Igor Skochinsky Sep 16 '13 at 13:38
  • Good to know. And it does make sense, as mapping onto the same address enable sharing across processes. – Lorenzo Dematté Sep 16 '13 at 14:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.