基于windows的内存分页机制,进程间的隔离让我们无法直接读写其他进程的地址空间,又因为copy on write让我们即使patch了系统dll也无法影响其他进程。但是这一根内存条就插在主板上,就不能有个方法能看到内容么? 在裸机上如果没有定制的外设是无解了,但是在虚拟化的框架下,这一切都显得再正常不过。
在虚拟化的框架下,客户机的“内存条”实际上是宿主机上申请的一段普通内存,如果我们能够找到GVA与HVA之间的映射关系,就可以绕开任何限制,直接在宿主机上读写任意位置的客户机内存。
我们先暂停vm后,通过KVM_GET_SREGS即可获取cr3寄存器。
gs寄存器在R0下存放的是KPCR,在R3下存放的是TEB
通过偏移计算KTHREAD->KPROCESS->EPROCESS->active_process_links获得这个进程双链表结构,通过遍历active_process_links我们可以获取当前系统所有进程,包括每个进程的CR3。
关于windows的分页机制,文档很多不赘述直接贴出部分代码
在能够获取所有进程cr3后,加上页表解析,可以轻松的在host上读写任意guest内存。当我们尝试在host抹掉guest进程notepad中的ntdll的PE头后,由于系统dll的特殊性加上直接修改了物理内存,系统也随之陷入一片混乱
54cK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6@1k6h3&6U0L8r3q4K6M7#2)9J5c8X3#2$3K9i4y4G2M7R3`.`. 使用右ctrl+F8唤起debug窗口,目前仅支持win10 guest。
machine_->Pause();
bool success = false;
for (auto vcpu : machine_->vcpus()) {
struct kvm_sregs sregs;
if (ioctl(vcpu->fd(), KVM_GET_SREGS, &sregs) < 0)
MV_PANIC("KVM_GET_REGS failed");
...
machine_->Pause();
bool success = false;
for (auto vcpu : machine_->vcpus()) {
struct kvm_sregs sregs;
if (ioctl(vcpu->fd(), KVM_GET_SREGS, &sregs) < 0)
MV_PANIC("KVM_GET_REGS failed");
...
...
if ((sregs.cs.base & 3) != 0) {
MV_LOG("current vcpu=%d is in usermode", vcpu->vcpu_id());
continue;
}
auto kpcr = (uint8_t*)GuestVAToHostAddress((uint64_t)sregs.gs.base, sregs.cr3);
...
...
if ((sregs.cs.base & 3) != 0) {
MV_LOG("current vcpu=%d is in usermode", vcpu->vcpu_id());
continue;
}
auto kpcr = (uint8_t*)GuestVAToHostAddress((uint64_t)sregs.gs.base, sregs.cr3);
...
//0xb080 bytes (sizeof)
struct _KPCR
{
union
{
struct _NT_TIB NtTib; //0x0
struct
{
union _KGDTENTRY64* GdtBase; //0x0
struct _KTSS64* TssBase; //0x8
ULONGLONG UserRsp; //0x10
struct _KPCR* Self; //0x18
struct _KPRCB* CurrentPrcb; //0x20
struct _KSPIN_LOCK_QUEUE* LockArray; //0x28
VOID* Used_Self; //0x30
};
};
union _KIDTENTRY64* IdtBase; //0x38
ULONGLONG Unused[2]; //0x40
UCHAR Irql; //0x50
UCHAR SecondLevelCacheAssociativity; //0x51
UCHAR ObsoleteNumber; //0x52
UCHAR Fill0; //0x53
ULONG Unused0[3]; //0x54
USHORT MajorVersion; //0x60
USHORT MinorVersion; //0x62
ULONG StallScaleFactor; //0x64
VOID* Unused1[3]; //0x68
ULONG KernelReserved[15]; //0x80
ULONG SecondLevelCacheSize; //0xbc
ULONG HalReserved[16]; //0xc0
ULONG Unused2; //0x100
VOID* KdVersionBlock; //0x108
VOID* Unused3; //0x110
ULONG PcrAlign1[24]; //0x118
struct _KPRCB Prcb; //0x180
};
//0x700 bytes (sizeof)
struct _KPRCB
{
ULONG MxCsr; //0x0
UCHAR LegacyNumber; //0x4
UCHAR ReservedMustBeZero; //0x5
UCHAR InterruptRequest; //0x6
UCHAR IdleHalt; //0x7
struct _KTHREAD* CurrentThread; //0x8
struct _KTHREAD* NextThread; //0x10
struct _KTHREAD* IdleThread; //0x18
UCHAR NestingLevel; //0x20
UCHAR ClockOwner; //0x21
union
{
UCHAR PendingTickFlags; //0x22
struct
{
UCHAR PendingTick:1; //0x22
UCHAR PendingBackupTick:1; //0x22
};
};
UCHAR IdleState; //0x23
ULONG Number; //0x24
ULONGLONG RspBase; //0x28
ULONGLONG PrcbLock; //0x30
CHAR* PriorityState; //0x38
CHAR CpuType; //0x40
CHAR CpuID; //0x41
union
{
USHORT CpuStep; //0x42
struct
{
UCHAR CpuStepping; //0x42
UCHAR CpuModel; //0x43
};
};
ULONG MHz; //0x44
ULONGLONG HalReserved[8]; //0x48
USHORT MinorVersion; //0x88
USHORT MajorVersion; //0x8a
UCHAR BuildType; //0x8c
UCHAR CpuVendor; //0x8d
UCHAR LegacyCoresPerPhysicalProcessor; //0x8e
UCHAR LegacyLogicalProcessorsPerCore; //0x8f
ULONGLONG TscFrequency; //0x90
ULONG CoresPerPhysicalProcessor; //0x98
ULONG LogicalProcessorsPerCore; //0x9c
ULONGLONG PrcbPad04[4]; //0xa0
struct _KNODE* ParentNode; //0xc0
ULONGLONG GroupSetMember; //0xc8
UCHAR Group; //0xd0
UCHAR GroupIndex; //0xd1
UCHAR PrcbPad05[2]; //0xd2
ULONG InitialApicId; //0xd4
ULONG ScbOffset; //0xd8
ULONG ApicMask; //0xdc
VOID* AcpiReserved; //0xe0
ULONG CFlushSize; //0xe8
ULONGLONG PrcbPad11[2]; //0xf0
struct _KPROCESSOR_STATE ProcessorState; //0x100
struct _XSAVE_AREA_HEADER* ExtendedSupervisorState; //0x6c0
ULONG ProcessorSignature; //0x6c8
ULONG ProcessorFlags; //0x6cc
ULONGLONG PrcbPad12a; //0x6d0
ULONGLONG PrcbPad12[3]; //0x6d8
};
//0xb080 bytes (sizeof)
struct _KPCR
{
union
{
struct _NT_TIB NtTib; //0x0
struct
{
union _KGDTENTRY64* GdtBase; //0x0
struct _KTSS64* TssBase; //0x8
ULONGLONG UserRsp; //0x10
struct _KPCR* Self; //0x18
struct _KPRCB* CurrentPrcb; //0x20
struct _KSPIN_LOCK_QUEUE* LockArray; //0x28
VOID* Used_Self; //0x30
};
};
union _KIDTENTRY64* IdtBase; //0x38
ULONGLONG Unused[2]; //0x40
UCHAR Irql; //0x50
UCHAR SecondLevelCacheAssociativity; //0x51
UCHAR ObsoleteNumber; //0x52
UCHAR Fill0; //0x53
ULONG Unused0[3]; //0x54
USHORT MajorVersion; //0x60
USHORT MinorVersion; //0x62
ULONG StallScaleFactor; //0x64
VOID* Unused1[3]; //0x68
ULONG KernelReserved[15]; //0x80
ULONG SecondLevelCacheSize; //0xbc
ULONG HalReserved[16]; //0xc0
ULONG Unused2; //0x100
VOID* KdVersionBlock; //0x108
VOID* Unused3; //0x110
ULONG PcrAlign1[24]; //0x118
struct _KPRCB Prcb; //0x180
};
//0x700 bytes (sizeof)
struct _KPRCB
{
ULONG MxCsr; //0x0
UCHAR LegacyNumber; //0x4
UCHAR ReservedMustBeZero; //0x5
UCHAR InterruptRequest; //0x6
UCHAR IdleHalt; //0x7
struct _KTHREAD* CurrentThread; //0x8
struct _KTHREAD* NextThread; //0x10
struct _KTHREAD* IdleThread; //0x18
UCHAR NestingLevel; //0x20
UCHAR ClockOwner; //0x21
union
{
UCHAR PendingTickFlags; //0x22
struct
{
UCHAR PendingTick:1; //0x22
UCHAR PendingBackupTick:1; //0x22
};
};
UCHAR IdleState; //0x23
ULONG Number; //0x24
ULONGLONG RspBase; //0x28
ULONGLONG PrcbLock; //0x30
CHAR* PriorityState; //0x38
CHAR CpuType; //0x40
CHAR CpuID; //0x41
union
{
USHORT CpuStep; //0x42
struct
{
UCHAR CpuStepping; //0x42
UCHAR CpuModel; //0x43
};
};
[培训]Windows内核深度攻防:从Hook技术到Rootkit实战!
最后于 2024-9-27 13:39
被Justgoon编辑
,原因: