-3

Despite the fact that memory allocation/write, finding LoadLibraryA address and creating a remote thread return valid (not NULL) results, absolutely nothing happens after that (mainly, the DllMain of the loaded DLL doesn't seem to get called).

#define PROC_NAME L"TestConsole.exe"
#define DLL_NAME "TestLib.dll\0"

HANDLE GetProcessByName(const wchar_t* name);

int main()
{
    const char dllName[] = DLL_NAME;
    int dllNameSize = strlen(dllName) + 1;

    HANDLE process = GetProcessByName(PROC_NAME);

    LPVOID allocMem = VirtualAllocEx(process, NULL, dllNameSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);

    WriteProcessMemory(process, allocMem, dllName, dllNameSize, NULL);

    // Just to make sure
    char buff[20];
    ReadProcessMemory(process, allocMem, buff, dllNameSize, NULL);
    printf("Data: %s\n", buff);

    LPVOID libraryAddress =
        (LPVOID)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryA");

    HANDLE remoteThread = CreateRemoteThread(process, NULL, NULL, (LPTHREAD_START_ROUTINE)libraryAddress, allocMem, NULL, NULL);
}

HANDLE GetProcessByName(const wchar_t* name)
{
    PROCESSENTRY32 entry;
    entry.dwSize = sizeof(PROCESSENTRY32);

    HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);

    if (Process32First(snapshot, &entry) == TRUE)
    {
        while (Process32Next(snapshot, &entry) == TRUE)
        {
            if (wcscmp(entry.szExeFile, name) == 0)
            {
                return OpenProcess(PROCESS_ALL_ACCESS, FALSE, entry.th32ParentProcessID);
            }
        }
    }

    return NULL;
}

Things I know/checked:

  • The thread gets created and a valid (not null) handle is returned. Despite it nothing happens.
  • I'm pretty sure that it's not DLL's fault. It's extremely simple, simply prints to console when it gets loaded and it works correctly when used simply with CreateThread().
  • Injector, DLL and the app to which I'm injecting are all 64 bit. If I chose any other platform (for all 3) everything works the same except for CreateRemoteThread(), which now fails.
QmlnR2F5
  • 934
  • 10
  • 17
  • @HansPassant How about MessageBox() Because this one doesn't work either. – QmlnR2F5 Jan 10 '21 at 22:52
  • Can I get a feedback on this downvote? I'd happily improve my question. A downvote doesn't tell much. – QmlnR2F5 Jan 10 '21 at 23:03
  • 2
    Your code is very buggy. `GetProcessByName()` is leaking the `HANDLE` from `CreateToolhelp32Snapshot()`, skipping the 1st file from `Process32First()`, passing the wrong process ID to `OpenProcess()`, and requesting too many access rights. `main()` is leaking the remote memory and thread. And your entire code is not doing any error handling. But most important, the file path you are passing to `LoadLibraryA()` is a *relative* path. `LoadLibraryA()` is executed in the remote process, so the DLL will be looked for relative to the *remote* EXE. Don’t use relative paths, always use absolute paths. – Remy Lebeau Jan 11 '21 at 00:33
  • @QmlnR2F5 - i sure that you post your actual code, with all errors in it. *Don’t use relative paths, always use absolute paths.* - faster of all this is main reason. if want understand - attach debugger to target process, set bp to thread entry point (`LoadLibraryA`) in your case and see. are it called, what result of call. etc – RbMm Jan 11 '21 at 01:32
  • @QmlnR2F5 posting minimal code without error handling would not get you downvoted. Not following [mcve] guidelines could, though. In this case, I think the downvotes are probably more due to a lack of apparent effort in trying to debug and troubleshoot the problem yourself, and expecting us to diagnose the problem without seeing the DLL code, error codes/messages, etc. – Remy Lebeau Jan 11 '21 at 02:59
  • Why has the error checking been omitted from the code in the question? – David Heffernan Jan 11 '21 at 10:13
  • To make the code at least 3x smaller @DavidHeffernan – QmlnR2F5 Jan 11 '21 at 10:18

1 Answers1

2

The entry.th32ParentProcessID is the identifier of the process that created this process (its parent process). which means you did inject into the parent process of the target process (explorer.exe in my test). You should use entry.th32ProcessID instead.

In addition, the open permission PROCESS_ALL_ACCESS used in OpenProcess is too large, you only need to use what the CreateRemoteThread document requires: PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ

Drake Wu
  • 6,927
  • 1
  • 7
  • 30
  • 1
    Thank you. It explains everything. I was keep testing and when it randomly started crashing my explorer I got absolutely stunned and didn't know what was happening. Now everything works flawlessly. And yes, I am aware that PROCESS_ALL_ACCESS is overkill in my case. As I've said. I also created the target process. I don't care about being noisy or following good practices here. I just wanted it to work, so I made sure it had all permissions just to make sure that permissions weren't the problem. – QmlnR2F5 Jan 11 '21 at 09:24