c++辅助修改游戏内存

打印程序目标地址附近内存

#include <stdio.h>   // printf、scanf 所需头文件
#include <sys/ptrace.h>  // ptrace 系统调用头文件
#include <sys/types.h>   // 部分系统下 ptrace 依赖的类型定义

int main(void)
{
    printf("Ptrace\n");
    
    // 输入目标进程 PID
    int pid;
    printf("please input pid:");
    scanf("%d", &pid);
    
    // 输入要读取的内存地址(十六进制)
    long address;
    printf("please input address:");
    scanf("%lX", &address);  // %lX 匹配 long 类型的十六进制输入
    
    // 附加到目标进程
    long ret = ptrace(PTRACE_ATTACH, pid, NULL, NULL);
    printf("PTRACE_ATTACH:%d\n", ret);
    
    // 读取目标进程内存数据
    print("%X",address)
    int num = 40;
    for(int i = 0; i < num; i++){
        ret = ptrace(PTRACE_PEEKDATA, pid, address, NULL);
        printf("%d\t", ret);  // 输出读取的内存值(十进制)
        address += 0x4;
        if((i+1)%4==0){//每输出4个地址,便输出一个换行。
            print("\n");
            if(i != (num-1)){
                print("%X",address);
            }
        }
    }

    
    // 与目标进程分离
    ret = ptrace(PTRACE_DETACH, pid, NULL, NULL);
    printf("PTRACE_DETACH:%d\n", ret);  // 补充原代码遗漏的分离结果打印
    
    return 0;
}

常用函数

ptrace()函数

ptrace(PTRACE_POKEDATA,pid,address,data);//写入数据

proc函数

int main(void)
{
    char * mem_path = "/proc/30044/mem";
    int fd = open(mem_path,O_RDWR);
    long int address = 0xBCF5D83C;
    //读取地址
    int res = 0;
    lseek(fd,address,SEEK_SET);
    read(fd,&res,sizeof(int));
    
    print("lX read int %d\n",address,res);
    close(fd);
    return 0;
}

Leek函数

lseek(mem_file, addr, SEEK_SET)

mem_file对应一个 /proc/[pid]/mem

调用 lseek(mem_file, addr, SEEK_SET) 后:
后续 read(mem_file, ...) 会读取进程虚拟地址 addr 处的数据。
后续 write(mem_file, ...) 会修改进程虚拟地址 addr 处的内容(需权限)。

proc读取libc相关地址

软件加载libc时,libc存放的位置/proc/pid/maps,里面有libc加载到的地址。

addrBegin-addrEnd     读写权限        地址信息

使用指令筛选
grep target_libc_name /proc/pid/maps

int main(){
    mem_file = open ("/proc/6312/mem",O_WORD);
    
    FILE *libnative = popen("grep libnative.so /proc/6312/maps","r");
    
    char temp[10];
    int i = 0;
    int ch = fgetc("libnative");
    while(ch != '-'){
        temp[i] = ch;
        ch = fgetc("libnative");
        i+=1;
    }
    temp[i]='\0';
    
    unintptr_t addr;
    sscanf(tmp,"%lx",&addr);    // 将char类型转换为16进制
    
}

process_vm

syscall(__NR_process_vm_readv,30044);//参数:系统调用函数名,被调函数参数(pid)

MFC界面辅助编写

MFC编写注意事项

  • 窗口句柄注意不要和已知软件名称重复。

调试信息

弹窗提示

CString msg;  // 定义字符串变量
msg.Format(_T("成功获取PID:%d"), pid);
AfxMessageBox(msg);
AfxMessageBox(_T("获取 进程句柄 失败"));

C++编写代码读取内存地址

项目创建

使用VS Studio:创建新项目-> c++ ->MFC项目
VS安装MFC


弹出来的选项:
应用程序类型:基于对话框
使用MFC:在静态库文中使用MFC

项目创建完成后,主对话框位置:资源文件->MFCApplication1.rc,双击,MFCApplication1->Dialog->IDD_MFCAPPLICATION1_DIALOG。

添加选择框和编辑框和按钮
使用static Text,和Edit Control,Button

设置窗口标题
右键窗口空白部分,选择属性。选择外观->描述文字

编辑框添加变量
右键编辑框->添加变量->输入变量名称,类型默认即可。 // 后续用这个名字来操纵编辑框

给按钮添加事件
双击按钮

void CMFCApplication1Dlg::OnBnClickedButton1()
{
	HWND 窗口句柄 = ::FindWindow(NULL, L"诛仙");    //找窗口句柄
	if (窗口句柄 == NULL)
	{
		// 未找到窗口:输出调试信息
		AfxMessageBox(_T("未找到标题为“诛仙”的窗口!"));  // 弹窗提示
		OutputDebugString(_T("FindWindow 失败:未找到“诛仙”窗口\n"));  // 输出到调试窗口
		return;  // 若未找到,可提前退出函数,避免后续无效操作
	}
	else
	{
		// 找到窗口:输出成功信息(可选)
		AfxMessageBox(_T("成功找到“诛仙”窗口!"));
		OutputDebugString(_T("FindWindow 成功:已找到“诛仙”窗口\n"));
	}
	DWORD pid;
	GetWindowThreadProcessId(窗口句柄, &pid);
	if (pid == 0)
	{
		AfxMessageBox(_T("pid未找到"));
		return;
	}
	else
	{
		CString msg;  // 定义字符串变量
		msg.Format(_T("成功获取PID:%d"), pid);
		AfxMessageBox(msg);
	}
	
	HANDLE 进程句柄 = OpenProcess(PROCESS_VM_READ, FALSE, pid);
	if (进程句柄 == NULL)
	{
		AfxMessageBox(_T("获取 进程句柄 失败"));
		return;
	}
	QWORD 当前气血;
	ReadProcessMemory(进程句柄, (LPCVOID)0x14176E868, &当前气血, sizeof(当前气血), NULL);    //目标进程的基址。
	ReadProcessMemory(进程句柄, (LPCVOID)(当前气血 + 0x60), &当前气血, sizeof(当前气血), NULL);//偏移
	ReadProcessMemory(进程句柄, (LPCVOID)(当前气血 + 0x558), &当前气血, sizeof(当前气血), NULL);//二级偏移

	//wchar_t juseming[30];    //读取字符串,读取角色名。
	//ReadProcessMemory(进程句柄, (LPCVOID)0x14135D8A8, &角色名, sizeof(角色名), NULL);//基址
	//ReadProcessMemory(进程句柄, (LPCVOID)(角色名 + 0x40), &角色名, sizeof(角色名), NULL);//
	//ReadProcessMemory(进程句柄, (LPCVOID)(角色名 + 0x80), &角色名, sizeof(角色名), NULL);//将角色名+0x80指向的地址赋值给角色名
	//ReadProcessMemory(进程句柄, (LPCVOID)(角色名 + 0), juseming, sizeof(juseming), NULL);

	CString str;
	str.Format(L"%d", 当前气血);
	edit当前气血.SetWindowTextW(str);
}

生成软件
选择realse->生成解决方案,在命令输出框中找到输出路径

注意用管理员启动

MFC的DLL注入技及C语言指针读取

项目创建选择MFC动态连接库,静态链接到MFC的常规DLL。
选择资源文件->xxxx.rc双击打开资源视图。


右键图示文件,添加资源,Dialog。
右键新建的Dialog窗口,添加类,类名不要取中文。
然后切换到解决方案,源文件->MFCLibrary1.cpp,添加头文件#include "mydialog.h"

打开MFCLibrary1.cpp

myDialog* mywindow;//定义全局指针
DWORD WINAPI 显示窗口(LPARAM lpDate)
{
	mywindow = new myDialog;//创建对象
	mywindow->DoModal();

	delete mywindow;//释放内存
	FreeLibraryAndExitThread(theApp.m_hInstance,1);//释放DLL
	return TRUE;

}


// CMFCLibrary1App 初始化

BOOL CMFCLibrary1App::InitInstance()
{
	CWinApp::InitInstance();
	::CreateThread(NULL,NULL,(LPTHREAD_START_ROUTINE)显示窗口,NULL,NULL,NULL);
	return TRUE;
}

生成文件
记住MFCLibrary1.dll的位置,打开游戏和CE
CE选择游戏后打开查看内存->工具->注入DLL

然后成功注入并且游戏和CE也都蹦掉了。

指针读取

void myDialog::OnBnClickedButton2()
{
	//ReadProcessMemory(进程句柄, (LPCVOID)0x14176E868, &当前气血, sizeof(当前气血), NULL);    //目标进程的基址。
	//ReadProcessMemory(进程句柄, (LPCVOID)(当前气血 + 0x60), &当前气血, sizeof(当前气血), NULL);//偏移
	//ReadProcessMemory(进程句柄, (LPCVOID)(当前气血 + 0x558), &当前气血, sizeof(当前气血), NULL);//二级偏移

	/*0x14176E868+60+558*/

	QWORD 当前气血 = *(QWORD*)0x14176E868;    //  注意如果访问了错误的指针,指针的值不存在会导致游戏崩溃。
	当前气血 = *(QWORD*)(当前气血 + 0x60);
	当前气血 = *(QWORD*)(当前气血 + 0x558);

	CString str;
	str.Format(L"%d", 当前气血);
	edit当前气血.SetWindowTextW(str);


}

使用后闪退不清楚原因。

DLL注入功能代码实现

创建项目->MFC应用->应用程序类型:基于对话框->使用MFC:在静态库中使用MFC

BOOL DLL注入(HANDLE 进程句柄,const char*DLL完整路径)
{
	LPVOID 地址 =  VirtualAllocEx(进程句柄,NULL,256,MEM_COMMIT,PAGE_READWRITE);//成功返回申请空间的地址
	if (地址 == NULL)
	{
		AfxMessageBox(_T("地址失败"));
		return FALSE;
	}
	BOOL ret =WriteProcessMemory(进程句柄, 地址, DLL完整路径, strlen(DLL完整路径) + 1, NULL);
	if (ret = NULL) {
		return FALSE;
	}
	HANDLE 线程句柄 = 	CreateRemoteThread(进程句柄, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibraryA, 地址, NULL, NULL);//Load参数加载DLL完整路径

	if (线程句柄 == NULL) 
	{
		VirtualFreeEx(进程句柄, 地址, 0, MEM_RELEASE);
		AfxMessageBox(_T("获取 线程句柄 失败"));
		return FALSE;
	}
	AfxMessageBox(_T("运行到这里成功"));
	WaitForSingleObject(线程句柄, INFINITE);
	CloseHandle(线程句柄);
	VirtualFreeEx(进程句柄, 地址, 0, MEM_RELEASE);
	return TRUE;
}
void CMFCApplication1Dlg::OnBnClickedButton2()
{
	HWND 窗口句柄 = ::FindWindow(NULL, L"诛仙");
	DWORD pid;
	GetWindowThreadProcessId(窗口句柄, &pid);
	if (pid == NULL)
	{
		AfxMessageBox(_T("获取 pid 失败"));
		return;
	}
	else
	{
		CString msg;  // 定义字符串变量
		msg.Format(_T("成功获取PID:%d"), pid);
		AfxMessageBox(msg);
	}
	HANDLE 进程句柄 = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_CREATE_THREAD,FALSE ,pid);//注意需要权限

	CString msg;  // 定义字符串变量
	msg.Format(_T("成功获取进程句柄:%d"), 进程句柄);
	AfxMessageBox(msg);

	DLL注入(进程句柄, "D:\\project\\vstudio\\C++\\MFCLibrary1\\x64\\Release\\MFCLibrary1.dll");

	CloseHandle(进程句柄);
}

参考链接

BV184AMeMELE?spm_id_from=333.788.player.switch&vd_source=d24c2772c59c9d862438971bcb05f991&p=6

posted @ 2025-08-04 16:43  MillionMind  阅读(5)  评论(0)    收藏  举报