實驗環境win7 sp1 x64,newbluepill-0.32,VS2013,WDK8.1
NewBluePill源代碼編譯後,使用InstDrv成功載入生成的兩個驅動:dbgclient.sys和newbp.sys。通過bpknock.exe查看運行結果,成功安裝了bluepill。
但卸載時出了問題,dbgclient.sys驅動可以成功卸載,但newbp.sys已卸載系統就停下不動了。
目的是基於newbluepill做實驗,但這很不方便,不能每次修改完代碼都重啓一次吧。不是什麼高難度的工作,只是沒找到有人告訴如何做,分享一下。
下面進入正文:
查閱相關資料在書《NewBluePill深入理解硬件虛擬機》的第90頁中看到了解釋。書中說默認情況下NewBluePill在Intel平臺上是不能正常關閉的,並分析了不能關閉的原因。
按照書中分析的原因,對代碼進行了一些修改,成功實現了卸載,不能卸載的具體原因,可參照書上的描述,就不重複了,下面只給出修復思路和代碼。
書中分析後得出的結論是:驅動卸載函數會爲每個CPU調用編號爲NBP_HYPERCALL_UNLOAD的VMCALL,不能成功卸載的原因是沒有對該VMMCALL進行處理。並給出了bluepill中另一個可以卸載虛擬機的函數,Hvm->ArchShutdown。
所以修復思路就是將編號爲NBP_HYPERCALL_UNLOAD的VMCALL註冊爲處理函數爲Hvm->ArchShutdown。後來發現NewBluePill實現了對vmmcall的處理函數,只是沒有註冊而已,該函數爲hypercalls.c裏的HcDispatchHypercall,所以註冊爲這個函數就可以,該函數裏已經寫好了對卸載事件的處理。
Bluepill中爲各個VMM Exit事件註冊處理函數的函數是VmxRegisterTraps。
原有代碼中爲VMCALL註冊處理函數的過程爲:
1. 定義一個數組:
TableOfVmxExits[]= {
EXIT_REASON_VMCALL,
EXIT_REASON_VMCALL,
EXIT_REASON_VMLAUNCH,
EXIT_REASON_VMRESUME,
EXIT_REASON_VMPTRLD,
EXIT_REASON_VMPTRST,
EXIT_REASON_VMREAD,
EXIT_REASON_VMWRITE,
EXIT_REASON_VMXON,
EXIT_REASON_VMXOFF
};
2. 在之後爲數組中的每一項註冊處理函數:
for(i = 0; i < sizeof (TableOfVmxExits) / sizeof (ULONG32); i++) {
if (!NT_SUCCESS (Status =TrInitializeGeneralTrap (Cpu, TableOfVmxExits[i], 0, // length of the instruction, 0 meanslength need to be get from vmcs later.
VmxDispatchVmxInstrDummy, &Trap))) {
_KdPrint (("VmxRegisterTraps():Failed to register VmxDispatchVmon with status 0x%08hX\n", Status));
return Status;
}
TrRegisterTrap (Cpu, Trap);
}
但註冊的處理函數爲VmxDispatchVmxInstrDummy。
進行的修改是:
將兩個EXIT_REASON_VMCALL衝上述數組中刪除。
在下面單獨爲其註冊處理函數:
if(!NT_SUCCESS(Status = TrInitializeGeneralTrap(Cpu, EXIT_REASON_VMCALL, 0, //length of the instruction, 0 means length need to be get from vmcs later.
HcDispatchHypercall, &Trap))) {
_KdPrint(("VmxRegisterTraps(): Failed to register VmxDispatchCpuidwith status 0x%08hX\n", Status));
return Status;
}
TrRegisterTrap(Cpu, Trap);
如此就可以成功卸載了。