乐趣区

关于c++:LyMemory-内核级内存读写驱动

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

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

退出移动版