亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何實現基于虛擬化的HIPS架構

發布時間:2021-10-14 13:34:06 來源:億速云 閱讀:176 作者:iii 欄目:編程語言

本篇內容介紹了“如何實現基于虛擬化的HIPS架構”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

1.準備工作

首先我們要確保SVM是否是支持的:
如何實現基于虛擬化的HIPS架構這是萬事開頭

之后分配VCPU結構區域跟上篇文章一樣,我這邊直接拿了上次的文章的代碼,

如何實現基于虛擬化的HIPS架構

唯一不同的是,vcpu區域多了這些

如何實現基于虛擬化的HIPS架構

relative_hvm相當于一個全局變量,這部分我是參考zero-tang的noir虛擬機,我會在文末放參考資料

guest_vmcb和host_state是重要的信息,分別代表:

用戶的VMCB區域(intel是叫做VMCS),主機的狀態(AMD用一個msr叫做VM_HSAVE_PA來放主機狀態的)

他們大小都是一個page_size

如何實現基于虛擬化的HIPS架構

順便一提vmcb的結構是這樣的:
如何實現基于虛擬化的HIPS架構由_vmcb_control_area和_vmcb_state_save_area結構控制,結構如下:

typedef struct _vmcb_control_area
{
	UINT16 InterceptCrRead;             // +0x000
	UINT16 InterceptCrWrite;            // +0x002
	UINT16 InterceptDrRead;             // +0x004
	UINT16 InterceptDrWrite;            // +0x006
	UINT32 InterceptException;          // +0x008
	UINT32 InterceptMisc1;              // +0x00c
	UINT32 InterceptMisc2;              // +0x010
	UINT8 Reserved1[0x03c - 0x014];     // +0x014
	UINT16 PauseFilterThreshold;        // +0x03c
	UINT16 PauseFilterCount;            // +0x03e
	UINT64 IopmBasePa;                  // +0x040
	UINT64 MsrpmBasePa;                 // +0x048
	UINT64 TscOffset;                   // +0x050
	UINT32 GuestAsid;                   // +0x058
	UINT32 TlbControl;                  // +0x05c
	UINT64 VIntr;                       // +0x060
	UINT64 InterruptShadow;             // +0x068
	UINT64 ExitCode;                    // +0x070
	UINT64 ExitInfo1;                   // +0x078
	UINT64 ExitInfo2;                   // +0x080
	UINT64 ExitIntInfo;                 // +0x088
	UINT64 NpEnable;                    // +0x090
	UINT64 AvicApicBar;                 // +0x098
	UINT64 GuestPaOfGhcb;               // +0x0a0
	UINT64 EventInj;                    // +0x0a8
	UINT64 NCr3;                        // +0x0b0
	UINT64 LbrVirtualizationEnable;     // +0x0b8
	UINT64 VmcbClean;                   // +0x0c0
	UINT64 NRip;                        // +0x0c8
	UINT8 NumOfBytesFetched;            // +0x0d0
	UINT8 GuestInstructionBytes[15];    // +0x0d1
	UINT64 AvicApicBackingPagePointer;  // +0x0e0
	UINT64 Reserved2;                   // +0x0e8
	UINT64 AvicLogicalTablePointer;     // +0x0f0
	UINT64 AvicPhysicalTablePointer;    // +0x0f8
	UINT64 Reserved3;                   // +0x100
	UINT64 VmcbSaveStatePointer;        // +0x108
	UINT8 Reserved4[0x400 - 0x110];     // +0x110
};
static_assert(sizeof(_vmcb_control_area) == 0x400, "size check");
typedef struct _vmcb_state_save_area
{
	UINT16 EsSelector;                  // +0x000
	UINT16 EsAttrib;                    // +0x002
	UINT32 EsLimit;                     // +0x004
	UINT64 EsBase;                      // +0x008
	UINT16 CsSelector;                  // +0x010
	UINT16 CsAttrib;                    // +0x012
	UINT32 CsLimit;                     // +0x014
	UINT64 CsBase;                      // +0x018
	UINT16 SsSelector;                  // +0x020
	UINT16 SsAttrib;                    // +0x022
	UINT32 SsLimit;                     // +0x024
	UINT64 SsBase;                      // +0x028
	UINT16 DsSelector;                  // +0x030
	UINT16 DsAttrib;                    // +0x032
	UINT32 DsLimit;                     // +0x034
	UINT64 DsBase;                      // +0x038
	UINT16 FsSelector;                  // +0x040
	UINT16 FsAttrib;                    // +0x042
	UINT32 FsLimit;                     // +0x044
	UINT64 FsBase;                      // +0x048
	UINT16 GsSelector;                  // +0x050
	UINT16 GsAttrib;                    // +0x052
	UINT32 GsLimit;                     // +0x054
	UINT64 GsBase;                      // +0x058
	UINT16 GdtrSelector;                // +0x060
	UINT16 GdtrAttrib;                  // +0x062
	UINT32 GdtrLimit;                   // +0x064
	UINT64 GdtrBase;                    // +0x068
	UINT16 LdtrSelector;                // +0x070
	UINT16 LdtrAttrib;                  // +0x072
	UINT32 LdtrLimit;                   // +0x074
	UINT64 LdtrBase;                    // +0x078
	UINT16 IdtrSelector;                // +0x080
	UINT16 IdtrAttrib;                  // +0x082
	UINT32 IdtrLimit;                   // +0x084
	UINT64 IdtrBase;                    // +0x088
	UINT16 TrSelector;                  // +0x090
	UINT16 TrAttrib;                    // +0x092
	UINT32 TrLimit;                     // +0x094
	UINT64 TrBase;                      // +0x098
	UINT8 Reserved1[0x0cb - 0x0a0];     // +0x0a0
	UINT8 Cpl;                          // +0x0cb
	UINT32 Reserved2;                   // +0x0cc
	UINT64 Efer;                        // +0x0d0
	UINT8 Reserved3[0x148 - 0x0d8];     // +0x0d8
	UINT64 Cr4;                         // +0x148
	UINT64 Cr3;                         // +0x150
	UINT64 Cr0;                         // +0x158
	UINT64 Dr7;                         // +0x160
	UINT64 Dr6;                         // +0x168
	UINT64 Rflags;                      // +0x170
	UINT64 Rip;                         // +0x178
	UINT8 Reserved4[0x1d8 - 0x180];     // +0x180
	UINT64 Rsp;                         // +0x1d8
	UINT8 Reserved5[0x1f8 - 0x1e0];     // +0x1e0
	UINT64 Rax;                         // +0x1f8
	UINT64 Star;                        // +0x200
	UINT64 LStar;                       // +0x208
	UINT64 CStar;                       // +0x210
	UINT64 SfMask;                      // +0x218
	UINT64 KernelGsBase;                // +0x220
	UINT64 SysenterCs;                  // +0x228
	UINT64 SysenterEsp;                 // +0x230
	UINT64 SysenterEip;                 // +0x238
	UINT64 Cr2;                         // +0x240
	UINT8 Reserved6[0x268 - 0x248];     // +0x248
	UINT64 GPat;                        // +0x268
	UINT64 DbgCtl;                      // +0x270
	UINT64 BrFrom;                      // +0x278
	UINT64 BrTo;                        // +0x280
	UINT64 LastExcepFrom;               // +0x288
	UINT64 LastExcepTo;                 // +0x290
};
static_assert(sizeof(_vmcb_state_save_area) == 0x298, "size check");

這個結構很關鍵.不要隨便亂動

2. 初始化SVM

我們一樣用我們的DPC Callback讓我們每個核心處理器都同步執行這些代碼

如何實現基于虛擬化的HIPS架構

init_logical_processor的邏輯非常簡單

首先你必須要給msr的amd64_efer(0xC0000080)增加一個amd64_efer_svme_bit(0x1000)

如何實現基于虛擬化的HIPS架構

其次你要操作你要攔截的msr的列表,不設置的話我們沒辦法攔截到特定的msr的中斷:

跟AMD白皮書里面寫的一樣

----
                    Secure Virtual Machine Enable (SVME) Bit
                    Bit 12, read/write. Enables the SVM extensions. (...) The
                    effect of turning off EFER.SVME while a guest is running is
                    undefined; therefore, the VMM should always prevent guests
                    from writing EFER.
                    ----
                    Each MSR is controlled by two bits in the MSRPM. The LSB of
                    the two bits controls read access to the MSR and the MSB
                    controls write access. A value of 1 indicates that the
                    operation is intercepted. This function locates an offset for
                    IA32_MSR_EFER and sets the MSB bit. For details of logic, see
                    "MSR Intercepts".

這就是為啥之前用g_relative_hvm的原因,這些全局變量放一個結構里面就行

https://github.com/tandasat/SimpleSvm/blob/b3591f74b3d893c4f82348fe7157f037c5d70b5e/SimpleSvm/SimpleSvm.cpp#L1465

第三步,設置guest_vmcb

Amd CPU的SVM不同于Intel VT-X 他的進入vm的方式是vmrun guest_vmcb

而不是intel VT-X的 _write_vmcs(這一點AMD NO)

所以我們要設置一下這個重要參數

基本上 就是一些寄存器信息

vcpu->guest_vmcb->state_save.CsSelector = state_p.cs.selector;
	vcpu->guest_vmcb->state_save.CsAttrib = svm_attrib(state_p.cs.attrib);
	vcpu->guest_vmcb->state_save.CsLimit = state_p.cs.limit;
	vcpu->guest_vmcb->state_save.CsBase = state_p.cs.base;

	vcpu->guest_vmcb->state_save.DsSelector = state_p.cs.selector;
	vcpu->guest_vmcb->state_save.DsAttrib = svm_attrib(state_p.ds.attrib);
	vcpu->guest_vmcb->state_save.DsLimit = state_p.ds.limit;
	vcpu->guest_vmcb->state_save.DsBase = state_p.ds.base;

	vcpu->guest_vmcb->state_save.EsSelector = state_p.es.selector;
	vcpu->guest_vmcb->state_save.EsAttrib = svm_attrib(state_p.es.attrib);
	vcpu->guest_vmcb->state_save.EsLimit = state_p.es.limit;
	vcpu->guest_vmcb->state_save.EsBase = state_p.es.base;

	vcpu->guest_vmcb->state_save.FsSelector = state_p.fs.selector;
	vcpu->guest_vmcb->state_save.FsAttrib = svm_attrib(state_p.fs.attrib);
	vcpu->guest_vmcb->state_save.FsLimit = state_p.fs.limit;
	vcpu->guest_vmcb->state_save.FsBase = state_p.fs.base;

	vcpu->guest_vmcb->state_save.GsSelector = state_p.gs.selector;
	vcpu->guest_vmcb->state_save.GsAttrib = svm_attrib(state_p.gs.attrib);
	vcpu->guest_vmcb->state_save.GsLimit = state_p.gs.limit;
	vcpu->guest_vmcb->state_save.GsBase = state_p.gs.base;

	vcpu->guest_vmcb->state_save.SsSelector = state_p.ss.selector;
	vcpu->guest_vmcb->state_save.SsAttrib = svm_attrib(state_p.ss.attrib);
	vcpu->guest_vmcb->state_save.SsLimit = state_p.ss.limit;
	vcpu->guest_vmcb->state_save.SsBase = state_p.ss.base;

	vcpu->guest_vmcb->state_save.TrSelector = state_p.tr.selector;
	vcpu->guest_vmcb->state_save.TrAttrib = svm_attrib(state_p.tr.attrib);
	vcpu->guest_vmcb->state_save.TrLimit = state_p.tr.limit;
	vcpu->guest_vmcb->state_save.TrBase = state_p.tr.base;
	//gdtr
	vcpu->guest_vmcb->state_save.GdtrBase = state_p.gdtr.base;
	vcpu->guest_vmcb->state_save.GdtrLimit = state_p.gdtr.limit;
	//idtr
	vcpu->guest_vmcb->state_save.IdtrLimit = state_p.idtr.limit;
	vcpu->guest_vmcb->state_save.IdtrBase = state_p.idtr.base;
	//ldtr
	vcpu->guest_vmcb->state_save.LdtrSelector = state_p.ldtr.selector;
	vcpu->guest_vmcb->state_save.LdtrAttrib = svm_attrib(state_p.ldtr.attrib);
	vcpu->guest_vmcb->state_save.LdtrLimit = state_p.ldtr.limit;
	vcpu->guest_vmcb->state_save.LdtrBase = state_p.ldtr.base;
	//cr
	vcpu->guest_vmcb->state_save.Cr0 = state_p.cr0;
	vcpu->guest_vmcb->state_save.Cr2 = state_p.cr2;
	vcpu->guest_vmcb->state_save.Cr3 = state_p.cr3;
	vcpu->guest_vmcb->state_save.Cr4 = state_p.cr4;
	// Save Debug Registers
	vcpu->guest_vmcb->state_save.Dr6 = state_p.dr6;
	vcpu->guest_vmcb->state_save.Dr7 = state_p.dr7;
	vcpu->guest_vmcb->state_save.Rflags = 2;

	vcpu->guest_vmcb->state_save.Rsp = vcpu->context_frame.Rsp;
	vcpu->guest_vmcb->state_save.Rip = vcpu->context_frame.Rip;
	vcpu->guest_vmcb->state_save.GPat = state_p.pat;
	vcpu->guest_vmcb->state_save.Efer = state_p.efer;
	vcpu->guest_vmcb->state_save.Star = state_p.star;
	vcpu->guest_vmcb->state_save.CStar = state_p.cstar;
	vcpu->guest_vmcb->state_save.SfMask = state_p.sfmask;
	vcpu->guest_vmcb->state_save.GsBase = state_p.gsswap;

然后是關鍵的IopmBasePa、MsrpmBasePa,這兩個要指向我們的relative_hvm所設置的東西(作用攔截msr中斷)

vcpu->guest_vmcb->control.IopmBasePa = vcpu->relative_hvm->iopm.physical_address;
	vcpu->guest_vmcb->control.MsrpmBasePa = vcpu->relative_hvm->msr_bitmap.physical_address;

最后是GuestAsid,這個東西全稱"Specify guest's address space ID" 我們要做到是頂級top level虛擬機,所以設置1就行

具體可以看amd的白皮書的"CPUID Fn8000_000A_EBX SVM Revision and Feature Identification" 這一章介紹

最后最后一步,設置我們要處理的vmexit事件:

結構如下:

typedef union _svm_instruction_intercept1
{
	struct
	{
		unsigned __int32 intercept_intr : 1;
		unsigned __int32 intercept_nmi : 1;
		unsigned __int32 intercept_smi : 1;
		unsigned __int32 intercept_init : 1;
		unsigned __int32 intercept_vint : 1;
		unsigned __int32 intercept_cr0_tsmp : 1;
		unsigned __int32 intercept_sidt : 1;
		unsigned __int32 intercept_sgdt : 1;
		unsigned __int32 intercept_sldt : 1;
		unsigned __int32 intercept_str : 1;
		unsigned __int32 intercept_lidt : 1;
		unsigned __int32 intercept_lgdt : 1;
		unsigned __int32 intercept_lldt : 1;
		unsigned __int32 intercept_ltr : 1;
		unsigned __int32 intercept_rdtsc : 1;
		unsigned __int32 intercept_rdpmc : 1;
		unsigned __int32 intercept_pushf : 1;
		unsigned __int32 intercept_popf : 1;
		unsigned __int32 intercept_cpuid : 1;
		unsigned __int32 intercept_rsm : 1;
		unsigned __int32 intercept_iret : 1;
		unsigned __int32 intercept_int : 1;
		unsigned __int32 intercept_invd : 1;
		unsigned __int32 intercept_pause : 1;
		unsigned __int32 intercept_hlt : 1;
		unsigned __int32 intercept_invlpg : 1;
		unsigned __int32 intercept_invlpga : 1;
		unsigned __int32 intercept_io : 1;
		unsigned __int32 intercept_msr : 1;
		unsigned __int32 intercept_task_switch : 1;
		unsigned __int32 intercept_ferr_freeze : 1;
		unsigned __int32 intercept_shutdown : 1;
	};
	unsigned __int32 value;
}svm_instruction_intercept1, * svm_instruction_intercept1_p;

typedef union _nvc_svm_instruction_intercept2
{
	struct
	{
		unsigned __int16 intercept_vmrun : 1;
		unsigned __int16 intercept_vmmcall : 1;
		unsigned __int16 intercept_vmload : 1;
		unsigned __int16 intercept_vmsave : 1;
		unsigned __int16 intercept_stgi : 1;
		unsigned __int16 intercept_clgi : 1;
		unsigned __int16 intercept_skinit : 1;
		unsigned __int16 intercept_rdtscp : 1;
		unsigned __int16 intercept_icebp : 1;
		unsigned __int16 intercept_wbinvd : 1;
		unsigned __int16 intercept_monitor : 1;
		unsigned __int16 intercept_mwait : 1;
		unsigned __int16 intercept_mwait_c : 1;
		unsigned __int16 intercept_xsetbv : 1;
		unsigned __int16 reserved1 : 1;
		unsigned __int16 intercept_post_efer_write : 1;
	};
	unsigned __int16 value;
}svm_instruction_intercept2, * svm_instruction_intercept2_p;

設置guest_vmcb的control字段來控制我們接受什么vmexit事件:

void svm::svm_setup_control_area(_vcpu_t* vcpu)
{
	svm_instruction_intercept1 intercept_misc_1;
	svm_instruction_intercept2 intercept_misc_2;
	intercept_misc_1.value = 0;
	intercept_misc_1.intercept_msr = 1; //中斷msr
	intercept_misc_1.intercept_rdtsc = 1;// 中斷rdtsc
	intercept_misc_2.value = 0;
	intercept_misc_2.intercept_vmrun = 1; //中斷vmrun
	intercept_misc_2.intercept_vmmcall = 1;//中斷vmcall
	intercept_misc_2.intercept_rdtscp = 1;//中斷rdtscp
	vcpu->guest_vmcb->control.InterceptMisc1 = intercept_misc_1.value;
	vcpu->guest_vmcb->control.InterceptMisc2 = intercept_misc_2.value;
}

保存我們的guest_vmcb

__svm_vmsave(vcpu->guest_vmcb_physical_address);

指定host機狀態存放位置(通過amd64_hsave_pa這個msr來控制區域(AMD挺迷惑的,為什么要用一個寄存器來存放host狀態而不是intel的VMCS)):

__svm_vmsave(vcpu->host_state_physical_address);
	__writemsr(amd64_hsave_pa, vcpu->host_state_physical_address);

3. 進入SVM

一切就緒后,在vm stack上開辟一個空間,用來給我們的vmexit_handler函數傳值:

_svm_initial_stack_p stack = (_svm_initial_stack_p)((uintptr_t)vcpu->stack + _stack_size - sizeof(_svm_initial_stack));
	stack->guest_vmcb_pa = svm::svm_set_vmcb(vcpu);
	stack->vcpu = vcpu;
	stack->proc_id = processor_number;
	launch_svm(stack);
	__debugbreak();
	return false;

還記得匯編中X64傳參嗎?

從左到右四個參數傳遞是RCX,RDX,R8,R9, 其余在RSP里面傳參

返回信息寄存器是RAX

知道這些,我們就可以寫launch_svm了:

這里有個坑是360的一個cc大佬提醒的我加上看了看zero tang的代碼才想到

就是svm的要切CR3,因為默認的驅動啟動是掛靠在進程里面的,訪問線性地址會炸,必須要切換成系統的CR3才行.之前被這個坑搞了好久,現在才搞定

INTEL VTX的沒這個問題,因為intel的VTX是在vmcs區域里面就指定了host cr3

如何實現基于虛擬化的HIPS架構

如何實現基于虛擬化的HIPS架構

核心思想就是,vmrun guest_vmcb后,就已經到guest機里面了,這個時候就要等待vmrun執行結束,vmrun結束后就是host機區域,就可以操作我們的vmexit_handler,在進vmexit_handler之前,要用vmsave保存一次vmcb的情況

這邊給的參數1是棧,參數2是當前cpu的number 我們試試

如何實現基于虛擬化的HIPS架構

如何實現基于虛擬化的HIPS架構

good 成功進入vmexit_handler

“如何實現基于虛擬化的HIPS架構”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

安吉县| 贵溪市| 上蔡县| 明星| 玛多县| 勐海县| 榕江县| 新密市| 托克逊县| 襄汾县| 阜康市| 营山县| 西乌珠穆沁旗| 古交市| 叶城县| 突泉县| 陆河县| 蓬安县| 和硕县| 永平县| 应用必备| 吴桥县| 台东市| 故城县| 邯郸县| 北票市| 基隆市| 哈密市| 东兰县| 赤壁市| 牡丹江市| 马鞍山市| 蛟河市| 甘泉县| 白山市| 都兰县| 松溪县| 景谷| 万安县| 德清县| 民乐县|