|
image
一款完全免费的内核级内存读写工具,可突破驱动保护,强制读写应用层任意进程内存数据,驱动工具目前支持读写整数,字节,字节集,单精度浮点数,双精度浮点数,多级偏移读写,取模块地址,分配远程内存等功能,读写效率高,速度快,兼容性好,使用时需自己签名或在测试模式下。
C++ 调用接口
目前驱动读写支持的读写函数如下表所示,需要注意的是SwitchDriver在基础版本中不存在,如需使用请购买Pro专业版,专业版与基础版唯一的区别是在读写方式上,专业版具有更强的读写模式,而基础版则只支持Cr3读写模式;
导出函数 | 函数作用 | BOOL SwitchDriver(PCHAR pSwitch) | 切换内存条模式(Pro) | BOOL SetPid(DWORD Pid) | 设置全局进程PID | BOOL Read(ULONG64 address, T* ret) | 自定义读内存 | BOOL Write(ULONG64 address, T data) | 自定义读内存 | BOOL ReadMemoryDWORD(ULONG64 addre, DWORD * ret) | 读内存DWORD | BOOL ReadMemoryDWORD64(ULONG64 addre, DWORD64 * ret) | 读内存DWORD64 | BOOL ReadMemoryBytes(ULONG64 addre, BYTE **ret, DWORD sizes) | 读内存字节 | BOOL ReadMemoryFloat(ULONG64 addre, float* ret) | 读内存浮点数 | BOOL ReadMemoryDouble(ULONG64 addre, double* ret) | 读内存双精度浮点数 | BOOL WriteMemoryBytes(ULONG64 addre, BYTE * data, DWORD sizes) | 写内存字节 | BOOL WriteMemoryDWORD(ULONG64 addre, DWORD ret) | 写内存DWORD | BOOL WriteMemoryDWORD64(ULONG64 addre, DWORD64 ret) | 写内存DWORD64 | BOOL WriteMemoryFloat(ULONG64 addre, float ret) | 写内存浮点数 | BOOL WriteMemoryDouble(ULONG64 addre, double ret) | 写内存双精度浮点数 | DWORD ReadDeviationMemory32(ProcessDeviationMemory *read_offset_struct) | 计算32位偏移数据基址 | DWORD64 ReadDeviationMemory64(ProcessDeviationMemory *read_offset_struct) | 计算64位偏移数据基址 | DWORD64 GetModuleAddress(std::string dllname) | 驱动读取进程模块基地址 | DWORD64 GetSystemRoutineAddress(std::string funcname) | 获取系统函数内存地址 | DWORD64 CreateRemoteMemory(DWORD length) | 在对端分配内存空间 | DWORD DeleteRemoteMemory(DWORD64 address, DWORD length) | 销毁对端内存 | 新版本读写API接口在读写内存之前需要提前设置进程PID号,后期的调用将不需要再传入进程PID,此类读写适合长期读,某些FPS射击类游戏的人物数组,3D类游戏坐标由于坐标会频繁移动,需持续不间断读取,此读写模块将很适,接下来将带大家分析并简单使用这些API接口实现功能。
在使用LyMemoryLib静态库之前请确保您已经正确的配置了Visual Studio引用头文件。
image
如何安装与卸载驱动: 读写的第一步是安装驱动并将其运行,当然你可以通过第三方组件对驱动进行安装,也可以使用LyMemoryLib中的函数实现安装,如下则是通过LyMemoryLib.hpp将驱动加载的完整实现;
// 署名权
// right to sign one's name on a piece of work
// PowerBy: LyShark
// Email: me@lyshark.com
#include "LyMemoryLib.h"
#include <Windows.h>
#include <iostream>
#pragma comment(lib,&#34;advapi32.lib&#34;)
#pragma comment(lib,&#34;LyMemoryLib.lib&#34;)
// 安装驱动
BOOL InstallDriver(LyMemoryDrvCtrl Memory)
{
char szSysFile[MAX_PATH] = { 0 };
char szSvcLnkName[] = &#34;LyMemory&#34;;;
BOOL ref = FALSE;
DWORD index = 0;
// 获取完整路径
Memory.GetAppPath(szSysFile);
strcat_s(szSysFile, &#34;LyMemory.sys&#34;);
printf(&#34;驱动路径: %s \n&#34;, szSysFile);
index = index + 1;
// 安装驱动
ref = Memory.Install(szSysFile, szSvcLnkName, szSvcLnkName);
printf(&#34;安装状态: %d \n&#34;, ref);
index = index + 1;
// 启动驱动
ref = Memory.Start();
printf(&#34;启动状态: %d \n&#34;, ref);
index = index + 1;
// 打开
ref = Memory.Open(&#34;\\\\.\\LyMemory&#34;);
printf(&#34;打开状态: %d \n&#34;, ref);
index = index + 1;
if (index == 4 && ref == TRUE)
{
return TRUE;
}
return FALSE;
}
// 卸载驱动
BOOL RemoveDriver(LyMemoryDrvCtrl Memory)
{
BOOL ref = 0;
// 关闭
ref = Memory.Stop();
printf(&#34;关闭状态: %d \n&#34;, ref);
// 移除
ref = Memory.Remove();
printf(&#34;移除状态: %d \n&#34;, ref);
return ref;
}
int main(int argc, char* argv[])
{
LyMemoryDrvCtrl DriveControl;
// 加载驱动
BOOL ref = InstallDriver(DriveControl);
if (ref == TRUE)
{
printf(&#34;
驱动已加载 \n&#34;);
}
// 卸载驱动
RemoveDriver(DriveControl);
system(&#34;pause&#34;);
return 0;
}如上代码编译后并以管理员权限运行,则会将驱动LyMemory.sys自动加载,并在调试板输出如下图所示的信息;
image
设置PID进程绑定: 如果需要使用读写函数,第一步则是设置进程PID绑定,通常可通过SetPid(DWORD Pid)函数传入进程PID进行绑定操作,一旦进程被绑定则后续无需再次打开,提高了读写效率,也可预防多次附加脱离导致应用层异常,如果需要使用设置PID则你可以这样来写;
// 署名权
// right to sign one&#39;s name on a piece of work
// PowerBy: LyShark
// Email: me@lyshark.com
#include &#34;LyMemoryLib.h&#34;
#include <Windows.h>
#include <iostream>
#pragma comment(lib,&#34;advapi32.lib&#34;)
#pragma comment(lib,&#34;LyMemoryLib.lib&#34;)
int main(int argc, char *argv[])
{
LyMemoryDrvCtrl DriveControl;
DriveControl.InstallAndRun();
BOOL set_pid = DriveControl.SetPid(6536);
if (set_pid == TRUE)
{
printf(&#34;
设置PID = %d \n&#34;, set_pid);
}
system(&#34;pause&#34;);
return 0;
}运行如上代码所示将自动绑定到进程6536并输出绑定状态,如下图所示;
image
内核读取模块基址: 由于目前进程已被附加到到驱动上,此时可以调用GetModuleAddress()获取进程内特定模块的基址,此函数接收一个模块名;
// 署名权
// right to sign one&#39;s name on a piece of work
// PowerBy: LyShark
// Email: me@lyshark.com
#include &#34;LyMemoryLib.h&#34;
#include <Windows.h>
#include <iostream>
#pragma comment(lib,&#34;advapi32.lib&#34;)
#pragma comment(lib,&#34;LyMemoryLib.lib&#34;)
int main(int argc, char *argv[])
{
LyMemoryDrvCtrl DriveControl;
DriveControl.InstallAndRun();
BOOL set_pid = DriveControl.SetPid(6536);
if (set_pid == TRUE)
{
printf(&#34;
设置PID = %d \n&#34;, set_pid);
}
// 取模块基址
DWORD64 user32 = DriveControl.GetModuleAddress(&#34;user32.dll&#34;);
printf(&#34;user32 = 0x%p \n&#34;, user32);
DWORD64 kernel32 = DriveControl.GetModuleAddress(&#34;kernel32.dll&#34;);
printf(&#34;kernel32 = 0x%p \n&#34;, kernel32);
system(&#34;pause&#34;);
return 0;
}如上代码编译并运行,则取出被附加进程内user32.dll以及kernel32.dll的模块基址,输出效果图如下所示;
image
取内核函数基址: 与取应用层模块基址类似,函数GetSystemRoutineAddress可用于获取到内核模块中特定导出函数的内存基址。
// 署名权
// right to sign one&#39;s name on a piece of work
// PowerBy: LyShark
// Email: me@lyshark.com
#include &#34;LyMemoryLib.h&#34;
#include <Windows.h>
#include <iostream>
#pragma comment(lib,&#34;advapi32.lib&#34;)
#pragma comment(lib,&#34;LyMemoryLib.lib&#34;)
int main(int argc, char *argv[])
{
LyMemoryDrvCtrl DriveControl;
DriveControl.InstallAndRun();
BOOL set_pid = DriveControl.SetPid(6536);
if (set_pid == TRUE)
{
printf(&#34;
设置PID = %d \n&#34;, set_pid);
}
// 取函数地址
CHAR *SzFunction[3] = { &#34;NtReadFile&#34;, &#34;NtClose&#34;, &#34;NtSetEvent&#34; };
for (size_t i = 0; i < 3; i++)
{
DWORD64 ptr = DriveControl.GetSystemRoutineAddress(SzFunction);
printf(&#34;函数 = %s | 地址 = 0x%p \n&#34;, SzFunction, ptr);
}
system(&#34;pause&#34;);
return 0;
}运行如上方所示的代码片段,则自动取出&#34;NtReadFile&#34;, &#34;NtClose&#34;, &#34;NtSetEvent&#34;三个函数的内存地址,输出效果图如下所示;
image
分配与释放堆空间: 在对端内存中开辟一段内存可调用CreateRemoteMemory函数实现,释放堆空间则可调用DeleteRemoteMemory函数,默认情况下分配的空间自带读写执行属性,为Hook挂钩转向提供可能。
// 署名权
// right to sign one&#39;s name on a piece of work
// PowerBy: LyShark
// Email: me@lyshark.com
#include &#34;LyMemoryLib.h&#34;
#include <Windows.h>
#include <iostream>
#pragma comment(lib,&#34;advapi32.lib&#34;)
#pragma comment(lib,&#34;LyMemoryLib.lib&#34;)
int main(int argc, char *argv[])
{
LyMemoryDrvCtrl DriveControl;
DriveControl.InstallAndRun();
BOOL set_pid = DriveControl.SetPid(6536);
if (set_pid == TRUE)
{
printf(&#34;
设置PID = %d \n&#34;, set_pid);
}
// 分配内存空间
DWORD64 address = DriveControl.CreateRemoteMemory(1024);
printf(&#34;[+] 已分配内存 = 0x%p \n&#34;, address);
// 释放内存
BOOL del = DriveControl.DeleteRemoteMemory(address, 1024);
if (del == TRUE)
{
printf(&#34;[-] 内存空间 0x%p 已被释放 \n&#34;, address);
}
system(&#34;pause&#34;);
return 0;
}如上代码片段运行后,将在对端内存中分配address的地址,分配后自动将其释放,输出效果图如下所示;
image
读/写内存整数型: 整数类型的读取可调用ReadMemoryDWORD读取32位整数,调用ReadMemoryDWORD64则读取64位整数型;
// 署名权
// right to sign one&#39;s name on a piece of work
// PowerBy: LyShark
// Email: me@lyshark.com
#include &#34;LyMemoryLib.h&#34;
#include <Windows.h>
#include <iostream>
#pragma comment(lib,&#34;advapi32.lib&#34;)
#pragma comment(lib,&#34;LyMemoryLib.lib&#34;)
int main(int argc, char *argv[])
{
LyMemoryDrvCtrl DriveControl;
DriveControl.InstallAndRun();
BOOL set_pid = DriveControl.SetPid(6536);
if (set_pid == TRUE)
{
printf(&#34;
设置PID = %d \n&#34;, set_pid);
}
// 读取32位整数
DWORD read_value = 0;
BOOL read_flag = DriveControl.ReadMemoryDWORD(0x0188F828, &read_value);
if (read_flag == TRUE)
{
printf(&#34;
读取32位数据 = %d \n&#34;, read_value);
}
// 读取64位整数
DWORD64 read64_value = 0;
BOOL read64_flag = DriveControl.ReadMemoryDWORD64(0x0188F828, &read64_value);
if (read64_flag == TRUE)
{
printf(&#34;
读取64位数据 = %d \n&#34;, read64_value);
}
system(&#34;pause&#34;);
return 0;
}编译并运行如上代码片段,则会读取0x0188F828处的整数类型数据,读取输出效果图如下所示;
image
写入整数类型同理,调用WriteMemoryDWORD写出32位整数,调用WriteMemoryDWORD64写出64位整数;
// 署名权
// right to sign one&#39;s name on a piece of work
// PowerBy: LyShark
// Email: me@lyshark.com
#include &#34;LyMemoryLib.h&#34;
#include <Windows.h>
#include <iostream>
#pragma comment(lib,&#34;advapi32.lib&#34;)
#pragma comment(lib,&#34;LyMemoryLib.lib&#34;)
int main(int argc, char *argv[])
{
LyMemoryDrvCtrl DriveControl;
DriveControl.InstallAndRun();
BOOL set_pid = DriveControl.SetPid(6536);
if (set_pid == TRUE)
{
printf(&#34;
设置PID = %d \n&#34;, set_pid);
}
// 写入32位整数
BOOL write32 = DriveControl.WriteMemoryDWORD(0x0188F828, 1000);
if (write32 == TRUE)
{
printf(&#34;[+] 写出数据完成 \n&#34;);
}
// 写入64位整数
BOOL write64 = DriveControl.WriteMemoryDWORD64(0x0188F828, 2000);
if (write64 == TRUE)
{
printf(&#34;[+] 写出数据完成 \n&#34;);
}
system(&#34;pause&#34;);
return 0;
}编译并运行代码,将向目标进程分别写出1000及2000,代码输出效果如下图所示;
image
读/写内存字节集: 内存读写字节集可调用ReadMemoryBytes函数,写出字节集调用WriteMemoryBytes函数;
// 署名权
// right to sign one&#39;s name on a piece of work
// PowerBy: LyShark
// Email: me@lyshark.com
#include &#34;LyMemoryLib.h&#34;
#include <Windows.h>
#include <iostream>
#pragma comment(lib,&#34;advapi32.lib&#34;)
#pragma comment(lib,&#34;LyMemoryLib.lib&#34;)
int main(int argc, char *argv[])
{
LyMemoryDrvCtrl DriveControl;
DriveControl.InstallAndRun();
BOOL set_pid = DriveControl.SetPid(6536);
if (set_pid == TRUE)
{
printf(&#34;
设置PID = %d \n&#34;, set_pid);
}
// 读取字节集
BYTE buffer[8] = { 0 };
BYTE* bufferPtr = buffer;
BOOL flag = DriveControl.ReadMemoryBytes(0x401000, &bufferPtr, sizeof(buffer));
if (flag == TRUE)
{
for (int x = 0; x < 8; x++)
{
printf(&#34;[+] 读取字节: 0x%x \n&#34;, buffer[x]);
}
}
system(&#34;pause&#34;);
return 0;
}运行如上代码片段,即可在内存0x401000处开始读取字节集,向后读取8字节,并存入buffer中,输出效果图如下所示;
image
写出字节集与读取基本一致,函数WriteMemoryBytes则用于写出字节集数据,写出是需传递一个定义好的字节数组;
// 署名权
// right to sign one&#39;s name on a piece of work
// PowerBy: LyShark
// Email: me@lyshark.com
#include &#34;LyMemoryLib.h&#34;
#include <Windows.h>
#include <iostream>
#pragma comment(lib,&#34;advapi32.lib&#34;)
#pragma comment(lib,&#34;LyMemoryLib.lib&#34;)
int main(int argc, char *argv[])
{
LyMemoryDrvCtrl DriveControl;
DriveControl.InstallAndRun();
BOOL set_pid = DriveControl.SetPid(6536);
if (set_pid == TRUE)
{
printf(&#34;
设置PID = %d \n&#34;, set_pid);
}
// 写内存字节集
BYTE writebuff[4] = { 0x90, 0x90, 0x90, 0x90 };
BOOL flag = DriveControl.WriteMemoryBytes(0x401000, writebuff, sizeof(writebuff));
if (flag == TRUE)
{
printf(&#34;[+] 写出字节集完成 \n&#34;);
}
system(&#34;pause&#34;);
return 0;
}运行如上代码片段,则将字节集写出到0x401000内存处,写出效果如下图所示;
image
读/写内存浮点数: 浮点数可分为单浮点与双浮点,单浮点可使用ReadMemoryFloat实现读写,双浮点则调用ReadMemoryDouble实现,两者实现原理完全一致,仅仅只是读写时多出了4个字节的宽度而已。
// 署名权
// right to sign one&#39;s name on a piece of work
// PowerBy: LyShark
// Email: me@lyshark.com
#include &#34;LyMemoryLib.h&#34;
#include <Windows.h>
#include <iostream>
#pragma comment(lib,&#34;advapi32.lib&#34;)
#pragma comment(lib,&#34;LyMemoryLib.lib&#34;)
int main(int argc, char *argv[])
{
LyMemoryDrvCtrl DriveControl;
DriveControl.InstallAndRun();
BOOL set_pid = DriveControl.SetPid(6536);
if (set_pid == TRUE)
{
printf(&#34;
设置PID = %d \n&#34;, set_pid);
}
// 读取单浮点
float read_float = 0;
BOOL float_flag = DriveControl.ReadMemoryFloat(0x01894EF8, &read_float);
if (float_flag == TRUE)
{
printf(&#34;[+] 读取单精度 = %f \n&#34;, read_float);
}
// 读取双浮点
double read_double = 0;
BOOL double_flag = DriveControl.ReadMemoryDouble(0x01894EF8, &read_double);
if (double_flag == TRUE)
{
printf(&#34;[+] 读取双精度 = %f \n&#34;, double_flag);
}
system(&#34;pause&#34;);
return 0;
}运行后输出两个浮点数,注意双精度此处并不是错误而是输出问题,效果图如下所示;
image
那么如何写出数据呢,只需要调用WriteMemoryFloat即可实现写出浮点数的目的;
// 署名权
// right to sign one&#39;s name on a piece of work
// PowerBy: LyShark
// Email: me@lyshark.com
#include &#34;LyMemoryLib.h&#34;
#include <Windows.h>
#include <iostream>
#pragma comment(lib,&#34;advapi32.lib&#34;)
#pragma comment(lib,&#34;LyMemoryLib.lib&#34;)
int main(int argc, char *argv[])
{
LyMemoryDrvCtrl DriveControl;
DriveControl.InstallAndRun();
BOOL set_pid = DriveControl.SetPid(6536);
if (set_pid == TRUE)
{
printf(&#34;
设置PID = %d \n&#34;, set_pid);
}
// 写取单浮点
BOOL ref = DriveControl.WriteMemoryFloat(0x01894EF8, 100.245);
if (ref == TRUE)
{
printf(&#34;[+] 写出数据完成 \n&#34;);
}
system(&#34;pause&#34;);
return 0;
}以单精度浮点数为例,写出数据后输出如下效果;
image
计算多级偏移动态地址: 函数ReadDeviationMemory32可实现动态计算多级偏移的功能,该函数最多可接受32级偏移的计算,计算后可得到一个动态地址,用户得到动态地址后可对其地址执行读写整数,字节,字节集,浮点数等各类操作,我们以整数读写为例子;
// 署名权
// right to sign one&#39;s name on a piece of work
// PowerBy: LyShark
// Email: me@lyshark.com
#include &#34;LyMemoryLib.h&#34;
#include <Windows.h>
#include <iostream>
#pragma comment(lib,&#34;advapi32.lib&#34;)
#pragma comment(lib,&#34;LyMemoryLib.lib&#34;)
int main(int argc, char *argv[])
{
LyMemoryDrvCtrl DriveControl;
DriveControl.InstallAndRun();
BOOL set_pid = DriveControl.SetPid(6536);
if (set_pid == TRUE)
{
printf(&#34;
设置PID = %d \n&#34;, set_pid);
}
// 计算四级偏移动态地址
ProcessDeviationMemory read_offset_struct = { 0 };
read_offset_struct.Address = 0x6566e0; // 基地址
read_offset_struct.OffsetSize = 4; // 偏移长度
read_offset_struct.Data = 0; // 读入的数据
read_offset_struct.Offset[0] = 0x18; // 一级偏移
read_offset_struct.Offset[1] = 0x0; // 二级偏移
read_offset_struct.Offset[2] = 0x14; // 三级偏移
read_offset_struct.Offset[3] = 0x0c; // 四级偏移
// 开始计算
DWORD BaseAddress = DriveControl.ReadDeviationMemory32(&read_offset_struct);
printf(&#34;[+] 得到动态地址 = 0x%016lx \n&#34;, BaseAddress);
// 读取整数
DWORD GetDWORD = 0;
BOOL flag = DriveControl.ReadMemoryDWORD(BaseAddress, &GetDWORD);
if (flag == TRUE)
{
printf(&#34;[+] 读取数据 = %d \n&#34;, GetDWORD);
}
system(&#34;pause&#34;);
return 0;
}如上代码通过调用ReadDeviationMemory32计算出当前动态地址的基址,并通过ReadMemoryDWORD读取此处的内存DWORD类型,输出效果如下所示;
image
内存读写反汇编: 读写函数我们可使用ReadMemoryBytes实现字节集的读取,通过运用capstone反汇编引擎即可对特定内存空间进行反汇编操作;
// 署名权
// right to sign one&#39;s name on a piece of work
// PowerBy: LyShark
// Email: me@lyshark.com
#include &#34;LyMemoryLib.h&#34;
#include <Windows.h>
#include <iostream>
#include <inttypes.h>
#include <capstone\capstone.h>
#pragma comment(lib,&#34;capstone64.lib&#34;)
#pragma comment(lib,&#34;advapi32.lib&#34;)
#pragma comment(lib,&#34;LyMemoryLib.lib&#34;)
int main(int argc, char *argv[])
{
LyMemoryDrvCtrl DriveControl;
DriveControl.InstallAndRun();
BOOL set_pid = DriveControl.SetPid(5588);
if (set_pid == TRUE)
{
printf(&#34;
设置PID = %d \n&#34;, set_pid);
}
// 读取前1024个字节
BYTE MyArray[1024] = { 0 };
BYTE* bufferPtr = MyArray;
BOOL flag = DriveControl.ReadMemoryBytes(0x401000, &bufferPtr, sizeof(MyArray));
if (flag == TRUE)
{
printf(&#34;
读取完毕 \n&#34;);
}
csh handle;
cs_insn *insn;
size_t count;
int size = 1023;
// 打开句柄
if (cs_open(CS_ARCH_X86, CS_MODE_32, &handle) != CS_ERR_OK)
{
return 0;
}
// 反汇编代码,地址从0x1000开始,返回总条数
count = cs_disasm(handle, (unsigned char *)MyArray, size, 0x401000, 0, &insn);
if (count > 0)
{
size_t index;
for (index = 0; index < count; index++)
{
/*
for (int x = 0; x < insn[index].size; x++)
{
printf(&#34;机器码: %d -> %02X \n&#34;, x, insn[index].bytes[x]);
}
*/
printf(&#34;地址: 0x%&#34;PRIx64&#34; | 长度: %d 反汇编: %s %s \n&#34;, \
insn[index].address, insn[index].size, insn[index].mnemonic, insn[index].op_str);
}
cs_free(insn, count);
}
/*
else
{
printf(&#34;反汇编返回长度为空 \n&#34;);
}
*/
cs_close(&handle);
system(&#34;pause&#34;);
return 0;
}运行后即可对进程中0x401000的内存区域向下反汇编1024个字节,输出效果图如下所示;
image
项目地址
https://github.com/lyshark/LyMemory |
|