一款完全免费的内核级内存读写工具,可冲破驱动爱护,强制读写应用层任意过程内存数据,驱动工具目前反对读写整数,字节,字节集,单精度浮点数,双精度浮点数,多级偏移读写,取模块地址,调配近程内存等性能,读写效率高,速度快,兼容性好,应用时需本人签名或在测试模式下。

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援用头文件。

如何装置与卸载驱动: 读写的第一步是装置驱动并将其运行,当然你能够通过第三方组件对驱动进行装置,也能够应用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,"advapi32.lib")#pragma comment(lib,"LyMemoryLib.lib")// 装置驱动BOOL InstallDriver(LyMemoryDrvCtrl Memory){    char szSysFile[MAX_PATH] = { 0 };    char szSvcLnkName[] = "LyMemory";;    BOOL ref = FALSE;    DWORD index = 0;    // 获取残缺门路    Memory.GetAppPath(szSysFile);    strcat_s(szSysFile, "LyMemory.sys");    printf("驱动门路: %s \n", szSysFile);    index = index + 1;    // 装置驱动    ref = Memory.Install(szSysFile, szSvcLnkName, szSvcLnkName);    printf("装置状态: %d \n", ref);    index = index + 1;    // 启动驱动    ref = Memory.Start();    printf("启动状态: %d \n", ref);    index = index + 1;    // 关上    ref = Memory.Open("\\\\.\\LyMemory");    printf("关上状态: %d \n", ref);    index = index + 1;    if (index == 4 && ref == TRUE)    {        return TRUE;    }    return FALSE;}// 卸载驱动BOOL RemoveDriver(LyMemoryDrvCtrl Memory){    BOOL ref = 0;    // 敞开    ref = Memory.Stop();    printf("敞开状态: %d \n", ref);    // 移除    ref = Memory.Remove();    printf("移除状态: %d \n", ref);    return ref;}int main(int argc, char* argv[]){    LyMemoryDrvCtrl DriveControl;    // 加载驱动    BOOL ref = InstallDriver(DriveControl);    if (ref == TRUE)    {        printf("[*] 驱动已加载 \n");    }    // 卸载驱动    RemoveDriver(DriveControl);    system("pause");    return 0;}

如上代码编译后并以管理员权限运行,则会将驱动LyMemory.sys主动加载,并在调试板输入如下图所示的信息;

设置PID过程绑定: 如果须要应用读写函数,第一步则是设置过程PID绑定,通常可通过SetPid(DWORD Pid)函数传入过程PID进行绑定操作,一旦过程被绑定则后续无需再次关上,进步了读写效率,也可预防屡次附加脱离导致应用层异样,如果须要应用设置PID则你能够这样来写;

// 署名权// 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,"advapi32.lib")#pragma comment(lib,"LyMemoryLib.lib")int main(int argc, char *argv[]){    LyMemoryDrvCtrl DriveControl;    DriveControl.InstallAndRun();    BOOL set_pid = DriveControl.SetPid(6536);    if (set_pid == TRUE)    {        printf("[*] 设置PID = %d \n", set_pid);    }    system("pause");    return 0;}

运行如上代码所示将主动绑定到过程6536并输入绑定状态,如下图所示;

内核读取模块基址: 因为目前过程已被附加到到驱动上,此时能够调用GetModuleAddress()获取过程内特定模块的基址,此函数接管一个模块名;

// 署名权// 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,"advapi32.lib")#pragma comment(lib,"LyMemoryLib.lib")int main(int argc, char *argv[]){    LyMemoryDrvCtrl DriveControl;    DriveControl.InstallAndRun();    BOOL set_pid = DriveControl.SetPid(6536);    if (set_pid == TRUE)    {        printf("[*] 设置PID = %d \n", set_pid);    }    // 取模块基址    DWORD64 user32 = DriveControl.GetModuleAddress("user32.dll");    printf("user32 = 0x%p \n", user32);    DWORD64 kernel32 = DriveControl.GetModuleAddress("kernel32.dll");    printf("kernel32 = 0x%p \n", kernel32);    system("pause");    return 0;}

如上代码编译并运行,则取出被附加过程内user32.dll以及kernel32.dll的模块基址,输入效果图如下所示;

取内核函数基址: 与取应用层模块基址相似,函数GetSystemRoutineAddress可用于获取到内核模块中特定导出函数的内存基址。

// 署名权// 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,"advapi32.lib")#pragma comment(lib,"LyMemoryLib.lib")int main(int argc, char *argv[]){    LyMemoryDrvCtrl DriveControl;    DriveControl.InstallAndRun();    BOOL set_pid = DriveControl.SetPid(6536);    if (set_pid == TRUE)    {        printf("[*] 设置PID = %d \n", set_pid);    }    // 取函数地址    CHAR *SzFunction[3] = { "NtReadFile", "NtClose", "NtSetEvent" };    for (size_t i = 0; i < 3; i++)    {        DWORD64 ptr = DriveControl.GetSystemRoutineAddress(SzFunction[i]);        printf("函数 = %s | 地址 = 0x%p \n", SzFunction[i], ptr);    }    system("pause");    return 0;}

运行如上方所示的代码片段,则主动取出"NtReadFile", "NtClose", "NtSetEvent"三个函数的内存地址,输入效果图如下所示;

调配与开释堆空间: 在对端内存中开拓一段内存可调用CreateRemoteMemory函数实现,开释堆空间则可调用DeleteRemoteMemory函数,默认状况下调配的空间自带读写执行属性,为Hook挂钩转向提供可能。

// 署名权// 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,"advapi32.lib")#pragma comment(lib,"LyMemoryLib.lib")int main(int argc, char *argv[]){    LyMemoryDrvCtrl DriveControl;    DriveControl.InstallAndRun();    BOOL set_pid = DriveControl.SetPid(6536);    if (set_pid == TRUE)    {        printf("[*] 设置PID = %d \n", set_pid);    }    // 分配内存空间    DWORD64 address = DriveControl.CreateRemoteMemory(1024);    printf("[+] 已分配内存 = 0x%p \n", address);    // 开释内存    BOOL del = DriveControl.DeleteRemoteMemory(address, 1024);    if (del == TRUE)    {        printf("[-] 内存空间 0x%p 已被开释 \n", address);    }    system("pause");    return 0;}

如上代码片段运行后,将在对端内存中调配address的地址,调配后主动将其开释,输入效果图如下所示;

读/写内存整数型: 整数类型的读取可调用ReadMemoryDWORD读取32位整数,调用ReadMemoryDWORD64则读取64位整数型;

// 署名权// 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,"advapi32.lib")#pragma comment(lib,"LyMemoryLib.lib")int main(int argc, char *argv[]){    LyMemoryDrvCtrl DriveControl;    DriveControl.InstallAndRun();    BOOL set_pid = DriveControl.SetPid(6536);    if (set_pid == TRUE)    {        printf("[*] 设置PID = %d \n", set_pid);    }    // 读取32位整数    DWORD read_value = 0;    BOOL read_flag = DriveControl.ReadMemoryDWORD(0x0188F828, &read_value);    if (read_flag == TRUE)    {        printf("[*] 读取32位数据 = %d \n", read_value);    }    // 读取64位整数    DWORD64 read64_value = 0;    BOOL read64_flag = DriveControl.ReadMemoryDWORD64(0x0188F828, &read64_value);    if (read64_flag == TRUE)    {        printf("[*] 读取64位数据 = %d \n", read64_value);    }    system("pause");    return 0;}

编译并运行如上代码片段,则会读取0x0188F828处的整数类型数据,读取输入效果图如下所示;

写入整数类型同理,调用WriteMemoryDWORD写出32位整数,调用WriteMemoryDWORD64写出64位整数;

// 署名权// 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,"advapi32.lib")#pragma comment(lib,"LyMemoryLib.lib")int main(int argc, char *argv[]){    LyMemoryDrvCtrl DriveControl;    DriveControl.InstallAndRun();    BOOL set_pid = DriveControl.SetPid(6536);    if (set_pid == TRUE)    {        printf("[*] 设置PID = %d \n", set_pid);    }    // 写入32位整数    BOOL write32 = DriveControl.WriteMemoryDWORD(0x0188F828, 1000);    if (write32 == TRUE)    {        printf("[+] 写出数据实现 \n");    }    // 写入64位整数    BOOL write64 = DriveControl.WriteMemoryDWORD64(0x0188F828, 2000);    if (write64 == TRUE)    {        printf("[+] 写出数据实现 \n");    }    system("pause");    return 0;}

编译并运行代码,将向指标过程别离写出10002000,代码输入成果如下图所示;

读/写内存字节集: 内存读写字节集可调用ReadMemoryBytes函数,写出字节集调用WriteMemoryBytes函数;

// 署名权// 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,"advapi32.lib")#pragma comment(lib,"LyMemoryLib.lib")int main(int argc, char *argv[]){    LyMemoryDrvCtrl DriveControl;    DriveControl.InstallAndRun();    BOOL set_pid = DriveControl.SetPid(6536);    if (set_pid == TRUE)    {        printf("[*] 设置PID = %d \n", 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("[+] 读取字节: 0x%x \n", buffer[x]);        }    }    system("pause");    return 0;}

运行如上代码片段,即可在内存0x401000处开始读取字节集,向后读取8字节,并存入buffer中,输入效果图如下所示;

写出字节集与读取基本一致,函数WriteMemoryBytes则用于写出字节集数据,写出是需传递一个定义好的字节数组;

// 署名权// 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,"advapi32.lib")#pragma comment(lib,"LyMemoryLib.lib")int main(int argc, char *argv[]){    LyMemoryDrvCtrl DriveControl;    DriveControl.InstallAndRun();    BOOL set_pid = DriveControl.SetPid(6536);    if (set_pid == TRUE)    {        printf("[*] 设置PID = %d \n", set_pid);    }    // 写内存字节集    BYTE writebuff[4] = { 0x90, 0x90, 0x90, 0x90 };    BOOL flag = DriveControl.WriteMemoryBytes(0x401000, writebuff, sizeof(writebuff));    if (flag == TRUE)    {        printf("[+] 写出字节集实现 \n");    }    system("pause");    return 0;}

运行如上代码片段,则将字节集写出到0x401000内存处,写出成果如下图所示;

读/写内存浮点数: 浮点数可分为单浮点与双浮点,单浮点可应用ReadMemoryFloat实现读写,双浮点则调用ReadMemoryDouble实现,两者实现原理完全一致,仅仅只是读写时多出了4个字节的宽度而已。

// 署名权// 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,"advapi32.lib")#pragma comment(lib,"LyMemoryLib.lib")int main(int argc, char *argv[]){    LyMemoryDrvCtrl DriveControl;    DriveControl.InstallAndRun();    BOOL set_pid = DriveControl.SetPid(6536);    if (set_pid == TRUE)    {        printf("[*] 设置PID = %d \n", set_pid);    }    // 读取单浮点    float read_float = 0;    BOOL float_flag = DriveControl.ReadMemoryFloat(0x01894EF8, &read_float);    if (float_flag == TRUE)    {        printf("[+] 读取单精度 = %f \n", read_float);    }    // 读取双浮点    double read_double = 0;    BOOL double_flag = DriveControl.ReadMemoryDouble(0x01894EF8, &read_double);    if (double_flag == TRUE)    {        printf("[+] 读取双精度 = %f \n", double_flag);    }    system("pause");    return 0;}

运行后输入两个浮点数,留神双精度此处并不是谬误而是输入问题,效果图如下所示;

那么如何写出数据呢,只须要调用WriteMemoryFloat即可实现写出浮点数的目标;

// 署名权// 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,"advapi32.lib")#pragma comment(lib,"LyMemoryLib.lib")int main(int argc, char *argv[]){    LyMemoryDrvCtrl DriveControl;    DriveControl.InstallAndRun();    BOOL set_pid = DriveControl.SetPid(6536);    if (set_pid == TRUE)    {        printf("[*] 设置PID = %d \n", set_pid);    }    // 写取单浮点    BOOL ref = DriveControl.WriteMemoryFloat(0x01894EF8, 100.245);    if (ref == TRUE)    {        printf("[+] 写出数据实现 \n");    }    system("pause");    return 0;}

以单精度浮点数为例,写出数据后输入如下成果;

计算多级偏移动静地址: 函数ReadDeviationMemory32可实现动静计算多级偏移的性能,该函数最多可承受32级偏移的计算,计算后可失去一个动静地址,用户失去动静地址后可对其地址执行读写整数,字节,字节集,浮点数等各类操作,咱们以整数读写为例子;

// 署名权// 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,"advapi32.lib")#pragma comment(lib,"LyMemoryLib.lib")int main(int argc, char *argv[]){    LyMemoryDrvCtrl DriveControl;    DriveControl.InstallAndRun();    BOOL set_pid = DriveControl.SetPid(6536);    if (set_pid == TRUE)    {        printf("[*] 设置PID = %d \n", 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("[+] 失去动静地址 = 0x%016lx \n", BaseAddress);    // 读取整数    DWORD GetDWORD = 0;        BOOL flag = DriveControl.ReadMemoryDWORD(BaseAddress, &GetDWORD);    if (flag == TRUE)    {        printf("[+] 读取数据 = %d \n", GetDWORD);    }    system("pause");    return 0;}

如上代码通过调用ReadDeviationMemory32计算出以后动静地址的基址,并通过ReadMemoryDWORD读取此处的内存DWORD类型,输入成果如下所示;

内存读写反汇编: 读写函数咱们可应用ReadMemoryBytes实现字节集的读取,通过使用capstone反汇编引擎即可对特定内存空间进行反汇编操作;

// 署名权// 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>#include <inttypes.h>#include <capstone\capstone.h>#pragma comment(lib,"capstone64.lib")#pragma comment(lib,"advapi32.lib")#pragma comment(lib,"LyMemoryLib.lib")int main(int argc, char *argv[]){    LyMemoryDrvCtrl DriveControl;    DriveControl.InstallAndRun();    BOOL set_pid = DriveControl.SetPid(5588);    if (set_pid == TRUE)    {        printf("[*] 设置PID = %d \n", set_pid);    }    // 读取前1024个字节    BYTE MyArray[1024] = { 0 };    BYTE* bufferPtr = MyArray;    BOOL flag = DriveControl.ReadMemoryBytes(0x401000, &bufferPtr, sizeof(MyArray));    if (flag == TRUE)    {        printf("[*] 读取结束 \n");    }    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("机器码: %d -> %02X \n", x, insn[index].bytes[x]);            }            */            printf("地址: 0x%"PRIx64" | 长度: %d 反汇编: %s %s \n", \                insn[index].address, insn[index].size, insn[index].mnemonic, insn[index].op_str);        }        cs_free(insn, count);    }    /*    else    {        printf("反汇编返回长度为空 \n");    }    */    cs_close(&handle);    system("pause");    return 0;}

运行后即可对过程中0x401000的内存区域向下反汇编1024个字节,输入效果图如下所示;

我的项目地址

https://github.com/lyshark/LyMemory