Skip to content

一款免费的内核级内存读写工具,可读写任意应用层进程内存数据。 已停止更新 A free kernel level memory reading and writing tool, which can break through driver protection and force reading and writing memory data of any application layer process.

License

Notifications You must be signed in to change notification settings

793359277/LyMemory

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

内核级内存读写驱动


image


Build status Crowdin OSCS Status


一款完全免费的内核级内存读写工具,可读写应用层任意进程内存数据,驱动工具目前支持读写整数,字节,字节集,单精度浮点数,双精度浮点数,多级偏移读写,取模块地址,分配远程内存等功能,读写效率高,速度快,兼容性好。

停更说明

已停止更新,不知道是触及到了谁的利益,也不知道国人的素质到底如何?又或者是哪个安全公司里?哪个游戏厂商里的打工人?为了评估软件的可用性,而整出的这些,至此,我还是决定永久停止该工具的更新,并停止其他版本的开放。

C++ 调用接口

目前驱动读写支持的读写函数如下表所示;

导出函数 函数作用
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,"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自动加载,并在调试板输出如下图所示的信息;

image

设置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并输出绑定状态,如下图所示;

image

内核读取模块基址: 由于目前进程已被附加到到驱动上,此时可以调用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的模块基址,输出效果图如下所示;

image

取内核函数基址: 与取应用层模块基址类似,函数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"三个函数的内存地址,输出效果图如下所示;

image

分配与释放堆空间: 在对端内存中开辟一段内存可调用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的地址,分配后自动将其释放,输出效果图如下所示;

image

读/写内存整数型: 整数类型的读取可调用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处的整数类型数据,读取输出效果图如下所示;

image

写入整数类型同理,调用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,代码输出效果如下图所示;

image

读/写内存字节集: 内存读写字节集可调用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中,输出效果图如下所示;

image

写出字节集与读取基本一致,函数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内存处,写出效果如下图所示;

image

读/写内存浮点数: 浮点数可分为单浮点与双浮点,单浮点可使用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;
}

运行后输出两个浮点数,注意双精度此处并不是错误而是输出问题,效果图如下所示;

image

那么如何写出数据呢,只需要调用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;
}

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

image

计算多级偏移动态地址: 函数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类型,输出效果如下所示;

image

内存读写反汇编: 读写函数我们可使用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个字节,输出效果图如下所示;

image

项目地址

https://github.com/lyshark/LyMemory

About

一款免费的内核级内存读写工具,可读写任意应用层进程内存数据。 已停止更新 A free kernel level memory reading and writing tool, which can break through driver protection and force reading and writing memory data of any application layer process.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • C++ 100.0%