【代码注释】无法被检测的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库进行进程和内存的监视和调试,仅供学习和参考目的。在实际使用时,应遵循相关法规,并确保以安全的方式使用该功能!
感谢@最后的戴托纳提供的代码开源!以上注释仅用于方便理解学习与交流! 不知道为啥复制粘贴都跑不起来
vmm = memprocfs.Vmm(['-device', 'existingremote'])
报错:
TypeError: Vmm.init(): Initialization of vmm failed. 打金者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" 参数来指定虚拟机的物理内存大小
你可以根据需要调整参数,在运行一下试试! 笨蛋の猫猫 发表于 2023-4-3 20:33
看这个报错应该是缺少了 memprocfs 模块或者 memprocfs 模块的某些依赖库
用
memprocfs 已经安装了,调整了参数之后也是不行,还是一样的报错,有机会在研究吧 DMA 2年游戏科技用户路过。。 本帖最后由 淡水千痕 于 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; bg2qna 发表于 2023-4-4 14:44
DMA 2年游戏科技用户路过。。
是不是要出新的硬件了 ? 要出新的硬件了 ? 暮光之城 发表于 2023-4-6 13:44
是不是要出新的硬件了 ?
DMA 硬件无非25T 35T 75T 100T
科技软件也就那么多。
主要还是看针对游戏的各厂商提供的固件,大概就是伪装驱动的意思
页:
[1]
2