寻找任务坐标的方法:
用CE寻找本人的x y z 坐标内存地址,并通过修改器实现效果,并找出基址
坐标比较精确 所以浮点数或者双浮点数
坐标在一些游戏中可能被加密过 变动的数值
初始值为未知 的初始值
x坐标地址 +4字节(十六进制)=Y坐标地址
y坐标地址 +4字节(十六进制)=Z坐标地址
x坐标地址 +4字节(十六进制) =Z坐标地址
Z坐标地址 +4字节(十六进制) =Y坐标地址
实现了一些小功能:
无限金币:
主要思路就是向内存中修改金币数量的地址写入新的值
//金币无限,可以修改为任意金币值
BOOL money_change(DWORD processId, LPVOID BaseAddress, int x) {
int numOffsets = 3;
intptr_t offsets[] = { 0x11069BC, 0x7C,0x1CC };
int numOffsets2 = 2;
intptr_t offsets2[] = { 0x11069BC, 0x14 };
HANDLE hProcess = OpenProcess(PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, processId);
if (WriteProcessMemory(hProcess, VisitMemory(processId, BaseAddress, offsets, numOffsets), &x, sizeof(int), NULL)&& WriteProcessMemory(hProcess,(LPVOID)0x1A1B9FC, &x, sizeof(int),NULL))
return 1;
}
血量无限:
思路和金币无限相同,但是有一个注意点就是,需要把是否掉血改为0,这样实现不掉血,不然血量再高还是会被杀死
//血量无限
BOOL Blood_change(DWORD processId, LPVOID BaseAddress, int x) {
int numOffsets =4;//血量多少地址
intptr_t offsets[] = { 0x11069BC, 0x7C,0x4,0x160 };
int numOffsets1 = 4;//是否掉血地址
intptr_t offsets1[] = { 0x11069BC, 0x7C,0x4,0x16C };
int y = 0;//这里将是否掉血改为0,就可以实现不掉血,即不会死,但是很奇怪一个点,定义一个变量为0然后进行写入就可以,但是直接进行写入,就写入失败
HANDLE hProcess = OpenProcess(PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, processId);
//修改血量值为255,但是还是回掉血,最后会被杀死,需要修改程序为不掉血
if (WriteProcessMemory(hProcess,VisitMemory(processId, BaseAddress, offsets, numOffsets), &x, sizeof(int), NULL)&& WriteProcessMemory(hProcess, VisitMemory(processId, BaseAddress, offsets1, numOffsets1), &y, sizeof(int), NULL))
return 1;
}
随时购物
这里就是修改指令代码,上面金币和血量修改的是指令的操作数,这里是修改整个指令
BOOL Shopping_angtime(DWORD processId, LPVOID BaseAddress) {
HANDLE hProcess = OpenProcess(PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, processId);
int numOffsets = 3;
intptr_t offsets[] = { 0x11069BC, 0x7C,0x3c0};
/*int x = 1;
if (WriteProcessMemory(hProcess, VisitMemory(processId, BaseAddress, offsets, numOffsets), &x, sizeof(int), NULL))*/
BYTE newBytes1[] = { 0xc7,0x86,0xc0,0x03,0x00,0x00,0x01 };
if(WriteProcessMemory(hProcess, (LPVOID)0x1aa59d75, newBytes1, sizeof(newBytes1), NULL))
return 1;
}
两秒17刀:
内存中+B8这个位置,如果持续点击左键的话,这个位置的数据会增加,所以把这里锁定为-1,这样实现两秒17刀效果
BOOL dao(DWORD processID, LPVOID BaseAddress) {
int numOffsets = 4;
intptr_t offsets[] = { 0x11069BC, 0x7C,0x5ec,0xb8 };
HANDLE hProcess = OpenProcess(PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, processId);
int x = -1;
if (WriteProcessMemory(hProcess, VisitMemory(processID, BaseAddress, offsets, numOffsets), &x, sizeof(int), NULL) )
return 1;
}
完整代码:
#include <Windows.h>
#include <Psapi.h>
#include <stdio.h>
#include<iostream>
DWORD processId;//进程ID变量
//获取进程句柄
HWND GethWnd() {
LPCWSTR targetWindowTitle = L"Counter-Strike";
HWND hWnd = FindWindow(NULL, targetWindowTitle);//获取窗口句柄
if (hWnd == NULL) {
printf("未找到目标窗口\n");
}
else return hWnd;
}
//获取进程ID
DWORD GetProcessID(HWND hWnd) {
GetWindowThreadProcessId(hWnd, &processId);
return processId;
}
//获取进程基地址
LPVOID GetProcessBaseAddress(DWORD ProcessID) {
HANDLE hProcess = OpenProcess(PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, ProcessID);
HMODULE hModules[1024];
DWORD needed;//枚举进程所有模块
if (EnumProcessModules(hProcess, hModules, sizeof(hModules), &needed)) {
int moduleCount = needed / sizeof(HMODULE);//计算模块数量
//获取指定模块信息
for (int i = 0; i < moduleCount; ++i) {
TCHAR moduleName[MAX_PATH];
if (GetModuleBaseName(hProcess, hModules[i], moduleName, sizeof(moduleName) / sizeof(TCHAR))) {
if (_wcsicmp(moduleName, L"cstrike.exe") == 0) {
MODULEINFO moduleInfo;
if (GetModuleInformation(hProcess, hModules[i], &moduleInfo, sizeof(moduleInfo))) {
return moduleInfo.lpBaseOfDll;
}
else {
printf("获取模块信息失败\n");
}
}
}
} printf("未找到名为\"cs\"的模块\n");
CloseHandle(hProcess); // Close the handle before returning NULL
return NULL;
}
else {
printf("枚举进程模块失败\n");
}
CloseHandle(hProcess);//关闭
}
//访问内存数据(根据基地址+传进来的偏移值计算最后要写入数据前的地址)
LPVOID VisitMemory(DWORD processId, LPVOID BaseAddress, intptr_t* offsets, int numOffsets) {
HANDLE hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, processId);
int i;
int value = 0;
LPVOID address;
for (i = 0; i < numOffsets; i++) {//循环找完偏移值
if (i == 0)
address = (LPVOID)((DWORD)BaseAddress + offsets[i]);//第一次是基地址+偏移
else
address = (LPVOID)((DWORD)value + offsets[i]);//后面就是内存中的值加偏移
if (i == numOffsets - 1) {
printf("%x\n", address);
return address;
}
ReadProcessMemory(hProcess, address, &value, sizeof(int), NULL);
}
}
//金币无限,可以修改为任意金币值
BOOL money_change(DWORD processId, LPVOID BaseAddress, int x) {
int numOffsets = 3;
intptr_t offsets[] = { 0x11069BC, 0x7C,0x1CC };
int numOffsets2 = 2;
intptr_t offsets2[] = { 0x11069BC, 0x14 };
HANDLE hProcess = OpenProcess(PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, processId);
if (WriteProcessMemory(hProcess, VisitMemory(processId, BaseAddress, offsets, numOffsets), &x, sizeof(int), NULL)&& WriteProcessMemory(hProcess,(LPVOID)0x1A1B9FC, &x, sizeof(int),NULL))
return 1;
}
//血量无限
BOOL Blood_change(DWORD processId, LPVOID BaseAddress, int x) {
int numOffsets =4;//血量多少地址
intptr_t offsets[] = { 0x11069BC, 0x7C,0x4,0x160 };
int numOffsets1 = 4;//是否掉血地址
intptr_t offsets1[] = { 0x11069BC, 0x7C,0x4,0x16C };
int y = 0;//这里将是否掉血改为0,就可以实现不掉血,即不会死,但是很奇怪一个点,定义一个变量为0然后进行写入就可以,但是直接进行写入,就写入失败
HANDLE hProcess = OpenProcess(PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, processId);
//修改血量值为255,但是还是回掉血,最后会被杀死,需要修改程序为不掉血
if (WriteProcessMemory(hProcess,VisitMemory(processId, BaseAddress, offsets, numOffsets), &x, sizeof(int), NULL)&& WriteProcessMemory(hProcess, VisitMemory(processId, BaseAddress, offsets1, numOffsets1), &y, sizeof(int), NULL))
return 1;
}
//两秒17刀
BOOL dao(DWORD processID, LPVOID BaseAddress) {
int numOffsets = 4;
intptr_t offsets[] = { 0x11069BC, 0x7C,0x5ec,0xb8 };
HANDLE hProcess = OpenProcess(PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, processId);
int x = -1;
if (WriteProcessMemory(hProcess, VisitMemory(processID, BaseAddress, offsets, numOffsets), &x, sizeof(int), NULL) )
return 1;
}
//随地购物
BOOL Shopping_angtime(DWORD processId, LPVOID BaseAddress) {
HANDLE hProcess = OpenProcess(PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, processId);
int numOffsets = 3;
intptr_t offsets[] = { 0x11069BC, 0x7C,0x3c0};
/*int x = 1;
if (WriteProcessMemory(hProcess, VisitMemory(processId, BaseAddress, offsets, numOffsets), &x, sizeof(int), NULL))*/
BYTE newBytes1[] = { 0xc7,0x86,0xc0,0x03,0x00,0x00,0x01 };
if(WriteProcessMemory(hProcess, (LPVOID)0x1aa59d75, newBytes1, sizeof(newBytes1), NULL))
return 1;
}
int main() {
HWND hWnd = GethWnd();
DWORD ProcessID = GetProcessID(hWnd);
LPVOID BaseAddress = GetProcessBaseAddress(ProcessID);
printf("%d\n", ProcessID);
printf("%x\n", BaseAddress);
if(money_change(ProcessID, BaseAddress, 10000))printf("金币无限成功1");
if (Blood_change(ProcessID, BaseAddress,0x437f0000))printf("血量无限成功2");
if (Shopping_angtime(ProcessID, BaseAddress))printf("随时购物成功3");
if (dao(ProcessID, BaseAddress))printf("两秒17刀成功4");
// BLOOD_NO(ProcessID, BaseAddress);
return 0;
}
参考文章
【C++】从零开始的CSGO逆向分析1——寻找偏移与基址的方法 - 水风井 - 博客园 (cnblogs.com)
FRK1/HazeTumper:最新的CSGO偏移量和HazeDucumper配置 (github.com)