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

浙公网安备 33010602011771号