views:

587

answers:

2

I have written some sample program and DLL to learn the concept of DLL injection.

My injection code to inject the DLL to the sample program is as follows (error handling omitted):

std::wstring dll(L"D:\\Path\\to\\my\\DLL.dll");
LPTHREAD_START_ROUTINE pLoadLibraryW = 
    (LPTHREAD_START_ROUTINE)GetProcAddress(hKernel32, "LoadLibraryW");
int bytesNeeded = WideCharToMultiByte(CP_UTF8, 0, dll.c_str(), dll.length(), 
    NULL, 0, NULL, NULL);
std::vector<byte> dllName(bytesNeeded);
WideCharToMultiByte(CP_UTF8, 0, dll.c_str(), dll.length(), 
    (LPSTR)&dllName[0], bytesNeeded, NULL, NULL);
// Memory is a class written by me to simplify memory processes. 
// Constructor takes desired permissions.
Memory mem (pid, false, true, false, true, false, false, false, 
    false, false, true, true, true, false);
// Ensures deletion of the allocated range.
// true / true / false = read and write access, no execute permissions
std::tr1::shared_ptr<void> allocated = 
    mem.AllocateBytes(dllName.size(), true, true, false);
mem.WriteBytes((unsigned int)allocated.get(), dllName);
mem.CreateThread(pLoadLibraryW, allocated.get());

Memory::CreateThread is as follows:

void Memory::CreateThread(LPTHREAD_START_ROUTINE address, LPVOID parameter) const {
    std::tr1::shared_ptr<void> hThread(CreateRemoteThread(m_hProcess.get(), 
        NULL, 0, address, parameter, 0, NULL), CloseHandle);
    if (hThread.get() == NULL) {
        throw std::runtime_error("Memory::CreateThread: CreateRemoteThread failed");
    }
    DWORD returned = WaitForSingleObject(hThread.get(), INFINITE);
    if (returned != WAIT_OBJECT_0) {
        throw std::runtime_error("Memory::CreateThread: The remote thread did not complete properly");
    }
}

The problem is, that the module isn't loaded. However, when I change the second line to

LPTHREAD_START_ROUTINE pLoadLibraryW =
    (LPTHREAD_START_ROUTINE)GetProcAddress(hKernel32, "LoadLibraryA");

it works (since the test dll has no unicode characters in it's name).

How to make it work with LoadLibraryW?

+1  A: 

I'm not sure why you are creating a thread and passing it the address of the LoadLibraryW function. Wouldn't it be easier and safer to call LoadLibraryW directly?

Either way, you certainly don't need to make any WideCharToMultiByte calls. LoadLibraryW expects a wide character module name.

Is there any reason why you can't just do this?

HMODULE hLibHandle = LoadLibraryW( L"D:\\Path\\to\\my\\DLL.dll" );
Charles Bailey
Yes, you have to call it from the other process so that the DLL gets loaded inside of it.
Etan
What other process? You have a second thread, but that's going to terminate as soon as `LoadLibraryW` returns.
Charles Bailey
@Charles - see the call to CreateRemoteThread? Mind you, that looks a bit dodgy. Can you guarantee that kernel32.dll has been loaded (and potentially relocated) to the same address in both processes?
Steve Folly
Oops, missed that. I think I read it as CreateThread.
Charles Bailey
You start a remote thread in a demo process (just a getchar(); return 0;) which then loads the DLL via LoadLibrary and executes your code inside of it's address space. That's DLL injection.
Etan
... and since the code doesn't run in your address space, you have to write the string first to the target process...
Etan
+2  A: 
HMODULE WINAPI LoadLibrary(
  __in  LPCTSTR lpFileName
);

It takes a TCHAR -- so the argument for LoadLibraryW has to be a wide string; the code above passes the multi-byte form of the argument, which is the form that LoadLibraryA wants.

Steve Gilham
And how to convert the wide string to bytes?
Etan
const char * ptrToWide = (const char*)dll.c_str() gets you a pointer; the length to allocate for a copy is 2 * (wcslen(dll.c_str()) + 1)
Steve Gilham