Skip to content

Unable to reliably get command line arguments. #197

@Oninaig

Description

@Oninaig

I've tried so many variations of extracting command line arguments from running processes in a VM with kvm-vmi but I am currently at a loss.

// vmi_probe.c
// Host-side VM introspection, Milestone 1 (fixed API usage).
// - Prints QEMU mappings for the VM (hugepages/memfd/shm hints).
// - Walks Windows EPROCESS list to find a target process by ImageFileName.
// - Reads that process's PEB->ProcessParameters->CommandLine.
// - Resolves DTB/CR3 with vmi_pid_to_dtb and uses access_context_t for reads.
//   Falls back to PID-based _va reads if DTB resolution fails.
//
// Build:
//   gcc -O2 -march=native -Wall -Wextra vmi_probe.c -o vmi_probe $(pkg-config --cflags --libs libvmi)
// If pkg-config isn't available for libvmi, try:
//   gcc -O2 -march=native -Wall -Wextra -I/usr/local/include -L/usr/local/lib -o vmi_probe vmi_probe.c -lvmi
//
// Run:
//   sudo ./vmi_probe <vm_name> <process_name>
//   e.g., sudo ./vmi_probe win10 notepad.exe

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
#include <stdbool.h>
#include <string.h>
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>

#include <libvmi/libvmi.h>

// ------------------------------
// Utils
// ------------------------------
static void to_lower(char *s) { for (; *s; ++s) *s = (char)tolower((unsigned char)*s); }

static bool strcasestr_bool(const char *hay, const char *needle) {
    if (!hay || !needle) return false;
    size_t nlen = strlen(needle);
    if (!nlen) return false;
    char *hcopy = strdup(hay);
    char *ncopy = strdup(needle);
    if (!hcopy || !ncopy) { free(hcopy); free(ncopy); return false; }
    to_lower(hcopy); to_lower(ncopy);
    bool found = strstr(hcopy, ncopy) != NULL;
    free(hcopy); free(ncopy);
    return found;
}

static bool read_cmdline(pid_t pid, char *buf, size_t buflen) {
    char path[128];
    snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
    int fd = open(path, O_RDONLY);
    if (fd < 0) return false;
    ssize_t n = read(fd, buf, (ssize_t)(buflen - 1));
    close(fd);
    if (n <= 0) return false;
    for (ssize_t i = 0; i < n; i++) if (buf[i] == '\0') buf[i] = ' ';
    buf[n] = '\0';
    return true;
}

static pid_t find_qemu_pid_for_guest(const char *guest_name) {
    DIR *d = opendir("/proc");
    if (!d) return -1;
    struct dirent *de;
    pid_t found = -1;
    char cmdbuf[8192];
    while ((de = readdir(d)) != NULL) {
        if (de->d_type != DT_DIR) continue;
        pid_t pid = (pid_t)atoi(de->d_name);
        if (pid <= 0) continue;

        char exe_path[256];
        snprintf(exe_path, sizeof(exe_path), "/proc/%d/exe", pid);
        char target[512];
        ssize_t len = readlink(exe_path, target, sizeof(target)-1);
        if (len < 0) continue;
        target[len] = '\0';
        if (!strstr(target, "qemu-system-")) continue;

        if (!read_cmdline(pid, cmdbuf, sizeof(cmdbuf))) continue;
        if (strcasestr_bool(cmdbuf, guest_name)) { found = pid; break; }
    }
    closedir(d);
    return found;
}

static void print_qemu_mem_maps(pid_t qemu_pid) {
    char path[128];
    snprintf(path, sizeof(path), "/proc/%d/maps", qemu_pid);
    FILE *f = fopen(path, "r");
    if (!f) { perror("fopen maps"); return; }
    printf("\n[+] QEMU PID %d memory maps:\n", qemu_pid);
    char *line = NULL; size_t cap = 0;
    while (getline(&line, &cap, f) != -1) {
        bool is_huge = (strstr(line, "huge") || strstr(line, "Huge") || strstr(line, "hugetlb"));
        bool is_shm  = (strstr(line, "/dev/shm"));
        bool is_memfd= (strstr(line, "memfd:"));
        bool is_anon = (strstr(line, "anon_inode") || strstr(line, "[anon]"));
        char tag[128] = "";
        if (is_huge) strcat(tag, " [huge]");
        if (is_shm)  strcat(tag, " [shm]");
        if (is_memfd)strcat(tag, " [memfd]");
        if (is_anon) strcat(tag, " [anon]");
        if (tag[0]) {
            size_t L = strlen(line);
            if (L && line[L-1] == '\n') line[L-1] = '\0';
            printf("%s%s\n", line, tag);
        } else {
            printf("%s", line);
        }
    }
    free(line); fclose(f);

    snprintf(path, sizeof(path), "/proc/%d/smaps", qemu_pid);
    f = fopen(path, "r");
    if (!f) { perror("fopen smaps"); return; }
    printf("\n[+] Selected /proc/%d/smaps flags (hugepage hints):\n", qemu_pid);
    char *hdr = NULL; size_t hcap = 0; line = NULL; cap = 0;
    while (getline(&line, &cap, f) != -1) {
        if (strchr(line, '-') && strstr(line, " r")) {
            free(hdr); hdr = strdup(line);
        }
        if (strstr(line, "Huge") || strstr(line, "VmFlags:")) {
            if (hdr) printf("%s", hdr);
            printf("%s", line);
        }
    }
    free(hdr); free(line); fclose(f);
}

// ------------------------------
// Windows offsets bundle
// ------------------------------
typedef struct WinOffsets {
    addr_t eprocess_list;
    addr_t eprocess_pid;
    addr_t eprocess_name;
    addr_t eprocess_peb;

    addr_t peb_process_parameters; // _PEB.ProcessParameters
    addr_t peb_ldr;                // _PEB.Ldr

    addr_t rupp_commandline;       // _RTL_USER_PROCESS_PARAMETERS.CommandLine (UNICODE_STRING)
    addr_t ldr_inloadorder;        // _PEB_LDR_DATA.InLoadOrderModuleList
    addr_t ldr_entry_dllbase;      // _LDR_DATA_TABLE_ENTRY.DllBase
    addr_t ldr_entry_basedllname;  // _LDR_DATA_TABLE_ENTRY.BaseDllName (UNICODE_STRING)
    addr_t ldr_entry_inloadlinks;  // _LDR_DATA_TABLE_ENTRY.InLoadOrderLinks

    addr_t unicode_string_length;  // _UNICODE_STRING.Length
    addr_t unicode_string_buffer;  // _UNICODE_STRING.Buffer
} WinOffsets;

static bool get_offsets(vmi_instance_t vmi, WinOffsets *wo) {
    memset(wo, 0, sizeof(*wo));
    if (VMI_FAILURE == vmi_get_kernel_struct_offset(vmi, "_EPROCESS", "ActiveProcessLinks", &wo->eprocess_list) ||
        VMI_FAILURE == vmi_get_kernel_struct_offset(vmi, "_EPROCESS", "UniqueProcessId",     &wo->eprocess_pid)  ||
        VMI_FAILURE == vmi_get_kernel_struct_offset(vmi, "_EPROCESS", "ImageFileName",       &wo->eprocess_name) ||
        VMI_FAILURE == vmi_get_kernel_struct_offset(vmi, "_EPROCESS", "Peb",                 &wo->eprocess_peb)) {
        fprintf(stderr, "[-] Failed to get _EPROCESS offsets (check Rekall/Volatility profile).\n");
        return false;
    }

    // PEB & RUPP
    vmi_get_kernel_struct_offset(vmi, "_PEB", "ProcessParameters", &wo->peb_process_parameters);
    vmi_get_kernel_struct_offset(vmi, "_PEB", "Ldr",               &wo->peb_ldr);
    vmi_get_kernel_struct_offset(vmi, "_RTL_USER_PROCESS_PARAMETERS", "CommandLine", &wo->rupp_commandline);

    // LDR lists and entries
    vmi_get_kernel_struct_offset(vmi, "_PEB_LDR_DATA", "InLoadOrderModuleList", &wo->ldr_inloadorder);
    vmi_get_kernel_struct_offset(vmi, "_LDR_DATA_TABLE_ENTRY", "DllBase",       &wo->ldr_entry_dllbase);
    vmi_get_kernel_struct_offset(vmi, "_LDR_DATA_TABLE_ENTRY", "BaseDllName",   &wo->ldr_entry_basedllname);
    vmi_get_kernel_struct_offset(vmi, "_LDR_DATA_TABLE_ENTRY", "InLoadOrderLinks", &wo->ldr_entry_inloadlinks);

    // UNICODE_STRING
    vmi_get_kernel_struct_offset(vmi, "_UNICODE_STRING", "Length", &wo->unicode_string_length);
    vmi_get_kernel_struct_offset(vmi, "_UNICODE_STRING", "Buffer", &wo->unicode_string_buffer);
    printf("[dbg] Offsets: EPROCESS.Peb=0x%llx PEB.ProcessParameters=0x%llx RUPP.CommandLine=0x%llx PEB.Ldr=0x%llx LDR.InLoadOrder=0x%llx\n",
       (unsigned long long)&wo -> eprocess_peb,
       (unsigned long long)&wo -> peb_process_parameters,
       (unsigned long long)&wo -> rupp_commandline,
       (unsigned long long)&wo -> peb_ldr,
       (unsigned long long)&wo -> ldr_inloadorder);


    return true;
}

// ------------------------------
// Read helpers: UNICODE_STRING via DTB context OR PID fallback
// ------------------------------
static bool read_unicode_string_with_dtb(vmi_instance_t vmi, addr_t us_va, addr_t dtb, const WinOffsets *wo, char **out_utf8) {
    *out_utf8 = NULL;
    if (!us_va) return false;

    ACCESS_CONTEXT(ctx,
        .translate_mechanism = VMI_TM_PROCESS_DTB,
        .dtb = dtb,
        .addr = 0);

    // Length (USHORT)
    uint16_t len = 0;
    ctx.addr = us_va + (wo->unicode_string_length ? wo->unicode_string_length : 0);
    if (VMI_SUCCESS != vmi_read_16(vmi, &ctx, &len)) return false;

    // Buffer (PWSTR)
    addr_t bufptr = 0;
    ctx.addr = us_va + (wo->unicode_string_buffer ? wo->unicode_string_buffer : (sizeof(uint16_t)*2));
    if (VMI_SUCCESS != vmi_read_addr(vmi, &ctx, &bufptr)) return false;

    if (!len || !bufptr) { *out_utf8 = strdup(""); return true; }

    uint8_t *raw = (uint8_t*)malloc(len + 2);
    if (!raw) return false;
    ctx.addr = bufptr;
    size_t br = 0;
    if (VMI_SUCCESS != vmi_read(vmi, &ctx, len, raw, &br) || br != len) {
        free(raw);
        return false;
    }

    size_t outlen = len / 2;
    char *utf8 = (char*)calloc(outlen + 1, 1);
    if (!utf8) { free(raw); return false; }
    for (size_t i = 0; i < outlen; i++) utf8[i] = (char)raw[i*2];
    utf8[outlen] = '\0';
    free(raw);
    *out_utf8 = utf8;
    return true;
}

static bool read_unicode_string_with_pid(vmi_instance_t vmi, addr_t us_va, vmi_pid_t pid, const WinOffsets *wo, char **out_utf8) {
    *out_utf8 = NULL;
    if (!us_va) return false;

    uint16_t len = 0;
    addr_t bufptr = 0;

    if (VMI_SUCCESS != vmi_read_16_va(vmi, us_va + (wo->unicode_string_length ? wo->unicode_string_length : 0), pid, &len))
        return false;
    if (VMI_SUCCESS != vmi_read_addr_va(vmi, us_va + (wo->unicode_string_buffer ? wo->unicode_string_buffer : (sizeof(uint16_t)*2)), pid, &bufptr))
        return false;

    if (!len || !bufptr) { *out_utf8 = strdup(""); return true; }

    uint8_t *raw = (uint8_t*)malloc(len + 2);
    if (!raw) return false;
    if (VMI_SUCCESS != vmi_read_va(vmi, bufptr, pid, len, raw, NULL)) { free(raw); return false; }

    size_t outlen = len / 2;
    char *utf8 = (char*)calloc(outlen + 1, 1);
    if (!utf8) { free(raw); return false; }
    for (size_t i = 0; i < outlen; i++) utf8[i] = (char)raw[i*2];
    utf8[outlen] = '\0';
    free(raw);
    *out_utf8 = utf8;
    return true;
}


static vmi_init_data_t* make_kvmi_init_data(const char *socket_path) {
    // Allocate entries array dynamically (1 entry)
    size_t sz = sizeof(vmi_init_data_t) + sizeof(vmi_init_data_entry_t);
    vmi_init_data_t *init = (vmi_init_data_t*)malloc(sz);
    if (!init) return NULL;
    memset(init, 0, sz);
    init->count = 1;
    init->entry[0].type = VMI_INIT_DATA_KVMI_SOCKET;
    init->entry[0].data = strdup(socket_path);
    if (!init->entry[0].data) { free(init); return NULL; }
    return init;
}


// ------------------------------
// Main
// ------------------------------
int main(int argc, char **argv) {
    if (argc < 3) {
        fprintf(stderr, "Usage: %s <vm_name> <guest_process_name>\n", argv[0]);
        return 1;
    }
    const char *vm_name = argv[1];
    const char *target_name = argv[2];

    // 1) QEMU PID + maps
    pid_t qpid = find_qemu_pid_for_guest(vm_name);
    if (qpid > 0) {
        printf("[+] Found QEMU PID for '%s': %d\n", vm_name, qpid);
        char cmdbuf[8192];
        if (read_cmdline(qpid, cmdbuf, sizeof(cmdbuf))) printf("[+] QEMU cmdline: %s\n", cmdbuf);
        print_qemu_mem_maps(qpid);
    } else {
        fprintf(stderr, "[!] Could not find QEMU PID for guest '%s' (continuing with LibVMI).\n", vm_name);
    }


    // 2) LibVMI init (domain name via /etc/libvmi.conf)
    vmi_instance_t vmi = NULL;
    vmi_init_error_t err = VMI_INIT_ERROR_NONE;
    const char *kvmi_socket = "/tmp/introspector";

    vmi_init_data_t *init_data = make_kvmi_init_data(kvmi_socket);
    if (VMI_FAILURE == vmi_init_complete(
            &vmi,
            vm_name,
            VMI_INIT_DOMAINNAME,
            init_data,
            VMI_CONFIG_GLOBAL_FILE_ENTRY,
            NULL,
            &err)) {
        fprintf(stderr, "[-] LibVMI init failed (err=%d)\n", err);
        return 1;
    }
    printf("\n[+] LibVMI initialized for VM '%s'\n", vm_name);
    if (vmi_get_ostype(vmi) != VMI_OS_WINDOWS) {
        fprintf(stderr, "[-] Guest OS is not Windows.\n");
        vmi_destroy(vmi);
        return 1;
    }
    printf("[+] Guest OS detected: Windows\n");

    // 3) Offsets
    WinOffsets wo;
    if (!get_offsets(vmi, &wo)) {
        vmi_destroy(vmi);
        return 1;
    }

    // 4) Resolve PsActiveProcessHead VA, then read first Flink
    addr_t list_head_va = 0;
    if (VMI_FAILURE == vmi_translate_ksym2v(vmi, "PsActiveProcessHead", &list_head_va) || !list_head_va) {
        fprintf(stderr, "[-] Could not translate PsActiveProcessHead.\n");
        vmi_destroy(vmi);
        return 1;
    }
    printf("[+] PsActiveProcessHead @ 0x%llx\n", (unsigned long long)list_head_va);

    addr_t next = 0;
    if (VMI_FAILURE == vmi_read_addr_va(vmi, list_head_va, 0, &next)) { // 0 => kernel address space
        fprintf(stderr, "[-] Failed to read Flink from PsActiveProcessHead.\n");
        vmi_destroy(vmi);
        return 1;
    }

    // 5) Walk EPROCESS list
    char target_lower[260];
    strncpy(target_lower, target_name, sizeof(target_lower)-1);
    target_lower[sizeof(target_lower)-1] = '\0';
    to_lower(target_lower);

    addr_t target_eproc = 0;
    vmi_pid_t target_pid = 0;
    addr_t target_dtb = 0;
    bool have_dtb = false;

    printf("[+] Scanning EPROCESS list for '%s'...\n", target_lower);

    while (next != list_head_va) {
        addr_t eproc = next - wo.eprocess_list;

        // read next Flink early (kernel VA)
        if (VMI_FAILURE == vmi_read_addr_va(vmi, next, 0, &next)) {
            fprintf(stderr, "[-] Failed to read next Flink.\n");
            break;
        }

        // ImageFileName (char[15]) — kernel VA
        char imagename[16] = {0};
        if (VMI_SUCCESS != vmi_read_va(vmi, eproc + wo.eprocess_name, 0, sizeof(imagename)-1, imagename, NULL))
            continue;
        imagename[15] = '\0';
        char lowername[16];
        strncpy(lowername, imagename, sizeof(lowername));
        lowername[sizeof(lowername)-1] = '\0';
        to_lower(lowername);

        // UniqueProcessId (HANDLE/pointer-sized) — kernel VA
        uint64_t pid64 = 0;
        if (VMI_SUCCESS != vmi_read_64_va(vmi, eproc + wo.eprocess_pid, 0, &pid64))
            continue;

        // Match by name (suffix or exact)
        if (strcmp(lowername, target_lower) == 0 || (strlen(lowername) < strlen(target_lower) && strcasestr_bool(target_lower, lowername))) {
            target_eproc = eproc;
            target_pid = (vmi_pid_t)pid64;

            // Resolve DTB/CR3 for process
            addr_t dtb = 0;
            if (VMI_SUCCESS == vmi_pid_to_dtb(vmi, target_pid, &dtb) && dtb) {
                target_dtb = dtb;
                have_dtb = true;
            }

            printf("[+] Candidate: %-15s PID=%" PRIu64 " EPROCESS=0x%llx DTB=0x%llx\n",
                   imagename, (uint64_t)target_pid,
                   (unsigned long long)target_eproc, (unsigned long long)target_dtb);
            break;
        }
    }

    if (!target_eproc) {
        fprintf(stderr, "[-] Target process '%s' not found.\n", target_name);
        vmi_destroy(vmi);
        return 1;
    }

    // 6) Verify via PEB -> ProcessParameters -> CommandLine
    addr_t peb = 0;
    if (VMI_SUCCESS != vmi_read_addr_va(vmi, target_eproc + wo.eprocess_peb, 0, &peb) || !peb) {
        fprintf(stderr, "[-] Failed to read PEB pointer.\n");
    } else {
        addr_t proc_params = 0;
        if (have_dtb) {
            ACCESS_CONTEXT(ctx,
                .translate_mechanism = VMI_TM_PROCESS_DTB,
                .dtb = target_dtb,
                .addr = peb + wo.peb_process_parameters);
            if (VMI_SUCCESS == vmi_read_addr(vmi, &ctx, &proc_params) && proc_params) {
                addr_t us_cmdline_va = proc_params + wo.rupp_commandline; // UNICODE_STRING is inline
                char *cmd = NULL;
                if (read_unicode_string_with_dtb(vmi, us_cmdline_va, target_dtb, &wo, &cmd)) { //end replace
                    printf("[+] Verified CommandLine: %s\n", cmd ? cmd : "");
                    free(cmd);
                } else {
                    printf("[!] Could not decode CommandLine (DTB path).\n");
                }
            
            } else {
                printf("[!] Could not read PEB->ProcessParameters (DTB path).\n");
            }
        } else {
            // Fallback: PID-based helpers
            if (VMI_SUCCESS == vmi_read_addr_va(vmi, peb + wo.peb_process_parameters, target_pid, &proc_params) && proc_params) {
                addr_t us_cmdline_va = proc_params + wo.rupp_commandline; // inline UNICODE_STRING
                char *cmd = NULL;
                if (read_unicode_string_with_pid(vmi, us_cmdline_va, target_pid, &wo, &cmd)) { //end replace
                    printf("[+] Verified CommandLine: %s\n", cmd ? cmd : "");
                    free(cmd);
                } else {
                    printf("[!] Could not decode CommandLine (PID path).\n");
                }
             
            } else {
                printf("[!] Could not read PEB->ProcessParameters (PID path).\n");
            }
        }
    }

    // 7) Bonus: first loaded module base bytes (DTB preferred, PID fallback)
    if (wo.peb_ldr && wo.ldr_inloadorder) {
        addr_t peb_ldr = 0;
        if (have_dtb) {
            ACCESS_CONTEXT(ctx, 
                .translate_mechanism = VMI_TM_PROCESS_DTB,
                .dtb = target_dtb,
                .addr = peb + wo.peb_ldr);
            if (VMI_SUCCESS == vmi_read_addr(vmi, &ctx, &peb_ldr) && peb_ldr) {
                addr_t list = 0;
                ctx.addr = peb_ldr + wo.ldr_inloadorder;
                if (VMI_SUCCESS == vmi_read_addr(vmi, &ctx, &list) && list) {
                    addr_t flink = 0;
                    ctx.addr = list;
                    if (VMI_SUCCESS == vmi_read_addr(vmi, &ctx, &flink) && flink && flink != list) {
                        addr_t ldr_entry = flink - wo.ldr_entry_inloadlinks;
                        addr_t dllbase = 0;
                        ctx.addr = ldr_entry + wo.ldr_entry_dllbase;
                        if (VMI_SUCCESS == vmi_read_addr(vmi, &ctx, &dllbase) && dllbase) {
                            uint8_t buf[32] = {0};
                            ctx.addr = dllbase;
                            size_t br2 = 0;
                            if (VMI_SUCCESS == vmi_read(vmi, &ctx, sizeof(buf), buf, &br2) && br2 == sizeof(buf)) {
                                printf("[+] First module DllBase=0x%llx ; first 32 bytes:", (unsigned long long)dllbase);
                                for (size_t i = 0; i < sizeof(buf); i++) {
                                    if (i % 16 == 0) printf("\n    ");
                                    printf("%02x ", buf[i]);
                                }
                                printf("\n");
                            } else {
                                printf("[!] Failed to read %zu bytes from module base VA 0x%llx.\n",
                                    sizeof(buf), (unsigned long long)dllbase);
                            }
                        }
                    }
                }
            }
        } else {
            if (VMI_SUCCESS == vmi_read_addr_va(vmi, peb + wo.peb_ldr, target_pid, &peb_ldr) && peb_ldr) {
                addr_t list = 0;
                if (VMI_SUCCESS == vmi_read_addr_va(vmi, peb_ldr + wo.ldr_inloadorder, target_pid, &list) && list) {
                    addr_t flink = 0;
                    if (VMI_SUCCESS == vmi_read_addr_va(vmi, list, target_pid, &flink) && flink && flink != list) {
                        addr_t ldr_entry = flink - wo.ldr_entry_inloadlinks;
                        addr_t dllbase = 0;
                        if (VMI_SUCCESS == vmi_read_addr_va(vmi, ldr_entry + wo.ldr_entry_dllbase, target_pid, &dllbase) && dllbase) {
                            uint8_t buf[32] = {0};
                            if (VMI_SUCCESS == vmi_read_va(vmi, dllbase, target_pid, sizeof(buf), buf, NULL)) {
                                printf("[+] First module DllBase=0x%llx ; first 32 bytes:", (unsigned long long)dllbase);
                                for (size_t i = 0; i < sizeof(buf); i++) {
                                    if (i % 16 == 0) printf("\n    ");
                                    printf("%02x ", buf[i]);
                                }
                                printf("\n");
                            }
                        }
                    }
                }
            }
        }
    }

    printf("\n[+] Target process summary:\n");
    printf("    Name     : %s\n", target_name);
    printf("    PID      : %" PRIu64 "\n", (uint64_t)target_pid);
    printf("    EPROCESS : 0x%llx\n", (unsigned long long)target_eproc);
    printf("    DTB/CR3  : 0x%llx (%s)\n", (unsigned long long)target_dtb, (have_dtb ? "resolved via vmi_pid_to_dtb" : "fallback to PID reads"));

    vmi_destroy(vmi);
    printf("[+] LibVMI destroyed. Milestone 1 complete.\n");
    return 0;
}




This always fails to decode the command line for any given process. I feel like I'm going crazy here because I can successfully get _all other information:

[+] LibVMI initialized for VM 'win10'
[+] Guest OS detected: Windows
[dbg] Offsets: EPROCESS.Peb=0x7ffe96f5a018 PEB.ProcessParameters=0x7ffe96f5a020 RUPP.CommandLine=0x7ffe96f5a030 PEB.Ldr=0x7ffe96f5a028 LDR.InLoadOrder=0x7ffe96f5a038
[+] PsActiveProcessHead @ 0xfffff80211e1e270
[+] Scanning EPROCESS list for 'fivem_gtaprocess.exe'...
[+] Candidate: FiveM_GTAProce  PID=9132 EPROCESS=0xffffbe0c7b3ee080 DTB=0x31bf14000
[!] Could not read PEB->ProcessParameters (DTB path).

[+] Target process summary:
    Name     : TestProcess.exe
    PID      : 9132
    EPROCESS : 0xffffbe0c7b3ee080
    DTB/CR3  : 0x31bf14000 (resolved via vmi_pid_to_dtb)
--Destroying KVM driver
[+] LibVMI destroyed.

However I believe the DTB is wrong, it never resolves to userspace only the kernel's DTB which I think could be part of it. Any ideas?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions