笨蛋の猫猫 发表于 2023-4-2 01:09

【代码注释】无法被检测的DMA物理读写内存设备到底是个啥

本帖最后由 笨蛋の猫猫 于 2023-4-2 01:37 编辑

我知道下面这位大佬 发的代码看起来有点难懂,但是如果这样看呢?
外挂界的大哥?号称无法被检测的DMA物理读写内存设备到底是个啥
https://www.52pojie.cn/thread-1767420-1-1.html
(出处: 吾爱破解论坛)


import memprocfs# 导入memprocfs模块,用于获取系统进程的内存映射信息
vmm = memprocfs.Vmm(['-device', 'existingremote'])# 创建一个Vmm对象并传入选项'-device'和'existingremote'
for process in vmm.process_list():# 遍历Vmm对象中所有进程列表
    for entry in process.maps.pte():# 遍历每个进程的映射表中的所有PTEs条目
      if '-rwx' in entry['flags']:# 判断该PTEs条目是否可读、可写、可执行
            print(str(process.pid) + ': ' + process.name + ': ' + str(entry))# 打印符合条件的进程PID、名称和PTEs条目

这段代码使用memprocfs模块和Vmm对象来遍历系统中所有进程的内存布局,并输出符合条件(即可读、可写、可执行)的页面的相关信息,对于调试和分析进程的内存使用情况非常有用。
char* temp_str[] = { "","-device","FPGA" };// 创建一个字符串数组,用于初始化VMM库
VMM_HANDLE handle = VMMDLL_Initialize(3, temp_str);// 调用VMMDLL_Initialize函数初始化VMM库并返回句柄

SIZE_T pcPIDs;// 定义一个变量pcPIDs,表示进程数目
VMMDLL_PidList(handle, nullptr, &pcPIDs);// 获取系统中所有进程的PID列表,并将进程数目存储在pcPIDs中
DWORD* pPIDs = (DWORD*)new char;// 在堆上分配一块内存,用于存储进程PID列表
VMMDLL_PidList(handle, pPIDs, &pcPIDs);// 将系统中所有进程的PID列表存储到pPIDs指向的缓冲区中

for (int i = 0; i < pcPIDs; i++)// 遍历所有进程
{
    VMMDLL_PROCESS_INFORMATION ProcessInformation = { 0 };// 定义一个进程信息结构体ProcessInformation,用于存储进程的相关信息
    ProcessInformation.magic = VMMDLL_PROCESS_INFORMATION_MAGIC;// 设置ProcessInformation的魔数为VMMDLL_PROCESS_INFORMATION_MAGIC
    ProcessInformation.wVersion = VMMDLL_PROCESS_INFORMATION_VERSION;// 设置ProcessInformation的版本号为VMMDLL_PROCESS_INFORMATION_VERSION
    SIZE_T pcbProcessInformation = sizeof(VMMDLL_PROCESS_INFORMATION);// 定义变量pcbProcessInformation,表示ProcessInformation结构体的大小
    VMMDLL_ProcessGetInformation(handle, pPIDs, &ProcessInformation, &pcbProcessInformation);// 获取指定进程的信息,并存储在ProcessInformation中

    std::cout << pPIDs << "---" << ProcessInformation.szName;// 输出当前进程的PID和名称

    VMMDLL_MAP_MODULEENTRY* ppModuleMapEntry = nullptr;// 定义一个指向VMMDLL_MAP_MODULEENTRY结构体的指针ppModuleMapEntry
    VMMDLL_Map_GetModuleFromNameU(handle, pPIDs, ProcessInformation.szName, &ppModuleMapEntry, VMMDLL_MODULE_FLAG_NORMAL);// 获取指定模块的信息,并将结果存储在ppModuleMapEntry中

    if (ppModuleMapEntry)// 如果获取到了模块信息
    {
      std::cout << "---" << ppModuleMapEntry->uszFullName << std::endl;// 输出该模块的完整路径
      if (ProcessInformation.szName == std::string("dwm.exe"))// 如果当前进程是桌面窗口管理器
      {
            std::cout << "IMAGE:" << std::hex << ppModuleMapEntry->vaBase << std::endl;// 输出模块的基地址
            ULONG temp = 0;
            VMMDLL_MemRead(handle, pPIDs, ppModuleMapEntry->vaBase, (PBYTE)&temp, 4);// 读取内存页面信息
            std::cout << "temp:" << temp << std::endl;// 输出读取到的内容
            temp = 0;
            VMMDLL_MemWrite(handle, pPIDs, ppModuleMapEntry->vaBase, (PBYTE)&temp, 4);// 修改内存页面信息
            VMMDLL_MemRead(handle, pPIDs, ppModuleMapEntry->vaBase, (PBYTE)&temp, 4);// 再次读取内存页面信息
            std::cout << "temp:" << temp << std::endl;// 输出修改后的内容
      }
    }
    else// 如果没有获取到模块信息
    {
      std::cout << std::endl;// 输出一个换行符
    }
}

这段代码使用了VMM库提供的函数,通过遍历进程列表、获取进程信息和模块信息,并读写进程的内存页面,用于实现对某些进程的监视和调试。
下面是对上面代码的每个函数的注释:

    // 创建一个字符串数组temp_str,用于初始化VMM库时的选项
    char* temp_str[] = { "","-device","FPGA" };

    // 调用VMMDLL_Initialize函数初始化VMM库,并将句柄存储在handle中
    VMM_HANDLE handle = VMMDLL_Initialize(3, temp_str);

    // 定义变量pcPIDs,表示系统中进程的数量
    SIZE_T pcPIDs;

    // 获取系统中所有进程的PID列表,并将进程数目保存在pcPIDs中
    VMMDLL_PidList(handle, nullptr, &pcPIDs);

    // 在堆上分配一块内存,用于存储进程PID列表
    DWORD* pPIDs = (DWORD*)new char;

    // 将系统中所有进程的PID列表存储到pPIDs指向的缓冲区中
    VMMDLL_PidList(handle, pPIDs, &pcPIDs);

    // 遍历所有系统进程
    for (int i = 0; i < pcPIDs; i++) {

    // 定义一个结构体ProcessInformation,用于存储进程信息
    VMMDLL_PROCESS_INFORMATION ProcessInformation = { 0 };
   
    // 设置ProcessInformation的魔数
    ProcessInformation.magic = VMMDLL_PROCESS_INFORMATION_MAGIC;
   
    // 设置ProcessInformation的版本号
    ProcessInformation.wVersion = VMMDLL_PROCESS_INFORMATION_VERSION;
   
    // 定义变量pcbProcessInformation,表示ProcessInformation结构体的大小
    SIZE_T pcbProcessInformation = sizeof(VMMDLL_PROCESS_INFORMATION);
   
    // 获取指定进程的信息,并将结果存储在ProcessInformation中
    VMMDLL_ProcessGetInformation(handle, pPIDs, &ProcessInformation, &pcbProcessInformation);

    // 定义一个指向VMMDLL_MAP_MODULEENTRY结构体的指针ppModuleMapEntry
    VMMDLL_MAP_MODULEENTRY* ppModuleMapEntry = nullptr;
   
    // 获取指定模块的信息,并将结果存储在ppModuleMapEntry中
    VMMDLL_Map_GetModuleFromNameU(handle, pPIDs, ProcessInformation.szName, &ppModuleMapEntry, VMMDLL_MODULE_FLAG_NORMAL);
   
    // 判断是否成功获取到模块的信息
    if (ppModuleMapEntry) {
      
      // 定义一个变量temp,用于存储从内存中读取的数据
      ULONG temp = 0;
      
      // 读取指定模块的内存页面信息
      VMMDLL_MemRead(handle, pPIDs, ppModuleMapEntry->vaBase, (PBYTE)&temp, 4);
      
      // 修改指定模块的内存页面信息
      VMMDLL_MemWrite(handle, pPIDs, ppModuleMapEntry->vaBase, (PBYTE)&temp, 4);
      
      // 输出当前进程的PID和名称
      std::cout << pPIDs << "---" << ProcessInformation.szName;
      
      // 输出当前模块的完整路径
      std::cout << "---" << ppModuleMapEntry->uszFullName << std::endl;
      
      // 输出从内存中读取的数据
      std::cout << "temp:" << temp << std::endl;
      
      // 输出修改后从内存中读取的数据
      std::cout << "temp:" << temp << std::endl;
    }
}





typedef struct tdVMMDLL_PROCESS_INFORMATION {
    ULONG64 magic;                              // 魔数,用于检查结构体是否合法
    WORD wVersion;                              // 结构体版本号
    WORD wSize;                                 // 结构体大小
    VMMDLL_MEMORYMODEL_TP tpMemoryModel;      // 内存模型类型,使用VMMDLL_MEMORYMODEL_*枚举类型表示
    VMMDLL_SYSTEM_TP tpSystem;                  // 系统类型,使用VMMDLL_SYSTEM_*枚举类型表示
    BOOL fUserOnly;                           // 是否只列出用户模式页面
    DWORD dwPID;                              // 进程ID
    DWORD dwPPID;                               // 父进程ID
    DWORD dwState;                              // 进程状态
    CHAR szName;                            // 进程名称,最长为15个字符(不含空字符)
    CHAR szNameLong;                        // 进程完整名称,最长为63个字符(不含空字符)
    ULONG64 paDTB;                              // 进程页目录表的物理地址
    ULONG64 paDTB_UserOpt;                      // 可能不存在,表示用户模式页目录表的物理地址
    struct {
      ULONG64 vaEPROCESS;                     // EPROCESS结构的虚拟地址
      ULONG64 vaPEB;                        // PEB结构的虚拟地址
      ULONG64 _Reserved1;                     // 保留字段
      BOOL fWow64;                            // 进程是否是32位应用程序(只有在64位系统上才有)
      DWORD vaPEB32;                        // 32位应用程序的PEB结构虚拟地址(只有在64位系统上才有)
      DWORD dwSessionId;                      // 进程所属会话ID
      ULONG64 qwLUID;                         // 进程所属用户的唯一标识符
      CHAR szSID;                   // 进程所属用户的安全标识符(SID)
      VMMDLL_PROCESS_INTEGRITY_LEVEL IntegrityLevel;// 进程完整性级别,使用VMMDLL_PROCESS_INTEGRITY_LEVEL枚举类型表示
    } win;
} VMMDLL_PROCESS_INFORMATION, *PVMMDLL_PROCESS_INFORMATION;

这是一个定义了进程信息的结构体。其中包括了进程的基本信息和其他一些详细信息,如进程的内存模型类型、系统类型、进程名称等。




typedef struct tdVMMDLL_MAP_MODULEENTRY {
    QWORD vaBase;                                           // 模块基址的虚拟地址
    QWORD vaEntry;                                          // 模块入口点的虚拟地址
    DWORD cbImageSize;                                    // 模块在内存中的映像大小
    BOOLfWoW64;                                           // 模块是否为32位应用程序(只有在64位系统上才有)
    union { LPSTRuszText; LPWSTR wszText; };            // 模块名称,使用LPSTR或LPWSTR表示(取决于编译选项)
    DWORD _Reserved3;                                       // 保留字段
    DWORD _Reserved4;                                       // 保留字段
    union { LPSTRuszFullName; LPWSTR wszFullName; };      // 模块完整路径,使用LPSTR或LPWSTR表示(取决于编译选项)
    VMMDLL_MODULE_TP tp;                                    // 模块类型,使用VMMDLL_MODULE_TP枚举类型表示
    DWORD cbFileSizeRaw;                                    // 模块文件大小
    DWORD cSection;                                       // 模块的节数
    DWORD cEAT;                                             // 导出函数表的数量(Export Address Table)
    DWORD cIAT;                                             // 导入函数表的数量(Import Address Table)
    DWORD _Reserved2;                                       // 保留字段
    QWORD _Reserved1;                                    // 保留字段
    PVMMDLL_MAP_MODULEENTRY_DEBUGINFO pExDebugInfo;         // 扩展调试信息,仅在指定了VMMDLL_MODULE_FLAG_DEBUGINFO标志时包含
    PVMMDLL_MAP_MODULEENTRY_VERSIONINFO pExVersionInfo;   // 扩展版本信息,仅在指定了VMMDLL_MODULE_FLAG_VERSIONINFO标志时包含
} VMMDLL_MAP_MODULEENTRY, *PVMMDLL_MAP_MODULEENTRY;

这是一个定义了模块信息的结构体。其中包括了模块的基本信息和其他一些详细信息,如模块的名称、完整路径、大小等。需要注意的是,该结构体中的某些字段可能仅适用于特定的操作系统平台或CPU体系结构。同时,该结构体中还包括了扩展的调试和版本信息,只有在指定了相应的编译选项时才会包含。


该代码主要用于演示在Windows操作系统上使用VMM库进行进程和内存的监视和调试,仅供学习和参考目的。在实际使用时,应遵循相关法规,并确保以安全的方式使用该功能!

感谢@最后的戴托纳提供的代码开源!以上注释仅用于方便理解学习与交流!

打金者BT 发表于 2023-4-3 17:21

不知道为啥复制粘贴都跑不起来
vmm = memprocfs.Vmm(['-device', 'existingremote'])
报错:
TypeError: Vmm.init(): Initialization of vmm failed.

笨蛋の猫猫 发表于 2023-4-3 20:33

打金者BT 发表于 2023-4-3 17:21
不知道为啥复制粘贴都跑不起来
vmm = memprocfs.Vmm(['-device', 'existingremote'])
报错:


看这个报错应该是缺少了 memprocfs 模块或者 memprocfs 模块的某些依赖库

import memprocfs
装一下memprocfs 模块试一下

如果 memprocfs 模块已经正确安装
可以尝试调整 Vmm 的初始化参数,例如:

vmm = memprocfs.Vmm(['-device', 'existingremote', '-physmem', '1024M'])
这里我添加了一个 "-physmem" 参数来指定虚拟机的物理内存大小
你可以根据需要调整参数,在运行一下试试!

打金者BT 发表于 2023-4-4 09:06

笨蛋の猫猫 发表于 2023-4-3 20:33
看这个报错应该是缺少了 memprocfs 模块或者 memprocfs 模块的某些依赖库



memprocfs 已经安装了,调整了参数之后也是不行,还是一样的报错,有机会在研究吧

bg2qna 发表于 2023-4-4 14:44

DMA 2年游戏科技用户路过。。

淡水千痕 发表于 2023-4-4 18:01

本帖最后由 淡水千痕 于 2023-4-4 18:03 编辑

这是我用chatGPT注释的代码// 定义一个字符指针数组temp_str,用于存储传递给VMM_HANDLE对象的参数
char* temp_str[] = { "","-device","FPGA" };

// 初始化VMM_HANDLE对象
VMM_HANDLE handle = VMMDLL_Initialize(3, temp_str);   

// 定义一个SIZE_T类型的变量pcPIDs
SIZE_T pcPIDs;

// 调用VMMDLL_PidList函数获取进程ID列表
VMMDLL_PidList(handle, nullptr, &pcPIDs);

// 为存储进程ID的指针分配内存
DWORD* pPIDs = (DWORD*)new char;

// 再次调用VMMDLL_PidList函数获取进程ID列表
VMMDLL_PidList(handle, pPIDs, &pcPIDs);

// 遍历进程ID列表
for (int i = 0; i < pcPIDs; i++) {                     
    // 定义一个VMMDLL_PROCESS_INFORMATION结构体变量ProcessInformation,并初始化
    VMMDLL_PROCESS_INFORMATION ProcessInformation = { 0 };         
    ProcessInformation.magic = VMMDLL_PROCESS_INFORMATION_MAGIC;         
    ProcessInformation.wVersion = VMMDLL_PROCESS_INFORMATION_VERSION;         
    SIZE_T pcbProcessInformation = sizeof(VMMDLL_PROCESS_INFORMATION);         
   
    // 调用VMMDLL_ProcessGetInformation函数获取进程信息
    VMMDLL_ProcessGetInformation(handle, pPIDs, &ProcessInformation, &pcbProcessInformation);         
   
    // 输出进程ID和进程名
    std::cout << pPIDs << "---" << ProcessInformation.szName;         
   
    // 定义一个VMMDLL_MAP_MODULEENTRY类型的指针ppModuleMapEntry,并初始化为nullptr
    VMMDLL_MAP_MODULEENTRY* ppModuleMapEntry = nullptr;         
   
    // 调用VMMDLL_Map_GetModuleFromNameU函数获取模块信息
    VMMDLL_Map_GetModuleFromNameU(handle, pPIDs, ProcessInformation.szName, &ppModuleMapEntry,VMMDLL_MODULE_FLAG_NORMAL);         
   
    // 如果获取到了模块信息
    if (ppModuleMapEntry) {               
      // 输出模块
std::cout << "---" << ppModuleMapEntry->uszFullName << std::endl;
      
      // 如果进程名为"dwm.exe"
      if (ProcessInformation.szName == std::string("dwm.exe")) {               
            // 输出模块的基地址
            std::cout << "IMAGE:"<<std::hex << ppModuleMapEntry->vaBase << std::endl;
            
            // 定义一个ULONG类型的变量temp,并初始化为0
            ULONG temp = 0;
            
            // 调用VMMDLL_MemRead函数读取模块内存,并输出结果
            VMMDLL_MemRead(handle, pPIDs, ppModuleMapEntry->vaBase, (PBYTE)&temp, 4);            
            std::cout << "temp:" << temp << std::endl;
            
            // 将temp设置为0,并再次读取模块内存
            temp = 0;            
            VMMDLL_MemWrite(handle, pPIDs, ppModuleMapEntry->vaBase, (PBYTE)&temp, 4);            
            VMMDLL_MemRead(handle, pPIDs, ppModuleMapEntry->vaBase, (PBYTE)&temp, 4);            
            std::cout << "temp:" << temp << std::endl;               
      }         
    } else {               
      std::cout << std::endl;         
    }            
}
// 定义一个结构体tdVMMDLL_PROCESS_INFORMATION,用于存储进程信息
typedef struct tdVMMDLL_PROCESS_INFORMATION {
    ULONG64 magic; // 魔数
    WORD wVersion; // 版本号
    WORD wSize; // 结构体大小
    VMMDLL_MEMORYMODEL_TP tpMemoryModel; // 内存模型类型
    VMMDLL_SYSTEM_TP tpSystem; // 系统类型
    BOOL fUserOnly; // 是否只列出用户模式页面
    DWORD dwPID; // 进程ID
    DWORD dwPPID; // 父进程ID
    DWORD dwState; // 进程状态
    CHAR szName; // 进程名
    CHAR szNameLong; // 进程全名
    ULONG64 paDTB; // DTB地址
    ULONG64 paDTB_UserOpt; // 可能不存在的用户DTB地址
    struct {
      ULONG64 vaEPROCESS; // EPROCESS虚拟地址
      ULONG64 vaPEB; // PEB虚拟地址
      ULONG64 _Reserved1; // 保留字段
      BOOL fWow64; // 是否是WoW64进程
      DWORD vaPEB32; // WoW64进程的PEB虚拟地址
      DWORD dwSessionId; // 会话ID
      ULONG64 qwLUID; // LUID
      CHAR szSID; // SID
      VMMDLL_PROCESS_INTEGRITY_LEVEL IntegrityLevel; // 进程完整性级别
    } win;
} VMMDLL_PROCESS_INFORMATION, *PVMMDLL_PROCESS_INFORMATION;
// 定义一个结构体tdVMMDLL_MAP_MODULEENTRY,用于存储模块信息
typedef struct tdVMMDLL_MAP_MODULEENTRY {
    QWORD vaBase; // 模块基地址
    QWORD vaEntry; // 模块入口地址
    DWORD cbImageSize; // 模块映像大小
    BOOLfWoW64; // 是否是WoW64模块
    union {
      LPSTRuszText; // 模块文件名(ANSI字符串)
      LPWSTR wszText; // 模块文件名(Unicode字符串)
    }; // 模块文件名
    DWORD _Reserved3; // 保留字段
    DWORD _Reserved4; // 保留字段
    union {
      LPSTRuszFullName; // 模块完整路径(ANSI字符串)
      LPWSTR wszFullName; // 模块完整路径(Unicode字符串)
    }; // 模块完整路径
    VMMDLL_MODULE_TP tp; // 模块类型
    DWORD cbFileSizeRaw; // 文件大小(字节)
    DWORD cSection; // 节的数量
    DWORD cEAT; // 导出函数数量
    DWORD cIAT; // 导入函数数量
    DWORD _Reserved2; // 保留字段
    QWORD _Reserved1; // 保留字段
    PVMMDLL_MAP_MODULEENTRY_DEBUGINFO pExDebugInfo; // 调试信息
    PVMMDLL_MAP_MODULEENTRY_VERSIONINFO pExVersionInfo; // 版本信息
} VMMDLL_MAP_MODULEENTRY, *PVMMDLL_MAP_MODULEENTRY;

暮光之城 发表于 2023-4-6 13:44

bg2qna 发表于 2023-4-4 14:44
DMA 2年游戏科技用户路过。。

是不是要出新的硬件了 ?

ZhangYongcun 发表于 2023-7-22 12:01

xuanyuzaixian 发表于 2023-7-23 16:29

要出新的硬件了 ?

bg2qna 发表于 2023-7-24 10:46

暮光之城 发表于 2023-4-6 13:44
是不是要出新的硬件了 ?

DMA 硬件无非25T 35T 75T 100T
科技软件也就那么多。
主要还是看针对游戏的各厂商提供的固件,大概就是伪装驱动的意思
页: [1] 2
查看完整版本: 【代码注释】无法被检测的DMA物理读写内存设备到底是个啥