首页
社区
课程
招聘
[原创]通过修改物理内存实现跨进程内存读写
发表于: 2024-5-6 21:10 12463

[原创]通过修改物理内存实现跨进程内存读写

2024-5-6 21:10
12463

学习一下利用修改物理内存来跨进程内存读写

系统:win10 21h1 x64

编译环境: vs2022 详情见附录

虚拟地址也称线性地址,一个线性地址+进程的DirBase地址可以转换成物理地址。先来看线性地址的含义

在x64体系中只实现了48位的virtual address,高16位被用作符号扩展,这高16位要么全是0,要么全是1。
不同于x86体系结构,每级页表寻址长度变成9位,由于在x64体系结构中,普通页大小仍为4KB,然而数据却表示64位长,因此一个4KB页在x64体系结构下只能包含512项内容,所以为了保证页对齐和以页为单位的页表内容换入换出,在x64下每级页表寻址部分长度定位9位。

img

从Page Map Level 4(PML4)开始到最后的物理地址,每一个都可以理解成一层页表的索引,索引值就是线性地址上不同的部分,分别缩写是PML4, PDPE, PDE,PTE。

注意,并不是取出来的值就直接指向一下一个页表,个人PC上一般是取值的12-35bit的值,其他置0。具体的后面见代码,或参考看雪的文章

img

使用windbg可以先查看进程对应的DirBase地址,然后再使用!vtop Dirbase地址 虚拟地址查看虚拟地址对应的物理地址,如下。

上面得到DirBase的值是235ae6000,然后需要查看物理地址的虚拟地址是0x0000A6E334FB00,就使用命令

得到最后对应的物理地址是0x11b10cb00。

简单例子代码如下:

运行后可以打印出来字符串的虚拟地址0000A6E334FB00,然后通过上述步骤得到物理地址。

我们尝试看看物理内存中的字符串,现在已经确定物理内存的地址是0xD0000147,使用!db 0xD0000147来查看物理内存,记住要!,没有感叹号的是查看虚拟内存的

可以看到物理内存上的字符串内容。

DirBase地址除了通过上述windbg直接得到这个值以外,还可以通过EPROCESS来得到,这个是代码比较需要的

DirectoryTableBase的值就是DirBase地址了,实际上就是EPROCESS + 0x28的偏移

还可以通过获取CR3寄存器的值,CR3寄存器中的值就是页目录表的物理地址,也就是DirBase

目的:进程B可以通过修改物理内存的内容来修改进程A内存中的数据

实验设置:进程A泄露一个变量地址,然后等待进程B修改,修改后再回复执行,打印变量值看是否修改成功

内核部分思路:

这里写一个例子来充当被攻击(修改内存)的进程。主要就是打印变量内容和地址,然后暂停程序等待一段时间(等待被驱动修改),然后再打印变量内容,看看是否被驱动修改内存成功。

这里就是主要逻辑,通过驱动代码取修改目标进程的内存内容,做到跨进程内存读取,修改。

定义一个读取物理内存函数

再定义一个写入物理内存的函数

我们需要将虚拟地址转换成物理地址,那么首先需要线性地址+DirBase地址,DirBase地址获取是通过PEPROCESS+0x28偏移读取的

得到DirBase后,就可以虚拟地址转换物理地址。

传入虚拟地址后,取后48bit,然后将这48bit分成4个9bit和最后12bit,分别是PML4,PDPE,PDE,PTE和页内偏移offset。需要注意的是DirBase就已经是物理内存了,所以读取DirBase内容并且一层一层读取都要用自定义函数ReadPhysicalAddress

每一层都是基地址+8*偏移,读取的内容,取12-35bit就是下一层的基地址

最后再主函数中定义一下逻辑。这里直接手动指定进程号和目标进程打印出来的变量地址,然后将虚拟地址转化成物理地址,读取物理地址上的内容并打印出来看看是否正确。再修改物理地址上的内容。

目标进程

image-20240505235113447

驱动

image-20240505235141011

可以看到目标进程的指定内存被修改,同时驱动也跨进程读取,修改内存成功

使用CR3切换实现读取指定进程内存数据 | pnpon.com

c/c++/易语言驱动内存无痕读写源码 | csdn.net

将虚拟地址转换为物理地址 | learn.microsoft.com

X64下的虚拟地址到物理地址的转换 | bbs.kanxue.com

几种挖掘任意读写驱动的方法 | myzxcg.com/

3: kd> !process 258c 0
Searching for Process with Cid == 258c
PROCESS ffffc40d2ab48340
    SessionId: 1  Cid: 258c    Peb: a6e35cd000  ParentCid: 1250
    DirBase: 235ae6000  ObjectTable: ffff998138d4ee00  HandleCount:  38.
    Image: test.exe
 
3: kd> !vtop 235ae6000 0000A6E334FB00
Amd64VtoP: Virt 000000a6e334fb00, pagedir 0000000235ae6000
Amd64VtoP: PML4E 0000000235ae6008
Amd64VtoP: PDPE 00000001087fb4d8
Amd64VtoP: PDE 000000010f7fc8c8
Amd64VtoP: PTE 00000000ad207a78
Amd64VtoP: Mapped phys 000000011b10cb00
Virtual address a6e334fb00 translates to physical address 11b10cb00.
3: kd> !process 258c 0
Searching for Process with Cid == 258c
PROCESS ffffc40d2ab48340
    SessionId: 1  Cid: 258c    Peb: a6e35cd000  ParentCid: 1250
    DirBase: 235ae6000  ObjectTable: ffff998138d4ee00  HandleCount:  38.
    Image: test.exe
 
3: kd> !vtop 235ae6000 0000A6E334FB00
Amd64VtoP: Virt 000000a6e334fb00, pagedir 0000000235ae6000
Amd64VtoP: PML4E 0000000235ae6008
Amd64VtoP: PDPE 00000001087fb4d8
Amd64VtoP: PDE 000000010f7fc8c8
Amd64VtoP: PTE 00000000ad207a78
Amd64VtoP: Mapped phys 000000011b10cb00
Virtual address a6e334fb00 translates to physical address 11b10cb00.
!vtop 235ae6000 0000A6E334FB00
!vtop 235ae6000 0000A6E334FB00
#include <stdio.h>
#include <stdlib.h>
 
int main() {
    char flag[] = {"flag{b7285d748dd042a4929d3dbec778e637}"};
 
    printf("value addr: %p", flag);
    getchar();
 
    return 0;
}
#include <stdio.h>
#include <stdlib.h>
 
int main() {
    char flag[] = {"flag{b7285d748dd042a4929d3dbec778e637}"};
 
    printf("value addr: %p", flag);
    getchar();
 
    return 0;
}
3: kd> !db 0x11b10cb00
#11b10cb00 66 6c 61 67 7b 62 37 32-38 35 64 37 34 38 64 64 flag{b7285d748dd
#11b10cb10 30 34 32 61 34 39 32 39-64 33 64 62 65 63 37 37 042a4929d3dbec77
#11b10cb20 38 65 36 33 37 7d 00 00-f8 82 20 82 f7 7f 00 00 8e637}.... .....
#11b10cb30 00 00 00 00 00 00 00 00-20 13 1f 82 f7 7f 00 00 ........ .......
#11b10cb40 00 00 00 00 00 00 00 00-99 13 1f 82 f7 7f 00 00 ................
#11b10cb50 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#11b10cb60 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#11b10cb70 00 00 00 00 00 00 00 00-44 73 d3 08 fe 7f 00 00 ........Ds......
3: kd> !db 0x11b10cb00
#11b10cb00 66 6c 61 67 7b 62 37 32-38 35 64 37 34 38 64 64 flag{b7285d748dd
#11b10cb10 30 34 32 61 34 39 32 39-64 33 64 62 65 63 37 37 042a4929d3dbec77
#11b10cb20 38 65 36 33 37 7d 00 00-f8 82 20 82 f7 7f 00 00 8e637}.... .....
#11b10cb30 00 00 00 00 00 00 00 00-20 13 1f 82 f7 7f 00 00 ........ .......
#11b10cb40 00 00 00 00 00 00 00 00-99 13 1f 82 f7 7f 00 00 ................
#11b10cb50 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#11b10cb60 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#11b10cb70 00 00 00 00 00 00 00 00-44 73 d3 08 fe 7f 00 00 ........Ds......
3: kd> dt _eprocess ffffc40d2ab48340
nt!_EPROCESS
   +0x000 Pcb              : _KPROCESS
   +0x438 ProcessLock      : _EX_PUSH_LOCK
   +0x440 UniqueProcessId  : 0x00000000`0000258c Void
   +0x448 ActiveProcessLinks : _LIST_ENTRY [ 0xffffc40d`2cb43788 - 0xffffc40d`2cd444c8 ]
   +0x458 RundownProtect   : _EX_RUNDOWN_REF
   .....
3: kd> dx -id 0,0,ffffc40d23c95040 -r1 (*((ntkrnlmp!_KPROCESS *)0xffffc40d2ab48340))
(*((ntkrnlmp!_KPROCESS *)0xffffc40d2ab48340))                 [Type: _KPROCESS]
    [+0x000] Header           [Type: _DISPATCHER_HEADER]
    [+0x018] ProfileListHead  [Type: _LIST_ENTRY]
    [+0x028] DirectoryTableBase : 0x235ae6000 [Type: unsigned __int64]
3: kd> dt _eprocess ffffc40d2ab48340
nt!_EPROCESS
   +0x000 Pcb              : _KPROCESS
   +0x438 ProcessLock      : _EX_PUSH_LOCK
   +0x440 UniqueProcessId  : 0x00000000`0000258c Void
   +0x448 ActiveProcessLinks : _LIST_ENTRY [ 0xffffc40d`2cb43788 - 0xffffc40d`2cd444c8 ]
   +0x458 RundownProtect   : _EX_RUNDOWN_REF
   .....
3: kd> dx -id 0,0,ffffc40d23c95040 -r1 (*((ntkrnlmp!_KPROCESS *)0xffffc40d2ab48340))
(*((ntkrnlmp!_KPROCESS *)0xffffc40d2ab48340))                 [Type: _KPROCESS]
    [+0x000] Header           [Type: _DISPATCHER_HEADER]
    [+0x018] ProfileListHead  [Type: _LIST_ENTRY]
    [+0x028] DirectoryTableBase : 0x235ae6000 [Type: unsigned __int64]
#include <stdio.h>
#include <stdlib.h>
 
int main() {
    char flag[] = {"flag{b7285d748dd042a4929d3dbec778e637}"};
 
    printf("value addr: %p\r\n", flag);
    printf("flag data: %s\r\n", flag);
    getchar();
 
    printf("flag data Now: %s\r\n", flag);
    return 0;
}
#include <stdio.h>
#include <stdlib.h>
 
int main() {
    char flag[] = {"flag{b7285d748dd042a4929d3dbec778e637}"};
 
    printf("value addr: %p\r\n", flag);
    printf("flag data: %s\r\n", flag);
    getchar();
 
    printf("flag data Now: %s\r\n", flag);
    return 0;
}
/// @brief 读取物理地址的内存内容
/// @param address 物理地址
/// @param buffer 复制内存地址到buffer
/// @param size 复制大小
/// @param BytesTransferred 读取的字节数
/// @return
NTSTATUS ReadPhysicalAddress(IN PVOID64 address, OUT PVOID64 buffer,
                             IN SIZE_T size, OUT SIZE_T* BytesTransferred)
{
    MM_COPY_ADDRESS Read          = {0};
    Read.PhysicalAddress.QuadPart = (LONG64)address;
    return MmCopyMemory(
        buffer, Read, size, MM_COPY_MEMORY_PHYSICAL, BytesTransferred);
}
/// @brief 读取物理地址的内存内容
/// @param address 物理地址
/// @param buffer 复制内存地址到buffer
/// @param size 复制大小
/// @param BytesTransferred 读取的字节数
/// @return
NTSTATUS ReadPhysicalAddress(IN PVOID64 address, OUT PVOID64 buffer,
                             IN SIZE_T size, OUT SIZE_T* BytesTransferred)
{
    MM_COPY_ADDRESS Read          = {0};
    Read.PhysicalAddress.QuadPart = (LONG64)address;
    return MmCopyMemory(
        buffer, Read, size, MM_COPY_MEMORY_PHYSICAL, BytesTransferred);
}
/// @brief 写入指定内容到物理内存中
/// @param address 被写入的物理地址
/// @param buffer 需要写入的缓冲区指针
/// @param size 需要写入的大小
/// @param BytesTransferred 写入成功后的大小
/// @return
NTSTATUS WritePhysicalAddress(IN PVOID64 address, IN PVOID64 buffer,
                              IN SIZE_T size, OUT SIZE_T* BytesTransferred)
{
    PVOID            map;
    PHYSICAL_ADDRESS Write = {0};
 
    if (!address) {
        kprintf("Address value error. \r\n");
        return STATUS_UNSUCCESSFUL;
    }
 
    Write.QuadPart = (LONG64)address;
    map            = MmMapIoSpaceEx(Write, size, PAGE_READWRITE);
 
    if (!map) {
        kprintf("Write Memory faild.\r\n");
        return STATUS_UNSUCCESSFUL;
    }
    RtlCopyMemory(map, buffer, size);
    *BytesTransferred = size;
    MmUnmapIoSpace(map, size);
    return STATUS_SUCCESS;
}
/// @brief 写入指定内容到物理内存中
/// @param address 被写入的物理地址
/// @param buffer 需要写入的缓冲区指针
/// @param size 需要写入的大小
/// @param BytesTransferred 写入成功后的大小
/// @return
NTSTATUS WritePhysicalAddress(IN PVOID64 address, IN PVOID64 buffer,
                              IN SIZE_T size, OUT SIZE_T* BytesTransferred)
{
    PVOID            map;
    PHYSICAL_ADDRESS Write = {0};
 
    if (!address) {
        kprintf("Address value error. \r\n");
        return STATUS_UNSUCCESSFUL;
    }
 
    Write.QuadPart = (LONG64)address;
    map            = MmMapIoSpaceEx(Write, size, PAGE_READWRITE);
 
    if (!map) {
        kprintf("Write Memory faild.\r\n");
        return STATUS_UNSUCCESSFUL;
    }
    RtlCopyMemory(map, buffer, size);
    *BytesTransferred = size;
    MmUnmapIoSpace(map, size);
    return STATUS_SUCCESS;
}
/// @brief 通过EPROCESS获取DirBase值
/// @param pid 进程PID
/// @param pDirbase 一个UINT64指针,获取成功后返回值
/// @return
NTSTATUS GetDirBaseByEprocess(IN UINT64 pid, OUT PUINT64 pDirbase)
{
    PEPROCESS pEprocess;
    NTSTATUS  status;
 
    status = PsLookupProcessByProcessId((HANDLE)pid, &pEprocess);
    if (!NT_SUCCESS(status)) {
        kprintf("[!] Get Pid=%d _EPROCESS failed!", pid);
        return STATUS_UNSUCCESSFUL;
    }
 
    *pDirbase =
        *(PUINT64)((PUCHAR)pEprocess + WIN10_21H1_EPROCESS2DIRBASE_OFFSET);
    kprintf("[+] uDirBase ==> %llx\r\n", *pDirbase);
 
    return STATUS_SUCCESS;
}
/// @brief 通过EPROCESS获取DirBase值
/// @param pid 进程PID
/// @param pDirbase 一个UINT64指针,获取成功后返回值
/// @return
NTSTATUS GetDirBaseByEprocess(IN UINT64 pid, OUT PUINT64 pDirbase)
{
    PEPROCESS pEprocess;
    NTSTATUS  status;
 
    status = PsLookupProcessByProcessId((HANDLE)pid, &pEprocess);
    if (!NT_SUCCESS(status)) {
        kprintf("[!] Get Pid=%d _EPROCESS failed!", pid);
        return STATUS_UNSUCCESSFUL;
    }
 
    *pDirbase =
        *(PUINT64)((PUCHAR)pEprocess + WIN10_21H1_EPROCESS2DIRBASE_OFFSET);
    kprintf("[+] uDirBase ==> %llx\r\n", *pDirbase);
 
    return STATUS_SUCCESS;
}
/// @brief 传入DirBase值和虚拟地址后,回转化成一个物理地址返回
/// @param DirBase DirBase地址,传入一个UINT64值
/// @param addr 传入一个指向虚拟地址的指针,转化成物理地址后会修改这个指针的值
/// @return
NTSTATUS TranslateAddress(IN UINT64 DirBase, _Inout_ PUINT64 addr)
{
    UINT16   PML4, PDPE, PDE, PTE, offset;
    UINT64   mask = 0x7fffff000;
    UINT64   uTmp;
    SIZE_T   BytesTransferred;
    NTSTATUS status;
 
    offset = *addr & 0xfff;
    PTE    = (*addr >> 12) & 0x1ff;
    PDE    = (*addr >> (12 + 9)) & 0x1ff;
    PDPE   = (*addr >> (9 * 2 + 12)) & 0x1ff;
    PML4   = (*addr >> (9 * 3 + 12)) & 0x1ff;
 
    status = ReadPhysicalAddress(
        (PVOID64)(DirBase + PML4 * 8), &uTmp, sizeof(uTmp), &BytesTransferred);
    uTmp &= mask;
    kprintf("[+] PML4(%x) ==> %llx\r\n", PML4, uTmp);
 
    status = ReadPhysicalAddress(
        (PVOID64)(uTmp + PDPE * 8), &uTmp, sizeof(uTmp), &BytesTransferred);
    uTmp &= mask;
    kprintf("[+] PDPE(%x) ==> %llx\r\n", PDPE, uTmp);
 
    status = ReadPhysicalAddress(
        (PVOID64)(uTmp + PDE * 8), &uTmp, sizeof(uTmp), &BytesTransferred);
    uTmp &= mask;
    kprintf("[+] PDE(%x) ==> %llx\r\n", PDE, uTmp);
 
    status = ReadPhysicalAddress(
        (PVOID64)(uTmp + PTE * 8), &uTmp, sizeof(uTmp), &BytesTransferred);
    uTmp &= mask;
    kprintf("[+] PTE(%x) ==> %llx\r\n", PTE, uTmp);
 
    *addr = uTmp + offset;
    kprintf("[+] physical address: %llx\r\n", *addr);
    return STATUS_SUCCESS;
}
/// @brief 传入DirBase值和虚拟地址后,回转化成一个物理地址返回
/// @param DirBase DirBase地址,传入一个UINT64值
/// @param addr 传入一个指向虚拟地址的指针,转化成物理地址后会修改这个指针的值
/// @return
NTSTATUS TranslateAddress(IN UINT64 DirBase, _Inout_ PUINT64 addr)
{
    UINT16   PML4, PDPE, PDE, PTE, offset;
    UINT64   mask = 0x7fffff000;
    UINT64   uTmp;
    SIZE_T   BytesTransferred;
    NTSTATUS status;
 
    offset = *addr & 0xfff;
    PTE    = (*addr >> 12) & 0x1ff;
    PDE    = (*addr >> (12 + 9)) & 0x1ff;
    PDPE   = (*addr >> (9 * 2 + 12)) & 0x1ff;
    PML4   = (*addr >> (9 * 3 + 12)) & 0x1ff;
 
    status = ReadPhysicalAddress(
        (PVOID64)(DirBase + PML4 * 8), &uTmp, sizeof(uTmp), &BytesTransferred);
    uTmp &= mask;
    kprintf("[+] PML4(%x) ==> %llx\r\n", PML4, uTmp);
 
    status = ReadPhysicalAddress(
        (PVOID64)(uTmp + PDPE * 8), &uTmp, sizeof(uTmp), &BytesTransferred);
    uTmp &= mask;
    kprintf("[+] PDPE(%x) ==> %llx\r\n", PDPE, uTmp);
 
    status = ReadPhysicalAddress(
        (PVOID64)(uTmp + PDE * 8), &uTmp, sizeof(uTmp), &BytesTransferred);
    uTmp &= mask;
    kprintf("[+] PDE(%x) ==> %llx\r\n", PDE, uTmp);
 
    status = ReadPhysicalAddress(
        (PVOID64)(uTmp + PTE * 8), &uTmp, sizeof(uTmp), &BytesTransferred);
    uTmp &= mask;
    kprintf("[+] PTE(%x) ==> %llx\r\n", PTE, uTmp);
 
    *addr = uTmp + offset;
    kprintf("[+] physical address: %llx\r\n", *addr);
    return STATUS_SUCCESS;
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING path)
{
    NTSTATUS status;
    UINT64   pid, uAddr, uDirBase;
    SIZE_T   BytesTransferred;
    UCHAR    charArry[40] = {0};
    UCHAR    example[40] = {"Yes I change memory by physical"};
 
    pid   = 10276;
    uAddr = 0x3629FAFB80;
 
    pDriver->DriverUnload = DriverUnload;
    // 手动指定进程号
    status = GetDirBaseByEprocess(pid, &uDirBase);
    if (!NT_SUCCESS(status)) {
        kprintf("[!] Get DirBase address failed!\r\n");
        return STATUS_UNSUCCESSFUL;
    }
 
    // 将虚拟地址转化成物理地址
    status = TranslateAddress(uDirBase, &uAddr);
    if (!NT_SUCCESS(status)) {
        kprintf("[!] Translate address failed!\r\n");
        return STATUS_UNSUCCESSFUL;
    }
 
    // 读取物理地址内容, 然后修改内容
    ReadPhysicalAddress((PVOID64)uAddr, charArry, 40, &BytesTransferred);
    kprintf("[+] data is %s\r\n", charArry);
 
    // 将example字符串写入物理内存
    WritePhysicalAddress((PVOID64)uAddr, example, 40, &BytesTransferred);
    kprintf("[+] Write end\r\n");
 
    return STATUS_SUCCESS;
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING path)
{
    NTSTATUS status;
    UINT64   pid, uAddr, uDirBase;
    SIZE_T   BytesTransferred;
    UCHAR    charArry[40] = {0};
    UCHAR    example[40] = {"Yes I change memory by physical"};
 
    pid   = 10276;
    uAddr = 0x3629FAFB80;
 
    pDriver->DriverUnload = DriverUnload;
    // 手动指定进程号
    status = GetDirBaseByEprocess(pid, &uDirBase);
    if (!NT_SUCCESS(status)) {
        kprintf("[!] Get DirBase address failed!\r\n");
        return STATUS_UNSUCCESSFUL;
    }
 
    // 将虚拟地址转化成物理地址
    status = TranslateAddress(uDirBase, &uAddr);
    if (!NT_SUCCESS(status)) {
        kprintf("[!] Translate address failed!\r\n");
        return STATUS_UNSUCCESSFUL;
    }
 
    // 读取物理地址内容, 然后修改内容

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 8
支持
分享
最新回复 (6)
雪    币: 2787
活跃值: (30801)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
感谢分享
2024-5-7 09:52
1
雪    币: 560
活跃值: (722)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
请问一下,使用MmMapIoSpaceEx的话,target os version为win7的话就过不了编译;使用MmMapIoSpace,Win10高版本就会失效;我为了兼容性使用的是ZwMapViewOfSection,但是无论是哪个系统,映射到PDE的时候,映射出的就不是PDE的地址了,但pdpte的地址和PDE的索引都是对的,该如何解决呢
2024-5-11 11:58
0
雪    币: 1856
活跃值: (1211)
能力值: ( LV5,RANK:75 )
在线值:
发帖
回帖
粉丝
4
ACZR 请问一下,使用MmMapIoSpaceEx的话,target os version为win7的话就过不了编译;使用MmMapIoSpace,Win10高版本就会失效;我为了兼容性使用的是ZwMapVi ...
MmMapIoSpaceEx最低支持的版本我看官方文档是win10, win7应该不行,你可以获取系统版本信息,然后根据版本信息选择MmMapIoSpaceEx或者MmMapIoSpace。至于PDE的值可能就需要手动调试看看具体的问题是什么了,我也不能确定
2024-5-13 16:14
0
雪    币: 560
活跃值: (722)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
mi1itray.axe MmMapIoSpaceEx最低支持的版本我看官方文档是win10, win7应该不行,你可以获取系统版本信息,然后根据版本信息选择MmMapIoSpaceEx或者MmMapIoSpace。至于PDE ...
是这样,带Ex的必须在Win10以上用,不带Ex的到了Win10高版本就无效了。为了兼容才用的ZwMapViewOfSection,但是这个函数映射到PDE就不对了,就很怪,我帖子里有发这个代码,如果有空的话可以帮忙看下
2024-5-13 17:46
0
雪    币: 0
活跃值: (225)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
拉闸了
2024-5-14 18:01
0
雪    币: 2
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
7

由于EAC的加密 所以如果想要读取被EAC的加密的游戏的话 需要另外获取进程的真实CR3(这个我已经实现了) 但是还存在一个问题,就是用MmCopy读取被EAC保护的内存时,会十分卡顿,于是我就对ReadPhysicalAddress函数做了一些修改,尽量不去使用MmCopy

auto readphysaddressV2(PVOID address, PVOID buffer, SIZE_T size, SIZE_T* read) -> NTSTATUS
{
	if (!address)
		return STATUS_UNSUCCESSFUL;

	PHYSICAL_ADDRESS physAddr;
	physAddr.QuadPart = (LONGLONG)address;
	PVOID virAddr = MmGetVirtualForPhysical(physAddr);
	if (!virAddr)
	{
		return STATUS_UNSUCCESSFUL;
	}

	RtlCopyMemory(buffer, virAddr, size);
	*read = size;

	return STATUS_SUCCESS;
}

这样改了之后 我读取其他进程没问题,但是读被EAC保护的游戏的话,就没法获取正确的值,有大佬知道是为什么吗?

2024-5-22 20:13
0
游客
登录 | 注册 方可回帖
返回
//