C library works by itself in executable form, but when used as Rust library using CC, it no longer works

1

I am trying to inject a dll into a specific application in rust. I gave up trying to do so in pure rust, as it was not working no matter what. So, I used a C injector and compiled it and it worked perfectly. However, when I use the CC crate to compile it and use the function, it no longer works at all. In this case, I was simply trying to inject a dll I made.

The code for the C is:

// test.c
#include <windows.h>
#include <TlHelp32.h> 
#include <stdio.h> 

#pragma comment(lib, "ntdll.lib")
EXTERN_C NTSYSAPI NTSTATUS NTAPI NtCreateThreadEx(PHANDLE,
    ACCESS_MASK, LPVOID, HANDLE, LPTHREAD_START_ROUTINE, LPVOID,
    BOOL, SIZE_T, SIZE_T, SIZE_T, LPVOID);

struct NtCreateThreadExBuffer
{
    SIZE_T Size;
    SIZE_T Unknown1;
    SIZE_T Unknown2;
    PULONG Unknown3;
    SIZE_T Unknown4;
    SIZE_T Unknown5;
    SIZE_T Unknown6;
    PULONG Unknown7;
    SIZE_T Unknown8;
};


DWORD GetPid(const wchar_t *targetProcess)
{
    HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    PROCESSENTRY32 procEntry;
    procEntry.dwSize = sizeof(procEntry);

    if (snap && snap != INVALID_HANDLE_VALUE && Process32First(snap, &procEntry))
    {
        do
        {
            if (!wcscmp(procEntry.szExeFile, targetProcess))
            {
                break;
            }
        } while (Process32Next(snap, &procEntry));
    }
    CloseHandle(snap);
    return procEntry.th32ProcessID;
}

void injectAmongUs()
{
    DWORD dwPid = GetPid(L"Among Us.exe");
    struct NtCreateThreadExBuffer ntbuffer;

    memset(&ntbuffer, 0, sizeof(struct NtCreateThreadExBuffer));
    DWORD temp1 = 0;
    DWORD temp2 = 0;

    ntbuffer.Size = sizeof(struct NtCreateThreadExBuffer);
    ntbuffer.Unknown1 = 0x10003;
    ntbuffer.Unknown2 = 0x8;
    ntbuffer.Unknown3 = (DWORD *)&temp2;
    ntbuffer.Unknown4 = 0;
    ntbuffer.Unknown5 = 0x10004;
    ntbuffer.Unknown6 = 4;
    ntbuffer.Unknown7 = &temp1;
    ntbuffer.Unknown8 = 0;

    HANDLE proc = OpenProcess(GENERIC_ALL, 0, dwPid);
    HANDLE hThread;
    wchar_t path[] = L"path/to/dll";
    LPVOID allocAddr = VirtualAllocEx(proc, 0, sizeof(path), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
    WriteProcessMemory(proc, allocAddr, path, sizeof(path), NULL);
    NTSTATUS status = NtCreateThreadEx(&hThread, GENERIC_ALL, NULL, proc,
        (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryW"), allocAddr,
        FALSE, NULL, NULL, NULL, &ntbuffer);

}

If I compile this file exactly the way it is but add a main method:

int main()
{
    injectAmongUs();

    return 1;
}

It works perfectly as intended. However, if I remove the main method and use CC with this build script:

// build.rs
fn main() {
    cc::Build::new()
        .file("test.c")
        .compile("injector.dll");
}

and then call it in main with

//main.rs
extern "C" {
    fn injectAmongUs();
}

fn main() {
    unsafe {
        injectAmongUs();;
    }
}

which results in (exit code: 0xc0000005, STATUS_ACCESS_VIOLATION). How can I get it to successfully inject as if I just ran the .exe normally? Currently I just put the .exe with it, but that is not desirable and would rather it be built and used as a library. Note, I am trying to inject Among Us, and so I am running this as 32 bit with cargo run --target i686-pc-windows-msvc.

c
windows
winapi
rust
dll-injection
asked on Stack Overflow Dec 24, 2020 by user3756718 • edited Dec 25, 2020 by user3756718

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0