6 Commits

Author SHA1 Message Date
lirent 8ca84a5861 Bump version to 0.1.6 2026-06-26 07:57:36 +03:00
lirent 91e5e05de4 Scope gva_code_xref by an explicit prot_any argument
It hard-coded VR_X, so a target whose page tables expose no executable
region silently yielded zero xrefs. Callers now pass the scope (VR_X to
restrict to code, VR_R when the X bit is unavailable); the decoder and
exact target match remain the correctness gate. Mirrors the prot_any
parameter gva_imm_xref already carries.
2026-06-26 07:57:35 +03:00
lirent 32440c7104 Drop the user-half top-level NX bit when deriving VR_X
Under KVA shadow (KPTI) the kernel CR3 marks user-half PML4Es NX as
hardening, so OR-ing that top-level NX down the walk made every user
region non-executable - even live code (ntdll .text read back r--u).
Ring 3 executes those pages via the user/shadow CR3, which reaches the
same shared lower tables through an NX-clear PML4E, so the kernel
table's user-half PML4E NX is not what enforces user execution. Ignore
it on the user half; sub-PML4E NX (shared between both CR3s) stays
authoritative.
2026-06-26 07:57:26 +03:00
lirent d26f6c0bf0 Install file(1) in the Debian CI job so shlibdeps can run
cpack's CPACK_DEBIAN_PACKAGE_SHLIBDEPS runs dpkg-shlibdeps, which needs
the file utility to detect ELF binaries and derive the runtime libc
dependency. The slim CI image does not ship it, so packaging failed at
the cpack step. Add file to the job toolchain.
2026-06-22 16:32:47 +03:00
lirent 0c3aa5ef25 Build a shared library and ship it as Debian packages
Factor the source list into an OBJECT library so the same objects back
both the existing static lib and a new shared libvmie.so (SONAME from the
project version; the version comes from the tag, falling back to a cached
default). Add install rules and a CPack DEB config that produce two
packages: libvmie0 (the runtime .so + SONAME symlink) and libvmie-dev
(public headers under include/vmie + the linker symlink), with the dev
package depending on the exact runtime version.

Add a CI job that, on a v* tag, builds the shared library, runs cpack,
and uploads both .deb files to the Gitea Debian package registry.
2026-06-22 15:52:39 +03:00
lirent 3028a4eb11 Take the kernel cr3 in the read-only win32 constructor
vmie_win32_open_ro_fd now takes a kcr3 and builds the struct-offset
profile read-only from the image (find ntoskrnl, resolve
PsInitialSystemProcess, build the profile, derive the System _EPROCESS),
so a read-only context has the full read surface - including
proc_list/proc_modules, not just the cr3-parameterised PE walks.

The read-only bring-up tail is factored out of host_bootstrap into a
shared helper; host_bootstrap keeps the beacon find / cr3 recovery / ACK
around it, so its behaviour and return codes are unchanged.
2026-06-20 17:02:29 +03:00
8 changed files with 205 additions and 57 deletions
+55
View File
@@ -70,3 +70,58 @@ jobs:
curl -fsSL -X POST -H "$auth" \ curl -fsSL -X POST -H "$auth" \
-F "attachment=@dist/${asset};type=application/zip" \ -F "attachment=@dist/${asset};type=application/zip" \
"${api}/releases/${rid}/assets?name=${asset}" "${api}/releases/${rid}/assets?name=${asset}"
deb:
runs-on: ubuntu-latest
container:
image: node:20-bookworm-slim
defaults:
run:
shell: bash
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install toolchain
run: |
apt-get update
apt-get install -y --no-install-recommends \
cmake make gcc libc6-dev dpkg-dev file \
gcc-mingw-w64-x86-64 ca-certificates curl
- name: Configure
env:
TAG: ${{ github.ref_name }}
run: cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DVMIE_VERSION=${TAG#v}
- name: Build shared library
run: cmake --build build -j --target vmie_shared
- name: Package
run: |
set -euo pipefail
(cd build && cpack -G DEB)
ls -l build/*.deb
- name: Publish to Debian registry
env:
TOKEN: ${{ secrets.PUBLISH_TOKEN }} # requires scope: package:write
SERVER: ${{ github.server_url }}
OWNER: ${{ github.repository_owner }}
DISTRIBUTION: stable
COMPONENT: main
run: |
set -euo pipefail
url="${SERVER}/api/packages/${OWNER}/debian/pool/${DISTRIBUTION}/${COMPONENT}/upload"
auth="Authorization: token ${TOKEN}"
for deb in build/*.deb; do
# 201 Created = uploaded; 409 Conflict = this version already present (re-run).
# Both are success; anything else fails. Do not use curl -f (it would fail 409).
code=$(curl -s -o /dev/null -w '%{http_code}' \
-X PUT -H "$auth" -T "$deb" "$url")
echo "$deb -> HTTP $code"
if [ "$code" != 201 ] && [ "$code" != 409 ]; then
echo "upload failed: $deb (HTTP $code)" >&2
exit 1
fi
done
+69 -7
View File
@@ -1,15 +1,19 @@
cmake_minimum_required(VERSION 3.18) # find_program(... REQUIRED) cmake_minimum_required(VERSION 3.18) # find_program(... REQUIRED)
project(vmi-engine C)
set(VMIE_VERSION "0.1.6" CACHE STRING "Library version (MAJOR.MINOR.PATCH); CI passes the tag")
project(vmi-engine VERSION ${VMIE_VERSION} LANGUAGES C)
set(CMAKE_C_STANDARD 17) # generation B uses no C23 feature set(CMAKE_C_STANDARD 17) # generation B uses no C23 feature
set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS ON) # deliberate: strnlen (POSIX) + void* arithmetic (GNU) set(CMAKE_C_EXTENSIONS ON) # deliberate: strnlen (POSIX) + void* arithmetic (GNU)
set(CMAKE_POSITION_INDEPENDENT_CODE ON) # -fPIC on all objects: static lib stays linkable into a shared object set(CMAKE_POSITION_INDEPENDENT_CODE ON) # -fPIC on all objects: static lib stays linkable into a shared object
include(GNUInstallDirs)
option(VMIE_LTO "Enable LTO" OFF) # build-only; shipped default is -O2, no LTO option(VMIE_LTO "Enable LTO" OFF) # build-only; shipped default is -O2, no LTO
# ---- host: VMI core as a static library --------------------------------- # ---- host: VMI core objects (single owner of the source list) -----------
add_library(vmie STATIC add_library(vmie_obj OBJECT
src/core/gpa.c src/core/gpa.c
src/engine/gva.c src/engine/gva.c
src/engine/sigphys.c src/engine/sigphys.c
@@ -27,15 +31,32 @@ add_library(vmie STATIC
src/handlers/x86dec.c src/handlers/x86dec.c
src/handlers/pmap.c src/handlers/pmap.c
src/handlers/snapdiff.c) src/handlers/snapdiff.c)
target_include_directories(vmie target_include_directories(vmie_obj
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include # public API: include/*.h PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include # public API: include/*.h
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src/core/include # private: core.h PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src/core/include # private: core.h
${CMAKE_CURRENT_SOURCE_DIR}/src/engine/include # private: engine-arch.h, pe.h ${CMAKE_CURRENT_SOURCE_DIR}/src/engine/include # private: engine-arch.h, pe.h
${CMAKE_CURRENT_SOURCE_DIR}/src/engine/win32) # private: engine-win32.h, contract.h ${CMAKE_CURRENT_SOURCE_DIR}/src/engine/win32) # private: engine-win32.h, contract.h
target_compile_options(vmie PRIVATE -O2 -Wall -Wextra) target_compile_options(vmie_obj PRIVATE -O2 -Wall -Wextra)
if(VMIE_LTO) if(VMIE_LTO)
target_compile_options(vmie PRIVATE -flto) target_compile_options(vmie_obj PRIVATE -flto)
target_link_options(vmie PRIVATE -flto) target_link_options(vmie_obj PRIVATE -flto)
endif()
# ---- host: static library (in-tree consumers: CLIs + test) --------------
# $<TARGET_OBJECTS:> carries object files only, not usage requirements:
# re-declare the PUBLIC include scope so vmie_cli/vmie_scan still see include/.
add_library(vmie STATIC $<TARGET_OBJECTS:vmie_obj>)
target_include_directories(vmie PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
# ---- host: shared library (external delivery: libvmie.so.*) -------------
add_library(vmie_shared SHARED $<TARGET_OBJECTS:vmie_obj>)
target_include_directories(vmie_shared PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
set_target_properties(vmie_shared PROPERTIES
OUTPUT_NAME vmie
SOVERSION ${PROJECT_VERSION_MAJOR}
VERSION ${PROJECT_VERSION})
if(VMIE_LTO)
target_link_options(vmie_shared PRIVATE -flto)
endif() endif()
# ---- host: CLI demonstrator over the library ---------------------------- # ---- host: CLI demonstrator over the library ----------------------------
@@ -61,3 +82,44 @@ add_custom_command(
COMMENT "Cross-compiling vmie-startup.exe (mingw-w64, x86-64)" COMMENT "Cross-compiling vmie-startup.exe (mingw-w64, x86-64)"
VERBATIM) VERBATIM)
add_custom_target(vmie-startup ALL DEPENDS ${VMIE_STARTUP}) add_custom_target(vmie-startup ALL DEPENDS ${VMIE_STARTUP})
# ---- install: shared library + public headers ---------------------------
# Versioned file + SONAME symlink -> runtime; unversioned linker symlink -> dev.
install(TARGETS vmie_shared
LIBRARY
DESTINATION ${CMAKE_INSTALL_LIBDIR}
COMPONENT runtime
NAMELINK_COMPONENT dev)
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/vmie
COMPONENT dev
FILES_MATCHING PATTERN "*.h")
# ---- package: two Debian packages (runtime + dev) -----------------------
set(CPACK_GENERATOR "DEB")
set(CPACK_DEB_COMPONENT_INSTALL ON)
set(CPACK_COMPONENTS_ALL runtime dev)
set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION})
# component -> Debian package name (Debian shared-library convention)
set(CPACK_DEBIAN_RUNTIME_PACKAGE_NAME "libvmie${PROJECT_VERSION_MAJOR}")
set(CPACK_DEBIAN_DEV_PACKAGE_NAME "libvmie-dev")
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "amd64")
set(VMIE_DEB_MAINTAINER "Gregory Lirent <opensource@lirent.ru>"
CACHE STRING "Debian package Maintainer field")
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "${VMIE_DEB_MAINTAINER}")
set(CPACK_DEBIAN_PACKAGE_SECTION "libs")
set(CPACK_DEBIAN_PACKAGE_PRIORITY "optional")
set(CPACK_DEBIAN_FILE_NAME "DEB-DEFAULT")
set(CPACK_COMPONENT_RUNTIME_DESCRIPTION
"VM introspection engine (Windows-guest memory introspection) - shared library")
set(CPACK_COMPONENT_DEV_DESCRIPTION
"VM introspection engine (Windows-guest memory introspection) - development files")
# dev depends on the exact runtime version; runtime libc dependency via shlibdeps
set(CPACK_DEBIAN_DEV_PACKAGE_DEPENDS "libvmie${PROJECT_VERSION_MAJOR} (= ${PROJECT_VERSION})")
set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
include(CPack)
+5 -1
View File
@@ -125,7 +125,11 @@ typedef struct {
* x86-64 has no read bit: a present page is readable, so VR_R is always set on a * x86-64 has no read bit: a present page is readable, so VR_R is always set on a
* returned region. Write/execute/user are the EFFECTIVE rights along the whole * returned region. Write/execute/user are the EFFECTIVE rights along the whole
* page-table path (RW & US are AND-ed across levels, NX is OR-ed), not just the * page-table path (RW & US are AND-ed across levels, NX is OR-ed), not just the
* leaf entry, so they reflect what the guest CPU actually enforces. */ * leaf entry, so they reflect what the guest CPU actually enforces. One
* exception keeps VR_X honest under KVA shadow (KPTI): the kernel CR3 marks
* user-half PML4Es NX as hardening, but ring 3 executes those pages via the
* user/shadow CR3 (same shared lower tables, NX-clear PML4E), so the user-half
* top-level NX bit is ignored when deriving VR_X. */
#ifndef VMIE_VREGION_DEFINED #ifndef VMIE_VREGION_DEFINED
#define VMIE_VREGION_DEFINED #define VMIE_VREGION_DEFINED
#define VR_R 0x1u /* readable (present => always set) */ #define VR_R 0x1u /* readable (present => always set) */
+12 -9
View File
@@ -70,18 +70,21 @@ int gva_sig_scan_multi(vmie_mem* m, uintptr_t cr3, uint64_t lo, uint64_t hi,
uint32_t prot_any, const sigset* s, uint32_t prot_any, const sigset* s,
sig_multi_hit* out, int max); sig_multi_hit* out, int max);
/* code-xref: every instruction in the X-regions of [lo,hi] whose near rel /* code-xref: every instruction in the regions of [lo,hi] kept by `prot_any`
* branch or RIP-relative memory operand resolves to `target_va`. Brute-scans * whose near rel branch or RIP-relative memory operand resolves to `target_va`.
* each byte offset with the light x86-64 decoder (x86dec.h, NOT a full * Brute-scans each byte offset with the light x86-64 decoder (x86dec.h, NOT a
* disassembler): an E8/E9/EB/Jcc rel branch matches when next_rip + rel == * full disassembler): an E8/E9/EB/Jcc rel branch matches when next_rip + rel ==
* target_va, and any RIP-relative operand (ModRM mod=00, rm=101) matches when * target_va, and any RIP-relative operand (ModRM mod=00, rm=101) matches when
* next_rip + disp32 == target_va (this covers lea/mov and any other rip-rel * next_rip + disp32 == target_va (this covers lea/mov and any other rip-rel
* form). Records each matching instruction-start VA. The sweep forces VR_X and * form). Records each matching instruction-start VA. The sweep is scoped by
* carries a >=15-byte overlap (max x86 instruction length) so no instruction is * `prot_any` (pass VR_X to restrict to code; pass VR_R when the target's
* cut at a window seam. Writes up to `max` VAs to `out` (NULL to count only) and * page-table X bit is unavailable - the decoder and exact target match keep the
* returns the TOTAL number of matches, or -1 on bad input. */ * result correct, only more bytes are decoded) and carries a >=15-byte overlap
* (max x86 instruction length) so no instruction is cut at a window seam. Writes
* up to `max` VAs to `out` (NULL to count only) and returns the TOTAL number of
* matches, or -1 on bad input. */
int gva_code_xref(vmie_mem* m, uintptr_t cr3, uint64_t lo, uint64_t hi, int gva_code_xref(vmie_mem* m, uintptr_t cr3, uint64_t lo, uint64_t hi,
uint64_t target_va, uint64_t* out, int max); uint32_t prot_any, uint64_t target_va, uint64_t* out, int max);
/* immediate / constant xref: every instruction in [lo,hi] (kept by the /* immediate / constant xref: every instruction in [lo,hi] (kept by the
* protection filter `prot_any`; pass VR_X to restrict to code) whose IMMEDIATE * protection filter `prot_any`; pass VR_X to restrict to code) whose IMMEDIATE
+12 -12
View File
@@ -93,18 +93,18 @@ vmie_win32* vmie_win32_open(const char* ram_path, uint64_t low);
vmie_win32* vmie_win32_open_fd(int fd, uint64_t low); vmie_win32* vmie_win32_open_fd(int fd, uint64_t low);
/* Open a READ-ONLY context over the RAM backing file `fd`, for a consumer that /* Open a READ-ONLY context over the RAM backing file `fd`, for a consumer that
* only reads. Unlike vmie_win32_open_fd this does NOT bootstrap (the magic- * only reads. It takes a caller-supplied `kcr3` (kernel cr3 / System DirectoryTableBase)
* signature handshake needs RW): the caller supplies the address space by passing * and builds the struct-offset profile read-only from the image (no bootstrap
* a cr3 to each read call. Every read API that takes a cr3 works - the section / * handshake - beacon and ACK are not used). The result has the FULL read
* function / import / export / callgraph / hook surfaces, gva_read_text, and the * capability: proc_list/proc_modules AND the section / function / import / export
* generic gva_* and scanner surfaces via vmie_win32_mem(); writes (gva_write) -1 * / callgraph / hook surfaces, gva_read_text, and the generic gva_* and scanner
* because the mapping is PROT_READ. proc_list/proc_modules are NOT available here: * surfaces via vmie_win32_mem(). Any write (gva_write) returns -1 because the
* they need the bootstrap-recovered profile, which a read-only context does not * mapping is PROT_READ. `fd` is BORROWED (dup()'d internally; the caller's fd
* carry. `fd` is BORROWED (dup()'d internally; the caller's fd stays valid after * stays valid after this call AND after vmie_win32_close()); an O_RDONLY fd is
* this call AND after vmie_win32_close()); an O_RDONLY fd is accepted. `low` is * accepted. `low` is the below-4G split, as in vmie_win32_open_fd. Returns a new
* the below-4G split, as in vmie_win32_open_fd. Returns a new context, or NULL on * context, or NULL if `kcr3` does not resolve a kernel (ntoskrnl not found under
* dup/fstat/mmap failure. Free with vmie_win32_close(). */ * it) or on dup/fstat/mmap failure. Free with vmie_win32_close(). */
vmie_win32* vmie_win32_open_ro_fd(int fd, uint64_t low); vmie_win32* vmie_win32_open_ro_fd(int fd, uint64_t low, uint64_t kcr3);
/* Unmap, close, and free a context. Safe on NULL. After this, every pointer /* Unmap, close, and free a context. Safe on NULL. After this, every pointer
* into guest memory obtained through this context is invalid. */ * into guest memory obtained through this context is invalid. */
+10 -1
View File
@@ -158,7 +158,16 @@ int gva_regions(vmie_mem* m, uintptr_t cr3, uint64_t lo, uint64_t hi,
if (!(e4 & PG_P)) continue; if (!(e4 & PG_P)) continue;
const uint64_t b4 = VA_CANON((uint64_t)i4 << 39); const uint64_t b4 = VA_CANON((uint64_t)i4 << 39);
if (!rgn_hit(b4, 1ull << 39, lo, hi)) continue; if (!rgn_hit(b4, 1ull << 39, lo, hi)) continue;
const int rw4 = (e4 >> 1) & 1, us4 = (e4 >> 2) & 1, nx4 = (int)(e4 >> 63) & 1; const int rw4 = (e4 >> 1) & 1, us4 = (e4 >> 2) & 1;
/* On a KVA-shadow (KPTI) Windows the kernel CR3 marks user-half PML4Es
* NX as hardening: the kernel must not execute user pages through its own
* mapping. Ring 3 runs under the user/shadow CR3, which reaches the SAME
* lower tables (PDPT/PD/PT are shared) through a PML4E with NX clear, so
* that top-level NX is not what executes user code. Drop it on the user
* half; sub-PML4E NX stays authoritative (it is shared between the two
* CR3s). On a non-KPTI guest a code-covering user PML4E already has NX
* clear, so this only ever discards a zero. i4 < 256 == canonical user. */
const int nx4 = (i4 < 256) ? 0 : ((int)(e4 >> 63) & 1);
const uint64_t* t3 = gpa_ptr(m, e4 & PFN_MASK, 4096); const uint64_t* t3 = gpa_ptr(m, e4 & PFN_MASK, 4096);
if (!t3) continue; if (!t3) continue;
+40 -25
View File
@@ -6,6 +6,9 @@
#define MZ 0x5A4Du #define MZ 0x5A4Du
__attribute__((cold))
static int host_profile_from_cr3(vmie_win32* v, uintptr_t cr3);
/* ---- lifecycle (cold) ---------------------------------------------------- */ /* ---- lifecycle (cold) ---------------------------------------------------- */
__attribute__((cold)) __attribute__((cold))
@@ -34,10 +37,12 @@ vmie_win32* vmie_win32_open_fd(int fd, uint64_t low) {
return v; return v;
} }
/* Read-only context: no bootstrap, the cr3 is supplied per read call. The mem is /* Read-only consumer context: maps the backing file PROT_READ and builds the
* mapped PROT_READ (gpa_from_ro_fd), so every write through it returns -1. */ * struct-offset profile from the image under the caller-supplied kcr3 (no
* beacon, no cr3 recovery, no ACK write). All read APIs work, incl.
* proc_list/proc_modules; writes return -1. */
__attribute__((cold)) __attribute__((cold))
vmie_win32* vmie_win32_open_ro_fd(int fd, uint64_t low) { vmie_win32* vmie_win32_open_ro_fd(int fd, uint64_t low, uint64_t kcr3) {
vmie_win32* v = calloc(1, sizeof *v); vmie_win32* v = calloc(1, sizeof *v);
if (!v) { if (!v) {
return NULL; return NULL;
@@ -46,6 +51,10 @@ vmie_win32* vmie_win32_open_ro_fd(int fd, uint64_t low) {
free(v); free(v);
return NULL; return NULL;
} }
if (host_profile_from_cr3(v, (uintptr_t)kcr3)) {
vmie_win32_close(v);
return NULL;
}
return v; return v;
} }
@@ -181,6 +190,31 @@ static uint32_t ko_export_rva(vmie_mem* m, uintptr_t cr3, uint64_t kbase, const
return 0; return 0;
} }
__attribute__((cold))
static int host_profile_from_cr3(vmie_win32* v, uintptr_t cr3) {
vmie_mem* m = &v->mem;
uint8_t guid[16];
uint32_t age, rva;
uint64_t sys_ep, dtb;
if (find_ntoskrnl(m, cr3, &v->kbase, guid, &age)) {
return -3;
}
rva = ko_export_rva(m, cr3, v->kbase, "PsInitialSystemProcess");
if (!rva || gva_read(m, cr3, v->kbase + rva, &sys_ep, 8)) {
return -4;
}
if (profile_build(v, cr3, sys_ep, guid, age)) {
return -5;
}
if (gva_read(m, cr3, sys_ep + v->prof.ep_dtb, &dtb, 8)) {
return -6;
}
v->kcr3 = dtb & PFN_MASK;
v->sysproc = sys_ep;
return 0;
}
static void beacon_ack(vmie_mem* m, uint64_t anchor_pa) { static void beacon_ack(vmie_mem* m, uint64_t anchor_pa) {
uint64_t ack = CONTRACT_MAGIC_R; uint64_t ack = CONTRACT_MAGIC_R;
gpa_write(m, anchor_pa + offsetof(contract, ack), &ack, 8); gpa_write(m, anchor_pa + offsetof(contract, ack), &ack, 8);
@@ -195,10 +229,6 @@ int host_bootstrap(vmie_win32* v) {
vmie_mem* m = &v->mem; vmie_mem* m = &v->mem;
uint64_t anchor_pa, va_self; uint64_t anchor_pa, va_self;
uintptr_t cr3boot; uintptr_t cr3boot;
uint32_t rva;
uint8_t guid[16];
uint32_t age;
uint64_t sys_ep;
if (beacon_find(m, &anchor_pa, &va_self)) { if (beacon_find(m, &anchor_pa, &va_self)) {
return -1; return -1;
@@ -208,26 +238,11 @@ int host_bootstrap(vmie_win32* v) {
return -2; return -2;
} }
if (find_ntoskrnl(m, cr3boot, &v->kbase, guid, &age)) { const int rc = host_profile_from_cr3(v, cr3boot);
return -3; if (rc) {
return rc;
} }
rva = ko_export_rva(m, cr3boot, v->kbase, "PsInitialSystemProcess");
if (!rva || gva_read(m, cr3boot, v->kbase + rva, &sys_ep, 8)) {
return -4;
}
if (profile_build(v, cr3boot, sys_ep, guid, age)) {
return -5;
}
uint64_t dtb;
if (gva_read(m, cr3boot, sys_ep + v->prof.ep_dtb, &dtb, 8)) {
return -6;
}
v->kcr3 = dtb & PFN_MASK;
v->sysproc = sys_ep;
beacon_ack(m, anchor_pa); beacon_ack(m, anchor_pa);
return 0; return 0;
} }
+2 -2
View File
@@ -115,10 +115,10 @@ static int xref_sweep_cb(void* u, const uint8_t* data, size_t len,
} }
int gva_code_xref(vmie_mem* m, uintptr_t cr3, uint64_t lo, uint64_t hi, int gva_code_xref(vmie_mem* m, uintptr_t cr3, uint64_t lo, uint64_t hi,
uint64_t target_va, uint64_t* out, int max) { uint32_t prot_any, uint64_t target_va, uint64_t* out, int max) {
struct xref_cb c; memset(&c, 0, sizeof c); struct xref_cb c; memset(&c, 0, sizeof c);
c.target = target_va; c.out = out; c.max = max; c.target = target_va; c.out = out; c.max = max;
if (gva_sweep(m, cr3, lo, hi, VR_X, X86_MAX_INSN, xref_sweep_cb, &c) < 0) { if (gva_sweep(m, cr3, lo, hi, prot_any, X86_MAX_INSN, xref_sweep_cb, &c) < 0) {
return -1; return -1;
} }
return c.n; return c.n;