VT笔记(2)突破patchguard保护完成X64Hook

85 篇文章 6 订阅
83 篇文章 9 订阅

win10,2018新年版后好像不支持了?

MSR hook

MSR (Model Specific Registers)是CPU 的一组64 位寄存器,可以分别通过RDMSR 和WRMSR 两条指令进行读和写的操作,前提要在ECX 中写入MSR 的地址(MSR地址就像一个宏STAR,LSTAR,CSTAR,SFMASK)。对于RDMSR 指令,将会返回相应的MSR 中64bit 信息到(EDX:EAX)寄存器中;对于WRMSR 指令,把要写入的信息存入(EDX:EAX)中,执行写指令后,即可将相应的信息存入ECX 指定的MSR 中。MSR 的指令必须执行在level 0 或实模式下。

MSR 总体来是为了设置CPU 的工作环境和标示CPU 的工作状态,包括温度控制,性能监控等,具体来说,分为以下几项:
1. Thermal
2. Frequency
3. C State
4. Microcode
5. EIST
6. TM
7. Key Features Of CPU
8. Voltage
9. Cache Control
10. MTRR
11. DCA(Direct Cache Access)
12. Machine Check
13. 硬件联机控制
14.other

其中MSR_LSTAR里存放着SYSCALL调用的KiSystemCall64的地址。(从应用层到内核层调用的函数,x86的kifastcall),所以我们可以把这个位置的函数通过WRMSR替换,就可以替换SSDT表,然后就实现了X64hook。因为如果直接修改,不经过VT,patchguard会定期检查这里,所以使用VT修改欺骗。当RDMSR会引发exit事件,被VT捕获,VT可以把原来的值给回去。

所以X64HOOk的流程是先做业务流程的x64hook(SSDTHOOK),在VT上hookMSR。此外还要禁用WRMSR,防止别人替换。

X64上syscall流程

NTXXX Ntdll.dll

-》syscall(快速系统调用,intelx用sysenter和sysexit,amd:syscall,SYSRETURN)

-》去msr_lstar地址调用KisystemCall64

-》去KiSystemServiceStart

-》  KiSystemServiceRepeat,通过r10(函数地址),rax(参数个数)来调用SSDT表中的函数。

所以我们急速要替换KisystemCall64,所以我们也要去找到KiSystemServiceStart地址,在我们的函数里调用。需要暴力搜索特征码。

SSDTHOOK思路

X86上

拿到ssdt表首地址

拿到函数索引号(函数地址第二个到第五个字节就是索引号,或者可以解析ntdll)

用新的hook函数替换原函数

X64

拿到未导出SSDT,可以通过KiSystemCall64来定位它,这是Syscall时64位程序进入的RIP,可以通过readmsr(0xc0000082)来获取,向下搜索0x100个字节左右就有KeSerciveDescriptorTable和ShadowTable

拿到函数索引号,计算函数地址,索引号不在第一条指令的,在中间,需要反汇编。另外这里索引号也变了,这里ssdt表函数地址是相对于ssdt表首地址的偏移左移了四位,所以计算函数地址,我们需要根据索引号找到ssdt表记录的地址,。右移四位加上ssdt首地址,才是函数地址。即ServiceTableBase+ServiceTableBase[x]>>4

构造自己的SSDT表,并替换SYSCALL入口,进入自己的SSDT表。

 

SSDT索引的计算

X86:&XwXxxxx+1,或者解析ntdll.dll,x64:&XwXxxxx+n,or解析ntdll.dll

可以在函数里找mov eax机器码是B8,后面就是索引号(?如果函数本身就有mov eax呢?)

代码思路

先备份原来的NtSyscallhander=(ULONG64)__readmsr(MSR_LSTAR),(欺骗patchguard用和恢复要用)

writemsr,就是自己写一个kisystemcall64替换msr中msr_lstar中的值

vt exit事件中,欺骗系统的readmsr,并禁止别人再writemsr

那syscall如何不被欺骗,因为syscall不是使用readmr读取这里值,是直接获取msr_lstar中的值,PG才是使用readmsr,readmsr才会陷入vt,所以syscall不会被欺骗。

注意要先hook,再VT,不然readmsr读不到VT值,而且vt对writemsr禁用,所以不能在替换了。所以要先hook。(pg不是试试的),所以卸载时候先关vt,在unhook

代码流程

1.备份NtSyscallhander=(ULONG64)__readmsr(MSR_LSTAR)

2.构造自己的SSDT表数组

SyscallPointTable[4096](HOOK之后的SSDT函数),SyscallHookEnabled[4096](标识对应的索引号有没被我们hook),SyscallParamTable[4096](每个索引号需要的函数参数个数)

3.提供汇编版的SyscallEntryPoint(GuestSyscallHandler,用来替换原来的KisystemCall64),所以

原来函数走kisystemcall64-》kisystemservicestart-》kisystemservicerepeat-》oldssdt

现在函数走syscallentrypoint-》kisystemcall64_Emulate->kisystemservicestart_Emulate->kisystemServiceReat(暴力搜索r10,rax确定函数地址,参数)-》syscallpointtable(newssdt)

4.__writemsr(MSR_LSTAR,GuestSyscallHandler),完成替换,开启vt

5.在readmsr的vt exit事件中,返回备份的NtSyscallHandler,欺骗系统,禁用writemsr。

 

 

往VThook框架添加要hook函数

流程

获取函数原型

Nt.c/h 宏定义index和old函数声明,index计算old函数地址计算,封装函数实现

Ssdt.c/ssdt.h(hook函数实现)

hook.c 导入index变量,addServicecallHook,removeServiceCallHook。

以NtCreateSection为例

__kernel_entry NTSYSCALLAPI NTSTATUS NtCreateSection(
  PHANDLE            SectionHandle,
  ACCESS_MASK        DesiredAccess,
  POBJECT_ATTRIBUTES ObjectAttributes,
  PLARGE_INTEGER     MaximumSize,
  ULONG              SectionPageProtection,
  ULONG              AllocationAttributes,
  HANDLE             FileHandle
);

现在nt.c中添加

ECL_NT(VtNtCreateSection,
		OUT PHANDLE				SectionHandle,
		IN ULONG                DesiredAccess,
		IN POBJECT_ATTRIBUTES   ObjectAttributes OPTIONAL,
		IN PLARGE_INTEGER       MaximumSize OPTIONAL,
		IN ULONG                PageAttributess,
		IN ULONG                SectionAttributes,
		IN HANDLE               FileHandle OPTIONAL);

在InitializeSection里加上获取ntcreatesection索引号

 

NTSTATUS InitializeSSDTHook()
{
	if (GetSSDTFunctionIndex((ULONG_PTR)&ZwClose, &IdVtNtClose) && 
		GetSSDTFunctionIndex((ULONG_PTR)&ZwOpenSection, &IdVtNtOpenSection)&&
		GetSSDTFunctionIndex((ULONG_PTR)&ZwCreateFile, &IdVtNtCreateFile) &&
		GetSSDTFunctionIndex((ULONG_PTR)&ZwCreateSection,&IdVtNtCreateSection))
		{
			KdPrint(("get index ok"));
		}
		else
		{
			KdPrint(("get index failed"));
			return STATUS_UNSUCCESSFUL;
		}

		*(ULONG_PTR *)&pVtNtClose						= GetSSDTEntry(IdVtNtClose);//pVtNtClose original address
		*(ULONG_PTR *)&pVtNtOpenSection					= GetSSDTEntry(IdVtNtOpenSection);
		*(ULONG_PTR *)&pVtNtCreateFile = GetSSDTEntry(IdVtNtCreateFile);
		*(ULONG_PTR *)&pVtNtCreateSection = GetSSDTEntry(IdVtNtCreateSection);

		if (!pVtNtClose || !pVtNtOpenSection || !pVtNtCreateFile || !pVtNtCreateSection)
			return STATUS_UNSUCCESSFUL;

		return STATUS_SUCCESS;
	}

然后比照之前函数包装一个相应函数,这个是用于放行的

NTSTATUS NTAPI VtNtCreateSection(
	OUT PHANDLE        SectionHandle,
	IN ULONG                DesiredAccess,
	IN POBJECT_ATTRIBUTES     ObjectAttributes OPTIONAL,
	IN PLARGE_INTEGER              MaximumSize OPTIONAL,
	IN ULONG                PageAttributess,
	IN ULONG                SectionAttributes,
	IN HANDLE                               FileHandle OPTIONAL)
{
		KdPrint(("NtCreateSection called\n"));
		return pVtNtCreateSection(
			SectionHandle,
			DesiredAccess,
			ObjectAttributes,
			MaximumSize,
			PageAttributess,
			SectionAttributes,
			FileHandle);
}

 

在nt.h加上这个函数,用于其他模块调用

NTSTATUS NTAPI VtNtCreateSection(
	OUT PHANDLE        SectionHandle,
	IN ULONG                DesiredAccess,
	IN POBJECT_ATTRIBUTES     ObjectAttributes OPTIONAL,
	IN PLARGE_INTEGER              MaximumSize OPTIONAL,
	IN ULONG                PageAttributess,
	IN ULONG                SectionAttributes,
	IN HANDLE                               FileHandle OPTIONAL);

 

然后在ssdt.h/c添加相应函数,实现新的hook

ssdt.c

NTSTATUS  hk_NtCreateSection(
	OUT PHANDLE        SectionHandle,
	IN ULONG                DesiredAccess,
	IN POBJECT_ATTRIBUTES     ObjectAttributes OPTIONAL,
	IN PLARGE_INTEGER              MaximumSize OPTIONAL,
	IN ULONG                PageAttributess,
	IN ULONG                SectionAttributes,
	IN HANDLE                               FileHandle OPTIONAL)
{
	KdPrint(("NtCreateSection called\n"));
	return VtNtCreateSection(
		SectionHandle,
		DesiredAccess,
		ObjectAttributes,
		MaximumSize,
		PageAttributess,
		SectionAttributes,
		FileHandle);

}

ssdt.h

NTSTATUS NTAPI hk_NtCreateSection(
	OUT PHANDLE        SectionHandle,
	IN ULONG                DesiredAccess,
	IN POBJECT_ATTRIBUTES     ObjectAttributes OPTIONAL,
	IN PLARGE_INTEGER              MaximumSize OPTIONAL,
	IN ULONG                PageAttributess,
	IN ULONG                SectionAttributes,
	IN HANDLE                               FileHandle OPTIONAL);

修改hook.c

导入id

extern UINT32 IdVtNtCreateSection;

函数 ServiceCallInitialize()里添加

AddServiceCallHook(IdVtNtCreateSection, 7, (PVOID)&hk_NtCreateSection);


NTSTATUS ServiceCallUnload()添加

RemoveServiceCallHook(IdVtNtCreateSection);

发现一家hook成功,但是pchunter没有发现钩子,已达成vt欺骗。

EPThook

原理:如果GuestPA转HostPA期间发生权限异常,客户机发生VmExit事件
,控制权回到宿主机手中(设置guesttrip,调到hook函数等),优点是无痕,缺点是控制粒度大,影响性能。

可以去单页权限控制,去执行权限,取消原函数所在物理页对应的物理扩展页表PTE执行权限,当执行到该函数的时候翻书异常,判断发生溢出的线性地址是否是HOOK函数位置,如果是恢复可执行权限,将客户机RIP寄存器设置为hook函数地址,设置MTF标志,以便返回到客户机执行完这几指令之后返回到宿主机中将该物理页可执行权限去除。(MTFMonitor trap flag,用来做程序调试的)

或者双页权限互斥(读写和执行权限分离),

总之VT下可以有针对内存读写的事件回调,也就是访问内存时(读写执行),会陷入到根模式,此时做处理自然就可以了 。

 

 

 

  • 6
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: x64dbg是一款功能强大的开源调试工具,它可以用于分析和调试32位和64位应用程序。而vt过驱动保护(Virtualization Technology-based code protection)是一种基于虚拟化技术的代码保护方法。 在使用x64dbg进行分析和调试时,有时会遇到一些应用程序使用了驱动程序进行保护,这些驱动程序可以实现对应用程序的安全保护,例如防止被调试、反反调试等。这时,我们需要绕过这些驱动程序的保护,以便更好地进行分析和调试。 x64dbg vt过驱动保护是指通过虚拟化技术来绕过驱动程序的保护。它的原理是在物理机上构建一个虚拟环境,将应用程序和保护驱动程序都运行在虚拟环境中进行分析和调试。通过虚拟化技术,我们可以对驱动程序的行为进行分析,找出其保护的特征和机制,进而绕过它们。 具体实现vt过驱动保护的步骤大致如下: 1. 寻找应用程序中使用的保护驱动程序; 2. 对驱动程序进行虚拟化处理,将其加载到虚拟环境中; 3. 运行虚拟环境,并将目标应用程序加载到虚拟环境中; 4. 在虚拟环境中使用x64dbg进行分析和调试。 通过vt过驱动保护,我们可以绕过驱动程序的防护,实现对应用程序的深入分析和调试。但需要注意的是,vt过驱动保护仅用于研究和教育目的,使用时需遵守法律法规,并且尊重软件的使用许可协议。 ### 回答2: x64dbg vt过驱动保护是指在使用x64dbg调试工具时,如何绕过或者应对针对驱动的保护机制。 在调试驱动程序时,为了防止恶意用户通过调试工具对驱动程序进行逆向工程、解密或修改等操作,开发者通常会加入一些保护机制,如反调试技术。 针对这些保护机制,可以通过以下方式进行绕过或应对: 1. 使用反反调试插件:x64dbg支持使用插件扩展功能,可以通过安装一些专门的反反调试插件来对抗驱动的反调试机制。 2. 分析并修改驱动代码:通过仔细分析驱动程序的代码,了解其中的保护机制实现方式,并进行必要的修改,以绕过或应对这些保护措施。 3. 使用虚拟机调试:在虚拟机环境中调试驱动程序,因为虚拟机对调试工具的防护相对较弱,可以更轻松地进行调试和分析。 4. Hook相关API函数:通过在调试程序中hook一些与保护相关的API函数,可以改变这些API函数的行为,使得驱动程序无法检测到调试环境。 5. 使用其他调试工具:x64dbg是一款强大的调试工具,但并不是唯一选择。根据需要,可以尝试其他调试工具,寻找更适合绕过驱动保护的工具。 绕过或应对驱动保护是一项技术挑战,需要有一定的反汇编和逆向工程知识。在进行任何操作前,请确保遵守法律法规,并仅在合法授权的范围内使用这些技术。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值