☰
DMA对抗浅析
2026/10/5 7:19:04 网站建设 项目流程

【1】 出世

本来大家都对抗的好好的你突然用硬件酱味打击这不胡闹吗?galgame里不是这样的,你应该先和我在R3上一决高下最后再在R0打的难舍难分... 相信大家对DMA的工作原理早就有过充分了解所以也不再赘述,非要说就是:

1

2

3

4

5

6

7

8

配置空间(Configuration Space)

CPU 发起 → Root Complex → PCIe TLP(Config) → 设备

用途:枚举设备、分配 BAR、读写能力寄存器

特点:请求者是 CPU,不经过 IOMMU

内存访问(DMA)

设备发起 → PCIe TLP(MemRd/MemWr) → [IOMMU] → 内存控制器 → 物理内存

用途:设备读写系统内存

特点:请求者是设备,IOMMU 启用时经其翻译 (后面要考)

是的就这样,使用DMA可以很轻松的做到任意物理内存读取,写入,更重要的是它不会留下痕迹。和很多的技术手段一样,本来DMA是老老实实作研究用的,可是君子无罪怀璧其罪。

总而言之,DMA刚出来的时候确实是完完全全的碾压了市面上所有的反作弊,没有人使用DMA去对抗反作弊,反作弊也就没有对应的需求,自然而然更加的海阔天空,第一批DMA使用者也就切切实实享受到了新世界。

2016年左右,PCILeech发布 (DMA读写从未如此简单):) DMA读写从此工程化

1

2

3

4

5

6

7

fpga固件 收发 PCIe TLP

|

leechcore 传输层

|

vmm/MemProcs 物理内存 → 进程视图、符号解析

|

上位机程序 读目标数据

19-21年这个时间段就依旧开始出现咋混共作弊的DMA作弊硬件流入市场,配套服务也非常好,固件配套服务也开始出现,逐渐成熟化了,对抗也进入了下一阶段。

【2】大众

总所周知,追求小众是一件非常大众的事情,而在反作弊对抗这块可以说大众了,就再也没有翻身的余地了,技术的泛滥与不断迭代,让旧技术狠狠的被碾压过去,不幸的,很显然DMA也没有逃过时代车轮的碾压,就在某个时间节点,DMA的用户迎来了大爆发,有人赚的盆满钵满,固件,教学等等雨后春笋一般冒出,设备成本的降低和名色大噪又反向助推用户数量的增长,于是肉眼可见的,DMA被盯上了。

另一边,反作弊厂商可以说是亚历山大了,于是正式打响对抗战争。

反作弊厂商首先想到的对抗方法是什么呢?既然DMA是设备那显然他们可以先遍历检查一下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

以下代码为伪代码还原示例

ANSI_STRING a; UNICODE_STRING u;

charpath[] ="\\Driver\\pci";

RtlInitAnsiString(&a, path);

RtlAnsiStringToUnicodeString(&u, &a, TRUE);

g_pci = ObReferenceObjectByName(&u, ...);

//遍历 PCI 总线驱动自己的设备链表

//g_pci + 0x200 是 LIST_ENTRY 头(node+0 = Flink,node+8 = Blink)

//记录基址 elem = node - 0x280

//配置空间头就嵌在 elem + 0x04

for(node = *(PVOID*)(g_pci + 0x200); ; node = *(PVOID*)node) {

Word vendor = *(Word *)(elem + 0x04);

Word device = *(Word *)(elem + 0x06);

if(vendor != 0x8086)continue;// 判断是不是Intel

if(device <= 0x7D0B) {

if(device == 0x7D0B || device == 0x201D || device == 0x28C0 ||

device == 0x467F || device == 0x4C3D)gotomatched;

}else{

if(device == 0x9A0B || device == 0xA77F || device == 0xAD0B)gotomatched;

}

continue;

if(!(flags & 8))continue;

先拿这块设备内核 PDO,再找到分配的 MMIO 资源

PDEVICE_OBJECT pdo = *(PDEVICE_OBJECT *)(elem + 0x108);

ULONGlen = 0;

status = IoGetDeviceProperty(pdo,

0x15/* DevicePropertyAllocatedResources */,

0, NULL, &len);

if(status != 0xC0000023/* STATUS_BUFFER_TOO_SMALL */) bail;

PVOIDbuf = ExAllocatePoolWithTag(NonPagedPool, 0x200,'pciR');

IoGetDeviceProperty(pdo, 0x15, 0x200, buf, &len);

PCM_RESOURCE_LIST rl = buf;

if(rl->List[0].PartialResourceList.PartialDescriptors[0].Type

!= 3/* CmResourceTypeMemory */) bail;

bar = ...[0].u.Memory.Start;

barLen = ...[0].u.Memory.Length;

//越过 VMD 桥本身,直读它下游总线的配置空间窗口

if(barLen >= 0x100000) {

p = MmMapIoSpace(bar + 0x100000, 4, MmNonCached);

if(*(ULONG*)p == 0xFFFFFFFF) {

//总线 1 上没东西

MmUnmapIoSpace(p, 4);

ExFreePoolWithTag(buf, 0);

}else{

//上有设备 → 把它的完整 256 字节配置空间读下来

MmUnmapIoSpace(p, 4);

if(barLen >= 0x100000 + 0x1100) {

out = 0;

sub_14001BAF0(bar + 0x100000, &out, elem);

}

}

if(barLen >= 0x200000) {

q = MmMapIoSpace(bar + 0x200000, 4, MmNonCached);

if(*(ULONG*)q == 0xFFFFFFFF) { MmUnmapIoSpace(q, 4); }

else{//同上 }

}

ExFreePoolWithTag(buf, 0);

}

sub_14001BAF0(bar + 0x100000, &out, elem);

}

voidsub_14001BAF0(PHYSICAL_ADDRESS addr,ULONG*out,UCHAR*elem)

{

void*p = MmMapIoSpace(addr, 0x1100, MmNonCached);// 0x1400d7338

scratch = ExAllocatePoolWithTag(0x200, 0x1100,'pcfg');// 0x1400d743d

i = 0x1000;

while(((UCHAR*)p)[i] == 0xFF) i++;// 全 0xFF 无设备

sub_140026280((UCHAR*)p + 1, (UCHAR*)p + 0x1001, 0xFF);// 0x1400d768a

*out = 1;

for(i = 0; i < 0x100; i++)// 展开 256 条 store8

elem[0x158 + i] = ((UCHAR*)p)[0x1000 + i];// → elem[0x158..0x257]

MmUnmapIoSpace(p, 0x1100);

}

那么这几个case 的十六进制常量是什么呢? 通过查看PCI ID Repository我们可以看到

1

2

3

4

5

0x201D 0x467F 0x4C3D 0x9A0B ="Volume Management Device NVMe RAID Controller";

0x28C0 ="Volume Management Device (VMD)";

0x7D0B ="Core Ultra 200H/200V Series Processors VMD";

0xA77F ="RST Volume Management Device Controller";

0xAD0B` ="Core Ultra 200 Series Processors VMD";

那就会有人问了,反作弊拿这个elem 0x158-257又是干什么呢?难道里面有什么可以判断是不是DMA的信息吗。

于是我们就查一查

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

status = sub_14001C9D0(...);// 填充记录(含直读配置空间)

if(status < 0)gotodone;

node = *(PVOID*)(P + 0x200);

if(node == (PVOID*)(P + 0x200))gotoempty;// 空链

out = user_buffer;

out[0x00..0x02] = elem[0x00..0x02];

*(WORD*)(out + 0x03) = *(WORD*)(elem + 0x04);// VendorID

*(WORD*)(out + 0x05) = *(WORD*)(elem + 0x06);// DeviceID

*(U64 *)(out + 0x07) = ((U64)*(ULONG*)(elem+0x120) << 32)

| (U64)*(ULONG*)(elem+0x11C);

*(ULONG*)(out + 0x0F) = *(ULONG*)(elem + 0x130);

*(U64 *)(out + 0x13) = *(U64 *)(elem + 0x128);

*(ULONG*)(out + 0x33) = *(ULONG*)(elem + 0x14C);

*(ULONG*)(out + 0x37) = *(ULONG*)(elem + 0x150);

*(ULONG*)(out + 0x3B) = *(ULONG*)(elem + 0x154);

*(U64 *)(out + 0x3F) = *(U64 *)(elem + 0x158);// ← 直读配置空间七点

/* 一直到 out+0x27E */

*(ULONG*)r14 = 2;

sub_14001BD00(P + 0x210, out + 0x27E, ...);

直接查资料看看他都收集了哪些东西吧,忘了说了这么多还没贴出来资料:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

typedefstruct_PCI_COMMON_HEADER

0x00 Vendor IDUSHORTVendorID / PCI_VENDOR_ID 0x00

0x02 Device IDUSHORTDeviceID / PCI_DEVICE_ID 0x02

0x04 Command(16 位) PCI_ENABLE_IO_SPACE 0x0001 / PCI_ENABLE_MEMORY_SPACE 0x0002 / PCI_ENABLE_BUS_MASTER 0x0004

0x06 Status PCI_STATUS_CAPABILITIES_LIST 0x0010 等

0x08 Revision IDUCHARRevisionID

0x09 ProgIf(编程接口)UCHARProgIf / PCI_CLASS_PROG 0x09

0x0A SubClassUCHARSubClass

0x0B BaseClassUCHARBaseClass / PCI_CLASS_DEVICE 0x0a(16 位,含 SubClass)

0x0E HeaderType PCI_HEADER_TYPE 0x0e;0=普通设备,1=PCI 桥,2=CardBus

0x10–0x27 BAR0–BAR5(6×32 位)ULONGBaseAddresses[PCI_TYPE0_ADDRESSES],PCI_TYPE0_ADDRESSES 为 6

0x28 CIS / CardBus 指针ULONGCIS

0x2C Subsystem Vendor IDUSHORTSubVendorID

0x2E Subsystem IDUSHORTSubSystemID

0x30 Expansion ROM 基址ULONGROMBaseAddress

0x34 Capabilities PointerUCHARCapabilitiesPtr / PCI_CAPABILITY_LIST 0x34

0x3C Interrupt LineUCHARInterruptLine

0x3D Interrupt PinUCHARInterruptPin(只读)

1

2

3

4

5

6

7

0x00 Vendor / Device ID 身份;DMA 卡常报成网卡/声卡

0x04 Command:bit1 Command寄存器

0x08–0x0B Revision / ProgIF / SubClass / BaseClass 你是什么设备

0x10–0x27 BAR0–BAR5 MMIO

0x2C Subsystem Vendor / Device

0x34 Capabilities Pointer 能力链头

0x3C/0x3D Interrupt Line / PIN 中断

什么是MMIO?

MMIO就是 Memory-Mapped I/O,0x10–0x27 那 6 个 32 位 BAR 是设备声明自己需要一段地址空间的寄存器

1

2

3

4

5

#define PCI_BASE_ADDRESS_0 0x10

#define PCI_BASE_ADDRESS_5 0x24

#define PCI_BASE_ADDRESS_SPACE 0x01 /* 0 = 内存空间, 1 = I/O 空间 */

#define PCI_BASE_ADDRESS_MEM_TYPE_64 0x04 /* 64 位地址 */

#define PCI_BASE_ADDRESS_MEM_PREFETCH 0x08 /* 可预取 */

系统给这段空间分配物理地址后把基址写回 BAR;之后 CPU 访问这段物理地址,就是访问设备的板载寄存器。

为什么收集MMIO?

设备内部的寄存器里,包含 DMA 引擎的描述符地址、长度、启动位、完成状态。这些寄存器通常映射在 BAR 里,CPU 只能通过这段 MMIO 去操作 DMA 。

为什么收集 Command 寄存器?

1

2

3

4

5

6

7

8

9

10

11

#define PCI_ENABLE_IO_SPACE 0x0001

#define PCI_ENABLE_MEMORY_SPACE 0x0002 // bit1

#define PCI_ENABLE_BUS_MASTER 0x0004 // bit2

#define PCI_ENABLE_SPECIAL_CYCLES 0x0008

#define PCI_ENABLE_WRITE_AND_INVALIDATE 0x0010

#define PCI_ENABLE_VGA_COMPATIBLE_PALETTE 0x0020

#define PCI_ENABLE_PARITY 0x0040 // (ro+)

#define PCI_ENABLE_WAIT_CYCLE 0x0080 // (ro+)

#define PCI_ENABLE_SERR 0x0100 // (ro+)

#define PCI_ENABLE_FAST_BACK_TO_BACK 0x0200 // (ro)

#define PCI_DISABLE_LEVEL_INTERRUPT 0x0400

当 PCI_ENABLE_BUS_MASTER = 1 时,该 Function 可以主动向总线发起 Memory Read / Write Request(即 DMA 操作)。

当 PCI_ENABLE_BUS_MASTER = 0 时,该 Function 不允许发起任何 DMA 请求,只能被动响应 CPU 的访问。

还可以在用户态继续一下

1

2

3

4

5

6

7

HDEVINFO h = SetupDiGetClassDevs(&guid, NULL, NULL, DIGCF_ALLCLASSES | DIGCF_PRESENT);

for(DWORDi = 0; SetupDiEnumDeviceInfo(h, i, &di); i++) {

SetupDiGetDeviceRegistryProperty(h, &di, SPDRP_HARDWAREID,

NULL, buf,sizeofbuf, NULL);

//读取Vendor ID对比一下黑名单id

}

这里也有一些被拉黑的数据,收集数据,建立数据库狠狠的拉黑这些板子使用者。

1

2

3

109E Brooktree Corporation Bt848 / Bt878 / Bt879 视频采集 pci-ids 109E

1CD7 Nanjing Magewell Electronics(美乐威) Pro Capture / Eco Capture 采集卡 pci-ids 1CD7

BDBD Blackmagic Design DeckLink / Intensity / UltraStudio 采集卡 pci-ids BDBD (注意都是采集卡下面也要考)

校验方案:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

//没服务

for(inti = 0; i < total; i++, elem += 0x848) {

if(*(U32 *)(elem + 0x808) == 0)//设备没有绑定任何驱动服务

//上报

}

//有服务

for(inti = 0; i < total; i++, elem += 0x848) {

if(*(U32 *)(elem + 0x808) == 0)continue;// 无服务 → 归 dma_nosrv 管

if(*(U32 *)(elem + 0x812) != 786)continue;// ← 第二个判据

if(ven_match(o, hwid(elem), o->vendor_list))

report_event(7990, 102, 9015);

}

//假服务:

boolvm = ven_match(o, hwid(elem), o->vendor_list);// 子串查找

boolvs = svc_match(o, svc(elem), o->service_list);// 字符串全等

if(vm && vs) report_event(7990, 102, 9019);

boolven_match(Type134 *o,char*hwid, vector<string> *list) {

if(list->empty() || !hwid)returnfalse;

for(each v in *list) {

string pat ="VEN_"+ v;

if(sub_181737594(hwid, pat.c_str()))// ← 在 hwid 里找这个子串

returntrue;

}

returnfalse;

}

if(*(U32 *)(elem + 0x00) == 0 &&

*(U32 *)(elem + 0x04) == 0 &&

*(U32 *)(elem + 0x08) != 0 &&// ← 这一项要求"非零"

*(U32 *)(elem + 0x10) == 0 &&

*(U32 *)(elem + 0x14) != 0 &&

all_zero(elem + 0x18, 256) &&// ← 连续 256 字节全零

total == 1)// ← 记录总数恰好为 1

这里给出参考表也不再赘述了,核心对抗就是你伪造的我就校验,这也是为什么某些垃圾固件确实会拉闸。

1

2

3

4

5

6

7

8

elem+0x808 U32 nosrv / wrongsrv == 0 无驱动服务

elem+0x812 U32 wrongsrv == 786 服务起不来

硬件 ID 字符串 string fakesrv VEN_<厂商> 子串 厂商身份

服务名字符串 string fakesrv 全等 3 个虚拟机名 伪造服务名

elem+0x00/04/08/10/14 5×U32 hide 零/非零交替 空壳形态

elem+0x18..0x117 256 B hide 全零 该填未填

记录总数inthide ==1 / 变化 藏得太干净

两来源 ID U32×2 cfg 互相相等 读取链被改

【3】现在

难道说DMA不小众了我就不玩了吗,但那是弱者的思维。哪怕是在VTD大清洗后,还是有相当数量的八旗子弟仍旧抱着DMA四死死不放手,这也能理解,毕竟双机硬件搭配依旧能解决很多问题,比如签名,软件特征等等。

DMA为了应对反作弊厂商的严肃进攻,也是做出了努力,比如他们尝试伪装固件,把收集到的公开的固件刷到自己这里,或者伪装自己的ID用于对抗反作弊的黑固件数据库,甚至是自己实现一个协议去对抗反作弊的行为检测。

不过反作弊也迎来了史上最强VTD vs 现代最强DMA

1

2

3

4

5

6

7

8

0xe87f test al, al

0xe881 je 0x14000e890

0xe883 cmp byte ptr [0x14003027A], 0 ; g_securePciEnabled

0xe88a jne 0x14000e912 ; Secure PCI 已启用 → 跳过整段

0xe890 cmp dword ptr [rbp - 0x7c], 0x10ec ; 未启用 → 检查 vendor == Realtek

0xe897 jne 0x14000e912

0xe8a5 lea rdx, [r13 + 0x10] ; 遍历设备条目,步长 0x14

0xe8c5 cmp byte ptr [rcx], 3 ; 子类型 == 3

1

2

3

4

5

6

7

/* g_securePciEnabled 由 VslGetSecurePciEnabled() 写入(0x14000D586 → 0x140016F5C) */

if(secure_pci_enabled)

return;//直接过

if(vendor != 0x10EC)

return;

/* 遍历设备条目,按子类型继续查 */

系统已经启用了 Secure PCI就不管,至于为什么只检查Realtak就懂的都懂了。

不过反作弊也利用起了大杀器,VTD,还记得前面说的IOMMU吗?这里就考到了,DMA要访问是必须经过IOMMU的。

在没有VTD时候,DMA是这样访问的:

1

设备 ──DMA──▶ 物理地址 0x0000_0000 / 内核代码 / 其他进程 / 其他 VM

而在打开了VTD之后就是如此访问的:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

PCIe 设备

│ DMA 请求(带 IOVA + Requester ID / BDF)

▼

VT-d DMA Remapping Engine(Root Complex 里)

│ 1. 用 BDF 查 Root Entry → Context Entry

│ 2. 找到这个设备的 I/O 页表(Domain)

│ 3. IOVA → HPA 翻译

│ 4. 检查 R/W/EXEC 权限

▼

物理内存

0x00 Signature"DMAR"

0x04 Length

0x08 Revision

0x09 Checksum

0x0A OEMID 6 字节

0x10 OEM Table ID 8 字节

0x18 OEM Revision

0x1C Creator ID 4 字节

0x20 Creator Revision

0x24 HAW

0x25 Flags

0x26 Reserved

0x28 Remapping Structures (DRHD/RMRR/ATSR/...)

PCIE设备只能看到IOVA(I/O VirtualAddress),而不是直接拿到真实的物理地址了,此时此刻真实的物理地址由VTD硬件查表页决定。

而如果他要读取就需要系统在IOMMU页表里建映射表,如果没有映射的话就会计入DMAR fault,看到这里你应该也能感觉到VTD的姜维打击了,还是那句话,如果身份互换,我会让你知道我的痛苦,可以说,打开VTD几乎DMA就没有还手之力了。

1

2

3

4

5

6

7

8

9

call NtQuerySystemInformation ;class0x4C = SystemFirmwareTableInformation

; 返回一串 4 字节 ACPI 表签名

loop:

cmp ecx, 0x52414D44 ;'DMAR'

je → TRUE

cmp ecx, 0x53525649 ;'IVRS'

je → TRUE

end:

→ FALSE

当然DMA玩家也并非全无办法,比如:想办法解析DMAR表篡改数据,或者伪造设备已经打开了VTD。

比如我可以构造一张假的DMAR表:

1

2

3

4

5

6

7

8

定位 RSDP → 找到 XSDT 物理地址

解析 XSDT → 收集所有 ACPI 表项地址

扫描物理内存,找 4KB 对齐且空闲的区域(与现有表至少隔 4KB)

在该区域构造一份合法的 DMAR 表(含 DRHD/RMRR 等子结构)

DRHD 寄存器基址选 >4GB 的空闲 PCIe MMIO 页

把新 DMAR 的物理地址写入 XSDT 条目(替换或追加)

修正校验和,回读验证

观察系统 IOMMU 行为变化

关键代码: 取自kEv1nZ0/VTD-Bypass: 全自动过VTD检测

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

定位 RSDP → XSDT

# 扫描物理内存低 1MB 找 RSDP

forpainrange(0x000E0000,0x00100000,16):

buf=lc.read(pa,36)

ifbuf[0:8]==b'RSD PTR ':

rsdp=buf

break

xsdt_pa=struct.unpack_from('<Q', rsdp,24)[0]# XsdtAddress at offset 24

找空闲4KB对齐区域

deffind_free_4k(start, end, used_list):

"""找和 used_list 中每个地址至少隔 4KB 的空洞"""

forpainrange(start, end,0x1000):

conflict=False

forusedinused_list:

ifabs(pa-used) <0x1000:

conflict=True

break

ifnotconflict:

returnpa

return0

构造 DMAR 表

defbuild_dmar(dmar_pa):

dmar=bytearray(48)# 表头 48 字节

struct.pack_into('4s', dmar,0, b'DMAR')

struct.pack_into('<I', dmar,4,48)

dmar[8]=1# Revision

# OEMID / OEM Table ID / Creator ID 模仿原固件

# Checksum 后面算

returndmar

defcalc_checksum(buf):

return(-sum(buf)) &0xFF

dmar=build_dmar(dmar_pa)

dmar[9]=calc_checksum(dmar)

DRHD 基址选 >4GBMMIO

defpick_drhd_base():

"""选 >4GB 的空闲 PCIe MMIO 页"""

forpainrange(0x100000000,0x10000000000,0x1000):

ifnotis_mmio_mapped(pa)andnotis_used(pa):

returnpa

return0

写入新 DMAR 并挂进 XSDT

# 写入 DMAR 表体

lc.write(dmar_pa, bytes(dmar))

# 替换 XSDT 中的 DMAR 条目

fori, entryinenumerate(entries):

iflc.read(entry,4)==b'DMAR':

lc.write(xsdt_pa+36+i*8, struct.pack('<Q', dmar_pa))

break

# 修正 XSDT 校验和

xsdt_data=lc.read(xsdt_pa, length)

xsdt_data[9]=calc_checksum(xsdt_data)

lc.write(xsdt_pa, xsdt_data)

最后再回读验证一下

verify=lc.read(dmar_pa,4)

assertverify==b'DMAR',"DMAR 写入失败"

verify_xsdt=lc.read(xsdt_pa+36+i*8,8)

assertstruct.unpack('<Q', verify_xsdt)[0]==dmar_pa,"XSDT 条目更新失败"

当然,大部分反作弊也会在用API判断完后检查DMAR表,也可以利用固件元数据不一致来判断环境是否可信。

1

2

3

4

5

6

7

8

9

10

11

12

*(U32*)(dmar+0x0B) 0x0B OEMID(0x0A,6) 之内

*(U16*)(dmar+0x0F) 0x0F OEMID 末 + OEMTableID 首

*(U32*)(dmar+0x1D) 0x1D CreatorID(0x1C) 之内

RtlCompareMemory(dmar+0x0B, sdt+0x0B, 6) 0x0B 起 6 B

伪代码:

PVOIDdmar = FindAcpiTable('DMAR');

PVOIDroot = FindAcpiTable('XSDT');

boolvt_d_seen = (dmar != NULL);

boolsame_oem = vt_d_seen && RtlCompareMemory(dmar + 0x0B,

root + 0x0B, 6) == 0;

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询