吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 6663|回复: 10
上一主题 下一主题
收起左侧

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

[复制链接]
跳转到指定楼层
楼主
笨蛋の猫猫 发表于 2023-4-2 01:09 回帖奖励
本帖最后由 笨蛋の猫猫 于 2023-4-2 01:37 编辑

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

[Python] 纯文本查看 复制代码
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对象来遍历系统中所有进程的内存布局,并输出符合条件(即可读、可写、可执行)的页面的相关信息,对于调试和分析进程的内存使用情况非常有用。
[C++] 纯文本查看 复制代码
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[pcPIDs * 4];  // 在堆上分配一块内存,用于存储进程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[i], &ProcessInformation, &pcbProcessInformation);  // 获取指定进程的信息,并存储在ProcessInformation中

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

    VMMDLL_MAP_MODULEENTRY* ppModuleMapEntry = nullptr;  // 定义一个指向VMMDLL_MAP_MODULEENTRY结构体的指针ppModuleMapEntry
    VMMDLL_Map_GetModuleFromNameU(handle, pPIDs[i], 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[i], ppModuleMapEntry->vaBase, (PBYTE)&temp, 4);  // 读取内存页面信息
            std::cout << "temp:" << temp << std::endl;  // 输出读取到的内容
            temp = 0;  
            VMMDLL_MemWrite(handle, pPIDs[i], ppModuleMapEntry->vaBase, (PBYTE)&temp, 4);  // 修改内存页面信息
            VMMDLL_MemRead(handle, pPIDs[i], ppModuleMapEntry->vaBase, (PBYTE)&temp, 4);  // 再次读取内存页面信息
            std::cout << "temp:" << temp << std::endl;  // 输出修改后的内容
        }
    }
    else  // 如果没有获取到模块信息
    {
        std::cout << std::endl;  // 输出一个换行符
    }
}

这段代码使用了VMM库提供的函数,通过遍历进程列表、获取进程信息和模块信息,并读写进程的内存页面,用于实现对某些进程的监视和调试。
下面是对上面代码的每个函数的注释:
[C++] 纯文本查看 复制代码
    // 创建一个字符串数组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[pcPIDs * 4];

    // 将系统中所有进程的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[i], &ProcessInformation, &pcbProcessInformation);

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




[C++] 纯文本查看 复制代码
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[16];                            // 进程名称,最长为15个字符(不含空字符)
    CHAR szNameLong[64];                        // 进程完整名称,最长为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[MAX_PATH];                   // 进程所属用户的安全标识符(SID)
        VMMDLL_PROCESS_INTEGRITY_LEVEL IntegrityLevel;  // 进程完整性级别,使用VMMDLL_PROCESS_INTEGRITY_LEVEL枚举类型表示
    } win;
} VMMDLL_PROCESS_INFORMATION, *PVMMDLL_PROCESS_INFORMATION;

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



[C++] 纯文本查看 复制代码
typedef struct tdVMMDLL_MAP_MODULEENTRY {
    QWORD vaBase;                                           // 模块基址的虚拟地址
    QWORD vaEntry;                                          // 模块入口点的虚拟地址
    DWORD cbImageSize;                                      // 模块在内存中的映像大小
    BOOL  fWoW64;                                           // 模块是否为32位应用程序(只有在64位系统上才有)
    union { LPSTR  uszText; LPWSTR wszText; };              // 模块名称,使用LPSTR或LPWSTR表示(取决于编译选项)
    DWORD _Reserved3;                                       // 保留字段
    DWORD _Reserved4;                                       // 保留字段
    union { LPSTR  uszFullName; 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[3];                                    // 保留字段
    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库进行进程和内存的监视和调试,仅供学习和参考目的。在实际使用时,应遵循相关法规,并确保以安全的方式使用该功能!

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

免费评分

参与人数 1吾爱币 +7 热心值 +1 收起 理由
Hmily + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

沙发
打金者BT 发表于 2023-4-3 17:21
不知道为啥复制粘贴都跑不起来
vmm = memprocfs.Vmm(['-device', 'existingremote'])
报错:
TypeError: Vmm.init(): Initialization of vmm failed.
3#
 楼主| 笨蛋の猫猫 发表于 2023-4-3 20:33 |楼主
打金者BT 发表于 2023-4-3 17:21
不知道为啥复制粘贴都跑不起来
vmm = memprocfs.Vmm(['-device', 'existingremote'])
报错:

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

[Python] 纯文本查看 复制代码
import memprocfs

装一下memprocfs 模块试一下

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

[Python] 纯文本查看 复制代码
vmm = memprocfs.Vmm(['-device', 'existingremote', '-physmem', '1024M'])

这里我添加了一个 "-physmem" 参数来指定虚拟机的物理内存大小
你可以根据需要调整参数,在运行一下试试!
4#
打金者BT 发表于 2023-4-4 09:06
笨蛋の猫猫 发表于 2023-4-3 20:33
看这个报错应该是缺少了 memprocfs 模块或者 memprocfs 模块的某些依赖库

[mw_shl_code=python,true ...

memprocfs 已经安装了,调整了参数之后也是不行,还是一样的报错,有机会在研究吧
5#
bg2qna 发表于 2023-4-4 14:44
DMA 2年游戏科技用户路过。。

点评

是不是要出新的硬件了 ?  详情 回复 发表于 2023-4-6 13:44
6#
淡水千痕 发表于 2023-4-4 18:01
本帖最后由 淡水千痕 于 2023-4-4 18:03 编辑

这是我用chatGPT注释的代码
[C++] 纯文本查看 复制代码
// 定义一个字符指针数组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[pcPIDs * 4]; 

// 再次调用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[i], &ProcessInformation, &pcbProcessInformation);           
    
    // 输出进程ID和进程名
    std::cout << pPIDs[i] << "---" << ProcessInformation.szName;           
    
    // 定义一个VMMDLL_MAP_MODULEENTRY类型的指针ppModuleMapEntry,并初始化为nullptr
    VMMDLL_MAP_MODULEENTRY* ppModuleMapEntry = nullptr;         
    
    // 调用VMMDLL_Map_GetModuleFromNameU函数获取模块信息
    VMMDLL_Map_GetModuleFromNameU(handle, pPIDs[i], 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[i], ppModuleMapEntry->vaBase, (PBYTE)&temp, 4);             
            std::cout << "temp:" << temp << std::endl; 
            
            // 将temp设置为0,并再次读取模块内存
            temp = 0;             
            VMMDLL_MemWrite(handle, pPIDs[i], ppModuleMapEntry->vaBase, (PBYTE)&temp, 4);             
            VMMDLL_MemRead(handle, pPIDs[i], ppModuleMapEntry->vaBase, (PBYTE)&temp, 4);             
            std::cout << "temp:" << temp << std::endl;                 
        }         
    } else {                
        std::cout << std::endl;         
    }             
}

[C++] 纯文本查看 复制代码
// 定义一个结构体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[16]; // 进程名
    CHAR szNameLong[64]; // 进程全名
    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[MAX_PATH]; // SID
        VMMDLL_PROCESS_INTEGRITY_LEVEL IntegrityLevel; // 进程完整性级别
    } win;
} VMMDLL_PROCESS_INFORMATION, *PVMMDLL_PROCESS_INFORMATION;

[C++] 纯文本查看 复制代码
// 定义一个结构体tdVMMDLL_MAP_MODULEENTRY,用于存储模块信息
typedef struct tdVMMDLL_MAP_MODULEENTRY {
    QWORD vaBase; // 模块基地址
    QWORD vaEntry; // 模块入口地址
    DWORD cbImageSize; // 模块映像大小
    BOOL  fWoW64; // 是否是WoW64模块
    union {
        LPSTR  uszText; // 模块文件名(ANSI字符串)
        LPWSTR wszText; // 模块文件名(Unicode字符串)
    }; // 模块文件名
    DWORD _Reserved3; // 保留字段
    DWORD _Reserved4; // 保留字段
    union {
        LPSTR  uszFullName; // 模块完整路径(ANSI字符串)
        LPWSTR wszFullName; // 模块完整路径(Unicode字符串)
    }; // 模块完整路径
    VMMDLL_MODULE_TP tp; // 模块类型
    DWORD cbFileSizeRaw; // 文件大小(字节)
    DWORD cSection; // 节的数量
    DWORD cEAT; // 导出函数数量
    DWORD cIAT; // 导入函数数量
    DWORD _Reserved2; // 保留字段
    QWORD _Reserved1[3]; // 保留字段
    PVMMDLL_MAP_MODULEENTRY_DEBUGINFO pExDebugInfo; // 调试信息
    PVMMDLL_MAP_MODULEENTRY_VERSIONINFO pExVersionInfo; // 版本信息
} VMMDLL_MAP_MODULEENTRY, *PVMMDLL_MAP_MODULEENTRY;
7#
暮光之城 发表于 2023-4-6 13:44
bg2qna 发表于 2023-4-4 14:44
DMA 2年游戏科技用户路过。。

是不是要出新的硬件了 ?
头像被屏蔽
8#
ZhangYongcun 发表于 2023-7-22 12:01
提示: 该帖被管理员或版主屏蔽
9#
xuanyuzaixian 发表于 2023-7-23 16:29
要出新的硬件了 ?
10#
bg2qna 发表于 2023-7-24 10:46
暮光之城 发表于 2023-4-6 13:44
是不是要出新的硬件了 ?

DMA 硬件无非25T 35T 75T 100T
科技软件也就那么多。
主要还是看针对游戏的各厂商提供的固件,大概就是伪装驱动的意思
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-21 18:28

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表